mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-05-10 07:44:43 +00:00
feat($browser): jQuery style url method, onUrlChange event
This is just basic implementation of $browser.url, $browser.onUrlChange methods:
$browser.url() - returns current location.href
$browser.url('/new') - set url to /new
If supported, history.pushState is used, location.href property otherwise.
$browser.url('/new', true) - replace current url with /new
If supported, history.replaceState is used, location.replace otherwise.
$browser.onUrlChange is only fired when url is changed from the browser:
- user types into address bar
- user clicks on back/forward button
- user clicks on link
It's not fired when url is changed using $browser.url()
Breaks Removed $browser.setUrl(), $browser.getUrl(), use $browser.url()
Breaks Removed $browser.onHashChange(), use $browser.onUrlChange()
This commit is contained in:
parent
fc2f188d4d
commit
988ed451b5
8 changed files with 276 additions and 158 deletions
|
|
@ -4,8 +4,9 @@ var browserSingleton;
|
||||||
|
|
||||||
angularService('$browser', function($log){
|
angularService('$browser', function($log){
|
||||||
if (!browserSingleton) {
|
if (!browserSingleton) {
|
||||||
|
// TODO(vojta): inject $sniffer service when implemented
|
||||||
browserSingleton = new Browser(window, jqLite(window.document), jqLite(window.document.body),
|
browserSingleton = new Browser(window, jqLite(window.document), jqLite(window.document.body),
|
||||||
XHR, $log);
|
XHR, $log, {});
|
||||||
browserSingleton.bind();
|
browserSingleton.bind();
|
||||||
}
|
}
|
||||||
return browserSingleton;
|
return browserSingleton;
|
||||||
|
|
|
||||||
130
src/Browser.js
130
src/Browser.js
|
|
@ -34,15 +34,16 @@ var XHR = window.XMLHttpRequest || function () {
|
||||||
* @param {object} body jQuery wrapped document.body.
|
* @param {object} body jQuery wrapped document.body.
|
||||||
* @param {function()} XHR XMLHttpRequest constructor.
|
* @param {function()} XHR XMLHttpRequest constructor.
|
||||||
* @param {object} $log console.log or an object with the same interface.
|
* @param {object} $log console.log or an object with the same interface.
|
||||||
|
* @param {object} $sniffer $sniffer service
|
||||||
*/
|
*/
|
||||||
function Browser(window, document, body, XHR, $log) {
|
function Browser(window, document, body, XHR, $log, $sniffer) {
|
||||||
var self = this,
|
var self = this,
|
||||||
rawDocument = document[0],
|
rawDocument = document[0],
|
||||||
location = window.location,
|
location = window.location,
|
||||||
|
history = window.history,
|
||||||
setTimeout = window.setTimeout,
|
setTimeout = window.setTimeout,
|
||||||
clearTimeout = window.clearTimeout,
|
clearTimeout = window.clearTimeout,
|
||||||
pendingDeferIds = {},
|
pendingDeferIds = {};
|
||||||
lastLocationUrl;
|
|
||||||
|
|
||||||
self.isMock = false;
|
self.isMock = false;
|
||||||
|
|
||||||
|
|
@ -194,78 +195,103 @@ function Browser(window, document, body, XHR, $log) {
|
||||||
// URL API
|
// URL API
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
var lastBrowserUrl = location.href;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @workInProgress
|
* @workInProgress
|
||||||
* @ngdoc method
|
* @ngdoc method
|
||||||
* @name angular.service.$browser#setUrl
|
* @name angular.service.$browser#url
|
||||||
* @methodOf angular.service.$browser
|
* @methodOf angular.service.$browser
|
||||||
*
|
*
|
||||||
* @param {string} url New url
|
|
||||||
*
|
|
||||||
* @description
|
* @description
|
||||||
* Sets browser's url
|
* GETTER:
|
||||||
|
* Without any argument, this method just returns current value of location.href.
|
||||||
|
*
|
||||||
|
* SETTER:
|
||||||
|
* With at least one argument, this method sets url to new value.
|
||||||
|
* If html5 history api supported, pushState/replaceState is used, otherwise
|
||||||
|
* location.href/location.replace is used.
|
||||||
|
* Returns its own instance to allow chaining
|
||||||
|
*
|
||||||
|
* NOTE: this api is intended for use only by the $location service. Please use the
|
||||||
|
* {@link angular.service.$location $location service} to change url.
|
||||||
|
*
|
||||||
|
* @param {string} url New url (when used as setter)
|
||||||
|
* @param {boolean=} replace Should new url replace current history record ?
|
||||||
*/
|
*/
|
||||||
self.setUrl = function(url) {
|
self.url = function(url, replace) {
|
||||||
|
// setter
|
||||||
var existingURL = lastLocationUrl;
|
if (url) {
|
||||||
if (!existingURL.match(/#/)) existingURL += '#';
|
lastBrowserUrl = url;
|
||||||
if (!url.match(/#/)) url += '#';
|
if ($sniffer.history) {
|
||||||
if (existingURL != url) {
|
if (replace) history.replaceState(null, '', url);
|
||||||
location.href = url;
|
else history.pushState(null, '', url);
|
||||||
|
} else {
|
||||||
|
if (replace) location.replace(url);
|
||||||
|
else location.href = url;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
// getter
|
||||||
|
} else {
|
||||||
|
return location.href;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @workInProgress
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.service.$browser#getUrl
|
|
||||||
* @methodOf angular.service.$browser
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Get current browser's url
|
|
||||||
*
|
|
||||||
* @returns {string} Browser's url
|
|
||||||
*/
|
|
||||||
self.getUrl = function() {
|
|
||||||
return lastLocationUrl = location.href;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var urlChangeListeners = [],
|
||||||
|
urlChangeInit = false;
|
||||||
|
|
||||||
|
function fireUrlChange() {
|
||||||
|
if (lastBrowserUrl == self.url()) return;
|
||||||
|
|
||||||
|
lastBrowserUrl = self.url();
|
||||||
|
forEach(urlChangeListeners, function(listener) {
|
||||||
|
listener(self.url());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @workInProgress
|
* @workInProgress
|
||||||
* @ngdoc method
|
* @ngdoc method
|
||||||
* @name angular.service.$browser#onHashChange
|
* @name angular.service.$browser#onUrlChange
|
||||||
* @methodOf angular.service.$browser
|
* @methodOf angular.service.$browser
|
||||||
|
* @TODO(vojta): refactor to use node's syntax for events
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
* Detects if browser support onhashchange events and register a listener otherwise registers
|
* Register callback function that will be called, when url changes.
|
||||||
* $browser poller. The `listener` will then get called when the hash changes.
|
|
||||||
*
|
*
|
||||||
* The listener gets called with either HashChangeEvent object or simple object that also contains
|
* It's only called when the url is changed by outside of angular:
|
||||||
* `oldURL` and `newURL` properties.
|
* - user types different url into address bar
|
||||||
|
* - user clicks on history (forward/back) button
|
||||||
|
* - user clicks on a link
|
||||||
*
|
*
|
||||||
* Note: this api is intended for use only by the $location service. Please use the
|
* It's not called when url is changed by $browser.url() method
|
||||||
* {@link angular.service.$location $location service} to monitor hash changes in angular apps.
|
|
||||||
*
|
*
|
||||||
* @param {function(event)} listener Listener function to be called when url hash changes.
|
* The listener gets called with new url as parameter.
|
||||||
* @return {function()} Returns the registered listener fn - handy if the fn is anonymous.
|
*
|
||||||
|
* NOTE: this api is intended for use only by the $location service. Please use the
|
||||||
|
* {@link angular.service.$location $location service} to monitor url changes in angular apps.
|
||||||
|
*
|
||||||
|
* @param {function(string)} listener Listener function to be called when url changes.
|
||||||
|
* @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
|
||||||
*/
|
*/
|
||||||
self.onHashChange = function(listener) {
|
self.onUrlChange = function(callback) {
|
||||||
// IE8 comp mode returns true, but doesn't support hashchange event
|
if (!urlChangeInit) {
|
||||||
var dm = window.document.documentMode;
|
// We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
|
||||||
if ('onhashchange' in window && (isUndefined(dm) || dm >= 8)) {
|
// don't fire popstate when user change the address bar and don't fire hashchange when url
|
||||||
jqLite(window).bind('hashchange', listener);
|
// changed by push/replaceState
|
||||||
} else {
|
|
||||||
var lastBrowserUrl = self.getUrl();
|
|
||||||
|
|
||||||
self.addPollFn(function() {
|
// html5 history api - popstate event
|
||||||
if (lastBrowserUrl != self.getUrl()) {
|
if ($sniffer.history) jqLite(window).bind('popstate', fireUrlChange);
|
||||||
listener();
|
// hashchange event
|
||||||
lastBrowserUrl = self.getUrl();
|
if ($sniffer.hashchange) jqLite(window).bind('hashchange', fireUrlChange);
|
||||||
}
|
// polling
|
||||||
});
|
else self.addPollFn(fireUrlChange);
|
||||||
|
|
||||||
|
urlChangeInit = true;
|
||||||
}
|
}
|
||||||
return listener;
|
|
||||||
|
urlChangeListeners.push(callback);
|
||||||
|
return callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
23
src/angular-mocks.js
vendored
23
src/angular-mocks.js
vendored
|
|
@ -89,19 +89,19 @@ function MockBrowser() {
|
||||||
requests = [];
|
requests = [];
|
||||||
|
|
||||||
this.isMock = true;
|
this.isMock = true;
|
||||||
self.url = "http://server";
|
self.$$url = "http://server";
|
||||||
self.lastUrl = self.url; // used by url polling fn
|
self.$$lastUrl = self.$$url; // used by url polling fn
|
||||||
self.pollFns = [];
|
self.pollFns = [];
|
||||||
|
|
||||||
|
|
||||||
// register url polling fn
|
// register url polling fn
|
||||||
|
|
||||||
self.onHashChange = function(listener) {
|
self.onUrlChange = function(listener) {
|
||||||
self.pollFns.push(
|
self.pollFns.push(
|
||||||
function() {
|
function() {
|
||||||
if (self.lastUrl != self.url) {
|
if (self.$$lastUrl != self.$$url) {
|
||||||
self.lastUrl = self.url;
|
self.$$lastUrl = self.$$url;
|
||||||
listener();
|
listener(self.$$url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -326,12 +326,13 @@ MockBrowser.prototype = {
|
||||||
hover: function(onHover) {
|
hover: function(onHover) {
|
||||||
},
|
},
|
||||||
|
|
||||||
getUrl: function(){
|
url: function(url, replace) {
|
||||||
return this.url;
|
if (url) {
|
||||||
},
|
this.$$url = url;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
setUrl: function(url){
|
return this.$$url;
|
||||||
this.url = url;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
cookies: function(name, value) {
|
cookies: function(name, value) {
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,8 @@ angularServiceInject("$location", function($browser) {
|
||||||
var location = {update: update, updateHash: updateHash};
|
var location = {update: update, updateHash: updateHash};
|
||||||
var lastLocation = {}; // last state since last update().
|
var lastLocation = {}; // last state since last update().
|
||||||
|
|
||||||
$browser.onHashChange(bind(this, this.$apply, function() { //register
|
$browser.onUrlChange(bind(this, this.$apply, function() { //register
|
||||||
update($browser.getUrl());
|
update($browser.url());
|
||||||
}))(); //initialize
|
}))(); //initialize
|
||||||
|
|
||||||
this.$watch(sync);
|
this.$watch(sync);
|
||||||
|
|
@ -120,7 +120,7 @@ angularServiceInject("$location", function($browser) {
|
||||||
|
|
||||||
location.href = composeHref(location);
|
location.href = composeHref(location);
|
||||||
}
|
}
|
||||||
$browser.setUrl(location.href);
|
$browser.url(location.href);
|
||||||
copy(location, lastLocation);
|
copy(location, lastLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
describe('browser', function(){
|
describe('browser', function(){
|
||||||
|
|
||||||
var browser, fakeWindow, xhr, logs, scripts, removedScripts, setTimeoutQueue;
|
var browser, fakeWindow, xhr, logs, scripts, removedScripts, setTimeoutQueue, sniffer;
|
||||||
|
|
||||||
function fakeSetTimeout(fn) {
|
function fakeSetTimeout(fn) {
|
||||||
return setTimeoutQueue.push(fn) - 1; //return position in the queue
|
return setTimeoutQueue.push(fn) - 1; //return position in the queue
|
||||||
|
|
@ -26,8 +26,32 @@ describe('browser', function(){
|
||||||
scripts = [];
|
scripts = [];
|
||||||
removedScripts = [];
|
removedScripts = [];
|
||||||
xhr = null;
|
xhr = null;
|
||||||
|
sniffer = {history: true, hashchange: true};
|
||||||
|
|
||||||
|
// mock window, extract ?
|
||||||
fakeWindow = {
|
fakeWindow = {
|
||||||
location: {href:"http://server"},
|
events: {},
|
||||||
|
fire: function(name) {
|
||||||
|
forEach(this.events[name], function(listener) {
|
||||||
|
listener.apply(null, arguments);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addEventListener: function(name, listener) {
|
||||||
|
if (isUndefined(this.events[name])) {
|
||||||
|
this.events[name] = [];
|
||||||
|
}
|
||||||
|
this.events[name].push(listener);
|
||||||
|
},
|
||||||
|
attachEvent: function(name, listener) {
|
||||||
|
if (isUndefined(this.events[name])) {
|
||||||
|
this.events[name] = [];
|
||||||
|
}
|
||||||
|
this.events[name].push(listener);
|
||||||
|
},
|
||||||
|
removeEventListener: noop,
|
||||||
|
detachEvent: noop,
|
||||||
|
location: {href: 'http://server', replace: noop},
|
||||||
|
history: {replaceState: noop, pushState: noop},
|
||||||
setTimeout: fakeSetTimeout,
|
setTimeout: fakeSetTimeout,
|
||||||
clearTimeout: fakeClearTimeout
|
clearTimeout: fakeClearTimeout
|
||||||
};
|
};
|
||||||
|
|
@ -59,7 +83,7 @@ describe('browser', function(){
|
||||||
error: function() { logs.error.push(slice.call(arguments)); }};
|
error: function() { logs.error.push(slice.call(arguments)); }};
|
||||||
|
|
||||||
browser = new Browser(fakeWindow, jqLite(window.document), fakeBody, FakeXhr,
|
browser = new Browser(fakeWindow, jqLite(window.document), fakeBody, FakeXhr,
|
||||||
fakeLog);
|
fakeLog, sniffer);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should contain cookie cruncher', function() {
|
it('should contain cookie cruncher', function() {
|
||||||
|
|
@ -482,96 +506,162 @@ describe('browser', function(){
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('url', function() {
|
||||||
|
var pushState, replaceState, locationReplace;
|
||||||
|
|
||||||
describe('url api', function() {
|
beforeEach(function() {
|
||||||
it('should use $browser poller to detect url changes when onhashchange event is unsupported',
|
pushState = spyOn(fakeWindow.history, 'pushState');
|
||||||
function() {
|
replaceState = spyOn(fakeWindow.history, 'replaceState');
|
||||||
|
locationReplace = spyOn(fakeWindow.location, 'replace');
|
||||||
fakeWindow = {
|
|
||||||
location: {href:"http://server"},
|
|
||||||
document: {},
|
|
||||||
setTimeout: fakeSetTimeout
|
|
||||||
};
|
|
||||||
|
|
||||||
browser = new Browser(fakeWindow, {}, {});
|
|
||||||
browser.startPoller = function() {};
|
|
||||||
|
|
||||||
var events = [];
|
|
||||||
|
|
||||||
browser.onHashChange(function() {
|
|
||||||
events.push('x');
|
|
||||||
});
|
|
||||||
|
|
||||||
fakeWindow.location.href = "http://server/#newHash";
|
|
||||||
expect(events).toEqual([]);
|
|
||||||
fakeSetTimeout.flush();
|
|
||||||
expect(events).toEqual(['x']);
|
|
||||||
|
|
||||||
//don't do anything if url hasn't changed
|
|
||||||
events = [];
|
|
||||||
fakeSetTimeout.flush();
|
|
||||||
expect(events).toEqual([]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return current location.href', function() {
|
||||||
|
fakeWindow.location.href = 'http://test.com';
|
||||||
|
expect(browser.url()).toEqual('http://test.com');
|
||||||
|
|
||||||
it('should use onhashchange events to detect url changes when supported by browser',
|
fakeWindow.location.href = 'https://another.com';
|
||||||
function() {
|
expect(browser.url()).toEqual('https://another.com');
|
||||||
|
|
||||||
var onHashChngListener;
|
|
||||||
|
|
||||||
fakeWindow = {location: {href:"http://server"},
|
|
||||||
addEventListener: function(type, listener) {
|
|
||||||
expect(type).toEqual('hashchange');
|
|
||||||
onHashChngListener = listener;
|
|
||||||
},
|
|
||||||
attachEvent: function(type, listener) {
|
|
||||||
expect(type).toEqual('onhashchange');
|
|
||||||
onHashChngListener = listener;
|
|
||||||
},
|
|
||||||
removeEventListener: angular.noop,
|
|
||||||
detachEvent: angular.noop,
|
|
||||||
document: {}
|
|
||||||
};
|
|
||||||
fakeWindow.onhashchange = true;
|
|
||||||
|
|
||||||
browser = new Browser(fakeWindow, {}, {});
|
|
||||||
|
|
||||||
var events = [],
|
|
||||||
event = {type: "hashchange"};
|
|
||||||
|
|
||||||
browser.onHashChange(function(e) {
|
|
||||||
events.push(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(events).toEqual([]);
|
|
||||||
onHashChngListener(event);
|
|
||||||
|
|
||||||
expect(events.length).toBe(1);
|
|
||||||
expect(events[0].originalEvent || events[0]).toBe(event); // please jQuery and jqLite
|
|
||||||
|
|
||||||
// clean up the jqLite cache so that the global afterEach doesn't complain
|
|
||||||
if (!jQuery) {
|
|
||||||
jqLite(fakeWindow).dealoc();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// asynchronous test
|
it('should use history.pushState when available', function() {
|
||||||
it('should fire onHashChange when location.hash change', function() {
|
sniffer.history = true;
|
||||||
var callback = jasmine.createSpy('onHashChange');
|
browser.url('http://new.org');
|
||||||
browser = new Browser(window, {}, {});
|
|
||||||
browser.onHashChange(callback);
|
|
||||||
|
|
||||||
window.location.hash = 'new-hash';
|
expect(pushState).toHaveBeenCalled();
|
||||||
browser.addPollFn(function() {});
|
expect(pushState.argsForCall[0][2]).toEqual('http://new.org');
|
||||||
|
|
||||||
waitsFor(function() {
|
expect(replaceState).not.toHaveBeenCalled();
|
||||||
return callback.callCount;
|
expect(locationReplace).not.toHaveBeenCalled();
|
||||||
}, 'onHashChange callback to be called', 1000);
|
expect(fakeWindow.location.href).toEqual('http://server');
|
||||||
|
});
|
||||||
|
|
||||||
runs(function() {
|
it('should use history.replaceState when available', function() {
|
||||||
if (!jQuery) jqLite(window).dealoc();
|
sniffer.history = true;
|
||||||
window.location.hash = '';
|
browser.url('http://new.org', true);
|
||||||
});
|
|
||||||
|
expect(replaceState).toHaveBeenCalled();
|
||||||
|
expect(replaceState.argsForCall[0][2]).toEqual('http://new.org');
|
||||||
|
|
||||||
|
expect(pushState).not.toHaveBeenCalled();
|
||||||
|
expect(locationReplace).not.toHaveBeenCalled();
|
||||||
|
expect(fakeWindow.location.href).toEqual('http://server');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set location.href when pushState not available', function() {
|
||||||
|
sniffer.history = false;
|
||||||
|
browser.url('http://new.org');
|
||||||
|
|
||||||
|
expect(fakeWindow.location.href).toEqual('http://new.org');
|
||||||
|
|
||||||
|
expect(pushState).not.toHaveBeenCalled();
|
||||||
|
expect(replaceState).not.toHaveBeenCalled();
|
||||||
|
expect(locationReplace).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use location.replace when history.replaceState not available', function() {
|
||||||
|
sniffer.history = false;
|
||||||
|
browser.url('http://new.org', true);
|
||||||
|
|
||||||
|
expect(locationReplace).toHaveBeenCalledWith('http://new.org');
|
||||||
|
|
||||||
|
expect(pushState).not.toHaveBeenCalled();
|
||||||
|
expect(replaceState).not.toHaveBeenCalled();
|
||||||
|
expect(fakeWindow.location.href).toEqual('http://server');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return $browser to allow chaining', function() {
|
||||||
|
expect(browser.url('http://any.com')).toBe(browser);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('urlChange', function() {
|
||||||
|
var callback;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
callback = jasmine.createSpy('onUrlChange');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
if (!jQuery) jqLite(fakeWindow).dealoc();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return registered callback', function() {
|
||||||
|
expect(browser.onUrlChange(callback)).toBe(callback);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should forward popstate event with new url when history supported', function() {
|
||||||
|
sniffer.history = true;
|
||||||
|
browser.onUrlChange(callback);
|
||||||
|
fakeWindow.location.href = 'http://server/new';
|
||||||
|
|
||||||
|
fakeWindow.fire('popstate');
|
||||||
|
expect(callback).toHaveBeenCalledWith('http://server/new');
|
||||||
|
|
||||||
|
fakeWindow.fire('hashchange');
|
||||||
|
fakeSetTimeout.flush();
|
||||||
|
expect(callback.callCount).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should forward only popstate event when both history and hashchange supported', function() {
|
||||||
|
sniffer.history = true;
|
||||||
|
sniffer.hashchange = true;
|
||||||
|
browser.onUrlChange(callback);
|
||||||
|
fakeWindow.location.href = 'http://server/new';
|
||||||
|
|
||||||
|
fakeWindow.fire('popstate');
|
||||||
|
expect(callback).toHaveBeenCalledWith('http://server/new');
|
||||||
|
|
||||||
|
fakeWindow.fire('hashchange');
|
||||||
|
fakeSetTimeout.flush();
|
||||||
|
expect(callback.callCount).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should forward hashchange event with new url when only hashchange supported', function() {
|
||||||
|
sniffer.history = false;
|
||||||
|
sniffer.hashchange = true;
|
||||||
|
browser.onUrlChange(callback);
|
||||||
|
fakeWindow.location.href = 'http://server/new';
|
||||||
|
|
||||||
|
fakeWindow.fire('hashchange');
|
||||||
|
expect(callback).toHaveBeenCalledWith('http://server/new');
|
||||||
|
|
||||||
|
fakeWindow.fire('popstate');
|
||||||
|
fakeSetTimeout.flush();
|
||||||
|
expect(callback.callCount).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use polling when neither history nor hashchange supported', function() {
|
||||||
|
sniffer.history = false;
|
||||||
|
sniffer.hashchange = false;
|
||||||
|
browser.onUrlChange(callback);
|
||||||
|
|
||||||
|
fakeWindow.location.href = 'http://server.new';
|
||||||
|
fakeSetTimeout.flush();
|
||||||
|
expect(callback).toHaveBeenCalledWith('http://server.new');
|
||||||
|
|
||||||
|
fakeWindow.fire('popstate');
|
||||||
|
fakeWindow.fire('hashchange');
|
||||||
|
expect(callback.callCount).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not fire urlChange if changed by browser.url method (polling)', function() {
|
||||||
|
sniffer.history = false;
|
||||||
|
sniffer.hashchange = false;
|
||||||
|
browser.onUrlChange(callback);
|
||||||
|
browser.url('http://new.com');
|
||||||
|
|
||||||
|
fakeSetTimeout.flush();
|
||||||
|
expect(callback).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not fire urlChange if changed by browser.url method (hashchange)', function() {
|
||||||
|
sniffer.history = false;
|
||||||
|
sniffer.hashchange = true;
|
||||||
|
browser.onUrlChange(callback);
|
||||||
|
browser.url('http://new.com');
|
||||||
|
|
||||||
|
fakeWindow.fire('hashchange');
|
||||||
|
expect(callback).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ describe("ScenarioSpec: Compilation", function(){
|
||||||
var $location = scope.$service('$location');
|
var $location = scope.$service('$location');
|
||||||
var $browser = scope.$service('$browser');
|
var $browser = scope.$service('$browser');
|
||||||
expect($location.hashSearch.book).toBeUndefined();
|
expect($location.hashSearch.book).toBeUndefined();
|
||||||
$browser.setUrl(url);
|
$browser.url(url);
|
||||||
$browser.poll();
|
$browser.poll();
|
||||||
expect($location.hashSearch.book).toEqual('moby');
|
expect($location.hashSearch.book).toEqual('moby');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -32,24 +32,24 @@ describe('$location', function() {
|
||||||
|
|
||||||
it('should update location when browser url changed', function() {
|
it('should update location when browser url changed', function() {
|
||||||
var origUrl = $location.href;
|
var origUrl = $location.href;
|
||||||
expect(origUrl).toEqual($browser.getUrl());
|
expect(origUrl).toEqual($browser.url());
|
||||||
|
|
||||||
var newUrl = 'http://somenew/url#foo';
|
var newUrl = 'http://somenew/url#foo';
|
||||||
$browser.setUrl(newUrl);
|
$browser.url(newUrl);
|
||||||
$browser.poll();
|
$browser.poll();
|
||||||
expect($location.href).toEqual(newUrl);
|
expect($location.href).toEqual(newUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should update browser at the end of $eval', function() {
|
it('should update browser at the end of $eval', function() {
|
||||||
var origBrowserUrl = $browser.getUrl();
|
var origBrowserUrl = $browser.url();
|
||||||
$location.update('http://www.angularjs.org/');
|
$location.update('http://www.angularjs.org/');
|
||||||
$location.update({path: '/a/b'});
|
$location.update({path: '/a/b'});
|
||||||
expect($location.href).toEqual('http://www.angularjs.org/a/b');
|
expect($location.href).toEqual('http://www.angularjs.org/a/b');
|
||||||
expect($browser.getUrl()).toEqual('http://www.angularjs.org/a/b');
|
expect($browser.url()).toEqual('http://www.angularjs.org/a/b');
|
||||||
$location.path = '/c';
|
$location.path = '/c';
|
||||||
scope.$digest();
|
scope.$digest();
|
||||||
expect($browser.getUrl()).toEqual('http://www.angularjs.org/c');
|
expect($browser.url()).toEqual('http://www.angularjs.org/c');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1183,7 +1183,7 @@ describe("widget", function(){
|
||||||
var myApp = angular.scope();
|
var myApp = angular.scope();
|
||||||
var $browser = myApp.$service('$browser');
|
var $browser = myApp.$service('$browser');
|
||||||
$browser.xhr.expectGET('includePartial.html').respond('view: <ng:view></ng:view>');
|
$browser.xhr.expectGET('includePartial.html').respond('view: <ng:view></ng:view>');
|
||||||
$browser.setUrl('http://server/#/foo');
|
$browser.url('http://server/#/foo');
|
||||||
|
|
||||||
var $route = myApp.$service('$route');
|
var $route = myApp.$service('$route');
|
||||||
$route.when('/foo', {controller: angular.noop, template: 'viewPartial.html'});
|
$route.when('/foo', {controller: angular.noop, template: 'viewPartial.html'});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue