tiny-essentials 1.17.1 → 1.18.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/dist/legacy/get/countObj.cjs +2 -2
- package/dist/legacy/get/countObj.d.mts +1 -1
- package/dist/legacy/get/countObj.mjs +1 -1
- package/dist/legacy/index.cjs +2 -1
- package/dist/v1/TinyBasicsEs.js +559 -411
- package/dist/v1/TinyBasicsEs.min.js +1 -1
- package/dist/v1/TinyClipboard.js +459 -0
- package/dist/v1/TinyClipboard.min.js +1 -0
- package/dist/v1/TinyDragger.js +170 -2454
- package/dist/v1/TinyDragger.min.js +1 -2
- package/dist/v1/TinyEssentials.js +1093 -63
- package/dist/v1/TinyEssentials.min.js +1 -1
- package/dist/v1/TinyHtml.js +164 -21
- package/dist/v1/TinyHtml.min.js +1 -1
- package/dist/v1/TinySmartScroller.js +164 -21
- package/dist/v1/TinySmartScroller.min.js +1 -1
- package/dist/v1/TinyTextRangeEditor.js +497 -0
- package/dist/v1/TinyTextRangeEditor.min.js +1 -0
- package/dist/v1/TinyUploadClicker.js +219 -467
- package/dist/v1/TinyUploadClicker.min.js +1 -1
- package/dist/v1/basics/html.cjs +3 -3
- package/dist/v1/basics/html.mjs +1 -1
- package/dist/v1/basics/index.cjs +3 -2
- package/dist/v1/basics/index.d.mts +2 -2
- package/dist/v1/basics/index.mjs +2 -1
- package/dist/v1/basics/objChecker.cjs +46 -0
- package/dist/v1/basics/objChecker.d.mts +29 -0
- package/dist/v1/basics/objChecker.mjs +45 -0
- package/dist/v1/basics/objFilter.cjs +4 -45
- package/dist/v1/basics/objFilter.d.mts +3 -28
- package/dist/v1/basics/objFilter.mjs +2 -45
- package/dist/v1/build/TinyClipboard.cjs +7 -0
- package/dist/v1/build/TinyClipboard.d.mts +3 -0
- package/dist/v1/build/TinyClipboard.mjs +2 -0
- package/dist/v1/build/TinyTextRangeEditor.cjs +7 -0
- package/dist/v1/build/TinyTextRangeEditor.d.mts +3 -0
- package/dist/v1/build/TinyTextRangeEditor.mjs +2 -0
- package/dist/v1/index.cjs +7 -2
- package/dist/v1/index.d.mts +5 -3
- package/dist/v1/index.mjs +5 -2
- package/dist/v1/libs/TinyClipboard.cjs +420 -0
- package/dist/v1/libs/TinyClipboard.d.mts +155 -0
- package/dist/v1/libs/TinyClipboard.mjs +398 -0
- package/dist/v1/libs/TinyDragger.cjs +3 -3
- package/dist/v1/libs/TinyDragger.mjs +1 -1
- package/dist/v1/libs/TinyHtml.cjs +164 -21
- package/dist/v1/libs/TinyHtml.d.mts +150 -27
- package/dist/v1/libs/TinyHtml.mjs +158 -20
- package/dist/v1/libs/TinyTextRangeEditor.cjs +458 -0
- package/dist/v1/libs/TinyTextRangeEditor.d.mts +200 -0
- package/dist/v1/libs/TinyTextRangeEditor.mjs +424 -0
- package/dist/v1/libs/TinyUploadClicker.cjs +5 -4
- package/docs/v1/README.md +3 -0
- package/docs/v1/basics/objChecker.md +47 -0
- package/docs/v1/basics/objFilter.md +0 -40
- package/docs/v1/libs/TinyClipboard.md +213 -0
- package/docs/v1/libs/TinyHtml.md +112 -15
- package/docs/v1/libs/TinyTextRangeEditor.md +208 -0
- package/package.json +1 -1
- package/dist/v1/TinyDragger.min.js.LICENSE.txt +0 -8
|
@@ -2912,9 +2912,55 @@ __webpack_require__.d(collision_namespaceObject, {
|
|
|
2912
2912
|
|
|
2913
2913
|
// EXTERNAL MODULE: ./node_modules/buffer/index.js
|
|
2914
2914
|
var buffer = __webpack_require__(287);
|
|
2915
|
+
;// ./src/v1/basics/objChecker.mjs
|
|
2916
|
+
/**
|
|
2917
|
+
* Counts the number of elements in an array or the number of properties in an object.
|
|
2918
|
+
*
|
|
2919
|
+
* @param {Array<*>|Record<string | number | symbol, any>} obj - The array or object to count.
|
|
2920
|
+
* @returns {number} - The count of items (array elements or object keys), or `0` if the input is neither an array nor an object.
|
|
2921
|
+
*
|
|
2922
|
+
* @example
|
|
2923
|
+
* countObj([1, 2, 3]); // 3
|
|
2924
|
+
* countObj({ a: 1, b: 2 }); // 2
|
|
2925
|
+
* countObj('not an object'); // 0
|
|
2926
|
+
*/
|
|
2927
|
+
function countObj(obj) {
|
|
2928
|
+
// Is Array
|
|
2929
|
+
if (Array.isArray(obj)) return obj.length;
|
|
2930
|
+
// Object
|
|
2931
|
+
if (isJsonObject(obj)) return Object.keys(obj).length;
|
|
2932
|
+
// Nothing
|
|
2933
|
+
return 0;
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
/**
|
|
2937
|
+
* Determines whether a given value is a pure JSON object (plain object).
|
|
2938
|
+
*
|
|
2939
|
+
* A pure object satisfies the following:
|
|
2940
|
+
* - It is not null.
|
|
2941
|
+
* - Its type is "object".
|
|
2942
|
+
* - Its internal [[Class]] is "[object Object]".
|
|
2943
|
+
* - It is not an instance of built-in types like Array, Date, Map, Set, etc.
|
|
2944
|
+
*
|
|
2945
|
+
* This function is useful for strict data validation when you want to ensure
|
|
2946
|
+
* a value is a clean JSON-compatible object, free of class instances or special types.
|
|
2947
|
+
*
|
|
2948
|
+
* @param {unknown} value - The value to test.
|
|
2949
|
+
* @returns {value is Record<string | number | symbol, unknown>} Returns true if the value is a pure object.
|
|
2950
|
+
*/
|
|
2951
|
+
function isJsonObject(value) {
|
|
2952
|
+
if (value === null || typeof value !== 'object') return false;
|
|
2953
|
+
if (Array.isArray(value)) return false;
|
|
2954
|
+
if (Object.prototype.toString.call(value) !== '[object Object]') return false;
|
|
2955
|
+
return true;
|
|
2956
|
+
}
|
|
2957
|
+
|
|
2915
2958
|
;// ./src/v1/basics/objFilter.mjs
|
|
2916
2959
|
|
|
2917
2960
|
|
|
2961
|
+
|
|
2962
|
+
|
|
2963
|
+
|
|
2918
2964
|
const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
|
2919
2965
|
|
|
2920
2966
|
/**
|
|
@@ -3107,48 +3153,6 @@ function getCheckObj() {
|
|
|
3107
3153
|
return Object.fromEntries(Object.entries(typeValidator.items).map(([key, fn]) => [key, fn]));
|
|
3108
3154
|
}
|
|
3109
3155
|
|
|
3110
|
-
/**
|
|
3111
|
-
* Counts the number of elements in an array or the number of properties in an object.
|
|
3112
|
-
*
|
|
3113
|
-
* @param {Array<*>|Record<string|number, any>} obj - The array or object to count.
|
|
3114
|
-
* @returns {number} - The count of items (array elements or object keys), or `0` if the input is neither an array nor an object.
|
|
3115
|
-
*
|
|
3116
|
-
* @example
|
|
3117
|
-
* countObj([1, 2, 3]); // 3
|
|
3118
|
-
* countObj({ a: 1, b: 2 }); // 2
|
|
3119
|
-
* countObj('not an object'); // 0
|
|
3120
|
-
*/
|
|
3121
|
-
function countObj(obj) {
|
|
3122
|
-
// Is Array
|
|
3123
|
-
if (Array.isArray(obj)) return obj.length;
|
|
3124
|
-
// Object
|
|
3125
|
-
if (objType(obj, 'object')) return Object.keys(obj).length;
|
|
3126
|
-
// Nothing
|
|
3127
|
-
return 0;
|
|
3128
|
-
}
|
|
3129
|
-
|
|
3130
|
-
/**
|
|
3131
|
-
* Determines whether a given value is a pure JSON object (plain object).
|
|
3132
|
-
*
|
|
3133
|
-
* A pure object satisfies the following:
|
|
3134
|
-
* - It is not null.
|
|
3135
|
-
* - Its type is "object".
|
|
3136
|
-
* - Its internal [[Class]] is "[object Object]".
|
|
3137
|
-
* - It is not an instance of built-in types like Array, Date, Map, Set, etc.
|
|
3138
|
-
*
|
|
3139
|
-
* This function is useful for strict data validation when you want to ensure
|
|
3140
|
-
* a value is a clean JSON-compatible object, free of class instances or special types.
|
|
3141
|
-
*
|
|
3142
|
-
* @param {unknown} value - The value to test.
|
|
3143
|
-
* @returns {value is Record<string | number | symbol, unknown>} Returns true if the value is a pure object.
|
|
3144
|
-
*/
|
|
3145
|
-
function objFilter_isJsonObject(value) {
|
|
3146
|
-
if (value === null || typeof value !== 'object') return false;
|
|
3147
|
-
if (Array.isArray(value)) return false;
|
|
3148
|
-
if (Object.prototype.toString.call(value) !== '[object Object]') return false;
|
|
3149
|
-
return true;
|
|
3150
|
-
}
|
|
3151
|
-
|
|
3152
3156
|
// Insert obj types
|
|
3153
3157
|
|
|
3154
3158
|
extendObjType([
|
|
@@ -3271,7 +3275,7 @@ extendObjType([
|
|
|
3271
3275
|
[
|
|
3272
3276
|
'object',
|
|
3273
3277
|
/** @param {*} val @returns {val is Record<string | number | symbol, unknown>} */
|
|
3274
|
-
(val) =>
|
|
3278
|
+
(val) => isJsonObject(val),
|
|
3275
3279
|
],
|
|
3276
3280
|
]);
|
|
3277
3281
|
|
|
@@ -3471,404 +3475,6 @@ class ColorSafeStringify {
|
|
|
3471
3475
|
|
|
3472
3476
|
/* harmony default export */ const libs_ColorSafeStringify = ((/* unused pure expression or super */ null && (ColorSafeStringify)));
|
|
3473
3477
|
|
|
3474
|
-
;// ./src/v1/basics/html.mjs
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
/////////////////////////////////////////////////////////////////
|
|
3478
|
-
|
|
3479
|
-
/**
|
|
3480
|
-
* Reads the contents of a file using the specified FileReader method.
|
|
3481
|
-
*
|
|
3482
|
-
* @param {File} file - The file to be read.
|
|
3483
|
-
* @param {'readAsArrayBuffer'|'readAsDataURL'|'readAsText'|'readAsBinaryString'} method -
|
|
3484
|
-
* The FileReader method to use for reading the file.
|
|
3485
|
-
* @returns {Promise<any>} - A promise that resolves with the file content, according to the chosen method.
|
|
3486
|
-
* @throws {Error} - If an unexpected error occurs while handling the result.
|
|
3487
|
-
* @throws {DOMException} - If the FileReader encounters an error while reading the file.
|
|
3488
|
-
*/
|
|
3489
|
-
function readFileBlob(file, method) {
|
|
3490
|
-
return new Promise((resolve, reject) => {
|
|
3491
|
-
const reader = new FileReader();
|
|
3492
|
-
reader.onload = () => {
|
|
3493
|
-
try {
|
|
3494
|
-
resolve(reader.result);
|
|
3495
|
-
} catch (error) {
|
|
3496
|
-
reject(error);
|
|
3497
|
-
}
|
|
3498
|
-
};
|
|
3499
|
-
reader.onerror = () => {
|
|
3500
|
-
reject(reader.error);
|
|
3501
|
-
};
|
|
3502
|
-
reader[method](file);
|
|
3503
|
-
});
|
|
3504
|
-
}
|
|
3505
|
-
|
|
3506
|
-
/**
|
|
3507
|
-
* Reads a file as a Base64 string using FileReader, and optionally formats it as a full data URL.
|
|
3508
|
-
*
|
|
3509
|
-
* Performs strict validation to ensure the result is a valid Base64 string or a proper data URL.
|
|
3510
|
-
*
|
|
3511
|
-
* @param {File} file - The file to be read.
|
|
3512
|
-
* @param {boolean|string} [isDataUrl=false] - If true, returns a full data URL; if false, returns only the Base64 string;
|
|
3513
|
-
* if a string is passed, it is used as the MIME type in the data URL.
|
|
3514
|
-
* @returns {Promise<string>} - A promise that resolves with the Base64 string or data URL.
|
|
3515
|
-
*
|
|
3516
|
-
* @throws {TypeError} - If the result is not a string or if `isDataUrl` is not a valid type.
|
|
3517
|
-
* @throws {Error} - If the result does not match the expected data URL format or Base64 structure.
|
|
3518
|
-
* @throws {DOMException} - If the FileReader fails to read the file.
|
|
3519
|
-
*/
|
|
3520
|
-
function readBase64Blob(file, isDataUrl = false) {
|
|
3521
|
-
return new Promise((resolve, reject) => {
|
|
3522
|
-
if (typeof isDataUrl !== 'string' && typeof isDataUrl !== 'boolean')
|
|
3523
|
-
reject(new TypeError('The isDataUrl parameter must be a boolean or a string.'));
|
|
3524
|
-
readFileBlob(file, 'readAsDataURL')
|
|
3525
|
-
.then(
|
|
3526
|
-
/**
|
|
3527
|
-
* Ensure that the URL format is correct in the required pattern
|
|
3528
|
-
* @param {string} base64Data
|
|
3529
|
-
*/ (base64Data) => {
|
|
3530
|
-
if (typeof base64Data !== 'string')
|
|
3531
|
-
throw new TypeError('Expected file content to be a string.');
|
|
3532
|
-
|
|
3533
|
-
const match = base64Data.match(/^data:(.+);base64,(.*)$/);
|
|
3534
|
-
if (!match || !match[2])
|
|
3535
|
-
throw new Error('Invalid data URL format or missing Base64 content.');
|
|
3536
|
-
const [, mimeType, base64] = match;
|
|
3537
|
-
if (!/^[\w/+]+=*$/.test(base64)) throw new Error('Base64 content is malformed.');
|
|
3538
|
-
|
|
3539
|
-
if (typeof isDataUrl === 'boolean') return resolve(isDataUrl ? base64Data : base64);
|
|
3540
|
-
if (!/^[\w-]+\/[\w.+-]+$/.test(isDataUrl))
|
|
3541
|
-
throw new Error(`Invalid MIME type string: ${isDataUrl}`);
|
|
3542
|
-
|
|
3543
|
-
return resolve(`data:${isDataUrl};base64,${base64}`);
|
|
3544
|
-
},
|
|
3545
|
-
)
|
|
3546
|
-
.catch(reject);
|
|
3547
|
-
});
|
|
3548
|
-
}
|
|
3549
|
-
|
|
3550
|
-
/**
|
|
3551
|
-
* Reads a file and strictly validates its content as proper JSON using FileReader.
|
|
3552
|
-
*
|
|
3553
|
-
* Performs several checks to ensure the file contains valid, parsable JSON data.
|
|
3554
|
-
*
|
|
3555
|
-
* @param {File} file - The file to be read. It must contain valid JSON as plain text.
|
|
3556
|
-
* @returns {Promise<Record<string|number|symbol, any>|any[]>} - A promise that resolves with the parsed JSON object.
|
|
3557
|
-
*
|
|
3558
|
-
* @throws {SyntaxError} - If the file content is not valid JSON syntax.
|
|
3559
|
-
* @throws {TypeError} - If the result is not a string or does not represent a JSON value.
|
|
3560
|
-
* @throws {Error} - If the result is empty or structurally invalid as JSON.
|
|
3561
|
-
* @throws {DOMException} - If the FileReader fails to read the file.
|
|
3562
|
-
*/
|
|
3563
|
-
function readJsonBlob(file) {
|
|
3564
|
-
return new Promise((resolve, reject) =>
|
|
3565
|
-
readFileBlob(file, 'readAsText')
|
|
3566
|
-
.then((data) => {
|
|
3567
|
-
if (typeof data !== 'string') throw new TypeError('Expected file content to be a string.');
|
|
3568
|
-
const trimmed = data.trim();
|
|
3569
|
-
if (trimmed.length === 0) throw new Error('File is empty or contains only whitespace.');
|
|
3570
|
-
const parsed = JSON.parse(trimmed);
|
|
3571
|
-
if (typeof parsed !== 'object' || parsed === null)
|
|
3572
|
-
throw new Error('Parsed content is not a valid JSON object or array.');
|
|
3573
|
-
resolve(parsed);
|
|
3574
|
-
})
|
|
3575
|
-
.catch(reject),
|
|
3576
|
-
);
|
|
3577
|
-
}
|
|
3578
|
-
|
|
3579
|
-
/**
|
|
3580
|
-
* Saves a JSON object as a downloadable file.
|
|
3581
|
-
* @param {string} filename
|
|
3582
|
-
* @param {any} data
|
|
3583
|
-
* @param {number} [spaces=2]
|
|
3584
|
-
*/
|
|
3585
|
-
function saveJsonFile(filename, data, spaces = 2) {
|
|
3586
|
-
const json = JSON.stringify(data, null, spaces);
|
|
3587
|
-
const blob = new Blob([json], { type: 'application/json' });
|
|
3588
|
-
const url = URL.createObjectURL(blob);
|
|
3589
|
-
|
|
3590
|
-
const link = document.createElement('a');
|
|
3591
|
-
link.href = url;
|
|
3592
|
-
link.download = filename;
|
|
3593
|
-
|
|
3594
|
-
document.body.appendChild(link);
|
|
3595
|
-
link.click();
|
|
3596
|
-
document.body.removeChild(link);
|
|
3597
|
-
|
|
3598
|
-
URL.revokeObjectURL(url);
|
|
3599
|
-
}
|
|
3600
|
-
|
|
3601
|
-
/**
|
|
3602
|
-
* @typedef {Object} FetchTemplateOptions
|
|
3603
|
-
* @property {string} [method="GET"] - HTTP method to use (GET, POST, etc.).
|
|
3604
|
-
* @property {any} [body] - Request body (only for methods like POST, PUT).
|
|
3605
|
-
* @property {number} [timeout=0] - Timeout in milliseconds (ignored if signal is provided).
|
|
3606
|
-
* @property {number} [retries=0] - Number of retry attempts (ignored if signal is provided).
|
|
3607
|
-
* @property {Headers|Record<string, *>} [headers={}] - Additional headers.
|
|
3608
|
-
* @property {AbortSignal|null} [signal] - External AbortSignal; disables timeout and retries.
|
|
3609
|
-
*/
|
|
3610
|
-
|
|
3611
|
-
/**
|
|
3612
|
-
* @param {string} url - The full URL to fetch data from.
|
|
3613
|
-
* @param {FetchTemplateOptions} [options] - Optional settings.
|
|
3614
|
-
* @returns {Promise<Response>} Result data.
|
|
3615
|
-
* @throws {Error} Throws if fetch fails, times out.
|
|
3616
|
-
*/
|
|
3617
|
-
async function fetchTemplate(
|
|
3618
|
-
url,
|
|
3619
|
-
{ method = 'GET', body, timeout = 0, retries = 0, headers = {}, signal = null } = {},
|
|
3620
|
-
) {
|
|
3621
|
-
if (
|
|
3622
|
-
typeof url !== 'string' ||
|
|
3623
|
-
(!url.startsWith('../') &&
|
|
3624
|
-
!url.startsWith('./') &&
|
|
3625
|
-
!url.startsWith('/') &&
|
|
3626
|
-
!url.startsWith('https://') &&
|
|
3627
|
-
!url.startsWith('http://'))
|
|
3628
|
-
)
|
|
3629
|
-
throw new Error('Invalid URL: must be a valid http or https address.');
|
|
3630
|
-
|
|
3631
|
-
if (typeof method !== 'string' || !method.trim())
|
|
3632
|
-
throw new Error('Invalid method: must be a non-empty string.');
|
|
3633
|
-
|
|
3634
|
-
if (!signal) {
|
|
3635
|
-
if (
|
|
3636
|
-
typeof timeout !== 'number' ||
|
|
3637
|
-
!Number.isFinite(timeout) ||
|
|
3638
|
-
Number.isNaN(timeout) ||
|
|
3639
|
-
timeout < 0
|
|
3640
|
-
)
|
|
3641
|
-
throw new Error('Invalid timeout: must be a positive number.');
|
|
3642
|
-
|
|
3643
|
-
if (
|
|
3644
|
-
typeof retries !== 'number' ||
|
|
3645
|
-
!Number.isFinite(retries) ||
|
|
3646
|
-
Number.isNaN(retries) ||
|
|
3647
|
-
retries < 0
|
|
3648
|
-
)
|
|
3649
|
-
throw new Error('Invalid retries: must be a positive number.');
|
|
3650
|
-
}
|
|
3651
|
-
|
|
3652
|
-
const attempts = signal ? 1 : retries + 1;
|
|
3653
|
-
/** @type {Error|null} */
|
|
3654
|
-
let lastError = null;
|
|
3655
|
-
|
|
3656
|
-
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
3657
|
-
const controller = signal ? null : new AbortController();
|
|
3658
|
-
const localSignal = signal || (controller?.signal ?? null);
|
|
3659
|
-
const timer =
|
|
3660
|
-
!signal && timeout && controller ? setTimeout(() => controller.abort(), timeout) : null;
|
|
3661
|
-
|
|
3662
|
-
try {
|
|
3663
|
-
const response = await fetch(url, {
|
|
3664
|
-
method: method.toUpperCase(),
|
|
3665
|
-
headers: {
|
|
3666
|
-
Accept: 'application/json',
|
|
3667
|
-
...headers,
|
|
3668
|
-
},
|
|
3669
|
-
body: body !== undefined ? (isJsonObject(body) ? JSON.stringify(body) : body) : undefined,
|
|
3670
|
-
signal: localSignal,
|
|
3671
|
-
});
|
|
3672
|
-
|
|
3673
|
-
if (timer) clearTimeout(timer);
|
|
3674
|
-
|
|
3675
|
-
if (!response.ok) throw new Error(`HTTP error: ${response.status} ${response.statusText}`);
|
|
3676
|
-
return response;
|
|
3677
|
-
} catch (err) {
|
|
3678
|
-
lastError = /** @type {Error} */ (err);
|
|
3679
|
-
if (signal) break; // if an external signal came, it does not retry
|
|
3680
|
-
if (attempt < retries)
|
|
3681
|
-
await new Promise((resolve) => setTimeout(resolve, 300 * (attempt + 1)));
|
|
3682
|
-
}
|
|
3683
|
-
}
|
|
3684
|
-
|
|
3685
|
-
throw new Error(
|
|
3686
|
-
`Failed to fetch JSON from "${url}"${lastError ? `: ${lastError.message}` : '.'}`,
|
|
3687
|
-
);
|
|
3688
|
-
}
|
|
3689
|
-
|
|
3690
|
-
/**
|
|
3691
|
-
* Loads and parses a JSON from a remote URL using Fetch API.
|
|
3692
|
-
*
|
|
3693
|
-
* @param {string} url - The full URL to fetch JSON from.
|
|
3694
|
-
* @param {Object} [options] - Optional settings.
|
|
3695
|
-
* @returns {Promise<any[] | Record<string | number | symbol, unknown>>} Parsed JSON object.
|
|
3696
|
-
* @throws {Error} Throws if fetch fails, times out, or returns invalid JSON.
|
|
3697
|
-
*/
|
|
3698
|
-
async function fetchJson(url, options) {
|
|
3699
|
-
return new Promise((resolve, reject) => {
|
|
3700
|
-
fetchTemplate(url, options)
|
|
3701
|
-
.then(async (res) => {
|
|
3702
|
-
const contentType = res.headers.get('content-type') || '';
|
|
3703
|
-
if (!contentType.includes('application/json'))
|
|
3704
|
-
throw new Error(`Unexpected content-type: ${contentType}`);
|
|
3705
|
-
|
|
3706
|
-
const data = await res.json();
|
|
3707
|
-
|
|
3708
|
-
if (!Array.isArray(data) && !isJsonObject(data))
|
|
3709
|
-
throw new Error('Received invalid data instead of valid JSON.');
|
|
3710
|
-
|
|
3711
|
-
return resolve(data);
|
|
3712
|
-
})
|
|
3713
|
-
.catch(reject);
|
|
3714
|
-
});
|
|
3715
|
-
}
|
|
3716
|
-
|
|
3717
|
-
/**
|
|
3718
|
-
* Loads a remote file as a Blob using Fetch API.
|
|
3719
|
-
*
|
|
3720
|
-
* @param {string} url - The full URL to fetch the file from.
|
|
3721
|
-
* @param {Object} [options] - Optional fetch options.
|
|
3722
|
-
* @param {string[]} [allowedMimeTypes] - Optional list of accepted MIME types (e.g., ['image/jpeg']).
|
|
3723
|
-
* @returns {Promise<Blob>} - The fetched file as a Blob.
|
|
3724
|
-
* @throws {Error} Throws if fetch fails, response is not ok, or MIME type is not allowed.
|
|
3725
|
-
*/
|
|
3726
|
-
async function fetchBlob(url, allowedMimeTypes, options) {
|
|
3727
|
-
return new Promise((resolve, reject) => {
|
|
3728
|
-
fetchTemplate(url, options)
|
|
3729
|
-
.then(async (res) => {
|
|
3730
|
-
const contentType = res.headers.get('content-type') || '';
|
|
3731
|
-
|
|
3732
|
-
if (
|
|
3733
|
-
Array.isArray(allowedMimeTypes) &&
|
|
3734
|
-
allowedMimeTypes.length > 0 &&
|
|
3735
|
-
!allowedMimeTypes.some((type) => contentType.includes(type))
|
|
3736
|
-
) {
|
|
3737
|
-
throw new Error(`Blocked MIME type: ${contentType}`);
|
|
3738
|
-
}
|
|
3739
|
-
|
|
3740
|
-
const data = await res.blob();
|
|
3741
|
-
return resolve(data);
|
|
3742
|
-
})
|
|
3743
|
-
.catch(reject);
|
|
3744
|
-
});
|
|
3745
|
-
}
|
|
3746
|
-
|
|
3747
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
3748
|
-
|
|
3749
|
-
/**
|
|
3750
|
-
* Installs a script that toggles CSS classes on a given element
|
|
3751
|
-
* based on the page's visibility or focus state, and optionally
|
|
3752
|
-
* triggers callbacks on visibility changes.
|
|
3753
|
-
*
|
|
3754
|
-
* @param {Object} [settings={}]
|
|
3755
|
-
* @param {Element} [settings.element=document.body] - The element to receive visibility classes.
|
|
3756
|
-
* @param {string} [settings.hiddenClass='windowHidden'] - CSS class applied when the page is hidden.
|
|
3757
|
-
* @param {string} [settings.visibleClass='windowVisible'] - CSS class applied when the page is visible.
|
|
3758
|
-
* @param {() => void} [settings.onVisible] - Callback called when page becomes visible.
|
|
3759
|
-
* @param {() => void} [settings.onHidden] - Callback called when page becomes hidden.
|
|
3760
|
-
* @returns {() => void} Function that removes all installed event listeners.
|
|
3761
|
-
* @throws {TypeError} If any provided setting is invalid.
|
|
3762
|
-
*/
|
|
3763
|
-
function installWindowHiddenScript({
|
|
3764
|
-
element = document.body,
|
|
3765
|
-
hiddenClass = 'windowHidden',
|
|
3766
|
-
visibleClass = 'windowVisible',
|
|
3767
|
-
onVisible,
|
|
3768
|
-
onHidden,
|
|
3769
|
-
} = {}) {
|
|
3770
|
-
if (!(element instanceof Element))
|
|
3771
|
-
throw new TypeError(`"element" must be an instance of Element.`);
|
|
3772
|
-
if (typeof hiddenClass !== 'string') throw new TypeError(`"hiddenClass" must be a string.`);
|
|
3773
|
-
if (typeof visibleClass !== 'string') throw new TypeError(`"visibleClass" must be a string.`);
|
|
3774
|
-
if (onVisible !== undefined && typeof onVisible !== 'function')
|
|
3775
|
-
throw new TypeError(`"onVisible" must be a function if provided.`);
|
|
3776
|
-
if (onHidden !== undefined && typeof onHidden !== 'function')
|
|
3777
|
-
throw new TypeError(`"onHidden" must be a function if provided.`);
|
|
3778
|
-
|
|
3779
|
-
const removeClass = () => {
|
|
3780
|
-
element.classList.remove(hiddenClass);
|
|
3781
|
-
element.classList.remove(visibleClass);
|
|
3782
|
-
};
|
|
3783
|
-
|
|
3784
|
-
/** @type {string|null} */
|
|
3785
|
-
let hiddenProp = null;
|
|
3786
|
-
|
|
3787
|
-
const visibilityEvents = [
|
|
3788
|
-
'visibilitychange',
|
|
3789
|
-
'mozvisibilitychange',
|
|
3790
|
-
'webkitvisibilitychange',
|
|
3791
|
-
'msvisibilitychange',
|
|
3792
|
-
];
|
|
3793
|
-
|
|
3794
|
-
const visibilityProps = ['hidden', 'mozHidden', 'webkitHidden', 'msHidden'];
|
|
3795
|
-
|
|
3796
|
-
for (let i = 0; i < visibilityProps.length; i++) {
|
|
3797
|
-
if (visibilityProps[i] in document) {
|
|
3798
|
-
hiddenProp = visibilityProps[i];
|
|
3799
|
-
break;
|
|
3800
|
-
}
|
|
3801
|
-
}
|
|
3802
|
-
|
|
3803
|
-
/** @type {(this: any, evt: Event) => void} */
|
|
3804
|
-
const handler = function (evt) {
|
|
3805
|
-
removeClass();
|
|
3806
|
-
|
|
3807
|
-
const type = evt?.type;
|
|
3808
|
-
// @ts-ignore
|
|
3809
|
-
const isHidden = hiddenProp && document[hiddenProp];
|
|
3810
|
-
|
|
3811
|
-
const visibleEvents = ['focus', 'focusin', 'pageshow'];
|
|
3812
|
-
const hiddenEvents = ['blur', 'focusout', 'pagehide'];
|
|
3813
|
-
|
|
3814
|
-
if (visibleEvents.includes(type)) {
|
|
3815
|
-
element.classList.add(visibleClass);
|
|
3816
|
-
onVisible?.();
|
|
3817
|
-
} else if (hiddenEvents.includes(type)) {
|
|
3818
|
-
element.classList.add(hiddenClass);
|
|
3819
|
-
onHidden?.();
|
|
3820
|
-
} else {
|
|
3821
|
-
if (isHidden) {
|
|
3822
|
-
element.classList.add(hiddenClass);
|
|
3823
|
-
onHidden?.();
|
|
3824
|
-
} else {
|
|
3825
|
-
element.classList.add(visibleClass);
|
|
3826
|
-
onVisible?.();
|
|
3827
|
-
}
|
|
3828
|
-
}
|
|
3829
|
-
};
|
|
3830
|
-
|
|
3831
|
-
/** @type {() => void} */
|
|
3832
|
-
let uninstall = () => {};
|
|
3833
|
-
|
|
3834
|
-
if (hiddenProp) {
|
|
3835
|
-
const eventType = visibilityEvents[visibilityProps.indexOf(hiddenProp)];
|
|
3836
|
-
document.addEventListener(eventType, handler);
|
|
3837
|
-
window.addEventListener('focus', handler);
|
|
3838
|
-
window.addEventListener('blur', handler);
|
|
3839
|
-
|
|
3840
|
-
uninstall = () => {
|
|
3841
|
-
document.removeEventListener(eventType, handler);
|
|
3842
|
-
window.removeEventListener('focus', handler);
|
|
3843
|
-
window.removeEventListener('blur', handler);
|
|
3844
|
-
removeClass();
|
|
3845
|
-
};
|
|
3846
|
-
} else if ('onfocusin' in document) {
|
|
3847
|
-
// Fallback for IE9 and older
|
|
3848
|
-
// @ts-ignore
|
|
3849
|
-
document.onfocusin = document.onfocusout = handler;
|
|
3850
|
-
uninstall = () => {
|
|
3851
|
-
// @ts-ignore
|
|
3852
|
-
document.onfocusin = document.onfocusout = null;
|
|
3853
|
-
removeClass();
|
|
3854
|
-
};
|
|
3855
|
-
} else {
|
|
3856
|
-
// Last resort fallback
|
|
3857
|
-
window.onpageshow = window.onpagehide = window.onfocus = window.onblur = handler;
|
|
3858
|
-
uninstall = () => {
|
|
3859
|
-
window.onpageshow = window.onpagehide = window.onfocus = window.onblur = null;
|
|
3860
|
-
removeClass();
|
|
3861
|
-
};
|
|
3862
|
-
}
|
|
3863
|
-
|
|
3864
|
-
// Trigger initial state
|
|
3865
|
-
// @ts-ignore
|
|
3866
|
-
const simulatedEvent = new Event(hiddenProp && document[hiddenProp] ? 'blur' : 'focus');
|
|
3867
|
-
handler(simulatedEvent);
|
|
3868
|
-
|
|
3869
|
-
return uninstall;
|
|
3870
|
-
}
|
|
3871
|
-
|
|
3872
3478
|
;// ./src/v1/basics/collision.mjs
|
|
3873
3479
|
/**
|
|
3874
3480
|
* A direction relative to a rectangle.
|
|
@@ -4358,6 +3964,21 @@ const {
|
|
|
4358
3964
|
* @typedef {Element|Window|Document} ElementAndWinAndDoc
|
|
4359
3965
|
*/
|
|
4360
3966
|
|
|
3967
|
+
/**
|
|
3968
|
+
* Represents a raw DOM element with document or an instance of TinyHtml.
|
|
3969
|
+
* This type is used to abstract interactions with both plain elements
|
|
3970
|
+
* and wrapped elements via the TinyHtml class.
|
|
3971
|
+
*
|
|
3972
|
+
* @typedef {ElementWithDoc|TinyHtml} TinyElementWithDoc
|
|
3973
|
+
*/
|
|
3974
|
+
|
|
3975
|
+
/**
|
|
3976
|
+
* Represents a value that can be either a DOM Element, or the document object.
|
|
3977
|
+
* Useful for functions that operate generically on measurable targets.
|
|
3978
|
+
*
|
|
3979
|
+
* @typedef {Element|Document} ElementWithDoc
|
|
3980
|
+
*/
|
|
3981
|
+
|
|
4361
3982
|
/**
|
|
4362
3983
|
* A parameter type used for filtering or matching elements.
|
|
4363
3984
|
* It can be:
|
|
@@ -4377,12 +3998,6 @@ const {
|
|
|
4377
3998
|
* @typedef {Window|Element|Document|Text} ConstructorElValues
|
|
4378
3999
|
*/
|
|
4379
4000
|
|
|
4380
|
-
/**
|
|
4381
|
-
* The handler function used in event listeners.
|
|
4382
|
-
*
|
|
4383
|
-
* @typedef {(e: Event) => any} EventRegistryHandle
|
|
4384
|
-
*/
|
|
4385
|
-
|
|
4386
4001
|
/**
|
|
4387
4002
|
* Options passed to `addEventListener` or `removeEventListener`.
|
|
4388
4003
|
* Can be a boolean or an object of type `AddEventListenerOptions`.
|
|
@@ -4394,7 +4009,7 @@ const {
|
|
|
4394
4009
|
* Structure describing a registered event callback and its options.
|
|
4395
4010
|
*
|
|
4396
4011
|
* @typedef {Object} EventRegistryItem
|
|
4397
|
-
* @property {
|
|
4012
|
+
* @property {EventListenerOrEventListenerObject|null} handler - The function to be executed when the event is triggered.
|
|
4398
4013
|
* @property {EventRegistryOptions} [options] - Optional configuration passed to the listener.
|
|
4399
4014
|
*/
|
|
4400
4015
|
|
|
@@ -4953,9 +4568,9 @@ class TinyHtml_TinyHtml {
|
|
|
4953
4568
|
* Ensures the input is returned as an array.
|
|
4954
4569
|
* Useful to normalize operations across multiple or single element/window/document elements.
|
|
4955
4570
|
*
|
|
4956
|
-
* @param {TinyElementAndWinAndDoc|TinyElementAndWinAndDoc[]} elems - A single element/window element or array of html elements.
|
|
4571
|
+
* @param {TinyElementAndWinAndDoc|TinyElementAndWinAndDoc[]} elems - A single element/document/window element or array of html elements.
|
|
4957
4572
|
* @param {string} where - The method or context name where validation is being called.
|
|
4958
|
-
* @returns {ElementAndWindow[]} - Always returns an array of element/window elements.
|
|
4573
|
+
* @returns {ElementAndWindow[]} - Always returns an array of element/document/window elements.
|
|
4959
4574
|
* @readonly
|
|
4960
4575
|
*/
|
|
4961
4576
|
static _preElemsAndWinAndDoc(elems, where) {
|
|
@@ -4972,9 +4587,9 @@ class TinyHtml_TinyHtml {
|
|
|
4972
4587
|
* Ensures the input is returned as an single element/window/document element.
|
|
4973
4588
|
* Useful to normalize operations across multiple or single element/window/document elements.
|
|
4974
4589
|
*
|
|
4975
|
-
* @param {TinyElementAndWinAndDoc|TinyElementAndWinAndDoc[]} elems - A single element/window element or array of html elements.
|
|
4590
|
+
* @param {TinyElementAndWinAndDoc|TinyElementAndWinAndDoc[]} elems - A single element/document/window element or array of html elements.
|
|
4976
4591
|
* @param {string} where - The method or context name where validation is being called.
|
|
4977
|
-
* @returns {ElementAndWindow} - Always returns an single element/window element.
|
|
4592
|
+
* @returns {ElementAndWindow} - Always returns an single element/document/window element.
|
|
4978
4593
|
* @readonly
|
|
4979
4594
|
*/
|
|
4980
4595
|
static _preElemAndWinAndDoc(elems, where) {
|
|
@@ -4988,6 +4603,32 @@ class TinyHtml_TinyHtml {
|
|
|
4988
4603
|
return result;
|
|
4989
4604
|
}
|
|
4990
4605
|
|
|
4606
|
+
/**
|
|
4607
|
+
* Ensures the input is returned as an array.
|
|
4608
|
+
* Useful to normalize operations across multiple or single element with document elements.
|
|
4609
|
+
*
|
|
4610
|
+
* @param {TinyElementWithDoc|TinyElementWithDoc[]} elems - A single element with document element or array of html elements.
|
|
4611
|
+
* @param {string} where - The method or context name where validation is being called.
|
|
4612
|
+
* @returns {ElementWithDoc[]} - Always returns an array of element with document elements.
|
|
4613
|
+
* @readonly
|
|
4614
|
+
*/
|
|
4615
|
+
static _preElemsWithDoc(elems, where) {
|
|
4616
|
+
return TinyHtml_TinyHtml._preElemsTemplate(elems, where, [Element, Document], ['Element', 'Document']);
|
|
4617
|
+
}
|
|
4618
|
+
|
|
4619
|
+
/**
|
|
4620
|
+
* Ensures the input is returned as an single element with document element.
|
|
4621
|
+
* Useful to normalize operations across multiple or single element with document elements.
|
|
4622
|
+
*
|
|
4623
|
+
* @param {TinyElementWithDoc|TinyElementWithDoc[]} elems - A single element/window element or array of html elements.
|
|
4624
|
+
* @param {string} where - The method or context name where validation is being called.
|
|
4625
|
+
* @returns {ElementWithDoc} - Always returns an single element/window element.
|
|
4626
|
+
* @readonly
|
|
4627
|
+
*/
|
|
4628
|
+
static _preElemWithDoc(elems, where) {
|
|
4629
|
+
return TinyHtml_TinyHtml._preElemTemplate(elems, where, [Element, Document], ['Element', 'Document']);
|
|
4630
|
+
}
|
|
4631
|
+
|
|
4991
4632
|
/**
|
|
4992
4633
|
* Normalizes and converts one or more DOM elements (or TinyHtml instances)
|
|
4993
4634
|
* into an array of `TinyHtml` instances.
|
|
@@ -8247,12 +7888,120 @@ class TinyHtml_TinyHtml {
|
|
|
8247
7888
|
|
|
8248
7889
|
////////////////////////////////////////////
|
|
8249
7890
|
|
|
7891
|
+
/**
|
|
7892
|
+
* Registers a listener for the "paste" event to extract files and text from the clipboard (e.g., when the user presses Ctrl+V).
|
|
7893
|
+
*
|
|
7894
|
+
* This method allows reacting to pasted content by providing separate callbacks for files and plain text.
|
|
7895
|
+
* Useful for building file upload areas, rich-text editors, or input enhancements.
|
|
7896
|
+
*
|
|
7897
|
+
* @param {TinyElementWithDoc|TinyElementWithDoc[]} el - The target element(s) where the "paste" event will be listened.
|
|
7898
|
+
* @param {Object} [settings={}] - Optional callbacks to handle clipboard content.
|
|
7899
|
+
* @param {(data: DataTransferItem, file: File) => void} [settings.onFilePaste] - Called for each file pasted from the clipboard (e.g., images).
|
|
7900
|
+
* @param {(data: DataTransferItem, text: string) => void} [settings.onTextPaste] - Called when plain text is pasted from the clipboard.
|
|
7901
|
+
* @returns {EventListenerOrEventListenerObject} The internal "paste" event handler used.
|
|
7902
|
+
*/
|
|
7903
|
+
static listenForPaste(el, { onFilePaste, onTextPaste } = {}) {
|
|
7904
|
+
if (typeof onFilePaste !== 'undefined' && typeof onFilePaste !== 'function')
|
|
7905
|
+
throw new TypeError('onFilePaste must be a function.');
|
|
7906
|
+
if (typeof onTextPaste !== 'undefined' && typeof onTextPaste !== 'function')
|
|
7907
|
+
throw new TypeError('onTextPaste must be a function.');
|
|
7908
|
+
|
|
7909
|
+
/** @type {EventListenerOrEventListenerObject} */
|
|
7910
|
+
const pasteEvent = (event) => {
|
|
7911
|
+
if (!(event instanceof ClipboardEvent)) return;
|
|
7912
|
+
const items = event.clipboardData?.items || [];
|
|
7913
|
+
for (const item of items) {
|
|
7914
|
+
if (item.kind === 'file') {
|
|
7915
|
+
if (typeof onFilePaste === 'function') {
|
|
7916
|
+
const file = item.getAsFile();
|
|
7917
|
+
if (file) onFilePaste(item, file);
|
|
7918
|
+
}
|
|
7919
|
+
} else if (item.kind === 'string') {
|
|
7920
|
+
if (typeof onTextPaste === 'function')
|
|
7921
|
+
item.getAsString((text) => onTextPaste(item, text));
|
|
7922
|
+
}
|
|
7923
|
+
}
|
|
7924
|
+
};
|
|
7925
|
+
|
|
7926
|
+
TinyHtml_TinyHtml._preElemsWithDoc(el, 'listenForPaste').forEach((elem) =>
|
|
7927
|
+
TinyHtml_TinyHtml.on(elem, 'paste', pasteEvent),
|
|
7928
|
+
);
|
|
7929
|
+
return pasteEvent;
|
|
7930
|
+
}
|
|
7931
|
+
|
|
7932
|
+
/**
|
|
7933
|
+
* Registers a listener for the "paste" event to extract files and text from the clipboard (e.g., when the user presses Ctrl+V).
|
|
7934
|
+
*
|
|
7935
|
+
* This method allows reacting to pasted content by providing separate callbacks for files and plain text.
|
|
7936
|
+
* Useful for building file upload areas, rich-text editors, or input enhancements.
|
|
7937
|
+
*
|
|
7938
|
+
* @param {Object} [settings={}] - Optional callbacks to handle clipboard content.
|
|
7939
|
+
* @param {(data: DataTransferItem, file: File) => void} [settings.onFilePaste] - Called for each file pasted from the clipboard (e.g., images).
|
|
7940
|
+
* @param {(data: DataTransferItem, text: string) => void} [settings.onTextPaste] - Called when plain text is pasted from the clipboard.
|
|
7941
|
+
* @returns {EventListenerOrEventListenerObject} The internal "paste" event handler used.
|
|
7942
|
+
*/
|
|
7943
|
+
listenForPaste({ onFilePaste, onTextPaste } = {}) {
|
|
7944
|
+
return TinyHtml_TinyHtml.listenForPaste(this, { onFilePaste, onTextPaste });
|
|
7945
|
+
}
|
|
7946
|
+
|
|
7947
|
+
/**
|
|
7948
|
+
* Checks if the element has a listener for a specific event.
|
|
7949
|
+
*
|
|
7950
|
+
* @param {TinyEventTarget} el - The element to check.
|
|
7951
|
+
* @param {string} event - The event name to check.
|
|
7952
|
+
* @returns {boolean}
|
|
7953
|
+
*/
|
|
7954
|
+
static hasEventListener(el, event) {
|
|
7955
|
+
const elem = TinyHtml_TinyHtml._preEventTargetElem(el, 'hasEventListener');
|
|
7956
|
+
if (!__eventRegistry.has(elem)) return false;
|
|
7957
|
+
const events = __eventRegistry.get(elem);
|
|
7958
|
+
return !!(events && Array.isArray(events[event]) && events[event].length > 0);
|
|
7959
|
+
}
|
|
7960
|
+
|
|
7961
|
+
/**
|
|
7962
|
+
* Checks if the element has a listener for a specific event.
|
|
7963
|
+
*
|
|
7964
|
+
* @param {string} event - The event name to check.
|
|
7965
|
+
* @returns {boolean}
|
|
7966
|
+
*/
|
|
7967
|
+
hasEventListener(event) {
|
|
7968
|
+
return TinyHtml_TinyHtml.hasEventListener(this, event);
|
|
7969
|
+
}
|
|
7970
|
+
|
|
7971
|
+
/**
|
|
7972
|
+
* Checks if the element has the exact handler registered for a specific event.
|
|
7973
|
+
*
|
|
7974
|
+
* @param {TinyEventTarget} el - The element to check.
|
|
7975
|
+
* @param {string} event - The event name to check.
|
|
7976
|
+
* @param {EventListenerOrEventListenerObject} handler - The handler function to check.
|
|
7977
|
+
* @returns {boolean}
|
|
7978
|
+
*/
|
|
7979
|
+
static hasExactEventListener(el, event, handler) {
|
|
7980
|
+
const elem = TinyHtml_TinyHtml._preEventTargetElem(el, 'hasExactEventListener');
|
|
7981
|
+
if (typeof handler !== 'function') throw new TypeError('The "handler" must be a function.');
|
|
7982
|
+
if (!__eventRegistry.has(elem)) return false;
|
|
7983
|
+
const events = __eventRegistry.get(elem);
|
|
7984
|
+
if (!events || !Array.isArray(events[event])) return false;
|
|
7985
|
+
return events[event].some((item) => item.handler === handler);
|
|
7986
|
+
}
|
|
7987
|
+
|
|
7988
|
+
/**
|
|
7989
|
+
* Checks if the element has the exact handler registered for a specific event.
|
|
7990
|
+
*
|
|
7991
|
+
* @param {string} event - The event name to check.
|
|
7992
|
+
* @param {EventListenerOrEventListenerObject} handler - The handler function to check.
|
|
7993
|
+
* @returns {boolean}
|
|
7994
|
+
*/
|
|
7995
|
+
hasExactEventListener(event, handler) {
|
|
7996
|
+
return TinyHtml_TinyHtml.hasExactEventListener(this, event, handler);
|
|
7997
|
+
}
|
|
7998
|
+
|
|
8250
7999
|
/**
|
|
8251
8000
|
* Registers an event listener on the specified element.
|
|
8252
8001
|
*
|
|
8253
8002
|
* @param {TinyEventTarget|TinyEventTarget[]} el - The target to listen on.
|
|
8254
8003
|
* @param {string} event - The event type (e.g. 'click', 'keydown').
|
|
8255
|
-
* @param {
|
|
8004
|
+
* @param {EventListenerOrEventListenerObject|null} handler - The callback function to run on event.
|
|
8256
8005
|
* @param {EventRegistryOptions} [options] - Optional event listener options.
|
|
8257
8006
|
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
8258
8007
|
*/
|
|
@@ -8274,7 +8023,7 @@ class TinyHtml_TinyHtml {
|
|
|
8274
8023
|
* Registers an event listener on the specified element.
|
|
8275
8024
|
*
|
|
8276
8025
|
* @param {string} event - The event type (e.g. 'click', 'keydown').
|
|
8277
|
-
* @param {
|
|
8026
|
+
* @param {EventListenerOrEventListenerObject|null} handler - The callback function to run on event.
|
|
8278
8027
|
* @param {EventRegistryOptions} [options] - Optional event listener options.
|
|
8279
8028
|
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
8280
8029
|
*/
|
|
@@ -8287,17 +8036,17 @@ class TinyHtml_TinyHtml {
|
|
|
8287
8036
|
*
|
|
8288
8037
|
* @param {TinyEventTarget|TinyEventTarget[]} el - The target to listen on.
|
|
8289
8038
|
* @param {string} event - The event type (e.g. 'click', 'keydown').
|
|
8290
|
-
* @param {
|
|
8039
|
+
* @param {EventListenerOrEventListenerObject} handler - The callback function to run on event.
|
|
8291
8040
|
* @param {EventRegistryOptions} [options={}] - Optional event listener options.
|
|
8292
8041
|
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
8293
8042
|
*/
|
|
8294
8043
|
static once(el, event, handler, options = {}) {
|
|
8295
8044
|
if (typeof event !== 'string') throw new TypeError('The event name must be a string.');
|
|
8296
8045
|
TinyHtml_TinyHtml._preEventTargetElems(el, 'once').forEach((elem) => {
|
|
8297
|
-
/** @type {
|
|
8046
|
+
/** @type {EventListenerOrEventListenerObject} */
|
|
8298
8047
|
const wrapped = (e) => {
|
|
8299
8048
|
TinyHtml_TinyHtml.off(elem, event, wrapped);
|
|
8300
|
-
handler(e);
|
|
8049
|
+
if (typeof handler === 'function') handler(e);
|
|
8301
8050
|
};
|
|
8302
8051
|
|
|
8303
8052
|
TinyHtml_TinyHtml.on(
|
|
@@ -8314,7 +8063,7 @@ class TinyHtml_TinyHtml {
|
|
|
8314
8063
|
* Registers an event listener that runs only once, then is removed.
|
|
8315
8064
|
*
|
|
8316
8065
|
* @param {string} event - The event type (e.g. 'click', 'keydown').
|
|
8317
|
-
* @param {
|
|
8066
|
+
* @param {EventListenerOrEventListenerObject} handler - The callback function to run on event.
|
|
8318
8067
|
* @param {EventRegistryOptions} [options={}] - Optional event listener options.
|
|
8319
8068
|
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
8320
8069
|
*/
|
|
@@ -8327,7 +8076,7 @@ class TinyHtml_TinyHtml {
|
|
|
8327
8076
|
*
|
|
8328
8077
|
* @param {TinyEventTarget|TinyEventTarget[]} el - The target element.
|
|
8329
8078
|
* @param {string} event - The event type.
|
|
8330
|
-
* @param {
|
|
8079
|
+
* @param {EventListenerOrEventListenerObject|null} handler - The function originally bound to the event.
|
|
8331
8080
|
* @param {boolean|EventListenerOptions} [options] - Optional listener options.
|
|
8332
8081
|
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
8333
8082
|
*/
|
|
@@ -8349,7 +8098,7 @@ class TinyHtml_TinyHtml {
|
|
|
8349
8098
|
* Removes a specific event listener from an element.
|
|
8350
8099
|
*
|
|
8351
8100
|
* @param {string} event - The event type.
|
|
8352
|
-
* @param {
|
|
8101
|
+
* @param {EventListenerOrEventListenerObject|null} handler - The function originally bound to the event.
|
|
8353
8102
|
* @param {boolean|EventListenerOptions} [options] - Optional listener options.
|
|
8354
8103
|
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
8355
8104
|
*/
|
|
@@ -8392,7 +8141,7 @@ class TinyHtml_TinyHtml {
|
|
|
8392
8141
|
* Removes all event listeners of all types from the element.
|
|
8393
8142
|
*
|
|
8394
8143
|
* @param {TinyEventTarget|TinyEventTarget[]} el - The target element.
|
|
8395
|
-
* @param {((handler: EventListenerOrEventListenerObject, event: string) => boolean)|null} [filterFn=null] -
|
|
8144
|
+
* @param {((handler: EventListenerOrEventListenerObject|null, event: string) => boolean)|null} [filterFn=null] -
|
|
8396
8145
|
* Optional filter function to selectively remove specific handlers.
|
|
8397
8146
|
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
8398
8147
|
*/
|
|
@@ -8419,7 +8168,7 @@ class TinyHtml_TinyHtml {
|
|
|
8419
8168
|
/**
|
|
8420
8169
|
* Removes all event listeners of all types from the element.
|
|
8421
8170
|
*
|
|
8422
|
-
* @param {((handler: EventListenerOrEventListenerObject, event: string) => boolean)|null} [filterFn=null] -
|
|
8171
|
+
* @param {((handler: EventListenerOrEventListenerObject|null, event: string) => boolean)|null} [filterFn=null] -
|
|
8423
8172
|
* Optional filter function to selectively remove specific handlers.
|
|
8424
8173
|
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
8425
8174
|
*/
|
|
@@ -10080,7 +9829,7 @@ class TinyDragger {
|
|
|
10080
9829
|
if (
|
|
10081
9830
|
options.vibration !== undefined &&
|
|
10082
9831
|
options.vibration !== false &&
|
|
10083
|
-
!
|
|
9832
|
+
!isJsonObject(options.vibration)
|
|
10084
9833
|
)
|
|
10085
9834
|
throw new Error('The "vibration" option must be an object or false.');
|
|
10086
9835
|
|
|
@@ -10124,7 +9873,7 @@ class TinyDragger {
|
|
|
10124
9873
|
const vibrationTemplate = { start: false, end: false, collide: false, move: false };
|
|
10125
9874
|
this.#vibration = Object.assign(
|
|
10126
9875
|
vibrationTemplate,
|
|
10127
|
-
|
|
9876
|
+
isJsonObject(options.vibration) ? options.vibration : {},
|
|
10128
9877
|
);
|
|
10129
9878
|
|
|
10130
9879
|
if (typeof options.classDragging === 'string') this.#classDragging = options.classDragging;
|
|
@@ -11969,6 +11718,9 @@ class TinySmartScroller {
|
|
|
11969
11718
|
|
|
11970
11719
|
|
|
11971
11720
|
|
|
11721
|
+
|
|
11722
|
+
|
|
11723
|
+
|
|
11972
11724
|
|
|
11973
11725
|
|
|
11974
11726
|
|
|
@@ -12048,7 +11800,7 @@ class TinyUploadClicker {
|
|
|
12048
11800
|
* @throws {TypeError} If the config is invalid or required options are missing.
|
|
12049
11801
|
*/
|
|
12050
11802
|
constructor(options) {
|
|
12051
|
-
if (!
|
|
11803
|
+
if (!isJsonObject(options))
|
|
12052
11804
|
throw new TypeError('TinyUploadClicker: "options" must be a valid object.');
|
|
12053
11805
|
|
|
12054
11806
|
this.#config = {
|
|
@@ -12114,10 +11866,10 @@ class TinyUploadClicker {
|
|
|
12114
11866
|
)
|
|
12115
11867
|
throw new TypeError('TinyUploadClicker: "onFileLoad" must be a function or null.');
|
|
12116
11868
|
|
|
12117
|
-
if (options.inputAttributes !== undefined && !
|
|
11869
|
+
if (options.inputAttributes !== undefined && !isJsonObject(options.inputAttributes))
|
|
12118
11870
|
throw new TypeError('TinyUploadClicker: "inputAttributes" must be an object.');
|
|
12119
11871
|
|
|
12120
|
-
if (options.inputStyles !== undefined && !
|
|
11872
|
+
if (options.inputStyles !== undefined && !isJsonObject(options.inputStyles))
|
|
12121
11873
|
throw new TypeError('TinyUploadClicker: "inputStyles" must be an object.');
|
|
12122
11874
|
|
|
12123
11875
|
this.#boundClick = this.#handleClick.bind(this);
|