import { HTMLWidget, Platform, Utility, Widget } from "@hpcc-js/common"; import { event as d3Event, select as d3Select, selectAll as d3SelectAll } from "d3-selection"; import { Paginator } from "./Paginator"; import "../src/Table.css"; function replacer(key, value) { if (value instanceof Widget) { return "Widget with class: " + value.classID(); } return value; } export class Table extends HTMLWidget { protected _paginator; protected _selectionBag; protected _selectionPrevClick; protected _paginatorTableSpacing; tableDiv; thead; table; fixedHead; fixedHeadTable; fixedThead; unfixedThead; tbody; tfoot; fixedCol; fixedColTable; fixedColHead; fixedColHeadRow; fixedColBody; fixedColFoot; fixedColFootRow; protected _prevDescending; protected _prevSortByFieldIndex; protected _hasChildWidgets; protected _tNumPages; protected _empty_col_idx_arr: any[]; constructor() { super(); this._tag = "div"; this.columns([]); this._paginator = new Paginator(); this._selectionBag = new Utility.Selection(this); this._selectionPrevClick = null; this._paginatorTableSpacing = 4; } size(): any; size(_): Widget; size(_?): any | Widget { const retVal = super.size.apply(this, arguments); if (arguments.length) { if (this.tableDiv) { const topMargin = this.showHeader() && this.fixedHeader() ? this.thead.property("offsetHeight") : 0; this.tableDiv .style("width", this._size.width + "px") .style("height", this._size.height - topMargin + "px") ; this._element .style("width", this._size.width + "px") .style("height", this._size.height + "px") ; } } return retVal; } isHidden(colIdx) { if (this.pivot()) return false; if (this.hiddenColumns().indexOf(colIdx) !== -1) return true; const fields = this.fields(); if (fields && fields[colIdx] && (fields[colIdx].type() === "hidden" || this._empty_col_idx_arr.indexOf(colIdx) !== -1)) { return true; } return false; } tableColumns(_?: string[]): string[] { const retVal = this.columns.apply(this, arguments); if (!arguments.length && this.pivot()) { return this._db.column(0); } return retVal; } tableData(_?) { const retVal = this.data.apply(this, arguments); if (!arguments.length && this.pivot()) { return this._db.columns().filter(function (col, idx) { return idx > 0; }); } return retVal; } field(rowIdx, colIdx) { const noTransform = { transform: d => d }; if (this.pivot()) { if (colIdx === 0) return noTransform; return this.fields()[rowIdx + 1]; } if (rowIdx === -1) return noTransform; return this.fields()[colIdx]; } calcFieldsIndex(colIdx) { let i = -1; let offset = 0; const colLen = this.columns().length; let visibleCount = 0; while (i < colLen && visibleCount <= colIdx) { i++; if (this.isHidden(i)) { offset++; } else { visibleCount++; } } return colIdx + offset; } getEmptyColumnIdxArr(columns, data) { const ret_arr = []; if (this.hideEmptyColumns()) { for (let col_idx = 0; col_idx < columns.length; col_idx++) { let column_is_empty = true; for (let row_idx = 0; row_idx < data.length; row_idx++) { if (["", null, undefined].indexOf(data[row_idx][col_idx]) === -1) { column_is_empty = false; break; } } if (column_is_empty) { ret_arr.push(col_idx); } } } return ret_arr; } enter(domNode, element) { super.enter(domNode, element); this._placeholderElement.style("overflow", "hidden"); this.tableDiv = element.append("div").attr("class", "tableDiv"); this.table = this.tableDiv.append("table"); this.fixedHead = element.append("div").classed("header-wrapper", true); this.fixedHeadTable = this.fixedHead.append("table"); this.fixedThead = this.fixedHeadTable.append("thead").append("tr"); this.unfixedThead = this.table.append("thead").append("tr"); this.tbody = this.table.append("tbody"); this.tfoot = this.table.append("tfoot").append("tr"); this.fixedCol = element.append("div").classed("rows-wrapper", true); this.fixedColTable = this.fixedCol.append("table"); this.fixedColHead = this.fixedColTable.append("thead"); this.fixedColHeadRow = this.fixedColHead.append("tr"); this.fixedColBody = this.fixedColTable.append("tbody"); this.fixedColFoot = this.fixedColTable.append("tfoot"); this.fixedColFootRow = this.fixedColFoot.append("tr"); this.tableDiv .style("overflow", "auto") ; } update(domNode, element) { super.update(domNode, element); const context = this; const columns = context.tableColumns(); const data = context.tableData(); const scrollLeft = this.tableDiv.node().scrollLeft; this._empty_col_idx_arr = this.getEmptyColumnIdxArr(columns, data); this.element().selectAll("table,tbody,th,td").style("width", null); if (this.sortByFieldIndex_exists() && (this._prevSortByFieldIndex !== this.sortByFieldIndex() || this._prevDescending !== this.descending())) { Utility.multiSort(data, [{ idx: this.sortByFieldIndex(), reverse: this.descending() }]); this._prevSortByFieldIndex = this.sortByFieldIndex(); this._prevDescending = this.descending(); } this._hasChildWidgets = false; if (this.fixedHeader()) { this.thead = this.fixedThead; } else { this.thead = this.unfixedThead; } this.fixedHead.style("display", this.fixedHeader() ? "table-row" : "none"); this.unfixedThead.style("display", this.fixedHeader() ? "none" : "table-row"); const thSel = this.thead.selectAll("th").data(this.showHeader() ? columns.filter(function (col, idx) { return !context.isHidden(idx) && context._empty_col_idx_arr.indexOf(idx) === -1; }) : []); const thUpdate = thSel.enter().append("th") .each(function (d) { const element2 = d3Select(this); element2 .append("span") .attr("class", "thText") ; element2 .append("span") .attr("class", "thIcon") ; }) .on("click", function (column, idx) { context.headerClick(column, idx); }) .merge(thSel) .style("background-color", this.theadRowBackgroundColor()) .style("border-color", this.theadCellBorderColor()) .style("color", this.theadFontColor()) .style("font-size", this.theadFontSize()) ; thUpdate.select(".thText") .style("font-family", this.theadFontFamily()) .text(function (column, idx) { const fieldsIdx = context.calcFieldsIndex(idx); return context.field(-1, fieldsIdx).transform(column); }) ; thUpdate.select(".thIcon") .text(function (column, idx) { if (context.descending()) { return context.sortByFieldIndex() === idx ? "\uf078" : ""; } else { return context.sortByFieldIndex() === idx ? "\uf077" : ""; } }) ; thSel.exit() .remove() ; thUpdate.order(); if (this.paginationLimit()) { this.pagination(data.length >= parseInt(this.paginationLimit()) ? true : false); } if (this.pagination()) { if (this._paginator.target() === null) { this._paginator.target(element.node()); } const ipp = this._calcRowsPerPage(thUpdate); this.itemsPerPage(ipp); this._paginator.numItems(data.length); this._tNumPages = Math.ceil(this._paginator.numItems() / this.itemsPerPage()) || 1; if (this.pageNumber() > this._tNumPages || this.pageNumber() <= 0) { this.pageNumber(1); } // resets if current pagenum selected out of range this._paginator._onSelect = function (p, d) { context.pageNumber(p); context.render(); return; }; } else { this._paginator.numItems(0); // remove widget } // pageNumber starts at index 1 const startIndex = this.pageNumber() - 1; const itemsOnPage = this.itemsPerPage(); const start = startIndex * itemsOnPage; const end = startIndex * parseInt(itemsOnPage) + parseInt(itemsOnPage); let tData = null; if (this.topN()) { tData = data.slice(0, this.topN()); } else if (this.pagination()) { tData = data.slice(start, end); } else { tData = data; } const totalRow: any[] = [this.totalledLabel() ? this.totalledLabel() : null]; if (this.totalledColumns().length !== 0) { for (let i = 0; i < this.totalledColumns().length; i++) this.totalledColumns()[i] = +this.totalledColumns()[i]; for (let j = 1; j < columns.length; j++) { let sum = 0; if (this.totalledColumns().indexOf(j) !== -1) { for (let k = 0; k < tData.length; k++) { sum = sum + tData[k][j]; } totalRow.push(sum); } else { totalRow.push(""); } } const tfSel = this.tfoot.selectAll("td").data(totalRow); tfSel.enter() .append("td") .merge(tfSel) .style("background-color", this.tfootRowBackgroundColor()) .style("border-color", this.tfootCellBorderColor()) .style("color", this.tfootFontColor()) .style("font-size", this.tfootFontSize()) [this.renderHtmlDataCells() ? "html" : "text"](function (d, idx) { return context.fields()[idx].transform(d); }); tfSel.exit() .remove() ; } const rowsSel = this.tbody.selectAll("tr.tr_" + this.id()).data(tData.map(function (d, idx) { // TODO - Move fix closer to data source? for (let i = 0; i < d.length; ++i) { if (d[i] === undefined) { d[i] = null; } } return { rowIdx: idx, row: d }; })); const rowsUpdate = rowsSel.enter().append("tr") .attr("class", "tr_" + this.id()) .on("click.selectionBag", function (_d) { if (_d.row) { const d = _d.row; const i = _d.rowIdx; context.selectionBagClick(d, i); context.applyRowStyles(context.getBodyRow(i)); context.applyFirstColRowStyles(context.getFixedRow(i)); } }, true) // capture=true: event is caught on the way down the DOM before the cell click. .on("mouseover", function (_d) { if (_d.row) { const i = _d.rowIdx; const fixedLeftRows = context.getFixedRow(i); if (!fixedLeftRows.empty()) { fixedLeftRows.classed("hover", true); } const tbodyRows = context.getBodyRow(i); tbodyRows.classed("hover", true); context.applyStyleToRows(tbodyRows); context.applyFirstColRowStyles(fixedLeftRows); } }) .on("mouseout", function (_d) { if (_d.row) { const i = _d.rowIdx; const fixedLeftRows = context.getFixedRow(i); fixedLeftRows.classed("hover", false); const tbodyRows = context.getBodyRow(i); tbodyRows.classed("hover", false); context.applyStyleToRows(tbodyRows); context.applyFirstColRowStyles(fixedLeftRows); } }) .merge(rowsSel) .classed("selected", function (_d) { const d = _d.row; return context._selectionBag.isSelected(context._createSelectionObject(d)); }) .classed("trId" + this._id, true) ; rowsSel.exit() .remove() ; this.applyStyleToRows(rowsUpdate); const cellsSel = rowsUpdate.selectAll(".td_" + this.id()).data(function (_d, _trIdx) { return _d.row.filter(function (cell, idx) { return idx < columns.length && !context.isHidden(idx) && context._empty_col_idx_arr.indexOf(idx) === -1; }).map(function (cell, idx) { return { rowInfo: _d, colIdx: idx, cell }; }); }); cellsSel.enter() .append("td") .attr("class", "td_" + this.id()) .on("click", function (tdContents) { if (tdContents.rowInfo) { context.click(context.rowToObj(tdContents.rowInfo.row), context.columns()[tdContents.colIdx], context._selectionBag.isSelected(context._createSelectionObject(tdContents.rowInfo.row))); } }) .on("dblclick", function (tdContents, idx) { if (tdContents.rowInfo) { context.dblclick(context.rowToObj(tdContents.rowInfo.row), context.columns()[tdContents.colIdx], context._selectionBag.isSelected(context._createSelectionObject(tdContents.rowInfo.row))); } }) .each(function (tdContents, tdIdx) { const alignment = context.getColumnAlignment(tdContents.rowInfo.rowIdx, tdContents.colIdx, tdContents.cell); const el = d3Select(this); el .style("height", null) .style("text-align", alignment) .style("vertical-align", context.verticalAlign()) .classed("tr-" + tdContents.rowInfo.rowIdx + "-td-" + tdIdx, true) ; }) .merge(cellsSel) .each(function (tdContents) { const el = d3Select(this); if (tdContents.cell instanceof Widget) { el[context.renderHtmlDataCells() ? "html" : "text"](null); const widgetDiv = el.selectAll(".div_" + context.id()).data([tdContents.cell], function (d: any) { return d.id(); }); widgetDiv.exit() .each(function (d: any) { d.target(null); }) .remove() ; widgetDiv.enter().append("div") .attr("class", "div_" + context.id()) .style("width", context.minWidgetWidth() + "px") .style("height", context.minWidgetHeight() + "px") .each(function (d) { const widgetDiv2 = d3Select(this); d._parentWidget = context; if (d._class.indexOf("childWidget") < 0) { d._class = "childWidget " + d._class; } d .target(null) .target(widgetDiv2.node()) ; }) .merge(widgetDiv as any) .each(function (d) { d .resize() .lazyRender() ; context._hasChildWidgets = true; }) ; } else { el.selectAll(".div_" + context.id()).remove(); const fieldsIdx = context.calcFieldsIndex(tdContents.colIdx); el[context.renderHtmlDataCells() ? "html" : "text"]( context.field(tdContents.rowInfo.rowIdx, fieldsIdx).transform(tdContents.cell) ); } }) ; cellsSel.exit() .remove() ; const tableMarginHeight = parseInt(this.thead.node().offsetHeight); if (this.pagination() && this._hasChildWidgets) { this.tableDiv.style("overflow-y", "auto"); this.table.style("margin-bottom", "50px"); console.log("Warning: displaying another widget in the table may cause problems with pagination"); } else { this.tableDiv.style("overflow-y", null); this.table.style("margin-bottom", null); } this.size(this._size); let fixedColWidth = 0; const fixedColThSel = this.fixedColHeadRow.selectAll("th").data(this.fixedColumn() && this.showHeader() ? [columns[0]] : []); const fixedColThUpdate = fixedColThSel.enter().append("th") .each(function (d) { const element2 = d3Select(this); element2 .append("span") .attr("class", "thText") ; element2 .append("span") .attr("class", "thIcon") ; }) .on("click", function (column, idx) { context.headerClick(column, idx); }) .merge(fixedColThSel) .style("background-color", this.theadRowBackgroundColor()) .style("border-color", this.theadCellBorderColor()) .style("color", this.theadFontColor()) .style("font-size", this.theadFontSize()) ; fixedColThUpdate.select(".thText") .style("font-family", this.theadFontFamily()) .text(function (column) { return column; }) ; fixedColThUpdate.select(".thIcon") .text(function (column, idx) { if (context.descending()) { return context.sortByFieldIndex() === idx ? "\uf078" : ""; } else { return context.sortByFieldIndex() === idx ? "\uf077" : ""; } }) ; fixedColThSel.exit() .remove() ; const fixedColTrSel = this.fixedColBody.selectAll("tr").data(this.fixedColumn() ? tData : []); const fixedColTrUpdate = fixedColTrSel.enter().append("tr") .attr("class", function () { return "trId" + context._id; }) .merge(fixedColTrSel) .on("click", function (d, i) { (d3Select(rowsUpdate[0][i]).on("click.selectionBag") as any)(rowsUpdate.data()[i], i) ; }) .on("mouseover", function (d, i) { (d3Select(rowsUpdate[0][i]).on("mouseover") as any)(rowsUpdate.data()[i], i) ; }) .on("mouseout", function (d, i) { (d3Select(rowsUpdate[0][i]).on("mouseout") as any)(rowsUpdate.data()[i], i) ; }) .classed("selected", function (d) { return context._selectionBag.isSelected(context._createSelectionObject(d)); }) ; fixedColTrSel.exit() .remove() ; const fixedColTdSel = fixedColTrUpdate.selectAll("td").data(function (d, i) { return [d[0]]; }); const fixedColTdUpdate = fixedColTdSel.enter().append("td") .merge(fixedColTdSel)[this.renderHtmlDataCells() ? "html" : "text"](function (d): any { if (typeof (d) === "string") { return d.trim(); } else if (typeof (d) === "number") { return d; } return ""; }); fixedColTdSel.exit() .remove() ; const fixedColFootTdSel = this.fixedColFootRow.selectAll("td").data(this.fixedColumn() && this.totalledLabel() ? [this.totalledLabel()] : []); const fixedColFootTdUpdate = fixedColFootTdSel.enter().append("td") .merge(fixedColFootTdSel)[this.renderHtmlDataCells() ? "html" : "text"](function (d): any { if (typeof (d) === "string") { return d.trim(); } else if (typeof (d) === "number") { return d; } return ""; }); fixedColFootTdSel.exit() .remove() ; if (this.fixedColumn() && !this.fixedSize() && fixedColFootTdUpdate.length) { if (this.showHeader()) { fixedColWidth = fixedColFootTdUpdate.property("offsetWidth") > fixedColFootTdUpdate.property("offsetWidth") ? fixedColFootTdUpdate.property("offsetWidth") : fixedColFootTdUpdate.property("offsetWidth"); } else { fixedColWidth = fixedColFootTdUpdate.property("offsetWidth"); } this.fixedCol .style("position", "absolute") .style("margin-top", -this.tableDiv.property("scrollTop") + tableMarginHeight + "px") ; fixedColTdUpdate .style("width", fixedColWidth + "px") ; this.fixedColHead .style("position", "absolute") .style("margin-top", (this.fixedHeader() ? this.tableDiv.property("scrollTop") : 0) - tableMarginHeight + "px") ; fixedColThUpdate .style("width", fixedColWidth + "px") ; rowsUpdate.each(function (d, i) { const height = d3Select(this).select("td").property("offsetHeight"); d3Select(fixedColTdUpdate[i][0]).style("height", height + "px"); }); } this.table .style("margin-left", -fixedColWidth + "px") ; this.tableDiv .style("margin-left", fixedColWidth + "px") .style("width", this.width() - fixedColWidth + "px") ; if (!rowsUpdate.empty()) this.setColumnWidths(rowsUpdate); let box; let newTableHeight; let finalWidth; let maxWidth; if (this.fixedSize()) { const node = d3Select(".tableDiv > table").node(); if (node) { box = (node as any).getBoundingClientRect(); let newTableHeight; let finalWidth; if (box.width !== 0 && box.height !== 0) { calcWidth(); calcHeight(); } else { if (box.height - tableMarginHeight <= context.tableDiv.property("offsetHeight")) { calcHeight(); } else { if (context.fixedHeader()) { newTableHeight = context.tableDiv.property("offsetHeight"); // is tableDiv correct? newTableHeight = newTableHeight + "px"; } else { newTableHeight = "100%"; } } if (box.width - fixedColWidth < context.tableDiv.property("offsetWidth")) { calcWidth(); } else { if (context.fixedColumn()) { finalWidth = context.tableDiv.property("offsetWidth") - fixedColWidth; // is tableDiv correct? finalWidth = finalWidth + "px"; } else { finalWidth = "100%"; } } } if (element.classed("childWidget")) { context._placeholderElement .style("width", finalWidth + "px") .style("height", newTableHeight + "px") ; context.tableDiv .style("overflow", "hidden") ; } context.size({ width: finalWidth, height: newTableHeight }); } } this.setOnScrollEvents(this.tableDiv.node(), tableMarginHeight); function calcWidth() { const newTableWidth = box.width; maxWidth = context.tbody.property("offsetWidth") + 1; finalWidth = newTableWidth > maxWidth ? maxWidth : newTableWidth; finalWidth = finalWidth; } function calcHeight() { newTableHeight = context.tbody.property("offsetHeight") + tableMarginHeight; newTableHeight = newTableHeight; } this._paginator.render(); setTimeout(function () { context._paginator .right((context.hasVScroll(element) ? Platform.getScrollbarWidth() : 0) + context._paginatorTableSpacing) .bottom((context.hasHScroll(element) ? Platform.getScrollbarWidth() : 0) + context._paginatorTableSpacing) .render(function () { context.tableDiv.node().scrollLeft = scrollLeft; }) ; }, 0); } exit(domNode, element) { this._paginator.target(null); super.exit(domNode, element); } setColumnWidths(rows) { const context = this; const firstRow = rows.filter(function (d, i) { return i === 0; }); let tds = d3Select(null); firstRow.each(function (d) { tds = d3SelectAll(this.childNodes); }); const tableMarginHeight = this.fixedHeader() ? this.thead.property("offsetHeight") : 0; let totalWidth = 1; const tdWidths = {}; tds.each(function (d, i) { tdWidths[i] = (this as any).offsetWidth; }); const th = this.thead.selectAll("th"); th.each(function (d, i) { const thwidth = this.offsetWidth; const tdwidth = tds.empty() ? 0 : tdWidths[i]; const usewidth = thwidth >= tdwidth ? thwidth : tdwidth; this.style.width = usewidth + "px"; tds .filter((_d, idx) => idx === 0) .each(function () { d3Select(this).style("width", usewidth + "px"); }) ; totalWidth += usewidth; }); this.thead .style("position", this.fixedHeader() ? "absolute" : "relative") .style("width", totalWidth + "px") .style("margin-top", "0px") ; this.table .style("width", totalWidth + "px") ; this.tableDiv .style("margin-top", (context.fixedHeader() ? tableMarginHeight : 0) + "px") ; this.tbody .style("width", totalWidth + "px") ; } getBodyRow(i) { return this.table.selectAll("tbody tr.trId" + this._id) .filter(function (d, idx) { return idx === i; }) ; } getFixedRow(i) { return this._element.selectAll(".rows-wrapper tbody tr") .filter(function (d, idx) { return idx === i; }) ; } setOnScrollEvents(scrollNode, margHeight) { const context = this; scrollNode.onscroll = function (e) { const topDelta = e.target.scrollTop; const leftDelta = e.target.scrollLeft; if (context.fixedHeader()) { context.thead .style("margin-left", -leftDelta + "px") ; } if (context.fixedColumn()) { context.fixedCol .style("margin-top", -topDelta + margHeight + "px") ; if (context.fixedHeader()) { context.fixedColHead .style("margin-top", topDelta - margHeight + "px") ; } } }; } _generateTempRow() { const trow = this.tbody.append("tr"); trow.append("td").text("QQQ"); return trow; } _createSelectionObject(d) { const context = this; return { _id: d, element: () => context.tbody ? context.tbody.selectAll("tr").filter(function (d2) { return d2 === d; }) : d3Select(null) }; } _calcRowsPerPage(th) { if (this._paginator.numItems() === 0) { // only run on first render this._paginator.numItems(1); this.itemsPerPage(1); } this._paginator.render(); const thHeight = this.thead.selectAll("th").node() ? this.thead.selectAll("th").node().clientHeight : 0; const tfootHeight = this.tfoot.selectAll("td").node() ? this.tfoot.selectAll("td").node().clientHeight : 0; const tmpRow = this._generateTempRow(); const tcellHeight = tmpRow.node().clientHeight; tmpRow.remove(); const paginatorHeight = this.calcHeight(this._paginator.element()); 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; if (this.totalledColumns().length !== 0) { ipp -= 1; } return ipp; } sort(idx) { if (this.sortByFieldIndex() !== idx) { this.descending(false); } else { this.descending(!this.descending()); } this.sortByFieldIndex(idx); return this; } selection(_) { if (!arguments.length) return this._selectionBag.get().map(function (d) { return d._id; }); this._selectionBag.set(_.map(function (row) { return this._createSelectionObject(row); }, this)); return this; } selectionBagClick(d, i) { if (this.multiSelect() && d3Event.shiftKey && this._selectionPrevClick) { let inRange = false; const rows = []; const selection = this.tableData().filter(function (row, i2) { let lastInRangeRow = false; if (row === d || row === this._selectionPrevClick) { if (inRange) { lastInRangeRow = true; } inRange = !inRange; rows.push(i2); } return inRange || lastInRangeRow; }, this); this.selection(selection); } else if (this.multiSelect()) { this._selectionBag.click(this._createSelectionObject(d), d3Event); this._selectionPrevClick = d; } else { const selObj = this._createSelectionObject(d); this._selectionBag.click(selObj, { ctrlKey: this._selectionBag.isSelected(selObj) }); this._selectionPrevClick = d; } this.render(); } applyHoverRowStyles(row) { const context = this; row .style("color", context.tbodyHoverRowFontColor()) .style("background-color", context.tbodyHoverRowBackgroundColor()) ; } applySelectedRowStyles(row) { const context = this; row .style("color", context.tbodySelectedRowFontColor()) .style("background-color", context.tbodySelectedRowBackgroundColor()) ; } applyRowStyles(row, isFirstCol: boolean = false) { const dataRow = row.datum().row; row .style("color", isFirstCol ? this.tbodyFirstColFontColor() : this.tbodyFontColor()) .style("background-color", isFirstCol ? this.tbodyFirstColBackgroundColor() : this.tableZebraColor_exists() && this.tableData().indexOf(dataRow) % 2 ? this.tbodyRowBackgroundColor() : this.tableZebraColor()) ; } applyFirstColRowStyles(rows) { this.applyStyleToRows(rows, true); } applyStyleToRows(rows, isFirstCol: boolean = false) { isFirstCol = typeof isFirstCol !== "undefined" ? isFirstCol : false; const context = this; rows.each(function () { const tr = d3Select(this); if (tr.classed("hover")) { context.applyHoverRowStyles(tr); } else if (tr.classed("selected")) { context.applySelectedRowStyles(tr); } else { context.applyRowStyles(tr, isFirstCol); } }) ; } getColumnAlignment(rowIdx, colIdx, cell) { const fieldsIdx = this.calcFieldsIndex(colIdx); const field = this.field(rowIdx, fieldsIdx); switch ((field as any).__prop_type) { case "string": return this.stringAlign(); case "number": return this.numberAlign(); case "": case undefined: switch (typeof cell) { case "string": return this.stringAlign(); case "number": return this.numberAlign(); } } return null; } serializeState() { return { selection: this._selectionBag.get().map(function (d) { return d._id; }), data: this.data() }; } deserializeState(state) { if (state) { if (state.selection) { const context = this; this._selectionBag.set(state.selection.map(function (d) { return context._createSelectionObject(d); })); } if (state.data) { this.data(state.data); } } return this; } click(row, column, selected) { console.log("click: " + JSON.stringify(row, replacer) + ", " + column + "," + selected); } dblclick(row, column, selected) { console.log("dblclick: " + JSON.stringify(row, replacer) + ", " + column + "," + selected); } headerClick(column, idx) { this .sort(idx) .render() ; } renderHtmlDataCells: { (): boolean; (_: boolean): Table; }; pagination: { (): boolean; (_: boolean): Table; }; paginationLimit: { (): any; (_: any): Table; }; itemsPerPage: { (): any; (_: any): Table; }; pageNumber: { (): number; (_: number): Table; }; adjacentPages: { (): number; (_: number): Table; }; topN: { (): number; (_: number): Table; }; pivot: { (): boolean; (_: boolean): Table; }; showHeader: { (): boolean; (_: boolean): Table; }; fixedHeader: { (): boolean; (_: boolean): Table; }; fixedColumn: { (): boolean; (_: boolean): Table; }; multiSelect: { (): boolean; (_: boolean): Table; }; fixedSize: { (): boolean; (_: boolean): Table; }; hideEmptyColumns: { (): boolean; (_: boolean): Table; }; theadFontSize: { (): string; (_: string): Table; }; tbodyFontSize: { (): string; (_: string): Table; }; tfootFontSize: { (): string; (_: string): Table; }; theadFontColor: { (): string; (_: string): Table; }; tbodyFontColor: { (): string; (_: string): Table; }; tfootFontColor: { (): string; (_: string): Table; }; theadFontFamily: { (): string; (_: string): Table; }; tbodyFontFamily: { (): string; (_: string): Table; }; tfootFontFamily: { (): string; (_: string): Table; }; theadCellBorderColor: { (): string; (_: string): Table; }; tfootCellBorderColor: { (): string; (_: string): Table; }; theadRowBackgroundColor: { (): string; (_: string): Table; }; tfootRowBackgroundColor: { (): string; (_: string): Table; }; tbodyCellBorderColor: { (): string; (_: string): Table; }; tbodyRowBackgroundColor: { (): string; (_: string): Table; }; tbodyFirstColFontColor: { (): string; (_: string): Table; }; tbodyFirstColBackgroundColor: { (): string; (_: string): Table; }; tbodyHoverRowFontColor: { (): string; (_: string): Table; }; tbodyHoverRowBackgroundColor: { (): string; (_: string): Table; }; tbodySelectedRowFontColor: { (): string; (_: string): Table; }; tbodySelectedRowBackgroundColor: { (): string; (_: string): Table; }; tableZebraColor: { (): string; (_: string): Table; }; tableZebraColor_exists: () => boolean; totalledColumns: { (): any[]; (_: any[]): Table; }; totalledLabel: { (): string; (_: string): Table; }; hiddenColumns: { (): any[]; (_: any[]): Table; }; stringAlign: { (): string; (_: string): Table; }; numberAlign: { (): string; (_: string): Table; }; verticalAlign: { (): string; (_: string): Table; }; minWidgetWidth: { (): number; (_: number): Table; }; minWidgetHeight: { (): number; (_: number): Table; }; sortByFieldIndex: { (): number; (_: number): Table; }; sortByFieldIndex_exists: () => boolean; descending: { (): boolean; (_: boolean): Table; }; } Table.prototype._class += " other_Table"; Table.prototype.publish("renderHtmlDataCells", false, "boolean", "enable or disable HTML within cells", null, { tags: ["Private"] }); Table.prototype.publish("pagination", true, "boolean", "Enable or disable pagination", null, { tags: ["Private"] }); Table.prototype.publish("paginationLimit", null, "number", "Maximum number of rows allowed before pagination defaults to on", null, { tags: ["Private"] }); Table.prototype.publishProxy("itemsPerPage", "_paginator"); Table.prototype.publishProxy("pageNumber", "_paginator", "pageNumber", 1); Table.prototype.publishProxy("adjacentPages", "_paginator"); Table.prototype.publish("topN", null, "number", "Total number or rows of data to be displayed in the table", null, { tags: ["Private"] }); Table.prototype.publish("pivot", false, "boolean", "Pivot Table"); Table.prototype.publish("showHeader", true, "boolean", "Show or hide the table header", null, { tags: ["Private"] }); Table.prototype.publish("fixedHeader", true, "boolean", "Enable or disable fixed table header", null, { tags: ["Private"] }); Table.prototype.publish("fixedColumn", false, "boolean", "Enable or disable fixed first column", null, { tags: ["Private"] }); Table.prototype.publish("multiSelect", false, "boolean", "Multiple Selection", null, { tags: ["Basic"] }); Table.prototype.publish("fixedSize", false, "boolean", "Fix Size to Min Width/Height"); Table.prototype.publish("hideEmptyColumns", false, "boolean", "Hide columns with all empty cells"); Table.prototype.publish("theadFontSize", null, "string", "Table head font size", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tbodyFontSize", null, "string", "Table body font size", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tfootFontSize", null, "string", "Table body font size", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("theadFontColor", null, "html-color", "Table head font color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tbodyFontColor", null, "html-color", "Table body font color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tfootFontColor", null, "html-color", "Table body font color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("theadFontFamily", null, "string", "Table head font family", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tbodyFontFamily", null, "string", "Table body font family", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tfootFontFamily", null, "string", "Table body font family", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("theadCellBorderColor", null, "html-color", "Table head cell border color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tfootCellBorderColor", null, "html-color", "Table head cell border color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("theadRowBackgroundColor", null, "html-color", "Table head row color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tfootRowBackgroundColor", null, "html-color", "Table head row color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tbodyCellBorderColor", null, "html-color", "Table body cell border color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tbodyRowBackgroundColor", null, "html-color", "Table body row color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tbodyFirstColFontColor", null, "html-color", "Table body first column font color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tbodyFirstColBackgroundColor", null, "html-color", "Table body first column background color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tbodyHoverRowFontColor", null, "html-color", "Table body hover row font color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tbodyHoverRowBackgroundColor", null, "html-color", "Table body hover row background color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tbodySelectedRowFontColor", null, "html-color", "Table body selected row color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tbodySelectedRowBackgroundColor", null, "html-color", "Table body selected row color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("tableZebraColor", null, "html-color", "Table zebra row color", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("totalledColumns", [], "array", "Array of indices of the columns to be totalled", null, { tags: ["Basic"], optional: true, disable: (w: any) => w.pivot() }); 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() }); Table.prototype.publish("hiddenColumns", [], "array", "Array of indices of the columns to be hidden", null, { tags: ["Basic"], optional: true, disable: (w) => w.pivot() }); Table.prototype.publish("stringAlign", "left", "set", "Cell alignment for strings", ["left", "right", "center"], { tags: ["Basic"], optional: true }); Table.prototype.publish("numberAlign", "right", "set", "Cell alignment for numbers", ["left", "right", "center"], { tags: ["Basic"], optional: true }); Table.prototype.publish("verticalAlign", null, "set", "Cell vertical alignment", [null, "middle", "top", "bottom"], { tags: ["Basic"], optional: true }); Table.prototype.publish("minWidgetWidth", 320, "number", "Minimum width of a child widget", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("minWidgetHeight", 240, "number", "Minimum height of a child widget", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("sortByFieldIndex", null, "number", "Index for the field/column to sort the data", null, { tags: ["Basic"], optional: true }); Table.prototype.publish("descending", false, "boolean", "Direction for sorting the data: ascending (true) or descending (false)", null, { tags: ["Basic"], optional: true });