Browse Source

:art: https://github.com/Vanessa219/vditor/issues/1849

Vanessa 1 month ago
parent
commit
484254df06
5 changed files with 40 additions and 4 deletions
  1. 2 0
      CHANGELOG.md
  2. 1 0
      README.md
  3. 1 0
      README_en_US.md
  4. 19 4
      src/ts/wysiwyg/highlightToolbarWYSIWYG.ts
  5. 17 0
      types/index.d.ts

+ 2 - 0
CHANGELOG.md

@@ -3,6 +3,7 @@
 ### 升级
 
 * 3.11
+  * 添加 options.customWysiwygToolbar
   * 添加 options.upload.base64ToLink
   * 添加 options.upload.xhr
   * 添加 options.upload.cancel
@@ -29,6 +30,7 @@
  
 ### v3.11.2 / 2025-07
 
+* [添加 `customWysiwygToolbar` 方法对 wysiwyg 模式下的工具栏进行自定义](https://github.com/Vanessa219/vditor/issues/1849) `引入特性`
 * [特定情况下工具栏图标无法正常加载](https://github.com/Vanessa219/vditor/issues/1846) `兼容性`
 * [改进粘贴 markdown 导致的 XSS](https://github.com/Vanessa219/vditor/issues/1827) `改进功能`
 * [支持西班牙语和越南语](https://github.com/Vanessa219/vditor/pull/1828) `引入特性`

+ 1 - 0
README.md

@@ -219,6 +219,7 @@ Markdown 输出的 HTML 所展现的外观。内置 ant-design, light,dark,w
 | theme | 主题:classic, dark | 'classic' |
 | icon | 图标风格:ant, material | 'ant' |
 | customRenders: {language: string, render: (element: HTMLElement, vditor: IVditor) => void}[] | 自定义渲染器 | [] |
+| customWysiwygToolbar(type: TWYSISYGToolbar, element: HTMLElement): void | 对 wysiwyg 模式下的工具栏进行自定义 | - |
 
 #### options.toolbar
 

+ 1 - 0
README_en_US.md

@@ -195,6 +195,7 @@ Can be filled with element `id` or element itself` HTMLElement`
 | theme | Theme: classic, dark | 'classic' |
 | icon | icon theme: ant, material | 'ant' |
 | customRenders: {language: string, render: (element: HTMLElement, vditor: IVditor) => void}[] | Custom render | [] |
+| customWysiwygToolbar(type: TWYSISYGToolbar, element: HTMLElement): void | Customizing the toolbar in wysiwyg mode | - |
 
 #### options.toolbar
 

+ 19 - 4
src/ts/wysiwyg/highlightToolbarWYSIWYG.ts

@@ -65,6 +65,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
         if (footnotesElement) {
             vditor.wysiwyg.popover.innerHTML = "";
             genClose(footnotesElement, vditor);
+            customWysiwygToolbar(vditor, "footnotes-block")
             setPopoverPosition(vditor, footnotesElement);
             return;
         }
@@ -195,6 +196,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
         if (tocElement) {
             vditor.wysiwyg.popover.innerHTML = "";
             genClose(tocElement, vditor);
+            customWysiwygToolbar(vditor, "vditor-toc")
             setPopoverPosition(vditor, tocElement);
             return;
         }
@@ -206,6 +208,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
             genUp(range, blockquoteElement, vditor);
             genDown(range, blockquoteElement, vditor);
             genClose(blockquoteElement, vditor);
+            customWysiwygToolbar(vditor, "blockquote")
             setPopoverPosition(vditor, blockquoteElement);
         }
 
@@ -216,7 +219,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
             genUp(range, liElement, vditor);
             genDown(range, liElement, vditor);
             genClose(liElement, vditor);
-
+            customWysiwygToolbar(vditor, "li")
             setPopoverPosition(vditor, liElement);
         }
 
@@ -549,6 +552,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
             vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap);
             vditor.wysiwyg.popover.insertAdjacentHTML("beforeend", " x ");
             vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input2Wrap);
+            customWysiwygToolbar(vditor, "table")
             setPopoverPosition(vditor, tableElement);
         }
 
@@ -596,6 +600,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
 
             genClose(footnotesRefElement, vditor);
             vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap);
+            customWysiwygToolbar(vditor, "footnotes-ref")
             setPopoverPosition(vditor, footnotesRefElement);
         }
 
@@ -684,7 +689,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
                     }
                     const matchLangData: IHintData[] = [];
                     const key = language.value.substring(0, language.selectionStart);
-                    (vditor.options.preview.hljs.langs ||  Constants.ALIAS_CODE_LANGUAGES.concat((window.hljs?.listLanguages() ?? []).sort())).forEach((keyName) => {
+                    (vditor.options.preview.hljs.langs || Constants.ALIAS_CODE_LANGUAGES.concat((window.hljs?.listLanguages() ?? []).sort())).forEach((keyName) => {
                         if (keyName.indexOf(key.toLowerCase()) > -1) {
                             matchLangData.push({
                                 html: keyName,
@@ -696,6 +701,9 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
                     event.preventDefault();
                 };
                 vditor.wysiwyg.popover.insertAdjacentElement("beforeend", languageWrap);
+                customWysiwygToolbar(vditor, "code-block")
+            } else {
+                customWysiwygToolbar(vditor, "block")
             }
             setPopoverPosition(vditor, blockRenderElement);
         } else {
@@ -735,6 +743,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
             genDown(range, headingElement, vditor);
             genClose(headingElement, vditor);
             vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap);
+            customWysiwygToolbar(vditor, "heading")
             setPopoverPosition(vditor, headingElement);
         }
 
@@ -763,7 +772,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
                 genUp(range, blockElement, vditor);
                 genDown(range, blockElement, vditor);
                 genClose(blockElement, vditor);
-
+                customWysiwygToolbar(vditor, "block")
                 setPopoverPosition(vditor, blockElement);
             } else {
                 vditor.wysiwyg.popover.style.display = "none";
@@ -864,6 +873,7 @@ export const genLinkRefPopover = (vditor: IVditor, linkRefElement: HTMLElement,
     genClose(linkRefElement, vditor);
     vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap);
     vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input1Wrap);
+    customWysiwygToolbar(vditor, "link-ref")
     setPopoverPosition(vditor, linkRefElement);
 };
 
@@ -1058,6 +1068,7 @@ export const genAPopover = (vditor: IVditor, aElement: HTMLElement, range: Range
     vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap);
     vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input1Wrap);
     vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input2Wrap);
+    customWysiwygToolbar(vditor, "a")
     setPopoverPosition(vditor, aElement);
 };
 
@@ -1122,7 +1133,7 @@ export const genImagePopover = (event: Event, vditor: IVditor) => {
     vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap);
     vditor.wysiwyg.popover.insertAdjacentElement("beforeend", altWrap);
     vditor.wysiwyg.popover.insertAdjacentElement("beforeend", titleWrap);
-
+    customWysiwygToolbar(vditor, "image")
     setPopoverPosition(vditor, imgElement);
 };
 
@@ -1137,3 +1148,7 @@ const focusToElement = (event: KeyboardEvent, range: Range) => {
         return true;
     }
 };
+
+const customWysiwygToolbar = (vditor: IVditor, type: TWYSISYGToolbar) => {
+    vditor.options.customWysiwygToolbar(type, vditor.wysiwyg.popover);
+};

+ 17 - 0
types/index.d.ts

@@ -2,6 +2,20 @@ declare module "*.svg";
 
 declare module "*.png";
 
+type TWYSISYGToolbar =
+    "table"
+    | "code-block"
+    | "heading"
+    | "link-ref"
+    | "a"
+    | "image"
+    | "footnotes-block"
+    | "footnotes-ref"
+    | "vditor-toc"
+    | "blockquote"
+    | "li"
+    | "block"
+
 interface Window {
     VditorI18n: ITips;
     hljs: {
@@ -796,6 +810,9 @@ interface IOptions {
 
     /** 编辑器中未选中文字后触发 */
     unSelect?(): void;
+
+    /** 对 wysiwyg 模式下的工具栏进行自定义 */
+    customWysiwygToolbar?(type: TWYSISYGToolbar, element: HTMLElement): void
 }
 
 interface IEChart {