1. Introduction
User agents expose powerful features to web sites, which are features that are important to some use cases, but can be easily abused. The arguably canonical example of such a powerful feature is camera access, which is essential to many use cases like online meetups, but unsolicited camera activation would be a major privacy issue. To handle this, user agents use permissions to ask the user whether they wish for a particular access to be allowed or not.
These permission requests began as a fairly direct passthrough: A site would ask for some capability and the user agent immediately prompts the user to make a decision for the request. Meanwhile, spam and abuse have forced user agents to take a more opinionated approach to protect users' security, privacy, and attention. The status quo is that users get a multitude of permission requests, where it’s oftentimes unclear to users what the consequences of these requests might be.
This spec introduces a new mechanism that requests and initiates access to powerful features through in-page elements, with built-in protections against abuse. This wants to tie permission requests to the actual context in which they will be used, thus reducing "permission spam" and at the same time providing implementations with a better signal of user intent.
2. Common Behaviours Of The HTML Permission Elements: InPagePermissionMixin
The elements in this specification exhibit a number of common behaviours, which
are captured by the InPagePermissionMixin
and its associated state,
algorithms, and rendering rules.
- Content attributes:
isValid
— query whether the element can currently be activated.invalidReason
— return a string representation of why the element currently cannot be activated.onpromptdismiss
— notifies when the user has dismissed a permission prompt that resulted from an interaction with the elementonpromptaction
— notifies when a permission prompt that resulted from an interaction with the element has been answered by the user (positively or negatively).onvalidationstatuschange
— notifies when the validation status changes.- Accessibility considerations:
- TODO
- DOM interface:
-
interface mixin
{InPagePermissionMixin readonly attribute boolean isValid ;readonly attribute InPagePermissionMixinBlockerReason invalidReason ;readonly attribute PermissionState initialPermissionStatus ;readonly attribute PermissionState permissionStatus ;attribute EventHandler
;onpromptaction attribute EventHandler
;onpromptdismiss attribute EventHandler
; };onvalidationstatuschange
The isValid
attribute reflects whether a the
permission element is not currently blocked.
The invalidReason
attribute is an
enumerated attribute that reflects the internal state of the permission
element. Its value set is InPagePermissionMixinBlockerReason
.
The global lang attribute is observed by the element to select localized text.
The default value
for the global tabindex
content attribute on the
element is 0.
The following are the event handlers (and their corresponding event handler event types) that must be supported on elements that include the InPagePermissionMixin
:
onpromptaction | Event |
---|---|
onpromptdismiss | Event |
onvalidationstatuschange | Event |
2.1. Mixin
internal state
The HTML permission elements represent capabilities gated by user-requestable permissions,
which the user can activate to allow the site to start accessing them.
It is core to the these elements that such requests are
triggered by the user, and not by the page’s script. To enforce
this, the element checks whether the activation event is trusted
. Additionally it watches a number of conditions, like whether the element is
(partially) occluded, or if it has recently been moved. The element maintains
an internal [[BlockerList]]
to keep track of this.
InPagePermissionMixin
elements have the following internal slots:
-
[[Features]]
is null or an ordered set of powerful features. For most permission elements this is likely a fixed set, while for some this may be variable. Making it an internal slot allows us to write algorithms that work for all of them. -
[[InitialPermissionStatus]]
is aPermissionState
that stores the initialPermissionState
for[[Features]]
. -
The
[[BlockerList]]
is a list of records, containing a blocker timestamp and a blocker reason. The blocker reason is aInPagePermissionMixinBlockerReason
, but not the empty string. -
[[IntersectionObserver]]
is a reference to anIntersectionObserver
. -
[[IntersectionRect]]
is aDOMRectReadOnly
that stores the most recently seen intersection, i.e. the position of thepermission
relative to the viewport. -
[[LastNotifiedValidState]]
is a boolean that stores the most recently notified state ofisValid
. -
[[LastNotifiedInvalidReason]]
is a string that stores the most recently notified state ofinvalidReason
.[[LastNotifiedValidState]]
and[[LastNotifiedInvalidReason]]
are used to determine whether anonvalidationstatuschange
event needs to be dispatches.
2.2. Mixin
-supporting state at the navigable
In order to support the InPagePermissionMixin
, the navigable maintains
an ordered set of elements, [[PermissionElements]]
. This ordered set is used to evaluate the blockers of type unsuccesful_registration
.
2.3. Mixin
activation and activation blockers
The key goal of the family of permission elements is to reflect a user’s conscious choice, and we need to make sure the user cannot easily be tricked into activating it. To do so, the permission elements maintain a list of blocker reasons, which may - permanently or temporarily - prevent the element from being activated.
The majority of these behaviours should be identical to all permission elements. For simplicity, we’ll also include blockers that only apply to one or a subset of elements.
enum { // No blocker reason.
InPagePermissionMixinBlockerReason , // Blocker reasons supported by all InPagePermissionMixin users.
"" ,
"illegal_subframe" ,
"unsuccesful_registration" ,
"recently_attached" ,
"intersection_changed" ,
"intersection_out_of_viewport_or_clipped" ,
"intersection_occluded_or_distorted" , // Blocker reason specific to HTMLPermissionElement.
"style_invalid" , };
"type_invalid"
The permission elements keep track of "blockers", reasons why the element (currently) cannot be activated. These blockers come with three lifetimes: Permanent, temporary, and expiring.
- Permanent blocker
-
Once an element has a permanent blocker, it will be disabled permanently. There are used for issues that the website owner is expected to fix. An example is a
permission
element inside afencedframe
. - Temporary blocker
-
This is a blocker that will only be valid until the blocking condition no no longer occurs. An example is a
permission
element that is not currently in view. All temporary blockers turn into expiring blockers once the condition no longer applies. - Expiring blocker
-
This is a blocker that is only valid for a fixed period of time. This is used to block abuse scenarios like "click jacking". An example is a
permission
element that has recently been moved.
Blocker name | Blocker type | Example condition | Order hint |
---|---|---|---|
type_invalid
| permanent | When an unsupported permission type has been
set.
| 1 |
illegal_subframe
| permanent | When the element is used inside a fencedframe .
| 2 |
unsuccesful_registration
| temporary | When too many other elements for the same powerful feature have been inserted into the same document. | 3 |
recently_attached
| expiring | When the element has just been attached to the DOM. | 4 |
intersection_changed
| expiring | When the element is being moved. | 6 |
intersection_out_of_viewport_or_clipped
| temporary | When the element is not or not fully in the viewport. | 7 |
intersection_occluded_or_distorted
| temporary | When the element is fully in the viewport, but still not fully visible (e.g. because it’s partly behind other content). | 8 |
style_invalid
| temporary | 9 |
InPagePermissionMixinBlockerReason
reason and an optional flag expires:
-
Assert: reason is not
""
. (The empty string inInPagePermissionMixinBlockerReason
signals no blocker is present. Why would you add a non-blocking blockern empty string?) -
Let timestamp be None.
-
If expires, then let timestamp be current high resolution time plus the blocker delay.
-
Append an entry to the internal
[[BlockerList]]
with reason and timestamp.
InPagePermissionMixinBlockerReason
reason:
-
Assert: reason is listed as "expiring" in the blocker reason table.
-
Add a blocker with reason and true.
InPagePermissionMixinBlockerReason
reason:
-
Assert: reason is listed as "temporary" in the blocker reason table.
-
Add a blocker with reason and false.
InPagePermissionMixinBlockerReason
reason:
-
Assert: reason is listed as "permanent" in the blocker reason table.
-
Add a blocker with reason and false.
InPagePermissionMixinBlockerReason
reason from an element:
-
Assert: reason is listed as "temporary" in the blocker reason table.
-
For each entry in element’s
[[BlockerList]]
:-
If entry’s reason equals reason, then remove entry from element’s
[[BlockerList]]
.
-
-
Add a blocker with reason and true.
InPagePermissionMixin
element’s
blocker:
-
Let blockers be the result of sorting element’s
[[BlockerList]]
with the blocker ordering algorithm. -
If blockers is not empty and blockers[0] is blocking, then return blockers[0].
-
Return nothing.
-
Let really large number be 99.
-
Assert: No order hint in the blocker reason table is equal to or greater than really large number.
-
If a is blocking, then let a hint be the order hint of a’s reason in the blocker reason table, otherwise let a hint be really large number.
-
If b is blocking, then let b hint be the order hint of b’s reason in the blocker reason table, otherwise let b hint be really large number.
-
Return whether a hint is less than or equal to b hint.
InPagePermissionMixin
’s blocker list’s entry is
blocking if:
-
entry has no blocker timestamp,
-
or entry has a blocker timestamp, and the blocker timestamp is greater or equal to the current high resolution time.
NOTE: The spec maintains blockers as a list [[BlockerList]]
, which may
potentially grow indefinitely (since some blocker types simply expire,
but are not removed).
This structure is chosen for the simplicity of explanation, rather than for
efficiency. The details of this blocker structure are not observable except
for a handful of algorithms defined here, which should open plenty of
opportunities for implementations to handle this more efficiently.
2.4. Mixin
algorithms
InPagePermissionMixin
element’s isValid
getter steps are:
-
Return whether element’s blocker is Nothing.
InPagePermissionMixin
element’s invalidReason
getter steps are:
InPagePermissionMixin
element’s
initialPermissionStatus
getter steps are:
-
Return element’s internal
[[InitialPermissionStatus]]
.
InPagePermissionMixin
element’s
permissionStatus
getter steps are:
-
Return get the current permission state for element.
InPagePermissionMixin
element depends on the
particular element that includes the mixin.
So each element must define its own algorithm.
2.5. Mixin
event algorithms
-
Let oldState be
[[LastNotifiedValidState]]
. -
Let newState be whether element’s blocker is Nothing.
-
Set
[[LastNotifiedValidState]]
to newState. -
Let oldReason be
[[LastNotifiedInvalidReason]]
. -
Let newReason be whether element’s
invalidReason
. -
Set
[[LastNotifiedInvalidReason]]
to newReason. -
If oldState != newState or oldReason != newReason, then:
-
Let event be a new
Event
. -
Initialize event with type "
onvalidationstatuschange
", bubbles true, and cancelable true. -
Dispatch event to element.
-
-
Let event be a new
Event
. -
Initialize event with type "
onpromptaction
", bubbles true, and cancelable true. -
Dispatch event to element.
-
Let event be a new
Event
. -
Initialize event with type "
onpromptdismiss
", bubbles true, and cancelable true. -
Dispatch event to element.
3. Common Rendering, and Styling Restrictions
The permission elements are non-devolvable widget and are chiefly
rendered like a button
. The button label is largely expected to be
determined by the browser, rather than the page, and reflects one or several
of the powerful features listed in [[Features]]
, expressed as text and
icons. The element may also convey information about the current state of
the underlying powerful feature. The actual rendering is defined by each
element.
The page can influence the permission elements' styling, but with
constraints to prevent abuse (e.g. minimum and maximum sizes for fonts and
the label itself). The page can also select a locale for the text via the
lang
attribute.
The permission elements support fallback content, which will be displayed by any browser not yet supporting that element. Note that there are also conditions under which a browser that supports a respective permission element falls back to its fallback content.
3.1. Presentation
There isn’t much precedence for describing the user agent UI in detail. It may be better to leave more freedom to user agents.
The permission elements contains browser-chosen content, text and maybe an icon. Activating them will often prompt the user to choose. This provides two bits of user interface that a user can interact with. The user agent is largely free to determine these — rendering of the element and the subsequent permission prompt — in whichever way it thinks best convey’s the element’s intent.
UI options for the permission elements' presentation include:
-
Name the powerful features listed in
[[Features]]
, in the language indicated by the language of the element. Note that this would always be the language indicated by thelang
attribute, if present. -
An icon indicating the powerful feature type or types.
-
The current permission state of the powerful feature in questions. For example, if the permission is already
granted
, thepermission
element might be labeled as "geolocation already in use". -
A modal prompt with a "scrim". (I.e., darkening out the page behind the prompt.) This would normally quite disruptive. But here our goal is to ensure a user means to make this choice.
User agents are encouraged to name or describe the powerful features in a way that’s consistent with similar usage in program or the platform it is running on.
Very non-normative examples might be:
-
<permission lang="de" types="geolocation">
: "Standort verwenden". -
<permission types="microphone">
(in an English language page): "Use microphone. 🎤". -
Upon activiating
<permission types="microphone">
, when the corresponding permission state isdenied
, modify the text to "Continue blocking".
3.2. Styling
Permission elements constrain the styling that can be applied to them. These constraints come in three flavours:
-
If the condition isn’t met, the element is deactivated.
-
A user-agent defined stylesheet enforces certain styling.
-
The user-agent enforces bounds on additional styles, where the bounds cannot be easily expressed in CSS. For example, if the style bounds are expressed relative to the computed style of the element.
3.2.1. Conditions that Deactivate the Element
If one of these conditions is not met, then a
temporary blocker is added with type
style_invalid
.
'color', 'background-color' |
Set by default to the user agent’s default button colors.
The contrast ratio between the 2 colors needs to be at least 3.
Alpha has to be 1.
|
---|---|
'font-size' |
If specified value is expressed as <relative-size>:
|
3.2.2. User-Agent Defined Stylesheet
A permission element is expected to render with the following styles:
@namespace "http://www.w3.org/1999/xhtml" ; permission, geolocation{ opacity : 1.0 ; line-height : normal !important; whitespace : nowrap !important; user-select : none !important; appearance : auto !important; box-sizing : content-box !important; vertical-align : middle !important; text-emphasis : initial !important; text-shadow : initial !important; }
3.2.3. Additional User-Agent Defined Style Bounds
Permission elements define several bounds on styles. For example, we want the font size are constraints on the The style bounds are explained below.For notational convenience, we imagine that the computed value of an element
could be accessed in CSS rules with computed
, just like the
inherited value of an element can via the inherit
keyword.
Then the following sheet expresses the style bounds:
@namespace "http://www.w3.org/1999/xhtml" ; permission{ outline-offset : clamp ( 0 , computed, none); /* No negative outline-offsets. */ font-weight:clamp ( 200 , computed, none); /* No font-weights below 200. */ word-spacing:clamp ( 0 , computed, 0.5 em ); /* Word-spacing between 0..0.5em */ letter-spacing:clamp ( -0.05 em , commputed, 0.2 em ); /* Letter spacing between -0.05..0.2em */ min-height:clamp ( 1 em , computed, none); max-height : clamp ( none, computed, 3 em ); min-width : clamp ( none, computed, calc ( fit-content)); border-width : clamp ( none, computed, 1 em ); font-style : if ( computed ="normal" or computed ="italic" , computed, "normal" ); display : if( computed ="inline-block" or computed ="none" , computed, "inline-block" ); cursor : if( computed ="pointer" or computed ="not-allowed" , computed, "pointer" ) }
Additionally, some rules apply based on conditions not easily expressible as CSS.
If height is auto
, then apply:
@namespace "http://www.w3.org/1999/xhtml" ; permission{ padding-top : clamp ( 1 em , computed, none); padding-bottom : calc ( padding-top); }
If width is auto
, then apply:
@namespace "http://www.w3.org/1999/xhtml" ; permission{ padding-left : clamp ( none, computed, 5 em ); padding-right : calc ( padding-left); }
Apply the following sheet, if the element does not have all of the following:
-
A border width of at least
1px
, -
a color to background-color contrast ratio of at least 3,
-
and alpha of 1.
@namespace "http://www.w3.org/1999/xhtml" ; permission{ max-width : clamp ( none, computed, calc ( 3 * fit-content)); }
The following CSS properties can be used normally:
-
border and all border shorthand properties, border-top, border-right, border-bottom, border-left
-
flex and its longhands, flex-grow, flex-shrink, flex-basis
-
outline and mostly its longhands, outline-color and outline-style.
Note that outline-offset is clamped by the rules above. -
overscroll-behavior and its longhands, overscroll-behavior-inline, overscroll-behavior-block, overscroll-behavior-x, overscroll-behavior-y
-
scroll-margin and its longhands, scroll-margin-top, scroll-margin-right, scroll-marginbottom', scroll-margin-left
-
scroll-padding and its longhands, scroll-padding-top, scroll-padding-right, scroll-padding-bottom, scroll-padding-left, scroll-padding-inline-start, scroll-padding-block-start, scroll-padding-block-start, scroll-padding-inline-end, scroll-padding-block-end
Properties that are not listed above, or in the rules in this section, and aren’t logically equivalent to one of the properties mentioned here, will be ignored.
3.3. Falling Back
A user agent that does not support a particular permission element would
recognize them as HTMLUnknownElement
and render their children as
regular HTML.
User agents that support such an element should usually
render the element as described in § 3 Common Rendering, and Styling Restrictions, but are still
required to render the fallback content under one condition:
If the internal [[BlockerList]]
contains a record whose
blocker reason is type_invalid
,
then the permission
element should render the fallback content
instead of the permission
’s usual rendering.
4. The permission
Element
Note: The permission
element is the original proposed in-page permission
element, which can work with any powerful feature or feature combinations.
While we do not wish to preempt future standards discussion, we presently
expect that this element will be removed in favour of the more specific
elements detailled in the following chapters.
The permission
element can request arbitrary powerful features.
- Categories:
- Flow content.
- Phrasing content.
- Interactive content.
- Palpable content.
- Phrasing content.
- Contexts in which this element can be used:
- Where phrasing content is expected.
- Content model:
- Flow content.
- Content attributes:
- Global attributes
- Permission elements attributes
type
— Type of permission this element applies to.lang
— Like the global lang attribute. - Permission elements attributes
- Accessibility considerations:
- DOM interface:
HTMLPermissionElement
Add accessibility considerations.
Check attribute & event handler & invalid reason names against current proposal(s).
The permission
element’s content, if any, are its fallback content.
The type
attribute controls the behavior
of the
permission
element when it is activated. Is is an enumerated attribute,
whose values are the names of powerful features. It
has neither a
missing value default state nor a invalid value default state.
The lang
attribute is the same as the
global lang attribute. It is
observed by the permission
element to select localized text.
The default value
for the global tabindex
content attribute on the
permission
element is 0.
[Exposed =Window ]interface :
HTMLPermissionElement HTMLElement { [HTMLConstructor ]constructor (); [CEReactions ,Reflect ]attribute DOMString ;
type static boolean (
isTypeSupported DOMString ); };
type HTMLPermissionElement includes InPagePermissionMixin ;
The type
attribute reflects the type
element attribute.
The isTypeSupported(type)
static operation determines whether a given DOMString
type
,
that is, a given
enumeration of powerful features, is supported.
It predicts whether creating a permission
element and assigning the given
type
string will work, or whether it will create
an element blocked by a type_invalid
permanent blocker.
4.1. permission
element internal state
The permission
element has the same internal slots as the InPagePermissionMixin
, described in § 2.1 Mixin internal state.
4.2. permission
element interesting behaviours
The permission
element has a few surprising behaviours, to support its
security properties:
4.2.1. The type
property
The permission type cannot be modified. Modifying the permission type at will
may lead to user confusion, and hence we’d like to prevent it. Since, however,
a page may create a permission
element dynamically we still need to offer
an API to modify it. To do do, we distinguish between a freshly initialized and
an empty or invalid (no permission) state, where the former allows setting the
type and the latter does not.
Example:
// Changing a valid type: var pepc= document. createElement( "permission" ); pepc. type= "camera" ; // Okay. pepc. type; // "camera". pepc. type= "geolocation" ; // Not okay. Would have been okay as initial assignment. pepc. type; // "camera". Reflects the internal state, which has not changed. // Setting an invalid type: pepc= document. createElement( "permission" ); pepc. type= "icecream" ; // Ice cream is not a powerful browser feature. Not okay. pepc. type; // "". Reflects the internal state. pepc. type= "camera" ; // Still Not okay, because type as already been set. // Would have been okay as initial assignment. pepc. type; // "". Reflects the internal state, which has not changed.
type
getter steps are:
-
If
[[Features]]
is null: Return""
. -
Return a string, containing the concatenation of all powerful feature names in
[[Features]]
, seperated by " ".
type
setter steps are:
-
If
[[Features]]
is not null: Return. -
Set
[[Features]]
to «». -
Let features be the result of calling parse a type string with the input string.
-
If features is None, return.
-
Append each powerful feature name to the
[[Features]]
ordered set. -
Set
[[InitialPermissionStatus]]
to the result of get the current permission state.
Note: The supported sets of powerful features is implementation-defined.
To query whether a feature (or group of features) is supported:
isTypeSupported()
method
steps with argument with DOMString
typeare:
-
Let features be the result of calling parse a type string with type.
-
Return whether features is not None.
-
Let list be the result of parsing type as a string of powerful feature names, seperated by whitespace.
-
If any errors occured, return None.
-
Check if the set of powerful features is supported for the
HTMLPermissionElement
by the user agent. If not, return None. -
Return list.
4.3. permission
element algorithms
HTMLPermissionElement
constructor()
steps are:
-
Initialize the internal
[[Features]]
slot to null. -
Initialize the internal
[[BlockerList]]
to «». -
Initialize the internal
[[LastNotifiedValidState]]
with false. -
Initialize the internal
[[LastNotifiedInvalidReason]]
with the empty string. -
Initialize the internal
[[InitialPermissionStatus]]
to the result of get the current permission state.
HTMLPermissionElement
insertion steps are:
-
If
[[Features]]
is null, set[[Features]]
to «». -
Initialize the internal
[[BlockerList]]
to «». -
Initialize the internal
[[IntersectionRect]]
with undefined. -
Initialize the internal
[[IntersectionObserver]]
with the result of constructing a newIntersectionObserver
with IntersectionObserver callback and «[ "rootMargin
" →"-4px"
]». -
Call
[[IntersectionObserver]]
.observe(this). -
If
[[Features]]
is empty, then add a permanent blocker with reasontype_invalid
. -
If this is not type permissible, then add a temporary blocker with
unsuccesful_registration
. -
Add an expiring blocker with reason
recently_attached
. -
If the traversable navigable of the node navigable of this is a fenced navigable, then add a permanent blocker with
illegal_subframe
.
HTMLPermissionElement
removing steps are:
permission
element’s activation behavior given event is:
-
Assert: element’s
[[Features]]
is not null. -
If element’s
[[Features]]
is empty, then return. -
If event.
isTrusted
is false, then return. -
If element.
isValid
is false, then return. -
Let descriptor be the result of build a permission descriptor for element.
-
Request permission to use the powerful features described by descriptor.
-
If the previous step was cancelled or dismissed by the user, then dispatch onpromptdismiss on this and return.
The [PERMISSIONS] spec assumes that request permission to use will always succeed. That is, it assumes that the user will always make a choice and that the algorithm will always deliver a
grant
/deny
answer corresponding to that choice. But you can’t force a user to do that. Some user agents may have different UI affordances for an explicit denial (e.g. a "deny" button) on one hand, and cancelling or dismissing the request dialog (e.g. an "X" button in the top right corner). Here, we distinguish between these two actions, despite no clear hook for this in the underlying specification.
HTMLPermissionElement
element:
The [Permissions] specification assumes a descriptor describes a
single permission without parameters (like an equivalent of
enableHighAccuracy
). Here, we assume a permissions model
that is more expressive. This needs to be resolved -- likely upstream,
in [Permissions], plus adaptions here.
-
Let result be a new
PermissionDescriptor
. -
Fill in result:
-
Include the powerful feature names contained in element’s
[[Features]]
.
-
-
Return result.
IntersectionObserverCallback
and runs the following steps:
-
Assert: The
IntersectionObserver
’sroot
is the document -
Let entries be the value of the first callback parameter, the list of
intersection observer entries
. -
Let entry be entries’s last item.
-
If entry.
isVisible
, then: -
Otherwise:
-
If entry.
intersectionRatio
>= 1, then:-
Let reason be
intersection_occluded_or_distorted
.
-
-
Otherwise:
-
Let reason be
intersection_out_of_viewport_or_clipped
.
-
-
Add a temporary blocker with reason.
-
-
If
[[IntersectionRect]]
does not equal entry.intersectionRect
then add an expiring blocker withintersection_changed
. -
Set
[[IntersectionRect]]
to entry.intersectionRect
-
Assert: element’s node navigable’s
[[PermissionElements]]
contains element. -
Let count be 0.
-
For each current in element’s node navigable’s
[[PermissionElements]]
:-
If current is element, then break.
-
If element.
[[Features]]
equals current.[[Features]]
then increment count by 1.
-
-
Return whether count is less than 3.
-
For each current in document’s
[[PermissionElements]]
:-
If current is type permissible, then remove blockers with
unsuccesful_registration
from current.
-
HTMLPermissionElement
element:
-
Let types be element’s internal
[[Features]]
. -
Let current be
granted
. -
For each type of types:
-
Let state be the result of get the current permission state for type.
-
Let current be the smaller of current and state, assuming the following ordering:
granted
>prompt
>denied
.
-
-
Return current.
It’s not clear what the PermissionState for 'no valid permission type' should be. Here I pick "prompt" based on Chrome’s implementation; but that choice is arbitrary.
5. The geolocation
Element
The HTML geolocation
element can request access to
"geolocation".
- Categories:
- Flow content.
- Phrasing content.
- Interactive content.
- Palpable content.
- Phrasing content.
- Contexts in which this element can be used:
- Where phrasing content is expected.
- Content model:
- Flow content.
- Content attributes:
- Global attributes.
- Permission elements attributes.
autolocate
— Whether to locate right away (if permission has already been granted).watch
— Wether to read the position once, or watch it continously. - Permission elements attributes.
- Accessibility considerations:
- DOM interface:
HTMLGeolocationElement
The isValid
and
invalidReason
, as well as the global
lang and
tabindex
content attributes, and the
onpromptaction
,
onpromptdismiss
, and
onvalidationstatuschange
event handlers follow the
description in § 2 Common Behaviours Of The HTML Permission Elements: InPagePermissionMixin.
The autolocate
attribute determines
whether the geolocation
element should start locating immediately (if
permission has already been granted).
The watch
attribute determine whether
the geolocation
element report the location once or continously.
[Exposed =Window ]interface :
HTMLGeolocationElement HTMLElement { [HTMLConstructor ]constructor ();readonly attribute GeolocationPosition position ;readonly attribute GeolocationPositionError error ; [CEReactions ,Reflect ]attribute boolean autolocate ; [CEReactions ,Reflect ]attribute boolean watch ;attribute EventHandler onlocation ; };HTMLGeolocationElement includes InPagePermissionMixin ;
If the user has decided to allow access to geolocation information, the
readonly attributes position
and
error
reflect the current
GeolocationPosition
and GeolocationPositionError
values, just like
the PositionCallback
and
PositionErrorCallback
callbacks (respectively) would have returned
If the boolean attribute autolocate
is true,
and if the "geolocation" permission has already been granted by
the user, then the location should be retrieved immediately when the
geolocation
element is attached to the document. If the permission has
not already been granted at insertion time, then this attribute has no effect.
If the boolean attribute watch
is set to true, the onlocation
event is called
every time the position changes, matching the behaviour of watchPosition
.
When a location is available, an Event
is dispatched on the
onlocation
event handler.
When the event is
dispatched, the location, or information about a failure to retrieve the
location, are available in the position
or the
error
attributes. Depending on the
watch
element this happens once (if absent or false),
or continously (if true).
HTMLGeolocationElement
wants to mirror the Geolocation
interface.
There is a direct correspondance:
position | Result of PositionCallback .
|
---|---|
error | Result of PositionErrorCallback .
|
watch | Use watchPosition() .
|
¬ watch | Use getCurrentPosition() .
|
5.1. geolocation
element internal state
The geolocation
element uses all the internal slots from the InPagePermissionMixin
, described in § 2.1 Mixin internal state. Additionally,
geolocation
has the following internal slots:
-
A constant
[[watchIDs]]
, which is used with the request a position algorithm. -
[[position]]
, which contains the most recentGeolocationPosition
. -
[[positionError]]
, which contains the most recentGeolocationPositionError
.
5.2. geolocation
element algorithms
HTMLGeolocationElement
constructor()
steps are:
-
Initialize the internal
[[Features]]
slot to « "geolocation" » -
Initialize the internal
[[BlockerList]]
to «». -
Initialize the internal
[[LastNotifiedValidState]]
with false. -
Initialize the internal
[[LastNotifiedInvalidReason]]
with the empty string. -
Initialize the internal
[[InitialPermissionStatus]]
to the result of get the current permission state. -
Initialize the internal
[[watchIDs]]
to « watchID », where watchID is an implementation-definedunsigned long
that is greater than zero. -
Initialize the internal
[[position]]
to undefined. -
Initialize the internal
[[positionError]]
to undefined.
HTMLGeolocationElement
insertion steps are:
-
Initialize the internal
[[BlockerList]]
to «». -
Initialize the internal
[[IntersectionRect]]
with undefined. -
Initialize the internal
[[IntersectionObserver]]
with the result of constructing a newIntersectionObserver
with IntersectionObserver callback and «[ "rootMargin
" →"-4px"
]». -
Call
[[IntersectionObserver]]
.observe(this). -
If
[[Features]]
is empty, then add a permanent blocker with reasontype_invalid
. -
If this is not type permissible, then add a temporary blocker with
unsuccesful_registration
. -
Add an expiring blocker with reason
recently_attached
. -
If the traversable navigable of the node navigable of this is a fenced navigable, then add a permanent blocker with
illegal_subframe
.
HTMLGeolocationElement
removing steps are:
HTMLGeolocationElement
element’s activation behavior given event is:
-
Assert: element’s
[[Features]]
is not null. -
If element’s
[[Features]]
is empty, then return. -
If event.
isTrusted
is false, then return. -
If element.
isValid
is false, then return. -
Let descriptor be the result of build a permission descriptor for element.
-
Request permission to use the powerful features described by descriptor.
-
If the previous step was cancelled or dismissed by the user, then dispatch onpromptdismiss on this and return.
The [Permissions] spec assumes that request permission to use will always succeed. That is, it assumes that the user will always make a choice and that the algorithm will always deliver a
grant
/deny
answer corresponding to that choice. But you can’t force a user to do that. Some user agents may have different UI affordances for an explicit denial (e.g. a "deny" button) on one hand, and cancelling or dismissing the request dialog (e.g. an "X" button in the top right corner). Here, we distinguish between these two actions, despite no clear hook for this in the underlying specification.
position
getter steps are to return the value
of [[position]]
.
error
getter steps are to return the value of
[[positionError]]
.
-
If get the current permission state is not
granted
, then return. -
If
autolocate
is not true, then return.
-
Let positionCallback be a
PositionCallback
that performs the following steps:-
Set this’s
[[positionError]]
to undefined. -
Set this’s
[[position]]
toPositionCallback
’s position argument.
-
-
Let errorCallback be a
PositionErrorCallback
that performs the following steps:-
Set this’s
[[position]]
to undefined. -
Set this’s
[[positionError]]
toPositionCallback
’s positionError argument.
-
-
Let positionOptions be «[]»
-
Let geolocation be the relevant global object’s
Geolocation
. -
-
Request a position with geolocation, positionCallback, errorCallback, positionOptions, and this’s
[[watchIDs]]
.
-
-
Otherwise:
-
Request a position with geolocation, positionCallback, errorCallback, positionOptions.
-
5.3. geolocation
element event algorithms
-
Let event be a new
Event
. -
Initialize event with
type
"onlocation
". -
Dispatch event to element.
6. Security & Privacy Considerations
Note: Security & Privacy Considerations can be found here & there, in the Explainer. This section will eventually contain a specification-worthy transcription of those Explainer sections.