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