Merge branch 'master' into refactor/separate-og-and-db-version

This commit is contained in:
Tienson Qin
2025-12-26 13:10:29 +08:00
9 changed files with 211 additions and 128 deletions

View File

@@ -335,3 +335,71 @@
result (ls-api-call! :editor.get_tag_objects "logseq.class/Task")] result (ls-api-call! :editor.get_tag_objects "logseq.class/Task")]
(is (= (count result) 1)) (is (= (count result) 1))
(is (= "task 1" (get (first result) "title")))))) (is (= "task 1" (get (first result) "title"))))))
(deftest create-and-get-tag-test
(testing "create and get tag with title or ident"
(let [title "book1"
title-ident (str :plugin.class._test_plugin/book1)
tag1 (ls-api-call! :editor.createTag title)
tag2 (ls-api-call! :editor.getTag title)
tag3 (ls-api-call! :editor.getTag title-ident)
tag4 (ls-api-call! :editor.getTag (get tag1 "uuid"))]
(is (= (get tag1 "ident") title-ident) "create tag with title from test as plugin")
(is (= (get tag2 "ident") title-ident) "get tag with title")
(is (= (get tag3 "title") title) "get tag with ident")
(is (= (get tag4 "title") title) "get tag with uuid")))
(testing "add and remove tag extends"
(let [tag1 (ls-api-call! :editor.createTag "tag1")
tag2 (ls-api-call! :editor.createTag "tag2")
tag3 (ls-api-call! :editor.createTag "tag3")
id1 (get tag1 "id")
id2 (get tag2 "id")
id3 (get tag3 "id")
_ (ls-api-call! :editor.addTagExtends id1 id2)
tag1 (ls-api-call! :editor.getTag id1)]
(is (= (get tag1 ":logseq.property.class/extends") [id2]) "tag1 extends tag2 with db id")
(let [_ (ls-api-call! :editor.addTagExtends id1 id3)
tag1 (ls-api-call! :editor.getTag id1)]
(is (= (get tag1 ":logseq.property.class/extends") [id2 id3]) "tag1 extends tag2,tag3 with db ids")))))
(deftest get-tags-by-name-test
(testing "get tags by exact name"
(let [tag-name "product"
tag1 (ls-api-call! :editor.createTag tag-name)
result (ls-api-call! :editor.getTagsByName tag-name)]
(is (= 1 (count result)) "should return exactly one tag")
(is (= (get tag1 "uuid") (get (first result) "uuid")) "should return the created tag")
(is (= (get tag1 "title") (get (first result) "title")) "tag title should match")))
(testing "get tags by name is case-insensitive"
(let [tag-name "TestTag123"
_ (ls-api-call! :editor.createTag tag-name)
result-lower (ls-api-call! :editor.getTagsByName "testtag123")
result-upper (ls-api-call! :editor.getTagsByName "TESTTAG123")
result-mixed (ls-api-call! :editor.getTagsByName "TeStTaG123")]
(is (= 1 (count result-lower)) "should find tag with lowercase search")
(is (= 1 (count result-upper)) "should find tag with uppercase search")
(is (= 1 (count result-mixed)) "should find tag with mixed case search")
(is (= (get (first result-lower) "uuid") (get (first result-upper) "uuid")) "all searches should return same tag")
(is (= (get (first result-lower) "uuid") (get (first result-mixed) "uuid")) "all searches should return same tag")))
(testing "get tags by name returns empty array for non-existent tag"
(let [result (ls-api-call! :editor.getTagsByName "NonExistentTag12345")]
(is (empty? result) "should return empty array for non-existent tag")))
(testing "get tags by name filters out non-tag pages"
(let [page-name "regular-page"
_ (page/new-page page-name)
result (ls-api-call! :editor.getTagsByName page-name)]
(is (empty? result) "should not return regular pages, only tags")))
(testing "get tags by name with multiple tags having similar names"
(let [tag1 (ls-api-call! :editor.createTag "category")
tag2 (ls-api-call! :editor.createTag "Category")
result (ls-api-call! :editor.getTagsByName "category")]
;; Due to case-insensitive name normalization, both tags should be the same
(is (>= (count result) 1) "should return at least one tag")
;; Verify the result contains valid tag structure
(is (string? (get (first result) "uuid")) "returned tag should have uuid")
(is (string? (get (first result) "title")) "returned tag should have title"))))

View File

@@ -247,6 +247,7 @@
(map (fn [id] (d/entity db [:block/uuid id])) tags) (map (fn [id] (d/entity db [:block/uuid id])) tags)
tags) tags)
class? (or class? (some (fn [t] (= :logseq.class/Tag (:db/ident t))) tags)) class? (or class? (some (fn [t] (= :logseq.class/Tag (:db/ident t))) tags))
class-ident-namespace? (and class? class-ident-namespace (string? class-ident-namespace))
title (sanitize-title title*) title (sanitize-title title*)
types (cond class? types (cond class?
#{:logseq.class/Tag} #{:logseq.class/Tag}
@@ -258,29 +259,38 @@
(set (map :db/ident tags)) (set (map :db/ident tags))
:else :else
#{:logseq.class/Page}) #{:logseq.class/Page})
existing-page-id (first (ldb/page-exists? db title types)) existing-names-page (ldb/page-exists? db title types)
existing-page-id (some->> existing-names-page
(filter #(try (when-let [e (and class-ident-namespace? (d/entity db %))]
(let [ns' (namespace (:db/ident e))]
(= (str ns') class-ident-namespace)))
(catch :default _ false)))
(first))
existing-page (some->> existing-page-id (d/entity db))] existing-page (some->> existing-page-id (d/entity db))]
(if (and existing-page (not (:block/parent existing-page))) (if (and existing-page (not (:block/parent existing-page)))
(let [tx-meta {:persist-op? persist-op? (let [tx-meta {:persist-op? persist-op?
:outliner-op :save-block}] :outliner-op :save-block}]
(when (and class? (if (and class?
(not (ldb/class? existing-page)) (not (ldb/class? existing-page))
(ldb/internal-page? existing-page)) (ldb/internal-page? existing-page))
;; Convert existing page to class ;; Convert existing page to class
(let [tx-data [(merge (db-class/build-new-class db (let [tx-data [(merge (db-class/build-new-class db
(select-keys existing-page [:block/title :block/uuid :block/created-at]) (select-keys existing-page [:block/title :block/uuid :block/created-at])
(when (and class? class-ident-namespace (string? class-ident-namespace)) (when class-ident-namespace?
{:ident-namespace class-ident-namespace})) {:ident-namespace class-ident-namespace}))
(select-keys existing-page [:db/ident])) (select-keys existing-page [:db/ident]))
[:db/retract [:block/uuid (:block/uuid existing-page)] :block/tags :logseq.class/Page]]] [:db/retract [:block/uuid (:block/uuid existing-page)] :block/tags :logseq.class/Page]]]
{:tx-meta tx-meta {:tx-meta tx-meta
:tx-data tx-data :tx-data tx-data
:page-uuid (:block/uuid existing-page) :page-uuid (:block/uuid existing-page)
:title (:block/title existing-page)}))) :title (:block/title existing-page)})
(let [page (gp-block/page-name->map title db true date-formatter ;; Just return existing page info
{:class? class? {:page-uuid (:block/uuid existing-page)
:page-uuid (when (uuid? uuid') uuid') :title (:block/title existing-page)}))
:skip-existing-page-check? true}) (let [page (gp-block/page-name->map title db true date-formatter
{:class? class?
:page-uuid (when (uuid? uuid') uuid')
:skip-existing-page-check? true})
[page parents'] (if (and (text/namespace-page? title) split-namespace?) [page parents'] (if (and (text/namespace-page? title) split-namespace?)
(let [pages (split-namespace-pages db page date-formatter class?)] (let [pages (split-namespace-pages db page date-formatter class?)]
[(last pages) (butlast pages)]) [(last pages) (butlast pages)])
@@ -296,11 +306,11 @@
(outliner-validate/validate-page-title-characters (str (:block/title parent)) {:node parent}))) (outliner-validate/validate-page-title-characters (str (:block/title parent)) {:node parent})))
(let [page-uuid (:block/uuid page) (let [page-uuid (:block/uuid page)
page-txs (build-page-tx db properties page (select-keys options [:whiteboard? :class? :tags :class-ident-namespace])) page-txs (build-page-tx db properties page (select-keys options [:whiteboard? :class? :tags :class-ident-namespace]))
txs (concat txs (concat
;; transact doesn't support entities ;; transact doesn't support entities
(remove de/entity? parents') (remove de/entity? parents')
page-txs) page-txs)
tx-meta (cond-> {:persist-op? persist-op? tx-meta (cond-> {:persist-op? persist-op?
:outliner-op :create-page} :outliner-op :create-page}
today-journal? today-journal?
@@ -315,5 +325,5 @@
[conn title opts] [conn title opts]
(let [{:keys [tx-meta tx-data title' page-uuid]} (create @conn title opts)] (let [{:keys [tx-meta tx-data title' page-uuid]} (create @conn title opts)]
(when (seq tx-data) (when (seq tx-data)
(ldb/transact! conn tx-data tx-meta) (ldb/transact! conn tx-data tx-meta))
[title' page-uuid]))) [title' page-uuid]))

View File

@@ -14,8 +14,8 @@
"build": "tsc && rm dist/*.js && npm run build:user", "build": "tsc && rm dist/*.js && npm run build:user",
"lint": "prettier --check \"src/**/*.{ts, js}\"", "lint": "prettier --check \"src/**/*.{ts, js}\"",
"fix": "prettier --write \"src/**/*.{ts, js}\"", "fix": "prettier --write \"src/**/*.{ts, js}\"",
"build:docs": "typedoc src/LSPlugin.user.ts", "build:docs": "typedoc --plugin typedoc-plugin-lsp-docs src/LSPlugin.user.ts",
"build:docs:json": "typedoc --plugin typedoc-plugin-lsp-docs src/LSPlugin.user.ts && typedoc --json docs/out.json ./src/LSPlugin.user.ts" "build:docs:json": "typedoc --json docs/out.json ./src/LSPlugin.user.ts"
}, },
"dependencies": { "dependencies": {
"csstype": "3.1.0", "csstype": "3.1.0",
@@ -41,7 +41,7 @@
"terser-webpack-plugin": "^5.3.6", "terser-webpack-plugin": "^5.3.6",
"ts-loader": "9.3.0", "ts-loader": "9.3.0",
"typedoc": "0.28.15", "typedoc": "0.28.15",
"typedoc-plugin-lsp-docs": "^0.0.1", "typedoc-plugin-lsp-docs": "^0.0.2",
"typescript": "5.9.3", "typescript": "5.9.3",
"webpack": "5.94.0", "webpack": "5.94.0",
"webpack-bundle-analyzer": "4.5.0", "webpack-bundle-analyzer": "4.5.0",

View File

@@ -697,15 +697,13 @@ export interface IEditorProxy extends Record<string, any> {
* @param opts * @param opts
*/ */
insertBlock: ( insertBlock: (
srcBlock: BlockIdentity, srcBlock: BlockIdentity | EntityID,
content: string, content: string,
opts?: Partial<{ opts?: Partial<{
before: boolean before: boolean
sibling: boolean sibling: boolean
start: boolean start: boolean
end: boolean end: boolean
isPageBlock: boolean
focus: boolean
customUUID: string customUUID: string
properties: {} properties: {}
}> }>
@@ -723,30 +721,20 @@ export interface IEditorProxy extends Record<string, any> {
) => Promise<Array<BlockEntity> | null> ) => Promise<Array<BlockEntity> | null>
updateBlock: ( updateBlock: (
srcBlock: BlockIdentity, srcBlock: BlockIdentity | EntityID,
content: string, content: string,
opts?: Partial<{ properties: {} }> opts?: Partial<{ properties: {} }>
) => Promise<void> ) => Promise<void>
removeBlock: (srcBlock: BlockIdentity) => Promise<void> removeBlock: (srcBlock: BlockIdentity | EntityID) => Promise<void>
getBlock: ( getBlock: (
srcBlock: BlockIdentity | EntityID, srcBlock: BlockIdentity | EntityID,
opts?: Partial<{ includeChildren: boolean }> opts?: Partial<{ includeChildren: boolean }>
) => Promise<BlockEntity | null> ) => Promise<BlockEntity | null>
/**
* @example
*
* ```ts
* logseq.Editor.setBlockCollapsed('uuid', true)
* logseq.Editor.setBlockCollapsed('uuid', 'toggle')
* ```
* @param uuid
* @param opts
*/
setBlockCollapsed: ( setBlockCollapsed: (
uuid: BlockUUID, srcBlock: BlockIdentity | EntityID,
opts: { flag: boolean | 'toggle' } | boolean | 'toggle' opts: { flag: boolean | 'toggle' } | boolean | 'toggle'
) => Promise<void> ) => Promise<void>
@@ -780,7 +768,8 @@ export interface IEditorProxy extends Record<string, any> {
getAllProperties: () => Promise<PageEntity[] | null> getAllProperties: () => Promise<PageEntity[] | null>
getTagObjects: (nameOrIdent: string) => Promise<BlockEntity[] | null> getTagObjects: (nameOrIdent: string) => Promise<BlockEntity[] | null>
createTag: (tagName: string, opts?: Partial<{ uuid: string }>) => Promise<PageEntity | null> createTag: (tagName: string, opts?: Partial<{ uuid: string }>) => Promise<PageEntity | null>
getTag: (nameOrIdent: string) => Promise<PageEntity | null> getTag: (nameOrIdent: string | EntityID) => Promise<PageEntity | null>
getTagsByName: (tagName: string) => Promise<Array<PageEntity> | null>
addTagProperty: (tagId: BlockIdentity, propertyIdOrName: BlockIdentity) => Promise<void> addTagProperty: (tagId: BlockIdentity, propertyIdOrName: BlockIdentity) => Promise<void>
removeTagProperty: (tagId: BlockIdentity, propertyIdOrName: BlockIdentity) => Promise<void> removeTagProperty: (tagId: BlockIdentity, propertyIdOrName: BlockIdentity) => Promise<void>
addTagExtends: (tagId: BlockIdentity, parentTagIdOrName: BlockIdentity) => Promise<void> addTagExtends: (tagId: BlockIdentity, parentTagIdOrName: BlockIdentity) => Promise<void>
@@ -806,11 +795,11 @@ export interface IEditorProxy extends Record<string, any> {
) => Promise<BlockEntity | null> ) => Promise<BlockEntity | null>
getPreviousSiblingBlock: ( getPreviousSiblingBlock: (
srcBlock: BlockIdentity srcBlock: BlockIdentity | EntityID
) => Promise<BlockEntity | null> ) => Promise<BlockEntity | null>
getNextSiblingBlock: ( getNextSiblingBlock: (
srcBlock: BlockIdentity srcBlock: BlockIdentity | EntityID
) => Promise<BlockEntity | null> ) => Promise<BlockEntity | null>
moveBlock: ( moveBlock: (
@@ -843,17 +832,15 @@ export interface IEditorProxy extends Record<string, any> {
// block property related APIs // block property related APIs
upsertBlockProperty: ( upsertBlockProperty: (
block: BlockIdentity, block: BlockIdentity | EntityID,
key: string, key: string,
value: any value: any
) => Promise<void> ) => Promise<void>
removeBlockProperty: (block: BlockIdentity, key: string) => Promise<void> removeBlockProperty: (block: BlockIdentity | EntityID, key: string) => Promise<void>
getBlockProperty: (block: BlockIdentity | EntityID, key: string) => Promise<BlockEntity | null>
getBlockProperty: (block: BlockIdentity, key: string) => Promise<BlockEntity | unknown> getBlockProperties: (block: BlockIdentity | EntityID) => Promise<Record<string, any> | null>
getPageProperties: (page: PageIdentity | EntityID) => Promise<Record<string, any> | null>
getBlockProperties: (block: BlockIdentity) => Promise<Record<string, any> | null>
getPageProperties: (page: PageIdentity) => Promise<Record<string, any> | null>
scrollToBlockInPage: ( scrollToBlockInPage: (
pageName: BlockPageName, pageName: BlockPageName,
@@ -862,6 +849,7 @@ export interface IEditorProxy extends Record<string, any> {
) => void ) => void
openInRightSidebar: (id: BlockUUID | EntityID) => void openInRightSidebar: (id: BlockUUID | EntityID) => void
openPDFViewer: (assetBlockIdOrFileUrl: string | EntityID) => Promise<void>
/** /**
* @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-a-translator * @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-a-translator

View File

@@ -1279,6 +1279,13 @@
(fn [] (fn []
#(set-property-value! @*value)) #(set-property-value! @*value))
[]) [])
(hooks/use-effect!
(fn []
(set-value! number-value)
#())
[number-value])
[:div.ls-number.flex.flex-1.jtrigger [:div.ls-number.flex.flex-1.jtrigger
{:ref *ref {:ref *ref
:on-click #(do :on-click #(do
@@ -1291,6 +1298,7 @@
:class (str "ls-number-input h-6 px-0 py-0 border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 text-base" :class (str "ls-number-input h-6 px-0 py-0 border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 text-base"
(when table-view? " text-sm")) (when table-view? " text-sm"))
:value value :value value
:type "number"
:on-change (fn [e] :on-change (fn [e]
(set-value! (util/evalue e)) (set-value! (util/evalue e))
(reset! *value (util/evalue e))) (reset! *value (util/evalue e)))

View File

@@ -3327,10 +3327,11 @@
(defn toggle-open-block-children! [block-id] (defn toggle-open-block-children! [block-id]
(p/let [blocks (<all-blocks-with-level {:incremental? false (p/let [blocks (<all-blocks-with-level {:incremental? false
:collapse? true :expanded? true
:root-block block-id}) :root-block block-id})
all-expanded? (empty? blocks)] children-blocks (remove #(= block-id (:block/uuid %)) blocks)
(if all-expanded? any-expanded? (seq (filter (complement util/collapsed?) children-blocks))]
(if any-expanded?
(collapse-all! block-id {:collapse-self? false}) (collapse-all! block-id {:collapse-self? false})
(expand-all! block-id)))) (expand-all! block-id))))

View File

@@ -132,6 +132,7 @@
(def ^:export set_block_collapsed api-editor/set_block_collapsed) (def ^:export set_block_collapsed api-editor/set_block_collapsed)
(def ^:export update_block api-editor/update_block) (def ^:export update_block api-editor/update_block)
(def ^:export upsert_block_property api-editor/upsert_block_property) (def ^:export upsert_block_property api-editor/upsert_block_property)
(def ^:export open_pdf_viewer api-editor/open_pdf_viewer)
;; ui ;; ui
(def ^:export show_msg sdk-ui/-show_msg) (def ^:export show_msg sdk-ui/-show_msg)
@@ -200,6 +201,7 @@
(def ^:export get_tag_objects db-based-api/get-tag-objects) (def ^:export get_tag_objects db-based-api/get-tag-objects)
(def ^:export create_tag db-based-api/create-tag) (def ^:export create_tag db-based-api/create-tag)
(def ^:export get_tag db-based-api/get-tag) (def ^:export get_tag db-based-api/get-tag)
(def ^:export get_tags_by_name db-based-api/get-tags-by-name)
(def ^:export add_tag_extends db-based-api/add-tag-extends) (def ^:export add_tag_extends db-based-api/add-tag-extends)
(def ^:export remove_tag_extends db-based-api/remove-tag-extends) (def ^:export remove_tag_extends db-based-api/remove-tag-extends)
(def ^:export add_block_tag db-based-api/add-block-tag) (def ^:export add_block_tag db-based-api/add-block-tag)

View File

@@ -8,6 +8,7 @@
[datascript.core :as d] [datascript.core :as d]
[frontend.db :as db] [frontend.db :as db]
[frontend.db.async :as db-async] [frontend.db.async :as db-async]
[frontend.db.conn :as db-conn]
[frontend.db.model :as db-model] [frontend.db.model :as db-model]
[frontend.handler.common.page :as page-common-handler] [frontend.handler.common.page :as page-common-handler]
[frontend.handler.db-based.page :as db-page-handler] [frontend.handler.db-based.page :as db-page-handler]
@@ -21,6 +22,7 @@
[logseq.api.block :as api-block] [logseq.api.block :as api-block]
[logseq.db :as ldb] [logseq.db :as ldb]
[logseq.db.common.entity-util :as common-entity-util] [logseq.db.common.entity-util :as common-entity-util]
[logseq.db.frontend.entity-util :as entity-util]
[logseq.graph-parser.text :as text] [logseq.graph-parser.text :as text]
[logseq.outliner.core :as outliner-core] [logseq.outliner.core :as outliner-core]
[logseq.sdk.core] [logseq.sdk.core]
@@ -219,9 +221,12 @@
(when (text/namespace-page? title) (when (text/namespace-page? title)
(throw (ex-info "Tag title shouldn't include forward slash" {:title title}))) (throw (ex-info "Tag title shouldn't include forward slash" {:title title})))
(let [opts (bean/->clj opts) (let [opts (bean/->clj opts)
custom-ident-namespace (:customIdentNamespace opts)
class-ident-namespace (or (some-> custom-ident-namespace (api-block/sanitize-user-property-name))
(api-block/resolve-class-prefix-for-db this))
opts' (assoc opts opts' (assoc opts
:redirect? false :redirect? false
:class-ident-namespace (api-block/resolve-class-prefix-for-db this))] :class-ident-namespace class-ident-namespace)]
(p/let [tag (db-page-handler/<create-class! title opts')] (p/let [tag (db-page-handler/<create-class! title opts')]
(sdk-utils/result->js tag))))) (sdk-utils/result->js tag)))))
@@ -254,21 +259,28 @@
(:db/id extend)))) (:db/id extend))))
(defn get-tag [class-uuid-or-ident-or-title] (defn get-tag [class-uuid-or-ident-or-title]
(this-as (this-as this
this (let [eid (if (number? class-uuid-or-ident-or-title)
(let [title-or-ident (-> (if-not (string? class-uuid-or-ident-or-title) class-uuid-or-ident-or-title
(str class-uuid-or-ident-or-title) (let [title-or-ident (-> (if-not (string? class-uuid-or-ident-or-title)
class-uuid-or-ident-or-title) (str class-uuid-or-ident-or-title)
(string/replace #"^:+" "")) class-uuid-or-ident-or-title)
eid (if (text/namespace-page? title-or-ident) (string/replace #"^:+" ""))]
(keyword title-or-ident) (if (text/namespace-page? title-or-ident)
(if (util/uuid-string? title-or-ident) (keyword title-or-ident)
(when-let [id (sdk-utils/uuid-or-throw-error title-or-ident)] (if (util/uuid-string? title-or-ident)
[:block/uuid id]) (when-let [id (sdk-utils/uuid-or-throw-error title-or-ident)]
(keyword (api-block/resolve-class-prefix-for-db this) title-or-ident))) [:block/uuid id])
tag (db/entity eid)] (keyword (api-block/resolve-class-prefix-for-db this) title-or-ident)))))
(when (ldb/class? tag) tag (db/entity eid)]
(sdk-utils/result->js tag))))) (when (ldb/class? tag)
(sdk-utils/result->js tag)))))
(defn get-tags-by-name [name]
(when-let [tags (some->> (entity-util/get-pages-by-name (db-conn/get-db) name)
(map #(some-> % (first) (db/entity)))
(filter ldb/class?))]
(sdk-utils/result->js tags)))
(defn tag-add-property [tag-id property-id-or-name] (defn tag-add-property [tag-id property-id-or-name]
(p/let [tag (db/get-case-page tag-id) (p/let [tag (db/get-case-page tag-id)

View File

@@ -2,13 +2,14 @@
"Editor related APIs" "Editor related APIs"
(:require [cljs-bean.core :as bean] (:require [cljs-bean.core :as bean]
[cljs.reader] [cljs.reader]
[clojure.string :as string]
[frontend.commands :as commands] [frontend.commands :as commands]
[frontend.date :as date] [frontend.date :as date]
[frontend.db :as db] [frontend.db :as db]
[frontend.db.async :as db-async] [frontend.db.async :as db-async]
[frontend.db.model :as db-model] [frontend.db.model :as db-model]
[frontend.db.utils :as db-utils] [frontend.db.utils :as db-utils]
[frontend.extensions.pdf.assets :as pdf-assets]
[frontend.handler.assets :as assets-handler]
[frontend.handler.code :as code-handler] [frontend.handler.code :as code-handler]
[frontend.handler.dnd :as editor-dnd-handler] [frontend.handler.dnd :as editor-dnd-handler]
[frontend.handler.editor :as editor-handler] [frontend.handler.editor :as editor-handler]
@@ -24,6 +25,7 @@
[goog.dom :as gdom] [goog.dom :as gdom]
[logseq.api.block :as api-block] [logseq.api.block :as api-block]
[logseq.api.db-based :as db-based-api] [logseq.api.db-based :as db-based-api]
[logseq.common.path :as path]
[logseq.common.util.date-time :as date-time-util] [logseq.common.util.date-time :as date-time-util]
[logseq.db :as ldb] [logseq.db :as ldb]
[logseq.sdk.core] [logseq.sdk.core]
@@ -185,26 +187,13 @@
block)) block))
(defn insert_block (defn insert_block
[block-uuid-or-page-name content ^js opts] [id content ^js opts]
(this-as this (this-as this
(when (string/blank? block-uuid-or-page-name) (p/let [block (<get-block id)]
(throw (js/Error. "Page title or block UUID shouldn't be empty."))) (when-let [block-uuid (:block/uuid block)]
(p/let [{:keys [before start end sibling customUUID properties autoOrderedList schema]} (bean/->clj opts)
(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 (or customUUID (:id properties))
custom-uuid (when custom-uuid (sdk-utils/uuid-or-throw-error custom-uuid)) 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)) _ (when (and custom-uuid (db-model/query-block-by-uuid custom-uuid))
(throw (js/Error. (throw (js/Error.
(util/format "Custom block UUID already exists (%s)." custom-uuid)))) (util/format "Custom block UUID already exists (%s)." custom-uuid))))
@@ -227,8 +216,7 @@
:before? before? :before? before?
:start? start :start? start
:end? end :end? end
:edit-block? edit-block? :edit-block? false
:page page-name
:custom-uuid custom-uuid :custom-uuid custom-uuid
:ordered-list? (if (boolean? autoOrderedList) autoOrderedList false)}] :ordered-list? (if (boolean? autoOrderedList) autoOrderedList false)}]
(db-based-api/insert-block this content properties schema opts')))))) (db-based-api/insert-block this content properties schema opts'))))))
@@ -245,17 +233,18 @@
(db-based-api/insert-batch-blocks this block blocks' opts)))))))) (db-based-api/insert-batch-blocks this block blocks' opts))))))))
(def remove_block (def remove_block
(fn [block-uuid ^js _opts] (fn [id ^js _opts]
(p/let [repo (state/get-current-repo) (p/let [repo (state/get-current-repo)
_ (<get-block block-uuid {:children? false})] block (<get-block id {:children? false})]
(editor-handler/delete-block-aux! (when-let [block-uuid (:block/uuid block)]
{:block/uuid (sdk-utils/uuid-or-throw-error block-uuid) :repo repo})))) (editor-handler/delete-block-aux!
{:block/uuid block-uuid :repo repo})))))
(def update_block (def update_block
(fn [block-uuid content ^js opts] (fn [id content ^js opts]
(this-as (this-as
this this
(p/let [block (<get-block block-uuid {:children? false}) (p/let [block (<get-block id {:children? false})
opts' (bean/->clj opts)] opts' (bean/->clj opts)]
(when block (when block
(db-based-api/update-block this block content opts')))))) (db-based-api/update-block this block content opts'))))))
@@ -295,9 +284,8 @@
(get_block (:block/uuid block) opts)))) (get_block (:block/uuid block) opts))))
(def get_previous_sibling_block (def get_previous_sibling_block
(fn [block-uuid ^js opts] (fn [id ^js opts]
(p/let [id (sdk-utils/uuid-or-throw-error block-uuid) (p/let [block (<get-block id)
block (<get-block id)
;; Load all children blocks ;; Load all children blocks
_ (api-block/<sync-children-blocks! block)] _ (api-block/<sync-children-blocks! block)]
(when block (when block
@@ -305,9 +293,8 @@
(get_block (:block/uuid sibling) opts)))))) (get_block (:block/uuid sibling) opts))))))
(def get_next_sibling_block (def get_next_sibling_block
(fn [block-uuid ^js opts] (fn [id ^js opts]
(p/let [id (sdk-utils/uuid-or-throw-error block-uuid) (p/let [block (<get-block id)
block (<get-block id)
;; Load all children blocks ;; Load all children blocks
_ (api-block/<sync-children-blocks! block)] _ (api-block/<sync-children-blocks! block)]
(when block (when block
@@ -315,11 +302,11 @@
(get_block (:block/uuid sibling) opts)))))) (get_block (:block/uuid sibling) opts))))))
(def set_block_collapsed (def set_block_collapsed
(fn [block-uuid ^js opts] (fn [id ^js opts]
(p/let [block-uuid (sdk-utils/uuid-or-throw-error block-uuid) (p/let [block (<get-block id {:children? false})]
block (<get-block block-uuid {:children? false})]
(when block (when block
(let [opts (bean/->clj opts) (let [block-uuid (:block/uuid block)
opts (bean/->clj opts)
opts (if (or (string? opts) (boolean? opts)) {:flag opts} opts) opts (if (or (string? opts) (boolean? opts)) {:flag opts} opts)
{:keys [flag]} opts {:keys [flag]} opts
flag (if (= "toggle" flag) flag (if (= "toggle" flag)
@@ -422,35 +409,29 @@
;; block properties ;; block properties
(defn upsert_block_property (defn upsert_block_property
[block-uuid key ^js value ^js options] [id key ^js value ^js options]
(this-as (this-as this
this (p/let [key' (api-block/sanitize-user-property-name key)
(p/let [key' (api-block/sanitize-user-property-name key) opts (bean/->clj options)
opts (bean/->clj options) block (<get-block id {:children? false})
block-uuid (sdk-utils/uuid-or-throw-error block-uuid) value (bean/->clj value)]
block (<get-block block-uuid {:children? false}) (when block
value (bean/->clj value)] (db-based-api/upsert-block-property this block key' value opts)))))
(when block
(db-based-api/upsert-block-property this block key' value opts)))))
(defn remove_block_property (defn remove_block_property
[block-uuid key] [id key]
(this-as this (this-as this
(p/let [key (api-block/sanitize-user-property-name key) (p/let [block (<get-block id {:children? false})]
block-uuid (sdk-utils/uuid-or-throw-error block-uuid) (when-let [block-uuid (:block/uuid block)]
_block (<get-block block-uuid {:children? false}) (let [key (api-block/sanitize-user-property-name key)
key-ns? (namespace (keyword key)) key (api-block/get-db-ident-from-property-name key this)]
key (if (not key-ns?) (property-handler/remove-block-property! block-uuid key))))))
(api-block/get-db-ident-from-property-name key this)
key)]
(property-handler/remove-block-property! block-uuid key))))
(defn get_block_property (defn get_block_property
[block-uuid key] [id key]
(this-as this (this-as this
(p/let [block-uuid (sdk-utils/uuid-or-throw-error block-uuid) (p/let [block (<get-block id {:children? false})]
_block (<get-block block-uuid {:children? false})] (when-let [properties (some-> block (:block/uuid) (db-model/get-block-by-uuid) (:block/properties))]
(when-let [properties (some-> block-uuid (db-model/get-block-by-uuid) (:block/properties))]
(when (seq properties) (when (seq properties)
(let [property-name (api-block/sanitize-user-property-name key) (let [property-name (api-block/sanitize-user-property-name key)
ident (api-block/get-db-ident-from-property-name property-name this) ident (api-block/get-db-ident-from-property-name property-name this)
@@ -470,9 +451,8 @@
(bean/->js (sdk-utils/normalize-keyword-for-json property-value))))))))) (bean/->js (sdk-utils/normalize-keyword-for-json property-value)))))))))
(def get_block_properties (def get_block_properties
(fn [block-uuid] (fn [id]
(p/let [block-uuid (sdk-utils/uuid-or-throw-error block-uuid) (p/let [block (<get-block id {:children? false})]
block (<get-block block-uuid {:children? false})]
(when block (when block
(let [properties (api-block/into-readable-db-properties (:block/properties block))] (let [properties (api-block/into-readable-db-properties (:block/properties block))]
(sdk-utils/result->js properties)))))) (sdk-utils/result->js properties))))))
@@ -482,3 +462,17 @@
(p/let [page (<get-block id-or-page-name {:children? false})] (p/let [page (<get-block id-or-page-name {:children? false})]
(when-let [id (:block/uuid page)] (when-let [id (:block/uuid page)]
(get_block_properties id)))) (get_block_properties id))))
(defn open_pdf_viewer
[block-identity-or-file-url]
(p/let [[block href] (if (and (string? block-identity-or-file-url)
(or (path/protocol-url? block-identity-or-file-url)
(path/absolute? block-identity-or-file-url)))
[nil block-identity-or-file-url]
(p/let [block (<get-block block-identity-or-file-url {:children? false})]
[block (if block
(util/format "../assets/%s.pdf" (:block/uuid block))
block-identity-or-file-url)]))
href' (assets-handler/<make-asset-url href)]
(when-let [current (pdf-assets/inflate-asset href {:block block :href href'})]
(state/set-current-pdf! current))))