fix(docs-infra): do not break when cookies are disabled in the browser (#33829)
Whenever cookies are disabled in the browser, `window.sessionStorage` is not avaialable to the app (i.e. even trying to access `window.sessionStorage` throws an error). To avoid breaking the app, we use a no-op `Storage` implementation if `window.sessionStorage` is not available. Fixes #33795 PR Close #33829
This commit is contained in:
parent
8555d51bc7
commit
f69c6e204a
|
@ -94,6 +94,22 @@ describe('ScrollService', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not break when cookies are disabled in the browser', () => {
|
||||||
|
// Simulate `window.sessionStorage` being inaccessible, when cookies are disabled.
|
||||||
|
spyOnProperty(window, 'sessionStorage', 'get').and.throwError('The operation is insecure');
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
const platformLoc = platformLocation as PlatformLocation;
|
||||||
|
const service = new ScrollService(document, platformLoc, viewportScrollerStub, location);
|
||||||
|
|
||||||
|
service.updateScrollLocationHref();
|
||||||
|
expect(service.getStoredScrollLocationHref()).toBeNull();
|
||||||
|
|
||||||
|
service.removeStoredScrollInfo();
|
||||||
|
expect(service.getStoredScrollPosition()).toBeNull();
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
describe('#topOffset', () => {
|
describe('#topOffset', () => {
|
||||||
it('should query for the top-bar by CSS selector', () => {
|
it('should query for the top-bar by CSS selector', () => {
|
||||||
expect(document.querySelector).not.toHaveBeenCalled();
|
expect(document.querySelector).not.toHaveBeenCalled();
|
||||||
|
|
|
@ -19,6 +19,7 @@ export class ScrollService implements OnDestroy {
|
||||||
private _topOffset: number | null;
|
private _topOffset: number | null;
|
||||||
private _topOfPageElement: Element;
|
private _topOfPageElement: Element;
|
||||||
private onDestroy = new Subject<void>();
|
private onDestroy = new Subject<void>();
|
||||||
|
private storage: Storage;
|
||||||
|
|
||||||
// The scroll position which has to be restored, after a `popstate` event.
|
// The scroll position which has to be restored, after a `popstate` event.
|
||||||
poppedStateScrollPosition: ScrollPosition | null = null;
|
poppedStateScrollPosition: ScrollPosition | null = null;
|
||||||
|
@ -49,6 +50,21 @@ export class ScrollService implements OnDestroy {
|
||||||
private platformLocation: PlatformLocation,
|
private platformLocation: PlatformLocation,
|
||||||
private viewportScroller: ViewportScroller,
|
private viewportScroller: ViewportScroller,
|
||||||
private location: Location) {
|
private location: Location) {
|
||||||
|
try {
|
||||||
|
this.storage = window.sessionStorage;
|
||||||
|
} catch {
|
||||||
|
// When cookies are disabled in the browser, even trying to access
|
||||||
|
// `window.sessionStorage` throws an error. Use a no-op storage.
|
||||||
|
this.storage = {
|
||||||
|
length: 0,
|
||||||
|
clear: () => undefined,
|
||||||
|
getItem: () => null,
|
||||||
|
key: () => null,
|
||||||
|
removeItem: () => undefined,
|
||||||
|
setItem: () => undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// On resize, the toolbar might change height, so "invalidate" the top offset.
|
// On resize, the toolbar might change height, so "invalidate" the top offset.
|
||||||
fromEvent(window, 'resize')
|
fromEvent(window, 'resize')
|
||||||
.pipe(takeUntil(this.onDestroy))
|
.pipe(takeUntil(this.onDestroy))
|
||||||
|
@ -180,7 +196,7 @@ export class ScrollService implements OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateScrollLocationHref(): void {
|
updateScrollLocationHref(): void {
|
||||||
window.sessionStorage.setItem('scrollLocationHref', window.location.href);
|
this.storage.setItem('scrollLocationHref', window.location.href);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -190,17 +206,17 @@ export class ScrollService implements OnDestroy {
|
||||||
if (this.supportManualScrollRestoration) {
|
if (this.supportManualScrollRestoration) {
|
||||||
const currentScrollPosition = this.viewportScroller.getScrollPosition();
|
const currentScrollPosition = this.viewportScroller.getScrollPosition();
|
||||||
this.location.replaceState(this.location.path(true), undefined, {scrollPosition: currentScrollPosition});
|
this.location.replaceState(this.location.path(true), undefined, {scrollPosition: currentScrollPosition});
|
||||||
window.sessionStorage.setItem('scrollPosition', currentScrollPosition.join(','));
|
this.storage.setItem('scrollPosition', currentScrollPosition.join(','));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getStoredScrollLocationHref(): string | null {
|
getStoredScrollLocationHref(): string | null {
|
||||||
const href = window.sessionStorage.getItem('scrollLocationHref');
|
const href = this.storage.getItem('scrollLocationHref');
|
||||||
return href || null;
|
return href || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getStoredScrollPosition(): ScrollPosition | null {
|
getStoredScrollPosition(): ScrollPosition | null {
|
||||||
const position = window.sessionStorage.getItem('scrollPosition');
|
const position = this.storage.getItem('scrollPosition');
|
||||||
if (!position) { return null; }
|
if (!position) { return null; }
|
||||||
|
|
||||||
const [x, y] = position.split(',');
|
const [x, y] = position.split(',');
|
||||||
|
@ -208,8 +224,8 @@ export class ScrollService implements OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
removeStoredScrollInfo() {
|
removeStoredScrollInfo() {
|
||||||
window.sessionStorage.removeItem('scrollLocationHref');
|
this.storage.removeItem('scrollLocationHref');
|
||||||
window.sessionStorage.removeItem('scrollPosition');
|
this.storage.removeItem('scrollPosition');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue