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

gerben pushed a commit to branch allow-node-as-scope
in repository https://gitbox.apache.org/repos/asf/incubator-annotator.git

commit ed9d1b9f33b9f232e8704fd00c48ecd7cb046ce7
Author: Gerben <[email protected]>
AuthorDate: Fri Jun 4 19:38:39 2021 +0200

    Make css matcher also accept a Node as scope
---
 packages/dom/src/css.ts                            | 10 ++++----
 packages/dom/src/owner-document.ts                 | 17 ++++++++++---
 ...{owner-document.ts => range-node-conversion.ts} | 28 ++++++++++++++++++----
 3 files changed, 44 insertions(+), 11 deletions(-)

diff --git a/packages/dom/src/css.ts b/packages/dom/src/css.ts
index 038698e..143da9e 100644
--- a/packages/dom/src/css.ts
+++ b/packages/dom/src/css.ts
@@ -21,6 +21,7 @@
 import optimalSelect from 'optimal-select';
 import type { CssSelector, Matcher } from '@apache-annotator/selector';
 import { ownerDocument } from './owner-document';
+import { toRange } from './range-node-conversion';
 
 /**
  * Find the elements corresponding to the given {@link
@@ -45,16 +46,17 @@ import { ownerDocument } from './owner-document';
  * > “If […] the user agent discovers multiple matching text sequences, then 
the
  * > selection SHOULD be treated as matching all of the matches.”
  *
- * @param selector - The {@link CssSelector} to be anchored
- * @returns A {@link Matcher} function that applies `selector` to a given 
{@link https://developer.mozilla.org/en-US/docs/Web/API/Range
- * | Range}
+ * @param selector - The {@link CssSelector} to be anchored.
+ * @returns A {@link Matcher} function that applies `selector` to a given
+ * `scope`.
  *
  * @public
  */
 export function createCssSelectorMatcher(
   selector: CssSelector,
-): Matcher<Range, Element> {
+): Matcher<Node | Range, Element> {
   return async function* matchAll(scope) {
+    scope = toRange(scope);
     const document = ownerDocument(scope);
     for (const element of document.querySelectorAll(selector.value)) {
       const range = document.createRange();
diff --git a/packages/dom/src/owner-document.ts 
b/packages/dom/src/owner-document.ts
index 1c0621e..fe7818a 100644
--- a/packages/dom/src/owner-document.ts
+++ b/packages/dom/src/owner-document.ts
@@ -18,8 +18,19 @@
  * under the License.
  */
 
-export function ownerDocument(range: Range): Document {
-  const { startContainer } = range;
+/**
+ * Get the ownerDocument for either a range or a node.
+ *
+ * @param nodeOrRange the node or range for which to get the owner document.
+ */
+export function ownerDocument(nodeOrRange: Node | Range): Document {
+  const node = isRange(nodeOrRange)
+    ? nodeOrRange.startContainer
+    : nodeOrRange;
   // node.ownerDocument is null iff node is itself a Document.
-  return startContainer.ownerDocument ?? (startContainer as Document);
+  return node.ownerDocument ?? (node as Document);
+}
+
+function isRange(nodeOrRange: Node | Range): nodeOrRange is Range {
+  return ('startContainer' in nodeOrRange);
 }
diff --git a/packages/dom/src/owner-document.ts 
b/packages/dom/src/range-node-conversion.ts
similarity index 53%
copy from packages/dom/src/owner-document.ts
copy to packages/dom/src/range-node-conversion.ts
index 1c0621e..fd62543 100644
--- a/packages/dom/src/owner-document.ts
+++ b/packages/dom/src/range-node-conversion.ts
@@ -18,8 +18,28 @@
  * under the License.
  */
 
-export function ownerDocument(range: Range): Document {
-  const { startContainer } = range;
-  // node.ownerDocument is null iff node is itself a Document.
-  return startContainer.ownerDocument ?? (startContainer as Document);
+import { ownerDocument } from "./owner-document";
+
+/**
+ * Returns a range that exactly selects the contents of the given node.
+ *
+ * This function is idempotent: If the given argument is already a range, it
+ * simply returns that range.
+ *
+ * @param nodeOrRange The node/range to convert to a range if it is not already
+ * a range.
+ */
+export function toRange(nodeOrRange: Node | Range): Range {
+  if (isRange(nodeOrRange)) {
+    return nodeOrRange;
+  } else {
+    const node = nodeOrRange;
+    const range = ownerDocument(node).createRange();
+    range.selectNodeContents(node);
+    return range;
+  }
+}
+
+function isRange(nodeOrRange: Node | Range): nodeOrRange is Range {
+  return ('startContainer' in nodeOrRange);
 }

Reply via email to