Skip to content

Commit 6e30856

Browse files
Merge pull request #3879 from wangeditor-team/fix-link-fill
fix: 链接修改字号后再点链接按钮无法看到链接地址
2 parents be6c314 + b396a1e commit 6e30856

File tree

4 files changed

+131
-13
lines changed

4 files changed

+131
-13
lines changed

src/menus/link/bind-event/tooltip-event.ts

+21-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import $, { DomElement } from '../../../utils/dom-core'
77
import Tooltip, { TooltipConfType } from '../../menu-constructors/Tooltip'
88
import Editor from '../../../editor/index'
9+
import { EXTRA_TAG } from '../is-active'
910

1011
/**
1112
* 生成 Tooltip 的显示隐藏函数
@@ -50,9 +51,26 @@ function createShowHideFn(editor: Editor) {
5051
style=${$selectIMG?.getAttribute('style')}>`
5152
)
5253
} else {
53-
// 用文字,替换链接
54-
const selectionText = $link.text()
55-
editor.cmd.do('insertHTML', '<span>' + selectionText + '</span>')
54+
/**
55+
* 替换链接
56+
*
57+
* 两种情况
58+
* 1. a标签里面可能会含有其他元素如:b, i等,要保留: <a><b></b></a> 先添加链接后加粗
59+
* 2. 特殊标签里嵌套a,也要保留特殊标签:<b><a></a></b> 先加粗后添加链接
60+
*/
61+
const linkElem = $link.elems[0]
62+
63+
// a标签里面的html结构
64+
const selectionContent = linkElem.innerHTML
65+
66+
// a标签的父元素
67+
const linkParentNode = linkElem.parentElement
68+
69+
if (linkParentNode && EXTRA_TAG.includes(linkParentNode.nodeName)) {
70+
linkParentNode.innerHTML = selectionContent
71+
} else {
72+
editor.cmd.do('insertHTML', '<span>' + selectionContent + '</span>')
73+
}
5674
}
5775

5876
// 返回 true,表示执行完之后,隐藏 tooltip。否则不隐藏。

src/menus/link/create-panel-conf.ts

+62-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Editor from '../../editor/index'
77
import { PanelConf } from '../menu-constructors/Panel'
88
import { getRandom } from '../../utils/util'
99
import $, { DomElement } from '../../utils/dom-core'
10-
import isActive from './is-active'
10+
import isActive, { getParentNodeA, EXTRA_TAG } from './is-active'
1111
import { insertHtml } from './util'
1212

1313
export default function (editor: Editor, text: string, link: string): PanelConf {
@@ -78,9 +78,35 @@ export default function (editor: Editor, text: string, link: string): PanelConf
7878
}
7979
// 选中整个链接
8080
selectLinkElem()
81-
// 用文本替换链接
82-
const selectionText = $selectedLink.text()
83-
editor.cmd.do('insertHTML', '<span>' + selectionText + '</span>')
81+
82+
/**
83+
* 替换链接
84+
*
85+
* 两种情况
86+
* 1. 特殊标签里嵌套a,也要保留特殊标签:<b><a></a></b> 先加粗后添加链接
87+
* 2. a标签里面可能会含有其他元素如:b, i等,要保留: <a><b></b></a> 先添加链接后加粗
88+
*/
89+
90+
if ($selectedLink.getNodeName() === 'A') {
91+
const linkElem = $selectedLink.elems[0]
92+
const linkParentNode = linkElem.parentElement
93+
94+
// 判断父级元素是不是特殊元素
95+
if (linkParentNode && EXTRA_TAG.includes(linkParentNode.nodeName)) {
96+
// 将特殊元素的内容设置为a标签的内容
97+
linkParentNode.innerHTML = linkElem.innerHTML
98+
} else {
99+
// 如果父级不是特殊元素,直接设置内容
100+
editor.cmd.do('insertHTML', '<span>' + linkElem.innerHTML + '</span>')
101+
}
102+
} else {
103+
// 如果链接上选区是特殊元素,需要获取最近的a标签,获取html结果,以保留特殊元素
104+
const parentNodeA = getParentNodeA($selectedLink)!
105+
106+
const selectionContent = parentNodeA.innerHTML
107+
108+
editor.cmd.do('insertHTML', '<span>' + selectionContent + '</span>')
109+
}
84110
}
85111

86112
/**
@@ -143,6 +169,10 @@ export default function (editor: Editor, text: string, link: string): PanelConf
143169
selector: '#' + btnOkId,
144170
type: 'click',
145171
fn: () => {
172+
// 获取链接区间的顶层元素
173+
const $selectionContainerElem = editor.selection.getSelectionContainerElem()!
174+
const $elem = $selectionContainerElem?.elems[0]
175+
146176
// 获取选取
147177
editor.selection.restoreSelection()
148178
const topNode = editor.selection
@@ -181,6 +211,34 @@ export default function (editor: Editor, text: string, link: string): PanelConf
181211
if (!text) text = link
182212
// 校验链接是否满足用户的规则,若不满足则不插入
183213
if (!checkLink(text, link)) return
214+
215+
/**
216+
* 插入链接
217+
* 1、针对首次插入链接,利用选区插入a标签即可
218+
* 1、针对:<a><b>xxxx</b></a> 情况,用户操作修改或者替换链接时,编辑得到a,修改已有a标签的href
219+
* 2、针对:<b><a>xxxx</a></b> 情况, 用户操作修改或者替换链接时,只要修改已有a标签的href
220+
*/
221+
222+
// 选区范围是a标签,直接替换href链接即可
223+
if ($elem?.nodeName === 'A') {
224+
$elem.setAttribute('href', link)
225+
226+
return true
227+
}
228+
229+
// 不是a标签,并且为特殊元素, 需要检查是不是首次设置链接,还是已经设置过链接。
230+
if ($elem?.nodeName !== 'A' && EXTRA_TAG.includes($elem.nodeName)) {
231+
const nodeA = getParentNodeA($selectionContainerElem)
232+
233+
// 防止第一次设置就为特殊元素,这种情况应该为首次设置链接
234+
if (nodeA) {
235+
nodeA.setAttribute('href', link)
236+
237+
return true
238+
}
239+
}
240+
241+
// 首次插入链接
184242
insertLink(text, link)
185243

186244
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭

src/menus/link/index.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import PanelMenu from '../menu-constructors/PanelMenu'
77
import Editor from '../../editor/index'
88
import $, { DomElement } from '../../utils/dom-core'
99
import createPanelConf from './create-panel-conf'
10-
import isActive from './is-active'
10+
import isActive, { getParentNodeA } from './is-active'
1111
import Panel from '../menu-constructors/Panel'
1212
import { MenuActive } from '../menu-constructors/Menu'
1313
import bindEvent from './bind-event/index'
@@ -57,14 +57,27 @@ class Link extends PanelMenu implements MenuActive {
5757
}
5858

5959
if (this.isActive) {
60+
let text = ''
61+
let href = ''
62+
6063
// 菜单被激活,说明选区在链接里
6164
$linkElem = editor.selection.getSelectionContainerElem()
65+
6266
if (!$linkElem) {
6367
return
6468
}
6569

70+
if ($linkElem.getNodeName() !== 'A') {
71+
const parentNodeA = getParentNodeA($linkElem)!
72+
73+
$linkElem = $(parentNodeA)
74+
}
75+
76+
text = $linkElem.text()
77+
href = $linkElem.attr('href')
78+
6679
// 弹出 panel
67-
this.createPanel($linkElem.text(), $linkElem.attr('href'))
80+
this.createPanel(text, href)
6881
} else {
6982
// 菜单未被激活,说明选区不在链接里
7083
if (editor.selection.isSelectionEmpty()) {

src/menus/link/is-active.ts

+33-4
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,46 @@
44
*/
55

66
import Editor from '../../editor/index'
7+
import { DomElement } from '../../utils/dom-core'
78

8-
function isActive(editor: Editor): boolean {
9+
// 加粗 b
10+
// 字号/字体/颜色 font
11+
// 斜体 i
12+
// 删除线 strike
13+
export const EXTRA_TAG = ['B', 'FONT', 'I', 'STRIKE']
14+
15+
export function getParentNodeA(selectionELem: DomElement) {
16+
let node = selectionELem.elems[0]
17+
18+
while (node && EXTRA_TAG.includes(node.nodeName)) {
19+
node = node.parentElement!
20+
21+
if (node.nodeName === 'A') {
22+
return node
23+
}
24+
}
25+
}
26+
27+
function isActive(editor: Editor) {
928
const $selectionELem = editor.selection.getSelectionContainerElem()
10-
if (!$selectionELem?.length) {
29+
30+
if (!$selectionELem?.elems?.length) {
1131
return false
1232
}
33+
34+
// 选中直接是a元素
1335
if ($selectionELem.getNodeName() === 'A') {
1436
return true
15-
} else {
16-
return false
1737
}
38+
39+
// 有可能a里面嵌套了其他元素,比如b、i元素等
40+
const parentNode = getParentNodeA($selectionELem)
41+
42+
if (parentNode && parentNode.nodeName === 'A') {
43+
return true
44+
}
45+
46+
return false
1847
}
1948

2049
export default isActive

0 commit comments

Comments
 (0)