create-prisma-php-app 1.13.2 → 1.13.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/app/js/index.js
CHANGED
|
@@ -29,163 +29,6 @@ function debounce(func, wait = 300, immediate = false) {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
/**
|
|
33
|
-
* Represents a HTTP request.
|
|
34
|
-
*/
|
|
35
|
-
class RequestApi {
|
|
36
|
-
static instance = null;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* The constructor is now private. To ensure it's not accessible from outside,
|
|
40
|
-
* you can throw an error if someone tries to instantiate it directly
|
|
41
|
-
* (though JavaScript does not have true private constructors).
|
|
42
|
-
*/
|
|
43
|
-
constructor(baseURL = window.location.origin) {
|
|
44
|
-
this.baseURL = baseURL;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Static method to get instance of RequestApi.
|
|
49
|
-
*
|
|
50
|
-
* @param {string} [baseURL=window.location.origin] - The base URL for the request.
|
|
51
|
-
* @returns {RequestApi} The singleton instance of the RequestApi.
|
|
52
|
-
*/
|
|
53
|
-
static getInstance(baseURL = window.location.origin) {
|
|
54
|
-
if (!RequestApi.instance) {
|
|
55
|
-
RequestApi.instance = new RequestApi(baseURL);
|
|
56
|
-
}
|
|
57
|
-
return RequestApi.instance;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Sends a HTTP request.
|
|
62
|
-
*
|
|
63
|
-
* @async
|
|
64
|
-
* @param {string} method - The HTTP method.
|
|
65
|
-
* @param {string} url - The URL to send the request to.
|
|
66
|
-
* @param {*} [data=null] - The data to send with the request.
|
|
67
|
-
* @param {Object} [headers={}] - The headers to include in the request.
|
|
68
|
-
* @returns {Promise<unknown>} - A promise that resolves to the response data.
|
|
69
|
-
*/
|
|
70
|
-
async request(method, url, data = null, headers = {}) {
|
|
71
|
-
let fullUrl = `${this.baseURL}${url}`;
|
|
72
|
-
const options = {
|
|
73
|
-
method,
|
|
74
|
-
headers: {
|
|
75
|
-
"Content-Type": "application/json",
|
|
76
|
-
"X-Requested-With": "XMLHttpRequest",
|
|
77
|
-
...headers,
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
if (data) {
|
|
82
|
-
if (method === "GET") {
|
|
83
|
-
const params = new URLSearchParams(data).toString();
|
|
84
|
-
fullUrl += `?${params}`;
|
|
85
|
-
} else if (method !== "HEAD" && method !== "OPTIONS") {
|
|
86
|
-
options.body = JSON.stringify(data);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
try {
|
|
91
|
-
const response = await fetch(fullUrl, options);
|
|
92
|
-
if (method === "HEAD") {
|
|
93
|
-
return response.headers;
|
|
94
|
-
}
|
|
95
|
-
const contentType = response.headers.get("content-type");
|
|
96
|
-
if (contentType && contentType.includes("application/json")) {
|
|
97
|
-
return await response.json();
|
|
98
|
-
} else {
|
|
99
|
-
return await response.text();
|
|
100
|
-
}
|
|
101
|
-
} catch (error) {
|
|
102
|
-
throw error;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Sends a GET request.
|
|
108
|
-
*
|
|
109
|
-
* @param {string} url - The URL to send the request to.
|
|
110
|
-
* @param {*} [params] - The parameters to include in the request.
|
|
111
|
-
* @param {Object} [headers={}] - The headers to include in the request.
|
|
112
|
-
* @returns {Promise<unknown>} - A promise that resolves to the response data.
|
|
113
|
-
*/
|
|
114
|
-
get(url, params, headers) {
|
|
115
|
-
return this.request("GET", url, params, headers);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Sends a POST request.
|
|
120
|
-
*
|
|
121
|
-
* @param {string} url - The URL to send the request to.
|
|
122
|
-
* @param {*} data - The data to send with the request.
|
|
123
|
-
* @param {Object} [headers={}] - The headers to include in the request.
|
|
124
|
-
* @returns {Promise<unknown>} - A promise that resolves to the response data.
|
|
125
|
-
*/
|
|
126
|
-
post(url, data, headers) {
|
|
127
|
-
return this.request("POST", url, data, headers);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Sends a PUT request.
|
|
132
|
-
*
|
|
133
|
-
* @param {string} url - The URL to send the request to.
|
|
134
|
-
* @param {*} data - The data to send with the request.
|
|
135
|
-
* @param {Object} [headers={}] - The headers to include in the request.
|
|
136
|
-
* @returns {Promise<unknown>} - A promise that resolves to the response data.
|
|
137
|
-
*/
|
|
138
|
-
put(url, data, headers) {
|
|
139
|
-
return this.request("PUT", url, data, headers);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Sends a DELETE request.
|
|
144
|
-
*
|
|
145
|
-
* @param {string} url - The URL to send the request to.
|
|
146
|
-
* @param {*} data - The data to send with the request.
|
|
147
|
-
* @param {Object} [headers={}] - The headers to include in the request.
|
|
148
|
-
* @returns {Promise<unknown>} - A promise that resolves to the response data.
|
|
149
|
-
*/
|
|
150
|
-
delete(url, data, headers) {
|
|
151
|
-
return this.request("DELETE", url, data, headers);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Sends a PATCH request.
|
|
156
|
-
*
|
|
157
|
-
* @param {string} url - The URL to send the request to.
|
|
158
|
-
* @param {*} data - The data to send with the request.
|
|
159
|
-
* @param {Object} [headers={}] - The headers to include in the request.
|
|
160
|
-
* @returns {Promise<unknown>} - A promise that resolves to the response data.
|
|
161
|
-
*/
|
|
162
|
-
patch(url, data, headers) {
|
|
163
|
-
return this.request("PATCH", url, data, headers);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Sends a HEAD request.
|
|
168
|
-
*
|
|
169
|
-
* @param {string} url - The URL to send the request to.
|
|
170
|
-
* @param {Object} [headers={}] - The headers to include in the request.
|
|
171
|
-
* @returns {Promise<unknown>} - A promise that resolves to the response headers.
|
|
172
|
-
*/
|
|
173
|
-
head(url, headers) {
|
|
174
|
-
return this.request("HEAD", url, null, headers);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Sends an OPTIONS request.
|
|
179
|
-
*
|
|
180
|
-
* @param {string} url - The URL to send the request to.
|
|
181
|
-
* @param {Object} [headers={}] - The headers to include in the request.
|
|
182
|
-
* @returns {Promise<unknown>} - A promise that resolves to the options available.
|
|
183
|
-
*/
|
|
184
|
-
options(url, headers) {
|
|
185
|
-
return this.request("OPTIONS", url, null, headers);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
32
|
/**
|
|
190
33
|
* Copies text to the clipboard.
|
|
191
34
|
*
|
|
@@ -230,310 +73,493 @@ function copyCode(btnElement) {
|
|
|
230
73
|
copyToClipboard(textToCopy, btnElement);
|
|
231
74
|
}
|
|
232
75
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
76
|
+
if (
|
|
77
|
+
typeof RequestApi === "undefined" &&
|
|
78
|
+
typeof StateManager === "undefined" &&
|
|
79
|
+
typeof HXConnector === "undefined"
|
|
80
|
+
) {
|
|
239
81
|
/**
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
* @param {{}} [initialState={}] - The initial state.
|
|
82
|
+
* Represents a HTTP request.
|
|
243
83
|
*/
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
84
|
+
class RequestApi {
|
|
85
|
+
static instance = null;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The constructor is now private. To ensure it's not accessible from outside,
|
|
89
|
+
* you can throw an error if someone tries to instantiate it directly
|
|
90
|
+
* (though JavaScript does not have true private constructors).
|
|
91
|
+
*/
|
|
92
|
+
constructor(baseURL = window.location.origin) {
|
|
93
|
+
this.baseURL = baseURL;
|
|
94
|
+
}
|
|
248
95
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Static method to get instance of RequestApi.
|
|
98
|
+
*
|
|
99
|
+
* @param {string} [baseURL=window.location.origin] - The base URL for the request.
|
|
100
|
+
* @returns {RequestApi} The singleton instance of the RequestApi.
|
|
101
|
+
*/
|
|
102
|
+
static getInstance(baseURL = window.location.origin) {
|
|
103
|
+
if (!RequestApi.instance) {
|
|
104
|
+
RequestApi.instance = new RequestApi(baseURL);
|
|
105
|
+
}
|
|
106
|
+
return RequestApi.instance;
|
|
260
107
|
}
|
|
261
|
-
return StateManager.instance;
|
|
262
|
-
}
|
|
263
108
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Sends a HTTP request.
|
|
111
|
+
*
|
|
112
|
+
* @async
|
|
113
|
+
* @param {string} method - The HTTP method.
|
|
114
|
+
* @param {string} url - The URL to send the request to.
|
|
115
|
+
* @param {*} [data=null] - The data to send with the request.
|
|
116
|
+
* @param {Object} [headers={}] - The headers to include in the request.
|
|
117
|
+
* @returns {Promise<unknown>} - A promise that resolves to the response data.
|
|
118
|
+
*/
|
|
119
|
+
async request(method, url, data = null, headers = {}) {
|
|
120
|
+
let fullUrl = `${this.baseURL}${url}`;
|
|
121
|
+
const options = {
|
|
122
|
+
method,
|
|
123
|
+
headers: {
|
|
124
|
+
"Content-Type": "application/json",
|
|
125
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
126
|
+
...headers,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
if (data) {
|
|
131
|
+
if (method === "GET") {
|
|
132
|
+
const params = new URLSearchParams(data).toString();
|
|
133
|
+
fullUrl += `?${params}`;
|
|
134
|
+
} else if (method !== "HEAD" && method !== "OPTIONS") {
|
|
135
|
+
options.body = JSON.stringify(data);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
const response = await fetch(fullUrl, options);
|
|
141
|
+
if (method === "HEAD") {
|
|
142
|
+
return response.headers;
|
|
143
|
+
}
|
|
144
|
+
const contentType = response.headers.get("content-type");
|
|
145
|
+
if (contentType && contentType.includes("application/json")) {
|
|
146
|
+
return await response.json();
|
|
147
|
+
} else {
|
|
148
|
+
return await response.text();
|
|
149
|
+
}
|
|
150
|
+
} catch (error) {
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
275
153
|
}
|
|
276
|
-
}
|
|
277
154
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
155
|
+
/**
|
|
156
|
+
* Sends a GET request.
|
|
157
|
+
*
|
|
158
|
+
* @param {string} url - The URL to send the request to.
|
|
159
|
+
* @param {*} [params] - The parameters to include in the request.
|
|
160
|
+
* @param {Object} [headers={}] - The headers to include in the request.
|
|
161
|
+
* @returns {Promise<unknown>} - A promise that resolves to the response data.
|
|
162
|
+
*/
|
|
163
|
+
get(url, params, headers) {
|
|
164
|
+
return this.request("GET", url, params, headers);
|
|
165
|
+
}
|
|
290
166
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
167
|
+
/**
|
|
168
|
+
* Sends a POST request.
|
|
169
|
+
*
|
|
170
|
+
* @param {string} url - The URL to send the request to.
|
|
171
|
+
* @param {*} data - The data to send with the request.
|
|
172
|
+
* @param {Object} [headers={}] - The headers to include in the request.
|
|
173
|
+
* @returns {Promise<unknown>} - A promise that resolves to the response data.
|
|
174
|
+
*/
|
|
175
|
+
post(url, data, headers) {
|
|
176
|
+
return this.request("POST", url, data, headers);
|
|
177
|
+
}
|
|
297
178
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
179
|
+
/**
|
|
180
|
+
* Sends a PUT request.
|
|
181
|
+
*
|
|
182
|
+
* @param {string} url - The URL to send the request to.
|
|
183
|
+
* @param {*} data - The data to send with the request.
|
|
184
|
+
* @param {Object} [headers={}] - The headers to include in the request.
|
|
185
|
+
* @returns {Promise<unknown>} - A promise that resolves to the response data.
|
|
186
|
+
*/
|
|
187
|
+
put(url, data, headers) {
|
|
188
|
+
return this.request("PUT", url, data, headers);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Sends a DELETE request.
|
|
193
|
+
*
|
|
194
|
+
* @param {string} url - The URL to send the request to.
|
|
195
|
+
* @param {*} data - The data to send with the request.
|
|
196
|
+
* @param {Object} [headers={}] - The headers to include in the request.
|
|
197
|
+
* @returns {Promise<unknown>} - A promise that resolves to the response data.
|
|
198
|
+
*/
|
|
199
|
+
delete(url, data, headers) {
|
|
200
|
+
return this.request("DELETE", url, data, headers);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Sends a PATCH request.
|
|
205
|
+
*
|
|
206
|
+
* @param {string} url - The URL to send the request to.
|
|
207
|
+
* @param {*} data - The data to send with the request.
|
|
208
|
+
* @param {Object} [headers={}] - The headers to include in the request.
|
|
209
|
+
* @returns {Promise<unknown>} - A promise that resolves to the response data.
|
|
210
|
+
*/
|
|
211
|
+
patch(url, data, headers) {
|
|
212
|
+
return this.request("PATCH", url, data, headers);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Sends a HEAD request.
|
|
217
|
+
*
|
|
218
|
+
* @param {string} url - The URL to send the request to.
|
|
219
|
+
* @param {Object} [headers={}] - The headers to include in the request.
|
|
220
|
+
* @returns {Promise<unknown>} - A promise that resolves to the response headers.
|
|
221
|
+
*/
|
|
222
|
+
head(url, headers) {
|
|
223
|
+
return this.request("HEAD", url, null, headers);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Sends an OPTIONS request.
|
|
228
|
+
*
|
|
229
|
+
* @param {string} url - The URL to send the request to.
|
|
230
|
+
* @param {Object} [headers={}] - The headers to include in the request.
|
|
231
|
+
* @returns {Promise<unknown>} - A promise that resolves to the options available.
|
|
232
|
+
*/
|
|
233
|
+
options(url, headers) {
|
|
234
|
+
return this.request("OPTIONS", url, null, headers);
|
|
306
235
|
}
|
|
307
236
|
}
|
|
308
237
|
|
|
309
238
|
/**
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
* @param {boolean} [clearFromStorage=false] - Whether to clear the state from localStorage.
|
|
239
|
+
* Manages the application state.
|
|
313
240
|
*/
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
241
|
+
class StateManager {
|
|
242
|
+
static instance = null;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Creates a new StateManager instance.
|
|
246
|
+
*
|
|
247
|
+
* @param {{}} [initialState={}] - The initial state.
|
|
248
|
+
*/
|
|
249
|
+
constructor(initialState = {}) {
|
|
250
|
+
this.state = initialState;
|
|
251
|
+
this.listeners = [];
|
|
319
252
|
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
253
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
254
|
+
/**
|
|
255
|
+
* Gets the singleton instance of StateManager.
|
|
256
|
+
*
|
|
257
|
+
* @static
|
|
258
|
+
* @param {{}} [initialState={}] - The initial state.
|
|
259
|
+
* @returns {StateManager} - The StateManager instance.
|
|
260
|
+
*/
|
|
261
|
+
static getInstance(initialState = {}) {
|
|
262
|
+
if (!StateManager.instance) {
|
|
263
|
+
StateManager.instance = new StateManager(initialState);
|
|
264
|
+
StateManager.instance.loadState(); // Load state immediately after instance creation
|
|
265
|
+
}
|
|
266
|
+
return StateManager.instance;
|
|
267
|
+
}
|
|
326
268
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
269
|
+
/**
|
|
270
|
+
* Sets the state.
|
|
271
|
+
*
|
|
272
|
+
* @param {*} update - The state update.
|
|
273
|
+
* @param {boolean} [saveToStorage=false] - Whether to save the state to localStorage.
|
|
274
|
+
*/
|
|
275
|
+
setState(update, saveToStorage = false) {
|
|
276
|
+
this.state = { ...this.state, ...update };
|
|
277
|
+
this.listeners.forEach((listener) => listener(this.state));
|
|
278
|
+
if (saveToStorage) {
|
|
279
|
+
this.saveState();
|
|
280
|
+
}
|
|
331
281
|
}
|
|
332
282
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
283
|
+
/**
|
|
284
|
+
* Subscribes to state changes.
|
|
285
|
+
*
|
|
286
|
+
* @param {*} listener - The listener function.
|
|
287
|
+
* @returns {Function} - A function to unsubscribe the listener.
|
|
288
|
+
*/
|
|
289
|
+
subscribe(listener) {
|
|
290
|
+
this.listeners.push(listener);
|
|
291
|
+
listener(this.state); // Immediately invoke the listener with the current state
|
|
292
|
+
return () =>
|
|
293
|
+
(this.listeners = this.listeners.filter((l) => l !== listener));
|
|
294
|
+
}
|
|
336
295
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
296
|
+
/**
|
|
297
|
+
* Saves the state to localStorage.
|
|
298
|
+
*/
|
|
299
|
+
saveState() {
|
|
300
|
+
localStorage.setItem("appState", JSON.stringify(this.state));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Loads the state from localStorage.
|
|
305
|
+
*/
|
|
306
|
+
loadState() {
|
|
307
|
+
const state = localStorage.getItem("appState");
|
|
308
|
+
if (state) {
|
|
309
|
+
this.state = JSON.parse(state);
|
|
310
|
+
this.listeners.forEach((listener) => listener(this.state));
|
|
311
|
+
}
|
|
341
312
|
}
|
|
342
|
-
return HXConnector.instance;
|
|
343
|
-
}
|
|
344
313
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
});
|
|
314
|
+
/**
|
|
315
|
+
* Resets the state to its initial value.
|
|
316
|
+
*
|
|
317
|
+
* @param {boolean} [clearFromStorage=false] - Whether to clear the state from localStorage.
|
|
318
|
+
*/
|
|
319
|
+
resetState(clearFromStorage = false) {
|
|
320
|
+
this.state = {}; // Reset the state to an empty object or a default state if you prefer
|
|
321
|
+
this.listeners.forEach((listener) => listener(this.state));
|
|
322
|
+
if (clearFromStorage) {
|
|
323
|
+
localStorage.removeItem("appState"); // Clear the state from localStorage
|
|
324
|
+
}
|
|
325
|
+
}
|
|
358
326
|
}
|
|
359
327
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
this.updateElementValues(targetElem, target.value);
|
|
376
|
-
}
|
|
377
|
-
});
|
|
378
|
-
}
|
|
328
|
+
/**
|
|
329
|
+
* Connects elements with `hx-trigger` and `hx-vals` attributes to update
|
|
330
|
+
* their values and attributes based on the specified triggers.
|
|
331
|
+
* Also handles form events based on the `hx-form` attribute.
|
|
332
|
+
* This class is a singleton.
|
|
333
|
+
**/
|
|
334
|
+
class HXConnector {
|
|
335
|
+
// Static property to hold the single instance
|
|
336
|
+
static instance = null;
|
|
337
|
+
|
|
338
|
+
// Private constructor to prevent direct instantiation
|
|
339
|
+
constructor() {
|
|
340
|
+
if (HXConnector.instance) {
|
|
341
|
+
return HXConnector.instance;
|
|
342
|
+
}
|
|
379
343
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
const element = document.getElementById(attributeSet.id);
|
|
384
|
-
if (element) {
|
|
385
|
-
Object.keys(attributeSet.attributes).forEach((attr) => {
|
|
386
|
-
const value = attributeSet.attributes[attr];
|
|
387
|
-
switch (attr) {
|
|
388
|
-
case "class":
|
|
389
|
-
this.updateClassAttribute(element, value);
|
|
390
|
-
break;
|
|
391
|
-
case "add":
|
|
392
|
-
element.setAttribute(value, "");
|
|
393
|
-
break;
|
|
394
|
-
case "remove":
|
|
395
|
-
element.removeAttribute(value);
|
|
396
|
-
break;
|
|
397
|
-
default:
|
|
398
|
-
element.setAttribute(attr, value);
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
});
|
|
403
|
-
}
|
|
344
|
+
this.init();
|
|
345
|
+
HXConnector.instance = this;
|
|
346
|
+
}
|
|
404
347
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
default:
|
|
426
|
-
element.setAttribute(attr, value);
|
|
427
|
-
}
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
});
|
|
431
|
-
},
|
|
432
|
-
{
|
|
433
|
-
once: true,
|
|
434
|
-
}
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
348
|
+
// Static method to get the single instance
|
|
349
|
+
static getInstance() {
|
|
350
|
+
if (!HXConnector.instance) {
|
|
351
|
+
HXConnector.instance = new HXConnector();
|
|
352
|
+
}
|
|
353
|
+
return HXConnector.instance;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Initializes the HXConnector by connecting attributes of elements with
|
|
357
|
+
// `hx-trigger` and `hx-vals` attributes, and sets up an event listener to handle
|
|
358
|
+
// new elements added after HTMX swaps.
|
|
359
|
+
init() {
|
|
360
|
+
this.connectAttributes(document.querySelectorAll("[hx-trigger][hx-vals]"));
|
|
361
|
+
this.handleFormEvents(document.querySelectorAll("[hx-form]"));
|
|
362
|
+
|
|
363
|
+
document.body.addEventListener("htmx:afterSwap", (event) => {
|
|
364
|
+
this.connectAttributes(
|
|
365
|
+
event.detail.target.querySelectorAll("[hx-trigger][hx-vals]")
|
|
366
|
+
);
|
|
367
|
+
this.handleFormEvents(event.detail.target.querySelectorAll("[hx-form]"));
|
|
438
368
|
});
|
|
439
|
-
}
|
|
440
|
-
}
|
|
369
|
+
}
|
|
441
370
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
371
|
+
// Connects attributes of the provided elements based on the values specified
|
|
372
|
+
// in their `hx-vals` attributes and attaches event listeners based on `hx-trigger`.
|
|
373
|
+
connectAttributes(elements) {
|
|
374
|
+
elements.forEach((element) => {
|
|
375
|
+
const event = element.getAttribute("hx-trigger");
|
|
376
|
+
element.addEventListener(event, (el) => {
|
|
377
|
+
const targetElement = el.target.closest("[hx-trigger]");
|
|
378
|
+
if (targetElement) {
|
|
379
|
+
const values = JSON.parse(targetElement.getAttribute("hx-vals"));
|
|
380
|
+
|
|
381
|
+
// Process targets
|
|
382
|
+
if (values.targets) {
|
|
383
|
+
values.targets.forEach((target) => {
|
|
384
|
+
const targetElem = document.getElementById(target.id);
|
|
385
|
+
if (targetElem) {
|
|
386
|
+
this.updateElementValues(targetElem, target.value);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Process attributes
|
|
392
|
+
if (values.attributes) {
|
|
393
|
+
values.attributes.forEach((attributeSet) => {
|
|
394
|
+
const element = document.getElementById(attributeSet.id);
|
|
395
|
+
if (element) {
|
|
396
|
+
Object.keys(attributeSet.attributes).forEach((attr) => {
|
|
397
|
+
const value = attributeSet.attributes[attr];
|
|
398
|
+
switch (attr) {
|
|
399
|
+
case "class":
|
|
400
|
+
this.updateClassAttribute(element, value);
|
|
401
|
+
break;
|
|
402
|
+
case "add":
|
|
403
|
+
element.setAttribute(value, "");
|
|
404
|
+
break;
|
|
405
|
+
case "remove":
|
|
406
|
+
element.removeAttribute(value);
|
|
407
|
+
break;
|
|
408
|
+
default:
|
|
409
|
+
element.setAttribute(attr, value);
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Register swaps to be processed after the htmx request completes
|
|
417
|
+
if (values.swaps) {
|
|
418
|
+
document.addEventListener(
|
|
419
|
+
"htmx:afterRequest",
|
|
420
|
+
() => {
|
|
421
|
+
values.swaps.forEach((swap) => {
|
|
422
|
+
const element = document.getElementById(swap.id);
|
|
423
|
+
if (element) {
|
|
424
|
+
Object.keys(swap.attributes).forEach((attr) => {
|
|
425
|
+
const value = swap.attributes[attr];
|
|
426
|
+
switch (attr) {
|
|
427
|
+
case "class":
|
|
428
|
+
this.updateClassAttribute(element, value);
|
|
429
|
+
break;
|
|
430
|
+
case "add":
|
|
431
|
+
element.setAttribute(value, "");
|
|
432
|
+
break;
|
|
433
|
+
case "remove":
|
|
434
|
+
element.removeAttribute(value);
|
|
435
|
+
break;
|
|
436
|
+
default:
|
|
437
|
+
element.setAttribute(attr, value);
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
once: true,
|
|
445
|
+
}
|
|
446
|
+
);
|
|
447
|
+
}
|
|
476
448
|
}
|
|
477
449
|
});
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
450
|
+
});
|
|
451
|
+
}
|
|
481
452
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
453
|
+
// Handles form events for the provided forms based on their `hx-form` attribute.
|
|
454
|
+
handleFormEvents(forms) {
|
|
455
|
+
forms.forEach((form) => {
|
|
456
|
+
const eventAttr = form.getAttribute("hx-form");
|
|
457
|
+
if (eventAttr) {
|
|
458
|
+
const [eventType, functionName] = eventAttr.split(":");
|
|
459
|
+
|
|
460
|
+
form.addEventListener(`htmx:${eventType}`, (event) => {
|
|
461
|
+
switch (functionName) {
|
|
462
|
+
case "reset":
|
|
463
|
+
if (event.detail.successful) {
|
|
464
|
+
form.reset();
|
|
465
|
+
}
|
|
466
|
+
break;
|
|
467
|
+
|
|
468
|
+
case "clear":
|
|
469
|
+
if (event.detail.successful) {
|
|
470
|
+
this.clearForm(form);
|
|
471
|
+
}
|
|
472
|
+
break;
|
|
473
|
+
|
|
474
|
+
case "disable":
|
|
475
|
+
this.toggleForm(form, true);
|
|
476
|
+
break;
|
|
477
|
+
|
|
478
|
+
case "enable":
|
|
479
|
+
this.toggleForm(form, false);
|
|
480
|
+
break;
|
|
481
|
+
|
|
482
|
+
// Add more cases as needed
|
|
483
|
+
|
|
484
|
+
default:
|
|
485
|
+
console.warn(`Unhandled function name: ${functionName}`);
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
}
|
|
493
492
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
493
|
+
// Clears the input values of the specified form.
|
|
494
|
+
clearForm(form) {
|
|
495
|
+
const inputs = form.querySelectorAll("input, textarea, select");
|
|
496
|
+
inputs.forEach((input) => {
|
|
497
|
+
if (input.type === "checkbox" || input.type === "radio") {
|
|
498
|
+
input.checked = false;
|
|
499
|
+
} else {
|
|
500
|
+
input.value = "";
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Toggles the disabled state of the specified form's inputs.
|
|
506
|
+
toggleForm(form, state) {
|
|
507
|
+
const inputs = form.querySelectorAll("input, textarea, select, button");
|
|
508
|
+
inputs.forEach((input) => {
|
|
509
|
+
input.disabled = state;
|
|
510
|
+
});
|
|
511
|
+
}
|
|
501
512
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
513
|
+
// Updates the values of the specified element based on its tag name and type.
|
|
514
|
+
updateElementValues(element, value) {
|
|
515
|
+
const tagName = element.tagName;
|
|
516
|
+
const inputType = element.type;
|
|
506
517
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
518
|
+
if (tagName === "INPUT" || tagName === "TEXTAREA") {
|
|
519
|
+
if (inputType === "checkbox") {
|
|
520
|
+
element.checked = value;
|
|
521
|
+
} else {
|
|
522
|
+
element.value = value;
|
|
523
|
+
}
|
|
510
524
|
} else {
|
|
511
|
-
element.
|
|
525
|
+
element.textContent = value;
|
|
512
526
|
}
|
|
513
|
-
}
|
|
514
|
-
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Updates the class attribute of the specified element. Class names starting
|
|
530
|
+
// with a hyphen (`-`) are removed, others are added.
|
|
531
|
+
updateClassAttribute(element, className) {
|
|
532
|
+
const classNames = className.split(" ");
|
|
533
|
+
classNames.forEach((name) => {
|
|
534
|
+
if (name.startsWith("-")) {
|
|
535
|
+
element.classList.remove(name.substring(1));
|
|
536
|
+
} else {
|
|
537
|
+
element.classList.add(name);
|
|
538
|
+
}
|
|
539
|
+
});
|
|
515
540
|
}
|
|
516
541
|
}
|
|
517
542
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
}
|
|
528
|
-
});
|
|
543
|
+
let store = null;
|
|
544
|
+
let api = null;
|
|
545
|
+
let hxConnector = null;
|
|
546
|
+
|
|
547
|
+
// Function to initialize instances
|
|
548
|
+
function initializeInstances() {
|
|
549
|
+
store = StateManager.getInstance();
|
|
550
|
+
api = RequestApi.getInstance();
|
|
551
|
+
hxConnector = HXConnector.getInstance();
|
|
529
552
|
}
|
|
530
|
-
}
|
|
531
553
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
554
|
+
// Initialize instances on initial page load
|
|
555
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
556
|
+
initializeInstances();
|
|
557
|
+
|
|
558
|
+
// Ensure document.body exists before attaching the event listener
|
|
559
|
+
if (document.body) {
|
|
560
|
+
document.body.addEventListener("htmx:afterOnLoad", function () {
|
|
561
|
+
initializeInstances();
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
}
|