Hello I am developing my own router api in Javascript. It does routing based on #FregmentIdentifiers (document.location.hash).
The api is almos finished but I am still working on the backbuttom event. Whenever the backbuttom is pressed and the hash has changed, and was seen before, the old content will be restored.
Do you know a way to do the saving and restoring of all content?
My problem here is that if I save and restore document.body.innerHTML only the markup is restored but not the events, so e.g. googlemaps stops working. I was trying to clone document.body or document.documentElement but javascript either told me that the field does not have a setter or that my clone is not valid.
EDIT:
To make clear after all what I am working on, I decided to post my current code. The question aims at the parts marked with a //TODO comment.
function Router(){
var that = this;
var router = this;
var executionObservers = [];
that.routes = [];
this.registerRoute = function(route){
that.routes.push(route);
};
var history = null;
this.init = function(){
var i;
var identifier = document.location.hash;
history = new History();
history.start();
if(identifier.length > 0){
identifier = identifier.substring(1,identifier.length);
for(i = 0; i< that.routes.length; i++){
var route = that.routes[i];
if(route.contains(identifier)){
route.getAction(identifier)(route.getParams(identifier));
return true;
}
}
}
return false;
};
this.executed = function (identifier){
var i;
for(i=0; i<executionObservers.length; i++){
executionObservers[i](identifier);
}
document.location.hash = identifier;
};
this.addExecutionObserver = function(observer){
executionObservers.push(observer);
};
function History(){
var history = [];
var timeout = 200;
var lastAddedHash = null;
var loop = function(callback){
var hash = window.location.hash;
window.setTimeout(
function(){
if(window.location.hash!=hash){
hash = window.location.hash;
callback(hash);
}
loop(callback);
},
timeout
);
};
this.add = function(hash){
lastAddedHash = hash;
window.setTimeout(addCallback(hash), timeout);
};
addCallback = function(hash){
return function(){
var i;
var found = false;
for(i =0; i< history.length&&!found; i++){
if(history[i][1] == hash){
found = true;
//TODO create backup
//history[i][0] =
}
}
if(!found){history.push(new Array(document.documentElement.cloneNode(true),hash));}
}
}
this.setTimeout = function(micoseconds){
timeout = microseconds;
};
started = false;
this.start = function(){
if(!started){
started = true;
loop(function(hash){
var i;
if(lastAddedHash!=null&&hash!=lastAddedHash){
for(i =0; i<history.length; i++){
if(history[i][1] == hash){
//TODO restore from backup
document.location.reload();
}
}
}
});
}
};
router.addExecutionObserver(this.add);
}
}
Router.instance = null;
Router.getInstance = function(){
if(Router.instance === null ){
Router.instance = new Router();
}
return Router.instance;
};
/**
* @param getParams = function(identifier)
* @param getIdentifier = function(params)
* @param contains = function(identifier)
*/
function Route(action, getParams, getIdentifier, contains){
var that = this;
var router = Router.getInstance();
this.contains = contains;
this.getParams = getParams;
this.getAction = function(){
return action;
}
this.reExecute = function(identifier){
action(getParams(identifier));
};
this.execute = function(params){
action(params);
this.executed(params);
}
this.executed = function(params){
router.executed('#' + getIdentifier(params));
};
this.register = function(){
router.registerRoute(this);
};
}
function PrefixedRouterConfig(prefix,paramRegexes){
this.contains = function(identifier){
var regex = "^" + prefix;
for(var i=0;i<paramRegexes.length;i++){
regex+="_"+paramRegexes[i];
}
regex +="$";
var match = identifier.match(regex);
return match != null && (typeof match) == 'object' && (match[0] == identifier);
};
this.getIdentifier = function(params){
ret = prefix;
for(var i=0;i<params.length;i++){
ret+="_"+params[i];
}
return ret;
};
this.getParams = function(identifier){
var regex = "^" + prefix;
for(var i=0;i<paramRegexes.length;i++){
regex+="_("+paramRegexes[i]+")";
}
regex +="$";
var matches = identifier.match(regex);
var ret = [];
for(var i=1;i<matches.length;i++){
ret.push(matches[i]);
}
return ret;
};
}
An example usage of my api can look like this:
config = new PrefixedRouterConfig('show_map',new Array("\\d+", "-?\\d+(?:\\.\\d+)?", "-?\\d+(?:\\.\\d+)?"));
var ROUTE_SHOW_MAP = new Route(
function(params){
var zoom = params[0];
var lat = params[1];
var lng = params[2];
MyGmapInterface.preparePage(-1);
addTabSelectedCallback(MyGmapInterface.tabLoaded);
addTabClosedCallback(MyGmapInterface.tabClosed);
MyGmapInterface.tabsLoaded = true;
MyGmapInterface.myMap = new MyMap(lat,lng,zoom,MyGmapInterface.getMapContainer(),MyGmapInterface.notCompatible);
MyGmapInterface.addNewCamMarkers(MyGmapInterface.loadCams());
MyGmapInterface.initListeners();
tabSelected(TAB_LEFT);
},
config.getParams,
config.getIdentifier,
config.contains
);
ROUTE_SHOW_MAP.register();
After all Javascript files are included (which may register routes) I call Router.getInstance().init();
When I do somewhere an ajax request (by hand) for which a route exists, I call ROUTE_NAME.executed() to set the fregment identifier and to register it with the history.
Furthermore I have an observer which updates some links, which are used for direct translations, whenever a location hash is changed by executed()
This is the same situation as a refresh so you should re-use that system.
Basicly your hash has to contain enough information to rebuild the whole page. Ofcourse, sometimes you need to save some user input to rebuild a page. That's where the localStorage is for (userData for IE)
Unless you've added your events through an API which tracks them (like jQuery does; see http://api.jquery.com/clone#true ), you won't be able to reflect on the events which have been added in order to get them serialized/preserved.
If you have made the unlikely choice of using DOM user data, you will also need setUserData() to serialize any DOM user data (or again, a library like jQuery to track it for you).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With