Skip to content

[cssom-view-1] Scroll methods in Element and Window return Promises #12355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 60 additions & 34 deletions cssom-view-1/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -420,22 +420,27 @@ an associated element or [=pseudo-element=] <var>element</var> and optionally a
(which is "<code>auto</code>" if omitted),
the following steps must be run:

<ol>
<li><a lt="smooth scroll aborted">Abort</a> any ongoing <a>smooth scroll</a> for <var>box</var>.
<li>If the user agent honors the 'scroll-behavior' property and one of the following are true:
1. <a lt="smooth scroll aborted">Abort</a> any ongoing <a>smooth scroll</a> for <var>box</var>.
1. Resolve any pending promise for <var>box</var> with false.
1. Let <var>scrollPromise</var> be a new promise.
1. Return <var>scrollPromise</var>, and run the remaining steps <a>in parallel</a>.
1. If the user agent honors the 'scroll-behavior' property and one of the following is true:
<ul>
<li><var>behavior</var> is "<code>auto</code>" and <var>element</var> is not null and its computed value of the
'scroll-behavior' property is ''scroll-behavior/smooth''
'scroll-behavior' property is ''scroll-behavior/smooth'', or
<li><var>behavior</var> is <code>smooth</code>
</ul>
...then perform a <a>smooth scroll</a> of <var>box</var> to <var>position</var>. Once the position has finished updating, emit the <a event>scrollend</a> event.
Otherwise, perform an <a>instant scroll</a> of <var>box</var> to <var>position</var>. After an <a>instant scroll</a> emit the <a event>scrollend</a> event.
then perform a <a>smooth scroll</a> of <var>box</var> to <var>position</var>;
otherwise, perform an <a>instant scroll</a> of <var>box</var> to <var>position</var>.
1. Wait until the position has finished updating.
1. If the scroll position changed as a result of this call, emit the <a event>scrollend</a> event.
1. Resolve <var>scrollPromise</var> with true if it is still in the pending state.

Note: <code>behavior: "instant"</code> always performs an <a>instant scroll</a> by this algorithm.

Note: If the scroll position did not change as a result of the user interaction or programmatic invocation, where no translations were applied as a result, then no <a event>scrollend</a> event fires because no scrolling occurred.
</ol>

Issue: What values to use when fulfilling programmatic scroll promises at scroll completion vs interruption? #12355
</div>

<div algorithm="perform a scroll of a viewport">
Expand All @@ -460,8 +465,14 @@ When a user agent is to <dfn for="viewport" export>perform a scroll</dfn> of a <
1. Let <var>element</var> be <var>doc</var>'s root element if there is one, null otherwise.
1. <a for="/">Perform a scroll</a> of the <a>viewport</a>'s <a>scrolling box</a> to its current scroll position + (<var>layout dx</var>, <var>layout dy</var>) with <var>element</var> as the
associated element, and <var>behavior</var> as the scroll behavior.
Let <var>scrollPromise1</var> be the promise returned from this step.
1. <a for="/">Perform a scroll</a> of <var>vv</var>'s <a>scrolling box</a> to its current scroll position + (<var>visual dx</var>, <var>visual dy</var>) with <var>element</var> as the associated
element, and <var>behavior</var> as the scroll behavior.
Let <var>scrollPromise2</var> be the promise returned from this step.
1. If both <var>scrollPromise1</var> and <var>scrollPromise2</var> get resolved with true,
return a promise resolved with true.
Otherwise (either one gets resolved with false or gets rejected)
return a promise resolved with a false.

Note: Conceptually, the visual viewport is scrolled until it "bumps up" against the layout viewport
edge and then "pushes" the layout viewport by applying the scroll delta to the layout viewport.
Expand Down Expand Up @@ -551,12 +562,12 @@ partial interface Window {
[Replaceable] readonly attribute double pageXOffset;
[Replaceable] readonly attribute double scrollY;
[Replaceable] readonly attribute double pageYOffset;
undefined scroll(optional ScrollToOptions options = {});
undefined scroll(unrestricted double x, unrestricted double y);
undefined scrollTo(optional ScrollToOptions options = {});
undefined scrollTo(unrestricted double x, unrestricted double y);
undefined scrollBy(optional ScrollToOptions options = {});
undefined scrollBy(unrestricted double x, unrestricted double y);
Promise<undefined> scroll(optional ScrollToOptions options = {});
Promise<undefined> scroll(unrestricted double x, unrestricted double y);
Promise<undefined> scrollTo(optional ScrollToOptions options = {});
Promise<undefined> scrollTo(unrestricted double x, unrestricted double y);
Promise<undefined> scrollBy(optional ScrollToOptions options = {});
Promise<undefined> scrollBy(unrestricted double x, unrestricted double y);

// client
[Replaceable] readonly attribute long screenX;
Expand Down Expand Up @@ -669,7 +680,7 @@ steps must be run:
1. Let <var>options</var> be null <a lt="converted to an IDL value">converted</a> to a {{ScrollToOptions}} dictionary. [[!WEBIDL]]
1. Let <var>x</var> and <var>y</var> be the arguments, respectively.
1. <a>Normalize non-finite values</a> for <var>x</var> and <var>y</var>.
1. If there is no <a>viewport</a>, abort these steps.
1. If there is no <a>viewport</a>, return a promise resolved with false and abort the remaining steps.
1. Let <var>viewport width</var> be the width of the <a>viewport</a> excluding the width of the scroll bar, if any.
1. Let <var>viewport height</var> be the height of the <a>viewport</a> excluding the height of the scroll bar, if any.
1.
Expand All @@ -694,11 +705,13 @@ steps must be run:
and aligning the y-coordinate <var>y</var> of the <a>viewport</a> <a>scrolling area</a>
with the top of the <a>viewport</a>.
1. If <var>position</var> is the same as the <a>viewport’s</a> current scroll position,
and the <a>viewport</a> does not have an ongoing <a>smooth scroll</a>, abort these steps.
and the <a>viewport</a> does not have an ongoing <a>smooth scroll</a>, return a promise resolved with false and abort the remaining steps.
1. Let <var>document</var> be the <a>viewport’s</a> associated {{Document}}.
1. <a for="viewport">Perform a scroll</a> of the <a>viewport</a> to <var>position</var>,
<var>document</var>'s [=root element=] as the associated element, if there is one, or null otherwise,
and the scroll behavior being the value of the {{ScrollOptions/behavior}} dictionary member of <var>options</var>.
Let <var>scrollPromise</var> be the promise returned from this step.
1. Return <var>scrollPromise</var>.

Issue: User agents do not agree whether this uses the (coordinated) <a>viewport</a> <a for="viewport">perform a scroll</a> or the
<a>scrolling box</a> <a for="/">perform a scroll</a> on the layout viewport's scrolling box.
Expand All @@ -717,7 +730,7 @@ user agent must run these steps:
1. <a>Normalize non-finite values</a> for the {{ScrollToOptions/left}} and {{ScrollToOptions/top}} dictionary members of <var>options</var>.
1. Add the value of {{scrollX}} to the {{ScrollToOptions/left}} dictionary member.
1. Add the value of {{scrollY}} to the {{ScrollToOptions/top}} dictionary member.
1. Act as if the {{Window/scroll()}} method was invoked with <var>options</var> as the only argument.
1. Return the promise returned from {{Window/scroll()}} after the method is invoked with <var>options</var> as the only argument.

The <dfn attribute for=Window>screenX</dfn> and <dfn attribute for=Window>screenLeft</dfn> attributes must return the x-coordinate,
relative to the origin of the <a>Web-exposed screen area</a>, of the left of
Expand Down Expand Up @@ -1185,13 +1198,13 @@ partial interface Element {

boolean checkVisibility(optional CheckVisibilityOptions options = {});

undefined scrollIntoView(optional (boolean or ScrollIntoViewOptions) arg = {});
undefined scroll(optional ScrollToOptions options = {});
undefined scroll(unrestricted double x, unrestricted double y);
undefined scrollTo(optional ScrollToOptions options = {});
undefined scrollTo(unrestricted double x, unrestricted double y);
undefined scrollBy(optional ScrollToOptions options = {});
undefined scrollBy(unrestricted double x, unrestricted double y);
Promise<undefined> scrollIntoView(optional (boolean or ScrollIntoViewOptions) arg = {});
Promise<undefined> scroll(optional ScrollToOptions options = {});
Promise<undefined> scroll(unrestricted double x, unrestricted double y);
Promise<undefined> scrollTo(optional ScrollToOptions options = {});
Promise<undefined> scrollTo(unrestricted double x, unrestricted double y);
Promise<undefined> scrollBy(optional ScrollToOptions options = {});
Promise<undefined> scrollBy(unrestricted double x, unrestricted double y);
attribute unrestricted double scrollTop;
attribute unrestricted double scrollLeft;
readonly attribute long scrollWidth;
Expand Down Expand Up @@ -1304,10 +1317,12 @@ The <dfn method for=Element caniuse=scrollintoview>scrollIntoView(<var>arg</var>
1. Otherwise, if <var>arg</var> is false, then set <var>block</var> to "<code>end</code>".
1. If the element does not have any associated [=CSS/box=],
or is not available to user-agent features,
then return.
then return a promise resolved with false.
1. <a lt='scroll a target into view'>Scroll the element into view</a>
with <var>behavior</var>, <var>block</var>, <var>inline</var>, and <var>container</var>.
Let <var>scrollPromise</var> be the promise returned from this step
1. Optionally perform some other action that brings the element to the user's attention.
1. Return <var>scrollPromise</var>.

The <dfn method for=Element lt="scroll(options)|scroll(x, y)">scroll()</dfn> method must run these steps:

Expand All @@ -1323,23 +1338,24 @@ The <dfn method for=Element lt="scroll(options)|scroll(x, y)">scroll()</dfn> met
1. Let the {{ScrollToOptions/left}} dictionary member of <var>options</var> have the value <var>x</var>.
1. Let the {{ScrollToOptions/top}} dictionary member of <var>options</var> have the value <var>y</var>.
1. Let <var>document</var> be the element's <a>node document</a>.
1. If <var>document</var> is not the <a>active document</a>, terminate these steps.
1. If <var>document</var> is not the <a>active document</a>, return a promise resolved with false and abort the remaining steps.
1. Let <var>window</var> be the value of <var>document</var>'s {{Document/defaultView}} attribute.
1. If <var>window</var> is null, terminate these steps.
1. If the element is the [=root element=] and <var>document</var> is in <a>quirks mode</a>, terminate these steps.
1. If the element is the [=root element=] invoke {{Window/scroll()}} on <var>window</var> with {{Window/scrollX}} on <var>window</var> as first argument and <var>y</var> as second argument,
and terminate these steps.
1. If <var>window</var> is null, return a promise resolved with false and abort the remaining steps.
1. If the element is the [=root element=] and <var>document</var> is in <a>quirks mode</a>, return a promise resolved with false and abort the remaining steps.
1. If the element is the [=root element=], return the promise returned by {{Window/scroll()}} on <var>window</var> after the method is invoked with
{{Window/scrollX}} on <var>window</var> as first argument and <var>y</var> as second argument, and abort the remaining steps.
1. If the element is <a>the <code>body</code> element</a>,
<var>document</var> is in <a>quirks mode</a>,
and the element is not <a>potentially scrollable</a>,
invoke {{Window/scroll()}} on <var>window</var> with <var>options</var> as the only argument,
and terminate these steps.
return the promise returned by {{Window/scroll()}} on <var>window</var> after the method is invoked with
<var>options</var> as the only argument, and abort the remaining steps.
1. If the element does not have any associated [=CSS/box=],
the element has no associated <a>scrolling box</a>,
or the element has no overflow,
terminate these steps.
return a promise resolved with false and abort the remaining steps.
1. <a lt='scroll an element'>Scroll the element</a> to <var>x</var>,<var>y</var>,
with the scroll behavior being the value of the {{ScrollOptions/behavior}} dictionary member of <var>options</var>.
with the scroll behavior being the value of the {{ScrollOptions/behavior}} dictionary member of <var>options</var>. Let <var>scrollPromise</var> be the promise returned from this step.
1. Return <var>scrollPromise</var>.

When the <dfn method for=Element lt="scrollTo(options)|scrollTo(x, y)">scrollTo()</dfn> method is invoked, the
user agent must act as if the {{Element/scroll()}} method was invoked with the same arguments.
Expand All @@ -1358,7 +1374,7 @@ user agent must run these steps:
1. Let the {{ScrollToOptions/top}} dictionary member of <var>options</var> have the value <var>y</var>.
1. Add the value of {{Element/scrollLeft}} to the {{ScrollToOptions/left}} dictionary member.
1. Add the value of {{Element/scrollTop}} to the {{ScrollToOptions/top}} dictionary member.
1. Act as if the {{Element/scroll()}} method was invoked with <var>options</var> as the only argument.
1. Return the promise returned by {{Element/scroll()}} after the method is invoked with <var>options</var> as the only argument.

The <dfn attribute for=Element>scrollTop</dfn> attribute, on getting, must return the result of running these steps:

Expand Down Expand Up @@ -1527,6 +1543,7 @@ an inline base direction position <var>inline</var>,
and an optional containing <a>Element</a> to stop scrolling after reaching <var>container</var>,
means to run these steps:

1. Let <var>ancestorPromises</var> be an empty set of promises.
1. For each ancestor element or <a>viewport</a> that establishes a <a>scrolling box</a> <var>scrolling box</var>,
in order of innermost to outermost <a>scrolling box</a>, run these substeps:
1. If the {{Document}} associated with <var>target</var> is not <a>same origin</a> with the {{Document}} associated with the element or <a>viewport</a> associated with <var>scrolling box</var>, terminate these steps.
Expand All @@ -1538,15 +1555,22 @@ means to run these steps:
<dd>
<a for="/">Perform a scroll</a> of the element's <var>scrolling box</var> to <var>position</var>, with the element as the associated element and
<var>behavior</var> as the scroll behavior.
Add the promise retured from this step in the set <var>ancestorPromises</var>.
<dt>If <var>scrolling box</var> is associated with a <a>viewport</a>
<dd>
1. Let <var>document</var> be the <a>viewport’s</a> associated {{Document}}.
1. Let <var>root element</var> be <var>document</var>'s [=root element=], if there is one, or null otherwise.
1. <a for="viewport">Perform a scroll</a> of the <a>viewport</a> to <var>position</var>, with <var>root element</var> as the associated element and <var>behavior</var>
as the scroll behavior.
Add the promise retured from this step in the set <var>ancestorPromises</var>.
</dl>
1. If <var>container</var> is not null and <var>scrolling box</var> is a [=shadow-including inclusive ancestor=] of <var>container</var>,
abort the rest of these steps.
1. If all promises in <var>ancestorPromises</var> get resolved with true,
return a promise resolved with true.
Otherwise (any of the promises gets resolved with false or gets rejected)
return a promise resolved with a false.


</div>

Expand All @@ -1572,6 +1596,8 @@ To <dfn>scroll an element</dfn> (or [=pseudo-element=]) <var>element</var> to <v
1. Let <var>position</var> be the scroll position <var>box</var> would have by aligning <a>scrolling area</a> x-coordinate <var>x</var> with the left of <var>box</var> and aligning <a>scrolling area</a> y-coordinate <var>y</var> with the top of <var>box</var>.
1. If <var>position</var> is the same as <var>box</var>'s current scroll position, and <var>box</var> does not have an ongoing <a>smooth scroll</a>, abort these steps.
1. <a for="/">Perform a scroll</a> of <var>box</var> to <var>position</var>, <var>element</var> as the associated element and <var>behavior</var> as the scroll behavior.
Let <var>scrollPromise</var> be the promise returned from this step.
1. Return <var>scrollPromise</var>.

</div>

Expand Down