I worked out a way to override normal history behavior and create distinct back
and forward
button events, using the HTML5 history API (it won't work in IE 9). This is very hacky, but effective if you wanted to intercept the back and forward button events and handle them however you want. This could be useful in a number of scenarios, e.g. if you were displaying a remote desktop window and needed to reproduce back and forward button clicks on the remote machine.
The following would override the back and forward button behavior:
var myHistoryOverride = new HistoryButtonOverride(function()
{
console.log("Back Button Pressed");
return true;
},
function()
{
console.log("Forward Button Pressed");
return true;
});
If you returned false in either of those callback functions, you would be allowing the browser to proceed with a normal back/forward operation and leave your page.
Here is the full script required:
function addEvent(el, eventType, handler) {
if (el.addEventListener) { // DOM Level 2 browsers
el.addEventListener(eventType, handler, false);
} else if (el.attachEvent) { // IE <= 8
el.attachEvent('on' + eventType, handler);
} else { // ancient browsers
el['on' + eventType] = handler;
}
}
function HistoryButtonOverride(BackButtonPressed, ForwardButtonPressed)
{
var Reset = function ()
{
if (history.state == null)
return;
if (history.state.customHistoryStage == 1)
history.forward();
else if (history.state.customHistoryStage == 3)
history.back();
}
var BuildURLWithHash = function ()
{
// The URLs of our 3 history states must have hash strings in them so that back and forward events never cause a page reload.
return location.origin + location.pathname + location.search + (location.hash && location.hash.length > 1 ? location.hash : "#");
}
if (history.state == null)
{
// This is the first page load. Inject new history states to help identify back/forward button presses.
var initialHistoryLength = history.length;
history.replaceState({ customHistoryStage: 1, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash());
history.pushState({ customHistoryStage: 2, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash());
history.pushState({ customHistoryStage: 3, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash());
history.back();
}
else if (history.state.customHistoryStage == 1)
history.forward();
else if (history.state.customHistoryStage == 3)
history.back();
addEvent(window,"popstate",function ()
{
// Called when history navigation occurs.
if (history.state == null)
return;
if (history.state.customHistoryStage == 1)
{
if (typeof BackButtonPressed == "function" && BackButtonPressed())
{
Reset();
return;
}
if (history.state.initialHistoryLength > 1)
history.back(); // There is back-history to go to.
else
history.forward(); // No back-history to go to, so undo the back operation.
}
else if (history.state.customHistoryStage == 3)
{
if (typeof ForwardButtonPressed == "function" && ForwardButtonPressed())
{
Reset();
return;
}
if (history.length > history.state.initialHistoryLength + 2)
history.forward(); // There is forward-history to go to.
else
history.back(); // No forward-history to go to, so undo the forward operation.
}
});
};
This works by a simple concept. When our page loads, we create 3 distinct history states (numbered 1, 2, and 3) and navigate the browser to state number 2. Because state 2 is in the middle, the next history navigation event will put us in either state 1 or 3, and from this we can determine which direction the user pressed. And just like that, we've intercepted a back or forward button event. We then handle it however we want and return to state number 2 so we can capture the next history navigation event.
Obviously, you would need to refrain from using history.replaceState and history.pushState methods while using the HistoryButtonOverride script, or else you'd break it.
// doesn't work
or something like that so people who scan the answer briefly know you are not offering that as a solution. – Cher