You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@annotator.apache.org by ge...@apache.org on 2020/10/13 20:59:39 UTC

[incubator-annotator] 04/05: Turn seek into Seeker class

This is an automated email from the ASF dual-hosted git repository.

gerben pushed a commit to branch import-dom-seek
in repository https://gitbox.apache.org/repos/asf/incubator-annotator.git

commit c442273f6eb527ae8fcd84ac8b9eaccabfcbff7a
Author: Gerben <ge...@treora.com>
AuthorDate: Fri Oct 9 22:07:56 2020 +0200

    Turn seek into Seeker class
    
    So it can just contain its NodeIterator.
---
 packages/dom/src/seek.ts                | 124 +++++++++++++++++---------------
 packages/dom/src/text-position/match.ts |  23 ++----
 packages/dom/src/text-quote/describe.ts |  19 ++---
 packages/dom/src/text-quote/match.ts    |  23 ++----
 4 files changed, 81 insertions(+), 108 deletions(-)

diff --git a/packages/dom/src/seek.ts b/packages/dom/src/seek.ts
index 3a707ed..c8f77ad 100644
--- a/packages/dom/src/seek.ts
+++ b/packages/dom/src/seek.ts
@@ -1,75 +1,81 @@
-const E_END = 'Iterator exhausted before seek ended.';
-const E_SHOW = 'Argument 1 of seek must use filter NodeFilter.SHOW_TEXT.';
-const E_WHERE = 'Argument 2 of seek must be an integer or a Text Node.';
-
-const DOCUMENT_POSITION_PRECEDING = 2;
-const SHOW_TEXT = 4;
-const TEXT_NODE = 3;
-
-export default function seek(iter: NodeIterator, where: number | Text): number {
-  if (iter.whatToShow !== SHOW_TEXT) {
-    let error: Error & { code?: number };
-
-    // istanbul ignore next
-    try {
-      error = new DOMException(E_SHOW, 'InvalidStateError');
-    } catch {
-      error = new Error(E_SHOW);
-      error.code = 11;
-      error.name = 'InvalidStateError';
-      error.toString = () => `InvalidStateError: ${E_SHOW}`;
-    }
+import { ownerDocument } from "./owner-document";
 
-    throw error;
+const E_END = 'Iterator exhausted before seek ended.';
+const E_WHERE = 'Argument of seek must be an integer or a Text Node.';
+
+export class Seeker {
+  iter: NodeIterator;
+
+  constructor(scope: Range) {
+    const document = ownerDocument(scope);
+    this.iter = document.createNodeIterator(
+      scope.commonAncestorContainer,
+      NodeFilter.SHOW_TEXT,
+      {
+        acceptNode(node: Text) {
+          return scope.intersectsNode(node)
+            ? NodeFilter.FILTER_ACCEPT
+            : NodeFilter.FILTER_REJECT;
+        },
+      },
+    );
   }
 
-  let count = 0;
-  let node: Node | null = iter.referenceNode;
-  let predicates = null;
-
-  if (isInteger(where)) {
-    predicates = {
-      forward: () => count < where,
-      backward: () => count > where || !iter.pointerBeforeReferenceNode,
-    };
-  } else if (isText(where)) {
-    predicates = {
-      forward: before(node, where) ? () => false : () => node !== where,
-      backward: () => node !== where || !iter.pointerBeforeReferenceNode,
-    };
-  } else {
-    throw new TypeError(E_WHERE);
+  getCurrentNode() {
+    return this.iter.referenceNode;
   }
 
-  while (predicates.forward()) {
-    node = iter.nextNode();
+  seek(where: number | Text): number {
+    const iter = this.iter;
+
+    let count = 0;
+    let node: Node | null = iter.referenceNode;
+    let predicates = null;
+
+    if (isInteger(where)) {
+      predicates = {
+        forward: () => count < where,
+        backward: () => count > where || !iter.pointerBeforeReferenceNode,
+      };
+    } else if (isText(where)) {
+      predicates = {
+        forward: before(node, where) ? () => false : () => node !== where,
+        backward: () => node !== where || !iter.pointerBeforeReferenceNode,
+      };
+    } else {
+      throw new TypeError(E_WHERE);
+    }
+
+    while (predicates.forward()) {
+      node = iter.nextNode();
 
-    if (node === null) {
-      throw new RangeError(E_END);
+      if (node === null) {
+        throw new RangeError(E_END);
+      }
+
+      count += (node as Text).data.length;
     }
 
-    count += (node as Text).data.length;
-  }
+    if (iter.nextNode()) {
+      node = iter.previousNode();
+    }
 
-  if (iter.nextNode()) {
-    node = iter.previousNode();
-  }
+    while (predicates.backward()) {
+      node = iter.previousNode();
 
-  while (predicates.backward()) {
-    node = iter.previousNode();
+      if (node === null) {
+        throw new RangeError(E_END);
+      }
 
-    if (node === null) {
-      throw new RangeError(E_END);
+      count -= (node as Text).data.length;
     }
 
-    count -= (node as Text).data.length;
-  }
+    if (!isText(iter.referenceNode)) {
+      throw new RangeError(E_END);
+    }
 
-  if (!isText(iter.referenceNode)) {
-    throw new RangeError(E_END);
+    return count;
   }
-
-  return count;
 }
 
 function isInteger(n: any): n is number {
@@ -78,9 +84,9 @@ function isInteger(n: any): n is number {
 }
 
 function isText(node: Node): node is Text {
-  return node.nodeType === TEXT_NODE;
+  return node.nodeType === Node.TEXT_NODE;
 }
 
 function before(ref: Node, node: Node): boolean {
-  return !!(ref.compareDocumentPosition(node) & DOCUMENT_POSITION_PRECEDING);
+  return !!(ref.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_PRECEDING);
 }
diff --git a/packages/dom/src/text-position/match.ts b/packages/dom/src/text-position/match.ts
index 00acd4c..7a57226 100644
--- a/packages/dom/src/text-position/match.ts
+++ b/packages/dom/src/text-position/match.ts
@@ -20,7 +20,7 @@
 
 import type { Matcher, TextPositionSelector } from '@annotator/selector';
 import { ownerDocument } from '../owner-document';
-import seek from '../seek';
+import { Seeker } from '../seek';
 
 export function createTextPositionSelectorMatcher(
   selector: TextPositionSelector,
@@ -31,18 +31,7 @@ export function createTextPositionSelectorMatcher(
 
     const { start, end } = selector;
 
-    const iter = document.createNodeIterator(
-      scope.commonAncestorContainer,
-      NodeFilter.SHOW_TEXT,
-      {
-        acceptNode(node: Text) {
-          // Only reveal nodes within the range; and skip any empty text nodes.
-          return scope.intersectsNode(node) && node.length > 0
-            ? NodeFilter.FILTER_ACCEPT
-            : NodeFilter.FILTER_REJECT;
-        },
-      },
-    );
+    const seeker = new Seeker(scope);
 
     // The index of the first character of iter.referenceNode inside the text.
     let referenceNodeIndex = isTextNode(scope.startContainer)
@@ -57,12 +46,12 @@ export function createTextPositionSelectorMatcher(
     const match = document.createRange();
 
     // Seek to the start of the match, make the range start there.
-    referenceNodeIndex += seek(iter, matchStartIndex - referenceNodeIndex);
-    match.setStart(iter.referenceNode, matchStartIndex - referenceNodeIndex);
+    referenceNodeIndex += seeker.seek(matchStartIndex - referenceNodeIndex);
+    match.setStart(seeker.getCurrentNode(), matchStartIndex - referenceNodeIndex);
 
     // Seek to the end of the match, make the range end there.
-    referenceNodeIndex += seek(iter, matchEndIndex - referenceNodeIndex);
-    match.setEnd(iter.referenceNode, matchEndIndex - referenceNodeIndex);
+    referenceNodeIndex += seeker.seek(matchEndIndex - referenceNodeIndex);
+    match.setEnd(seeker.getCurrentNode(), matchEndIndex - referenceNodeIndex);
 
     // Yield the match.
     yield match;
diff --git a/packages/dom/src/text-quote/describe.ts b/packages/dom/src/text-quote/describe.ts
index 514208b..e5846bc 100644
--- a/packages/dom/src/text-quote/describe.ts
+++ b/packages/dom/src/text-quote/describe.ts
@@ -20,7 +20,7 @@
 
 import type { TextQuoteSelector } from '@annotator/selector';
 import { ownerDocument } from '../owner-document';
-import seek from '../seek';
+import { Seeker } from '../seek';
 
 export async function describeTextQuote(
   range: Range,
@@ -120,22 +120,11 @@ function calculateContextForDisambiguation(
 
 // Get the index of the first character of range within the text of scope.
 function getRangeTextPosition(range: Range, scope: Range): number {
-  const iter = ownerDocument(scope).createNodeIterator(
-    scope.commonAncestorContainer,
-    NodeFilter.SHOW_TEXT,
-    {
-      acceptNode(node: Text) {
-        // Only reveal nodes within the range
-        return scope.intersectsNode(node)
-          ? NodeFilter.FILTER_ACCEPT
-          : NodeFilter.FILTER_REJECT;
-      },
-    },
-  );
+  const seeker = new Seeker(scope);
   const scopeOffset = isTextNode(scope.startContainer) ? scope.startOffset : 0;
   if (isTextNode(range.startContainer))
-    return seek(iter, range.startContainer) + range.startOffset - scopeOffset;
-  else return seek(iter, firstTextNodeInRange(range)) - scopeOffset;
+    return seeker.seek(range.startContainer) + range.startOffset - scopeOffset;
+  else return seeker.seek(firstTextNodeInRange(range)) - scopeOffset;
 }
 
 function firstTextNodeInRange(range: Range): Text {
diff --git a/packages/dom/src/text-quote/match.ts b/packages/dom/src/text-quote/match.ts
index c6b769b..6282769 100644
--- a/packages/dom/src/text-quote/match.ts
+++ b/packages/dom/src/text-quote/match.ts
@@ -20,7 +20,7 @@
 
 import type { Matcher, TextQuoteSelector } from '@annotator/selector';
 import { ownerDocument } from '../owner-document';
-import seek from '../seek';
+import { Seeker } from '../seek';
 
 export function createTextQuoteSelectorMatcher(
   selector: TextQuoteSelector,
@@ -34,18 +34,7 @@ export function createTextQuoteSelectorMatcher(
     const suffix = selector.suffix || '';
     const searchPattern = prefix + exact + suffix;
 
-    const iter = document.createNodeIterator(
-      scope.commonAncestorContainer,
-      NodeFilter.SHOW_TEXT,
-      {
-        acceptNode(node: Text) {
-          // Only reveal nodes within the range; and skip any empty text nodes.
-          return scope.intersectsNode(node) && node.length > 0
-            ? NodeFilter.FILTER_ACCEPT
-            : NodeFilter.FILTER_REJECT;
-        },
-      },
-    );
+    const seeker = new Seeker(scope);
 
     // The index of the first character of iter.referenceNode inside the text.
     let referenceNodeIndex = isTextNode(scope.startContainer)
@@ -66,12 +55,12 @@ export function createTextQuoteSelectorMatcher(
       const match = document.createRange();
 
       // Seek to the start of the match, make the range start there.
-      referenceNodeIndex += seek(iter, matchStartIndex - referenceNodeIndex);
-      match.setStart(iter.referenceNode, matchStartIndex - referenceNodeIndex);
+      referenceNodeIndex += seeker.seek(matchStartIndex - referenceNodeIndex);
+      match.setStart(seeker.getCurrentNode(), matchStartIndex - referenceNodeIndex);
 
       // Seek to the end of the match, make the range end there.
-      referenceNodeIndex += seek(iter, matchEndIndex - referenceNodeIndex);
-      match.setEnd(iter.referenceNode, matchEndIndex - referenceNodeIndex);
+      referenceNodeIndex += seeker.seek(matchEndIndex - referenceNodeIndex);
+      match.setEnd(seeker.getCurrentNode(), matchEndIndex - referenceNodeIndex);
 
       // Yield the match.
       yield match;