tiny-essentials 1.11.0 → 1.12.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.
- package/README.md +12 -3
- package/dist/node_modules/firebase-functions/lib/common/trace.cjs +82 -0
- package/dist/node_modules/firebase-functions/lib/logger/common.cjs +57 -0
- package/dist/node_modules/firebase-functions/lib/logger/index.cjs +158 -0
- package/dist/v1/TinyBasicsEs.js +1653 -1
- package/dist/v1/TinyBasicsEs.min.js +1 -1
- package/dist/v1/TinyDragDropDetector.js +307 -0
- package/dist/v1/TinyDragDropDetector.min.js +1 -0
- package/dist/v1/TinyDragger.js +3668 -0
- package/dist/v1/TinyDragger.min.js +2 -0
- package/dist/v1/TinyDragger.min.js.LICENSE.txt +8 -0
- package/dist/v1/TinyEssentials.js +2888 -2
- package/dist/v1/TinyEssentials.min.js +1 -1
- package/dist/v1/TinyNotifyCenter.js +32 -0
- package/dist/v1/TinyNotifyCenter.min.js +1 -1
- package/dist/v1/TinyToastNotify.js +24 -0
- package/dist/v1/TinyToastNotify.min.js +1 -1
- package/dist/v1/TinyUploadClicker.js +5340 -0
- package/dist/v1/TinyUploadClicker.min.js +2 -0
- package/dist/v1/TinyUploadClicker.min.js.LICENSE.txt +8 -0
- package/dist/v1/basics/fileManager.cjs +524 -0
- package/dist/v1/basics/fileManager.d.mts +209 -0
- package/dist/v1/basics/fileManager.mjs +443 -0
- package/dist/v1/basics/fullScreen.cjs +134 -0
- package/dist/v1/basics/fullScreen.d.mts +8 -0
- package/dist/v1/basics/fullScreen.mjs +121 -0
- package/dist/v1/basics/html.cjs +262 -0
- package/dist/v1/basics/html.d.mts +63 -0
- package/dist/v1/basics/html.mjs +208 -0
- package/dist/v1/basics/index.cjs +40 -0
- package/dist/v1/basics/index.d.mts +38 -1
- package/dist/v1/basics/index.mjs +4 -1
- package/dist/v1/build/TinyDragDropDetector.cjs +7 -0
- package/dist/v1/build/TinyDragDropDetector.d.mts +3 -0
- package/dist/v1/build/TinyDragDropDetector.mjs +2 -0
- package/dist/v1/build/TinyDragger.cjs +7 -0
- package/dist/v1/build/TinyDragger.d.mts +3 -0
- package/dist/v1/build/TinyDragger.mjs +2 -0
- package/dist/v1/build/TinyUploadClicker.cjs +7 -0
- package/dist/v1/build/TinyUploadClicker.d.mts +3 -0
- package/dist/v1/build/TinyUploadClicker.mjs +2 -0
- package/dist/v1/css/TinyDraggerExample.css +21 -0
- package/dist/v1/css/TinyDraggerExample.min.css +1 -0
- package/dist/v1/index.cjs +44 -0
- package/dist/v1/index.d.mts +40 -1
- package/dist/v1/index.mjs +6 -1
- package/dist/v1/libs/TinyDragDropDetector.cjs +268 -0
- package/dist/v1/libs/TinyDragDropDetector.d.mts +123 -0
- package/dist/v1/libs/TinyDragDropDetector.mjs +228 -0
- package/dist/v1/libs/TinyDragger.cjs +906 -0
- package/dist/v1/libs/TinyDragger.d.mts +316 -0
- package/dist/v1/libs/TinyDragger.mjs +783 -0
- package/dist/v1/libs/TinyNotifyCenter.cjs +32 -0
- package/dist/v1/libs/TinyNotifyCenter.d.mts +9 -0
- package/dist/v1/libs/TinyNotifyCenter.mjs +28 -0
- package/dist/v1/libs/TinyToastNotify.cjs +24 -0
- package/dist/v1/libs/TinyToastNotify.d.mts +8 -0
- package/dist/v1/libs/TinyToastNotify.mjs +20 -0
- package/dist/v1/libs/TinyUploadClicker.cjs +223 -0
- package/dist/v1/libs/TinyUploadClicker.d.mts +80 -0
- package/dist/v1/libs/TinyUploadClicker.mjs +182 -0
- package/docs/v1/README.md +8 -2
- package/docs/v1/basics/fileManager.md +222 -0
- package/docs/v1/basics/fullScreen.md +183 -0
- package/docs/v1/basics/html.md +243 -0
- package/docs/v1/libs/TinyDragDropDetector.md +143 -0
- package/docs/v1/libs/TinyDragger.md +430 -0
- package/docs/v1/libs/TinyLevelUp.md +1 -1
- package/docs/v1/libs/TinyNotifyCenter.md +20 -0
- package/docs/v1/libs/TinyToastNotify.md +19 -0
- package/docs/v1/libs/TinyUploadClicker.md +108 -0
- package/package.json +12 -2
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks if the document is currently in fullscreen mode.
|
|
5
|
+
*
|
|
6
|
+
* @returns {boolean}
|
|
7
|
+
*/
|
|
8
|
+
const documentIsFullScreen = () =>
|
|
9
|
+
!!(
|
|
10
|
+
document.fullscreenElement ||
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
document.webkitFullscreenElement ||
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
document.mozFullScreenElement ||
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
document.msFullscreenElement ||
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
document.webkitIsFullScreen ||
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
document.mozFullScreen
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Checks if the window occupies the entire screen dimensions.
|
|
25
|
+
*
|
|
26
|
+
* @returns {boolean}
|
|
27
|
+
*/
|
|
28
|
+
const isScreenFilled = () =>
|
|
29
|
+
window.innerHeight === screen.height && window.innerWidth === screen.width;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Checks if fullscreen mode is active either via document API or by matching screen dimensions.
|
|
33
|
+
*
|
|
34
|
+
* @returns {boolean}
|
|
35
|
+
*/
|
|
36
|
+
const isFullScreenMode = () => documentIsFullScreen() || isScreenFilled();
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Requests fullscreen mode for the document.
|
|
40
|
+
*
|
|
41
|
+
* @param {FullscreenOptions} [ops]
|
|
42
|
+
* @returns {Promise<void>}
|
|
43
|
+
*/
|
|
44
|
+
const requestFullScreen = (ops) =>
|
|
45
|
+
new Promise(async (resolve, reject) => {
|
|
46
|
+
const docElm = document.documentElement;
|
|
47
|
+
try {
|
|
48
|
+
if (docElm.requestFullscreen) {
|
|
49
|
+
await docElm.requestFullscreen(ops);
|
|
50
|
+
// @ts-ignore
|
|
51
|
+
} else if (docElm.mozRequestFullScreen) {
|
|
52
|
+
// @ts-ignore
|
|
53
|
+
docElm.mozRequestFullScreen(ops);
|
|
54
|
+
// @ts-ignore
|
|
55
|
+
} else if (docElm.webkitRequestFullScreen) {
|
|
56
|
+
// @ts-ignore
|
|
57
|
+
docElm.webkitRequestFullScreen(ops);
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
} else if (docElm.msRequestFullscreen) {
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
docElm.msRequestFullscreen(ops);
|
|
62
|
+
}
|
|
63
|
+
resolve();
|
|
64
|
+
} catch (err) {
|
|
65
|
+
reject(err);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Exits fullscreen mode.
|
|
71
|
+
*
|
|
72
|
+
* @returns {Promise<void>}
|
|
73
|
+
*/
|
|
74
|
+
const exitFullScreen = () =>
|
|
75
|
+
new Promise((resolve, reject) => {
|
|
76
|
+
if (document.exitFullscreen) {
|
|
77
|
+
document.exitFullscreen().then(resolve).catch(reject);
|
|
78
|
+
} else {
|
|
79
|
+
try {
|
|
80
|
+
// @ts-ignore
|
|
81
|
+
if (document.mozCancelFullScreen) document.mozCancelFullScreen();
|
|
82
|
+
// @ts-ignore
|
|
83
|
+
else if (document.webkitCancelFullScreen) document.webkitCancelFullScreen();
|
|
84
|
+
// @ts-ignore
|
|
85
|
+
else if (document.msExitFullscreen) document.msExitFullscreen();
|
|
86
|
+
else throw new Error('Fullscreen API is not supported');
|
|
87
|
+
resolve();
|
|
88
|
+
} catch (err) {
|
|
89
|
+
reject(err);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
/** @type {readonly string[]} */
|
|
95
|
+
const fullScreenEvents = [
|
|
96
|
+
'fullscreenchange',
|
|
97
|
+
'webkitfullscreenchange',
|
|
98
|
+
'mozfullscreenchange',
|
|
99
|
+
'MSFullscreenChange',
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Attaches a listener to fullscreen change events.
|
|
104
|
+
*
|
|
105
|
+
* @param {EventListenerOrEventListenerObject} listener
|
|
106
|
+
* @param {boolean|AddEventListenerOptions} [ops]
|
|
107
|
+
* @returns {void}
|
|
108
|
+
*/
|
|
109
|
+
const onFullScreenChange = (listener, ops) => {
|
|
110
|
+
fullScreenEvents.forEach((event) => {
|
|
111
|
+
document.addEventListener(event, listener, ops);
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Removes a listener from fullscreen change events.
|
|
117
|
+
*
|
|
118
|
+
* @param {EventListenerOrEventListenerObject} listener
|
|
119
|
+
* @param {boolean|AddEventListenerOptions} [ops]
|
|
120
|
+
* @returns {void}
|
|
121
|
+
*/
|
|
122
|
+
const offFullScreenChange = (listener, ops) => {
|
|
123
|
+
fullScreenEvents.forEach((event) => {
|
|
124
|
+
document.removeEventListener(event, listener, ops);
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
exports.documentIsFullScreen = documentIsFullScreen;
|
|
129
|
+
exports.exitFullScreen = exitFullScreen;
|
|
130
|
+
exports.isFullScreenMode = isFullScreenMode;
|
|
131
|
+
exports.isScreenFilled = isScreenFilled;
|
|
132
|
+
exports.offFullScreenChange = offFullScreenChange;
|
|
133
|
+
exports.onFullScreenChange = onFullScreenChange;
|
|
134
|
+
exports.requestFullScreen = requestFullScreen;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function documentIsFullScreen(): boolean;
|
|
2
|
+
export function isScreenFilled(): boolean;
|
|
3
|
+
export function isFullScreenMode(): boolean;
|
|
4
|
+
export function requestFullScreen(ops?: FullscreenOptions): Promise<void>;
|
|
5
|
+
export function exitFullScreen(): Promise<void>;
|
|
6
|
+
export function onFullScreenChange(listener: EventListenerOrEventListenerObject, ops?: boolean | AddEventListenerOptions): void;
|
|
7
|
+
export function offFullScreenChange(listener: EventListenerOrEventListenerObject, ops?: boolean | AddEventListenerOptions): void;
|
|
8
|
+
//# sourceMappingURL=fullScreen.d.mts.map
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if the document is currently in fullscreen mode.
|
|
3
|
+
*
|
|
4
|
+
* @returns {boolean}
|
|
5
|
+
*/
|
|
6
|
+
export const documentIsFullScreen = () => !!(document.fullscreenElement ||
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
document.webkitFullscreenElement ||
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
document.mozFullScreenElement ||
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
document.msFullscreenElement ||
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
document.webkitIsFullScreen ||
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
document.mozFullScreen);
|
|
17
|
+
/**
|
|
18
|
+
* Checks if the window occupies the entire screen dimensions.
|
|
19
|
+
*
|
|
20
|
+
* @returns {boolean}
|
|
21
|
+
*/
|
|
22
|
+
export const isScreenFilled = () => window.innerHeight === screen.height && window.innerWidth === screen.width;
|
|
23
|
+
/**
|
|
24
|
+
* Checks if fullscreen mode is active either via document API or by matching screen dimensions.
|
|
25
|
+
*
|
|
26
|
+
* @returns {boolean}
|
|
27
|
+
*/
|
|
28
|
+
export const isFullScreenMode = () => documentIsFullScreen() || isScreenFilled();
|
|
29
|
+
/**
|
|
30
|
+
* Requests fullscreen mode for the document.
|
|
31
|
+
*
|
|
32
|
+
* @param {FullscreenOptions} [ops]
|
|
33
|
+
* @returns {Promise<void>}
|
|
34
|
+
*/
|
|
35
|
+
export const requestFullScreen = (ops) => new Promise(async (resolve, reject) => {
|
|
36
|
+
const docElm = document.documentElement;
|
|
37
|
+
try {
|
|
38
|
+
if (docElm.requestFullscreen) {
|
|
39
|
+
await docElm.requestFullscreen(ops);
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
}
|
|
42
|
+
else if (docElm.mozRequestFullScreen) {
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
docElm.mozRequestFullScreen(ops);
|
|
45
|
+
// @ts-ignore
|
|
46
|
+
}
|
|
47
|
+
else if (docElm.webkitRequestFullScreen) {
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
docElm.webkitRequestFullScreen(ops);
|
|
50
|
+
// @ts-ignore
|
|
51
|
+
}
|
|
52
|
+
else if (docElm.msRequestFullscreen) {
|
|
53
|
+
// @ts-ignore
|
|
54
|
+
docElm.msRequestFullscreen(ops);
|
|
55
|
+
}
|
|
56
|
+
resolve();
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
reject(err);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* Exits fullscreen mode.
|
|
64
|
+
*
|
|
65
|
+
* @returns {Promise<void>}
|
|
66
|
+
*/
|
|
67
|
+
export const exitFullScreen = () => new Promise((resolve, reject) => {
|
|
68
|
+
if (document.exitFullscreen) {
|
|
69
|
+
document.exitFullscreen().then(resolve).catch(reject);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
try {
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
if (document.mozCancelFullScreen)
|
|
75
|
+
document.mozCancelFullScreen();
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
else if (document.webkitCancelFullScreen)
|
|
78
|
+
document.webkitCancelFullScreen();
|
|
79
|
+
// @ts-ignore
|
|
80
|
+
else if (document.msExitFullscreen)
|
|
81
|
+
document.msExitFullscreen();
|
|
82
|
+
else
|
|
83
|
+
throw new Error('Fullscreen API is not supported');
|
|
84
|
+
resolve();
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
reject(err);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
/** @type {readonly string[]} */
|
|
92
|
+
const fullScreenEvents = [
|
|
93
|
+
'fullscreenchange',
|
|
94
|
+
'webkitfullscreenchange',
|
|
95
|
+
'mozfullscreenchange',
|
|
96
|
+
'MSFullscreenChange',
|
|
97
|
+
];
|
|
98
|
+
/**
|
|
99
|
+
* Attaches a listener to fullscreen change events.
|
|
100
|
+
*
|
|
101
|
+
* @param {EventListenerOrEventListenerObject} listener
|
|
102
|
+
* @param {boolean|AddEventListenerOptions} [ops]
|
|
103
|
+
* @returns {void}
|
|
104
|
+
*/
|
|
105
|
+
export const onFullScreenChange = (listener, ops) => {
|
|
106
|
+
fullScreenEvents.forEach((event) => {
|
|
107
|
+
document.addEventListener(event, listener, ops);
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Removes a listener from fullscreen change events.
|
|
112
|
+
*
|
|
113
|
+
* @param {EventListenerOrEventListenerObject} listener
|
|
114
|
+
* @param {boolean|AddEventListenerOptions} [ops]
|
|
115
|
+
* @returns {void}
|
|
116
|
+
*/
|
|
117
|
+
export const offFullScreenChange = (listener, ops) => {
|
|
118
|
+
fullScreenEvents.forEach((event) => {
|
|
119
|
+
document.removeEventListener(event, listener, ops);
|
|
120
|
+
});
|
|
121
|
+
};
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var objFilter = require('./objFilter.cjs');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Checks if two DOM elements are colliding on the screen.
|
|
7
|
+
*
|
|
8
|
+
* @param {Element} elem1 - First DOM element.
|
|
9
|
+
* @param {Element} elem2 - Second DOM element.
|
|
10
|
+
* @returns {boolean} - Returns true if the elements are colliding.
|
|
11
|
+
*/
|
|
12
|
+
function areHtmlElsColliding(elem1, elem2) {
|
|
13
|
+
const rect1 = elem1.getBoundingClientRect();
|
|
14
|
+
const rect2 = elem2.getBoundingClientRect();
|
|
15
|
+
|
|
16
|
+
return !(
|
|
17
|
+
rect1.right < rect2.left ||
|
|
18
|
+
rect1.left > rect2.right ||
|
|
19
|
+
rect1.bottom < rect2.top ||
|
|
20
|
+
rect1.top > rect2.bottom
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Reads and parses a JSON data using FileReader.
|
|
26
|
+
* Throws an error if the content is not valid JSON.
|
|
27
|
+
* @param {File} file
|
|
28
|
+
* @returns {Promise<any>}
|
|
29
|
+
*/
|
|
30
|
+
function readJsonBlob(file) {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
const reader = new FileReader();
|
|
33
|
+
|
|
34
|
+
reader.onload = () => {
|
|
35
|
+
try {
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
const result = JSON.parse(reader.result);
|
|
38
|
+
resolve(result);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
reject(new Error(`Invalid JSON in file: ${file.name}\n${error.message}`));
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
reader.onerror = () => {
|
|
46
|
+
reject(new Error(`Error reading file: ${file.name}`));
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
reader.readAsText(file);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Saves a JSON object as a downloadable file.
|
|
55
|
+
* @param {string} filename
|
|
56
|
+
* @param {any} data
|
|
57
|
+
* @param {number} [spaces=2]
|
|
58
|
+
*/
|
|
59
|
+
function saveJsonFile(filename, data, spaces = 2) {
|
|
60
|
+
const json = JSON.stringify(data, null, spaces);
|
|
61
|
+
const blob = new Blob([json], { type: 'application/json' });
|
|
62
|
+
const url = URL.createObjectURL(blob);
|
|
63
|
+
|
|
64
|
+
const link = document.createElement('a');
|
|
65
|
+
link.href = url;
|
|
66
|
+
link.download = filename;
|
|
67
|
+
|
|
68
|
+
document.body.appendChild(link);
|
|
69
|
+
link.click();
|
|
70
|
+
document.body.removeChild(link);
|
|
71
|
+
|
|
72
|
+
URL.revokeObjectURL(url);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Loads and parses a JSON from a remote URL using Fetch API.
|
|
77
|
+
*
|
|
78
|
+
* @param {string} url - The full URL to fetch JSON from.
|
|
79
|
+
* @param {Object} [options] - Optional settings.
|
|
80
|
+
* @param {string} [options.method="GET"] - HTTP method to use (GET, POST, etc.).
|
|
81
|
+
* @param {any} [options.body] - Request body (only for methods like POST, PUT).
|
|
82
|
+
* @param {number} [options.timeout=0] - Timeout in milliseconds (ignored if signal is provided).
|
|
83
|
+
* @param {number} [options.retries=0] - Number of retry attempts (ignored if signal is provided).
|
|
84
|
+
* @param {Headers|Record<string, *>} [options.headers={}] - Additional headers.
|
|
85
|
+
* @param {AbortSignal|null} [options.signal] - External AbortSignal; disables timeout and retries.
|
|
86
|
+
* @returns {Promise<*>} Parsed JSON object.
|
|
87
|
+
* @throws {Error} Throws if fetch fails, times out, or returns invalid JSON.
|
|
88
|
+
*/
|
|
89
|
+
async function fetchJson(
|
|
90
|
+
url,
|
|
91
|
+
{ method = 'GET', body, timeout = 0, retries = 0, headers = {}, signal = null } = {},
|
|
92
|
+
) {
|
|
93
|
+
if (
|
|
94
|
+
typeof url !== 'string' ||
|
|
95
|
+
(!url.startsWith('../') &&
|
|
96
|
+
!url.startsWith('./') &&
|
|
97
|
+
!url.startsWith('/') &&
|
|
98
|
+
!url.startsWith('https://') &&
|
|
99
|
+
!url.startsWith('http://'))
|
|
100
|
+
)
|
|
101
|
+
throw new Error('Invalid URL: must be a valid http or https address.');
|
|
102
|
+
|
|
103
|
+
if (typeof method !== 'string' || !method.trim())
|
|
104
|
+
throw new Error('Invalid method: must be a non-empty string.');
|
|
105
|
+
|
|
106
|
+
if (!signal) {
|
|
107
|
+
if (
|
|
108
|
+
typeof timeout !== 'number' ||
|
|
109
|
+
!Number.isFinite(timeout) ||
|
|
110
|
+
Number.isNaN(timeout) ||
|
|
111
|
+
timeout < 0
|
|
112
|
+
)
|
|
113
|
+
throw new Error('Invalid timeout: must be a positive number.');
|
|
114
|
+
|
|
115
|
+
if (
|
|
116
|
+
typeof retries !== 'number' ||
|
|
117
|
+
!Number.isFinite(retries) ||
|
|
118
|
+
Number.isNaN(retries) ||
|
|
119
|
+
retries < 0
|
|
120
|
+
)
|
|
121
|
+
throw new Error('Invalid retries: must be a positive number.');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const attempts = signal ? 1 : retries + 1;
|
|
125
|
+
/** @type {Error|null} */
|
|
126
|
+
let lastError = null;
|
|
127
|
+
|
|
128
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
129
|
+
const controller = signal ? null : new AbortController();
|
|
130
|
+
const localSignal = signal || (controller?.signal ?? null);
|
|
131
|
+
const timer =
|
|
132
|
+
!signal && timeout && controller ? setTimeout(() => controller.abort(), timeout) : null;
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const response = await fetch(url, {
|
|
136
|
+
method: method.toUpperCase(),
|
|
137
|
+
headers: {
|
|
138
|
+
Accept: 'application/json',
|
|
139
|
+
...headers,
|
|
140
|
+
},
|
|
141
|
+
body: body !== undefined ? (objFilter.isJsonObject(body) ? JSON.stringify(body) : body) : undefined,
|
|
142
|
+
signal: localSignal,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
if (timer) clearTimeout(timer);
|
|
146
|
+
|
|
147
|
+
if (!response.ok) throw new Error(`HTTP error: ${response.status} ${response.statusText}`);
|
|
148
|
+
|
|
149
|
+
const contentType = response.headers.get('content-type') || '';
|
|
150
|
+
if (!contentType.includes('application/json'))
|
|
151
|
+
throw new Error(`Unexpected content-type: ${contentType}`);
|
|
152
|
+
|
|
153
|
+
const data = await response.json();
|
|
154
|
+
|
|
155
|
+
if (!objFilter.isJsonObject(data)) throw new Error('Received invalid data instead of valid JSON.');
|
|
156
|
+
|
|
157
|
+
return data;
|
|
158
|
+
} catch (err) {
|
|
159
|
+
lastError = /** @type {Error} */ (err);
|
|
160
|
+
if (signal) break; // if an external signal came, it does not retry
|
|
161
|
+
if (attempt < retries)
|
|
162
|
+
await new Promise((resolve) => setTimeout(resolve, 300 * (attempt + 1)));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
throw new Error(
|
|
167
|
+
`Failed to fetch JSON from "${url}"${lastError ? `: ${lastError.message}` : '.'}`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @typedef {Object} HtmlElBoxSides
|
|
173
|
+
* @property {number} x - Total horizontal size (left + right)
|
|
174
|
+
* @property {number} y - Total vertical size (top + bottom)
|
|
175
|
+
* @property {number} left
|
|
176
|
+
* @property {number} right
|
|
177
|
+
* @property {number} top
|
|
178
|
+
* @property {number} bottom
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Returns the total border width and individual sides from `border{Side}Width` CSS properties.
|
|
183
|
+
*
|
|
184
|
+
* @param {Element} el - The target DOM element.
|
|
185
|
+
* @returns {HtmlElBoxSides} - Total horizontal (x) and vertical (y) border widths, and each side individually.
|
|
186
|
+
*/
|
|
187
|
+
const getHtmlElBordersWidth = (el) => {
|
|
188
|
+
const styles = getComputedStyle(el);
|
|
189
|
+
const left = parseFloat(styles.borderLeftWidth) || 0;
|
|
190
|
+
const right = parseFloat(styles.borderRightWidth) || 0;
|
|
191
|
+
const top = parseFloat(styles.borderTopWidth) || 0;
|
|
192
|
+
const bottom = parseFloat(styles.borderBottomWidth) || 0;
|
|
193
|
+
const x = left + right;
|
|
194
|
+
const y = top + bottom;
|
|
195
|
+
|
|
196
|
+
return { x, y, left, right, top, bottom };
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Returns the total border size and individual sides from `border{Side}` CSS properties.
|
|
201
|
+
*
|
|
202
|
+
* @param {Element} el - The target DOM element.
|
|
203
|
+
* @returns {HtmlElBoxSides} - Total horizontal (x) and vertical (y) border sizes, and each side individually.
|
|
204
|
+
*/
|
|
205
|
+
const getHtmlElBorders = (el) => {
|
|
206
|
+
const styles = getComputedStyle(el);
|
|
207
|
+
const left = parseFloat(styles.borderLeft) || 0;
|
|
208
|
+
const right = parseFloat(styles.borderRight) || 0;
|
|
209
|
+
const top = parseFloat(styles.borderTop) || 0;
|
|
210
|
+
const bottom = parseFloat(styles.borderBottom) || 0;
|
|
211
|
+
const x = left + right;
|
|
212
|
+
const y = top + bottom;
|
|
213
|
+
|
|
214
|
+
return { x, y, left, right, top, bottom };
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Returns the total margin and individual sides from `margin{Side}` CSS properties.
|
|
219
|
+
*
|
|
220
|
+
* @param {Element} el - The target DOM element.
|
|
221
|
+
* @returns {HtmlElBoxSides} - Total horizontal (x) and vertical (y) margins, and each side individually.
|
|
222
|
+
*/
|
|
223
|
+
const getHtmlElMargin = (el) => {
|
|
224
|
+
const styles = getComputedStyle(el);
|
|
225
|
+
const left = parseFloat(styles.marginLeft) || 0;
|
|
226
|
+
const right = parseFloat(styles.marginRight) || 0;
|
|
227
|
+
const top = parseFloat(styles.marginTop) || 0;
|
|
228
|
+
const bottom = parseFloat(styles.marginBottom) || 0;
|
|
229
|
+
|
|
230
|
+
const x = left + right;
|
|
231
|
+
const y = top + bottom;
|
|
232
|
+
|
|
233
|
+
return { x, y, left, right, top, bottom };
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Returns the total padding and individual sides from `padding{Side}` CSS properties.
|
|
238
|
+
*
|
|
239
|
+
* @param {Element} el - The target DOM element.
|
|
240
|
+
* @returns {HtmlElBoxSides} - Total horizontal (x) and vertical (y) paddings, and each side individually.
|
|
241
|
+
*/
|
|
242
|
+
const getHtmlElPadding = (el) => {
|
|
243
|
+
const styles = getComputedStyle(el);
|
|
244
|
+
const left = parseFloat(styles.paddingLeft) || 0;
|
|
245
|
+
const right = parseFloat(styles.paddingRight) || 0;
|
|
246
|
+
const top = parseFloat(styles.paddingTop) || 0;
|
|
247
|
+
const bottom = parseFloat(styles.paddingBottom) || 0;
|
|
248
|
+
|
|
249
|
+
const x = left + right;
|
|
250
|
+
const y = top + bottom;
|
|
251
|
+
|
|
252
|
+
return { x, y, left, right, top, bottom };
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
exports.areHtmlElsColliding = areHtmlElsColliding;
|
|
256
|
+
exports.fetchJson = fetchJson;
|
|
257
|
+
exports.getHtmlElBorders = getHtmlElBorders;
|
|
258
|
+
exports.getHtmlElBordersWidth = getHtmlElBordersWidth;
|
|
259
|
+
exports.getHtmlElMargin = getHtmlElMargin;
|
|
260
|
+
exports.getHtmlElPadding = getHtmlElPadding;
|
|
261
|
+
exports.readJsonBlob = readJsonBlob;
|
|
262
|
+
exports.saveJsonFile = saveJsonFile;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if two DOM elements are colliding on the screen.
|
|
3
|
+
*
|
|
4
|
+
* @param {Element} elem1 - First DOM element.
|
|
5
|
+
* @param {Element} elem2 - Second DOM element.
|
|
6
|
+
* @returns {boolean} - Returns true if the elements are colliding.
|
|
7
|
+
*/
|
|
8
|
+
export function areHtmlElsColliding(elem1: Element, elem2: Element): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Reads and parses a JSON data using FileReader.
|
|
11
|
+
* Throws an error if the content is not valid JSON.
|
|
12
|
+
* @param {File} file
|
|
13
|
+
* @returns {Promise<any>}
|
|
14
|
+
*/
|
|
15
|
+
export function readJsonBlob(file: File): Promise<any>;
|
|
16
|
+
/**
|
|
17
|
+
* Saves a JSON object as a downloadable file.
|
|
18
|
+
* @param {string} filename
|
|
19
|
+
* @param {any} data
|
|
20
|
+
* @param {number} [spaces=2]
|
|
21
|
+
*/
|
|
22
|
+
export function saveJsonFile(filename: string, data: any, spaces?: number): void;
|
|
23
|
+
/**
|
|
24
|
+
* Loads and parses a JSON from a remote URL using Fetch API.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} url - The full URL to fetch JSON from.
|
|
27
|
+
* @param {Object} [options] - Optional settings.
|
|
28
|
+
* @param {string} [options.method="GET"] - HTTP method to use (GET, POST, etc.).
|
|
29
|
+
* @param {any} [options.body] - Request body (only for methods like POST, PUT).
|
|
30
|
+
* @param {number} [options.timeout=0] - Timeout in milliseconds (ignored if signal is provided).
|
|
31
|
+
* @param {number} [options.retries=0] - Number of retry attempts (ignored if signal is provided).
|
|
32
|
+
* @param {Headers|Record<string, *>} [options.headers={}] - Additional headers.
|
|
33
|
+
* @param {AbortSignal|null} [options.signal] - External AbortSignal; disables timeout and retries.
|
|
34
|
+
* @returns {Promise<*>} Parsed JSON object.
|
|
35
|
+
* @throws {Error} Throws if fetch fails, times out, or returns invalid JSON.
|
|
36
|
+
*/
|
|
37
|
+
export function fetchJson(url: string, { method, body, timeout, retries, headers, signal }?: {
|
|
38
|
+
method?: string | undefined;
|
|
39
|
+
body?: any;
|
|
40
|
+
timeout?: number | undefined;
|
|
41
|
+
retries?: number | undefined;
|
|
42
|
+
headers?: Headers | Record<string, any> | undefined;
|
|
43
|
+
signal?: AbortSignal | null | undefined;
|
|
44
|
+
}): Promise<any>;
|
|
45
|
+
export function getHtmlElBordersWidth(el: Element): HtmlElBoxSides;
|
|
46
|
+
export function getHtmlElBorders(el: Element): HtmlElBoxSides;
|
|
47
|
+
export function getHtmlElMargin(el: Element): HtmlElBoxSides;
|
|
48
|
+
export function getHtmlElPadding(el: Element): HtmlElBoxSides;
|
|
49
|
+
export type HtmlElBoxSides = {
|
|
50
|
+
/**
|
|
51
|
+
* - Total horizontal size (left + right)
|
|
52
|
+
*/
|
|
53
|
+
x: number;
|
|
54
|
+
/**
|
|
55
|
+
* - Total vertical size (top + bottom)
|
|
56
|
+
*/
|
|
57
|
+
y: number;
|
|
58
|
+
left: number;
|
|
59
|
+
right: number;
|
|
60
|
+
top: number;
|
|
61
|
+
bottom: number;
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=html.d.mts.map
|