From 2535769a65b9d7f84b882533d0982ece3d61c50b Mon Sep 17 00:00:00 2001 From: Georgios Kalpakas Date: Sat, 1 Apr 2017 02:21:11 +0300 Subject: [PATCH] feat(aio): allow reloading page from ServiceWorker update notification --- aio/src/app/sw-updates/global.value.ts | 5 +++++ .../sw-update-notifications.service.spec.ts | 22 ++++++++++++++++++- .../sw-update-notifications.service.ts | 18 ++++++++++++--- aio/src/app/sw-updates/sw-updates.module.ts | 3 +++ 4 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 aio/src/app/sw-updates/global.value.ts diff --git a/aio/src/app/sw-updates/global.value.ts b/aio/src/app/sw-updates/global.value.ts new file mode 100644 index 0000000000..58ff6b2562 --- /dev/null +++ b/aio/src/app/sw-updates/global.value.ts @@ -0,0 +1,5 @@ +import { InjectionToken } from '@angular/core'; + + +export const Global = new InjectionToken('global'); +export const globalProvider = { provide: Global, useValue: window }; diff --git a/aio/src/app/sw-updates/sw-update-notifications.service.spec.ts b/aio/src/app/sw-updates/sw-update-notifications.service.spec.ts index 5f1ec50d66..35d2b8178b 100644 --- a/aio/src/app/sw-updates/sw-update-notifications.service.spec.ts +++ b/aio/src/app/sw-updates/sw-update-notifications.service.spec.ts @@ -5,6 +5,7 @@ import { Observable } from 'rxjs/Observable'; import { Subject } from 'rxjs/Subject'; import { MockSwUpdatesService } from 'testing/sw-updates.service'; +import { Global } from './global.value'; import { SwUpdateNotificationsService } from './sw-update-notifications.service'; import { SwUpdatesService } from './sw-updates.service'; @@ -26,6 +27,7 @@ describe('SwUpdateNotificationsService', () => { beforeEach(() => { injector = ReflectiveInjector.resolveAndCreate([ + { provide: Global, useClass: MockGlobal }, { provide: MdSnackBar, useClass: MockMdSnackBar }, { provide: SwUpdatesService, useClass: MockSwUpdatesService }, SwUpdateNotificationsService @@ -87,10 +89,22 @@ describe('SwUpdateNotificationsService', () => { activateUpdate(true); expect(snackBar.$$lastRef.$$message).toContain('Update activated successfully'); - expect(snackBar.$$lastRef.$$action).toBeNull(); + expect(snackBar.$$lastRef.$$action).toBe('Reload'); expect(snackBar.$$lastRef.$$config.duration).toBeUndefined(); })); + it('should reload the page when clicking on `Reload` (after a successful activation)', + fakeAsync(() => { + const global = injector.get(Global); + + activateUpdate(true); + expect(global.location.reload).not.toHaveBeenCalled(); + + snackBar.$$lastRef.$$onActionSubj.next(); + expect(global.location.reload).toHaveBeenCalled(); + }) + ); + it('should report a failed activation', fakeAsync(() => { activateUpdate(false); @@ -158,6 +172,12 @@ describe('SwUpdateNotificationsService', () => { }); // Mocks +class MockGlobal { + location = { + reload: jasmine.createSpy('MockGlobal.reload') + }; +} + class MockMdSnackBarRef { $$afterDismissedSubj = new Subject(); $$onActionSubj = new Subject(); diff --git a/aio/src/app/sw-updates/sw-update-notifications.service.ts b/aio/src/app/sw-updates/sw-update-notifications.service.ts index d321f1f5d3..8ce39ed2e9 100644 --- a/aio/src/app/sw-updates/sw-update-notifications.service.ts +++ b/aio/src/app/sw-updates/sw-update-notifications.service.ts @@ -1,8 +1,9 @@ -import { Injectable } from '@angular/core'; +import { Inject, Injectable } from '@angular/core'; import { MdSnackBar, MdSnackBarConfig, MdSnackBarRef } from '@angular/material'; import { Subject } from 'rxjs/Subject'; import 'rxjs/add/operator/filter'; +import { Global } from './global.value'; import { SwUpdatesService } from './sw-updates.service'; @@ -29,7 +30,9 @@ export class SwUpdateNotificationsService { private snackBars: MdSnackBarRef[] = []; private enabled = false; - constructor(private snackBarService: MdSnackBar, private swUpdates: SwUpdatesService) { + constructor(@Inject(Global) private global: any, + private snackBarService: MdSnackBar, + private swUpdates: SwUpdatesService) { this.onDisable.subscribe(() => this.snackBars.forEach(sb => sb.dismiss())); } @@ -71,7 +74,9 @@ export class SwUpdateNotificationsService { } private onActivateSuccess() { - this.openSnackBar('Update activated successfully! Reload the page to see the latest content.'); + const message = 'Update activated successfully! Reload the page to see the latest content.'; + this.openSnackBar(message, 'Reload') + .onAction().subscribe(() => this.reloadPage()); } private openSnackBar(message: string, action?: string, config?: MdSnackBarConfig): MdSnackBarRef { @@ -82,4 +87,11 @@ export class SwUpdateNotificationsService { return snackBar; } + + private reloadPage() { + const location = this.global && (this.global as Window).location; + if (location && location.reload) { + location.reload(); + } + } } diff --git a/aio/src/app/sw-updates/sw-updates.module.ts b/aio/src/app/sw-updates/sw-updates.module.ts index eea4900b19..71b53ea6e3 100644 --- a/aio/src/app/sw-updates/sw-updates.module.ts +++ b/aio/src/app/sw-updates/sw-updates.module.ts @@ -2,16 +2,19 @@ import { NgModule } from '@angular/core'; import { MdSnackBarModule } from '@angular/material'; import { ServiceWorkerModule } from '@angular/service-worker'; +import { globalProvider } from './global.value'; import { noopNgServiceWorkerProviders } from './noop-ng-service-worker'; import { SwUpdateNotificationsService } from './sw-update-notifications.service'; import { SwUpdatesService } from './sw-updates.service'; + @NgModule({ imports: [ MdSnackBarModule, ServiceWorkerModule ], providers: [ + globalProvider, noopNgServiceWorkerProviders, SwUpdateNotificationsService, SwUpdatesService