Browse Source

fix: scroll the view when selecting multiple blocks (#9444)

Giuseppe D'Andrea 2 years ago
parent
commit
6bf8dcebec
2 changed files with 37 additions and 25 deletions
  1. 14 15
      src/main/frontend/handler/editor.cljs
  2. 23 10
      src/main/frontend/util.cljc

+ 14 - 15
src/main/frontend/handler/editor.cljs

@@ -1193,10 +1193,6 @@
       (common-handler/copy-to-clipboard-without-id-property! (:block/format block) md-content html sorted-blocks)
       (delete-block-aux! block true))))
 
-(defn clear-last-selected-block!
-  []
-  (state/drop-last-selection-block!))
-
 (defn highlight-selection-area!
   [end-block]
   (when-let [start-block (state/get-selection-start-block-or-first)]
@@ -1212,13 +1208,17 @@
   (cond
     ;; when editing, quit editing and select current block
     (state/editing?)
-    (state/exit-editing-and-set-selected-blocks! [(gdom/getElement (state/get-editing-block-dom-id))])
+    (let [element (gdom/getElement (state/get-editing-block-dom-id))]
+      (when element
+        (util/scroll-to-block element)
+        (state/exit-editing-and-set-selected-blocks! [element])))
 
     ;; when selection and one block selected, select next block
     (and (state/selection?) (== 1 (count (state/get-selection-blocks))))
     (let [f (if (= :up direction) util/get-prev-block-non-collapsed util/get-next-block-non-collapsed-skip)
           element (f (first (state/get-selection-blocks)))]
       (when element
+        (util/scroll-to-block element)
         (state/conj-selection-block! element direction)))
 
     ;; if same direction, keep conj on same direction
@@ -1227,11 +1227,17 @@
           first-last (if (= :up direction) first last)
           element (f (first-last (state/get-selection-blocks)))]
       (when element
+        (util/scroll-to-block element)
         (state/conj-selection-block! element direction)))
 
     ;; if different direction, keep clear until one left
     (state/selection?)
-    (clear-last-selected-block!))
+    (let [f (if (= :up direction) util/get-prev-block-non-collapsed util/get-next-block-non-collapsed)
+          last-first (if (= :up direction) last first)
+          element (f (last-first (state/get-selection-blocks)))]
+      (when element
+        (util/scroll-to-block element)
+        (state/drop-last-selection-block!))))
   nil)
 
 (defn on-select-block
@@ -2482,13 +2488,6 @@
       (.preventDefault e)
       (keydown-new-line))))
 
-(defn- scroll-to-block
-  [block]
-  (when block
-    (when-not (util/element-visible? block)
-      (.scrollIntoView block #js {:behavior "smooth"
-                                  :block "center"}))))
-
 (defn- select-first-last
   "Select first or last block in viewpoint"
   [direction]
@@ -2496,7 +2495,7 @@
         block (->> (util/get-blocks-noncollapse)
                    (f))]
     (when block
-      (scroll-to-block block)
+      (util/scroll-to-block block)
       (state/exit-editing-and-set-selected-blocks! [block]))))
 
 (defn- select-up-down [direction]
@@ -2509,7 +2508,7 @@
             :down util/get-next-block-non-collapsed)
         sibling-block (f selected)]
     (when (and sibling-block (dom/attr sibling-block "blockid"))
-      (scroll-to-block sibling-block)
+      (util/scroll-to-block sibling-block)
       (state/exit-editing-and-set-selected-blocks! [sibling-block]))))
 
 (defn- move-cross-boundary-up-down

+ 23 - 10
src/main/frontend/util.cljc

@@ -405,6 +405,16 @@
                 %))
            (take-while (complement nil?) (iterate #(.-parentElement %) element)))))
 
+#?(:cljs
+   (defn element-visible?
+     [element]
+     (when element
+       (when-let [r (.getBoundingClientRect element)]
+         (and (>= (.-top r) 0)
+              (<= (+ (.-bottom r) 64)
+                  (or (.-innerHeight js/window)
+                      (js/document.documentElement.clientHeight))))))))
+
 #?(:cljs
    (defn element-top [elem top]
      (when elem
@@ -455,6 +465,19 @@
      ([animate?]
       (scroll-to (app-scroll-container-node) 0 animate?))))
 
+#?(:cljs
+   (defn scroll-to-block
+     "Scroll into the view to vertically align a non-visible block to the centre
+     of the visible area"
+     ([block]
+      (scroll-to-block block true))
+     ([block animate?]
+      (when block
+        (when-not (element-visible? block)
+          (.scrollIntoView block
+                           #js {:behavior (if animate? "smooth" "auto")
+                                :block    "center"}))))))
+
 #?(:cljs
    (defn link?
      [node]
@@ -1404,16 +1427,6 @@
       (fn [resolve]
         (load url resolve)))))
 
-#?(:cljs
-   (defn element-visible?
-     [element]
-     (when element
-       (when-let [r (.getBoundingClientRect element)]
-         (and (>= (.-top r) 0)
-              (<= (+ (.-bottom r) 64)
-                  (or (.-innerHeight js/window)
-                      (js/document.documentElement.clientHeight))))))))
-
 #?(:cljs
    (defn copy-image-to-clipboard
      [src]