<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      custom:用戶自定義插件,提供開放能力

      custom 插件的功能:支持用戶 在右鍵菜單中自定義插件

      簡介

      custom 插件大量采用聲明式代碼(聲明代替代碼開發),比如:

      • 只需使用 style = () => "...",即可注冊 css。
      • 只需使用 styleTemplate = () => ({renderArg}),即可引入 css 文件,并且支持渲染模板。
      • 只需使用 html = () => "...",即可注冊 HTML 元素。
      • 只需使用 hint = () => "將當前標題的路徑復制到剪切板",即可注冊 hint。
      • 只需使用 selector = () => "...",即可注冊允許運行命令的光標位置。
      • 只需使用 hotkey = () => ["ctrl+shift+y"] ,即可注冊快捷鍵。
      • 只需使用 this.modal 函數即可自動生成自定義的模態框。
      • init、html、process、callback 等等生命周期函數。
      class fullPathCopy extends BaseCustomPlugin {
          style = () => "..."
          html = () => "..."
          hint = () => "將當前標題的路徑復制到剪切板"
          hotkey = () => ["ctrl+shift+y"]
          callback = anchorNode => {
              const modal = {
                  title: "這是模態框標題",
                  components: [
                      { label: "input的label", type: "input", value: "input的默認value", placeholder: "nput的placeholder" },
                      // password、textarea、checkbox、radio、select
                      ...
                  ]
              };
              const callback = response => console.log(response)
              this.modal(modal, callback)
          }
      }
      

      如何使用

      僅需兩步:

      1. ./plugin/custom/custom_plugin.user.toml 添加配置。
      2. ./plugin/custom/plugins 目錄下,創建和插件同名的 js 文件,在此文件中創建一個 class 繼承自 BaseCustomPlugin,并導出為 plugin

      示例一:快速開始

      您可以根據下面的步驟,先把插件跑起來。

      步驟一:在 ./plugin/custom/custom_plugin.user.toml 添加如下配置:

      [helloWorld]
      name = "你好世界"   # 右鍵菜單中展示的名稱
      enable = true     # 是否啟用此二級插件
      hide = false      # 是否在右鍵菜單中隱藏
      order = 1         # 在右鍵菜單中的出現順序(越大越排到后面,允許負數)
      
      	[helloWorld.config]
      	hotkey_string = "ctrl+alt+u"
      	console_message = "i am in process"
      	show_message = "this is hello world plugin"
      

      如果您對 TOML 不太了解,可以花三分鐘了解 TOML 教程

      步驟二:創建文件 ./plugin/custom/plugins/helloWorld.js 文件,將下面代碼保存到該文件中:

      // ./plugin/custom/plugins/helloWorld.js
      
      class helloWorld extends BaseCustomPlugin {
          hint = () => "this is hello world hint"
      
          hotkey = () => [this.config.hotkey_string]
      
          // process方法會在插件初始化時自動運行
          process = () => {
              console.log(this.config.console_message);
              console.log("[helloWorldPlugin]:", this);
          }
      
          // callback方法會在插件被調用時運行,參數anchorNode:調用此插件時,鼠標光標所在的Element
          callback = anchorNode => {
              alert(this.config.show_message);
          }
      }
      
      module.exports = { plugin: helloWorld };
      

      步驟三:驗證,完成以上步驟后,重啟 Typora。

      1. 打開【檢查元素】,發現控制臺輸出了 i am in process 和 插件對象。你可以仔細看看 this 自帶的屬性和方法。
      2. 鼠標右鍵,彈出菜單,鼠標懸停在 常用插件 -> 二級插件 -> 你好世界。發現出現了 hint,顯示 this is hello world hint。點擊 你好世界,發現彈出了提示框,顯示 this is hello world plugin
      3. 鍵入快捷鍵 ctrl+alt+u,發現彈出了同樣的提示框。

      示例二:簡易功能

      此示例來自 此 issue,簡易實現了一個輕量化的需求,旨在讓用戶了解如何實現一個插件。

      需求:md 文檔中有幾百行的復選框(任務列表)內容,一個個點選中或取消,效率太低了。希望開發全選、反選復選框功能的插件。

      步驟一:打開文件 plugin\global\settings\custom_plugin.user.toml,添加下面內容:

      [selectCheckboxes]
      name = "反選復選框"       # 右鍵菜單中展示的名稱
      enable = true           # 是否啟用此二級插件
      hide = false            # 是否在右鍵菜單中隱藏
      order = 1               # 在右鍵菜單中的出現順序(越大越排到后面,允許負數)
      
          [selectCheckboxes.config]
          select_all_hotkey = "ctrl+alt+h"      # 全選快捷鍵
          select_none_hotkey = "ctrl+alt+j"     # 取消全部選擇快捷鍵
          select_reverse_hotkey = "ctrl+alt+k"  # 反選快捷鍵
      

      步驟二:打開目錄 plugin\custom\plugins,在此目錄下創建文件 selectCheckboxes.js,寫入如下內容:

      class selectCheckboxes extends BaseCustomPlugin {
          rangeTaskListItem = fn => document.querySelectorAll('.md-task-list-item input[type="checkbox"]').forEach(fn)
      
          selectAll = input => !input.checked && input.click()
          selectNone = input => input.checked && input.click()
          selectReverse = input => input.click()
      
          process = () => {
              const { select_all_hotkey, select_none_hotkey, select_reverse_hotkey } = this.config;
              this.utils.registerHotkey([
                  { hotkey: select_all_hotkey, callback: () => this.rangeTaskListItem(this.selectAll) },
                  { hotkey: select_none_hotkey, callback: () => this.rangeTaskListItem(this.selectNone) },
                  { hotkey: select_reverse_hotkey, callback: () => this.rangeTaskListItem(this.selectReverse) },
              ])
          }
      
          callback = () => this.rangeTaskListItem(this.selectReverse)
      }
      
      module.exports = { plugin: selectCheckboxes };
      

      步驟三:重啟 Typora,創建一個帶有任務列表的 md 文件,嘗試以下操作:

      示例三:實戰

      需求如下:

      1. 在右鍵菜單中添加一個 獲取標題路徑 (類似于 messing.md\無 一級標題\開放平臺 二級標題\window_tab 三級標題),然后將其寫入剪切板。
      2. 當光標位于【正文標題】中才可使用。
      3. 快捷鍵 ctrl+shift+u

      實現:

      步驟一:修改 ./plugin/global/settings/custom_plugin.user.toml,添加配置:

      • name:(必選)右鍵菜單中展示的名稱
      • enable:(必選)是否啟用此插件
      • hide:(可選)是否在右鍵菜單中隱藏,默認為 false
      • order:(可選)在右鍵菜單中的出現順序(越大越排到后面,允許負數),默認為 1
      • config:(可選)插件自己的配置,這里的內容將被封裝為 插件類的 this.config 屬性
      # ./plugin/global/settings/custom_plugin.user.toml
      
      [myFullPathCopy]
      name = "我的復制標題路徑插件"
      enable = true
      hide = false
      order = 1
      
          # 插件配置
          [myFullPathCopy.config]
          # 快捷鍵
          hotkey = "ctrl+shift+u"
          # 如果在空白頁調用此插件,使用的文件名(因為尚不存在該文件,需要用一個默認的文件名代替)
          untitled_file_name = "untitled"
          # 跳過空白的標題
          ignore_empty_header = false
          # 標題和提示之前添加空格
          add_space = true
          # 使用絕對路徑
          full_file_path = false
      

      步驟二:在 ./plugin/custom/plugins 目錄下,創建和插件同名的 js 文件(myFullPathCopy.js),在此文件中創建一個 class 繼承自 BaseCustomPlugin,并導出為 plugin

      // ./plugin/custom/plugins/myFullPathCopy.js
      
      // 1
      class myFullPathCopy extends BaseCustomPlugin {
          // 2
          selector = () => "#write h1, h2, h3, h4, h5, h6"
          // 3
          hint = () => "將當前標題的路徑復制到剪切板"
          // 4
          init = () => {}
          // 5
          style = () => {}
          // 6
          styleTemplate = () => {}
          // 7
          html = () => {}
          // 8
          hotkey = () => [this.config.hotkey]
          // 9
          beforeProcess = async () => {}
          // 10
          process = () => {}
          // 11
          callback = anchorNode => {
              const paragraphList = ["H1", "H2", "H3", "H4", "H5", "H6"];
              const nameList = ["一級標題", "二級標題", "三級標題", "四級標題", "五級標題", "六級標題"];
              const pList = [];
              let ele = anchorNode;
      
              while (ele) {
                  const idx = paragraphList.indexOf(ele.tagName);
                  if (idx !== -1) {
                      if (pList.length === 0 || (pList[pList.length - 1].idx > idx)) {
                          pList.push({ele, idx})
                          if (pList[pList.length - 1].idx === 0) break;
                      }
                  }
                  ele = ele.previousElementSibling;
              }
      
              pList.reverse();
      
              let filePath = (this.config.full_file_path) ? this.utils.getFilePath() : File.getFileName();
              filePath = filePath || this.config.untitled_file_name;
              const result = [filePath];
              let headerIdx = 0;
              for (const p of pList) {
                  while (headerIdx < 6 && p.ele.tagName !== paragraphList[headerIdx]) {
                      if (!this.config.ignore_empty_header) {
                          const name = this.getHeaderName("無", nameList[headerIdx]);
                          result.push(name);
                      }
                      headerIdx++;
                  }
      
                  if (p.ele.tagName === paragraphList[headerIdx]) {
                      const name = this.getHeaderName(p.ele.querySelector("span").textContent, nameList[headerIdx]);
                      result.push(name);
                      headerIdx++;
                  }
              }
      
              const text = this.utils.Package.Path.join(...result);
              navigator.clipboard.writeText(text);
          }
      
          getHeaderName = (title, name) => {
              const space = this.config.add_space ? " " : "";
              return title + space + name
          }
      }
      
      // 12
      module.exports = { plugin: myFullPathCopy };
      
      // 1. 創建 class,繼承 BaseCustomPlugin 類。之后 myFullPathCopy 將自動擁有 utils、info、config 屬性。
      //    - utils:插件系統自帶的靜態工具類,其定義在 `./plugin/global/core/plugin.js/utils`。其中有三個重要的函數:utils.getPlugin(fixedName) 和 utils.getCustomPlugin(fixedName) 用于獲取已經實現的全部插件,調用其 API,具體的 API 可看 ./plugin/custom/openPlatformAPI.md 文件。utils.addEventListener(eventType, listener) 用于監聽 Typora 的生命周期事件。
      //    - info:該插件在 custom_plugin.user.toml 里的所有字段
      //    - config:等同于 info.config,即配置文件里的 config 屬性
      // 2. selector:允許運行命令的光標位置:當光標位于哪些位置時,此命令才可用。返回 null-like value 表示任何位置都可用,在這里的含義就是:只當光標位于【正文標題】時可用
      // 3. hint:當鼠標移動到右鍵菜單時的提示
      // 4. init:在這里初始化你要的變量
      // 5. style:給 Typora 插入 style 標簽。返回值為 string。若你想指定標簽的 id,也可以返回 {textID: "", text: ""}。其中 textID 為此 style 標簽的 id,text 為 style 內容。
      // 6. styleTemplate: 引入 `./plugin/global/user_styles` 目錄下和插件同名的 css 文件。詳情請參考`user_styles/請讀我.md`
      // 7. html:為 Typora 插入 HTML 標簽,返回 Element 類型或者 Element-string。
      // 8. hotkey:為 callabck 注冊快捷鍵,返回 Array<string> 類型。
      // 9. beforeProcess:最先執行的函數,在這里初始化插件需要的數據。若返回 this.utils.stopLoadPluginError,則停止加載插件
      // 10. process:在這里添加添加插件業務邏輯,比如添加 listener 和修改 Typora 的第一方函數
      // 11. callback:右鍵菜單中點擊/鍵入快捷鍵后的回調函數。anchorNode 參數: 鼠標光標所在的 Element
      // 12. export:導出名為 plugin
      

      驗證:

      打開 Typora,將光標置于正文標題出,右鍵彈出菜單,常用插件 -> 二級插件 -> 復制標題路徑,點擊。當前的標題路徑就寫入剪切板了。在目標文檔區域,粘貼,即可把標題路徑復制到相應文檔區域。

      示例四:參考

      如果您有心自己寫插件,可以參考 noImageMode 插件,僅有 30+ 行代碼。

      ./plugin/custom/plugins/noImageMode.js
      
      posted @ 2024-05-28 23:21  人下人下人下人  閱讀(163)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 无码国产偷倩在线播放| 在线观看无码av五月花| 另类专区一区二区三区| 樱花草视频www日本韩国| 免费无码va一区二区三区 | 亚洲欧洲美洲无码精品va| 国产成人午夜福利在线播放| 少妇办公室好紧好爽再浪一点| 奇米四色7777中文字幕| 亚洲护士一区二区三区| 亚洲性日韩精品一区二区| av鲁丝一区鲁丝二区鲁丝三区 | 桃花岛亚洲成在人线AV| 盘山县| 国产无遮挡又黄又爽又色| 欧美性猛交xxxx乱大交极品| 色偷偷亚洲女人天堂观看| 国内视频偷拍一区,二区,三区| 精品无码国产污污污免费| 亚洲性一交一乱一伦视频| 91精品91久久久久久| 国产精品视频一区二区不卡 | 亚洲精品香蕉一区二区| 扎囊县| 亚洲欧美日韩高清一区二区三区| 国产又色又爽又黄的视频在线| 色婷婷五月综合久久| 亚洲一区中文字幕人妻| 成人免费亚洲av在线| 玩弄放荡人妻少妇系列| 性xxxx视频播放免费| 国产免费高清69式视频在线观看| 老鸭窝| 精品午夜福利无人区乱码| 少妇xxxxx性开放| 日韩中文字幕高清有码| 国产视频有码字幕一区二区| 91网站在线看| 亚洲欧洲日产国无高清码图片| 国产亚洲精品日韩香蕉网| 成人福利一区二区视频在线 |