@neovici/cosmoz-omnitable 12.0.2 → 12.1.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/cosmoz-omnitable-column.js +6 -1
- package/cosmoz-omnitable-styles.js +2 -2
- package/cosmoz-omnitable.js +37 -539
- package/lib/render-footer.js +71 -0
- package/lib/render-header.js +34 -0
- package/lib/render-list.js +62 -0
- package/lib/settings/use-settings.js +7 -5
- package/lib/use-dom-columns.js +34 -28
- package/lib/use-fast-layout.js +21 -3
- package/lib/use-footer.js +22 -0
- package/lib/use-header.js +72 -0
- package/lib/use-list.js +214 -0
- package/lib/use-omnitable.js +50 -92
- package/lib/use-processed-items.js +37 -16
- package/lib/use-public-interface.js +96 -0
- package/package.json +1 -1
|
@@ -9,7 +9,12 @@ import { html } from 'lit-html';
|
|
|
9
9
|
|
|
10
10
|
const
|
|
11
11
|
onChange = setState => event => setState(state => {
|
|
12
|
-
|
|
12
|
+
// skip the event emitted during paper-input initialization
|
|
13
|
+
if(state.inputValue === undefined && event.target.value === '') {
|
|
14
|
+
return state;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
clearTimeout(state.t);
|
|
13
18
|
const t = setTimeout(() => setState(state => ({ ...state, filter: state.inputValue })), 1000);
|
|
14
19
|
return { ...state, inputValue: event.target.value, t };
|
|
15
20
|
}),
|
|
@@ -76,7 +76,7 @@ const checkbox = css`
|
|
|
76
76
|
|
|
77
77
|
export { checkbox };
|
|
78
78
|
|
|
79
|
-
export default
|
|
79
|
+
export default `
|
|
80
80
|
:host {
|
|
81
81
|
display: flex;
|
|
82
82
|
flex-direction: column;
|
|
@@ -435,4 +435,4 @@ export default `<style>
|
|
|
435
435
|
.expand:hover, .fold:hover {
|
|
436
436
|
color: #000;
|
|
437
437
|
}
|
|
438
|
-
|
|
438
|
+
`;
|
package/cosmoz-omnitable.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable max-lines-per-function */
|
|
1
2
|
/* eslint-disable max-lines */
|
|
2
3
|
import '@polymer/iron-icons/iron-icons';
|
|
3
4
|
import '@polymer/iron-icon/iron-icon';
|
|
@@ -15,545 +16,42 @@ import './cosmoz-omnitable-group-row';
|
|
|
15
16
|
import './cosmoz-omnitable-columns';
|
|
16
17
|
import styles from './cosmoz-omnitable-styles';
|
|
17
18
|
|
|
18
|
-
import {
|
|
19
|
-
import { html } from '
|
|
20
|
-
import { html as litHtml } from 'lit-html';
|
|
19
|
+
import { html as polymerHtml } from '@polymer/polymer/lib/utils/html-tag';
|
|
20
|
+
import { html } from 'lit-html';
|
|
21
21
|
|
|
22
|
-
import { translatable } from '@neovici/cosmoz-i18next';
|
|
23
|
-
import { mixin, hauntedPolymer } from '@neovici/cosmoz-utils';
|
|
24
|
-
import { isEmpty } from '@neovici/cosmoz-utils/template';
|
|
25
22
|
import { useOmnitable } from './lib/use-omnitable';
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
/>
|
|
59
|
-
<cosmoz-omnitable-header-row
|
|
60
|
-
data="[[ data ]]"
|
|
61
|
-
columns="[[ columns ]]"
|
|
62
|
-
filters="[[ filters ]]"
|
|
63
|
-
group-on-column="[[ groupOnColumn ]]"
|
|
64
|
-
set-filter-state="[[ setFilterState ]]"
|
|
65
|
-
settings-config="[[ settingsConfig ]]"
|
|
66
|
-
></cosmoz-omnitable-header-row>
|
|
67
|
-
</div>
|
|
68
|
-
</sort-and-group-provider>
|
|
69
|
-
<div class="tableContent" id="tableContent">
|
|
70
|
-
<template is="dom-if" if="[[ !_dataIsValid ]]">
|
|
71
|
-
<div class="tableContent-empty">
|
|
72
|
-
<slot name="empty-set-message">
|
|
73
|
-
<iron-icon icon="icons:announcement"></iron-icon>
|
|
74
|
-
<div class="tableContent-empty-message">
|
|
75
|
-
<h3>[[ _('Working set empty', t) ]]</h3>
|
|
76
|
-
<p>[[ _('No data to display', t) ]]</p>
|
|
77
|
-
</div>
|
|
78
|
-
</slot>
|
|
79
|
-
</div>
|
|
80
|
-
</template>
|
|
81
|
-
<template is="dom-if" if="[[ _filterIsTooStrict ]]">
|
|
82
|
-
<div class="tableContent-empty">
|
|
83
|
-
<iron-icon icon="icons:announcement"></iron-icon>
|
|
84
|
-
<div>
|
|
85
|
-
<h3>[[ _('Filter too strict', t) ]]</h3>
|
|
86
|
-
<p>[[ _('No matches for selection', t) ]]</p>
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
</template>
|
|
90
|
-
<template is="dom-if" if="[[ loading ]]">
|
|
91
|
-
<div class="tableContent-empty overlay">
|
|
92
|
-
<paper-spinner-lite active="[[ loading ]]"></paper-spinner-lite>
|
|
93
|
-
<div>
|
|
94
|
-
<h3>[[ _('Data set is updating', t) ]]</h3>
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
</template>
|
|
98
|
-
<div class="tableContent-scroller" id="scroller">
|
|
99
|
-
<cosmoz-grouped-list
|
|
100
|
-
id="groupedList"
|
|
101
|
-
data="{{ sortedFilteredGroupedItems }}"
|
|
102
|
-
selected-items="{{ selectedItems }}"
|
|
103
|
-
display-empty-groups="[[ displayEmptyGroups ]]"
|
|
104
|
-
compare-items-fn="[[ compareItemsFn ]]"
|
|
105
|
-
render-item="[[ renderItem(collapsedColumns) ]]"
|
|
106
|
-
render-group="[[ renderGroup ]]"
|
|
107
|
-
></cosmoz-grouped-list>
|
|
108
|
-
</div>
|
|
109
|
-
</div>
|
|
110
|
-
<cosmoz-bottom-bar
|
|
111
|
-
id="bottomBar"
|
|
112
|
-
on-action="_onAction"
|
|
113
|
-
active$="[[ !isEmpty(selectedItems.length) ]]"
|
|
114
|
-
>
|
|
115
|
-
<slot name="info" slot="info"
|
|
116
|
-
>[[ ngettext('{0} selected item', '{0} selected items',
|
|
117
|
-
selectedItems.length, t) ]]</slot
|
|
118
|
-
>
|
|
119
|
-
<slot name="actions" id="actions"></slot>
|
|
120
|
-
<!-- These slots are needed by cosmoz-bottom-bar
|
|
121
|
-
as it might change the slot of the actions to distribute them in the menu -->
|
|
122
|
-
<slot name="bottom-bar-toolbar" slot="bottom-bar-toolbar"></slot>
|
|
123
|
-
<slot name="bottom-bar-menu" slot="bottom-bar-menu"></slot>
|
|
124
|
-
<cosmoz-dropdown-menu slot="extra" placement="[[ topPlacement ]]">
|
|
125
|
-
<svg
|
|
126
|
-
slot="button"
|
|
127
|
-
width="14"
|
|
128
|
-
height="18"
|
|
129
|
-
viewBox="0 0 14 18"
|
|
130
|
-
fill="none"
|
|
131
|
-
stroke="currentColor"
|
|
132
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
133
|
-
>
|
|
134
|
-
<path
|
|
135
|
-
d="M1 8.5L7.00024 14.5L13 8.5"
|
|
136
|
-
stroke-width="2"
|
|
137
|
-
stroke-linecap="round"
|
|
138
|
-
stroke-linejoin="round"
|
|
139
|
-
/>
|
|
140
|
-
<path d="M13 17L1 17" stroke-width="2" stroke-linecap="round" />
|
|
141
|
-
<path d="M7 1V13" stroke-width="2" stroke-linecap="round" />
|
|
142
|
-
</svg>
|
|
143
|
-
<button on-click="_saveAsCsvAction">
|
|
144
|
-
[[ _('Save as CSV', t) ]]
|
|
145
|
-
</button>
|
|
146
|
-
<button on-click="_saveAsXlsxAction">
|
|
147
|
-
[[ _('Save as XLSX', t) ]]
|
|
148
|
-
</button>
|
|
149
|
-
<slot name="download-menu"></slot>
|
|
150
|
-
</cosmoz-dropdown-menu>
|
|
151
|
-
</cosmoz-bottom-bar>
|
|
152
|
-
</div>
|
|
153
|
-
|
|
154
|
-
<div id="columns">
|
|
155
|
-
<slot id="columnsSlot"></slot>
|
|
156
|
-
</div>
|
|
157
|
-
`;
|
|
158
|
-
template.setAttribute('strip-whitespace', '');
|
|
159
|
-
return template;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
renderItem(collapsedColumns) {
|
|
163
|
-
return (item, index, { selected, expanded, toggleCollapse }) => {
|
|
164
|
-
return litHtml`
|
|
165
|
-
<div class="item-row-wrapper">
|
|
166
|
-
<div ?selected=${selected}
|
|
167
|
-
part="itemRow itemRow-${item[indexSymbol]}"
|
|
168
|
-
.dataIndex=${item[indexSymbol]}
|
|
169
|
-
.dataItem=${item}
|
|
170
|
-
class="itemRow"
|
|
171
|
-
@click=${this.onItemClick}
|
|
172
|
-
>
|
|
173
|
-
<input class="checkbox"
|
|
174
|
-
type="checkbox"
|
|
175
|
-
.checked=${selected}
|
|
176
|
-
.dataItem=${item}
|
|
177
|
-
@input=${this._onCheckboxChange}
|
|
178
|
-
?disabled=${!this._dataIsValid} />
|
|
179
|
-
<cosmoz-omnitable-item-row
|
|
180
|
-
.columns=${this.columns}
|
|
181
|
-
.index=${index}
|
|
182
|
-
.selected=${selected}
|
|
183
|
-
.expanded=${expanded}
|
|
184
|
-
.item=${item}
|
|
185
|
-
.groupOnColumn=${this.groupOnColumn}
|
|
186
|
-
.onItemChange=${this.onItemChange}>
|
|
187
|
-
</cosmoz-omnitable-item-row>
|
|
188
|
-
<paper-icon-button
|
|
189
|
-
class="expand"
|
|
190
|
-
?hidden=${isEmpty(collapsedColumns.length)}
|
|
191
|
-
.icon=${this._getFoldIcon(expanded)}
|
|
192
|
-
@click=${toggleCollapse}
|
|
193
|
-
></paper-icon-button>
|
|
194
|
-
</div>
|
|
195
|
-
<cosmoz-omnitable-item-expand .columns=${collapsedColumns}
|
|
196
|
-
.item=${item}
|
|
197
|
-
.index=${index}
|
|
198
|
-
?selected=${selected}
|
|
199
|
-
?expanded=${expanded}
|
|
200
|
-
.groupOnColumn=${this.groupOnColumn}
|
|
201
|
-
part="item-expand">
|
|
202
|
-
</cosmoz-omnitable-item-expand>
|
|
203
|
-
</div>`;
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
renderGroup(item, index, { selected, folded, toggleFold }) {
|
|
208
|
-
return litHtml`
|
|
209
|
-
<div class="${this._getGroupRowClasses(folded)}"
|
|
210
|
-
part="groupRow groupRow-${item[indexSymbol]}">
|
|
211
|
-
<input class="checkbox"
|
|
212
|
-
type="checkbox"
|
|
213
|
-
.checked=${selected}
|
|
214
|
-
.dataItem=${item}
|
|
215
|
-
@input=${this._onCheckboxChange}
|
|
216
|
-
?disabled=${!this._dataIsValid} />
|
|
217
|
-
<h3 class="groupRow-label">
|
|
218
|
-
<div><span>${this.groupOnColumn?.title}</span>: </div>
|
|
219
|
-
<cosmoz-omnitable-group-row
|
|
220
|
-
.column=${this.groupOnColumn}
|
|
221
|
-
.item=${item.items?.[0]}
|
|
222
|
-
.selected=${selected}
|
|
223
|
-
.folded=${folded}
|
|
224
|
-
.group=${item}
|
|
225
|
-
></cosmoz-omnitable-group-row>
|
|
226
|
-
</h3>
|
|
227
|
-
<div class="groupRow-badge">${item.items.length}</div>
|
|
228
|
-
<paper-icon-button
|
|
229
|
-
class="fold"
|
|
230
|
-
.icon=${this._getFoldIcon(folded)}
|
|
231
|
-
@click=${toggleFold}></paper-icon-button>
|
|
232
|
-
</div>`;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/* eslint-disable-next-line max-lines-per-function */
|
|
236
|
-
static get properties() {
|
|
237
|
-
return {
|
|
238
|
-
/**
|
|
239
|
-
* Filename when saving as CSV
|
|
240
|
-
*/
|
|
241
|
-
csvFilename: { type: String, value: 'omnitable.csv' },
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Filename when saving as XLSX
|
|
245
|
-
*/
|
|
246
|
-
xlsxFilename: { type: String, value: 'omnitable.xlsx' },
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Sheet name when saving as XLSX
|
|
250
|
-
*/
|
|
251
|
-
xlsxSheetname: { type: String, value: 'Omnitable' },
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Array used to list items.
|
|
255
|
-
*/
|
|
256
|
-
data: { type: Array },
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* This function is used to determine which items are kept selected across data updates
|
|
260
|
-
*/
|
|
261
|
-
compareItemsFn: Function,
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* True if data is a valid and not empty array.
|
|
265
|
-
*/
|
|
266
|
-
_dataIsValid: {
|
|
267
|
-
type: Boolean,
|
|
268
|
-
value: false,
|
|
269
|
-
computed: '_computeDataValidity(data.*)',
|
|
270
|
-
},
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* If set to true, then group a row will be displayed for groups that contain no items.
|
|
274
|
-
*/
|
|
275
|
-
displayEmptyGroups: { type: Boolean, value: false },
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Specific columns to enable
|
|
279
|
-
*/
|
|
280
|
-
enabledColumns: { type: Array, notify: true },
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Whether bottom-bar has actions.
|
|
284
|
-
*/
|
|
285
|
-
hasActions: { type: Boolean, value: false },
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Shows a loading overlay to indicate data will be updated
|
|
289
|
-
*/
|
|
290
|
-
loading: { type: Boolean, value: false },
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* List of selected rows/items in `data`.
|
|
294
|
-
*/
|
|
295
|
-
selectedItems: { type: Array, notify: true, value: () => [] },
|
|
296
|
-
descending: { type: Boolean, value: false, notify: true },
|
|
297
|
-
sortOn: { type: String, value: '', notify: true },
|
|
298
|
-
groupOnDescending: { type: Boolean, value: false },
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* The column name to group on.
|
|
302
|
-
*/
|
|
303
|
-
groupOn: { type: String, notify: true, value: '' },
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Sorted items structure after filtering and grouping.
|
|
307
|
-
*/
|
|
308
|
-
sortedFilteredGroupedItems: { type: Array, notify: true },
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* List of columns definition for this table.
|
|
312
|
-
*/
|
|
313
|
-
columns: { type: Array, notify: true, value: () => [] },
|
|
314
|
-
settings: { type: Object, notify: true },
|
|
315
|
-
_filterIsTooStrict: {
|
|
316
|
-
type: Boolean,
|
|
317
|
-
computed:
|
|
318
|
-
'_computeFilterIsTooStrict(_dataIsValid, sortedFilteredGroupedItems.length)',
|
|
319
|
-
},
|
|
320
|
-
hashParam: { type: String },
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* True when all items are selected.
|
|
324
|
-
*/
|
|
325
|
-
_allSelected: { type: Boolean },
|
|
326
|
-
computedBarHeight: { type: Number },
|
|
327
|
-
settingsId: { type: String, value: undefined },
|
|
328
|
-
topPlacement: {
|
|
329
|
-
value: ['top-right', ...defaultPlacement],
|
|
330
|
-
},
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
static get observers() {
|
|
335
|
-
return ['_selectedItemsChanged(selectedItems.*)'];
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
constructor() {
|
|
339
|
-
super();
|
|
340
|
-
|
|
341
|
-
this._onKey = this._onKey.bind(this);
|
|
342
|
-
this._onCheckboxChange = this._onCheckboxChange.bind(this);
|
|
343
|
-
this.renderItem = this.renderItem.bind(this);
|
|
344
|
-
this.renderGroup = this.renderGroup.bind(this);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
connectedCallback() {
|
|
348
|
-
super.connectedCallback();
|
|
349
|
-
|
|
350
|
-
this.$.groupedList.scrollTarget = this.$.scroller;
|
|
351
|
-
|
|
352
|
-
window.addEventListener('keydown', this._onKey);
|
|
353
|
-
window.addEventListener('keyup', this._onKey);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
disconnectedCallback() {
|
|
357
|
-
super.disconnectedCallback();
|
|
358
|
-
|
|
359
|
-
window.removeEventListener('keydown', this._onKey);
|
|
360
|
-
window.removeEventListener('keyup', this._onKey);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/** ELEMENT BEHAVIOR */
|
|
364
|
-
|
|
365
|
-
_computeDataValidity({ base: data } = {}) {
|
|
366
|
-
return data && Array.isArray(data) && data.length > 0;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
_computeFilterIsTooStrict(dataIsValid, visibleItemsLength) {
|
|
370
|
-
return dataIsValid && visibleItemsLength < 1;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
_onKey(e) {
|
|
374
|
-
this._shiftKey = e.shiftKey;
|
|
375
|
-
this._ctrlKey = e.ctrlKey;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
_onCheckboxChange(event) {
|
|
379
|
-
const item = event.target.dataItem,
|
|
380
|
-
selected = event.target.checked;
|
|
381
|
-
if (this._shiftKey) {
|
|
382
|
-
this.$.groupedList.toggleSelectTo(item, selected);
|
|
383
|
-
} else if (this._ctrlKey) {
|
|
384
|
-
event.target.checked = true;
|
|
385
|
-
this.$.groupedList.selectOnly(item);
|
|
386
|
-
} else {
|
|
387
|
-
this.$.groupedList.toggleSelect(item, selected);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
event.preventDefault();
|
|
391
|
-
event.stopPropagation();
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Triggers a download of selected rows as a CSV file.
|
|
396
|
-
* @returns {undefined}
|
|
397
|
-
*/
|
|
398
|
-
_saveAsCsvAction() {
|
|
399
|
-
saveAsCsvAction(this.columns, this.selectedItems, this.csvFilename);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* Triggers a download of selected rows as a XLSX file.
|
|
404
|
-
* @returns {undefined}
|
|
405
|
-
*/
|
|
406
|
-
_saveAsXlsxAction() {
|
|
407
|
-
saveAsXlsxAction(
|
|
408
|
-
this.columns,
|
|
409
|
-
this.selectedItems,
|
|
410
|
-
this.xlsxFilename,
|
|
411
|
-
this.xlsxSheetname
|
|
412
|
-
);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/** view functions */
|
|
416
|
-
|
|
417
|
-
_getGroupRowClasses(folded) {
|
|
418
|
-
return folded ? 'groupRow groupRow-folded' : 'groupRow';
|
|
419
|
-
}
|
|
420
|
-
_getFoldIcon(expanded) {
|
|
421
|
-
return expanded ? 'expand-less' : 'expand-more';
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Turn an `action` event into a `run` event
|
|
426
|
-
* @param {Event} event `action` event
|
|
427
|
-
* @param {Object} detail `action` event details
|
|
428
|
-
* @returns {undefined}
|
|
429
|
-
*/
|
|
430
|
-
_onAction(event, detail) {
|
|
431
|
-
detail.item.dispatchEvent(
|
|
432
|
-
new window.CustomEvent('run', {
|
|
433
|
-
bubbles: true,
|
|
434
|
-
cancelable: true,
|
|
435
|
-
detail: {
|
|
436
|
-
omnitable: this,
|
|
437
|
-
items: this.selectedItems,
|
|
438
|
-
},
|
|
439
|
-
})
|
|
440
|
-
);
|
|
441
|
-
event.stopPropagation();
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
_selectedItemsChanged(change) {
|
|
445
|
-
if (
|
|
446
|
-
change.path === 'selectedItems' ||
|
|
447
|
-
change.path === 'selectedItems.splices'
|
|
448
|
-
) {
|
|
449
|
-
this._allSelected =
|
|
450
|
-
this.data &&
|
|
451
|
-
this.data.length > 0 &&
|
|
452
|
-
change.base.length === this.data.length;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
_onAllCheckboxChange(event) {
|
|
457
|
-
if (event.target.checked) {
|
|
458
|
-
this.$.groupedList.selectAll();
|
|
459
|
-
} else {
|
|
460
|
-
this.$.groupedList.deselectAll();
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// TODO: move to publicInterface mixin
|
|
465
|
-
/** PUBLIC */
|
|
466
|
-
/**
|
|
467
|
-
* Remove multiple items from `data`
|
|
468
|
-
* @param {Array} items Array of items to remove
|
|
469
|
-
* @return {Array} Array containing removed items
|
|
470
|
-
*/
|
|
471
|
-
removeItems(items) {
|
|
472
|
-
const removedItems = [];
|
|
473
|
-
|
|
474
|
-
for (let i = items.length - 1; i >= 0; i -= 1) {
|
|
475
|
-
const removed = this.removeItem(items[i]);
|
|
476
|
-
if (removed != null) {
|
|
477
|
-
removedItems.push(removed);
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
return removedItems;
|
|
481
|
-
}
|
|
482
|
-
/**
|
|
483
|
-
* Helper method to remove an item from `data`.
|
|
484
|
-
* @param {Object} item Item to remove
|
|
485
|
-
* @return {Object} item removed
|
|
486
|
-
*/
|
|
487
|
-
removeItem(item) {
|
|
488
|
-
const index = this.data.indexOf(item);
|
|
489
|
-
|
|
490
|
-
if (index < 0) {
|
|
491
|
-
return null;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
const removed = this.splice('data', index, 1);
|
|
495
|
-
this.data = this.data.slice();
|
|
496
|
-
if (Array.isArray(removed) && removed.length > 0) {
|
|
497
|
-
return removed[0];
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
replaceItem(oldItem, newItem) {
|
|
501
|
-
const itemIndex = this.data.indexOf(oldItem);
|
|
502
|
-
if (itemIndex > -1) {
|
|
503
|
-
return this.replaceItemAtIndex(itemIndex, newItem);
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
replaceItemAtIndex(index, newItem) {
|
|
507
|
-
this.splice('data', index, 1, newItem);
|
|
508
|
-
this.data = this.data.slice();
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* Convenience method for setting a value to an item's path and notifying any
|
|
512
|
-
* element bound to this item's path.
|
|
513
|
-
* @param {Object} item The item.
|
|
514
|
-
* @param {itemPath} itemPath The path of the item.
|
|
515
|
-
* @param {String} value The new value of the item.
|
|
516
|
-
* @returns {void}
|
|
517
|
-
*/
|
|
518
|
-
setItemValue(item, itemPath, value) {
|
|
519
|
-
const key = this.data.indexOf(item);
|
|
520
|
-
|
|
521
|
-
this.set('data.' + key + '.' + itemPath, value);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
selectItem(item) {
|
|
525
|
-
this.$.groupedList.select(item);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
deselectItem(item) {
|
|
529
|
-
this.$.groupedList.deselect(item);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
isItemSelected(item) {
|
|
533
|
-
return this.$.groupedList.isItemSelected(item);
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
onItemClick(e) {
|
|
537
|
-
const composedPath = e.composedPath(),
|
|
538
|
-
path = composedPath.slice(0, composedPath.indexOf(e.currentTarget));
|
|
539
|
-
|
|
540
|
-
if (path.find((e) => e.matches?.('a, .checkbox, .expand'))) {
|
|
541
|
-
return;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
this.dispatchEvent(
|
|
545
|
-
new window.CustomEvent('omnitable-item-click', {
|
|
546
|
-
bubbles: true,
|
|
547
|
-
composed: true,
|
|
548
|
-
detail: {
|
|
549
|
-
item: e.currentTarget.dataItem,
|
|
550
|
-
index: e.currentTarget.dataIndex,
|
|
551
|
-
},
|
|
552
|
-
})
|
|
553
|
-
);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
customElements.define('cosmoz-omnitable', Omnitable);
|
|
23
|
+
import { component } from 'haunted';
|
|
24
|
+
import { renderHeader } from './lib/render-header';
|
|
25
|
+
import { renderFooter } from './lib/render-footer';
|
|
26
|
+
import { renderList } from './lib/render-list';
|
|
27
|
+
|
|
28
|
+
const Omnitable = (host) => {
|
|
29
|
+
const { header, list, footer } = useOmnitable(host);
|
|
30
|
+
|
|
31
|
+
return html`
|
|
32
|
+
<style>
|
|
33
|
+
${styles}
|
|
34
|
+
</style>
|
|
35
|
+
<div id="layoutStyle"></div>
|
|
36
|
+
|
|
37
|
+
<div class="mainContainer">
|
|
38
|
+
${renderHeader(header)}
|
|
39
|
+
<div class="tableContent" id="tableContent">${renderList(list)}</div>
|
|
40
|
+
${renderFooter(footer)}
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div id="columns">
|
|
44
|
+
<slot id="columnsSlot"></slot>
|
|
45
|
+
</div>
|
|
46
|
+
`;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
customElements.define(
|
|
50
|
+
'cosmoz-omnitable',
|
|
51
|
+
component(Omnitable, {
|
|
52
|
+
observedAttributes: ['hash-param', 'sort-on', 'group-on'],
|
|
53
|
+
})
|
|
54
|
+
);
|
|
557
55
|
|
|
558
56
|
const tmplt = `
|
|
559
57
|
<slot name="actions" slot="actions"></slot>
|
|
@@ -561,5 +59,5 @@ const tmplt = `
|
|
|
561
59
|
<slot name="bottom-bar-menu" slot="bottom-bar-menu"></slot>
|
|
562
60
|
`;
|
|
563
61
|
|
|
564
|
-
export const actionSlots =
|
|
565
|
-
actionSlotsPolymer =
|
|
62
|
+
export const actionSlots = html(Object.assign([tmplt], { raw: [tmplt] })),
|
|
63
|
+
actionSlotsPolymer = polymerHtml(Object.assign([tmplt], { raw: [tmplt] }));
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { html } from 'lit-html';
|
|
2
|
+
import { ngettext, _ } from '@neovici/cosmoz-i18next';
|
|
3
|
+
import { saveAsCsvAction } from './save-as-csv-action';
|
|
4
|
+
import { saveAsXlsxAction } from './save-as-xlsx-action';
|
|
5
|
+
import { isEmpty } from '@neovici/cosmoz-utils/template';
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line max-lines-per-function
|
|
8
|
+
export const renderFooter = ({
|
|
9
|
+
columns,
|
|
10
|
+
selectedItems,
|
|
11
|
+
csvFilename,
|
|
12
|
+
xlsxFilename,
|
|
13
|
+
xlsxSheetname,
|
|
14
|
+
topPlacement
|
|
15
|
+
}) => {
|
|
16
|
+
return html`
|
|
17
|
+
<cosmoz-bottom-bar
|
|
18
|
+
id="bottomBar"
|
|
19
|
+
?active=${!isEmpty(selectedItems.length)}
|
|
20
|
+
>
|
|
21
|
+
<slot name="info" slot="info">
|
|
22
|
+
${ngettext(
|
|
23
|
+
'{0} selected item',
|
|
24
|
+
'{0} selected items',
|
|
25
|
+
selectedItems.length
|
|
26
|
+
)}
|
|
27
|
+
</slot>
|
|
28
|
+
<slot name="actions" id="actions"></slot>
|
|
29
|
+
<!-- These slots are needed by cosmoz-bottom-bar
|
|
30
|
+
as it might change the slot of the actions to distribute them in the menu -->
|
|
31
|
+
<slot name="bottom-bar-toolbar" slot="bottom-bar-toolbar"></slot>
|
|
32
|
+
<slot name="bottom-bar-menu" slot="bottom-bar-menu"></slot>
|
|
33
|
+
<cosmoz-dropdown-menu slot="extra" placement=${topPlacement}>
|
|
34
|
+
<svg
|
|
35
|
+
slot="button"
|
|
36
|
+
width="14"
|
|
37
|
+
height="18"
|
|
38
|
+
viewBox="0 0 14 18"
|
|
39
|
+
fill="none"
|
|
40
|
+
stroke="currentColor"
|
|
41
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
42
|
+
>
|
|
43
|
+
<path
|
|
44
|
+
d="M1 8.5L7.00024 14.5L13 8.5"
|
|
45
|
+
stroke-width="2"
|
|
46
|
+
stroke-linecap="round"
|
|
47
|
+
stroke-linejoin="round"
|
|
48
|
+
/>
|
|
49
|
+
<path d="M13 17L1 17" stroke-width="2" stroke-linecap="round" />
|
|
50
|
+
<path d="M7 1V13" stroke-width="2" stroke-linecap="round" />
|
|
51
|
+
</svg>
|
|
52
|
+
<button
|
|
53
|
+
@click=${() => saveAsCsvAction(columns, selectedItems, csvFilename)}
|
|
54
|
+
>
|
|
55
|
+
${_('Save as CSV')}
|
|
56
|
+
</button>
|
|
57
|
+
<button
|
|
58
|
+
@click=${() =>
|
|
59
|
+
saveAsXlsxAction(
|
|
60
|
+
columns,
|
|
61
|
+
selectedItems,
|
|
62
|
+
xlsxFilename,
|
|
63
|
+
xlsxSheetname
|
|
64
|
+
)}
|
|
65
|
+
>
|
|
66
|
+
${_('Save as XLSX')}
|
|
67
|
+
</button>
|
|
68
|
+
<slot name="download-menu"></slot>
|
|
69
|
+
</cosmoz-dropdown-menu>
|
|
70
|
+
</cosmoz-bottom-bar>`;
|
|
71
|
+
};
|