import moment from "moment"; import { SlickDataView, SlickGrid } from "slickgrid"; import { removeHtml } from "shared/lib/strings"; import { IColumn, IPrinter, ISlickRow, ISlickTable } from "shared/model/types"; import { IHtmlDocElements } from "shared/model/types"; import { getDisplayedRows } from "../../../lib"; import { applyHtmlToDocument } from "./lib"; import { printStyles } from "./model"; export class DefaultPrinter implements IPrinter { clientId = 0; clientName = ""; cssStyles = printStyles; getClientName(): HTMLTableRowElement { const result = document.createElement("tr"); const name = document.createElement("th"); name.classList.add("client-name"); name.setAttribute("colspan", "100%"); name.innerText = `${this.clientName} [${this.clientId}]`; result.append(name); return result; } getHtmlTemplate(args: IHtmlDocElements): string { const { body = "", footer = "", header = "", styles = "", title = "", } = args; return ` ${title} ${header} ${footer}
${body}
`; } columnNames(table: ISlickTable): HTMLTableSectionElement { const result = document.createElement("thead"); const tr = document.createElement("tr"); tr.classList.add("row-column-names"); const grid = table.grid; const columns: IColumn[] = grid?.getColumns() || []; const columnsFiltered = columns.filter((el) => el.forPrint); columnsFiltered.forEach(({ name }) => { const th = document.createElement("th"); th.classList.add("text-left"); if (typeof name === "string") { th.innerText = name; } else { th.innerText = " "; } tr.append(th); }); result.append(tr); return result; } tableNameAndTime(table: ISlickTable): HTMLTableRowElement { const result = document.createElement("tr"); const tableName = document.createElement("th"); tableName.classList.add("text-left"); tableName.innerText = table.name || table.id; result.append(tableName); const dateStamp = document.createElement("th"); dateStamp.classList.add("text-right"); dateStamp.innerText = moment().format("MM/DD/YYYY h:mm A"); result.append(dateStamp); return result; } createTableElement(table: ISlickTable): HTMLTableElement { const result = document.createElement("table"); result.classList.add("slick-table"); result.style.width = "100%"; result.append(this.columnNames(table)); result.append(this.createTbody(table)); return result; } createTbody(table: ISlickTable): HTMLTableSectionElement { const result = document.createElement("tbody"); const grid = table.grid; if (!grid) return result; const columns: IColumn[] = grid.getColumns(); const columnsFiltered = columns.filter((el) => el.forPrint); const dataView: SlickDataView = grid.getData(); const displayedRows = getDisplayedRows(dataView); displayedRows.forEach((_row, rowIndex) => { const tr = this.createTr(columnsFiltered, rowIndex, grid); result.append(tr); }); result.append(...this.totals(table)); return result; } filters(table: ISlickTable): HTMLTableRowElement[] { const result: HTMLTableRowElement[] = []; if (table.filter) { const appliedFilters = table.filter.print(table); if (appliedFilters.length) { const tr = document.createElement("tr"); const th = document.createElement("th"); th.setAttribute("colspan", "100%"); th.classList.add("text-left"); th.innerText = "Applied filters"; tr.append(th); result.push(tr); } appliedFilters.forEach((filter) => { result.push(filter); }); } return result; } /** for tables with total calculations */ totals(_table: ISlickTable): HTMLTableRowElement[] { return []; } createHeader(table: ISlickTable): HTMLTableSectionElement { const result = document.createElement("thead"); const tr = document.createElement("tr"); tr.classList.add("empty-row"); result.append(this.getClientName()); result.append(this.tableNameAndTime(table)); result.append(...this.filters(table)); result.append(tr); return result; } createTr( columns: IColumn[], rowIndex: number, grid: SlickGrid, ): HTMLTableRowElement { const result = document.createElement("tr"); const dataView: SlickDataView = grid.getData(); const row = dataView.getItem(rowIndex); const isGroupTitle = row.__group; const isGroupTotal = row.__groupTotals; if (isGroupTitle) { const td = document.createElement("td"); td.setAttribute("colspan", "100%"); td.innerText = removeHtml(row.title); result.append(td); } else { columns.forEach((column) => { const td = document.createElement("td"); if (column.cssClass) td.classList.add(column.cssClass); const field = column.field; const metaData = dataView.getItemMetadata(rowIndex); const formatterSpecific = metaData?.columns?.[field]?.formatter; const formatter = column.printer || formatterSpecific || column.formatter; let value = row[field]; if (isGroupTotal) { const totalsFormatter = column.groupTotalsFormatter; value = totalsFormatter ? totalsFormatter(row, column, grid) : ""; } else if (formatter) { value = formatter(0, 0, value, column, row, grid); } td.innerText = value || ""; result.append(td); }); } return result; } print(table: ISlickTable, clientId: number, clientName: string): void { const newTab = window.open(); if (!newTab) return; this.clientId = clientId; this.clientName = clientName; applyHtmlToDocument( newTab.document, this.getHtmlTemplate({ title: table.name || table.id, styles: this.cssStyles, header: this.createHeader(table).outerHTML, body: this.createTableElement(table).outerHTML, footer: this.createFooter().outerHTML, }), ); newTab.print(); } createFooter(): HTMLTableSectionElement { const result = document.createElement("tfoot"); return result; } }