While there are some legitimate bugs and differences in state handling even in modern browsers, they are relatively small enough now that you can just use the native HTML5 History API. If you intend to support legacy browsers, then History.js is your bet.
This notice is here as History.js does not receive enough funding to be maintained, so it exists only in legacy condition for legacy browsers. Perhaps it still works for modern browsers, but it could really do with maintenance. Maintenance is very difficult as the library requires manual testing in HTML5 and HTML4 modes, and for each adapter, and for each browser. So that means 2^(# of adapters)^(# of browsers and their versions)
tests that need to be run by a human. Tests need to be run by a human as certain failures require browser interactions, such as navigating from the test suite to a different domain and back again, or clicking the physical back buttons, or checking if the physical back buttons actually work. This takes a lot of time.
Despite History.js being one of the most popular JavaScript libraries there is, and has been used by even multi-million-user companies in its time - the reality of economy and company practices seems to be that companies prefer to fork their own internal versions and fix locally with their own devs rather than fund open-source maintainers what they would pay their own devs to make things better for everyone, including themselves, which would be cheaper - but no, that would require too many tiers of company approval that don't understand the need.
As such, if you are an open-source developer, I'd recommend just working on open-source projects that are paid for by your own consulting work or your own company (e.g. every successful open-source project). As otherwise, when they become popular, you better hope they are easily maintainable and testable, otherwise the cost of maintenance is higher than the free time of the maintainers.
So with all that said, this repo still exists for archival purposes, legacy browsers, and a hub for anarachistic issue & fork maintenance.
Cheers, Benjamin Lupton, founder of Bevry, creator of History.js
- 22/06/2013: Beta 2 of v1.8 is released. Fixes and uncompressed bundled files.
- 31/05/2013: Beta 1 of v1.8 is released. Fixes.
- 14/02/2013: Alpha 4 of v1.8 is released. Fixes.
- 05/02/2013: Alpha 3 of v1.8 is released. Tests updated.
- 21/01/2013: Alpha 2 of v1.8 is released. Correct statechange behaviour.
- 19/01/2013: Alpha 1 of v1.8 is released. Started to categorize old balupton's issues.
See the HISTORY.md
file for a detailed list of features, changes, solved issues and bugs
Please create an issue if something doesn't work or if there is a browser specific bug. I'll try to fix it as soon as possible. Please send me your Pull requests if you have a nice solution! I'm also going to review old issues in balupton's repository and try to solve them too.
- Follow the HTML5 History API as much as possible
- Provide a cross-compatible experience for all HTML5 Browsers (they all implement the HTML5 History API a little bit differently causing different behaviours and sometimes bugs - History.js fixes this ensuring the experience is as expected / the same / great throughout the HTML5 browsers)
- Provide a backwards-compatible experience for all HTML4 Browsers using a hash-fallback (including continued support for the HTML5 History API's
data
,title
,pushState
andreplaceState
) with the option to remove HTML4 support if it is not right for your application - Provide a forwards-compatible experience for HTML4 States to HTML5 States (so if a hash-fallbacked url is accessed by a HTML5 browser it is naturally transformed into its non-hashed url equivalent)
- Provide support for as many javascript frameworks as possible via adapters; especially Dojo, ExtJS, jQuery, MooTools, Right.js and Zepto.
To ajaxify your entire website with the HTML5 History API, History.js and jQuery the Ajaxify script is all you need. It's that easy.
If you don't have access to your server, or just want to try out the Ajaxify script first, you can install the History.js It! Google Chrome Extension to try out History.js via Ajaxify on select websites without actually installing History.js/Ajaxify on your server.
If you are using Rails, then the easiest way for you to try History.js would be to use Wiselinks gem. Wiselinks integrates into Rails application and allows you to start using History.js with three lines of code.
(function(window,undefined){
// Bind to StateChange Event
History.Adapter.bind(window,'statechange',function(){ // Note: We are using statechange instead of popstate
var State = History.getState(); // Note: We are using History.getState() instead of event.state
});
// Change our States
History.pushState({state:1}, "State 1", "?state=1"); // logs {state:1}, "State 1", "?state=1"
History.pushState({state:2}, "State 2", "?state=2"); // logs {state:2}, "State 2", "?state=2"
History.replaceState({state:3}, "State 3", "?state=3"); // logs {state:3}, "State 3", "?state=3"
History.pushState(null, null, "?state=4"); // logs {}, '', "?state=4"
History.back(); // logs {state:3}, "State 3", "?state=3"
History.back(); // logs {state:1}, "State 1", "?state=1"
History.back(); // logs {}, "Home Page", "?"
History.go(2); // logs {state:3}, "State 3", "?state=3"
})(window);
- www.mysite.com
- www.mysite.com/?state=1
- www.mysite.com/?state=2
- www.mysite.com/?state=3
- www.mysite.com/?state=4
- www.mysite.com/?state=3
- www.mysite.com/?state=1
- www.mysite.com
- www.mysite.com/?state=3
Note: These urls also work in HTML4 browsers and Search Engines. So no need for the hashbang (
#!
) fragment-identifier that google "recommends".
- www.mysite.com
- www.mysite.com/#?state=1&_suid=1
- www.mysite.com/#?state=2&_suid=2
- www.mysite.com/#?state=3&_suid=3
- www.mysite.com/#?state=4
- www.mysite.com/#?state=3&_suid=3
- www.mysite.com/#?state=1&_suid=1
- www.mysite.com
- www.mysite.com/#?state=3&_suid=3
Note 1: These urls also work in HTML5 browsers - we use
replaceState
to transform these HTML4 states into their HTML5 equivalents so the user won't even notice :-)Note 2: These urls will be automatically url-encoded in IE6 to prevent certain browser-specific bugs.
Note 3: Support for HTML4 browsers (this hash fallback) is optional - why supporting HTML4 browsers could be either good or bad based on my app's use cases
- SUIDs (State Unique Identifiers) are used when we utilise a
title
and/ordata
in our state. Adding a SUID allows us to associate particular states with data and titles while keeping the urls as simple as possible (don't worry it's all tested, working and a lot smarter than I'm making it out to be). - If you aren't utilising
title
ordata
then we don't even include a SUID (as there is no need for it) - as seen by State 4 above :-) - We also shrink the urls to make sure that the smallest url will be used. For instance we will adjust
http://www.mysite.com/#http://www.mysite.com/projects/History.js
to becomehttp://www.mysite.com/#/projects/History.js
automatically. (again tested, working, and smarter). - It works with domains, subdomains, subdirectories, whatever - doesn't matter where you put it. It's smart.
- Safari 5 will also have a SUID appended to the URL, it is entirely transparent but just a visible side-effect. It is required to fix a bug with Safari 5.
- 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.
-
Download History.js and upload it to your webserver. Download links: tar.gz or zip
-
Include History.js
-
For Dojo v1.8+
<script src="http://www.yourwebsite.com/history.js/scripts/bundled/html4+html5/dojo.history.js"></script> -
For ExtJs v1.8+
<script src="http://www.yourwebsite.com/history.js/scripts/bundled/html4+html5/extjs.history.js"></script> -
For jQuery v1.3+
<script src="http://www.yourwebsite.com/history.js/scripts/bundled/html4+html5/jquery.history.js"></script> -
For Mootools v1.3+
<script src="http://www.yourwebsite.com/history.js/scripts/bundled/html4+html5/mootools.history.js"></script> -
For Right.js v2.2+
<script src="http://www.yourwebsite.com/history.js/scripts/bundled/html4+html5/right.history.js"></script> -
For Zepto v0.5+
<script src="http://www.yourwebsite.com/history.js/scripts/bundled/html4+html5/zepto.history.js"></script> -
For everything else
<script src="http://www.yourwebsite.com/history.js/scripts/bundled/html4+html5/native.history.js"></script>
-
Note: If you want to only support HTML5 Browsers and not HTML4 Browsers (so no hash fallback support) then just change the
/html4+html5/
part in the urls to just/html5/
. See Why supporting HTML4 browsers could be either good or bad based on my app's use cases
- For Commit RSS/Atom Updates:
- You can subscribe via the GitHub Commit Atom Feed
- For GitHub News Feed Updates:
- You can click the "watch" button up the top right of History.js's GitHub Project Page
-
History.js is maintained by people like you. If you find a bug, report it to the GitHub Issue Tracker. If you've fixed a bug submit a Pull Request and add your fork to the Network Wiki Page.
-
If you would like paid support and trainings, or have job offers, then refer to the Network Wiki Page. If you are qualified with History.js, then be sure to add your details to that page too.
-
If your company uses History.js on your projects, and would like to see it grow and prosper (better documentation, bugfixes, upgrades, maintenance, etc.) and would love to become a corporate sponsor then do email sponsor@bevry.me
-
If you would like free support for History.js, then post your question on Stackoverflow and be sure to use the
history.js
tag when asking your question. -
If you've created a website that uses History.js, or know of one, be sure to add it to the Showcase Wiki Page.
-
If you'd love to +1 or like this project, then be sure to tweet about it and click the "watch" button up the top of its Project Page.
-
For anything else, refer to the History.js GitHub Wiki Site.
Thanks! every bit of help really does make a difference!
- Firefox 4+
- Chrome 8+
- Opera 11.5+
- Safari 5.0+
- Safari iOS 4.3+
- IE 6, 7, 8, 9, (10)
- Firefox 3
- Opera 10, 11.0
- Safari 4
- Safari iOS 4.2, 4.1, 4.0, 3.2
History.pushState(data,title,url)
Pushes a new state to the browser;data
can be null or an object,title
can be null or a string,url
must be a stringHistory.replaceState(data,title,url)
Replaces the existing state with a new state to the browser;data
can be null or an object,title
can be null or a string,url
must be a stringHistory.getState()
Gets the current state of the browser, returns an object withdata
,title
andurl
History.getStateByIndex
Gets a state by the indexHistory.getCurrentIndex
Gets the current indexHistory.getHash()
Gets the current hash of the browser
History.Adapter.bind(element,event,callback)
A framework independent event binder, you may either use this or your framework's native event binder.History.Adapter.trigger(element,event)
A framework independent event trigger, you may either use this or your framework's native event trigger.History.Adapter.onDomLoad(callback)
A framework independent onDomLoad binder, you may either use this or your framework's native onDomLoad binder.
History.back()
Go back once through the history (same as hitting the browser's back button)History.forward()
Go forward once through the history (same as hitting the browser's forward button)History.go(X)
If X is negative go back through history X times, if X is positive go forwards through history X times
History.log(...)
Logs messages to the console, the log element, and fallbacks to alert if neither of those two existHistory.debug(...)
Same asHistory.log
but only runs ifHistory.options.debug === true
History.options.hashChangeInterval
How long should the interval be before hashchange checksHistory.options.safariPollInterval
How long should the interval be before safari poll checksHistory.options.doubleCheckInterval
How long should the interval be before we perform a double checkHistory.options.disableSuid
Force History not to append suidHistory.options.storeInterval
How long should we wait between store callsHistory.options.busyDelay
How long should we wait between busy eventsHistory.options.debug
If true will enable debug messages to be loggedHistory.options.initialTitle
What is the title of the initial stateHistory.options.html4Mode
If true, will force HTMl4 mode (hashtags)History.options.delayInit
Want to override default options and call init manually.
window.onstatechange
Fired when the state of the page changes (does not include hash changes)window.onanchorchange
Fired when the anchor of the page changes (does not include state hashes)
- Opera 11 fails to create history entries when under stressful loads (events fire perfectly, just the history events fail) - there is nothing we can do about this
- Mercury iOS fails to apply url changes (hashes and HTML5 History API states) - there is nothing we can do about this
- History.js solves the following browser bugs:
- HTML5 Browsers
- Chrome 8 sometimes does not contain the correct state data when traversing back to the initial state
- Safari 5, Safari iOS 4 and Firefox 3 and 4 do not fire the
onhashchange
event when the page is loaded with a hash - Safari 5 and Safari iOS 4 do not fire the
onpopstate
event when the hash has changed unlike the other browsers - Safari 5 and Safari iOS 4 fail to return to the correct state once a hash is replaced by a
replaceState
call / bug report - Safari 5 and Safari iOS 4 sometimes fail to apply the state change under busy conditions / bug report
- Google Chrome 8,9,10 and Firefox 4 prior to the RC will always fire
onpopstate
once the page has loaded / change recommendation - 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
- None of the HTML5 browsers actually utilise the
title
argument to thepushState
andreplaceState
calls
- HTML4 Browsers
- Old browsers like MSIE 6,7 and Firefox 2 do not have a
onhashchange
event - MSIE 6 and 7 sometimes do not apply a hash even it was told to (requiring a second call to the apply function)
- Non-Opera HTML4 browsers sometimes do not apply the hash when the hash is not
urlencoded
- Old browsers like MSIE 6,7 and Firefox 2 do not have a
- All Browsers
- State data and titles do not persist once the site is left and then returned (includes page refreshes)
- State titles are never applied to the
document.title
- HTML5 Browsers
- 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 - Data persistance and synchronisation works like so: Every second or so, the SUIDs and URLs of the states will synchronise between the store and the local session. When a new session opens a familiar state (via the SUID or the URL) and it is not found locally then it will attempt to load the last known stored state with that information.
- URLs will be unescaped to the maximum, so for instance the URL
?key=a%20b%252c
will become?key=a b c
. This is to ensure consistency between browser url encodings. - Changing the hash of the page causes
onpopstate
to fire (this is expected/standard functionality). To ensure correct compatibility between HTML5 and HTML4 browsers the following events have been created:window.onstatechange
: this is the same as theonpopstate
event except it does not fire for traditional anchorswindow.onanchorchange
: this is the same as theonhashchange
event except it does not fire for states
Licensed under the New BSD License
Copyright © 2014+ Bevry Pty Ltd us@bevry.me
Copyright © 2011-2013 Benjamin Arthur Lupton b@lupton.cc
For support see the Getting Support section.