Re: [whatwg] HTML5 History Management
Mike, It does sound like we're asking for similar things. I think that my personal proposal is history.replaceState() which does exactly history.pushState() but pops the history stack first. Theoretically this wouldn't be hard to implement and mirrors the relationship between location.href = and history.replace(). Others: thoughts? Nathan On Aug 5, 2009, at 4:58 AM, Mike Wilson wrote: Nathan Hammond wrote: I should have stated this one with a goal: the ability to ensure that the popstate event always fires with a full understanding of the (app/page) state when navigating through history. This would be lost when a user manually changes the hash. [...] Any other techniques for remembering data other than this would still be a hack because, in and of itself, the data stored are not uniquely tied to a particular history state. [...] Using sessionStorage I have the additional task of mapping the stored series of states to a particular visit of the (app/page) if the user visits the site again after navigating away: example.com - whatwg.com - example.com Hi Nathan, I think I touched on the same need in my thread html5 state handling: overview and extensions, see http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2009-June/020423.html or http://www.nabble.com/html5-state-handling:-overview-and-extensions-td240347 73.html See the table on SCRIPT-CONTROLLED STATE at the end of that mail. As you can see I am suggesting to add a state construct for the missing Document state level. I'm just back from vacation but I'm doing some more research and hope to provide more information on that thread later this month. Best regards Mike Wilson
Re: [whatwg] HTML5 History Management
Ian, Thanks for the comments. I've simply omitted pieces that I feel like are completely addressed. For all of those: Yes, I agree, right, right, great, and perfect. Thanks for clarifying and answering silly questions. For the rest, see below. On Aug 4, 2009, at 9:29 PM, Ian Hickson wrote: On Wed, 29 Jul 2009, Nathan Hammond wrote: Possible Action Items 1. Specify the order in which history related events are triggered. In what order would one expect the events triggered by window.history.pushState({}, Title, #newhash)? No events are triggered by doing that. With my new understanding of pushState, not triggering popstate makes sense. With regards to pushState not triggering a hashchange event, I like it, but I do want to be absolutely sure that all implementers get this right. So, could we clarify this in the spec? Right now I think that the spec could be read where since it adjusts the document's current address it might should cause a hashchange event. Providing this specific example would do the trick. Related, is window.location.hash = newhash; supposed to trigger a hashchange event? (Is this specified? I couldn't find it.) I do believe it does in IE8, but I don't have IE8 available to me at this moment to check. 2. Specify a method to allow access to the history stack. (At least readable within the context of same-origin, possibly mutable.) This would allow for understanding on the client side of a user's path through the site, even after navigating away from the page. If this is not implemented the absolute first thing I will be implementing is a method to track this information, a rather large duplication of effort for something that could easily be made available. This would involve a something like currentstate = { _previous: currentstate, title: window.title, newval: true }; plus a form-based storage mechanism to repopulate state in case the user exits on a page which they manually changed the hash to get to (which would not have access to the data object upon revisiting later since there wouldn't be one stored with that history state). I'm aware of the privacy ramifications, but at the same time, I'm going to be exposing those exact same concerns with the above method. It turns out to be quite complex to expose this in the API currently, because the History object exposes a mix of all the various frames at once, and you can get to the History object of cross-origin frames, and there's some other legacy baggage here also (e.g. history.length). Since it's not entirely clear what the use case is, and since you can do it to some extent already using onload, onhashchange, and onpopstate, I'd rather just let authors reimplement this themselves at this point, and maybe revisit this in a future version. Complexity. Bah! (Then again, you don't have to tell me.) The use case I find is pretty simple: in the event that there are two separate ways to get to a specific page in the app I need to know how the person got there. Or this could be used to provide content tailored specifically to that user based upon their history (whether suggestions, ads, or help text). Really though, this point is far less critical (as it is easy enough to handle in client code) and does greatly increase the complexity for getting all implementers on board. If this *isn't* implemented however, the point below becomes more critical for being able to successfully track state in client code... 3. Specify a method to modify the current history state without adding a new history point. Assuming you don't mind causing the page to reload, you can use history.replace(). I'm not sure what it would mean to replace the history state without changing the Document or anything, though. This would alleviate the need for the (incredibly brittle) form-based storage mechanism I describe above. Can you use sessionStorage for this? I should have stated this one with a goal: the ability to ensure that the popstate event always fires with a full understanding of the (app/ page) state when navigating through history. This would be lost when a user manually changes the hash. With that as my goal, history.replace does not achieve what I am trying to accomplish. Neither does pushState without a URL as that still registers a new history point. Any other techniques for remembering data other than this would still be a hack because, in and of itself, the data stored are not uniquely tied to a particular history state. In my semi-professional opinion form storage is really more appropriate for this task as it is correctly mapped to the document object on which the data was entered. Using sessionStorage I have the additional task of mapping the stored series of states to a particular visit of the (app/page) if the user visits the site again after navigating away: example.com - whatwg.com - example.com (Use case is the game idea
Re: [whatwg] HTML5 History Management
Hey Jonas et al.: Thanks for the reply, forgive my disbelief on Clarification 1. :) If I'm completely with you, that is entirely unexpected on my part (and I've read this part of the spec a few times). Is this to imply that, no matter what the arguments to pushState(), if the path is relative to the current URL there will be no request for a new document and no user-agent initiated network activity? This is a behavior I'm fine with and will meet my needs just as well, I was simply expecting to have to use the approach from Clarification 2 in order to retain my document object. It does however lend itself to some confusion when paired with user agents that don't yet support the history portions of the spec as they will have to be handled with hash-based addressing while those that support pushState() will have more sane URLs--but that is no matter in the grand scheme of things. Also, that would imply that the popstate only fires when you're navigating through history. Is that correct? Thanks! Nathan On Jul 30, 2009, at 4:42 AM, Jonas Sicking wrote: On Wed, Jul 29, 2009 at 7:38 PM, Nathan Hammondnat...@nathanhammond.com wrote: Clarifications 1. window.history.pushState({}, Title, /path/to/new/file.html?s=newvalue#newhash) replaces the current document object with the one specified by the new URL. It then causes the event popstate to fire immediately after the load event, correct? No. The above line with change the uri of the existing document to be http://example.com/path/to/new/file.html?s=newvalue#newhash; (with the part before 'path' obviously depending on where the original page lives). So no network activity takes place and the Document node remains the same. Also no popstate event is fired. 2. window.history.pushState({}, Title, #newhash) creates a new history state object with the specified data object, the specified title, the same document object, and a location object that replaces the existing hash with #newhash, correct? Yes. / Jonas
Re: [whatwg] HTML5 History Management
Sebastian, The same-origin is pretty clearly specified, I've included the excerpt from the spec below. Your suggestion for clarity on updating Location fields in the the UI would be a part of step five in the description of pushState in section 6.10.2 is a good one. Ian, I feel like this counts as a possible action item. Nathan *** Possible Action Items 1. Clarify how the user agent uses the calculated location value from the pushState description step 2 in section 6.10.2 in terms of being reflected in the Location object. It is my opinion that this URL should be reflected in the Location value. This would imply that it would be reflected in the location bar of user agents that have this as part of their UI. It seems that the place to include this clarification would be the pushState description step 5 in section 6.10.2 2. Clarify that pushState() does not cause navigation. I read the spec quite a few times and still got this wrong, apparently. Making this completely clear would not hurt. *** If a third argument is specified, run these substeps: 1. Resolve the value of the third argument, relative to the first script's base URL. 2. If that fails, raise a SECURITY_ERR exception and abort the pushState() steps. 3. Compare the resulting absolute URL to the document's address. If any part of these two URLs differ other than the path, query, and fragment components, then raise a SECURITY_ERR exception and abort the pushState() steps. For the purposes of the comparison in the above substeps, the path and query components can only be the same if the URLs use a hierarchical scheme. On Jul 30, 2009, at 10:27 AM, Sebastian Markbåge wrote: Jonas, That is my interpretation too. But I think it's a little unclear whether that means that the UA should update any Location fields in the UI. I understand that this may be optional or outside the scope, but I think that it should still be mentioned. Now if the UA is suppose to update the Location field, shouldn't push state URL be subject to same-domain policies? Is that defined clearly? Otherwise, this can be used during phishing attacks. Sebastian On Thu, Jul 30, 2009 at 4:13 PM, Nathan Hammond nat...@nathanhammond.com wrote: Hey Jonas et al.: Thanks for the reply, forgive my disbelief on Clarification 1. :) If I'm completely with you, that is entirely unexpected on my part (and I've read this part of the spec a few times). Is this to imply that, no matter what the arguments to pushState(), if the path is relative to the current URL there will be no request for a new document and no user-agent initiated network activity? This is a behavior I'm fine with and will meet my needs just as well, I was simply expecting to have to use the approach from Clarification 2 in order to retain my document object. It does however lend itself to some confusion when paired with user agents that don't yet support the history portions of the spec as they will have to be handled with hash-based addressing while those that support pushState() will have more sane URLs--but that is no matter in the grand scheme of things. Also, that would imply that the popstate only fires when you're navigating through history. Is that correct? Thanks! Nathan On Jul 30, 2009, at 4:42 AM, Jonas Sicking wrote: On Wed, Jul 29, 2009 at 7:38 PM, Nathan Hammondnat...@nathanhammond.com wrote: Clarifications 1. window.history.pushState({}, Title, /path/to/new/file.html?s=newvalue#newhash) replaces the current document object with the one specified by the new URL. It then causes the event popstate to fire immediately after the load event, correct? No. The above line with change the uri of the existing document to be http://example.com/path/to/new/file.html?s=newvalue#newhash; (with the part before 'path' obviously depending on where the original page lives). So no network activity takes place and the Document node remains the same. Also no popstate event is fired. 2. window.history.pushState({}, Title, #newhash) creates a new history state object with the specified data object, the specified title, the same document object, and a location object that replaces the existing hash with #newhash, correct? Yes. / Jonas
[whatwg] HTML5 History Management
Ian et al.: About a year ago, after I wrote the first version of my history manager, I began the process of looking into the HTML5 history spec and had a few conversations with folks like Bertrand Le Roy, Brad Neuberg, and Brian Dillard. Some of my notes from back then have been addressed, but I've still got a few more. Everything is included below for your reading pleasure. Enjoy! Nathan *** Clarifications 1. window.history.pushState({}, Title, /path/to/new/file.html? s=newvalue#newhash) replaces the current document object with the one specified by the new URL. It then causes the event popstate to fire immediately after the load event, correct? 2. window.history.pushState({}, Title, #newhash) creates a new history state object with the specified data object, the specified title, the same document object, and a location object that replaces the existing hash with #newhash, correct? Possible Action Items 1. Specify the order in which history related events are triggered. In what order would one expect the events triggered by window.history.pushState({}, Title, #newhash)? There are two events of interest: popstate, and hashchange. If popstate is fired first it will make it easy to catch programmatic versus user changes to the hash and respond accordingly. This would imply queueing the popstate event prior to changing the URL when the document isn't changing, or having the browser respond to the popstate event by changing the hash. (This concern exists only when the new URL reuses the same document object.) Regardless of the outcome, the order in which these events are triggered really needs to be specified and each individual triggering of these pair of events needs to be assured to occur entirely before the next time the pair are triggered. 2. Specify a method to allow access to the history stack. (At least readable within the context of same-origin, possibly mutable.) This would allow for understanding on the client side of a user's path through the site, even after navigating away from the page. If this is not implemented the absolute first thing I will be implementing is a method to track this information, a rather large duplication of effort for something that could easily be made available. This would involve a something like currentstate = { _previous: currentstate, title: window.title, newval: true }; plus a form-based storage mechanism to repopulate state in case the user exits on a page which they manually changed the hash to get to (which would not have access to the data object upon revisiting later since there wouldn't be one stored with that history state). I'm aware of the privacy ramifications, but at the same time, I'm going to be exposing those exact same concerns with the above method. 3. Specify a method to modify the current history state without adding a new history point. This would alleviate the need for the (incredibly brittle) form-based storage mechanism I describe above. 4. Specify additional properties on the hashchange event. Lots of possible useful information with the number one most important being the new hash that triggered the event to prevent race conditions reading window.location.hash. Other fun things that are a bit more pie in the sky: the previous hash and knowledge of how it was triggered (manually? pushState? window.location.hash = ? window.location.href = ?).