Permalink
Comparing changes
Open a pull request
- 2 commits
- 2 files changed
- 0 commit comments
- 2 contributors
Commits on Dec 17, 2014
The original fix for which this mock location logic was written fixes a bug in master which also exists in 1.2.x. Cherry-picking the fix to the 1.2.x branch was difficult because the mock location object used ES5 get/set syntax, which is not supported in IE8. This fix changes the implementation to work with IE8 and modern browsers. IE8's defineProperty only works on certain types of objects, such as DOM elements. So the mock location is a div element in this implementation.
Unified
Split
Showing
with
62 additions
and 7 deletions.
- +8 −1 src/ng/browser.js
- +54 −6 test/ng/browserSpecs.js
| @@ -62,6 +62,11 @@ function Browser(window, document, $log, $sniffer) { | ||
| } | ||
| } | ||
|
|
||
| function getHash(url) { | ||
| var index = url.indexOf('#'); | ||
| return index === -1 ? '' : url.substr(index + 1); | ||
| } | ||
|
|
||
| /** | ||
| * @private | ||
| * Note: this method is used only by scenario runner | ||
| @@ -173,8 +178,10 @@ function Browser(window, document, $log, $sniffer) { | ||
| } | ||
| if (replace) { | ||
| location.replace(url); | ||
| } else { | ||
| } else if (!sameBase) { | ||
| location.href = url; | ||
| } else { | ||
| location.hash = getHash(url); | ||
| } | ||
| } | ||
| return self; | ||
| @@ -1,8 +1,18 @@ | ||
| 'use strict'; | ||
|
|
||
| function MockWindow() { | ||
| /* global getHash:true, stripHash:true */ | ||
|
|
||
| var historyEntriesLength; | ||
| var sniffer = {}; | ||
|
|
||
| function MockWindow(options) { | ||
| if (typeof options !== 'object') { | ||
| options = {}; | ||
| } | ||
| var events = {}; | ||
| var timeouts = this.timeouts = []; | ||
| var locationHref = 'http://server/'; | ||
| var mockWindow = this; | ||
|
|
||
| this.setTimeout = function(fn) { | ||
| return timeouts.push(fn) - 1; | ||
| @@ -35,10 +45,37 @@ function MockWindow() { | ||
| }); | ||
| }; | ||
|
|
||
| this.location = { | ||
| href: 'http://server/', | ||
| replace: noop | ||
| //IE8 hack. defineProperty doesn't work with POJS, just with certain DOM elements | ||
| this.location = document.createElement('div'); | ||
| this.location.href = {}; | ||
| this.location.hash = {}; | ||
| this.location.replace = function(url) { | ||
| locationHref = url; | ||
| mockWindow.history.state = null; | ||
| }; | ||
| Object.defineProperty(this.location, 'href', { | ||
| enumerable: false, | ||
| configurable: true, | ||
| set: function(value) { | ||
| locationHref = value; | ||
| mockWindow.history.state = null; | ||
| historyEntriesLength++; | ||
| }, | ||
| get: function() { | ||
| return locationHref; | ||
| } | ||
| }); | ||
|
|
||
| Object.defineProperty(this.location, 'hash', { | ||
| enumerable: false, | ||
| configurable: true, | ||
| set: function(value) { | ||
| locationHref = stripHash(locationHref) + '#' + value; | ||
| }, | ||
| get: function() { | ||
| return getHash(locationHref); | ||
| } | ||
| }); | ||
|
|
||
| this.history = { | ||
| replaceState: noop, | ||
| @@ -89,7 +126,6 @@ describe('browser', function() { | ||
| warn: function() { logs.warn.push(slice.call(arguments)); }, | ||
| info: function() { logs.info.push(slice.call(arguments)); }, | ||
| error: function() { logs.error.push(slice.call(arguments)); }}; | ||
|
|
||
| browser = new Browser(fakeWindow, fakeDocument, fakeLog, sniffer); | ||
| }); | ||
|
|
||
| @@ -451,6 +487,17 @@ describe('browser', function() { | ||
| expect(locationReplace).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it("should retain the # character when the only change is clearing the hash fragment, to prevent page reload", function() { | ||
| sniffer.history = true; | ||
|
|
||
| browser.url('http://server/#123'); | ||
| expect(fakeWindow.location.href).toEqual('http://server/#123'); | ||
|
|
||
| browser.url('http://server/'); | ||
| expect(fakeWindow.location.href).toEqual('http://server/#'); | ||
|
|
||
| }); | ||
|
|
||
| it('should use location.replace when history.replaceState not available', function() { | ||
| sniffer.history = false; | ||
| browser.url('http://new.org', true); | ||
| @@ -462,6 +509,7 @@ describe('browser', function() { | ||
| expect(fakeWindow.location.href).toEqual('http://server/'); | ||
| }); | ||
|
|
||
|
|
||
| it('should use location.replace and not use replaceState when the url only changed in the hash fragment to please IE10/11', function() { | ||
| sniffer.history = true; | ||
| browser.url('http://server/#123', true); | ||
| @@ -473,6 +521,7 @@ describe('browser', function() { | ||
| expect(fakeWindow.location.href).toEqual('http://server/'); | ||
| }); | ||
|
|
||
|
|
||
| it('should return $browser to allow chaining', function() { | ||
| expect(browser.url('http://any.com')).toBe(browser); | ||
| }); | ||
| @@ -835,7 +884,6 @@ describe('browser', function() { | ||
| expect(browser.url()).toBe(newUrl); | ||
| $rootScope.$digest(); | ||
| expect(browser.url()).toBe(newUrl); | ||
| expect(fakeWindow.location.href).toBe(current); | ||
| }); | ||
| }); | ||
|
|
||