From 335cf0c77293ae06aafd75a2acfdea8ec761497e Mon Sep 17 00:00:00 2001
From: Domenic Denicola
For each window in windows, set - window's last activation timestamp to the current high resolution - time.
For each window in windows:
+ +Set window's last activation timestamp to the current + high resolution time.
Notify the close watcher manager about user activation given + window.
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.
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.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:
Groups, a list of lists of close watchers, initially + empty.
Allowed number of + groups, a number, initially 1.
Next user interaction allows a new group, + a boolean, initially true.
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:
+ +Allowed: user interaction; create a close watcher in its own group; user interaction; + create a close watcher in a second independent group.
Disallowed: user interaction; user interaction; create a close watcher in its own group; + create a close watcher in a second independent group.
It isn't quite a proper stack, as items can get removed from the middle of it if a - close watcher is destroyed or closed via web developer code. User-initiated close requests always act on the top of the close watcher - stack, however.
+Allowed: user interaction; user interaction; create a close watcher in its own group; + create a close watcher grouped with the previous one.
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:
Let manager be window's close watcher manager.
If manager's next user interaction + allows a new group is true, then increment manager's allowed number of groups.
Set manager's next user interaction + allows a new group to false.
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.Assert: window's associated
- Document
is fully active.
Let wasCreatedWithUserActivation and isGroupedWithPrevious be - null.
If window has history-action activation, then:
- -Consume history-action user activation given window.
Set wasCreatedWithUserActivation to true.
Set isGroupedWithPrevious to false.
Otherwise, if there is no close watcher in window's close - watcher stack whose was created with user - activation is false, then:
- -Set wasCreatedWithUserActivation to false.
Set isGroupedWithPrevious to false.
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.
-Otherwise:
- -Set wasCreatedWithUserActivation to false.
Set isGroupedWithPrevious to true.
Assert: window's associated Document
is fully
+ active.
Let closeWatcher be a new close watcher, with
@@ -82083,19 +82104,36 @@ body { display:none }Append closeWatcher to window's - close watcher stack.
Let manager be window's close watcher manager.
If manager's groups's size is less than manager's allowed number of groups, then append « closeWatcher » to manager's groups.
Otherwise:
+ +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.
Append closeWatcher to + manager's groups's last item.
Set manager's next user interaction + allows a new group to true.
Return closeWatcher.
If closeWatcher is not active, then - return.
If closeWatcher's is running - cancel action is true, then return.
Let window be closeWatcher's window.
If window's associated
- Document
is not fully active, then return.
Document
is not fully active, then return true.
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:
Set closeWatcher's is running
@@ -82135,21 +82177,20 @@ body { display:none }
Consume history-action user activation given window. Return. 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.
Close closeWatcher.
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: + +Let manager be closeWatcher's window's close watcher manager.
For each group of manager's + groups: remove closeWatcher from group.
Remove any item from manager's groups that is + empty.
To process close watchers given a Window
window:
To process close watchers given a Window
window:
Let processedACloseWatcher be false.
While window's close watcher stack is not empty:
+If window's close watcher manager's groups is not empty:
Let closeWatcher be the last item in - window's close watcher stack.
Let group be the last item in + window's close watcher manager's groups.
Request to close - closeWatcher.
For each closeWatcher of group, + in reverse order:
-Set processedACloseWatcher to true.
Set processedACloseWatcher to true.
Let shouldProceed be the result of requesting to close + closeWatcher.
If closeWatcher's is grouped with - previous is false, then break.
If shouldProceed is false, then break.
If window's close watcher manager's allowed number of groups is greater than 1, decrement + it by 1.
Return processedACloseWatcher.