;
beforeEach(() => {
- setupComponentTestingModule({declarations: [PhExampleComponent]});
+ setupComponentTestingModule({ declarations: [PhExampleComponent] });
fixture = TestBed.createComponent(PhExampleComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
- it('should be created', () => {
+ it("should be created", () => {
expect(component).toBeTruthy();
});
});
diff --git a/src/example/example-component.ts b/src/example/example-component.ts
index ae53dcf..e71fce4 100644
--- a/src/example/example-component.ts
+++ b/src/example/example-component.ts
@@ -1,8 +1,7 @@
-import {Component} from '@angular/core';
+import { Component } from "@angular/core";
@Component({
- selector: 'ph-example-component',
- template: 'ph-example-component works!
',
+ selector: "ph-example-component",
+ template: "ph-example-component works!
",
})
-export class PhExampleComponent {
-}
+export class PhExampleComponent {}
diff --git a/src/example/example-module.ts b/src/example/example-module.ts
index 29a50c9..968079e 100644
--- a/src/example/example-module.ts
+++ b/src/example/example-module.ts
@@ -1,9 +1,8 @@
-import {NgModule} from '@angular/core';
-import {PhExampleComponent} from './example-component';
+import { NgModule } from "@angular/core";
+import { PhExampleComponent } from "./example-component";
@NgModule({
declarations: [PhExampleComponent],
exports: [PhExampleComponent],
})
-export class PhExampleModule {
-}
+export class PhExampleModule {}
diff --git a/src/example/index.ts b/src/example/index.ts
index 4f46909..79ed473 100644
--- a/src/example/index.ts
+++ b/src/example/index.ts
@@ -1,2 +1,2 @@
-export * from './example-component';
-export * from './example-module';
+export * from "./example-component";
+export * from "./example-module";
diff --git a/src/files-drop-area/files-drop-area.spec.ts b/src/files-drop-area/files-drop-area.spec.ts
index 4d5c9ea..de2be37 100644
--- a/src/files-drop-area/files-drop-area.spec.ts
+++ b/src/files-drop-area/files-drop-area.spec.ts
@@ -1,16 +1,21 @@
-import {Component} from '@angular/core';
-import {ComponentFixture, TestBed} from '@angular/core/testing';
-import {By} from '@angular/platform-browser';
+import { Component } from "@angular/core";
+import { ComponentFixture, TestBed } from "@angular/core/testing";
+import { By } from "@angular/platform-browser";
-import {setupComponentTestingModule} from '../testing/test-lib';
+import { setupComponentTestingModule } from "../testing/test-lib";
-import {FilesDropAreaModule} from './files-drop-area';
+import { FilesDropAreaDirective } from "./files-drop-area";
@Component({
template: `
-
-
+
`,
+ standalone: true,
+ imports: [FilesDropAreaDirective],
})
class MockComponent {
readonly droppedFiles: File[] = [];
@@ -27,69 +32,74 @@ class MockComponent {
}
}
-describe('The FilesDropAreaDirective', () => {
+describe("The FilesDropAreaDirective", () => {
let component: MockComponent;
let fixture: ComponentFixture;
beforeEach(() => {
setupComponentTestingModule({
- declarations: [MockComponent],
- imports: [FilesDropAreaModule],
+ imports: [MockComponent],
});
fixture = TestBed.createComponent(MockComponent);
component = fixture.componentInstance;
});
- it('adds the active class when the user drags files over the host element',
- () => {
- fixture.nativeElement.querySelector('.component')
- .dispatchEvent(new DragEvent('dragover'));
- fixture.detectChanges();
-
- const elementClassList = fixture.debugElement.query(By.css('.component'))
- .nativeElement.classList;
- expect(elementClassList.value).toContain('dragover-active');
- });
-
- it('removes the active class when the user drags over and then out of the ' +
- 'host element',
- () => {
- fixture.nativeElement.querySelector('.component')
- .dispatchEvent(new DragEvent('dragover'));
- fixture.detectChanges();
-
- fixture.nativeElement.querySelector('.component')
- .dispatchEvent(new DragEvent('dragleave'));
- fixture.detectChanges();
-
- const elementClassList = fixture.debugElement.query(By.css('.component'))
- .nativeElement.classList;
- expect(elementClassList.value).not.toContain('dragover-active');
- });
-
- it('removes the active class when the user drops a file', () => {
- fixture.nativeElement.querySelector('.component')
- .dispatchEvent(new DragEvent('dragover'));
+ it("adds the active class when the user drags files over the host element", () => {
+ fixture.nativeElement
+ .querySelector(".component")
+ .dispatchEvent(new DragEvent("dragover"));
fixture.detectChanges();
- const event = new DragEvent('drop', {dataTransfer: new DataTransfer()});
- fixture.nativeElement.querySelector('.component').dispatchEvent(event);
+ const elementClassList = fixture.debugElement.query(By.css(".component"))
+ .nativeElement.classList;
+ expect(elementClassList.value).toContain("dragover-active");
+ });
+
+ it(
+ "removes the active class when the user drags over and then out of the " +
+ "host element",
+ () => {
+ fixture.nativeElement
+ .querySelector(".component")
+ .dispatchEvent(new DragEvent("dragover"));
+ fixture.detectChanges();
+
+ fixture.nativeElement
+ .querySelector(".component")
+ .dispatchEvent(new DragEvent("dragleave"));
+ fixture.detectChanges();
+
+ const elementClassList = fixture.debugElement.query(By.css(".component"))
+ .nativeElement.classList;
+ expect(elementClassList.value).not.toContain("dragover-active");
+ },
+ );
+
+ it("removes the active class when the user drops a file", () => {
+ fixture.nativeElement
+ .querySelector(".component")
+ .dispatchEvent(new DragEvent("dragover"));
+ fixture.detectChanges();
+
+ const event = new DragEvent("drop", { dataTransfer: new DataTransfer() });
+ fixture.nativeElement.querySelector(".component").dispatchEvent(event);
fixture.detectChanges();
- const elementClassList = fixture.debugElement.query(By.css('.component'))
- .nativeElement.classList;
- expect(elementClassList.value).not.toContain('dragover-active');
+ const elementClassList = fixture.debugElement.query(By.css(".component"))
+ .nativeElement.classList;
+ expect(elementClassList.value).not.toContain("dragover-active");
});
- it('emits the files when the user drops on the element', () => {
- const dropSpy = spyOn(component, 'onFilesDropped').and.callThrough();
- const mockFile = new File([''], 'dummy.jpg');
+ it("emits the files when the user drops on the element", () => {
+ const dropSpy = spyOn(component, "onFilesDropped").and.callThrough();
+ const mockFile = new File([""], "dummy.jpg");
const mockdataTransfer = new DataTransfer();
mockdataTransfer.items.add(mockFile);
- fixture.nativeElement.querySelector('.component')
- .dispatchEvent(new DragEvent('drop', {dataTransfer: mockdataTransfer}));
+ fixture.nativeElement
+ .querySelector(".component")
+ .dispatchEvent(new DragEvent("drop", { dataTransfer: mockdataTransfer }));
fixture.detectChanges();
expect(dropSpy).toHaveBeenCalledTimes(1);
diff --git a/src/files-drop-area/files-drop-area.ts b/src/files-drop-area/files-drop-area.ts
index f22c7e5..4346d83 100644
--- a/src/files-drop-area/files-drop-area.ts
+++ b/src/files-drop-area/files-drop-area.ts
@@ -1,49 +1,51 @@
-import {Directive, EventEmitter, HostBinding, HostListener, NgModule, Output} from '@angular/core';
+import {
+ Directive,
+ EventEmitter,
+ HostBinding,
+ HostListener,
+ Output,
+} from "@angular/core";
/**
* Directive to handle the functionality for dragging and dropping one or more
* files onto an element on the page - frequently used for uploading files.
*/
-@Directive({selector: '[filesDropArea]'})
+@Directive({
+ selector: "[filesDropArea]",
+ standalone: true,
+})
export class FilesDropAreaDirective {
/**
* Class activated on the host element while the user is dragging files over
* the top of it.
*/
- @HostBinding('class.dragover-active') isDragoverActive = false;
+ @HostBinding("class.dragover-active") isDragoverActive = false;
/** Emits the file or files dragged and dropped onto the element. */
@Output() readonly filesDrop = new EventEmitter();
- @HostListener('dragover', ['$event'])
+ @HostListener("dragover", ["$event"])
onDragover(event: DragEvent) {
event.preventDefault();
event.stopPropagation();
this.isDragoverActive = true;
}
- @HostListener('dragleave', ['$event'])
+ @HostListener("dragleave", ["$event"])
onDragleave(event: DragEvent) {
event.preventDefault();
event.stopPropagation();
this.isDragoverActive = false;
}
- @HostListener('drop', ['$event'])
+ @HostListener("drop", ["$event"])
onDrop(event: DragEvent) {
event.preventDefault();
event.stopPropagation();
this.isDragoverActive = false;
- const {files} = event.dataTransfer;
+ const { files } = event.dataTransfer;
if (files.length) {
this.filesDrop.emit(files);
}
}
}
-
-@NgModule({
- declarations: [FilesDropAreaDirective],
- exports: [FilesDropAreaDirective],
-})
-export class FilesDropAreaModule {
-}
diff --git a/src/files-drop-area/index.ts b/src/files-drop-area/index.ts
index 0a62f57..69b9376 100644
--- a/src/files-drop-area/index.ts
+++ b/src/files-drop-area/index.ts
@@ -1 +1 @@
-export * from './files-drop-area';
+export * from "./files-drop-area";
diff --git a/src/index.ts b/src/index.ts
index 18eb416..7bb339c 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,7 +1,7 @@
-export * from './clipboard/index';
-export * from './files-drop-area/index';
-export * from './loading/index';
-export * from './safe-pipe/index';
-export * from './scroll/index';
-export * from './share/index';
-export * from './window/index';
+export * from "./clipboard/index";
+export * from "./files-drop-area/index";
+export * from "./loading/index";
+export * from "./safe-pipe/index";
+export * from "./scroll/index";
+export * from "./share/index";
+export * from "./window/index";
diff --git a/src/loading/index.ts b/src/loading/index.ts
index 22652cc..b50fe21 100644
--- a/src/loading/index.ts
+++ b/src/loading/index.ts
@@ -1 +1 @@
-export * from './loading';
+export * from "./loading";
diff --git a/src/loading/loading.spec.ts b/src/loading/loading.spec.ts
index 122f803..1ad46c2 100644
--- a/src/loading/loading.spec.ts
+++ b/src/loading/loading.spec.ts
@@ -1,23 +1,22 @@
-import {Component} from '@angular/core';
-import {TestBed} from '@angular/core/testing';
-import {Router} from '@angular/router';
-import {RouterTestingModule} from '@angular/router/testing';
-import {Observable} from 'rxjs';
-import {scan, shareReplay} from 'rxjs/operators';
+import { Component } from "@angular/core";
+import { TestBed } from "@angular/core/testing";
+import { Router } from "@angular/router";
+import { RouterTestingModule } from "@angular/router/testing";
+import { Observable } from "rxjs";
+import { scan, shareReplay } from "rxjs/operators";
-import {setupComponentTestingModule} from '../testing/test-lib';
+import { setupComponentTestingModule } from "../testing/test-lib";
-import {LoadingService} from './loading';
+import { LoadingService } from "./loading";
-const TEST_ROUTE = 'test-route';
+const TEST_ROUTE = "test-route";
@Component({
- template: '',
+ template: "",
})
-class FakeComponent {
-}
+class FakeComponent {}
-describe('The loading service', () => {
+describe("The loading service", () => {
let loadingService: LoadingService;
let router: Router;
@@ -34,7 +33,7 @@ describe('The loading service', () => {
imports: [
RouterTestingModule.withRoutes([
{
- path: '',
+ path: "",
component: FakeComponent,
},
{
@@ -50,17 +49,18 @@ describe('The loading service', () => {
router = TestBed.inject(Router);
accumulatedLoadingState$ = loadingService.getLoadingState().pipe(
- scan((acc: boolean[], curr: boolean) => [...acc, curr], []),
- shareReplay(1));
+ scan((acc: boolean[], curr: boolean) => [...acc, curr], []),
+ shareReplay(1),
+ );
});
- it('should not initially show the loading spinner', () => {
- loadingService.getLoadingState().subscribe(value => {
+ it("should not initially show the loading spinner", () => {
+ loadingService.getLoadingState().subscribe((value) => {
expect(value).toBe(false);
});
});
- it('emits true on navigation start and false on navigation end', async () => {
+ it("emits true on navigation start and false on navigation end", async () => {
const fixture = TestBed.createComponent(FakeComponent);
// Subscribe to make the observable hot and start collecting values before
// navigating.
@@ -71,24 +71,26 @@ describe('The loading service', () => {
await fixture.whenStable();
expect(router.routerState.snapshot.url).toBe(`/${TEST_ROUTE}`);
- accumulatedLoadingState$.subscribe(result => {
+ accumulatedLoadingState$.subscribe((result) => {
expect(result).toEqual([false, true, false]);
});
});
});
- it('allows a user to force the loading state manually using the ' +
- 'setLoadingState method',
- () => {
- // Subscribe to make the observable hot and start collecting values
- // before manually setting them.
- accumulatedLoadingState$.subscribe();
+ it(
+ "allows a user to force the loading state manually using the " +
+ "setLoadingState method",
+ () => {
+ // Subscribe to make the observable hot and start collecting values
+ // before manually setting them.
+ accumulatedLoadingState$.subscribe();
- loadingService.setLoadingState(true);
- loadingService.setLoadingState(false);
+ loadingService.setLoadingState(true);
+ loadingService.setLoadingState(false);
- accumulatedLoadingState$.subscribe(result => {
- expect(result).toEqual([false, true, false]);
- });
- });
+ accumulatedLoadingState$.subscribe((result) => {
+ expect(result).toEqual([false, true, false]);
+ });
+ },
+ );
});
diff --git a/src/loading/loading.ts b/src/loading/loading.ts
index dfd36b9..49b40ba 100644
--- a/src/loading/loading.ts
+++ b/src/loading/loading.ts
@@ -1,11 +1,28 @@
-import {Injectable} from '@angular/core';
-import {Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router} from '@angular/router';
-import {BehaviorSubject, merge, Observable} from 'rxjs';
-import {distinctUntilChanged, filter, map, shareReplay, startWith} from 'rxjs/operators';
+import { Injectable } from "@angular/core";
+import {
+ Event,
+ NavigationCancel,
+ NavigationEnd,
+ NavigationError,
+ NavigationStart,
+ Router,
+} from "@angular/router";
+import { BehaviorSubject, merge, Observable } from "rxjs";
+import {
+ distinctUntilChanged,
+ filter,
+ map,
+ shareReplay,
+ startWith,
+} from "rxjs/operators";
function isNavigationEvent(event: Event): boolean {
- return event instanceof NavigationEnd || event instanceof NavigationError ||
- event instanceof NavigationStart || event instanceof NavigationCancel;
+ return (
+ event instanceof NavigationEnd ||
+ event instanceof NavigationError ||
+ event instanceof NavigationStart ||
+ event instanceof NavigationCancel
+ );
}
/**
@@ -13,23 +30,31 @@ function isNavigationEvent(event: Event): boolean {
* state.
*/
@Injectable({
- providedIn: 'root',
+ providedIn: "root",
})
export class LoadingService {
+ constructor(private readonly router: Router) {}
+
/**
* An observable stream which emits true while data is loading during router
* navigation and false when navigation is complete.
*/
- private readonly navigationLoadingState$ = this.router.events.pipe(
- filter(event => isNavigationEvent(event)),
- map(event => event instanceof NavigationStart), startWith(false));
+ private readonly navigationLoadingState$ =
+ this.createNavigationLoadingStateObs();
private readonly userDefinedLoadingState = new BehaviorSubject(false);
- private readonly isLoading$ =
- merge(this.navigationLoadingState$, this.userDefinedLoadingState)
- .pipe(distinctUntilChanged(), shareReplay(1));
+ private readonly isLoading$ = merge(
+ this.navigationLoadingState$,
+ this.userDefinedLoadingState,
+ ).pipe(distinctUntilChanged(), shareReplay(1));
- constructor(private readonly router: Router) {}
+ private createNavigationLoadingStateObs(): Observable {
+ return this.router.events.pipe(
+ filter((event) => isNavigationEvent(event)),
+ map((event) => event instanceof NavigationStart),
+ startWith(false),
+ );
+ }
/**
* Returns an observable which emits the latest loading state from both
diff --git a/src/safe-pipe/index.ts b/src/safe-pipe/index.ts
index 74a2142..f29a686 100644
--- a/src/safe-pipe/index.ts
+++ b/src/safe-pipe/index.ts
@@ -1 +1 @@
-export * from './safe-pipe';
+export * from "./safe-pipe";
diff --git a/src/safe-pipe/safe-pipe.spec.ts b/src/safe-pipe/safe-pipe.spec.ts
index 96e333e..c63fcb1 100644
--- a/src/safe-pipe/safe-pipe.spec.ts
+++ b/src/safe-pipe/safe-pipe.spec.ts
@@ -1,7 +1,7 @@
-import {inject, TestBed} from '@angular/core/testing';
-import {DomSanitizer} from '@angular/platform-browser';
+import { inject, TestBed } from "@angular/core/testing";
+import { DomSanitizer } from "@angular/platform-browser";
-import {SafePipe} from './safe-pipe';
+import { SafePipe } from "./safe-pipe";
class DomSanitizerMock {
bypassSecurityTrustHtml(value: string): string {
@@ -25,7 +25,7 @@ class DomSanitizerMock {
}
}
-describe('The SafePipe', () => {
+describe("The SafePipe", () => {
let domSanitizer: DomSanitizer;
let safePipe: SafePipe;
@@ -33,7 +33,7 @@ describe('The SafePipe', () => {
TestBed.configureTestingModule({
providers: [
SafePipe,
- {provide: DomSanitizer, useClass: DomSanitizerMock},
+ { provide: DomSanitizer, useClass: DomSanitizerMock },
],
});
});
@@ -43,46 +43,46 @@ describe('The SafePipe', () => {
safePipe = pipe;
}));
- it('sanitizes HTML correctly', () => {
- spyOn(domSanitizer, 'bypassSecurityTrustHtml').and.callThrough();
- const mockHtml = 'Some mock html
';
- const safeHtml = safePipe.transform(mockHtml, 'html');
+ it("sanitizes HTML correctly", () => {
+ spyOn(domSanitizer, "bypassSecurityTrustHtml").and.callThrough();
+ const mockHtml = "Some mock html
";
+ const safeHtml = safePipe.transform(mockHtml, "html");
expect(domSanitizer.bypassSecurityTrustHtml).toHaveBeenCalled();
expect(safeHtml).toBe(mockHtml);
});
- it('sanitizes styles correctly', () => {
- spyOn(domSanitizer, 'bypassSecurityTrustStyle').and.callThrough();
- const mockStyle = '';
- const safeStyle = safePipe.transform(mockStyle, 'style');
+ it("sanitizes styles correctly", () => {
+ spyOn(domSanitizer, "bypassSecurityTrustStyle").and.callThrough();
+ const mockStyle = "";
+ const safeStyle = safePipe.transform(mockStyle, "style");
expect(domSanitizer.bypassSecurityTrustStyle).toHaveBeenCalled();
expect(safeStyle).toBe(mockStyle);
});
- it('sanitizes scripts correctly', () => {
- spyOn(domSanitizer, 'bypassSecurityTrustScript').and.callThrough();
+ it("sanitizes scripts correctly", () => {
+ spyOn(domSanitizer, "bypassSecurityTrustScript").and.callThrough();
const mockScript = ``;
- const safeScript = safePipe.transform(mockScript, 'script');
+ const safeScript = safePipe.transform(mockScript, "script");
expect(domSanitizer.bypassSecurityTrustScript).toHaveBeenCalled();
expect(safeScript).toBe(mockScript);
});
- it('sanitizes URLs correctly', () => {
- spyOn(domSanitizer, 'bypassSecurityTrustUrl').and.callThrough();
- const mockUrl = 'https://www.example.com';
- const safeUrl = safePipe.transform(mockUrl, 'url');
+ it("sanitizes URLs correctly", () => {
+ spyOn(domSanitizer, "bypassSecurityTrustUrl").and.callThrough();
+ const mockUrl = "https://www.example.com";
+ const safeUrl = safePipe.transform(mockUrl, "url");
expect(domSanitizer.bypassSecurityTrustUrl).toHaveBeenCalled();
expect(safeUrl).toBe(mockUrl);
});
- it('sanitizes resource URLs correctly', () => {
- spyOn(domSanitizer, 'bypassSecurityTrustResourceUrl').and.callThrough();
- const mockResourceUrl = 'https://www.example.com';
- const safeResourceUrl = safePipe.transform(mockResourceUrl, 'resourceUrl');
+ it("sanitizes resource URLs correctly", () => {
+ spyOn(domSanitizer, "bypassSecurityTrustResourceUrl").and.callThrough();
+ const mockResourceUrl = "https://www.example.com";
+ const safeResourceUrl = safePipe.transform(mockResourceUrl, "resourceUrl");
expect(domSanitizer.bypassSecurityTrustResourceUrl).toHaveBeenCalled();
expect(safeResourceUrl).toBe(mockResourceUrl);
diff --git a/src/safe-pipe/safe-pipe.ts b/src/safe-pipe/safe-pipe.ts
index 7ed1b60..159d63c 100644
--- a/src/safe-pipe/safe-pipe.ts
+++ b/src/safe-pipe/safe-pipe.ts
@@ -1,28 +1,35 @@
-import {NgModule, Pipe, PipeTransform} from '@angular/core';
-import {DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl} from '@angular/platform-browser';
+import { Pipe, PipeTransform } from "@angular/core";
+import {
+ DomSanitizer,
+ SafeHtml,
+ SafeResourceUrl,
+ SafeScript,
+ SafeStyle,
+ SafeUrl,
+} from "@angular/platform-browser";
-type SafeType = SafeHtml|SafeStyle|SafeScript|SafeUrl|SafeResourceUrl;
-type ContentType = 'html'|'style'|'script'|'url'|'resourceUrl';
+type SafeType = SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl;
+type ContentType = "html" | "style" | "script" | "url" | "resourceUrl";
/**
* Safe pipe which acts as a convenience wapper around the various methods of
* Angular's DomSanitizer
*/
-@Pipe({name: 'safe'})
+@Pipe({ name: "safe", standalone: true })
export class SafePipe implements PipeTransform {
constructor(private readonly sanitizer: DomSanitizer) {}
transform(value: string, type: ContentType): SafeType {
switch (type) {
- case 'html':
+ case "html":
return this.sanitizer.bypassSecurityTrustHtml(value);
- case 'style':
+ case "style":
return this.sanitizer.bypassSecurityTrustStyle(value);
- case 'script':
+ case "script":
return this.sanitizer.bypassSecurityTrustScript(value);
- case 'url':
+ case "url":
return this.sanitizer.bypassSecurityTrustUrl(value);
- case 'resourceUrl':
+ case "resourceUrl":
return this.sanitizer.bypassSecurityTrustResourceUrl(value);
default:
throw new Error(`SafePipe unable to bypass security for invalid type:
@@ -31,10 +38,3 @@ export class SafePipe implements PipeTransform {
}
}
}
-
-@NgModule({
- declarations: [SafePipe],
- exports: [SafePipe],
-})
-export class SafePipeModule {
-}
diff --git a/src/scroll/index.ts b/src/scroll/index.ts
index 56057e0..e953a9a 100644
--- a/src/scroll/index.ts
+++ b/src/scroll/index.ts
@@ -1 +1 @@
-export * from './scroll';
+export * from "./scroll";
diff --git a/src/scroll/scroll.spec.ts b/src/scroll/scroll.spec.ts
deleted file mode 100644
index 0571134..0000000
--- a/src/scroll/scroll.spec.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-import {Component, OnDestroy} from '@angular/core';
-import {ComponentFixture, TestBed} from '@angular/core/testing';
-import {WindowModule} from '@phntms/angular-lib/window';
-import {ReplaySubject} from 'rxjs';
-import {takeUntil} from 'rxjs/operators';
-
-import {setupComponentTestingModule} from '../testing/test-lib';
-
-import {ScrollDirection, ScrollService} from './scroll';
-
-const DEFAULT_SCROLL_DISTANCE = 200;
-
-@Component({
- selector: 'ph-scroll-service-test',
- template: `
-
-
- `,
- styles: [`
- div {
- height: 10000px;
- }
- `],
-})
-class ScrollServiceTestComponent implements OnDestroy {
- private readonly destroy = new ReplaySubject(1);
-
- readonly scrollDirection$ = this.scrollService.getScrollDirection()
- .pipe(takeUntil(this.destroy))
- .subscribe(direction => {
- this.currentScrollDirection = direction;
- });
- readonly scrollPosition$ = this.scrollService.getScrollPosition()
- .pipe(takeUntil(this.destroy))
- .subscribe(position => {
- this.currentScrollPosition = position;
- });
-
- currentScrollPosition?: number;
- currentScrollDirection?: ScrollDirection;
-
-
- constructor(private readonly scrollService: ScrollService) {}
-
- ngOnDestroy() {
- this.destroy.next();
- }
-}
-
-function mockScrollEvent(scrollDepth = DEFAULT_SCROLL_DISTANCE) {
- const scrollEvent = document.createEvent('CustomEvent');
- scrollEvent.initCustomEvent('scroll', false, false, null);
-
- window.scrollTo(0, scrollDepth);
- window.dispatchEvent(scrollEvent);
-}
-
-describe('The scroll service', () => {
- let component: ScrollServiceTestComponent;
- let fixture: ComponentFixture;
-
- beforeEach(() => {
- setupComponentTestingModule({
- declarations: [
- ScrollServiceTestComponent,
- ],
- imports: [WindowModule],
- });
- });
-
- afterEach(() => {
- component.ngOnDestroy();
- });
-
- it('starts with the current scroll position', () => {
- fixture = TestBed.createComponent(ScrollServiceTestComponent);
- component = fixture.componentInstance;
- expect(component.currentScrollPosition).toBe(0);
- });
-
- it('gets the current scroll position', () => {
- fixture = TestBed.createComponent(ScrollServiceTestComponent);
- component = fixture.componentInstance;
- mockScrollEvent();
-
- expect(component.currentScrollPosition).toBe(DEFAULT_SCROLL_DISTANCE);
- });
-
- it('gets the current scroll direction when the user has scrolled down',
- () => {
- fixture = TestBed.createComponent(ScrollServiceTestComponent);
- component = fixture.componentInstance;
- mockScrollEvent();
-
- expect(component.currentScrollDirection).toBe(ScrollDirection.DOWN);
- });
-
- it('gets the current scroll direction when the user has scrolled up', () => {
- spyOn(window, 'pageYOffset').and.returnValue(DEFAULT_SCROLL_DISTANCE + 100);
- fixture = TestBed.createComponent(ScrollServiceTestComponent);
- component = fixture.componentInstance;
- mockScrollEvent();
-
- expect(component.currentScrollDirection).toBe(ScrollDirection.UP);
- });
-});
diff --git a/src/scroll/scroll.ts b/src/scroll/scroll.ts
index c43e4c3..3f19a78 100644
--- a/src/scroll/scroll.ts
+++ b/src/scroll/scroll.ts
@@ -1,7 +1,14 @@
-import {Inject, Injectable} from '@angular/core';
-import {animationFrameScheduler, fromEvent, Observable} from 'rxjs';
-import {distinctUntilChanged, map, pairwise, shareReplay, startWith, throttleTime} from 'rxjs/operators';
-import {WINDOW} from '@phntms/angular-lib/window';
+import { Inject, Injectable } from "@angular/core";
+import { animationFrameScheduler, fromEvent, Observable } from "rxjs";
+import {
+ distinctUntilChanged,
+ map,
+ pairwise,
+ shareReplay,
+ startWith,
+ throttleTime,
+} from "rxjs/operators";
+import { WINDOW } from "../window";
export enum ScrollDirection {
DOWN,
@@ -12,7 +19,7 @@ export enum ScrollDirection {
* A service providing helper methods for interacting with scroll events.
* @dynamic
*/
-@Injectable({providedIn: 'root'})
+@Injectable({ providedIn: "root" })
export class ScrollService {
private readonly scrollPosition$ = this.createPositionObservable();
private readonly scrollDirection$ = this.createDirectionObservable();
@@ -25,13 +32,14 @@ export class ScrollService {
private createDirectionObservable(): Observable {
return this.scrollPosition$.pipe(
- pairwise(),
- map(([previousPosition, currentPosition]) => {
- return previousPosition < currentPosition ? ScrollDirection.DOWN :
- ScrollDirection.UP;
- }),
- distinctUntilChanged(),
- shareReplay(1),
+ pairwise(),
+ map(([previousPosition, currentPosition]) => {
+ return previousPosition < currentPosition
+ ? ScrollDirection.DOWN
+ : ScrollDirection.UP;
+ }),
+ distinctUntilChanged(),
+ shareReplay(1),
);
}
@@ -40,14 +48,15 @@ export class ScrollService {
}
private createPositionObservable(): Observable {
- return fromEvent(this.window, 'scroll')
- .pipe(
- throttleTime(0, animationFrameScheduler),
- startWith(this.getCurrentScrollPosition()),
- map(() => this.getCurrentScrollPosition()), shareReplay(1));
+ return fromEvent(this.window, "scroll").pipe(
+ throttleTime(0, animationFrameScheduler),
+ startWith(this.getCurrentScrollPosition()),
+ map(() => this.getCurrentScrollPosition()),
+ shareReplay(1),
+ );
}
private getCurrentScrollPosition(): number {
- return window.pageYOffset;
+ return this.window.scrollY;
}
}
diff --git a/src/share/add_to_calendar.spec.ts b/src/share/add_to_calendar.spec.ts
index ce4f5ce..82362a2 100644
--- a/src/share/add_to_calendar.spec.ts
+++ b/src/share/add_to_calendar.spec.ts
@@ -1,16 +1,21 @@
-import {BASE_URL_ADD_TO_CALENDAR_URL, GoogleCalendarEventOptions, GoogleCalendarEvent, USER_TIME_ZONE} from './add_to_calendar';
+import {
+ BASE_URL_ADD_TO_CALENDAR_URL,
+ GoogleCalendarEventOptions,
+ GoogleCalendarEvent,
+ USER_TIME_ZONE,
+} from "./add_to_calendar";
const MOCK_START_DATE = new Date(2019, 4, 5, 11, 30);
const MOCK_END_DATE = new Date(2019, 4, 6, 11, 30);
-const MOCK_CONVERTED_START_DATE = '20190505T113000';
-const MOCK_CONVERTED_END_DATE = '20190506T113000';
-const MOCK_LOCATION = 'London';
-const MOCK_TITLE = 'Some event name';
-const MOCK_DETAILS = 'Some event details';
-const MOCK_TIMEZONE = 'America/New_York';
-
-describe('The GoogleCalendarEvent class', () => {
- it('returns a link without any event details or location', () => {
+const MOCK_CONVERTED_START_DATE = "20190505T113000";
+const MOCK_CONVERTED_END_DATE = "20190506T113000";
+const MOCK_LOCATION = "London";
+const MOCK_TITLE = "Some event name";
+const MOCK_DETAILS = "Some event details";
+const MOCK_TIMEZONE = "America/New_York";
+
+describe("The GoogleCalendarEvent class", () => {
+ it("returns a link without any event details or location", () => {
const MOCK_OPTIONS: GoogleCalendarEventOptions = {
endDate: MOCK_END_DATE,
startDate: MOCK_START_DATE,
@@ -20,13 +25,15 @@ describe('The GoogleCalendarEvent class', () => {
const calendarEvent = new GoogleCalendarEvent(MOCK_OPTIONS);
const expectedLink = encodeURI(
- `${BASE_URL_ADD_TO_CALENDAR_URL}&dates=${MOCK_CONVERTED_START_DATE}Z/${
- MOCK_CONVERTED_END_DATE}Z&text=${MOCK_TITLE}`);
+ `${BASE_URL_ADD_TO_CALENDAR_URL}&dates=${MOCK_CONVERTED_START_DATE}Z/${
+ MOCK_CONVERTED_END_DATE
+ }Z&text=${MOCK_TITLE}`,
+ );
expect(calendarEvent.getEventLink()).toBe(expectedLink);
});
- it('returns a link with event details and location', () => {
+ it("returns a link with event details and location", () => {
const MOCK_OPTIONS: GoogleCalendarEventOptions = {
details: MOCK_DETAILS,
endDate: MOCK_END_DATE,
@@ -36,14 +43,18 @@ describe('The GoogleCalendarEvent class', () => {
};
const calendarEvent = new GoogleCalendarEvent(MOCK_OPTIONS);
- const expectedLink = encodeURI(`${BASE_URL_ADD_TO_CALENDAR_URL}&dates=${
- MOCK_CONVERTED_START_DATE}Z/${MOCK_CONVERTED_END_DATE}Z&text=${
- MOCK_TITLE}&details=${MOCK_DETAILS}&location=${MOCK_LOCATION}`);
+ const expectedLink = encodeURI(
+ `${BASE_URL_ADD_TO_CALENDAR_URL}&dates=${
+ MOCK_CONVERTED_START_DATE
+ }Z/${MOCK_CONVERTED_END_DATE}Z&text=${
+ MOCK_TITLE
+ }&details=${MOCK_DETAILS}&location=${MOCK_LOCATION}`,
+ );
expect(calendarEvent.getEventLink()).toBe(expectedLink);
});
- it('returns a link for an all day event correctly', () => {
+ it("returns a link for an all day event correctly", () => {
const MOCK_OPTIONS: GoogleCalendarEventOptions = {
endDate: new Date(2019, 4, 7),
isAllDayEvent: true,
@@ -53,30 +64,36 @@ describe('The GoogleCalendarEvent class', () => {
const calendarEvent = new GoogleCalendarEvent(MOCK_OPTIONS);
const expectedLink = encodeURI(
- `${BASE_URL_ADD_TO_CALENDAR_URL}&dates=20190506/20190507&text=${
- MOCK_TITLE}`);
+ `${BASE_URL_ADD_TO_CALENDAR_URL}&dates=20190506/20190507&text=${
+ MOCK_TITLE
+ }`,
+ );
expect(calendarEvent.getEventLink()).toBe(expectedLink);
});
- it('returns a link for an event where the timezone is set to the users ' +
- 'default',
- () => {
- const MOCK_OPTIONS: GoogleCalendarEventOptions = {
- endDate: MOCK_END_DATE,
- startDate: MOCK_START_DATE,
- title: MOCK_TITLE,
- timeZone: USER_TIME_ZONE,
- };
- const calendarEvent = new GoogleCalendarEvent(MOCK_OPTIONS);
-
- const expectedLink = encodeURI(`${BASE_URL_ADD_TO_CALENDAR_URL}&dates=${
- MOCK_CONVERTED_START_DATE}/${MOCK_CONVERTED_END_DATE}&text=${
- MOCK_TITLE}`);
-
- expect(calendarEvent.getEventLink()).toBe(expectedLink);
- });
-
- it('returns a link for an event where a custom timezone is set', () => {
+ it(
+ "returns a link for an event where the timezone is set to the users " +
+ "default",
+ () => {
+ const MOCK_OPTIONS: GoogleCalendarEventOptions = {
+ endDate: MOCK_END_DATE,
+ startDate: MOCK_START_DATE,
+ title: MOCK_TITLE,
+ timeZone: USER_TIME_ZONE,
+ };
+ const calendarEvent = new GoogleCalendarEvent(MOCK_OPTIONS);
+
+ const expectedLink = encodeURI(
+ `${BASE_URL_ADD_TO_CALENDAR_URL}&dates=${
+ MOCK_CONVERTED_START_DATE
+ }/${MOCK_CONVERTED_END_DATE}&text=${MOCK_TITLE}`,
+ );
+
+ expect(calendarEvent.getEventLink()).toBe(expectedLink);
+ },
+ );
+
+ it("returns a link for an event where a custom timezone is set", () => {
const MOCK_OPTIONS: GoogleCalendarEventOptions = {
endDate: MOCK_END_DATE,
startDate: MOCK_START_DATE,
@@ -86,13 +103,15 @@ describe('The GoogleCalendarEvent class', () => {
const calendarEvent = new GoogleCalendarEvent(MOCK_OPTIONS);
const expectedLink = encodeURI(
- `${BASE_URL_ADD_TO_CALENDAR_URL}&dates=${MOCK_CONVERTED_START_DATE}/${
- MOCK_CONVERTED_END_DATE}&text=${MOCK_TITLE}&ctz=${MOCK_TIMEZONE}`);
+ `${BASE_URL_ADD_TO_CALENDAR_URL}&dates=${MOCK_CONVERTED_START_DATE}/${
+ MOCK_CONVERTED_END_DATE
+ }&text=${MOCK_TITLE}&ctz=${MOCK_TIMEZONE}`,
+ );
expect(calendarEvent.getEventLink()).toBe(expectedLink);
});
- it('throws an error if the start date is later than the end date', () => {
+ it("throws an error if the start date is later than the end date", () => {
const MOCK_OPTIONS: GoogleCalendarEventOptions = {
endDate: new Date(2019, 0, 1),
startDate: new Date(2020, 0, 1),
diff --git a/src/share/add_to_calendar.ts b/src/share/add_to_calendar.ts
index bf17dc3..4e442c5 100644
--- a/src/share/add_to_calendar.ts
+++ b/src/share/add_to_calendar.ts
@@ -1,15 +1,15 @@
-import {isDevMode} from '@angular/core';
+import { isDevMode } from "@angular/core";
export const BASE_URL_ADD_TO_CALENDAR_URL =
- 'http://www.google.com/calendar/event?action=TEMPLATE';
+ "http://www.google.com/calendar/event?action=TEMPLATE";
/**
* Constant signifying to that a calendar event should be set to the users
* current timezone. Note - the actual value of this constant is not used.
*/
-export const USER_TIME_ZONE = 'User timezone';
+export const USER_TIME_ZONE = "User timezone";
-const UTC_TIME_ZONE_CODE = 'Z';
+const UTC_TIME_ZONE_CODE = "Z";
export interface GoogleCalendarEventOptions {
/** Optional property which fills the event details section of an event. */
@@ -56,11 +56,14 @@ export interface GoogleCalendarEventOptions {
}
function formatDateSegment(dateSegment: number): string {
- return dateSegment.toString().padStart(2, '0');
+ return dateSegment.toString().padStart(2, "0");
}
function formatDateString(
- date: Date, isAllDayEvent = false, timeZone = UTC_TIME_ZONE_CODE): string {
+ date: Date,
+ isAllDayEvent = false,
+ timeZone = UTC_TIME_ZONE_CODE,
+): string {
const year = date.getFullYear();
const month = formatDateSegment(date.getMonth() + 1);
const day = formatDateSegment(date.getDate());
@@ -71,7 +74,7 @@ function formatDateString(
// Timezone should only be included in the date string if UTC ('Z') is being
// used.
const timeZoneCode =
- timeZone === UTC_TIME_ZONE_CODE ? UTC_TIME_ZONE_CODE : '';
+ timeZone === UTC_TIME_ZONE_CODE ? UTC_TIME_ZONE_CODE : "";
const hours = formatDateSegment(date.getHours());
const minutes = formatDateSegment(date.getMinutes());
const seconds = formatDateSegment(date.getSeconds());
@@ -112,23 +115,30 @@ export class GoogleCalendarEvent extends CalendarEvent {
location,
startDate,
timeZone,
- title
+ title,
} = this.options;
if (isDevMode() && startDate.getTime() > endDate.getTime()) {
- throw new Error('Start date must not be later than end date!');
+ throw new Error("Start date must not be later than end date!");
}
- const formattedStartDate =
- formatDateString(startDate, isAllDayEvent, timeZone);
+ const formattedStartDate = formatDateString(
+ startDate,
+ isAllDayEvent,
+ timeZone,
+ );
const formattedEndDate = formatDateString(endDate, isAllDayEvent, timeZone);
const timeZoneSection =
- timeZone && timeZone !== USER_TIME_ZONE ? `&ctz=${timeZone}` : '';
- const detailsSection = details ? `&details=${details}` : '';
- const locationSection = location ? `&location=${location}` : '';
-
- return encodeURI(`${BASE_URL_ADD_TO_CALENDAR_URL}&dates=${
- formattedStartDate}/${formattedEndDate}&text=${title}${
- timeZoneSection}${detailsSection}${locationSection}`);
+ timeZone && timeZone !== USER_TIME_ZONE ? `&ctz=${timeZone}` : "";
+ const detailsSection = details ? `&details=${details}` : "";
+ const locationSection = location ? `&location=${location}` : "";
+
+ return encodeURI(
+ `${BASE_URL_ADD_TO_CALENDAR_URL}&dates=${
+ formattedStartDate
+ }/${formattedEndDate}&text=${title}${
+ timeZoneSection
+ }${detailsSection}${locationSection}`,
+ );
}
}
diff --git a/src/share/index.ts b/src/share/index.ts
index b2837bc..1ad829c 100644
--- a/src/share/index.ts
+++ b/src/share/index.ts
@@ -1,2 +1,2 @@
-export * from './share';
-export * from './add_to_calendar';
+export * from "./share";
+export * from "./add_to_calendar";
diff --git a/src/share/share.spec.ts b/src/share/share.spec.ts
index 0a3de08..f39cc13 100644
--- a/src/share/share.spec.ts
+++ b/src/share/share.spec.ts
@@ -1,17 +1,22 @@
-import {TestBed} from '@angular/core/testing';
-import {WINDOW, WindowModule} from '@phntms/angular-lib/window';
+import { TestBed } from "@angular/core/testing";
+import { WINDOW, WindowModule } from "../window";
-import {setupComponentTestingModule} from '../testing/test-lib';
+import { setupComponentTestingModule } from "../testing/test-lib";
-import {getSocialNetworkShareLink, ShareService, SocialNetwork, SocialNetworkUrl} from './share';
+import {
+ getSocialNetworkShareLink,
+ ShareService,
+ SocialNetwork,
+ SocialNetworkUrl,
+} from "./share";
-const MOCK_HASHTAG_LIST = ['cool', 'story', 'bro'];
-const MOCK_SHARE_COPY = 'Check out my sick link';
-const MOCK_VIA_PARAMETER = 'James Riall';
-const MOCK_WINDOW_LOCATION = 'https://example.com/';
-const MOCK_OVERRIDE_URL = 'https://external-example.com/share/';
+const MOCK_HASHTAG_LIST = ["cool", "story", "bro"];
+const MOCK_SHARE_COPY = "Check out my sick link";
+const MOCK_VIA_PARAMETER = "James Riall";
+const MOCK_WINDOW_LOCATION = "https://example.com/";
+const MOCK_OVERRIDE_URL = "https://external-example.com/share/";
-describe('The share service', () => {
+describe("The share service", () => {
let shareService: ShareService;
beforeEach(() => {
@@ -32,93 +37,107 @@ describe('The share service', () => {
shareService = TestBed.inject(ShareService);
});
- it('shares a link to Facebook correctly', () => {
+ it("shares a link to Facebook correctly", () => {
const expectedShareUrl = SocialNetworkUrl.FACEBOOK + MOCK_WINDOW_LOCATION;
expect(
- getSocialNetworkShareLink(MOCK_WINDOW_LOCATION, SocialNetwork.FACEBOOK))
- .toBe(expectedShareUrl);
+ getSocialNetworkShareLink(MOCK_WINDOW_LOCATION, SocialNetwork.FACEBOOK),
+ ).toBe(expectedShareUrl);
});
- it('shares a link to LinkedIn correctly', () => {
+ it("shares a link to LinkedIn correctly", () => {
const expectedShareUrl = SocialNetworkUrl.LINKEDIN + MOCK_WINDOW_LOCATION;
expect(
- getSocialNetworkShareLink(MOCK_WINDOW_LOCATION, SocialNetwork.LINKEDIN))
- .toBe(expectedShareUrl);
+ getSocialNetworkShareLink(MOCK_WINDOW_LOCATION, SocialNetwork.LINKEDIN),
+ ).toBe(expectedShareUrl);
});
- it('shares a link with no prefilled copy to Twitter correctly', () => {
+ it("shares a link with no prefilled copy to Twitter correctly", () => {
const expectedShareUrl = SocialNetworkUrl.TWITTER + MOCK_WINDOW_LOCATION;
expect(
- getSocialNetworkShareLink(MOCK_WINDOW_LOCATION, SocialNetwork.TWITTER))
- .toBe(expectedShareUrl);
+ getSocialNetworkShareLink(MOCK_WINDOW_LOCATION, SocialNetwork.TWITTER),
+ ).toBe(expectedShareUrl);
});
- it('shares a link with prefilled copy to Twitter correctly', () => {
- const expectedShareUrl = SocialNetworkUrl.TWITTER + MOCK_WINDOW_LOCATION +
- '&text=Check%20out%20my%20sick%20link';
+ it("shares a link with prefilled copy to Twitter correctly", () => {
+ const expectedShareUrl =
+ SocialNetworkUrl.TWITTER +
+ MOCK_WINDOW_LOCATION +
+ "&text=Check%20out%20my%20sick%20link";
- expect(getSocialNetworkShareLink(
- MOCK_WINDOW_LOCATION, SocialNetwork.TWITTER,
- {prefillCopy: MOCK_SHARE_COPY}))
- .toBe(expectedShareUrl);
+ expect(
+ getSocialNetworkShareLink(MOCK_WINDOW_LOCATION, SocialNetwork.TWITTER, {
+ prefillCopy: MOCK_SHARE_COPY,
+ }),
+ ).toBe(expectedShareUrl);
});
it(`shares a link with the 'hashtags' parameter to Twitter correctly`, () => {
- const expectedShareUrl = SocialNetworkUrl.TWITTER + MOCK_WINDOW_LOCATION +
- '&hashtags=cool,story,bro';
+ const expectedShareUrl =
+ SocialNetworkUrl.TWITTER +
+ MOCK_WINDOW_LOCATION +
+ "&hashtags=cool,story,bro";
- expect(getSocialNetworkShareLink(
- MOCK_WINDOW_LOCATION, SocialNetwork.TWITTER,
- {twitterHashtagList: MOCK_HASHTAG_LIST}))
- .toBe(expectedShareUrl);
+ expect(
+ getSocialNetworkShareLink(MOCK_WINDOW_LOCATION, SocialNetwork.TWITTER, {
+ twitterHashtagList: MOCK_HASHTAG_LIST,
+ }),
+ ).toBe(expectedShareUrl);
});
it(`shares a link with the 'via' parameter to Twitter correctly`, () => {
const expectedShareUrl =
- SocialNetworkUrl.TWITTER + MOCK_WINDOW_LOCATION + '&via=James%20Riall';
+ SocialNetworkUrl.TWITTER + MOCK_WINDOW_LOCATION + "&via=James%20Riall";
- expect(getSocialNetworkShareLink(
- MOCK_WINDOW_LOCATION, SocialNetwork.TWITTER,
- {twitterVia: MOCK_VIA_PARAMETER}))
- .toBe(expectedShareUrl);
+ expect(
+ getSocialNetworkShareLink(MOCK_WINDOW_LOCATION, SocialNetwork.TWITTER, {
+ twitterVia: MOCK_VIA_PARAMETER,
+ }),
+ ).toBe(expectedShareUrl);
});
it(`shares a link with multiple parameters to Twitter correctly`, () => {
- const expectedShareUrl = SocialNetworkUrl.TWITTER + MOCK_WINDOW_LOCATION +
- '&text=Check%20out%20my%20sick%20link' +
- '&hashtags=cool,story,bro' +
- '&via=James%20Riall';
+ const expectedShareUrl =
+ SocialNetworkUrl.TWITTER +
+ MOCK_WINDOW_LOCATION +
+ "&text=Check%20out%20my%20sick%20link" +
+ "&hashtags=cool,story,bro" +
+ "&via=James%20Riall";
const mockShareOptions = {
prefillCopy: MOCK_SHARE_COPY,
twitterHashtagList: MOCK_HASHTAG_LIST,
twitterVia: MOCK_VIA_PARAMETER,
};
- expect(getSocialNetworkShareLink(
- MOCK_WINDOW_LOCATION, SocialNetwork.TWITTER, mockShareOptions))
- .toBe(expectedShareUrl);
+ expect(
+ getSocialNetworkShareLink(
+ MOCK_WINDOW_LOCATION,
+ SocialNetwork.TWITTER,
+ mockShareOptions,
+ ),
+ ).toBe(expectedShareUrl);
});
- it('shares a link with no prefilled copy to WhatsApp correctly', () => {
+ it("shares a link with no prefilled copy to WhatsApp correctly", () => {
const expectedShareUrl = SocialNetworkUrl.WHATSAPP + MOCK_WINDOW_LOCATION;
expect(
- getSocialNetworkShareLink(MOCK_WINDOW_LOCATION, SocialNetwork.WHATSAPP))
- .toBe(expectedShareUrl);
+ getSocialNetworkShareLink(MOCK_WINDOW_LOCATION, SocialNetwork.WHATSAPP),
+ ).toBe(expectedShareUrl);
});
- it('shares a link with prefilled copy to WhatsApp correctly', () => {
- const expectedShareUrl =
- `${SocialNetworkUrl.WHATSAPP}Check%20out%20my%20sick%20link%20${
- MOCK_WINDOW_LOCATION}`;
+ it("shares a link with prefilled copy to WhatsApp correctly", () => {
+ const expectedShareUrl = `${SocialNetworkUrl.WHATSAPP}Check%20out%20my%20sick%20link%20${
+ MOCK_WINDOW_LOCATION
+ }`;
- expect(getSocialNetworkShareLink(
- MOCK_WINDOW_LOCATION, SocialNetwork.WHATSAPP,
- {prefillCopy: MOCK_SHARE_COPY}))
- .toBe(expectedShareUrl);
+ expect(
+ getSocialNetworkShareLink(MOCK_WINDOW_LOCATION, SocialNetwork.WHATSAPP, {
+ prefillCopy: MOCK_SHARE_COPY,
+ }),
+ ).toBe(expectedShareUrl);
});
it(`shares a link with a custom url`, () => {
@@ -128,8 +147,12 @@ describe('The share service', () => {
const expectedShareUrl = SocialNetworkUrl.FACEBOOK + mockShareOptions.url;
- expect(getSocialNetworkShareLink(
- MOCK_WINDOW_LOCATION, SocialNetwork.FACEBOOK, mockShareOptions))
- .toBe(expectedShareUrl);
+ expect(
+ getSocialNetworkShareLink(
+ MOCK_WINDOW_LOCATION,
+ SocialNetwork.FACEBOOK,
+ mockShareOptions,
+ ),
+ ).toBe(expectedShareUrl);
});
});
diff --git a/src/share/share.ts b/src/share/share.ts
index 468a0b4..82f6194 100644
--- a/src/share/share.ts
+++ b/src/share/share.ts
@@ -1,9 +1,9 @@
-import {Inject, Injectable} from '@angular/core';
-import {WINDOW} from '@phntms/angular-lib/window';
+import { Inject, Injectable } from "@angular/core";
+import { WINDOW } from "../window";
-
-const POPUP_OPTIONS = 'menubar=no,toolbar=no,resizable=yes,' +
- 'scrollbars=yes,height=253,width=600';
+const POPUP_OPTIONS =
+ "menubar=no,toolbar=no,resizable=yes," +
+ "scrollbars=yes,height=253,width=600";
export enum SocialNetwork {
NETWORK_UNSPECIFIED,
@@ -14,10 +14,10 @@ export enum SocialNetwork {
}
export enum SocialNetworkUrl {
- FACEBOOK = 'https://www.facebook.com/sharer/sharer.php?u=',
- TWITTER = 'https://twitter.com/intent/tweet?url=',
- LINKEDIN = 'https://www.linkedin.com/shareArticle?url=',
- WHATSAPP = 'https://api.whatsapp.com/send?phone=whatsappphonenumber&text=',
+ FACEBOOK = "https://www.facebook.com/sharer/sharer.php?u=",
+ TWITTER = "https://twitter.com/intent/tweet?url=",
+ LINKEDIN = "https://www.linkedin.com/shareArticle?url=",
+ WHATSAPP = "https://api.whatsapp.com/send?phone=whatsappphonenumber&text=",
}
export declare interface SocialShareOptions {
@@ -28,7 +28,9 @@ export declare interface SocialShareOptions {
}
function getTwitterShareLink(
- location: string, socialShareOptions?: SocialShareOptions): string {
+ location: string,
+ socialShareOptions?: SocialShareOptions,
+): string {
let twitterShareLink = SocialNetworkUrl.TWITTER + location;
if (socialShareOptions && socialShareOptions.prefillCopy) {
@@ -36,8 +38,7 @@ function getTwitterShareLink(
}
if (socialShareOptions && socialShareOptions.twitterHashtagList) {
- twitterShareLink +=
- `&hashtags=${socialShareOptions.twitterHashtagList.join(',')}`;
+ twitterShareLink += `&hashtags=${socialShareOptions.twitterHashtagList.join(",")}`;
}
if (socialShareOptions && socialShareOptions.twitterVia) {
@@ -48,41 +49,51 @@ function getTwitterShareLink(
}
export function getSocialNetworkShareLink(
- location: string, socialNetwork: SocialNetwork,
- socialShareOptions?: SocialShareOptions): string {
+ location: string,
+ socialNetwork: SocialNetwork,
+ socialShareOptions?: SocialShareOptions,
+): string {
const overrideUrl = socialShareOptions && socialShareOptions.url;
const shareUrl = overrideUrl || location;
switch (socialNetwork) {
- case (SocialNetwork.FACEBOOK):
+ case SocialNetwork.FACEBOOK:
return SocialNetworkUrl.FACEBOOK + shareUrl;
- case (SocialNetwork.LINKEDIN):
+ case SocialNetwork.LINKEDIN:
return SocialNetworkUrl.LINKEDIN + shareUrl;
- case (SocialNetwork.TWITTER):
+ case SocialNetwork.TWITTER:
return getTwitterShareLink(shareUrl, socialShareOptions);
- case (SocialNetwork.WHATSAPP):
+ case SocialNetwork.WHATSAPP:
if (socialShareOptions && socialShareOptions.prefillCopy) {
- return SocialNetworkUrl.WHATSAPP +
- encodeURI(socialShareOptions.prefillCopy + ' ') + shareUrl;
+ return (
+ SocialNetworkUrl.WHATSAPP +
+ encodeURI(socialShareOptions.prefillCopy + " ") +
+ shareUrl
+ );
} else {
return SocialNetworkUrl.WHATSAPP + shareUrl;
}
default:
- return '';
+ return "";
}
}
/** @dynamic */
-@Injectable({providedIn: 'root'})
+@Injectable({ providedIn: "root" })
export class ShareService {
constructor(@Inject(WINDOW) private readonly window: Window) {}
shareToSocialNetwork(
- socialNetwork: SocialNetwork, socialShareOptions?: SocialShareOptions) {
+ socialNetwork: SocialNetwork,
+ socialShareOptions?: SocialShareOptions,
+ ) {
const location = this.window.location.href;
- const socialNetworkShareLink =
- getSocialNetworkShareLink(location, socialNetwork, socialShareOptions);
+ const socialNetworkShareLink = getSocialNetworkShareLink(
+ location,
+ socialNetwork,
+ socialShareOptions,
+ );
- this.window.open(socialNetworkShareLink, '', POPUP_OPTIONS);
+ this.window.open(socialNetworkShareLink, "", POPUP_OPTIONS);
}
}
diff --git a/src/test.ts b/src/test.ts
index 0f4c696..dc7c240 100644
--- a/src/test.ts
+++ b/src/test.ts
@@ -1,23 +1,23 @@
// This file is required by karma.conf.js and loads recursively all the .spec
// and framework files
-import 'core-js/es7/reflect';
-import 'zone.js/dist/zone';
-import 'zone.js/dist/zone-testing';
-import { getTestBed } from '@angular/core/testing';
+import "core-js/es/reflect";
+import "zone.js";
+import "zone.js/testing";
+import { getTestBed } from "@angular/core/testing";
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting,
-} from '@angular/platform-browser-dynamic/testing';
+} from "@angular/platform-browser-dynamic/testing";
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
- platformBrowserDynamicTesting()
+ platformBrowserDynamicTesting(),
);
-// Then we find all the tests.
-const context = require.context('./', true, /\.spec\.ts$/);
-// And load the modules.
-context.keys().map(context);
+// Then we explicitly import all test files
+import "./clipboard/copy-to-clipboard-directive.spec";
+import "./share/share.spec";
+import "./window/window.spec";
diff --git a/src/testing/index.ts b/src/testing/index.ts
index b5a85b2..569ddf7 100644
--- a/src/testing/index.ts
+++ b/src/testing/index.ts
@@ -1 +1 @@
-export * from './test-lib';
+export * from "./test-lib";
diff --git a/src/testing/test-lib.ts b/src/testing/test-lib.ts
index 74af746..cab10d5 100644
--- a/src/testing/test-lib.ts
+++ b/src/testing/test-lib.ts
@@ -1,8 +1,8 @@
-import { APP_BASE_HREF } from '@angular/common';
-import { HttpClientTestingModule } from '@angular/common/http/testing';
-import { ModuleWithProviders, Provider, Type } from '@angular/core';
-import { TestBed } from '@angular/core/testing';
-import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { APP_BASE_HREF } from "@angular/common";
+import { HttpClientTestingModule } from "@angular/common/http/testing";
+import { ModuleWithProviders, Provider, Type } from "@angular/core";
+import { TestBed } from "@angular/core/testing";
+import { NoopAnimationsModule } from "@angular/platform-browser/animations";
export declare interface ModuleConfig {
declarations?: Array> | null;
@@ -16,7 +16,7 @@ const DEFAULT_COMPONENT_TEST_IMPORTS: Array<
const BASE_HREF_PROVIDER: Provider = {
provide: APP_BASE_HREF,
- useValue: '/',
+ useValue: "/",
};
/**
@@ -24,9 +24,29 @@ const BASE_HREF_PROVIDER: Provider = {
* reducing boilerplate when setting up test modules.
*/
export function setupComponentTestingModule(config: ModuleConfig) {
+ const imports = [...DEFAULT_COMPONENT_TEST_IMPORTS];
+ const declarations = [];
+
+ // Add standard imports
+ if (config.imports) {
+ imports.push(...config.imports);
+ }
+
+ // Handle components
+ if (config.declarations) {
+ for (const declaration of config.declarations) {
+ // Check if component is standalone
+ if ((declaration as any).ɵcmp?.standalone) {
+ imports.push(declaration);
+ } else {
+ declarations.push(declaration);
+ }
+ }
+ }
+
TestBed.configureTestingModule({
- ...config,
- imports: DEFAULT_COMPONENT_TEST_IMPORTS.concat(config.imports || []),
- providers: [BASE_HREF_PROVIDER].concat(config.providers || []),
+ declarations,
+ imports,
+ providers: [BASE_HREF_PROVIDER, ...(config.providers || [])],
}).compileComponents();
}
diff --git a/src/window/index.ts b/src/window/index.ts
index 945eec3..9702578 100644
--- a/src/window/index.ts
+++ b/src/window/index.ts
@@ -1 +1 @@
-export * from './window';
+export * from "./window";
diff --git a/src/window/window.spec.ts b/src/window/window.spec.ts
index 896b68c..3f11081 100644
--- a/src/window/window.spec.ts
+++ b/src/window/window.spec.ts
@@ -1,13 +1,13 @@
-import {Component, Inject, PLATFORM_ID, NgModule} from '@angular/core';
-import {ComponentFixture, TestBed} from '@angular/core/testing';
+import { Component, Inject, PLATFORM_ID, NgModule } from "@angular/core";
+import { ComponentFixture, TestBed } from "@angular/core/testing";
-import {setupComponentTestingModule} from '../testing/test-lib';
+import { setupComponentTestingModule } from "../testing/test-lib";
-import {browserWindowProvider, WINDOW, windowProvider} from './window';
+import { browserWindowProvider, WINDOW, windowProvider } from "./window";
@Component({
- selector: 'ph-window-test-host',
- template: '',
+ selector: "ph-window-test-host",
+ template: "",
})
class WindowTestHostComponent {
constructor(@Inject(WINDOW) private readonly window: Window) {}
@@ -18,8 +18,8 @@ class WindowTestHostComponent {
}
enum PlatformType {
- BROWSER = 'browser',
- SERVER = 'server',
+ BROWSER = "browser",
+ SERVER = "server",
}
function setupWindowTestingModule(platformType: PlatformType) {
@@ -41,11 +41,11 @@ function setupWindowTestingModule(platformType: PlatformType) {
});
}
-describe('The window provider', () => {
+describe("The window provider", () => {
let component: WindowTestHostComponent;
let fixture: ComponentFixture;
- describe('when in the browser', () => {
+ describe("when in the browser", () => {
beforeEach(() => {
setupWindowTestingModule(PlatformType.BROWSER);
@@ -53,23 +53,22 @@ describe('The window provider', () => {
component = fixture.componentInstance;
});
- it('gets the window object', () => {
+ it("gets the window object", () => {
const window = component.getWindow();
expect(window).toBeDefined();
});
- it('allows for interaction with the window methods properties and methods',
- () => {
- const {innerHeight, innerWidth, setTimeout} = component.getWindow();
+ it("allows for interaction with the window methods properties and methods", () => {
+ const { innerHeight, innerWidth, setTimeout } = component.getWindow();
- expect(innerHeight).toBeGreaterThan(0);
- expect(innerWidth).toBeGreaterThan(0);
- expect(typeof setTimeout).toBe('function');
- });
+ expect(innerHeight).toBeGreaterThan(0);
+ expect(innerWidth).toBeGreaterThan(0);
+ expect(typeof setTimeout).toBe("function");
+ });
});
- describe('when on the server', () => {
+ describe("when on the server", () => {
beforeEach(() => {
setupWindowTestingModule(PlatformType.SERVER);
@@ -77,7 +76,7 @@ describe('The window provider', () => {
component = fixture.componentInstance;
});
- it('gets an empty object instead of the window when on the server', () => {
+ it("gets an empty object instead of the window when on the server", () => {
expect(Object.keys(component.getWindow())).toEqual([]);
});
});
diff --git a/src/window/window.ts b/src/window/window.ts
index f29f483..9e31cb2 100644
--- a/src/window/window.ts
+++ b/src/window/window.ts
@@ -1,7 +1,14 @@
-import {isPlatformBrowser} from '@angular/common';
-import {ClassProvider, FactoryProvider, Injectable, InjectionToken, NgModule, PLATFORM_ID} from '@angular/core';
+import { isPlatformBrowser } from "@angular/common";
+import {
+ ClassProvider,
+ FactoryProvider,
+ Injectable,
+ InjectionToken,
+ NgModule,
+ PLATFORM_ID,
+} from "@angular/core";
-export const WINDOW = new InjectionToken('WindowToken');
+export const WINDOW = new InjectionToken("WindowToken");
/**
* Define abstract class for obtaining reference to the global window object.
@@ -22,8 +29,9 @@ export class BrowserWindowRef extends WindowRef {
}
export function windowFactory(
- browserWindowRef: BrowserWindowRef,
- platformId: InjectionToken