diff --git a/src/menus/lineHeight/index.ts b/src/menus/lineHeight/index.ts index 8e780112e..6a3c1da42 100644 --- a/src/menus/lineHeight/index.ts +++ b/src/menus/lineHeight/index.ts @@ -9,7 +9,6 @@ import $, { DomElement } from '../../utils/dom-core' import Editor from '../../editor/index' import { MenuActive } from '../menu-constructors/Menu' import lineHeightList from './lineHeightList' -import { UA } from '../../utils/util' class LineHeight extends DropListMenu implements MenuActive { constructor(editor: Editor) { @@ -39,163 +38,81 @@ class LineHeight extends DropListMenu implements MenuActive { * @param value value */ public command(value: string): void { - let selection = window.getSelection ? window.getSelection() : document.getSelection() - //允许设置dom - const allowArray: string[] = ['P'] const editor = this.editor - let st: string = '' - //恢复焦点 + + //重置选区 editor.selection.restoreSelection() - const $selectionElem = $(editor.selection.getSelectionContainerElem()) - if (!$selectionElem?.length) return + // 获取选区的祖先元素 + const $containerElem = $(editor.selection.getSelectionContainerElem()) - const $selectionAll = $(editor.selection.getSelectionContainerElem()) - // let dom:HTMLElement= $selectionElem.elems[0] - let dom: HTMLElement = $(editor.selection.getSelectionStartElem()).elems[0] - //获取元素的style - let style: string | null = '' - let styleList: string[] = [] - //点击默认的时候删除line-height属性 并重新设置 style - let styleStr: string = '' + if (!$containerElem.elems.length) return //选中多行操作 - if ($selectionElem && editor.$textElem.equal($selectionElem)) { - let isIE = UA.isIE() - //获取range 开头结束的dom在 祖父元素的下标 - let indexStore: Array = [] - let arrayDom_a: Array = [] - let arrayDom_b: Array = [] + if ($containerElem && editor.$textElem.equal($containerElem)) { + // 标识是否可以设置行高的样式 + let setStyleLock: boolean = false + //获取range 开头结束的dom - const StartElem: DomElement = $(editor.selection.getSelectionStartElem()) - const EndElem: DomElement = $(editor.selection.getSelectionEndElem()) - const childList: NodeListOf | undefined = editor.selection.getRange() - ?.commonAncestorContainer.childNodes - arrayDom_a.push(this.getDom(StartElem.elems[0])) - childList?.forEach((item, index) => { - if (item === this.getDom(StartElem.elems[0])) { - indexStore.push(index) - } - if (item === this.getDom(EndElem.elems[0])) { - indexStore.push(index) - } - }) - //遍历 获取头尾之间的dom元素 - let i = 0 - let d: HTMLElement - arrayDom_b.push(this.getDom(StartElem.elems[0])) - while (arrayDom_a[i] !== this.getDom(EndElem.elems[0])) { - d = $(arrayDom_a[i].nextElementSibling).elems[0] - if (allowArray.indexOf($(d).getNodeName()) !== -1) { - arrayDom_b.push(d) - arrayDom_a.push(d) - } else { - arrayDom_a.push(d) - } - i++ - } + const selectionStartElem: HTMLElement = $(editor.selection.getSelectionStartElem()) + .elems[0] + const SelectionEndElem: HTMLElement = $(editor.selection.getSelectionEndElem()).elems[0] - //设置段落选取 全选 - if ($(arrayDom_a[0]).getNodeName() !== 'P') { - i = 0 - //遍历集合得到第一个p标签的下标 - for (var k = 0; k < arrayDom_a.length; k++) { - if ($(arrayDom_a[k]).getNodeName() === 'P') { - i = k - break - } - } - //i===0 说明选区中没有p段落 - if (i === 0) { - return - } - let _i = 0 - while (_i !== i) { - arrayDom_a.shift() - _i++ + // 获取选区中,在contenteditable下的直接父元素 + const StartElemWrap: HTMLElement = this.getDom(selectionStartElem) + const EndElemWrap: HTMLElement = this.getDom(SelectionEndElem) + + const containerElemChildren = $containerElem.elems[0].children + + for (let i = 0; i < containerElemChildren.length; i++) { + const item: HTMLElement = containerElemChildren[i] as HTMLElement + + // 目前只支持p 段落标签设置行高 + if ($(item).getNodeName() !== 'P') { + continue } - } - //设置替换的选区 - this.setRange(arrayDom_a[0], arrayDom_a[arrayDom_a.length - 1]) - //生成innerHtml html字符串 - arrayDom_a.forEach(item => { - style = item.getAttribute('style') - styleList = style ? style.split(';') : [] - styleStr = this.styleProcessing(styleList) - - if ($(item).getNodeName() === 'P') { - //判断是否 点击默认 - if (value) { - styleStr += value ? `line-height:${value};` : '' - } + + if (item === StartElemWrap) { + setStyleLock = true } - if (!isIE) { - st += `<${$(item).getNodeName().toLowerCase()} style="${styleStr}">${ - item.innerHTML - }` - } else { + // 证明在区间节点里 + if (setStyleLock) { $(item).css('line-height', value) - } - }) - if (st) { - this.action(st, editor) + if (item === EndElemWrap) { + setStyleLock = false + + // 当设置完选择的EndElemWrap时,就可以退出 + return + } + } } - //恢复已选择的选区 - dom = $selectionAll.elems[0] - this.setRange(dom.children[indexStore[0]], dom.children[indexStore[1]]) + //重新设置选区 + editor.selection.createRangeByElems(selectionStartElem, SelectionEndElem) + return } - //遍历dom 获取祖父元素 直到contenteditable属性的div标签 - dom = this.getDom(dom) + // 单行操作 + // 选中区间的dom元素 + const selectElem = $containerElem.elems[0] - //校验允许lineheight设置标签 - if (allowArray.indexOf($(dom).getNodeName()) === -1) { - return - } - style = dom.getAttribute('style') - styleList = style ? style.split(';') : [] - //全选 dom下所有的内容 - selection?.selectAllChildren(dom) - //保存range - editor.selection.saveRange() - //判断是否存在value 默认 移除line-height - if (!value) { - if (style) { - styleStr = this.styleProcessing(styleList) - //避免没有其它属性 只留下 ‘style’ 减少代码 - if (styleStr === '') { - st = `<${$(dom).getNodeName().toLowerCase()}>${dom.innerHTML}` - } else { - st = `<${$(dom).getNodeName().toLowerCase()} style="${styleStr}">${ - dom.innerHTML - }` - } - this.action(st, editor) - } + // 获取选区中,在contenteditable下的直接父元素 + const selectElemWrapdom = this.getDom(selectElem) + + // 目前只支持p 段落标签设置行高 + if ($(selectElemWrapdom).getNodeName() !== 'P') { return } - if (style) { - //存在style 检索其它style属性 - styleStr = this.styleProcessing(styleList) + `line-height:${value};` - } else { - styleStr = `line-height:${value};` - } - st = `<${$(dom).getNodeName().toLowerCase()} style="${styleStr}">${dom.innerHTML}` - //防止BLOCKQUOTE叠加 or IE下导致P嵌套出现误删 - if ($(dom).getNodeName() === 'BLOCKQUOTE' || UA.isIE()) { - $(dom).css('line-height', value) - } else { - this.action(st, editor) - } + $(selectElemWrapdom).css('line-height', value) + + //重新设置选区 + editor.selection.createRangeByElems(selectElemWrapdom, selectElemWrapdom) + + return } /** @@ -220,16 +137,10 @@ class LineHeight extends DropListMenu implements MenuActive { return DOM } - /** - * 执行 document.execCommand - * - */ - public action(html_str: string, editor: Editor): void { - editor.cmd.do('insertHTML', html_str) - } - /** * style 处理 + * + * 废弃的方法 */ public styleProcessing(styleList: Array): string { let styleStr = '' @@ -243,6 +154,8 @@ class LineHeight extends DropListMenu implements MenuActive { /** * 段落全选 比如:避免11变成111 + * + * 废弃的方法 */ public setRange(startDom: Node, endDom: Node): void { const editor = this.editor diff --git a/test/unit/menus/lineHeight.test.ts b/test/unit/menus/lineHeight.test.ts index 20365d072..679f5e4f1 100644 --- a/test/unit/menus/lineHeight.test.ts +++ b/test/unit/menus/lineHeight.test.ts @@ -32,8 +32,13 @@ describe('LineHeight menu', () => { mockCmdFn(document) const cmdVal = '2' lineHeightMenu.command(cmdVal) - // 此处触发 editor.cmd.do('insertHTML', xx),可以被 jest 成功执行,具体参考 mockCmdFn 的描述 - expect(editor.$textElem.elems[0]).toContainHTML('


') + + // 空状态下,设置行高 + expect( + editor.$textElem.elems[0].innerHTML.indexOf( + '


' + ) + ).toBeGreaterThanOrEqual(0) }) test('lineHeight 菜单:选择多行增加行高', () => { @@ -99,7 +104,8 @@ describe('LineHeight menu', () => { const cmdVal = '2' lineHeightMenu.command(cmdVal) - // 此处触发 editor.cmd.do('insertHTML', xx),可以被 jest 成功执行,具体参考 mockCmdFn 的描述 + + // 设置多行时,只针对p, 段落标签其设置 expect( editor.$textElem.elems[0].innerHTML.indexOf( '
345
234123
' @@ -110,15 +116,16 @@ describe('LineHeight menu', () => { test('lineHeight 菜单:增加行高, 如果不传value值,则设为默认行高,并且不设置 line-height 样式', () => { mockCmdFn(document) - editor.txt.html('

123

') + editor.txt.html('

123

') const [startNode] = Array.from(editor.$textElem.elems[0].childNodes) lineHeightMenu.setRange(startNode, startNode) lineHeightMenu.command('') // 此处触发 editor.cmd.do('insertHTML', xx),可以被 jest 成功执行,具体参考 mockCmdFn 的描述 + expect( - editor.$textElem.elems[0].innerHTML.indexOf('

123

') + editor.$textElem.elems[0].innerHTML.indexOf('

123

') ).toBeGreaterThanOrEqual(0) }) @@ -132,9 +139,10 @@ describe('LineHeight menu', () => { lineHeightMenu.command('2') // 此处触发 editor.cmd.do('insertHTML', xx),可以被 jest 成功执行,具体参考 mockCmdFn 的描述 + expect( editor.$textElem.elems[0].innerHTML.indexOf( - '

123

' + '

123

' ) ).toBeGreaterThanOrEqual(0) })