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 5706821a20472b934fd7a524e2298bd7cb346b9c
Author: Gerben <[email protected]>
AuthorDate: Mon Nov 16 23:01:25 2020 +0100

    Implement describe text position
---
 packages/dom/src/text-position/describe.ts | 74 ++++++++++++++++++++++++++++++
 packages/dom/src/text-position/index.ts    |  1 +
 2 files changed, 75 insertions(+)

diff --git a/packages/dom/src/text-position/describe.ts 
b/packages/dom/src/text-position/describe.ts
new file mode 100644
index 0000000..8baff8d
--- /dev/null
+++ b/packages/dom/src/text-position/describe.ts
@@ -0,0 +1,74 @@
+/**
+ * @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.
+ */
+
+import type { TextPositionSelector } from '@annotator/selector';
+import { ownerDocument } from '../owner-document';
+import { Chunk, Chunker, ChunkRange, TextNodeChunker, PartialTextNode } from 
'../chunker';
+import { CodePointSeeker } from '../code-point-seeker';
+import { TextSeeker, NonEmptyChunker } from '../seek';
+
+export async function describeTextPosition(
+  range: Range,
+  maybeScope?: Range,
+): Promise<TextPositionSelector> {
+  // Default to search in the whole document.
+  let scope: Range;
+  if (maybeScope !== undefined) {
+    scope = maybeScope;
+  } else {
+    const document = ownerDocument(range);
+    scope = document.createRange();
+    scope.selectNodeContents(document);
+  }
+
+  // Take the part of the range that falls within the scope.
+  range = range.cloneRange();
+  if (range.compareBoundaryPoints(Range.START_TO_START, scope) === -1)
+    range.setStart(scope.startContainer, scope.startOffset);
+  if (range.compareBoundaryPoints(Range.END_TO_END, scope) === 1)
+    range.setEnd(scope.endContainer, scope.endOffset);
+
+  const textChunks = new TextNodeChunker(scope);
+  if (textChunks.currentChunk === null)
+    throw new RangeError('Range does not contain any Text nodes.');
+
+  return await abstractDescribeTextPosition(
+    textChunks.rangeToChunkRange(range),
+    textChunks as NonEmptyChunker<PartialTextNode>,
+  );
+}
+
+async function abstractDescribeTextPosition<TChunk extends Chunk<string>>(
+  target: ChunkRange<TChunk>,
+  scope: NonEmptyChunker<TChunk>,
+): Promise<TextPositionSelector> {
+  const codeUnitSeeker = new TextSeeker(scope);
+  const codePointSeeker = new CodePointSeeker(codeUnitSeeker);
+
+  codePointSeeker.seekToChunk(target.startChunk, target.startIndex);
+  const start = codePointSeeker.position;
+  codePointSeeker.seekToChunk(target.endChunk, target.endIndex);
+  const end = codePointSeeker.position;
+  return {
+    type: 'TextPositionSelector',
+    start,
+    end,
+  };
+}
diff --git a/packages/dom/src/text-position/index.ts 
b/packages/dom/src/text-position/index.ts
index 011e994..bb73732 100644
--- a/packages/dom/src/text-position/index.ts
+++ b/packages/dom/src/text-position/index.ts
@@ -18,4 +18,5 @@
  * under the License.
  */
 
+export * from './describe';
 export * from './match';

Reply via email to