Skip to content

Instantly share code, notes, and snippets.

@JosePedroDias
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JosePedroDias/a1a8ad58db77143abfce to your computer and use it in GitHub Desktop.
Save JosePedroDias/a1a8ad58db77143abfce to your computer and use it in GitHub Desktop.
state w/ location.search and optional history API
(function() {
var clone = function(o) {
return JSON.parse( JSON.stringify(o) );
};
var parseQueryString = function(url) {
var aParams = {};
if (url.match(/\?(.+)/i)) {
var queryStr = url.replace(/^(.*)\?([^\#]+)(\#(.*))?/g, "$2");
if (queryStr.length > 0) {
var aQueryStr = queryStr.split(/[;&]/);
for(var i=0; i < aQueryStr.length; i++) {
var pairVar = aQueryStr[i].split('=');
aParams[decodeURIComponent(pairVar[0])] = (typeof(pairVar[1]) !== 'undefined' && pairVar[1]) ? decodeURIComponent(pairVar[1]) : '';
}
}
}
return aParams;
};
var toQueryString = function(o) {
var res = [];
var keys = [];
for (var prop in o) {
if (o.hasOwnProperty(prop)) {
keys.push(prop);
}
}
for (var i = 0; i < keys.length; i++) {
var val = o[keys[i]];
res.push( [encodeURIComponent(keys[i]), encodeURIComponent(val)].join('=') );
}
return '?' + res.join('&');
};
window.handleState = function(mapping) {
var STATE;
var forObject = function(o, cb) {
for (var k in o) {
if (!o.hasOwnProperty(k)) { continue; }
cb(o[k], k);
}
};
var mapObject = function(o, cb) {
var res = {};
for (var k in o) {
if (!o.hasOwnProperty(k)) { continue; }
res[k] = cb(o[k], k);
}
return res;
};
var objectHasUndefinedValue = function(keysBag, o) {
for (var k in keysBag) {
if (!keysBag.hasOwnProperty(k)) { continue; }
if (o[k] === undefined) {
return true;
}
}
return false;
};
var getStateFromInputs = function() {
return mapObject(mapping, function(field, fieldName) {
return field.validator( field.getter() );
});
};
var setInputsFromState = function(state) {
forObject(mapping, function(field, fieldName) {
field.setter(state[fieldName]);
});
};
var getStateFromLocation = function() {
var state;
try {
state = parseQueryString(location.search);
state = mapObject(state, function(value, key) {
return mapping[key].validator(value);
});
if (objectHasUndefinedValue(mapping, state)) {
throw 'faulty state!';
}
} catch (ex) {
state = mapObject(mapping, function(field, fieldName) {
return field.value;
});
}
return state;
};
var setStateToLocation = function(state, skipHistory) {
var state_S = JSON.stringify(state);
var STATE_S = JSON.stringify(STATE);
var stateChanged = (state !== STATE);
STATE = state;
if (!stateChanged) { return; }
var qs = toQueryString(state);
var url = [window.location.protocol, "//", window.location.host, window.location.pathname, qs].join('');
if (window.history && window.history.pushState && !skipHistory && stateChanged) {
window.history.pushState(state, '', url);
}
else {
location.search = qs;
}
};
var setStateOnInputsChange = function() {
setStateToLocation( getStateFromInputs() );
};
window.addEventListener('popstate', function(ev) {
if (ev.state) {
setInputsFromState(ev.state);
}
});
var state = getStateFromLocation();
setInputsFromState(state);
setStateToLocation(state);
return { // public API
setStateOnInputsChange: setStateOnInputsChange,
getState: function() {
return clone(state);
},
setField: function(fieldName, value) {
var field = mapping[fieldName];
value = field.validator(value);
if (value === undefined || value === state[fieldName]) { return; }
field.setter(value);
}
};
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment