66 lines
2.6 KiB
JavaScript
66 lines
2.6 KiB
JavaScript
import { getUIValue } from '../../document/UI.js';
|
|
import '../../utils/click/isClickableInput.js';
|
|
import '../../utils/dataTransfer/Clipboard.js';
|
|
import '../../utils/edit/isEditable.js';
|
|
import '../../utils/edit/maxLength.js';
|
|
import { hasOwnSelection } from '../../utils/focus/selection.js';
|
|
import '../../utils/keyDef/readNextDescriptor.js';
|
|
import '../../utils/misc/level.js';
|
|
import '../../options.js';
|
|
|
|
function resolveCaretPosition({ target, node, offset }) {
|
|
if (hasOwnSelection(target)) {
|
|
return {
|
|
node: target,
|
|
offset: offset !== null && offset !== void 0 ? offset : getUIValue(target).length
|
|
};
|
|
} else if (node) {
|
|
return {
|
|
node,
|
|
offset: offset !== null && offset !== void 0 ? offset : node.nodeType === 3 ? node.nodeValue.length : node.childNodes.length
|
|
};
|
|
}
|
|
return findNodeAtTextOffset(target, offset);
|
|
}
|
|
function findNodeAtTextOffset(node, offset, isRoot = true) {
|
|
// When clicking after the content the browser behavior can be complicated:
|
|
// 1. If there is textContent after the last element child,
|
|
// the cursor is moved there.
|
|
// 2. If there is textContent in the last element child,
|
|
// the browser moves the cursor to the last non-empty text node inside this element.
|
|
// 3. Otherwise the cursor is moved to the end of the target.
|
|
let i = offset === undefined ? node.childNodes.length - 1 : 0;
|
|
const step = offset === undefined ? -1 : +1;
|
|
while(offset === undefined ? i >= (isRoot ? Math.max(node.childNodes.length - 1, 0) : 0) : i <= node.childNodes.length){
|
|
if (offset && i === node.childNodes.length) {
|
|
throw new Error('The given offset is out of bounds.');
|
|
}
|
|
const c = node.childNodes.item(i);
|
|
const text = String(c.textContent);
|
|
if (text.length) {
|
|
if (offset !== undefined && text.length < offset) {
|
|
offset -= text.length;
|
|
} else if (c.nodeType === 1) {
|
|
return findNodeAtTextOffset(c, offset, false);
|
|
} else {
|
|
// The pre-commit hooks keeps changing this
|
|
// See https://github.com/kentcdodds/kcd-scripts/issues/218
|
|
/* istanbul ignore else */ // eslint-disable-next-line no-lonely-if
|
|
if (c.nodeType === 3) {
|
|
return {
|
|
node: c,
|
|
offset: offset !== null && offset !== void 0 ? offset : c.nodeValue.length
|
|
};
|
|
}
|
|
}
|
|
}
|
|
i += step;
|
|
}
|
|
return {
|
|
node,
|
|
offset: node.childNodes.length
|
|
};
|
|
}
|
|
|
|
export { resolveCaretPosition };
|