| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780 |
- (ns frontend.handler.page
- (:require [cljs.reader :as reader]
- [clojure.string :as string]
- [clojure.walk :as walk]
- [datascript.core :as d]
- [frontend.commands :as commands]
- [frontend.config :as config]
- [frontend.date :as date]
- [frontend.db :as db]
- [logseq.db.schema :as db-schema]
- [frontend.db.model :as model]
- [frontend.db.utils :as db-utils]
- [frontend.db.conn :as conn]
- [frontend.fs :as fs]
- [frontend.handler.common :as common-handler]
- [frontend.handler.editor :as editor-handler]
- [frontend.handler.notification :as notification]
- [frontend.handler.route :as route-handler]
- [frontend.handler.ui :as ui-handler]
- [frontend.handler.web.nfs :as web-nfs]
- [frontend.handler.config :as config-handler]
- [frontend.handler.recent :as recent-handler]
- [frontend.modules.outliner.core :as outliner-core]
- [frontend.modules.outliner.file :as outliner-file]
- [frontend.modules.outliner.tree :as outliner-tree]
- [frontend.state :as state]
- [frontend.util :as util]
- [frontend.util.cursor :as cursor]
- [frontend.util.property :as property]
- [frontend.util.page-property :as page-property]
- [goog.object :as gobj]
- [lambdaisland.glogi :as log]
- [promesa.core :as p]
- [frontend.mobile.util :as mobile-util]
- [logseq.graph-parser.util :as gp-util]
- [logseq.graph-parser.config :as gp-config]
- [logseq.graph-parser.block :as gp-block]
- [frontend.format.block :as block]
- [goog.functions :refer [debounce]]))
- (defn- get-directory
- [journal?]
- (if journal?
- (config/get-journals-directory)
- (config/get-pages-directory)))
- (defn- get-file-name
- [journal? title]
- (when-let [s (if journal?
- (date/journal-title->default title)
- (gp-util/page-name-sanity (string/lower-case title)))]
- ;; Win10 file path has a length limit of 260 chars
- (gp-util/safe-subs s 0 200)))
- (defn get-page-file-path
- ([] (get-page-file-path (state/get-current-page)))
- ([page-name]
- (when page-name
- (let [page-name (util/page-name-sanity-lc page-name)]
- (when-let [page (db/entity [:block/name page-name])]
- (:file/path (:block/file page)))))))
- (defn- build-title [page]
- (let [original-name (:block/original-name page)]
- (if (string/includes? original-name ",")
- (util/format "\"%s\"" original-name)
- original-name)))
- (defn default-properties-block
- ([title format page]
- (default-properties-block title format page {}))
- ([title format page properties]
- (let [p (common-handler/get-page-default-properties title)
- ps (merge p properties)
- content (page-property/insert-properties format "" ps)
- refs (gp-block/get-page-refs-from-properties properties
- (db/get-db (state/get-current-repo))
- (state/get-date-formatter))]
- {:block/uuid (db/new-block-id)
- :block/properties ps
- :block/properties-order (keys ps)
- :block/refs refs
- :block/left page
- :block/format format
- :block/content content
- :block/parent page
- :block/page page})))
- (defn- create-title-property?
- [journal? page-name]
- (and (not journal?)
- (util/create-title-property? page-name)))
- (defn- build-page-tx [format properties page journal?]
- (when (:block/uuid page)
- (let [page-entity [:block/uuid (:block/uuid page)]
- create-title? (create-title-property? journal?
- (or
- (:block/original-name page)
- (:block/name page)))
- page (if (seq properties) (assoc page :block/properties properties) page)
- page-empty? (db/page-empty? (state/get-current-repo) (:block/name page))]
- (cond
- (not page-empty?)
- [page]
- create-title?
- (let [properties-block (default-properties-block (build-title page) format page-entity properties)]
- [page
- properties-block])
- (seq properties)
- [page (editor-handler/properties-block properties format page-entity)]
- :else
- [page]))))
- (defn create!
- "Create page.
- :redirect? - when true, redirect to the created page, otherwise return sanitized page name.
- :split-namespace? - when true, split hierarchical namespace into levels.
- :create-first-block? - when true, create an empty block if the page is empty.
- :uuid - when set, use this uuid instead of generating a new one."
- ([title]
- (create! title {}))
- ([title {:keys [redirect? create-first-block? format properties split-namespace? journal? uuid]
- :or {redirect? true
- create-first-block? true
- format nil
- properties nil
- split-namespace? true
- uuid nil}}]
- (let [title (string/trim title)
- title (gp-util/remove-boundary-slashes title)
- page-name (util/page-name-sanity-lc title)
- repo (state/get-current-repo)
- with-uuid? (if (uuid? uuid) uuid true)] ;; FIXME: prettier validation
- (when (db/page-empty? repo page-name)
- (let [pages (if split-namespace?
- (gp-util/split-namespace-pages title)
- [title])
- format (or format (state/get-preferred-format))
- pages (map (fn [page]
- ;; only apply uuid to the deepest hierarchy of page to create if provided.
- (-> (block/page-name->map page (if (= page title) with-uuid? true))
- (assoc :block/format format)))
- pages)
- txs (->> pages
- ;; for namespace pages, only last page need properties
- drop-last
- (mapcat #(build-page-tx format nil % journal?))
- (remove nil?)
- (remove (fn [m]
- (some? (db/entity [:block/name (:block/name m)])))))
- last-txs (build-page-tx format properties (last pages) journal?)
- txs (concat txs last-txs)]
- (when (seq txs)
- (db/transact! txs)))
- (when create-first-block?
- (when (or
- (db/page-empty? repo (:db/id (db/entity [:block/name page-name])))
- (create-title-property? journal? page-name))
- (editor-handler/api-insert-new-block! "" {:page page-name}))))
- (when redirect?
- (route-handler/redirect-to-page! page-name))
- page-name)))
- (defn delete-file!
- [repo page-name unlink-file?]
- (let [file (db/get-page-file page-name)
- file-path (:file/path file)]
- ;; delete file
- (when-not (string/blank? file-path)
- (db/transact! [[:db.fn/retractEntity [:file/path file-path]]])
- (when unlink-file?
- (-> (fs/unlink! repo (config/get-repo-path repo file-path) nil)
- (p/catch (fn [error] (js/console.error error))))))))
- (defn- compute-new-file-path
- [old-path new-name]
- (let [result (string/split old-path "/")
- file-name (gp-util/page-name-sanity new-name true)
- ext (last (string/split (last result) "."))
- new-file (str file-name "." ext)
- parts (concat (butlast result) [new-file])]
- (string/join "/" parts)))
- (defn rename-file!
- [file new-name ok-handler]
- (let [repo (state/get-current-repo)
- file (db/pull (:db/id file))
- old-path (:file/path file)
- new-path (compute-new-file-path old-path new-name)]
- ;; update db
- (db/transact! repo [{:db/id (:db/id file)
- :file/path new-path}])
- (->
- (p/let [_ (fs/rename! repo old-path new-path)]
- (ok-handler))
- (p/catch (fn [error]
- (println "file rename failed: " error))))))
- (defn- replace-page-ref!
- "Unsanitized names"
- [content old-name new-name]
- (let [[original-old-name original-new-name] (map string/trim [old-name new-name])
- [old-ref new-ref] (map #(util/format "[[%s]]" %) [old-name new-name])
- [old-name new-name] (map #(if (string/includes? % "/")
- (string/replace % "/" ".")
- %)
- [original-old-name original-new-name])
- old-org-ref (and (= :org (state/get-preferred-format))
- (:org-mode/insert-file-link? (state/get-config))
- (re-find
- (re-pattern
- (util/format
- "\\[\\[file:\\.*/.*%s\\.org\\]\\[(.*?)\\]\\]" old-name))
- content))]
- (-> (if old-org-ref
- (let [[old-full-ref old-label] old-org-ref
- new-label (if (= old-label original-old-name)
- original-new-name
- old-label)
- new-full-ref (-> (string/replace old-full-ref old-name new-name)
- (string/replace (str "[" old-label "]")
- (str "[" new-label "]")))]
- (string/replace content old-full-ref new-full-ref))
- content)
- (string/replace old-ref new-ref))))
- (defn- replace-tag-ref!
- [content old-name new-name]
- (let [old-tag (util/format "#%s" old-name)
- new-tag (if (re-find #"[\s\t]+" new-name)
- (util/format "#[[%s]]" new-name)
- (str "#" new-name))]
- (-> (util/replace-ignore-case content (str "^" old-tag "\\b") new-tag)
- (util/replace-ignore-case (str " " old-tag " ") (str " " new-tag " "))
- (util/replace-ignore-case (str " " old-tag "$") (str " " new-tag)))))
- (defn- replace-old-page!
- "Unsanitized names"
- [content old-name new-name]
- (when (and (string? content) (string? old-name) (string? new-name))
- (-> content
- (replace-page-ref! old-name new-name)
- (replace-tag-ref! old-name new-name))))
- (defn- walk-replace-old-page!
- "Unsanitized names"
- [form old-name new-name]
- (walk/postwalk (fn [f]
- (cond
- (and (vector? f)
- (contains? #{"Search" "Label"} (first f))
- (string/starts-with? (second f) (str old-name "/")))
- [(first f) (string/replace-first (second f)
- (str old-name "/")
- (str new-name "/"))]
- (string? f)
- (if (= f old-name)
- new-name
- (replace-old-page! f old-name new-name))
- :else
- f))
- form))
- (defn favorited?
- [page-name]
- (let [favorites (->> (:favorites (state/get-config))
- (filter string?)
- (map string/lower-case)
- (set))]
- (contains? favorites page-name)))
- (defn favorite-page!
- [page-name]
- (when-not (string/blank? page-name)
- (let [favorites (->
- (cons
- page-name
- (or (:favorites (state/get-config)) []))
- (distinct)
- (vec))]
- (config-handler/set-config! :favorites favorites))))
- (defn unfavorite-page!
- [page-name]
- (when-not (string/blank? page-name)
- (let [favorites (->> (:favorites (state/get-config))
- (remove #(= (string/lower-case %) (string/lower-case page-name)))
- (vec))]
- (config-handler/set-config! :favorites favorites))))
- (defn toggle-favorite! []
- ;; NOTE: in journals or settings, current-page is nil
- (when-let [page-name (state/get-current-page)]
- (let [favorites (:favorites (state/sub-graph-config))
- favorited? (contains? (set (map string/lower-case favorites))
- (string/lower-case page-name))]
- (if favorited?
- (unfavorite-page! page-name)
- (favorite-page! page-name)))))
- (defn delete!
- [page-name ok-handler & {:keys [delete-file?]
- :or {delete-file? true}}]
- (when page-name
- (when-let [repo (state/get-current-repo)]
- (let [page-name (util/page-name-sanity-lc page-name)
- blocks (db/get-page-blocks-no-cache page-name)
- tx-data (mapv
- (fn [block]
- [:db.fn/retractEntity [:block/uuid (:block/uuid block)]])
- blocks)
- page (db/entity [:block/name page-name])]
- (db/transact! tx-data)
- (delete-file! repo page-name delete-file?)
- ;; if other page alias this pagename,
- ;; then just remove some attrs of this entity instead of retractEntity
- (when-not (:block/_namespace page)
- (if (model/get-alias-source-page (state/get-current-repo) page-name)
- (when-let [id (:db/id (db/entity [:block/name page-name]))]
- (let [txs (mapv (fn [attribute]
- [:db/retract id attribute])
- db-schema/retract-page-attributes)]
- (db/transact! txs)))
- (db/transact! [[:db.fn/retractEntity [:block/name page-name]]])))
- (unfavorite-page! page-name)
- (when (fn? ok-handler) (ok-handler))
- (ui-handler/re-render-root!)))))
- (defn- rename-update-block-refs!
- [refs from-id to-id]
- (->> refs
- (remove #{{:db/id from-id}})
- (cons {:db/id to-id})
- (distinct)
- (vec)))
- (defn- rename-update-refs!
- "Unsanitized only"
- [page old-original-name new-name]
- ;; update all pages which have references to this page
- (let [repo (state/get-current-repo)
- to-page (db/entity [:block/name (util/page-name-sanity-lc new-name)])
- blocks (db/get-page-referenced-blocks-no-cache (:db/id page))
- page-ids (->> (map :block/page blocks)
- (remove nil?)
- (set))
- tx (->> (map (fn [{:block/keys [uuid content properties] :as block}]
- (let [content (let [content' (replace-old-page! content old-original-name new-name)]
- (when-not (= content' content)
- content'))
- properties (let [properties' (walk-replace-old-page! properties old-original-name new-name)]
- (when-not (= properties' properties)
- properties'))]
- (when (or content properties)
- (util/remove-nils-non-nested
- {:block/uuid uuid
- :block/content content
- :block/properties properties
- :block/refs (rename-update-block-refs! (:block/refs block) (:db/id page) (:db/id to-page))
- :block/path-refs (rename-update-block-refs! (:block/path-refs block) (:db/id page) (:db/id to-page))})))) blocks)
- (remove nil?))]
- (db/transact! repo tx)
- (doseq [page-id page-ids]
- (outliner-file/sync-to-file page-id))))
- (defn- rename-page-aux
- "Only accepts unsanitized page names"
- [old-name new-name redirect?]
- (let [old-page-name (util/page-name-sanity-lc old-name)
- new-file-name (util/file-name-sanity new-name)
- new-page-name (util/page-name-sanity-lc new-name)
- repo (state/get-current-repo)
- page (db/pull [:block/name old-page-name])]
- (when (and repo page)
- (let [old-original-name (:block/original-name page)
- file (:block/file page)
- journal? (:block/journal? page)
- properties-block (:data (outliner-tree/-get-down (outliner-core/block page)))
- properties-block-tx (when (and properties-block
- (string/includes? (util/page-name-sanity-lc (:block/content properties-block))
- old-page-name))
- (let [front-matter? (and (property/front-matter? (:block/content properties-block))
- (= :markdown (:block/format properties-block)))]
- {:db/id (:db/id properties-block)
- :block/content (property/insert-property (:block/format properties-block)
- (:block/content properties-block)
- :title
- new-name
- front-matter?)}))
- page-txs [{:db/id (:db/id page)
- :block/uuid (:block/uuid page)
- :block/name new-page-name
- :block/original-name new-name}]
- page-txs (if properties-block-tx (conj page-txs properties-block-tx) page-txs)]
- (d/transact! (db/get-db repo false) page-txs)
- ;; If page name changed after sanitization
- (when (or (util/create-title-property? new-page-name)
- (not= (gp-util/page-name-sanity new-name false) new-name))
- (page-property/add-property! new-page-name :title new-name))
- (when (and file (not journal?))
- (rename-file! file new-file-name (fn [] nil)))
- (rename-update-refs! page old-original-name new-name)
- (outliner-file/sync-to-file page))
- ;; Redirect to the newly renamed page
- (when redirect?
- (route-handler/redirect! {:to :page
- :push false
- :path-params {:name new-page-name}}))
- (when (favorited? old-page-name)
- (p/do!
- (unfavorite-page! old-page-name)
- (favorite-page! new-page-name)))
- (recent-handler/update-or-add-renamed-page repo old-page-name new-page-name)
- (ui-handler/re-render-root!))))
- (defn- rename-nested-pages
- "Unsanitized names only"
- [old-ns-name new-ns-name]
- (let [repo (state/get-current-repo)
- nested-page-str (util/format "[[%s]]" (util/page-name-sanity-lc old-ns-name))
- ns-prefix (util/format "[[%s/" (util/page-name-sanity-lc old-ns-name))
- nested-pages (db/get-pages-by-name-partition repo nested-page-str)
- nested-pages-ns (db/get-pages-by-name-partition repo ns-prefix)]
- (when nested-pages
- ;; rename page "[[obsidian]] is a tool" to "[[logseq]] is a tool"
- (doseq [{:block/keys [name original-name]} nested-pages]
- (let [old-page-title (or original-name name)
- new-page-title (string/replace
- old-page-title
- (util/format "[[%s]]" old-ns-name)
- (util/format "[[%s]]" new-ns-name))]
- (when (and old-page-title new-page-title)
- (p/do!
- (rename-page-aux old-page-title new-page-title false)
- (println "Renamed " old-page-title " to " new-page-title))))))
- (when nested-pages-ns
- ;; rename page "[[obsidian/page1]] is a tool" to "[[logseq/page1]] is a tool"
- (doseq [{:block/keys [name original-name]} nested-pages-ns]
- (let [old-page-title (or original-name name)
- new-page-title (string/replace
- old-page-title
- (util/format "[[%s/" old-ns-name)
- (util/format "[[%s/" new-ns-name))]
- (when (and old-page-title new-page-title)
- (p/do!
- (rename-page-aux old-page-title new-page-title false)
- (println "Renamed " old-page-title " to " new-page-title))))))))
- (defn- rename-namespace-pages!
- "Original names (unsanitized only)"
- [repo old-name new-name]
- (let [pages (db/get-namespace-pages repo old-name)
- page (db/pull [:block/name (util/page-name-sanity-lc old-name)])
- pages (cons page pages)]
- (doseq [{:block/keys [name original-name]} pages]
- (let [old-page-title (or original-name name)
- new-page-title (string/replace old-page-title old-name new-name)
- redirect? (= name (:block/name page))]
- (when (and old-page-title new-page-title)
- (p/let [_ (rename-page-aux old-page-title new-page-title redirect?)]
- (println "Renamed " old-page-title " to " new-page-title)))))))
- (defn merge-pages!
- "Only accepts sanitized page names"
- [from-page-name to-page-name]
- (when (and (db/page-exists? from-page-name)
- (db/page-exists? to-page-name)
- (not= from-page-name to-page-name))
- (let [to-page (db/entity [:block/name to-page-name])
- to-id (:db/id to-page)
- from-page (db/entity [:block/name from-page-name])
- from-id (:db/id from-page)
- from-first-child (some->> (db/pull from-id)
- (outliner-core/block)
- (outliner-tree/-get-down)
- (outliner-core/get-data))
- to-last-direct-child-id (model/get-block-last-direct-child (db/get-db) to-id false)
- repo (state/get-current-repo)
- conn (conn/get-db repo false)
- datoms (d/datoms @conn :avet :block/page from-id)
- block-eids (mapv :e datoms)
- blocks (db-utils/pull-many repo '[:db/id :block/page :block/refs :block/path-refs :block/left :block/parent] block-eids)
- tx-data (map (fn [block]
- (let [id (:db/id block)]
- (cond->
- {:db/id id
- :block/page {:db/id to-id}
- :block/path-refs (rename-update-block-refs! (:block/path-refs block) from-id to-id)
- :block/refs (rename-update-block-refs! (:block/refs block) from-id to-id)}
- (and from-first-child (= id (:db/id from-first-child)))
- (assoc :block/left {:db/id (or to-last-direct-child-id to-id)})
- (= (:block/parent block) {:db/id from-id})
- (assoc :block/parent {:db/id to-id})))) blocks)]
- (d/transact! conn tx-data)
- (outliner-file/sync-to-file {:db/id to-id})
- (rename-update-refs! from-page
- (util/get-page-original-name from-page)
- (util/get-page-original-name to-page)))
- (delete! from-page-name nil)
- (route-handler/redirect! {:to :page
- :push false
- :path-params {:name to-page-name}})))
- (defn rename!
- "Accepts unsanitized page names"
- [old-name new-name]
- (let [repo (state/get-current-repo)
- old-name (string/trim old-name)
- new-name (string/trim new-name)
- old-page-name (util/page-name-sanity-lc old-name)
- new-page-name (util/page-name-sanity-lc new-name)
- name-changed? (not= old-name new-name)]
- (if (and old-name
- new-name
- (not (string/blank? new-name))
- name-changed?)
- (do
- (cond
- (= old-page-name new-page-name)
- (rename-page-aux old-name new-name true)
- (db/pull [:block/name new-page-name])
- (merge-pages! old-page-name new-page-name)
- :else
- (rename-namespace-pages! repo old-name new-name))
- (rename-nested-pages old-name new-name))
- (when (string/blank? new-name)
- (notification/show! "Please use a valid name, empty name is not allowed!" :error)))))
- (defn- split-col-by-element
- [col element]
- (let [col (vec col)
- idx (.indexOf col element)]
- [(subvec col 0 (inc idx))
- (subvec col (inc idx))]))
- (defn reorder-favorites!
- [{:keys [to up?]}]
- (let [favorites (:favorites (state/get-config))
- from (get @state/state :favorites/dragging)]
- (when (and from to (not= from to))
- (let [[prev next] (split-col-by-element favorites to)
- [prev next] (mapv #(remove (fn [e] (= from e)) %) [prev next])
- favorites (->>
- (if up?
- (concat (drop-last prev) [from (last prev)] next)
- (concat prev [from] next))
- (remove nil?)
- (distinct))]
- (config-handler/set-config! :favorites favorites)))))
- (defn has-more-journals?
- []
- (let [current-length (:journals-length @state/state)]
- (< current-length (db/get-journals-length))))
- (defn load-more-journals!
- []
- (when (has-more-journals?)
- (state/set-journals-length! (+ (:journals-length @state/state) 7))))
- (defn update-public-attribute!
- [page-name value]
- (page-property/add-property! page-name :public value))
- (defn get-page-ref-text
- [page]
- (let [edit-block-file-path (model/get-block-file-path (state/get-edit-block))
- page-name (string/lower-case page)]
- (if (and edit-block-file-path
- (state/org-mode-file-link? (state/get-current-repo)))
- (if-let [ref-file-path (:file/path (db/get-page-file page-name))]
- (util/format "[[file:%s][%s]]"
- (util/get-relative-path edit-block-file-path ref-file-path)
- page)
- (let [journal? (date/valid-journal-title? page)
- ref-file-path (str
- (if (or (util/electron?) (mobile-util/native-platform?))
- (-> (config/get-repo-dir (state/get-current-repo))
- js/decodeURI
- (string/replace #"/+$" "")
- (str "/"))
- "")
- (get-directory journal?)
- "/"
- (get-file-name journal? page)
- ".org")]
- (create! page {:redirect? false})
- (util/format "[[file:%s][%s]]"
- (util/get-relative-path edit-block-file-path ref-file-path)
- page)))
- (util/format "[[%s]]" page))))
- (defn init-commands!
- []
- (commands/init-commands! get-page-ref-text))
- (def rebuild-slash-commands-list!
- (debounce init-commands! 1500))
- (defn template-exists?
- [title]
- (when title
- (let [templates (keys (db/get-all-templates))]
- (when (seq templates)
- (let [templates (map string/lower-case templates)]
- (contains? (set templates) (string/lower-case title)))))))
- (defn ls-dir-files!
- [ok-handler]
- (web-nfs/ls-dir-files-with-handler!
- (fn []
- (init-commands!)
- (when ok-handler (ok-handler)))))
- (defn get-all-pages
- [repo]
- (->> (db/get-all-pages repo)
- (remove (fn [p]
- (let [name (:block/name p)]
- (or (util/uuid-string? name)
- (gp-config/draw? name)
- (db/built-in-pages-names (string/upper-case name))))))
- (common-handler/fix-pages-timestamps)))
- (defn get-filters
- [page-name]
- (let [properties (db/get-page-properties page-name)
- properties-str (get properties :filters "{}")]
- (try (reader/read-string properties-str)
- (catch js/Error e
- (log/error :syntax/filters e)))))
- (defn save-filter!
- [page-name filter-state]
- (page-property/add-property! page-name :filters filter-state))
- ;; Editor
- (defn page-not-exists-handler
- [input id q current-pos]
- (state/set-editor-show-page-search! false)
- (if (state/org-mode-file-link? (state/get-current-repo))
- (let [page-ref-text (get-page-ref-text q)
- value (gobj/get input "value")
- old-page-ref (util/format "[[%s]]" q)
- new-value (string/replace value
- old-page-ref
- page-ref-text)]
- (state/set-edit-content! id new-value)
- (let [new-pos (+ current-pos
- (- (count page-ref-text)
- (count old-page-ref))
- 2)]
- (cursor/move-cursor-to input new-pos)))
- (let [current-selected (util/get-selected-text)]
- (cursor/move-cursor-forward input (+ 2 (count current-selected))))))
- (defn on-chosen-handler
- [input id _q pos format]
- (let [current-pos (cursor/pos input)
- edit-content (state/sub [:editor/content id])
- q (or
- @editor-handler/*selected-text
- (when (state/sub :editor/show-page-search-hashtag?)
- (gp-util/safe-subs edit-content pos current-pos))
- (when (> (count edit-content) current-pos)
- (gp-util/safe-subs edit-content pos current-pos)))]
- (if (state/sub :editor/show-page-search-hashtag?)
- (fn [chosen _click?]
- (state/set-editor-show-page-search! false)
- (let [wrapped? (= "[[" (gp-util/safe-subs edit-content (- pos 2) pos))
- chosen (if (string/starts-with? chosen "New page: ") ;; FIXME: What if a page named "New page: XXX"?
- (subs chosen 10)
- chosen)
- chosen (if (and (util/safe-re-find #"\s+" chosen) (not wrapped?))
- (util/format "[[%s]]" chosen)
- chosen)
- q (if @editor-handler/*selected-text "" q)
- [last-pattern forward-pos] (if wrapped?
- [q 3]
- (if (= \# (first q))
- [(subs q 1) 1]
- [q 2]))
- last-pattern (str "#" (when wrapped? "[[") last-pattern)]
- (editor-handler/insert-command! id
- (str "#" (when wrapped? "[[") chosen)
- format
- {:last-pattern last-pattern
- :end-pattern (when wrapped? "]]")
- :forward-pos forward-pos})))
- (fn [chosen _click?]
- (state/set-editor-show-page-search! false)
- (let [chosen (if (string/starts-with? chosen "New page: ")
- (subs chosen 10)
- chosen)
- page-ref-text (get-page-ref-text chosen)]
- (editor-handler/insert-command! id
- page-ref-text
- format
- {:last-pattern (str "[[" (if @editor-handler/*selected-text "" q))
- :end-pattern "]]"
- :postfix-fn (fn [s] (util/replace-first "]]" s ""))
- :forward-pos 3}))))))
- (defn create-today-journal!
- []
- (when-let [repo (state/get-current-repo)]
- (when (and (state/enable-journals? repo)
- (not (state/loading-files? repo)))
- (state/set-today! (date/today))
- (when (or (config/local-db? repo)
- (and (= "local" repo) (not (mobile-util/native-platform?))))
- (let [title (date/today)
- today-page (util/page-name-sanity-lc title)
- format (state/get-preferred-format repo)
- file-name (date/journal-title->default title)
- path (str (config/get-journals-directory) "/" file-name "."
- (config/get-file-extension format))
- file-path (str "/" path)
- repo-dir (config/get-repo-dir repo)
- template (state/get-default-journal-template)]
- (p/let [file-exists? (fs/file-exists? repo-dir file-path)
- file-content (when file-exists?
- (fs/read-file repo-dir file-path))]
- (when (and (db/page-empty? repo today-page)
- (or (not file-exists?)
- (and file-exists? (string/blank? file-content))))
- (create! title {:redirect? false
- :split-namespace? false
- :create-first-block? (not template)
- :journal? true})
- (state/pub-event! [:journal/insert-template today-page])
- (ui-handler/re-render-root!))))))))
- (defn open-today-in-sidebar
- []
- (when-let [page (db/entity [:block/name (util/page-name-sanity-lc (date/today))])]
- (state/sidebar-add-block!
- (state/get-current-repo)
- (:db/id page)
- :page)))
- (defn open-file-in-default-app []
- (when-let [file-path (and (util/electron?) (get-page-file-path))]
- (js/window.apis.openPath file-path)))
- (defn copy-current-file []
- (when-let [file-path (and (util/electron?) (get-page-file-path))]
- (util/copy-to-clipboard! file-path)))
- (defn open-file-in-directory []
- (when-let [file-path (and (util/electron?) (get-page-file-path))]
- (js/window.apis.showItemInFolder file-path)))
|