@akc42/app-utils 3.1.5

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/dom-host.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ @licence
3
+ Copyright (c) 2020 Alan Chandler, all rights reserved
4
+
5
+ This file is part of @akc42/app-utils.
6
+
7
+ @akc42/app-utils is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ @akc42/app-utils is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with @akc42/app-utils. If not, see <http://www.gnu.org/licenses/>.
19
+ */
20
+
21
+
22
+
23
+ function domHost(self) {
24
+ let parent = self.parentNode;
25
+ while (parent && parent.nodeType !== 11) {
26
+ parent = parent.parentNode; //work up the hierarchy
27
+ }
28
+
29
+ return parent ? parent.host : self;
30
+ }
31
+ export default domHost;
@@ -0,0 +1,99 @@
1
+ /**
2
+ @licence
3
+ Copyright (c) 2020 Alan Chandler, all rights reserved
4
+
5
+ This file is part of @akc42/app-utils.
6
+
7
+ @akc42/app-utils is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ @akc42/app-utils is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with @akc42/app-utils. If not, see <http://www.gnu.org/licenses/>.
19
+ */
20
+
21
+ let master = false;
22
+ let masterResolver;
23
+ let masterPromise = new Promise(resolve => masterResolver = resolve);
24
+
25
+
26
+ let otherTabs = new Set();
27
+ let timer = 0.
28
+ const tabId = Date.now().toString();
29
+ const storageHandler = (e) => {
30
+ if (e.key === 'pageOpen') {
31
+ otherTabs.add(localStorage.getItem('pageOpen'))
32
+ localStorage.setItem('pageAvailable', tabId); //respond - so the ender knows he is not master.
33
+ }
34
+ if (e.key === 'pageAvailable') {
35
+ if (timer > 0) {
36
+ clearTimeout(timer);
37
+ master = false;
38
+ masterResolver(false);
39
+ }
40
+ }
41
+ if (e.key === 'pageClose') {
42
+ const closer = JSON.parse(localStorage.getItem('pageClose'));
43
+ if (master) {
44
+ otherTabs.delete(closer.id);
45
+ } else {
46
+ if (closer.master) {
47
+ otherTabs = new Set(closer.list); //Make a set from the list the closing master had
48
+ otherTabs.delete(tabId); //remove self
49
+ masterPromise = new Promise(resolve => masterResolver = resolve);
50
+
51
+ if (closer.size === 1) {
52
+ //must be just me left, so I become master
53
+ master = true;
54
+ masterResolver(true);
55
+ } else {
56
+ //We need to wait a random time before trying to become master, but
57
+ timer = setTimeout(() => {
58
+ timer = setTimeout(() => {
59
+ master = true;
60
+ masterResolver(true);
61
+ }, 70); //wait 70 ms to see if our claim was refuted
62
+ localStorage.setItem('pageClaim', tabId); //try and claim storage
63
+ }, 70 * Math.floor((Math.random() * 40))); //wait random time between 70ms and about 3 seconds before trying to claim master
64
+ }
65
+ window.dispatchEvent(new CustomEvent('master-close', { composed: true, bubbles: true }));
66
+ }
67
+ }
68
+ }
69
+ if (e.key === 'pageClaim') {
70
+ if (timer > 0) {
71
+ clearTimeout(timer); //someone else has claimed master ship, kill of our attempt;
72
+ master = false;
73
+ masterResolver(false);
74
+ }
75
+ }
76
+ }
77
+
78
+ window.addEventListener('storage', storageHandler);
79
+ const unloadHandler = () => {
80
+ localStorage.setItem('pageClose', JSON.stringify({
81
+ master: master,
82
+ id: tabId,
83
+ size: otherTabs.size,
84
+ list: Array.from(otherTabs)
85
+ }));
86
+ window.removeEventListener('storage', storageHandler);
87
+ window.removeEventListener('beforeunload', unloadHandler);
88
+ };
89
+ window.addEventListener('unload', unloadHandler);
90
+ timer = setTimeout(() => {
91
+ timer = 0; //prevent our assertion being overridden by a later try
92
+ master = true;
93
+ masterResolver(true);
94
+ }, 70);
95
+ localStorage.setItem('pageOpen', tabId);
96
+ function getPromise() {
97
+ return masterPromise;
98
+ };
99
+ export default getPromise;
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@akc42/app-utils",
3
+ "version": "3.1.5",
4
+ "description": "General Utilities for SPAs",
5
+ "exports": {
6
+ ".": "./*.js"
7
+ },
8
+ "scripts": {
9
+ "test": "echo \"Error: no test specified\" && exit 1"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/akc42/app-utils.git"
14
+ },
15
+ "keywords": [
16
+ "utilities"
17
+ ],
18
+ "author": "Alan Chandler",
19
+ "license": "GPL-3.0-or-later",
20
+ "bugs": {
21
+ "url": "https://github.com/akc42/app-utils/issues"
22
+ },
23
+ "homepage": "https://github.com/akc42/app-utils#readme"
24
+ }
package/pdf.js ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ @licence
3
+ Copyright (c) 2021 Alan Chandler, all rights reserved
4
+
5
+ This file is part of @akc42/app-utils.
6
+
7
+ @akc42/app-utils is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ @akc42/app-utils is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with @akc42/app-utils. If not, see <http://www.gnu.org/licenses/>.
19
+ */
20
+ import api from './post-api.js';
21
+ export default (url,params) => {
22
+ api(`pdf/${url}`,params,true);
23
+ }
package/post-api.js ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ @licence
3
+ Copyright (c) 2020 Alan Chandler, all rights reserved
4
+
5
+ This file is part of @akc42/app-utils.
6
+
7
+ @akc42/app-utils is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ @akc42/app-utils is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with @akc42/app-utils. If not, see <http://www.gnu.org/licenses/>.
19
+ */
20
+
21
+
22
+ export default async function api(url, params, blob, signal) {
23
+ const options = {
24
+ credentials: 'same-origin',
25
+ method: 'post',
26
+ headers: new Headers({
27
+ 'content-type': 'application/json'
28
+ }),
29
+ body: JSON.stringify(params ?? {})
30
+ };
31
+ if (signal) options.signal = signal;
32
+ let text;
33
+ try {
34
+ const response = await window.fetch('/api/' + url, options);
35
+ if (!response.ok) throw new CustomEvent('api-error', {composed: true, bubbles: true , detail:response.status});
36
+ if (blob) {
37
+ text = '---502---'; //Simulate a 502 (bad gateway) incase there is an error in following.
38
+ const b = await response.blob();
39
+ window.open(
40
+ URL.createObjectURL(b),
41
+ '_blank',
42
+ 'chrome=yes,centerscreen,resizable,scrollbars,status,height=800,width=800');
43
+ return {};
44
+ } else {
45
+ text = await response.text();
46
+ if (text.length > 0) return JSON.parse(text);
47
+ return {};
48
+ }
49
+ } catch (err) {
50
+ if (err.type === 'api-error') throw err; //just throw whatever error we had
51
+ //we failed to parse the json - the actual code should be in the text near the end;
52
+ throw new CustomEvent('api-error', { composed: true, bubbles: true, detail: parseInt((text?? '---502---').substr(-6, 3), 10) });
53
+ }
54
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ @licence
3
+ Copyright (c) 2020 Alan Chandler, all rights reserved
4
+
5
+ This file is part of @akc42/app-utils.
6
+
7
+ @akc42/app-utils is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ @akc42/app-utils is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with @akc42/app-utils. If not, see <http://www.gnu.org/licenses/>.
19
+ */
20
+
21
+ //handle the on submit event from a form and make it an api call
22
+
23
+ import api from './post-api.js';
24
+
25
+ function checkNode(node, params) {
26
+
27
+ if (node.localName === 'input' || node.localName === 'select') {
28
+ if (node.type === 'radio' || node.type === 'checkbox') {
29
+ if (node.name !== undefined && node.value !== undefined && node.checked) params[node.name] = node.value;
30
+ return true;
31
+ }
32
+ if (node.name !== undefined && node.value !== undefined) params[node.name] = node.value;
33
+ return node.checkValidity() && node.dispatchEvent(new CustomEvent('validity-check', { bubbles: true, cancelable: true, composed: true, detail: node.value }));
34
+ }
35
+ if (node.localName === 'slot') {
36
+ const assignedNodes = node.assignedNodes();
37
+ if (assignedNodes.length > 0) {
38
+ //we have assigned nodes, so ignore the slots children
39
+ return assignedNodes.filter(n => n.nodeType === Node.ELEMENT_NODE).reduce((a, n) => checkNode(n, params) && a, true);
40
+ }
41
+ }
42
+ //even if node validator fails we want to carry on because the checkValidity calls will trigger the error messages.
43
+ if (customElements.get(node.localName)) {
44
+ /*
45
+ ignore the children of custom element, they will get picked up as a slot, or we don't care because it is pretending
46
+ itself to be an input element and so (if it needs it) it will have a checkValidity Function - and if it does that will
47
+ dispatch the 'validity check' event
48
+ */
49
+ if (node.name !== undefined && node.value !== undefined) {
50
+ params[node.name] = node.value;
51
+ if (typeof node.checkValidity === 'function') {
52
+ return node.checkValidity();
53
+ }
54
+ return node.dispatchEvent(new CustomEvent('validity-check', { bubbles: true, cancelable: true, composed: true, detail: node.value }));
55
+ }
56
+ return checkLevel(node.shadowRoot, params);
57
+ }
58
+
59
+ if (node.children.length > 0) return checkLevel(node, params);
60
+ return true
61
+ }
62
+
63
+ function checkLevel(target, params) {
64
+ return Array.prototype.filter.call(target.children, n => n.nodeType === Node.ELEMENT_NODE).reduce((acc, node) => checkNode(node, params) && acc, true);
65
+ }
66
+
67
+ export default function submit(e) {
68
+ let target;
69
+ if (e.currentTarget) {
70
+ e.stopPropagation();
71
+ e.preventDefault();
72
+ target = e.currentTarget;
73
+ } else {
74
+ target = e;
75
+ }
76
+ const params = {};
77
+ if (checkLevel(target, params)) {
78
+ const action = target.getAttribute('action')
79
+ if (target.dispatchEvent(new CustomEvent('form-submitting', { cancelable:true, composed: true, bubbles: true, detail: params}))) {
80
+ document.body.dispatchEvent(new CustomEvent('wait-request', {detail: true }));
81
+ api(action, params).then(response => {
82
+ document.body.dispatchEvent(new CustomEvent('wait-request', {detail: false }));
83
+ target.dispatchEvent(new CustomEvent('form-response', { composed: true, bubbles: true, detail: response }));
84
+ });
85
+ }
86
+ return params;
87
+ } else {
88
+ target.dispatchEvent(new CustomEvent('form-response', { composed: true, bubbles: true, detail: null }));
89
+ return false;
90
+ }
91
+ }
package/switch-path.js ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ @licence
3
+ Copyright (c) 2020 Alan Chandler, all rights reserved
4
+
5
+ This file is part of @akc42/app-utils.
6
+
7
+ @akc42/app-utils is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ @akc42/app-utils is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with @akc42/app-utils. If not, see <http://www.gnu.org/licenses/>.
19
+ */
20
+
21
+ export function generateUri(path, params) {
22
+ var str = [];
23
+ if (params) {
24
+ for (var param in params) {
25
+ //eslint-disable-next-line no-prototype-builtins
26
+ if (params.hasOwnProperty(param)) {
27
+ str.push(encodeURIComponent(param) + '=' + encodeURIComponent(params[param]));
28
+ }
29
+ }
30
+ if (str.length > 0) {
31
+ return path + '?' + str.join('&');
32
+ }
33
+ }
34
+ return path;
35
+ }
36
+
37
+ export function switchPath(path, params) {
38
+ history.pushState({}, null, generateUri(path, params));
39
+ window.dispatchEvent(new CustomEvent('location-altered', { composed: true, bubbles: true }));
40
+ }
41
+ export default switchPath;
42
+