diff --git a/index.bs b/index.bs index 1a62c261..7f713338 100644 --- a/index.bs +++ b/index.bs @@ -706,35 +706,22 @@ occurred on the [=remote end=]. are run when multiple events are enabled at once, with lower integers indicating steps that run earlier. -A [=BiDi session=] has a global event set -which is a [=/set=] containing the event names for events that are enabled for all -navigables. This initially contains the [=event name=] for events that -are in the default event set. - -A [=BiDi session=] has a navigable event map, -which is a [=/map=] with [=/top-level traversable=] keys and values -that are a [=/set=] of [=event name=]s for events that are enabled in the given -navigable. - -
- -To obtain a list of event enabled navigables given -|session| and |event name|: - -1. Let |navigables| be an empty [=/set=]. +A [=BiDi session=] has subscriptions which is a [=/list=] of [=subscriptions=]. -1. For each |navigable| → |events| of |session|'s [=navigable event map=]: +A [=BiDi session=] has a known subscription ids which is a [=/set=] of +all [=subscription/subscription ids=] that have been issued to the [=local end=] but which have not yet been unsubscribed. - 1. If |events| contains |event name|, append |navigable| to |navigables| +A subscription is a [=/struct=] consisting of a +subscription id (a string), +event names (a [=/set=] of event names) +and top-level traversable ids (a [=/set=] of IDs of [=/top-level traversables=]). -1. Return |navigables|. - -
+A [=subscription=] |subscription| is global +if |subscription|'s [=subscription/top-level traversable ids=] is an empty set.
-The set of sessions for which an event is enabled given |event -name| and |navigables| is: +The set of sessions for which an event is enabled given |event name| and |navigables| is: 1. Let |sessions| be a new [=/set=]. @@ -755,47 +742,50 @@ To determine if an event is enabled given |session|, Note: |navigables| is a set because a [=shared worker=] can be associated with multiple contexts. -1. Let |top-level traversables| be an empty [=/set=]. - -1. For each |navigable| of |navigables|, append |navigable|'s [=navigable/top-level traversable=] to |top-level traversables|. +1. Let |top-level traversables| be [=get top-level traversables=] with |navigables|. -1. Let |event map| be the [=navigable event map=] for |session|. +1. For each |subscription| in |session|'s [=subscriptions=]: -1. For each |navigable| of |top-level traversables|: + 1. If |subscription|'s [=subscription/event names=] do not [=set/contains=] |event name|, [=continue=]. - 1. If |event map| [=map/contains=] |navigable|, let |navigable events| - be |event map|[|navigable|]. Otherwise let |navigable events| be null. + 1. If |subscription| is [=subscription/global=] return true. - 1. If |navigable events| is not null, and |navigable events| - [=list/contains=] |event name|, return true. + 1. Let |subscription top-level traversables| be [=get navigables by ids=] with |subscription|'s [=subscription/top-level traversable ids=]. -1. If the [=global event set=] for |session| [=list/contains=] |event name| return - true. + 1. If the [=set/intersection=] of |top-level traversables| and + |subscription top-level traversables| is not [=list/empty=] return true. 1. Return false.
-To obtain a set of event names given an |name|: -1. Let |events| be an empty [=/set=]. +The set of top-level traversables for which an event is enabled +given |event name| and |session| is: -1. If |name| contains a U+002E (period): +1. Let |result| be a new [=/set=]. - 1. If |name| is the [=event name=] for an event, append |name| to |events| - and return [=success=] with data |events|. +1. For each |subscription| in |session|'s [=subscriptions=]: - 1. Return an [=error=] with [=error code=] [=invalid argument=] + 1. If |subscription|'s [=subscription/event names=] [=set/contains|does not contain=] |event name|, + [=continue=]. -1. Otherwise |name| is interpreted as representing all the events in a - module. If |name| is not a [=module name=] return an [=error=] with - [=error code=] [=invalid argument=]. + 1. If |subscription|'s is [=subscription/global=]: + + 1. For each |traversable| in remote end's [=/top-level traversables=]: + + 1. [=set/Append=] |traversable| to |result|. -1. Append the [=event name=] for each [=event=] in the module with name |name| to - |events|. + 1. [=Break=]. -1. Return [=success=] with data |events|. + 1. Otherwise: + + 1. Let |top-level traversables| be [=get navigables by ids=] with |subscription|'s [=subscription/top-level traversable ids=]. + + 1. [=set/Append=] each item of |top-level traversables| to |result|. + +1. Return |result|.
@@ -1109,6 +1099,37 @@ To get related navigables given an [=script/settings object=] +
+ +To get navigables by ids given a [=/list=] of context ids |navigable ids|: + +1. Let |result| be an empty [=/set=]. + +1. For each |navigable id| in |navigable ids|: + + 1. Let |navigable| be the [=/navigable=] with id |navigable id| + if such [=/navigable=] exists, and null otherwise. + + 1. [=set/Append=] |navigable| to |result| if |navigable| is not null. + +1. Return |result|. + +
+ +
+ +To get top-level traversables given a [=/list=] of [=/navigables=] |navigables|: + +1. Let |result| be an empty [=/set=]. + +1. For each |navigable| in |navigables|: + + 1. [=set/Append=] |navigable|'s [=navigable/top-level traversable=] to |result|. + +1. Return |result|. + +
+
To emit an event given |session|, and |body|: 1. [=Assert=]: |body| has [=map/size=] 2 and [=map/contains=] "method" @@ -1482,113 +1503,6 @@ To cleanup remote end state.
-
-To update the event map, given -|session|, |requested event names|, |navigables|, and |enabled|: - -Note: The return value of this algorithm is a map between event names and -navigables. When the events are being enabled, the navigables in the return value -are those for which the event are now enabled but were not previously. When -events are disabled, the return value is always empty. - -1. Let |global event set| be a [=set/clone=] of the [=global event set=] for - |session|. - -1. Let |event map| be a new [=/map=]. - -1. For each |key| → |value| of the [=navigable event map=] for - |session|: - - 1. Set |event map|[|key|] to a [=set/clone=] of |value|. - -1. Let |event names| be an empty [=/set=]. - -1. For each entry |name| in |requested event names|, - let |event names| be the union of |event names| and the result of - [=trying=] to [=obtain a set of event names=] with |name|. - -1. Let |enabled events| be a new [=/map=]. - -1. If |navigables| is null: - - 1. If |enabled| is true: - - 1. For each |event name| of |event names|: - - 1. If |global event set| doesn't contain |event name|: - - 1. Let |already enabled navigables| be the [=event enabled navigables=] - given |session| and |event name|. - - 1. Add |event name| to |global event set|. - - 1. For each |navigable| of |already enabled navigables|, remove |event - name| from |event map|[|navigable|]. - - 1. Let |newly enabled contexts| be a list of all [=/top-level traversable=] - that are not contained in |already enabled navigables|, - - 1. Set |enabled events|[|event name|] to |newly enabled contexts|. - - 1. If |enabled| is false: - - 1. For each |event name| in |event names|: - - 1. If |global event set| [=list/contains=] |event name|, remove |event - name| from |global event set|. Otherwise return [=error=] with - [=error code=] [=invalid argument=]. - -1. Otherwise, if |navigables| is not null: - - 1. Let |targets| be an empty [=/map=]. - - 1. For each |navigable id| in |navigables|: - - 1. Let |navigable| be the result of [=trying=] to [=get a navigable=] - with |navigable id|. - - 1. Let |top-level traversable| be the [=navigable/top-level traversable=] for |navigable|. - - 1. If |event map| does not contain |top-level traversable|, set |event - map|[|top-level traversable|] to a new [=/set=]. - - 1. Set |targets|[|top-level traversable|] to |event map|[|top-level traversable|]. - - 1. For each |event name| in |event names|: - - 1. If |enabled| is true and |global event set| contains |event name|, continue. - - 1. For each |navigable| → |target| in |targets|: - - 1. If |enabled| is true and |target| does not contain |event name|: - - 1. Add |event name| to |target|. - - 1. If |enabled events| does not contain |event name|, set |enabled - events|[|event name|] to a new [=/set=]. - - 1. Append |navigable| to |enabled events|[|event name|]. - - 1. If |enabled| is false: - - 1. If |target| contains |event name|, remove |event name| from - |target|. Otherwise return [=error=] with [=error code=] [=invalid - argument=]. - -1. Set the [=global event set=] for |session| to |global event set|. - -1. Set the [=navigable event map=] for |session| to |event map|. - -1. Return [=success=] with data |enabled events|. - -Note: Implementations that do additional work when an event is enabled, -e.g. subscribing to the relevant engine-internal events, will likely perform -those additional steps when updating the event map. This specification uses -a model where hooks are always called and then the event map is used to -filter only those that ought to be returned to the local end. - -
- ### Types ### {#module-session-types} #### The session.CapabilitiesRequest Type #### {#type-session-CapabilitiesRequest} @@ -1733,6 +1647,14 @@ session.UserPromptHandlerType = "accept" / "dismiss" / "ignore"; The session.UserPromptHandlerType type represents the behavior of the user prompt handler. +#### The session.Subscription Type #### {#type-session-Subscription} + +
+session.Subscription = text
+
+ +The session.Subscription type represents a unique subscription identifier. + #### The session.SubscriptionRequest Type #### {#type-session-SubscriptionRequest}
@@ -1745,6 +1667,31 @@ session.SubscriptionRequest = {
 The session.SubscriptionRequest type represents a request to
 subscribe to or unsubscribe from a specific set of events.
 
+#### The session.UnsubscribeByIDRequest Type #### {#type-session-UnsubscribeByIDRequest}
+
+
+session.UnsubscribeByIDRequest = {
+  subscriptions: [+session.Subscription],
+}
+
+ +The session.UnsubscribeByIDRequest type represents a request to +remove event subscriptions identified by subscription IDs. + +#### The session.UnsubscribeByAttributesRequest Type #### {#type-session-UnsubscribeByAttributesRequest} + +Note: contexts param is deprecated and will be removed in the future versions. + +
+session.UnsubscribeByAttributesRequest = {
+  events: [+text],
+  ? contexts: [+browsingContext.BrowsingContext],
+}
+
+ +The session.UnsubscribeByAttributesRequest type represents a request to +unsubscribe using subscription attributes. + ### Commands ### {#module-session-commands} #### The session.status Command #### {#command-session-status} @@ -1938,31 +1885,61 @@ Issue: This needs to be generalized to work with realms too.
Result Type
- - EmptyResult - +
+        session.SubscriptionRequestResult = {
+          subscription: session.Subscription,
+        }
+      
The [=remote end steps=] with |session| and |command parameters| are: -1. Let the |list of event names| be the value of the events field of - |command parameters| +1. Let the |event names| be [=set/create=] a [=/set=] given |command parameters|["events"]. + +1. Let |subscription navigables| be a [=/set=]. + +1. Let |top-level traversable context ids| be a [=/set=]. + +1. Let |input context ids| be [=set/create=] a [=/set=] given |command parameters|[contexts]. + +1. If |input context ids| is not empty: -1. Let the |list of navigables| be the value of the contexts - field of |command parameters| if it is present or null if it isn't. + 1. Let |navigables| be [=get navigables by ids=] with |input context ids|. -1. Let |enabled events| be the result of [=trying=] to [=update the event map=] - with |session|, |list of event names| , |list of navigables| and - enabled true. + 1. If [=list/size=] of |navigables| does not equal [=list/size=] of |input context ids|: + + 1. Return [=error=] with [=error code=] [=invalid argument=]. + + 1. Set |subscription navigables| be [=get top-level traversables=] with |navigables|. + + 1. For each |navigable| in |subscription navigables|: + + 1. [=set/Append=] |navigable|'s [=navigable id=] to |top-level traversable context ids|. + +1. Otherwise, set |subscription navigables| to a [=/set=] of all [=navigable/top-level traversables=] in the [=remote end=]. + +1. Let |subscription| be a [=subscription=] with + [=subscription/subscription id=] set to the string representation of a [[!RFC9562|UUID]], + [=subscription/event names=] set to |event names|, and + [=subscription/top-level traversable ids=] set to |top-level traversable context ids|. 1. Let |subscribe step events| be a new [=/map=]. -1. For each |event name| → |navigables| in |enabled events|: +1. For each |event name| in the |event names|: - 1. If the [=event=] with [=event name=] |event name| defines [=remote end - subscribe steps=], set |subscribe step events|[|event name|] to |navigables|. + 1. If the [=event=] with [=event name=] |event name| does not define [=remote end + subscribe steps=], continue; + + 1. Let |existing navigables| be a [=set of top-level traversables for which an event is enabled=] with |session| and |event name|. + + 1. Set |subscribe step events|[|event name|] to [=set/difference=] of + |subscription navigables| and |existing navigables|. + +1. Append |subscription| to |session|'s [=subscriptions=]. + +1. Append |subscription|'s [=subscription/subscription id=] to |session|'s [=known subscription ids=]. 1. [=map/Sort in ascending order=] |subscribe step events| using the following less than algorithm given two entries with keys |event name one| and |event @@ -1975,7 +1952,7 @@ The [=remote end steps=] with |session| and |command parameters| are: 1. Return true if |event one|'s [=subscribe priority=] is less than |event two|'s subscribe priority, or false otherwise. -1. If |list of navigables| is null, let |include global| be true, otherwise let +1. If |subscription| is [=subscription/global=], let |include global| be true, otherwise let |include global| be false. 1. For each |event name| → |navigables| in |subscribe step events|: @@ -1994,13 +1971,16 @@ either globally or for a set of navigables. Issue: This needs to be generalised to work with realms too. +Note: contexts parameter in UnsubscribeByAttributesRequest is deprecated +and will be removed in the future versions. +
Command Type
      session.Unsubscribe = (
        method: "session.unsubscribe",
-       params: session.SubscriptionRequest
+       params: session.UnsubscribeByAttributesRequest / session.UnsubscribeByIDRequest,
      )
      
@@ -2015,14 +1995,107 @@ Issue: This needs to be generalised to work with realms too.
The [=remote end steps=] with |session| and |command parameters| are: -1. Let the |list of event names| be the value of the events field of - |command parameters|. +1. If |command parameters| matches the session.UnsubscribeByAttributesRequest production: + + 1. Let |event names| be [=set/create|create a set=] with |command parameters|["events"]. + + 1. Let |top-level traversable context ids| be a [=/set=]. + + 1. Let |input context ids| be [=set/create=] a [=/set=] given |command parameters|[contexts]. + + 1. If |input context ids| is not empty: + + 1. Let |navigables| be [=get navigables by ids=] with |input context ids|. + + 1. If [=list/size=] of |navigables| does not equal [=list/size=] of |input context ids|: + + 1. Return [=error=] with [=error code=] [=invalid argument=]. + + 1. Set |top-level traversables| be [=get top-level traversables=] with |navigables|. + + 1. For each |navigable| in |top-level traversables|: + + 1. [=set/Append=] |navigable|'s [=navigable id=] to |top-level traversable context ids|. -1. Let the |list of contexts| be the value of the contexts - field of |command parameters| if it is present or null if it isn't. + 1. Let |new subscriptions| to be a [=/list=]. -1. [=Try=] to [=update the event map=] with |session|, - |list of event names|, |list of contexts| and enabled false. + 1. For each |subscription| of |session|'s [=subscriptions=]: + + 1. If [=set/intersection=] of |subscription|'s [=subscription/event names=] and |event names| is an empty [=/set=]: + + 1. [=list/append=] |subscription| to |new subscriptions|. + + 1. Continue. + + 1. If |top-level traversable context ids| is an empty [=/set=]: + + 1. [=list/Remove=] all items [=list/contains|contained=] in |event names| from |subscription|'s [=subscription/event names=]. + + 1. If |subscription|'s [=subscription/event names=] is not empty: + + 1. [=list/append=] |subscription| to |new subscriptions|. + + 1. Otherwise: + + 1. If |subscription| is [=subscription/global=]: + + 1. [=list/append=] |subscription| to |new subscriptions|. + + 1. Otherwise: + + Note: unsubscribe by contexts is deprecated and will be removed in the future versions. + + 1. Let |event map| be an empty [=/map=]. + + 1. For each |event name| in |subscription|'s [=subscription/event names=]: + + 1. Set |event map|[|event name|] to [=set/clone=] of |subscription|'s [=subscription/top-level traversable ids=]. + + 1. For each |event name| in |event names|: + + 1. If |event map|[|event name|] does not exist, + continue. + + 1. Set |event map|[|event name|] to the [=set/difference=] + between |event map|[|event name|] and |top-level traversable context ids|. + + 1. If |event map|[|event name|] is an empty [=/set=], + + 1. [=map/Remove=] |event map|[|event name|]. + + 1. For each |event name| → |remaining top-level traversable ids| in |event map|: + + 1. Let |partial subscription| be a [=subscription=] with + [=subscription/subscription id=] set to |subscription|'s [=subscription/subscription id=], + [=subscription/event names=] set to a new [=/set=] containing |event name|, + [=subscription/top-level traversable ids=] set to |remaining top-level traversable ids|. + + 1. [=list/append=] |partial subscription| to |new subscriptions|. + + 1. Set |session|'s [=subscriptions=] to |new subscriptions|. + +1. Otherwise: + + 1. Let |subscriptions| be [=set/create=] a [=/set=] with |command parameters|[subscriptions]. + + 1. Let |unknown subscription ids| to [=set/difference=] between |subscriptions| and |session|'s [=known subscription ids=]. + + 1. If |unknown subscription ids| is not empty: + + 1. Return [=error=] with [=error code=] [=invalid argument=]. + + 1. Let |subscriptions to remove| be an empty [=/set=]. + + 1. For each |subscription| in |session|'s [=subscriptions=]: + + 1. If |subscriptions| [=set/contains=] |subscription|'s [=subscription/subscription id=]: + + 1. [=set/Append=] |subscription| to |subscriptions to remove|. + + 1. Set |session|'s [=known subscription ids=] to + [=set/difference=] between |session|'s [=known subscription ids=] and |subscriptions|. + + 1. [=list/Remove=] each item in |subscriptions to remove| from |session|'s [=subscriptions=]. 1. Return [=success=] with data null. @@ -4677,6 +4750,20 @@ the WebDriver BiDi navigable destroyed steps given |navigable| 1. [=Emit an event=] with |session| and |body|. + 1. Let |subscriptions to remove| be a [=/set=]. + + 1. For each |subscription| in |session|'s [=subscriptions=]: + + 1. If |subscription|'s [=subscription/top-level traversable ids=] [=set/contains=] |navigable|'s [=navigable id=]; + + 1. [=set/Remove=] |navigable|'s [=navigable id=] from |subscription|'s [=subscription/top-level traversable ids=]. + + 1. If |subscription|'s [=subscription/top-level traversable ids=] is empty: + + 1. [=set/Append=] |subscription| to |subscriptions to remove|. + + 1. [=list/Remove=] |subscriptions to remove| from |session|'s [=subscriptions=]. + Issue: It's unclear if we ought to only fire this event for browsing contexts that have active documents; navigation can also cause contexts to become inaccessible but not yet get discarded because bfcache.