diff --git a/index.bs b/index.bs index cfc38bd4..63eb447d 100644 --- a/index.bs +++ b/index.bs @@ -45,6 +45,7 @@ spec: WEBDRIVER; urlPrefix: https://w3c.github.io/webdriver/ text: intermediary node; url: dfn-intermediary-node text: invalid argument; url: dfn-invalid-argument text: unknown command; url: dfn-unknown-command + text: unknown error; url: dfn-unknown-error text: no such element; url: dfn-no-such-element text: no such frame; url: dfn-no-such-frame text: active sessions; url: dfn-active-session @@ -100,6 +101,7 @@ spec: HTML; urlPrefix: https://html.spec.whatwg.org/ text: create a new browsing context; url: creating-a-new-browsing-context text: environment settings object's Realm; url: environment-settings-object's-realm text: handled; url: concept-error-handled + text: navigation id; url: concept-navigation-id text: report an error; url: report-the-error text: remove a browsing context; url: bcg-remove text: session history; url: session-history @@ -130,6 +132,45 @@ This specification depends on the Infra Standard. [[!INFRA]] Network protocol messages are defined using CDDL. [[!RFC8610]] +This specification defines a wait queue which is a map. + +Issue: Surely there's a better mechanism for doing this "wait for an event" thing. + +
+ +When an algorithm |algorithm| running [=in parallel=] awaits a set of +events |events|, and |resume id|: + +1. Pause the execution of |algorithm|. + +1. Assert: [=wait queue=] does not contain |resume id|. + +1. Set [=wait queue=][|resume id|] to (|events|, |algorithm|). + +
+ +
+To resume given |name|, |id| and |parameters|: + +1. If [=wait queue=] does not contain |id|, return. + +1. Let (|events|, |algorithm|) be [=wait queue=][|id|] + +1. For each |event| in |events|: + + 1. If |event| equals |name|: + + 1. Remove |id| from [=wait queue=]. + + 1. Resume running the steps in |algorithm| from the + point at which they were paused, passing |name| and |parameters| as the + result of the [=await=]. + + Issue: Should we have something like microtasks to ensure this runs + before any other tasks on the event loop? + +
+ # Protocol # {#protocol} This section defines the basic concepts of the WebDriver BiDi @@ -1631,24 +1672,56 @@ The [=remote end steps=] with |command parameters| are: The browsingContext module contains commands and events relating to browsing contexts. +The progress of navigation is communicated using an immutable WebDriver +navigation status struct, which has the following items: + +
+
id
+
The [=navigation id=] for the navigation, or null when the navigation is + canceled before making progress.
+ +
status
+
A status code that is either + "canceled", + "pending", or + "complete". +
+ +
url
+
The URL which is being loaded in the navigation
+
+ ### Definition ### {#module-browsingContext-definition} [=remote end definition=]
 
-BrowsingContextCommand = (BrowsingContextGetTreeCommand)
+BrowsingContextCommand = (
+    BrowsingContextGetTreeCommand //
+    BrowsingContextNavigateCommand
+)
 
[=local end definition=]
 
-BrowsingContextResult = (BrowsingContextGetTreeResult)
+BrowsingContextResult = (
+    BrowsingContextGetTreeResult //
+    BrowsingContextNavigateResult
+)
 
 BrowsingContextEvent = (
     BrowsingContextCreatedEvent //
-    BrowsingContextDestroyedEvent
+    BrowsingContextDestroyedEvent //
+    BrowsingContextNavigationStartedEvent //
+    BrowsingContextFragmentNavigatedEvent //
+    BrowsingContextDomContentLoadedEvent //
+    BrowsingContextLoadEvent //
+    BrowsingContextDownloadWillBegin //
+    BrowsingContextNavigationAbortedEvent //
+    BrowsingContextNavigationFailedEvent
 )
 
 
@@ -1703,7 +1776,8 @@ BrowsingContextInfo = { The BrowsingContextInfo type represents the properties of a browsing context. -
To get the browsing context info given |context|, +
+To get the browsing context info given |context|, |depth| and |max depth|: 1. Let |context id| be the [=browsing context id=] for |context|. @@ -1758,9 +1832,54 @@ browsing context.
+#### The browsingContext.Navigation Type #### {#type-browsingContext-Navigation} + +[=remote end definition=] and [=local end definition=] + +
+Navigation = text;
+
+ +The Navigation type is a unique string identifying an ongoing +navigation. + +TODO: Link to the definition in the HTML spec. + + +#### The browsingContext.NavigationInfo Type #### {#type-browsingContext-NavigationInfo} + +[=local end definition=]: + +
+NavigationInfo = {
+  context: BrowsingContext,
+  navigation: Navigation / null,
+  url: text,
+}
+
+ +The NavigationInfo type provides details of an ongoing navigation. + +
+To get the navigation info, given |context| and |navigation status|: + +1. Let |context id| be the [=browsing context id=] for |context|. + +1. Let |navigation id| be |navigation status|'s id. + +1. Let |url| be |navigation status|'s url. + +1. Return a [=map=] matching the + NavigationInfo production, with the + context field set to |context id|, the navigation + field set to |navigation id|, and the url field set to the + result of the [=URL serializer=] given |url|. + +
+ ### Commands ### {#module-browsingContext-commands} -#### The browsingContext.getTree Command #### {#command-browsingContext-list} +#### The browsingContext.getTree Command #### {#command-browsingContext-getTree} The browsingContext.getTree command returns a tree of all browsing contexts that are descendents of the given context, or all @@ -1812,6 +1931,156 @@ The [=remote end steps=] with |command parameters| are:
+#### The browsingContext.navigate Command #### {#command-browsingContext-navigate} + +The browsingContext.navigate command navigates a +browsing context to the given URL. + +
+
Command Type
+
+
+      BrowsingContextNavigateCommand = {
+        method: "browsingContext.navigate",
+        params: BrowsingContextNavigateParameters
+      }
+
+      BrowsingContextNavigateParameters = {
+        context: BrowsingContext,
+        url: text,
+        ?wait: ReadinessState,
+      }
+
+       ReadinessState = "none" / "interactive" / "complete"
+      
+
+
Return Type
+
+
+        BrowsingContextNavigateResult = {
+            navigation: Navigation / null,
+            url: text,
+        }
+    
+
+
+ +
+The [=remote end steps=] with |command parameters| are: + + 1. Let |context id| be the value of the context field of + |command parameters|. + + 1. Let |context| be the result of [=trying=] to [=get a browsing context=] + with |context id|. + + 1. Assert: |context| is not null. + + 1. Let |wait condition| be the value of the wait field of |command + parameters| if present, or "none" otherwise. + + 1. Let |url| be the value of the url field of |command + parameters|. + + 1. Let |document| be |context|'s [=active document=]. + + 1. Let |base| be |document|'s [=base URL=]. + + 1. Let |url record| be the result of applying the [=URL parser=] to |url|, + with [=base URL=] |base|. + + 1. If |url record| is failure, return [=error=] with [=error code=] [=invalid + argument=]. + + 1. Let |request| be a new [=/request=] whose URL is |url record|. + + 1. Let |navigation id| be the string representation of a + [[!RFC4122|UUID]] based on truly random, or pseudo-random numbers. + + 1. [=Navigate=] |context| with resource |request|, and using |context| as the + [=source browsing context=], and with navigation id |navigation id|. + + 1. Let (|event received|, |navigate status|) be [=await=] given + «"navigation started", "navigation failed", + and "fragment navigated"» and |navigation id|. + + 1. Assert: |navigate status|'s id is |navigation id|. + + 1. If |navigate status|'s status is "complete": + + 1. Let |body| be a [=map=] matching the + BrowsingContextNavigateResult production, with the + navigation field set to |navigation id|, and the + url field set to the result of the [=URL serializer=] given + |navigate status|'s url. + + 1. Return [=success=] with data |body|, and then run the following steps [=in + parallel=]: + + 1. Run the [=WebDriver-BiDi fragment navigated=] steps given |context| + and |navigate status| + + Note: this is the case if the navigation only caused the fragment to + change. The parallel steps here ensure that we return the command result + before emitting the event, so the navigation id is known. + + 1. If |navigate status|'s status is "canceled" return [=error=] + with [=error code=] [=unknown error=]. + + TODO: is this the right way to handle errors here? + + 1. Assert: |navigate status|'s status is "pending" and + |navigation id| is not null. + + 1. If |wait condition| is "none": + + 1. Let |body| be a [=map=] matching the + BrowsingContextNavigateResult production, with the + navigation field set to |navigation id|, and the + url field set to the result of the [=URL serializer=] given + |navigate status|'s url. + + 1. Return [=success=] with data |body|, and then run the following steps [=in + parallel=]: + + 1. Run the [=WebDriver-BiDi navigation started=] steps given |context| + and |navigate status| + + 1. Run the [=WebDriver-BiDi navigation started=] steps given |context| + and |navigate status| + + Note: this event was previously suppressed to ensure that it would come + after the command response in the case that |wait condition| is + "none". + + Issue: Replace this suppression mechanism with an event queue. + + 1. If |wait condition| is "interactive", let |event name| be + "domContentLoaded", otherwise let |event name| be + "load". + + 1. Let (|event received|, |status|) be [=await=] given «|event name|, + "download started", "navigation aborted", + "navigation failed"» and |navigation id|. + + 1. If |event received| is "navigation failed" + return [=error=] with [=error code=] [=unknown error=]. + + Issue: Are we surfacing enough information about what failed and why with + an error here? What error code do we want? Is there going to be a problem + where local ends parse the implementation-defined strings to figure out + what actually went wrong? + + 1. Let |body| be a [=map=] matching the + BrowsingContextNavigateResult production, with the + navigation field set to |status|'s id, and the + url field set to the result of the [=URL serializer=] given + |status|'s url. + + 1. Return [=success=] with data |body|. + +
+ ### Events ### {#module-contexts-events} #### The browsingContext.contextCreated Event #### {#event-browsingContext-contextCreated} @@ -1898,7 +2167,7 @@ The [=remote end event trigger=] is:
-Run the following [=browsing context tree discarded=] steps: +Define the following [=browsing context tree discarded=] steps: 1. If the [=current session=] is null, return. @@ -1923,6 +2192,270 @@ contexts that have active documents; navigation can also cause contexts to become inaccessible but not yet get discarded because bfcache.
+#### The browsingContext.navigationStarted Event #### {#event-browsingContext-navigationStarted} + +
+
Event Type
+
+
+        BrowsingContextNavigationStartedEvent = {
+         method: "browsingContext.navigationStarted",
+         params: NavigationInfo
+       }
+      
+
+
+ +
+The [=remote end event trigger=] is the WebDriver-BiDi navigation +started steps given |context| and |navigation status|: + + 1. If the [=current session=] is null, return. + + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. + + 1. Let |body| be a [=map=] matching the + BrowsingContextNavigationStarted production, with the + params field set to |params|. + + 1. Let |navigation id| be |navigation status|'s id. + + 1. Let |related browsing contexts| be a set containing |context|. + + 1. [=Resume=] with "navigation started", |navigation id|, and + |navigation status|. + + 1. [=Emit an event=] with |body| and |related browsing contexts|. + +
+ +#### The browsingContext.fragmentNavigated Event #### {#event-browsingContext-fragmentNavigated} + +
+
Event Type
+
+
+        BrowsingContextFragmentNavigatedEvent = {
+         method: "browsingContext.fragmentNavigated",
+         params: NavigationInfo
+       }
+      
+
+
+ +
+The [=remote end event trigger=] is the WebDriver-BiDi fragment +navigated steps given |context| and |navigation status|: + + 1. If the [=current session=] is null, return. + + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. + + 1. Let |body| be a [=map=] matching the + BrowsingContextFragmentNavigatedEvent production, with the + params field set to |params|. + + 1. Let |navigation id| be |navigation status|'s id. + + 1. Let |related browsing contexts| be a set containing |context|. + + 1. [=Resume=] with "fragment navigated", |navigation id|, and + |navigation status|. + + 1. [=Emit an event=] with |body| and |related browsing contexts|. + +
+ +#### The browsingContext.domContentLoaded Event #### {#event-browsingContext-domContentLoaded} + +
+
Event Type
+
+
+        BrowsingContextDomContentLoadedEvent = {
+         method: "browsingContext.domContentLoaded",
+         params: NavigationInfo
+       }
+      
+
+
+ +
+The [=remote end event trigger=] is the WebDriver-BiDi DOM content +loaded steps given |context| and |navigation status|: + + 1. If the [=current session=] is null, return. + + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. + + 1. Let |body| be a [=map=] matching the + BrowsingContextDomContentLoadedEvent production, with the + params field set to |params|. + + 1. Let |related browsing contexts| be a set containing |context|. + + 1. Let |navigation id| be |navigation status|'s id. + + 1. [=Resume=] with "domContentLoaded", |navigation id|, and + |navigation status|. + + 1. [=Emit an event=] with |body| and |related browsing contexts|. + +
+ +#### The browsingContext.load Event #### {#event-browsingContext-load} + +
+
Event Type
+
+
+        BrowsingContextLoadEvent = {
+         method: "browsingContext.load",
+         params: NavigationInfo
+       }
+      
+
+
+ +
+The [=remote end event trigger=] is the WebDriver-BiDi load +complete steps given |context| and |navigation status|: + + 1. If the [=current session=] is null, return. + + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. + + 1. Let |body| be a [=map=] matching the BrowsingContextLoadEvent + production, with the params field set to |params|. + + 1. Let |related browsing contexts| be a set containing |context|. + + 1. Let |navigation id| be |navigation status|'s id. + + 1. [=Resume=] with "load", |navigation id| and + |navigation status|. + + 1. [=Emit an event=] with |body| and |related browsing contexts|. + +
+ +#### The browsingContext.downloadWillBegin Event #### {#event-browsingContext-downoadWillBegin} + +
+
Event Type
+
+
+        BrowsingContextDownloadWillBegin = {
+         method: "browsingContext.downloadWillBegin",
+         params: NavigationInfo
+       }
+      
+
+
+ +
+The [=remote end event trigger=] is the WebDriver-BiDi download +started steps given |context| and |navigation status|: + + 1. If the [=current session=] is null, return. + + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. + + 1. Let |body| be a [=map=] matching the + BrowsingContextDownloadWillBegin production, with the + params field set to |params|. + + 1. Let |navigation id| be |navigation status|'s id. + + 1. Let |related browsing contexts| be a set containing |context|. + + 1. [=Resume=] with "download started", |navigation id|, and |navigation status|. + + 1. [=Emit an event=] with |body| and |related browsing contexts|. + +
+ +#### The browsingContext.navigationAborted Event #### {#event-browsingContext-navigationAborted} + +
+
Event Type
+
+
+        BrowsingContextNavigationAborted = {
+         method: "browsingContext.navigationAborted",
+         params: NavigationInfo
+       }
+      
+
+
+ +
+The [=remote end event trigger=] is the WebDriver-BiDi navigation +aborted steps given |context| and |navigation status|: + + 1. If the [=current session=] is null, return. + + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. + + 1. Let |body| be a [=map=] matching the + BrowsingContextNavigationAborted production, with the + params field set to |params|. + + 1. Let |navigation id| be |navigation status|'s id. + + 1. Let |related browsing contexts| be a set containing |context|. + + 1. [=Resume=] with "navigation aborted", |navigation id|, and |navigation status|. + + 1. [=Emit an event=] with |body| and |related browsing contexts|. + +
+ + +#### The browsingContext.navigationFailed Event #### {#event-browsingContext-navigationFailed} + +
+
Event Type
+
+
+        BrowsingContextNavigationFailed = {
+         method: "browsingContext.navigationFailed",
+         params: NavigationInfo
+       }
+      
+
+
+ +
+The [=remote end event trigger=] is the WebDriver-BiDi navigation +failed steps given |context| and |navigation status|: + + 1. If the [=current session=] is null, return. + + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. + + 1. Let |body| be a [=map=] matching the + BrowsingContextNavigationFailed production, with the + params field set to |params|. + + 1. Let |navigation id| be |navigation status|'s id. + + 1. Let |related browsing contexts| be a set containing |context|. + + 1. [=Resume=] with "navigation failed", |navigation id|, and |navigation status|. + + 1. [=Emit an event=] with |body| and |related browsing contexts|. + +
+ + ## The script Module ## {#module-script} The script module contains commands and events @@ -2621,7 +3154,7 @@ The [=a browsing context is discarded=] algorithm is modified to read as follows To discard a browsing context |browsingContext|, run these steps: 1. If this is not a recursive invocation of this algorithm, call any browsing context - tree discarded steps defined in external specifications with |browsingContext|. + tree discarded steps defined in other applicable specifications with |browsingContext|. 1. Discard all {{Document}} objects for all the entries in |browsingContext|'s [=session history=].