ignore react comment nodes when locating/setting caret

This commit is contained in:
Bruno Windels 2019-05-08 11:12:47 +02:00
parent 6be6492cd2
commit 8f0074f824

View file

@ -26,7 +26,10 @@ export function getCaretOffset(editor) {
if (node === editor) { if (node === editor) {
let offset = 0; let offset = 0;
for (let i = 0; i < sel.focusOffset; ++i) { for (let i = 0; i < sel.focusOffset; ++i) {
offset += editor.childNodes[i].textContent.length; const node = editor.childNodes[i];
if (isVisibleNode(node)) {
offset += node.textContent.length;
}
} }
return {offset, atNodeEnd: false}; return {offset, atNodeEnd: false};
} }
@ -36,8 +39,10 @@ export function getCaretOffset(editor) {
// include all preceding siblings of the non-direct editor children // include all preceding siblings of the non-direct editor children
while (node.previousSibling) { while (node.previousSibling) {
node = node.previousSibling; node = node.previousSibling;
if (isVisibleNode(node)) {
offset += node.textContent.length; offset += node.textContent.length;
} }
}
// then move up // then move up
// I guess technically there could be preceding text nodes in the parents here as well, // I guess technically there could be preceding text nodes in the parents here as well,
// but we're assuming there are no mixed text and element nodes // but we're assuming there are no mixed text and element nodes
@ -48,8 +53,10 @@ export function getCaretOffset(editor) {
// now include the text length of all preceding direct editor children // now include the text length of all preceding direct editor children
while (node.previousSibling) { while (node.previousSibling) {
node = node.previousSibling; node = node.previousSibling;
if (isVisibleNode(node)) {
offset += node.textContent.length; offset += node.textContent.length;
} }
}
// { // {
// const {focusOffset, focusNode} = sel; // const {focusOffset, focusNode} = sel;
// console.log("selection", {focusOffset, focusNode, position, atNodeEnd}); // console.log("selection", {focusOffset, focusNode, position, atNodeEnd});
@ -57,22 +64,40 @@ export function getCaretOffset(editor) {
return {offset, atNodeEnd}; return {offset, atNodeEnd};
} }
function isVisibleNode(node) {
return node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE;
}
function untilVisibleNode(node) {
// need to ignore comment nodes that react uses
while (node && !isVisibleNode(node)) {
node = node.nextSibling;
}
return node;
}
export function setCaretPosition(editor, caretPosition) { export function setCaretPosition(editor, caretPosition) {
if (caretPosition) { let node = untilVisibleNode(editor.firstChild);
let focusNode = editor.childNodes[caretPosition.index]; if (!node) {
if (!focusNode) { node = editor;
focusNode = editor;
} else { } else {
let {index} = caretPosition;
while (node && index) {
node = untilVisibleNode(node.nextSibling);
--index;
}
if (!node) {
node = editor;
} else if (node.nodeType === Node.ELEMENT_NODE) {
// make sure we have a text node // make sure we have a text node
if (focusNode.nodeType === Node.ELEMENT_NODE) { node = node.childNodes[0];
focusNode = focusNode.childNodes[0];
} }
} }
console.log("setting caret", caretPosition, node);
const sel = document.getSelection(); const sel = document.getSelection();
sel.removeAllRanges(); sel.removeAllRanges();
const range = document.createRange(); const range = document.createRange();
range.setStart(focusNode, caretPosition.offset); range.setStart(node, caretPosition.offset);
range.collapse(true); range.collapse(true);
sel.addRange(range); sel.addRange(range);
}
} }