Skip to content

Commit 87ace90

Browse files
committed
fix($sniffer): fix history sniffing in Chrome Packaged Apps
Although `window.history` is present in the context of Chrome Packaged Apps, it is not allowed to access `window.history.pushState` or `window.history.state`, resulting in errors when trying to "sniff" history support. This commit fixes it by detecting a Chrome Packaged App (through the presence of `window.chrome.app.runtime`). Note that `window.chrome.app` is present in the context of "normal" webpages as well, but it doesn't have the `runtime` property, which is only available to packaged apps (e.g. see https://developer.chrome.com/apps/api_index). Fixes angular#11932
1 parent 566b31c commit 87ace90

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

src/ng/sniffer.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
function $SnifferProvider() {
1818
this.$get = ['$window', '$document', function($window, $document) {
1919
var eventSupport = {},
20+
isChromePackagedApp = $window.chrome && $window.chrome.app && $window.chrome.app.runtime,
21+
hasHistoryPushState = $window.history && $window.history.pushState,
2022
android =
2123
toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
2224
boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
@@ -57,11 +59,13 @@ function $SnifferProvider() {
5759
// http://code.google.com/p/android/issues/detail?id=17471
5860
// https://github.com/angular/angular.js/issues/904
5961

62+
// Chrome Packaged Apps are not allowed to access `history.pushState`. They can be detected by
63+
// the presence of `chrome.app.runtime` (see https://developer.chrome.com/apps/api_index)
6064
// older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
6165
// so let's not use the history API also
6266
// We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
6367
// jshint -W018
64-
history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
68+
history: !!(!isChromePackagedApp && hasHistoryPushState && !(android < 4) && !boxee),
6569
// jshint +W018
6670
hasEvent: function(event) {
6771
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have

test/ng/snifferSpec.js

+26
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,32 @@ describe('$sniffer', function() {
4343

4444
expect(sniffer(mockWindow).history).toBe(false);
4545
});
46+
47+
48+
it('should be false on Chrome Packaged Apps', function() {
49+
// Chrome Packaged Apps are not allowed to access `window.history.pushState`.
50+
// In Chrome, `window.app` might be available in "normal" webpages, but `window.app.runtime`
51+
// only exists in the context of a packaged app.
52+
53+
expect(sniffer(createMockWindow()).history).toBe(true);
54+
expect(sniffer(createMockWindow(true)).history).toBe(true);
55+
expect(sniffer(createMockWindow(true, true)).history).toBe(false);
56+
57+
function createMockWindow(isChrome, isPackagedApp) {
58+
var mockWindow = {
59+
history: {
60+
pushState: noop
61+
}
62+
};
63+
64+
if (isChrome) {
65+
var chromeAppObj = isPackagedApp ? {runtime: {}} : {};
66+
mockWindow.chrome = {app: chromeAppObj};
67+
}
68+
69+
return mockWindow;
70+
}
71+
});
4672
});
4773

4874

0 commit comments

Comments
 (0)