import $ from 'jquery'; import dt from 'datatables.net'; import resp from 'datatables.net-responsive'; import resp2 from 'datatables.net-responsive-dt'; import jszip from 'jszip/dist/jszip.js'; import bttn from 'datatables.net-buttons-dt'; import bttn2 from 'datatables.net-buttons'; import bttnHtml5 from 'datatables.net-buttons/js/buttons.html5.js'; import bttnPrint from 'datatables.net-buttons/js/buttons.print.js'; import {createInstance} from './i18n'; import {css, html, unsafeCSS} from 'lit'; import de from '../assets/datatables/i18n/German'; import en from '../assets/datatables/i18n/English'; import {getIconSVGURL} from '@dbp-toolkit/common'; import * as commonUtils from '@dbp-toolkit/common/utils'; import * as commonStyles from '@dbp-toolkit/common/styles'; import {name as pkgName} from './../package.json'; import {AdapterLitElement} from "@dbp-toolkit/provider/src/adapter-lit-element"; dt(window, $); resp(window, $); resp2(window, $); bttn(window, $); bttn2(window, $); bttnHtml5(window, $, jszip); bttnPrint(window, $); export class DataTableView extends AdapterLitElement { constructor() { super(); this._i18n = createInstance(); this.lang = this._i18n.language; // datatable properties this.table = null; this.responsive = null; this.paging = false; this.searching = false; this.columns = []; this.columnDefs = []; this.data = []; this.cssStyle = ''; this.exportable = false; this.exportName = 'Data Export'; this.columnSearching = false; this.defaultOrder = []; } setCSSStyle(style) { this.cssStyle = style; } static get properties() { return { ...super.properties, lang: { type: String }, table: { type: Object, attribute: false }, paging: { type: Boolean }, searching: { type: Boolean }, columns: { type: Array, attribute: false }, columnDefs: { type: Array, attribute: false }, data: { type: Array, attribute: false }, cssStyle: { type: String, attribute: false }, exportable: { type: Boolean }, exportName: { type: String, attribute: 'export-name' }, columnSearching: { type: Boolean, attribute: 'column-searching'}, defaultOrder: { type: Array, attribute: 'default-order'} }; } set_columns(cols) { this.columns = cols; return this; } set_columnDefs(defs) { this.columnDefs = defs; return this; } set_defaultOrder(order) { this.defaultOrder = order; return this; } add_row(row) { this.data.push(row); this.table.row.add(row); return this; } draw() { this.table.draw(); return this; } columnSearch(col, str) { this.table.column(col).search(str).draw(); } columnReduce(col, func, init=0) { return this.table.column(col, { search: 'applied' }).data().reduce( func, init); } on(eventName, func) { this.table.on(eventName, func); return this; } set_datatable(data, languageChange = false) { const lang_obj = this.lang === 'de' ? de : en; const i18n = this._i18n; if (typeof this.columns === 'undefined' || !this.columns.length) { if (data.length) throw new Error('columns not set-up'); return this; } if (this.columnSearching) { const existing_tfoot = this.shadowRoot.querySelector('table tfoot'); if (existing_tfoot === null || !existing_tfoot.hasChildNodes() || languageChange) { if (existing_tfoot !== null) { existing_tfoot.remove(); } const fragment = document.createDocumentFragment(); const tfoot = document.createElement('tfoot'); const tr = document.createElement('tr'); this.columns.forEach(function (element, index) { const th = document.createElement('td'); if (element !== null && (typeof element.visible === 'undefined' || element.visible !== false) && (typeof element.searchable === 'undefined' || element.searchable !== false)) { const input = document.createElement('input'); input.type = 'text'; input.className = 'column-search-line'; input.id = 'input-col-' + index; input.placeholder = i18n.t('column-search-placeholder', {fieldName: element.title}); th.appendChild(input); } tr.appendChild(th); }); tfoot.appendChild(tr); fragment.appendChild(tfoot); this.shadowRoot.querySelector('table').appendChild(fragment); } } this.table = $(this.shadowRoot.querySelector('table')).DataTable({ destroy: true, autoWidth: true, language: lang_obj, paging: this.paging, searching: this.searching, columns: this.columns, columnDefs: this.columnDefs, dom: (this.exportable ? '<"export-btn"B>' : '') + 'lfrtip', buttons: [ { extend: 'excelHtml5', text: i18n.t('export-excel'), title: this.exportName, filename: this.exportName, className: 'button is-small', }, { extend: 'csvHtml5', text: i18n.t('export-csv'), title: this.exportName, filename: this.exportName, className: 'button is-small', charset: 'UTF-8', bom: true, fieldSeparator: this.lang === 'en' ? ',' : ';' }, { extend: 'print', text: i18n.t('print'), title: this.exportName, className: 'button is-small', }, ] }); const dataTableLength = sessionStorage.getItem('dbp-data-table-length'); //Retrieve page length from session storage if (dataTableLength !== null) { this.table.page.len(dataTableLength); } //Save page length in session storage this.table.on('length.dt', function ( e, settings, len ) { sessionStorage.setItem('dbp-data-table-length', len); }); this.data = data; this.table.clear(); if (this.data.length) { this.table.rows.add(this.data); } new $.fn.dataTable.Responsive(this.table, { details: true }); if (this.columnSearching) { const thisTable = this.table; const that = this; this.columns.forEach(function (element, index) { if (element !== null && (typeof element.visible === 'undefined' || element.visible !== false) && (typeof element.searchable === 'undefined' || element.searchable !== false)) { const input = that.shadowRoot.querySelector('#input-col-' + index); if (input) { ['keyup', 'change', 'clear'].forEach(function (event) { input.addEventListener(event, function () { const column = thisTable.column(index); if (column.search() !== input.value) { column.search(input.value).draw(); } }); }); } } }); } this.table.order(this.defaultOrder); this.table.draw(); return this; } update(changedProperties) { let languageChange = false; changedProperties.forEach((oldValue, propName) => { if (propName === "lang") { this._i18n.changeLanguage(this.lang).catch(e => { console.log(e);}); languageChange = true; } }); this.updateComplete.then(this.set_datatable(this.data, languageChange)).catch(e => { console.log(e);}); super.update(changedProperties); } static get styles() { // language=css const orderExpandIconOverrides = css` table.dataTable.dtr-inline.collapsed > tbody > tr[role="row"] > td:first-child::before, table.dataTable.dtr-inline.collapsed > tbody > tr[role="row"] > th:first-child::before { all: initial; top: 0.7em; left: 0.4em; height: 1em; width: 1em; display: block; cursor: pointer; position: absolute; box-sizing: content-box; text-align: center; text-indent: 0 !important; line-height: 0.9em; color: var(--dbp-primary-text); background-color: var(--dbp-primary-base); content: '+'; } table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child::before, table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child::before { content: '-'; } table.dataTable thead .sorting { background-image: url('${unsafeCSS(getIconSVGURL('chevron-up'))}'), url('${unsafeCSS(getIconSVGURL('chevron-down'))}'); background-position: 100% 40%, 100% 60%; background-size: 0.5em, 0.5em; } table.dataTable thead .sorting_desc { background-image: url('${unsafeCSS(getIconSVGURL('chevron-up'))}'); background-position: 100% 50%; background-size: 0.8em; } table.dataTable thead .sorting_asc { background-image: url('${unsafeCSS(getIconSVGURL('chevron-down'))}'); background-size: 0.8em; background-position: 100% 50%; } `; // language=css return css` ${commonStyles.getThemeCSS()} ${commonStyles.getGeneralCSS()} ${commonStyles.getButtonCSS()} ${orderExpandIconOverrides} .dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover { color: var(--dbp-muted-text-dark); border-radius: var(--dbp-border-radius); background: transparent; } .export-btn { margin-bottom: .6rem; } select { border-radius: calc(var(--dbp-border-radius)/2); height: 28px; margin-left: 3px; } :host { display: block; } .dataTables_filter input { border-radius: 0; border:; padding: 0.1em; } table.dataTable .column-search-line { width: 100%; } `; } render() { let dt_css = commonUtils.getAssetURL(pkgName, 'css/jquery.dataTables.min.css'); let rs_css = commonUtils.getAssetURL(pkgName, 'css/responsive.dataTables.min.css'); let bt_css = commonUtils.getAssetURL(pkgName, 'css/buttons.dataTables.min.css'); return html` <link rel="stylesheet" href="${dt_css}"> <link rel="stylesheet" href="${rs_css}"> <link rel="stylesheet" href="${bt_css}"> <style> ${this.cssStyle} </style> <div><table width="100%"></table></div> `; } }