From cadde5a4b5303d01309c52e20a8708853df33915 Mon Sep 17 00:00:00 2001
From: Stepan Grigorovich <gsdstr@gmail.com>
Date: Tue, 12 Mar 2024 19:57:41 +0300
Subject: [PATCH] 4547 (#4917)

Signed-off-by: Stepan Grigorovich <gsdstr@gmail.com>
---
 .../src/components/ActionHandler.svelte       | 114 +++++++++---------
 .../src/components/Workbench.svelte           |   2 +-
 2 files changed, 58 insertions(+), 58 deletions(-)

diff --git a/plugins/view-resources/src/components/ActionHandler.svelte b/plugins/view-resources/src/components/ActionHandler.svelte
index a000f6ab48..183d1398e8 100644
--- a/plugins/view-resources/src/components/ActionHandler.svelte
+++ b/plugins/view-resources/src/components/ActionHandler.svelte
@@ -14,7 +14,7 @@
 -->
 <script lang="ts">
   import { Analytics } from '@hcengineering/analytics'
-  import core, { Doc, Hierarchy, Ref, TxRemoveDoc } from '@hcengineering/core'
+  import core, { Doc, Hierarchy, Ref, Space, TxRemoveDoc } from '@hcengineering/core'
   import { getResource } from '@hcengineering/platform'
   import { addTxListener, contextStore, getClient } from '@hcengineering/presentation'
   import { AnyComponent, Component } from '@hcengineering/ui'
@@ -24,6 +24,8 @@
   import { ListSelectionProvider, SelectionStore, focusStore, previewDocument, selectionStore } from '../selection'
   import { getObjectPreview, restrictionStore } from '../utils'
 
+  export let currentSpace: Ref<Space> | undefined
+
   const client = getClient()
 
   addTxListener((tx) => {
@@ -131,7 +133,8 @@
   $: disableActions = $restrictionStore.disableActions
 
   async function handleKeys (evt: KeyboardEvent): Promise<void> {
-    if (disableActions) return
+    // For none we ignore all actions.
+    if (disableActions || ctx?.mode === 'none') return
     const targetTagName = (evt.target as any)?.tagName?.toLowerCase()
 
     let elm = evt.target as HTMLElement
@@ -165,63 +168,61 @@
       }
     }
 
-    // For none we ignore all actions.
-    if (ctx?.mode === 'none') {
-      return
-    }
     clearTimeout(timer)
 
-    currentActions = currentActions.filter(({ keyBinding, allowedForEditableContent }) => {
-      const hasKeyBinding = keyBinding !== undefined && keyBinding.length > 0
-      const allowed = !isContentEditable || allowedForEditableContent
+    async function activateAction (a: Action): Promise<boolean> {
+      const action = await getResource(a.action)
+      if (action === undefined) return false
 
-      return hasKeyBinding && allowed
-    })
-
-    if (lastKey !== undefined) {
-      for (const a of sequences) {
-        // TODO: Handle multiple keys here
-        if (a.keyBinding?.find((it) => (lastKey ? matchKeySequence(evt, it, lastKey) : false)) !== undefined) {
-          const action = await getResource(a.action)
-          if (action !== undefined) {
-            sequences = []
-            lastKey = undefined
-            delayedAction = undefined
-            Analytics.handleEvent(a._id)
-            await action(selectionDocs, evt, a.actionProps)
-            return
-          }
-        }
-      }
-    }
-
-    sequences = getSequences(evt, currentActions)
-    let found = false
-    for (const a of currentActions) {
-      // TODO: Handle multiple keys here
-      if (a.keyBinding?.find((it) => matchKey(evt, it)) !== undefined) {
-        const action = await getResource(a.action)
-        if (action !== undefined) {
-          if (sequences.length === 0) {
-            lastKey = undefined
-            sequences = []
-            delayedAction = undefined
-            Analytics.handleEvent(a._id)
-            await action(selectionDocs, evt, a.actionProps)
-            return
-          } else {
-            delayedAction = async () => {
-              Analytics.handleEvent(a._id)
-              await action(selectionDocs, evt, a.actionProps)
-            }
-            found = true
-          }
-        }
-      }
-    }
-    if (!found && delayedAction) {
-      delayedAction()
+      lastKey = undefined
       delayedAction = undefined
+      Analytics.handleEvent(a._id)
+      const actionProps = { ...a.actionProps }
+      if (!Object.prototype.hasOwnProperty.call(actionProps, 'props')) actionProps.props = {}
+      actionProps.props.space = currentSpace
+      await action(selectionDocs, evt, actionProps)
+      return true
+    }
+
+    // 3 cases for keyBinding
+    //  matches the sequence - immediately action
+    //  start sequence - postpone other action
+    //  matches the key - execute if there is no start sequence actions
+
+    let postpone = false
+    let nonSequenceAction: Action | undefined
+
+    for (const a of currentActions) {
+      if (a.keyBinding === undefined || a.keyBinding.length < 1) continue
+      if (isContentEditable && a.allowedForEditableContent !== true) continue
+      const t = lastKey
+      if (t !== undefined && a.keyBinding.some((it) => matchKeySequence(evt, it, t)) && (await activateAction(a))) {
+        return
+      }
+      if (!postpone && a.keyBinding.some((p) => findKeySequence(p, evt))) {
+        postpone = true
+        continue
+      }
+      if (nonSequenceAction === undefined && a.keyBinding.some((it) => matchKey(evt, it))) {
+        nonSequenceAction = a
+      }
+    }
+
+    if (delayedAction !== undefined) {
+      await delayedAction()
+      delayedAction = undefined
+    }
+
+    const t = nonSequenceAction
+    if (t !== undefined) {
+      if (!postpone) {
+        await activateAction(t)
+        return
+      }
+
+      delayedAction = async () => {
+        await activateAction(t)
+      }
     }
 
     lastKey = evt
@@ -230,8 +231,7 @@
       lastKey = undefined
       sequences = []
       if (delayedAction !== undefined) {
-        delayedAction()
-        delayedAction = undefined
+        void delayedAction()
       }
     }, 300)
   }
diff --git a/plugins/workbench-resources/src/components/Workbench.svelte b/plugins/workbench-resources/src/components/Workbench.svelte
index 43a3ff582a..5edc10d013 100644
--- a/plugins/workbench-resources/src/components/Workbench.svelte
+++ b/plugins/workbench-resources/src/components/Workbench.svelte
@@ -634,7 +634,7 @@
     />
   </div>
 {:else if employee?.active || account.role === AccountRole.Owner || isAdminUser()}
-  <ActionHandler />
+  <ActionHandler {currentSpace} />
   <svg class="svg-mask">
     <clipPath id="notify-normal">
       <path d="M12,14c0-3.3,2.7-6,6-6c0.7,0,1.4,0.1,2,0.4V0H0v20h18C14.7,20,12,17.3,12,14z" />