mhx 2026.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 +202 -0
- package/README.mbt.md +298 -0
- package/dist/index.js +9621 -0
- package/dist/mhx_ffi.js +962 -0
- package/npm/index.js +12 -0
- package/package.json +21 -0
package/dist/mhx_ffi.js
ADDED
|
@@ -0,0 +1,962 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mhx_ffi.js - JavaScript FFI glue code for MoonBit Hypermedia X
|
|
3
|
+
*
|
|
4
|
+
* This file provides the JavaScript implementations for all FFI functions
|
|
5
|
+
* declared in the MoonBit FFI bindings.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Callback registries for async operations
|
|
9
|
+
const fetchCallbacks = new Map();
|
|
10
|
+
const mutationCallbacks = new Map();
|
|
11
|
+
const mutationRecordsMap = new Map();
|
|
12
|
+
|
|
13
|
+
// Reference to the MoonBit module (set during initialization)
|
|
14
|
+
let mbtModule = null;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Initialize the FFI with the MoonBit module reference
|
|
18
|
+
* @param {object} module - The MoonBit WASM module exports
|
|
19
|
+
*/
|
|
20
|
+
export function initMhxFfi(module) {
|
|
21
|
+
mbtModule = module;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Register public exports and callback hooks from MoonBit runtime
|
|
25
|
+
export function register_exports(
|
|
26
|
+
init_mhx,
|
|
27
|
+
process,
|
|
28
|
+
handle_event,
|
|
29
|
+
version,
|
|
30
|
+
on_fetch_success,
|
|
31
|
+
on_fetch_error,
|
|
32
|
+
on_mutation_observed
|
|
33
|
+
) {
|
|
34
|
+
globalThis.mhx = {
|
|
35
|
+
init_mhx,
|
|
36
|
+
process,
|
|
37
|
+
handle_event,
|
|
38
|
+
version,
|
|
39
|
+
};
|
|
40
|
+
mbtModule = {
|
|
41
|
+
on_fetch_success,
|
|
42
|
+
on_fetch_error,
|
|
43
|
+
on_mutation_observed,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Internal: allow MoonBit code to register exports via FFI
|
|
48
|
+
export function mhx_register_exports(
|
|
49
|
+
initMhx,
|
|
50
|
+
processFn,
|
|
51
|
+
handleEvent,
|
|
52
|
+
versionStr,
|
|
53
|
+
onFetchSuccess,
|
|
54
|
+
onFetchError,
|
|
55
|
+
onMutationObserved
|
|
56
|
+
) {
|
|
57
|
+
register_exports(
|
|
58
|
+
initMhx,
|
|
59
|
+
processFn,
|
|
60
|
+
handleEvent,
|
|
61
|
+
versionStr,
|
|
62
|
+
onFetchSuccess,
|
|
63
|
+
onFetchError,
|
|
64
|
+
onMutationObserved
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// Document and Window
|
|
70
|
+
// ============================================================================
|
|
71
|
+
|
|
72
|
+
export function get_document() {
|
|
73
|
+
return document;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function get_window() {
|
|
77
|
+
return window;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function document_body(doc) {
|
|
81
|
+
return doc.body;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function document_head(doc) {
|
|
85
|
+
return doc.head;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function document_document_element(doc) {
|
|
89
|
+
return doc.documentElement;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function document_query_selector(doc, selector) {
|
|
93
|
+
return doc.querySelector(selector);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function document_query_selector_exists(doc, selector) {
|
|
97
|
+
return doc.querySelector(selector) !== null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function document_query_selector_all_count(doc, selector) {
|
|
101
|
+
return doc.querySelectorAll(selector).length;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function document_query_selector_all_at(doc, selector, index) {
|
|
105
|
+
return doc.querySelectorAll(selector)[index];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function document_get_element_by_id(doc, id) {
|
|
109
|
+
return doc.getElementById(id);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function document_element_exists(doc, id) {
|
|
113
|
+
return doc.getElementById(id) !== null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function document_create_element(doc, tag) {
|
|
117
|
+
return doc.createElement(tag);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function document_url(doc) {
|
|
121
|
+
return doc.URL;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function document_title(doc) {
|
|
125
|
+
return doc.title;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function document_set_title(doc, title) {
|
|
129
|
+
doc.title = title;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function document_active_element(doc) {
|
|
133
|
+
return doc.activeElement;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function document_has_active_element(doc) {
|
|
137
|
+
return doc.activeElement !== null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function document_add_event_listener(doc, eventType, handler) {
|
|
141
|
+
doc.addEventListener(eventType, handler);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function window_add_event_listener(win, eventType, handler) {
|
|
145
|
+
win.addEventListener(eventType, handler);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function window_location_href(win) {
|
|
149
|
+
return win.location.href;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function window_set_location_href(win, href) {
|
|
153
|
+
win.location.href = href;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function window_history_push_state(win, url, title) {
|
|
157
|
+
win.history.pushState({}, title, url);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function window_history_replace_state(win, url, title) {
|
|
161
|
+
win.history.replaceState({}, title, url);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function window_history_back(win) {
|
|
165
|
+
win.history.back();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function window_history_forward(win) {
|
|
169
|
+
win.history.forward();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function window_set_timeout(win, handler, delayMs) {
|
|
173
|
+
return win.setTimeout(handler, delayMs);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function window_clear_timeout(win, id) {
|
|
177
|
+
win.clearTimeout(id);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function window_set_interval(win, handler, intervalMs) {
|
|
181
|
+
return win.setInterval(handler, intervalMs);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function window_clear_interval(win, id) {
|
|
185
|
+
win.clearInterval(id);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function window_request_animation_frame(win, handler) {
|
|
189
|
+
return win.requestAnimationFrame(handler);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function window_cancel_animation_frame(win, id) {
|
|
193
|
+
win.cancelAnimationFrame(id);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ============================================================================
|
|
197
|
+
// Element
|
|
198
|
+
// ============================================================================
|
|
199
|
+
|
|
200
|
+
export function element_get_attribute(elem, name) {
|
|
201
|
+
return elem.getAttribute(name) ?? "";
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function element_set_attribute(elem, name, value) {
|
|
205
|
+
elem.setAttribute(name, value);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function element_remove_attribute(elem, name) {
|
|
209
|
+
elem.removeAttribute(name);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function element_has_attribute(elem, name) {
|
|
213
|
+
return !!(elem && elem.hasAttribute && elem.hasAttribute(name));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function element_add_class(elem, className) {
|
|
217
|
+
elem.classList.add(className);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function element_remove_class(elem, className) {
|
|
221
|
+
elem.classList.remove(className);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function element_toggle_class(elem, className) {
|
|
225
|
+
return elem.classList.toggle(className);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function element_has_class(elem, className) {
|
|
229
|
+
return elem.classList.contains(className);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function element_query_selector(elem, selector) {
|
|
233
|
+
return elem.querySelector(selector);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function element_query_selector_exists(elem, selector) {
|
|
237
|
+
return elem.querySelector(selector) !== null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function element_closest(elem, selector) {
|
|
241
|
+
return elem.closest(selector);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function element_closest_exists(elem, selector) {
|
|
245
|
+
return elem.closest(selector) !== null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function element_matches(elem, selector) {
|
|
249
|
+
return elem.matches(selector);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export function element_same(a, b) {
|
|
253
|
+
return a === b;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function element_parent_element(elem) {
|
|
257
|
+
return elem.parentElement;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export function element_has_parent(elem) {
|
|
261
|
+
return elem.parentElement !== null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function element_tag_name(elem) {
|
|
265
|
+
return elem.tagName;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export function element_id(elem) {
|
|
269
|
+
return elem.id ?? "";
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export function element_set_id(elem, id) {
|
|
273
|
+
elem.id = id;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export function element_inner_html(elem) {
|
|
277
|
+
return elem.innerHTML;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export function element_set_inner_html(elem, html) {
|
|
281
|
+
elem.innerHTML = html;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function element_outer_html(elem) {
|
|
285
|
+
return elem.outerHTML;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export function element_set_outer_html(elem, html) {
|
|
289
|
+
elem.outerHTML = html;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export function element_text_content(elem) {
|
|
293
|
+
return elem.textContent ?? "";
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export function element_set_text_content(elem, text) {
|
|
297
|
+
elem.textContent = text;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export function element_insert_adjacent_html(elem, position, html) {
|
|
301
|
+
elem.insertAdjacentHTML(position, html);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export function element_remove(elem) {
|
|
305
|
+
elem.remove();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function element_focus(elem) {
|
|
309
|
+
elem.focus();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export function element_blur(elem) {
|
|
313
|
+
elem.blur();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export function element_is_null(elem) {
|
|
317
|
+
return elem == null;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export function element_child_count(elem) {
|
|
321
|
+
return elem.children.length;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export function element_child_at(elem, index) {
|
|
325
|
+
return elem.children[index];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export function element_value(elem) {
|
|
329
|
+
return elem.value ?? "";
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export function element_set_value(elem, value) {
|
|
333
|
+
elem.value = value;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// ============================================================================
|
|
337
|
+
// Event
|
|
338
|
+
// ============================================================================
|
|
339
|
+
|
|
340
|
+
export function event_type(event) {
|
|
341
|
+
return event.type;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export function event_target(event) {
|
|
345
|
+
return event.target;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export function event_current_target(event) {
|
|
349
|
+
return event.currentTarget;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export function event_has_target(event) {
|
|
353
|
+
return event.target !== null;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export function event_prevent_default(event) {
|
|
357
|
+
event.preventDefault();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
export function event_stop_propagation(event) {
|
|
361
|
+
event.stopPropagation();
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export function event_stop_immediate_propagation(event) {
|
|
365
|
+
event.stopImmediatePropagation();
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export function event_is_trusted(event) {
|
|
369
|
+
return event.isTrusted;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export function event_default_prevented(event) {
|
|
373
|
+
return event.defaultPrevented;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export function event_cancel_bubble(event) {
|
|
377
|
+
return event.cancelBubble;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export function event_time_stamp(event) {
|
|
381
|
+
return event.timeStamp;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export function event_eval_filter(event, expr) {
|
|
385
|
+
try {
|
|
386
|
+
const fn = new Function('event', `with (event) { return !!(${expr}); }`);
|
|
387
|
+
return fn(event);
|
|
388
|
+
} catch (_) {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Mouse Event
|
|
394
|
+
export function event_as_mouse_event(event) {
|
|
395
|
+
return event;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export function mouse_event_client_x(event) {
|
|
399
|
+
return event.clientX;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export function mouse_event_client_y(event) {
|
|
403
|
+
return event.clientY;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export function mouse_event_ctrl_key(event) {
|
|
407
|
+
return event.ctrlKey;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export function mouse_event_shift_key(event) {
|
|
411
|
+
return event.shiftKey;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export function mouse_event_alt_key(event) {
|
|
415
|
+
return event.altKey;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
export function mouse_event_meta_key(event) {
|
|
419
|
+
return event.metaKey;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export function mouse_event_button(event) {
|
|
423
|
+
return event.button;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Keyboard Event
|
|
427
|
+
export function event_as_keyboard_event(event) {
|
|
428
|
+
return event;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export function keyboard_event_key(event) {
|
|
432
|
+
return event.key;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export function keyboard_event_code(event) {
|
|
436
|
+
return event.code;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export function keyboard_event_ctrl_key(event) {
|
|
440
|
+
return event.ctrlKey;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export function keyboard_event_shift_key(event) {
|
|
444
|
+
return event.shiftKey;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
export function keyboard_event_alt_key(event) {
|
|
448
|
+
return event.altKey;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
export function keyboard_event_meta_key(event) {
|
|
452
|
+
return event.metaKey;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
export function keyboard_event_repeat(event) {
|
|
456
|
+
return event.repeat;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Input Event
|
|
460
|
+
export function event_as_input_event(event) {
|
|
461
|
+
return event;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
export function input_event_data(event) {
|
|
465
|
+
return event.data ?? "";
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export function input_event_input_type(event) {
|
|
469
|
+
return event.inputType ?? "";
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Submit Event
|
|
473
|
+
export function event_as_submit_event(event) {
|
|
474
|
+
return event;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
export function submit_event_submitter(event) {
|
|
478
|
+
return event.submitter;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
export function submit_event_has_submitter(event) {
|
|
482
|
+
return event.submitter !== null;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// ============================================================================
|
|
486
|
+
// Fetch API
|
|
487
|
+
// ============================================================================
|
|
488
|
+
|
|
489
|
+
export function fetch(url, optionsJson) {
|
|
490
|
+
const options = JSON.parse(optionsJson);
|
|
491
|
+
return window.fetch(url, options);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export function response_status(response) {
|
|
495
|
+
return response.status;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
export function response_status_text(response) {
|
|
499
|
+
return response.statusText;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
export function response_ok(response) {
|
|
503
|
+
return response.ok;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
export function response_headers(response) {
|
|
507
|
+
return response.headers;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export function response_url(response) {
|
|
511
|
+
return response.url;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export function response_redirected(response) {
|
|
515
|
+
return response.redirected;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
export function response_text(response) {
|
|
519
|
+
return response.text();
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export function response_json(response) {
|
|
523
|
+
return response.json();
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
export function headers_get(headers, name) {
|
|
527
|
+
return headers.get(name) ?? "";
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
export function headers_has(headers, name) {
|
|
531
|
+
return headers.has(name);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
export function abort_controller_new() {
|
|
535
|
+
return new AbortController();
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
export function abort_controller_signal(controller) {
|
|
539
|
+
return controller.signal;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
export function abort_controller_abort(controller) {
|
|
543
|
+
controller.abort();
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
export function abort_signal_aborted(signal) {
|
|
547
|
+
return signal.aborted;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
export function form_data_new() {
|
|
551
|
+
return new FormData();
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
export function form_data_from_element(element) {
|
|
555
|
+
return new FormData(element);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
export function form_data_append(formData, name, value) {
|
|
559
|
+
formData.append(name, value);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
export function form_data_get(formData, name) {
|
|
563
|
+
return formData.get(name) ?? "";
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
export function form_data_has(formData, name) {
|
|
567
|
+
return formData.has(name);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
export function form_data_to_url_encoded(formData) {
|
|
571
|
+
return new URLSearchParams(formData).toString();
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// ============================================================================
|
|
575
|
+
// Async Fetch with Callbacks
|
|
576
|
+
// ============================================================================
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Initiate a fetch request with callback support
|
|
580
|
+
* @param {string} url - The URL to fetch
|
|
581
|
+
* @param {string} optionsJson - JSON-encoded fetch options
|
|
582
|
+
* @param {number} callbackId - The callback ID for response handling
|
|
583
|
+
*/
|
|
584
|
+
export function initiate_fetch(url, optionsJson, callbackId) {
|
|
585
|
+
const options = JSON.parse(optionsJson);
|
|
586
|
+
const controller = new AbortController();
|
|
587
|
+
|
|
588
|
+
fetchCallbacks.set(callbackId, { controller });
|
|
589
|
+
|
|
590
|
+
window.fetch(url, { ...options, signal: controller.signal })
|
|
591
|
+
.then(async (response) => {
|
|
592
|
+
const text = await response.text();
|
|
593
|
+
const callbacks = mbtModule || globalThis.mhx_callbacks;
|
|
594
|
+
if (callbacks && fetchCallbacks.has(callbackId)) {
|
|
595
|
+
callbacks.on_fetch_success(callbackId, text);
|
|
596
|
+
}
|
|
597
|
+
})
|
|
598
|
+
.catch((error) => {
|
|
599
|
+
const callbacks = mbtModule || globalThis.mhx_callbacks;
|
|
600
|
+
if (callbacks && fetchCallbacks.has(callbackId)) {
|
|
601
|
+
callbacks.on_fetch_error(callbackId, error.message);
|
|
602
|
+
}
|
|
603
|
+
})
|
|
604
|
+
.finally(() => {
|
|
605
|
+
fetchCallbacks.delete(callbackId);
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Cancel a pending fetch request
|
|
611
|
+
* @param {number} callbackId - The callback ID to cancel
|
|
612
|
+
*/
|
|
613
|
+
export function cancel_fetch(callbackId) {
|
|
614
|
+
const entry = fetchCallbacks.get(callbackId);
|
|
615
|
+
if (entry) {
|
|
616
|
+
entry.controller.abort();
|
|
617
|
+
fetchCallbacks.delete(callbackId);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Create a dummy response for testing
|
|
623
|
+
*/
|
|
624
|
+
export function create_dummy_response() {
|
|
625
|
+
return new Response("", { status: 200 });
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// ============================================================================
|
|
629
|
+
// MutationObserver
|
|
630
|
+
// ============================================================================
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Create a new MutationObserver
|
|
634
|
+
* @param {number} callbackId - The callback ID for mutation notifications
|
|
635
|
+
*/
|
|
636
|
+
export function mutation_observer_new(callbackId) {
|
|
637
|
+
const observer = new MutationObserver((mutations) => {
|
|
638
|
+
// Store mutations for retrieval
|
|
639
|
+
mutationRecordsMap.set(callbackId, mutations);
|
|
640
|
+
// Notify MoonBit
|
|
641
|
+
const callbacks = mbtModule || globalThis.mhx_callbacks;
|
|
642
|
+
if (callbacks) {
|
|
643
|
+
callbacks.on_mutation_observed(callbackId);
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
mutationCallbacks.set(callbackId, observer);
|
|
647
|
+
return observer;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Start observing a target element
|
|
652
|
+
*/
|
|
653
|
+
export function mutation_observer_observe(observer, target, subtree, childList, attributes) {
|
|
654
|
+
observer.observe(target, {
|
|
655
|
+
subtree,
|
|
656
|
+
childList,
|
|
657
|
+
attributes,
|
|
658
|
+
attributeOldValue: true,
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Stop observing
|
|
664
|
+
*/
|
|
665
|
+
export function mutation_observer_disconnect(observer) {
|
|
666
|
+
observer.disconnect();
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Get the number of pending mutation records
|
|
671
|
+
*/
|
|
672
|
+
export function mutation_observer_records_count(observer) {
|
|
673
|
+
// Find the callback ID for this observer
|
|
674
|
+
for (const [callbackId, obs] of mutationCallbacks) {
|
|
675
|
+
if (obs === observer) {
|
|
676
|
+
const records = mutationRecordsMap.get(callbackId);
|
|
677
|
+
return records ? records.length : 0;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return 0;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Get mutation record at index
|
|
685
|
+
*/
|
|
686
|
+
export function mutation_observer_record_at(observer, index) {
|
|
687
|
+
for (const [callbackId, obs] of mutationCallbacks) {
|
|
688
|
+
if (obs === observer) {
|
|
689
|
+
const records = mutationRecordsMap.get(callbackId);
|
|
690
|
+
return records ? records[index] : null;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Clear the records queue
|
|
698
|
+
*/
|
|
699
|
+
export function mutation_observer_clear_records(observer) {
|
|
700
|
+
for (const [callbackId, obs] of mutationCallbacks) {
|
|
701
|
+
if (obs === observer) {
|
|
702
|
+
mutationRecordsMap.delete(callbackId);
|
|
703
|
+
break;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// MutationRecord accessors
|
|
709
|
+
export function mutation_record_type(record) {
|
|
710
|
+
return record.type;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
export function mutation_record_target(record) {
|
|
714
|
+
return record.target;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
export function mutation_record_added_nodes_count(record) {
|
|
718
|
+
return record.addedNodes.length;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
export function mutation_record_added_node_at(record, index) {
|
|
722
|
+
return record.addedNodes[index];
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
export function mutation_record_removed_nodes_count(record) {
|
|
726
|
+
return record.removedNodes.length;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
export function mutation_record_removed_node_at(record, index) {
|
|
730
|
+
return record.removedNodes[index];
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
export function mutation_record_attribute_name(record) {
|
|
734
|
+
return record.attributeName ?? "";
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
export function mutation_record_has_attribute_name(record) {
|
|
738
|
+
return record.attributeName !== null;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
export function mutation_record_old_value(record) {
|
|
742
|
+
return record.oldValue ?? "";
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
export function mutation_record_has_old_value(record) {
|
|
746
|
+
return record.oldValue !== null;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// Node accessors
|
|
750
|
+
export function node_is_element(node) {
|
|
751
|
+
return node.nodeType === Node.ELEMENT_NODE;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
export function node_as_element(node) {
|
|
755
|
+
return node;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
export function node_node_type(node) {
|
|
759
|
+
return node.nodeType;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
export function node_node_name(node) {
|
|
763
|
+
return node.nodeName;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// ============================================================================
|
|
767
|
+
// Console
|
|
768
|
+
// ============================================================================
|
|
769
|
+
|
|
770
|
+
export function console_log(message) {
|
|
771
|
+
console.log(message);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
export function console_error(message) {
|
|
775
|
+
console.error(message);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
export function console_warn(message) {
|
|
779
|
+
console.warn(message);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
export function console_info(message) {
|
|
783
|
+
console.info(message);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// ============================================================================
|
|
787
|
+
// Timing
|
|
788
|
+
// ============================================================================
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* Get current time in milliseconds
|
|
792
|
+
* Uses performance.now() if available, falls back to Date.now()
|
|
793
|
+
*/
|
|
794
|
+
export function current_time() {
|
|
795
|
+
return typeof performance !== 'undefined'
|
|
796
|
+
? performance.now()
|
|
797
|
+
: Date.now();
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// ============================================================================
|
|
801
|
+
// Export all FFI functions as a module
|
|
802
|
+
// ============================================================================
|
|
803
|
+
|
|
804
|
+
export default {
|
|
805
|
+
initMhxFfi,
|
|
806
|
+
// Document/Window
|
|
807
|
+
get_document,
|
|
808
|
+
get_window,
|
|
809
|
+
document_body,
|
|
810
|
+
document_head,
|
|
811
|
+
document_document_element,
|
|
812
|
+
document_query_selector,
|
|
813
|
+
document_query_selector_exists,
|
|
814
|
+
document_query_selector_all_count,
|
|
815
|
+
document_query_selector_all_at,
|
|
816
|
+
document_get_element_by_id,
|
|
817
|
+
document_element_exists,
|
|
818
|
+
document_create_element,
|
|
819
|
+
document_url,
|
|
820
|
+
document_title,
|
|
821
|
+
document_set_title,
|
|
822
|
+
document_active_element,
|
|
823
|
+
document_has_active_element,
|
|
824
|
+
document_add_event_listener,
|
|
825
|
+
window_add_event_listener,
|
|
826
|
+
window_location_href,
|
|
827
|
+
window_set_location_href,
|
|
828
|
+
window_history_push_state,
|
|
829
|
+
window_history_replace_state,
|
|
830
|
+
window_history_back,
|
|
831
|
+
window_history_forward,
|
|
832
|
+
window_set_timeout,
|
|
833
|
+
window_clear_timeout,
|
|
834
|
+
window_set_interval,
|
|
835
|
+
window_clear_interval,
|
|
836
|
+
window_request_animation_frame,
|
|
837
|
+
window_cancel_animation_frame,
|
|
838
|
+
// Element
|
|
839
|
+
element_get_attribute,
|
|
840
|
+
element_set_attribute,
|
|
841
|
+
element_remove_attribute,
|
|
842
|
+
element_has_attribute,
|
|
843
|
+
element_add_class,
|
|
844
|
+
element_remove_class,
|
|
845
|
+
element_toggle_class,
|
|
846
|
+
element_has_class,
|
|
847
|
+
element_query_selector,
|
|
848
|
+
element_query_selector_exists,
|
|
849
|
+
element_closest,
|
|
850
|
+
element_closest_exists,
|
|
851
|
+
element_matches,
|
|
852
|
+
element_same,
|
|
853
|
+
element_parent_element,
|
|
854
|
+
element_has_parent,
|
|
855
|
+
element_tag_name,
|
|
856
|
+
element_id,
|
|
857
|
+
element_set_id,
|
|
858
|
+
element_inner_html,
|
|
859
|
+
element_set_inner_html,
|
|
860
|
+
element_outer_html,
|
|
861
|
+
element_set_outer_html,
|
|
862
|
+
element_text_content,
|
|
863
|
+
element_set_text_content,
|
|
864
|
+
element_insert_adjacent_html,
|
|
865
|
+
element_remove,
|
|
866
|
+
element_focus,
|
|
867
|
+
element_blur,
|
|
868
|
+
element_is_null,
|
|
869
|
+
element_child_count,
|
|
870
|
+
element_child_at,
|
|
871
|
+
element_value,
|
|
872
|
+
element_set_value,
|
|
873
|
+
// Event
|
|
874
|
+
event_type,
|
|
875
|
+
event_target,
|
|
876
|
+
event_current_target,
|
|
877
|
+
event_has_target,
|
|
878
|
+
event_prevent_default,
|
|
879
|
+
event_stop_propagation,
|
|
880
|
+
event_stop_immediate_propagation,
|
|
881
|
+
event_is_trusted,
|
|
882
|
+
event_default_prevented,
|
|
883
|
+
event_cancel_bubble,
|
|
884
|
+
event_time_stamp,
|
|
885
|
+
event_eval_filter,
|
|
886
|
+
event_as_mouse_event,
|
|
887
|
+
mouse_event_client_x,
|
|
888
|
+
mouse_event_client_y,
|
|
889
|
+
mouse_event_ctrl_key,
|
|
890
|
+
mouse_event_shift_key,
|
|
891
|
+
mouse_event_alt_key,
|
|
892
|
+
mouse_event_meta_key,
|
|
893
|
+
mouse_event_button,
|
|
894
|
+
event_as_keyboard_event,
|
|
895
|
+
keyboard_event_key,
|
|
896
|
+
keyboard_event_code,
|
|
897
|
+
keyboard_event_ctrl_key,
|
|
898
|
+
keyboard_event_shift_key,
|
|
899
|
+
keyboard_event_alt_key,
|
|
900
|
+
keyboard_event_meta_key,
|
|
901
|
+
keyboard_event_repeat,
|
|
902
|
+
event_as_input_event,
|
|
903
|
+
input_event_data,
|
|
904
|
+
input_event_input_type,
|
|
905
|
+
event_as_submit_event,
|
|
906
|
+
submit_event_submitter,
|
|
907
|
+
submit_event_has_submitter,
|
|
908
|
+
// Fetch
|
|
909
|
+
fetch,
|
|
910
|
+
response_status,
|
|
911
|
+
response_status_text,
|
|
912
|
+
response_ok,
|
|
913
|
+
response_headers,
|
|
914
|
+
response_url,
|
|
915
|
+
response_redirected,
|
|
916
|
+
response_text,
|
|
917
|
+
response_json,
|
|
918
|
+
headers_get,
|
|
919
|
+
headers_has,
|
|
920
|
+
abort_controller_new,
|
|
921
|
+
abort_controller_signal,
|
|
922
|
+
abort_controller_abort,
|
|
923
|
+
abort_signal_aborted,
|
|
924
|
+
form_data_new,
|
|
925
|
+
form_data_from_element,
|
|
926
|
+
form_data_append,
|
|
927
|
+
form_data_get,
|
|
928
|
+
form_data_has,
|
|
929
|
+
form_data_to_url_encoded,
|
|
930
|
+
// Async Fetch
|
|
931
|
+
initiate_fetch,
|
|
932
|
+
cancel_fetch,
|
|
933
|
+
create_dummy_response,
|
|
934
|
+
// MutationObserver
|
|
935
|
+
mutation_observer_new,
|
|
936
|
+
mutation_observer_observe,
|
|
937
|
+
mutation_observer_disconnect,
|
|
938
|
+
mutation_observer_records_count,
|
|
939
|
+
mutation_observer_record_at,
|
|
940
|
+
mutation_observer_clear_records,
|
|
941
|
+
mutation_record_type,
|
|
942
|
+
mutation_record_target,
|
|
943
|
+
mutation_record_added_nodes_count,
|
|
944
|
+
mutation_record_added_node_at,
|
|
945
|
+
mutation_record_removed_nodes_count,
|
|
946
|
+
mutation_record_removed_node_at,
|
|
947
|
+
mutation_record_attribute_name,
|
|
948
|
+
mutation_record_has_attribute_name,
|
|
949
|
+
mutation_record_old_value,
|
|
950
|
+
mutation_record_has_old_value,
|
|
951
|
+
node_is_element,
|
|
952
|
+
node_as_element,
|
|
953
|
+
node_node_type,
|
|
954
|
+
node_node_name,
|
|
955
|
+
// Console
|
|
956
|
+
console_log,
|
|
957
|
+
console_error,
|
|
958
|
+
console_warn,
|
|
959
|
+
console_info,
|
|
960
|
+
// Timing
|
|
961
|
+
current_time,
|
|
962
|
+
};
|