diff --git a/source b/source index 09230c2df53..402cad4fced 100644 --- a/source +++ b/source @@ -78586,9 +78586,17 @@ interface VisibilityStateEntry : PerformanceEntryorigin is same origin with document's origin.

-
  • For each window in windows, set - window's last activation timestamp to the current high resolution - time.

  • +
  • +

    For each window in windows:

    + +
      +
    1. Set window's last activation timestamp to the current + high resolution time.

    2. + +
    3. Notify the close watcher manager about user activation given + window.

    4. +
    +
  • An activation triggering input event is any event whose fullscreenchange to be eventually fired.

    +
  • +

    Optionally, skip to the step labeled alternative + processing.

    + +

    For example, if the user agent detects user frustration at repeated close + request interception by the current web page, it might take this path.

    +
  • +
  • Fire any relevant events, per UI Events or other relevant specifications. UIEVENTS

    @@ -81946,9 +81962,9 @@ body { display:none }
  • If closedSomething is true, then return.

  • -
  • Otherwise, there was nothing watching for a close request. The user agent - may instead interpret this interaction as some other action, instead of interpreting it as a - close request.

  • +
  • Alternative processing: Otherwise, there was nothing + watching for a close request. The user agent may instead interpret this interaction + as some other action, instead of interpreting it as a close request.

  • @@ -81963,25 +81979,83 @@ body { display:none }

    On platforms where a back button is a potential close request, no event is involved, so when the back button is pressed, the user agent proceeds directly to - process close watchers. If there is a close watcher on the close - watcher stack, then that will get triggered. If there is not, then the user agent can - interpret the back button press in another way, for example as a request to traverse the - history by a delta of −1.

    + process close watchers. If there is an active close watcher, then that will get + triggered. If there is not, then the user agent can interpret the back button press in another + way, for example as a request to traverse the history by a delta of −1.

    Close watcher infrastructure

    -

    Each Window has a close watcher stack, a list of close watchers, initially empty.

    +

    Each Window has a close watcher manager, which is a + struct with the following items:

    + + + +

    Most of the complexity of the close watcher manager comes from anti-abuse + protections designed to prevent developers from disabling users' history traversal abilities, for + platforms where a close request's fallback + action is the main mechanism of history traversal. In particular:

    + +

    The grouping of close watchers is designed so that if + multiple close watchers are created without history-action activation, they are + grouped together, so that a user-triggered close request will close all of the close + watchers in a group. This ensures that web developers can't intercept an unlimited number of + close requests by creating close watchers; instead they can create a number equal to at most 1 + + the number of times the user activates the page.

    + +

    The next user interaction allows a new group + boolean encourages web developers to create close watchers in + a way that is tied to individual user activations. Without + it, each user activation would increase the allowed number of groups, even if the web developer isn't "using" those user + activations to create close watchers. In short:

    + + + +

    This protection is not important for upholding our desired invariant of creating at + most (1 + the number of times the user activates the page) + groups. A determined abuser will just create one close watcher per user interaction, "banking" + them for future abuse. But this system causes more predictable behavior for the normal case, and + encourages non-abusive developers to create close watchers directly in response to user + interactions.

    + +

    To notify the close watcher manager about user activation given a + Window window:

    + +
      +
    1. Let manager be window's close watcher manager.

    2. + +
    3. If manager's next user interaction + allows a new group is true, then increment manager's allowed number of groups.

    4. + +
    5. Set manager's next user interaction + allows a new group to false.

    6. +
    + +

    A close watcher is a struct with the following items:

    @@ -81997,27 +82071,14 @@ body { display:none }
  • A close action, a list of steps. These steps can never throw an exception.

  • -
  • A was created with user activation - boolean.

  • - -
  • An is grouped with previous boolean.

  • -
  • An is running cancel action boolean.

  • -

    The is grouped with previous boolean - is set if a close watcher is created without history-action activation. - (Except the very first close watcher in the close watcher stack that is created - without transient activation, which gets a pass on this restriction.) It causes a user-triggered - close request to close all such grouped-together close watchers, thus ensuring that - web developers can't make close requests ineffective by creating an excessive number of close - watchers.

    -

    A close watcher closeWatcher is active if closeWatcher's window's - close watcher stack contains - closeWatcher.

    + close watcher manager contains any list which + contains closeWatcher.


    @@ -82026,49 +82087,9 @@ body { display:none } list of steps closeAction:

      -
    1. Assert: window's associated - Document is fully active.

    2. - -
    3. Let wasCreatedWithUserActivation and isGroupedWithPrevious be - null.

    4. - -
    5. -

      If window has history-action activation, then:

      - -
        -
      1. Consume history-action user activation given window.

      2. - -
      3. Set wasCreatedWithUserActivation to true.

      4. - -
      5. Set isGroupedWithPrevious to false.

      6. -
      -
    6. - -
    7. -

      Otherwise, if there is no close watcher in window's close - watcher stack whose was created with user - activation is false, then:

      - -
        -
      1. Set wasCreatedWithUserActivation to false.

      2. - -
      3. Set isGroupedWithPrevious to false.

      4. -
      - -

      This will be the one "free" close watcher created without user activation, which - is useful for cases like session inactivity timeout dialogs or notifications from the - server.

      -
    8. - -
    9. -

      Otherwise:

      - -
        -
      1. Set wasCreatedWithUserActivation to false.

      2. - -
      3. Set isGroupedWithPrevious to true.

      4. -
      -
    10. +
    11. Assert: window's associated Document is fully + active.

    12. Let closeWatcher be a new close watcher, with

      @@ -82083,19 +82104,36 @@ body { display:none }
      close action
      closeAction
      -
      was created with user activation
      -
      wasCreatedWithUserActivation
      - -
      is grouped with previous
      -
      isGroupedWithPrevious
      -
      is running cancel action
      false
    13. -
    14. Append closeWatcher to window's - close watcher stack.

    15. +
    16. Let manager be window's close watcher manager.

    17. + +
    18. If manager's groups's size is less than manager's allowed number of groups, then append « closeWatcher » to manager's groups.

    19. + +
    20. +

      Otherwise:

      + +
        +
      1. Assert: manager's groups's size is at least 1 in this branch, + since manager's allowed number of groups is always at least 1.

      2. + +
      3. Append closeWatcher to + manager's groups's last item.

      4. +
      +
    21. + +
    22. Set manager's next user interaction + allows a new group to true.

    23. Return closeWatcher.

    @@ -82105,19 +82143,23 @@ body { display:none }
    1. If closeWatcher is not active, then - return.

    2. + return true.

    3. If closeWatcher's is running - cancel action is true, then return.

    4. + cancel action is true, then return true.

    5. Let window be closeWatcher's window.

    6. If window's associated - Document is not fully active, then return.

    7. + Document is not fully active, then return true.

    8. -

      If window has history-action activation, then:

      +

      If window's close watcher manager's groups's size is less than + window's close watcher manager's allowed number of groups, and window has + history-action activation, then:

      1. Set closeWatcher's is running @@ -82135,21 +82177,20 @@ body { display:none }

        1. Consume history-action user activation given window.

        2. -
        3. Return.

        4. +
        5. Return false.

      -

      The guard on these substeps means that the cancel action only has a chance to prevent us from - continuing onward to the close action when - window has history-action activation. In particular, since these - substeps consume history-action user activation, requesting to close a close watcher - twice without any intervening user activation will skip these substeps.

      +

      Note that since these substeps consume history-action user + activation, requesting to close a + close watcher twice without any intervening user activation will skip + these substeps.

    9. Close closeWatcher.

    10. + +
    11. Return true.

    To close a close watcher @@ -82170,34 +82211,58 @@ body { display:none }

    To destroy a close watcher - closeWatcher, remove closeWatcher from - closeWatcher's window's close watcher - stack.

    + closeWatcher:

    + +
      +
    1. Let manager be closeWatcher's window's close watcher manager.

    2. + +
    3. For each group of manager's + groups: remove closeWatcher from group.

    4. + +
    5. Remove any item from manager's groups that is + empty.

    6. +

    -

    To process close watchers given a Window window:

    +

    To process close watchers given a Window window:

    1. Let processedACloseWatcher be false.

    2. -

      While window's close watcher stack is not empty:

      +

      If window's close watcher manager's groups is not empty:

        -
      1. Let closeWatcher be the last item in - window's close watcher stack.

      2. +
      3. Let group be the last item in + window's close watcher manager's groups.

      4. -
      5. Request to close - closeWatcher.

      6. +
      7. +

        For each closeWatcher of group, + in reverse order:

        -
      8. Set processedACloseWatcher to true.

      9. +
          +
        1. Set processedACloseWatcher to true.

        2. + +
        3. Let shouldProceed be the result of requesting to close + closeWatcher.

        4. -
        5. If closeWatcher's is grouped with - previous is false, then break.

        6. +
        7. If shouldProceed is false, then break.

        8. +
        +
    3. +
    4. If window's close watcher manager's allowed number of groups is greater than 1, decrement + it by 1.

    5. +
    6. Return processedACloseWatcher.