Skip to content

Commit

Permalink
Merge pull request jashkenas#3006 from akre54/history-native-hooks
Browse files Browse the repository at this point in the history
History native calls
  • Loading branch information
jashkenas committed Feb 27, 2014
2 parents d4b5f59 + 16b6f1e commit 1853297
Showing 1 changed file with 30 additions and 12 deletions.
42 changes: 30 additions & 12 deletions backbone.js
Original file line number Diff line number Diff line change
Expand Up @@ -1353,9 +1353,6 @@
// 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 = /\/$/;

Expand Down Expand Up @@ -1410,27 +1407,39 @@
this.options = _.extend({root: '/'}, this.options, options);
this.root = this.options.root;
this._wantsHashChange = this.options.hashChange !== false;
this._hasHashChange = 'onhashchange' in window;
this._wantsPushState = !!this.options.pushState;
this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState);
var fragment = this.getFragment();
var docMode = document.documentMode;
var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));

// Add a cross-platform `addEventListener` shim for older browsers.
var addEventListener = window.addEventListener || function (eventName, listener) {
return attachEvent('on' + eventName, listener);
};

// Normalize root to always include a leading and trailing slash.
this.root = ('/' + this.root + '/').replace(rootStripper, '/');

if (oldIE && this._wantsHashChange) {
var frame = Backbone.$('<iframe src="javascript:0" tabindex="-1">');
this.iframe = frame.hide().appendTo('body')[0].contentWindow;
// Proxy an iframe to handle location events if the browser doesn't
// support the `hashchange` event, HTML5 history, or the user wants
// `hashChange` but not `pushState`.
if (!this._hasHashChange && this._wantsHashChange && (!this._wantsPushState || !this._hasPushState)) {
var iframe = document.createElement('iframe');
iframe.src = 'javascript:0';
iframe.style.display = 'none';
iframe.tabIndex = -1;
var body = document.body;
// Using `appendChild` will throw on IE < 9 if the document is not ready.
this.iframe = body.insertBefore(iframe, body.firstChild).contentWindow;
this.navigate(fragment);
}

// Depending on whether we're using pushState or hashes, and whether
// 'onhashchange' is supported, determine how we check the URL state.
if (this._hasPushState) {
Backbone.$(window).on('popstate', this.checkUrl);
} else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
Backbone.$(window).on('hashchange', this.checkUrl);
addEventListener('popstate', this.checkUrl, false);
} else if (this._wantsHashChange && this._hasHashChange && !this.iframe) {
addEventListener('hashchange', this.checkUrl, false);
} else if (this._wantsHashChange) {
this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
}
Expand Down Expand Up @@ -1467,7 +1476,16 @@
// Disable Backbone.history, perhaps temporarily. Not useful in a real app,
// but possibly useful for unit testing Routers.
stop: function() {
Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
// Add a cross-platform `removeEventListener` shim for older browsers.
var removeEventListener = window.removeEventListener || function (eventName, listener) {
return detachEvent('on' + eventName, listener);
};

if (this._hasPushState) {
removeEventListener('popstate', this.checkUrl, false);
} else if (this._wantsHashChange && this._hasHashChange && !this.iframe) {
removeEventListener('hashchange', this.checkUrl, false);
}
// Some environments will throw when clearing an undefined interval.
if (this._checkUrlInterval) clearInterval(this._checkUrlInterval);
History.started = false;
Expand Down

0 comments on commit 1853297

Please sign in to comment.