Browse Source

Add action whitelist and special handling for link/image input dialog

Phoenix Eliot 3 years ago
parent
commit
7cb1fc9c3c

+ 27 - 0
e2e-tests/editor.spec.ts

@@ -234,3 +234,30 @@ test('press escape when autocomplete menu is open, should close autocomplete men
     expect(await block.isEditing()).toBe(true)
   }
 })
+
+test('press escape when link/image dialog is open, should restore focus to input', async ({ page, block }) => {
+  for (const [commandTrigger, modalName] of [['/link', 'commands']]) {
+    await createRandomPage(page)
+
+    // Open the action modal
+    await block.mustFill('')
+    await page.waitForTimeout(550)
+    for (const char of commandTrigger) {
+      await page.keyboard.type(char) // Type it one character at a time, because too quickly can fail to trigger it sometimes
+    }
+    await page.waitForTimeout(100)
+    await expect(page.locator(`[data-modal-name="${modalName}"]`)).toBeVisible()
+    await page.waitForTimeout(100)
+
+    // Press enter to open the link dialog
+    await page.keyboard.press('Enter')
+    await expect(page.locator(`[data-modal-name="input"]`)).toBeVisible()
+
+    // Press escape; should close link dialog and restore focus to the block textarea
+    await page.keyboard.press('Escape')
+    await page.waitForTimeout(100)
+    await expect(page.locator(`[data-modal-name="input"]`)).not.toBeVisible()
+    await page.waitForTimeout(1000)
+    expect(await block.isEditing()).toBe(true)
+  }
+})

+ 9 - 3
src/main/frontend/components/editor.cljs

@@ -298,8 +298,12 @@
                 (let [[_id on-submit] (:rum/args state)
                       command (:command (first input-option))]
                   (on-submit command @input-value))
-                (reset! input-value nil))))})))
-  [state _id on-submit]
+                (reset! input-value nil))))
+       ;; escape
+       27 (fn [_state _e]
+            (let [[id _on-submit on-cancel] (:rum/args state)]
+              (on-cancel id)))})))
+  [state _id on-submit _on-cancel]
   (when (= :input (state/sub :editor/action))
     (when-let [action-data (state/sub :editor/action-data)]
       (let [{:keys [pos options]} action-data
@@ -556,7 +560,9 @@
       (= :input action)
       (animated-modal "input" (input id
                                      (fn [command m]
-                                       (editor-handler/handle-command-input command id format m)))
+                                       (editor-handler/handle-command-input command id format m))
+                                     (fn []
+                                       (editor-handler/handle-command-input-close id)))
                       true)
 
       (= :zotero action)

+ 8 - 6
src/main/frontend/handler/editor.cljs

@@ -1729,6 +1729,13 @@
       :markdown (util/format "![%s](%s)" label link)
       :org (util/format "[[%s]]"))))
 
+(defn handle-command-input-close [id]
+  (state/set-editor-show-input! nil)
+  (when-let [saved-cursor (state/get-editor-last-pos)]
+    (when-let [input (gdom/getElement id)]
+      (.focus input)
+      (cursor/move-cursor-to input saved-cursor))))
+
 (defn handle-command-input [command id format m]
   ;; TODO: Add error handling for when user doesn't provide a required field.
   ;; (The current behavior is to just revert back to the editor.)
@@ -1752,12 +1759,7 @@
 
     nil)
 
-  (state/set-editor-show-input! nil)
-
-  (when-let [saved-cursor (state/get-editor-last-pos)]
-    (when-let [input (gdom/getElement id)]
-      (.focus input)
-      (cursor/move-cursor-to input saved-cursor))))
+  (handle-command-input-close id))
 
 (defn get-search-q
   []

+ 10 - 1
src/main/frontend/handler/editor/keyboards.cljs

@@ -15,9 +15,18 @@
      (fn [_state e event]
        (let [target (.-target e)]
          (cond
-           (state/get-editor-action)
+           (contains?
+            #{:commands :block-commands
+              :page-search :page-search-hashtag :block-search :template-search
+              :property-search :property-value-search
+              :datepicker}
+            (state/get-editor-action))
            (state/clear-editor-action!) ;; FIXME: This should probably be handled as a keydown handler in editor, but this handler intercepts Esc first
 
+           ;; editor/input component handles Escape directly, so just prevent handling it here
+           (= :input (state/get-editor-action))
+           nil
+
            (d/has-class? target "bottom-action") ;; FIXME: not particular case
            (.preventDefault e)