@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/LICENSE +674 -0
- package/README.md +172 -0
- package/app-keys.js +294 -0
- package/config-promise.js +72 -0
- package/csv.js +37 -0
- package/debug.js +109 -0
- package/dom-host.js +31 -0
- package/master-tab-promise.js +99 -0
- package/package.json +24 -0
- package/pdf.js +23 -0
- package/post-api.js +54 -0
- package/submit-function.js +91 -0
- package/switch-path.js +42 -0
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
|
+
|