@ge-ge/highlight
Version:
226 lines (218 loc) • 6.65 kB
text/typescript
/**
* 递归获取nodeList内元素,如果元素内只有文本,则不继续深一层遍历
* @param df
* @param deep 是否深一层遍历,元素内只有文本的元素
*/
export function getNodeList(
df: DocumentFragment | Node | Element,
deep = false,
) {
function recursion(node: Element | Node) {
const list: Node[] = [];
const pushToList = (list: Node[], pNode: Node | Node[]) => {
if (pNode instanceof Array) {
list.push(...pNode);
} else {
list.push(pNode);
}
};
if (node.nodeType === Node.TEXT_NODE) {
pushToList(list, node);
return list;
} else if (
node.nodeType === Node.ELEMENT_NODE &&
'childElementCount' in node &&
node.childElementCount === 0 &&
!deep
) {
pushToList(list, node);
return list;
} else {
// NodeList is not an Array, NodeList才有所有信息
const length = node.childNodes.length;
for (let i = 0; i < length; i++) {
const item = node.childNodes[i];
if (item.nodeType !== Node.TEXT_NODE) {
const list2 = recursion(item);
pushToList(list, list2);
} else {
pushToList(list, item);
}
}
return list;
}
}
return recursion(df);
}
function nextSibling(
ele: DocumentFragment | Node | Element | ParentNode,
root?: Node | Element,
// eslint-disable-next-line no-unused-vars
cb?: (list2: Node[]) => any,
) {
const list: Node[] = [];
if (ele.nextSibling) {
list.push(ele.nextSibling);
const list2 = nextSibling(ele.nextSibling, root);
list.push(...list2);
cb && cb(list2);
} else if (
root &&
ele.parentNode &&
ele.parentNode !== root &&
ele.parentNode.parentNode !== root
) {
const list2 = nextSibling(ele.parentNode, root);
list.push(...list2);
cb && cb(list2);
}
return list;
}
function previousSibling(
ele: DocumentFragment | Node | Element | ParentNode,
root?: Node | Element,
// eslint-disable-next-line no-unused-vars
cb?: (list2: Node[]) => any,
) {
const list: Node[] = [];
if (ele.previousSibling) {
list.unshift(ele.previousSibling);
const list2 = previousSibling(ele.previousSibling, root);
list.unshift(...list2);
cb && cb(list2);
} else if (
root &&
ele.parentNode &&
ele.parentNode !== root &&
ele.parentNode.parentNode !== root
) {
const list2 = previousSibling(ele.parentNode, root);
list.unshift(...list2);
cb && cb(list2);
}
return list;
}
function getPath(
ele: DocumentFragment | Node | Element | ParentNode,
root?: Node | Element,
) {
const path: ParentNode[] = [];
const r = (ele: DocumentFragment | Node | ParentNode | Element) => {
if (ele !== root && ele.parentNode && ele.parentNode !== root) {
path.push(ele.parentNode);
r(ele.parentNode);
}
};
r(ele);
return path;
}
/**
* @description 将Range分成开头、结尾部分
* @return Array
* */
export function splitRange(range: Range) {
const ranges: {
start?: { id: string; range: Range };
end?: { id: string; range: Range };
} = {};
const start: Range = document.createRange();
const end: Range = document.createRange();
// 当开头结尾为同一个元素时
if (range.startContainer === range.endContainer) {
start.setStart(range.startContainer, range.startOffset);
start.setEnd(range.endContainer, range.endOffset);
} else {
if (range.startContainer) {
start.setStart(range.startContainer, range.startOffset);
if (range.startContainer.nodeType === Node.TEXT_NODE) {
start.setEndAfter(range.startContainer);
} else {
start.setEnd(
range.startContainer,
range.startContainer.childNodes.length,
);
}
}
end.setStart(range.endContainer, 0);
end.setEnd(range.endContainer, range.endOffset);
}
ranges.start = {
id: 'start',
range: start,
};
ranges.end = {
id: 'end',
range: end,
};
return ranges;
}
export function splitRange2(range: Range) {
const { startContainer, endContainer, commonAncestorContainer } = range;
if (startContainer === endContainer) {
return [];
}
if (
startContainer &&
endContainer &&
startContainer.parentNode === endContainer.parentNode
) {
const range: Range = document.createRange();
range.setStartAfter(startContainer);
range.setEndBefore(endContainer);
return [range];
}
function createRange(list: Node[]) {
const range: Range = document.createRange();
range.setStartBefore(list[0]);
range.setEndAfter(list[list.length - 1]);
return range;
}
// 从startContainer 开始遍历
const startSiblingList: Range[] = [];
nextSibling(startContainer, commonAncestorContainer, (list) => {
if (list && list.length) startSiblingList.push(createRange(list));
});
const endSiblingList: Range[] = [];
previousSibling(endContainer, commonAncestorContainer, (list) => {
if (list && list.length) endSiblingList.push(createRange(list));
});
const centerList = [];
let isStart = false;
if (commonAncestorContainer.childNodes.length > 2) {
const sPath = getPath(startContainer, commonAncestorContainer);
const ePath = getPath(endContainer, commonAncestorContainer);
for (let i = 0; i < commonAncestorContainer.childNodes.length - 1; i++) {
const item = commonAncestorContainer.childNodes[i];
if (item === <Node>sPath[sPath.length - 1]) {
isStart = true;
continue;
}
if (!isStart) continue;
if (item === <Node>ePath[ePath.length - 1]) {
break;
}
centerList.push(item);
}
}
if (centerList.length) {
const centerRangeList = createRange(centerList);
return [...startSiblingList, centerRangeList, ...endSiblingList];
}
return [...startSiblingList, ...endSiblingList];
}
// eslint-disable-next-line no-unused-vars
export function customMark(range: Range, cb: (arg0: DocumentFragment) => any) {
const { start, end } = splitRange(range);
const new_range_list = splitRange2(range); // 分割成多个range
if (start && start.range) new_range_list.unshift(start.range);
if (end && end.range) new_range_list.push(end.range);
for (const new_range of new_range_list) {
if (!new_range) continue;
const docFragment = new_range.extractContents(); // 将选区内的元素移出到documentFragment
// 对docFragment进行处理
cb && cb(docFragment);
// 处理完成后插入到对应的range,range被修改没有参考意义
new_range.deleteContents();
new_range.insertNode(docFragment);
}
}