Skip to content

Commit

Permalink
Make requestPermission()'s behavior more backwards-compatible
Browse files Browse the repository at this point in the history
The changes added in #123 have introduced some behavior changes to the two
requestPermission() operations that were not originally intended.

Although the original steps were heavily modeled after the WebKit
implementation and do not follow what other specifications normally do, some
behavior changes from #123 have not been discussed and have been made more
backwards-compatible:

- Calls to "request permission to use" may return "prompt", while the
  previous version implicitly converted anything that was not "granted" to
  "denied" (possibly because the current Safari implementation shows a modal
  dialog asking for access, so users can only allow or deny the permission
  request, so remaining at the "prompt" state is not possible).
  From a specification perspective, if a user has not explicitly granted the
  permission request, "prompt" is essentially the same as "denied" anyway,
  so we now explicitly set anything that is not "granted" to "denied" again.
- The previous steps only checked for transient activation if users had not
  made an explicit permission choice yet, which basically means that the
  permission state is set to "prompt".
  This change restores this behavior by first checking the current
  permission states for all required permission names and only throwing a
  NotAllowed exception if one of them is "prompt" and there is no transient
  activation. In other words, if a permission is either "granted" or
  "denied" then requestPermission() will resolve to one of the values
  without requiring transient activation.

While here, refer to the right definitions of "granted" and "denied": use
the PermissionState enum definitions, which is what the Permissions API
algorithms we invoke return, rather than the non-Web IDL definitions that
these enum values correspond to.
  • Loading branch information
rakuco committed Jan 10, 2024
1 parent 2dab013 commit 5c4cc92
Showing 1 changed file with 21 additions and 12 deletions.
33 changes: 21 additions & 12 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -306,20 +306,24 @@ The <dfn attribute for="DeviceOrientationEvent">absolute</dfn> attribute must re
The <dfn method for="DeviceOrientationEvent">requestPermission(<var>absolute</var>)</dfn> method steps are:

1. Let <var>global</var> be the <a>current global object</a>.
1. If <a>this</a>'s <a>relevant global object</a> does not have <a>transient activation</a>, return <a>a promise rejected with</a> a "{{NotAllowedError}}" {{DOMException}}.
1. Let <var>hasTransientActivation</var> be true if <a>this</a>'s <a>relevant global object</a> has <a>transient activation</a>, and false otherwise.
1. Let <var>result</var> be <a>a new promise</a> in <a>this</a>'s <a>relevant Realm</a>.
1. Run these steps <a>in parallel</a>:
1. If <var>absolute</var> is true:
1. Let <var>permissions</var> be « "<a permission>accelerometer</a>", "<a permission>gyroscope</a>", "<a permission>magnetometer</a>" ».
1. Otherwise:
1. Let <var>permissions</var> be « "<a permission>accelerometer</a>", "<a permission>gyroscope</a>" ».
1. Let <var>permissionState</var> be "<a for="permission">granted</a>".
1. <a for="list">For each</a> <var>name</var> of <var>permissions</var>:
1. If <var>name</var>'s <a>permission state</a> is "{{PermissionState/prompt}}" and <var>hasTransientActivation</var> is false:
1. <a>Queue a global task</a> on the <a>device motion and orientation task source</a> given <var>global</var> to <a>reject</a> <var>result</var> with a "{{NotAllowedError}}" {{DOMException}}.
1. Return.
1. Let <var>permissionState</var> be "{{PermissionState/granted}}".
1. <a for="list">For each</a> <var>name</var> of <var>permissions</var>:

Note: There is no algorithm for requesting multiple permissions at once. However, user agents are encouraged to bundle concurrent requests for different kinds of media into a single user-facing permission prompt.

1. If the result of <a>requesting permission to use</a> <var>name</var> is "<a for="permission">denied</a>":
1. Set <var>permissionState</var> to "<a for="permission">denied</a>".
1. If the result of <a>requesting permission to use</a> <var>name</var> is not "{{PermissionState/granted}}":
1. Set <var>permissionState</var> to "{{PermissionState/denied}}".
1. <a>Break</a>
1. <a>Queue a global task</a> on the <a>device motion and orientation task source</a> given <var>global</var> to <a>resolve</a> <var>result</var> with <var>permissionState</var>.</li>
1. Return <var>result</var>.
Expand Down Expand Up @@ -350,7 +354,7 @@ To <dfn>fire an orientation event</dfn> given a <var>event name</var> (a string)
1. Run these steps <a>in parallel</a>:
1. <a for="list">For each</a> <var>permission name</var> in <var>permissions</var>:
1. Let <var>state</var> be the result of <a>getting the current permission state</a> with <var>permission name</var> and <var>environment</var>.
1. If <var>state</var> is not "<a for="permission">granted</a>", return.
1. If <var>state</var> is not "{{PermissionState/granted}}", return.
1. <a>Queue a global task</a> on the <a>device motion and orientation task source</a> given <var>window</var> to run the following steps:
1. Let <var>z rotation</var> be <var>orientation</var>'s representation as intrinsic Tait-Bryan angles Z - X' - Y'' along the Z axis, or null if the implementation cannot provide an angle value.
1. If <var>z rotation</var> is not null, limit <var>z rotation</var>'s precision to 0.1 degrees.
Expand Down Expand Up @@ -529,16 +533,21 @@ The <dfn attribute for="DeviceMotionEvent">interval</dfn> attribute must return
The <dfn method for="DeviceMotionEvent">requestPermission()</dfn> method steps are:

1. Let <var>global</var> be the <a>current global object</a>.
1. If <a>this</a>'s <a>relevant global object</a> does not have <a>transient activation</a>, return <a>a promise rejected with</a> a "{{NotAllowedError}}" {{DOMException}}.
1. Let <var>hasTransientActivation</var> be true if <a>this</a>'s <a>relevant global object</a> has <a>transient activation</a>, and false otherwise.
1. Let <var>result</var> be <a>a new promise</a> in <a>this</a>'s <a>relevant Realm</a>.
1. Run these steps <a>in parallel</a>:
1. Let <var>permissionState</var> be "<a for="permission">granted</a>".
1. <a for="list">For each</a> <var>name</var> of « "<a permission>accelerometer</a>", "<a permission>gyroscope</a>" »:
1. Let <var>permissions</var> be « "<a permission>accelerometer</a>", "<a permission>gyroscope</a>" ».
1. <a for="list">For each</a> <var>name</var> of <var>permissions</var>:
1. If <var>name</var>'s <a>permission state</a> is "{{PermissionState/prompt}}" and <var>hasTransientActivation</var> is false:
1. <a>Queue a global task</a> on the <a>device motion and orientation task source</a> given <var>global</var> to <a>reject</a> <var>result</var> with a "{{NotAllowedError}}" {{DOMException}}.
1. Return.
1. Let <var>permissionState</var> be "{{PermissionState/granted}}".
1. <a for="list">For each</a> <var>name</var> of <var>permissions</var>:

Note: There is no algorithm for requesting multiple permissions at once. However, user agents are encouraged to bundle concurrent requests for different kinds of media into a single user-facing permission prompt.

1. If the result of <a>requesting permission to use</a> <var>name</var> is "<a for="permission">denied</a>":
1. Set <var>permissionState</var> to "<a for="permission">denied</a>".
1. If the result of <a>requesting permission to use</a> <var>name</var> is not "{{PermissionState/granted}}":
1. Set <var>permissionState</var> to "{{PermissionState/denied}}".
1. <a>Break</a>
1. <a>Queue a global task</a> on the <a>device motion and orientation task source</a> given <var>global</var> to <a>resolve</a> <var>result</var> with <var>permissionState</var>.</li>
1. Return <var>result</var>.
Expand Down Expand Up @@ -601,7 +610,7 @@ At an <a>implementation-defined</a> interval <var>interval</var>, the user agent
1. Run these steps <a>in parallel</a>:
1. <a for="list">For each</a> <var>permission name</var> in « "<a permission>accelerometer</a>", "<a permission>gyroscope</a>" »:
1. Let <var>state</var> be the result of <a>getting the current permission state</a> with <var>permission name</var> and <var>environment</var>.
1. If <var>state</var> is not "<a for="permission">granted</a>", return.
1. If <var>state</var> is not "{{PermissionState/granted}}", return.
1. <a>Queue a global task</a> on the <a>device motion and orientation task source</a> given <var>window</var> to run the following steps:
1. <a>Fire an event</a> named <a event for="Window"><code>devicemotion</code></a> at <var>window</var>, using {{DeviceMotionEvent}}, with the {{DeviceMotionEvent/acceleration}} attribute initialized to <var>acceleration</var>, the {{DeviceMotionEvent/accelerationIncludingGravity}} attribute initialized to <var>accelerationIncludingGravity</var>, the {{DeviceMotionEvent/rotationRate}} attribute initialized to <var>rotationRate</var>, and the {{DeviceMotionEvent/interval}} attribute initialized to <var>interval</var>.

Expand Down Expand Up @@ -1082,4 +1091,4 @@ This section summarizes substantial changes and notable editorial improvements t
- Make security and privacy considerations normative
- Add the ondeviceorientationabsolute event handler attribute into the IDL block (was only in prose)
- Remove '?' from dictionary members of DeviceMotionEventInit
- Use [Exposed=Window] extended attribute
- Use [Exposed=Window] extended attribute

0 comments on commit 5c4cc92

Please sign in to comment.