rcmerci 4 роки тому
батько
коміт
4e76f78fd8

+ 4 - 4
src/main/frontend/handler/editor.cljs

@@ -754,7 +754,7 @@
     (when block
       (->
        (outliner-core/block block)
-       (outliner-core/delete-node children?))
+       (outliner-yjs/delete-node-op children?))
       (db/refresh! repo {:key :block/change :data [block]}))))
 
 (defn- move-to-prev-block
@@ -1713,7 +1713,7 @@
                 top-level-nodes (->> (filter #(= (get-in end-node-parent [:data :db/id])
                                                  (get-in % [:block/parent :db/id])) blocks)
                                      (map outliner-core/block))]
-            (outliner-core/indent-outdent-nodes top-level-nodes (= direction :right))
+            (outliner-yjs/indent-outdent-nodes-op top-level-nodes (= direction :right))
             (let [opts {:key :block/change
                         :data blocks}]
               (db/refresh! repo opts)
@@ -2033,7 +2033,7 @@
             _ (outliner-yjs/insert-nodes-op metadata-replaced-blocks target-block sibling?)
             _ (when (and delete-editing-block? editing-block)
                 (when-let [id (:db/id editing-block)]
-                  (outliner-core/delete-node (outliner-core/block (db/pull id)) true)))
+                  (outliner-yjs/delete-node-op (outliner-core/block (db/pull id)) true)))
             new-blocks (db/pull-many repo '[*] (map (fn [id] [:block/uuid id]) @new-block-uuids))]
         (db/refresh! repo {:key :block/insert :data new-blocks})
         (last metadata-replaced-blocks)))))
@@ -2518,7 +2518,7 @@
   (let [{:keys [block]} (get-state)]
     (when block
       (let [current-node (outliner-core/block block)]
-        (outliner-core/indent-outdent-nodes [current-node] indent?)
+        (outliner-yjs/indent-outdent-nodes-op [current-node] indent?)
         (let [repo (state/get-current-repo)]
           (db/refresh! repo
                        {:key :block/change :data [(:data current-node)]}))))

+ 145 - 94
src/main/frontend/modules/outliner/yjs.cljs

@@ -18,6 +18,9 @@
 (def doc-local (y/Doc.))
 (def doc-remote (y/Doc.))
 
+(def syncing-pages (atom #{}))
+
+
 (def wsProvider1 (y-ws/WebsocketProvider. "ws://localhost:1234", "test-user", doc-remote))
 
 (defn- contentmap [] (.getMap doc-local "content"))
@@ -27,7 +30,11 @@
 (defn- remote-structarray [page-name] (.getArray doc-remote (str page-name "-struct")))
 
 (defn- assoc-contents [contents contentmap]
-  (mapv (fn [[k v]] (.set contentmap k v)) contents))
+  (mapv (fn [[k v]]  (.set contentmap k v)) contents))
+
+(defn- dissoc-contents [ids contentmap]
+  (mapv (fn [id] (.delete contentmap id)) ids))
+
 
 (defn- distinct-struct [struct id-set]
   (loop [i 0]
@@ -111,10 +118,10 @@
     (let [content-map (contentmap)
           format (or (:block/format block) :markdown)
           new-content (.toString (.get content-map id)) ;TODO orgmode
-          updated-block (content->block new-content format nil)]
+          updated-block (content->block new-content format {:block/page (:block/page block)})]
       (def www updated-block)
       (outliner-core/save-node (outliner-core/block updated-block))
-      (db/refresh! (state/get-current-repo) {:key :block/insert :data [updated-block]}))))
+      (db/refresh! (state/get-current-repo) {:key :block/change :data [updated-block]}))))
 
 (defn- get-item-left&parent [item id]
   (let [item-content id
@@ -186,8 +193,7 @@
         target-node (outliner-core/block target-block)
         new-block (content->block content format
                                   {:block/page (:block/page target-block)
-                                   :block/uuid (uuid id)
-                                   :block/format format} )
+                                   :block/uuid (uuid id)} )
         new-node (outliner-core/block new-block)
         sibling? (not= parent-id left-id)]
     (def zzz [new-node target-node sibling?])
@@ -195,9 +201,10 @@
     (db/refresh! (state/get-current-repo) {:key :block/insert :data [new-block]})))
 
 (defn- delete-node [id]
+  (println "[YJS] delete-node" id)
   (when-let [block (db-model/query-block-by-uuid id)]
     (outliner-core/delete-node (outliner-core/block block) false)
-    true))
+    (db/refresh! (state/get-current-repo)  {:key :block/change :data [block]})))
 
 (defn- observe-struct-fn [page-name]
   (fn [events]
@@ -206,7 +213,6 @@
           contentmap (contentmap)]
       (mapv
        (fn [item]
-         (def yyy item)
          (mapv (fn [id]
                  (println "observe-struct-fn id:" id)
                  (let [[left-id parent-id] (get-item-left&parent item id)
@@ -221,6 +227,8 @@
 (def observe-struct-fn-memo (memoize observe-struct-fn))
 
 (defn- observe-content-fn [event]
+  (println "[YJS] observe-content-fn")
+  (js/console.log event)
   (when-not (.-local (.-transaction event))
     (let [keys (js->clj (into [] (.-keys event)))]
       (mapv (fn [[k v]]
@@ -252,10 +260,7 @@
 
 (defn sync-doc [local remote]
   (.on remote "update" (fn [update]
-                         (y/applyUpdate local update)))
-  ;; (.on local "update" (fn [update]
-  ;;                       (y/applyUpdate remote update)))
-  )
+                         (y/applyUpdate local update))))
 
 
 (defn- remove-all-blocks-in-page [page-blocks page-name]
@@ -347,29 +352,38 @@
       s
       (recur (inc i) (.get s (get pos i))))))
 
+
+
 (deftype Pos [pos-vec]
 
   Object
   (toString [_] pos-vec)
 
+  ;; [1 2 3] -> [1 2 4]
   (inc-pos [_] (Pos. (conj (vec (butlast pos-vec)) (inc (last pos-vec)))))
+  ;; [1 2 3] -> [1 2 4 0]
   (inc-level-pos [_] (Pos. (conj (Pos. (conj (vec (butlast pos-vec)) (inc (last pos-vec)))) 0)))
+  ;; [1 2 3] -> [1 2 3 0]
   (add-next-level [_] (Pos. (conj pos-vec 0)))
+  ;; [1 2 3] -> [1 2]
+  (upper-level [_]
+    (when-some [pos-vec* (butlast pos-vec)]
+      (Pos. pos-vec*)))
 
   (next-sibling-pos [_ struct]
     (let [inner-struct (goto-innermost-struct-array pos-vec struct)
           next-item (.get inner-struct (inc (last pos-vec)))]
-    (if (instance? y/Array next-item)
-      (Pos. (conj (vec (butlast pos-vec)) (+ 2 (last pos-vec))))
-      (Pos. (conj (vec (butlast pos-vec)) (+ 1 (last pos-vec)))))))
+      (if (instance? y/Array next-item)
+        (Pos. (conj (vec (butlast pos-vec)) (+ 2 (last pos-vec))))
+        (Pos. (conj (vec (butlast pos-vec)) (+ 1 (last pos-vec)))))))
 
   (next-non-sibling-pos! [this struct]
     "create a y/Array when no child follows item at POS"
     (let [inner-struct (goto-innermost-struct-array this struct)
-        next-item (.get inner-struct (inc (last this)))]
-    (when-not (instance? y/Array next-item)
-      (.insert inner-struct (inc (last this)) (clj->js [(y/Array.)])))
-    (.inc-level-pos this)))
+          next-item (.get inner-struct (inc (last this)))]
+      (when-not (instance? y/Array next-item)
+        (.insert inner-struct (inc (last this)) (clj->js [(y/Array.)])))
+      (.inc-level-pos this)))
 
   ICounted
   (-count [_] (count pos-vec))
@@ -410,6 +424,17 @@
               (= nthi1 nthi2)
               (recur (inc i)))))))))
 
+(defn- delete-item [pos root-struct]
+  "Delete item at POS. Also delete struct when empty"
+  (let [inner-struct (goto-innermost-struct-array pos root-struct)
+        last-pos-index (last pos)]
+    (.delete inner-struct last-pos-index 1)
+    (when-some [upper-pos (.upper-level pos)]
+      (let [last-upper-pos-index (last upper-pos)]
+        (when (= 0 (.-length inner-struct))
+          (let [inner-upper-struct (goto-innermost-struct-array upper-pos root-struct)]
+            (.delete inner-upper-struct last-upper-pos-index 1)))))))
+
 (defn find-pos [struct id]
   (let [toplevel (js->clj (.toArray struct))
         index (.indexOf toplevel id)]
@@ -446,40 +471,14 @@
         (println e vec1 vec2)
         (js/console.trace)))))
 
-;; (defn distance [pos-vec1 pos-vec2]
-;;     "(distance [1 2] [1 4]) => [[[1 2] 3]] => [[prefix-of-THIS-pos length]]
-;; (distance [1 2 3 1] [1 4 1]) => [[[1 2 3 1] :all] [[1 2 4] :all] [[1 3] 1] [[1 4 0] 2]]"
-;;   (let [[same-prefix-vec pos-vec1* pos-vec2*] (common-prefix pos-vec1 pos-vec2)
-;;         r (transient [])]
-;;     (when (> (count pos-vec1*) 1)
-;;       (conj! r [(vec (concat same-prefix-vec pos-vec1*)) :all]))
-;;     (loop [sublen (dec (count pos-vec1*))]
-;;       (when (> sublen 1)
-;;         (let [prefix (vec (concat same-prefix-vec (subvec pos-vec1* 0 sublen)))
-;;               prefix* (conj (vec (butlast prefix)) (inc (last prefix)))]
-;;           (conj! r [prefix* :all])
-;;           (recur (dec sublen)))))
-;;     (let [prefix (vec (concat same-prefix-vec (subvec pos-vec1* 0 1)))
-;;           prefix* (conj (vec (butlast prefix)) (inc (last prefix)))]
-;;       (if-let [pos-vec2*-first (pos-vec2 0 nil)]
-;;         (conj! r [])
-;;         )
-;;       )
-
-;;     (persistent! r)
-;;     ))
-
-
-;;; outliner op + yjs op
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; outliner op + yjs op ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 ;; (defn move-subtree [root target-node sibling?]
 ;;   (outliner-core/move-subtree root target-node sibling?))
 
-
-;; (defn indent-outdent-nodes [nodes indent?]
-;;   )
-
-
 (defn- nodes-tree->struct&content [nodes-tree]
   (let [contents (atom {})
         struct (clojure.walk/postwalk
@@ -495,7 +494,6 @@
     [struct @contents]))
 
 
-
 (defn- insert-nodes-aux [insert-structs pos struct]
   "insert INSERT-STRUCTS at POS"
   (loop [i 0 pos pos]
@@ -512,8 +510,7 @@
           :else
           (do
             (.insert struct* (last pos) (clj->js [s]))
-            (recur (inc i) (.inc-pos pos)))))))
-    )
+            (recur (inc i) (.inc-pos pos))))))))
 
 
 (defn insert-nodes-yjs [page-name new-nodes-tree target-uuid sibling?]
@@ -556,41 +553,49 @@
             (catch js/Error e
               (println e)
               (println new-node target-node)
-              (js/console.trace)
-              )
-            )))))
-
-
-(defn- delete-range-nodes-prefix-part [prefix-vec start-pos-vec end-pos-vec struct]
-  (let [start-pos-vec-len (count start-pos-vec)]
-    ;; (when (> start-pos-vec-len 0))
-    (let [inner-struct (goto-innermost-struct-array (->Pos (vec (concat prefix-vec start-pos-vec))) struct)
-          start-index (last start-pos-vec)
-          len-to-remove (if (and (end-pos-vec 0 nil) (= start-pos-vec-len 1))
-                          (if (> (count end-pos-vec) 1)
-                            (- (end-pos-vec 0) start-index)
-                            (inc (- (end-pos-vec 0) start-index)))
-                          (- (.-length inner-struct) start-index))]
-      (.delete inner-struct start-index len-to-remove)
-      (if (>= start-pos-vec-len 2)
-        (delete-range-nodes-prefix-part [prefix-vec
+              (js/console.trace)))))))
+
+
+(defn- delete-range-nodes-prefix-part
+  ([prefix-vec start-pos-vec end-pos-vec struct] (delete-range-nodes-prefix-part prefix-vec start-pos-vec end-pos-vec struct false))
+  ([prefix-vec start-pos-vec end-pos-vec struct debug?]
+   (let [start-pos-vec-len (count start-pos-vec)]
+     ;; (when (> start-pos-vec-len 0))
+     (let [inner-struct (goto-innermost-struct-array (->Pos (vec (concat prefix-vec start-pos-vec))) struct)
+           start-index (last start-pos-vec)
+           len-to-remove (if (and (end-pos-vec 0 nil) (= start-pos-vec-len 1))
+                           (if (> (count end-pos-vec) 1)
+                             (- (end-pos-vec 0) start-index)
+                             (inc (- (end-pos-vec 0) start-index)))
+                           (- (.-length inner-struct) start-index))]
+       (if debug?
+         (println "delete: struct:" (.toJSON inner-struct)
+                  "start-index" start-index
+                  "len-to-remove" len-to-remove)
+         (.delete inner-struct start-index len-to-remove))
+       (if (>= start-pos-vec-len 2)
+         (delete-range-nodes-prefix-part prefix-vec
                                          (conj (subvec start-pos-vec 0 (- start-pos-vec-len 2))
                                                (inc (start-pos-vec (- start-pos-vec-len 2) nil)))
-                                         end-pos-vec struct])
-        len-to-remove))))
-
-
-(defn- delete-range-nodes-suffix-part [prefix-vec end-pos-vec struct]
-  (let [end-pos-vec-len (count end-pos-vec)]
-    (when (> end-pos-vec-len 0)
-      (let [inner-struct (goto-innermost-struct-array (->Pos (vec (concat prefix-vec end-pos-vec))) struct)]
-        (if (<= (dec (.-length inner-struct)) (last end-pos-vec))
-          (delete-range-nodes-suffix-part prefix-vec (butlast end-pos-vec) struct)
-          (when (>= end-pos-vec-len 2)
-            (let [next-end-pos-vec (conj (subvec end-pos-vec 0 (- end-pos-vec-len 2))
-                                         (dec (end-pos-vec (- end-pos-vec-len 2))))]
-              (.delete inner-struct 0 (inc (last end-pos-vec)))
-              (delete-range-nodes-suffix-part prefix-vec next-end-pos-vec struct))))))))
+                                         end-pos-vec struct debug?)
+         len-to-remove)))))
+
+
+(defn- delete-range-nodes-suffix-part
+  ([prefix-vec end-pos-vec struct] (delete-range-nodes-suffix-part prefix-vec end-pos-vec struct false))
+  ([prefix-vec end-pos-vec struct debug?]
+   (let [end-pos-vec-len (count end-pos-vec)]
+     (when (> end-pos-vec-len 0)
+       (let [inner-struct (goto-innermost-struct-array (->Pos (vec (concat prefix-vec end-pos-vec))) struct)]
+         (if (<= (dec (.-length inner-struct)) (last end-pos-vec))
+           (delete-range-nodes-suffix-part prefix-vec (butlast end-pos-vec) struct)
+           (when (>= end-pos-vec-len 2)
+             (let [next-end-pos-vec (conj (subvec end-pos-vec 0 (- end-pos-vec-len 2))
+                                          (dec (end-pos-vec (- end-pos-vec-len 2))))]
+               (if debug?
+                 (println "delete struct:" (.toJSON inner-struct) "len" (inc (last end-pos-vec)))
+                 (.delete inner-struct 0 (inc (last end-pos-vec))))
+               (delete-range-nodes-suffix-part prefix-vec next-end-pos-vec struct)))))))))
 
 (defn delete-range-nodes [start-pos end-pos struct]
   ;; {:pre [(<= (compare start-pos end-pos) 0)]}
@@ -601,12 +606,15 @@
           (delete-range-nodes-suffix-part same-prefix-vec pos-vec2*-after-delete-prefix-part struct))
         (delete-range-nodes-suffix-part same-prefix-vec pos-vec2* struct)))))
 
-(defn delete-nodes-yjs [page-name start-uuid end-uuid]
+(defn delete-nodes-yjs [page-name start-uuid end-uuid block-ids]
   (let [struct (structarray page-name)
         start-pos (find-pos struct (str start-uuid))
-        end-pos (find-pos struct (str end-uuid))]
-    (println "delete-nodes-yjs" start-uuid end-uuid)
-    (delete-range-nodes start-pos end-pos struct)))
+        end-pos (find-pos struct (str end-uuid))
+        ids (mapv (fn [id-tuple] (str (second id-tuple))) block-ids)]
+    (delete-range-nodes start-pos end-pos struct)
+    (println "delete-nodes-yjs:" ids)
+    (dissoc-contents ids (contentmap))))
+
 
 (defn delete-nodes-op [start-node end-node block-ids]
   (let [start-block (:data start-node)
@@ -615,32 +623,75 @@
                              (:block/name (db/entity (:db/id (:block/page start-block)))))]
       (when-let [start-uuid (:block/uuid start-block)]
         (when-let [end-uuid (:block/uuid end-block)]
-          (delete-nodes-yjs page-name start-uuid end-uuid)
+          (delete-nodes-yjs page-name start-uuid end-uuid block-ids)
           (distinct-struct (structarray page-name) (atom #{}))
           (merge-doc doc-remote doc-local)
           (outliner-core/delete-nodes start-node end-node block-ids))))))
 
+(defn delete-node-yjs [page-name id]
+  (let [struct (structarray page-name)
+        pos (find-pos struct id)]
+    (delete-item pos struct)
+    (dissoc-contents [id] (contentmap))))
+
+(defn delete-node-op [node children?]
+  (let [block (:data node)]
+    (when-let [page-name (:block/name (db/entity (:db/id (:block/page block))))]
+      (let [uuid (str (:block/uuid block))]
+        (delete-node-yjs page-name uuid)
+        (merge-doc doc-remote doc-local)
+        (outliner-core/delete-node node children?)))))
+
 (defn save-node-op [node]
   (let [block (:data node)
         contentmap (contentmap)]
-
     (when-let [page-name (:block/name (db/entity (:db/id (:block/page block))))]
       (when-let [block-uuid (:block/uuid block)]
-        (def uuu node)
         (.set contentmap (str block-uuid) (:block/content block))
         (distinct-struct (structarray page-name) (atom #{}))
         (merge-doc doc-remote doc-local)
+        (outliner-core/save-node node)))))
+
+
+
+
+(defn indent-outdent-nodes-op [nodes indent?]
+  (println "[YJS] indent-outdent-nodes(before):" nodes indent?)
+  (outliner-core/indent-outdent-nodes nodes indent?)
+  (println "[YJS] indent-outdent-nodes(after):"
+           (mapv (fn [node]
+                   (db/pull (:db/id (:data node))))
+                 nodes)))
+
 
-        (outliner-core/save-node node)
 
-             ))))
 
-(start-sync-page "test-page")
 ;; (defn move-subtree-yjs [src-page-name dst-page-name root target-node sibling?]
 
 ;;   )
 
 
+;;;;;;;;;;;;;;;;;;;;;;;;;
+;; functions for debug ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defn- struct->content-struct [struct contentmap]
+  (mapv (fn [i]
+          (cond
+            (string? i)
+            (try (.toString (.get contentmap i))
+                 (catch js/Error e
+                   (println e)
+                   (println i)))
+
+            :else
+            (struct->content-struct i contentmap))) struct))
+
+(defn- page-contents [page-name]
+  (let [struct (.toJSON (structarray page-name))
+        contentmap (contentmap)]
+    (struct->content-struct struct contentmap)))
+
 (comment
  (def test-doc (y/Doc.))
  (def test-struct (.getArray test-doc "test-struct"))