Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Mon, Jul 13, 2015 at 5:56 PM, Majid Valipour maji...@google.com wrote: On Mon, Jul 13, 2015 at 10:55 AM Philip Jägenstedt phil...@opera.com If the StateOptions interface could be implemented with no internal reference back to its owning History object it seems pretty harmless, a mere holder of values, I think a reference to History may be needed because changing scrollState needs to update current entry with the new effective value. So it is not a simple value holder. I somewhat suspected that, and it would make StateOptions a tear-off from History, and tear-offs are a bit annoying IMHO :) Philip
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Sun, Jul 12, 2015 at 1:51 PM Anne van Kesteren ann...@annevk.nl wrote: On Sun, Jul 12, 2015 at 7:49 PM, Jonas Sicking jo...@sicking.cc wrote: I think we've already made that assumption given that history.state already relies on this. Good point. I'm still somewhat skeptical of introducing new objects just for the purpose of grouping some properties if they don't serve a purpose on their own. It is only used as way to group properties (perhaps similar to ValidityState?) and to keep History interface clean and stack-like. If that is not valuable enough to introduce a new interface then putting these on the History interface is fine. Majid
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Mon, Jul 13, 2015 at 3:58 PM, Majid Valipour maji...@chromium.org wrote: It is only used as way to group properties (perhaps similar to ValidityState?) and to keep History interface clean and stack-like. If that is not valuable enough to introduce a new interface then putting these on the History interface is fine. I personally prefer flatter structures, but you're correct that there's precedent for both and given a 1:1 relationship without setter it does seem rather harmless. -- https://annevankesteren.nl/
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Mon, Jul 13, 2015 at 4:26 PM, Anne van Kesteren ann...@annevk.nl wrote: On Mon, Jul 13, 2015 at 3:58 PM, Majid Valipour maji...@chromium.org wrote: It is only used as way to group properties (perhaps similar to ValidityState?) and to keep History interface clean and stack-like. If that is not valuable enough to introduce a new interface then putting these on the History interface is fine. I personally prefer flatter structures, but you're correct that there's precedent for both and given a 1:1 relationship without setter it does seem rather harmless. FWIW, I also think that just history.scrollRestoration would be fine, better even. Given the generic name options, any future additions to it would still have the same names as if they're added directly to the History interface, I'm guessing. If the StateOptions interface could be implemented with no internal reference back to its owning History object it seems pretty harmless, a mere holder of values, but it'll look pretty weird if no additions are actually made to it in the future. Philip
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Fri, Jul 10, 2015 at 1:54 PM, Majid Valipour maji...@chromium.org wrote: On Mon, Jun 29, 2015 at 5:20 PM Jonas Sicking jo...@sicking.cc wrote: FWIW I still prefer an API like history.scrollRestoration = 'manual'; The main reason is that it seems to me that pushState/replaceState has a largely orthogonal set of use cases that it tries to address from scroll restoration. So I suspect that grouping the two together will create awkwardness in the API in the future. But I don't have time to chase this issue. / Jonas Jonas, After some offline discussion with Rick, we have decided to converge to your preferred API. I hope this addresses your concern about potential future awkwardness and help make adoption easier. I have updated the proposed spec to reflect this change. The semantic of history.options.scrollRestoration is based on our previous discussion in this thread [1]. It short, it does not change any previous entries and navigating across documents resets its value so it only applies to entries created for the same document. Minor bikeshed: I have put scrollRestoration on history.options instead of directly history itself in order to use history.options as an interface to contain any other restoration related attributes which have similar semantics (e.g., recorder scroll position, scale restoration, recorded scale). Thanks Majid! This sounds great! / Jonas
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Sun, Jul 12, 2015 at 7:49 PM, Jonas Sicking jo...@sicking.cc wrote: I think we've already made that assumption given that history.state already relies on this. Good point. I'm still somewhat skeptical of introducing new objects just for the purpose of grouping some properties if they don't serve a purpose on their own. -- https://annevankesteren.nl/
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Sat, Jul 11, 2015 at 10:51 AM, Anne van Kesteren ann...@annevk.nl wrote: On Fri, Jul 10, 2015 at 10:54 PM, Majid Valipour maji...@chromium.org wrote: Minor bikeshed: I have put scrollRestoration on history.options instead of directly history itself in order to use history.options as an interface to contain any other restoration related attributes which have similar semantics (e.g., recorder scroll position, scale restoration, recorded scale). Is the History object Document-bound in all implementations? Otherwise adding new dependent objects will be problematic security-wise. I think we've already made that assumption given that history.state already relies on this. / Jonas
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Fri, Jul 10, 2015 at 10:54 PM, Majid Valipour maji...@chromium.org wrote: Minor bikeshed: I have put scrollRestoration on history.options instead of directly history itself in order to use history.options as an interface to contain any other restoration related attributes which have similar semantics (e.g., recorder scroll position, scale restoration, recorded scale). Is the History object Document-bound in all implementations? Otherwise adding new dependent objects will be problematic security-wise. Also, History isn't that full and can easily contain a bunch of properties. What's the use of a new object, can you use it independently somehow? -- https://annevankesteren.nl/
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Mon, Jun 29, 2015 at 5:20 PM Jonas Sicking jo...@sicking.cc wrote: FWIW I still prefer an API like history.scrollRestoration = 'manual'; The main reason is that it seems to me that pushState/replaceState has a largely orthogonal set of use cases that it tries to address from scroll restoration. So I suspect that grouping the two together will create awkwardness in the API in the future. But I don't have time to chase this issue. / Jonas Jonas, After some offline discussion with Rick, we have decided to converge to your preferred API. I hope this addresses your concern about potential future awkwardness and help make adoption easier. I have updated the proposed spec http://majido.github.io/scroll-restoration-proposal/history-based-api.html to reflect this change. The semantic of history.options.scrollRestoration is based on our previous discussion in this thread [1]. It short, it does not change any previous entries and navigating across documents resets its value so it only applies to entries created for the same document. Minor bikeshed: I have put scrollRestoration on history.options instead of directly history itself in order to use history.options as an interface to contain any other restoration related attributes which have similar semantics (e.g., recorder scroll position, scale restoration, recorded scale). Majid [1] https://lists.w3.org/Archives/Public/public-whatwg-archive/2015Apr/0123.html
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Wed, May 20, 2015 at 11:00 AM Majid Valipour maji...@chromium.org wrote: It will be great if we could make progress on getting a consensus on the API so that we can actually ship this feature. I think we have narrowed it down to two main options: 1- Setting scroll options using history.{push, replace}State. This is what we have implemented in chrome (see IDLs above). history.replaceState(history.state, '','', {scrollRestoration: 'manual'}) 2- Setting scroll options directly on history object. This is what Jonas has proposed. Per our earlier discussions in this thread it should be possible to define the semantics such that we get per-entry control. history.options.scrollRestoration = 'manual' Both are equally powerful with #1 being better for complex situations where different entries may need to have different scroll restoration behaviour and #2 being better for simpler case where the application wants the same scroll restoration for all its entries. As an experiment, I have created a small script https://gist.github.com/majido/4cbd0b68d742de319aeb#file-scroll-restoration-global-flag-js that implements #2 on top of #1. Jonas prefers #2. I am partial to #1. Spec editors (Anne, Ian, Simon, Robin): Do you have a preference here? Anne, Ian, Simon, Robin, Do you have a preference one way or another for either of the above APIs? I have a git repo https://github.com/majido/scroll-restoration-proposal where I have spec'd the first option http://majido.github.io/scroll-restoration-proposal/history-based-api.html (as implemented in Chromium) and am tracking issues against it. Unless there is a strong preference against #1, I feel it is reasonable to try to ship it. Majid
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Mon, Jun 29, 2015 at 5:14 PM, Majid Valipour maji...@chromium.org wrote: Do you have a preference one way or another for either of the above APIs? Not really. The fact that history and navigation is not really cross-browser makes me a bit wary about extending it further, since we obviously don't really understand the primitives well, but I don't have the bandwidth to tackle that at the moment. -- https://annevankesteren.nl/
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
FWIW I still prefer an API like history.scrollRestoration = 'manual'; The main reason is that it seems to me that pushState/replaceState has a largely orthogonal set of use cases that it tries to address from scroll restoration. So I suspect that grouping the two together will create awkwardness in the API in the future. But I don't have time to chase this issue. / Jonas On Mon, Jun 29, 2015 at 8:14 AM, Majid Valipour maji...@chromium.org wrote: On Wed, May 20, 2015 at 11:00 AM Majid Valipour maji...@chromium.org wrote: It will be great if we could make progress on getting a consensus on the API so that we can actually ship this feature. I think we have narrowed it down to two main options: 1- Setting scroll options using history.{push, replace}State. This is what we have implemented in chrome (see IDLs above). history.replaceState(history.state, '','', {scrollRestoration: 'manual'}) 2- Setting scroll options directly on history object. This is what Jonas has proposed. Per our earlier discussions in this thread it should be possible to define the semantics such that we get per-entry control. history.options.scrollRestoration = 'manual' Both are equally powerful with #1 being better for complex situations where different entries may need to have different scroll restoration behaviour and #2 being better for simpler case where the application wants the same scroll restoration for all its entries. As an experiment, I have created a small script that implements #2 on top of #1. Jonas prefers #2. I am partial to #1. Spec editors (Anne, Ian, Simon, Robin): Do you have a preference here? Anne, Ian, Simon, Robin, Do you have a preference one way or another for either of the above APIs? I have a git repo where I have spec'd the first option (as implemented in Chromium) and am tracking issues against it. Unless there is a strong preference against #1, I feel it is reasonable to try to ship it. Majid
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
Hi all, I wanted to give you an update on the progress. I have implemented this in Chromium in version 44 behind a runtime enabled experimental feature flag chrome://flags/#enable-experimental-web-platform-features. Here are the relevant IDL files for the API: - StateOptions.idl https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/core/frame/StateOptions.idlq=StateOptions.idlsq=package:chromiumtype=cs - History.idl https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/core/frame/History.idlq=History.idlsq=package:chromiumtype=cs It will be great if we could make progress on getting a consensus on the API so that we can actually ship this feature. I think we have narrowed it down to two main options: 1- Setting scroll options using history.{push, replace}State. This is what we have implemented in chrome (see IDLs above). history.replaceState(history.state, '','', {scrollRestoration: 'manual'}) 2- Setting scroll options directly on history object. This is what Jonas has proposed. Per our earlier discussions in this thread it should be possible to define the semantics such that we get per-entry control. history.options.scrollRestoration = 'manual' Both are equally powerful with #1 being better for complex situations where different entries may need to have different scroll restoration behaviour and #2 being better for simpler case where the application wants the same scroll restoration for all its entries. As an experiment, I have created a small script https://gist.github.com/majido/4cbd0b68d742de319aeb#file-scroll-restoration-global-flag-js that implements #2 on top of #1. Jonas prefers #2. I am partial to #1. Spec editors (Anne, Ian, Simon, Robin): Do you have a preference here? As a side note, I think it is possible to combine both these in a single API. I just don't feel if the benefit is large enough to justify the added complexity. Simply take #1 and remove readonly limitation from 'history.options' and make it the effective default options value for the page (with the semantic we discussed earlier). Both pushState and replaceState will continue to take an optional options parameter that can overrides values set in history.options. Regards Majid
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Thu, Apr 9, 2015 at 3:05 PM Ian Hickson i...@hixie.ch wrote: Also, I'd recommend an option name that suggests more strongly that the author is expected to restore the position themselves, rather than just that the position shouldn't be restored. For example, calling it something like willRestoreScrollPosition (defaulting to false, meaning the UA should do it). How about: enum ScrollRestoration { 'auto', 'manual'}; defaulting to 'auto' meaning UA should do it. I think 'manual' and 'auto' work better here. I was trying to use 'willRestoreScroll' but it is confusing as it does not convey who will restore the scroll position. auto|manual makes this clear and the advantage of enum is that we can add other values in future too if needed. Majid
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Tue, Apr 28, 2015 at 3:24 PM Jonas Sicking jo...@sicking.cc wrote: On Tue, Apr 28, 2015 at 9:16 AM, Majid Valipour maji...@google.com wrote: On Mon, Apr 27, 2015 at 9:54 PM Jonas Sicking jo...@sicking.cc wrote: Jumping in at the end here. As I've said before, I like the general idea of giving pages more control over scroll restoration, but I don't think we should tie this to pushState()/replaceState()/onscroll. My proposal is instead that we add an API like history.restoreScroll = boolean; Interesting. I believe Simon has also proposed a similar API for which you can find my original objections here. One of my objections was that any proposed API should give developers control of scroll restoration per individual history entry. Initially I assumed a single boolean flag cannot provide that control but now I believe what you are proposing here can in fact provide per-entry control. More on this later. My other objection was that because scroll restoration behaviour is ultimately tied to a specific history entry, the API to control it should reflect this underlying fact. IMO a flag on history object hides this fact while original proposal does not. I understand that for pages that do not create any state other than their default initial state (e.g., infinite scrollers) setting history.restoreScroll is simpler than using history.replaceState({restorScroll: false}). But I think this additional complexity is not prohibitive and can be justified when the upside is an API that better explains the underlying behaviour and is simpler for pages that do create multiple states using history.pushState. I agree that the difference between history.restoreScroll = false; and history.replaceState({restoreScroll: false}); is not that big and mainly comes down to taste. I like the former more. I agree it comes down to taste. In fact there are three API proposed: 1. Using a fourth optional dictionary parameter on {push|replace}State: backward compatible and consistent. 2. New history.push, history.replace methods accepting a bool flag: cleaner API that allows us to clean minor old warts such as making 'url' required and 'title' optional (or even remove it). 3. Options dictionary on history object that contain boolean flags (history.options.restoreScroll): Simplified usage for pages that don't use pushState API. There has been support for all three in particular Spec editor favoring #1. Soon I am hoping to get feedback for #1 by implementing it in Blink behind a runtime flag. Note that all three options are extensible enough to allow exposing recorded scroll position in future. This property would default to true. Whenever pushState() is called, or the user navigates away from the current page, for example by clicking a a href=... the value of history.restoreScroll is copied into the session-history-entry data that the browser keeps internally. As soon as the new session-history-entry is created, restoreScroll is set to true again. So history.restoreScroll is copied into current history entry anytime a new history entry is created (or replaced). If my reading is correct then this makes sense and it can give per history entry control. The value of history.restoreScroll is reset to its default when a new document is loaded. Consider this case where page A uses pushState once and then navigates to page B. This creates three history entries: 2 for A and one for B. A -- Ai (*) == B where: -- pushState == navigation to new page (*) history.restoreScroll is set to 'false' This is what I think should happen: on A load: history.restoreScroll is reset to default value: TRUE. history entry is created for A. on --:current entry (A) is updated with current restoreScroll: TRUE history entry is created for Ai on (*): history.restoreScroll is set to 'FALSE'. on ==:current entry (Ai) is updated with current restoreScroll: FALSE on B load: history.restoreScroll is reset to default value: TRUE history entry for B is created. A gets TRUE Ai gets FALSE B gets TRUE Agreed. Additionally we could enable passing a boolean to pushState(), and this value would be used as the new initial value for restoreScroll. So something like pushState({ url: myURL, restoreScroll: false });. This would simply be syntax sugar for |pushState(, , myURL); history.restoreScroll = false;|. It is a nice syntax sugar but I don't feel it adds enough value to justify doing this at browser level. It can be done in Javascript by framework/poly-fill authors. I'm fine either way. I think that's all that's needed. Yes. Both APIs are equally expressive and one may be built on top of the other. I suggest two minor changes though: 1. We specifically proposed using a dictionary for
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Tue, Apr 28, 2015 at 9:16 AM, Majid Valipour maji...@google.com wrote: On Mon, Apr 27, 2015 at 9:54 PM Jonas Sicking jo...@sicking.cc wrote: Jumping in at the end here. As I've said before, I like the general idea of giving pages more control over scroll restoration, but I don't think we should tie this to pushState()/replaceState()/onscroll. My proposal is instead that we add an API like history.restoreScroll = boolean; Interesting. I believe Simon has also proposed a similar API for which you can find my original objections here. One of my objections was that any proposed API should give developers control of scroll restoration per individual history entry. Initially I assumed a single boolean flag cannot provide that control but now I believe what you are proposing here can in fact provide per-entry control. More on this later. My other objection was that because scroll restoration behaviour is ultimately tied to a specific history entry, the API to control it should reflect this underlying fact. IMO a flag on history object hides this fact while original proposal does not. I understand that for pages that do not create any state other than their default initial state (e.g., infinite scrollers) setting history.restoreScroll is simpler than using history.replaceState({restorScroll: false}). But I think this additional complexity is not prohibitive and can be justified when the upside is an API that better explains the underlying behaviour and is simpler for pages that do create multiple states using history.pushState. I agree that the difference between history.restoreScroll = false; and history.replaceState({restoreScroll: false}); is not that big and mainly comes down to taste. I like the former more. This property would default to true. Whenever pushState() is called, or the user navigates away from the current page, for example by clicking a a href=... the value of history.restoreScroll is copied into the session-history-entry data that the browser keeps internally. As soon as the new session-history-entry is created, restoreScroll is set to true again. So history.restoreScroll is copied into current history entry anytime a new history entry is created (or replaced). If my reading is correct then this makes sense and it can give per history entry control. The value of history.restoreScroll is reset to its default when a new document is loaded. Consider this case where page A uses pushState once and then navigates to page B. This creates three history entries: 2 for A and one for B. A -- Ai (*) == B where: -- pushState == navigation to new page (*) history.restoreScroll is set to 'false' This is what I think should happen: on A load: history.restoreScroll is reset to default value: TRUE. history entry is created for A. on --:current entry (A) is updated with current restoreScroll: TRUE history entry is created for Ai on (*): history.restoreScroll is set to 'FALSE'. on ==:current entry (Ai) is updated with current restoreScroll: FALSE on B load: history.restoreScroll is reset to default value: TRUE history entry for B is created. A gets TRUE Ai gets FALSE B gets TRUE Agreed. Additionally we could enable passing a boolean to pushState(), and this value would be used as the new initial value for restoreScroll. So something like pushState({ url: myURL, restoreScroll: false });. This would simply be syntax sugar for |pushState(, , myURL); history.restoreScroll = false;|. It is a nice syntax sugar but I don't feel it adds enough value to justify doing this at browser level. It can be done in Javascript by framework/poly-fill authors. I'm fine either way. I think that's all that's needed. Yes. Both APIs are equally expressive and one may be built on top of the other. I suggest two minor changes though: 1. We specifically proposed using a dictionary for options with scroll restoration being one of its parameters. This allows us to add additional history entry control parameters in the future. For example we can expose zoom restoration similarly if there is enough demand. 2. As suggested earlier in the thread it is better to use a name that suggests more strongly that the author is expected to restore the position themselves. So: history.options = { willRestoreScroll = false } I'm not strongly opinionated on naming. Are there other APIs in the platform which are named similarly? In order to make it easier for pages we could also expose a history.restoredScrollPosition which is a readonly property which the UA writes to any time it restores a session history entry, which is the scroll position that it would have restored scrolling to if the page hadn't disabled scroll restoration for the given session history entry. This is isn't strictly needed though since the page can simply use sessionStorage
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
Jumping in at the end here. As I've said before, I like the general idea of giving pages more control over scroll restoration, but I don't think we should tie this to pushState()/replaceState()/onscroll. My proposal is instead that we add an API like history.restoreScroll = boolean; This property would default to true. Whenever pushState() is called, or the user navigates away from the current page, for example by clicking a a href=... the value of history.restoreScroll is copied into the session-history-entry data that the browser keeps internally. As soon as the new session-history-entry is created, restoreScroll is set to true again. Additionally we could enable passing a boolean to pushState(), and this value would be used as the new initial value for restoreScroll. So something like pushState({ url: myURL, restoreScroll: false });. This would simply be syntax sugar for |pushState(, , myURL); history.restoreScroll = false;|. I think that's all that's needed. In order to make it easier for pages we could also expose a history.restoredScrollPosition which is a readonly property which the UA writes to any time it restores a session history entry, which is the scroll position that it would have restored scrolling to if the page hadn't disabled scroll restoration for the given session history entry. This is isn't strictly needed though since the page can simply use sessionStorage and update the scroll position in a onscroll handler. But history.restoredScrollPosition would reduce boilerplate code. Also, using sessionStorage is somewhat complex to do correctly given that the user might visit the same URL multiple times in the same session. (As an aside, it would be great if we had something like sessionStorage, but specific for a given page. Right now sessionStorage seems to make it very hard to store page specific state unless I'm missing something obvious?) / Jonas On Thu, Apr 23, 2015 at 3:25 PM, Majid Valipour maji...@chromium.org wrote: On Tue, Apr 21, 2015 at 4:58 PM Ian Hickson i...@hixie.ch wrote: On Sun, 12 Apr 2015, Anne van Kesteren wrote: On Thu, Apr 9, 2015 at 9:05 PM, Ian Hickson i...@hixie.ch wrote: I'd strongly recommend against adding new methods. It'll mean we now have two different ways to do the same thing, which means more bugs, which means less interoperability, more confusing behaviour for authors, more to document, etc. If the existing method didn't have the flaw with the title argument I wouldn't have suggested it. Also, since they both built upon the same primitive I think we'd be okay in the bugs and interop department. You are more optimistic than I. In any case, I strongly recommend against such redundancy. On Wed, 15 Apr 2015, Majid Valipour wrote: Actually URL is optional in current spec and it defaults to current URL. Why is this suboptimal? Because it means you can't bookmark the state or share the state, reloading the page loses the state, etc. In anycase If making URL required is a goal then it is best done by introducing a new method to avoid breaking compatibility. Why is that better? Changing the optional third argument to become required on the existing methods will break any call site that is not passing it. This is a non trivial compatibility issue which does not exists with a new method. I personally find a dictionary with only optional members which have appropriate defaults to be very convenient. I don't disagree... for new APIs. But when we already have an existing API, maintaining consistency and lack of redundancy IMHO trumps pretty much everything else, if you want the end result to be usable. A lot of the pain with using the Web's APIs is the inconsistency and redundancy that is rampant throughout. I understand the desire for maintaining consistency and reducing redundancy. On the other hand a new API will allow fixing some existing warts. I can see merits in both arguments. I am happy to defer the API decision to spec editors. I created the W3C bug for this proposal: https://www.w3.org/Bugs/Public/show_bug.cgi?id=28553 Majid
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Tue, Apr 21, 2015 at 4:58 PM Ian Hickson i...@hixie.ch wrote: On Sun, 12 Apr 2015, Anne van Kesteren wrote: On Thu, Apr 9, 2015 at 9:05 PM, Ian Hickson i...@hixie.ch wrote: I'd strongly recommend against adding new methods. It'll mean we now have two different ways to do the same thing, which means more bugs, which means less interoperability, more confusing behaviour for authors, more to document, etc. If the existing method didn't have the flaw with the title argument I wouldn't have suggested it. Also, since they both built upon the same primitive I think we'd be okay in the bugs and interop department. You are more optimistic than I. In any case, I strongly recommend against such redundancy. On Wed, 15 Apr 2015, Majid Valipour wrote: Actually URL is optional in current spec and it defaults to current URL. Why is this suboptimal? Because it means you can't bookmark the state or share the state, reloading the page loses the state, etc. In anycase If making URL required is a goal then it is best done by introducing a new method to avoid breaking compatibility. Why is that better? Changing the optional third argument to become required on the existing methods will break any call site that is not passing it. This is a non trivial compatibility issue which does not exists with a new method. I personally find a dictionary with only optional members which have appropriate defaults to be very convenient. I don't disagree... for new APIs. But when we already have an existing API, maintaining consistency and lack of redundancy IMHO trumps pretty much everything else, if you want the end result to be usable. A lot of the pain with using the Web's APIs is the inconsistency and redundancy that is rampant throughout. I understand the desire for maintaining consistency and reducing redundancy. On the other hand a new API will allow fixing some existing warts. I can see merits in both arguments. I am happy to defer the API decision to spec editors. I created the W3C bug for this proposal: https://www.w3.org/Bugs/Public/show_bug.cgi?id=28553 Majid
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Sun, 12 Apr 2015, Anne van Kesteren wrote: On Thu, Apr 9, 2015 at 9:05 PM, Ian Hickson i...@hixie.ch wrote: I'd strongly recommend against adding new methods. It'll mean we now have two different ways to do the same thing, which means more bugs, which means less interoperability, more confusing behaviour for authors, more to document, etc. If the existing method didn't have the flaw with the title argument I wouldn't have suggested it. Also, since they both built upon the same primitive I think we'd be okay in the bugs and interop department. You are more optimistic than I. In any case, I strongly recommend against such redundancy. On Wed, 15 Apr 2015, Majid Valipour wrote: Actually URL is optional in current spec and it defaults to current URL. Why is this suboptimal? Because it means you can't bookmark the state or share the state, reloading the page loses the state, etc. In anycase If making URL required is a goal then it is best done by introducing a new method to avoid breaking compatibility. Why is that better? I personally find a dictionary with only optional members which have appropriate defaults to be very convenient. I don't disagree... for new APIs. But when we already have an existing API, maintaining consistency and lack of redundancy IMHO trumps pretty much everything else, if you want the end result to be usable. A lot of the pain with using the Web's APIs is the inconsistency and redundancy that is rampant throughout. -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
I think the original approach of adding a fourth argument is much better. It's also a better API in general, since the URL should always be given. If we had a one-argument form with a dictionary, people would consider not giving the URL but just disabling scrolling, which is suboptimal. You can require arguments with dictionaries. Actually URL is optional in current spec and it defaults to current URL. Why is this suboptimal? In anycase If making URL required is a goal then it is best done by introducing a new method to avoid breaking compatibility. I personally find a dictionary with only optional members which have appropriate defaults to be very convenient. Here are some reasonable defaults: - url: current URL - title: current title - state: null - restoreScroll: true (or willRestoreScrollPosition: false)
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Thu, Apr 9, 2015 at 9:05 PM, Ian Hickson i...@hixie.ch wrote: I'd strongly recommend against adding new methods. It'll mean we now have two different ways to do the same thing, which means more bugs, which means less interoperability, more confusing behaviour for authors, more to document, etc. If the existing method didn't have the flaw with the title argument I wouldn't have suggested it. Also, since they both built upon the same primitive I think we'd be okay in the bugs and interop department. I think the original approach of adding a fourth argument is much better. It's also a better API in general, since the URL should always be given. If we had a one-argument form with a dictionary, people would consider not giving the URL but just disabling scrolling, which is suboptimal. You can require arguments with dictionaries. -- https://annevankesteren.nl/
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
Below is the IDL for the proposed changes: partial interface History { void pushState(in any data, in DOMString title, in optional DOMString url, in optional StateOptions options); void replaceState(in any data, in DOMString title, in optional DOMString url, in optional StateOptions options); readonly attribute StateOptions options; }; dictionary StateOptions { Boolean restoreScroll = true, } I'm not sure there's much point exposing history.options, what's the purpose of that? Its main purpose is to allow feature detection because it is not possible to feature detect the existence of the new optional fourth argument on its own. Exposing option allows the following feature detection: var canControlScrollRestoration = ‘options’ in window.history ‘restoreScroll’ in window.history.options; As a minor advantage, it may be useful for libraries that will handle scroll restoration. They can check history.options.restoreScroll and decide whether they need to restore scroll or user agents will do so. The same can be done with a boolean in state itself so this is just a nice to have. Of course if we were to add a new method this would not be needed. Also, I'd recommend an option name that suggests more strongly that the author is expected to restore the position themselves, rather than just that the position shouldn't be restored. For example, calling it something like willRestoreScrollPosition (defaulting to false, meaning the UA should do it). I think this is a good idea. On Wed, 25 Mar 2015, Jonas Sicking wrote: Is this really something we should tie to the pushState/replaceState API? It seems like websites that lazily add more content as the user scroll down, like the facebook feed or twitter feed, might not use pushState/replaceState, but would still like to handle restoring scroll position themselves. On Thu, 26 Mar 2015, Simon Pieters wrote: Yeah... also consider navigating back and forth between two different sites/apps, without navigating within each site/app. Should they be able to turn off scroll restore? Is this something that should be toggled on a per-page basis or on a per-navigation basis? If per-page, is it enough to just be able to turn it off (i.e. not turn it on again)? These are interesting points. It seems like what you really want is a way to hook into the scroll behaviour. For example, we could fire an event at the document saying we're about to automatically scroll to 75% of the way down the page, cancel this if you want to do it yourself. The real problem with that, though, is that 75% means nothing in the cases where you'd want to actually do it yourself. It's not clear to me how you could convey the information that is actually needed. Maybe infinite-scroll pages _should_ use replaceState(), to say how much they have loaded. At which point, the boolean flag seems reasonable again. I think a method to prevent/customize scrolls https://code.google.com/p/chromium/issues/detail?id=416862 might be helpful in this situation but it may be a while before such an API actually becomes available. In the meantime, this proposal is simple and easy to implement and addresses a serious issue for developers. Are there other vendors interested in implementing this? If not, I recommend that Chrome implement this as the fourth argument with a dictionary with a boolean that implies that the author will perform the scroll position restoration behaviour themselves, and then filing a bug on the spec with the Target Milestone set to Needs Impl Interest. Sounds like a reasonable plan. Hopefully we can get more vendors interested and I am more than happy to adjust the proposal to help this happen. Majid
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Thu, 19 Mar 2015, Majid Valipour wrote: Almost all browsers restore scroll position when a user traverses history. This behavior works well for document style web sites but it is often not appropriate for single-page web applications where the page content may be reconstructed (often asynchronously) upon navigation and where the application wants to control the details of visual transition between UI states. Seems reasonable. Avoid document scrolling altogether by fixing body size and putting content in an inner scrollable div. This breaks browser features that depend on document scrolling such as top controls hiding, or overscroll visuals and in some cases disables fast scroll optimizations for document scrolling. Also really it's a bug in browsers that such divs aren't getting the scroll position restored as well. Below is the IDL for the proposed changes: partial interface History { void pushState(in any data, in DOMString title, in optional DOMString url, in optional StateOptions options); void replaceState(in any data, in DOMString title, in optional DOMString url, in optional StateOptions options); readonly attribute StateOptions options; }; dictionary StateOptions { Boolean restoreScroll = true, } I'm not sure there's much point exposing history.options, what's the purpose of that? Also, I'd recommend an option name that suggests more strongly that the author is expected to restore the position themselves, rather than just that the position shouldn't be restored. For example, calling it something like willRestoreScrollPosition (defaulting to false, meaning the UA should do it). On Wed, 25 Mar 2015, Anne van Kesteren wrote: The only suggestion I have is that instead of having four-argument methods we might want to consider introducing two new methods that take a dictionary. E.g. history.push() and history.replace(). Giving the page more control over the scroll position when navigating makes sense to me. I'd strongly recommend against adding new methods. It'll mean we now have two different ways to do the same thing, which means more bugs, which means less interoperability, more confusing behaviour for authors, more to document, etc. I think the original approach of adding a fourth argument is much better. It's also a better API in general, since the URL should always be given. If we had a one-argument form with a dictionary, people would consider not giving the URL but just disabling scrolling, which is suboptimal. On Wed, 25 Mar 2015, Jonas Sicking wrote: Is this really something we should tie to the pushState/replaceState API? It seems like websites that lazily add more content as the user scroll down, like the facebook feed or twitter feed, might not use pushState/replaceState, but would still like to handle restoring scroll position themselves. On Thu, 26 Mar 2015, Simon Pieters wrote: Yeah... also consider navigating back and forth between two different sites/apps, without navigating within each site/app. Should they be able to turn off scroll restore? Is this something that should be toggled on a per-page basis or on a per-navigation basis? If per-page, is it enough to just be able to turn it off (i.e. not turn it on again)? These are interesting points. It seems like what you really want is a way to hook into the scroll behaviour. For example, we could fire an event at the document saying we're about to automatically scroll to 75% of the way down the page, cancel this if you want to do it yourself. The real problem with that, though, is that 75% means nothing in the cases where you'd want to actually do it yourself. It's not clear to me how you could convey the information that is actually needed. Maybe infinite-scroll pages _should_ use replaceState(), to say how much they have loaded. At which point, the boolean flag seems reasonable again. Are there other vendors interested in implementing this? If not, I recommend that Chrome implement this as the fourth argument with a dictionary with a boolean that implies that the author will perform the scroll position restoration behaviour themselves, and then filing a bug on the spec with the Target Milestone set to Needs Impl Interest. -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
** Re-sending my response with my member email address to ensure it is included in the mailing list archive. Apologies for duplication. On Thu, Mar 26, 2015 at 5:16 AM Simon Pieters sim...@opera.com … Yeah... also consider navigating back and forth between two different sites/apps, without navigating within each site/app. Should they be able to turn off scroll restore? Yes. It think it should be possible for the application to control scroll restoration for all of its own history entries including the one implicitly created by the user agent upon initial load and the ones that are explicitly create by itself for the purpose of internal navigation. For example a news site may want to always send user to the page top where top news are displayed regardless of where the user was before. This is currently being achieved by resorting to workarounds such as setting body size to 100% and using inner divs (e.g., CBC news http://www.cbc.ca/m/news/). Note that currently scroll is consistently restored regardless of the type of the navigation (intra-app, inter-app). I don't think we should start treating them distinctly or even change their default restoration behavior as long as we provide ability for application to opt out of scroll restoration for either type. The current proposal does just that and lets the application decide what is best for their particular need. … Is this something that should be toggled on a per-page basis or on a per-navigation basis? If per-page, is it enough to just be able to turn it off (i.e. not turn it on again)? e.g. history.restoreScroll = false; or history.disableRestoreScroll(); We did consider a per-page global flags as an alternative design and it is discussed in the original proposal document https://docs.google.com/a/chromium.org/document/d/1Tiu8PjvBtNOAgeh6yrs7bOrXxQcavQLiNtRJ_ToLlVM. Here is a summary of why we think an API that gives per-navigation control is a better fit: - Scroll is restored per-navigation so an API for controlling it per-navigation is more natural and better represents the underlying behavior. A global per-page switch hides this fact and is harder to reason about unless we also change the scroll restoration to become per-page. - Controlling scroll restoration per-navigation is more flexible than per-page. It is trivial to implement a pollyfill for disabling scroll restoration per-page if we have the per-navigation version but the reverse is not true. I imagine libraries such as History.js and jQuery UI will be providing a flag to disable it per-page (or per app). - There are legitimate usecases where an application may want to have different scroll restoration behavior for its different UI state (i.e., per navigation). For example Facebook may want to have automatic restoration in timeline but disable it on photo pages. Thanks
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Thu, Mar 26, 2015 at 11:12 AM Anne van Kesteren ann...@annevk.nl wrote: On Thu, Mar 26, 2015 at 3:57 PM, Majid Valipour maji...@google.com wrote: That is fair. Assuming clear documentation helps alleviate potential confusion I am fine with deprecation route. I suppose the purpose of the spec is to not only document the current recommended behavior but also capture any legacy ones until it is fully removed. Yeah, we don't want any new user agents such as Spartan or Servo run into pages that only work with history.replaceState(). They'd then have to reverse engineer it rather than simply reading a specification which is not nice. ** Re-sending with my member email address. Apologies for duplication. I have updated the proposal document https://docs.google.com/a/chromium.org/document/d/1Tiu8PjvBtNOAgeh6yrs7bOrXxQcavQLiNtRJ_ToLlVM based on feedback around API design: partial interface History { void push(in optional HistoryEntry entry); void replace(in optional HistoryEntry entry); } dictionary HistoryEntry { any state, DOMString title, DOMString url, Boolean restoreScroll = true, } Now instead of adding a fourth optional parameter to existing methods it introduces new methods (push, replace) which accept dictionaries. Although not required I think it improves API completeness if the following two modifications are also included: 1. Add a readonly 'history.current' attribute which returns the current entry in joint history session analogous to how history.state behaves now. This allows developers to access title, url, and restoreScroll of the current history entry. 2. Add a new attribute 'entry' of type HistoryEntry to PopStateEvent in addition to 'state'. This one may actually be unnecessary if we have history.current and knowing that there can only ever be one PopState event in flight. Thanks
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
Majid Valipour maji...@chromium.org writes: For example a news site may want to always send user to the page top where top news are displayed regardless of where the user was before. This is currently being achieved by resorting to workarounds such as setting body size to 100% and using inner divs (e.g., CBC news http://www.cbc.ca/m/news/). Note that many users consider breaking the back button an annoyance. I do not want “take me back where I came from” to suddenly mean “take me back where the site owner would like to me to get”. Especially with “social” news feeds, following a link and then not being able to get back to the position on the page you came from is very frustrating. -- Nils Dagsson Moskopp // erlehmann http://dieweltistgarnichtso.net
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
Hi Nils, I am not advocating for breaking the back button but in fact the opposite. The idea is to allow single-page applications that are creating new history entries and for whom the automatic scroll restoration is *broken* (because the page is being re-creating on popstate event) to be able to replace user-agent's default scroll restoration with their own custom implementation. Note that in practice, major mobile optimized sites are implementing their own scroll restoration via various ugly hacks because the user agent scroll restoration is broken for them. In my proposal, I have listed a few of these hacks (e.g., double scroll, inner scrolling div) and their negative implications. Websites that are trying to provide good back button behavior should not resort to hacks and suffer for it. Also the proposal is backward compatible and opts for restoring scroll position by default so existing websites will continue to behave as before. Majid On Tue, Apr 7, 2015 at 1:50 PM Nils Dagsson Moskopp n...@dieweltistgarnichtso.net wrote: Majid Valipour maji...@chromium.org writes: For example a news site may want to always send user to the page top where top news are displayed regardless of where the user was before. This is currently being achieved by resorting to workarounds such as setting body size to 100% and using inner divs (e.g., CBC news http://www.cbc.ca/m/news/). Note that many users consider breaking the back button an annoyance. I do not want “take me back where I came from” to suddenly mean “take me back where the site owner would like to me to get”. Especially with “social” news feeds, following a link and then not being able to get back to the position on the page you came from is very frustrating. -- Nils Dagsson Moskopp // erlehmann http://dieweltistgarnichtso.net
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Wed, 25 Mar 2015 21:31:51 +0100, Jonas Sicking jo...@sicking.cc wrote: Is this really something we should tie to the pushState/replaceState API? It seems like websites that lazily add more content as the user scroll down, like the facebook feed or twitter feed, might not use pushState/replaceState, but would still like to handle restoring scroll position themselves. Yeah... also consider navigating back and forth between two different sites/apps, without navigating within each site/app. Should they be able to turn off scroll restore? Is this something that should be toggled on a per-page basis or on a per-navigation basis? If per-page, is it enough to just be able to turn it off (i.e. not turn it on again)? e.g. history.restoreScroll = false; or history.disableRestoreScroll(); -- Simon Pieters Opera Software
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Thu, Mar 26, 2015 at 1:22 AM, Majid Valipour maji...@google.com wrote: My only concern is to make sure that these new methods replace history.pushState() and history.replaceState() in the spec. Otherwise I feel the benefits of a cleaner API is not worth the additional confusion of having different methods for doing (almost) the same thing. Well, I doubt that they can, maybe over a very long period of time but I wouldn't count on it. However, if MDN describes them as more capable methods (and without the useless second argument), I doubt there will be much confusion. Having four required arguments is no picnic either. -- https://annevankesteren.nl/
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Thu, Mar 26, 2015 at 3:57 PM, Majid Valipour maji...@google.com wrote: That is fair. Assuming clear documentation helps alleviate potential confusion I am fine with deprecation route. I suppose the purpose of the spec is to not only document the current recommended behavior but also capture any legacy ones until it is fully removed. Yeah, we don't want any new user agents such as Spartan or Servo run into pages that only work with history.replaceState(). They'd then have to reverse engineer it rather than simply reading a specification which is not nice. -- https://annevankesteren.nl/
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On Thu, Mar 19, 2015 at 6:31 PM, Majid Valipour maji...@chromium.org wrote: partial interface History { void pushState(in any data, in DOMString title, in optional DOMString url, in optional StateOptions options); void replaceState(in any data, in DOMString title, in optional DOMString url, in optional StateOptions options); readonly attribute StateOptions options; }; dictionary StateOptions { Boolean restoreScroll = true, } The only suggestion I have is that instead of having four-argument methods we might want to consider introducing two new methods that take a dictionary. E.g. history.push() and history.replace(). Giving the page more control over the scroll position when navigating makes sense to me. -- https://annevankesteren.nl/
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
On 25/03/2015 14:54 , Anne van Kesteren wrote: The only suggestion I have is that instead of having four-argument methods we might want to consider introducing two new methods that take a dictionary. E.g. history.push() and history.replace(). Giving the page more control over the scroll position when navigating makes sense to me. +1 This has the added benefit of getting rid of the second argument wart. -- Robin Berjon - http://berjon.com/ - @robinberjon
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
Is this really something we should tie to the pushState/replaceState API? It seems like websites that lazily add more content as the user scroll down, like the facebook feed or twitter feed, might not use pushState/replaceState, but would still like to handle restoring scroll position themselves. / Jonas On Wed, Mar 25, 2015 at 6:54 AM, Anne van Kesteren ann...@annevk.nl wrote: On Thu, Mar 19, 2015 at 6:31 PM, Majid Valipour maji...@chromium.org wrote: partial interface History { void pushState(in any data, in DOMString title, in optional DOMString url, in optional StateOptions options); void replaceState(in any data, in DOMString title, in optional DOMString url, in optional StateOptions options); readonly attribute StateOptions options; }; dictionary StateOptions { Boolean restoreScroll = true, } The only suggestion I have is that instead of having four-argument methods we might want to consider introducing two new methods that take a dictionary. E.g. history.push() and history.replace(). Giving the page more control over the scroll position when navigating makes sense to me. -- https://annevankesteren.nl/
Re: [whatwg] Proposal: Allow disabling of default scroll restoration behavior
Ping. Any thoughts from folks familiar with the history API definition? This proposal resolves a high-profile issue we've received from a number of major websites. As Majid said, mobile-optimized websites are being forced to choose between the fullscreen UX users expect from websites on phones (document scrolling) and the navigation transitions users expect from rich mobile apps (full page div scrolling). This is unacceptable for apps trying to provide a 1st-class mobile UX on the web. We're anxious to ship a solution in blink ASAP. Thanks, Rick On Thu, Mar 19, 2015 at 1:31 PM, Majid Valipour maji...@chromium.org wrote: # Problem Almost all browsers restore scroll position when a user traverses history. This behavior works well for document style web sites but it is often not appropriate for single-page web applications where the page content may be reconstructed (often asynchronously) upon navigation and where the application wants to control the details of visual transition between UI states. Currently it is not possible to disable the scroll behavior so web developers have resorted to various hacks [1]. Here are the two most popular: - Avoid document scrolling altogether by fixing body size and putting content in an inner scrollable div. This breaks browser features that depend on document scrolling such as top controls hiding, or overscroll visuals and in some cases disables fast scroll optimizations for document scrolling. - Use a secondary scroll after browser's initial attempts to restore scroll. This leads to two visible jumps and bad UX. Few documented cases of web developers struggling with this problem may be found in [2, 3, 4]. # Proposal Allow web applications to explicitly disable user agents default scroll restoration behavior via History API. This is achieved by adding a fourth optional parameter 'options' to both history.pushState, history.replaceState. Obviously the default values will be backward compatible. We should also provide a new attribute (history.options) that exposes the current effective value of this new property and use it to provide a simple feature detection. Below is the IDL for the proposed changes: partial interface History { void pushState(in any data, in DOMString title, in optional DOMString url, in optional StateOptions options); void replaceState(in any data, in DOMString title, in optional DOMString url, in optional StateOptions options); readonly attribute StateOptions options; }; dictionary StateOptions { Boolean restoreScroll = true, } Here is a more complete version of this proposal with details around background, current proposal design, and considered alternative designs: https://docs.google.com/a/chromium.org/document/d/1Tiu8PjvBtNOAgeh6yrs7bOrXxQcavQLiNtRJ_ToLlVM We like to implement this or something similar in blink and would be interested to hear from other vendors. All feedback on proposed design is welcome. :) Thanks Majid Valipour [1] http://stackoverflow.com/questions/10742422/prevent-browser-scroll-on-html5-history-popstate [2] https://bugzilla.mozilla.org/show_bug.cgi?id=679458 [3] https://github.com/rackt/react-router/issues/707 [4] http://andrz.me/blog/scrollx-scroll-why-history