yjs.cljs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. (ns frontend.modules.outliner.yjs
  2. (:require ["yjs" :as y]
  3. ["y-websocket" :as y-ws]
  4. [frontend.modules.outliner.tree :as tree]
  5. [frontend.modules.outliner.core :as outliner-core]
  6. [frontend.format.block :as block]
  7. [frontend.format.mldoc :as mldoc]
  8. [frontend.handler.common :as common-handler]
  9. [frontend.state :as state]
  10. [frontend.db :as db]
  11. [frontend.db.model :as db-model]
  12. [frontend.util.property :as property]
  13. [clojure.zip :as zip]
  14. [datascript.core :as d]))
  15. (set! *warn-on-infer* false)
  16. (def doc-local (y/Doc.))
  17. (def doc-remote (y/Doc.))
  18. (def syncing-pages (atom #{}))
  19. (def wsProvider1 (y-ws/WebsocketProvider. "ws://localhost:1234", "test-user", doc-remote))
  20. (defn- contentmap [] (.getMap doc-local "content"))
  21. (defn- structarray [page-name] (.getArray doc-local (str page-name "-struct")))
  22. (defn- remote-contentmap [] (.getMap doc-remote "content"))
  23. (defn- remote-structarray [page-name] (.getArray doc-remote (str page-name "-struct")))
  24. (defn- assoc-contents [contents contentmap]
  25. (mapv (fn [[k v]] (.set contentmap k v)) contents))
  26. (defn- dissoc-contents [ids contentmap]
  27. (mapv (fn [id] (.delete contentmap id)) ids))
  28. (defn- goto-innermost-struct-array [pos struct]
  29. (loop [i 0 s struct]
  30. (if (> i (- (count pos) 2))
  31. s
  32. (recur (inc i) (.get s (get pos i))))))
  33. (deftype Pos [pos-vec]
  34. Object
  35. (toString [_] pos-vec)
  36. ;; [1 2 3] -> [1 2 2]
  37. ;; [1 2 0] -> nil
  38. (dec-pos [_] (Pos. (conj (vec (butlast pos-vec)) (dec (last pos-vec)))))
  39. ;; [1 2 3] -> [1 2 4]
  40. (inc-pos [_] (Pos. (conj (vec (butlast pos-vec)) (inc (last pos-vec)))))
  41. ;; [1 2 3] -> [1 2 4 0]
  42. (inc-level-pos [_] (Pos. (conj (Pos. (conj (vec (butlast pos-vec)) (inc (last pos-vec)))) 0)))
  43. ;; [1 2 3] -> [1 2 3 0]
  44. (add-next-level [_] (Pos. (conj pos-vec 0)))
  45. ;; [1 2 3] -> [1 2]
  46. (upper-level [_]
  47. (when-some [pos-vec* (vec (butlast pos-vec))]
  48. (Pos. pos-vec*)))
  49. (next-sibling-pos [_ struct]
  50. (let [inner-struct (goto-innermost-struct-array pos-vec struct)
  51. next-item (.get inner-struct (inc (last pos-vec)))]
  52. (if (instance? y/Array next-item)
  53. (Pos. (conj (vec (butlast pos-vec)) (+ 2 (last pos-vec))))
  54. (Pos. (conj (vec (butlast pos-vec)) (+ 1 (last pos-vec)))))))
  55. (next-non-sibling-pos! [this struct]
  56. "create a y/Array when no child follows item at POS"
  57. (let [inner-struct (goto-innermost-struct-array this struct)
  58. next-item (.get inner-struct (inc (last this)))]
  59. (when-not (instance? y/Array next-item)
  60. (.insert inner-struct (inc (last this)) (clj->js [(y/Array.)])))
  61. (.inc-level-pos this)))
  62. ICounted
  63. (-count [_] (count pos-vec))
  64. ILookup
  65. (-lookup [_ k] (get pos-vec k))
  66. (-lookup [_ k not-found] (get pos-vec k not-found))
  67. INext
  68. (-next [_] (next pos-vec))
  69. ISeq
  70. (-first [_] (first pos-vec))
  71. (-rest [_] (rest pos-vec))
  72. ISeqable
  73. (-seq [_] (seq pos-vec))
  74. ISequential
  75. IComparable
  76. (-compare [this other]
  77. (let [pos1 (.-pos-vec this)
  78. pos2 (.-pos-vec other)
  79. len1 (count pos1)
  80. len2 (count pos2)]
  81. (loop [i 0]
  82. (cond
  83. (and (< i len1) (>= i len2))
  84. -1
  85. (and (< i len2) (>= i len1))
  86. 1
  87. (and (>= i len1) (>= i len2))
  88. 0
  89. :else
  90. (let [nthi1 (nth pos1 i)
  91. nthi2 (nth pos2 i)]
  92. (cond
  93. (< nthi1 nthi2)
  94. -1
  95. (> nthi1 nthi2)
  96. 1
  97. (= nthi1 nthi2)
  98. (recur (inc i)))))))))
  99. (defn find-pos [struct id]
  100. (let [toplevel (js->clj (.toArray struct))
  101. index (.indexOf toplevel id)]
  102. (if (not= -1 index)
  103. (->Pos [index])
  104. (loop [i 0]
  105. (if (>= i (count toplevel))
  106. nil
  107. (let [sublevel (get toplevel i)]
  108. (if (instance? y/Array sublevel)
  109. (if-some [index-pos (find-pos sublevel id)]
  110. (let [index (flatten index-pos)]
  111. (->Pos (vec (flatten [i index]))))
  112. (recur (+ i 1)))
  113. (recur (+ i 1)))))))))
  114. (defn- get-pos-item [pos struct]
  115. (loop [i 0 s struct]
  116. (if (>= i (count pos))
  117. s
  118. (recur (inc i) (.get s (get pos i))))))
  119. (defn- get-child-array [pos struct]
  120. "return child array if exists.
  121. [1 [2 3]]
  122. ^
  123. pos
  124. return [2 3]
  125. "
  126. (let [child (get-pos-item (.inc-pos pos) struct)]
  127. (when (instance? y/Array child)
  128. child)))
  129. (defn- distinct-struct [struct id-set]
  130. (loop [i 0]
  131. (when (< i (.-length struct))
  132. (let [s (.get struct i)]
  133. (if (instance? y/Array s)
  134. (do
  135. (distinct-struct s id-set)
  136. (if (= 0 (.-length s))
  137. (do
  138. (.delete struct i)
  139. (recur i))
  140. (recur (inc i))))
  141. (if (contains? @id-set s)
  142. (do
  143. (if (and
  144. (>= (dec i) 0)
  145. (< (inc i) (.-length struct))
  146. (instance? y/Array (.get struct (dec i)))
  147. (instance? y/Array (.get struct (inc i))))
  148. (let [next-item (.get struct (inc i))]
  149. (distinct-struct next-item id-set)
  150. (.push (.get struct (dec i)) (.toArray next-item))
  151. (.delete struct (inc i))
  152. (.delete struct i)
  153. (recur i))
  154. (do
  155. (.delete struct i)
  156. (recur i))))
  157. (do
  158. (swap! id-set #(conj % s))
  159. (recur (inc i)))))))))
  160. (defn- ->content-map [blocks map]
  161. (clojure.walk/postwalk (fn [v]
  162. (when (and (map? v) (:block/uuid v))
  163. (.set map (str (:block/uuid v)) (y/Text. (:block/content v))))
  164. v)
  165. blocks))
  166. (defn- ->struct-array [blocks arr]
  167. (let [arr (or arr (y/Array.))]
  168. (mapv (fn [block-or-children]
  169. (when (map? block-or-children)
  170. (.push arr (clj->js [(or (str (:block/uuid block-or-children)) "")]))
  171. (when-some [children (:block/children block-or-children)]
  172. (let [child (->struct-array children nil)]
  173. (when (and child (> (.-length child) 0))
  174. (.push arr (clj->js [child])))))))
  175. blocks)
  176. arr))
  177. (defn- ensure-block-data [block format other-props]
  178. (dissoc
  179. (merge (common-handler/wrap-parse-block block)
  180. {:block/format format}
  181. other-props)
  182. :block/pre-block?))
  183. (defn- content->block [content format other-props]
  184. (->
  185. (assoc
  186. (first
  187. (block/extract-blocks (mldoc/->edn content (mldoc/default-config format))
  188. content true format))
  189. :block/format format)
  190. (ensure-block-data format other-props)))
  191. (defn page-blocks->doc [page-blocks page-name]
  192. (if-some [t (tree/blocks->vec-tree page-blocks page-name)]
  193. (let [content (contentmap)
  194. struct (structarray page-name)]
  195. (->content-map t content)
  196. (->struct-array t struct))))
  197. (defn- update-block-content [id]
  198. (println "[YJS] update-block-content" id (.get (contentmap) id))
  199. (when-some [block (db-model/query-block-by-uuid id)]
  200. (let [content-map (contentmap)
  201. format (or (:block/format block) :markdown)
  202. new-content (.toString (.get content-map id)) ;TODO orgmode
  203. updated-block (content->block new-content format {:block/page (:block/page block)})]
  204. (def www updated-block)
  205. (outliner-core/save-node (outliner-core/block updated-block))
  206. (db/refresh! (state/get-current-repo) {:key :block/change :data [updated-block]}))))
  207. (defn- get-item-left&parent [item id]
  208. (let [item-content id
  209. item-array (.toArray (.-parent item))
  210. item-index (.indexOf item-array item-content)
  211. left-content (loop [i (dec item-index)]
  212. (when (>= i 0)
  213. (when-some [content (nth item-array i)]
  214. (if (instance? y/Array content)
  215. (recur (dec i))
  216. content))))
  217. parent-array (and (.-parent (.-parent item))
  218. (.toArray (.-parent (.-parent item))))
  219. array-index (loop [i 0]
  220. (when (< i (count parent-array))
  221. (when-some [item (nth parent-array i)]
  222. (if (instance? y/Array item)
  223. (if (not= -1 (.indexOf (.toArray item) item-content))
  224. i
  225. (recur (inc i)))
  226. (recur (inc i))
  227. ))))
  228. parent-content (when array-index
  229. (loop [i (dec array-index)]
  230. (when (>= i 0)
  231. (when-some [content (nth parent-array i)]
  232. (if (instance? y/Array content)
  233. (recur (dec i))
  234. content)))))]
  235. [left-content parent-content]))
  236. (defn- get-id-left&parent [struct id]
  237. (let [pos (find-pos struct id)
  238. upper-pos (.upper-level pos)
  239. parent-id (get-pos-item (.dec-pos upper-pos) struct)
  240. left-id (if-some [left-pos (.dec-pos pos)]
  241. (let [left1 (get-pos-item left-pos struct)]
  242. (if (instance? y/Array left1)
  243. (get-pos-item (.dec-pos left-pos) struct)
  244. left1))
  245. parent-id)
  246. left-id (or left-id parent-id)]
  247. [left-id parent-id]))
  248. (defn- events->array&items [events]
  249. "get related y/arrays and y/items from y/events, ignore local transactions"
  250. (let [arrays
  251. (->> (mapv (fn [event]
  252. (when-not (.-local (.-transaction event))
  253. (.-target event))) events)
  254. (remove nil?)
  255. (distinct))
  256. add-items
  257. (->> (mapv (fn [event]
  258. (when-not (.-local (.-transaction event))
  259. (into [] (.-added (.-changes event))))) events)
  260. (flatten)
  261. (remove nil?))
  262. delete-items
  263. (->> (mapv (fn [event]
  264. (when-not (.-local (.-transaction event))
  265. (into [] (.-added (.-changes event))))) events)
  266. (flatten)
  267. (remove nil?))]
  268. [arrays add-items delete-items]))
  269. (defn- insert-node [left-id parent-id id contentmap]
  270. {:pre [(seq parent-id)]}
  271. (println "[YJS]insert-node:" left-id parent-id id)
  272. (let [left-id (or left-id parent-id)
  273. format :markdown
  274. content (property/insert-property
  275. format
  276. (property/remove-id-property format (.get contentmap id))
  277. "ID" id) ;TODO orgmode
  278. target-block (db-model/query-block-by-uuid left-id)
  279. target-node (outliner-core/block target-block)
  280. new-block (content->block content format
  281. {:block/page (:block/page target-block)
  282. :block/uuid (uuid id)} )
  283. new-node (outliner-core/block new-block)
  284. sibling? (not= parent-id left-id)]
  285. (def zzz [new-node target-node sibling?])
  286. (outliner-core/insert-node new-node target-node sibling?)
  287. (db/refresh! (state/get-current-repo) {:key :block/insert :data [new-block]})))
  288. (defn- delete-node [id]
  289. (println "[YJS] delete-node" id)
  290. (when-some [block (db-model/query-block-by-uuid id)]
  291. (outliner-core/delete-node (outliner-core/block block) false)
  292. (db/refresh! (state/get-current-repo) {:key :block/change :data [block]})))
  293. (defn- observe-struct-fn-aux-insert-ids [ids page-name contentmap]
  294. (let [struct (structarray page-name)]
  295. (mapv (fn [id]
  296. (println "[YJS] observe-struct-fn id:" id)
  297. (let [[left-id parent-id] (get-id-left&parent struct id)
  298. parent-id (or parent-id (:block/uuid (db/entity [:block/name page-name])))]
  299. (when-some [parent-id (and parent-id (str parent-id))]
  300. (when (db/entity [:block/uuid (uuid id)])
  301. (delete-node id))
  302. (insert-node left-id parent-id id contentmap)))) ids)))
  303. (defn- observe-struct-fn-aux-insert-items-array [yarray page-name contentmap]
  304. (let [struct (structarray page-name)
  305. array (js->clj (.toArray yarray))
  306. group (group-by #(instance? y/Array %) array)
  307. sub-arrays (group true)
  308. ids (group false)]
  309. (mapv (fn [id]
  310. (let [[left-id parent-id] (get-id-left&parent struct id)]
  311. (when (not (or left-id parent-id))
  312. (throw (js/Error. (str "empty left-id&parent-id of id: " id))))
  313. (let [parent-id (or parent-id (:block/uuid (db/entity [:block/name page-name])))
  314. parent-id (and parent-id (str parent-id))]
  315. (when (db/entity [:block/uuid (uuid id)])
  316. (delete-node id))
  317. (insert-node left-id parent-id id contentmap))))
  318. ids)
  319. (mapv #(observe-struct-fn-aux-insert-items-array % page-name contentmap) sub-arrays)))
  320. (defn- observe-struct-fn [page-name]
  321. (fn [events]
  322. (def xxx events)
  323. (let [[arrays added-items deleted-items] (events->array&items events)
  324. contentmap (contentmap)]
  325. (mapv
  326. (fn [item]
  327. (observe-struct-fn-aux-insert-ids (.-arr (.-content item)) page-name contentmap)
  328. (when-some [yarray (.-type (.-content item))]
  329. (observe-struct-fn-aux-insert-items-array yarray page-name contentmap)))
  330. added-items))))
  331. (def observe-struct-fn-memo (memoize observe-struct-fn))
  332. (defn- observe-content-fn [event]
  333. (when-not (.-local (.-transaction event))
  334. (let [keys (js->clj (into [] (.-keys event)))]
  335. (mapv (fn [[k v]]
  336. (case (get v "action")
  337. "update" (update-block-content k)
  338. "delete" (delete-node k)
  339. (println "action" v))) keys))))
  340. (defn observe-page-doc [page-name doc]
  341. (let [struct (.getArray doc (str page-name "-struct"))
  342. contentmap (contentmap)]
  343. (.unobserveDeep struct (observe-struct-fn-memo page-name))
  344. (.unobserve contentmap observe-content-fn)
  345. (.observeDeep struct (observe-struct-fn-memo page-name))
  346. (.observe contentmap observe-content-fn)))
  347. (defn unobserve-page-doc [page-name doc]
  348. (let [struct (.getArray doc (str page-name "-struct"))]
  349. (.unobserveDeep struct (observe-struct-fn-memo page-name))
  350. (.unobserve struct observe-content-fn)))
  351. (defn merge-doc [doc1 doc2]
  352. (let [s1 (y/encodeStateVector doc1)
  353. s2 (y/encodeStateVector doc2)
  354. d1 (y/encodeStateAsUpdate doc1 s2)
  355. d2 (y/encodeStateAsUpdate doc2 s1)]
  356. (y/applyUpdate doc1 d2)
  357. (y/applyUpdate doc2 d1)))
  358. (defn sync-doc [local remote]
  359. (.on remote "update" (fn [update]
  360. (y/applyUpdate local update))))
  361. (defn- remove-all-blocks-in-page [page-blocks page-name]
  362. (let [order-blocks (common-handler/reorder-blocks page-blocks)
  363. start-block (first order-blocks)
  364. end-block (last order-blocks)
  365. block-ids (mapv (fn [b] [:block/uuid (:block/uuid b)]) order-blocks)]
  366. (when (and start-block end-block)
  367. (outliner-core/delete-nodes (outliner-core/block start-block)
  368. (outliner-core/block end-block)
  369. block-ids))))
  370. (defn- insert-doc-contents [page-name]
  371. (let [page-block (db/pull (:db/id (db/get-page page-name)))
  372. format (or (:block/format page-block)
  373. (state/get-preferred-format))
  374. contentmap (contentmap)
  375. content-tree (loop [loc (zip/vector-zip (js->clj (.toJSON (structarray page-name))))]
  376. (if (zip/end? loc)
  377. (zip/root loc)
  378. (cond
  379. (string? (zip/node loc))
  380. (recur (zip/next
  381. (zip/replace loc (property/insert-property
  382. format
  383. (property/remove-id-property
  384. format (.toString (.get contentmap (zip/node loc))))
  385. "ID" (zip/node loc)))))
  386. :else
  387. (recur (zip/next loc)))))
  388. node-tree (loop [loc (zip/vector-zip content-tree)]
  389. (if (zip/end? loc)
  390. (zip/root loc)
  391. (cond
  392. (string? (zip/node loc))
  393. (let [block (first
  394. (block/extract-blocks
  395. (mldoc/->edn (zip/node loc) (mldoc/default-config format))
  396. (zip/node loc) true format))
  397. block (merge
  398. (dissoc block
  399. :block/pre-block?
  400. :db/id
  401. :block/left
  402. :block/parent
  403. :block/file)
  404. {:block/page (select-keys page-block [:db/id])
  405. :block/format format
  406. :block/path-refs (->> (cons (:db/id page-block)
  407. (:block/path-refs block))
  408. (remove nil?))})]
  409. (if (:block/uuid block)
  410. (recur (zip/next
  411. (zip/replace
  412. loc
  413. (outliner-core/block block))))
  414. (recur (zip/remove loc))))
  415. :else
  416. (recur (zip/next loc)))))]
  417. (when-not (empty? node-tree)
  418. (outliner-core/insert-nodes node-tree (outliner-core/block page-block) false)
  419. (let [new-block-uuids (mapv (fn [n] (:block/uuid (:data n))) (flatten node-tree))
  420. new-blocks (db/pull-many (state/get-current-repo) '[*] (map (fn [id] [:block/uuid id]) new-block-uuids))]
  421. new-blocks))))
  422. (defn doc->page-blocks [page-blocks page-name]
  423. (let [contentmap (contentmap)
  424. struct (structarray page-name)]
  425. (remove-all-blocks-in-page page-blocks page-name)
  426. (when-some [new-blocks (insert-doc-contents page-name)]
  427. (db/refresh! (state/get-current-repo) {:key :block/insert :data new-blocks}))))
  428. (defn start-sync-page [page-name]
  429. (let [page-blocks (db/get-page-blocks-no-cache page-name)]
  430. (page-blocks->doc page-blocks page-name)
  431. (sync-doc doc-local doc-remote)
  432. (distinct-struct (structarray page-name) (atom #{}))
  433. (merge-doc doc-remote doc-local)
  434. (doc->page-blocks page-blocks page-name)
  435. (observe-page-doc page-name doc-local)))
  436. (defn stop-sync-page [page-name]
  437. (unobserve-page-doc page-name doc-local))
  438. (defn- delete-item [pos root-struct]
  439. "Delete item at POS. Also delete struct when empty"
  440. (let [inner-struct (goto-innermost-struct-array pos root-struct)
  441. last-pos-index (last pos)]
  442. (.delete inner-struct last-pos-index 1)
  443. (when-some [upper-pos (.upper-level pos)]
  444. (let [last-upper-pos-index (last upper-pos)]
  445. (when (= 0 (.-length inner-struct))
  446. (let [inner-upper-struct (goto-innermost-struct-array upper-pos root-struct)]
  447. (.delete inner-upper-struct last-upper-pos-index 1)))))))
  448. (defn- common-prefix [vec1 vec2]
  449. (let [vec1 (or (.-pos-vec vec1) vec1)
  450. vec2 (or (.-pos-vec vec2) vec2)]
  451. (try
  452. (let [len1 (count vec1)
  453. len2 (count vec2)]
  454. (loop [i 0 r1 vec1 r2 vec2]
  455. (cond
  456. (or (>= i len1) (>= i len2))
  457. [(subvec vec1 0 i) r1 r2]
  458. (= (get vec1 i) (get vec2 i))
  459. (recur (inc i) (vec (rest r1)) (vec (rest r2)))
  460. :else
  461. [(subvec vec1 0 i) r1 r2])))
  462. (catch js/Error e
  463. (println e vec1 vec2)
  464. (js/console.trace)))))
  465. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  466. ;; outliner op + yjs op ;;
  467. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  468. ;; (defn move-subtree [root target-node sibling?]
  469. ;; (outliner-core/move-subtree root target-node sibling?))
  470. (defn- nodes-tree->struct&content [nodes-tree]
  471. (let [contents (atom {})
  472. struct (clojure.walk/postwalk
  473. (fn [node]
  474. (if (instance? outliner-core/Block node)
  475. (let [block (:data node)
  476. block-uuid (:block/uuid block)
  477. block-content (:block/content block)]
  478. (when block-uuid
  479. (swap! contents (fn [o] (assoc o (str block-uuid) block-content))))
  480. (str block-uuid))
  481. node)) nodes-tree)]
  482. [struct @contents]))
  483. (defn- insert-nodes-aux [insert-structs pos struct]
  484. "insert INSERT-STRUCTS at POS"
  485. (loop [i 0 pos pos]
  486. (when (< i (count insert-structs))
  487. (let [s (nth insert-structs i)
  488. struct* (goto-innermost-struct-array pos struct)]
  489. (cond
  490. (vector? s)
  491. (let [pos* (.add-next-level pos)]
  492. (.insert struct* (last pos) (clj->js [(y/Array.)]))
  493. (insert-nodes-aux s pos* struct)
  494. (recur (inc i) (.inc-pos pos)))
  495. :else
  496. (do
  497. (.insert struct* (last pos) (clj->js [s]))
  498. (recur (inc i) (.inc-pos pos))))))))
  499. (defn insert-nodes-yjs [page-name new-nodes-tree target-uuid sibling?]
  500. (let [[structs contents] (nodes-tree->struct&content new-nodes-tree)
  501. struct (structarray page-name)]
  502. (when-some [target-pos (find-pos (structarray page-name) (str target-uuid))]
  503. (let [pos (if sibling?
  504. (.next-sibling-pos target-pos struct)
  505. (.next-non-sibling-pos! target-pos struct))]
  506. (insert-nodes-aux structs pos (structarray page-name))
  507. (assoc-contents contents (contentmap))))))
  508. (defn insert-nodes-op [new-nodes-tree target-node sibling?]
  509. (let [target-block (:data target-node)]
  510. (when-some [page-name (or (:block/name target-block)
  511. (:block/name (db/entity (:db/id (:block/page target-block)))))]
  512. (insert-nodes-yjs page-name new-nodes-tree (str (:block/uuid target-block)) sibling?)
  513. (distinct-struct (structarray page-name) (atom #{}))
  514. (merge-doc doc-remote doc-local)
  515. (outliner-core/insert-nodes new-nodes-tree target-node sibling?))))
  516. (defn insert-node-yjs [page-name new-node target-uuid sibling?]
  517. (insert-nodes-yjs page-name [new-node] target-uuid sibling?))
  518. (defn insert-node-op
  519. ([new-node target-node sibling?]
  520. (insert-node-op new-node target-node sibling? nil))
  521. ([new-node target-node sibling? {:keys [blocks-atom skip-transact?]
  522. :or {skip-transact? false}
  523. :as opts}]
  524. (println "[YJS] insert-node-op" new-node)
  525. (let [target-block (:data target-node)]
  526. (when-some [page-name (or (:block/name target-block)
  527. (:block/name (db/entity (:db/id (:block/page target-block)))))]
  528. (insert-node-yjs page-name new-node (str (:block/uuid target-block)) sibling?)
  529. (distinct-struct (structarray page-name) (atom #{}))
  530. (merge-doc doc-remote doc-local)
  531. (try (outliner-core/insert-node new-node target-node sibling? opts)
  532. (catch js/Error e
  533. (println e)
  534. (println new-node target-node)
  535. (js/console.trace)))))))
  536. (defn- delete-range-nodes-prefix-part
  537. ([prefix-vec start-pos-vec end-pos-vec struct] (delete-range-nodes-prefix-part prefix-vec start-pos-vec end-pos-vec struct false))
  538. ([prefix-vec start-pos-vec end-pos-vec struct debug?]
  539. (let [start-pos-vec-len (count start-pos-vec)]
  540. ;; (when (> start-pos-vec-len 0))
  541. (let [inner-struct (goto-innermost-struct-array (->Pos (vec (concat prefix-vec start-pos-vec))) struct)
  542. start-index (last start-pos-vec)
  543. len-to-remove (if (and (end-pos-vec 0 nil) (= start-pos-vec-len 1))
  544. (if (> (count end-pos-vec) 1)
  545. (- (end-pos-vec 0) start-index)
  546. (inc (- (end-pos-vec 0) start-index)))
  547. (- (.-length inner-struct) start-index))]
  548. (if debug?
  549. (println "delete: struct:" (.toJSON inner-struct)
  550. "start-index" start-index
  551. "len-to-remove" len-to-remove)
  552. (.delete inner-struct start-index len-to-remove))
  553. (if (>= start-pos-vec-len 2)
  554. (delete-range-nodes-prefix-part prefix-vec
  555. (conj (subvec start-pos-vec 0 (- start-pos-vec-len 2))
  556. (inc (start-pos-vec (- start-pos-vec-len 2) nil)))
  557. end-pos-vec struct debug?)
  558. len-to-remove)))))
  559. (defn- delete-range-nodes-suffix-part
  560. ([prefix-vec end-pos-vec struct] (delete-range-nodes-suffix-part prefix-vec end-pos-vec struct false))
  561. ([prefix-vec end-pos-vec struct debug?]
  562. (let [end-pos-vec-len (count end-pos-vec)]
  563. (when (> end-pos-vec-len 0)
  564. (let [inner-struct (goto-innermost-struct-array (->Pos (vec (concat prefix-vec end-pos-vec))) struct)]
  565. (if (<= (dec (.-length inner-struct)) (last end-pos-vec))
  566. (delete-range-nodes-suffix-part prefix-vec (butlast end-pos-vec) struct)
  567. (when (>= end-pos-vec-len 2)
  568. (let [next-end-pos-vec (conj (subvec end-pos-vec 0 (- end-pos-vec-len 2))
  569. (dec (end-pos-vec (- end-pos-vec-len 2))))]
  570. (if debug?
  571. (println "delete struct:" (.toJSON inner-struct) "len" (inc (last end-pos-vec)))
  572. (.delete inner-struct 0 (inc (last end-pos-vec))))
  573. (delete-range-nodes-suffix-part prefix-vec next-end-pos-vec struct)))))))))
  574. (defn delete-range-nodes [start-pos end-pos struct]
  575. ;; {:pre [(<= (compare start-pos end-pos) 0)]}
  576. (let [[same-prefix-vec pos-vec1* pos-vec2*] (common-prefix start-pos end-pos)]
  577. (let [len-removed (delete-range-nodes-prefix-part same-prefix-vec pos-vec1* pos-vec2* struct)]
  578. (if (>(count pos-vec2*) 0)
  579. (let [pos-vec2*-after-delete-prefix-part (vec (cons (- (first pos-vec2*) len-removed) (rest pos-vec2*)))]
  580. (delete-range-nodes-suffix-part same-prefix-vec pos-vec2*-after-delete-prefix-part struct))
  581. (delete-range-nodes-suffix-part same-prefix-vec pos-vec2* struct)))))
  582. (defn delete-nodes-yjs [page-name start-uuid end-uuid block-ids]
  583. (let [struct (structarray page-name)
  584. start-pos (find-pos struct (str start-uuid))
  585. end-pos (find-pos struct (str end-uuid))
  586. ids (mapv (fn [id-tuple] (str (second id-tuple))) block-ids)]
  587. (delete-range-nodes start-pos end-pos struct)
  588. (println "delete-nodes-yjs:" ids)
  589. (dissoc-contents ids (contentmap))))
  590. (defn delete-nodes-op [start-node end-node block-ids]
  591. (let [start-block (:data start-node)
  592. end-block (:data end-node)]
  593. (when-some [page-name (or (:block/name start-block)
  594. (:block/name (db/entity (:db/id (:block/page start-block)))))]
  595. (when-some [start-uuid (:block/uuid start-block)]
  596. (when-some [end-uuid (:block/uuid end-block)]
  597. (delete-nodes-yjs page-name start-uuid end-uuid block-ids)
  598. (distinct-struct (structarray page-name) (atom #{}))
  599. (merge-doc doc-remote doc-local)
  600. (outliner-core/delete-nodes start-node end-node block-ids))))))
  601. (defn delete-node-yjs [page-name id]
  602. (let [struct (structarray page-name)
  603. pos (find-pos struct id)]
  604. (delete-item pos struct)
  605. (dissoc-contents [id] (contentmap))))
  606. (defn delete-node-op [node children?]
  607. (let [block (:data node)]
  608. (when-some [page-name (:block/name (db/entity (:db/id (:block/page block))))]
  609. (let [uuid (str (:block/uuid block))]
  610. (delete-node-yjs page-name uuid)
  611. (merge-doc doc-remote doc-local)
  612. (outliner-core/delete-node node children?)))))
  613. (defn save-node-op [node]
  614. (let [block (:data node)
  615. contentmap (contentmap)]
  616. (when-some [page-name (:block/name (db/entity (:db/id (:block/page block))))]
  617. (when-some [block-uuid (:block/uuid block)]
  618. (.set contentmap (str block-uuid) (:block/content block))
  619. (distinct-struct (structarray page-name) (atom #{}))
  620. (merge-doc doc-remote doc-local)
  621. (outliner-core/save-node node)))))
  622. (defn- outdentable? [pos]
  623. (> (count pos) 1))
  624. (defn- indentable? [pos]
  625. (not= 0 (last pos)))
  626. (defn- indent-item [struct id]
  627. "indent an item(and its children)"
  628. (when-some [pos (find-pos struct id)]
  629. (when (indentable? pos)
  630. (let [item-parent-array (goto-innermost-struct-array pos struct)
  631. item (get-pos-item pos struct)
  632. item-children (get-child-array pos struct)
  633. item-children-clone (and item-children (.clone item-children))
  634. push-items (if item-children-clone
  635. [item item-children-clone]
  636. [item])]
  637. (let [prev-item (get-pos-item (.dec-pos pos) struct)]
  638. (.delete item-parent-array (last pos) (if item-children-clone 2 1))
  639. ; [other-item prev-item item]
  640. (if (instance? y/Array prev-item) ;prev-item is array
  641. (do
  642. (.push prev-item (clj->js push-items)))
  643. ;; prev-item is not array
  644. (let [insert-pos (last pos)
  645. new-array (y/Array.)]
  646. (.insert item-parent-array insert-pos (clj->js [new-array]))
  647. (.push new-array (clj->js push-items)))))))))
  648. (defn- outdent-item [struct id]
  649. "outdent an item(and its children)"
  650. (when-some [pos (find-pos struct id)]
  651. (when (outdentable? pos)
  652. (let [upper-pos (.upper-level pos)
  653. item-parent-array (goto-innermost-struct-array pos struct)
  654. item-parent-parent-array (goto-innermost-struct-array upper-pos struct)
  655. item (get-pos-item pos struct)
  656. item-children (get-child-array pos struct)
  657. item-children-clone (and item-children (.clone item-children))
  658. item-parent-array-clone (.clone item-parent-array)]
  659. (.delete item-parent-array (last pos) (- (.-length item-parent-array) (last pos)))
  660. (.delete item-parent-array-clone 0 (+ (last pos) (if item-children-clone 2 1)))
  661. (let [empty-parent-array? (= 0 (.-length item-parent-array))
  662. insert-pos (if empty-parent-array? (last upper-pos) (inc (last upper-pos)))
  663. insert-items (if item-children-clone [item item-children-clone] [item])]
  664. (when empty-parent-array?
  665. (.delete item-parent-parent-array (last upper-pos) 1))
  666. (.insert item-parent-parent-array insert-pos (clj->js insert-items))
  667. (when (> (.-length item-parent-array-clone) 0)
  668. (.insert item-parent-parent-array (+ insert-pos (if item-children-clone 2 1))
  669. (clj->js [item-parent-array-clone]))))))))
  670. (defn- indent-outdent-nodes-yjs [page-name ids indent?]
  671. (let [struct (structarray page-name)]
  672. (mapv
  673. (fn [id]
  674. (if indent?
  675. (indent-item struct id)
  676. (outdent-item struct id)))
  677. ids)))
  678. (defn indent-outdent-nodes-op [nodes indent?]
  679. (when-some [page-name
  680. (:block/name (db/entity (:db/id (:block/page (:data (first nodes))))))]
  681. (let [ids (mapv (fn [node] (str (:block/uuid (:data node)))) nodes)]
  682. (println "[YJS] indent-outdent-nodes(before):" nodes indent?)
  683. (indent-outdent-nodes-yjs page-name ids indent?)
  684. (merge-doc doc-remote doc-local)
  685. (outliner-core/indent-outdent-nodes nodes indent?)
  686. (println "[YJS] indent-outdent-nodes(after):"
  687. (mapv (fn [node]
  688. (db/pull (:db/id (:data node))))
  689. nodes)))))
  690. (defn move-subtree-same-page-yjs [struct root-id target-id sibling?]
  691. (when (find-pos struct target-id)
  692. (when-some [root-pos (find-pos struct root-id)]
  693. (let [root-item (get-pos-item root-pos struct)
  694. root-item-parent-array (goto-innermost-struct-array root-pos struct)
  695. child-array (get-child-array root-pos struct)
  696. child-array-clone (and child-array (.clone child-array))
  697. insert-items (if child-array [root-item child-array-clone] [root-item])]
  698. (.delete root-item-parent-array (last root-pos) (if child-array 2 1))
  699. (when (= 0 (.-length root-item-parent-array))
  700. (let [upper-pos (.upper-level root-pos)
  701. root-item-parent-parent-array (goto-innermost-struct-array upper-pos struct)]
  702. (.delete root-item-parent-parent-array (last upper-pos))))
  703. (let [target-pos (find-pos struct target-id)
  704. target-item-parent-array (goto-innermost-struct-array target-pos struct)]
  705. (if sibling?
  706. (let [sibling-insert-pos (let [insert-pos (.inc-pos target-pos)
  707. next-item (get-pos-item insert-pos struct)]
  708. (if (instance? y/Array next-item)
  709. (inc (last insert-pos))
  710. (last insert-pos)))]
  711. (.insert target-item-parent-array sibling-insert-pos (clj->js insert-items)))
  712. (let [insert-pos (inc (last target-pos))
  713. new-array (when-not (instance? y/Array (.get target-item-parent-array insert-pos))
  714. (y/Array.))]
  715. (when new-array
  716. (.insert target-item-parent-array insert-pos (clj->js [new-array])))
  717. (let [target-child-array (.get target-item-parent-array insert-pos)]
  718. (.insert target-child-array 0 (clj->js insert-items))))))))))
  719. (defn move-subtree-same-page-op [root target-node sibling?]
  720. (when-some [page-name (:block/name (db/entity (:db/id (:block/page (:data root)))))]
  721. (let [struct (structarray page-name)
  722. root-id (str (:block/uuid (:data root)))
  723. target-id (str (:block/uuid (:data target-node)))]
  724. (move-subtree-same-page-yjs struct root-id target-id sibling?)
  725. (merge-doc doc-remote doc-local)
  726. (outliner-core/move-subtree root target-node sibling?))))
  727. ;;;;;;;;;;;;;;;;;;;;;;;;;
  728. ;; functions for debug ;;
  729. ;;;;;;;;;;;;;;;;;;;;;;;;;
  730. (defn- struct->content-struct [struct contentmap]
  731. (mapv (fn [i]
  732. (cond
  733. (string? i)
  734. (try (.toString (.get contentmap i))
  735. (catch js/Error e
  736. (println e)
  737. (println i)))
  738. :else
  739. (struct->content-struct i contentmap))) struct))
  740. (defn- page-contents [page-name]
  741. (let [struct (.toJSON (structarray page-name))
  742. contentmap (contentmap)]
  743. (struct->content-struct struct contentmap)))
  744. (defn- build-test-struct []
  745. (def test-doc (y/Doc.))
  746. (def test-struct (.getArray test-doc "test-struct"))
  747. (.insert test-struct 0 (clj->js ["1"]))
  748. (.insert test-struct 1 (clj->js ["2"]))
  749. (.insert test-struct 2 (clj->js [(y/Array.)]))
  750. (.insert (.get test-struct 2) 0 (clj->js ["3"]))
  751. (.insert (.get test-struct 2) 1 (clj->js ["4"]))
  752. (.insert (.get test-struct 2) 2 (clj->js [(y/Array.)]))
  753. (.insert (.get (.get test-struct 2) 2) 0 (clj->js ["5"]))
  754. (.observeDeep test-struct (fn [e] (def eee e)))
  755. (println (.toJSON test-struct))
  756. )