haori 0.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.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +157 -0
  3. package/README.md +158 -0
  4. package/dist/haori.cjs.js +13 -0
  5. package/dist/haori.cjs.js.map +1 -0
  6. package/dist/haori.es.js +2929 -0
  7. package/dist/haori.es.js.map +1 -0
  8. package/dist/haori.iife.js +13 -0
  9. package/dist/haori.iife.js.map +1 -0
  10. package/dist/index.d.ts +824 -0
  11. package/dist/src/core.d.ts +144 -0
  12. package/dist/src/core.d.ts.map +1 -0
  13. package/dist/src/core.js +605 -0
  14. package/dist/src/core.js.map +1 -0
  15. package/dist/src/dev.d.ts +35 -0
  16. package/dist/src/dev.d.ts.map +1 -0
  17. package/dist/src/dev.js +44 -0
  18. package/dist/src/dev.js.map +1 -0
  19. package/dist/src/env.d.ts +25 -0
  20. package/dist/src/env.d.ts.map +1 -0
  21. package/dist/src/env.js +64 -0
  22. package/dist/src/env.js.map +1 -0
  23. package/dist/src/event.d.ts +144 -0
  24. package/dist/src/event.d.ts.map +1 -0
  25. package/dist/src/event.js +221 -0
  26. package/dist/src/event.js.map +1 -0
  27. package/dist/src/event_dispatcher.d.ts +50 -0
  28. package/dist/src/event_dispatcher.d.ts.map +1 -0
  29. package/dist/src/event_dispatcher.js +99 -0
  30. package/dist/src/event_dispatcher.js.map +1 -0
  31. package/dist/src/expression.d.ts +39 -0
  32. package/dist/src/expression.d.ts.map +1 -0
  33. package/dist/src/expression.js +148 -0
  34. package/dist/src/expression.js.map +1 -0
  35. package/dist/src/form.d.ts +113 -0
  36. package/dist/src/form.d.ts.map +1 -0
  37. package/dist/src/form.js +361 -0
  38. package/dist/src/form.js.map +1 -0
  39. package/dist/src/fragment.d.ts +427 -0
  40. package/dist/src/fragment.d.ts.map +1 -0
  41. package/dist/src/fragment.js +1168 -0
  42. package/dist/src/fragment.js.map +1 -0
  43. package/dist/src/haori.d.ts +54 -0
  44. package/dist/src/haori.d.ts.map +1 -0
  45. package/dist/src/haori.js +120 -0
  46. package/dist/src/haori.js.map +1 -0
  47. package/dist/src/import.d.ts +19 -0
  48. package/dist/src/import.d.ts.map +1 -0
  49. package/dist/src/import.js +64 -0
  50. package/dist/src/import.js.map +1 -0
  51. package/dist/src/index.d.ts +17 -0
  52. package/dist/src/index.d.ts.map +1 -0
  53. package/dist/src/index.js +21 -0
  54. package/dist/src/index.js.map +1 -0
  55. package/dist/src/log.d.ts +32 -0
  56. package/dist/src/log.d.ts.map +1 -0
  57. package/dist/src/log.js +43 -0
  58. package/dist/src/log.js.map +1 -0
  59. package/dist/src/observer.d.ts +17 -0
  60. package/dist/src/observer.d.ts.map +1 -0
  61. package/dist/src/observer.js +102 -0
  62. package/dist/src/observer.js.map +1 -0
  63. package/dist/src/procedure.d.ts +203 -0
  64. package/dist/src/procedure.d.ts.map +1 -0
  65. package/dist/src/procedure.js +1040 -0
  66. package/dist/src/procedure.js.map +1 -0
  67. package/dist/src/queue.d.ts +28 -0
  68. package/dist/src/queue.d.ts.map +1 -0
  69. package/dist/src/queue.js +150 -0
  70. package/dist/src/queue.js.map +1 -0
  71. package/dist/src/url.d.ts +14 -0
  72. package/dist/src/url.d.ts.map +1 -0
  73. package/dist/src/url.js +22 -0
  74. package/dist/src/url.js.map +1 -0
  75. package/dist/tests/click-attributes.test.d.ts +2 -0
  76. package/dist/tests/click-attributes.test.d.ts.map +1 -0
  77. package/dist/tests/click-attributes.test.js +95 -0
  78. package/dist/tests/click-attributes.test.js.map +1 -0
  79. package/dist/tests/core.test.d.ts +5 -0
  80. package/dist/tests/core.test.d.ts.map +1 -0
  81. package/dist/tests/core.test.js +158 -0
  82. package/dist/tests/core.test.js.map +1 -0
  83. package/dist/tests/data-each-browserlike.test.d.ts +2 -0
  84. package/dist/tests/data-each-browserlike.test.d.ts.map +1 -0
  85. package/dist/tests/data-each-browserlike.test.js +48 -0
  86. package/dist/tests/data-each-browserlike.test.js.map +1 -0
  87. package/dist/tests/data-each-fragment-debug.test.d.ts +2 -0
  88. package/dist/tests/data-each-fragment-debug.test.d.ts.map +1 -0
  89. package/dist/tests/data-each-fragment-debug.test.js +119 -0
  90. package/dist/tests/data-each-fragment-debug.test.js.map +1 -0
  91. package/dist/tests/data-each-table.test.d.ts +2 -0
  92. package/dist/tests/data-each-table.test.d.ts.map +1 -0
  93. package/dist/tests/data-each-table.test.js +63 -0
  94. package/dist/tests/data-each-table.test.js.map +1 -0
  95. package/dist/tests/dev.test.d.ts +2 -0
  96. package/dist/tests/dev.test.d.ts.map +1 -0
  97. package/dist/tests/dev.test.js +51 -0
  98. package/dist/tests/dev.test.js.map +1 -0
  99. package/dist/tests/each_arg.test.d.ts +2 -0
  100. package/dist/tests/each_arg.test.d.ts.map +1 -0
  101. package/dist/tests/each_arg.test.js +41 -0
  102. package/dist/tests/each_arg.test.js.map +1 -0
  103. package/dist/tests/env.test.d.ts +2 -0
  104. package/dist/tests/env.test.d.ts.map +1 -0
  105. package/dist/tests/env.test.js +96 -0
  106. package/dist/tests/env.test.js.map +1 -0
  107. package/dist/tests/event.test.d.ts +2 -0
  108. package/dist/tests/event.test.d.ts.map +1 -0
  109. package/dist/tests/event.test.js +287 -0
  110. package/dist/tests/event.test.js.map +1 -0
  111. package/dist/tests/expression.test.d.ts +2 -0
  112. package/dist/tests/expression.test.d.ts.map +1 -0
  113. package/dist/tests/expression.test.js +281 -0
  114. package/dist/tests/expression.test.js.map +1 -0
  115. package/dist/tests/fetch-and-procedure-scenarios.test.d.ts +2 -0
  116. package/dist/tests/fetch-and-procedure-scenarios.test.d.ts.map +1 -0
  117. package/dist/tests/fetch-and-procedure-scenarios.test.js +133 -0
  118. package/dist/tests/fetch-and-procedure-scenarios.test.js.map +1 -0
  119. package/dist/tests/form.test.d.ts +2 -0
  120. package/dist/tests/form.test.d.ts.map +1 -0
  121. package/dist/tests/form.test.js +607 -0
  122. package/dist/tests/form.test.js.map +1 -0
  123. package/dist/tests/fragment.test.d.ts +2 -0
  124. package/dist/tests/fragment.test.d.ts.map +1 -0
  125. package/dist/tests/fragment.test.js +164 -0
  126. package/dist/tests/fragment.test.js.map +1 -0
  127. package/dist/tests/import.test.d.ts +2 -0
  128. package/dist/tests/import.test.d.ts.map +1 -0
  129. package/dist/tests/import.test.js +148 -0
  130. package/dist/tests/import.test.js.map +1 -0
  131. package/dist/tests/log.test.d.ts +2 -0
  132. package/dist/tests/log.test.d.ts.map +1 -0
  133. package/dist/tests/log.test.js +58 -0
  134. package/dist/tests/log.test.js.map +1 -0
  135. package/dist/tests/procedure-action-operations.test.d.ts +2 -0
  136. package/dist/tests/procedure-action-operations.test.d.ts.map +1 -0
  137. package/dist/tests/procedure-action-operations.test.js +148 -0
  138. package/dist/tests/procedure-action-operations.test.js.map +1 -0
  139. package/dist/tests/procedure-fetch-options.test.d.ts +2 -0
  140. package/dist/tests/procedure-fetch-options.test.d.ts.map +1 -0
  141. package/dist/tests/procedure-fetch-options.test.js +131 -0
  142. package/dist/tests/procedure-fetch-options.test.js.map +1 -0
  143. package/dist/tests/procedure.test.d.ts +2 -0
  144. package/dist/tests/procedure.test.d.ts.map +1 -0
  145. package/dist/tests/procedure.test.js +136 -0
  146. package/dist/tests/procedure.test.js.map +1 -0
  147. package/dist/tests/procedure_events.test.d.ts +7 -0
  148. package/dist/tests/procedure_events.test.d.ts.map +1 -0
  149. package/dist/tests/procedure_events.test.js +96 -0
  150. package/dist/tests/procedure_events.test.js.map +1 -0
  151. package/dist/tests/reset_each.test.d.ts +2 -0
  152. package/dist/tests/reset_each.test.d.ts.map +1 -0
  153. package/dist/tests/reset_each.test.js +215 -0
  154. package/dist/tests/reset_each.test.js.map +1 -0
  155. package/dist/tests/row-move.test.d.ts +2 -0
  156. package/dist/tests/row-move.test.d.ts.map +1 -0
  157. package/dist/tests/row-move.test.js +197 -0
  158. package/dist/tests/row-move.test.js.map +1 -0
  159. package/dist/tests/row-operations.test.d.ts +2 -0
  160. package/dist/tests/row-operations.test.d.ts.map +1 -0
  161. package/dist/tests/row-operations.test.js +238 -0
  162. package/dist/tests/row-operations.test.js.map +1 -0
  163. package/dist/tests/url.test.d.ts +2 -0
  164. package/dist/tests/url.test.d.ts.map +1 -0
  165. package/dist/tests/url.test.js +150 -0
  166. package/dist/tests/url.test.js.map +1 -0
  167. package/dist/vite.config.d.ts +3 -0
  168. package/dist/vite.config.d.ts.map +1 -0
  169. package/dist/vite.config.js +28 -0
  170. package/dist/vite.config.js.map +1 -0
  171. package/dist/vitest.config.d.ts +3 -0
  172. package/dist/vitest.config.d.ts.map +1 -0
  173. package/dist/vitest.config.js +19 -0
  174. package/dist/vitest.config.js.map +1 -0
  175. package/package.json +68 -0
@@ -0,0 +1,2929 @@
1
+ const C = class C {
2
+ /**
3
+ * 開発モードの状態を取得します。
4
+ *
5
+ * @returns 開発モードならtrue、そうでなければfalse
6
+ */
7
+ static isEnabled() {
8
+ return C.devMode;
9
+ }
10
+ /**
11
+ * 開発モードを有効化します。
12
+ */
13
+ static enable() {
14
+ C.devMode = !0;
15
+ }
16
+ /**
17
+ * 開発モードを無効化します。
18
+ */
19
+ static disable() {
20
+ C.devMode = !1;
21
+ }
22
+ /**
23
+ * 開発モードを切り替えます。
24
+ *
25
+ * @param enabled trueで有効化、falseで無効化
26
+ */
27
+ static set(t) {
28
+ C.devMode = t;
29
+ }
30
+ };
31
+ C.devMode = !1;
32
+ let D = C;
33
+ const k = class k {
34
+ /**
35
+ * 実行環境からプレフィックスと開発モードかどうかを自動検出します。
36
+ * scriptタグにdata-prefixがある場合は、その値+"-"をプレフィックスとして使用します。
37
+ * scriptタグにdata-dev属性がある場合、
38
+ * もしくはローカルホスト系ドメインであれば開発モードを有効化します。
39
+ */
40
+ static detect() {
41
+ try {
42
+ const t = document.currentScript || document.querySelector('script[src*="haori"]');
43
+ if (t instanceof HTMLScriptElement) {
44
+ const s = t.getAttribute("data-prefix") || k._prefix;
45
+ k._prefix = s.endsWith("-") ? s : s + "-";
46
+ }
47
+ if (t instanceof HTMLScriptElement && t.hasAttribute(`${k._prefix}dev`)) {
48
+ D.set(!0);
49
+ return;
50
+ }
51
+ const e = window.location.hostname;
52
+ if (e === "localhost" || e.endsWith(".localhost") || e === "127.0.0.1" || e === "::1" || e.endsWith(".local")) {
53
+ D.set(!0);
54
+ return;
55
+ }
56
+ D.set(!1);
57
+ } catch {
58
+ }
59
+ }
60
+ /**
61
+ * プレフィックスを取得します。
62
+ *
63
+ * @returns プレフィックス
64
+ */
65
+ static get prefix() {
66
+ return k._prefix;
67
+ }
68
+ };
69
+ k._prefix = "data-";
70
+ let c = k;
71
+ document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", c.detect) : c.detect();
72
+ class h {
73
+ /**
74
+ * 開発モードでのみコンソールに情報を出力します。
75
+ *
76
+ * @param message 出力するメッセージ
77
+ * @param args 追加の引数
78
+ */
79
+ static info(t, ...e) {
80
+ D.isEnabled() && console.log && console.log(t, ...e);
81
+ }
82
+ /**
83
+ * 開発モードでのみコンソールに警告を出力します。
84
+ *
85
+ * @param message 出力するメッセージ
86
+ * @param args 追加の引数
87
+ */
88
+ static warn(t, ...e) {
89
+ D.isEnabled() && console.warn && console.warn(t, ...e);
90
+ }
91
+ /**
92
+ * モードに関係なくコンソールにエラーを出力します。
93
+ *
94
+ * @param message 出力するメッセージ
95
+ * @param args 追加の引数
96
+ */
97
+ static error(t, ...e) {
98
+ console.error(t, ...e);
99
+ }
100
+ }
101
+ class X {
102
+ constructor() {
103
+ this.MAX_BUDGET = 8, this.queue = [], this.processing = !1;
104
+ }
105
+ /**
106
+ * 処理をキューに追加します
107
+ *
108
+ * @param task 実行する処理
109
+ * @param prepend trueの場合はキューの先頭に追加、falseの場合は末尾に追加
110
+ * @returns 処理完了Promise
111
+ */
112
+ enqueue(t, e = !1) {
113
+ let s, r;
114
+ const i = new Promise((a, u) => {
115
+ s = a, r = u;
116
+ }), n = {
117
+ task: t,
118
+ timestamp: performance.now(),
119
+ promise: i,
120
+ resolve: s,
121
+ reject: r
122
+ };
123
+ return e ? this.queue.unshift(n) : this.queue.push(n), this.scheduleProcessing(), i;
124
+ }
125
+ /**
126
+ * キューを処理します。
127
+ *
128
+ * @returns 処理完了Promise
129
+ */
130
+ async processQueue() {
131
+ if (!(this.processing || this.queue.length === 0)) {
132
+ this.processing = !0;
133
+ try {
134
+ const t = performance.now();
135
+ for (; this.queue.length > 0; ) {
136
+ const e = this.queue.shift();
137
+ if (!e)
138
+ return;
139
+ try {
140
+ const s = await e.task();
141
+ e.resolve(s);
142
+ } catch (s) {
143
+ e.reject(s), h.error("[Haori]", `Task ${e.timestamp} failed:`, s);
144
+ }
145
+ if (performance.now() - t > this.MAX_BUDGET)
146
+ break;
147
+ }
148
+ } catch (t) {
149
+ h.error("[Haori]", "Error processing queue:", t);
150
+ } finally {
151
+ this.processing = !1, this.queue.length > 0 && this.scheduleProcessing();
152
+ }
153
+ }
154
+ }
155
+ /**
156
+ * 処理をスケジュールします。
157
+ */
158
+ scheduleProcessing() {
159
+ this.processing || (typeof requestAnimationFrame < "u" ? requestAnimationFrame(() => {
160
+ this.processQueue();
161
+ }) : setTimeout(() => {
162
+ this.processQueue();
163
+ }, 16));
164
+ }
165
+ /**
166
+ * キューが空になるまで待機します。
167
+ *
168
+ * @returns キューが空になったら解決されるPromise
169
+ */
170
+ async wait() {
171
+ if (this.queue.length === 0 && !this.processing)
172
+ return;
173
+ const t = this.queue.map((e) => e.promise);
174
+ t.length > 0 && await Promise.allSettled(t);
175
+ }
176
+ }
177
+ const K = class K {
178
+ /**
179
+ * タスクをキューに追加します。
180
+ *
181
+ * @param task 実行する処理
182
+ * @param prepend trueの場合はキューの先頭に追加、falseの場合は末尾に追加
183
+ * @returns 処理完了Promise
184
+ */
185
+ static enqueue(t, e = !1) {
186
+ return this.ASYNC_QUEUE.enqueue(t, e);
187
+ }
188
+ /**
189
+ * 全てのキュー処理が完了するまで待機します。
190
+ */
191
+ static wait() {
192
+ return this.ASYNC_QUEUE.wait();
193
+ }
194
+ };
195
+ K.ASYNC_QUEUE = new X();
196
+ let v = K;
197
+ class M {
198
+ /**
199
+ * 通知ダイアログを表示します。
200
+ *
201
+ * @param message 表示メッセージ
202
+ * @returns 通知が閉じられると解決されるPromise
203
+ */
204
+ static dialog(t) {
205
+ return v.enqueue(() => {
206
+ window.alert(t);
207
+ }, !0);
208
+ }
209
+ /**
210
+ * 通知トーストを表示します。
211
+ *
212
+ * @param message 表示メッセージ
213
+ * @param level メッセージのレベル('info' | 'warning' | 'error')
214
+ * @return 通知が表示されると解決されるPromise
215
+ */
216
+ static async toast(t, e) {
217
+ const s = document.createElement("div");
218
+ s.className = `haori-toast haori-toast-${e}`, s.textContent = t, s.setAttribute("popover", "manual"), s.setAttribute("role", "status"), s.setAttribute("aria-live", "polite"), document.body.appendChild(s), s.showPopover(), setTimeout(() => {
219
+ try {
220
+ s.hidePopover();
221
+ } finally {
222
+ s.remove();
223
+ }
224
+ }, 3e3);
225
+ }
226
+ /**
227
+ * 確認ダイアログを表示します。
228
+ *
229
+ * @param message 確認メッセージ
230
+ * @returns ユーザーがOKをクリックした場合はtrue、キャンセルした場合はfalseが解決されるPromise
231
+ */
232
+ static confirm(t) {
233
+ return v.enqueue(() => window.confirm(t), !0);
234
+ }
235
+ /**
236
+ * ダイアログを開きます。
237
+ *
238
+ * @param element 開くダイアログのHTML要素
239
+ */
240
+ static openDialog(t) {
241
+ return v.enqueue(() => {
242
+ t instanceof HTMLDialogElement ? t.showModal() : h.error("[Haori]", "Element is not a dialog: ", t);
243
+ }, !0);
244
+ }
245
+ /**
246
+ * ダイアログを閉じます。
247
+ *
248
+ * @param element 閉じるダイアログのHTML要素
249
+ */
250
+ static closeDialog(t) {
251
+ return v.enqueue(() => {
252
+ t instanceof HTMLDialogElement ? t.close() : h.error("[Haori]", "Element is not a dialog: ", t);
253
+ }, !0);
254
+ }
255
+ /**
256
+ * エラーメッセージを追加します。
257
+ *
258
+ * @param target メッセージを表示する要素
259
+ * @param message エラーメッセージ
260
+ */
261
+ static addErrorMessage(t, e) {
262
+ return v.enqueue(() => {
263
+ if (t instanceof HTMLFormElement) {
264
+ t.setAttribute("data-message", e);
265
+ return;
266
+ }
267
+ if (t.parentElement) {
268
+ t.parentElement.setAttribute("data-message", e);
269
+ return;
270
+ }
271
+ t.setAttribute("data-message", e);
272
+ }, !0);
273
+ }
274
+ /**
275
+ * 対象のエレメントおよびその子要素のメッセージをクリアします。
276
+ *
277
+ * @param parent メッセージをクリアする親要素
278
+ */
279
+ static clearMessages(t) {
280
+ return v.enqueue(() => {
281
+ t.removeAttribute("data-message"), t.querySelectorAll("[data-message]").forEach((e) => {
282
+ e.removeAttribute("data-message");
283
+ });
284
+ }, !0);
285
+ }
286
+ }
287
+ class E {
288
+ /**
289
+ * フォーム内にある入力エレメントの値をオブジェクトとして取得します。
290
+ * data-form-object属性があると、そのエレメント内の値はオブジェクトとして処理されます。
291
+ * 入力エレメントにdata-form-list属性があると、そのエレメントの値はリストとして処理されます。
292
+ * 入力エレメント以外にdata-form-list属性があると、そのエレメントの値はオブジェクトのリストとして処理されます。
293
+ *
294
+ * @param form フォームのElementFragment
295
+ */
296
+ static getValues(t) {
297
+ const e = {};
298
+ return E.getPartValues(t, e);
299
+ }
300
+ /**
301
+ * フォーム内の各入力エレメントから値を取得し、オブジェクトとして返します。
302
+ * 入力エレメントのname属性、data-form-object属性、data-form-list属性に基づいて値を整理します。
303
+ *
304
+ * @param fragment 対象のElementFragment
305
+ * @param values オブジェクトに追加する値のオブジェクト
306
+ * @returns values と同じオブジェクト
307
+ */
308
+ static getPartValues(t, e) {
309
+ const s = t.getAttribute("name"), r = t.getAttribute(`${c.prefix}form-object`), i = t.getAttribute(`${c.prefix}form-list`);
310
+ if (s) {
311
+ i ? Array.isArray(e[String(s)]) ? e[String(s)].push(t.getValue()) : e[String(s)] = [t.getValue()] : e[String(s)] = t.getValue(), r && h.warn(
312
+ "Haori",
313
+ `Element cannot have both ${c.prefix}form-object and name attributes.`
314
+ );
315
+ for (const n of t.getChildElementFragments())
316
+ E.getPartValues(n, e);
317
+ } else if (r) {
318
+ const n = {};
319
+ for (const a of t.getChildElementFragments())
320
+ E.getPartValues(a, n);
321
+ Object.keys(n).length > 0 && (e[String(r)] = n), i && h.warn(
322
+ "Haori",
323
+ `Element cannot have both ${c.prefix}form-list and ${c.prefix}form-object attributes.`
324
+ );
325
+ } else if (i) {
326
+ const n = [];
327
+ for (const a of t.getChildElementFragments()) {
328
+ const u = {};
329
+ E.getPartValues(a, u), Object.keys(u).length > 0 && n.push(u);
330
+ }
331
+ n.length > 0 && (e[String(i)] = n);
332
+ } else
333
+ for (const n of t.getChildElementFragments())
334
+ E.getPartValues(n, e);
335
+ return e;
336
+ }
337
+ /**
338
+ * フォーム内にある入力エレメントに値を設定します。
339
+ * フォームのdata-bind属性に値が反映されます。
340
+ *
341
+ * @param form フォームのElementFragment
342
+ * @param values フォームに設定する値のオブジェクト
343
+ * @param force data-form-detach属性があるエレメントにも値を反映するかどうか
344
+ * @returns Promise(DOMの更新が完了したら解決される)
345
+ */
346
+ static setValues(t, e, s = !1) {
347
+ return E.setPartValues(t, e, null, s);
348
+ }
349
+ /**
350
+ * フラグメント内にある各入力エレメントに値を設定します。
351
+ *
352
+ * @param fragment 対象フラグメント
353
+ * @param values フラグメントに設定する値のオブジェクト
354
+ * @param index 配列の場合のインデックス
355
+ * @param force data-form-detach属性があるエレメントにも値を反映するかどうか
356
+ * @returns Promise(DOMの更新が完了したら解決される)
357
+ */
358
+ static setPartValues(t, e, s = null, r = !1) {
359
+ const i = [], n = t.getAttribute("name"), a = t.getAttribute(`${c.prefix}form-object`), u = t.getAttribute(`${c.prefix}form-list`), m = t.getAttribute(`${c.prefix}form-detach`);
360
+ if (n) {
361
+ if (!m || r) {
362
+ const l = e[String(n)];
363
+ u && Array.isArray(l) && s !== null ? i.push(t.setValue(l[s])) : typeof l == "string" || typeof l == "number" || typeof l == "boolean" || l === null ? i.push(t.setValue(l)) : i.push(t.setValue(String(l)));
364
+ }
365
+ } else if (a) {
366
+ const l = e[String(a)];
367
+ if (l && typeof l == "object")
368
+ for (const b of t.getChildElementFragments())
369
+ i.push(
370
+ E.setPartValues(
371
+ b,
372
+ l,
373
+ null,
374
+ r
375
+ )
376
+ );
377
+ } else if (u) {
378
+ const l = e[String(u)];
379
+ if (Array.isArray(l)) {
380
+ const b = t.getChildElementFragments();
381
+ for (let o = 0; o < b.length; o++) {
382
+ const d = b[o];
383
+ l.length > o ? i.push(
384
+ E.setPartValues(
385
+ d,
386
+ l[o],
387
+ o,
388
+ r
389
+ )
390
+ ) : i.push(E.setPartValues(d, {}, o, r));
391
+ }
392
+ }
393
+ } else
394
+ for (const l of t.getChildElementFragments())
395
+ i.push(E.setPartValues(l, e, null, r));
396
+ return Promise.all(i).then(() => {
397
+ });
398
+ }
399
+ /**
400
+ * 対象フラグメントとその子孫要素の値を初期化します。
401
+ * 値の初期化とメッセージのクリアを行います。
402
+ *
403
+ * @param fragment 対象フラグメント
404
+ * @returns すべての初期化処理が完了するPromise
405
+ */
406
+ static async reset(t) {
407
+ E.clearValues(t), await Promise.all([
408
+ E.clearMessages(t),
409
+ E.clearEachClones(t)
410
+ ]), await v.enqueue(() => {
411
+ const e = t.getTarget();
412
+ if (e instanceof HTMLFormElement)
413
+ e.reset();
414
+ else {
415
+ const s = e.parentElement;
416
+ if (s) {
417
+ const r = e.nextElementSibling, i = document.createElement("form");
418
+ i.appendChild(e), i.reset(), s.insertBefore(e, r);
419
+ }
420
+ }
421
+ }), await N.evaluateAll(t);
422
+ }
423
+ /**
424
+ * data-each によって生成された複製(テンプレート以外)を削除します。
425
+ * 既存のテンプレートは保持し、その後の再評価で必要に応じて再生成されます。
426
+ * 対象エレメント自体がdata-eachを持つ場合はその子の複製を削除しますが、
427
+ * 対象エレメント自体は削除しません。
428
+ */
429
+ static clearEachClones(t) {
430
+ const e = [], s = (i) => {
431
+ if (i.hasAttribute(`${c.prefix}each`))
432
+ for (const n of i.getChildElementFragments()) {
433
+ const a = n.hasAttribute(`${c.prefix}each-before`), u = n.hasAttribute(`${c.prefix}each-after`);
434
+ !a && !u && e.push(n.remove());
435
+ }
436
+ }, r = (i) => {
437
+ s(i);
438
+ for (const n of i.getChildElementFragments())
439
+ r(n);
440
+ };
441
+ s(t);
442
+ for (const i of t.getChildElementFragments())
443
+ r(i);
444
+ return Promise.all(e).then(() => {
445
+ });
446
+ }
447
+ /**
448
+ * 再帰的に値を初期化します。
449
+ *
450
+ * @param fragment 対象フラグメント
451
+ */
452
+ static clearValues(t) {
453
+ t.clearValue();
454
+ for (const e of t.getChildElementFragments())
455
+ E.clearValues(e);
456
+ }
457
+ /**
458
+ * フラグメントとその子要素のメッセージをクリアします。
459
+ *
460
+ * @param fragment 対象フラグメント
461
+ * @returns Promise(メッセージのクリアが完了したら解決される)
462
+ */
463
+ static clearMessages(t) {
464
+ return M.clearMessages(t.getTarget());
465
+ }
466
+ /**
467
+ * キーに一致するフラグメントにエラーメッセージを追加します。
468
+ * キーに一致するフラグメントが見つからない場合は、指定されたフラグメントにメッセージを追加します。
469
+ *
470
+ * @param fragment 対象フラグメント
471
+ * @param key キー(ドット区切りの文字列)
472
+ * @param message 追加するエラーメッセージ]
473
+ * @return Promise(メッセージの追加が完了したら解決される)
474
+ */
475
+ static addErrorMessage(t, e, s) {
476
+ const r = [], i = E.findFragmentsByKey(t, e);
477
+ return i.forEach((n) => {
478
+ r.push(M.addErrorMessage(n.getTarget(), s));
479
+ }), i.length === 0 && r.push(M.addErrorMessage(t.getTarget(), s)), Promise.all(r).then(() => {
480
+ });
481
+ }
482
+ /**
483
+ * 指定されたキーに一致するフラグメントを検索します。
484
+ *
485
+ * @param fragment 対象フラグメント
486
+ * @param key キー(ドット区切りの文字列)
487
+ * @returns 一致するフラグメントの配列
488
+ */
489
+ static findFragmentsByKey(t, e) {
490
+ return E.findFragmentByKeyParts(t, e.split("."));
491
+ }
492
+ /**
493
+ * 指定されたキーに一致するフラグメントを検索します。
494
+ * data-form-list属性で指定された場合はdata-row属性を持つ子要素の位置と添字が一致するものを対象とします。
495
+ *
496
+ * @param fragment 対象フラグメント
497
+ * @param parts キーのパーツ
498
+ * @returns 一致するフラグメントの配列
499
+ */
500
+ static findFragmentByKeyParts(t, e) {
501
+ const s = [], r = e[0];
502
+ if (e.length == 1 && t.getAttribute("name") === r && s.push(t), t.hasAttribute(`${c.prefix}form-object`))
503
+ e.length > 1 && t.getAttribute(`${c.prefix}form-object`) === r && t.getChildElementFragments().forEach((n) => {
504
+ s.push(...E.findFragmentByKeyParts(n, e.slice(1)));
505
+ });
506
+ else if (t.hasAttribute(`${c.prefix}form-list`)) {
507
+ if (e.length > 1) {
508
+ const i = t.getAttribute(`${c.prefix}form-list`), n = r.lastIndexOf("["), a = r.lastIndexOf("]");
509
+ if (n !== -1 && a !== -1 && n < a) {
510
+ const u = r.substring(0, n);
511
+ if (i === u) {
512
+ const m = r.substring(n + 1, a), l = Number(m);
513
+ if (isNaN(l))
514
+ h.error("Haori", `Invalid index: ${r}`);
515
+ else {
516
+ const b = t.getChildElementFragments().filter((o) => o.hasAttribute(`${c.prefix}row`));
517
+ l < b.length && s.push(
518
+ ...E.findFragmentByKeyParts(b[l], e.slice(1))
519
+ );
520
+ }
521
+ }
522
+ }
523
+ }
524
+ } else
525
+ t.getChildElementFragments().forEach((i) => {
526
+ s.push(...E.findFragmentByKeyParts(i, e));
527
+ });
528
+ return s;
529
+ }
530
+ /**
531
+ * 対象のフラグメントがフォームフラグメントであればそれを返し、
532
+ * そうでなければ先祖要素をたどってフォームフラグメントを探します。
533
+ *
534
+ * @param fragment
535
+ */
536
+ static getFormFragment(t) {
537
+ if (t.getTarget() instanceof HTMLFormElement)
538
+ return t;
539
+ const s = t.getParent();
540
+ return s ? this.getFormFragment(s) : null;
541
+ }
542
+ }
543
+ const P = class P {
544
+ /**
545
+ * 式を評価します。
546
+ *
547
+ * @param expression 評価する式文字列
548
+ * @param bindedValue バインドされた値のオブジェクト
549
+ */
550
+ static evaluate(t, e = {}) {
551
+ if (t.trim() === "")
552
+ return h.warn("[Haori]", t, "Expression is empty"), null;
553
+ if (this.containsDangerousPatterns(t))
554
+ return h.warn("[Haori]", t, "Expression contains dangerous patterns"), null;
555
+ if (this.containsForbiddenKeys(e))
556
+ return h.warn("[Haori]", e, "Binded values contain forbidden keys"), null;
557
+ const s = Object.keys(e).filter(
558
+ (n) => !this.FORBIDDEN_NAMES.includes(n) && !this.STRICT_FORBIDDEN_NAMES.includes(n)
559
+ ).sort(), r = `${t}:${s.join(",")}`;
560
+ let i = this.EXPRESSION_CACHE.get(r);
561
+ if (!i) {
562
+ const n = `"use strict";
563
+ ${this.assignments};
564
+ return (${t});`;
565
+ try {
566
+ i = new Function(...s, n), this.EXPRESSION_CACHE.set(r, i);
567
+ } catch (a) {
568
+ return h.error(
569
+ "[Haori]",
570
+ "Failed to compile expression:",
571
+ t,
572
+ a
573
+ ), null;
574
+ }
575
+ }
576
+ try {
577
+ const n = [];
578
+ return s.forEach((a) => {
579
+ n.push(e[a]);
580
+ }), i(...n);
581
+ } catch (n) {
582
+ return h.error("[Haori]", "Expression evaluation error:", t, n), n instanceof ReferenceError ? void 0 : null;
583
+ }
584
+ }
585
+ /**
586
+ * 式にevalや危険な構文が含まれているかチェックします。
587
+ *
588
+ * @param expression チェック対象の式文字列
589
+ * @return 危険なパターンが含まれている場合はtrue
590
+ */
591
+ static containsDangerousPatterns(t) {
592
+ return [
593
+ /\beval\s*\(/,
594
+ // eval(...)
595
+ /\barguments\s*\[/,
596
+ // arguments[...]
597
+ /\barguments\s*\./
598
+ // arguments.xxx
599
+ ].some((s) => s.test(t));
600
+ }
601
+ /**
602
+ * valuesオブジェクトに禁止識別子が含まれていないか再帰的にチェックします。
603
+ *
604
+ * @param obj チェック対象のオブジェクト
605
+ * @return 禁止識別子が含まれていればtrue
606
+ */
607
+ static containsForbiddenKeys(t) {
608
+ if (t && typeof t == "object") {
609
+ for (const e of Object.keys(t))
610
+ if (this.FORBIDDEN_NAMES.includes(e) || this.STRICT_FORBIDDEN_NAMES.includes(e) || this.containsForbiddenKeys(t[e]))
611
+ return !0;
612
+ }
613
+ return !1;
614
+ }
615
+ };
616
+ P.FORBIDDEN_NAMES = [
617
+ // グローバルオブジェクト
618
+ "window",
619
+ "self",
620
+ "globalThis",
621
+ "frames",
622
+ "parent",
623
+ "top",
624
+ // 危険な関数/オブジェクト
625
+ "Function",
626
+ "setTimeout",
627
+ "setInterval",
628
+ "requestAnimationFrame",
629
+ "alert",
630
+ "confirm",
631
+ "prompt",
632
+ "fetch",
633
+ "XMLHttpRequest",
634
+ // 脱出経路・プロトタイプ
635
+ "constructor",
636
+ "__proto__",
637
+ "prototype",
638
+ "Object",
639
+ // その他
640
+ "document",
641
+ "location",
642
+ "navigator",
643
+ "localStorage",
644
+ "sessionStorage",
645
+ "IndexedDB",
646
+ "history"
647
+ ], P.STRICT_FORBIDDEN_NAMES = ["eval", "arguments"], P.EXPRESSION_CACHE = /* @__PURE__ */ new Map(), (() => {
648
+ const t = [];
649
+ P.FORBIDDEN_NAMES.forEach((e) => {
650
+ t.push(`const ${e} = undefined`);
651
+ }), P.assignments = t.join(`;
652
+ `);
653
+ })();
654
+ let L = P;
655
+ const R = class R {
656
+ /**
657
+ * フラグメントのコンストラクタ。
658
+ *
659
+ * @param target 対象ノード
660
+ */
661
+ constructor(t) {
662
+ this.parent = null, this.mounted = !1, this.skipMutationNodes = !1, this.target = t, R.FRAGMENT_CACHE.set(t, this);
663
+ }
664
+ static get(t) {
665
+ if (t == null)
666
+ return null;
667
+ if (R.FRAGMENT_CACHE.has(t))
668
+ return R.FRAGMENT_CACHE.get(t);
669
+ let e;
670
+ switch (t.nodeType) {
671
+ case Node.ELEMENT_NODE:
672
+ e = new F(t);
673
+ break;
674
+ case Node.TEXT_NODE:
675
+ e = new j(t);
676
+ break;
677
+ case Node.COMMENT_NODE:
678
+ e = new U(t);
679
+ break;
680
+ default:
681
+ return h.warn("[Haori]", "Unsupported node type:", t.nodeType), null;
682
+ }
683
+ return e;
684
+ }
685
+ /**
686
+ * skipMutationNodesフラグの値を取得します。
687
+ *
688
+ * @returns skipMutationNodesの値
689
+ */
690
+ isSkipMutationNodes() {
691
+ return this.skipMutationNodes;
692
+ }
693
+ /**
694
+ * フラグメントをDOMから除去します。
695
+ *
696
+ * @return 除去のPromise
697
+ */
698
+ unmount() {
699
+ if (!this.mounted || this.skipMutationNodes)
700
+ return Promise.resolve();
701
+ if (this.parent) {
702
+ const t = this.parent, e = t.skipMutationNodes;
703
+ return v.enqueue(() => {
704
+ t.skipMutationNodes = !0, this.target.parentNode === t.getTarget() && t.getTarget().removeChild(this.target), this.mounted = !1;
705
+ }).finally(() => {
706
+ t.skipMutationNodes = e;
707
+ });
708
+ } else {
709
+ const t = this.target.parentNode;
710
+ if (t)
711
+ return v.enqueue(() => {
712
+ this.target.parentNode === t && t.removeChild(this.target), this.mounted = !1;
713
+ });
714
+ this.mounted = !1;
715
+ }
716
+ return Promise.resolve();
717
+ }
718
+ /**
719
+ * フラグメントをDOMに追加します。
720
+ *
721
+ * @return 追加のPromise
722
+ */
723
+ mount() {
724
+ if (this.mounted || this.skipMutationNodes)
725
+ return Promise.resolve();
726
+ if (this.parent) {
727
+ const t = this.parent, e = t.skipMutationNodes;
728
+ return v.enqueue(() => {
729
+ t.skipMutationNodes = !0, this.target.parentNode !== t.getTarget() && t.getTarget().appendChild(this.target), this.mounted = !0;
730
+ }).finally(() => {
731
+ t.skipMutationNodes = e;
732
+ });
733
+ }
734
+ return Promise.resolve();
735
+ }
736
+ /**
737
+ * フラグメントのマウント状態を取得します。
738
+ *
739
+ * @returns マウント状態
740
+ */
741
+ isMounted() {
742
+ return this.mounted;
743
+ }
744
+ /**
745
+ * フラグメントのマウント状態を設定します。
746
+ *
747
+ * @param mounted マウント状態
748
+ */
749
+ setMounted(t) {
750
+ this.mounted = t;
751
+ }
752
+ /**
753
+ * フラグメントとノードを削除します。
754
+ *
755
+ * @param unmount DOMからの除去を行うかどうか(内部の子呼び出しの場合のみfalseとする)
756
+ * @return 除去のPromise
757
+ */
758
+ remove(t = !0) {
759
+ return this.parent && this.parent.removeChild(this), R.FRAGMENT_CACHE.delete(this.target), t ? this.unmount() : Promise.resolve();
760
+ }
761
+ /**
762
+ * 対象ノードを取得します。
763
+ *
764
+ * @returns 対象ノード
765
+ */
766
+ getTarget() {
767
+ return this.target;
768
+ }
769
+ /**
770
+ * 親フラグメントを取得します。
771
+ *
772
+ * @returns 親フラグメント
773
+ */
774
+ getParent() {
775
+ return this.parent;
776
+ }
777
+ /**
778
+ * 親フラグメントを設定します。
779
+ *
780
+ * @param parent 親フラグメント
781
+ */
782
+ setParent(t) {
783
+ this.parent = t;
784
+ }
785
+ };
786
+ R.FRAGMENT_CACHE = /* @__PURE__ */ new WeakMap();
787
+ let A = R;
788
+ class F extends A {
789
+ /**
790
+ * エレメントフラグメントのコンストラクタ。
791
+ * アトリビュートや子フラグメントの作成も行います。
792
+ *
793
+ * @param target 対象エレメント
794
+ */
795
+ constructor(t) {
796
+ super(t), this.INPUT_EVENT_TYPES = [
797
+ "text",
798
+ "password",
799
+ "email",
800
+ "url",
801
+ "tel",
802
+ "search",
803
+ "number",
804
+ "range",
805
+ "color",
806
+ "date",
807
+ "datetime-local",
808
+ "month",
809
+ "time",
810
+ "week"
811
+ ], this.children = [], this.attributeMap = /* @__PURE__ */ new Map(), this.bindingData = null, this.bindingDataCache = null, this.visible = !0, this.display = null, this.template = null, this.listKey = null, this.value = null, this.skipMutationAttributes = !1, this.skipChangeValue = !1, this.syncValue(), t.getAttributeNames().forEach((e) => {
812
+ const s = t.getAttribute(e);
813
+ if (s !== null && !this.attributeMap.has(e)) {
814
+ const r = new I(e, s);
815
+ this.attributeMap.set(e, r);
816
+ }
817
+ }), t.childNodes.forEach((e) => {
818
+ const s = A.get(e);
819
+ s.setParent(this), this.children.push(s);
820
+ });
821
+ }
822
+ /**
823
+ * 子フラグメントのリストを取得します。
824
+ *
825
+ * @returns 子フラグメントのリスト
826
+ */
827
+ getChildren() {
828
+ return this.children;
829
+ }
830
+ /**
831
+ * 子エレメントフラグメントのリストを取得します。
832
+ *
833
+ * @returns 子エレメントフラグメントのリスト
834
+ */
835
+ getChildElementFragments() {
836
+ return this.children.filter(
837
+ (t) => t instanceof F
838
+ );
839
+ }
840
+ /**
841
+ * 子フラグメントをリストに追加します。
842
+ * DOMの追加は行いません。
843
+ *
844
+ * @param child 追加する子フラグメント
845
+ */
846
+ pushChild(t) {
847
+ this.children.push(t), t.setParent(this);
848
+ }
849
+ /**
850
+ * 子フラグメントをリストから削除します。
851
+ * DOMからの削除は行いません。
852
+ *
853
+ * @param child 削除する子フラグメント
854
+ */
855
+ removeChild(t) {
856
+ const e = this.children.indexOf(t);
857
+ if (e < 0) {
858
+ h.warn("[Haori]", "Child fragment not found.", t);
859
+ return;
860
+ }
861
+ this.children.splice(e, 1), t.setParent(null);
862
+ }
863
+ /**
864
+ * フラグメントをクローンします。
865
+ *
866
+ * @returns クローンされたフラグメント
867
+ */
868
+ clone() {
869
+ const t = new F(
870
+ this.target.cloneNode(!1)
871
+ );
872
+ return this.children.forEach((e) => {
873
+ const s = e.clone();
874
+ t.getTarget().appendChild(s.getTarget()), t.pushChild(s);
875
+ }), t.mounted = !1, t.bindingData = this.bindingData, t.clearBindingDataCache(), t.visible = this.visible, t.display = this.display, t.template = this.template, t;
876
+ }
877
+ /**
878
+ * フラグメントとノードを削除します。
879
+ *
880
+ * @param unmount DOMからの除去を行うかどうか(内部の子呼び出しの場合のみfalseとする)
881
+ * @return 除去のPromise
882
+ */
883
+ remove(t = !0) {
884
+ const e = [];
885
+ return this.children.forEach((s) => {
886
+ e.push(s.remove(!1));
887
+ }), this.children.length = 0, this.attributeMap.clear(), this.bindingData = null, this.bindingDataCache = null, this.template && (e.push(this.template.remove(!1)), this.template = null), e.push(super.remove(t)), Promise.all(e).then(() => {
888
+ });
889
+ }
890
+ /**
891
+ * フラグメントの対象エレメントを取得します。
892
+ *
893
+ * @returns フラグメントの対象エレメント
894
+ */
895
+ getTarget() {
896
+ return this.target;
897
+ }
898
+ /**
899
+ * 継承を考慮したバインドデータを取得します。
900
+ *
901
+ * @returns バインドデータのオブジェクト
902
+ */
903
+ getBindingData() {
904
+ return this.bindingDataCache ? this.bindingDataCache : (this.bindingDataCache = {}, this.parent && Object.assign(this.bindingDataCache, this.parent.getBindingData()), this.bindingData && Object.assign(this.bindingDataCache, this.bindingData), this.bindingDataCache);
905
+ }
906
+ /**
907
+ * 生のバインドデータを取得します。
908
+ *
909
+ * @returns 生のバインドデータ
910
+ */
911
+ getRawBindingData() {
912
+ return this.bindingData;
913
+ }
914
+ /**
915
+ * バインドデータを設定します。
916
+ *
917
+ * @param data バインドデータ
918
+ */
919
+ setBindingData(t) {
920
+ this.bindingData = t, this.clearBindingDataCache();
921
+ }
922
+ /**
923
+ * バインドデータのキャッシュをクリアします。
924
+ */
925
+ clearBindingDataCache() {
926
+ this.bindingDataCache = null, this.children.forEach((t) => {
927
+ t instanceof F && t.clearBindingDataCache();
928
+ });
929
+ }
930
+ /**
931
+ * フラグメントのテンプレートを取得します。
932
+ *
933
+ * @returns テンプレート
934
+ */
935
+ getTemplate() {
936
+ return this.template;
937
+ }
938
+ /**
939
+ * フラグメントのテンプレートを設定します。
940
+ *
941
+ * @param template フラグメントのテンプレート
942
+ */
943
+ setTemplate(t) {
944
+ this.template = t;
945
+ }
946
+ /**
947
+ * 比較用リストキーを設定します。
948
+ *
949
+ * @param key 比較用リストキー
950
+ */
951
+ setListKey(t) {
952
+ this.listKey = t;
953
+ }
954
+ /**
955
+ * 比較用リストキーを取得します。
956
+ *
957
+ * @returns 比較用リストキー
958
+ */
959
+ getListKey() {
960
+ return this.listKey;
961
+ }
962
+ /**
963
+ * 入力エレメントに値を設定します。
964
+ * チェックボックとラジオボタンの場合は値に一致するかどうかでチェック状態を変更します。
965
+ *
966
+ * @param value 値
967
+ * @returns エレメントの更新のPromise
968
+ */
969
+ setValue(t) {
970
+ if (this.skipChangeValue || this.value === t)
971
+ return Promise.resolve();
972
+ const e = this.getTarget();
973
+ if (e instanceof HTMLInputElement && (e.type === "checkbox" || e.type === "radio")) {
974
+ const s = this.getAttribute("value");
975
+ let r;
976
+ return s === "true" ? r = t === !0 : s === "false" ? r = t === !1 : r = s === String(t), this.value = r ? t : null, e.checked === r ? Promise.resolve() : (this.skipChangeValue = !0, v.enqueue(() => {
977
+ e.checked = r, e.dispatchEvent(new Event("change", { bubbles: !0 }));
978
+ }).finally(() => {
979
+ this.skipChangeValue = !1;
980
+ }));
981
+ } else return e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement || e instanceof HTMLSelectElement ? (this.value = t, this.skipChangeValue = !0, v.enqueue(() => {
982
+ e.value = t === null ? "" : String(t), (e instanceof HTMLInputElement && this.INPUT_EVENT_TYPES.includes(e.type) || e instanceof HTMLTextAreaElement) && e.dispatchEvent(new Event("input", { bubbles: !0 })), e.dispatchEvent(new Event("change", { bubbles: !0 }));
983
+ }).finally(() => {
984
+ this.skipChangeValue = !1;
985
+ })) : (h.warn(
986
+ "[Haori]",
987
+ "setValue is not supported for this element type.",
988
+ e
989
+ ), Promise.resolve());
990
+ }
991
+ /**
992
+ * 入力エレメントの値を取得します。
993
+ * DOM要素の現在の値と同期します。
994
+ *
995
+ * @returns 入力エレメントの値
996
+ */
997
+ getValue() {
998
+ return this.value;
999
+ }
1000
+ /**
1001
+ * 内部の値をクリアします。エレメントのvalue値は変化しません。
1002
+ */
1003
+ clearValue() {
1004
+ this.value = null;
1005
+ }
1006
+ /**
1007
+ * 内部の値をDOMの値と同期します。
1008
+ * changeイベント時など、DOM値が変更された後に呼び出されます。
1009
+ */
1010
+ syncValue() {
1011
+ const t = this.getTarget();
1012
+ if (t instanceof HTMLInputElement)
1013
+ if (t.type === "checkbox" || t.type === "radio")
1014
+ if (t.checked) {
1015
+ const e = t.value;
1016
+ e === "true" ? this.value = !0 : e === "false" ? this.value = !1 : this.value = e;
1017
+ } else {
1018
+ const e = t.value;
1019
+ e === "true" ? this.value = !1 : e === "false" ? this.value = !0 : this.value = null;
1020
+ }
1021
+ else
1022
+ this.value = t.value;
1023
+ else t instanceof HTMLTextAreaElement ? this.value = t.value : t instanceof HTMLSelectElement && (this.value = t.value);
1024
+ }
1025
+ /**
1026
+ * 属性の値を評価して設定します。
1027
+ * 評価値がfalseの場合は属性を削除します。
1028
+ * 矯正評価属性の場合は元の値を設定します。
1029
+ *
1030
+ * @param name 属性名
1031
+ * @param value 属性値
1032
+ * @returns 属性の更新のPromise
1033
+ */
1034
+ setAttribute(t, e) {
1035
+ if (this.skipMutationAttributes)
1036
+ return Promise.resolve();
1037
+ if (e === null)
1038
+ return this.removeAttribute(t);
1039
+ const s = new I(t, e);
1040
+ this.attributeMap.set(t, s), this.skipMutationAttributes = !0;
1041
+ const r = this.getTarget(), i = s.isForceEvaluation() ? e : this.getAttribute(t);
1042
+ return v.enqueue(() => {
1043
+ if (i === null || i === !1)
1044
+ r.removeAttribute(t);
1045
+ else {
1046
+ const n = String(i);
1047
+ r.getAttribute(t) !== n && r.setAttribute(t, n);
1048
+ }
1049
+ }).finally(() => {
1050
+ this.skipMutationAttributes = !1;
1051
+ });
1052
+ }
1053
+ /**
1054
+ * 属性の値を削除します。
1055
+ *
1056
+ * @param name 属性名
1057
+ * @returns 属性の削除のPromise
1058
+ */
1059
+ removeAttribute(t) {
1060
+ if (this.skipMutationAttributes)
1061
+ return Promise.resolve();
1062
+ this.attributeMap.delete(t), this.skipMutationAttributes = !0;
1063
+ const e = this.getTarget();
1064
+ return v.enqueue(() => {
1065
+ e.removeAttribute(t);
1066
+ }).finally(() => {
1067
+ this.skipMutationAttributes = !1;
1068
+ });
1069
+ }
1070
+ /**
1071
+ * 属性の評価された値を取得します。
1072
+ * 複数の評価値がある場合は結合して返します。
1073
+ *
1074
+ * @param name 属性名
1075
+ * @returns 評価された値
1076
+ */
1077
+ getAttribute(t) {
1078
+ const e = this.attributeMap.get(t);
1079
+ if (e === void 0)
1080
+ return null;
1081
+ const s = e.evaluate(this.getBindingData());
1082
+ return s.length === 1 ? s[0] : $.joinEvaluateResults(s);
1083
+ }
1084
+ /**
1085
+ * 属性の生の値を取得します。
1086
+ *
1087
+ * @param name 属性名
1088
+ * @returns 生の属性値
1089
+ */
1090
+ getRawAttribute(t) {
1091
+ const e = this.attributeMap.get(t);
1092
+ return e === void 0 ? null : e.getValue();
1093
+ }
1094
+ /**
1095
+ * 属性名のリストを取得します。
1096
+ *
1097
+ * @return 属性名のリスト
1098
+ */
1099
+ getAttributeNames() {
1100
+ return Array.from(this.attributeMap.keys());
1101
+ }
1102
+ /**
1103
+ * 属性の有無を確認します。
1104
+ *
1105
+ * @param name 属性名
1106
+ * @returns 属性の有無
1107
+ */
1108
+ hasAttribute(t) {
1109
+ return this.attributeMap.has(t);
1110
+ }
1111
+ /**
1112
+ * 子ノードを参照ノードの前に挿入します。
1113
+ * 参照ノードがnullの場合、親の最後に追加されます。
1114
+ *
1115
+ * @param newChild 新しい子ノード
1116
+ * @param referenceChild 参照ノード
1117
+ * @return 挿入のPromise
1118
+ */
1119
+ insertBefore(t, e) {
1120
+ if (this.skipMutationNodes)
1121
+ return Promise.resolve();
1122
+ if (t === this)
1123
+ return h.error("[Haori]", "Cannot insert element as child of itself"), Promise.reject(new Error("Self-insertion not allowed"));
1124
+ const s = /* @__PURE__ */ new Set();
1125
+ let r = this.parent;
1126
+ for (; r; )
1127
+ s.add(r), r = r.getParent();
1128
+ if (s.has(t))
1129
+ return h.error("[Haori]", "Cannot create circular reference"), Promise.reject(new Error("Circular reference detected"));
1130
+ const i = t.getParent() === this;
1131
+ let n = -1, a = -1;
1132
+ i && (n = this.children.indexOf(t), e !== null && (a = this.children.indexOf(e)));
1133
+ const u = t.getParent();
1134
+ if (u !== null && u.removeChild(t), e === null)
1135
+ this.children.push(t);
1136
+ else {
1137
+ let l;
1138
+ i ? n !== -1 && n < a ? l = a - 1 : l = a : l = this.children.indexOf(e), l === -1 ? (h.warn(
1139
+ "[Haori]",
1140
+ "Reference child not found in children.",
1141
+ e
1142
+ ), this.children.push(t)) : this.children.splice(l, 0, t);
1143
+ }
1144
+ t.setParent(this), t.setMounted(this.mounted);
1145
+ const m = this.skipMutationNodes;
1146
+ return this.skipMutationNodes = !0, v.enqueue(() => {
1147
+ this.target.insertBefore(
1148
+ t.getTarget(),
1149
+ e?.getTarget() || null
1150
+ );
1151
+ }).finally(() => {
1152
+ this.skipMutationNodes = m;
1153
+ });
1154
+ }
1155
+ /**
1156
+ * 指定した参照ノードの後に子ノードを挿入します。
1157
+ *
1158
+ * @param newChild 子ノード
1159
+ * @param referenceChild 参照ノード
1160
+ * @returns 挿入のPromise
1161
+ */
1162
+ insertAfter(t, e) {
1163
+ if (e == null)
1164
+ return this.insertBefore(t, null);
1165
+ const s = this.children.indexOf(e);
1166
+ return s === -1 ? (h.warn(
1167
+ "[Haori]",
1168
+ "Reference child not found in children.",
1169
+ e
1170
+ ), this.insertBefore(t, null)) : this.insertBefore(t, this.children[s + 1] || null);
1171
+ }
1172
+ /**
1173
+ * 前のエレメントフラグメントを取得します。
1174
+ * 存在しない場合はnullを返します。
1175
+ *
1176
+ * @return 前のエレメントフラグメントまたはnull
1177
+ */
1178
+ getPrevious() {
1179
+ const t = this.getParent();
1180
+ if (t === null)
1181
+ return null;
1182
+ const e = t.getChildElementFragments(), s = e.indexOf(this);
1183
+ return s <= 0 ? null : e[s - 1];
1184
+ }
1185
+ /**
1186
+ * 次のエレメントフラグメントを取得します。
1187
+ * 存在しない場合はnullを返します。
1188
+ *
1189
+ * @return 次のエレメントフラグメントまたはnull
1190
+ */
1191
+ getNext() {
1192
+ const t = this.getParent();
1193
+ if (t === null)
1194
+ return null;
1195
+ const e = t.getChildElementFragments(), s = e.indexOf(this);
1196
+ return s < 0 || s + 1 >= e.length ? null : e[s + 1];
1197
+ }
1198
+ /**
1199
+ * 表示状態を返します。
1200
+ *
1201
+ * @returns 表示状態
1202
+ */
1203
+ isVisible() {
1204
+ return this.visible;
1205
+ }
1206
+ /**
1207
+ * エレメントを非表示にします。
1208
+ *
1209
+ * @returns エレメントの非表示のPromise
1210
+ */
1211
+ hide() {
1212
+ return this.visible = !1, this.display = this.getTarget().style.display, this.getTarget().style.display = "none", this.getTarget().setAttribute(`${c.prefix}if-false`, ""), Promise.resolve();
1213
+ }
1214
+ /**
1215
+ * エレメントを表示します。
1216
+ *
1217
+ * @return エレメントの表示のPromise
1218
+ */
1219
+ show() {
1220
+ return this.getTarget().style.display = this.display ?? "", this.getTarget().removeAttribute(`${c.prefix}if-false`), this.visible = !0, Promise.resolve();
1221
+ }
1222
+ /**
1223
+ * 指定した属性名を持つ最も近い親要素を返します。
1224
+ * 見つからない場合はnullを返します。
1225
+ *
1226
+ * @param name 属性名
1227
+ * @returns 最も近い親要素またはnull
1228
+ */
1229
+ closestByAttribute(t) {
1230
+ if (this.hasAttribute(t))
1231
+ return this;
1232
+ const e = this.getParent();
1233
+ return e === null ? null : e.closestByAttribute(t);
1234
+ }
1235
+ }
1236
+ class j extends A {
1237
+ /**
1238
+ * テキストフラグメントのコンストラクタ。
1239
+ * 対象テキストノードの内容を初期化します。
1240
+ *
1241
+ * @param target 対象テキストノード
1242
+ */
1243
+ constructor(t) {
1244
+ super(t), this.skipMutation = !1, this.text = t.textContent || "", this.contents = new $(this.text);
1245
+ }
1246
+ /**
1247
+ * フラグメントをクローンします。
1248
+ *
1249
+ * @returns クローンされたフラグメント
1250
+ */
1251
+ clone() {
1252
+ const t = new j(this.target.cloneNode(!0));
1253
+ return t.mounted = !1, t.text = this.text, t.contents = this.contents, t;
1254
+ }
1255
+ /**
1256
+ * フラグメントの対象ノードを取得します。
1257
+ *
1258
+ * @returns フラグメントの対象ノード
1259
+ */
1260
+ getTarget() {
1261
+ return this.target;
1262
+ }
1263
+ /**
1264
+ * コンテンツを更新します。
1265
+ *
1266
+ * @param text テキスト
1267
+ * @returns 更新のPromise
1268
+ */
1269
+ setContent(t) {
1270
+ return this.skipMutation || this.text === t ? Promise.resolve() : (this.text = t, this.contents = new $(t), this.evaluate());
1271
+ }
1272
+ /**
1273
+ * フラグメントを評価します。
1274
+ *
1275
+ * @returns 評価結果のPromise
1276
+ */
1277
+ evaluate() {
1278
+ return this.contents.isRawEvaluate && this.parent === null ? Promise.reject(
1279
+ new Error("Parent fragment is required for raw evaluation")
1280
+ ) : v.enqueue(() => {
1281
+ this.skipMutation = !0, this.contents.isRawEvaluate ? this.parent.getTarget().innerHTML = this.contents.evaluate(
1282
+ this.parent.getBindingData()
1283
+ )[0] : this.contents.isEvaluate ? this.target.textContent = $.joinEvaluateResults(
1284
+ this.contents.evaluate(this.parent.getBindingData())
1285
+ ) : this.target.textContent = this.text;
1286
+ }).finally(() => {
1287
+ this.skipMutation = !1;
1288
+ });
1289
+ }
1290
+ }
1291
+ class U extends A {
1292
+ /**
1293
+ * コメントフラグメントのコンストラクタ。
1294
+ * 対象コメントノードの内容を初期化します。
1295
+ *
1296
+ * @param target 対象コメントノード
1297
+ */
1298
+ constructor(t) {
1299
+ super(t), this.skipMutation = !1, this.text = t.textContent || "";
1300
+ }
1301
+ /**
1302
+ * フラグメントをクローンします。
1303
+ *
1304
+ * @returns クローンされたフラグメント
1305
+ */
1306
+ clone() {
1307
+ const t = new U(this.target.cloneNode(!0));
1308
+ return t.mounted = !1, t.text = this.text, t;
1309
+ }
1310
+ /**
1311
+ * フラグメントの対象ノードを取得します。
1312
+ *
1313
+ * @returns フラグメントの対象ノード
1314
+ */
1315
+ getTarget() {
1316
+ return this.target;
1317
+ }
1318
+ /**
1319
+ * コンテンツを更新します。
1320
+ *
1321
+ * @param text テキスト
1322
+ * @return 更新のPromise
1323
+ */
1324
+ setContent(t) {
1325
+ return this.skipMutation || this.text === t ? Promise.resolve() : (this.text = t, v.enqueue(() => {
1326
+ this.skipMutation = !0, this.target.textContent = this.text;
1327
+ }).finally(() => {
1328
+ this.skipMutation = !1;
1329
+ }));
1330
+ }
1331
+ }
1332
+ const V = class V {
1333
+ /**
1334
+ * コンストラクタ。
1335
+ *
1336
+ * @param text テキスト
1337
+ */
1338
+ constructor(t) {
1339
+ this.contents = [], this.isEvaluate = !1, this.isRawEvaluate = !1, this.value = t;
1340
+ const e = [...t.matchAll(V.PLACEHOLDER_REGEX)];
1341
+ let s = 0, r = !1, i = !1;
1342
+ for (const n of e) {
1343
+ n.index > s && this.contents.push({
1344
+ text: t.slice(s, n.index),
1345
+ type: 0
1346
+ /* TEXT */
1347
+ });
1348
+ const a = {
1349
+ text: n[1] ?? n[2],
1350
+ type: n[1] ? 2 : 1
1351
+ /* EXPRESSION */
1352
+ };
1353
+ r = !0, i = i || a.type === 2, this.contents.push(a), s = n.index + n[0].length;
1354
+ }
1355
+ s < t.length && this.contents.push({
1356
+ text: t.slice(s),
1357
+ type: 0
1358
+ /* TEXT */
1359
+ }), this.isEvaluate = r, this.isRawEvaluate = i, this.checkRawExpressions();
1360
+ }
1361
+ /**
1362
+ * 評価結果を結合して文字列にします。
1363
+ *
1364
+ * @param contents 評価結果の配列
1365
+ * @returns 結合された文字列
1366
+ */
1367
+ static joinEvaluateResults(t) {
1368
+ return t === null || t.length === 0 ? "" : t.map((e) => e == null || e === !1 || Number.isNaN(e) ? "" : typeof e != "string" ? String(e) : e).join("");
1369
+ }
1370
+ /**
1371
+ * 評価前の値を取得します。
1372
+ *
1373
+ * @returns 評価前の値
1374
+ */
1375
+ getValue() {
1376
+ return this.value;
1377
+ }
1378
+ /**
1379
+ * RAW_EXPRESSION のチェックを行います。
1380
+ */
1381
+ checkRawExpressions() {
1382
+ for (let t = 0; t < this.contents.length; t++)
1383
+ this.contents[t].type === 2 && this.contents.length > 1 && (h.error(
1384
+ "[Haori]",
1385
+ "Raw expressions are not allowed in multi-content expressions."
1386
+ ), this.contents[t].type = 1);
1387
+ }
1388
+ /**
1389
+ * 式評価を行い、結果を返します。
1390
+ *
1391
+ * @param bindingValues バインディングされた値のオブジェクト
1392
+ * @returns 評価結果のリスト
1393
+ */
1394
+ evaluate(t) {
1395
+ if (!this.isEvaluate && !this.isRawEvaluate)
1396
+ return this.contents.map((s) => s.text);
1397
+ const e = [];
1398
+ return this.contents.forEach((s) => {
1399
+ try {
1400
+ if (s.type === 1 || s.type === 2) {
1401
+ const r = L.evaluate(s.text, t);
1402
+ e.push(r);
1403
+ } else
1404
+ e.push(s.text);
1405
+ } catch (r) {
1406
+ h.error(
1407
+ "[Haori]",
1408
+ `Error evaluating text expression: ${s.text}`,
1409
+ r
1410
+ ), e.push("");
1411
+ }
1412
+ }), e;
1413
+ }
1414
+ };
1415
+ V.PLACEHOLDER_REGEX = /\{\{\{([\s\S]+?)\}\}\}|\{\{([\s\S]+?)\}\}/g;
1416
+ let $ = V;
1417
+ const q = class q extends $ {
1418
+ /**
1419
+ * コンストラクタ。
1420
+ *
1421
+ * @param name 属性名
1422
+ * @param text 属性値
1423
+ */
1424
+ constructor(t, e) {
1425
+ super(e), this.forceEvaluation = q.FORCE_EVALUATION_ATTRIBUTES.includes(t);
1426
+ }
1427
+ /**
1428
+ * 強制評価フラグを取得します。
1429
+ *
1430
+ * @returns 強制評価フラグ
1431
+ */
1432
+ isForceEvaluation() {
1433
+ return this.forceEvaluation;
1434
+ }
1435
+ /**
1436
+ * 式評価を行い、結果を返します。
1437
+ *
1438
+ * @param bindingValues バインディングされた値のオブジェクト
1439
+ * @returns 評価結果のリスト
1440
+ */
1441
+ evaluate(t) {
1442
+ if (!this.isEvaluate && !this.forceEvaluation)
1443
+ return this.contents.map((s) => s.text);
1444
+ const e = [];
1445
+ return this.contents.forEach((s) => {
1446
+ try {
1447
+ if (this.forceEvaluation && s.type === 0 || s.type === 1 || s.type === 2) {
1448
+ const r = L.evaluate(s.text, t);
1449
+ e.push(r);
1450
+ } else
1451
+ e.push(s.text);
1452
+ } catch (r) {
1453
+ h.error(
1454
+ "[Haori]",
1455
+ `Error evaluating attribute expression: ${s.text}`,
1456
+ r
1457
+ ), e.push("");
1458
+ }
1459
+ }), this.forceEvaluation && e.length > 1 ? (h.error(
1460
+ "[Haori]",
1461
+ "each or if expressions must have a single content.",
1462
+ e
1463
+ ), [e[0]]) : e;
1464
+ }
1465
+ };
1466
+ q.FORCE_EVALUATION_ATTRIBUTES = [
1467
+ "data-if",
1468
+ "hor-if",
1469
+ "data-each",
1470
+ "hor-each"
1471
+ ];
1472
+ let I = q;
1473
+ class y {
1474
+ /**
1475
+ * カスタムイベントを発火します。
1476
+ *
1477
+ * @param target イベントを発火する対象要素
1478
+ * @param eventName イベント名(haori:プレフィックスは自動追加)
1479
+ * @param detail イベントの詳細データ
1480
+ * @param options イベントオプション
1481
+ */
1482
+ static dispatch(t, e, s, r) {
1483
+ const i = new CustomEvent(`haori:${e}`, {
1484
+ bubbles: r?.bubbles ?? !0,
1485
+ cancelable: r?.cancelable ?? !1,
1486
+ composed: r?.composed ?? !0,
1487
+ detail: s
1488
+ });
1489
+ return t.dispatchEvent(i);
1490
+ }
1491
+ /**
1492
+ * readyイベントを発火します。
1493
+ *
1494
+ * @param version ライブラリバージョン
1495
+ */
1496
+ static ready(t) {
1497
+ y.dispatch(document, "ready", { version: t });
1498
+ }
1499
+ /**
1500
+ * renderイベントを発火します。
1501
+ *
1502
+ * @param target 評価対象要素
1503
+ */
1504
+ static render(t) {
1505
+ y.dispatch(t, "render", { target: t });
1506
+ }
1507
+ /**
1508
+ * importstartイベントを発火します。
1509
+ *
1510
+ * @param target data-import要素
1511
+ * @param url インポート対象URL
1512
+ */
1513
+ static importStart(t, e) {
1514
+ y.dispatch(t, "importstart", {
1515
+ url: e,
1516
+ startedAt: performance.now()
1517
+ });
1518
+ }
1519
+ /**
1520
+ * importendイベントを発火します。
1521
+ *
1522
+ * @param target data-import要素
1523
+ * @param url インポート対象URL
1524
+ * @param bytes 取得バイト数
1525
+ * @param startedAt 開始時刻
1526
+ */
1527
+ static importEnd(t, e, s, r) {
1528
+ y.dispatch(t, "importend", {
1529
+ url: e,
1530
+ bytes: s,
1531
+ durationMs: performance.now() - r
1532
+ });
1533
+ }
1534
+ /**
1535
+ * importerrorイベントを発火します。
1536
+ *
1537
+ * @param target data-import要素
1538
+ * @param url インポート対象URL
1539
+ * @param error エラー内容
1540
+ */
1541
+ static importError(t, e, s) {
1542
+ y.dispatch(t, "importerror", { url: e, error: s });
1543
+ }
1544
+ /**
1545
+ * bindchangeイベントを発火します。
1546
+ *
1547
+ * @param target バインド対象要素
1548
+ * @param previous 変更前のデータ
1549
+ * @param next 変更後のデータ
1550
+ * @param reason 変更理由
1551
+ */
1552
+ static bindChange(t, e, s, r = "other") {
1553
+ const i = [], n = new Set(Object.keys(e || {})), a = new Set(Object.keys(s)), u = /* @__PURE__ */ new Set([...n, ...a]);
1554
+ for (const m of u) {
1555
+ const l = e?.[m], b = s[m];
1556
+ l !== b && i.push(m);
1557
+ }
1558
+ y.dispatch(t, "bindchange", {
1559
+ previous: e || {},
1560
+ next: s,
1561
+ changedKeys: i,
1562
+ reason: r
1563
+ });
1564
+ }
1565
+ /**
1566
+ * eachupdateイベントを発火します。
1567
+ *
1568
+ * @param target data-each要素
1569
+ * @param added 追加された行のキー
1570
+ * @param removed 削除された行のキー
1571
+ * @param order 現在の順序
1572
+ */
1573
+ static eachUpdate(t, e, s, r) {
1574
+ y.dispatch(t, "eachupdate", {
1575
+ added: e,
1576
+ removed: s,
1577
+ order: r,
1578
+ total: r.length
1579
+ });
1580
+ }
1581
+ /**
1582
+ * rowaddイベントを発火します。
1583
+ *
1584
+ * @param target 行要素
1585
+ * @param key 行キー
1586
+ * @param index インデックス
1587
+ * @param item 行データ
1588
+ */
1589
+ static rowAdd(t, e, s, r) {
1590
+ y.dispatch(t, "rowadd", { key: e, index: s, item: r });
1591
+ }
1592
+ /**
1593
+ * rowremoveイベントを発火します。
1594
+ *
1595
+ * @param target 行要素
1596
+ * @param key 行キー
1597
+ * @param index インデックス
1598
+ */
1599
+ static rowRemove(t, e, s) {
1600
+ y.dispatch(t, "rowremove", { key: e, index: s });
1601
+ }
1602
+ /**
1603
+ * rowmoveイベントを発火します。
1604
+ *
1605
+ * @param target 行要素
1606
+ * @param key 行キー
1607
+ * @param from 移動前インデックス
1608
+ * @param to 移動後インデックス
1609
+ */
1610
+ static rowMove(t, e, s, r) {
1611
+ y.dispatch(t, "rowmove", { key: e, from: s, to: r });
1612
+ }
1613
+ /**
1614
+ * showイベントを発火します。
1615
+ *
1616
+ * @param target data-if要素
1617
+ */
1618
+ static show(t) {
1619
+ y.dispatch(t, "show", { visible: !0 });
1620
+ }
1621
+ /**
1622
+ * hideイベントを発火します。
1623
+ *
1624
+ * @param target data-if要素
1625
+ */
1626
+ static hide(t) {
1627
+ y.dispatch(t, "hide", { visible: !1 });
1628
+ }
1629
+ /**
1630
+ * fetchstartイベントを発火します。
1631
+ *
1632
+ * @param target 起点要素
1633
+ * @param url フェッチURL
1634
+ * @param options フェッチオプション
1635
+ * @param payload 送信データ
1636
+ */
1637
+ static fetchStart(t, e, s, r) {
1638
+ y.dispatch(t, "fetchstart", {
1639
+ url: e,
1640
+ options: s || {},
1641
+ payload: r,
1642
+ startedAt: performance.now()
1643
+ });
1644
+ }
1645
+ /**
1646
+ * fetchendイベントを発火します。
1647
+ *
1648
+ * @param target 起点要素
1649
+ * @param url フェッチURL
1650
+ * @param status HTTPステータス
1651
+ * @param startedAt 開始時刻
1652
+ */
1653
+ static fetchEnd(t, e, s, r) {
1654
+ y.dispatch(t, "fetchend", {
1655
+ url: e,
1656
+ status: s,
1657
+ durationMs: performance.now() - r
1658
+ });
1659
+ }
1660
+ /**
1661
+ * fetcherrorイベントを発火します。
1662
+ *
1663
+ * @param target 起点要素
1664
+ * @param url フェッチURL
1665
+ * @param error エラー内容
1666
+ * @param status HTTPステータス(存在する場合)
1667
+ * @param startedAt 開始時刻(存在する場合)
1668
+ */
1669
+ static fetchError(t, e, s, r, i) {
1670
+ y.dispatch(t, "fetcherror", {
1671
+ url: e,
1672
+ status: r,
1673
+ error: s,
1674
+ durationMs: i ? performance.now() - i : void 0
1675
+ });
1676
+ }
1677
+ }
1678
+ class f {
1679
+ /**
1680
+ * イベント属性名を正しく生成します。
1681
+ * 例: ("click", "fetch") => "data-click-fetch"
1682
+ * (null, "fetch") => "data-fetch"
1683
+ * ("change", "bind-arg") => "data-change-bind-arg"
1684
+ * 非イベント変種が "data-fetch-xxx" として存在するものについては、event が null の場合にそちらを返します。
1685
+ */
1686
+ static attrName(t, e, s = !1) {
1687
+ return t ? `${c.prefix}${t}-${e}` : s ? `${c.prefix}fetch-${e}` : `${c.prefix}${e}`;
1688
+ }
1689
+ /**
1690
+ * オプションをフラグメントの属性から構築します。
1691
+ *
1692
+ * @param fragment フラグメント
1693
+ * @param event イベント名
1694
+ * @return 構築されたオプション
1695
+ */
1696
+ static buildOptions(t, e) {
1697
+ const s = {
1698
+ targetFragment: t
1699
+ };
1700
+ if (e) {
1701
+ if (t.hasAttribute(f.attrName(e, "validate")) && (s.valid = !0), t.hasAttribute(f.attrName(e, "confirm")) && (s.confirmMessage = t.getAttribute(
1702
+ f.attrName(e, "confirm")
1703
+ )), t.hasAttribute(f.attrName(e, "data")) && (s.data = N.parseDataBind(
1704
+ t.getRawAttribute(f.attrName(e, "data"))
1705
+ )), t.hasAttribute(f.attrName(e, "form"))) {
1706
+ const o = t.getRawAttribute(
1707
+ f.attrName(e, "form")
1708
+ );
1709
+ if (o) {
1710
+ const d = document.body.querySelector(o);
1711
+ d !== null ? s.formFragment = E.getFormFragment(
1712
+ A.get(d)
1713
+ ) : h.error(
1714
+ "Haori",
1715
+ `Form element not found: ${o} (${f.attrName(e, "form")})`
1716
+ );
1717
+ } else
1718
+ s.formFragment = E.getFormFragment(t);
1719
+ } else e === "change" && (s.formFragment = E.getFormFragment(t));
1720
+ if (t.hasAttribute(`${c.prefix}${e}-before-run`)) {
1721
+ const o = t.getRawAttribute(
1722
+ `${c.prefix}${e}-before-run`
1723
+ );
1724
+ try {
1725
+ s.beforeCallback = new Function(
1726
+ "fetchUrl",
1727
+ "fetchOptions",
1728
+ `
1729
+ "use strict";
1730
+ ${o}
1731
+ `
1732
+ );
1733
+ } catch (d) {
1734
+ h.error("Haori", `Invalid before script: ${d}`);
1735
+ }
1736
+ }
1737
+ }
1738
+ const r = f.attrName(e, "fetch"), i = t.hasAttribute(r);
1739
+ i && (s.fetchUrl = t.getAttribute(r));
1740
+ const n = {};
1741
+ if (e) {
1742
+ const o = f.attrName(e, "fetch-method");
1743
+ t.hasAttribute(o) && (n.method = t.getAttribute(
1744
+ o
1745
+ ));
1746
+ } else {
1747
+ const o = f.attrName(null, "method", !0);
1748
+ t.hasAttribute(o) && (n.method = t.getAttribute(
1749
+ o
1750
+ ));
1751
+ }
1752
+ if (e) {
1753
+ const o = f.attrName(e, "fetch-headers");
1754
+ if (t.hasAttribute(o)) {
1755
+ const d = t.getRawAttribute(
1756
+ o
1757
+ );
1758
+ try {
1759
+ n.headers = N.parseDataBind(d);
1760
+ } catch (p) {
1761
+ h.error("Haori", `Invalid fetch headers: ${p}`);
1762
+ }
1763
+ }
1764
+ } else {
1765
+ const o = f.attrName(
1766
+ null,
1767
+ "headers",
1768
+ !0
1769
+ );
1770
+ if (t.hasAttribute(o)) {
1771
+ const d = t.getRawAttribute(
1772
+ o
1773
+ );
1774
+ try {
1775
+ n.headers = N.parseDataBind(d);
1776
+ } catch (p) {
1777
+ h.error("Haori", `Invalid fetch headers: ${p}`);
1778
+ }
1779
+ }
1780
+ }
1781
+ if (e) {
1782
+ const o = f.attrName(
1783
+ e,
1784
+ "fetch-content-type"
1785
+ );
1786
+ if (t.hasAttribute(o))
1787
+ n.headers = {
1788
+ ...n.headers,
1789
+ "Content-Type": t.getAttribute(o)
1790
+ };
1791
+ else if (n.method && n.method !== "GET" && n.method !== "HEAD" && n.method !== "OPTIONS") {
1792
+ let d = !1;
1793
+ n.headers && typeof n.headers == "object" && (d = "Content-Type" in n.headers), d || (n.headers = {
1794
+ ...n.headers,
1795
+ "Content-Type": "application/json"
1796
+ });
1797
+ } else n.method && (n.method === "GET" || n.method === "HEAD" || n.method === "OPTIONS") && (n.headers = {
1798
+ ...n.headers,
1799
+ "Content-Type": "application/x-www-form-urlencoded"
1800
+ });
1801
+ } else {
1802
+ const o = f.attrName(
1803
+ null,
1804
+ "content-type",
1805
+ !0
1806
+ );
1807
+ if (t.hasAttribute(o))
1808
+ n.headers = {
1809
+ ...n.headers,
1810
+ "Content-Type": t.getAttribute(o)
1811
+ };
1812
+ else if (n.method && n.method !== "GET" && n.method !== "HEAD" && n.method !== "OPTIONS") {
1813
+ let d = !1;
1814
+ n.headers && typeof n.headers == "object" && (d = "Content-Type" in n.headers), d || (n.headers = {
1815
+ ...n.headers,
1816
+ "Content-Type": "application/json"
1817
+ });
1818
+ } else n.method && (n.method === "GET" || n.method === "HEAD" || n.method === "OPTIONS") && (n.headers = {
1819
+ ...n.headers,
1820
+ "Content-Type": "application/x-www-form-urlencoded"
1821
+ });
1822
+ }
1823
+ Object.keys(n).length > 0 && (s.fetchOptions = n);
1824
+ const a = e ? f.attrName(e, "bind") : f.attrName(null, "bind", !0);
1825
+ if (t.hasAttribute(a)) {
1826
+ const o = t.getRawAttribute(a);
1827
+ if (o) {
1828
+ const d = document.body.querySelectorAll(o);
1829
+ d.length > 0 ? (s.bindFragments = [], d.forEach((p) => {
1830
+ const w = A.get(p);
1831
+ w && s.bindFragments.push(w);
1832
+ })) : h.error(
1833
+ "Haori",
1834
+ `Bind element not found: ${o} (${a})`
1835
+ );
1836
+ }
1837
+ }
1838
+ const u = f.attrName(e, "bind-arg"), m = f.attrName(
1839
+ null,
1840
+ "arg",
1841
+ !0
1842
+ ), l = f.attrName(
1843
+ null,
1844
+ "bind-arg",
1845
+ !0
1846
+ );
1847
+ e ? t.hasAttribute(u) && (s.bindArg = t.getRawAttribute(u)) : t.hasAttribute(m) ? s.bindArg = t.getRawAttribute(
1848
+ m
1849
+ ) : t.hasAttribute(l) && (s.bindArg = t.getRawAttribute(l));
1850
+ const b = e ? f.attrName(e, "bind-params") : f.attrName(null, "bind-params", !0);
1851
+ if (t.hasAttribute(b)) {
1852
+ const o = t.getRawAttribute(b);
1853
+ s.bindParams = o.split("&").map((d) => d.trim());
1854
+ }
1855
+ if (e) {
1856
+ if (t.hasAttribute(f.attrName(e, "adjust"))) {
1857
+ const d = t.getRawAttribute(
1858
+ f.attrName(e, "adjust")
1859
+ );
1860
+ if (d) {
1861
+ const p = document.body.querySelectorAll(d);
1862
+ p.length > 0 ? (s.adjustFragments = [], p.forEach((w) => {
1863
+ const T = A.get(w);
1864
+ T && s.adjustFragments.push(T);
1865
+ })) : h.error(
1866
+ "Haori",
1867
+ `Adjust element not found: ${d} (${f.attrName(e, "adjust")})`
1868
+ );
1869
+ }
1870
+ if (t.hasAttribute(f.attrName(e, "adjust-value"))) {
1871
+ const p = t.getRawAttribute(
1872
+ f.attrName(e, "adjust-value")
1873
+ ), w = Number(p);
1874
+ isNaN(w) || (s.adjustValue = w);
1875
+ }
1876
+ }
1877
+ if (t.hasAttribute(f.attrName(e, "row-add")) && (s.rowAdd = !0), t.hasAttribute(f.attrName(e, "row-remove")) && (s.rowRemove = !0), t.hasAttribute(f.attrName(e, "row-prev")) && (s.rowMovePrev = !0), t.hasAttribute(f.attrName(e, "row-next")) && (s.rowMoveNext = !0), t.hasAttribute(`${c.prefix}${e}-after-run`)) {
1878
+ const d = t.getRawAttribute(
1879
+ `${c.prefix}${e}-after-run`
1880
+ );
1881
+ try {
1882
+ s.afterCallback = new Function(
1883
+ "response",
1884
+ `
1885
+ "use strict";
1886
+ ${d}
1887
+ `
1888
+ );
1889
+ } catch (p) {
1890
+ h.error("Haori", `Invalid after script: ${p}`);
1891
+ }
1892
+ }
1893
+ t.hasAttribute(f.attrName(e, "dialog")) && (s.dialogMessage = t.getAttribute(
1894
+ f.attrName(e, "dialog")
1895
+ )), t.hasAttribute(f.attrName(e, "toast")) && (s.toastMessage = t.getAttribute(
1896
+ f.attrName(e, "toast")
1897
+ )), t.hasAttribute(f.attrName(e, "redirect")) && (s.redirectUrl = t.getAttribute(
1898
+ f.attrName(e, "redirect")
1899
+ )), [
1900
+ "reset",
1901
+ "refetch",
1902
+ "click",
1903
+ "open",
1904
+ "close"
1905
+ ].forEach((d) => {
1906
+ const p = f.attrName(e, d);
1907
+ if (!t.hasAttribute(p))
1908
+ return;
1909
+ const w = t.getRawAttribute(p), T = [];
1910
+ if (w ? (document.body.querySelectorAll(w).forEach((x) => {
1911
+ const S = A.get(x);
1912
+ S && T.push(S);
1913
+ }), T.length === 0 && h.error("Haori", `Element not found: ${w} (${p})`)) : T.push(t), T.length > 0)
1914
+ switch (d) {
1915
+ case "reset":
1916
+ s.resetFragments = T;
1917
+ break;
1918
+ case "refetch":
1919
+ s.refetchFragments = T;
1920
+ break;
1921
+ case "click":
1922
+ s.clickFragments = T;
1923
+ break;
1924
+ case "open":
1925
+ s.openFragments = T;
1926
+ break;
1927
+ case "close":
1928
+ s.closeFragments = T;
1929
+ break;
1930
+ }
1931
+ });
1932
+ }
1933
+ if (!e) {
1934
+ if (t.hasAttribute(f.attrName(null, "data", !0))) {
1935
+ const o = t.getRawAttribute(
1936
+ f.attrName(null, "data", !0)
1937
+ );
1938
+ s.data = N.parseDataBind(o);
1939
+ }
1940
+ if (t.hasAttribute(f.attrName(null, "form", !0))) {
1941
+ const o = t.getRawAttribute(
1942
+ f.attrName(null, "form", !0)
1943
+ );
1944
+ if (o) {
1945
+ const d = document.body.querySelector(o);
1946
+ d !== null ? s.formFragment = E.getFormFragment(
1947
+ A.get(d)
1948
+ ) : h.error(
1949
+ "Haori",
1950
+ `Form element not found: ${o} (${f.attrName(null, "fetch-form", !0)})`
1951
+ );
1952
+ } else
1953
+ s.formFragment = E.getFormFragment(t);
1954
+ }
1955
+ }
1956
+ return i && (!s.bindFragments || s.bindFragments.length === 0) && (s.bindFragments = [t]), s;
1957
+ }
1958
+ /**
1959
+ * ElementFragment の構造的タイプガード。
1960
+ *
1961
+ * @param value チェックする値
1962
+ * @returns ElementFragment である場合は true、それ以外は false
1963
+ */
1964
+ static isElementFragment(t) {
1965
+ if (typeof t != "object" || t === null)
1966
+ return !1;
1967
+ const e = t;
1968
+ return typeof e.getTarget == "function" && typeof e.getChildElementFragments == "function";
1969
+ }
1970
+ /**
1971
+ * コンストラクタ。
1972
+ *
1973
+ * @param arg1 オプションもしくはフラグメント
1974
+ * @param arg2 イベント名
1975
+ */
1976
+ constructor(t, e = null) {
1977
+ f.isElementFragment(t) ? this.options = f.buildOptions(t, e) : this.options = t;
1978
+ }
1979
+ /**
1980
+ * 一連の処理を実行します。オプションが空の場合は即座にresolveされます。
1981
+ *
1982
+ * @returns 実行結果のPromise
1983
+ */
1984
+ run() {
1985
+ return Object.keys(this.options).length === 0 || this.options.formFragment && this.validate(this.options.formFragment) === !1 ? Promise.resolve() : this.confirm().then((t) => {
1986
+ if (!t)
1987
+ return Promise.resolve();
1988
+ let e = this.options.fetchUrl, s = this.options.fetchOptions;
1989
+ if (this.options.beforeCallback) {
1990
+ const n = this.options.beforeCallback(
1991
+ e || null,
1992
+ s || null
1993
+ );
1994
+ if (n != null) {
1995
+ if (n === !1 || typeof n == "object" && n.stop)
1996
+ return Promise.resolve();
1997
+ typeof n == "object" && (e = "fetchUrl" in n ? n.fetchUrl : e, s = "fetchOptions" in n ? n.fetchOptions : s);
1998
+ }
1999
+ }
2000
+ const r = {};
2001
+ if (this.options.formFragment) {
2002
+ const n = E.getValues(this.options.formFragment);
2003
+ Object.assign(r, n);
2004
+ }
2005
+ this.options.data && typeof this.options.data == "object" && Object.assign(r, this.options.data);
2006
+ const i = Object.keys(r).length > 0;
2007
+ if (e) {
2008
+ const n = { ...s || {} }, a = new Headers(
2009
+ n.headers || void 0
2010
+ ), u = (n.method || "GET").toUpperCase();
2011
+ if (u === "GET" || u === "HEAD" || u === "OPTIONS") {
2012
+ if (i) {
2013
+ const m = new URL(e, window.location.href), l = new URLSearchParams(m.search);
2014
+ for (const [b, o] of Object.entries(r))
2015
+ o !== void 0 && (o === null ? l.append(b, "") : Array.isArray(o) ? o.forEach((d) => {
2016
+ l.append(b, String(d));
2017
+ }) : typeof o == "object" || typeof o == "function" ? l.append(b, JSON.stringify(o)) : l.append(b, String(o)));
2018
+ m.search = l.toString(), e = m.toString();
2019
+ }
2020
+ } else if (i) {
2021
+ const m = a.get("Content-Type") || "";
2022
+ if (/multipart\/form-data/i.test(m)) {
2023
+ a.delete("Content-Type");
2024
+ const l = new FormData();
2025
+ for (const [b, o] of Object.entries(r))
2026
+ o == null ? l.append(b, "") : o instanceof Blob ? l.append(b, o) : Array.isArray(o) ? o.forEach((d) => l.append(b, String(d))) : typeof o == "object" ? l.append(b, JSON.stringify(o)) : l.append(b, String(o));
2027
+ n.body = l;
2028
+ } else if (/application\/x-www-form-urlencoded/i.test(m)) {
2029
+ const l = new URLSearchParams();
2030
+ for (const [b, o] of Object.entries(r))
2031
+ o !== void 0 && (o === null ? l.append(b, "") : Array.isArray(o) ? o.forEach((d) => l.append(b, String(d))) : typeof o == "object" ? l.append(b, JSON.stringify(o)) : l.append(b, String(o)));
2032
+ n.body = l;
2033
+ } else
2034
+ a.set("Content-Type", "application/json"), n.body = JSON.stringify(r);
2035
+ }
2036
+ if (n.headers = a, this.options.targetFragment && e) {
2037
+ const m = performance.now();
2038
+ return y.fetchStart(
2039
+ this.options.targetFragment.getTarget(),
2040
+ e,
2041
+ n,
2042
+ i ? r : void 0
2043
+ ), fetch(e, n).then((l) => this.handleFetchResult(
2044
+ l,
2045
+ e || void 0,
2046
+ m
2047
+ )).catch((l) => {
2048
+ throw e && y.fetchError(
2049
+ this.options.targetFragment.getTarget(),
2050
+ e,
2051
+ l
2052
+ ), l;
2053
+ });
2054
+ } else return e ? fetch(e, n).then((m) => this.handleFetchResult(m, e || void 0)) : Promise.resolve();
2055
+ } else {
2056
+ if ((!this.options.bindFragments || this.options.bindFragments.length === 0) && this.options.formFragment && i) {
2057
+ const u = this.options.formFragment, m = u.getTarget();
2058
+ m.setAttribute(
2059
+ `${c.prefix}bind`,
2060
+ JSON.stringify(r)
2061
+ );
2062
+ const l = u.getBindingData();
2063
+ return Object.assign(l, r), N.setBindingData(m, l);
2064
+ }
2065
+ const n = i ? r : {}, a = new Response(JSON.stringify(n), {
2066
+ headers: { "Content-Type": "application/json" }
2067
+ });
2068
+ return this.handleFetchResult(a);
2069
+ }
2070
+ });
2071
+ }
2072
+ /**
2073
+ * フェッチ後の処理を実行します。
2074
+ */
2075
+ handleFetchResult(t, e, s) {
2076
+ if (!t.ok)
2077
+ return this.options.targetFragment && e && y.fetchError(
2078
+ this.options.targetFragment.getTarget(),
2079
+ e,
2080
+ new Error(`${t.status} ${t.statusText}`),
2081
+ t.status,
2082
+ s
2083
+ ), this.handleFetchError(t);
2084
+ if (this.options.targetFragment && e && s && y.fetchEnd(
2085
+ this.options.targetFragment.getTarget(),
2086
+ e,
2087
+ t.status,
2088
+ s
2089
+ ), this.options.afterCallback) {
2090
+ const i = this.options.afterCallback(t);
2091
+ if (i != null) {
2092
+ if (i === !1 || typeof i == "object" && i.stop)
2093
+ return Promise.resolve();
2094
+ typeof i == "object" && "response" in i && (t = "response" in i ? i.response : t);
2095
+ }
2096
+ }
2097
+ const r = [];
2098
+ return r.push(this.bindResult(t)), r.push(this.adjust()), r.push(this.addRow()), r.push(this.removeRow()), r.push(this.movePrevRow()), r.push(this.moveNextRow()), this.options.resetFragments && this.options.resetFragments.length > 0 && this.options.resetFragments.forEach((i) => {
2099
+ r.push(E.reset(i));
2100
+ }), this.options.refetchFragments && this.options.refetchFragments.length > 0 && this.options.refetchFragments.forEach((i) => {
2101
+ r.push(new f(i, null).run());
2102
+ }), this.options.clickFragments && this.options.clickFragments.length > 0 && this.options.clickFragments.forEach((i) => {
2103
+ const n = i.getTarget();
2104
+ typeof n.click == "function" ? n.click() : n.dispatchEvent(
2105
+ new MouseEvent("click", { bubbles: !0, cancelable: !0 })
2106
+ );
2107
+ }), this.options.openFragments && this.options.openFragments.length > 0 && this.options.openFragments.forEach((i) => {
2108
+ const n = i.getTarget();
2109
+ n instanceof HTMLDialogElement ? r.push(M.openDialog(n)) : h.error("Haori", "Element is not a dialog: ", n);
2110
+ }), this.options.closeFragments && this.options.closeFragments.length > 0 && this.options.closeFragments.forEach((i) => {
2111
+ const n = i.getTarget();
2112
+ n instanceof HTMLDialogElement ? r.push(M.closeDialog(n)) : h.error("Haori", "Element is not a dialog: ", n);
2113
+ }), Promise.all(r).then(() => this.options.dialogMessage ? M.dialog(this.options.dialogMessage) : Promise.resolve()).then(() => this.options.toastMessage ? M.toast(this.options.toastMessage, "info") : Promise.resolve()).then(() => (this.options.redirectUrl && (window.location.href = this.options.redirectUrl), Promise.resolve()));
2114
+ }
2115
+ /**
2116
+ * フェッチエラー応答のメッセージを適切な要素へ伝播します。
2117
+ */
2118
+ async handleFetchError(t) {
2119
+ let e = null;
2120
+ this.options.formFragment ? e = this.options.formFragment : this.options.targetFragment && (e = E.getFormFragment(this.options.targetFragment) || this.options.targetFragment);
2121
+ const s = async (i) => {
2122
+ const n = e ? e.getTarget() : document.body;
2123
+ await M.addErrorMessage(n, i);
2124
+ };
2125
+ if ((t.headers.get("Content-Type") || "").includes("application/json"))
2126
+ try {
2127
+ const i = await t.json(), n = [];
2128
+ if (i && typeof i == "object") {
2129
+ if (typeof i.message == "string" && n.push({ message: i.message }), Array.isArray(i.messages))
2130
+ for (const a of i.messages)
2131
+ typeof a == "string" && n.push({ message: a });
2132
+ if (i.errors && typeof i.errors == "object")
2133
+ for (const [a, u] of Object.entries(i.errors))
2134
+ Array.isArray(u) ? n.push({ key: a, message: u.join(`
2135
+ `) }) : typeof u == "string" ? n.push({ key: a, message: u }) : u != null && n.push({ key: a, message: String(u) });
2136
+ if (n.length === 0)
2137
+ for (const [a, u] of Object.entries(i))
2138
+ a === "message" || a === "messages" || a === "errors" || (Array.isArray(u) ? n.push({ key: a, message: u.join(`
2139
+ `) }) : typeof u == "string" && n.push({ key: a, message: u }));
2140
+ }
2141
+ if (n.length === 0) {
2142
+ await s(`${t.status} ${t.statusText}`);
2143
+ return;
2144
+ }
2145
+ for (const a of n)
2146
+ a.key && e ? await E.addErrorMessage(e, a.key, a.message) : await s(a.message);
2147
+ return;
2148
+ } catch {
2149
+ }
2150
+ try {
2151
+ const i = await t.text();
2152
+ i && i.trim().length > 0 ? await s(i.trim()) : await s(`${t.status} ${t.statusText}`);
2153
+ } catch {
2154
+ await s(`${t.status} ${t.statusText}`);
2155
+ }
2156
+ }
2157
+ /**
2158
+ * 対象のフラグメント以下の入力要素に対してバリデーションを実行します。
2159
+ * バリデーションエラーがある場合は、最初のエラー要素にフォーカスを移動します。
2160
+ *
2161
+ * @param fragment 対象のフラグメント
2162
+ * @returns バリデーション結果(true: 成功, false: 失敗)
2163
+ */
2164
+ validate(t) {
2165
+ if (this.options.valid !== !0)
2166
+ return !0;
2167
+ const e = t.getTarget();
2168
+ let s = this.validateOne(t);
2169
+ return s || e.focus(), t.getChildElementFragments().reverse().forEach((r) => {
2170
+ s &&= this.validate(r);
2171
+ }), s;
2172
+ }
2173
+ /**
2174
+ * 対象のフラグメントに対してバリデーションを実行します。
2175
+ *
2176
+ * @param fragment 対象のフラグメント
2177
+ * @returns バリデーション結果(true: 成功, false: 失敗)
2178
+ */
2179
+ validateOne(t) {
2180
+ const e = t.getTarget();
2181
+ return e instanceof HTMLInputElement || e instanceof HTMLSelectElement || e instanceof HTMLTextAreaElement ? e.reportValidity() : !0;
2182
+ }
2183
+ /**
2184
+ * 確認メッセージを表示し、ユーザーの確認を求めます。
2185
+ * メッセージが設定されていない場合は、即座に成功とみなします。
2186
+ *
2187
+ * @returns ユーザーの確認結果を含むPromise(true: 確認, false: キャンセル)
2188
+ */
2189
+ confirm() {
2190
+ const t = this.options.confirmMessage;
2191
+ return t == null ? Promise.resolve(!0) : M.confirm(t);
2192
+ }
2193
+ /**
2194
+ * 結果データを対象のフラグメントにバインドします。
2195
+ *
2196
+ * @param response フェッチのレスポンスオブジェクト
2197
+ */
2198
+ bindResult(t) {
2199
+ return !this.options.bindFragments || this.options.bindFragments.length === 0 ? Promise.resolve() : (t.headers.get("Content-Type")?.includes("application/json") ? t.json() : t.text()).then((s) => {
2200
+ if (this.options.bindParams) {
2201
+ const i = {};
2202
+ this.options.bindParams.forEach((n) => {
2203
+ s && typeof s == "object" && n in s && (i[n] = s[n]);
2204
+ }), s = i;
2205
+ }
2206
+ const r = [];
2207
+ if (this.options.bindArg)
2208
+ this.options.bindFragments.forEach((i) => {
2209
+ const n = i.getBindingData();
2210
+ n[this.options.bindArg] = s, r.push(N.setBindingData(i.getTarget(), n));
2211
+ });
2212
+ else {
2213
+ if (typeof s == "string")
2214
+ return h.error("Haori", "string data cannot be bound without a bindArg."), Promise.reject(
2215
+ new Error("string data cannot be bound without a bindArg.")
2216
+ );
2217
+ this.options.bindFragments.forEach((i) => {
2218
+ r.push(
2219
+ N.setBindingData(
2220
+ i.getTarget(),
2221
+ s
2222
+ )
2223
+ );
2224
+ });
2225
+ }
2226
+ return Promise.all(r).then(() => {
2227
+ });
2228
+ });
2229
+ }
2230
+ /**
2231
+ * 値の増減を行います。
2232
+ */
2233
+ adjust() {
2234
+ if (!this.options.adjustFragments || this.options.adjustFragments.length === 0)
2235
+ return Promise.resolve();
2236
+ const t = this.options.adjustValue ?? 0, e = [];
2237
+ for (const s of this.options.adjustFragments) {
2238
+ let r = s.getValue();
2239
+ (r == null || r === "") && (r = "0");
2240
+ let i = Number(r);
2241
+ isNaN(i) && (i = 0), i += t, e.push(s.setValue(String(i)));
2242
+ }
2243
+ return Promise.all(e).then(() => {
2244
+ });
2245
+ }
2246
+ /**
2247
+ * 行フラグメントを取得します。
2248
+ *
2249
+ * @returns 行フラグメントまたはnull
2250
+ */
2251
+ getRowFragment() {
2252
+ if (!this.options.targetFragment)
2253
+ return h.error("Haori", "Target fragment is not specified for row operation."), null;
2254
+ const t = this.options.targetFragment.closestByAttribute(
2255
+ `${c.prefix}row`
2256
+ );
2257
+ return t || (h.error("Haori", "Row fragment not found."), null);
2258
+ }
2259
+ /**
2260
+ * 行を追加します。
2261
+ *
2262
+ * @returns 処理結果のPromise
2263
+ */
2264
+ addRow() {
2265
+ if (this.options.rowAdd !== !0)
2266
+ return Promise.resolve();
2267
+ const t = this.getRowFragment();
2268
+ if (!t)
2269
+ return Promise.reject(new Error("Row fragment not found."));
2270
+ const e = [], s = t.clone();
2271
+ return e.push(
2272
+ t.getParent().insertAfter(s, t)
2273
+ ), e.push(N.evaluateAll(s)), e.push(E.reset(s)), Promise.all(e).then(() => {
2274
+ });
2275
+ }
2276
+ /**
2277
+ * 行を削除します。
2278
+ *
2279
+ * @returns 処理結果のPromise
2280
+ */
2281
+ removeRow() {
2282
+ if (this.options.rowRemove !== !0)
2283
+ return Promise.resolve();
2284
+ const t = this.getRowFragment();
2285
+ if (!t)
2286
+ return Promise.reject(new Error("Row fragment not found."));
2287
+ const e = t.getParent();
2288
+ return e && e.getChildElementFragments().filter((r) => !r.hasAttribute(`${c.prefix}each-before`) && !r.hasAttribute(`${c.prefix}each-after`)).length <= 1 ? Promise.resolve() : t.remove();
2289
+ }
2290
+ /**
2291
+ * 前の行へ移動します。
2292
+ *
2293
+ * @returns 処理結果のPromise
2294
+ */
2295
+ movePrevRow() {
2296
+ if (this.options.rowMovePrev !== !0)
2297
+ return Promise.resolve();
2298
+ const t = this.getRowFragment();
2299
+ if (!t)
2300
+ return Promise.reject(new Error("Row fragment not found."));
2301
+ const e = t.getPrevious();
2302
+ if (!e)
2303
+ return Promise.resolve();
2304
+ const s = t.getParent();
2305
+ return s ? s.insertBefore(t, e) : Promise.resolve();
2306
+ }
2307
+ /**
2308
+ * 次の行へ移動します。
2309
+ *
2310
+ * @returns 処理結果のPromise
2311
+ */
2312
+ moveNextRow() {
2313
+ if (this.options.rowMoveNext !== !0)
2314
+ return Promise.resolve();
2315
+ const t = this.getRowFragment();
2316
+ if (!t)
2317
+ return Promise.reject(new Error("Row fragment not found."));
2318
+ const e = t.getNext();
2319
+ if (!e)
2320
+ return Promise.resolve();
2321
+ const s = t.getParent();
2322
+ return s ? s.insertAfter(t, e) : Promise.resolve();
2323
+ }
2324
+ }
2325
+ class J {
2326
+ /**
2327
+ * URLのクエリパラメータを取得します。
2328
+ *
2329
+ * @returns URLのクエリパラメータのキーと値のマップ
2330
+ */
2331
+ static readParams() {
2332
+ const t = {}, e = window.location.search;
2333
+ return new URLSearchParams(e).forEach((r, i) => {
2334
+ t[i] = r;
2335
+ }), t;
2336
+ }
2337
+ }
2338
+ class W {
2339
+ /**
2340
+ * 指定URLから HTML を取得し、body 内の HTML 文字列を返します。
2341
+ *
2342
+ * 振る舞い:
2343
+ * - HTTP ステータスが成功以外の場合は例外を投げます。
2344
+ * - HTML のパースに失敗した場合はログを出力し、テキスト全体を返します(フォールバック)。
2345
+ * - body タグが存在しない場合もテキスト全体を返します(フォールバック)。
2346
+ *
2347
+ * @param url 取得先の URL
2348
+ * @param init fetch のオプション(任意)
2349
+ * @returns body 内の HTML 文字列
2350
+ */
2351
+ static async load(t, e) {
2352
+ let s;
2353
+ try {
2354
+ s = await fetch(t, e);
2355
+ } catch (i) {
2356
+ throw h.error("[Haori]", "Failed to fetch import source:", t, i), new Error(`Failed to fetch: ${t}`);
2357
+ }
2358
+ if (!s.ok) {
2359
+ const i = `${s.status} ${s.statusText}`;
2360
+ throw h.error("[Haori]", "Import HTTP error:", t, i), new Error(`Failed to load ${t}: ${i}`);
2361
+ }
2362
+ let r;
2363
+ try {
2364
+ r = await s.text();
2365
+ } catch (i) {
2366
+ throw h.error("[Haori]", "Failed to read response text:", t, i), new Error(`Failed to read response from: ${t}`);
2367
+ }
2368
+ try {
2369
+ const n = new DOMParser().parseFromString(r, "text/html");
2370
+ return n && n.body ? n.body.innerHTML : (h.warn("[Haori]", "No body found in imported document:", t), r);
2371
+ } catch (i) {
2372
+ return h.error("[Haori]", "Failed to parse imported HTML:", t, i), r;
2373
+ }
2374
+ }
2375
+ }
2376
+ const g = class g {
2377
+ /**
2378
+ * 遅延属性かどうか(完全名で判定)を判定します。
2379
+ *
2380
+ * @param name 属性名
2381
+ * @returns 遅延属性かどうか
2382
+ */
2383
+ static isDeferredAttributeName(t) {
2384
+ return g.DEFERRED_ATTRIBUTE_SUFFIXES.some(
2385
+ (e) => t === `${c.prefix}${e}`
2386
+ );
2387
+ }
2388
+ /**
2389
+ * 指定された要素と、その子要素をスキャンし、Fragmentを生成します。
2390
+ *
2391
+ * @param element スキャン対象の要素
2392
+ * @returns Promise (スキャンが完了したときに解決される)
2393
+ */
2394
+ static scan(t) {
2395
+ const e = A.get(t);
2396
+ if (!e)
2397
+ return Promise.resolve();
2398
+ t.parentNode && (A.get(t.parentNode)?.isMounted() || document.body.contains(t) ? e.setMounted(!0) : e.setMounted(!1));
2399
+ const s = [], r = /* @__PURE__ */ new Set();
2400
+ for (const i of g.PRIORITY_ATTRIBUTE_SUFFIXES) {
2401
+ const n = c.prefix + i;
2402
+ e.hasAttribute(n) && (s.push(
2403
+ g.setAttribute(
2404
+ e.getTarget(),
2405
+ n,
2406
+ e.getRawAttribute(n)
2407
+ )
2408
+ ), r.add(n));
2409
+ }
2410
+ for (const i of e.getAttributeNames()) {
2411
+ if (r.has(i) || g.isDeferredAttributeName(i))
2412
+ continue;
2413
+ const n = e.getRawAttribute(i);
2414
+ n !== null && s.push(g.setAttribute(e.getTarget(), i, n));
2415
+ }
2416
+ for (const i of g.DEFERRED_ATTRIBUTE_SUFFIXES) {
2417
+ const n = c.prefix + i;
2418
+ e.hasAttribute(n) && (s.push(
2419
+ g.setAttribute(
2420
+ e.getTarget(),
2421
+ n,
2422
+ e.getRawAttribute(n)
2423
+ )
2424
+ ), r.add(n));
2425
+ }
2426
+ return e.getChildren().forEach((i) => {
2427
+ i instanceof F ? s.push(g.scan(i.getTarget())) : i instanceof j && s.push(g.evaluateText(i));
2428
+ }), Promise.all(s).then(() => {
2429
+ });
2430
+ }
2431
+ /**
2432
+ * エレメントに属性を設定します。
2433
+ * 属性固有の処理も行います。
2434
+ *
2435
+ * @param element エレメント
2436
+ * @param name 属性名
2437
+ * @param value 属性値
2438
+ * @returns Promise (DOM操作が完了したときに解決される)
2439
+ */
2440
+ static setAttribute(t, e, s) {
2441
+ const r = A.get(t), i = [];
2442
+ switch (e) {
2443
+ case `${c.prefix}bind`: {
2444
+ s === null ? (r.clearBindingDataCache(), r.setBindingData({})) : r.setBindingData(g.parseDataBind(s));
2445
+ break;
2446
+ }
2447
+ case `${c.prefix}if`:
2448
+ i.push(g.evaluateIf(r));
2449
+ break;
2450
+ case `${c.prefix}each`:
2451
+ i.push(g.evaluateEach(r));
2452
+ break;
2453
+ case `${c.prefix}fetch`:
2454
+ i.push(new f(r, null).run());
2455
+ break;
2456
+ case `${c.prefix}import`: {
2457
+ if (typeof s == "string") {
2458
+ const n = r.getTarget(), a = performance.now();
2459
+ y.importStart(n, s), i.push(
2460
+ W.load(s).then((u) => {
2461
+ const m = new TextEncoder().encode(u).length;
2462
+ return v.enqueue(() => {
2463
+ n.innerHTML = u;
2464
+ }).then(() => {
2465
+ y.importEnd(n, s, m, a);
2466
+ });
2467
+ }).catch((u) => {
2468
+ y.importError(n, s, u), h.error("[Haori]", "Failed to import HTML:", s, u);
2469
+ })
2470
+ );
2471
+ }
2472
+ break;
2473
+ }
2474
+ case `${c.prefix}url-param`: {
2475
+ const n = r.getAttribute(`${c.prefix}url-arg`), a = J.readParams();
2476
+ if (n === null)
2477
+ g.setBindingData(t, a);
2478
+ else {
2479
+ const u = r.getRawBindingData() || {};
2480
+ u[String(n)] = a, g.setBindingData(t, u);
2481
+ }
2482
+ break;
2483
+ }
2484
+ }
2485
+ return s === null ? i.push(r.removeAttribute(e)) : i.push(r.setAttribute(e, s)), Promise.all(i).then(() => {
2486
+ });
2487
+ }
2488
+ /**
2489
+ * エレメントに属性を設定し、評価を行います。
2490
+ *
2491
+ * @param element エレメント
2492
+ * @param name 属性名
2493
+ * @param value 属性値
2494
+ * @returns Promise (DOM操作が完了したときに解決される)
2495
+ */
2496
+ static setBindingData(t, e) {
2497
+ const s = A.get(t), r = s.getRawBindingData();
2498
+ s.setBindingData(e);
2499
+ const i = [];
2500
+ return i.push(
2501
+ s.setAttribute(`${c.prefix}bind`, JSON.stringify(e))
2502
+ ), i.push(g.evaluateAll(s)), y.bindChange(t, r, e, "manual"), Promise.all(i).then(() => {
2503
+ });
2504
+ }
2505
+ /**
2506
+ * data-bind 属性の値をパースします。
2507
+ *
2508
+ * @param data data-bind 属性の値
2509
+ * @returns パースされたデータオブジェクト
2510
+ */
2511
+ static parseDataBind(t) {
2512
+ if (t.startsWith("{") || t.startsWith("["))
2513
+ try {
2514
+ return JSON.parse(t);
2515
+ } catch (e) {
2516
+ return h.error("[Haori]", "Invalid JSON in data-bind:", e), {};
2517
+ }
2518
+ else {
2519
+ const e = new URLSearchParams(t), s = {};
2520
+ for (const [r, i] of e.entries())
2521
+ s[r] !== void 0 ? Array.isArray(s[r]) ? s[r].push(i) : s[r] = [s[r], i] : s[r] = i;
2522
+ return s;
2523
+ }
2524
+ }
2525
+ /**
2526
+ * ノードを親要素に追加し評価を行います。
2527
+ *
2528
+ * @param parentElement 親エレメント
2529
+ * @param node 追加するノード
2530
+ */
2531
+ static addNode(t, e) {
2532
+ const s = A.get(t);
2533
+ if (s.isSkipMutationNodes())
2534
+ return;
2535
+ const r = A.get(e.nextSibling), i = A.get(e);
2536
+ i && (s.insertBefore(i, r), i instanceof F ? g.scan(i.getTarget()) : i instanceof j && g.evaluateText(i));
2537
+ }
2538
+ /**
2539
+ * ノードを親要素から削除します。
2540
+ *
2541
+ * @param node 削除するノード
2542
+ */
2543
+ static removeNode(t) {
2544
+ const e = A.get(t);
2545
+ if (e) {
2546
+ const s = e.getParent();
2547
+ if (s && s.isSkipMutationNodes())
2548
+ return;
2549
+ e.remove();
2550
+ }
2551
+ }
2552
+ /**
2553
+ * ノードのテキストを変更します。
2554
+ *
2555
+ * @param node 変更するノード
2556
+ * @param text 新しいテキスト
2557
+ */
2558
+ static changeText(t, e) {
2559
+ const s = A.get(t);
2560
+ s && s.setContent(e);
2561
+ }
2562
+ /**
2563
+ * エレメントの値を変更します。
2564
+ * フォームの双方向バインディングを考慮し、フォームのバインドデータも更新します。
2565
+ *
2566
+ * @param element 変更するエレメント
2567
+ * @param value 新しい値
2568
+ * @returns Promise (DOM操作が完了したときに解決される)
2569
+ */
2570
+ static changeValue(t, e) {
2571
+ const s = A.get(t);
2572
+ if (s.getValue() === e)
2573
+ return Promise.resolve();
2574
+ const r = [];
2575
+ r.push(s.setValue(e));
2576
+ const i = g.getFormFragment(s);
2577
+ if (i) {
2578
+ const n = E.getValues(i), a = i.getAttribute(`${c.prefix}form-arg`);
2579
+ let u;
2580
+ a ? (u = i.getRawBindingData(), u || (u = {}), u[String(a)] = n) : u = n, r.push(g.setBindingData(i.getTarget(), u));
2581
+ }
2582
+ return Promise.all(r).then(() => {
2583
+ });
2584
+ }
2585
+ /**
2586
+ * フォームフラグメントを取得します。
2587
+ *
2588
+ * @param fragment フラグメント
2589
+ * @returns フォームフラグメントまたはnull
2590
+ */
2591
+ static getFormFragment(t) {
2592
+ if (t.getTarget() instanceof HTMLFormElement)
2593
+ return t;
2594
+ const e = t.getParent();
2595
+ return e ? g.getFormFragment(e) : null;
2596
+ }
2597
+ /**
2598
+ * フラグメントとその子要素を評価します。
2599
+ *
2600
+ * @param fragment 対象フラグメント
2601
+ * @return Promise (DOM操作が完了したときに解決される)
2602
+ */
2603
+ static evaluateAll(t) {
2604
+ const e = [];
2605
+ return t.hasAttribute(`${c.prefix}if`) && e.push(g.evaluateIf(t)), t.hasAttribute(`${c.prefix}each`) && e.push(g.evaluateEach(t)), t.getChildren().forEach((s) => {
2606
+ s instanceof F ? e.push(g.evaluateAll(s)) : s instanceof j && e.push(g.evaluateText(s));
2607
+ }), Promise.all(e).then(() => {
2608
+ });
2609
+ }
2610
+ /**
2611
+ * テキストフラグメントを評価します。
2612
+ *
2613
+ * @param fragment 対象フラグメント
2614
+ * @returns Promise (DOM操作が完了したときに解決される)
2615
+ */
2616
+ static evaluateText(t) {
2617
+ return t.evaluate();
2618
+ }
2619
+ /**
2620
+ * if要素を評価します。
2621
+ * 値がfalse、null、undefined、NaNの場合は非表示にし、それ以外の場合は表示します。
2622
+ *
2623
+ * @param fragment 対象フラグメント
2624
+ * @return Promise (DOM操作が完了したときに解決される)
2625
+ */
2626
+ static evaluateIf(t) {
2627
+ const e = [], s = t.getAttribute(`${c.prefix}if`);
2628
+ return s === !1 || s === void 0 || s === null || Number.isNaN(s) ? t.isVisible() && e.push(
2629
+ t.hide().then(() => {
2630
+ y.hide(t.getTarget());
2631
+ })
2632
+ ) : t.isVisible() || (e.push(
2633
+ t.show().then(() => {
2634
+ y.show(t.getTarget());
2635
+ })
2636
+ ), e.push(g.evaluateAll(t))), Promise.all(e).then(() => {
2637
+ });
2638
+ }
2639
+ /**
2640
+ * each要素を評価します。
2641
+ * 非表示または未マウントの場合は処理をスキップします。
2642
+ *
2643
+ * @param fragment 対象フラグメント
2644
+ */
2645
+ static evaluateEach(t) {
2646
+ if (!t.isVisible() || !t.isMounted())
2647
+ return Promise.resolve();
2648
+ let e = t.getTemplate();
2649
+ if (e === null) {
2650
+ const r = [];
2651
+ t.getChildren().forEach((n) => {
2652
+ if (n instanceof F) {
2653
+ if (n.hasAttribute(`${c.prefix}each-before`) || n.hasAttribute(`${c.prefix}each-after`))
2654
+ return;
2655
+ if (e === null) {
2656
+ e = n, t.removeChild(n);
2657
+ const a = n.getTarget();
2658
+ a.parentNode && r.push(
2659
+ v.enqueue(() => {
2660
+ a.parentNode && a.parentNode.removeChild(a), n.setMounted(!1);
2661
+ })
2662
+ );
2663
+ } else
2664
+ h.warn("[Haori]", "Template must be a single child element.");
2665
+ }
2666
+ }), t.setTemplate(e);
2667
+ const i = t.getAttribute(`${c.prefix}each`);
2668
+ return Array.isArray(i) ? Promise.all(r).then(
2669
+ () => this.updateDiff(t, i)
2670
+ ) : (h.error("[Haori]", "Invalid each attribute:", i), Promise.reject(new Error("Invalid each attribute.")));
2671
+ }
2672
+ const s = t.getAttribute(`${c.prefix}each`);
2673
+ return Array.isArray(s) ? this.updateDiff(t, s) : (h.error("[Haori]", "Invalid each attribute:", s), Promise.reject(new Error("Invalid each attribute.")));
2674
+ }
2675
+ /**
2676
+ * 差分を更新します。
2677
+ *
2678
+ * @param parent 親フラグメント
2679
+ * @param newList 新しいリスト
2680
+ */
2681
+ static updateDiff(t, e) {
2682
+ const s = t.getTemplate();
2683
+ if (s === null)
2684
+ return h.error("[Haori]", "Template is not set for each element."), Promise.resolve();
2685
+ let r = t.getAttribute(`${c.prefix}each-index`);
2686
+ r && (r = String(r));
2687
+ const i = t.getAttribute(`${c.prefix}each-key`), n = t.getAttribute(`${c.prefix}each-arg`), a = /* @__PURE__ */ new Map(), u = [];
2688
+ e.forEach((p, w) => {
2689
+ const T = g.createListKey(
2690
+ p,
2691
+ i ? String(i) : null,
2692
+ w
2693
+ );
2694
+ u.push(T), a.set(T, { item: p, itemIndex: w });
2695
+ });
2696
+ const m = [];
2697
+ let l = t.getChildren().filter((p) => p instanceof F).filter(
2698
+ (p) => !p.hasAttribute(`${c.prefix}each-before`) && !p.hasAttribute(`${c.prefix}each-after`)
2699
+ );
2700
+ l = l.filter((p) => u.indexOf(String(p.getListKey())) === -1 ? (m.push(p.remove()), !1) : !0);
2701
+ const b = l.map((p) => p.getListKey()), o = t.getChildren().filter((p) => p instanceof F).filter((p) => p.hasAttribute(`${c.prefix}each-before`)).length;
2702
+ let d = Promise.resolve();
2703
+ return u.forEach((p, w) => {
2704
+ const T = b.indexOf(p), { item: B, itemIndex: x } = a.get(p);
2705
+ let S;
2706
+ T !== -1 ? S = l[T] : S = s.clone(), g.updateRowFragment(
2707
+ S,
2708
+ B,
2709
+ r,
2710
+ x,
2711
+ n ? String(n) : null,
2712
+ p
2713
+ );
2714
+ const G = o + w;
2715
+ d = d.then(
2716
+ () => t.insertBefore(S, t.getChildren()[G] || null).then(() => g.evaluateAll(S))
2717
+ );
2718
+ }), Promise.all(m).then(() => d).then(() => {
2719
+ const p = u.filter(
2720
+ (x) => x !== null
2721
+ ), w = b.filter(
2722
+ (x) => x !== null
2723
+ ), T = p.filter(
2724
+ (x) => !w.includes(x)
2725
+ ), B = w.filter(
2726
+ (x) => !p.includes(x)
2727
+ );
2728
+ y.eachUpdate(
2729
+ t.getTarget(),
2730
+ T,
2731
+ B,
2732
+ p
2733
+ );
2734
+ });
2735
+ }
2736
+ /**
2737
+ * リスト比較用のキーを生成します。
2738
+ *
2739
+ * @param item 対象オブジェクト
2740
+ * @param keyArg リストキーに使用するプロパティ名
2741
+ * @param index 配列のインデックス
2742
+ * @returns リストキー
2743
+ */
2744
+ static createListKey(t, e, s) {
2745
+ let r;
2746
+ if (typeof t == "object" && t !== null)
2747
+ if (e) {
2748
+ const i = t[e];
2749
+ i == null ? r = `__index_${s}` : typeof i == "object" ? r = JSON.stringify(i) : r = String(i);
2750
+ } else
2751
+ r = `__index_${s}`;
2752
+ else
2753
+ r = String(t);
2754
+ return r;
2755
+ }
2756
+ /**
2757
+ * 行フラグメントにデータを設定します。
2758
+ *
2759
+ * @param rowFragment 行フラグメント
2760
+ * @param data 行データ
2761
+ * @param indexKey インデックスキー
2762
+ * @param index インデックス番号
2763
+ * @param arg バインドデータパラメータ名
2764
+ * @param listKey リストキー
2765
+ */
2766
+ static updateRowFragment(t, e, s, r, i, n) {
2767
+ let a = e;
2768
+ if (typeof e == "object" && e !== null)
2769
+ a = { ...e }, s && (a[s] = r), i && (a = {
2770
+ [i]: a
2771
+ });
2772
+ else if (i)
2773
+ a = {
2774
+ [i]: e
2775
+ }, s && (a[s] = r);
2776
+ else {
2777
+ h.error(
2778
+ "[Haori]",
2779
+ `Primitive value requires '${c.prefix}each-arg' attribute: ${e}`
2780
+ );
2781
+ return;
2782
+ }
2783
+ t.setListKey(n), t.setAttribute(`${c.prefix}row`, n), t.setBindingData(a);
2784
+ }
2785
+ };
2786
+ g.PRIORITY_ATTRIBUTE_SUFFIXES = ["bind", "if", "each"], g.DEFERRED_ATTRIBUTE_SUFFIXES = ["fetch", "url-param"];
2787
+ let N = g;
2788
+ class Y {
2789
+ /**
2790
+ * コンストラクタ。
2791
+ *
2792
+ * @param root 監視対象のルート要素(デフォルトは document )
2793
+ */
2794
+ constructor(t = document) {
2795
+ this.onClick = (e) => this.delegate(e, "click"), this.onChange = (e) => this.delegate(e, "change"), this.onLoadCapture = (e) => this.delegate(e, "load"), this.onWindowLoad = () => {
2796
+ const e = document.documentElement, s = A.get(e);
2797
+ s && new f(s, "load").run();
2798
+ }, this.root = t;
2799
+ }
2800
+ /**
2801
+ * イベントリスナーの登録を開始します。
2802
+ * クリック、変更、ロードイベントを監視し、対応するProcedureを実行します。
2803
+ */
2804
+ start() {
2805
+ this.root.addEventListener("click", this.onClick), this.root.addEventListener("change", this.onChange), this.root.addEventListener("load", this.onLoadCapture, !0), window.addEventListener("load", this.onWindowLoad, { once: !0 });
2806
+ }
2807
+ /**
2808
+ * イベントリスナーの登録を停止します。
2809
+ */
2810
+ stop() {
2811
+ this.root.removeEventListener("click", this.onClick), this.root.removeEventListener("change", this.onChange), this.root.removeEventListener("load", this.onLoadCapture, !0), window.removeEventListener("load", this.onWindowLoad);
2812
+ }
2813
+ /**
2814
+ * イベントを処理し、対応するProcedureを実行します。
2815
+ *
2816
+ * @param event 発生したイベント
2817
+ * @param type イベントタイプ('click', 'change', 'load'など)
2818
+ */
2819
+ delegate(t, e) {
2820
+ const s = this.getElementFromTarget(t.target);
2821
+ if (!s)
2822
+ return;
2823
+ const r = A.get(s);
2824
+ r && (e === "change" && r instanceof F && r.syncValue(), new f(r, e).run().catch((i) => {
2825
+ h.error("[Haori]", "Procedure execution error:", i);
2826
+ }));
2827
+ }
2828
+ /**
2829
+ * イベントのターゲットから HTMLElement を取得します。
2830
+ *
2831
+ * @param target イベントのターゲット
2832
+ * @returns HTMLElement または null
2833
+ */
2834
+ getElementFromTarget(t) {
2835
+ return t ? t instanceof HTMLElement ? t : t instanceof Node ? t.parentElement : null : null;
2836
+ }
2837
+ }
2838
+ class O {
2839
+ /**
2840
+ * 初期化メソッド。
2841
+ * ドキュメントのheadとbodyを監視対象として設定します。
2842
+ */
2843
+ static async init() {
2844
+ const t = await Promise.allSettled([
2845
+ N.scan(document.head),
2846
+ N.scan(document.body)
2847
+ ]), [e, s] = t;
2848
+ e.status !== "fulfilled" && h.error("[Haori]", "Failed to build head fragment:", e.reason), s.status !== "fulfilled" && h.error("[Haori]", "Failed to build body fragment:", s.reason), O.observe(document.head), O.observe(document.body), new Y().start();
2849
+ }
2850
+ /**
2851
+ * 指定された要素を監視します。
2852
+ *
2853
+ * @param root 監視対象の要素
2854
+ */
2855
+ static observe(t) {
2856
+ new MutationObserver(async (s) => {
2857
+ for (const r of s)
2858
+ try {
2859
+ switch (r.type) {
2860
+ case "attributes": {
2861
+ h.info(
2862
+ "[Haori]",
2863
+ "Attribute changed:",
2864
+ r.target,
2865
+ r.attributeName
2866
+ );
2867
+ const i = r.target;
2868
+ N.setAttribute(
2869
+ i,
2870
+ r.attributeName,
2871
+ i.getAttribute(r.attributeName)
2872
+ );
2873
+ break;
2874
+ }
2875
+ case "childList": {
2876
+ h.info(
2877
+ "[Haori]",
2878
+ "Child list changed:",
2879
+ Array.from(r.removedNodes).map((i) => i.nodeName),
2880
+ Array.from(r.addedNodes).map((i) => i.nodeName)
2881
+ ), Array.from(r.removedNodes).forEach((i) => {
2882
+ N.removeNode(i);
2883
+ }), Array.from(r.addedNodes).forEach((i) => {
2884
+ i.parentElement instanceof HTMLElement && N.addNode(i.parentElement, i);
2885
+ });
2886
+ break;
2887
+ }
2888
+ case "characterData": {
2889
+ h.info(
2890
+ "[Haori]",
2891
+ "Character data changed:",
2892
+ r.target,
2893
+ r.target.textContent
2894
+ ), r.target instanceof Text || r.target instanceof Comment ? N.changeText(r.target, r.target.textContent) : h.warn(
2895
+ "[Haori]",
2896
+ "Unsupported character data type:",
2897
+ r.target
2898
+ );
2899
+ break;
2900
+ }
2901
+ default:
2902
+ h.warn("[Haori]", "Unknown mutation type:", r.type);
2903
+ continue;
2904
+ }
2905
+ } catch (i) {
2906
+ h.error("[Haori]", "Error processing mutation:", i);
2907
+ }
2908
+ }).observe(t, {
2909
+ childList: !0,
2910
+ subtree: !0,
2911
+ attributes: !0,
2912
+ characterData: !0
2913
+ }), h.info("[Haori]", "Observer initialized for", t);
2914
+ }
2915
+ }
2916
+ document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", O.init) : O.init();
2917
+ const Q = "0.1.0";
2918
+ export {
2919
+ N as Core,
2920
+ c as Env,
2921
+ E as Form,
2922
+ A as Fragment,
2923
+ M as Haori,
2924
+ h as Log,
2925
+ v as Queue,
2926
+ M as default,
2927
+ Q as version
2928
+ };
2929
+ //# sourceMappingURL=haori.es.js.map