Permalink
Browse files

v1.4.1 - Added HTML5 Supported for Safari 5 and Safari iOS 4.2.1

  • Loading branch information...
1 parent b0edf7a commit 04697acc6038bd7a7fc7e0dbe1c017ae572382e5 @balupton committed Feb 9, 2011
Showing with 7,663 additions and 64 deletions.
  1. +19 −13 README.md
  2. +4 −1 demo/html5.html
  3. +32 −31 scripts/compressed/history.min.js
  4. +88 −9 scripts/uncompressed/history.js
  5. +4 −2 tests/index.php
  6. +2 −8 tests/tests.js
  7. +7,514 −0 vendor/firebug-lite.js
View
32 README.md
@@ -1,4 +1,4 @@
-Welcome to History.js (v1.4.0 - February 10 2011)
+Welcome to History.js (v1.4.1 - February 10 2011)
==================
@@ -79,7 +79,7 @@ What's the deal with the UIDs used in the HTML4 States?
Is there a working demo?
- Sure is, give it a download and navigate to the demo directory in your browser :-)
-- If you are after something a bit more adventurous than a end-user demo, open up the tests directory in your browser and editor - it'll rock your world and show all the vast use cases that History.js supports. _Note: you will have to run a `git submodule init; git submodule update` prior to running the tests._
+- If you are after something a bit more adventurous than a end-user demo, open up the tests directory in your browser and editor - it'll rock your world and show all the vast use cases that History.js supports. _Note: you will have to [run a `git submodule init; git submodule update` and update the `tests/.htaccess` for your path] prior to running the tests._
## Download & Installation
@@ -120,17 +120,28 @@ Is there a working demo?
<script type="text/javascript" src="http://www.yourwebsite.com/history.js/scripts/compressed/history.min.js"></script>
+## Subscribe to Updates
+
+- For GitHub News Feed Updates:
+ - You can click the "watch" button up the top right of History.js's [GitHub Project Page](https://github.com/balupton/History.js)
+- For Email Updates:
+ - There is a subscription form within the demo
+- For Commit RSS/Atom Updates:
+ - You can subscribe via the [GitHub Commit Atom Feed](https://github.com/balupton/History.js/commits/master.atom)
+
+
## Browsers: Tested and Working In
### HTML5 Browsers
- Chrome 8,9
- Firefox 4
+- Safari 5
+- Safari iOS 4.2.1
### HTML4 Browsers
- Opera 10,11
-- Safari 5
- Firefox 3
- IE 6,7,8
@@ -162,7 +173,7 @@ Is there a working demo?
- State data will always contain the State's title and url at: `data.title` and `data.url`
- 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.
-- State titles will always be applied to the document.title if set.
+- State titles will always be applied to the `document.title` if set.
- ReplaceState functionality is emulated in HTML4 browsers by discarding the replaced state, so when the discarded state is accessed it is skipped using the appropriate `History.back()` / `History.forward()` call.
- History.js fixes a bug in Google Chrome where traversing back through the history to the home page does not return the correct state data.
- Setting a hash (even in HTML5 browsers) causes `onpopstate` to fire - this is expected/standard functionality.
@@ -174,6 +185,10 @@ Is there a working demo?
## Changelog
+- v1.4.1 - February 10 2011
+ - Added HTML History API Support for Safari 5 and Safari iOS 4.2.1
+ - Cleaned code a bit (mostly with unit tests)
+
- v1.4.0 - February 10 2011
- Unit Testing now uses [QUnit](http://docs.jquery.com/Qunit)
- Corrected Safari 5 Support
@@ -211,13 +226,4 @@ Is there a working demo?
## Todo for Upcoming Releases
- Normal: Style Demo
-- Normal: Add `History.queue`
- Minor: Add a compilation test to ensure `.debug = false` and no `History.log` calls exist.
-
-## Subscribe To Updates
-
-<form action="http://balupton.createsend.com/t/r/s/phujuu/" method="post" id="subForm">
-<label for="phujuu-phujuu">Email:</label>
-<input type="text" name="cm-phujuu-phujuu" id="phujuu-phujuu" />
-<input type="submit" value="Subscribe" />
-</form>
View
5 demo/html5.html
@@ -6,7 +6,10 @@
(function(){
window.onpopstate = function(event) {
- console.log("location: " + document.location + ", data: " + JSON.stringify(event.state));
+ console.log("onpopstate: location: " + document.location.href + ", data: " + JSON.stringify(event.state));
+ };
+ window.onhashchange = function(event) {
+ console.log("onhashchange: location: " + document.location.href);
};
setTimeout(function(){
View
63 scripts/compressed/history.min.js
@@ -5,34 +5,35 @@
Public Domain
@author Benjamin Lupton <contact@balupton.com>
*/
-(function(i,l){i.History=i.History||{};var k=i.console||l,h=i.document,c={},a=i.History,m=i.history;if(typeof a.emulated!=="undefined")throw Error("History.js has already been emulated...");a.init=function(){a.options={hashChangeCheckerDelay:100,busyDelay:250};a.debug=function(){a.debug.enable&&a.log.apply(a,arguments)};a.debug.enable=false;a.log=function(){var b=typeof k!=="undefined",d=h.getElementById("log"),e="\n"+arguments[0]+"\n",f;if(b){f=Array.prototype.slice.call(arguments);e=f.shift();typeof k.debug!==
-"undefined"?k.debug.apply(k,[e,f]):k.log.apply(k,[e,f])}f=1;for(n=arguments.length;f<n;++f){var g=arguments[f];if(typeof g==="object"&&typeof JSON!=="undefined")try{g=JSON.stringify(g)}catch(j){}e+="\n"+g+"\n"}if(d){d.value+=e+"\n-----\n";d.scrollTop=d.scrollHeight-d.clientHeight}else b||alert(e);return true};c.getInternetExplorerMajorVersion=function(){return c.getInternetExplorerMajorVersion.cached=typeof c.getInternetExplorerMajorVersion.cached!=="undefined"?c.getInternetExplorerMajorVersion.cached:
-function(){for(var b=3,d=h.createElement("div"),e=d.getElementsByTagName("i");d.innerHTML="<\!--[if gt IE "+ ++b+"]><i></i><![endif]--\>",e[0];);return b>4?b:void 0}()};c.isInternetExplorer=function(){return c.isInternetExplorer.cached=typeof c.isInternetExplorer.cached!=="undefined"?c.isInternetExplorer.cached:c.getInternetExplorerMajorVersion()!==0};a.emulated={pushState:!Boolean(i.history&&i.history.pushState&&i.history.replaceState&&navigator.vendor!=="Apple Computer, Inc."),hashChange:Boolean(!("onhashchange"in
-i||"onhashchange"in h)||c.isInternetExplorer()&&c.getInternetExplorerMajorVersion()<8)};c.isEmptyObject=function(b){for(var d in b)if(this.hasOwnProperty(d))return false;return true};c.cloneObject=function(b){if(b){b=JSON.stringify(b);b=JSON.parse(b)}else b={};return b};a.setHash=function(b,d){if(d!==false&&a.busy()){a.debug("History.setHash: we must wait",arguments);a.pushQueue({scope:a,callback:a.setHash,args:arguments,queue:d});return false}a.busy(true);var e=c.escapeHash(b);a.debug("History.setHash",
-this,arguments,"hash:",b,"adjustedHash:",e,"oldHash:",h.location.hash);h.location.hash=e;return b};a.getHash=function(){return c.unescapeHash(h.location.hash)};c.escapeHash=function(b){b=c.normalizeHash(b);if(/[^a-zA-Z0-9\/\-\_\%\.]/.test(b))b=escape(b);return b};c.unescapeHash=function(b){b=c.normalizeHash(b);if(/[\%]/.test(b))b=unescape(b);return b};c.normalizeHash=function(b){return b.replace(/[^#]*#/,"").replace(/#.*/,"")};a.extractHashFromUrl=function(b){b=String(b).replace(/([^#]*)#?([^#]*)#?(.*)/,
-"$2");return b=c.unescapeHash(b)};a.isTraditionalAnchor=function(b){b=a.extractHashFromUrl(b);return typeof h.getElementById(b)!=="undefined"};a.contractUrl=function(b){b=a.expandUrl(b);var d=h.location.protocol+"//"+(h.location.hostname||h.location.host);if(h.location.port)d+=":"+h.location.port;d+="/";return b=b.replace(d,"/")};a.expandUrl=function(b){b=b||"";if(!/[a-z]+\:\/\//.test(b))if(b.length===0||b.substring(0,1)==="?")b=h.location.href.replace(/[#\?].*/,"")+b;else{var d=h.getElementsByTagName("base"),
-e=null;e="";if(d.length===1){e=d[0];e=e.href;if(e[e.length-1]!=="/")e+="/";b=e+b.replace(/^\//,"")}else if(b.substring(0,1)==="."){d=h.location.href.replace(/[#\?].*/,"").replace(/[^\/]+$/,"");if(d[d.length-1]!=="/")d+="/";b=d+b}else{d=h.location.protocol+"//"+(h.location.hostname||h.location.host);if(h.location.port)d+=":"+h.location.port;d+="/";b=d+b.replace(/^\//,"")}}return b};a.expandState=function(b){b=b||{};b={data:b.data||{},url:a.expandUrl(b.url||""),title:b.title||""};b.data.title=b.data.title||
-b.title;b.data.url=b.data.url||b.url;return b};a.createStateObject=function(b,d,e){b={data:b,title:d,url:e};return b=a.expandState(b)};a.expandHash=function(b){var d=null;try{d=JSON.parse(b)}catch(e){var f=/(.*)\/uid=([0-9]+)$/.exec(b);if(f=f?String(f[2]||""):"")d=c.getStateByUid(f)||null;if(!d&&/\//.test(b)){b=a.expandUrl(b);d=a.createStateObject(null,null,b)}}return d=d?a.expandState(d):null};a.contractState=function(b){if(!b)return null;var d=null;if(b=c.cloneObject(b)){b.data=b.data||{};delete b.data.title;
-delete b.data.url;if(c.isEmptyObject(b)&&!b.title)d=a.contractUrl(b.url);else{d=JSON.stringify(b);var e;if(typeof c.hashesToUids[d]!=="undefined")e=c.hashesToUids[d];else for(;;){e=String(Math.floor(Math.random()*1E3));if(typeof c.uidsToStates[e]==="undefined")break}c.hashesToUids[d]=e;c.uidsToStates[e]=b;d=a.contractUrl(b.url)+"/uid="+e}}return d};c.uidsToStates={};c.hashesToUids={};c.getStateByUid=function(b){return c.uidsToStates[String(b)]||l};c.statesByUrl={};c.duplicateStateUrls={};c.statesByHash=
-{};c.savedStates=[];a.getState=function(){return c.getStateByIndex()};a.getStateHash=function(){return a.contractState(a.getState())};c.getStateByUrl=function(b){return c.statesByUrl[b]||l};c.getStateByHash=function(b){return c.statesByHash[b]||l};c.storeState=function(b){var d=a.contractState(b),e=c.getStateByUrl(b.url);if(typeof e!=="undefined")if(a.contractState(e)!==d)c.duplicateStateUrls[b.url]=true;c.statesByUrl[b.url]=c.statesByHash[d]=b;return true};c.isLastState=function(b){b=a.contractState(b);
-var d=a.getStateHash();return c.savedStates.length&&b===d};c.saveState=function(b){if(c.isLastState(b))return false;c.savedStates.push(b);return true};c.getStateByIndex=function(b){var d=null;return d=typeof b==="undefined"?c.savedStates[c.savedStates.length-1]:b<0?c.savedStates[c.savedStates.length+b]:c.savedStates[b]};c.stateUrlExists=function(b){return typeof c.statesByUrl[b]!=="undefined"};c.urlDuplicateExists=function(b){return typeof c.duplicateStateUrls[b]!=="undefined"};c.savedHashes=[];c.isLastHash=
-function(b){var d=c.getHashByIndex();return b===d};c.saveHash=function(b){if(c.isLastHash(b))return false;c.savedHashes.push(b);return true};c.getHashByIndex=function(b){var d=null;return d=typeof b==="undefined"?c.savedHashes[c.savedHashes.length-1]:b<0?c.savedHashes[c.savedHashes.length+b]:c.savedHashes[b]};c.stateHashExists=function(b){return typeof c.statesByHash[b]!=="undefined"};c.discardedHashes={};c.discardedStates={};c.discardState=function(b,d,e){a.debug("History.discardState",this,arguments);
-var f=a.contractState(b);c.discardedStates[f]={discardedState:b,backState:e,forwardState:d};return true};c.discardHash=function(b,d,e){a.debug("History.discardState",this,arguments);c.discardedHashes[b]={discardedHash:b,backState:e,forwardState:d};return true};c.discardedState=function(b){b=a.contractState(b);return c.discardedStates[b]||false};c.discardedHash=function(b){return c.discardedHashes[b]||false};c.recycleState=function(b){a.debug("History.recycleState",this,arguments);var d=a.contractState(b);
-c.discardedState(b)&&delete c.discardedStates[d];return true};a.queues=[];a.busy=function(b){a.debug("History.busy: called",arguments,a.busy.flag||l,a.queues);if(typeof b!=="undefined")a.busy.flag=b;else if(typeof a.busy.flag==="undefined")a.busy.flag=false;if(!a.busy.flag){clearTimeout(a.busy.timeout);var d=function(){if(!a.busy.flag)for(var e=a.queues.length-1;e>=0;--e){var f=a.queues[e];if(f.length!==0){f=f.shift();a.debug("History.busy: firing",f);f.callback.apply(f.scope||a,f.args||[]);a.busy.timeout=
-setTimeout(d,a.options.busyDelay)}}};a.busy.timeout=setTimeout(d,a.options.busyDelay)}return a.busy.flag};a.pushQueue=function(b){a.debug("History.pushQueue: called",arguments);a.queues[b.queue||0]=a.queues[b.queue||0]||[];a.queues[b.queue||0].push(b);return true};a.back=function(b){a.debug("History.back: called",arguments);if(b!==false&&a.busy()){a.debug("History.back: we must wait",arguments);a.pushQueue({scope:a,callback:a.back,args:arguments,queue:b});return false}a.busy(true);if(a.emulated.hashChange&&
-c.isInternetExplorer()){var d=a.getHash();setTimeout(function(){if(a.getHash()===d){a.debug("History.back: trying again");return a.back(false)}return true},a.options.hashChangeCheckerDelay*5)}m.go(-1)};a.forward=function(b){a.debug("History.forward: called",arguments);if(b!==false&&a.busy()){a.debug("History.forward: we must wait",arguments);a.pushQueue({scope:a,callback:a.forward,args:arguments,queue:b});return false}a.busy(true);if(a.emulated.hashChange&&c.isInternetExplorer()){var d=a.getHash();
-setTimeout(function(){if(a.getHash()===d){a.debug("History.forward: trying again");return a.forward(false)}return true},a.options.hashChangeCheckerDelay*5)}m.go(1)};a.go=function(b,d){a.debug("History.go: called",arguments);if(b>0)for(var e=1;e<=b;++e)a.forward(d);else if(b<0)for(e=-1;e>=b;--e)a.back(d);else throw Error("History.go: History.go requires a positive or negative integer passed.");return true};if(a.emulated.hashChange)a.Adapter.onDomLoad(function(){c.checkerFunction=null;if(c.isInternetExplorer()){var b=
-h.createElement("iframe");b.setAttribute("id","historyjs-iframe");b.style.display="none";h.body.appendChild(b);b.contentWindow.document.open();b.contentWindow.document.close();var d=null,e=null,f=false;c.checkerFunction=function(){if(f){a.debug("hashchange.checker: checker is running");return false}f=true;var g=a.getHash(),j=c.unescapeHash(b.contentWindow.document.location.hash);if(g!==d){d=g;if(j!==g){a.debug("hashchange.checker: iframe hash change","documentHash (new):",g,"iframeHash (old):",j);
-e=g;b.contentWindow.document.open();b.contentWindow.document.close();b.contentWindow.document.location.hash=c.escapeHash(g)}a.Adapter.trigger(i,"hashchange")}else if(j!==e){a.debug("hashchange.checker: iframe hash out of sync","iframeHash (new):",j,"documentHash (old):",g);e=j;a.setHash(j,false)}f=false;return true}}else{d=null;c.checkerFunction=function(){var g=a.getHash();if(g!==d){d=g;a.Adapter.trigger(i,"hashchange")}return true}}setInterval(c.checkerFunction,a.options.hashChangeCheckerDelay);
-return true});if(a.emulated.pushState){c.onHashChange=function(b){a.debug("_History.onHashChange",this,arguments);currentHash=unescape(a.extractHashFromUrl(b&&b.newURL||h.location.href));currentStateHashExits=currentStateHash=currentState=null;if(c.isLastHash(currentHash)){a.debug("_History.onHashChange: no change");a.busy(false);return false}c.saveHash(currentHash);currentState=a.expandHash(currentHash);if(!currentState){a.debug("_History.onHashChange: traditional anchor");a.Adapter.trigger(i,"anchorchange");
-a.busy(false);return false}if(c.isLastState(currentState)){a.debug("_History.onHashChange: no change");a.busy(false);return false}currentStateHash=a.contractState(currentState);a.debug("_History.onHashChange: ","currentStateHash",currentStateHash,"Hash -1",c.getHashByIndex(-1),"Hash -2",c.getHashByIndex(-2),"Hash -3",c.getHashByIndex(-3),"Hash -4",c.getHashByIndex(-4),"Hash -5",c.getHashByIndex(-5),"Hash -6",c.getHashByIndex(-6),"Hash -7",c.getHashByIndex(-7));var d=c.discardedState(currentState);
-if(d){a.debug("forwardState:",a.contractState(d.forwardState),"backState:",a.contractState(d.backState));if(c.getHashByIndex(-2)===a.contractState(d.forwardState)){a.debug("_History.onHashChange: go backwards");a.back(false)}else{a.debug("_History.onHashChange: go forwards");a.forward(false)}a.busy(false);return false}a.debug("_History.onHashChange: success hashchange");a.pushState(currentState.data,currentState.title,currentState.url,false);return true};a.Adapter.bind(i,"hashchange",c.onHashChange);
-a.pushState=function(b,d,e,f){a.debug("History.pushState",this,arguments);if(a.extractHashFromUrl(e))throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(f!==false&&a.busy()){a.debug("History.pushState: we must wait",arguments);a.pushQueue({scope:a,callback:a.pushState,args:arguments,queue:f});return false}a.busy(true);var g=a.createStateObject(b,d,e),j=a.contractState(g);a.getState();var o=a.getStateHash(),p=unescape(a.getHash());c.storeState(g);c.recycleState(g);
-if(h.title!==g.title){h.title=g.title;try{h.getElementsByTagName("title")[0].innerHTML=g.title}catch(q){}}a.debug("History.pushState: details","newStateHash:",j,"oldStateHash:",o,"html4Hash:",p);if(j===o){a.debug("History.pushState: no change",j);return false}if(j!==p){a.debug("History.pushState: update hash",j);a.setHash(j,false);return false}c.saveState(g);a.debug("History.pushState: trigger popstate");a.Adapter.trigger(i,"statechange");a.busy(false);return true};a.replaceState=function(b,d,e,f){a.debug("History.replaceState",
-this,arguments);if(a.extractHashFromUrl(e))throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(f!==false&&a.busy()){a.debug("History.replaceState: we must wait",arguments);a.pushQueue({scope:a,callback:a.replaceState,args:arguments,queue:f});return false}a.busy(true);var g=a.createStateObject(b,d,e),j=a.getState(),o=c.getStateByIndex(-2);c.discardState(j,g,o);a.pushState(g.data,g.title,g.url,false);return true};if(!h.location.hash||h.location.hash==="#")a.Adapter.onDomLoad(function(){a.debug("Internet Explorer Initial State Change Fix");
-var b=a.createStateObject({},"",h.location.href);a.pushState(b.data,b.title,b.url)});else if(!a.emulated.hashChange){a.debug("Firefox Initial State Change Fix");a.Adapter.onDomLoad(function(){c.onHashChange()})}}else{c.onPopState=function(b){a.debug("_History.onPopState",this,arguments);var d=unescape(a.getHash());if(d){var e=a.expandHash(d);if(e){a.debug("_History.onPopState: state anchor",d,e);a.replaceState(e.data,e.tite,e.url,false)}else{a.debug("_History.onPopState: traditional anchor",d);a.Adapter.trigger(i,
-"anchorchange");a.busy(false)}return false}d={};var f=e=null;d=null;b=b||{};if(typeof b.state==="undefined")if(typeof b.originalEvent!=="undefined"&&typeof b.originalEvent.state!=="undefined")b.state=b.originalEvent.state;else if(typeof b.event!=="undefined"&&typeof b.event.state!=="undefined")b.state=b.event.state;if(b.state===null)d=b.state;else if(typeof b.state!=="undefined"){e=a.expandUrl(h.location.href);d=c.getStateByUrl(e);e=c.urlDuplicateExists(e);d=typeof d!=="undefined"&&!e?d.data:b.state}else{e=
-a.expandUrl(h.location.href);if((d=c.getStateByUrl(e))&&e==d.url)d=d.data;else throw Error("Unknown state");}d=typeof d!=="object"||d===null?{}:d;e=d.title||"";f=d.url||h.location.href;d=a.createStateObject(d,e,f);if(c.isLastState(d)){a.debug("_History.onPopState: no change",d,c.savedStates);a.busy(false);return false}a.debug("_History.onPopState","newState:",d,"oldState:",c.getStateByUrl(a.expandUrl(h.location.href)),"duplicateExists:",c.urlDuplicateExists(a.expandUrl(h.location.href)));c.storeState(d);
-c.saveState(d);if(d.title)h.title=d.title;a.Adapter.trigger(i,"statechange");a.busy(false);return true};a.Adapter.bind(i,"popstate",c.onPopState);a.pushState=function(b,d,e,f){if(a.extractHashFromUrl(e))throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(f!==false&&a.busy()){a.debug("History.pushState: we must wait",arguments);a.pushQueue({scope:a,callback:a.pushState,args:arguments,queue:f});return false}a.busy(true);var g=a.createStateObject(b,d,e);
-c.storeState(g);m.pushState(g.data,g.title,g.url);a.Adapter.trigger(i,"popstate");return true};a.replaceState=function(b,d,e,f){if(a.extractHashFromUrl(e))throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(f!==false&&a.busy()){a.debug("History.replaceState: we must wait",arguments);a.pushQueue({scope:a,callback:a.replaceState,args:arguments,queue:f});return false}a.busy(true);var g=a.createStateObject(b,d,e);c.storeState(g);m.replaceState(g.data,g.title,
-g.url);a.Adapter.trigger(i,"popstate");return true}}};typeof a.Adapter!=="undefined"&&a.init()})(window);
+(function(i,l){i.History=i.History||{};var k=i.console||l,h=i.document,c={},b=i.History,m=i.history;if(typeof b.emulated!=="undefined")throw Error("History.js has already been emulated...");b.init=function(){b.options={hashChangeCheckerDelay:100,busyDelay:250};b.debug=function(){b.debug.enable&&b.log.apply(b,arguments)};b.debug.enable=false;b.log=function(){var a=typeof k!=="undefined",d=h.getElementById("log"),e="\n"+arguments[0]+"\n",f;if(a){f=Array.prototype.slice.call(arguments);e=f.shift();typeof k.debug!==
+"undefined"?k.debug.apply(k,[e,f]):k.log.apply(k,[e,f])}f=1;for(n=arguments.length;f<n;++f){var g=arguments[f];if(typeof g==="object"&&typeof JSON!=="undefined")try{g=JSON.stringify(g)}catch(j){}e+="\n"+g+"\n"}if(d){d.value+=e+"\n-----\n";d.scrollTop=d.scrollHeight-d.clientHeight}else a||alert(e);return true};c.getInternetExplorerMajorVersion=function(){return c.getInternetExplorerMajorVersion.cached=typeof c.getInternetExplorerMajorVersion.cached!=="undefined"?c.getInternetExplorerMajorVersion.cached:
+function(){for(var a=3,d=h.createElement("div"),e=d.getElementsByTagName("i");d.innerHTML="<\!--[if gt IE "+ ++a+"]><i></i><![endif]--\>",e[0];);return a>4?a:void 0}()};c.isInternetExplorer=function(){return c.isInternetExplorer.cached=typeof c.isInternetExplorer.cached!=="undefined"?c.isInternetExplorer.cached:c.getInternetExplorerMajorVersion()!==0};b.emulated={pushState:!Boolean(i.history&&i.history.pushState&&i.history.replaceState),hashChange:Boolean(!("onhashchange"in i||"onhashchange"in h)||
+c.isInternetExplorer()&&c.getInternetExplorerMajorVersion()<8)};c.isEmptyObject=function(a){for(var d in a)if(this.hasOwnProperty(d))return false;return true};c.cloneObject=function(a){if(a){a=JSON.stringify(a);a=JSON.parse(a)}else a={};return a};b.setHash=function(a,d){if(d!==false&&b.busy()){b.debug("History.setHash: we must wait",arguments);b.pushQueue({scope:b,callback:b.setHash,args:arguments,queue:d});return false}var e=c.escapeHash(a);b.debug("History.setHash",this,arguments,"hash:",a,"adjustedHash:",
+e,"oldHash:",h.location.hash);b.busy(true);h.location.hash=e;return a};b.getHash=function(){return c.unescapeHash(h.location.hash)};c.escapeHash=function(a){a=c.normalizeHash(a);if(/[^a-zA-Z0-9\/\-\_\%\.]/.test(a))a=escape(a);return a};c.unescapeHash=function(a){a=c.normalizeHash(a);if(/[\%]/.test(a))a=unescape(a);return a};c.normalizeHash=function(a){return a.replace(/[^#]*#/,"").replace(/#.*/,"")};b.extractHashFromUrl=function(a){a=String(a).replace(/([^#]*)#?([^#]*)#?(.*)/,"$2");return a=c.unescapeHash(a)};
+b.isTraditionalAnchor=function(a){a=b.extractHashFromUrl(a);return typeof h.getElementById(a)!=="undefined"};b.contractUrl=function(a){a=b.expandUrl(a);var d=h.location.protocol+"//"+(h.location.hostname||h.location.host);if(h.location.port)d+=":"+h.location.port;d+="/";return a=a.replace(d,"/")};b.expandUrl=function(a){a=a||"";if(!/[a-z]+\:\/\//.test(a))if(a.length===0||a.substring(0,1)==="?")a=h.location.href.replace(/[#\?].*/,"")+a;else{var d=h.getElementsByTagName("base"),e=null;e="";if(d.length===
+1){e=d[0];e=e.href;if(e[e.length-1]!=="/")e+="/";a=e+a.replace(/^\//,"")}else if(a.substring(0,1)==="."){d=h.location.href.replace(/[#\?].*/,"").replace(/[^\/]+$/,"");if(d[d.length-1]!=="/")d+="/";a=d+a}else{d=h.location.protocol+"//"+(h.location.hostname||h.location.host);if(h.location.port)d+=":"+h.location.port;d+="/";a=d+a.replace(/^\//,"")}}return a};b.expandState=function(a){a=a||{};a={data:a.data||{},url:b.expandUrl(a.url||""),title:a.title||""};a.data.title=a.data.title||a.title;a.data.url=
+a.data.url||a.url;return a};b.createStateObject=function(a,d,e){a={data:a,title:d,url:e};return a=b.expandState(a)};b.expandHash=function(a){var d=null;try{d=JSON.parse(a)}catch(e){var f=/(.*)\/uid=([0-9]+)$/.exec(a);if(f=f?String(f[2]||""):"")d=c.getStateByUid(f)||null;if(!d&&/\//.test(a)){a=b.expandUrl(a);d=b.createStateObject(null,null,a)}}return d=d?b.expandState(d):null};b.contractState=function(a){if(!a)return null;var d=null;if(a=c.cloneObject(a)){a.data=a.data||{};delete a.data.title;delete a.data.url;
+if(c.isEmptyObject(a)&&!a.title)d=b.contractUrl(a.url);else{d=JSON.stringify(a);var e;if(typeof c.hashesToUids[d]!=="undefined")e=c.hashesToUids[d];else for(;;){e=String(Math.floor(Math.random()*1E3));if(typeof c.uidsToStates[e]==="undefined")break}c.hashesToUids[d]=e;c.uidsToStates[e]=a;d=b.contractUrl(a.url)+"/uid="+e}}return d};c.uidsToStates={};c.hashesToUids={};c.getStateByUid=function(a){return c.uidsToStates[String(a)]||l};c.statesByUrl={};c.duplicateStateUrls={};c.statesByHash={};c.savedStates=
+[];b.getState=function(){return c.getStateByIndex()};b.getStateHash=function(){return b.contractState(b.getState())};c.getStateByUrl=function(a){return c.statesByUrl[a]||l};c.getStateByHash=function(a){return c.statesByHash[a]||l};c.storeState=function(a){var d=b.contractState(a),e=c.getStateByUrl(a.url);if(typeof e!=="undefined")if(b.contractState(e)!==d)c.duplicateStateUrls[a.url]=true;c.statesByUrl[a.url]=c.statesByHash[d]=a;return true};c.isLastState=function(a){a=b.contractState(a);var d=b.getStateHash();
+return c.savedStates.length&&a===d};c.saveState=function(a){if(c.isLastState(a))return false;c.savedStates.push(a);return true};c.getStateByIndex=function(a){var d=null;return d=typeof a==="undefined"?c.savedStates[c.savedStates.length-1]:a<0?c.savedStates[c.savedStates.length+a]:c.savedStates[a]};c.stateUrlExists=function(a){return typeof c.statesByUrl[a]!=="undefined"};c.urlDuplicateExists=function(a){return typeof c.duplicateStateUrls[a]!=="undefined"};c.savedHashes=[];c.isLastHash=function(a){var d=
+c.getHashByIndex();return a===d};c.saveHash=function(a){if(c.isLastHash(a))return false;c.savedHashes.push(a);return true};c.getHashByIndex=function(a){var d=null;return d=typeof a==="undefined"?c.savedHashes[c.savedHashes.length-1]:a<0?c.savedHashes[c.savedHashes.length+a]:c.savedHashes[a]};c.stateHashExists=function(a){return typeof c.statesByHash[a]!=="undefined"};c.discardedHashes={};c.discardedStates={};c.discardState=function(a,d,e){b.debug("History.discardState",this,arguments);var f=b.contractState(a);
+c.discardedStates[f]={discardedState:a,backState:e,forwardState:d};return true};c.discardHash=function(a,d,e){b.debug("History.discardState",this,arguments);c.discardedHashes[a]={discardedHash:a,backState:e,forwardState:d};return true};c.discardedState=function(a){a=b.contractState(a);return c.discardedStates[a]||false};c.discardedHash=function(a){return c.discardedHashes[a]||false};c.recycleState=function(a){b.debug("History.recycleState",this,arguments);var d=b.contractState(a);c.discardedState(a)&&
+delete c.discardedStates[d];return true};b.queues=[];b.busy=function(a){b.debug("History.busy: called: changing ["+(b.busy.flag||false)+"] to ["+(a||false)+"]",b.queues);if(typeof a!=="undefined")b.busy.flag=a;else if(typeof b.busy.flag==="undefined")b.busy.flag=false;if(!b.busy.flag){clearTimeout(b.busy.timeout);var d=function(){if(!b.busy.flag)for(var e=b.queues.length-1;e>=0;--e){var f=b.queues[e];if(f.length!==0){f=f.shift();b.debug("History.busy: firing",f);b.fireQueueItem(f);b.busy.timeout=
+setTimeout(d,b.options.busyDelay)}}};b.busy.timeout=setTimeout(d,b.options.busyDelay)}return b.busy.flag};b.fireQueueItem=function(a){return a.callback.apply(a.scope||b,a.args||[])};b.pushQueue=function(a){b.debug("History.pushQueue: called",arguments);b.queues[a.queue||0]=b.queues[a.queue||0]||[];b.queues[a.queue||0].push(a);return true};b.queue=function(a,d){if(typeof a==="function")a={callback:a};if(typeof d!=="undefined")a.queue=d;b.busy()?b.pushQueue(a):b.fireQueueItem(a);return true};b.back=
+function(a){b.debug("History.back: called",arguments);if(a!==false&&b.busy()){b.debug("History.back: we must wait",arguments);b.pushQueue({scope:b,callback:b.back,args:arguments,queue:a});return false}b.busy(true);if(b.emulated.hashChange&&c.isInternetExplorer()){var d=b.getHash();setTimeout(function(){if(b.getHash()===d){b.debug("History.back: trying again");return b.back(false)}return true},b.options.hashChangeCheckerDelay*5)}m.go(-1);return true};b.forward=function(a){b.debug("History.forward: called",
+arguments);if(a!==false&&b.busy()){b.debug("History.forward: we must wait",arguments);b.pushQueue({scope:b,callback:b.forward,args:arguments,queue:a});return false}b.busy(true);if(b.emulated.hashChange&&c.isInternetExplorer()){var d=b.getHash();setTimeout(function(){if(b.getHash()===d){b.debug("History.forward: trying again");return b.forward(false)}return true},b.options.hashChangeCheckerDelay*5)}m.go(1);return true};b.go=function(a,d){b.debug("History.go: called",arguments);if(a>0)for(var e=1;e<=
+a;++e)b.forward(d);else if(a<0)for(e=-1;e>=a;--e)b.back(d);else throw Error("History.go: History.go requires a positive or negative integer passed.");return true};if(b.emulated.hashChange)b.Adapter.onDomLoad(function(){c.checkerFunction=null;if(c.isInternetExplorer()){var a=h.createElement("iframe");a.setAttribute("id","historyjs-iframe");a.style.display="none";h.body.appendChild(a);a.contentWindow.document.open();a.contentWindow.document.close();var d=null,e=null,f=false;c.checkerFunction=function(){if(f){b.debug("hashchange.checker: checker is running");
+return false}f=true;var g=b.getHash(),j=c.unescapeHash(a.contentWindow.document.location.hash);if(g!==d){d=g;if(j!==g){b.debug("hashchange.checker: iframe hash change","documentHash (new):",g,"iframeHash (old):",j);e=g;a.contentWindow.document.open();a.contentWindow.document.close();a.contentWindow.document.location.hash=c.escapeHash(g)}b.Adapter.trigger(i,"hashchange")}else if(j!==e){b.debug("hashchange.checker: iframe hash out of sync","iframeHash (new):",j,"documentHash (old):",g);e=j;b.setHash(j,
+false)}f=false;return true}}else{d=null;c.checkerFunction=function(){var g=b.getHash();if(g!==d){d=g;b.Adapter.trigger(i,"hashchange")}return true}}setInterval(c.checkerFunction,b.options.hashChangeCheckerDelay);return true});if(b.emulated.pushState){c.onHashChange=function(a){b.debug("_History.onHashChange",this,arguments);currentHash=unescape(b.extractHashFromUrl(a&&a.newURL||h.location.href));currentStateHashExits=currentStateHash=currentState=null;if(c.isLastHash(currentHash)){b.debug("_History.onHashChange: no change");
+b.busy(false);return false}c.saveHash(currentHash);currentState=b.expandHash(currentHash);if(!currentState){b.debug("_History.onHashChange: traditional anchor");b.Adapter.trigger(i,"anchorchange");b.busy(false);return false}if(c.isLastState(currentState)){b.debug("_History.onHashChange: no change");b.busy(false);return false}currentStateHash=b.contractState(currentState);b.debug("_History.onHashChange: ","currentStateHash",currentStateHash,"Hash -1",c.getHashByIndex(-1),"Hash -2",c.getHashByIndex(-2),
+"Hash -3",c.getHashByIndex(-3),"Hash -4",c.getHashByIndex(-4),"Hash -5",c.getHashByIndex(-5),"Hash -6",c.getHashByIndex(-6),"Hash -7",c.getHashByIndex(-7));var d=c.discardedState(currentState);if(d){b.debug("forwardState:",b.contractState(d.forwardState),"backState:",b.contractState(d.backState));if(c.getHashByIndex(-2)===b.contractState(d.forwardState)){b.debug("_History.onHashChange: go backwards");b.back(false)}else{b.debug("_History.onHashChange: go forwards");b.forward(false)}b.busy(false);return false}b.debug("_History.onHashChange: success hashchange");
+b.pushState(currentState.data,currentState.title,currentState.url,false);return true};b.Adapter.bind(i,"hashchange",c.onHashChange);b.pushState=function(a,d,e,f){b.debug("History.pushState",this,arguments);if(b.extractHashFromUrl(e))throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(f!==false&&b.busy()){b.debug("History.pushState: we must wait",arguments);b.pushQueue({scope:b,callback:b.pushState,args:arguments,queue:f});return false}b.busy(true);var g=
+b.createStateObject(a,d,e),j=b.contractState(g);b.getState();var o=b.getStateHash(),p=unescape(b.getHash());c.storeState(g);c.recycleState(g);if(h.title!==g.title){h.title=g.title;try{h.getElementsByTagName("title")[0].innerHTML=g.title}catch(q){}}b.debug("History.pushState: details","newStateHash:",j,"oldStateHash:",o,"html4Hash:",p);if(j===o){b.debug("History.pushState: no change",j);return false}if(j!==p){b.debug("History.pushState: update hash",j);b.setHash(j,false);return false}c.saveState(g);
+b.debug("History.pushState: trigger popstate");b.Adapter.trigger(i,"statechange");b.busy(false);return true};b.replaceState=function(a,d,e,f){b.debug("History.replaceState",this,arguments);if(b.extractHashFromUrl(e))throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(f!==false&&b.busy()){b.debug("History.replaceState: we must wait",arguments);b.pushQueue({scope:b,callback:b.replaceState,args:arguments,queue:f});return false}b.busy(true);var g=b.createStateObject(a,
+d,e),j=b.getState(),o=c.getStateByIndex(-2);c.discardState(j,g,o);b.pushState(g.data,g.title,g.url,false);return true};if(!h.location.hash||h.location.hash==="#")b.Adapter.onDomLoad(function(){b.debug("Internet Explorer Initial State Change Fix");var a=b.createStateObject({},"",h.location.href);b.pushState(a.data,a.title,a.url)});else if(!b.emulated.hashChange){b.debug("Firefox Initial State Change Fix");b.Adapter.onDomLoad(function(){c.onHashChange()})}}else{c.onPopState=function(a){b.debug("_History.onPopState",
+this,arguments);var d=unescape(b.getHash());if(d){var e=b.expandHash(d);if(e){b.debug("_History.onPopState: state anchor",d,e);b.replaceState(e.data,e.tite,e.url,false)}else{b.debug("_History.onPopState: traditional anchor",d);b.Adapter.trigger(i,"anchorchange");b.busy(false)}return false}d={};var f=e=null;d=null;a=a||{};if(typeof a.state==="undefined")if(typeof a.originalEvent!=="undefined"&&typeof a.originalEvent.state!=="undefined")a.state=a.originalEvent.state;else if(typeof a.event!=="undefined"&&
+typeof a.event.state!=="undefined")a.state=a.event.state;if(a.state===null)d=a.state;else if(typeof a.state!=="undefined"){e=b.expandUrl(h.location.href);d=c.getStateByUrl(e);e=c.urlDuplicateExists(e);d=typeof d!=="undefined"&&!e?d.data:a.state}else{e=b.expandUrl(h.location.href);if((d=c.getStateByUrl(e))&&e==d.url)d=d.data;else throw Error("Unknown state");}d=typeof d!=="object"||d===null?{}:d;e=d.title||"";f=d.url||h.location.href;d=b.createStateObject(d,e,f);if(c.isLastState(d)){b.debug("_History.onPopState: no change",
+d,c.savedStates);b.busy(false);return false}b.debug("_History.onPopState","newState:",d,"oldState:",c.getStateByUrl(b.expandUrl(h.location.href)),"duplicateExists:",c.urlDuplicateExists(b.expandUrl(h.location.href)));c.storeState(d);c.saveState(d);if(d.title)h.title=d.title;b.Adapter.trigger(i,"statechange");b.busy(false);return true};b.Adapter.bind(i,"popstate",c.onPopState);b.pushState=function(a,d,e,f){if(b.extractHashFromUrl(e))throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");
+if(f!==false&&b.busy()){b.debug("History.pushState: we must wait",arguments);b.pushQueue({scope:b,callback:b.pushState,args:arguments,queue:f});return false}b.busy(true);var g=b.createStateObject(a,d,e);c.storeState(g);m.pushState(g.data,g.title,g.url);b.Adapter.trigger(i,"popstate");return true};b.replaceState=function(a,d,e,f){if(b.extractHashFromUrl(e))throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(f!==false&&b.busy()){b.debug("History.replaceState: we must wait",
+arguments);b.pushQueue({scope:b,callback:b.replaceState,args:arguments,queue:f});return false}b.busy(true);var g=b.createStateObject(a,d,e);c.storeState(g);m.replaceState(g.data,g.title,g.url);b.Adapter.trigger(i,"popstate");return true};if(navigator.vendor==="Apple Computer, Inc."){b.Adapter.onDomLoad(function(){b.debug("Safari Initial State Change Fix");var a=b.createStateObject({},"",h.location.href);b.pushState(a.data,a.title,a.url)});b.Adapter.bind(i,"hashchange",function(){b.Adapter.trigger(i,
+"popstate")})}}};typeof b.Adapter!=="undefined"&&b.init()})(window);
View
97 scripts/uncompressed/history.js
@@ -164,7 +164,7 @@
* Which features require emulating?
*/
History.emulated = {
- pushState: !Boolean(window.history && window.history.pushState && window.history.replaceState && navigator.vendor !== 'Apple Computer, Inc.'),
+ pushState: !Boolean(window.history && window.history.pushState && window.history.replaceState),
hashChange: Boolean(
!('onhashchange' in window || 'onhashchange' in document)
||
@@ -230,15 +230,15 @@
return false;
}
- // Make Busy + Continue
- History.busy(true);
-
// Prepare
var adjustedHash = _History.escapeHash(hash);
// Log hash
History.debug('History.setHash',this,arguments,'hash:',hash,'adjustedHash:',adjustedHash,'oldHash:',document.location.hash);
+ // Make Busy + Continue
+ History.busy(true);
+
// Apply hash
document.location.hash = adjustedHash;
@@ -1012,7 +1012,7 @@
* @return {boolean} busy
*/
History.busy = function(value){
- History.debug('History.busy: called', arguments, History.busy.flag||undefined, History.queues);
+ History.debug('History.busy: called: changing ['+(History.busy.flag||false)+'] to ['+(value||false)+']', History.queues);
// Apply
if ( typeof value !== 'undefined' ) {
@@ -1034,7 +1034,7 @@
if ( queue.length === 0 ) continue;
var item = queue.shift();
History.debug('History.busy: firing', item);
- item.callback.apply(item.scope||History,item.args||[]);
+ History.fireQueueItem(item);
History.busy.timeout = setTimeout(fireNext,History.options.busyDelay);
}
};
@@ -1043,7 +1043,17 @@
// Return
return History.busy.flag;
- }
+ };
+
+ /**
+ * History.fireQueueItem(item)
+ * Fire a Queue Item
+ * @param {Object} item
+ * @return {Mixed} result
+ */
+ History.fireQueueItem = function(item){
+ return item.callback.apply(item.scope||History,item.args||[]);
+ };
/**
* History.pushQueue(callback,args)
@@ -1063,9 +1073,40 @@
return true;
};
+ /**
+ * History.queue (item,queue), (func,queue), (func), (item)
+ * Either firs the item now if not busy, or adds it to the queue
+ */
+ History.queue = function(item,queue){
+ // Prepare
+ if ( typeof item === 'function' ) {
+ item = {
+ callback: item
+ };
+ }
+ if ( typeof queue !== 'undefined' ) {
+ item.queue = queue;
+ }
+
+ // Handle
+ if ( History.busy() ) {
+ History.pushQueue(item);
+ } else {
+ History.fireQueueItem(item);
+ }
+
+ // End queue closure
+ return true;
+ };
+
// ----------------------------------------------------------------------
// HTML4 State Aliases
+ /**
+ * History.back(queue)
+ * Send the browser history back one item
+ * @param {Integer} queue [optional]
+ */
History.back = function(queue){
History.debug('History.back: called', arguments);
@@ -1104,8 +1145,16 @@
// Go back
history.go(-1);
+
+ // End back closure
+ return true;
};
+ /**
+ * History.forward(queue)
+ * Send the browser history forward one item
+ * @param {Integer} queue [optional]
+ */
History.forward = function(queue){
History.debug('History.forward: called', arguments);
@@ -1144,8 +1193,16 @@
// Go forward
history.go(1);
+
+ // End forward closure
+ return true;
};
+ /**
+ * History.go(index,queue)
+ * Send the browser history back or forward index times
+ * @param {Integer} queue [optional]
+ */
History.go = function(index,queue){
History.debug('History.go: called', arguments);
@@ -1166,12 +1223,11 @@
throw new Error('History.go: History.go requires a positive or negative integer passed.');
}
- // Return true
+ // End go closure
return true;
};
-
// ----------------------------------------------------------------------
// HTML4 HashChange Support
@@ -1787,8 +1843,31 @@
// Return true
return true;
}
+
+
+ /**
+ * Ensure Cross Browser Compatibility
+ **/
+ if ( navigator.vendor === 'Apple Computer, Inc.' ) {
+ /**
+ * Fix Safari Initial State Issue
+ */
+ History.Adapter.onDomLoad(function(){
+ History.debug('Safari Initial State Change Fix');
+ var currentState = History.createStateObject({},'',document.location.href);
+ History.pushState(currentState.data,currentState.title,currentState.url);
+ });
+
+ /**
+ * Fix Safari HashChange Issue
+ */
+ History.Adapter.bind(window,'hashchange',function(){
+ History.Adapter.trigger(window,'popstate');
+ });
+ }
}
+
}; // init
// Check Load Status
View
6 tests/index.php
@@ -7,7 +7,9 @@
}
$Adapter = ucwords($adapter);
# Base URL
- $base_url = 'http://'.$_SERVER['HTTP_HOST'].'/products/history.js';
+ $relative_url = $_SERVER['REQUEST_URI'];
+ $relative_url = substr($relative_url,0,strpos($relative_url,'/history.js')).'/history.js';
+ $base_url = 'http://'.$_SERVER['HTTP_HOST'].$relative_url;
$tests_url = $base_url.'/tests/'.$adapter;
?><!DOCTYPE html>
<html>
@@ -25,7 +27,7 @@
<script type="text/javascript">
if ( typeof console === 'undefined' ) {
var
- url = 'https://getfirebug.com/firebug-lite.js',
+ url = '<?=$base_url?>/vendor/firebug-lite.js',
scriptEl = document.createElement('script');
scriptEl.type = 'text/javascript';
scriptEl.src = url;
View
10 tests/tests.js
@@ -67,15 +67,9 @@ History.Adapter.bind(window,'statechange',function(){
var addLog = function(){
var args = arguments;
- if ( History.busy() ) {
- History.pushQueue({
- callback: function(){
- History.log.apply(History,args);
- }
- });
- } else {
+ History.queue(function(){
History.log.apply(History,args);
- }
+ });
};
History.Adapter.onDomLoad(function(){
View
7,514 vendor/firebug-lite.js
7,514 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.

0 comments on commit 04697ac

Please sign in to comment.