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.
- package/LICENSE +21 -0
- package/README.ja.md +157 -0
- package/README.md +158 -0
- package/dist/haori.cjs.js +13 -0
- package/dist/haori.cjs.js.map +1 -0
- package/dist/haori.es.js +2929 -0
- package/dist/haori.es.js.map +1 -0
- package/dist/haori.iife.js +13 -0
- package/dist/haori.iife.js.map +1 -0
- package/dist/index.d.ts +824 -0
- package/dist/src/core.d.ts +144 -0
- package/dist/src/core.d.ts.map +1 -0
- package/dist/src/core.js +605 -0
- package/dist/src/core.js.map +1 -0
- package/dist/src/dev.d.ts +35 -0
- package/dist/src/dev.d.ts.map +1 -0
- package/dist/src/dev.js +44 -0
- package/dist/src/dev.js.map +1 -0
- package/dist/src/env.d.ts +25 -0
- package/dist/src/env.d.ts.map +1 -0
- package/dist/src/env.js +64 -0
- package/dist/src/env.js.map +1 -0
- package/dist/src/event.d.ts +144 -0
- package/dist/src/event.d.ts.map +1 -0
- package/dist/src/event.js +221 -0
- package/dist/src/event.js.map +1 -0
- package/dist/src/event_dispatcher.d.ts +50 -0
- package/dist/src/event_dispatcher.d.ts.map +1 -0
- package/dist/src/event_dispatcher.js +99 -0
- package/dist/src/event_dispatcher.js.map +1 -0
- package/dist/src/expression.d.ts +39 -0
- package/dist/src/expression.d.ts.map +1 -0
- package/dist/src/expression.js +148 -0
- package/dist/src/expression.js.map +1 -0
- package/dist/src/form.d.ts +113 -0
- package/dist/src/form.d.ts.map +1 -0
- package/dist/src/form.js +361 -0
- package/dist/src/form.js.map +1 -0
- package/dist/src/fragment.d.ts +427 -0
- package/dist/src/fragment.d.ts.map +1 -0
- package/dist/src/fragment.js +1168 -0
- package/dist/src/fragment.js.map +1 -0
- package/dist/src/haori.d.ts +54 -0
- package/dist/src/haori.d.ts.map +1 -0
- package/dist/src/haori.js +120 -0
- package/dist/src/haori.js.map +1 -0
- package/dist/src/import.d.ts +19 -0
- package/dist/src/import.d.ts.map +1 -0
- package/dist/src/import.js +64 -0
- package/dist/src/import.js.map +1 -0
- package/dist/src/index.d.ts +17 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +21 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/log.d.ts +32 -0
- package/dist/src/log.d.ts.map +1 -0
- package/dist/src/log.js +43 -0
- package/dist/src/log.js.map +1 -0
- package/dist/src/observer.d.ts +17 -0
- package/dist/src/observer.d.ts.map +1 -0
- package/dist/src/observer.js +102 -0
- package/dist/src/observer.js.map +1 -0
- package/dist/src/procedure.d.ts +203 -0
- package/dist/src/procedure.d.ts.map +1 -0
- package/dist/src/procedure.js +1040 -0
- package/dist/src/procedure.js.map +1 -0
- package/dist/src/queue.d.ts +28 -0
- package/dist/src/queue.d.ts.map +1 -0
- package/dist/src/queue.js +150 -0
- package/dist/src/queue.js.map +1 -0
- package/dist/src/url.d.ts +14 -0
- package/dist/src/url.d.ts.map +1 -0
- package/dist/src/url.js +22 -0
- package/dist/src/url.js.map +1 -0
- package/dist/tests/click-attributes.test.d.ts +2 -0
- package/dist/tests/click-attributes.test.d.ts.map +1 -0
- package/dist/tests/click-attributes.test.js +95 -0
- package/dist/tests/click-attributes.test.js.map +1 -0
- package/dist/tests/core.test.d.ts +5 -0
- package/dist/tests/core.test.d.ts.map +1 -0
- package/dist/tests/core.test.js +158 -0
- package/dist/tests/core.test.js.map +1 -0
- package/dist/tests/data-each-browserlike.test.d.ts +2 -0
- package/dist/tests/data-each-browserlike.test.d.ts.map +1 -0
- package/dist/tests/data-each-browserlike.test.js +48 -0
- package/dist/tests/data-each-browserlike.test.js.map +1 -0
- package/dist/tests/data-each-fragment-debug.test.d.ts +2 -0
- package/dist/tests/data-each-fragment-debug.test.d.ts.map +1 -0
- package/dist/tests/data-each-fragment-debug.test.js +119 -0
- package/dist/tests/data-each-fragment-debug.test.js.map +1 -0
- package/dist/tests/data-each-table.test.d.ts +2 -0
- package/dist/tests/data-each-table.test.d.ts.map +1 -0
- package/dist/tests/data-each-table.test.js +63 -0
- package/dist/tests/data-each-table.test.js.map +1 -0
- package/dist/tests/dev.test.d.ts +2 -0
- package/dist/tests/dev.test.d.ts.map +1 -0
- package/dist/tests/dev.test.js +51 -0
- package/dist/tests/dev.test.js.map +1 -0
- package/dist/tests/each_arg.test.d.ts +2 -0
- package/dist/tests/each_arg.test.d.ts.map +1 -0
- package/dist/tests/each_arg.test.js +41 -0
- package/dist/tests/each_arg.test.js.map +1 -0
- package/dist/tests/env.test.d.ts +2 -0
- package/dist/tests/env.test.d.ts.map +1 -0
- package/dist/tests/env.test.js +96 -0
- package/dist/tests/env.test.js.map +1 -0
- package/dist/tests/event.test.d.ts +2 -0
- package/dist/tests/event.test.d.ts.map +1 -0
- package/dist/tests/event.test.js +287 -0
- package/dist/tests/event.test.js.map +1 -0
- package/dist/tests/expression.test.d.ts +2 -0
- package/dist/tests/expression.test.d.ts.map +1 -0
- package/dist/tests/expression.test.js +281 -0
- package/dist/tests/expression.test.js.map +1 -0
- package/dist/tests/fetch-and-procedure-scenarios.test.d.ts +2 -0
- package/dist/tests/fetch-and-procedure-scenarios.test.d.ts.map +1 -0
- package/dist/tests/fetch-and-procedure-scenarios.test.js +133 -0
- package/dist/tests/fetch-and-procedure-scenarios.test.js.map +1 -0
- package/dist/tests/form.test.d.ts +2 -0
- package/dist/tests/form.test.d.ts.map +1 -0
- package/dist/tests/form.test.js +607 -0
- package/dist/tests/form.test.js.map +1 -0
- package/dist/tests/fragment.test.d.ts +2 -0
- package/dist/tests/fragment.test.d.ts.map +1 -0
- package/dist/tests/fragment.test.js +164 -0
- package/dist/tests/fragment.test.js.map +1 -0
- package/dist/tests/import.test.d.ts +2 -0
- package/dist/tests/import.test.d.ts.map +1 -0
- package/dist/tests/import.test.js +148 -0
- package/dist/tests/import.test.js.map +1 -0
- package/dist/tests/log.test.d.ts +2 -0
- package/dist/tests/log.test.d.ts.map +1 -0
- package/dist/tests/log.test.js +58 -0
- package/dist/tests/log.test.js.map +1 -0
- package/dist/tests/procedure-action-operations.test.d.ts +2 -0
- package/dist/tests/procedure-action-operations.test.d.ts.map +1 -0
- package/dist/tests/procedure-action-operations.test.js +148 -0
- package/dist/tests/procedure-action-operations.test.js.map +1 -0
- package/dist/tests/procedure-fetch-options.test.d.ts +2 -0
- package/dist/tests/procedure-fetch-options.test.d.ts.map +1 -0
- package/dist/tests/procedure-fetch-options.test.js +131 -0
- package/dist/tests/procedure-fetch-options.test.js.map +1 -0
- package/dist/tests/procedure.test.d.ts +2 -0
- package/dist/tests/procedure.test.d.ts.map +1 -0
- package/dist/tests/procedure.test.js +136 -0
- package/dist/tests/procedure.test.js.map +1 -0
- package/dist/tests/procedure_events.test.d.ts +7 -0
- package/dist/tests/procedure_events.test.d.ts.map +1 -0
- package/dist/tests/procedure_events.test.js +96 -0
- package/dist/tests/procedure_events.test.js.map +1 -0
- package/dist/tests/reset_each.test.d.ts +2 -0
- package/dist/tests/reset_each.test.d.ts.map +1 -0
- package/dist/tests/reset_each.test.js +215 -0
- package/dist/tests/reset_each.test.js.map +1 -0
- package/dist/tests/row-move.test.d.ts +2 -0
- package/dist/tests/row-move.test.d.ts.map +1 -0
- package/dist/tests/row-move.test.js +197 -0
- package/dist/tests/row-move.test.js.map +1 -0
- package/dist/tests/row-operations.test.d.ts +2 -0
- package/dist/tests/row-operations.test.d.ts.map +1 -0
- package/dist/tests/row-operations.test.js +238 -0
- package/dist/tests/row-operations.test.js.map +1 -0
- package/dist/tests/url.test.d.ts +2 -0
- package/dist/tests/url.test.d.ts.map +1 -0
- package/dist/tests/url.test.js +150 -0
- package/dist/tests/url.test.js.map +1 -0
- package/dist/vite.config.d.ts +3 -0
- package/dist/vite.config.d.ts.map +1 -0
- package/dist/vite.config.js +28 -0
- package/dist/vite.config.js.map +1 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +19 -0
- package/dist/vitest.config.js.map +1 -0
- package/package.json +68 -0
package/dist/haori.es.js
ADDED
|
@@ -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
|