Kaynağa Gözat

Merge branch 'disable-webview-resize' of github.com:logseq/logseq into disable-webview-resize

llcc 3 yıl önce
ebeveyn
işleme
bcfc2bc6ce

+ 1 - 3
.carve/config.edn

@@ -5,7 +5,5 @@
                   ;; Ignore b/c too many false positives
                   frontend.db
                   ;; Used for debugging
-                  frontend.db.debug
-                  ;; namespace fns are lazily loaded
-                  frontend.extensions.age-encryption]
+                  frontend.db.debug]
  :report {:format :ignore}}

+ 2 - 2
android/app/build.gradle

@@ -6,8 +6,8 @@ android {
         applicationId "com.logseq.app"
         minSdkVersion rootProject.ext.minSdkVersion
         targetSdkVersion rootProject.ext.targetSdkVersion
-        versionCode 19
-        versionName "0.6.6"
+        versionCode 20
+        versionName "0.6.7"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         aaptOptions {
              // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.

+ 4 - 3
libs/README.md

@@ -1,6 +1,6 @@
 ## @logseq/libs
 
-🚀 Logseq SDK libraries [Draft].
+🚀 Logseq SDK libraries.
 
 #### Installation
 
@@ -16,8 +16,9 @@ Load `logseq` plugin sdk as global namespace
 import "@logseq/libs"
 ```
 
-#### Samples
-https://github.com/logseq/logseq-plugin-samples
+#### APIs & Samples
+- https://logseq.github.io/plugins/
+- https://github.com/logseq/logseq-plugin-samples
 
 #### Community templates
 

+ 1 - 1
libs/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@logseq/libs",
-  "version": "0.0.2",
+  "version": "0.0.6",
   "description": "Logseq SDK libraries",
   "main": "dist/lsplugin.user.js",
   "typings": "index.d.ts",

+ 1 - 1
libs/src/LSPlugin.caller.ts

@@ -159,7 +159,7 @@ class LSPluginCaller extends EventEmitter {
             payload._sync = tag
 
             actor.setTag(`async call #${tag}`)
-            debug('async call #', tag)
+            debug(`async call #${tag}`)
           }
 
           refParent.emit(LSPMSGFn(model.baseInfo.id), { type, payload })

+ 52 - 2
libs/src/LSPlugin.ts

@@ -112,6 +112,12 @@ export interface AppUserInfo {
   [key: string]: any
 }
 
+export interface AppInfo {
+  version: string
+
+  [key: string]: any
+}
+
 /**
  * User's app configurations
  */
@@ -271,7 +277,12 @@ export type UserProxyTags = 'app' | 'editor' | 'db' | 'git' | 'ui' | 'assets'
  * App level APIs
  */
 export interface IAppProxy {
-  // base
+  /**
+   * @added 0.0.4
+   * @param key
+   */
+  getInfo: (key?: keyof AppInfo) => Promise<AppInfo | any>
+
   getUserInfo: () => Promise<AppUserInfo | null>
   getUserConfigs: () => Promise<AppUserConfigs>
 
@@ -349,10 +360,23 @@ export interface IAppProxy {
 
   // ui
   queryElementById: (id: string) => Promise<string | boolean>
+
+  /**
+   * @added 0.0.5
+   * @param selector
+   */
+  queryElementRect: (selector: string) => Promise<DOMRectReadOnly | null>
+
+  /**
+   * @deprecated
+   * @param content
+   * @param status
+   */
   showMsg: (
     content: string,
     status?: 'success' | 'warning' | 'error' | string
   ) => void
+  
   setZoomFactor: (factor: number) => void
   setFullScreen: (flag: boolean | 'toggle') => void
   setLeftSidebarVisible: (flag: boolean | 'toggle') => void
@@ -547,9 +571,19 @@ export interface IEditorProxy extends Record<string, any> {
     opts?: Partial<{ includeChildren: boolean }>
   ) => Promise<BlockEntity | null>
 
+  /**
+   * @example
+   *
+   * ```ts
+   *  logseq.Editor.setBlockCollapsed('uuid', true)
+   *  logseq.Editor.setBlockCollapsed('uuid', 'toggle')
+   * ```
+   * @param uuid
+   * @param opts
+   */
   setBlockCollapsed: (
     uuid: BlockUUID,
-    opts?: { flag: boolean | 'toggle' }
+    opts: { flag: boolean | 'toggle' } | boolean | 'toggle'
   ) => Promise<void>
 
   getPage: (
@@ -642,6 +676,8 @@ export interface IDBProxy {
 
   /**
    * Hook all transaction data of DB
+   *
+   * @added 0.0.2
    */
   onChanged: IUserHook<{
     blocks: Array<BlockEntity>
@@ -651,6 +687,8 @@ export interface IDBProxy {
 
   /**
    * Subscribe a specific block changed event
+   *
+   * @added 0.0.2
    */
   onBlockChanged(
     uuid: BlockUUID,
@@ -667,6 +705,7 @@ export interface IDBProxy {
  */
 export interface IGitProxy {
   /**
+   * @added 0.0.2
    * @link https://github.com/desktop/dugite/blob/master/docs/api/exec.md
    * @param args
    */
@@ -687,6 +726,13 @@ export type UIMsgOptions = {
 export type UIMsgKey = UIMsgOptions['key']
 
 export interface IUIProxy {
+  /**
+   * @added 0.0.2
+   *
+   * @param content
+   * @param status
+   * @param opts
+   */
   showMsg: (
     content: string,
     status?: 'success' | 'warning' | 'error' | string,
@@ -700,6 +746,10 @@ export interface IUIProxy {
  * Assets related APIs
  */
 export interface IAssetsProxy {
+  /**
+   * @added 0.0.2
+   * @param exts
+   */
   listFilesOfCurrentGraph(
     exts: string | string[]
   ): Promise<{

+ 25 - 7
libs/src/LSPlugin.user.ts

@@ -32,6 +32,7 @@ import {
   BlockEntity,
   IDatom,
   IAssetsProxy,
+  AppInfo,
 } from './LSPlugin'
 import Debug from 'debug'
 import * as CSS from 'csstype'
@@ -85,7 +86,18 @@ function registerSimpleCommand(
   })
 }
 
+let _appBaseInfo: AppInfo = null
 const app: Partial<IAppProxy> = {
+  async getInfo(
+    this: LSPluginUser,
+    key
+  ) {
+    if (!_appBaseInfo) {
+      _appBaseInfo = await this._execCallableAPIAsync('get-app-info')
+    }
+    return typeof key === 'string' ? _appBaseInfo[key] : _appBaseInfo
+  },
+
   registerCommand: registerSimpleCommand,
 
   registerCommandPalette(
@@ -166,7 +178,7 @@ const app: Partial<IAppProxy> = {
     } else {
       flag ? sf(true) : sf()
     }
-  },
+  }
 }
 
 let registeredCmdUid = 0
@@ -402,7 +414,6 @@ export class LSPluginUser
         console.warn(e)
       }
 
-
       callback && callback.call(this, baseInfo)
     } catch (e) {
       console.error(`${this._debugTag} [Ready Error]`, e)
@@ -557,7 +568,7 @@ export class LSPluginUser
         return function (this: any, ...args: any) {
           if (origMethod) {
             const ret = origMethod.apply(that, args.concat(tag))
-            if (ret !== PROXY_CONTINUE) return
+            if (ret !== PROXY_CONTINUE) return ret
           }
 
           // Handle hook
@@ -575,14 +586,21 @@ export class LSPluginUser
               const handler = args[0]
               caller[f](type, handler)
 
-              if (isOff) {
-                return () => {
-                  caller.off(type, handler)
+              const unlisten = () => {
+                caller.off(type, handler)
+                if (!caller.listenerCount(type)) {
                   that.App._uninstallPluginHook(pid, type)
                 }
+              }
+
+              if (!isOff) {
+                that.App._installPluginHook(pid, type)
               } else {
-                return that.App._installPluginHook(pid, type)
+                unlisten()
+                return
               }
+
+              return unlisten
             }
           }
 

+ 2 - 2
libs/src/helpers.ts

@@ -224,8 +224,8 @@ export function setupInjectedUI(
     float = true
   }
 
-  const id = `${ui.key}-${slot}-${pl.id}`
-  const key = `${ui.key}--${pl.id}`
+  const id = `${pl.id}--${ui.key}`
+  const key = id
 
   const target = float
     ? document.body

+ 24 - 1
libs/src/modules/LSPlugin.Experiments.ts

@@ -3,7 +3,9 @@ import { PluginLocal } from '../LSPlugin.core'
 import { safeSnakeCase } from '../helpers'
 
 /**
- * Some experiment features
+ * WARN: These are some experience features and may be adjusted at any time.
+ * These unofficial plugins that use these APIs are temporarily
+ * not supported on the Marketplace.
  */
 export class LSPluginExperiments {
   constructor(private ctx: LSPluginUser) {}
@@ -57,6 +59,27 @@ export class LSPluginExperiments {
     )
   }
 
+  registerExtensionsEnhancer<T = any>(
+    type: 'katex',
+    enhancer: (v: T) => Promise<any>
+  ) {
+    const host = this.ensureHostScope()
+
+    switch (type) {
+      case 'katex':
+        if (host.katex) {
+          enhancer(host.katex).catch(console.error)
+        }
+        break
+      default:
+    }
+
+    return host.logseq.api.exper_register_extensions_enhancer(
+      this.ctx.baseInfo.id,
+      type, enhancer
+    )
+  }
+
   ensureHostScope(): any {
     if (window === top) {
       throw new Error('Can not access host scope!')

Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
resources/js/lsplugin.core.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
resources/js/lsplugin.user.js


+ 1 - 1
resources/package.json

@@ -1,6 +1,6 @@
 {
   "name": "Logseq",
-  "version": "0.6.6",
+  "version": "0.6.7",
   "main": "electron.js",
   "author": "Logseq",
   "license": "AGPL-3.0",

+ 2 - 1
src/main/frontend/components/editor.cljs

@@ -321,7 +321,7 @@
               (when set-default-width?
                 {:width max-width})
               (let [^js/HTMLElement textarea
-                    (js/document.querySelector "textarea")]
+                    (js/document.querySelector "textarea.ls-textarea")]
                 (if (<= (.-clientWidth textarea) (+ left (if set-default-width? max-width 500)))
                   {:right 0}
                   {:left (if (and y-diff (= y-diff 0)) left 0)})))}
@@ -389,6 +389,7 @@
   (let [content (if content (str content) "")]
     ;; as the function is binding to the editor content, optimization is welcome
     (str
+     "ls-textarea "
      (if (or (> (.-length content) 1000)
              (string/includes? content "\n"))
        "multiline-block"

+ 20 - 2
src/main/frontend/dicts.cljc

@@ -2778,7 +2778,7 @@
         :more "詳細"
         :search/result-for "Search result for "
         :search/items "items"
-        :search/page-names "Search page names"
+        :search/page-names "ページ名で検索"
         :help/context-menu "ブロックのコンテキストメニュー"
         :help/fold-unfold "ブロックの折りたたみ/展開 (編集モードでないとき)"
         :help/markdown-syntax "マークダウン文法"
@@ -2825,6 +2825,8 @@
         :page/action-publish "パブリッシュする"
         :page/make-public "パブリッシュのため公開する"
         :page/version-history "ページ履歴の確認"
+        :page/open-backup-directory "ページのバックアップディレクトリを開く"
+        :page/file-sync-versions "Page versions"
         :page/make-private "非公開にする"
         :page/delete "ページ削除"
         :page/add-to-favorites "お気に入りへ追加"
@@ -2837,6 +2839,7 @@
         :page/new-title "新規ページのタイトル?"
         :page/earlier "もっと前へ"
         :page/no-more-journals "これ以上日誌はありません"
+        :page/copy-page-url "ページの URL をコピー"
         :journal/multiple-files-with-different-formats "異なるフォーマットの日誌ファイルが同じ月にあるようです。各月には一つの日誌ファイルだけを置くようにしてください。"
         :journal/go-to "ファイルへ"
         :file/name "ファイル名"
@@ -2911,6 +2914,8 @@
         :settings-page/tab-shortcuts "ショートカット"
         :settings-page/tab-version-control "バージョンコントロール"
         :settings-page/tab-advanced "高度な設定"
+        :settings-page/plugin-system "プラグインシステム"
+        :settings-page/network-proxy "ネットワークプロキシ"
         :logseq "Logseq"
         :on "ON"
         :more-options "他のオプション"
@@ -2921,11 +2926,18 @@
         :cancel "キャンセル"
         :close "閉じる"
         :delete "削除"
+        :save "保存"
+        :type "種別"
+        :host "ホスト"
+        :port "ポート"
         :re-index "インデックス再構築"
         :re-index-detail "グラフ再構築"
+        :re-index-multiple-windows-warning "このグラフのインデックスを再構築する前に、Logseq で開いている他のウィンドウを閉じる必要があります。"
+        :re-index-discard-unsaved-changes-warning "インデックスの再構築は現在のグラフをいったん破棄し、現在ディスク上にある全てのファイルから再構築します。未保存の内容は失われます。また、少し時間がかかります。実行してもよいですか?"
         :open-new-window "新規ウィンドウ"
         :sync-from-local-files "再表示"
         :sync-from-local-files-detail "ローカルファイルの変更点をインポート"
+        :sync-from-local-changes-detected " 再表示は、ディスク上で変更されて Logseq 上のページと内容が変わってしまったファイルを検出し、読み込みます。実行してもよいですか?"
         :unlink "リンク解除"
         :search/publishing "検索"
         :search "検索/新規ページ名"
@@ -2936,6 +2948,11 @@
         :new-graph "新規グラフを追加"
         :graph "グラフ"
         :graph-view "グラフを見る"
+        :graph/persist "Logseq の内部状態を同期中です。少々お待ちください。"
+        :graph/persist-error "内部状態の同期に失敗しました。"
+        :graph/save "保存中..."
+        :graph/save-success "保存に成功しました"
+        :graph/save-error "保存に失敗しました"
         :cards-view "カードを見る"
         :publishing "パブリッシング"
         :export "エクスポート"
@@ -2989,6 +3006,7 @@
         :help/shortcut-page-title "キーボードショートカット"
 
         :plugin/installed "インストール済"
+        :plugin/not-installed "未インストール"
         :plugin/installing "インストール中"
         :plugin/install "インストール"
         :plugin/reload "リロード"
@@ -3022,7 +3040,7 @@
         :pdf/copy-ref "参照をコピー"
         :pdf/copy-text "テキストをコピー"
         :pdf/linked-ref "リンクありの参照元"
-        :pdf/toggle-dashed "Dashed style for area highlight"
+        :pdf/toggle-dashed "破線で Area highlight"
 
         :updater/new-version-install "新しいバージョンがダウンロードされました。"
         :updater/quit-and-install "インストールのためアプリを再起動してください。"

+ 10 - 3
src/main/frontend/extensions/latex.cljs

@@ -4,6 +4,8 @@
             [frontend.ui :as ui]
             [frontend.config :as config]
             [frontend.util :as util]
+            [frontend.handler.plugin :refer [lsp-enabled? hook-extensions-enhancer-by-type] :as plugin-handler]
+            [promesa.core :as p]
             [goog.dom :as gdom]))
 
 ;; TODO: extracted to a rum mixin
@@ -37,9 +39,14 @@
          (loader/load
           (config/asset-uri "/static/js/mhchem.min.js")
           (fn []
-            (reset! *loading? false)
-            (render! state)))))))
-  state)
+            (p/finally
+              (p/all (when-let [enhancers (and lsp-enabled? (seq (hook-extensions-enhancer-by-type :katex)))]
+                       (for [{f :enhancer} enhancers]
+                         (when (fn? f) (f js/window.katex)))))
+              (fn []
+                (reset! *loading? false)
+                (render! state))))))
+       state))))
 
 (rum/defc latex < rum/reactive
   {:did-mount (fn [state]

+ 17 - 1
src/main/frontend/handler/plugin.cljs

@@ -330,7 +330,7 @@
 
 (def *fenced-code-providers (atom #{}))
 
-(defn register_fenced_code_renderer
+(defn register-fenced-code-renderer
   [pid type {:keys [before subs render edit] :as _opts}]
   (when-let [key (and type (keyword type))]
     (register-plugin-resources pid :fenced-code-renderers
@@ -344,6 +344,22 @@
     (first (map #(state/get-plugin-resource % :fenced-code-renderers key)
                 @*fenced-code-providers))))
 
+(def *extensions-enhancer-providers (atom #{}))
+
+(defn register-extensions-enhancer
+  [pid type {:keys [enhancer] :as _opts}]
+  (when-let [key (and type (keyword type))]
+    (register-plugin-resources pid :extensions-enhancers
+       {:key key :enhancer enhancer})
+    (swap! *extensions-enhancer-providers conj pid)
+    #(swap! *extensions-enhancer-providers disj pid)))
+
+(defn hook-extensions-enhancer-by-type
+  [type]
+  (when-let [key (and type (keyword type))]
+    (map #(state/get-plugin-resource % :extensions-enhancers key)
+         @*extensions-enhancer-providers)))
+
 (defn select-a-plugin-theme
   [pid]
   (when-let [themes (get (group-by :pid (:plugin/installed-themes @state/state)) pid)]

+ 6 - 6
src/main/frontend/modules/shortcut/config.cljs

@@ -37,10 +37,10 @@
    :date-picker/next-day         {:binding "right"
                                   :fn      ui-handler/shortcut-next-day}
 
-   :date-picker/prev-week        {:binding "up"
+   :date-picker/prev-week        {:binding ["up" "ctrl+p"]
                                   :fn      ui-handler/shortcut-prev-week}
 
-   :date-picker/next-week        {:binding "down"
+   :date-picker/next-week        {:binding ["down" "ctrl+n"]
                                   :fn      ui-handler/shortcut-next-week}
 
    :pdf/previous-page            {:binding "alt+p"
@@ -52,10 +52,10 @@
    :auto-complete/complete       {:binding "enter"
                                   :fn      ui-handler/auto-complete-complete}
 
-   :auto-complete/prev           {:binding "up"
+   :auto-complete/prev           {:binding ["up" "ctrl+p"]
                                   :fn      ui-handler/auto-complete-prev}
 
-   :auto-complete/next           {:binding "down"
+   :auto-complete/next           {:binding ["down" "ctrl+n"]
                                   :fn      ui-handler/auto-complete-next}
 
    :auto-complete/shift-complete {:binding "shift+enter"
@@ -152,10 +152,10 @@
    :editor/cycle-todo              {:binding "mod+enter"
                                     :fn      editor-handler/cycle-todo!}
 
-   :editor/up                      {:binding "up"
+   :editor/up                      {:binding ["up" "ctrl+p"]
                                     :fn      (editor-handler/shortcut-up-down :up)}
 
-   :editor/down                    {:binding "down"
+   :editor/down                    {:binding ["down" "ctrl+n"]
                                     :fn      (editor-handler/shortcut-up-down :down)}
 
    :editor/left                    {:binding "left"

+ 4 - 1
src/main/frontend/modules/shortcut/dicts.cljc

@@ -706,7 +706,7 @@
              :command.ui/open-new-window              "別のウィンドウを開く"
              :command.go/search-in-page               "ページ内を検索"
              :command.ui/toggle-document-mode         "ドキュメントモードのトグル"
-             :command.ui/toggle-contents              "コンテンツのトグル"
+             :command.ui/toggle-contents              "目次のトグル"
              :command.ui/toggle-theme                 "テーマのトグル"
              :command.ui/toggle-right-sidebar         "右サイドバーのトグル"
              :command.ui/toggle-settings              "トグル設定"
@@ -726,6 +726,8 @@
              :command.editor/down                     "カーソル下移動 / 下を選択"
              :command.editor/left                     "カーソル左移動 / 左を選択"
              :command.editor/right                    "カーソル右移動 / 右を選択"
+             :command.editor/select-up                "上のコンテンツを選ぶ"
+             :command.editor/select-down              "下のコンテンツを選ぶ"
              :command.editor/backspace                "前の文字を削除"
              :command.editor/delete                   "次の文字を削除"
              :command.editor/cycle-todo               "現在の項目の TODO 状態をローテートさせる"
@@ -758,6 +760,7 @@
              :command.auto-complete/prev                      "自動補完:前の項目を選択"
              :command.auto-complete/next                      "自動補完:次の項目を選択"
              :command.auto-complete/shift-complete            "自動補完:選択した項目をサイドバーで開く"
+             :command.auto-complete/open-link                 "自動補完:選択したアイテムをブラウザで開く"
              :command.date-picker/complete                    "日付選択:選択した日で決定"
              :command.date-picker/prev-day                    "日付選択:前の日を選ぶ"
              :command.date-picker/next-day                    "日付選択:次の日を選ぶ"

+ 18 - 26
src/main/frontend/util/clock.cljs

@@ -84,30 +84,22 @@
   [body string?]
   (when-let [logbook (drawer/get-logbook body)]
     (when-let [logbook-lines (last logbook)]
-      (when-let [clock-lines (filter #(string/starts-with? % "CLOCK:") logbook-lines)]
-        (let [times (map #(string/trim (last (string/split % "=>"))) clock-lines)
-              hours-coll (map #(int (first (string/split % ":"))) times)
-              minutes-coll (map #(int (second (string/split % ":"))) times)
-              seconds-coll (map #(int (nth (string/split % ":") 2 0)) times)
-              reduced-seconds (reduce + seconds-coll)
-              reduced-minutes (reduce + minutes-coll)
-              reduced-hours (reduce + hours-coll)
-              seconds (mod reduced-seconds 60)
-              minutes (mod (+ reduced-minutes (quot reduced-seconds 60)) 60)
-              hours (+ reduced-hours
-                       (quot (+ reduced-minutes (quot reduced-seconds 60)) 60))]
+      (when-let [clock-lines (seq (filter #(string/starts-with? % "CLOCK:") logbook-lines))]
+        (let [[hours minutes seconds] (apply map + (->> clock-lines
+                                                        (map #(string/split (string/trim (last (string/split % "=>"))) ":"))
+                                                        (map #(map int %))))
+              duration (t/period :hours hours
+                                 :minutes minutes
+                                 :seconds seconds)
+              duration-in-minutes (t/in-minutes duration)
+              zero-minutes? (zero? duration-in-minutes)]
           (if string?
-            (util/format "%s%s%s"
-                         (if (>= hours 1)
-                           (when hours (str hours "h"))
-                           "")
-                         (if (zero? minutes)
-                           ""
-                           (str minutes "m"))
-                         (if (zero? seconds)
-                           ""
-                           (str seconds "s")))
-            (let [minutes (+ (* hours 60) minutes)]
-              (if (zero? minutes)
-                seconds
-                minutes))))))))
+            (if zero-minutes?
+              (str seconds "s")
+              (-> (tf/unparse-duration duration)
+                  (string/replace #"\s+days?\s+" "d")
+                  (string/replace #"\s+hours?\s+" "h")
+                  (string/replace #"\s+minutes?$" "m")))
+            (if zero-minutes?
+              seconds
+              duration-in-minutes)))))))

+ 1 - 1
src/main/frontend/version.cljs

@@ -1,3 +1,3 @@
 (ns frontend.version)
 
-(defonce version "0.6.6")
+(defonce version "0.6.7")

+ 29 - 7
src/main/logseq/api.cljs

@@ -36,6 +36,7 @@
             [promesa.core :as p]
             [reitit.frontend.easy :as rfe]
             [sci.core :as sci]
+            [frontend.version :as fv]
             [frontend.handler.shell :as shell]
             [frontend.modules.layout.core]))
 
@@ -82,6 +83,13 @@
                  (keyword %)))
          (get-in @state/state))))
 
+(defn ^:export get_app_info
+  ;; get app base info
+  []
+  (bean/->js
+    (normalize-keyword-for-json
+      {:version fv/version})))
+
 (def ^:export get_user_configs
   (fn []
     (bean/->js
@@ -543,13 +551,15 @@
 (def ^:export set_block_collapsed
   (fn [block-uuid ^js opts]
     (when-let [block (db-model/get-block-by-uuid block-uuid)]
-      (let [{:keys [flag]} (bean/->clj opts)
+      (let [opts       (bean/->clj opts)
+            opts       (if (or (string? opts) (boolean? opts)) {:flag opts} opts)
+            {:keys [flag]} opts
             block-uuid (uuid block-uuid)
-            flag (if (= "toggle" flag)
-                   (not (util/collapsed? block))
-                   (boolean flag))]
+            flag       (if (= "toggle" flag)
+                         (not (util/collapsed? block))
+                         (boolean flag))]
         (if flag (editor-handler/collapse-block! block-uuid)
-                 (editor-handler/expand-block! block-uuid))
+          (editor-handler/expand-block! block-uuid))
         nil))))
 
 (def ^:export upsert_block_property
@@ -729,6 +739,7 @@
 ;; ui
 (defn ^:export show_msg
   ([content] (show_msg content :success nil))
+  ([content status] (show_msg content status nil))
   ([content status ^js opts]
    (let [{:keys [key timeout]} (bean/->clj opts)
          hiccup? (and (string? content) (string/starts-with? (string/triml content) "[:"))
@@ -772,16 +783,27 @@
 (defn ^:export exper_register_fenced_code_renderer
   [pid type ^js opts]
   (when-let [^js _pl (plugin-handler/get-plugin-inst pid)]
-    (plugin-handler/register_fenced_code_renderer
+    (plugin-handler/register-fenced-code-renderer
       (keyword pid) type (reduce #(assoc %1 %2 (aget opts (name %2))) {}
                                  [:edit :before :subs :render]))))
 
+(defn ^:export exper_register_extensions_enhancer
+  [pid type enhancer]
+  (when-let [^js _pl (and (fn? enhancer) (plugin-handler/get-plugin-inst pid))]
+    (plugin-handler/register-extensions-enhancer
+      (keyword pid) type {:enhancer enhancer})))
+
 ;; helpers
 (defn ^:export query_element_by_id
   [id]
-  (let [^js el (gdom/getElement id)]
+  (when-let [^js el (gdom/getElement id)]
     (if el (str (.-tagName el) "#" id) false)))
 
+(defn ^:export query_element_rect
+  [selector]
+  (when-let [^js el (js/document.querySelector selector)]
+    (bean/->js (.toJSON (.getBoundingClientRect el)))))
+
 (defn ^:export set_focused_settings
   [pid]
   (when-let [plugin (state/get-plugin-by-id pid)]

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor