浏览代码

feat: preserve expand/collapse state

Also, fixed several issues related to data migration
Tienson Qin 4 年之前
父节点
当前提交
402c5db938

+ 18 - 30
src/main/frontend/components/block.cljs

@@ -14,7 +14,6 @@
             [dommy.core :as d]
             [datascript.core :as dc]
             [goog.dom :as gdom]
-            [frontend.handler.expand :as expand]
             [frontend.components.svg :as svg]
             [frontend.components.datetime :as datetime-comp]
             [frontend.ui :as ui]
@@ -1019,12 +1018,12 @@
                                 :path-params {:name (str uuid)}}))))
 
 (rum/defcs block-control < rum/reactive
-  [state config block uuid block-id body children dummy? *control-show? *collapsed?]
+  [state config block uuid block-id body children dummy? *control-show?]
   (let [has-child? (and
                     (not (:pre-block? block))
                     (or (seq children)
                         (seq body)))
-        collapsed? (rum/react *collapsed?)
+        collapsed? (get (:block/properties block) :collapsed)
         control-show? (util/react *control-show?)
         dark? (= "dark" (state/sub :ui/theme))]
     [:div.mr-2.flex.flex-row.items-center
@@ -1039,10 +1038,8 @@
                :margin-right 2}
        :on-click (fn [e]
                    (util/stop e)
-                   (if collapsed?
-                     (expand/expand! block)
-                     (expand/collapse! block))
-                   (reset! *collapsed? (not collapsed?)))}
+                   (when-not (and (not collapsed?) (not has-child?))
+                       (editor-handler/set-block-property! uuid :collapsed (not collapsed?))))}
       (cond
         (and control-show? collapsed?)
         (svg/caret-right)
@@ -1407,8 +1404,9 @@
   (editor-handler/unhighlight-blocks!))
 
 (rum/defc block-content < rum/reactive
-  [config {:block/keys [uuid title body meta content marker dummy? page format repo children pre-block? properties collapsed? idx container block-refs-count scheduled deadline repeated?] :as block} edit-input-id block-id slide?]
-  (let [dragging? (rum/react *dragging?)
+  [config {:block/keys [uuid title body meta content marker dummy? page format repo children pre-block? properties idx container block-refs-count scheduled deadline repeated?] :as block} edit-input-id block-id slide?]
+  (let [collapsed? (get properties :collapsed)
+        dragging? (rum/react *dragging?)
         content (if (string? content) (string/trim content) "")
         mouse-down-key (if (util/ios?)
                          :on-click
@@ -1478,12 +1476,12 @@
      (when (and (= marker "DONE")
                 (state/enable-timetracking?))
        (let [start-time (or
-                         (get properties "now")
-                         (get properties "doing")
-                         (get properties "in-progress")
-                         (get properties "later")
-                         (get properties "todo"))
-             finish-time (get properties "done")]
+                         (get properties :now)
+                         (get properties :doing)
+                         (get properties :in-progress)
+                         (get properties :later)
+                         (get properties :todo))
+             finish-time (get properties :done)]
          (when (and start-time finish-time (> finish-time start-time))
            [:div.text-sm.absolute.time-spent {:style {:top 0
                                                       :right 0
@@ -1493,7 +1491,7 @@
              (utils/timeConversion (- finish-time start-time))]])))]))
 
 (rum/defc block-content-or-editor < rum/reactive
-  [config {:block/keys [uuid title body meta content dummy? page format repo children pre-block? collapsed? idx] :as block} edit-input-id block-id slide?]
+  [config {:block/keys [uuid title body meta content dummy? page format repo children pre-block? idx] :as block} edit-input-id block-id slide?]
   (let [edit? (state/sub [:editor/editing? edit-input-id])
         editor-box (get config :editor-box)]
     (if (and edit? editor-box)
@@ -1653,23 +1651,13 @@
 
 (rum/defcs block-container < rum/static
   {:init (fn [state]
-           (let [block (last (:rum/args state))
-                 collapsed? (:block/collapsed? block)]
-             (assoc state
-                    ::control-show? (atom false)
-                    ::collapsed? (atom collapsed?))))
-   :did-mount (fn [state]
-                (let [block (nth (:rum/args state) 1)
-                      collapsed? (:block/collapsed? block)]
-                  (when collapsed?
-                    (expand/collapse! block))
-                  state))
+           (assoc state ::control-show? (atom false)))
    :should-update (fn [old-state new-state]
                     (not= (:block/content (second (:rum/args old-state)))
                           (:block/content (second (:rum/args new-state)))))}
-  [state config {:block/keys [uuid title body meta content dummy? page format repo children collapsed? pre-block? top? properties refs-with-children] :as block}]
+  [state config {:block/keys [uuid title body meta content dummy? page format repo children pre-block? top? properties refs-with-children] :as block}]
   (let [*control-show? (get state ::control-show?)
-        *collapsed? (get state ::collapsed?)
+        collapsed? (get properties :collapsed)
         ref? (boolean (:ref? config))
         breadcrumb-show? (:breadcrumb-show? config)
         sidebar? (boolean (:sidebar? config))
@@ -1709,7 +1697,7 @@
 
      [:div.flex-1.flex-row
       (when (not slide?)
-        (block-control config block uuid block-id body children dummy? *control-show? *collapsed?))
+        (block-control config block uuid block-id body children dummy? *control-show?))
 
       (let [edit-input-id (str "edit-block-" unique-dom-id uuid)]
         (block-content-or-editor config block edit-input-id block-id slide?))]

+ 4 - 4
src/main/frontend/components/content.cljs

@@ -113,9 +113,9 @@
                                        [:p "Template already exists!"]
                                        :error)
                                       (do
-                                        (editor-handler/set-block-property! block-id "template" title)
+                                        (editor-handler/set-block-property! block-id :template title)
                                         (when (false? including-parent?)
-                                          (editor-handler/set-block-property! block-id "including-parent" false))
+                                          (editor-handler/set-block-property! block-id :including-parent false))
                                         (state/hide-custom-context-menu!)))))))])
       (ui/menu-link
        {:key "Make template"
@@ -136,14 +136,14 @@
             (for [color block-background-colors]
               [:a.m-2.shadow-sm
                {:on-click (fn [_e]
-                            (editor-handler/set-block-property! block-id :background-color color))}
+                            (editor-handler/set-block-property! block-id "background-color" color))}
                [:div.heading-bg {:style {:background-color color}}]])]
            [:a.text-sm
             {:title (t :remove-background)
              :style {:margin-right 14
                      :margin-top 4}
              :on-click (fn [_e]
-                         (editor-handler/remove-block-property! block-id :background-color))}
+                         (editor-handler/remove-block-property! block-id "background-color"))}
             "Clear"]]
           (let [empty-properties? (not (text/contains-properties? (:block/content block)))
                 all-hidden? (text/properties-hidden? (:block/properties block))]

+ 2 - 2
src/main/frontend/db/model.cljs

@@ -1141,7 +1141,7 @@
 (defn get-all-templates
   []
   (let [pred (fn [db properties]
-               (some? (get properties "template")))]
+               (some? (:template properties)))]
     (->> (d/q
           '[:find ?b ?p
             :in $ ?pred
@@ -1151,7 +1151,7 @@
           (conn/get-conn)
           pred)
          (map (fn [[e m]]
-                [(get m "template") e]))
+                [(get m :template) e]))
          (into {}))))
 
 (defonce blocks-count-cache (atom nil))

+ 2 - 2
src/main/frontend/db/query_dsl.cljs

@@ -224,7 +224,7 @@
                    '?v
                      (uniq-symbol counter "?v"))]
          [['?b :block/properties '?prop]
-          [(list 'get '?prop (name (nth e 1))) sym]
+          [(list 'get '?prop (keyword (nth e 1))) sym]
           (list
            'or
            [(list '= sym v)]
@@ -233,7 +233,7 @@
        (and (= 'property fe)
             (= 2 (count e)))
        [['?b :block/properties '?prop]
-        [(list 'get '?prop (name (nth e 1)))]]
+        [(list 'get '?prop (keyword (nth e 1)))]]
 
        (= 'todo fe)
        (let [markers (if (coll? (first (rest e)))

+ 0 - 1
src/main/frontend/db_schema.cljs

@@ -130,6 +130,5 @@
     :block/scheduled
     :block/deadline
     :block/repeated?
-    :block/properties
     }
   )

+ 31 - 22
src/main/frontend/format/block.cljs

@@ -158,7 +158,7 @@
    (:name (first (second block)))))
 
 (defonce non-parsing-properties
-  (atom #{:background-color}))
+  (atom #{"background-color" "background_color"}))
 
 (defn extract-properties
   [[_ properties] _start-pos _end-pos]
@@ -179,25 +179,33 @@
                         (medley/map-kv (fn [k v]
                                          (let [v (string/trim v)
                                                k (string/replace k " " "-")
-                                               k (string/replace k "_" "-")]
-                                           (cond
-                                             (and (= "\"" (first v) (last v))) ; wrapped in ""
-                                             [(string/lower-case k) (string/trim (subs v 1 (dec (count v))))]
-
-                                             (contains? @non-parsing-properties (string/lower-case k))
-                                             [(string/lower-case k) v]
-
-                                             :else
-                                             (let [k' (and k (string/trim (string/lower-case k)))
-                                                   v' v
-                                                   ;; built-in collections
-                                                   comma? (contains? #{"tags" "alias"} k)
-                                                   v' (if (and k' v'
-                                                               (contains? config/markers k')
-                                                               (util/safe-parse-int v'))
-                                                        (util/safe-parse-int v')
-                                                        (text/split-page-refs-without-brackets v' comma?))]
-                                               [k' v']))))))]
+                                               k (string/replace k "_" "-")
+                                               k (string/lower-case k)
+                                               v (cond
+                                                   (= v "true")
+                                                   true
+                                                   (= v "false")
+                                                   false
+
+                                                   (re-find #"^\d+$" v)
+                                                   (util/safe-parse-int v)
+
+                                                   (and (= "\"" (first v) (last v))) ; wrapped in ""
+                                                   (string/trim (subs v 1 (dec (count v))))
+
+                                                   (contains? @non-parsing-properties (string/lower-case k))
+                                                   v
+
+                                                   :else
+                                                   (let [v' v
+                                                         ;; built-in collections
+                                                         comma? (contains? #{"tags" "alias"} k)]
+                                                     (if (and k v'
+                                                              (contains? config/markers k)
+                                                              (util/safe-parse-int v'))
+                                                       (util/safe-parse-int v')
+                                                       (text/split-page-refs-without-brackets v' comma?))))]
+                                           [(keyword k) v]))))]
     {:properties properties
      :page-refs page-refs}))
 
@@ -427,8 +435,9 @@
                   (recur headings block-body (rest blocks) timestamps properties last-pos last-level children))
 
                 (heading-block? block)
-                (let [id (or (when-let [custom-id (or (get-in properties [:properties "custom_id"])
-                                                      (get-in properties [:properties "id"]))]
+                (let [id (or (when-let [custom-id (or (get-in properties [:properties :custom-id])
+                                                      (get-in properties [:properties :custom_id])
+                                                      (get-in properties [:properties :id]))]
                                (let [custom-id (string/trim custom-id)]
                                  (when (util/uuid-string? custom-id)
                                    (uuid custom-id))))

+ 7 - 20
src/main/frontend/handler.cljs

@@ -46,10 +46,6 @@
   []
   (storage/set :db-schema db-schema/schema))
 
-(defn refactored-version?
-  []
-  (:block/name (storage/get :db-schema)))
-
 (defn- get-me-and-repos
   []
   (let [me (and js/window.user (bean/->clj js/window.user))
@@ -152,17 +148,10 @@
             (when-not config/dev? (init-sentry)))]
     (set! js/window.onload f)))
 
-(defn clear-stores-and-init!
-  [me logged?]
-  (let [example-repo {:url config/local-repo
-                      :example? true}]
-    (p/let [repos (get-repos)]
-      (doseq [repo (distinct (conj repos example-repo))]
-        (repo-handler/remove-repo! repo))
-      (p/let [_ (idb/clear-local-storage-and-idb!)
-              repos [example-repo]]
-        (state/set-repos! repos)
-        (restore-and-setup! me repos logged?)))))
+(defn clear-stores-and-refresh!
+  []
+  (p/let [_ (idb/clear-local-storage-and-idb!)]
+    (js/window.location.reload)))
 
 (defn start!
   [render]
@@ -180,11 +169,9 @@
 
     (events/run!)
 
-    (if-not (refactored-version?)
-      (clear-stores-and-init! me logged?)
-      (p/let [repos (get-repos)]
-        (state/set-repos! repos)
-        (restore-and-setup! me repos logged?)))
+    (p/let [repos (get-repos)]
+      (state/set-repos! repos)
+      (restore-and-setup! me repos logged?))
 
     (reset! db/*sync-search-indice-f search/sync-search-indice!)
     (db/run-batch-txs!)

+ 0 - 34
src/main/frontend/handler/block.cljs

@@ -25,40 +25,6 @@
            block)]
     @ids))
 
-(defn collapse-block!
-  [block]
-  (let [repo (:block/repo block)]
-    (db/transact! repo
-      [{:block/uuid (:block/uuid block)
-        :block/collapsed? true}])))
-
-(defn collapse-blocks!
-  [block-ids]
-  (let [repo (state/get-current-repo)]
-    (db/transact! repo
-      (map
-        (fn [id]
-          {:block/uuid id
-           :block/collapsed? true})
-        block-ids))))
-
-(defn expand-block!
-  [block]
-  (let [repo (:block/repo block)]
-    (db/transact! repo
-      [{:block/uuid (:block/uuid block)
-        :block/collapsed? false}])))
-
-(defn expand-blocks!
-  [block-ids]
-  (let [repo (state/get-current-repo)]
-    (db/transact! repo
-      (map
-        (fn [id]
-          {:block/uuid id
-           :block/collapsed? false})
-        block-ids))))
-
 ;; TODO: should we remove this dummy block and use the page's root block instead?
 (defn with-dummy-block
   ([blocks format]

+ 27 - 18
src/main/frontend/handler/editor.cljs

@@ -9,7 +9,6 @@
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.repo :as repo-handler]
             [frontend.handler.notification :as notification]
-            [frontend.handler.expand :as expand]
             [frontend.handler.block :as block-handler]
             [frontend.format.mldoc :as mldoc]
             [frontend.format :as format]
@@ -325,7 +324,7 @@
          e (db/entity repo [:block/uuid uuid])
          format (or format (state/get-preferred-format))
          page (db/entity repo (:db/id page))
-         block-id (when (map? properties) (get properties "id"))]
+         block-id (when (map? properties) (get properties :id))]
      (cond
        (another-block-with-same-id-exists? uuid block-id)
        (notification/show!
@@ -727,14 +726,16 @@
 
 (defn remove-block-property!
   [block-id key]
-  (block-property-aux! block-id key nil)
+  (let [key (keyword key)]
+    (block-property-aux! block-id key nil))
   (db/refresh! (state/get-current-repo)
                {:key :block/change
                 :data [(db/pull [:block/uuid block-id])]}))
 
 (defn set-block-property!
   [block-id key value]
-  (block-property-aux! block-id key value)
+  (let [key (keyword key)]
+    (block-property-aux! block-id key value))
   (db/refresh! (state/get-current-repo)
                {:key :block/change
                 :data [(db/pull [:block/uuid block-id])]}))
@@ -1521,22 +1522,30 @@
 (defn expand!
   []
   (when-let [current-block (state/get-edit-block)]
-    (expand/expand! current-block)))
+    (remove-block-property! (:block/uuid current-block) :collapsed)))
 
 (defn collapse!
   []
   (when-let [current-block (state/get-edit-block)]
-    (expand/collapse! current-block)))
+    (set-block-property! (:block/uuid current-block) :collapsed true)))
 
+;; TODO:
 (defn cycle-collapse!
   [e]
-  (when (and
-         ;; not input, t
-         (nil? (state/get-edit-input-id))
-         (not (state/get-editor-show-input))
-         (string/blank? (:search/q @state/state)))
-    (util/stop e)
-    (expand/cycle!)))
+  ;; (let [current-page (state/get-current-page)]
+  ;;   (when (and
+  ;;         ;; not input, t
+  ;;         (nil? (state/get-edit-input-id))
+  ;;         (not (state/get-editor-show-input))
+  ;;         (string/blank? (:search/q @state/state))
+  ;;         current-page)
+  ;;    (util/stop e)
+  ;;    (let [page (db/pull [:block/name (string/lower-case current-page)])
+  ;;          collapsed? (boolean (get (:block/properties page) :collapsed))]
+  ;;      (prn {:current-page current-page
+  ;;            :collapsed? collapsed?})
+  ;;      (set-block-property! (:block/uuid page) :collapsed (not collapsed?)))))
+  )
 
 (defn on-tab
   "direction = :left|:right, only indent or outdent when blocks are siblings"
@@ -1740,7 +1749,7 @@
 
       ;; Save it so it'll be parsed correctly in the future
       (set-block-property! (:block/uuid chosen)
-                           "ID"
+                           :id
                            uuid-string)
 
       (when-let [input (gdom/getElement id)]
@@ -1800,8 +1809,8 @@
                                                    :block/file (select-keys file [:db/id])
                                                    :block/format format
                                                    :block/properties (apply dissoc (:block/properties %)
-                                                                            (concat ["id" "custom_id"]
-                                                                                    exclude-properties))
+                                                                       (concat [:id :custom_id :custom-id]
+                                                                               exclude-properties))
                                                    :block/meta (dissoc (:block/meta %) :start-pos :end-pos)
                                                    :block/content new-content
                                                    :block/title new-title}
@@ -1827,11 +1836,11 @@
     (let [repo (state/get-current-repo)
           block (db/entity db-id)
           block-uuid (:block/uuid block)
-          including-parent? (not= "false" (get (:block/properties block) "including-parent"))
+          including-parent? (not (false? (:including-parent (:block/properties block))))
           blocks (if including-parent? (db/get-block-and-children repo block-uuid) (db/get-block-children repo block-uuid))
           level-blocks-map (blocks-with-level blocks)
           tree (blocks-vec->tree (vals level-blocks-map))]
-      (paste-block-tree-at-point tree ["template" "including-parent"]
+      (paste-block-tree-at-point tree [:template :including-parent]
                                  (fn [content]
                                    (-> content
                                        (text/remove-property "template")

+ 0 - 102
src/main/frontend/handler/expand.cljs

@@ -1,102 +0,0 @@
-(ns frontend.handler.expand
-  (:require [dommy.core :as d]
-            [goog.dom :as gdom]
-            [goog.object :as gobj]
-            [frontend.util :as util]
-            [frontend.state :as state]
-            [frontend.handler.block :as block-handler]))
-
-(defn- hide!
-  [element]
-  (d/set-style! element :display "none"))
-
-(defn- show!
-  [element]
-  (d/set-style! element :display ""))
-
-(defn collapse!
-  [block]
-  (let [has-title? (seq (:block/title block))
-        uuid (:block/uuid block)
-        nodes (array-seq (js/document.getElementsByClassName (str uuid)))]
-    (doseq [node nodes]
-      (d/add-class! node "collapsed")
-      (when has-title?
-        (when-let [e (.querySelector node ".block-body")]
-         (hide! e)))
-      (when-let [e (.querySelector node ".block-children")]
-        (hide! e)
-        (let [elements (d/by-class node "ls-block")]
-          (doseq [element elements]
-            (hide! element))))
-      (block-handler/collapse-block! block))))
-
-(defn expand!
-  [block]
-  (let [uuid (:block/uuid block)
-        nodes (array-seq (js/document.getElementsByClassName (str uuid)))]
-    (doseq [node nodes]
-      (when-let [e (.querySelector node ".block-body")]
-        (show! e))
-      (when-let [e (.querySelector node ".block-children")]
-        (let [elements (d/by-class node "ls-block")]
-          (doseq [element elements]
-            (show! element)))
-        (show! e))
-      (block-handler/expand-block! block))))
-
-(defn set-bullet-closed!
-  [element]
-  (when element
-    (when-let [node (.querySelector element ".bullet-container")]
-      (d/add-class! node "bullet-closed"))))
-
-;; Collapse acts like TOC
-;; There are three modes to cycle:
-;; 1. Collapse all blocks which levels are greater than 2
-;; 2. Hide all block's body (user can still see the block title)
-;; 3. Show everything
-(defn cycle!
-  []
-  (let [mode (state/next-collapse-mode)
-        get-blocks (fn []
-                     (let [elements (d/by-class "ls-block")
-                           result (group-by (fn [e]
-                                              (let [level (d/attr e "level")]
-                                                (and level
-                                                     (> (util/parse-int level) 2)))) elements)]
-                       [(get result true) (get result false)]))]
-    (case mode
-      :show-all
-      (do
-        (doseq [element (d/by-class "ls-block")]
-          (show! element))
-        (let [elements (d/by-class "block-body")]
-          (doseq [element elements]
-            (show! element)))
-        (doseq [element (d/by-class "bullet-closed")]
-          (d/remove-class! element "bullet-closed"))
-        (doseq [element (d/by-class "block-children")]
-          (show! element)))
-
-      :hide-block-body
-      (let [elements (d/by-class "block-body")]
-        (doseq [element elements]
-          (d/set-style! element :display "none")
-          (when-let [parent (util/rec-get-block-node element)]
-            (set-bullet-closed! parent))))
-
-      :hide-block-children
-      (let [[elements top-level-elements] (get-blocks)
-            level-2-elements (filter (fn [e]
-                                       (let [level (d/attr e "level")]
-                                         (and level
-                                              (= (util/parse-int level) 2)
-                                              (not (d/has-class? e "pre-block")))))
-                                     top-level-elements)]
-        (doseq [element elements]
-          (hide! element))
-        (doseq [element level-2-elements]
-          (when (= "true" (d/attr element "haschild"))
-            (set-bullet-closed! element)))))
-    (state/cycle-collapse!)))

+ 21 - 12
src/main/frontend/handler/web/nfs.cljs

@@ -19,7 +19,9 @@
             [frontend.db.model :as db-model]
             [frontend.config :as config]
             [lambdaisland.glogi :as log]
-            [frontend.encrypt :as encrypt]))
+            [frontend.encrypt :as encrypt]
+            [frontend.search :as search]
+            [frontend.storage :as storage]))
 
 (defn remove-ignore-files
   [files]
@@ -278,25 +280,32 @@
         (p/finally (fn [_]
                      (state/set-graph-syncing? false))))))))
 
-(defn refresh!
-  [repo ok-handler]
-  (when repo
-    (state/set-nfs-refreshing! true)
-    (p/let [_ (reload-dir! repo)
-            _ (ok-handler)]
-      (state/set-nfs-refreshing! false))))
-
 (defn rebuild-index!
   [repo ok-handler]
   (when repo
     (state/set-nfs-refreshing! true)
-
-    ;; TODO: What about other relationships?
-    (db-model/remove-all-aliases! repo)
+    (search/reset-indice! repo)
+    (db/remove-conn! repo)
+    (db/clear-query-state!)
+    (db/start-db-conn! (state/get-me) repo)
     (p/let [_ (reload-dir! repo true)
             _ (ok-handler)]
       (state/set-nfs-refreshing! false))))
 
+(defn refactored-version?
+  []
+  (:block/name (storage/get :db-schema)))
+
+(defn refresh!
+  [repo ok-handler]
+  (if (refactored-version?)
+    (rebuild-index! repo ok-handler)
+    (when repo
+      (state/set-nfs-refreshing! true)
+      (p/let [_ (reload-dir! repo)
+              _ (ok-handler)]
+        (state/set-nfs-refreshing! false)))))
+
 (defn supported?
   []
   (or (utils/nfsSupported) (util/electron?)))

+ 2 - 1
src/main/frontend/search.cljs

@@ -120,7 +120,8 @@
                   (fn [{:keys [item]}]
                     (:name item))
                  result)
-                (remove nil?))))))))
+                (remove nil?)
+                (util/distinct-by :name))))))))
 
 (defn file-search
   ([q]

+ 3 - 3
src/main/frontend/text.cljs

@@ -137,7 +137,7 @@
 
 (def hidden-properties
   (set/union
-   #{:id :custom-id :background-color :heading}
+   #{:id :custom-id :background-color :heading :collapsed}
    config/markers))
 
 (defn properties-hidden?
@@ -195,8 +195,8 @@
                         :or {remove-blank? true
                              block-with-title? true}}]
    (let [content (string/triml content)
-         properties (if (= (get properties "heading") "false")
-                      (dissoc properties "heading")
+         properties (if (false? (get properties :heading))
+                      (dissoc properties :heading)
                       properties)
          properties (if remove-blank?
                       (remove (fn [[k _v]] (string/blank? k)) properties)