Created
August 11, 2010 16:44
-
-
Save rgrove/519292 to your computer and use it in GitHub Desktop.
History Lite for YUI 2.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Lightweight history utility for YUI 2. Similar in purpose to the YUI Browser | |
* History Manager, but with a more flexible API, no initialization requirement, | |
* no IE6/7 support, and a much smaller footprint. | |
* | |
* @module history-lite | |
* @requires YAHOO, Event | |
* @class HistoryLite | |
* @static | |
*/ | |
(function () { | |
var d = document, | |
w = window, | |
Y = YAHOO, | |
yut = Y.util, | |
yue = yut.Event, | |
ua = Y.env.ua, | |
encode = encodeURIComponent, | |
lastHash, | |
pollInterval, | |
self; | |
// -- Private Methods ------------------------------------------------------ | |
/** | |
* Creates a hash string from the specified object of name/value parameter | |
* pairs. | |
* | |
* @method createHash | |
* @param {Object} params name/value parameter pairs | |
* @return {String} hash string | |
* @private | |
*/ | |
function createHash(params) { | |
var hash = [], | |
name, value; | |
for (name in params) { | |
if (params.hasOwnProperty(name)) { | |
value = params[name]; | |
if (Y.lang.isValue(value)) { | |
hash.push(encode(name) + '=' + encode(value)); | |
} | |
} | |
} | |
return hash.join('&'); | |
} | |
/** | |
* Wrapper around <code>decodeURIComponent()</code> that also converts + | |
* chars into spaces. | |
* | |
* @method decode | |
* @param {String} string string to decode | |
* @return {String} decoded string | |
* @private | |
*/ | |
function decode(string) { | |
return decodeURIComponent(string.replace(/\+/g, ' ')); | |
} | |
/** | |
* Gets the current URL hash. | |
* | |
* @method getHash | |
* @return {String} | |
* @private | |
*/ | |
var getHash; | |
if (Y.env.ua.gecko) { | |
// We branch at runtime for Gecko since window.location.hash in Gecko | |
// returns a decoded string, and we want all encoding untouched. | |
getHash = function () { | |
var matches = /#.*$/.exec(w.location.href); | |
return matches && matches[0] ? matches[0] : ''; | |
}; | |
} else { | |
getHash = function () { | |
return w.location.hash; | |
}; | |
} | |
/** | |
* Sets the browser's location hash to the specified string. | |
* | |
* @method setHash | |
* @param {String} hash | |
* @private | |
*/ | |
function setHash(hash) { | |
w.location.hash = hash; | |
} | |
/** | |
* Begins polling to check for location hash changes. | |
* | |
* @method startPolling | |
* @private | |
*/ | |
function startPolling() { | |
lastHash = getHash(); | |
// IE8 supports the hashchange event, but only in IE8 Standards | |
// Mode. However, IE8 in IE7 compatibility mode still defines the | |
// event (but never fires it), so we can't just sniff for the event. We | |
// also can't just sniff for IE8, since other browsers will eventually | |
// support this event as well. Thanks Microsoft! | |
if ('onhashchange' in w && (!d.documentMode || d.documentMode > 7)) { | |
yue.on(w, 'hashchange', function () { | |
handleHashChange(getHash()); | |
}); | |
} else { | |
pollInterval = pollInterval || setInterval(function () { | |
var hash = getHash(); | |
if (hash !== lastHash) { | |
handleHashChange(hash); | |
} | |
}, 50); | |
} | |
} | |
// -- Private Event Handlers ----------------------------------------------- | |
/** | |
* Handles changes to the location hash and fires the onChange event if | |
* necessary. | |
* | |
* @method handleHashChange | |
* @param {String} newHash new hash value | |
* @private | |
*/ | |
function handleHashChange(newHash) { | |
var changedParams = {}, | |
lastParsed = self.parseQuery(lastHash), | |
newParsed = self.parseQuery(newHash), | |
removedParams = {}, | |
isChanged, name; | |
// Figure out what changed. | |
for (name in newParsed) { | |
if (newParsed.hasOwnProperty(name) && | |
lastParsed[name] !== newParsed[name]) { | |
changedParams[name] = newParsed[name]; | |
isChanged = true; | |
} | |
} | |
// Figure out what was removed. | |
for (name in lastParsed) { | |
if (lastParsed.hasOwnProperty(name) && | |
!newParsed.hasOwnProperty(name)) { | |
removedParams[name] = lastParsed[name]; | |
isChanged = true; | |
} | |
} | |
if (isChanged) { | |
lastHash = newHash; | |
self.onChange.fire(changedParams, removedParams); | |
} | |
} | |
Y.HistoryLite = self = { | |
// -- Public Events ---------------------------------------------------- | |
/** | |
* Fired when the history state changes. | |
* | |
* @event onChange | |
* @param {Object} changedParams name/value pairs of history parameters | |
* that have been added or changed | |
* @param {Object} removedParams name/value pairs of history parameters | |
* that have been removed (values are the old values) | |
*/ | |
onChange: new yut.CustomEvent('browserHistoryChange'), | |
// -- Public Methods --------------------------------------------------- | |
/** | |
* Adds a history entry with changes to the specified parameters. Any | |
* parameters with a <code>null</code> or <code>undefined</code> value | |
* will be removed from the new history entry. | |
* | |
* @method add | |
* @param {String|Object} params query string, hash string, or object | |
* containing name/value parameter pairs | |
* @param {Boolean} quiet if <em>true</em>, a history change event will | |
* not be fired for this change | |
*/ | |
add: function (params, quiet) { | |
var newHash = createHash(Y.lang.merge(self.parseQuery(getHash()), | |
Y.lang.isString(params) ? self.parseQuery(params) : params)); | |
if (quiet) { | |
lastHash = newHash; | |
} | |
setHash(newHash); | |
}, | |
/** | |
* Gets the current value of the specified history parameter, or an | |
* object of name/value pairs for all current values if no parameter | |
* name is specified. | |
* | |
* @method get | |
* @param {String} name (optional) parameter name | |
* @return {Object|mixed} | |
*/ | |
get: function (name) { | |
var params = self.parseQuery(getHash()); | |
return name ? params[name] : params; | |
}, | |
/** | |
* Parses a query string or hash string into an object of name/value | |
* parameter pairs. | |
* | |
* @method parseQuery | |
* @param {String} query query string or hash string | |
* @return {Object} | |
*/ | |
parseQuery: function (query) { | |
var matches = query.match(/([^\?#&]+)=([^&]+)/g) || [], | |
params = {}, | |
i, len, param; | |
for (i = 0, len = matches.length; i < len; ++i) { | |
param = matches[i].split('='); | |
params[decode(param[0])] = decode(param[1]); | |
} | |
return params; | |
} | |
}; | |
startPolling(); | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment