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.
@@ -0,0 +1,4317 @@
1
+ /*
2
+ EstreUI rimwork — Page Handle + Handler + Model (tightly coupled)
3
+ Part of the split from estreUi.js (roadmap #002 phase 2).
4
+
5
+ This file is loaded as a plain <script> tag and shares the global scope
6
+ with the other estreUi-*.js files. Load order matters: see index.html.
7
+ */
8
+
9
+ // MODULE: Page Handle -- EstrePageHandle, EstrePageHostHandle,
10
+ // EstreComponent variants, EstreContainer, EstreArticle
11
+ // ======================================================================
12
+
13
+ /**
14
+ * Common page handle model
15
+ */
16
+ class EstrePageHandle {
17
+
18
+ hostType = "unknown";
19
+
20
+ #host = null;
21
+ get host() { return this.#host; }
22
+ #$host = null;
23
+ get $host() { return this.#$host; }
24
+
25
+ id = null;
26
+ get instanceId() { return !this.isStatic && this.isMultiInstance ? this.id + "^" + this.instanceOrigin : this.id; }
27
+ get instanceOrigin() { return !this.isStatic && this.isMultiInstance ? this.$host?.attr(eds.instanceOrigin)?.ifEmpty(_ => u) : u; }
28
+ set instanceOrigin(value) { if (!this.isStatic && this.isMultiInstance) this.$host?.attr(eds.instanceOrigin, value ?? ""); }
29
+
30
+ #page = null;
31
+ get page() { return this.#page; }
32
+ get pid() { return this.page?.pid; }
33
+ get instancePid() { return this.page?.instancePid; }
34
+
35
+ get isStatic() { return this.$host?.attr(eds.static) == t1; }
36
+ get isFullyStatic() { return this.isStatic; }
37
+ get isModal() { return this.$host?.hasClass("modal"); }
38
+ get isOnTop() {
39
+ const onTop = this.$host?.attr(eds.onTop);
40
+ return onTop == t1 || onTop == "1*";
41
+ }
42
+ get isMultiInstance() { return this.$host?.attr(eds.multiInstance) == t1; }
43
+
44
+ get isCanBack() { return false; }
45
+
46
+ get title() { return this.$host?.attr(eds.title); }
47
+
48
+ #appbarLeft = null;
49
+ #appbarRight = null;
50
+ #appbarCenter = null;
51
+ get appbarLeft() { return val(this.#appbarLeft, it => it ?? val(this.$host?.attr(eds.appbarLeft)?.trim(), aa => isNully(aa) || aa.length < 2 ? it : (aa == "tp" ? undefined : aa))); }
52
+ set appbarLeft(value) { this.#appbarLeft = value; } //this.$host?.attr(eds.appbarLeft, Doctre.stringify(value)); }
53
+ get appbarRight() { return val(this.#appbarRight, it => it ?? val(this.$host?.attr(eds.appbarRight)?.trim(), aa => isNully(aa) || aa.length < 2 ? it : (aa == "tp" ? undefined : aa))); }
54
+ set appbarRight(value) { this.#appbarRight = value; } //this.$host?.attr(eds.appbarRight, Doctre.stringify(value)); }
55
+ get appbarCenter() { return val(this.#appbarCenter, it => it ?? val(this.$host?.attr(eds.appbarCenter)?.trim(), aa => isNully(aa) || aa.length < 2 ? it : (aa == "tp" ? undefined : aa))); }
56
+ set appbarCenter(value) { this.#appbarCenter = value; } //this.$host?.attr(eds.appbarCenter, Doctre.stringify(value)); }
57
+ get isAppbarLeftAssigned() { return this.hostType != "component" && !(this.isStatic && !this.isFullyStatic) && (this.$host.let(it => it.hasClass("constraint") || (it.hasClass("fwvs") && !EUX.isExtensive))) ? !typeUndefined(this.appbarLeft) : isNotNully(this.appbarLeft); }
58
+ get isAppbarRightAssigned() { return this.hostType != "component" && !(this.isStatic && !this.isFullyStatic) && (this.$host.let(it => it.hasClass("constraint") || (it.hasClass("fwvs") && !EUX.isExtensive))) ? !typeUndefined(this.appbarRight) : isNotNully(this.appbarRight); }
59
+ get isAppbarCenterAssigned() { return this.hostType != "component" && !(this.isStatic && !this.isFullyStatic) && (this.$host.let(it => it.hasClass("constraint") || (it.hasClass("fwvs") && !EUX.isExtensive))) ? !typeUndefined(this.appbarCenter) : isNotNully(this.appbarCenter); }
60
+ get appbarLeftFeed() { return setter => {
61
+ const $set = setter(this.appbarLeft)?.let(it => $(it));
62
+ this.$appbarLeft = $set;
63
+ this.onInitAppbarLeft($set);
64
+ return $set;
65
+ } }
66
+ get appbarRightFeed() { return setter => {
67
+ const $set = setter(this.appbarRight)?.let(it => $(it));
68
+ this.$appbarRight = $set;
69
+ this.onInitAppbarRight($set);
70
+ return $set;
71
+ } }
72
+ get appbarCenterFeed() { return setter => {
73
+ const $set = setter(this.appbarCenter)?.let(it => $(it));
74
+ this.$appbarCenter = $set;
75
+ this.onInitAppbarCenter($set);
76
+ return $set;
77
+ } }
78
+ $appbarLeft;
79
+ $appbarRight;
80
+ $appbarCenter;
81
+ onInitAppbarLeft = $appbarLeft => {};
82
+ onInitAppbarRight = $appbarRight => {};
83
+ onInitAppbarCenter = $appbarCenter => {};
84
+
85
+ get isFullyHided() {
86
+ const onTop = this.$host?.attr(eds.onTop);
87
+ return onTop == "" || onTop == t0;
88
+ }
89
+
90
+ #handler = null;
91
+ get handler() { return this.#handler; }
92
+
93
+ #intent = null;
94
+ get intent() { return this.#intent; }
95
+
96
+ #isOpened = false;
97
+ get isOpened() { return this.#isOpened; }
98
+ #isShowing = false;
99
+ get isShowing() { return this.isOpened && this.#isShowing; }
100
+ #isFocused = false;
101
+ get isFocused() { return this.isShowing && this.#isFocused; }
102
+
103
+ #isHiding = false;
104
+ get isHiding() { return this.#isHiding; }
105
+ #isClosing = false;
106
+ get isClosing() { return this.#isClosing; }
107
+ #isReleasing = false;
108
+ get isReleasing() { return this.#isReleasing; }
109
+
110
+ #currentOnTop = null;
111
+ get currentOnTop() { return this.#currentOnTop; };
112
+ set currentOnTop(handle) {
113
+ this.#currentOnTop = handle;
114
+ }
115
+
116
+ #intentProxy;
117
+ #intentDataProxy;
118
+ #intentDataBindProxy = {};
119
+ // #revokeIntentProxy;
120
+ // #revokeIntentDataProxy;
121
+ // #revokeIntentDataBindProxy = {};
122
+
123
+ #isProcessing = f;
124
+ get isProcessing() { return this.#isProcessing; }
125
+
126
+ get mainArticle() { return this; }
127
+
128
+
129
+ constructor(host, instanceOrigin) {
130
+ this.#host = host;
131
+ this.#$host = $(host);
132
+
133
+ if (host.pageHandle != null && host.pageHandle != this) {
134
+ try {
135
+ host.pageHandle.release();
136
+ } catch (ex) {
137
+ if (window.isLogging) console.error(ex.name + "\n", ex.message);
138
+ }
139
+ }
140
+ this.#host.pageHandle = this;
141
+ if (!this.isStatic && this.isMultiInstance) this.instanceOrigin = instanceOrigin ?? "ai_" + Date.now();
142
+ }
143
+
144
+ release(remove) {
145
+ this.onRelease(remove);
146
+
147
+ if (this.host != null) delete this.host.pageHandle;
148
+
149
+ if (remove === true) this.$host?.remove();
150
+ else {
151
+ if (remove === false) this.$host?.empty();
152
+ this.#host = n;
153
+ this.#$host = n;
154
+ }
155
+ }
156
+
157
+ init(page, intent) {
158
+ this.#page = page;
159
+ page.fetchHandler(this);
160
+ if (this.handler == null) this.setHandler(new EstrePageHandler(this));
161
+
162
+ this.pushIntent(intent, true);
163
+
164
+ this.onBring();
165
+
166
+ return this;
167
+ }
168
+
169
+ setHandler(handler) {
170
+ if (this.#handler == null) this.#handler = handler;
171
+ }
172
+
173
+ takeOnPageIntent(intent = {}) {
174
+ // this.#revokeIntentProxy?.();
175
+ if (nn(intent?.data) && !intent.data.isProxy) intent.data = this.takeOnPageData(intent.data);
176
+ // const { proxy, revoke } = nn(intent) ? Proxy.revocable(intent, {
177
+ const proxy = nn(intent) ? new Proxy(intent, {
178
+ get: (target, prop) => prop == "isProxy" ? t : target[prop],
179
+ set: (target, prop, value) => {
180
+ if (prop == "data") {
181
+ target.data = this.takeOnPageData(value);
182
+ if (!this.mainArticle.isProcessing) this.mainArticle.applyActiveStruct(this.mainArticle.$host, this);
183
+ } else target[prop] = value;
184
+ return t;
185
+ },
186
+ deleteProperty: (target, prop) => {
187
+ if (prop == "data") {
188
+ this.takeOnPageData(u);
189
+ delete target.data;
190
+ } else delete target[prop];
191
+ if (!this.mainArticle.isProcessing) this.mainArticle.applyActiveStruct(this.mainArticle.$host, this);
192
+ return t;
193
+ },
194
+ }) : u;//{ proxy: u, revoke: u };
195
+ this.#intentProxy = proxy;
196
+ // this.#revokeIntentProxy = revoke;
197
+ return proxy ?? intent;
198
+ }
199
+
200
+ takeOnPageData(data = {}) {
201
+ // this.#revokeIntentDataProxy?.();
202
+ const isObject = nn(data) && tj(data);
203
+ if (isObject) for (const key in data) if (!data[key]?.isProxy) data[key] = this.takeOnPageBind(key, data[key]);
204
+ // const { proxy, revoke } = isObject ? Proxy.revocable(data, {
205
+ const proxy = isObject ? new Proxy(data, {
206
+ get: (target, prop) => prop == "isProxy" ? t : target[prop],
207
+ set: (target, prop, value) => {
208
+ target[prop] = this.takeOnPageBind(prop, value);
209
+ if (!this.mainArticle.isProcessing) this.mainArticle.applyActiveStruct(this.mainArticle.$host, this);
210
+ return t;
211
+ },
212
+ deleteProperty: (target, prop) => {
213
+ this.takeOnPageBind(prop, u);
214
+ delete target[prop];
215
+ if (!this.mainArticle.isProcessing) this.mainArticle.applyActiveStruct(this.mainArticle.$host, this);
216
+ return t;
217
+ },
218
+ }) : u;//{ proxy: u, revoke: u };
219
+ this.#intentDataProxy = proxy;
220
+ // this.#revokeIntentDataProxy = revoke;
221
+ return proxy ?? data;
222
+ }
223
+
224
+ takeOnPageBind(pr, bind) {
225
+ // const rv = this.#revokeIntentDataBindProxy[pr];
226
+ // if (tf(rv)) rv();
227
+ if (nn(bind) && tj(bind)) {
228
+ // const { proxy, revoke } = Proxy.revocable(bind, {
229
+ const proxy = new Proxy(bind, {
230
+ get: (target, prop) => prop == "isProxy" ? t : target[prop],
231
+ set: (target, prop, value) => {
232
+ target[prop] = value;
233
+ if (!this.mainArticle.isProcessing) this.mainArticle.applyActiveStruct(this.mainArticle.$host, this);
234
+ return t;
235
+ },
236
+ deleteProperty: (target, prop) => {
237
+ delete target[prop];
238
+ if (!this.mainArticle.isProcessing) this.mainArticle.applyActiveStruct(this.mainArticle.$host, this);
239
+ return t;
240
+ },
241
+ });
242
+ this.#intentDataBindProxy[pr] = proxy;
243
+ // this.#revokeIntentDataBindProxy[pr] = revoke;
244
+ return proxy;
245
+ } else {
246
+ delete this.#intentDataBindProxy[pr];
247
+ // delete this.#revokeIntentDataBindProxy[pr];
248
+ return bind;
249
+ }
250
+ }
251
+
252
+ apply(process = (data, intent) => {}, $bound = this.mainArticle.$host, handle = this) {
253
+ if (this.mainArticle != this) return this.mainArticle.apply(process, $bound, this);
254
+ const isAlreadyProcessing = this.#isProcessing;
255
+ if (!isAlreadyProcessing) this.#isProcessing = t;
256
+ this.placeIntentData();
257
+ process(this.intent.data, this.intent);
258
+ if (!isAlreadyProcessing) this.#isProcessing = f;
259
+ return this.applyActiveStruct($bound, handle);
260
+ }
261
+
262
+ async applyAsync(process = async (data, intent) => {}, $bound = this.mainArticle.$host, handle = this) {
263
+ if (this.mainArticle != this) return await this.mainArticle.applyAsync(process, $bound, handle);
264
+ const isAlreadyProcessing = this.#isProcessing;
265
+ if (!isAlreadyProcessing) this.#isProcessing = t;
266
+ this.placeIntentData();
267
+ await process(this.intent.data, this.intent);
268
+ if (!isAlreadyProcessing) this.#isProcessing = f;
269
+ return await this.applyActiveStruct($bound, handle);
270
+ }
271
+
272
+ placeIntent(intent = {}) {
273
+ return this.#intent ??= this.takeOnPageIntent(intent);
274
+ }
275
+
276
+ placeIntentData(data = {}) {
277
+ this.placeIntent();
278
+ return this.#intent.data ??= data;
279
+ }
280
+
281
+ pushIntent(intent, onInit = false) {
282
+ if (intent != n) {
283
+ const push = _ => {
284
+ if (intent === f) this.#intent = n;
285
+ else if (this.intent == n) this.#intent = this.takeOnPageIntent(intent.isProxy ? intent.clone : intent);
286
+ else for (const key in intent) this.intent[key] = intent[key];
287
+
288
+ if (window.isVerbosely) console.log("pushed intent on " + this.hostType + " " + EstreUiPage.from(this).pid + "\n", this.intent);
289
+ else if (window.isDebug) console.log("pushed intent on " + this.hostType + " " + EstreUiPage.from(this).pid + "\n");
290
+ this.onIntentUpdated(this, intent);
291
+ };
292
+ if (this.#isOpened) this.apply(push);
293
+ else push();
294
+ return true;
295
+ } else false;
296
+ }
297
+
298
+
299
+ show(isRequest = false, setFocus = true) {
300
+ if (!this.isShowing) {
301
+ this.onOpen();
302
+ this.onShow();
303
+ this.$host.attr(eds.onTop, t1 + "*");
304
+ setTimeout(async _ => {
305
+ const $host = this?.$host;
306
+ if ($host != null && $host.attr(eds.onTop) == t1 + "*") {
307
+ $host.attr(eds.onTop, t1);
308
+ if (setFocus && this != null && this.hostType == "article") await estreUi.focus(this);//this?.focus();
309
+ }
310
+ }, 0);
311
+ return true;
312
+ } else return false;
313
+ }
314
+
315
+ focus() {
316
+ if (!this.isFocused) {
317
+ this.onFocus();
318
+ return true;
319
+ } else return false;
320
+ }
321
+
322
+ reload(isRequest = true) {
323
+ if (isRequest) return this.onReload();
324
+ else if (this.#isOpened) {
325
+ const onTop = this.currentOnTop;
326
+ const onReload = this.handler?.onReload;
327
+ return (onTop != null && onTop.onReload()) || (onReload != null && (handle => {
328
+ if (window.isVerbosely) console.log("[performReload] " + this.sectionBound + " " + this.hostType + " " + this.pid, this.host);
329
+ else if (window.isDebug) console.log("[performReload] " + this.sectionBound + " " + this.hostType + " " + this.pid);
330
+ return handle?.handler?.onReload(this);
331
+ })(this));
332
+ } else return false;
333
+ }
334
+
335
+ async back(isRequest = true) {
336
+ if (isRequest) return await this.onBack();
337
+ else if (this.isShowing) {
338
+ const onTop = this.currentOnTop;
339
+ const onBack = this.handler?.onBack;
340
+ return (onTop != null && await onTop.onBack()) || (onBack != null && await (async (handle) => {
341
+ if (window.isVerbosely) console.log("[performBack] " + this.sectionBound + " " + this.hostType + " " + this.pid, this.host);
342
+ else if (window.isDebug) console.log("[performBack] " + this.sectionBound + " " + this.hostType + " " + this.pid);
343
+ return await handle?.handler?.onBack(this);
344
+ })(this));
345
+ } else return false;
346
+ }
347
+
348
+ blur() {
349
+ if (this.isFocused) {
350
+ return this.onBlur();
351
+ } else return false;
352
+ }
353
+
354
+ async hide(fullyHide = true) {
355
+ if ((!this.isHiding && this.isShowing) || (fullyHide && !this.isFullyHided)) {
356
+ this.#isHiding = true;
357
+ await this.blur();
358
+ await this.onHide(fullyHide);
359
+ if (fullyHide) {
360
+ this.$host.attr(eds.onTop, t0);
361
+ const delay = cvt.t2ms(this.$host.css(a.trdr));
362
+ return new Promise(async (resolve) => {
363
+ setTimeout(_ =>{
364
+ const $host = this?.$host;
365
+ if ($host != null && $host.attr(eds.onTop) == t0) {
366
+ $host.attr(eds.onTop, "");
367
+ resolve(true);
368
+ } else resolve(false);
369
+ }, delay);
370
+ });
371
+ } else {
372
+ this.$host.attr(eds.onTop, t0 + "*");
373
+ return true;
374
+ }
375
+ } else return false;
376
+ }
377
+
378
+ close(isTermination = false, isOnRelease = false) {
379
+ if (this.isOpened) {
380
+ if (this.isOpened && (isOnRelease || isTermination || !this.isStatic)) this.#isClosing = true;
381
+ const task = this.hide();
382
+ return postAsyncQueue(async _ => {
383
+ await task;
384
+ return await this.onClose(isTermination, isOnRelease);
385
+ });
386
+ } else return false;
387
+ }
388
+
389
+
390
+ onBring() {
391
+ if (window.isDebug) console.log("[onBring] " + this.sectionBound + " " + this.hostType + " " + this.pid);//, this.host);
392
+ if (this.handler?.onBring != null) this.handler.onBring(this);
393
+ if (this.intent?.onBring != null) for (var item of this.intent.onBring) if (item.from == this.hostType && !item.disabled) this.processAction(item);
394
+ }
395
+
396
+ onOpen() {
397
+ if (!this.isOpened) {
398
+ if (window.isDebug) console.log("[onOpen] " + this.sectionBound + " " + this.hostType + " " + this.pid);//, this.host);
399
+ this.#isOpened = true;
400
+ if (this.handler?.onOpen != null) this.handler.onOpen(this);
401
+ if (this.intent?.onOpen != null) for (var item of this.intent.onOpen) if (item.from == this.hostType && !item.disabled) this.processAction(item);
402
+ return true;
403
+ } else return false;
404
+ }
405
+
406
+ onShow() {
407
+ if (this.isOpened && !this.isShowing) {
408
+ if (window.isVerbosely) console.log("[onShow] " + this.sectionBound + " " + this.hostType + " " + this.pid, this.host);
409
+ else if (window.isDebug) console.log("[onShow] " + this.sectionBound + " " + this.hostType + " " + this.pid);
410
+ this.#isShowing = true;
411
+ if (this.handler?.onShow != null) this.handler.onShow(this);
412
+ if (this.intent?.onShow != null) for (var item of this.intent.onShow) if (item.from == this.hostType && !item.disabled) this.processAction(item);
413
+ return true;
414
+ } else return false;
415
+ }
416
+
417
+ onFocus() {
418
+ if (!this.isFocused) {
419
+ if (window.isDebug) console.log("[onFocus] " + this.sectionBound + " " + this.hostType + " " + this.pid);//, this.host);
420
+ this.#isFocused = true;
421
+ if (this.handler?.onFocus != null) this.handler.onFocus(this);
422
+ if (this.intent?.onFocus != null) for (var item of this.intent.onFocus) if (item.from == this.hostType && !item.disabled) this.processAction(item);
423
+ return true;
424
+ } else return false;
425
+ }
426
+
427
+ onIntentUpdated(handle, intent) {
428
+ if (this.isOpened) {
429
+ if (window.isDebug) console.log("[onIntentUpdated] " + this.sectionBound + " " + this.hostType + " " + this.pid);//, this.host);
430
+ if (this.handler?.onIntentUpdated != null) this.handler.onIntentUpdated(this, intent);
431
+ if (this.intent?.onIntentUpdated != null) for (var item of this.intent.onIntentUpdated) if (item.from == this.hostType && !item.disabled) this.processAction(item);
432
+ }
433
+ }
434
+
435
+ onReload() {
436
+ if (this.isOpened) {
437
+ if (window.isDebug) console.log("[onReload] " + this.sectionBound + " " + this.hostType + " " + this.pid);//, this.host);
438
+ return this.reload(false);
439
+ } else return false;
440
+ }
441
+
442
+ async onBack() {
443
+ if (this.isShowing) {
444
+ if (window.isDebug) console.log("[onBack] " + this.sectionBound + " " + this.hostType + " " + this.pid);//, this.host);
445
+ return await this.back(false);
446
+ } else return false;
447
+ }
448
+
449
+ async onBlur() {
450
+ if (this.isShowing) {
451
+ this.#isFocused = false;
452
+ if (window.isDebug) console.log("[onBlur] " + this.sectionBound + " " + this.hostType + " " + this.pid);//, this.host);
453
+ if (this.intent?.onBlur != null) for (var item of this.intent.onBlur) if (item.from == this.hostType && !item.disabled) await this.processAction(item);
454
+ if (this.handler?.onBlur != null) await this.handler.onBlur(this);
455
+ return true;
456
+ } else return false;
457
+ }
458
+
459
+ async onHide(fullyHide) {
460
+ if (this.isShowing) {
461
+ this.#isShowing = false;
462
+ if (window.isVerbosely) console.log("[onHide] " + this.sectionBound + " " + this.hostType + " " + this.pid, this.host);
463
+ else if (window.isDebug) console.log("[onHide] " + this.sectionBound + " " + this.hostType + " " + this.pid);
464
+ if (this.intent?.onHide != null) for (var item of this.intent.onHide) if (item.from == this.hostType && !item.disabled) await this.processAction(item);
465
+ if (this.handler?.onHide != null) await this.handler.onHide(this, fullyHide);
466
+ if (this.intent?.bringOnBack != null && this.intent.bringOnBack.pid != n) {
467
+ const bringOnBack = this.intent.bringOnBack;
468
+ const isNotAssignedHostType = bringOnBack.hostType == n;
469
+ const isMatchHostType = bringOnBack.hostType == this.hostType;
470
+ if ((this.isStatic && isMatchHostType) || this.isClosing && (isNotAssignedHostType || isMatchHostType)) {
471
+ const pid = bringOnBack.pid;
472
+ delete this.intent.bringOnBack;
473
+ if (window.isDebug) console.log("Bringing on back to " + pid);
474
+ postQueue(_ => pageManager.bringPage(pid));
475
+ }
476
+ }
477
+ return true;
478
+ } else return false;
479
+ }
480
+
481
+ async onClose(isTermination = false, isOnRelease = false) {
482
+ if (this.isOpened && (isOnRelease || !this.isStatic)) {
483
+ this.#isOpened = false;
484
+ if (window.isDebug) console.log("[onClose] " + this.sectionBound + " " + this.hostType + " " + this.pid);//, this.host);
485
+ if (this.intent?.onClose != null) for (var item of this.intent.onClose) if (item.from == this.hostType && !item.disabled) await this.processAction(item);
486
+ if (this.handler?.onClose != null) await this.handler.onClose(this);
487
+ if (this.intent?.bringOnBack != null && this.intent.bringOnBack.pid != n) {
488
+ const bringOnBack = this.intent.bringOnBack;
489
+ const isNotAssignedHostType = bringOnBack.hostType == n;
490
+ const isMatchHostType = bringOnBack.hostType == this.hostType;
491
+ if (isNotAssignedHostType || isMatchHostType) {
492
+ const pid = bringOnBack.pid;
493
+ delete this.intent.bringOnBack;
494
+ if (window.isDebug) console.log("Bringing on back to " + pid);
495
+ postQueue(_ => pageManager.bringPage(pid));
496
+ }
497
+ }
498
+ return true;
499
+ } else return false;
500
+ }
501
+
502
+ async onRelease(remove) {
503
+ if (!this.isReleasing) {
504
+ this.#isReleasing = true;
505
+ if (this.isStatic) await this.close(false, true);
506
+ const removal = remove == null ? "leave" : (remove ? "remove" : "empty")
507
+ if (window.isDebug) console.log("[onRelease(" + removal + ")] " + this.sectionBound + " " + this.hostType + " " + this.pid);//, this.host);
508
+ if (this.handler?.onRelease != null) await this.handler.onRelease(this, remove);
509
+ if (this.intent?.onRelease != null) for (var item of this.intent.onRelease) if (item.from == this.hostType && !item.disabled) await this.processAction(item);
510
+
511
+ // for (const revoke of this.#revokeIntentDataBindProxy.looks) try {
512
+ // revoke?.();
513
+ // } catch (ex) {}
514
+ // this.#revokeIntentDataProxy?.();
515
+ // this.#revokeIntentProxy?.();
516
+ return true;
517
+ } else return false;
518
+ }
519
+
520
+
521
+ processAction(data) {
522
+ if (data?.from == this.hostType) {
523
+ switch (data.action) {
524
+ case "autoClose":
525
+ if (data.host != null) {
526
+ const handle = this.getHost(data.host);
527
+ if (data.time != null && !isNaN(data.time)) {
528
+ setTimeout(_ => handle?.close(), parseInt(data.time));
529
+ }
530
+ }
531
+ break;
532
+
533
+ case "closePage":
534
+ if (data.targetPid != null) {
535
+ pageManager.closePage(data.targetPid);
536
+ }
537
+ break;
538
+ }
539
+ }
540
+ }
541
+
542
+ getHost(hostType) {
543
+ return this;
544
+ }
545
+
546
+
547
+
548
+ // active struct master
549
+ applyActiveStruct($host = this.$host, handle = this, replaceHandles = false) {
550
+ this.initContentBrokers($host);
551
+ this.initLiveElement($host, replaceHandles);
552
+
553
+ const applied = this.handler.onApplied?.(this, this.intent?.data, this.intent, $host, replaceHandles);
554
+ if (handle != this) handle.handler.onApplied?.(handle, handle.intent?.data, handle.intent, $host, replaceHandles);
555
+ return applied;
556
+ }
557
+
558
+ applyActiveStructLocalBind($host = this.$host) {
559
+ this.initDataBind($host);
560
+ }
561
+
562
+ applyActiveStructAfterBind($host = this.$host, replaceHandles = false) {
563
+ this.initContentBrokersAfterBind($host);
564
+ this.initLiveElement($host, replaceHandles);
565
+ }
566
+
567
+ // content brokers
568
+ initContentBrokers($host = this.$host) {
569
+ this.initDataBind($host);
570
+ this.initContentBrokersAfterBind($host);
571
+ }
572
+
573
+ initContentBrokersAfterBind($host = this.$host) {
574
+ this.initSolidPoint($host);
575
+ this.initLocalStyle($host);
576
+ }
577
+
578
+ initDataBind($host = this.$host) {
579
+ const eachTarget = ($elem, attrId, each = (target, prefix = "", suffix = "") => {}) => {
580
+ const specifier = $elem.attr(attrId);
581
+ if (specifier != null && specifier != "") {
582
+ const targets = specifier.split(s);
583
+ for (let target of targets) {
584
+ let prefix = "", suffix = "";
585
+ if (target.indexOf(cf) > -1) [target, prefix] = target.split(cf);
586
+ if (target.indexOf(ds) > -1) [suffix, target] = target.split(ds);
587
+ each(target, prefix, suffix);
588
+ }
589
+ }
590
+ }
591
+ const eachTargetFor = ($elem, attrId, each = (targetItem, targetName, prefix = "", suffix = "") => {}) => {
592
+ const specifier = $elem.attr(attrId);
593
+ if (specifier != null && specifier != "") {
594
+ const targets = specifier.split(s);
595
+ for (const target of targets) {
596
+ let [targetItem, targetName] = target.split(at);
597
+ let prefix = "", suffix = "";
598
+ if (targetItem.indexOf(cf) > -1) [targetItem, prefix] = targetItem.split(cf);
599
+ if (targetItem.indexOf(ds) > -1) [suffix, targetItem] = targetItem.split(ds);
600
+ each(targetItem, targetName, prefix, suffix);
601
+ }
602
+ }
603
+ }
604
+
605
+ if (this.intent != null) {
606
+ const data = this.intent.data;
607
+
608
+ if (data != null) for (var item in data) {
609
+ const value = data[item];
610
+
611
+ if (isNully(value)) continue;
612
+
613
+ if ($host.is(aiv(eds.bind, item))) $host.html(value);
614
+ if ($host.is(aiv(eds.bindAmount, item))) $host.html(v2a(value));
615
+ if ($host.is(aiv(eds.bindValue, item))) $host.val(value);
616
+ $host.find(aiv(eds.bind, item)).html(value);
617
+ $host.find(aiv(eds.bindAmount, item)).html(v2a(value));
618
+ $host.find(aiv(eds.bindValue, item)).val(value);
619
+
620
+ if ($host.is(acv(eds.bindAttr, item) + acv(eds.bindAttr, at))) eachTargetFor($host, eds.bindAttr, (targetItem, targetAttr, prefix = "", suffix = "") => {
621
+ if (targetItem == item) $host.attr(targetAttr, prefix + value + suffix);
622
+ });
623
+ $host.find(acv(eds.bindAttr, item) + acv(eds.bindAttr, at)).each((i, elem) => {
624
+ const $elem = $(elem);
625
+ eachTargetFor($elem, eds.bindAttr, (targetItem, targetAttr, prefix = "", suffix = "") => {
626
+ if (targetItem == item) $elem.attr(targetAttr, prefix + value + suffix);
627
+ });
628
+ });
629
+
630
+ if ($host.find(acv(eds.bindStyle, item) + acv(eds.bindStyle, at))) eachTargetFor($host, eds.bindStyle, (targetItem, targetStyle, prefix = "", suffix = "") => {
631
+ if (targetItem == item) $host.css(targetStyle, prefix + value + suffix);
632
+ });
633
+ $host.find(acv(eds.bindStyle, item) + acv(eds.bindStyle, at)).each((i, elem) => {
634
+ const $elem = $(elem);
635
+ eachTargetFor($elem, eds.bindStyle, (targetItem, targetStyle, prefix = "", suffix = "") => {
636
+ if (targetItem == item) $elem.css(targetStyle, prefix + value + suffix);
637
+ });
638
+ });
639
+
640
+ if (value instanceof Array) $host.find(aiv(eds.bindArray, item)).each((i, elem) => {
641
+ const $elem = $(elem);
642
+
643
+ const placeholderMessage = $elem.attr(eds.placeholder);
644
+ const $placeholder = $elem.find(uis.placeholder);
645
+ // $placeholder.remove();
646
+ if (elem.dataset.frozenPlaceholder == null) {
647
+ $placeholder.find(".message").html("|message|");
648
+ const solidPlaceholder = $placeholder.length > 0 ? $placeholder[0].stringified() : (new Doctre("div.placeholder", [["span.message", "|message|"]])).toString();
649
+ $elem.attr(eds.frozenPlaceholder, solidPlaceholder);
650
+ }
651
+
652
+ // const liHtml = $elem.first().html().trim();
653
+ // $elem.empty();
654
+ if (elem.dataset.frozenItem == null) elem.solid("frozenItem");
655
+ else $elem.empty();
656
+
657
+ if (value.length < 1) {
658
+ // if ($placeholder.length > 0) {
659
+ // if (nne(placeholderMessage)) $placeholder.find(".message").html(placeholderMessage);
660
+ // $elem.append($placeholder);
661
+ // } else {
662
+ // const placeholder = doc.ce(div, "placeholder");
663
+ // const message = doc.ce(sp, "message", nne(placeholderMessage) ? placeholderMessage : "No data");
664
+ // placeholder.append(message);
665
+ // $elem.append(placeholder);
666
+ // }
667
+ elem.melt({ "message": (isNotNullAndEmpty(placeholderMessage) ? placeholderMessage : "No data") }, "frozenPlaceholder");
668
+ } else for (var index in value) {
669
+ const arrayItem = value[index];
670
+
671
+ // const li = $.parseHTML(liHtml);
672
+ // const $li = $(li);
673
+ const $li = $(elem.hot({}, "frozenItem")).children();
674
+ $elem.append($li);
675
+
676
+ const valueIsObject = typeof arrayItem == "object";
677
+
678
+ var arrayItemValue = arrayItem;
679
+
680
+ if (isNotNully(arrayItemValue)) {
681
+ if (valueIsObject) {
682
+ arrayItemValue = JSON.stringify(arrayItem);
683
+
684
+ for (var objItem in arrayItem) {
685
+ const value = arrayItem[objItem];
686
+
687
+ if (isNully(value)) continue;
688
+
689
+ if ($li.is(aiv(eds.bindObjectArrayItem, objItem))) $li.html(value);
690
+ if ($li.is(aiv(eds.bindObjectArrayAmount, objItem))) $li.html(v2a(value));
691
+ if ($li.is(aiv(eds.bindObjectArrayValue, objItem))) $li.val(value);
692
+ $li.find(aiv(eds.bindObjectArrayItem, objItem)).html(value);
693
+ $li.find(aiv(eds.bindObjectArrayAmount, objItem)).html(v2a(value));
694
+ $li.find(aiv(eds.bindObjectArrayValue, objItem)).val(value);
695
+
696
+ if ($li.is(acv(eds.bindObjectArrayAttr, objItem) + acv(eds.bindObjectArrayAttr, at))) eachTargetFor($li, eds.bindObjectArrayAttr, (targetItem, targetAttr, prefix = "", suffix = "") => {
697
+ if (targetItem == objItem) $li.attr(targetAttr, prefix + value + suffix);
698
+ });
699
+ $li.find(acv(eds.bindObjectArrayAttr, objItem) + acv(eds.bindObjectArrayAttr, at)).each((i, elem) => {
700
+ const $elem = $(elem);
701
+ eachTargetFor($elem, eds.bindObjectArrayAttr, (targetItem, targetAttr, prefix = "", suffix = "") => {
702
+ if (targetItem == objItem) $elem.attr(targetAttr, prefix + value + suffix);
703
+ });
704
+ });
705
+
706
+ const styleValue = isEmpty(value) ? "unset" : value;
707
+
708
+ if ($li.is(acv(eds.bindObjectArrayStyle, objItem) + acv(eds.bindObjectArrayStyle, at))) eachTargetFor($li, eds.bindObjectArrayStyle, (targetItem, targetStyle, prefix = "", suffix = "") => {
709
+ if (targetItem == objItem) $li.css(targetStyle, prefix + styleValue + suffix);
710
+ });
711
+ $li.find(acv(eds.bindObjectArrayStyle, objItem) + acv(eds.bindObjectArrayStyle, at)).each((i, elem) => {
712
+ const $elem = $(elem);
713
+ eachTargetFor($elem, eds.bindObjectArrayStyle, (targetItem, targetStyle, prefix = "", suffix = "") => {
714
+ if (targetItem == objItem) $elem.css(targetStyle, prefix + styleValue + suffix);
715
+ });
716
+ });
717
+ }
718
+ }
719
+
720
+ if ($li.is(ax(eds.bindArrayItem))) $li.html(arrayItemValue);
721
+ if ($li.is(ax(eds.bindArrayAmount))) $li.html(v2a(arrayItemValue));
722
+ if ($li.is(ax(eds.bindArrayValue))) $li.val(arrayItemValue);
723
+ $li.find(ax(eds.bindArrayItem)).html(arrayItemValue);
724
+ $li.find(ax(eds.bindArrayAmount)).html(v2a(arrayItemValue));
725
+ $li.find(ax(eds.bindArrayValue)).val(arrayItemValue);
726
+
727
+ if ($li.is(ax(eds.bindArrayIndex))) $li.html(index);
728
+ if ($li.is(ax(eds.bindArrayIndexAmount))) $li.html(v2a(index));
729
+ if ($li.is(ax(eds.bindArrayIndexValue))) $li.val(index);
730
+ $li.find(ax(eds.bindArrayIndex)).html(index);
731
+ $li.find(ax(eds.bindArrayIndexAmount)).html(v2a(index));
732
+ $li.find(ax(eds.bindArrayIndexValue)).val(index);
733
+
734
+ if (valueIsObject) arrayItemValue = btoa(Jcodd.toCodd(arrayItemValue));
735
+
736
+
737
+ if ($li.is(ax(eds.bindArrayIndexAttr))) eachTarget($li, eds.bindArrayIndexAttr, (target, prefix = "", suffix = "") => {
738
+ $li.attr(target, prefix + index + suffix);
739
+ });
740
+ $li.find(ax(eds.bindArrayIndexAttr)).each((i, elem) => {
741
+ const $elem = $(elem);
742
+ eachTarget($elem, eds.bindArrayIndexAttr, (target, prefix = "", suffix = "") => {
743
+ $elem.attr(target, prefix + index + suffix);
744
+ });
745
+ });
746
+
747
+
748
+ if ($li.is(ax(eds.bindArrayAttr))) eachTarget($li, eds.bindArrayAttr, (target, prefix = "", suffix = "") => {
749
+ $li.attr(target, prefix + arrayItemValue + suffix);
750
+ });
751
+ $li.find(ax(eds.bindArrayAttr)).each((i, elem) => {
752
+ const $elem = $(elem);
753
+ eachTarget($elem, eds.bindArrayAttr, (target, prefix = "", suffix = "") => {
754
+ $elem.attr(target, prefix + arrayItemValue + suffix);
755
+ });
756
+ });
757
+
758
+ const styleArrayItemValue = isEmpty(value) ? "unset" : value;
759
+
760
+ if ($li.find(ax(eds.bindArrayStyle))) eachTarget($li, eds.bindArrayStyle, (target, prefix = "", suffix = "") => {
761
+ $li.css(target, prefix + styleArrayItemValue + suffix);
762
+ });
763
+ $li.find(ax(eds.bindArrayStyle)).each((i, elem) => {
764
+ const $elem = $(elem);
765
+ eachTarget($elem, eds.bindArrayStyle, (target, prefix = "", suffix = "") => {
766
+ $elem.css(target, prefix + styleArrayItemValue + suffix);
767
+ });
768
+ });
769
+ }
770
+
771
+
772
+ if ($li.is(ax(eds.showOnExistsObjectArrayItem))) {
773
+ if (isNully(arrayItem) || isNully(arrayItem[$li.attr(eds.showOnExistsObjectArrayItem)])) $li.css("display", "none");
774
+ else $li.css("display", "");
775
+ }
776
+ $li.find(ax(eds.showOnExistsObjectArrayItem)).each((i, elem) => {
777
+ if (isNully(arrayItem) || isNully(arrayItem[elem.dataset.showOnExistsObjectArrayItem])) $(elem).css("display", "none");
778
+ else $(elem).css("display", "");
779
+ });
780
+
781
+ if ($li.is(ax(eds.showOnNotExistsObjectArrayItem))) {
782
+ if (isNotNully(arrayItem) && isNotNully(arrayItem[$li.attr(eds.showOnNotExistsObjectArrayItem)])) $li.css("display", "none");
783
+ else $li.css("display", "");
784
+ }
785
+ $li.find(ax(eds.showOnNotExistsObjectArrayItem)).each((i, elem) => {
786
+ if (isNotNully(arrayItem) && isNotNully(arrayItem[elem.dataset.showOnNotExistsObjectArrayItem])) $(elem).css("display", "none");
787
+ else $(elem).css("display", "");
788
+ });
789
+
790
+ if ($li.is(acv(eds.showOnEqualsObjectArrayItem, "="))) {
791
+ const [objItem, matchValue] = $li.attr(eds.showOnEqualsObjectArrayItem).split("=");
792
+ if (isNully(arrayItem) || arrayItem[objItem] != matchValue) $li.css("display", "none");
793
+ else $li.css("display", "");
794
+ }
795
+ $li.find(acv(eds.showOnEqualsObjectArrayItem, "=")).each((i, elem) => {
796
+ const [objItem, matchValue] = elem.dataset.showOnEqualsObjectArrayItem.split("=");
797
+ if (isNully(arrayItem) || arrayItem[objItem] != matchValue) $(elem).css("display", "none");
798
+ else $(elem).css("display", "");
799
+ });
800
+ }
801
+ });
802
+ }
803
+
804
+ if ($host.is(ax(eds.showOnExists))) {
805
+ if (isNully(data) || isNully(data[$host.attr(eds.showOnExists)])) $host.css("display", "none");
806
+ else $host.css("display", "");
807
+ }
808
+ $host.find(ax(eds.showOnExists)).each((i, elem) => {
809
+ if (isNully(data) || isNully(data[elem.dataset.showOnExists])) $(elem).css("display", "none");
810
+ else $(elem).css("display", "");
811
+ });
812
+
813
+ if ($host.is(ax(eds.showOnNotExists))) {
814
+ if (isNotNully(data) && isNotNully(data[$host.attr(eds.showOnNotExists)])) $host.css("display", "none");
815
+ else $host.css("display", "");
816
+ }
817
+ $host.find(ax(eds.showOnNotExists)).each((i, elem) => {
818
+ if (isNotNully(data) && isNotNully(data[elem.dataset.showOnNotExists])) $(elem).css("display", "none");
819
+ else $(elem).css("display", "");
820
+ });
821
+
822
+ if ($host.is(acv(eds.showOnEquals, "="))) {
823
+ const [item, matchValue] = $host.attr(eds.showOnEquals).split("=");
824
+ if (isNully(data) || data[item] != matchValue) $host.css("display", "none");
825
+ }
826
+ $host.find(acv(eds.showOnEquals, "=")).each((i, elem) => {
827
+ const [item, matchValue] = elem.dataset.showOnEquals.split("=");
828
+ if (isNully(data) || data[item] != matchValue) $(elem).css("display", "none");
829
+ });
830
+ }
831
+ }
832
+
833
+ initSolidPoint($host = this.$host) {
834
+ const $solidPoint = $host.find(ax(eds.solid));
835
+
836
+ const points = [];
837
+ for (const point of $solidPoint) {
838
+ const val = point.dataset.solid;
839
+ if (isNotNullAndEmpty(val?.trim()) && !isNaN(val)) {
840
+ const priority = parseInt(val);
841
+ if (points[priority] == null) points[priority] = [];
842
+ points[priority].push(point);
843
+ }
844
+ }
845
+
846
+ for (const index of points.ways.reverse()) {
847
+ const pointSet = points[index];
848
+ if (pointSet != null) for (var i = pointSet.length - 1; i >= 0; i--) {
849
+ const point = pointSet[i];
850
+ if (isNullOrEmpty(point.dataset.frozen) && point.solid?.() != null) point.dataset.solid = "";
851
+ }
852
+ }
853
+ }
854
+
855
+ // local styler
856
+ initLocalStyle($host = this.$host) {
857
+ const $localStyles = $host.find("local-style");
858
+ for (const elem of $localStyles) LocalStyle.localize(elem);
859
+ }
860
+
861
+
862
+ // live element
863
+ initLiveElement($host = this.$host, replaceHandles = false) {
864
+ this.initHandles($host, replaceHandles);
865
+ this.initPassiveLinks($host);
866
+ this.initLottieLoaders($host);
867
+ }
868
+
869
+ releaseHandles($host = this.$host) {
870
+ if ($host != null) EstreHandle.releaseHandles($host, this);
871
+ }
872
+
873
+ initHandles($host = this.$host, replace = false) {
874
+ EstreHandle.initHandles($host, this, replace);
875
+ }
876
+
877
+ // passive links
878
+ initPassiveLinks($host = this.$host) {
879
+ this.initInternalLink($host);
880
+ this.initPageLink($host);
881
+ }
882
+
883
+ initInternalLink($host = this.$host) {
884
+ if ($host.is(ax(eds.openTarget) + ax(eds.openContainer) + ax(eds.openId))) this.setEventInternalLink($host[0]);
885
+ const $links = $host.find(ax(eds.openTarget) + ax(eds.openContainer) + ax(eds.openId));
886
+ for (const item of $links) this.setEventInternalLink(item);
887
+ }
888
+
889
+ initPageLink($host = this.$host) {
890
+ if ($host.is(ax(eds.closePage))) this.setEventPageCloseLink($host[0]);
891
+ const $closeLinks = $host.find(ax(eds.closePage));
892
+ for (const item of $closeLinks) this.setEventPageCloseLink(item);
893
+
894
+ if ($host.is(ax(eds.openPage))) this.setEventPageOpenLink($host[0]);
895
+ const $openLinks = $host.find(ax(eds.openPage));
896
+ for (const item of $openLinks) this.setEventPageOpenLink(item);
897
+
898
+ if ($host.is(ax(eds.showPage))) this.setEventPageShowLink($host[0]);
899
+ const $showLinks = $host.find(ax(eds.showPage));
900
+ for (const item of $showLinks) this.setEventPageShowLink(item);
901
+ }
902
+
903
+ initLottieLoaders($host = this.$host) {
904
+ const $loaders = $host.find(uis.dotlottieLoader);
905
+ for (const loader of $loaders) {
906
+ const player = doc.ce(dlp);
907
+ for (const { name, value } of loader.attributes) player.setAttribute(name, value);
908
+ loader.after(player);
909
+ loader.remove();
910
+ }
911
+ }
912
+
913
+
914
+ // event handlers
915
+ #internalLinkEvent = null;
916
+ #pageOpenLinkEvent = null;
917
+ #pageCloseLinkEvent = null;
918
+ #pageShowLinkEvent = null;
919
+
920
+ setEventInternalLink(item) {
921
+ const handle = this;
922
+
923
+ this.#internalLinkEvent ??= async function(e) {
924
+ e.preventDefault();
925
+
926
+ const $this = $(this);
927
+
928
+ const targetSet = $this.attr(eds.openTarget).split("@");
929
+ const target = targetSet.length < 2 ? "self" : targetSet[0];//$this.closest(se + uis.rootTabContent).attr("id")
930
+ const targetBound = targetSet[targetSet.length < 2 ? 0 : 1];
931
+ const container = $this.attr(eds.openContainer);
932
+ const id = $this.attr(eds.openId);
933
+ const action = $this.attr(eds.openAction)?.let(it => isEmpty(it) ? n : it);
934
+ const data = $this.attr(eds.openData)?.let(it => isEmpty(it) ? n : it.let(_ => {
935
+ try {
936
+ return Jcodd.parse(it);
937
+ } catch (exc) {
938
+ return Jcodd.parse(it.replace(/'/g, '"'));
939
+ }
940
+ }));
941
+ const bringOnBackPid = $this.attr(eds.openBringOnBack)?.let(it => isEmpty(it) ? n : it == t1 ? handle.pid : it);
942
+
943
+ let intent = nn(action) ? (nn(data) ? { data, action } : { action }) : nn(data) ? { data } : u;
944
+ if (nn(bringOnBackPid)) {
945
+ const bringOnBack = { pid: bringOnBackPid, hostType: container };
946
+ if (tu(intent)) intent = { bringOnBack };
947
+ else intent.bringOnBack = bringOnBack;
948
+ }
949
+ let pushedIntent = typeof intent == U;
950
+
951
+ switch (targetBound) {
952
+ case "root":
953
+ switch (container) {
954
+ case "component":
955
+ let component;
956
+ switch (handle.sectionBound) {
957
+ case "main":
958
+ if (pushedIntent) estreUi.switchRootTab(id);
959
+ else {
960
+ estreUi.switchRootTab(id, intent);
961
+ pushedIntent = true;
962
+ }
963
+ break;
964
+
965
+ case "blind":
966
+ component = estreUi.blindSections[id];
967
+ if (component == null) {
968
+ if (pushedIntent) estreUi.openInstantBlinded(id);
969
+ else {
970
+ estreUi.openInstantBlinded(id, intent);
971
+ pushedIntent = true;
972
+ }
973
+ component = estreUi.blindSections[id];
974
+ }
975
+ if (component != null) {
976
+ if (pushedIntent) estreUi.showInstantBlinded(id);
977
+ else estreUi.showInstantBlinded(id, intent);
978
+ }
979
+ break;
980
+
981
+ case "overlay":
982
+ component = estreUi.overlaySections[id];
983
+ if (component == null) {
984
+ if (pushedIntent) estreUi.openManagedOverlay(id);
985
+ else {
986
+ estreUi.openManagedOverlay(id, intent);
987
+ pushedIntent = true;
988
+ }
989
+ component = estreUi.overlaySections[id];
990
+ }
991
+ if (component != null) {
992
+ if (pushedIntent) estreUi.showManagedOverlay(id);
993
+ else estreUi.showManagedOverlay(id, intent);
994
+ }
995
+ break;
996
+
997
+ case "menu":
998
+ component = estreUi.menuSections[id];
999
+ if (component == null) {
1000
+ if (pushedIntent) estreUi.openMenuArea(id);
1001
+ else {
1002
+ estreUi.openMenuArea(id, intent);
1003
+ pushedIntent = true;
1004
+ }
1005
+ component = estreUi.menuSections[id];
1006
+ }
1007
+ if (component != null) {
1008
+ if (pushedIntent) estreUi.showMenuArea(id);
1009
+ else estreUi.showMenuArea(id, intent);
1010
+ }
1011
+ break;
1012
+
1013
+ case "header":
1014
+ component = estreUi.headerSections[id];
1015
+ if (component == null) {
1016
+ if (pushedIntent) estreUi.openHeaderBar(id);
1017
+ else {
1018
+ estreUi.openHeaderBar(id, intent);
1019
+ pushedIntent = true;
1020
+ }
1021
+ component = estreUi.headerSections[id];
1022
+ }
1023
+ if (component != null) {
1024
+ if (pushedIntent) estreUi.showHeaderBar(id);
1025
+ else estreUi.showHeaderBar(id, intent);
1026
+ }
1027
+ break;
1028
+ }
1029
+ break;
1030
+ }
1031
+ break;
1032
+
1033
+ case "component":
1034
+ switch (container) {
1035
+ case "container":
1036
+ const isSelf = target == "self";
1037
+ const thisComponent = handle.container.component;
1038
+ let component;
1039
+ if (isSelf) component = thisComponent;
1040
+ else switch (thisComponent.sectionBound) {
1041
+ case "main":
1042
+ component = estreUi.mainSections[target];
1043
+ if (component == null) {
1044
+ //estreUi.switchRootTab(target);
1045
+ component = estreUi.mainSections[target];
1046
+ }
1047
+ break;
1048
+
1049
+ case "blind":
1050
+ component = estreUi.blindSections[target];
1051
+ if (component == null) {
1052
+ estreUi.openInstantBlinded(target);
1053
+ component = estreUi.blindSections[target];
1054
+ }
1055
+ break;
1056
+
1057
+ case "overlay":
1058
+ component = estreUi.overlaySections[target];
1059
+ if (component == null) {
1060
+ estreUi.openManagedOverlay(target);
1061
+ component = estreUi.overlaySections[target];
1062
+ }
1063
+ break;
1064
+
1065
+ case "menu":
1066
+ component = estreUi.menuSections[target];
1067
+ if (component == null) {
1068
+ estreUi.openMenuArea(target);
1069
+ component = estreUi.menuSections[target];
1070
+ }
1071
+ break;
1072
+
1073
+ case "header":
1074
+ component = estreUi.headerSections[target];
1075
+ if (component == null) {
1076
+ estreUi.openHeaderBar(target);
1077
+ component = estreUi.headerSections[target];
1078
+ }
1079
+ break;
1080
+ }
1081
+ if (component != null) {
1082
+ let targetContainer = component.containers[id];
1083
+ if (targetContainer == null) {
1084
+ if (pushedIntent) component.openContainer(id);
1085
+ else {
1086
+ component.openContainer(id, intent);
1087
+ pushedIntent = true;
1088
+ }
1089
+ targetContainer = component.containers[id];
1090
+ }
1091
+ if (targetContainer != null) {
1092
+ let success = pushedIntent ? targetContainer.show() : component.showContainer(id, intent);
1093
+ if (success && !isSelf) switch (component.sectionBound) {
1094
+ case "main":
1095
+ estreUi.switchRootTab(target);
1096
+ break;
1097
+
1098
+ case "blind":
1099
+ estreUi.showInstantBlinded(target);
1100
+ break;
1101
+
1102
+ case "overlay":
1103
+ estreUi.showManagedOverlay(target);
1104
+ break;
1105
+
1106
+ case "menu":
1107
+ estreUi.showMenuArea(target);
1108
+ break;
1109
+
1110
+ case "header":
1111
+ estreUi.showHeaderBar(target);
1112
+ break;
1113
+ }
1114
+ }
1115
+ }
1116
+ break;
1117
+ }
1118
+ break;
1119
+
1120
+ case "container":
1121
+ switch (container) {
1122
+ case "article":
1123
+ const isSelf = target == "self";
1124
+ const component = handle.container.component;
1125
+ let targetContainer = isSelf ? handle.container : component.containers[target];
1126
+ if (targetContainer == null) {
1127
+ component.openContainer(target);
1128
+ targetContainer = component.containers[target];
1129
+ }
1130
+ if (targetContainer != null) {
1131
+ let article = targetContainer.articles[id];
1132
+ if (article == null) {
1133
+ if (pushedIntent) targetContainer.openArticle(id);
1134
+ else {
1135
+ targetContainer.openArticle(id, intent);
1136
+ pushedIntent = true;
1137
+ }
1138
+ article = targetContainer.articles[id];
1139
+ }
1140
+ if (article != null) {
1141
+ let success = pushedIntent ? article.show() : targetContainer.showArticle(id, intent);
1142
+ if (success) targetContainer.show();
1143
+ }
1144
+ }
1145
+ break;
1146
+ }
1147
+ break;
1148
+
1149
+ }
1150
+
1151
+ return false;
1152
+ };
1153
+
1154
+ $(item).off("click", this.#internalLinkEvent).click(this.#internalLinkEvent);
1155
+ }
1156
+
1157
+ setEventPageOpenLink(item) {
1158
+ const handle = this;
1159
+
1160
+ this.#pageOpenLinkEvent ??= function(e) {
1161
+ e.stopPropagation();
1162
+
1163
+ const $this = $(this);
1164
+
1165
+ const pid = $this.attr(eds.openPage);
1166
+ const action = $this.attr(eds.openAction)?.let(it => isEmpty(it) ? n : it);
1167
+ const data = $this.attr(eds.openData)?.let(it => isEmpty(it) ? n : it.let(_ => {
1168
+ try {
1169
+ return Jcodd.parse(it);
1170
+ } catch (exc) {
1171
+ return Jcodd.parse(it.replace(/'/g, '"'));
1172
+ }
1173
+ }));
1174
+ const bringOnBackPid = $this.attr(eds.openBringOnBack)?.let(it => isEmpty(it) ? n : it == t1 ? handle.pid : it);
1175
+
1176
+ let intent = nn(action) ? (nn(data) ? { data, action } : { action }) : nn(data) ? { data } : u;
1177
+ if (nn(bringOnBackPid)) {
1178
+ const bringOnBack = { pid: bringOnBackPid };
1179
+ if (tu(intent)) intent = { bringOnBack };
1180
+ else intent.bringOnBack = bringOnBack;
1181
+ }
1182
+ let intentReady = typeof intent != UNDEFINED;
1183
+
1184
+ if (intentReady) pageManager.bringPage(pid, intent);
1185
+ else pageManager.bringPage(pid);
1186
+ };
1187
+
1188
+ $(item).off("click", this.#pageOpenLinkEvent).click(this.#pageOpenLinkEvent);
1189
+ }
1190
+
1191
+ setEventPageShowLink(item) {
1192
+ const handle = this;
1193
+
1194
+ this.#pageShowLinkEvent ??= function(e) {
1195
+ e.stopPropagation();
1196
+
1197
+ const $this = $(this);
1198
+
1199
+ const pid = $this.attr(eds.showPage);
1200
+ const action = $this.attr(eds.showAction)?.let(it => isEmpty(it) ? n : it);
1201
+ const data = $this.attr(eds.showData)?.let(it => isEmpty(it) ? n : it.let(_ => {
1202
+ try {
1203
+ return Jcodd.parse(it);
1204
+ } catch (exc) {
1205
+ return Jcodd.parse(it.replace(/'/g, '"'));
1206
+ }
1207
+ }));
1208
+ const bringOnBackPid = $this.attr(eds.showBringOnBack)?.let(it => isEmpty(it) ? n : it == t1 ? handle.pid : it);
1209
+
1210
+ let intent = nn(action) ? (nn(data) ? { data, action } : { action }) : nn(data) ? { data } : u;
1211
+ if (nn(bringOnBackPid)) {
1212
+ const bringOnBack = { pid: bringOnBackPid };
1213
+ if (tu(intent)) intent = { bringOnBack };
1214
+ else intent.bringOnBack = bringOnBack;
1215
+ }
1216
+ let intentReady = typeof intent != UNDEFINED;
1217
+
1218
+ if (intentReady) pageManager.showPage(pid, intent);
1219
+ else pageManager.showPage(pid);
1220
+ };
1221
+
1222
+ $(item).off("click", this.#pageShowLinkEvent).click(this.#pageShowLinkEvent);
1223
+ }
1224
+
1225
+ setEventPageCloseLink(item) {
1226
+ this.#pageCloseLinkEvent ??= function(e) {
1227
+ e.stopPropagation();
1228
+
1229
+ const $this = $(this);
1230
+
1231
+ const pid = $this.attr(eds.closePage);
1232
+
1233
+ pageManager.closePage(pid);
1234
+ };
1235
+
1236
+ $(item).off("click", this.#pageCloseLinkEvent).click(this.#pageCloseLinkEvent);
1237
+ }
1238
+ }
1239
+
1240
+
1241
+ /**
1242
+ * Page host's handle (page handles sub pages)
1243
+ */
1244
+ class EstrePageHostHandle extends EstrePageHandle {
1245
+
1246
+ get title() { return this.currentOnTop?.title ?? this.$host?.attr(eds.title); }
1247
+
1248
+ // get appbarLeft() { return val(this.currentOnTop?.appbarLeft, it => tu(it) ? super.appbarLeft : it); }
1249
+ // set appbarLeft(value) { super.appbarLeft = value; }
1250
+ // get appbarRight() { return val(this.currentOnTop?.appbarRight, it => tu(it) ? super.appbarRight : it); }
1251
+ // set appbarRight(value) { super.appbarRight = value; }
1252
+ // get appbarCenter() { return val(this.currentOnTop?.appbarCenter, it => tu(it) ? super.appbarCenter : it); }
1253
+ // set appbarCenter(value) { super.appbarCenter = value; }
1254
+ get isAppbarLeftAssigned() { return this.currentOnTop?.isAppbarLeftAssigned || super.isAppbarLeftAssigned; }
1255
+ get isAppbarRightAssigned() { return this.currentOnTop?.isAppbarRightAssigned || super.isAppbarRightAssigned; }
1256
+ get isAppbarCenterAssigned() { return this.currentOnTop?.isAppbarCenterAssigned || super.isAppbarCenterAssigned; }
1257
+ get appbarLeftFeed() { return this.currentOnTop?.isAppbarLeftAssigned ? this.currentOnTop?.appbarLeftFeed : super.appbarLeftFeed; }
1258
+ get appbarRightFeed() { return this.currentOnTop?.isAppbarRightAssigned ? this.currentOnTop?.appbarRightFeed : super.appbarRightFeed; }
1259
+ get appbarCenterFeed() { return this.currentOnTop?.isAppbarCenterAssigned ? this.currentOnTop?.appbarCenterFeed : super.appbarCenterFeed; }
1260
+
1261
+ get subPages() { return {}; }
1262
+ get subPageList() { return []; }
1263
+ get $subPages() { return $(); }
1264
+ get $subPage() { return {}; }
1265
+
1266
+ get isSingleSubPage() { return this.$subPages.length === 1; }
1267
+ get isMultiSubPages() { return this.$subPages.length > 1; }
1268
+
1269
+ get currentTop() { return this.currentOnTop ?? this.subPageList.at(-1); }
1270
+
1271
+ #prevSubPageIds = new Set();
1272
+ get latestSubPageId() { return [...this.#prevSubPageIds].pop(); }
1273
+ get prevSubPageId() {
1274
+ const subPageIds = this.subPages.ways;
1275
+ let latestSubPageId = null;
1276
+ while (latestSubPageId = this.latestSubPageId) {
1277
+ this.#prevSubPageIds.delete(latestSubPageId);
1278
+ if (subPageIds.includes(latestSubPageId)) return latestSubPageId;
1279
+ }
1280
+ return null;
1281
+ };
1282
+ set prevSubPageId(id) {
1283
+ if (id == null) return;
1284
+ if (this.#prevSubPageIds.has(id)) this.#prevSubPageIds.delete(id);
1285
+ this.#prevSubPageIds.add(id);
1286
+ };
1287
+
1288
+ get isAvailablePrevSubPage() {
1289
+ const latestSubPageId = this.latestSubPageId;
1290
+ return latestSubPageId != null && this.subPages[latestSubPageId] != null;
1291
+ }
1292
+
1293
+
1294
+ initSubPages(intent) {
1295
+
1296
+ }
1297
+
1298
+ registerSubPage(element, intent) {
1299
+
1300
+ }
1301
+
1302
+ unregisterSubPage(pageHandle) {
1303
+
1304
+ }
1305
+
1306
+
1307
+ showSubPage(id, intent, instanceOrigin) {
1308
+ return false;
1309
+ }
1310
+
1311
+ openSubPage(id, intent, instanceOrigin) {
1312
+ return false;
1313
+ }
1314
+
1315
+ bringSubPage(id, intent, instanceOrigin) {
1316
+ return false;
1317
+ }
1318
+
1319
+ closeSubPage(id, instanceOrigin, isTermination = false) {
1320
+
1321
+ }
1322
+
1323
+ terminate() {
1324
+
1325
+ }
1326
+
1327
+ close(isTermination = false) {
1328
+ return super.close(isTermination);
1329
+ }
1330
+
1331
+ focus() {
1332
+ const processed = super.focus();
1333
+ let subPageProcessed = false;
1334
+ if (this.isFocused) subPageProcessed = this.currentTop?.focus();
1335
+ return processed || subPageProcessed;
1336
+ }
1337
+
1338
+ }
1339
+
1340
+
1341
+ /**
1342
+ * Component page handle for main sections & menu sections
1343
+ */
1344
+ class EstreComponent extends EstrePageHostHandle {
1345
+ // constants
1346
+ hostType = "component";
1347
+ get sectionBound() { return "main" };
1348
+
1349
+ // class property
1350
+ static components = {};
1351
+ static componentList = [];
1352
+
1353
+
1354
+ // static methods;
1355
+ static register(component) {
1356
+ const registered = EstreUiPage.registerOrCommitFrom(component);
1357
+ if (registered === false) return false;
1358
+ this.unregister(component);
1359
+ this.componentList.push(component);
1360
+ this.components[component.instanceId] = component;
1361
+ return registered;
1362
+ }
1363
+
1364
+ static unregister(component) {
1365
+ const instanceId = component.instanceId;
1366
+ if (this.components[instanceId] != null) delete this.components[instanceId];
1367
+ const index = this.componentList.indexOf(component);
1368
+ if (index > -1) this.componentList.splice(index, 1);
1369
+ return EstreUiPage.unregisterFrom(component);
1370
+ }
1371
+
1372
+
1373
+ // instance property
1374
+ get isCanBack() { switch (this.sectionBound) {
1375
+ case "main":
1376
+ const latestRootTabId = estreUi.latestRootTabId;
1377
+ return !this.isHome && ((latestRootTabId != null && estreUi.mainSections[latestRootTabId] != null) || estreUi.mainSections["home"] != null);
1378
+
1379
+ case "blind":
1380
+ case "menu":
1381
+ case "overlay":
1382
+ case "header":
1383
+ return false;
1384
+ }
1385
+ }
1386
+
1387
+ get subPages() { return this.containers; }
1388
+ get subPageList() { return this.containerList; }
1389
+ get $subPages() { return this.$containers; }
1390
+ get $subPage() { return this.$container; }
1391
+
1392
+ containers = {};
1393
+ containerList = [];
1394
+ get $containers() { return this.$host?.find(c.c + uis.container); };
1395
+ $container = {};
1396
+
1397
+ get rootContainer() { return this.containers.root; }
1398
+ get mainArticle() { return this.rootContainer?.mainArticle; }
1399
+
1400
+ get isSingleContainer() { return this.isSingleSubPage; }
1401
+ get isMultiContainer() { return this.isMultiSubPages; }
1402
+
1403
+ get isAvailableRootContainer() { return this.rootContainer != null; }
1404
+ get isExistBackContainer() { return this.isMultiSubPages && (this.isAvailablePrevSubPage || ((this.currentTop?.isSub ?? false) && this.isAvailableRootContainer)); }
1405
+
1406
+ get isContainersAllyStatic() {
1407
+ for (var container of this.containerList) if (!container.isStatic) return false;
1408
+ return true;
1409
+ }
1410
+
1411
+ get $articles() { return this.$host.find(c.c + uis.container + c.c + uis.article); };
1412
+
1413
+ get isHome() { return this.id == "home" || this.$host.hasClass("home"); }
1414
+
1415
+ constructor(component, instanceOrigin) {
1416
+ super(component, instanceOrigin);
1417
+ this.id = component.id;
1418
+ }
1419
+
1420
+ release(remove) {
1421
+
1422
+ this.unregister();
1423
+
1424
+ return super.release(remove);
1425
+ }
1426
+
1427
+ init(intent) {
1428
+ const page = this.register();
1429
+ if (page === false) return true;
1430
+
1431
+ super.init(page, intent);
1432
+
1433
+ this.initContainers(intent);
1434
+
1435
+ return this;
1436
+ }
1437
+
1438
+ register() {
1439
+ return EstreComponent.register(this);
1440
+ }
1441
+
1442
+ unregister() {
1443
+ EstreComponent.unregister(this);
1444
+ }
1445
+
1446
+
1447
+ initSubPages(intent) {
1448
+ return this.initContainers(intent);
1449
+ }
1450
+
1451
+ registerSubPage(element, intent, instanceOrigin) {
1452
+ return this.registerContainer(element, intent, instanceOrigin);
1453
+ }
1454
+
1455
+ unregisterSubPage(pageHandle) {
1456
+ return this.unregisterConatiner(pageHandle);
1457
+ }
1458
+
1459
+ initContainers(intent) {
1460
+ for (var container of this.$containers) {
1461
+ const $container = $(container);
1462
+ this.$container[$container.attr(eds.containerId)] = $container;
1463
+ this.registerContainer(container, intent);
1464
+ }
1465
+
1466
+ let $top = this.$containers.filter(asv(eds.onTop, t1));
1467
+ if ($top.length < 1) $top = this.$containers.filter(aiv(eds.containerId, "root"));
1468
+ if ($top.length < 1) $top = this.$containers;
1469
+ $top[$top.length - 1]?.pageHandle?.show(false, false);
1470
+ }
1471
+
1472
+ registerContainer(element, intent, instanceOrigin) {
1473
+ this.unregisterConatiner(element.pageHandle);
1474
+ const container = new EstreContainer(element, this, instanceOrigin);
1475
+ const instanceId = container.instanceId;
1476
+ this.$container[instanceId] = container.$host;
1477
+ this.containers[instanceId] = container;
1478
+ this.containerList.push(container);
1479
+ const registered = EstreUiPage.registerOrCommitFrom(container);
1480
+ container.init(registered, intent);
1481
+ //if (container.isOnTop) container.show(false, false);
1482
+ return container;
1483
+ }
1484
+
1485
+ unregisterConatiner(container) {
1486
+ if (container == null) return;
1487
+ const instanceId = container.instanceId;
1488
+ const unregitered = EstreUiPage.unregisterFrom(container);
1489
+ container.release(!container.isStatic ? true : null);
1490
+ if (this.$container[instanceId] != null) delete this.$container[instanceId];
1491
+ if (this.containers[instanceId] != null) delete this.containers[instanceId];
1492
+ const index = this.containerList.indexOf(container);
1493
+ if (index > -1) this.containerList.splice(index, 1);
1494
+ return unregitered;
1495
+ }
1496
+
1497
+
1498
+ // handles
1499
+ showSubPage(id, intent, instanceOrigin) {
1500
+ return this.showContainer(id, intent, instanceOrigin);
1501
+ }
1502
+
1503
+ openSubPage(id, intent, instanceOrigin) {
1504
+ return this.openContainer(id, intent, instanceOrigin);
1505
+ }
1506
+
1507
+ bringSubPage(id, intent, instanceOrigin) {
1508
+ return this.bringContainer(id, intent, instanceOrigin);
1509
+ }
1510
+
1511
+ closeSubPage(id, instanceOrigin, isTermination = false) {
1512
+ return this.closeContainer(id, instanceOrigin, isTermination);
1513
+ }
1514
+
1515
+ showContainer(id, intent, instanceOrigin) {
1516
+ if (id != null && !this.isClosing) {
1517
+ const show = container => {
1518
+ const currentTopHandle = this.currentTop;
1519
+ const currentTopHandleId = currentTopHandle.instanceId;
1520
+ if (id != currentTopHandleId && currentTopHandleId != this.latestSubPageId) {
1521
+ this.prevSubPageId = currentTopHandleId;
1522
+
1523
+ // if (estreUi.euiState == "onReady" && currentTopHandle != null) switch (currentTopHandle.sectionBound) {
1524
+ // case "blind":
1525
+ // case "menu":
1526
+ // case "main":
1527
+ // estreUi.pushCurrentState(currentTopHandle);
1528
+ // break;
1529
+ // }
1530
+ }
1531
+ for (var current of this.containerList) if (current.isOnTop && current != container) {
1532
+ current.hide();
1533
+ }
1534
+ container.pushIntent(intent);
1535
+ container.show(false);
1536
+ this.currentOnTop = container;
1537
+
1538
+ switch (this.sectionBound) {
1539
+ case "menu":
1540
+ case "main":
1541
+ estreUi.showExactAppbar(this, container);
1542
+ break;
1543
+ }
1544
+ return true;
1545
+ };
1546
+
1547
+ const container = this.containers[id + (instanceOrigin?.let(it => "^" + it) ?? "")];
1548
+ if (container != null) return show(container);
1549
+ else if (instanceOrigin == n) {
1550
+ const containerIds = this.containers.ways.filter(it => it.startsWith(id + "^"));
1551
+ if (containerIds.length > 0) {
1552
+ const containerId = containerIds[containerIds.length - 1];
1553
+ const container = this.containers[containerId];
1554
+ if (container != null) return show(container);
1555
+ }
1556
+ }
1557
+ }
1558
+ return false;
1559
+ }
1560
+
1561
+ openContainer(id, intent, instanceOrigin) {
1562
+ if (this.isClosing) return false;
1563
+ const page = pageManager.getContainer(id, this.id, this.sectionBound);
1564
+ if (page == null) return null;
1565
+ if (page.statement == "static") return null;
1566
+ this.$host.append(page.live);
1567
+ const $container = this.$containers.filter(aiv(eds.containerId, id));
1568
+ if ($container == null || $container.length < 1) return null;
1569
+ return this.registerContainer($container[$container.length - 1], intent, instanceOrigin);
1570
+ }
1571
+
1572
+ closeContainer(id, instanceOrigin, isTermination = false) {
1573
+ if (id != null) {
1574
+ const close = container => {
1575
+ const task = container.close(false, isTermination || !container.isStatic);
1576
+ if (!isTermination && !this.isClosing) postAsyncQueue(async _ => {
1577
+ if (this.isClosing) return;
1578
+ const target = this.subPages[id];
1579
+ const subPageList = this.subPageList.filter(it => !it.isClosing && it != target);
1580
+ if (subPageList.length > 0) {
1581
+ const prev = this.prevSubPageId;
1582
+ if (prev != null) this.showSubPage(prev);
1583
+ else subPageList[subPageList.length - 1].show();
1584
+ } else {
1585
+ await task;
1586
+ if (!this.isClosing && !this.isStatic && subPageList.length < 1) this.close(true, true);
1587
+ };
1588
+ });
1589
+ return postAsyncQueue(async _ => {
1590
+ const result = await task;
1591
+ if (isTermination || !container.isStatic) this.unregisterConatiner(container);
1592
+ return result;
1593
+ });
1594
+ };
1595
+
1596
+ const container = this.containers[id + (instanceOrigin?.let(it => "^" + it) ?? "")];
1597
+ if (container != null) return close(container);
1598
+ else if (instanceOrigin == n) {
1599
+ const containerIds = this.containers.ways.filter(it => it.startsWith(id + "^"));
1600
+ if (containerIds.length > 0) {
1601
+ const containerId = containerIds[containerIds.length - 1];
1602
+ const container = this.containers[containerId];
1603
+ return close(container);
1604
+ }
1605
+ }
1606
+ }
1607
+ return null;
1608
+ }
1609
+
1610
+ bringContainer(id, intent, instanceOrigin) {
1611
+ if (this.containers[id] == null) {
1612
+ if (this.openContainer(id, intent, instanceOrigin)) return this.showContainer(id, u, instanceOrigin);
1613
+ else return false;
1614
+ } else return this.showContainer(id, intent, instanceOrigin);
1615
+ }
1616
+
1617
+ onCloseContainer() {
1618
+ return this.currentOnTop?.close();
1619
+ }
1620
+
1621
+ show(isRequest = true, setFocus = true) {
1622
+ if (isRequest) {
1623
+ return estreUi.switchRootTab(estreUi.$rootTabs.filter(aiv(eds.tabId, this.id)));
1624
+ } else return super.show(false, setFocus);
1625
+ }
1626
+
1627
+ // focus() {
1628
+ // if (this.isShowing) {
1629
+ // const $containers = this.$containers;
1630
+ // let $top = $containers.filter(asv(eds.onTop, t1));
1631
+ // var $targetContainer = null;
1632
+ // if ($top != null) $targetContainer = $top;
1633
+ // else if ($containers.length > 0) $targetContainer = $($containers[$containers.length-1]);
1634
+
1635
+ // let processed = false;
1636
+ // if ($targetContainer != null) {
1637
+ // processed = $targetContainer[$targetContainer.length - 1]?.pageHandle?.focus();
1638
+ // }
1639
+
1640
+ // super.focus();
1641
+
1642
+ // return processed;
1643
+ // } else false;
1644
+ // }
1645
+
1646
+ back(isRequest = true) {
1647
+ return super.back(isRequest);// || (this.sectionBound == "main" && this.isShowing && this.id != "home" && estreUi.switchRootTab("home"));
1648
+ }
1649
+
1650
+ blur() {
1651
+ super.blur()
1652
+
1653
+ const $containers = this.$containers;
1654
+ let $top = $containers.filter(asv(eds.onTop, t1));
1655
+ var $targetContainer = null;
1656
+ if ($top != null && $top.length > 0) $targetContainer = $top;
1657
+ else if ($containers.length > 0) $targetContainer = $($containers[$containers.length-1]);
1658
+
1659
+ if ($targetContainer != null) return postAsyncQueue(async _ => {
1660
+ var processed = false
1661
+ for (var container of $targetContainer) processed |= await container.pageHandle?.blur();
1662
+ return processed;
1663
+ });
1664
+ else return false;
1665
+ }
1666
+
1667
+ close(isRequest = true, isTermination = !this.isStatic) {
1668
+ if (isRequest) {
1669
+ if (this.isModal) {
1670
+ return this.onTop ? estreUi.closeModalTab(this.id, this.$host) : false;
1671
+ } else return false;
1672
+ } else return super.close(isTermination);
1673
+ }
1674
+
1675
+
1676
+ onShow() {
1677
+ const processed = super.onShow();
1678
+ let $top = this.$containers.filter(asv(eds.onTop, t1));
1679
+ if ($top.length < 1) $top = this.$containers;
1680
+ const container = $top[$top.length - 1]?.pageHandle;
1681
+ if (container != null) {
1682
+ container.onShow();
1683
+ this.currentOnTop = container;
1684
+ // container.onFocus();
1685
+ }
1686
+ return processed;
1687
+ }
1688
+
1689
+ async onHide() {
1690
+ if (this.$containers != n) {
1691
+ let $top = this.$containers.filter(asv(eds.onTop, t1));
1692
+ if ($top.length < 1) $top = this.$containers;
1693
+ const container = $top[$top.length - 1]?.pageHandle;
1694
+ if (container != null) {
1695
+ await container.onBlur();
1696
+ await container.onHide();
1697
+ }
1698
+ }
1699
+ return await super.onHide();
1700
+ }
1701
+
1702
+ async onClose(isTermination = false, isOnRelease = false) {
1703
+ const closer = [];
1704
+
1705
+ for (var container of this.containerList.reverse()) closer.push(container.close(true, isTermination));
1706
+
1707
+ await Promise.all(closer);
1708
+
1709
+ return await super.onClose(isTermination, isOnRelease);
1710
+ }
1711
+ }
1712
+
1713
+
1714
+
1715
+ /**
1716
+ * Component page handle for menu sections
1717
+ */
1718
+ class EstreMenuComponent extends EstreComponent {
1719
+ // constants
1720
+ get sectionBound() { return "menu"; };
1721
+
1722
+ // class property
1723
+ static components = {};
1724
+ static componentList = [];
1725
+
1726
+
1727
+ // static methods
1728
+
1729
+
1730
+
1731
+ // instance property
1732
+
1733
+
1734
+
1735
+
1736
+ constructor(component, instanceOrigin) {
1737
+ super(component, instanceOrigin);
1738
+ }
1739
+
1740
+ release(remove) {
1741
+
1742
+
1743
+ return super.release(remove);
1744
+ }
1745
+
1746
+ init(intent) {
1747
+
1748
+
1749
+ super.init(intent);
1750
+
1751
+
1752
+
1753
+ return this;
1754
+ }
1755
+
1756
+ register() {
1757
+ return EstreMenuComponent.register(this);
1758
+ }
1759
+
1760
+ unregister() {
1761
+ EstreMenuComponent.unregister(this);
1762
+ }
1763
+
1764
+ show(isRequest = true, setFocus = true) {
1765
+ if (isRequest) {
1766
+ return estreUi.showMenuArea(this.id);
1767
+ } else super.show(false, setFocus);
1768
+ }
1769
+
1770
+ close(isRequest = true, isTermination = !this.isStatic) {
1771
+ if (isRequest) {
1772
+ return estreUi.closeMenuArea(this.id, this.instanceOrigin, isTermination);
1773
+ } else return super.close(false, isTermination);
1774
+ }
1775
+ }
1776
+
1777
+
1778
+
1779
+ /**
1780
+ * Component page handle for header sections
1781
+ */
1782
+ class EstreHeaderComponent extends EstreComponent {
1783
+ // constants
1784
+ get sectionBound() { return "header"; };
1785
+
1786
+ // class property
1787
+ static components = {};
1788
+ static componentList = [];
1789
+
1790
+
1791
+ // static methods
1792
+
1793
+
1794
+
1795
+ // instance property
1796
+
1797
+
1798
+
1799
+
1800
+ constructor(component, instanceOrigin) {
1801
+ super(component, instanceOrigin);
1802
+ }
1803
+
1804
+ release(remove) {
1805
+
1806
+
1807
+ return super.release(remove);
1808
+ }
1809
+
1810
+ init(intent) {
1811
+
1812
+
1813
+ super.init(intent);
1814
+
1815
+
1816
+
1817
+ return this;
1818
+ }
1819
+
1820
+ register() {
1821
+ return EstreHeaderComponent.register(this);
1822
+ }
1823
+
1824
+ unregister() {
1825
+ EstreHeaderComponent.unregister(this);
1826
+ }
1827
+
1828
+ show(isRequest = true, setFocus = true) {
1829
+ if (isRequest) {
1830
+ return estreUi.showHeaderBar(this.id);
1831
+ } else super.show(false, setFocus);
1832
+ }
1833
+
1834
+ close(isRequest = true, isTermination = !this.isStatic) {
1835
+ if (isRequest) {
1836
+ return estreUi.closeHeaderBar(this.id, this.instanceOrigin, isTermination);
1837
+ } else return super.close(false, isTermination);
1838
+ }
1839
+ }
1840
+
1841
+
1842
+
1843
+ /**
1844
+ * Component page handle for blinded sections
1845
+ */
1846
+ class EstreInstantComponent extends EstreComponent {
1847
+ // constants
1848
+ get sectionBound() { return "blind"; };
1849
+
1850
+ // class property
1851
+ static components = {};
1852
+ static componentList = [];
1853
+
1854
+
1855
+ // static methods
1856
+
1857
+
1858
+
1859
+ // instance property
1860
+
1861
+
1862
+
1863
+
1864
+ constructor(component, instanceOrigin) {
1865
+ super(component, instanceOrigin);
1866
+ }
1867
+
1868
+ release(remove) {
1869
+
1870
+
1871
+ return super.release(remove);
1872
+ }
1873
+
1874
+ init(intent) {
1875
+
1876
+
1877
+ super.init(intent);
1878
+
1879
+
1880
+
1881
+ return this;
1882
+ }
1883
+
1884
+ register() {
1885
+ return EstreInstantComponent.register(this);
1886
+ }
1887
+
1888
+ unregister() {
1889
+ EstreInstantComponent.unregister(this);
1890
+ }
1891
+
1892
+ show(isRequest = true, setFocus = true) {
1893
+ if (isRequest) {
1894
+ return estreUi.showInstantBlinded(this.id);
1895
+ } else super.show(false, setFocus);
1896
+ }
1897
+
1898
+ close(isRequest = true, isTermination = !this.isStatic) {
1899
+ if (isRequest) {
1900
+ return estreUi.closeInstantBlinded(this.id, this.instanceOrigin, isTermination);
1901
+ } else return super.close(false, isTermination);
1902
+ }
1903
+ }
1904
+
1905
+
1906
+
1907
+ /**
1908
+ * Component page handle for managed overlay sections
1909
+ */
1910
+ class EstreOverlayComponent extends EstreInstantComponent {
1911
+ // constants
1912
+ get sectionBound() { return "overlay"; };
1913
+
1914
+ // class property
1915
+ static components = {};
1916
+ static componentList = [];
1917
+
1918
+
1919
+ // static methods
1920
+
1921
+
1922
+
1923
+ // instance property
1924
+
1925
+
1926
+
1927
+
1928
+ constructor(component, instanceOrigin) {
1929
+ super(component, instanceOrigin);
1930
+ }
1931
+
1932
+ release(remove) {
1933
+
1934
+
1935
+ return super.release(remove);
1936
+ }
1937
+
1938
+ init(intent) {
1939
+
1940
+
1941
+ super.init(intent);
1942
+
1943
+
1944
+
1945
+ return this;
1946
+ }
1947
+
1948
+ register() {
1949
+ return EstreOverlayComponent.register(this);
1950
+ }
1951
+
1952
+ unregister() {
1953
+ EstreOverlayComponent.unregister(this);
1954
+ }
1955
+
1956
+ show(isRequest = true, setFocus = true) {
1957
+ if (isRequest) {
1958
+ return estreUi.showManagedOverlay(this.id);
1959
+ } else super.show(false, setFocus);
1960
+ }
1961
+
1962
+ close(isRequest = true, isTermination = !this.isStatic) {
1963
+ if (isRequest) {
1964
+ return estreUi.closeManagedOverlay(this.id, this.instanceOrigin, isTermination);
1965
+ } else return super.close(false, isTermination);
1966
+ }
1967
+ }
1968
+
1969
+
1970
+ /**
1971
+ * Container page handle
1972
+ */
1973
+ class EstreContainer extends EstrePageHostHandle {
1974
+
1975
+ hostType = "container";
1976
+
1977
+ get sectionBound() { return this.component.sectionBound; }
1978
+
1979
+ component = null;
1980
+
1981
+ #articleStepsId = null;
1982
+
1983
+ #$stepNavigation = null;
1984
+ #$stepNavTitleName = null;
1985
+ #$stepIndicator = null;
1986
+ get #$stepPointers() { return this.#$stepIndicator.find(c.c + uis.stepPointer); }
1987
+ get #$stepDividers() { return this.#$stepIndicator.find(c.c + uis.stepDivider); }
1988
+
1989
+ #$masterFloat = null;
1990
+ #$masterFloatPad = null;
1991
+ #$masterButton = null;
1992
+ #$masterButtonTitle = null;
1993
+
1994
+ #onMasterButtonClick = null;
1995
+
1996
+ get isFullyStatic() { return this.component.isFullyStatic && this.isStatic; }
1997
+
1998
+ get isCanBack() { return this.component.isExistBackContainer; }
1999
+
2000
+ get isRoot() { return this.id == "root"; }
2001
+ get isSub() { return this.id != "root"; }
2002
+ get isStepNavigation() { return this.$host.hasClass("v_stack") || this.$host.hasClass("h_stack"); }
2003
+
2004
+ get subPages() { return this.articles; }
2005
+ get subPageList() { return this.articleList; }
2006
+ get $subPages() { return this.$articles; }
2007
+ get $subPage() { return this.$article; }
2008
+
2009
+ articles = {};
2010
+ articleList = [];
2011
+ get $articles() { return this.$host?.find(c.c + ar); };
2012
+ $article = {};
2013
+
2014
+ get mainArticle() { return this.articles.main; }
2015
+
2016
+ get isSingleArticle() { return this.isSingleSubPage; }
2017
+ get isMultiArticle() { return this.isMultiSubPages; }
2018
+
2019
+ get isAvailableMainArticle() { return this.mainArticle != null; }
2020
+ get isExistBackArticle() { return this.isMultiSubPages && (this.isAvailablePrevSubPage || ((this.currentTop?.isSub ?? false) && this.isAvailableMainArticle)); }
2021
+
2022
+ get isArticlesAllyStatic() {
2023
+ for (var article of this.articleList) if (!article.isStatic) return false;
2024
+ return true;
2025
+ }
2026
+
2027
+ get $currentArticle() {
2028
+ const $articles = this.$articles;
2029
+ const $onTop = $articles.filter(asv(eds.onTop, t1));
2030
+ if ($onTop.length < 1) return $($articles[$articles.length - 1]);
2031
+ else if ($onTop.length > 1) return $($onTop[$onTop.length - 1]);
2032
+ else return $onTop;
2033
+ }
2034
+ get currentArticleStepIndex() {
2035
+ return this.getArticleStepIndex(this.$currentArticle);
2036
+ }
2037
+ get stepPagesLength() { return pageManager.getStepPagesLength(this.#articleStepsId, this.id, this.component.id, this.component.sectionBound); }
2038
+
2039
+ constructor(container, component, instanceOrigin) {
2040
+ super(container, instanceOrigin);
2041
+ this.component = component;
2042
+ this.id = this.$host.attr(eds.containerId);
2043
+ }
2044
+
2045
+ release(remove) {
2046
+
2047
+ super.release(remove);
2048
+ }
2049
+
2050
+ init(page, intent) {
2051
+ super.init(page, intent);
2052
+
2053
+ this.setEventHandle();
2054
+
2055
+ this.initArticles(intent);
2056
+
2057
+ return this;
2058
+ }
2059
+
2060
+ setEventHandle() {
2061
+ const inst = this;
2062
+
2063
+ this.$host.find(".back_navigation").click(function (e) {
2064
+ e.preventDefault();
2065
+
2066
+ inst.backStep();
2067
+
2068
+ return false;
2069
+ });
2070
+
2071
+ this.$host.find(".container_closer").click(function (e) {
2072
+ e.preventDefault();
2073
+
2074
+ inst.close();
2075
+
2076
+ return false;
2077
+ });
2078
+
2079
+ const $masterFloat = this.$host.find(".container_master_float");
2080
+ if ($masterFloat.length > 0) {
2081
+ this.#$masterFloat = $masterFloat;
2082
+ const $masterButton = $masterFloat.find(".container_master_button");
2083
+ if ($masterButton.length > 0) {
2084
+ this.#$masterButton = $masterButton;
2085
+ this.#$masterButtonTitle = $masterButton.find(".container_master_action");
2086
+
2087
+ $masterButton.click(function (e) {
2088
+ e.preventDefault();
2089
+
2090
+ postAsyncQueue(_ => {
2091
+ const handled = (inst.#onMasterButtonClick?.(e, this)) ?? null;
2092
+ if (handled !== true) {
2093
+ const articleStepsId = inst.#articleStepsId;
2094
+ if (articleStepsId != null) {
2095
+ const current = inst.currentArticleStepIndex;
2096
+ if (current != NaN) {
2097
+ const length = inst.stepPagesLength;
2098
+ const next = current + 1;
2099
+ const nextId = articleStepsId + "%" + next;
2100
+ if (next < length) pageManager.bringPage(EstreUiPage.getPidArticle(nextId, inst.id, inst.component.id, inst.component.sectionBound), handled);
2101
+ }
2102
+ }
2103
+ }
2104
+ });
2105
+
2106
+ return false;
2107
+ });
2108
+ }
2109
+
2110
+ this.#$masterFloat.before(doc.ce(div, "master_float_pad"));
2111
+ this.#$masterFloatPad = this.$host.find(".master_float_pad");
2112
+ setTimeout(_ => this.#$masterFloatPad.css("height", + this.#$masterFloat.height() + "px"), 0);
2113
+ }
2114
+ }
2115
+
2116
+ initSubPages(intent) {
2117
+ return this.initArticles(intent);
2118
+ }
2119
+
2120
+ registerSubPage(element, intent, instanceOrigin) {
2121
+ return this.registerArticle(element, intent, instanceOrigin);
2122
+ }
2123
+
2124
+ unregisterConatiner(pageHandle) {
2125
+ return this.unregisterArticle(pageHandle);
2126
+ }
2127
+
2128
+ initArticles(intent) {
2129
+
2130
+ const articleStepsId = this.$host.attr(eds.articleStepsId);
2131
+ if (articleStepsId != null && articleStepsId != "") this.#initStepNavigation(articleStepsId);
2132
+
2133
+ for (var article of this.$articles) this.registerArticle(article, intent);
2134
+
2135
+ const $scalables = this.$host.find(c.c + ar + uis.scalable);
2136
+ if (this.host.innerWidth >= 740) {//반응형 와이드 모드 기본값 적용
2137
+ $scalables.attr(eds.lookScale, t2);
2138
+ } else switch ($scalables.length) { //섹션 컴포넌트의 메인 항목 갯수에 따른 초기 표시 모드 적용
2139
+ case 0: //해당 없음 - 기본적으로 학생 등록 항목 노출
2140
+ break;
2141
+
2142
+ case 1: //신규 등록 항목만 노출될 때
2143
+ case 2: //등록된 항목 1건
2144
+ // $scalables.attr(eds.lookScale, t2);
2145
+ // break;
2146
+
2147
+ // case 3: //등록된 항목 2건
2148
+ $scalables.attr(eds.lookScale, t1);
2149
+ break;
2150
+
2151
+ default: //등록된 항목 3건 이상
2152
+ $scalables.attr(eds.lookScale, t0);
2153
+ break;
2154
+ }
2155
+
2156
+ $scalables.filter(obk + eds.registered + equ + v0 + cbk).attr(eds.lookScale, t0);
2157
+
2158
+ let $top = this.$articles.filter(asv(eds.onTop, t1));
2159
+ if ($top.length < 1) $top = this.$articles.filter(aiv(eds.articleId, "main"));
2160
+ if ($top.length < 1) $top = this.$articles;
2161
+ const handle = $top[$top.length - 1]?.pageHandle;
2162
+
2163
+ if (handle != null) {
2164
+ if (handle.show(false, false)) {
2165
+ if (estreUi.euiState == "onReady") {
2166
+ estreUi.replaceCurrentState(handle);
2167
+ }
2168
+ }
2169
+ }
2170
+ }
2171
+
2172
+ registerArticle(element, intent, instanceOrigin) {
2173
+ this.unregisterArticle(element.pageHandle);
2174
+ const article = new EstreArticle(element, this, instanceOrigin);
2175
+ const instanceId = article.instanceId;
2176
+ this.$article[instanceId] = article.$host;
2177
+ this.articles[instanceId] = article;
2178
+ this.articleList.push(article);
2179
+ const registered = EstreUiPage.registerOrCommitFrom(article);
2180
+ article.init(registered, intent);
2181
+ //if (article.isOnTop) await article.show(false, false);
2182
+ return article;
2183
+ }
2184
+
2185
+ unregisterArticle(article) {
2186
+ if (article == null) return;
2187
+ const instanceId = article.instanceId;
2188
+ const unregistered = EstreUiPage.unregisterFrom(article);
2189
+ article.release(!article.isStatic ? true : null);
2190
+ if (this.$article[instanceId] != null) delete this.$article[instanceId];
2191
+ if (this.articles[instanceId] != null) delete this.articles[instanceId];
2192
+ const index = this.articleList.indexOf(article);
2193
+ if (index > -1) this.articleList.splice(index, 1);
2194
+ return unregistered;
2195
+ }
2196
+
2197
+ #initStepNavigation(articleStepsId) {
2198
+ this.#articleStepsId = articleStepsId;
2199
+ this.#$stepNavigation = this.$host.find(c.c + uis.stepNavigation);
2200
+ this.#$stepNavTitleName = this.#$stepNavigation.find(".cur_step_name");
2201
+ this.#$stepIndicator = this.#$stepNavigation.find(uis.stepIndicator);
2202
+
2203
+ this.#$stepIndicator.empty();
2204
+ this.#updateStepNavigation(articleStepsId);
2205
+ }
2206
+
2207
+ #updateStepNavigation(articleStepsId = this.#articleStepsId) {
2208
+ const $currentArticle = this.$currentArticle;
2209
+
2210
+ if (this.#$stepIndicator != null) {
2211
+ const $articleSteps = this.$host.find(asv(eds.articleId, articleStepsId + "%"));
2212
+ const $stepPointers = this.#$stepPointers;
2213
+ const $stepDividers = this.#$stepDividers;
2214
+ const length = Math.max(this.stepPagesLength, $articleSteps.length);
2215
+ var steps = $stepPointers.length;
2216
+ if ($stepDividers.length != steps - 1) {
2217
+ this.#$stepIndicator.empty();
2218
+ steps = 0;
2219
+ }
2220
+ if (steps < length) for (var i=steps; i<length; i++) {
2221
+ if (i > 0) this.#$stepIndicator.append(doc.ce(div, "step_divider"));
2222
+ this.#$stepIndicator.append(doc.ce(div, "step_pointer"));
2223
+ } else if (steps > length) {
2224
+ const diff = steps - length;
2225
+ for (var i=0; i<diff; i++) {
2226
+ this.#$stepIndicator.last().remove();
2227
+ if (this.#$stepPointers.length > 0) this.#$stepIndicator.last().remove();
2228
+ }
2229
+ }
2230
+
2231
+ const index = this.currentArticleStepIndex;
2232
+ const $pointers = this.#$stepPointers;
2233
+ if (index != NaN) {
2234
+ $pointers.filter(aiv(eds.active, t1)).attr(eds.active, null);
2235
+ $($pointers[index]).attr(eds.active, t1);
2236
+ }
2237
+ }
2238
+
2239
+ if ($currentArticle.length > 0) this.setCurrentStepName($currentArticle.attr(eds.title));
2240
+ }
2241
+
2242
+ setCurrentStepName(title) {
2243
+ if (this.#$stepNavTitleName != null) this.#$stepNavTitleName.text(title);
2244
+ }
2245
+
2246
+ focusMasterButton() {
2247
+ this.#$masterButton?.focus();
2248
+ }
2249
+
2250
+ performClickMasterButton() {
2251
+ this.#$masterButton?.click();
2252
+ }
2253
+
2254
+ setOnClickMasterButton(onClick = null) {
2255
+ this.#onMasterButtonClick = onClick;
2256
+ }
2257
+
2258
+ setMasterButtonDisabled(disabled) {
2259
+ this.#$masterButton?.prop("disabled", disabled);
2260
+ }
2261
+
2262
+ setMasterButtonText(text) {
2263
+ this.#$masterButtonTitle?.text(text);
2264
+ }
2265
+
2266
+ getHost(hostType) {
2267
+ if (this.hostType == hostType) return this;
2268
+ else return this.component.getHost(hostType);
2269
+ }
2270
+
2271
+ backStep() {
2272
+ if (this.isStepNavigation) {
2273
+ const index = this.currentArticleStepIndex;
2274
+ if (index != NaN) {
2275
+ const prevIndex = index - 1;
2276
+ if (prevIndex > -1) this.showArticle(this.#articleStepsId + "%" + prevIndex);
2277
+ }
2278
+ }
2279
+ }
2280
+
2281
+ show(isRequest = true, setFocus = true) {
2282
+ if (isRequest) {
2283
+ return this.component.showContainer(this.id);
2284
+ } else return super.show(false, setFocus);
2285
+ }
2286
+
2287
+ // focus() {
2288
+ // if (this.isShowing) {
2289
+ // const $articles = this.$articles;
2290
+ // let $top = $articles.filter(asv(eds.onTop, t1));
2291
+ // var $targetArticle = null;
2292
+ // if ($top != null && $top.length > 0) $targetArticle = $top;
2293
+ // else if ($articles.length > 0) $targetArticle = $($articles[$articles.length-1]);
2294
+
2295
+ // let processed = false;
2296
+ // if ($targetArticle != null) {
2297
+ // processed = $targetArticle[$targetArticle.length - 1]?.pageHandle?.focus();
2298
+ // }
2299
+
2300
+ // super.focus();
2301
+
2302
+ // return processed;
2303
+ // } else return false;
2304
+ // }
2305
+
2306
+ blur() {
2307
+ this.onBlur();
2308
+
2309
+ const $articles = this.$articles;
2310
+ let $top = $articles.filter(asv(eds.onTop, t1));
2311
+ var $targetArticle = null;
2312
+ if ($top != null && $top.length > 0) $targetArticle = $top;
2313
+ else if ($articles.length > 0) $targetArticle = $($articles[$articles.length-1]);
2314
+
2315
+ if ($targetArticle != null) return postAsyncQueue(async _ => {
2316
+ var processed = false;
2317
+ for (var article of $targetArticle) processed |= await article.pageHandle?.blur();
2318
+ return processed;
2319
+ });
2320
+ return false;
2321
+ }
2322
+
2323
+ close(isRequest = true, isTermination = false) {
2324
+ if (isRequest) {
2325
+ return this.component.closeContainer(this.id, this.instanceOrigin, isTermination) ?? super.close(isTermination);
2326
+ } else return super.close(isTermination);
2327
+ }
2328
+
2329
+ onShow() {
2330
+ const processed = super.onShow();
2331
+ let $top = this.$articles.filter(asv(eds.onTop, t1));
2332
+ if ($top.length < 1) $top = this.$articles;
2333
+ const article = $top[$top.length - 1]?.pageHandle;
2334
+ if (article != null) {
2335
+ const processed = article.onShow();
2336
+ this.currentOnTop = article;
2337
+ // article.onFocus();
2338
+
2339
+ if (estreUi.euiState == "onReady" && processed) {
2340
+ estreUi.replaceCurrentState(article);
2341
+ }
2342
+ }
2343
+ return processed;
2344
+ }
2345
+
2346
+ async onHide() {
2347
+ if (this.$articles != n) {
2348
+ let $top = this.$articles.filter(asv(eds.onTop, t1));
2349
+ if ($top.length < 1) $top = this.$articles;
2350
+ const article = $top[$top.length - 1]?.pageHandle;
2351
+ if (article != null) {
2352
+ await article.onBlur();
2353
+ await article.onHide();
2354
+ }
2355
+ }
2356
+ return await super.onHide();
2357
+ }
2358
+
2359
+ async onClose(isTermination = false, isOnRelease = false) {
2360
+ const stepped = [];
2361
+ for (var id in this.articles) if (id.indexOf(this.#articleStepsId + "%") === 0) stepped.push(id);
2362
+
2363
+ const closer = [];
2364
+
2365
+ if (stepped.length > 0) {
2366
+ const sorted = stepped.sort();
2367
+ for (var i=sorted.length-1; i>-1; i--) closer.push(this.closeArticle(sorted[i], u, isTermination));
2368
+ } else {
2369
+ for (var article of this.articleList.reverse()) closer.push(article.close(true, isTermination));
2370
+ }
2371
+
2372
+ await Promise.all(closer);
2373
+
2374
+ return super.onClose(isTermination, isOnRelease);
2375
+ }
2376
+
2377
+
2378
+ // handles
2379
+ showSubPage(id, intent, instanceOrigin) {
2380
+ return this.showArticle(id, intent, instanceOrigin);
2381
+ }
2382
+
2383
+ openSubPage(id, intent, instanceOrigin) {
2384
+ return this.openArticle(id, intent, instanceOrigin);
2385
+ }
2386
+
2387
+ bringSubPage(id, intent) {
2388
+ return this.bringArticle(id, intent, instanceOrigin);
2389
+ }
2390
+
2391
+ closeSubPage(id, instanceOrigin, isTermination = false) {
2392
+ return this.closeArticle(id, instanceOrigin, isTermination);
2393
+ }
2394
+
2395
+ showArticle(id, intent, instanceOrigin) {
2396
+ if (id != null && !this.isClosing) {
2397
+ const show = $target => {
2398
+ const onlyOne = this.$articles.filter(ntc("dummy")).length === 1;
2399
+ const $currentTop = this.$articles.filter(asv(eds.onTop, t1));
2400
+ //console.log("current top: ", $currentTop);
2401
+ const currentTopHandle = this.currentTop;
2402
+ const currentTopHandleId = currentTopHandle.id;
2403
+ if (id != currentTopHandleId && currentTopHandleId != this.latestSubPageId) {
2404
+ this.prevSubPageId = currentTopHandleId;
2405
+
2406
+ // if (estreUi.euiState == "onReady" && currentTopHandle != null) estreUi.pushCurrentState(currentTopHandle);
2407
+ }
2408
+ if (this.isStepNavigation) {
2409
+ $target[0]?.pageHandle?.pushIntent(intent);
2410
+ const current = this.currentArticleStepIndex;
2411
+ const target = this.getArticleStepIndex($target);
2412
+ const isNext = onlyOne || target > current;
2413
+ const currentOnTop1 = isNext ? "-1" : "+1";
2414
+ const targetOnTop1 = isNext ? "+1" : "-1";
2415
+ const targetOnTop2 = isNext ? "+" : "-";
2416
+ if ($currentTop.length > 0) {
2417
+ $currentTop.attr(eds.onTop, currentOnTop1);
2418
+ setTimeout(async _ => {
2419
+ for (var currentTop of $currentTop) if (currentTop.dataset.onTop == currentOnTop1) {
2420
+ await currentTop.pageHandle?.blur();
2421
+ await currentTop.pageHandle?.onHide();
2422
+ //currentTop.dataset.onTop = "";
2423
+ }
2424
+ $currentTop.attr(eds.onTop, null);
2425
+ }, cvt.t2ms($currentTop.css(a.trdr)));
2426
+ }
2427
+ $target.attr(eds.onTop, targetOnTop1);
2428
+ setTimeout(_ => {
2429
+ if ($target?.attr(eds.onTop) == targetOnTop1) {
2430
+ $target?.[0].pageHandle?.onOpen();
2431
+ $target?.[0].pageHandle?.onShow();
2432
+ $target?.attr(eds.onTop, targetOnTop2);
2433
+ setTimeout(_ => {
2434
+ if ($target?.attr(eds.onTop) == targetOnTop2) {
2435
+ $target?.attr(eds.onTop, t1);
2436
+ $target?.[0].pageHandle?.focus();
2437
+ this.#updateStepNavigation();
2438
+ }
2439
+ }, cvt.t2ms($target?.css(a.trdr)) + cvt.t2ms($target?.css(a.trdl)));
2440
+ }
2441
+ }, 0);
2442
+ const targetArticle = $target.pageHandle;
2443
+ this.currentOnTop = targetArticle;
2444
+
2445
+ if (estreUi.euiState == "onReady" && targetArticle != null) estreUi.replaceCurrentState(targetArticle);
2446
+ switch (this.sectionBound) {
2447
+ case "menu":
2448
+ case "main":
2449
+ estreUi.showExactAppbar(this, this.container, targetArticle);
2450
+ break;
2451
+ }
2452
+ return true;
2453
+ } else {
2454
+ const targetArticle = $target[0]?.pageHandle;
2455
+ for (var currentTop of $currentTop) {
2456
+ const article = currentTop.pageHandle
2457
+ if (article != null && (targetArticle == null || article != targetArticle)) {
2458
+ article.hide();
2459
+ }
2460
+ }
2461
+ targetArticle?.pushIntent(intent);
2462
+ targetArticle?.show(false);
2463
+ this.currentOnTop = targetArticle;
2464
+
2465
+
2466
+ if (estreUi.euiState == "onReady" && targetArticle != null) estreUi.replaceCurrentState(targetArticle);
2467
+ switch (this.sectionBound) {
2468
+ case "menu":
2469
+ case "main":
2470
+ estreUi.showExactAppbar(this.component, this, targetArticle);
2471
+ break;
2472
+ }
2473
+ return true;
2474
+ }
2475
+ };
2476
+
2477
+ const $target = this.$article[id + (instanceOrigin?.let(it => "^" + it) ?? "")];
2478
+ if ($target != null && $target.length > 0) return show($target);
2479
+ else if (instanceOrigin == n) {
2480
+ const articleIds = this.$article.ways.filter(it => it.startsWith(id + "^"));
2481
+ if (articleIds.length > 0) {
2482
+ const articleId = articleIds[articleIds.length - 1];
2483
+ const $target = this.$article[articleId];
2484
+ if ($target != null && $target.length > 0) return show($target);
2485
+ }
2486
+ }
2487
+ }
2488
+ return false;
2489
+ }
2490
+
2491
+ openArticle(id, intent, instanceOrigin) {
2492
+ if (this.isClosing) return false;
2493
+ const page = pageManager.getArticle(id, this.id, this.component.id, this.component.sectionBound);
2494
+ if (page == null) return null;
2495
+ if (page.statement == "static") return null;
2496
+ if (!page.isMultiInstance) {
2497
+ var $exist = this.$articles.filter(aiv(eds.articleId, id));
2498
+ if ($exist.length > 0) {
2499
+ this.closeArticle(id);
2500
+ var $exist = this.$articles.filter(aiv(eds.articleId, id));
2501
+ if ($exist.length > 0) {
2502
+ if ($exist[0].pageHandle != null) $exist[0].pageHandle.release(true);
2503
+ else $exist.remove();
2504
+ }
2505
+ }
2506
+ }
2507
+ const $articles = this.$articles;
2508
+ //this.$articles.filter(aiv(eds.onTop, t1)).attr(eds.onTop, "");
2509
+ if ($articles.length > 0) $($articles[$articles.length - 1]).after(page.live);
2510
+ else this.$host.append(page.live);
2511
+ const $article = this.$articles.filter(aiv(eds.articleId, id));
2512
+ if ($article == null || $article.length < 1) return null;
2513
+ const article = this.registerArticle($article[$article.length - 1], intent, instanceOrigin);
2514
+ //this.#updateStepNavigation();
2515
+ return article;
2516
+ }
2517
+
2518
+ bringArticle(id, intent, instanceOrigin) {
2519
+ if (this.articles[id] == null) {
2520
+ if (this.openArticle(id, intent, instanceOrigin)) return this.showArticle(id);
2521
+ else return false;
2522
+ } else return this.showArticle(id, intent);
2523
+ }
2524
+
2525
+ closeArticle(id, instanceOrigin, isTermination = false) {
2526
+ if (id != null) {
2527
+ const close = article => {
2528
+ const task = article.close(false, isTermination || !article.isStatic);
2529
+ if (!isTermination && !this.isClosing) postAsyncQueue(async _ => {
2530
+ if (this.isClosing) return;
2531
+ const target = this.subPages[id];
2532
+ const subPageList = this.subPageList.filter(it => !it.isClosing && it != target);
2533
+ if (subPageList.length > 0) {
2534
+ const prev = this.prevSubPageId;
2535
+ if (prev != null) this.showSubPage(prev);
2536
+ else subPageList[subPageList.length - 1].show();
2537
+ } else {
2538
+ await task;
2539
+ if (!this.isClosing && !this.isStatic && subPageList.length < 1) this.close(true, true);
2540
+ };
2541
+ });
2542
+ return postAsyncQueue(async _ => {
2543
+ const result = await task;
2544
+ if (isTermination || !article.isStatic) this.unregisterArticle(article);
2545
+ return result;
2546
+ });
2547
+ };
2548
+
2549
+ const article = this.articles[id + (instanceOrigin?.let(it => "^" + it) ?? "")];
2550
+ if (article != null) return close(article);
2551
+ else if (instanceOrigin == n) {
2552
+ const articleIds = this.$article.ways.filter(it => it.startsWith(id + "^"));
2553
+ if (articleIds.length > 0) {
2554
+ const articleId = articleIds[articleIds.length - 1];
2555
+ const article = this.articles[articleId];
2556
+ return close(article);
2557
+ }
2558
+ }
2559
+ }
2560
+ return null;
2561
+ }
2562
+
2563
+ getArticleStepIndex($article) {
2564
+ if ($article.length > 0) {
2565
+ return parseInt($article.attr(eds.articleId).split("%")[1]);
2566
+ } else return -1;
2567
+ }
2568
+ }
2569
+
2570
+
2571
+ /**
2572
+ * Article page handle
2573
+ */
2574
+ class EstreArticle extends EstrePageHandle {
2575
+
2576
+ hostType = "article";
2577
+
2578
+ get sectionBound() { return this.container.component.sectionBound; }
2579
+
2580
+ container = null;
2581
+
2582
+ get isFullyStatic() { return this.container.isFullyStatic && this.isStatic; }
2583
+
2584
+ get isMain() { return this.id == "main"; }
2585
+ get isSub() { return this.id != "main"; }
2586
+
2587
+ get isCanBack() { return this.container.isExistBackArticle; }
2588
+
2589
+
2590
+ handles = [];
2591
+
2592
+
2593
+ unifiedCalendars = [];
2594
+
2595
+ scalables = [];
2596
+ collapsibles = [];
2597
+ toggleBlocks = [];
2598
+ toggleTabBlocks = [];
2599
+ tabBlocks = [];
2600
+
2601
+ dateShowers = [];
2602
+
2603
+ constructor(article, container, instanceOrigin) {
2604
+ super(article, instanceOrigin);
2605
+ this.container = container;
2606
+ this.id = this.$host.attr(eds.articleId);
2607
+ }
2608
+
2609
+
2610
+ release(remove) {
2611
+ this.releaseHandles();
2612
+
2613
+ return super.release(remove);
2614
+ }
2615
+
2616
+ init(page, intent) {
2617
+ super.init(page, intent);
2618
+
2619
+ this.applyActiveStructAfterBind();
2620
+ return this;
2621
+ }
2622
+
2623
+ pushIntent(intent, onInit = false) {
2624
+ if (super.pushIntent(intent, onInit)) {
2625
+ if (window.isDebug) console.log("on called data bind - " + this.pid);
2626
+ this.applyActiveStruct();
2627
+ }
2628
+ }
2629
+
2630
+ registerHandle(specifier, handle) {
2631
+ if (this.handles[specifier] == null) this.handles[specifier] = [];
2632
+ this.handles[specifier].push(handle);
2633
+ }
2634
+
2635
+ unregisterHandle(specifier, handle) {
2636
+ const index = this.handles[specifier]?.indexOf(handle);
2637
+ this.handles[specifier]?.splice(index, 1);
2638
+ }
2639
+
2640
+
2641
+ show(isRequest = true, setFocus = true) {
2642
+ if (isRequest) {
2643
+ return this.container.showArticle(this.id);
2644
+ } else return super.show(false, setFocus);
2645
+ }
2646
+
2647
+ close(isRequest = true, isTermination = false) {
2648
+ if (isRequest) {
2649
+ return this.container.closeArticle(this.id, this.instanceOrigin, isTermination) ?? super.close(isTermination);
2650
+ } else return super.close(isTermination);
2651
+ }
2652
+
2653
+
2654
+ focus() {
2655
+ if (this.isShowing) {
2656
+ const $target = this.$host.find(ax(eds.focusOnBring));
2657
+ var bigger = 0;
2658
+ for (var item of $target) {
2659
+ const index = parseInt($(item).attr(eds.focusOnBring));
2660
+ if (index > bigger) bigger = index;
2661
+ }
2662
+
2663
+ for (var i=0; i<=bigger; i++) {
2664
+ const $found = $target.filter(aiv(eds.focusOnBring, i));
2665
+ if ($found.length > 0) {
2666
+ $($found[0]).focus();
2667
+ break;
2668
+ }
2669
+ }
2670
+
2671
+ super.focus();
2672
+
2673
+ return true;
2674
+ } else return false;
2675
+ }
2676
+
2677
+
2678
+ getHost(hostType) {
2679
+ if (this.hostType == hostType) return this;
2680
+ else return this.container.getHost(hostType);
2681
+ }
2682
+ }
2683
+
2684
+
2685
+
2686
+ // ======================================================================
2687
+ // MODULE: Page Handler -- EstrePageHandler, EstreLottieAnimatedHandler,
2688
+ // Dialog page handlers (Alert, Confirm, Prompt, Option, etc.)
2689
+ // ======================================================================
2690
+ /**
2691
+ * Base class defining page lifecycle callbacks.
2692
+ * Subclass in your project to override onBring, onShow, onHide, onClose, etc.
2693
+ * @class
2694
+ */
2695
+ class EstrePageHandler {
2696
+
2697
+ /** @type {*} The provider that registered this handler (set by EstreUiCustomPageManager). */
2698
+ #provider = null;
2699
+ get provider() { return this.#provider; }
2700
+
2701
+ /** @type {EstrePageHandle} The page handle instance this handler is bound to. */
2702
+ #handle = null;
2703
+ /** @type {EstrePageHandle} */
2704
+ get handle() { return this.#handle; }
2705
+ /** @type {EstreIntent|undefined} Current intent object. */
2706
+ get intent() { return this.handle.intent; }
2707
+ /** @type {string|undefined} The action field of the intent. */
2708
+ get intentAction() { return this.intent?.action; }
2709
+ /** @type {*} The data field of the intent. */
2710
+ get intentData() { return this.intent?.data; }
2711
+
2712
+ /**
2713
+ * @param {EstrePageHandle} handle - The page handle to bind.
2714
+ * @param {*} [provider] - The provider that registered this handler.
2715
+ */
2716
+ constructor (handle, provider) {
2717
+ this.#handle = handle;
2718
+ this.#provider = provider;
2719
+ }
2720
+
2721
+
2722
+ /**
2723
+ * Called when the page is first navigated (brought). Use for initial setup such as DOM reference caching.
2724
+ * @param {EstrePageHandle} handle - The page handle.
2725
+ */
2726
+ onBring(handle) {
2727
+
2728
+ }
2729
+
2730
+ /**
2731
+ * Called when the component/container/article is opened. Use for event binding, etc.
2732
+ * @param {EstrePageHandle} handle - The page handle.
2733
+ */
2734
+ onOpen(handle) {
2735
+
2736
+ }
2737
+
2738
+ /**
2739
+ * Called when the page is shown. Use for starting animations, refreshing data, etc.
2740
+ * @param {EstrePageHandle} handle - The page handle.
2741
+ */
2742
+ onShow(handle) {
2743
+
2744
+ }
2745
+
2746
+ /**
2747
+ * Called when the page receives focus.
2748
+ * @param {EstrePageHandle} handle - The page handle.
2749
+ */
2750
+ onFocus(handle) {
2751
+
2752
+ }
2753
+
2754
+ /**
2755
+ * Called on a reload request. Default behavior is to close and re-bring.
2756
+ * @param {EstrePageHandle} handle - The page handle.
2757
+ * @returns {Promise<boolean>|boolean} Whether the reload succeeded.
2758
+ */
2759
+ onReload(handle) {
2760
+ // Rebuild(close and bring) is default action
2761
+ if (!handle.isStatic) {
2762
+ const pid = EstreUiPage.from(handle).pid;
2763
+ const intent = handle.intent;
2764
+ return postAsyncQueue(async _ => {
2765
+ if (await handle.close()) {
2766
+ return pageManager.bringPage(pid, intent);
2767
+ } else {
2768
+ handle.show();
2769
+ return false;
2770
+ }
2771
+ });
2772
+ } else return false;
2773
+ }
2774
+
2775
+ /**
2776
+ * Called on a back request. Default behavior attempts to close based on hostType and sectionBound.
2777
+ * @param {EstrePageHandle} handle - The page handle.
2778
+ * @returns {Promise<boolean>} Whether the back action was handled.
2779
+ */
2780
+ async onBack(handle) {
2781
+ return handle.hostType != "component" ? (handle.isCanBack ? (handle.isStatic ? await handle.close() != null : await handle.close()) : false) : (
2782
+ handle.sectionBound == "blind" || !handle.isStatic ? await handle.close() : false);
2783
+ }
2784
+
2785
+ /**
2786
+ * Called when the page is hidden.
2787
+ * @param {EstrePageHandle} handle - The page handle.
2788
+ * @param {boolean} fullyHide - Whether to fully hide the page.
2789
+ */
2790
+ async onHide(handle, fullyHide) {
2791
+
2792
+ }
2793
+
2794
+ /**
2795
+ * Called when the page is closed. Use for resource cleanup.
2796
+ * @param {EstrePageHandle} handle - The page handle.
2797
+ */
2798
+ async onClose(handle) {
2799
+
2800
+ }
2801
+
2802
+ /**
2803
+ * Called when the page is released. Final cleanup before DOM removal.
2804
+ * @param {EstrePageHandle} handle - The page handle.
2805
+ * @param {boolean|undefined} remove - true to remove from DOM, false to empty.
2806
+ */
2807
+ async onRelease(handle, remove) {
2808
+
2809
+ }
2810
+ }
2811
+
2812
+ class EstreLottieAnimatedHandler extends EstrePageHandler {
2813
+ $container;
2814
+ $article;
2815
+ $lottie;
2816
+ get lottie() { return this.$lottie?.[0]; }
2817
+ get player() { return this.lottie?.getLottie(); }
2818
+
2819
+ async onBring(handle) {
2820
+ this.$container = handle.$host;
2821
+ this.$article = this.$container.find(ar + aiv(eds.articleId, "main"));
2822
+ }
2823
+
2824
+ onOpen(handle) {
2825
+ this.$lottie = this.$article.find(dlp);
2826
+ }
2827
+
2828
+ onShow(handle) {
2829
+ const player = this.player;
2830
+ if (player != n) player.play();
2831
+ else this.lottie?.addEventListener("ready", e => { e.target.play(); })
2832
+ }
2833
+
2834
+ onHide(handle) {
2835
+ this.player?.pause();
2836
+ }
2837
+
2838
+ onClose(handle) {
2839
+ this.player?.stop();
2840
+ this.player?.destroy();
2841
+ }
2842
+ }
2843
+
2844
+ class EstreDialogPageHandler extends EstrePageHandler {
2845
+ $container;
2846
+ $article;
2847
+ $dialog;
2848
+ $handle
2849
+ $title;
2850
+ $backer;
2851
+ $closer;
2852
+ $content;
2853
+ $message;
2854
+ $options;
2855
+ $actions;
2856
+
2857
+ handleSwipeHandler;
2858
+
2859
+ onBring(handle) {
2860
+ this.$container = handle.$host;
2861
+ this.$article = this.$container.find(ar + aiv(eds.articleId, "main"));
2862
+ this.$dialog = this.$article.find(div + cls + "dialog");
2863
+ this.$handle = this.$dialog.find(div + cls + "handle");
2864
+ this.$title = this.$dialog.find(div + cls + "title");
2865
+ this.$backer = this.$title.find(btn + cls + "back");
2866
+ this.$closer = this.$title.find(btn + cls + "close");
2867
+ this.$message = this.$dialog.find(div + cls + "message");
2868
+ this.$options = this.$dialog.find(div + cls + "options");
2869
+ this.$content = this.$dialog.find(div + cls + "content");
2870
+ if (this.$message.length < 1) this.$message = this.$content.find(div + cls + "message");
2871
+ if (this.$options.length < 1) this.$options = this.$content.find(div + cls + "options");
2872
+ this.$actions = this.$dialog.find(div + cls + "actions");
2873
+
2874
+ if (handle.intent?.data?.backButton === true) this.$dialog.attr("data-back", t1);
2875
+ if (handle.intent?.data?.closeButton === true) this.$dialog.attr("data-close", t1);
2876
+ }
2877
+
2878
+ onOpen(handle) {
2879
+ this.$container.click(function (e) {
2880
+ e.preventDefault();
2881
+ e.stopPropagation();
2882
+
2883
+ handle?.close();
2884
+
2885
+ return false;
2886
+ });
2887
+ this.$dialog.click(function (e) {
2888
+ // e.preventDefault();
2889
+ e.stopPropagation();
2890
+
2891
+ // return false;
2892
+ });
2893
+ this.$dialog.keydown(function (e) {
2894
+ if (e.keyCode == 27) {
2895
+ e.preventDefault();
2896
+ handle.close();
2897
+ return false;
2898
+ }
2899
+ });
2900
+ this.$backer.click(function (e) {
2901
+ e.preventDefault();
2902
+ e.stopPropagation();
2903
+
2904
+ handle.close();
2905
+
2906
+ return false;
2907
+ });
2908
+ this.$closer.click(function (e) {
2909
+ e.preventDefault();
2910
+ e.stopPropagation();
2911
+
2912
+ handle.close();
2913
+
2914
+ return false;
2915
+ });
2916
+ if (this.$handle.length > 0) this.handleSwipeHandler = new EstreSwipeHandler(this.$handle).setStopPropagation().setPreventDefault().setPreventAll().unuseX().setThresholdY(1).setDropStrayed(false).setResponseBound(this.$dialog).setOnUp(function (grabX, grabY, handled, canceled, directed) {
2917
+ const handledDirection = this.handledDirection;
2918
+ if (handled && handledDirection == "down" && Math.abs(grabY) > 80) handle.close();
2919
+ });
2920
+ this.$actions.find(inp + cor + btn).on("keydown", function (e) {
2921
+ if (e.keyCode == 27) {
2922
+ e.preventDefault();
2923
+
2924
+ handle?.close();
2925
+
2926
+ return false;
2927
+ }
2928
+ });
2929
+
2930
+
2931
+ const data = this.intentData;
2932
+ if (data?.containerBlindColor != n) this.$container.css("background-color", data.containerBlindColor);
2933
+ if (data?.articleBlindColor != n) this.$article.css("background-color", data.articleBlindColor);
2934
+ if (data?.bgColor != n) this.$dialog.css("background-color", data.bgColor);
2935
+ }
2936
+
2937
+ onIntentUpdated(handle, intent) {
2938
+ const data = intent?.data;
2939
+ if (data?.containerBlindColor != n) this.$container.css("background-color", data.containerBlindColor);
2940
+ if (data?.articleBlindColor != n) this.$article.css("background-color", data.articleBlindColor);
2941
+ if (data?.bgColor != n) this.$dialog.css("background-color", data.bgColor);
2942
+ }
2943
+
2944
+ async onBack(handle) {
2945
+ return await handle.close();
2946
+ }
2947
+
2948
+ onClose(handle) {
2949
+ if (handle?.intent?.onDissmiss != null) handle.intent.onDissmiss();
2950
+ }
2951
+ }
2952
+
2953
+ class EstreAlertDialogPageHandler extends EstreDialogPageHandler {
2954
+ $confirm;
2955
+
2956
+ onBring(handle) {
2957
+ super.onBring(handle);
2958
+
2959
+ this.$confirm = this.$actions.find(btn + cls + "confirm");
2960
+ }
2961
+
2962
+ onOpen(handle) {
2963
+ super.onOpen(handle);
2964
+
2965
+ this.$confirm.click(function (e) {
2966
+ e.preventDefault();
2967
+ e.stopPropagation();
2968
+ handle?.intent?.onOk?.();
2969
+ handle?.close();
2970
+ return false;
2971
+ });
2972
+
2973
+ this.$confirm.focus();
2974
+ }
2975
+
2976
+ onFocus(handle) {
2977
+ this.$confirm.focus();
2978
+ }
2979
+ }
2980
+
2981
+ class EstreConfirmDialogPageHandler extends EstreDialogPageHandler {
2982
+ $positive;
2983
+ $negative;
2984
+ $neutral;
2985
+
2986
+ onBring(handle) {
2987
+ super.onBring(handle);
2988
+
2989
+ this.$positive = this.$actions.find(btn + cls + "positive");
2990
+ this.$negative = this.$actions.find(btn + cls + "negative");
2991
+ this.$neutral = this.$actions.find(btn + cls + "neutral");
2992
+ }
2993
+
2994
+ onOpen(handle) {
2995
+ super.onOpen(handle);
2996
+
2997
+ this.$positive.click(function (e) {
2998
+ e.preventDefault();
2999
+ e.stopPropagation();
3000
+ handle?.intent?.onPositive?.();
3001
+ handle?.close();
3002
+ return false;
3003
+ });
3004
+ this.$negative.click(function (e) {
3005
+ e.preventDefault();
3006
+ e.stopPropagation();
3007
+ handle?.intent?.onNegative?.();
3008
+ handle?.close();
3009
+ return false;
3010
+ });
3011
+ if (handle?.intent?.data?.callbackNeutral == null) this.$neutral.remove();
3012
+ else this.$neutral.click(function (e) {
3013
+ e.preventDefault();
3014
+ e.stopPropagation();
3015
+ handle?.intent?.onNeutral?.();
3016
+ handle?.close();
3017
+ return false;
3018
+ });
3019
+
3020
+ this.$negative.focus();
3021
+ }
3022
+
3023
+ onFocus(handle) {
3024
+ this.$negative.focus();
3025
+ }
3026
+ }
3027
+
3028
+ class EstrePromptDialogPageHandler extends EstreDialogPageHandler {
3029
+ $input;
3030
+ $confirm;
3031
+
3032
+ onBring(handle) {
3033
+ super.onBring(handle);
3034
+
3035
+ this.$input = this.$actions.find(inp);
3036
+ this.$confirm = this.$actions.find(btn + cls + "confirm");
3037
+ }
3038
+
3039
+ onOpen(handle) {
3040
+ super.onOpen(handle);
3041
+
3042
+ this.$input.on("keydown", function (e) {
3043
+ if (e.keyCode == 13) {
3044
+ e.preventDefault();
3045
+
3046
+ handle?.handler?.$confirm?.click();
3047
+
3048
+ return false;
3049
+ }
3050
+ });
3051
+ this.$input.on("focus", function (e) {
3052
+ handle?.intent?.onPromptFocus?.(this, this.value, e);
3053
+ });
3054
+ this.$input.on("input paste cut", function (e) {
3055
+ handle?.intent?.onPromptInput?.(this, this.value, e);
3056
+ });
3057
+ this.$input.on("paste", function (e) {
3058
+ try {
3059
+ const pasteText = e.originalEvent.clipboardData.getData('text/plain');
3060
+ handle?.intent?.onPromptPaste?.(this, pasteText, this.value, e);
3061
+ } catch (err) {
3062
+ console.error(err);
3063
+ }
3064
+ });
3065
+ this.$input.on("change", function (e) {
3066
+ handle?.intent?.onPromptChange?.(this, this.value, e);
3067
+ });
3068
+ this.$input.on("blur", function (e) {
3069
+ handle?.intent?.onPromptBlur?.(this, this.value, e);
3070
+ });
3071
+ this.$confirm.click(function (e) {
3072
+ e.preventDefault();
3073
+ e.stopPropagation();
3074
+ handle?.intent?.onConfirm?.(handle?.handler?.$input?.val());
3075
+ handle?.close();
3076
+ return false;
3077
+ });
3078
+
3079
+ this.$input.focus();
3080
+ }
3081
+
3082
+ onFocus(handle) {
3083
+ this.$input.focus();
3084
+ }
3085
+ }
3086
+
3087
+ class EstreOptionDialogPageHandler extends EstreDialogPageHandler {
3088
+ $optionItems;
3089
+
3090
+ onBring(handle) {
3091
+ super.onBring(handle);
3092
+ }
3093
+
3094
+ onOpen(handle) {
3095
+ super.onOpen(handle);
3096
+
3097
+ this.$optionItems = this.$options.find(c.c + btn);
3098
+ this.$optionItems.click(function (e) {
3099
+ e.preventDefault();
3100
+ e.stopPropagation();
3101
+ const index = this.dataset.index;
3102
+ const value = handle?.intent?.data?.options?.[index];
3103
+ handle?.intent?.onSelected?.(index, value);
3104
+ handle?.close();
3105
+ return false;
3106
+ });
3107
+
3108
+ this.$optionItems[0]?.focus();
3109
+ }
3110
+
3111
+ onFocus(handle) {
3112
+ this.$optionItems[0]?.focus();
3113
+ }
3114
+ }
3115
+
3116
+ class EstreSelectionDialogPageHandler extends EstreDialogPageHandler {
3117
+ $optionItems;
3118
+ $optionCheckboxes;
3119
+
3120
+ $confirm;
3121
+ $another;
3122
+
3123
+ get $selected() {
3124
+ return this.$optionCheckboxes.filter(ckd);
3125
+ }
3126
+ get $unselected() {
3127
+ return this.$optionCheckboxes.filter(ncd);
3128
+ }
3129
+ get $disabled() {
3130
+ return this.$optionCheckboxes.filter(dad);
3131
+ }
3132
+
3133
+ get selected() {
3134
+ const options = this.intentData?.options;
3135
+ const selected = {};
3136
+ if (options != null) for (const checkbox of this.$selected) {
3137
+ const $checkbox = $(checkbox);
3138
+ const index = $checkbox.attr(eds.index);
3139
+ if (index != null) selected[index] = options[index];
3140
+ }
3141
+ return selected;
3142
+ }
3143
+
3144
+ onBring(handle) {
3145
+ super.onBring(handle);
3146
+
3147
+ this.$confirm = this.$actions.find(btn + cls + "confirm");
3148
+ this.$another = this.$actions.find(btn + cls + "another");
3149
+ }
3150
+
3151
+ onOpen(handle) {
3152
+ super.onOpen(handle);
3153
+
3154
+ const defaultSelected = this.intentData?.defaultSelected;
3155
+ if (isNotNully(defaultSelected)) forkv(defaultSelected, (k, v) => {
3156
+ switch(to(v)) {
3157
+ case BOOLEAN:
3158
+ this.$optionCheckboxes.filter(aiv(eds.index, k)).prop(m.v, v);
3159
+ break;
3160
+
3161
+ case NUMBER:
3162
+ this.$optionCheckboxes.filter(aiv(eds.index, v)).prop(m.v, true);
3163
+ break;
3164
+ }
3165
+ });
3166
+
3167
+ const handler = this;
3168
+
3169
+ this.$optionItems = this.$options.find(c.c + btn);
3170
+ this.$optionItems.click(function (e) {
3171
+ e.preventDefault();
3172
+ e.stopPropagation();
3173
+
3174
+ $(this).find(itc(_v)).let(it => {
3175
+ if (!it.prop(m.d)) it.prop(m.v, !it.prop(m.v)).change();
3176
+ });
3177
+
3178
+ return false;
3179
+ });
3180
+
3181
+ this.$optionCheckboxes = this.$optionItems.find(itc(_v));
3182
+ this.$optionCheckboxes.change(function (e) {
3183
+ const index = this.dataset.index;
3184
+ const value = handle?.intent?.data?.options?.[index] ?? this.value;
3185
+ const checked = this.checked;
3186
+ const fineChecked = handler.checkValidSelectAction(handle, handler, index, value, checked);
3187
+ if (fineChecked) {
3188
+ if (checked) handle?.intent?.onSelect?.(index, value);
3189
+ } else this.checked = !checked;
3190
+ });
3191
+
3192
+ this.$confirm.click(function (e) {
3193
+ e.preventDefault();
3194
+ e.stopPropagation();
3195
+ handle?.intent?.onConfirm?.(handler.selected);
3196
+ handle?.close();
3197
+ return false;
3198
+ });
3199
+ if (handle?.intent?.data?.callbackAnother == null) this.$another.remove();
3200
+ else this.$another.click(function (e) {
3201
+ e.preventDefault();
3202
+ e.stopPropagation();
3203
+ handle?.intent?.onAnother?.(handler.selected);
3204
+ handle?.close();
3205
+ return false;
3206
+ });
3207
+
3208
+ const min = this.intentData?.minSelection ?? 0;
3209
+ if (min > 0 && this.$selected.length < min) this.$confirm.prop(m.d, true);
3210
+
3211
+ this.$confirm.focus();
3212
+ }
3213
+
3214
+ onFocus(handle) {
3215
+ this.$confirm.focus();
3216
+ }
3217
+
3218
+ checkValidSelectAction(handle, handler, index, value, checked) {
3219
+ const intentData = handler.intentData;
3220
+ const min = intentData?.minSelection ?? 0;
3221
+ const max = intentData?.maxSelection ?? -1;
3222
+ const $selected = this.$selected;
3223
+ const length = $selected.length;
3224
+
3225
+ if (max > -1) {
3226
+ if (length >= max) this.$unselected.prop(m.d, true);
3227
+ else this.$disabled.prop(m.d, false);
3228
+ }
3229
+ this.$confirm.prop(m.d, length < min);
3230
+
3231
+ return checked ? max < 0 || length <= max : true;
3232
+ }
3233
+ }
3234
+
3235
+ class EstreDialsDialogPageHandler extends EstreDialogPageHandler {
3236
+ $dial;
3237
+ dialHandle;
3238
+
3239
+ $confirm;
3240
+ $another;
3241
+
3242
+ onBring(handle) {
3243
+ super.onBring(handle);
3244
+
3245
+ this.$dial = handle.$host.find(uis.multiDialSlot);
3246
+
3247
+ this.$confirm = this.$actions.find(btn + cls + "confirm");
3248
+ this.$another = this.$actions.find(btn + cls + "another");
3249
+ }
3250
+
3251
+ onOpen(handle) {
3252
+ super.onOpen(handle);
3253
+
3254
+ this.intent.handle = this.dialHandle = this.$dial[0].handle;
3255
+
3256
+ handle.intent?.onSelect?.let(it => this.dialHandle.setOnSelected(it));
3257
+
3258
+ handle.intent?.data?.let(it => {
3259
+ this.$dial.css("--font-size", it.fontSize ?? "2rem");
3260
+ if (it.fontWeight != n) this.$dial.css("--font-weight", it.fontWeight);
3261
+ this.$dial.css("--item-height", it.itemHeight ?? "1.2em");
3262
+ this.$dial.css("--holder-pad", it.holderPad ?? "var(--basic-ui-inset-h)");
3263
+ if (it.holderPadL != n) this.$dial.css("--holder-pad-l", it.holderPadL);
3264
+ if (it.holderPadR != n) this.$dial.css("--holder-pad-r", it.holderPadR);
3265
+ if (it.colGap != n) this.$dial.css("--col-gap", it.colGap);
3266
+ if (it.boundGap != n) this.$dial.css("--bound-gap", it.boundGap);
3267
+ });
3268
+
3269
+ const handler = this;
3270
+
3271
+ this.$confirm.click(function (e) {
3272
+ e.preventDefault();
3273
+ e.stopPropagation();
3274
+ const { itemSelectionIndexes, itemSelectionValues } = handler.dialHandle;
3275
+ handle?.intent?.onConfirm?.(itemSelectionIndexes.mock, itemSelectionValues.mock, handle.intent?.data?.initial);
3276
+ handle?.close();
3277
+ return false;
3278
+ });
3279
+ if (handle?.intent?.data?.callbackAnother == null) this.$another.remove();
3280
+ else this.$another.click(function (e) {
3281
+ e.preventDefault();
3282
+ e.stopPropagation();
3283
+ const { itemSelectionIndexes, itemSelectionValues } = handler.dialHandle;
3284
+ handle?.intent?.onAnother?.(itemSelectionIndexes.mock, itemSelectionValues.mock, handle.intent?.data?.initial);
3285
+ handle?.close();
3286
+ return false;
3287
+ });
3288
+
3289
+ this.$confirm.focus();
3290
+ }
3291
+
3292
+ onFocus(handle) {
3293
+ this.$confirm.focus();
3294
+ }
3295
+
3296
+ onClose(handle) {
3297
+ const { itemSelectionIndexes, itemSelectionValues } = this.dialHandle;
3298
+ handle?.intent?.onDissmiss(handle.intent?.data?.initial, itemSelectionIndexes.mock, itemSelectionValues.mock);
3299
+ }
3300
+ }
3301
+
3302
+
3303
+ // ======================================================================
3304
+ // MODULE: Page Model -- EstreUiPage (PID parsing, page data model)
3305
+ // ======================================================================
3306
+
3307
+ /**
3308
+ * Pages profiling manager
3309
+ */
3310
+ /**
3311
+ * EstreUI page model. Identified by a PID (Page IDentifier) string, encapsulating the
3312
+ * component/container/article hierarchy, sectionBound (main/blind/menu/overlay/header),
3313
+ * statement (static/instant), and multi-instance status.
3314
+ *
3315
+ * PID format: `$<statement>&<sectionBound>=<component>[^][#<container>[^][@<article>[^][%<step>]]]`
3316
+ * - `$s` = static, `$i` = instant
3317
+ * - `&m` = main, `&b` = blind, `&o` = overlay, `&h` = header, `&u` = menu
3318
+ * - `^` = multi-instance
3319
+ * @class
3320
+ */
3321
+ class EstreUiPage {
3322
+
3323
+ /** @type {Object<string, typeof EstrePageHandler>} PID → page handler class mapping (built-in handlers). */
3324
+ static #pageHandlers = {
3325
+ "$s&h=appbar": class extends EstrePageHandler {
3326
+ $appTitleBtn;
3327
+ $mainMenuBtn;
3328
+ $backNavigation;
3329
+ $containerCloser;
3330
+
3331
+ $pageTitleHolder;
3332
+ $pageTitle;
3333
+
3334
+ onBring(handle) {
3335
+ this.$appTitleBtn = handle.$host.find("#appTitleBtn");
3336
+ this.$mainMenuBtn = handle.$host.find("#mainMenuBtn");
3337
+ this.$backNavigation = handle.$host.find(".back_navigation");
3338
+ this.$containerCloser = handle.$host.find(".container_closer");
3339
+
3340
+ this.$pageTitleHolder = handle.$host.find(".page_title_holder");
3341
+ this.$pageTitle = this.$pageTitleHolder.find("#pageTitle");
3342
+ }
3343
+
3344
+ onOpen(handle) {
3345
+ this.$backNavigation.click(function (e) {
3346
+ e.preventDefault();
3347
+
3348
+ estreUi.back();
3349
+ // history.back();
3350
+
3351
+ return false;
3352
+ });
3353
+ this.$containerCloser.click(function (e) {
3354
+ e.preventDefault();
3355
+
3356
+ estreUi.closeContainer();
3357
+
3358
+ return false;
3359
+ });
3360
+ }
3361
+
3362
+ setPageTitle(title) {
3363
+ this.$pageTitle.html(title);
3364
+ }
3365
+
3366
+ setAppbarLeftToolSet(frostOrCold, matchReplacer, dataName = "frozen") {
3367
+ const exactContainer = this.handle.currentOnTop;
3368
+ const $exactArticle = exactContainer?.$article?.["left"];
3369
+ const $exactToolSet = $exactArticle?.find(nv + cls + "tool_set");
3370
+ if ($exactToolSet != null) {
3371
+ const nodes = [];
3372
+ if (isNotNully(frostOrCold)) {
3373
+ for (const toolset of $exactToolSet) toolset.alone(frostOrCold, matchReplacer)?.let(it => nodes.push(...it));
3374
+ } else {
3375
+ for (const toolset of $exactToolSet) toolset.melt(matchReplacer, dataName)?.let(it => nodes.push(...it));
3376
+ }
3377
+ this.handle.applyActiveStructAfterBind($exactToolSet);
3378
+ return nodes;
3379
+ } return null;
3380
+ }
3381
+
3382
+ setAppbarRightToolSet(frostOrCold, matchReplacer, dataName = "frozen") {
3383
+ const exactContainer = this.handle.currentOnTop;
3384
+ const $exactArticle = exactContainer?.$article?.["right"];
3385
+ const $exactToolSet = $exactArticle?.find(nv + cls + "tool_set");
3386
+ if ($exactToolSet != null) {
3387
+ const nodes = [];
3388
+ if (isNotNully(frostOrCold)) {
3389
+ for (const toolset of $exactToolSet) toolset.alone(frostOrCold, matchReplacer)?.let(it => nodes.push(...it));
3390
+ } else {
3391
+ for (const toolset of $exactToolSet) toolset.melt(matchReplacer, dataName)?.let(it => nodes.push(...it));
3392
+ }
3393
+ this.handle.applyActiveStructAfterBind($exactToolSet);
3394
+ return nodes;
3395
+ } return null;
3396
+ }
3397
+ },
3398
+
3399
+
3400
+ "$i&o=functional#popupBrowser^": class extends EstrePageHandler {
3401
+ id = "popupBrowser";
3402
+
3403
+ $browserArea
3404
+ iframe;
3405
+ get cw() { return this.iframe.contentWindow; }
3406
+ get history() {
3407
+ try {
3408
+ return this.cw?.history;
3409
+ } catch (ex) {
3410
+ if (window.isLogging) console.error(ex);
3411
+ return null;
3412
+ }
3413
+ }
3414
+ get location() {
3415
+ try {
3416
+ return this.cw?.location;
3417
+ } catch (ex) {
3418
+ if (window.isLogging) console.error(ex);
3419
+ return null;
3420
+ }
3421
+ }
3422
+ get url() { return this.loction?.href; }
3423
+
3424
+ $iframe;
3425
+
3426
+ $back;
3427
+ $forward;
3428
+ $home;
3429
+ $title;
3430
+ $refresh;
3431
+ $close;
3432
+
3433
+ onBring(handle) {
3434
+ const handler = this;
3435
+
3436
+ this.$browserArea = handle.$host.find(".browser_area");
3437
+ this.iframe = doc.ce("iframe", "webView");
3438
+ this.iframe.setAttribute("name", this.intentData.name ?? "webview");
3439
+ if (this.intentData.src != null) this.iframe.setAttribute("src", this.intentData.src);
3440
+ this.$iframe = $(this.iframe);
3441
+
3442
+ this.$back = handle.$host.find("button.back");
3443
+ this.$forward = handle.$host.find("button.forward");
3444
+ this.$home = handle.$host.find("button.home");
3445
+ this.$title = handle.$host.find("span.pageTitle");
3446
+ this.$refresh = handle.$host.find("button.refresh");
3447
+ this.$close = handle.$host.find("button.close");
3448
+
3449
+ // if (this.intentData.name != null) this.$iframe.prop("name", this.intentData.name);
3450
+
3451
+ this.$iframe.on("load", function (e) {
3452
+ let url = null;
3453
+ try {
3454
+ url = this.contentWindow.location.href;
3455
+ } catch (ex) {
3456
+ if (window.isLogging) console.error(ex);
3457
+ }
3458
+ let title = "";
3459
+ try {
3460
+ title = this.contentWindow.document.title;
3461
+ } catch (ex) {
3462
+ if (window.isLogging) console.error(ex);
3463
+ }
3464
+
3465
+ if (handler.intentData.fixedTitle == null) handler.$title.text(title);
3466
+
3467
+ handle.intent.onLoad(handle, this, url);
3468
+ });
3469
+
3470
+ if (this.intentData.hideBack) this.$back.hide();
3471
+ if (this.intentData.hideForward) this.$forward.hide();
3472
+ if (this.intentData.hideHome || this.intentData.src == null) this.$home.hide();
3473
+ if (this.intentData.hideRefresh) this.$refresh.hide();
3474
+ }
3475
+
3476
+ onOpen(handle) {
3477
+ const handler = this;
3478
+
3479
+ if (this.intentData.fixedTitle != null) this.$title.text(this.intentData.fixedTitle);
3480
+
3481
+ this.$back.click(function (e) {
3482
+ if (!handler.intent.onClickBack?.(handle, handler.iframe, handler.url)) handler.history?.back();
3483
+ });
3484
+ this.$forward.click(function (e) {
3485
+ if (!handler.intent.onClickForward?.(handle, handler.iframe, handler.url)) handler.history?.forward();
3486
+ });
3487
+ this.$home.click(function (e) {
3488
+ handler.iframe.src = handler.intentData.src;
3489
+ });
3490
+ this.$refresh.click(function (e) {
3491
+ if (!handler.intent.onClickRefresh?.(handle, handler.iframe, handler.url)) handler.history?.reload();
3492
+ });
3493
+ this.$close.click(function (e) {
3494
+ handle.close();
3495
+ });
3496
+
3497
+ this.intent.onBeforeAttach(handle, this.iframe);
3498
+ this.$browserArea.append(this.$iframe);
3499
+ this.intent.onAfterAttach(handle, this.iframe, this.url);
3500
+ }
3501
+
3502
+ onReload(handle) {
3503
+ if (this.intentData.hideRefresh || this.intent.onClickRefresh(handle, this.iframe, this.url)) this.history?.reload();
3504
+
3505
+ return true;
3506
+ }
3507
+
3508
+ async onBack(handle) {
3509
+ return await handle.close();
3510
+ }
3511
+
3512
+ onClose(handle) {
3513
+ this.intent.onClosePopup?.(handle, this.iframe, this.url);
3514
+ }
3515
+ },
3516
+
3517
+ "$i&o=toastUpSlide#alert^": class extends EstreAlertDialogPageHandler {
3518
+
3519
+ },
3520
+ "$i&o=toastUpSlide#confirm^": class extends EstreConfirmDialogPageHandler {
3521
+
3522
+ },
3523
+ "$i&o=toastUpSlide#prompt^": class extends EstrePromptDialogPageHandler {
3524
+
3525
+ },
3526
+ "$i&o=toastUpSlide#option^": class extends EstreOptionDialogPageHandler {
3527
+
3528
+ },
3529
+ "$i&o=toastUpSlide#selection^": class extends EstreSelectionDialogPageHandler {
3530
+
3531
+ },
3532
+ "$i&o=toastUpSlide#dials^": class extends EstreDialsDialogPageHandler {
3533
+
3534
+ },
3535
+
3536
+ "$i&o=interaction#onRunning^": class extends EstreLottieAnimatedHandler {
3537
+ isTriggeredCancellation = f;
3538
+
3539
+ onBack(handle) {
3540
+ const cancellationExceeds = this.intentData?.cancellationExceeds ?? 3;
3541
+ if (this.isTriggeredCancellation || this.intentData?.blockBack) {
3542
+ return true;
3543
+ } else if (backHolds < cancellationExceeds - 1) {
3544
+ return onBackWhile(handle);
3545
+ } else if (backHolds == cancellationExceeds - 1) {
3546
+ // const instanceOrigin = latestIO;
3547
+ backHolds = 0;
3548
+ this.isTriggeredCancellation = t;
3549
+ this.intentData?.callbackCancellation?.();
3550
+ // postQueue(_ => go(instanceOrigin));
3551
+ return handle.close();
3552
+ }
3553
+ }
3554
+ },
3555
+ "$i&o=interaction#onProgress^": class extends EstreLottieAnimatedHandler {
3556
+ get perfectValue() { return 1000; } // 100% value
3557
+ get zeroPosition() { return 15; } // 0% frame
3558
+ get halfPosition() { return 75; } // 50% frame
3559
+ get perfectPosition() { return 105; } // 100% frame
3560
+ get finishPosition() { return 251; } // complete frame
3561
+
3562
+ get halfValue() { return this.perfectValue / 2; } // 50% value
3563
+ get interFrames() { return this.perfectPosition - this.zeroPosition; } // progress frames
3564
+ get preFrames() { return this.halfPosition - this.zeroPosition; } // second half frames
3565
+ get postFrames() { return this.perfectPosition - this.halfPosition; } // second half frames
3566
+
3567
+ isRunning = false;
3568
+
3569
+ onBring(handle) {
3570
+ super.onBring(handle);
3571
+
3572
+ const intentData = handle.intent.data;
3573
+ intentData.binded = new class {
3574
+ instanceOrigin = intentData.instanceOrigin;
3575
+ #current = intentData.current ?? 0;
3576
+
3577
+ get current() { return this.#current; }
3578
+ set current(value) {
3579
+ handle.handler.applyProgress(value, this.#current);
3580
+ this.#current = value;
3581
+ }
3582
+ }
3583
+ }
3584
+
3585
+ onOpen(handle) {
3586
+ this.lottie?.addEventListener("ready", function (e) {
3587
+ const player = this.getLottie();
3588
+ if (player != null) {
3589
+ player.setSegment(0, handle.handler.zeroPosition);
3590
+ player.addEventListener("complete", function (e) {
3591
+ handle.handler.isRunning = false;
3592
+ if (window.isVerbosely) console.log("onComplete: ", player.firstFrame + player.currentFrame);
3593
+ if (handle.intent.data.binded?.current == null) {
3594
+ handle.close();
3595
+ }
3596
+ });
3597
+ player.goToAndPlay(0, true);
3598
+ handle.handler.isRunning = true;
3599
+ }
3600
+ });
3601
+ }
3602
+
3603
+ onShow(handle) {
3604
+ if (this.isRunning) this.player?.play();
3605
+ }
3606
+
3607
+ onHide(handle) {
3608
+ if (this.isRunning) this.player?.pause();
3609
+ }
3610
+
3611
+ applyProgress(value, current) {
3612
+ const val = parseInt(value);
3613
+ const player = this.player;
3614
+
3615
+ if (player != null) {
3616
+ player.pause();
3617
+ if (window.isVerbosely) console.log(value, current, player.firstFrame, player.currentFrame, player.firstFrame + player.currentFrame);
3618
+
3619
+ const begin = player.firstFrame + player.currentFrame;//this.zeroPosition + parseInt(this.interFrames * (parseInt(current) / this.perfectValue));
3620
+ const end = value != null ?
3621
+ this.zeroPosition + (val < this.halfValue ?
3622
+ parseInt(this.preFrames * (val / this.halfValue)) :
3623
+ this.preFrames + parseInt(this.postFrames * ((val - this.halfValue) / this.halfValue))
3624
+ ) : this.finishPosition;
3625
+
3626
+ const isForward = end >= begin;
3627
+
3628
+ if (window.isVerbosely) console.log("begin: " + begin + ", end: " + end + ", isForward: " + isForward);
3629
+
3630
+ if (isForward) player.setSegment(begin, end);
3631
+ else player.setSegment(end, begin);
3632
+ player.setDirection(isForward ? 1 : -1);
3633
+ player.goToAndPlay(isForward ? 0 : player.totalFrames, true);
3634
+ this.isRunning = true;
3635
+ }
3636
+ }
3637
+ },
3638
+
3639
+ "$i&o=interaction#alert^": class extends EstreAlertDialogPageHandler {
3640
+
3641
+ },
3642
+ "$i&o=interaction#confirm^": class extends EstreConfirmDialogPageHandler {
3643
+
3644
+ },
3645
+ "$i&o=interaction#prompt^": class extends EstrePromptDialogPageHandler {
3646
+
3647
+ },
3648
+ "$i&o=interaction#option^": class extends EstreOptionDialogPageHandler {
3649
+
3650
+ },
3651
+ "$i&o=interaction#selection^": class extends EstreSelectionDialogPageHandler {
3652
+
3653
+ },
3654
+
3655
+ "$i&o=notification#noti@noti^": class extends EstrePageHandler { },
3656
+ "$i&o=notification#note@note^": class extends EstrePageHandler {
3657
+ $postBlock;
3658
+
3659
+ onBring(handle) {
3660
+ this.$postBlock = handle.$host.find(".post_block");
3661
+ EstreNotationManager.current = handle.intent;
3662
+ if (window.isVerbosely) console.log("pushed", handle.intent);
3663
+ }
3664
+
3665
+ onOpen(handle) {
3666
+ this.$postBlock.click(function (e) {
3667
+ e.preventDefault();
3668
+
3669
+ if (window.isVerbosely) console.log("clicked: ", handle.intent);
3670
+ handle.intent?.onTakeInteraction?.(handle.intent);
3671
+
3672
+ return false;
3673
+ });
3674
+
3675
+ if (window.isVerbosely) console.log("showing: ", handle.intent);
3676
+ setTimeout(_ => handle.close(), handle.intent?.data?.showTime ?? 3000);
3677
+ }
3678
+
3679
+ onClose(handle) {
3680
+ EstreNotationManager.checkOut(handle.intent);
3681
+ }
3682
+ },
3683
+
3684
+ "$s&o=operation#root@timeline": class extends EstrePageHandler { },
3685
+ "$s&o=operation#root@quickPanel": class extends EstrePageHandler { },
3686
+
3687
+ };
3688
+ /** @type {Object<string, typeof EstrePageHandler>} Custom-registered page handlers (merged into #pageHandlers on commit). */
3689
+ static #registeredPageHandlers = {};
3690
+
3691
+ /** @type {*} Custom page provider (registered by EstreUiCustomPageManager). */
3692
+ static #customPagesProvider = null;
3693
+ static get provider() { return this.#customPagesProvider; }
3694
+
3695
+ /** @type {boolean} true after commit() has been called. */
3696
+ static #handlerCommited = false;
3697
+ static get handlerCommited() { return this.#handlerCommited; }
3698
+
3699
+ /**
3700
+ * Registers a custom page provider. Can only be called once, before commit.
3701
+ * @param {*} provider - The provider object.
3702
+ */
3703
+ static registerProvider(provider) {
3704
+ if (!this.#handlerCommited && this.#customPagesProvider == null) {
3705
+ this.#customPagesProvider = provider;
3706
+ }
3707
+ }
3708
+
3709
+ /**
3710
+ * Registers a page handler for a PID. Can only be called before commit.
3711
+ * @param {string} pid - Target PID.
3712
+ * @param {typeof EstrePageHandler} handler - Page handler class.
3713
+ */
3714
+ static registerHandler(pid, handler) {
3715
+ if (!this.#handlerCommited && this.#registeredPageHandlers[pid] == null) {
3716
+ this.#registeredPageHandlers[pid] = handler;
3717
+ }
3718
+ }
3719
+
3720
+ /** Commits handler registration. Subsequent registerHandler() calls are ignored. */
3721
+ static commit() {
3722
+ this.#handlerCommited = true;
3723
+
3724
+ for (const pid in this.#registeredPageHandlers) this.#pageHandlers[pid] = this.#registeredPageHandlers[pid];
3725
+ }
3726
+
3727
+
3728
+ /**
3729
+ * Strips the statement prefix (`$s`, `$i`) from a PID.
3730
+ * @param {string} pid
3731
+ * @returns {string}
3732
+ */
3733
+ static getPidStatementless(pid) {
3734
+ return pid.replace(/^\$\w/, "");
3735
+ }
3736
+
3737
+ /**
3738
+ * Strips the instance origin (everything after `^`) from a PID.
3739
+ * @param {string} pid
3740
+ * @returns {string}
3741
+ */
3742
+ static getPidOriginless(pid) {
3743
+ return pid.split("^")[0];
3744
+ }
3745
+
3746
+ /**
3747
+ * Strips both the statement prefix and instance origin from a PID.
3748
+ * @param {string} pid
3749
+ * @returns {string}
3750
+ */
3751
+ static getPidSeamless(pid) {
3752
+ return this.getPidOriginless(this.getPidStatementless(pid));
3753
+ }
3754
+
3755
+ /**
3756
+ * Searches for a handler class matching the PID. Falls back: full PID → statementless → originless → seamless.
3757
+ * @param {string} pid
3758
+ * @returns {typeof EstrePageHandler|undefined}
3759
+ */
3760
+ static foundHandler(pid) {
3761
+ let handler = this.#pageHandlers[pid];
3762
+ if (handler != null) return handler;
3763
+ const slpid = this.getPidStatementless(pid)
3764
+ handler = this.#pageHandlers[slpid];
3765
+ if (handler != null) return handler;
3766
+ const olpid = this.getPidOriginless(pid);
3767
+ handler = this.#pageHandlers[olpid];
3768
+ if (handler != null) return handler;
3769
+ const spid = this.getPidOriginless(slpid);
3770
+ handler = this.#pageHandlers[spid];
3771
+ return handler;
3772
+ }
3773
+
3774
+ /**
3775
+ * Returns the handler class matching the PID.
3776
+ * @param {string} pid
3777
+ * @returns {typeof EstrePageHandler|undefined}
3778
+ */
3779
+ static getHandler(pid) {
3780
+ return this.foundHandler(pid);
3781
+ }
3782
+
3783
+
3784
+ /** @type {Element|null} The original (raw) DOM element. */
3785
+ #raw = null;
3786
+ get raw() { return this.#raw; }
3787
+ /** @type {*} Doctre cold format data. */
3788
+ #cold = null;
3789
+ get cold() { return this.#cold; }
3790
+ /** @type {Element|undefined} The cold data restored to a live DOM element. */
3791
+ get live() { return this.cold?.let(it => Doctre.live(it)); }
3792
+
3793
+ #componentStatement = null;//static/instant
3794
+ #containerStatement = null;//static/instant
3795
+ #articleStatement = null;//static/instant
3796
+
3797
+ get componentStatement() { return this.#componentStatement; }
3798
+ get containerStatement() { return this.#containerStatement; }
3799
+ get articleStatement() { return this.#articleStatement; }
3800
+
3801
+ get componentIsInatant() { return this.componentStatement == "instant"; }
3802
+ get componentIsStatic() { return this.componentStatement == "static"; }
3803
+ get containerIsInatant() { return this.containerStatement == "instant"; }
3804
+ get containerIsStatic() { return this.containerStatement == "static"; }
3805
+ get articleIsInatant() { return this.articleStatement == "instant"; }
3806
+ get articleIsStatic() { return this.articleStatement == "static"; }
3807
+
3808
+ get statement() {
3809
+ if (this.#articleStatement != null) return this.#articleStatement;
3810
+ else if (this.#containerStatement != null) return this.#containerStatement;
3811
+ else if (this.#componentStatement != null) return this.#componentStatement;
3812
+ else return null;
3813
+ }
3814
+ get isInstant() { return this.statement == "instant"; }
3815
+ get isStatic() { return this.statement == "static"; }
3816
+ get isFullyStatic() {
3817
+ switch (this.hostType) {
3818
+ case "article":
3819
+ if (this.articleStatement == null) return null;
3820
+ else if (this.articleStatement != "static") return false;
3821
+ case "container":
3822
+ if (this.containerStatement == null) return null;
3823
+ else if (this.containerStatement != "static") return false;
3824
+ case "component":
3825
+ if (this.componentStatement == null) return null;
3826
+ else if (this.componentStatement != "static") return false;
3827
+ return true;
3828
+
3829
+ default:
3830
+ return null;
3831
+ }
3832
+ }
3833
+
3834
+ #componentIsMultiInstance = null;
3835
+ #containerIsMultiInstance = null;
3836
+ #articleIsMultiInstance = null;
3837
+
3838
+ get componentIsMultiInstance() { return this.#componentIsMultiInstance; }
3839
+ get containerIsMultiInstance() { return this.#containerIsMultiInstance; }
3840
+ get articleIsMultiInstance() { return this.#articleIsMultiInstance; }
3841
+
3842
+ get isMultiInstance() {
3843
+ if (this.#articleIsMultiInstance != null) return this.#articleIsMultiInstance;
3844
+ else if (this.#containerIsMultiInstance != null) return this.#containerIsMultiInstance;
3845
+ else if (this.#componentIsMultiInstance != null) return this.#componentIsMultiInstance;
3846
+ else return null;
3847
+ }
3848
+
3849
+ #sectionBound = null;//main/blind/menu/overlay
3850
+ get sectionBound() { return this.#sectionBound; }
3851
+ get isOverlay() { return this.sectionBound == "overlay"; }
3852
+ get isBlinded() { return this.sectionBound == "blind"; }
3853
+ get isMain() { return this.sectionBound == "main"; }
3854
+ get isMenu() { return this.sectionBound == "menu"; }
3855
+ get isHeader() { return this.sectionBound == "header"; }
3856
+
3857
+ get sections() {
3858
+ switch (this.sectionBound) {
3859
+ case "overlay":
3860
+ return estreUi.overlaySections;
3861
+
3862
+ case "blind":
3863
+ return estreUi.blindSections;
3864
+
3865
+ case "main":
3866
+ return estreUi.mainSections;
3867
+
3868
+ case "menu":
3869
+ return estreUi.menuSections;
3870
+
3871
+ case "header":
3872
+ return estreUi.headerSections;
3873
+ }
3874
+ }
3875
+
3876
+ #component = null;
3877
+ #container = null;
3878
+ #article = null;
3879
+
3880
+ get component() { return this.#component; }
3881
+ get container() { return this.#container; }
3882
+ get article() { return this.#article; }
3883
+
3884
+ get isComponent() { return this.component != null && this.container == null && this.article == null; }
3885
+ get isContainer() { return this.component != null && this.container != null && this.article == null; }
3886
+ get isArticle() { return this.component != null && this.container != null && this.article != null; }
3887
+
3888
+ get id() {
3889
+ if (this.#article != null) return this.#article;
3890
+ else if (this.#container != null) return this.#container;
3891
+ else if (this.#component != null) return this.#component;
3892
+ else return null;
3893
+ }
3894
+
3895
+ #componentInstanceOrigin;
3896
+ #containerInstanceOrigin;
3897
+ #articleInstanceOrigin;
3898
+
3899
+ get componentInstanceOrigin() { return this.#componentInstanceOrigin; }
3900
+ get containerInstanceOrigin() { return this.#containerInstanceOrigin; }
3901
+ get articleInstanceOrigin() { return this.#articleInstanceOrigin; }
3902
+
3903
+ get instanceOrigin() {
3904
+ if (this.#article != null) return this.#articleInstanceOrigin;
3905
+ else if (this.#container != null) return this.#containerInstanceOrigin;
3906
+ else if (this.#component != null) return this.#componentInstanceOrigin;
3907
+ else return null;
3908
+ }
3909
+
3910
+ get componentInstanceId() { return this.#componentIsMultiInstance ? this.#component + "^" + this.#componentInstanceOrigin : this.component; }
3911
+ get containerInstanceId() { return this.#containerIsMultiInstance ? this.#container + "^" + this.#containerInstanceOrigin : this.container; }
3912
+ get articleInstanceId() { return this.#articleIsMultiInstance ? this.#article + "^" + this.#articleInstanceOrigin : this.article; }
3913
+
3914
+ #instances = [];
3915
+ get instances() { return this.#instances; }
3916
+
3917
+ #$component = null;
3918
+ #$container = null;
3919
+ #$article = null;
3920
+
3921
+ get componentRefer() {
3922
+ switch (this.#sectionBound) {
3923
+ case "header":
3924
+ return estreUi.headerSections[this.id];
3925
+
3926
+ case "menu":
3927
+ return estreUi.menuSections[this.id];
3928
+
3929
+ case "main":
3930
+ return estreUi.mainSections[this.id];
3931
+
3932
+ case "blind":
3933
+ return estreUi.blindSections[this.id];
3934
+
3935
+ case "overlay":
3936
+ return estreUi.overlaySections[this.id];
3937
+
3938
+ default:
3939
+ return null;
3940
+ }
3941
+ }
3942
+ get $component() { return this.#$component; }
3943
+ get $container() { return this.#$container; }
3944
+ get $article() { return this.#$article; }
3945
+
3946
+ get $element() {
3947
+ if (this.#article != null) return this.#$article;
3948
+ else if (this.#container != null) return this.#$container;
3949
+ else if (this.#component != null) return this.#$component;
3950
+ else return null;
3951
+ }
3952
+ get hostType() {
3953
+ if (this.#article != null) return "article";
3954
+ else if (this.#container != null) return "container";
3955
+ else if (this.#component != null) return "component";
3956
+ else return null;
3957
+ }
3958
+
3959
+
3960
+ #commited = false;
3961
+
3962
+ get pid() {
3963
+ var pid = "";
3964
+ pid += "$" + (this.statement == "static" ? "s" : (this.statement == "instant" ? "i" : ""));
3965
+ pid += "&" + (this.sectionBound == "main" ? "m" : (this.sectionBound == "blind" ? "b" : (this.sectionBound == "overlay" ? "o" : (this.sectionBound == "header" ? "h" : (this.sectionBound == "menu" ? "u" : "")))));
3966
+ pid += "=";
3967
+ pid += this.#component;
3968
+ if (this.#componentIsMultiInstance) pid += "^";
3969
+ if (this.#container != null) {
3970
+ pid += "#" + this.#container;
3971
+ if (this.#containerIsMultiInstance) pid += "^";
3972
+ }
3973
+ if (this.#article != null) {
3974
+ pid += "@" + this.#article;
3975
+ if (this.#articleIsMultiInstance) pid += "^";
3976
+ }
3977
+ return pid;
3978
+ }
3979
+
3980
+ get instancePid() {
3981
+ var pid = "";
3982
+ pid += "$" + (this.statement == "static" ? "s" : (this.statement == "instant" ? "i" : ""));
3983
+ pid += "&" + (this.sectionBound == "main" ? "m" : (this.sectionBound == "blind" ? "b" : (this.sectionBound == "overlay" ? "o" : (this.sectionBound == "header" ? "h" : (this.sectionBound == "menu" ? "u" : "")))));
3984
+ pid += "=";
3985
+ pid += this.componentInstanceId;
3986
+ if (this.#container != null) pid += "#" + this.containerInstanceId;
3987
+ if (this.#article != null) pid += "@" + this.articleInstanceId;
3988
+ return pid;
3989
+ }
3990
+
3991
+ /**
3992
+ * Builds a component-level PID.
3993
+ * @param {string} id - Component ID.
3994
+ * @param {string} sectionBound - Section bound ("main"|"blind"|"overlay"|"header"|"menu").
3995
+ * @param {string} [statement] - "instant" or "static".
3996
+ * @returns {string|null} The generated PID, or null if invalid.
3997
+ */
3998
+ static getPidComponent(id, sectionBound, statement) {
3999
+ const stc = statement == "instant" ? "$i" : (statement == "static" ? "$s" : "");
4000
+ const sbc = sectionBound == "main" ? "&m" : (sectionBound == "blind" ? "&b" : (sectionBound == "overlay" ? "&o" : (sectionBound == "header" ? "&h" : (sectionBound == "menu" ? "&u" : null))));
4001
+ if (id != null && id != "" && sbc != null) return stc + sbc + "=" + id;
4002
+ else return null;
4003
+ }
4004
+
4005
+ /**
4006
+ * Builds a container-level PID.
4007
+ * @param {string} id - Container ID.
4008
+ * @param {string} componentId - Parent component ID.
4009
+ * @param {string} [sectionBound] - Section bound.
4010
+ * @param {string} [statement] - "instant" or "static".
4011
+ * @returns {string|undefined}
4012
+ */
4013
+ static getPidContainer(id, componentId, sectionBound, statement) {
4014
+ const basePid = this.getPidComponent(componentId, sectionBound, statement);
4015
+ if (basePid != null) return basePid + "#" + id;
4016
+ }
4017
+
4018
+ /**
4019
+ * Builds an article-level PID.
4020
+ * @param {string} id - Article ID.
4021
+ * @param {string} containerId - Parent container ID.
4022
+ * @param {string} componentId - Parent component ID.
4023
+ * @param {string} [sectionBound] - Section bound.
4024
+ * @param {string} [statement] - "instant" or "static".
4025
+ * @returns {string|undefined}
4026
+ */
4027
+ static getPidArticle(id, containerId, componentId, sectionBound, statement) {
4028
+ const basePid = this.getPidContainer(containerId, componentId, sectionBound, statement);
4029
+ if (basePid != null) return basePid + "@" + id;
4030
+ }
4031
+
4032
+ /**
4033
+ * Creates an EstreUiPage from a DOM element and registers or commits it.
4034
+ * @param {jQuery|Element} $element - Target element.
4035
+ * @returns {EstreUiPage}
4036
+ */
4037
+ static registerOrCommitFrom($element) {
4038
+ return this.registerOrCommit(this.from($element));
4039
+ }
4040
+
4041
+ /**
4042
+ * Registers an EstreUiPage with the page manager, or adds an instance if already registered.
4043
+ * @param {EstreUiPage} euiPage - Target page.
4044
+ * @returns {EstreUiPage}
4045
+ */
4046
+ static registerOrCommit(euiPage) {
4047
+ const exist = pageManager.get(euiPage.pid);
4048
+ if (exist == null) return euiPage.commit();
4049
+ else if (euiPage.statement == "instant") return exist.register(euiPage.$element);
4050
+ else return euiPage;
4051
+ }
4052
+
4053
+ /**
4054
+ * Unregisters a page instance from a DOM element or page handle.
4055
+ * @param {jQuery|Element|EstrePageHandle} $element - Target element or handle.
4056
+ * @param {string} [pid] - PID (auto-extracted when an EstrePageHandle is passed).
4057
+ * @returns {boolean}
4058
+ */
4059
+ static unregisterFrom($element, pid) {
4060
+ if ($element instanceof EstrePageHandle) {
4061
+ pid = $element.pid;
4062
+ $element = $element.$host;
4063
+ } else this.from($element)?.let(euiPage => {
4064
+ pid = euiPage.pid;
4065
+ $element = euiPage.$element;
4066
+ });
4067
+ if (pid == null || $element == null) return false;
4068
+ const exist = pageManager.get(pid);
4069
+ return exist?.unregister($element);
4070
+ }
4071
+
4072
+ /**
4073
+ * Reverse-constructs an EstreUiPage from a DOM element (section/div.container/article).
4074
+ * @param {jQuery|Element|EstrePageHandle} $element - Target element.
4075
+ * @returns {EstreUiPage|null}
4076
+ */
4077
+ static from($element) {
4078
+ let element;
4079
+ if ($element instanceof EstrePageHandle) {
4080
+ element = $element.host;
4081
+ $element = $element.$host;
4082
+ } else if ($element instanceof jQuery) element = $element[0];
4083
+ else {
4084
+ element = $element;
4085
+ $element = $($element);
4086
+ }
4087
+
4088
+ if (element != null) {
4089
+ const page = new EstreUiPage();
4090
+ switch (element.tagName) {
4091
+ case AR:
4092
+ page.setArticleRefer($element);
4093
+ break;
4094
+
4095
+ case DIV:
4096
+ if (!$element.hasClass("container")) break;
4097
+ page.setContainerRefer($element);
4098
+ break;
4099
+
4100
+ case SE:
4101
+ page.setComponentRefer($element);
4102
+ break;
4103
+ }
4104
+
4105
+ return page;
4106
+ } else return null;
4107
+ }
4108
+
4109
+ constructor() {}
4110
+
4111
+ /**
4112
+ * Sets the section bound. Only callable before commit.
4113
+ * @param {string} sectionBound - "main"|"blind"|"menu"|"overlay"|"header".
4114
+ * @returns {this|false} this for chaining, or false if already committed.
4115
+ */
4116
+ setSectionBound(sectionBound) {
4117
+ if (this.#commited) return false;
4118
+ this.#sectionBound = sectionBound;
4119
+ return this;
4120
+ }
4121
+
4122
+ /**
4123
+ * Sets the component ID. Only callable before commit and when not yet set.
4124
+ * @param {string} componentId
4125
+ * @returns {this|false}
4126
+ */
4127
+ setComponent(componentId) {
4128
+ if (this.#commited) return false;
4129
+ if (this.#component == null) this.#component = componentId;
4130
+ return this;
4131
+ }
4132
+
4133
+ /**
4134
+ * Sets the container ID. Only callable before commit and when not yet set.
4135
+ * @param {string} containerId
4136
+ * @returns {this|false}
4137
+ */
4138
+ setContainer(containerId) {
4139
+ if (this.#commited) return false;
4140
+ if (this.#container == null) this.#container = containerId;
4141
+ return this;
4142
+ }
4143
+
4144
+ /**
4145
+ * Sets the article ID. Only callable before commit and when not yet set.
4146
+ * @param {string} articleId
4147
+ * @returns {this|false}
4148
+ */
4149
+ setArticle(articleId) {
4150
+ if (this.#commited) return false;
4151
+ if (this.#article == null) this.#article = articleId;
4152
+ return this;
4153
+ }
4154
+
4155
+ /**
4156
+ * Sets the multi-instance origin. If an array, order is [component, container, article]; otherwise distributed by hostType.
4157
+ * @param {string|string[]} [instanceOrigin] - Instance origin.
4158
+ */
4159
+ setInstanceOrigin(instanceOrigin) {
4160
+ if (isArray(instanceOrigin)) {
4161
+ this.#componentInstanceOrigin = instanceOrigin[0];
4162
+ this.#containerInstanceOrigin = instanceOrigin[1];
4163
+ this.#articleInstanceOrigin = instanceOrigin[2];
4164
+ } else equalCase(this.hostType, {
4165
+ "component": _ => this.#componentInstanceOrigin = instanceOrigin,
4166
+ "container": _ => this.#containerInstanceOrigin = instanceOrigin,
4167
+ "article": _ => this.#articleInstanceOrigin = instanceOrigin,
4168
+ });
4169
+ }
4170
+
4171
+ setComponentRefer($component) {
4172
+ if (this.#commited) return false;
4173
+
4174
+ try {
4175
+ this.setComponent($component[0].id);
4176
+ } catch (ex) {
4177
+ if (window.isDebug) console.error(ex);
4178
+ return null;
4179
+ }
4180
+
4181
+ this.#componentStatement = $component.attr(eds.static) == t1 ? "static" : "instant";
4182
+ this.#componentIsMultiInstance = $component.attr(eds.multiInstance) == t1;
4183
+ this.#componentInstanceOrigin = $component.attr(eds.instanceOrigin)?.ifEmpty(_ => u);
4184
+
4185
+ if (this.#sectionBound == null) {
4186
+ const $componentHost = $component.closest("main, nav, header, footer");
4187
+ const hostId = $componentHost.attr("id");
4188
+ const sectionBound = hostId == "staticDoc" ? "main" : (hostId == "instantDoc" ? "blind" : (hostId == "managedOverlay" ? "overlay" : (hostId == "mainMenu" ? "menu" : (hostId == "fixedTop" ? "header" : null))));
4189
+ this.setSectionBound(sectionBound);
4190
+ }
4191
+
4192
+ this.#$component = $component;
4193
+
4194
+ return this;
4195
+ }
4196
+
4197
+ setContainerRefer($container, $component) {
4198
+ if (this.#commited) return false;
4199
+
4200
+ try {
4201
+ this.setContainer($container.attr(eds.containerId));
4202
+ } catch (ex) {
4203
+ if (window.isDebug) console.error(ex);
4204
+ return null;
4205
+ }
4206
+
4207
+ this.#containerStatement = $container.attr(eds.static) == t1 ? "static" : "instant";
4208
+ this.#containerIsMultiInstance = $container.attr(eds.multiInstance) == t1;
4209
+ this.#containerInstanceOrigin = $container.attr(eds.instanceOrigin)?.ifEmpty(_ => u);
4210
+
4211
+ if ($component == null) $component = $container.closest("section");
4212
+
4213
+ this.setComponentRefer($component);
4214
+
4215
+ this.#$container = $container;
4216
+
4217
+ return this;
4218
+ }
4219
+
4220
+ setArticleRefer($article, $container, $component) {
4221
+ if (this.#commited) return false;
4222
+
4223
+ try {
4224
+ this.setArticle($article.attr(eds.articleId));
4225
+ } catch (ex) {
4226
+ if (window.isDebug) console.error(ex);
4227
+ return null;
4228
+ }
4229
+
4230
+ this.#articleStatement = $article.attr(eds.static) == t1 ? "static" : "instant";
4231
+ this.#articleIsMultiInstance = $article.attr(eds.multiInstance) == t1;
4232
+ this.#articleInstanceOrigin = $article.attr(eds.instanceOrigin)?.ifEmpty(_ => u);
4233
+
4234
+ if ($container == null) $container = $article.closest("div.container");
4235
+
4236
+ this.setContainerRefer($container, $component);
4237
+
4238
+ this.#$article = $article;
4239
+
4240
+ return this;
4241
+ }
4242
+
4243
+ #checkRegisterSubPages() {
4244
+ if (this.#commited) return false;
4245
+ let $subPages;
4246
+ if (this.#container == null) $subPages = this.#$component.find(c.c + div + uis.container);
4247
+ else if (this.#article == null) $subPages = this.#$container.find(c.c + ar);
4248
+ else return;
4249
+
4250
+ for (var page of $subPages) EstreUiPage.registerOrCommitFrom(page);
4251
+ }
4252
+
4253
+ #pushInstance(host) {
4254
+ let $host;
4255
+ if (host instanceof jQuery) {
4256
+ $host = host;
4257
+ host = $host[0];
4258
+ } else $host = $(host);
4259
+
4260
+ this.#instances.push(host);
4261
+
4262
+ this.fetchHandler(host.pageHandle);
4263
+ }
4264
+
4265
+ fetchHandler(pageHandle) {
4266
+ const handler = EstreUiPage.getHandler(this.pid);
4267
+ if (window.isVerbosely) console.log("pushInstance - " + this.pid + "[" + handle?.handler + "]", handle, handler);
4268
+ if (pageHandle != null && handler != null && typeof handler == "function") {
4269
+ return pageHandle.setHandler(new handler(pageHandle, EstreUiPage.provider));
4270
+ }
4271
+ }
4272
+
4273
+ #sampleHTML() {
4274
+ if (this.#commited || this.#raw != null) return false;
4275
+ const $element = this.$element;
4276
+ const element = $element[0];
4277
+ this.#raw = element.outerHTML;
4278
+ this.#cold = element.coldify(true, true, false, false);
4279
+ if (this.statement == "instant") {
4280
+ $element.remove();
4281
+ return null;
4282
+ } else return this.#raw;
4283
+ }
4284
+
4285
+ commit() {
4286
+ if (this.#commited) return false;
4287
+ pageManager.register(this);
4288
+ if (this.isFullyStatic) this.#pushInstance(this.$element);
4289
+ if (this.#article == null) this.#checkRegisterSubPages();
4290
+ const removed = this.#sampleHTML() == null;
4291
+ this.#commited = true;
4292
+ if (removed) return false;
4293
+ else return this;
4294
+ }
4295
+
4296
+ register($instance) {
4297
+ if (this.isFullyStatic) return false;
4298
+ if ($instance instanceof jQuery) for (var item of $instance) this.#pushInstance(item);
4299
+ else if ($instance instanceof Element) this.#pushInstance($instance);
4300
+ else return;
4301
+ return this;
4302
+ }
4303
+
4304
+ unregister($instance) {
4305
+ if (this.isFullyStatic) return false;
4306
+ if ($instance instanceof jQuery) for (var item of $instance) this.unregister(item);
4307
+ else if ($instance instanceof Element) {
4308
+ const index = this.#instances.indexOf($instance);
4309
+ this.#instances.splice(index, 1);
4310
+ } else return;
4311
+ return this.#instances;
4312
+ }
4313
+
4314
+ }
4315
+
4316
+
4317
+ // ======================================================================