@toolbox-web/grid 0.0.7 → 0.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/all.d.ts +151 -95
- package/all.js +1554 -1452
- package/all.js.map +1 -1
- package/custom-elements.json +89 -7
- package/index.d.ts +68 -23
- package/index.js +1066 -948
- package/index.js.map +1 -1
- package/lib/plugins/clipboard/index.js +48 -49
- package/lib/plugins/clipboard/index.js.map +1 -1
- package/lib/plugins/column-virtualization/index.js +6 -6
- package/lib/plugins/column-virtualization/index.js.map +1 -1
- package/lib/plugins/context-menu/index.js +32 -34
- package/lib/plugins/context-menu/index.js.map +1 -1
- package/lib/plugins/export/index.js +7 -7
- package/lib/plugins/export/index.js.map +1 -1
- package/lib/plugins/filtering/index.js +5 -38
- package/lib/plugins/filtering/index.js.map +1 -1
- package/lib/plugins/grouping-columns/index.js +4 -32
- package/lib/plugins/grouping-columns/index.js.map +1 -1
- package/lib/plugins/grouping-rows/index.js +8 -45
- package/lib/plugins/grouping-rows/index.js.map +1 -1
- package/lib/plugins/master-detail/index.js +6 -30
- package/lib/plugins/master-detail/index.js.map +1 -1
- package/lib/plugins/multi-sort/index.js +19 -42
- package/lib/plugins/multi-sort/index.js.map +1 -1
- package/lib/plugins/pinned-columns/index.js +5 -6
- package/lib/plugins/pinned-columns/index.js.map +1 -1
- package/lib/plugins/pinned-rows/index.js +6 -80
- package/lib/plugins/pinned-rows/index.js.map +1 -1
- package/lib/plugins/pivot/index.js +673 -145
- package/lib/plugins/pivot/index.js.map +1 -1
- package/lib/plugins/reorder/index.js +22 -51
- package/lib/plugins/reorder/index.js.map +1 -1
- package/lib/plugins/selection/index.js +53 -83
- package/lib/plugins/selection/index.js.map +1 -1
- package/lib/plugins/server-side/index.js +2 -2
- package/lib/plugins/server-side/index.js.map +1 -1
- package/lib/plugins/tree/index.js +6 -14
- package/lib/plugins/tree/index.js.map +1 -1
- package/lib/plugins/undo-redo/index.js +2 -3
- package/lib/plugins/undo-redo/index.js.map +1 -1
- package/lib/plugins/visibility/index.js +13 -105
- package/lib/plugins/visibility/index.js.map +1 -1
- package/package.json +1 -1
- package/themes/dg-theme-bootstrap.css +73 -0
- package/themes/dg-theme-material.css +71 -0
- package/umd/grid.all.umd.js +40 -415
- package/umd/grid.all.umd.js.map +1 -1
- package/umd/grid.umd.js +29 -60
- package/umd/grid.umd.js.map +1 -1
- package/umd/plugins/clipboard.umd.js +4 -4
- package/umd/plugins/clipboard.umd.js.map +1 -1
- package/umd/plugins/column-virtualization.umd.js +1 -1
- package/umd/plugins/column-virtualization.umd.js.map +1 -1
- package/umd/plugins/context-menu.umd.js +2 -2
- package/umd/plugins/context-menu.umd.js.map +1 -1
- package/umd/plugins/export.umd.js +1 -1
- package/umd/plugins/export.umd.js.map +1 -1
- package/umd/plugins/filtering.umd.js +2 -34
- package/umd/plugins/filtering.umd.js.map +1 -1
- package/umd/plugins/grouping-columns.umd.js +1 -28
- package/umd/plugins/grouping-columns.umd.js.map +1 -1
- package/umd/plugins/grouping-rows.umd.js +1 -39
- package/umd/plugins/grouping-rows.umd.js.map +1 -1
- package/umd/plugins/master-detail.umd.js +1 -26
- package/umd/plugins/master-detail.umd.js.map +1 -1
- package/umd/plugins/multi-sort.umd.js +1 -25
- package/umd/plugins/multi-sort.umd.js.map +1 -1
- package/umd/plugins/pinned-columns.umd.js +1 -1
- package/umd/plugins/pinned-columns.umd.js.map +1 -1
- package/umd/plugins/pinned-rows.umd.js +1 -72
- package/umd/plugins/pinned-rows.umd.js.map +1 -1
- package/umd/plugins/pivot.umd.js +1 -7
- package/umd/plugins/pivot.umd.js.map +1 -1
- package/umd/plugins/reorder.umd.js +1 -30
- package/umd/plugins/reorder.umd.js.map +1 -1
- package/umd/plugins/selection.umd.js +1 -33
- package/umd/plugins/selection.umd.js.map +1 -1
- package/umd/plugins/server-side.umd.js +1 -1
- package/umd/plugins/server-side.umd.js.map +1 -1
- package/umd/plugins/tree.umd.js +1 -10
- package/umd/plugins/tree.umd.js.map +1 -1
- package/umd/plugins/undo-redo.umd.js +1 -1
- package/umd/plugins/undo-redo.umd.js.map +1 -1
- package/umd/plugins/visibility.umd.js +1 -93
- package/umd/plugins/visibility.umd.js.map +1 -1
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
const
|
|
1
|
+
const P = {
|
|
2
2
|
expand: "▶",
|
|
3
3
|
collapse: "▼",
|
|
4
4
|
sortAsc: "▲",
|
|
5
5
|
sortDesc: "▼",
|
|
6
6
|
sortNone: "⇅",
|
|
7
7
|
submenuArrow: "▶",
|
|
8
|
-
dragHandle: "⋮⋮"
|
|
8
|
+
dragHandle: "⋮⋮",
|
|
9
|
+
toolPanel: "☰"
|
|
9
10
|
};
|
|
10
|
-
class
|
|
11
|
+
class N {
|
|
11
12
|
/** Plugin version - override in subclass if needed */
|
|
12
13
|
version = "1.0.0";
|
|
13
14
|
/** CSS styles to inject into the grid's shadow DOM */
|
|
@@ -58,8 +59,8 @@ class m {
|
|
|
58
59
|
/**
|
|
59
60
|
* Emit a custom event from the grid.
|
|
60
61
|
*/
|
|
61
|
-
emit(e,
|
|
62
|
-
this.grid?.dispatchEvent?.(new CustomEvent(e, { detail:
|
|
62
|
+
emit(e, i) {
|
|
63
|
+
this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: i, bubbles: !0 }));
|
|
63
64
|
}
|
|
64
65
|
/**
|
|
65
66
|
* Request a re-render of the grid.
|
|
@@ -132,7 +133,7 @@ class m {
|
|
|
132
133
|
*/
|
|
133
134
|
get gridIcons() {
|
|
134
135
|
const e = this.grid?.gridConfig?.icons ?? {};
|
|
135
|
-
return { ...
|
|
136
|
+
return { ...P, ...e };
|
|
136
137
|
}
|
|
137
138
|
/**
|
|
138
139
|
* Resolve an icon value to string or HTMLElement.
|
|
@@ -142,8 +143,8 @@ class m {
|
|
|
142
143
|
* @param pluginOverride - Optional plugin-level override
|
|
143
144
|
* @returns The resolved icon value
|
|
144
145
|
*/
|
|
145
|
-
resolveIcon(e,
|
|
146
|
-
return
|
|
146
|
+
resolveIcon(e, i) {
|
|
147
|
+
return i !== void 0 ? i : this.gridIcons[e];
|
|
147
148
|
}
|
|
148
149
|
/**
|
|
149
150
|
* Set an icon value on an element.
|
|
@@ -152,8 +153,8 @@ class m {
|
|
|
152
153
|
* @param element - The element to set the icon on
|
|
153
154
|
* @param icon - The icon value (string or HTMLElement)
|
|
154
155
|
*/
|
|
155
|
-
setIcon(e,
|
|
156
|
-
typeof
|
|
156
|
+
setIcon(e, i) {
|
|
157
|
+
typeof i == "string" ? e.innerHTML = i : i instanceof HTMLElement && (e.innerHTML = "", e.appendChild(i.cloneNode(!0)));
|
|
157
158
|
}
|
|
158
159
|
/**
|
|
159
160
|
* Log a warning message.
|
|
@@ -162,223 +163,750 @@ class m {
|
|
|
162
163
|
console.warn(`[tbw-grid:${this.name}] ${e}`);
|
|
163
164
|
}
|
|
164
165
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
const m = {
|
|
167
|
+
sum: (t, e) => t.reduce((i, o) => i + (Number(o[e]) || 0), 0),
|
|
168
|
+
avg: (t, e) => {
|
|
169
|
+
const i = t.reduce((o, n) => o + (Number(n[e]) || 0), 0);
|
|
170
|
+
return t.length ? i / t.length : 0;
|
|
171
|
+
},
|
|
172
|
+
count: (t) => t.length,
|
|
173
|
+
min: (t, e) => Math.min(...t.map((i) => Number(i[e]) || 1 / 0)),
|
|
174
|
+
max: (t, e) => Math.max(...t.map((i) => Number(i[e]) || -1 / 0)),
|
|
175
|
+
first: (t, e) => t[0]?.[e],
|
|
176
|
+
last: (t, e) => t[t.length - 1]?.[e]
|
|
177
|
+
}, v = /* @__PURE__ */ new Map(), h = {
|
|
178
|
+
/**
|
|
179
|
+
* Register a custom aggregator function.
|
|
180
|
+
*/
|
|
181
|
+
register(t, e) {
|
|
182
|
+
v.set(t, e);
|
|
183
|
+
},
|
|
184
|
+
/**
|
|
185
|
+
* Unregister a custom aggregator function.
|
|
186
|
+
*/
|
|
187
|
+
unregister(t) {
|
|
188
|
+
v.delete(t);
|
|
189
|
+
},
|
|
190
|
+
/**
|
|
191
|
+
* Get an aggregator function by reference.
|
|
192
|
+
*/
|
|
193
|
+
get(t) {
|
|
194
|
+
if (t !== void 0)
|
|
195
|
+
return typeof t == "function" ? t : v.get(t) ?? m[t];
|
|
196
|
+
},
|
|
197
|
+
/**
|
|
198
|
+
* Run an aggregator on a set of rows.
|
|
199
|
+
*/
|
|
200
|
+
run(t, e, i, o) {
|
|
201
|
+
const n = this.get(t);
|
|
202
|
+
return n ? n(e, i, o) : void 0;
|
|
203
|
+
},
|
|
204
|
+
/**
|
|
205
|
+
* Check if an aggregator exists.
|
|
206
|
+
*/
|
|
207
|
+
has(t) {
|
|
208
|
+
return v.has(t) || t in m;
|
|
209
|
+
},
|
|
210
|
+
/**
|
|
211
|
+
* List all available aggregator names.
|
|
212
|
+
*/
|
|
213
|
+
list() {
|
|
214
|
+
return [...Object.keys(m), ...v.keys()];
|
|
215
|
+
}
|
|
216
|
+
}, A = {
|
|
217
|
+
sum: (t) => t.reduce((e, i) => e + i, 0),
|
|
218
|
+
avg: (t) => t.length ? t.reduce((e, i) => e + i, 0) / t.length : 0,
|
|
219
|
+
count: (t) => t.length,
|
|
220
|
+
min: (t) => t.length ? Math.min(...t) : 0,
|
|
221
|
+
max: (t) => t.length ? Math.max(...t) : 0,
|
|
222
|
+
first: (t) => t[0] ?? 0,
|
|
223
|
+
last: (t) => t[t.length - 1] ?? 0
|
|
224
|
+
};
|
|
225
|
+
function k(t) {
|
|
226
|
+
return A[t] ?? A.sum;
|
|
168
227
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
return (e) => e.length ? Math.min(...e) : 0;
|
|
179
|
-
case "max":
|
|
180
|
-
return (e) => e.length ? Math.max(...e) : 0;
|
|
181
|
-
case "first":
|
|
182
|
-
return (e) => e[0] ?? 0;
|
|
183
|
-
case "last":
|
|
184
|
-
return (e) => e[e.length - 1] ?? 0;
|
|
185
|
-
default:
|
|
186
|
-
return (e) => e.reduce((t, o) => t + o, 0);
|
|
187
|
-
}
|
|
228
|
+
h.register.bind(h);
|
|
229
|
+
h.unregister.bind(h);
|
|
230
|
+
h.get.bind(h);
|
|
231
|
+
h.run.bind(h);
|
|
232
|
+
h.list.bind(h);
|
|
233
|
+
const K = k;
|
|
234
|
+
function I(t) {
|
|
235
|
+
const e = [];
|
|
236
|
+
return !t.rowGroupFields?.length && !t.columnGroupFields?.length && e.push("At least one row or column group field is required"), t.valueFields?.length || e.push("At least one value field is required"), e;
|
|
188
237
|
}
|
|
189
|
-
function
|
|
190
|
-
return [...
|
|
238
|
+
function C(t, e) {
|
|
239
|
+
return [...t, e].join("|");
|
|
191
240
|
}
|
|
192
|
-
function
|
|
193
|
-
const
|
|
241
|
+
function S(t, e) {
|
|
242
|
+
const i = e.rowGroupFields ?? [], o = e.columnGroupFields ?? [], n = e.valueFields ?? [], r = V(t, o), a = L(
|
|
243
|
+
t,
|
|
244
|
+
i,
|
|
245
|
+
o,
|
|
246
|
+
r,
|
|
247
|
+
n,
|
|
248
|
+
0,
|
|
249
|
+
// starting depth
|
|
250
|
+
""
|
|
251
|
+
// parent key prefix
|
|
252
|
+
), s = H(a, r, n), l = Object.values(s).reduce((d, c) => d + c, 0);
|
|
194
253
|
return {
|
|
195
|
-
rows:
|
|
196
|
-
columnKeys:
|
|
197
|
-
totals:
|
|
198
|
-
grandTotal:
|
|
254
|
+
rows: a,
|
|
255
|
+
columnKeys: r,
|
|
256
|
+
totals: s,
|
|
257
|
+
grandTotal: l
|
|
199
258
|
};
|
|
200
259
|
}
|
|
201
|
-
function
|
|
260
|
+
function V(t, e) {
|
|
202
261
|
if (e.length === 0) return ["value"];
|
|
203
|
-
const
|
|
204
|
-
for (const o of
|
|
205
|
-
const
|
|
206
|
-
|
|
262
|
+
const i = /* @__PURE__ */ new Set();
|
|
263
|
+
for (const o of t) {
|
|
264
|
+
const n = e.map((r) => String(o[r] ?? "")).join("|");
|
|
265
|
+
i.add(n);
|
|
207
266
|
}
|
|
208
|
-
return [...
|
|
267
|
+
return [...i].sort();
|
|
209
268
|
}
|
|
210
|
-
function
|
|
211
|
-
const
|
|
212
|
-
for (const o of
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
return t;
|
|
269
|
+
function M(t, e) {
|
|
270
|
+
const i = /* @__PURE__ */ new Map();
|
|
271
|
+
for (const o of t) {
|
|
272
|
+
const n = String(o[e] ?? ""), r = i.get(n);
|
|
273
|
+
r ? r.push(o) : i.set(n, [o]);
|
|
274
|
+
}
|
|
275
|
+
return i;
|
|
219
276
|
}
|
|
220
|
-
function
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
277
|
+
function L(t, e, i, o, n, r, a) {
|
|
278
|
+
const s = [];
|
|
279
|
+
if (e.length === 0) {
|
|
280
|
+
const u = _(t, i, o, n), g = G(u);
|
|
281
|
+
return s.push({
|
|
282
|
+
rowKey: a || "all",
|
|
283
|
+
rowLabel: a || "All",
|
|
284
|
+
depth: r,
|
|
285
|
+
values: u,
|
|
286
|
+
total: g,
|
|
287
|
+
isGroup: !1,
|
|
288
|
+
rowCount: t.length
|
|
289
|
+
}), s;
|
|
290
|
+
}
|
|
291
|
+
const l = e[0], d = e.slice(1), c = d.length > 0, p = M(t, l);
|
|
292
|
+
for (const [u, g] of p) {
|
|
293
|
+
const F = a ? `${a}|${u}` : u, y = _(g, i, o, n), E = G(y);
|
|
294
|
+
let R;
|
|
295
|
+
c && (R = L(
|
|
296
|
+
g,
|
|
297
|
+
d,
|
|
298
|
+
i,
|
|
299
|
+
o,
|
|
300
|
+
n,
|
|
301
|
+
r + 1,
|
|
302
|
+
F
|
|
303
|
+
)), s.push({
|
|
304
|
+
rowKey: F,
|
|
305
|
+
rowLabel: u || "(blank)",
|
|
233
306
|
depth: r,
|
|
234
|
-
values:
|
|
235
|
-
total:
|
|
236
|
-
isGroup:
|
|
307
|
+
values: y,
|
|
308
|
+
total: E,
|
|
309
|
+
isGroup: c,
|
|
310
|
+
children: R,
|
|
311
|
+
rowCount: g.length
|
|
237
312
|
});
|
|
238
313
|
}
|
|
239
|
-
return
|
|
314
|
+
return s;
|
|
240
315
|
}
|
|
241
|
-
function
|
|
242
|
-
const
|
|
243
|
-
for (const r of
|
|
244
|
-
for (const
|
|
245
|
-
const
|
|
246
|
-
|
|
316
|
+
function _(t, e, i, o) {
|
|
317
|
+
const n = {};
|
|
318
|
+
for (const r of i)
|
|
319
|
+
for (const a of o) {
|
|
320
|
+
const l = (e.length > 0 ? t.filter((u) => e.map((g) => String(u[g] ?? "")).join("|") === r) : t).map((u) => Number(u[a.field]) || 0), d = K(a.aggFunc), c = l.length > 0 ? d(l) : null, p = C([r], a.field);
|
|
321
|
+
n[p] = c;
|
|
247
322
|
}
|
|
323
|
+
return n;
|
|
324
|
+
}
|
|
325
|
+
function G(t) {
|
|
326
|
+
let e = 0;
|
|
327
|
+
for (const i of Object.values(t))
|
|
328
|
+
e += i ?? 0;
|
|
329
|
+
return e;
|
|
330
|
+
}
|
|
331
|
+
function H(t, e, i) {
|
|
332
|
+
const o = {};
|
|
333
|
+
function n(r) {
|
|
334
|
+
for (const a of r)
|
|
335
|
+
if (!a.isGroup || !a.children?.length)
|
|
336
|
+
for (const s of e)
|
|
337
|
+
for (const l of i) {
|
|
338
|
+
const d = C([s], l.field);
|
|
339
|
+
o[d] = (o[d] ?? 0) + (a.values[d] ?? 0);
|
|
340
|
+
}
|
|
341
|
+
else a.children && n(a.children);
|
|
342
|
+
}
|
|
343
|
+
return n(t), o;
|
|
344
|
+
}
|
|
345
|
+
function D(t, e, i = !0) {
|
|
346
|
+
const o = [];
|
|
347
|
+
function n(r) {
|
|
348
|
+
o.push(r);
|
|
349
|
+
const a = e ? e.has(r.rowKey) : i;
|
|
350
|
+
if (r.children && a)
|
|
351
|
+
for (const s of r.children)
|
|
352
|
+
n(s);
|
|
353
|
+
}
|
|
354
|
+
for (const r of t)
|
|
355
|
+
n(r);
|
|
248
356
|
return o;
|
|
249
357
|
}
|
|
250
|
-
function
|
|
358
|
+
function w(t) {
|
|
251
359
|
const e = [];
|
|
252
|
-
function
|
|
253
|
-
if (e.push(o), o.children)
|
|
254
|
-
for (const
|
|
255
|
-
|
|
360
|
+
function i(o) {
|
|
361
|
+
if (o.isGroup && e.push(o.rowKey), o.children)
|
|
362
|
+
for (const n of o.children)
|
|
363
|
+
i(n);
|
|
256
364
|
}
|
|
257
|
-
for (const o of
|
|
258
|
-
|
|
365
|
+
for (const o of t)
|
|
366
|
+
i(o);
|
|
259
367
|
return e;
|
|
260
368
|
}
|
|
261
|
-
|
|
369
|
+
const z = ["sum", "avg", "count", "min", "max", "first", "last"];
|
|
370
|
+
function q(t, e, i, o) {
|
|
371
|
+
const n = new AbortController(), r = { config: e, callbacks: o, signal: n.signal }, a = document.createElement("div");
|
|
372
|
+
return a.className = "tbw-pivot-panel", a.appendChild(f("Options", () => U(i, r))), a.appendChild(f("Row Groups", () => T("rowGroups", r))), a.appendChild(f("Column Groups", () => T("columnGroups", r))), a.appendChild(f("Values", () => Z(r))), a.appendChild(f("Available Fields", () => j(r))), t.appendChild(a), () => {
|
|
373
|
+
n.abort(), a.remove();
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
function f(t, e) {
|
|
377
|
+
const i = document.createElement("div");
|
|
378
|
+
i.className = "tbw-pivot-section";
|
|
379
|
+
const o = document.createElement("div");
|
|
380
|
+
o.className = "tbw-pivot-section-header", o.textContent = t;
|
|
381
|
+
const n = document.createElement("div");
|
|
382
|
+
return n.className = "tbw-pivot-section-content", n.appendChild(e()), i.appendChild(o), i.appendChild(n), i;
|
|
383
|
+
}
|
|
384
|
+
function T(t, e) {
|
|
385
|
+
const { config: i, callbacks: o, signal: n } = e, r = document.createElement("div");
|
|
386
|
+
r.className = "tbw-pivot-drop-zone", r.setAttribute("data-zone", t);
|
|
387
|
+
const a = t === "rowGroups" ? i.rowGroupFields ?? [] : i.columnGroupFields ?? [];
|
|
388
|
+
if (a.length === 0) {
|
|
389
|
+
const s = document.createElement("div");
|
|
390
|
+
s.className = "tbw-pivot-placeholder", s.textContent = "Drag fields here or click to add", r.appendChild(s);
|
|
391
|
+
} else
|
|
392
|
+
for (const s of a)
|
|
393
|
+
r.appendChild(O(s, t, e));
|
|
394
|
+
return r.addEventListener(
|
|
395
|
+
"dragover",
|
|
396
|
+
(s) => {
|
|
397
|
+
s.preventDefault(), r.classList.add("drag-over");
|
|
398
|
+
},
|
|
399
|
+
{ signal: n }
|
|
400
|
+
), r.addEventListener(
|
|
401
|
+
"dragleave",
|
|
402
|
+
() => {
|
|
403
|
+
r.classList.remove("drag-over");
|
|
404
|
+
},
|
|
405
|
+
{ signal: n }
|
|
406
|
+
), r.addEventListener(
|
|
407
|
+
"drop",
|
|
408
|
+
(s) => {
|
|
409
|
+
s.preventDefault(), r.classList.remove("drag-over");
|
|
410
|
+
const l = s.dataTransfer?.getData("text/plain");
|
|
411
|
+
l && o.onAddFieldToZone(l, t);
|
|
412
|
+
},
|
|
413
|
+
{ signal: n }
|
|
414
|
+
), r;
|
|
415
|
+
}
|
|
416
|
+
function O(t, e, i) {
|
|
417
|
+
const { callbacks: o, signal: n } = i, r = document.createElement("div");
|
|
418
|
+
r.className = "tbw-pivot-field-chip", r.draggable = !0;
|
|
419
|
+
const a = o.getAvailableFields().find((d) => d.field === t), s = document.createElement("span");
|
|
420
|
+
s.className = "tbw-pivot-chip-label", s.textContent = a?.header ?? t;
|
|
421
|
+
const l = document.createElement("button");
|
|
422
|
+
return l.className = "tbw-pivot-chip-remove", l.innerHTML = "×", l.title = "Remove field", l.addEventListener(
|
|
423
|
+
"click",
|
|
424
|
+
(d) => {
|
|
425
|
+
d.stopPropagation(), o.onRemoveFieldFromZone(t, e);
|
|
426
|
+
},
|
|
427
|
+
{ signal: n }
|
|
428
|
+
), r.appendChild(s), r.appendChild(l), r.addEventListener(
|
|
429
|
+
"dragstart",
|
|
430
|
+
(d) => {
|
|
431
|
+
d.dataTransfer?.setData("text/plain", t), d.dataTransfer?.setData("source-zone", e), r.classList.add("dragging");
|
|
432
|
+
},
|
|
433
|
+
{ signal: n }
|
|
434
|
+
), r.addEventListener(
|
|
435
|
+
"dragend",
|
|
436
|
+
() => {
|
|
437
|
+
r.classList.remove("dragging");
|
|
438
|
+
},
|
|
439
|
+
{ signal: n }
|
|
440
|
+
), r;
|
|
441
|
+
}
|
|
442
|
+
function Z(t) {
|
|
443
|
+
const { config: e, callbacks: i, signal: o } = t, n = document.createElement("div");
|
|
444
|
+
n.className = "tbw-pivot-drop-zone tbw-pivot-values-zone", n.setAttribute("data-zone", "values");
|
|
445
|
+
const r = e.valueFields ?? [];
|
|
446
|
+
if (r.length === 0) {
|
|
447
|
+
const a = document.createElement("div");
|
|
448
|
+
a.className = "tbw-pivot-placeholder", a.textContent = "Drag numeric fields here for aggregation", n.appendChild(a);
|
|
449
|
+
} else
|
|
450
|
+
for (const a of r)
|
|
451
|
+
n.appendChild($(a, t));
|
|
452
|
+
return n.addEventListener(
|
|
453
|
+
"dragover",
|
|
454
|
+
(a) => {
|
|
455
|
+
a.preventDefault(), n.classList.add("drag-over");
|
|
456
|
+
},
|
|
457
|
+
{ signal: o }
|
|
458
|
+
), n.addEventListener(
|
|
459
|
+
"dragleave",
|
|
460
|
+
() => {
|
|
461
|
+
n.classList.remove("drag-over");
|
|
462
|
+
},
|
|
463
|
+
{ signal: o }
|
|
464
|
+
), n.addEventListener(
|
|
465
|
+
"drop",
|
|
466
|
+
(a) => {
|
|
467
|
+
a.preventDefault(), n.classList.remove("drag-over");
|
|
468
|
+
const s = a.dataTransfer?.getData("text/plain");
|
|
469
|
+
s && i.onAddValueField(s, "sum");
|
|
470
|
+
},
|
|
471
|
+
{ signal: o }
|
|
472
|
+
), n;
|
|
473
|
+
}
|
|
474
|
+
function $(t, e) {
|
|
475
|
+
const { callbacks: i, signal: o } = e, n = document.createElement("div");
|
|
476
|
+
n.className = "tbw-pivot-field-chip tbw-pivot-value-chip";
|
|
477
|
+
const r = i.getAvailableFields().find((c) => c.field === t.field), a = document.createElement("div");
|
|
478
|
+
a.className = "tbw-pivot-value-label-wrapper";
|
|
479
|
+
const s = document.createElement("span");
|
|
480
|
+
s.className = "tbw-pivot-chip-label", s.textContent = r?.header ?? t.field;
|
|
481
|
+
const l = document.createElement("select");
|
|
482
|
+
l.className = "tbw-pivot-agg-select", l.title = "Aggregation function";
|
|
483
|
+
for (const c of z) {
|
|
484
|
+
const p = document.createElement("option");
|
|
485
|
+
p.value = c, p.textContent = c.toUpperCase(), p.selected = c === t.aggFunc, l.appendChild(p);
|
|
486
|
+
}
|
|
487
|
+
l.addEventListener(
|
|
488
|
+
"change",
|
|
489
|
+
() => {
|
|
490
|
+
i.onUpdateValueAggFunc(t.field, l.value);
|
|
491
|
+
},
|
|
492
|
+
{ signal: o }
|
|
493
|
+
);
|
|
494
|
+
const d = document.createElement("button");
|
|
495
|
+
return d.className = "tbw-pivot-chip-remove", d.innerHTML = "×", d.title = "Remove value field", d.addEventListener(
|
|
496
|
+
"click",
|
|
497
|
+
(c) => {
|
|
498
|
+
c.stopPropagation(), i.onRemoveValueField(t.field);
|
|
499
|
+
},
|
|
500
|
+
{ signal: o }
|
|
501
|
+
), a.appendChild(s), a.appendChild(l), n.appendChild(a), n.appendChild(d), n;
|
|
502
|
+
}
|
|
503
|
+
function j(t) {
|
|
504
|
+
const { config: e, callbacks: i, signal: o } = t, n = document.createElement("div");
|
|
505
|
+
n.className = "tbw-pivot-available-fields";
|
|
506
|
+
const r = i.getAvailableFields(), a = /* @__PURE__ */ new Set([
|
|
507
|
+
...e.rowGroupFields ?? [],
|
|
508
|
+
...e.columnGroupFields ?? [],
|
|
509
|
+
...e.valueFields?.map((l) => l.field) ?? []
|
|
510
|
+
]), s = r.filter((l) => !a.has(l.field));
|
|
511
|
+
if (s.length === 0) {
|
|
512
|
+
const l = document.createElement("div");
|
|
513
|
+
l.className = "tbw-pivot-placeholder", l.textContent = "All fields are in use", n.appendChild(l);
|
|
514
|
+
} else
|
|
515
|
+
for (const l of s) {
|
|
516
|
+
const d = document.createElement("div");
|
|
517
|
+
d.className = "tbw-pivot-field-chip available", d.textContent = l.header, d.draggable = !0, d.title = `Drag to add "${l.field}" to a zone`, d.addEventListener(
|
|
518
|
+
"dragstart",
|
|
519
|
+
(c) => {
|
|
520
|
+
c.dataTransfer?.setData("text/plain", l.field), d.classList.add("dragging");
|
|
521
|
+
},
|
|
522
|
+
{ signal: o }
|
|
523
|
+
), d.addEventListener(
|
|
524
|
+
"dragend",
|
|
525
|
+
() => {
|
|
526
|
+
d.classList.remove("dragging");
|
|
527
|
+
},
|
|
528
|
+
{ signal: o }
|
|
529
|
+
), n.appendChild(d);
|
|
530
|
+
}
|
|
531
|
+
return n;
|
|
532
|
+
}
|
|
533
|
+
function U(t, e) {
|
|
534
|
+
const { config: i, callbacks: o, signal: n } = e, r = document.createElement("div");
|
|
535
|
+
return r.className = "tbw-pivot-options", r.appendChild(
|
|
536
|
+
x(
|
|
537
|
+
"Enable Pivot View",
|
|
538
|
+
t,
|
|
539
|
+
(a) => {
|
|
540
|
+
o.onTogglePivot(a);
|
|
541
|
+
},
|
|
542
|
+
n
|
|
543
|
+
)
|
|
544
|
+
), r.appendChild(
|
|
545
|
+
x(
|
|
546
|
+
"Show Row Totals",
|
|
547
|
+
i.showTotals ?? !0,
|
|
548
|
+
(a) => {
|
|
549
|
+
o.onOptionChange("showTotals", a);
|
|
550
|
+
},
|
|
551
|
+
n
|
|
552
|
+
)
|
|
553
|
+
), r.appendChild(
|
|
554
|
+
x(
|
|
555
|
+
"Show Grand Total",
|
|
556
|
+
i.showGrandTotal ?? !0,
|
|
557
|
+
(a) => {
|
|
558
|
+
o.onOptionChange("showGrandTotal", a);
|
|
559
|
+
},
|
|
560
|
+
n
|
|
561
|
+
)
|
|
562
|
+
), r;
|
|
563
|
+
}
|
|
564
|
+
function x(t, e, i, o) {
|
|
565
|
+
const n = document.createElement("label");
|
|
566
|
+
n.className = "tbw-pivot-checkbox";
|
|
567
|
+
const r = document.createElement("input");
|
|
568
|
+
r.type = "checkbox", r.checked = e, r.addEventListener("change", () => i(r.checked), { signal: o });
|
|
569
|
+
const a = document.createElement("span");
|
|
570
|
+
return a.textContent = t, n.appendChild(r), n.appendChild(a), n;
|
|
571
|
+
}
|
|
572
|
+
function B(t, e, i) {
|
|
573
|
+
return e.className = "pivot-group-row", e.setAttribute("data-pivot-depth", String(t.__pivotDepth ?? 0)), e.setAttribute("role", "row"), e.setAttribute("aria-expanded", String(t.__pivotExpanded)), e.innerHTML = "", i.columns.forEach((o, n) => {
|
|
574
|
+
const r = document.createElement("div");
|
|
575
|
+
if (r.className = "cell", r.setAttribute("data-col", String(n)), r.setAttribute("role", "gridcell"), n === 0) {
|
|
576
|
+
const a = Number(t.__pivotIndent) || 0;
|
|
577
|
+
r.style.paddingLeft = `${a}px`;
|
|
578
|
+
const s = String(t.__pivotRowKey), l = document.createElement("button");
|
|
579
|
+
l.type = "button", l.className = "pivot-toggle", l.setAttribute("aria-label", t.__pivotExpanded ? "Collapse group" : "Expand group"), i.setIcon(l, i.resolveIcon(t.__pivotExpanded ? "collapse" : "expand")), l.addEventListener("click", (p) => {
|
|
580
|
+
p.stopPropagation(), i.onToggle(s);
|
|
581
|
+
}), r.appendChild(l);
|
|
582
|
+
const d = document.createElement("span");
|
|
583
|
+
d.className = "pivot-label", d.textContent = String(t.__pivotLabel ?? ""), r.appendChild(d);
|
|
584
|
+
const c = document.createElement("span");
|
|
585
|
+
c.className = "pivot-count", c.textContent = ` (${Number(t.__pivotRowCount) || 0})`, r.appendChild(c);
|
|
586
|
+
} else {
|
|
587
|
+
const a = t[o.field];
|
|
588
|
+
r.textContent = a != null ? String(a) : "";
|
|
589
|
+
}
|
|
590
|
+
e.appendChild(r);
|
|
591
|
+
}), !0;
|
|
592
|
+
}
|
|
593
|
+
function W(t, e, i) {
|
|
594
|
+
return e.className = "pivot-leaf-row", e.setAttribute("data-pivot-depth", String(t.__pivotDepth ?? 0)), e.innerHTML = "", i.forEach((o, n) => {
|
|
595
|
+
const r = document.createElement("div");
|
|
596
|
+
if (r.className = "cell", r.setAttribute("data-col", String(n)), r.setAttribute("role", "gridcell"), n === 0) {
|
|
597
|
+
const a = Number(t.__pivotIndent) || 0;
|
|
598
|
+
r.style.paddingLeft = `${a + 20}px`;
|
|
599
|
+
const s = document.createElement("span");
|
|
600
|
+
s.className = "pivot-label", s.textContent = String(t.__pivotLabel ?? ""), r.appendChild(s);
|
|
601
|
+
} else {
|
|
602
|
+
const a = t[o.field];
|
|
603
|
+
r.textContent = a != null ? String(a) : "";
|
|
604
|
+
}
|
|
605
|
+
e.appendChild(r);
|
|
606
|
+
}), !0;
|
|
607
|
+
}
|
|
608
|
+
function J(t, e, i) {
|
|
609
|
+
return e.className = "pivot-grand-total-row", e.setAttribute("role", "row"), e.innerHTML = "", i.forEach((o, n) => {
|
|
610
|
+
const r = document.createElement("div");
|
|
611
|
+
if (r.className = "cell", r.setAttribute("data-col", String(n)), r.setAttribute("role", "gridcell"), n === 0) {
|
|
612
|
+
const a = document.createElement("span");
|
|
613
|
+
a.className = "pivot-label", a.textContent = "Grand Total", r.appendChild(a);
|
|
614
|
+
} else {
|
|
615
|
+
const a = t[o.field];
|
|
616
|
+
r.textContent = a != null ? String(a) : "";
|
|
617
|
+
}
|
|
618
|
+
e.appendChild(r);
|
|
619
|
+
}), !0;
|
|
620
|
+
}
|
|
621
|
+
const Q = '.pivot-group-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:600;background:var(--tbw-pivot-group-bg, var(--tbw-color-row-alt));min-height:var(--tbw-row-height);border-bottom:var(--tbw-row-divider)}.pivot-group-row:hover{background:var(--tbw-pivot-group-hover, var(--tbw-color-row-hover))}.pivot-leaf-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-pivot-leaf-bg, var(--tbw-color-bg));min-height:var(--tbw-row-height);border-bottom:var(--tbw-row-divider)}.pivot-grand-total-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:700;background:var(--tbw-pivot-grand-total-bg, var(--tbw-color-header-bg));min-height:var(--tbw-row-height);border-top:2px solid var(--tbw-color-border-strong)}.pivot-grand-total-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}.pivot-grand-total-row>.cell:last-child{border-right:0}.pivot-grand-total-footer{position:sticky;bottom:0;z-index:var(--tbw-z-layer-pinned-rows, 20);background:var(--tbw-pivot-grand-total-bg, var(--tbw-color-header-bg));min-width:fit-content}.pivot-group-row>.cell,.pivot-leaf-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}.pivot-group-row>.cell:last-child,.pivot-leaf-row>.cell:last-child{border-right:0}.pivot-toggle{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-right:6px;border:none;background:transparent;cursor:pointer;font-size:10px;color:var(--tbw-pivot-toggle-color, var(--tbw-color-fg-muted));border-radius:var(--tbw-border-radius);transition:background .15s,color .15s}.pivot-toggle:hover{background:var(--tbw-pivot-toggle-hover-bg, var(--tbw-color-row-hover));color:var(--tbw-pivot-toggle-hover-color, var(--tbw-color-fg))}.pivot-toggle:focus{outline:var(--tbw-focus-outline);outline-offset:var(--tbw-focus-outline-offset)}.pivot-label{font-weight:inherit}.pivot-count{color:var(--tbw-pivot-count-color, var(--tbw-color-fg-muted));font-size:.9em;font-weight:400}.pivot-total-row{font-weight:700;border-top:2px solid var(--tbw-pivot-border, var(--tbw-color-border-strong))}[data-pivot-depth="1"]{--tbw-pivot-depth: 1}[data-pivot-depth="2"]{--tbw-pivot-depth: 2}[data-pivot-depth="3"]{--tbw-pivot-depth: 3}[data-pivot-depth="4"]{--tbw-pivot-depth: 4}.tbw-pivot-panel{display:flex;flex-direction:column;gap:12px;padding:12px;height:100%;overflow-y:auto;font-size:13px}.tbw-pivot-section{border:1px solid var(--tbw-pivot-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);background:var(--tbw-pivot-section-bg, var(--tbw-color-bg))}.tbw-pivot-section-header{padding:8px 12px;font-weight:600;background:var(--tbw-pivot-header-bg, var(--tbw-color-header-bg));border-bottom:1px solid var(--tbw-pivot-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius) var(--tbw-border-radius) 0 0}.tbw-pivot-section-content{padding:8px}.tbw-pivot-toggle-wrapper{display:flex;align-items:center}.tbw-pivot-toggle-label{display:flex;align-items:center;gap:8px;cursor:pointer}.tbw-pivot-toggle-label input{width:16px;height:16px;cursor:pointer}.tbw-pivot-drop-zone{min-height:60px;padding:8px;border:2px dashed var(--tbw-pivot-drop-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);background:var(--tbw-pivot-drop-bg, var(--tbw-color-row-alt));display:flex;flex-wrap:wrap;gap:6px;align-content:flex-start;transition:all .15s ease}.tbw-pivot-drop-zone.drag-over{border-color:var(--tbw-color-accent);background:var(--tbw-pivot-drop-active, var(--tbw-focus-background))}.tbw-pivot-placeholder{color:var(--tbw-color-fg-muted);font-style:italic;padding:8px;text-align:center;width:100%}.tbw-pivot-field-chip{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:var(--tbw-pivot-chip-bg, var(--tbw-color-header-bg));border:1px solid var(--tbw-pivot-chip-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);cursor:grab;font-size:12px;transition:all .15s ease}.tbw-pivot-field-chip:hover{background:var(--tbw-pivot-chip-hover, var(--tbw-color-row-hover));border-color:var(--tbw-color-accent)}.tbw-pivot-field-chip.available{background:var(--tbw-color-bg)}.tbw-pivot-field-chip.dragging{opacity:.5;cursor:grabbing}.tbw-pivot-chip-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:120px}.tbw-pivot-chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;color:var(--tbw-color-fg-muted);font-size:14px;font-weight:700;cursor:pointer;border-radius:50%;transition:all .15s ease}.tbw-pivot-chip-remove:hover{background:var(--tbw-pivot-chip-remove-hover-bg, var(--tbw-color-accent));color:var(--tbw-pivot-chip-remove-hover-fg, var(--tbw-color-accent-fg))}.tbw-pivot-value-chip{padding:4px 8px}.tbw-pivot-value-label-wrapper{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.tbw-pivot-agg-select{padding:2px 4px;font-size:11px;border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);background:var(--tbw-color-bg);cursor:pointer}.tbw-pivot-available-fields{display:flex;flex-wrap:wrap;gap:6px;min-height:40px}.tbw-pivot-options{display:flex;flex-direction:column;gap:8px}.tbw-pivot-checkbox{display:flex;align-items:center;gap:8px;cursor:pointer}.tbw-pivot-checkbox input{width:14px;height:14px;cursor:pointer}';
|
|
622
|
+
class b extends N {
|
|
262
623
|
name = "pivot";
|
|
263
624
|
version = "1.0.0";
|
|
625
|
+
/** Tool panel ID for shell integration */
|
|
626
|
+
static PANEL_ID = "pivot";
|
|
264
627
|
get defaultConfig() {
|
|
265
628
|
return {
|
|
266
|
-
|
|
629
|
+
active: !0,
|
|
267
630
|
showTotals: !0,
|
|
268
631
|
showGrandTotal: !0
|
|
269
632
|
};
|
|
270
633
|
}
|
|
271
634
|
// ===== Internal State =====
|
|
272
635
|
isActive = !1;
|
|
636
|
+
hasInitialized = !1;
|
|
273
637
|
pivotResult = null;
|
|
274
|
-
|
|
275
|
-
|
|
638
|
+
fieldHeaderMap = /* @__PURE__ */ new Map();
|
|
639
|
+
expandedKeys = /* @__PURE__ */ new Set();
|
|
640
|
+
defaultExpanded = !0;
|
|
641
|
+
originalColumns = [];
|
|
642
|
+
panelContainer = null;
|
|
643
|
+
grandTotalFooter = null;
|
|
644
|
+
/**
|
|
645
|
+
* Check if the plugin has valid pivot configuration (at least value fields).
|
|
646
|
+
*/
|
|
647
|
+
hasValidPivotConfig() {
|
|
648
|
+
return (this.config.valueFields?.length ?? 0) > 0;
|
|
649
|
+
}
|
|
276
650
|
// ===== Lifecycle =====
|
|
277
651
|
detach() {
|
|
278
|
-
this.isActive = !1, this.pivotResult = null, this.
|
|
652
|
+
this.isActive = !1, this.hasInitialized = !1, this.pivotResult = null, this.fieldHeaderMap.clear(), this.originalColumns = [], this.panelContainer = null, this.cleanupGrandTotalFooter();
|
|
653
|
+
}
|
|
654
|
+
// ===== Shell Integration =====
|
|
655
|
+
getToolPanel() {
|
|
656
|
+
return {
|
|
657
|
+
id: b.PANEL_ID,
|
|
658
|
+
title: "Pivot",
|
|
659
|
+
icon: "⊞",
|
|
660
|
+
tooltip: "Configure pivot table",
|
|
661
|
+
order: 90,
|
|
662
|
+
render: (e) => this.renderPanel(e)
|
|
663
|
+
};
|
|
279
664
|
}
|
|
280
665
|
// ===== Hooks =====
|
|
281
666
|
processRows(e) {
|
|
282
|
-
if (!this.config.
|
|
667
|
+
if (!this.hasInitialized && this.config.active !== !1 && this.hasValidPivotConfig() && (this.hasInitialized = !0, this.isActive = !0), !this.isActive)
|
|
283
668
|
return [...e];
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
669
|
+
const i = I(this.config);
|
|
670
|
+
if (i.length > 0)
|
|
671
|
+
return this.warn(`Config errors: ${i.join(", ")}`), [...e];
|
|
672
|
+
if (this.buildFieldHeaderMap(), this.defaultExpanded = this.config.defaultExpanded ?? !0, this.expandedKeys.size === 0 && this.defaultExpanded && this.pivotResult) {
|
|
673
|
+
const r = w(this.pivotResult.rows);
|
|
674
|
+
for (const a of r)
|
|
675
|
+
this.expandedKeys.add(a);
|
|
676
|
+
}
|
|
677
|
+
if (this.pivotResult = S(e, this.config), this.expandedKeys.size === 0 && this.defaultExpanded) {
|
|
678
|
+
const r = w(this.pivotResult.rows);
|
|
679
|
+
for (const a of r)
|
|
680
|
+
this.expandedKeys.add(a);
|
|
681
|
+
}
|
|
682
|
+
const o = this.config.indentWidth ?? 20;
|
|
683
|
+
return D(
|
|
684
|
+
this.pivotResult.rows,
|
|
685
|
+
this.expandedKeys,
|
|
686
|
+
this.defaultExpanded
|
|
687
|
+
).map((r) => ({
|
|
688
|
+
__pivotRowKey: r.rowKey,
|
|
689
|
+
__pivotLabel: r.rowLabel,
|
|
690
|
+
__pivotDepth: r.depth,
|
|
691
|
+
__pivotIsGroup: r.isGroup,
|
|
692
|
+
__pivotHasChildren: !!r.children?.length,
|
|
693
|
+
__pivotExpanded: this.expandedKeys.has(r.rowKey),
|
|
694
|
+
__pivotRowCount: r.rowCount ?? 0,
|
|
695
|
+
__pivotIndent: r.depth * o,
|
|
696
|
+
__pivotTotal: r.total,
|
|
697
|
+
...r.values
|
|
698
|
+
}));
|
|
293
699
|
}
|
|
294
700
|
processColumns(e) {
|
|
295
|
-
if (!this.
|
|
701
|
+
if (!this.isActive || !this.pivotResult)
|
|
296
702
|
return [...e];
|
|
297
|
-
const
|
|
298
|
-
|
|
703
|
+
const i = [], o = (this.config.rowGroupFields ?? []).map((n) => this.fieldHeaderMap.get(n) ?? n).join(" / ");
|
|
704
|
+
i.push({
|
|
299
705
|
field: "__pivotLabel",
|
|
300
|
-
header:
|
|
706
|
+
header: o || "Group",
|
|
301
707
|
width: 200
|
|
302
708
|
});
|
|
303
|
-
for (const
|
|
709
|
+
for (const n of this.pivotResult.columnKeys)
|
|
304
710
|
for (const r of this.config.valueFields ?? []) {
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
field:
|
|
308
|
-
header: `${
|
|
711
|
+
const a = C([n], r.field), s = r.header || this.fieldHeaderMap.get(r.field) || r.field;
|
|
712
|
+
i.push({
|
|
713
|
+
field: a,
|
|
714
|
+
header: `${n} - ${s} (${r.aggFunc})`,
|
|
309
715
|
width: 120,
|
|
310
716
|
type: "number"
|
|
311
717
|
});
|
|
312
718
|
}
|
|
313
|
-
return this.config.showTotals &&
|
|
719
|
+
return this.config.showTotals && i.push({
|
|
314
720
|
field: "__pivotTotal",
|
|
315
721
|
header: "Total",
|
|
316
722
|
width: 100,
|
|
317
723
|
type: "number"
|
|
318
|
-
}),
|
|
724
|
+
}), i;
|
|
725
|
+
}
|
|
726
|
+
renderRow(e, i) {
|
|
727
|
+
const o = e;
|
|
728
|
+
return o.__pivotRowKey && o.__pivotHasChildren ? B(o, i, {
|
|
729
|
+
columns: this.gridColumns,
|
|
730
|
+
onToggle: (n) => this.toggle(n),
|
|
731
|
+
resolveIcon: (n) => this.resolveIcon(n),
|
|
732
|
+
setIcon: (n, r) => this.setIcon(n, r)
|
|
733
|
+
}) : o.__pivotRowKey !== void 0 && this.isActive ? W(o, i, this.gridColumns) : (this.cleanupPivotStyling(i), !1);
|
|
319
734
|
}
|
|
320
|
-
// ===== Public API =====
|
|
321
735
|
/**
|
|
322
|
-
*
|
|
736
|
+
* Remove pivot-specific classes, attributes, and inline styles from a row element.
|
|
737
|
+
* Called when pivot mode is disabled to clean up reused DOM elements.
|
|
738
|
+
* Clears innerHTML so the grid's default renderer can rebuild the row.
|
|
323
739
|
*/
|
|
324
|
-
|
|
325
|
-
|
|
740
|
+
cleanupPivotStyling(e) {
|
|
741
|
+
(e.classList.contains("pivot-group-row") || e.classList.contains("pivot-leaf-row") || e.classList.contains("pivot-grand-total-row")) && (e.classList.remove("pivot-group-row", "pivot-leaf-row", "pivot-grand-total-row"), e.classList.add("data-grid-row"), e.removeAttribute("data-pivot-depth"), e.innerHTML = "");
|
|
742
|
+
}
|
|
743
|
+
afterRender() {
|
|
744
|
+
this.isActive && this.config.showGrandTotal && this.pivotResult ? this.renderGrandTotalFooter() : this.cleanupGrandTotalFooter();
|
|
326
745
|
}
|
|
327
746
|
/**
|
|
328
|
-
*
|
|
747
|
+
* Render the grand total row as a sticky footer pinned to the bottom.
|
|
329
748
|
*/
|
|
330
|
-
|
|
331
|
-
|
|
749
|
+
renderGrandTotalFooter() {
|
|
750
|
+
if (!this.pivotResult) return;
|
|
751
|
+
const e = this.shadowRoot;
|
|
752
|
+
if (!e) return;
|
|
753
|
+
const i = e.querySelector(".tbw-scroll-area") ?? e.querySelector(".tbw-grid-content") ?? e.children[0];
|
|
754
|
+
if (!i) return;
|
|
755
|
+
this.grandTotalFooter || (this.grandTotalFooter = document.createElement("div"), this.grandTotalFooter.className = "pivot-grand-total-footer", i.appendChild(this.grandTotalFooter));
|
|
756
|
+
const o = {
|
|
757
|
+
__pivotRowKey: "__grandTotal",
|
|
758
|
+
__pivotLabel: "Grand Total",
|
|
759
|
+
__pivotIsGrandTotal: !0,
|
|
760
|
+
__pivotTotal: this.pivotResult.grandTotal,
|
|
761
|
+
...this.pivotResult.totals
|
|
762
|
+
};
|
|
763
|
+
J(o, this.grandTotalFooter, this.gridColumns);
|
|
332
764
|
}
|
|
333
765
|
/**
|
|
334
|
-
*
|
|
766
|
+
* Remove the grand total footer element.
|
|
335
767
|
*/
|
|
768
|
+
cleanupGrandTotalFooter() {
|
|
769
|
+
this.grandTotalFooter && (this.grandTotalFooter.remove(), this.grandTotalFooter = null);
|
|
770
|
+
}
|
|
771
|
+
// ===== Expand/Collapse API =====
|
|
772
|
+
toggle(e) {
|
|
773
|
+
this.expandedKeys.has(e) ? this.expandedKeys.delete(e) : this.expandedKeys.add(e), this.requestRender();
|
|
774
|
+
}
|
|
775
|
+
expand(e) {
|
|
776
|
+
this.expandedKeys.add(e), this.requestRender();
|
|
777
|
+
}
|
|
778
|
+
collapse(e) {
|
|
779
|
+
this.expandedKeys.delete(e), this.requestRender();
|
|
780
|
+
}
|
|
781
|
+
expandAll() {
|
|
782
|
+
if (this.pivotResult) {
|
|
783
|
+
const e = w(this.pivotResult.rows);
|
|
784
|
+
for (const i of e)
|
|
785
|
+
this.expandedKeys.add(i);
|
|
786
|
+
this.requestRender();
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
collapseAll() {
|
|
790
|
+
this.expandedKeys.clear(), this.requestRender();
|
|
791
|
+
}
|
|
792
|
+
isExpanded(e) {
|
|
793
|
+
return this.expandedKeys.has(e);
|
|
794
|
+
}
|
|
795
|
+
// ===== Public API =====
|
|
796
|
+
enablePivot() {
|
|
797
|
+
this.originalColumns.length === 0 && this.captureOriginalColumns(), this.isActive = !0, this.requestRender();
|
|
798
|
+
}
|
|
799
|
+
disablePivot() {
|
|
800
|
+
this.isActive = !1, this.pivotResult = null, this.requestRender();
|
|
801
|
+
}
|
|
336
802
|
isPivotActive() {
|
|
337
803
|
return this.isActive;
|
|
338
804
|
}
|
|
339
|
-
/**
|
|
340
|
-
* Get the current pivot result.
|
|
341
|
-
*/
|
|
342
805
|
getPivotResult() {
|
|
343
806
|
return this.pivotResult;
|
|
344
807
|
}
|
|
345
|
-
/**
|
|
346
|
-
* Set the row group fields for pivoting.
|
|
347
|
-
* @param fields - Array of field names to group rows by
|
|
348
|
-
*/
|
|
349
808
|
setRowGroupFields(e) {
|
|
350
809
|
this.config.rowGroupFields = e, this.requestRender();
|
|
351
810
|
}
|
|
352
|
-
/**
|
|
353
|
-
* Set the column group fields for pivoting.
|
|
354
|
-
* @param fields - Array of field names to create columns from
|
|
355
|
-
*/
|
|
356
811
|
setColumnGroupFields(e) {
|
|
357
812
|
this.config.columnGroupFields = e, this.requestRender();
|
|
358
813
|
}
|
|
359
|
-
/**
|
|
360
|
-
* Set the value fields with aggregation functions.
|
|
361
|
-
* @param fields - Array of value field configurations
|
|
362
|
-
*/
|
|
363
814
|
setValueFields(e) {
|
|
364
815
|
this.config.valueFields = e, this.requestRender();
|
|
365
816
|
}
|
|
366
|
-
/**
|
|
367
|
-
* Refresh the pivot by clearing cached results.
|
|
368
|
-
*/
|
|
369
817
|
refresh() {
|
|
370
818
|
this.pivotResult = null, this.requestRender();
|
|
371
819
|
}
|
|
820
|
+
// ===== Tool Panel API =====
|
|
821
|
+
showPanel() {
|
|
822
|
+
this.grid.openToolPanel(b.PANEL_ID);
|
|
823
|
+
}
|
|
824
|
+
hidePanel() {
|
|
825
|
+
this.grid.closeToolPanel();
|
|
826
|
+
}
|
|
827
|
+
togglePanel() {
|
|
828
|
+
this.grid.toggleToolPanel(b.PANEL_ID);
|
|
829
|
+
}
|
|
830
|
+
isPanelVisible() {
|
|
831
|
+
return this.grid.activeToolPanel === b.PANEL_ID;
|
|
832
|
+
}
|
|
833
|
+
// ===== Private Helpers =====
|
|
834
|
+
get gridColumns() {
|
|
835
|
+
return this.grid.columns ?? [];
|
|
836
|
+
}
|
|
837
|
+
buildFieldHeaderMap() {
|
|
838
|
+
const e = this.getAvailableFields();
|
|
839
|
+
this.fieldHeaderMap.clear();
|
|
840
|
+
for (const i of e)
|
|
841
|
+
this.fieldHeaderMap.set(i.field, i.header);
|
|
842
|
+
}
|
|
843
|
+
getAvailableFields() {
|
|
844
|
+
return this.originalColumns.length > 0 ? this.originalColumns : this.captureOriginalColumns();
|
|
845
|
+
}
|
|
846
|
+
captureOriginalColumns() {
|
|
847
|
+
const e = this.grid;
|
|
848
|
+
try {
|
|
849
|
+
const i = e.getAllColumns?.() ?? e.columns ?? [];
|
|
850
|
+
return this.originalColumns = i.filter((o) => !o.field.startsWith("__pivot")).map((o) => ({
|
|
851
|
+
field: o.field,
|
|
852
|
+
header: o.header ?? o.field
|
|
853
|
+
})), this.originalColumns;
|
|
854
|
+
} catch {
|
|
855
|
+
return [];
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
renderPanel(e) {
|
|
859
|
+
this.panelContainer = e, this.originalColumns.length === 0 && this.captureOriginalColumns();
|
|
860
|
+
const i = {
|
|
861
|
+
onTogglePivot: (o) => {
|
|
862
|
+
o ? this.enablePivot() : this.disablePivot(), this.refreshPanel();
|
|
863
|
+
},
|
|
864
|
+
onAddFieldToZone: (o, n) => this.addFieldToZone(o, n),
|
|
865
|
+
onRemoveFieldFromZone: (o, n) => this.removeFieldFromZone(o, n),
|
|
866
|
+
onAddValueField: (o, n) => this.addValueField(o, n),
|
|
867
|
+
onRemoveValueField: (o) => this.removeValueField(o),
|
|
868
|
+
onUpdateValueAggFunc: (o, n) => this.updateValueAggFunc(o, n),
|
|
869
|
+
onOptionChange: (o, n) => {
|
|
870
|
+
this.config[o] = n, this.isActive && this.refresh();
|
|
871
|
+
},
|
|
872
|
+
getAvailableFields: () => this.getAvailableFields()
|
|
873
|
+
};
|
|
874
|
+
return q(e, this.config, this.isActive, i);
|
|
875
|
+
}
|
|
876
|
+
refreshPanel() {
|
|
877
|
+
this.panelContainer && (this.panelContainer.innerHTML = "", this.renderPanel(this.panelContainer));
|
|
878
|
+
}
|
|
879
|
+
addFieldToZone(e, i) {
|
|
880
|
+
if (i === "rowGroups") {
|
|
881
|
+
const o = this.config.rowGroupFields ?? [];
|
|
882
|
+
o.includes(e) || (this.config.rowGroupFields = [...o, e]);
|
|
883
|
+
} else {
|
|
884
|
+
const o = this.config.columnGroupFields ?? [];
|
|
885
|
+
o.includes(e) || (this.config.columnGroupFields = [...o, e]);
|
|
886
|
+
}
|
|
887
|
+
this.removeFromOtherZones(e, i), this.isActive && this.refresh(), this.refreshPanel();
|
|
888
|
+
}
|
|
889
|
+
removeFieldFromZone(e, i) {
|
|
890
|
+
i === "rowGroups" ? this.config.rowGroupFields = (this.config.rowGroupFields ?? []).filter((o) => o !== e) : this.config.columnGroupFields = (this.config.columnGroupFields ?? []).filter((o) => o !== e), this.isActive && this.refresh(), this.refreshPanel();
|
|
891
|
+
}
|
|
892
|
+
removeFromOtherZones(e, i) {
|
|
893
|
+
i !== "rowGroups" && (this.config.rowGroupFields = (this.config.rowGroupFields ?? []).filter((o) => o !== e)), i !== "columnGroups" && (this.config.columnGroupFields = (this.config.columnGroupFields ?? []).filter((o) => o !== e)), i !== "values" && (this.config.valueFields = (this.config.valueFields ?? []).filter((o) => o.field !== e));
|
|
894
|
+
}
|
|
895
|
+
addValueField(e, i) {
|
|
896
|
+
const o = this.config.valueFields ?? [];
|
|
897
|
+
o.some((n) => n.field === e) || (this.config.valueFields = [...o, { field: e, aggFunc: i }]), this.removeFromOtherZones(e, "values"), this.isActive && this.refresh(), this.refreshPanel();
|
|
898
|
+
}
|
|
899
|
+
removeValueField(e) {
|
|
900
|
+
this.config.valueFields = (this.config.valueFields ?? []).filter((i) => i.field !== e), this.isActive && this.refresh(), this.refreshPanel();
|
|
901
|
+
}
|
|
902
|
+
updateValueAggFunc(e, i) {
|
|
903
|
+
const o = this.config.valueFields ?? [], n = o.findIndex((r) => r.field === e);
|
|
904
|
+
n >= 0 && (o[n] = { ...o[n], aggFunc: i }, this.config.valueFields = [...o]), this.isActive && this.refresh();
|
|
905
|
+
}
|
|
372
906
|
// ===== Styles =====
|
|
373
|
-
styles =
|
|
374
|
-
[data-pivot-depth="1"] { padding-left: 20px; }
|
|
375
|
-
[data-pivot-depth="2"] { padding-left: 40px; }
|
|
376
|
-
[data-pivot-depth="3"] { padding-left: 60px; }
|
|
377
|
-
.pivot-group-row { font-weight: bold; background: var(--tbw-pivot-group-bg, var(--tbw-color-panel-bg)); }
|
|
378
|
-
.pivot-total-row { font-weight: bold; border-top: 2px solid var(--tbw-pivot-border, var(--tbw-color-border-strong)); }
|
|
379
|
-
`;
|
|
907
|
+
styles = Q;
|
|
380
908
|
}
|
|
381
909
|
export {
|
|
382
|
-
|
|
910
|
+
b as PivotPlugin
|
|
383
911
|
};
|
|
384
912
|
//# sourceMappingURL=index.js.map
|