From 93a2d4b4da3632eb15ed7d4aa65499ab3249cdbd Mon Sep 17 00:00:00 2001 From: CodePencil Date: Fri, 16 Aug 2024 23:32:23 +0800 Subject: [PATCH 1/2] feat(format painter menu): add format painter menu --- .../basic-modules/src/constants/icon-svg.ts | 4 ++ packages/basic-modules/src/index.ts | 2 + packages/basic-modules/src/locale/en.ts | 3 + packages/basic-modules/src/locale/zh-CN.ts | 3 + .../src/modules/format-painter/helper.ts | 13 ++++ .../src/modules/format-painter/index.ts | 15 +++++ .../format-painter/menu/FormatPainter.ts | 67 +++++++++++++++++++ .../src/modules/format-painter/menu/index.ts | 13 ++++ .../src/modules/format-painter/plugin.ts | 34 ++++++++++ .../init-default-config/config/hoverbar.ts | 1 + .../src/init-default-config/config/toolbar.ts | 1 + 11 files changed, 156 insertions(+) create mode 100644 packages/basic-modules/src/modules/format-painter/helper.ts create mode 100644 packages/basic-modules/src/modules/format-painter/index.ts create mode 100644 packages/basic-modules/src/modules/format-painter/menu/FormatPainter.ts create mode 100644 packages/basic-modules/src/modules/format-painter/menu/index.ts create mode 100644 packages/basic-modules/src/modules/format-painter/plugin.ts diff --git a/packages/basic-modules/src/constants/icon-svg.ts b/packages/basic-modules/src/constants/icon-svg.ts index a228db90d..7fef44389 100644 --- a/packages/basic-modules/src/constants/icon-svg.ts +++ b/packages/basic-modules/src/constants/icon-svg.ts @@ -154,3 +154,7 @@ export const CHECK_BOX_SVG = // 回车 export const ENTER_SVG = '' + +// 格式刷 +export const FORMAT_PAINTER = + '' diff --git a/packages/basic-modules/src/index.ts b/packages/basic-modules/src/index.ts index 32d518b61..4988f543b 100644 --- a/packages/basic-modules/src/index.ts +++ b/packages/basic-modules/src/index.ts @@ -26,6 +26,7 @@ import wangEditorDividerModule from './modules/divider' import wangEditorCodeBlockModule from './modules/code-block' import wangEditorFullScreenModule from './modules/full-screen' import wangEditorCommonModule from './modules/common' +import wangEditorFormatPainterModule from './modules/format-painter' export default [ // text style @@ -54,6 +55,7 @@ export default [ wangEditorTodoModule, // command + wangEditorFormatPainterModule, wangEditorUndoRedoModule, wangEditorFullScreenModule, wangEditorCommonModule, diff --git a/packages/basic-modules/src/locale/en.ts b/packages/basic-modules/src/locale/en.ts index 311a0fd98..f2f795a0d 100644 --- a/packages/basic-modules/src/locale/en.ts +++ b/packages/basic-modules/src/locale/en.ts @@ -97,4 +97,7 @@ export default { todo: { todo: 'Todo', }, + formatPainter: { + title: 'Format Painter', + }, } diff --git a/packages/basic-modules/src/locale/zh-CN.ts b/packages/basic-modules/src/locale/zh-CN.ts index 4e860c987..6349197d8 100644 --- a/packages/basic-modules/src/locale/zh-CN.ts +++ b/packages/basic-modules/src/locale/zh-CN.ts @@ -97,4 +97,7 @@ export default { todo: { todo: '待办', }, + formatPainter: { + title: '格式刷', + }, } diff --git a/packages/basic-modules/src/modules/format-painter/helper.ts b/packages/basic-modules/src/modules/format-painter/helper.ts new file mode 100644 index 000000000..fe12933f7 --- /dev/null +++ b/packages/basic-modules/src/modules/format-painter/helper.ts @@ -0,0 +1,13 @@ +import { IDomEditor } from '@wangeditor-next/core' +import { SlateEditor } from '@wangeditor-next/editor' + +/** 清空所有标记(文本样式) */ +export function clearAllMarks(editor: IDomEditor) { + const marks = SlateEditor.marks(editor) + + if (marks) { + Object.keys(marks).forEach(mark => { + editor.removeMark(mark) + }) + } +} diff --git a/packages/basic-modules/src/modules/format-painter/index.ts b/packages/basic-modules/src/modules/format-painter/index.ts new file mode 100644 index 000000000..54a52ed34 --- /dev/null +++ b/packages/basic-modules/src/modules/format-painter/index.ts @@ -0,0 +1,15 @@ +/** + * @description format painter + * @author CodePencil + */ + +import { IModuleConf } from '@wangeditor-next/core' +import { formatPainterConf } from './menu/index' +import withFormatPainter from './plugin' + +const formatPainter: Partial = { + menus: [formatPainterConf], + editorPlugin: withFormatPainter, +} + +export default formatPainter diff --git a/packages/basic-modules/src/modules/format-painter/menu/FormatPainter.ts b/packages/basic-modules/src/modules/format-painter/menu/FormatPainter.ts new file mode 100644 index 000000000..094f33165 --- /dev/null +++ b/packages/basic-modules/src/modules/format-painter/menu/FormatPainter.ts @@ -0,0 +1,67 @@ +/** + * @description Format Painter + * @author CodePencil + */ + +import { IButtonMenu, IDomEditor, t } from '@wangeditor-next/core' +import { SlateEditor } from '@wangeditor-next/editor' +import { FORMAT_PAINTER } from '../../../constants/icon-svg' +import { Element, Text } from 'slate' +import { clearAllMarks } from '../helper' + +interface FormatPaintAttributes { + isSelect: boolean + formatStyle: Omit | null +} + +class FormatPainter implements IButtonMenu { + title = t('formatPainter.title') + iconSvg = FORMAT_PAINTER + tag = 'button' + static attrs: FormatPaintAttributes = { + isSelect: false, + formatStyle: null, + } + + getValue(editor: IDomEditor): string | boolean { + return '' + } + + isActive(editor: IDomEditor): boolean { + return FormatPainter.attrs.isSelect + } + + isDisabled(editor: IDomEditor): boolean { + return false + } + + setFormatHtml(editor: IDomEditor) { + if (!editor.getSelectionText().length) return + if (FormatPainter.attrs.formatStyle) { + clearAllMarks(editor) + for (const [key, value] of Object.entries(FormatPainter.attrs.formatStyle)) { + editor.addMark(key, value) + } + } + FormatPainter.attrs.formatStyle = {} + FormatPainter.attrs.isSelect = false + } + + exec(editor: IDomEditor, value: string | boolean) { + // 如果已经选中了格式刷则取消选中,反之保存已经选中文本的样式 + if (FormatPainter.attrs.isSelect) { + FormatPainter.attrs.isSelect = false + } else { + // 判断是否选中文本 + if (editor.getSelectionText().length) { + FormatPainter.attrs.formatStyle = SlateEditor.marks(editor) + FormatPainter.attrs.isSelect = true + } + } + + editor.blur() + editor.focus() + } +} + +export default FormatPainter diff --git a/packages/basic-modules/src/modules/format-painter/menu/index.ts b/packages/basic-modules/src/modules/format-painter/menu/index.ts new file mode 100644 index 000000000..c18644f6c --- /dev/null +++ b/packages/basic-modules/src/modules/format-painter/menu/index.ts @@ -0,0 +1,13 @@ +/** + * @description menu entry + * @author CodePencil + */ + +import FormatPainter from './FormatPainter' + +export const formatPainterConf = { + key: 'formatPainter', + factory() { + return new FormatPainter() + }, +} diff --git a/packages/basic-modules/src/modules/format-painter/plugin.ts b/packages/basic-modules/src/modules/format-painter/plugin.ts new file mode 100644 index 000000000..229f13a70 --- /dev/null +++ b/packages/basic-modules/src/modules/format-painter/plugin.ts @@ -0,0 +1,34 @@ +/** + * @description editor 插件,重写 editor API + * @author CodePencil + */ + +import { IDomEditor } from '@wangeditor-next/core' +import FormatPainter from './menu/FormatPainter' + +function withFormatPainter(editor: T): T { + const formatPainter = new FormatPainter() + + const { onChange } = editor + const newEditor = editor + + const handleMouseUp = () => { + formatPainter.setFormatHtml(newEditor) + document.removeEventListener('mouseup', handleMouseUp) + } + + newEditor.onChange = () => { + onChange() + + if (FormatPainter.attrs.isSelect) { + // 避免重复绑定 mouseup 事件 + document.removeEventListener('mouseup', handleMouseUp) + document.addEventListener('mouseup', handleMouseUp) + } + } + + // 返回 editor ,重要! + return newEditor +} + +export default withFormatPainter diff --git a/packages/editor/src/init-default-config/config/hoverbar.ts b/packages/editor/src/init-default-config/config/hoverbar.ts index 718318e57..ff9c77d76 100644 --- a/packages/editor/src/init-default-config/config/hoverbar.ts +++ b/packages/editor/src/init-default-config/config/hoverbar.ts @@ -55,6 +55,7 @@ export function genDefaultHoverbarKeys() { // 也可以自定义 match 来匹配元素,此时 key 就随意了 text: { menuKeys: [ + 'formatPainter', 'headerSelect', 'insertLink', 'bulletedList', diff --git a/packages/editor/src/init-default-config/config/toolbar.ts b/packages/editor/src/init-default-config/config/toolbar.ts index 27a1d7a1a..1b3b9e593 100644 --- a/packages/editor/src/init-default-config/config/toolbar.ts +++ b/packages/editor/src/init-default-config/config/toolbar.ts @@ -14,6 +14,7 @@ import { export function genDefaultToolbarKeys() { return [ + 'formatPainter', 'headerSelect', // 'header1', // 'header2', From a6acb5fe2900f44c4b887520100e4c7002c0d545 Mon Sep 17 00:00:00 2001 From: CodePencil Date: Sun, 18 Aug 2024 10:27:23 +0800 Subject: [PATCH 2/2] refactor(format painter menu): adjusted format painter menu display order --- .../src/modules/format-painter/menu/FormatPainter.ts | 2 +- packages/editor/src/init-default-config/config/toolbar.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/basic-modules/src/modules/format-painter/menu/FormatPainter.ts b/packages/basic-modules/src/modules/format-painter/menu/FormatPainter.ts index 094f33165..9723dd3a1 100644 --- a/packages/basic-modules/src/modules/format-painter/menu/FormatPainter.ts +++ b/packages/basic-modules/src/modules/format-painter/menu/FormatPainter.ts @@ -6,7 +6,7 @@ import { IButtonMenu, IDomEditor, t } from '@wangeditor-next/core' import { SlateEditor } from '@wangeditor-next/editor' import { FORMAT_PAINTER } from '../../../constants/icon-svg' -import { Element, Text } from 'slate' +import { Text } from 'slate' import { clearAllMarks } from '../helper' interface FormatPaintAttributes { diff --git a/packages/editor/src/init-default-config/config/toolbar.ts b/packages/editor/src/init-default-config/config/toolbar.ts index 1b3b9e593..bac3479b4 100644 --- a/packages/editor/src/init-default-config/config/toolbar.ts +++ b/packages/editor/src/init-default-config/config/toolbar.ts @@ -14,7 +14,6 @@ import { export function genDefaultToolbarKeys() { return [ - 'formatPainter', 'headerSelect', // 'header1', // 'header2', @@ -83,6 +82,7 @@ export function genDefaultToolbarKeys() { 'undo', 'redo', '|', + 'formatPainter', 'fullScreen', ] }