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 <[email protected]> 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;
