text-fragments-ts/lib/ whatwg-dom.js
105 lines
5.1 KiB

  1. /////////////////////////////////////////////
  2. // Required pieces of the WHATWG DOM spec ///
  3. /////////////////////////////////////////////
  4. // Based on the version of 29 June 2020 <https://dom.spec.whatwg.org/commit-snapshots/e191f73a0fcc09c48f9e962188748f811b09c239/>
  5. import { isElement, nextNode, } from './common.js';
  6. // https://dom.spec.whatwg.org/#concept-tree-descendant
  7. // “An object A is called a descendant of an object B, if either A is a child of B or A is a child of an object C that is a descendant of B.”
  8. export function isDescendant(nodeA, nodeB) {
  9. if (nodeA.parentNode === nodeB)
  10. return true;
  11. const nodeC = nodeA.parentNode;
  12. if (nodeC && isDescendant(nodeC, nodeB))
  13. return true;
  14. return false;
  15. }
  16. // https://dom.spec.whatwg.org/#concept-tree-following
  17. // “An object A is following an object B if A and B are in the same tree and A comes after B in tree order.”
  18. export function followsInTree(nodeA, nodeB) {
  19. return !!(nodeB.compareDocumentPosition(nodeA) & Node.DOCUMENT_POSITION_FOLLOWING);
  20. }
  21. // https://dom.spec.whatwg.org/#concept-node-length
  22. // “To determine the length of a node node, switch on node:”
  23. export function nodeLength(node) {
  24. switch (node.nodeType) {
  25. // “DocumentType”
  26. case Node.DOCUMENT_TYPE_NODE:
  27. // “Zero.”
  28. return 0;
  29. // “Text”
  30. case Node.TEXT_NODE:
  31. // “ProcessingInstruction”
  32. case Node.PROCESSING_INSTRUCTION_NODE:
  33. // “Comment”
  34. case Node.COMMENT_NODE:
  35. // “Its data’s length.”
  36. return node.data.length;
  37. // “Any other node”
  38. default:
  39. // “Its number of children.”
  40. return node.childNodes.length;
  41. }
  42. }
  43. // https://dom.spec.whatwg.org/#concept-shadow-including-tree-order
  44. // “In shadow-including tree order is shadow-including preorder, depth-first traversal of a node tree. Shadow-including preorder, depth-first traversal of a node tree tree is preorder, depth-first traversal of tree, with for each shadow host encountered in tree, shadow-including preorder, depth-first traversal of that element’s shadow root’s node tree just after it is encountered.”
  45. export function nextNodeInShadowIncludingTreeOrder(node) {
  46. if (isShadowHost(node)) {
  47. return nextNodeInShadowIncludingTreeOrder(node.shadowRoot);
  48. }
  49. else {
  50. return nextNode(node);
  51. }
  52. }
  53. export function isShadowHost(node) {
  54. return (isElement(node) && node.shadowRoot !== null);
  55. }
  56. // https://dom.spec.whatwg.org/#concept-shadow-including-descendant
  57. // “An object A is a shadow-including descendant of an object B, if A is a descendant of B, or A’s root is a shadow root and A’s root’s host is a shadow-including inclusive descendant of B.”
  58. export function isShadowIncludingDescendant(nodeA, nodeB) {
  59. if (isDescendant(nodeA, nodeB))
  60. return true;
  61. const nodeARoot = nodeA.getRootNode();
  62. if (nodeARoot instanceof ShadowRoot && isShadowIncludingInclusiveDescendant(nodeARoot.host, nodeB))
  63. return true;
  64. return false;
  65. }
  66. // https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-descendant
  67. // “A shadow-including inclusive descendant is an object or one of its shadow-including descendants.”
  68. export function isShadowIncludingInclusiveDescendant(nodeA, nodeB) {
  69. if (nodeA === nodeB)
  70. return true;
  71. if (isShadowIncludingDescendant(nodeA, nodeB))
  72. return true;
  73. return false;
  74. }
  75. // https://dom.spec.whatwg.org/#concept-shadow-including-ancestor
  76. // “An object A is a shadow-including ancestor of an object B, if and only if B is a shadow-including descendant of A.”
  77. export function isShadowIncludingAncestor(nodeA, nodeB) {
  78. return isShadowIncludingDescendant(nodeB, nodeA);
  79. }
  80. // https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor
  81. // “A shadow-including inclusive ancestor is an object or one of its shadow-including ancestors.”
  82. export function isShadowIncludingInclusiveAncestor(nodeA, nodeB) {
  83. if (nodeA === nodeB)
  84. return true;
  85. if (isShadowIncludingAncestor(nodeA, nodeB))
  86. return true;
  87. return false;
  88. }
  89. // https://dom.spec.whatwg.org/#concept-cd-substring
  90. // “To substring data with node node, offset offset, and count count, run these steps:”
  91. export function substringData(node, // XXX The spec says “node node”, but reads “node’s data” which is only defined for CharacterData nodes.
  92. offset, count) {
  93. // 1. “Let length be node’s length.”
  94. const length = nodeLength(node);
  95. // 2. “If offset is greater than length, then throw an "IndexSizeError" DOMException.”
  96. if (offset > length)
  97. throw new DOMException('', 'IndexSizeError');
  98. // 3. “If offset plus count is greater than length, return a string whose value is the code units from the offsetth code unit to the end of node’s data, and then return.”
  99. if (offset + count > length) {
  100. return node.data.substring(offset);
  101. }
  102. // TODO verify: “Return a string whose value is the code units from the offsetth code unit to the offset+countth code unit in node’s data.”
  103. return node.data.substring(offset, offset + count);
  104. }
  105. //# sourceMappingURL=whatwg-dom.js.map