Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement browsingContext.locateNodes #547

Merged
merged 86 commits into from
Nov 2, 2023
Merged
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
c7d9020
Implement browsingContext.locateNodes
jimevanssfdc Sep 14, 2023
70815c5
Fixing closing </div> tags
jimevanssfdc Sep 14, 2023
3273c1a
Fix variable usage
jimevanssfdc Sep 14, 2023
841dd88
More variable fixes
jimevanssfdc Sep 14, 2023
02b475d
Missed a variable instance
jimevanssfdc Sep 14, 2023
a44d832
Fixing ignored vars
jimevanssfdc Sep 14, 2023
8d736ff
Fix argument calls to algorithms
jimevanssfdc Sep 14, 2023
d12c49e
Fix typos from initial review
jimevanssfdc Sep 14, 2023
5f86c3e
Move to using script.ContextTarget for location instead of browsingCo…
jimevanssfdc Sep 17, 2023
65e042a
Missed a variable
jimevanssfdc Sep 17, 2023
de398fa
Remove JavaScriptLocator from spec for now
jimevanssfdc Sep 18, 2023
91343e5
Remove Frame locator
jimevanssfdc Sep 18, 2023
1103af6
Complete refactor
jimevanssfdc Sep 18, 2023
f9ad500
Fixing syntax errors
jimevanssfdc Sep 18, 2023
141d1be
Fix variable mixup
jimevanssfdc Sep 18, 2023
e35f766
Fix a variable syntax error
jimevanssfdc Sep 18, 2023
598d1de
Refer to correct variable in get elements by text
jimevanssfdc Sep 18, 2023
bd6084c
Remove unused variable
jimevanssfdc Sep 18, 2023
f6e4a16
Updating variable name to be more succint
jimevanssfdc Sep 18, 2023
2eca140
Fix return variable names to be more succinct
jimevanssfdc Sep 18, 2023
3dea404
Fix scoping root reference
jimevanssfdc Sep 18, 2023
91caa7f
Fix incorrect markup for <dl>
jimevanssfdc Sep 18, 2023
4d05a1d
Add forgotten equals sign
jimevanssfdc Sep 18, 2023
652eee3
Add reference to XPath snapshotItem
jimevanssfdc Sep 18, 2023
52216b4
Cosmetic update to locate using xpath algorithm
jimevanssfdc Sep 18, 2023
d26d4b0
Fix typo for matchCase attribute
jimevanssfdc Sep 18, 2023
2587025
Fix reference to result nodes
jimevanssfdc Sep 18, 2023
f6e6478
Fix return of nodes from CSS
jimevanssfdc Sep 18, 2023
bdfc7ba
Change TextLocator to use RegExp instead of other args
jimevanssfdc Sep 21, 2023
44f19fd
Merge branch 'main' into jimevans/locate-nodes
jimevans Sep 21, 2023
6da2cd8
Fix closing tag typo
jimevanssfdc Sep 21, 2023
7bf6647
Enable returning non-element nodes from XPath
jimevanssfdc Sep 22, 2023
fc0bb31
Missed vertical bar in find by text algorithm
jimevanssfdc Sep 22, 2023
70d5c2e
Tighten up language around calling RegExp.test()
jimevanssfdc Sep 22, 2023
a76f33f
Correct type to NodeRemoteValue
jimevans Sep 25, 2023
12e122c
Fix poor grammar
jimevans Sep 25, 2023
151ea70
Use <code> tag
jimevans Sep 25, 2023
dae6599
Remove erroneous space
jimevans Sep 28, 2023
8497c21
Rename algorithm for finding element by text
jimevanssfdc Oct 5, 2023
c00d75d
Address review comments
jimevanssfdc Oct 5, 2023
870a0b1
Handle review comments
jimevanssfdc Oct 6, 2023
4faf371
Merge branch 'main' into jimevans/locate-nodes
jimevans Oct 6, 2023
19e293e
First pass at replacing arrays with list
jimevanssfdc Oct 6, 2023
4dc30da
Reformat reading of command parameters
jimevanssfdc Oct 6, 2023
122a7a1
Fix syntax
jimevanssfdc Oct 6, 2023
e4605d1
Fix syntax
jimevanssfdc Oct 6, 2023
96d5079
Attempt to resolve locate by text issues
jimevanssfdc Oct 6, 2023
fa10dbc
Reomve unused variable
jimevanssfdc Oct 6, 2023
43752bf
Correct indentation
jimevanssfdc Oct 6, 2023
9d3f6f1
Aligning variable names and logic with property names
jimevanssfdc Oct 6, 2023
8f7d9c0
Fix missed variable name
jimevanssfdc Oct 6, 2023
552f203
Add note to indicate direct calls to XPath algorithms
jimevanssfdc Oct 6, 2023
98cc9f2
Move note into algorithm block
jimevanssfdc Oct 6, 2023
8988a1d
Update index.bs with correct punctuation
jimevans Oct 9, 2023
b97e723
Merge branch 'main' into jimevans/locate-nodes
jimevans Oct 9, 2023
165b4fc
Rename maxNodes to maxReturnedNodeCount
jimevanssfdc Oct 9, 2023
b137ed2
Update find by text algorithm to correctly find elements
jimevanssfdc Oct 10, 2023
9f57155
correct links to list/append
jimevanssfdc Oct 10, 2023
873a9e7
Attempt to specify string operations for locate by text
jimevanssfdc Oct 10, 2023
227da04
Attempt to fix infra links
jimevanssfdc Oct 10, 2023
f0eda02
Trying again to link to infra terms
jimevanssfdc Oct 10, 2023
efefd38
Correct substring case logic
jimevanssfdc Oct 10, 2023
3568ca4
Attempting to specify case-insensitivity in search
jimevanssfdc Oct 10, 2023
2eaa2b4
Link to Unicode spec for toUppercase
jimevanssfdc Oct 10, 2023
b3a2e59
Forgot a location of toUppercase
jimevanssfdc Oct 10, 2023
29a0314
Rename 'find by text' algorithm to 'find by inner text'
jimevanssfdc Oct 11, 2023
5516d01
Missed invocation of algorithm in previous commit
jimevanssfdc Oct 11, 2023
b66e363
Fix variable declaration
jimevanssfdc Oct 11, 2023
3d5b847
Missed location of changing 'text' to 'innerText'
jimevanssfdc Oct 11, 2023
aba2f66
remove extraneous 'return'
jimevanssfdc Oct 11, 2023
35f6a88
clean up command parameter property access
jimevanssfdc Oct 11, 2023
3c3eefd
more command parameter property access cleanup
jimevanssfdc Oct 11, 2023
d0bb5e1
Further grammar cleanup
jimevanssfdc Oct 11, 2023
13586ab
Still more grammar cleanup
jimevanssfdc Oct 11, 2023
a3cea57
Merge branch 'main' into jimevans/locate-nodes
jimevans Oct 12, 2023
297a11f
respond to code review comments
jimevanssfdc Oct 13, 2023
5572041
Add sandbox parameter to command parameters
jimevanssfdc Oct 13, 2023
99837f4
remove extraneous definition
jimevanssfdc Oct 13, 2023
c6f041e
Correct find by inner text algorithm to not early return
jimevanssfdc Oct 15, 2023
c8b7516
correct variable name typo
jimevanssfdc Oct 15, 2023
be123be
fix CDDL definition errors
jimevanssfdc Oct 26, 2023
0d77682
Add editorial change on assert
jimevans Oct 27, 2023
c14f010
Update defintion of 'invalid selector' error code
jimevanssfdc Oct 26, 2023
1d68171
Define behavior of inner text locator on empty string
jimevanssfdc Oct 26, 2023
fe2c9fc
Remove contextId from LocateNodesResult
jimevanssfdc Oct 27, 2023
ae9938d
Removed variable for 'serialization internal map'
jimevanssfdc Oct 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
328 changes: 328 additions & 0 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ spec: WEBDRIVER; urlPrefix: https://w3c.github.io/webdriver/
text: input cancel list; url: dfn-input-cancel-list
text: intermediary node; url: dfn-intermediary-node
text: invalid argument; url: dfn-invalid-argument
text: invalid selector; url: dfn-invalid-selector
text: invalid session id; url: dfn-invalid-session-id
text: is element origin; url: dfn-is-element-origin
text: local end; url: dfn-local-ends
Expand Down Expand Up @@ -145,6 +146,7 @@ spec: ECMASCRIPT; urlPrefix: https://tc39.es/ecma262/
text: realm; url: sec-code-realms
text: running execution context; url: running-execution-context
text: throw completion; url: sec-completion-record-specification-type
text: test; url: #sec-regexp.prototype.test
text: time value; url: sec-time-values-and-time-range
text: undefined; url: sec-undefined-value
spec: GEOMETRY; urlPrefix: https://drafts.fxtf.org/geometry/
Expand Down Expand Up @@ -177,6 +179,7 @@ spec: HTML; urlPrefix: https://html.spec.whatwg.org/multipage/
text: handled; url: webappapis.html#concept-error-handled
text: hidden; url: document-sequences.html#system-visibility-state
text: history handling behavior; url: browsing-the-web.html#history-handling-behavior
text: innerText getter steps; url:dom.html#dom-innertext
text: navigables; url: document-sequences.html#navigables
text: navigation id; url: browsing-the-web.html#navigation-id
text: origin-clean; url: canvas.html#concept-canvas-origin-clean
Expand Down Expand Up @@ -221,7 +224,24 @@ spec: CSSOM-VIEW; urlPrefix: https://drafts.csswg.org/cssom-view/
text: visual viewport; url: #visual-viewport
spec: DOM; urlPrefix: https://dom.spec.whatwg.org/
type: dfn
text: root; url: #concept-tree-root
text: document element; url: #ref-for-dom-document-documentelement
text: evaluate; url: #dom-xpathevaluatorbase-evaluate
text: ORDERED_NODE_SNAPSHOT_TYPE; url: #dom-xpathresult-ordered_node_snapshot_type
text: snapshotItem; url: #dom-xpathresult-snapshotitem
spec: SELECTORS4; urlPrefix: https://drafts.csswg.org/selectors-4/
type: dfn
text: match a selector against a tree; url: #match-a-selector-against-a-tree
text: parse a selector; url: #parse-a-selector
text: scoping root; url: #scoping-root
spec: WEB-IDL; urlPrefix: https://webidl.spec.whatwg.org/
type: dfn
text: DOMException; url: #idl-DOMException
text: SyntaxError; url:#syntaxerror
spec: UNICODE; urlPrefix: https://www.unicode.org/versions/Unicode15.0.0/
type: dfn
text: Unicode Default Case Conversion algorithm; url: ch03.pdf#G34944
text: toUppercase; url: ch03.pdf#G34078
</pre>

<pre class="biblio">
Expand Down Expand Up @@ -1848,6 +1868,7 @@ BrowsingContextCommand = (
browsingContext.Create //
browsingContext.GetTree //
browsingContext.HandleUserPrompt //
browsingContext.LocateNodes //
browsingContext.Navigate //
browsingContext.Print //
browsingContext.Reload //
Expand All @@ -1862,6 +1883,7 @@ BrowsingContextResult = (
browsingContext.CaptureScreenshotResult /
browsingContext.CreateResult /
browsingContext.GetTreeResult /
browsingContext.LocateNodesResult /
browsingContext.NavigateResult /
browsingContext.PrintResult
)
Expand Down Expand Up @@ -2098,6 +2120,39 @@ To <dfn>await a navigation</dfn> given |context|, |request|, |wait condition|, a

</div>

#### The browsingContext.Locator Type #### {#type-browsingContext-Locator}

[=remote end definition=] and [=local end definition=]

<pre class="cddl remote-cddl local-cddl">
browsingContext.Locator = (
jimevans marked this conversation as resolved.
Show resolved Hide resolved
browsingContext.CssLocator /
browsingContext.InnerTextLocator /
browsingContext.XPathLocator
)

browsingContext.CssLocator = {
type: "css",
value: text
}

browsingContext.InnerTextLocator = {
type: "innerText",
value: text,
? ignoreCase: bool
? matchType: "full" / "partial",
? maxDepth: js-uint,
thiagowfx marked this conversation as resolved.
Show resolved Hide resolved
}

browsingContext.XPathLocator = {
type: "xpath",
value: text
}
</pre>

The <code>browsingContext.Locator</code> type provides details on the strategy
for locating a node in a document.

#### The browsingContext.Navigation Type #### {#type-browsingContext-Navigation}

[=remote end definition=] and [=local end definition=]
Expand Down Expand Up @@ -2778,6 +2833,279 @@ The [=remote end steps=] with <var ignore>session</var> and |command parameters|

1. Return [=success=] with data null.

</div>
#### The browsingContext.locateNodes Command #### {#command-browsingContext-locateNodes}
jimevans marked this conversation as resolved.
Show resolved Hide resolved

The <dfn export for=commands>browsingContext.locateNodes</dfn> command returns a
list of all nodes matching the specified locator.

<dl>
<dt>Command Type</dt>
<dd>
<pre class="cddl remote-cddl">
browsingContext.LocateNodes = (
method: "browsingContext.locateNodes",
params: browsingContext.LocateNodesParameters
)

browsingContext.LocateNodesParameters = {
jimevans marked this conversation as resolved.
Show resolved Hide resolved
context: browsingContext.BrowsingContext,
locator: browsingContext.Locator,
? maxNodeCount: (js-uint .ge 1),
? ownership: script.ResultOwnership,
? sandbox: text,
jimevans marked this conversation as resolved.
Show resolved Hide resolved
? serializationOptions: script.SerializationOptions,
? startNodes: [ + script.SharedReference ]
}
</pre>
</dd>
<dt>Result Type</dt>
<dd>
<pre class="cddl local-cddl">
browsingContext.LocateNodesResult = {
nodes: [ * script.NodeRemoteValue ]
}
</pre>
</dd>
</dl>

<div algorithm="locate nodes using CSS">
To <dfn>locate nodes using CSS</dfn> with given |context target|, |context nodes|,
|selector|, |maximum returned node count|, and <var ignore>session</var>:

1. Let |returned nodes| be an empty [=/list=].

1. Let |parse result| be the result of [=parse a selector=] given |selector|.

1. If |parse result| is failure, return [=error=] with [=error code=] [=invalid selector=].

1. For each |context node| of |context nodes|:

1. Let |elements| be the result of [=match a selector against a tree=] with
|parse result| and |context target|’s [=active document=] [=root=] using
[=scoping root=] |context node|.

1. For each |element| in |elements|:

1. [=list/Append=] |element| to |returned nodes|.

1. If |maximum returned node count| is not null and [=list/size=] of
|returned nodes| is equal to |maximum returned node count|,
return |returned nodes|.

1. Return |returned nodes|.

</div>

<div algorithm="locate nodes using XPath">

To <dfn>locate nodes using XPath</dfn> with given |context target|,
|context nodes|, |selector|, |maximum returned node count|, and <var ignore>session</var>:

Note: Owing to the unmaintained state of the XPath specification, this algorithm
is phrased as if making calls to the XPath DOM APIs. However this is to be understood
as equivalent to spec-internal calls directly accessing the underlying algorithms,
without going via the ECMAScript runtime.

1. Let |returned nodes| be an empty [=/list=].

1. For each |context node| of |context nodes|:

1. Let |evaluate result| be the result of calling [=evaluate=] on |context target|'s
[=active document=], with arguments |selector|, |context node|, null,
[=ORDERED_NODE_SNAPSHOT_TYPE=], and null. If this throws a "[=SyntaxError=]"
[=DOMException=], return [=error=] with [=error code=] [=invalid selector=];
otherwise, if this throws any other exception return [=error=] with [=error code=]
[=unknown error=].

1. Let |index| be 0.

1. Let |length| be the result of getting the <code>snapshotLength</code> property
jimevans marked this conversation as resolved.
Show resolved Hide resolved
from |evaluate result|.

1. Repeat, while |index| is less than |length|:

1. Let |node| be the result of calling [=snapshotItem=] with |evaluate result|
as this and |index| as the argument.

1. [=list/Append=] |node| to |returned nodes|.

1. If |maximum returned node count| not null and [=list/size=] of
|returned nodes| is equal to |maximum returned node count|,
return |returned nodes|.

1. Set |index| to |index| + 1.

1. Return |returned nodes|.

</div>

<div algorithm="locate nodes using inner text">
To <dfn>locate nodes using inner text</dfn> with given |context target|, |context nodes|,
|selector|, |max depth|, |match type|, |ignore case|, |maximum returned node count|,
and |session|:

1. If |selector| is the empty string, return [=error=] with [=error code=]
[=invalid selector=].

1. Let |returned nodes| be an empty [=/list=].

1. If |ignore case| is false, let |search text| be |selector|. Otherwise, let
|search text| be the result of [=toUppercase=] with |selector| according
to the [=Unicode Default Case Conversion algorithm=].

1. For each |context node| in |context nodes|:

1. Let |node inner text| be the result of calling the [=innerText getter steps=] with
|context node| as the [=this=] value.

1. If |ignore case| is false, let |node text| be |node inner text|. Otherwise,
let |node text| be the result of [=toUppercase=] with |node inner text|
according to the [=Unicode Default Case Conversion algorithm=].

1. If |search text| is a [=code point substring=] of |node text|, perform the
following steps:

1. Let |child nodes| be an empty [=/list=] and, for each node |child| in the
<a spec=dom>children</a> of |context node|:

1. If |child| implements {{Element}}, [=list/append=] |child| to |child nodes|.

1. If [=list/size=] of |child nodes| is equal to 0 or |max depth| is equal to 0,
perform the following steps:

1. If |match type| is <code>"full"</code> and |node text| [=is=] |search text|,
[=list/append=] |context node| to |returned nodes|.

1. Otherwise, [=list/append=] |context node| to |returned nodes|.

1. Otherwise, perform the following steps:

1. Set |max depth| to |max depth| - 1.

1. Let |child node matches| be the result of [=locate nodes using inner text=]
with |context target|, |child nodes|, |selector|, |max depth|,
|match type|, |ignore case|, |maximum returned node count|, and |session|.

1. If [=list/size=] of |child node matches| is equal to 0 and |match type| is
<code>"partial"</code>, append |context node| to |returned nodes|. Otherwise,
[=list/extend=] |returned nodes| with |child node matches|.

1. If |maximum returned node count| is not null, [=list/remove=] all entries
in |returned nodes| with an index greater than or equal to |maximum returned
node count|.

1. Return |returned nodes|.

</div>

<div algorithm="remote end steps for browsingContext.locateNodes">
The [=remote end steps=] with |session| and |command parameters| are:

1. Let |context id| be |command parameters|["<code>context</code>"].

1. Let |context| be the result of [=trying=] to [=get a browsing context=]
with |context id|.

1. Assert: |context| is not null.

1. If |command parameters| [=map/contains=] "<code>sandbox</code>", let
|sandbox| be |command parameters|["<code>sandbox</code>"]. Otherwise,
let |sandbox| be null.

1. Let |current context target| be the a [=/map=] matching of the
<code>script.ContextTarget</code> production with the
<code>context</code> field set to the [=browsing context id=]
of |context| and the <code>sandbox</code> field set to |sandbox|.

1. Let |realm| be the result of [=trying=] to [=get a realm from a target=]
given |current context target|.

1. Let |locator| be |command parameters|["<code>locator</code>"].

1. If |command parameters| [=map/contains=] "<code>startNodes</code>", let
|start nodes parameter| be |command parameters|["<code>startNodes</code>"].
Otherwise let |start nodes parameter| be null.

1. If |command parameters| [=map/contains=] "<code>maxNodeCount</code>", let
|maximum returned node count| be |command parameters|["<code>maxNodeCount</code>"].
Otherwise, let |maximum returned node count| be null.

1. Let |context nodes| be an empty [=/list=].

1. If |start nodes parameter| is null, [=list/append=] the [=document element=]
of |context|'s [=active document=] to |context nodes|. Otherwise, for each
|serialized start node| in |start nodes parameter|:

1. Let |start node| be the result of [=trying=] to [=deserialize shared reference=] given
|serialized start node|, |realm| and |session|.

1. [=list/Append=] |start node| to |context nodes|.

1. Assert [=list/size=] of |context nodes| is greater than 0.

1. Let |type| be |locator|["<code>type</code>"].

1. In the following list of conditions and associated steps, run the first set
jimevans marked this conversation as resolved.
Show resolved Hide resolved
of steps for which the associated condition is true:

<dl>

<dt>|type| is the string "<code>css</code>"
<dd>
1. Let |selector| be |locator|["<code>value</code>"].

1. Let |result nodes| be a result of [=trying=] to [=locate nodes using css=]
given |current context target|, |context nodes|, |selector|, |maximum returned
nodes| and |session|.

<dt>|type| is the string "<code>xpath</code>"
<dd>
1. Let |selector| be |locator|["<code>value</code>"].

1. Let |result nodes| be a result of [=trying=] to [=locate nodes using xpath=]
given |current context target|, |context nodes|, |selector|, |maximum returned
nodes| and |session|.

<dt>|type| is the string "<code>innerText</code>"
<dd>
1. Let |selector| be |locator|["<code>value</code>"].

1. If |locator| [=map/contains=] <code>maxDepth</code>, let |max depth| be
|locator|["<code>maxDepth</code>"]. Otherwise, let |max depth| be null.

1. If |locator| [=map/contains=] <code>ignoreCase</code>, let |ignore case| be
|locator|["<code>ignoreCase</code>"]. Otherwise, let |ignore case| be false.

1. If |locator| [=map/contains=] <code>matchType</code>, let |match type| be
|locator|["<code>matchType</code>"]. Otherwise, let |match type| be "full".

1. Let |result nodes| be a result of [=trying=] to [=locate nodes using inner text=]
given |current context target|, |context nodes|, |selector|, |max depth|,
|match type|, |ignore case|, |maximum returned node count| and |session|.

jimevans marked this conversation as resolved.
Show resolved Hide resolved
1. Assert: |maximum returned node count| is null or [=list/size=] of |result nodes| is less
than or equal to |maximum returned node count|.

1. If |command parameters| [=map/contains=] "<code>serializationOptions</code>",
let |serialization options| be |command parameters|["<code>serializationOptions</code>"].
Otherwise, let |serialization options| be a [=/map=] matching the
<code>script.SerializationOptions</code> production with the fields
set to their default values.

1. If |command parameters| [=map/contains=] "<code>ownership</code>",
let |result ownership| be |command parameters|["<code>ownership</code>"].
Otherwise, let |result ownership| be "none".

1. Let |serialized nodes| be the result of [=serialize as a remote value=] with
|result nodes|, |serialization options|, |result ownership|, a new [=/map=]
as serialization internal map, |realm| and |session|.

1. Let |result| be a [=/map=] matching the <code>browsingContext.LocateNodesResult</code>
production, with the <code>nodes</code> field set |serialized nodes|.

1. Return [=success=] with data |result|.

</div>

#### The browsingContext.navigate Command #### {#command-browsingContext-navigate}
Expand Down