1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow
    
  8.  */
    
  9. 
    
  10. import {TEXT_NODE} from './HTMLNodeType';
    
  11. 
    
  12. /**
    
  13.  * Given any node return the first leaf node without children.
    
  14.  *
    
  15.  * @param {DOMElement|DOMTextNode} node
    
  16.  * @return {DOMElement|DOMTextNode}
    
  17.  */
    
  18. function getLeafNode(node: ?(Node | Element)) {
    
  19.   while (node && node.firstChild) {
    
  20.     node = node.firstChild;
    
  21.   }
    
  22.   return node;
    
  23. }
    
  24. 
    
  25. /**
    
  26.  * Get the next sibling within a container. This will walk up the
    
  27.  * DOM if a node's siblings have been exhausted.
    
  28.  *
    
  29.  * @param {DOMElement|DOMTextNode} node
    
  30.  * @return {?DOMElement|DOMTextNode}
    
  31.  */
    
  32. function getSiblingNode(node: ?(Node | Element)) {
    
  33.   while (node) {
    
  34.     if (node.nextSibling) {
    
  35.       return node.nextSibling;
    
  36.     }
    
  37.     node = node.parentNode;
    
  38.   }
    
  39. }
    
  40. 
    
  41. /**
    
  42.  * Get object describing the nodes which contain characters at offset.
    
  43.  *
    
  44.  * @param {DOMElement|DOMTextNode} root
    
  45.  * @param {number} offset
    
  46.  * @return {?object}
    
  47.  */
    
  48. function getNodeForCharacterOffset(root: Element, offset: number): ?Object {
    
  49.   let node = getLeafNode(root);
    
  50.   let nodeStart = 0;
    
  51.   let nodeEnd = 0;
    
  52. 
    
  53.   while (node) {
    
  54.     if (node.nodeType === TEXT_NODE) {
    
  55.       nodeEnd = nodeStart + node.textContent.length;
    
  56. 
    
  57.       if (nodeStart <= offset && nodeEnd >= offset) {
    
  58.         return {
    
  59.           node: node,
    
  60.           offset: offset - nodeStart,
    
  61.         };
    
  62.       }
    
  63. 
    
  64.       nodeStart = nodeEnd;
    
  65.     }
    
  66. 
    
  67.     node = getLeafNode(getSiblingNode(node));
    
  68.   }
    
  69. }
    
  70. 
    
  71. export default getNodeForCharacterOffset;