ソースを参照

fix: clear shortcut listeners when unmount

Related to https://github.com/logseq/logseq/issues/572.
Tienson Qin 5 年 前
コミット
ff80d85907

+ 6 - 3
src/main/frontend/components/content.cljs

@@ -236,9 +236,12 @@
                          (fn [_]
                            (editor-handler/copy-selection-blocks)
                            (editor-handler/clear-selection! nil)))
-  (mixins/keyboard-mixin (util/->system-modifier "ctrl+x") cut-blocks-and-clear-selections!)
-  (mixins/keyboard-mixin "backspace" cut-blocks-and-clear-selections!)
-  (mixins/keyboard-mixin "delete" cut-blocks-and-clear-selections!)
+  (mixins/keyboard-mixin (util/->system-modifier "ctrl+x")
+                         cut-blocks-and-clear-selections!)
+  (mixins/keyboard-mixin "backspace"
+                         cut-blocks-and-clear-selections!)
+  (mixins/keyboard-mixin "delete"
+                         cut-blocks-and-clear-selections!)
   []
   [:div#selection.hidden])
 

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

@@ -229,11 +229,11 @@
     svg/outdent-block]
    [:button.bottom-action
     {:style {:padding "5px"}
-     :on-click #(editor-handler/move-up-down parent-state % true)}
+     :on-click #(editor-handler/move-up-down % true)}
     svg/move-up-block]
    [:button.bottom-action
     {:style {:padding "5px"}
-     :on-click #(editor-handler/move-up-down parent-state % false)}
+     :on-click #(editor-handler/move-up-down % false)}
     svg/move-down-block]
    [:button.bottom-action
     {:style {:padding "5px"}
@@ -363,12 +363,6 @@
         *slash-caret-pos)))])
 
 (rum/defcs box < rum/reactive
-  (mixins/keyboard-mixin (util/->system-modifier "ctrl+shift+a") editor-handler/select-all-blocks!)
-  (mixins/keyboard-mixin (if util/mac? "meta+shift+up" "alt+shift+up")
-                         (fn [state e]
-                           (editor-handler/move-up-down state e true)))
-  (mixins/keyboard-mixin (if util/mac? "meta+shift+down" "alt+shift+down")
-                         (fn [state e] (editor-handler/move-up-down state e false)))
   (mixins/event-mixin
    (fn [state]
      (let [{:keys [id format block]} (get-state state)
@@ -618,6 +612,8 @@
   {:did-mount (fn [state]
                 (let [[{:keys [dummy? format block-parent-id]} id] (:rum/args state)
                       content (get-in @state/state [:editor/content id])]
+                  (when block-parent-id
+                    (state/set-editing-block-dom-id! block-parent-id))
                   (editor-handler/restore-cursor-pos! id content dummy?)
 
                   (when-let [input (gdom/getElement id)]
@@ -683,7 +679,7 @@
                                               {:re-render-root? true}))))
                        (editor-handler/save-block! (get-state state) value)))
                    state)}
-  [state {:keys [on-hide dummy? node format block]
+  [state {:keys [on-hide dummy? node format block block-parent-id]
           :or {dummy? false}
           :as option} id config]
   (let [content (state/sub [:editor/content id])]

+ 63 - 62
src/main/frontend/handler/editor.cljs

@@ -738,7 +738,7 @@
 
 (defn- with-timetracking-properties
   [block value]
-  (let [new-marker (first (re-find format/bare-marker-pattern value))
+  (let [new-marker (first (re-find format/bare-marker-pattern (or value "")))
         new-marker (if new-marker (string/lower-case (string/trim new-marker)))
         properties (into {} (:block/properties block))]
     (if (and
@@ -1647,67 +1647,68 @@
       string/join))
 
 (defn move-up-down
-  [state e up?]
-  (let [{:keys [id block-id block block-parent-id dummy? value pos format] :as block-state} (get-state state)
-        block (db/entity [:block/uuid block-id])
-        meta (:block/meta block)
-        page (:block/page block)
-        block-dom-node (gdom/getElement block-parent-id)
-        prev-block (get-prev-block-non-collapsed block-dom-node)
-        next-block (get-next-block-non-collapsed block-dom-node)
-        repo (state/get-current-repo)
-        move-upwards-to-parent? (and up? prev-block (< (d/attr prev-block "level") (:block/level block)))
-        move-down-to-higher-level? (and (not up?) next-block (< (d/attr next-block "level") (:block/level block)))]
-    (when-let [sibling-block (cond
-                               move-upwards-to-parent?
-                               prev-block
-                               move-down-to-higher-level?
-                               next-block
-                               :else
-                               (let [f (if up? util/get-prev-block-with-same-level util/get-next-block-with-same-level)]
-                                 (f block-dom-node)))]
-      (when-let [sibling-block-id (d/attr sibling-block "blockid")]
-        (when-let [sibling-block (db/pull-block (medley/uuid sibling-block-id))]
-          (let [sibling-meta (:block/meta sibling-block)
-                hc1 (db/get-block-and-children-no-cache repo (:block/uuid block))
-                hc2 (if (or move-upwards-to-parent? move-down-to-higher-level?)
-                      [sibling-block]
-                      (db/get-block-and-children-no-cache repo (:block/uuid sibling-block)))]
-            ;; Same page and next to the other
-            (when (and
-                   (= (:db/id (:block/page block))
-                      (:db/id (:block/page sibling-block)))
-                   (or
-                    (and up? (= (:end-pos (:block/meta (last hc2))) (:start-pos (:block/meta (first hc1)))))
-                    (and (not up?) (= (:end-pos (:block/meta (last hc1))) (:start-pos (:block/meta (first hc2)))))))
-              (let [hc1-content (block-and-children-content hc1)
-                    hc2-content (block-and-children-content hc2)
-                    file (db/get-block-file (:block/uuid block))
-                    file-path (:file/path file)
-                    old-file-content (db/get-file file-path)
-                    [start-pos end-pos new-content blocks] (if up?
-                                                             [(:start-pos sibling-meta)
-                                                              (get-in (last hc1) [:block/meta :end-pos])
-                                                              (str hc1-content hc2-content)
-                                                              (concat hc1 hc2)]
-                                                             [(:start-pos meta)
-                                                              (get-in (last hc2) [:block/meta :end-pos])
-                                                              (str hc2-content hc1-content)
-                                                              (concat hc2 hc1)])]
-                (when (and start-pos end-pos)
-                  (let [new-file-content (utf8/insert! old-file-content start-pos end-pos new-content)
-                        modified-time (modified-time-tx page file)
-                        blocks-meta (rebuild-blocks-meta start-pos blocks)]
-                    (profile
-                     (str "Move block " (if up? "up: " "down: "))
-                     (repo-handler/transact-react-and-alter-file!
-                      repo
-                      (concat
-                       blocks-meta
-                       modified-time)
-                      {:key :block/change
-                       :data (map (fn [block] (assoc block :block/page page)) blocks)}
-                      [[file-path new-file-content]]))))))))))))
+  [e up?]
+  (when-let [block-id (:block/uuid (state/get-edit-block))]
+    (let [block-parent-id (state/get-editing-block-dom-id)
+          block (db/entity [:block/uuid block-id])
+          meta (:block/meta block)
+          page (:block/page block)
+          block-dom-node (gdom/getElement block-parent-id)
+          prev-block (get-prev-block-non-collapsed block-dom-node)
+          next-block (get-next-block-non-collapsed block-dom-node)
+          repo (state/get-current-repo)
+          move-upwards-to-parent? (and up? prev-block (< (d/attr prev-block "level") (:block/level block)))
+          move-down-to-higher-level? (and (not up?) next-block (< (d/attr next-block "level") (:block/level block)))]
+      (when-let [sibling-block (cond
+                                 move-upwards-to-parent?
+                                 prev-block
+                                 move-down-to-higher-level?
+                                 next-block
+                                 :else
+                                 (let [f (if up? util/get-prev-block-with-same-level util/get-next-block-with-same-level)]
+                                   (f block-dom-node)))]
+        (when-let [sibling-block-id (d/attr sibling-block "blockid")]
+          (when-let [sibling-block (db/pull-block (medley/uuid sibling-block-id))]
+            (let [sibling-meta (:block/meta sibling-block)
+                  hc1 (db/get-block-and-children-no-cache repo (:block/uuid block))
+                  hc2 (if (or move-upwards-to-parent? move-down-to-higher-level?)
+                        [sibling-block]
+                        (db/get-block-and-children-no-cache repo (:block/uuid sibling-block)))]
+             ;; Same page and next to the other
+              (when (and
+                     (= (:db/id (:block/page block))
+                        (:db/id (:block/page sibling-block)))
+                     (or
+                      (and up? (= (:end-pos (:block/meta (last hc2))) (:start-pos (:block/meta (first hc1)))))
+                      (and (not up?) (= (:end-pos (:block/meta (last hc1))) (:start-pos (:block/meta (first hc2)))))))
+                (let [hc1-content (block-and-children-content hc1)
+                      hc2-content (block-and-children-content hc2)
+                      file (db/get-block-file (:block/uuid block))
+                      file-path (:file/path file)
+                      old-file-content (db/get-file file-path)
+                      [start-pos end-pos new-content blocks] (if up?
+                                                               [(:start-pos sibling-meta)
+                                                                (get-in (last hc1) [:block/meta :end-pos])
+                                                                (str hc1-content hc2-content)
+                                                                (concat hc1 hc2)]
+                                                               [(:start-pos meta)
+                                                                (get-in (last hc2) [:block/meta :end-pos])
+                                                                (str hc2-content hc1-content)
+                                                                (concat hc2 hc1)])]
+                  (when (and start-pos end-pos)
+                    (let [new-file-content (utf8/insert! old-file-content start-pos end-pos new-content)
+                          modified-time (modified-time-tx page file)
+                          blocks-meta (rebuild-blocks-meta start-pos blocks)]
+                      (profile
+                       (str "Move block " (if up? "up: " "down: "))
+                       (repo-handler/transact-react-and-alter-file!
+                        repo
+                        (concat
+                         blocks-meta
+                         modified-time)
+                        {:key :block/change
+                         :data (map (fn [block] (assoc block :block/page page)) blocks)}
+                        [[file-path new-file-content]])))))))))))))
 
 (defn expand!
   []

+ 13 - 9
src/main/frontend/keyboard.cljs

@@ -16,12 +16,16 @@
   ([key trigger once? target]
    (let [handler (new KeyboardShortcutHandler target)]
      (.registerShortcut handler (str key once?) key)
-     (events/listen
-      handler
-      EventType/SHORTCUT_TRIGGERED
-      (fn [e]
-        (trigger e)
-        (when once?
-          (.unregisterShortcut handler keys))))
-     (fn []
-       (.unregisterShortcut handler key)))))
+     (let [f (fn [e]
+               (trigger e)
+               (when once?
+                 (.unregisterShortcut handler key)))
+           listener (events/listen
+                     handler
+                     EventType/SHORTCUT_TRIGGERED
+                     f)
+           unlisten-fn (fn []
+                         (.dispose handler))]
+       (fn []
+         (.unregisterShortcut handler key)
+         (unlisten-fn))))))

+ 4 - 1
src/main/frontend/keyboards.cljs

@@ -67,7 +67,10 @@
     "ctrl+b" editor-handler/bold-format!
     "ctrl+i" editor-handler/italics-format!
     "ctrl+k" editor-handler/html-link-format!
-    "ctrl+h" editor-handler/highlight-format!}
+    "ctrl+h" editor-handler/highlight-format!
+    "ctrl+shift+a" editor-handler/select-all-blocks!
+    "alt+shift+up" (fn [state e] (editor-handler/move-up-down e true))
+    "alt+shift+down" (fn [state e] (editor-handler/move-up-down e false))}
    (medley/map-keys util/->system-modifier)))
 
 (defonce chords

+ 11 - 14
src/main/frontend/mixins.cljs

@@ -169,25 +169,22 @@
    If no target is given it is defaulted to js/window (global handler)
    Ex:
      (keyboard-mixin \"esc\" #(browse-to :home/home))"
-  ([key f] (keyboard-mixin key f (fn [_] true) js/window))
-  ([key f enable-f] (keyboard-mixin key f enable-f js/window))
-  ([key f enable-f target]
+  ([key f] (keyboard-mixin key f js/window))
+  ([key f target]
    (let [target-fn (if (fn? target) target (fn [_] target))]
      {:did-mount
       (fn [state]
-        (if (enable-f state)
-          (assoc state (str (name ::keyboard-listener) key)
-                 (keyboard/install-shortcut! key
-                                             (fn [e] (f state e))
-                                             false
-                                             (target-fn state)))
-          state))
+        (assoc state (str (name ::keyboard-listener) key)
+               (keyboard/install-shortcut! key
+                                           (fn [e] (f state e))
+                                           false
+                                           (target-fn state))))
       :will-unmount
       (fn [state]
-        (when (enable-f state)
-          (when-let [f (get state (str (name ::keyboard-listener) key))]
-            (f)))
-        state)})))
+        (let [k (str (name ::keyboard-listener) key)]
+          (when-let [f (get state k)]
+            (f))
+          (dissoc state k)))})))
 
 (defn keyboards-mixin
   ([m] (keyboards-mixin m (fn [_] true) js/window))

+ 9 - 0
src/main/frontend/state.cljs

@@ -72,6 +72,7 @@
     :editor/pos 0
     :editor/content {}
     :editor/block nil
+    :editor/block-dom-id nil
     :editor/set-timestamp-block nil
     :cursor-range nil
 
@@ -585,6 +586,14 @@
   (set-state! :ui/theme theme)
   (storage/set :ui/theme theme))
 
+(defn set-editing-block-dom-id!
+  [block-dom-id]
+  (set-state! :editor/block-dom-id block-dom-id))
+
+(defn get-editing-block-dom-id
+  []
+  (:editor/block-dom-id @state))
+
 (defn toggle-theme!
   []
   (let [theme (:ui/theme @state)