From 28328321af56e977de76089543d80fcf6d7ece90 Mon Sep 17 00:00:00 2001 From: Luke Warlow Date: Fri, 19 Jul 2024 16:10:50 +0100 Subject: [PATCH] [mediaqueries-5] Migrate Web Preferences API proposal --- mediaqueries-5/Overview.bs | 301 +++++++++++++++++++++++++++++++++++++ 1 file changed, 301 insertions(+) diff --git a/mediaqueries-5/Overview.bs b/mediaqueries-5/Overview.bs index d891b863d065..501727233606 100644 --- a/mediaqueries-5/Overview.bs +++ b/mediaqueries-5/Overview.bs @@ -34,6 +34,7 @@ spec:css-values-4; text: text: type:dfn; text:relative length +spec:dom; type:dfn; text:origin @@ -3216,6 +3217,306 @@ Automatic handling of User Preferences allows for unlimited data or is on a metered plan. +

+Script Control of User Preferences

+ +It is common for website authors to want to respect the user's system preferences while also allowing +those preferences to be overridden. To help with this, this specification defines a way for authors to +override the [[#mf-user-preferences]] using the {{PreferenceManager}} interface. + +This override allows the preference to integrate with various platform features that are affected by these preferences. + +

+Extensions to the {{Navigator}} interface

+ + + +

+{{preferences}} attribute

+ +When getting the {{preferences}} attribute always return the same instance of the {{PreferenceManager}} object. + +### {{PreferenceManager}} interface ### {#preference-manager} + + + +

+{{colorScheme}} attribute

+ +The {{colorScheme}} attribute is a {{PreferenceObject}} used to override the user's preference for the color scheme of the site. +This is modeled after the [[#prefers-color-scheme]]. + +
+ The get valid values for colorScheme algorithm, when invoked, must run these steps: + + 1. Let |validValues| be a new empty [=sequence=]. + 1. Add ''light'' to |validValues|. + 1. Add ''dark'' to |validValues|. + 1. Return |validValues|. +
+ +If an override is set for this preference: +- The user agent MUST use this override for the [[#prefers-color-scheme]] in all stylesheets applied to an [=origin=] including the UA style sheet. +- The user agent MUST also use this override when queried via `matchMedia()` from [[cssom-view#extensions-to-the-window-interface]]. +- The user agent MUST also use this override when calculating the [=used color scheme=]. +- The user agent MUST also use this override when sending [[USER-PREFERENCE-MEDIA-FEATURES-HEADERS#sec-ch-prefers-color-scheme]]. +- The user agent MUST also use this override for any UA features that are normally affected by [[#prefers-color-scheme]]. + +

+{{contrast}} attribute

+ +The {{contrast}} attribute is a {{PreferenceObject}} used to override the user's preference for the contrast of the site. +This is modeled after the [[#prefers-contrast]]. + +
+ The get valid values for contrast algorithm, when invoked, must run these steps: + + 1. Let |validValues| be a new empty [=sequence=]. + 1. Add ''@media/prefers-contrast/more'' to |validValues|. + 1. Add ''@media/prefers-contrast/less'' to |validValues|. + 1. Add ''@media/prefers-contrast/no-preference'' to |validValues|. + 1. Return |validValues|. +
+ +If an override is set for this preference: +- The user agent MUST use this override for the [[#prefers-contrast]] in all stylesheets applied to an [=origin=] including the UA style sheet. +- The user agent MUST also use this override when queried via `matchMedia()` from [[cssom-view#extensions-to-the-window-interface]]. +- The user agent MUST also use this override when sending [[USER-PREFERENCE-MEDIA-FEATURES-HEADERS#sec-ch-prefers-contrast]]. +- The user agent MUST also use this override for any UA features that are normally affected by [[#prefers-contrast]]. + +Note: Unlike the media feature this preference is NOT able to be set to ''@media/prefers-contrast/custom'' as this is tightly coupled to the [[#forced-colors]]. + +

+{{reducedMotion}} attribute

+ +The {{reducedMotion}} attribute is a {{PreferenceObject}} used to override the user's preference for reduced motion on the site. +This is modeled after the [[#prefers-reduced-motion]]. + +
+ The get valid values for reducedMotion algorithm, when invoked, must run these steps: + + 1. Let |validValues| be a new empty [=sequence=]. + 1. Add ''@media/prefers-reduced-motion/reduce'' to |validValues|. + 1. Add ''@media/prefers-reduced-motion/no-preference'' to |validValues|. + 1. Return |validValues|. +
+ +If an override is set for this preference: +- The user agent MUST use this override for the [[#prefers-reduced-motion]] in all stylesheets applied to an [=origin=] including the UA style sheet. +- The user agent MUST also use this override when queried via `matchMedia()` from [[cssom-view#extensions-to-the-window-interface]]. +- The user agent MUST also use this override when sending [[USER-PREFERENCE-MEDIA-FEATURES-HEADERS#sec-ch-prefers-reduced-motion]]. +- The user agent MUST also use this override for any UA features that are normally affected by [[#prefers-reduced-motion]]. + +Note: An example of a UA feature that is affected by this preference could be disabling smooth scrolling, or pausing marquee elements. + +

+{{reducedTransparency}} attribute

+ +The {{reducedTransparency}} attribute is a {{PreferenceObject}} used to override the user's preference for reduced transparency on the site. +This is modeled after the [[#prefers-reduced-transparency]]. + +
+ The get valid values for reducedTransparency algorithm, when invoked, must run these steps: + + 1. Let |validValues| be a new empty [=sequence=]. + 1. Add ''@media/prefers-reduced-transparency/reduce'' to |validValues|. + 1. Add ''@media/prefers-reduced-transparency/no-preference'' to |validValues|. + 1. Return |validValues|. +
+ +If an override is set for this preference: +- The user agent MUST use this override for the [[#prefers-reduced-transparency]] in all stylesheets applied to an [=origin=] including the UA style sheet. +- The user agent MUST also use this override when queried via `matchMedia()` from [[cssom-view#extensions-to-the-window-interface]]. +- The user agent MUST also use this override when sending [[USER-PREFERENCE-MEDIA-FEATURES-HEADERS#sec-ch-prefers-reduced-transparency]]. +- The user agent MUST also use this override for any UA features that are normally affected by [[#prefers-reduced-transparency]]. + +

+{{reducedData}} attribute

+ +The {{reducedData}} attribute is a {{PreferenceObject}} used to override the user's preference for reduced data usage on the site. +This is modeled after the [[#prefers-reduced-data]]. + +
+ The get valid values for reducedData algorithm, when invoked, must run these steps: + + 1. Let |validValues| be a new empty [=sequence=]. + 1. Add ''@media/prefers-reduced-data/reduce'' to |validValues|. + 1. Add ''@media/prefers-reduced-data/no-preference'' to |validValues|. + 1. Return |validValues|. +
+ +If an override is set for this preference: +- The user agent MUST use this override for the [[#prefers-reduced-data]] in all stylesheets applied to an [=origin=] including the UA style sheet. +- The user agent MUST also use this override when queried via `matchMedia()` from [[cssom-view#extensions-to-the-window-interface]]. +- The user agent MUST also use this override when sending [[SAVEDATA#save-data-request-header-field]]. +- The user agent MUST also use this override when calculating the [[SAVEDATA#savedata-attribute]]. +- The user agent MUST also use this override for any UA features that are normally affected by [[#prefers-reduced-data]]. + +

+{{PreferenceObject}} interface

+ + + +
+{{override}} attribute
+ +
+ The override attribute, when accessed, must run these steps: + + 1. Let |preference| be the preference object's name. + 1. Let |override| be null. + 1. If an override for |preference| exists, set |override| to the value of that override. + 1. Return |override|. +
+ +
+{{PreferenceObject/value}} attribute
+ +
+ The value attribute, when accessed, must run these steps: + + 1. Let |preference| be the preference object's name. + 1. Let |value| be null. + 1. If an override for |preference| exists, set |value| to the value of that override. + 1. If |value| is null, set |value| to the UA value of the preference. + 1. Return |value|. +
+ +
+{{validValues}} attribute
+ +
+ The validValues attribute, when accessed, must run these steps: + +
    +
  1. Let |preference| be the preference object's name. + +
  2. Switch on |preference|: +
    +
    "{{colorScheme}}"
    +
    Return the result of [=get valid values for colorScheme=].
    +
    "{{contrast}}"
    +
    Return the result of [=get valid values for contrast=].
    +
    "{{reducedMotion}}"
    +
    Return the result of [=get valid values for reducedMotion=].
    +
    "{{reducedTransparency}}"
    +
    Return the result of [=get valid values for reducedTransparency=].
    +
    "{{reducedData}}"
    +
    Return the result of [=get valid values for reducedData=].
    +
    +
+ +
+{{onchange}} event handler attribute
+ +The onchange attribute is an [=event handler IDL attribute=] for +the {{onchange}} [=event handler=], whose [=event handler event type=] +is change. + +
+Whenever the [=user agent=] is aware that the state of a {{PreferenceObject}} +instance |value| has changed, it runs the {{PreferenceObject}} +update steps: + +1. Let |preference| be the {{PreferenceObject}} object that |value| is associated with. +1. If [=this=]'s [=relevant global object=] is a {{Window}} object, then: + 1. Let |document| be |preference|'s [=relevant global object=]'s [=associated Document=]. + 1. If |document| is null or |document| is not [=Document/fully active=], terminate this algorithm. +1. Fire an event named change at |preference|. + +
+{{requestOverride()}} method
+ +
+ The requestOverride(value) method, when invoked, must run these steps: + + 1. Let |result| be [=a new promise=]. + 1. Let |allowed| be false. + 1. Set |allowed| to the result of executing a UA defined algorithm for deciding whether the request is allowed. + 1. If |allowed| is false, return [=a promise rejected with=] a "{{NotAllowedError}}" {{DOMException}}. + 1. Let |value| be the method's argument. + 1. Let |result| be [=a new promise=]. + 1. If |value| is null or the empty string: + 1. Run {{clearOverride}}. + 1. [=Resolve=] and return |result|. + 1. Let |currentValue| be the preference object's |value|. + 1. Let |validValues| be null. + 1. Switch on |preference|: +
+
"{{colorScheme}}"
+
Set |validValues| to the result of [=get valid values for colorScheme=].
+
"{{contrast}}"
+
Set |validValues| to the result of [=get valid values for contrast=].
+
"{{reducedMotion}}"
+
Set |validValues| to the result of [=get valid values for reducedMotion=].
+
"{{reducedTransparency}}"
+
Set |validValues| to the result of [=get valid values for reducedTransparency=].
+
"{{reducedData}}"
+
Set |validValues| to the result of [=get valid values for reducedData=].
+
+ 1. If |value| is not in |validValues|: + 1. [=Reject=] |result| with a "{{TypeError}}" {{DOMException}}. + 1. Return |result|. + 1. Let |previousOverride| be null. + 1. If an override for |preference| exists, set |previousOverride| to the value of that override. + 1. If |value| is different from |previousOverride|: + 1. Set the preference override for |preference| to |value|. + 1. If |previousOverride| is null, then: + 1. If |value| is the same as |currentValue|, then: + 1. Fire an event named change at [=this=]. + 1. [=Resolve=] and return |result|. +
+ +Issue: This algorithm needs more detail on what exactly setting the preference override does. + +Issue: Is TypeError correct here? + +Note: The `change` event is fired when the computed value changes, but when a new override is set it is also fired if the value hasn't changed. + +
+{{clearOverride()}} method
+ +
+ The clearOverride() method, when invoked, must run these steps: + + 1. Let |preference| be the preference object's name. + 1. Let |override| be null. + 1. If an override for |preference| exists, set |override| to the value of that override. + 1. If |override| is null, then return. + 1. Clear the override for |preference|. + 1. Let |newValue| be the preference object's |value|. + 1. If |newValue| is equal to |override|, then: + 1. Fire an event named change at [=this=]. +
+ +Note: The `change` event is fired when the computed value changes, but when an override is cleared it is also fired if the value hasn't changed. +