estreui 1.0.7 → 1.1.0

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.
@@ -20,6 +20,9 @@ const uis = {
20
20
  dotlottieLoader: "dotlottie-loader",
21
21
 
22
22
  // rim ui //
23
+ prefix: ".prefix",
24
+ suffix: ".suffix",
25
+ divider: ".divider",
23
26
 
24
27
  // component //
25
28
  container: ".container",
@@ -158,6 +161,20 @@ const uis = {
158
161
  paddedDate: ".padded_date",
159
162
  shortDay: ".short_day",
160
163
 
164
+ // live timestamp
165
+ liveTimestamp: "[data-live-timestamp]",
166
+
167
+
168
+ // on click set text
169
+ onClickSetText: "[data-on-click-set-text]",
170
+
171
+ // on click set html
172
+ onClickSetHtml: "[data-on-click-set-html]",
173
+
174
+
175
+ // help alert
176
+ dataHelpAlert: "[data-help-alert]",
177
+
161
178
  // num keypad
162
179
  numKeypad: ".num_keypad",
163
180
 
@@ -170,6 +187,12 @@ const uis = {
170
187
  // toaster slot
171
188
  toasterSlot: ".toaster_slot",
172
189
 
190
+ // multi dial slot
191
+ multiDialSlot: ".multi_dial_slot",
192
+ dialHolder: ".dialHolder",
193
+ dialBound: ".dial_bound",
194
+ dialHost: ".dial_host",
195
+
173
196
 
174
197
  // exported content
175
198
  exportedContent: ".exported_content",
@@ -313,6 +336,8 @@ const eds = {
313
336
  options: "data-options",
314
337
  code: "data-code",
315
338
  value: "data-value",
339
+ align: "data-align",
340
+ initial: "data-initial",
316
341
  intersectionRootMargin: "data-intersection-root-margin",
317
342
  intersectionThreshold: "data-intersection-threshold",
318
343
 
@@ -402,12 +427,32 @@ const eds = {
402
427
  withPrefix: "data-with-prefix",
403
428
  withSuffix: "data-with-suffix",
404
429
 
430
+ // for live timestamp
431
+ liveTimestamp: "data-live-timestamp",
432
+ shortSuffix: "data-short-suffix",
433
+
434
+
435
+ // for on click set text
436
+ onClickSetText: "data-on-click-set-text",
437
+
438
+ // for on click set html
439
+ onClickSetHtml: "data-on-click-set-html",
440
+
441
+
405
442
  // for month selector bar
406
443
  dropdownOpen: "data-dropdown-open",
407
444
  showFuture: "data-show-future",
408
445
  usePopupSelector: "data-use-popup-selector",
409
446
 
410
447
 
448
+ // multi dial slot
449
+ itemTable: "data-item-table", // [['item1', 'item2', 'item3', ...], ['item1', 'item2', 'item3', ...], ...]
450
+ itemAligns: "data-item-aligns", // [t, n, f, ...] :: f: left, n: center, t: right
451
+ itemPrefixes: "data-item-prefixes", // ['prefix1', 'prefix2', ...]
452
+ itemSuffixes: "data-item-suffixes", // ['suffix1', 'suffix2', ...]
453
+ itemDividers: "data-item-dividers", // ['before', 'dividerForAll', 'after'] / ['divider0', 'divider1', ...]
454
+
455
+
411
456
  // for solid point
412
457
  solid: "data-solid",
413
458
 
@@ -662,6 +707,74 @@ const selectionToast = (options = ["option A", "option B", "option C"],
662
707
  ) => toastSelection(title, message, minSelection, maxSelection, options, defaultSelected, callbackConfirm, callbackSelect, callbackDissmiss, callbackAnother, confirm, another);
663
708
 
664
709
 
710
+ function estreToastDials(options = {}) {
711
+ const arrays = [c.table, c.initial, c.aligns, c.prefixes, c.suffixes, c.dividers];
712
+ for (const name of arrays) if (!typeString(options[name])) options[name] = Jcodd.coddify(options[name]);
713
+ options.stretch = !options.stretch ? "" : t1;
714
+ options.hideScrollbar = !options.hideScrollbar ? "" : t1;
715
+ let intent;
716
+ new Promise((resolve) => {
717
+ intent = {
718
+ data: options,
719
+ onConfirm(selections, keys, values) {
720
+ this.data?.callbackConfirm?.(selections, keys, values);
721
+ resolve(selections)
722
+ },
723
+ onSelect(boundIndex, index, value, selectionIndexes, selectionValues) {
724
+ this?.data?.callbackSelect?.(boundIndex, index, value, selectionIndexes, selectionValues);
725
+ },
726
+ onAnother(selections, keys, values) {
727
+ this?.data?.callbackAnother?.(selections, keys, values);
728
+ resolve(false);
729
+ },
730
+ onDissmiss(selections, keys, values) {
731
+ this?.data?.callbackDissmiss?.(selections, keys, values);
732
+ resolve(undefined);
733
+ },
734
+ };
735
+ return pageManager.bringPage("!toastDials", intent);
736
+ });
737
+ return new class {
738
+ get data() { return intent.data; }
739
+ get handle() { return intent.handle; }
740
+ }();
741
+ }
742
+
743
+ const toastDials = (title = "", message = "",
744
+ table = [[]],
745
+ initial = [],
746
+ callbackConfirm = (selections, keys, values) => {},
747
+ callbackSelect = (boundIndex, index, value, selectionIndexes, selectionValues) => {},
748
+ callbackDissmiss = (selections, keys, values) => {},
749
+ callbackAnother = null,
750
+ confirm = isKorean() ? "닫기" : "Close",
751
+ another = isKorean() ? "되돌리기" : "rollback",
752
+ aligns = [],
753
+ prefixes = [],
754
+ suffixes = [],
755
+ dividers = [],
756
+ stretch = t,
757
+ hideScrollbar = t,
758
+ ) => estreToastDials({ title, message, table, initial, aligns, prefixes, suffixes, dividers, stretch, hideScrollbar, callbackConfirm, callbackSelect, callbackDissmiss, callbackAnother, confirm, another });
759
+
760
+ const dialsToast = (table = [[]],
761
+ initial = [],
762
+ title = "", message = "",
763
+ callbackConfirm = (selections, keys, values) => {},
764
+ confirm = isKorean() ? "닫기" : "Close",
765
+ callbackAnother = null,
766
+ another = isKorean() ? "되돌리기" : "rollback",
767
+ callbackDissmiss = (selections, keys, values) => {},
768
+ callbackSelect = (boundIndex, index, value, selectionIndexes, selectionValues) => {},
769
+ aligns = [],
770
+ prefixes = [],
771
+ suffixes = [],
772
+ dividers = [],
773
+ stretch = t,
774
+ hideScrollbar = t,
775
+ ) => toastDials(title, message, table, initial, callbackConfirm, callbackSelect, callbackDissmiss, callbackAnother, confirm, another, aligns, prefixes, suffixes, dividers, stretch, hideScrollbar);
776
+
777
+
665
778
 
666
779
 
667
780
  //override global(window) methods
@@ -1546,9 +1659,9 @@ class EstrePageHandle {
1546
1659
  #intentProxy;
1547
1660
  #intentDataProxy;
1548
1661
  #intentDataBindProxy = {};
1549
- #revokeIntentProxy;
1550
- #revokeIntentDataProxy;
1551
- #revokeIntentDataBindProxy = {};
1662
+ // #revokeIntentProxy;
1663
+ // #revokeIntentDataProxy;
1664
+ // #revokeIntentDataBindProxy = {};
1552
1665
 
1553
1666
  #isProcessing = f;
1554
1667
 
@@ -1597,9 +1710,10 @@ class EstrePageHandle {
1597
1710
  }
1598
1711
 
1599
1712
  takeOnPageIntent(intent = {}) {
1600
- this.#revokeIntentProxy?.();
1713
+ // this.#revokeIntentProxy?.();
1601
1714
  if (nn(intent?.data) && !intent.data.isProxy) intent.data = this.takeOnPageData(intent.data);
1602
- const { proxy, revoke } = nn(intent) ? Proxy.revocable(intent, {
1715
+ // const { proxy, revoke } = nn(intent) ? Proxy.revocable(intent, {
1716
+ const proxy = nn(intent) ? new Proxy(intent, {
1603
1717
  get: (target, prop) => prop == "isProxy" ? t : target[prop],
1604
1718
  set: (target, prop, value) => {
1605
1719
  if (prop == "data") {
@@ -1616,17 +1730,18 @@ class EstrePageHandle {
1616
1730
  if (!this.#isProcessing) this.applyActiveStruct();
1617
1731
  return t;
1618
1732
  },
1619
- }) : { proxy: u, revoke: u };
1733
+ }) : u;//{ proxy: u, revoke: u };
1620
1734
  this.#intentProxy = proxy;
1621
- this.#revokeIntentProxy = revoke;
1735
+ // this.#revokeIntentProxy = revoke;
1622
1736
  return proxy ?? intent;
1623
1737
  }
1624
1738
 
1625
1739
  takeOnPageData(data = {}) {
1626
- this.#revokeIntentDataProxy?.();
1740
+ // this.#revokeIntentDataProxy?.();
1627
1741
  const isObject = nn(data) && tj(data);
1628
1742
  if (isObject) for (const key in data) if (!data[key]?.isProxy) data[key] = this.takeOnPageBind(key, data[key]);
1629
- const { proxy, revoke } = isObject ? Proxy.revocable(data, {
1743
+ // const { proxy, revoke } = isObject ? Proxy.revocable(data, {
1744
+ const proxy = isObject ? new Proxy(data, {
1630
1745
  get: (target, prop) => prop == "isProxy" ? t : target[prop],
1631
1746
  set: (target, prop, value) => {
1632
1747
  target[prop] = this.takeOnPageBind(prop, value);
@@ -1639,17 +1754,18 @@ class EstrePageHandle {
1639
1754
  if (!this.#isProcessing) this.applyActiveStruct();
1640
1755
  return t;
1641
1756
  },
1642
- }) : { proxy: u, revoke: u };
1757
+ }) : u;//{ proxy: u, revoke: u };
1643
1758
  this.#intentDataProxy = proxy;
1644
- this.#revokeIntentDataProxy = revoke;
1759
+ // this.#revokeIntentDataProxy = revoke;
1645
1760
  return proxy ?? data;
1646
1761
  }
1647
1762
 
1648
1763
  takeOnPageBind(pr, bind) {
1649
- const rv = this.#revokeIntentDataBindProxy[pr];
1650
- if (tf(rv)) rv();
1764
+ // const rv = this.#revokeIntentDataBindProxy[pr];
1765
+ // if (tf(rv)) rv();
1651
1766
  if (nn(bind) && tj(bind)) {
1652
- const { proxy, revoke } = Proxy.revocable(bind, {
1767
+ // const { proxy, revoke } = Proxy.revocable(bind, {
1768
+ const proxy = new Proxy(bind, {
1653
1769
  get: (target, prop) => prop == "isProxy" ? t : target[prop],
1654
1770
  set: (target, prop, value) => {
1655
1771
  target[prop] = value;
@@ -1663,11 +1779,11 @@ class EstrePageHandle {
1663
1779
  },
1664
1780
  });
1665
1781
  this.#intentDataBindProxy[pr] = proxy;
1666
- this.#revokeIntentDataBindProxy[pr] = revoke;
1782
+ // this.#revokeIntentDataBindProxy[pr] = revoke;
1667
1783
  return proxy;
1668
1784
  } else {
1669
1785
  delete this.#intentDataBindProxy[pr];
1670
- delete this.#revokeIntentDataBindProxy[pr];
1786
+ // delete this.#revokeIntentDataBindProxy[pr];
1671
1787
  return bind;
1672
1788
  }
1673
1789
  }
@@ -1929,11 +2045,11 @@ class EstrePageHandle {
1929
2045
  if (this.handler?.onRelease != null) await this.handler.onRelease(this, remove);
1930
2046
  if (this.intent?.onRelease != null) for (var item of this.intent.onRelease) if (item.from == this.hostType && !item.disabled) await this.processAction(item);
1931
2047
 
1932
- for (const revoke of this.#revokeIntentDataBindProxy.looks) try {
1933
- revoke?.();
1934
- } catch (ex) {}
1935
- this.#revokeIntentDataProxy?.();
1936
- this.#revokeIntentProxy?.();
2048
+ // for (const revoke of this.#revokeIntentDataBindProxy.looks) try {
2049
+ // revoke?.();
2050
+ // } catch (ex) {}
2051
+ // this.#revokeIntentDataProxy?.();
2052
+ // this.#revokeIntentProxy?.();
1937
2053
  return true;
1938
2054
  } else return false;
1939
2055
  }
@@ -1998,11 +2114,11 @@ class EstrePageHandle {
1998
2114
  const eachTarget = ($elem, attrId, each = (target, prefix = "", suffix = "") => {}) => {
1999
2115
  const specifier = $elem.attr(attrId);
2000
2116
  if (specifier != null && specifier != "") {
2001
- const targets = specifier.split(" ");
2117
+ const targets = specifier.split(s);
2002
2118
  for (let target of targets) {
2003
2119
  let prefix = "", suffix = "";
2004
- if (target.indexOf("^") > -1) [target, prefix] = target.split("^");
2005
- if (target.indexOf("$") > -1) [suffix, target] = target.split("$");
2120
+ if (target.indexOf(cf) > -1) [target, prefix] = target.split(cf);
2121
+ if (target.indexOf(ds) > -1) [suffix, target] = target.split(ds);
2006
2122
  each(target, prefix, suffix);
2007
2123
  }
2008
2124
  }
@@ -2010,12 +2126,12 @@ class EstrePageHandle {
2010
2126
  const eachTargetFor = ($elem, attrId, each = (targetItem, targetName, prefix = "", suffix = "") => {}) => {
2011
2127
  const specifier = $elem.attr(attrId);
2012
2128
  if (specifier != null && specifier != "") {
2013
- const targets = specifier.split(" ");
2129
+ const targets = specifier.split(s);
2014
2130
  for (const target of targets) {
2015
- let [targetItem, targetName] = target.split("@");
2131
+ let [targetItem, targetName] = target.split(at);
2016
2132
  let prefix = "", suffix = "";
2017
- if (targetItem.indexOf("^") > -1) [targetItem, prefix] = targetItem.split("^");
2018
- if (targetItem.indexOf("$") > -1) [suffix, targetItem] = targetItem.split("$");
2133
+ if (targetItem.indexOf(cf) > -1) [targetItem, prefix] = targetItem.split(cf);
2134
+ if (targetItem.indexOf(ds) > -1) [suffix, targetItem] = targetItem.split(ds);
2019
2135
  each(targetItem, targetName, prefix, suffix);
2020
2136
  }
2021
2137
  }
@@ -2036,20 +2152,20 @@ class EstrePageHandle {
2036
2152
  $host.find(aiv(eds.bindAmount, item)).html(v2a(value));
2037
2153
  $host.find(aiv(eds.bindValue, item)).val(value);
2038
2154
 
2039
- if ($host.is(acv(eds.bindAttr, item + "@"))) eachTargetFor($host, eds.bindAttr, (targetItem, targetAttr, prefix = "", suffix = "") => {
2155
+ if ($host.is(acv(eds.bindAttr, item) + acv(eds.bindAttr, at))) eachTargetFor($host, eds.bindAttr, (targetItem, targetAttr, prefix = "", suffix = "") => {
2040
2156
  if (targetItem == item) $host.attr(targetAttr, prefix + value + suffix);
2041
2157
  });
2042
- $host.find(acv(eds.bindAttr, item + "@")).each((i, elem) => {
2158
+ $host.find(acv(eds.bindAttr, item) + acv(eds.bindAttr, at)).each((i, elem) => {
2043
2159
  const $elem = $(elem);
2044
2160
  eachTargetFor($elem, eds.bindAttr, (targetItem, targetAttr, prefix = "", suffix = "") => {
2045
2161
  if (targetItem == item) $elem.attr(targetAttr, prefix + value + suffix);
2046
2162
  });
2047
2163
  });
2048
2164
 
2049
- if ($host.find(acv(eds.bindStyle, item + "@"))) eachTargetFor($host, eds.bindStyle, (targetItem, targetStyle, prefix = "", suffix = "") => {
2165
+ if ($host.find(acv(eds.bindStyle, item) + acv(eds.bindStyle, at))) eachTargetFor($host, eds.bindStyle, (targetItem, targetStyle, prefix = "", suffix = "") => {
2050
2166
  if (targetItem == item) $host.css(targetStyle, prefix + value + suffix);
2051
2167
  });
2052
- $host.find(acv(eds.bindStyle, item + "@")).each((i, elem) => {
2168
+ $host.find(acv(eds.bindStyle, item) + acv(eds.bindStyle, at)).each((i, elem) => {
2053
2169
  const $elem = $(elem);
2054
2170
  eachTargetFor($elem, eds.bindStyle, (targetItem, targetStyle, prefix = "", suffix = "") => {
2055
2171
  if (targetItem == item) $elem.css(targetStyle, prefix + value + suffix);
@@ -2112,10 +2228,10 @@ class EstrePageHandle {
2112
2228
  $li.find(aiv(eds.bindObjectArrayAmount, objItem)).html(v2a(value));
2113
2229
  $li.find(aiv(eds.bindObjectArrayValue, objItem)).val(value);
2114
2230
 
2115
- if ($li.is(acv(eds.bindObjectArrayAttr, objItem + "@"))) eachTargetFor($li, eds.bindObjectArrayAttr, (targetItem, targetAttr, prefix = "", suffix = "") => {
2231
+ if ($li.is(acv(eds.bindObjectArrayAttr, objItem) + acv(eds.bindObjectArrayAttr, at))) eachTargetFor($li, eds.bindObjectArrayAttr, (targetItem, targetAttr, prefix = "", suffix = "") => {
2116
2232
  if (targetItem == objItem) $li.attr(targetAttr, prefix + value + suffix);
2117
2233
  });
2118
- $li.find(acv(eds.bindObjectArrayAttr, objItem + "@")).each((i, elem) => {
2234
+ $li.find(acv(eds.bindObjectArrayAttr, objItem) + acv(eds.bindObjectArrayAttr, at)).each((i, elem) => {
2119
2235
  const $elem = $(elem);
2120
2236
  eachTargetFor($elem, eds.bindObjectArrayAttr, (targetItem, targetAttr, prefix = "", suffix = "") => {
2121
2237
  if (targetItem == objItem) $elem.attr(targetAttr, prefix + value + suffix);
@@ -2124,10 +2240,10 @@ class EstrePageHandle {
2124
2240
 
2125
2241
  const styleValue = isEmpty(value) ? "unset" : value;
2126
2242
 
2127
- if ($li.is(acv(eds.bindObjectArrayStyle, objItem + "@"))) eachTargetFor($li, eds.bindObjectArrayStyle, (targetItem, targetStyle, prefix = "", suffix = "") => {
2243
+ if ($li.is(acv(eds.bindObjectArrayStyle, objItem) + acv(eds.bindObjectArrayStyle, at))) eachTargetFor($li, eds.bindObjectArrayStyle, (targetItem, targetStyle, prefix = "", suffix = "") => {
2128
2244
  if (targetItem == objItem) $li.css(targetStyle, prefix + styleValue + suffix);
2129
2245
  });
2130
- $li.find(acv(eds.bindObjectArrayStyle, objItem + "@")).each((i, elem) => {
2246
+ $li.find(acv(eds.bindObjectArrayStyle, objItem) + acv(eds.bindObjectArrayStyle, at)).each((i, elem) => {
2131
2247
  const $elem = $(elem);
2132
2248
  eachTargetFor($elem, eds.bindObjectArrayStyle, (targetItem, targetStyle, prefix = "", suffix = "") => {
2133
2249
  if (targetItem == objItem) $elem.css(targetStyle, prefix + styleValue + suffix);
@@ -4458,11 +4574,11 @@ class EstreSelectionDialogPageHandler extends EstreDialogPageHandler {
4458
4574
  if (isNotNully(defaultSelected)) forkv(defaultSelected, (k, v) => {
4459
4575
  switch(to(v)) {
4460
4576
  case BOOLEAN:
4461
- this.$optionCheckboxes.filter(aiv("data-index", k)).prop(m.v, v);
4577
+ this.$optionCheckboxes.filter(aiv(eds.index, k)).prop(m.v, v);
4462
4578
  break;
4463
4579
 
4464
4580
  case NUMBER:
4465
- this.$optionCheckboxes.filter(aiv("data-index", v)).prop(m.v, true);
4581
+ this.$optionCheckboxes.filter(aiv(eds.index, v)).prop(m.v, true);
4466
4582
  break;
4467
4583
  }
4468
4584
  });
@@ -4535,6 +4651,72 @@ class EstreSelectionDialogPageHandler extends EstreDialogPageHandler {
4535
4651
  }
4536
4652
  }
4537
4653
 
4654
+ class EstreDialsDialogPageHandler extends EstreDialogPageHandler {
4655
+ $dial;
4656
+ dialHandle;
4657
+
4658
+ $confirm;
4659
+ $another;
4660
+
4661
+ onBring(handle) {
4662
+ super.onBring(handle);
4663
+
4664
+ this.$dial = handle.$host.find(uis.multiDialSlot);
4665
+
4666
+ this.$confirm = this.$actions.find(btn + cls + "confirm");
4667
+ this.$another = this.$actions.find(btn + cls + "another");
4668
+ }
4669
+
4670
+ onOpen(handle) {
4671
+ super.onOpen(handle);
4672
+
4673
+ this.intent.handle = this.dialHandle = this.$dial[0].handle;
4674
+
4675
+ handle.intent?.onSelect?.let(it => this.dialHandle.setOnSelected(it));
4676
+
4677
+ handle.intent?.data?.let(it => {
4678
+ this.$dial.css("--font-size", it.fontSize ?? "2rem");
4679
+ if (it.fontWeight != n) this.$dial.css("--font-weight", it.fontWeight);
4680
+ this.$dial.css("--item-height", it.itemHeight ?? "1.2em");
4681
+ this.$dial.css("--holder-pad", it.holderPad ?? "var(--basic-ui-inset-h)");
4682
+ if (it.holderPadL != n) this.$dial.css("--holder-pad-l", it.holderPadL);
4683
+ if (it.holderPadR != n) this.$dial.css("--holder-pad-r", it.holderPadR);
4684
+ if (it.colGap != n) this.$dial.css("--col-gap", it.colGap);
4685
+ if (it.boundGap != n) this.$dial.css("--bound-gap", it.boundGap);
4686
+ });
4687
+
4688
+ const handler = this;
4689
+
4690
+ this.$confirm.click(function (e) {
4691
+ e.preventDefault();
4692
+ e.stopPropagation();
4693
+ const { itemSelectionIndexes, itemSelectionValues } = handler.dialHandle;
4694
+ handle?.intent?.onConfirm?.(itemSelectionIndexes.mock, itemSelectionValues.mock, handle.intent?.data?.initial);
4695
+ handle?.close();
4696
+ return false;
4697
+ });
4698
+ if (handle?.intent?.data?.callbackAnother == null) this.$another.remove();
4699
+ else this.$another.click(function (e) {
4700
+ e.preventDefault();
4701
+ e.stopPropagation();
4702
+ const { itemSelectionIndexes, itemSelectionValues } = handler.dialHandle;
4703
+ handle?.intent?.onAnother?.(itemSelectionIndexes.mock, itemSelectionValues.mock, handle.intent?.data?.initial);
4704
+ handle?.close();
4705
+ return false;
4706
+ });
4707
+
4708
+ this.$confirm.focus();
4709
+ }
4710
+
4711
+ onFocus(handle) {
4712
+ this.$confirm.focus();
4713
+ }
4714
+
4715
+ onClose(handle) {
4716
+ const { itemSelectionIndexes, itemSelectionValues } = this.dialHandle;
4717
+ handle?.intent?.onDissmiss(handle.intent?.data?.initial, itemSelectionIndexes.mock, itemSelectionValues.mock);
4718
+ }
4719
+ }
4538
4720
 
4539
4721
  /**
4540
4722
  * Pages profiling manager
@@ -4748,6 +4930,9 @@ class EstreUiPage {
4748
4930
  },
4749
4931
  "$i&o=toastUpSlide#selection^": class extends EstreSelectionDialogPageHandler {
4750
4932
 
4933
+ },
4934
+ "$i&o=toastUpSlide#dials^": class extends EstreDialsDialogPageHandler {
4935
+
4751
4936
  },
4752
4937
 
4753
4938
  "$i&o=interaction#onRunning^": class extends EstreLottieAnimatedHandler {
@@ -5402,6 +5587,7 @@ class EstreUiPageManager {
5402
5587
  get toastPrompt() { return "$i&o=toastUpSlide#prompt^"; },
5403
5588
  get toastOption() { return "$i&o=toastUpSlide#option^"; },
5404
5589
  get toastSelection() { return "$i&o=toastUpSlide#selection^"; },
5590
+ get toastDials() { return "$i&o=toastUpSlide#dials^"; },
5405
5591
 
5406
5592
 
5407
5593
  get onRunning() { return "$i&o=interaction#onRunning^"; },
@@ -5854,14 +6040,20 @@ class EstreHandle {
5854
6040
  get [uis.checkboxAlly]() { return EstreCheckboxAllyHandle; },
5855
6041
 
5856
6042
  get [uis.toasterSlot]() { return EstreToasterSlotHandle; },
6043
+ get [uis.multiDialSlot]() { return EstreMultiDialSlotHandle; },
5857
6044
 
5858
6045
  get [uis.customSelectorBar]() { return EstreCustomSelectorBarHandle; },
5859
6046
  get [uis.monthSelectorBar]() { return EstreMonthSelectorBarHandle; },
5860
6047
 
5861
6048
 
5862
6049
  get [uis.dateShower]() { return EstreDateShowerHandle; },
6050
+ get [uis.liveTimestamp]() { return EstreLiveTimestampHandle; },
6051
+
6052
+ get [uis.onClickSetText]() { return EstreOnClickSetTextHandle; },
6053
+ get [uis.onClickSetHtml]() { return EstreOnClickSetHtmlHandle; },
5863
6054
 
5864
6055
  get [uis.exportedContent]() { return EstreExportedContentHandle; },
6056
+ get [uis.dataHelpAlert]() { return EstreHelpAlertHandle; },
5865
6057
 
5866
6058
  get [uis.ezHidable]() { return EstreEzHidableHandle; },
5867
6059
  get [uis.fixedAccess]() { return EstreFixedAccessHandle; },
@@ -5954,7 +6146,7 @@ class EstreHandle {
5954
6146
  host.unregisterHandle(specifier, element.handle);
5955
6147
  const loaded = this.activeHandle[specifier];
5956
6148
  if (loaded != null) loaded.delete(element.handle);
5957
- element.handle.release();
6149
+ element.handle?.release();
5958
6150
  }
5959
6151
 
5960
6152
 
@@ -11340,7 +11532,687 @@ class EstreCheckboxAllyHandle extends EstreHandle {
11340
11532
 
11341
11533
 
11342
11534
  /**
11343
- * Toaster slots handle
11535
+ * Multi dial slot handle
11536
+ */
11537
+ class EstreMultiDialSlotHandle extends EstreHandle {
11538
+
11539
+ // constants
11540
+
11541
+
11542
+ // statics
11543
+
11544
+
11545
+ // open property
11546
+ $dialHolder;
11547
+ dialHolder;
11548
+ $dialBounds;
11549
+ $dialHosts;
11550
+ $dialPrefixes;
11551
+ $dialSuffixes;
11552
+ $dialDividers;
11553
+
11554
+
11555
+ // enclosed property
11556
+ #itemTableOrigin = [];
11557
+ #itemAlignsOrigin = [];
11558
+ #itemPrefixesOrigin = [];
11559
+ #itemSuffixesOrigin = [];
11560
+ #itemDividersOrigin = [];
11561
+
11562
+ #itemSelectionObserver = [];
11563
+ #itemTableProxy = [];
11564
+
11565
+ #itemTable;
11566
+ #itemAligns;
11567
+ #itemPrefixes;
11568
+ #itemSuffixes;
11569
+ #itemDividers;
11570
+
11571
+ #initialItemSelectionIndexes = [];
11572
+ #itemSelectionIndexes = [];
11573
+ #itemSelectionValues = [];
11574
+
11575
+ #itemSelectionIndexesProxy = [];
11576
+ #itemSelectionValuesProxy = [];
11577
+
11578
+ #onSelectionChanged;
11579
+
11580
+ #isInit = f;
11581
+
11582
+
11583
+ // getter and setter
11584
+ get itemTable() { return this.#itemTable; }
11585
+ set itemTable(value) { this.updateItemTable(value); }
11586
+ get itemAligns() { return this.#itemAligns; }
11587
+ set itemAligns(value) { this.updateItemAligns(value); }
11588
+ get itemPrefixes() { return this.#itemPrefixes; }
11589
+ set itemPrefixes(value) { this.updateItemPrefixes(value); }
11590
+ get itemSuffixes() { return this.#itemSuffixes; }
11591
+ set itemSuffixes(value) { this.updateItemSuffixes(value); }
11592
+ get itemDividers() { return this.#itemDividers; }
11593
+ set itemDividers(value) { this.updateItemDividers(value); }
11594
+
11595
+ get dataset() { return new Proxy({
11596
+ table: this.#itemTable,
11597
+ aligns: this.#itemAligns,
11598
+ prefixes: this.#itemPrefixes,
11599
+ suffixes: this.#itemSuffixes,
11600
+ dividers: this.#itemDividers,
11601
+ }, {
11602
+ set: (target, property, value) => {
11603
+ equalCase(property, {
11604
+ table: _ => this.updateItemTable(value),
11605
+ aligns: _ => this.updateItemAligns(value),
11606
+ prefixes: _ => this.updateItemPrefixes(value),
11607
+ suffixes: _ => this.updateItemSuffixes(value),
11608
+ dividers: _ => this.updateItemDividers(value),
11609
+ [def]: _ => target[property] = value,
11610
+ });
11611
+ return true;
11612
+ }
11613
+ }); }
11614
+ set dataset(value) { this.setDataset(value); }
11615
+
11616
+ get itemSelectionIndexes() { return this.#itemSelectionIndexesProxy; }
11617
+ set itemSelectionIndexes(value) { this.#setSelectionIndexes(value); }
11618
+ get itemSelectionValues() { return this.#itemSelectionValuesProxy; }
11619
+ set itemSelectionValues(value) { this.#setSelectionValues(value); }
11620
+ get itemSelections() {
11621
+ const selections = [];
11622
+ for (let i=0; i<this.#itemSelectionIndexes.length; i++) {
11623
+ selections.push([this.#itemSelectionIndexes[i], this.#itemSelectionValues[i]]);
11624
+ }
11625
+ return selections;
11626
+ }
11627
+
11628
+
11629
+ constructor(multiDialSlot, host) {
11630
+ super(multiDialSlot, host);
11631
+ }
11632
+
11633
+ release(remove) {
11634
+ super.release(remove);
11635
+ }
11636
+
11637
+ init() {
11638
+ super.init();
11639
+
11640
+ this.$dialHolder = this.$bound.find(uis.dialHolder);
11641
+ this.dialHolder = this.$dialHolder[0];
11642
+ this.$dialBounds = this.$dialHolder.find(uis.dialBound);
11643
+ this.$dialHosts = this.$dialBounds.find(uis.dialHost);
11644
+
11645
+ this.$dialHosts[0].solid();
11646
+ const divider = this.$dialHolder.find(li + cls + c.divider).stringified();
11647
+ this.$dialHolder.attr("data-frozen-divider", divider);
11648
+ this.$dialHolder[0].solid();
11649
+
11650
+ this.loadDataset();
11651
+ }
11652
+
11653
+ loadDataset() {
11654
+ try {
11655
+ const dataItemTable = this.$bound.attr(eds.itemTable);
11656
+ if (nne(dataItemTable)) this.#itemTableOrigin = Jcodd.parse(dataItemTable);
11657
+ } catch (e) {
11658
+ if (window.isLogging) console.error(e);
11659
+ }
11660
+
11661
+ try {
11662
+ const dataInitial = this.$bound.attr(eds.initial);
11663
+ if (nne(dataInitial)) this.#itemSelectionIndexes = Jcodd.parse(dataInitial);
11664
+ } catch (e) {
11665
+ if (window.isLogging) console.error(e);
11666
+ }
11667
+
11668
+ try {
11669
+ const dataItemAligns = this.$bound.attr(eds.itemAligns);
11670
+ if (nne(dataItemAligns)) this.#itemAlignsOrigin = Jcodd.parse(dataItemAligns);
11671
+ } catch (e) {
11672
+ if (window.isLogging) console.error(e);
11673
+ }
11674
+
11675
+ try {
11676
+ const dataItemPrefixes = this.$bound.attr(eds.itemPrefixes);
11677
+ if (nne(dataItemPrefixes)) this.#itemPrefixesOrigin = Jcodd.parse(dataItemPrefixes);
11678
+ } catch (e) {
11679
+ if (window.isLogging) console.error(e);
11680
+ }
11681
+
11682
+ try {
11683
+ const dataItemSuffixes = this.$bound.attr(eds.itemSuffixes);
11684
+ if (nne(dataItemSuffixes)) this.#itemSuffixesOrigin = Jcodd.parse(dataItemSuffixes);
11685
+ } catch (e) {
11686
+ if (window.isLogging) console.error(e);
11687
+ }
11688
+
11689
+ try {
11690
+ const dataItemDividers = this.$bound.attr(eds.itemDividers);
11691
+ if (nne(dataItemDividers)) this.#itemDividersOrigin = Jcodd.parse(dataItemDividers);
11692
+ } catch (e) {
11693
+ if (window.isLogging) console.error(e);
11694
+ }
11695
+
11696
+ this.updateAll();
11697
+ }
11698
+
11699
+ get$dialHost(boundIndex) {
11700
+ return this.$dialHosts[boundIndex]?.let(it => $(it));
11701
+ }
11702
+
11703
+ getDialItems(boundIndex) {
11704
+ return this.get$dialHost(boundIndex).find(c.c + li);
11705
+ }
11706
+
11707
+ setDataset(dataset = { table: [[]], initial: [], aligns: [], prefixes: [], suffixes: [], dividers: [] }) {
11708
+ this.#itemTableOrigin = dataset.table;
11709
+ this.#itemSelectionIndexes = dataset.initial;
11710
+ this.#itemAlignsOrigin = dataset.aligns;
11711
+ this.#itemPrefixesOrigin = dataset.prefixes;
11712
+ this.#itemSuffixesOrigin = dataset.suffixes;
11713
+ this.#itemDividersOrigin = dataset.dividers;
11714
+ this.updateAll();
11715
+ }
11716
+
11717
+ updateAll() {
11718
+ this.updateItemTable();
11719
+ this.updateItemAligns();
11720
+ this.updateItemPrefixes();
11721
+ this.updateItemSuffixes();
11722
+ this.updateItemDividers();
11723
+ }
11724
+
11725
+ updateItemTable(itemTable = this.#itemTableOrigin, itemSelectionIndexes = this.#itemSelectionIndexes) {
11726
+ const isInit = this.#isInit;
11727
+ if (!isInit) this.#isInit = t;
11728
+
11729
+ itemTable ??= [];
11730
+ const isNew = itemTable != this.#itemTableOrigin;
11731
+ if (isNew) {
11732
+ this.#itemTableOrigin = itemTable;
11733
+ this.#itemTableProxy = [];
11734
+ this.#itemSelectionObserver = [];
11735
+ }
11736
+
11737
+ if (itemSelectionIndexes.length != itemTable.length) {
11738
+ itemSelectionIndexes = [];
11739
+ for (let i=itemSelectionIndexes.length; i<itemTable.length; i++) itemSelectionIndexes[i] = 0;
11740
+ }
11741
+ if (itemSelectionIndexes != this.#itemSelectionIndexes) this.#itemSelectionIndexes = itemSelectionIndexes;
11742
+ this.#itemSelectionIndexesProxy = new Proxy(itemSelectionIndexes, {
11743
+ set: (target, property, value) => {
11744
+ const index = parseInt(property);
11745
+ const isIndex = !isNaN(index);
11746
+ if (isIndex) this.#scrollInstant(this.getDialItems(index)[value]);
11747
+ else target[property] = value;
11748
+ return true;
11749
+ }
11750
+ });
11751
+
11752
+ const itemSelectionValues = []
11753
+ this.#itemSelectionValues = itemSelectionValues;
11754
+ for (const [index, i] of itemSelectionIndexes.entries()) {
11755
+ const value = this.#itemTableOrigin[index]?.[i];
11756
+ this.#itemSelectionValues[index] = value;
11757
+ }
11758
+ this.#itemSelectionValuesProxy = new Proxy(itemSelectionValues, {
11759
+ set: (target, property, value) => {
11760
+ const index = parseInt(property);
11761
+ const isIndex = !isNaN(index);
11762
+ if (isIndex) {
11763
+ const itemIndex = this.#itemTableOrigin[index]?.indexOf(value);
11764
+ if (itemIndex > -1) this.#scrollInstant(this.getDialItems(index)[itemIndex]);
11765
+ } else target[property] = value;
11766
+ return true;
11767
+ }
11768
+ });
11769
+
11770
+ this.$dialHolder.empty();
11771
+ this.dialHolder.worm({ offset: 0 }, c.frozenDivider);
11772
+ for (var [index, list] of itemTable.entries()) {
11773
+ this.dialHolder.worm({ boundIndex: index });
11774
+ this.dialHolder.worm({ offset: index + 1 }, c.frozenDivider);
11775
+ }
11776
+ const updateBoundLinks = _ => {
11777
+ this.$dialBounds = this.$dialHolder.find(uis.dialBound);
11778
+ this.$dialHosts = this.$dialBounds.find(c.c + uis.dialHost);
11779
+ this.$dialPrefixes = this.$dialHolder.find(c.c + li + c.c + uis.prefix + c.c + sp);
11780
+ this.$dialSuffixes = this.$dialHolder.find(c.c + li + c.c + uis.suffix + c.c + sp);
11781
+ this.$dialDividers = this.$dialHolder.find(c.c + uis.divider + c.c + sp);
11782
+ }
11783
+ updateBoundLinks();
11784
+
11785
+ for (var [index, list] of itemTable.entries()) {
11786
+ this.#setItemBoundEvents(index);
11787
+ this.updateItemBound(index, list);
11788
+ }
11789
+
11790
+ if (!isInit) this.#isInit = f;
11791
+
11792
+ return this.#itemTable = new Proxy(this.#itemTableProxy, {
11793
+ set: (target, property, value) => {
11794
+ const index = parseInt(property);
11795
+ const isIndex = !isNaN(index);
11796
+ target[property] = isIndex ? this.#setItemTableProxy(index, value) : value;
11797
+ if (isIndex) {
11798
+ const boundLength = this.$dialBounds.length;
11799
+ if (boundLength > index) this.updateItemBound(index, value);
11800
+ else {
11801
+ for (let i=boundLength; i<=index; i++) {
11802
+ this.dialHolder.worm({ boundIndex: i });
11803
+ this.dialHolder.worm({ offset: i + 1 }, c.frozenDivider);
11804
+ }
11805
+ updateBoundLinks();
11806
+
11807
+ for (let i=boundLength; i<=index; i++) {
11808
+ this.#setItemBoundEvents(i);
11809
+ this.updateItemBound(i, i == index ? value : []);
11810
+ }
11811
+ }
11812
+ }
11813
+ return true;
11814
+ },
11815
+ deleteProperty: (target, property) => {
11816
+ delete target[property];
11817
+ const index = parseInt(property);
11818
+ const isIndex = !isNaN(index);
11819
+ if (isIndex) {
11820
+ this.$dialBounds[index].remove();
11821
+ this.$dialHolder.find(c.c + uis.dialDivider)[index + 1].remove();
11822
+ const dividerLength = this.#itemDividers.length;
11823
+ const dividerCount = this.$dialDividers.length;
11824
+ updateBoundLinks();
11825
+ this.#itemTableProxy.splice(index, 1);
11826
+ this.#itemAlignsOrigin.splice(index, 1);
11827
+ this.#itemPrefixesOrigin.splice(index, 1);
11828
+ this.#itemSuffixesOrigin.splice(index, 1);
11829
+ this.#itemSelectionObserver.splice(index, 1);
11830
+ if (dividerLength == 3 && dividerCount != 3) this.updateItemDividers();
11831
+ else this.#itemDividersOrigin.splice(index + 1, 1);
11832
+ }
11833
+ return true;
11834
+ }
11835
+ });
11836
+ }
11837
+
11838
+ #setItemBoundEvents(index, itemBound = this.$dialBounds[index]) {
11839
+ const inst = this;
11840
+ const $itemBound = $(itemBound);
11841
+
11842
+ $itemBound.on(c.wheel, function (e) {
11843
+ e.preventDefault();
11844
+
11845
+ const delta = Math.sign(e.originalEvent.deltaY);
11846
+ const selected = parseInt(this.dataset.selected);
11847
+ const $item = $(this).find(c.c + ul + c.c + li + aiv(eds.index, Math.min(Math.max(0, selected + delta), inst.#itemTable[index].length - 1) ) );
11848
+ $item.click();
11849
+
11850
+ return false;
11851
+ });
11852
+
11853
+
11854
+ const threshold = 1;
11855
+ const rootMargin = "0px";
11856
+
11857
+ this.#itemSelectionObserver[index] = new IntersectionObserver(entries => {
11858
+ for (const entry of entries) {
11859
+ if (entry.isIntersecting) {
11860
+ const idx = entry.target.dataset.index;
11861
+ const i = parseInt(idx);
11862
+ itemBound.dataset.selected = idx;
11863
+ this.#onSelected(index, i);
11864
+ }
11865
+ }
11866
+ }, {
11867
+ root: itemBound,
11868
+ rootMargin,
11869
+ threshold
11870
+ });
11871
+
11872
+ const ro = new ResizeObserver((entries) => {
11873
+ for (const entry of entries) {
11874
+ const items = this.getDialItems(index);
11875
+ const itemHeight = items[0]?.offsetHeight ?? 0;
11876
+ const halfHeight = parseInt(itemHeight / 2);
11877
+ const padding = getComputedStyle(entry.target.querySelector(ul)).padding;
11878
+ const paddings = padding.split(s).map(it => parseInt(it));
11879
+ for (let i=0; i<paddings.length; i+=2) paddings[i] = Math.max(paddings[i] - halfHeight, 0);
11880
+ const rootMargin = paddings.map(it => hp + it + c.px).join(s);
11881
+
11882
+ const current = this.#itemSelectionObserver[index];
11883
+
11884
+ if (current != null) for (const elem of items) current.unobserve(elem);
11885
+
11886
+ this.#itemSelectionObserver[index] = new IntersectionObserver(entries => {
11887
+ for (const entry of entries) {
11888
+ if (entry.isIntersecting) {
11889
+ const idx = entry.target.dataset.index;
11890
+ const i = parseInt(idx);
11891
+ itemBound.dataset.selected = idx;
11892
+ this.#onSelected(index, i);
11893
+ }
11894
+ }
11895
+ }, {
11896
+ root: itemBound,
11897
+ rootMargin,
11898
+ threshold
11899
+ });
11900
+
11901
+ for (const item of items) this.#setItemEvent(index, item.dataset.index, item);
11902
+ }
11903
+ });
11904
+
11905
+ ro.observe(itemBound);
11906
+
11907
+ return ro;
11908
+ }
11909
+
11910
+ updateItemBound(index, list) {
11911
+ const host = this.$dialHosts[index];
11912
+ if (host != n) {
11913
+ const isInit = this.#isInit;
11914
+ if (!isInit) this.#isInit = t;
11915
+
11916
+ const $host = $(host);
11917
+ const align = typeCase(list?.[0]?.let(it => parseFloat(it).let(num => isNaN(num) ? it : num)), {
11918
+ [NUMBER]: "right",
11919
+ [STRING]: "left",
11920
+ [DEFAULT]: c.center,
11921
+ });
11922
+ $host.attr(eds.align, align);
11923
+ if (list.length < 1) host.melt({ index: "0", value: "-" });
11924
+ else {
11925
+ $host.empty();
11926
+ for (const [index, value] of list.entries()) {
11927
+ host.worm({ index, value, dataPlaceholder: "" });
11928
+ }
11929
+ const $items = $host.find(c.c + li);
11930
+ for (let idx = 0; idx < $items.length; idx++) {
11931
+ this.#setItemEvent(index, idx, $items[idx]);
11932
+ }
11933
+ }
11934
+
11935
+ const $items = $host.find(c.c + li);
11936
+ const selectedIndex = Math.min(Math.max(0, this.#itemSelectionIndexes[index] ?? 0), $items.length - 1);
11937
+ this.#scrollInstant($items[selectedIndex]);
11938
+
11939
+ if (!isInit) this.#isInit = f;
11940
+
11941
+ return this.#setItemTableProxy(index, list);
11942
+ } else return this.#itemTable[index];
11943
+ }
11944
+
11945
+ #setItemTableProxy(boundIndex, list) {
11946
+ return this.#itemTableProxy[boundIndex] = new Proxy(list ?? [], {
11947
+ set: (target, property, value) => {
11948
+ const index = parseInt(property);
11949
+ const isIndex = !isNaN(index);
11950
+ target[property] = value;
11951
+ if (isIndex) {
11952
+ const host = this.$dialHosts[boundIndex];
11953
+ const $host = $(host);
11954
+ const $items = $host.find(c.c + li);
11955
+ const length = $items.length;
11956
+ if (length > index) {
11957
+ const $item = $($items[index]);
11958
+ const $span = $item.find(c.c + sp);
11959
+ $span.html(value);
11960
+ } else for (let i=length; i<=index; i++) {
11961
+ host.worm({ index: i, value: i == index ? value : "" });
11962
+ this.#setItemEvent(boundIndex, i);
11963
+ }
11964
+ }
11965
+ return true;
11966
+ },
11967
+ deleteProperty: (target, property) => {
11968
+ delete target[property];
11969
+ const index = parseInt(property);
11970
+ const isIndex = !isNaN(index);
11971
+ if (isIndex) this.getDialItems(boundIndex)[index].remove();
11972
+ return true;
11973
+ }
11974
+ });
11975
+ }
11976
+
11977
+ #setItemEvent(boundIndex, index, item = this.getDialItems(boundIndex)[index], observer = this.#itemSelectionObserver[boundIndex]) {
11978
+ const inst = this;
11979
+ observer.observe(item);
11980
+ $(item).off(c.click).click(function (e) {
11981
+ e.preventDefault();
11982
+
11983
+ inst.#scrollSmooth(this);
11984
+
11985
+ return false;
11986
+ });
11987
+ }
11988
+
11989
+ updateItemAligns(itemAligns = this.#itemAlignsOrigin) {
11990
+ itemAligns ??= [];
11991
+ if (itemAligns != this.#itemAlignsOrigin) this.#itemAlignsOrigin = itemAligns;
11992
+ for (const [index, value] of itemAligns.entries()) {
11993
+ const align = typeUndefined(value) ? "" : value == n ? c.center : value ? c.right : c.left;
11994
+ this.get$dialHost(index).attr(eds.align, align);
11995
+ }
11996
+ this.#itemAligns = new Proxy(itemAligns, {
11997
+ set: (target, property, value) => {
11998
+ const index = parseInt(property);
11999
+ const isIndex = !isNaN(index);
12000
+ target[property] = value;
12001
+ if (isIndex && index < this.$dialHosts.length) {
12002
+ const align = typeUndefined(value) ? "" : value == n ? c.center : value ? c.right : c.left;
12003
+ this.get$dialHost(index).attr(eds.align, align);
12004
+ }
12005
+ return true;
12006
+ },
12007
+ deleteProperty: (target, property) => {
12008
+ delete target[property];
12009
+ return true;
12010
+ }
12011
+ });
12012
+ }
12013
+
12014
+ updateItemPrefixes(itemPrefixes = this.#itemPrefixesOrigin) {
12015
+ itemPrefixes ??= [];
12016
+ if (itemPrefixes != this.#itemPrefixesOrigin) this.#itemPrefixesOrigin = itemPrefixes;
12017
+ for (const [index, value] of itemPrefixes.entries()) {
12018
+ $(this.$dialPrefixes[index]).html(value);
12019
+ }
12020
+ this.#itemPrefixes = new Proxy(itemPrefixes, {
12021
+ set: (target, property, value) => {
12022
+ const index = parseInt(property);
12023
+ const isIndex = !isNaN(index);
12024
+ target[property] = value;
12025
+ if (isIndex && index < this.$dialPrefixes.length) {
12026
+ $(this.$dialPrefixes[index]).html(value);
12027
+ }
12028
+ return true;
12029
+ },
12030
+ deleteProperty: (target, property) => {
12031
+ delete target[property];
12032
+ return true;
12033
+ }
12034
+ });
12035
+ }
12036
+
12037
+ updateItemSuffixes(itemSuffixes = this.#itemSuffixesOrigin) {
12038
+ itemSuffixes ??= [];
12039
+ if (itemSuffixes != this.#itemSuffixesOrigin) this.#itemSuffixesOrigin = itemSuffixes;
12040
+ for (const [index, value] of itemSuffixes.entries()) {
12041
+ $(this.$dialSuffixes[index]).html(value);
12042
+ }
12043
+ this.#itemSuffixes = new Proxy(itemSuffixes, {
12044
+ set: (target, property, value) => {
12045
+ const index = parseInt(property);
12046
+ const isIndex = !isNaN(index);
12047
+ target[property] = value;
12048
+ if (isIndex && index < this.$dialSuffixes.length) {
12049
+ $(this.$dialSuffixes[index]).html(value);
12050
+ }
12051
+ return true;
12052
+ },
12053
+ deleteProperty: (target, property) => {
12054
+ delete target[property];
12055
+ return true;
12056
+ }
12057
+ });
12058
+ }
12059
+
12060
+ updateItemDividers(itemDividers = this.#itemDividersOrigin) {
12061
+ itemDividers ??= [];
12062
+ if (itemDividers != this.#itemDividersOrigin) this.#itemDividersOrigin = itemDividers;
12063
+ if (itemDividers.length == 3) {
12064
+ const lastIndex = this.$dialDividers.length - 1;
12065
+ for (let i=0; i<this.$dialDividers.length; i++) {
12066
+ if (i == 0) $(this.$dialDividers[i]).html(itemDividers[0]);
12067
+ else if (i == lastIndex) $(this.$dialDividers[i]).html(itemDividers[2]);
12068
+ else $(this.$dialDividers[i]).html(itemDividers[1]);
12069
+ }
12070
+ } else for (const [index, value] of itemDividers.entire) {
12071
+ $(this.$dialDividers[index]).html(value);
12072
+ }
12073
+ this.#itemDividers = new Proxy(itemDividers, {
12074
+ set: (target, property, value) => {
12075
+ const index = parseInt(property);
12076
+ const isIndex = !isNaN(index);
12077
+ target[property] = value;
12078
+ if (isIndex) {
12079
+ if (target.length == 3 && index > 0) {
12080
+ const lastIndex = this.$dialDividers.length - 1;
12081
+ if (index == 3) $(this.$dialDividers[lastIndex]).html(value);
12082
+ else if (index == 2) for (let i=1; i<lastIndex; i++) $(this.$dialDividers[i]).html(value);
12083
+ } else if (index < this.$dialDividers.length) {
12084
+ $(this.$dialDividers[index]).html(value);
12085
+ }
12086
+ }
12087
+ return true;
12088
+ },
12089
+ deleteProperty: (target, property) => {
12090
+ delete target[property];
12091
+ return true;
12092
+ }
12093
+ });
12094
+ }
12095
+
12096
+
12097
+ setOnSelected(callback = (boundIndex, index, value, selectionIndexes, selectionValues) => {}) {
12098
+ this.#onSelectionChanged = callback;
12099
+ }
12100
+
12101
+ #onSelected(boundIndex, index, value = this.#itemTable[boundIndex][index]) {
12102
+ if (this.#initialItemSelectionIndexes[boundIndex] == n) {
12103
+ const idx = this.#itemSelectionIndexes[boundIndex];
12104
+ if (idx != n) {
12105
+ const item = this.getDialItems(boundIndex)?.[idx];
12106
+ if (item != n && this.$dialBounds[boundIndex].dataset.selected != idx) {
12107
+ const isInit = this.#isInit;
12108
+ if (!isInit) this.#isInit = t;
12109
+ this.#scrollInstant(item);
12110
+ if (!isInit) this.#isInit = f;
12111
+ return;
12112
+ }
12113
+ }
12114
+ this.#initialItemSelectionIndexes[boundIndex] = index;
12115
+ }
12116
+ if (!this.isInit) {
12117
+ if (window.isVerbosely) console.log("Item selected: [" + idx + "] " + value);
12118
+ this.#itemSelectionIndexes[boundIndex] = index;
12119
+ this.#itemSelectionValues[boundIndex] = value;
12120
+
12121
+ const selectionIndexes = this.#itemSelectionIndexes.mock;
12122
+ const selectionValues = this.#itemSelectionValues.mock;
12123
+ this.#onSelectionChanged?.(boundIndex, index, value, selectionIndexes, selectionValues);
12124
+ }
12125
+ }
12126
+
12127
+ #setSelectionIndexes(selectionIndexes = [], setByEvent = t) {
12128
+ const isInit = this.#isInit;
12129
+ const isInitializing = !setByEvent;
12130
+ const isSingleEvent = setByEvent == n;
12131
+ if (isInitializing && !isInit) this.#isInit = t;
12132
+ for (let i=0; i<this.#itemTableOrigin.length; i++) {
12133
+ const index = selectionIndexes[i];
12134
+ if (index != n) {
12135
+ if (isInitializing) {
12136
+ this.#itemSelectionIndexes[i] = index;
12137
+ this.#itemSelectionValues[i] = this.#itemTableOrigin[i]?.[index];
12138
+ }
12139
+ if (this.$dialBounds[i].dataset.selected != index) {
12140
+ const items = this.getDialItems(i);
12141
+ this.#scrollInstant(items[index]);
12142
+ }
12143
+ }
12144
+ }
12145
+ if (isInitializing && !isInit) this.#isInit = f;
12146
+ if (isSingleEvent) this.#onSelectionChanged?.(n, n, n, this.#itemSelectionIndexes.mock, this.itemSelectionValues.mock);
12147
+ return this.itemSelectionIndexes;
12148
+ }
12149
+
12150
+ #setSelectionValues(selectionValues = [], setByEvent = t) {
12151
+ const isInit = this.#isInit;
12152
+ const isInitializing = !setByEvent;
12153
+ const isSingleEvent = setByEvent == n;
12154
+ if (isInitializing && !isInit) this.#isInit = t;
12155
+ for (let i=0; i<this.#itemTableOrigin.length; i++) {
12156
+ const value = selectionValues[i];
12157
+ if (value != n) {
12158
+ const index = this.#itemTableOrigin[i]?.indexOf(value);
12159
+ if (index != n) {
12160
+ if (isInitializing) {
12161
+ this.#itemSelectionIndexes[i] = index;
12162
+ this.#itemSelectionValues[i] = value;
12163
+ }
12164
+ if (index > -1 && this.$dialBounds[i].dataset.selected != index) {
12165
+ const items = this.getDialItems(i);
12166
+ this.#scrollInstant(items[index]);
12167
+ }
12168
+ }
12169
+ }
12170
+ }
12171
+ if (isInitializing && !isInit) this.#isInit = f;
12172
+ if (isSingleEvent) this.#onSelectionChanged?.(n, n, n, this.#itemSelectionIndexes.mock, this.itemSelectionValues.mock);
12173
+ return this.itemSelectionValues;
12174
+ }
12175
+
12176
+ setSelectionsByIndexes(selectionIndexes = [], isUpdateOnly = n) {
12177
+ return this.#setSelectionIndexes(selectionIndexes, isUpdateOnly?.let(it => !it));
12178
+ }
12179
+
12180
+ setSelectionsByValues(selectionValues = [], isUpdateOnly = n) {
12181
+ return this.#setSelectionValues(selectionValues, isUpdateOnly?.let(it => !it));
12182
+ }
12183
+
12184
+ #scrollInstant(elem, host = elem?.parentElement) {
12185
+ // elem?.scrollIntoView({ behavior: c.instant, block: c.center });
12186
+ if (elem != n && host != n) {
12187
+ host.scrollTop = host.scrollTop;
12188
+
12189
+ postQueue(_ => {
12190
+ const hostRect = host.getBoundingClientRect();
12191
+ const elemRect = elem.getBoundingClientRect();
12192
+
12193
+ const offset = elemRect.top - hostRect.top - (hostRect.height / 2) + (elemRect.height / 2);
12194
+ host.scrollTop += offset;
12195
+ });
12196
+ }
12197
+ }
12198
+
12199
+ #scrollSmooth(elem, host = elem?.parentElement) {
12200
+ // elem?.scrollIntoView({ behavior: c.smooth, block: c.center });
12201
+ if (elem != n && host != n) {
12202
+ const hostRect = host.getBoundingClientRect();
12203
+ const elemRect = elem.getBoundingClientRect();
12204
+
12205
+ host.scrollBy({
12206
+ top: elemRect.top - hostRect.top - (hostRect.height / 2) + (elemRect.height / 2),
12207
+ behavior: c.smooth
12208
+ });
12209
+ }
12210
+ }
12211
+ }
12212
+
12213
+
12214
+ /**
12215
+ * Toaster slot handle
11344
12216
  */
11345
12217
  class EstreToasterSlotHandle extends EstreHandle {
11346
12218
 
@@ -11914,6 +12786,194 @@ class EstreDateShowerHandle extends EstreHandle {
11914
12786
  }
11915
12787
  }
11916
12788
 
12789
+ class EstreLiveTimestampHandle extends EstreHandle {
12790
+
12791
+ // constants
12792
+
12793
+
12794
+ // statics
12795
+
12796
+
12797
+ // open property
12798
+
12799
+
12800
+ // enclosed property
12801
+ #date;
12802
+
12803
+ #timeout;
12804
+
12805
+
12806
+ #nextTimeout = 1000;
12807
+
12808
+
12809
+ // getter and setter
12810
+ get date() { return new Date(this.#date); }
12811
+
12812
+ get from() { return this.$bound.attr(eds.liveTimestamp).int; }
12813
+
12814
+ get isShortSuffix() { return this.$bound.attr(eds.shortSuffix) == t1; }
12815
+
12816
+
12817
+ constructor(liveTimestamp, host) {
12818
+ super(liveTimestamp, host);
12819
+ }
12820
+
12821
+ release() {
12822
+ clearTimeout(this.#timeout);
12823
+ this.#timeout = n;
12824
+
12825
+ super.release();
12826
+ }
12827
+
12828
+ init() {
12829
+ super.init();
12830
+
12831
+ this.#date = new Date(this.from).time;
12832
+
12833
+ if (!isNaN(this.#date)) {
12834
+ this.updateDisplay();
12835
+
12836
+ this.setLive();
12837
+ }
12838
+
12839
+ return this;
12840
+ }
12841
+
12842
+ setLive() {
12843
+ if (this.#timeout != n) {
12844
+ clearTimeout(this.#timeout);
12845
+ this.#timeout = n;
12846
+ }
12847
+
12848
+ const postTimeout = _ => this.#timeout = setTimeout(_ => {
12849
+ if (!this.bound.isConnected) {
12850
+ clearTimeout(this.#timeout);
12851
+ this.#timeout = n
12852
+ return;
12853
+ }
12854
+ this.updateDisplay();
12855
+ if (this.#nextTimeout != n) postTimeout();
12856
+ else this.#timeout = n;
12857
+ }, this.#nextTimeout);
12858
+
12859
+ if (this.#nextTimeout != n) postTimeout();
12860
+ else this.#timeout = n;
12861
+ }
12862
+
12863
+ updateDisplay() {
12864
+ const suffixType = this.isShortSuffix ? "ShortSuffix" : "Suffix";
12865
+ const now = dt.t;
12866
+ const time = this.#date;
12867
+ const diff = now - time;
12868
+ let text = "";
12869
+ let nextTimeout = n;
12870
+ if (diff < 10000) {
12871
+ text = EsLocale.get("now");
12872
+ nextTimeout = 10000 - diff;
12873
+ } else {
12874
+ const texts = [];
12875
+ const ago = EsLocale.get("ago");
12876
+ if (diff < 20000) {
12877
+ texts.push(EsLocale.get("just"));
12878
+ nextTimeout = 20000 - diff;
12879
+ } else if (diff < 60000) {
12880
+ texts.push(Math.floor(diff / 1000) + EsLocale.get("seconds" + suffixType));
12881
+ nextTimeout = 10000;
12882
+ } else if (diff < 3600000) {
12883
+ texts.push(Math.floor(diff / 60000) + EsLocale.get("minutes" + suffixType));
12884
+ nextTimeout = 60000;
12885
+ } else if (diff < 86400000) {
12886
+ texts.push(Math.floor(diff / 3600000) + EsLocale.get("hours" + suffixType));
12887
+ nextTimeout = 3600000;
12888
+ } else if (diff < 604800000) {
12889
+ texts.push(Math.floor(diff / 86400000) + EsLocale.get("days" + suffixType));
12890
+ nextTimeout = 86400000;
12891
+ } else if (diff < 2592000000) texts.push(Math.floor(diff / 604800000) + EsLocale.get("weeks" + suffixType));
12892
+ else if (diff < 31104000000) texts.push(Math.floor(diff / 2592000000) + EsLocale.get("months" + suffixType));
12893
+ else texts.push(Math.floor(diff / 31104000000) + EsLocale.get("years" + suffixType));
12894
+ texts.push(ago);
12895
+ text = texts.join(s);
12896
+ }
12897
+ this.#nextTimeout = nextTimeout;
12898
+ this.$bound.html(text);
12899
+ }
12900
+ }
12901
+
12902
+
12903
+
12904
+ // on click set text
12905
+ class EstreOnClickSetTextHandle extends EstreHandle {
12906
+ // constants
12907
+
12908
+ // statics
12909
+
12910
+ // open property
12911
+
12912
+ // enclosed property
12913
+
12914
+ // getter and setter
12915
+
12916
+
12917
+ constructor(bound, host) {
12918
+ super(bound, host);
12919
+ }
12920
+
12921
+ release() {
12922
+ super.release();
12923
+ }
12924
+
12925
+ init() {
12926
+ super.init();
12927
+
12928
+ this.$bound.click(function (e) {
12929
+ e.preventDefault();
12930
+
12931
+ const text = this.dataset.onClickSetText;
12932
+ $(this).text(text);
12933
+
12934
+ return false;
12935
+ });
12936
+ }
12937
+
12938
+ }
12939
+
12940
+ // on click set html
12941
+ class EstreOnClickSetHtmlHandle extends EstreHandle {
12942
+ // constants
12943
+
12944
+ // statics
12945
+
12946
+ // open property
12947
+
12948
+ // enclosed property
12949
+
12950
+ // getter and setter
12951
+
12952
+
12953
+ constructor(bound, host) {
12954
+ super(bound, host);
12955
+ }
12956
+
12957
+ release() {
12958
+ super.release();
12959
+ }
12960
+
12961
+ init() {
12962
+ super.init();
12963
+
12964
+ this.$bound.click(function (e) {
12965
+ e.preventDefault();
12966
+
12967
+ const text = this.dataset.onClickSetHtml;
12968
+ $(this).html(text);
12969
+
12970
+ return false;
12971
+ });
12972
+ }
12973
+
12974
+ }
12975
+
12976
+
11917
12977
 
11918
12978
  // exported content
11919
12979
  class EstreExportedContentHandle extends EstreHandle {
@@ -11964,6 +13024,44 @@ class EstreExportedContentHandle extends EstreHandle {
11964
13024
  }
11965
13025
  }
11966
13026
 
13027
+ class EstreHelpAlertHandle extends EstreHandle {
13028
+
13029
+ // constants
13030
+
13031
+ // statics
13032
+
13033
+
13034
+ // open property
13035
+
13036
+
13037
+ // enclosed property
13038
+
13039
+
13040
+ // getter and setter
13041
+
13042
+
13043
+ constructor(bound, host) {
13044
+ super(bound, host);
13045
+ }
13046
+
13047
+ release() {
13048
+ super.release();
13049
+ }
13050
+
13051
+ init() {
13052
+ super.init();
13053
+
13054
+ this.$bound.click(function (e) {
13055
+ e.preventDefault();
13056
+
13057
+ alert(this.dataset.helpAlertTitle?.replace(/\\n/g, "<br />") ?? "", this.dataset.helpAlert.replace(/\\n/g, "<br />") ?? "");
13058
+
13059
+ return false;
13060
+ });
13061
+ }
13062
+ }
13063
+
13064
+
11967
13065
 
11968
13066
  // quick transitions
11969
13067
  class EstreEzHidableHandle extends EstreHandle {