tiny-essentials 1.16.2 → 1.17.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/crypto/decrypt.cjs +1 -0
- package/dist/legacy/crypto/decrypt.d.mts +1 -0
- package/dist/legacy/crypto/decrypt.mjs +1 -0
- package/dist/legacy/crypto/encrypt.cjs +1 -0
- package/dist/legacy/crypto/encrypt.d.mts +1 -0
- package/dist/legacy/crypto/encrypt.mjs +1 -0
- package/dist/legacy/get/decimalColor.cjs +1 -0
- package/dist/legacy/get/decimalColor.d.mts +1 -0
- package/dist/legacy/get/decimalColor.mjs +1 -0
- package/dist/legacy/get/pagination.cjs +1 -0
- package/dist/legacy/get/pagination.d.mts +1 -0
- package/dist/legacy/get/pagination.mjs +1 -0
- package/dist/legacy/get/queryUrlByName.cjs +1 -0
- package/dist/legacy/get/queryUrlByName.d.mts +1 -0
- package/dist/legacy/get/queryUrlByName.mjs +1 -0
- package/dist/legacy/get/queryUrlJSON.cjs +1 -0
- package/dist/legacy/get/queryUrlJSON.d.mts +1 -0
- package/dist/legacy/get/queryUrlJSON.mjs +1 -0
- package/dist/legacy/get/super_string_filter.cjs +1 -0
- package/dist/legacy/get/super_string_filter.d.mts +1 -0
- package/dist/legacy/get/super_string_filter.mjs +1 -0
- package/dist/legacy/get/versionCheck.cjs +1 -0
- package/dist/legacy/get/versionCheck.d.mts +1 -0
- package/dist/legacy/get/versionCheck.mjs +1 -0
- package/dist/legacy/http/HTTP-1.0.cjs +2 -0
- package/dist/legacy/http/HTTP-1.0.mjs +2 -0
- package/dist/legacy/http/auth.cjs +1 -0
- package/dist/legacy/http/auth.d.mts +1 -0
- package/dist/legacy/http/auth.mjs +1 -0
- package/dist/legacy/http/check_domain.cjs +11 -0
- package/dist/legacy/http/check_domain.d.mts +3 -0
- package/dist/legacy/http/check_domain.mjs +11 -0
- package/dist/legacy/http/csrfTokenAnalyze.cjs +1 -0
- package/dist/legacy/http/csrfTokenAnalyze.d.mts +1 -0
- package/dist/legacy/http/csrfTokenAnalyze.mjs +1 -0
- package/dist/legacy/http/domainValidator.cjs +1 -0
- package/dist/legacy/http/domainValidator.d.mts +1 -0
- package/dist/legacy/http/domainValidator.mjs +1 -0
- package/dist/legacy/http/errorsCallback.cjs +1 -0
- package/dist/legacy/http/errorsCallback.d.mts +1 -0
- package/dist/legacy/http/errorsCallback.mjs +1 -0
- package/dist/legacy/http/fetch/json.cjs +1 -0
- package/dist/legacy/http/fetch/json.d.mts +1 -0
- package/dist/legacy/http/fetch/json.mjs +1 -0
- package/dist/legacy/http/fetch/text.cjs +1 -0
- package/dist/legacy/http/fetch/text.d.mts +1 -0
- package/dist/legacy/http/fetch/text.mjs +1 -0
- package/dist/legacy/http/fileCache.cjs +1 -0
- package/dist/legacy/http/fileCache.d.mts +1 -0
- package/dist/legacy/http/fileCache.mjs +1 -0
- package/dist/legacy/http/getDomainURL.cjs +1 -0
- package/dist/legacy/http/getDomainURL.d.mts +1 -0
- package/dist/legacy/http/getDomainURL.mjs +1 -0
- package/dist/legacy/http/userIP.cjs +1 -0
- package/dist/legacy/http/userIP.d.mts +1 -0
- package/dist/legacy/http/userIP.mjs +1 -0
- package/dist/legacy/libs/capitalize.cjs +1 -0
- package/dist/legacy/libs/capitalize.d.mts +1 -0
- package/dist/legacy/libs/capitalize.mjs +1 -0
- package/dist/legacy/libs/convertBytes.cjs +2 -0
- package/dist/legacy/libs/convertBytes.mjs +2 -0
- package/dist/legacy/libs/custom_module_loader.cjs +2 -0
- package/dist/legacy/libs/custom_module_loader.mjs +2 -0
- package/dist/legacy/libs/dice.cjs +2 -0
- package/dist/legacy/libs/dice.mjs +2 -0
- package/dist/legacy/libs/markdown.cjs +1 -0
- package/dist/legacy/libs/markdown.mjs +1 -0
- package/dist/legacy/libs/percentage.cjs +1 -0
- package/dist/legacy/libs/percentage.mjs +1 -0
- package/dist/legacy/libs/regex/getLetter.cjs +2 -0
- package/dist/legacy/libs/regex/getLetter.d.mts +2 -0
- package/dist/legacy/libs/regex/getLetter.mjs +2 -0
- package/dist/legacy/libs/rule3.cjs +1 -0
- package/dist/legacy/libs/rule3.mjs +1 -0
- package/dist/legacy/momentjs/getAge.cjs +1 -0
- package/dist/legacy/momentjs/getAge.d.mts +1 -0
- package/dist/legacy/momentjs/getAge.mjs +1 -0
- package/dist/legacy/momentjs/timeDuration.cjs +1 -0
- package/dist/legacy/momentjs/timeDuration.d.mts +1 -0
- package/dist/legacy/momentjs/timeDuration.mjs +1 -0
- package/dist/legacy/socket.io/antiFlood/install.cjs +1 -0
- package/dist/legacy/socket.io/antiFlood/install.d.mts +1 -0
- package/dist/legacy/socket.io/antiFlood/install.mjs +1 -0
- package/dist/legacy/socket.io/antiFlood/verify.cjs +1 -0
- package/dist/legacy/socket.io/antiFlood/verify.d.mts +1 -0
- package/dist/legacy/socket.io/antiFlood/verify.mjs +1 -0
- package/dist/legacy/socket.io/cookie-session.cjs +1 -0
- package/dist/legacy/socket.io/cookie-session.d.mts +1 -0
- package/dist/legacy/socket.io/cookie-session.mjs +1 -0
- package/dist/legacy/socket.io/discord.cjs +1 -0
- package/dist/legacy/socket.io/discord.d.mts +1 -0
- package/dist/legacy/socket.io/discord.mjs +1 -0
- package/dist/v1/TinyBasicsEs.js +729 -93
- package/dist/v1/TinyBasicsEs.min.js +1 -1
- package/dist/v1/TinyDragger.js +656 -69
- package/dist/v1/TinyDragger.min.js +1 -1
- package/dist/v1/TinyEssentials.js +2688 -116
- package/dist/v1/TinyEssentials.min.js +1 -1
- package/dist/v1/TinyHtml.js +656 -69
- package/dist/v1/TinyHtml.min.js +1 -1
- package/dist/v1/TinySmartScroller.js +6378 -0
- package/dist/v1/TinySmartScroller.min.js +1 -0
- package/dist/v1/TinyUploadClicker.js +1732 -118
- package/dist/v1/TinyUploadClicker.min.js +1 -1
- package/dist/v1/UltraRandomMsgGen.js +995 -0
- package/dist/v1/UltraRandomMsgGen.min.js +1 -0
- package/dist/v1/basics/html.cjs +74 -24
- package/dist/v1/basics/html.d.mts +38 -15
- package/dist/v1/basics/html.mjs +63 -20
- package/dist/v1/build/TinySmartScroller.cjs +7 -0
- package/dist/v1/build/TinySmartScroller.d.mts +3 -0
- package/dist/v1/build/TinySmartScroller.mjs +2 -0
- package/dist/v1/build/UltraRandomMsgGen.cjs +7 -0
- package/dist/v1/build/UltraRandomMsgGen.d.mts +3 -0
- package/dist/v1/build/UltraRandomMsgGen.mjs +2 -0
- package/dist/v1/index.cjs +4 -0
- package/dist/v1/index.d.mts +3 -1
- package/dist/v1/index.mjs +3 -1
- package/dist/v1/libs/TinyHtml.cjs +656 -69
- package/dist/v1/libs/TinyHtml.d.mts +440 -139
- package/dist/v1/libs/TinyHtml.mjs +591 -72
- package/dist/v1/libs/TinySmartScroller.cjs +976 -0
- package/dist/v1/libs/TinySmartScroller.d.mts +458 -0
- package/dist/v1/libs/TinySmartScroller.mjs +856 -0
- package/dist/v1/libs/UltraRandomMsgGen.cjs +956 -0
- package/dist/v1/libs/UltraRandomMsgGen.d.mts +390 -0
- package/dist/v1/libs/UltraRandomMsgGen.mjs +825 -0
- package/docs/v1/README.md +2 -0
- package/docs/v1/basics/html.md +17 -2
- package/docs/v1/libs/TinyHtml.md +296 -8
- package/docs/v1/libs/TinySmartScroller.md +523 -0
- package/docs/v1/libs/UltraRandomMsgGen.md +289 -0
- package/package.json +1 -1
|
@@ -2896,7 +2896,9 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
2896
2896
|
TinyNotifyCenter: () => (/* reexport */ libs_TinyNotifyCenter),
|
|
2897
2897
|
TinyPromiseQueue: () => (/* reexport */ libs_TinyPromiseQueue),
|
|
2898
2898
|
TinyRateLimiter: () => (/* reexport */ libs_TinyRateLimiter),
|
|
2899
|
+
TinySmartScroller: () => (/* reexport */ libs_TinySmartScroller),
|
|
2899
2900
|
TinyToastNotify: () => (/* reexport */ libs_TinyToastNotify),
|
|
2901
|
+
UltraRandomMsgGen: () => (/* reexport */ libs_UltraRandomMsgGen),
|
|
2900
2902
|
addAiMarkerShortcut: () => (/* reexport */ addAiMarkerShortcut),
|
|
2901
2903
|
areElsCollBottom: () => (/* reexport */ areElsCollBottom),
|
|
2902
2904
|
areElsCollLeft: () => (/* reexport */ areElsCollLeft),
|
|
@@ -6363,20 +6365,22 @@ function saveJsonFile(filename, data, spaces = 2) {
|
|
|
6363
6365
|
}
|
|
6364
6366
|
|
|
6365
6367
|
/**
|
|
6366
|
-
*
|
|
6367
|
-
*
|
|
6368
|
-
* @
|
|
6369
|
-
* @
|
|
6370
|
-
* @
|
|
6371
|
-
* @
|
|
6372
|
-
* @
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
* @
|
|
6377
|
-
* @
|
|
6368
|
+
* @typedef {Object} FetchTemplateOptions
|
|
6369
|
+
* @property {string} [method="GET"] - HTTP method to use (GET, POST, etc.).
|
|
6370
|
+
* @property {any} [body] - Request body (only for methods like POST, PUT).
|
|
6371
|
+
* @property {number} [timeout=0] - Timeout in milliseconds (ignored if signal is provided).
|
|
6372
|
+
* @property {number} [retries=0] - Number of retry attempts (ignored if signal is provided).
|
|
6373
|
+
* @property {Headers|Record<string, *>} [headers={}] - Additional headers.
|
|
6374
|
+
* @property {AbortSignal|null} [signal] - External AbortSignal; disables timeout and retries.
|
|
6375
|
+
*/
|
|
6376
|
+
|
|
6377
|
+
/**
|
|
6378
|
+
* @param {string} url - The full URL to fetch data from.
|
|
6379
|
+
* @param {FetchTemplateOptions} [options] - Optional settings.
|
|
6380
|
+
* @returns {Promise<Response>} Result data.
|
|
6381
|
+
* @throws {Error} Throws if fetch fails, times out.
|
|
6378
6382
|
*/
|
|
6379
|
-
async function
|
|
6383
|
+
async function fetchTemplate(
|
|
6380
6384
|
url,
|
|
6381
6385
|
{ method = 'GET', body, timeout = 0, retries = 0, headers = {}, signal = null } = {},
|
|
6382
6386
|
) {
|
|
@@ -6435,17 +6439,7 @@ async function fetchJson(
|
|
|
6435
6439
|
if (timer) clearTimeout(timer);
|
|
6436
6440
|
|
|
6437
6441
|
if (!response.ok) throw new Error(`HTTP error: ${response.status} ${response.statusText}`);
|
|
6438
|
-
|
|
6439
|
-
const contentType = response.headers.get('content-type') || '';
|
|
6440
|
-
if (!contentType.includes('application/json'))
|
|
6441
|
-
throw new Error(`Unexpected content-type: ${contentType}`);
|
|
6442
|
-
|
|
6443
|
-
const data = await response.json();
|
|
6444
|
-
|
|
6445
|
-
if (!Array.isArray(data) && !isJsonObject(data))
|
|
6446
|
-
throw new Error('Received invalid data instead of valid JSON.');
|
|
6447
|
-
|
|
6448
|
-
return data;
|
|
6442
|
+
return response;
|
|
6449
6443
|
} catch (err) {
|
|
6450
6444
|
lastError = /** @type {Error} */ (err);
|
|
6451
6445
|
if (signal) break; // if an external signal came, it does not retry
|
|
@@ -6459,6 +6453,63 @@ async function fetchJson(
|
|
|
6459
6453
|
);
|
|
6460
6454
|
}
|
|
6461
6455
|
|
|
6456
|
+
/**
|
|
6457
|
+
* Loads and parses a JSON from a remote URL using Fetch API.
|
|
6458
|
+
*
|
|
6459
|
+
* @param {string} url - The full URL to fetch JSON from.
|
|
6460
|
+
* @param {Object} [options] - Optional settings.
|
|
6461
|
+
* @returns {Promise<any[] | Record<string | number | symbol, unknown>>} Parsed JSON object.
|
|
6462
|
+
* @throws {Error} Throws if fetch fails, times out, or returns invalid JSON.
|
|
6463
|
+
*/
|
|
6464
|
+
async function fetchJson(url, options) {
|
|
6465
|
+
return new Promise((resolve, reject) => {
|
|
6466
|
+
fetchTemplate(url, options)
|
|
6467
|
+
.then(async (res) => {
|
|
6468
|
+
const contentType = res.headers.get('content-type') || '';
|
|
6469
|
+
if (!contentType.includes('application/json'))
|
|
6470
|
+
throw new Error(`Unexpected content-type: ${contentType}`);
|
|
6471
|
+
|
|
6472
|
+
const data = await res.json();
|
|
6473
|
+
|
|
6474
|
+
if (!Array.isArray(data) && !isJsonObject(data))
|
|
6475
|
+
throw new Error('Received invalid data instead of valid JSON.');
|
|
6476
|
+
|
|
6477
|
+
return resolve(data);
|
|
6478
|
+
})
|
|
6479
|
+
.catch(reject);
|
|
6480
|
+
});
|
|
6481
|
+
}
|
|
6482
|
+
|
|
6483
|
+
/**
|
|
6484
|
+
* Loads a remote file as a Blob using Fetch API.
|
|
6485
|
+
*
|
|
6486
|
+
* @param {string} url - The full URL to fetch the file from.
|
|
6487
|
+
* @param {Object} [options] - Optional fetch options.
|
|
6488
|
+
* @param {string[]} [allowedMimeTypes] - Optional list of accepted MIME types (e.g., ['image/jpeg']).
|
|
6489
|
+
* @returns {Promise<Blob>} - The fetched file as a Blob.
|
|
6490
|
+
* @throws {Error} Throws if fetch fails, response is not ok, or MIME type is not allowed.
|
|
6491
|
+
*/
|
|
6492
|
+
async function fetchBlob(url, allowedMimeTypes, options) {
|
|
6493
|
+
return new Promise((resolve, reject) => {
|
|
6494
|
+
fetchTemplate(url, options)
|
|
6495
|
+
.then(async (res) => {
|
|
6496
|
+
const contentType = res.headers.get('content-type') || '';
|
|
6497
|
+
|
|
6498
|
+
if (
|
|
6499
|
+
Array.isArray(allowedMimeTypes) &&
|
|
6500
|
+
allowedMimeTypes.length > 0 &&
|
|
6501
|
+
!allowedMimeTypes.some((type) => contentType.includes(type))
|
|
6502
|
+
) {
|
|
6503
|
+
throw new Error(`Blocked MIME type: ${contentType}`);
|
|
6504
|
+
}
|
|
6505
|
+
|
|
6506
|
+
const data = await res.blob();
|
|
6507
|
+
return resolve(data);
|
|
6508
|
+
})
|
|
6509
|
+
.catch(reject);
|
|
6510
|
+
});
|
|
6511
|
+
}
|
|
6512
|
+
|
|
6462
6513
|
///////////////////////////////////////////////////////////////////////////////
|
|
6463
6514
|
|
|
6464
6515
|
/**
|
|
@@ -6990,6 +7041,19 @@ const {
|
|
|
6990
7041
|
areElsCollRight: TinyHtml_areElsCollRight,
|
|
6991
7042
|
} = collision_namespaceObject;
|
|
6992
7043
|
|
|
7044
|
+
/**
|
|
7045
|
+
* Callback invoked on each animation frame with the current scroll position,
|
|
7046
|
+
* normalized animation time (`0` to `1`), and a completion flag.
|
|
7047
|
+
*
|
|
7048
|
+
* @typedef {(progress: { x: number, y: number, isComplete: boolean, time: number }) => void} OnScrollAnimation
|
|
7049
|
+
*/
|
|
7050
|
+
|
|
7051
|
+
/**
|
|
7052
|
+
* A list of supported easing function names for smooth animations.
|
|
7053
|
+
*
|
|
7054
|
+
* @typedef {'linear' | 'easeInQuad' | 'easeOutQuad' | 'easeInOutQuad' | 'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic'} Easings
|
|
7055
|
+
*/
|
|
7056
|
+
|
|
6993
7057
|
/**
|
|
6994
7058
|
* Represents a raw Node element or an instance of TinyHtml.
|
|
6995
7059
|
* This type is used to abstract interactions with both plain elements
|
|
@@ -7045,6 +7109,21 @@ const {
|
|
|
7045
7109
|
* @typedef {Element|Window} ElementAndWindow
|
|
7046
7110
|
*/
|
|
7047
7111
|
|
|
7112
|
+
/**
|
|
7113
|
+
* Represents a raw DOM element/window/document or an instance of TinyHtml.
|
|
7114
|
+
* This type is used to abstract interactions with both plain elements
|
|
7115
|
+
* and wrapped elements via the TinyHtml class.
|
|
7116
|
+
*
|
|
7117
|
+
* @typedef {ElementAndWinAndDoc|TinyHtml} TinyElementAndWinAndDoc
|
|
7118
|
+
*/
|
|
7119
|
+
|
|
7120
|
+
/**
|
|
7121
|
+
* Represents a value that can be either a DOM Element, or the global Window object, or the document object.
|
|
7122
|
+
* Useful for functions that operate generically on scrollable or measurable targets.
|
|
7123
|
+
*
|
|
7124
|
+
* @typedef {Element|Window|Document} ElementAndWinAndDoc
|
|
7125
|
+
*/
|
|
7126
|
+
|
|
7048
7127
|
/**
|
|
7049
7128
|
* A parameter type used for filtering or matching elements.
|
|
7050
7129
|
* It can be:
|
|
@@ -7061,7 +7140,7 @@ const {
|
|
|
7061
7140
|
* Elements accepted as constructor values for TinyHtml.
|
|
7062
7141
|
* These include common DOM elements and root containers.
|
|
7063
7142
|
*
|
|
7064
|
-
* @typedef {Window|Element|Document} ConstructorElValues
|
|
7143
|
+
* @typedef {Window|Element|Document|Text} ConstructorElValues
|
|
7065
7144
|
*/
|
|
7066
7145
|
|
|
7067
7146
|
/**
|
|
@@ -7182,40 +7261,114 @@ class TinyHtml_TinyHtml {
|
|
|
7182
7261
|
|
|
7183
7262
|
static Utils = { ...collision_namespaceObject };
|
|
7184
7263
|
|
|
7264
|
+
/**
|
|
7265
|
+
* Creates a new DOM element with the specified tag name and options, then wraps it in a TinyHtml instance.
|
|
7266
|
+
*
|
|
7267
|
+
* @param {string} tagName - The tag name of the element to create (e.g., 'div', 'span').
|
|
7268
|
+
* @param {ElementCreationOptions} ops - Optional settings for creating the element.
|
|
7269
|
+
* @returns {TinyHtml} A TinyHtml instance wrapping the newly created DOM element.
|
|
7270
|
+
* @throws {TypeError} If tagName is not a string or ops is not an object.
|
|
7271
|
+
*/
|
|
7272
|
+
static createElement(tagName, ops) {
|
|
7273
|
+
if (typeof tagName !== 'string')
|
|
7274
|
+
throw new TypeError(`[TinyHtml] createElement(): The tagName must be a string.`);
|
|
7275
|
+
if (typeof ops !== 'undefined' && typeof ops !== 'object')
|
|
7276
|
+
throw new TypeError(`[TinyHtml] createElement(): The ops must be a object.`);
|
|
7277
|
+
return new TinyHtml_TinyHtml(document.createElement(tagName, ops));
|
|
7278
|
+
}
|
|
7279
|
+
|
|
7280
|
+
/**
|
|
7281
|
+
* Creates a new TinyHtml instance that wraps a DOM TextNode.
|
|
7282
|
+
*
|
|
7283
|
+
* This method is useful when you want to insert raw text content into the DOM
|
|
7284
|
+
* without it being interpreted as HTML. The returned instance behaves like any
|
|
7285
|
+
* other TinyHtml element and can be appended or manipulated as needed.
|
|
7286
|
+
*
|
|
7287
|
+
* @param {string} value - The plain text content to be wrapped in a TextNode.
|
|
7288
|
+
* @returns {TinyHtml} A TinyHtml instance wrapping the newly created DOM TextNode.
|
|
7289
|
+
* @throws {TypeError} If the provided value is not a string.
|
|
7290
|
+
*/
|
|
7291
|
+
static createTextNode(value) {
|
|
7292
|
+
if (typeof value !== 'string')
|
|
7293
|
+
throw new TypeError(`[TinyHtml] createTextNode(): The value must be a string.`);
|
|
7294
|
+
return new TinyHtml_TinyHtml(document.createTextNode(value));
|
|
7295
|
+
}
|
|
7296
|
+
|
|
7297
|
+
/**
|
|
7298
|
+
* Creates an HTMLElement or TextNode from an HTML string.
|
|
7299
|
+
* Supports both elements and plain text.
|
|
7300
|
+
*
|
|
7301
|
+
* @param {string} htmlString - The HTML string to convert.
|
|
7302
|
+
* @returns {TinyHtml} - A single HTMLElement or TextNode.
|
|
7303
|
+
*/
|
|
7304
|
+
static createElementFromHTML(htmlString) {
|
|
7305
|
+
const template = document.createElement('template');
|
|
7306
|
+
htmlString = htmlString.trim();
|
|
7307
|
+
|
|
7308
|
+
// If it's only text (e.g., no "<" tag), return a TextNode
|
|
7309
|
+
if (!htmlString.startsWith('<')) {
|
|
7310
|
+
return TinyHtml_TinyHtml.createTextNode(htmlString);
|
|
7311
|
+
}
|
|
7312
|
+
|
|
7313
|
+
template.innerHTML = htmlString;
|
|
7314
|
+
if (!(template.content.firstChild instanceof Element)) throw new Error('');
|
|
7315
|
+
return new TinyHtml_TinyHtml(template.content.firstChild);
|
|
7316
|
+
}
|
|
7317
|
+
|
|
7185
7318
|
/**
|
|
7186
7319
|
* Queries the document for the first element matching the CSS selector and wraps it in a TinyHtml instance.
|
|
7187
7320
|
*
|
|
7188
7321
|
* @param {string} selector - A valid CSS selector string.
|
|
7189
|
-
* @
|
|
7190
|
-
* @
|
|
7322
|
+
* @param {Document|Element} elem - Target element.
|
|
7323
|
+
* @returns {TinyHtml|null} A TinyHtml instance wrapping the matched element.
|
|
7191
7324
|
*/
|
|
7192
|
-
static query(selector) {
|
|
7193
|
-
const newEl =
|
|
7194
|
-
if (!newEl)
|
|
7325
|
+
static query(selector, elem = document) {
|
|
7326
|
+
const newEl = elem.querySelector(selector);
|
|
7327
|
+
if (!newEl) return null;
|
|
7195
7328
|
return new TinyHtml_TinyHtml(newEl);
|
|
7196
7329
|
}
|
|
7197
7330
|
|
|
7331
|
+
/**
|
|
7332
|
+
* Queries the element for the first element matching the CSS selector and wraps it in a TinyHtml instance.
|
|
7333
|
+
*
|
|
7334
|
+
* @param {string} selector - A valid CSS selector string.
|
|
7335
|
+
* @returns {TinyHtml|null} A TinyHtml instance wrapping the matched element.
|
|
7336
|
+
*/
|
|
7337
|
+
querySelector(selector) {
|
|
7338
|
+
return TinyHtml_TinyHtml.query(selector, TinyHtml_TinyHtml._preElem(this, 'query'));
|
|
7339
|
+
}
|
|
7340
|
+
|
|
7198
7341
|
/**
|
|
7199
7342
|
* Queries the document for all elements matching the CSS selector and wraps them in TinyHtml instances.
|
|
7200
7343
|
*
|
|
7201
7344
|
* @param {string} selector - A valid CSS selector string.
|
|
7345
|
+
* @param {Document|Element} elem - Target element.
|
|
7202
7346
|
* @returns {TinyHtml[]} An array of TinyHtml instances wrapping the matched elements.
|
|
7203
7347
|
*/
|
|
7204
|
-
static queryAll(selector) {
|
|
7205
|
-
const newEls =
|
|
7348
|
+
static queryAll(selector, elem = document) {
|
|
7349
|
+
const newEls = elem.querySelectorAll(selector);
|
|
7206
7350
|
return TinyHtml_TinyHtml.toTinyElm([...newEls]);
|
|
7207
7351
|
}
|
|
7208
7352
|
|
|
7353
|
+
/**
|
|
7354
|
+
* Queries the element for all elements matching the CSS selector and wraps them in TinyHtml instances.
|
|
7355
|
+
*
|
|
7356
|
+
* @param {string} selector - A valid CSS selector string.
|
|
7357
|
+
* @returns {TinyHtml[]} An array of TinyHtml instances wrapping the matched elements.
|
|
7358
|
+
*/
|
|
7359
|
+
querySelectorAll(selector) {
|
|
7360
|
+
return TinyHtml_TinyHtml.queryAll(selector, TinyHtml_TinyHtml._preElem(this, 'queryAll'));
|
|
7361
|
+
}
|
|
7362
|
+
|
|
7209
7363
|
/**
|
|
7210
7364
|
* Retrieves an element by its ID and wraps it in a TinyHtml instance.
|
|
7211
7365
|
*
|
|
7212
7366
|
* @param {string} selector - The ID of the element to retrieve.
|
|
7213
|
-
* @returns {TinyHtml} A TinyHtml instance wrapping the found element.
|
|
7214
|
-
* @throws {Error} If no element is found with the specified ID.
|
|
7367
|
+
* @returns {TinyHtml|null} A TinyHtml instance wrapping the found element.
|
|
7215
7368
|
*/
|
|
7216
7369
|
static getById(selector) {
|
|
7217
7370
|
const newEl = document.getElementById(selector);
|
|
7218
|
-
if (!newEl)
|
|
7371
|
+
if (!newEl) return null;
|
|
7219
7372
|
return new TinyHtml_TinyHtml(newEl);
|
|
7220
7373
|
}
|
|
7221
7374
|
|
|
@@ -7223,13 +7376,24 @@ class TinyHtml_TinyHtml {
|
|
|
7223
7376
|
* Retrieves all elements with the specified class name and wraps them in TinyHtml instances.
|
|
7224
7377
|
*
|
|
7225
7378
|
* @param {string} selector - The class name to search for.
|
|
7379
|
+
* @param {Document|Element} elem - Target element.
|
|
7226
7380
|
* @returns {TinyHtml[]} An array of TinyHtml instances wrapping the found elements.
|
|
7227
7381
|
*/
|
|
7228
|
-
static getByClassName(selector) {
|
|
7229
|
-
const newEls =
|
|
7382
|
+
static getByClassName(selector, elem = document) {
|
|
7383
|
+
const newEls = elem.getElementsByClassName(selector);
|
|
7230
7384
|
return TinyHtml_TinyHtml.toTinyElm([...newEls]);
|
|
7231
7385
|
}
|
|
7232
7386
|
|
|
7387
|
+
/**
|
|
7388
|
+
* Retrieves all elements with the specified class name and wraps them in TinyHtml instances.
|
|
7389
|
+
*
|
|
7390
|
+
* @param {string} selector - The class name to search for.
|
|
7391
|
+
* @returns {TinyHtml[]} An array of TinyHtml instances wrapping the found elements.
|
|
7392
|
+
*/
|
|
7393
|
+
getElementsByClassName(selector) {
|
|
7394
|
+
return TinyHtml_TinyHtml.getByClassName(selector, TinyHtml_TinyHtml._preElem(this, 'getByClassName'));
|
|
7395
|
+
}
|
|
7396
|
+
|
|
7233
7397
|
/**
|
|
7234
7398
|
* Retrieves all elements with the specified name attribute and wraps them in TinyHtml instances.
|
|
7235
7399
|
*
|
|
@@ -7247,13 +7411,30 @@ class TinyHtml_TinyHtml {
|
|
|
7247
7411
|
*
|
|
7248
7412
|
* @param {string} localName - The local name (tag) of the elements to search for.
|
|
7249
7413
|
* @param {string|null} [namespaceURI='http://www.w3.org/1999/xhtml'] - The namespace URI to search within.
|
|
7414
|
+
* @param {Document|Element} elem - Target element.
|
|
7250
7415
|
* @returns {TinyHtml[]} An array of TinyHtml instances wrapping the found elements.
|
|
7251
7416
|
*/
|
|
7252
|
-
static getByTagNameNS(localName, namespaceURI = 'http://www.w3.org/1999/xhtml') {
|
|
7253
|
-
const newEls =
|
|
7417
|
+
static getByTagNameNS(localName, namespaceURI = 'http://www.w3.org/1999/xhtml', elem = document) {
|
|
7418
|
+
const newEls = elem.getElementsByTagNameNS(namespaceURI, localName);
|
|
7254
7419
|
return TinyHtml_TinyHtml.toTinyElm([...newEls]);
|
|
7255
7420
|
}
|
|
7256
7421
|
|
|
7422
|
+
/**
|
|
7423
|
+
* Retrieves all elements with the specified local tag name within the given namespace URI,
|
|
7424
|
+
* and wraps them in TinyHtml instances.
|
|
7425
|
+
*
|
|
7426
|
+
* @param {string} localName - The local name (tag) of the elements to search for.
|
|
7427
|
+
* @param {string|null} [namespaceURI='http://www.w3.org/1999/xhtml'] - The namespace URI to search within.
|
|
7428
|
+
* @returns {TinyHtml[]} An array of TinyHtml instances wrapping the found elements.
|
|
7429
|
+
*/
|
|
7430
|
+
getElementsByTagNameNS(localName, namespaceURI = 'http://www.w3.org/1999/xhtml') {
|
|
7431
|
+
return TinyHtml_TinyHtml.getByTagNameNS(
|
|
7432
|
+
localName,
|
|
7433
|
+
namespaceURI,
|
|
7434
|
+
TinyHtml_TinyHtml._preElem(this, 'getByTagNameNS'),
|
|
7435
|
+
);
|
|
7436
|
+
}
|
|
7437
|
+
|
|
7257
7438
|
//////////////////////////////////////////////////////////////////
|
|
7258
7439
|
|
|
7259
7440
|
/**
|
|
@@ -7534,6 +7715,45 @@ class TinyHtml_TinyHtml {
|
|
|
7534
7715
|
return TinyHtml_TinyHtml._preElemTemplate(elems, where, [Element, Window], ['Element', 'Window']);
|
|
7535
7716
|
}
|
|
7536
7717
|
|
|
7718
|
+
/**
|
|
7719
|
+
* Ensures the input is returned as an array.
|
|
7720
|
+
* Useful to normalize operations across multiple or single element/window/document elements.
|
|
7721
|
+
*
|
|
7722
|
+
* @param {TinyElementAndWinAndDoc|TinyElementAndWinAndDoc[]} elems - A single element/window element or array of html elements.
|
|
7723
|
+
* @param {string} where - The method or context name where validation is being called.
|
|
7724
|
+
* @returns {ElementAndWindow[]} - Always returns an array of element/window elements.
|
|
7725
|
+
* @readonly
|
|
7726
|
+
*/
|
|
7727
|
+
static _preElemsAndWinAndDoc(elems, where) {
|
|
7728
|
+
const result = TinyHtml_TinyHtml._preElemsTemplate(
|
|
7729
|
+
elems,
|
|
7730
|
+
where,
|
|
7731
|
+
[Element, Window, Document],
|
|
7732
|
+
['Element', 'Window', 'Document'],
|
|
7733
|
+
);
|
|
7734
|
+
return result.map((elem) => (!(elem instanceof Document) ? elem : elem.documentElement));
|
|
7735
|
+
}
|
|
7736
|
+
|
|
7737
|
+
/**
|
|
7738
|
+
* Ensures the input is returned as an single element/window/document element.
|
|
7739
|
+
* Useful to normalize operations across multiple or single element/window/document elements.
|
|
7740
|
+
*
|
|
7741
|
+
* @param {TinyElementAndWinAndDoc|TinyElementAndWinAndDoc[]} elems - A single element/window element or array of html elements.
|
|
7742
|
+
* @param {string} where - The method or context name where validation is being called.
|
|
7743
|
+
* @returns {ElementAndWindow} - Always returns an single element/window element.
|
|
7744
|
+
* @readonly
|
|
7745
|
+
*/
|
|
7746
|
+
static _preElemAndWinAndDoc(elems, where) {
|
|
7747
|
+
const result = TinyHtml_TinyHtml._preElemTemplate(
|
|
7748
|
+
elems,
|
|
7749
|
+
where,
|
|
7750
|
+
[Element, Window, Document],
|
|
7751
|
+
['Element', 'Window', 'Document'],
|
|
7752
|
+
);
|
|
7753
|
+
if (result instanceof Document) return result.documentElement;
|
|
7754
|
+
return result;
|
|
7755
|
+
}
|
|
7756
|
+
|
|
7537
7757
|
/**
|
|
7538
7758
|
* Normalizes and converts one or more DOM elements (or TinyHtml instances)
|
|
7539
7759
|
* into an array of `TinyHtml` instances.
|
|
@@ -7880,12 +8100,13 @@ class TinyHtml_TinyHtml {
|
|
|
7880
8100
|
* @param {string} key - The key under which the data will be stored.
|
|
7881
8101
|
* @param {any} value - The value to store.
|
|
7882
8102
|
* @param {boolean} [isPrivate=false] - Whether to store the data in the private store.
|
|
7883
|
-
* @returns {
|
|
8103
|
+
* @returns {TinyElement}
|
|
7884
8104
|
*/
|
|
7885
8105
|
static setData(el, key, value, isPrivate = false) {
|
|
7886
8106
|
const data = TinyHtml_TinyHtml._dataSelector[!isPrivate ? 'public' : 'private']('setData', el);
|
|
7887
8107
|
if (typeof key !== 'string') throw new TypeError('The key must be a string.');
|
|
7888
8108
|
data[key] = value;
|
|
8109
|
+
return el;
|
|
7889
8110
|
}
|
|
7890
8111
|
|
|
7891
8112
|
/**
|
|
@@ -7894,7 +8115,7 @@ class TinyHtml_TinyHtml {
|
|
|
7894
8115
|
* @param {string} key - The key under which the data will be stored.
|
|
7895
8116
|
* @param {any} value - The value to store.
|
|
7896
8117
|
* @param {boolean} [isPrivate=false] - Whether to store the data in the private store.
|
|
7897
|
-
* @returns {
|
|
8118
|
+
* @returns {TinyElement}
|
|
7898
8119
|
*/
|
|
7899
8120
|
setData(key, value, isPrivate = false) {
|
|
7900
8121
|
return TinyHtml_TinyHtml.setData(this, key, value, isPrivate);
|
|
@@ -8241,18 +8462,21 @@ class TinyHtml_TinyHtml {
|
|
|
8241
8462
|
/**
|
|
8242
8463
|
* Appends child elements or strings to the end of the target element(s).
|
|
8243
8464
|
*
|
|
8244
|
-
* @param {TinyElement
|
|
8465
|
+
* @param {TinyElement} el - The target element(s) to receive children.
|
|
8245
8466
|
* @param {...(TinyNode | TinyNode[] | string)} children - The child elements or text to append.
|
|
8467
|
+
* @returns {TinyElement}
|
|
8246
8468
|
*/
|
|
8247
8469
|
static append(el, ...children) {
|
|
8248
8470
|
const elem = TinyHtml_TinyHtml._preElem(el, 'append');
|
|
8249
8471
|
elem.append(...TinyHtml_TinyHtml._appendChecker('append', ...children));
|
|
8472
|
+
return el;
|
|
8250
8473
|
}
|
|
8251
8474
|
|
|
8252
8475
|
/**
|
|
8253
8476
|
* Appends child elements or strings to the end of the target element(s).
|
|
8254
8477
|
*
|
|
8255
8478
|
* @param {...(TinyNode | TinyNode[] | string)} children - The child elements or text to append.
|
|
8479
|
+
* @returns {TinyElement}
|
|
8256
8480
|
*/
|
|
8257
8481
|
append(...children) {
|
|
8258
8482
|
return TinyHtml_TinyHtml.append(this, ...children);
|
|
@@ -8261,18 +8485,21 @@ class TinyHtml_TinyHtml {
|
|
|
8261
8485
|
/**
|
|
8262
8486
|
* Prepends child elements or strings to the beginning of the target element(s).
|
|
8263
8487
|
*
|
|
8264
|
-
* @param {TinyElement
|
|
8488
|
+
* @param {TinyElement} el - The target element(s) to receive children.
|
|
8265
8489
|
* @param {...(TinyNode | TinyNode[] | string)} children - The child elements or text to prepend.
|
|
8490
|
+
* @returns {TinyElement}
|
|
8266
8491
|
*/
|
|
8267
8492
|
static prepend(el, ...children) {
|
|
8268
8493
|
const elem = TinyHtml_TinyHtml._preElem(el, 'prepend');
|
|
8269
8494
|
elem.prepend(...TinyHtml_TinyHtml._appendChecker('prepend', ...children));
|
|
8495
|
+
return el;
|
|
8270
8496
|
}
|
|
8271
8497
|
|
|
8272
8498
|
/**
|
|
8273
8499
|
* Prepends child elements or strings to the beginning of the target element(s).
|
|
8274
8500
|
*
|
|
8275
8501
|
* @param {...(TinyNode | TinyNode[] | string)} children - The child elements or text to prepend.
|
|
8502
|
+
* @returns {TinyElement}
|
|
8276
8503
|
*/
|
|
8277
8504
|
prepend(...children) {
|
|
8278
8505
|
return TinyHtml_TinyHtml.prepend(this, ...children);
|
|
@@ -8281,18 +8508,21 @@ class TinyHtml_TinyHtml {
|
|
|
8281
8508
|
/**
|
|
8282
8509
|
* Inserts elements or strings immediately before the target element(s) in the DOM.
|
|
8283
8510
|
*
|
|
8284
|
-
* @param {TinyElement
|
|
8511
|
+
* @param {TinyElement} el - The target element(s) before which new content is inserted.
|
|
8285
8512
|
* @param {...(TinyNode | TinyNode[] | string)} children - Elements or text to insert before the target.
|
|
8513
|
+
* @returns {TinyElement}
|
|
8286
8514
|
*/
|
|
8287
8515
|
static before(el, ...children) {
|
|
8288
8516
|
const elem = TinyHtml_TinyHtml._preElem(el, 'before');
|
|
8289
8517
|
elem.before(...TinyHtml_TinyHtml._appendChecker('before', ...children));
|
|
8518
|
+
return el;
|
|
8290
8519
|
}
|
|
8291
8520
|
|
|
8292
8521
|
/**
|
|
8293
8522
|
* Inserts elements or strings immediately before the target element(s) in the DOM.
|
|
8294
8523
|
*
|
|
8295
8524
|
* @param {...(TinyNode | TinyNode[] | string)} children - Elements or text to insert before the target.
|
|
8525
|
+
* @returns {TinyElement}
|
|
8296
8526
|
*/
|
|
8297
8527
|
before(...children) {
|
|
8298
8528
|
return TinyHtml_TinyHtml.before(this, ...children);
|
|
@@ -8301,18 +8531,21 @@ class TinyHtml_TinyHtml {
|
|
|
8301
8531
|
/**
|
|
8302
8532
|
* Inserts elements or strings immediately after the target element(s) in the DOM.
|
|
8303
8533
|
*
|
|
8304
|
-
* @param {TinyElement
|
|
8534
|
+
* @param {TinyElement} el - The target element(s) after which new content is inserted.
|
|
8305
8535
|
* @param {...(TinyNode | TinyNode[] | string)} children - Elements or text to insert after the target.
|
|
8536
|
+
* @returns {TinyElement}
|
|
8306
8537
|
*/
|
|
8307
8538
|
static after(el, ...children) {
|
|
8308
8539
|
const elem = TinyHtml_TinyHtml._preElem(el, 'after');
|
|
8309
8540
|
elem.after(...TinyHtml_TinyHtml._appendChecker('after', ...children));
|
|
8541
|
+
return el;
|
|
8310
8542
|
}
|
|
8311
8543
|
|
|
8312
8544
|
/**
|
|
8313
8545
|
* Inserts elements or strings immediately after the target element(s) in the DOM.
|
|
8314
8546
|
*
|
|
8315
8547
|
* @param {...(TinyNode | TinyNode[] | string)} children - Elements or text to insert after the target.
|
|
8548
|
+
* @returns {TinyElement}
|
|
8316
8549
|
*/
|
|
8317
8550
|
after(...children) {
|
|
8318
8551
|
return TinyHtml_TinyHtml.after(this, ...children);
|
|
@@ -8321,18 +8554,21 @@ class TinyHtml_TinyHtml {
|
|
|
8321
8554
|
/**
|
|
8322
8555
|
* Replaces the target element(s) in the DOM with new elements or text.
|
|
8323
8556
|
*
|
|
8324
|
-
* @param {TinyElement
|
|
8557
|
+
* @param {TinyElement} el - The element(s) to be replaced.
|
|
8325
8558
|
* @param {...(TinyNode | TinyNode[] | string)} newNodes - New elements or text to replace the target.
|
|
8559
|
+
* @returns {TinyElement}
|
|
8326
8560
|
*/
|
|
8327
8561
|
static replaceWith(el, ...newNodes) {
|
|
8328
8562
|
const elem = TinyHtml_TinyHtml._preElem(el, 'replaceWith');
|
|
8329
8563
|
elem.replaceWith(...TinyHtml_TinyHtml._appendChecker('replaceWith', ...newNodes));
|
|
8564
|
+
return el;
|
|
8330
8565
|
}
|
|
8331
8566
|
|
|
8332
8567
|
/**
|
|
8333
8568
|
* Replaces the target element(s) in the DOM with new elements or text.
|
|
8334
8569
|
*
|
|
8335
8570
|
* @param {...(TinyNode | TinyNode[] | string)} newNodes - New elements or text to replace the target.
|
|
8571
|
+
* @returns {TinyElement}
|
|
8336
8572
|
*/
|
|
8337
8573
|
replaceWith(...newNodes) {
|
|
8338
8574
|
return TinyHtml_TinyHtml.replaceWith(this, ...newNodes);
|
|
@@ -8343,6 +8579,7 @@ class TinyHtml_TinyHtml {
|
|
|
8343
8579
|
*
|
|
8344
8580
|
* @param {TinyNode | TinyNode[]} el - The element(s) to append.
|
|
8345
8581
|
* @param {TinyNode | TinyNode[]} targets - Target element(s) where content will be appended.
|
|
8582
|
+
* @returns {TinyNode|TinyNode[]}
|
|
8346
8583
|
*/
|
|
8347
8584
|
static appendTo(el, targets) {
|
|
8348
8585
|
const elems = TinyHtml_TinyHtml._preNodeElems(el, 'appendTo');
|
|
@@ -8352,12 +8589,14 @@ class TinyHtml_TinyHtml {
|
|
|
8352
8589
|
target.appendChild(i === tars.length - 1 ? elem : elem.cloneNode(true)),
|
|
8353
8590
|
);
|
|
8354
8591
|
});
|
|
8592
|
+
return el;
|
|
8355
8593
|
}
|
|
8356
8594
|
|
|
8357
8595
|
/**
|
|
8358
8596
|
* Appends the given element(s) to each target element in sequence.
|
|
8359
8597
|
*
|
|
8360
8598
|
* @param {TinyNode | TinyNode[]} targets - Target element(s) where content will be appended.
|
|
8599
|
+
* @returns {TinyNode|TinyNode[]}
|
|
8361
8600
|
*/
|
|
8362
8601
|
appendTo(targets) {
|
|
8363
8602
|
return TinyHtml_TinyHtml.appendTo(this, targets);
|
|
@@ -8368,6 +8607,7 @@ class TinyHtml_TinyHtml {
|
|
|
8368
8607
|
*
|
|
8369
8608
|
* @param {TinyElement | TinyElement[]} el - The element(s) to prepend.
|
|
8370
8609
|
* @param {TinyElement | TinyElement[]} targets - Target element(s) where content will be prepended.
|
|
8610
|
+
* @returns {TinyElement|TinyElement[]}
|
|
8371
8611
|
*/
|
|
8372
8612
|
static prependTo(el, targets) {
|
|
8373
8613
|
const elems = TinyHtml_TinyHtml._preElems(el, 'prependTo');
|
|
@@ -8378,12 +8618,14 @@ class TinyHtml_TinyHtml {
|
|
|
8378
8618
|
.reverse()
|
|
8379
8619
|
.forEach((elem) => target.prepend(i === tars.length - 1 ? elem : elem.cloneNode(true)));
|
|
8380
8620
|
});
|
|
8621
|
+
return el;
|
|
8381
8622
|
}
|
|
8382
8623
|
|
|
8383
8624
|
/**
|
|
8384
8625
|
* Prepends the given element(s) to each target element in sequence.
|
|
8385
8626
|
*
|
|
8386
8627
|
* @param {TinyElement | TinyElement[]} targets - Target element(s) where content will be prepended.
|
|
8628
|
+
* @returns {TinyElement|TinyElement[]}
|
|
8387
8629
|
*/
|
|
8388
8630
|
prependTo(targets) {
|
|
8389
8631
|
return TinyHtml_TinyHtml.prependTo(this, targets);
|
|
@@ -8395,6 +8637,7 @@ class TinyHtml_TinyHtml {
|
|
|
8395
8637
|
* @param {TinyNode | TinyNode[]} el - The element(s) to insert.
|
|
8396
8638
|
* @param {TinyNode | TinyNode[]} target - The reference element where insertion happens.
|
|
8397
8639
|
* @param {TinyNode | TinyNode[] | null} [child=null] - Optional child to insert before, defaults to target.
|
|
8640
|
+
* @returns {TinyNode|TinyNode[]}
|
|
8398
8641
|
*/
|
|
8399
8642
|
static insertBefore(el, target, child = null) {
|
|
8400
8643
|
const elem = TinyHtml_TinyHtml._preNodeElem(el, 'insertBefore');
|
|
@@ -8402,6 +8645,7 @@ class TinyHtml_TinyHtml {
|
|
|
8402
8645
|
const childNode = TinyHtml_TinyHtml._preNodeElemWithNull(child, 'insertBefore');
|
|
8403
8646
|
if (!targ.parentNode) throw new Error('');
|
|
8404
8647
|
targ.parentNode.insertBefore(elem, childNode || targ);
|
|
8648
|
+
return el;
|
|
8405
8649
|
}
|
|
8406
8650
|
|
|
8407
8651
|
/**
|
|
@@ -8409,6 +8653,7 @@ class TinyHtml_TinyHtml {
|
|
|
8409
8653
|
*
|
|
8410
8654
|
* @param {TinyNode | TinyNode[]} target - The reference element where insertion happens.
|
|
8411
8655
|
* @param {TinyNode | TinyNode[] | null} [child=null] - Optional child to insert before, defaults to target.
|
|
8656
|
+
* @returns {TinyNode|TinyNode[]}
|
|
8412
8657
|
*/
|
|
8413
8658
|
insertBefore(target, child) {
|
|
8414
8659
|
return TinyHtml_TinyHtml.insertBefore(this, target, child);
|
|
@@ -8420,6 +8665,7 @@ class TinyHtml_TinyHtml {
|
|
|
8420
8665
|
* @param {TinyNode | TinyNode[]} el - The element(s) to insert.
|
|
8421
8666
|
* @param {TinyNode | TinyNode[]} target - The reference element where insertion happens.
|
|
8422
8667
|
* @param {TinyNode | TinyNode[] | null} [child=null] - Optional child to insert after, defaults to target.
|
|
8668
|
+
* @returns {TinyNode|TinyNode[]}
|
|
8423
8669
|
*/
|
|
8424
8670
|
static insertAfter(el, target, child = null) {
|
|
8425
8671
|
const elem = TinyHtml_TinyHtml._preNodeElem(el, 'insertAfter');
|
|
@@ -8427,6 +8673,7 @@ class TinyHtml_TinyHtml {
|
|
|
8427
8673
|
const childNode = TinyHtml_TinyHtml._preNodeElemWithNull(child, 'insertBefore');
|
|
8428
8674
|
if (!targ.parentNode) throw new Error('');
|
|
8429
8675
|
targ.parentNode.insertBefore(elem, childNode || targ.nextSibling);
|
|
8676
|
+
return el;
|
|
8430
8677
|
}
|
|
8431
8678
|
|
|
8432
8679
|
/**
|
|
@@ -8434,6 +8681,7 @@ class TinyHtml_TinyHtml {
|
|
|
8434
8681
|
*
|
|
8435
8682
|
* @param {TinyNode | TinyNode[]} target - The reference element where insertion happens.
|
|
8436
8683
|
* @param {TinyNode | TinyNode[] | null} [child=null] - Optional child to insert after, defaults to target.
|
|
8684
|
+
* @returns {TinyNode|TinyNode[]}
|
|
8437
8685
|
*/
|
|
8438
8686
|
insertAfter(target, child) {
|
|
8439
8687
|
return TinyHtml_TinyHtml.insertAfter(this, target, child);
|
|
@@ -8445,6 +8693,7 @@ class TinyHtml_TinyHtml {
|
|
|
8445
8693
|
*
|
|
8446
8694
|
* @param {TinyNode | TinyNode[]} el - The new element(s) to insert.
|
|
8447
8695
|
* @param {TinyNode | TinyNode[]} targets - The elements to be replaced.
|
|
8696
|
+
* @returns {TinyNode|TinyNode[]}
|
|
8448
8697
|
*/
|
|
8449
8698
|
static replaceAll(el, targets) {
|
|
8450
8699
|
const elems = TinyHtml_TinyHtml._preNodeElems(el, 'replaceAll');
|
|
@@ -8456,6 +8705,7 @@ class TinyHtml_TinyHtml {
|
|
|
8456
8705
|
parent.replaceChild(i === tars.length - 1 ? elem : elem.cloneNode(true), target);
|
|
8457
8706
|
});
|
|
8458
8707
|
});
|
|
8708
|
+
return el;
|
|
8459
8709
|
}
|
|
8460
8710
|
|
|
8461
8711
|
/**
|
|
@@ -8463,6 +8713,7 @@ class TinyHtml_TinyHtml {
|
|
|
8463
8713
|
* If multiple targets exist, the inserted elements are cloned accordingly.
|
|
8464
8714
|
*
|
|
8465
8715
|
* @param {TinyNode | TinyNode[]} targets - The elements to be replaced.
|
|
8716
|
+
* @returns {TinyNode|TinyNode[]}
|
|
8466
8717
|
*/
|
|
8467
8718
|
replaceAll(targets) {
|
|
8468
8719
|
return TinyHtml_TinyHtml.replaceAll(this, targets);
|
|
@@ -8486,7 +8737,12 @@ class TinyHtml_TinyHtml {
|
|
|
8486
8737
|
throw new Error(
|
|
8487
8738
|
`[TinyHtml] You are trying to put a TinyHtml inside another TinyHtml in constructor.`,
|
|
8488
8739
|
);
|
|
8489
|
-
if (
|
|
8740
|
+
if (
|
|
8741
|
+
!(el instanceof Element) &&
|
|
8742
|
+
!(el instanceof Window) &&
|
|
8743
|
+
!(el instanceof Document) &&
|
|
8744
|
+
!(el instanceof Text)
|
|
8745
|
+
)
|
|
8490
8746
|
throw new Error(`[TinyHtml] Invalid Target in constructor.`);
|
|
8491
8747
|
this.#el = el;
|
|
8492
8748
|
}
|
|
@@ -8936,6 +9192,7 @@ class TinyHtml_TinyHtml {
|
|
|
8936
9192
|
* @param {TinyHtmlElement|TinyHtmlElement[]} el - The element to inspect.
|
|
8937
9193
|
* @param {string|Object} prop - The property name or an object with key-value pairs
|
|
8938
9194
|
* @param {string|null} [value=null] - The value to set (if `prop` is a string)
|
|
9195
|
+
* @returns {TinyHtmlElement|TinyHtmlElement[]}
|
|
8939
9196
|
*/
|
|
8940
9197
|
static setStyle(el, prop, value = null) {
|
|
8941
9198
|
TinyHtml_TinyHtml._preHtmlElems(el, 'setStyle').forEach((elem) => {
|
|
@@ -8948,6 +9205,7 @@ class TinyHtml_TinyHtml {
|
|
|
8948
9205
|
}
|
|
8949
9206
|
} else elem.style.setProperty(TinyHtml_TinyHtml.toStyleKc(prop), value);
|
|
8950
9207
|
});
|
|
9208
|
+
return el;
|
|
8951
9209
|
}
|
|
8952
9210
|
|
|
8953
9211
|
/**
|
|
@@ -8958,6 +9216,7 @@ class TinyHtml_TinyHtml {
|
|
|
8958
9216
|
*
|
|
8959
9217
|
* @param {string|Object} prop - The property name or an object with key-value pairs
|
|
8960
9218
|
* @param {string|null} [value=null] - The value to set (if `prop` is a string)
|
|
9219
|
+
* @returns {TinyHtmlElement|TinyHtmlElement[]}
|
|
8961
9220
|
*/
|
|
8962
9221
|
setStyle(prop, value) {
|
|
8963
9222
|
return TinyHtml_TinyHtml.setStyle(this, prop, value);
|
|
@@ -9053,6 +9312,7 @@ class TinyHtml_TinyHtml {
|
|
|
9053
9312
|
*
|
|
9054
9313
|
* @param {TinyHtmlElement|TinyHtmlElement[]} el - A single element or an array of elements.
|
|
9055
9314
|
* @param {string|string[]} prop - A property name or an array of property names to remove.
|
|
9315
|
+
* @returns {TinyHtmlElement|TinyHtmlElement[]}
|
|
9056
9316
|
*/
|
|
9057
9317
|
static removeStyle(el, prop) {
|
|
9058
9318
|
TinyHtml_TinyHtml._preHtmlElems(el, 'removeStyle').forEach((elem) => {
|
|
@@ -9062,12 +9322,14 @@ class TinyHtml_TinyHtml {
|
|
|
9062
9322
|
}
|
|
9063
9323
|
} else elem.style.removeProperty(TinyHtml_TinyHtml.toStyleKc(prop));
|
|
9064
9324
|
});
|
|
9325
|
+
return el;
|
|
9065
9326
|
}
|
|
9066
9327
|
|
|
9067
9328
|
/**
|
|
9068
9329
|
* Removes one or more inline CSS properties from the given element(s).
|
|
9069
9330
|
*
|
|
9070
9331
|
* @param {string|string[]} prop - A property name or an array of property names to remove.
|
|
9332
|
+
* @returns {TinyHtmlElement|TinyHtmlElement[]}
|
|
9071
9333
|
*/
|
|
9072
9334
|
removeStyle(prop) {
|
|
9073
9335
|
return TinyHtml_TinyHtml.removeStyle(this, prop);
|
|
@@ -9082,6 +9344,7 @@ class TinyHtml_TinyHtml {
|
|
|
9082
9344
|
* @param {string} prop - The CSS property to toggle.
|
|
9083
9345
|
* @param {string} val1 - The first value (used as "current" check).
|
|
9084
9346
|
* @param {string} val2 - The second value (used as the "alternative").
|
|
9347
|
+
* @returns {TinyHtmlElement|TinyHtmlElement[]}
|
|
9085
9348
|
*/
|
|
9086
9349
|
static toggleStyle(el, prop, val1, val2) {
|
|
9087
9350
|
TinyHtml_TinyHtml._preHtmlElems(el, 'toggleStyle').forEach((elem) => {
|
|
@@ -9089,6 +9352,7 @@ class TinyHtml_TinyHtml {
|
|
|
9089
9352
|
const newVal = current === TinyHtml_TinyHtml.toStyleKc(val1) ? val2 : val1;
|
|
9090
9353
|
TinyHtml_TinyHtml.setStyle(elem, prop, newVal);
|
|
9091
9354
|
});
|
|
9355
|
+
return el;
|
|
9092
9356
|
}
|
|
9093
9357
|
|
|
9094
9358
|
/**
|
|
@@ -9099,6 +9363,7 @@ class TinyHtml_TinyHtml {
|
|
|
9099
9363
|
* @param {string} prop - The CSS property to toggle.
|
|
9100
9364
|
* @param {string} val1 - The first value (used as "current" check).
|
|
9101
9365
|
* @param {string} val2 - The second value (used as the "alternative").
|
|
9366
|
+
* @returns {TinyHtmlElement|TinyHtmlElement[]}
|
|
9102
9367
|
*/
|
|
9103
9368
|
toggleStyle(prop, val1, val2) {
|
|
9104
9369
|
return TinyHtml_TinyHtml.toggleStyle(this, prop, val1, val2);
|
|
@@ -9108,14 +9373,16 @@ class TinyHtml_TinyHtml {
|
|
|
9108
9373
|
* Removes all inline styles (`style` attribute) from the given element(s).
|
|
9109
9374
|
*
|
|
9110
9375
|
* @param {TinyElement|TinyElement[]} el - A single element or an array of elements.
|
|
9376
|
+
* @returns {TinyElement|TinyElement[]}
|
|
9111
9377
|
*/
|
|
9112
9378
|
static clearStyle(el) {
|
|
9113
9379
|
TinyHtml_TinyHtml._preElems(el, 'clearStyle').forEach((elem) => elem.removeAttribute('style'));
|
|
9380
|
+
return el;
|
|
9114
9381
|
}
|
|
9115
9382
|
|
|
9116
9383
|
/**
|
|
9117
9384
|
* Removes all inline styles (`style` attribute) from the given element(s).
|
|
9118
|
-
*
|
|
9385
|
+
* @returns {TinyElement|TinyElement[]}
|
|
9119
9386
|
*/
|
|
9120
9387
|
clearStyle() {
|
|
9121
9388
|
return TinyHtml_TinyHtml.clearStyle(this);
|
|
@@ -9127,14 +9394,17 @@ class TinyHtml_TinyHtml {
|
|
|
9127
9394
|
* Focus the element.
|
|
9128
9395
|
*
|
|
9129
9396
|
* @param {TinyHtmlElement} el - The element or a selector string.
|
|
9397
|
+
* @returns {TinyHtmlElement}
|
|
9130
9398
|
*/
|
|
9131
9399
|
static focus(el) {
|
|
9132
9400
|
const elem = TinyHtml_TinyHtml._preHtmlElem(el, 'focus');
|
|
9133
9401
|
elem.focus();
|
|
9402
|
+
return el;
|
|
9134
9403
|
}
|
|
9135
9404
|
|
|
9136
9405
|
/**
|
|
9137
9406
|
* Focus the element.
|
|
9407
|
+
* @returns {TinyHtmlElement}
|
|
9138
9408
|
*/
|
|
9139
9409
|
focus() {
|
|
9140
9410
|
return TinyHtml_TinyHtml.focus(this);
|
|
@@ -9144,19 +9414,46 @@ class TinyHtml_TinyHtml {
|
|
|
9144
9414
|
* Blur the element.
|
|
9145
9415
|
*
|
|
9146
9416
|
* @param {TinyHtmlElement} el - The element or a selector string.
|
|
9417
|
+
* @returns {TinyHtmlElement}
|
|
9147
9418
|
*/
|
|
9148
9419
|
static blur(el) {
|
|
9149
9420
|
const elem = TinyHtml_TinyHtml._preHtmlElem(el, 'blur');
|
|
9150
9421
|
elem.blur();
|
|
9422
|
+
return el;
|
|
9151
9423
|
}
|
|
9152
9424
|
|
|
9153
9425
|
/**
|
|
9154
9426
|
* Blur the element.
|
|
9427
|
+
* @returns {TinyHtmlElement}
|
|
9155
9428
|
*/
|
|
9156
9429
|
blur() {
|
|
9157
9430
|
return TinyHtml_TinyHtml.blur(this);
|
|
9158
9431
|
}
|
|
9159
9432
|
|
|
9433
|
+
/**
|
|
9434
|
+
* Interprets a value as a boolean `true` if it matches a common truthy representation.
|
|
9435
|
+
*
|
|
9436
|
+
* This method checks if the input is any of the common forms used to represent `true`,
|
|
9437
|
+
* such as the string `'true'`, `'1'`, `'on'`, the boolean `true`, or the number `1`.
|
|
9438
|
+
*
|
|
9439
|
+
* @param {string|boolean|number} [value] - The value to interpret as boolean.
|
|
9440
|
+
* @returns {boolean} `true` if the value represents a truthy state, otherwise `false`.
|
|
9441
|
+
*/
|
|
9442
|
+
static boolCheck(value) {
|
|
9443
|
+
if (
|
|
9444
|
+
typeof value !== 'undefined' &&
|
|
9445
|
+
(value === 'true' ||
|
|
9446
|
+
value === '1' ||
|
|
9447
|
+
value === true ||
|
|
9448
|
+
value === 'on' ||
|
|
9449
|
+
(typeof value === 'number' && value > 0))
|
|
9450
|
+
) {
|
|
9451
|
+
return true;
|
|
9452
|
+
} else {
|
|
9453
|
+
return false;
|
|
9454
|
+
}
|
|
9455
|
+
}
|
|
9456
|
+
|
|
9160
9457
|
//////////////////////////////////////////////////////////////////////
|
|
9161
9458
|
|
|
9162
9459
|
/**
|
|
@@ -9165,7 +9462,7 @@ class TinyHtml_TinyHtml {
|
|
|
9165
9462
|
*/
|
|
9166
9463
|
static setWinScrollTop(value) {
|
|
9167
9464
|
if (typeof value !== 'number') throw new TypeError('The value must be a number.');
|
|
9168
|
-
|
|
9465
|
+
TinyHtml_TinyHtml.setScrollTop(window, value);
|
|
9169
9466
|
}
|
|
9170
9467
|
|
|
9171
9468
|
/**
|
|
@@ -9174,7 +9471,7 @@ class TinyHtml_TinyHtml {
|
|
|
9174
9471
|
*/
|
|
9175
9472
|
static setWinScrollLeft(value) {
|
|
9176
9473
|
if (typeof value !== 'number') throw new TypeError('The value must be a number.');
|
|
9177
|
-
|
|
9474
|
+
TinyHtml_TinyHtml.setScrollLeft(window, value);
|
|
9178
9475
|
}
|
|
9179
9476
|
|
|
9180
9477
|
/**
|
|
@@ -9209,16 +9506,40 @@ class TinyHtml_TinyHtml {
|
|
|
9209
9506
|
return window.innerWidth || document.documentElement.clientWidth;
|
|
9210
9507
|
}
|
|
9211
9508
|
|
|
9509
|
+
/**
|
|
9510
|
+
* Checks if the page is currently scrolled to the very top.
|
|
9511
|
+
*
|
|
9512
|
+
* This method compares the current vertical scroll position with the total document height.
|
|
9513
|
+
* It's useful for detecting if the user has reached the top of the page.
|
|
9514
|
+
*
|
|
9515
|
+
* @returns {boolean} `true` if the page is scrolled to the top, otherwise `false`.
|
|
9516
|
+
*/
|
|
9517
|
+
static isPageTop() {
|
|
9518
|
+
return window.scrollY === 0;
|
|
9519
|
+
}
|
|
9520
|
+
|
|
9521
|
+
/**
|
|
9522
|
+
* Checks if the page is currently scrolled to the very bottom.
|
|
9523
|
+
*
|
|
9524
|
+
* This method uses the `scrollY` and `innerHeight` properties to determine if the
|
|
9525
|
+
* user has reached the end of the document.
|
|
9526
|
+
*
|
|
9527
|
+
* @returns {boolean} `true` if the page is scrolled to the bottom, otherwise `false`.
|
|
9528
|
+
*/
|
|
9529
|
+
static isPageBottom() {
|
|
9530
|
+
return window.innerHeight + window.scrollY >= document.body.offsetHeight;
|
|
9531
|
+
}
|
|
9532
|
+
|
|
9212
9533
|
/**
|
|
9213
9534
|
* Gets the width or height of an element based on the box model.
|
|
9214
|
-
* @param {
|
|
9535
|
+
* @param {TinyElementAndWinAndDoc} el - The element or window.
|
|
9215
9536
|
* @param {"width"|"height"} type - Dimension type.
|
|
9216
9537
|
* @param {"content"|"padding"|"border"|"margin"} [extra='content'] - Box model context.
|
|
9217
9538
|
* @returns {number} - Computed dimension.
|
|
9218
9539
|
* @throws {TypeError} If `type` or `extra` is not a string.
|
|
9219
9540
|
*/
|
|
9220
9541
|
static getDimension(el, type, extra = 'content') {
|
|
9221
|
-
const elem = TinyHtml_TinyHtml.
|
|
9542
|
+
const elem = TinyHtml_TinyHtml._preElemAndWinAndDoc(el, 'getDimension');
|
|
9222
9543
|
if (typeof type !== 'string') throw new TypeError('The type must be a string.');
|
|
9223
9544
|
if (typeof extra !== 'string') throw new TypeError('The extra must be a string.');
|
|
9224
9545
|
|
|
@@ -9306,17 +9627,20 @@ class TinyHtml_TinyHtml {
|
|
|
9306
9627
|
* @param {TinyHtmlElement} el - Target element.
|
|
9307
9628
|
* @param {string|number} value - Height value.
|
|
9308
9629
|
* @throws {TypeError} If `value` is neither a string nor number.
|
|
9630
|
+
* @returns {TinyHtmlElement}
|
|
9309
9631
|
*/
|
|
9310
9632
|
static setHeight(el, value) {
|
|
9311
9633
|
const elem = TinyHtml_TinyHtml._preHtmlElem(el, 'setHeight');
|
|
9312
9634
|
if (typeof value !== 'number' && typeof value !== 'string')
|
|
9313
9635
|
throw new TypeError('The value must be a string or number.');
|
|
9314
9636
|
elem.style.height = typeof value === 'number' ? `${value}px` : value;
|
|
9637
|
+
return el;
|
|
9315
9638
|
}
|
|
9316
9639
|
|
|
9317
9640
|
/**
|
|
9318
9641
|
* Sets the height of the element.
|
|
9319
9642
|
* @param {string|number} value - Height value.
|
|
9643
|
+
* @returns {TinyHtmlElement}
|
|
9320
9644
|
*/
|
|
9321
9645
|
setHeight(value) {
|
|
9322
9646
|
return TinyHtml_TinyHtml.setHeight(this, value);
|
|
@@ -9327,17 +9651,20 @@ class TinyHtml_TinyHtml {
|
|
|
9327
9651
|
* @param {TinyHtmlElement} el - Target element.
|
|
9328
9652
|
* @param {string|number} value - Width value.
|
|
9329
9653
|
* @throws {TypeError} If `value` is neither a string nor number.
|
|
9654
|
+
* @returns {TinyHtmlElement}
|
|
9330
9655
|
*/
|
|
9331
9656
|
static setWidth(el, value) {
|
|
9332
9657
|
const elem = TinyHtml_TinyHtml._preHtmlElem(el, 'setWidth');
|
|
9333
9658
|
if (typeof value !== 'number' && typeof value !== 'string')
|
|
9334
9659
|
throw new TypeError('The value must be a string or number.');
|
|
9335
9660
|
elem.style.width = typeof value === 'number' ? `${value}px` : value;
|
|
9661
|
+
return el;
|
|
9336
9662
|
}
|
|
9337
9663
|
|
|
9338
9664
|
/**
|
|
9339
9665
|
* Sets the width of the element.
|
|
9340
9666
|
* @param {string|number} value - Width value.
|
|
9667
|
+
* @returns {TinyHtmlElement}
|
|
9341
9668
|
*/
|
|
9342
9669
|
setWidth(value) {
|
|
9343
9670
|
return TinyHtml_TinyHtml.setWidth(this, value);
|
|
@@ -9345,11 +9672,11 @@ class TinyHtml_TinyHtml {
|
|
|
9345
9672
|
|
|
9346
9673
|
/**
|
|
9347
9674
|
* Returns content box height.
|
|
9348
|
-
* @param {
|
|
9675
|
+
* @param {TinyElementAndWinAndDoc} el - Target element.
|
|
9349
9676
|
* @returns {number}
|
|
9350
9677
|
*/
|
|
9351
9678
|
static height(el) {
|
|
9352
|
-
const elem = TinyHtml_TinyHtml.
|
|
9679
|
+
const elem = TinyHtml_TinyHtml._preElemAndWinAndDoc(el, 'height');
|
|
9353
9680
|
return TinyHtml_TinyHtml.getDimension(elem, 'height', 'content');
|
|
9354
9681
|
}
|
|
9355
9682
|
|
|
@@ -9363,11 +9690,11 @@ class TinyHtml_TinyHtml {
|
|
|
9363
9690
|
|
|
9364
9691
|
/**
|
|
9365
9692
|
* Returns content box width.
|
|
9366
|
-
* @param {
|
|
9693
|
+
* @param {TinyElementAndWinAndDoc} el - Target element.
|
|
9367
9694
|
* @returns {number}
|
|
9368
9695
|
*/
|
|
9369
9696
|
static width(el) {
|
|
9370
|
-
const elem = TinyHtml_TinyHtml.
|
|
9697
|
+
const elem = TinyHtml_TinyHtml._preElemAndWinAndDoc(el, 'width');
|
|
9371
9698
|
return TinyHtml_TinyHtml.getDimension(elem, 'width', 'content');
|
|
9372
9699
|
}
|
|
9373
9700
|
|
|
@@ -9381,11 +9708,11 @@ class TinyHtml_TinyHtml {
|
|
|
9381
9708
|
|
|
9382
9709
|
/**
|
|
9383
9710
|
* Returns padding box height.
|
|
9384
|
-
* @param {
|
|
9711
|
+
* @param {TinyElementAndWinAndDoc} el - Target element.
|
|
9385
9712
|
* @returns {number}
|
|
9386
9713
|
*/
|
|
9387
9714
|
static innerHeight(el) {
|
|
9388
|
-
const elem = TinyHtml_TinyHtml.
|
|
9715
|
+
const elem = TinyHtml_TinyHtml._preElemAndWinAndDoc(el, 'innerHeight');
|
|
9389
9716
|
return TinyHtml_TinyHtml.getDimension(elem, 'height', 'padding');
|
|
9390
9717
|
}
|
|
9391
9718
|
|
|
@@ -9399,11 +9726,11 @@ class TinyHtml_TinyHtml {
|
|
|
9399
9726
|
|
|
9400
9727
|
/**
|
|
9401
9728
|
* Returns padding box width.
|
|
9402
|
-
* @param {
|
|
9729
|
+
* @param {TinyElementAndWinAndDoc} el - Target element.
|
|
9403
9730
|
* @returns {number}
|
|
9404
9731
|
*/
|
|
9405
9732
|
static innerWidth(el) {
|
|
9406
|
-
const elem = TinyHtml_TinyHtml.
|
|
9733
|
+
const elem = TinyHtml_TinyHtml._preElemAndWinAndDoc(el, 'innerWidth');
|
|
9407
9734
|
return TinyHtml_TinyHtml.getDimension(elem, 'width', 'padding');
|
|
9408
9735
|
}
|
|
9409
9736
|
|
|
@@ -9417,14 +9744,14 @@ class TinyHtml_TinyHtml {
|
|
|
9417
9744
|
|
|
9418
9745
|
/**
|
|
9419
9746
|
* Returns outer height of the element, optionally including margin.
|
|
9420
|
-
* @param {
|
|
9747
|
+
* @param {TinyElementAndWinAndDoc} el - Target element.
|
|
9421
9748
|
* @param {boolean} [includeMargin=false] - Whether to include margin.
|
|
9422
9749
|
* @returns {number}
|
|
9423
9750
|
*/
|
|
9424
9751
|
static outerHeight(el, includeMargin = false) {
|
|
9425
9752
|
if (typeof includeMargin !== 'boolean')
|
|
9426
9753
|
throw new TypeError('The "includeMargin" must be a boolean.');
|
|
9427
|
-
const elem = TinyHtml_TinyHtml.
|
|
9754
|
+
const elem = TinyHtml_TinyHtml._preElemAndWinAndDoc(el, 'outerHeight');
|
|
9428
9755
|
return TinyHtml_TinyHtml.getDimension(elem, 'height', includeMargin ? 'margin' : 'border');
|
|
9429
9756
|
}
|
|
9430
9757
|
|
|
@@ -9439,14 +9766,14 @@ class TinyHtml_TinyHtml {
|
|
|
9439
9766
|
|
|
9440
9767
|
/**
|
|
9441
9768
|
* Returns outer width of the element, optionally including margin.
|
|
9442
|
-
* @param {
|
|
9769
|
+
* @param {TinyElementAndWinAndDoc} el - Target element.
|
|
9443
9770
|
* @param {boolean} [includeMargin=false] - Whether to include margin.
|
|
9444
9771
|
* @returns {number}
|
|
9445
9772
|
*/
|
|
9446
9773
|
static outerWidth(el, includeMargin = false) {
|
|
9447
9774
|
if (typeof includeMargin !== 'boolean')
|
|
9448
9775
|
throw new TypeError('The "includeMargin" must be a boolean.');
|
|
9449
|
-
const elem = TinyHtml_TinyHtml.
|
|
9776
|
+
const elem = TinyHtml_TinyHtml._preElemAndWinAndDoc(el, 'outerWidth');
|
|
9450
9777
|
return TinyHtml_TinyHtml.getDimension(elem, 'width', includeMargin ? 'margin' : 'border');
|
|
9451
9778
|
}
|
|
9452
9779
|
|
|
@@ -9461,6 +9788,30 @@ class TinyHtml_TinyHtml {
|
|
|
9461
9788
|
|
|
9462
9789
|
//////////////////////////////////////////////////
|
|
9463
9790
|
|
|
9791
|
+
/**
|
|
9792
|
+
* Applies an animation to one or multiple TinyElement instances.
|
|
9793
|
+
*
|
|
9794
|
+
* @param {TinyElement|TinyElement[]} el - A single TinyElement or an array of TinyElements to animate.
|
|
9795
|
+
* @param {Keyframe[] | PropertyIndexedKeyframes | null} keyframes - The keyframes used to define the animation.
|
|
9796
|
+
* @param {number | KeyframeAnimationOptions} [ops] - Timing or configuration options for the animation.
|
|
9797
|
+
* @returns {TinyElement|TinyElement[]}
|
|
9798
|
+
*/
|
|
9799
|
+
static animate(el, keyframes, ops) {
|
|
9800
|
+
TinyHtml_TinyHtml._preElems(el, 'animate').forEach((elem) => elem.animate(keyframes, ops));
|
|
9801
|
+
return el;
|
|
9802
|
+
}
|
|
9803
|
+
|
|
9804
|
+
/**
|
|
9805
|
+
* Applies an animation to one or multiple TinyElement instances.
|
|
9806
|
+
*
|
|
9807
|
+
* @param {Keyframe[] | PropertyIndexedKeyframes | null} keyframes - The keyframes used to define the animation.
|
|
9808
|
+
* @param {number | KeyframeAnimationOptions} [ops] - Timing or configuration options for the animation.
|
|
9809
|
+
* @returns {TinyElement|TinyElement[]}
|
|
9810
|
+
*/
|
|
9811
|
+
animate(keyframes, ops) {
|
|
9812
|
+
return TinyHtml_TinyHtml.animate(this, keyframes, ops);
|
|
9813
|
+
}
|
|
9814
|
+
|
|
9464
9815
|
/**
|
|
9465
9816
|
* Gets the offset of the element relative to the document.
|
|
9466
9817
|
* @param {TinyElement} el - Target element.
|
|
@@ -9615,28 +9966,152 @@ class TinyHtml_TinyHtml {
|
|
|
9615
9966
|
return TinyHtml_TinyHtml.scrollLeft(this);
|
|
9616
9967
|
}
|
|
9617
9968
|
|
|
9969
|
+
/**
|
|
9970
|
+
* Collection of easing functions used for scroll and animation calculations.
|
|
9971
|
+
* Each function receives a normalized time value (`t` from 0 to 1) and returns the eased progress.
|
|
9972
|
+
*
|
|
9973
|
+
* @type {Record<string, (t: number) => number>}
|
|
9974
|
+
*/
|
|
9975
|
+
static easings = {
|
|
9976
|
+
linear: (t) => t,
|
|
9977
|
+
easeInQuad: (t) => t * t,
|
|
9978
|
+
easeOutQuad: (t) => t * (2 - t),
|
|
9979
|
+
easeInOutQuad: (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),
|
|
9980
|
+
easeInCubic: (t) => t * t * t,
|
|
9981
|
+
easeOutCubic: (t) => --t * t * t + 1,
|
|
9982
|
+
easeInOutCubic: (t) => (t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1),
|
|
9983
|
+
};
|
|
9984
|
+
|
|
9985
|
+
/**
|
|
9986
|
+
* Smoothly scrolls one or more elements (or the window) to the specified X and Y coordinates
|
|
9987
|
+
* using a custom duration and easing function.
|
|
9988
|
+
*
|
|
9989
|
+
* If `duration` or a valid `easing` is not provided, the scroll will be performed immediately.
|
|
9990
|
+
*
|
|
9991
|
+
* @param {TinyElementAndWindow | TinyElementAndWindow[]} el - A single element, array of elements, or the window to scroll.
|
|
9992
|
+
* @param {Object} [settings={}] - Configuration object for the scroll animation.
|
|
9993
|
+
* @param {number} [settings.targetX] - The horizontal scroll target in pixels.
|
|
9994
|
+
* @param {number} [settings.targetY] - The vertical scroll target in pixels.
|
|
9995
|
+
* @param {number} [settings.duration] - The duration of the animation in milliseconds.
|
|
9996
|
+
* @param {Easings} [settings.easing] - The easing function name to use for the scroll animation.
|
|
9997
|
+
* @param {OnScrollAnimation} [settings.onAnimation] - Optional callback invoked on each animation
|
|
9998
|
+
* frame with the current scroll position, normalized animation time (`0` to `1`), and a completion flag.
|
|
9999
|
+
* @returns {TinyElementAndWindow|TinyElementAndWindow[]}
|
|
10000
|
+
* @throws {TypeError} If `el` is not a valid element, array, or window.
|
|
10001
|
+
* @throws {TypeError} If `targetX` or `targetY` is defined but not a number.
|
|
10002
|
+
* @throws {TypeError} If `duration` is defined but not a number.
|
|
10003
|
+
* @throws {TypeError} If `easing` is defined but not a valid easing function name.
|
|
10004
|
+
* @throws {TypeError} If `onAnimation` is defined but not a function.
|
|
10005
|
+
*/
|
|
10006
|
+
static scrollToXY(el, { targetX, targetY, duration, easing, onAnimation } = {}) {
|
|
10007
|
+
if (targetX !== undefined && typeof targetX !== 'number')
|
|
10008
|
+
throw new TypeError('`targetX` must be a number if provided.');
|
|
10009
|
+
if (targetY !== undefined && typeof targetY !== 'number')
|
|
10010
|
+
throw new TypeError('`targetY` must be a number if provided.');
|
|
10011
|
+
if (duration !== undefined && typeof duration !== 'number')
|
|
10012
|
+
throw new TypeError('`duration` must be a number if provided.');
|
|
10013
|
+
if (easing !== undefined && typeof easing !== 'string')
|
|
10014
|
+
throw new TypeError('`easing` must be a string if provided.');
|
|
10015
|
+
if (easing !== undefined && typeof TinyHtml_TinyHtml.easings[easing] !== 'function')
|
|
10016
|
+
throw new TypeError(`Unknown easing function: "${easing}".`);
|
|
10017
|
+
if (onAnimation !== undefined && typeof onAnimation !== 'function')
|
|
10018
|
+
throw new TypeError('`onAnimation` must be a function if provided.');
|
|
10019
|
+
|
|
10020
|
+
/**
|
|
10021
|
+
* Performs an instant scroll to the given coordinates.
|
|
10022
|
+
*
|
|
10023
|
+
* @param {ElementAndWindow} elem - The element or window to scroll.
|
|
10024
|
+
* @param {number} newX - The final horizontal scroll position.
|
|
10025
|
+
* @param {number} newY - The final vertical scroll position.
|
|
10026
|
+
* @param {number} time - Normalized progress value.
|
|
10027
|
+
*/
|
|
10028
|
+
const executeScroll = (elem, newX, newY, time) => {
|
|
10029
|
+
if (elem instanceof Window) {
|
|
10030
|
+
window.scrollTo(newX, newY);
|
|
10031
|
+
} else if (elem.nodeType === 9) {
|
|
10032
|
+
// @ts-ignore
|
|
10033
|
+
elem.defaultView.scrollTo(newX, newY);
|
|
10034
|
+
} else {
|
|
10035
|
+
const startX = elem instanceof Window ? window.scrollX : elem.scrollLeft;
|
|
10036
|
+
const startY = elem instanceof Window ? window.scrollY : elem.scrollTop;
|
|
10037
|
+
if (startX !== newX) elem.scrollLeft = newX;
|
|
10038
|
+
if (startY !== newY) elem.scrollTop = newY;
|
|
10039
|
+
}
|
|
10040
|
+
if (typeof onAnimation === 'function')
|
|
10041
|
+
onAnimation({ x: newX, y: newY, isComplete: time >= 1, time });
|
|
10042
|
+
};
|
|
10043
|
+
|
|
10044
|
+
TinyHtml_TinyHtml._preElemsAndWindow(el, 'scrollToXY').forEach((elem) => {
|
|
10045
|
+
const startX = elem instanceof Window ? window.scrollX : elem.scrollLeft;
|
|
10046
|
+
const startY = elem instanceof Window ? window.scrollY : elem.scrollTop;
|
|
10047
|
+
const targX = targetX ?? startX;
|
|
10048
|
+
const targY = targetY ?? startY;
|
|
10049
|
+
|
|
10050
|
+
const changeX = targX - startX;
|
|
10051
|
+
const changeY = targY - startY;
|
|
10052
|
+
|
|
10053
|
+
const ease = (typeof easing === 'string' && TinyHtml_TinyHtml.easings[easing]) || null;
|
|
10054
|
+
if (typeof duration !== 'number' || typeof ease !== 'function')
|
|
10055
|
+
return executeScroll(elem, targX, targY, 1);
|
|
10056
|
+
const startTime = performance.now();
|
|
10057
|
+
const dur = duration ?? 0;
|
|
10058
|
+
|
|
10059
|
+
/**
|
|
10060
|
+
* Animates the scroll position based on easing and time.
|
|
10061
|
+
*
|
|
10062
|
+
* @param {number} currentTime - Timestamp provided by requestAnimationFrame.
|
|
10063
|
+
*/
|
|
10064
|
+
function animateScroll(currentTime) {
|
|
10065
|
+
if (typeof ease !== 'function') return;
|
|
10066
|
+
const time = Math.min(1, (currentTime - startTime) / dur);
|
|
10067
|
+
const easedTime = ease(time);
|
|
10068
|
+
|
|
10069
|
+
const newX = startX + changeX * easedTime;
|
|
10070
|
+
const newY = startY + changeY * easedTime;
|
|
10071
|
+
executeScroll(elem, newX, newY, time);
|
|
10072
|
+
|
|
10073
|
+
if (time < 1) requestAnimationFrame(animateScroll);
|
|
10074
|
+
}
|
|
10075
|
+
|
|
10076
|
+
requestAnimationFrame(animateScroll);
|
|
10077
|
+
});
|
|
10078
|
+
return el;
|
|
10079
|
+
}
|
|
10080
|
+
|
|
10081
|
+
/**
|
|
10082
|
+
* Smoothly scrolls one or more elements (or the window) to the specified X and Y coordinates
|
|
10083
|
+
* using a custom duration and easing function.
|
|
10084
|
+
*
|
|
10085
|
+
* If `duration` or a valid `easing` is not provided, the scroll will be performed immediately.
|
|
10086
|
+
*
|
|
10087
|
+
* @param {Object} [settings={}] - Configuration object for the scroll animation.
|
|
10088
|
+
* @param {number} [settings.targetX] - The horizontal scroll target in pixels.
|
|
10089
|
+
* @param {number} [settings.targetY] - The vertical scroll target in pixels.
|
|
10090
|
+
* @param {number} [settings.duration] - The duration of the animation in milliseconds.
|
|
10091
|
+
* @param {Easings} [settings.easing] - The easing function name to use for the scroll animation.
|
|
10092
|
+
* @param {OnScrollAnimation} [settings.onAnimation] - Optional callback invoked on each animation
|
|
10093
|
+
* frame with the current scroll position, normalized animation time (`0` to `1`), and a completion flag.
|
|
10094
|
+
* @returns {TinyElementAndWindow|TinyElementAndWindow[]}
|
|
10095
|
+
*/
|
|
10096
|
+
scrollToXY({ targetX, targetY, duration, easing, onAnimation } = {}) {
|
|
10097
|
+
return TinyHtml_TinyHtml.scrollToXY(this, { targetX, targetY, duration, easing, onAnimation });
|
|
10098
|
+
}
|
|
10099
|
+
|
|
9618
10100
|
/**
|
|
9619
10101
|
* Sets the vertical scroll position.
|
|
9620
10102
|
* @param {TinyElementAndWindow|TinyElementAndWindow[]} el - Element or window.
|
|
9621
10103
|
* @param {number} value - Scroll top value.
|
|
10104
|
+
* @returns {TinyElementAndWindow|TinyElementAndWindow[]}
|
|
9622
10105
|
*/
|
|
9623
10106
|
static setScrollTop(el, value) {
|
|
9624
10107
|
if (typeof value !== 'number') throw new TypeError('ScrollTop value must be a number.');
|
|
9625
|
-
TinyHtml_TinyHtml.
|
|
9626
|
-
if (TinyHtml_TinyHtml.isWindow(elem)) {
|
|
9627
|
-
elem.scrollTo(elem.pageXOffset, value);
|
|
9628
|
-
} else if (elem.nodeType === 9) {
|
|
9629
|
-
// @ts-ignore
|
|
9630
|
-
elem.defaultView.scrollTo(elem.defaultView.pageXOffset, value);
|
|
9631
|
-
} else {
|
|
9632
|
-
elem.scrollTop = value;
|
|
9633
|
-
}
|
|
9634
|
-
});
|
|
10108
|
+
return TinyHtml_TinyHtml.scrollToXY(el, { targetY: value });
|
|
9635
10109
|
}
|
|
9636
10110
|
|
|
9637
10111
|
/**
|
|
9638
10112
|
* Sets the vertical scroll position.
|
|
9639
10113
|
* @param {number} value - Scroll top value.
|
|
10114
|
+
* @returns {TinyElementAndWindow|TinyElementAndWindow[]}
|
|
9640
10115
|
*/
|
|
9641
10116
|
setScrollTop(value) {
|
|
9642
10117
|
return TinyHtml_TinyHtml.setScrollTop(this, value);
|
|
@@ -9646,24 +10121,17 @@ class TinyHtml_TinyHtml {
|
|
|
9646
10121
|
* Sets the horizontal scroll position.
|
|
9647
10122
|
* @param {TinyElementAndWindow|TinyElementAndWindow[]} el - Element or window.
|
|
9648
10123
|
* @param {number} value - Scroll left value.
|
|
10124
|
+
* @returns {TinyElementAndWindow|TinyElementAndWindow[]}
|
|
9649
10125
|
*/
|
|
9650
10126
|
static setScrollLeft(el, value) {
|
|
9651
10127
|
if (typeof value !== 'number') throw new TypeError('ScrollLeft value must be a number.');
|
|
9652
|
-
TinyHtml_TinyHtml.
|
|
9653
|
-
if (TinyHtml_TinyHtml.isWindow(elem)) {
|
|
9654
|
-
elem.scrollTo(value, elem.pageYOffset);
|
|
9655
|
-
} else if (elem.nodeType === 9) {
|
|
9656
|
-
// @ts-ignore
|
|
9657
|
-
elem.defaultView.scrollTo(value, elem.defaultView.pageYOffset);
|
|
9658
|
-
} else {
|
|
9659
|
-
elem.scrollLeft = value;
|
|
9660
|
-
}
|
|
9661
|
-
});
|
|
10128
|
+
return TinyHtml_TinyHtml.scrollToXY(el, { targetX: value });
|
|
9662
10129
|
}
|
|
9663
10130
|
|
|
9664
10131
|
/**
|
|
9665
10132
|
* Sets the horizontal scroll position.
|
|
9666
10133
|
* @param {number} value - Scroll left value.
|
|
10134
|
+
* @returns {TinyElementAndWindow|TinyElementAndWindow[]}
|
|
9667
10135
|
*/
|
|
9668
10136
|
setScrollLeft(value) {
|
|
9669
10137
|
return TinyHtml_TinyHtml.setScrollLeft(this, value);
|
|
@@ -9794,15 +10262,16 @@ class TinyHtml_TinyHtml {
|
|
|
9794
10262
|
|
|
9795
10263
|
/**
|
|
9796
10264
|
* Adds one or more CSS class names to the element.
|
|
9797
|
-
* @type {(el: TinyElement|TinyElement[], ...tokens: string[]) =>
|
|
10265
|
+
* @type {(el: TinyElement|TinyElement[], ...tokens: string[]) => (TinyElement|TinyElement[])} - One or more class names to add.
|
|
9798
10266
|
*/
|
|
9799
10267
|
static addClass(el, ...args) {
|
|
9800
10268
|
TinyHtml_TinyHtml._preElems(el, 'addClass').forEach((elem) => elem.classList.add(...args));
|
|
10269
|
+
return el;
|
|
9801
10270
|
}
|
|
9802
10271
|
|
|
9803
10272
|
/**
|
|
9804
10273
|
* Adds one or more CSS class names to the element.
|
|
9805
|
-
* @type {(...tokens: string[]) =>
|
|
10274
|
+
* @type {(...tokens: string[]) => (TinyElement|TinyElement[])} - One or more class names to add.
|
|
9806
10275
|
*/
|
|
9807
10276
|
addClass(...args) {
|
|
9808
10277
|
return TinyHtml_TinyHtml.addClass(this, ...args);
|
|
@@ -9810,15 +10279,16 @@ class TinyHtml_TinyHtml {
|
|
|
9810
10279
|
|
|
9811
10280
|
/**
|
|
9812
10281
|
* Removes one or more CSS class names from the element.
|
|
9813
|
-
* @type {(el: TinyElement|TinyElement[], ...tokens: string[]) =>
|
|
10282
|
+
* @type {(el: TinyElement|TinyElement[], ...tokens: string[]) => (TinyElement|TinyElement[])} - One or more class names to remove.
|
|
9814
10283
|
*/
|
|
9815
10284
|
static removeClass(el, ...args) {
|
|
9816
10285
|
TinyHtml_TinyHtml._preElems(el, 'removeClass').forEach((elem) => elem.classList.remove(...args));
|
|
10286
|
+
return el;
|
|
9817
10287
|
}
|
|
9818
10288
|
|
|
9819
10289
|
/**
|
|
9820
10290
|
* Removes one or more CSS class names from the element.
|
|
9821
|
-
* @type {(...tokens: string[]) =>
|
|
10291
|
+
* @type {(...tokens: string[]) => (TinyElement|TinyElement[])} - One or more class names to remove.
|
|
9822
10292
|
*/
|
|
9823
10293
|
removeClass(...args) {
|
|
9824
10294
|
return TinyHtml_TinyHtml.removeClass(this, ...args);
|
|
@@ -10028,15 +10498,18 @@ class TinyHtml_TinyHtml {
|
|
|
10028
10498
|
* Set text content of elements.
|
|
10029
10499
|
* @param {TinyElement|TinyElement[]} el
|
|
10030
10500
|
* @param {string} value
|
|
10501
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10031
10502
|
*/
|
|
10032
10503
|
static setText(el, value) {
|
|
10033
10504
|
if (typeof value !== 'string') throw new Error('Value is not a valid string.');
|
|
10034
10505
|
TinyHtml_TinyHtml._preElems(el, 'setText').forEach((el) => (el.textContent = value));
|
|
10506
|
+
return el;
|
|
10035
10507
|
}
|
|
10036
10508
|
|
|
10037
10509
|
/**
|
|
10038
10510
|
* Set text content of the element.
|
|
10039
10511
|
* @param {string} value
|
|
10512
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10040
10513
|
*/
|
|
10041
10514
|
setText(value) {
|
|
10042
10515
|
return TinyHtml_TinyHtml.setText(this, value);
|
|
@@ -10045,13 +10518,16 @@ class TinyHtml_TinyHtml {
|
|
|
10045
10518
|
/**
|
|
10046
10519
|
* Remove all child nodes from each element.
|
|
10047
10520
|
* @param {TinyElement|TinyElement[]} el
|
|
10521
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10048
10522
|
*/
|
|
10049
10523
|
static empty(el) {
|
|
10050
10524
|
TinyHtml_TinyHtml._preElems(el, 'empty').forEach((el) => (el.textContent = ''));
|
|
10525
|
+
return el;
|
|
10051
10526
|
}
|
|
10052
10527
|
|
|
10053
10528
|
/**
|
|
10054
10529
|
* Remove all child nodes of the element.
|
|
10530
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10055
10531
|
*/
|
|
10056
10532
|
empty() {
|
|
10057
10533
|
return TinyHtml_TinyHtml.empty(this);
|
|
@@ -10059,35 +10535,40 @@ class TinyHtml_TinyHtml {
|
|
|
10059
10535
|
|
|
10060
10536
|
/**
|
|
10061
10537
|
* Get the innerHTML of the element.
|
|
10062
|
-
* @param {TinyElement
|
|
10538
|
+
* @param {TinyElement} el
|
|
10539
|
+
* @param {GetHTMLOptions} [ops]
|
|
10063
10540
|
* @returns {string}
|
|
10064
10541
|
*/
|
|
10065
|
-
static html(el) {
|
|
10542
|
+
static html(el, ops) {
|
|
10066
10543
|
const elem = TinyHtml_TinyHtml._preElem(el, 'html');
|
|
10067
|
-
return elem.
|
|
10544
|
+
return elem.getHTML(ops);
|
|
10068
10545
|
}
|
|
10069
10546
|
|
|
10070
10547
|
/**
|
|
10071
10548
|
* Get the innerHTML of the element.
|
|
10549
|
+
* @param {GetHTMLOptions} [ops]
|
|
10072
10550
|
* @returns {string}
|
|
10073
10551
|
*/
|
|
10074
|
-
html() {
|
|
10075
|
-
return TinyHtml_TinyHtml.html(this);
|
|
10552
|
+
html(ops) {
|
|
10553
|
+
return TinyHtml_TinyHtml.html(this, ops);
|
|
10076
10554
|
}
|
|
10077
10555
|
|
|
10078
10556
|
/**
|
|
10079
10557
|
* Set the innerHTML of each element.
|
|
10080
10558
|
* @param {TinyElement|TinyElement[]} el
|
|
10081
10559
|
* @param {string} value
|
|
10560
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10082
10561
|
*/
|
|
10083
10562
|
static setHtml(el, value) {
|
|
10084
10563
|
if (typeof value !== 'string') throw new Error('Value is not a valid string.');
|
|
10085
10564
|
TinyHtml_TinyHtml._preElems(el, 'setHtml').forEach((el) => (el.innerHTML = value));
|
|
10565
|
+
return el;
|
|
10086
10566
|
}
|
|
10087
10567
|
|
|
10088
10568
|
/**
|
|
10089
10569
|
* Set the innerHTML of the element.
|
|
10090
10570
|
* @param {string} value
|
|
10571
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10091
10572
|
*/
|
|
10092
10573
|
setHtml(value) {
|
|
10093
10574
|
return TinyHtml_TinyHtml.setHtml(this, value);
|
|
@@ -10221,6 +10702,7 @@ class TinyHtml_TinyHtml {
|
|
|
10221
10702
|
* @param {TinyInputElement|TinyInputElement[]} el - Target element.
|
|
10222
10703
|
* @param {SetValueList|((el: InputElement, val: SetValueList) => SetValueList)} value - The value to assign or a function that returns it.
|
|
10223
10704
|
* @throws {Error} If the computed value is not a valid string or boolean.
|
|
10705
|
+
* @returns {TinyInputElement|TinyInputElement[]}
|
|
10224
10706
|
*/
|
|
10225
10707
|
static setVal(el, value) {
|
|
10226
10708
|
TinyHtml_TinyHtml._preInputElems(el, 'setVal').forEach((elem) => {
|
|
@@ -10260,6 +10742,7 @@ class TinyHtml_TinyHtml {
|
|
|
10260
10742
|
if (typeof valToSet === 'string') elem.value = valToSet;
|
|
10261
10743
|
}
|
|
10262
10744
|
});
|
|
10745
|
+
return el;
|
|
10263
10746
|
}
|
|
10264
10747
|
|
|
10265
10748
|
/**
|
|
@@ -10267,6 +10750,7 @@ class TinyHtml_TinyHtml {
|
|
|
10267
10750
|
* Accepts strings, numbers, booleans or arrays of these values, or a callback function that computes them.
|
|
10268
10751
|
*
|
|
10269
10752
|
* @param {SetValueList|((el: InputElement, val: SetValueList) => SetValueList)} value - The value to assign or a function that returns it.
|
|
10753
|
+
* @returns {TinyInputElement|TinyInputElement[]}
|
|
10270
10754
|
* @throws {Error} If the computed value is not a valid string or boolean.
|
|
10271
10755
|
*/
|
|
10272
10756
|
setVal(value) {
|
|
@@ -10536,6 +11020,7 @@ class TinyHtml_TinyHtml {
|
|
|
10536
11020
|
* @param {string} event - The event type (e.g. 'click', 'keydown').
|
|
10537
11021
|
* @param {EventRegistryHandle} handler - The callback function to run on event.
|
|
10538
11022
|
* @param {EventRegistryOptions} [options] - Optional event listener options.
|
|
11023
|
+
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
10539
11024
|
*/
|
|
10540
11025
|
static on(el, event, handler, options) {
|
|
10541
11026
|
if (typeof event !== 'string') throw new TypeError('The event name must be a string.');
|
|
@@ -10548,6 +11033,7 @@ class TinyHtml_TinyHtml {
|
|
|
10548
11033
|
if (!Array.isArray(events[event])) events[event] = [];
|
|
10549
11034
|
events[event].push({ handler, options });
|
|
10550
11035
|
});
|
|
11036
|
+
return el;
|
|
10551
11037
|
}
|
|
10552
11038
|
|
|
10553
11039
|
/**
|
|
@@ -10556,6 +11042,7 @@ class TinyHtml_TinyHtml {
|
|
|
10556
11042
|
* @param {string} event - The event type (e.g. 'click', 'keydown').
|
|
10557
11043
|
* @param {EventRegistryHandle} handler - The callback function to run on event.
|
|
10558
11044
|
* @param {EventRegistryOptions} [options] - Optional event listener options.
|
|
11045
|
+
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
10559
11046
|
*/
|
|
10560
11047
|
on(event, handler, options) {
|
|
10561
11048
|
return TinyHtml_TinyHtml.on(this, event, handler, options);
|
|
@@ -10568,6 +11055,7 @@ class TinyHtml_TinyHtml {
|
|
|
10568
11055
|
* @param {string} event - The event type (e.g. 'click', 'keydown').
|
|
10569
11056
|
* @param {EventRegistryHandle} handler - The callback function to run on event.
|
|
10570
11057
|
* @param {EventRegistryOptions} [options={}] - Optional event listener options.
|
|
11058
|
+
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
10571
11059
|
*/
|
|
10572
11060
|
static once(el, event, handler, options = {}) {
|
|
10573
11061
|
if (typeof event !== 'string') throw new TypeError('The event name must be a string.');
|
|
@@ -10585,6 +11073,7 @@ class TinyHtml_TinyHtml {
|
|
|
10585
11073
|
typeof options === 'boolean' ? options : { ...options, once: true },
|
|
10586
11074
|
);
|
|
10587
11075
|
});
|
|
11076
|
+
return el;
|
|
10588
11077
|
}
|
|
10589
11078
|
|
|
10590
11079
|
/**
|
|
@@ -10593,6 +11082,7 @@ class TinyHtml_TinyHtml {
|
|
|
10593
11082
|
* @param {string} event - The event type (e.g. 'click', 'keydown').
|
|
10594
11083
|
* @param {EventRegistryHandle} handler - The callback function to run on event.
|
|
10595
11084
|
* @param {EventRegistryOptions} [options={}] - Optional event listener options.
|
|
11085
|
+
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
10596
11086
|
*/
|
|
10597
11087
|
once(event, handler, options = {}) {
|
|
10598
11088
|
return TinyHtml_TinyHtml.once(this, event, handler, options);
|
|
@@ -10605,6 +11095,7 @@ class TinyHtml_TinyHtml {
|
|
|
10605
11095
|
* @param {string} event - The event type.
|
|
10606
11096
|
* @param {EventRegistryHandle} handler - The function originally bound to the event.
|
|
10607
11097
|
* @param {boolean|EventListenerOptions} [options] - Optional listener options.
|
|
11098
|
+
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
10608
11099
|
*/
|
|
10609
11100
|
static off(el, event, handler, options) {
|
|
10610
11101
|
if (typeof event !== 'string') throw new TypeError('The event name must be a string.');
|
|
@@ -10617,6 +11108,7 @@ class TinyHtml_TinyHtml {
|
|
|
10617
11108
|
if (events[event].length === 0) delete events[event];
|
|
10618
11109
|
}
|
|
10619
11110
|
});
|
|
11111
|
+
return el;
|
|
10620
11112
|
}
|
|
10621
11113
|
|
|
10622
11114
|
/**
|
|
@@ -10625,6 +11117,7 @@ class TinyHtml_TinyHtml {
|
|
|
10625
11117
|
* @param {string} event - The event type.
|
|
10626
11118
|
* @param {EventRegistryHandle} handler - The function originally bound to the event.
|
|
10627
11119
|
* @param {boolean|EventListenerOptions} [options] - Optional listener options.
|
|
11120
|
+
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
10628
11121
|
*/
|
|
10629
11122
|
off(event, handler, options) {
|
|
10630
11123
|
return TinyHtml_TinyHtml.off(this, event, handler, options);
|
|
@@ -10635,6 +11128,7 @@ class TinyHtml_TinyHtml {
|
|
|
10635
11128
|
*
|
|
10636
11129
|
* @param {TinyEventTarget|TinyEventTarget[]} el - The target element.
|
|
10637
11130
|
* @param {string} event - The event type to remove (e.g. 'click').
|
|
11131
|
+
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
10638
11132
|
*/
|
|
10639
11133
|
static offAll(el, event) {
|
|
10640
11134
|
if (typeof event !== 'string') throw new TypeError('The event name must be a string.');
|
|
@@ -10647,12 +11141,14 @@ class TinyHtml_TinyHtml {
|
|
|
10647
11141
|
delete events[event];
|
|
10648
11142
|
}
|
|
10649
11143
|
});
|
|
11144
|
+
return el;
|
|
10650
11145
|
}
|
|
10651
11146
|
|
|
10652
11147
|
/**
|
|
10653
11148
|
* Removes all event listeners of a specific type from the element.
|
|
10654
11149
|
*
|
|
10655
11150
|
* @param {string} event - The event type to remove (e.g. 'click').
|
|
11151
|
+
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
10656
11152
|
*/
|
|
10657
11153
|
offAll(event) {
|
|
10658
11154
|
return TinyHtml_TinyHtml.offAll(this, event);
|
|
@@ -10664,6 +11160,7 @@ class TinyHtml_TinyHtml {
|
|
|
10664
11160
|
* @param {TinyEventTarget|TinyEventTarget[]} el - The target element.
|
|
10665
11161
|
* @param {((handler: EventListenerOrEventListenerObject, event: string) => boolean)|null} [filterFn=null] -
|
|
10666
11162
|
* Optional filter function to selectively remove specific handlers.
|
|
11163
|
+
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
10667
11164
|
*/
|
|
10668
11165
|
static offAllTypes(el, filterFn = null) {
|
|
10669
11166
|
if (filterFn !== null && typeof filterFn !== 'function')
|
|
@@ -10682,6 +11179,7 @@ class TinyHtml_TinyHtml {
|
|
|
10682
11179
|
|
|
10683
11180
|
__eventRegistry.delete(elem);
|
|
10684
11181
|
});
|
|
11182
|
+
return el;
|
|
10685
11183
|
}
|
|
10686
11184
|
|
|
10687
11185
|
/**
|
|
@@ -10689,6 +11187,7 @@ class TinyHtml_TinyHtml {
|
|
|
10689
11187
|
*
|
|
10690
11188
|
* @param {((handler: EventListenerOrEventListenerObject, event: string) => boolean)|null} [filterFn=null] -
|
|
10691
11189
|
* Optional filter function to selectively remove specific handlers.
|
|
11190
|
+
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
10692
11191
|
*/
|
|
10693
11192
|
offAllTypes(filterFn = null) {
|
|
10694
11193
|
return TinyHtml_TinyHtml.offAllTypes(this, filterFn);
|
|
@@ -10700,6 +11199,7 @@ class TinyHtml_TinyHtml {
|
|
|
10700
11199
|
* @param {TinyEventTarget|TinyEventTarget[]} el - Target element where the event should be triggered.
|
|
10701
11200
|
* @param {string} event - Name of the event to trigger.
|
|
10702
11201
|
* @param {Event|CustomEvent|CustomEventInit} [payload] - Optional event object or data to pass.
|
|
11202
|
+
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
10703
11203
|
*/
|
|
10704
11204
|
static trigger(el, event, payload = {}) {
|
|
10705
11205
|
if (typeof event !== 'string') throw new TypeError('The event name must be a string.');
|
|
@@ -10715,6 +11215,7 @@ class TinyHtml_TinyHtml {
|
|
|
10715
11215
|
|
|
10716
11216
|
elem.dispatchEvent(evt);
|
|
10717
11217
|
});
|
|
11218
|
+
return el;
|
|
10718
11219
|
}
|
|
10719
11220
|
|
|
10720
11221
|
/**
|
|
@@ -10722,6 +11223,7 @@ class TinyHtml_TinyHtml {
|
|
|
10722
11223
|
*
|
|
10723
11224
|
* @param {string} event - Name of the event to trigger.
|
|
10724
11225
|
* @param {Event|CustomEvent|CustomEventInit} [payload] - Optional event object or data to pass.
|
|
11226
|
+
* @returns {TinyEventTarget|TinyEventTarget[]}
|
|
10725
11227
|
*/
|
|
10726
11228
|
trigger(event, payload = {}) {
|
|
10727
11229
|
return TinyHtml_TinyHtml.trigger(this, event, payload);
|
|
@@ -10764,6 +11266,7 @@ class TinyHtml_TinyHtml {
|
|
|
10764
11266
|
* @param {TinyElement|TinyElement[]} el
|
|
10765
11267
|
* @param {string} name
|
|
10766
11268
|
* @param {string|null} [value=null]
|
|
11269
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10767
11270
|
*/
|
|
10768
11271
|
static setAttr(el, name, value = null) {
|
|
10769
11272
|
if (typeof name !== 'string') throw new TypeError('The "name" must be a string.');
|
|
@@ -10773,12 +11276,14 @@ class TinyHtml_TinyHtml {
|
|
|
10773
11276
|
if (value === null) elem.removeAttribute(name);
|
|
10774
11277
|
else elem.setAttribute(name, value);
|
|
10775
11278
|
});
|
|
11279
|
+
return el;
|
|
10776
11280
|
}
|
|
10777
11281
|
|
|
10778
11282
|
/**
|
|
10779
11283
|
* Set an attribute on an element.
|
|
10780
11284
|
* @param {string} name
|
|
10781
11285
|
* @param {string|null} [value=null]
|
|
11286
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10782
11287
|
*/
|
|
10783
11288
|
setAttr(name, value) {
|
|
10784
11289
|
return TinyHtml_TinyHtml.setAttr(this, name, value);
|
|
@@ -10788,15 +11293,18 @@ class TinyHtml_TinyHtml {
|
|
|
10788
11293
|
* Remove attribute(s) from an element.
|
|
10789
11294
|
* @param {TinyElement|TinyElement[]} el
|
|
10790
11295
|
* @param {string} name Space-separated list of attributes.
|
|
11296
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10791
11297
|
*/
|
|
10792
11298
|
static removeAttr(el, name) {
|
|
10793
11299
|
if (typeof name !== 'string') throw new TypeError('The "name" must be a string.');
|
|
10794
11300
|
TinyHtml_TinyHtml._preElems(el, 'removeAttr').forEach((elem) => elem.removeAttribute(name));
|
|
11301
|
+
return el;
|
|
10795
11302
|
}
|
|
10796
11303
|
|
|
10797
11304
|
/**
|
|
10798
11305
|
* Remove attribute(s) from an element.
|
|
10799
11306
|
* @param {string} name Space-separated list of attributes.
|
|
11307
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10800
11308
|
*/
|
|
10801
11309
|
removeAttr(name) {
|
|
10802
11310
|
return TinyHtml_TinyHtml.removeAttr(this, name);
|
|
@@ -10851,6 +11359,7 @@ class TinyHtml_TinyHtml {
|
|
|
10851
11359
|
* Set a property on an element.
|
|
10852
11360
|
* @param {TinyElement|TinyElement[]} el
|
|
10853
11361
|
* @param {string} name
|
|
11362
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10854
11363
|
*/
|
|
10855
11364
|
static addProp(el, name) {
|
|
10856
11365
|
if (typeof name !== 'string') throw new TypeError('The "name" must be a string.');
|
|
@@ -10860,11 +11369,13 @@ class TinyHtml_TinyHtml {
|
|
|
10860
11369
|
// @ts-ignore
|
|
10861
11370
|
elem[name] = true;
|
|
10862
11371
|
});
|
|
11372
|
+
return el;
|
|
10863
11373
|
}
|
|
10864
11374
|
|
|
10865
11375
|
/**
|
|
10866
11376
|
* Set a property on an element.
|
|
10867
11377
|
* @param {string} name
|
|
11378
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10868
11379
|
*/
|
|
10869
11380
|
addProp(name) {
|
|
10870
11381
|
return TinyHtml_TinyHtml.addProp(this, name);
|
|
@@ -10874,6 +11385,7 @@ class TinyHtml_TinyHtml {
|
|
|
10874
11385
|
* Remove a property from an element.
|
|
10875
11386
|
* @param {TinyElement|TinyElement[]} el
|
|
10876
11387
|
* @param {string} name
|
|
11388
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10877
11389
|
*/
|
|
10878
11390
|
static removeProp(el, name) {
|
|
10879
11391
|
if (typeof name !== 'string') throw new TypeError('The "name" must be a string.');
|
|
@@ -10883,11 +11395,13 @@ class TinyHtml_TinyHtml {
|
|
|
10883
11395
|
// @ts-ignore
|
|
10884
11396
|
elem[name] = false;
|
|
10885
11397
|
});
|
|
11398
|
+
return el;
|
|
10886
11399
|
}
|
|
10887
11400
|
|
|
10888
11401
|
/**
|
|
10889
11402
|
* Remove a property from an element.
|
|
10890
11403
|
* @param {string} name
|
|
11404
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10891
11405
|
*/
|
|
10892
11406
|
removeProp(name) {
|
|
10893
11407
|
return TinyHtml_TinyHtml.removeProp(this, name);
|
|
@@ -10928,13 +11442,16 @@ class TinyHtml_TinyHtml {
|
|
|
10928
11442
|
/**
|
|
10929
11443
|
* Removes an element from the DOM.
|
|
10930
11444
|
* @param {TinyElement|TinyElement[]} el - The DOM element or selector to remove.
|
|
11445
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10931
11446
|
*/
|
|
10932
11447
|
static remove(el) {
|
|
10933
11448
|
TinyHtml_TinyHtml._preElems(el, 'remove').forEach((elem) => elem.remove());
|
|
11449
|
+
return el;
|
|
10934
11450
|
}
|
|
10935
11451
|
|
|
10936
11452
|
/**
|
|
10937
11453
|
* Removes the element from the DOM.
|
|
11454
|
+
* @returns {TinyElement|TinyElement[]}
|
|
10938
11455
|
*/
|
|
10939
11456
|
remove() {
|
|
10940
11457
|
return TinyHtml_TinyHtml.remove(this);
|
|
@@ -11278,6 +11795,14 @@ class TinyHtml_TinyHtml {
|
|
|
11278
11795
|
*/
|
|
11279
11796
|
static isInViewport(el) {
|
|
11280
11797
|
const elem = TinyHtml_TinyHtml._preElem(el, 'isInViewport');
|
|
11798
|
+
if (
|
|
11799
|
+
!elem.checkVisibility({
|
|
11800
|
+
contentVisibilityAuto: false,
|
|
11801
|
+
opacityProperty: false,
|
|
11802
|
+
visibilityProperty: false,
|
|
11803
|
+
})
|
|
11804
|
+
)
|
|
11805
|
+
return false;
|
|
11281
11806
|
const elementTop = TinyHtml_TinyHtml.offset(elem).top;
|
|
11282
11807
|
const elementBottom = elementTop + TinyHtml_TinyHtml.outerHeight(elem);
|
|
11283
11808
|
|
|
@@ -11304,6 +11829,14 @@ class TinyHtml_TinyHtml {
|
|
|
11304
11829
|
*/
|
|
11305
11830
|
static isScrolledIntoView(el) {
|
|
11306
11831
|
const elem = TinyHtml_TinyHtml._preElem(el, 'isScrolledIntoView');
|
|
11832
|
+
if (
|
|
11833
|
+
!elem.checkVisibility({
|
|
11834
|
+
contentVisibilityAuto: false,
|
|
11835
|
+
opacityProperty: false,
|
|
11836
|
+
visibilityProperty: false,
|
|
11837
|
+
})
|
|
11838
|
+
)
|
|
11839
|
+
return false;
|
|
11307
11840
|
const docViewTop = TinyHtml_TinyHtml.scrollTop(window);
|
|
11308
11841
|
const docViewBottom = docViewTop + TinyHtml_TinyHtml.height(window);
|
|
11309
11842
|
|
|
@@ -11321,33 +11854,138 @@ class TinyHtml_TinyHtml {
|
|
|
11321
11854
|
isScrolledIntoView() {
|
|
11322
11855
|
return TinyHtml_TinyHtml.isScrolledIntoView(this);
|
|
11323
11856
|
}
|
|
11324
|
-
}
|
|
11325
11857
|
|
|
11326
|
-
|
|
11858
|
+
/**
|
|
11859
|
+
* Checks if the given element is at least partially visible within the boundaries of a container.
|
|
11860
|
+
*
|
|
11861
|
+
* @param {TinyElement} el - The DOM element to check.
|
|
11862
|
+
* @param {TinyElement} cont - The container element acting as the viewport.
|
|
11863
|
+
* @returns {boolean} True if the element is partially visible within the container, false otherwise.
|
|
11864
|
+
*/
|
|
11865
|
+
static isInContainer(el, cont) {
|
|
11866
|
+
const elem = TinyHtml_TinyHtml._preElem(el, 'isInContainer');
|
|
11867
|
+
const container = TinyHtml_TinyHtml._preElem(cont, 'isInContainer');
|
|
11327
11868
|
|
|
11328
|
-
|
|
11869
|
+
if (
|
|
11870
|
+
!elem.checkVisibility({
|
|
11871
|
+
contentVisibilityAuto: false,
|
|
11872
|
+
opacityProperty: false,
|
|
11873
|
+
visibilityProperty: false,
|
|
11874
|
+
})
|
|
11875
|
+
)
|
|
11876
|
+
return false;
|
|
11877
|
+
const elemRect = elem.getBoundingClientRect();
|
|
11878
|
+
const containerRect = container.getBoundingClientRect();
|
|
11329
11879
|
|
|
11880
|
+
const verticallyVisible =
|
|
11881
|
+
elemRect.bottom > containerRect.top && elemRect.top < containerRect.bottom;
|
|
11330
11882
|
|
|
11331
|
-
|
|
11332
|
-
|
|
11333
|
-
*
|
|
11334
|
-
* @param {Element} elem1 - First DOM element.
|
|
11335
|
-
* @param {Element} elem2 - Second DOM element.
|
|
11336
|
-
* @returns {boolean} - Returns true if the elements are colliding.
|
|
11337
|
-
* @deprecated - Use TinyHtml.isCollWith instead.
|
|
11338
|
-
*/
|
|
11339
|
-
function areHtmlElsColliding(elem1, elem2) {
|
|
11340
|
-
return libs_TinyHtml.isCollWith(elem1, elem2);
|
|
11341
|
-
}
|
|
11883
|
+
const horizontallyVisible =
|
|
11884
|
+
elemRect.right > containerRect.left && elemRect.left < containerRect.right;
|
|
11342
11885
|
|
|
11343
|
-
|
|
11344
|
-
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
|
|
11886
|
+
return verticallyVisible && horizontallyVisible;
|
|
11887
|
+
}
|
|
11888
|
+
|
|
11889
|
+
/**
|
|
11890
|
+
* Checks if the given element is at least partially visible within the boundaries of a container.
|
|
11891
|
+
*
|
|
11892
|
+
* @param {TinyElement} cont - The container element acting as the viewport.
|
|
11893
|
+
* @returns {boolean} True if the element is partially visible within the container, false otherwise.
|
|
11894
|
+
*/
|
|
11895
|
+
isInContainer(cont) {
|
|
11896
|
+
return TinyHtml_TinyHtml.isInContainer(this, cont);
|
|
11897
|
+
}
|
|
11898
|
+
|
|
11899
|
+
/**
|
|
11900
|
+
* Checks if the given element is fully visible within the boundaries of a container (top and bottom).
|
|
11901
|
+
*
|
|
11902
|
+
* @param {TinyElement} el - The DOM element to check.
|
|
11903
|
+
* @param {TinyElement} cont - The container element acting as the viewport.
|
|
11904
|
+
* @returns {boolean} True if the element is fully visible within the container, false otherwise.
|
|
11905
|
+
*/
|
|
11906
|
+
static isFullyInContainer(el, cont) {
|
|
11907
|
+
const elem = TinyHtml_TinyHtml._preElem(el, 'isScrolledIntoView');
|
|
11908
|
+
const container = TinyHtml_TinyHtml._preElem(cont, 'isInContainer');
|
|
11909
|
+
|
|
11910
|
+
if (
|
|
11911
|
+
!elem.checkVisibility({
|
|
11912
|
+
contentVisibilityAuto: false,
|
|
11913
|
+
opacityProperty: false,
|
|
11914
|
+
visibilityProperty: false,
|
|
11915
|
+
})
|
|
11916
|
+
)
|
|
11917
|
+
return false;
|
|
11918
|
+
const elemRect = elem.getBoundingClientRect();
|
|
11919
|
+
const containerRect = container.getBoundingClientRect();
|
|
11920
|
+
|
|
11921
|
+
const isFullyVisible =
|
|
11922
|
+
elemRect.top >= containerRect.top &&
|
|
11923
|
+
elemRect.bottom <= containerRect.bottom &&
|
|
11924
|
+
elemRect.left >= containerRect.left &&
|
|
11925
|
+
elemRect.right <= containerRect.right;
|
|
11926
|
+
|
|
11927
|
+
return isFullyVisible;
|
|
11928
|
+
}
|
|
11929
|
+
|
|
11930
|
+
/**
|
|
11931
|
+
* Checks if the given element is fully visible within the boundaries of a container (top and bottom).
|
|
11932
|
+
*
|
|
11933
|
+
* @param {TinyElement} cont - The container element acting as the viewport.
|
|
11934
|
+
* @returns {boolean} True if the element is fully visible within the container, false otherwise.
|
|
11935
|
+
*/
|
|
11936
|
+
isFullyInContainer(cont) {
|
|
11937
|
+
return TinyHtml_TinyHtml.isFullyInContainer(this, cont);
|
|
11938
|
+
}
|
|
11939
|
+
|
|
11940
|
+
/**
|
|
11941
|
+
* Checks if an element has scrollable content.
|
|
11942
|
+
*
|
|
11943
|
+
* @param {TinyElement} el - The DOM element to check.
|
|
11944
|
+
* @returns {{ v: boolean, h: boolean }} - True if scroll is needed in that direction.
|
|
11945
|
+
*/
|
|
11946
|
+
static hasScroll(el) {
|
|
11947
|
+
const elem = TinyHtml_TinyHtml._preElem(el, 'hasScroll');
|
|
11948
|
+
return {
|
|
11949
|
+
v: elem.scrollHeight > elem.clientHeight,
|
|
11950
|
+
h: elem.scrollWidth > elem.clientWidth,
|
|
11951
|
+
};
|
|
11952
|
+
}
|
|
11953
|
+
|
|
11954
|
+
/**
|
|
11955
|
+
* Checks if an element has scrollable content.
|
|
11956
|
+
*
|
|
11957
|
+
* @returns {{ v: boolean, h: boolean }} - True if scroll is needed in that direction.
|
|
11958
|
+
*/
|
|
11959
|
+
hasScroll() {
|
|
11960
|
+
return TinyHtml_TinyHtml.hasScroll(this);
|
|
11961
|
+
}
|
|
11962
|
+
}
|
|
11963
|
+
|
|
11964
|
+
/* harmony default export */ const libs_TinyHtml = (TinyHtml_TinyHtml);
|
|
11965
|
+
|
|
11966
|
+
;// ./src/v1/basics/html_deprecated.mjs
|
|
11967
|
+
|
|
11968
|
+
|
|
11969
|
+
/**
|
|
11970
|
+
* Checks if two DOM elements are colliding on the screen.
|
|
11971
|
+
*
|
|
11972
|
+
* @param {Element} elem1 - First DOM element.
|
|
11973
|
+
* @param {Element} elem2 - Second DOM element.
|
|
11974
|
+
* @returns {boolean} - Returns true if the elements are colliding.
|
|
11975
|
+
* @deprecated - Use TinyHtml.isCollWith instead.
|
|
11976
|
+
*/
|
|
11977
|
+
function areHtmlElsColliding(elem1, elem2) {
|
|
11978
|
+
return libs_TinyHtml.isCollWith(elem1, elem2);
|
|
11979
|
+
}
|
|
11980
|
+
|
|
11981
|
+
/**
|
|
11982
|
+
* Checks if two DOM elements are colliding on the screen.
|
|
11983
|
+
*
|
|
11984
|
+
* @param {Element} elem1 - First DOM element.
|
|
11985
|
+
* @param {Element} elem2 - Second DOM element.
|
|
11986
|
+
* @returns {boolean} - Returns true if the elements are colliding.
|
|
11987
|
+
* @deprecated - Use TinyHtml.isCollPerfWith instead.
|
|
11988
|
+
*/
|
|
11351
11989
|
function areHtmlElsPerfColliding(elem1, elem2) {
|
|
11352
11990
|
return TinyHtml.isCollPerfWith(elem1, elem2);
|
|
11353
11991
|
}
|
|
@@ -13951,7 +14589,1941 @@ class TinyAfterScrollWatcher {
|
|
|
13951
14589
|
|
|
13952
14590
|
/* harmony default export */ const libs_TinyAfterScrollWatcher = (TinyAfterScrollWatcher);
|
|
13953
14591
|
|
|
13954
|
-
;// ./src/v1/
|
|
14592
|
+
;// ./src/v1/libs/UltraRandomMsgGen.mjs
|
|
14593
|
+
const defaultWords = [
|
|
14594
|
+
'lorem',
|
|
14595
|
+
'ipsum',
|
|
14596
|
+
'dolor',
|
|
14597
|
+
'sit',
|
|
14598
|
+
'amet',
|
|
14599
|
+
'consectetur',
|
|
14600
|
+
'adipiscing',
|
|
14601
|
+
'elit',
|
|
14602
|
+
'sed',
|
|
14603
|
+
'do',
|
|
14604
|
+
'eiusmod',
|
|
14605
|
+
'tempor',
|
|
14606
|
+
'incididunt',
|
|
14607
|
+
'ut',
|
|
14608
|
+
'labore',
|
|
14609
|
+
'et',
|
|
14610
|
+
'dolore',
|
|
14611
|
+
'magna',
|
|
14612
|
+
'aliqua',
|
|
14613
|
+
];
|
|
14614
|
+
const defaultEmojis = [
|
|
14615
|
+
'😂',
|
|
14616
|
+
'🌈',
|
|
14617
|
+
'🤖',
|
|
14618
|
+
'💥',
|
|
14619
|
+
'🐸',
|
|
14620
|
+
'🍕',
|
|
14621
|
+
'🦄',
|
|
14622
|
+
'🧠',
|
|
14623
|
+
'🧬',
|
|
14624
|
+
'🚀',
|
|
14625
|
+
'🫠',
|
|
14626
|
+
'💫',
|
|
14627
|
+
'🍩',
|
|
14628
|
+
'👾',
|
|
14629
|
+
'🎉',
|
|
14630
|
+
'🥴',
|
|
14631
|
+
'🐙',
|
|
14632
|
+
'🧃',
|
|
14633
|
+
'🪐',
|
|
14634
|
+
'🎈',
|
|
14635
|
+
'🧸',
|
|
14636
|
+
'👻',
|
|
14637
|
+
'🥳',
|
|
14638
|
+
'🍭',
|
|
14639
|
+
'💖',
|
|
14640
|
+
'😺',
|
|
14641
|
+
'🌮',
|
|
14642
|
+
'🪅',
|
|
14643
|
+
'🎮',
|
|
14644
|
+
'🥓',
|
|
14645
|
+
'🍮',
|
|
14646
|
+
];
|
|
14647
|
+
|
|
14648
|
+
const defaultNouns = [
|
|
14649
|
+
'pudding',
|
|
14650
|
+
'bean',
|
|
14651
|
+
'snuggle',
|
|
14652
|
+
'bloop',
|
|
14653
|
+
'jelly',
|
|
14654
|
+
'unicorn',
|
|
14655
|
+
'floof',
|
|
14656
|
+
'giggle',
|
|
14657
|
+
'bubble',
|
|
14658
|
+
'muffin',
|
|
14659
|
+
'puff',
|
|
14660
|
+
'pickle',
|
|
14661
|
+
'goblin',
|
|
14662
|
+
'waffle',
|
|
14663
|
+
'sprinkle',
|
|
14664
|
+
'cupcake',
|
|
14665
|
+
'fizzle',
|
|
14666
|
+
'marshmallow',
|
|
14667
|
+
'duckling',
|
|
14668
|
+
'sock',
|
|
14669
|
+
'cloud',
|
|
14670
|
+
'teacup',
|
|
14671
|
+
'nugget',
|
|
14672
|
+
'gnome',
|
|
14673
|
+
'hug',
|
|
14674
|
+
'moonbean',
|
|
14675
|
+
'crayon',
|
|
14676
|
+
'jiggle',
|
|
14677
|
+
'glitter',
|
|
14678
|
+
'carrot',
|
|
14679
|
+
'goober',
|
|
14680
|
+
];
|
|
14681
|
+
|
|
14682
|
+
const defaultVerbs = [
|
|
14683
|
+
'wiggles',
|
|
14684
|
+
'bounces',
|
|
14685
|
+
'flies',
|
|
14686
|
+
'splats',
|
|
14687
|
+
'scoots',
|
|
14688
|
+
'giggles',
|
|
14689
|
+
'wigglesnacks',
|
|
14690
|
+
'twirls',
|
|
14691
|
+
'boops',
|
|
14692
|
+
'pops',
|
|
14693
|
+
'sings',
|
|
14694
|
+
'hugs',
|
|
14695
|
+
'floats',
|
|
14696
|
+
'glows',
|
|
14697
|
+
'flaps',
|
|
14698
|
+
'mlems',
|
|
14699
|
+
'dances',
|
|
14700
|
+
'puddles',
|
|
14701
|
+
'nomnoms',
|
|
14702
|
+
'wigglejumps',
|
|
14703
|
+
'sniffs',
|
|
14704
|
+
'tumbles',
|
|
14705
|
+
'slides',
|
|
14706
|
+
'chirps',
|
|
14707
|
+
'burps',
|
|
14708
|
+
'sparkles',
|
|
14709
|
+
'waddles',
|
|
14710
|
+
'rambles',
|
|
14711
|
+
'blinks',
|
|
14712
|
+
'mews',
|
|
14713
|
+
];
|
|
14714
|
+
|
|
14715
|
+
const defaultAdjectives = [
|
|
14716
|
+
'fluffy',
|
|
14717
|
+
'silly',
|
|
14718
|
+
'yummy',
|
|
14719
|
+
'squishy',
|
|
14720
|
+
'wobbly',
|
|
14721
|
+
'magical',
|
|
14722
|
+
'tiny',
|
|
14723
|
+
'sleepy',
|
|
14724
|
+
'wiggly',
|
|
14725
|
+
'bubbly',
|
|
14726
|
+
'glittery',
|
|
14727
|
+
'fuzzy',
|
|
14728
|
+
'jiggly',
|
|
14729
|
+
'sparkly',
|
|
14730
|
+
'giggly',
|
|
14731
|
+
'crunchy',
|
|
14732
|
+
'goofy',
|
|
14733
|
+
'soft',
|
|
14734
|
+
'mushy',
|
|
14735
|
+
'sweet',
|
|
14736
|
+
'loopy',
|
|
14737
|
+
'floaty',
|
|
14738
|
+
'bonkers',
|
|
14739
|
+
'chewy',
|
|
14740
|
+
'ticklish',
|
|
14741
|
+
'dreamy',
|
|
14742
|
+
'pastel',
|
|
14743
|
+
'cozy',
|
|
14744
|
+
'teensy',
|
|
14745
|
+
'grumbly',
|
|
14746
|
+
];
|
|
14747
|
+
|
|
14748
|
+
const defaultTemplates = [
|
|
14749
|
+
// 🧁 Tiny
|
|
14750
|
+
'Boop!',
|
|
14751
|
+
'Wiggle achieved.',
|
|
14752
|
+
'Oops, {noun} everywhere!',
|
|
14753
|
+
'Tiny {adj} {noun}, big {adj} {noun}.',
|
|
14754
|
+
'Snuggle initiated with a {adj} {noun}.',
|
|
14755
|
+
'{adj} vibes only, powered by {noun}.',
|
|
14756
|
+
'No {noun}, no {noun}.',
|
|
14757
|
+
'Bounce first, {verb} later.',
|
|
14758
|
+
'Mlem. {verb}. {noun}.',
|
|
14759
|
+
'{noun} go brrr and {verb}.',
|
|
14760
|
+
'Why not? {noun} did. Then {noun} followed.',
|
|
14761
|
+
|
|
14762
|
+
// 🍬 Simple
|
|
14763
|
+
'A {adj} {noun} just {verb} near the {adj} window.',
|
|
14764
|
+
'That {adj} {noun} stole my {noun}!',
|
|
14765
|
+
'Look, a {adj} {noun} trying to {verb} again!',
|
|
14766
|
+
'Every {noun} deserves a {adj} nap.',
|
|
14767
|
+
'The {adj} {noun} is my {adj} spirit animal.',
|
|
14768
|
+
'Someone call the {noun}, it’s {verb}ing and {verb}ing again!',
|
|
14769
|
+
'Don’t touch the {adj} {noun}. It {verb}s loudly.',
|
|
14770
|
+
'{noun} forgot how {noun}s work and just {verb}ed.',
|
|
14771
|
+
|
|
14772
|
+
// 🍩 Averages
|
|
14773
|
+
'There once was a {adj} {noun} who loved to {verb} with a {adj} {noun} all day.',
|
|
14774
|
+
'Apparently, {noun}s are banned from {verb}ing and {verb}ing in the {noun} library.',
|
|
14775
|
+
'That {adj} noise? Just a {noun} learning to {verb} on a {adj} {noun}.',
|
|
14776
|
+
'I saw a {adj} {noun} {verb} so hard, it became a {adj} muffin.',
|
|
14777
|
+
'The {adj} {noun} met a {adj} pickle and everything {verb}ed.',
|
|
14778
|
+
'{noun}s are like {noun}: {adj}, unpredictable, and wiggly.',
|
|
14779
|
+
'Don’t judge a {adj} {noun} by its ability to {verb}, or by its {adj} hat.',
|
|
14780
|
+
'All I wanted was peace, but a {adj} {noun} with a {adj} {noun} had other plans.',
|
|
14781
|
+
|
|
14782
|
+
// 🍓 Giants
|
|
14783
|
+
'One {adj} morning, a {adj} {noun} decided it was finally time to {verb}, but halfway through, it tripped on a {noun} and turned into a {adj} marshmallow.',
|
|
14784
|
+
'I tried to be {adj} today, but then a {noun} {verb}ed across my {noun} and typed “asdfgh{noun}” repeatedly.',
|
|
14785
|
+
'If you think you’ve seen everything, wait until a {adj} {noun} {verb}s on a {noun} wearing {adj} socks with tiny {noun}s.',
|
|
14786
|
+
'No one ever believed the stories about the ancient {adj} {noun} who could {verb} with such {adj} grace that entire {noun}s turned pink out of embarrassment.',
|
|
14787
|
+
'A curious {adj} {noun} wandered into a {noun} shop, not knowing that its destiny involved twelve {adj} {noun}s, one rubber {noun}, and a suspiciously quiet {adj} llama.',
|
|
14788
|
+
|
|
14789
|
+
// 🍒 Giants and narratives
|
|
14790
|
+
'In a land where every {adj} {noun} was made of pudding and the sky was {adj} whipped cream, one brave {adj} {noun} set out to discover the legendary Spoon of {noun}s, facing obstacles like bouncing {noun}s, sassy {noun}s, and the Great Wobble of the {noun}.',
|
|
14791
|
+
'Once upon a {adj} time, long before the {noun}s learned to {verb}, there existed a tiny {adj} {noun} who dreamed of swimming in a pool made entirely of {adj} glitter pudding while {verb}ing off-key lullabies to passing {noun}s with monocles.',
|
|
14792
|
+
'The Council of {noun}s gathered in {adj} secret when the sacred {adj} {noun} started to {verb} uncontrollably, threatening the entire {adj} dessert-based civilization with spontaneous {noun} jiggles and uncontainable {noun} fits across the {noun}.',
|
|
14793
|
+
|
|
14794
|
+
// ☎️ Chats and chats
|
|
14795
|
+
'Hey... do you ever wonder if {noun}s dream of {noun}s?',
|
|
14796
|
+
'Okay but hear me out: what if the {adj} {noun} could actually {verb} backwards?',
|
|
14797
|
+
'Can we talk about the {noun} that just {verb}ed and vanished?',
|
|
14798
|
+
'So I was talking to a {noun}, and it told me to stop being {adj}. Rude.',
|
|
14799
|
+
'Not to alarm you, but there’s a {adj} {noun} behind you doing the {verb}.',
|
|
14800
|
+
'Why does this {noun} keep staring at me like I owe it pudding?',
|
|
14801
|
+
'Is this a safe space to admit I accidentally {verb}ed a {noun}?',
|
|
14802
|
+
'I just walked into the room and someone shouted “{adj} {noun}!” — what did I miss?',
|
|
14803
|
+
'Wait... we were supposed to bring a {noun}? No one told me!',
|
|
14804
|
+
'Okay but what if the {adj} {noun} has feelings too?',
|
|
14805
|
+
'Be honest, do I look like a {noun} that forgot how to {verb}?',
|
|
14806
|
+
'If I say "oops", do I still have to explain why the {noun} is glowing?',
|
|
14807
|
+
'I don’t know what’s going on but I brought snacks and a confused {noun}.',
|
|
14808
|
+
'Do you think pudding knows it’s pudding? Just a thought.',
|
|
14809
|
+
'Is this about the time I {verb}ed the {adj} {noun} by accident? Because I can explain.',
|
|
14810
|
+
|
|
14811
|
+
// 🌀 Confusions, unexpected entrances, lost people
|
|
14812
|
+
'Wait, are we talking about {noun}s or am I on the wrong chat again?',
|
|
14813
|
+
'What is this group even about? I just saw "pudding" and joined.',
|
|
14814
|
+
'Hi! I have no idea what’s happening but I’m here and I brought a {noun}.',
|
|
14815
|
+
'I blinked and now there’s a {adj} {noun} in charge of everything.',
|
|
14816
|
+
'Can someone please explain why the {noun} is floating and chanting?',
|
|
14817
|
+
'Okay who gave the {noun} access to glitter and emotional support pickles?',
|
|
14818
|
+
'I came for a calm discussion and now there’s a {adj} battle between {noun}s.',
|
|
14819
|
+
'Not sure if I’m early, late, or inside a {noun} dream.',
|
|
14820
|
+
'I was gone for 3 minutes and now someone’s riding a {noun} into the pudding realm.',
|
|
14821
|
+
'This isn’t the pudding appreciation group, is it? ...oh no.',
|
|
14822
|
+
'So... who summoned the {adj} {noun} this time? Be honest.',
|
|
14823
|
+
'I came here for vibes and stayed for the {noun}s.',
|
|
14824
|
+
'Does anyone else hear faint giggling or is that just the {adj} {noun} again?',
|
|
14825
|
+
'I feel like I missed step one, two, and also three of this conversation.',
|
|
14826
|
+
'All I asked was “what’s up?” and now I’m emotionally attached to a {noun}.',
|
|
14827
|
+
|
|
14828
|
+
// 💬 More interactive chat style
|
|
14829
|
+
'Me: "I’ll be normal today." Also me: *{verb}s into a meeting riding a {adj} {noun}*',
|
|
14830
|
+
'"It’s just pudding," they said. "It can’t hurt you," they said. They were wrong.',
|
|
14831
|
+
'I said one nice thing to a {noun} and now it follows me everywhere.',
|
|
14832
|
+
'Can we take a moment to appreciate how the {adj} {noun} is just vibing?',
|
|
14833
|
+
'Who put a tiny hat on the {noun}? Because that’s adorable.',
|
|
14834
|
+
'My life has been different ever since the {noun} started {verb}ing.',
|
|
14835
|
+
'Raise your hand if you’ve ever been personally attacked by a {adj} {noun}.',
|
|
14836
|
+
'"Don’t be weird," they said. So I became a {noun} instead.',
|
|
14837
|
+
'Do {noun}s have feelings? Asking for a {adj} friend.',
|
|
14838
|
+
'I trusted the {noun} and all I got was a glitter-covered sock.',
|
|
14839
|
+
'Plot twist: the {adj} {noun} was inside us all along.',
|
|
14840
|
+
|
|
14841
|
+
// Mini cute explosions and chaos
|
|
14842
|
+
'The {adj} {noun} {verb} and {verb} all over the {adj} {noun}!',
|
|
14843
|
+
'Oops! {noun}s {verb}ed into the {adj} {noun} while {verb}ing crazily.',
|
|
14844
|
+
'{adj}, {adj}, and more {adj} {noun}s just {verb}ed by!',
|
|
14845
|
+
'Why does the {adj} {noun} keep {verb}ing and {verb}ing without stopping?',
|
|
14846
|
+
'Look! A {adj} {noun}, a {adj} {noun}, and a {noun} all {verb}ing together!',
|
|
14847
|
+
'Sometimes, the {noun} just {verb}s, then {verb}s again, and never stops being {adj}.',
|
|
14848
|
+
|
|
14849
|
+
// Phrases with repetition and multiple spaces for chaos
|
|
14850
|
+
'{noun}, {noun}, and {noun} — all {verb}ing and {verb}ing in a {adj} {noun}.',
|
|
14851
|
+
'I saw a {adj} {noun} {verb}, then another {noun} {verb}ing with a {adj} {noun}.',
|
|
14852
|
+
'The {noun} {verb}s {verb} while the {adj} {noun} {verb}s and the {noun} just {verb}s.',
|
|
14853
|
+
'Can a {adj} {noun} {verb} {verb} without a {adj} {noun} watching?',
|
|
14854
|
+
|
|
14855
|
+
// Phrases with interactions and breaks for fun
|
|
14856
|
+
'Whoa! The {adj} {noun} just {verb}ed... and then {verb}ed again!',
|
|
14857
|
+
'Hey... did you see that {adj} {noun} {verb} over there?',
|
|
14858
|
+
'Umm, the {noun} is {verb}ing but also {verb}ing and {verb}ing!',
|
|
14859
|
+
'Lol! {noun}s {verb} so {adj}ly, it’s impossible not to giggle.',
|
|
14860
|
+
|
|
14861
|
+
// Mini exaggerated and cute dialogues
|
|
14862
|
+
'"Hey! What’s up?" asked the {adj} {noun}, who {verb}ed loudly.',
|
|
14863
|
+
'"I’m just a {adj} {noun} trying to {verb}, you know?"',
|
|
14864
|
+
'"Did you see the {adj} {noun} that just {verb}ed in the pudding?"',
|
|
14865
|
+
'"No way! The {noun} {verb}s better than me!"',
|
|
14866
|
+
'"Wait, the {adj} {noun} said it would {verb}, but it {verb}ed instead!"',
|
|
14867
|
+
|
|
14868
|
+
// Extensive, crazy and fun narrative phrases
|
|
14869
|
+
'Once upon a {adj} {noun}, a group of {adj} {noun}s {verb}ed through the {adj} forest, singing {adj} songs and eating {noun}s made of pudding.',
|
|
14870
|
+
'The legend tells of a {adj} {noun} who could {verb} faster than any {noun} ever seen, leaving trails of {adj} sparkles behind.',
|
|
14871
|
+
'Every day, the {adj} {noun} would {verb} around the {adj} meadow, trying to convince the {noun}s to join the grand pudding party.',
|
|
14872
|
+
'No one knows why the {adj} {noun} suddenly {verb}ed and then {verb}ed again, but everyone agrees it was the cutest thing they ever saw.',
|
|
14873
|
+
'In the kingdom of {adj} {noun}s, only the bravest {noun} dared to {verb} the giant pudding monster, armed with nothing but {adj} smiles and jellybeans.',
|
|
14874
|
+
|
|
14875
|
+
// Total cases with many placeholders
|
|
14876
|
+
'{adj} {noun} {verb} {verb} {verb} {noun} {verb} {adj} {noun} {verb} {noun}!',
|
|
14877
|
+
'{noun} {noun} {verb} {adj} {noun} and then {verb} {verb} the {adj} {noun}.',
|
|
14878
|
+
'{verb} the {adj} {noun}, then {verb} the {noun} while {verb}ing {adj}ly.',
|
|
14879
|
+
'Can the {adj} {noun} {verb} and {verb} the {adj} {noun} at the same time?',
|
|
14880
|
+
'{noun} {verb} {noun} {verb}, but the {adj} {noun} {verb}s better.',
|
|
14881
|
+
|
|
14882
|
+
// Frases with cute interjections and silly sounds
|
|
14883
|
+
'Boop! The {adj} {noun} just {verb}ed in the pudding.',
|
|
14884
|
+
'Bloop bloop, the {noun} is {verb}ing all over again!',
|
|
14885
|
+
'Mlem mlem, a {adj} {noun} {verb}s quietly in the corner.',
|
|
14886
|
+
'Splat! {noun} {verb}ed right on the {adj} {noun}.',
|
|
14887
|
+
'Yum! A {adj} {noun} just {verb}ed in my mouth.',
|
|
14888
|
+
|
|
14889
|
+
// Phrases with silly questions
|
|
14890
|
+
'Do {noun}s really {verb} when nobody’s watching?',
|
|
14891
|
+
'Why does the {adj} {noun} always {verb} at midnight?',
|
|
14892
|
+
'Can a {noun} be too {adj} to {verb} properly?',
|
|
14893
|
+
'Is it normal for a {adj} {noun} to {verb} three times in a row?',
|
|
14894
|
+
'Who taught the {noun} to {verb} like that?',
|
|
14895
|
+
|
|
14896
|
+
// Frases of confusion and fun surprises
|
|
14897
|
+
'Wait, did the {adj} {noun} just {verb} itself?',
|
|
14898
|
+
'I can’t believe the {noun} {verb}ed into a {adj} {noun}!',
|
|
14899
|
+
'Suddenly, a {adj} {noun} appeared and started to {verb} wildly.',
|
|
14900
|
+
'That {noun} was {verb}ing so {adj}ly it broke the pudding meter.',
|
|
14901
|
+
'Everyone’s talking about the {adj} {noun} that {verb}ed out of nowhere.',
|
|
14902
|
+
];
|
|
14903
|
+
|
|
14904
|
+
/**
|
|
14905
|
+
* @typedef {'mixed'|'readable'|'chaotic'|'natural'} RandomMsgModes
|
|
14906
|
+
* Defines how the message content is generated:
|
|
14907
|
+
* - `mixed`: Combines readable words, gibberish, symbols, emojis, etc.
|
|
14908
|
+
* - `readable`: Focuses on human-readable words only.
|
|
14909
|
+
* - `chaotic`: Pure chaos, mostly gibberish and symbols.
|
|
14910
|
+
* - `natural`: Uses structured grammar templates to form silly but proper sentences.
|
|
14911
|
+
*/
|
|
14912
|
+
|
|
14913
|
+
/**
|
|
14914
|
+
* @typedef {'inline'|'end'|'none'} EmojiPlacement
|
|
14915
|
+
* Controls where emojis are placed:
|
|
14916
|
+
* - `inline`: Emojis may appear throughout the text.
|
|
14917
|
+
* - `end`: Emojis appear at the end of lines.
|
|
14918
|
+
* - `none`: No emojis will be used.
|
|
14919
|
+
*/
|
|
14920
|
+
|
|
14921
|
+
/**
|
|
14922
|
+
* @typedef {Object} MsgGenConfig
|
|
14923
|
+
* Configuration object for customizing message generation.
|
|
14924
|
+
*
|
|
14925
|
+
* @property {number} minLength - Minimum total length (in characters) of the final generated text.
|
|
14926
|
+
* @property {number} maxLength - Maximum total length (in characters) of the final generated text.
|
|
14927
|
+
* @property {boolean} readable - Whether to favor readable word-like strings.
|
|
14928
|
+
* @property {boolean} useEmojis - Whether emojis are allowed in the generated content.
|
|
14929
|
+
* @property {boolean} includeNumbers - Whether random numbers can appear in the text.
|
|
14930
|
+
* @property {boolean} includeSymbols - Whether random symbols (e.g., !@#) are included.
|
|
14931
|
+
* @property {boolean} allowWeirdSpacing - Enables fun spacing effects (e.g., extra spaces, newlines, uppercase words).
|
|
14932
|
+
*
|
|
14933
|
+
* @property {string[]} emojiSet - List of emojis to choose from. Overrides default set if provided.
|
|
14934
|
+
* @property {string[]} wordSet - List of base words used in readable and mixed modes.
|
|
14935
|
+
*
|
|
14936
|
+
* @property {RandomMsgModes} mode - Determines the overall generation strategy (`mixed`, `readable`, `chaotic`, or `natural`).
|
|
14937
|
+
*
|
|
14938
|
+
* @property {Object} grammar - Grammar configuration used when `mode` is set to `'natural'`.
|
|
14939
|
+
* @property {string[]} grammar.templates - Sentence templates using placeholders (`{noun}`, `{verb}`, `{adj}`).
|
|
14940
|
+
* @property {string[]} grammar.nouns - List of nouns to insert into `{noun}` placeholders.
|
|
14941
|
+
* @property {string[]} grammar.verbs - List of verbs to insert into `{verb}` placeholders.
|
|
14942
|
+
* @property {string[]} grammar.adjectives - List of adjectives to insert into `{adj}` placeholders.
|
|
14943
|
+
*
|
|
14944
|
+
* @property {boolean} repeatWords - If false, avoids repeating the same word within a single generation.
|
|
14945
|
+
* @property {EmojiPlacement} emojiPlacement - Controls how emojis are placed in the text.
|
|
14946
|
+
*
|
|
14947
|
+
* @property {Object} [paragraphs] - Optional paragraph configuration.
|
|
14948
|
+
* @property {number} paragraphs.min - Minimum number of paragraphs to generate.
|
|
14949
|
+
* @property {number} paragraphs.max - Maximum number of paragraphs to generate.
|
|
14950
|
+
*
|
|
14951
|
+
* @property {Object} line - Configuration for line-based generation.
|
|
14952
|
+
* @property {number} line.minLength - Minimum number of characters per line.
|
|
14953
|
+
* @property {number} line.maxLength - Maximum number of characters per line.
|
|
14954
|
+
* @property {number} line.emojiChance - Probability (0 to 1) that a line will end with an emoji when allowed.
|
|
14955
|
+
*/
|
|
14956
|
+
|
|
14957
|
+
/**
|
|
14958
|
+
* UltraRandomMsgGen - Phrase templates and word lists
|
|
14959
|
+
*
|
|
14960
|
+
* Portions of the templates, word sets, and phrase structures
|
|
14961
|
+
* were generated and expanded by ChatGPT (OpenAI).
|
|
14962
|
+
*
|
|
14963
|
+
* This content was crafted to produce innocent, playful, and diverse
|
|
14964
|
+
* random messages focused on a pudding-themed, whimsical style.
|
|
14965
|
+
*
|
|
14966
|
+
* @class
|
|
14967
|
+
*/
|
|
14968
|
+
class UltraRandomMsgGen {
|
|
14969
|
+
/** @type {string[]} */
|
|
14970
|
+
static defaultWords = defaultWords;
|
|
14971
|
+
/** @type {string[]} */
|
|
14972
|
+
static defaultEmojis = defaultEmojis;
|
|
14973
|
+
/** @type {string[]} */
|
|
14974
|
+
static defaultNouns = defaultNouns;
|
|
14975
|
+
/** @type {string[]} */
|
|
14976
|
+
static defaultVerbs = defaultVerbs;
|
|
14977
|
+
/** @type {string[]} */
|
|
14978
|
+
static defaultAdjectives = defaultAdjectives;
|
|
14979
|
+
/** @type {string[]} */
|
|
14980
|
+
static defaultTemplates = defaultTemplates;
|
|
14981
|
+
|
|
14982
|
+
/** @type {MsgGenConfig} */
|
|
14983
|
+
config = {
|
|
14984
|
+
minLength: 10,
|
|
14985
|
+
maxLength: 300,
|
|
14986
|
+
readable: true,
|
|
14987
|
+
useEmojis: true,
|
|
14988
|
+
includeNumbers: true,
|
|
14989
|
+
includeSymbols: true,
|
|
14990
|
+
allowWeirdSpacing: false,
|
|
14991
|
+
emojiSet: [],
|
|
14992
|
+
wordSet: [],
|
|
14993
|
+
mode: 'mixed', // 'mixed', 'readable', 'chaotic'
|
|
14994
|
+
grammar: {
|
|
14995
|
+
templates: [],
|
|
14996
|
+
nouns: [],
|
|
14997
|
+
verbs: [],
|
|
14998
|
+
adjectives: [],
|
|
14999
|
+
},
|
|
15000
|
+
repeatWords: true,
|
|
15001
|
+
emojiPlacement: 'inline', // 'inline' | 'end' | 'none'
|
|
15002
|
+
line: {
|
|
15003
|
+
minLength: 20,
|
|
15004
|
+
maxLength: 120,
|
|
15005
|
+
emojiChance: 0.3, // 30% chance per line
|
|
15006
|
+
},
|
|
15007
|
+
};
|
|
15008
|
+
|
|
15009
|
+
/**
|
|
15010
|
+
* Creates an instance of UltraRandomMsgGen.
|
|
15011
|
+
*
|
|
15012
|
+
* @param {Object} [config={}] - Configuration object to customize the generator.
|
|
15013
|
+
* @param {number} [config.minLength=10] - Minimum total length (in characters) of generated text.
|
|
15014
|
+
* @param {number} [config.maxLength=300] - Maximum total length (in characters) of generated text.
|
|
15015
|
+
* @param {boolean} [config.readable=true] - Whether to generate readable words or random strings.
|
|
15016
|
+
* @param {boolean} [config.useEmojis=true] - Whether to include emojis in the generated text.
|
|
15017
|
+
* @param {boolean} [config.includeNumbers=true] - Whether to include numbers randomly.
|
|
15018
|
+
* @param {boolean} [config.includeSymbols=true] - Whether to include symbols randomly.
|
|
15019
|
+
* @param {boolean} [config.allowWeirdSpacing=false] - Whether to allow weird spacing (newlines, extra spaces, uppercase).
|
|
15020
|
+
* @param {string[]} [config.emojiSet] - Array of emojis to use (defaults to internal emoji set).
|
|
15021
|
+
* @param {string[]} [config.wordSet] - Array of words to use (defaults to internal word set).
|
|
15022
|
+
* @param {RandomMsgModes} [config.mode='mixed'] - Mode of text generation.
|
|
15023
|
+
* @param {Object} [config.grammar] - Grammar configuration with templates and word categories.
|
|
15024
|
+
* @param {string[]} [config.grammar.templates] - Array of string templates with placeholders for generating sentences.
|
|
15025
|
+
* @param {string[]} [config.grammar.nouns] - Array of noun strings for template substitution.
|
|
15026
|
+
* @param {string[]} [config.grammar.verbs] - Array of verb strings for template substitution.
|
|
15027
|
+
* @param {string[]} [config.grammar.adjectives] - Array of adjective strings for template substitution.
|
|
15028
|
+
* @param {boolean} [config.repeatWords=true] - Whether to allow repeating words in the output.
|
|
15029
|
+
* @param {EmojiPlacement} [config.emojiPlacement='inline'] - Placement mode for emojis in generated text.
|
|
15030
|
+
* @param {Object} [config.paragraphs] - Paragraph configuration object or null for single block text.
|
|
15031
|
+
* @param {number} [config.paragraphs.min] - Minimum number of paragraphs to generate.
|
|
15032
|
+
* @param {number} [config.paragraphs.max] - Maximum number of paragraphs to generate.
|
|
15033
|
+
* @param {Object} [config.line] - Line configuration for generated text.
|
|
15034
|
+
* @param {number} [config.line.minLength=20] - Minimum length (characters) per line.
|
|
15035
|
+
* @param {number} [config.line.maxLength=120] - Maximum length (characters) per line.
|
|
15036
|
+
* @param {number} [config.line.emojiChance=0.3] - Probability (0–1) of placing emoji per line.
|
|
15037
|
+
*/
|
|
15038
|
+
constructor(config = {}) {
|
|
15039
|
+
this.symbols = '!@#$%^&*()-_=+[]{}|;:,.<>?/\\~'.split('');
|
|
15040
|
+
|
|
15041
|
+
const {
|
|
15042
|
+
minLength,
|
|
15043
|
+
maxLength,
|
|
15044
|
+
readable,
|
|
15045
|
+
useEmojis,
|
|
15046
|
+
includeNumbers,
|
|
15047
|
+
includeSymbols,
|
|
15048
|
+
allowWeirdSpacing,
|
|
15049
|
+
emojiSet,
|
|
15050
|
+
wordSet,
|
|
15051
|
+
mode,
|
|
15052
|
+
grammar,
|
|
15053
|
+
repeatWords,
|
|
15054
|
+
emojiPlacement,
|
|
15055
|
+
paragraphs,
|
|
15056
|
+
line,
|
|
15057
|
+
} = config;
|
|
15058
|
+
|
|
15059
|
+
// Validations
|
|
15060
|
+
if (minLength !== undefined && (!Number.isInteger(minLength) || minLength < 1)) {
|
|
15061
|
+
throw new TypeError('config.minLength must be an integer >= 1');
|
|
15062
|
+
}
|
|
15063
|
+
|
|
15064
|
+
if (maxLength !== undefined && (!Number.isInteger(maxLength) || maxLength < 1)) {
|
|
15065
|
+
throw new TypeError('config.maxLength must be an integer >= 1');
|
|
15066
|
+
}
|
|
15067
|
+
|
|
15068
|
+
if (minLength !== undefined && maxLength !== undefined && minLength > maxLength) {
|
|
15069
|
+
throw new RangeError('config.minLength cannot be greater than config.maxLength');
|
|
15070
|
+
}
|
|
15071
|
+
|
|
15072
|
+
if (readable !== undefined && typeof readable !== 'boolean') {
|
|
15073
|
+
throw new TypeError('config.readable must be a boolean');
|
|
15074
|
+
}
|
|
15075
|
+
|
|
15076
|
+
if (useEmojis !== undefined && typeof useEmojis !== 'boolean') {
|
|
15077
|
+
throw new TypeError('config.useEmojis must be a boolean');
|
|
15078
|
+
}
|
|
15079
|
+
|
|
15080
|
+
if (includeNumbers !== undefined && typeof includeNumbers !== 'boolean') {
|
|
15081
|
+
throw new TypeError('config.includeNumbers must be a boolean');
|
|
15082
|
+
}
|
|
15083
|
+
|
|
15084
|
+
if (includeSymbols !== undefined && typeof includeSymbols !== 'boolean') {
|
|
15085
|
+
throw new TypeError('config.includeSymbols must be a boolean');
|
|
15086
|
+
}
|
|
15087
|
+
|
|
15088
|
+
if (allowWeirdSpacing !== undefined && typeof allowWeirdSpacing !== 'boolean') {
|
|
15089
|
+
throw new TypeError('config.allowWeirdSpacing must be a boolean');
|
|
15090
|
+
}
|
|
15091
|
+
|
|
15092
|
+
if (emojiSet !== undefined && !Array.isArray(emojiSet)) {
|
|
15093
|
+
throw new TypeError('config.emojiSet must be an array of strings');
|
|
15094
|
+
}
|
|
15095
|
+
|
|
15096
|
+
if (wordSet !== undefined && !Array.isArray(wordSet)) {
|
|
15097
|
+
throw new TypeError('config.wordSet must be an array of strings');
|
|
15098
|
+
}
|
|
15099
|
+
|
|
15100
|
+
if (mode !== undefined && !['mixed', 'readable', 'chaotic', 'natural'].includes(mode)) {
|
|
15101
|
+
throw new RangeError('config.mode must be one of: "mixed", "readable", "chaotic", "natural');
|
|
15102
|
+
}
|
|
15103
|
+
|
|
15104
|
+
if (grammar !== undefined) {
|
|
15105
|
+
if (typeof grammar !== 'object' || grammar === null) {
|
|
15106
|
+
throw new TypeError('config.grammar must be an object');
|
|
15107
|
+
}
|
|
15108
|
+
const { templates, nouns, verbs, adjectives } = grammar;
|
|
15109
|
+
if (templates !== undefined && !Array.isArray(templates)) {
|
|
15110
|
+
throw new TypeError('config.grammar.templates must be an array of strings');
|
|
15111
|
+
}
|
|
15112
|
+
if (nouns !== undefined && !Array.isArray(nouns)) {
|
|
15113
|
+
throw new TypeError('config.grammar.nouns must be an array of strings');
|
|
15114
|
+
}
|
|
15115
|
+
if (verbs !== undefined && !Array.isArray(verbs)) {
|
|
15116
|
+
throw new TypeError('config.grammar.verbs must be an array of strings');
|
|
15117
|
+
}
|
|
15118
|
+
if (adjectives !== undefined && !Array.isArray(adjectives)) {
|
|
15119
|
+
throw new TypeError('config.grammar.adjectives must be an array of strings');
|
|
15120
|
+
}
|
|
15121
|
+
}
|
|
15122
|
+
|
|
15123
|
+
if (repeatWords !== undefined && typeof repeatWords !== 'boolean') {
|
|
15124
|
+
throw new TypeError('config.repeatWords must be a boolean');
|
|
15125
|
+
}
|
|
15126
|
+
|
|
15127
|
+
if (emojiPlacement !== undefined && !['inline', 'end', 'none'].includes(emojiPlacement)) {
|
|
15128
|
+
throw new RangeError('config.emojiPlacement must be one of: "inline", "end", "none"');
|
|
15129
|
+
}
|
|
15130
|
+
|
|
15131
|
+
if (paragraphs !== undefined) {
|
|
15132
|
+
if (typeof paragraphs !== 'object') {
|
|
15133
|
+
throw new TypeError('config.paragraphs must be an object or null');
|
|
15134
|
+
}
|
|
15135
|
+
const { min, max } = paragraphs;
|
|
15136
|
+
if (min !== undefined && (!Number.isInteger(min) || min < 1)) {
|
|
15137
|
+
throw new TypeError('config.paragraphs.min must be an integer >= 1');
|
|
15138
|
+
}
|
|
15139
|
+
if (max !== undefined && (!Number.isInteger(max) || max < 1)) {
|
|
15140
|
+
throw new TypeError('config.paragraphs.max must be an integer >= 1');
|
|
15141
|
+
}
|
|
15142
|
+
if (min !== undefined && max !== undefined && min > max) {
|
|
15143
|
+
throw new RangeError('config.paragraphs.min cannot be greater than config.paragraphs.max');
|
|
15144
|
+
}
|
|
15145
|
+
}
|
|
15146
|
+
|
|
15147
|
+
if (line !== undefined) {
|
|
15148
|
+
if (typeof line !== 'object' || line === null) {
|
|
15149
|
+
throw new TypeError('config.line must be an object');
|
|
15150
|
+
}
|
|
15151
|
+
const { minLength: lineMin, maxLength: lineMax, emojiChance } = line;
|
|
15152
|
+
if (lineMin !== undefined && (!Number.isInteger(lineMin) || lineMin < 1)) {
|
|
15153
|
+
throw new TypeError('config.line.minLength must be an integer >= 1');
|
|
15154
|
+
}
|
|
15155
|
+
if (lineMax !== undefined && (!Number.isInteger(lineMax) || lineMax < 1)) {
|
|
15156
|
+
throw new TypeError('config.line.maxLength must be an integer >= 1');
|
|
15157
|
+
}
|
|
15158
|
+
if (lineMin !== undefined && lineMax !== undefined && lineMin > lineMax) {
|
|
15159
|
+
throw new RangeError('config.line.minLength cannot be greater than config.line.maxLength');
|
|
15160
|
+
}
|
|
15161
|
+
if (
|
|
15162
|
+
emojiChance !== undefined &&
|
|
15163
|
+
(typeof emojiChance !== 'number' || emojiChance < 0 || emojiChance > 1)
|
|
15164
|
+
) {
|
|
15165
|
+
throw new RangeError('config.line.emojiChance must be a number between 0 and 1');
|
|
15166
|
+
}
|
|
15167
|
+
}
|
|
15168
|
+
|
|
15169
|
+
this.config.emojiSet = [...defaultEmojis];
|
|
15170
|
+
this.config.wordSet = [...defaultWords];
|
|
15171
|
+
|
|
15172
|
+
this.config.grammar.templates = [...defaultTemplates];
|
|
15173
|
+
this.config.grammar.nouns = [...defaultNouns];
|
|
15174
|
+
this.config.grammar.verbs = [...defaultVerbs];
|
|
15175
|
+
this.config.grammar.adjectives = [...defaultAdjectives];
|
|
15176
|
+
Object.assign(this.config, config);
|
|
15177
|
+
}
|
|
15178
|
+
|
|
15179
|
+
/**
|
|
15180
|
+
* Merges new configuration values into the current instance.
|
|
15181
|
+
* @param {Object} newConfig - Object with one or more configuration overrides.
|
|
15182
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15183
|
+
*/
|
|
15184
|
+
configure(newConfig = {}) {
|
|
15185
|
+
Object.assign(this.config, newConfig);
|
|
15186
|
+
return this;
|
|
15187
|
+
}
|
|
15188
|
+
|
|
15189
|
+
/**
|
|
15190
|
+
* Replaces the entire list of grammar templates.
|
|
15191
|
+
* @param {...string[]} templates - One or more arrays or strings containing sentence templates.
|
|
15192
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15193
|
+
*/
|
|
15194
|
+
setGrammarTemplates(...templates) {
|
|
15195
|
+
this.config.grammar.templates = templates.flat();
|
|
15196
|
+
return this;
|
|
15197
|
+
}
|
|
15198
|
+
|
|
15199
|
+
/**
|
|
15200
|
+
* Adds new grammar templates to the existing list.
|
|
15201
|
+
* @param {...string[]} templates - One or more arrays or strings containing sentence templates.
|
|
15202
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15203
|
+
*/
|
|
15204
|
+
addGrammarTemplates(...templates) {
|
|
15205
|
+
this.config.grammar.templates.push(...templates.flat());
|
|
15206
|
+
return this;
|
|
15207
|
+
}
|
|
15208
|
+
|
|
15209
|
+
/**
|
|
15210
|
+
* Replaces the list of noun words used in grammar templates.
|
|
15211
|
+
* @param {...string[]} nouns - One or more arrays or strings of nouns.
|
|
15212
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15213
|
+
*/
|
|
15214
|
+
setGrammarNouns(...nouns) {
|
|
15215
|
+
this.config.grammar.nouns = nouns.flat();
|
|
15216
|
+
return this;
|
|
15217
|
+
}
|
|
15218
|
+
|
|
15219
|
+
/**
|
|
15220
|
+
* Adds noun words to the existing list used in grammar templates.
|
|
15221
|
+
* @param {...string[]} nouns - One or more arrays or strings of nouns.
|
|
15222
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15223
|
+
*/
|
|
15224
|
+
addGrammarNouns(...nouns) {
|
|
15225
|
+
this.config.grammar.nouns.push(...nouns.flat());
|
|
15226
|
+
return this;
|
|
15227
|
+
}
|
|
15228
|
+
|
|
15229
|
+
/**
|
|
15230
|
+
* Replaces the list of verb words used in grammar templates.
|
|
15231
|
+
* @param {...string[]} verbs - One or more arrays or strings of verbs.
|
|
15232
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15233
|
+
*/
|
|
15234
|
+
setGrammarVerbs(...verbs) {
|
|
15235
|
+
this.config.grammar.verbs = verbs.flat();
|
|
15236
|
+
return this;
|
|
15237
|
+
}
|
|
15238
|
+
|
|
15239
|
+
/**
|
|
15240
|
+
* Adds verb words to the existing list used in grammar templates.
|
|
15241
|
+
* @param {...string[]} verbs - One or more arrays or strings of verbs.
|
|
15242
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15243
|
+
*/
|
|
15244
|
+
addGrammarVerbs(...verbs) {
|
|
15245
|
+
this.config.grammar.verbs.push(...verbs.flat());
|
|
15246
|
+
return this;
|
|
15247
|
+
}
|
|
15248
|
+
|
|
15249
|
+
/**
|
|
15250
|
+
* Replaces the list of adjective words used in grammar templates.
|
|
15251
|
+
* @param {...string[]} adjectives - One or more arrays or strings of adjectives.
|
|
15252
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15253
|
+
*/
|
|
15254
|
+
setGrammarAdjectives(...adjectives) {
|
|
15255
|
+
this.config.grammar.adjectives = adjectives.flat();
|
|
15256
|
+
return this;
|
|
15257
|
+
}
|
|
15258
|
+
|
|
15259
|
+
/**
|
|
15260
|
+
* Adds adjective words to the existing list used in grammar templates.
|
|
15261
|
+
* @param {...string[]} adjectives - One or more arrays or strings of adjectives.
|
|
15262
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15263
|
+
*/
|
|
15264
|
+
addGrammarAdjectives(...adjectives) {
|
|
15265
|
+
this.config.grammar.adjectives.push(...adjectives.flat());
|
|
15266
|
+
return this;
|
|
15267
|
+
}
|
|
15268
|
+
|
|
15269
|
+
/**
|
|
15270
|
+
* Removes specific grammar templates from the current list.
|
|
15271
|
+
* @param {...string[]} templates - One or more arrays or strings of templates to remove.
|
|
15272
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15273
|
+
*/
|
|
15274
|
+
removeGrammarTemplates(...templates) {
|
|
15275
|
+
const removeSet = new Set(templates.flat());
|
|
15276
|
+
this.config.grammar.templates = this.config.grammar.templates.filter((t) => !removeSet.has(t));
|
|
15277
|
+
return this;
|
|
15278
|
+
}
|
|
15279
|
+
|
|
15280
|
+
/**
|
|
15281
|
+
* Removes specific noun words from the grammar noun list.
|
|
15282
|
+
* @param {...string[]} nouns - One or more arrays or strings of nouns to remove.
|
|
15283
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15284
|
+
*/
|
|
15285
|
+
removeGrammarNouns(...nouns) {
|
|
15286
|
+
const removeSet = new Set(nouns.flat());
|
|
15287
|
+
this.config.grammar.nouns = this.config.grammar.nouns.filter((n) => !removeSet.has(n));
|
|
15288
|
+
return this;
|
|
15289
|
+
}
|
|
15290
|
+
|
|
15291
|
+
/**
|
|
15292
|
+
* Removes specific verb words from the grammar verb list.
|
|
15293
|
+
* @param {...string[]} verbs - One or more arrays or strings of verbs to remove.
|
|
15294
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15295
|
+
*/
|
|
15296
|
+
removeGrammarVerbs(...verbs) {
|
|
15297
|
+
const removeSet = new Set(verbs.flat());
|
|
15298
|
+
this.config.grammar.verbs = this.config.grammar.verbs.filter((v) => !removeSet.has(v));
|
|
15299
|
+
return this;
|
|
15300
|
+
}
|
|
15301
|
+
|
|
15302
|
+
/**
|
|
15303
|
+
* Removes specific adjective words from the grammar adjective list.
|
|
15304
|
+
* @param {...string[]} adjectives - One or more arrays or strings of adjectives to remove.
|
|
15305
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15306
|
+
*/
|
|
15307
|
+
removeGrammarAdjectives(...adjectives) {
|
|
15308
|
+
const removeSet = new Set(adjectives.flat());
|
|
15309
|
+
this.config.grammar.adjectives = this.config.grammar.adjectives.filter(
|
|
15310
|
+
(a) => !removeSet.has(a),
|
|
15311
|
+
);
|
|
15312
|
+
return this;
|
|
15313
|
+
}
|
|
15314
|
+
|
|
15315
|
+
/**
|
|
15316
|
+
* Replaces the entire word set used in readable/mixed modes.
|
|
15317
|
+
* @param {...string[]} words - One or more arrays or strings of words.
|
|
15318
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15319
|
+
*/
|
|
15320
|
+
setWords(...words) {
|
|
15321
|
+
this.config.wordSet = words.flat();
|
|
15322
|
+
return this;
|
|
15323
|
+
}
|
|
15324
|
+
|
|
15325
|
+
/**
|
|
15326
|
+
* Adds new words to the word set used in readable/mixed modes.
|
|
15327
|
+
* @param {...string[]} words - One or more arrays or strings of words.
|
|
15328
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15329
|
+
*/
|
|
15330
|
+
addWords(...words) {
|
|
15331
|
+
this.config.wordSet.push(...words.flat());
|
|
15332
|
+
return this;
|
|
15333
|
+
}
|
|
15334
|
+
|
|
15335
|
+
/**
|
|
15336
|
+
* Removes specific words from the word set.
|
|
15337
|
+
* @param {...string[]} words - Words to be removed.
|
|
15338
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15339
|
+
*/
|
|
15340
|
+
removeWords(...words) {
|
|
15341
|
+
const removeSet = new Set(words.flat());
|
|
15342
|
+
this.config.wordSet = this.config.wordSet.filter((word) => !removeSet.has(word));
|
|
15343
|
+
return this;
|
|
15344
|
+
}
|
|
15345
|
+
|
|
15346
|
+
/**
|
|
15347
|
+
* Replaces the emoji set used in generated output.
|
|
15348
|
+
* @param {...string[]} emojis - One or more arrays or strings of emojis.
|
|
15349
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15350
|
+
*/
|
|
15351
|
+
setEmojis(...emojis) {
|
|
15352
|
+
this.config.emojiSet = emojis.flat();
|
|
15353
|
+
return this;
|
|
15354
|
+
}
|
|
15355
|
+
|
|
15356
|
+
/**
|
|
15357
|
+
* Adds new emojis to the emoji set.
|
|
15358
|
+
* @param {...string[]} emojis - One or more arrays or strings of emojis.
|
|
15359
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15360
|
+
*/
|
|
15361
|
+
addEmojis(...emojis) {
|
|
15362
|
+
this.config.emojiSet.push(...emojis.flat());
|
|
15363
|
+
return this;
|
|
15364
|
+
}
|
|
15365
|
+
|
|
15366
|
+
/**
|
|
15367
|
+
* Removes specific emojis from the emoji set.
|
|
15368
|
+
* @param {...string[]} emojis - Emojis to be removed.
|
|
15369
|
+
* @returns {UltraRandomMsgGen} - The instance for chaining.
|
|
15370
|
+
*/
|
|
15371
|
+
removeEmojis(...emojis) {
|
|
15372
|
+
const removeSet = new Set(emojis.flat());
|
|
15373
|
+
this.config.emojiSet = this.config.emojiSet.filter((emoji) => !removeSet.has(emoji));
|
|
15374
|
+
return this;
|
|
15375
|
+
}
|
|
15376
|
+
|
|
15377
|
+
/**
|
|
15378
|
+
* Returns a random item from an array.
|
|
15379
|
+
* @private
|
|
15380
|
+
* @param {string[]} array - Array to pick from.
|
|
15381
|
+
* @returns {string} - Random item from array.
|
|
15382
|
+
*/
|
|
15383
|
+
_getRandomItem(array) {
|
|
15384
|
+
return array[Math.floor(Math.random() * array.length)];
|
|
15385
|
+
}
|
|
15386
|
+
|
|
15387
|
+
/**
|
|
15388
|
+
* Generates a single random content chunk based on the mode and settings.
|
|
15389
|
+
* @private
|
|
15390
|
+
* @returns {string} - A chunk (word, emoji, symbol, number, etc.).
|
|
15391
|
+
*/
|
|
15392
|
+
_generateChunk() {
|
|
15393
|
+
const {
|
|
15394
|
+
wordSet,
|
|
15395
|
+
emojiSet,
|
|
15396
|
+
includeNumbers,
|
|
15397
|
+
includeSymbols,
|
|
15398
|
+
useEmojis,
|
|
15399
|
+
readable,
|
|
15400
|
+
mode,
|
|
15401
|
+
emojiPlacement,
|
|
15402
|
+
} = this.config;
|
|
15403
|
+
|
|
15404
|
+
if (mode === 'natural') {
|
|
15405
|
+
return this._generateNaturalSentence();
|
|
15406
|
+
}
|
|
15407
|
+
|
|
15408
|
+
const pools = [];
|
|
15409
|
+
|
|
15410
|
+
if (readable || mode === 'readable' || mode === 'mixed') {
|
|
15411
|
+
pools.push(this._getRandomItem(wordSet));
|
|
15412
|
+
}
|
|
15413
|
+
|
|
15414
|
+
if (mode === 'chaotic' || mode === 'mixed') {
|
|
15415
|
+
pools.push(Math.random().toString(36).slice(2));
|
|
15416
|
+
}
|
|
15417
|
+
|
|
15418
|
+
if (includeNumbers) {
|
|
15419
|
+
pools.push(Math.floor(Math.random() * 99999).toString());
|
|
15420
|
+
}
|
|
15421
|
+
|
|
15422
|
+
if (includeSymbols) {
|
|
15423
|
+
pools.push(this._getRandomItem(this.symbols));
|
|
15424
|
+
}
|
|
15425
|
+
|
|
15426
|
+
if (emojiPlacement === 'inline' && useEmojis && emojiSet.length) {
|
|
15427
|
+
pools.push(this._getRandomItem(emojiSet));
|
|
15428
|
+
}
|
|
15429
|
+
|
|
15430
|
+
return this._getRandomItem(pools);
|
|
15431
|
+
}
|
|
15432
|
+
|
|
15433
|
+
/**
|
|
15434
|
+
* Generates a natural sentence by replacing placeholders in a template.
|
|
15435
|
+
* @private
|
|
15436
|
+
* @returns {string} - A generated sentence.
|
|
15437
|
+
*/
|
|
15438
|
+
_generateNaturalSentence() {
|
|
15439
|
+
const { templates, nouns, verbs, adjectives } = this.config.grammar;
|
|
15440
|
+
|
|
15441
|
+
let template = this._getRandomItem(templates);
|
|
15442
|
+
|
|
15443
|
+
return template
|
|
15444
|
+
.replace(/{noun}/g, () => this._getRandomItem(nouns))
|
|
15445
|
+
.replace(/{verb}/g, () => this._getRandomItem(verbs))
|
|
15446
|
+
.replace(/{adj}/g, () => this._getRandomItem(adjectives));
|
|
15447
|
+
}
|
|
15448
|
+
|
|
15449
|
+
/**
|
|
15450
|
+
* Generates a single line of text with target length and rules.
|
|
15451
|
+
* @private
|
|
15452
|
+
* @param {number} targetLength - Target character length for the line.
|
|
15453
|
+
* @param {Set<string>} [seenWords] - Set of already used words (for avoiding repeats).
|
|
15454
|
+
* @returns {string} - A generated line.
|
|
15455
|
+
*/
|
|
15456
|
+
_generateLine(targetLength, seenWords) {
|
|
15457
|
+
const { allowWeirdSpacing, repeatWords, readable, emojiSet, useEmojis, emojiPlacement, line } =
|
|
15458
|
+
this.config;
|
|
15459
|
+
|
|
15460
|
+
const parts = [];
|
|
15461
|
+
seenWords ??= new Set();
|
|
15462
|
+
|
|
15463
|
+
while (parts.join(' ').length < targetLength) {
|
|
15464
|
+
let chunk = this._generateChunk();
|
|
15465
|
+
|
|
15466
|
+
if (!repeatWords && seenWords.has(chunk)) continue;
|
|
15467
|
+
seenWords.add(chunk);
|
|
15468
|
+
|
|
15469
|
+
if (allowWeirdSpacing) {
|
|
15470
|
+
if (Math.random() < 0.1) chunk = '\n' + chunk;
|
|
15471
|
+
if (Math.random() < 0.1) chunk = ' ' + chunk;
|
|
15472
|
+
if (Math.random() < 0.05) chunk = chunk.toUpperCase();
|
|
15473
|
+
}
|
|
15474
|
+
|
|
15475
|
+
parts.push(chunk);
|
|
15476
|
+
}
|
|
15477
|
+
|
|
15478
|
+
let lineText = parts.join(readable ? ' ' : '');
|
|
15479
|
+
|
|
15480
|
+
if (
|
|
15481
|
+
emojiPlacement === 'end' &&
|
|
15482
|
+
useEmojis &&
|
|
15483
|
+
emojiSet.length &&
|
|
15484
|
+
Math.random() < (line?.emojiChance || 0)
|
|
15485
|
+
) {
|
|
15486
|
+
lineText += ' ' + this._getRandomItem(emojiSet);
|
|
15487
|
+
}
|
|
15488
|
+
|
|
15489
|
+
return lineText;
|
|
15490
|
+
}
|
|
15491
|
+
|
|
15492
|
+
/**
|
|
15493
|
+
* Generates lines to form a paragraph based on total length.
|
|
15494
|
+
* @private
|
|
15495
|
+
* @param {number} totalLength - Total target character count for the paragraph.
|
|
15496
|
+
* @returns {string[]} - Array of lines that form the paragraph.
|
|
15497
|
+
*/
|
|
15498
|
+
_generateParagraphLines(totalLength) {
|
|
15499
|
+
const { line } = this.config;
|
|
15500
|
+
const lines = [];
|
|
15501
|
+
const seenWords = new Set();
|
|
15502
|
+
let currentTotal = 0;
|
|
15503
|
+
|
|
15504
|
+
while (currentTotal < totalLength) {
|
|
15505
|
+
const lineLength = Math.floor(
|
|
15506
|
+
Math.random() * (line.maxLength - line.minLength + 1) + line.minLength,
|
|
15507
|
+
);
|
|
15508
|
+
|
|
15509
|
+
const adjustedLength = Math.min(lineLength, totalLength - currentTotal);
|
|
15510
|
+
|
|
15511
|
+
lines.push(this._generateLine(adjustedLength, seenWords));
|
|
15512
|
+
currentTotal += adjustedLength;
|
|
15513
|
+
}
|
|
15514
|
+
|
|
15515
|
+
return lines;
|
|
15516
|
+
}
|
|
15517
|
+
|
|
15518
|
+
/**
|
|
15519
|
+
* Generates the final random message, which can be a paragraph or block of lines.
|
|
15520
|
+
* Uses full configuration rules (grammar, symbols, emojis, etc).
|
|
15521
|
+
* @returns {string} - A full generated message.
|
|
15522
|
+
*/
|
|
15523
|
+
generate() {
|
|
15524
|
+
const { minLength, maxLength, paragraphs } = this.config;
|
|
15525
|
+
|
|
15526
|
+
const totalLength = Math.floor(Math.random() * (maxLength - minLength + 1)) + minLength;
|
|
15527
|
+
|
|
15528
|
+
if (paragraphs && typeof paragraphs === 'object') {
|
|
15529
|
+
const paraCount =
|
|
15530
|
+
Math.floor(Math.random() * (paragraphs.max - paragraphs.min + 1)) + paragraphs.min;
|
|
15531
|
+
const approxLength = Math.floor(totalLength / paraCount);
|
|
15532
|
+
const paragraphsArray = [];
|
|
15533
|
+
|
|
15534
|
+
for (let i = 0; i < paraCount; i++) {
|
|
15535
|
+
const lines = this._generateParagraphLines(approxLength);
|
|
15536
|
+
paragraphsArray.push(lines.join('\n'));
|
|
15537
|
+
}
|
|
15538
|
+
|
|
15539
|
+
return paragraphsArray.join('\n\n');
|
|
15540
|
+
}
|
|
15541
|
+
|
|
15542
|
+
return this._generateParagraphLines(totalLength).join('\n');
|
|
15543
|
+
}
|
|
15544
|
+
}
|
|
15545
|
+
|
|
15546
|
+
/* harmony default export */ const libs_UltraRandomMsgGen = (UltraRandomMsgGen);
|
|
15547
|
+
|
|
15548
|
+
;// ./src/v1/libs/TinySmartScroller.mjs
|
|
15549
|
+
|
|
15550
|
+
|
|
15551
|
+
|
|
15552
|
+
/**
|
|
15553
|
+
* Represents the dimensions of a DOM element.
|
|
15554
|
+
*
|
|
15555
|
+
* @typedef {Object} NodeSizes
|
|
15556
|
+
* @property {number} height - The height of the element in pixels.
|
|
15557
|
+
* @property {number} width - The width of the element in pixels.
|
|
15558
|
+
*/
|
|
15559
|
+
|
|
15560
|
+
/**
|
|
15561
|
+
* A callback function that receives node size change data and optionally returns a modified NodeSizes object.
|
|
15562
|
+
*
|
|
15563
|
+
* @callback NodeSizesEvent
|
|
15564
|
+
* @param {Element} elem - The DOM element whose size is being tracked.
|
|
15565
|
+
* @param {{ old: NodeSizes, now: NodeSizes }} sizes - The old and new size measurements of the element.
|
|
15566
|
+
* @param {{ old: number, now: number }} elemAmount - The number of matching elements before and after the update.
|
|
15567
|
+
* @returns {NodeSizes|undefined} A modified NodeSizes object to override the default measurement, or undefined to use the original.
|
|
15568
|
+
*/
|
|
15569
|
+
|
|
15570
|
+
/**
|
|
15571
|
+
* A generic scroll-related event listener callback function.
|
|
15572
|
+
*
|
|
15573
|
+
* @callback ScrollListenersFunc
|
|
15574
|
+
* @param {any} payload - The data payload passed when the scroll event is triggered. The type may vary depending on the event.
|
|
15575
|
+
* @returns {void}
|
|
15576
|
+
*/
|
|
15577
|
+
|
|
15578
|
+
/**
|
|
15579
|
+
* TinySmartScroller is a utility class designed to enhance and manage scroll behaviors within containers or the window.
|
|
15580
|
+
*
|
|
15581
|
+
* It enables advanced scroll monitoring, auto-scrolling to bottom, preserving scroll position during DOM changes,
|
|
15582
|
+
* and detecting visibility changes of elements. This is particularly useful for dynamic UIs like chat applications,
|
|
15583
|
+
* feed viewers, or live content containers.
|
|
15584
|
+
*
|
|
15585
|
+
* Features:
|
|
15586
|
+
* - Detects when the scroll reaches the top, bottom, or custom boundaries
|
|
15587
|
+
* - Supports automatic scrolling to the bottom unless the user scrolls away
|
|
15588
|
+
* - Observes DOM mutations and resizes, and adapts scroll position accordingly
|
|
15589
|
+
* - Emits scroll-related events such as 'onScrollBoundary', 'onAutoScroll', and 'onScrollPause'
|
|
15590
|
+
* - Includes customizable scroll correction filters for layout shift mitigation
|
|
15591
|
+
* - Handles media element load events (e.g. `<img>`, `<iframe>`, `<video>`) to prevent sudden scroll jumps
|
|
15592
|
+
*
|
|
15593
|
+
* This class is **not framework-dependent** and works with vanilla DOM elements and the window object.
|
|
15594
|
+
*/
|
|
15595
|
+
class TinySmartScroller {
|
|
15596
|
+
static Utils = { ...collision_namespaceObject, TinyHtml: libs_TinyHtml };
|
|
15597
|
+
|
|
15598
|
+
/** @type {WeakMap<Element, NodeSizes>} */
|
|
15599
|
+
#oldSizes = new WeakMap();
|
|
15600
|
+
/** @type {WeakMap<Element, NodeSizes>} */
|
|
15601
|
+
#newSizes = new WeakMap();
|
|
15602
|
+
|
|
15603
|
+
/** @type {WeakMap<Element, boolean>} */
|
|
15604
|
+
#newVisibles = new WeakMap();
|
|
15605
|
+
/** @type {WeakMap<Element, boolean>} */
|
|
15606
|
+
#oldVisibles = new WeakMap();
|
|
15607
|
+
|
|
15608
|
+
/** @type {WeakMap<Element, boolean>} */
|
|
15609
|
+
#newVisiblesByTime = new WeakMap();
|
|
15610
|
+
/** @type {WeakMap<Element, boolean>} */
|
|
15611
|
+
#oldVisiblesByTime = new WeakMap();
|
|
15612
|
+
|
|
15613
|
+
/** @type {Record<string, ScrollListenersFunc[]>} */
|
|
15614
|
+
#scrollListeners = {};
|
|
15615
|
+
|
|
15616
|
+
/** @type {ResizeObserver|null} */
|
|
15617
|
+
#resizeObserver = null;
|
|
15618
|
+
/** @type {MutationObserver|null} */
|
|
15619
|
+
#mutationObserver = null;
|
|
15620
|
+
|
|
15621
|
+
/** @type {Set<string>} */
|
|
15622
|
+
#loadTags = new Set(['IMG', 'IFRAME', 'VIDEO']);
|
|
15623
|
+
|
|
15624
|
+
/** @type {null|EventListenerOrEventListenerObject} */
|
|
15625
|
+
#handler = null;
|
|
15626
|
+
|
|
15627
|
+
#isAtBottom = false;
|
|
15628
|
+
#isAtTop = false;
|
|
15629
|
+
#isAtCustomTop = false;
|
|
15630
|
+
#isAtCustomBottom = false;
|
|
15631
|
+
|
|
15632
|
+
#querySelector = '';
|
|
15633
|
+
#useWindow = false;
|
|
15634
|
+
#destroyed = false;
|
|
15635
|
+
#scrollPaused = false;
|
|
15636
|
+
#autoScrollBottom = false;
|
|
15637
|
+
#observeMutations = false;
|
|
15638
|
+
#preserveScrollOnLayoutShift = false;
|
|
15639
|
+
#debounceTime = 0;
|
|
15640
|
+
#elemAmount = 0;
|
|
15641
|
+
#elemOldAmount = 0;
|
|
15642
|
+
#lastKnownScrollBottomOffset = 0;
|
|
15643
|
+
#extraScrollBoundary = 0;
|
|
15644
|
+
|
|
15645
|
+
/** @type {Set<string>} */
|
|
15646
|
+
#attributeFilter;
|
|
15647
|
+
|
|
15648
|
+
/** @type {Element} */
|
|
15649
|
+
#target;
|
|
15650
|
+
|
|
15651
|
+
/** @type {Set<NodeSizesEvent>} */
|
|
15652
|
+
#sizeFilter = new Set();
|
|
15653
|
+
|
|
15654
|
+
/**
|
|
15655
|
+
* Creates a new instance of TinySmartScroller, attaching scroll and resize observers to manage
|
|
15656
|
+
* automatic scroll behaviors, layout shift correction, and visibility tracking.
|
|
15657
|
+
*
|
|
15658
|
+
* @param {Element|Window} target - The scroll container to monitor. Can be an element or `window`.
|
|
15659
|
+
* @param {Object} [options={}] - Optional settings to configure scroll behavior.
|
|
15660
|
+
* @param {number} [options.extraScrollBoundary=0] - Extra margin in pixels to extend scroll boundary detection.
|
|
15661
|
+
* @param {boolean} [options.autoScrollBottom=true] - Whether to auto-scroll to bottom on layout updates.
|
|
15662
|
+
* @param {boolean} [options.observeMutations=true] - Enables MutationObserver to detect DOM changes.
|
|
15663
|
+
* @param {boolean} [options.preserveScrollOnLayoutShift=true] - Prevents scroll jumps when layout changes.
|
|
15664
|
+
* @param {number} [options.debounceTime=100] - Debounce time in milliseconds for scroll events.
|
|
15665
|
+
* @param {string|null} [options.querySelector=null] - Optional CSS selector to filter observed child nodes.
|
|
15666
|
+
* @param {string[]|Set<string>|null} [options.attributeFilter=['class', 'style', 'src', 'data-*', 'height', 'width']]
|
|
15667
|
+
* - Which attributes to observe for changes.
|
|
15668
|
+
*/
|
|
15669
|
+
constructor(
|
|
15670
|
+
target,
|
|
15671
|
+
{
|
|
15672
|
+
extraScrollBoundary = 0,
|
|
15673
|
+
autoScrollBottom = true,
|
|
15674
|
+
observeMutations = true,
|
|
15675
|
+
preserveScrollOnLayoutShift = true,
|
|
15676
|
+
debounceTime = 100,
|
|
15677
|
+
querySelector = null,
|
|
15678
|
+
attributeFilter = ['class', 'style', 'src', 'data-*', 'height', 'width'],
|
|
15679
|
+
} = {},
|
|
15680
|
+
) {
|
|
15681
|
+
// === target ===
|
|
15682
|
+
if (!(target instanceof Element || target === window))
|
|
15683
|
+
throw new TypeError(
|
|
15684
|
+
`TinySmartScroller: 'target' must be a DOM Element or 'window', but got ${typeof target}`,
|
|
15685
|
+
);
|
|
15686
|
+
// === extraScrollBoundary ===
|
|
15687
|
+
if (typeof extraScrollBoundary !== 'number' || Number.isNaN(extraScrollBoundary))
|
|
15688
|
+
throw new TypeError(
|
|
15689
|
+
`TinySmartScroller: 'extraScrollBoundary' must be a valid number, received ${extraScrollBoundary}`,
|
|
15690
|
+
);
|
|
15691
|
+
// === autoScrollBottom ===
|
|
15692
|
+
if (typeof autoScrollBottom !== 'boolean')
|
|
15693
|
+
throw new TypeError(
|
|
15694
|
+
`TinySmartScroller: 'autoScrollBottom' must be a boolean, received ${typeof autoScrollBottom}`,
|
|
15695
|
+
);
|
|
15696
|
+
// === observeMutations ===
|
|
15697
|
+
if (typeof observeMutations !== 'boolean')
|
|
15698
|
+
throw new TypeError(
|
|
15699
|
+
`TinySmartScroller: 'observeMutations' must be a boolean, received ${typeof observeMutations}`,
|
|
15700
|
+
);
|
|
15701
|
+
// === preserveScrollOnLayoutShift ===
|
|
15702
|
+
if (typeof preserveScrollOnLayoutShift !== 'boolean')
|
|
15703
|
+
throw new TypeError(
|
|
15704
|
+
`TinySmartScroller: 'preserveScrollOnLayoutShift' must be a boolean, received ${typeof preserveScrollOnLayoutShift}`,
|
|
15705
|
+
);
|
|
15706
|
+
// === debounceTime ===
|
|
15707
|
+
if (typeof debounceTime !== 'number' || debounceTime < 0 || Number.isNaN(debounceTime))
|
|
15708
|
+
throw new TypeError(
|
|
15709
|
+
`TinySmartScroller: 'debounceTime' must be a non-negative number, received ${debounceTime}`,
|
|
15710
|
+
);
|
|
15711
|
+
// === querySelector ===
|
|
15712
|
+
if (querySelector !== null && typeof querySelector !== 'string')
|
|
15713
|
+
throw new TypeError(
|
|
15714
|
+
`TinySmartScroller: 'querySelector' must be a string or null, received ${typeof querySelector}`,
|
|
15715
|
+
);
|
|
15716
|
+
// === attributeFilter ===
|
|
15717
|
+
const isValidAttrList =
|
|
15718
|
+
attributeFilter === null || Array.isArray(attributeFilter) || attributeFilter instanceof Set;
|
|
15719
|
+
if (!isValidAttrList)
|
|
15720
|
+
throw new TypeError(
|
|
15721
|
+
`TinySmartScroller: 'attributeFilter' must be an array, Set, or null. Got ${typeof attributeFilter}`,
|
|
15722
|
+
);
|
|
15723
|
+
|
|
15724
|
+
// Start values
|
|
15725
|
+
this.#target = target instanceof Window ? document.documentElement : target;
|
|
15726
|
+
this.#useWindow = target instanceof Window;
|
|
15727
|
+
this.#autoScrollBottom = autoScrollBottom;
|
|
15728
|
+
this.#observeMutations = observeMutations;
|
|
15729
|
+
this.#preserveScrollOnLayoutShift = preserveScrollOnLayoutShift;
|
|
15730
|
+
this.#debounceTime = debounceTime;
|
|
15731
|
+
this.#extraScrollBoundary = extraScrollBoundary;
|
|
15732
|
+
this.#querySelector = querySelector || '';
|
|
15733
|
+
this.#attributeFilter = new Set(attributeFilter || undefined);
|
|
15734
|
+
|
|
15735
|
+
// Bind scroll
|
|
15736
|
+
/** @type {NodeJS.Timeout} */
|
|
15737
|
+
let timeout;
|
|
15738
|
+
this.#handler = () => {
|
|
15739
|
+
this._scrollDataUpdater();
|
|
15740
|
+
clearTimeout(timeout);
|
|
15741
|
+
timeout = setTimeout(() => this._onScroll(), this.#debounceTime);
|
|
15742
|
+
};
|
|
15743
|
+
(this.#useWindow ? window : this.#target).addEventListener('scroll', this.#handler, {
|
|
15744
|
+
passive: true,
|
|
15745
|
+
});
|
|
15746
|
+
|
|
15747
|
+
// Mutations
|
|
15748
|
+
if (this.#observeMutations) {
|
|
15749
|
+
this._observeMutations();
|
|
15750
|
+
this._observeResizes(this.#target.children);
|
|
15751
|
+
}
|
|
15752
|
+
|
|
15753
|
+
this._scrollDataUpdater();
|
|
15754
|
+
}
|
|
15755
|
+
|
|
15756
|
+
/**
|
|
15757
|
+
* Returns a size difference callback that only reacts when height changes, filtered by tag name.
|
|
15758
|
+
*
|
|
15759
|
+
* @param {string[]} filter - List of tag names to allow. If empty, all tags are accepted.
|
|
15760
|
+
* @returns {NodeSizesEvent} A function that compares previous and current height, returning height delta.
|
|
15761
|
+
*/
|
|
15762
|
+
getSimpleOnHeight(filter = []) {
|
|
15763
|
+
if (!Array.isArray(filter))
|
|
15764
|
+
throw new TypeError('getSimpleOnHeight(filter): filter must be an array of tag names');
|
|
15765
|
+
return (elem, sizes, amounts) => {
|
|
15766
|
+
if ((filter.length > 0 && !filter.includes(elem.tagName)) || amounts.now !== amounts.old)
|
|
15767
|
+
return;
|
|
15768
|
+
const oldSize = sizes.old;
|
|
15769
|
+
const newSize = sizes.now;
|
|
15770
|
+
const height = newSize.height - oldSize.height;
|
|
15771
|
+
return { height, width: 0 };
|
|
15772
|
+
};
|
|
15773
|
+
}
|
|
15774
|
+
|
|
15775
|
+
/**
|
|
15776
|
+
* Adds a height difference callback to the size filter system.
|
|
15777
|
+
*
|
|
15778
|
+
* @param {string[]} filter - List of tag names to allow.
|
|
15779
|
+
* @returns {NodeSizesEvent} The added size difference callback.
|
|
15780
|
+
*/
|
|
15781
|
+
addSimpleOnHeight(filter) {
|
|
15782
|
+
if (!Array.isArray(filter))
|
|
15783
|
+
throw new TypeError('addSimpleOnHeight(filter): filter must be an array of tag names');
|
|
15784
|
+
const result = this.getSimpleOnHeight(filter);
|
|
15785
|
+
this.onSize(result);
|
|
15786
|
+
return result;
|
|
15787
|
+
}
|
|
15788
|
+
|
|
15789
|
+
/**
|
|
15790
|
+
* Returns a list of all currently tracked load tags.
|
|
15791
|
+
*
|
|
15792
|
+
* @returns {string[]} Array of tag names.
|
|
15793
|
+
*/
|
|
15794
|
+
getLoadTags() {
|
|
15795
|
+
return Array.from(this.#loadTags);
|
|
15796
|
+
}
|
|
15797
|
+
|
|
15798
|
+
/**
|
|
15799
|
+
* Adds a new tag to the set of load tags.
|
|
15800
|
+
*
|
|
15801
|
+
* @param {string} tag - The tag name to add (e.g., 'IMG').
|
|
15802
|
+
*/
|
|
15803
|
+
addLoadTag(tag) {
|
|
15804
|
+
if (typeof tag !== 'string') throw new TypeError('addLoadTag(tag): tag must be a string');
|
|
15805
|
+
this.#loadTags.add(tag.toUpperCase());
|
|
15806
|
+
}
|
|
15807
|
+
|
|
15808
|
+
/**
|
|
15809
|
+
* Removes a tag from the set of load tags.
|
|
15810
|
+
*
|
|
15811
|
+
* @param {string} tag - The tag name to remove.
|
|
15812
|
+
*/
|
|
15813
|
+
removeLoadTag(tag) {
|
|
15814
|
+
if (typeof tag !== 'string') throw new TypeError('removeLoadTag(tag): tag must be a string');
|
|
15815
|
+
this.#loadTags.delete(tag.toUpperCase());
|
|
15816
|
+
}
|
|
15817
|
+
|
|
15818
|
+
/**
|
|
15819
|
+
* Checks whether a tag is tracked as a load tag.
|
|
15820
|
+
*
|
|
15821
|
+
* @param {string} tag - The tag name to check.
|
|
15822
|
+
* @returns {boolean} True if the tag is being tracked.
|
|
15823
|
+
*/
|
|
15824
|
+
hasLoadTag(tag) {
|
|
15825
|
+
if (typeof tag !== 'string') throw new TypeError('hasLoadTag(tag): tag must be a string');
|
|
15826
|
+
return this.#loadTags.has(tag.toUpperCase());
|
|
15827
|
+
}
|
|
15828
|
+
|
|
15829
|
+
/**
|
|
15830
|
+
* Clears the set of load tags. If `addDefault` is true, it will reset to the default tags: 'IMG', 'IFRAME', and 'VIDEO'.
|
|
15831
|
+
*
|
|
15832
|
+
* @param {boolean} [addDefault=false] - Whether to restore the default tags after clearing.
|
|
15833
|
+
* @throws {TypeError} If `addDefault` is not a boolean.
|
|
15834
|
+
*/
|
|
15835
|
+
resetLoadTags(addDefault = false) {
|
|
15836
|
+
if (typeof addDefault !== 'boolean')
|
|
15837
|
+
throw new TypeError('resetLoadTags(addDefault): addDefault must be a boolean');
|
|
15838
|
+
this.#loadTags.clear();
|
|
15839
|
+
if (!addDefault) return;
|
|
15840
|
+
this.#loadTags.add('IMG');
|
|
15841
|
+
this.#loadTags.add('IFRAME');
|
|
15842
|
+
this.#loadTags.add('VIDEO');
|
|
15843
|
+
}
|
|
15844
|
+
|
|
15845
|
+
/**
|
|
15846
|
+
* Returns a list of all currently tracked attribute filters.
|
|
15847
|
+
*
|
|
15848
|
+
* @returns {string[]} Array of attribute names.
|
|
15849
|
+
*/
|
|
15850
|
+
getAttributeFilters() {
|
|
15851
|
+
return Array.from(this.#attributeFilter);
|
|
15852
|
+
}
|
|
15853
|
+
|
|
15854
|
+
/**
|
|
15855
|
+
* Adds an attribute to the filter list.
|
|
15856
|
+
*
|
|
15857
|
+
* @param {string} attr - The attribute name to add.
|
|
15858
|
+
*/
|
|
15859
|
+
addAttributeFilter(attr) {
|
|
15860
|
+
if (typeof attr !== 'string')
|
|
15861
|
+
throw new TypeError('addAttributeFilter(attr): attr must be a string');
|
|
15862
|
+
this.#attributeFilter.add(attr);
|
|
15863
|
+
}
|
|
15864
|
+
|
|
15865
|
+
/**
|
|
15866
|
+
* Removes an attribute from the filter list.
|
|
15867
|
+
*
|
|
15868
|
+
* @param {string} attr - The attribute name to remove.
|
|
15869
|
+
*/
|
|
15870
|
+
removeAttributeFilter(attr) {
|
|
15871
|
+
if (typeof attr !== 'string')
|
|
15872
|
+
throw new TypeError('removeAttributeFilter(attr): attr must be a string');
|
|
15873
|
+
this.#attributeFilter.delete(attr);
|
|
15874
|
+
}
|
|
15875
|
+
|
|
15876
|
+
/**
|
|
15877
|
+
* Checks whether a specific attribute is being filtered.
|
|
15878
|
+
*
|
|
15879
|
+
* @param {string} attr - The attribute name to check.
|
|
15880
|
+
* @returns {boolean} True if the attribute is being filtered.
|
|
15881
|
+
*/
|
|
15882
|
+
hasAttributeFilter(attr) {
|
|
15883
|
+
if (typeof attr !== 'string')
|
|
15884
|
+
throw new TypeError('hasAttributeFilter(attr): attr must be a string');
|
|
15885
|
+
return this.#attributeFilter.has(attr);
|
|
15886
|
+
}
|
|
15887
|
+
|
|
15888
|
+
/**
|
|
15889
|
+
* Clears the set of observed attribute filters. If `addDefault` is true, it will reset to the default attributes:
|
|
15890
|
+
* 'class', 'style', 'src', 'data-*', 'height', and 'width'.
|
|
15891
|
+
*
|
|
15892
|
+
* @param {boolean} [addDefault=false] - Whether to restore the default attribute filters after clearing.
|
|
15893
|
+
* @throws {TypeError} If `addDefault` is not a boolean.
|
|
15894
|
+
*/
|
|
15895
|
+
resetAttributeFilters(addDefault = false) {
|
|
15896
|
+
if (typeof addDefault !== 'boolean')
|
|
15897
|
+
throw new TypeError('resetAttributeFilters(addDefault): addDefault must be a boolean');
|
|
15898
|
+
this.#attributeFilter.clear();
|
|
15899
|
+
if (!addDefault) return;
|
|
15900
|
+
['class', 'style', 'src', 'data-*', 'height', 'width'].forEach((attr) =>
|
|
15901
|
+
this.#attributeFilter.add(attr),
|
|
15902
|
+
);
|
|
15903
|
+
}
|
|
15904
|
+
|
|
15905
|
+
/**
|
|
15906
|
+
* Registers a custom node size change handler to the internal size filter set.
|
|
15907
|
+
*
|
|
15908
|
+
* @param {NodeSizesEvent} handler - Function that compares old and new sizes.
|
|
15909
|
+
*/
|
|
15910
|
+
onSize(handler) {
|
|
15911
|
+
if (this.#destroyed) return;
|
|
15912
|
+
if (typeof handler !== 'function')
|
|
15913
|
+
throw new TypeError('onSize(handler): handler must be a function');
|
|
15914
|
+
this.#sizeFilter.add(handler);
|
|
15915
|
+
}
|
|
15916
|
+
|
|
15917
|
+
/**
|
|
15918
|
+
* Unregisters a previously registered size handler from the internal filter set.
|
|
15919
|
+
*
|
|
15920
|
+
* @param {NodeSizesEvent} handler - The handler function to remove.
|
|
15921
|
+
*/
|
|
15922
|
+
offSize(handler) {
|
|
15923
|
+
if (this.#destroyed) return;
|
|
15924
|
+
if (typeof handler !== 'function')
|
|
15925
|
+
throw new TypeError('offSize(handler): handler must be a function');
|
|
15926
|
+
this.#sizeFilter.delete(handler);
|
|
15927
|
+
}
|
|
15928
|
+
|
|
15929
|
+
/**
|
|
15930
|
+
* Adds a scroll-related event listener.
|
|
15931
|
+
*
|
|
15932
|
+
* @param {string} event - Event name, such as 'onScrollBoundary' or 'onAutoScroll'.
|
|
15933
|
+
* @param {ScrollListenersFunc} handler - Callback function to be called when event fires.
|
|
15934
|
+
*/
|
|
15935
|
+
on(event, handler) {
|
|
15936
|
+
if (this.#destroyed) return;
|
|
15937
|
+
if (typeof event !== 'string')
|
|
15938
|
+
throw new TypeError('on(event, handler): event name must be a string');
|
|
15939
|
+
if (typeof handler !== 'function')
|
|
15940
|
+
throw new TypeError('on(event, handler): handler must be a function');
|
|
15941
|
+
|
|
15942
|
+
if (!this.#scrollListeners[event]) this.#scrollListeners[event] = [];
|
|
15943
|
+
this.#scrollListeners[event].push(handler);
|
|
15944
|
+
}
|
|
15945
|
+
|
|
15946
|
+
/**
|
|
15947
|
+
* Removes a previously registered scroll-related event listener.
|
|
15948
|
+
*
|
|
15949
|
+
* @param {string} event - The name of the event to remove the handler from.
|
|
15950
|
+
* @param {ScrollListenersFunc} handler - The specific callback function to remove.
|
|
15951
|
+
*/
|
|
15952
|
+
off(event, handler) {
|
|
15953
|
+
if (this.#destroyed) return;
|
|
15954
|
+
if (typeof event !== 'string')
|
|
15955
|
+
throw new TypeError('off(event, handler): event name must be a string');
|
|
15956
|
+
if (typeof handler !== 'function')
|
|
15957
|
+
throw new TypeError('off(event, handler): handler must be a function');
|
|
15958
|
+
|
|
15959
|
+
const listeners = this.#scrollListeners[event];
|
|
15960
|
+
if (!Array.isArray(listeners)) return;
|
|
15961
|
+
|
|
15962
|
+
const index = listeners.indexOf(handler);
|
|
15963
|
+
if (index !== -1) listeners.splice(index, 1);
|
|
15964
|
+
|
|
15965
|
+
// Optionally clean up empty arrays (optional)
|
|
15966
|
+
if (listeners.length === 0) delete this.#scrollListeners[event];
|
|
15967
|
+
}
|
|
15968
|
+
|
|
15969
|
+
/**
|
|
15970
|
+
* Checks which elements inside the target are currently visible and updates internal maps.
|
|
15971
|
+
*
|
|
15972
|
+
* @returns {Map<Element, { oldIsVisible: boolean; isVisible: boolean }>} Visibility comparison results.
|
|
15973
|
+
*/
|
|
15974
|
+
_scrollDataUpdater() {
|
|
15975
|
+
const results = new Map();
|
|
15976
|
+
this.#target.querySelectorAll(this.#querySelector || '*').forEach((target) => {
|
|
15977
|
+
const oldIsVisible = this.#newVisibles.get(target) ?? false;
|
|
15978
|
+
this.#oldVisibles.set(target, oldIsVisible);
|
|
15979
|
+
|
|
15980
|
+
const isVisible = libs_TinyHtml.isInContainer(this.#target, target);
|
|
15981
|
+
this.#newVisibles.set(target, isVisible);
|
|
15982
|
+
|
|
15983
|
+
results.set(target, { oldIsVisible, isVisible });
|
|
15984
|
+
});
|
|
15985
|
+
return results;
|
|
15986
|
+
}
|
|
15987
|
+
|
|
15988
|
+
/**
|
|
15989
|
+
* Emits a scroll-related event to all registered listeners.
|
|
15990
|
+
*
|
|
15991
|
+
* @param {string} event - Event name.
|
|
15992
|
+
* @param {*} [payload] - Optional event data payload.
|
|
15993
|
+
*/
|
|
15994
|
+
_emit(event, payload) {
|
|
15995
|
+
if (this.#destroyed) return;
|
|
15996
|
+
if (typeof event !== 'string')
|
|
15997
|
+
throw new TypeError('_emit(event, payload): event name must be a string');
|
|
15998
|
+
(this.#scrollListeners[event] || []).forEach((fn) => fn(payload));
|
|
15999
|
+
}
|
|
16000
|
+
|
|
16001
|
+
/**
|
|
16002
|
+
* Handles scroll events, calculates position-related statuses, and emits appropriate events.
|
|
16003
|
+
*/
|
|
16004
|
+
_onScroll() {
|
|
16005
|
+
if (this.#destroyed) return;
|
|
16006
|
+
// Get values
|
|
16007
|
+
const scrollCache = this._scrollDataUpdater();
|
|
16008
|
+
const el = this.#target;
|
|
16009
|
+
const scrollTop = el.scrollTop;
|
|
16010
|
+
const scrollHeight = el.scrollHeight;
|
|
16011
|
+
const clientHeight = el.clientHeight;
|
|
16012
|
+
|
|
16013
|
+
// Prepare sroll values
|
|
16014
|
+
const scrollResult = { scrollTop, scrollHeight, clientHeight };
|
|
16015
|
+
let atResult = null;
|
|
16016
|
+
let atCustomResult = null;
|
|
16017
|
+
|
|
16018
|
+
const atTop = scrollTop === 0;
|
|
16019
|
+
const atBottom = scrollTop + clientHeight >= scrollHeight - 1;
|
|
16020
|
+
|
|
16021
|
+
const atCustomTop = scrollTop <= 0 + this.#extraScrollBoundary;
|
|
16022
|
+
const atCustomBottom = scrollTop + clientHeight >= scrollHeight - 1 - this.#extraScrollBoundary;
|
|
16023
|
+
|
|
16024
|
+
// Scroll results
|
|
16025
|
+
if (atTop && atBottom) atResult = 'all';
|
|
16026
|
+
else if (atTop) atResult = 'top';
|
|
16027
|
+
else if (atBottom) atResult = 'bottom';
|
|
16028
|
+
|
|
16029
|
+
if (atCustomTop && atCustomBottom) atCustomResult = 'all';
|
|
16030
|
+
else if (atCustomTop) atCustomResult = 'top';
|
|
16031
|
+
else if (atCustomBottom) atCustomResult = 'bottom';
|
|
16032
|
+
|
|
16033
|
+
this.#isAtTop = atTop;
|
|
16034
|
+
this.#isAtBottom = atBottom;
|
|
16035
|
+
|
|
16036
|
+
this.#isAtCustomTop = atCustomTop;
|
|
16037
|
+
this.#isAtCustomBottom = atCustomBottom;
|
|
16038
|
+
|
|
16039
|
+
this.#scrollPaused = !(this.#autoScrollBottom && this.#isAtBottom);
|
|
16040
|
+
|
|
16041
|
+
this.#lastKnownScrollBottomOffset = scrollHeight - scrollTop - clientHeight;
|
|
16042
|
+
|
|
16043
|
+
// Send results
|
|
16044
|
+
this._emit('onScrollBoundary', { status: atResult, ...scrollResult, scrollCache });
|
|
16045
|
+
this._emit('onExtraScrollBoundary', { status: atCustomResult, ...scrollResult, scrollCache });
|
|
16046
|
+
|
|
16047
|
+
if (!this.#scrollPaused) {
|
|
16048
|
+
this._emit('onAutoScroll', { ...scrollResult, scrollCache });
|
|
16049
|
+
} else {
|
|
16050
|
+
this._emit('onScrollPause', { ...scrollResult, scrollCache });
|
|
16051
|
+
}
|
|
16052
|
+
}
|
|
16053
|
+
|
|
16054
|
+
/**
|
|
16055
|
+
* Attempts to correct the scroll position when layout shifts happen, preserving the user position if needed.
|
|
16056
|
+
*
|
|
16057
|
+
* @param {Element[]} [targets=[]] - List of elements involved in the size change.
|
|
16058
|
+
*/
|
|
16059
|
+
_fixScroll(targets = []) {
|
|
16060
|
+
if (this.#destroyed) return;
|
|
16061
|
+
// === Validation ===
|
|
16062
|
+
if (!Array.isArray(targets))
|
|
16063
|
+
throw new TypeError('_fixScroll: targets must be an array of Elements');
|
|
16064
|
+
|
|
16065
|
+
// Get Scroll data
|
|
16066
|
+
const prevScrollHeight = this.#target.scrollHeight;
|
|
16067
|
+
const prevScrollTop = this.#target.scrollTop;
|
|
16068
|
+
const prevBottomOffset =
|
|
16069
|
+
this.#target.scrollHeight - this.#target.scrollTop - this.#target.clientHeight;
|
|
16070
|
+
|
|
16071
|
+
// Get new size
|
|
16072
|
+
const newScrollHeight = this.#target.scrollHeight;
|
|
16073
|
+
const heightDelta = newScrollHeight - prevScrollHeight;
|
|
16074
|
+
|
|
16075
|
+
/** @type {() => NodeSizes} */
|
|
16076
|
+
const calculateScrollSize = () => {
|
|
16077
|
+
// Run size getter
|
|
16078
|
+
const scrollSize = { height: 0, width: 0 };
|
|
16079
|
+
for (const target of targets) {
|
|
16080
|
+
const tgOs = this.#oldSizes.get(target) || { height: 0, width: 0 };
|
|
16081
|
+
const tgNs = this.#newSizes.get(target) || { height: 0, width: 0 };
|
|
16082
|
+
this.#sizeFilter.forEach((fn) => {
|
|
16083
|
+
/** @type {NodeSizes| undefined} */
|
|
16084
|
+
const sizes = fn(
|
|
16085
|
+
target,
|
|
16086
|
+
{ old: tgOs, now: tgNs },
|
|
16087
|
+
{ old: this.#elemOldAmount, now: this.#elemAmount },
|
|
16088
|
+
);
|
|
16089
|
+
|
|
16090
|
+
// Fix size
|
|
16091
|
+
if (this.#newVisibles.get(target) || this.#newVisiblesByTime.get(target)) {
|
|
16092
|
+
if (typeof sizes !== 'undefined' && typeof sizes !== 'object')
|
|
16093
|
+
throw new Error('_fixScroll: size filter must return an object or undefined');
|
|
16094
|
+
if (typeof sizes === 'undefined') return;
|
|
16095
|
+
scrollSize.height = sizes.height;
|
|
16096
|
+
scrollSize.width = sizes.width;
|
|
16097
|
+
}
|
|
16098
|
+
});
|
|
16099
|
+
}
|
|
16100
|
+
|
|
16101
|
+
// Checker
|
|
16102
|
+
if (typeof scrollSize.height !== 'number' && scrollSize.height < 0)
|
|
16103
|
+
throw new Error('_fixScroll: invalid scrollSize.height value');
|
|
16104
|
+
if (typeof scrollSize.width !== 'number' && scrollSize.width < 0)
|
|
16105
|
+
throw new Error('_fixScroll: invalid scrollSize.width value');
|
|
16106
|
+
|
|
16107
|
+
if (scrollSize.height !== 0 || scrollSize.width !== 0) {
|
|
16108
|
+
for (const target of targets) {
|
|
16109
|
+
this.#newVisiblesByTime.set(target, this.#newVisibles.get(target) ?? false);
|
|
16110
|
+
this.#oldVisiblesByTime.set(target, this.#oldVisibles.get(target) ?? false);
|
|
16111
|
+
}
|
|
16112
|
+
}
|
|
16113
|
+
|
|
16114
|
+
return scrollSize;
|
|
16115
|
+
};
|
|
16116
|
+
|
|
16117
|
+
// Fix scroll size
|
|
16118
|
+
if (
|
|
16119
|
+
this.#elemOldAmount > 0 &&
|
|
16120
|
+
libs_TinyHtml.hasScroll(this.#target).v &&
|
|
16121
|
+
this.#autoScrollBottom &&
|
|
16122
|
+
this.#preserveScrollOnLayoutShift &&
|
|
16123
|
+
!this.#isAtBottom &&
|
|
16124
|
+
!this.#isAtTop
|
|
16125
|
+
) {
|
|
16126
|
+
const scrollSize = calculateScrollSize();
|
|
16127
|
+
// Complete
|
|
16128
|
+
this.#target.scrollTop = prevScrollTop + heightDelta + scrollSize.height;
|
|
16129
|
+
if (scrollSize.width > 0)
|
|
16130
|
+
this.#target.scrollLeft = this.#target.scrollLeft + scrollSize.width;
|
|
16131
|
+
}
|
|
16132
|
+
|
|
16133
|
+
// Normal stuff
|
|
16134
|
+
else if (!this.#scrollPaused && this.#autoScrollBottom) {
|
|
16135
|
+
calculateScrollSize();
|
|
16136
|
+
this.scrollToBottom();
|
|
16137
|
+
} else if (!this.#autoScrollBottom && !this.#isAtBottom) {
|
|
16138
|
+
calculateScrollSize();
|
|
16139
|
+
this.#target.scrollTop =
|
|
16140
|
+
this.#target.scrollHeight - this.#target.clientHeight - prevBottomOffset;
|
|
16141
|
+
}
|
|
16142
|
+
}
|
|
16143
|
+
/**
|
|
16144
|
+
* Sets up a MutationObserver to watch for DOM changes and react accordingly to maintain scroll consistency.
|
|
16145
|
+
*/
|
|
16146
|
+
_observeMutations() {
|
|
16147
|
+
this.#mutationObserver = new MutationObserver((mutations) => {
|
|
16148
|
+
if (this.#destroyed) return;
|
|
16149
|
+
this._scrollDataUpdater();
|
|
16150
|
+
this.#elemOldAmount = this.#elemAmount;
|
|
16151
|
+
this.#elemAmount = this.#target.childElementCount;
|
|
16152
|
+
|
|
16153
|
+
mutations.forEach((mutation) => {
|
|
16154
|
+
mutation.addedNodes.forEach((node) => {
|
|
16155
|
+
if (!(node instanceof Element) || node.nodeType !== 1) return;
|
|
16156
|
+
|
|
16157
|
+
this._observeResizes([node]);
|
|
16158
|
+
this._listenLoadEvents(node);
|
|
16159
|
+
|
|
16160
|
+
if (this.#querySelector) {
|
|
16161
|
+
const children = node.querySelectorAll(this.#querySelector);
|
|
16162
|
+
this._observeResizes(children);
|
|
16163
|
+
this._listenLoadEvents(children);
|
|
16164
|
+
}
|
|
16165
|
+
});
|
|
16166
|
+
});
|
|
16167
|
+
|
|
16168
|
+
this._fixScroll();
|
|
16169
|
+
});
|
|
16170
|
+
|
|
16171
|
+
// Install observer
|
|
16172
|
+
this.#mutationObserver.observe(this.#target, {
|
|
16173
|
+
childList: true,
|
|
16174
|
+
subtree: true,
|
|
16175
|
+
attributes: true,
|
|
16176
|
+
attributeFilter:
|
|
16177
|
+
this.#attributeFilter.size > 0 ? Array.from(this.#attributeFilter) : undefined,
|
|
16178
|
+
});
|
|
16179
|
+
}
|
|
16180
|
+
|
|
16181
|
+
/**
|
|
16182
|
+
* Adds a ResizeObserver to monitor elements' size changes and trigger layout adjustments.
|
|
16183
|
+
*
|
|
16184
|
+
* @param {NodeListOf<Element>|Element[]|HTMLCollection} elements - Elements to observe.
|
|
16185
|
+
*/
|
|
16186
|
+
_observeResizes(elements) {
|
|
16187
|
+
// Add resize observer
|
|
16188
|
+
if (!this.#resizeObserver) {
|
|
16189
|
+
this.#resizeObserver = new ResizeObserver((entries) => {
|
|
16190
|
+
if (this.#destroyed) return;
|
|
16191
|
+
this._scrollDataUpdater();
|
|
16192
|
+
/** @type {Element[]} */
|
|
16193
|
+
const targets = [];
|
|
16194
|
+
for (const entry of entries) {
|
|
16195
|
+
// Target
|
|
16196
|
+
const target = entry.target;
|
|
16197
|
+
|
|
16198
|
+
// Update old size
|
|
16199
|
+
const oldSize = this.#newSizes.get(target);
|
|
16200
|
+
if (oldSize) this.#oldSizes.set(target, oldSize);
|
|
16201
|
+
|
|
16202
|
+
// Set new size
|
|
16203
|
+
const { width, height } = entry.contentRect;
|
|
16204
|
+
this.#newSizes.set(target, { width, height });
|
|
16205
|
+
targets.push(target);
|
|
16206
|
+
}
|
|
16207
|
+
|
|
16208
|
+
// Animation frame
|
|
16209
|
+
this._fixScroll(targets);
|
|
16210
|
+
});
|
|
16211
|
+
}
|
|
16212
|
+
|
|
16213
|
+
// Execute observer
|
|
16214
|
+
Array.from(elements).forEach((el) => {
|
|
16215
|
+
if (!this.#resizeObserver)
|
|
16216
|
+
throw new Error('_observeResizes: ResizeObserver instance is not initialized');
|
|
16217
|
+
this.#resizeObserver.observe(el);
|
|
16218
|
+
});
|
|
16219
|
+
}
|
|
16220
|
+
|
|
16221
|
+
/**
|
|
16222
|
+
* Listens for media/content load events (e.g., images, iframes, videos) to trigger scroll updates.
|
|
16223
|
+
*
|
|
16224
|
+
* @param {NodeListOf<Element>|Element} elements - Target element(s) to listen on.
|
|
16225
|
+
*/
|
|
16226
|
+
_listenLoadEvents(elements) {
|
|
16227
|
+
if (this.#destroyed) return;
|
|
16228
|
+
const list = elements instanceof NodeList ? Array.from(elements) : [elements];
|
|
16229
|
+
|
|
16230
|
+
list.forEach((el) => {
|
|
16231
|
+
if (this.#loadTags.has(el.tagName)) {
|
|
16232
|
+
// @ts-ignore
|
|
16233
|
+
if (!el.complete) {
|
|
16234
|
+
el.addEventListener('load', () => {
|
|
16235
|
+
this._scrollDataUpdater();
|
|
16236
|
+
if (!this.#scrollPaused && this.#autoScrollBottom) {
|
|
16237
|
+
this.scrollToBottom();
|
|
16238
|
+
}
|
|
16239
|
+
});
|
|
16240
|
+
}
|
|
16241
|
+
}
|
|
16242
|
+
});
|
|
16243
|
+
}
|
|
16244
|
+
|
|
16245
|
+
/**
|
|
16246
|
+
* Returns the internal scroll container element being monitored.
|
|
16247
|
+
*
|
|
16248
|
+
* @returns {Element} The DOM element used as the scroll container target.
|
|
16249
|
+
*/
|
|
16250
|
+
get target() {
|
|
16251
|
+
return this.#target;
|
|
16252
|
+
}
|
|
16253
|
+
|
|
16254
|
+
/**
|
|
16255
|
+
* Returns the previous size of a given element, or undefined if not tracked.
|
|
16256
|
+
*
|
|
16257
|
+
* @param {Element} el - The DOM element to query.
|
|
16258
|
+
* @returns {NodeSizes|null} The old size, or undefined.
|
|
16259
|
+
*/
|
|
16260
|
+
getOldSize(el) {
|
|
16261
|
+
return this.#oldSizes.get(el) ?? null;
|
|
16262
|
+
}
|
|
16263
|
+
|
|
16264
|
+
/**
|
|
16265
|
+
* Returns the current size of a given element, or undefined if not tracked.
|
|
16266
|
+
*
|
|
16267
|
+
* @param {Element} el - The DOM element to query.
|
|
16268
|
+
* @returns {NodeSizes|null} The new size, or undefined.
|
|
16269
|
+
*/
|
|
16270
|
+
getNewSize(el) {
|
|
16271
|
+
return this.#newSizes.get(el) ?? null;
|
|
16272
|
+
}
|
|
16273
|
+
|
|
16274
|
+
/**
|
|
16275
|
+
* Returns whether the given element was visible in the last scroll update.
|
|
16276
|
+
*
|
|
16277
|
+
* @param {Element} el - The DOM element to check.
|
|
16278
|
+
* @returns {boolean} True if visible, false if not, or undefined if not tracked.
|
|
16279
|
+
*/
|
|
16280
|
+
wasVisible(el) {
|
|
16281
|
+
return this.#oldVisibles.get(el) ?? false;
|
|
16282
|
+
}
|
|
16283
|
+
|
|
16284
|
+
/**
|
|
16285
|
+
* Returns whether the given element is currently visible.
|
|
16286
|
+
*
|
|
16287
|
+
* @param {Element} el - The DOM element to check.
|
|
16288
|
+
* @returns {boolean} True if visible, false if not, or undefined if not tracked.
|
|
16289
|
+
*/
|
|
16290
|
+
isVisible(el) {
|
|
16291
|
+
return this.#newVisibles.get(el) ?? false;
|
|
16292
|
+
}
|
|
16293
|
+
|
|
16294
|
+
/**
|
|
16295
|
+
* Returns whether the element was visible in the last time-based visibility check.
|
|
16296
|
+
*
|
|
16297
|
+
* @param {Element} el - The DOM element to check.
|
|
16298
|
+
* @returns {boolean} Visibility state from the previous timed check.
|
|
16299
|
+
*/
|
|
16300
|
+
wasTimedVisible(el) {
|
|
16301
|
+
return this.#oldVisiblesByTime.get(el) ?? false;
|
|
16302
|
+
}
|
|
16303
|
+
|
|
16304
|
+
/**
|
|
16305
|
+
* Returns whether the element is currently visible in the time-based check.
|
|
16306
|
+
*
|
|
16307
|
+
* @param {Element} el - The DOM element to check.
|
|
16308
|
+
* @returns {boolean} Visibility state from the current timed check.
|
|
16309
|
+
*/
|
|
16310
|
+
isTimedVisible(el) {
|
|
16311
|
+
return this.#newVisiblesByTime.get(el) ?? false;
|
|
16312
|
+
}
|
|
16313
|
+
|
|
16314
|
+
/**
|
|
16315
|
+
* Sets the extra scroll boundary margin used when determining if the user is at a "custom" bottom or top.
|
|
16316
|
+
*
|
|
16317
|
+
* @param {number} value - Pixels of additional margin to use.
|
|
16318
|
+
*/
|
|
16319
|
+
setExtraScrollBoundary(value) {
|
|
16320
|
+
if (typeof value !== 'number' || Number.isNaN(value))
|
|
16321
|
+
throw new TypeError('setExtraScrollBoundary(value): value must be a valid number');
|
|
16322
|
+
this.#extraScrollBoundary = value;
|
|
16323
|
+
}
|
|
16324
|
+
|
|
16325
|
+
/**
|
|
16326
|
+
* Returns the current extra scroll boundary setting.
|
|
16327
|
+
*
|
|
16328
|
+
* @returns {number}
|
|
16329
|
+
*/
|
|
16330
|
+
getExtraScrollBoundary() {
|
|
16331
|
+
return this.#extraScrollBoundary;
|
|
16332
|
+
}
|
|
16333
|
+
|
|
16334
|
+
/**
|
|
16335
|
+
* Returns the last known distance (in pixels) from the bottom of the scroll container.
|
|
16336
|
+
*
|
|
16337
|
+
* @returns {number}
|
|
16338
|
+
*/
|
|
16339
|
+
getLastKnownScrollBottomOffset() {
|
|
16340
|
+
return this.#lastKnownScrollBottomOffset;
|
|
16341
|
+
}
|
|
16342
|
+
|
|
16343
|
+
/**
|
|
16344
|
+
* Forces the scroll position to move to the very bottom of the target.
|
|
16345
|
+
*/
|
|
16346
|
+
scrollToBottom() {
|
|
16347
|
+
this.#target.scrollTop = this.#target.scrollHeight;
|
|
16348
|
+
}
|
|
16349
|
+
|
|
16350
|
+
/**
|
|
16351
|
+
* Forces the scroll position to move to the very top of the target.
|
|
16352
|
+
*/
|
|
16353
|
+
scrollToTop() {
|
|
16354
|
+
this.#target.scrollTop = 0;
|
|
16355
|
+
}
|
|
16356
|
+
|
|
16357
|
+
/**
|
|
16358
|
+
* Checks if the user is within the defined extra scroll boundary from the bottom.
|
|
16359
|
+
*
|
|
16360
|
+
* @returns {boolean}
|
|
16361
|
+
*/
|
|
16362
|
+
isUserAtCustomBottom() {
|
|
16363
|
+
return this.#isAtCustomBottom;
|
|
16364
|
+
}
|
|
16365
|
+
|
|
16366
|
+
/**
|
|
16367
|
+
* Checks if the user is within the defined extra scroll boundary from the top.
|
|
16368
|
+
*
|
|
16369
|
+
* @returns {boolean}
|
|
16370
|
+
*/
|
|
16371
|
+
isUserAtCustomTop() {
|
|
16372
|
+
return this.#isAtCustomTop;
|
|
16373
|
+
}
|
|
16374
|
+
|
|
16375
|
+
/**
|
|
16376
|
+
* Returns true if the user is currently scrolled to the bottom of the element.
|
|
16377
|
+
*
|
|
16378
|
+
* @returns {boolean}
|
|
16379
|
+
*/
|
|
16380
|
+
isUserAtBottom() {
|
|
16381
|
+
return this.#isAtBottom;
|
|
16382
|
+
}
|
|
16383
|
+
|
|
16384
|
+
/**
|
|
16385
|
+
* Returns true if the user is currently scrolled to the top of the element.
|
|
16386
|
+
*
|
|
16387
|
+
* @returns {boolean}
|
|
16388
|
+
*/
|
|
16389
|
+
isUserAtTop() {
|
|
16390
|
+
return this.#isAtTop;
|
|
16391
|
+
}
|
|
16392
|
+
|
|
16393
|
+
/**
|
|
16394
|
+
* Returns true if automatic scrolling is currently paused.
|
|
16395
|
+
*
|
|
16396
|
+
* @returns {boolean}
|
|
16397
|
+
*/
|
|
16398
|
+
isScrollPaused() {
|
|
16399
|
+
return this.#scrollPaused;
|
|
16400
|
+
}
|
|
16401
|
+
|
|
16402
|
+
/**
|
|
16403
|
+
* Returns whether the target is the window object.
|
|
16404
|
+
*
|
|
16405
|
+
* @returns {boolean} True if the scroll target is window, false otherwise.
|
|
16406
|
+
*/
|
|
16407
|
+
isWindow() {
|
|
16408
|
+
return this.#useWindow;
|
|
16409
|
+
}
|
|
16410
|
+
|
|
16411
|
+
/**
|
|
16412
|
+
* Returns whether the instance has been destroyed.
|
|
16413
|
+
*
|
|
16414
|
+
* @returns {boolean} True if the instance is destroyed, false otherwise.
|
|
16415
|
+
*/
|
|
16416
|
+
isDestroyed() {
|
|
16417
|
+
return this.#destroyed;
|
|
16418
|
+
}
|
|
16419
|
+
|
|
16420
|
+
/**
|
|
16421
|
+
* Returns whether auto-scroll-to-bottom is enabled.
|
|
16422
|
+
*
|
|
16423
|
+
* @returns {boolean} True if auto-scroll is active, false otherwise.
|
|
16424
|
+
*/
|
|
16425
|
+
getAutoScrollBottom() {
|
|
16426
|
+
return this.#autoScrollBottom;
|
|
16427
|
+
}
|
|
16428
|
+
|
|
16429
|
+
/**
|
|
16430
|
+
* Returns whether MutationObserver is enabled.
|
|
16431
|
+
*
|
|
16432
|
+
* @returns {boolean} True if mutation observation is active, false otherwise.
|
|
16433
|
+
*/
|
|
16434
|
+
getObserveMutations() {
|
|
16435
|
+
return this.#observeMutations;
|
|
16436
|
+
}
|
|
16437
|
+
|
|
16438
|
+
/**
|
|
16439
|
+
* Returns whether layout shift protection is enabled.
|
|
16440
|
+
*
|
|
16441
|
+
* @returns {boolean} True if scroll preservation is active, false otherwise.
|
|
16442
|
+
*/
|
|
16443
|
+
getPreserveScrollOnLayoutShift() {
|
|
16444
|
+
return this.#preserveScrollOnLayoutShift;
|
|
16445
|
+
}
|
|
16446
|
+
|
|
16447
|
+
/**
|
|
16448
|
+
* Returns the debounce delay in milliseconds used for scroll events.
|
|
16449
|
+
*
|
|
16450
|
+
* @returns {number} Debounce delay time.
|
|
16451
|
+
*/
|
|
16452
|
+
getDebounceTime() {
|
|
16453
|
+
return this.#debounceTime;
|
|
16454
|
+
}
|
|
16455
|
+
|
|
16456
|
+
/**
|
|
16457
|
+
* Returns the current number of matching elements observed inside the scroll target.
|
|
16458
|
+
*
|
|
16459
|
+
* @returns {number} Current count of matching elements.
|
|
16460
|
+
*/
|
|
16461
|
+
getElemAmount() {
|
|
16462
|
+
return this.#elemAmount;
|
|
16463
|
+
}
|
|
16464
|
+
|
|
16465
|
+
/**
|
|
16466
|
+
* Returns the previous known count of matching elements from the last update.
|
|
16467
|
+
*
|
|
16468
|
+
* @returns {number} Previous count of matching elements.
|
|
16469
|
+
*/
|
|
16470
|
+
getPrevElemAmount() {
|
|
16471
|
+
return this.#elemOldAmount;
|
|
16472
|
+
}
|
|
16473
|
+
|
|
16474
|
+
/**
|
|
16475
|
+
* Returns the query selector string used to filter observed elements.
|
|
16476
|
+
*
|
|
16477
|
+
* @returns {string} The CSS selector string, or an empty string if none was provided.
|
|
16478
|
+
*/
|
|
16479
|
+
getQuerySelector() {
|
|
16480
|
+
return this.#querySelector;
|
|
16481
|
+
}
|
|
16482
|
+
|
|
16483
|
+
/**
|
|
16484
|
+
* Disconnects all listeners, observers, and clears memory structures.
|
|
16485
|
+
* Once destroyed, this instance should no longer be used.
|
|
16486
|
+
*/
|
|
16487
|
+
destroy() {
|
|
16488
|
+
if (this.#destroyed) return;
|
|
16489
|
+
this.#destroyed = true;
|
|
16490
|
+
|
|
16491
|
+
// Disconnects MutationObserver
|
|
16492
|
+
if (this.#mutationObserver) {
|
|
16493
|
+
this.#mutationObserver.disconnect();
|
|
16494
|
+
this.#mutationObserver = null;
|
|
16495
|
+
}
|
|
16496
|
+
|
|
16497
|
+
// Disconnect ResizeObserver
|
|
16498
|
+
if (this.#resizeObserver) {
|
|
16499
|
+
this.#resizeObserver.disconnect();
|
|
16500
|
+
this.#resizeObserver = null;
|
|
16501
|
+
}
|
|
16502
|
+
|
|
16503
|
+
// Removes scroll listener
|
|
16504
|
+
const target = this.#useWindow ? window : this.#target;
|
|
16505
|
+
if (this.#handler) target.removeEventListener('scroll', this.#handler);
|
|
16506
|
+
|
|
16507
|
+
// Clean the WeakMaps
|
|
16508
|
+
this.#oldSizes = new WeakMap();
|
|
16509
|
+
this.#newSizes = new WeakMap();
|
|
16510
|
+
this.#newVisibles = new WeakMap();
|
|
16511
|
+
this.#oldVisibles = new WeakMap();
|
|
16512
|
+
this.#newVisiblesByTime = new WeakMap();
|
|
16513
|
+
this.#oldVisiblesByTime = new WeakMap();
|
|
16514
|
+
|
|
16515
|
+
// Cleans listeners and filters
|
|
16516
|
+
this.#scrollListeners = {};
|
|
16517
|
+
this.#sizeFilter.clear();
|
|
16518
|
+
this.#loadTags.clear();
|
|
16519
|
+
}
|
|
16520
|
+
}
|
|
16521
|
+
|
|
16522
|
+
/* harmony default export */ const libs_TinySmartScroller = (TinySmartScroller);
|
|
16523
|
+
|
|
16524
|
+
;// ./src/v1/index.mjs
|
|
16525
|
+
|
|
16526
|
+
|
|
13955
16527
|
|
|
13956
16528
|
|
|
13957
16529
|
|