@cdmx/wappler_ag_grid 2.1.3 → 2.1.5

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.
@@ -0,0 +1,93 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>12 · Component Methods</title>
6
+ <link rel="stylesheet" href="./lib/test-suite.css">
7
+ <link rel="stylesheet" href="../node_modules/ag-grid-community/styles/ag-theme-alpine.css">
8
+ <link rel="stylesheet" href="../ag-theme-custom.css">
9
+ <link rel="stylesheet" href="../switch-toggle-slider.css">
10
+ <script src="./dmxAppConnect/dmxAppConnect.js" defer></script>
11
+ <script src="./lib/version-banner.js" defer></script>
12
+ <script src="./lib/test-helpers.js" defer></script>
13
+ <script src="./lib/page-template.js" defer></script>
14
+ <script src="../node_modules/ag-grid-community/dist/ag-grid-community.min.js" defer></script>
15
+ <script src="../dmx-ag-grid.js" defer></script>
16
+ <script src="./data/sample-data.js" defer></script>
17
+ </head>
18
+ <body is="dmx-app" id="page12">
19
+
20
+ <script>
21
+ window.addEventListener('DOMContentLoaded', () => {
22
+ TestPage.header({
23
+ title: '12 · Component Methods',
24
+ summary: 'Every imperative method exposed in components.hjson, wired to a button so agents can fuzz them.'
25
+ });
26
+ });
27
+ </script>
28
+
29
+ <main class="test-main">
30
+ <dmx-test-data id="rows" source="employees"></dmx-test-data>
31
+
32
+ <section class="feature">
33
+ <h2>Method playground</h2>
34
+ <p class="desc">Each button calls a documented method. Watch the binding row + console for effects.</p>
35
+
36
+ <div class="grid-wrap">
37
+ <dmx-ag-grid
38
+ id="m"
39
+ dmx-bind:data="rows.value"
40
+ grid_theme="ag-theme-alpine"
41
+ quick_filter_field="qf_input"
42
+ dmx-bind:pagination="true"
43
+ dmx-bind:pagination_page_size="10">
44
+ </dmx-ag-grid>
45
+ </div>
46
+
47
+ <div class="controls" style="margin-top: 12px;">
48
+ <button class="primary" onclick="TestKit.callMethod('m','loadGrid')">loadGrid()</button>
49
+ <button onclick="TestKit.callMethod('m','reloadGrid', true)">reloadGrid(true)</button>
50
+ <button onclick="TestKit.callMethod('m','destroyGrid')">destroyGrid()</button>
51
+ <button onclick="TestKit.callMethod('m','pinColumns','first_name')">pinColumns('first_name')</button>
52
+ <button onclick="TestKit.callMethod('m','hideColumns','email')">hideColumns('email')</button>
53
+ <button onclick="TestKit.callMethod('m','getSelectedRows')">getSelectedRows()</button>
54
+ <button onclick="TestKit.callMethod('m','getAppliedFilters')">getAppliedFilters()</button>
55
+ <button onclick="TestKit.callMethod('m','getFilteredData')">getFilteredData()</button>
56
+ <button onclick="programmaticFilter()">applyFilters({department:'Sales'})</button>
57
+ <button onclick="TestKit.callMethod('m','clearFilters')">clearFilters()</button>
58
+ <button onclick="TestKit.callMethod('m','saveColumnState')">saveColumnState()</button>
59
+ <button onclick="TestKit.callMethod('m','resetColumnState')">resetColumnState()</button>
60
+ </div>
61
+
62
+ <div class="controls">
63
+ <input type="text" id="qf_input" placeholder="quick filter text" oninput="TestKit.callMethod('m','quickFilter')">
64
+ <button onclick="dump()">log component state</button>
65
+ </div>
66
+
67
+ <div class="kv">
68
+ <div class="k">count</div><div class="v" dmx-text="m.count">0</div>
69
+ <div class="k">selectedRows.length</div><div class="v" dmx-text="m.selectedRows.length">0</div>
70
+ <div class="k">filterState</div><div class="v" dmx-text="m.filterState">{}</div>
71
+ </div>
72
+
73
+ <div class="log" id="cli-log"></div>
74
+ </section>
75
+ </main>
76
+
77
+ <script>
78
+ function programmaticFilter() {
79
+ TestKit.callMethod('m', 'applyFilters', {
80
+ department: { type: 'equals', filter: 'Sales' }
81
+ });
82
+ }
83
+ function dump() {
84
+ const snap = TestKit.snapshot('m');
85
+ const box = document.getElementById('cli-log');
86
+ const e = document.createElement('div');
87
+ e.className = 'log-entry';
88
+ e.textContent = new Date().toISOString().slice(11,19) + ' → ' + JSON.stringify(snap);
89
+ box.insertBefore(e, box.firstChild);
90
+ }
91
+ </script>
92
+ </body>
93
+ </html>
@@ -0,0 +1,374 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>13 · Flags &amp; Styles · AG Grid Test Suite</title>
6
+ <link rel="stylesheet" href="./lib/test-suite.css">
7
+ <link rel="stylesheet" href="../node_modules/ag-grid-community/styles/ag-theme-alpine.css">
8
+ <link rel="stylesheet" href="../ag-theme-custom.css">
9
+ <link rel="stylesheet" href="../switch-toggle-slider.css">
10
+ <script src="./dmxAppConnect/dmxAppConnect.js" defer></script>
11
+ <script src="./lib/version-banner.js" defer></script>
12
+ <script src="./lib/test-helpers.js" defer></script>
13
+ <script src="./lib/page-template.js" defer></script>
14
+ <script src="../node_modules/ag-grid-community/dist/ag-grid-community.min.js" defer></script>
15
+ <script src="../dmx-ag-grid.js" defer></script>
16
+ <script src="./data/sample-data.js" defer></script>
17
+
18
+ <script>
19
+ // Window-scoped function condition target for rstyles[*].condition = 'isRowVip()'.
20
+ // Must take row data and return boolean.
21
+ window.isRowVip = function (row) {
22
+ return !!row && row.rating >= 4.7 && row.active === true;
23
+ };
24
+ </script>
25
+ </head>
26
+ <body is="dmx-app" id="page13">
27
+
28
+ <script>
29
+ window.addEventListener('DOMContentLoaded', () => {
30
+ TestPage.header({
31
+ title: '13 · Flags & Styles (rstyles v2.1.4)',
32
+ summary: 'Suppression flags + the full rstyles condition matrix added in 2.1.4: function, value/operator, compound, field+shorthand, first-match-wins, legacy object form.'
33
+ });
34
+ });
35
+ </script>
36
+
37
+ <main class="test-main">
38
+ <dmx-test-data id="rows" source="employees"></dmx-test-data>
39
+
40
+ <section class="feature">
41
+ <h2>Suppression flags + ci_sort + hide_filters/sort</h2>
42
+ <p class="desc">
43
+ Most behavior-suppression flags toggled on at once. <code>hide_filters="email,rating"</code>
44
+ and <code>hide_sort="department"</code> selectively disable filtering / sorting per column.
45
+ </p>
46
+ <div class="grid-wrap">
47
+ <dmx-ag-grid
48
+ id="flagsGrid"
49
+ dmx-bind:data="rows.value"
50
+ grid_theme="ag-theme-alpine"
51
+ dmx-bind:ci_sort="true"
52
+ dmx-bind:suppress_row_deselection="true"
53
+ dmx-bind:suppress_row_click_selection="true"
54
+ dmx-bind:suppress_menu_hide="true"
55
+ dmx-bind:suppress_movable_columns="true"
56
+ dmx-bind:suppress_clipboard_paste="true"
57
+ dmx-bind:suppress_scroll_on_new_data="true"
58
+ dmx-bind:always_show_vertical_scroll="true"
59
+ hide_filters="email,rating"
60
+ hide_sort="department"
61
+ dmx-bind:tooltip_show_delay="500"
62
+ dmx-bind:pagination="false">
63
+ </dmx-ag-grid>
64
+ </div>
65
+ </section>
66
+
67
+ <!--
68
+ rstyles entry shape (2.1.4):
69
+ { field?: string, condition: string, customColor: css-color }
70
+ condition forms (first matching entry wins, color is applied as row background):
71
+ 1. Function: condition = 'myFn()' — window.myFn(rowData) returns boolean
72
+ 2. Value/operator: condition = 'salary > 90000', '==', '!=', '>=', '<=', '<'
73
+ 3. Compound: condition = 'active == true && department == Engineering'
74
+ 4. Field+shorthand: field = 'department', condition = 'Engineering' (exact match)
75
+ Bare values (no operator, no field) are skipped. customColor is applied as
76
+ `background` on the row.
77
+ -->
78
+
79
+ <section class="feature">
80
+ <h2>rstyles · function condition</h2>
81
+ <p class="desc">
82
+ Single entry: <code>{ condition: 'isRowVip()', customColor: '#fef3c7' }</code>.
83
+ <code>window.isRowVip(row)</code> returns true when rating ≥ 4.7 and active.
84
+ Expect ~4 highlighted rows (David, Kate, Olivia, Sam, Xavier).
85
+ </p>
86
+ <div class="grid-wrap">
87
+ <dmx-ag-grid
88
+ id="rsFn"
89
+ dmx-bind:data="rows.value"
90
+ grid_theme="ag-theme-alpine"
91
+ dmx-bind:rstyles='[{"condition":"isRowVip()","customColor":"#fef3c7"}]'
92
+ dmx-bind:pagination="false">
93
+ </dmx-ag-grid>
94
+ </div>
95
+ </section>
96
+
97
+ <section class="feature">
98
+ <h2>rstyles · value/operator condition</h2>
99
+ <p class="desc">
100
+ <code>condition: 'salary &gt; 90000'</code> → light green for high earners,
101
+ <code>condition: 'salary &lt;= 65000'</code> → light red for low (exercises the 2.1.4
102
+ <code>&lt;=</code>/<code>&gt;=</code> parser fix).
103
+ </p>
104
+ <div class="grid-wrap">
105
+ <dmx-ag-grid
106
+ id="rsOp"
107
+ dmx-bind:data="rows.value"
108
+ grid_theme="ag-theme-alpine"
109
+ dmx-bind:rstyles='[{"condition":"salary > 90000","customColor":"#d1fae5"},{"condition":"salary <= 65000","customColor":"#fee2e2"}]'
110
+ dmx-bind:pagination="false">
111
+ </dmx-ag-grid>
112
+ </div>
113
+ </section>
114
+
115
+ <section class="feature">
116
+ <h2>rstyles · compound &amp;&amp; / ||</h2>
117
+ <p class="desc">
118
+ <code>active == true &amp;&amp; department == Engineering</code> →
119
+ light blue.
120
+ </p>
121
+ <div class="grid-wrap">
122
+ <dmx-ag-grid
123
+ id="rsCompound"
124
+ dmx-bind:data="rows.value"
125
+ grid_theme="ag-theme-alpine"
126
+ dmx-bind:rstyles='[{"condition":"active == true && department == Engineering","customColor":"#dbeafe"}]'
127
+ dmx-bind:pagination="false">
128
+ </dmx-ag-grid>
129
+ </div>
130
+ </section>
131
+
132
+ <section class="feature">
133
+ <h2>rstyles · Field + plain-value shorthand</h2>
134
+ <p class="desc">
135
+ <code>{ field: 'department', condition: 'Marketing', customColor: '#fce7f3' }</code> —
136
+ exact string match on <code>row.department</code>.
137
+ </p>
138
+ <div class="grid-wrap">
139
+ <dmx-ag-grid
140
+ id="rsShort"
141
+ dmx-bind:data="rows.value"
142
+ grid_theme="ag-theme-alpine"
143
+ dmx-bind:rstyles='[{"field":"department","condition":"Marketing","customColor":"#fce7f3"}]'
144
+ dmx-bind:pagination="false">
145
+ </dmx-ag-grid>
146
+ </div>
147
+ </section>
148
+
149
+ <section class="feature">
150
+ <h2>rstyles · first-match wins</h2>
151
+ <p class="desc">
152
+ Two overlapping conditions on the same field. The first entry
153
+ (<code>salary &gt; 95000 → orange</code>) should win for David (110k) and
154
+ Kate (105k); the second entry (<code>salary &gt; 90000 → yellow</code>) catches
155
+ the next band only.
156
+ </p>
157
+ <div class="grid-wrap">
158
+ <dmx-ag-grid
159
+ id="rsFirst"
160
+ dmx-bind:data="rows.value"
161
+ grid_theme="ag-theme-alpine"
162
+ dmx-bind:rstyles='[{"condition":"salary > 95000","customColor":"#fed7aa"},{"condition":"salary > 90000","customColor":"#fef9c3"}]'
163
+ dmx-bind:pagination="false">
164
+ </dmx-ag-grid>
165
+ </div>
166
+ </section>
167
+
168
+ <section class="feature">
169
+ <h2>rstyles · legacy object form (backwards compat)</h2>
170
+ <p class="desc">
171
+ Pre-2.1.4 callers passed an object keyed by field name. The runtime still accepts both
172
+ shapes (<code>Object.values()</code> normalises to the array path), but
173
+ <code>rstyles</code>'s schema is <code>type: Array</code>, so AppConnect coerces an
174
+ object-shaped <code>dmx-bind:</code> attribute to <code>[]</code> before the runtime sees
175
+ it. The legacy code path is only reachable programmatically — this scenario sets
176
+ <code>rstyles</code> via <code>dmx.app.get('rsLegacy').set(...)</code> and reloads.
177
+ </p>
178
+ <div class="grid-wrap">
179
+ <dmx-ag-grid
180
+ id="rsLegacy"
181
+ dmx-bind:data="rows.value"
182
+ grid_theme="ag-theme-alpine"
183
+ dmx-bind:pagination="false">
184
+ </dmx-ag-grid>
185
+ </div>
186
+ </section>
187
+
188
+ <section class="feature">
189
+ <h2>cstyles · text + cell area, with &gt;= / &lt;= operators</h2>
190
+ <p class="desc">
191
+ Two cstyles entries for <code>salary</code>:
192
+ <code>area:'text'</code> recolors the text (green if ≥ 90k),
193
+ <code>area:'cell'</code> sets the cell background (red if &lt;= 65k).
194
+ Exercises the same 2.1.4 operator parsing fix.
195
+ </p>
196
+ <div class="grid-wrap">
197
+ <dmx-ag-grid
198
+ id="csCell"
199
+ dmx-bind:data="rows.value"
200
+ grid_theme="ag-theme-alpine"
201
+ dmx-bind:cstyles='[{"field":"salary","condition":"salary >= 90000","customColor":"#047857","font":"bold","area":"text"},{"field":"salary","condition":"salary <= 65000","customColor":"#fee2e2","area":"cell"}]'
202
+ dmx-bind:pagination="false">
203
+ </dmx-ag-grid>
204
+ </div>
205
+ </section>
206
+
207
+ <section class="feature">
208
+ <h2>data_changes &amp; display_data_changes</h2>
209
+ <p class="desc">
210
+ <code>data_changes</code> rewrites field values before display.
211
+ <code>display_data_changes</code> overlays HTML badges on values.
212
+ </p>
213
+ <div class="grid-wrap">
214
+ <dmx-ag-grid
215
+ id="transformGrid"
216
+ dmx-bind:data="rows.value"
217
+ grid_theme="ag-theme-alpine"
218
+ dmx-bind:data_changes="[{field:'department', changes:[{from:'Engineering', to:'Eng.'},{from:'Marketing', to:'Mktg.'}]}]"
219
+ dmx-bind:display_data_changes="[{field:'active', changes:[{from:true, to:'<span style=color:green>ACTIVE</span>'},{from:false, to:'<span style=color:red>INACTIVE</span>'}]}]"
220
+ dmx-bind:pagination="false">
221
+ </dmx-ag-grid>
222
+ </div>
223
+ </section>
224
+
225
+ <section class="feature">
226
+ <h2>Custom tooltip</h2>
227
+ <p class="desc"><code>custom_tooltip</code> sets an HTML tooltip template; <code>tooltip_show_delay</code> shortens the hover delay.</p>
228
+ <div class="grid-wrap">
229
+ <dmx-ag-grid
230
+ id="tipGrid"
231
+ dmx-bind:data="rows.value"
232
+ grid_theme="ag-theme-alpine"
233
+ custom_tooltip="<b>{{field}}</b>: {{value}}"
234
+ dmx-bind:tooltip_config="[{field:'email'},{field:'salary'}]"
235
+ dmx-bind:tooltip_show_delay="300"
236
+ dmx-bind:pagination="false">
237
+ </dmx-ag-grid>
238
+ </div>
239
+ </section>
240
+
241
+ <section class="feature">
242
+ <h2>Live rstyles assertions</h2>
243
+ <p class="desc">
244
+ Runs in the page after the grids render and counts coloured rows per scenario.
245
+ The puppeteer runner reads <code>window.__rsCheck</code> and fails the page if any
246
+ condition didn't apply at least one matching row.
247
+ </p>
248
+ <pre class="log" id="rs-check"></pre>
249
+ </section>
250
+ </main>
251
+
252
+ <script>
253
+ // Helpers: count rows in a grid's DOM with a given background colour. Multiple matches
254
+ // are accepted (puppeteer normalises CSS to rgb()).
255
+ function bgCount(gridId, predicate) {
256
+ const root = document.querySelector('#' + gridId + '-grid');
257
+ if (!root) return -1;
258
+ let n = 0;
259
+ root.querySelectorAll('.ag-row').forEach(row => {
260
+ const bg = (row.getAttribute('style') || '').toLowerCase();
261
+ if (predicate(bg)) n++;
262
+ });
263
+ return n;
264
+ }
265
+ // Match a hex color by translating to the rgb() AG Grid leaves on style="".
266
+ function hexToRgb(hex) {
267
+ hex = hex.replace('#', '');
268
+ if (hex.length === 3) hex = hex.split('').map(c => c + c).join('');
269
+ const num = parseInt(hex, 16);
270
+ return 'rgb(' + ((num >> 16) & 255) + ', ' + ((num >> 8) & 255) + ', ' + (num & 255) + ')';
271
+ }
272
+ function hasBg(color) {
273
+ const rgb = hexToRgb(color);
274
+ return bg => bg.includes(rgb) || bg.includes(color.toLowerCase());
275
+ }
276
+
277
+ // Inject the legacy object-form rstyles directly onto the component, then trigger a
278
+ // re-render — this is the only way to exercise the backwards-compat branch in 2.1.4
279
+ // because `dmx-bind:rstyles="{…}"` is coerced to [] by AppConnect's Array type schema.
280
+ function primeLegacy() {
281
+ if (!window.dmx || !dmx.app || !dmx.app.get) return setTimeout(primeLegacy, 100);
282
+ const c = dmx.app.get('rsLegacy');
283
+ if (!c) return setTimeout(primeLegacy, 100);
284
+ if (!c.__primed) {
285
+ const legacy = {
286
+ sales: { field: 'department', condition: 'Sales', customColor: '#e9d5ff' },
287
+ hr: { field: 'department', condition: 'HR', customColor: '#fef9c3' }
288
+ };
289
+ // Reach the underlying component instance so we can mutate props.rstyles and call
290
+ // refreshGrid — `c` is the reactive proxy, not the component.
291
+ const inst = document.getElementById('rsLegacy');
292
+ const comp = inst && inst.dmxComponent;
293
+ if (comp) {
294
+ comp.props.rstyles = legacy;
295
+ if (typeof comp.refreshGrid === 'function') {
296
+ const gi = comp.refreshGrid();
297
+ comp.set('gridInstance', gi);
298
+ }
299
+ c.__primed = true;
300
+ }
301
+ }
302
+ }
303
+ primeLegacy();
304
+
305
+ // Wait for ready then evaluate every rstyles scenario and store outcomes for the runner.
306
+ function runChecks() {
307
+ if (document.body.dataset.gridsReady !== 'true') return setTimeout(runChecks, 200);
308
+ // Read fixtures here — they're populated by the deferred sample-data.js, so capturing
309
+ // them at module scope would freeze them at [] before that script ran.
310
+ const employees = (window.SampleData && window.SampleData.employees) || [];
311
+ if (!employees.length) return setTimeout(runChecks, 200);
312
+ // Wait an extra cycle so the legacy-form re-render lands before we count rows.
313
+ if (!document.querySelector('#rsLegacy-grid .ag-row [col-id]')) return setTimeout(runChecks, 200);
314
+
315
+ // Expected hand-counts derived from sample-data.js
316
+ const vipRows = employees.filter(r => r.rating >= 4.7 && r.active === true).length;
317
+ const highSalary = employees.filter(r => r.salary > 90000).length;
318
+ const lowSalary = employees.filter(r => r.salary <= 65000).length;
319
+ const activeEng = employees.filter(r => r.active === true && r.department === 'Engineering').length;
320
+ const marketingRows = employees.filter(r => r.department === 'Marketing').length;
321
+ const over95 = employees.filter(r => r.salary > 95000).length;
322
+ const between90_95 = employees.filter(r => r.salary > 90000 && r.salary <= 95000).length;
323
+ const salesRows = employees.filter(r => r.department === 'Sales').length;
324
+ const hrRows = employees.filter(r => r.department === 'HR').length;
325
+
326
+ const checks = {
327
+ rsFn: { expect: vipRows, actual: bgCount('rsFn', hasBg('#fef3c7')) },
328
+ rsOp_high: { expect: highSalary, actual: bgCount('rsOp', hasBg('#d1fae5')) },
329
+ rsOp_low: { expect: lowSalary, actual: bgCount('rsOp', hasBg('#fee2e2')) },
330
+ rsCompound: { expect: activeEng, actual: bgCount('rsCompound', hasBg('#dbeafe')) },
331
+ rsShort: { expect: marketingRows, actual: bgCount('rsShort', hasBg('#fce7f3')) },
332
+ rsFirst_top: { expect: over95, actual: bgCount('rsFirst', hasBg('#fed7aa')) },
333
+ rsFirst_mid: { expect: between90_95, actual: bgCount('rsFirst', hasBg('#fef9c3')) },
334
+ rsLegacy_sl: { expect: salesRows, actual: bgCount('rsLegacy', hasBg('#e9d5ff')) },
335
+ rsLegacy_hr: { expect: hrRows, actual: bgCount('rsLegacy', hasBg('#fef9c3')) }
336
+ };
337
+ // cstyles: text-area uses inline color: rgb(...) on the cell, cell-area uses background-color
338
+ const csTextHigh = (() => {
339
+ const root = document.querySelector('#csCell-grid');
340
+ if (!root) return -1;
341
+ let n = 0;
342
+ const targetRgb = hexToRgb('#047857');
343
+ root.querySelectorAll('[col-id="salary"]').forEach(cell => {
344
+ const s = (cell.getAttribute('style') || '').toLowerCase();
345
+ if (s.includes(targetRgb)) n++;
346
+ });
347
+ return n;
348
+ })();
349
+ const csCellLow = (() => {
350
+ const root = document.querySelector('#csCell-grid');
351
+ if (!root) return -1;
352
+ let n = 0;
353
+ const targetRgb = hexToRgb('#fee2e2');
354
+ root.querySelectorAll('[col-id="salary"]').forEach(cell => {
355
+ const s = (cell.getAttribute('style') || '').toLowerCase();
356
+ if (s.includes(targetRgb)) n++;
357
+ });
358
+ return n;
359
+ })();
360
+ checks.cs_textHigh = { expect: highSalary, actual: csTextHigh };
361
+ checks.cs_cellLow = { expect: lowSalary, actual: csCellLow };
362
+
363
+ const failed = Object.entries(checks).filter(([_, v]) => v.actual !== v.expect);
364
+ window.__rsCheck = { checks, ok: failed.length === 0, failed: failed.map(([k]) => k) };
365
+
366
+ const box = document.getElementById('rs-check');
367
+ box.textContent = Object.entries(checks)
368
+ .map(([k, v]) => (v.actual === v.expect ? '✓' : '✗') + ' ' + k + ' — expected ' + v.expect + ', got ' + v.actual)
369
+ .join('\n');
370
+ }
371
+ runChecks();
372
+ </script>
373
+ </body>
374
+ </html>
@@ -0,0 +1,112 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>14 · Compact View &amp; Extended Buttons</title>
6
+ <link rel="stylesheet" href="./lib/test-suite.css">
7
+ <link rel="stylesheet" href="../node_modules/ag-grid-community/styles/ag-theme-alpine.css">
8
+ <link rel="stylesheet" href="../ag-theme-custom.css">
9
+ <link rel="stylesheet" href="../switch-toggle-slider.css">
10
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
11
+ <script src="./dmxAppConnect/dmxAppConnect.js" defer></script>
12
+ <script src="./lib/version-banner.js" defer></script>
13
+ <script src="./lib/test-helpers.js" defer></script>
14
+ <script src="./lib/page-template.js" defer></script>
15
+ <script src="../node_modules/ag-grid-community/dist/ag-grid-community.min.js" defer></script>
16
+ <script src="../dmx-ag-grid.js" defer></script>
17
+ <script src="./data/sample-data.js" defer></script>
18
+ </head>
19
+ <body is="dmx-app" id="page14">
20
+
21
+ <script>
22
+ window.addEventListener('DOMContentLoaded', () => {
23
+ TestPage.header({
24
+ title: '14 · Compact View & Extended Buttons',
25
+ summary: 'compact_view layout; buttons 6–15 wired up to verify the extended button slots and class toggles.'
26
+ });
27
+ });
28
+ </script>
29
+
30
+ <main class="test-main">
31
+ <dmx-test-data id="rows" source="employees"></dmx-test-data>
32
+ <dmx-event-log id="evLog"></dmx-event-log>
33
+
34
+ <section class="feature">
35
+ <h2>Compact view mode</h2>
36
+ <p class="desc"><code>compact_view=true</code> with a 3-column grid, row height 20px.</p>
37
+ <div class="grid-wrap">
38
+ <dmx-ag-grid
39
+ id="compactGrid"
40
+ dmx-bind:data="rows.value"
41
+ grid_theme="ag-theme-alpine"
42
+ dmx-bind:compact_view="true"
43
+ dmx-bind:compact_view_grid_size="3"
44
+ dmx-bind:compact_view_item_height="20"
45
+ dmx-bind:pagination="false">
46
+ </dmx-ag-grid>
47
+ </div>
48
+ </section>
49
+
50
+ <section class="feature">
51
+ <h2>Buttons 6 – 15 + class toggles</h2>
52
+ <p class="desc">
53
+ Exercises the upper range of custom action buttons + the
54
+ <code>action_button_class_toggles</code> / <code>action_button_icon_class_toggles</code> arrays.
55
+ </p>
56
+ <div class="grid-wrap">
57
+ <dmx-ag-grid
58
+ id="extButtons"
59
+ dmx-bind:data="rows.value"
60
+ grid_theme="ag-theme-alpine"
61
+ dmx-bind:enable_actions="true"
62
+ actions_column_position="right"
63
+ dmx-bind:pin_actions="true"
64
+ dmx-bind:enable_custom_action_btns="true"
65
+ dmx-bind:button6_action_btn="true" button6_action_tooltip="Link" button6_action_icon_class="fas fa-link"
66
+ dmx-bind:button7_action_btn="true" button7_action_tooltip="DL" button7_action_icon_class="fas fa-download"
67
+ dmx-bind:button8_action_btn="true" button8_action_tooltip="PDF" button8_action_icon_class="fas fa-file-pdf"
68
+ dmx-bind:button9_action_btn="true" button9_action_tooltip="Star" button9_action_icon_class="fas fa-star"
69
+ dmx-bind:button10_action_btn="true" button10_action_tooltip="Trash" button10_action_icon_class="fas fa-trash-alt"
70
+ dmx-bind:button11_action_btn="true" button11_action_tooltip="Cog" button11_action_icon_class="fas fa-cog"
71
+ dmx-bind:button12_action_btn="true" button12_action_tooltip="Search" button12_action_icon_class="fas fa-search"
72
+ dmx-bind:button13_action_btn="true" button13_action_tooltip="Like" button13_action_icon_class="fas fa-thumbs-up"
73
+ dmx-bind:button14_action_btn="true" button14_action_tooltip="Bell" button14_action_icon_class="fas fa-bell"
74
+ dmx-bind:button15_action_btn="true" button15_action_tooltip="Ban" button15_action_icon_class="fas fa-ban"
75
+ dmx-bind:action_button_class_toggles="[{btn_id:'button6', condition:'active', class:'btn-success'}]"
76
+ dmx-bind:action_button_icon_class_toggles="[{btn_id:'button9', condition:'rating >= 4.5', class:'fa-spin'}]"
77
+ dmx-bind:pagination="false"
78
+ dmx-on:row_action_button6="evLog.add('row_action_button6')"
79
+ dmx-on:row_action_button10="evLog.add('row_action_button10')"
80
+ dmx-on:row_action_button15="evLog.add('row_action_button15')">
81
+ </dmx-ag-grid>
82
+ </div>
83
+ <div class="kv">
84
+ <div class="k">last action</div><div class="v" dmx-text="evLog.last.name">—</div>
85
+ <div class="k">total actions</div><div class="v" dmx-text="evLog.count">0</div>
86
+ </div>
87
+ </section>
88
+
89
+ <section class="feature">
90
+ <h2>Cell + row events explicitly enabled</h2>
91
+ <p class="desc">
92
+ <code>cell_click_event</code> and <code>row_double_click_event</code> with actions enabled — cell clicks
93
+ report as cell events instead of row events.
94
+ </p>
95
+ <div class="grid-wrap">
96
+ <dmx-ag-grid
97
+ id="cellEvtGrid"
98
+ dmx-bind:data="rows.value"
99
+ grid_theme="ag-theme-alpine"
100
+ dmx-bind:enable_actions="true"
101
+ dmx-bind:edit_action_btn="true"
102
+ dmx-bind:cell_click_event="true"
103
+ dmx-bind:row_double_click_event="true"
104
+ dmx-bind:pagination="false"
105
+ dmx-on:cell_clicked="evLog.add('cell_clicked')"
106
+ dmx-on:row_double_clicked="evLog.add('row_double_clicked')">
107
+ </dmx-ag-grid>
108
+ </div>
109
+ </section>
110
+ </main>
111
+ </body>
112
+ </html>