From be5d4fd769b65f30456c8dc00250282becc4587c Mon Sep 17 00:00:00 2001 From: Brad Dunbar Date: Sat, 16 Jun 2012 12:45:08 -0400 Subject: [PATCH] Fix #1366 - Root should not be prepended to history.fragment. --- backbone.js | 19 ++++++++++--------- test/router.js | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/backbone.js b/backbone.js index a066a355..fe71caa9 100644 --- a/backbone.js +++ b/backbone.js @@ -959,6 +959,7 @@ this.handlers = []; _.bindAll(this, 'checkUrl'); this.location = options && options.location || root.location; + this.history = options && options.history || root.history; }; // Cached regex for cleaning leading hashes and slashes . @@ -1009,7 +1010,7 @@ this.options = _.extend({}, {root: '/'}, this.options, options); this._wantsHashChange = this.options.hashChange !== false; this._wantsPushState = !!this.options.pushState; - this._hasPushState = !!(this.options.pushState && window.history && window.history.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)); @@ -1047,7 +1048,7 @@ // in a browser where it could be `pushState`-based instead... } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) { this.fragment = this.getHash().replace(routeStripper, ''); - window.history.replaceState({}, document.title, loc.protocol + '//' + loc.host + this.options.root + this.fragment); + this.history.replaceState({}, document.title, loc.protocol + '//' + loc.host + this.options.root + this.fragment); } if (!this.options.silent) { @@ -1107,21 +1108,21 @@ if (!options || options === true) options = {trigger: options}; var frag = (fragment || '').replace(routeStripper, ''); if (this.fragment == frag) return; - var fullFrag = (frag.indexOf(this.options.root) != 0 ? this.options.root : '') + frag; + this.fragment = frag; + var url = (frag.indexOf(this.options.root) != 0 ? this.options.root : '') + frag; // If pushState is available, we use it to set the fragment as a real URL. if (this._hasPushState) { - this.fragment = fullFrag; - window.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, fullFrag); + this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url); // If hash changes haven't been explicitly disabled, update the hash // fragment to store history. } else if (this._wantsHashChange) { - this.fragment = frag; this._updateHash(this.location, frag, options.replace); if (this.iframe && (frag != this.getFragment(this.getHash(this.iframe)))) { - // Opening and closing the iframe tricks IE7 and earlier to push a history entry on hash-tag change. - // When replace is true, we don't want this. + // Opening and closing the iframe tricks IE7 and earlier to push a + // history entry on hash-tag change. When replace is true, we don't + // want this. if(!options.replace) this.iframe.document.open().close(); this._updateHash(this.iframe.location, frag, options.replace); } @@ -1129,7 +1130,7 @@ // If you've told us that you explicitly don't want fallback hashchange- // based history, then `navigate` becomes a page refresh. } else { - return this.location.assign(fullFrag); + return this.location.assign(url); } if (options.trigger) this.loadUrl(fragment); }, diff --git a/test/router.js b/test/router.js index d366243a..0ebd0faf 100644 --- a/test/router.js +++ b/test/router.js @@ -24,6 +24,9 @@ $(document).ready(function() { 'fragment', 'pathname' )); + // In IE, anchor.pathname does not contain a leading slash though + // window.location.pathname does. + if (!/^\//.test(this.pathname)) this.pathname = '/' + this.pathname; }, toString: function() { @@ -281,4 +284,24 @@ $(document).ready(function() { Backbone.history.navigate('/fragment'); }); + test("#1366 - History does not prepend root to fragment.", 2, function() { + Backbone.history.stop(); + location.replace('http://example.com/root/'); + Backbone.history = new Backbone.History({ + location: location, + history: { + pushState: function(state, title, url) { + strictEqual(url, '/root/x'); + } + } + }); + Backbone.history.start({ + root: '/root/', + pushState: true, + hashChange: false + }); + Backbone.history.navigate('x'); + strictEqual(Backbone.history.fragment, 'x'); + }); + });