@hpcc-js/other 3.4.10 → 3.5.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/src/Table.ts CHANGED
@@ -1,1099 +1,1099 @@
1
- import { d3Event, HTMLWidget, Platform, select as d3Select, selectAll as d3SelectAll, Utility, Widget } from "@hpcc-js/common";
2
- import { Paginator } from "./Paginator.ts";
3
-
4
- import "../src/Table.css";
5
-
6
- export class Table extends HTMLWidget {
7
- protected _paginator;
8
- protected _selectionBag;
9
- protected _selectionPrevClick;
10
- protected _paginatorTableSpacing;
11
-
12
- tableDiv;
13
- thead;
14
- table;
15
- fixedHead;
16
- fixedHeadTable;
17
- fixedThead;
18
- unfixedThead;
19
- tbody;
20
- tfoot;
21
- fixedCol;
22
- fixedColTable;
23
- fixedColHead;
24
- fixedColHeadRow;
25
- fixedColBody;
26
- fixedColFoot;
27
- fixedColFootRow;
28
- protected _prevDescending;
29
- protected _prevSortByFieldIndex;
30
- protected _hasChildWidgets;
31
- protected _tNumPages;
32
- protected _empty_col_idx_arr: any[];
33
-
34
- constructor() {
35
- super();
36
- this._tag = "div";
37
- this.columns([]);
38
- this._paginator = new Paginator();
39
- this._selectionBag = new Utility.Selection(this);
40
- this._selectionPrevClick = null;
41
- this._paginatorTableSpacing = 4;
42
- }
43
-
44
- size(): any;
45
- size(_): Widget;
46
- size(_?): any | Widget {
47
- const retVal = super.size.apply(this, arguments);
48
- if (arguments.length) {
49
- if (this.tableDiv) {
50
- const topMargin = this.showHeader() && this.fixedHeader() ? this.thead.property("offsetHeight") : 0;
51
- this.tableDiv
52
- .style("width", this._size.width + "px")
53
- .style("height", this._size.height - topMargin + "px")
54
- ;
55
- this._element
56
- .style("width", this._size.width + "px")
57
- .style("height", this._size.height + "px")
58
- ;
59
- }
60
- }
61
-
62
- return retVal;
63
- }
64
-
65
- isHidden(colIdx) {
66
- if (this.pivot()) return false;
67
- if (this.hiddenColumns().indexOf(colIdx) !== -1) return true;
68
- const fields = this.fields();
69
- if (fields && fields[colIdx] && (fields[colIdx].type() === "hidden" || this._empty_col_idx_arr.indexOf(colIdx) !== -1)) {
70
- return true;
71
- }
72
- return false;
73
- }
74
-
75
- tableColumns(_?: string[]): string[] {
76
- const retVal = this.columns.apply(this, arguments);
77
- if (!arguments.length && this.pivot()) {
78
- return this._db.column(0);
79
- }
80
- return retVal;
81
- }
82
-
83
- tableData(_?) {
84
- const retVal = this.data.apply(this, arguments);
85
- if (!arguments.length && this.pivot()) {
86
- return this._db.columns().filter(function (col, idx) { return idx > 0; });
87
- }
88
- return retVal;
89
- }
90
-
91
- field(rowIdx, colIdx) {
92
- const noTransform = { transform: d => d };
93
- if (this.pivot()) {
94
- if (colIdx === 0) return noTransform;
95
- return this.fields()[rowIdx + 1];
96
- }
97
- if (rowIdx === -1) return noTransform;
98
- return this.fields()[colIdx];
99
- }
100
-
101
- calcFieldsIndex(colIdx) {
102
- let i = -1;
103
- let offset = 0;
104
- const colLen = this.columns().length;
105
- let visibleCount = 0;
106
- while (i < colLen && visibleCount <= colIdx) {
107
- i++;
108
- if (this.isHidden(i)) {
109
- offset++;
110
- } else {
111
- visibleCount++;
112
- }
113
- }
114
- return colIdx + offset;
115
- }
116
-
117
- getEmptyColumnIdxArr(columns, data) {
118
- const ret_arr = [];
119
- if (this.hideEmptyColumns()) {
120
- for (let col_idx = 0; col_idx < columns.length; col_idx++) {
121
- let column_is_empty = true;
122
- for (let row_idx = 0; row_idx < data.length; row_idx++) {
123
- if (["", null, undefined].indexOf(data[row_idx][col_idx]) === -1) {
124
- column_is_empty = false;
125
- break;
126
- }
127
- }
128
- if (column_is_empty) {
129
- ret_arr.push(col_idx);
130
- }
131
- }
132
- }
133
- return ret_arr;
134
- }
135
-
136
- enter(domNode, element) {
137
- super.enter(domNode, element);
138
- this._placeholderElement.style("overflow", "hidden");
139
-
140
- this.tableDiv = element.append("div").attr("class", "tableDiv");
141
- this.table = this.tableDiv.append("table");
142
- this.fixedHead = element.append("div").classed("header-wrapper", true);
143
- this.fixedHeadTable = this.fixedHead.append("table");
144
- this.fixedThead = this.fixedHeadTable.append("thead").append("tr");
145
- this.unfixedThead = this.table.append("thead").append("tr");
146
- this.tbody = this.table.append("tbody");
147
- this.tfoot = this.table.append("tfoot").append("tr");
148
- this.fixedCol = element.append("div").classed("rows-wrapper", true);
149
- this.fixedColTable = this.fixedCol.append("table");
150
- this.fixedColHead = this.fixedColTable.append("thead");
151
- this.fixedColHeadRow = this.fixedColHead.append("tr");
152
- this.fixedColBody = this.fixedColTable.append("tbody");
153
- this.fixedColFoot = this.fixedColTable.append("tfoot");
154
- this.fixedColFootRow = this.fixedColFoot.append("tr");
155
-
156
- this.tableDiv
157
- .style("overflow", "auto")
158
- ;
159
- }
160
-
161
- update(domNode, element) {
162
- super.update(domNode, element);
163
- const context = this;
164
- const columns = context.tableColumns();
165
- const data = context.tableData();
166
- const scrollLeft = this.tableDiv.node().scrollLeft;
167
- this._empty_col_idx_arr = this.getEmptyColumnIdxArr(columns, data);
168
-
169
- this.element().selectAll("table,tbody,th,td").style("width", null);
170
-
171
- if (this.sortByFieldIndex_exists() && (this._prevSortByFieldIndex !== this.sortByFieldIndex() || this._prevDescending !== this.descending())) {
172
- Utility.multiSort(data, [{ idx: this.sortByFieldIndex(), reverse: this.descending() }]);
173
- this._prevSortByFieldIndex = this.sortByFieldIndex();
174
- this._prevDescending = this.descending();
175
- }
176
-
177
- this._hasChildWidgets = false;
178
-
179
- if (this.fixedHeader()) {
180
- this.thead = this.fixedThead;
181
- } else {
182
- this.thead = this.unfixedThead;
183
- }
184
- this.fixedHead.style("display", this.fixedHeader() ? "table-row" : "none");
185
- this.unfixedThead.style("display", this.fixedHeader() ? "none" : "table-row");
186
-
187
- const thSel = this.thead.selectAll("th").data(this.showHeader() ? columns.filter(function (col, idx) {
188
- return !context.isHidden(idx) && context._empty_col_idx_arr.indexOf(idx) === -1;
189
- }) : []);
190
- const thUpdate = thSel.enter().append("th")
191
- .each(function (d) {
192
- const element2 = d3Select(this);
193
- element2
194
- .append("span")
195
- .attr("class", "thText")
196
- ;
197
- element2
198
- .append("span")
199
- .attr("class", "thIcon")
200
- ;
201
- })
202
- .on("click", function (column, idx) {
203
- context.headerClick(column, idx);
204
- })
205
- .merge(thSel)
206
- .style("background-color", this.theadRowBackgroundColor())
207
- .style("border-color", this.theadCellBorderColor())
208
- .style("color", this.theadFontColor())
209
- .style("font-size", this.theadFontSize())
210
- ;
211
- thUpdate.select(".thText")
212
- .style("font-family", this.theadFontFamily())
213
- .text(function (column, idx) {
214
- const fieldsIdx = context.calcFieldsIndex(idx);
215
- return context.field(-1, fieldsIdx).transform(column);
216
- })
217
- ;
218
- thUpdate.select(".thIcon")
219
- .text(function (column, idx) {
220
- if (context.descending()) {
221
- return context.sortByFieldIndex() === idx ? "\uf078" : "";
222
- } else {
223
- return context.sortByFieldIndex() === idx ? "\uf077" : "";
224
- }
225
- })
226
- ;
227
- thSel.exit()
228
- .remove()
229
- ;
230
- thUpdate.order();
231
-
232
- if (this.paginationLimit()) {
233
- this.pagination(data.length >= parseInt(this.paginationLimit()) ? true : false);
234
- }
235
- if (this.pagination()) {
236
- if (this._paginator.target() === null) {
237
- this._paginator.target(element.node());
238
- }
239
-
240
- const ipp = this._calcRowsPerPage(thUpdate);
241
- this.itemsPerPage(ipp);
242
-
243
- this._paginator.numItems(data.length);
244
- this._tNumPages = Math.ceil(this._paginator.numItems() / this.itemsPerPage()) || 1;
245
- if (this.pageNumber() > this._tNumPages || this.pageNumber() <= 0) { this.pageNumber(1); } // resets if current pagenum selected out of range
246
-
247
- this._paginator._onSelect = function (p, d) {
248
- context.pageNumber(p);
249
- context.render();
250
- return;
251
- };
252
- } else {
253
- this._paginator.numItems(0); // remove widget
254
- }
255
-
256
- // pageNumber starts at index 1
257
- const startIndex = this.pageNumber() - 1;
258
- const itemsOnPage = this.itemsPerPage();
259
-
260
- const start = startIndex * itemsOnPage;
261
- const end = startIndex * parseInt(itemsOnPage) + parseInt(itemsOnPage);
262
-
263
- let tData = null;
264
-
265
- if (this.topN()) {
266
- tData = data.slice(0, this.topN());
267
- } else if (this.pagination()) {
268
- tData = data.slice(start, end);
269
- } else {
270
- tData = data;
271
- }
272
-
273
- const totalRow: any[] = [this.totalledLabel() ? this.totalledLabel() : null];
274
- if (this.totalledColumns().length !== 0) {
275
- for (let i = 0; i < this.totalledColumns().length; i++) this.totalledColumns()[i] = +this.totalledColumns()[i];
276
- for (let j = 1; j < columns.length; j++) {
277
- let sum = 0;
278
- if (this.totalledColumns().indexOf(j) !== -1) {
279
- for (let k = 0; k < tData.length; k++) {
280
- sum = sum + tData[k][j];
281
- }
282
- totalRow.push(sum);
283
- } else {
284
- totalRow.push("");
285
- }
286
- }
287
-
288
- const tfSel = this.tfoot.selectAll("td").data(totalRow);
289
- tfSel.enter()
290
- .append("td")
291
- .merge(tfSel)
292
- .style("background-color", this.tfootRowBackgroundColor())
293
- .style("border-color", this.tfootCellBorderColor())
294
- .style("color", this.tfootFontColor())
295
- .style("font-size", this.tfootFontSize())
296
- [this.renderHtmlDataCells() ? "html" : "text"](function (d, idx) {
297
- return context.fields()[idx].transform(d);
298
- });
299
- tfSel.exit()
300
- .remove()
301
- ;
302
- }
303
-
304
- const rowsSel = this.tbody.selectAll("tr.tr_" + this.id()).data(tData.map(function (d, idx) {
305
- // TODO - Move fix closer to data source?
306
- for (let i = 0; i < d.length; ++i) {
307
- if (d[i] === undefined) {
308
- d[i] = null;
309
- }
310
- }
311
- return {
312
- rowIdx: idx,
313
- row: d
314
- };
315
- }));
316
- const rowsUpdate = rowsSel.enter().append("tr")
317
- .attr("class", "tr_" + this.id())
318
- .on("click.selectionBag", function (_d) {
319
- if (_d.row) {
320
- const d = _d.row;
321
- const i = _d.rowIdx;
322
- context.selectionBagClick(d, i);
323
- context.applyRowStyles(context.getBodyRow(i));
324
- context.applyFirstColRowStyles(context.getFixedRow(i));
325
- }
326
- }, true) // capture=true: event is caught on the way down the DOM before the cell click.
327
- .on("mouseover", function (_d) {
328
- if (_d.row) {
329
- const i = _d.rowIdx;
330
- const fixedLeftRows = context.getFixedRow(i);
331
- if (!fixedLeftRows.empty()) {
332
- fixedLeftRows.classed("hover", true);
333
- }
334
- const tbodyRows = context.getBodyRow(i);
335
- tbodyRows.classed("hover", true);
336
- context.applyStyleToRows(tbodyRows);
337
- context.applyFirstColRowStyles(fixedLeftRows);
338
- }
339
- })
340
- .on("mouseout", function (_d) {
341
- if (_d.row) {
342
- const i = _d.rowIdx;
343
- const fixedLeftRows = context.getFixedRow(i);
344
- fixedLeftRows.classed("hover", false);
345
- const tbodyRows = context.getBodyRow(i);
346
- tbodyRows.classed("hover", false);
347
- context.applyStyleToRows(tbodyRows);
348
- context.applyFirstColRowStyles(fixedLeftRows);
349
- }
350
- })
351
- .merge(rowsSel)
352
- .classed("selected", function (_d) {
353
- const d = _d.row;
354
- return context._selectionBag.isSelected(context._createSelectionObject(d));
355
- })
356
- .classed("trId" + this._id, true)
357
- ;
358
- rowsSel.exit()
359
- .remove()
360
- ;
361
- this.applyStyleToRows(rowsUpdate);
362
-
363
- const cellsSel = rowsUpdate.selectAll(".td_" + this.id()).data(function (_d, _trIdx) {
364
- return _d.row.filter(function (cell, idx) {
365
- return idx < columns.length && !context.isHidden(idx) && context._empty_col_idx_arr.indexOf(idx) === -1;
366
- }).map(function (cell, idx) {
367
- return {
368
- rowInfo: _d,
369
- colIdx: idx,
370
- cell
371
- };
372
- });
373
- });
374
- cellsSel.enter()
375
- .append("td")
376
- .attr("class", "td_" + this.id())
377
- .on("click", function (tdContents) {
378
- if (tdContents.rowInfo) {
379
- context.click(context.rowToObj(tdContents.rowInfo.row), context.columns()[tdContents.colIdx], context._selectionBag.isSelected(context._createSelectionObject(tdContents.rowInfo.row)));
380
- }
381
- })
382
- .on("dblclick", function (tdContents, idx) {
383
- if (tdContents.rowInfo) {
384
- context.dblclick(context.rowToObj(tdContents.rowInfo.row), context.columns()[tdContents.colIdx], context._selectionBag.isSelected(context._createSelectionObject(tdContents.rowInfo.row)));
385
- }
386
- })
387
- .each(function (tdContents, tdIdx) {
388
- const alignment = context.getColumnAlignment(tdContents.rowInfo.rowIdx, tdContents.colIdx, tdContents.cell);
389
- const el = d3Select(this);
390
- el
391
- .style("height", null)
392
- .style("text-align", alignment)
393
- .style("vertical-align", context.verticalAlign())
394
- .classed("tr-" + tdContents.rowInfo.rowIdx + "-td-" + tdIdx, true)
395
- ;
396
- })
397
- .merge(cellsSel)
398
- .each(function (tdContents) {
399
- const el = d3Select(this);
400
- if (tdContents.cell instanceof Widget) {
401
- el[context.renderHtmlDataCells() ? "html" : "text"](null);
402
- const widgetDiv = el.selectAll(".div_" + context.id()).data([tdContents.cell], function (d: any) { return d.id(); });
403
- widgetDiv.exit()
404
- .each(function (d: any) {
405
- d.target(null);
406
- })
407
- .remove()
408
- ;
409
- widgetDiv.enter().append("div")
410
- .attr("class", "div_" + context.id())
411
- .style("width", context.minWidgetWidth() + "px")
412
- .style("height", context.minWidgetHeight() + "px")
413
- .each(function (d) {
414
- const widgetDiv2 = d3Select(this);
415
- d._parentWidget = context;
416
- if (d._class.indexOf("childWidget") < 0) {
417
- d._class = "childWidget " + d._class;
418
- }
419
- d
420
- .target(null)
421
- .target(widgetDiv2.node())
422
- ;
423
- })
424
- .merge(widgetDiv as any)
425
- .each(function (d) {
426
- d
427
- .resize()
428
- .lazyRender()
429
- ;
430
- context._hasChildWidgets = true;
431
- })
432
- ;
433
- } else {
434
- el.selectAll(".div_" + context.id()).remove();
435
- const fieldsIdx = context.calcFieldsIndex(tdContents.colIdx);
436
- el[context.renderHtmlDataCells() ? "html" : "text"](
437
- context.field(tdContents.rowInfo.rowIdx, fieldsIdx).transform(tdContents.cell)
438
- );
439
- }
440
- })
441
- ;
442
- cellsSel.exit()
443
- .remove()
444
- ;
445
- const tableMarginHeight = parseInt(this.thead.node().offsetHeight);
446
-
447
- if (this.pagination() && this._hasChildWidgets) {
448
- this.tableDiv.style("overflow-y", "auto");
449
- this.table.style("margin-bottom", "50px");
450
- console.warn("Warning: displaying another widget in the table may cause problems with pagination");
451
- } else {
452
- this.tableDiv.style("overflow-y", null);
453
- this.table.style("margin-bottom", null);
454
-
455
- }
456
- this.size(this._size);
457
-
458
- let fixedColWidth = 0;
459
- const fixedColThSel = this.fixedColHeadRow.selectAll("th").data(this.fixedColumn() && this.showHeader() ? [columns[0]] : []);
460
- const fixedColThUpdate = fixedColThSel.enter().append("th")
461
- .each(function (d) {
462
- const element2 = d3Select(this);
463
- element2
464
- .append("span")
465
- .attr("class", "thText")
466
- ;
467
- element2
468
- .append("span")
469
- .attr("class", "thIcon")
470
- ;
471
- })
472
- .on("click", function (column, idx) {
473
- context.headerClick(column, idx);
474
- })
475
- .merge(fixedColThSel)
476
- .style("background-color", this.theadRowBackgroundColor())
477
- .style("border-color", this.theadCellBorderColor())
478
- .style("color", this.theadFontColor())
479
- .style("font-size", this.theadFontSize())
480
- ;
481
- fixedColThUpdate.select(".thText")
482
- .style("font-family", this.theadFontFamily())
483
- .text(function (column) {
484
- return column;
485
- })
486
- ;
487
- fixedColThUpdate.select(".thIcon")
488
- .text(function (column, idx) {
489
- if (context.descending()) {
490
- return context.sortByFieldIndex() === idx ? "\uf078" : "";
491
- } else {
492
- return context.sortByFieldIndex() === idx ? "\uf077" : "";
493
- }
494
- })
495
- ;
496
- fixedColThSel.exit()
497
- .remove()
498
- ;
499
-
500
- const fixedColTrSel = this.fixedColBody.selectAll("tr").data(this.fixedColumn() ? tData : []);
501
- const fixedColTrUpdate = fixedColTrSel.enter().append("tr")
502
- .attr("class", function () {
503
- return "trId" + context._id;
504
- })
505
- .merge(fixedColTrSel)
506
- .on("click", function (d, i) {
507
- (d3Select(rowsUpdate[0][i]).on("click.selectionBag") as any)(rowsUpdate.data()[i], i)
508
- ;
509
- })
510
- .on("mouseover", function (d, i) {
511
- (d3Select(rowsUpdate[0][i]).on("mouseover") as any)(rowsUpdate.data()[i], i)
512
- ;
513
- })
514
- .on("mouseout", function (d, i) {
515
- (d3Select(rowsUpdate[0][i]).on("mouseout") as any)(rowsUpdate.data()[i], i)
516
- ;
517
- })
518
- .classed("selected", function (d) {
519
- return context._selectionBag.isSelected(context._createSelectionObject(d));
520
- })
521
- ;
522
- fixedColTrSel.exit()
523
- .remove()
524
- ;
525
- const fixedColTdSel = fixedColTrUpdate.selectAll("td").data(function (d, i) {
526
- return [d[0]];
527
- });
528
- const fixedColTdUpdate = fixedColTdSel.enter().append("td")
529
- .merge(fixedColTdSel)[this.renderHtmlDataCells() ? "html" : "text"](function (d): any {
530
- if (typeof (d) === "string") {
531
- return d.trim();
532
- } else if (typeof (d) === "number") {
533
- return d;
534
- }
535
- return "";
536
- });
537
- fixedColTdSel.exit()
538
- .remove()
539
- ;
540
-
541
- const fixedColFootTdSel = this.fixedColFootRow.selectAll("td").data(this.fixedColumn() && this.totalledLabel() ? [this.totalledLabel()] : []);
542
- const fixedColFootTdUpdate = fixedColFootTdSel.enter().append("td")
543
- .merge(fixedColFootTdSel)[this.renderHtmlDataCells() ? "html" : "text"](function (d): any {
544
- if (typeof (d) === "string") {
545
- return d.trim();
546
- } else if (typeof (d) === "number") {
547
- return d;
548
- }
549
- return "";
550
- });
551
- fixedColFootTdSel.exit()
552
- .remove()
553
- ;
554
-
555
- if (this.fixedColumn() && !this.fixedSize() && fixedColFootTdUpdate.length) {
556
- if (this.showHeader()) {
557
- fixedColWidth = fixedColFootTdUpdate.property("offsetWidth") > fixedColFootTdUpdate.property("offsetWidth") ? fixedColFootTdUpdate.property("offsetWidth") : fixedColFootTdUpdate.property("offsetWidth");
558
- } else {
559
- fixedColWidth = fixedColFootTdUpdate.property("offsetWidth");
560
- }
561
- this.fixedCol
562
- .style("position", "absolute")
563
- .style("margin-top", -this.tableDiv.property("scrollTop") + tableMarginHeight + "px")
564
- ;
565
- fixedColTdUpdate
566
- .style("width", fixedColWidth + "px")
567
- ;
568
- this.fixedColHead
569
- .style("position", "absolute")
570
- .style("margin-top", (this.fixedHeader() ? this.tableDiv.property("scrollTop") : 0) - tableMarginHeight + "px")
571
- ;
572
- fixedColThUpdate
573
- .style("width", fixedColWidth + "px")
574
- ;
575
- rowsUpdate.each(function (d, i) {
576
- const height = d3Select(this).select("td").property("offsetHeight");
577
- d3Select(fixedColTdUpdate[i][0]).style("height", height + "px");
578
- });
579
- }
580
-
581
- this.table
582
- .style("margin-left", -fixedColWidth + "px")
583
- ;
584
- this.tableDiv
585
- .style("margin-left", fixedColWidth + "px")
586
- .style("width", this.width() - fixedColWidth + "px")
587
- ;
588
-
589
- if (!rowsUpdate.empty()) this.setColumnWidths(rowsUpdate);
590
-
591
- let box;
592
- let newTableHeight;
593
- let finalWidth;
594
- let maxWidth;
595
- if (this.fixedSize()) {
596
- const node = d3Select(".tableDiv > table").node();
597
- if (node) {
598
- box = (node as any).getBoundingClientRect();
599
- let newTableHeight;
600
- let finalWidth;
601
- if (box.width !== 0 && box.height !== 0) {
602
- calcWidth();
603
- calcHeight();
604
- } else {
605
- if (box.height - tableMarginHeight <= context.tableDiv.property("offsetHeight")) {
606
- calcHeight();
607
- } else {
608
- if (context.fixedHeader()) {
609
- newTableHeight = context.tableDiv.property("offsetHeight"); // is tableDiv correct?
610
- newTableHeight = newTableHeight + "px";
611
- } else {
612
- newTableHeight = "100%";
613
- }
614
- }
615
- if (box.width - fixedColWidth < context.tableDiv.property("offsetWidth")) {
616
- calcWidth();
617
- } else {
618
- if (context.fixedColumn()) {
619
- finalWidth = context.tableDiv.property("offsetWidth") - fixedColWidth; // is tableDiv correct?
620
- finalWidth = finalWidth + "px";
621
- } else {
622
- finalWidth = "100%";
623
- }
624
- }
625
- }
626
- if (element.classed("childWidget")) {
627
- context._placeholderElement
628
- .style("width", finalWidth + "px")
629
- .style("height", newTableHeight + "px")
630
- ;
631
- context.tableDiv
632
- .style("overflow", "hidden")
633
- ;
634
- }
635
- context.size({ width: finalWidth, height: newTableHeight });
636
- }
637
- }
638
-
639
- this.setOnScrollEvents(this.tableDiv.node(), tableMarginHeight);
640
-
641
- function calcWidth() {
642
- const newTableWidth = box.width;
643
- maxWidth = context.tbody.property("offsetWidth") + 1;
644
- finalWidth = newTableWidth > maxWidth ? maxWidth : newTableWidth;
645
- finalWidth = finalWidth;
646
- }
647
-
648
- function calcHeight() {
649
- newTableHeight = context.tbody.property("offsetHeight") + tableMarginHeight;
650
- newTableHeight = newTableHeight;
651
- }
652
-
653
- this._paginator.render();
654
- setTimeout(function () {
655
- context._paginator
656
- .right((context.hasVScroll(element) ? Platform.getScrollbarWidth() : 0) + context._paginatorTableSpacing)
657
- .bottom((context.hasHScroll(element) ? Platform.getScrollbarWidth() : 0) + context._paginatorTableSpacing)
658
- .render(function () {
659
- context.tableDiv.node().scrollLeft = scrollLeft;
660
- })
661
- ;
662
- }, 0);
663
- }
664
-
665
- exit(domNode, element) {
666
- this._paginator.target(null);
667
- super.exit(domNode, element);
668
- }
669
-
670
- setColumnWidths(rows) {
671
- const context = this;
672
- const firstRow = rows.filter(function (d, i) { return i === 0; });
673
-
674
- let tds = d3Select(null);
675
- firstRow.each(function (d) {
676
- tds = d3SelectAll(this.childNodes);
677
- });
678
-
679
- const tableMarginHeight = this.fixedHeader() ? this.thead.property("offsetHeight") : 0;
680
- let totalWidth = 1;
681
- const tdWidths = {};
682
-
683
- tds.each(function (d, i) {
684
- tdWidths[i] = (this as any).offsetWidth;
685
- });
686
-
687
- const th = this.thead.selectAll("th");
688
- th.each(function (d, i) {
689
- const thwidth = this.offsetWidth;
690
- const tdwidth = tds.empty() ? 0 : tdWidths[i];
691
- const usewidth = thwidth >= tdwidth ? thwidth : tdwidth;
692
- this.style.width = usewidth + "px";
693
- tds
694
- .filter((_d, idx) => idx === 0)
695
- .each(function () {
696
- d3Select(this).style("width", usewidth + "px");
697
- })
698
- ;
699
- totalWidth += usewidth;
700
- });
701
- this.thead
702
- .style("position", this.fixedHeader() ? "absolute" : "relative")
703
- .style("width", totalWidth + "px")
704
- .style("margin-top", "0px")
705
- ;
706
- this.table
707
- .style("width", totalWidth + "px")
708
- ;
709
- this.tableDiv
710
- .style("margin-top", (context.fixedHeader() ? tableMarginHeight : 0) + "px")
711
- ;
712
- this.tbody
713
- .style("width", totalWidth + "px")
714
- ;
715
- }
716
-
717
- getBodyRow(i) {
718
- return this.table.selectAll("tbody tr.trId" + this._id)
719
- .filter(function (d, idx) {
720
- return idx === i;
721
- })
722
- ;
723
- }
724
-
725
- getFixedRow(i) {
726
- return this._element.selectAll(".rows-wrapper tbody tr")
727
- .filter(function (d, idx) {
728
- return idx === i;
729
- })
730
- ;
731
- }
732
-
733
- setOnScrollEvents(scrollNode, margHeight) {
734
- const context = this;
735
- scrollNode.onscroll = function (e) {
736
- const topDelta = e.target.scrollTop;
737
- const leftDelta = e.target.scrollLeft;
738
- if (context.fixedHeader()) {
739
- context.thead
740
- .style("margin-left", -leftDelta + "px")
741
- ;
742
- }
743
- if (context.fixedColumn()) {
744
- context.fixedCol
745
- .style("margin-top", -topDelta + margHeight + "px")
746
- ;
747
- if (context.fixedHeader()) {
748
- context.fixedColHead
749
- .style("margin-top", topDelta - margHeight + "px")
750
- ;
751
- }
752
- }
753
- };
754
- }
755
-
756
- _generateTempRow() {
757
- const trow = this.tbody.append("tr");
758
- trow.append("td").text("QQQ");
759
- return trow;
760
- }
761
-
762
- _createSelectionObject(d) {
763
- const context = this;
764
- return {
765
- _id: d,
766
- element: () => context.tbody ? context.tbody.selectAll("tr").filter(function (d2) { return d2 === d; }) : d3Select(null)
767
- };
768
- }
769
-
770
- _calcRowsPerPage(th) {
771
- if (this._paginator.numItems() === 0) { // only run on first render
772
- this._paginator.numItems(1);
773
- this.itemsPerPage(1);
774
- }
775
- this._paginator.render();
776
-
777
- const thHeight = this.thead.selectAll("th").node() ? this.thead.selectAll("th").node().clientHeight : 0;
778
- const tfootHeight = this.tfoot.selectAll("td").node() ? this.tfoot.selectAll("td").node().clientHeight : 0;
779
- const tmpRow = this._generateTempRow();
780
- const tcellHeight = tmpRow.node().clientHeight;
781
- tmpRow.remove();
782
- const paginatorHeight = this.calcHeight(this._paginator.element());
783
- let ipp = Math.floor((this.height() - thHeight - tfootHeight - paginatorHeight - (this.table.style("width") >= this.table.style("width") ? Platform.getScrollbarWidth() : 0) - this._paginatorTableSpacing * 2) / tcellHeight) || 1;
784
- if (this.totalledColumns().length !== 0) {
785
- ipp -= 1;
786
- }
787
- return ipp;
788
- }
789
-
790
- sort(idx) {
791
- if (this.sortByFieldIndex() !== idx) {
792
- this.descending(false);
793
- } else {
794
- this.descending(!this.descending());
795
- }
796
- this.sortByFieldIndex(idx);
797
-
798
- return this;
799
- }
800
-
801
- selection(_) {
802
- if (!arguments.length) return this._selectionBag.get().map(function (d) { return d._id; });
803
- this._selectionBag.set(_.map(function (row) {
804
- return this._createSelectionObject(row);
805
- }, this));
806
- return this;
807
- }
808
-
809
- selectionBagClick(d, i) {
810
- if (this.multiSelect() && d3Event().shiftKey && this._selectionPrevClick) {
811
- let inRange = false;
812
- const rows = [];
813
- const selection = this.tableData().filter(function (row, i2) {
814
- let lastInRangeRow = false;
815
- if (row === d || row === this._selectionPrevClick) {
816
- if (inRange) {
817
- lastInRangeRow = true;
818
- }
819
- inRange = !inRange;
820
- rows.push(i2);
821
- }
822
- return inRange || lastInRangeRow;
823
- }, this);
824
- this.selection(selection);
825
- } else if (this.multiSelect()) {
826
- this._selectionBag.click(this._createSelectionObject(d), d3Event);
827
- this._selectionPrevClick = d;
828
- } else {
829
- const selObj = this._createSelectionObject(d);
830
- this._selectionBag.click(selObj, { ctrlKey: this._selectionBag.isSelected(selObj) });
831
- this._selectionPrevClick = d;
832
- }
833
- this.render();
834
- }
835
-
836
- applyHoverRowStyles(row) {
837
- const context = this;
838
- row
839
- .style("color", context.tbodyHoverRowFontColor())
840
- .style("background-color", context.tbodyHoverRowBackgroundColor())
841
- ;
842
- }
843
- applySelectedRowStyles(row) {
844
- const context = this;
845
- row
846
- .style("color", context.tbodySelectedRowFontColor())
847
- .style("background-color", context.tbodySelectedRowBackgroundColor())
848
- ;
849
- }
850
- applyRowStyles(row, isFirstCol: boolean = false) {
851
- const dataRow = row.datum().row;
852
- row
853
- .style("color", isFirstCol ? this.tbodyFirstColFontColor() : this.tbodyFontColor())
854
- .style("background-color", isFirstCol ? this.tbodyFirstColBackgroundColor() : this.tableZebraColor_exists() && this.tableData().indexOf(dataRow) % 2 ? this.tbodyRowBackgroundColor() : this.tableZebraColor())
855
- ;
856
- }
857
- applyFirstColRowStyles(rows) {
858
- this.applyStyleToRows(rows, true);
859
- }
860
- applyStyleToRows(rows, isFirstCol: boolean = false) {
861
- isFirstCol = typeof isFirstCol !== "undefined" ? isFirstCol : false;
862
- const context = this;
863
- rows.each(function () {
864
- const tr = d3Select(this);
865
- if (tr.classed("hover")) {
866
- context.applyHoverRowStyles(tr);
867
- } else if (tr.classed("selected")) {
868
- context.applySelectedRowStyles(tr);
869
- } else {
870
- context.applyRowStyles(tr, isFirstCol);
871
- }
872
- })
873
- ;
874
- }
875
-
876
- getColumnAlignment(rowIdx, colIdx, cell) {
877
- const fieldsIdx = this.calcFieldsIndex(colIdx);
878
- const field = this.field(rowIdx, fieldsIdx);
879
- switch ((field as any).__prop_type) {
880
- case "string":
881
- return this.stringAlign();
882
- case "number":
883
- return this.numberAlign();
884
- case "":
885
- case undefined:
886
- switch (typeof cell) {
887
- case "string":
888
- return this.stringAlign();
889
- case "number":
890
- return this.numberAlign();
891
- }
892
- }
893
- return null;
894
- }
895
-
896
- serializeState() {
897
- return {
898
- selection: this._selectionBag.get().map(function (d) {
899
- return d._id;
900
- }),
901
- data: this.data()
902
- };
903
- }
904
-
905
- deserializeState(state) {
906
- if (state) {
907
- if (state.selection) {
908
- const context = this;
909
- this._selectionBag.set(state.selection.map(function (d) {
910
- return context._createSelectionObject(d);
911
- }));
912
- }
913
- if (state.data) {
914
- this.data(state.data);
915
- }
916
- }
917
- return this;
918
- }
919
-
920
- click(row, column, selected) {
921
- }
922
-
923
- dblclick(row, column, selected) {
924
- }
925
-
926
- headerClick(column, idx) {
927
- this
928
- .sort(idx)
929
- .render()
930
- ;
931
- }
932
- }
933
- Table.prototype._class += " other_Table";
934
-
935
- export interface Table {
936
- renderHtmlDataCells(): boolean;
937
- renderHtmlDataCells(_: boolean): this;
938
- pagination(): boolean;
939
- pagination(_: boolean): this;
940
- paginationLimit(): any;
941
- paginationLimit(_: any): this;
942
- itemsPerPage(): any;
943
- itemsPerPage(_: any): this;
944
- pageNumber(): number;
945
- pageNumber(_: number): this;
946
- adjacentPages(): number;
947
- adjacentPages(_: number): this;
948
- topN(): number;
949
- topN(_: number): this;
950
- pivot(): boolean;
951
- pivot(_: boolean): this;
952
- showHeader(): boolean;
953
- showHeader(_: boolean): this;
954
- fixedHeader(): boolean;
955
- fixedHeader(_: boolean): this;
956
- fixedColumn(): boolean;
957
- fixedColumn(_: boolean): this;
958
- multiSelect(): boolean;
959
- multiSelect(_: boolean): this;
960
-
961
- fixedSize(): boolean;
962
- fixedSize(_: boolean): this;
963
-
964
- hideEmptyColumns(): boolean;
965
- hideEmptyColumns(_: boolean): this;
966
-
967
- theadFontSize(): string;
968
- theadFontSize(_: string): this;
969
- tbodyFontSize(): string;
970
- tbodyFontSize(_: string): this;
971
- tfootFontSize(): string;
972
- tfootFontSize(_: string): this;
973
- theadFontColor(): string;
974
- theadFontColor(_: string): this;
975
- tbodyFontColor(): string;
976
- tbodyFontColor(_: string): this;
977
- tfootFontColor(): string;
978
- tfootFontColor(_: string): this;
979
- theadFontFamily(): string;
980
- theadFontFamily(_: string): this;
981
- tbodyFontFamily(): string;
982
- tbodyFontFamily(_: string): this;
983
- tfootFontFamily(): string;
984
- tfootFontFamily(_: string): this;
985
-
986
- theadCellBorderColor(): string;
987
- theadCellBorderColor(_: string): this;
988
- tfootCellBorderColor(): string;
989
- tfootCellBorderColor(_: string): this;
990
- theadRowBackgroundColor(): string;
991
- theadRowBackgroundColor(_: string): this;
992
- tfootRowBackgroundColor(): string;
993
- tfootRowBackgroundColor(_: string): this;
994
-
995
- tbodyCellBorderColor(): string;
996
- tbodyCellBorderColor(_: string): this;
997
-
998
- tbodyRowBackgroundColor(): string;
999
- tbodyRowBackgroundColor(_: string): this;
1000
- tbodyFirstColFontColor(): string;
1001
- tbodyFirstColFontColor(_: string): this;
1002
- tbodyFirstColBackgroundColor(): string;
1003
- tbodyFirstColBackgroundColor(_: string): this;
1004
-
1005
- tbodyHoverRowFontColor(): string;
1006
- tbodyHoverRowFontColor(_: string): this;
1007
- tbodyHoverRowBackgroundColor(): string;
1008
- tbodyHoverRowBackgroundColor(_: string): this;
1009
-
1010
- tbodySelectedRowFontColor(): string;
1011
- tbodySelectedRowFontColor(_: string): this;
1012
- tbodySelectedRowBackgroundColor(): string;
1013
- tbodySelectedRowBackgroundColor(_: string): this;
1014
- tableZebraColor(): string;
1015
- tableZebraColor(_: string): this;
1016
- tableZebraColor_exists(): boolean;
1017
- totalledColumns(): any[];
1018
- totalledColumns(_: any[]): this;
1019
- totalledLabel(): string;
1020
- totalledLabel(_: string): this;
1021
- hiddenColumns(): any[];
1022
- hiddenColumns(_: any[]): this;
1023
-
1024
- stringAlign(): string;
1025
- stringAlign(_: string): this;
1026
- numberAlign(): string;
1027
- numberAlign(_: string): this;
1028
- verticalAlign(): string;
1029
- verticalAlign(_: string): this;
1030
-
1031
- minWidgetWidth(): number;
1032
- minWidgetWidth(_: number): this;
1033
- minWidgetHeight(): number;
1034
- minWidgetHeight(_: number): this;
1035
-
1036
- sortByFieldIndex(): number;
1037
- sortByFieldIndex(_: number): this;
1038
- sortByFieldIndex_exists(): boolean;
1039
- descending(): boolean;
1040
- descending(_: boolean): this;
1041
- }
1042
-
1043
- Table.prototype.publish("renderHtmlDataCells", false, "boolean", "enable or disable HTML within cells", null, { tags: ["Private"] });
1044
- Table.prototype.publish("pagination", true, "boolean", "Enable or disable pagination", null, { tags: ["Private"] });
1045
- Table.prototype.publish("paginationLimit", null, "number", "Maximum number of rows allowed before pagination defaults to on", null, { tags: ["Private"] });
1046
- Table.prototype.publishProxy("itemsPerPage", "_paginator");
1047
- Table.prototype.publishProxy("pageNumber", "_paginator", "pageNumber", 1);
1048
- Table.prototype.publishProxy("adjacentPages", "_paginator");
1049
- Table.prototype.publish("topN", null, "number", "Total number or rows of data to be displayed in the table", null, { tags: ["Private"] });
1050
- Table.prototype.publish("pivot", false, "boolean", "Pivot Table");
1051
- Table.prototype.publish("showHeader", true, "boolean", "Show or hide the table header", null, { tags: ["Private"] });
1052
- Table.prototype.publish("fixedHeader", true, "boolean", "Enable or disable fixed table header", null, { tags: ["Private"] });
1053
- Table.prototype.publish("fixedColumn", false, "boolean", "Enable or disable fixed first column", null, { tags: ["Private"] });
1054
- Table.prototype.publish("multiSelect", false, "boolean", "Multiple Selection", null, { tags: ["Basic"] });
1055
-
1056
- Table.prototype.publish("fixedSize", false, "boolean", "Fix Size to Min Width/Height");
1057
-
1058
- Table.prototype.publish("hideEmptyColumns", false, "boolean", "Hide columns with all empty cells");
1059
-
1060
- Table.prototype.publish("theadFontSize", null, "string", "Table head font size", null, { tags: ["Basic"], optional: true });
1061
- Table.prototype.publish("tbodyFontSize", null, "string", "Table body font size", null, { tags: ["Basic"], optional: true });
1062
- Table.prototype.publish("tfootFontSize", null, "string", "Table body font size", null, { tags: ["Basic"], optional: true });
1063
- Table.prototype.publish("theadFontColor", null, "html-color", "Table head font color", null, { tags: ["Basic"], optional: true });
1064
- Table.prototype.publish("tbodyFontColor", null, "html-color", "Table body font color", null, { tags: ["Basic"], optional: true });
1065
- Table.prototype.publish("tfootFontColor", null, "html-color", "Table body font color", null, { tags: ["Basic"], optional: true });
1066
- Table.prototype.publish("theadFontFamily", null, "string", "Table head font family", null, { tags: ["Basic"], optional: true });
1067
- Table.prototype.publish("tbodyFontFamily", null, "string", "Table body font family", null, { tags: ["Basic"], optional: true });
1068
- Table.prototype.publish("tfootFontFamily", null, "string", "Table body font family", null, { tags: ["Basic"], optional: true });
1069
-
1070
- Table.prototype.publish("theadCellBorderColor", null, "html-color", "Table head cell border color", null, { tags: ["Basic"], optional: true });
1071
- Table.prototype.publish("tfootCellBorderColor", null, "html-color", "Table head cell border color", null, { tags: ["Basic"], optional: true });
1072
- Table.prototype.publish("theadRowBackgroundColor", null, "html-color", "Table head row color", null, { tags: ["Basic"], optional: true });
1073
- Table.prototype.publish("tfootRowBackgroundColor", null, "html-color", "Table head row color", null, { tags: ["Basic"], optional: true });
1074
-
1075
- Table.prototype.publish("tbodyCellBorderColor", null, "html-color", "Table body cell border color", null, { tags: ["Basic"], optional: true });
1076
-
1077
- Table.prototype.publish("tbodyRowBackgroundColor", null, "html-color", "Table body row color", null, { tags: ["Basic"], optional: true });
1078
- Table.prototype.publish("tbodyFirstColFontColor", null, "html-color", "Table body first column font color", null, { tags: ["Basic"], optional: true });
1079
- Table.prototype.publish("tbodyFirstColBackgroundColor", null, "html-color", "Table body first column background color", null, { tags: ["Basic"], optional: true });
1080
-
1081
- Table.prototype.publish("tbodyHoverRowFontColor", null, "html-color", "Table body hover row font color", null, { tags: ["Basic"], optional: true });
1082
- Table.prototype.publish("tbodyHoverRowBackgroundColor", null, "html-color", "Table body hover row background color", null, { tags: ["Basic"], optional: true });
1083
-
1084
- Table.prototype.publish("tbodySelectedRowFontColor", null, "html-color", "Table body selected row color", null, { tags: ["Basic"], optional: true });
1085
- Table.prototype.publish("tbodySelectedRowBackgroundColor", null, "html-color", "Table body selected row color", null, { tags: ["Basic"], optional: true });
1086
- Table.prototype.publish("tableZebraColor", null, "html-color", "Table zebra row color", null, { tags: ["Basic"], optional: true });
1087
- Table.prototype.publish("totalledColumns", [], "array", "Array of indices of the columns to be totalled", null, { tags: ["Basic"], optional: true, disable: (w: any) => w.pivot() });
1088
- Table.prototype.publish("totalledLabel", null, "string", "Adds a label to the first column of the 'Totalled' row", null, { tags: ["Basic"], optional: true, disable: (w: any) => w.pivot() });
1089
- Table.prototype.publish("hiddenColumns", [], "array", "Array of indices of the columns to be hidden", null, { tags: ["Basic"], optional: true, disable: (w) => w.pivot() });
1090
-
1091
- Table.prototype.publish("stringAlign", "left", "set", "Cell alignment for strings", ["left", "right", "center"], { tags: ["Basic"], optional: true });
1092
- Table.prototype.publish("numberAlign", "right", "set", "Cell alignment for numbers", ["left", "right", "center"], { tags: ["Basic"], optional: true });
1093
- Table.prototype.publish("verticalAlign", null, "set", "Cell vertical alignment", [null, "middle", "top", "bottom"], { tags: ["Basic"], optional: true });
1094
-
1095
- Table.prototype.publish("minWidgetWidth", 320, "number", "Minimum width of a child widget", null, { tags: ["Basic"], optional: true });
1096
- Table.prototype.publish("minWidgetHeight", 240, "number", "Minimum height of a child widget", null, { tags: ["Basic"], optional: true });
1097
-
1098
- Table.prototype.publish("sortByFieldIndex", null, "number", "Index for the field/column to sort the data", null, { tags: ["Basic"], optional: true });
1099
- Table.prototype.publish("descending", false, "boolean", "Direction for sorting the data: ascending (true) or descending (false)", null, { tags: ["Basic"], optional: true });
1
+ import { d3Event, HTMLWidget, Platform, select as d3Select, selectAll as d3SelectAll, Utility, Widget } from "@hpcc-js/common";
2
+ import { Paginator } from "./Paginator.ts";
3
+
4
+ import "../src/Table.css";
5
+
6
+ export class Table extends HTMLWidget {
7
+ protected _paginator;
8
+ protected _selectionBag;
9
+ protected _selectionPrevClick;
10
+ protected _paginatorTableSpacing;
11
+
12
+ tableDiv;
13
+ thead;
14
+ table;
15
+ fixedHead;
16
+ fixedHeadTable;
17
+ fixedThead;
18
+ unfixedThead;
19
+ tbody;
20
+ tfoot;
21
+ fixedCol;
22
+ fixedColTable;
23
+ fixedColHead;
24
+ fixedColHeadRow;
25
+ fixedColBody;
26
+ fixedColFoot;
27
+ fixedColFootRow;
28
+ protected _prevDescending;
29
+ protected _prevSortByFieldIndex;
30
+ protected _hasChildWidgets;
31
+ protected _tNumPages;
32
+ protected _empty_col_idx_arr: any[];
33
+
34
+ constructor() {
35
+ super();
36
+ this._tag = "div";
37
+ this.columns([]);
38
+ this._paginator = new Paginator();
39
+ this._selectionBag = new Utility.Selection(this);
40
+ this._selectionPrevClick = null;
41
+ this._paginatorTableSpacing = 4;
42
+ }
43
+
44
+ size(): any;
45
+ size(_): Widget;
46
+ size(_?): any | Widget {
47
+ const retVal = super.size.apply(this, arguments);
48
+ if (arguments.length) {
49
+ if (this.tableDiv) {
50
+ const topMargin = this.showHeader() && this.fixedHeader() ? this.thead.property("offsetHeight") : 0;
51
+ this.tableDiv
52
+ .style("width", this._size.width + "px")
53
+ .style("height", this._size.height - topMargin + "px")
54
+ ;
55
+ this._element
56
+ .style("width", this._size.width + "px")
57
+ .style("height", this._size.height + "px")
58
+ ;
59
+ }
60
+ }
61
+
62
+ return retVal;
63
+ }
64
+
65
+ isHidden(colIdx) {
66
+ if (this.pivot()) return false;
67
+ if (this.hiddenColumns().indexOf(colIdx) !== -1) return true;
68
+ const fields = this.fields();
69
+ if (fields && fields[colIdx] && (fields[colIdx].type() === "hidden" || this._empty_col_idx_arr.indexOf(colIdx) !== -1)) {
70
+ return true;
71
+ }
72
+ return false;
73
+ }
74
+
75
+ tableColumns(_?: string[]): string[] {
76
+ const retVal = this.columns.apply(this, arguments);
77
+ if (!arguments.length && this.pivot()) {
78
+ return this._db.column(0);
79
+ }
80
+ return retVal;
81
+ }
82
+
83
+ tableData(_?) {
84
+ const retVal = this.data.apply(this, arguments);
85
+ if (!arguments.length && this.pivot()) {
86
+ return this._db.columns().filter(function (col, idx) { return idx > 0; });
87
+ }
88
+ return retVal;
89
+ }
90
+
91
+ field(rowIdx, colIdx) {
92
+ const noTransform = { transform: d => d };
93
+ if (this.pivot()) {
94
+ if (colIdx === 0) return noTransform;
95
+ return this.fields()[rowIdx + 1];
96
+ }
97
+ if (rowIdx === -1) return noTransform;
98
+ return this.fields()[colIdx];
99
+ }
100
+
101
+ calcFieldsIndex(colIdx) {
102
+ let i = -1;
103
+ let offset = 0;
104
+ const colLen = this.columns().length;
105
+ let visibleCount = 0;
106
+ while (i < colLen && visibleCount <= colIdx) {
107
+ i++;
108
+ if (this.isHidden(i)) {
109
+ offset++;
110
+ } else {
111
+ visibleCount++;
112
+ }
113
+ }
114
+ return colIdx + offset;
115
+ }
116
+
117
+ getEmptyColumnIdxArr(columns, data) {
118
+ const ret_arr = [];
119
+ if (this.hideEmptyColumns()) {
120
+ for (let col_idx = 0; col_idx < columns.length; col_idx++) {
121
+ let column_is_empty = true;
122
+ for (let row_idx = 0; row_idx < data.length; row_idx++) {
123
+ if (["", null, undefined].indexOf(data[row_idx][col_idx]) === -1) {
124
+ column_is_empty = false;
125
+ break;
126
+ }
127
+ }
128
+ if (column_is_empty) {
129
+ ret_arr.push(col_idx);
130
+ }
131
+ }
132
+ }
133
+ return ret_arr;
134
+ }
135
+
136
+ enter(domNode, element) {
137
+ super.enter(domNode, element);
138
+ this._placeholderElement.style("overflow", "hidden");
139
+
140
+ this.tableDiv = element.append("div").attr("class", "tableDiv");
141
+ this.table = this.tableDiv.append("table");
142
+ this.fixedHead = element.append("div").classed("header-wrapper", true);
143
+ this.fixedHeadTable = this.fixedHead.append("table");
144
+ this.fixedThead = this.fixedHeadTable.append("thead").append("tr");
145
+ this.unfixedThead = this.table.append("thead").append("tr");
146
+ this.tbody = this.table.append("tbody");
147
+ this.tfoot = this.table.append("tfoot").append("tr");
148
+ this.fixedCol = element.append("div").classed("rows-wrapper", true);
149
+ this.fixedColTable = this.fixedCol.append("table");
150
+ this.fixedColHead = this.fixedColTable.append("thead");
151
+ this.fixedColHeadRow = this.fixedColHead.append("tr");
152
+ this.fixedColBody = this.fixedColTable.append("tbody");
153
+ this.fixedColFoot = this.fixedColTable.append("tfoot");
154
+ this.fixedColFootRow = this.fixedColFoot.append("tr");
155
+
156
+ this.tableDiv
157
+ .style("overflow", "auto")
158
+ ;
159
+ }
160
+
161
+ update(domNode, element) {
162
+ super.update(domNode, element);
163
+ const context = this;
164
+ const columns = context.tableColumns();
165
+ const data = context.tableData();
166
+ const scrollLeft = this.tableDiv.node().scrollLeft;
167
+ this._empty_col_idx_arr = this.getEmptyColumnIdxArr(columns, data);
168
+
169
+ this.element().selectAll("table,tbody,th,td").style("width", null);
170
+
171
+ if (this.sortByFieldIndex_exists() && (this._prevSortByFieldIndex !== this.sortByFieldIndex() || this._prevDescending !== this.descending())) {
172
+ Utility.multiSort(data, [{ idx: this.sortByFieldIndex(), reverse: this.descending() }]);
173
+ this._prevSortByFieldIndex = this.sortByFieldIndex();
174
+ this._prevDescending = this.descending();
175
+ }
176
+
177
+ this._hasChildWidgets = false;
178
+
179
+ if (this.fixedHeader()) {
180
+ this.thead = this.fixedThead;
181
+ } else {
182
+ this.thead = this.unfixedThead;
183
+ }
184
+ this.fixedHead.style("display", this.fixedHeader() ? "table-row" : "none");
185
+ this.unfixedThead.style("display", this.fixedHeader() ? "none" : "table-row");
186
+
187
+ const thSel = this.thead.selectAll("th").data(this.showHeader() ? columns.filter(function (col, idx) {
188
+ return !context.isHidden(idx) && context._empty_col_idx_arr.indexOf(idx) === -1;
189
+ }) : []);
190
+ const thUpdate = thSel.enter().append("th")
191
+ .each(function (d) {
192
+ const element2 = d3Select(this);
193
+ element2
194
+ .append("span")
195
+ .attr("class", "thText")
196
+ ;
197
+ element2
198
+ .append("span")
199
+ .attr("class", "thIcon")
200
+ ;
201
+ })
202
+ .on("click", function (column, idx) {
203
+ context.headerClick(column, idx);
204
+ })
205
+ .merge(thSel)
206
+ .style("background-color", this.theadRowBackgroundColor())
207
+ .style("border-color", this.theadCellBorderColor())
208
+ .style("color", this.theadFontColor())
209
+ .style("font-size", this.theadFontSize())
210
+ ;
211
+ thUpdate.select(".thText")
212
+ .style("font-family", this.theadFontFamily())
213
+ .text(function (column, idx) {
214
+ const fieldsIdx = context.calcFieldsIndex(idx);
215
+ return context.field(-1, fieldsIdx).transform(column);
216
+ })
217
+ ;
218
+ thUpdate.select(".thIcon")
219
+ .text(function (column, idx) {
220
+ if (context.descending()) {
221
+ return context.sortByFieldIndex() === idx ? "\uf078" : "";
222
+ } else {
223
+ return context.sortByFieldIndex() === idx ? "\uf077" : "";
224
+ }
225
+ })
226
+ ;
227
+ thSel.exit()
228
+ .remove()
229
+ ;
230
+ thUpdate.order();
231
+
232
+ if (this.paginationLimit()) {
233
+ this.pagination(data.length >= parseInt(this.paginationLimit()) ? true : false);
234
+ }
235
+ if (this.pagination()) {
236
+ if (this._paginator.target() === null) {
237
+ this._paginator.target(element.node());
238
+ }
239
+
240
+ const ipp = this._calcRowsPerPage(thUpdate);
241
+ this.itemsPerPage(ipp);
242
+
243
+ this._paginator.numItems(data.length);
244
+ this._tNumPages = Math.ceil(this._paginator.numItems() / this.itemsPerPage()) || 1;
245
+ if (this.pageNumber() > this._tNumPages || this.pageNumber() <= 0) { this.pageNumber(1); } // resets if current pagenum selected out of range
246
+
247
+ this._paginator._onSelect = function (p, d) {
248
+ context.pageNumber(p);
249
+ context.render();
250
+ return;
251
+ };
252
+ } else {
253
+ this._paginator.numItems(0); // remove widget
254
+ }
255
+
256
+ // pageNumber starts at index 1
257
+ const startIndex = this.pageNumber() - 1;
258
+ const itemsOnPage = this.itemsPerPage();
259
+
260
+ const start = startIndex * itemsOnPage;
261
+ const end = startIndex * parseInt(itemsOnPage) + parseInt(itemsOnPage);
262
+
263
+ let tData = null;
264
+
265
+ if (this.topN()) {
266
+ tData = data.slice(0, this.topN());
267
+ } else if (this.pagination()) {
268
+ tData = data.slice(start, end);
269
+ } else {
270
+ tData = data;
271
+ }
272
+
273
+ const totalRow: any[] = [this.totalledLabel() ? this.totalledLabel() : null];
274
+ if (this.totalledColumns().length !== 0) {
275
+ for (let i = 0; i < this.totalledColumns().length; i++) this.totalledColumns()[i] = +this.totalledColumns()[i];
276
+ for (let j = 1; j < columns.length; j++) {
277
+ let sum = 0;
278
+ if (this.totalledColumns().indexOf(j) !== -1) {
279
+ for (let k = 0; k < tData.length; k++) {
280
+ sum = sum + tData[k][j];
281
+ }
282
+ totalRow.push(sum);
283
+ } else {
284
+ totalRow.push("");
285
+ }
286
+ }
287
+
288
+ const tfSel = this.tfoot.selectAll("td").data(totalRow);
289
+ tfSel.enter()
290
+ .append("td")
291
+ .merge(tfSel)
292
+ .style("background-color", this.tfootRowBackgroundColor())
293
+ .style("border-color", this.tfootCellBorderColor())
294
+ .style("color", this.tfootFontColor())
295
+ .style("font-size", this.tfootFontSize())
296
+ [this.renderHtmlDataCells() ? "html" : "text"](function (d, idx) {
297
+ return context.fields()[idx].transform(d);
298
+ });
299
+ tfSel.exit()
300
+ .remove()
301
+ ;
302
+ }
303
+
304
+ const rowsSel = this.tbody.selectAll("tr.tr_" + this.id()).data(tData.map(function (d, idx) {
305
+ // TODO - Move fix closer to data source?
306
+ for (let i = 0; i < d.length; ++i) {
307
+ if (d[i] === undefined) {
308
+ d[i] = null;
309
+ }
310
+ }
311
+ return {
312
+ rowIdx: idx,
313
+ row: d
314
+ };
315
+ }));
316
+ const rowsUpdate = rowsSel.enter().append("tr")
317
+ .attr("class", "tr_" + this.id())
318
+ .on("click.selectionBag", function (_d) {
319
+ if (_d.row) {
320
+ const d = _d.row;
321
+ const i = _d.rowIdx;
322
+ context.selectionBagClick(d, i);
323
+ context.applyRowStyles(context.getBodyRow(i));
324
+ context.applyFirstColRowStyles(context.getFixedRow(i));
325
+ }
326
+ }, true) // capture=true: event is caught on the way down the DOM before the cell click.
327
+ .on("mouseover", function (_d) {
328
+ if (_d.row) {
329
+ const i = _d.rowIdx;
330
+ const fixedLeftRows = context.getFixedRow(i);
331
+ if (!fixedLeftRows.empty()) {
332
+ fixedLeftRows.classed("hover", true);
333
+ }
334
+ const tbodyRows = context.getBodyRow(i);
335
+ tbodyRows.classed("hover", true);
336
+ context.applyStyleToRows(tbodyRows);
337
+ context.applyFirstColRowStyles(fixedLeftRows);
338
+ }
339
+ })
340
+ .on("mouseout", function (_d) {
341
+ if (_d.row) {
342
+ const i = _d.rowIdx;
343
+ const fixedLeftRows = context.getFixedRow(i);
344
+ fixedLeftRows.classed("hover", false);
345
+ const tbodyRows = context.getBodyRow(i);
346
+ tbodyRows.classed("hover", false);
347
+ context.applyStyleToRows(tbodyRows);
348
+ context.applyFirstColRowStyles(fixedLeftRows);
349
+ }
350
+ })
351
+ .merge(rowsSel)
352
+ .classed("selected", function (_d) {
353
+ const d = _d.row;
354
+ return context._selectionBag.isSelected(context._createSelectionObject(d));
355
+ })
356
+ .classed("trId" + this._id, true)
357
+ ;
358
+ rowsSel.exit()
359
+ .remove()
360
+ ;
361
+ this.applyStyleToRows(rowsUpdate);
362
+
363
+ const cellsSel = rowsUpdate.selectAll(".td_" + this.id()).data(function (_d, _trIdx) {
364
+ return _d.row.filter(function (cell, idx) {
365
+ return idx < columns.length && !context.isHidden(idx) && context._empty_col_idx_arr.indexOf(idx) === -1;
366
+ }).map(function (cell, idx) {
367
+ return {
368
+ rowInfo: _d,
369
+ colIdx: idx,
370
+ cell
371
+ };
372
+ });
373
+ });
374
+ cellsSel.enter()
375
+ .append("td")
376
+ .attr("class", "td_" + this.id())
377
+ .on("click", function (tdContents) {
378
+ if (tdContents.rowInfo) {
379
+ context.click(context.rowToObj(tdContents.rowInfo.row), context.columns()[tdContents.colIdx], context._selectionBag.isSelected(context._createSelectionObject(tdContents.rowInfo.row)));
380
+ }
381
+ })
382
+ .on("dblclick", function (tdContents, idx) {
383
+ if (tdContents.rowInfo) {
384
+ context.dblclick(context.rowToObj(tdContents.rowInfo.row), context.columns()[tdContents.colIdx], context._selectionBag.isSelected(context._createSelectionObject(tdContents.rowInfo.row)));
385
+ }
386
+ })
387
+ .each(function (tdContents, tdIdx) {
388
+ const alignment = context.getColumnAlignment(tdContents.rowInfo.rowIdx, tdContents.colIdx, tdContents.cell);
389
+ const el = d3Select(this);
390
+ el
391
+ .style("height", null)
392
+ .style("text-align", alignment)
393
+ .style("vertical-align", context.verticalAlign())
394
+ .classed("tr-" + tdContents.rowInfo.rowIdx + "-td-" + tdIdx, true)
395
+ ;
396
+ })
397
+ .merge(cellsSel)
398
+ .each(function (tdContents) {
399
+ const el = d3Select(this);
400
+ if (tdContents.cell instanceof Widget) {
401
+ el[context.renderHtmlDataCells() ? "html" : "text"](null);
402
+ const widgetDiv = el.selectAll(".div_" + context.id()).data([tdContents.cell], function (d: any) { return d.id(); });
403
+ widgetDiv.exit()
404
+ .each(function (d: any) {
405
+ d.target(null);
406
+ })
407
+ .remove()
408
+ ;
409
+ widgetDiv.enter().append("div")
410
+ .attr("class", "div_" + context.id())
411
+ .style("width", context.minWidgetWidth() + "px")
412
+ .style("height", context.minWidgetHeight() + "px")
413
+ .each(function (d) {
414
+ const widgetDiv2 = d3Select(this);
415
+ d._parentWidget = context;
416
+ if (d._class.indexOf("childWidget") < 0) {
417
+ d._class = "childWidget " + d._class;
418
+ }
419
+ d
420
+ .target(null)
421
+ .target(widgetDiv2.node())
422
+ ;
423
+ })
424
+ .merge(widgetDiv as any)
425
+ .each(function (d) {
426
+ d
427
+ .resize()
428
+ .lazyRender()
429
+ ;
430
+ context._hasChildWidgets = true;
431
+ })
432
+ ;
433
+ } else {
434
+ el.selectAll(".div_" + context.id()).remove();
435
+ const fieldsIdx = context.calcFieldsIndex(tdContents.colIdx);
436
+ el[context.renderHtmlDataCells() ? "html" : "text"](
437
+ context.field(tdContents.rowInfo.rowIdx, fieldsIdx).transform(tdContents.cell)
438
+ );
439
+ }
440
+ })
441
+ ;
442
+ cellsSel.exit()
443
+ .remove()
444
+ ;
445
+ const tableMarginHeight = parseInt(this.thead.node().offsetHeight);
446
+
447
+ if (this.pagination() && this._hasChildWidgets) {
448
+ this.tableDiv.style("overflow-y", "auto");
449
+ this.table.style("margin-bottom", "50px");
450
+ console.warn("Warning: displaying another widget in the table may cause problems with pagination");
451
+ } else {
452
+ this.tableDiv.style("overflow-y", null);
453
+ this.table.style("margin-bottom", null);
454
+
455
+ }
456
+ this.size(this._size);
457
+
458
+ let fixedColWidth = 0;
459
+ const fixedColThSel = this.fixedColHeadRow.selectAll("th").data(this.fixedColumn() && this.showHeader() ? [columns[0]] : []);
460
+ const fixedColThUpdate = fixedColThSel.enter().append("th")
461
+ .each(function (d) {
462
+ const element2 = d3Select(this);
463
+ element2
464
+ .append("span")
465
+ .attr("class", "thText")
466
+ ;
467
+ element2
468
+ .append("span")
469
+ .attr("class", "thIcon")
470
+ ;
471
+ })
472
+ .on("click", function (column, idx) {
473
+ context.headerClick(column, idx);
474
+ })
475
+ .merge(fixedColThSel)
476
+ .style("background-color", this.theadRowBackgroundColor())
477
+ .style("border-color", this.theadCellBorderColor())
478
+ .style("color", this.theadFontColor())
479
+ .style("font-size", this.theadFontSize())
480
+ ;
481
+ fixedColThUpdate.select(".thText")
482
+ .style("font-family", this.theadFontFamily())
483
+ .text(function (column) {
484
+ return column;
485
+ })
486
+ ;
487
+ fixedColThUpdate.select(".thIcon")
488
+ .text(function (column, idx) {
489
+ if (context.descending()) {
490
+ return context.sortByFieldIndex() === idx ? "\uf078" : "";
491
+ } else {
492
+ return context.sortByFieldIndex() === idx ? "\uf077" : "";
493
+ }
494
+ })
495
+ ;
496
+ fixedColThSel.exit()
497
+ .remove()
498
+ ;
499
+
500
+ const fixedColTrSel = this.fixedColBody.selectAll("tr").data(this.fixedColumn() ? tData : []);
501
+ const fixedColTrUpdate = fixedColTrSel.enter().append("tr")
502
+ .attr("class", function () {
503
+ return "trId" + context._id;
504
+ })
505
+ .merge(fixedColTrSel)
506
+ .on("click", function (d, i) {
507
+ (d3Select(rowsUpdate[0][i]).on("click.selectionBag") as any)(rowsUpdate.data()[i], i)
508
+ ;
509
+ })
510
+ .on("mouseover", function (d, i) {
511
+ (d3Select(rowsUpdate[0][i]).on("mouseover") as any)(rowsUpdate.data()[i], i)
512
+ ;
513
+ })
514
+ .on("mouseout", function (d, i) {
515
+ (d3Select(rowsUpdate[0][i]).on("mouseout") as any)(rowsUpdate.data()[i], i)
516
+ ;
517
+ })
518
+ .classed("selected", function (d) {
519
+ return context._selectionBag.isSelected(context._createSelectionObject(d));
520
+ })
521
+ ;
522
+ fixedColTrSel.exit()
523
+ .remove()
524
+ ;
525
+ const fixedColTdSel = fixedColTrUpdate.selectAll("td").data(function (d, i) {
526
+ return [d[0]];
527
+ });
528
+ const fixedColTdUpdate = fixedColTdSel.enter().append("td")
529
+ .merge(fixedColTdSel)[this.renderHtmlDataCells() ? "html" : "text"](function (d): any {
530
+ if (typeof (d) === "string") {
531
+ return d.trim();
532
+ } else if (typeof (d) === "number") {
533
+ return d;
534
+ }
535
+ return "";
536
+ });
537
+ fixedColTdSel.exit()
538
+ .remove()
539
+ ;
540
+
541
+ const fixedColFootTdSel = this.fixedColFootRow.selectAll("td").data(this.fixedColumn() && this.totalledLabel() ? [this.totalledLabel()] : []);
542
+ const fixedColFootTdUpdate = fixedColFootTdSel.enter().append("td")
543
+ .merge(fixedColFootTdSel)[this.renderHtmlDataCells() ? "html" : "text"](function (d): any {
544
+ if (typeof (d) === "string") {
545
+ return d.trim();
546
+ } else if (typeof (d) === "number") {
547
+ return d;
548
+ }
549
+ return "";
550
+ });
551
+ fixedColFootTdSel.exit()
552
+ .remove()
553
+ ;
554
+
555
+ if (this.fixedColumn() && !this.fixedSize() && fixedColFootTdUpdate.length) {
556
+ if (this.showHeader()) {
557
+ fixedColWidth = fixedColFootTdUpdate.property("offsetWidth") > fixedColFootTdUpdate.property("offsetWidth") ? fixedColFootTdUpdate.property("offsetWidth") : fixedColFootTdUpdate.property("offsetWidth");
558
+ } else {
559
+ fixedColWidth = fixedColFootTdUpdate.property("offsetWidth");
560
+ }
561
+ this.fixedCol
562
+ .style("position", "absolute")
563
+ .style("margin-top", -this.tableDiv.property("scrollTop") + tableMarginHeight + "px")
564
+ ;
565
+ fixedColTdUpdate
566
+ .style("width", fixedColWidth + "px")
567
+ ;
568
+ this.fixedColHead
569
+ .style("position", "absolute")
570
+ .style("margin-top", (this.fixedHeader() ? this.tableDiv.property("scrollTop") : 0) - tableMarginHeight + "px")
571
+ ;
572
+ fixedColThUpdate
573
+ .style("width", fixedColWidth + "px")
574
+ ;
575
+ rowsUpdate.each(function (d, i) {
576
+ const height = d3Select(this).select("td").property("offsetHeight");
577
+ d3Select(fixedColTdUpdate[i][0]).style("height", height + "px");
578
+ });
579
+ }
580
+
581
+ this.table
582
+ .style("margin-left", -fixedColWidth + "px")
583
+ ;
584
+ this.tableDiv
585
+ .style("margin-left", fixedColWidth + "px")
586
+ .style("width", this.width() - fixedColWidth + "px")
587
+ ;
588
+
589
+ if (!rowsUpdate.empty()) this.setColumnWidths(rowsUpdate);
590
+
591
+ let box;
592
+ let newTableHeight;
593
+ let finalWidth;
594
+ let maxWidth;
595
+ if (this.fixedSize()) {
596
+ const node = d3Select(".tableDiv > table").node();
597
+ if (node) {
598
+ box = (node as any).getBoundingClientRect();
599
+ let newTableHeight;
600
+ let finalWidth;
601
+ if (box.width !== 0 && box.height !== 0) {
602
+ calcWidth();
603
+ calcHeight();
604
+ } else {
605
+ if (box.height - tableMarginHeight <= context.tableDiv.property("offsetHeight")) {
606
+ calcHeight();
607
+ } else {
608
+ if (context.fixedHeader()) {
609
+ newTableHeight = context.tableDiv.property("offsetHeight"); // is tableDiv correct?
610
+ newTableHeight = newTableHeight + "px";
611
+ } else {
612
+ newTableHeight = "100%";
613
+ }
614
+ }
615
+ if (box.width - fixedColWidth < context.tableDiv.property("offsetWidth")) {
616
+ calcWidth();
617
+ } else {
618
+ if (context.fixedColumn()) {
619
+ finalWidth = context.tableDiv.property("offsetWidth") - fixedColWidth; // is tableDiv correct?
620
+ finalWidth = finalWidth + "px";
621
+ } else {
622
+ finalWidth = "100%";
623
+ }
624
+ }
625
+ }
626
+ if (element.classed("childWidget")) {
627
+ context._placeholderElement
628
+ .style("width", finalWidth + "px")
629
+ .style("height", newTableHeight + "px")
630
+ ;
631
+ context.tableDiv
632
+ .style("overflow", "hidden")
633
+ ;
634
+ }
635
+ context.size({ width: finalWidth, height: newTableHeight });
636
+ }
637
+ }
638
+
639
+ this.setOnScrollEvents(this.tableDiv.node(), tableMarginHeight);
640
+
641
+ function calcWidth() {
642
+ const newTableWidth = box.width;
643
+ maxWidth = context.tbody.property("offsetWidth") + 1;
644
+ finalWidth = newTableWidth > maxWidth ? maxWidth : newTableWidth;
645
+ finalWidth = finalWidth;
646
+ }
647
+
648
+ function calcHeight() {
649
+ newTableHeight = context.tbody.property("offsetHeight") + tableMarginHeight;
650
+ newTableHeight = newTableHeight;
651
+ }
652
+
653
+ this._paginator.render();
654
+ setTimeout(function () {
655
+ context._paginator
656
+ .right((context.hasVScroll(element) ? Platform.getScrollbarWidth() : 0) + context._paginatorTableSpacing)
657
+ .bottom((context.hasHScroll(element) ? Platform.getScrollbarWidth() : 0) + context._paginatorTableSpacing)
658
+ .render(function () {
659
+ context.tableDiv.node().scrollLeft = scrollLeft;
660
+ })
661
+ ;
662
+ }, 0);
663
+ }
664
+
665
+ exit(domNode, element) {
666
+ this._paginator.target(null);
667
+ super.exit(domNode, element);
668
+ }
669
+
670
+ setColumnWidths(rows) {
671
+ const context = this;
672
+ const firstRow = rows.filter(function (d, i) { return i === 0; });
673
+
674
+ let tds = d3Select(null);
675
+ firstRow.each(function (d) {
676
+ tds = d3SelectAll(this.childNodes);
677
+ });
678
+
679
+ const tableMarginHeight = this.fixedHeader() ? this.thead.property("offsetHeight") : 0;
680
+ let totalWidth = 1;
681
+ const tdWidths = {};
682
+
683
+ tds.each(function (d, i) {
684
+ tdWidths[i] = (this as any).offsetWidth;
685
+ });
686
+
687
+ const th = this.thead.selectAll("th");
688
+ th.each(function (d, i) {
689
+ const thwidth = this.offsetWidth;
690
+ const tdwidth = tds.empty() ? 0 : tdWidths[i];
691
+ const usewidth = thwidth >= tdwidth ? thwidth : tdwidth;
692
+ this.style.width = usewidth + "px";
693
+ tds
694
+ .filter((_d, idx) => idx === 0)
695
+ .each(function () {
696
+ d3Select(this).style("width", usewidth + "px");
697
+ })
698
+ ;
699
+ totalWidth += usewidth;
700
+ });
701
+ this.thead
702
+ .style("position", this.fixedHeader() ? "absolute" : "relative")
703
+ .style("width", totalWidth + "px")
704
+ .style("margin-top", "0px")
705
+ ;
706
+ this.table
707
+ .style("width", totalWidth + "px")
708
+ ;
709
+ this.tableDiv
710
+ .style("margin-top", (context.fixedHeader() ? tableMarginHeight : 0) + "px")
711
+ ;
712
+ this.tbody
713
+ .style("width", totalWidth + "px")
714
+ ;
715
+ }
716
+
717
+ getBodyRow(i) {
718
+ return this.table.selectAll("tbody tr.trId" + this._id)
719
+ .filter(function (d, idx) {
720
+ return idx === i;
721
+ })
722
+ ;
723
+ }
724
+
725
+ getFixedRow(i) {
726
+ return this._element.selectAll(".rows-wrapper tbody tr")
727
+ .filter(function (d, idx) {
728
+ return idx === i;
729
+ })
730
+ ;
731
+ }
732
+
733
+ setOnScrollEvents(scrollNode, margHeight) {
734
+ const context = this;
735
+ scrollNode.onscroll = function (e) {
736
+ const topDelta = e.target.scrollTop;
737
+ const leftDelta = e.target.scrollLeft;
738
+ if (context.fixedHeader()) {
739
+ context.thead
740
+ .style("margin-left", -leftDelta + "px")
741
+ ;
742
+ }
743
+ if (context.fixedColumn()) {
744
+ context.fixedCol
745
+ .style("margin-top", -topDelta + margHeight + "px")
746
+ ;
747
+ if (context.fixedHeader()) {
748
+ context.fixedColHead
749
+ .style("margin-top", topDelta - margHeight + "px")
750
+ ;
751
+ }
752
+ }
753
+ };
754
+ }
755
+
756
+ _generateTempRow() {
757
+ const trow = this.tbody.append("tr");
758
+ trow.append("td").text("QQQ");
759
+ return trow;
760
+ }
761
+
762
+ _createSelectionObject(d) {
763
+ const context = this;
764
+ return {
765
+ _id: d,
766
+ element: () => context.tbody ? context.tbody.selectAll("tr").filter(function (d2) { return d2 === d; }) : d3Select(null)
767
+ };
768
+ }
769
+
770
+ _calcRowsPerPage(th) {
771
+ if (this._paginator.numItems() === 0) { // only run on first render
772
+ this._paginator.numItems(1);
773
+ this.itemsPerPage(1);
774
+ }
775
+ this._paginator.render();
776
+
777
+ const thHeight = this.thead.selectAll("th").node() ? this.thead.selectAll("th").node().clientHeight : 0;
778
+ const tfootHeight = this.tfoot.selectAll("td").node() ? this.tfoot.selectAll("td").node().clientHeight : 0;
779
+ const tmpRow = this._generateTempRow();
780
+ const tcellHeight = tmpRow.node().clientHeight;
781
+ tmpRow.remove();
782
+ const paginatorHeight = this.calcHeight(this._paginator.element());
783
+ let ipp = Math.floor((this.height() - thHeight - tfootHeight - paginatorHeight - (this.table.style("width") >= this.table.style("width") ? Platform.getScrollbarWidth() : 0) - this._paginatorTableSpacing * 2) / tcellHeight) || 1;
784
+ if (this.totalledColumns().length !== 0) {
785
+ ipp -= 1;
786
+ }
787
+ return ipp;
788
+ }
789
+
790
+ sort(idx) {
791
+ if (this.sortByFieldIndex() !== idx) {
792
+ this.descending(false);
793
+ } else {
794
+ this.descending(!this.descending());
795
+ }
796
+ this.sortByFieldIndex(idx);
797
+
798
+ return this;
799
+ }
800
+
801
+ selection(_) {
802
+ if (!arguments.length) return this._selectionBag.get().map(function (d) { return d._id; });
803
+ this._selectionBag.set(_.map(function (row) {
804
+ return this._createSelectionObject(row);
805
+ }, this));
806
+ return this;
807
+ }
808
+
809
+ selectionBagClick(d, i) {
810
+ if (this.multiSelect() && d3Event().shiftKey && this._selectionPrevClick) {
811
+ let inRange = false;
812
+ const rows = [];
813
+ const selection = this.tableData().filter(function (row, i2) {
814
+ let lastInRangeRow = false;
815
+ if (row === d || row === this._selectionPrevClick) {
816
+ if (inRange) {
817
+ lastInRangeRow = true;
818
+ }
819
+ inRange = !inRange;
820
+ rows.push(i2);
821
+ }
822
+ return inRange || lastInRangeRow;
823
+ }, this);
824
+ this.selection(selection);
825
+ } else if (this.multiSelect()) {
826
+ this._selectionBag.click(this._createSelectionObject(d), d3Event);
827
+ this._selectionPrevClick = d;
828
+ } else {
829
+ const selObj = this._createSelectionObject(d);
830
+ this._selectionBag.click(selObj, { ctrlKey: this._selectionBag.isSelected(selObj) });
831
+ this._selectionPrevClick = d;
832
+ }
833
+ this.render();
834
+ }
835
+
836
+ applyHoverRowStyles(row) {
837
+ const context = this;
838
+ row
839
+ .style("color", context.tbodyHoverRowFontColor())
840
+ .style("background-color", context.tbodyHoverRowBackgroundColor())
841
+ ;
842
+ }
843
+ applySelectedRowStyles(row) {
844
+ const context = this;
845
+ row
846
+ .style("color", context.tbodySelectedRowFontColor())
847
+ .style("background-color", context.tbodySelectedRowBackgroundColor())
848
+ ;
849
+ }
850
+ applyRowStyles(row, isFirstCol: boolean = false) {
851
+ const dataRow = row.datum().row;
852
+ row
853
+ .style("color", isFirstCol ? this.tbodyFirstColFontColor() : this.tbodyFontColor())
854
+ .style("background-color", isFirstCol ? this.tbodyFirstColBackgroundColor() : this.tableZebraColor_exists() && this.tableData().indexOf(dataRow) % 2 ? this.tbodyRowBackgroundColor() : this.tableZebraColor())
855
+ ;
856
+ }
857
+ applyFirstColRowStyles(rows) {
858
+ this.applyStyleToRows(rows, true);
859
+ }
860
+ applyStyleToRows(rows, isFirstCol: boolean = false) {
861
+ isFirstCol = typeof isFirstCol !== "undefined" ? isFirstCol : false;
862
+ const context = this;
863
+ rows.each(function () {
864
+ const tr = d3Select(this);
865
+ if (tr.classed("hover")) {
866
+ context.applyHoverRowStyles(tr);
867
+ } else if (tr.classed("selected")) {
868
+ context.applySelectedRowStyles(tr);
869
+ } else {
870
+ context.applyRowStyles(tr, isFirstCol);
871
+ }
872
+ })
873
+ ;
874
+ }
875
+
876
+ getColumnAlignment(rowIdx, colIdx, cell) {
877
+ const fieldsIdx = this.calcFieldsIndex(colIdx);
878
+ const field = this.field(rowIdx, fieldsIdx);
879
+ switch ((field as any).__prop_type) {
880
+ case "string":
881
+ return this.stringAlign();
882
+ case "number":
883
+ return this.numberAlign();
884
+ case "":
885
+ case undefined:
886
+ switch (typeof cell) {
887
+ case "string":
888
+ return this.stringAlign();
889
+ case "number":
890
+ return this.numberAlign();
891
+ }
892
+ }
893
+ return null;
894
+ }
895
+
896
+ serializeState() {
897
+ return {
898
+ selection: this._selectionBag.get().map(function (d) {
899
+ return d._id;
900
+ }),
901
+ data: this.data()
902
+ };
903
+ }
904
+
905
+ deserializeState(state) {
906
+ if (state) {
907
+ if (state.selection) {
908
+ const context = this;
909
+ this._selectionBag.set(state.selection.map(function (d) {
910
+ return context._createSelectionObject(d);
911
+ }));
912
+ }
913
+ if (state.data) {
914
+ this.data(state.data);
915
+ }
916
+ }
917
+ return this;
918
+ }
919
+
920
+ click(row, column, selected) {
921
+ }
922
+
923
+ dblclick(row, column, selected) {
924
+ }
925
+
926
+ headerClick(column, idx) {
927
+ this
928
+ .sort(idx)
929
+ .render()
930
+ ;
931
+ }
932
+ }
933
+ Table.prototype._class += " other_Table";
934
+
935
+ export interface Table {
936
+ renderHtmlDataCells(): boolean;
937
+ renderHtmlDataCells(_: boolean): this;
938
+ pagination(): boolean;
939
+ pagination(_: boolean): this;
940
+ paginationLimit(): any;
941
+ paginationLimit(_: any): this;
942
+ itemsPerPage(): any;
943
+ itemsPerPage(_: any): this;
944
+ pageNumber(): number;
945
+ pageNumber(_: number): this;
946
+ adjacentPages(): number;
947
+ adjacentPages(_: number): this;
948
+ topN(): number;
949
+ topN(_: number): this;
950
+ pivot(): boolean;
951
+ pivot(_: boolean): this;
952
+ showHeader(): boolean;
953
+ showHeader(_: boolean): this;
954
+ fixedHeader(): boolean;
955
+ fixedHeader(_: boolean): this;
956
+ fixedColumn(): boolean;
957
+ fixedColumn(_: boolean): this;
958
+ multiSelect(): boolean;
959
+ multiSelect(_: boolean): this;
960
+
961
+ fixedSize(): boolean;
962
+ fixedSize(_: boolean): this;
963
+
964
+ hideEmptyColumns(): boolean;
965
+ hideEmptyColumns(_: boolean): this;
966
+
967
+ theadFontSize(): string;
968
+ theadFontSize(_: string): this;
969
+ tbodyFontSize(): string;
970
+ tbodyFontSize(_: string): this;
971
+ tfootFontSize(): string;
972
+ tfootFontSize(_: string): this;
973
+ theadFontColor(): string;
974
+ theadFontColor(_: string): this;
975
+ tbodyFontColor(): string;
976
+ tbodyFontColor(_: string): this;
977
+ tfootFontColor(): string;
978
+ tfootFontColor(_: string): this;
979
+ theadFontFamily(): string;
980
+ theadFontFamily(_: string): this;
981
+ tbodyFontFamily(): string;
982
+ tbodyFontFamily(_: string): this;
983
+ tfootFontFamily(): string;
984
+ tfootFontFamily(_: string): this;
985
+
986
+ theadCellBorderColor(): string;
987
+ theadCellBorderColor(_: string): this;
988
+ tfootCellBorderColor(): string;
989
+ tfootCellBorderColor(_: string): this;
990
+ theadRowBackgroundColor(): string;
991
+ theadRowBackgroundColor(_: string): this;
992
+ tfootRowBackgroundColor(): string;
993
+ tfootRowBackgroundColor(_: string): this;
994
+
995
+ tbodyCellBorderColor(): string;
996
+ tbodyCellBorderColor(_: string): this;
997
+
998
+ tbodyRowBackgroundColor(): string;
999
+ tbodyRowBackgroundColor(_: string): this;
1000
+ tbodyFirstColFontColor(): string;
1001
+ tbodyFirstColFontColor(_: string): this;
1002
+ tbodyFirstColBackgroundColor(): string;
1003
+ tbodyFirstColBackgroundColor(_: string): this;
1004
+
1005
+ tbodyHoverRowFontColor(): string;
1006
+ tbodyHoverRowFontColor(_: string): this;
1007
+ tbodyHoverRowBackgroundColor(): string;
1008
+ tbodyHoverRowBackgroundColor(_: string): this;
1009
+
1010
+ tbodySelectedRowFontColor(): string;
1011
+ tbodySelectedRowFontColor(_: string): this;
1012
+ tbodySelectedRowBackgroundColor(): string;
1013
+ tbodySelectedRowBackgroundColor(_: string): this;
1014
+ tableZebraColor(): string;
1015
+ tableZebraColor(_: string): this;
1016
+ tableZebraColor_exists(): boolean;
1017
+ totalledColumns(): any[];
1018
+ totalledColumns(_: any[]): this;
1019
+ totalledLabel(): string;
1020
+ totalledLabel(_: string): this;
1021
+ hiddenColumns(): any[];
1022
+ hiddenColumns(_: any[]): this;
1023
+
1024
+ stringAlign(): string;
1025
+ stringAlign(_: string): this;
1026
+ numberAlign(): string;
1027
+ numberAlign(_: string): this;
1028
+ verticalAlign(): string;
1029
+ verticalAlign(_: string): this;
1030
+
1031
+ minWidgetWidth(): number;
1032
+ minWidgetWidth(_: number): this;
1033
+ minWidgetHeight(): number;
1034
+ minWidgetHeight(_: number): this;
1035
+
1036
+ sortByFieldIndex(): number;
1037
+ sortByFieldIndex(_: number): this;
1038
+ sortByFieldIndex_exists(): boolean;
1039
+ descending(): boolean;
1040
+ descending(_: boolean): this;
1041
+ }
1042
+
1043
+ Table.prototype.publish("renderHtmlDataCells", false, "boolean", "enable or disable HTML within cells", null, { tags: ["Private"] });
1044
+ Table.prototype.publish("pagination", true, "boolean", "Enable or disable pagination", null, { tags: ["Private"] });
1045
+ Table.prototype.publish("paginationLimit", null, "number", "Maximum number of rows allowed before pagination defaults to on", null, { tags: ["Private"] });
1046
+ Table.prototype.publishProxy("itemsPerPage", "_paginator");
1047
+ Table.prototype.publishProxy("pageNumber", "_paginator", "pageNumber", 1);
1048
+ Table.prototype.publishProxy("adjacentPages", "_paginator");
1049
+ Table.prototype.publish("topN", null, "number", "Total number or rows of data to be displayed in the table", null, { tags: ["Private"] });
1050
+ Table.prototype.publish("pivot", false, "boolean", "Pivot Table");
1051
+ Table.prototype.publish("showHeader", true, "boolean", "Show or hide the table header", null, { tags: ["Private"] });
1052
+ Table.prototype.publish("fixedHeader", true, "boolean", "Enable or disable fixed table header", null, { tags: ["Private"] });
1053
+ Table.prototype.publish("fixedColumn", false, "boolean", "Enable or disable fixed first column", null, { tags: ["Private"] });
1054
+ Table.prototype.publish("multiSelect", false, "boolean", "Multiple Selection", null, { tags: ["Basic"] });
1055
+
1056
+ Table.prototype.publish("fixedSize", false, "boolean", "Fix Size to Min Width/Height");
1057
+
1058
+ Table.prototype.publish("hideEmptyColumns", false, "boolean", "Hide columns with all empty cells");
1059
+
1060
+ Table.prototype.publish("theadFontSize", null, "string", "Table head font size", null, { tags: ["Basic"], optional: true });
1061
+ Table.prototype.publish("tbodyFontSize", null, "string", "Table body font size", null, { tags: ["Basic"], optional: true });
1062
+ Table.prototype.publish("tfootFontSize", null, "string", "Table body font size", null, { tags: ["Basic"], optional: true });
1063
+ Table.prototype.publish("theadFontColor", null, "html-color", "Table head font color", null, { tags: ["Basic"], optional: true });
1064
+ Table.prototype.publish("tbodyFontColor", null, "html-color", "Table body font color", null, { tags: ["Basic"], optional: true });
1065
+ Table.prototype.publish("tfootFontColor", null, "html-color", "Table body font color", null, { tags: ["Basic"], optional: true });
1066
+ Table.prototype.publish("theadFontFamily", null, "string", "Table head font family", null, { tags: ["Basic"], optional: true });
1067
+ Table.prototype.publish("tbodyFontFamily", null, "string", "Table body font family", null, { tags: ["Basic"], optional: true });
1068
+ Table.prototype.publish("tfootFontFamily", null, "string", "Table body font family", null, { tags: ["Basic"], optional: true });
1069
+
1070
+ Table.prototype.publish("theadCellBorderColor", null, "html-color", "Table head cell border color", null, { tags: ["Basic"], optional: true });
1071
+ Table.prototype.publish("tfootCellBorderColor", null, "html-color", "Table head cell border color", null, { tags: ["Basic"], optional: true });
1072
+ Table.prototype.publish("theadRowBackgroundColor", null, "html-color", "Table head row color", null, { tags: ["Basic"], optional: true });
1073
+ Table.prototype.publish("tfootRowBackgroundColor", null, "html-color", "Table head row color", null, { tags: ["Basic"], optional: true });
1074
+
1075
+ Table.prototype.publish("tbodyCellBorderColor", null, "html-color", "Table body cell border color", null, { tags: ["Basic"], optional: true });
1076
+
1077
+ Table.prototype.publish("tbodyRowBackgroundColor", null, "html-color", "Table body row color", null, { tags: ["Basic"], optional: true });
1078
+ Table.prototype.publish("tbodyFirstColFontColor", null, "html-color", "Table body first column font color", null, { tags: ["Basic"], optional: true });
1079
+ Table.prototype.publish("tbodyFirstColBackgroundColor", null, "html-color", "Table body first column background color", null, { tags: ["Basic"], optional: true });
1080
+
1081
+ Table.prototype.publish("tbodyHoverRowFontColor", null, "html-color", "Table body hover row font color", null, { tags: ["Basic"], optional: true });
1082
+ Table.prototype.publish("tbodyHoverRowBackgroundColor", null, "html-color", "Table body hover row background color", null, { tags: ["Basic"], optional: true });
1083
+
1084
+ Table.prototype.publish("tbodySelectedRowFontColor", null, "html-color", "Table body selected row color", null, { tags: ["Basic"], optional: true });
1085
+ Table.prototype.publish("tbodySelectedRowBackgroundColor", null, "html-color", "Table body selected row color", null, { tags: ["Basic"], optional: true });
1086
+ Table.prototype.publish("tableZebraColor", null, "html-color", "Table zebra row color", null, { tags: ["Basic"], optional: true });
1087
+ Table.prototype.publish("totalledColumns", [], "array", "Array of indices of the columns to be totalled", null, { tags: ["Basic"], optional: true, disable: (w: any) => w.pivot() });
1088
+ Table.prototype.publish("totalledLabel", null, "string", "Adds a label to the first column of the 'Totalled' row", null, { tags: ["Basic"], optional: true, disable: (w: any) => w.pivot() });
1089
+ Table.prototype.publish("hiddenColumns", [], "array", "Array of indices of the columns to be hidden", null, { tags: ["Basic"], optional: true, disable: (w) => w.pivot() });
1090
+
1091
+ Table.prototype.publish("stringAlign", "left", "set", "Cell alignment for strings", ["left", "right", "center"], { tags: ["Basic"], optional: true });
1092
+ Table.prototype.publish("numberAlign", "right", "set", "Cell alignment for numbers", ["left", "right", "center"], { tags: ["Basic"], optional: true });
1093
+ Table.prototype.publish("verticalAlign", null, "set", "Cell vertical alignment", [null, "middle", "top", "bottom"], { tags: ["Basic"], optional: true });
1094
+
1095
+ Table.prototype.publish("minWidgetWidth", 320, "number", "Minimum width of a child widget", null, { tags: ["Basic"], optional: true });
1096
+ Table.prototype.publish("minWidgetHeight", 240, "number", "Minimum height of a child widget", null, { tags: ["Basic"], optional: true });
1097
+
1098
+ Table.prototype.publish("sortByFieldIndex", null, "number", "Index for the field/column to sort the data", null, { tags: ["Basic"], optional: true });
1099
+ Table.prototype.publish("descending", false, "boolean", "Direction for sorting the data: ascending (true) or descending (false)", null, { tags: ["Basic"], optional: true });