-
Notifications
You must be signed in to change notification settings - Fork 26
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
Replace transitionWhile()/canTransition with intercept()/canIntercept #235
Conversation
Previously, we were setting an entry's serialized state as part of the end of the navigate() call. This will work less well after #235; there, we need to set the state right after the commit, but before any handlers are called. So most of this patch is just a for-now-editorial rearrangement, to set the serialized state in a different place in the spec (but observably the same given the current API). One part of this includes rearranging things so that if options["state"] is not given to reload() or navigate(), we now pass through the serialization of undefined, instead of passing through null. This allows null to be used as a sentinel for traverse cases. This change is also not observable, since getState() would turn null into undefined.
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that insetad of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Bug: 1183545 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that insetad of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that insetad of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Just one optional nitpick.
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
Previously, we were setting an entry's serialized state as part of the end of the navigate() call. This will work less well after #235; there, we need to set the state right after the commit, but before any handlers are called. So most of this patch is just a for-now-editorial rearrangement, to set the serialized state in a different place in the spec (but observably the same given the current API). One part of this includes rearranging things so that if options["state"] is not given to reload() or navigate(), we now pass through the serialization of undefined, instead of passing through null. This allows null to be used as a sentinel for traverse cases. This change is also not observable, since getState() would turn null into undefined.
bc7ffa3
to
e057298
Compare
I know I caused a lot of trouble by whinging about this late in the process, but I'm really grateful that this change happened. I'm giving a talk on this later, and this API makes it so much easier to explain (especially as I'm talking about page transitions in the same talk). |
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/jyWqjAEv5LU Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/jyWqjAEv5LU Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/jyWqjAEv5LU Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/jyWqjAEv5LU Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/jyWqjAEv5LU Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3688177 Reviewed-by: Chris Harrelson <chrishtr@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Reviewed-by: Domenic Denicola <domenic@chromium.org> Cr-Commit-Position: refs/heads/main@{#1026325}
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/jyWqjAEv5LU Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3688177 Reviewed-by: Chris Harrelson <chrishtr@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Reviewed-by: Domenic Denicola <domenic@chromium.org> Cr-Commit-Position: refs/heads/main@{#1026325}
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/jyWqjAEv5LU Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3688177 Reviewed-by: Chris Harrelson <chrishtr@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Reviewed-by: Domenic Denicola <domenic@chromium.org> Cr-Commit-Position: refs/heads/main@{#1026325}
…navigateEvent.canIntercept, a=testonly Automatic update from web-platform-tests Implement navigateEvent.intercept() and navigateEvent.canIntercept Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/jyWqjAEv5LU Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3688177 Reviewed-by: Chris Harrelson <chrishtr@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Reviewed-by: Domenic Denicola <domenic@chromium.org> Cr-Commit-Position: refs/heads/main@{#1026325} -- wpt-commits: 5f0779f40dbb30349778db64db04754df8c4a4ef wpt-pr: 34353
…navigateEvent.canIntercept, a=testonly Automatic update from web-platform-tests Implement navigateEvent.intercept() and navigateEvent.canIntercept Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/jyWqjAEv5LU Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3688177 Reviewed-by: Chris Harrelson <chrishtr@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Reviewed-by: Domenic Denicola <domenic@chromium.org> Cr-Commit-Position: refs/heads/main@{#1026325} -- wpt-commits: 5f0779f40dbb30349778db64db04754df8c4a4ef wpt-pr: 34353
Follows WICG/navigation-api#235 intercept() works very similarly to transitionWhile(), except that instead of taking a mandatory Promise, it takes an optional handler function. If a function is provided and it returns a promise, navigation finish will be delayed until the Promise resolve, just as transitionWhile() delays navigation finish for its Promise. canIntercept is identical to canTransition. Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/jyWqjAEv5LU Bug: 1336000 Change-Id: I94edd7fdc727080594f16fe4511cb7c302d88941 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3688177 Reviewed-by: Chris Harrelson <chrishtr@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Reviewed-by: Domenic Denicola <domenic@chromium.org> Cr-Commit-Position: refs/heads/main@{#1026325} NOKEYCHECK=True GitOrigin-RevId: d53817e29d5e857782ff8d977dbc3b89eb53831b
Fixes #230. Mini-explainer:
The
"navigate"
event provided by the navigation API has a method on itsNavigateEvent
instance,event.transitionWhile(promise, options)
. This method would intercept the navigation, convert it into a same-document navigation, and then use the provided promise to signal to the browser and to other parts of the web application that we were in a transitional phase while the new navigation finishes up.However, the signature of
transitionWhile(promise)
worked poorly in practice. The most important reason is the common coding pattern of:i.e., the common pattern of generating a promise via an immediately-invoked async function. The problem with this pattern is that it's equivalent to
This means some portion of your "navigation handling code" would run, before the
navigate
event had finished firing and the URL/entry had been updated.We know of at least two bad examples of this:
When you synchronously modify the DOM. This throws off scroll restoration logic, as discussed in transitionWhile doesn't quite work for scroll restoration #230 (with detail at transitionWhile doesn't quite work for scroll restoration #230 (comment)). Because the sync code is modifying the DOM of the starting entry, not the destination entry.
When you are trying to create a redirect. See First-class "client-side redirect" support #124 (comment). If you can synchronously determine you want to redirect, you need to do one behavior (canceling the current navigation, then starting a new one), whereas if you need to use async logic, then you need to do another behavior (replacing the current page). We proposed creating a first-class
navigation.transition.redirect()
helper to abstract this logic, but it's not a great sign that we'd need to create such a helper in the first place.Our solution is to replace
transitionWhile(promise, options)
withintercept({ handler, ...options })
. Essentially, we are replacing the idea of you passing a promise---which people would often generate with an async function---with the idea of you passing an async function directly. Then, the user agent can be sure to schedule the entirety of the async function after thenavigate
event has finished firing, and the URL/entry updated. This avoids the above problems.This particular API shape has other minor benefits:
Code such as
hid some fairly-important information (the
focusReset: "manual"
) down at the bottom. With the new structure, we can instead writeIt is common in applications that are just starting to use the navigation API, and are not yet ready to centralize their routing logic into the
"navigate"
event handler, to simply want to intercept the navigation and convert it into a navigation-API-handled one, but leave the rest of their application as the one that reacts to this navigation. Previously this would requirewhich felt like a hack. ("I want to transition, while an already-fulfilled promise is outstanding"!?) Now it is simply
which communicates the intent better.
The immediately-invoked async function pattern was ugly. So ugly we were contemplating JavaScript language and Web IDL-level changes to get rid of it. See Maybe allow respondWith to take a promise-returning function? #40 and Allow functions to be used as promise inputs whatwg/webidl#1020. These changes are now not necessary, at least for our API.
This change slightly reduces (but does not fully remove) the confusion between the navigation API's notion of a navigation transition, and the in-progress shared element transitions spec's idea of a navigation transition. See Naming clash with navigation API view-transitions#143. The reason it does not eliminate it is that
navigation.transition
still exists. (We may settle this by renamingnavigation.transition
; see transitionWhile doesn't quite work for scroll restoration #230 (comment).)Preview | Diff