/** * Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved. * Available via the MIT license. * see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details. */ /** * This module is based on Backbone's core history support. It abstracts away the low level details of working with browser history and url changes in order to provide a solid foundation for a router. * @module history * @requires system * @requires jquery */ define(['durandal/system', 'jquery'], function (system, $) { // Cached regex for stripping a leading hash/slash and trailing space. var routeStripper = /^[#\/]|\s+$/g; // Cached regex for stripping leading and trailing slashes. var rootStripper = /^\/+|\/+$/g; // Cached regex for detecting MSIE. var isExplorer = /msie [\w.]+/; // Cached regex for removing a trailing slash. var trailingSlash = /\/$/; // Update the hash location, either replacing the current entry, or adding // a new one to the browser history. function updateHash(location, fragment, replace) { if (replace) { var href = location.href.replace(/(javascript:|#).*$/, ''); if (history.history.replaceState) { history.history.replaceState({}, document.title, href + '#' + fragment); // using history.replaceState instead of location.replace to work around chrom bug } else { location.replace(href + '#' + fragment); } } else { // Some browsers require that `hash` contains a leading #. location.hash = '#' + fragment; } }; /** * @class HistoryModule * @static */ var history = { /** * The setTimeout interval used when the browser does not support hash change events. * @property {string} interval * @default 50 */ interval: 50, /** * Indicates whether or not the history module is actively tracking history. * @property {string} active */ active: false }; // Ensure that `History` can be used outside of the browser. if (typeof window !== 'undefined') { history.location = window.location; history.history = window.history; } /** * Gets the true hash value. Cannot use location.hash directly due to a bug in Firefox where location.hash will always be decoded. * @method getHash * @param {string} [window] The optional window instance * @return {string} The hash. */ history.getHash = function(window) { var match = (window || history).location.href.match(/#(.*)$/); return match ? match[1] : ''; }; /** * Get the cross-browser normalized URL fragment, either from the URL, the hash, or the override. * @method getFragment * @param {string} fragment The fragment. * @param {boolean} forcePushState Should we force push state? * @return {string} he fragment. */ history.getFragment = function(fragment, forcePushState) { if (fragment == null) { if (history._hasPushState || !history._wantsHashChange || forcePushState) { fragment = history.location.pathname + history.location.search; var root = history.root.replace(trailingSlash, ''); if (!fragment.indexOf(root)) { fragment = fragment.substr(root.length); } } else { fragment = history.getHash(); } } return fragment.replace(routeStripper, ''); }; /** * Activate the hash change handling, returning `true` if the current URL matches an existing route, and `false` otherwise. * @method activate * @param {HistoryOptions} options. * @return {boolean|undefined} Returns true/false from loading the url unless the silent option was selected. */ history.activate = function(options) { if (history.active) { system.error("History has already been activated."); } history.active = true; // Figure out the initial configuration. Do we need an iframe? // Is pushState desired ... is it available? history.options = system.extend({}, { root: '/' }, history.options, options); history.root = history.options.root; history._wantsHashChange = history.options.hashChange !== false; history._wantsPushState = !!history.options.pushState; history._hasPushState = !!(history.options.pushState && history.history && history.history.pushState); var fragment = history.getFragment(); var docMode = document.documentMode; var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7)); // Normalize root to always include a leading and trailing slash. history.root = ('/' + history.root + '/').replace(rootStripper, '/'); if (oldIE && history._wantsHashChange) { history.iframe = $('