@bitblit/ngx-acute-common 5.0.512-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/License.txt +13 -0
- package/README.md +7 -0
- package/artifacts/coverage/base.css +224 -0
- package/artifacts/coverage/block-navigation.js +87 -0
- package/artifacts/coverage/clover.xml +1565 -0
- package/artifacts/coverage/coverage-final.json +40 -0
- package/artifacts/coverage/favicon.png +0 -0
- package/artifacts/coverage/index.html +236 -0
- package/artifacts/coverage/modules/acute-common/src/build/index.html +116 -0
- package/artifacts/coverage/modules/acute-common/src/build/ngx-acute-common-info.ts.html +142 -0
- package/artifacts/coverage/modules/acute-common/src/components/dialogs/alert/alert.component.ts.html +184 -0
- package/artifacts/coverage/modules/acute-common/src/components/dialogs/alert/index.html +116 -0
- package/artifacts/coverage/modules/acute-common/src/components/dialogs/block-ui/block-ui.component.ts.html +271 -0
- package/artifacts/coverage/modules/acute-common/src/components/dialogs/block-ui/index.html +116 -0
- package/artifacts/coverage/modules/acute-common/src/pipes/capitalize.pipe.ts.html +118 -0
- package/artifacts/coverage/modules/acute-common/src/pipes/dollar-formatted.pipe.ts.html +124 -0
- package/artifacts/coverage/modules/acute-common/src/pipes/index.html +251 -0
- package/artifacts/coverage/modules/acute-common/src/pipes/map-values.pipe.ts.html +142 -0
- package/artifacts/coverage/modules/acute-common/src/pipes/number-with-commas.pipe.ts.html +112 -0
- package/artifacts/coverage/modules/acute-common/src/pipes/order-by.pipe.ts.html +259 -0
- package/artifacts/coverage/modules/acute-common/src/pipes/percent-formatted.pipe.ts.html +112 -0
- package/artifacts/coverage/modules/acute-common/src/pipes/plural.pipe.ts.html +127 -0
- package/artifacts/coverage/modules/acute-common/src/pipes/round.pipe.ts.html +112 -0
- package/artifacts/coverage/modules/acute-common/src/pipes/time-ago-formatted.pipe.ts.html +115 -0
- package/artifacts/coverage/modules/acute-common/src/pipes/timing.pipe.ts.html +139 -0
- package/artifacts/coverage/modules/acute-common/src/services/google-analytics.service.ts.html +280 -0
- package/artifacts/coverage/modules/acute-common/src/services/graphql-query.service.ts.html +394 -0
- package/artifacts/coverage/modules/acute-common/src/services/index.html +161 -0
- package/artifacts/coverage/modules/acute-common/src/services/local-storage.service.ts.html +235 -0
- package/artifacts/coverage/modules/acute-common/src/services/window-ref.service.ts.html +160 -0
- package/artifacts/coverage/prettify.css +1 -0
- package/artifacts/coverage/prettify.js +2 -0
- package/artifacts/coverage/sort-arrow-sprite.png +0 -0
- package/artifacts/coverage/sorter.js +196 -0
- package/lib/my-angular-library.cjs.js +7 -0
- package/lib/my-angular-library.esm.js +7 -0
- package/lib/my-angular-library.umd.js +7 -0
- package/package.json +56 -0
- package/rollup.config.mjs +58 -0
- package/src/build/ngx-acute-common-info.ts +19 -0
- package/src/components/dialogs/alert/alert.component.ts +33 -0
- package/src/components/dialogs/block-ui/block-ui.component.html +9 -0
- package/src/components/dialogs/block-ui/block-ui.component.spec.ts +24 -0
- package/src/components/dialogs/block-ui/block-ui.component.ts +62 -0
- package/src/index.ts +2 -0
- package/src/model/google-analytics-config.ts +3 -0
- package/src/pipes/capitalize.pipe.ts +11 -0
- package/src/pipes/dollar-formatted.pipe.ts +13 -0
- package/src/pipes/map-values.pipe.ts +19 -0
- package/src/pipes/number-with-commas.pipe.ts +9 -0
- package/src/pipes/order-by.pipe.ts +58 -0
- package/src/pipes/percent-formatted.pipe.ts +9 -0
- package/src/pipes/plural.pipe.ts +14 -0
- package/src/pipes/round.pipe.ts +9 -0
- package/src/pipes/time-ago-formatted.pipe.ts +10 -0
- package/src/pipes/timing.pipe.ts +18 -0
- package/src/services/google-analytics.service.spec.ts +17 -0
- package/src/services/google-analytics.service.ts +65 -0
- package/src/services/graphql-query.service.spec.ts +17 -0
- package/src/services/graphql-query.service.ts +103 -0
- package/src/services/local-storage.service.spec.ts +17 -0
- package/src/services/local-storage.service.ts +50 -0
- package/src/services/window-ref.service.spec.ts +17 -0
- package/src/services/window-ref.service.ts +25 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Pipe, PipeTransform } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Pipe({ name: 'acuteOrderBy', pure: false, standalone: true })
|
|
4
|
+
export class OrderByPipe implements PipeTransform {
|
|
5
|
+
static _orderByComparator(a: any, b: any): number {
|
|
6
|
+
if (isNaN(parseFloat(a)) || !isFinite(a) || isNaN(parseFloat(b)) || !isFinite(b)) {
|
|
7
|
+
//Isn't a number so lowercase the string to properly compare
|
|
8
|
+
if (String(a).toLowerCase() < String(b).toLowerCase()) return -1;
|
|
9
|
+
if (String(a).toLowerCase() > String(b).toLowerCase()) return 1;
|
|
10
|
+
} else {
|
|
11
|
+
//Parse strings as numbers to compare properly
|
|
12
|
+
if (parseFloat(a) < parseFloat(b)) return -1;
|
|
13
|
+
if (parseFloat(a) > parseFloat(b)) return 1;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return 0; //equal each other
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
transform(input: any, [config = '+']): any {
|
|
20
|
+
if (!Array.isArray(input)) return input;
|
|
21
|
+
|
|
22
|
+
if (!Array.isArray(config) || (Array.isArray(config) && config.length == 1)) {
|
|
23
|
+
const propertyToCheck: string = !Array.isArray(config) ? config : config[0];
|
|
24
|
+
const desc = propertyToCheck.substr(0, 1) == '-';
|
|
25
|
+
|
|
26
|
+
//Basic array
|
|
27
|
+
if (!propertyToCheck || propertyToCheck == '-' || propertyToCheck == '+') {
|
|
28
|
+
return !desc ? input.sort() : input.sort().reverse();
|
|
29
|
+
} else {
|
|
30
|
+
const property: string =
|
|
31
|
+
propertyToCheck.substr(0, 1) == '+' || propertyToCheck.substr(0, 1) == '-' ? propertyToCheck.substr(1) : propertyToCheck;
|
|
32
|
+
|
|
33
|
+
return input.sort(function (a: any, b: any) {
|
|
34
|
+
return !desc
|
|
35
|
+
? OrderByPipe._orderByComparator(a[property], b[property])
|
|
36
|
+
: -OrderByPipe._orderByComparator(a[property], b[property]);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
//Loop over property of the array in order and sort
|
|
41
|
+
return input.sort(function (a: any, b: any) {
|
|
42
|
+
for (let i: number = 0; i < config.length; i++) {
|
|
43
|
+
const desc = config[i].substr(0, 1) == '-';
|
|
44
|
+
const property = config[i].substr(0, 1) == '+' || config[i].substr(0, 1) == '-' ? config[i].substr(1) : config[i];
|
|
45
|
+
|
|
46
|
+
const comparison = !desc
|
|
47
|
+
? OrderByPipe._orderByComparator(a[property], b[property])
|
|
48
|
+
: -OrderByPipe._orderByComparator(a[property], b[property]);
|
|
49
|
+
|
|
50
|
+
//Don't return 0 yet in case of needing to sort by next property
|
|
51
|
+
if (comparison != 0) return comparison;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return 0; //equal each other
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Pipe, PipeTransform } from '@angular/core';
|
|
2
|
+
import {NumberRatchet} from "@bitblit/ratchet-common/lang/number-ratchet";
|
|
3
|
+
|
|
4
|
+
@Pipe({ name: 'acutePercent' , standalone: true })
|
|
5
|
+
export class PercentFormattedPipe implements PipeTransform {
|
|
6
|
+
transform(input: number): string {
|
|
7
|
+
return NumberRatchet.pctFormatted(input);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Pipe, PipeTransform } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Pipe({ name: 'acutePlural' , standalone: true})
|
|
4
|
+
export class PluralPipe implements PipeTransform {
|
|
5
|
+
|
|
6
|
+
transform(input: number, label: string, pluralLabel: string = ''): string {
|
|
7
|
+
input = input || 0;
|
|
8
|
+
return input === 1
|
|
9
|
+
? `${input} ${label}`
|
|
10
|
+
: pluralLabel
|
|
11
|
+
? `${input} ${pluralLabel}`
|
|
12
|
+
: `${input} ${label}s`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {Pipe, PipeTransform} from '@angular/core';
|
|
2
|
+
import {DurationRatchet} from "@bitblit/ratchet-common/lang/duration-ratchet";
|
|
3
|
+
import {NumberRatchet} from "@bitblit/ratchet-common/lang/number-ratchet";
|
|
4
|
+
|
|
5
|
+
@Pipe({ name: 'acuteTimeAgo' , standalone: true})
|
|
6
|
+
export class TimeAgoFormattedPipe implements PipeTransform {
|
|
7
|
+
transform(input: number): string {
|
|
8
|
+
return DurationRatchet.formatMsDuration(new Date().getTime() - NumberRatchet.safeNumber(input));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Pipe, PipeTransform } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Pipe({ name: 'acuteTiming' , standalone: true})
|
|
4
|
+
export class TimingPipe implements PipeTransform {
|
|
5
|
+
transform(time: number): string {
|
|
6
|
+
if (time) {
|
|
7
|
+
const minutes = Math.floor(time / 60);
|
|
8
|
+
const seconds = Math.floor(time % 60);
|
|
9
|
+
return `${this.initZero(minutes)}${minutes}:${this.initZero(seconds)}${seconds}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return '00:00';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private initZero(time: number): string {
|
|
16
|
+
return time < 10 ? '0' : '';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
import { beforeEach, describe, expect, test } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import {GraphqlQueryService} from "./graphql-query.service";
|
|
5
|
+
|
|
6
|
+
describe('GraphqlQueryService', () => {
|
|
7
|
+
let service: GraphqlQueryService;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
TestBed.configureTestingModule({});
|
|
11
|
+
service = TestBed.inject(GraphqlQueryService);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test.skip('should be created', () => {
|
|
15
|
+
expect(service).toBeTruthy();
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { NavigationEnd, Router } from '@angular/router';
|
|
3
|
+
import { Logger } from '@bitblit/ratchet-common/logger/logger';
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
6
|
+
declare let gtag: Function;
|
|
7
|
+
|
|
8
|
+
@Injectable({
|
|
9
|
+
providedIn: 'root',
|
|
10
|
+
})
|
|
11
|
+
// See : https://lumin8media.com/blog/add-google-analytics-angular
|
|
12
|
+
export class GoogleAnalyticsService {
|
|
13
|
+
private static readonly IS_PROD: boolean = true;
|
|
14
|
+
|
|
15
|
+
constructor(private router: Router) {}
|
|
16
|
+
|
|
17
|
+
public initialize() {
|
|
18
|
+
this.onRouteChange();
|
|
19
|
+
|
|
20
|
+
// dynamically add analytics scripts to document head
|
|
21
|
+
try {
|
|
22
|
+
const url:string = 'https://www.googletagmanager.com/gtag/js?id=';
|
|
23
|
+
const gTagScript = document.createElement('script');
|
|
24
|
+
gTagScript.async = true;
|
|
25
|
+
const tagId: string = GoogleAnalyticsService.IS_PROD ? 'G-7D5BBK4K8X' : null;
|
|
26
|
+
gTagScript.src = `${url}${tagId}`;
|
|
27
|
+
document.head.appendChild(gTagScript);
|
|
28
|
+
|
|
29
|
+
const dataLayerScript = document.createElement('script');
|
|
30
|
+
dataLayerScript.innerHTML = `
|
|
31
|
+
window.dataLayer = window.dataLayer || [];
|
|
32
|
+
function gtag(){dataLayer.push(arguments);}
|
|
33
|
+
gtag('js', new Date());
|
|
34
|
+
gtag('config', '${tagId}', {'send_page_view': false});`;
|
|
35
|
+
document.head.appendChild(dataLayerScript);
|
|
36
|
+
} catch (e) {
|
|
37
|
+
Logger.error('Error adding Google Analytics', e, e);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// track visited routes
|
|
42
|
+
private onRouteChange() {
|
|
43
|
+
const tagId: string = GoogleAnalyticsService.IS_PROD ? 'G-7D5BBK4K8X' : null;
|
|
44
|
+
|
|
45
|
+
this.router.events.subscribe((event) => {
|
|
46
|
+
if (event instanceof NavigationEnd) {
|
|
47
|
+
gtag('config', tagId, {
|
|
48
|
+
page_path: event.urlAfterRedirects,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
Logger.info('Sending Google Analytics tracking for: ', event.urlAfterRedirects);
|
|
52
|
+
Logger.info('Google Analytics property ID: ', tagId);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// use gtag.js to send Google Analytics Events
|
|
58
|
+
public event(action: string, eventCategory?: string, eventLabel?: string, value?: string) {
|
|
59
|
+
gtag('event', action, {
|
|
60
|
+
...(eventCategory && { event_category: eventCategory }),
|
|
61
|
+
...(eventLabel && { event_label: eventLabel }),
|
|
62
|
+
...(value && { value: value }),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
import { beforeEach, describe, expect, test } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import {GraphqlQueryService} from "./graphql-query.service";
|
|
5
|
+
|
|
6
|
+
describe('GraphqlQueryService', () => {
|
|
7
|
+
let service: GraphqlQueryService;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
TestBed.configureTestingModule({});
|
|
11
|
+
service = TestBed.inject(GraphqlQueryService);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test.skip('should be created', () => {
|
|
15
|
+
expect(service).toBeTruthy();
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { DialogService } from 'primeng/dynamicdialog';
|
|
3
|
+
import { MessageService } from 'primeng/api';
|
|
4
|
+
import { Logger } from '@bitblit/ratchet-common/logger/logger';
|
|
5
|
+
import { GraphqlRatchet } from '@bitblit/ratchet-graphql/graphql/graphql-ratchet';
|
|
6
|
+
import { BlockUiComponent } from "../components/dialogs/block-ui/block-ui.component";
|
|
7
|
+
import {AuthorizationStyle} from "@bitblit/ratchet-graphql/graphql/authorization-style";
|
|
8
|
+
|
|
9
|
+
@Injectable({providedIn: 'root'})
|
|
10
|
+
export class GraphqlQueryService {
|
|
11
|
+
constructor(
|
|
12
|
+
private graphqlRatchet: GraphqlRatchet,
|
|
13
|
+
private dialogService: DialogService,
|
|
14
|
+
private messageService: MessageService,
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
public async executeQuery<T>(queryName: string, variables: any, authStyle: AuthorizationStyle = AuthorizationStyle.TokenRequired
|
|
18
|
+
): Promise<T | null> {
|
|
19
|
+
let rval: T | null = null;
|
|
20
|
+
this.messageService.add({ severity: 'info', summary: 'Running query', detail: queryName, life: 3000 });
|
|
21
|
+
|
|
22
|
+
Logger.info('eq: %j -: %s --: %s ---: %j', queryName, variables);
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
rval = await this.graphqlRatchet.executeQuery<T>(queryName, variables, authStyle);
|
|
26
|
+
} catch (err) {
|
|
27
|
+
Logger.error('Fail : %s', err);
|
|
28
|
+
} finally {
|
|
29
|
+
this.messageService.clear();
|
|
30
|
+
}
|
|
31
|
+
return rval;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public async executeQueryWithBlock<T>(
|
|
35
|
+
blockMessage: string,
|
|
36
|
+
queryName: string,
|
|
37
|
+
variables: any,
|
|
38
|
+
authStyle: AuthorizationStyle = AuthorizationStyle.TokenRequired
|
|
39
|
+
): Promise<T | null> {
|
|
40
|
+
let rval: T | null = null;
|
|
41
|
+
this.messageService.add({ severity: 'info', summary: 'Running query', detail: queryName, life: 3000 });
|
|
42
|
+
|
|
43
|
+
Logger.info('eqb: %j -: %s --: %s ---: %j', blockMessage, queryName, variables);
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
rval = await BlockUiComponent.runPromiseWithUiBlock<T>(
|
|
47
|
+
this.dialogService,
|
|
48
|
+
this.graphqlRatchet.executeQuery<T>(queryName, variables, authStyle),
|
|
49
|
+
blockMessage,
|
|
50
|
+
);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
Logger.error('Fail : %s', err);
|
|
53
|
+
} finally {
|
|
54
|
+
this.messageService.clear();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return rval;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
public async executeMutate<T>(queryName: string, variables: any, authStyle: AuthorizationStyle = AuthorizationStyle.TokenRequired
|
|
62
|
+
): Promise<T | null> {
|
|
63
|
+
let rval: T | null = null;
|
|
64
|
+
this.messageService.add({ severity: 'info', summary: 'Running query', detail: queryName, life: 3000 });
|
|
65
|
+
|
|
66
|
+
Logger.info('eq: %j -: %s --: %s ---: %j', queryName, variables);
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
rval = await this.graphqlRatchet.executeMutate<T>(queryName, variables, authStyle);
|
|
70
|
+
} catch (err) {
|
|
71
|
+
Logger.error('Fail : %s', err);
|
|
72
|
+
} finally {
|
|
73
|
+
this.messageService.clear();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return rval;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public async executeMutateWithBlock<T>(
|
|
80
|
+
blockMessage: string,
|
|
81
|
+
queryName: string,
|
|
82
|
+
variables: any,
|
|
83
|
+
authStyle: AuthorizationStyle = AuthorizationStyle.TokenRequired
|
|
84
|
+
|
|
85
|
+
): Promise<T | null> {
|
|
86
|
+
let rval: T | null = null;
|
|
87
|
+
this.messageService.add({ severity: 'info', summary: 'Running query', detail: queryName, life: 3000 });
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
rval = await BlockUiComponent.runPromiseWithUiBlock<T>(
|
|
91
|
+
this.dialogService,
|
|
92
|
+
this.graphqlRatchet.executeMutate<T>(queryName, variables, authStyle),
|
|
93
|
+
blockMessage,
|
|
94
|
+
);
|
|
95
|
+
} catch (err) {
|
|
96
|
+
Logger.error('Fail : %s', err);
|
|
97
|
+
} finally {
|
|
98
|
+
this.messageService.clear();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return rval;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
import { beforeEach, describe, expect, test } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import {LocalStorageService} from "./local-storage.service";
|
|
5
|
+
|
|
6
|
+
describe('LocalStorageService', () => {
|
|
7
|
+
let service: LocalStorageService<any>;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
TestBed.configureTestingModule({});
|
|
11
|
+
service = TestBed.inject(LocalStorageService);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test.skip('should be created', () => {
|
|
15
|
+
expect(service).toBeTruthy();
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { Logger } from '@bitblit/ratchet-common/logger/logger';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export function storageFinder(): Storage | null {
|
|
6
|
+
if (typeof window !== 'undefined') {
|
|
7
|
+
if (typeof window.localStorage !=='undefined') {
|
|
8
|
+
return window.localStorage;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@Injectable({providedIn: 'root'})
|
|
15
|
+
export class LocalStorageService<T> {
|
|
16
|
+
private static readonly APP_NAME: string = 'Scribe';
|
|
17
|
+
|
|
18
|
+
public get storageReady(): boolean {
|
|
19
|
+
return !!storageFinder();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public clear(): void {
|
|
23
|
+
this.update({ } as T );
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public update(value: T): T {
|
|
27
|
+
if (this.storageReady) {
|
|
28
|
+
const toSave: T = value || ({} as T);
|
|
29
|
+
const saveString: string = JSON.stringify(toSave);
|
|
30
|
+
Logger.info('Updating storage to %s', saveString);
|
|
31
|
+
localStorage.setItem(LocalStorageService.APP_NAME, saveString);
|
|
32
|
+
return toSave;
|
|
33
|
+
} else {
|
|
34
|
+
Logger.info('Skipping update - storage not ready : %j', value);
|
|
35
|
+
return {} as T;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fetch(): T {
|
|
40
|
+
if (this.storageReady) {
|
|
41
|
+
const loadString: string = localStorage.getItem(LocalStorageService.APP_NAME) || '{}';
|
|
42
|
+
const rval: T = JSON.parse(loadString) as T;
|
|
43
|
+
return rval;
|
|
44
|
+
} else {
|
|
45
|
+
Logger.info('Skipping fetch - storage not ready');
|
|
46
|
+
return {} as T;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
import { beforeEach, describe, expect, test } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import {WindowRefService} from "./window-ref.service";
|
|
5
|
+
|
|
6
|
+
describe('WindowRefService', () => {
|
|
7
|
+
let service: WindowRefService;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
TestBed.configureTestingModule({});
|
|
11
|
+
service = TestBed.inject(WindowRefService);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test.skip('should be created', () => {
|
|
15
|
+
expect(service).toBeTruthy();
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {Injectable} from '@angular/core';
|
|
2
|
+
|
|
3
|
+
// Taken from https://juristr.com/blog/2016/09/ng2-get-window-ref/
|
|
4
|
+
// Here to make transition to Angular Universal later easier
|
|
5
|
+
|
|
6
|
+
/* This interface is optional, showing how you can add strong typings for custom globals.
|
|
7
|
+
// Just use "Window" as the type if you don't have custom global stuff
|
|
8
|
+
export interface ICustomWindow extends Window {
|
|
9
|
+
__custom_global_stuff: string;
|
|
10
|
+
} */
|
|
11
|
+
|
|
12
|
+
function getWindow(): any {
|
|
13
|
+
if (typeof window !== 'undefined') {
|
|
14
|
+
return window;
|
|
15
|
+
} else {
|
|
16
|
+
throw new Error('Cannot find window object - running in SSR?');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Injectable({providedIn: 'root'})
|
|
21
|
+
export class WindowRefService {
|
|
22
|
+
public nativeWindow(): Window {
|
|
23
|
+
return getWindow();
|
|
24
|
+
}
|
|
25
|
+
}
|