/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ import {TEXT_NODE} from '../shared/HTMLNodeType'; /** * Given any node return the first leaf node without children. * * @param {DOMElement|DOMTextNode} node * @return {DOMElement|DOMTextNode} */ function getLeafNode(node) { while (node && node.firstChild) { node = node.firstChild; } return node; } /** * Get the next sibling within a container. This will walk up the * DOM if a node's siblings have been exhausted. * * @param {DOMElement|DOMTextNode} node * @return {?DOMElement|DOMTextNode} */ function getSiblingNode(node) { while (node) { if (node.nextSibling) { return node.nextSibling; } node = node.parentNode; } } /** * Get object describing the nodes which contain characters at offset. * * @param {DOMElement|DOMTextNode} root * @param {number} offset * @return {?object} */ function getNodeForCharacterOffset(root: Element, offset: number): ?Object { let node = getLeafNode(root); let nodeStart = 0; let nodeEnd = 0; while (node) { if (node.nodeType === TEXT_NODE) { nodeEnd = nodeStart + node.textContent.length; if (nodeStart <= offset && nodeEnd >= offset) { return { node: node, offset: offset - nodeStart, }; } nodeStart = nodeEnd; } node = getLeafNode(getSiblingNode(node)); } } export default getNodeForCharacterOffset;