I'm using the jQuery BBQ plug-in to track the users progress through the page. However, I only want to create 1 additional entry in the user's history, not one for every hash change.
I've tried the jQuery.bbq.pushState
and merge_mode
methods, without success: New history entries are still added:
jQuery.bbq.pushState({ sort: encodeURIComponent(sort) });
I have also tried location.replace()
, but that doesn't work for Safari 5.1.2.
location.replace('#' + encodeURIComponent(sort))
What's the cross-browser solution to modify the hash, without adding too much entries to the history?
First, I show the definition of function replaceHash
, which accepts only one argument: The new location hash. A detailed explanation of the logic can be found at the bottom of the answer.
// Should be executed BEFORE any hash change has occurred.
(function(namespace) { // Closure to protect local variable "var hash"
if ('replaceState' in history) { // Yay, supported!
namespace.replaceHash = function(newhash) {
if ((''+newhash).charAt(0) !== '#') newhash = '#' + newhash;
history.replaceState('', '', newhash);
}
} else {
var hash = location.hash;
namespace.replaceHash = function(newhash) {
if (location.hash !== hash) history.back();
location.hash = newhash;
};
}
})(window);
// This function can be namespaced. In this example, we define it on window:
window.replaceHash('Newhashvariable');
history.replaceState
is supported, the function will always replace the current hash, without any side effects.Otherwise, a reference (hash
) to the very first location.hash
property is created, and the following function is defined:
location.hash != hash
, then we know for sure that the history's state is at least past the first page view. We can safely go back in the history, without unloading the page. history.back(); // Go back in the history
.location.hash
property. If we went back in the history in the previous step, the history entry is overwritten.
The fallback (last) method may not always replace the history:
When location.hash == hash
, either of the following is true:
history.back();
, the page might be unloaded, which is not desirable.
So, to be safe, we never unload the page when the hash is equal to the saved original hash.
Note: It is important to run this code before a hash change. When the hash has already been changed, the script is not reliable any more. The user could have navigated to the very first hash state, which is not equal to the saved hash
. Consequently, history.back()
unloads the page.