@openremote/or-mwc-components 1.8.0 → 1.8.1
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/package.json +7 -7
- package/build.gradle +0 -36
- package/playwright.config.ts +0 -3
- package/rspack.config.js +0 -7
- package/src/or-mwc-dialog.ts +0 -374
- package/src/or-mwc-drawer.ts +0 -100
- package/src/or-mwc-input.ts +0 -1876
- package/src/or-mwc-list.ts +0 -335
- package/src/or-mwc-menu.ts +0 -279
- package/src/or-mwc-snackbar.ts +0 -157
- package/src/or-mwc-table.ts +0 -712
- package/src/or-mwc-tabs.ts +0 -175
- package/src/style.ts +0 -125
- package/test/or-mwc-input.test.ts +0 -46
- package/tsconfig.json +0 -15
- package/tsconfig.tsbuildinfo +0 -1
package/src/or-mwc-table.ts
DELETED
|
@@ -1,712 +0,0 @@
|
|
|
1
|
-
import {css, html, LitElement, TemplateResult, unsafeCSS} from "lit";
|
|
2
|
-
import {customElement, property, state} from "lit/decorators.js";
|
|
3
|
-
import {classMap} from "lit/directives/class-map.js";
|
|
4
|
-
import {until} from 'lit/directives/until.js';
|
|
5
|
-
import {MDCDataTable} from "@material/data-table";
|
|
6
|
-
import {when} from 'lit/directives/when.js';
|
|
7
|
-
import {DefaultColor3, DefaultColor2, DefaultColor1} from "@openremote/core";
|
|
8
|
-
import {i18next} from "@openremote/or-translate";
|
|
9
|
-
import {InputType, OrInputChangedEvent} from "./or-mwc-input";
|
|
10
|
-
import { styleMap } from "lit/directives/style-map.js";
|
|
11
|
-
import moment from "moment";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const dataTableStyle = require("@material/data-table/dist/mdc.data-table.css");
|
|
15
|
-
|
|
16
|
-
// language=CSS
|
|
17
|
-
const style = css`
|
|
18
|
-
|
|
19
|
-
:host {
|
|
20
|
-
width: 100%;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
:host([hidden]) {
|
|
24
|
-
display: none;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.mdc-data-table {
|
|
28
|
-
width: 100%;
|
|
29
|
-
overflow: auto;
|
|
30
|
-
max-height: 500px;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.mdc-data-table__paginated {
|
|
34
|
-
overflow: hidden;
|
|
35
|
-
max-height: 700px;
|
|
36
|
-
justify-content: space-between;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.mdc-data-table__fullheight {
|
|
40
|
-
height: 100%;
|
|
41
|
-
max-height: none !important;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/* first column should be sticky*/
|
|
45
|
-
.mdc-data-table.has-sticky-first-column tr th:first-of-type,
|
|
46
|
-
.mdc-data-table.has-sticky-first-column tr td:first-of-type {
|
|
47
|
-
z-index: 1;
|
|
48
|
-
position: sticky;
|
|
49
|
-
left: 0;
|
|
50
|
-
background-color: ${unsafeCSS(DefaultColor2)};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.mdc-data-table.has-sticky-first-column tr th:first-of-type {
|
|
54
|
-
z-index: 2;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
thead th {
|
|
58
|
-
box-shadow: 0 1px 0 0 rgb(229, 229, 229);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.mdc-data-table.has-sticky-first-column tr td:first-of-type {
|
|
62
|
-
box-shadow: 1px 0 0 0 rgb(229, 229, 229);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
thead th:first-of-type {
|
|
66
|
-
box-shadow: 1px 1px 0 0 rgb(229, 229, 229);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
th {
|
|
70
|
-
position: sticky;
|
|
71
|
-
top: 0;
|
|
72
|
-
background-color: ${unsafeCSS(DefaultColor1)};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
th, td {
|
|
76
|
-
cursor: default;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.mdc-data-table__header-cell {
|
|
80
|
-
font-weight: bold;
|
|
81
|
-
color: ${unsafeCSS(DefaultColor3)};
|
|
82
|
-
font-size: 14px;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.mdc-data-table__pagination-rows-per-page-select {
|
|
86
|
-
/*min-width: 112px;*/
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.mdc-data-table__pagination {
|
|
90
|
-
min-height: 64px;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.mdc-data-table__cell--clickable {
|
|
94
|
-
cursor: pointer;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.sort-button {
|
|
98
|
-
padding-right: 0;
|
|
99
|
-
border: none;
|
|
100
|
-
color: ${unsafeCSS(DefaultColor3)};
|
|
101
|
-
background-color: transparent;
|
|
102
|
-
cursor: pointer;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
.sort-button-reverse {
|
|
106
|
-
padding-left: 0;
|
|
107
|
-
border: none;
|
|
108
|
-
color: ${unsafeCSS(DefaultColor3)};
|
|
109
|
-
cursor: pointer;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.sortable {
|
|
113
|
-
flex-direction: row;
|
|
114
|
-
cursor: pointer;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
.sortable-reverse {
|
|
118
|
-
flex-direction: row-reverse;
|
|
119
|
-
cursor: pointer;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
.hidden {
|
|
123
|
-
visibility: hidden;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
#column-1 {
|
|
127
|
-
width: var(--or-mwc-table-column-width-1, unset);
|
|
128
|
-
}
|
|
129
|
-
#column-2 {
|
|
130
|
-
width: var(--or-mwc-table-column-width-2, unset);
|
|
131
|
-
}
|
|
132
|
-
#column-3 {
|
|
133
|
-
width: var(--or-mwc-table-column-width-3, unset);
|
|
134
|
-
}
|
|
135
|
-
#column-4 {
|
|
136
|
-
width: var(--or-mwc-table-column-width-4, unset);
|
|
137
|
-
}
|
|
138
|
-
#column-5 {
|
|
139
|
-
width: var(--or-mwc-table-column-width-5, unset);
|
|
140
|
-
}
|
|
141
|
-
#column-6 {
|
|
142
|
-
width: var(--or-mwc-table-column-width-6, unset);
|
|
143
|
-
}
|
|
144
|
-
#column-7 {
|
|
145
|
-
width: var(--or-mwc-table-column-width-7, unset);
|
|
146
|
-
}
|
|
147
|
-
#column-8 {
|
|
148
|
-
width: var(--or-mwc-table-column-width-8, unset);
|
|
149
|
-
}
|
|
150
|
-
#column-9 {
|
|
151
|
-
width: var(--or-mwc-table-column-width-9, unset);
|
|
152
|
-
}
|
|
153
|
-
#column-10 {
|
|
154
|
-
width: var(--or-mwc-table-column-width-10, unset);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
@media screen and (max-width: 768px) {
|
|
158
|
-
.hide-mobile {
|
|
159
|
-
display: none;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
`;
|
|
163
|
-
|
|
164
|
-
export interface TableConfig {
|
|
165
|
-
columnFilter?: string[];
|
|
166
|
-
stickyFirstColumn?: boolean;
|
|
167
|
-
fullHeight?: boolean;
|
|
168
|
-
pagination?: {
|
|
169
|
-
enable?: boolean;
|
|
170
|
-
options?: number[];
|
|
171
|
-
}
|
|
172
|
-
multiSelect?: boolean;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export interface TableColumn {
|
|
176
|
-
title?: string,
|
|
177
|
-
isNumeric?: boolean,
|
|
178
|
-
hideMobile?: boolean,
|
|
179
|
-
isSortable?: boolean
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export type TableContent = string | number | Date | TemplateResult
|
|
183
|
-
|
|
184
|
-
export interface TableRow {
|
|
185
|
-
content?: TableContent[]
|
|
186
|
-
clickable?: boolean
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export interface OrMwcTableRowClickDetail {
|
|
190
|
-
index: number
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export interface OrMwcTableRowSelectDetail extends OrMwcTableRowClickDetail {
|
|
194
|
-
state: boolean
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export class OrMwcTableRowClickEvent extends CustomEvent<OrMwcTableRowClickDetail> {
|
|
198
|
-
|
|
199
|
-
public static readonly NAME = "or-mwc-table-row-click";
|
|
200
|
-
|
|
201
|
-
constructor(index: number) {
|
|
202
|
-
super(OrMwcTableRowClickEvent.NAME, {
|
|
203
|
-
detail: {
|
|
204
|
-
index: index
|
|
205
|
-
},
|
|
206
|
-
bubbles: true,
|
|
207
|
-
composed: true
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
export class OrMwcTableRowSelectEvent extends CustomEvent<OrMwcTableRowSelectDetail> {
|
|
213
|
-
|
|
214
|
-
public static readonly NAME = "or-mwc-table-row-select";
|
|
215
|
-
|
|
216
|
-
constructor(index: number, state: boolean) {
|
|
217
|
-
super(OrMwcTableRowSelectEvent.NAME, {
|
|
218
|
-
detail: {
|
|
219
|
-
index: index,
|
|
220
|
-
state: state
|
|
221
|
-
},
|
|
222
|
-
bubbles: true,
|
|
223
|
-
composed: true
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
@customElement("or-mwc-table")
|
|
229
|
-
export class OrMwcTable extends LitElement {
|
|
230
|
-
|
|
231
|
-
static get styles() {
|
|
232
|
-
return [
|
|
233
|
-
css`${unsafeCSS(dataTableStyle)}`,
|
|
234
|
-
style
|
|
235
|
-
];
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
@property({type: Array})
|
|
239
|
-
public columns?: TableColumn[] | string[];
|
|
240
|
-
|
|
241
|
-
@property({type: Object}) // to manually control HTML
|
|
242
|
-
protected columnsTemplate?: TemplateResult;
|
|
243
|
-
|
|
244
|
-
@property({type: Array})
|
|
245
|
-
public rows?: TableRow[] | string[][];
|
|
246
|
-
|
|
247
|
-
@property({type: Object}) // to manually control HTML (requires td and tr elements)
|
|
248
|
-
protected rowsTemplate?: TemplateResult;
|
|
249
|
-
|
|
250
|
-
@property({type: Array})
|
|
251
|
-
protected config: TableConfig = {
|
|
252
|
-
columnFilter: [],
|
|
253
|
-
stickyFirstColumn: true,
|
|
254
|
-
fullHeight: false,
|
|
255
|
-
pagination: {
|
|
256
|
-
enable: false
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
@property({type: Number})
|
|
261
|
-
protected paginationIndex: number = 0;
|
|
262
|
-
|
|
263
|
-
@property({type: Number})
|
|
264
|
-
public paginationSize: number = 10;
|
|
265
|
-
|
|
266
|
-
@state()
|
|
267
|
-
protected _dataTable?: MDCDataTable;
|
|
268
|
-
|
|
269
|
-
@property({ type: String })
|
|
270
|
-
protected sortDirection: 'ASC' | 'DESC' = 'ASC';
|
|
271
|
-
|
|
272
|
-
@property({type: Number})
|
|
273
|
-
protected sortIndex?: number = -1;
|
|
274
|
-
|
|
275
|
-
@property({type: Array})
|
|
276
|
-
public selectedRows?: TableRow[] | string[][] | any[] = [];
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
/* ------------------- */
|
|
280
|
-
|
|
281
|
-
protected firstUpdated(changedProperties: Map<string, any>) {
|
|
282
|
-
const elem = this.shadowRoot!.querySelector('.mdc-data-table');
|
|
283
|
-
this._dataTable = new MDCDataTable(elem!);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
protected updated(changedProperties: Map<string, any>) {
|
|
287
|
-
if ((changedProperties.has('paginationIndex') || changedProperties.has('paginationSize')) && this.config.pagination?.enable) {
|
|
288
|
-
const elem = (this._dataTable ? this._dataTable.root.children[0] : this.shadowRoot!.querySelector('.mdc-data-table__table-container'));
|
|
289
|
-
|
|
290
|
-
// Using an observer to prevent forced reflow / DOM measurements; prevents blocking the thread
|
|
291
|
-
const observer = new IntersectionObserver((entries, observer) => {
|
|
292
|
-
(entries[0].target as HTMLElement).scrollTop = 0;
|
|
293
|
-
observer.unobserve(entries[0].target);
|
|
294
|
-
})
|
|
295
|
-
observer.observe(elem!);
|
|
296
|
-
|
|
297
|
-
// Reset selected rows properties
|
|
298
|
-
this.selectedRows = [];
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
protected render() {
|
|
303
|
-
const tableClasses = {
|
|
304
|
-
"mdc-data-table": true,
|
|
305
|
-
"mdc-data-table__paginated": !!this.config.pagination?.enable,
|
|
306
|
-
"mdc-data-table__fullheight": !!this.config.fullHeight,
|
|
307
|
-
"has-sticky-first-column": !!this.config.stickyFirstColumn
|
|
308
|
-
}
|
|
309
|
-
// Only show pagination if enabled in config, and when "the amount of rows doesn't fit on the page".
|
|
310
|
-
const showPagination = this.config.pagination?.enable && (!!this.rowsTemplate || (this.rows && (this.rows.length > this.paginationSize)));
|
|
311
|
-
const tableWidth = this.shadowRoot?.firstElementChild?.clientWidth;
|
|
312
|
-
return html`
|
|
313
|
-
<div class="${classMap(tableClasses)}">
|
|
314
|
-
<div class="mdc-data-table__table-container" style="flex: 1;">
|
|
315
|
-
<table class="mdc-data-table__table">
|
|
316
|
-
<!-- Header row that normally includes entries like 'id' and 'name'. You can use either a template or a list of columns -->
|
|
317
|
-
${when(this.columnsTemplate, () => this.columnsTemplate, () => {
|
|
318
|
-
return this.columns ? html`
|
|
319
|
-
<thead>
|
|
320
|
-
<tr class="mdc-data-table__header-row">
|
|
321
|
-
${this.columns.map((column: TableColumn | string, index: number) => {
|
|
322
|
-
const styles = {
|
|
323
|
-
width: this.getColumnWidth(index, this.columns, tableWidth),
|
|
324
|
-
maxWidth: this.getMaxColumnWidth(index, this.columns, tableWidth),
|
|
325
|
-
} as any;
|
|
326
|
-
if(index === 0 && this.config.multiSelect){
|
|
327
|
-
const allSelected = this.rows && this.rows.length > 0 && this.selectedRows?.length === this.rows?.length;
|
|
328
|
-
const indeterminate = !allSelected && this.selectedRows && this.selectedRows.length > 0;
|
|
329
|
-
return html`
|
|
330
|
-
<th class="mdc-data-table__header-cell mdc-data-table__header-cell--checkbox"
|
|
331
|
-
role="columnheader" scope="col">
|
|
332
|
-
<or-mwc-input type="${InputType.CHECKBOX}" id="checkbox"
|
|
333
|
-
.indeterminate="${indeterminate}" .value="${allSelected}"
|
|
334
|
-
@or-mwc-input-changed="${(ev: OrInputChangedEvent) => this.onCheckChanged(ev, ev.detail.value, "all")}">
|
|
335
|
-
</or-mwc-input>
|
|
336
|
-
</th>
|
|
337
|
-
${(typeof column === "string") ? html`
|
|
338
|
-
<th class="mdc-data-table__header-cell ${this.config.multiSelect ? "mdc-data-table__header-cell" : ''}" id="column-${index + 1}"
|
|
339
|
-
role="columnheader" scope="col"
|
|
340
|
-
title="${column}">
|
|
341
|
-
column
|
|
342
|
-
</th>
|
|
343
|
-
` : html`
|
|
344
|
-
<th class="mdc-data-table__header-cell ${classMap({
|
|
345
|
-
'mdc-data-table__cell--numeric': !!column.isNumeric,
|
|
346
|
-
'hide-mobile': !!column.hideMobile,
|
|
347
|
-
'mdc-data-table__header-cell--with-sort': !!column.isSortable,
|
|
348
|
-
})}"
|
|
349
|
-
role="columnheader" scope="col" title="${column.title}" data-column-id="${column.title}"
|
|
350
|
-
@click="${(ev: MouseEvent) => column.isSortable! ? this.onColumnSort(ev, index, this.sortDirection!) : ''}">
|
|
351
|
-
${(!column.isSortable ? column.title : until(this.getSortHeader(index, column.title!, this.sortDirection!), html`${i18next.t('loading')}`))}
|
|
352
|
-
</th>
|
|
353
|
-
`
|
|
354
|
-
}`
|
|
355
|
-
}
|
|
356
|
-
return (typeof column == "string") ? html`
|
|
357
|
-
<th class="mdc-data-table__header-cell ${!!this.config.multiSelect ? "mdc-data-table__header-cell" : ''}" id="column-${index+1}" role="columnheader" scope="col"
|
|
358
|
-
title="${column}">
|
|
359
|
-
${column}
|
|
360
|
-
</th>
|
|
361
|
-
` : html`
|
|
362
|
-
<th class="mdc-data-table__header-cell ${classMap({
|
|
363
|
-
'mdc-data-table__cell--numeric': !!column.isNumeric,
|
|
364
|
-
'hide-mobile': !!column.hideMobile,
|
|
365
|
-
'mdc-data-table__header-cell--with-sort': !!column.isSortable,
|
|
366
|
-
})}"
|
|
367
|
-
style="${styleMap(styles)}"
|
|
368
|
-
role="columnheader" scope="col" title="${column.title}" data-column-id="${column.title}"
|
|
369
|
-
@click="${(ev: MouseEvent) => column.isSortable! ? this.onColumnSort(ev, index, this.sortDirection ? this.sortDirection : 'ASC') : ''}">
|
|
370
|
-
${(!column.isSortable ? column.title : until(this.getSortHeader(index, column.title!, this.sortDirection!, !!column.isNumeric), html`${i18next.t('loading')}`))}
|
|
371
|
-
</th>
|
|
372
|
-
`
|
|
373
|
-
})}
|
|
374
|
-
</tr>
|
|
375
|
-
</thead>
|
|
376
|
-
` : undefined;
|
|
377
|
-
})}
|
|
378
|
-
<!-- Table content, where either the template or an array of rows is displayed -->
|
|
379
|
-
<tbody class="mdc-data-table__content">
|
|
380
|
-
${when(this.rowsTemplate, () => {
|
|
381
|
-
if (this.config.pagination?.enable) { // if paginated, filter out the rows by index by manually collecting a list of <tr> elements.
|
|
382
|
-
this.updateComplete.then(async () => {
|
|
383
|
-
const elem = await this.getTableElem(false);
|
|
384
|
-
const rows = elem?.querySelectorAll('tr');
|
|
385
|
-
rows?.forEach((row, index) => {
|
|
386
|
-
const hidden = (index <= (this.paginationIndex * this.paginationSize) || index > (this.paginationIndex * this.paginationSize) + this.paginationSize) && !row.classList.contains('mdc-data-table__header-row');
|
|
387
|
-
row.style.display = (hidden ? 'none' : 'table-row');
|
|
388
|
-
});
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
return html`${this.rowsTemplate}`;
|
|
392
|
-
}, () => {
|
|
393
|
-
return this.rows ? (this.rows as any[])
|
|
394
|
-
.filter((row, index) => !this.config.pagination?.enable || (index >= (this.paginationIndex * this.paginationSize)) && (index < (this.paginationIndex * this.paginationSize + this.paginationSize)))
|
|
395
|
-
.map((item: TableRow | string[]) => {
|
|
396
|
-
const content: TableContent[] | undefined = (Array.isArray(item) ? item : (item as TableRow).content);
|
|
397
|
-
return html`
|
|
398
|
-
<tr class="mdc-data-table__row" @click="${(ev: MouseEvent) => this.onRowClick(ev, item)}">
|
|
399
|
-
${content?.map((cell: TableContent, index: number) => {
|
|
400
|
-
const classes = {
|
|
401
|
-
"mdc-data-table__cell": true,
|
|
402
|
-
"mdc-data-table__cell--numeric": typeof cell === "number",
|
|
403
|
-
"mdc-data-table__cell--clickable": (!Array.isArray(item) && (item as TableRow).clickable)!,
|
|
404
|
-
"hide-mobile": (this.columns && typeof this.columns[index] != "string" && (this.columns[index] as TableColumn).hideMobile)!
|
|
405
|
-
}
|
|
406
|
-
const styles = {
|
|
407
|
-
maxWidth: this.getMaxColumnWidth(index, this.columns, tableWidth),
|
|
408
|
-
} as any;
|
|
409
|
-
return html`
|
|
410
|
-
${when(index === 0 && this.config.multiSelect, () => html`
|
|
411
|
-
<td class="mdc-data-table__cell mdc-data-table__cell--checkbox" >
|
|
412
|
-
<div class="">
|
|
413
|
-
<or-mwc-input type="${InputType.CHECKBOX}" id="checkbox-${index}"
|
|
414
|
-
@or-mwc-input-changed="${(ev: OrInputChangedEvent) => this.onCheckChanged(ev,ev.detail.value,"single",item)}"
|
|
415
|
-
.value="${this.selectedRows?.includes(item)}"
|
|
416
|
-
></or-mwc-input>
|
|
417
|
-
</div>
|
|
418
|
-
</td>
|
|
419
|
-
`)}
|
|
420
|
-
<td class="${classMap(classes)}" title="${typeof cell === 'object' ? "" : cell}" style="${styleMap(styles)}">
|
|
421
|
-
${until(this.getTableContent(cell))}
|
|
422
|
-
</td>
|
|
423
|
-
`;
|
|
424
|
-
})}
|
|
425
|
-
</tr>
|
|
426
|
-
`
|
|
427
|
-
})
|
|
428
|
-
: undefined;
|
|
429
|
-
})}
|
|
430
|
-
</tbody>
|
|
431
|
-
</table>
|
|
432
|
-
</div>
|
|
433
|
-
<!-- Pagination HTML, shown on the bottom right. Same as Material Design spec -->
|
|
434
|
-
${when(showPagination, () => {
|
|
435
|
-
const options = this.config.pagination?.options || [10, 25, 100];
|
|
436
|
-
return html`
|
|
437
|
-
<div class="mdc-data-table__pagination">
|
|
438
|
-
<div class="mdc-data-table__pagination-trailing">
|
|
439
|
-
<div class="mdc-data-table__pagination-rows-per-page">
|
|
440
|
-
<div class="mdc-data-table__pagination-rows-per-page-label">
|
|
441
|
-
${i18next.t('rowsPerPage')}
|
|
442
|
-
</div>
|
|
443
|
-
<or-mwc-input class="mdc-data-table__pagination-rows-per-page-select"
|
|
444
|
-
.type="${InputType.SELECT}" compact comfortable outlined .readonly="${options.length === 1}"
|
|
445
|
-
.value="${this.paginationSize}" .options="${options}"
|
|
446
|
-
@or-mwc-input-changed="${(ev: OrInputChangedEvent) => {
|
|
447
|
-
this.paginationSize = ev.detail.value;
|
|
448
|
-
this.paginationIndex = 0;
|
|
449
|
-
}}"
|
|
450
|
-
></or-mwc-input>
|
|
451
|
-
</div>
|
|
452
|
-
${until(this.getPaginationControls(), html`${i18next.t('loading')}`)}
|
|
453
|
-
</div>
|
|
454
|
-
</div>
|
|
455
|
-
`
|
|
456
|
-
})}
|
|
457
|
-
</div>
|
|
458
|
-
`;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
/**
|
|
462
|
-
* Function that is responsible for formatting the table content.
|
|
463
|
-
* For example; dates should be formatted differently than strings, numbers and HTML templates.
|
|
464
|
-
*/
|
|
465
|
-
protected getTableContent(content: TableContent): TemplateResult | string {
|
|
466
|
-
if (typeof content === 'string' || typeof content === 'number') {
|
|
467
|
-
return content as string;
|
|
468
|
-
} else if (content instanceof Date) {
|
|
469
|
-
return moment(content).format("lll");
|
|
470
|
-
} else {
|
|
471
|
-
return content;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
/**
|
|
476
|
-
* "When user clicks on a row", it dispatches an {@link OrMwcTableRowClickEvent} to the parent component / listeners.
|
|
477
|
-
*/
|
|
478
|
-
protected onRowClick(ev: MouseEvent, item: TableRow | string[]) {
|
|
479
|
-
if(this.config.multiSelect) {
|
|
480
|
-
const elem = ev.target as HTMLElement;
|
|
481
|
-
if(elem.nodeName === "OR-MWC-INPUT" && elem.id.includes('checkbox')) {
|
|
482
|
-
return; // if checkbox is clicked, the regular "click on row" should not trigger.
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
this.dispatchEvent(new OrMwcTableRowClickEvent((this.rows as any[]).indexOf(item)))
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* "When user clicks on a checkbox" when multiselect is enabled,
|
|
490
|
-
* it dispatches an {@link OrMwcTableRowSelectEvent} to the parent component / listeners.
|
|
491
|
-
*/
|
|
492
|
-
protected onCheckChanged(event: Event, checked: boolean, type: "all" | "single", item?: any) {
|
|
493
|
-
event.stopPropagation();
|
|
494
|
-
if (type === "all") {
|
|
495
|
-
if (checked) {
|
|
496
|
-
this.selectedRows = this.rows;
|
|
497
|
-
} else {
|
|
498
|
-
this.selectedRows = [];
|
|
499
|
-
}
|
|
500
|
-
// Dispatch events to parent component
|
|
501
|
-
this.rows?.forEach((_, index) => this.dispatchEvent(new OrMwcTableRowSelectEvent(index, checked)));
|
|
502
|
-
|
|
503
|
-
} else {
|
|
504
|
-
if (checked) {
|
|
505
|
-
if (this.selectedRows === undefined) {
|
|
506
|
-
this.selectedRows = [item];
|
|
507
|
-
} else if (this.selectedRows.indexOf(item) === -1) {
|
|
508
|
-
this.selectedRows.push(item);
|
|
509
|
-
this.requestUpdate('selectedRows');
|
|
510
|
-
}
|
|
511
|
-
} else {
|
|
512
|
-
this.selectedRows = this.selectedRows?.filter((e: TableRow) => e !== item);
|
|
513
|
-
}
|
|
514
|
-
// Dispatch events to parent component
|
|
515
|
-
const index = this.rows?.indexOf(item);
|
|
516
|
-
if (index !== undefined && index > -1) {
|
|
517
|
-
this.dispatchEvent(new OrMwcTableRowSelectEvent(index, checked));
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
/**
|
|
523
|
-
* Event handling function for when users try to sort the rows within a column.
|
|
524
|
-
*/
|
|
525
|
-
async onColumnSort(ev: MouseEvent, index: number, sortDirection: 'ASC' | 'DESC') {
|
|
526
|
-
if (this.config.multiSelect) {
|
|
527
|
-
const elem = ev.target as HTMLElement;
|
|
528
|
-
if (elem.nodeName === "OR-MWC-INPUT" && elem.id.includes('checkbox')) {
|
|
529
|
-
return; // if checkbox is clicked, sort should not trigger.
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
const newDirection = (sortDirection == 'ASC') ? 'DESC' : 'ASC';
|
|
533
|
-
this.sortDirection = newDirection;
|
|
534
|
-
this.sortIndex = index;
|
|
535
|
-
if (this.rows && this.rows.length > 0) {
|
|
536
|
-
|
|
537
|
-
// If string array of rows,
|
|
538
|
-
if (Array.isArray(this.rows[0])) {
|
|
539
|
-
(this.rows as string[][]).sort((a: string[], b: string[]) => {
|
|
540
|
-
return this.sortPrimitiveRows(a, b, index, newDirection);
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
// Else if row is TableRow
|
|
544
|
-
else {
|
|
545
|
-
(this.rows as TableRow[]).sort((a: TableRow, b: TableRow) => {
|
|
546
|
-
return this.sortObjectRows(a, b, index, newDirection);
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
/**
|
|
553
|
-
* Sorts either numbers incrementally or strings alphabetically depending on the sorting direction.
|
|
554
|
-
*/
|
|
555
|
-
protected sortPrimitiveRows(rowA: string[] | number[], rowB: string[] | number[], cIndex: number, sortDirection: 'ASC' | 'DESC'): number {
|
|
556
|
-
const cellA = rowA[cIndex];
|
|
557
|
-
const cellB = rowB[cIndex];
|
|
558
|
-
if (!cellA && !cellB) {
|
|
559
|
-
return 0;
|
|
560
|
-
} else if (!cellA || cellA.toString().length === 0) {
|
|
561
|
-
return sortDirection === 'DESC' ? 1 : -1;
|
|
562
|
-
} else if (!cellB || cellB.toString().length === 0) {
|
|
563
|
-
return sortDirection === 'DESC' ? -1 : 1;
|
|
564
|
-
} else {
|
|
565
|
-
if (typeof cellA === 'string' && typeof cellB === 'string') {
|
|
566
|
-
if (sortDirection === 'DESC') {
|
|
567
|
-
return (cellB as string).localeCompare(cellA as string, 'en', {numeric: true});
|
|
568
|
-
} else {
|
|
569
|
-
return (cellA as string).localeCompare(cellB as string, 'en', {numeric: true});
|
|
570
|
-
}
|
|
571
|
-
} else if (typeof cellA === 'number' && typeof cellB === 'number') {
|
|
572
|
-
if (sortDirection === 'DESC') {
|
|
573
|
-
return cellA > cellB ? -1 : 1;
|
|
574
|
-
} else {
|
|
575
|
-
return cellA > cellB ? 1 : -1;
|
|
576
|
-
}
|
|
577
|
-
} else {
|
|
578
|
-
console.warn("sortPrimitiveRows() was called using neither a number nor a string.")
|
|
579
|
-
return 1;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
/**
|
|
585
|
-
* Function that handles several sorts of table content; from dates to HTML templates.
|
|
586
|
-
* */
|
|
587
|
-
protected sortObjectRows(rowA: TableRow, rowB: TableRow, cIndex: number, sortDirection: 'ASC' | 'DESC'): number {
|
|
588
|
-
const cellA = rowA.content?.[cIndex];
|
|
589
|
-
const cellB = rowB.content?.[cIndex];
|
|
590
|
-
const isSortable = (content: any) => (typeof content === 'string' || typeof content === 'number');
|
|
591
|
-
const isTemplate = (content: any) => (content.strings !== undefined && content.values !== undefined);
|
|
592
|
-
|
|
593
|
-
if (!cellA || !cellB || isSortable(cellA) || isSortable(cellB)) {
|
|
594
|
-
return this.sortPrimitiveRows([cellA as string], [cellB as string], 0, sortDirection);
|
|
595
|
-
|
|
596
|
-
} else if (cellA instanceof Date && cellB instanceof Date) {
|
|
597
|
-
return this.sortDateRows(cellA, cellB, 0, sortDirection);
|
|
598
|
-
|
|
599
|
-
} else if (isTemplate(cellA) || isTemplate(cellB)) {
|
|
600
|
-
return this.sortTemplateRows(cellA, cellB, 0, sortDirection);
|
|
601
|
-
}
|
|
602
|
-
return 1;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
protected sortDateRows(dateA: Date, dateB: Date, cIndex: number, sortDirection: 'ASC' | 'DESC'): number {
|
|
606
|
-
if (sortDirection === 'DESC') {
|
|
607
|
-
return dateA > dateB ? -1 : 1;
|
|
608
|
-
} else {
|
|
609
|
-
return dateA > dateB ? 1 : -1;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
/**
|
|
614
|
-
* Uses the {@link TemplateResult} content to identify and analyze the content.
|
|
615
|
-
* See the documentation here; https://lit.dev/docs/v2/api/templates/#TemplateResult
|
|
616
|
-
* Sometimes it cannot analyze the HTML; if so, it will retain the same order.
|
|
617
|
-
*/
|
|
618
|
-
protected sortTemplateRows(cellA: any, cellB: any, cIndex: number, sortDirection: 'ASC' | 'DESC'): number {
|
|
619
|
-
const valueA: string | undefined = (cellA.values as any[]).filter(v => typeof v === 'string' || typeof v === 'number').map(v => v.toString())?.[0];
|
|
620
|
-
const valueB: string | undefined = (cellB.values as any[]).filter(v => typeof v === 'string' || typeof v === 'number').map(v => v.toString())?.[0];
|
|
621
|
-
if (valueA !== undefined && valueB !== undefined) {
|
|
622
|
-
return this.sortPrimitiveRows([valueA], [valueB], 0, sortDirection);
|
|
623
|
-
} else {
|
|
624
|
-
return 1;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
// HTML for the sort header, that adds click functionality and a up/down arrow.
|
|
629
|
-
async getSortHeader(index: number, title: string, sortDirection: 'ASC' | 'DESC', arrowOnLeft = false): Promise<TemplateResult> {
|
|
630
|
-
this.sortIndex === -1 ? this.sortIndex = index : '';
|
|
631
|
-
return html`
|
|
632
|
-
<div class="mdc-data-table__header-cell-wrapper ${arrowOnLeft ? 'sortable-reverse' : 'sortable'}">
|
|
633
|
-
<div class="mdc-data-table__header-cell-label">
|
|
634
|
-
${title}
|
|
635
|
-
</div>
|
|
636
|
-
<button class="mdc-icon-button material-icons ${arrowOnLeft ? 'sort-button-reverse' : 'sort-button'} ${this.sortIndex === index ? '' : 'hidden'}"
|
|
637
|
-
aria-label="Sort by ${title}" aria-describedby="${title}-status-label" aria-hidden="${!(this.sortIndex === index)}">
|
|
638
|
-
<or-icon icon="${sortDirection == 'ASC' ? "arrow-up" : "arrow-down"}"></or-icon>
|
|
639
|
-
</button>
|
|
640
|
-
<div class="mdc-data-table__sort-status-label" aria-hidden="true" id="${title}-status-label">
|
|
641
|
-
</div>
|
|
642
|
-
</div>
|
|
643
|
-
`;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
// HTML for the controls on the bottom of the table.
|
|
648
|
-
// Includes basic pagination for browsing pages, with calculations of where to go.
|
|
649
|
-
async getPaginationControls(): Promise<TemplateResult> {
|
|
650
|
-
const max: number = await this.getRowCount();
|
|
651
|
-
const start: number = (this.paginationIndex * this.paginationSize) + 1;
|
|
652
|
-
let end: number = this.paginationIndex * this.paginationSize + this.paginationSize;
|
|
653
|
-
if (end > max) {
|
|
654
|
-
end = max;
|
|
655
|
-
}
|
|
656
|
-
return html`
|
|
657
|
-
<div class="mdc-data-table__pagination-navigation">
|
|
658
|
-
<div class="mdc-data-table__pagination-total">
|
|
659
|
-
<span>${start}-${end} of ${max}</span>
|
|
660
|
-
</div>
|
|
661
|
-
<or-mwc-input class="mdc-data-table__pagination-button" .type="${InputType.BUTTON}"
|
|
662
|
-
data-first-page="true" icon="page-first" .disabled="${this.paginationIndex == 0}"
|
|
663
|
-
@or-mwc-input-changed="${() => this.paginationIndex = 0}"></or-mwc-input>
|
|
664
|
-
<or-mwc-input class="mdc-data-table__pagination-button" .type="${InputType.BUTTON}"
|
|
665
|
-
data-prev-page="true" icon="chevron-left" .disabled="${this.paginationIndex == 0}"
|
|
666
|
-
@or-mwc-input-changed="${() => this.paginationIndex--}"></or-mwc-input>
|
|
667
|
-
<or-mwc-input class="mdc-data-table__pagination-button" .type="${InputType.BUTTON}"
|
|
668
|
-
data-next-page="true" icon="chevron-right"
|
|
669
|
-
.disabled="${this.paginationIndex * this.paginationSize + this.paginationSize >= max}"
|
|
670
|
-
@or-mwc-input-changed="${() => this.paginationIndex++}"></or-mwc-input>
|
|
671
|
-
<or-mwc-input class="mdc-data-table__pagination-button" .type="${InputType.BUTTON}"
|
|
672
|
-
data-last-page="true" icon="page-last"
|
|
673
|
-
.disabled="${this.paginationIndex * this.paginationSize + this.paginationSize >= max}"
|
|
674
|
-
@or-mwc-input-changed="${async () => {
|
|
675
|
-
let pages: number = max / this.paginationSize;
|
|
676
|
-
pages = pages.toString().includes('.') ? Math.floor(pages) : (pages - 1);
|
|
677
|
-
this.paginationIndex = pages;
|
|
678
|
-
}}"
|
|
679
|
-
></or-mwc-input>
|
|
680
|
-
</div>
|
|
681
|
-
`;
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
// Getting the amount of rows/entries in the table.
|
|
685
|
-
// Makes sure that both the rows, and rowsTemplate properties work.
|
|
686
|
-
async getRowCount(wait: boolean = true, tableElem?: HTMLElement): Promise<number> {
|
|
687
|
-
if (this.rows?.length) {
|
|
688
|
-
return this.rows?.length;
|
|
689
|
-
}
|
|
690
|
-
if (!tableElem) {
|
|
691
|
-
tableElem = await this.getTableElem(wait);
|
|
692
|
-
}
|
|
693
|
-
const rowElems = tableElem?.querySelectorAll('tr');
|
|
694
|
-
return rowElems!.length;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
async getTableElem(wait: boolean = false): Promise<HTMLElement | undefined> {
|
|
698
|
-
if (wait) {
|
|
699
|
-
await this.updateComplete;
|
|
700
|
-
}
|
|
701
|
-
return this._dataTable ? (this._dataTable.root as HTMLElement) : (this.shadowRoot!.querySelector('.mdc-data-table') as HTMLElement);
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
protected getColumnWidth(index: number, columns?: string[] | TableColumn[], tableWidthPx?: number): string | undefined {
|
|
705
|
-
return undefined;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
protected getMaxColumnWidth(index: number, columns?: string[] | TableColumn[], tableWidthPx?: number): string | undefined {
|
|
709
|
-
return undefined;
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
}
|