import {Constants} from "../constants"; import {isChrome} from "./compatibility"; import {hasClosestBlock, hasClosestByClassName} from "./hasClosest"; export const getEditorRange = (vditor: IVditor) => { let range: Range; const element = vditor[vditor.currentMode].element; if (getSelection().rangeCount > 0) { range = getSelection().getRangeAt(0); if (element.isEqualNode(range.startContainer) || element.contains(range.startContainer)) { return range; } } if (vditor[vditor.currentMode].range) { return vditor[vditor.currentMode].range; } element.focus(); range = element.ownerDocument.createRange(); range.setStart(element, 0); range.collapse(true); return range; }; export const getCursorPosition = (editor: HTMLElement) => { const range = window.getSelection().getRangeAt(0); if (!editor.contains(range.startContainer) && !hasClosestByClassName(range.startContainer, "vditor-panel--none")) { return { left: 0, top: 0, }; } const parentRect = editor.parentElement.getBoundingClientRect(); let cursorRect; if (range.getClientRects().length === 0) { if (range.startContainer.nodeType === 3) { // 空行时,会出现没有 br 的情况,需要根据父元素
获取位置信息
const parent = range.startContainer.parentElement;
if (parent && parent.getClientRects().length > 0) {
cursorRect = parent.getClientRects()[0];
} else {
return {
left: 0,
top: 0,
};
}
} else {
const children = (range.startContainer as Element).children;
if (children[range.startOffset] &&
children[range.startOffset].getClientRects().length > 0) {
// markdown 模式回车
cursorRect = children[range.startOffset].getClientRects()[0];
} else if (range.startContainer.childNodes.length > 0) {
// in table or code block
const cloneRange = range.cloneRange();
range.selectNode(range.startContainer.childNodes[Math.max(0, range.startOffset - 1)]);
cursorRect = range.getClientRects()[0];
range.setEnd(cloneRange.endContainer, cloneRange.endOffset);
range.setStart(cloneRange.startContainer, cloneRange.startOffset);
} else {
cursorRect = (range.startContainer as HTMLElement).getClientRects()[0];
}
if (!cursorRect) {
let parentElement = range.startContainer.childNodes[range.startOffset] as HTMLElement;
while (!parentElement.getClientRects ||
(parentElement.getClientRects && parentElement.getClientRects().length === 0)) {
parentElement = parentElement.parentElement;
}
cursorRect = parentElement.getClientRects()[0];
}
}
} else {
cursorRect = range.getClientRects()[0];
}
return {
left: cursorRect.left - parentRect.left,
top: cursorRect.top - parentRect.top,
};
};
export const selectIsEditor = (editor: HTMLElement, range?: Range) => {
if (!range) {
if (getSelection().rangeCount === 0) {
return false;
} else {
range = getSelection().getRangeAt(0);
}
}
const container = range.commonAncestorContainer;
return editor.isEqualNode(container) || editor.contains(container);
};
export const setSelectionFocus = (range: Range) => {
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
};
export const getSelectPosition = (selectElement: HTMLElement, editorElement: HTMLElement, range?: Range) => {
const position = {
end: 0,
start: 0,
};
if (!range) {
if (getSelection().rangeCount === 0) {
return position;
}
range = window.getSelection().getRangeAt(0);
}
if (selectIsEditor(editorElement, range)) {
const preSelectionRange = range.cloneRange();
if (selectElement.childNodes[0] && selectElement.childNodes[0].childNodes[0]) {
preSelectionRange.setStart(selectElement.childNodes[0].childNodes[0], 0);
} else {
preSelectionRange.selectNodeContents(selectElement);
}
preSelectionRange.setEnd(range.startContainer, range.startOffset);
position.start = preSelectionRange.toString().length;
position.end = position.start + range.toString().length;
}
return position;
};
export const setSelectionByPosition = (start: number, end: number, editor: HTMLElement) => {
let charIndex = 0;
let line = 0;
let pNode = editor.childNodes[line];
let foundStart = false;
let stop = false;
start = Math.max(0, start);
end = Math.max(0, end);
const range = editor.ownerDocument.createRange();
range.setStart(pNode || editor, 0);
range.collapse(true);
while (!stop && pNode) {
const nextCharIndex = charIndex + pNode.textContent.length;
if (!foundStart && start >= charIndex && start <= nextCharIndex) {
if (start === 0) {
range.setStart(pNode, 0);
} else {
if (pNode.childNodes[0].nodeType === 3) {
range.setStart(pNode.childNodes[0], start - charIndex);
} else if (pNode.nextSibling) {
range.setStartBefore(pNode.nextSibling);
} else {
range.setStartAfter(pNode);
}
}
foundStart = true;
if (start === end) {
stop = true;
break;
}
}
if (foundStart && end >= charIndex && end <= nextCharIndex) {
if (end === 0) {
range.setEnd(pNode, 0);
} else {
if (pNode.childNodes[0].nodeType === 3) {
range.setEnd(pNode.childNodes[0], end - charIndex);
} else if (pNode.nextSibling) {
range.setEndBefore(pNode.nextSibling);
} else {
range.setEndAfter(pNode);
}
}
stop = true;
}
charIndex = nextCharIndex;
pNode = editor.childNodes[++line];
}
if (!stop && editor.childNodes[line - 1]) {
range.setStartBefore(editor.childNodes[line - 1]);
}
setSelectionFocus(range);
return range;
};
// 设置光标
export const setRangeByWbr = (element: HTMLElement, range: Range, event?: InsertValueEvent, insertValue?: string) => {
const wbrElement = element.querySelector("wbr");
if (!wbrElement) {
return;
}
if (event && event.inputType === 'insertValue') {
if (wbrElement.nextSibling) {
if (wbrElement.nextSibling.nodeType === 3) {
//
https://github.com/Vanessa219/vditor/issues/400
range.setStartAfter(wbrElement.nextSibling);
}
} else if (wbrElement.previousSibling) {
if (wbrElement.previousSibling.nodeType === 3) {
// text
https://github.com/Vanessa219/vditor/issues/400
range.setStartBefore(wbrElement.nextSibling);
}
} else {
// 内容为空
range.setStart(wbrElement.parentElement, 0);
}
} else {
if (wbrElement.previousElementSibling.isSameNode(wbrElement.previousSibling)) {
if (wbrElement.previousElementSibling.lastChild) {
// text