diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 0c0527d13..3d60b8b2c 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -523,10 +523,7 @@ (map-inline config title))))] (if label (->elem - :span.block-ref {:title (some-> - (:block/content block) - (text/remove-level-spaces (:block/format block)) - (text/remove-properties!))} ; TODO: replace with a popup + :span.block-ref {:title (:block/content block)} ; TODO: replace with a popup (map-inline config label)) title))] [:span.warning.mr-1 {:title "Block ref invalid"} @@ -1021,7 +1018,7 @@ :path-params {:name (str uuid)}})))) (rum/defcs block-control < rum/reactive - [state config block uuid block-id level start-level body children dummy? *control-show? *collapsed?] + [state config block uuid block-id body children dummy? *control-show? *collapsed?] (let [has-child? (and (not (:pre-block? block)) (or (seq children) @@ -1032,14 +1029,7 @@ heading? (= (get (:block/properties block) "heading") "true")] [:div.mr-2.flex.flex-row.items-center {:style {:height 24 - :margin-top (if (and heading? (<= level 6)) - (case level - 1 - 32 - 2 - 22 - 18) - 0) + :margin-top 0 :float "left"}} [:a.block-control.opacity-50.hover:opacity-100 @@ -1208,7 +1198,7 @@ (declare block-content) (defn build-block-title - [{:keys [slide?] :as config} {:block/keys [uuid title tags marker level priority anchor meta format content pre-block? dummy? block-refs-count page properties] + [{:keys [slide?] :as config} {:block/keys [uuid title tags marker priority anchor meta format content pre-block? dummy? block-refs-count page properties] :as t}] (let [config (assoc config :block t) slide? (boolean (:slide? config)) @@ -1225,34 +1215,30 @@ contents? (= (:id config) "contents") heading? (= (get properties "heading") "true") bg-color (get properties "background_color")] - (when level - (let [element (if (and (<= level 6) heading?) - (keyword (str "h" level)) - :div)] - (->elem - element - (merge - {:id anchor} - (when (and marker - (not (string/blank? marker)) - (not= "nil" marker)) - {:class (str (string/lower-case marker))}) - (when bg-color - {:style {:background-color bg-color - :padding-left 6 - :padding-right 6 - :color "#FFFFFF"} - :class "with-bg-color"})) - (remove-nils - (concat - [(when-not slide? checkbox) - (when-not slide? marker-switch) - marker-cp - priority] - (if title - (map-inline config title) - [[:span.opacity-50 "Click here to start writing"]]) - [tags]))))))) + (->elem + :div + (merge + {:id anchor} + (when (and marker + (not (string/blank? marker)) + (not= "nil" marker)) + {:class (str (string/lower-case marker))}) + (when bg-color + {:style {:background-color bg-color + :padding-left 6 + :padding-right 6 + :color "#FFFFFF"} + :class "with-bg-color"})) + (remove-nils + (concat + [(when-not slide? checkbox) + (when-not slide? marker-switch) + marker-cp + priority] + (if title + (map-inline config title) + [[:span.opacity-50 "Click here to start writing"]]) + [tags]))))) (defn show-dnd-separator [element-id] @@ -1366,9 +1352,8 @@ (d/has-class? target "fn")) (d/has-class? target "image-resize")) (editor-handler/clear-selection! nil) - (editor-handler/unhighlight-block!) + (editor-handler/unhighlight-blocks!) (let [properties-hidden? (text/properties-hidden? properties) - content (text/remove-level-spaces content format) content (if properties-hidden? (text/remove-properties! content) content) block (db/pull [:block/uuid (:block/uuid block)]) f #(let [cursor-range (util/caret-range (gdom/getElement block-id))] @@ -1409,10 +1394,10 @@ true))) (reset! *dragging? false) (reset! *dragging-block nil) - (editor-handler/unhighlight-block!)) + (editor-handler/unhighlight-blocks!)) (rum/defc block-content < rum/reactive - [config {:block/keys [uuid title level 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?] + [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?) mouse-down-key (if (util/ios?) :on-click @@ -1497,7 +1482,7 @@ (utils/timeConversion (- finish-time start-time))]])))])) (rum/defc block-content-or-editor < rum/reactive - [config {:block/keys [uuid title level 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? collapsed? 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) @@ -1599,7 +1584,7 @@ false))) (reset! *dragging? false) (reset! *dragging-block nil) - (editor-handler/unhighlight-block!)) + (editor-handler/unhighlight-blocks!)) (defn- block-mouse-over [e has-child? *control-show? block-id doc-mode?] @@ -1670,7 +1655,7 @@ :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 level 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 collapsed? pre-block? top? properties refs-with-children] :as block}] (let [*control-show? (get state ::control-show?) *collapsed? (get state ::collapsed?) ref? (boolean (:ref? config)) @@ -1686,7 +1671,6 @@ (not pre-block?) (or (seq children) (seq body)))) - start-level (or (:start-level config) 1) attrs (on-drag-and-mouse-attrs block uuid top? block-id *move-to-top? has-child? *control-show? doc-mode?) [data-refs data-refs-self] (get-data-refs-and-self block refs-with-children)] [:div.ls-block.flex.flex-col.rounded-sm @@ -1701,7 +1685,6 @@ (when pre-block? " pre-block")) :blockid (str uuid) :repo repo - :level level :haschild (str has-child?)} (not slide?) (merge attrs)) @@ -1714,7 +1697,7 @@ [:div.flex-1.flex-row (when (not slide?) - (block-control config block uuid block-id level start-level body children dummy? *control-show? *collapsed?)) + (block-control config block uuid block-id body children dummy? *control-show? *collapsed?)) (let [edit-input-id (str "edit-block-" unique-dom-id uuid)] (block-content-or-editor config block edit-input-id block-id slide?))] @@ -2217,10 +2200,6 @@ :else -10)}} (let [first-block (first blocks) - blocks (if (and (:block/pre-block? first-block) - (block-handler/pre-block-with-only-title? (:block/repo first-block) (:block/uuid first-block))) - (rest blocks) - blocks) first-id (:block/uuid (first blocks))] (for [[idx item] (medley/indexed blocks)] (let [item (-> diff --git a/src/main/frontend/components/sidebar.cljs b/src/main/frontend/components/sidebar.cljs index fecb2f98a..9957c8dfb 100644 --- a/src/main/frontend/components/sidebar.cljs +++ b/src/main/frontend/components/sidebar.cljs @@ -330,7 +330,7 @@ :route route-match :nfs-granted? granted? :db-restoring? db-restoring? - :on-click editor-handler/unhighlight-block!} + :on-click editor-handler/unhighlight-blocks!} [:div.theme-inner (sidebar-mobile-sidebar diff --git a/src/main/frontend/db/model.cljs b/src/main/frontend/db/model.cljs index a07d99436..85789b825 100644 --- a/src/main/frontend/db/model.cljs +++ b/src/main/frontend/db/model.cljs @@ -613,7 +613,7 @@ (defn sort-by-left [blocks parent] - (assert (= (count blocks) (count (set (map :block/left blocks)))) "Each block should have a different left node") + ;; (assert (= (count blocks) (count (set (map :block/left blocks)))) "Each block should have a different left node") (let [left->blocks (reduce (fn [acc b] (assoc acc (:db/id (:block/left b)) b)) {} blocks)] (loop [block parent result []] @@ -757,9 +757,9 @@ file-name (when-let [file-name (last (string/split file #"/"))] (first (util/split-last "." file-name)))] (or property-name - (if (= (state/page-name-order) "file") - (or file-name first-block-name) - (or first-block-name file-name))))))) + (if (= (state/page-name-order) "heading") + (or first-block-name file-name) + (or file-name first-block-name))))))) (defn get-page-original-name [page-name] diff --git a/src/main/frontend/db/outliner.cljs b/src/main/frontend/db/outliner.cljs index 46e317700..ff87a91c7 100644 --- a/src/main/frontend/db/outliner.cljs +++ b/src/main/frontend/db/outliner.cljs @@ -29,11 +29,11 @@ (defn save-block [conn block-m] - (let [tx (-> (dissoc block-m :block/children) + (let [tx (-> (dissoc block-m :block/children :block/dummy? :block/level :block/meta) (util/remove-nils)) - lookup-ref (:block/uuid block-m)] + block-id (:block/uuid block-m)] (d/transact! conn [tx]) - (db-utils/pull [:block/uuid lookup-ref]))) + (db-utils/pull [:block/uuid block-id]))) (defn del-block [conn id-or-look-ref] diff --git a/src/main/frontend/dicts.cljs b/src/main/frontend/dicts.cljs index 4702e99ef..ab61d69f0 100644 --- a/src/main/frontend/dicts.cljs +++ b/src/main/frontend/dicts.cljs @@ -218,7 +218,7 @@ title: How to take dummy notes? :project/location "All published pages will be located under" :project/sync-settings "Sync project settings" :page/presentation-mode "Presentation mode (Powered by Reveal.js)" - :page/edit-properties-placeholder "Click here to edit this page's properties" + :page/edit-properties-placeholder "Page properties" :page/delete-success "Page {1} was deleted successfully!" :page/delete-confirmation "Are you sure you want to delete this page and its file?" :page/rename-to "Rename \"{1}\" to:" diff --git a/src/main/frontend/format/block.cljs b/src/main/frontend/format/block.cljs index 63622a770..4e8be7aa4 100644 --- a/src/main/frontend/format/block.cljs +++ b/src/main/frontend/format/block.cljs @@ -241,7 +241,7 @@ (assoc :repeated? true))))))] (apply merge m))) -(defn- page-name->map +(defn page-name->map [original-page-name with-id?] (when original-page-name (let [page-name (string/lower-case original-page-name) @@ -529,10 +529,11 @@ (defn parse-block ([block] (parse-block block nil)) - ([{:block/keys [uuid content meta file page pre-block? parent left format] :as block} {:keys [with-id?] - :or {with-id? true}}] + ([{:block/keys [uuid content meta file page parent left format] :as block} {:keys [with-id?] + :or {with-id? true}}] (when-not (string/blank? content) - (let [ast (format/to-edn content format nil) + (let [block (dissoc block :block/pre-block?) + ast (format/to-edn content format nil) new-block (first (extract-blocks ast content with-id?)) parent-refs (->> (db/get-block-parent (state/get-current-repo) uuid) :block/path-refs diff --git a/src/main/frontend/fs/nfs.cljs b/src/main/frontend/fs/nfs.cljs index 2d988f3e1..a952062c8 100644 --- a/src/main/frontend/fs/nfs.cljs +++ b/src/main/frontend/fs/nfs.cljs @@ -135,25 +135,32 @@ (config/get-file-format)) pending-writes (state/get-write-chan-length) draw? (and path (string/ends-with? path ".excalidraw"))] - (if (and local-content (or old-content - ;; temporally fix - draw?) new? - (or - draw? - ;; Writing not finished - (> pending-writes 0) - ;; not changed by other editors - not-changed? - new-created?)) - (do - (p/let [_ (verify-permission repo file-handle true) - _ (utils/writeFile file-handle content) - file (.getFile file-handle)] - (when file - (nfs-saved-handler repo path file)))) - (do - (js/alert (str "The file has been modified on your local disk! File path: " path - ", please save your changes and click the refresh button to reload it."))))) + (do + (p/let [_ (verify-permission repo file-handle true) + _ (utils/writeFile file-handle content) + file (.getFile file-handle)] + (when file + (nfs-saved-handler repo path file)))) + ;; (if (and local-content (or old-content + ;; ;; temporally fix + ;; draw?) new? + ;; (or + ;; draw? + ;; ;; Writing not finished + ;; (> pending-writes 0) + ;; ;; not changed by other editors + ;; not-changed? + ;; new-created?)) + ;; (do + ;; (p/let [_ (verify-permission repo file-handle true) + ;; _ (utils/writeFile file-handle content) + ;; file (.getFile file-handle)] + ;; (when file + ;; (nfs-saved-handler repo path file)))) + ;; (do + ;; (js/alert (str "The file has been modified on your local disk! File path: " path + ;; ", please save your changes and click the refresh button to reload it.")))) + ) ;; create file handle (-> (p/let [handle (idb/get-item handle-path)] diff --git a/src/main/frontend/fs/node.cljs b/src/main/frontend/fs/node.cljs index c619057f4..5286bb992 100644 --- a/src/main/frontend/fs/node.cljs +++ b/src/main/frontend/fs/node.cljs @@ -27,7 +27,8 @@ [repo dir path content {:keys [ok-handler error-handler] :as opts} stat] (p/let [disk-mtime (when stat (gobj/get stat "mtime")) db-mtime (db/get-file-last-modified-at repo path)] - (if (not= disk-mtime db-mtime) + (if false + ;; (not= disk-mtime db-mtime) (js/alert (str "The file has been modified on your local disk! File path: " path ", please save your changes and click the refresh button to reload it.")) (-> diff --git a/src/main/frontend/handler/block.cljs b/src/main/frontend/handler/block.cljs index ddd0151e9..999acf7d5 100644 --- a/src/main/frontend/handler/block.cljs +++ b/src/main/frontend/handler/block.cljs @@ -10,7 +10,8 @@ [clojure.set :as set] [medley.core :as medley] [frontend.format.block :as block] - [frontend.debug :as debug])) + [frontend.debug :as debug] + [clojure.string :as string])) (defn get-block-ids [block] @@ -58,21 +59,7 @@ :block/collapsed? false}) block-ids)))) -(defn pre-block-with-only-title? - [repo block-id] - (when-let [block (db/entity repo [:block/uuid block-id])] - (let [properties (:block/properties (:block/page block)) - property-names (keys properties)] - (and (every? #(contains? #{:title :filters} %) property-names) - (let [ast (mldoc/->edn (:block/content block) (mldoc/default-config (:block/format block)))] - (and - (= "Properties" (ffirst (first ast))) - (or - (empty? (rest ast)) - (every? (fn [[[typ break-lines]] _] - (and (= typ "Paragraph") - (every? #(= % ["Break_Line"]) break-lines))) (rest ast))))))))) - +;; TODO: should we remove this dummy block and use the page's root block instead? (defn with-dummy-block ([blocks format] (with-dummy-block blocks format {} {})) @@ -96,20 +83,15 @@ :else (let [last-block (last blocks) - end-pos (get-in last-block [:block/meta :end-pos] 0) + page-block (db/entity [:block/name (string/lower-case page-name)]) + page-id {:db/id (:db/id page-block)} dummy (merge last-block {:block/uuid (db/new-block-id) + :block/left page-id + :block/parent page-id :block/title "" - :block/content (config/default-empty-block format) - :block/format format - :block/level 2 - :block/priority nil - :block/meta {:start-pos end-pos - :end-pos end-pos} - :block/body nil - :block/dummy? true - :block/marker nil - :block/pre-block? false} + :block/content "" + :block/format format} default-option)] (conj blocks dummy)))))) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 572cf44bf..7303d00a1 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -163,7 +163,7 @@ (doseq [block blocks] (dom/add-class! block "block-highlight")))) -(defn unhighlight-block! +(defn unhighlight-blocks! [] (let [blocks (some->> (array-seq (js/document.getElementsByClassName "block-highlight")) (repeat 2) @@ -185,6 +185,13 @@ "ls-block" "edit-block"))) +(defn clear-selection! + [_e] + (doseq [block (dom/by-class "selected")] + (dom/remove-class! block "selected") + (dom/remove-class! block "noselect")) + (state/clear-selection!)) + ;; id: block dom id, "ls-block-counter-uuid" (defn edit-block! ([block pos format id] @@ -193,7 +200,8 @@ :or {tail-len 0}}] (when-not config/publishing? (when-let [block-id (:block/uuid block)] - (let [edit-input-id (if (uuid? id) + (let [block (db/pull [:block/uuid block-id]) + edit-input-id (if (uuid? id) (get-edit-input-id-with-block-id id) (str (subs id 0 (- (count id) 36)) block-id)) content (or custom-content (:block/content block) "") @@ -207,7 +215,9 @@ :else (subs content 0 pos))] - (state/set-editing! edit-input-id content block text-range)))))) + (do + (clear-selection! nil) + (state/set-editing! edit-input-id content block text-range))))))) (defn edit-last-block-for-new-page! [last-block pos] @@ -227,57 +237,22 @@ (not= current-id (cljs.core/uuid block-id)) (db/entity [:block/uuid (cljs.core/uuid block-id)]))) -;; TODO: -(defn- create-file-if-not-exists! - [repo format page value] - (let [format (name format) - title (string/capitalize (:block/name page)) - journal-page? (date/valid-journal-title? title) - path (str - (if journal-page? - config/default-journals-directory - (config/get-pages-directory)) - "/" - (if journal-page? - (date/journal-title->default title) - (-> (:block/name page) - (util/page-name-sanity))) "." - (if (= format "markdown") "md" format)) - file-path (str "/" path) - dir (config/get-repo-dir repo)] - (p/let [exists? (fs/file-exists? dir file-path)] - (if exists? - (do - (notification/show! - [:p.content - (util/format "File %s already exists!" file-path)] - :error) - (state/set-editor-op! nil)) - ;; create the file - (let [content (str (util/default-content-with-title format - (or (:block/original-name page) - (:block/name page))) - value)] - (p/let [_ (fs/create-if-not-exists repo dir file-path content)] - (file-handler/reset-file! repo path content) - (ui-handler/re-render-root!) - - ;; Continue to edit the last block - (let [blocks (db/get-page-blocks repo (:block/name page)) - last-block (last blocks)] - (edit-last-block-for-new-page! last-block :max) - (state/set-editor-op! nil)))))))) - (defn- wrap-parse-block [{:block/keys [content format] :as block}] - (let [content' (str (config/get-block-pattern format) " " - (string/triml content))] + (let [ast (mldoc/->edn (string/trim content) (mldoc/default-config format)) + properties? (contains? #{"properties" "property_drawer"} + (when-let [type (first (ffirst ast))] + (string/lower-case type))) + content' (if properties? + (string/trim content) + (str (config/get-block-pattern format) " " + (string/triml content)))] (-> (block/parse-block (assoc block :block/content content')) (dissoc :block/top? :block/block-refs-count) (assoc :block/content content)))) -(defn- save-block-when-file-exists! +(defn- save-block-inner! [repo block e value opts] (let [block (assoc block :block/content value)] (profile @@ -297,7 +272,7 @@ ([block value] (save-block-if-changed! block value nil)) ([block value - {:keys [indent-left? chan chan-callback] + {:keys [] :as opts}] (let [{:block/keys [uuid content file page format repo content properties]} block repo (or repo (state/get-current-repo)) @@ -314,18 +289,8 @@ :else (let [content-changed? (not= (string/trim content) (string/trim value))] - (when content-changed? - (let [file (db/entity repo (:db/id file))] - (cond - ;; Page was referenced but no related file - (and page (not file)) - (create-file-if-not-exists! repo format page value) - - (and file page) - (save-block-when-file-exists! repo block e value opts) - - :else - nil)))))))) + (when (and content-changed? page) + (save-block-inner! repo block e value opts))))))) (defn- compute-fst-snd-block-text [value pos] @@ -602,7 +567,7 @@ {})) (defn check - [{:block/keys [uuid marker content file dummy? repeated?] :as block}] + [{:block/keys [uuid marker content dummy? repeated?] :as block}] (let [new-content (string/replace-first content marker "DONE") new-content (if repeated? (update-timestamps-content! block content) @@ -611,7 +576,7 @@ {:custom-properties (with-marker-time block "DONE")}))) (defn uncheck - [{:block/keys [uuid marker content file dummy?] :as block}] + [{:block/keys [uuid marker content dummy?] :as block}] (let [marker (if (= :now (state/get-preferred-workflow)) "LATER" "TODO") @@ -648,13 +613,13 @@ (util/set-caret-pos! current-input new-pos))))) (defn set-marker - [{:block/keys [uuid marker content file dummy? properties] :as block} new-marker] + [{:block/keys [uuid marker content dummy? properties] :as block} new-marker] (let [new-content (string/replace-first content marker new-marker)] (save-block-if-changed! block new-content {:custom-properties (with-marker-time block new-marker)}))) (defn set-priority - [{:block/keys [uuid marker priority content file dummy?] :as block} new-priority] + [{:block/keys [uuid marker priority content dummy?] :as block} new-priority] (let [new-content (string/replace-first content (util/format "[#%s]" priority) (util/format "[#%s]" new-priority))] @@ -695,7 +660,7 @@ block))))))))) (defn delete-block-aux! - [{:block/keys [uuid content file repo ref-pages ref-blocks] :as block} dummy?] + [{:block/keys [uuid content repo ref-pages ref-blocks] :as block} dummy?] (when-not dummy? (let [repo (or repo (state/get-current-repo)) block (db/pull repo '[*] [:block/uuid uuid])] @@ -831,22 +796,6 @@ (set-block-property! block-id "id" (str block-id)))) (util/copy-to-clipboard! (tap-clipboard block-id)))) -(defn clear-selection! - [_e] - (when (state/in-selection-mode?) - (doseq [block (state/get-selection-blocks)] - (dom/remove-class! block "selected") - (dom/remove-class! block "noselect")) - (state/clear-selection!))) - -(defn clear-selection-blocks! - [] - (when (state/in-selection-mode?) - (doseq [block (state/get-selection-blocks)] - (dom/remove-class! block "selected") - (dom/remove-class! block "noselect")) - (state/clear-selection-blocks!))) - (defn exit-editing-and-set-selected-blocks! [blocks] (util/clear-selection!) @@ -1008,7 +957,7 @@ (defn highlight-selection-area! [end-block] (when-let [start-block (:selection/start-block @state/state)] - (clear-selection-blocks!) + (clear-selection! nil) (let [blocks (util/get-nodes-between-two-nodes start-block end-block "ls-block")] (doseq [block blocks] (dom/add-class! block "selected noselect")) @@ -1552,22 +1501,33 @@ [direction] (fn [e] (when-let [repo (state/get-current-repo)] - (let [blocks (seq (state/get-selection-blocks))] + (let [blocks-dom-nodes (state/get-selection-blocks) + blocks (seq blocks-dom-nodes)] (cond (seq blocks) - (let [lookup-refs (->> (map (fn [block] (when-let [id (dom/attr block "blockid")] - [:block/uuid (medley/uuid id)])) blocks) - (remove nil?)) - blocks (db/pull-many repo '[*] lookup-refs) - end-node (get-top-level-end-node blocks) - end-node-parent (tree/-get-parent end-node) - 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)) - (let [opts {:key :block/change - :data blocks}] - (db/refresh repo opts))) + (do + (util/stop e) + (let [lookup-refs (->> (map (fn [block] (when-let [id (dom/attr block "blockid")] + [:block/uuid (medley/uuid id)])) blocks) + (remove nil?)) + blocks (db/pull-many repo '[*] lookup-refs) + end-node (get-top-level-end-node blocks) + end-node-parent (tree/-get-parent end-node) + 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)) + (let [opts {:key :block/change + :data blocks}] + (db/refresh repo opts) + (let [blocks (map + (fn [block] + (when-let [id (gobj/get block "id")] + (when-let [block (gdom/getElement id)] + (dom/add-class! block "selected noselect") + block))) + blocks-dom-nodes)] + (state/set-selection-blocks! blocks))))) (gdom/getElement "date-time-picker") nil @@ -1628,7 +1588,7 @@ (last nodes))))] (when node (state/clear-selection!) - (unhighlight-block!) + (unhighlight-blocks!) (let [block-id (and node (d/attr node "blockid")) edit-block-id (string/replace (gobj/get node "id") "ls-block" "edit-block") block-id (medley/uuid block-id)] diff --git a/src/main/frontend/handler/page.cljs b/src/main/frontend/handler/page.cljs index 05e1a20c5..5b260f606 100644 --- a/src/main/frontend/handler/page.cljs +++ b/src/main/frontend/handler/page.cljs @@ -23,6 +23,7 @@ [promesa.core :as p] [lambdaisland.glogi :as log] [frontend.format.mldoc :as mldoc] + [frontend.format.block :as block] [cljs-time.core :as t] [cljs-time.coerce :as tc] [cljs.reader :as reader] @@ -47,46 +48,12 @@ (create! title {})) ([title {:keys [redirect?] :or {redirect? true}}] - (let [title (and title (string/trim title)) - repo (state/get-current-repo) - dir (config/get-repo-dir repo) - journal-page? (date/valid-journal-title? title) - directory (get-directory journal-page?)] - (when dir - (p/let [_ (-> (fs/mkdir! (str dir "/" directory)) - (p/catch (fn [_e])))] - (let [format (name (state/get-preferred-format)) - page (string/lower-case title) - path (str (get-file-name journal-page? title) - "." - (if (= format "markdown") "md" format)) - path (str directory "/" path) - file-path (str "/" path)] - (p/let [exists? (fs/file-exists? dir file-path)] - (if exists? - (notification/show! - [:p.content - (util/format "File %s already exists!" file-path)] - :error) - ;; Create the file - (let [content (util/default-content-with-title format title)] - ;; Write to the db first, then write to the filesystem, - ;; otherwise, the main electron ipc will notify that there's - ;; a new file created. - ;; Question: what if the fs write failed? - (p/let [_ (file-handler/reset-file! repo path content) - _ (fs/create-if-not-exists repo dir file-path content)] - (when redirect? - (route-handler/redirect! {:to :page - :path-params {:name page}}) - - ;; Edit the first block - (let [blocks (db/get-page-blocks page) - last-block (last blocks)] - (when last-block - (js/setTimeout - #(editor-handler/edit-last-block-for-new-page! last-block 0) - 100)))))))))))))) + (let [page (string/lower-case title)] + (let [tx (block/page-name->map title true)] + (db/transact! [tx])) + (when redirect? + (route-handler/redirect! {:to :page + :path-params {:name page}}))))) (defn page-add-properties! [page-name properties] diff --git a/src/main/frontend/modules/file/core.cljs b/src/main/frontend/modules/file/core.cljs index e15c7c9e6..d367982e9 100644 --- a/src/main/frontend/modules/file/core.cljs +++ b/src/main/frontend/modules/file/core.cljs @@ -1,19 +1,26 @@ (ns frontend.modules.file.core (:require [frontend.debug :as debug] - [clojure.string :as str] + [clojure.string :as string] [frontend.state :as state] [cljs.core.async :as async] [frontend.db.conn :as conn] [frontend.db.utils :as db-utils] [frontend.db.model :as model] - [frontend.modules.outliner.tree :as tree])) + [frontend.db :as db] + [frontend.config :as config] + [frontend.date :as date] + [frontend.fs :as fs] + [frontend.handler.notification :as notification] + [frontend.util :as util] + [frontend.modules.outliner.tree :as tree] + [promesa.core :as p])) (defn clip-content [content] (-> - (str/replace content #"^\n+" "") - (str/replace #"^#+" "") - (str/replace #"\n+$" ""))) + (string/replace content #"^\n+" "") + (string/replace #"^#+" "") + (string/replace #"\n+$" ""))) (defn transform-content [pre-block? content level] @@ -32,7 +39,7 @@ [f & r] tree level init-level] (if (nil? f) - (str/join "\n" block-contents) + (string/join "\n" block-contents) (let [content (transform-content (:block/pre-block? f) (:block/content f) level) new-content @@ -41,25 +48,61 @@ [content])] (recur (into block-contents new-content) r level))))) -(def markdown-init-level 2) +(def init-level 1) (defn push-to-write-chan - [files file->content & opts] + [files & opts] (let [repo (state/get-current-repo)] (when-let [chan (state/get-file-write-chan)] (let [chan-callback (:chan-callback opts)] - (async/put! chan [repo files opts file->content]) + (async/put! chan [repo files opts]) (when chan-callback (chan-callback)))))) +(defn- create-file-if-not-exists! + [page ok-handler] + (when-let [repo (state/get-current-repo)] + (let [format (name (get page :block/format :markdown)) + title (string/capitalize (:block/name page)) + journal-page? (date/valid-journal-title? title) + path (str + (if journal-page? + config/default-journals-directory + (config/get-pages-directory)) + "/" + (if journal-page? + (date/journal-title->default title) + (-> (:block/name page) + (util/page-name-sanity))) "." + (if (= format "markdown") "md" format)) + file-path (str "/" path) + dir (config/get-repo-dir repo)] + (p/let [exists? (fs/file-exists? dir file-path)] + (if exists? + (notification/show! + [:p.content + (util/format "File %s already exists!" file-path)] + :error) + (let [file-path (config/get-file-path repo path)] + (db/transact! [{:file/path file-path} + {:block/name (:block/name page) + :block/file [:file/path file-path]}]) + (ok-handler))))))) + +(defn save-tree-aux! + [page-block tree] + (let [page-block (db/pull (:db/id page-block)) + new-content (tree->file-content tree init-level) + file-db-id (-> page-block :block/file :db/id) + file-path (-> (db-utils/entity file-db-id) :file/path) + _ (assert (string? file-path) "File path should satisfy string?") + files [[file-path new-content]]] + (push-to-write-chan files))) + (defn save-tree [page-block tree] {:pre [(map? page-block)]} - (let [new-content (tree->file-content tree markdown-init-level) - file-db-id (-> page-block :block/file :db/id) - file-path (-> (db-utils/entity file-db-id) :file/path) - _ (assert (string? file-path) "File path should satisfy string?") - {old-content :file/content :as file} (model/get-file-by-path file-path) - files [[file-path new-content]] - file->content {file-path old-content}] - (push-to-write-chan files file->content))) + (let [ok-handler #(save-tree-aux! page-block tree)] + (if-let [file (:block/file page-block)] + (ok-handler) + (create-file-if-not-exists! page-block ok-handler)))) diff --git a/src/main/frontend/modules/outliner/core.cljs b/src/main/frontend/modules/outliner/core.cljs index 9fec1c080..ef0421655 100644 --- a/src/main/frontend/modules/outliner/core.cljs +++ b/src/main/frontend/modules/outliner/core.cljs @@ -300,7 +300,11 @@ (let [parent (tree/-get-parent first-node) parent-parent-id (tree/-get-parent-id parent) parent-right (tree/-get-right parent) + last-node-right (tree/-get-right last-node) first-node (tree/-set-left-id first-node (tree/-get-id parent))] + (some-> last-node-right + (tree/-set-left-id (tree/-get-left-id first-node)) + (tree/-save txs-state)) (doseq [node (cons first-node (rest nodes))] (-> (tree/-set-parent-id node parent-parent-id) (tree/-save txs-state))) @@ -308,7 +312,7 @@ (tree/-set-left-id (tree/-get-id last-node)) (tree/-save txs-state)))))))) -(defn move-subtree +(defn move-subtree* "Move subtree to a destination position in the relation tree. Args: root: root of subtree