estreui 1.2.3 → 1.2.4
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/index.html +8 -1
- package/package.json +4 -4
- package/scripts/alienese.js +282 -275
- package/scripts/boot.js +107 -67
- package/scripts/doctre.js +330 -6
- package/scripts/estreU0EEOZ.js +25 -4
- package/scripts/estreUi-core.js +555 -0
- package/scripts/estreUi-dialog.js +511 -0
- package/scripts/estreUi-handles.js +7243 -0
- package/scripts/estreUi-interaction.js +1374 -0
- package/scripts/estreUi-main.js +1667 -0
- package/scripts/estreUi-notation.js +596 -0
- package/scripts/estreUi-pageManager.js +625 -0
- package/scripts/estreUi-pageModel.js +4317 -0
- package/scripts/modernism.js +44 -3
- package/serviceWorker.js +10 -3
- package/scripts/estreUi.js +0 -16337
package/scripts/doctre.js
CHANGED
|
@@ -30,7 +30,7 @@ SOFTWARE.
|
|
|
30
30
|
//
|
|
31
31
|
// Cold(array object) assigning of HTML Tree for make to JSON string.
|
|
32
32
|
//
|
|
33
|
-
// v1.1.
|
|
33
|
+
// v1.1.2 / release 2026.04.18
|
|
34
34
|
//
|
|
35
35
|
// cold = [] - Cold HTML child node list
|
|
36
36
|
// cold[0] - Tag name, classes, id, name, type = "tag.class1.class2#id@name$type" : string
|
|
@@ -45,8 +45,63 @@ SOFTWARE.
|
|
|
45
45
|
// Match replace
|
|
46
46
|
// ex) Doctre.parse([["|tag|.|classes|#|id|", "empty content"], "|divider|"], { tag: () => isInline ? "span" | "div", classes: "test fixed", id: getId(), divider: it => '<hr class="' + it + '" />' })
|
|
47
47
|
|
|
48
|
+
// ──────────────────────────────────────────────
|
|
49
|
+
// @typedef — reusable type shapes
|
|
50
|
+
// ──────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Extracted solidId components.
|
|
54
|
+
* @typedef {Object} DoctreSolidId
|
|
55
|
+
* @property {string} tagName - HTML tag name.
|
|
56
|
+
* @property {string} [class] - Space-separated CSS class names.
|
|
57
|
+
* @property {string} [id] - Element id.
|
|
58
|
+
* @property {string} [name] - Element name attribute.
|
|
59
|
+
* @property {string} [type] - Element type attribute.
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* A single cold element entry — serialized DOM node in array form.
|
|
64
|
+
*
|
|
65
|
+
* `[solidId, contentData, style, attrs, datas]`
|
|
66
|
+
* @typedef {Array} DoctreColdElement
|
|
67
|
+
* @property {string|DoctreSolidId} 0 - solidId string or extracted object.
|
|
68
|
+
* @property {DoctreColdElement[]|string|null} [1] - Child content (cold array, text, or null).
|
|
69
|
+
* @property {string|Object} [2] - Inline style string or style object.
|
|
70
|
+
* @property {Object<string, string>} [3] - Regular HTML attributes (excluding id/name/type/class/style/data-*).
|
|
71
|
+
* @property {Object<string, string>} [4] - data-* attributes.
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Token replacement map used by Doctre.matchReplace.
|
|
76
|
+
* Keys are token names (matched as `|key|`); values are replacement strings, functions, or objects.
|
|
77
|
+
* @typedef {Object<string, string|Function|Object>} DoctreMatchReplacer
|
|
78
|
+
* @property {string} [dataPlaceholder] - Default replacement for unmatched tokens.
|
|
79
|
+
* @property {boolean} [coverReplaceable] - If true, replaces all unmatched tokens with dataPlaceholder.
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Document Object Cold Taste Refrigeration Effortlessness — DOM serialization/deserialization engine.
|
|
84
|
+
* Preserves and restores HTML trees using cold (array object) and frost (JSON string) formats.
|
|
85
|
+
*
|
|
86
|
+
* **cold format**: `[solidId, contentData, style, attrs, datas]`
|
|
87
|
+
* - `solidId`: `"tag.class1.class2#id@name$type"` string or extracted object
|
|
88
|
+
* - `contentData`: cold array / text string / NodeList / Element / Node
|
|
89
|
+
* - `style`: style string or object
|
|
90
|
+
* - `attrs`: regular attribute object
|
|
91
|
+
* - `datas`: data-* attribute object
|
|
92
|
+
*
|
|
93
|
+
* **frost format**: JSON.stringify'd cold string
|
|
94
|
+
*
|
|
95
|
+
* **matchReplace**: replaces `|key|` tokens with values from the matchReplacer object
|
|
96
|
+
* @class
|
|
97
|
+
*/
|
|
48
98
|
class Doctre {
|
|
49
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Splits a solidId string into the tag name and remaining major attribute parts.
|
|
102
|
+
* @param {string|Object} solidId - solidId string or `{ tagName, ... }` object.
|
|
103
|
+
* @returns {[string, string|Object]} `[tagName, majorAttrs]` tuple.
|
|
104
|
+
*/
|
|
50
105
|
static extractTagName(solidId) {
|
|
51
106
|
let tagName, majorAttrs;
|
|
52
107
|
if (typeof solidId == "string") {
|
|
@@ -61,6 +116,12 @@ class Doctre {
|
|
|
61
116
|
return [tagName, majorAttrs];
|
|
62
117
|
}
|
|
63
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Parses the major attribute part (`.class#id@name$type`) of a solidId into an object.
|
|
121
|
+
* @param {string} majorAttrs - Major attribute string.
|
|
122
|
+
* @param {Object} [to={}] - Object to store results into.
|
|
123
|
+
* @returns {Object} `{ class?, id?, name?, type? }` attribute object.
|
|
124
|
+
*/
|
|
64
125
|
static extractMajorAttrs(majorAttrs, to = {}) {
|
|
65
126
|
const process = (string, divider, attrName) => {
|
|
66
127
|
const filter = new RegExp(divider + "[\\w.-]*");
|
|
@@ -77,12 +138,28 @@ class Doctre {
|
|
|
77
138
|
return to;
|
|
78
139
|
}
|
|
79
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Extracts both the tag name and major attributes from a solidId.
|
|
143
|
+
* @param {string} solidId - solidId string.
|
|
144
|
+
* @returns {Object} `{ tagName, class?, id?, name?, type? }`.
|
|
145
|
+
*/
|
|
80
146
|
static extractTagAndMajorAttrs(solidId) {
|
|
81
147
|
const [tagName, majorAttrs] = this.extractTagName(solidId);
|
|
82
148
|
return this.extractMajorAttrs(majorAttrs, { tagName });
|
|
83
149
|
}
|
|
84
150
|
|
|
85
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Creates a DOM element from cold parameters.
|
|
154
|
+
* @param {string|Array} [tagName="template"] - Tag name or cold array.
|
|
155
|
+
* @param {string|Object} [majorAttrs] - Major attributes string/object.
|
|
156
|
+
* @param {string|Array|NodeList|Node|Doctre|null} [contentData] - Child content.
|
|
157
|
+
* @param {string|Object} [style={}] - Style.
|
|
158
|
+
* @param {Object} [attrs={}] - Regular attributes.
|
|
159
|
+
* @param {Object} [datas={}] - data-* attributes.
|
|
160
|
+
* @param {DoctreMatchReplacer} [matchReplacer={}] - `|key|` token replacement map.
|
|
161
|
+
* @returns {Element} The created DOM element.
|
|
162
|
+
*/
|
|
86
163
|
static createElement(tagName = "template", majorAttrs, contentData, style = {}, attrs = {}, datas = {}, matchReplacer = {}) {
|
|
87
164
|
if (tagName instanceof Array) return this.createElement(...tagName);
|
|
88
165
|
|
|
@@ -132,10 +209,32 @@ class Doctre {
|
|
|
132
209
|
return element;
|
|
133
210
|
}
|
|
134
211
|
|
|
212
|
+
/**
|
|
213
|
+
* createElement variant that takes matchReplacer as the first argument.
|
|
214
|
+
* @param {DoctreMatchReplacer} matchReplacer - Token replacement map.
|
|
215
|
+
* @param {string} tagName - Tag name.
|
|
216
|
+
* @param {string|Object} [majorAttrs] - Major attributes.
|
|
217
|
+
* @param {*} [contentData] - Child content.
|
|
218
|
+
* @param {string|Object} [style={}] - Style.
|
|
219
|
+
* @param {Object} [attrs={}] - Regular attributes.
|
|
220
|
+
* @param {Object} [datas={}] - data-* attributes.
|
|
221
|
+
* @param {DoctreMatchReplacer} [matchReplacerOrigin={}] - Fallback when matchReplacer is null.
|
|
222
|
+
* @returns {Element}
|
|
223
|
+
*/
|
|
135
224
|
static createElementReplaced(matchReplacer, tagName, majorAttrs, contentData, style = {}, attrs = {}, datas = {}, matchReplacerOrigin = {}) {
|
|
136
225
|
return this.createElement(tagName, majorAttrs, contentData, style, attrs, datas, matchReplacer ?? matchReplacerOrigin);
|
|
137
226
|
}
|
|
138
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Creates an element from a solidId string. Automatically extracts tagName and majorAttrs from solidId.
|
|
230
|
+
* @param {string|Array} solidId - solidId string or array.
|
|
231
|
+
* @param {*} [contentData] - Child content.
|
|
232
|
+
* @param {string|Object} [style={}] - Style.
|
|
233
|
+
* @param {Object} [attrs={}] - Regular attributes.
|
|
234
|
+
* @param {Object} [datas={}] - data-* attributes.
|
|
235
|
+
* @param {DoctreMatchReplacer} [matchReplacer={}] - Token replacement map.
|
|
236
|
+
* @returns {Element}
|
|
237
|
+
*/
|
|
139
238
|
static createElementBy(solidId, contentData, style = {}, attrs = {}, datas = {}, matchReplacer = {}) {
|
|
140
239
|
if (solidId instanceof Array) return this.createElementBy(...solidId);
|
|
141
240
|
|
|
@@ -143,10 +242,27 @@ class Doctre {
|
|
|
143
242
|
return this.createElement(tagName, majorAttrs, contentData, style, attrs, datas, matchReplacer);
|
|
144
243
|
}
|
|
145
244
|
|
|
245
|
+
/**
|
|
246
|
+
* createElementBy variant that takes matchReplacer as the first argument.
|
|
247
|
+
* @param {DoctreMatchReplacer} matchReplacer - Token replacement map.
|
|
248
|
+
* @param {string} solidId - solidId string.
|
|
249
|
+
* @param {*} [contentData] - Child content.
|
|
250
|
+
* @param {string|Object} [style={}] - Style.
|
|
251
|
+
* @param {Object} [attrs={}] - Regular attributes.
|
|
252
|
+
* @param {Object} [datas={}] - data-* attributes.
|
|
253
|
+
* @param {DoctreMatchReplacer} [matchReplacerOrigin={}] - Fallback replacement map.
|
|
254
|
+
* @returns {Element}
|
|
255
|
+
*/
|
|
146
256
|
static createElementReplacedBy(matchReplacer, solidId, contentData, style = {}, attrs = {}, datas = {}, matchReplacerOrigin = {}) {
|
|
147
257
|
return this.createElementBy(solidId, contentData, style, attrs, datas, matchReplacer ?? matchReplacerOrigin);
|
|
148
258
|
}
|
|
149
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Creates a DocumentFragment from a cold (HCNL) array.
|
|
262
|
+
* @param {Array} hcnlArray - HTML Cold Node List array.
|
|
263
|
+
* @param {DoctreMatchReplacer} [matchReplacer={}] - Token replacement map.
|
|
264
|
+
* @returns {DocumentFragment}
|
|
265
|
+
*/
|
|
150
266
|
static createFragment(hcnlArray, matchReplacer = {}) {
|
|
151
267
|
const df = document.createDocumentFragment();
|
|
152
268
|
for (const val of hcnlArray) switch (typeof val) {
|
|
@@ -168,22 +284,42 @@ class Doctre {
|
|
|
168
284
|
return df;
|
|
169
285
|
}
|
|
170
286
|
|
|
287
|
+
/** @type {string} Current User-Agent string. */
|
|
171
288
|
static get userAgent() { return navigator?.userAgent ?? ""; }
|
|
289
|
+
/** @type {boolean} Whether newline/tab escaping is needed for Safari/iOS. */
|
|
172
290
|
static get isRequiredEscape() {
|
|
173
291
|
const userAgent = this.userAgent;
|
|
174
292
|
return userAgent != "" && (userAgent.includes("iPad") || userAgent.includes("iPhone") || userAgent.includes("iPod") || (userAgent.includes("Macintosh") && !userAgent.includes("Chrome") && !userAgent.includes("Firefox") && !userAgent.includes("Edge") && !userAgent.includes("Opera")));
|
|
175
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Escapes newlines and tabs in JSON strings for Safari compatibility.
|
|
296
|
+
* @param {string} jsonContent - JSON string.
|
|
297
|
+
* @returns {string} Escaped string (returned as-is on non-Safari).
|
|
298
|
+
*/
|
|
176
299
|
static crashBroker(jsonContent) {
|
|
177
300
|
if (this.isRequiredEscape) jsonContent = jsonContent.replace(/\r\n/gm, "\\r\\n").replace(/\n\r/gm, "\\n\\r").replace(/\r/gm, "\\r").replace(/\n/gm, "\\n").replace(/\t/g, "\\t");
|
|
178
301
|
return jsonContent;
|
|
179
302
|
}
|
|
180
303
|
|
|
304
|
+
/**
|
|
305
|
+
* Copies only primitive-type values from an object. Used to avoid circular references.
|
|
306
|
+
* @param {Object} obj - Source object.
|
|
307
|
+
* @returns {Object} A new object containing only primitive values.
|
|
308
|
+
*/
|
|
181
309
|
static copyPrimitives(obj) {
|
|
182
310
|
return Object.fromEntries(
|
|
183
311
|
Object.entries(obj).filter(([, v]) => v !== Object(v))
|
|
184
312
|
);
|
|
185
313
|
}
|
|
186
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Replaces `|key|` tokens in a string with values from the matchReplacer. Delegates to matchReplaceObject for objects.
|
|
317
|
+
* @param {string|Object} frostOrString - String or object to apply replacements to.
|
|
318
|
+
* @param {DoctreMatchReplacer} [matchReplacer={}] - `{ key: value }` replacement map. Values can be string/function/object.
|
|
319
|
+
* - `dataPlaceholder`: default replacement for unmatched tokens.
|
|
320
|
+
* - `coverReplaceable`: if true, replaces all unmatched tokens with dataPlaceholder.
|
|
321
|
+
* @returns {string|Object} The replaced result.
|
|
322
|
+
*/
|
|
187
323
|
static matchReplace(frostOrString, matchReplacer = {}) {
|
|
188
324
|
if (typeof frostOrString != "string") return this.matchReplaceObject(frostOrString, matchReplacer);
|
|
189
325
|
|
|
@@ -249,12 +385,24 @@ class Doctre {
|
|
|
249
385
|
return frostOrString;
|
|
250
386
|
}
|
|
251
387
|
|
|
388
|
+
/**
|
|
389
|
+
* Recursively applies matchReplace to both keys and values of an object.
|
|
390
|
+
* @param {Object} object - Object to apply replacements to.
|
|
391
|
+
* @param {DoctreMatchReplacer} [matchReplacer={}] - Replacement map.
|
|
392
|
+
* @returns {Object} A new object with replacements applied.
|
|
393
|
+
*/
|
|
252
394
|
static matchReplaceObject(object, matchReplacer = {}) {
|
|
253
395
|
const replaced = object.constructor();
|
|
254
396
|
for (const key in object) replaced[this.matchReplace(key, matchReplacer)] = this.matchReplace(object[key], matchReplacer);
|
|
255
397
|
return replaced;
|
|
256
398
|
}
|
|
257
399
|
|
|
400
|
+
/**
|
|
401
|
+
* Parses a frost (JSON string) and restores it as a DocumentFragment.
|
|
402
|
+
* @param {string} frost - Frost format JSON string.
|
|
403
|
+
* @param {DoctreMatchReplacer} [matchReplacer={}] - Token replacement map.
|
|
404
|
+
* @returns {DocumentFragment}
|
|
405
|
+
*/
|
|
258
406
|
static parse(frost, matchReplacer = {}) {
|
|
259
407
|
frost = this.crashBroker(frost);
|
|
260
408
|
const trimmedFrost = frost.trim();
|
|
@@ -273,11 +421,23 @@ class Doctre {
|
|
|
273
421
|
return this.createFragment(parsed);
|
|
274
422
|
}
|
|
275
423
|
|
|
424
|
+
/**
|
|
425
|
+
* Restores frost (string) or cold (array) to a live DOM (DocumentFragment).
|
|
426
|
+
* @param {string|Array} frostOrCold - Frost string or cold array.
|
|
427
|
+
* @param {DoctreMatchReplacer} [matchReplacer={}] - Token replacement map.
|
|
428
|
+
* @returns {DocumentFragment}
|
|
429
|
+
*/
|
|
276
430
|
static live(frostOrCold, matchReplacer = {}) {
|
|
277
431
|
if (typeof frostOrCold == "string") return this.parse(frostOrCold, matchReplacer);
|
|
278
432
|
else return this.createFragment(frostOrCold);
|
|
279
433
|
}
|
|
280
434
|
|
|
435
|
+
/**
|
|
436
|
+
* Wraps frost/cold in a template element and returns it.
|
|
437
|
+
* @param {string|Array} frostOrCold - Frost or cold data.
|
|
438
|
+
* @param {DoctreMatchReplacer} [matchReplacer={}] - Token replacement map.
|
|
439
|
+
* @returns {Element} Template element containing the content.
|
|
440
|
+
*/
|
|
281
441
|
static takeOut(frostOrCold, matchReplacer = {}) {
|
|
282
442
|
const element = this.createElement();
|
|
283
443
|
element.append(this.live(frostOrCold, matchReplacer));
|
|
@@ -285,6 +445,15 @@ class Doctre {
|
|
|
285
445
|
}
|
|
286
446
|
|
|
287
447
|
|
|
448
|
+
/**
|
|
449
|
+
* Assembles a solidId string from tag name and major attributes.
|
|
450
|
+
* @param {string} tagName - Tag name.
|
|
451
|
+
* @param {string} [className] - CSS classes (space-separated).
|
|
452
|
+
* @param {string} [id] - ID.
|
|
453
|
+
* @param {string} [name] - name attribute.
|
|
454
|
+
* @param {string} [type] - type attribute.
|
|
455
|
+
* @returns {string} solidId string (e.g. `"div.box.float#app@root$text"`).
|
|
456
|
+
*/
|
|
288
457
|
static getSolidId(tagName, className, id, name, type) {
|
|
289
458
|
let solidId = tagName;
|
|
290
459
|
if (className != null) solidId += "." + className.replace(/ /g, ".");
|
|
@@ -294,6 +463,12 @@ class Doctre {
|
|
|
294
463
|
return solidId;
|
|
295
464
|
}
|
|
296
465
|
|
|
466
|
+
/**
|
|
467
|
+
* Extracts the tag name and major attributes (class, id, name, type) from a DOM element.
|
|
468
|
+
* @param {Element} element - Target element.
|
|
469
|
+
* @param {boolean} [asSolidId=false] - If true returns solidId string, if false returns object.
|
|
470
|
+
* @returns {string|Object} solidId string or `{ tagName, class?, id?, name?, type? }`.
|
|
471
|
+
*/
|
|
297
472
|
static packTagAndMajorAttrs(element, asSolidId = false) {
|
|
298
473
|
const tagName = element.tagName.toLowerCase();
|
|
299
474
|
const className = element.getAttribute("class");
|
|
@@ -312,6 +487,11 @@ class Doctre {
|
|
|
312
487
|
}
|
|
313
488
|
}
|
|
314
489
|
|
|
490
|
+
/**
|
|
491
|
+
* Parses a CSS style string into a `{ property: value }` object.
|
|
492
|
+
* @param {string} style - Inline style string.
|
|
493
|
+
* @returns {Object<string, string>}
|
|
494
|
+
*/
|
|
315
495
|
static getStyleObject(style) {
|
|
316
496
|
const styles = {};
|
|
317
497
|
const divided = style.split(";");
|
|
@@ -325,6 +505,11 @@ class Doctre {
|
|
|
325
505
|
return styles;
|
|
326
506
|
}
|
|
327
507
|
|
|
508
|
+
/**
|
|
509
|
+
* Extracts attributes from a NamedNodeMap, excluding id/name/type/class/style/data-*.
|
|
510
|
+
* @param {NamedNodeMap} attrs - Element's attributes.
|
|
511
|
+
* @returns {Object<string, string>}
|
|
512
|
+
*/
|
|
328
513
|
static packAttributes(attrs) {
|
|
329
514
|
const pack = {};
|
|
330
515
|
for (const attr of attrs) {
|
|
@@ -345,6 +530,11 @@ class Doctre {
|
|
|
345
530
|
return pack;
|
|
346
531
|
}
|
|
347
532
|
|
|
533
|
+
/**
|
|
534
|
+
* Copies a DOMStringMap (dataset) to a plain object.
|
|
535
|
+
* @param {DOMStringMap} dataset - Element's dataset.
|
|
536
|
+
* @returns {Object<string, string>}
|
|
537
|
+
*/
|
|
348
538
|
static getDataObject(dataset) {
|
|
349
539
|
const datas = {};
|
|
350
540
|
for (const key in dataset) datas[key] = dataset[key];
|
|
@@ -352,6 +542,11 @@ class Doctre {
|
|
|
352
542
|
}
|
|
353
543
|
|
|
354
544
|
|
|
545
|
+
/**
|
|
546
|
+
* Removes trailing empty entries (null, empty string, empty array, empty object) from an HECP (cold element array).
|
|
547
|
+
* @param {Array} hecp - Cold element array `[solidId, content, style, attrs, datas]`.
|
|
548
|
+
* @returns {Array} The trimmed array (mutates the original).
|
|
549
|
+
*/
|
|
355
550
|
static trimHecp(hecp) {
|
|
356
551
|
for (var i = hecp.length - 1; i > 0; i--) {
|
|
357
552
|
if (hecp[i] == null) delete hecp[i];
|
|
@@ -367,6 +562,16 @@ class Doctre {
|
|
|
367
562
|
return hecp;
|
|
368
563
|
}
|
|
369
564
|
|
|
565
|
+
/**
|
|
566
|
+
* Serializes a DOM element into a cold array.
|
|
567
|
+
* @param {Element} element - Target element.
|
|
568
|
+
* @param {boolean} [trimBobbleNode=false] - Remove whitespace-only text nodes.
|
|
569
|
+
* @param {boolean} [trimHecp=false] - Trim trailing empty entries.
|
|
570
|
+
* @param {boolean} [styleToObject=!trimHecp] - Convert style to object.
|
|
571
|
+
* @param {boolean} [trimIndent=trimHecp] - Trim text indentation.
|
|
572
|
+
* @param {boolean} [elementAsDoctre=!trimHecp] - Preserve child elements as Doctre instances.
|
|
573
|
+
* @returns {Array} Cold array.
|
|
574
|
+
*/
|
|
370
575
|
static frostElement(element, trimBobbleNode = false, trimHecp = false, styleToObject = !trimHecp, trimIndent = trimHecp, elementAsDoctre = !trimHecp) {
|
|
371
576
|
const frozen = [];
|
|
372
577
|
frozen.push(this.packTagAndMajorAttrs(element, !elementAsDoctre));
|
|
@@ -379,6 +584,12 @@ class Doctre {
|
|
|
379
584
|
return trimHecp ? this.trimHecp(frozen) : frozen;
|
|
380
585
|
}
|
|
381
586
|
|
|
587
|
+
/**
|
|
588
|
+
* Trims leading/trailing whitespace from each line of text.
|
|
589
|
+
* @param {string} text - Source text.
|
|
590
|
+
* @param {boolean} [trimIndent=false] - If true, fully removes indentation; if false, collapses to single space.
|
|
591
|
+
* @returns {string}
|
|
592
|
+
*/
|
|
382
593
|
static trimTextIndent(text, trimIndent = false) {
|
|
383
594
|
return text.split("\n").map(line => {
|
|
384
595
|
let std = line.trimStart();
|
|
@@ -389,6 +600,16 @@ class Doctre {
|
|
|
389
600
|
}).join("\n");
|
|
390
601
|
}
|
|
391
602
|
|
|
603
|
+
/**
|
|
604
|
+
* Serializes a single node to cold format. Branches by node type.
|
|
605
|
+
* @param {Node|Doctre|Array} node - Target node.
|
|
606
|
+
* @param {boolean} [trimBobbleNode=false] - Remove whitespace text nodes.
|
|
607
|
+
* @param {boolean} [trimHecp=false] - Trim trailing empty entries.
|
|
608
|
+
* @param {boolean} [styleToObject=!trimHecp] - Convert style to object.
|
|
609
|
+
* @param {boolean} [trimIndent=trimHecp] - Trim text indentation.
|
|
610
|
+
* @param {boolean} [elementAsDoctre=!trimHecp] - Preserve child elements as Doctre.
|
|
611
|
+
* @returns {Array|Doctre|string} Cold array, Doctre instance, or text string.
|
|
612
|
+
*/
|
|
392
613
|
static frostNode(node, trimBobbleNode = false, trimHecp = false, styleToObject = !trimHecp, trimIndent = trimHecp, elementAsDoctre = !trimHecp) {
|
|
393
614
|
if (node instanceof Doctre) return elementAsDoctre ? node : node.frost(trimBobbleNode, trimHecp, styleToObject, trimIndent, elementAsDoctre);
|
|
394
615
|
else if (node instanceof DocumentFragment) return this.coldify(node.childNodes, trimBobbleNode, trimHecp, styleToObject, trimIndent, elementAsDoctre);
|
|
@@ -400,6 +621,16 @@ class Doctre {
|
|
|
400
621
|
}
|
|
401
622
|
}
|
|
402
623
|
|
|
624
|
+
/**
|
|
625
|
+
* Serializes a node or node list into a cold array.
|
|
626
|
+
* @param {Node|NodeList|Doctre|string} nodeOrList - Target node/list.
|
|
627
|
+
* @param {boolean} [trimBobbleNode=false] - Remove whitespace text nodes.
|
|
628
|
+
* @param {boolean} [trimHecp=false] - Trim trailing empty entries.
|
|
629
|
+
* @param {boolean} [styleToObject=!trimHecp] - Convert style to object.
|
|
630
|
+
* @param {boolean} [trimIndent=trimHecp] - Trim text indentation.
|
|
631
|
+
* @param {boolean} [elementAsDoctre=!trimHecp] - Preserve child elements as Doctre.
|
|
632
|
+
* @returns {Array} Cold array.
|
|
633
|
+
*/
|
|
403
634
|
static coldify(nodeOrList, trimBobbleNode = false, trimHecp = false, styleToObject = !trimHecp, trimIndent = trimHecp, elementAsDoctre = !trimHecp) {
|
|
404
635
|
if (typeof nodeOrList == "string") return this.coldify([nodeOrList], trimBobbleNode, trimHecp, styleToObject, trimIndent, elementAsDoctre);
|
|
405
636
|
|
|
@@ -413,6 +644,16 @@ class Doctre {
|
|
|
413
644
|
return cold;
|
|
414
645
|
}
|
|
415
646
|
|
|
647
|
+
/**
|
|
648
|
+
* Serializes node/list/cold to frost (JSON string).
|
|
649
|
+
* @param {Node|NodeList|Array} nodeOrListOrCold - Target.
|
|
650
|
+
* @param {boolean|number} [prettyJson=false] - If true or a number (indent), produces pretty-printed JSON.
|
|
651
|
+
* @param {boolean} [trimBobbleNode=false] - Remove whitespace text nodes.
|
|
652
|
+
* @param {boolean} [trimHecp=true] - Trim trailing empty entries.
|
|
653
|
+
* @param {boolean} [styleToObject=!trimHecp] - Convert style to object.
|
|
654
|
+
* @param {boolean} [trimIndent=trimHecp] - Trim text indentation.
|
|
655
|
+
* @returns {string} Frost JSON string.
|
|
656
|
+
*/
|
|
416
657
|
static stringify(nodeOrListOrCold, prettyJson = false, trimBobbleNode = false, trimHecp = true, styleToObject = !trimHecp, trimIndent = trimHecp) {
|
|
417
658
|
const cold = this.coldify(nodeOrListOrCold, trimBobbleNode, trimHecp, styleToObject, trimIndent, false);
|
|
418
659
|
|
|
@@ -421,6 +662,17 @@ class Doctre {
|
|
|
421
662
|
}
|
|
422
663
|
|
|
423
664
|
|
|
665
|
+
/**
|
|
666
|
+
* Injects Doctre convenience methods into Node, NodeList, Element, and jQuery prototypes.
|
|
667
|
+
*
|
|
668
|
+
* **NodeList/Node**: `coldify`, `coldified`, `stringify`, `stringified`
|
|
669
|
+
* **Element**: `cold`, `takeCold`, `frozen`, `takeFrozen`,
|
|
670
|
+
* `alive`(append), `alone`(replace+append),
|
|
671
|
+
* `freeze`(→data-frozen), `solid`(freeze+clear),
|
|
672
|
+
* `hot`(data-frozen→fragment), `worm`(hot+append), `melt`(clear+worm),
|
|
673
|
+
* `burn`(hot+delete data), `wormOut`(worm+delete), `meltOut`(clear+wormOut)
|
|
674
|
+
* **jQuery**: `coldify`, `coldified`, `stringify`, `stringified` (only when jQuery is available)
|
|
675
|
+
*/
|
|
424
676
|
static patch() {
|
|
425
677
|
const attach = (cls, name, value) => Object.defineProperty(cls.prototype, name, { value, writable: true, configurable: true, enumerable: false });
|
|
426
678
|
const attachGS = (cls, name, getter, setter) => Object.defineProperty(cls.prototype, name, { getter, setter, configurable: true, enumerable: false });
|
|
@@ -464,22 +716,35 @@ class Doctre {
|
|
|
464
716
|
}
|
|
465
717
|
|
|
466
718
|
|
|
719
|
+
/** @type {string} Tag name. */
|
|
467
720
|
tagName;
|
|
468
|
-
|
|
721
|
+
/** @type {string[]} CSS class array. */
|
|
469
722
|
classes;
|
|
470
|
-
|
|
723
|
+
/** @type {string|undefined} ID. */
|
|
471
724
|
id;
|
|
725
|
+
/** @type {string|undefined} name attribute. */
|
|
472
726
|
name;
|
|
727
|
+
/** @type {string|undefined} type attribute. */
|
|
473
728
|
type;
|
|
474
|
-
|
|
729
|
+
/** @type {Array} Child cold array (Doctre instances or strings). */
|
|
475
730
|
childDoctres;
|
|
476
|
-
|
|
731
|
+
/** @type {string|Object} Style. */
|
|
477
732
|
style;
|
|
733
|
+
/** @type {Object} Regular attributes. */
|
|
478
734
|
attrs;
|
|
735
|
+
/** @type {Object} data-* attributes. */
|
|
479
736
|
datas;
|
|
480
|
-
|
|
737
|
+
/** @type {DoctreMatchReplacer} Default token replacement map. */
|
|
481
738
|
matchReplacer;
|
|
482
739
|
|
|
740
|
+
/**
|
|
741
|
+
* @param {string|Object|Array} [solidIdOrExtracted] - solidId string, extracted object, or cold array.
|
|
742
|
+
* @param {*} [contentData] - Child content.
|
|
743
|
+
* @param {string|Object} [style={}] - Style.
|
|
744
|
+
* @param {Object} [attrs={}] - Regular attributes.
|
|
745
|
+
* @param {Object} [datas={}] - data-* attributes.
|
|
746
|
+
* @param {DoctreMatchReplacer} [matchReplacer={}] - Token replacement map.
|
|
747
|
+
*/
|
|
483
748
|
constructor(solidIdOrExtracted, contentData, style = {}, attrs = {}, datas = {}, matchReplacer = {}) {
|
|
484
749
|
if (solidIdOrExtracted instanceof Array) {
|
|
485
750
|
solidIdOrExtracted = solidIdOrExtracted[0];
|
|
@@ -511,9 +776,11 @@ class Doctre {
|
|
|
511
776
|
this.matchReplacer = matchReplacer ?? {};
|
|
512
777
|
}
|
|
513
778
|
|
|
779
|
+
/** @type {string} Space-separated class string. */
|
|
514
780
|
get className() { return this.classes.join(" "); }
|
|
515
781
|
set className(value) { this.classes = value.split(" "); }
|
|
516
782
|
|
|
783
|
+
/** @type {Object} Major attributes object `{ class, id, name, type }`. */
|
|
517
784
|
get majorAttrs() {
|
|
518
785
|
return {
|
|
519
786
|
class: this.className,
|
|
@@ -523,20 +790,46 @@ class Doctre {
|
|
|
523
790
|
};
|
|
524
791
|
}
|
|
525
792
|
|
|
793
|
+
/** @type {string} solidId string for this instance. */
|
|
526
794
|
get solidId() { return Doctre.getSolidId(this.tagName, this.className, this.id, this.name, this.type); }
|
|
527
795
|
|
|
528
796
|
|
|
797
|
+
/** @type {Element} Creates a live DOM element from this Doctre (without default matchReplacer). */
|
|
529
798
|
get live() { return Doctre.createElement(this.tagName, this.majorAttrs, this.childDoctres, this.style, this.attrs, this.datas); }
|
|
530
799
|
|
|
800
|
+
/**
|
|
801
|
+
* Creates a live DOM element with the applied matchReplacer.
|
|
802
|
+
* @param {DoctreMatchReplacer} [matchReplacer] - Token replacement map. Uses instance default if omitted.
|
|
803
|
+
* @returns {Element}
|
|
804
|
+
*/
|
|
531
805
|
fresh(matchReplacer) { return Doctre.createElement(this.tagName, this.majorAttrs, this.childDoctres, this.style, this.attrs, this.datas, matchReplacer ?? this.matchReplacer ?? {}); }
|
|
532
806
|
|
|
807
|
+
/**
|
|
808
|
+
* Serializes this Doctre to a cold array.
|
|
809
|
+
* @param {boolean} [trimBobbleNode=false]
|
|
810
|
+
* @param {boolean} [trimHecp=false]
|
|
811
|
+
* @param {boolean} [styleToObject=!trimHecp]
|
|
812
|
+
* @param {boolean} [trimIndent=trimHecp]
|
|
813
|
+
* @param {boolean} [elementAsDoctre=!trimHecp]
|
|
814
|
+
* @returns {Array} Cold array.
|
|
815
|
+
*/
|
|
533
816
|
frost(trimBobbleNode = false, trimHecp = false, styleToObject = !trimHecp, trimIndent = trimHecp, elementAsDoctre = !trimHecp) {
|
|
534
817
|
const hecp = [[this.solidId, this.cold(trimBobbleNode, trimHecp, styleToObject, trimIndent, elementAsDoctre), this.style, this.attrs, this.datas]];
|
|
535
818
|
return trimHecp ? Doctre.trimHecp(hecp) : hecp;
|
|
536
819
|
}
|
|
537
820
|
|
|
821
|
+
/** @type {Array} Compact (trimmed) frost — `frost(false, true, false, false)`. */
|
|
538
822
|
get icy() { return this.frost(false, true, false, false); }
|
|
539
823
|
|
|
824
|
+
/**
|
|
825
|
+
* Serializes this Doctre to a frost JSON string.
|
|
826
|
+
* @param {boolean|number} [prettyJson=false]
|
|
827
|
+
* @param {boolean} [trimBobbleNode=false]
|
|
828
|
+
* @param {boolean} [trimHecp=true]
|
|
829
|
+
* @param {boolean} [styleToObject=!trimHecp]
|
|
830
|
+
* @param {boolean} [trimIndent=trimHecp]
|
|
831
|
+
* @returns {string} Frost JSON string.
|
|
832
|
+
*/
|
|
540
833
|
toString(prettyJson = false, trimBobbleNode = false, trimHecp = true, styleToObject = !trimHecp, trimIndent = trimHecp) {
|
|
541
834
|
const hecp = this.frost(trimBobbleNode, trimHecp, styleToObject, trimIndent, false);
|
|
542
835
|
if (prettyJson == null || prettyJson === false) return JSON.stringify(hecp);
|
|
@@ -545,19 +838,50 @@ class Doctre {
|
|
|
545
838
|
|
|
546
839
|
|
|
547
840
|
|
|
841
|
+
/** @type {DocumentFragment} Restores child cold to a live DocumentFragment. */
|
|
548
842
|
get chill() { return Doctre.createFragment(this.childDoctres); }
|
|
549
843
|
|
|
844
|
+
/**
|
|
845
|
+
* Serializes child content to a cold array.
|
|
846
|
+
* @param {boolean} [trimBobbleNode=false]
|
|
847
|
+
* @param {boolean} [trimHecp=false]
|
|
848
|
+
* @param {boolean} [styleToObject=!trimHecp]
|
|
849
|
+
* @param {boolean} [trimIndent=trimHecp]
|
|
850
|
+
* @param {boolean} [elementAsDoctre=!trimHecp]
|
|
851
|
+
* @returns {Array}
|
|
852
|
+
*/
|
|
550
853
|
cold(trimBobbleNode = false, trimHecp = false, styleToObject = !trimHecp, trimIndent = trimHecp, elementAsDoctre = !trimHecp) {
|
|
551
854
|
return Doctre.coldify(this.childDoctres, trimBobbleNode, trimHecp, styleToObject, trimIndent, elementAsDoctre);
|
|
552
855
|
}
|
|
553
856
|
|
|
857
|
+
/**
|
|
858
|
+
* Serializes child content to a frost JSON string.
|
|
859
|
+
* @param {boolean|number} [prettyJson=false]
|
|
860
|
+
* @param {boolean} [trimBobbleNode=false]
|
|
861
|
+
* @param {boolean} [trimHecp=true]
|
|
862
|
+
* @param {boolean} [styleToObject=!trimHecp]
|
|
863
|
+
* @param {boolean} [trimIndent=trimHecp]
|
|
864
|
+
* @returns {string}
|
|
865
|
+
*/
|
|
554
866
|
frozen(prettyJson = false, trimBobbleNode = false, trimHecp = true, styleToObject = !trimHecp, trimIndent = trimHecp) {
|
|
555
867
|
return Doctre.stringify(this.childDoctres, prettyJson, trimBobbleNode, trimHecp, styleToObject, trimIndent);
|
|
556
868
|
}
|
|
557
869
|
}
|
|
558
870
|
|
|
871
|
+
/**
|
|
872
|
+
* Node array extending Array. Preserves nodes from DocumentFragment or NodeList as an array.
|
|
873
|
+
* Since a Fragment loses its children when appended to the DOM, use NodeArray to maintain references.
|
|
874
|
+
* @class
|
|
875
|
+
* @extends Array
|
|
876
|
+
*/
|
|
559
877
|
class NodeArray extends Array {
|
|
560
878
|
|
|
879
|
+
/**
|
|
880
|
+
* Copies nodes from a DocumentFragment or NodeList into a NodeArray.
|
|
881
|
+
* @param {DocumentFragment|NodeList} fragmentOrNodeList - Source.
|
|
882
|
+
* @param {NodeArray} [into=new NodeArray()] - Array to store results into.
|
|
883
|
+
* @returns {NodeArray}
|
|
884
|
+
*/
|
|
561
885
|
static box(fragmentOrNodeList, into = new NodeArray()) {
|
|
562
886
|
const nodeList = fragmentOrNodeList instanceof DocumentFragment ? fragmentOrNodeList.childNodes : fragmentOrNodeList;
|
|
563
887
|
for (const node of nodeList) into.push(node);
|
package/scripts/estreU0EEOZ.js
CHANGED
|
@@ -12,7 +12,11 @@
|
|
|
12
12
|
|
|
13
13
|
Doctre?.patch?.();
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Document access shorthand object — DOM queries, element creation, Doctre integration.
|
|
17
|
+
* `doc.b` = document.body, `doc.ce()` = Doctre.createElement, `doc.l()` = Doctre.live, etc.
|
|
18
|
+
* @type {Object}
|
|
19
|
+
*/
|
|
16
20
|
const doc = {
|
|
17
21
|
get b() { return document.body; },
|
|
18
22
|
get $b() { return $(this.b); },
|
|
@@ -879,10 +883,20 @@ class EUX {
|
|
|
879
883
|
|
|
880
884
|
|
|
881
885
|
/**
|
|
882
|
-
* Estre Local
|
|
886
|
+
* Estre Local Styler — generates local-scope styles by replacing `##` tokens with the CSS path up to the parent element.
|
|
887
|
+
*
|
|
888
|
+
* When `##` is used in an HTML `<style>` tag, it is automatically replaced based on the style tag's position
|
|
889
|
+
* with a parent → ancestor CSS selector chain. Achieves scoped style effect without Shadow DOM.
|
|
890
|
+
* @class
|
|
883
891
|
*/
|
|
884
892
|
class LocalStyle {
|
|
885
893
|
|
|
894
|
+
/**
|
|
895
|
+
* Replaces `##` in the element's style text with the local CSS selector path.
|
|
896
|
+
* @param {Element|null} elem - Element containing style text. If null, adds directly to location.
|
|
897
|
+
* @param {string} [styleText=elem.innerHTML] - Style text to replace.
|
|
898
|
+
* @param {Element} [location=elem.parentElement] - Base element for the local path.
|
|
899
|
+
*/
|
|
886
900
|
static localize(elem, styleText = elem.innerHTML, location = elem.parentElement) {
|
|
887
901
|
const htmlEntities = {
|
|
888
902
|
" ": " ",
|
|
@@ -947,6 +961,11 @@ class LocalStyle {
|
|
|
947
961
|
}
|
|
948
962
|
}
|
|
949
963
|
|
|
964
|
+
/**
|
|
965
|
+
* Directly adds a local style at the given location.
|
|
966
|
+
* @param {Element} location - Base element to insert the style at.
|
|
967
|
+
* @param {string} localStyle - Style text containing `##`.
|
|
968
|
+
*/
|
|
950
969
|
static appendLocalize(location, localStyle) {
|
|
951
970
|
this.localize(null, localStyle, location);
|
|
952
971
|
}
|
|
@@ -954,7 +973,9 @@ class LocalStyle {
|
|
|
954
973
|
|
|
955
974
|
|
|
956
975
|
/**
|
|
957
|
-
*
|
|
976
|
+
* Estre locale constants — per-language weekday names, month names, date/time prefix/suffix collections.
|
|
977
|
+
* Detects the current language via `EsLocale.currentLanguage` and looks up locale strings from `EsLocale.collections`.
|
|
978
|
+
* @class
|
|
958
979
|
*/
|
|
959
980
|
class EsLocale {
|
|
960
981
|
static get currentLocale() { return navigator.language; }
|
|
@@ -1574,7 +1595,7 @@ const Ecal = {
|
|
|
1574
1595
|
}
|
|
1575
1596
|
},
|
|
1576
1597
|
|
|
1577
|
-
/**
|
|
1598
|
+
/** Chronological sort function */
|
|
1578
1599
|
byTime: (a, b) => a.time - b.time,
|
|
1579
1600
|
|
|
1580
1601
|
eoo
|