arrmatura 5.2.0 → 6.2.1

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.
Files changed (110) hide show
  1. package/index.ts +20 -0
  2. package/package.json +14 -44
  3. package/src/core/composition.ts +71 -0
  4. package/src/core/conditionals.ts +80 -0
  5. package/src/core/elementary.ts +40 -0
  6. package/src/core/fragment.ts +21 -0
  7. package/src/core/index.ts +19 -0
  8. package/src/core/iterations.ts +121 -0
  9. package/src/core/root.ts +46 -0
  10. package/src/core/routing.ts +37 -0
  11. package/src/core/selection.ts +57 -0
  12. package/src/core/slot.ts +36 -0
  13. package/src/ctx/Ctx.ts +424 -0
  14. package/src/ctx/CtxNode.ts +159 -0
  15. package/src/utils/compileExpression.ts +126 -0
  16. package/src/utils/stringify.ts +39 -0
  17. package/LICENSE +0 -21
  18. package/README.md +0 -54
  19. package/commons/auth/AuthService.ts +0 -111
  20. package/commons/auth/UserService.ts +0 -57
  21. package/commons/auth/index.ts +0 -5
  22. package/commons/auth/user.xml +0 -64
  23. package/commons/components/buttons.xml +0 -25
  24. package/commons/components/index.ts +0 -13
  25. package/commons/components/inputs.xml +0 -33
  26. package/commons/components/layouts.xml +0 -77
  27. package/commons/components/media.xml +0 -21
  28. package/commons/components/modal.xml +0 -37
  29. package/commons/components/navigation.xml +0 -73
  30. package/commons/components/popups.xml +0 -12
  31. package/commons/components/searchbar.xml +0 -54
  32. package/commons/components/table.xml +0 -140
  33. package/commons/components/toasts.xml +0 -18
  34. package/commons/components/viewport.xml +0 -48
  35. package/commons/forms/FieldItem.xml +0 -20
  36. package/commons/forms/FormController.ts +0 -87
  37. package/commons/forms/Item.ts +0 -132
  38. package/commons/forms/ItemCollectionController.ts +0 -113
  39. package/commons/forms/ItemController.ts +0 -91
  40. package/commons/forms/MultiEnumField.xml +0 -44
  41. package/commons/forms/MultivalueController.ts +0 -49
  42. package/commons/forms/NewItemController.ts +0 -46
  43. package/commons/forms/SmartareaField.xml +0 -51
  44. package/commons/forms/SuggestionController.ts +0 -80
  45. package/commons/forms/SuggestionField.xml +0 -28
  46. package/commons/forms/fields.xml +0 -151
  47. package/commons/forms/form.xml +0 -37
  48. package/commons/forms/index.ts +0 -29
  49. package/commons/index.ts +0 -6
  50. package/commons/services/ApiClientService.ts +0 -32
  51. package/commons/services/ErrorHandlingService.ts +0 -11
  52. package/commons/services/FirebaseService.ts +0 -185
  53. package/commons/services/GSheetsService.ts +0 -120
  54. package/commons/services/HeartbeatService.ts +0 -35
  55. package/commons/services/Invoke.ts +0 -29
  56. package/commons/services/JsonpService.ts +0 -18
  57. package/commons/services/Loader.ts +0 -17
  58. package/commons/services/MetadataService.ts +0 -50
  59. package/commons/services/NavigationService.ts +0 -74
  60. package/commons/services/Service.ts +0 -62
  61. package/commons/services/ServiceWorker.ts +0 -111
  62. package/commons/services/Storage.ts +0 -55
  63. package/commons/services/ToastService.ts +0 -61
  64. package/commons/services/index.ts +0 -13
  65. package/core/Arrmatura.ts +0 -79
  66. package/core/CNode.ts +0 -111
  67. package/core/Component.ts +0 -424
  68. package/core/cnodes/composition.ts +0 -100
  69. package/core/cnodes/conditionals.ts +0 -52
  70. package/core/cnodes/elementary.ts +0 -44
  71. package/core/cnodes/iterations.ts +0 -92
  72. package/core/cnodes/routing.ts +0 -25
  73. package/core/compileNode.ts +0 -39
  74. package/core/expression.ts +0 -73
  75. package/core/index.ts +0 -1
  76. package/core/register.ts +0 -43
  77. package/core/utils.ts +0 -23
  78. package/core-web/WebPlatform.ts +0 -25
  79. package/core-web/attributes.ts +0 -218
  80. package/core-web/elements.ts +0 -81
  81. package/core-web/index.ts +0 -28
  82. package/core-web/reflow.ts +0 -30
  83. package/core-web/support.ts +0 -27
  84. package/core-web/type.ts +0 -18
  85. package/docs/index.js +0 -485
  86. package/lib/array/arrayGroupBy.ts +0 -19
  87. package/lib/array/arraySortBy.ts +0 -49
  88. package/lib/array/arrayToObject.ts +0 -18
  89. package/lib/array/arrayish.ts +0 -7
  90. package/lib/array/index.ts +0 -4
  91. package/lib/crypto/index.ts +0 -25
  92. package/lib/date/index.ts +0 -127
  93. package/lib/func/curry.ts +0 -11
  94. package/lib/func/fx.ts +0 -56
  95. package/lib/func/identity.ts +0 -6
  96. package/lib/func/nextId.ts +0 -9
  97. package/lib/func/noop.ts +0 -6
  98. package/lib/geo/index.js +0 -22
  99. package/lib/index.ts +0 -17
  100. package/lib/object/index.ts +0 -69
  101. package/lib/parsing/codus.ts +0 -25
  102. package/lib/parsing/compiler.ts +0 -26
  103. package/lib/parsing/scalarParse.ts +0 -25
  104. package/lib/parsing/urls.ts +0 -91
  105. package/lib/parsing/xml.ts +0 -117
  106. package/lib/resources/l10n.ts +0 -40
  107. package/lib/resources/resources.ru.ts +0 -20
  108. package/lib/resources/resources.ts +0 -20
  109. package/lib/string/index.ts +0 -58
  110. package/lib/support/createListeners.ts +0 -12
@@ -1,185 +0,0 @@
1
- import { Service } from './Service';
2
-
3
- const unpackDocs = (s) =>
4
- s.docs.reduce((r, e) => {
5
- const d = e.data();
6
- d.id = e.id;
7
- r.push(d);
8
- return r;
9
- }, []);
10
-
11
- const firebase = window.firebase;
12
-
13
- export class FirebaseService {
14
- firestore: any;
15
- auth: any;
16
- providers: { Google: any };
17
-
18
- constructor({ ...config }) {
19
- firebase.initializeApp(config);
20
- this.firestore = firebase.firestore();
21
- this.firestore.enablePersistence({ synchronizeTabs: true }).catch(function (err) {
22
- if (err.code === 'failed-precondition') {
23
- // Multiple tabs open, persistence can only be enabled
24
- // in one tab at a time.
25
- // ...
26
- } else if (err.code === 'unimplemented') {
27
- // The current browser does not support all of the
28
- // features required to enable persistence
29
- // ...
30
- }
31
- });
32
- this.auth = firebase.auth();
33
- this.auth.languageCode = 'by';
34
- this.providers = {
35
- Google: firebase.auth.GoogleAuthProvider,
36
- };
37
- }
38
-
39
- done() {
40
- firebase.app().delete();
41
- }
42
- // auth
43
- signInAnonymously() {
44
- this.auth.signInAnonymously().catch(function (error) {
45
- var errorMessage = error.message;
46
- console.log('signInAnonymously err=' + errorMessage);
47
- });
48
- }
49
- listenUser(cb) {
50
- this.auth.onAuthStateChanged(cb);
51
- }
52
- getCurrentUser() {
53
- return this.auth.currentUser;
54
- }
55
- linkProvider() {
56
- const provider = new this.providers.Google();
57
- provider.addScope('https://www.googleapis.com/auth/contacts.readonly');
58
- return this.auth
59
- .signInWithPopup(provider)
60
- .then((result) => {
61
- // This gives you a Google Access Token. You can use it to access the Google API.
62
- // var token = result.credential.accessToken
63
- // The signed-in user info.
64
- var googleUser = result.user;
65
- var credential = this.auth.GoogleAuthProvider.credential(googleUser.getAuthResponse().id_token);
66
- this.getCurrentUser()
67
- .linkAndRetrieveDataWithCredential(credential)
68
- .then(
69
- function (usercred) {
70
- var user = usercred.user;
71
- console.log('Anonymous account successfully upgraded', user);
72
- },
73
- function (error) {
74
- console.log('Error upgrading anonymous account', error);
75
- }
76
- );
77
- // ...
78
- })
79
- .catch(function (error) {
80
- // Handle Errors here.
81
- // var errorCode = error.code
82
- var errorMessage = error.message;
83
- // The email of the user's account used.
84
- // var email = error.email
85
- // The firebase.auth.AuthCredential type that was used.
86
- // var credential = error.credential
87
- console.log('signInAnonymously err=' + errorMessage);
88
- // ...
89
- });
90
- }
91
- logout() {
92
- return this.signInAnonymously();
93
- }
94
- getCollection(coll, since) {
95
- return ((c) => (since ? c.where('modified_at', '>', since) : c))(this.firestore.collection(coll))
96
- .get()
97
- .then(unpackDocs);
98
- }
99
- // db
100
- listenCollection(coll, ts = 0, cb) {
101
- return ((c) => (ts ? c.where('modified_at', '>', ts) : c))(this.firestore.collection(coll)).onSnapshot(function (
102
- querySnapshot
103
- ) {
104
- var r = [];
105
- querySnapshot.forEach(function (e) {
106
- const d = e.data();
107
- d.id = e.id;
108
- r.push(d);
109
- });
110
- cb(null, { [coll]: r });
111
- });
112
- }
113
- nextId(coll) {
114
- return this.firestore.collection(coll).doc().id;
115
- }
116
- update(delta) {
117
- const now = Date.now().valueOf();
118
- // Get a new write batch
119
- var batch = this.firestore.batch();
120
- Object.keys(delta).forEach((coll) => {
121
- const c = this.firestore.collection(coll);
122
- delta[coll].forEach((d) => {
123
- d.modified_at = now;
124
- if (!d.created_at) {
125
- d.created_at = now;
126
- }
127
- var ref = c.doc('' + d.id);
128
- batch.set(ref, d, { merge: true });
129
- });
130
- });
131
- return batch.commit();
132
- }
133
- }
134
-
135
- export class FirebaseUserService extends Service {
136
- get fb() {
137
- return this.$.app.firebase.impl;
138
- }
139
- init() {
140
- this.fb.listenUser((user) => {
141
- if (user) {
142
- } else {
143
- this.fb.signInAnonymously();
144
- // User is signed out.
145
- // ...
146
- }
147
- this.emit('signed');
148
- });
149
- }
150
- getInfo() {
151
- const user = this.fb.getCurrentUser();
152
- if (user !== null) {
153
- user.providerData.forEach(function (profile) {
154
- // console.log('Sign-in provider: ' + profile.providerId)
155
- // console.log(' Provider-specific UID: ' + profile.uid)
156
- // console.log(' Name: ' + profile.displayName)
157
- // console.log(' Email: ' + profile.email)
158
- // console.log(' Photo URL: ' + profile.photoURL)
159
- });
160
- }
161
- return !user
162
- ? { isLoading: true }
163
- : {
164
- ...user,
165
- isLoading: false,
166
- };
167
- }
168
- onLogin() {
169
- return this.fb.linkProvider();
170
- }
171
- onLogout() {
172
- return this.fb.logout();
173
- }
174
- onSigned() {
175
- return {
176
- _: NaN,
177
- };
178
- }
179
- }
180
-
181
- const hot = typeof module === 'undefined' ? null : module.hot;
182
- if (hot) {
183
- // hot.addStatusHandler(function (d) {})
184
- hot.accept();
185
- }
@@ -1,120 +0,0 @@
1
- import { arrayToObject } from '../../lib';
2
- import { JsonpService } from './JsonpService';
3
- import { Storage } from './Storage';
4
- import { Service } from './Service';
5
-
6
- export class GSheetsService extends Service {
7
- url: string = '';
8
- token: string = '';
9
- kind: string = 'items';
10
- remote = new JsonpService();
11
- persistence: 'local' | 'session' | 'transient' = 'transient';
12
- local?: Storage;
13
-
14
- get items() {
15
- return this.local?.get(this.kind) || null;
16
- }
17
-
18
- set items(items) {
19
- this.local?.set(this.kind, !items ? null : items.filter((e) => !e.deleted && e.status !== 'deleted'));
20
- }
21
-
22
- get since() {
23
- return +this.local?.get(this.kind + '_since') || 0;
24
- }
25
-
26
- set since(s) {
27
- this.local?.set(this.kind + '_since', s || 0);
28
- }
29
-
30
- init() {
31
- this.local = new Storage(this.persistence);
32
- return this.sync();
33
- }
34
-
35
- submit(_data: any): Promise<any> {
36
- throw new Error('Method not implemented.');
37
- }
38
-
39
- sync() {
40
- const promise = this.submit({ path: `?action=items&kind=${this.kind}`, body: { since: String(this.since || 0) } })
41
- .then(({ items, reset, timestamp }) => {
42
- this.log('sync ' + this.kind, timestamp, items?.length);
43
- if (items?.length || !this.since) {
44
- if (!reset) {
45
- const items0 = this.items || [];
46
- items = Object.values({ ...arrayToObject(items0), ...arrayToObject(items) });
47
- }
48
- return { items, isLoading: false, since: timestamp };
49
- }
50
- return { isLoading: false };
51
- })
52
- .catch((error) => {
53
- const message = error?.message || error || 'unknown';
54
- this.toast({ id: message, mode: 'error', message: 'Ошибка: ' + message });
55
- return { isLoading: false, error: message };
56
- });
57
-
58
- return {
59
- isLoading: true,
60
- error: null,
61
- '*items': promise,
62
- };
63
- }
64
-
65
- submitData(data: Delta) {
66
- return {
67
- busy: true,
68
- error: null,
69
- '*upsert': this.submit({ path: `?action=upsert&kind=${this.kind}`, body: data })
70
- .then(({ item }) => {
71
- this.log('update sync' + this.kind, item.id);
72
- return {
73
- busy: false,
74
- lastUpdatedItemId: item.id,
75
- items: [item, ...this.items?.filter((e: Hash) => e.id != item.id)],
76
- };
77
- })
78
- .catch((error) => {
79
- return { busy: false, error };
80
- }),
81
- };
82
- }
83
-
84
- syncItem(data: Delta) {
85
- return {
86
- isItemLoading: true,
87
- error: null,
88
- '*item': this.submit({ path: `?action=item&kind=${this.kind}`, body: data })
89
- .then(({ item }) => {
90
- this.log('sync item' + this.kind, item.id, item);
91
- return {
92
- isItemLoading: false,
93
- lastUpdatedItemId: item.id,
94
- items: [item, ...this.items?.filter((e: Hash) => e.id != item.id)],
95
- };
96
- })
97
- .catch((error) => {
98
- return { isItemLoading: false, error: error };
99
- }),
100
- };
101
- }
102
-
103
- // event handlers:
104
-
105
- onReload() {
106
- return this.sync();
107
- }
108
-
109
- onUpsert(data: Delta) {
110
- return this.submitData(data);
111
- }
112
-
113
- onItem(data: Delta) {
114
- return this.syncItem(data);
115
- }
116
-
117
- onDelete({ id }: Delta) {
118
- return this.submitData({ [String(id)]: { status: 'deleted' } });
119
- }
120
- }
@@ -1,35 +0,0 @@
1
- export class HeartbeatService {
2
- interval: any;
3
- watcher?: Procedure;
4
-
5
- constructor(watcher?: Procedure) {
6
- this.setWatcher(watcher);
7
- }
8
-
9
- setWatcher(watcher?: Procedure) {
10
- this.watcher = watcher;
11
- }
12
-
13
- startWatch() {
14
- if (!this.interval) {
15
- this.interval = setInterval(() => {
16
- this.watcher?.();
17
- }, 1000);
18
- }
19
- }
20
-
21
- stopWatch() {
22
- if (this.interval) {
23
- clearInterval(this.interval);
24
- this.interval = 0;
25
- }
26
- }
27
-
28
- setActive(active: boolean) {
29
- if (!active) {
30
- this.stopWatch();
31
- } else {
32
- this.startWatch();
33
- }
34
- }
35
- }
@@ -1,29 +0,0 @@
1
- export class Invoke {
2
- action?: (d?: Delta) => void;
3
- data?: Delta;
4
- delay = 0;
5
- hot = false;
6
- trigger?: any;
7
-
8
- setTrigger(val: any) {
9
- this.trigger = val;
10
- if (val) {
11
- this.reload();
12
- }
13
- }
14
-
15
- init() {
16
- if (this.hot) {
17
- this.reload();
18
- }
19
- }
20
-
21
- reload() {
22
- setTimeout(() => {
23
- if (!this.isDone) {
24
- console.log(this.data);
25
- this.action?.(this.data);
26
- }
27
- }, (this.delay || 0) * 1000);
28
- }
29
- }
@@ -1,18 +0,0 @@
1
- import { urlAppendParams } from '../../lib';
2
-
3
- let count = 0;
4
-
5
- export class JsonpService {
6
- fetch(url: string) {
7
- return new Promise((resolve, reject) => {
8
- const jsonp: string = 'jsonp_' + ++count;
9
- const a = window.document.createElement('script');
10
- a.async = true;
11
- a.onerror = reject;
12
- a.src = urlAppendParams(url, { jsonp });
13
- window[jsonp] = resolve;
14
- const m = window.document.getElementsByTagName('body')[0];
15
- m?.parentNode?.insertBefore(a, m);
16
- });
17
- }
18
- }
@@ -1,17 +0,0 @@
1
- export class Loader {
2
- init() {
3
- this.reload();
4
- }
5
-
6
- setTrigger(val) {
7
- this.trigger = val;
8
- this.reload();
9
- }
10
-
11
- reload() {
12
- const { from, data, into } = this;
13
- if (from && into) {
14
- from({ data, callback: (error, result) => into({ error, ...result }) });
15
- }
16
- }
17
- }
@@ -1,50 +0,0 @@
1
- import { Storage } from './Storage';
2
- import { Service } from './Service';
3
-
4
- const mergeMeta = (meta: Hash<any>, target: Hash<any>) =>
5
- Object.entries(meta).reduce((res, [key, val]) => {
6
- res[key] = typeof res[key] === 'object' && !Array.isArray(res[key]) ? { ...res[key], ...val } : val;
7
- return res;
8
- }, target);
9
-
10
- const load = (url: string, version: string) =>
11
- fetch(url, {
12
- method: 'POST',
13
- mode: 'cors',
14
- redirect: 'follow',
15
- body: JSON.stringify({ data: { version } }),
16
- }).then((res) => res.json());
17
-
18
- export class MetadataService extends Service {
19
- url: string = '';
20
- version: string = '';
21
- ttl = 24 * 3600000;
22
-
23
- init() {
24
- const local = new Storage('local', this.url.replace(/\//g, '_'));
25
- const meta0 = local.get('$meta') || {};
26
- if (+(meta0?.timestamp || 0) + this.ttl > Date.now()) {
27
- mergeMeta(meta0, this.res(''));
28
- return { ready: true, meta: meta0 };
29
- }
30
- return {
31
- ready: false,
32
- meta: meta0,
33
- error: null,
34
- '*': load(this.url, meta0?.version).then(
35
- (meta2) => {
36
- const isUpdated = meta0?.version !== meta2?.version;
37
- const meta = !isUpdated ? { ...meta0 } : meta2;
38
- meta.timestamp = Date.now();
39
- mergeMeta(meta, this.res(''));
40
- local.set('$meta', meta);
41
- return { ready: true, isUpdated, meta };
42
- },
43
- (error) => {
44
- const message = error?.message || error || 'unknown';
45
- return { ready: true, error: message };
46
- }
47
- ),
48
- };
49
- }
50
- }
@@ -1,74 +0,0 @@
1
- import { urlParse, urlStringify } from '../../lib';
2
- import { Service } from './Service';
3
-
4
- export class NavigationService extends Service {
5
- prevHash: string = '';
6
- host: any;
7
- path: any;
8
- params: any;
9
-
10
- init() {
11
- this.prevHash;
12
- window.addEventListener('hashchange', () => this.hashchange());
13
- setTimeout(() => this.hashchange(), 0);
14
- }
15
-
16
- hashchange() {
17
- const hash = window.location.hash.slice(1);
18
- if (hash[0] === '/' && hash !== this.prevHash) {
19
- this.emit('this.hash', { value: hash.slice(1) });
20
- this.prevHash = hash;
21
- } else if (!this.prevHash) {
22
- this.emit('this.hash', { value: 'main' });
23
- }
24
- }
25
-
26
- done() {
27
- window.removeEventListener('hashchange', this.hashchange);
28
- }
29
-
30
- setTitle(d: string) {
31
- window.document.title = d;
32
- }
33
-
34
- setHash(d) {
35
- const { host, path = ['*'], params } = urlParse('/' + d);
36
- const state = {
37
- host: (!host || host === '*' ? this.host : host) || 'main',
38
- path: path[0] === '*' ? this.path : path,
39
- params: params.reset ? { ...params, reset: null } : { ...this.params, ...params },
40
- };
41
- window.location.hash = this.prevHash = urlStringify(state).slice(1);
42
- this.up(state);
43
- }
44
-
45
- getRoute() {
46
- return {
47
- host: this.host,
48
- path: this.path,
49
- params: this.params,
50
- };
51
- }
52
-
53
- onReload() {
54
- window.location.reload();
55
- }
56
-
57
- onCopyToClipboard({ value }) {
58
- navigator.clipboard.writeText(value).then(
59
- () => {
60
- this.toast('Copied to clipboard');
61
- },
62
- (err) => {
63
- this.toast('Could not copy to clipboard: ' + err.message);
64
- }
65
- );
66
- }
67
-
68
- onHash({ value }) {
69
- this.setHash('/' + value);
70
- }
71
- onParams(params) {
72
- this.setHash({ params: { ...params, data: null } });
73
- }
74
- }
@@ -1,62 +0,0 @@
1
- import { Component } from '../../core/Component';
2
- import { Toast } from './ToastService';
3
-
4
- export class Service {
5
- #$: Component;
6
- state: any;
7
-
8
- constructor(state: unknown, $: Component) {
9
- this.state = state;
10
- this.#$ = $;
11
- }
12
-
13
- /**
14
- * Framework
15
- */
16
- lookupService(ref: string) {
17
- return this.#$.getByRef(ref);
18
- }
19
-
20
- up(d: Delta) {
21
- return this.#$.up(d);
22
- }
23
-
24
- defer(fn: ComponentProcedure) {
25
- return this.#$.defer(fn);
26
- }
27
-
28
- emit(key: string, data: Delta) {
29
- return this.#$?.emit(key, data);
30
- }
31
-
32
- createEmitter(key: string) {
33
- return (data: Delta) => this.emit(key, data);
34
- }
35
-
36
- res(key: string) {
37
- return this.#$.res(key);
38
- }
39
-
40
- log(val: any, ...args: unknown[]) {
41
- return this.#$.log(val, ...args);
42
- }
43
-
44
- /**
45
- * Error handling
46
- */
47
-
48
- handleError({ message = '', code = '' }) {
49
- // may overriden from props
50
- const handler = this.lookupService('errorHandler');
51
- if (handler) {
52
- handler.handleError({ message, code, source: this.#$ });
53
- } else {
54
- console.error(this.#$.ref + ': ERROR: ', message, code);
55
- }
56
- }
57
-
58
- toast(message: string | Partial<Toast> = 'ok') {
59
- // may overriden from props
60
- this.emit('toasters.send', typeof message === 'string' ? { message } : message);
61
- }
62
- }
@@ -1,111 +0,0 @@
1
- import { Service } from './Service';
2
-
3
- export class ServiceWorker extends Service {
4
- get api() {
5
- return navigator.serviceWorker;
6
- }
7
-
8
- init() {
9
- try {
10
- Function.assert(this.api, 'Service Workers are not supported');
11
-
12
- const { source = '/service-worker.js', scope = '/', push } = this;
13
-
14
- this.api
15
- .register(source, { scope })
16
- .then((registration) => this.registered(registration))
17
- .then(() => this.ready(() => this.log('Service Worker Ready')));
18
-
19
- this.api.addEventListener('message', (ev) => this.onMessage(ev));
20
-
21
- if (push) {
22
- this.subscribe();
23
- }
24
- } catch (error) {
25
- this.fallback(error);
26
- }
27
- }
28
-
29
- // ensures that `fn` executed when api is ready
30
- ready(fn) {
31
- return this.api.ready.then(fn);
32
- }
33
-
34
- fallback(error) {
35
- this.log(error);
36
- }
37
-
38
- // hook on registered
39
- registered(registration) {
40
- this.log('Service Worker Registered');
41
- return registration;
42
- }
43
- /**
44
- * Push
45
- */
46
-
47
- withPushManager(fn) {
48
- return this.ready(({ pushManager }) => pushManager).then(fn);
49
- }
50
-
51
- unsubscribe() {
52
- this.withPushManager((pushManager) => pushManager.getSubscription())
53
- .then((ss) => ss && ss.unsubscribe())
54
- .then(() => this.saveSubscription())
55
- .catch(function (e) {
56
- console.log('Error thrown while unsubscribing from push messaging.', e);
57
- });
58
- }
59
-
60
- subscribe() {
61
- function urlBase64ToUint8Array(base64String) {
62
- const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
63
- const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
64
-
65
- const rawData = window.atob(base64);
66
- return Uint8Array.from([...rawData].map((char) => char.charCodeAt(0)));
67
- }
68
- if (Notification.permission === 'granted') {
69
- /* do our magic */
70
- } else if (Notification.permission === 'blocked') {
71
- /* the user has previously denied push. Can't reprompt. */
72
- } else {
73
- /* show a prompt to the user */
74
- }
75
- const applicationServerKey = urlBase64ToUint8Array(this.vapidPublicKey);
76
- this.withPushManager((pushManager) =>
77
- pushManager
78
- .getSubscription()
79
- // .then((ss) => ss && ss.unsubscribe())
80
- .then(
81
- (ss) =>
82
- ss ||
83
- pushManager.subscribe({
84
- userVisibleOnly: true,
85
- applicationServerKey,
86
- })
87
- )
88
- .then((subscription) => this.saveSubscription(subscription.toJSON()))
89
- .catch((err) => {
90
- if (Notification.permission === 'denied') {
91
- this.log('The user has blocked notifications.');
92
- }
93
- this.handleError(err);
94
- })
95
- );
96
- }
97
-
98
- // to be overriden from props
99
- saveSubscription(ss) {
100
- this.subscription = ss;
101
- }
102
-
103
- /**
104
- * Intercommunication between service worker.
105
- */
106
-
107
- // handles a message posted from Service worker.
108
- onMessage(payload) {
109
- this.log('onMessage', payload);
110
- }
111
- }