Bug 6309 - multiple problems prevent bookmarking/back button technique for AJAX/DHTML applications from working
Summary: multiple problems prevent bookmarking/back button technique for AJAX/DHTML ap...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 420+
Hardware: All OS X 10.4
: P1 Major
Assignee: Anders Carlsson
URL:
Keywords: InRadar
: 7516 8522 9184 9266 9281 9711 (view as bug list)
Depends on: 7058
Blocks: 9610 6628
  Show dependency treegraph
 
Reported: 2005-12-31 02:46 PST by Brad Neuberg
Modified: 2006-10-02 19:52 PDT (History)
14 users (show)

See Also:


Attachments
Test case (910 bytes, text/html)
2006-01-31 20:35 PST, David Kilzer (:ddkilzer)
no flags Details
Patch v1 (probably not final fix) (756 bytes, patch)
2006-01-31 21:59 PST, David Kilzer (:ddkilzer)
darin: review-
Details | Formatted Diff | Diff
Testcase using Back button (1.20 KB, text/html)
2006-02-08 01:30 PST, Sjoerd Mulder
no flags Details
Patch (19.94 KB, patch)
2006-06-01 07:51 PDT, Anders Carlsson
darin: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Brad Neuberg 2005-12-31 02:46:39 PST
I'm the designer of the Really Simple History library, an open source framework
that makes it possible to support bookmarking and the back/forward buttons in
AJAX/DHTML applications (for an intro to the framework see an O'Reilly Net
article at
http://www.onjava.com/pub/a/onjava/2005/10/26/ajax-handling-bookmarks-and-back-button.html).
This framework is being integrated into the Dojo project
(http://dojotoolkit.org), a popular library for AJAX/DHTML applications, and was
recently brought into Google for their own applications.

Unfortunately, RSH does not support Safari/WebKit, primarily because it is
impossible to do so; RSH works on Firefox and IE. I spent about two weeks full
time attempting to explore work arounds for Safari, but it turns out to be
impossible for a number of reasons I blogged about here:
http://codinginparadise.org/weblog/2005/09/safari-no-dhtml-history-possible.html

The RSH home page: http://codinginparadise.org/projects/dhtml_history/README.html

Here is what Safari/WebKit _should_ do:
1) If JavaScript updates the location of the web page to an anchor:
window.location.href = "#some_new_location"

The URL location toolbar _should_ update with the new location (and the browser
throbber should stop spinning; it currently goes into a continious loop in some
conditions). In addition, every time JavaScript updates the location, this entry
should be placed into the browser's history, so that it affects the back and
forward buttons, just like Firefox. In addition, if I create a timer to check
the location of the page:

var checkLocation = function(){
  var newLoc = document.location.href;
  // do something with the hash location
};
window.setInterval(checkLocation, 200);

It _should_ always be able to see the _current_ location of the document,
including the new hash value, and _should_ return the hash value as well
(sometimes you don't get the hash value).

The ability to do bookmarking and back button support is very important to the
kind of large scale AJAX/DHTML apps that are appearing, such as the new AJAX
Yahoo Mail, the new Google RSS Reader, and others. Just as a side note, I should
let you know that more and more AJAX/DHTML developers are abandoning Safari as a
platform for these advanced apps, which does not bode well for Safari. In
addition, many of the ones doing this are the ones creating the frameworks and
libraries that others will use, which will lock Safari/WebKit even more out of
some of the really cool things that are going on on the web right now.

Feel free to contact me at bkn3@columbia.edu if you have any questions; many
people I know really want to see this bug fixed.
Comment 1 Dave Hyatt 2006-01-31 14:48:59 PST
If you have any simple reduced test cases (if you can host them) would be very helpful.  The issues with window.location.href are pretty well known, but reading your linked blog entry, I didn't quite follow what your issue was with iframes/forms.
Comment 2 Dave Hyatt 2006-01-31 14:58:22 PST
Inifnite loop = p1.

This is probably related to 6958.
Comment 3 Brad Neuberg 2006-01-31 15:08:32 PST
Iframe history support is more of a hack to support history and bookmarking on IE. If you were to work exactly like Firefox, which is much better at these things, it would be better.

Here's what Firefox does:

1) If you change the window.location.href to an anchor:

window.location.href = "#foobar"

Then this anchor should go into the browsers history. I.e., if I start at the website http://foobar.com, and add three anchors:

window.location.href = "#location1";
window.location.href = "#location2";
window.location.href = "#location3";

there should now be four things on the history stack:
http://foobar.com
http://foobar.com#location1
http://foobar.com#location2
http://foobar.com#location3

If I hit the back button, the browser should jump through each of these locations, changing the browser's location bar to show each of them.

At the same time, if I have a JavaScript interval timer running checking the browser's location:

window.setInterval(function(){
  var location = window.location.href;
  // check the location for a change
}, 200)

this timer should be able to see anchor location changes.

This is exactly how Firefox works, by the way, and it is the basis for AJAX history support in that browser.
Comment 4 Brad Neuberg 2006-01-31 15:10:04 PST
By the way, it doesn't matter how you handle iframes and history if you support the process above. IE also doesn't work correctly with updating the anchor location (it doesn't always go into history), so IE needed to use a deeper hack using hidden iframes to register history events (it's nasty).
Comment 5 Dave Hyatt 2006-01-31 15:18:50 PST
I'm pretty sure we intended to put # URLS into the session history.  Probably just a bug (or design flaw) that we lose intermediate ones.  Our session history code is 3 years old and Firefox's is 7, so it's unsurprising that we have more bugs. :)

Comment 6 Dave Hyatt 2006-01-31 15:20:28 PST
BTW whenever you have problems with Safari/WebKit, you can come to #webkit on Freenode to ask for help.  No need to beat against something for 2 weeks when you can ask for help from the actual developers.
Comment 7 David Kilzer (:ddkilzer) 2006-01-31 20:35:31 PST
Created attachment 6173 [details]
Test case

Test case for setting window.location.href using relative links.
Comment 8 David Kilzer (:ddkilzer) 2006-01-31 21:59:17 PST
Created attachment 6174 [details]
Patch v1 (probably not final fix)

Poking around kjs_window.cpp, I found that the change in this patch would fix the attached test case (Attachment 6173 [details]).

The change from calling scheduleLocationChange() to changeLocation() causes the Redirection Timer not to spin endlessly after the test case is done.

The change from "!userGesture" to "false" in the third argument causes the history to be written for each change to the URL fragment/reference (#locationX).

I have no idea if this is the correct fix, though, since it takes a while for the "Back" history button to update after the test case is run, and the test case seems to reload the entire page every time.  It seems like there is a missing optimization where loading a URL fragment (#locationX) on the same page shouldn't force the entire page to be reloaded.
Comment 9 Darin Adler 2006-01-31 22:22:42 PST
Comment on attachment 6174 [details]
Patch v1 (probably not final fix)

We definitely can't do this. It sill introduce all sorts of problems to try to actually change the location right away.

Sadly, I don't know exactly which problem it will cause -- it would be great to have the test cases, but I don't think we do.
Comment 10 Trey Matteson 2006-01-31 23:13:32 PST
I would expect that passing "false" instead of "!userGesture", as proposed in the patch, would break a large number of sites that implement redirects using pure JS.  In fact, the attached test case of changing the location in onload() is a perfect example.  We solved a lot of conflicting bugs when we realized the existing "userGesture" flag in khtml was the way to distinguish whether window.location=foo should add to the history.

You might try a test case that acts in response to a user event to see if it changes the behavior of TOT.  If I'm right, I realize this situation might not be good enough to meet your original goals.
Comment 11 Brad Neuberg 2006-02-01 11:33:01 PST
By the way, setting an anchor location should _not_ reload the page, reset the DOM, etc. Other browsers don't do this.
Comment 12 Darin Adler 2006-02-02 10:20:09 PST
(In reply to comment #11)
> By the way, setting an anchor location should _not_ reload the page, reset the
> DOM, etc. Other browsers don't do this.

Good point. Maybe we can break that part of this out into a separate bug report. This one seems to be about a set of related issues, and so it's a little hard to understand and fix.
Comment 13 Darin Adler 2006-02-02 10:21:03 PST
In general, the most helpful thing here would be to break this up into discrete pieces that are each easy to understand.
Comment 14 Sjoerd Mulder 2006-02-03 00:23:20 PST
This bug is also in Radar: <rdar://4432143>
Comment 15 David Kilzer (:ddkilzer) 2006-02-04 12:25:51 PST
(In reply to comment #12)
> (In reply to comment #11)
> > By the way, setting an anchor location should _not_ reload the page, reset the
> > DOM, etc. Other browsers don't do this.
> 
> Good point. Maybe we can break that part of this out into a separate bug
> report. This one seems to be about a set of related issues, and so it's a
> little hard to understand and fix.

Actually, as far as I can tell (using ethereal to trace network activity), the page is NOT reloaded during the test case.  (It's only loaded once to load the page in the first place.)  It may look like it is reloaded because the spinner (via RedirectionTimer) is fired up, but WebKit doesn't actually go back out to the network to request the page.

This means that two things should happen to fix this bug, e.g., when JavaScript requests a '#name' URL on the same page:

1. The RedirectionTimer should NOT fire when requesting a '#name' URL on the same page.

2. The current URL should be pushed onto the history stack before jumping to the new '#name' URL.  (This could be taken care of by introducing a local 'lockHistory' variable that is always false for a '#name' URL on the same page regardless of source, but !userGesture otherwise.) 

I just tested the attached Test case (Attachment 6173 [details]) on MSIE 6, and it's in "denial" about additional history entries when the "Test case" link is clicked after opening this bug (the count of "3" comes from the default page opening when MSIE 6 starts, the Bug 6309 page opening, then the Attachment 6173 [details] opening):

One
Two
Three
Status: FAIL initialLength = 3 window.history.length = 3

However, if one right-clicks on the "Test case" link and opens it in a new window, the test passes!  What the heck?!
Comment 16 David Kilzer (:ddkilzer) 2006-02-04 19:38:13 PST
(In reply to comment #15)
> 1. The RedirectionTimer should NOT fire when requesting a '#name' URL on the
> same page.

Hmm...it would seem that Bug 3552 covers this issue!
Comment 17 David Kilzer (:ddkilzer) 2006-02-07 21:21:30 PST
This bug was fixed with the commit for Bug 7058 (confirmed locally by applying the patch in reverse and rebuilding r12652), so marking it a duplicate of that bug.  Bug 3552 was also fixed at the same time.

Reporter, please verify that this was fixed with nightly r12598 or newer.

Should a test case be prepared and checked in for WebKit to make sure this doesn't regress?


*** This bug has been marked as a duplicate of 7058 ***
Comment 18 Sjoerd Mulder 2006-02-08 01:26:59 PST
This bug is definitly NOT a duplicate of bug 7058!
This bug is about Safari supporting back / forward button in AJAX applications, I agree it's come one step closer by fixing bug 7058 but it still has some problems! Attaching a better testcase! (where you actually have to use the history by pressing Back)
Comment 19 Sjoerd Mulder 2006-02-08 01:30:50 PST
Created attachment 6339 [details]
Testcase using Back button
Comment 20 Brad Neuberg 2006-02-08 01:48:12 PST
Here is a test page using the Really Simple History library which works on IE and Firefox:

http://www.onjava.com/onjava/2005/10/26/examples/examples/oreillymail/oreillymail.html

You can use this to make sure that your fixes work. This is a simple, fake AJAX/DHTML email client put together to show AJAX history, bookmarking, and back/button support.

What you should do is click around on the left hand sidebar; make sure that the page location changes at the top, showing a new anchor location. Then, press the back and forward buttons, and make sure that the history changes in the anchor bar. Press the reload button and make sure the page stays the same, then press back and forward again to make sure the history is still there. Manually change the anchor location to a new place (such as #drafts), then press enter; the page should correctly change; continue using the history to make sure this manual change doesn't break things, by clicking on the sidebar more. Then, go to http://google.com in this window, let Google load, and then press the back button to jump back to the test page; you should be on the last history location you left it at. Continue pressing the back button to jump through your history state, ensuring that leaving the page and then returning has not cleared out your AJAX history.

This all works in IE and Firefox. It should work in Safari. Google has adopted this library for some of their own projects, so getting it working in Safari would be nice.
Comment 21 David Kilzer (:ddkilzer) 2006-02-08 05:06:12 PST
Adding Bug 7058 to depends-on list since it fixed part of the issue originally described in the description of this bug.

I apologize for missing the "location.hash does not get updated" issue when I wrote the initial test case (Attachment 6173 [details]), but "(sometimes you don't get the hash value)" in the original description didn't inform me that "location.hash" wasn't getting updated.  I thought that meant the hash value wasn't available in location.href.

In the future if you want Software X or Web Site Y to work with WebKit and there are multiple individual issues that are able to be identified, please set up a "Master" or "Tracking" bug (like Bug 6628 for Backbase or Bug 6627 for TinyMCE) and then reference existing bugs or create additional bugs (with test cases!) that block the master/tracking bug.  Thanks!
Comment 22 Kevin Newman 2006-04-11 11:10:57 PDT
Hello. I just wanted to let you know of another project that relies on this functionality to implement a history for AJAX and Flash RIAs. You can find it a simple test page here: http://www.unfocus.com/projects/source/historykeeper.html and another one using flash here: http://www.unfocus.com/projects/source/#About .

These pages are not always stable, as they are WIP pages, I will try to send some specific bug test cases when I find time (increasingly scarce time).

BTW, there is a bit of a workaround for this that has been implemented in my script, which is to watch the history.length property. This property seems to incorrectly change as you go back through the history (is this another bug?).

I mentioned on webkit-dev mailing list, that I think this is kind of a missing feature on the web platform. It would be great if we could get some kind of more robust history interface in javascript for AJAX and Flash RIAs, since they are becoming more popular (maybe this is a feature request?). Even just a new (onHistoryChange or something) event on the History or location element would be good.

Anyway, if there is anything I can do to help (test cases, help with the dojo scripts, etc.), please let me know. I have no mac osx Tiger to test with unfortunately though..
Comment 23 Darin Adler 2006-04-11 12:02:37 PDT
The most helpful thing anyone could do about this bug would be to write some small specific bug reports. This giant one about a whole category of problems is very difficult to work on. Individual specific ones, each with a small, specific set of steps would be a lot easier to resolve.
Comment 24 Anders Carlsson 2006-05-27 05:03:29 PDT
I'm working on this. I have a patch which fixes most problems, it just needs some more testing
Comment 25 Darin Adler 2006-05-30 10:57:44 PDT
Anders says he's working on this, so assigning to him to reflect that fact.
Comment 26 Anders Carlsson 2006-06-01 07:51:59 PDT
Created attachment 8642 [details]
Patch

This patch fixes the issues described above
Comment 27 Darin Adler 2006-06-01 13:00:36 PDT
Comment on attachment 8642 [details]
Patch

Since == already works on KURL, it seems to me that we only need a function that does the "== ignoring hash" operation. Also, for symmetric operations like equality, I prefer functions to members. So I'd like to see the isEqualTo function renamed and remove the boolean parameter and be a "free" function rather than a member function.

In historyURL: we should not use braces around single-line if statements.

Otherwise looks good, and those are nitpicks, so r=me.
Comment 28 David Kilzer (:ddkilzer) 2006-06-01 17:38:34 PDT
*** Bug 8522 has been marked as a duplicate of this bug. ***
Comment 29 David Kilzer (:ddkilzer) 2006-06-02 09:53:05 PDT
*** Bug 7516 has been marked as a duplicate of this bug. ***
Comment 30 David Kilzer (:ddkilzer) 2006-06-02 09:57:52 PDT
*** Bug 9184 has been marked as a duplicate of this bug. ***
Comment 31 David Kilzer (:ddkilzer) 2006-06-02 20:43:18 PDT
*** Bug 9281 has been marked as a duplicate of this bug. ***
Comment 32 David Kilzer (:ddkilzer) 2006-06-02 20:51:00 PDT
*** Bug 9266 has been marked as a duplicate of this bug. ***
Comment 33 Anders Carlsson 2006-07-09 14:35:22 PDT
*** Bug 9711 has been marked as a duplicate of this bug. ***