diff --git a/packages/basic-modules/src/modules/header/helper.ts b/packages/basic-modules/src/modules/header/helper.ts new file mode 100644 index 000000000..5337dece9 --- /dev/null +++ b/packages/basic-modules/src/modules/header/helper.ts @@ -0,0 +1,65 @@ +/** + * @description header helper + * @author wangfupeng + */ + +import { Editor, Transforms } from 'slate' +import { IDomEditor, DomEditor } from '@wangeditor/core' + +/** + * 获取 node type('header1' 'header2' 等),未匹配则返回 'paragraph' + */ +export function getHeaderType(editor: IDomEditor): string { + const [match] = Editor.nodes(editor, { + match: n => { + const type = DomEditor.getNodeType(n) + return type.startsWith('header') // 匹配 node.type 是 header 开头的 node + }, + universal: true, + }) + + // 未匹配到 header + if (match == null) return 'paragraph' + + // 匹配到 header + const [n] = match + + return DomEditor.getNodeType(n) +} + +export function isMenuDisabled(editor: IDomEditor): boolean { + if (editor.selection == null) return true + + const [nodeEntry] = Editor.nodes(editor, { + match: n => { + const type = DomEditor.getNodeType(n) + + // 只可用于 p 和 header + if (type === 'paragraph') return true + if (type.startsWith('header')) return true + + return false + }, + universal: true, + mode: 'highest', // 匹配最高层级 + }) + + // 匹配到 p header ,不禁用 + if (nodeEntry) { + return false + } + // 未匹配到 p header ,则禁用 + return true +} + +/** + * 设置 node type ('header1' 'header2' 'paragraph' 等) + */ +export function setHeaderType(editor: IDomEditor, type: string) { + if (!type) return + + // 执行命令 + Transforms.setNodes(editor, { + type: type, + }) +} diff --git a/packages/basic-modules/src/modules/header/index.ts b/packages/basic-modules/src/modules/header/index.ts index 6f2be2637..4545883d1 100644 --- a/packages/basic-modules/src/modules/header/index.ts +++ b/packages/basic-modules/src/modules/header/index.ts @@ -5,14 +5,24 @@ import { IModuleConf } from '@wangeditor/core' import { renderHeader1Conf, renderHeader2Conf, renderHeader3Conf } from './render-elem' -import { headerMenuConf } from './menu/index' +import { + HeaderSelectMenuConf, + Header1ButtonMenuConf, + Header2ButtonMenuConf, + Header3ButtonMenuConf, +} from './menu/index' import { header1ToHtmlConf, header2ToHtmlConf, header3ToHtmlConf } from './elem-to-html' import withHeader from './plugin' const bold: Partial = { renderElems: [renderHeader1Conf, renderHeader2Conf, renderHeader3Conf], elemsToHtml: [header1ToHtmlConf, header2ToHtmlConf, header3ToHtmlConf], - menus: [headerMenuConf], + menus: [ + HeaderSelectMenuConf, + Header1ButtonMenuConf, + Header2ButtonMenuConf, + Header3ButtonMenuConf, + ], editorPlugin: withHeader, } diff --git a/packages/basic-modules/src/modules/header/menu/Header1ButtonMenu.ts b/packages/basic-modules/src/modules/header/menu/Header1ButtonMenu.ts new file mode 100644 index 000000000..89426b5fc --- /dev/null +++ b/packages/basic-modules/src/modules/header/menu/Header1ButtonMenu.ts @@ -0,0 +1,13 @@ +/** + * @description header1 button menu + * @author wangfupeng + */ + +import HeaderButtonMenuBase from './HeaderButtonMenuBase' + +class Header1ButtonMenu extends HeaderButtonMenuBase { + title = 'H1' + type = 'header1' +} + +export default Header1ButtonMenu diff --git a/packages/basic-modules/src/modules/header/menu/Header2ButtonMenu.ts b/packages/basic-modules/src/modules/header/menu/Header2ButtonMenu.ts new file mode 100644 index 000000000..28fd480f1 --- /dev/null +++ b/packages/basic-modules/src/modules/header/menu/Header2ButtonMenu.ts @@ -0,0 +1,13 @@ +/** + * @description header2 button menu + * @author wangfupeng + */ + +import HeaderButtonMenuBase from './HeaderButtonMenuBase' + +class Header2ButtonMenu extends HeaderButtonMenuBase { + title = 'H2' + type = 'header2' +} + +export default Header2ButtonMenu diff --git a/packages/basic-modules/src/modules/header/menu/Header3ButtonMenu.ts b/packages/basic-modules/src/modules/header/menu/Header3ButtonMenu.ts new file mode 100644 index 000000000..c8915421f --- /dev/null +++ b/packages/basic-modules/src/modules/header/menu/Header3ButtonMenu.ts @@ -0,0 +1,13 @@ +/** + * @description header3 button menu + * @author wangfupeng + */ + +import HeaderButtonMenuBase from './HeaderButtonMenuBase' + +class Header3ButtonMenu extends HeaderButtonMenuBase { + title = 'H3' + type = 'header3' +} + +export default Header3ButtonMenu diff --git a/packages/basic-modules/src/modules/header/menu/HeaderButtonMenuBase.ts b/packages/basic-modules/src/modules/header/menu/HeaderButtonMenuBase.ts new file mode 100644 index 000000000..76ae63af5 --- /dev/null +++ b/packages/basic-modules/src/modules/header/menu/HeaderButtonMenuBase.ts @@ -0,0 +1,45 @@ +/** + * @description button menu base + * @author wangfupeng + */ + +import { IButtonMenu, IDomEditor } from '@wangeditor/core' +import { getHeaderType, isMenuDisabled, setHeaderType } from '../helper' + +abstract class HeaderButtonMenuBase implements IButtonMenu { + abstract readonly title: string + abstract readonly type: string // 'header1' 'header2' 等 + readonly tag = 'button' + + /** + * 获取选中节点的 node.type + * @param editor editor + */ + getValue(editor: IDomEditor): string | boolean { + return getHeaderType(editor) + } + + isActive(editor: IDomEditor): boolean { + return this.getValue(editor) === this.type + } + + isDisabled(editor: IDomEditor): boolean { + return isMenuDisabled(editor) + } + + exec(editor: IDomEditor, value: string | boolean) { + const { type } = this + let newType + if (value === type) { + // 选中的 node.type 和当前 type 一样,则取消 + newType = 'paragraph' + } else { + // 否则,则设置 + newType = type + } + + setHeaderType(editor, newType) + } +} + +export default HeaderButtonMenuBase diff --git a/packages/basic-modules/src/modules/header/menu/HeaderMenu.ts b/packages/basic-modules/src/modules/header/menu/HeaderSelectMenu.ts similarity index 55% rename from packages/basic-modules/src/modules/header/menu/HeaderMenu.ts rename to packages/basic-modules/src/modules/header/menu/HeaderSelectMenu.ts index 566be37d9..49f80bcbb 100644 --- a/packages/basic-modules/src/modules/header/menu/HeaderMenu.ts +++ b/packages/basic-modules/src/modules/header/menu/HeaderSelectMenu.ts @@ -3,11 +3,11 @@ * @author wangfupeng */ -import { Editor, Transforms } from 'slate' -import { ISelectMenu, IDomEditor, IOption, DomEditor } from '@wangeditor/core' +import { ISelectMenu, IDomEditor, IOption } from '@wangeditor/core' import { HEADER_SVG } from '../../../constants/icon-svg' +import { getHeaderType, isMenuDisabled, setHeaderType } from '../helper' -class HeaderMenu implements ISelectMenu { +class HeaderSelectMenu implements ISelectMenu { readonly title = '标题' readonly iconSvg = HEADER_SVG readonly tag = 'select' @@ -54,49 +54,15 @@ class HeaderMenu implements ISelectMenu { } /** - * 获取 node.type + * 获取选中节点的 node.type * @param editor editor */ getValue(editor: IDomEditor): string | boolean { - const [match] = Editor.nodes(editor, { - match: n => { - const type = DomEditor.getNodeType(n) - return type.startsWith('header') // 匹配 node.type 是 header 开头的 node - }, - universal: true, - }) - - // 未匹配到 header - if (match == null) return 'paragraph' - - // 匹配到 header - const [n] = match - - return DomEditor.getNodeType(n) + return getHeaderType(editor) } - isDisabled(editor: IDomEditor): boolean { - if (editor.selection == null) return true - - const [nodeEntry] = Editor.nodes(editor, { - match: n => { - const type = DomEditor.getNodeType(n) - // 只可用于 p 和 header - if (type === 'paragraph') return true - if (type.startsWith('header')) return true - - return false - }, - universal: true, - mode: 'highest', // 匹配最高层级 - }) - - // 匹配到 p header ,不禁用 - if (nodeEntry) { - return false - } - // 未匹配到 p header ,则禁用 - return true + isDisabled(editor: IDomEditor): boolean { + return isMenuDisabled(editor) } /** @@ -105,13 +71,9 @@ class HeaderMenu implements ISelectMenu { * @param value node.type */ exec(editor: IDomEditor, value: string | boolean) { - if (!value) return - - // 执行命令 - Transforms.setNodes(editor, { - type: value.toString(), - }) + //【注意】value 是 select change 时获取的,并不是 this.getValue 的值 + setHeaderType(editor, value.toString()) } } -export default HeaderMenu +export default HeaderSelectMenu diff --git a/packages/basic-modules/src/modules/header/menu/index.ts b/packages/basic-modules/src/modules/header/menu/index.ts index 04c72971c..2b25ec1d7 100644 --- a/packages/basic-modules/src/modules/header/menu/index.ts +++ b/packages/basic-modules/src/modules/header/menu/index.ts @@ -3,11 +3,35 @@ * @author wangfupeng */ -import HeaderMenu from './HeaderMenu' +import HeaderSelectMenu from './HeaderSelectMenu' +import Header1ButtonMenu from './Header1ButtonMenu' +import Header2ButtonMenu from './Header2ButtonMenu' +import Header3ButtonMenu from './Header3ButtonMenu' -export const headerMenuConf = { - key: 'header', +export const HeaderSelectMenuConf = { + key: 'headerSelect', factory() { - return new HeaderMenu() + return new HeaderSelectMenu() + }, +} + +export const Header1ButtonMenuConf = { + key: 'header1', + factory() { + return new Header1ButtonMenu() + }, +} + +export const Header2ButtonMenuConf = { + key: 'header2', + factory() { + return new Header2ButtonMenu() + }, +} + +export const Header3ButtonMenuConf = { + key: 'header3', + factory() { + return new Header3ButtonMenu() }, } diff --git a/packages/editor/src/editor-config/hoverbar.ts b/packages/editor/src/editor-config/hoverbar.ts index c21ffa53a..1f049d72c 100644 --- a/packages/editor/src/editor-config/hoverbar.ts +++ b/packages/editor/src/editor-config/hoverbar.ts @@ -19,12 +19,26 @@ export function genHoverbarKeys() { let parentType = '' const [parent] = Editor.parent(editor, selection, { edge: 'start' }) if (Element.isElement(parent)) parentType = parent.type - if (parentType === 'code' || parentType === 'pre') return false // code-block 不允许 + if (parentType === 'code' || parentType === 'pre' || parentType.startsWith('header')) { + // code-block header 禁止 + return false + } if (Text.isText(n)) return true // 匹配 text node return false }, - menuKeys: ['header', '|', 'bold', 'underline', 'through', '|', 'color'], + menuKeys: [ + 'headerSelect', + '|', + 'bold', + 'underline', + 'through', + '|', + 'color', + 'bgColor', + '|', + 'insertLink', + ], }, { desc: '选中链接 selected link', diff --git a/packages/editor/src/editor-config/toolbar.ts b/packages/editor/src/editor-config/toolbar.ts index de319a2d4..20ff8b5e7 100644 --- a/packages/editor/src/editor-config/toolbar.ts +++ b/packages/editor/src/editor-config/toolbar.ts @@ -7,7 +7,10 @@ import { INDENT_RIGHT_SVG, JUSTIFY_LEFT_SVG, IMAGE_SVG, MORE_SVG } from '../cons export function genToolbarKeys() { return [ - 'header', + 'headerSelect', + // 'header1', + // 'header2', + // 'header3', 'blockquote', '|', 'bold',