@exmg/exm-grid 1.0.0
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/README.md +501 -0
- package/assets/arrow-upward.svg +7 -0
- package/index.d.ts +14 -0
- package/index.js +15 -0
- package/package.json +58 -0
- package/src/search/exm-toolbar-search.d.ts +25 -0
- package/src/search/exm-toolbar-search.js +197 -0
- package/src/styles/exm-grid-base-toolbar-styles-css.d.ts +2 -0
- package/src/styles/exm-grid-base-toolbar-styles-css.js +4 -0
- package/src/styles/exm-grid-base-toolbar-styles.scss +89 -0
- package/src/styles/exm-grid-common-styles-css.d.ts +2 -0
- package/src/styles/exm-grid-common-styles-css.js +4 -0
- package/src/styles/exm-grid-common-styles.scss +1 -0
- package/src/styles/exm-grid-pagination-styles-css.d.ts +2 -0
- package/src/styles/exm-grid-pagination-styles-css.js +4 -0
- package/src/styles/exm-grid-pagination-styles.scss +69 -0
- package/src/styles/exm-grid-setting-selection-list-styles-css.d.ts +2 -0
- package/src/styles/exm-grid-setting-selection-list-styles-css.js +4 -0
- package/src/styles/exm-grid-setting-selection-list-styles.scss +8 -0
- package/src/styles/exm-grid-styles-css.d.ts +2 -0
- package/src/styles/exm-grid-styles-css.js +4 -0
- package/src/styles/exm-grid-styles.scss +387 -0
- package/src/table/exm-grid-base-toolbar.d.ts +23 -0
- package/src/table/exm-grid-base-toolbar.js +91 -0
- package/src/table/exm-grid-pagination.d.ts +37 -0
- package/src/table/exm-grid-pagination.js +190 -0
- package/src/table/exm-grid-setting-selection-list.d.ts +24 -0
- package/src/table/exm-grid-setting-selection-list.js +124 -0
- package/src/table/exm-grid-smart-toolbar.d.ts +31 -0
- package/src/table/exm-grid-smart-toolbar.js +138 -0
- package/src/table/exm-grid-toolbar-filters.d.ts +36 -0
- package/src/table/exm-grid-toolbar-filters.js +77 -0
- package/src/table/exm-grid-toolbar.d.ts +42 -0
- package/src/table/exm-grid-toolbar.js +283 -0
- package/src/table/exm-grid.d.ts +130 -0
- package/src/table/exm-grid.js +333 -0
- package/src/table/featrues/exm-column-sortable.d.ts +12 -0
- package/src/table/featrues/exm-column-sortable.js +50 -0
- package/src/table/featrues/exm-row-expandable.d.ts +9 -0
- package/src/table/featrues/exm-row-expandable.js +42 -0
- package/src/table/featrues/exm-row-selectable.d.ts +20 -0
- package/src/table/featrues/exm-row-selectable.js +204 -0
- package/src/table/featrues/exm-row-sortable.d.ts +9 -0
- package/src/table/featrues/exm-row-sortable.js +50 -0
- package/src/table/types/exm-grid-smart-toolbar-types.d.ts +17 -0
- package/src/table/types/exm-grid-smart-toolbar-types.js +6 -0
- package/src/table/types/exm-grid-toolbar-types.d.ts +55 -0
- package/src/table/types/exm-grid-toolbar-types.js +16 -0
- package/src/table/types/exm-grid-types.d.ts +15 -0
- package/src/table/types/exm-grid-types.js +2 -0
- package/src/table/utils/exm-query-selectors.d.ts +12 -0
- package/src/table/utils/exm-query-selectors.js +37 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { html } from 'lit';
|
|
3
|
+
import { ExmgElement } from '@exmg/lit-base/index.js';
|
|
4
|
+
import { property, customElement, state } from 'lit/decorators.js';
|
|
5
|
+
import { cache } from 'lit/directives/cache.js';
|
|
6
|
+
import '@exmg/exm-sortable/exm-sortable.js';
|
|
7
|
+
import { style as exmgGridTableStyles } from '../styles/exm-grid-styles-css.js';
|
|
8
|
+
import { ExmgRowSelectable } from './featrues/exm-row-selectable.js';
|
|
9
|
+
import { ExmgQuerySelectors } from './utils/exm-query-selectors.js';
|
|
10
|
+
import { ExmgRowExpandable } from './featrues/exm-row-expandable.js';
|
|
11
|
+
import { ExmgColumnSortable } from './featrues/exm-column-sortable.js';
|
|
12
|
+
import { ExmgRowSortable } from './featrues/exm-row-sortable.js';
|
|
13
|
+
/**
|
|
14
|
+
* ### Styling
|
|
15
|
+
* The following custom properties and mixins are available for styling:
|
|
16
|
+
*
|
|
17
|
+
* Custom property | Description | Default
|
|
18
|
+
* ----------------|-------------|----------
|
|
19
|
+
* `--exm-arrow-upward-url` | Url to icon that is used for soring direction indicator | `url('/assets/arrow-upward.svg');`
|
|
20
|
+
* `--exm-table-card-width` | table card width | `100%;`
|
|
21
|
+
* `--exm-table-card-margin-bottom` | table bottom margin | `5px;`
|
|
22
|
+
* `--exm-table-color` | table text color | `#02182b;`
|
|
23
|
+
* `--exm-table-background-color` | table background color | `#ffffff;`
|
|
24
|
+
* `--exm-table-box-shadow` | table box shadow | `#{0px 1px 5px 0px rgba($onSurface, .2), 0px 2px 2px 0px rgba($onSurface, .14), 0px 3px 1px -2px rgba($onSurface, .12)},`
|
|
25
|
+
* `--exm-table-row-divider-color` | table rows separator color | `#dbdbdb;`
|
|
26
|
+
* `--exm-table-row-selected-color` | selected row text color | `#02182b;`
|
|
27
|
+
* `--exm-table-row-selected-background-color` | selected row background color | `#e2f1fe;`
|
|
28
|
+
* `--exm-table-row-hover-color` | row hover text color | `#02182b;`
|
|
29
|
+
* `--exm-table-row-hover-background-color` | row hover background color | `#f1f1f1;`
|
|
30
|
+
* `--exm-table-row-dragged-background-color` | sortable row background color when dragged | `#f1f1f1;`
|
|
31
|
+
* `--exm-table-rows-expanded-divider-border` | border between row and expanded row detail | `none;`
|
|
32
|
+
* `--exm-table-rows-expanded-border` | border around row and expanded row detail | `1px solid #dbdbdb;`
|
|
33
|
+
* `--exm-table-rows-expanded-background-color` | background color of row and expanded row detail | `#e2f1fe;`
|
|
34
|
+
* `--exm-table-rows-expanded-color` | text color of row and expanded row detail | `#02182b;`
|
|
35
|
+
* `--exm-table-th-color` | header text color | `#0071dc;`
|
|
36
|
+
* `--exm-table-columns-background-color` | header background color | `#ffffff;`
|
|
37
|
+
* `--exm-table-th-sortable-hover-color` | sortable header hover text color | `#02182b;`
|
|
38
|
+
* `--exm-table-th-height` | header height | `48px;`
|
|
39
|
+
* `--exm-table-th-sort-margin-left` | header margin after text but before icon | `0px;`
|
|
40
|
+
* `--exm-table-td-height` | row cell height | `48px;`
|
|
41
|
+
* `--exm-table-th-sort-icon-height` | sort icon height | `1em;`
|
|
42
|
+
* `--exm-table-th-sort-icon-width` | sort icon width | `1em;`
|
|
43
|
+
* `--exm-table-col-number-padding-right` | right padding of number column | `10px;`
|
|
44
|
+
* `--exm-table-checkbox-cell-width` | width of cell with checkbox | `24px;`
|
|
45
|
+
*/
|
|
46
|
+
let ExmgGrid = class ExmgGrid extends ExmgElement {
|
|
47
|
+
constructor() {
|
|
48
|
+
super(...arguments);
|
|
49
|
+
/**
|
|
50
|
+
* Array of data which mapped to rows
|
|
51
|
+
*/
|
|
52
|
+
this.items = [];
|
|
53
|
+
/**
|
|
54
|
+
* Feature that turn on sort by column
|
|
55
|
+
*/
|
|
56
|
+
this.sortable = false;
|
|
57
|
+
/**
|
|
58
|
+
* Feature that allow sort rows
|
|
59
|
+
* If table has turn on feature `selectable` then it takes precedence and `rowSelectable` will be ignored
|
|
60
|
+
*/
|
|
61
|
+
this.rowsSortable = false;
|
|
62
|
+
/**
|
|
63
|
+
* Feature that allow select rows
|
|
64
|
+
*/
|
|
65
|
+
this.rowsSelectable = false;
|
|
66
|
+
/**
|
|
67
|
+
* By default a ros is also selactable by clicking anywhere inside the row when the rowSElectable option is enabled
|
|
68
|
+
*/
|
|
69
|
+
this.disableRowClickSelection = false;
|
|
70
|
+
/**
|
|
71
|
+
* Map of column names that should be hidden
|
|
72
|
+
*/
|
|
73
|
+
this.hiddenColumnNames = {};
|
|
74
|
+
/**
|
|
75
|
+
* Map of row id and selection state
|
|
76
|
+
* Useful for setup default selection or manipulating programmatically
|
|
77
|
+
*/
|
|
78
|
+
this.selectedRowIds = {};
|
|
79
|
+
/**
|
|
80
|
+
* Map of row id and expandable row state
|
|
81
|
+
* Useful for setup default expanded rows or manipulating programmatically
|
|
82
|
+
*/
|
|
83
|
+
this.expandedRowIds = {};
|
|
84
|
+
/**
|
|
85
|
+
* Set table layout. If fixed then text overflow will be hidden and ellipsis added.
|
|
86
|
+
*/
|
|
87
|
+
this.tableLayout = 'auto';
|
|
88
|
+
this.withToolbar = false;
|
|
89
|
+
this.componentReady = false;
|
|
90
|
+
}
|
|
91
|
+
getQuerySelectors() {
|
|
92
|
+
if (!this.querySelectors) {
|
|
93
|
+
throw new Error('ExmgQuerySelector not initialized yet');
|
|
94
|
+
}
|
|
95
|
+
return this.querySelectors;
|
|
96
|
+
}
|
|
97
|
+
getTable() {
|
|
98
|
+
return this.getQuerySelectors().getTable();
|
|
99
|
+
}
|
|
100
|
+
getTableBody() {
|
|
101
|
+
return this.getQuerySelectors().getTableBody();
|
|
102
|
+
}
|
|
103
|
+
findTableBody() {
|
|
104
|
+
if (this.querySelectors) {
|
|
105
|
+
return this.getTableBody() || undefined;
|
|
106
|
+
}
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
// eslint-disable-next-line
|
|
110
|
+
getColumns(selector = 'th') {
|
|
111
|
+
return this.getQuerySelectors().getColumns(selector);
|
|
112
|
+
}
|
|
113
|
+
getBodyRowSelector(selector = '') {
|
|
114
|
+
return this.getQuerySelectors().getBodyRowSelector(selector);
|
|
115
|
+
}
|
|
116
|
+
canSortRows() {
|
|
117
|
+
return !this.sortable && this.rowsSortable;
|
|
118
|
+
}
|
|
119
|
+
rowsOrderChange(e) {
|
|
120
|
+
setTimeout(() => {
|
|
121
|
+
const { sourceIndex, targetIndex } = e.detail;
|
|
122
|
+
const items = [...this.items];
|
|
123
|
+
const movedElement = items[sourceIndex];
|
|
124
|
+
items.splice(sourceIndex, 1);
|
|
125
|
+
items.splice(targetIndex, 0, movedElement);
|
|
126
|
+
this.dispatchEvent(new CustomEvent('exm-grid-rows-order-updated', {
|
|
127
|
+
composed: true,
|
|
128
|
+
bubbles: true,
|
|
129
|
+
detail: { sourceIndex, targetIndex },
|
|
130
|
+
}));
|
|
131
|
+
this.dispatchEvent(new CustomEvent('exm-grid-rows-order-changed', {
|
|
132
|
+
composed: true,
|
|
133
|
+
bubbles: true,
|
|
134
|
+
detail: { items },
|
|
135
|
+
}));
|
|
136
|
+
}, 0);
|
|
137
|
+
}
|
|
138
|
+
updateColumnVisibility(previousHiddenColumnNames = {}) {
|
|
139
|
+
let visibleColumns = 0;
|
|
140
|
+
this.getColumns().forEach((column, index) => {
|
|
141
|
+
const columnKey = column.getAttribute('data-column-key');
|
|
142
|
+
visibleColumns += this.hiddenColumnNames[columnKey || ''] ? 0 : 1;
|
|
143
|
+
if (columnKey && previousHiddenColumnNames[columnKey] !== this.hiddenColumnNames[columnKey]) {
|
|
144
|
+
const nextDisplayValue = this.hiddenColumnNames[columnKey] ? 'none' : 'table-cell';
|
|
145
|
+
column.style.display = nextDisplayValue;
|
|
146
|
+
this.getTable()
|
|
147
|
+
.querySelectorAll(`tbody.grid-data tr:not(.grid-row-detail) td:nth-child(${index + 1})`)
|
|
148
|
+
.forEach((cell) => {
|
|
149
|
+
cell.style.display = nextDisplayValue;
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
this.updateAutoColspan(visibleColumns);
|
|
154
|
+
}
|
|
155
|
+
updateAutoColspan(visibleColumns) {
|
|
156
|
+
this.getTable()
|
|
157
|
+
.querySelectorAll('[data-auto-colspan]')
|
|
158
|
+
.forEach((element) => {
|
|
159
|
+
const offset = Number.parseInt(element.getAttribute('data-auto-span') || '0', 10);
|
|
160
|
+
element.setAttribute('colspan', (visibleColumns - offset).toString());
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
observeExpandedRowIds(changedProps) {
|
|
164
|
+
if (changedProps.has('expandedRowIds')) {
|
|
165
|
+
Object.entries(this.expandedRowIds).forEach(([rowId, nextExpandedState]) => {
|
|
166
|
+
const expendableToggle = this.getTableBody().querySelector(this.getBodyRowSelector(`[data-row-key="${rowId}"] ${this.expandableToggleSelector}`));
|
|
167
|
+
if (expendableToggle) {
|
|
168
|
+
const isExpanded = expendableToggle.hasAttribute('data-is-expanded');
|
|
169
|
+
if (isExpanded !== nextExpandedState) {
|
|
170
|
+
expendableToggle.dispatchEvent(new MouseEvent('click'));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
observeSelectedRowIds(changedProps) {
|
|
177
|
+
if (changedProps.has('selectedRowIds')) {
|
|
178
|
+
Object.entries(this.selectedRowIds).forEach(([rowId, nextSelectionState]) => {
|
|
179
|
+
const row = this.getTableBody().querySelector(this.getBodyRowSelector(`[data-row-key="${rowId}"]`));
|
|
180
|
+
if (row) {
|
|
181
|
+
const isSelected = row.hasAttribute('data-selected');
|
|
182
|
+
if (isSelected !== nextSelectionState) {
|
|
183
|
+
row.dispatchEvent(new MouseEvent('click'));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
observeItems(changedProps) {
|
|
190
|
+
if (changedProps.has('items') && this.rowSelectableFeature) {
|
|
191
|
+
this.rowSelectableFeature.syncSelectedItems();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async initGridAttributes() {
|
|
195
|
+
await this.updateComplete;
|
|
196
|
+
const toolbarSlot = this.shadowRoot.querySelector('slot[name="toolbar"]');
|
|
197
|
+
if (toolbarSlot && toolbarSlot.assignedNodes && toolbarSlot.assignedNodes().length) {
|
|
198
|
+
// make TS happy - this.withToolbar is declared but never read
|
|
199
|
+
this.withToolbar = this.withToolbar || true;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async firstUpdated() {
|
|
203
|
+
const table = this.shadowRoot.host.querySelector('table');
|
|
204
|
+
const tableBody = table.querySelector('tbody.grid-data');
|
|
205
|
+
this.querySelectors = new ExmgQuerySelectors(table, tableBody);
|
|
206
|
+
this.initGridAttributes();
|
|
207
|
+
const bodyRows = this.querySelectors.getBodyRows();
|
|
208
|
+
if (this.sortable) {
|
|
209
|
+
this.columnSortableFeature = new ExmgColumnSortable(this.querySelectors, (event) => this.dispatchEvent(event), this.defaultSortColumn, this.defaultSortDirection);
|
|
210
|
+
this.columnSortableFeature.initFeature();
|
|
211
|
+
}
|
|
212
|
+
if (this.canSortRows()) {
|
|
213
|
+
this.rowSortableFeature = new ExmgRowSortable(this.querySelectors);
|
|
214
|
+
this.rowSortableFeature.initFeature();
|
|
215
|
+
}
|
|
216
|
+
if (this.rowsSelectable) {
|
|
217
|
+
this.rowSelectableFeature = new ExmgRowSelectable(this.querySelectors, (event) => this.dispatchEvent(event), this.disableRowClickSelection, this.selectableCheckboxSelector);
|
|
218
|
+
this.rowSelectableFeature.initFeature(bodyRows);
|
|
219
|
+
}
|
|
220
|
+
if (this.expandableToggleSelector) {
|
|
221
|
+
this.rowExpandableFeature = new ExmgRowExpandable(this.querySelectors, this.expandableToggleSelector);
|
|
222
|
+
this.rowExpandableFeature.initFeature();
|
|
223
|
+
}
|
|
224
|
+
this.updateColumnVisibility();
|
|
225
|
+
bodyRows.forEach((row) => row.setAttribute('data-initialized', ''));
|
|
226
|
+
this.querySelectors.getColumns('th:not([title])').forEach((col) => col.setAttribute('title', col.innerText));
|
|
227
|
+
this.querySelectors.getTable().setAttribute('data-table-layout', this.tableLayout);
|
|
228
|
+
await this.updateComplete;
|
|
229
|
+
this.componentReady = true;
|
|
230
|
+
}
|
|
231
|
+
updated(changedProps) {
|
|
232
|
+
if (changedProps.has('hiddenColumnNames') || changedProps.has('items')) {
|
|
233
|
+
this.updateColumnVisibility(changedProps.get('hiddenColumnNames'));
|
|
234
|
+
}
|
|
235
|
+
this.observeItems(changedProps);
|
|
236
|
+
this.observeExpandedRowIds(changedProps);
|
|
237
|
+
this.observeSelectedRowIds(changedProps);
|
|
238
|
+
if (this.componentReady && changedProps.has('items')) {
|
|
239
|
+
const bodyRows = this.querySelectors.getBodyRowsNotInitialized();
|
|
240
|
+
if (this.rowSelectableFeature) {
|
|
241
|
+
this.rowSelectableFeature.updateFeature(bodyRows);
|
|
242
|
+
}
|
|
243
|
+
if (this.rowExpandableFeature) {
|
|
244
|
+
this.rowExpandableFeature.updateFeature();
|
|
245
|
+
}
|
|
246
|
+
if (this.rowSortableFeature) {
|
|
247
|
+
this.rowSortableFeature.updateFeature();
|
|
248
|
+
}
|
|
249
|
+
bodyRows.forEach((row) => row.setAttribute('data-initialized', ''));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
renderWithoutSortable() {
|
|
253
|
+
return html ` <slot></slot> `;
|
|
254
|
+
}
|
|
255
|
+
renderWithSortable() {
|
|
256
|
+
return html `
|
|
257
|
+
<exm-sortable
|
|
258
|
+
orientation="${'vertical'}"
|
|
259
|
+
animation-enabled
|
|
260
|
+
item-selector="tbody.grid-data > tr:not(.grid-row-detail)"
|
|
261
|
+
handle-selector=".grid-row-drag-handler"
|
|
262
|
+
.sortableHostNode="${this.findTableBody()}"
|
|
263
|
+
@dom-order-change="${this.rowsOrderChange}"
|
|
264
|
+
>
|
|
265
|
+
<slot></slot>
|
|
266
|
+
</exm-sortable>
|
|
267
|
+
`;
|
|
268
|
+
}
|
|
269
|
+
render() {
|
|
270
|
+
return html `
|
|
271
|
+
<div class="table-card-container">
|
|
272
|
+
<slot name="toolbar"></slot>
|
|
273
|
+
<div class="table-card">
|
|
274
|
+
<div class="table-container">
|
|
275
|
+
${cache(this.canSortRows() ? this.renderWithSortable() : this.renderWithoutSortable())}
|
|
276
|
+
</div>
|
|
277
|
+
<slot name="pagination"></slot>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
`;
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
ExmgGrid.styles = [exmgGridTableStyles];
|
|
284
|
+
__decorate([
|
|
285
|
+
property({ type: Array })
|
|
286
|
+
], ExmgGrid.prototype, "items", void 0);
|
|
287
|
+
__decorate([
|
|
288
|
+
property({ type: Boolean, reflect: true })
|
|
289
|
+
], ExmgGrid.prototype, "sortable", void 0);
|
|
290
|
+
__decorate([
|
|
291
|
+
property({ type: String, attribute: 'default-sort-column' })
|
|
292
|
+
], ExmgGrid.prototype, "defaultSortColumn", void 0);
|
|
293
|
+
__decorate([
|
|
294
|
+
property({ type: String, attribute: 'default-sort-direction' })
|
|
295
|
+
], ExmgGrid.prototype, "defaultSortDirection", void 0);
|
|
296
|
+
__decorate([
|
|
297
|
+
property({ type: Boolean, reflect: true, attribute: 'rows-sortable' })
|
|
298
|
+
], ExmgGrid.prototype, "rowsSortable", void 0);
|
|
299
|
+
__decorate([
|
|
300
|
+
property({ type: Boolean, attribute: 'rows-selectable' })
|
|
301
|
+
], ExmgGrid.prototype, "rowsSelectable", void 0);
|
|
302
|
+
__decorate([
|
|
303
|
+
property({ type: Boolean, attribute: 'disable-row-click-selection' })
|
|
304
|
+
], ExmgGrid.prototype, "disableRowClickSelection", void 0);
|
|
305
|
+
__decorate([
|
|
306
|
+
property({ type: String, attribute: 'selectable-checkbox-selector' })
|
|
307
|
+
], ExmgGrid.prototype, "selectableCheckboxSelector", void 0);
|
|
308
|
+
__decorate([
|
|
309
|
+
property({ type: Object })
|
|
310
|
+
], ExmgGrid.prototype, "hiddenColumnNames", void 0);
|
|
311
|
+
__decorate([
|
|
312
|
+
property({ type: Object })
|
|
313
|
+
], ExmgGrid.prototype, "selectedRowIds", void 0);
|
|
314
|
+
__decorate([
|
|
315
|
+
property({ type: Object })
|
|
316
|
+
], ExmgGrid.prototype, "expandedRowIds", void 0);
|
|
317
|
+
__decorate([
|
|
318
|
+
property({ type: String, attribute: 'expandable-toggle-selector', reflect: true })
|
|
319
|
+
], ExmgGrid.prototype, "expandableToggleSelector", void 0);
|
|
320
|
+
__decorate([
|
|
321
|
+
property({ type: String, attribute: 'table-layout', reflect: true })
|
|
322
|
+
], ExmgGrid.prototype, "tableLayout", void 0);
|
|
323
|
+
__decorate([
|
|
324
|
+
state()
|
|
325
|
+
], ExmgGrid.prototype, "querySelectors", void 0);
|
|
326
|
+
__decorate([
|
|
327
|
+
property({ type: Boolean, reflect: true, attribute: 'data-with-toolbar' })
|
|
328
|
+
], ExmgGrid.prototype, "withToolbar", void 0);
|
|
329
|
+
ExmgGrid = __decorate([
|
|
330
|
+
customElement('exm-grid')
|
|
331
|
+
], ExmgGrid);
|
|
332
|
+
export { ExmgGrid };
|
|
333
|
+
//# sourceMappingURL=exm-grid.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ExmgQuerySelectors } from '../utils/exm-query-selectors.js';
|
|
2
|
+
import { SORT_DIRECTION } from '../types/exm-grid-types.js';
|
|
3
|
+
export declare class ExmgColumnSortable {
|
|
4
|
+
private querySelectors;
|
|
5
|
+
private dispatchEvent;
|
|
6
|
+
private defaultSortColumn?;
|
|
7
|
+
private defaultSortDirection?;
|
|
8
|
+
constructor(qs: ExmgQuerySelectors, de: (e: Event) => boolean, dsc?: string, dsd?: SORT_DIRECTION);
|
|
9
|
+
initFeature(): void;
|
|
10
|
+
private registerListeners;
|
|
11
|
+
private fireSortChanged;
|
|
12
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export class ExmgColumnSortable {
|
|
2
|
+
constructor(qs, de, dsc, dsd) {
|
|
3
|
+
this.querySelectors = qs;
|
|
4
|
+
this.dispatchEvent = de;
|
|
5
|
+
this.defaultSortColumn = dsc;
|
|
6
|
+
this.defaultSortDirection = dsd;
|
|
7
|
+
}
|
|
8
|
+
initFeature() {
|
|
9
|
+
this.querySelectors.getColumns('th[data-sort]').forEach((column) => {
|
|
10
|
+
const columnId = column.getAttribute('data-sort') || column.getAttribute('data-column-key');
|
|
11
|
+
// set default sort column if any
|
|
12
|
+
if (!!this.defaultSortColumn && !!this.defaultSortDirection && this.defaultSortColumn === columnId) {
|
|
13
|
+
column.setAttribute('data-sort-direction', this.defaultSortDirection);
|
|
14
|
+
}
|
|
15
|
+
this.registerListeners(column, columnId);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
registerListeners(column, columnId) {
|
|
19
|
+
column.addEventListener('click', () => {
|
|
20
|
+
const columnSortDirection = column.getAttribute('data-sort-direction');
|
|
21
|
+
const nextSortDirection = columnSortDirection === 'ASC' ? 'DESC' : columnSortDirection === 'DESC' ? undefined : 'ASC';
|
|
22
|
+
// reset previous
|
|
23
|
+
this.querySelectors
|
|
24
|
+
.getColumns('th[data-sort-direction=ASC], th[data-sort-direction=DESC]')
|
|
25
|
+
.forEach((alreadySortedColumn) => {
|
|
26
|
+
if (alreadySortedColumn !== column) {
|
|
27
|
+
alreadySortedColumn.removeAttribute('data-sort-direction');
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
if (nextSortDirection) {
|
|
31
|
+
column.setAttribute('data-sort-direction', nextSortDirection);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
column.removeAttribute('data-sort-direction');
|
|
35
|
+
}
|
|
36
|
+
this.fireSortChanged(columnId, nextSortDirection);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
fireSortChanged(columnId, sortDirection) {
|
|
40
|
+
this.dispatchEvent(new CustomEvent('exm-grid-sort-change', {
|
|
41
|
+
bubbles: true,
|
|
42
|
+
composed: true,
|
|
43
|
+
detail: {
|
|
44
|
+
column: columnId,
|
|
45
|
+
sortDirection: sortDirection ? sortDirection : undefined,
|
|
46
|
+
},
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=exm-column-sortable.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ExmgQuerySelectors } from '../utils/exm-query-selectors.js';
|
|
2
|
+
export declare class ExmgRowExpandable {
|
|
3
|
+
private querySelectors;
|
|
4
|
+
private expandableToggleSelector;
|
|
5
|
+
constructor(qs: ExmgQuerySelectors, ets: string);
|
|
6
|
+
initFeature(): void;
|
|
7
|
+
updateFeature(): void;
|
|
8
|
+
private registerClickListener;
|
|
9
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export class ExmgRowExpandable {
|
|
2
|
+
constructor(qs, ets) {
|
|
3
|
+
this.querySelectors = qs;
|
|
4
|
+
this.expandableToggleSelector = ets;
|
|
5
|
+
}
|
|
6
|
+
initFeature() {
|
|
7
|
+
this.querySelectors
|
|
8
|
+
.getTableBody()
|
|
9
|
+
.querySelectorAll(`${this.expandableToggleSelector}:not([data-is-expandable])`)
|
|
10
|
+
.forEach((triggerElement) => {
|
|
11
|
+
triggerElement.setAttribute('data-is-expandable', '');
|
|
12
|
+
this.registerClickListener(triggerElement);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
updateFeature() {
|
|
16
|
+
this.initFeature();
|
|
17
|
+
}
|
|
18
|
+
registerClickListener(triggerElement) {
|
|
19
|
+
triggerElement.addEventListener('click', (event) => {
|
|
20
|
+
const parentRow = triggerElement.closest('tr');
|
|
21
|
+
const rowDetail = parentRow && parentRow.nextElementSibling;
|
|
22
|
+
if (!parentRow || !rowDetail) {
|
|
23
|
+
// console.error(`Cannot find parent <tr> for selector ${this.expandableToggleSelector}`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
event.preventDefault();
|
|
27
|
+
event.stopPropagation();
|
|
28
|
+
const isExpanded = triggerElement.hasAttribute('data-is-expanded');
|
|
29
|
+
if (isExpanded) {
|
|
30
|
+
triggerElement.removeAttribute('data-is-expanded');
|
|
31
|
+
rowDetail.removeAttribute('data-is-row-expanded');
|
|
32
|
+
parentRow.removeAttribute('data-has-expanded-detail');
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
triggerElement.setAttribute('data-is-expanded', '');
|
|
36
|
+
rowDetail.setAttribute('data-is-row-expanded', '');
|
|
37
|
+
parentRow.setAttribute('data-has-expanded-detail', '');
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=exm-row-expandable.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ExmgQuerySelectors } from '../utils/exm-query-selectors.js';
|
|
2
|
+
export declare class ExmgRowSelectable {
|
|
3
|
+
allCheckbox?: HTMLInputElement;
|
|
4
|
+
selectedRows: HTMLTableRowElement[];
|
|
5
|
+
private querySelectors;
|
|
6
|
+
private dispatchEvent;
|
|
7
|
+
private selectableCheckboxSelector?;
|
|
8
|
+
private disableRowClickSelection;
|
|
9
|
+
constructor(qs: ExmgQuerySelectors, de: (event: Event) => boolean, drcs: boolean, scs?: string);
|
|
10
|
+
initFeature(bodyRows: NodeListOf<HTMLTableRowElement>): void;
|
|
11
|
+
updateFeature(bodyRows: NodeListOf<HTMLTableRowElement>): void;
|
|
12
|
+
syncSelectedItems(): void;
|
|
13
|
+
private fireSelectableRows;
|
|
14
|
+
private updateBodyRowsListeners;
|
|
15
|
+
private initAllCheckbox;
|
|
16
|
+
private syncRowSelectionWithBodyCheckboxes;
|
|
17
|
+
private getBodyCheckboxes;
|
|
18
|
+
private handleAllCheckboxStateChange;
|
|
19
|
+
private updateSelectAllCheckbox;
|
|
20
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
const checkCheckbox = (checkboxElement) => {
|
|
2
|
+
checkboxElement.setAttribute('checked', 'checked');
|
|
3
|
+
checkboxElement.removeAttribute('indeterminate');
|
|
4
|
+
checkboxElement.checked = true;
|
|
5
|
+
};
|
|
6
|
+
const uncheckCheckbox = (checkboxElement) => {
|
|
7
|
+
checkboxElement.removeAttribute('checked');
|
|
8
|
+
checkboxElement.removeAttribute('indeterminate');
|
|
9
|
+
checkboxElement.checked = false;
|
|
10
|
+
};
|
|
11
|
+
const indeterminateCheckbox = (checkboxElement) => {
|
|
12
|
+
checkboxElement.removeAttribute('checked');
|
|
13
|
+
checkboxElement.setAttribute('indeterminate', 'true');
|
|
14
|
+
checkboxElement.checked = true;
|
|
15
|
+
};
|
|
16
|
+
const syncCheckboxAttrFromProp = (checkboxElement) => {
|
|
17
|
+
if (checkboxElement.checked) {
|
|
18
|
+
checkboxElement.setAttribute('checked', 'checked');
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
checkboxElement.removeAttribute('checked');
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
export class ExmgRowSelectable {
|
|
25
|
+
constructor(qs, de, drcs, scs) {
|
|
26
|
+
this.selectedRows = [];
|
|
27
|
+
this.querySelectors = qs;
|
|
28
|
+
this.dispatchEvent = de;
|
|
29
|
+
this.selectableCheckboxSelector = scs;
|
|
30
|
+
this.disableRowClickSelection = drcs;
|
|
31
|
+
}
|
|
32
|
+
// eslint-disable-next-line
|
|
33
|
+
initFeature(bodyRows) {
|
|
34
|
+
const fireEvent = this.initAllCheckbox();
|
|
35
|
+
const rowsSelectionSyncShouldTriggerEvent = this.syncRowSelectionWithBodyCheckboxes();
|
|
36
|
+
this.updateBodyRowsListeners(bodyRows);
|
|
37
|
+
if (fireEvent || rowsSelectionSyncShouldTriggerEvent) {
|
|
38
|
+
this.fireSelectableRows();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// eslint-disable-next-line
|
|
42
|
+
updateFeature(bodyRows) {
|
|
43
|
+
this.updateBodyRowsListeners(bodyRows);
|
|
44
|
+
const rowsSelectionSyncShouldTriggerEvent = this.syncRowSelectionWithBodyCheckboxes();
|
|
45
|
+
this.updateSelectAllCheckbox();
|
|
46
|
+
if (rowsSelectionSyncShouldTriggerEvent) {
|
|
47
|
+
this.fireSelectableRows();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
syncSelectedItems() {
|
|
51
|
+
if (this.syncRowSelectionWithBodyCheckboxes()) {
|
|
52
|
+
this.fireSelectableRows();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
fireSelectableRows() {
|
|
56
|
+
this.dispatchEvent(new CustomEvent('exm-grid-selected-rows-change', {
|
|
57
|
+
bubbles: true,
|
|
58
|
+
composed: true,
|
|
59
|
+
detail: {
|
|
60
|
+
rows: [...this.selectedRows],
|
|
61
|
+
},
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
// eslint-disable-next-line
|
|
65
|
+
updateBodyRowsListeners(bodyRows) {
|
|
66
|
+
bodyRows.forEach((row) => {
|
|
67
|
+
row.setAttribute('data-is-selectable', '');
|
|
68
|
+
row.addEventListener('click', (e) => {
|
|
69
|
+
const target = e.target;
|
|
70
|
+
// Also TR needed for initial auto selected rows on init / if disable row selection it is only possible to use the md-checkbox
|
|
71
|
+
if ((this.disableRowClickSelection && target.tagName !== 'MD-CHECKBOX' && target.tagName !== 'TR') ||
|
|
72
|
+
(target.tagName !== 'TR' && target.tagName !== 'TD' && target.tagName !== 'MD-CHECKBOX')) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const index = this.selectedRows.indexOf(row);
|
|
76
|
+
const isRowAlreadySelected = index > -1;
|
|
77
|
+
if (isRowAlreadySelected) {
|
|
78
|
+
row.removeAttribute('data-selected');
|
|
79
|
+
this.selectedRows.splice(index, 1);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
row.setAttribute('data-selected', '');
|
|
83
|
+
this.selectedRows.push(row);
|
|
84
|
+
}
|
|
85
|
+
const rowCheckbox = this.selectableCheckboxSelector && row.querySelector(this.selectableCheckboxSelector);
|
|
86
|
+
if (rowCheckbox && rowCheckbox !== e.target) {
|
|
87
|
+
if (isRowAlreadySelected) {
|
|
88
|
+
uncheckCheckbox(rowCheckbox);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
checkCheckbox(rowCheckbox);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else if (rowCheckbox) {
|
|
95
|
+
syncCheckboxAttrFromProp(rowCheckbox);
|
|
96
|
+
}
|
|
97
|
+
this.updateSelectAllCheckbox();
|
|
98
|
+
this.fireSelectableRows();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
initAllCheckbox() {
|
|
103
|
+
let fireEvent = false;
|
|
104
|
+
this.allCheckbox = this.selectableCheckboxSelector
|
|
105
|
+
? this.querySelectors.getColumn(this.selectableCheckboxSelector)
|
|
106
|
+
: undefined;
|
|
107
|
+
if (this.allCheckbox) {
|
|
108
|
+
if (this.allCheckbox.checked) {
|
|
109
|
+
this.handleAllCheckboxStateChange();
|
|
110
|
+
fireEvent = true;
|
|
111
|
+
}
|
|
112
|
+
this.allCheckbox.addEventListener('change', () => {
|
|
113
|
+
syncCheckboxAttrFromProp(this.allCheckbox);
|
|
114
|
+
this.handleAllCheckboxStateChange();
|
|
115
|
+
this.fireSelectableRows();
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return fireEvent;
|
|
119
|
+
}
|
|
120
|
+
syncRowSelectionWithBodyCheckboxes() {
|
|
121
|
+
let fireEvent = false;
|
|
122
|
+
if (this.selectableCheckboxSelector) {
|
|
123
|
+
// remove row attribute data-selected if checkbox not selected
|
|
124
|
+
this.querySelectors
|
|
125
|
+
.getTableBody()
|
|
126
|
+
.querySelectorAll(`tr[data-selected] ${this.selectableCheckboxSelector}:not([checked])`)
|
|
127
|
+
.forEach((uncheckedCheckbox) => {
|
|
128
|
+
const row = uncheckedCheckbox.closest('tr');
|
|
129
|
+
if (row) {
|
|
130
|
+
row.removeAttribute('data-selected');
|
|
131
|
+
fireEvent = true;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
// add row attribute data-selected if checkbox is selected
|
|
135
|
+
this.querySelectors
|
|
136
|
+
.getTableBody()
|
|
137
|
+
.querySelectorAll(`tr:not([data-selected]) ${this.selectableCheckboxSelector}[checked]`)
|
|
138
|
+
.forEach((checkedCheckbox) => {
|
|
139
|
+
const row = checkedCheckbox.closest('tr');
|
|
140
|
+
if (row) {
|
|
141
|
+
row.setAttribute('data-selected', '');
|
|
142
|
+
fireEvent = true;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
const prevSelectedRowsCount = this.selectedRows.length;
|
|
146
|
+
this.selectedRows = Array.from(this.querySelectors.getTableBody().querySelectorAll('tr[data-selected]'));
|
|
147
|
+
if (prevSelectedRowsCount !== this.selectedRows.length) {
|
|
148
|
+
fireEvent = true;
|
|
149
|
+
}
|
|
150
|
+
if (this.allCheckbox && !this.allCheckbox.checked) {
|
|
151
|
+
if (this.selectedRows.length && this.selectedRows.length === this.querySelectors.getBodyRows().length) {
|
|
152
|
+
checkCheckbox(this.allCheckbox);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return fireEvent;
|
|
157
|
+
}
|
|
158
|
+
getBodyCheckboxes() {
|
|
159
|
+
return this.selectableCheckboxSelector
|
|
160
|
+
? Array.from(this.querySelectors.getTableBody().querySelectorAll(this.selectableCheckboxSelector))
|
|
161
|
+
: [];
|
|
162
|
+
}
|
|
163
|
+
handleAllCheckboxStateChange() {
|
|
164
|
+
if (this.allCheckbox.checked) {
|
|
165
|
+
this.allCheckbox.removeAttribute('indeterminate');
|
|
166
|
+
this.selectedRows = [];
|
|
167
|
+
this.querySelectors.getBodyRows().forEach((row) => {
|
|
168
|
+
row.setAttribute('data-selected', '');
|
|
169
|
+
this.selectedRows.push(row);
|
|
170
|
+
});
|
|
171
|
+
this.getBodyCheckboxes().forEach((checkbox) => {
|
|
172
|
+
checkCheckbox(checkbox);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
this.allCheckbox.removeAttribute('indeterminate');
|
|
177
|
+
this.selectedRows = [];
|
|
178
|
+
this.querySelectors
|
|
179
|
+
.getTableBody()
|
|
180
|
+
.querySelectorAll('tr[data-selected]')
|
|
181
|
+
.forEach((row) => {
|
|
182
|
+
row.removeAttribute('data-selected');
|
|
183
|
+
});
|
|
184
|
+
this.getBodyCheckboxes().forEach((checkbox) => {
|
|
185
|
+
uncheckCheckbox(checkbox);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
updateSelectAllCheckbox() {
|
|
190
|
+
const selectedRowsCount = this.selectedRows.length;
|
|
191
|
+
if (this.allCheckbox) {
|
|
192
|
+
if (!this.allCheckbox.checked && selectedRowsCount === this.querySelectors.getBodyRows().length) {
|
|
193
|
+
checkCheckbox(this.allCheckbox);
|
|
194
|
+
}
|
|
195
|
+
else if (selectedRowsCount === 0) {
|
|
196
|
+
uncheckCheckbox(this.allCheckbox);
|
|
197
|
+
}
|
|
198
|
+
else if (selectedRowsCount < this.querySelectors.getBodyRows().length) {
|
|
199
|
+
indeterminateCheckbox(this.allCheckbox);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=exm-row-selectable.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ExmgQuerySelectors } from '../utils/exm-query-selectors.js';
|
|
2
|
+
export declare class ExmgRowSortable {
|
|
3
|
+
private querySelectors;
|
|
4
|
+
constructor(qs: ExmgQuerySelectors);
|
|
5
|
+
initFeature(): void;
|
|
6
|
+
updateFeature(): void;
|
|
7
|
+
private getRowDetailQuerySelectorFactory;
|
|
8
|
+
private registerMouseListenersHideDetailOnStartDragging;
|
|
9
|
+
}
|