This is an automated email from the ASF dual-hosted git repository. gerben pushed a commit to branch improve-range-stuff in repository https://gitbox.apache.org/repos/asf/incubator-annotator.git
commit 2be85b60f215851808a92ebabbbeaf3424b32cff Author: Gerben <[email protected]> AuthorDate: Thu Jun 25 23:40:54 2020 +0200 WIP reimplement range iteration --- packages/dom/src/text-iterator.ts | 64 +++++++++++++++++++++++++++++++++ packages/dom/src/text-quote/describe.ts | 25 ++----------- 2 files changed, 66 insertions(+), 23 deletions(-) diff --git a/packages/dom/src/text-iterator.ts b/packages/dom/src/text-iterator.ts new file mode 100644 index 0000000..53e8732 --- /dev/null +++ b/packages/dom/src/text-iterator.ts @@ -0,0 +1,64 @@ +/** + * @license + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +interface TextRange extends Range { + // We guarantee that to always have Text nodes as start and end containers. + readonly startContainer: Text; + readonly endContainer: Text; + cloneRange(): TextRange; + + // Allow only Text nodes to be passed to these methods. + insertNode(node: Text): void; + selectNodeContents(node: Text): void; + setEnd(node: Text, offset: number): void; + setStart(node: Text, offset: number): void; + + // Do not allow these methods to be used at all. + selectNode(node: never): void; + setEndAfter(node: never): void; + setEndBefore(node: never): void; + setStartAfter(node: never): void; + setStartBefore(node: never): void; + surroundContents(newParent: never): void; +} + +function shrinkRangeToTextNodes(range: Range): TextRange { + // TODO walk to first & last text nodes inside the range. + return range as TextRange; +} + +class TextIterator { + constructor(range: Range) { + const iter = document.createNodeIterator( + range.commonAncestorContainer, + NodeFilter.SHOW_TEXT, + { + acceptNode: node => + range.intersectsNode(node) + ? NodeFilter.FILTER_ACCEPT + : NodeFilter.FILTER_REJECT + }, + ); + + // Move to the start of the first text node (if any). + if (iter.nextNode()) + iter.previousNode(); + } +} diff --git a/packages/dom/src/text-quote/describe.ts b/packages/dom/src/text-quote/describe.ts index 15749c9..0cc1760 100644 --- a/packages/dom/src/text-quote/describe.ts +++ b/packages/dom/src/text-quote/describe.ts @@ -148,29 +148,8 @@ function getRangeTextPosition(range: Range, scope: DomScope): number { }, ); const scopeOffset = isTextNode(scopeAsRange.startContainer) ? scopeAsRange.startOffset : 0; - if (isTextNode(range.startContainer)) - return seek(iter, range.startContainer) + range.startOffset - scopeOffset; - else - return seek(iter, firstTextNodeInRange(range)) - scopeOffset; -} - -function firstTextNodeInRange(range: Range): Text { - // Find the first text node inside the range. - const iter = document.createNodeIterator( - range.commonAncestorContainer, - NodeFilter.SHOW_TEXT, - { - acceptNode(node: Text) { - // Only reveal nodes within the range; and skip any empty text nodes. - return range.intersectsNode(node) && node.length > 0 - ? NodeFilter.FILTER_ACCEPT - : NodeFilter.FILTER_REJECT - }, - }, - ); - const node = iter.nextNode() as Text | null; - if (node === null) throw new Error('Range contains no text nodes'); - return node; + const rangeOffset = isTextNode(range.startContainer) ? range.startOffset : 0; + return seek(iter, range.startContainer) + rangeOffset - scopeOffset; } function isTextNode(node: Node): node is Text {
