@salve-software/react-native-nitro-jsdom 1.1.0 → 2.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/android/CMakeLists.txt +6 -0
- package/cpp/HybridHtmlSandbox.cpp +14 -7
- package/cpp/HybridHtmlSandbox.hpp +1 -1
- package/cpp/lexbor/LexborDocument.cpp +65 -3
- package/cpp/lexbor/LexborDocument.hpp +17 -2
- package/cpp/quickjs/DOMBindings.cpp +14 -1
- package/cpp/quickjs/DOMBindingsInternal.cpp +67 -0
- package/cpp/quickjs/DOMBindingsInternal.hpp +39 -0
- package/cpp/quickjs/QuickJSRuntime.cpp +13 -0
- package/cpp/quickjs/QuickJSRuntime.hpp +29 -0
- package/cpp/quickjs/bindings/AbortBindings.cpp +14 -0
- package/cpp/quickjs/bindings/BlobBindings.cpp +28 -1
- package/cpp/quickjs/bindings/BlobBindings.hpp +3 -3
- package/cpp/quickjs/bindings/CSSOMBindings.cpp +96 -0
- package/cpp/quickjs/bindings/CSSOMBindings.hpp +3 -1
- package/cpp/quickjs/bindings/CustomElementsBindings.cpp +1 -1
- package/cpp/quickjs/bindings/DOMParserBindings.cpp +299 -0
- package/cpp/quickjs/bindings/DOMParserBindings.hpp +45 -0
- package/cpp/quickjs/bindings/DocumentBindings.cpp +174 -11
- package/cpp/quickjs/bindings/ElementBindings.cpp +516 -20
- package/cpp/quickjs/bindings/EventBindings.cpp +281 -5
- package/cpp/quickjs/bindings/EventBindings.hpp +3 -0
- package/cpp/quickjs/bindings/EventTargetBindings.cpp +75 -0
- package/cpp/quickjs/bindings/EventTargetBindings.hpp +24 -0
- package/cpp/quickjs/bindings/FetchBindings.cpp +43 -8
- package/cpp/quickjs/bindings/FormBindings.cpp +294 -0
- package/cpp/quickjs/bindings/FormBindings.hpp +9 -5
- package/cpp/quickjs/bindings/IntlBindings.cpp +352 -0
- package/cpp/quickjs/bindings/IntlBindings.hpp +29 -0
- package/cpp/quickjs/bindings/LayoutStubBindings.cpp +104 -0
- package/cpp/quickjs/bindings/LayoutStubBindings.hpp +28 -0
- package/cpp/quickjs/bindings/LiveCollectionBindings.cpp +45 -0
- package/cpp/quickjs/bindings/TimerBindings.cpp +79 -0
- package/cpp/quickjs/bindings/TreeWalkerBindings.cpp +306 -0
- package/cpp/quickjs/bindings/TreeWalkerBindings.hpp +28 -0
- package/cpp/quickjs/bindings/UrlBindings.cpp +43 -0
- package/cpp/quickjs/bindings/WindowBindings.cpp +295 -4
- package/cpp/quickjs/bindings/WindowBindings.hpp +3 -2
- package/cpp/quickjs/bindings/WindowNamedPropertiesBindings.cpp +241 -0
- package/cpp/quickjs/bindings/WindowNamedPropertiesBindings.hpp +30 -0
- package/lib/commonjs/classes/JSDOM/JSDOM.class.js +2 -1
- package/lib/commonjs/classes/JSDOM/JSDOM.class.js.map +1 -1
- package/lib/module/classes/JSDOM/JSDOM.class.js +2 -1
- package/lib/module/classes/JSDOM/JSDOM.class.js.map +1 -1
- package/lib/typescript/src/classes/JSDOM/JSDOM.class.d.ts.map +1 -1
- package/lib/typescript/src/classes/JSDOM/types/IJSDOMOptions.d.ts +5 -4
- package/lib/typescript/src/classes/JSDOM/types/IJSDOMOptions.d.ts.map +1 -1
- package/lib/typescript/src/specs/HtmlSandbox.nitro.d.ts +1 -1
- package/lib/typescript/src/specs/HtmlSandbox.nitro.d.ts.map +1 -1
- package/nitrogen/generated/shared/c++/HybridHtmlSandboxSpec.hpp +1 -1
- package/package.json +17 -2
- package/src/classes/JSDOM/JSDOM.class.ts +2 -1
- package/src/classes/JSDOM/types/IJSDOMOptions.ts +5 -4
- package/src/specs/HtmlSandbox.nitro.ts +1 -1
|
@@ -34,9 +34,17 @@ JSValue js_Event_constructor(JSContext* ctx, JSValue, int argc, JSValue* argv) {
|
|
|
34
34
|
else { cancelable = JS_ToBool(ctx, c) > 0; JS_FreeValue(ctx, c); }
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
bool composed = false;
|
|
38
|
+
if (argc >= 2 && JS_IsObject(argv[1])) {
|
|
39
|
+
JSValue c = JS_GetPropertyStr(ctx, argv[1], "composed");
|
|
40
|
+
if (JS_IsException(c)) { JS_FreeValue(ctx, JS_GetException(ctx)); }
|
|
41
|
+
else { composed = JS_ToBool(ctx, c) > 0; JS_FreeValue(ctx, c); }
|
|
42
|
+
}
|
|
43
|
+
|
|
37
44
|
JS_SetPropertyStr(ctx, obj, "defaultPrevented", JS_NewBool(ctx, false));
|
|
38
45
|
JS_SetPropertyStr(ctx, obj, "bubbles", JS_NewBool(ctx, bubbles));
|
|
39
46
|
JS_SetPropertyStr(ctx, obj, "cancelable", JS_NewBool(ctx, cancelable));
|
|
47
|
+
JS_SetPropertyStr(ctx, obj, "composed", JS_NewBool(ctx, composed));
|
|
40
48
|
return obj;
|
|
41
49
|
}
|
|
42
50
|
|
|
@@ -64,9 +72,17 @@ JSValue js_CustomEvent_constructor(JSContext* ctx, JSValue, int argc, JSValue* a
|
|
|
64
72
|
else { cancelable = JS_ToBool(ctx, c) > 0; JS_FreeValue(ctx, c); }
|
|
65
73
|
}
|
|
66
74
|
|
|
75
|
+
bool composed = false;
|
|
76
|
+
if (argc >= 2 && JS_IsObject(argv[1])) {
|
|
77
|
+
JSValue c = JS_GetPropertyStr(ctx, argv[1], "composed");
|
|
78
|
+
if (JS_IsException(c)) { JS_FreeValue(ctx, JS_GetException(ctx)); }
|
|
79
|
+
else { composed = JS_ToBool(ctx, c) > 0; JS_FreeValue(ctx, c); }
|
|
80
|
+
}
|
|
81
|
+
|
|
67
82
|
JS_SetPropertyStr(ctx, obj, "detail", detail);
|
|
68
83
|
JS_SetPropertyStr(ctx, obj, "bubbles", JS_NewBool(ctx, bubbles));
|
|
69
84
|
JS_SetPropertyStr(ctx, obj, "cancelable", JS_NewBool(ctx, cancelable));
|
|
85
|
+
JS_SetPropertyStr(ctx, obj, "composed", JS_NewBool(ctx, composed));
|
|
70
86
|
JS_SetPropertyStr(ctx, obj, "defaultPrevented", JS_NewBool(ctx, false));
|
|
71
87
|
return obj;
|
|
72
88
|
}
|
|
@@ -113,6 +129,7 @@ JSValue js_KeyboardEvent_constructor(JSContext* ctx, JSValue, int argc, JSValue*
|
|
|
113
129
|
JSValue init = (argc >= 2) ? argv[1] : JS_UNDEFINED;
|
|
114
130
|
JS_SetPropertyStr(ctx, obj, "bubbles", JS_NewBool(ctx, get_bool_init_field(ctx, init, "bubbles")));
|
|
115
131
|
JS_SetPropertyStr(ctx, obj, "cancelable", JS_NewBool(ctx, get_bool_init_field(ctx, init, "cancelable")));
|
|
132
|
+
JS_SetPropertyStr(ctx, obj, "composed", JS_NewBool(ctx, get_bool_init_field(ctx, init, "composed")));
|
|
116
133
|
JS_SetPropertyStr(ctx, obj, "defaultPrevented", JS_NewBool(ctx, false));
|
|
117
134
|
|
|
118
135
|
std::string key = get_str_init_field(ctx, init, "key", "");
|
|
@@ -137,6 +154,7 @@ JSValue js_MouseEvent_constructor(JSContext* ctx, JSValue, int argc, JSValue* ar
|
|
|
137
154
|
JSValue init = (argc >= 2) ? argv[1] : JS_UNDEFINED;
|
|
138
155
|
JS_SetPropertyStr(ctx, obj, "bubbles", JS_NewBool(ctx, get_bool_init_field(ctx, init, "bubbles")));
|
|
139
156
|
JS_SetPropertyStr(ctx, obj, "cancelable", JS_NewBool(ctx, get_bool_init_field(ctx, init, "cancelable")));
|
|
157
|
+
JS_SetPropertyStr(ctx, obj, "composed", JS_NewBool(ctx, get_bool_init_field(ctx, init, "composed")));
|
|
140
158
|
JS_SetPropertyStr(ctx, obj, "defaultPrevented", JS_NewBool(ctx, false));
|
|
141
159
|
|
|
142
160
|
JS_SetPropertyStr(ctx, obj, "clientX", JS_NewFloat64(ctx, get_num_init_field(ctx, init, "clientX", 0)));
|
|
@@ -173,6 +191,18 @@ JSValue js_event_stopImmediatePropagation(JSContext* ctx, JSValue this_val, int,
|
|
|
173
191
|
return JS_UNDEFINED;
|
|
174
192
|
}
|
|
175
193
|
|
|
194
|
+
// __composedPath is populated by dispatch_event_on_target() right before
|
|
195
|
+
// listener invocation begins; an event that was never dispatched (just
|
|
196
|
+
// constructed) has none, matching the spec's "not currently dispatched" case.
|
|
197
|
+
JSValue js_event_composedPath(JSContext* ctx, JSValue this_val, int, JSValue*) {
|
|
198
|
+
JSValue path = JS_GetPropertyStr(ctx, this_val, "__composedPath");
|
|
199
|
+
if (JS_IsUndefined(path) || JS_IsException(path)) {
|
|
200
|
+
if (JS_IsException(path)) JS_FreeValue(ctx, JS_GetException(ctx));
|
|
201
|
+
return JS_NewArray(ctx);
|
|
202
|
+
}
|
|
203
|
+
return path;
|
|
204
|
+
}
|
|
205
|
+
|
|
176
206
|
// ── addEventListener / removeEventListener (element) ──────────────────────────
|
|
177
207
|
|
|
178
208
|
JSValue js_el_addEventListener(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
@@ -189,7 +219,7 @@ JSValue js_el_addEventListener(JSContext* ctx, JSValue this_val, int argc, JSVal
|
|
|
189
219
|
|
|
190
220
|
void* node = lxb_dom_interface_node(el);
|
|
191
221
|
for (auto& l : rctx->listeners) {
|
|
192
|
-
if (l.node == node && l.event_type == event_type) {
|
|
222
|
+
if (l.node == node && l.event_type == event_type && !l.is_handler_property) {
|
|
193
223
|
JSValue* stored = static_cast<JSValue*>(l.callback);
|
|
194
224
|
if (JS_VALUE_GET_TAG(*stored) == JS_VALUE_GET_TAG(argv[1]) &&
|
|
195
225
|
JS_VALUE_GET_PTR(*stored) == JS_VALUE_GET_PTR(argv[1]))
|
|
@@ -219,7 +249,7 @@ JSValue js_el_removeEventListener(JSContext* ctx, JSValue this_val, int argc, JS
|
|
|
219
249
|
|
|
220
250
|
void* node = lxb_dom_interface_node(el);
|
|
221
251
|
for (auto it = rctx->listeners.begin(); it != rctx->listeners.end(); ) {
|
|
222
|
-
if (it->node == node && it->event_type == event_type) {
|
|
252
|
+
if (it->node == node && it->event_type == event_type && !it->is_handler_property) {
|
|
223
253
|
JSValue* stored_cb = static_cast<JSValue*>(it->callback);
|
|
224
254
|
if (JS_VALUE_GET_TAG(*stored_cb) == JS_VALUE_GET_TAG(argv[1]) &&
|
|
225
255
|
JS_VALUE_GET_PTR(*stored_cb) == JS_VALUE_GET_PTR(argv[1])) {
|
|
@@ -254,6 +284,7 @@ JSValue dispatch_event_on_target(JSContext* ctx, RuntimeContext* rctx, JSValue e
|
|
|
254
284
|
JS_FreeCString(ctx, type_str);
|
|
255
285
|
|
|
256
286
|
bool bubbles = get_bool_prop(ctx, event_obj, "bubbles");
|
|
287
|
+
bool composed = get_bool_prop(ctx, event_obj, "composed");
|
|
257
288
|
|
|
258
289
|
lxb_dom_node_t* doc_node = nullptr;
|
|
259
290
|
if (rctx->document) {
|
|
@@ -267,7 +298,46 @@ JSValue dispatch_event_on_target(JSContext* ctx, RuntimeContext* rctx, JSValue e
|
|
|
267
298
|
std::vector<lxb_dom_node_t*> chain;
|
|
268
299
|
chain.push_back(target_node);
|
|
269
300
|
if (bubbles) {
|
|
270
|
-
|
|
301
|
+
// Climb ancestors; when we reach the top of a shadow tree (a registered
|
|
302
|
+
// ShadowRoot — it has no `parent` in the node tree, since Lexbor doesn't
|
|
303
|
+
// link a shadow root into its host's child list) and the event is
|
|
304
|
+
// composed, retarget through the shadow host (found by reverse-lookup in
|
|
305
|
+
// element_shadow_roots) and keep climbing into the light tree above it —
|
|
306
|
+
// this is how a composed event (e.g. 'click') escapes a shadow boundary
|
|
307
|
+
// while a non-composed one stays contained. The ShadowRoot node itself is
|
|
308
|
+
// never added to the chain/composedPath (unlike real DOM, which does
|
|
309
|
+
// include it): this sandbox's ShadowRoot wrapper only exists via
|
|
310
|
+
// ShadowRootBindings' host-keyed cache, so building one here via the
|
|
311
|
+
// generic make_element() path (used for every other chain entry) would
|
|
312
|
+
// produce a broken, non-ShadowRoot-shaped object instead. Simplification:
|
|
313
|
+
// this sandbox has no separate capture phase, so composedPath()/
|
|
314
|
+
// retargeting are only computed along the bubble chain — a non-bubbling
|
|
315
|
+
// event's composedPath() is just [target].
|
|
316
|
+
lxb_dom_node_t* p = target_node->parent;
|
|
317
|
+
while (p) {
|
|
318
|
+
void* host = nullptr;
|
|
319
|
+
for (auto& kv : rctx->element_shadow_roots) {
|
|
320
|
+
if (kv.second == static_cast<void*>(p)) { host = kv.first; break; }
|
|
321
|
+
}
|
|
322
|
+
if (host) {
|
|
323
|
+
if (!composed) break;
|
|
324
|
+
p = static_cast<lxb_dom_node_t*>(host);
|
|
325
|
+
}
|
|
326
|
+
chain.push_back(p);
|
|
327
|
+
p = p->parent;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
{
|
|
332
|
+
JSValue path_arr = JS_NewArray(ctx);
|
|
333
|
+
for (size_t i = 0; i < chain.size(); i++) {
|
|
334
|
+
lxb_dom_node_t* level = chain[i];
|
|
335
|
+
JSValue entry = (level == doc_node)
|
|
336
|
+
? ([&]() { JSValue g = JS_GetGlobalObject(ctx); JSValue d = JS_GetPropertyStr(ctx, g, "document"); JS_FreeValue(ctx, g); return d; })()
|
|
337
|
+
: make_element(ctx, level);
|
|
338
|
+
JS_SetPropertyUint32(ctx, path_arr, (uint32_t)i, entry);
|
|
339
|
+
}
|
|
340
|
+
JS_SetPropertyStr(ctx, event_obj, "__composedPath", path_arr);
|
|
271
341
|
}
|
|
272
342
|
|
|
273
343
|
for (lxb_dom_node_t* level : chain) {
|
|
@@ -287,11 +357,13 @@ JSValue dispatch_event_on_target(JSContext* ctx, RuntimeContext* rctx, JSValue e
|
|
|
287
357
|
|
|
288
358
|
std::vector<JSValue> cbs_to_fire;
|
|
289
359
|
std::vector<JSValue*> cb_ptrs;
|
|
360
|
+
std::vector<bool> cb_is_handler_property;
|
|
290
361
|
for (auto& listener : rctx->listeners) {
|
|
291
362
|
if (listener.node == level && listener.event_type == event_type) {
|
|
292
363
|
JSValue* cb = static_cast<JSValue*>(listener.callback);
|
|
293
364
|
cbs_to_fire.push_back(JS_DupValue(ctx, *cb));
|
|
294
365
|
cb_ptrs.push_back(cb);
|
|
366
|
+
cb_is_handler_property.push_back(listener.is_handler_property);
|
|
295
367
|
}
|
|
296
368
|
}
|
|
297
369
|
|
|
@@ -314,7 +386,27 @@ JSValue dispatch_event_on_target(JSContext* ctx, RuntimeContext* rctx, JSValue e
|
|
|
314
386
|
JS_FreeValue(ctx, cbs_to_fire[i]);
|
|
315
387
|
continue;
|
|
316
388
|
}
|
|
317
|
-
JSValue ret
|
|
389
|
+
JSValue ret;
|
|
390
|
+
if (cb_is_handler_property[i] && event_type == "error") {
|
|
391
|
+
JSValue message_val = JS_GetPropertyStr(ctx, event_obj, "message");
|
|
392
|
+
JSValue error_val = JS_GetPropertyStr(ctx, event_obj, "error");
|
|
393
|
+
JSValue global = JS_GetGlobalObject(ctx);
|
|
394
|
+
JSValue location_val = JS_GetPropertyStr(ctx, global, "location");
|
|
395
|
+
JSValue source_val = JS_GetPropertyStr(ctx, location_val, "href");
|
|
396
|
+
JS_FreeValue(ctx, location_val);
|
|
397
|
+
JS_FreeValue(ctx, global);
|
|
398
|
+
JSValue lineno_val = JS_NewInt32(ctx, 0);
|
|
399
|
+
JSValue colno_val = JS_NewInt32(ctx, 0);
|
|
400
|
+
JSValue args[5] = { message_val, source_val, lineno_val, colno_val, error_val };
|
|
401
|
+
ret = JS_Call(ctx, cbs_to_fire[i], current_target, 5, args);
|
|
402
|
+
JS_FreeValue(ctx, message_val);
|
|
403
|
+
JS_FreeValue(ctx, source_val);
|
|
404
|
+
JS_FreeValue(ctx, lineno_val);
|
|
405
|
+
JS_FreeValue(ctx, colno_val);
|
|
406
|
+
JS_FreeValue(ctx, error_val);
|
|
407
|
+
} else {
|
|
408
|
+
ret = JS_Call(ctx, cbs_to_fire[i], current_target, 1, &event_obj);
|
|
409
|
+
}
|
|
318
410
|
JS_FreeValue(ctx, cbs_to_fire[i]);
|
|
319
411
|
if (JS_IsException(ret)) {
|
|
320
412
|
JS_FreeValue(ctx, ret);
|
|
@@ -331,14 +423,23 @@ JSValue dispatch_event_on_target(JSContext* ctx, RuntimeContext* rctx, JSValue e
|
|
|
331
423
|
JS_FreeValue(ctx, msg_prop);
|
|
332
424
|
JS_FreeValue(ctx, ex);
|
|
333
425
|
JS_ThrowInternalError(ctx, "%s", err.c_str());
|
|
426
|
+
JS_SetPropertyStr(ctx, event_obj, "__composedPath", JS_NewArray(ctx));
|
|
334
427
|
return JS_EXCEPTION;
|
|
335
428
|
}
|
|
429
|
+
if (cb_is_handler_property[i] && JS_IsBool(ret) && JS_ToBool(ctx, ret) == 0 &&
|
|
430
|
+
get_bool_prop(ctx, event_obj, "cancelable")) {
|
|
431
|
+
JS_SetPropertyStr(ctx, event_obj, "defaultPrevented", JS_NewBool(ctx, true));
|
|
432
|
+
}
|
|
336
433
|
JS_FreeValue(ctx, ret);
|
|
337
434
|
}
|
|
338
435
|
JS_FreeValue(ctx, current_target);
|
|
339
436
|
}
|
|
340
437
|
|
|
341
438
|
bool defaultPrevented = get_bool_prop(ctx, event_obj, "defaultPrevented");
|
|
439
|
+
// Per spec, composedPath() only returns a populated path while the event is
|
|
440
|
+
// actively being dispatched — reset it so a reference to `event` saved by
|
|
441
|
+
// a listener returns [] if composedPath() is called after dispatch ends.
|
|
442
|
+
JS_SetPropertyStr(ctx, event_obj, "__composedPath", JS_NewArray(ctx));
|
|
342
443
|
return JS_NewBool(ctx, !defaultPrevented);
|
|
343
444
|
}
|
|
344
445
|
|
|
@@ -367,7 +468,7 @@ JSValue js_doc_addEventListener(JSContext* ctx, JSValue, int argc, JSValue* argv
|
|
|
367
468
|
static_cast<lxb_html_document_t*>(rctx->document->documentHtmlPtr())));
|
|
368
469
|
|
|
369
470
|
for (auto& l : rctx->listeners) {
|
|
370
|
-
if (l.node == doc_node && l.event_type == event_type) {
|
|
471
|
+
if (l.node == doc_node && l.event_type == event_type && !l.is_handler_property) {
|
|
371
472
|
JSValue* stored = static_cast<JSValue*>(l.callback);
|
|
372
473
|
if (JS_VALUE_GET_TAG(*stored) == JS_VALUE_GET_TAG(argv[1]) &&
|
|
373
474
|
JS_VALUE_GET_PTR(*stored) == JS_VALUE_GET_PTR(argv[1]))
|
|
@@ -427,6 +528,130 @@ JSValue js_doc_dispatchEvent(JSContext* ctx, JSValue, int argc, JSValue* argv) {
|
|
|
427
528
|
return dispatch_event_on_target(ctx, rctx, argv[0], node);
|
|
428
529
|
}
|
|
429
530
|
|
|
531
|
+
const char* kHandlerEventTypes[] = { "click", "load", "error", "unhandledrejection", "change", "input", "submit", "reset" };
|
|
532
|
+
|
|
533
|
+
JSValue get_handler_prop_for_node(JSContext* ctx, RuntimeContext* rctx, void* node, const std::string& event_type) {
|
|
534
|
+
if (!rctx || !node) return JS_NULL;
|
|
535
|
+
for (auto& l : rctx->listeners) {
|
|
536
|
+
if (l.node == node && l.event_type == event_type && l.is_handler_property)
|
|
537
|
+
return JS_DupValue(ctx, *static_cast<JSValue*>(l.callback));
|
|
538
|
+
}
|
|
539
|
+
return JS_NULL;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
JSValue set_handler_prop_for_node(JSContext* ctx, RuntimeContext* rctx, void* node, const std::string& event_type, JSValue val) {
|
|
543
|
+
if (!rctx || !node) return JS_UNDEFINED;
|
|
544
|
+
for (auto it = rctx->listeners.begin(); it != rctx->listeners.end(); ++it) {
|
|
545
|
+
if (it->node == node && it->event_type == event_type && it->is_handler_property) {
|
|
546
|
+
JSValue* stored = static_cast<JSValue*>(it->callback);
|
|
547
|
+
JS_FreeValue(ctx, *stored);
|
|
548
|
+
delete stored;
|
|
549
|
+
rctx->listeners.erase(it);
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (JS_IsFunction(ctx, val)) {
|
|
554
|
+
EventListener listener;
|
|
555
|
+
listener.node = node;
|
|
556
|
+
listener.event_type = event_type;
|
|
557
|
+
listener.callback = new JSValue(JS_DupValue(ctx, val));
|
|
558
|
+
listener.is_handler_property = true;
|
|
559
|
+
rctx->listeners.push_back(std::move(listener));
|
|
560
|
+
}
|
|
561
|
+
return JS_UNDEFINED;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
JSValue js_el_get_handler(JSContext* ctx, JSValue this_val, int magic) {
|
|
565
|
+
auto* rctx = get_ctx(ctx);
|
|
566
|
+
auto* node = unwrap_node(ctx, this_val);
|
|
567
|
+
return get_handler_prop_for_node(ctx, rctx, node, kHandlerEventTypes[magic]);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
JSValue js_el_set_handler(JSContext* ctx, JSValue this_val, JSValue val, int magic) {
|
|
571
|
+
auto* rctx = get_ctx(ctx);
|
|
572
|
+
auto* node = unwrap_node(ctx, this_val);
|
|
573
|
+
return set_handler_prop_for_node(ctx, rctx, node, kHandlerEventTypes[magic], val);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
void* doc_node_of(RuntimeContext* rctx) {
|
|
577
|
+
if (!rctx || !rctx->document) return nullptr;
|
|
578
|
+
return lxb_dom_interface_node(lxb_dom_interface_document(
|
|
579
|
+
static_cast<lxb_html_document_t*>(rctx->document->documentHtmlPtr())));
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
JSValue js_doc_get_handler(JSContext* ctx, JSValue, int magic) {
|
|
583
|
+
auto* rctx = get_ctx(ctx);
|
|
584
|
+
return get_handler_prop_for_node(ctx, rctx, doc_node_of(rctx), kHandlerEventTypes[magic]);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
JSValue js_doc_set_handler(JSContext* ctx, JSValue, JSValue val, int magic) {
|
|
588
|
+
auto* rctx = get_ctx(ctx);
|
|
589
|
+
return set_handler_prop_for_node(ctx, rctx, doc_node_of(rctx), kHandlerEventTypes[magic], val);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
void define_element_handler(JSContext* ctx, JSValue obj, const char* name, int magic) {
|
|
593
|
+
JSAtom atom = JS_NewAtom(ctx, name);
|
|
594
|
+
JSValue get_fn = JS_NewCFunction2(ctx, (JSCFunction*)js_el_get_handler, name, 0, JS_CFUNC_getter_magic, magic);
|
|
595
|
+
JSValue set_fn = JS_NewCFunction2(ctx, (JSCFunction*)js_el_set_handler, name, 1, JS_CFUNC_setter_magic, magic);
|
|
596
|
+
JS_DefinePropertyGetSet(ctx, obj, atom, get_fn, set_fn, JS_PROP_CONFIGURABLE);
|
|
597
|
+
JS_FreeAtom(ctx, atom);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
void define_doc_handler(JSContext* ctx, JSValue obj, const char* name, int magic) {
|
|
601
|
+
JSAtom atom = JS_NewAtom(ctx, name);
|
|
602
|
+
JSValue get_fn = JS_NewCFunction2(ctx, (JSCFunction*)js_doc_get_handler, name, 0, JS_CFUNC_getter_magic, magic);
|
|
603
|
+
JSValue set_fn = JS_NewCFunction2(ctx, (JSCFunction*)js_doc_set_handler, name, 1, JS_CFUNC_setter_magic, magic);
|
|
604
|
+
JS_DefinePropertyGetSet(ctx, obj, atom, get_fn, set_fn, JS_PROP_CONFIGURABLE);
|
|
605
|
+
JS_FreeAtom(ctx, atom);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
JSValue make_simple_event(JSContext* ctx, const char* type, bool bubbles, bool cancelable) {
|
|
609
|
+
JSValue obj = JS_NewObjectClass(ctx, js_event_class_id);
|
|
610
|
+
JS_SetPropertyStr(ctx, obj, "type", JS_NewString(ctx, type));
|
|
611
|
+
JS_SetPropertyStr(ctx, obj, "bubbles", JS_NewBool(ctx, bubbles));
|
|
612
|
+
JS_SetPropertyStr(ctx, obj, "cancelable", JS_NewBool(ctx, cancelable));
|
|
613
|
+
JS_SetPropertyStr(ctx, obj, "defaultPrevented", JS_NewBool(ctx, false));
|
|
614
|
+
return obj;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
void fire_simple_event(JSContext* ctx, RuntimeContext* rctx, const char* type, bool bubbles, bool cancelable, lxb_dom_node_t* node) {
|
|
618
|
+
JSValue evt = make_simple_event(ctx, type, bubbles, cancelable);
|
|
619
|
+
JSValue r = dispatch_event_on_target(ctx, rctx, evt, node);
|
|
620
|
+
JS_FreeValue(ctx, evt);
|
|
621
|
+
if (JS_IsException(r)) JS_FreeValue(ctx, JS_GetException(ctx));
|
|
622
|
+
else JS_FreeValue(ctx, r);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
JSValue js_el_click(JSContext* ctx, JSValue this_val, int, JSValue*) {
|
|
626
|
+
auto* rctx = get_ctx(ctx);
|
|
627
|
+
auto* node = unwrap_node(ctx, this_val);
|
|
628
|
+
if (!rctx || !node) return JS_UNDEFINED;
|
|
629
|
+
fire_simple_event(ctx, rctx, "click", true, true, node);
|
|
630
|
+
return JS_UNDEFINED;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
JSValue js_el_focus(JSContext* ctx, JSValue this_val, int, JSValue*) {
|
|
634
|
+
auto* rctx = get_ctx(ctx);
|
|
635
|
+
auto* node = unwrap_node(ctx, this_val);
|
|
636
|
+
if (!rctx || !node || rctx->active_element == node) return JS_UNDEFINED;
|
|
637
|
+
|
|
638
|
+
void* previous = rctx->active_element;
|
|
639
|
+
rctx->active_element = node;
|
|
640
|
+
if (previous) fire_simple_event(ctx, rctx, "blur", false, false, static_cast<lxb_dom_node_t*>(previous));
|
|
641
|
+
fire_simple_event(ctx, rctx, "focus", false, false, node);
|
|
642
|
+
return JS_UNDEFINED;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
JSValue js_el_blur(JSContext* ctx, JSValue this_val, int, JSValue*) {
|
|
646
|
+
auto* rctx = get_ctx(ctx);
|
|
647
|
+
auto* node = unwrap_node(ctx, this_val);
|
|
648
|
+
if (!rctx || !node || rctx->active_element != node) return JS_UNDEFINED;
|
|
649
|
+
|
|
650
|
+
rctx->active_element = nullptr;
|
|
651
|
+
fire_simple_event(ctx, rctx, "blur", false, false, node);
|
|
652
|
+
return JS_UNDEFINED;
|
|
653
|
+
}
|
|
654
|
+
|
|
430
655
|
} // namespace
|
|
431
656
|
|
|
432
657
|
void EventBindings::install(JSContext* ctx) {
|
|
@@ -438,6 +663,7 @@ void EventBindings::install(JSContext* ctx) {
|
|
|
438
663
|
JS_SetPropertyStr(ctx, event_proto, "preventDefault", JS_NewCFunction(ctx, js_event_preventDefault, "preventDefault", 0));
|
|
439
664
|
JS_SetPropertyStr(ctx, event_proto, "stopPropagation", JS_NewCFunction(ctx, js_event_stopPropagation, "stopPropagation", 0));
|
|
440
665
|
JS_SetPropertyStr(ctx, event_proto, "stopImmediatePropagation", JS_NewCFunction(ctx, js_event_stopImmediatePropagation, "stopImmediatePropagation", 0));
|
|
666
|
+
JS_SetPropertyStr(ctx, event_proto, "composedPath", JS_NewCFunction(ctx, js_event_composedPath, "composedPath", 0));
|
|
441
667
|
JS_SetClassProto(ctx, js_event_class_id, event_proto);
|
|
442
668
|
|
|
443
669
|
// ── Event / CustomEvent constructors ───────────────────────────────────────
|
|
@@ -457,14 +683,32 @@ void EventBindings::install(JSContext* ctx) {
|
|
|
457
683
|
JS_SetPropertyStr(ctx, node_proto, "addEventListener", JS_NewCFunction(ctx, js_el_addEventListener, "addEventListener", 2));
|
|
458
684
|
JS_SetPropertyStr(ctx, node_proto, "removeEventListener", JS_NewCFunction(ctx, js_el_removeEventListener, "removeEventListener", 2));
|
|
459
685
|
JS_SetPropertyStr(ctx, node_proto, "dispatchEvent", JS_NewCFunction(ctx, js_el_dispatchEvent, "dispatchEvent", 1));
|
|
686
|
+
|
|
687
|
+
define_element_handler(ctx, node_proto, "onclick", 0);
|
|
688
|
+
define_element_handler(ctx, node_proto, "onload", 1);
|
|
689
|
+
define_element_handler(ctx, node_proto, "onerror", 2);
|
|
690
|
+
define_element_handler(ctx, node_proto, "onchange", 4);
|
|
691
|
+
define_element_handler(ctx, node_proto, "oninput", 5);
|
|
692
|
+
define_element_handler(ctx, node_proto, "onsubmit", 6);
|
|
693
|
+
define_element_handler(ctx, node_proto, "onreset", 7);
|
|
460
694
|
JS_FreeValue(ctx, node_proto);
|
|
461
695
|
|
|
696
|
+
JSValue element_proto = JS_GetClassProto(ctx, js_element_class_id);
|
|
697
|
+
JS_SetPropertyStr(ctx, element_proto, "click", JS_NewCFunction(ctx, js_el_click, "click", 0));
|
|
698
|
+
JS_SetPropertyStr(ctx, element_proto, "focus", JS_NewCFunction(ctx, js_el_focus, "focus", 0));
|
|
699
|
+
JS_SetPropertyStr(ctx, element_proto, "blur", JS_NewCFunction(ctx, js_el_blur, "blur", 0));
|
|
700
|
+
JS_FreeValue(ctx, element_proto);
|
|
701
|
+
|
|
462
702
|
// ── addEventListener/removeEventListener/dispatchEvent on document ────────
|
|
463
703
|
// DocumentBindings::install() must have already run so globalThis.document exists.
|
|
464
704
|
JSValue doc = JS_GetPropertyStr(ctx, global, "document");
|
|
465
705
|
JS_SetPropertyStr(ctx, doc, "addEventListener", JS_NewCFunction(ctx, js_doc_addEventListener, "addEventListener", 2));
|
|
466
706
|
JS_SetPropertyStr(ctx, doc, "removeEventListener", JS_NewCFunction(ctx, js_doc_removeEventListener, "removeEventListener", 2));
|
|
467
707
|
JS_SetPropertyStr(ctx, doc, "dispatchEvent", JS_NewCFunction(ctx, js_doc_dispatchEvent, "dispatchEvent", 1));
|
|
708
|
+
|
|
709
|
+
define_doc_handler(ctx, doc, "onclick", 0);
|
|
710
|
+
define_doc_handler(ctx, doc, "onload", 1);
|
|
711
|
+
define_doc_handler(ctx, doc, "onerror", 2);
|
|
468
712
|
JS_FreeValue(ctx, doc);
|
|
469
713
|
|
|
470
714
|
// ── addEventListener/removeEventListener/dispatchEvent on window ──────────
|
|
@@ -480,7 +724,39 @@ void EventBindings::install(JSContext* ctx) {
|
|
|
480
724
|
JS_SetPropertyStr(ctx, global, "removeEventListener", JS_NewCFunction(ctx, js_doc_removeEventListener, "removeEventListener", 2));
|
|
481
725
|
JS_SetPropertyStr(ctx, global, "dispatchEvent", JS_NewCFunction(ctx, js_doc_dispatchEvent, "dispatchEvent", 1));
|
|
482
726
|
|
|
727
|
+
define_doc_handler(ctx, global, "onclick", 0);
|
|
728
|
+
define_doc_handler(ctx, global, "onload", 1);
|
|
729
|
+
define_doc_handler(ctx, global, "onerror", 2);
|
|
730
|
+
define_doc_handler(ctx, global, "onunhandledrejection", 3);
|
|
731
|
+
|
|
483
732
|
JS_FreeValue(ctx, global);
|
|
484
733
|
}
|
|
485
734
|
|
|
735
|
+
void EventBindings::dispatchErrorEvent(JSContext* ctx, const std::string& message, JSValue error_value) {
|
|
736
|
+
auto* rctx = get_ctx(ctx);
|
|
737
|
+
void* node = doc_node_of(rctx);
|
|
738
|
+
if (!rctx || !node) return;
|
|
739
|
+
|
|
740
|
+
JSValue evt = make_simple_event(ctx, "error", false, true);
|
|
741
|
+
JS_SetPropertyStr(ctx, evt, "message", JS_NewStringLen(ctx, message.data(), message.size()));
|
|
742
|
+
JS_SetPropertyStr(ctx, evt, "error", JS_DupValue(ctx, error_value));
|
|
743
|
+
JSValue r = dispatch_event_on_target(ctx, rctx, evt, static_cast<lxb_dom_node_t*>(node));
|
|
744
|
+
JS_FreeValue(ctx, evt);
|
|
745
|
+
if (JS_IsException(r)) JS_FreeValue(ctx, JS_GetException(ctx));
|
|
746
|
+
else JS_FreeValue(ctx, r);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
void EventBindings::dispatchUnhandledRejectionEvent(JSContext* ctx, JSValue reason) {
|
|
750
|
+
auto* rctx = get_ctx(ctx);
|
|
751
|
+
void* node = doc_node_of(rctx);
|
|
752
|
+
if (!rctx || !node) return;
|
|
753
|
+
|
|
754
|
+
JSValue evt = make_simple_event(ctx, "unhandledrejection", false, true);
|
|
755
|
+
JS_SetPropertyStr(ctx, evt, "reason", JS_DupValue(ctx, reason));
|
|
756
|
+
JSValue r = dispatch_event_on_target(ctx, rctx, evt, static_cast<lxb_dom_node_t*>(node));
|
|
757
|
+
JS_FreeValue(ctx, evt);
|
|
758
|
+
if (JS_IsException(r)) JS_FreeValue(ctx, JS_GetException(ctx));
|
|
759
|
+
else JS_FreeValue(ctx, r);
|
|
760
|
+
}
|
|
761
|
+
|
|
486
762
|
} // namespace margelo::nitro::nitrojsdom
|
|
@@ -10,12 +10,15 @@
|
|
|
10
10
|
// attach addEventListener/dispatchEvent there too).
|
|
11
11
|
|
|
12
12
|
#include "quickjs.h"
|
|
13
|
+
#include <string>
|
|
13
14
|
|
|
14
15
|
namespace margelo::nitro::nitrojsdom {
|
|
15
16
|
|
|
16
17
|
class EventBindings {
|
|
17
18
|
public:
|
|
18
19
|
static void install(JSContext* ctx);
|
|
20
|
+
static void dispatchErrorEvent(JSContext* ctx, const std::string& message, JSValue error_value);
|
|
21
|
+
static void dispatchUnhandledRejectionEvent(JSContext* ctx, JSValue reason);
|
|
19
22
|
};
|
|
20
23
|
|
|
21
24
|
} // namespace margelo::nitro::nitrojsdom
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#include "EventTargetBindings.hpp"
|
|
2
|
+
#include <cstring>
|
|
3
|
+
|
|
4
|
+
namespace margelo::nitro::nitrojsdom {
|
|
5
|
+
|
|
6
|
+
namespace {
|
|
7
|
+
|
|
8
|
+
const char* kEventTargetBootstrapScript = R"JS(
|
|
9
|
+
(function() {
|
|
10
|
+
function EventTarget() {
|
|
11
|
+
this._listeners = Object.create(null);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
EventTarget.prototype.addEventListener = function(type, listener, options) {
|
|
15
|
+
if (typeof listener !== 'function' && !(listener && typeof listener.handleEvent === 'function')) return;
|
|
16
|
+
type = String(type);
|
|
17
|
+
var capture = !!(options === true || (options && options.capture));
|
|
18
|
+
var once = !!(options && options.once);
|
|
19
|
+
var list = this._listeners[type] || (this._listeners[type] = []);
|
|
20
|
+
for (var i = 0; i < list.length; i++) {
|
|
21
|
+
if (list[i].listener === listener && list[i].capture === capture) return;
|
|
22
|
+
}
|
|
23
|
+
list.push({ listener: listener, capture: capture, once: once });
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
EventTarget.prototype.removeEventListener = function(type, listener, options) {
|
|
27
|
+
var list = this._listeners[String(type)];
|
|
28
|
+
if (!list) return;
|
|
29
|
+
var capture = !!(options === true || (options && options.capture));
|
|
30
|
+
for (var i = 0; i < list.length; i++) {
|
|
31
|
+
if (list[i].listener === listener && list[i].capture === capture) { list.splice(i, 1); return; }
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
EventTarget.prototype.dispatchEvent = function(event) {
|
|
36
|
+
var list = this._listeners[event.type];
|
|
37
|
+
Object.defineProperty(event, 'target', { value: this, configurable: true });
|
|
38
|
+
Object.defineProperty(event, 'currentTarget', { value: this, configurable: true });
|
|
39
|
+
try {
|
|
40
|
+
if (list) {
|
|
41
|
+
var snapshot = list.slice();
|
|
42
|
+
for (var i = 0; i < snapshot.length; i++) {
|
|
43
|
+
var entry = snapshot[i];
|
|
44
|
+
if (list.indexOf(entry) === -1) continue;
|
|
45
|
+
if (entry.once) {
|
|
46
|
+
var idx = list.indexOf(entry);
|
|
47
|
+
if (idx !== -1) list.splice(idx, 1);
|
|
48
|
+
}
|
|
49
|
+
if (typeof entry.listener === 'function') entry.listener.call(this, event);
|
|
50
|
+
else entry.listener.handleEvent(event);
|
|
51
|
+
if (event.__immediatePropagationStopped) break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
} finally {
|
|
55
|
+
Object.defineProperty(event, 'currentTarget', { value: null, configurable: true });
|
|
56
|
+
}
|
|
57
|
+
return !event.defaultPrevented;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
globalThis.EventTarget = EventTarget;
|
|
61
|
+
})();
|
|
62
|
+
)JS";
|
|
63
|
+
|
|
64
|
+
} // namespace
|
|
65
|
+
|
|
66
|
+
void EventTargetBindings::install(JSContext* ctx) {
|
|
67
|
+
JSValue result = JS_Eval(ctx, kEventTargetBootstrapScript, strlen(kEventTargetBootstrapScript),
|
|
68
|
+
"<event-target-bootstrap>", JS_EVAL_TYPE_GLOBAL);
|
|
69
|
+
if (JS_IsException(result)) {
|
|
70
|
+
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
71
|
+
}
|
|
72
|
+
JS_FreeValue(ctx, result);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
} // namespace margelo::nitro::nitrojsdom
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// globalThis.EventTarget — a standalone, constructible EventTarget for
|
|
4
|
+
// scripts that want addEventListener/removeEventListener/dispatchEvent
|
|
5
|
+
// pub-sub semantics without extending an Element/document/window (which
|
|
6
|
+
// already have their own dispatch paths — see EventBindings). Pure JS: its
|
|
7
|
+
// own per-instance listener map, no bubbling (a bare EventTarget has no
|
|
8
|
+
// ancestors to bubble through), reusing the Event/CustomEvent classes
|
|
9
|
+
// EventBindings already installs.
|
|
10
|
+
//
|
|
11
|
+
// Must run after EventBindings (globalThis.Event, DOMException already
|
|
12
|
+
// available for the "listener not a function" TypeError path — actually
|
|
13
|
+
// mirrors native EventTarget, which silently ignores a non-callable
|
|
14
|
+
// listener rather than throwing).
|
|
15
|
+
|
|
16
|
+
#include "quickjs.h"
|
|
17
|
+
|
|
18
|
+
namespace margelo::nitro::nitrojsdom {
|
|
19
|
+
|
|
20
|
+
struct EventTargetBindings {
|
|
21
|
+
static void install(JSContext* ctx);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
} // namespace margelo::nitro::nitrojsdom
|
|
@@ -118,7 +118,7 @@ const char* kFetchBootstrapScript = R"JS(
|
|
|
118
118
|
this.status = init.status !== undefined ? init.status : 200;
|
|
119
119
|
this.statusText = init.statusText !== undefined ? init.statusText : '';
|
|
120
120
|
this.ok = this.status >= 200 && this.status < 300;
|
|
121
|
-
this.headers =
|
|
121
|
+
this.headers = new Headers(init.headers);
|
|
122
122
|
this.bodyUsed = false;
|
|
123
123
|
}
|
|
124
124
|
Response.prototype.text = function() {
|
|
@@ -138,19 +138,54 @@ const char* kFetchBootstrapScript = R"JS(
|
|
|
138
138
|
};
|
|
139
139
|
globalThis.Response = Response;
|
|
140
140
|
|
|
141
|
+
function Request(input, init) {
|
|
142
|
+
init = init || {};
|
|
143
|
+
var fromRequest = input instanceof Request;
|
|
144
|
+
if (fromRequest && input.bodyUsed) {
|
|
145
|
+
throw new TypeError('Cannot construct a Request with a Request object that has already been used.');
|
|
146
|
+
}
|
|
147
|
+
this.url = fromRequest ? input.url : String(input);
|
|
148
|
+
this.method = (init.method || (fromRequest ? input.method : 'GET')).toUpperCase();
|
|
149
|
+
this.headers = new Headers(init.headers || (fromRequest ? input.headers : undefined));
|
|
150
|
+
var initBody = (init.body === undefined) ? (fromRequest ? input._body : undefined) : init.body;
|
|
151
|
+
this._body = (initBody === undefined || initBody === null) ? undefined : initBody;
|
|
152
|
+
this.signal = init.signal || (fromRequest ? input.signal : undefined);
|
|
153
|
+
this.bodyUsed = false;
|
|
154
|
+
if (fromRequest) input.bodyUsed = true;
|
|
155
|
+
}
|
|
156
|
+
Request.prototype.text = function() {
|
|
157
|
+
if (this.bodyUsed) return Promise.reject(new TypeError('Body has already been consumed.'));
|
|
158
|
+
this.bodyUsed = true;
|
|
159
|
+
return Promise.resolve(this._body === undefined ? '' : String(this._body));
|
|
160
|
+
};
|
|
161
|
+
Request.prototype.json = function() {
|
|
162
|
+
if (this.bodyUsed) return Promise.reject(new TypeError('Body has already been consumed.'));
|
|
163
|
+
this.bodyUsed = true;
|
|
164
|
+
try {
|
|
165
|
+
return Promise.resolve(JSON.parse(this._body));
|
|
166
|
+
} catch (e) {
|
|
167
|
+
return Promise.reject(e);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
Request.prototype.clone = function() {
|
|
171
|
+
if (this.bodyUsed) throw new TypeError('Failed to execute clone: body is already used.');
|
|
172
|
+
return new Request(this.url, { method: this.method, headers: this.headers, body: this._body, signal: this.signal });
|
|
173
|
+
};
|
|
174
|
+
globalThis.Request = Request;
|
|
175
|
+
|
|
141
176
|
globalThis.fetch = function(input, init) {
|
|
142
177
|
return new Promise(function(resolve, reject) {
|
|
143
178
|
try {
|
|
144
|
-
|
|
145
|
-
if (
|
|
146
|
-
reject(
|
|
179
|
+
var req = new Request(input, init);
|
|
180
|
+
if (req.signal && req.signal.aborted) {
|
|
181
|
+
reject(req.signal.reason !== undefined ? req.signal.reason : new Error('The operation was aborted'));
|
|
147
182
|
return;
|
|
148
183
|
}
|
|
149
|
-
var url =
|
|
150
|
-
var method =
|
|
151
|
-
var headers = normalizeHeaders(
|
|
184
|
+
var url = req.url;
|
|
185
|
+
var method = req.method;
|
|
186
|
+
var headers = normalizeHeaders(req.headers);
|
|
152
187
|
var headersJson = JSON.stringify(headers);
|
|
153
|
-
var body =
|
|
188
|
+
var body = req._body === undefined ? undefined : String(req._body);
|
|
154
189
|
|
|
155
190
|
var raw = __nativeFetchSync(url, method, headersJson, body);
|
|
156
191
|
if (raw.error) {
|