-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcontent.js
More file actions
81 lines (58 loc) · 2.07 KB
/
content.js
File metadata and controls
81 lines (58 loc) · 2.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
const DELAY = 0,
MAX_LENGTH = 50;
let timer, lastText;
$('body').on('mouseup dbclick', e => {
clearTimeout(timer);
timer = setTimeout(() => {
let selection = getSelection();
let text = $.trim(selection.toString());
if (lastText == text) { // do nothing if selection is the same as lastText
return;
}
undoHighlight();
lastText = null;
if (text.length <= MAX_LENGTH && text.length > 0) {
lastText = text;
doHighight(text, [selection.anchorNode, selection.baseNode]); //ignore anchorNode and baseNode
}
}, DELAY);
})
function doHighight(selectedText, ignores = []) {
let regex;
if (/[^a-zA-z0-9_\$]/.test(selectedText)) { // 满足这个条件的不用\b, 针对非变量名的情况
regex = new RegExp(`${escRegExp(selectedText)}`, `g`);
} else { // 否则加上\b匹配, 要求匹配整个单词
regex = new RegExp(`\\b${escRegExp(selectedText)}\\b`, `g`);
}
let textList = getVisibleTextNodesIn('body');
textList.each((index, textNode) => {
// 递归调用, 每次进处理第一个词, 将剩余的词放入下一次递归中处理
(function handlerFirstTextInStr(textNode) {
let curText = textNode.nodeValue;
let parentNode = textNode.parentNode;
regex.lastIndex = 0;
if (regex.test(curText) && ignores.indexOf(textNode) == -1) {
// curText => `textLeft_selectedText_textRemain`
// one node => three nodes
let [textLeft = '', ...textRemain] = curText.split(selectedText);
textNode.nodeValue = textRemain.join(selectedText);
parentNode.insertBefore(document.createTextNode(textLeft), textNode);
parentNode.insertBefore($(`<qs-highlight>${selectedText}</qs-highlight>`)[0], textNode);
handlerFirstTextInStr(textNode);
}
})(textNode);
})
}
function undoHighlight() {
$('qs-highlight').each((index, el) => {
el.outerHTML = el.innerHTML;
})
}
function getVisibleTextNodesIn(el) {
return $(el).find(":not(iframe, textarea):visible").addBack().contents().filter(function() {
return this.nodeType == 3;
});
};
function escRegExp(str) {
return String(str).replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&');
}