xbintsc 0.3.25 → 0.3.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +33 -0
  2. package/dist/src/cli/main.js +124 -30
  3. package/dist/src/cli/main.js.map +1 -1
  4. package/dist/src/codegen/generator/calls/access.js +8 -1
  5. package/dist/src/codegen/generator/calls/access.js.map +1 -1
  6. package/dist/src/codegen/generator/state.js +20 -0
  7. package/dist/src/codegen/generator/state.js.map +1 -1
  8. package/dist/src/codegen/generator/tables.d.ts +6 -0
  9. package/dist/src/codegen/generator/tables.js +38 -0
  10. package/dist/src/codegen/generator/tables.js.map +1 -1
  11. package/dist/src/driver/bundler/commonjs.d.ts +52 -0
  12. package/dist/src/driver/bundler/commonjs.js +493 -0
  13. package/dist/src/driver/bundler/commonjs.js.map +1 -0
  14. package/dist/src/driver/bundler/graph.js +14 -0
  15. package/dist/src/driver/bundler/graph.js.map +1 -1
  16. package/dist/src/driver/bundler/merge.js +14 -0
  17. package/dist/src/driver/bundler/merge.js.map +1 -1
  18. package/dist/src/driver/bundler/types.d.ts +8 -0
  19. package/dist/src/driver/compiler.d.ts +8 -1
  20. package/dist/src/driver/compiler.js +73 -5
  21. package/dist/src/driver/compiler.js.map +1 -1
  22. package/dist/src/driver/config.d.ts +53 -0
  23. package/dist/src/driver/config.js +141 -0
  24. package/dist/src/driver/config.js.map +1 -0
  25. package/dist/src/driver/icon.d.ts +62 -0
  26. package/dist/src/driver/icon.js +151 -0
  27. package/dist/src/driver/icon.js.map +1 -0
  28. package/dist/src/driver/index.d.ts +4 -0
  29. package/dist/src/driver/index.js +4 -0
  30. package/dist/src/driver/index.js.map +1 -1
  31. package/dist/src/driver/mac-bundle.d.ts +41 -0
  32. package/dist/src/driver/mac-bundle.js +123 -0
  33. package/dist/src/driver/mac-bundle.js.map +1 -0
  34. package/dist/src/driver/win-icon.d.ts +27 -0
  35. package/dist/src/driver/win-icon.js +80 -0
  36. package/dist/src/driver/win-icon.js.map +1 -0
  37. package/dist/src/parser/statements.js +17 -4
  38. package/dist/src/parser/statements.js.map +1 -1
  39. package/dist/tests/cli/main.test.js +46 -1
  40. package/dist/tests/cli/main.test.js.map +1 -1
  41. package/dist/tests/driver/config.test.d.ts +1 -0
  42. package/dist/tests/driver/config.test.js +124 -0
  43. package/dist/tests/driver/config.test.js.map +1 -0
  44. package/dist/tests/driver/icon.test.d.ts +1 -0
  45. package/dist/tests/driver/icon.test.js +421 -0
  46. package/dist/tests/driver/icon.test.js.map +1 -0
  47. package/dist/tests/driver/modules.test.js +109 -0
  48. package/dist/tests/driver/modules.test.js.map +1 -1
  49. package/dist/tests/e2e/fetch.test.d.ts +12 -0
  50. package/dist/tests/e2e/fetch.test.js +272 -0
  51. package/dist/tests/e2e/fetch.test.js.map +1 -0
  52. package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
  53. package/dist/tests/e2e/gui-dom.test.js +102 -0
  54. package/dist/tests/e2e/gui-dom.test.js.map +1 -0
  55. package/dist/tests/e2e/gui-events.test.d.ts +5 -0
  56. package/dist/tests/e2e/gui-events.test.js +60 -0
  57. package/dist/tests/e2e/gui-events.test.js.map +1 -0
  58. package/dist/tests/e2e/gui-helpers.d.ts +31 -0
  59. package/dist/tests/e2e/gui-helpers.js +74 -0
  60. package/dist/tests/e2e/gui-helpers.js.map +1 -0
  61. package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
  62. package/dist/tests/e2e/gui-layout.test.js +88 -0
  63. package/dist/tests/e2e/gui-layout.test.js.map +1 -0
  64. package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
  65. package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
  66. package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
  67. package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
  68. package/dist/tests/e2e/gui-paint.test.js +111 -0
  69. package/dist/tests/e2e/gui-paint.test.js.map +1 -0
  70. package/dist/tests/e2e/gui-script.test.d.ts +5 -0
  71. package/dist/tests/e2e/gui-script.test.js +78 -0
  72. package/dist/tests/e2e/gui-script.test.js.map +1 -0
  73. package/dist/tests/e2e/gui-style.test.d.ts +5 -0
  74. package/dist/tests/e2e/gui-style.test.js +175 -0
  75. package/dist/tests/e2e/gui-style.test.js.map +1 -0
  76. package/dist/tests/e2e/icon.test.d.ts +7 -0
  77. package/dist/tests/e2e/icon.test.js +80 -0
  78. package/dist/tests/e2e/icon.test.js.map +1 -0
  79. package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
  80. package/dist/tests/e2e/npm-modules.test.js +47 -1
  81. package/dist/tests/e2e/npm-modules.test.js.map +1 -1
  82. package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
  83. package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
  84. package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
  85. package/dist/tests/parser/statements.test.js +11 -0
  86. package/dist/tests/parser/statements.test.js.map +1 -1
  87. package/package.json +1 -1
  88. package/runtime/ext_gui/css.cpp +4 -517
  89. package/runtime/ext_gui/css_internal.h +27 -0
  90. package/runtime/ext_gui/css_match.cpp +195 -0
  91. package/runtime/ext_gui/css_selector.cpp +207 -0
  92. package/runtime/ext_gui/css_sheet.cpp +129 -0
  93. package/runtime/ext_gui/dom.cpp +7 -403
  94. package/runtime/ext_gui/dom_api.cpp +63 -1146
  95. package/runtime/ext_gui/dom_api_document.cpp +96 -0
  96. package/runtime/ext_gui/dom_api_events.cpp +123 -0
  97. package/runtime/ext_gui/dom_api_internal.h +135 -0
  98. package/runtime/ext_gui/dom_api_node.cpp +329 -0
  99. package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
  100. package/runtime/ext_gui/dom_api_proto.cpp +130 -0
  101. package/runtime/ext_gui/dom_api_style.cpp +192 -0
  102. package/runtime/ext_gui/dom_internal.h +39 -0
  103. package/runtime/ext_gui/dom_parse.cpp +348 -0
  104. package/runtime/ext_gui/dom_serialize.cpp +54 -0
  105. package/runtime/ext_gui/gui.cpp +56 -286
  106. package/runtime/ext_gui/gui_events.cpp +294 -0
  107. package/runtime/ext_gui/gui_internal.h +29 -0
  108. package/runtime/ext_gui/layout.cpp +6 -597
  109. package/runtime/ext_gui/layout_flex.cpp +200 -0
  110. package/runtime/ext_gui/layout_flow.cpp +191 -0
  111. package/runtime/ext_gui/layout_flow_internal.h +149 -0
  112. package/runtime/ext_gui/layout_inline.cpp +181 -0
  113. package/runtime/ext_gui/layout_internal.h +20 -0
  114. package/runtime/ext_gui/renderer.cpp +15 -679
  115. package/runtime/ext_gui/renderer_image.cpp +233 -0
  116. package/runtime/ext_gui/renderer_internal.h +112 -0
  117. package/runtime/ext_gui/renderer_shaders.h +108 -0
  118. package/runtime/ext_gui/renderer_text.cpp +342 -0
  119. package/runtime/ext_gui/style.cpp +12 -660
  120. package/runtime/ext_gui/style_internal.h +33 -0
  121. package/runtime/ext_gui/style_print.cpp +113 -0
  122. package/runtime/ext_gui/style_ua.cpp +98 -0
  123. package/runtime/ext_gui/style_values.cpp +468 -0
  124. package/runtime/rt.h +6 -0
  125. package/runtime/rt_internal.h +4 -0
  126. package/runtime/xt_builtins.c +1 -0
  127. package/runtime/xt_containers/access.inc +32 -1
  128. package/runtime/xt_fetch/buffer.inc +64 -0
  129. package/runtime/xt_fetch/headers.inc +312 -0
  130. package/runtime/xt_fetch/request.inc +386 -0
  131. package/runtime/xt_fetch/response.inc +107 -0
  132. package/runtime/xt_fetch/socket.inc +72 -0
  133. package/runtime/xt_fetch/url.inc +108 -0
  134. package/runtime/xt_fetch.c +39 -0
  135. package/runtime/xt_stdlib2/set.inc +1 -1
  136. package/runtime/xt_typed_array.c +614 -0
  137. package/src/cli/main.ts +137 -29
  138. package/src/codegen/generator/calls/access.ts +9 -1
  139. package/src/codegen/generator/state.ts +20 -0
  140. package/src/codegen/generator/tables.ts +40 -0
  141. package/src/driver/bundler/commonjs.ts +553 -0
  142. package/src/driver/bundler/graph.ts +14 -0
  143. package/src/driver/bundler/merge.ts +15 -0
  144. package/src/driver/bundler/types.ts +8 -0
  145. package/src/driver/compiler.ts +83 -5
  146. package/src/driver/config.ts +173 -0
  147. package/src/driver/icon.ts +184 -0
  148. package/src/driver/index.ts +30 -0
  149. package/src/driver/mac-bundle.ts +156 -0
  150. package/src/driver/win-icon.ts +96 -0
  151. package/src/parser/statements.ts +17 -4
  152. package/dist/tests/e2e/gui.test.d.ts +0 -12
  153. package/dist/tests/e2e/gui.test.js +0 -702
  154. package/dist/tests/e2e/gui.test.js.map +0 -1
@@ -0,0 +1,96 @@
1
+ /*
2
+ * xbintsc GUI engine — `document` node methods (queries + element creation).
3
+ */
4
+
5
+ #include "dom_api_internal.h"
6
+
7
+ #include <cctype>
8
+ #include <string>
9
+ #include <vector>
10
+
11
+ namespace domapi {
12
+
13
+ static const xtgui::Node *find_by_tag(const xtgui::Node *node, const std::string &tag) {
14
+ if (node->isElement() && node->tag == tag) return node;
15
+ for (const std::unique_ptr<xtgui::Node> &child : node->children) {
16
+ if (const xtgui::Node *found = find_by_tag(child.get(), tag)) return found;
17
+ }
18
+ return nullptr;
19
+ }
20
+
21
+ static const xtgui::Node *find_by_id(const xtgui::Node *node, const std::string &id) {
22
+ if (node->isElement()) {
23
+ const std::string *value = node->attr("id");
24
+ if (value != nullptr && *value == id) return node;
25
+ }
26
+ for (const std::unique_ptr<xtgui::Node> &child : node->children) {
27
+ if (const xtgui::Node *found = find_by_id(child.get(), id)) return found;
28
+ }
29
+ return nullptr;
30
+ }
31
+
32
+ #define METHOD(name) xt_value name(xt_value self, xt_value env, int32_t argc, xt_value *argv)
33
+
34
+ METHOD(doc_query_selector) {
35
+ (void)env;
36
+ XtGuiWindow *win = resolve_window(self);
37
+ if (win == nullptr || win->document == nullptr || argc < 1) return XT_UNDEFINED;
38
+ return xt_gui_node_handle(win, win->document->querySelector(to_string_value(xt_arg(argc, argv, 0))));
39
+ }
40
+
41
+ METHOD(doc_query_selector_all) {
42
+ (void)env;
43
+ XtGuiWindow *win = resolve_window(self);
44
+ if (win == nullptr || win->document == nullptr || argc < 1) return xt_array_new(0, NULL);
45
+ std::vector<const xtgui::Node *> matches =
46
+ win->document->querySelectorAll(to_string_value(xt_arg(argc, argv, 0)));
47
+ xt_value array = xt_array_new(0, NULL);
48
+ for (const xtgui::Node *node : matches) xt_array_push(array, xt_gui_node_handle(win, node));
49
+ return array;
50
+ }
51
+
52
+ METHOD(doc_get_element_by_id) {
53
+ (void)env;
54
+ XtGuiWindow *win = resolve_window(self);
55
+ if (win == nullptr || win->document == nullptr || argc < 1) return XT_UNDEFINED;
56
+ return xt_gui_node_handle(
57
+ win, find_by_id(win->document->root(), to_string_value(xt_arg(argc, argv, 0))));
58
+ }
59
+
60
+ METHOD(doc_create_element) {
61
+ (void)env;
62
+ XtGuiWindow *win = resolve_window(self);
63
+ if (win == nullptr || win->document == nullptr || argc < 1) return XT_UNDEFINED;
64
+ std::string tag = to_string_value(xt_arg(argc, argv, 0));
65
+ for (char &c : tag) c = (char)std::tolower((unsigned char)c);
66
+ return xt_gui_node_handle(win, win->document->createElement(tag));
67
+ }
68
+
69
+ METHOD(doc_create_text_node) {
70
+ (void)env;
71
+ XtGuiWindow *win = resolve_window(self);
72
+ if (win == nullptr || win->document == nullptr || argc < 1) return XT_UNDEFINED;
73
+ return xt_gui_node_handle(win, win->document->createTextNode(to_string_value(xt_arg(argc, argv, 0))));
74
+ }
75
+
76
+ METHOD(doc_body_get) {
77
+ (void)env;
78
+ (void)argc;
79
+ (void)argv;
80
+ XtGuiWindow *win = resolve_window(self);
81
+ if (win == nullptr || win->document == nullptr) return XT_UNDEFINED;
82
+ return xt_gui_node_handle(win, find_by_tag(win->document->root(), "body"));
83
+ }
84
+
85
+ METHOD(doc_document_element_get) {
86
+ (void)env;
87
+ (void)argc;
88
+ (void)argv;
89
+ XtGuiWindow *win = resolve_window(self);
90
+ if (win == nullptr || win->document == nullptr) return XT_UNDEFINED;
91
+ return xt_gui_node_handle(win, find_by_tag(win->document->root(), "html"));
92
+ }
93
+
94
+ #undef METHOD
95
+
96
+ } // namespace domapi
@@ -0,0 +1,123 @@
1
+ /*
2
+ * xbintsc GUI engine — DOM event machinery (dispatch, listeners, propagation)
3
+ * and the `Event` prototype methods.
4
+ */
5
+
6
+ #include "dom_api_internal.h"
7
+
8
+ #include <string>
9
+ #include <vector>
10
+
11
+ namespace domapi {
12
+
13
+ static xt_value make_dom_event(XtGuiWindow *win, const char *type, const xtgui::Node *target,
14
+ xt_value legacy) {
15
+ xt_value event = xt_object_new_with_proto(event_proto());
16
+ xt_object_set(event, xt_string_from_cstr("type"), xt_string_from_cstr(type));
17
+ xt_object_set(event, xt_string_from_cstr("target"), xt_gui_node_handle(win, target));
18
+ xt_object_set(event, xt_string_from_cstr("defaultPrevented"), XT_FALSE);
19
+ xt_object_set(event, xt_string_from_cstr("bubbles"), XT_TRUE);
20
+ if (XT_IS_OBJECT(legacy)) {
21
+ static const char *const fields[] = {
22
+ "x", "y", "clientX", "clientY", "button", "clicks",
23
+ "deltaX", "deltaY", "key", "code", "repeat", "ctrl",
24
+ "shift", "alt", "meta",
25
+ };
26
+ for (const char *field : fields) {
27
+ xt_value value = xt_object_get_cstr(legacy, field);
28
+ if (!XT_IS_UNDEFINED(value)) xt_object_set(event, xt_string_from_cstr(field), value);
29
+ }
30
+ }
31
+ return event;
32
+ }
33
+
34
+ void remove_listener(XtGuiWindow *win, xtgui::Node *node, const std::string &type, xt_value fn,
35
+ bool capture) {
36
+ auto found = win->node_listeners.find(node);
37
+ if (found == win->node_listeners.end()) return;
38
+ std::vector<XtGuiNodeListener> &list = found->second;
39
+ for (auto it = list.begin(); it != list.end(); ++it) {
40
+ if (it->type == type && it->capture == capture && xt_truthy(xt_seq(it->fn, fn))) {
41
+ list.erase(it);
42
+ return;
43
+ }
44
+ }
45
+ }
46
+
47
+ static bool call_node_listeners(XtGuiWindow *win, xtgui::Node *node, const char *type,
48
+ xt_value event, bool capture) {
49
+ auto found = win->node_listeners.find(node);
50
+ if (found == win->node_listeners.end()) return false;
51
+ std::vector<XtGuiNodeListener> snapshot = found->second;
52
+ for (const XtGuiNodeListener &listener : snapshot) {
53
+ if (listener.type != type || listener.capture != capture) continue;
54
+ if (listener.once) remove_listener(win, node, listener.type, listener.fn, listener.capture);
55
+ xt_value self = xt_gui_node_handle(win, node);
56
+ xt_object_set(event, xt_string_from_cstr("currentTarget"), self);
57
+ xt_value args[1] = {event};
58
+ xt_call_with_this(listener.fn, self, 1, args);
59
+ if (value_truthy(xt_object_get_cstr(event, "__stopImmediate"))) return true;
60
+ if (value_truthy(xt_object_get_cstr(event, "__stop"))) return true;
61
+ }
62
+ return value_truthy(xt_object_get_cstr(event, "__stop"));
63
+ }
64
+
65
+ #define METHOD(name) xt_value name(xt_value self, xt_value env, int32_t argc, xt_value *argv)
66
+
67
+ METHOD(event_prevent_default) {
68
+ (void)env;
69
+ (void)argc;
70
+ (void)argv;
71
+ xt_object_set(self, xt_string_from_cstr("defaultPrevented"), XT_TRUE);
72
+ return XT_UNDEFINED;
73
+ }
74
+
75
+ METHOD(event_stop_propagation) {
76
+ (void)env;
77
+ (void)argc;
78
+ (void)argv;
79
+ xt_object_set(self, xt_string_from_cstr("__stop"), XT_TRUE);
80
+ return XT_UNDEFINED;
81
+ }
82
+
83
+ METHOD(event_stop_immediate_propagation) {
84
+ (void)env;
85
+ (void)argc;
86
+ (void)argv;
87
+ xt_object_set(self, xt_string_from_cstr("__stop"), XT_TRUE);
88
+ xt_object_set(self, xt_string_from_cstr("__stopImmediate"), XT_TRUE);
89
+ return XT_UNDEFINED;
90
+ }
91
+
92
+ #undef METHOD
93
+
94
+ } // namespace domapi
95
+
96
+ void xt_gui_emit_dom_event(XtGuiWindow *win, const char *type, const xtgui::Node *target,
97
+ xt_value legacy) {
98
+ using namespace domapi;
99
+ if (win == nullptr || win->document == nullptr || target == nullptr) return;
100
+ if (win->node_listeners.empty()) return;
101
+ std::vector<xtgui::Node *> path;
102
+ for (xtgui::Node *node = const_cast<xtgui::Node *>(target); node != nullptr; node = node->parent) {
103
+ path.push_back(node);
104
+ }
105
+ xt_value event = make_dom_event(win, type, target, legacy);
106
+ /* Capture phase: root -> target. */
107
+ for (auto it = path.rbegin(); it != path.rend(); ++it) {
108
+ if (call_node_listeners(win, *it, type, event, true)) return;
109
+ }
110
+ /* Bubble phase: target -> root. */
111
+ for (auto it = path.begin(); it != path.end(); ++it) {
112
+ if (call_node_listeners(win, *it, type, event, false)) return;
113
+ }
114
+ }
115
+
116
+ void xt_gui_dispatch_to_node(XtGuiWindow *win, const xtgui::Node *target, const char *type) {
117
+ if (win == nullptr || target == nullptr) return;
118
+ xt_value legacy = xt_object_new();
119
+ xt_object_set(legacy, xt_string_from_cstr("type"), xt_string_from_cstr(type));
120
+ std::string describe = xtgui::xt_dom_describe(target);
121
+ xt_object_set(legacy, xt_string_from_cstr("target"), xt_string_from_cstr(describe.c_str()));
122
+ xt_gui_emit_dom_event(win, type, target, legacy);
123
+ }
@@ -0,0 +1,135 @@
1
+ /*
2
+ * xbintsc GUI engine — shared declarations for the DOM object model
3
+ * translation units (`dom_api.cpp`, `dom_api_events.cpp`,
4
+ * `dom_api_document.cpp`, `dom_api_node.cpp`, `dom_api_node_read.cpp`,
5
+ * `dom_api_style.cpp`, `dom_api_proto.cpp`).
6
+ *
7
+ * The prototypes and the helpers that more than one unit needs live in
8
+ * `xtgui`-adjacent namespace `domapi` so the three public entry points
9
+ * (`xt_gui_node_handle` and friends, declared in `gui_engine.h`) can stay at
10
+ * global scope.
11
+ */
12
+ #ifndef XT_GUI_DOM_API_INTERNAL_H
13
+ #define XT_GUI_DOM_API_INTERNAL_H
14
+
15
+ #include <cstdint>
16
+ #include <string>
17
+ #include <vector>
18
+
19
+ #include "gui_engine.h"
20
+
21
+ namespace domapi {
22
+
23
+ /* -- prototypes ----------------------------------------------------------- */
24
+
25
+ extern xt_value g_node_proto;
26
+ extern xt_value g_document_proto;
27
+ extern xt_value g_event_proto;
28
+ extern xt_value g_class_list_proto;
29
+ extern xt_value g_style_proto;
30
+
31
+ xt_value node_proto();
32
+ xt_value document_proto();
33
+ xt_value event_proto();
34
+ xt_value class_list_proto();
35
+ xt_value style_proto();
36
+
37
+ /* -- cross-unit helpers --------------------------------------------------- */
38
+
39
+ std::string to_string_value(xt_value value);
40
+ bool value_truthy(xt_value value);
41
+ XtGuiWindow *resolve_window(xt_value self);
42
+ xtgui::Node *resolve_node(xt_value self, XtGuiWindow **winOut);
43
+ void mark_dirty(XtGuiWindow *win);
44
+ void set_attribute_raw(xtgui::Node *node, const std::string &name, const std::string &value);
45
+ void remove_attribute_raw(xtgui::Node *node, const std::string &name);
46
+ void set_attribute(XtGuiWindow *win, xtgui::Node *node, const std::string &name,
47
+ const std::string &value);
48
+ std::string class_name_of(const xtgui::Node *node);
49
+ void set_class_name(XtGuiWindow *win, xtgui::Node *node, const std::string &value);
50
+ void remove_listener(XtGuiWindow *win, xtgui::Node *node, const std::string &type, xt_value fn,
51
+ bool capture);
52
+
53
+ /* -- method definitions (uniform `(self, env, argc, argv)` ABI) ----------- */
54
+
55
+ #define METHOD(name) xt_value name(xt_value self, xt_value env, int32_t argc, xt_value *argv)
56
+
57
+ /* document */
58
+ METHOD(doc_query_selector);
59
+ METHOD(doc_query_selector_all);
60
+ METHOD(doc_get_element_by_id);
61
+ METHOD(doc_create_element);
62
+ METHOD(doc_create_text_node);
63
+ METHOD(doc_body_get);
64
+ METHOD(doc_document_element_get);
65
+
66
+ /* node getters */
67
+ METHOD(node_tag_name_get);
68
+ METHOD(node_node_type_get);
69
+ METHOD(node_id_get);
70
+ METHOD(node_id_set);
71
+ METHOD(node_class_name_get);
72
+ METHOD(node_class_name_set);
73
+ METHOD(node_text_content_get);
74
+ METHOD(node_text_content_set);
75
+ METHOD(node_inner_html_get);
76
+ METHOD(node_inner_html_set);
77
+ METHOD(node_parent_node_get);
78
+ METHOD(node_parent_element_get);
79
+ METHOD(node_children_get);
80
+ METHOD(node_child_nodes_get);
81
+ METHOD(node_child_element_count_get);
82
+ METHOD(node_first_element_child_get);
83
+ METHOD(node_last_element_child_get);
84
+ METHOD(node_next_element_sibling_get);
85
+ METHOD(node_previous_element_sibling_get);
86
+ METHOD(node_is_connected_get);
87
+ METHOD(node_class_list_get);
88
+ METHOD(node_style_get);
89
+
90
+ /* node methods */
91
+ METHOD(node_get_attribute);
92
+ METHOD(node_set_attribute);
93
+ METHOD(node_remove_attribute);
94
+ METHOD(node_has_attribute);
95
+ METHOD(node_query_selector);
96
+ METHOD(node_query_selector_all);
97
+ METHOD(node_matches);
98
+ METHOD(node_append_child);
99
+ METHOD(node_insert_before);
100
+ METHOD(node_remove_child);
101
+ METHOD(node_replace_child);
102
+ METHOD(node_remove);
103
+ METHOD(node_clone_node);
104
+ METHOD(node_get_bounding_rect);
105
+ METHOD(node_offset_width_get);
106
+ METHOD(node_offset_height_get);
107
+ METHOD(node_contains);
108
+ METHOD(node_focus);
109
+ METHOD(node_blur);
110
+ METHOD(node_click);
111
+ METHOD(node_add_event_listener);
112
+ METHOD(node_remove_event_listener);
113
+ METHOD(node_dispatch_event);
114
+
115
+ /* event methods */
116
+ METHOD(event_prevent_default);
117
+ METHOD(event_stop_propagation);
118
+ METHOD(event_stop_immediate_propagation);
119
+
120
+ /* classList methods */
121
+ METHOD(class_list_add);
122
+ METHOD(class_list_remove);
123
+ METHOD(class_list_toggle);
124
+ METHOD(class_list_contains);
125
+
126
+ /* style methods */
127
+ METHOD(style_set_property);
128
+ METHOD(style_get_property_value);
129
+ METHOD(style_remove_property);
130
+
131
+ #undef METHOD
132
+
133
+ } // namespace domapi
134
+
135
+ #endif /* XT_GUI_DOM_API_INTERNAL_H */
@@ -0,0 +1,329 @@
1
+ /*
2
+ * xbintsc GUI engine — element handle methods (attributes, queries, tree
3
+ * mutation, geometry reads, focus, events).
4
+ */
5
+
6
+ #include "dom_api_internal.h"
7
+
8
+ #include <algorithm>
9
+ #include <cmath>
10
+ #include <memory>
11
+ #include <string>
12
+ #include <vector>
13
+
14
+ namespace domapi {
15
+
16
+ static void collect_matches(const xtgui::Node *node,
17
+ const std::vector<xtgui::ComplexSelector> &selectors,
18
+ std::vector<const xtgui::Node *> &out) {
19
+ if (node->isElement()) {
20
+ for (const xtgui::ComplexSelector &selector : selectors) {
21
+ if (xtgui::xt_css_match(node, selector)) {
22
+ out.push_back(node);
23
+ break;
24
+ }
25
+ }
26
+ }
27
+ for (const std::unique_ptr<xtgui::Node> &child : node->children) {
28
+ collect_matches(child.get(), selectors, out);
29
+ }
30
+ }
31
+
32
+ static xtgui::Node *clone_node(XtGuiWindow *win, const xtgui::Node *source, bool deep) {
33
+ if (source->isText()) return win->document->createTextNode(source->text);
34
+ if (!source->isElement()) return nullptr;
35
+ xtgui::Node *copy = win->document->createElement(source->tag);
36
+ for (const xtgui::Attr &attr : source->attrs) copy->attrs.push_back(attr);
37
+ if (deep) {
38
+ for (const std::unique_ptr<xtgui::Node> &child : source->children) {
39
+ xtgui::Node *childCopy = clone_node(win, child.get(), true);
40
+ if (childCopy != nullptr) win->document->appendChild(copy, childCopy);
41
+ }
42
+ }
43
+ return copy;
44
+ }
45
+
46
+ /** Laid-out border-box size, rounded like the browser `offsetWidth`/
47
+ * `offsetHeight` (0 when the element has no box yet). Applies pending
48
+ * mutations first so a read after a write is up to date. */
49
+ static xt_value node_offset_dimension(xt_value self, bool width) {
50
+ XtGuiWindow *win = nullptr;
51
+ xtgui::Node *node = resolve_node(self, &win);
52
+ if (node == nullptr || win == nullptr || win->document == nullptr) return xt_number(0);
53
+ xt_gui_flush_dom(win);
54
+ const xtgui::LayoutBox *box = win->document->boxOf(node);
55
+ if (box == nullptr) return xt_number(0);
56
+ return xt_number((double)std::lround(width ? box->width : box->height));
57
+ }
58
+
59
+ #define METHOD(name) xt_value name(xt_value self, xt_value env, int32_t argc, xt_value *argv)
60
+
61
+ METHOD(node_get_attribute) {
62
+ (void)env;
63
+ xtgui::Node *node = resolve_node(self, nullptr);
64
+ if (node == nullptr || !node->isElement() || argc < 1) return XT_UNDEFINED;
65
+ const std::string *value = node->attr(to_string_value(xt_arg(argc, argv, 0)));
66
+ if (value == nullptr) return XT_UNDEFINED;
67
+ return xt_string_from_cstr(value->c_str());
68
+ }
69
+
70
+ METHOD(node_set_attribute) {
71
+ (void)env;
72
+ XtGuiWindow *win = nullptr;
73
+ xtgui::Node *node = resolve_node(self, &win);
74
+ if (node == nullptr || !node->isElement() || argc < 2) return XT_UNDEFINED;
75
+ set_attribute(win, node, to_string_value(xt_arg(argc, argv, 0)),
76
+ to_string_value(xt_arg(argc, argv, 1)));
77
+ return XT_UNDEFINED;
78
+ }
79
+
80
+ METHOD(node_remove_attribute) {
81
+ (void)env;
82
+ XtGuiWindow *win = nullptr;
83
+ xtgui::Node *node = resolve_node(self, &win);
84
+ if (node == nullptr || !node->isElement() || argc < 1) return XT_UNDEFINED;
85
+ remove_attribute_raw(node, to_string_value(xt_arg(argc, argv, 0)));
86
+ mark_dirty(win);
87
+ return XT_UNDEFINED;
88
+ }
89
+
90
+ METHOD(node_has_attribute) {
91
+ (void)env;
92
+ xtgui::Node *node = resolve_node(self, nullptr);
93
+ if (node == nullptr || !node->isElement() || argc < 1) return XT_FALSE;
94
+ return node->attr(to_string_value(xt_arg(argc, argv, 0))) != nullptr ? XT_TRUE : XT_FALSE;
95
+ }
96
+
97
+ METHOD(node_query_selector) {
98
+ (void)env;
99
+ XtGuiWindow *win = nullptr;
100
+ xtgui::Node *node = resolve_node(self, &win);
101
+ if (node == nullptr || argc < 1) return XT_UNDEFINED;
102
+ std::vector<xtgui::ComplexSelector> selectors =
103
+ xtgui::xt_css_parse_selector_list(to_string_value(xt_arg(argc, argv, 0)));
104
+ if (selectors.empty()) return XT_UNDEFINED;
105
+ std::vector<const xtgui::Node *> matches;
106
+ for (const std::unique_ptr<xtgui::Node> &child : node->children) {
107
+ collect_matches(child.get(), selectors, matches);
108
+ }
109
+ return matches.empty() ? XT_UNDEFINED : xt_gui_node_handle(win, matches.front());
110
+ }
111
+
112
+ METHOD(node_query_selector_all) {
113
+ (void)env;
114
+ XtGuiWindow *win = nullptr;
115
+ xtgui::Node *node = resolve_node(self, &win);
116
+ xt_value array = xt_array_new(0, NULL);
117
+ if (node == nullptr || argc < 1) return array;
118
+ std::vector<xtgui::ComplexSelector> selectors =
119
+ xtgui::xt_css_parse_selector_list(to_string_value(xt_arg(argc, argv, 0)));
120
+ std::vector<const xtgui::Node *> matches;
121
+ for (const std::unique_ptr<xtgui::Node> &child : node->children) {
122
+ collect_matches(child.get(), selectors, matches);
123
+ }
124
+ for (const xtgui::Node *match : matches) xt_array_push(array, xt_gui_node_handle(win, match));
125
+ return array;
126
+ }
127
+
128
+ METHOD(node_matches) {
129
+ (void)env;
130
+ xtgui::Node *node = resolve_node(self, nullptr);
131
+ if (node == nullptr || !node->isElement() || argc < 1) return XT_FALSE;
132
+ std::vector<xtgui::ComplexSelector> selectors =
133
+ xtgui::xt_css_parse_selector_list(to_string_value(xt_arg(argc, argv, 0)));
134
+ for (const xtgui::ComplexSelector &selector : selectors) {
135
+ if (xtgui::xt_css_match(node, selector)) return XT_TRUE;
136
+ }
137
+ return XT_FALSE;
138
+ }
139
+
140
+ METHOD(node_append_child) {
141
+ (void)env;
142
+ XtGuiWindow *win = nullptr;
143
+ xtgui::Node *node = resolve_node(self, &win);
144
+ if (node == nullptr || win == nullptr || argc < 1) return XT_UNDEFINED;
145
+ xtgui::Node *child = resolve_node(xt_arg(argc, argv, 0), nullptr);
146
+ if (child == nullptr) return XT_UNDEFINED;
147
+ return xt_gui_node_handle(win, win->document->appendChild(node, child));
148
+ }
149
+
150
+ METHOD(node_insert_before) {
151
+ (void)env;
152
+ XtGuiWindow *win = nullptr;
153
+ xtgui::Node *node = resolve_node(self, &win);
154
+ if (node == nullptr || win == nullptr || argc < 1) return XT_UNDEFINED;
155
+ xtgui::Node *child = resolve_node(xt_arg(argc, argv, 0), nullptr);
156
+ xtgui::Node *reference = argc >= 2 ? resolve_node(xt_arg(argc, argv, 1), nullptr) : nullptr;
157
+ if (child == nullptr) return XT_UNDEFINED;
158
+ return xt_gui_node_handle(win, win->document->insertBefore(node, child, reference));
159
+ }
160
+
161
+ METHOD(node_remove_child) {
162
+ (void)env;
163
+ XtGuiWindow *win = nullptr;
164
+ xtgui::Node *node = resolve_node(self, &win);
165
+ if (node == nullptr || win == nullptr || argc < 1) return XT_UNDEFINED;
166
+ xtgui::Node *child = resolve_node(xt_arg(argc, argv, 0), nullptr);
167
+ if (child == nullptr) return XT_UNDEFINED;
168
+ win->document->removeChild(node, child);
169
+ return xt_gui_node_handle(win, child);
170
+ }
171
+
172
+ METHOD(node_replace_child) {
173
+ (void)env;
174
+ XtGuiWindow *win = nullptr;
175
+ xtgui::Node *node = resolve_node(self, &win);
176
+ if (node == nullptr || win == nullptr || argc < 2) return XT_UNDEFINED;
177
+ xtgui::Node *newChild = resolve_node(xt_arg(argc, argv, 0), nullptr);
178
+ xtgui::Node *oldChild = resolve_node(xt_arg(argc, argv, 1), nullptr);
179
+ if (newChild == nullptr || oldChild == nullptr) return XT_UNDEFINED;
180
+ return xt_gui_node_handle(win, win->document->replaceChild(node, newChild, oldChild));
181
+ }
182
+
183
+ METHOD(node_remove) {
184
+ (void)env;
185
+ (void)argc;
186
+ (void)argv;
187
+ XtGuiWindow *win = nullptr;
188
+ xtgui::Node *node = resolve_node(self, &win);
189
+ if (node == nullptr || win == nullptr) return XT_UNDEFINED;
190
+ win->document->detach(node);
191
+ win->struct_dirty = 1;
192
+ return XT_UNDEFINED;
193
+ }
194
+
195
+ METHOD(node_clone_node) {
196
+ (void)env;
197
+ XtGuiWindow *win = nullptr;
198
+ xtgui::Node *node = resolve_node(self, &win);
199
+ if (node == nullptr || win == nullptr) return XT_UNDEFINED;
200
+ bool deep = argc >= 1 ? value_truthy(xt_arg(argc, argv, 0)) : false;
201
+ return xt_gui_node_handle(win, clone_node(win, node, deep));
202
+ }
203
+
204
+ METHOD(node_get_bounding_rect) {
205
+ (void)env;
206
+ (void)argc;
207
+ (void)argv;
208
+ XtGuiWindow *win = nullptr;
209
+ xtgui::Node *node = resolve_node(self, &win);
210
+ if (node == nullptr || win == nullptr || win->document == nullptr) return XT_UNDEFINED;
211
+ const xtgui::LayoutBox *box = win->document->boxOf(node);
212
+ if (box == nullptr) return XT_UNDEFINED;
213
+ xt_value object = xt_object_new();
214
+ xt_object_set(object, xt_string_from_cstr("x"), xt_number(box->x));
215
+ xt_object_set(object, xt_string_from_cstr("y"), xt_number(box->y));
216
+ xt_object_set(object, xt_string_from_cstr("width"), xt_number(box->width));
217
+ xt_object_set(object, xt_string_from_cstr("height"), xt_number(box->height));
218
+ return object;
219
+ }
220
+
221
+ METHOD(node_offset_width_get) {
222
+ (void)env;
223
+ (void)argc;
224
+ (void)argv;
225
+ return node_offset_dimension(self, true);
226
+ }
227
+
228
+ METHOD(node_offset_height_get) {
229
+ (void)env;
230
+ (void)argc;
231
+ (void)argv;
232
+ return node_offset_dimension(self, false);
233
+ }
234
+
235
+ METHOD(node_contains) {
236
+ (void)env;
237
+ xtgui::Node *node = resolve_node(self, nullptr);
238
+ if (node == nullptr || argc < 1) return XT_FALSE;
239
+ xtgui::Node *other = resolve_node(xt_arg(argc, argv, 0), nullptr);
240
+ if (other == nullptr) return XT_FALSE;
241
+ return node->contains(other) ? XT_TRUE : XT_FALSE;
242
+ }
243
+
244
+ METHOD(node_focus) {
245
+ (void)env;
246
+ (void)argc;
247
+ (void)argv;
248
+ XtGuiWindow *win = nullptr;
249
+ xtgui::Node *node = resolve_node(self, &win);
250
+ if (node == nullptr || win == nullptr || win->document == nullptr) return XT_UNDEFINED;
251
+ if (win->document->setFocus(node)) win->geometry.dirty = 1;
252
+ return XT_UNDEFINED;
253
+ }
254
+
255
+ METHOD(node_blur) {
256
+ (void)env;
257
+ (void)argc;
258
+ (void)argv;
259
+ XtGuiWindow *win = nullptr;
260
+ xtgui::Node *node = resolve_node(self, &win);
261
+ if (node == nullptr || win == nullptr || win->document == nullptr) return XT_UNDEFINED;
262
+ if (win->document->focus() == node && win->document->setFocus(nullptr)) win->geometry.dirty = 1;
263
+ return XT_UNDEFINED;
264
+ }
265
+
266
+ METHOD(node_click) {
267
+ (void)env;
268
+ (void)argc;
269
+ (void)argv;
270
+ XtGuiWindow *win = nullptr;
271
+ xtgui::Node *node = resolve_node(self, &win);
272
+ if (node == nullptr || win == nullptr) return XT_UNDEFINED;
273
+ xt_gui_dispatch_to_node(win, node, "click");
274
+ return XT_UNDEFINED;
275
+ }
276
+
277
+ METHOD(node_add_event_listener) {
278
+ (void)env;
279
+ XtGuiWindow *win = nullptr;
280
+ xtgui::Node *node = resolve_node(self, &win);
281
+ if (node == nullptr || win == nullptr || argc < 2) return self;
282
+ xt_value fn = xt_arg(argc, argv, 1);
283
+ if (!XT_IS_FUNCTION(fn)) return self;
284
+ bool capture = false;
285
+ bool once = false;
286
+ xt_value options = xt_arg(argc, argv, 2);
287
+ if (XT_IS_OBJECT(options)) {
288
+ capture = value_truthy(xt_object_get_cstr(options, "capture"));
289
+ once = value_truthy(xt_object_get_cstr(options, "once"));
290
+ } else if (XT_IS_BOOL(options)) {
291
+ capture = value_truthy(options);
292
+ }
293
+ XtGuiNodeListener listener;
294
+ listener.type = to_string_value(xt_arg(argc, argv, 0));
295
+ listener.fn = fn;
296
+ listener.once = once;
297
+ listener.capture = capture;
298
+ win->node_listeners[node].push_back(listener);
299
+ return self;
300
+ }
301
+
302
+ METHOD(node_remove_event_listener) {
303
+ (void)env;
304
+ XtGuiWindow *win = nullptr;
305
+ xtgui::Node *node = resolve_node(self, &win);
306
+ if (node == nullptr || win == nullptr || argc < 2) return self;
307
+ bool capture = false;
308
+ xt_value options = xt_arg(argc, argv, 2);
309
+ if (XT_IS_OBJECT(options)) capture = value_truthy(xt_object_get_cstr(options, "capture"));
310
+ else if (XT_IS_BOOL(options)) capture = value_truthy(options);
311
+ remove_listener(win, node, to_string_value(xt_arg(argc, argv, 0)), xt_arg(argc, argv, 1), capture);
312
+ return self;
313
+ }
314
+
315
+ METHOD(node_dispatch_event) {
316
+ (void)env;
317
+ XtGuiWindow *win = nullptr;
318
+ xtgui::Node *node = resolve_node(self, &win);
319
+ if (node == nullptr || win == nullptr || argc < 1) return XT_FALSE;
320
+ xt_value event = xt_arg(argc, argv, 0);
321
+ std::string type = XT_IS_OBJECT(event) ? to_string_value(xt_object_get_cstr(event, "type"))
322
+ : to_string_value(event);
323
+ xt_gui_emit_dom_event(win, type.c_str(), node, event);
324
+ return XT_TRUE;
325
+ }
326
+
327
+ #undef METHOD
328
+
329
+ } // namespace domapi