100 lines
2.6 KiB
TypeScript
100 lines
2.6 KiB
TypeScript
const extractorEl = document.createElement('div');
|
|
|
|
export function insertHtmlInSelection(html: string) {
|
|
const selection = window.getSelection();
|
|
|
|
if (selection?.getRangeAt && selection.rangeCount) {
|
|
const range = selection.getRangeAt(0);
|
|
range.deleteContents();
|
|
|
|
const fragment = range.createContextualFragment(html);
|
|
const lastInsertedNode = fragment.lastChild;
|
|
range.insertNode(fragment);
|
|
if (lastInsertedNode) {
|
|
range.setStartAfter(lastInsertedNode);
|
|
range.setEndAfter(lastInsertedNode);
|
|
} else {
|
|
range.collapse(false);
|
|
}
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
}
|
|
}
|
|
|
|
export function getHtmlBeforeSelection(container?: HTMLElement, useCommonAncestor?: boolean) {
|
|
if (!container) {
|
|
return '';
|
|
}
|
|
|
|
const sel = window.getSelection();
|
|
if (!sel || !sel.rangeCount) {
|
|
return container.innerHTML;
|
|
}
|
|
|
|
const range = sel.getRangeAt(0).cloneRange();
|
|
if (!range.intersectsNode(container)) {
|
|
return container.innerHTML;
|
|
}
|
|
|
|
if (!useCommonAncestor && !container.contains(range.commonAncestorContainer)) {
|
|
return '';
|
|
}
|
|
|
|
range.collapse(true);
|
|
range.setStart(container, 0);
|
|
|
|
extractorEl.innerHTML = '';
|
|
extractorEl.appendChild(range.cloneContents());
|
|
|
|
return extractorEl.innerHTML;
|
|
}
|
|
|
|
// https://stackoverflow.com/a/3976125
|
|
export function getCaretPosition(element: HTMLElement) {
|
|
let caretPosition = 0;
|
|
const selection = window.getSelection();
|
|
if (!selection || selection.rangeCount === 0) {
|
|
return caretPosition;
|
|
}
|
|
|
|
const range = selection.getRangeAt(0);
|
|
const caretRange = range.cloneRange();
|
|
caretRange.selectNodeContents(element);
|
|
caretRange.setEnd(range.endContainer, range.endOffset);
|
|
caretPosition = caretRange.toString().length;
|
|
|
|
return caretPosition;
|
|
}
|
|
|
|
// https://stackoverflow.com/a/36953852
|
|
export function setCaretPosition(element: Node, position: number) {
|
|
for (const node of element.childNodes) {
|
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
if ((node as Text).length >= position) {
|
|
const range = document.createRange();
|
|
const selection = window.getSelection()!;
|
|
range.setStart(node, position);
|
|
range.collapse(true);
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
|
|
return -1;
|
|
} else {
|
|
position -= 'length' in node ? node.length as number : 0;
|
|
}
|
|
} else {
|
|
position = setCaretPosition(node, position);
|
|
if (position === -1) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return position;
|
|
}
|
|
|
|
export function removeAllSelections() {
|
|
const selection = window.getSelection();
|
|
selection?.removeAllRanges();
|
|
}
|