// Backbone.History // ---------------- // Handles cross-browser history management, based on URL fragments. If the // browser does not support `onhashchange`, falls back to polling. Backbone.History = function() { this.handlers = []; _.bindAll(this, 'checkUrl'); }; // Cached regex for cleaning hashes. var hashStrip = /^#*/; // Cached regex for detecting MSIE. var isExplorer = /msie [\w.]+/; // Has the history handling already been started? var historyStarted = false; // Set up all inheritable **Backbone.History** properties and methods. _.extend(Backbone.History.prototype, { // The default interval to poll for hash changes, if necessary, is // twenty times a second. interval: 50, // Get the cross-browser normalized URL fragment, either from the URL, // the hash, or the override. getFragment : function(fragment, forcePushState) { if (fragment == null) { if (this._hasPushState || forcePushState) { fragment = window.location.pathname; var search = window.location.search; if (search) fragment += search; } else { fragment = window.location.hash; } } fragment = decodeURIComponent(fragment.replace(hashStrip, '')); if (!fragment.indexOf(this.options.root)) fragment = fragment.substr(this.options.root.length); return fragment; }, // Start the hash change handling, returning `true` if the current URL matches // an existing route, and `false` otherwise. start : function(options) { // Figure out the initial configuration. Do we need an iframe? // Is pushState desired ... is it available? if (historyStarted) throw new Error("Backbone.history has already been started"); this.options = _.extend({}, {root: '/'}, this.options, options); this._wantsPushState = !!this.options.pushState; this._hasPushState = !!(this.options.pushState && window.history && window.history.pushState); var fragment = this.getFragment(); var docMode = document.documentMode; var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7)); if (oldIE) { this.iframe = $('