estreui 1.3.0 → 1.5.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.
@@ -45,6 +45,80 @@ class EstrePageHandle {
45
45
 
46
46
  get title() { return this.$host?.attr(eds.title); }
47
47
 
48
+ /**
49
+ * Cover-bar entry label override. Falls back to `title` (= `data-title`) when unset.
50
+ * Set via `setCoverTitle(value)`; pass `undefined` to clear the override.
51
+ * @type {string|undefined}
52
+ */
53
+ #coverTitle = undefined;
54
+ get coverTitle() { return this.#coverTitle ?? this.title; }
55
+ setCoverTitle(value) {
56
+ this.#coverTitle = value;
57
+ if (this.#coverEntryToken != null) {
58
+ estreUi.coverBarHandle?.updateEntry(this.#coverEntryToken, { title: this.coverTitle });
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Cover-bar entry icon override. Distinguishes "unset" (falls back to
64
+ * `data-icon`) from explicit set values via #isCoverIconSet — `undefined`,
65
+ * `null`, `""`, `"none"`, and an arbitrary URL are all distinct outcomes
66
+ * the bar's fallback branch interprets in Phase 1C.
67
+ * @type {string|null|undefined}
68
+ */
69
+ #coverIcon = undefined;
70
+ #isCoverIconSet = false;
71
+ get coverIcon() {
72
+ if (this.#isCoverIconSet) return this.#coverIcon;
73
+ return this.$host?.attr(eds.icon);
74
+ }
75
+ setCoverIcon(value) {
76
+ this.#coverIcon = value;
77
+ this.#isCoverIconSet = true;
78
+ if (this.#coverEntryToken != null) {
79
+ estreUi.coverBarHandle?.updateEntry(this.#coverEntryToken, { icon: this.coverIcon });
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Opt-in flag for cover-bar mounting. `data-cover-mount="1"` on the page
85
+ * section enables this; sub-class handlers can override the getter for
86
+ * programmatic opt-in (Phase 1C will also expose a constructor option).
87
+ */
88
+ get coverMount() { return this.$host?.attr(eds.coverMount) == t1; }
89
+
90
+ /**
91
+ * Token returned by `estreUi.coverBarHandle.pushEntry()` when this handle's
92
+ * page was registered in the cover bar. `null` whenever no entry is live
93
+ * (page closed / cover bar not ready / coverMount opt-out).
94
+ */
95
+ #coverEntryToken = null;
96
+ get coverEntryToken() { return this.#coverEntryToken; }
97
+
98
+ /**
99
+ * Internal — push an entry for this handle into the cover bar when opt-in
100
+ * is set and the bar is ready. Re-entry-safe: noop if already registered.
101
+ */
102
+ #registerCoverEntry() {
103
+ if (this.#coverEntryToken != null) return;
104
+ if (!this.coverMount) return;
105
+ const handle = estreUi.coverBarHandle;
106
+ if (handle == null) return;
107
+ this.#coverEntryToken = handle.pushEntry({
108
+ pageHandle: this,
109
+ sectionBound: this.sectionBound,
110
+ title: this.coverTitle,
111
+ icon: this.coverIcon,
112
+ });
113
+ }
114
+
115
+ /** Internal — remove this handle's cover-bar entry, if any. */
116
+ #releaseCoverEntry() {
117
+ if (this.#coverEntryToken == null) return;
118
+ estreUi.coverBarHandle?.removeEntry(this.#coverEntryToken);
119
+ this.#coverEntryToken = null;
120
+ }
121
+
48
122
  #appbarLeft = null;
49
123
  #appbarRight = null;
50
124
  #appbarCenter = null;
@@ -403,6 +477,7 @@ class EstrePageHandle {
403
477
  if (!this.isOpened) {
404
478
  if (window.isDebug) console.log("[onOpen] " + this.sectionBound + " " + this.hostType + " " + this.pid);//, this.host);
405
479
  this.#isOpened = true;
480
+ this.#registerCoverEntry();
406
481
  if (this.handler?.onOpen != null) this.handler.onOpen(this);
407
482
  if (this.intent?.onOpen != null) for (var item of this.intent.onOpen) if (item.from == this.hostType && !item.disabled) this.processAction(item);
408
483
  return true;
@@ -414,6 +489,7 @@ class EstrePageHandle {
414
489
  if (window.isVerbosely) console.log("[onShow] " + this.sectionBound + " " + this.hostType + " " + this.pid, this.host);
415
490
  else if (window.isDebug) console.log("[onShow] " + this.sectionBound + " " + this.hostType + " " + this.pid);
416
491
  this.#isShowing = true;
492
+ if (this.#coverEntryToken != null) estreUi.coverBarHandle?.setMinimizedByToken(this.#coverEntryToken, false);
417
493
  if (this.handler?.onShow != null) this.handler.onShow(this);
418
494
  if (this.intent?.onShow != null) for (var item of this.intent.onShow) if (item.from == this.hostType && !item.disabled) this.processAction(item);
419
495
  return true;
@@ -426,6 +502,7 @@ class EstrePageHandle {
426
502
  if (window.isDebug) console.log("[onFocus] " + this.sectionBound + " " + this.hostType + " " + this.pid);//, this.host);
427
503
  this.#isFocused = true;
428
504
  this.#everFocused = true;
505
+ if (this.#coverEntryToken != null) estreUi.coverBarHandle?.setActiveByToken(this.#coverEntryToken);
429
506
  const handled = this.handler?.onFocus?.(this, isFirstFocus);
430
507
  if (this.intent?.onFocus != null) for (var item of this.intent.onFocus) if (item.from == this.hostType && !item.disabled) this.processAction(item);
431
508
  if (handled === true) {
@@ -475,6 +552,7 @@ class EstrePageHandle {
475
552
  this.#isShowing = false;
476
553
  if (window.isVerbosely) console.log("[onHide] " + this.sectionBound + " " + this.hostType + " " + this.pid, this.host);
477
554
  else if (window.isDebug) console.log("[onHide] " + this.sectionBound + " " + this.hostType + " " + this.pid);
555
+ if (this.#coverEntryToken != null) estreUi.coverBarHandle?.setMinimizedByToken(this.#coverEntryToken, true);
478
556
  if (this.intent?.onHide != null) for (var item of this.intent.onHide) if (item.from == this.hostType && !item.disabled) await this.processAction(item);
479
557
  if (this.handler?.onHide != null) await this.handler.onHide(this, fullyHide);
480
558
  if (this.intent?.bringOnBack != null && this.intent.bringOnBack.pid != n) {
@@ -499,6 +577,7 @@ class EstrePageHandle {
499
577
  this.#everFocused = false;
500
578
  this.lastFocusedElement = null;
501
579
  if (window.isDebug) console.log("[onClose] " + this.sectionBound + " " + this.hostType + " " + this.pid);//, this.host);
580
+ this.#releaseCoverEntry();
502
581
  if (this.intent?.onClose != null) for (var item of this.intent.onClose) if (item.from == this.hostType && !item.disabled) await this.processAction(item);
503
582
  if (this.handler?.onClose != null) await this.handler.onClose(this);
504
583
  if (this.intent?.bringOnBack != null && this.intent.bringOnBack.pid != n) {
@@ -2774,6 +2853,17 @@ class EstrePageHandler {
2774
2853
  /** @type {*} The data field of the intent. */
2775
2854
  get intentData() { return this.intent?.data; }
2776
2855
 
2856
+ /** Cover-bar entry label — see EstrePageHandle.coverTitle. */
2857
+ get coverTitle() { return this.handle?.coverTitle; }
2858
+ /** Cover-bar entry icon — see EstrePageHandle.coverIcon. */
2859
+ get coverIcon() { return this.handle?.coverIcon; }
2860
+ /** Cover-bar opt-in flag — see EstrePageHandle.coverMount. */
2861
+ get coverMount() { return this.handle?.coverMount ?? false; }
2862
+ /** Updates the cover-bar entry label for this handler's page. */
2863
+ setCoverTitle(value) { return this.handle?.setCoverTitle(value); }
2864
+ /** Updates the cover-bar entry icon for this handler's page. See EstrePageHandle.coverIcon for unset/empty/"none"/URL semantics. */
2865
+ setCoverIcon(value) { return this.handle?.setCoverIcon(value); }
2866
+
2777
2867
  /**
2778
2868
  * @param {EstrePageHandle} handle - The page handle to bind.
2779
2869
  * @param {*} [provider] - The provider that registered this handler.
@@ -3723,7 +3813,147 @@ class EstreUiPage {
3723
3813
 
3724
3814
  },
3725
3815
 
3726
- "$i&o=notification#noti@noti^": class extends EstrePageHandler { },
3816
+ "$i&o=notification#noti@noti^": class extends EstrePageHandler {
3817
+ $postBlock;
3818
+ $mainIconPlace;
3819
+ $subIconPlace;
3820
+ $titleLine;
3821
+ $subtitleLine;
3822
+ $contentLine;
3823
+ swipeHandler;
3824
+ #closeTimer;
3825
+ #closing = false;
3826
+
3827
+ #applyIntentToBlock(intent) {
3828
+ const data = intent?.data ?? {};
3829
+ this.$mainIconPlace.toggle(data.largeIconSrc != null && data.largeIconSrc !== "");
3830
+ this.$subIconPlace.toggle(data.iconSrc != null && data.iconSrc !== "");
3831
+ this.$titleLine.toggle(data.contentTitle != null && data.contentTitle !== "");
3832
+ this.$subtitleLine.toggle(data.subtitle != null && data.subtitle !== "");
3833
+ this.$contentLine.toggle(data.content != null && data.content !== "");
3834
+ }
3835
+
3836
+ #resetCloseTimer(handle) {
3837
+ if (this.#closeTimer != null) {
3838
+ clearTimeout(this.#closeTimer);
3839
+ this.#closeTimer = null;
3840
+ }
3841
+ const showTime = handle.intent?.data?.showTime ?? EstreNotificationManager.defaultShowTime;
3842
+ this.#closeTimer = setTimeout(_ => this.#beginClose(handle), showTime);
3843
+ }
3844
+
3845
+ #beginClose(handle) {
3846
+ if (this.#closing) return;
3847
+ this.#closing = true;
3848
+ if (this.#closeTimer != null) {
3849
+ clearTimeout(this.#closeTimer);
3850
+ this.#closeTimer = null;
3851
+ }
3852
+
3853
+ if (!EstreNotificationManager.hasQueued) {
3854
+ handle.close();
3855
+ return;
3856
+ }
3857
+
3858
+ const $block = this.$postBlock;
3859
+ const blockEl = $block[0];
3860
+ if (blockEl == null) { handle.close(); return; }
3861
+ const $article = $block.parent();
3862
+ const articleEl = $article[0];
3863
+ const rect = blockEl.getBoundingClientRect();
3864
+ const articleRect = articleEl.getBoundingClientRect();
3865
+ const $ghost = $block.clone(false).removeClass("banner_incoming");
3866
+ $ghost.addClass("banner_ghost_exit");
3867
+ $ghost.css({
3868
+ position: "absolute",
3869
+ left: (rect.left - articleRect.left) + "px",
3870
+ top: (rect.top - articleRect.top) + "px",
3871
+ width: rect.width + "px",
3872
+ margin: 0,
3873
+ pointerEvents: "none",
3874
+ });
3875
+ $article.append($ghost);
3876
+ setTimeout(() => $ghost.remove(), 550);
3877
+
3878
+ $block.css({ visibility: "hidden", pointerEvents: "none" });
3879
+
3880
+ EstreNotificationManager.beginCheckOut(handle.intent);
3881
+ }
3882
+
3883
+ onBring(handle) {
3884
+ const $host = handle.$host;
3885
+ this.$postBlock = $host.find(".post_block");
3886
+ this.$mainIconPlace = this.$postBlock.children(".icon_place");
3887
+ this.$titleLine = this.$postBlock.find("> .content_place > .title_line");
3888
+ this.$subtitleLine = this.$postBlock.find("> .content_place > .subtitle_line");
3889
+ this.$contentLine = this.$postBlock.find("> .content_place > .content_area > .content_place");
3890
+ this.$subIconPlace = this.$postBlock.find("> .content_place > .content_area > .icon_place");
3891
+
3892
+ this.#applyIntentToBlock(handle.intent);
3893
+
3894
+ EstreNotificationManager.current = handle.intent;
3895
+ if (window.isVerbosely) console.log("pushed", handle.intent);
3896
+ }
3897
+
3898
+ onOpen(handle) {
3899
+ this.#closing = false;
3900
+ this.$postBlock.click((e) => {
3901
+ e.preventDefault();
3902
+
3903
+ if (window.isVerbosely) console.log("clicked: ", handle.intent);
3904
+ handle.intent?.onTakeInteraction?.(handle.intent);
3905
+ this.#beginClose(handle);
3906
+
3907
+ return false;
3908
+ });
3909
+
3910
+ const self = this;
3911
+ this.swipeHandler = new EstreSwipeHandler(this.$postBlock)
3912
+ .setStopPropagation()
3913
+ .setPreventDefault()
3914
+ .unuseX()
3915
+ .setThresholdY(1)
3916
+ .setDropStrayed(false)
3917
+ .setResponseBound(this.$postBlock)
3918
+ .setOnUp(function (grabX, grabY, handled, canceled, directed) {
3919
+ if (!handled) return;
3920
+ if (this.handledDirection === "up" && Math.abs(grabY) > 20) {
3921
+ self.#beginClose(handle);
3922
+ } else if (this.handledDirection === "down" && Math.abs(grabY) > 40) {
3923
+ handle.intent?.onTakeInteraction?.(handle.intent);
3924
+ self.#beginClose(handle);
3925
+ }
3926
+ });
3927
+
3928
+ this.#resetCloseTimer(handle);
3929
+ if (window.isVerbosely) console.log("showing: ", handle.intent);
3930
+ }
3931
+
3932
+ onIntentUpdated(handle, intent) {
3933
+ // Queue-chain handover: previous banner's exit is playing on a
3934
+ // detached ghost clone; this article reuses the same DOM with
3935
+ // fresh content + a restart-triggered enter animation.
3936
+ this.#closing = false;
3937
+ if (intent?.data != null) this.#applyIntentToBlock(intent);
3938
+ EstreNotificationManager.current = handle.intent;
3939
+
3940
+ const $block = this.$postBlock;
3941
+ $block.css({ visibility: "", pointerEvents: "" });
3942
+ $block.removeClass("banner_incoming");
3943
+ void $block[0]?.offsetWidth;
3944
+ $block.addClass("banner_incoming");
3945
+
3946
+ this.#resetCloseTimer(handle);
3947
+ }
3948
+
3949
+ onClose(handle) {
3950
+ if (this.#closeTimer != null) {
3951
+ clearTimeout(this.#closeTimer);
3952
+ this.#closeTimer = null;
3953
+ }
3954
+ EstreNotificationManager.checkOut(handle.intent);
3955
+ }
3956
+ },
3727
3957
  "$i&o=notification#note@note^": class extends EstrePageHandler {
3728
3958
  $postBlock;
3729
3959
 
package/serviceWorker.js CHANGED
@@ -1,4 +1,4 @@
1
- const INSTALLATION_VERSION_NAME = "1.3.0-r20260421";
1
+ const INSTALLATION_VERSION_NAME = "1.5.0-r20260524";
2
2
  // ^^ Use for check new update "Native application(webview) version(or Android/iOS version combo) - PWA release version"
3
3
  // ex) "1.0.1/1.0.0-r20251101k"
4
4
 
@@ -22,7 +22,7 @@ const INSTALLATION_FILE_LIST = [
22
22
 
23
23
 
24
24
  // Common files cache - Be changes some time but, well not changed very often
25
- const CACHE_NAME_COMMON_FILES = "common-files-cache-v1-20260421";
25
+ const CACHE_NAME_COMMON_FILES = "common-files-cache-v1-20260524";
26
26
 
27
27
  const COMMON_FILES_TO_CACHE = [
28
28
  "./",
@@ -51,6 +51,7 @@ const COMMON_FILES_TO_CACHE = [
51
51
  "./scripts/estreUi-core.js",
52
52
  "./scripts/estreUi-dialog.js",
53
53
  "./scripts/estreUi-notation.js",
54
+ "./scripts/estreUi-notification.js",
54
55
  "./scripts/estreUi-pageModel.js",
55
56
  "./scripts/estreUi-pageManager.js",
56
57
  "./scripts/estreUi-handles.js",
@@ -60,7 +61,7 @@ const COMMON_FILES_TO_CACHE = [
60
61
 
61
62
 
62
63
  // Static files cache - Rarely changes after release
63
- const CACHE_NAME_STATIC_FILES = "static-files-cache-v1-20260221";
64
+ const CACHE_NAME_STATIC_FILES = "static-files-cache-v1-20260524";
64
65
 
65
66
  const STATIC_FILES_TO_CACHE = [
66
67
  "./favicon.ico",
@@ -96,6 +97,9 @@ const STATIC_FILES_TO_CACHE = [
96
97
 
97
98
  "./vectors/more_vertical_slim_icon.svg",
98
99
  "./vectors/app_icon.svg",
100
+ "./vectors/cover-icon-default-static.svg",
101
+ "./vectors/cover-icon-default-instant.svg",
102
+ "./vectors/cover-icon-default-overlay.svg",
99
103
  ];
100
104
 
101
105