templates/jquery/history.js in compass-jquery-plugin-0.3.2.8 vs templates/jquery/history.js in compass-jquery-plugin-0.3.3.0

- old
+ new

@@ -4,1845 +4,1872 @@ * @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com> * @license New BSD License <http://creativecommons.org/licenses/BSD/> */ (function(window, undefined) { - "use strict"; + "use strict"; - // -------------------------------------------------------------------------- - // Initialise + // -------------------------------------------------------------------------- + // Initialise - // Localise Globals - var - console = window.console || undefined, // Prevent a JSLint complain - document = window.document, // Make sure we are using the correct document - navigator = window.navigator, // Make sure we are using the correct navigator - amplify = window.amplify || false, // Amplify.js - setTimeout = window.setTimeout, - clearTimeout = window.clearTimeout, - setInterval = window.setInterval, - JSON = window.JSON, - History = window.History = window.History || {}, // Public History Object - history = window.history; // Old History Object + // Localise Globals + var + console = window.console || undefined, // Prevent a JSLint complain + document = window.document, // Make sure we are using the correct document + navigator = window.navigator, // Make sure we are using the correct navigator + amplify = window.amplify || false, // Amplify.js + setTimeout = window.setTimeout, + clearTimeout = window.clearTimeout, + setInterval = window.setInterval, + clearInterval = window.clearInterval, + JSON = window.JSON, + History = window.History = window.History || {}, // Public History Object + history = window.history; // Old History Object - // MooTools Compatibility - JSON.stringify = JSON.stringify || JSON.encode; - JSON.parse = JSON.parse || JSON.decode; + // MooTools Compatibility + JSON.stringify = JSON.stringify || JSON.encode; + JSON.parse = JSON.parse || JSON.decode; - // Check Existence - if (typeof History.init !== 'undefined') { - throw new Error('History.js Core has already been loaded...'); + // Check Existence + if (typeof History.init !== 'undefined') { + throw new Error('History.js Core has already been loaded...'); + } + + // Initialise History + History.init = function() { + // Check Load Status of Adapter + if (typeof History.Adapter === 'undefined') { + return false; } - // Initialise History - History.init = function() { - // Check Load Status of Adapter - if (typeof History.Adapter === 'undefined') { - return false; - } + // Check Load Status of Core + if (typeof History.initCore !== 'undefined') { + History.initCore(); + } - // Check Load Status of Core - if (typeof History.initCore !== 'undefined') { - History.initCore(); - } + // Check Load Status of HTML4 Support + if (typeof History.initHtml4 !== 'undefined') { + History.initHtml4(); + } - // Check Load Status of HTML4 Support - if (typeof History.initHtml4 !== 'undefined') { - History.initHtml4(); - } + // Return true + return true; + }; - // Return true - return true; - }; + // -------------------------------------------------------------------------- + // Initialise Core - // -------------------------------------------------------------------------- - // Initialise Core + // Initialise Core + History.initCore = function() { + // Initialise + if (typeof History.initCore.initialized !== 'undefined') { + // Already Loaded + return false; + } + else { + History.initCore.initialized = true; + } - // Initialise Core - History.initCore = function() { - // Initialise - if (typeof History.initCore.initialized !== 'undefined') { - // Already Loaded - return false; - } - else { - History.initCore.initialized = true; - } + // ---------------------------------------------------------------------- + // Options - // ---------------------------------------------------------------------- - // Options + /** + * History.options + * Configurable options + */ + History.options = History.options || {}; - /** - * History.options - * Configurable options - */ - History.options = History.options || {}; + /** + * History.options.hashChangeInterval + * How long should the interval be before hashchange checks + */ + History.options.hashChangeInterval = History.options.hashChangeInterval || 100; - /** - * History.options.hashChangeInterval - * How long should the interval be before hashchange checks - */ - History.options.hashChangeInterval = History.options.hashChangeInterval || 100; + /** + * History.options.safariPollInterval + * How long should the interval be before safari poll checks + */ + History.options.safariPollInterval = History.options.safariPollInterval || 500; - /** - * History.options.safariPollInterval - * How long should the interval be before safari poll checks - */ - History.options.safariPollInterval = History.options.safariPollInterval || 500; + /** + * History.options.doubleCheckInterval + * How long should the interval be before we perform a double check + */ + History.options.doubleCheckInterval = History.options.doubleCheckInterval || 500; - /** - * History.options.doubleCheckInterval - * How long should the interval be before we perform a double check - */ - History.options.doubleCheckInterval = History.options.doubleCheckInterval || 500; + /** + * History.options.storeInterval + * How long should we wait between store calls + */ + History.options.storeInterval = History.options.storeInterval || 1000; - /** - * History.options.storeInterval - * How long should we wait between store calls - */ - History.options.storeInterval = History.options.storeInterval || 1000; + /** + * History.options.busyDelay + * How long should we wait between busy events + */ + History.options.busyDelay = History.options.busyDelay || 250; - /** - * History.options.busyDelay - * How long should we wait between busy events - */ - History.options.busyDelay = History.options.busyDelay || 250; + /** + * History.options.debug + * If true will enable debug messages to be logged + */ + History.options.debug = History.options.debug || false; - /** - * History.options.debug - * If true will enable debug messages to be logged - */ - History.options.debug = History.options.debug || false; + /** + * History.options.initialTitle + * What is the title of the initial state + */ + History.options.initialTitle = History.options.initialTitle || document.title; - /** - * History.options.initialTitle - * What is the title of the initial state - */ - History.options.initialTitle = History.options.initialTitle || document.title; + // ---------------------------------------------------------------------- + // Interval record - // ---------------------------------------------------------------------- - // Debug + /** + * History.intervalList + * List of intervals set, to be cleared when document is unloaded. + */ + History.intervalList = []; - /** - * History.debug(message,...) - * Logs the passed arguments if debug enabled - */ - History.debug = function() { - if ((History.options.debug || false)) { - History.log.apply(History, arguments); - } - }; + /** + * History.clearAllIntervals + * Clears all setInterval instances. + */ + History.clearAllIntervals = function() { + var i, il = History.intervalList; + if (typeof il !== "undefined" && il !== null) { + for (i = 0; i < il.length; i++) { + clearInterval(il[i]); + } + History.intervalList = null; + } + }; + History.Adapter.bind(window, "beforeunload", History.clearAllIntervals); + History.Adapter.bind(window, "unload", History.clearAllIntervals); - /** - * History.log(message,...) - * Logs the passed arguments - */ - History.log = function() { - // Prepare - var - consoleExists = !(typeof console === 'undefined' || typeof console.log === 'undefined' || typeof console.log.apply === 'undefined'), - textarea = document.getElementById('log'), - message, - i,n - ; - // Write to Console - if (consoleExists) { - var args = Array.prototype.slice.call(arguments); - message = args.shift(); - if (typeof console.debug !== 'undefined') { - console.debug.apply(console, [message,args]); - } - else { - console.log.apply(console, [message,args]); - } - } - else { - message = ("\n" + arguments[0] + "\n"); - } + // ---------------------------------------------------------------------- + // Debug - // Write to log - for (i = 1,n = arguments.length; i < n; ++i) { - var arg = arguments[i]; - if (typeof arg === 'object' && typeof JSON !== 'undefined') { - try { - arg = JSON.stringify(arg); - } - catch (Exception) { - // Recursive Object - } - } - message += "\n" + arg + "\n"; - } + /** + * History.debug(message,...) + * Logs the passed arguments if debug enabled + */ + History.debug = function() { + if ((History.options.debug || false)) { + History.log.apply(History, arguments); + } + }; - // Textarea - if (textarea) { - textarea.value += message + "\n-----\n"; - textarea.scrollTop = textarea.scrollHeight - textarea.clientHeight; - } - // No Textarea, No Console - else if (!consoleExists) { - alert(message); - } + /** + * History.log(message,...) + * Logs the passed arguments + */ + History.log = function() { + // Prepare + var + consoleExists = !(typeof console === 'undefined' || typeof console.log === 'undefined' || typeof console.log.apply === 'undefined'), + textarea = document.getElementById('log'), + message, + i,n + ; - // Return true - return true; - }; + // Write to Console + if (consoleExists) { + var args = Array.prototype.slice.call(arguments); + message = args.shift(); + if (typeof console.debug !== 'undefined') { + console.debug.apply(console, [message,args]); + } + else { + console.log.apply(console, [message,args]); + } + } + else { + message = ("\n" + arguments[0] + "\n"); + } - // ---------------------------------------------------------------------- - // Emulated Status + // Write to log + for (i = 1,n = arguments.length; i < n; ++i) { + var arg = arguments[i]; + if (typeof arg === 'object' && typeof JSON !== 'undefined') { + try { + arg = JSON.stringify(arg); + } + catch (Exception) { + // Recursive Object + } + } + message += "\n" + arg + "\n"; + } - /** - * History.getInternetExplorerMajorVersion() - * Get's the major version of Internet Explorer - * @return {integer} - * @license Public Domain - * @author Benjamin Arthur Lupton <contact@balupton.com> - * @author James Padolsey <https://gist.github.com/527683> - */ - History.getInternetExplorerMajorVersion = function() { - var result = History.getInternetExplorerMajorVersion.cached = - (typeof History.getInternetExplorerMajorVersion.cached !== 'undefined') - ? History.getInternetExplorerMajorVersion.cached - : (function() { - var v = 3, - div = document.createElement('div'), - all = div.getElementsByTagName('i'); - while ((div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->') && all[0]) { - } - return (v > 4) ? v : false; - })() - ; - return result; - }; + // Textarea + if (textarea) { + textarea.value += message + "\n-----\n"; + textarea.scrollTop = textarea.scrollHeight - textarea.clientHeight; + } + // No Textarea, No Console + else if (!consoleExists) { + alert(message); + } - /** - * History.isInternetExplorer() - * Are we using Internet Explorer? - * @return {boolean} - * @license Public Domain - * @author Benjamin Arthur Lupton <contact@balupton.com> - */ - History.isInternetExplorer = function() { - var result = - History.isInternetExplorer.cached = - (typeof History.isInternetExplorer.cached !== 'undefined') - ? History.isInternetExplorer.cached - : Boolean(History.getInternetExplorerMajorVersion()) - ; - return result; - }; + // Return true + return true; + }; - /** - * History.emulated - * Which features require emulating? - */ - History.emulated = { - pushState: !Boolean( - window.history && window.history.pushState && window.history.replaceState - && !( - (/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i).test(navigator.userAgent) /* disable for versions of iOS before version 4.3 (8F190) */ - || (/AppleWebKit\/5([0-2]|3[0-2])/i).test(navigator.userAgent) /* disable for the mercury iOS browser, or at least older versions of the webkit engine */ - ) - ), - hashChange: Boolean( - !(('onhashchange' in window) || ('onhashchange' in document)) - || - (History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8) - ) - }; + // ---------------------------------------------------------------------- + // Emulated Status - /** - * History.enabled - * Is History enabled? - */ - History.enabled = !History.emulated.pushState; + /** + * History.getInternetExplorerMajorVersion() + * Get's the major version of Internet Explorer + * @return {integer} + * @license Public Domain + * @author Benjamin Arthur Lupton <contact@balupton.com> + * @author James Padolsey <https://gist.github.com/527683> + */ + History.getInternetExplorerMajorVersion = function() { + var result = History.getInternetExplorerMajorVersion.cached = + (typeof History.getInternetExplorerMajorVersion.cached !== 'undefined') + ? History.getInternetExplorerMajorVersion.cached + : (function() { + var v = 3, + div = document.createElement('div'), + all = div.getElementsByTagName('i'); + while ((div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->') && all[0]) { + } + return (v > 4) ? v : false; + })() + ; + return result; + }; - /** - * History.bugs - * Which bugs are present - */ - History.bugs = { - /** - * Safari 5 and Safari iOS 4 fail to return to the correct state once a hash is replaced by a `replaceState` call - * https://bugs.webkit.org/show_bug.cgi?id=56249 - */ - setHash: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)), + /** + * History.isInternetExplorer() + * Are we using Internet Explorer? + * @return {boolean} + * @license Public Domain + * @author Benjamin Arthur Lupton <contact@balupton.com> + */ + History.isInternetExplorer = function() { + var result = + History.isInternetExplorer.cached = + (typeof History.isInternetExplorer.cached !== 'undefined') + ? History.isInternetExplorer.cached + : Boolean(History.getInternetExplorerMajorVersion()) + ; + return result; + }; - /** - * Safari 5 and Safari iOS 4 sometimes fail to apply the state change under busy conditions - * https://bugs.webkit.org/show_bug.cgi?id=42940 - */ - safariPoll: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)), + /** + * History.emulated + * Which features require emulating? + */ + History.emulated = { + pushState: !Boolean( + window.history && window.history.pushState && window.history.replaceState + && !( + (/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i).test(navigator.userAgent) /* disable for versions of iOS before version 4.3 (8F190) */ + || (/AppleWebKit\/5([0-2]|3[0-2])/i).test(navigator.userAgent) /* disable for the mercury iOS browser, or at least older versions of the webkit engine */ + ) + ), + hashChange: Boolean( + !(('onhashchange' in window) || ('onhashchange' in document)) + || + (History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8) + ) + }; - /** - * MSIE 6 and 7 sometimes do not apply a hash even it was told to (requiring a second call to the apply function) - */ - ieDoubleCheck: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8), + /** + * History.enabled + * Is History enabled? + */ + History.enabled = !History.emulated.pushState; - /** - * MSIE 6 requires the entire hash to be encoded for the hashes to trigger the onHashChange event - */ - hashEscape: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 7) - }; + /** + * History.bugs + * Which bugs are present + */ + History.bugs = { + /** + * Safari 5 and Safari iOS 4 fail to return to the correct state once a hash is replaced by a `replaceState` call + * https://bugs.webkit.org/show_bug.cgi?id=56249 + */ + setHash: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)), - /** - * History.isEmptyObject(obj) - * Checks to see if the Object is Empty - * @param {Object} obj - * @return {boolean} - */ - History.isEmptyObject = function(obj) { - for (var name in obj) { - return false; - } - return true; - }; + /** + * Safari 5 and Safari iOS 4 sometimes fail to apply the state change under busy conditions + * https://bugs.webkit.org/show_bug.cgi?id=42940 + */ + safariPoll: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)), - /** - * History.cloneObject(obj) - * Clones a object - * @param {Object} obj - * @return {Object} - */ - History.cloneObject = function(obj) { - var hash,newObj; - if (obj) { - hash = JSON.stringify(obj); - newObj = JSON.parse(hash); - } - else { - newObj = {}; - } - return newObj; - }; + /** + * MSIE 6 and 7 sometimes do not apply a hash even it was told to (requiring a second call to the apply function) + */ + ieDoubleCheck: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8), - // ---------------------------------------------------------------------- - // URL Helpers + /** + * MSIE 6 requires the entire hash to be encoded for the hashes to trigger the onHashChange event + */ + hashEscape: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 7) + }; - /** - * History.getRootUrl() - * Turns "http://mysite.com/dir/page.html?asd" into "http://mysite.com" - * @return {String} rootUrl - */ - History.getRootUrl = function() { - // Create - var rootUrl = document.location.protocol + '//' + (document.location.hostname || document.location.host); - if (document.location.port || false) { - rootUrl += ':' + document.location.port; - } - rootUrl += '/'; + /** + * History.isEmptyObject(obj) + * Checks to see if the Object is Empty + * @param {Object} obj + * @return {boolean} + */ + History.isEmptyObject = function(obj) { + for (var name in obj) { + return false; + } + return true; + }; - // Return - return rootUrl; - }; + /** + * History.cloneObject(obj) + * Clones a object + * @param {Object} obj + * @return {Object} + */ + History.cloneObject = function(obj) { + var hash,newObj; + if (obj) { + hash = JSON.stringify(obj); + newObj = JSON.parse(hash); + } + else { + newObj = {}; + } + return newObj; + }; - /** - * History.getBaseHref() - * Fetches the `href` attribute of the `<base href="...">` element if it exists - * @return {String} baseHref - */ - History.getBaseHref = function() { - // Create - var - baseElements = document.getElementsByTagName('base'), - baseElement = null, - baseHref = ''; + // ---------------------------------------------------------------------- + // URL Helpers - // Test for Base Element - if (baseElements.length === 1) { - // Prepare for Base Element - baseElement = baseElements[0]; - baseHref = baseElement.href.replace(/[^\/]+$/, ''); - } + /** + * History.getRootUrl() + * Turns "http://mysite.com/dir/page.html?asd" into "http://mysite.com" + * @return {String} rootUrl + */ + History.getRootUrl = function() { + // Create + var rootUrl = document.location.protocol + '//' + (document.location.hostname || document.location.host); + if (document.location.port || false) { + rootUrl += ':' + document.location.port; + } + rootUrl += '/'; - // Adjust trailing slash - baseHref = baseHref.replace(/\/+$/, ''); - if (baseHref) baseHref += '/'; + // Return + return rootUrl; + }; - // Return - return baseHref; - }; + /** + * History.getBaseHref() + * Fetches the `href` attribute of the `<base href="...">` element if it exists + * @return {String} baseHref + */ + History.getBaseHref = function() { + // Create + var + baseElements = document.getElementsByTagName('base'), + baseElement = null, + baseHref = ''; - /** - * History.getBaseUrl() - * Fetches the baseHref or basePageUrl or rootUrl (whichever one exists first) - * @return {String} baseUrl - */ - History.getBaseUrl = function() { - // Create - var baseUrl = History.getBaseHref() || History.getBasePageUrl() || History.getRootUrl(); + // Test for Base Element + if (baseElements.length === 1) { + // Prepare for Base Element + baseElement = baseElements[0]; + baseHref = baseElement.href.replace(/[^\/]+$/, ''); + } - // Return - return baseUrl; - }; + // Adjust trailing slash + baseHref = baseHref.replace(/\/+$/, ''); + if (baseHref) baseHref += '/'; - /** - * History.getPageUrl() - * Fetches the URL of the current page - * @return {String} pageUrl - */ - History.getPageUrl = function() { - // Fetch - var - State = History.getState(false, false), - stateUrl = (State || {}).url || document.location.href; + // Return + return baseHref; + }; - // Create - var pageUrl = stateUrl.replace(/\/+$/, '').replace(/[^\/]+$/, function(part, index, string) { - return (/\./).test(part) ? part : part + '/'; - }); + /** + * History.getBaseUrl() + * Fetches the baseHref or basePageUrl or rootUrl (whichever one exists first) + * @return {String} baseUrl + */ + History.getBaseUrl = function() { + // Create + var baseUrl = History.getBaseHref() || History.getBasePageUrl() || History.getRootUrl(); - // Return - return pageUrl; - }; + // Return + return baseUrl; + }; - /** - * History.getBasePageUrl() - * Fetches the Url of the directory of the current page - * @return {String} basePageUrl - */ - History.getBasePageUrl = function() { - // Create - var basePageUrl = document.location.href.replace(/[#\?].*/, '').replace(/[^\/]+$/, - function(part, index, string) { - return (/[^\/]$/).test(part) ? '' : part; - }).replace(/\/+$/, '') + '/'; + /** + * History.getPageUrl() + * Fetches the URL of the current page + * @return {String} pageUrl + */ + History.getPageUrl = function() { + // Fetch + var + State = History.getState(false, false), + stateUrl = (State || {}).url || document.location.href; - // Return - return basePageUrl; - }; + // Create + var pageUrl = stateUrl.replace(/\/+$/, '').replace(/[^\/]+$/, function(part, index, string) { + return (/\./).test(part) ? part : part + '/'; + }); - /** - * History.getFullUrl(url) - * Ensures that we have an absolute URL and not a relative URL - * @param {string} url - * @param {Boolean} allowBaseHref - * @return {string} fullUrl - */ - History.getFullUrl = function(url, allowBaseHref) { - // Prepare - var fullUrl = url, firstChar = url.substring(0, 1); - allowBaseHref = (typeof allowBaseHref === 'undefined') ? true : allowBaseHref; + // Return + return pageUrl; + }; - // Check - if (/[a-z]+\:\/\//.test(url)) { - // Full URL - } - else if (firstChar === '/') { - // Root URL - fullUrl = History.getRootUrl() + url.replace(/^\/+/, ''); - } - else if (firstChar === '#') { - // Anchor URL - fullUrl = History.getPageUrl().replace(/#.*/, '') + url; - } - else if (firstChar === '?') { - // Query URL - fullUrl = History.getPageUrl().replace(/[\?#].*/, '') + url; - } - else { - // Relative URL - if (allowBaseHref) { - fullUrl = History.getBaseUrl() + url.replace(/^(\.\/)+/, ''); - } else { - fullUrl = History.getBasePageUrl() + url.replace(/^(\.\/)+/, ''); - } - // We have an if condition above as we do not want hashes - // which are relative to the baseHref in our URLs - // as if the baseHref changes, then all our bookmarks - // would now point to different locations - // whereas the basePageUrl will always stay the same - } + /** + * History.getBasePageUrl() + * Fetches the Url of the directory of the current page + * @return {String} basePageUrl + */ + History.getBasePageUrl = function() { + // Create + var basePageUrl = document.location.href.replace(/[#\?].*/, '').replace(/[^\/]+$/, + function(part, index, string) { + return (/[^\/]$/).test(part) ? '' : part; + }).replace(/\/+$/, '') + '/'; - // Return - return fullUrl.replace(/\#$/, ''); - }; + // Return + return basePageUrl; + }; - /** - * History.getShortUrl(url) - * Ensures that we have a relative URL and not a absolute URL - * @param {string} url - * @return {string} url - */ - History.getShortUrl = function(url) { - // Prepare - var shortUrl = url, baseUrl = History.getBaseUrl(), rootUrl = History.getRootUrl(); + /** + * History.getFullUrl(url) + * Ensures that we have an absolute URL and not a relative URL + * @param {string} url + * @param {Boolean} allowBaseHref + * @return {string} fullUrl + */ + History.getFullUrl = function(url, allowBaseHref) { + // Prepare + var fullUrl = url, firstChar = url.substring(0, 1); + allowBaseHref = (typeof allowBaseHref === 'undefined') ? true : allowBaseHref; - // Trim baseUrl - if (History.emulated.pushState) { - // We are in a if statement as when pushState is not emulated - // The actual url these short urls are relative to can change - // So within the same session, we the url may end up somewhere different - shortUrl = shortUrl.replace(baseUrl, ''); - } + // Check + if (/[a-z]+\:\/\//.test(url)) { + // Full URL + } + else if (firstChar === '/') { + // Root URL + fullUrl = History.getRootUrl() + url.replace(/^\/+/, ''); + } + else if (firstChar === '#') { + // Anchor URL + fullUrl = History.getPageUrl().replace(/#.*/, '') + url; + } + else if (firstChar === '?') { + // Query URL + fullUrl = History.getPageUrl().replace(/[\?#].*/, '') + url; + } + else { + // Relative URL + if (allowBaseHref) { + fullUrl = History.getBaseUrl() + url.replace(/^(\.\/)+/, ''); + } else { + fullUrl = History.getBasePageUrl() + url.replace(/^(\.\/)+/, ''); + } + // We have an if condition above as we do not want hashes + // which are relative to the baseHref in our URLs + // as if the baseHref changes, then all our bookmarks + // would now point to different locations + // whereas the basePageUrl will always stay the same + } - // Trim rootUrl - shortUrl = shortUrl.replace(rootUrl, '/'); + // Return + return fullUrl.replace(/\#$/, ''); + }; - // Ensure we can still detect it as a state - if (History.isTraditionalAnchor(shortUrl)) { - shortUrl = './' + shortUrl; - } + /** + * History.getShortUrl(url) + * Ensures that we have a relative URL and not a absolute URL + * @param {string} url + * @return {string} url + */ + History.getShortUrl = function(url) { + // Prepare + var shortUrl = url, baseUrl = History.getBaseUrl(), rootUrl = History.getRootUrl(); - // Clean It - shortUrl = shortUrl.replace(/^(\.\/)+/g, './').replace(/\#$/, ''); + // Trim baseUrl + if (History.emulated.pushState) { + // We are in a if statement as when pushState is not emulated + // The actual url these short urls are relative to can change + // So within the same session, we the url may end up somewhere different + shortUrl = shortUrl.replace(baseUrl, ''); + } - // Return - return shortUrl; - }; + // Trim rootUrl + shortUrl = shortUrl.replace(rootUrl, '/'); - // ---------------------------------------------------------------------- - // State Storage + // Ensure we can still detect it as a state + if (History.isTraditionalAnchor(shortUrl)) { + shortUrl = './' + shortUrl; + } - /** - * History.store - * The store for all session specific data - */ - History.store = amplify ? (amplify.store('History.store') || {}) : {}; - History.store.idToState = History.store.idToState || {}; - History.store.urlToId = History.store.urlToId || {}; - History.store.stateToId = History.store.stateToId || {}; + // Clean It + shortUrl = shortUrl.replace(/^(\.\/)+/g, './').replace(/\#$/, ''); - /** - * History.idToState - * 1-1: State ID to State Object - */ - History.idToState = History.idToState || {}; + // Return + return shortUrl; + }; - /** - * History.stateToId - * 1-1: State String to State ID - */ - History.stateToId = History.stateToId || {}; + // ---------------------------------------------------------------------- + // State Storage - /** - * History.urlToId - * 1-1: State URL to State ID - */ - History.urlToId = History.urlToId || {}; + /** + * History.store + * The store for all session specific data + */ + History.store = amplify ? (amplify.store('History.store') || {}) : {}; + History.store.idToState = History.store.idToState || {}; + History.store.urlToId = History.store.urlToId || {}; + History.store.stateToId = History.store.stateToId || {}; - /** - * History.storedStates - * Store the states in an array - */ - History.storedStates = History.storedStates || []; + /** + * History.idToState + * 1-1: State ID to State Object + */ + History.idToState = History.idToState || {}; - /** - * History.savedStates - * Saved the states in an array - */ - History.savedStates = History.savedStates || []; + /** + * History.stateToId + * 1-1: State String to State ID + */ + History.stateToId = History.stateToId || {}; - /** - * History.getState() - * Get an object containing the data, title and url of the current state - * @param {Boolean} friendly - * @param {Boolean} create - * @return {Object} State - */ - History.getState = function(friendly, create) { - // Prepare - if (typeof friendly === 'undefined') { - friendly = true; - } - if (typeof create === 'undefined') { - create = true; - } + /** + * History.urlToId + * 1-1: State URL to State ID + */ + History.urlToId = History.urlToId || {}; - // Fetch - var State = History.getLastSavedState(); + /** + * History.storedStates + * Store the states in an array + */ + History.storedStates = History.storedStates || []; - // Create - if (!State && create) { - State = History.createStateObject(); - } + /** + * History.savedStates + * Saved the states in an array + */ + History.savedStates = History.savedStates || []; - // Adjust - if (friendly) { - State = History.cloneObject(State); - State.url = State.cleanUrl || State.url; - } + /** + * History.getState() + * Get an object containing the data, title and url of the current state + * @param {Boolean} friendly + * @param {Boolean} create + * @return {Object} State + */ + History.getState = function(friendly, create) { + // Prepare + if (typeof friendly === 'undefined') { + friendly = true; + } + if (typeof create === 'undefined') { + create = true; + } - // Return - return State; - }; + // Fetch + var State = History.getLastSavedState(); - /** - * History.getIdByState(State) - * Gets a ID for a State - * @param {State} newState - * @return {String} id - */ - History.getIdByState = function(newState) { + // Create + if (!State && create) { + State = History.createStateObject(); + } - // Fetch ID - var id = History.extractId(newState.url); - if (!id) { - // Find ID via State String - var str = History.getStateString(newState); - if (typeof History.stateToId[str] !== 'undefined') { - id = History.stateToId[str]; - } - else if (typeof History.store.stateToId[str] !== 'undefined') { - id = History.store.stateToId[str]; - } - else { - // Generate a new ID - while (true) { - id = String(Math.floor(Math.random() * 1000)); - if (typeof History.idToState[id] === 'undefined' && typeof History.store.idToState[id] === 'undefined') { - break; - } - } + // Adjust + if (friendly) { + State = History.cloneObject(State); + State.url = State.cleanUrl || State.url; + } - // Apply the new State to the ID - History.stateToId[str] = id; - History.idToState[id] = newState; - } - } + // Return + return State; + }; - // Return ID - return id; - }; + /** + * History.getIdByState(State) + * Gets a ID for a State + * @param {State} newState + * @return {String} id + */ + History.getIdByState = function(newState) { - /** - * History.normalizeState(State) - * Expands a State Object - * @param {object} State - * @return {object} - */ - History.normalizeState = function(oldState) { - // Prepare - if (!oldState || (typeof oldState !== 'object')) { - oldState = {}; + // Fetch ID + var id = History.extractId(newState.url); + if (!id) { + // Find ID via State String + var str = History.getStateString(newState); + if (typeof History.stateToId[str] !== 'undefined') { + id = History.stateToId[str]; + } + else if (typeof History.store.stateToId[str] !== 'undefined') { + id = History.store.stateToId[str]; + } + else { + // Generate a new ID + while (true) { + id = String(Math.floor(Math.random() * 1000)); + if (typeof History.idToState[id] === 'undefined' && typeof History.store.idToState[id] === 'undefined') { + break; } + } - // Check - if (typeof oldState.normalized !== 'undefined') { - return oldState; - } + // Apply the new State to the ID + History.stateToId[str] = id; + History.idToState[id] = newState; + } + } - // Adjust - if (!oldState.data || (typeof oldState.data !== 'object')) { - oldState.data = {}; - } + // Return ID + return id; + }; - // ---------------------------------------------------------------------- + /** + * History.normalizeState(State) + * Expands a State Object + * @param {object} State + * @return {object} + */ + History.normalizeState = function(oldState) { + // Prepare + if (!oldState || (typeof oldState !== 'object')) { + oldState = {}; + } - // Create - var newState = {}; - newState.normalized = true; - newState.title = oldState.title || ''; - newState.url = History.getFullUrl(History.unescapeString(oldState.url || document.location.href)); - newState.hash = History.getShortUrl(newState.url); - newState.data = History.cloneObject(oldState.data); + // Check + if (typeof oldState.normalized !== 'undefined') { + return oldState; + } - // Fetch ID - newState.id = History.getIdByState(newState); + // Adjust + if (!oldState.data || (typeof oldState.data !== 'object')) { + oldState.data = {}; + } - // ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- - // Clean the URL - newState.cleanUrl = newState.url.replace(/\??\&_suid.*/, ''); - newState.url = newState.cleanUrl; + // Create + var newState = {}; + newState.normalized = true; + newState.title = oldState.title || ''; + newState.url = History.getFullUrl(History.unescapeString(oldState.url || document.location.href)); + newState.hash = History.getShortUrl(newState.url); + newState.data = History.cloneObject(oldState.data); - // Check to see if we have more than just a url - var dataNotEmpty = !History.isEmptyObject(newState.data); + // Fetch ID + newState.id = History.getIdByState(newState); - // Apply - if (newState.title || dataNotEmpty) { - // Add ID to Hash - newState.hash = History.getShortUrl(newState.url).replace(/\??\&_suid.*/, ''); - if (!/\?/.test(newState.hash)) { - newState.hash += '?'; - } - newState.hash += '&_suid=' + newState.id; - } + // ---------------------------------------------------------------------- - // Create the Hashed URL - newState.hashedUrl = History.getFullUrl(newState.hash); + // Clean the URL + newState.cleanUrl = newState.url.replace(/\??\&_suid.*/, ''); + newState.url = newState.cleanUrl; - // ---------------------------------------------------------------------- + // Check to see if we have more than just a url + var dataNotEmpty = !History.isEmptyObject(newState.data); - // Update the URL if we have a duplicate - if ((History.emulated.pushState || History.bugs.safariPoll) && History.hasUrlDuplicate(newState)) { - newState.url = newState.hashedUrl; - } + // Apply + if (newState.title || dataNotEmpty) { + // Add ID to Hash + newState.hash = History.getShortUrl(newState.url).replace(/\??\&_suid.*/, ''); + if (!/\?/.test(newState.hash)) { + newState.hash += '?'; + } + newState.hash += '&_suid=' + newState.id; + } - // ---------------------------------------------------------------------- + // Create the Hashed URL + newState.hashedUrl = History.getFullUrl(newState.hash); - // Return - return newState; - }; + // ---------------------------------------------------------------------- - /** - * History.createStateObject(data,title,url) - * Creates a object based on the data, title and url state params - * @param {object} data - * @param {string} title - * @param {string} url - * @return {object} - */ - History.createStateObject = function(data, title, url) { - // Hashify - var State = { - 'data': data, - 'title': title, - 'url': url - }; + // Update the URL if we have a duplicate + if ((History.emulated.pushState || History.bugs.safariPoll) && History.hasUrlDuplicate(newState)) { + newState.url = newState.hashedUrl; + } - // Expand the State - State = History.normalizeState(State); + // ---------------------------------------------------------------------- - // Return object - return State; - }; + // Return + return newState; + }; - /** - * History.getStateById(id) - * Get a state by it's UID - * @param {String} id - */ - History.getStateById = function(id) { - // Prepare - id = String(id); + /** + * History.createStateObject(data,title,url) + * Creates a object based on the data, title and url state params + * @param {object} data + * @param {string} title + * @param {string} url + * @return {object} + */ + History.createStateObject = function(data, title, url) { + // Hashify + var State = { + 'data': data, + 'title': title, + 'url': url + }; - // Retrieve - var State = History.idToState[id] || History.store.idToState[id] || undefined; + // Expand the State + State = History.normalizeState(State); - // Return State - return State; - }; + // Return object + return State; + }; - /** - * Get a State's String - * @param {State} passedState - */ - History.getStateString = function(passedState) { - // Prepare - var State = History.normalizeState(passedState); + /** + * History.getStateById(id) + * Get a state by it's UID + * @param {String} id + */ + History.getStateById = function(id) { + // Prepare + id = String(id); - // Clean - var cleanedState = { - data: State.data, - title: passedState.title, - url: passedState.url - }; + // Retrieve + var State = History.idToState[id] || History.store.idToState[id] || undefined; - // Fetch - var str = JSON.stringify(cleanedState); + // Return State + return State; + }; - // Return - return str; - }; + /** + * Get a State's String + * @param {State} passedState + */ + History.getStateString = function(passedState) { + // Prepare + var State = History.normalizeState(passedState); - /** - * Get a State's ID - * @param {State} passedState - * @return {String} id - */ - History.getStateId = function(passedState) { - // Prepare - var State = History.normalizeState(passedState); + // Clean + var cleanedState = { + data: State.data, + title: passedState.title, + url: passedState.url + }; - // Fetch - var id = State.id; + // Fetch + var str = JSON.stringify(cleanedState); - // Return - return id; - }; + // Return + return str; + }; - /** - * History.getHashByState(State) - * Creates a Hash for the State Object - * @param {State} passedState - * @return {String} hash - */ - History.getHashByState = function(passedState) { - // Prepare - var hash, State = History.normalizeState(passedState); + /** + * Get a State's ID + * @param {State} passedState + * @return {String} id + */ + History.getStateId = function(passedState) { + // Prepare + var State = History.normalizeState(passedState); - // Fetch - hash = State.hash; + // Fetch + var id = State.id; - // Return - return hash; - }; + // Return + return id; + }; - /** - * History.extractId(url_or_hash) - * Get a State ID by it's URL or Hash - * @param {string} url_or_hash - * @return {string} id - */ - History.extractId = function (url_or_hash) { - // Prepare - var id; + /** + * History.getHashByState(State) + * Creates a Hash for the State Object + * @param {State} passedState + * @return {String} hash + */ + History.getHashByState = function(passedState) { + // Prepare + var hash, State = History.normalizeState(passedState); - // Extract - var parts,url; - parts = /(.*)\&_suid=([0-9]+)$/.exec(url_or_hash); - url = parts ? (parts[1] || url_or_hash) : url_or_hash; - id = parts ? String(parts[2] || '') : ''; + // Fetch + hash = State.hash; - // Return - return id || false; - }; + // Return + return hash; + }; - /** - * History.isTraditionalAnchor - * Checks to see if the url is a traditional anchor or not - * @param {String} url_or_hash - * @return {Boolean} - */ - History.isTraditionalAnchor = function(url_or_hash) { - // Check - var isTraditional = !(/[\/\?\.]/.test(url_or_hash)); + /** + * History.extractId(url_or_hash) + * Get a State ID by it's URL or Hash + * @param {string} url_or_hash + * @return {string} id + */ + History.extractId = function (url_or_hash) { + // Prepare + var id; - // Return - return isTraditional; - }; + // Extract + var parts,url; + parts = /(.*)\&_suid=([0-9]+)$/.exec(url_or_hash); + url = parts ? (parts[1] || url_or_hash) : url_or_hash; + id = parts ? String(parts[2] || '') : ''; - /** - * History.extractState - * Get a State by it's URL or Hash - * @param {String} url_or_hash - * @return {State|null} - */ - History.extractState = function(url_or_hash, create) { - // Prepare - var State = null; - create = create || false; + // Return + return id || false; + }; - // Fetch SUID - var id = History.extractId(url_or_hash); - if (id) { - State = History.getStateById(id); - } + /** + * History.isTraditionalAnchor + * Checks to see if the url is a traditional anchor or not + * @param {String} url_or_hash + * @return {Boolean} + */ + History.isTraditionalAnchor = function(url_or_hash) { + // Check + var isTraditional = !(/[\/\?\.]/.test(url_or_hash)); - // Fetch SUID returned no State - if (!State) { - // Fetch URL - var url = History.getFullUrl(url_or_hash); + // Return + return isTraditional; + }; - // Check URL - id = History.getIdByUrl(url) || false; - if (id) { - State = History.getStateById(id); - } + /** + * History.extractState + * Get a State by it's URL or Hash + * @param {String} url_or_hash + * @return {State|null} + */ + History.extractState = function(url_or_hash, create) { + // Prepare + var State = null; + create = create || false; - // Create State - if (!State && create && !History.isTraditionalAnchor(url_or_hash)) { - State = History.createStateObject(null, null, url); - } - } + // Fetch SUID + var id = History.extractId(url_or_hash); + if (id) { + State = History.getStateById(id); + } - // Return - return State; - }; + // Fetch SUID returned no State + if (!State) { + // Fetch URL + var url = History.getFullUrl(url_or_hash); - /** - * History.getIdByUrl() - * Get a State ID by a State URL - */ - History.getIdByUrl = function(url) { - // Fetch - var id = History.urlToId[url] || History.store.urlToId[url] || undefined; + // Check URL + id = History.getIdByUrl(url) || false; + if (id) { + State = History.getStateById(id); + } - // Return - return id; - }; + // Create State + if (!State && create && !History.isTraditionalAnchor(url_or_hash)) { + State = History.createStateObject(null, null, url); + } + } - /** - * History.getLastSavedState() - * Get an object containing the data, title and url of the current state - * @return {Object} State - */ - History.getLastSavedState = function() { - return History.savedStates[History.savedStates.length - 1] || undefined; - }; + // Return + return State; + }; - /** - * History.getLastStoredState() - * Get an object containing the data, title and url of the current state - * @return {Object} State - */ - History.getLastStoredState = function() { - return History.storedStates[History.storedStates.length - 1] || undefined; - }; + /** + * History.getIdByUrl() + * Get a State ID by a State URL + */ + History.getIdByUrl = function(url) { + // Fetch + var id = History.urlToId[url] || History.store.urlToId[url] || undefined; - /** - * History.hasUrlDuplicate - * Checks if a Url will have a url conflict - * @param {Object} newState - * @return {Boolean} hasDuplicate - */ - History.hasUrlDuplicate = function(newState) { - // Prepare - var hasDuplicate = false; + // Return + return id; + }; - // Fetch - var oldState = History.extractState(newState.url); + /** + * History.getLastSavedState() + * Get an object containing the data, title and url of the current state + * @return {Object} State + */ + History.getLastSavedState = function() { + return History.savedStates[History.savedStates.length - 1] || undefined; + }; - // Check - hasDuplicate = oldState && oldState.id !== newState.id; + /** + * History.getLastStoredState() + * Get an object containing the data, title and url of the current state + * @return {Object} State + */ + History.getLastStoredState = function() { + return History.storedStates[History.storedStates.length - 1] || undefined; + }; - // Return - return hasDuplicate; - }; + /** + * History.hasUrlDuplicate + * Checks if a Url will have a url conflict + * @param {Object} newState + * @return {Boolean} hasDuplicate + */ + History.hasUrlDuplicate = function(newState) { + // Prepare + var hasDuplicate = false; - /** - * History.storeState - * Store a State - * @param {Object} newState - * @return {Object} newState - */ - History.storeState = function(newState) { - // Store the State - History.urlToId[newState.url] = newState.id; + // Fetch + var oldState = History.extractState(newState.url); - // Push the State - History.storedStates.push(History.cloneObject(newState)); + // Check + hasDuplicate = oldState && oldState.id !== newState.id; - // Return newState - return newState; - }; + // Return + return hasDuplicate; + }; - /** - * History.isLastSavedState(newState) - * Tests to see if the state is the last state - * @param {Object} newState - * @return {boolean} isLast - */ - History.isLastSavedState = function(newState) { - // Prepare - var isLast = false; + /** + * History.storeState + * Store a State + * @param {Object} newState + * @return {Object} newState + */ + History.storeState = function(newState) { + // Store the State + History.urlToId[newState.url] = newState.id; - // Check - if (History.savedStates.length) { - var - newId = newState.id, - oldState = History.getLastSavedState(), - oldId = oldState.id; + // Push the State + History.storedStates.push(History.cloneObject(newState)); - // Check - isLast = (newId === oldId); - } + // Return newState + return newState; + }; - // Return - return isLast; - }; + /** + * History.isLastSavedState(newState) + * Tests to see if the state is the last state + * @param {Object} newState + * @return {boolean} isLast + */ + History.isLastSavedState = function(newState) { + // Prepare + var isLast = false; - /** - * History.saveState - * Push a State - * @param {Object} newState - * @return {boolean} changed - */ - History.saveState = function(newState) { - // Check Hash - if (History.isLastSavedState(newState)) { - return false; - } + // Check + if (History.savedStates.length) { + var + newId = newState.id, + oldState = History.getLastSavedState(), + oldId = oldState.id; - // Push the State - History.savedStates.push(History.cloneObject(newState)); + // Check + isLast = (newId === oldId); + } - // Return true - return true; - }; + // Return + return isLast; + }; - /** - * History.getStateByIndex() - * Gets a state by the index - * @param {integer} index - * @return {Object} - */ - History.getStateByIndex = function(index) { - // Prepare - var State = null; + /** + * History.saveState + * Push a State + * @param {Object} newState + * @return {boolean} changed + */ + History.saveState = function(newState) { + // Check Hash + if (History.isLastSavedState(newState)) { + return false; + } - // Handle - if (typeof index === 'undefined') { - // Get the last inserted - State = History.savedStates[History.savedStates.length - 1]; - } - else if (index < 0) { - // Get from the end - State = History.savedStates[History.savedStates.length + index]; - } - else { - // Get from the beginning - State = History.savedStates[index]; - } + // Push the State + History.savedStates.push(History.cloneObject(newState)); - // Return State - return State; - }; + // Return true + return true; + }; - // ---------------------------------------------------------------------- - // Hash Helpers + /** + * History.getStateByIndex() + * Gets a state by the index + * @param {integer} index + * @return {Object} + */ + History.getStateByIndex = function(index) { + // Prepare + var State = null; - /** - * History.getHash() - * Gets the current document hash - * @return {string} - */ - History.getHash = function() { - var hash = History.unescapeHash(document.location.hash); - return hash; - }; + // Handle + if (typeof index === 'undefined') { + // Get the last inserted + State = History.savedStates[History.savedStates.length - 1]; + } + else if (index < 0) { + // Get from the end + State = History.savedStates[History.savedStates.length + index]; + } + else { + // Get from the beginning + State = History.savedStates[index]; + } - /** - * History.unescapeString() - * Unescape a string - * @param {String} str - * @return {string} - */ - History.unescapeString = function(str) { - // Prepare - var result = str; + // Return State + return State; + }; - // Unescape hash - var tmp; - while (true) { - tmp = window.unescape(result); - if (tmp === result) { - break; - } - result = tmp; - } + // ---------------------------------------------------------------------- + // Hash Helpers - // Return result - return result; - }; + /** + * History.getHash() + * Gets the current document hash + * @return {string} + */ + History.getHash = function() { + var hash = History.unescapeHash(document.location.hash); + return hash; + }; - /** - * History.unescapeHash() - * normalize and Unescape a Hash - * @param {String} hash - * @return {string} - */ - History.unescapeHash = function(hash) { - // Prepare - var result = History.normalizeHash(hash); + /** + * History.unescapeString() + * Unescape a string + * @param {String} str + * @return {string} + */ + History.unescapeString = function(str) { + // Prepare + var result = str; - // Unescape hash - result = History.unescapeString(result); + // Unescape hash + var tmp; + while (true) { + tmp = window.unescape(result); + if (tmp === result) { + break; + } + result = tmp; + } - // Return result - return result; - }; + // Return result + return result; + }; - /** - * History.normalizeHash() - * normalize a hash across browsers - * @return {string} - */ - History.normalizeHash = function(hash) { - var result = hash.replace(/[^#]*#/, '').replace(/#.*/, ''); + /** + * History.unescapeHash() + * normalize and Unescape a Hash + * @param {String} hash + * @return {string} + */ + History.unescapeHash = function(hash) { + // Prepare + var result = History.normalizeHash(hash); - // Return result - return result; - }; + // Unescape hash + result = History.unescapeString(result); - /** - * History.setHash(hash) - * Sets the document hash - * @param {string} hash - * @return {History} - */ - History.setHash = function(hash, queue) { - // Handle Queueing - if (queue !== false && History.busy()) { - // Wait + Push to Queue - //History.debug('History.setHash: we must wait', arguments); - History.pushQueue({ - scope: History, - callback: History.setHash, - args: arguments, - queue: queue - }); - return false; - } + // Return result + return result; + }; - // Log - //History.debug('History.setHash: called',hash); + /** + * History.normalizeHash() + * normalize a hash across browsers + * @return {string} + */ + History.normalizeHash = function(hash) { + var result = hash.replace(/[^#]*#/, '').replace(/#.*/, ''); - // Prepare - var adjustedHash = History.escapeHash(hash); + // Return result + return result; + }; - // Make Busy + Continue - History.busy(true); + /** + * History.setHash(hash) + * Sets the document hash + * @param {string} hash + * @return {History} + */ + History.setHash = function(hash, queue) { + // Handle Queueing + if (queue !== false && History.busy()) { + // Wait + Push to Queue + //History.debug('History.setHash: we must wait', arguments); + History.pushQueue({ + scope: History, + callback: History.setHash, + args: arguments, + queue: queue + }); + return false; + } - // Check if hash is a state - var State = History.extractState(hash, true); - if (State && !History.emulated.pushState) { - // Hash is a state so skip the setHash - //History.debug('History.setHash: Hash is a state so skipping the hash set with a direct pushState call',arguments); + // Log + //History.debug('History.setHash: called',hash); - // PushState - History.pushState(State.data, State.title, State.url, false); - } - else if (document.location.hash !== adjustedHash) { - // Hash is a proper hash, so apply it + // Prepare + var adjustedHash = History.escapeHash(hash); - // Handle browser bugs - if (History.bugs.setHash) { - // Fix Safari Bug https://bugs.webkit.org/show_bug.cgi?id=56249 + // Make Busy + Continue + History.busy(true); - // Fetch the base page - var pageUrl = History.getPageUrl(); + // Check if hash is a state + var State = History.extractState(hash, true); + if (State && !History.emulated.pushState) { + // Hash is a state so skip the setHash + //History.debug('History.setHash: Hash is a state so skipping the hash set with a direct pushState call',arguments); - // Safari hash apply - History.pushState(null, null, pageUrl + '#' + adjustedHash, false); - } - else { - // Normal hash apply - document.location.hash = adjustedHash; - } - } + // PushState + History.pushState(State.data, State.title, State.url, false); + } + else if (document.location.hash !== adjustedHash) { + // Hash is a proper hash, so apply it - // Chain - return History; - }; + // Handle browser bugs + if (History.bugs.setHash) { + // Fix Safari Bug https://bugs.webkit.org/show_bug.cgi?id=56249 - /** - * History.escape() - * normalize and Escape a Hash - * @return {string} - */ - History.escapeHash = function(hash) { - var result = History.normalizeHash(hash); + // Fetch the base page + var pageUrl = History.getPageUrl(); - // Escape hash - result = window.escape(result); + // Safari hash apply + History.pushState(null, null, pageUrl + '#' + adjustedHash, false); + } + else { + // Normal hash apply + document.location.hash = adjustedHash; + } + } - // IE6 Escape Bug - if (!History.bugs.hashEscape) { - // Restore common parts - result = result - .replace(/\%21/g, '!') - .replace(/\%26/g, '&') - .replace(/\%3D/g, '=') - .replace(/\%3F/g, '?'); - } + // Chain + return History; + }; - // Return result - return result; - }; + /** + * History.escape() + * normalize and Escape a Hash + * @return {string} + */ + History.escapeHash = function(hash) { + var result = History.normalizeHash(hash); - /** - * History.getHashByUrl(url) - * Extracts the Hash from a URL - * @param {string} url - * @return {string} url - */ - History.getHashByUrl = function(url) { - // Extract the hash - var hash = String(url) - .replace(/([^#]*)#?([^#]*)#?(.*)/, '$2') - ; + // Escape hash + result = window.escape(result); - // Unescape hash - hash = History.unescapeHash(hash); + // IE6 Escape Bug + if (!History.bugs.hashEscape) { + // Restore common parts + result = result + .replace(/\%21/g, '!') + .replace(/\%26/g, '&') + .replace(/\%3D/g, '=') + .replace(/\%3F/g, '?'); + } - // Return hash - return hash; - }; + // Return result + return result; + }; - /** - * History.setTitle(title) - * Applies the title to the document - * @param {State} newState - * @return {Boolean} - */ - History.setTitle = function(newState) { - // Prepare - var title = newState.title; + /** + * History.getHashByUrl(url) + * Extracts the Hash from a URL + * @param {string} url + * @return {string} url + */ + History.getHashByUrl = function(url) { + // Extract the hash + var hash = String(url) + .replace(/([^#]*)#?([^#]*)#?(.*)/, '$2') + ; - // Initial - if (!title) { - var firstState = History.getStateByIndex(0); - if (firstState && firstState.url === newState.url) { - title = firstState.title || History.options.initialTitle; - } - } + // Unescape hash + hash = History.unescapeHash(hash); - // Apply - try { - document.getElementsByTagName('title')[0].innerHTML = title.replace('<', '&lt;').replace('>', '&gt;').replace(' & ', ' &amp; '); - } - catch (Exception) { - } - document.title = title; + // Return hash + return hash; + }; - // Chain - return History; - }; + /** + * History.setTitle(title) + * Applies the title to the document + * @param {State} newState + * @return {Boolean} + */ + History.setTitle = function(newState) { + // Prepare + var title = newState.title; - // ---------------------------------------------------------------------- - // Queueing + // Initial + if (!title) { + var firstState = History.getStateByIndex(0); + if (firstState && firstState.url === newState.url) { + title = firstState.title || History.options.initialTitle; + } + } - /** - * History.queues - * The list of queues to use - * First In, First Out - */ - History.queues = []; + // Apply + try { + document.getElementsByTagName('title')[0].innerHTML = title.replace('<', '&lt;').replace('>', '&gt;').replace(' & ', ' &amp; '); + } + catch (Exception) { + } + document.title = title; - /** - * History.busy(value) - * @param {boolean} value [optional] - * @return {boolean} busy - */ - History.busy = function(value) { - // Apply - if (typeof value !== 'undefined') { - //History.debug('History.busy: changing ['+(History.busy.flag||false)+'] to ['+(value||false)+']', History.queues.length); - History.busy.flag = value; - } - // Default - else if (typeof History.busy.flag === 'undefined') { - History.busy.flag = false; - } + // Chain + return History; + }; - // Queue - if (!History.busy.flag) { - // Execute the next item in the queue - clearTimeout(History.busy.timeout); - var fireNext = function() { - if (History.busy.flag) return; - for (var i = History.queues.length - 1; i >= 0; --i) { - var queue = History.queues[i]; - if (queue.length === 0) continue; - var item = queue.shift(); - History.fireQueueItem(item); - History.busy.timeout = setTimeout(fireNext, History.options.busyDelay); - } - }; - History.busy.timeout = setTimeout(fireNext, History.options.busyDelay); - } + // ---------------------------------------------------------------------- + // Queueing - // Return - return History.busy.flag; - }; + /** + * History.queues + * The list of queues to use + * First In, First Out + */ + History.queues = []; - /** - * History.fireQueueItem(item) - * Fire a Queue Item - * @param {Object} item - * @return {Mixed} result - */ - History.fireQueueItem = function(item) { - return item.callback.apply(item.scope || History, item.args || []); + /** + * History.busy(value) + * @param {boolean} value [optional] + * @return {boolean} busy + */ + History.busy = function(value) { + // Apply + if (typeof value !== 'undefined') { + //History.debug('History.busy: changing ['+(History.busy.flag||false)+'] to ['+(value||false)+']', History.queues.length); + History.busy.flag = value; + } + // Default + else if (typeof History.busy.flag === 'undefined') { + History.busy.flag = false; + } + + // Queue + if (!History.busy.flag) { + // Execute the next item in the queue + clearTimeout(History.busy.timeout); + var fireNext = function() { + if (History.busy.flag) return; + for (var i = History.queues.length - 1; i >= 0; --i) { + var queue = History.queues[i]; + if (queue.length === 0) continue; + var item = queue.shift(); + History.fireQueueItem(item); + History.busy.timeout = setTimeout(fireNext, History.options.busyDelay); + } }; + History.busy.timeout = setTimeout(fireNext, History.options.busyDelay); + } - /** - * History.pushQueue(callback,args) - * Add an item to the queue - * @param {Object} item [scope,callback,args,queue] - */ - History.pushQueue = function(item) { - // Prepare the queue - History.queues[item.queue || 0] = History.queues[item.queue || 0] || []; + // Return + return History.busy.flag; + }; - // Add to the queue - History.queues[item.queue || 0].push(item); + /** + * History.fireQueueItem(item) + * Fire a Queue Item + * @param {Object} item + * @return {Mixed} result + */ + History.fireQueueItem = function(item) { + return item.callback.apply(item.scope || History, item.args || []); + }; - // Chain - return History; - }; + /** + * History.pushQueue(callback,args) + * Add an item to the queue + * @param {Object} item [scope,callback,args,queue] + */ + History.pushQueue = function(item) { + // Prepare the queue + History.queues[item.queue || 0] = History.queues[item.queue || 0] || []; - /** - * History.queue (item,queue), (func,queue), (func), (item) - * Either firs the item now if not busy, or adds it to the queue - */ - History.queue = function(item, queue) { - // Prepare - if (typeof item === 'function') { - item = { - callback: item - }; - } - if (typeof queue !== 'undefined') { - item.queue = queue; - } + // Add to the queue + History.queues[item.queue || 0].push(item); - // Handle - if (History.busy()) { - History.pushQueue(item); - } else { - History.fireQueueItem(item); - } + // Chain + return History; + }; - // Chain - return History; + /** + * History.queue (item,queue), (func,queue), (func), (item) + * Either firs the item now if not busy, or adds it to the queue + */ + History.queue = function(item, queue) { + // Prepare + if (typeof item === 'function') { + item = { + callback: item }; + } + if (typeof queue !== 'undefined') { + item.queue = queue; + } - /** - * History.clearQueue() - * Clears the Queue - */ - History.clearQueue = function() { - History.busy.flag = false; - History.queues = []; - return History; - }; + // Handle + if (History.busy()) { + History.pushQueue(item); + } else { + History.fireQueueItem(item); + } + // Chain + return History; + }; - // ---------------------------------------------------------------------- - // IE Bug Fix + /** + * History.clearQueue() + * Clears the Queue + */ + History.clearQueue = function() { + History.busy.flag = false; + History.queues = []; + return History; + }; - /** - * History.stateChanged - * States whether or not the state has changed since the last double check was initialised - */ - History.stateChanged = false; - /** - * History.doubleChecker - * Contains the timeout used for the double checks - */ - History.doubleChecker = false; + // ---------------------------------------------------------------------- + // IE Bug Fix - /** - * History.doubleCheckComplete() - * Complete a double check - * @return {History} - */ - History.doubleCheckComplete = function() { - // Update - History.stateChanged = true; + /** + * History.stateChanged + * States whether or not the state has changed since the last double check was initialised + */ + History.stateChanged = false; - // Clear - History.doubleCheckClear(); + /** + * History.doubleChecker + * Contains the timeout used for the double checks + */ + History.doubleChecker = false; - // Chain - return History; - }; + /** + * History.doubleCheckComplete() + * Complete a double check + * @return {History} + */ + History.doubleCheckComplete = function() { + // Update + History.stateChanged = true; - /** - * History.doubleCheckClear() - * Clear a double check - * @return {History} - */ - History.doubleCheckClear = function() { - // Clear - if (History.doubleChecker) { - clearTimeout(History.doubleChecker); - History.doubleChecker = false; - } + // Clear + History.doubleCheckClear(); - // Chain - return History; - }; + // Chain + return History; + }; - /** - * History.doubleCheck() - * Create a double check - * @return {History} - */ - History.doubleCheck = function(tryAgain) { - // Reset - History.stateChanged = false; - History.doubleCheckClear(); + /** + * History.doubleCheckClear() + * Clear a double check + * @return {History} + */ + History.doubleCheckClear = function() { + // Clear + if (History.doubleChecker) { + clearTimeout(History.doubleChecker); + History.doubleChecker = false; + } - // Fix IE6,IE7 bug where calling history.back or history.forward does not actually change the hash (whereas doing it manually does) - // Fix Safari 5 bug where sometimes the state does not change: https://bugs.webkit.org/show_bug.cgi?id=42940 - if (History.bugs.ieDoubleCheck) { - // Apply Check - History.doubleChecker = setTimeout( - function() { - History.doubleCheckClear(); - if (!History.stateChanged) { - //History.debug('History.doubleCheck: State has not yet changed, trying again', arguments); - // Re-Attempt - tryAgain(); - } - return true; - }, - History.options.doubleCheckInterval - ); - } + // Chain + return History; + }; - // Chain - return History; - }; + /** + * History.doubleCheck() + * Create a double check + * @return {History} + */ + History.doubleCheck = function(tryAgain) { + // Reset + History.stateChanged = false; + History.doubleCheckClear(); - // ---------------------------------------------------------------------- - // Safari Bug Fix + // Fix IE6,IE7 bug where calling history.back or history.forward does not actually change the hash (whereas doing it manually does) + // Fix Safari 5 bug where sometimes the state does not change: https://bugs.webkit.org/show_bug.cgi?id=42940 + if (History.bugs.ieDoubleCheck) { + // Apply Check + History.doubleChecker = setTimeout( + function() { + History.doubleCheckClear(); + if (!History.stateChanged) { + //History.debug('History.doubleCheck: State has not yet changed, trying again', arguments); + // Re-Attempt + tryAgain(); + } + return true; + }, + History.options.doubleCheckInterval + ); + } - /** - * History.safariStatePoll() - * Poll the current state - * @return {History} - */ - History.safariStatePoll = function() { - // Poll the URL + // Chain + return History; + }; - // Get the Last State which has the new URL - var - urlState = History.extractState(document.location.href), - newState; + // ---------------------------------------------------------------------- + // Safari Bug Fix - // Check for a difference - if (!History.isLastSavedState(urlState)) { - newState = urlState; - } - else { - return; - } + /** + * History.safariStatePoll() + * Poll the current state + * @return {History} + */ + History.safariStatePoll = function() { + // Poll the URL - // Check if we have a state with that url - // If not create it - if (!newState) { - //History.debug('History.safariStatePoll: new'); - newState = History.createStateObject(); - } + // Get the Last State which has the new URL + var + urlState = History.extractState(document.location.href), + newState; - // Apply the New State - //History.debug('History.safariStatePoll: trigger'); - History.Adapter.trigger(window, 'popstate'); + // Check for a difference + if (!History.isLastSavedState(urlState)) { + newState = urlState; + } + else { + return; + } - // Chain - return History; - }; + // Check if we have a state with that url + // If not create it + if (!newState) { + //History.debug('History.safariStatePoll: new'); + newState = History.createStateObject(); + } - // ---------------------------------------------------------------------- - // State Aliases + // Apply the New State + //History.debug('History.safariStatePoll: trigger'); + History.Adapter.trigger(window, 'popstate'); - /** - * History.back(queue) - * Send the browser history back one item - * @param {Integer} queue [optional] - */ - History.back = function(queue) { - //History.debug('History.back: called', arguments); + // Chain + return History; + }; - // Handle Queueing - if (queue !== false && History.busy()) { - // Wait + Push to Queue - //History.debug('History.back: we must wait', arguments); - History.pushQueue({ - scope: History, - callback: History.back, - args: arguments, - queue: queue - }); - return false; - } + // ---------------------------------------------------------------------- + // State Aliases - // Make Busy + Continue - History.busy(true); + /** + * History.back(queue) + * Send the browser history back one item + * @param {Integer} queue [optional] + */ + History.back = function(queue) { + //History.debug('History.back: called', arguments); - // Fix certain browser bugs that prevent the state from changing - History.doubleCheck(function() { - History.back(false); - }); + // Handle Queueing + if (queue !== false && History.busy()) { + // Wait + Push to Queue + //History.debug('History.back: we must wait', arguments); + History.pushQueue({ + scope: History, + callback: History.back, + args: arguments, + queue: queue + }); + return false; + } - // Go back - history.go(-1); + // Make Busy + Continue + History.busy(true); - // End back closure - return true; - }; + // Fix certain browser bugs that prevent the state from changing + History.doubleCheck(function() { + History.back(false); + }); - /** - * History.forward(queue) - * Send the browser history forward one item - * @param {Integer} queue [optional] - */ - History.forward = function(queue) { - //History.debug('History.forward: called', arguments); + // Go back + history.go(-1); - // Handle Queueing - if (queue !== false && History.busy()) { - // Wait + Push to Queue - //History.debug('History.forward: we must wait', arguments); - History.pushQueue({ - scope: History, - callback: History.forward, - args: arguments, - queue: queue - }); - return false; - } + // End back closure + return true; + }; - // Make Busy + Continue - History.busy(true); + /** + * History.forward(queue) + * Send the browser history forward one item + * @param {Integer} queue [optional] + */ + History.forward = function(queue) { + //History.debug('History.forward: called', arguments); - // Fix certain browser bugs that prevent the state from changing - History.doubleCheck(function() { - History.forward(false); - }); + // Handle Queueing + if (queue !== false && History.busy()) { + // Wait + Push to Queue + //History.debug('History.forward: we must wait', arguments); + History.pushQueue({ + scope: History, + callback: History.forward, + args: arguments, + queue: queue + }); + return false; + } - // Go forward - history.go(1); + // Make Busy + Continue + History.busy(true); - // End forward closure - return true; - }; + // Fix certain browser bugs that prevent the state from changing + History.doubleCheck(function() { + History.forward(false); + }); - /** - * History.go(index,queue) - * Send the browser history back or forward index times - * @param {Integer} queue [optional] - */ - History.go = function(index, queue) { - //History.debug('History.go: called', arguments); + // Go forward + history.go(1); - // Prepare - var i; + // End forward closure + return true; + }; - // Handle - if (index > 0) { - // Forward - for (i = 1; i <= index; ++i) { - History.forward(queue); - } - } - else if (index < 0) { - // Backward - for (i = -1; i >= index; --i) { - History.back(queue); - } - } - else { - throw new Error('History.go: History.go requires a positive or negative integer passed.'); - } + /** + * History.go(index,queue) + * Send the browser history back or forward index times + * @param {Integer} queue [optional] + */ + History.go = function(index, queue) { + //History.debug('History.go: called', arguments); - // Chain - return History; - }; + // Prepare + var i; + // Handle + if (index > 0) { + // Forward + for (i = 1; i <= index; ++i) { + History.forward(queue); + } + } + else if (index < 0) { + // Backward + for (i = -1; i >= index; --i) { + History.back(queue); + } + } + else { + throw new Error('History.go: History.go requires a positive or negative integer passed.'); + } - // ---------------------------------------------------------------------- - // Initialise + // Chain + return History; + }; - /** - * Create the initial State - */ - History.saveState(History.storeState(History.extractState(document.location.href, true))); - /** - * Bind for Saving Store - */ - if (amplify) { - History.onUnload = function() { - // Prepare - var - currentStore = amplify.store('History.store') || {}, - item; + // ---------------------------------------------------------------------- + // Initialise - // Ensure - currentStore.idToState = currentStore.idToState || {}; - currentStore.urlToId = currentStore.urlToId || {}; - currentStore.stateToId = currentStore.stateToId || {}; + /** + * Create the initial State + */ + History.saveState(History.storeState(History.extractState(document.location.href, true))); - // Sync - for (item in History.idToState) { - if (!History.idToState.hasOwnProperty(item)) { - continue; - } - currentStore.idToState[item] = History.idToState[item]; - } - for (item in History.urlToId) { - if (!History.urlToId.hasOwnProperty(item)) { - continue; - } - currentStore.urlToId[item] = History.urlToId[item]; - } - for (item in History.stateToId) { - if (!History.stateToId.hasOwnProperty(item)) { - continue; - } - currentStore.stateToId[item] = History.stateToId[item]; - } + /** + * Bind for Saving Store + */ + if (amplify) { + History.onUnload = function() { + // Prepare + var + currentStore = amplify.store('History.store') || {}, + item; - // Update - History.store = currentStore; + // Ensure + currentStore.idToState = currentStore.idToState || {}; + currentStore.urlToId = currentStore.urlToId || {}; + currentStore.stateToId = currentStore.stateToId || {}; - // Store - amplify.store('History.store', currentStore); - }; - // For Internet Explorer - setInterval(History.onUnload, History.options.storeInterval); - // For Other Browsers - History.Adapter.bind(window, 'beforeunload', History.onUnload); - History.Adapter.bind(window, 'unload', History.onUnload); - // Both are enabled for consistency + // Sync + for (item in History.idToState) { + if (!History.idToState.hasOwnProperty(item)) { + continue; + } + currentStore.idToState[item] = History.idToState[item]; } + for (item in History.urlToId) { + if (!History.urlToId.hasOwnProperty(item)) { + continue; + } + currentStore.urlToId[item] = History.urlToId[item]; + } + for (item in History.stateToId) { + if (!History.stateToId.hasOwnProperty(item)) { + continue; + } + currentStore.stateToId[item] = History.stateToId[item]; + } + // Update + History.store = currentStore; - // ---------------------------------------------------------------------- - // HTML5 State Support + // Store + amplify.store('History.store', currentStore); + }; + // For Internet Explorer + History.intervalList.push(setInterval(History.onUnload, History.options.storeInterval)); + // For Other Browsers + History.Adapter.bind(window, 'beforeunload', History.onUnload); + History.Adapter.bind(window, 'unload', History.onUnload); + // Both are enabled for consistency + } - if (History.emulated.pushState) { - /* - * Provide Skeleton for HTML4 Browsers - */ - // Prepare - var emptyFunction = function() { - }; - History.pushState = History.pushState || emptyFunction; - History.replaceState = History.replaceState || emptyFunction; - } - else { - /* - * Use native HTML5 History API Implementation - */ + // ---------------------------------------------------------------------- + // HTML5 State Support - /** - * History.onPopState(event,extra) - * Refresh the Current State - */ - History.onPopState = function(event) { - // Reset the double check - History.doubleCheckComplete(); + if (History.emulated.pushState) { + /* + * Provide Skeleton for HTML4 Browsers + */ - // Check for a Hash, and handle apporiatly - var currentHash = History.getHash(); - if (currentHash) { - // Expand Hash - var currentState = History.extractState(currentHash || document.location.href, true); - if (currentState) { - // We were able to parse it, it must be a State! - // Let's forward to replaceState - //History.debug('History.onPopState: state anchor', currentHash, currentState); - History.replaceState(currentState.data, currentState.title, currentState.url, false); - } - else { - // Traditional Anchor - //History.debug('History.onPopState: traditional anchor', currentHash); - History.Adapter.trigger(window, 'anchorchange'); - History.busy(false); - } + // Prepare + var emptyFunction = function() { + }; + History.pushState = History.pushState || emptyFunction; + History.replaceState = History.replaceState || emptyFunction; + } + else { + /* + * Use native HTML5 History API Implementation + */ - // We don't care for hashes - History.expectedStateId = false; - return false; - } + /** + * History.onPopState(event,extra) + * Refresh the Current State + */ + History.onPopState = function(event) { + // Reset the double check + History.doubleCheckComplete(); - // Prepare - var newState = false; + // Check for a Hash, and handle apporiatly + var currentHash = History.getHash(); + if (currentHash) { + // Expand Hash + var currentState = History.extractState(currentHash || document.location.href, true); + if (currentState) { + // We were able to parse it, it must be a State! + // Let's forward to replaceState + //History.debug('History.onPopState: state anchor', currentHash, currentState); + History.replaceState(currentState.data, currentState.title, currentState.url, false); + } + else { + // Traditional Anchor + //History.debug('History.onPopState: traditional anchor', currentHash); + History.Adapter.trigger(window, 'anchorchange'); + History.busy(false); + } - // Prepare - event = event || {}; - if (typeof event.state === 'undefined') { - // jQuery - if (typeof event.originalEvent !== 'undefined' && typeof event.originalEvent.state !== 'undefined') { - event.state = event.originalEvent.state || false; - } - // MooTools - else if (typeof event.event !== 'undefined' && typeof event.event.state !== 'undefined') { - event.state = event.event.state || false; - } - } + // We don't care for hashes + History.expectedStateId = false; + return false; + } - // Ensure - event.state = (event.state || false); + // Prepare + var newState = false; - // Fetch State - if (event.state) { - // Vanilla: Back/forward button was used - newState = History.getStateById(event.state); - } - else if (History.expectedStateId) { - // Vanilla: A new state was pushed, and popstate was called manually - newState = History.getStateById(History.expectedStateId); - } - else { - // Initial State - newState = History.extractState(document.location.href); - } + // Prepare + event = event || {}; + if (typeof event.state === 'undefined') { + // jQuery + if (typeof event.originalEvent !== 'undefined' && typeof event.originalEvent.state !== 'undefined') { + event.state = event.originalEvent.state || false; + } + // MooTools + else if (typeof event.event !== 'undefined' && typeof event.event.state !== 'undefined') { + event.state = event.event.state || false; + } + } - // The State did not exist in our store - if (!newState) { - // Regenerate the State - newState = History.createStateObject(null, null, document.location.href); - } + // Ensure + event.state = (event.state || false); - // Clean - History.expectedStateId = false; + // Fetch State + if (event.state) { + // Vanilla: Back/forward button was used + newState = History.getStateById(event.state); + } + else if (History.expectedStateId) { + // Vanilla: A new state was pushed, and popstate was called manually + newState = History.getStateById(History.expectedStateId); + } + else { + // Initial State + newState = History.extractState(document.location.href); + } - // Check if we are the same state - if (History.isLastSavedState(newState)) { - // There has been no change (just the page's hash has finally propagated) - //History.debug('History.onPopState: no change', newState, History.savedStates); - History.busy(false); - return false; - } + // The State did not exist in our store + if (!newState) { + // Regenerate the State + newState = History.createStateObject(null, null, document.location.href); + } - // Store the State - History.storeState(newState); - History.saveState(newState); + // Clean + History.expectedStateId = false; - // Force update of the title - History.setTitle(newState); + // Check if we are the same state + if (History.isLastSavedState(newState)) { + // There has been no change (just the page's hash has finally propagated) + //History.debug('History.onPopState: no change', newState, History.savedStates); + History.busy(false); + return false; + } - // Fire Our Event - History.Adapter.trigger(window, 'statechange'); - History.busy(false); + // Store the State + History.storeState(newState); + History.saveState(newState); - // Return true - return true; - }; - History.Adapter.bind(window, 'popstate', History.onPopState); + // Force update of the title + History.setTitle(newState); - /** - * History.pushState(data,title,url) - * Add a new State to the history object, become it, and trigger onpopstate - * We have to trigger for HTML4 compatibility - * @param {object} data - * @param {string} title - * @param {string} url - * @return {true} - */ - History.pushState = function(data, title, url, queue) { - //History.debug('History.pushState: called', arguments); + // Fire Our Event + History.Adapter.trigger(window, 'statechange'); + History.busy(false); - // Check the State - if (History.getHashByUrl(url) && History.emulated.pushState) { - throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).'); - } + // Return true + return true; + }; + History.Adapter.bind(window, 'popstate', History.onPopState); - // Handle Queueing - if (queue !== false && History.busy()) { - // Wait + Push to Queue - //History.debug('History.pushState: we must wait', arguments); - History.pushQueue({ - scope: History, - callback: History.pushState, - args: arguments, - queue: queue - }); - return false; - } + /** + * History.pushState(data,title,url) + * Add a new State to the history object, become it, and trigger onpopstate + * We have to trigger for HTML4 compatibility + * @param {object} data + * @param {string} title + * @param {string} url + * @return {true} + */ + History.pushState = function(data, title, url, queue) { + //History.debug('History.pushState: called', arguments); - // Make Busy + Continue - History.busy(true); + // Check the State + if (History.getHashByUrl(url) && History.emulated.pushState) { + throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).'); + } - // Create the newState - var newState = History.createStateObject(data, title, url); + // Handle Queueing + if (queue !== false && History.busy()) { + // Wait + Push to Queue + //History.debug('History.pushState: we must wait', arguments); + History.pushQueue({ + scope: History, + callback: History.pushState, + args: arguments, + queue: queue + }); + return false; + } - // Check it - if (History.isLastSavedState(newState)) { - // Won't be a change - History.busy(false); - } - else { - // Store the newState - History.storeState(newState); - History.expectedStateId = newState.id; + // Make Busy + Continue + History.busy(true); - // Push the newState - history.pushState(newState.id, newState.title, newState.url); + // Create the newState + var newState = History.createStateObject(data, title, url); - // Fire HTML5 Event - History.Adapter.trigger(window, 'popstate'); - } + // Check it + if (History.isLastSavedState(newState)) { + // Won't be a change + History.busy(false); + } + else { + // Store the newState + History.storeState(newState); + History.expectedStateId = newState.id; - // End pushState closure - return true; - }; + // Push the newState + history.pushState(newState.id, newState.title, newState.url); - /** - * History.replaceState(data,title,url) - * Replace the State and trigger onpopstate - * We have to trigger for HTML4 compatibility - * @param {object} data - * @param {string} title - * @param {string} url - * @return {true} - */ - History.replaceState = function(data, title, url, queue) { - //History.debug('History.replaceState: called', arguments); + // Fire HTML5 Event + History.Adapter.trigger(window, 'popstate'); + } - // Check the State - if (History.getHashByUrl(url) && History.emulated.pushState) { - throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).'); - } + // End pushState closure + return true; + }; - // Handle Queueing - if (queue !== false && History.busy()) { - // Wait + Push to Queue - //History.debug('History.replaceState: we must wait', arguments); - History.pushQueue({ - scope: History, - callback: History.replaceState, - args: arguments, - queue: queue - }); - return false; - } + /** + * History.replaceState(data,title,url) + * Replace the State and trigger onpopstate + * We have to trigger for HTML4 compatibility + * @param {object} data + * @param {string} title + * @param {string} url + * @return {true} + */ + History.replaceState = function(data, title, url, queue) { + //History.debug('History.replaceState: called', arguments); - // Make Busy + Continue - History.busy(true); + // Check the State + if (History.getHashByUrl(url) && History.emulated.pushState) { + throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).'); + } - // Create the newState - var newState = History.createStateObject(data, title, url); + // Handle Queueing + if (queue !== false && History.busy()) { + // Wait + Push to Queue + //History.debug('History.replaceState: we must wait', arguments); + History.pushQueue({ + scope: History, + callback: History.replaceState, + args: arguments, + queue: queue + }); + return false; + } - // Check it - if (History.isLastSavedState(newState)) { - // Won't be a change - History.busy(false); - } - else { - // Store the newState - History.storeState(newState); - History.expectedStateId = newState.id; + // Make Busy + Continue + History.busy(true); - // Push the newState - history.replaceState(newState.id, newState.title, newState.url); + // Create the newState + var newState = History.createStateObject(data, title, url); - // Fire HTML5 Event - History.Adapter.trigger(window, 'popstate'); - } + // Check it + if (History.isLastSavedState(newState)) { + // Won't be a change + History.busy(false); + } + else { + // Store the newState + History.storeState(newState); + History.expectedStateId = newState.id; - // End replaceState closure - return true; - }; + // Push the newState + history.replaceState(newState.id, newState.title, newState.url); - // Be aware, the following is only for native pushState implementations - // If you are wanting to include something for all browsers - // Then include it above this if block + // Fire HTML5 Event + History.Adapter.trigger(window, 'popstate'); + } - /** - * Setup Safari Fix - */ - if (History.bugs.safariPoll) { - setInterval(History.safariStatePoll, History.options.safariPollInterval); - } + // End replaceState closure + return true; + }; - /** - * Ensure Cross Browser Compatibility - */ - if (navigator.vendor === 'Apple Computer, Inc.' || (navigator.appCodeName || '') === 'Mozilla') { - /** - * Fix Safari HashChange Issue - */ + // Be aware, the following is only for native pushState implementations + // If you are wanting to include something for all browsers + // Then include it above this if block - // Setup Alias - History.Adapter.bind(window, 'hashchange', function() { - History.Adapter.trigger(window, 'popstate'); - }); + /** + * Setup Safari Fix + */ + if (History.bugs.safariPoll) { + History.intervalList.push(setInterval(History.safariStatePoll, History.options.safariPollInterval)); + } - // Initialise Alias - if (History.getHash()) { - History.Adapter.onDomLoad(function() { - History.Adapter.trigger(window, 'hashchange'); - }); - } - } + /** + * Ensure Cross Browser Compatibility + */ + if (navigator.vendor === 'Apple Computer, Inc.' || (navigator.appCodeName || '') === 'Mozilla') { + /** + * Fix Safari HashChange Issue + */ - } // !History.emulated.pushState + // Setup Alias + History.Adapter.bind(window, 'hashchange', function() { + History.Adapter.trigger(window, 'popstate'); + }); - }; // History.initCore + // Initialise Alias + if (History.getHash()) { + History.Adapter.onDomLoad(function() { + History.Adapter.trigger(window, 'hashchange'); + }); + } + } - // Try and Initialise History - History.init(); + } // !History.emulated.pushState + + }; // History.initCore + + // Try and Initialise History + History.init(); })(window);