From c3ca6c22e12fc29c9459a0587cb761cbbc99cd47 Mon Sep 17 00:00:00 2001
From: Domenic Denicola
Let document be removedNode's node document.
If removedNode's node document's focused area is removedNode, then set removedNode's - node document's focused area to - removedNode's node document's viewport.
+If document's focused area is + removedNode, then set document's focused area to document's viewport, and set + document's relevant global object's navigation API's focus changed during ongoing + navigation to false.
This does not perform the unfocusing steps,
focusing steps, or focus update steps, and thus no exposed
[Global]
[LegacyFactoryFunction]
[LegacyLenientThis]
EventInit
dictionary typetype
attributeis
value
MutationObserver
interface and mutation observers in generalAbortController
and its
+ signalAbortSignal
Interactive user agents may provide users with a means to follow the hyperlinks created using the link
element, somewhere
- within their user interface. The exact interface is not defined by this specification, but it
- could include the following information (obtained from the element's attributes, again as defined
- below), in some form or another (possibly simplified), for each hyperlink created
- with each link
element in the document:
browser UI
". The exact interface is not defined by this
+ specification, but it could include the following information (obtained from the element's
+ attributes, again as defined below), in some form or another (possibly simplified), for each
+ hyperlink created with each link
element in the document:
replace
".
+ data-x="NavigationHistoryBehavior-replace">replace".
For the purposes of the previous paragraph, a refresh is said to have come due as soon as the later of the following two conditions occurs:
@@ -21294,50 +21309,6 @@ interface HTMLAnchorElement : HTMLElement { attributes may be used to indicate to the user the likely nature of the target resource before the user follows the link. -The activation behavior of an a
element element given an
- event event is:
If element has no href
attribute,
- then return.
Let hyperlinkSuffix be null.
If event's target is an
- img
with an ismap
attribute specified,
- then:
Let x and y be 0.
If event's isTrusted
attribute is
- initialized to true, then set x to the distance in CSS
- pixels from the left edge of the image to the location of the click, and set
- y to the distance in CSS pixels from the top edge of the
- image to the location of the click.
If x is negative, set x to 0.
If y is negative, set y to 0.
Set hyperlinkSuffix to the concatenation of U+003F (?), the value of - x expressed as a base-ten integer using ASCII digits, U+002C (,), and - the value of y expressed as a base-ten integer using ASCII - digits.
If element has a download
- attribute, or if the user has expressed a preference to download the hyperlink, then download the hyperlink created by element given
- hyperlinkSuffix.
Otherwise, follow the hyperlink created by - element given hyperlinkSuffix.
When an a
or area
element's activation behavior is
- invoked, the user agent may allow the user to indicate a preference regarding whether the
- hyperlink is to be used for navigation or whether the resource it
- specifies is to be downloaded.
In the absence of a user preference, the default should be navigation if the element has no
- download
attribute, and should be to download the
- specified resource if it does.
Whether determined by the user's preferences or via the presence or absence of the attribute, - if the decision is to use the hyperlink for navigation then the user - agent must follow the hyperlink, and if the decision is - to use the hyperlink to download a resource, the user agent must download the hyperlink. These terms are defined in subsequent sections - below.
-The download
attribute, if present, indicates that the author intends the hyperlink to be used for downloading a resource. The attribute may have a value; the
@@ -24394,7 +24349,6 @@ document.body.appendChild(wbr);
cautioned that most file systems have limitations with regard to what punctuation is supported in
filenames, and user agents are likely to adjust filenames accordingly.
The ping
attribute, if present, gives the URLs of the
resources that are interested in being notified if the user follows the hyperlink. The value must
@@ -24444,6 +24398,76 @@ document.body.appendChild(wbr);
policy attribute. Its purpose is to set the referrer policy used when
following hyperlinks.
When an a
or area
element's activation behavior is
+ invoked, the user agent may allow the user to indicate a preference regarding whether the
+ hyperlink is to be used for navigation or whether the resource it
+ specifies is to be downloaded.
In the absence of a user preference, the default should be navigation if the element has no
+ download
attribute, and should be to download the
+ specified resource if it does.
The activation behavior of an a
or area
element
+ element given an event event is:
If element has no href
attribute,
+ then return.
Let hyperlinkSuffix be null.
If element is an a
element, and event's target is an img
with an ismap
attribute specified, then:
Let x and y be 0.
If event's isTrusted
attribute is
+ initialized to true, then set x to the distance in CSS
+ pixels from the left edge of the image to the location of the click, and set
+ y to the distance in CSS pixels from the top edge of the
+ image to the location of the click.
If x is negative, set x to 0.
If y is negative, set y to 0.
Set hyperlinkSuffix to the concatenation of U+003F (?), the value of + x expressed as a base-ten integer using ASCII digits, U+002C (,), and + the value of y expressed as a base-ten integer using ASCII + digits.
Let userInvolvement be event's user + navigation involvement.
If the user has expressed a preference to download the hyperlink, then set
+ userInvolvement to "browser UI
".
That is, if the user has expressed a specific preference for downloading, this
+ no longer counts as merely "activation
".
If element has a download
+ attribute, or if the user has expressed a preference to download the hyperlink, then download the hyperlink created by element with
+ hyperlinkSuffix set to hyperlinkSuffix and
+ userInvolvement set to
+ userInvolvement.
Otherwise, follow the hyperlink created by + element with hyperlinkSuffix set to + hyperlinkSuffix and userInvolvement set to + userInvolvement.
a
and area
elementsTo follow the hyperlink created by an element - subject, given an optional hyperlinkSuffix (default null):
+ subject, given an optional hyperlinkSuffix (default null) and an + optional userInvolvement (default "none
"):
If subject cannot navigate, then return.
Navigate targetNavigable to url using subject's node document, with referrerPolicy set to referrerPolicy.
+ data-x="navigation-referrer-policy">referrerPolicy set to referrerPolicy and userInvolvement set to userInvolvement.Unlike many other types of navigations, following hyperlinks does not have
- special "replace
" behavior for when documents are not
- completely loaded. This is true for both user-initiated instances of following
- hyperlinks, as well as script-triggered ones via, e.g., replace
" behavior for when
+ documents are not completely loaded. This is true for both user-initiated instances
+ of following hyperlinks, as well as script-triggered ones via, e.g., aElement.click()
.
The following allowed to download algorithm takes two booleans - sourceAllowsDownloading and targetAllowsDownloading, and returns a boolean - indicating whether or not downloading is allowed:
- -If either sourceAllowsDownloading or targetAllowsDownloading are - false, then return false.
- -Optionally, the user agent may return false, if it believes doing so would safeguard the - user from a potentially hostile download.
Return true.
To download the hyperlink created by an - element subject, given an optional hyperlinkSuffix (default null):
+ element subject, given an optional hyperlinkSuffix (default null) and an + optional userInvolvement (default + "none
"):
If subject cannot navigate, then return.
Let sourceAllowsDownloading be false if subject's node - document's active sandboxing flag set has the sandboxed downloads - browsing context flag set; otherwise true.
If the result of the allowed to download algorithm with - sourceAllowsDownloading and true is false, then return.
If subject's node document's active + sandboxing flag set has the sandboxed downloads browsing context flag set, + then return.
Parse a URL given subject's If parsing the URL fails, then return. Otherwise, let URL be the resulting URL string. Otherwise, let url be the resulting URL string. If hyperlinkSuffix is non-null, then append it to URL. If hyperlinkSuffix is non-null, then append it to url. If userInvolvement is not " Assert: subject has a Let navigation be subject's relevant global object's
+ navigation API. Let filename be the value of subject's Let continue be the result of firing a download request If continue is false, then return. Run these steps in parallel: Optionally, the user agent may abort these steps, if it believes doing so would
+ safeguard the user from a potentially hostile download. Let request be a new request whose
- URL is URL,
+ URL is url,
client is entry settings object,
initiator is " Let historyHandling be " Let historyHandling be " If element's content navigable's active document is not completely loaded, then set
- historyHandling to "href
attribute, relative to subject's node
@@ -25116,16 +25130,44 @@ document.body.appendChild(wbr);
browser UI
",
+ then:
+
+ download
attribute.download
attribute.navigate
event at
+ navigation with destinationURL
+ set to url, userInvolvement
+ set to userInvolvement, and filename
+ set to filename.
+
download
",
destination is the empty string, and whose
@@ -32755,11 +32797,13 @@ interface HTMLIFrameElement : HTMLElement {
null):
-
push
".auto
".replace
".replace
".
If element is an iframe
, then set element's pending resource-timing start time to
@@ -33458,7 +33502,7 @@ interface HTMLEmbedElement : HTMLElement {
data-x="concept-response-url">URL using element's node
document, with response set to
response, and historyHandling set to "replace
".
element's src
attribute
does not get updated if the content navigable gets further navigated to
@@ -33957,7 +34001,7 @@ interface HTMLObjectElement : HTMLElement {
navigate the element's content navigable to
response's URL using the element's
node document, with historyHandling set to
- "replace
".
replace
".
The data
attribute of the
object
element doesn't get updated if the content navigable gets
@@ -41214,12 +41258,12 @@ interface HTMLAreaElement : HTMLElement {
When user agents allow users to follow hyperlinks or
download hyperlinks created using the
- area
element, as described in the next section, the href
, target
, download
, and ping
- attributes decide how the link is followed. The rel
- attribute may be used to indicate to the user the likely nature of the target resource before the
- user follows the link.
area
element, the href
, target
, download
, and ping
attributes decide how the link is followed. The rel
attribute may be used to indicate to the user the likely
+ nature of the target resource before the user follows the link.
@@ -41235,22 +41279,6 @@ interface HTMLAreaElement : HTMLElement {
The activation behavior of an area
element element is:
If element has no href
attribute,
- then return.
If element has a download
- attribute, or if the user has expressed a preference to download the hyperlink, then download the hyperlink created by
- element.
Otherwise, follow the hyperlink created by - element.
The IDL attributes alt
, coords
, HTMLFormElement
: HTMLElement {
The submit()
- method, when invoked, must submit the form
- element from the form
element itself, with the submitted from submit()
method flag set.
submit()
method set to true.
The requestSubmit(submitter)
method, when
@@ -47251,17 +47279,19 @@ interface HTMLInputElement : HTMLElement {
data-x="concept-input-checked-dirty-flag">dirty checkedness flag from the node being cloned
to the copy.
The activation behavior for input
elements are these steps:
The activation behavior for input
elements element, given
+ event, are these steps:
If this element is not mutable and is not in the Checkbox state and is not in the If element is not mutable and is not in the
+ Checkbox state and is not in the Radio state, then return.
Run this element's input activation behavior, if any, and do nothing +
Run element's input activation behavior, if any, and do nothing otherwise.
Run the popover target attribute activation behavior on this element.
Run the popover target attribute activation behavior on + element.
Recall that an element's activation behavior runs for both
@@ -50180,7 +50210,7 @@ ldh-str = < as defined in If the element's node document is not fully active, then
return. Submit the form owner from the
- element. Submit the element's form owner
+ from the element with userInvolvement set to
+ event's user navigation involvement.
Submit the form owner from the - element.
Submit the element's form owner + from the element with userInvolvement set to + event's user navigation involvement.
The element's selected coordinate @@ -52355,7 +52387,8 @@ interface HTMLButtonElement : HTMLElement { Button state, the element is barred from constraint validation.
-A button
element element's activation behavior is:
A button
element element's activation behavior given
+ event is:
If element is disabled, then @@ -52371,7 +52404,9 @@ interface HTMLButtonElement : HTMLElement {
Submit element's form - owner from element.
Reset element's form
@@ -58634,12 +58669,19 @@ fur
If the form has
no submit button, then the implicit submission
- mechanism must do nothing if the form has more than one field that blocks implicit
- submission, and must submit the If the form has more than one field that blocks implicit submission, then
+ return. Submit the For the purpose of the previous paragraph, an element is a field that blocks implicit
- submission of a For the purpose of the previous paragraph, an element is a field that blocks implicit
+ submission of a Each When a To submit a If form cannot navigate, then return.form
- element from the form
element itself otherwise.
+
- form
element from the
+ form
element itself with userInvolvement set
+ to "activation
".form
element if it is an input
element whose
+ form
element if it is an input
element whose
form owner is that form
element and whose type
attribute is in one of the following states:
Text,
@@ -58669,11 +58711,13 @@ fur
form
element has a firing submission events boolean, initially
false.form
element form is submitted from an element submitter
- (typically a button), optionally with a submitted from submit()
method flag set, the user agent must run the
- following steps:form
element form
+ from an element submitter (typically a button), given an optional boolean submitted from submit()
method (default false) and an optional
+ user navigation involvement userInvolvement (default "none
"):
has its sandboxed forms browsing context flag set, then return.
If the submitted from submit()
method flag
- is not set, then:
+
If submitted from submit()
method is false,
+ then:
If form's firing submission events is true, then @@ -58827,12 +58871,13 @@ fur
If targetNavigable is null, then return.
Let historyHandling be "push
".
Let historyHandling be "auto
".
If form document equals targetNavigable's active document, and form document has not yet
completely loaded, then set historyHandling to "replace
".
Select the appropriate row in the table below based on scheme as given by the @@ -58905,10 +58950,11 @@ fur
Navigate targetNavigable to url
using the form
element's node document, with historyHandling set to historyHandling, referrerPolicy set to referrerPolicy, documentResource set to postResource, and cspNavigationType set to "form-submission
".
For the purpose of tracking user activation, each Window
W has a
- last activation timestamp. This is a number indicating the last time W got
- an activation notification. It corresponds to a
- DOMHighResTimeStamp
value except for two cases: positive infinity
- indicates that W has never been activated, while negative infinity indicates that a user activation-gated API has consumed the last user activation of W. The initial value is
- positive infinity.
For the purpose of tracking user activation, each Window
W has two
+ relevant values:
A last activation timestamp, which is either a
+ DOMHighResTimeStamp
, positive infinity (indicating that W has never been
+ activated), or negative infinity (indicating that the activation has been consumed). Initially positive infinity.
A last history-action activation timestamp, which is either a
+ DOMHighResTimeStamp
or positive infinity, initially positive infinity.
A user agent also defines a transient activation duration, which is a constant
number indicating how long a user activation is available for certain VisibilityStateEntry : PerformanceEntry
- These two values imply two boolean user activation states for W: We then have the following boolean user activation states for W:
When the last history-action activation timestamp of W is not equal + to the last activation timestamp of W, then W is said to have + history-action activation.
+ +This is a special variant of user activation, used to allow access to certain session history + APIs which, if used too frequently, would make it harder for the user to traverse back using browser UI. It starts with a false value, and becomes true whenever + the user interacts with W, but is reset to false through history-action activation consumption. This ensures such + APIs cannot be used multiple times in a row without an intervening user activation. But unlike + transient activation, there is no time limit within which such APIs must be + used.
+The last activation timestamp is retained even after the
- Document
changes its fully active status (e.g. after navigating away
- from a Document
, or navigating to a cached Document
). This means
- sticky activation state spans multiple navigations as long as the same
- Document
gets reused. For the transient activation state, the original
- expiry time remains unchanged (i.e. the state still
- expires within the transient activation duration limit from the original
- activation triggering input event). It is important to consider this when deciding
- whether to base certain things off sticky activation or transient
- activation.
The last activation timestamp and last history-action
+ activation timestamp are retained even after the Document
changes its
+ fully active status (e.g., after navigating away from a Document
, or
+ navigating to a cached Document
). This means sticky activation state
+ spans multiple navigations as long as the same Document
gets reused. For the
+ transient activation state, the original expiry time
+ remains unchanged (i.e., the state still expires within the transient activation
+ duration limit from the original activation triggering input event). It is
+ important to consider this when deciding whether to base certain things off sticky
+ activation or transient activation.
keydown
, provided the key is neither the Esc key nor a
- shortcut key reserved by the user agent.mousedown
.pointerdown
, provided the event's pointerType
is "mouse".pointerup
, provided the event's pointerType
is not "mouse".touchend
.keydown
", provided the key is neither the
+ Esc key nor a shortcut key reserved by the user agent.mousedown
".pointerdown
", provided the event's
+ pointerType
is "mouse
".pointerup
", provided the event's
+ pointerType
is not "mouse
".touchend
".Activation consuming APIs defined in this and @@ -77235,6 +77307,29 @@ interface VisibilityStateEntry : PerformanceEntrywindow's last activation timestamp to negative infinity.
+History-action activation-consuming
+ APIs can consume history-action user activation by performing the following
+ steps, given a Window
W:
If W's navigable is null, then + return.
Let top be W's navigable's + top-level traversable.
Let navigables be the inclusive descendant navigables of + top's active document.
Let windows be the list of Window
objects constructed by taking
+ the active window of each item in
+ navigables.
For each window in windows, set + window's last history-action activation timestamp to window's + window's last activation timestamp.
Note the asymmetry in the sets of browsing
contexts in the page that are affected by an activation notification vs an
activation consumption: an activation consumption
@@ -77248,15 +77343,12 @@ interface VisibilityStateEntry : PerformanceEntry
- APIs that are dependent on user activation are classified into three different levels. The
- levels are as follows, sorted by their "strength of dependence" on user activation (from weakest
- to strongest): APIs that are dependent on user activation are classified into different levels: These APIs require the sticky
- activation state to be true, so they are blocked until the very first user
- activation. These APIs require the sticky activation state to be true, so they are
+ blocked until the very first user activation. These APIs require the transient
@@ -77264,10 +77356,15 @@ interface VisibilityStateEntry : PerformanceEntryconsume it, so multiple calls are allowed per user activation until the
transient state expires. These APIs require the
- transient activation state to be true, and they consume user
- activation in each call to prevent multiple calls per user activation. These APIs require the transient activation state to be true, and they
+ consume user activation in each call to prevent multiple calls per user
+ activation. These APIs require the history-action activation state to be true, and they
+ consume history-action user activation in each call to prevent multiple calls per
+ user activation. If entry is a focusable area: designate entry as the
- focused area of the document. If entry is a focusable area, and the focused area of the
+ document is not entry: Set document's relevant global object's navigation API's focus changed during ongoing
+ navigation to true. Designate entry as the focused area of the document. If topmostPopover is null, then return. If event is a If event is a
-
@@ -78386,8 +78483,16 @@ partial interface {
controls (back and forward buttons,
+ reload buttons, etc.).
+
PointerEvent
and event's type
is pointerdown
, then:
- set document's popover pointerdown target to the result of running
+ data-x="dom-Event-type">type is "pointerdown
",
+ then: set document's popover pointerdown target to the result of running
topmost clicked popover given target.PointerEvent
and event's type
is pointerup
,
+ data-x="dom-Event-type">type is "pointerup
",
then:
@@ -86439,6 +86544,7 @@ interface Window : EventTarget {
attribute DOMString name;
[PutForwards=href, LegacyUnforgeable] readonly attribute Location location;
readonly attribute History history;
+ readonly attribute Navigation navigation;
readonly attribute CustomElementRegistry customElements;
[Replaceable] readonly attribute BarProp locationbar;
[Replaceable] readonly attribute BarProp menubar;
@@ -87454,8 +87560,8 @@ interface BarProp {
BarProp
object
The locationbar
@@ -88129,7 +88235,7 @@ interface Location { // but see also push"):
Let navigable be location's relevant global object's @@ -88142,7 +88248,8 @@ interface Location { // but see also incumbent global object
replace
".
+ historyHandling to "replace
".
Navigate navigable to url using sourceDocument, with exceptionsEnabled set to true and Location { // but see also replace".
replace
".
The replace()
method intentionally has
@@ -88794,9 +88902,9 @@ interface History {
history.state
Returns the serialized state of the active session history entry, deserialized into a - JavaScript value.
Returns the classic history API state + of the active session history entry, deserialized + into a JavaScript value.
history.go()
history.pushState(data, "")
Adds a new entry into session history with its serialized state set to a serialization of - data. The active history entry's + data-x="she-classic-history-api-state">classic history API state
(The second parameter exists for historical reasons, and cannot be omitted; passing the @@ -88846,8 +88954,8 @@ interface History {
history.pushState(data, "", url)
Adds a new entry into session history with its serialized state set to a serialization of - data, and with its URL set to url.
+ data-x="she-classic-history-api-state">classic history API state set to a serialization + of data, and with its URL set to url.If the current Document
cannot have
its URL rewritten to url, a "SecurityError
"
@@ -88859,9 +88967,9 @@ interface History {
history.replaceState(data, "")
Updates the serialized state of the active session history entry to a structured clone of - data.
+Updates the classic history API state of + the active session history entry to a structured + clone of data.
(The second parameter exists for historical reasons, and cannot be omitted; passing the empty string is traditional.)
@@ -88869,9 +88977,9 @@ interface History {history.replaceState(data, "", url)
Updates the serialized state of the active session history entry to a structured clone of - data, and its URL to url.
+Updates the classic history API state of + the active session history entry to a structured + clone of data, and its URL to url.
If the current Document
cannot have
its URL rewritten to url, a "SecurityError
"
@@ -88982,20 +89090,21 @@ interface History {
navigable.
Traverse the history by a delta given document's node - navigable's traversable navigable, - delta, and document.
The pushState(data,
unused, url)
method steps are to run the shared history
push/replace state steps given this, data, url, and
- "push
".
push
".
The replaceState(data, unused,
url)
method steps are to run the shared history push/replace state
steps given this, data, url, and "replace
".
The shared history push/replace state steps, given a History
history, a value data, a scalar value string-or-null
@@ -89040,6 +89149,20 @@ interface History {
data-x="">history.pushState(null, "", "") (which bypasses it).
Let navigation be history's relevant global object's + navigation API.
Let continue be the result of firing a push/replace/reload navigate
event at
+ navigation with navigationType set to
+ historyHandling, isSameDocument set
+ to true, destinationURL set to
+ newURL, and classicHistoryAPIState set to
+ serializedData.
If continue is false, then return.
+Run the URL and history update steps given document and newURL, with serializedData set to serializedData and historyHandling set to @@ -89259,8 +89382,3384 @@ interface History { +
The navigation API, provided by the global navigation
+ property, provides a modern and web application-focused way of managing navigations and history entries. It is a successor to the classic location
and history
APIs.
One ability the API provides is inspecting session history entries. For example, the following will display the entries' URLs in an ordered list:
+ +const ol = document.createElement("ol");
+ol.start = 0; // so that the list items' ordinal values match up with the entry indices
+
+for (const entry of navigation.entries()) {
+ const li = document.createElement("li");
+
+ if (entry.index < navigation.currentEntry.index) {
+ li.className = "backward";
+ } else if (entry.index > navigation.currentEntry.index) {
+ li.className = "forward";
+ } else {
+ li.className = "current";
+ }
+
+ li.textContent = entry.url;
+ ol.append(li);
+}
+
+ The navigation.entries()
array contains NavigationHistoryEntry
instances, which have other useful properties in addition to the url
and index
properties shown here. Note that the array only contains NavigationHistoryEntry
objects that represent the current navigable, and thus its contents are not impacted by navigations inside navigable containers such as iframe
s, or by navigations of the parent navigable in cases where the navigation API is itself being used inside an iframe
. Additionally, it only contains NavigationHistoryEntry
objects representing same-origin session history entries, meaning that if the user has visited other origins before or after the current one, there will not be corresponding NavigationHistoryEntry
s.
The navigation API can also be used to navigate, reload, or traverse through the history:
+ +<button onclick="navigation.reload()">Reload</button>
+
+<input type="url" id="navigationURL">
+<button onclick="navigation.navigate(navigationURL.value)">Navigate</button>
+
+<button id="backButton" onclick="navigation.back()">Back</button>
+<button id="forwardButton" onclick="navigation.forward()">Forward</button>
+
+<select id="traversalDestinations"></select>
+<button id="goButton" onclick="navigation.traverseTo(traversalDestinations.value)">Traverse To</button>
+
+<script>
+backButton.disabled = !navigation.canGoBack;
+forwardButton.disabled = !navigation.canGoForward;
+
+for (const entry of navigation.entries()) {
+ traversalDestinations.append(new Option(entry.url, entry.key));
+}
+</script>
+
+ Note that traversals are again limited to same-origin destinations, meaning that, for example, navigation.canGoBack
will be false if the previous session history entry is for a page from another origin.
The most powerful part of the navigation API is the navigate
event, which fires whenever almost any navigation or traversal occurs in the current navigable:
navigation.onnavigate = event => {
+ console.log(event.navigationType); // "push", "replace", "reload", or "traverse"
+ console.log(event.destination.url);
+ console.log(event.userInitiated);
+ // ... and other useful properties
+};
+
+ (The event will not fire for location bar-initiated navigations, or navigations initiated from other windows, when the destination of the navigation is a new document.)
+ +Much of the time, the event's cancelable
property will be true, meaning this event can be canceled using preventDefault()
:
navigation.onnavigate = event => {
+ if (event.cancelable && isDisallowedURL(event.destination.url)) {
+ alert(`Please don't go to ${event.destination.url}!`);
+ event.preventDefault();
+ }
+};
+
+
+ The cancelable
property will be false for some "traverse
" navigations, such as those taking place inside child navigables, those crossing to new origins, or when the user attempts to traverse again shortly after a previous call to preventDefault()
prevented them from doing so.
The NavigateEvent
's intercept()
method allows intercepting a navigation and converting it into a same-document navigation:
navigation.addEventListener("navigate", e => {
+ // Some navigations, e.g. cross-origin navigations, we cannot intercept.
+ // Let the browser handle those normally.
+ if (!e.canIntercept) {
+ return;
+ }
+
+ // Similarly, don't intercept fragment navigations or downloads.
+ if (e.hashChange || e.downloadRequest !== null) {
+ return;
+ }
+
+ const url = new URL(event.destination.url);
+
+ if (url.pathname.startsWith("/articles/")) {
+ e.intercept({
+ async handler() {
+ // The URL has already changed, so show a placeholder while
+ // fetching the new content, such as a spinner or loading page.
+ renderArticlePagePlaceholder();
+
+ // Fetch the new content and display when ready.
+ const articleContent = await getArticleContent(url.pathname, { signal: e.signal });
+ renderArticlePage(articleContent);
+ }
+ });
+ }
+});
+
+ Note that the handler
function can return a promise to represent the asynchronous progress, and success or failure, of the navigation. While the promise is still pending, browser UI can treat the navigation as ongoing (e.g., by presenting a loading spinner). Other parts of the navigation API are also sensitive to these promises, such as the return value of navigation.navigate()
:
+
+
const { committed, finished } = await navigation.navigate("/articles/the-navigation-api-is-cool");
+
+// The committed promise will fulfill once the URL has changed, which happens
+// immediately (as long as the NavigateEvent wasn't canceled).
+await committed;
+
+// The finished promise will fulfill once the Promise returned by handler() has
+// fulfilled, which happens once the article is downloaded and rendered. (Or,
+// it will reject, if handler() fails along the way).
+await finished;
+
+ Navigation
inteface[Exposed=Window]
+interface Navigation : EventTarget {
+ sequence<NavigationHistoryEntry> entries();
+ readonly attribute NavigationHistoryEntry? currentEntry;
+ undefined updateCurrentEntry(NavigationUpdateCurrentEntryOptions options);
+ readonly attribute NavigationTransition? transition;
+
+ readonly attribute boolean canGoBack;
+ readonly attribute boolean canGoForward;
+
+ NavigationResult navigate(USVString url, optional NavigationNavigateOptions options = {});
+ NavigationResult reload(optional NavigationReloadOptions options = {});
+
+ NavigationResult traverseTo(DOMString key, optional NavigationOptions options = {});
+ NavigationResult back(optional NavigationOptions options = {});
+ NavigationResult forward(optional NavigationOptions options = {});
+
+ attribute EventHandler onnavigate;
+ attribute EventHandler onnavigatesuccess;
+ attribute EventHandler onnavigateerror;
+ attribute EventHandler oncurrententrychange;
+};
+
+dictionary NavigationUpdateCurrentEntryOptions {
+ required any state;
+};
+
+dictionary NavigationOptions {
+ any info;
+};
+
+dictionary NavigationNavigateOptions : NavigationOptions {
+ any state;
+ NavigationHistoryBehavior history = "auto";
+};
+
+dictionary NavigationReloadOptions : NavigationOptions {
+ any state;
+};
+
+dictionary NavigationResult {
+ Promise<NavigationHistoryEntry> committed;
+ Promise<NavigationHistoryEntry> finished;
+};
+
+enum NavigationHistoryBehavior {
+ "auto",
+ "push",
+ "replace"
+};
+
+ Each Window
has an associated navigation
+ API, which is a Navigation
object. Upon creation of the Window
+ object, its navigation API must be set to a
+ new Navigation
object created in the Window
object's relevant realm.
The navigation
getter
+ steps are to return this's navigation
+ API.
The following are the event handlers (and their corresponding event handler event types) that must be supported,
+ as event handler IDL attributes, by all objects implementing the
+ Navigation
interface:
Event handler + | Event handler event type + |
---|---|
onnavigate
+ | navigate
+ |
onnavigatesuccess
+ | navigatesuccess
+ |
onnavigateerror
+ | navigateerror
+ |
oncurrententrychange
+ | currententrychange
+ |
Each Navigation
has an associated entry
+ list, a list of NavigationHistoryEntry
objects, initially
+ empty.
Each Navigation
has an associated current entry index, an integer, initially
+ −1.
The current entry of a Navigation
+ navigation is the result of running the following steps:
If navigation has entries and events disabled, then return + null.
Assert: navigation's current entry index is not −1.
Return navigation's entry + list[navigation's current entry + index].
A Navigation
navigation has entries and events disabled if
+ the following steps return true:
Let document be navigation's relevant global object's
+ associated Document
.
If document is not fully active, then return true.
If document's is initial about:blank
is true, then
+ return true.
If document's origin is opaque, then return true.
Return false.
To get the navigation API entry
+ index of a session history entry she within a
+ Navigation
navigation:
Let index be 0.
For each nhe of navigation's entry list:
+ +If nhe's session history entry is equal to + she, then return index.
Increment index by 1.
Return −1.
A key type used throughout the navigation API is the NavigationType
+ enumeration:
enum NavigationType {
+ "push",
+ "replace",
+ "reload",
+ "traverse"
+};
+
+ This captures the main web developer-visible types of "navigations", which (as noted elsewhere) do not exactly correspond to this standard's + singular navigate algorithm. The meaning of each value is the following:
+ +push
"push
", or to
+ history.pushState()
.replace
"replace
", or
+ to history.replaceState()
.reload
"traverse
"The value space of the NavigationType
enumeration is a superset of
+ the value space of the specification-internal history handling behavior type. Several
+ parts of this standard make use of this overlap, by passing in a history handling
+ behavior to an algorithm that expects a NavigationType
.
To initialize the navigation API entries for a new document given a
+ Navigation
navigation, a list of session history entries newSHEs, and a session history
+ entry initialSHE:
Assert: navigation's entry + list is empty.
Assert: navigation's current entry index is −1.
If navigation has entries and events disabled, then + return.
For each newSHE of newSHEs:
+ +Let newNHE be a new NavigationHistoryEntry
created
+ in the relevant realm of
+ navigation.
Set newNHE's session history entry to + newSHE.
Append newNHE to navigation's + entry list.
newSHEs will have originally come from getting session history + entries for the navigation API, and thus each newSHE will be contiguous same origin with + initialSHE.
+Set navigation's current entry + index to the result of getting the navigation API entry index of + initialSHE within navigation.
To update the navigation API entries for reactivation given a
+ Navigation
navigation, a list of session history entries newSHEs, and a session history
+ entry reactivatedSHE:
If navigation has entries and events disabled, then + return.
Let newNHEs be a new empty list.
Let oldNHEs be a clone of + navigation's entry list.
For each newSHE of newSHEs:
+ +Let newNHE be null.
If oldNHEs contains a
+ NavigationHistoryEntry
matchingOldNHE whose session history entry is newSHE, then:
Set newNHE to matchingOldNHE.
Remove matchingOldNHE from + oldNHEs.
Otherwise:
+ +Set newNHE to a new NavigationHistoryEntry
+ created in the relevant realm of
+ navigation.
Set newNHE's session history entry to + newSHE.
Append newNHE to + newNHEs.
newSHEs will have originally come from getting session history + entries for the navigation API, and thus each newSHE will be contiguous same origin with + reactivatedSHE.
+ +By the end of this loop, all NavigationHistoryEntry
s that remain in
+ oldNHEs represent session history entries
+ which have been disposed while the Document
was in bfcache.
Set navigation's entry list to newNHEs.
Set navigation's current entry + index to the result of getting the navigation API entry index of + reactivatedSHE within navigation.
Queue a global task on the navigation and traversal task source + given navigation's relevant global object to run the following + steps:
+ +For each disposedNHE of + oldNHEs:
+ +Fire an event named dispose
at disposedNHE.
We delay these steps by a task to ensure that dispose
+ events will fire after the pageshow
event. This ensures
+ that pageshow
is the first event a page receives upon
+ reactivation.
(However, the rest of this algorithm runs before the pageshow
event fires. This ensures that navigation.entries()
and navigation.currentEntry
will have correctly-updated
+ values during any pageshow
event handlers.)
To update the navigation API entries for a same-document navigation given a
+ Navigation
navigation, a session history entry
+ destinationSHE, and a NavigationType
navigationType:
If navigation has entries and events disabled, then + return.
Let oldCurrentNHE be the current + entry of navigation.
Let disposedNHEs be a new empty list.
If navigationType is "traverse
",
+ then:
Set navigation's current entry + index to the result of getting the navigation API entry index of + destinationSHE within navigation.
Assert: navigation's current entry index is not −1.
This algorithm is only called for same-document traversals. Cross-document + traversals will instead call either initialize the navigation API entries for a new + document or update the navigation API entries for reactivation.
+Otherwise, if navigationType is "push
", then:
Set navigation's current entry + index to navigation's current + entry index + 1.
Let i be navigation's current entry index.
While i < navigation's entry list's size:
+ +Append navigation's entry list[i] to + disposedNHEs.
Set i to i + 1.
Remove all items in disposedNHEs from + navigation's entry list.
Otherwise, if navigationType is "replace
", then:
Append oldCurrentNHE to + disposedNHEs.
If navigationType is "push
" or
+ "replace
", then:
Let newNHE be a new NavigationHistoryEntry
created
+ in the relevant realm of
+ navigation.
Set newNHE's session history entry to + destinationSHE.
Set navigation's entry + list[navigation's current entry + index] to newNHE.
If navigation's ongoing API method tracker is non-null, then + notify about the committed-to entry given navigation's ongoing API + method tracker and the current entry of + navigation.
+ +It is important to do this before firing the dispose
or currententrychange
events, since event handlers could
+ start another navigation, or otherwise change the value of navigation's ongoing
+ API method tracker.
Prepare to run script given navigation's relevant settings + object.
+ +See the discussion + for other navigation API events to understand why we do this.
+Fire an event named currententrychange
at navigation using
+ NavigationCurrentEntryChangeEvent
, with its navigationType
attribute
+ initialized to navigationType and its from
initialized to
+ oldCurrentNHE.
For each disposedNHE of + disposedNHEs:
+ +Fire an event named dispose
at disposedNHE.
Clean up after running script given navigation's relevant + settings object.
In implementations, same-document navigations can cause session history entries to be disposed by falling off the back of the + session history entry list. This is not yet handled by the above algorithm (or by any other part + of this standard). See issue #8620 to + track progress on defining the correct behavior in such cases.
+ +NavigationHistoryEntry
interface[Exposed=Window]
+interface NavigationHistoryEntry : EventTarget {
+ readonly attribute USVString? url;
+ readonly attribute DOMString key;
+ readonly attribute DOMString id;
+ readonly attribute long long index;
+ readonly attribute boolean sameDocument;
+
+ any getState();
+
+ attribute EventHandler ondispose;
+};
+
+ entry.url
The URL of this navigation history entry.
+ +This can return null if the entry corresponds to a different Document
than the
+ current one (i.e., if sameDocument
+ is false), and that Document
was fetched with a referrer policy of
+ "no-referrer
" or "origin
", since that indicates
+ the Document
in question is hiding its URL even from other same-origin pages.
entry.key
A user agent-generated random UUID string representing this navigation history entry's place
+ in the navigation history list. This value will be reused by other
+ NavigationHistoryEntry
instances that replace this one due to "replace
" navigations, and will survive reloads and
+ session restores.
This is useful for navigating back to this entry in the navigation history list, using navigation.traverseTo(key)
.
entry.id
A user agent-generated random UUID string representing this specific navigation history
+ entry. This value will not be reused by other NavigationHistoryEntry
+ instances. This value will survive reloads and session restores.
This is useful for associating data with this navigation history entry using other storage + APIs.
+entry.index
The index of this NavigationHistoryEntry
within navigation.entries()
, or −1 if the entry is not in
+ the navigation history entry list.
entry.sameDocument
Indicates whether or not this navigation history entry is for the same
+ Document
as the current one, or not. This will be true, for example, when the entry
+ represents a fragment navigation or single-page app navigation.
entry.getState()
Returns the deserialization of the state stored
+ in this entry, which was added to the entry using navigation.navigate()
or navigation.updateCurrentEntry()
. This state
+ survives reloads and session restores.
Note that in general, unless the state value is a primitive, entry.getState() !== entry.getState()
, since a fresh deserialization is
+ returned each time.
This state is unrelated to the classic history API's history.state
.
Each NavigationHistoryEntry
has an associated session
+ history entry, which is a session history entry.
The key of a
+ NavigationHistoryEntry
nhe is given by the return value of the following
+ algorithm:
If nhe's relevant global object's associated Document
is not fully
+ active, then return the empty string.
Return nhe's session history entry's navigation API key.
The ID of a
+ NavigationHistoryEntry
nhe is given by the return value of the following
+ algorithm:
If nhe's relevant global object's associated Document
is not fully
+ active, then return the empty string.
Return nhe's session history entry's navigation API ID.
The index of a
+ NavigationHistoryEntry
nhe is given by the return value of the following
+ algorithm:
If nhe's relevant global object's associated Document
is not fully
+ active, then return −1.
Return the result of getting the navigation API entry index of + this's session history entry within + this's relevant global object's navigation API.
The url
getter steps are:
Let document be this's relevant global object's associated Document
.
If document is not fully active, then return the empty + string.
Let she be this's session history + entry.
If she's document does not equal
+ document, and she's document
+ state's request referrer
+ policy is "no-referrer
" or "origin
", then
+ return null.
Return she's URL, serialized.
The key
getter steps are to return
+ this's key.
The id
getter steps are to return
+ this's ID.
The index
getter steps are to return
+ this's index.
The sameDocument
getter steps are:
Let document be this's relevant global object's associated Document
.
If document is not fully active, then return false.
Return true if this's session history entry's + document equals document, and false + otherwise.
The getState()
method steps are:
If this's relevant global object's associated Document
is not fully
+ active, then return undefined.
Return StructuredDeserialize(this's session + history entry's navigation API state). + Rethrow any exceptions.
+ +This can in theory throw an exception, if attempting to deserialize a large
+ ArrayBuffer
when not enough memory is available.
The following are the event handlers (and their corresponding event handler event types) that must be supported,
+ as event handler IDL attributes, by all objects implementing the
+ NavigationHistoryEntry
interface:
Event handler + | Event handler event type + |
---|---|
ondispose
+ | dispose
+ |
entries = navigation.entries()
Returns an array of NavigationHistoryEntry
instances represent the current
+ navigation history entry list, i.e., all session history
+ entries for this navigable that are same origin and contiguous
+ to the current session history entry.
navigation.currentEntry
Returns the NavigationHistoryEntry
corresponding to the current session history entry.
navigation.updateCurrentEntry({ state })
Updates the navigation API state of the current session history entry, without performing a
+ navigation like navigation.reload()
would do.
This method is best used to capture updates to the page that have already happened, and need
+ to be reflected into the navigation API state. For cases where the state update is meant to
+ drive a page update, instead use navigation.navigate()
or navigation.reload()
, which will trigger a navigate
event.
navigation.canGoBack
Returns true if the current current session
+ history entry (i.e., currentEntry
) is
+ not the first one in the navigation history entry list (i.e., in entries()
). This means that there is a previous
+ session history entry for this navigable, and its document state's origin is same origin with the current
+ Document
's origin.
navigation.canGoForward
Returns true if the current current session
+ history entry (i.e., currentEntry
) is
+ not the last one in the navigation history entry list (i.e., in entries()
). This means that there is a next session
+ history entry for this navigable, and its document state's origin is same origin with the current
+ Document
's origin.
The entries()
+ method steps are:
If this has entries and events disabled, then return the empty + list.
Return this's entry list.
+ +Recall that because of Web IDL's sequence type conversion rules, this will
+ create a new JavaScript array object on each call. That is, navigation.entries() !== navigation.entries()
.
The currentEntry
getter steps are to return the
+ current entry of this.
The updateCurrentEntry(options)
+ method steps are:
Let current be the current entry + of this.
If current is null, then throw an "InvalidStateError
"
+ DOMException
.
Let serializedState be
+ StructuredSerializeForStorage(options["state
"]), rethrowing any
+ excpetions.
Set current's session history entry's navigation API state to + serializedState.
Fire an event named currententrychange
at this using
+ NavigationCurrentEntryChangeEvent
, with its navigationType
attribute
+ initialized to null and its from
+ initialized to current.
The canGoBack
getter steps are:
If this has entries and events disabled, then return + false.
Assert: this's current entry index is not −1.
If this's current entry + index is 0, then return false.
Return true.
The canGoForward
getter steps are:
If this has entries and events disabled, then return + false.
Assert: this's current entry index is not −1.
If this's current entry + index is equal to this's entry + list's size, then return false.
Return true.
{ committed, finished } = navigation.navigate(url)
{ committed, finished } = navigation.navigate(url, options)
Navigates the current page to the given url. + options can contain the following values:
+ +history
can be set to
+ "replace
" to replace the current
+ session history entry, instead of pushing a new one.
info
can be set to any value; it
+ will populate the info
property of the
+ corresponding NavigateEvent
.
state
can be set to any
+ serializable value; it will populate the state
+ retrieved by navigation.currentEntry.getState()
once the
+ navigation completes, for same-document navigations. (It will be ignored for navigations that
+ end up cross-document.)
By default this will perform a full navigation (i.e., a cross-document navigation, unless the
+ given URL differs only in a fragment from the current
+ one). The navigateEvent.intercept()
method can
+ be used to convert it into a same-document navigation.
The returned promises will behave as follows:
+ +For navigations that get aborted, both promises will reject with an
+ "AbortError
" DOMException
.
For same-document navigations created by using the navigateEvent.intercept()
method, committed
will fulfill immediately, and finished
will fulfill or reject according to any
+ promsies returned by handlers passed to intercept()
.
For other same-document navigations (e.g., non-intercepted fragment navigations), both promises will fulfill + immediately.
For cross-document navigations, or navigations that result in 204 or 205 statuses or `Content-Disposition: attachment
` header fields from
+ the server (and thus do not actually navigate), both promises will never settle.
In all cases, when the returned promises fulfill, it will be with the
+ NavigationHistoryEntry
that was navigated to.
{ committed, finished } = navigation.reload(options)
Reloads the current page. options can contain info
and state
, which behave as described above.
The default behavior of performing a from-network-or-cache reload of the current page can be
+ overriden by the using the navigateEvent.intercept()
method. Doing so will mean
+ this call only updates state or passes along the appropriate info
, plus performing whater actions the navigate
event handlers see fit to carry out.
The returned promises will behave as follows:
+ +If the reload is intercepted by using the navigateEvent.intercept()
method, committed
will fulfill immediately, and finished
will fulfill or reject according to any
+ promsies returned by handlers passed to intercept()
.
Otherwise, both promises will never settle.
{ committed, finished } = navigation.traverseTo(key)
{ committed, finished } = navigation.traverseTo(key, { info })
Traverses to the closest session
+ history entry that matches the NavigationHistoryEntry
with the given
+ key. info
can be set to any value;
+ it will populate the info
property of the
+ corresponding NavigateEvent
.
If a traversal to that session history entry is already in progress, then this
+ will return the promises for that original traversal, and info
will be ignored.
The returned promises will behave as follows:
+ +If there is no NavigationHistoryEntry
in navigation.entries()
whose key
matches key, both promises will
+ reject with an "InvalidStateError
"
+ DOMException
.
For same-document traversals intercepted by the navigateEvent.intercept()
method, committed
will fulfill as soon as the traversal
+ is processed and navigation.currentEntry
is
+ updated, and finished
will fulfill or
+ reject according to any promsies returned by the handlers passed to intercept()
.
For non-intercepted same-document travesals, both promises will fulfill as soon as the
+ traversal is processed and navigation.currentEntry
is updated.
For cross-document traversals, including attempted cross-document traversals that end up
+ resulting in a 204 or 205 statuses or `Content-Disposition: attachment
` header fields from
+ the server (and thus do not actually traverse), both promises will never settle.
{ committed, finished } = navigation.back(key)
{ committed, finished } = navigation.back(key, { info })
Traverses to the closest previous session history entry which results in this
+ navigable traversing, i.e., which corresponds to a different
+ NavigationHistoryEntry
and thus will cause navigation.currentEntry
to change. info
can be set to any value; it will populate the
+ info
property of the corresponding
+ NavigateEvent
.
If a traversal to that session history entry is already in progress, then this
+ will return the promises for that original traversal, and info
will be ignored.
The returned promises behave equivalently to those returned by traverseTo()
.
{ committed, finished } = navigation.forward(key)
{ committed, finished } = navigation.forward(key, { info })
Traverses to the closest forward session history entry which results in this
+ navigable traversing, i.e., which corresponds to a different
+ NavigationHistoryEntry
and thus will cause navigation.currentEntry
to change. info
can be set to any value; it will populate the
+ info
property of the corresponding
+ NavigateEvent
.
If a traversal to that session history entry is already in progress, then this
+ will return the promises for that original traversal, and info
will be ignored.
The returned promises behave equivalently to those returned by traverseTo()
.
The navigate(options)
method steps are:
Parse url relative to this's
+ relevant settings object. If that returns failure, then return an early error result for a
+ "SyntaxError
" DOMException
. Otherwise, let
+ urlRecord be the resulting URL record.
Let document be this's relevant global object's associated Document
.
If options["history
"] is "push
", and the navigation must be a
+ replace given urlRecord and document, then return an early error result for a
+ "NotSupportedError
" DOMException
.
Let state be options["state
"], if it exists; otherwise, undefined.
Let serializedState be + StructuredSerializeForStorage(state). If this throws an exception, then + return an early error result for that + exception.
+ +It is importantly to perform this step early, since serialization can invoke web + developer code, which in turn might change various things we check in later steps.
+If document is not fully active, then return an early error result for an
+ "InvalidStateError
" DOMException
.
If document's unload counter is greater than 0, then return an
+ early error result for an
+ "InvalidStateError
" DOMException
.
Let info be options["info
"], if it exists;
+ otherwise, undefined.
Let apiMethodTracker be the result of maybe setting the upcoming non-traverse API method + tracker for this given info and + serializedState.
Navigate document's node
+ navigable to urlRecord using document, with historyHandling set to options["history
"] and navigationAPIState set to
+ serializedState.
Unlike location.assign()
and friends,
+ which are exposed across origin-domain boundaries,
+ navigation.navigate()
can only be accessed by code
+ with direct synchronous access to the window.navigation
+ property. Thus, we avoid the complications about attributing the source document of the
+ navigation, and we don't need to deal with the allowed by sandboxing to navigate
+ check and its acccompanying exceptionsEnabled flag. We just
+ treat all navigations as if they come from the Document
corresponding to this
+ Navigation
object itself (i.e., document).
If this's upcoming non-traverse API method tracker is + apiMethodTracker, then:
+ +If the upcoming non-traverse API method tracker is still
+ apiMethodTracker, this means that the navigate algorithm bailed out
+ before ever getting to the inner navigate
event
+ firing algorithm which would promote that upcoming API method tracker to ongoing.
Set this's upcoming non-traverse API method tracker to + null.
Return an early error result for
+ an "AbortError
" DOMException
.
Return a navigation API method tracker-derived result for + apiMethodTracker.
The reload(options)
method steps are:
Let document be this's relevant global object's associated Document
.
Let serializedState be + StructuredSerializeForStorage(undefined).
If options["state
"] exists, then set serializedState to
+ StructuredSerializeForStorage(options["state
"]). If this throws an exception, then
+ return an early error result for that
+ exception.
It is importantly to perform this step early, since serialization can invoke web + developer code, which in turn might change various things we check in later steps.
+Otherwise:
+ +Let current be the current + entry of this.
If current is not null, then set serializedState to + current's session history entry's navigation API state.
If document is not fully active, then return an early error result for an
+ "InvalidStateError
" DOMException
.
If document's unload counter is greater than 0, then return an
+ early error result for an
+ "InvalidStateError
" DOMException
.
Let info be options["info
"], if it exists;
+ otherwise, undefined.
Let apiMethodTracker be the result of maybe setting the upcoming non-traverse API method + tracker for this given info and + serializedState.
Reload document's node navigable with navigationAPIState set to + serializedState.
Return a navigation API method tracker-derived result for + apiMethodTracker.
The traverseTo(key, options)
+ method steps are:
If this's current entry
+ index is −1, then return an early
+ error result for an "InvalidStateError
"
+ DOMException
.
If this's entry list does not
+ contain a NavigationHistoryEntry
whose session history entry's navigation
+ API key equals key, then return an early error result for an
+ "InvalidStateError
" DOMException
.
Return the result of performing a navigation API traversal given + this, key, and options.
The back(options)
method steps are:
If this's current entry
+ index is −1 or 0, then return an early error result for an
+ "InvalidStateError
" DOMException
.
Let key be this's entry + list[this's current entry + index − 1]'s session history entry's navigation API key.
Return the result of performing a navigation API traversal given + this, key, and options.
The forward(options)
method steps are:
If this's current entry
+ index is −1 or is equal to this's entry list's size −
+ 1, then return an early error result for
+ an "InvalidStateError
" DOMException
.
Let key be this's entry + list[this's current entry + index + 1]'s session history entry's navigation API key.
Return the result of performing a navigation API traversal given + this, key, and options.
To perform a navigation API traversal
+ given a Navigation
navigation, a string key, and a
+ NavigationOptions
options:
Let document be navigation's relevant global object's
+ associated Document
.
If document is not fully active, then return an early error result for an
+ "InvalidStateError
" DOMException
.
If document's unload counter is greater than 0, then return an
+ early error result for an
+ "InvalidStateError
" DOMException
.
Let current be the current entry + of navigation.
If key equals current's session history
+ entry's navigation API key, then return «[
+ "committed
" → a promise resolved
+ with current, "finished
"
+ → a promise resolved with current ]».
If navigation's upcoming traverse API method + trackers[key] exists, then return a + navigation API method tracker-derived result for navigation's + upcoming traverse API method trackers[key].
Let info be options["info
"], if it exists;
+ otherwise, undefined.
Let apiMethodTracker be the result of adding an upcoming traverse API method tracker for + navigation given key and info.
Let navigable be document's node navigable.
Let traversable be navigable's traversable navigable.
Let sourceSnapshotParams be the result of snapshotting source snapshot + params given document.
Append the following session history + traversal steps to traversable:
+ +Let navigableSHEs be the result of getting session history + entries given navigable.
Let targetSHE be the session history entry in + navigableSHEs whose navigation API key + is key. If no such entry exists, then:
+ +Queue a global task on the navigation and traversal task
+ source given navigation's relevant global object to
+ reject the finished promise for apiMethodTracker with an
+ "InvalidStateError
" DOMException
.
Abort these steps.
This path is taken if navigation's entry list was outdated compared to + navigableSHEs, which can occur for brief periods while all the relevant threads and + processes are being synchronized in reaction to a history change.
+If targetSHE is navigable's active session history entry, then abort these + steps.
+ +This can occur if a previously queued traversal already took us to + this session history entry. In that case the previous traversal will have dealt + with apiMethodTracker already.
+Let result be the result of applying the traverse history step given by targetSHE's step to traversable, given sourceSnapshotParams,
+ navigable, and "none
".
If result is "canceled-by-beforeunload
", then
+ queue a global task on the navigation and traversal task source given
+ navigation's relevant global object to reject the finished
+ promise for apiMethodTracker with a new
+ "AbortError
" DOMException
created in
+ navigation's relevant realm.
If result is "initiator-disallowed
", then queue a
+ global task on the navigation and traversal task source given
+ navigation's relevant global object to reject the finished
+ promise for apiMethodTracker with a new
+ "SecurityError
" DOMException
created in
+ navigation's relevant realm.
When result is "canceled-by-beforeunload
" or "initiator-disallowed
", the navigate
+ event was never fired, aborting the ongoing
+ navigation would not be correct; it would result in a navigateerror
event without a preceding navigate
event.
In the "canceled-by-navigate
" case, navigate
is fired, but the inner navigate
event firing algorithm will take care of
+ aborting the ongoing navigation.
Return a navigation API method tracker-derived result for + apiMethodTracker.
An early error result for an exception
+ e is a NavigationResult
dictionary instance given by «[ "committed
" → a promise rejected with
+ e, "finished
" → a promise
+ rejected with e ]».
A navigation API method tracker-derived result for a navigation API method
+ tracker is a NavigationResult
dictionary instance given by «[ "committed
" apiMethodTracker's committed promise, "finished
" → apiMethodTracker's finished promise ]».
During any given navigation (in the broad sense of the
+ word), the Navigation
object needs to keep track of the following:
State + | Duration + | Explanation + |
---|---|---|
The NavigateEvent
+ | For the duration of event firing + | So that if the navigation is canceled while the event is firing, we can cancel the event + |
The event's abort controller + | Until all promises returned from handlers passed to intercept() have settled
+ | So that if the navigation is canceled, we can signal abort + |
Whether a new element was focused + | Until all promises returned from handlers passed to intercept() have settled
+ | So that if one was, focus is not reset + |
The NavigationHistoryEntry being navigated to
+ | From when it is determined, until all promises returned from handlers passed to intercept() have settled
+ | So that we know what to resolve any committed and finished promises with
+ |
Any finished promise that was returned
+ | Until all promises returned from handlers passed to intercept() have settled
+ | So that we can resolve or reject it appropriately + |
State + | Duration + | Explanation + |
---|---|---|
Any state
+ | For the duration of event firing + | So that we can update the current entry's navigation API state if the event finishes firing without being canceled + |
State + | Duration + | Explanation + |
---|---|---|
Any info
+ | Until the task is queued to fire the navigate event
+ | So that we can use it to fire the navigate after the trip through the session history traversal queue.
+ |
Any committed promise that was returned
+ | Until the session history is updated (inside that same task) + | So that we can resolve or reject it appropriately + |
Whether intercept() was called
+ | Until the session history is updated (inside that same task) + | So that we can suppress the normal scroll restoration logic in favor of the behavior given by the scroll option
+ |
We also cannot assume there is only a single navigation requested at any given time, due to web + developer code such as:
+ +const p1 = navigation.navigate(url1).finished;
+const p2 = navigation.navigate(url2).finished;
+
+ That is, in this scenario, we need to ensure that while navigating to url2
, we still have the promise p1
around so that we can
+ reject it. We can't just get rid of any ongoing navigation promises the moment the second call to
+ navigate()
happens.
We end up accomplishing all this by associating the following with each
+ Navigation
:
Ongoing navigate
event, a
+ NavigateEvent
or null, initially null.
Focus changed during ongoing navigation, a boolean, initially false.
Suppress normal scroll restoration during ongoing navigation, a boolean, + initially false.
Ongoing API method tracker, a navigation API method tracker or + null, initially null.
Upcoming non-traverse API method tracker, a navigation API method + tracker or null, initially null.
Upcoming traverse API method trackers, a map from strings to navigation API method trackers, initially + empty.
The state here that is not stored in navigation API method trackers is state which needs to be tracked even for + navigations that are not initiated via navigation API methods.
+ +A navigation API method tracker is a struct with the following items:
+ +A navigation object, a
+ Navigation
A key, a string or null
An info, a JavaScript + value
A serialized state, a + serialized state or null
A committed-to entry,
+ a NavigationHistoryEntry
or null
A committed promise, a + promise
A finished promise, a + promise
All this state is then managed via the following algorithms.
+ +To maybe set the upcoming non-traverse API method tracker given a
+ Navigation
navigation, a JavaScript value info, and a
+ serialized state-or-null serializedState:
Let committedPromise and finishedPromise be new promises created in + navigation's relevant realm.
Mark as handled finishedPromise.
+ + +Let apiMethodTracker be a new navigation API method tracker with:
+ +Assert: navigation's upcoming non-traverse API method + tracker is null.
If navigation does not have + entries and events disabled, then set navigation's upcoming + non-traverse API method tracker to apiMethodTracker.
+ +If navigation has entries and events disabled, then
+ committedPromise and finishedPromise will never fulfill (since we never
+ create a NavigationHistoryEntry
object for such Document
s, and so we
+ have nothing to resolve them with); there is no NavigationHistoryEntry
to apply
+ serializedState to; and there is no navigate
+ event to include info with. So, we don't need to track this API method call after
+ all.
Return apiMethodTracker.
To add an upcoming traverse API method tracker given a Navigation
+ navigation, a string destinationKey, and a JavaScript value
+ info:
Let committedPromise and finishedPromise be new promises created in + navigation's relevant realm.
Mark as handled finishedPromise.
+ +See the previous + discussion about why this is done.
+Let apiMethodTracker be a new navigation API method tracker with:
+ +Set navigation's upcoming traverse API method + trackers[key] to apiMethodTracker.
Return apiMethodTracker.
To promote an upcoming API method tracker to ongoing given a Navigation
+ navigation and a string-or-null destinationKey:
Assert: navigation's ongoing API method tracker is + null.
If destinationKey is not null, then:
+ +Assert: navigation's upcoming non-traverse API method + tracker is null.
If navigation's upcoming traverse API method + trackers[destinationKey] exists, then:
+ +Set navigation's ongoing API method tracker to + navigation's upcoming traverse API method + trackers[destinationKey].
Remove navigation's upcoming + traverse API method trackers[destinationKey].
Otherwise:
+ +Set navigation's ongoing API method tracker to + navigation's upcoming non-traverse API method tracker.
Set navigation's upcoming non-traverse API method tracker to + null.
To clean up a navigation API + method tracker apiMethodTracker:
+ +Let navigation be apiMethodTracker's navigation object.
If navigation's ongoing API method tracker is + apiMethodTracker, then set navigation's ongoing API method + tracker to null.
Otherwise:
+ +Let key be apiMethodTracker's key.
Assert: key is not null.
Assert: navigation's upcoming traverse API method + trackers[key] exists.
Remove navigation's upcoming traverse + API method trackers[key].
To notify about the committed-to entry given a navigation API method
+ tracker apiMethodTracker and a NavigationHistoryEntry
+ nhe:
Set apiMethodTracker's committed-to entry to + nhe.
If apiMethodTracker's serialized state is not null, then set + nhe's session history entry's navigation API state to apiMethodTracker's + serialized state.
+ +If it's null, then we're traversing to nhe via navigation.traverseTo()
, which does not allow changing
+ the state.
At this point, apiMethodTracker's serialized state is no longer needed. + Implementations might want to clear it out to avoid keeping it alive for the lifetime of the + navigation API method tracker.
+Resolve apiMethodTracker's committed promise with + nhe.
+ +At this point, apiMethodTracker's committed promise is only needed in + cases where it has not yet been returned to author code. Implementations might want to clear it + out to avoid keeping it alive for the lifetime of the navigation API method + tracker.
+To resolve the finished promise for a navigation API method tracker + apiMethodTracker:
+ +Resolve apiMethodTracker's committed promise with its committed-to entry.
+ +Usually, notify about the committed-to entry has previously been + called on apiMethodTracker, and so this will do nothing. However, in some cases + resolve the finished promise is called directly, in which case this step is + necessary.
+Resolve apiMethodTracker's finished promise with its committed-to entry.
Clean up + apiMethodTracker.
To reject the finished promise for a navigation API method tracker + apiMethodTracker with a JavaScript value exception:
+ +Reject apiMethodTracker's committed promise with + exception.
+ +This will do nothing if apiMethodTracker's committed promise was previously + resolved via notify about the committed-to entry.
+Reject apiMethodTracker's finished promise with + exception.
Clean up + apiMethodTracker.
To abort the ongoing navigation given a Navigation
+ navigation and an optional DOMException
error:
Let event be navigation's ongoing navigate
event.
Assert: event is not null.
Set navigation's focus changed during ongoing navigation to + false.
Set navigation's suppress normal scroll restoration during ongoing + navigation to false.
If error was not given, then let error be a new
+ "AbortError
" DOMException
created in
+ navigation's relevant realm.
If event's dispatch flag is set, then set event's + canceled flag to true.
Signal abort on event's abort controller given + error.
Set navigation's ongoing navigate
+ event to null.
Fire an event named navigateerror
at navigation using
+ ErrorEvent
, with error
initialized to
+ error, and message
, filename
, lineno
, and colno
initialized to appropriate values
+ that can be extracted from error and the current JavaScript stack in the same
+ underspecified way that the report the exception algorithm does.
Thus, for example, if this algorithm is reached because of a call to window.stop()
, these properties would probably end up
+ initialized based on the line of script that called window.stop()
. But if it's because the user clicked the stop
+ button, these properties would probably end up with default values like the empty string or
+ 0.
If navigation's ongoing API method tracker is non-null, then + reject the finished promise for apiMethodTracker with + error.
If navigation's transition is + not null, then:
+ +Reject navigation's transition's finished promise with + error.
Set navigation's transition to null.
To inform the navigation API about aborting navigation in a navigable + navigable:
+ +If this algorithm is running on navigable's active + window's relevant agent's event + loop, then continue on to the following steps. Otherwise, queue a global task + on the navigation and traversal task source given navigable's active window to run the following steps.
Let navigation be navigable's active + window's navigation API.
If navigation's ongoing navigate
+ event is null, then return.
Abort the ongoing navigation given navigation.
To inform the navigation API about child navigable destruction given a + navigable navigable:
+ +Inform the navigation API about aborting navigation in + navigable.
Let navigation be navigable's active + window's navigation API.
Let traversalAPIMethodTrackers to be clone of + navigation's upcoming traverse API method trackers.
For each apiMethodTracker of
+ traversalAPIMethodTrackers: reject the finished promise for
+ apiMethodTracker with a new "AbortError
"
+ DOMException
created in navigation's relevant realm.
The ongoing navigation concept is most-directly exposed to web developers through the navigation.transition
property, which is an instance of
+ the NavigationTransition
interface:
[Exposed=Window]
+interface NavigationTransition {
+ readonly attribute NavigationType navigationType;
+ readonly attribute NavigationHistoryEntry from;
+ readonly attribute Promise<undefined> finished;
+};
+
+ navigation.transition
A NavigationTransition
representing any ongoing navigation that hasn't yet
+ reached the navigatesuccess
or navigateerror
stage, if one exists; or null, if there is no
+ such transition ongoing.
Since navigation.currentEntry
(and other
+ properties like location.href
) are updated immediately
+ upon navigation, this navigation.transition
+ property is useful for determining when such navigations are not yet fully settled, according to
+ any handlers passed to navigateEvent.intercept()
.
navigation.transition.navigationType
One of "push
", "replace
", "reload
", or "traverse
", indicating what type of navigation this
+ transition is for.
navigation.transition.from
The NavigationHistoryEntry
from which the transition is coming. This can be
+ useful to compare against navigation.currentEntry
.
navigation.transition.finished
A promise which fulfills at the same time as the navigatesuccess
fires, or rejects at the same time the
+ navigateerror
event fires.
Each Navigation
has a transition, which is a
+ NavigationTransition
or null, initially null.
The transition
getter steps are to return
+ this's transition.
Each NavigationTransition
has an associated navigation type, which is a
+ NavigationType
.
Each NavigationTransition
has an associated from entry, which is a
+ NavigationHistoryEntry
.
Each NavigationTransition
has an associated finished promise, which is a promise.
The navigationType
getter steps are to
+ return this's navigation
+ type.
The from
getter steps are to return
+ this's from entry.
The finished
getter steps are to return
+ this's finished
+ promise.
navigate
eventA major feature of the navigation API is the navigate
+ event. This event is fired on any navigation (in the broad sense of
+ the word), allowing web developers to monitor such outgoing navigations. In many cases, the
+ event is cancelable
, which allows preventing the
+ navigation from happening. And in others, the navigation can be intercepted and replaced with a
+ same-document navigation by using the intercept()
method of the NavigateEvent
+ class.
NavigateEvent
interface[Exposed=Window]
+interface NavigateEvent : Event {
+ constructor(DOMString type, NavigateEventInit eventInitDict);
+
+ readonly attribute NavigationType navigationType;
+ readonly attribute NavigationDestination destination;
+ readonly attribute boolean canIntercept;
+ readonly attribute boolean userInitiated;
+ readonly attribute boolean hashChange;
+ readonly attribute AbortSignal signal;
+ readonly attribute FormData
? formData;
+ readonly attribute DOMString? downloadRequest;
+ readonly attribute any info;
+
+ undefined intercept(optional NavigationInterceptOptions options = {});
+ undefined scroll();
+};
+
+dictionary NavigateEventInit : EventInit {
+ NavigationType navigationType = "push";
+ required NavigationDestination destination;
+ boolean canIntercept = false;
+ boolean userInitiated = false;
+ boolean hashChange = false;
+ required AbortSignal signal;
+ FormData? formData = null;
+ DOMString? downloadRequest = null;
+ any info;
+};
+
+dictionary NavigationInterceptOptions {
+ NavigationInterceptHandler handler;
+ NavigationFocusReset focusReset;
+ NavigationScrollBehavior scroll;
+};
+
+enum NavigationFocusReset {
+ "after-transition",
+ "manual"
+};
+
+enum NavigationScrollBehavior {
+ "after-transition",
+ "manual"
+};
+
+callback NavigationInterceptHandler = Promise<undefined> ();
+
+ event.navigationType
One of "push
", "replace
", "reload
", or "traverse
", indicating what type of navigation this
+ is.
event.destination
A NavigationDestination
representing the destination of the
+ navigation.
event.canIntercept
True if intercept()
can be called to
+ intercept this navigation and convert it into a same-document navigation, replacing its usual
+ behavior; false otherwise.
Generally speaking, this will be true whenever the current Document
can
+ have its URL rewritten to the destination URL, except for in the case of cross-document
+ "traverse
" navigations, where it will always
+ be false.
event.userInitiated
True if this navigation was due to a user clicking on an a
element,
+ submitting a form
element, or using the browser UI
+ to navigate; false otherwise.
event.hashChange
True for a fragment navigation; false + otherwise.
event.signal
An AbortSignal
which will become aborted if the navigation gets canceled, e.g.,
+ by the user pressing their browser's "Stop" button, or by another navigation interrupting this
+ one.
The expected pattern is for developers to pass this along to any async operations, such as
+ fetch()
, which they perform as part of handling this navigation.
event.formData
The FormData
representing the submitted form entries for this navigation, if
+ this navigation is a "push
" or "replace
" navigation representing a POST form submission; null otherwise.
(Notably, this will be null even for "reload
"
+ or "traverse
" navigations that are revisiting
+ a session history entry that was originally created from a form submission.)
event.downloadRequest
Represents whether or not this navigation was requested to be a download, by using an
+ a
or area
element's download
attribute:
If a download was not requested, then this property is null.
If a download was requested, returns the filename that was supplied as the download
attribute's value. (This could be the empty
+ string.)
Note that a download being requested does not always mean that a download will happen: for
+ example, a download might be blocked by browser security policies, or end up being treated as a
+ "push
" navigation for unspecified reasons.
Similarly, a navigation might end up being a download even if it was not requested to be one,
+ due to the destination server responding with a `Content-Disposition: attachment
` header.
Finally, note that the navigate
event will not fire at
+ all for downloads initiated using browser UI affordances, e.g., those created by right-clicking
+ and choosing to save the target of a link.
event.info
An arbitrary JavaScript value passed via one of the navigation API methods which initiated this + navigation, or undefined if the navigation was initiated by the user or by a different + API.
event.intercept({ handler, focusReset, scroll })
Intercepts this navigation, preventing its normal handling and instead converting it into a + same-document navigation of the same type to the destination URL.
+ +The handler
option can be a
+ function that returns a promise. The handler function will run after the navigate
event has finished firing, and the navigation.currentEntry
property has been
+ synchronously updated. This returned promise is used to signal the duration, and success or
+ failure, of the navigation. After it settles, the browser signals to the user (e.g., via a
+ loading spinner UI, or assistive technology) that the navigation is finished. Additionally, it
+ fires navigatesuccess
or navigateerror
events as appropriate, which other parts of
+ the web application can respond to.
By default, using this method will cause focus to reset when any handlers' returned promises
+ settle. Focus will be reset to the first element with the autofocus
attribute set, or the body element if
+ the attribute isn't present. The focusReset
option can be set to "manual
" to avoid this behavior.
By default, using this method will delay the browser's scroll restoration logic for "traverse
" or "reload
" navigations, or its
+ scroll-reset/scroll-to-a-fragment logic for "push
"
+ or "replace
" navigations, until any handlers'
+ returned promises settle. The scroll
+ option can be set to "manual
" to turn
+ off any browser-driven scroll behavior entirely for this navigation, or scroll()
can be called before the promise settles to
+ trigger this behavior early.
This method will throw a "SecurityError
" DOMException
+ if canIntercept
is false, or if isTrusted
is false. It will throw an
+ "InvalidStateError
" DOMException
if not called
+ synchronously, during event dispatch.
event.scroll()
For "traverse
" or "reload
" navigations, restores the scroll position
+ using the browser's usual scroll restoration logic.
For "push
" or "replace
" navigations, either resets the scroll
+ position to the top of the document or scrolls to the fragment specified by destination.url
if there is one.
If called more than once, or called after automatic post-transition scroll processing has
+ happened due to the scroll
option
+ being left as "after-transition
", or called
+ before the navigation has committed, this method will throw an
+ "InvalidStateError
" DOMException
.
Each NavigateEvent
has an interception state, which is either "none
", "intercepted
", "committed
",
+ "scrolled
", or "finished
", initially "none
".
Each NavigateEvent
has a navigation handler list, a
+ list of NavigationInterceptHandler
callbacks, initially empty.
Each NavigateEvent
has a focus
+ reset behavior, a NavigationFocusReset
-or-null, initially null.
Each NavigateEvent
has a scroll
+ behavior, a NavigationScrollBehavior
-or-null, initially null.
Each NavigateEvent
has an abort controller, an
+ AbortController
-or-null, initially null.
Each NavigateEvent
has a classic history API state, a
+ serialized state or null. It is only used in some cases where the event's navigationType
is "push
" or "replace
", and is set appropriately when the event is
+ fired.
The navigationType
, destination
, canIntercept
, userInitiated
,
+ hashChange
, signal
, formData
, downloadRequest
, and info
attributes must return
+ the values they are initialized to.
The intercept(options)
method steps
+ are:
Perform shared checks given + this.
If this's canIntercept
+ attribute was initialized to false, then throw a "SecurityError
"
+ DOMException
.
If this's dispatch flag is unset, then throw an
+ "InvalidStateError
" DOMException
.
Assert: this's interception state is either "none
" or "intercepted
".
Set this's interception state to "intercepted
".
If options["handler
"] exists, then append it to this's
+ navigation handler
+ list.
If options["focusReset
"] exists, then:
If this's focus reset
+ behavior is not null, and it is not equal to options["focusReset
"], then the user agent may
+ report a warning to the console indicating that the focusReset
option for a previous call
+ to intercept()
was overridden by this new
+ value, and the previous value will be ignored.
Set this's focus reset
+ behavior to options["focusReset
"].
If options["scroll
"]
+ exists, then:
If this's scroll
+ behavior is not null, and it is not equal to options["scroll
"], then the user agent may
+ report a warning to the console indicating that the scroll
option for a previous call to
+ intercept()
was overridden by this new value,
+ and the previous value will be ignored.
Set this's scroll
+ behavior to options["scroll
"].
The scroll()
method steps are:
Perform shared checks given + this.
If this's interception state is not "committed
", then throw an "InvalidStateError
"
+ DOMException
.
Process scroll behavior given this.
To perform shared checks for a
+ NavigateEvent
event:
If event's relevant global object's associated Document
is not fully
+ active, then throw an "InvalidStateError
"
+ DOMException
.
If event's isTrusted
attribute was
+ initialized to false, then throw a "SecurityError
"
+ DOMException
.
If event's canceled flag is set, then throw an
+ "InvalidStateError
" DOMException
.
NavigationDestination
interface[Exposed=Window]
+interface NavigationDestination {
+ readonly attribute USVString url;
+ readonly attribute DOMString key;
+ readonly attribute DOMString id;
+ readonly attribute long long index;
+ readonly attribute boolean sameDocument;
+
+ any getState();
+};
+
+ event.destination.url
The URL being navigated to.
event.destination.key
The value of the key
property of the
+ destination NavigationHistoryEntry
, if this is a "traverse
" navigation, or the empty string otherwise.
event.destination.id
The value of the id
property of the
+ destination NavigationHistoryEntry
, if this is a "traverse
" navigation, or the empty string otherwise.
event.destination.index
The value of the index
property of
+ the destination NavigationHistoryEntry
, if this is a "traverse
" navigation, or −1 otherwise.
+
event.destination.sameDocument
Indicates whether or not this navigation is to the same Document
as the current
+ one, or not. This will be true, for example, in the case of fragment navigations or history.pushState()
navigations.
Note that this property indicates the original nature of the navigation. If a cross-document
+ navigation is converted into a same-document navigation using navigateEvent.intercept()
, that will not change the
+ value of this property.
event.destination.getState()
For "traverse
" navigations, returns the
+ deserialization of the state stored in the
+ destination session history entry.
For "push
" or "replace
" navigations, returns the deserialization of the state passed to navigation.navigate()
, if the navigation was initiated
+ by that method, or undefined it if it wasn't.
For "reload
" navigations, returns the deserialization of the state passed to navigation.reload()
, if the reload was initiated by that
+ method, or undefined it if it wasn't.
Each NavigationDestination
has a URL, which is a URL.
Each NavigationDestination
has an entry, which is a
+ NavigationHistoryEntry
or null.
It will be non-null if and only if the NavigationDestination
+ corresponds to a "traverse
" navigation.
Each NavigationDestination
has a state, which is a serialized
+ state.
Each NavigationDestination
has an is same document, which is a
+ boolean.
The url
getter steps are to return
+ this's URL, serialized.
The key
getter steps are:
If this's entry is + null, then return the empty string.
Return this's entry's key.
The id
getter steps are:
If this's entry is + null, then return the empty string.
Return this's entry's ID.
The index
getter steps are:
If this's entry is + null, then return −1.
Return this's entry's index.
The sameDocument
getter steps are to
+ return this's is same
+ document.
The getState()
method steps are to return
+ StructuredDeserialize(this's state).
Other parts of the standard fire the navigate
event,
+ through a series of wrapper algorithms given in this section.
To fire a traverse navigate
event at a
+ Navigation
navigation given a session history entry destinationSHE and an optional
+ user navigation involvement userInvolvement (default "none
"):
Let event be the result of creating an event given
+ NavigateEvent
, in navigation's relevant realm.
Set event's classic history API state to + null.
Let destination be a new NavigationDestination
+ created in navigation's relevant
+ realm.
Set destination's URL + to destinationSHE's URL.
Let destinationNHE be the NavigationHistoryEntry
in
+ navigation's entry list whose session history entry is destinationSHE, or null if no such
+ NavigationHistoryEntry
exists.
If destinationNHE is non-null, then:
+ +Set destination's entry to + destinationNHE.
Set destination's state to destinationSHE's navigation API state.
Otherwise,
+ +Set destination's entry to null.
Set destination's state to + StructuredSerializeForStorage(null).
Set destination's is
+ same document to true if destinationSHE's document is equal to navigation's relevant global
+ object's associated Document
;
+ otherwise false.
Return the result of performing the inner navigate
event firing algorithm given
+ navigation, "traverse
",
+ event, destination, userInvolvement, null, and null.
To fire a push/replace/reload navigate
event at
+ a Navigation
navigation given a NavigationType
navigationType, a URL destinationURL, a boolean isSameDocument, an optional user
+ navigation involvement userInvolvement (default "none
"), an optional entry list-or-null formDataEntryList (default null), an
+ optional serialized state navigationAPIState (default
+ StructuredSerializeForStorage(null)), and an optional serialized
+ state-or-null classicHistoryAPIState (default
+ null):
Let event be the result of creating an event given
+ NavigateEvent
, in navigation's relevant realm.
Set event's classic history API state to + classicHistoryAPIState.
Let destination be a new NavigationDestination
+ created in navigation's relevant
+ realm.
Set destination's URL + to destinationURL.
Set destination's entry to null.
Set destination's state to + navigationAPIState.
Set destination's is + same document to isSameDocument.
Return the result of performing the inner navigate
event firing algorithm given
+ navigation, navigationType, event, destination,
+ userInvolvement, formDataEntryList, and null.
To fire a download request navigate
event at a
+ Navigation
navigation given a URL destinationURL, a user
+ navigation involvement userInvolvement, and a string
+ filename:
Let event be the result of creating an event given
+ NavigateEvent
, in navigation's relevant realm.
Set event's classic history API state to + null.
Let destination be a new NavigationDestination
+ created in navigation's relevant
+ realm.
Set destination's URL + to destinationURL.
Set destination's entry to null.
Set destination's state to + StructuredSerializeForStorage(null).
Set destination's is + same document to false.
Return the result of performing the inner navigate
event firing algorithm given
+ navigation, "push
", event,
+ destination, userInvolvement, null, and filename.
The inner navigate
event firing algorithm
+ consists of the following steps, given a Navigation
navigation, a
+ NavigationType
navigationType, a NavigateEvent
+ event, a NavigationDestination
destination, a user
+ navigation involvement userInvolvement, an entry list-or-null
+ formDataEntryList, and a string-or-null downloadRequestFilename:
If navigation has entries and events disabled, then:
+ +Assert: navigation's ongoing API method tracker is + null.
Assert: navigation's upcoming non-traverse API method + tracker is null.
Assert: navigation's upcoming traverse API method + trackers is empty.
Return true.
These assertions holds because traverseTo()
, back()
, and forward()
will immediately fail when entries and events
+ are disabled (since there are no entries to traverse to), and if our starting point is instead
+ navigate()
or reload()
, then we avoided setting the
+ upcoming non-traverse API method tracker in the first place.
Let destinationKey be null.
If destination's entry is non-null, then set + destinationKey to destination's entry's key.
Assert: destinationKey is not the empty string.
Promote an upcoming API method tracker to ongoing given + navigation and destinationKey.
Let apiMethodTracker be navigation's ongoing API method + tracker.
Let navigable be navigation's relevant global object's + navigable.
Let document be navigation's relevant global object's
+ associated Document
.
If document can have its URL rewritten to destination's
+ URL, and either destination's
+ is same document is true or
+ navigationType is not "traverse
",
+ then initialize event's canIntercept
to true. Otherwise, initialize it to
+ false.
If either:
+ +navigationType is not "traverse
"; or
traverseCanBeCanceled is true
the initialize event's cancelable
to
+ true. Otherwise, initialize it to false.
Initialize event's type
to "navigate
".
Initialize event's navigationType
to
+ navigationType.
Initialize event's destination
to destination.
Initialize event's downloadRequest
to
+ downloadRequestFilename.
If apiMethodTracker is not null, then initialize event's info
to apiMethodTracker's info. Otherwise, initialize it to
+ undefined.
At this point apiMethodTracker's info is no longer needed and can be nulled + out instead of keeping it alive for the lifetime of the navigation API method + tracker.
+Set event's abort
+ controller to a new AbortController
created in
+ navigation's relevant realm.
Initialize event's signal
to
+ event's abort
+ controller's signal.
Let currentURL be document's URL.
If all of the following are true:
+ +destination's is + same document is true;
destination's URL + equals currentURL with exclude fragments set to true; and
destination's URL's + fragment is not identical to + currentURL's fragment
then initialize event's hashChange
to true. Otherwise, initialize it to
+ false.
If userInvolvement is not "none
", then
+ initialize event's userInitiated
+ to true. Otherwise, initialize it to false.
If formDataEntryList is not null, then initialize event's formData
to a new FormData
+ created in navigation's relevant realm,
+ associated to formDataEntryList. Otherwise, initialize it to null.
Assert: navigation's ongoing navigate
event is null.
Set navigation's ongoing navigate
+ event to event.
Set navigation's focus changed during ongoing navigation to + false.
Set navigation's suppress normal scroll restoration during ongoing + navigation to false.
Let dispatchResult be the result of dispatching event at + navigation.
If dispatchResult is false:
+ +If navigationType is "traverse
", then consume history-action user
+ activation.
If event's abort + controller's signal is not aborted, then abort the ongoing navigation + given navigation.
Return false.
Let endResultIsSameDocument be true if event's interception state is not "none
" or event's destination
's is same document is true.
Prepare to run script given navigation's relevant settings + object.
+ + +If event's interception
+ state is not "none
":
Set event's interception state to "committed
".
Let fromNHE be the current + entry of navigation.
Assert: fromNHE is not null.
Set navigation's transition to a new
+ NavigationTransition
created in navigation's relevant realm, whose navigation type is
+ navigationType, from entry
+ is fromNHE, and whose finished
+ promise is a new promise created in navigation's relevant realm.
Mark as handled navigation's transition's finished promise.
+ +See the discussion + about other finished promises to understand why this is done.
+If navigationType is "traverse
", then set navigation's
+ suppress normal scroll restoration during ongoing navigation to true.
If event's scroll
+ behavior was set to "after-transition
", then scroll
+ restoration will happen as part of finishing the
+ relevant NavigateEvent
. Otherwise, there will be no scroll restoration. That is,
+ no navigation which is intercepted by intercept()
goes through the normal scroll
+ restoration process; scroll restoration for such navigations is either done manually, by the
+ web developer, or is done after the transition.
If navigationType is "push
" or
+ "replace
", then run the URL and history
+ update steps given document and event's destination
's URL, with serialiedData set to event's classic history API state and
+ historyHandling set to navigationType.
If navigationType is "reload
",
+ then we are converting a reload into a "same-document reload", for which the
+ URL and history update steps are not appropriate. Navigation API-related stuff
+ still happens, such as updating the active session
+ history entry's navigation API state if
+ this was caused by a call to navigation.reload()
,
+ and all the ongoing navigation tracking.
If navigationType is "traverse
", then this event firing is happening as
+ part of the traversal process, and that
+ process will take care of performing the appropriate session history entry updates.
If endResultIsSameDocument is true:
+ +Let promisesList be an empty list.
For each handler of event's navigation handler list:
+ +Append the result of invoking handler with an empty + arguments list to promisesList.
If promisesList's size is 0, then set + promisesList to « a promise resolved with undefined ».
+ +There is a subtle timing difference between how waiting for all schedules its success and failure steps when given zero promises
+ versus ≥1 promises. For most uses of waiting for all,
+ this does not matter. However, with this API, there are so many events and promise handlers
+ which could fire around the same time that the difference is pretty easily observable: it can
+ cause the event/promise handler sequence to vary. (Some of the events and promises involved
+ include: navigatesuccess
/ navigateerror
, currententrychange
, dispose
, apiMethodTracker's promises, and the navigation.transition.finished
promise.)
+
Wait for all of promisesList, with the following success steps:
+ +If event's relevant global object is not fully + active, then abort these steps.
If event's abort + controller's signal is aborted, then abort these steps.
Assert: event equals navigation's ongoing
+ navigate
event.
Set navigation's ongoing navigate
event to null.
Finish event given + true.
Fire an event named navigatesuccess
at navigation.
If navigation's transition is not null, then resolve + navigation's transition's + finished promise with + undefined.
Set navigation's transition to null.
If apiMethodTracker is non-null, then resolve the finished + promise for apiMethodTracker.
and the following failure steps given reason rejectionReason:
+ +If event's relevant global object is not fully + active, then abort these steps.
If event's abort + controller's signal is aborted, then abort these steps.
Assert: event equals navigation's ongoing
+ navigate
event.
Set navigation's ongoing navigate
event to null.
Finish event given + false.
Fire an event named navigateerror
at navigation using
+ ErrorEvent
, with error
initialized to
+ rejectionReason, and message
, filename
, lineno
, and colno
initialized to appropriate
+ values that can be extracted from rejectionReason in the same underspecified way
+ that the report the exception algorithm does.
If navigation's transition is not null, then reject + navigation's transition's + finished promise with + rejectionReason.
Set navigation's transition to null.
If apiMethodTracker is non-null, then reject the finished + promise for apiMethodTracker with rejectionReason.
Otherwise, if apiMethodTracker is non-null, then clean up + apiMethodTracker.
Clean up after running script given navigation's relevant + settings object.
+ +Per the previous + note, this stops suppressing any potential promise handler microtasks, causing them to run + at this point or later.
+If event's interception
+ state is "none
", then return true.
Return false.
By calling navigateEvent.intercept()
, web
+ developers can suppress the normal scroll and focus behavior for same-document navigations,
+ instead invoking cross-document navigation-like behavior at a later time. The algorithms in this
+ section are called at those appropriate later points.
To finish a NavigateEvent
+ event, given a boolean didFulfill:
Assert: event's interception state is not "intercepted
" or "finished
".
If event's interception
+ state is "none
", then return.
Potentially reset the focus given event.
If didFulfill is true, then potentially process scroll behavior + given event.
Set event's interception state to "finished
".
To potentially reset the focus given a NavigateEvent
+ event:
Assert: event's interception state is "committed
" or "scrolled
".
Let navigation be event's relevant global object's + navigation API.
Let focusChanged be navigation's focus changed during ongoing + navigation.
Set navigation's focus changed during ongoing navigation to + false.
If focusChanged is true, then return.
If event's focus reset
+ behavior is "manual
", then
+ return.
If it was left as null, then we treat that as "after-transition
", and continue
+ onward.
Let document be event's relevant global object's associated Document
.
Let focusTarget be the autofocus delegate for + document.
If focusTarget is null, then set focusTarget to + document's body element.
If focusTarget is null, then set focusTarget to + document's document element.
Run the focusing steps for focusTarget, with document's + viewport as the fallback target.
Move the sequential focus navigation starting point to + focusTarget.
To potentially process scroll behavior given a NavigateEvent
+ event:
Assert: event's interception state is "committed
" or "scrolled
".
If event's interception
+ state is "scrolled
", then return.
If event's scroll behavior is
+ "manual
", then return.
If it was left as null, then we treat that as "after-transition
", and continue
+ onward.
Process scroll behavior given event.
+To process scroll behavior given a NavigateEvent
event:
Assert: event's interception state is "committed
".
Set event's interception state to "scrolled
".
If event's navigationType
was initialized to "traverse
" or "reload
", then restore scroll position data
+ given event's relevant global object's navigable's active session history
+ entry.
Otherwise:
+ + +The NavigateEvent
interface has its own
+ dedicated section, due to its complexity.
NavigationCurrentEntryChangeEvent
interface[Exposed=Window]
+interface NavigationCurrentEntryChangeEvent : Event {
+ constructor(DOMString type, NavigationCurrentEntryChangeEventInit eventInitDict);
+
+ readonly attribute NavigationType? navigationType;
+ readonly attribute NavigationHistoryEntry from;
+};
+
+dictionary NavigationCurrentEntryChangeEventInit : EventInit {
+ NavigationType? navigationType = null;
+ required NavigationHistoryEntry from;
+};
+
+ event.navigationType
Returns the type of navigation which caused the current entry to change, or null if the
+ change is due to navigation.updateCurrentEntry()
.
event.from
Returns the previous value of navigation.currentEntry
, before the current entry
+ changed.
If navigationType
+ is null or "reload
", then this value will be the
+ same as navigation.currentEntry
. In that case,
+ the event signifies that the contents of the entry changed, even if we did not move to a new
+ entry or replace the current one.
The navigationType
and from
attributes must return the
+ values they were initialized to.
PopStateEvent
interfaceThere are no BeforeUnloadEvent
-specific initialization methods.
The BeforeUnloadEvent
interface is a legacy interface which allows checking
- if unloading is user-canceled to be controlled not only by canceling the event, but by
- setting the returnValue
attribute to a
- value besides the empty string. Authors should use the to be controlled not only by canceling the event, but by setting
+ the
returnValue
attribute to a value
+ besides the empty string. Authors should use the preventDefault()
method, or other means of canceling
events, instead of using returnValue
.
The returnValue
attribute controls the
- process of checking if unloading is user-canceled. When the event is created, the
+ data-x="dom-BeforeUnloadEvent-returnValue">returnValue attribute controls the process
+ of checking if unloading is canceled. When the event is created, the
attribute must be set to the empty string. On getting, it must return the last value it was set
to. On setting, the attribute must be set to the new value.
A non-displayable, non-error response is received during history traversal. This updates the A non-displayable, non-error response is received when applying the history step. This updates the current session history entry but leaves the active session history entry as-is.
Apply pending history changes to traversable.
Update for navigable creation/destruction given + traversable.
Set container's content navigable to null.
Inform the navigation API about child navigable destruction given + navigable.
Destroy navigable's active document.
Apply pending history changes to traversable.
Update for navigable creation/destruction given + traversable.
Let toUnload be traversable's active document's inclusive descendant navigables.
If the result of checking if unloading is user-canceled for - toUnload is true, then return.
If the result of checking if unloading is canceled for toUnload is + true, then return.
Unload the active documents of each of toUnload. In what @@ -90459,9 +93963,9 @@ interface BeforeUnloadEvent : Event { popup sandboxing flag set.
If the newly created navigable chosen is immediately navigated, then the navigation will be done with "replace
" history handling behavior.
If the newly created navigable chosen is immediately
+ navigated, then the navigation will be done as a "replace
" navigation.
about:blank
Document
to
- another, which will be done with replacement.
+ another, which will be done with replacement.
document state, a document state.
serialized state, which is serialized - state, initially StructuredSerializeForStorage(null).
classic history API + state, which is serialized state, initially + StructuredSerializeForStorage(null).
navigation API state, which is a + serialized state, initially + StructuredSerializeForStorage(undefined).
navigation API key, which is a string, + initially set to the result of generating a random UUID.
navigation API ID, which is a string, initially + set to the result of generating a random UUID.
scroll restoration mode, a scroll
restoration mode, initially "
standard when manipulating session history. The best way to get a sense of what they do is to
look at their call sites.
To get session history entries for a - navigable, navigable:
+To get session history entries of a + navigable navigable:
Let traversable be navigable's
Assert: this step is not reached.
To get session history + entries for the navigation API of a navigable navigable given an + integer targetStep:
+ +Let rawEntries be the result of getting session history entries + for navigable.
Let entriesForNavigationAPI be a new empty list.
Let startingIndex be the index of the session history entry in + rawEntries who has the greatest step less than or + equal to targetStep.
+ +See this example to + understand why it's the greatest step less than or equal to targetStep.
+Append rawEntries[startingIndex] + to entriesForNavigationAPI.
Let startingOrigin be rawEntries[startingIndex]'s document state's origin.
Let i be startingIndex − 1.
While i > 0:
+ +If rawEntries[i]'s document + state's origin is not same + origin with startingOrigin, then break.
Prepend rawEntries[i] to + entriesForNavigationAPI.
Set i to i − 1.
Set i to startingIndex + 1.
While i < rawEntries's size:
+ +If rawEntries[i]'s document + state's origin is not same + origin with startingOrigin, then break.
Append rawEntries[i] to + entriesForNavigationAPI.
Set i to i + 1.
Return entriesForNavigationAPI.
To clear the forward session history of a traversable navigable navigable:
@@ -91837,19 +95416,6 @@ location.href = '#foo';Return steps, sorted.
To apply pending history changes to a traversable navigable - traversable with optional boolean checkForUserCancelation (default - false):
- -Let targetStep be traversable's current session history step.
Apply the history step targetStep to traversable with - checkForUserCancelation set to - checkForUserCancelation.
location.assign()
methods can all cause navigation.
-