Skip to content

Instantly share code, notes, and snippets.

@germain-gg
Last active October 26, 2020 15:46
Show Gist options
  • Save germain-gg/664ce3284fefa38e52d4 to your computer and use it in GitHub Desktop.
Save germain-gg/664ce3284fefa38e52d4 to your computer and use it in GitHub Desktop.
Utils to get and set the caret position in a content editable
var getCaretOffsetWithin = function(node) {
var treeWalker = createTreeWalker(node);
var sel = window.getSelection();
var pos = {
start: 0,
end: 0
};
var isBeyondStart = false;
while(treeWalker.nextNode()) {
// anchorNode is where the selection starts
if (!isBeyondStart && treeWalker.currentNode === sel.anchorNode ) {
isBeyondStart = true;
// sel object gives pos within the current html element only
// the tree walker reached that node
// and the `Selection` obj contains the caret offset in that el
pos.start += sel.anchorOffset;
if (sel.isCollapsed) {
pos.end = pos.start;
break;
}
} else if (!isBeyondStart) {
// The node we are looking for is after
// therefore let's sum the full length of that el
pos.start += treeWalker.currentNode.length;
}
// FocusNode is where the selection stops
if (!sel.isCollapsed && treeWalker.currentNode === sel.focusNode) {
// sel object gives pos within the current html element only
// the tree walker reached that node
// and the `Selection` obj contains the caret offset in that el
pos.end += sel.focusOffset;
break;
} else if (!sel.isCollapsed) {
// The node we are looking for is after
// therefore let's sum the full length of that el
pos.end += treeWalker.currentNode.length;
}
}
return pos;
};
var setCaretPositionWithin = function(node, index) {
var treeWalker = createTreeWalker(node);
var currentPos = 0;
while(treeWalker.nextNode()) {
// while we don't reach the node that contains
// our index we increment `currentPos`
currentPos += treeWalker.currentNode.length;
if (currentPos >= index) {
// offset is relative to the current html element
// We get the value before reaching the node that goes
// over the thresold and then calculate the offset
// within the current node.
var prevValue = currentPos - treeWalker.currentNode.length;
var offset = index - prevValue;
// create a new range that will set the caret
// at the good position
var range = document.createRange();
range.setStart(treeWalker.currentNode, offset);
range.collapse(true);
// Update the selection to reflect the range
// change on the UI
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
break;
}
}
};
var createTreeWalker = function(node) {
return document.createTreeWalker(
node,
NodeFilter.SHOW_TEXT,
{ acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } },
false
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment