Open Bug 753264 Opened 13 years ago Updated 2 years ago

history.replaceState creates NEW history items

Categories

(Toolkit :: Places, defect, P3)

defect

Tracking

()

People

(Reporter: eric.hoffmn, Unassigned)

References

Details

Attachments

(1 file)

When using the history.replaceState method, the URL is replaced and no tab-history item appears to be created (back- and forward history). However, every manipulation of the URL using the replaceState-method (like in the pushState-method) causes the new history state to appear in the global history without the original history entry being removed. When using this Method extensively to mark minor changes to the state of a web application across sessions an trying to keep those out of the global history this is undesireable. It could lead to clutter in the history and omnibar and, in extreme cases, slow the startup of Firefox. The documentation available to developers please refer to https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history#The_replaceState().C2.A0method
Are you using history.replaceState with null as the first argument? I change my code to use a empty string (as I didn't need any state data just the URL changed) and no new history items seemed to be created. Using null should not create new history state. Chrome works with null and FF used to (not sure what version that this behaviour changed).
I was indeed using NULL as the first parameter, but replacing it with an empty string did nothing to stop the creation of unwanted history items. Right now I am very willing to believe that something is going wrong in my code or some extension is causing the problem. Thanks for your answer and best guess though, it is very much appreciated ;) I think that I will try playing around with a completely new Firefox-installation and see if the problem persists using that and only this one api-call when I can find the time...
Component: Bookmarks & History → Document Navigation
Product: Firefox → Core
replaceState should basically add just like a location.replace() load in history terms, no? As in, update session history in-place, add to global history...
> replaceState should basically add just like a location.replace() load in history terms, no? Yes... It sounds like that's what's happening: The URL gets added to global history, but not shistory: > However, every manipulation of the URL using the replaceState-method (like in the pushState-method) > causes the new history state to appear in the *global history* without the original history entry > being removed. Global history isn't spec'ed, so we could change this, I suppose. But it's not clear to me that the current behavior is wrong.
> Global history isn't spec'ed I realize now that I said this without checking it, which is just /asking/ for you to prove me wrong... :)
I am not aware of any spec for global history.
(In reply to Boris Zbarsky (:bz) from comment #6) > I am not aware of any spec for global history. Phew. :) In the case that the reporter is describing (many fast replaceState calls), I agree it doesn't make sense to add to global history. But you can imagine a different case (a few slow replaceState calls) where it /does/ make sense to do so. For example, bugzilla uses replaceState to change process_bug.cgi into show_bug.cgi?id=123456. We certainly want the latter to go into global history. I don't know if there's some compromise to be reached here. If not, we should probably close this bug.
The current behavior does seem wrong in the use cases that I can think of. I believe the desired behavior is that the global history entry representing the pre-replaceState state is updated to the post-replaceState state and moved to the top of the global history. This would seem to cover the bugzilla use case as well, as I doubt it's useful to have both process_bug.cgi and show_bug.cgi?id=123456 entries in the global history -- you want only the latter.
There is no such thing as "global history entry". There's just a list of urls that global history stores. I don't think the current behavior is wrong in many of the cases replaceState is supposed to be used for: doing in-page state updates that are still represented by a URI.
Here's an example of where the current behavior is undesirable: https://github.com/openstreetmap/openstreetmap-website/pull/378#issuecomment-21756758 We'd like to use location.replace or history.replaceState to track the current location and zoom level of the map on openstreetmap.org without polluting the global history.
The thing is, what you call "pollution" a user may well think of as "a way to get to that map I was looking at yesterday". I have certainly used global history that way in the past. :(
FWIW, using replaceState() is almost always a very explicit choice on the part of the page’s author. Short of it posing a security risk, it seems strange to me that the browser wouldn't respect that choice. It also seems a little weird as a Firefox user that, in two places where I see my browsing history, I see differing content. Why shouldn't the global history be consistent with the back button?
The global history is not at all related to the back button. For one simple example, the global history persists across many windows, tabs, and restarting your browser. replaceState, like location.replace are all about interaction with the _session_ history. Again, there is no specification for global history: the browser is allowed to not have one, to have one that stores everything the user has ever visited, or anything in between, as desired. And browsers do.
> The global history is not at all related to the back button. Oh, definitely, I get that. What I'm trying to say is, as a user (not as a software engineer), a) the back/forward buttons are directly representative of the current tab's history (i.e the different states they can put me in *are* the tab's history) and b) the global history is just the history of all my tabs ever. It may be that I'm weird in perceiving it this way, but I don't think I am. > there is no specification for global history Got it! But in any case I'm not arguing whether this matching a spec; I'm simply giving my opinion on whether the behavior actually makes sense to me as a user and author. I totally understand that, technically speaking, the global history is a list of URLs I've seen and not a list of my combined *history* (i.e. the thing I can move back and forth within). That said, it's not the behavior I'd expect from this feature and it's certainly not the behavior others would, given that they raised this issue. I'm also not sure it's a behavior I *want,* now that I understand what it is. Again, I understand we aren't talking about a standard or a spec here; we're just talking about a particular feature of the Firefox UI. But I do think it would be improved if it reflected the way the history of each tab worked (which is spec'ed).
The question isn't whether there exists a use-case where we'd want only the last URI to be in the history. The question is, given that we need to pick one behavior (*), which behavior should we pick? Changing existing behavior on the web is something we do only with great care. We've already chosen to include the replaceState'd pages in global history. Changing that behavior could break existing pages (e.g. bugzilla; see comment 7); that's something we strive not to do. If you want us to change our behavior, I think you'd get a lot further if you could demonstrate that Firefox's behavior doesn't match other browsers'. But that would just be a start... (*) I suppose we could talk about modifying the API to let you specify whether you want the entry to be included in global history. I think we'd have a heck of a time getting that adopted universally.
Maybe I'm misunderstanding something here. How would the change have any effect on a web application’s behavior (including the Bugzilla example)? As John points out in comment 8, it seems debatable whether current behavior is even the right thing in the Bugzilla case. You could make some good points either way. However, what the global history shows doesn't affect the behavior of the back/forward buttons (right? Also, I'm not talking about changing how those behave) and certainly doesn't have any effect on a web app itself, so I'm a bit confused on this might “break” anything. The only way it seems to me that the current behavior of the global history (or changing it) has any effect on a web app is that the current behavior discourages use of replaceState() for more mindful authors (and has no effect on less mindful authors) because it has an adverse effect on part of the UI in Firefox. This also seems at odds with the replaceState() API, whose whole point is to help authors manage this aspect of browser UI (again, I understand we aren't talking about something explicitly covered by that spec, but this discussion wouldn't exist if it weren't for the behaviors and expectations created by that spec). replaceState() is there to allow authors to make the history more friendly and sensible to users, but that same intention is thwarted for authors who want to really put that to use because it still makes the global history look nuts. I guess the opposite viewpoint might be that authors shouldn't worry about this—use replaceState() to keep a URL up-to-date with the UI as suggested by the spec and that's the end of the story. What the browser chooses to display to the user in their global history isn't an author’s concern. But as someone who cares a lot about the experience of using a site I've built, that seems disappointing to me.
The main use of global history is visited-link coloring, not the Firefox UI view. So the key question to ask is whether links to something that was visited should be colored visited if there was then a replaceState to some other URL..
> The main use of global history is visited-link coloring, not the Firefox UI view. Ah! So, to be clear, my concern (and I think John's) is that Firefox's *UI* in this case is not optimal (or, at the very least, it's a *huge* discouragement to a really useful web UI pattern). My concern isn't really about the global history, but about the UI that shows it. I certainly don't think the way visited links are colored should change (at least I don't think so; I admit to not having given it deep thought). It seems that what I'm really arguing is that the particular *UI* we're talking about shouldn't be directly tied to the global history. I have no idea how much more complex that makes this, though!
Yes, I agree with Rob -- ideally we could consider the behavior of the global UI and visited links independently. This is perhaps obvious, but to make it explicit -- the contrast here is with pushState. The authorial choice between pushState and replaceState is often a judgement call as to the value to the user of being able to go back to the previous state at a later time versus not cluttering the history UI (both back button and global UI). Rob and my argument is that page authors who are mindful of this choice will be using pushState in cases where recording a separate entry in both places is desirable, and that the value to the large majority of apps in being able to record an entry in the global history UI but not in the back button is low, especially when compared to the value of being able to _avoid_ recording an entry in the global UI. It would be informative to see more concrete counterexamples.
> the value of being able to _avoid_ recording an entry in the global UI To be more precise, this should read "avoid recording an _additional_ entry in the global UI" -- it would ideally update the previous entry (with the recognition that this may require the introduction of a concept of "global UI entry" that doesn't currently exist).
Other browser behavior: Chrome 28: Both location.replace and history.replaceState create new entries in the global history UI. Chrome 30: location.replace updates the existing entry, history.replaceState creates new entries Opera 12: Neither location.replace nor history.replaceState create new entries (but neither update the existing entry) Opera 15: Sometimes location.replace creates a new entry, sometimes it updates an existing one (no idea what the criteria are). history.replaceState always creates a new entry. Safari 6: Both location.replace and history.replaceState create new entries in the global history UI. I haven't been able to test IE.
If this is just about the Firefox UI, over to UI-land.
Component: Document Navigation → Places
Product: Core → Toolkit
Attached image Screenshot of History UI (deleted) —
Here's what the history UI looks like after panning and zooming some other major map webapps (new Google Maps and Nokia Here).
An use case where it is, imho, clearly wrong: Discourse. They assign a URL for each post in thread so the user is return the post in thread where he was before he left. Browsing the a thread in discourse renders recent history useless. See for yourselves, just scroll down this thread: http://try.discourse.org/t/funny-pictures-keep-em-clean-folks/62
Status: UNCONFIRMED → NEW
Ever confirmed: true
OS: Windows 7 → All
Hardware: x86 → All
Version: 12 Branch → Trunk
Priority: -- → P3
So is this stranded here, or was it pushed to UI-land?
Severity: normal → S3

Jake, this is a polite reminder that this is our professional working environment as much as it is our issue tracker, and I'm asking you to refrain from making further comments that don't move this bug towards a resolution.

Duplicate of this bug: 1816054

The severity field for this bug is set to S3. However, the following bug duplicate has higher severity:

:mak, could you consider increasing the severity of this bug to S2?

For more information, please visit auto_nag documentation.

Flags: needinfo?(mak)
Flags: needinfo?(mak)
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: