nx_dom_click.nx source
↩ module page · 145 lines · 5866 B
1// nx_dom_click.nx -- bits-up "click intent" extractor. Locates an
2// element by selector criteria and extracts its (action_id, arg0..arg3)
3// tuple from the data-action / data-arg0..3 attributes. The test
4// driver then passes those values to the game's nx_*_action() function
5// to simulate the click.
6//
7// Composes nx_dom_query.nx (locates the element). Single-exit pattern
8// to sidestep the parser scope quirk noted in
9// [[project-bits-up-test-driver-roadmap-2026-05-20]].
10
11import "nx_dom_query.nx"
12
13struct NxClickIntent {
14 found: i64, // 1 if matching element exists AND has data-action
15 action: i64, // value of data-action (integer)
16 arg0: i64, // value of data-arg0 (or 0 if absent)
17 arg1: i64, // value of data-arg1 (or 0 if absent)
18 arg2: i64, // value of data-arg2 (or 0 if absent)
19 arg3: i64 // value of data-arg3 (or 0 if absent)
20}
21
22func _ck_strlen(s: *u8) -> i64 {
23 var n: i64 = 0
24 while s[n] != 0 { n = n + 1 }
25 return n
26}
27
28// Parse a decimal integer (signed via leading '-') from a byte range.
29// Returns the value via out_val; returns 1 on success, 0 on parse error.
30func _ck_parse_int(src: *u8, off: i64, len: i64, out_val: *i64) -> i64 {
31 if len <= 0 { return 0 }
32 var i: i64 = 0
33 var sign: i64 = 1
34 if src[off] == 45 { // '-'
35 sign = -1
36 i = 1
37 }
38 if i >= len { return 0 }
39 var acc: i64 = 0
40 while i < len {
41 let b: i64 = src[off + i] as i64
42 if b < 48 { return 0 }
43 if b > 57 { return 0 }
44 acc = acc * 10 + (b - 48)
45 i = i + 1
46 }
47 out_val[0] = acc * sign
48 return 1
49}
50
51// Extract a data-attr's integer value from a START_TAG slice. If the
52// attr is missing OR present-but-non-numeric, returns the supplied
53// default.
54func nx_dom_attr_int_at(html: *u8, tag_off: i64, tag_len: i64,
55 attr_name: *u8, default_val: i64) -> i64 {
56 let val_off: *i64 = sys_mmap(8) as *i64
57 let val_len: *i64 = sys_mmap(8) as *i64
58 let has: i64 = nx_dom_find_attr(html, tag_off, tag_len,
59 attr_name, val_off, val_len)
60 if has != 1 { return default_val }
61 let parsed: *i64 = sys_mmap(8) as *i64
62 let ok: i64 = _ck_parse_int(html, val_off[0], val_len[0], parsed)
63 if ok != 1 { return default_val }
64 return parsed[0]
65}
66
67// Locate an element by (attr_name == attr_value) and extract its click
68// intent. Single entry point the test driver uses for "click N-th sq"
69// or "click button with data-action=2".
70func nx_dom_click_intent(html: *u8, html_len: i64,
71 attr_name: *u8, attr_value: *u8) -> *NxClickIntent {
72 let intent: *NxClickIntent = sys_mmap(48) as *NxClickIntent
73 intent.found = 0
74 intent.action = 0
75 intent.arg0 = 0
76 intent.arg1 = 0
77 intent.arg2 = 0
78 intent.arg3 = 0
79
80 let r: *NxDomQueryResult = nx_dom_find_attr_eq(html, html_len,
81 attr_name, attr_value)
82 if r.found != 1 { return intent }
83
84 // The element must have data-action to be clickable.
85 let val_off: *i64 = sys_mmap(8) as *i64
86 let val_len: *i64 = sys_mmap(8) as *i64
87 let action_attr: *u8 = "data-action" as *u8
88 let has_action: i64 = nx_dom_find_attr(html, r.tag_off, r.tag_len,
89 action_attr, val_off, val_len)
90 if has_action != 1 { return intent }
91 let parsed: *i64 = sys_mmap(8) as *i64
92 let ok: i64 = _ck_parse_int(html, val_off[0], val_len[0], parsed)
93 if ok != 1 { return intent }
94
95 intent.found = 1
96 intent.action = parsed[0]
97 intent.arg0 = nx_dom_attr_int_at(html, r.tag_off, r.tag_len,
98 "data-arg0" as *u8, 0 as i64)
99 intent.arg1 = nx_dom_attr_int_at(html, r.tag_off, r.tag_len,
100 "data-arg1" as *u8, 0 as i64)
101 intent.arg2 = nx_dom_attr_int_at(html, r.tag_off, r.tag_len,
102 "data-arg2" as *u8, 0 as i64)
103 intent.arg3 = nx_dom_attr_int_at(html, r.tag_off, r.tag_len,
104 "data-arg3" as *u8, 0 as i64)
105 return intent
106}
107
108// Variant: locate first element with class==class_name (word-boundary)
109// and extract its click intent. Useful for "click the first reset button"
110// when there's only one element of that class.
111func nx_dom_click_intent_by_class(html: *u8, html_len: i64,
112 class_name: *u8) -> *NxClickIntent {
113 let intent: *NxClickIntent = sys_mmap(48) as *NxClickIntent
114 intent.found = 0
115 intent.action = 0
116 intent.arg0 = 0
117 intent.arg1 = 0
118 intent.arg2 = 0
119 intent.arg3 = 0
120
121 let r: *NxDomQueryResult = nx_dom_find_class(html, html_len, class_name)
122 if r.found != 1 { return intent }
123
124 let val_off: *i64 = sys_mmap(8) as *i64
125 let val_len: *i64 = sys_mmap(8) as *i64
126 let action_attr: *u8 = "data-action" as *u8
127 let has_action: i64 = nx_dom_find_attr(html, r.tag_off, r.tag_len,
128 action_attr, val_off, val_len)
129 if has_action != 1 { return intent }
130 let parsed: *i64 = sys_mmap(8) as *i64
131 let ok: i64 = _ck_parse_int(html, val_off[0], val_len[0], parsed)
132 if ok != 1 { return intent }
133
134 intent.found = 1
135 intent.action = parsed[0]
136 intent.arg0 = nx_dom_attr_int_at(html, r.tag_off, r.tag_len,
137 "data-arg0" as *u8, 0 as i64)
138 intent.arg1 = nx_dom_attr_int_at(html, r.tag_off, r.tag_len,
139 "data-arg1" as *u8, 0 as i64)
140 intent.arg2 = nx_dom_attr_int_at(html, r.tag_off, r.tag_len,
141 "data-arg2" as *u8, 0 as i64)
142 intent.arg3 = nx_dom_attr_int_at(html, r.tag_off, r.tag_len,
143 "data-arg3" as *u8, 0 as i64)
144 return intent
145}