diff --git a/apps/docs/src/app/pages/docs/angular/core/services/window-service/index.md b/apps/docs/src/app/pages/docs/angular/core/services/window-service/index.md index aedc733c..4e004cb0 100644 --- a/apps/docs/src/app/pages/docs/angular/core/services/window-service/index.md +++ b/apps/docs/src/app/pages/docs/angular/core/services/window-service/index.md @@ -12,12 +12,12 @@ It is convenient for using the document or window without breaking SSR. The window-service exposes a `width$` observable to get the window-width. It defaults to `1200` when no window is defined. ```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; export class YourComponent { public windowWidth$: Observable; - constructor(private windowService: WindowService) { + constructor(private windowService: NgxWindowService) { this.windowWidth$ = this.windowService.width$; } } @@ -28,12 +28,12 @@ export class YourComponent { The window-service exposes a `scrollingUp$` observable to know when the scroll has ended. ```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; export class YourComponent { public scrollingUp$: Observable; - constructor(private windowService: WindowService) { + constructor(private windowService: NgxWindowService) { this.scrollingUp$ = this.windowService.scrollingUp$; } } @@ -44,12 +44,12 @@ export class YourComponent { The window-service exposes a `currentScrollPosition` property that contains the currentScrollPosition after handleContentScroll has been called. ```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; export class YourComponent { public currentScrollPosition: Observable; - constructor(private windowService: WindowService) { + constructor(private windowService: NgxWindowService) { this.currentScrollPosition = this.windowService.currentScrollPosition; } } @@ -60,12 +60,12 @@ export class YourComponent { The window-service exposes the `window` property which is a link to the `Window` object. ```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; export class YourComponent { public window: Observable; - constructor(private windowService: WindowService) { + constructor(private windowService: NgxWindowService) { this.window = this.windowService.window; } } @@ -76,12 +76,12 @@ export class YourComponent { The window-service also exposes the `document` property which is a link to the `Document` object. ```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; export class YourComponent { public window: Observable; - constructor(private windowService: WindowService) { + constructor(private windowService: NgxWindowService) { this.window = this.windowService.window; } } @@ -96,10 +96,10 @@ A `scrollTo` method is provided to scroll to a position on the page. When there The offset is set to `0` by default so triggering the method without a value will scroll to the top of the page. ```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; export class YourComponent { - constructor(private windowService: WindowService) {} + constructor(private windowService: NgxWindowService) {} public somethingHappened(): void { this.windowService.scrollTo(500); @@ -112,10 +112,10 @@ export class YourComponent { The `hasDocument`-method is provided to check if there is a document. ```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; export class YourComponent { - constructor(private windowService: WindowService) {} + constructor(private windowService: NgxWindowService) {} public aCoolMethod(): void { if (this.windowService.hasDocument()) { @@ -132,10 +132,10 @@ The `isBrowser`-method is provided to check if the current platform is a browser It uses the `isPlatformBrowser` method with the `PLATFORM_ID` injection-token internally. ```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; export class YourComponent { - constructor(private windowService: WindowService) {} + constructor(private windowService: NgxWindowService) {} public aCoolMethod(): void { if (this.windowService.isBrowser()) { @@ -152,10 +152,10 @@ The `runInBrowser`-method is provided to run a specific callback only when in th The callback has access to the window and the document elements provided in its parameters. ```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; export class YourComponent { - constructor(private windowService: WindowService) {} + constructor(private windowService: NgxWindowService) {} public aCoolMethod(): void { this.windowService.runInBrowser(({ browserWindow, browserDocument }) => { diff --git a/apps/docs/src/app/pages/docs/angular/utils/pipes/replace-elements/index.md b/apps/docs/src/app/pages/docs/angular/utils/pipes/replace-elements/index.md index 1bcb0bb7..c1aa22bb 100644 --- a/apps/docs/src/app/pages/docs/angular/utils/pipes/replace-elements/index.md +++ b/apps/docs/src/app/pages/docs/angular/utils/pipes/replace-elements/index.md @@ -35,10 +35,10 @@ Then register it as a web component in your `app.component.ts`: export class AppComponent { constructor( // ... - private readonly windowService: WindowService, + private readonly windowService: NgxWindowService, private readonly injector: Injector ) { - // Note that we are using our WindowService (ngx-utils) to avoid SSR issues. + // Note that we are using our WindowService (ngx-core) to avoid SSR issues. if (this.windowService.isBrowser) { const linkComponent = createCustomElement(LinkComponent, { injector: this.injector }); diff --git a/apps/docs/src/app/pages/docs/angular/utils/pipes/with-router-links/index.md b/apps/docs/src/app/pages/docs/angular/utils/pipes/with-router-links/index.md index b831dada..ac2bd8f8 100644 --- a/apps/docs/src/app/pages/docs/angular/utils/pipes/with-router-links/index.md +++ b/apps/docs/src/app/pages/docs/angular/utils/pipes/with-router-links/index.md @@ -35,10 +35,10 @@ Then register it as a web component in your `app.component.ts`: export class AppComponent { constructor( // ... - private readonly windowService: WindowService, + private readonly windowService: NgxWindowService, private readonly injector: Injector ) { - // Note that we are using our WindowService (ngx-utils) to avoid SSR issues. + // Note that we are using our WindowService (ngx-core) to avoid SSR issues. if (this.windowService.isBrowser) { const linkComponent = createCustomElement(LinkComponent, { injector: this.injector }); diff --git a/apps/docs/src/app/pages/docs/angular/utils/services/broadcast-channel/index.md b/apps/docs/src/app/pages/docs/angular/utils/services/broadcast-channel/index.md index 98531d74..f596a57c 100644 --- a/apps/docs/src/app/pages/docs/angular/utils/services/broadcast-channel/index.md +++ b/apps/docs/src/app/pages/docs/angular/utils/services/broadcast-channel/index.md @@ -26,7 +26,7 @@ export class YourComponent { #### Safety -The `initChannel` uses the `isPlatformBrowser` check to ensure it only runs in the browser, taking SSR into account as the BroadcastChannel API is not available in node by default. +The `initChannel` uses the `NgxWindowService` check to ensure it only runs in the browser, taking SSR into account as the BroadcastChannel API is not available in node by default. If the channel already exists, it will return the existing channel to avoid overriding existing channels and listeners. diff --git a/apps/docs/src/app/pages/docs/angular/utils/services/window-service/index.md b/apps/docs/src/app/pages/docs/angular/utils/services/window-service/index.md index f00c5717..0285d36b 100644 --- a/apps/docs/src/app/pages/docs/angular/utils/services/window-service/index.md +++ b/apps/docs/src/app/pages/docs/angular/utils/services/window-service/index.md @@ -4,166 +4,3 @@ keyword: UtilsWindowServicePage > **Warning** > This is deprecated in favor of the `*NgxWindowServicePage` in Core - -This service uses the `DOCUMENT` injection-token to provide several methods to access both document and window and related information. -It is convenient for using the document or window without breaking SSR. - -## Properties - -### width$ - -The window-service exposes a `width$` observable to get the window-width. It defaults to `1200` when no window is defined. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - public windowWidth$: Observable; - - constructor(private windowService: WindowService) { - this.windowWidth$ = this.windowService.width$; - } -} -``` - -### scrollingUp$ - -The window-service exposes a `scrollingUp$` observable to know when the scroll has ended. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - public scrollingUp$: Observable; - - constructor(private windowService: WindowService) { - this.scrollingUp$ = this.windowService.scrollingUp$; - } -} -``` - -### currentScrollPosition - -The window-service exposes a `currentScrollPosition` property that contains the currentScrollPosition after handleContentScroll has been called. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - public currentScrollPosition: Observable; - - constructor(private windowService: WindowService) { - this.currentScrollPosition = this.windowService.currentScrollPosition; - } -} -``` - -### window - -The window-service exposes the `window` property which is a link to the `Window` object. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - public window: Observable; - - constructor(private windowService: WindowService) { - this.window = this.windowService.window; - } -} -``` - -### document - -The window-service also exposes the `document` property which is a link to the `Document` object. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - public window: Observable; - - constructor(private windowService: WindowService) { - this.window = this.windowService.window; - } -} -``` - -## Methods - -### scrollTo - -A `scrollTo` method is provided to scroll to a position on the page. When there is no window, it will do nothing. - -The offset is set to `0` by default so triggering the method without a value will scroll to the top of the page. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - constructor(private windowService: WindowService) {} - - public somethingHappened(): void { - this.windowService.scrollTo(500); - } -} -``` - -### hasDocument - -The `hasDocument`-method is provided to check if there is a document. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - constructor(private windowService: WindowService) {} - - public aCoolMethod(): void { - if (this.windowService.hasDocument()) { - // do something that depends on the document. - } - } -} -``` - -### isBrowser - -The `isBrowser`-method is provided to check if the current platform is a browser. - -It uses the `isPlatformBrowser` method with the `PLATFORM_ID` injection-token internally. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - constructor(private windowService: WindowService) {} - - public aCoolMethod(): void { - if (this.windowService.isBrowser()) { - // do something that depends on the browser. - } - } -} -``` - -### runInBrowser - -The `runInBrowser`-method is provided to run a specific callback only when in the browser. - -The callback has access to the window and the document elements provided in its parameters. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - constructor(private windowService: WindowService) {} - - public aCoolMethod(): void { - this.windowService.runInBrowser(({ browserWindow, browserDocument }) => { - // Do something with the browser window or document - }); - } -} -``` diff --git a/libs/angular/cookies/src/lib/services/cookie/cookie.service.ts b/libs/angular/cookies/src/lib/services/cookie/cookie.service.ts index 2302a82d..4c2e604b 100644 --- a/libs/angular/cookies/src/lib/services/cookie/cookie.service.ts +++ b/libs/angular/cookies/src/lib/services/cookie/cookie.service.ts @@ -1,6 +1,6 @@ -import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; -import { isPlatformBrowser } from '@angular/common'; +import { Injectable } from '@angular/core'; import * as CookieConsent from 'vanilla-cookieconsent'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; import { BehaviorSubject, @@ -81,7 +81,7 @@ export class NgxCookieService { public readonly cookiesChanged$: Observable> = this.cookiesChangedSubject.asObservable(); - constructor(@Inject(PLATFORM_ID) private platformId: string) {} + constructor(private readonly windowsService: NgxWindowService) {} /** * Sets up the CookieConsent. @@ -99,7 +99,7 @@ export class NgxCookieService { configuration?: NgxCookieConfiguration ): void { // Iben: If we're not in the browser, we early exit, so server-side rendering can be enabled - if (!isPlatformBrowser(this.platformId)) { + if (!this.windowsService.isBrowser()) { return; } diff --git a/libs/angular/core/src/lib/services/window/window.service.mock.ts b/libs/angular/core/src/lib/services/window/window.service.mock.ts index 7cc7fa99..3b008113 100644 --- a/libs/angular/core/src/lib/services/window/window.service.mock.ts +++ b/libs/angular/core/src/lib/services/window/window.service.mock.ts @@ -26,11 +26,15 @@ export const NgxWindowMock = (spy: unknown) => ({ * example: * NgxWindowServiceMock(jasmine.createSpy(), 1440); * */ -export const NgxWindowServiceMock = (spy: unknown, width: number = 1200) => ({ - width: new BehaviorSubject(width), - window: NgxWindowMock(spy), - scrollTo: () => null, - hasDocument: () => true, - isBrowser: () => true, - runInBrowser: (callback: () => void) => callback(), -}); +export const NgxWindowServiceMock = (spy: unknown, width: number = 1200) => { + const window = NgxWindowMock(spy) as unknown as Window; + return { + width: new BehaviorSubject(width), + window: NgxWindowMock(spy), + scrollTo: () => null, + hasDocument: () => true, + isBrowser: () => true, + runInBrowser: (callback: (data: { browserWindow: Window }) => void) => + callback({ browserWindow: window }), + }; +}; diff --git a/libs/angular/core/src/lib/services/window/window.service.ts b/libs/angular/core/src/lib/services/window/window.service.ts index 0f14e1eb..f869c0cc 100644 --- a/libs/angular/core/src/lib/services/window/window.service.ts +++ b/libs/angular/core/src/lib/services/window/window.service.ts @@ -111,7 +111,6 @@ export class NgxWindowService { if (this.isBrowser) { return action({ browserWindow: this.window, browserDocument: this.document }); } - console.warn('Browser depended function has not run.'); return undefined; } diff --git a/libs/angular/i18n/src/lib/services/root-i18n/root-i18n.service.ts b/libs/angular/i18n/src/lib/services/root-i18n/root-i18n.service.ts index c3e85993..e2eb184a 100644 --- a/libs/angular/i18n/src/lib/services/root-i18n/root-i18n.service.ts +++ b/libs/angular/i18n/src/lib/services/root-i18n/root-i18n.service.ts @@ -1,7 +1,8 @@ -import { isPlatformBrowser } from '@angular/common'; -import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; +import { Inject, Injectable } from '@angular/core'; import { BehaviorSubject, filter, Observable } from 'rxjs'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; +import { NgxStorageService } from '@ngx/utils'; import { NgxI18nConfiguration } from '../../i18n.types'; import { NgxI18nConfigurationToken } from '../../tokens'; @@ -40,8 +41,9 @@ export class NgxI18nRootService { public languageRouteParam: string; constructor( - @Inject(PLATFORM_ID) private readonly platformId: string, @Inject(NgxI18nConfigurationToken) + private readonly windowsService: NgxWindowService, + private readonly storageService: NgxStorageService, private readonly configuration: NgxI18nConfiguration ) { // Iben: Set the initial values so that we can refer to the services as the source of truth @@ -73,8 +75,8 @@ export class NgxI18nRootService { const newLanguage = this.getNewLanguage(language); // Iben: Save the current language to the localStorage when we're in the browser - if (isPlatformBrowser(this.platformId)) { - localStorage.setItem('ngx-i18n-language', newLanguage); + if (this.windowsService.isBrowser()) { + this.storageService.localStorage.setItem('ngx-i18n-language', newLanguage); } // Iben: Update the subject @@ -95,8 +97,10 @@ export class NgxI18nRootService { // Iben: If the current language does not exist, we check if it exists in the local storage, if not, we use the default config let language = this.defaultLanguage; - if (isPlatformBrowser(this.platformId)) { - language = localStorage.getItem('ngx-i18n-language') || this.defaultLanguage; + if (this.windowsService.isBrowser()) { + language = + this.storageService.localStorage.getItem('ngx-i18n-language') || + this.defaultLanguage; } // Iben: We set the new language diff --git a/libs/angular/inform/src/lib/abstracts/modal/modal.abstract.component.ts b/libs/angular/inform/src/lib/abstracts/modal/modal.abstract.component.ts index 0662de5e..1656685a 100644 --- a/libs/angular/inform/src/lib/abstracts/modal/modal.abstract.component.ts +++ b/libs/angular/inform/src/lib/abstracts/modal/modal.abstract.component.ts @@ -4,13 +4,11 @@ import { ElementRef, EventEmitter, HostListener, - Inject, Input, Output, - PLATFORM_ID, } from '@angular/core'; -import { isPlatformBrowser } from '@angular/common'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; import { NgxModalActionType } from '../../types'; /** @@ -53,13 +51,13 @@ export class NgxModalAbstractComponent = new EventEmitter(); constructor( - @Inject(PLATFORM_ID) private platformId: string, + private readonly windowService: NgxWindowService, private readonly elementRef: ElementRef ) {} public ngAfterViewInit(): void { // Iben: If we are in the browser, check if either of the two accessibility labels are set - if (isPlatformBrowser(this.platformId) && (this.ariaLabelledBy || this.ariaDescribedBy)) { + if (this.windowService.isBrowser() && (this.ariaLabelledBy || this.ariaDescribedBy)) { // Iben: Find the element with the id and the parent const element = document.getElementById(this.ariaLabelledBy || this.ariaDescribedBy); const parent = this.elementRef.nativeElement; diff --git a/libs/angular/layout/src/lib/services/online-service/online.service.ts b/libs/angular/layout/src/lib/services/online-service/online.service.ts index dd0800f4..4ae13949 100644 --- a/libs/angular/layout/src/lib/services/online-service/online.service.ts +++ b/libs/angular/layout/src/lib/services/online-service/online.service.ts @@ -1,6 +1,6 @@ -import { isPlatformBrowser } from '@angular/common'; -import { Inject, Injectable, OnDestroy, PLATFORM_ID } from '@angular/core'; +import { Injectable, OnDestroy } from '@angular/core'; import { Observable, Subject, fromEvent, takeUntil, tap } from 'rxjs'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; /** * A service that provides the currently online status of the application @@ -22,9 +22,9 @@ export class NgxOnlineService implements OnDestroy { */ public readonly online$: Observable = this.onlineSubject.asObservable(); - constructor(@Inject(PLATFORM_ID) platformId: string) { + constructor(private readonly windowService: NgxWindowService) { // Iben: When we're in the browser, listen to the online and offline status of the application - if (isPlatformBrowser(platformId)) { + if (this.windowService.isBrowser()) { // Iben: Handle the on and offline status of the application fromEvent(window, 'online') .pipe( diff --git a/libs/angular/tour/src/lib/operators/use-mock-data-during-tour/use-mock-data-during-tour.operator.spec.ts b/libs/angular/tour/src/lib/operators/use-mock-data-during-tour/use-mock-data-during-tour.operator.spec.ts index 0d56206d..9d35f29a 100644 --- a/libs/angular/tour/src/lib/operators/use-mock-data-during-tour/use-mock-data-during-tour.operator.spec.ts +++ b/libs/angular/tour/src/lib/operators/use-mock-data-during-tour/use-mock-data-during-tour.operator.spec.ts @@ -1,7 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { subscribeSpyTo } from '@hirez_io/observer-spy'; -import { PLATFORM_ID } from '@angular/core'; import { provideNgxTourConfiguration } from '../../providers'; import { MockTourHolderComponent, MockTourStepComponent } from '../../mocks'; @@ -17,7 +16,6 @@ xdescribe('useMockDataDuringTour', () => { imports: [MockTourHolderComponent], providers: [ provideNgxTourConfiguration(MockTourStepComponent), - { provide: PLATFORM_ID, useValue: 'browser' }, ], }); diff --git a/libs/angular/tour/src/lib/services/tour-service/tour-server.spec.ts b/libs/angular/tour/src/lib/services/tour-service/tour-server.spec.ts index f6169066..1ece140f 100644 --- a/libs/angular/tour/src/lib/services/tour-service/tour-server.spec.ts +++ b/libs/angular/tour/src/lib/services/tour-service/tour-server.spec.ts @@ -1,4 +1,5 @@ import { subscribeSpyTo } from '@hirez_io/observer-spy'; +import { NgxWindowService, NgxWindowServiceMock } from '@studiohyperdrive/ngx-core'; import { MockTourStepComponent, OverlayMock } from '../../mocks'; import { NgxTourService } from './tour.service'; @@ -6,10 +7,17 @@ describe('NgxTourService Server', () => { let service: NgxTourService; beforeEach(() => { - service = new NgxTourService(OverlayMock(new MockTourStepComponent(service)), 'server', { - component: MockTourStepComponent, - offset: {}, - }); + const windowServiceMock = NgxWindowServiceMock(undefined); + jest.spyOn(windowServiceMock, 'isBrowser').mockReturnValue(false); + + service = new NgxTourService( + OverlayMock(new MockTourStepComponent(service)), + windowServiceMock as unknown as NgxWindowService, + { + component: MockTourStepComponent, + offset: {}, + } + ); }); it('should not start the tour', (done) => { diff --git a/libs/angular/tour/src/lib/services/tour-service/tour.service.spec.ts b/libs/angular/tour/src/lib/services/tour-service/tour.service.spec.ts index 2f941dfe..4f80d5c1 100644 --- a/libs/angular/tour/src/lib/services/tour-service/tour.service.spec.ts +++ b/libs/angular/tour/src/lib/services/tour-service/tour.service.spec.ts @@ -1,5 +1,6 @@ import { subscribeSpyTo } from '@hirez_io/observer-spy'; +import { NgxWindowService, NgxWindowServiceMock } from '@studiohyperdrive/ngx-core'; import { MockTourStepComponent, OverlayMock } from '../../mocks'; import { NgxTourService } from './tour.service'; @@ -12,10 +13,14 @@ xdescribe('NgxTourService Browser', () => { let service: NgxTourService; beforeEach(() => { - service = new NgxTourService(OverlayMock(new MockTourStepComponent(service)), 'browser', { - component: MockTourStepComponent, - offset: {}, - }); + service = new NgxTourService( + OverlayMock(new MockTourStepComponent(service)), + NgxWindowServiceMock(undefined) as unknown as NgxWindowService, + { + component: MockTourStepComponent, + offset: {}, + } + ); }); afterAll(() => { diff --git a/libs/angular/tour/src/lib/services/tour-service/tour.service.ts b/libs/angular/tour/src/lib/services/tour-service/tour.service.ts index b08945d7..b8d4d854 100644 --- a/libs/angular/tour/src/lib/services/tour-service/tour.service.ts +++ b/libs/angular/tour/src/lib/services/tour-service/tour.service.ts @@ -1,4 +1,4 @@ -import { ComponentRef, Inject, Injectable, OnDestroy, PLATFORM_ID } from '@angular/core'; +import { ComponentRef, Inject, Injectable, OnDestroy } from '@angular/core'; import { BehaviorSubject, Observable, @@ -19,8 +19,8 @@ import { } from 'rxjs'; import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; import { ComponentPortal } from '@angular/cdk/portal'; -import { isPlatformBrowser, isPlatformServer } from '@angular/common'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; import { NgxTourStepComponent } from '../../abstracts'; import { NgxTourItemDirective } from '../../directives'; import { NgxTourStepToken } from '../../tokens'; @@ -185,7 +185,7 @@ export class NgxTourService implements OnDestroy { constructor( private readonly cdkOverlayService: Overlay, - @Inject(PLATFORM_ID) private readonly platformId: string, + private readonly windowService: NgxWindowService, @Inject(NgxTourStepToken) private readonly configuration: NgxTourTokenConfiguration ) { // Iben: We use a subject with concatMap here because we want each event to be handled correctly and the elements record should finish updating before updating it again. @@ -200,7 +200,7 @@ export class NgxTourService implements OnDestroy { .subscribe(); // Iben: Listen to the onresize event of the window - this.runInBrowser(({ browserWindow }) => { + this.windowService.runInBrowser(({ browserWindow }) => { browserWindow.onresize = () => { this.windowResizeSubject.next(); }; @@ -220,7 +220,7 @@ export class NgxTourService implements OnDestroy { startIndex = 0 ): Observable { // Wouter: Early exit if the tour is run on the server, for which this service is not intended - if (isPlatformServer(this.platformId)) { + if (!this.windowService.isBrowser()) { console.warn( 'NgxTourService: The tour service is not intended to be run on the server. The tour will not be started.' ); @@ -228,7 +228,7 @@ export class NgxTourService implements OnDestroy { return of(null); } - this.runInBrowser(({ browserWindow, browserDocument }) => { + this.windowService.runInBrowser(({ browserWindow, browserDocument }) => { // Iben: Save the current scroll position so we can return to it when we close the tour this.startingScrollPosition = browserWindow.scrollY; @@ -278,7 +278,7 @@ export class NgxTourService implements OnDestroy { take(1), switchMap(() => this.runStepFunction(onClose)), tap(() => { - this.runInBrowser(({ browserWindow, browserDocument }) => { + this.windowService.runInBrowser(({ browserWindow, browserDocument }) => { // Iben: Scroll back to the starting position browserWindow.scrollTo({ top: this.startingScrollPosition }); @@ -360,7 +360,7 @@ export class NgxTourService implements OnDestroy { this.handleBodyClass('remove'); // Iben: Get rid of the onresize event - this.runInBrowser(({ browserWindow }) => { + this.windowService.runInBrowser(({ browserWindow }) => { browserWindow.onresize = null; }); } @@ -459,7 +459,7 @@ export class NgxTourService implements OnDestroy { currentStep: NgxTourStep, item?: NgxTourItemDirective ): ComponentRef { - return this.runInBrowser(({ browserDocument, browserWindow }) => { + return this.windowService.runInBrowser(({ browserDocument, browserWindow }) => { // Iben: Update the previous and current step subject this.previousStepSubject.next(this.currentStepSubject.getValue()); this.currentStepSubject.next(currentStep); @@ -623,9 +623,9 @@ export class NgxTourService implements OnDestroy { * Surrounds the provided item with a cutout in the backdrop * * @private - * @param backdrop - The provided backdrop - * @param item - The item we wish to surround - * @param cutoutMargin - The amount of margin we want around the item + * @param event.backdrop - The provided backdrop + * @param event.item - The item we wish to surround + * @param event.cutoutMargin - The amount of margin we want around the item */ private setClipPath(event: NgxTourBackdropClipEvent): void { const { backdrop, item, cutoutMargin } = event; @@ -703,7 +703,7 @@ export class NgxTourService implements OnDestroy { * Sets or removes the body class to indicate the tour is active */ private handleBodyClass(action: 'set' | 'remove'): void { - this.runInBrowser(({ browserDocument }) => { + this.windowService.runInBrowser(({ browserDocument }) => { if (action === 'set') { browserDocument.body.classList.add('ngx-tour-active'); } else { @@ -711,15 +711,4 @@ export class NgxTourService implements OnDestroy { } }); } - - //TODO: Iben: Remove this function in service of the WindowService once it is shared - private runInBrowser( - callback: (data: { browserWindow: Window; browserDocument: Document }) => ReturnType - ): ReturnType { - if (isPlatformBrowser(this.platformId)) { - return callback({ browserWindow: document.defaultView, browserDocument: document }); - } - - return undefined; - } } diff --git a/libs/angular/tour/src/test-setup.ts b/libs/angular/tour/src/test-setup.ts index 2e097520..bc3333bb 100644 --- a/libs/angular/tour/src/test-setup.ts +++ b/libs/angular/tour/src/test-setup.ts @@ -1,7 +1,6 @@ -globalThis.ngJest = { - testEnvironmentOptions: { - errorOnUnknownElements: true, - errorOnUnknownProperties: true, - }, -}; -import 'jest-preset-angular/setup-jest'; +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; + +setupZoneTestEnv({ + errorOnUnknownElements: true, + errorOnUnknownProperties: true, +}); diff --git a/libs/angular/utils/src/lib/pipes/replace-elements/replace-elements.pipe.md b/libs/angular/utils/src/lib/pipes/replace-elements/replace-elements.pipe.md index 63f1d1c7..5dba54a0 100644 --- a/libs/angular/utils/src/lib/pipes/replace-elements/replace-elements.pipe.md +++ b/libs/angular/utils/src/lib/pipes/replace-elements/replace-elements.pipe.md @@ -33,10 +33,10 @@ Then register it as a web component in your `app.component.ts`: export class AppComponent { constructor( // ... - private readonly windowService: WindowService, + private readonly windowService: NgxWindowService, private readonly injector: Injector ) { - // Note that we are using our WindowService (ngx-utils) to avoid SSR issues. + // Note that we are using our NgxWindowService (ngx-core) to avoid SSR issues. if (this.windowService.isBrowser) { const linkComponent = createCustomElement(LinkComponent, { injector: this.injector }); diff --git a/libs/angular/utils/src/lib/pipes/with-router-links/with-router-links.md b/libs/angular/utils/src/lib/pipes/with-router-links/with-router-links.md index aca02723..6e02c607 100644 --- a/libs/angular/utils/src/lib/pipes/with-router-links/with-router-links.md +++ b/libs/angular/utils/src/lib/pipes/with-router-links/with-router-links.md @@ -33,10 +33,10 @@ Then register it as a web component in your `app.component.ts`: export class AppComponent { constructor( // ... - private readonly windowService: WindowService, + private readonly windowService: NgxWindowService, private readonly injector: Injector ) { - // Note that we are using our WindowService (ngx-utils) to avoid SSR issues. + // Note that we are using our NgxWindowService (ngx-core) to avoid SSR issues. if (this.windowService.isBrowser) { const linkComponent = createCustomElement(LinkComponent, { injector: this.injector }); diff --git a/libs/angular/utils/src/lib/services/broadcast-channel/broadcast-channel.md b/libs/angular/utils/src/lib/services/broadcast-channel/broadcast-channel.md index 2850908b..a753a564 100644 --- a/libs/angular/utils/src/lib/services/broadcast-channel/broadcast-channel.md +++ b/libs/angular/utils/src/lib/services/broadcast-channel/broadcast-channel.md @@ -24,7 +24,7 @@ export class YourComponent { #### Safety -The `initChannel` uses the `isPlatformBrowser` check to ensure it only runs in the browser, taking SSR into account as the BroadcastChannel API is not available in node by default. +The `initChannel` uses the `NgxWindowService` check to ensure it only runs in the browser, taking SSR into account as the BroadcastChannel API is not available in node by default. If the channel already exists, it will return the existing channel to avoid overriding existing channels and listeners. diff --git a/libs/angular/utils/src/lib/services/broadcast-channel/broadcast-channel.service.spec.ts b/libs/angular/utils/src/lib/services/broadcast-channel/broadcast-channel.service.spec.ts index 6aa8382a..2d49d137 100644 --- a/libs/angular/utils/src/lib/services/broadcast-channel/broadcast-channel.service.spec.ts +++ b/libs/angular/utils/src/lib/services/broadcast-channel/broadcast-channel.service.spec.ts @@ -1,5 +1,5 @@ import { Subscription } from 'rxjs'; -import { windowServiceMock } from '../window-service/window.service.mock'; +import { NgxWindowServiceMock } from '@studiohyperdrive/ngx-core'; import { NgxBroadcastChannelService } from './broadcast-channel.service'; class MockBroadcastChannel { @@ -45,7 +45,7 @@ describe('NgxBroadcastChannelService', () => { let subscriptions: Subscription[] = []; beforeEach(() => { - service = new NgxBroadcastChannelService(windowServiceMock(undefined) as any); + service = new NgxBroadcastChannelService(NgxWindowServiceMock(undefined) as any); }); afterEach(() => { @@ -223,7 +223,7 @@ describe('NgxBroadcastChannelService', () => { describe('not in browser', () => { let service: NgxBroadcastChannelService; - const windowService = windowServiceMock(undefined); + const windowService = NgxWindowServiceMock(undefined); windowService.runInBrowser = () => { return; }; diff --git a/libs/angular/utils/src/lib/services/broadcast-channel/broadcast-channel.service.ts b/libs/angular/utils/src/lib/services/broadcast-channel/broadcast-channel.service.ts index 2ad57694..b6efad82 100644 --- a/libs/angular/utils/src/lib/services/broadcast-channel/broadcast-channel.service.ts +++ b/libs/angular/utils/src/lib/services/broadcast-channel/broadcast-channel.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { EMPTY, fromEvent, Observable } from 'rxjs'; -import { WindowService } from '../window-service/window.service'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; /** * A service that wraps the BroadCastChannel API and provides an Observable based implementation to the channel messages. @@ -17,7 +17,7 @@ export class NgxBroadcastChannelService { */ private broadcastChannel: Record = {}; - constructor(private readonly windowService: WindowService) {} + constructor(private readonly windowService: NgxWindowService) {} /** * initChannel diff --git a/libs/angular/utils/src/lib/services/index.ts b/libs/angular/utils/src/lib/services/index.ts index 51132887..6e9d5483 100644 --- a/libs/angular/utils/src/lib/services/index.ts +++ b/libs/angular/utils/src/lib/services/index.ts @@ -1,5 +1,4 @@ export { WindowService } from './window-service/window.service'; -export { windowMock, windowServiceMock } from './window-service/window.service.mock'; export { NgxBroadcastChannelService } from './broadcast-channel/broadcast-channel.service'; export { SubscriptionService } from './subscription-service/subscription.service'; diff --git a/libs/angular/utils/src/lib/services/media-query/mediaquery.service.ts b/libs/angular/utils/src/lib/services/media-query/mediaquery.service.ts index 6d374274..99e459ca 100644 --- a/libs/angular/utils/src/lib/services/media-query/mediaquery.service.ts +++ b/libs/angular/utils/src/lib/services/media-query/mediaquery.service.ts @@ -1,6 +1,6 @@ import { Injectable, OnDestroy } from '@angular/core'; import { filter, map, Observable, ReplaySubject } from 'rxjs'; -import { WindowService } from '../window-service/window.service'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; /** * A service that can be used to track media queries and their changes. It exposes a method @@ -34,7 +34,7 @@ export class NgxMediaQueryService implements OnDestroy { */ private readonly queryChangedSubject: ReplaySubject = new ReplaySubject(); - constructor(private readonly windowService: WindowService) {} + constructor(private readonly windowService: NgxWindowService) {} /** * Register a list of media queries that need to be tracked by the service. diff --git a/libs/angular/utils/src/lib/services/storage-service/storage.service.spec.ts b/libs/angular/utils/src/lib/services/storage-service/storage.service.spec.ts index ff322a53..4877f07e 100644 --- a/libs/angular/utils/src/lib/services/storage-service/storage.service.spec.ts +++ b/libs/angular/utils/src/lib/services/storage-service/storage.service.spec.ts @@ -1,12 +1,12 @@ import { subscribeSpyTo } from '@hirez_io/observer-spy'; -import { windowServiceMock } from '../window-service/window.service.mock'; +import { NgxWindowServiceMock } from '@studiohyperdrive/ngx-core'; import { NgxStorageService } from './storage.service'; describe('NgxStorageService', () => { let service: NgxStorageService; beforeEach(() => { - service = new NgxStorageService(windowServiceMock(undefined) as any); + service = new NgxStorageService(NgxWindowServiceMock(undefined) as any); localStorage.clear(); sessionStorage.clear(); }); diff --git a/libs/angular/utils/src/lib/services/storage-service/storage.service.ts b/libs/angular/utils/src/lib/services/storage-service/storage.service.ts index 27ce3efd..ed558b88 100644 --- a/libs/angular/utils/src/lib/services/storage-service/storage.service.ts +++ b/libs/angular/utils/src/lib/services/storage-service/storage.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, NEVER, Observable, Subject } from 'rxjs'; +import { NgxWindowService } from '@studiohyperdrive/ngx-core'; import { NgxStorage, NgxStorageClearEvent, @@ -9,7 +10,6 @@ import { NgxStorageSetEvent, NgxStorageType, } from '../../types'; -import { WindowService } from '../window-service/window.service'; /** * A service that provides a SSR-proof Observable based approach to the session- and localStorage. @@ -35,7 +35,7 @@ export class NgxStorageService { public readonly storageEvents$: Observable = this.storageEventSubject.asObservable(); - constructor(private readonly windowService: WindowService) { + constructor(private readonly windowService: NgxWindowService) { // Iben: Get the initial values of the session and the local storage windowService.runInBrowser(() => { this.setupStorage(sessionStorage, this.sessionStorageRecord); diff --git a/libs/angular/utils/src/lib/services/window-service/window.service.md b/libs/angular/utils/src/lib/services/window-service/window.service.md index fd653b12..2657a0b1 100644 --- a/libs/angular/utils/src/lib/services/window-service/window.service.md +++ b/libs/angular/utils/src/lib/services/window-service/window.service.md @@ -1,164 +1,3 @@ # Window service -This service uses the `DOCUMENT` injection-token to provide several methods to access both document and window and related information. -It is convenient for using the document or window without breaking SSR. - -## Properties - -### width$ - -The window-service exposes a `width$` observable to get the window-width. It defaults to `1200` when no window is defined. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - public windowWidth$: Observable; - - constructor(private windowService: WindowService) { - this.windowWidth$ = this.windowService.width$; - } -} -``` - -### scrollingUp$ - -The window-service exposes a `scrollingUp$` observable to know when the scroll has ended. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - public scrollingUp$: Observable; - - constructor(private windowService: WindowService) { - this.scrollingUp$ = this.windowService.scrollingUp$; - } -} -``` - -### currentScrollPosition - -The window-service exposes a `currentScrollPosition` property that contains the currentScrollPosition after handleContentScroll has been called. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - public currentScrollPosition: Observable; - - constructor(private windowService: WindowService) { - this.currentScrollPosition = this.windowService.currentScrollPosition; - } -} -``` - -### window - -The window-service exposes the `window` property which is a link to the `Window` object. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - public window: Observable; - - constructor(private windowService: WindowService) { - this.window = this.windowService.window; - } -} -``` - -### document - -The window-service also exposes the `document` property which is a link to the `Document` object. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - public window: Observable; - - constructor(private windowService: WindowService) { - this.window = this.windowService.window; - } -} -``` - -## Methods - -### scrollTo - -A `scrollTo` method is provided to scroll to a position on the page. When there is no window, it will do nothing. - -The offset is set to `0` by default so triggering the method without a value will scroll to the top of the page. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - constructor(private windowService: WindowService) {} - - public somethingHappened(): void { - this.windowService.scrollTo(500); - } -} -``` - -### hasDocument - -The `hasDocument`-method is provided to check if there is a document. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - constructor(private windowService: WindowService) {} - - public aCoolMethod(): void { - if (this.windowService.hasDocument()) { - // do something that depends on the document. - } - } -} -``` - -### isBrowser - -The `isBrowser`-method is provided to check if the current platform is a browser. - -It uses the `isPlatformBrowser` method with the `PLATFORM_ID` injection-token internally. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - constructor(private windowService: WindowService) {} - - public aCoolMethod(): void { - if (this.windowService.isBrowser()) { - // do something that depends on the browser. - } - } -} -``` - -### runInBrowser - -The `runInBrowser`-method is provided to run a specific callback only when in the browser. - -The callback has access to the window and the document elements provided in its parameters. - -```typescript -import { WindowService } from '@studiohyperdrive/ngx-utils'; - -export class YourComponent { - constructor(private windowService: WindowService) {} - - public aCoolMethod(): void { - this.windowService.runInBrowser(({ browserWindow, browserDocument }) => { - // Do something with the browser window or document - }); - } -} -``` +> This is deprecated in favor of the `NgxWindowService` in ngx-core diff --git a/libs/angular/utils/src/lib/services/window-service/window.service.mock.ts b/libs/angular/utils/src/lib/services/window-service/window.service.mock.ts deleted file mode 100644 index 0f890a0e..00000000 --- a/libs/angular/utils/src/lib/services/window-service/window.service.mock.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { BehaviorSubject } from 'rxjs'; - -/* - * This windowMock constant return an object with a selected spy. - * The reason why the spy is not provided by default is for this mock - * to work on both Jest and Jasmine based test-suites. - * - * example: - * windowMock(jasmine.createSpy()); - * */ -export const windowMock = (spy: unknown) => ({ - addEventListener: spy, - defaultView: { - scrollTo: () => null, - innerWidth: 720, - addEventListener: spy, - }, -}); - -/* - * Provide a spy for your testing framework because the windowMock requires it. - * - * The reason why the spy is not provided by default is for this mock - * to work on both Jest and Jasmine based test-suites. - * - * example: - * windowServiceMock(jasmine.createSpy(), 1440); - * */ -export const windowServiceMock = (spy: unknown, width: number = 1200) => ({ - width: new BehaviorSubject(width), - window: windowMock(spy), - scrollTo: () => null, - hasDocument: () => true, - isBrowser: () => true, - runInBrowser: (callback: () => void) => callback(), -}); diff --git a/libs/angular/utils/src/lib/services/window-service/window.service.spec.ts b/libs/angular/utils/src/lib/services/window-service/window.service.spec.ts index cc7ea005..d82a043b 100644 --- a/libs/angular/utils/src/lib/services/window-service/window.service.spec.ts +++ b/libs/angular/utils/src/lib/services/window-service/window.service.spec.ts @@ -1,5 +1,5 @@ +import { NgxWindowMock } from '@studiohyperdrive/ngx-core'; import { WindowService } from './window.service'; -import { windowMock } from './window.service.mock'; describe('WindowService', () => { describe('with no document', () => { @@ -32,7 +32,7 @@ describe('WindowService', () => { describe('with a document', () => { let service: WindowService; - const document: any = windowMock(jasmine.createSpy()); + const document: any = NgxWindowMock(jasmine.createSpy()); const platform = 'browser'; beforeEach(() => { @@ -42,7 +42,7 @@ describe('WindowService', () => { describe('construct', () => { it('should set the width$ BehaviorSubject to the value of the window-width', () => { expect((service as any).widthSubject$.getValue()).toBe( - windowMock(jasmine.createSpy()).defaultView.innerWidth + NgxWindowMock(jasmine.createSpy()).defaultView.innerWidth ); }); }); diff --git a/libs/angular/utils/src/lib/services/window-service/window.service.ts b/libs/angular/utils/src/lib/services/window-service/window.service.ts index 5056bb98..f8902af5 100644 --- a/libs/angular/utils/src/lib/services/window-service/window.service.ts +++ b/libs/angular/utils/src/lib/services/window-service/window.service.ts @@ -3,6 +3,9 @@ import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; // @dynamic +/** + * @deprecated: This service has been deprecated in favor of the one in @studiohyperdrive/ngx-core + */ @Injectable({ providedIn: 'root', })