mirror of
https://github.com/logseq/logseq.git
synced 2026-05-21 03:12:38 +00:00
refactor: separate api into multiple namespaces
This commit is contained in:
File diff suppressed because it is too large
Load Diff
182
src/main/logseq/api/app.cljs
Normal file
182
src/main/logseq/api/app.cljs
Normal file
@@ -0,0 +1,182 @@
|
||||
(ns logseq.api.app
|
||||
"app state/ui related apis"
|
||||
(:require [cljs-bean.core :as bean]
|
||||
[cljs.reader]
|
||||
[clojure.string :as string]
|
||||
[electron.ipc :as ipc]
|
||||
[frontend.config :as config]
|
||||
[frontend.db.utils :as db-utils]
|
||||
[frontend.handler.command-palette :as palette-handler]
|
||||
[frontend.handler.config :as config-handler]
|
||||
[frontend.handler.plugin :as plugin-handler]
|
||||
[frontend.handler.recent :as recent-handler]
|
||||
[frontend.handler.route :as route-handler]
|
||||
[frontend.modules.layout.core]
|
||||
[frontend.state :as state]
|
||||
[frontend.util :as util]
|
||||
[frontend.version :as fv]
|
||||
[logseq.api.db-based :as db-based-api]
|
||||
[logseq.sdk.core]
|
||||
[logseq.sdk.experiments]
|
||||
[logseq.sdk.git]
|
||||
[logseq.sdk.utils :as sdk-utils]
|
||||
[reitit.frontend.easy :as rfe]))
|
||||
|
||||
(defn get_state_from_store
|
||||
[^js path]
|
||||
(when-let [path (if (string? path) [path] (bean/->clj path))]
|
||||
(some->> path
|
||||
(map #(if (string/starts-with? % "@")
|
||||
(subs % 1)
|
||||
(keyword %)))
|
||||
(get-in @state/state)
|
||||
(#(if (util/atom? %) @% %))
|
||||
(sdk-utils/normalize-keyword-for-json)
|
||||
(bean/->js))))
|
||||
|
||||
(defn set_state_from_store
|
||||
[^js path ^js value]
|
||||
(when-let [path (if (string? path) [path] (bean/->clj path))]
|
||||
(some->> path
|
||||
(map #(if (string/starts-with? % "@")
|
||||
(subs % 1)
|
||||
(keyword %)))
|
||||
(into [])
|
||||
(#(state/set-state! % (bean/->clj value))))))
|
||||
|
||||
(defn get_app_info
|
||||
;; get app base info
|
||||
[]
|
||||
(-> (sdk-utils/normalize-keyword-for-json
|
||||
{:version fv/version
|
||||
:supportDb true})
|
||||
(bean/->js)))
|
||||
|
||||
(def get_user_configs
|
||||
(fn []
|
||||
(bean/->js
|
||||
(sdk-utils/normalize-keyword-for-json
|
||||
{:preferred-language (:preferred-language @state/state)
|
||||
:preferred-theme-mode (:ui/theme @state/state)
|
||||
:preferred-format (state/get-preferred-format)
|
||||
:preferred-workflow (state/get-preferred-workflow)
|
||||
:preferred-todo (state/get-preferred-todo)
|
||||
:preferred-date-format (state/get-date-formatter)
|
||||
:preferred-start-of-week (state/get-start-of-week)
|
||||
:current-graph (state/get-current-repo)
|
||||
:show-brackets (state/show-brackets?)
|
||||
:enabled-journals (state/enable-journals?)
|
||||
:enabled-flashcards (state/enable-flashcards?)
|
||||
:me (state/get-me)}))))
|
||||
|
||||
(def get_current_graph_configs
|
||||
(fn [& keys]
|
||||
(some-> (state/get-config)
|
||||
(#(if (seq keys) (get-in % (map keyword keys)) %))
|
||||
(bean/->js))))
|
||||
|
||||
(def set_current_graph_configs
|
||||
(fn [^js configs]
|
||||
(when-let [configs (bean/->clj configs)]
|
||||
(when (map? configs)
|
||||
(doseq [[k v] configs]
|
||||
(config-handler/set-config! k v))))))
|
||||
|
||||
(def get_current_graph_favorites
|
||||
(fn []
|
||||
(if (config/db-based-graph?)
|
||||
(db-based-api/get-favorites)
|
||||
(some->> (:favorites (state/get-config))
|
||||
(remove string/blank?)
|
||||
(filter string?)
|
||||
(bean/->js)))))
|
||||
|
||||
(def get_current_graph_recent
|
||||
(fn []
|
||||
(some->> (recent-handler/get-recent-pages)
|
||||
(map #(db-utils/entity (:db/id %)))
|
||||
(remove nil?)
|
||||
(sdk-utils/normalize-keyword-for-json)
|
||||
(bean/->js))))
|
||||
|
||||
(def get_current_graph
|
||||
(fn []
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when-not (= config/demo-repo repo)
|
||||
(bean/->js {:url repo
|
||||
:name (util/node-path.basename repo)
|
||||
:path (config/get-repo-dir repo)})))))
|
||||
|
||||
(def show_themes
|
||||
(fn []
|
||||
(state/pub-event! [:modal/show-themes-modal])))
|
||||
|
||||
(def set_theme_mode
|
||||
(fn [mode]
|
||||
(state/set-theme-mode! mode)))
|
||||
|
||||
(def relaunch
|
||||
(fn []
|
||||
(ipc/ipc "relaunchApp")))
|
||||
|
||||
(def quit
|
||||
(fn []
|
||||
(ipc/ipc "quitApp")))
|
||||
|
||||
(def open_external_link
|
||||
(fn [url]
|
||||
(when (re-find #"https?://" url)
|
||||
(js/apis.openExternal url))))
|
||||
|
||||
(def invoke_external_command
|
||||
(fn [type & args]
|
||||
(when-let [id (and (string/starts-with? type "logseq.")
|
||||
(-> (string/replace type #"^logseq." "")
|
||||
(util/safe-lower-case)
|
||||
(keyword)))]
|
||||
(when-let [action (get-in (palette-handler/get-commands-unique) [id :action])]
|
||||
(apply plugin-handler/hook-lifecycle-fn! id action args)))))
|
||||
|
||||
;; flag - boolean | 'toggle'
|
||||
(def set_left_sidebar_visible
|
||||
(fn [flag]
|
||||
(if (= flag "toggle")
|
||||
(state/toggle-left-sidebar!)
|
||||
(state/set-state! :ui/left-sidebar-open? (boolean flag)))
|
||||
nil))
|
||||
|
||||
;; flag - boolean | 'toggle'
|
||||
(def set_right_sidebar_visible
|
||||
(fn [flag]
|
||||
(if (= flag "toggle")
|
||||
(state/toggle-sidebar-open?!)
|
||||
(state/set-state! :ui/sidebar-open? (boolean flag)))
|
||||
nil))
|
||||
|
||||
(def clear_right_sidebar_blocks
|
||||
(fn [^js opts]
|
||||
(state/clear-sidebar-blocks!)
|
||||
(when-let [opts (and opts (bean/->clj opts))]
|
||||
(and (:close opts) (state/hide-right-sidebar!)))
|
||||
nil))
|
||||
|
||||
(def push_state
|
||||
(fn [^js k ^js params ^js query]
|
||||
(let [k (keyword k)
|
||||
page? (= k :page)
|
||||
params (bean/->clj params)
|
||||
query (bean/->clj query)]
|
||||
(if page?
|
||||
(-> (:name params)
|
||||
(route-handler/redirect-to-page! {:anchor (:anchor query) :push true}))
|
||||
(rfe/push-state k params query)))))
|
||||
|
||||
(def replace_state
|
||||
(fn [^js k ^js params ^js query]
|
||||
(let [k (keyword k)
|
||||
page? (= k :page)
|
||||
params (bean/->clj params)
|
||||
query (bean/->clj query)]
|
||||
(if-let [page-name (and page? (:name params))]
|
||||
(route-handler/redirect-to-page! page-name {:anchor (:anchor query) :push false})
|
||||
(rfe/replace-state k params query)))))
|
||||
@@ -1,124 +1,51 @@
|
||||
(ns logseq.api.db
|
||||
"DB version related fns"
|
||||
"DB APIs"
|
||||
(:require [cljs-bean.core :as bean]
|
||||
[cljs.reader]
|
||||
[clojure.walk :as walk]
|
||||
[datascript.core :as d]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.model :as db-model]
|
||||
[frontend.handler.common.page :as page-common-handler]
|
||||
[frontend.handler.editor :as editor-handler]
|
||||
[frontend.handler.page :as page-handler]
|
||||
[frontend.db.async :as db-async]
|
||||
[frontend.db.query-custom :as query-custom]
|
||||
[frontend.db.query-dsl :as query-dsl]
|
||||
[frontend.db.query-react :as query-react]
|
||||
[frontend.modules.layout.core]
|
||||
[frontend.state :as state]
|
||||
[frontend.util :as util]
|
||||
[logseq.api.block :as api-block]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.outliner.core :as outliner-core]
|
||||
[logseq.sdk.core]
|
||||
[logseq.sdk.experiments]
|
||||
[logseq.sdk.git]
|
||||
[logseq.sdk.utils :as sdk-utils]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defn result->js
|
||||
[result]
|
||||
(-> result
|
||||
sdk-utils/normalize-keyword-for-json
|
||||
bean/->js))
|
||||
(defn q
|
||||
[query-string]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(p/let [result (query-dsl/query repo query-string
|
||||
{:disable-reactive? true
|
||||
:return-promise? true})]
|
||||
(bean/->js (sdk-utils/normalize-keyword-for-json (flatten result))))))
|
||||
|
||||
(defn get-favorites
|
||||
[]
|
||||
(p/let [favorites (page-handler/get-favorites)]
|
||||
(result->js favorites)))
|
||||
(defn datascript_query
|
||||
[query & inputs]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when-let [db (db/get-db repo)]
|
||||
(p/let [query (cljs.reader/read-string query)
|
||||
resolved-inputs (map #(cond
|
||||
(string? %)
|
||||
(some->> % (cljs.reader/read-string) (query-react/resolve-input db))
|
||||
|
||||
(defn insert-batch-blocks
|
||||
[this target blocks opts]
|
||||
(let [blocks' (walk/prewalk
|
||||
(fn [f]
|
||||
(if (and (map? f) (:content f) (nil? (:uuid f)))
|
||||
(assoc f :uuid (d/squuid))
|
||||
f))
|
||||
blocks)
|
||||
{:keys [sibling before schema]} opts
|
||||
block (if before
|
||||
(db/pull (:db/id (ldb/get-left-sibling (db/entity (:db/id target))))) target)
|
||||
sibling? (if (ldb/page? block) false sibling)
|
||||
uuid->properties (let [blocks (outliner-core/tree-vec-flatten blocks' :children)]
|
||||
(when (some (fn [b] (seq (:properties b))) blocks)
|
||||
(zipmap (map :uuid blocks)
|
||||
(map :properties blocks))))]
|
||||
(p/let [result (editor-handler/insert-block-tree-after-target
|
||||
(:db/id block) sibling? blocks' (get block :block/format :markdown) true)
|
||||
blocks (:blocks result)]
|
||||
(when (seq blocks)
|
||||
(p/doseq [block blocks]
|
||||
(let [id (:block/uuid block)
|
||||
b (db/entity [:block/uuid id])
|
||||
properties (when uuid->properties (uuid->properties id))]
|
||||
(when (seq properties)
|
||||
(api-block/db-based-save-block-properties! b properties {:plugin this
|
||||
:schema schema})))))
|
||||
(let [blocks' (map (fn [b] (db/entity [:block/uuid (:block/uuid b)])) blocks)]
|
||||
(result->js blocks')))))
|
||||
(fn? %)
|
||||
(fn [& args]
|
||||
(.apply % nil (clj->js (mapv bean/->js args))))
|
||||
|
||||
(defn insert-block
|
||||
[this content properties schema opts]
|
||||
(p/let [new-block (editor-handler/api-insert-new-block! content opts)]
|
||||
(when (seq properties)
|
||||
(api-block/db-based-save-block-properties! new-block properties {:plugin this
|
||||
:schema schema}))
|
||||
(let [block (db/entity [:block/uuid (:block/uuid new-block)])]
|
||||
(result->js block))))
|
||||
:else %)
|
||||
inputs)
|
||||
result (apply db-async/<q repo {:transact-db? false}
|
||||
(cons query resolved-inputs))]
|
||||
(bean/->js (sdk-utils/normalize-keyword-for-json result false))))))
|
||||
|
||||
(defn update-block
|
||||
[this block content opts]
|
||||
(when block
|
||||
(let [repo (state/get-current-repo)
|
||||
block-uuid (:block/uuid block)]
|
||||
(p/do!
|
||||
(when (seq (:properties opts))
|
||||
(api-block/db-based-save-block-properties! block (:properties opts)
|
||||
{:plugin this
|
||||
:schema (:schema opts)}))
|
||||
(editor-handler/save-block! repo
|
||||
(sdk-utils/uuid-or-throw-error block-uuid) content
|
||||
(dissoc opts :properties))))))
|
||||
|
||||
(defn remove-property
|
||||
[property]
|
||||
(when-let [uuid (and (api-block/plugin-property-key? (:db/ident property))
|
||||
(:block/uuid property))]
|
||||
(page-common-handler/<delete! uuid nil nil)))
|
||||
|
||||
(defn upsert-block-property
|
||||
[this block key' value schema]
|
||||
(let [opts {:plugin this
|
||||
:schema (when schema
|
||||
{key schema})}]
|
||||
(api-block/db-based-save-block-properties! block {key' value} opts)))
|
||||
|
||||
(defn get-all-tags
|
||||
[]
|
||||
(-> (db-model/get-all-classes (state/get-current-repo)
|
||||
{:except-root-class? true})
|
||||
result->js))
|
||||
|
||||
(defn get-all-properties
|
||||
[]
|
||||
(-> (ldb/get-all-properties (db/get-db))
|
||||
result->js))
|
||||
|
||||
(defn get-tag-objects
|
||||
[class-uuid-or-ident]
|
||||
(let [eid (if (util/uuid-string? class-uuid-or-ident)
|
||||
(when-let [id (sdk-utils/uuid-or-throw-error class-uuid-or-ident)]
|
||||
[:block/uuid id])
|
||||
(keyword (api-block/sanitize-user-property-name class-uuid-or-ident)))
|
||||
class (db/entity eid)]
|
||||
(if-not class
|
||||
(throw (ex-info (str "Tag not exists with id: " eid) {}))
|
||||
(p/let [result (state/<invoke-db-worker :thread-api/get-class-objects
|
||||
(state/get-current-repo)
|
||||
(:db/id class))]
|
||||
(result->js result)))))
|
||||
(defn custom_query
|
||||
[query-string]
|
||||
(p/let [result (let [query (cljs.reader/read-string query-string)]
|
||||
(query-custom/custom-query {:query query
|
||||
:disable-reactive? true
|
||||
:return-promise? true}))]
|
||||
(bean/->js (sdk-utils/normalize-keyword-for-json (flatten result)))))
|
||||
|
||||
169
src/main/logseq/api/db_based.cljs
Normal file
169
src/main/logseq/api/db_based.cljs
Normal file
@@ -0,0 +1,169 @@
|
||||
(ns logseq.api.db-based
|
||||
"DB version related fns"
|
||||
(:require [cljs-bean.core :as bean]
|
||||
[cljs.reader]
|
||||
[clojure.string :as string]
|
||||
[clojure.walk :as walk]
|
||||
[datascript.core :as d]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.model :as db-model]
|
||||
[frontend.handler.common.page :as page-common-handler]
|
||||
[frontend.handler.db-based.property :as db-property-handler]
|
||||
[frontend.handler.editor :as editor-handler]
|
||||
[frontend.handler.page :as page-handler]
|
||||
[frontend.modules.layout.core]
|
||||
[frontend.state :as state]
|
||||
[frontend.util :as util]
|
||||
[logseq.api.block :as api-block]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.outliner.core :as outliner-core]
|
||||
[logseq.sdk.core]
|
||||
[logseq.sdk.experiments]
|
||||
[logseq.sdk.git]
|
||||
[logseq.sdk.utils :as sdk-utils]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defn -get-property
|
||||
[^js plugin k]
|
||||
(when-let [k' (and (string? k) (api-block/sanitize-user-property-name k))]
|
||||
(let [property-ident (api-block/get-db-ident-from-property-name k' plugin)]
|
||||
(db/entity property-ident))))
|
||||
|
||||
(defn get-favorites
|
||||
[]
|
||||
(p/let [favorites (page-handler/get-favorites)]
|
||||
(sdk-utils/result->js favorites)))
|
||||
|
||||
(defn insert-batch-blocks
|
||||
[this target blocks opts]
|
||||
(let [blocks' (walk/prewalk
|
||||
(fn [f]
|
||||
(if (and (map? f) (:content f) (nil? (:uuid f)))
|
||||
(assoc f :uuid (d/squuid))
|
||||
f))
|
||||
blocks)
|
||||
{:keys [sibling before schema]} opts
|
||||
block (if before
|
||||
(db/pull (:db/id (ldb/get-left-sibling (db/entity (:db/id target))))) target)
|
||||
sibling? (if (ldb/page? block) false sibling)
|
||||
uuid->properties (let [blocks (outliner-core/tree-vec-flatten blocks' :children)]
|
||||
(when (some (fn [b] (seq (:properties b))) blocks)
|
||||
(zipmap (map :uuid blocks)
|
||||
(map :properties blocks))))]
|
||||
(p/let [result (editor-handler/insert-block-tree-after-target
|
||||
(:db/id block) sibling? blocks' (get block :block/format :markdown) true)
|
||||
blocks (:blocks result)]
|
||||
(when (seq blocks)
|
||||
(p/doseq [block blocks]
|
||||
(let [id (:block/uuid block)
|
||||
b (db/entity [:block/uuid id])
|
||||
properties (when uuid->properties (uuid->properties id))]
|
||||
(when (seq properties)
|
||||
(api-block/db-based-save-block-properties! b properties {:plugin this
|
||||
:schema schema})))))
|
||||
(let [blocks' (map (fn [b] (db/entity [:block/uuid (:block/uuid b)])) blocks)]
|
||||
(sdk-utils/result->js blocks')))))
|
||||
|
||||
(defn insert-block
|
||||
[this content properties schema opts]
|
||||
(p/let [new-block (editor-handler/api-insert-new-block! content opts)]
|
||||
(when (seq properties)
|
||||
(api-block/db-based-save-block-properties! new-block properties {:plugin this
|
||||
:schema schema}))
|
||||
(let [block (db/entity [:block/uuid (:block/uuid new-block)])]
|
||||
(sdk-utils/result->js block))))
|
||||
|
||||
(defn update-block
|
||||
[this block content opts]
|
||||
(when block
|
||||
(let [repo (state/get-current-repo)
|
||||
block-uuid (:block/uuid block)]
|
||||
(p/do!
|
||||
(when (seq (:properties opts))
|
||||
(api-block/db-based-save-block-properties! block (:properties opts)
|
||||
{:plugin this
|
||||
:schema (:schema opts)}))
|
||||
(editor-handler/save-block! repo
|
||||
(sdk-utils/uuid-or-throw-error block-uuid) content
|
||||
(dissoc opts :properties))))))
|
||||
|
||||
(defn get-property
|
||||
[k]
|
||||
(this-as this
|
||||
(p/let [prop (-get-property this k)]
|
||||
(some-> prop
|
||||
(assoc :type (:logseq.property/type prop))
|
||||
(sdk-utils/normalize-keyword-for-json)
|
||||
(bean/->js)))))
|
||||
|
||||
(defn upsert-property
|
||||
"schema:
|
||||
{:type :default | :number | :date | :datetime | :checkbox | :url | :node | :json | :string
|
||||
:cardinality :many | :one
|
||||
:hide? true
|
||||
:view-context :page
|
||||
:public? false}
|
||||
"
|
||||
[k ^js schema ^js opts]
|
||||
(this-as
|
||||
this
|
||||
(when-not (string/blank? k)
|
||||
(p/let [opts (or (some-> opts bean/->clj) {})
|
||||
property-ident (api-block/get-db-ident-from-property-name k this)
|
||||
_ (api-block/ensure-property-upsert-control this property-ident k)
|
||||
schema (or (some-> schema (bean/->clj)
|
||||
(update-keys #(if (contains? #{:hide :public} %)
|
||||
(keyword (str (name %) "?")) %))) {})
|
||||
schema (cond-> schema
|
||||
(string? (:cardinality schema))
|
||||
(-> (assoc :db/cardinality (keyword (:cardinality schema)))
|
||||
(dissoc :cardinality))
|
||||
|
||||
(string? (:type schema))
|
||||
(-> (assoc :logseq.property/type (keyword (:type schema)))
|
||||
(dissoc :type)))
|
||||
p (db-property-handler/upsert-property! property-ident schema
|
||||
(assoc opts :property-name name))
|
||||
p (db/entity (:db/id p))]
|
||||
(sdk-utils/result->js p)))))
|
||||
|
||||
(defn remove-property
|
||||
[k]
|
||||
(this-as
|
||||
this
|
||||
(p/let [property (-get-property this k)]
|
||||
(when-let [uuid (and (api-block/plugin-property-key? (:db/ident property))
|
||||
(:block/uuid property))]
|
||||
(page-common-handler/<delete! uuid nil nil)))))
|
||||
|
||||
(defn upsert-block-property
|
||||
[this block key' value schema]
|
||||
(let [opts {:plugin this
|
||||
:schema (when schema
|
||||
{key schema})}]
|
||||
(api-block/db-based-save-block-properties! block {key' value} opts)))
|
||||
|
||||
(defn get-all-tags
|
||||
[]
|
||||
(-> (db-model/get-all-classes (state/get-current-repo)
|
||||
{:except-root-class? true})
|
||||
sdk-utils/result->js))
|
||||
|
||||
(defn get-all-properties
|
||||
[]
|
||||
(-> (ldb/get-all-properties (db/get-db))
|
||||
sdk-utils/result->js))
|
||||
|
||||
(defn get-tag-objects
|
||||
[class-uuid-or-ident]
|
||||
(let [eid (if (util/uuid-string? class-uuid-or-ident)
|
||||
(when-let [id (sdk-utils/uuid-or-throw-error class-uuid-or-ident)]
|
||||
[:block/uuid id])
|
||||
(keyword (api-block/sanitize-user-property-name class-uuid-or-ident)))
|
||||
class (db/entity eid)]
|
||||
(if-not class
|
||||
(throw (ex-info (str "Tag not exists with id: " eid) {}))
|
||||
(p/let [result (state/<invoke-db-worker :thread-api/get-class-objects
|
||||
(state/get-current-repo)
|
||||
(:db/id class))]
|
||||
(sdk-utils/result->js result)))))
|
||||
528
src/main/logseq/api/editor.cljs
Normal file
528
src/main/logseq/api/editor.cljs
Normal file
@@ -0,0 +1,528 @@
|
||||
(ns logseq.api.editor
|
||||
"Editor related APIs"
|
||||
(:require [cljs-bean.core :as bean]
|
||||
[cljs.reader]
|
||||
[clojure.string :as string]
|
||||
[datascript.core :as d]
|
||||
[frontend.commands :as commands]
|
||||
[frontend.config :as config]
|
||||
[frontend.date :as date]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.async :as db-async]
|
||||
[frontend.db.conn :as conn]
|
||||
[frontend.db.model :as db-model]
|
||||
[frontend.db.utils :as db-utils]
|
||||
[frontend.handler.code :as code-handler]
|
||||
[frontend.handler.dnd :as editor-dnd-handler]
|
||||
[frontend.handler.editor :as editor-handler]
|
||||
[frontend.handler.export :as export-handler]
|
||||
[frontend.handler.page :as page-handler]
|
||||
[frontend.handler.property :as property-handler]
|
||||
[frontend.handler.shell :as shell]
|
||||
[frontend.modules.layout.core]
|
||||
[frontend.modules.outliner.tree :as outliner-tree]
|
||||
[frontend.state :as state]
|
||||
[frontend.util :as util]
|
||||
[frontend.util.cursor :as cursor]
|
||||
[goog.date :as gdate]
|
||||
[goog.dom :as gdom]
|
||||
[logseq.api.block :as api-block]
|
||||
[logseq.api.db-based :as db-based-api]
|
||||
[logseq.common.util :as common-util]
|
||||
[logseq.common.util.date-time :as date-time-util]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.outliner.core :as outliner-core]
|
||||
[logseq.sdk.core]
|
||||
[logseq.sdk.experiments]
|
||||
[logseq.sdk.git]
|
||||
[logseq.sdk.utils :as sdk-utils]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defn- <get-block
|
||||
[id-or-name & opts]
|
||||
(when id-or-name
|
||||
(db-async/<get-block (state/get-current-repo) id-or-name opts)))
|
||||
|
||||
(def save_focused_code_editor_content
|
||||
(fn []
|
||||
(code-handler/save-code-editor!)))
|
||||
|
||||
(def check_editing
|
||||
(fn []
|
||||
(if (state/get-edit-input-id)
|
||||
(str (:block/uuid (state/get-edit-block))) false)))
|
||||
|
||||
(def exit_editing_mode
|
||||
(fn [select?]
|
||||
(editor-handler/escape-editing {:select? select?})
|
||||
nil))
|
||||
|
||||
(def insert_at_editing_cursor
|
||||
(fn [content]
|
||||
(when-let [input-id (state/get-edit-input-id)]
|
||||
(commands/simple-insert! input-id content {})
|
||||
(when-let [input (gdom/getElement input-id)]
|
||||
(.focus input)))))
|
||||
|
||||
(def restore_editing_cursor
|
||||
(fn []
|
||||
(when-let [input-id (state/get-edit-input-id)]
|
||||
(when-let [input (gdom/getElement input-id)]
|
||||
(when (util/el-visible-in-viewport? input)
|
||||
(.focus input))))))
|
||||
|
||||
(def get_editing_cursor_position
|
||||
(fn []
|
||||
(when-let [input-id (state/get-edit-input-id)]
|
||||
(bean/->js (sdk-utils/normalize-keyword-for-json (cursor/get-caret-pos (gdom/getElement input-id)))))))
|
||||
|
||||
(def get_editing_block_content
|
||||
(fn []
|
||||
(state/get-edit-content)))
|
||||
|
||||
(def get_selected_blocks
|
||||
(fn []
|
||||
(when-let [blocks (state/selection?)]
|
||||
(let [blocks (->> blocks
|
||||
(map (fn [^js el] (some->
|
||||
(.getAttribute el "blockid")
|
||||
(db-model/get-block-by-uuid)))))]
|
||||
(sdk-utils/result->js blocks)))))
|
||||
|
||||
(def clear_selected_blocks
|
||||
(fn []
|
||||
(state/clear-selection!)))
|
||||
|
||||
(def get_current_page
|
||||
(fn []
|
||||
(when-let [page (state/get-current-page)]
|
||||
(p/let [page (<get-block page {:children? false})]
|
||||
(when page
|
||||
(sdk-utils/result->js page))))))
|
||||
|
||||
(defn get_page
|
||||
[id-or-page-name]
|
||||
(p/let [page (<get-block id-or-page-name {:children? false})]
|
||||
(when page
|
||||
(sdk-utils/result->js page))))
|
||||
|
||||
;; FIXME: this doesn't work because the ui doesn't have all pages
|
||||
(defn get_all_pages
|
||||
[]
|
||||
(let [db (conn/get-db (state/get-current-repo))]
|
||||
(some->
|
||||
(->>
|
||||
(d/datoms db :avet :block/name)
|
||||
(map #(db-utils/pull (:e %)))
|
||||
(remove ldb/hidden?)
|
||||
(remove (fn [page]
|
||||
(common-util/uuid-string? (:block/name page)))))
|
||||
(sdk-utils/normalize-keyword-for-json)
|
||||
(bean/->js))))
|
||||
|
||||
(defn create_page
|
||||
[name ^js properties ^js opts]
|
||||
(this-as
|
||||
this
|
||||
(let [properties (bean/->clj properties)
|
||||
db-based? (config/db-based-graph?)
|
||||
{:keys [redirect format journal schema]} (bean/->clj opts)]
|
||||
(p/let [page (<get-block name {:children? false})
|
||||
new-page (when-not page
|
||||
(page-handler/<create!
|
||||
name
|
||||
(cond->
|
||||
{:redirect? (if (boolean? redirect) redirect true)
|
||||
:journal? journal
|
||||
:format format}
|
||||
(not db-based?)
|
||||
(assoc :properties properties))))
|
||||
_ (when (and db-based? (seq properties))
|
||||
(api-block/db-based-save-block-properties! new-page properties {:plugin this
|
||||
:schema schema}))]
|
||||
(some-> (or page new-page)
|
||||
sdk-utils/result->js)))))
|
||||
|
||||
(defn create_journal_page
|
||||
[^js date]
|
||||
(let [date (js/Date. date)]
|
||||
(when-let [datestr (and (not (js/isNaN (.getTime date)))
|
||||
(-> (gdate/Date. date)
|
||||
(date-time-util/format "yyyy-MM-dd")))]
|
||||
(create_page datestr nil #js {:journal true :redirect false}))))
|
||||
|
||||
(defn delete_page
|
||||
[name]
|
||||
(page-handler/<delete! name nil))
|
||||
|
||||
(def rename_page
|
||||
page-handler/rename!)
|
||||
|
||||
(defn open_in_right_sidebar
|
||||
[block-id-or-uuid]
|
||||
(editor-handler/open-block-in-sidebar!
|
||||
(if (number? block-id-or-uuid)
|
||||
block-id-or-uuid
|
||||
(sdk-utils/uuid-or-throw-error block-id-or-uuid))))
|
||||
|
||||
(defn new_block_uuid []
|
||||
(str (db/new-block-id)))
|
||||
|
||||
(def select_block
|
||||
(fn [block-uuid]
|
||||
(when-let [block (db-model/get-block-by-uuid (sdk-utils/uuid-or-throw-error block-uuid))]
|
||||
(editor-handler/select-block! (:block/uuid block)) nil)))
|
||||
|
||||
(def edit_block
|
||||
(fn [block-uuid ^js opts]
|
||||
(when-let [block-uuid (and block-uuid (sdk-utils/uuid-or-throw-error block-uuid))]
|
||||
(when-let [block (db-model/query-block-by-uuid block-uuid)]
|
||||
(let [{:keys [pos] :or {pos :max}} (bean/->clj opts)]
|
||||
(editor-handler/edit-block! block pos {:container-id :unknown-container}))))))
|
||||
|
||||
(defn- <ensure-page-loaded
|
||||
[block-uuid-or-page-name]
|
||||
(p/let [repo (state/get-current-repo)
|
||||
block (db-async/<get-block repo (str block-uuid-or-page-name)
|
||||
{:children? true
|
||||
:include-collapsed-children? true})
|
||||
_ (when-let [page-id (:db/id (:block/page block))]
|
||||
(when-let [page-uuid (:block/uuid (db/entity page-id))]
|
||||
(db-async/<get-block repo page-uuid)))]
|
||||
block))
|
||||
|
||||
(defn insert_block
|
||||
[block-uuid-or-page-name content ^js opts]
|
||||
(this-as this
|
||||
(when (string/blank? block-uuid-or-page-name)
|
||||
(throw (js/Error. "Page title or block UUID shouldn't be empty.")))
|
||||
|
||||
(p/let [block? (util/uuid-string? (str block-uuid-or-page-name))
|
||||
block (<get-block (str block-uuid-or-page-name))]
|
||||
(if (and block? (not block))
|
||||
(throw (js/Error. "Block not exists"))
|
||||
(p/let [{:keys [before start end sibling focus customUUID properties autoOrderedList schema]} (bean/->clj opts)
|
||||
[page-name block-uuid] (if (util/uuid-string? block-uuid-or-page-name)
|
||||
[nil (uuid block-uuid-or-page-name)]
|
||||
[block-uuid-or-page-name nil])
|
||||
page-name (when page-name (util/page-name-sanity-lc page-name))
|
||||
_ (when (and page-name
|
||||
(nil? (ldb/get-page (db/get-db) page-name)))
|
||||
(page-handler/<create! block-uuid-or-page-name {}))
|
||||
custom-uuid (or customUUID (:id properties))
|
||||
custom-uuid (when custom-uuid (sdk-utils/uuid-or-throw-error custom-uuid))
|
||||
edit-block? (if (nil? focus) true focus)
|
||||
_ (when (and custom-uuid (db-model/query-block-by-uuid custom-uuid))
|
||||
(throw (js/Error.
|
||||
(util/format "Custom block UUID already exists (%s)." custom-uuid))))
|
||||
block-uuid' (if (and (not sibling) before block-uuid)
|
||||
(let [block (db/entity [:block/uuid block-uuid])
|
||||
first-child (ldb/get-first-child (db/get-db) (:db/id block))]
|
||||
(if first-child
|
||||
(:block/uuid first-child)
|
||||
block-uuid))
|
||||
block-uuid)
|
||||
insert-at-first-child? (not= block-uuid' block-uuid)
|
||||
[sibling? before?] (if insert-at-first-child?
|
||||
[true true]
|
||||
[sibling before])
|
||||
db-based? (config/db-based-graph?)
|
||||
before? (if (and (false? sibling?) before? (not insert-at-first-child?))
|
||||
false
|
||||
before?)
|
||||
opts' {:block-uuid block-uuid'
|
||||
:sibling? sibling?
|
||||
:before? before?
|
||||
:start? start
|
||||
:end? end
|
||||
:edit-block? edit-block?
|
||||
:page page-name
|
||||
:custom-uuid custom-uuid
|
||||
:ordered-list? (if (boolean? autoOrderedList) autoOrderedList false)
|
||||
:properties (when (not db-based?)
|
||||
(merge properties
|
||||
(when custom-uuid {:id custom-uuid})))}]
|
||||
(if db-based?
|
||||
(db-based-api/insert-block this content properties schema opts')
|
||||
(p/let [new-block (editor-handler/api-insert-new-block! content opts')]
|
||||
(bean/->js (sdk-utils/normalize-keyword-for-json new-block)))))))))
|
||||
|
||||
(def insert_batch_block
|
||||
(fn [block-uuid ^js batch-blocks-js ^js opts-js]
|
||||
(this-as
|
||||
this
|
||||
(p/let [block (<ensure-page-loaded block-uuid)]
|
||||
(when block
|
||||
(when-let [blocks (bean/->clj batch-blocks-js)]
|
||||
(let [db-based? (config/db-based-graph?)
|
||||
blocks' (if-not (vector? blocks) (vector blocks) blocks)
|
||||
opts (bean/->clj opts-js)
|
||||
{:keys [sibling before _schema keepUUID]} opts]
|
||||
(if db-based?
|
||||
(db-based-api/insert-batch-blocks this block blocks' opts)
|
||||
(let [keep-uuid? (or keepUUID false)
|
||||
_ (when keep-uuid? (doseq
|
||||
[block (outliner-core/tree-vec-flatten blocks' :children)]
|
||||
(let [uuid (:id (:properties block))]
|
||||
(when (and uuid (db-model/query-block-by-uuid (sdk-utils/uuid-or-throw-error uuid)))
|
||||
(throw (js/Error.
|
||||
(util/format "Custom block UUID already exists (%s)." uuid)))))))
|
||||
block (if before
|
||||
(db/pull (:db/id (ldb/get-left-sibling (db/entity (:db/id block))))) block)
|
||||
sibling? (if (ldb/page? block) false sibling)]
|
||||
(p/let [result (editor-handler/insert-block-tree-after-target
|
||||
(:db/id block) sibling? blocks' (get block :block/format :markdown) keep-uuid?)
|
||||
blocks (:blocks result)]
|
||||
(let [blocks' (map (fn [b] (db/entity [:block/uuid (:block/uuid b)])) blocks)]
|
||||
(-> blocks'
|
||||
sdk-utils/normalize-keyword-for-json
|
||||
bean/->js))))))))))))
|
||||
|
||||
(def remove_block
|
||||
(fn [block-uuid ^js _opts]
|
||||
(p/let [repo (state/get-current-repo)
|
||||
_ (<get-block block-uuid {:children? false})]
|
||||
(editor-handler/delete-block-aux!
|
||||
{:block/uuid (sdk-utils/uuid-or-throw-error block-uuid) :repo repo}))))
|
||||
|
||||
(def update_block
|
||||
(fn [block-uuid content ^js opts]
|
||||
(this-as
|
||||
this
|
||||
(p/let [repo (state/get-current-repo)
|
||||
db-based? (config/db-based-graph?)
|
||||
block (<get-block block-uuid {:children? false})
|
||||
opts' (bean/->clj opts)]
|
||||
(when block
|
||||
(if db-based?
|
||||
(db-based-api/update-block this block content opts')
|
||||
(editor-handler/save-block! repo
|
||||
(sdk-utils/uuid-or-throw-error block-uuid) content
|
||||
(if db-based? (dissoc opts' :properties) opts'))))))))
|
||||
|
||||
(def move_block
|
||||
(fn [src-block-uuid target-block-uuid ^js opts]
|
||||
(p/let [_ (<get-block src-block-uuid {:children? false})
|
||||
_ (<get-block target-block-uuid {:children? false})]
|
||||
(let [{:keys [before children]} (bean/->clj opts)
|
||||
move-to (cond
|
||||
(boolean before)
|
||||
:top
|
||||
|
||||
(boolean children)
|
||||
:nested
|
||||
|
||||
:else
|
||||
nil)
|
||||
src-block (db-model/query-block-by-uuid (sdk-utils/uuid-or-throw-error src-block-uuid))
|
||||
target-block (db-model/query-block-by-uuid (sdk-utils/uuid-or-throw-error target-block-uuid))]
|
||||
(editor-dnd-handler/move-blocks nil [src-block] target-block nil move-to)))))
|
||||
|
||||
(def get_block
|
||||
(fn [id ^js opts]
|
||||
(p/let [_ (db-async/<get-block (state/get-current-repo) id {:children? true
|
||||
:include-collapsed-children? true})]
|
||||
(api-block/get_block id (or opts #js {:includePage true})))))
|
||||
|
||||
(def get_current_block
|
||||
(fn [^js opts]
|
||||
(let [block (state/get-edit-block)
|
||||
block (or block
|
||||
(some-> (or (first (state/get-selection-blocks))
|
||||
(state/get-editor-block-container))
|
||||
(.getAttribute "blockid")
|
||||
(db-model/get-block-by-uuid)))]
|
||||
(get_block (:block/uuid block) opts))))
|
||||
|
||||
(def get_previous_sibling_block
|
||||
(fn [block-uuid ^js opts]
|
||||
(p/let [id (sdk-utils/uuid-or-throw-error block-uuid)
|
||||
block (<get-block id)
|
||||
;; Load all children blocks
|
||||
_ (api-block/<sync-children-blocks! block)]
|
||||
(when block
|
||||
(when-let [sibling (ldb/get-left-sibling (db/entity (:db/id block)))]
|
||||
(get_block (:block/uuid sibling) opts))))))
|
||||
|
||||
(def get_next_sibling_block
|
||||
(fn [block-uuid ^js opts]
|
||||
(p/let [id (sdk-utils/uuid-or-throw-error block-uuid)
|
||||
block (<get-block id)
|
||||
;; Load all children blocks
|
||||
_ (api-block/<sync-children-blocks! block)]
|
||||
(when block
|
||||
(p/let [sibling (ldb/get-right-sibling (db/entity (:db/id block)))]
|
||||
(get_block (:block/uuid sibling) opts))))))
|
||||
|
||||
(def set_block_collapsed
|
||||
(fn [block-uuid ^js opts]
|
||||
(p/let [block-uuid (sdk-utils/uuid-or-throw-error block-uuid)
|
||||
block (<get-block block-uuid {:children? false})]
|
||||
(when block
|
||||
(let [opts (bean/->clj opts)
|
||||
opts (if (or (string? opts) (boolean? opts)) {:flag opts} opts)
|
||||
{:keys [flag]} opts
|
||||
flag (if (= "toggle" flag)
|
||||
(not (util/collapsed? block))
|
||||
(boolean flag))]
|
||||
(if flag
|
||||
(editor-handler/collapse-block! block-uuid)
|
||||
(editor-handler/expand-block! block-uuid))
|
||||
nil)))))
|
||||
|
||||
(def get_current_page_blocks_tree
|
||||
(fn []
|
||||
(when-let [page (state/get-current-page)]
|
||||
(let [page-id (:db/id (ldb/get-page (db/get-db) page))
|
||||
blocks (db-model/get-page-blocks-no-cache page-id)
|
||||
blocks (outliner-tree/blocks->vec-tree blocks page-id)
|
||||
;; clean key
|
||||
blocks (sdk-utils/normalize-keyword-for-json blocks)]
|
||||
(bean/->js blocks)))))
|
||||
|
||||
(def get_page_blocks_tree
|
||||
(fn [id-or-page-name]
|
||||
(p/let [_ (<ensure-page-loaded id-or-page-name)]
|
||||
(when-let [page-id (:db/id (db-model/get-page id-or-page-name))]
|
||||
(let [blocks (db-model/get-page-blocks-no-cache page-id)
|
||||
blocks (outliner-tree/blocks->vec-tree blocks page-id)
|
||||
blocks (sdk-utils/normalize-keyword-for-json blocks)]
|
||||
(bean/->js blocks))))))
|
||||
|
||||
(defn get_page_linked_references
|
||||
[page-name-or-uuid]
|
||||
(p/let [repo (state/get-current-repo)
|
||||
block (<get-block page-name-or-uuid {:children? false})]
|
||||
(when-let [id (:db/id block)]
|
||||
(p/let [result (db-async/<get-block-refs repo id)
|
||||
ref-blocks (db-utils/group-by-page result)]
|
||||
(bean/->js (sdk-utils/normalize-keyword-for-json ref-blocks))))))
|
||||
|
||||
(defn prepend_block_in_page
|
||||
[uuid-or-page-name content ^js opts]
|
||||
(p/let [uuid-or-page-name (or
|
||||
uuid-or-page-name
|
||||
(state/get-current-page)
|
||||
(date/today))
|
||||
block (<get-block uuid-or-page-name)
|
||||
new-page (when (and (not block) (not (util/uuid-string? uuid-or-page-name))) ; page not exists
|
||||
(page-handler/<create! uuid-or-page-name
|
||||
{:redirect? false
|
||||
:format (state/get-preferred-format)}))]
|
||||
(let [block (or block new-page)
|
||||
opts (bean/->clj opts)
|
||||
opts' (assoc opts :before false :sibling false :start true)]
|
||||
(insert_block (str (:block/uuid block)) content (bean/->js opts')))))
|
||||
|
||||
(defn append_block_in_page
|
||||
[uuid-or-page-name content ^js opts]
|
||||
(let [uuid-or-page-name (or
|
||||
uuid-or-page-name
|
||||
(state/get-current-page)
|
||||
(date/today))]
|
||||
(p/let [_ (<ensure-page-loaded uuid-or-page-name)
|
||||
page? (not (util/uuid-string? uuid-or-page-name))
|
||||
page (db-model/get-page uuid-or-page-name)
|
||||
page-not-exist? (and page? (nil? page))
|
||||
new-page (when page-not-exist?
|
||||
(page-handler/<create! uuid-or-page-name
|
||||
{:redirect? false
|
||||
:format (state/get-preferred-format)}))
|
||||
block (or page new-page)]
|
||||
(let [children (:block/_parent block)
|
||||
[target sibling?] (if (seq children)
|
||||
[(last (ldb/sort-by-order children)) true]
|
||||
[block false])
|
||||
target-id (str (:block/uuid target))
|
||||
opts (-> (bean/->clj opts)
|
||||
(assoc :sibling sibling?))]
|
||||
(insert_block target-id content opts)))))
|
||||
|
||||
(defn download_graph_db
|
||||
[]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(export-handler/export-repo-as-sqlite-db! repo)))
|
||||
|
||||
(defn download_graph_pages
|
||||
[]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(export-handler/export-repo-as-zip! repo)))
|
||||
|
||||
(defn exec_git_command
|
||||
[^js args]
|
||||
(when-let [args (and args (seq (bean/->clj args)))]
|
||||
(shell/run-git-command! args)))
|
||||
|
||||
;; block properties
|
||||
(defn upsert_block_property
|
||||
[block-uuid key ^js value ^js options]
|
||||
(this-as
|
||||
this
|
||||
(p/let [key' (api-block/sanitize-user-property-name key)
|
||||
opts (bean/->clj options)
|
||||
block-uuid (sdk-utils/uuid-or-throw-error block-uuid)
|
||||
repo (state/get-current-repo)
|
||||
block (<get-block block-uuid {:children? false})
|
||||
db-based? (config/db-based-graph?)
|
||||
value (bean/->clj value)]
|
||||
(when block
|
||||
(if db-based?
|
||||
(db-based-api/upsert-block-property this block key' value (:schema opts))
|
||||
(property-handler/set-block-property! repo block-uuid key' value))))))
|
||||
|
||||
(defn remove_block_property
|
||||
[block-uuid key]
|
||||
(this-as this
|
||||
(p/let [key (api-block/sanitize-user-property-name key)
|
||||
block-uuid (sdk-utils/uuid-or-throw-error block-uuid)
|
||||
_block (<get-block block-uuid {:children? false})
|
||||
db-based? (config/db-based-graph?)
|
||||
key-ns? (namespace (keyword key))
|
||||
key (if (and db-based? (not key-ns?))
|
||||
(api-block/get-db-ident-from-property-name
|
||||
key (api-block/resolve-property-prefix-for-db this))
|
||||
key)]
|
||||
(property-handler/remove-block-property!
|
||||
(state/get-current-repo)
|
||||
block-uuid key))))
|
||||
|
||||
(defn get_block_property
|
||||
[block-uuid key]
|
||||
(this-as this
|
||||
(p/let [block-uuid (sdk-utils/uuid-or-throw-error block-uuid)
|
||||
_block (<get-block block-uuid {:children? false})]
|
||||
(when-let [properties (some-> block-uuid (db-model/get-block-by-uuid) (:block/properties))]
|
||||
(when (seq properties)
|
||||
(let [property-name (api-block/sanitize-user-property-name key)
|
||||
ident (api-block/get-db-ident-from-property-name
|
||||
property-name (api-block/resolve-property-prefix-for-db this))
|
||||
property-value (or (get properties property-name)
|
||||
(get properties (keyword property-name))
|
||||
(get properties ident))
|
||||
property-value (if-let [property-id (:db/id property-value)]
|
||||
(db/pull property-id) property-value)
|
||||
property-value (cond-> property-value
|
||||
(map? property-value)
|
||||
(assoc
|
||||
:value (or (:logseq.property/value property-value)
|
||||
(:block/title property-value))
|
||||
:ident ident))
|
||||
parsed-value (api-block/parse-property-json-value-if-need ident property-value)]
|
||||
(or parsed-value
|
||||
(bean/->js (sdk-utils/normalize-keyword-for-json property-value)))))))))
|
||||
|
||||
(def get_block_properties
|
||||
(fn [block-uuid]
|
||||
(p/let [block-uuid (sdk-utils/uuid-or-throw-error block-uuid)
|
||||
block (<get-block block-uuid {:children? false})]
|
||||
(when block
|
||||
(let [properties (if (config/db-based-graph?)
|
||||
(api-block/into-readable-db-properties (:block/properties block))
|
||||
(:block/properties block))]
|
||||
(sdk-utils/result->js properties))))))
|
||||
|
||||
(defn get_page_properties
|
||||
[id-or-page-name]
|
||||
(p/let [page (<get-block id-or-page-name {:children? false})]
|
||||
(when-let [id (:block/uuid page)]
|
||||
(get_block_properties id))))
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns logseq.api.file
|
||||
(ns logseq.api.file-based
|
||||
"File version related fns"
|
||||
(:require [cljs-bean.core :as bean]
|
||||
[cljs.reader]
|
||||
338
src/main/logseq/api/plugin.cljs
Normal file
338
src/main/logseq/api/plugin.cljs
Normal file
@@ -0,0 +1,338 @@
|
||||
(ns logseq.api.plugin
|
||||
"Plugin related apis"
|
||||
(:require [cljs-bean.core :as bean]
|
||||
[cljs.reader]
|
||||
[clojure.string :as string]
|
||||
[electron.ipc :as ipc]
|
||||
[frontend.config :as config]
|
||||
[frontend.fs :as fs]
|
||||
[frontend.handler.command-palette :as palette-handler]
|
||||
[frontend.handler.common.plugin :as plugin-common-handler]
|
||||
[frontend.handler.plugin :as plugin-handler]
|
||||
[frontend.idb :as idb]
|
||||
[frontend.modules.layout.core]
|
||||
[frontend.modules.shortcut.config :as shortcut-config]
|
||||
[frontend.modules.shortcut.core :as st]
|
||||
[frontend.state :as state]
|
||||
[frontend.util :as util]
|
||||
[goog.object :as gobj]
|
||||
[lambdaisland.glogi :as log]
|
||||
[logseq.sdk.core]
|
||||
[logseq.sdk.experiments]
|
||||
[logseq.sdk.git]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defn get-caller-plugin-id
|
||||
[] (gobj/get js/window "$$callerPluginID"))
|
||||
|
||||
;; helpers
|
||||
(defn install-plugin-hook
|
||||
[pid hook ^js opts]
|
||||
(state/install-plugin-hook pid hook (bean/->clj opts)))
|
||||
|
||||
(defn uninstall-plugin-hook
|
||||
[pid hook-or-all]
|
||||
(state/uninstall-plugin-hook pid hook-or-all))
|
||||
|
||||
(defn should-exec-plugin-hook
|
||||
[pid hook]
|
||||
(plugin-handler/plugin-hook-installed? pid hook))
|
||||
|
||||
(def load_plugin_config
|
||||
(fn [path]
|
||||
(if (util/electron?)
|
||||
(fs/read-file nil (util/node-path.join path "package.json"))
|
||||
(js/console.log "TODO: load plugin package.json from web plugin."))))
|
||||
|
||||
(def load_plugin_readme
|
||||
(fn [path]
|
||||
(fs/read-file nil (util/node-path.join path "readme.md"))))
|
||||
|
||||
(def save_plugin_package_json
|
||||
(fn [path ^js data]
|
||||
(let [repo ""
|
||||
path (util/node-path.join path "package.json")]
|
||||
(fs/write-plain-text-file! repo nil path (js/JSON.stringify data nil 2) {:skip-compare? true}))))
|
||||
|
||||
(defn- write_rootdir_file
|
||||
[file content sub-root root-dir]
|
||||
(p/let [repo ""
|
||||
path (util/node-path.join root-dir sub-root)
|
||||
exist? (fs/file-exists? path "")
|
||||
_ (when-not exist? (fs/mkdir-recur! path))
|
||||
user-path (util/node-path.join path file)
|
||||
sub-dir? (string/starts-with? user-path path)
|
||||
_ (when-not sub-dir?
|
||||
(log/info :debug user-path)
|
||||
(throw (js/Error. "write file denied")))
|
||||
user-path-root (util/node-path.dirname user-path)
|
||||
exist? (fs/file-exists? user-path-root "")
|
||||
_ (when-not exist? (fs/mkdir-recur! user-path-root))
|
||||
_ (fs/write-plain-text-file! repo nil user-path content {:skip-compare? true})]
|
||||
user-path))
|
||||
|
||||
(defn write_dotdir_file
|
||||
[file content sub-root]
|
||||
(some-> (plugin-handler/get-ls-dotdir-root)
|
||||
(p/then #(write_rootdir_file file content sub-root %))))
|
||||
|
||||
(defn write_assetsdir_file
|
||||
[file content sub-root]
|
||||
(if-let [assets-dir (config/get-current-repo-assets-root)]
|
||||
(write_rootdir_file file content sub-root assets-dir)
|
||||
false))
|
||||
|
||||
(defn- read_rootdir_file
|
||||
[file sub-root root-dir]
|
||||
(p/let [path (util/node-path.join root-dir sub-root)
|
||||
user-path (util/node-path.join path file)
|
||||
sub-dir? (string/starts-with? user-path path)
|
||||
_ (when-not sub-dir? (log/info :debug user-path) (throw (js/Error. "read file denied")))
|
||||
exist? (fs/file-exists? "" user-path)
|
||||
_ (when-not exist? (log/info :debug user-path) (throw (js/Error. "file not existed")))
|
||||
content (fs/read-file "" user-path)]
|
||||
content))
|
||||
|
||||
(defn- read_dotdir_file
|
||||
[file sub-root]
|
||||
(some-> (plugin-handler/get-ls-dotdir-root)
|
||||
(p/then #(read_rootdir_file file sub-root %))))
|
||||
|
||||
(defn- read_assetsdir_file
|
||||
[file sub-root]
|
||||
(when-let [root-dir (config/get-current-repo-assets-root)]
|
||||
(read_rootdir_file file sub-root root-dir)))
|
||||
|
||||
(defn- unlink_rootdir_file!
|
||||
[file sub-root root-dir]
|
||||
(p/let [repo ""
|
||||
path (util/node-path.join root-dir sub-root)
|
||||
user-path (util/node-path.join path file)
|
||||
sub-dir? (string/starts-with? user-path path)
|
||||
_ (when-not sub-dir? (log/info :debug user-path) (throw (js/Error. "access file denied")))
|
||||
exist? (fs/file-exists? "" user-path)
|
||||
_ (when-not exist? (log/info :debug user-path) (throw (js/Error. "file not existed")))
|
||||
_ (fs/unlink! repo user-path {})]))
|
||||
|
||||
(defn- unlink_dotdir_file!
|
||||
[file sub-root]
|
||||
(some-> (plugin-handler/get-ls-dotdir-root)
|
||||
(p/then #(unlink_rootdir_file! file sub-root %))))
|
||||
|
||||
(defn- unlink_assetsdir_file!
|
||||
[file sub-root]
|
||||
(when-let [root-dir (config/get-current-repo-assets-root)]
|
||||
(unlink_rootdir_file! file sub-root root-dir)))
|
||||
|
||||
(def write_user_tmp_file
|
||||
(fn [file content]
|
||||
(write_dotdir_file file content "tmp")))
|
||||
|
||||
(def write_plugin_storage_file
|
||||
(fn [plugin-id file content assets?]
|
||||
(let [plugin-id (util/node-path.basename plugin-id)
|
||||
sub-root (util/node-path.join "storages" plugin-id)]
|
||||
(if (true? assets?)
|
||||
(write_assetsdir_file file content sub-root)
|
||||
(write_dotdir_file file content sub-root)))))
|
||||
|
||||
(def read_plugin_storage_file
|
||||
(fn [plugin-id file assets?]
|
||||
(let [plugin-id (util/node-path.basename plugin-id)
|
||||
sub-root (util/node-path.join "storages" plugin-id)]
|
||||
(if (true? assets?)
|
||||
(read_assetsdir_file file sub-root)
|
||||
(read_dotdir_file file sub-root)))))
|
||||
|
||||
(def unlink_plugin_storage_file
|
||||
(fn [plugin-id file assets?]
|
||||
(let [plugin-id (util/node-path.basename plugin-id)
|
||||
sub-root (util/node-path.join "storages" plugin-id)]
|
||||
(if (true? assets?)
|
||||
(unlink_assetsdir_file! file sub-root)
|
||||
(unlink_dotdir_file! file sub-root)))))
|
||||
|
||||
(def exist_plugin_storage_file
|
||||
(fn [plugin-id file assets?]
|
||||
(p/let [root (if (true? assets?)
|
||||
(config/get-current-repo-assets-root)
|
||||
(plugin-handler/get-ls-dotdir-root))
|
||||
plugin-id (util/node-path.basename plugin-id)
|
||||
exist? (fs/file-exists?
|
||||
(util/node-path.join root "storages" plugin-id)
|
||||
file)]
|
||||
exist?)))
|
||||
|
||||
(def clear_plugin_storage_files
|
||||
(fn [plugin-id assets?]
|
||||
(p/let [root (if (true? assets?)
|
||||
(config/get-current-repo-assets-root)
|
||||
(plugin-handler/get-ls-dotdir-root))
|
||||
plugin-id (util/node-path.basename plugin-id)]
|
||||
(fs/rmdir! (util/node-path.join root "storages" plugin-id)))))
|
||||
|
||||
(def list_plugin_storage_files
|
||||
(fn [plugin-id assets?]
|
||||
(p/let [root (if (true? assets?)
|
||||
(config/get-current-repo-assets-root)
|
||||
(plugin-handler/get-ls-dotdir-root))
|
||||
plugin-id (util/node-path.basename plugin-id)
|
||||
files-path (util/node-path.join root "storages" plugin-id)
|
||||
^js files (ipc/ipc :listdir files-path)]
|
||||
(when (js-iterable? files)
|
||||
(bean/->js
|
||||
(map #(some-> (string/replace-first % files-path "")
|
||||
(string/replace #"^/+" "")) files))))))
|
||||
|
||||
(def load_user_preferences
|
||||
(fn []
|
||||
(let [repo ""
|
||||
path (plugin-handler/get-ls-dotdir-root)
|
||||
path (util/node-path.join path "preferences.json")]
|
||||
(if (util/electron?)
|
||||
(p/let [_ (fs/create-if-not-exists repo nil path)
|
||||
json (fs/read-file nil path)
|
||||
json (if (string/blank? json) "{}" json)]
|
||||
(js/JSON.parse json))
|
||||
(p/let [json (idb/get-item path)]
|
||||
(or json #js {}))))))
|
||||
|
||||
(def save_user_preferences
|
||||
(fn [^js data]
|
||||
(when data
|
||||
(let [repo ""
|
||||
path (plugin-handler/get-ls-dotdir-root)
|
||||
path (util/node-path.join path "preferences.json")]
|
||||
(if (util/electron?)
|
||||
(fs/write-plain-text-file! repo nil path (js/JSON.stringify data nil 2) {:skip-compare? true})
|
||||
(idb/set-item! path data))))))
|
||||
|
||||
(def load_plugin_user_settings
|
||||
;; results [path data]
|
||||
(plugin-handler/make-fn-to-load-dotdir-json "settings" #js {}))
|
||||
|
||||
(def save_plugin_user_settings
|
||||
(fn [key ^js data]
|
||||
((plugin-handler/make-fn-to-save-dotdir-json "settings")
|
||||
key data)))
|
||||
|
||||
(defn load_installed_web_plugins
|
||||
[]
|
||||
(let [getter (plugin-handler/make-fn-to-load-dotdir-json "installed-plugins-for-web" #js {})]
|
||||
(some-> (getter :all) (p/then second))))
|
||||
|
||||
(defn save_installed_web_plugin
|
||||
([^js plugin] (save_installed_web_plugin plugin false))
|
||||
([^js plugin remove?]
|
||||
(when-let [id (some-> plugin (.-key) (name))]
|
||||
(let [setter (plugin-handler/make-fn-to-save-dotdir-json "installed-plugins-for-web")
|
||||
plugin (js/JSON.parse (js/JSON.stringify plugin))]
|
||||
(p/let [^js plugins (or (load_installed_web_plugins) #js {})]
|
||||
(if (true? remove?)
|
||||
(when (aget plugins id)
|
||||
(js-delete plugins id))
|
||||
(gobj/set plugins id plugin))
|
||||
(setter :all plugins))))))
|
||||
|
||||
(defn unlink_installed_web_plugin
|
||||
[key]
|
||||
(save_installed_web_plugin #js {:key key} true))
|
||||
|
||||
(def unlink_plugin_user_settings
|
||||
(plugin-handler/make-fn-to-unlink-dotdir-json "settings"))
|
||||
|
||||
(def register_plugin_slash_command
|
||||
(fn [pid ^js cmd-actions]
|
||||
(when-let [[cmd actions] (bean/->clj cmd-actions)]
|
||||
(plugin-handler/register-plugin-slash-command
|
||||
pid [cmd (mapv #(into [(keyword (first %))]
|
||||
(rest %)) actions)]))))
|
||||
|
||||
(def register_plugin_simple_command
|
||||
(fn [pid ^js cmd-action palette?]
|
||||
(when-let [[cmd action] (bean/->clj cmd-action)]
|
||||
(let [action (assoc action 0 (keyword (first action)))
|
||||
cmd (assoc cmd :key (-> (:key cmd) (string/trim) (string/replace ":" "-") (string/replace #"^([0-9])" "_$1")))
|
||||
key (:key cmd)
|
||||
keybinding (:keybinding cmd)
|
||||
palette-cmd (plugin-handler/simple-cmd->palette-cmd pid cmd action)
|
||||
action' #(state/pub-event! [:exec-plugin-cmd {:type type :key key :pid pid :cmd cmd :action action}])]
|
||||
|
||||
;; handle simple commands
|
||||
(plugin-handler/register-plugin-simple-command pid cmd action)
|
||||
|
||||
;; handle palette commands
|
||||
(when palette?
|
||||
(palette-handler/register palette-cmd))
|
||||
|
||||
;; handle keybinding commands
|
||||
(when-let [shortcut-args (and keybinding (plugin-handler/simple-cmd-keybinding->shortcut-args pid key keybinding))]
|
||||
(let [dispatch-cmd (fn [_e]
|
||||
(if palette?
|
||||
(palette-handler/invoke-command palette-cmd)
|
||||
(action')))
|
||||
[mode-id id shortcut-map] (update shortcut-args 2 merge cmd {:fn dispatch-cmd :cmd palette-cmd})]
|
||||
|
||||
(cond
|
||||
;; FIX ME: move to register logic
|
||||
(= mode-id :shortcut.handler/block-editing-only)
|
||||
(shortcut-config/add-shortcut! mode-id id shortcut-map)
|
||||
|
||||
:else
|
||||
(do
|
||||
(println :shortcut/register-shortcut [mode-id id shortcut-map])
|
||||
(st/register-shortcut! mode-id id shortcut-map)))))))))
|
||||
|
||||
(defn unregister_plugin_simple_command
|
||||
[pid]
|
||||
;; remove simple commands
|
||||
(plugin-handler/unregister-plugin-simple-command pid)
|
||||
|
||||
;; remove palette commands
|
||||
(let [cmds-matched (->> (vals @shortcut-config/*shortcut-cmds)
|
||||
(filter #(string/includes? (str (:id %)) (str "plugin." pid))))]
|
||||
(when (seq cmds-matched)
|
||||
(doseq [cmd cmds-matched]
|
||||
(palette-handler/unregister (:id cmd))
|
||||
;; remove keybinding commands
|
||||
(when (seq (:shortcut cmd))
|
||||
(println :shortcut/unregister-shortcut cmd)
|
||||
(st/unregister-shortcut! (:handler-id cmd) (:id cmd)))))))
|
||||
|
||||
(defn register_search_service
|
||||
[pid name ^js opts]
|
||||
(plugin-handler/register-plugin-search-service pid name (bean/->clj opts)))
|
||||
|
||||
(defn unregister_search_services
|
||||
[pid]
|
||||
(plugin-handler/unregister-plugin-search-services pid))
|
||||
|
||||
(def register_plugin_ui_item
|
||||
(fn [pid type ^js opts]
|
||||
(when-let [opts (bean/->clj opts)]
|
||||
(plugin-handler/register-plugin-ui-item
|
||||
pid (assoc opts :type type)))))
|
||||
|
||||
(defn get_external_plugin
|
||||
[pid]
|
||||
(when-let [^js pl (plugin-handler/get-plugin-inst pid)]
|
||||
(.toJSON pl)))
|
||||
|
||||
(defn invoke_external_plugin_cmd
|
||||
[pid cmd-group cmd-key cmd-args]
|
||||
(case (keyword cmd-group)
|
||||
:models
|
||||
(plugin-handler/call-plugin-user-model! pid cmd-key cmd-args)
|
||||
|
||||
:commands
|
||||
(plugin-handler/call-plugin-user-command! pid cmd-key cmd-args)))
|
||||
|
||||
(defn validate_external_plugins [urls]
|
||||
(ipc/ipc :validateUserExternalPlugins urls))
|
||||
|
||||
(def __install_plugin
|
||||
(fn [^js manifest]
|
||||
(when-let [{:keys [repo id] :as manifest} (bean/->clj manifest)]
|
||||
(if-not (and repo id)
|
||||
(throw (js/Error. "[required] :repo :id"))
|
||||
(plugin-common-handler/install-marketplace-plugin! manifest)))))
|
||||
@@ -79,6 +79,12 @@
|
||||
(reduce {} (gobj/getKeys obj)))
|
||||
obj))
|
||||
|
||||
(defn result->js
|
||||
[result]
|
||||
(-> result
|
||||
normalize-keyword-for-json
|
||||
bean/->js))
|
||||
|
||||
(def ^:export to-clj bean/->clj)
|
||||
(def ^:export jsx-to-clj jsx->clj)
|
||||
(def ^:export to-js bean/->js)
|
||||
|
||||
Reference in New Issue
Block a user