diff --git a/src/menus/link/bind-event/tooltip-event.ts b/src/menus/link/bind-event/tooltip-event.ts index 6bcc62492..c3648bfcc 100644 --- a/src/menus/link/bind-event/tooltip-event.ts +++ b/src/menus/link/bind-event/tooltip-event.ts @@ -6,6 +6,7 @@ import $, { DomElement } from '../../../utils/dom-core' import Tooltip, { TooltipConfType } from '../../menu-constructors/Tooltip' import Editor from '../../../editor/index' +import { EXTRA_TAG } from '../is-active' /** * 生成 Tooltip 的显示隐藏函数 @@ -50,9 +51,26 @@ function createShowHideFn(editor: Editor) { style=${$selectIMG?.getAttribute('style')}>` ) } else { - // 用文字,替换链接 - const selectionText = $link.text() - editor.cmd.do('insertHTML', '' + selectionText + '') + /** + * 替换链接 + * + * 两种情况 + * 1. a标签里面可能会含有其他元素如:b, i等,要保留: 先添加链接后加粗 + * 2. 特殊标签里嵌套a,也要保留特殊标签: 先加粗后添加链接 + */ + const linkElem = $link.elems[0] + + // a标签里面的html结构 + const selectionContent = linkElem.innerHTML + + // a标签的父元素 + const linkParentNode = linkElem.parentElement + + if (linkParentNode && EXTRA_TAG.includes(linkParentNode.nodeName)) { + linkParentNode.innerHTML = selectionContent + } else { + editor.cmd.do('insertHTML', '' + selectionContent + '') + } } // 返回 true,表示执行完之后,隐藏 tooltip。否则不隐藏。 diff --git a/src/menus/link/create-panel-conf.ts b/src/menus/link/create-panel-conf.ts index 34e83a65a..8bbff1831 100644 --- a/src/menus/link/create-panel-conf.ts +++ b/src/menus/link/create-panel-conf.ts @@ -7,7 +7,7 @@ import Editor from '../../editor/index' import { PanelConf } from '../menu-constructors/Panel' import { getRandom } from '../../utils/util' import $, { DomElement } from '../../utils/dom-core' -import isActive from './is-active' +import isActive, { getParentNodeA, EXTRA_TAG } from './is-active' import { insertHtml } from './util' export default function (editor: Editor, text: string, link: string): PanelConf { @@ -78,9 +78,35 @@ export default function (editor: Editor, text: string, link: string): PanelConf } // 选中整个链接 selectLinkElem() - // 用文本替换链接 - const selectionText = $selectedLink.text() - editor.cmd.do('insertHTML', '' + selectionText + '') + + /** + * 替换链接 + * + * 两种情况 + * 1. 特殊标签里嵌套a,也要保留特殊标签: 先加粗后添加链接 + * 2. a标签里面可能会含有其他元素如:b, i等,要保留: 先添加链接后加粗 + */ + + if ($selectedLink.getNodeName() === 'A') { + const linkElem = $selectedLink.elems[0] + const linkParentNode = linkElem.parentElement + + // 判断父级元素是不是特殊元素 + if (linkParentNode && EXTRA_TAG.includes(linkParentNode.nodeName)) { + // 将特殊元素的内容设置为a标签的内容 + linkParentNode.innerHTML = linkElem.innerHTML + } else { + // 如果父级不是特殊元素,直接设置内容 + editor.cmd.do('insertHTML', '' + linkElem.innerHTML + '') + } + } else { + // 如果链接上选区是特殊元素,需要获取最近的a标签,获取html结果,以保留特殊元素 + const parentNodeA = getParentNodeA($selectedLink)! + + const selectionContent = parentNodeA.innerHTML + + editor.cmd.do('insertHTML', '' + selectionContent + '') + } } /** @@ -143,6 +169,10 @@ export default function (editor: Editor, text: string, link: string): PanelConf selector: '#' + btnOkId, type: 'click', fn: () => { + // 获取链接区间的顶层元素 + const $selectionContainerElem = editor.selection.getSelectionContainerElem()! + const $elem = $selectionContainerElem?.elems[0] + // 获取选取 editor.selection.restoreSelection() const topNode = editor.selection @@ -181,6 +211,34 @@ export default function (editor: Editor, text: string, link: string): PanelConf if (!text) text = link // 校验链接是否满足用户的规则,若不满足则不插入 if (!checkLink(text, link)) return + + /** + * 插入链接 + * 1、针对首次插入链接,利用选区插入a标签即可 + * 1、针对:xxxx 情况,用户操作修改或者替换链接时,编辑得到a,修改已有a标签的href + * 2、针对:xxxx 情况, 用户操作修改或者替换链接时,只要修改已有a标签的href + */ + + // 选区范围是a标签,直接替换href链接即可 + if ($elem?.nodeName === 'A') { + $elem.setAttribute('href', link) + + return true + } + + // 不是a标签,并且为特殊元素, 需要检查是不是首次设置链接,还是已经设置过链接。 + if ($elem?.nodeName !== 'A' && EXTRA_TAG.includes($elem.nodeName)) { + const nodeA = getParentNodeA($selectionContainerElem) + + // 防止第一次设置就为特殊元素,这种情况应该为首次设置链接 + if (nodeA) { + nodeA.setAttribute('href', link) + + return true + } + } + + // 首次插入链接 insertLink(text, link) // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 diff --git a/src/menus/link/index.ts b/src/menus/link/index.ts index 6f9e46772..b4c24c30e 100644 --- a/src/menus/link/index.ts +++ b/src/menus/link/index.ts @@ -7,7 +7,7 @@ import PanelMenu from '../menu-constructors/PanelMenu' import Editor from '../../editor/index' import $, { DomElement } from '../../utils/dom-core' import createPanelConf from './create-panel-conf' -import isActive from './is-active' +import isActive, { getParentNodeA } from './is-active' import Panel from '../menu-constructors/Panel' import { MenuActive } from '../menu-constructors/Menu' import bindEvent from './bind-event/index' @@ -57,14 +57,27 @@ class Link extends PanelMenu implements MenuActive { } if (this.isActive) { + let text = '' + let href = '' + // 菜单被激活,说明选区在链接里 $linkElem = editor.selection.getSelectionContainerElem() + if (!$linkElem) { return } + if ($linkElem.getNodeName() !== 'A') { + const parentNodeA = getParentNodeA($linkElem)! + + $linkElem = $(parentNodeA) + } + + text = $linkElem.text() + href = $linkElem.attr('href') + // 弹出 panel - this.createPanel($linkElem.text(), $linkElem.attr('href')) + this.createPanel(text, href) } else { // 菜单未被激活,说明选区不在链接里 if (editor.selection.isSelectionEmpty()) { diff --git a/src/menus/link/is-active.ts b/src/menus/link/is-active.ts index 7437110d1..9416c0d03 100644 --- a/src/menus/link/is-active.ts +++ b/src/menus/link/is-active.ts @@ -4,17 +4,46 @@ */ import Editor from '../../editor/index' +import { DomElement } from '../../utils/dom-core' -function isActive(editor: Editor): boolean { +// 加粗 b +// 字号/字体/颜色 font +// 斜体 i +// 删除线 strike +export const EXTRA_TAG = ['B', 'FONT', 'I', 'STRIKE'] + +export function getParentNodeA(selectionELem: DomElement) { + let node = selectionELem.elems[0] + + while (node && EXTRA_TAG.includes(node.nodeName)) { + node = node.parentElement! + + if (node.nodeName === 'A') { + return node + } + } +} + +function isActive(editor: Editor) { const $selectionELem = editor.selection.getSelectionContainerElem() - if (!$selectionELem?.length) { + + if (!$selectionELem?.elems?.length) { return false } + + // 选中直接是a元素 if ($selectionELem.getNodeName() === 'A') { return true - } else { - return false } + + // 有可能a里面嵌套了其他元素,比如b、i元素等 + const parentNode = getParentNodeA($selectionELem) + + if (parentNode && parentNode.nodeName === 'A') { + return true + } + + return false } export default isActive