Skip to content

Commit 330416f

Browse files
committed
Added some more demos. Fixed safari bug replaceState bug. Now need to fix safari load bug. Also cleaned url functions.
1 parent e366806 commit 330416f

File tree

9 files changed

+437
-196
lines changed

9 files changed

+437
-196
lines changed

README.md

+19-10
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,18 @@ Thanks! every bit of help really does make a difference. Again thank you.
162162

163163
### HTML5 Browsers
164164

165-
- Chrome 8,9
165+
- Chrome 8,9,10
166166
- Firefox 4
167167
- Safari 5
168+
- Safari iOS 4.3
168169

169170
### HTML4 Browsers
170171

171-
- Safari iOS 4.2.1
172-
- Opera 10,11
173-
- Firefox 3
174172
- IE 6,7,8
173+
- Firefox 3
174+
- Opera 10,11
175+
- Safari 4
176+
- Safari iOS prior to version 4.3
175177

176178

177179
## Exposed API
@@ -200,11 +202,17 @@ Thanks! every bit of help really does make a difference. Again thank you.
200202
## Notes on Compatibility
201203

202204
- History.js **solves** the following browser bugs:
203-
- Chrome does not retrieve the correct state data when traversing back to the initial state
204-
- Safari 5 and Safari iOS 4.2.1 do not fire the `onpopstate` event when the hash has changed, preventing HTML4 states from being picked up.
205-
- Safari iOS 4.2.1 HTML5 History API works perfectly; however the actual back buttons of the browser fail. As such we use the HTML4 fallback for it allowing it to work perfectly with the same API.
206-
- MSIE 6 and 7 sometimes do not actually apply hash-changes
207-
- Non-Opera HTML4 browsers sometimes fail when the hash is not `urlencoded`
205+
- HTML5 Browsers
206+
- Chrome 8 and 9 (fixed in 10) do not contain the correct state data when traversing back to the initial state
207+
- Safari 5 and Safari iOS 4 do not fire the `onpopstate` event when the hash has changed unlike the other browsers
208+
- Safari 5 and Safari iOS 4 fail to return to the correct state once a hash is replaced by a `replaceState` call / [bug report](https://bugs.webkit.org/show_bug.cgi?id=56249)
209+
- Safari 5 and Safari iOS 4 sometimes fail to apply the state change under busy conditions / [bug report](https://bugs.webkit.org/show_bug.cgi?id=42940)
210+
- Google Chrome 8,9,10 and Firefox 4 prior to the RC will always fire `onpopstate` once the page has loaded / [change recommendation](http://hacks.mozilla.org/2011/03/history-api-changes-in-firefox-4/)
211+
- Safari iOS 4.0, 4.1, 4.2 have a working HTML5 History API - although the actual back buttons of the browsers do not work, therefore we treat them as HTML4 browsers
212+
- HTML4 Browsers
213+
- Old browsers like MSIE 6,7 and Firefox 2 does not have a hashchange event
214+
- MSIE 6 and 7 sometimes do not apply a hashchange even it was told to (requiring a second call to the apply function)
215+
- Non-Opera HTML4 browsers sometimes do not apply the hash when the hash is not `urlencoded`
208216
- State data will always contain the State's title and url at: `data.title` and `data.url`
209217
- State data and title will not persist if the page was closed then re-opened, or navigated to another website then back - this is expected/standard functionality
210218
- State titles will always be applied to the `document.title` if set
@@ -221,7 +229,8 @@ Thanks! every bit of help really does make a difference. Again thank you.
221229
- Added Zepto adapter thanks to [Matt Garret](http://twitter.com/#!/matthewgarrett)
222230
- The readme now references the supported versions of the libraries we use
223231
- Updated vendors to the most recent copies. jQuery 1.5.1 and Mootools 1.3.1
224-
- Reverted iOS Safari 4.2.1 to a HTML4 Browser
232+
- Reverted versions of iOS prior to version 4.3 to be HTML4 browsers, iOS 4.3 is a HTML5 browser
233+
- Fixed issue with extra state being inserted on Safari 5 requiring an extra click on the back button to go home. [Reported](https://github.com/balupton/history.js/issues#issue/17) by [Rob Madole](http://robmadole.com/)
225234
- **B/C BREAK:** StateChange now only fires if the state has changed, it no longer fires on init. This is following the [Firefox 4 History API Changes](http://hacks.mozilla.org/2011/03/history-api-changes-in-firefox-4/) which we agree with - this breaks standard, but makes more sense.
226235

227236
- v1.5.0 - February 12 2011

demo/bcherry.html

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
2+
<!DOCTYPE html>
3+
<html lang="en">
4+
<head>
5+
<meta charset="utf-8" />
6+
7+
<title>WebKit is Dropping HTML5 "popstate" Events</title>
8+
9+
<link rel="stylesheet" href="/static/lib/css/blueprint/blueprint.min.css" media="screen, projection" />
10+
<link rel="stylesheet" href="/static/lib/css/blueprint/print.min.css" media="print" />
11+
<!--[if lt IE 8]>
12+
<link rel="stylesheet" href="/static/lib/css/blueprint/ie.min.css" media="screen, projection">
13+
<![endif]-->
14+
<link href="/static/lib/css/bcherry.css" rel="stylesheet" media="screen" />
15+
<style>
16+
#n {
17+
font-size: 48px;
18+
}
19+
p {
20+
padding: 0 20px;
21+
}
22+
</style>
23+
24+
<script type="text/javascript" src="../vendor/jquery.js"></script>
25+
<script type="text/javascript" src="../scripts/uncompressed/history.adapter.jquery.js"></script>
26+
<script type="text/javascript" src="../scripts/uncompressed/history.js"></script>
27+
28+
</head>
29+
<body>
30+
<div id="n"></div>
31+
<p>There's a bug in the HTML5 "popstate" event, as implemented in WebKit (Safari and Chrome). View this page in one of those browsers. Your browser has had history entries added from #0 to #19 (you should start at #19). Hitting back/forward will navigate through these. On each URL, the large number above should reflect the hash value. If you hit back/forward quickly, you'll notice that your number gets out of sync with the URL. This is because WebKit is dropping popstate events (they are not firing). It seems to happen when outbound network requests are in progress when the user navigates in their browser happens. In this case, your browser is downloading an image that takes 1s to serve on every popstate, so you'll have to wait 1s between backs/forwards to have the feature work correctly. You could also cause constant network traffic by putting an image download in a setInterval, in which case your popstate events will never fire. This implementation simulates an AJAX application that makes a network request when you navigate between URLs using pushState/popstate. View the source for more info.</p>
32+
<p>This was filed as <a href="https://bugs.webkit.org/show_bug.cgi?id=42940">Bug 42940</a> with WebKit on July 24, 2010. The Firefox 4 beta does not have this bug, which is good news.</p>
33+
<p>This is put together by <a href="http://www.adequatelygood.com">Ben Cherry</a>. Ben is a front-end engineer at <a href="http://twitter.com/">Twitter</a>, and you can follow him at <a href="http://twitter.com/bcherry">@bcherry</a>.</p>
34+
<script>
35+
// Bind to popstate
36+
$(window).bind("statechange", function(e) {
37+
var State = window.History.getState();
38+
39+
// log that this event was fired, and the current URL
40+
if (window.console && window.console.log) {
41+
console.log("popstate", State, window.location.href);
42+
}
43+
// update the page
44+
$("#n").text(State.data.n);
45+
46+
// Make an outbound image request that will take 1s. This request seems to be the cause of dropped popstates.
47+
// Removing this, or replacing it with something else, avoids the issue. Even if it's replaced with slow, blocking code (i.e. 1s of execution) events are not dropped.
48+
(new Image()).src = "http://www.bcherry.net/playground/pushstate.jpg";
49+
});
50+
51+
// Seed the browser history
52+
for (var i = 0; i < 20; i++) {
53+
window.History.pushState({n:i}, i, "?" + i);
54+
$("#n").text(i);
55+
}
56+
</script>
57+
</body>
58+
</html>

demo/chrome.html

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<html>
2+
<head>
3+
<title>Chrome History API Data Artifact</title>
4+
</head>
5+
<body>
6+
<p>This demo demonstrates an issue with Google Chrome versions 8-10 (possibly 11) where if you push a state with data, then do history.back to the initial state, the event.state will contain the pushed states data instead of being null.</p>
7+
<p>Note: The issue requires a clean history list, as such this should always be opened in a new tab/window where there are no prior history items.</p>
8+
<p>Reported by <a href="http://balupton.com">Benjamin Lupton</a> author of <a href="http://github.com/balupton/history.js">History.js</a></p>
9+
<button id="bug">bug</button>
10+
<button id="reset">reset</button>
11+
<textarea id="log" style="width:100%;height:200px;margin-top:1em;"></textarea>
12+
<script type="text/javascript">
13+
(function(){
14+
15+
window.onpopstate = function(event) {
16+
var message = ("onpopstate: location: " + document.location.href + ", data: " + JSON.stringify(event.state));
17+
document.getElementById('log').innerHTML += message+"\n\n";
18+
};
19+
20+
document.getElementById('bug').onclick = function(){
21+
setTimeout(function(){
22+
history.pushState({state:'new'},'New State','?new');
23+
},1e3);
24+
25+
setTimeout(function(){
26+
history.back();
27+
},2e3);
28+
};
29+
30+
document.getElementById('reset').onclick = function(){
31+
document.location.href = document.location.href.replace(/[\#\?].*/,"");
32+
};
33+
34+
})();
35+
</script>
36+
</body>
37+
</html>
File renamed without changes.

demo/native.html

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<html>
2+
<head>
3+
<title>HTML5 History API Demo</title>
4+
</head>
5+
<body>
6+
<textarea id="log" style="width:100%;height:400px;margin:1em;"></textarea>
7+
<div id="url" style="border:1px black dotted;height:1em;margin:1em;"></div>
8+
<div id="buttons" style="margin:1em;"></div>
9+
<script type="text/javascript">
10+
var $url = document.getElementById('url'), $log = document.getElementById('log');
11+
12+
window.onpopstate = function(event) {
13+
var message =
14+
"onpopstate: "+
15+
"location: " + location.href + ", " +
16+
"data: " + JSON.stringify(event.state) +
17+
"\n\n"
18+
;
19+
20+
$url.innerHTML = location.href;
21+
$log.innerHTML += message;
22+
console.log(message);
23+
};
24+
25+
window.onhashchange = function(event) {
26+
var message =
27+
"onhashchange: "+
28+
"location: " + location.href + ", "+
29+
"hash: " + location.hash +
30+
"\n\n"
31+
;
32+
33+
$url.innerHTML = location.href;
34+
$log.innerHTML += message;
35+
console.log(message);
36+
};
37+
38+
// Prepare Buttons
39+
var
40+
buttons = document.getElementById('buttons'),
41+
scripts = [
42+
'history.pushState({state:1}, "State 1", "?state=1");',
43+
'history.pushState({state:2}, "State 2", "?state=2");',
44+
'history.replaceState({state:3}, "State 3", "?state=3");',
45+
'location.hash = Math.random();',
46+
'history.back();',
47+
'history.forward();',
48+
'document.location.href = document.location.href.replace(/[\#\?].*/,"");'
49+
],
50+
buttonsHTML = ''
51+
;
52+
53+
// Add Buttons
54+
for ( var i=0,n=scripts.length; i<n; ++i ) {
55+
var _script = scripts[i];
56+
buttonsHTML +=
57+
'<li><button onclick=\'javascript:'+_script+'\'>'+_script+'</button></li>';
58+
}
59+
buttons.innerHTML = buttonsHTML;
60+
</script>
61+
</body>
62+
</html>

demo/safari.html

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<html>
2+
<head>
3+
<title>Safari Hash ReplaceState History Traversal Bug</title>
4+
</head>
5+
<body>
6+
<p>This demo demonstrates an issue with Safari 5.0.4 (6533.20.27) handing of hashes and replace state. When a hash is set, and then replaced using replaceState the history list are then broken, when traversing back the hash does not change.</p>
7+
<p>Note: The issue requires a clean history list, as such this should always be opened in a new tab/window where there are no prior history items.</p>
8+
<p>Reported by <a href="http://balupton.com">Benjamin Lupton</a> author of <a href="http://github.com/balupton/history.js">History.js</a></p>
9+
<button id="bug">bug</button>
10+
<button id="workaround">workaround</button>
11+
<button id="reset">reset</button>
12+
<textarea id="log" style="width:100%;height:200px;margin-top:1em;"></textarea>
13+
<script type="text/javascript">
14+
(function(){
15+
16+
window.onpopstate = function(event) {
17+
var message = ("onpopstate: location: " + document.location.href);
18+
document.getElementById('log').innerHTML += message+"\n\n";
19+
};
20+
21+
window.onhashchange = function(event) {
22+
var message = ("onhashchange: location: " + document.location.href);
23+
document.getElementById('log').innerHTML += message+"\n\n";
24+
};
25+
26+
document.getElementById('bug').onclick = function(){
27+
setTimeout(function(){
28+
document.location.hash = Math.random();
29+
},1e3);
30+
31+
setTimeout(function(){
32+
history.replaceState(null,'','?blah');
33+
},2e3);
34+
35+
setTimeout(function(){
36+
history.back(); // should take us to the initial page, it doesn't
37+
},3e3);
38+
};
39+
40+
document.getElementById('workaround').onclick = function(){
41+
setTimeout(function(){
42+
history.pushState(null,'','#'+Math.random());
43+
},1e3);
44+
45+
setTimeout(function(){
46+
history.replaceState(null,'','?blah');
47+
},2e3);
48+
49+
setTimeout(function(){
50+
history.back(); // will take us to the initial page
51+
},3e3);
52+
};
53+
54+
document.getElementById('reset').onclick = function(){
55+
document.location.href = document.location.href.replace(/[\#\?].*/,"");
56+
};
57+
58+
})();
59+
</script>
60+
</body>
61+
</html>

scripts/uncompressed/history.html4.js

+1-44
Original file line numberDiff line numberDiff line change
@@ -39,49 +39,6 @@
3939
// ----------------------------------------------------------------------
4040
// Emulated Status
4141

42-
/**
43-
* _History.getInternetExplorerMajorVersion()
44-
* Get's the major version of Internet Explorer
45-
* @return {integer}
46-
* @license Public Domain
47-
* @author Benjamin Arthur Lupton <[email protected]>
48-
* @author James Padolsey <https://gist.github.com/527683>
49-
*/
50-
_History.getInternetExplorerMajorVersion = function(){
51-
var result = _History.getInternetExplorerMajorVersion.cached =
52-
(typeof _History.getInternetExplorerMajorVersion.cached !== 'undefined')
53-
? _History.getInternetExplorerMajorVersion.cached
54-
: (function(){
55-
var undef,
56-
v = 3,
57-
div = document.createElement('div'),
58-
all = div.getElementsByTagName('i');
59-
while (
60-
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
61-
all[0]
62-
);
63-
return v > 4 ? v : undef;
64-
})()
65-
;
66-
return result;
67-
};
68-
69-
/**
70-
* _History.isInternetExplorer()
71-
* Are we using Internet Explorer?
72-
* @return {boolean}
73-
* @license Public Domain
74-
* @author Benjamin Arthur Lupton <[email protected]>
75-
*/
76-
_History.isInternetExplorer = function(){
77-
var result = _History.isInternetExplorer.cached =
78-
(typeof _History.isInternetExplorer.cached !== 'undefined')
79-
? _History.isInternetExplorer.cached
80-
: (_History.getInternetExplorerMajorVersion() !== 0)
81-
;
82-
return result;
83-
};
84-
8542
/**
8643
* History.emulated
8744
* Which features require emulating?
@@ -600,7 +557,7 @@
600557
}
601558

602559
// Update HTML4 Hash
603-
if ( newStateHash !== html4Hash && newStateHash !== History.contractUrl() ) {
560+
if ( newStateHash !== html4Hash && newStateHash !== History.getShortUrl() ) {
604561
History.debug('History.pushState: update hash', newStateHash, html4Hash);
605562
History.setHash(newStateHash,false);
606563
return false;

0 commit comments

Comments
 (0)