diff --git a/packages/data-table-view/README.md b/packages/data-table-view/README.md index a744794273b0e0ab971d0e2e71c06ffc6d40e308..63f26c9ab56c551bd6bd488174680cb895843f7a 100644 --- a/packages/data-table-view/README.md +++ b/packages/data-table-view/README.md @@ -9,22 +9,12 @@ ``` # Attributes -- `value`: api request - - example `<vpu-data-table-view value="api/request"></vpu-data-table-view>` -- `filter`: optional filter for the request (append to api url) - - example 'Abc' will be `?search=Abc` -- `blacklisted-columns`: optional string with all column names to be excluded - . example '@id @type' (both are hydra columns) - `lang` (optional, default: `de`): set to `de` or `en` for German or English - example `<vpu-data-table-view lang="de"></vpu-data-table-view>` -- `entry-point-url` (optional, default is the TU Graz entry point url): entry point url to access the api - - example `<vpu-data-table-view entry-point-url="http://127.0.0.1:8000"></vpu-data-table-view>` - `paging` (optional, required to let datatable do the paging of loaded rows) - example `<vpu-data-table-view paging></vpu-data-table-view>` - `searching` (optional, required if a search box is desired) - example `<vpu-data-table-view searching></vpu-data-table-view>` -- `wait-until-all-loaded` (optional, required if all rows must load before use) - - example `<vpu-data-table-view wait-until-all-loaded></vpu-data-table-view>` # Local development ```bash diff --git a/packages/data-table-view/src/data-table-view.js b/packages/data-table-view/src/data-table-view.js index 593cb838e11b68159afb9c403c0c80b25b44cb67..0083365fc7b8824bb283e94b9fbb513ae57d58e6 100644 --- a/packages/data-table-view/src/data-table-view.js +++ b/packages/data-table-view/src/data-table-view.js @@ -2,11 +2,9 @@ import $ from 'jquery'; import dt from 'datatables.net'; import resp from 'datatables.net-responsive'; import resp2 from 'datatables.net-responsive-dt'; -import {getAPiUrl, getAssetURL,} from './utils.js'; +//import {getAssetURL,} from './utils.js'; import {i18n} from './i18n'; import {html, LitElement} from 'lit-element'; -import {unsafeHTML} from 'lit-html/directives/unsafe-html.js'; -import JSONLD from 'vpu-common/jsonld'; import commonUtils from 'vpu-common/utils'; dt(window, $); @@ -17,136 +15,36 @@ class DataTableView extends LitElement { constructor() { super(); this.lang = 'de'; - this.entryPointUrl = getAPiUrl(); - this.jsonld = null; - this.value = null; - this.filter = null; - this.apiUrl = null; - this.whitelist_cols = '*'; - this.blacklist_cols = ''; - this.table_columns = []; // all possible columns, defined by API entity - this.show_columns = []; // all columns visible in table, defined by property whhitelist/blacklist - this.display_columns = []; // all possible columns, in desired order for the table // datatable properties this.table = null; this.responsive = null; this.paging = false; this.searching = false; - // - this.is_loading = false; - this.wait_until_all_loaded = false; } static get properties() { return { lang: { type: String }, - value: { type: String }, - entryPointUrl: { type: String, attribute: 'entry-point-url' }, - filter: { type: String }, - apiUrl: { type: String, attribute: false }, - whitelist_cols: { type: String, attribute: 'whitelisted-columns' }, - blacklist_cols: { type: String, attribute: 'blacklisted-columns' }, - table_columns: { type: Array, attribute: false }, - show_columns: { type: Array, attribute: false }, - display_columns: { type: Array, attribute: false }, table: { type: Object, attribute: false }, paging: { type: Boolean }, searching: { type: Boolean }, - is_loading: { type: Boolean, attribute: false }, - wait_until_all_loaded: { type: Boolean, attribute: 'wait-until-all-loaded'} }; } - connectedCallback() { - super.connectedCallback(); - const that = this; - - JSONLD.initialize(this.entryPointUrl, function (jsonld) { - that.jsonld = jsonld; - try { - that.apiUrl = that.jsonld.getApiUrlForEntityName(that.value); - if (that.jsonld.entities[that.value] === undefined) { - console.dir(that.jsonld); - throw "Error: Could not get information about " + that.value; - } - that.table_columns = that.jsonld.entities[that.value]['hydra:supportedProperty'].map(obj => obj['hydra:title']); - - // display empty table - that.setup_columns(); - let columns = []; - for (let i = 0; i < that.display_columns.length; ++i) { - columns[i] = { - title: that.display_columns[i], - visible: that.show_columns.indexOf(that.display_columns[i]) > -1 - }; - } - that.set_datatable(columns); - if (that.filter) { - that.loadWebPageElement(); - } - } catch (e) { - that.table_columns = ['message from server']; - that.setup_columns(); - that.set_datatable([{title: 'message from server', visible: true}]); - that.table.row.add(['<span style="color:red;background:lightgray;">' + e.toString() + '</span>']); - } - }); - - // disabled, load first on toggle to visible - window.addEventListener("vpu-auth-init", () => that.loadWebPageElement()); - } - - setup_columns() { - if (this.whitelist_cols === '*') { - const blacklist_cols = this.blacklist_cols.split(' '); - this.show_columns = this.table_columns.filter(col => blacklist_cols.indexOf(col) === -1); - } else { - this.show_columns = this.whitelist_cols.split(' '); - } - this.display_columns = this.show_columns.slice(); - for(let i=0; i < this.table_columns.length; ++i) { - if (this.display_columns.indexOf(this.table_columns[i]) === -1) { - this.display_columns.push(this.table_columns[i]); - } - } - } - - set_datatable(columns) { + set_datatable() { const lang_de_url = 'datatables/i18n/German.json'; const lang_en_url = 'datatables/i18n/English.json'; - this.table = $(this.shadowRoot.querySelector('#dt')).DataTable({ - destroy: true, + + if (this.table) { + this.table.destroy(); + } + this.table = $(this.querySelector('table')).DataTable({ autoWidth: false, language: { url: this.lang === 'de' ? lang_de_url : lang_en_url, }, - columns: columns, - data: [], paging: this.paging, searching: this.searching, - columnDefs: [ - { - "render": function ( data, type, row ) { - let itemText = data; - if (itemText) { - let dat = itemText.toString(); - if (dat.match(/\+\d{2} \(\d+\) \d+/)) { - itemText = "<a href='tel:" + dat + "'>" + dat + '</a>'; - } else if (dat.match(/\w+(?:\+\w+)?@(?:\w+\.)+\w+/)) { - itemText = "<a href='mailto:" + dat + "'>" + dat + '</a>'; - } else if (dat.match(/(\d{4})-(\d{2})-(\d{2})/)) { - itemText = dat.replace(/(\d{4})-(\d{2})-(\d{2})/, "$3.$2.$1"); - // itemText = dat.replace(/(\d{4})-(\d{2})-(\d{2})/, "<input type='date' value='$1-$2-$3' min='$1-$2-$3' max='$1-$2-$3'>"); - // } else if (dat.match(/CAT-\d+/)) { - // itemText = '<button>' + dat + '</button>'; - } - } - // console.log(data); - return itemText; - }, - "targets": [...columns.keys()] - }, - ] }); try { @@ -158,152 +56,22 @@ class DataTableView extends LitElement { } } - update_datatable(columns, rows, is_first_page) { - const that = this; - if (this.table) { - // set column visibility/titles on first page load only - if (is_first_page) { - columns.forEach(function (item) { //, index) { - let i = that.display_columns.indexOf(item.title); - that.table.columns([i]).visible(item.visible === true); - // if column order has changed, update column title also - let t = that.table.columns([i]).header(); - $(t).html(item.title); - }); - } - rows.forEach(row => this.table.row.add(row)); - // now ready to draw - this.table.draw(); - } - } - - async loader(page) { - const apiUrlWithFilter = this.apiUrl + '?search=' + this.filter + '&page=' + page; - const that = this; - - return await fetch(apiUrlWithFilter, { - headers: { - 'Content-Type': 'application/ld+json', - 'Authorization': 'Bearer ' + window.VPUAuthToken, - }, - }) - .then(res => res.json()) - .then(function (data) { - // TODO - that.setup_columns(); - - const items = data['hydra:member']; - let rows = []; - let columns = []; - for (let i = 0; i < that.display_columns.length; ++i) { - columns[i] = { - title: that.display_columns[i], - visible: that.show_columns.indexOf(that.display_columns[i]) > -1 - }; - if (items) { - for (let j = 0; j < items.length; ++j) { - if (rows[j] === undefined) { - rows[j] = []; - } - rows[j][i] = items[j][that.display_columns[i]] || ''; - } - } - } - - that.update_datatable(columns, rows, page === 1); - - if (!that.wait_until_all_loaded) - that.is_loading = false; - - return rows.length; - }); - } - - async call_loader(page) { - return await this.loader(page); - } - - async loadWebPageElement() { - if (window.VPUAuthToken === undefined || window.VPUAuthToken === "") { - return; - } - if (this.apiUrl === null || this.jsonld === null) { - return; - } - - this.is_loading = true; - let page = 1; - while (await this.call_loader(page++) > 0) {} - this.is_loading = false; - } - update(changedProperties) { changedProperties.forEach((oldValue, propName) => { - // noinspection FallThroughInSwitchStatementJS - switch (propName) { - case "lang": - i18n.changeLanguage(this.lang).catch(e => { console.log(e)}); - break; - case "whitelist_cols": - case "blacklist_cols": - this.setup_columns(); - case "filter": - case "paging": - case "searching": - if (this.table) - this.table.clear(); - this.loadWebPageElement().catch(e => { console.log(e); }); - break; - case "value": - case "entryPointUrl": - const that = this; - JSONLD.initialize(this.entryPointUrl, function (jsonld) { - that.jsonld = jsonld; - that.apiUrl = that.jsonld.getApiUrlForEntityName(that.value); - }); - this.loadWebPageElement().catch(e => { console.log(e)}); - break; - default: - // nothing to do for this properties + if (propName === "lang") { + i18n.changeLanguage(this.lang).catch(e => { console.log(e)}); } }); super.update(changedProperties); + this.updateComplete.then(this.set_datatable()).catch(e => { console.log(e)}); } render() { - let dt_css = getAssetURL('datatables/css/jquery.dataTables.min.css'); - let rs_css = getAssetURL('datatables/css/responsive.dataTables.css'); return html` - <link rel="stylesheet" href="${dt_css}"> - <link rel="stylesheet" href="${rs_css}"> <style> - #dt-parent { - display: block; - width: 100%; - min-height: 50px; - position: relative; - } - #cover { - display: ${this.is_loading ? 'block' : 'none'}; - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - z-index: 999; - background: white url("data:image/gif;base64,R0lGODlhEAAQAPQAAP///wAAAPj4+Dg4OISEhAYGBiYmJtbW1qioqBYWFnZ2dmZmZuTk5JiYmMbGxkhISFZWVgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAAQAAAFUCAgjmRpnqUwFGwhKoRgqq2YFMaRGjWA8AbZiIBbjQQ8AmmFUJEQhQGJhaKOrCksgEla+KIkYvC6SJKQOISoNSYdeIk1ayA8ExTyeR3F749CACH5BAAKAAEALAAAAAAQABAAAAVoICCKR9KMaCoaxeCoqEAkRX3AwMHWxQIIjJSAZWgUEgzBwCBAEQpMwIDwY1FHgwJCtOW2UDWYIDyqNVVkUbYr6CK+o2eUMKgWrqKhj0FrEM8jQQALPFA3MAc8CQSAMA5ZBjgqDQmHIyEAIfkEAAoAAgAsAAAAABAAEAAABWAgII4j85Ao2hRIKgrEUBQJLaSHMe8zgQo6Q8sxS7RIhILhBkgumCTZsXkACBC+0cwF2GoLLoFXREDcDlkAojBICRaFLDCOQtQKjmsQSubtDFU/NXcDBHwkaw1cKQ8MiyEAIfkEAAoAAwAsAAAAABAAEAAABVIgII5kaZ6AIJQCMRTFQKiDQx4GrBfGa4uCnAEhQuRgPwCBtwK+kCNFgjh6QlFYgGO7baJ2CxIioSDpwqNggWCGDVVGphly3BkOpXDrKfNm/4AhACH5BAAKAAQALAAAAAAQABAAAAVgICCOZGmeqEAMRTEQwskYbV0Yx7kYSIzQhtgoBxCKBDQCIOcoLBimRiFhSABYU5gIgW01pLUBYkRItAYAqrlhYiwKjiWAcDMWY8QjsCf4DewiBzQ2N1AmKlgvgCiMjSQhACH5BAAKAAUALAAAAAAQABAAAAVfICCOZGmeqEgUxUAIpkA0AMKyxkEiSZEIsJqhYAg+boUFSTAkiBiNHks3sg1ILAfBiS10gyqCg0UaFBCkwy3RYKiIYMAC+RAxiQgYsJdAjw5DN2gILzEEZgVcKYuMJiEAOwAAAAAAAAAAAA==") center center no-repeat; - opacity: .9; - } - #dt { - min-width: 100px; - width: 100%; - } </style> - <div id="dt-parent"> - ${unsafeHTML('<div><table id="dt" class="display"></table></div>')} - <div id="cover"></div> - </div> + <slot name="table"></slot> `; } } diff --git a/packages/data-table-view/src/demo.js b/packages/data-table-view/src/demo.js index 9f4dc5852f9c63f8eba05c83872f5bfeb2088309..289fdc8a173f1b61f2e8b64d661f83e8855ab649 100644 --- a/packages/data-table-view/src/demo.js +++ b/packages/data-table-view/src/demo.js @@ -1,6 +1,6 @@ import 'vpu-auth'; import './data-table-view.js'; -import {setting, getAPiUrl} from './utils.js'; +import {setting, getAssetURL,} from './utils.js'; import {i18n} from './i18n'; import {html, LitElement} from 'lit-element'; import commonUtils from 'vpu-common/utils'; @@ -27,37 +27,21 @@ class DataTableViewDemo extends LitElement { super.update(changedProperties); } - filterChange(e) { - let datatable = this.shadowRoot.querySelector('#dt1'); - datatable.setAttribute('filter', e.target.value); - } - - colsChange(e) { - let datatable = this.shadowRoot.querySelector('#dt1'); - if (datatable === undefined) { alter('datatable not found'); return; } - datatable.setAttribute('whitelisted-columns', e.target.value); - } - render() { + // datatable.net tyles must be applied here :-/ + let dt_css = getAssetURL('datatables/css/jquery.dataTables.min.css'); + let rs_css = getAssetURL('datatables/css/responsive.dataTables.css'); return html` + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css"> + <link rel="stylesheet" href="${dt_css}"> + <link rel="stylesheet" href="${rs_css}"> <style> .box { margin: 10px; padding: 10px; border: 1px solid orange; } - .box2 { - margin: 10px; - padding: 10px; - border: 1px solid green; - } - .box3 { - margin: 10px; - padding: 10px; - border: 1px solid blue; - } </style> - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css"> <section class="section"> <div class="content"> @@ -68,75 +52,175 @@ class DataTableViewDemo extends LitElement { </div> <div class="content"> <h4>DataTable: paging and searching</h4> - <p> - <label for="filter">Filter für die Suche:</label> - <input type="text" name="filter" id="filter" value="" placeholder="Geben Sie mindestens 3 Zeichen ein" @change="${this.filterChange}"> - </p> - <p> - <label for="columns">Spalten im Ergbnis:</label> - <input type="text" name="columns" id="columns" value="*" placeholder="Geben Sie einen Stern * für alle ein" @change="${this.colsChange}"> - </p> - <div class="box"> - <vpu-data-table-view - lang="${this.lang}" - value="Person" - filter="" - whitelisted-columns="*" - blacklisted-columns="phoneExtension name" - id="dt1" - paging - searching - ></vpu-data-table-view> + <div class="box"> + <vpu-data-table-view lang="${this.lang}" paging searching> + <div slot="table"><!-- slot encapsulates table --> + <table class="display"> + <thead> + <tr> + <th>A</th> + <th>B</th> + <th>C</th> + </tr> + </thead> + <tbody> + <tr> + <td>abc</td> + <td>123</td> + <td>a-2-4-g</td> + </tr> + <tr> + <td>def</td> + <td>456</td> + <td>b-3-5-h</td> + </tr> + <tr> + <td>ghi</td> + <td>789</td> + <td>c-4-6-i</td> + </tr> + <tr> + <td>jkl</td> + <td>012</td> + <td>x-8-0-a</td> + </tr> + <tr> + <td>abc</td> + <td>123</td> + <td>a-2-4-g</td> + </tr> + <tr> + <td>def</td> + <td>456</td> + <td>b-3-5-h</td> + </tr> + <tr> + <td>ghi</td> + <td>789</td> + <td>c-4-6-i</td> + </tr> + <tr> + <td>jkl</td> + <td>012</td> + <td>x-8-0-a</td> + </tr> + <tr> + <td>abc</td> + <td>123</td> + <td>a-2-4-g</td> + </tr> + <tr> + <td>def</td> + <td>456</td> + <td>b-3-5-h</td> + </tr> + <tr> + <td>ghi</td> + <td>789</td> + <td>c-4-6-i</td> + </tr> + <tr> + <td>jkl</td> + <td>012</td> + <td>x-8-0-a</td> + </tr> + </tbody> + </table> + </div> + </vpu-data-table-view> </div> - </div> - </section> - <!-- - <section class="section"> - <div class="content"> <h4>DataTable: no paging, no searching</h4> - <div class="box2"> - <vpu-data-table-view - lang="${this.lang}" - value="Person" - filter="Ab" - whitelisted-columns="name telephone email" - blacklisted-columns="" - id="dt2" - wait-until-all-loaded - ></vpu-data-table-view> + <div class="box"> + <vpu-data-table-view lang="${this.lang}"> + <div slot="table"><!-- slot encapsulates table --> + <table class="display"> + <thead> + <tr> + <th>A</th> + <th>B</th> + <th>C</th> + </tr> + </thead> + <tbody> + <tr> + <td>abc</td> + <td>123</td> + <td>a-2-4-g</td> + </tr> + <tr> + <td>ghi</td> + <td>789</td> + <td>c-4-6-i</td> + </tr> + <tr> + <td>jkl</td> + <td>012</td> + <td>x-8-0-a</td> + </tr> + </tbody> + </table> + </div> + </vpu-data-table-view> </div> </div> - </section> - --> - <section class="section"> <div class="content"> - <h4>DataTable: DummyProduct</h4> - <div class="box2"> - <vpu-data-table-view - lang="${this.lang}" - value="DummyProduct" - filter="*" - whitelisted-columns="*" - blacklisted-columns="" - id="dt3" - wait-until-all-loaded - paging - searching - ></vpu-data-table-view> - </div> - <h4>DataTable: nonExistantEntity</h4> - <div class="box3"> - <vpu-data-table-view - lang="${this.lang}" - value="nonExistantEntity" - filter="*" - whitelisted-columns="*" - blacklisted-columns="" - id="dt4" - wait-until-all-loaded - paging - searching - ></vpu-data-table-view> + <h4>Common Table</h4> + <div class="box"> + <!-- <vpu-data-table-view lang="${this.lang}" paging searching> --> + <div slot="table"> + <table class="display"> + <thead> + <tr> + <th>A</th> + <th>B</th> + <th>C</th> + </tr> + </thead> + <tbody> + <tr> + <td>abc</td> + <td>123</td> + <td>a-2-4-g</td> + </tr> + <tr> + <td>def</td> + <td>456</td> + <td>b-3-5-h</td> + </tr> + <tr> + <td>ghi</td> + <td>789</td> + <td>c-4-6-i</td> + </tr> + <tr> + <td>jkl</td> + <td>012</td> + <td>x-8-0-a</td> + </tr> + <tr> + <td>abc</td> + <td>123</td> + <td>a-2-4-g</td> + </tr> + <tr> + <td>def</td> + <td>456</td> + <td>b-3-5-h</td> + </tr> + <tr> + <td>ghi</td> + <td>789</td> + <td>c-4-6-i</td> + </tr> + <tr> + <td>jkl</td> + <td>012</td> + <td>x-8-0-a</td> + </tr> + </tbody> + </table> + </div> + <!-- </vpu-data-table-view> --> </div> </div> </section>