From c3ca6c22e12fc29c9459a0587cb761cbbc99cd47 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Mon, 26 Jun 2023 09:09:47 +0000 Subject: [PATCH] Add the navigation API This imports much of the specification from https://github.com/WICG/navigation-api/blob/91c2e7f959418d71e26e5b9a6723fed2944001d9/spec.bs. It includes some fixes and renamings, as well as a lot of rearranging to flow better, but the feature set is the same. In addition to the new "navigation API" section under "APIs related to navigation and session history", this makes the following changes to integrate the navigation API: * Introduces the NavigationHistoryBehavior enum, as a superset of the "history handling" specification type. This includes an "auto" value to reflect that existing entry points will sometimes default to "replace" instead of "push". The navigation API allows overriding that auto behavior in some circumstances by explicitly supplying "push". (But in some cases, i.e., the initial about:blank or javascript: URLs, this is still not allowed.) * Introduces the concept of "user navigation involvement". This will be helpful for solving issues such as https://github.com/w3c/webappsec-fetch-metadata/issues/71. * Introduces the concept of "history-action user activation", which is a separate type of user activation meant to be used specifically to prevent back button tracking. It has no associated timeout (unlike transient activation), but can be flipped to false (unlike sticky activation). It is used by the navigation API to prevent calling navigateEvent.preventDefault() on two traversals in a row without intervening user activation. It is likely also to be useful for issues such as https://github.com/whatwg/html/issues/7832. * The activation behavior for and elements is made more rigorous and consolidated into one place, so that we can hook into it appropriately to fire navigate events. * Some surgery was needed on "apply the history step". The result is that it now has slightly more parameters, but also several wrapper algorithms which take care of setting up those parameters correctly for the cases of: navigable creation/destruction, push/replace, reload, and traverse. It also returns a value indicating if the application of the history step was canceled, and if so, how; this is used to give informative errors as return values of navigation.traverseTo(). * The "check if unloading is user-canceled" algorithm has become "check if unloading is canceled", as it now handles firing a possibly-cancelable navigate event at the top-level traversable. Other changes scattered throughout are mostly integrating appropriate calls to the navigation API as necessary, especially to fire navigate events. --- source | 5136 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 4638 insertions(+), 498 deletions(-) diff --git a/source b/source index 56bf755e762..3338bb1f8f0 100644 --- a/source +++ b/source @@ -1799,11 +1799,15 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute removedNode and optionally oldParent, are defined as the following:

    +
  1. Let document be removedNode's node document.

  2. +
  3. -

    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

  4. a promise resolved with
  5. a promise rejected with
  6. +
  7. wait for all
  8. upon rejection
  9. upon fulfillment
  10. +
  11. mark as handled
  12. [Global]
  13. [LegacyFactoryFunction]
  14. [LegacyLenientThis]
  15. @@ -3186,6 +3192,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
  16. The create an event algorithm
  17. The fire an event algorithm
  18. The canceled flag
  19. +
  20. The dispatch flag
  21. The dispatch algorithm
  22. EventInit dictionary type
  23. type attribute
  24. @@ -3239,6 +3246,11 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute is value
  25. MutationObserver interface and mutation observers in general
  26. +
  27. AbortController and its + signal
  28. +
  29. AbortSignal
  30. +
  31. aborted
  32. +
  33. signal abort
  34. The get an attribute by name algorithm
  35. @@ -15910,10 +15922,13 @@ data-x="rel-preload">preload; as=font<

    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:

    + within their user interface. Such invocations of the follow + the hyperlink algorithm must set the userInvolvement argument to "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:

      @@ -16895,7 +16910,7 @@ people expect to have work and what is necessary. flag set, then navigate document's node navigable to urlRecord using document, with historyHandling set to "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:

      - -
        -
      1. If element has no href attribute, - then return.

      2. - -
      3. Let hyperlinkSuffix be null.

      4. - -
      5. If event's target is an - img with an ismap attribute specified, - then:

        - -
          - - -
        1. Let x and y be 0.

        2. - -
        3. 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.

        4. - -
        5. If x is negative, set x to 0.

        6. - -
        7. If y is negative, set y to 0.

        8. - -
        9. 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.

        10. -
        -
      6. - -
      7. 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.

      8. - -
      9. Otherwise, follow the hyperlink created by - element given hyperlinkSuffix.

      10. -
      -
      @@ -24370,22 +24341,6 @@ document.body.appendChild(wbr); name of the navigable that will be used. User agents use this name 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.

      - -

      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:

      + +
        +
      1. If element has no href attribute, + then return.

      2. + +
      3. Let hyperlinkSuffix be null.

      4. + +
      5. If element is an a element, and event's target is an img with an ismap attribute specified, then:

        + +
          + + +
        1. Let x and y be 0.

        2. + +
        3. 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.

        4. + +
        5. If x is negative, set x to 0.

        6. + +
        7. If y is negative, set y to 0.

        8. + +
        9. 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.

        10. +
        +
      6. + +
      7. Let userInvolvement be event's user + navigation involvement.

      8. + +
      9. +

        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".

        +
      10. + +
      11. 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.

      12. + +
      13. Otherwise, follow the hyperlink created by + element with hyperlinkSuffix set to + hyperlinkSuffix and userInvolvement set to + userInvolvement.

      14. +
      +

      API for a and area elements

      @@ -24998,7 +25022,10 @@ document.body.appendChild(wbr);

To 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"):

  1. If subject cannot navigate, then return.

  2. @@ -25044,12 +25071,13 @@ document.body.appendChild(wbr);
  3. 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().

@@ -25083,32 +25111,18 @@ document.body.appendChild(wbr);
-

The following allowed to download algorithm takes two booleans - sourceAllowsDownloading and targetAllowsDownloading, and returns a boolean - indicating whether or not downloading is allowed:

- -
    -
  1. If either sourceAllowsDownloading or targetAllowsDownloading are - false, then return false.

    - -
  2. Optionally, the user agent may return false, if it believes doing so would safeguard the - user from a potentially hostile download.

  3. - -
  4. Return true.

  5. -
-

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"):

  1. If subject cannot navigate, then return.

  2. -
  3. Let sourceAllowsDownloading be false if subject's node - document's active sandboxing flag set has the sandboxed downloads - browsing context flag set; otherwise true.

  4. - -
  5. If the result of the allowed to download algorithm with - sourceAllowsDownloading and true is false, then return.

  6. +
  7. If subject's node document's active + sandboxing flag set has the sandboxed downloads browsing context flag set, + then return.

  8. Parse a URL given subject's href attribute, relative to subject's node @@ -25116,16 +25130,44 @@ document.body.appendChild(wbr);

  9. If parsing the URL fails, then return.

    -
  10. Otherwise, let URL be the resulting URL string.

  11. +
  12. Otherwise, let url be the resulting URL string.

  13. -
  14. If hyperlinkSuffix is non-null, then append it to URL.

  15. +
  16. If hyperlinkSuffix is non-null, then append it to url.

  17. + +
  18. +

    If userInvolvement is not "browser UI", + then:

    + +
      +
    1. Assert: subject has a download attribute.

    2. + +
    3. Let navigation be subject's relevant global object's + navigation API.

    4. + +
    5. Let filename be the value of subject's download attribute.

    6. + +
    7. Let continue be the result of firing a download request navigate event at + navigation with destinationURL + set to url, userInvolvement + set to userInvolvement, and filename + set to filename.

    8. + +
    9. If continue is false, then return.

    10. +
    +
  19. Run these steps in parallel:

      +
    1. Optionally, the user agent may abort these steps, if it believes doing so would + safeguard the user from a potentially hostile download.

    2. +
    3. Let request be a new request whose - URL is URL, + URL is url, client is entry settings object, initiator is "download", destination is the empty string, and whose @@ -32755,11 +32797,13 @@ interface HTMLIFrameElement : HTMLElement { null):

        -
      1. Let historyHandling be "push".

        +
      2. Let historyHandling be "auto".

      3. If element's content navigable's active document is not completely loaded, then set - historyHandling to "replace".

      4. + historyHandling to "replace".

      5. 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".

        + data-x="NavigationHistoryBehavior-replace">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:

        - -
          -
        1. If element has no href attribute, - then return.

        2. - -
        3. 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.

        4. - -
        5. Otherwise, follow the hyperlink created by - element.

        6. -
        -

        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.

        + method steps are to submit this from + this, with submitted from 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:

          -
        1. 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.

        2. -
        3. Run this element's input activation behavior, if any, and do nothing +

        4. Run element's input activation behavior, if any, and do nothing otherwise.

        5. -
        6. Run the popover target attribute activation behavior on this element.

        7. +
        8. 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.

      6. -
      7. Submit the form owner from the - element.

        +
      8. Submit the element's form owner + from the element with userInvolvement set to + event's user navigation involvement.

      @@ -50403,7 +50434,7 @@ ldh-str = < as defined in
    4. -
    5. Submit the form owner from the - element.

    6. +
    7. 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:

    1. If element is disabled, then @@ -52371,7 +52404,9 @@ interface HTMLButtonElement : HTMLElement {

      Submit Button

      Submit element's form - owner from element.

      + owner from element with userInvolvement set to event's user navigation involvement.

      Reset Button

      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 form - element from the form element itself otherwise.

      + mechanism must perform the following steps: + +
        +
      1. If the form has more than one field that blocks implicit submission, then + return.

      2. + +
      3. Submit the form element from the + form element itself with userInvolvement set + to "activation".

      4. +
      -

      For the purpose of the previous paragraph, an element is a field that blocks implicit - submission of a form element if it is an input element whose +

      For the purpose of the previous paragraph, an element is a field that blocks implicit + submission of a 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

      Each form element has a firing submission events boolean, initially false.

      -

      When a 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:

      +

      To submit a 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"):

      1. If form cannot navigate, then return.

      2. @@ -58686,8 +58730,8 @@ fur set has its sandboxed forms browsing context flag set, then return.

      3. -

        If the submitted from submit() method flag - is not set, then: +

        If submitted from submit() method is false, + then:

        1. If form's firing submission events is true, then @@ -58827,12 +58871,13 @@ fur

        2. If targetNavigable is null, then return.

        3. -
        4. Let historyHandling be "push".

        5. +
        6. Let historyHandling be "auto".

        7. If form document equals targetNavigable's active document, and form document has not yet completely loaded, then set historyHandling to "replace".

        8. + data-x="NavigationHistoryBehavior-replace">replace
          ".

        9. Select the appropriate row in the table below based on scheme as given by the @@ -58905,10 +58950,11 @@ fur

        10. 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".

          + data-x="navigation-user-involvement">userInvolvement set to userInvolvement, + referrerPolicy set to referrerPolicy, + documentResource set to postResource, and formDataEntryList set to entry + list.

      4. @@ -77109,14 +77155,18 @@ interface VisibilityStateEntry : PerformanceEntryData model -

        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:

        Sticky activation
        @@ -77157,18 +77207,34 @@ interface VisibilityStateEntry : PerformanceEntryactivation consumption.

      + +
      History-action activation
      +
      +

      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.

      Processing model

      @@ -77204,12 +77270,18 @@ interface VisibilityStateEntry : PerformanceEntrytype is one of:

        -
      • 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:

    + +
      +
    1. If W's navigable is null, then + return.

    2. + +
    3. Let top be W's navigable's + top-level traversable.

    4. + +
    5. Let navigables be the inclusive descendant navigables of + top's active document.

    6. + +
    7. Let windows be the list of Window objects constructed by taking + the active window of each item in + navigables.

    8. + +
    9. For each window in windows, set + window's last history-action activation timestamp to window's + window's last activation timestamp.

    10. +
    +

    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:

    -
    Sticky activation-gated APIs

    These APIs require the sticky - activation state to be true, so they are blocked until the very first user - activation.

    +
    Sticky activation-gated APIs
    +

    These APIs require the sticky activation state to be true, so they are + blocked until the very first user activation.

    Transient activation-gated APIs

    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.

    -
    Transient activation-consuming APIs

    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.

    +
    Transient activation-consuming APIs
    +

    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.

    + +
    History-action activation-consuming APIs
    +

    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.

    @@ -78386,8 +78483,16 @@ partial interface Navigator {
    1. -

      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:

      + +
        +
      1. Set document's relevant global object's navigation API's focus changed during ongoing + navigation to true.

      2. + +
      3. Designate entry as the focused area of the document.

        +
    2. @@ -83228,13 +83333,13 @@ dictionary DragEventInit : MouseEventInit {
    3. If topmostPopover is null, then return.

    4. If event is a 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.

    5. If event is a 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 {
        The toolbar BarProp object
        Historically represented the user interface element found immediately above or before the document, as appropriate for the user's media, which typically provides session history traversal controls (back and forward buttons, reload - buttons, etc.).
        + traverse history step">session history traversal controls (back and forward buttons, + reload buttons, etc.).

        The locationbar @@ -88129,7 +88235,7 @@ interface Location { // but see also push"):

        + data-x="NavigationHistoryBehavior-auto">auto"):

        1. Let navigable be location's relevant global object's @@ -88142,7 +88248,8 @@ interface Location { // but see also incumbent global object does not have transient activation, then set - historyHandling to "replace".

        2. + historyHandling to "replace".

        3. Navigate navigable to url using sourceDocument, with exceptionsEnabled set to true and Location { // but see also replace".

        4. + resulting URL record given "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()
        @@ -88835,8 +88943,8 @@ interface History {
        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 set to a serialization + of data. The active history entry's URL will be copied over and used for the new entry's URL.

        (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.

      1. Traverse the history by a delta given document's node - navigable's traversable navigable, - delta, and document.

      2. + navigable's traversable navigable, delta, + and with sourceDocument set to + 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".

      + data-x="NavigationHistoryBehavior-replace">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).

    6. +
    7. Let navigation be history's relevant global object's + navigation API.

    8. + +
    9. 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.

    10. + +
    11. If continue is false, then return.

      +
    12. 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 iframes, 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 NavigationHistoryEntrys.

      + +
      + +

      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;
      + + + +
      + +
      [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:

      + +
        +
      1. If navigation has entries and events disabled, then return + null.

      2. + +
      3. Assert: navigation's current entry index is not −1.

      4. + +
      5. Return navigation's entry + list[navigation's current entry + index].

      6. +
      + +

      A Navigation navigation has entries and events disabled if + the following steps return true:

      + +
        +
      1. Let document be navigation's relevant global object's + associated Document.

      2. + +
      3. If document is not fully active, then return true.

      4. + +
      5. If document's is initial about:blank is true, then + return true.

      6. + +
      7. If document's origin is opaque, then return true.

      8. + +
      9. Return false.

      10. +
      + +

      To get the navigation API entry + index of a session history entry she within a + Navigation navigation:

      + +
        +
      1. Let index be 0.

      2. + +
      3. +

        For each nhe of navigation's entry list:

        + +
          +
        1. If nhe's session history entry is equal to + she, then return index.

        2. + +
        3. Increment index by 1.

        4. +
        +
      4. + +
      5. Return −1.

      6. +
      + +
      + +
      + +

      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"
      +
      Corresponds to calls to navigate where the history handling + behavior ends up as "push", or to + history.pushState().
      + +
      "replace"
      +
      Corresponds to calls to navigate where the history handling + behavior ends up as "replace", or + to history.replaceState().
      + +
      "reload"
      +
      Corresponds to calls to reload.
      + +
      "traverse"
      +
      Corresponds to calls to traverse the history by a delta.
      +
      + +
      + +

      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.

      + + +
      Initializing and updating the entry list
      + +

      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:

      + +
        +
      1. Assert: navigation's entry + list is empty.

      2. + +
      3. Assert: navigation's current entry index is −1.

      4. + +
      5. If navigation has entries and events disabled, then + return.

      6. + +
      7. +

        For each newSHE of newSHEs:

        + +
          +
        1. Let newNHE be a new NavigationHistoryEntry created + in the relevant realm of + navigation.

        2. + +
        3. Set newNHE's session history entry to + newSHE.

        4. + +
        5. Append newNHE to navigation's + entry list.

        6. +
        + +

        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.

        +
      8. + +
      9. Set navigation's current entry + index to the result of getting the navigation API entry index of + initialSHE within navigation.

      10. +
      + +

      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:

      + +
        +
      1. If navigation has entries and events disabled, then + return.

      2. + +
      3. Let newNHEs be a new empty list.

      4. + +
      5. Let oldNHEs be a clone of + navigation's entry list.

      6. + +
      7. +

        For each newSHE of newSHEs:

        + +
          +
        1. Let newNHE be null.

        2. + +
        3. +

          If oldNHEs contains a + NavigationHistoryEntry matchingOldNHE whose session history entry is newSHE, then:

          + +
            +
          1. Set newNHE to matchingOldNHE.

          2. + +
          3. Remove matchingOldNHE from + oldNHEs.

          4. +
          +
        4. + +
        5. +

          Otherwise:

          + +
            +
          1. Set newNHE to a new NavigationHistoryEntry + created in the relevant realm of + navigation.

          2. + +
          3. Set newNHE's session history entry to + newSHE.

          4. +
          +
        6. + +
        7. Append newNHE to + newNHEs.

        8. +
        + +

        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 NavigationHistoryEntrys that remain in + oldNHEs represent session history entries + which have been disposed while the Document was in bfcache.

        +
      8. + +
      9. Set navigation's entry list to newNHEs.

      10. + +
      11. Set navigation's current entry + index to the result of getting the navigation API entry index of + reactivatedSHE within navigation.

      12. + +
      13. +

        Queue a global task on the navigation and traversal task source + given navigation's relevant global object to run the following + steps:

        + +
          +
        1. +

          For each disposedNHE of + oldNHEs:

          + +
            +
          1. Fire an event named dispose at disposedNHE.

          2. +
          +
        2. +
        + +
        +

        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.)

        +
        +
      14. +
      + +

      To update the navigation API entries for a same-document navigation given a + Navigation navigation, a session history entry + destinationSHE, and a NavigationType navigationType:

      + +
        +
      1. If navigation has entries and events disabled, then + return.

      2. + +
      3. Let oldCurrentNHE be the current + entry of navigation.

      4. + +
      5. Let disposedNHEs be a new empty list.

      6. + +
      7. +

        If navigationType is "traverse", + then:

        + +
          +
        1. Set navigation's current entry + index to the result of getting the navigation API entry index of + destinationSHE within navigation.

        2. + +
        3. Assert: navigation's current entry index is not −1.

        4. +
        + +

        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.

        +
      8. + +
      9. +

        Otherwise, if navigationType is "push", then:

        + +
          +
        1. Set navigation's current entry + index to navigation's current + entry index + 1.

        2. + +
        3. Let i be navigation's current entry index.

        4. + +
        5. +

          While i < navigation's entry list's size:

          + +
            +
          1. Append navigation's entry list[i] to + disposedNHEs.

          2. + +
          3. Set i to i + 1.

          4. +
          +
        6. + +
        7. Remove all items in disposedNHEs from + navigation's entry list.

        8. +
        +
      10. + +
      11. +

        Otherwise, if navigationType is "replace", then:

        + +
          +
        1. Append oldCurrentNHE to + disposedNHEs.

        2. +
        +
      12. + +
      13. +

        If navigationType is "push" or + "replace", then:

        + +
          +
        1. Let newNHE be a new NavigationHistoryEntry created + in the relevant realm of + navigation.

        2. + +
        3. Set newNHE's session history entry to + destinationSHE.

        4. + +
        5. Set navigation's entry + list[navigation's current entry + index] to newNHE.

        6. +
        +
      14. + +
      15. +

        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.

        +
      16. + +
      17. +

        Prepare to run script given navigation's relevant settings + object.

        + +

        See the discussion + for other navigation API events to understand why we do this.

        +
      18. + +
      19. Fire an event named currententrychange at navigation using + NavigationCurrentEntryChangeEvent, with its navigationType attribute + initialized to navigationType and its from initialized to + oldCurrentNHE.

      20. + +
      21. +

        For each disposedNHE of + disposedNHEs:

        + +
          +
        1. Fire an event named dispose at disposedNHE.

        2. +
        +
      22. + +
      23. Clean up after running script given navigation's relevant + settings object.

      24. +
      + +

      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.

      + +
      + + +
      The 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:

      + +
        +
      1. If nhe's relevant global object's associated Document is not fully + active, then return the empty string.

      2. + +
      3. Return nhe's session history entry's navigation API key.

      4. +
      + +

      The ID of a + NavigationHistoryEntry nhe is given by the return value of the following + algorithm:

      + +
        +
      1. If nhe's relevant global object's associated Document is not fully + active, then return the empty string.

      2. + +
      3. Return nhe's session history entry's navigation API ID.

      4. +
      + +

      The index of a + NavigationHistoryEntry nhe is given by the return value of the following + algorithm:

      + +
        +
      1. If nhe's relevant global object's associated Document is not fully + active, then return −1.

      2. + +
      3. 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.

      4. +
      + +

      The url getter steps are:

      + +
        +
      1. Let document be this's relevant global object's associated Document.

      2. + +
      3. If document is not fully active, then return the empty + string.

      4. + +
      5. Let she be this's session history + entry.

      6. + +
      7. 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.

      8. + +
      9. Return she's URL, serialized.

      10. +
      + +

      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:

      + +
        +
      1. Let document be this's relevant global object's associated Document.

      2. + +
      3. If document is not fully active, then return false.

      4. + +
      5. Return true if this's session history entry's + document equals document, and false + otherwise.

      6. +
      + +

      The getState() method steps are:

      + +
        +
      1. If this's relevant global object's associated Document is not fully + active, then return undefined.

      2. + +
      3. +

        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.

        +
      4. +
      + +
      + +

      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 +
      + + +
      The history entry list
      + +
      +
      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:

      + +
        +
      1. If this has entries and events disabled, then return the empty + list.

      2. + +
      3. +

        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().

        +
      4. +
      + +

      The currentEntry getter steps are to return the + current entry of this.

      + +

      The updateCurrentEntry(options) + method steps are:

      + +
        +
      1. Let current be the current entry + of this.

      2. + +
      3. If current is null, then throw an "InvalidStateError" + DOMException.

      4. + +
      5. Let serializedState be + StructuredSerializeForStorage(options["state"]), rethrowing any + excpetions.

      6. + +
      7. Set current's session history entry's navigation API state to + serializedState.

      8. + +
      9. Fire an event named currententrychange at this using + NavigationCurrentEntryChangeEvent, with its navigationType attribute + initialized to null and its from + initialized to current.

      10. +
      + +

      The canGoBack getter steps are:

      + +
        +
      1. If this has entries and events disabled, then return + false.

      2. + +
      3. Assert: this's current entry index is not −1.

      4. + +
      5. If this's current entry + index is 0, then return false.

      6. + +
      7. Return true.

      8. +
      + +

      The canGoForward getter steps are:

      + +
        +
      1. If this has entries and events disabled, then return + false.

      2. + +
      3. Assert: this's current entry index is not −1.

      4. + +
      5. If this's current entry + index is equal to this's entry + list's size, then return false.

      6. + +
      7. Return true.

      8. +
      + +
      + + + + +
      +
      { 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:

      + +
        +
      1. 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.

      2. + +
      3. Let document be this's relevant global object's associated Document.

      4. + +
      5. 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.

        + +
      6. Let state be options["state"], if it exists; otherwise, undefined.

      7. + +
      8. +

        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.

        +
      9. + +
      10. If document is not fully active, then return an early error result for an + "InvalidStateError" DOMException.

        + +
      11. If document's unload counter is greater than 0, then return an + early error result for an + "InvalidStateError" DOMException.

      12. + +
      13. Let info be options["info"], if it exists; + otherwise, undefined.

      14. + +
      15. Let apiMethodTracker be the result of maybe setting the upcoming non-traverse API method + tracker for this given info and + serializedState.

      16. + +
      17. +

        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).

        +
      18. + +
      19. +

        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.

        + +
          +
        1. Set this's upcoming non-traverse API method tracker to + null.

        2. + +
        3. Return an early error result for + an "AbortError" DOMException.

        4. +
        +
      20. + +
      21. Return a navigation API method tracker-derived result for + apiMethodTracker.

      22. +
      + +

      The reload(options) method steps are:

      + +
        +
      1. Let document be this's relevant global object's associated Document.

      2. + +
      3. Let serializedState be + StructuredSerializeForStorage(undefined).

      4. + +
      5. +

        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.

        +
      6. + +
      7. +

        Otherwise:

        + +
          +
        1. Let current be the current + entry of this.

        2. + +
        3. If current is not null, then set serializedState to + current's session history entry's navigation API state.

        4. +
        +
      8. + +
      9. If document is not fully active, then return an early error result for an + "InvalidStateError" DOMException.

        + +
      10. If document's unload counter is greater than 0, then return an + early error result for an + "InvalidStateError" DOMException.

      11. + +
      12. Let info be options["info"], if it exists; + otherwise, undefined.

      13. + +
      14. Let apiMethodTracker be the result of maybe setting the upcoming non-traverse API method + tracker for this given info and + serializedState.

      15. + +
      16. Reload document's node navigable with navigationAPIState set to + serializedState.

      17. + +
      18. Return a navigation API method tracker-derived result for + apiMethodTracker.

      19. +
      + +

      The traverseTo(key, options) + method steps are:

      + +
        +
      1. If this's current entry + index is −1, then return an early + error result for an "InvalidStateError" + DOMException.

      2. + +
      3. 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.

      4. + +
      5. Return the result of performing a navigation API traversal given + this, key, and options.

      6. +
      + +

      The back(options) method steps are:

      + +
        +
      1. If this's current entry + index is −1 or 0, then return an early error result for an + "InvalidStateError" DOMException.

      2. + +
      3. Let key be this's entry + list[this's current entry + index − 1]'s session history entry's navigation API key.

      4. + +
      5. Return the result of performing a navigation API traversal given + this, key, and options.

      6. +
      + +

      The forward(options) method steps are:

      + +
        +
      1. 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.

      2. + +
      3. Let key be this's entry + list[this's current entry + index + 1]'s session history entry's navigation API key.

      4. + +
      5. Return the result of performing a navigation API traversal given + this, key, and options.

      6. +
      + +

      To perform a navigation API traversal + given a Navigation navigation, a string key, and a + NavigationOptions options:

      + +
        +
      1. Let document be navigation's relevant global object's + associated Document.

      2. + +
      3. If document is not fully active, then return an early error result for an + "InvalidStateError" DOMException.

        + +
      4. If document's unload counter is greater than 0, then return an + early error result for an + "InvalidStateError" DOMException.

      5. + +
      6. Let current be the current entry + of navigation.

      7. + +
      8. 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 ]».

      9. + +
      10. 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].

      11. + +
      12. Let info be options["info"], if it exists; + otherwise, undefined.

      13. + +
      14. Let apiMethodTracker be the result of adding an upcoming traverse API method tracker for + navigation given key and info.

      15. + +
      16. Let navigable be document's node navigable.

      17. + +
      18. Let traversable be navigable's traversable navigable.

      19. + +
      20. Let sourceSnapshotParams be the result of snapshotting source snapshot + params given document.

      21. + +
      22. +

        Append the following session history + traversal steps to traversable:

        + +
          +
        1. Let navigableSHEs be the result of getting session history + entries given navigable.

        2. + +
        3. +

          Let targetSHE be the session history entry in + navigableSHEs whose navigation API key + is key. If no such entry exists, then:

          + +
            +
          1. 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.

          2. + +
          3. Abort these steps.

          4. +
          + +

          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.

          +
        4. + +
        5. +

          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.

          +
        6. + +
        7. Let result be the result of applying the traverse history step given by targetSHE's step to traversable, given sourceSnapshotParams, + navigable, and "none".

        8. + +
        9. 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.

        10. + +
        11. +

          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.

          +
          +
        12. +
        +
      23. + +
      24. Return a navigation API method tracker-derived result for + apiMethodTracker.

      25. +
      + +

      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 ]».

      + +
      + + +
      Ongoing navigation tracking
      + +
      + +

      During any given navigation (in the broad sense of the + word), the Navigation object needs to keep track of the following:

      + + + + + + + + + + + +
      For all navigations
      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 +
      + + + + + + + +
      For non-"traverse" navigations
      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 +
      + + + + + + + + + +
      For "traverse" navigations
      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:

      + +
        +
      1. Let committedPromise and finishedPromise be new promises created in + navigation's relevant realm.

      2. + +
      3. +

        Mark as handled finishedPromise.

        + +
        +

        The web developer doesn’t necessarily care about finishedPromise being + rejected:

        + +
          +
        • They might only care about committedPromise.

        • + +
        • They could be doing multiple synchronous navigations within the same task, in which + case all but the last will be aborted (causing their finishedPromise to reject). + This could be an application bug, but also could just be an emergent feature of disparate + parts of the application overriding each others' actions.

        • + +
        • They might prefer to listen to other transition-failure signals instead of + finishedPromise, e.g., the navigateerror + event, or the navigation.transition.finished + promise.

        • +
        + +

        As such, we mark it as handled to ensure that it never triggers unhandledrejection events.

        +
        +
      4. + +
      5. +

        Let apiMethodTracker be a new navigation API method tracker with:

        + +
        +
        navigation object
        +
        navigation
        + +
        key
        +
        null
        + +
        info
        +
        info
        + +
        serialized state
        +
        serializedState
        + +
        comitted-to entry
        +
        null
        + +
        comitted promise
        +
        committedPromise
        + +
        finished promise
        +
        finishedPromise
        +
        +
      6. + +
      7. Assert: navigation's upcoming non-traverse API method + tracker is null.

      8. + +
      9. +

        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 Documents, 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.

        +
      10. + +
      11. Return apiMethodTracker.

      12. +
      + +

      To add an upcoming traverse API method tracker given a Navigation + navigation, a string destinationKey, and a JavaScript value + info:

      + +
        +
      1. Let committedPromise and finishedPromise be new promises created in + navigation's relevant realm.

      2. + +
      3. +

        Mark as handled finishedPromise.

        + +

        See the previous + discussion about why this is done.

        +
      4. + +
      5. +

        Let apiMethodTracker be a new navigation API method tracker with:

        + +
        +
        navigation object
        +
        navigation
        + +
        key
        +
        destinationKey
        + +
        info
        +
        info
        + +
        serialized state
        +
        null
        + +
        comitted-to entry
        +
        null
        + +
        comitted promise
        +
        committedPromise
        + +
        finished promise
        +
        finishedPromise
        +
        +
      6. + +
      7. Set navigation's upcoming traverse API method + trackers[key] to apiMethodTracker.

      8. + +
      9. Return apiMethodTracker.

      10. +
      + +

      To promote an upcoming API method tracker to ongoing given a Navigation + navigation and a string-or-null destinationKey:

      + +
        +
      1. Assert: navigation's ongoing API method tracker is + null.

      2. + +
      3. +

        If destinationKey is not null, then:

        + +
          +
        1. Assert: navigation's upcoming non-traverse API method + tracker is null.

        2. + +
        3. +

          If navigation's upcoming traverse API method + trackers[destinationKey] exists, then:

          + +
            +
          1. Set navigation's ongoing API method tracker to + navigation's upcoming traverse API method + trackers[destinationKey].

          2. + +
          3. Remove navigation's upcoming + traverse API method trackers[destinationKey].

          4. +
          +
        4. +
        +
      4. + +
      5. +

        Otherwise:

        + +
          +
        1. Set navigation's ongoing API method tracker to + navigation's upcoming non-traverse API method tracker.

        2. + +
        3. Set navigation's upcoming non-traverse API method tracker to + null.

        4. +
        +
      6. +
      + +

      To clean up a navigation API + method tracker apiMethodTracker:

      + +
        +
      1. Let navigation be apiMethodTracker's navigation object.

      2. + +
      3. If navigation's ongoing API method tracker is + apiMethodTracker, then set navigation's ongoing API method + tracker to null.

      4. + +
      5. +

        Otherwise:

        + +
          +
        1. Let key be apiMethodTracker's key.

        2. + +
        3. Assert: key is not null.

        4. + +
        5. Assert: navigation's upcoming traverse API method + trackers[key] exists.

        6. + +
        7. Remove navigation's upcoming traverse + API method trackers[key].

        8. +
        +
      6. +
      + +

      To notify about the committed-to entry given a navigation API method + tracker apiMethodTracker and a NavigationHistoryEntry + nhe:

      + +
        +
      1. Set apiMethodTracker's committed-to entry to + nhe.

      2. + +
      3. +

        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.

        +
      4. + +
      5. +

        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.

        +
      6. +
      + +

      To resolve the finished promise for a navigation API method tracker + apiMethodTracker:

      + +
        +
      1. +

        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.

        +
      2. + +
      3. Resolve apiMethodTracker's finished promise with its committed-to entry.

      4. + +
      5. Clean up + apiMethodTracker.

      6. +
      + +

      To reject the finished promise for a navigation API method tracker + apiMethodTracker with a JavaScript value exception:

      + +
        +
      1. +

        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.

        +
      2. + +
      3. Reject apiMethodTracker's finished promise with + exception.

      4. + +
      5. Clean up + apiMethodTracker.

      6. +
      + +

      To abort the ongoing navigation given a Navigation + navigation and an optional DOMException error:

      + +
        +
      1. Let event be navigation's ongoing navigate event.

      2. + +
      3. Assert: event is not null.

      4. + +
      5. Set navigation's focus changed during ongoing navigation to + false.

      6. + +
      7. Set navigation's suppress normal scroll restoration during ongoing + navigation to false.

      8. + +
      9. If error was not given, then let error be a new + "AbortError" DOMException created in + navigation's relevant realm.

      10. + +
      11. If event's dispatch flag is set, then set event's + canceled flag to true.

      12. + +
      13. Signal abort on event's abort controller given + error.

      14. + +
      15. Set navigation's ongoing navigate + event to null.

      16. + +
      17. +

        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.

        +
      18. + +
      19. If navigation's ongoing API method tracker is non-null, then + reject the finished promise for apiMethodTracker with + error.

      20. + +
      21. +

        If navigation's transition is + not null, then:

        + +
          +
        1. Reject navigation's transition's finished promise with + error.

        2. + +
        3. Set navigation's transition to null.

        4. +
        +
      22. +
      + +

      To inform the navigation API about aborting navigation in a navigable + navigable:

      + +
        +
      1. 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.

      2. + +
      3. Let navigation be navigable's active + window's navigation API.

      4. + +
      5. If navigation's ongoing navigate + event is null, then return.

      6. + +
      7. Abort the ongoing navigation given navigation.

      8. +
      + +

      To inform the navigation API about child navigable destruction given a + navigable navigable:

      + +
        +
      1. Inform the navigation API about aborting navigation in + navigable.

      2. + +
      3. Let navigation be navigable's active + window's navigation API.

      4. + +
      5. Let traversalAPIMethodTrackers to be clone of + navigation's upcoming traverse API method trackers.

      6. + +
      7. For each apiMethodTracker of + traversalAPIMethodTrackers: reject the finished promise for + apiMethodTracker with a new "AbortError" + DOMException created in navigation's relevant realm.

      8. +
      + +
      + +

      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.

      + +
      + + + +
      The navigate event
      + +

      A 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.

      + +
      The 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:

      + +
        +
      1. Perform shared checks given + this.

      2. + +
      3. If this's canIntercept + attribute was initialized to false, then throw a "SecurityError" + DOMException.

      4. + +
      5. If this's dispatch flag is unset, then throw an + "InvalidStateError" DOMException.

      6. + +
      7. Assert: this's interception state is either "none" or "intercepted".

      8. + +
      9. Set this's interception state to "intercepted".

      10. + +
      11. If options["handler"] exists, then append it to this's + navigation handler + list.

      12. + +
      13. +

        If options["focusReset"] exists, then:

        + +
          +
        1. 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.

        2. + +
        3. Set this's focus reset + behavior to options["focusReset"].

        4. +
        +
      14. + +
      15. +

        If options["scroll"] + exists, then:

        + +
          +
        1. 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.

        2. + +
        3. Set this's scroll + behavior to options["scroll"].

        4. +
        +
      16. +
      + +

      The scroll() method steps are:

      + +
        +
      1. Perform shared checks given + this.

      2. + +
      3. If this's interception state is not "committed", then throw an "InvalidStateError" + DOMException.

      4. + +
      5. Process scroll behavior given this.

      6. +
      + +

      To perform shared checks for a + NavigateEvent event:

      + +
        +
      1. If event's relevant global object's associated Document is not fully + active, then throw an "InvalidStateError" + DOMException.

      2. + +
      3. If event's isTrusted attribute was + initialized to false, then throw a "SecurityError" + DOMException.

      4. + +
      5. If event's canceled flag is set, then throw an + "InvalidStateError" DOMException.

      6. +
      + +
      + +
      The 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:

      + +
        +
      1. If this's entry is + null, then return the empty string.

      2. + +
      3. Return this's entry's key.

      4. +
      + +

      The id getter steps are:

      + +
        +
      1. If this's entry is + null, then return the empty string.

      2. + +
      3. Return this's entry's ID.

      4. +
      + +

      The index getter steps are:

      + +
        +
      1. If this's entry is + null, then return −1.

      2. + +
      3. Return this's entry's index.

      4. +
      + +

      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"):

      + +
        +
      1. Let event be the result of creating an event given + NavigateEvent, in navigation's relevant realm.

      2. + +
      3. Set event's classic history API state to + null.

      4. + +
      5. Let destination be a new NavigationDestination + created in navigation's relevant + realm.

      6. + +
      7. Set destination's URL + to destinationSHE's URL.

      8. + +
      9. Let destinationNHE be the NavigationHistoryEntry in + navigation's entry list whose session history entry is destinationSHE, or null if no such + NavigationHistoryEntry exists.

      10. + +
      11. +

        If destinationNHE is non-null, then:

        + +
          +
        1. Set destination's entry to + destinationNHE.

        2. + +
        3. Set destination's state to destinationSHE's navigation API state.

        4. +
        +
      12. + +
      13. +

        Otherwise,

        + +
          +
        1. Set destination's entry to null.

        2. + +
        3. Set destination's state to + StructuredSerializeForStorage(null).

        4. +
        +
      14. + +
      15. 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.

      16. + +
      17. Return the result of performing the inner navigate event firing algorithm given + navigation, "traverse", + event, destination, userInvolvement, null, and null.

      18. +
      + +

      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):

      + +
        +
      1. Let event be the result of creating an event given + NavigateEvent, in navigation's relevant realm.

      2. + +
      3. Set event's classic history API state to + classicHistoryAPIState.

      4. + +
      5. Let destination be a new NavigationDestination + created in navigation's relevant + realm.

      6. + +
      7. Set destination's URL + to destinationURL.

      8. + +
      9. Set destination's entry to null.

      10. + +
      11. Set destination's state to + navigationAPIState.

      12. + +
      13. Set destination's is + same document to isSameDocument.

      14. + +
      15. Return the result of performing the inner navigate event firing algorithm given + navigation, navigationType, event, destination, + userInvolvement, formDataEntryList, and null.

      16. +
      + +

      To fire a download request navigate event at a + Navigation navigation given a URL destinationURL, a user + navigation involvement userInvolvement, and a string + filename:

      + +
        +
      1. Let event be the result of creating an event given + NavigateEvent, in navigation's relevant realm.

      2. + +
      3. Set event's classic history API state to + null.

      4. + +
      5. Let destination be a new NavigationDestination + created in navigation's relevant + realm.

      6. + +
      7. Set destination's URL + to destinationURL.

      8. + +
      9. Set destination's entry to null.

      10. + +
      11. Set destination's state to + StructuredSerializeForStorage(null).

      12. + +
      13. Set destination's is + same document to false.

      14. + +
      15. Return the result of performing the inner navigate event firing algorithm given + navigation, "push", event, + destination, userInvolvement, null, and filename.

      16. +
      + +

      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:

      + +
        +
      1. +

        If navigation has entries and events disabled, then:

        + +
          +
        1. Assert: navigation's ongoing API method tracker is + null.

        2. + +
        3. Assert: navigation's upcoming non-traverse API method + tracker is null.

        4. + +
        5. Assert: navigation's upcoming traverse API method + trackers is empty.

        6. + +
        7. Return true.

        8. +
        + +

        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.

        +
      2. + +
      3. Let destinationKey be null.

      4. + +
      5. If destination's entry is non-null, then set + destinationKey to destination's entry's key.

      6. + +
      7. Assert: destinationKey is not the empty string.

      8. + +
      9. Promote an upcoming API method tracker to ongoing given + navigation and destinationKey.

      10. + +
      11. Let apiMethodTracker be navigation's ongoing API method + tracker.

      12. + +
      13. Let navigable be navigation's relevant global object's + navigable.

      14. + +
      15. Let document be navigation's relevant global object's + associated Document.

      16. + +
      17. 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.

      18. + + + +
      19. +

        If either:

        + +
          +
        • navigationType is not "traverse"; or

        • + +
        • traverseCanBeCanceled is true

        • +
        + +

        the initialize event's cancelable to + true. Otherwise, initialize it to false.

        +
      20. + +
      21. Initialize event's type to "navigate".

      22. + +
      23. Initialize event's navigationType to + navigationType.

      24. + +
      25. Initialize event's destination to destination.

      26. + +
      27. Initialize event's downloadRequest to + downloadRequestFilename.

      28. + +
      29. +

        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.

        +
      30. + +
      31. Set event's abort + controller to a new AbortController created in + navigation's relevant realm.

      32. + +
      33. Initialize event's signal to + event's abort + controller's signal.

      34. + +
      35. Let currentURL be document's URL.

      36. + +
      37. +

        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.

        +
      38. + +
      39. If userInvolvement is not "none", then + initialize event's userInitiated + to true. Otherwise, initialize it to false.

      40. + +
      41. 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.

      42. + +
      43. Assert: navigation's ongoing navigate event is null.

      44. + +
      45. Set navigation's ongoing navigate + event to event.

      46. + +
      47. Set navigation's focus changed during ongoing navigation to + false.

      48. + +
      49. Set navigation's suppress normal scroll restoration during ongoing + navigation to false.

      50. + +
      51. Let dispatchResult be the result of dispatching event at + navigation.

      52. + +
      53. +

        If dispatchResult is false:

        + +
          +
        1. If navigationType is "traverse", then consume history-action user + activation.

        2. + +
        3. If event's abort + controller's signal is not aborted, then abort the ongoing navigation + given navigation.

        4. + +
        5. Return false.

        6. +
        +
      54. + +
      55. Let endResultIsSameDocument be true if event's interception state is not "none" or event's destination's is same document is true.

      56. + +
      57. +

        Prepare to run script given navigation's relevant settings + object.

        + +
        +

        This is done to avoid the JavaScript execution context stack becoming empty + right after any currententrychange event + handlers run as a result of the URL and history update steps that could soon + happen. If the stack were to become empty at that time, then it would immediately perform + a microtask checkpoint, causing various promise fulfillment handlers to run interleaved + with the event handlers and before any handlers passed to navigateEvent.intercept(). This is undesirable + since it means promise handler ordering vs. currententrychange event handler ordering vs. intercept() handler ordering would be dependent on + whether the navigation is happening with an empty JavaScript execution context + stack (e.g., because the navigation was user-initiated) or with a nonempty one (e.g., + because the navigation was caused by a JavaScript API call).

        + +

        By inserting an otherwise-unnecessary JavaScript execution context onto the + stack in this step, we essentially suppress the perform a microtask checkpoint + algorithm until later, thus ensuring that the sequence is always: currententrychange event handlers, then intercept() handlers, then promise handlers.

        +
        +
      58. + +
      59. +

        If event's interception + state is not "none":

        + +
          +
        1. Set event's interception state to "committed".

        2. + +
        3. Let fromNHE be the current + entry of navigation.

        4. + +
        5. Assert: fromNHE is not null.

        6. + +
        7. 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.

        8. + +
        9. +

          Mark as handled navigation's transition's finished promise.

          + +

          See the discussion + about other finished promises to understand why this is done.

          +
        10. + +
        11. +

          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.

          +
        12. + +
        13. +

          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.

          +
          +
        14. +
        +
      60. + +
      61. +

        If endResultIsSameDocument is true:

        + +
          +
        1. Let promisesList be an empty list.

        2. + +
        3. +

          For each handler of event's navigation handler list:

          + +
            +
          1. Append the result of invoking handler with an empty + arguments list to promisesList.

          2. +
          +
        4. + +
        5. +

          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.) +

        6. + +
        7. +

          Wait for all of promisesList, with the following success steps:

          + +
            +
          1. If event's relevant global object is not fully + active, then abort these steps.

          2. + +
          3. If event's abort + controller's signal is aborted, then abort these steps.

          4. + +
          5. Assert: event equals navigation's ongoing + navigate event.

          6. + +
          7. Set navigation's ongoing navigate event to null.

          8. + +
          9. Finish event given + true.

          10. + +
          11. Fire an event named navigatesuccess at navigation.

          12. + +
          13. If navigation's transition is not null, then resolve + navigation's transition's + finished promise with + undefined.

          14. + +
          15. Set navigation's transition to null.

          16. + +
          17. If apiMethodTracker is non-null, then resolve the finished + promise for apiMethodTracker.

          18. +
          + +

          and the following failure steps given reason rejectionReason:

          + +
            +
          1. If event's relevant global object is not fully + active, then abort these steps.

          2. + +
          3. If event's abort + controller's signal is aborted, then abort these steps.

          4. + +
          5. Assert: event equals navigation's ongoing + navigate event.

          6. + +
          7. Set navigation's ongoing navigate event to null.

          8. + +
          9. Finish event given + false.

          10. + +
          11. 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.

            + +
          12. If navigation's transition is not null, then reject + navigation's transition's + finished promise with + rejectionReason.

          13. + +
          14. Set navigation's transition to null.

          15. + +
          16. If apiMethodTracker is non-null, then reject the finished + promise for apiMethodTracker with rejectionReason.

          17. +
          +
        8. +
        +
      62. + +
      63. Otherwise, if apiMethodTracker is non-null, then clean up + apiMethodTracker.

      64. + +
      65. +

        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.

        +
      66. + +
      67. If event's interception + state is "none", then return true.

      68. + +
      69. Return false.

      70. +
      + + + + +

      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:

      + +
        +
      1. Assert: event's interception state is not "intercepted" or "finished".

      2. + +
      3. If event's interception + state is "none", then return.

      4. + +
      5. Potentially reset the focus given event.

      6. + +
      7. If didFulfill is true, then potentially process scroll behavior + given event.

      8. + +
      9. Set event's interception state to "finished".

      10. +
      + +

      To potentially reset the focus given a NavigateEvent + event:

      + +
        +
      1. Assert: event's interception state is "committed" or "scrolled".

      2. + +
      3. Let navigation be event's relevant global object's + navigation API.

      4. + +
      5. Let focusChanged be navigation's focus changed during ongoing + navigation.

      6. + +
      7. Set navigation's focus changed during ongoing navigation to + false.

      8. + +
      9. If focusChanged is true, then return.

      10. + +
      11. +

        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.

        +
      12. + +
      13. Let document be event's relevant global object's associated Document.

      14. + +
      15. Let focusTarget be the autofocus delegate for + document.

      16. + +
      17. If focusTarget is null, then set focusTarget to + document's body element.

      18. + +
      19. If focusTarget is null, then set focusTarget to + document's document element.

      20. + +
      21. Run the focusing steps for focusTarget, with document's + viewport as the fallback target.

      22. + +
      23. Move the sequential focus navigation starting point to + focusTarget.

      24. +
      + +

      To potentially process scroll behavior given a NavigateEvent + event:

      + +
        +
      1. Assert: event's interception state is "committed" or "scrolled".

      2. + +
      3. If event's interception + state is "scrolled", then return.

      4. + +
      5. +

        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.

        +
      6. + +
      7. Process scroll behavior given event.

        +
      + +

      To process scroll behavior given a NavigateEvent event:

      + +
        +
      1. Assert: event's interception state is "committed".

      2. + +
      3. Set event's interception state to "scrolled".

      4. + +
      5. 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.

      6. + +
      7. +

        Otherwise:

        + +
          +
        1. Let document be event's relevant global object's + associated Document.

        2. + +
        3. If document's indicated part is null, then scroll to the + beginning of the document given document.

        4. + +
        5. Otherwise, scroll to the fragment given document.

        6. +
        +
      8. +
      + +
      + +

      The NavigateEvent interface has its own + dedicated section, due to its complexity.

      + + +
      The 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.

      + +
      +
      The PopStateEvent interface
      @@ -89415,17 +92914,17 @@ interface BeforeUnloadEvent : Event {

      There 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.

      @@ -89516,8 +93015,8 @@ interface BeforeUnloadEvent : Event { data-x="nav-active-history-entry">active session history entry to temporarily step ahead of the current session history entry.

    13. -
    14. 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.

    15. @@ -89894,7 +93393,8 @@ interface BeforeUnloadEvent : Event { parentDocState's nested histories.

      -
    16. Apply pending history changes to traversable.

    17. +
    18. Update for navigable creation/destruction given + traversable.

@@ -90102,6 +93602,9 @@ interface BeforeUnloadEvent : Event {
  • Set container's content navigable to null.

  • +
  • Inform the navigation API about child navigable destruction given + navigable.

  • +
  • Destroy navigable's active document.

  • @@ -90122,7 +93625,8 @@ interface BeforeUnloadEvent : Event { history traversal steps to traversable:

      -
    1. Apply pending history changes to traversable.

    2. +
    3. Update for navigable creation/destruction given + traversable.

    @@ -90169,8 +93673,8 @@ interface BeforeUnloadEvent : Event {
  • 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.

    If the user agent has been configured such that in this instance it will choose currentNavigable
    @@ -90563,7 +94067,8 @@ interface BeforeUnloadEvent : Event { same browsing context, such that the mapping is then 1-to-2. This occurs when a browsing context is navigated from the initial about:blank Document to - another, which will be done with replacement.

    + another, which will be done with replacement.

    Creating browsing contexts
    @@ -91205,8 +94710,19 @@ interface BeforeUnloadEvent : Event {
  • 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:

    1. Let traversable be navigable's

    2. Assert: this step is not reached.

    +

    To get session history + entries for the navigation API of a navigable navigable given an + integer targetStep:

    + +
      +
    1. Let rawEntries be the result of getting session history entries + for navigable.

    2. + +
    3. Let entriesForNavigationAPI be a new empty list.

    4. + +
    5. +

      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.

      +
    6. + +
    7. Append rawEntries[startingIndex] + to entriesForNavigationAPI.

    8. + +
    9. Let startingOrigin be rawEntries[startingIndex]'s document state's origin.

    10. + +
    11. Let i be startingIndex − 1.

    12. + +
    13. +

      While i > 0:

      + +
        +
      1. If rawEntries[i]'s document + state's origin is not same + origin with startingOrigin, then break.

      2. + +
      3. Prepend rawEntries[i] to + entriesForNavigationAPI.

      4. + +
      5. Set i to i − 1.

      6. +
      +
    14. + +
    15. Set i to startingIndex + 1.

    16. + +
    17. +

      While i < rawEntries's size:

      + +
        +
      1. If rawEntries[i]'s document + state's origin is not same + origin with startingOrigin, then break.

      2. + +
      3. Append rawEntries[i] to + entriesForNavigationAPI.

      4. + +
      5. Set i to i + 1.

      6. +
      +
    18. + +
    19. Return entriesForNavigationAPI.

    20. +
    +

    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):

    - -
      -
    1. Let targetStep be traversable's current session history step.

    2. - -
    3. Apply the history step targetStep to traversable with - checkForUserCancelation set to - checkForUserCancelation.

    4. -
    - @@ -91861,7 +95427,7 @@ location.href = '#foo'; data-x="dom-open">window.open() and location.assign() methods can all cause navigation.

    -
    +

    Although in this standard the word "navigation" refers specifically to the navigate algorithm, this doesn't always line up with web developer or user perceptions. For example:

    @@ -92036,25 +95602,90 @@ location.href = '#foo';

    After Document creation, the relevant traversable navigable's session history gets updated. A history handling - behavior is used to track the desired type of session history update throughout the - navigation process. It is one of the following:

    + data-x="tn-session-history-entries">session history gets updated. The + NavigationHistoryBehavior enumeration is used to indicate the desired type of session + history update to the navigate algorithm. It is one of the following:

    -
    "push"
    A regular - navigation which adds a new session history entry, and will clear the forward - session history.
    +
    "push"
    +
    A regular navigation which adds a new session history entry, and will + clear the forward session history.
    -
    "replace"
    A navigation that will - replace the active session history entry.
    +
    "replace"
    +
    A navigation that will replace the active session + history entry.
    + +
    "auto"
    +
    The default value, which will be converted very early in the navigate algorithm + into "push" or "replace". Usually it becomes "push", but under certain circumstances it becomes "replace" instead.
    -
    Beginning navigation
    +

    A history handling behavior is a NavigationHistoryBehavior that is + either "push" or "replace", i.e., that has been resolved away from + any initial "auto" value.

    -

    Each navigable has an ongoing navigation, - which is a navigation ID, "traversal", or null, initially - null. It is used to track navigation aborting and to prevent any navigations from taking place - during traversal.

    +

    The navigation must be a replace, given a URL url and a + Document document, if either of the following conditions hold:

    + +
      +
    • url's scheme is "javascript"; or

    • + +
    • document's is initial about:blank is true

    • +
    + +
    +

    Other cases that often, but not always, force a "replace" navigation are:

    + +
      +
    • If the Document is not completely loaded; or,

    • + +
    • If the target URL equals the Document's URL.

    • +
    +
    + +
    + +

    Various parts of the platform track whether a user is involved in a navigation. A user + navigation involvement is one of the following:

    + +
    +
    "browser UI"
    +
    The navigation was initiated by the user via browser UI mechanisms.
    + +
    "activation"
    +
    The navigation was initiated by the user via the activation behavior of an + element.
    + +
    "none"
    +
    The navigation was not initiated by the user.
    +
    + +

    For convenience at certain call sites, the user navigation + involvement for an Event event is defined as follows:

    + +
      +
    1. Assert: this algorithm is being called as part of an activation + behavior definition.

    2. + +
    3. Assert: event's type is + "click".

    4. + +
    5. If event's isTrusted is initialized + to true, then return "activation".

    6. + +
    7. Return "none".

    8. +
    + + +
    Beginning navigation
  • Otherwise, set historyHandling to "push".

  • + +
  • If the navigation must be a replace given url and + navigable's active document, then set + historyHandling to "replace".

  • +
  • -

    Set navigable's ongoing navigation to navigationId.

    +

    Set the ongoing navigation for navigable to + navigationId.

    This will have the effect of aborting other ongoing navigations of navigable, since at certain points during navigation changes to the ongoing @@ -92240,12 +95883,66 @@ location.href = '#foo';

  • +
  • +

    If all of the following are true:

    + +
      +
    • userInvolvement is not "browser + UI";

    • + +
    • navigable's active document's origin is same origin-domain with + sourceDocument's origin;

    • + +
    • navigable's active document's is + initial about:blank is false; and

    • + +
    • url's scheme is a fetch + scheme

    • +
    + +

    then:

    + +
      +
    1. Let navigation be navigable's active + window's navigation API.

    2. + +
    3. Let entryListForFiring be formDataEntryList if + documentResource is a POST resource; otherwise, null.

    4. + +
    5. Let navigationAPIStateForFiring be navigationAPIState if + navigationAPIState is not null; otherwise, + StructuredSerializeForStorage(undefined).

    6. + +
    7. Let continue be the result of firing a push/replace/reload navigate + event at navigation with navigationType set to historyHandling, + isSameDocument set to false, userInvolvement set to + userInvolvement, formDataEntryList set to + entryListForFiring, destinationURL + set to url, and navigationAPIState set to + navigationAPIStateForFiring.

    8. + +
    9. If continue is false, then return.

      +
    + +

    It is possible for navigations with userInvolvement of "browser UI" or initiated by a cross origin-domain sourceDocument to fire navigate events, if they go through the earlier navigate to a fragment path.

    +
  • +
  • In parallel, run these steps:

    1. Let unloadPromptCanceled be the result of checking if unloading is - user-canceled for navigable's active + canceled for navigable's active document's inclusive descendant navigables.

    2. @@ -92482,8 +96179,8 @@ location.href = '#foo';
    3. Let entryToReplace be navigable's active session history entry if - historyHandling is "replace", otherwise - null.

    4. + historyHandling is "replace", + otherwise null.

    5. Let traversable be navigable's traversable navigable.

    6. @@ -92518,12 +96215,19 @@ location.href = '#foo';
    7. Set historyEntry's step to entryToReplace's step.

    8. +
    9. If historyEntry's document state's + origin is same origin with + entryToReplace's document state's origin, then set historyEntry's navigation API key to entryToReplace's navigation API key.

    10. +
    11. Set targetStep to traversable's current session history step.

  • -
  • Apply the history step targetStep to +

  • Apply the push/replace history step targetStep to traversable.

  • @@ -92541,9 +96245,9 @@ location.href = '#foo';
    1. Assert: historyHandling is "replace".

    2. + data-x="NavigationHistoryBehavior-replace">replace".

      -
    3. Set targetNavigable's ongoing navigation to null.

    4. +
    5. Set the ongoing navigation for targetNavigable to null.

    6. If initiatorOrigin is not same origin-domain with targetNavigable's active document's

      To navigate to a fragment given a navigable navigable, a URL url, a history handling behavior - historyHandling, and a navigation ID navigationId:

      + historyHandling, a user navigation involvement userInvolvement, + a serialized state-or-null navigationAPIState, and a navigation + ID navigationId:

        +
      1. Let navigation be navigable's active + window's navigation API.

      2. + +
      3. Let destinationNavigationAPIState be navigable's active session history entry's navigation API state.

      4. + +
      5. If navigationAPIState is not null, then set + destinationNavigationAPIState to navigationAPIState.

      6. + +
      7. Let continue be the result of firing a push/replace/reload navigate event at + navigation with navigationType set to + historyHandling, isSameDocument set + to true, userInvolvement set to + userInvolvement, and destinationURL + set to url, and navigationAPIState set to + destinationNavigationAPIState.

      8. + +
      9. If continue is false, then return.

        +
      10. Let historyEntry be a new session history entry, with

        @@ -92798,16 +96526,33 @@ location.href = '#foo';
        navigable's active session history entry's document state
        +
        navigation API state
        +
        destinationNavigationAPIState
        +
        scroll restoration mode
        navigable's active session history entry's scroll restoration mode
        + +
        +

        For navigations peformed with navigation.navigate(), the value provided by the state option is used for the new navigation API state. (This will set it to the + serialization of undefined, if no value is provided for that option.) For other fragment + navigations, including user-initiated ones, the navigation API state is carried over from the previous + entry.

        + +

        The classic history API state is never + carried over.

        +
      11. Let entryToReplace be navigable's active session history entry if - historyHandling is "replace", otherwise - null.

      12. + historyHandling is "replace", + otherwise null.

      13. Let history be navigable's active document's history object.

      14. @@ -92819,7 +96564,8 @@ location.href = '#foo'; data-x="concept-history-length">length.

      15. -

        If historyHandling is "push", then:

        +

        If historyHandling is "push", + then:

        1. Set history's state to @@ -92847,6 +96593,9 @@ location.href = '#foo'; untouched, and no events are fired.

        2. +
        3. Update the navigation API entries for a same-document navigation given + navigation, historyEntry, and historyHandling.

        4. +
        5. Scroll to the fragment given navigable's active document.

          @@ -92935,10 +96684,12 @@ location.href = '#foo';
        6. -

          Apply the history step targetStep to traversable.

          +

          Apply the push/replace history step targetStep to + traversable.

          -

          This is done even for "replace" navigations, - as it resolves race conditions across multiple synchronous navigations.

          +

          This is done even for "replace" navigations, as it resolves race + conditions across multiple synchronous navigations.

        @@ -93142,20 +96893,126 @@ location.href = '#foo';
      16. Return true.

      -

      To check if unloading is user-canceled for list of navigables navigables:

      +

      To check if unloading is canceled for a list of navigables navigablesThatNeedBeforeUnload, given an optional + traversable navigable traversable, an optional integer + targetStep, and an optional user navigation involvement-or-null + userInvolvementForNavigateEvent, run these steps. They return "canceled-by-beforeunload", "canceled-by-navigate", or + "continue".

        -
      1. Let documents be the active document of - each item in navigables.

      2. +
      3. Let documentsToFireBeforeunload be the active + document of each item in + navigablesThatNeedBeforeUnload.

      4. Let unloadPromptShown be false.

      5. -
      6. Let unloadPromptCanceled be false.

      7. +
      8. Let finalStatus be "continue".

      9. + +
      10. +

        If traversable was given, then:

        + +
          +
        1. Assert: targetStep and + userInvolvementForNavigateEvent were given.

        2. + +
        3. Let targetEntry be the result of getting the target history + entry given traversable and targetStep.

        4. + +
        5. +

          If targetEntry is not traversable's current session history entry, and + targetEntry's document state's origin is the same as + traversable's current session history + entry's document state's origin, then:

          + +
          +

          In this case, we're going to fire the navigate event + for traversable here. Because under some circumstances it might be + canceled, we need to do this separately from other traversal navigate events, which happen later.

          + +

          Additionally, because we want beforeunload events + to fire before navigate events, this means we need to + fire beforeunload for traversable here + (if applicable), instead of doing it as part of the below loop over + documentsToFireBeforeunload.

          +
          + +
            +
          1. Assert: userInvolvementForNavigateEvent is not null.

          2. + +
          3. Let eventsFired be false.

          4. + +
          5. Let needsBeforeunload be true if navigablesThatNeedBeforeUnload + contains traversable; otherwise + false.

          6. + +
          7. If needsBeforeunload is true, then remove + traversable's active document from + documentsToFireBeforeunload.

          8. + +
          9. +

            Queue a global task on the navigation and traversal task source + given traversable's active window to perform the + following steps:

            + +
              +
            1. +

              If needsBeforeunload is true, then:

              + +
                +
              1. Let (unloadPromptShownForThisDocument, + unloadPromptCanceledByThisDocument) be the result of running the steps + to fire beforeunload given + traversable's active document and + false.

              2. + +
              3. If unloadPromptShownForThisDocument is true, then set + unloadPromptShown to true.

              4. + +
              5. If unloadPromptCanceledByThisDocument is true, then set + finalStatus to "canceled-by-beforeunload".

              6. +
              +
            2. + +
            3. If finalStatus is "canceled-by-beforeunload", then + abort these steps.

            4. + +
            5. Let navigation be traversable's active window's navigation + API.

            6. + +
            7. Let navigateEventResult be the result of firing a traverse navigate + event at a Navigation navigation given + targetEntry and userInvolvementForNavigateEvent.

            8. + +
            9. If navigateEventResult is false, then set finalStatus to + "canceled-by-navigate".

            10. + +
            11. Set eventsFired to true.

            12. +
            +
          10. + +
          11. Wait until eventsFired is true.

          12. + +
          13. If finalStatus is not "continue", then return + finalStatus.

          14. +
          +
        6. +
        +
      11. Let totalTasks be the size of - documents.

      12. + documentsThatNeedBeforeunload.

      13. Let completedTasks be 0.

      14. @@ -93165,85 +97022,163 @@ location.href = '#foo'; document's relevant global object to run the steps:

          -
        1. Increase the document's unload counter by 1.

        2. +
        3. Let (unloadPromptShownForThisDocument, + unloadPromptCanceledByThisDocument) be the result of running the steps to fire + beforeunload given document and + unloadPromptShown.

        4. -
        5. Increase the event loop's termination nesting level by - 1.

        6. +
        7. If unloadPromptShownForThisDocument is true, then set + unloadPromptShown to true.

        8. -
        9. Let event be the result of creating an event using - BeforeUnloadEvent.

        10. +
        11. If unloadPromptCanceledByThisDocument is true, then set + finalStatus to "canceled-by-beforeunload".

        12. -
        13. Initialize event's type attribute to - beforeunload and its cancelable attribute true.

        14. +
        15. Increment completedTasks.

        16. +
        + -
      15. Dispatch event at - document's relevant global object.

      16. +
      17. Wait for completedTasks to be totalTasks.

      18. -
      19. Decrease the event loop's termination nesting level by - 1.

      20. +
      21. Return finalStatus.

      22. +
      -
    7. -

      If all of the following are true:

      +

      The steps to fire beforeunload given a + Document document and a boolean unloadPromptShown are:

      -
      • unloadPromptShown is false;

      • +
          +
        1. Let unloadPromptCanceled be false.

        2. -
        3. document's active sandboxing flag set does not have its - sandboxed modals flag set;

        4. +
        5. Increase the document's unload counter by 1.

        6. -
        7. document's relevant global object has sticky - activation;

        8. +
        9. Increase document's relevant agent's event loop's termination nesting level by + 1.

        10. -
        11. event's canceled flag is set, or the returnValue attribute of event - is not the empty string; and

        12. +
        13. Let eventFiringResult be the result of firing + an event named beforeunload at + document's relevant global object, using BeforeUnloadEvent, + with the cancelable attribute initialized to + true.

        14. -
        15. showing an unload prompt is unlikely to be annoying, deceptive, or pointless

        16. -
      +
    8. Decrease document's relevant agent's event loop's termination nesting level by + 1.

    9. -

      then:

      +
    10. +

      If all of the following are true:

      -
        -
      1. Set unloadPromptShown to true.

      2. +
          +
        • unloadPromptShown is false;

        • -
        • Invoke WebDriver BiDi user prompt opened with document's - relevant global object, "beforeunload", and "".

        • +
        • document's active sandboxing flag set does not have its + sandboxed modals flag set;

        • -
        • -

          Ask the user to confirm that they wish to unload the document, and pause - while waiting for the user's response.

          +
        • document's relevant global object has sticky + activation;

        • -

          The message shown to the user is not customizable, but instead determined - by the user agent. In particular, the actual value of the returnValue attribute is ignored.

          - +
        • eventFiringResult is false, or the returnValue attribute of event is + not the empty string; and

        • -
        • If the user did not confirm the page navigation, set unloadPromptCanceled - to true.

        • +
        • showing an unload prompt is unlikely to be annoying, deceptive, or pointless

        • +
        -
      3. Invoke WebDriver BiDi user prompt closed with document's - relevant global object and true if unloadPromptCanceled is false or - false otherwise.

      4. -
      +

      then:

      + +
        +
      1. Set unloadPromptShown to true.

      2. + +
      3. Invoke WebDriver BiDi user prompt opened with document's + relevant global object, "beforeunload", and "".

      4. + +
      5. +

        Ask the user to confirm that they wish to unload the document, and pause while + waiting for the user's response.

        + +

        The message shown to the user is not customizable, but instead determined by + the user agent. In particular, the actual value of the returnValue attribute is ignored.

      6. -
      7. Decrease the document's unload counter by 1.

      8. +
      9. If the user did not confirm the page navigation, set unloadPromptCanceled to + true.

      10. -
      11. Increment completedTasks.

      12. +
      13. Invoke WebDriver BiDi user prompt closed with document's + relevant global object and true if unloadPromptCanceled is false or + false otherwise.

    11. -
    12. Wait for completedTasks to be totalTasks.

    13. +
    14. Decrease document's unload counter by 1.

    15. + +
    16. Return (unloadPromptShown, unloadPromptCanceled).

    17. +
    + + +
    Aborting navigation
    + +

    Each navigable has an ongoing navigation, + which is a navigation ID, "traversal", or null, initially + null. It is used to track navigation aborting and to prevent any navigations from taking place + during traversal.

    -
  • Return unloadPromptCanceled.

  • +

    To set the ongoing navigation for a navigable navigable to + newValue:

    + +
      +
    1. If navigable's ongoing navigation is equal to newValue, + then return.

    2. + +
    3. Inform the navigation API about aborting navigation given + navigable.

    4. + +
    5. Set navigable's ongoing navigation to + newValue.

    Reloading and traversing

    -

    To reload a navigable navigable:

    +

    To reload a navigable navigable given an optional + serialized state-or-null navigationAPIState (default null) and an + optional user navigation involvement userInvolvement (default "none"):

      +
    1. +

      If userInvolvement is not "browser UI", + then:

      + +
        +
      1. Let navigation be navigable's active + window's navigation API.

      2. + +
      3. Let destinationNavigationAPIState be navigable's active session history entry's navigation API state.

      4. + +
      5. If navigationAPIState is not null, then set + destinationNavigationAPIState to navigationAPIState.

      6. + +
      7. Let continue be the result of firing a push/replace/reload navigate + event at navigation with navigationType set to "reload", isSameDocument set to false, userInvolvement set to + userInvolvement, and destinationURL + set to navigable's active session history + entry's URL, and navigationAPIState set to + destinationNavigationAPIState.

      8. + +
      9. If continue is false, then return.

      10. +
      +
    2. +
    3. Set navigable's active session history entry's document state's reload pending to true.

    4. @@ -93256,27 +97191,21 @@ location.href = '#foo'; history traversal steps to traversable:

        -
      1. -

        Apply pending history changes to traversable with true.

        - -

        It is intentional that the resulting call to apply the history - step does not pass sourceSnapshotParams or initiatorToCheck. Reloading is always treated as if - it were done by navigable itself, even in cases like parent.location.reload().

        -
      2. +
      3. Apply the reload history step to traversable.

    To traverse the history by a delta given a traversable navigable - traversable, an integer delta, and an optional Document - sourceDocument:

    + traversable, an integer delta, and an optional Document sourceDocument:

    1. Let sourceSnapshotParams and initiatorToCheck be null.

    2. +
    3. Let userInvolvement be "browser + UI".

    4. +
    5. If sourceDocument is given, then:

      @@ -93286,6 +97215,8 @@ location.href = '#foo';
    6. Set initiatorToCheck to sourceDocument's node navigable.

    7. + +
    8. Set userInvolvement to "none".

    @@ -93307,12 +97238,10 @@ location.href = '#foo';
  • If allSteps[targetStepIndex] does not exist, then abort these steps.

  • -
  • Apply the history step allSteps[targetStepIndex] to - traversable, with checkForUserCancelation - set to true, sourceSnapshotParams set to - sourceSnapshotParams, and initiatorToCheck set to - initiatorToCheck.

  • +
  • Apply the traverse history step + allSteps[targetStepIndex] to traversable, given + sourceSnapshotParams, initiatorToCheck, and + userInvolvement.

  • @@ -93333,7 +97262,7 @@ location.href = '#foo'; state-or-null serializedData (default null), and an optional history handling behavior historyHandling (default "replace"), are:

    + data-x="NavigationHistoryBehavior-replace">replace"), are:

    1. Let navigable be document's node navigable.

    2. @@ -93348,9 +97277,10 @@ location.href = '#foo';
      URL
      newURL
      -
      serialized state
      +
      serialized state
      if serializedData is not null, serializedData; otherwise - activeEntry's serialized state
      + activeEntry's classic history API + state
      document state
      activeEntry's document state
      @@ -93366,7 +97296,8 @@ location.href = '#foo';
    3. If document's is initial about:blank is true, then set - historyHandling to "replace".

      + historyHandling to "replace".

      This means that pushState() on an initial about:blank @@ -93375,10 +97306,11 @@ location.href = '#foo';

    4. Let entryToReplace be activeEntry if historyHandling is - "replace", otherwise null.

    5. + "replace", otherwise null.

    6. -

      If historyHandling is "push", then:

      +

      If historyHandling is "push", + then:

      1. Increment document's history object's @@ -93409,6 +97341,11 @@ location.href = '#foo';

      2. Set navigable's active session history entry to newEntry.

      3. +
      4. Update the navigation API entries for a same-document navigation given + document's relevant global object's navigation API, newEntry, and + historyHandling.

      5. +
      6. Let traversable be navigable's traversable navigable.

      7. @@ -93661,19 +97598,29 @@ location.href = '#foo'; final sandboxing flag set has the sandboxed downloads browsing context flag set; otherwise true.

        -
      8. If the result of running allowed to download with - sourceAllowsDownloading and targetAllowsDownloading is true, then - handle navigationParams's response as a download.

      9. +
      10. Let uaAllowsDownloading be true.

      11. -
      12. Invoke WebDriver BiDi download started with - currentBrowsingContext and a new WebDriver BiDi navigation status - whose id is navigationId, status is "complete", and url is navigationParams's response's URL.

      13. +
      14. Optionally, the user agent may set uaAllowsDownloading to false, if it + believes doing so would safeguard the user from a potentially hostile download.

      15. + +
      16. +

        If sourceAllowsDownloading, targetAllowsDownloading, and + uaAllowsDownloading are true, then:

        + +
          +
        1. Handle navigationParams's response as a download.

        2. + +
        3. Invoke WebDriver BiDi download started with + currentBrowsingContext and a new WebDriver BiDi navigation status + whose id is navigationId, status is "complete", and url is navigationParams's response's URL.

        4. +
        +
      17. Run completionSteps.

      18. @@ -94203,8 +98150,8 @@ location.href = '#foo';
      19. Assert: locationURL is a URL.

      20. -
      21. Set entry's serialized state to - StructuredSerializeForStorage(null).

      22. +
      23. Set entry's classic history API + state to StructuredSerializeForStorage(null).

      24. Let oldDocState be entry's document state.

      25. @@ -94597,19 +98544,80 @@ location.href = '#foo';
        A boolean
        -

        To apply the history step - non-negative integer step to a traversable navigable - traversable, with optional boolean checkForUserCancelation (default false), - optional source snapshot params-or-null sourceSnapshotParams (default null), - and optional navigable initiatorToCheck:

        +
        + +

        Although all updates to the traversable navigable end up in the same apply + the history step algorithm, each possible entry point comes along with some minor + customizations:

        + +

        To update for navigable creation/destruction given a traversable + navigable traversable:

        + +
          +
        1. Let step be traversable's current session history step.

        2. + +
        3. Return the result of applying the history + step step to traversable given false, false, null, null, and + null.

        4. +
        + +

        To apply the push/replace history step given a non-negative integer step + to a traversable navigable traversable:

        + +
          +
        1. Return the result of applying the history + step step to traversable given false, false, null, null, and + null.

        2. +
        + +

        Apply the push/replace history step never passes source + snapshot params or an initiator navigable to apply the history + step. This is because those checks are done earlier in the navigation algorithm.

        -

        sourceSnapshotParams and initiatorToCheck are always either - both given or both not given. They are usually not given, as most callers do not need the extra - checks on the navigation initiator that they cause. (Possibly because the caller has already - performed such checks themselves.)

        +

        To apply the reload history step given a non-negative integer step to a + traversable navigable traversable:

        + +
          +
        1. Let step be traversable's current session history step.

        2. + +
        3. Return the result of applying the history + step step to traversable given true, false, null, null, and + null.

        4. +
        + +

        Apply the reload history step never passes source snapshot + params or an initiator navigable to apply the history step. This + is because reloading is always treated as if it were done by the navigable itself, + even in cases like parent.location.reload().

        + +
        + +

        Now for the algorithm itself.

        + +

        To apply the traverse history step given a non-negative integer step to a + traversable navigable traversable, with source snapshot + params sourceSnapshotParams, navigable initiatorToCheck, + and user navigation involvement userInvolvement, perform the following + steps. They return either "initiator-disallowed", "canceled-by-beforeunload", "canceled-by-navigate", or + "applied".

        + +
          +
        1. Return the result of applying the history + step step to traversable given true, true, + sourceSnapshotParams, initiatorToCheck, and + userInvolvement.

        2. +
        + +

        To apply the history step given a + non-negative integer step to a traversable navigable + traversable, with booleans checkForCancelation and + fireNavigateEventOnCommit, source snapshot params-or-null + sourceSnapshotParams, navigable-or-null initiatorToCheck, and + user navigation involvement-or-null userInvolvementForNavigateEvents:

        1. Assert: This is running within traversable's traversable and step.

        2. -

          If initiatorToCheck is given, then:

          +

          If initiatorToCheck is not null, then:

          1. Assert: sourceSnapshotParams is not null.

          2. @@ -94627,7 +98635,8 @@ location.href = '#foo';
          3. For each navigable of get all navigables whose current session history entry will change or reload: if initiatorToCheck is not allowed by sandboxing to navigate - navigable given sourceSnapshotParams, then return.

          4. + navigable given sourceSnapshotParams, then return "initiator-disallowed".

        3. @@ -94635,19 +98644,10 @@ location.href = '#foo'; that might experience a cross-document traversal given traversable and targetStep.

          -
        4. -

          If checkForUserCancelation is true, and the result of checking if unloading - is user-canceled given navigablesCrossingDocuments given - traversable and targetStep is true, then return.

          - -

          Some algorithms check if - unloading is user-canceled as a prerequisite to modifying the history tree. Those - algorithms will set checkForUserCancelation to false when calling this algorithm to - avoid performing the check twice.

          - -

          It might not be correct to block on beforeunload results here. This may have - observable consequences.

          -
        5. +
        6. If checkForCancelation is true, and the result of checking if unloading + is canceled given navigablesCrossingDocuments, traversable, + targetStep, and userInvolvementForNavigateEvents is not "continue", then return that result.

        7. Let changingNavigables be the result of get all navigables whose current session history entry will change or reload given traversable and @@ -94668,7 +98668,7 @@ location.href = '#foo';

        8. Set navigable's current session history entry to targetEntry.

        9. -
        10. Set navigable's ongoing navigation to "

          Set the ongoing navigation for navigable to "traversal".

        @@ -94810,13 +98810,29 @@ location.href = '#foo';

        This means we tried to populate the document, but were unable to do so, e.g. because of the server returning a 204.

        + +
        +

        These kinds of failed navigations or traversals will not be signaled to the navigation API (e.g., through the promises of any + navigation API method tracker, or the navigateerror event). Doing so would leak information + about the timing of responses from other origins, in the cross-origin case, and providing + different results in the cross-origin vs. same-origin cases was deemed too confusing.

        + +

        However, implementations could use this opportunity to clear any promise handlers for + the navigation.transition.finished + promise, as they are guaranteed at this point to never run. And, they might wish to + report a warning to the console if any part of the navigation API initiated + these navigations, to make it clear to the web developer why their promises will never + settle and events will never fire.

        +
      26. If targetEntry's document's origin is not oldOrigin, then set - targetEntry's serialized state to - StructuredSerializeForStorage(null).

        + targetEntry's classic history API + state to StructuredSerializeForStorage(null).

        This clears history state when the origin changed vs a previous load of targetEntry without a redirect occuring. This can happen due to a change in CSP @@ -94932,7 +98948,7 @@ location.href = '#foo'; data-x="changing-nav-continuation-navigable">navigable.

      27. -

        Set navigable's ongoing navigation to null.

        +

        Set the ongoing navigation for navigable to null.

        This allows new navigations of navigable to start, whereas during the traversal they were blocked.

        @@ -94956,6 +98972,10 @@ location.href = '#foo'; href="#sync-navigation-steps-queue-jumping-examples">More details can be found here.

      28. +
      29. Let entriesForNavigationAPI be the result of getting session history + entries for the navigation API given navigable and + targetStep.

      30. +
      31. Queue a global task on the navigation and traversal task source given navigable's active window to run the @@ -94981,18 +99001,31 @@ location.href = '#foo';

    7. -
    8. If targetEntry's document is not equal - to displayedDocument, then queue a global task on the - navigation and traversal task source given targetEntry's document's relevant global object to perform the - following step. Otherwise, continue onward to perform the following step within the - currently-queued task.

    9. - -
    10. Update document for history step application given - targetEntry's document, - targetEntry, changingNavigableContinuation's

      If navigable is not traversable, and targetEntry is + not navigable's current session history + entry, and targetEntry's document + state's origin is the same as navigable's current session history entry's document state's origin, then fire a traverse navigate event given targetEntry and + userInvolvementForNavigateEvents.

    11. + +
    12. Let updateDocument be an algorithm step which performs update + document for history step application given targetEntry's document, targetEntry, + changingNavigableContinuation's update-only, - scriptHistoryLength, and scriptHistoryIndex.

    13. + scriptHistoryLength, scriptHistoryIndex, and + entriesForNavigationAPI.

      + +
    14. If targetEntry's document is equal to + displayedDocument, then perform updateDocument.

    15. + +
    16. Otherwise, queue a global task on the navigation and traversal task + source given targetEntry's document's + relevant global object to perform updateDocument.

    17. Increment completedChangeJobs.

    @@ -95040,6 +99073,8 @@ location.href = '#foo';
  • Set traversable's current session history step to targetStep.

  • + +
  • Return "applied".

  • To activate history entry session history entry entry for @@ -95226,7 +99261,7 @@ location.href = '#foo'; greatest step less than or equal to step.

    -
    +

    To see why getting the target history entry returns the entry with the greatest step less than or equal to the input step, consider the following Jake diagram:

    @@ -95318,8 +99353,9 @@ location.href = '#foo';

    To update document for history step application given a Document document, a session history entry entry, a boolean - doNotReactivate, and integers scriptHistoryLength and - scriptHistoryIndex:

    + doNotReactivate, integers scriptHistoryLength and + scriptHistoryIndex, and an optional list of session history entries entriesForNavigationAPI:

    1. Let documentIsNew be true if document's latest entry @@ -95346,28 +99382,53 @@ location.href = '#foo';

    2. Restore the history object state given document and entry.

    3. -
    4. If documentIsNew is false, then fire an - event named popstate at document's - relevant global object, using PopStateEvent, with the state attribute initialized to document's - history object's state.

      +
    5. Let navigation be history's relevant global object's + navigation API.

    6. -
    7. Restore persisted state given entry.

    8. +
    9. +

      If documentIsNew is false, then:

      -
    10. If documentIsNew is false, and oldURL's fragment is not equal to entry's URL's fragment, then - queue a global task on the DOM manipulation task source given - document's relevant global object to fire an event named hashchange at document's relevant global - object, using HashChangeEvent, with the oldURL attribute initialized to the serialization of oldURL and the newURL attribute initialized to the serialization of entry's URL.

    11. +
        +
      1. Update the navigation API entries for a same-document navigation given + navigation, entry, and "traverse".

      2. + +
      3. Fire an event named popstate at document's relevant global + object, using PopStateEvent, with the state attribute initialized to document's + history object's state.

        + +
      4. Restore persisted state given entry.

      5. + +
      6. If oldURL's fragment is not + equal to entry's URL's fragment, then queue a global task on the + DOM manipulation task source given document's relevant global + object to fire an event named hashchange at document's relevant global + object, using HashChangeEvent, with the oldURL attribute initialized to the serialization of oldURL and the newURL attribute initialized to the serialization of entry's URL.

      7. +
      + + +
    12. +

      Otherwise:

      + +
        +
      1. Assert: entriesForNavigationAPI is given.

      2. + +
      3. Restore persisted state given entry.

      4. + +
      5. Initialize the navigation API entries for a new document given + navigation, entriesForNavigationAPI, and entry.

      6. +
      +
    @@ -95384,7 +99445,14 @@ location.href = '#foo';
  • Otherwise, if documentsEntryChanged is false and doNotReactivate is - false, then reactivate document.

    + false, then:

    + +
      +
    1. Assert: entriesForNavigationAPI is given.

    2. + +
    3. Reactivate document given + entry and entriesForNavigationAPI.

      +

    documentsEntryChanged can be false for one of two reasons: either we are restoring from bfcache, or we are asynchronously finishing up a @@ -95402,8 +99470,8 @@ location.href = '#foo'; data-x="concept-relevant-realm">relevant realm.

  • Let state be StructuredDeserialize(entry's serialized state, targetRealm). If this throws - an exception, catch it and let state be null.

  • + data-x="she-classic-history-api-state">classic history API state, targetRealm). + If this throws an exception, catch it and let state be null.

  • Set document's history object's state to state.

  • @@ -95432,8 +99500,10 @@ location.href = '#foo'; data-x="concept-environment-execution-ready-flag">execution ready flag.

    -

    To reactivate a Document - document:

    +

    To reactivate a + Document document given a session history entry + reactivatedEntry and a list of session history entries entriesForNavigationAPI:

    This algorithm updates document after it has come out of bfcache, i.e., after it has been made fully active @@ -95468,6 +99538,11 @@ location.href = '#foo'; +

  • Update the navigation API entries for reactivation given + document's relevant global object's navigation API, entriesForNavigationAPI, and + reactivatedEntry.

  • +
  • If document's current document readiness is "complete", and document's page showing flag is false, @@ -95658,14 +99733,23 @@ location.href = '#foo';

    1. If entry's scroll restoration - mode is "auto", then restore - scroll position data given entry.

      + mode is "auto", and entry's + document's relevant global object's navigation API's suppress normal scroll restoration + during ongoing navigation is false, then restore scroll position data given + entry.

      The user agent not restoring scroll positions does not imply that scroll positions will be left at any particular value (e.g., (0,0)). The actual scroll position depends on the navigation type and the user agent's particular caching strategy. So web applications cannot assume any particular scroll position but rather are urged to set it to what they want it to be.

      + +

      If suppress normal scroll restoration during ongoing navigation is + true, then restoring scroll position data + might still happen at a later point, as part of finishing the relevant NavigateEvent, or via a + navigateEvent.scroll() method call.

    2. @@ -96266,7 +100350,7 @@ new PaymentRequest(…); // Allowed to use data-x="navigation-response">response set to navigationParams's response and historyHandling set to "replace".

      + data-x="NavigationHistoryBehavior-replace">replace".

    3. Return document.

    4. @@ -96790,8 +100874,8 @@ new PaymentRequest(…); // Allowed to use
    5. If document's unload counter is 0, and navigable's - ongoing navigation is a navigation ID, then set - navigable's ongoing navigation to null.

      + ongoing navigation is a navigation ID, then set the ongoing + navigation for navigable to null.

      This will have the effect of aborting any ongoing navigations of navigable, since at certain points during navigation, changes to the ongoing @@ -97035,9 +101119,9 @@ new PaymentRequest(…); // Allowed to use

      -

      Browser user agents should provide the ability to navigate, reload, - and stop loading any top-level traversable in their - top-level traversable set.

      +

      Browser user agents should provide the ability to navigate, reload, and stop loading + any top-level traversable in their top-level traversable set.

      For example, via a location bar and reload/stop button UI.

      @@ -97072,8 +101156,9 @@ new PaymentRequest(…); // Allowed to use

      Browser user agents may provide ways for the user to explicitly cause any - navigable (not just a top-level traversable) to navigate, - reload, or stop loading.

      + navigable (not just a top-level traversable) to navigate, reload, or stop + loading.

      For example, via a context menu.

      @@ -97097,6 +101182,20 @@ new PaymentRequest(…); // Allowed to use
      +

      All calls to navigate initiated by the mechanisms mentioned above must have the userInvolvement argument set to "browser UI".

      + +

      All calls to reload initiated by the mechanisms mentioned above must have the userInvolvement argument set to "browser UI".

      + +

      All calls to traverse the history by a delta initiated by the mechanisms mentioned + above must not pass a value for the sourceDocument + argument.

      + +
      +

      The above recommendations, and the data structures in this specification, are not meant to place restrictions on how user agents represent the session history to the user.

      @@ -102154,7 +106253,9 @@ import "https://example.com/foo/../module2.mjs";

      For each fully active Document in docs, if the focused area of that Document is not a focusable area, then run the focusing steps for that - Document's viewport.

      + Document's viewport, and set the Document's + relevant global object's navigation + API's focus changed during ongoing navigation to false.

      For example, this might happen because an element has the hidden attribute added, causing it to stop being @@ -102638,7 +106739,7 @@ import "https://example.com/foo/../module2.mjs";

      This task source is used to queue tasks involved in navigation and history + data-x="navigate">navigation and history traversal.

      @@ -103238,7 +107339,7 @@ import "https://example.com/foo/../module2.mjs";
    6. Let special error event handling be true if event is an ErrorEvent object, event's type is - error, and event's error", and event's currentTarget implements the WindowOrWorkerGlobalScope mixin. Otherwise, let special error event handling be false.

    7. @@ -103286,8 +107387,8 @@ import "https://example.com/foo/../module2.mjs";
      If event is a BeforeUnloadEvent object and event's type is beforeunload
      + data-x="dom-Event-type">type is "beforeunload" algorithm, with historyHandling set to "replace" and - other inputs kept the same, but this time skip the encoding sniffing algorithm and - instead just set the encoding to the new encoding and the confidence to certain. Whenever possible, - this should be done without actually contacting the network layer (the bytes should be re-parsed - from memory), even if, e.g., the document is marked as not being cacheable. If this is not - possible and contacting the network layer would involve repeating a request that uses a method - other than `GET`, then instead set the historyHandling set to "replace" and other inputs kept the same, but + this time skip the encoding sniffing algorithm and instead just set the encoding to + the new encoding and the confidence to + certain. Whenever possible, this should be done without actually contacting the network + layer (the bytes should be re-parsed from memory), even if, e.g., the document is marked as not + being cacheable. If this is not possible and contacting the network layer would involve repeating + a request that uses a method other than `GET`, then instead set the confidence to certain and ignore the new encoding. The resource will be misinterpreted. User agents may notify the user of the situation, to aid in application development.

      @@ -133384,6 +137486,18 @@ INSERT INTERFACES HERE canvas elements, OffscreenCanvas objects Fired when the corresponding CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D is restored after being lost + + currententrychange + NavigationCurrentEntryChangeEvent + Navigation + Fired when navigation.currentEntry changes + + + dispose + Event + NavigationHistoryEntry + Fired when the session history entry corresponding to the NavigationHistoryEntry has been permanently evicted from session history and can no longer be traversed to + error Event or ErrorEvent @@ -133444,6 +137558,24 @@ INSERT INTERFACES HERE Window, MessagePort, BroadcastChannel, DedicatedWorkerGlobalScope, Worker, ServiceWorkerContainer Fired at an object when it receives a message that cannot be deserialized + + navigate + NavigateEvent + Navigation + Fired before the navigable navigates, reloads, traverses, or otherwise changes its URL + + + navigateerror + ErrorEvent + Navigation + Fired when a navigation does not complete successfully + + + navigatesuccess + Event + Navigation + Fired when a navigation completes successfully + offline Event @@ -135100,6 +139232,7 @@ INSERT INTERFACES HERE Mustaq Ahmed, Myles Borins, Nadia Heninger, + Nate Chapin, NARUSE Yui, Navid Zolghadr, Neil Deakin, @@ -135612,6 +139745,13 @@ INSERT INTERFACES HERE href="https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document">W3C Software and Document License.

      +

      Part of the revision history of the navigation API feature can be found in the WICG/navigation-api + repository, which is available under the W3C Software and + Document License.

      +

      Copyright © WHATWG (Apple, Google, Mozilla, Microsoft). This work is licensed under a Creative Commons Attribution 4.0 International License. To the extent portions of it are incorporated into source code, such