Skip to content

Commit

Permalink
Add a browsingContext.traverseHistory command
Browse files Browse the repository at this point in the history
This traverses the history by a specified `delta` (e.g. +1 for forward,
or -1 for back). Like other navigation commands the `wait` parameter
controls whether to return as soon as the history traversal starts, or
wait for a specified level of completeness.

Mush like other navigation commands, history traversal is tracked with
a unique navigation id.

Typically history traversal results in a navigation, but in the case
of the history entry being in the bfcache, no navigation is
necessary. In this case any non-"none" value for wait will return once
the `pageshow` event is fired, and the `persisted` attribute of the
return value is set to `true`.

This model differs somewhat from the CDP model where one navigates to
an explicit history entry and failure is only possible if the entry id
is invalid. But back/forwward only seems closer to the use cases we
have, and allowing events to be traced to a specific traversal seems
consistent with the way we handle other navigation-related events.
  • Loading branch information
jgraham committed Jul 30, 2021
1 parent bc60336 commit 39072b4
Showing 1 changed file with 159 additions and 6 deletions.
165 changes: 159 additions & 6 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ spec: HTML; urlPrefix: https://html.spec.whatwg.org/
text: session history; url: session-history
text: set up a window environment settings object; url: set-up-a-window-environment-settings-object
text: set up a worker environment settings object; url: set-up-a-worker-environment-settings-object
text: traverse the history by a delta; url: traverse-the-history-by-a-delta
text: worker event loop; url: worker-event-loop-2
text: worklet global scopes; url: concept-document-worklet-global-scopes
</pre>
Expand Down Expand Up @@ -1700,7 +1701,8 @@ navigation status</dfn> struct, which has the following items:
BrowsingContextCommand = (
BrowsingContextGetTreeCommand //
BrowsingContextNavigateCommand //
BrowsingContextReloadCommand
BrowsingContextReloadCommand //
BrowsingContextTraverseHistoryCommand
)
</pre>

Expand All @@ -1710,7 +1712,8 @@ BrowsingContextCommand = (

BrowsingContextResult = (
BrowsingContextGetTreeResult //
BrowsingContextNavigateResult
BrowsingContextNavigateResult //
BrowsingContextTraverseHistoryResult
)

BrowsingContextEvent = (
Expand Down Expand Up @@ -2112,20 +2115,161 @@ The [=remote end steps=] with |command parameters| are:
1. Let |ignore cache| be the the value of the <code>ignoreCache</code> field of |command
parameters| if present, or false otherwise.

1. Let |wait condition| be the value of the <code>wait</code> field of |command
parameters| if present, or "<code>none</code>" otherwise.

1. Let |document| be |context|'s [=active document=].

1. Let |URL| be |document|'s <a spec=DOM>URL</a>.

1. Let |request| be a new [=/request=] whose URL is |URl|.
1. Let |request| be a new [=/request=] whose URL is |URL|.

1. Return the result of [=await a navigation=] with |context|, |request|,
history handling "<code>reload</code>", and ignore cache |ignore cache|.

</div>

#### The browsingContext.traverseHistory Command #### {#command-browsingContext-traverseHistory}

The <dfn export for=commands>browsingContext.traverseHistory</dfn> command
traverses the history of a given context by a delta.

<dl>
<dt>Command Type</dt>
<dd>
<pre class="cddl remote-cddl">
BrowsingContextTraverseHistoryCommand = {
method: "browsingContext.traverseHistory",
params: BrowsingContextTraverseHistoryParameters
}

BrowsingContextTraverseHistoryParameters = {
context: BrowsingContext,
delta: int,
?wait: ReadinessState,
}
</pre>
</dd>
<dt>Return Type</dt>
<dd>
<pre class="cddl local-cddl">
BrowsingContextTraverseHistoryResult = {
navigation: Navigation / null,
?persisted: bool
url: text,
}
</pre>
</dd>
</dl>

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

1. Let |context id| be the value of the <code>context</code> 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 |delta| be the value of the <code>delta</code> field of |command
parameters|.

1. Let |wait condition| be the value of the <code>wait</code> field of |command
parameters| if present, or "<code>none</code>" otherwise.

1. Let |navigation id| be the string representation of a
[[!RFC4122|UUID]] based on truly random, or pseudo-random numbers.

1. [=Traverse the history by a delta=] given |delta|, |context|, and
|navigation id|.

1. Let (|event received|, |navigate status|) be [=await=] given
«"<code>navigation started</code>", "<code>navigation failed</code>",
"<code>fragment navigated</code>", "<code>pop state</code>"», and
|navigation id|.

1. Assert: |navigate status|'s id is |navigation id|.

1. If |navigate status|'s status is "<code>complete</code>":

1. Let |body| be a [=map=] matching the
<code>BrowsingContextTraverseHistoryResult</code> production, with the
<code>navigation</code> field set to |navigation id|, and the
<code>url</code> field set to the result of the [=URL serializer=] given
|navigate status|'s url.

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

1. If |navigate status|'s status is "<code>canceled</code>" return [=error=]
with [=error code=] [=unknown error=].

1. Assert: |navigate status|'s status is "<code>pending</code>" and
|navigation id| is not null.

1. If |wait condition| is "<code>none</code>":

1. Let |body| be a [=map=] matching the
<code>BrowsingContextTraverseHistoryResult</code> production, with the
<code>navigation</code> field set to |navigation id|, and the
<code>url</code> field set to the result of the [=URL serializer=] given
|navigate status|'s url.

1. If |wait condition| is "<code>interactive</code>", let |event name| be
"<code>domContentLoaded</code>", otherwise let |event name| be
"<code>load</code>".

1. Let (|event received|, |status|) be [=await=] given «|event name|,
"<code>download started</code>", "<code>navigation aborted</code>",
"<code>navigation failed</code>", "<code>page show</code>"», and |navigation
id|.

1. If |event received| is "<code>navigation failed</code>"
return [=error=] with [=error code=] [=unknown error=].

1. If event received is "<code>page show</code>", let |persisted| be true,
otherwise let |persisted| be false.

1. Let |body| be a [=map=] matching the
<code>BrowsingContextTraverseHistoryResult</code> production, with the
<code>navigation</code> field set to |status|'s id, the
<code>persisted</code> field set to |persisted|, and the <code>url</code>
field set to the result of the [=URL serializer=] given |status|'s url.

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

</div>

<div algorithm>

The <dfn export>WebDriver-BiDi page show</dfn> steps given <var
ignore>context</var> and |navigation status| are:

Issue: Do we want to expose a `browsingContext.pageShow event? In that case we'd
need to call this whenever `pageshow` is going to be emitted, not just on
bfcache restore, and also add the persisted status to the data.

1. If the [=current session=] is null, return.

1. Let |navigation id| be |navigation status|'s id.

1. [=Resume=] with "<code>page show</code>", |navigation id|, and
|navigation status|.

</div>

<div algorithm>

The <dfn export>WebDriver-BiDi pop state</dfn> steps given <var
ignore>context</var> and |navigation status| are:

1. If the [=current session=] is null, return.

1. Let |navigation id| be |navigation status|'s id.

1. [=Resume=] with "<code>pop state</code>", |navigation id|, and
|navigation status|.

</div>


### Events ### {#module-contexts-events}

Expand Down Expand Up @@ -2493,6 +2637,15 @@ failed</dfn> steps given |context| and |navigation status|:

1. Let |navigation id| be |navigation status|'s id.

1. If |navigation id| is null, then return.

Issue: The idea here is that we only get events if the navigation was
initiated by us and got far enough to have an id. In particular we wouldn't
get events for e.g. a page doing <code>history.back()</code> on a page where
that would fail. But maybe we want the actual invariant to be that we only
get a <code>navigationFailed</code> event if we already got a
<code>navigationStarted</code> event.

1. Let |related browsing contexts| be a set containing |context|.

1. [=Resume=] with "<code>navigation failed</code>", |navigation id|, and |navigation status|.
Expand Down

0 comments on commit 39072b4

Please sign in to comment.