@neovici/cosmoz-omnitable 7.2.0 → 8.0.0-beta.10
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-amount.js +89 -320
- package/cosmoz-omnitable-column-autocomplete.js +38 -47
- package/cosmoz-omnitable-column-boolean.js +107 -209
- package/cosmoz-omnitable-column-date.js +89 -102
- package/cosmoz-omnitable-column-datetime.js +86 -119
- package/cosmoz-omnitable-column-list-data.js +4 -1
- package/cosmoz-omnitable-column-list-horizontal.js +20 -38
- package/cosmoz-omnitable-column-list-mixin.js +135 -140
- package/cosmoz-omnitable-column-list.js +19 -28
- package/cosmoz-omnitable-column-mixin.js +70 -447
- package/cosmoz-omnitable-column-number.js +91 -183
- package/cosmoz-omnitable-column-time.js +77 -162
- package/cosmoz-omnitable-column.js +49 -93
- package/cosmoz-omnitable-group-row.js +1 -5
- package/cosmoz-omnitable-header-row.js +9 -6
- package/cosmoz-omnitable-item-expand.js +0 -3
- package/cosmoz-omnitable-item-row.js +5 -8
- package/cosmoz-omnitable-styles.js +4 -8
- package/cosmoz-omnitable.js +74 -771
- package/lib/cosmoz-omnitable-amount-range-input.js +295 -0
- package/{cosmoz-omnitable-column-date-mixin.js → lib/cosmoz-omnitable-date-input-mixin.js} +4 -26
- package/lib/cosmoz-omnitable-date-range-input.js +81 -0
- package/lib/cosmoz-omnitable-datetime-range-input.js +75 -0
- package/lib/cosmoz-omnitable-number-range-input.js +159 -0
- package/{cosmoz-omnitable-column-range-mixin.js → lib/cosmoz-omnitable-range-input-mixin.js} +45 -129
- package/lib/cosmoz-omnitable-settings.js +8 -5
- package/lib/cosmoz-omnitable-time-range-input.js +130 -0
- package/lib/generic-sorter.js +2 -2
- package/lib/invoke.js +1 -0
- package/lib/memoize.js +54 -0
- package/lib/normalize-settings.js +2 -5
- package/lib/polymer-haunted-render-mixin.js +19 -0
- package/lib/save-as-csv-action.js +32 -0
- package/lib/save-as-xlsx-action.js +25 -0
- package/lib/use-canvas-width.js +1 -1
- package/lib/use-dom-columns.js +143 -0
- package/lib/use-fast-layout.js +23 -18
- package/lib/use-hash-state.js +59 -0
- package/lib/use-layout.js +1 -1
- package/lib/use-omnitable.js +81 -22
- package/lib/use-processed-items.js +133 -0
- package/lib/use-resizable-columns.js +1 -2
- package/lib/use-sort-and-group-options.js +30 -0
- package/lib/utils-amount.js +147 -0
- package/lib/utils-data.js +41 -0
- package/lib/utils-date.js +204 -0
- package/lib/utils-datetime.js +71 -0
- package/lib/utils-number.js +112 -0
- package/lib/utils-time.js +115 -0
- package/package.json +1 -2
- package/lib/use-force-render.js +0 -8
- package/lib/use-render-on-column-updates.js +0 -18
package/{cosmoz-omnitable-column-range-mixin.js → lib/cosmoz-omnitable-range-input-mixin.js}
RENAMED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/* eslint-disable max-lines */
|
|
2
|
-
import { dedupingMixin } from '@polymer/polymer/lib/utils/mixin.js';
|
|
3
2
|
import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js';
|
|
4
3
|
import { timeOut } from '@polymer/polymer/lib/utils/async.js';
|
|
5
4
|
import { enqueueDebouncer } from '@polymer/polymer/lib/utils/flush.js';
|
|
@@ -15,7 +14,7 @@ const getCloseableParent = el =>
|
|
|
15
14
|
* @param {class} base The base class
|
|
16
15
|
* @returns {class} The base class with the mixin applied
|
|
17
16
|
*/
|
|
18
|
-
export const
|
|
17
|
+
export const rangeInputMixin = base => // eslint-disable-line max-lines-per-function
|
|
19
18
|
/**
|
|
20
19
|
* @polymer
|
|
21
20
|
* @mixinClass
|
|
@@ -23,10 +22,9 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
23
22
|
class extends base {
|
|
24
23
|
static get properties() { // eslint-disable-line max-lines-per-function
|
|
25
24
|
return {
|
|
26
|
-
|
|
27
|
-
type:
|
|
28
|
-
|
|
29
|
-
value: true
|
|
25
|
+
filter: {
|
|
26
|
+
type: Object,
|
|
27
|
+
notify: true
|
|
30
28
|
},
|
|
31
29
|
|
|
32
30
|
values: {
|
|
@@ -36,6 +34,11 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
36
34
|
}
|
|
37
35
|
},
|
|
38
36
|
|
|
37
|
+
headerFocused: {
|
|
38
|
+
type: Boolean,
|
|
39
|
+
notify: true
|
|
40
|
+
},
|
|
41
|
+
|
|
39
42
|
min: {
|
|
40
43
|
type: Number,
|
|
41
44
|
value: null
|
|
@@ -118,13 +121,13 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
/**
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
* Converts a value to number optionaly limiting it.
|
|
125
|
+
*
|
|
126
|
+
* @param {Number|*} value The value to convert to number
|
|
127
|
+
* @param {Number|*} limit The value used to limit the number
|
|
128
|
+
* @param {Function} limitFunc The function used to limit the number (Math.min|Math.max)
|
|
129
|
+
* @returns {Number|void} Value converted to Number or void
|
|
130
|
+
*/
|
|
128
131
|
toNumber(value, limit, limitFunc) {
|
|
129
132
|
if (value == null || value === '') {
|
|
130
133
|
return;
|
|
@@ -149,11 +152,11 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
149
152
|
|
|
150
153
|
/**
|
|
151
154
|
* Get the comparable value of an item.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
*
|
|
156
|
+
* @param {Object} item Item to be processed
|
|
157
|
+
* @param {String} valuePath Property path
|
|
158
|
+
* @returns {Number|void} Valid value or void
|
|
159
|
+
*/
|
|
157
160
|
getComparableValue(item, valuePath) {
|
|
158
161
|
if (item == null) {
|
|
159
162
|
return;
|
|
@@ -164,27 +167,6 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
164
167
|
}
|
|
165
168
|
return this.toValue(value);
|
|
166
169
|
}
|
|
167
|
-
|
|
168
|
-
toXlsxValue(item, valuePath = this.valuePath) {
|
|
169
|
-
const value = this.getComparableValue(item, valuePath);
|
|
170
|
-
if (value == null) {
|
|
171
|
-
return '';
|
|
172
|
-
}
|
|
173
|
-
return value;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
getString(item, valuePath = this.valuePath) {
|
|
177
|
-
if (valuePath === undefined) {
|
|
178
|
-
// eslint-disable-next-line no-console
|
|
179
|
-
console.error(this, 'has undefined valuePath', valuePath, 'for item', item);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
const value = this.get(valuePath, item);
|
|
183
|
-
if (value == null) {
|
|
184
|
-
return '';
|
|
185
|
-
}
|
|
186
|
-
return this.renderValue(value);
|
|
187
|
-
}
|
|
188
170
|
renderValue() {
|
|
189
171
|
//overrideable
|
|
190
172
|
}
|
|
@@ -195,15 +177,15 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
195
177
|
}
|
|
196
178
|
|
|
197
179
|
/**
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
180
|
+
* Computes min/max range from values.
|
|
181
|
+
*
|
|
182
|
+
* @param {Object} change `values` property changes
|
|
183
|
+
* @returns {Object} Computed min/max
|
|
184
|
+
*/
|
|
203
185
|
_computeRange(change) {
|
|
204
186
|
const allValues = change.base,
|
|
205
187
|
values = Array.isArray(allValues) && allValues.length
|
|
206
|
-
|
|
188
|
+
&& allValues.map(v => this.toValue(v)).filter(n => n != null);
|
|
207
189
|
|
|
208
190
|
if (!values || values.length < 1) {
|
|
209
191
|
return {
|
|
@@ -237,31 +219,6 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
237
219
|
};
|
|
238
220
|
}
|
|
239
221
|
|
|
240
|
-
getFilterFn() {
|
|
241
|
-
const min = this.getComparableValue(this.filter, 'min'),
|
|
242
|
-
max = this.getComparableValue(this.filter, 'max');
|
|
243
|
-
|
|
244
|
-
if (min == null && max == null) {
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
return this._applySingleFilter.bind(this, this.filter);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
_applySingleFilter(filter, item) {
|
|
251
|
-
const value = this.getComparableValue(item, this.valuePath),
|
|
252
|
-
minValue = this.getComparableValue(filter, 'min'),
|
|
253
|
-
maxValue = this.getComparableValue(filter, 'max');
|
|
254
|
-
|
|
255
|
-
if (value < minValue) {
|
|
256
|
-
return false;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
if (value > maxValue) {
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
return true;
|
|
264
|
-
}
|
|
265
222
|
|
|
266
223
|
_computeFilterText(change) {
|
|
267
224
|
if (change.base == null) {
|
|
@@ -309,12 +266,12 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
309
266
|
}
|
|
310
267
|
|
|
311
268
|
/**
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
269
|
+
* Observes changes of _filterInput, saves the path, debounces _limitInput.
|
|
270
|
+
*
|
|
271
|
+
* @param {Object} change '_filterInput' property changes
|
|
272
|
+
* @param {Boolean} autoupdate whether to auto-update on value changes
|
|
273
|
+
* @returns {void}
|
|
274
|
+
*/
|
|
318
275
|
_filterInputChanged(change, autoupdate) {
|
|
319
276
|
const path = change.path.split('.')[1];
|
|
320
277
|
this.__inputChangePath = path || null;
|
|
@@ -397,9 +354,10 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
397
354
|
|
|
398
355
|
|
|
399
356
|
/**
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
357
|
+
* Debounced function called by `_filterInputChanged` when `_filterInput` changes.
|
|
358
|
+
*
|
|
359
|
+
* @returns {void}
|
|
360
|
+
*/
|
|
403
361
|
_limitInput() {
|
|
404
362
|
const input = this._filterInput,
|
|
405
363
|
path = this.__inputChangePath,
|
|
@@ -438,15 +396,12 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
438
396
|
max = this._fromInputString(input.max, 'max');
|
|
439
397
|
|
|
440
398
|
if (this.getComparableValue(min) === this.getComparableValue(filter, 'min')
|
|
441
|
-
|
|
399
|
+
&& this.getComparableValue(max) === this.getComparableValue(filter, 'max')
|
|
442
400
|
) {
|
|
443
401
|
return;
|
|
444
402
|
}
|
|
445
403
|
|
|
446
|
-
this.set('filter', {
|
|
447
|
-
min,
|
|
448
|
-
max
|
|
449
|
-
});
|
|
404
|
+
this.set('filter', { min, max });
|
|
450
405
|
}
|
|
451
406
|
|
|
452
407
|
_filterChanged(change) {
|
|
@@ -459,7 +414,7 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
459
414
|
max = this._fromInputString(input.max, 'max');
|
|
460
415
|
|
|
461
416
|
if (this.getComparableValue(min) === this.getComparableValue(filter, 'min')
|
|
462
|
-
|
|
417
|
+
&& this.getComparableValue(max) === this.getComparableValue(filter, 'max')
|
|
463
418
|
) {
|
|
464
419
|
return;
|
|
465
420
|
}
|
|
@@ -474,53 +429,14 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
474
429
|
}
|
|
475
430
|
|
|
476
431
|
hasFilter() {
|
|
477
|
-
const filter = this.filter
|
|
478
|
-
|
|
479
|
-
if (!isSet) {
|
|
432
|
+
const filter = this.filter;
|
|
433
|
+
if (filter == null) {
|
|
480
434
|
return false;
|
|
481
435
|
}
|
|
482
436
|
return this.toValue(filter.min) != null || this.toValue(filter.max) != null;
|
|
483
437
|
}
|
|
484
438
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
const min = this.toValue(filter.min),
|
|
490
|
-
max = this.toValue(filter.max);
|
|
491
|
-
|
|
492
|
-
if (min == null && max == null) {
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
return this._toHashString(min) + '~' + this._toHashString(max);
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
_deserializeFilter(obj) {
|
|
499
|
-
if (obj == null || obj === '') {
|
|
500
|
-
return null;
|
|
501
|
-
}
|
|
502
|
-
const matches = obj.match(/^([^~]+)?~([^~]+)?/iu);
|
|
503
|
-
|
|
504
|
-
if (!Array.isArray(matches)) {
|
|
505
|
-
return null;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
return {
|
|
509
|
-
min: this._fromHashString(matches[1], 'min'),
|
|
510
|
-
max: this._fromHashString(matches[2], 'max')
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
_toHashString(value) {
|
|
515
|
-
const string = this._toInputString(value);
|
|
516
|
-
if (string == null) {
|
|
517
|
-
return '';
|
|
518
|
-
}
|
|
519
|
-
return string;
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
_fromHashString(value, property) {
|
|
523
|
-
return this._fromInputString(value, property);
|
|
439
|
+
resetFilter() {
|
|
440
|
+
this.filter = this._getDefaultFilter();
|
|
524
441
|
}
|
|
525
|
-
}
|
|
526
|
-
);
|
|
442
|
+
};
|
|
@@ -5,7 +5,7 @@ import { portal } from '@neovici/cosmoz-utils/lib/directives/portal';
|
|
|
5
5
|
import { useMeta } from '@neovici/cosmoz-utils/lib/hooks/use-meta';
|
|
6
6
|
import { checkbox } from '../cosmoz-omnitable-styles';
|
|
7
7
|
import { nothing } from 'lit-html';
|
|
8
|
-
import {
|
|
8
|
+
import { isEmpty } from '@neovici/cosmoz-utils/lib/template';
|
|
9
9
|
const settingsStyles = `
|
|
10
10
|
:host {
|
|
11
11
|
position: fixed;
|
|
@@ -95,6 +95,8 @@ const settingsStyles = `
|
|
|
95
95
|
onSave: host.onSave,
|
|
96
96
|
onReset: host.onReset,
|
|
97
97
|
|
|
98
|
+
filters: host.filters,
|
|
99
|
+
|
|
98
100
|
onDown: useCallback(e => {
|
|
99
101
|
if (!e.target.closest('.sort')) {
|
|
100
102
|
return;
|
|
@@ -170,7 +172,7 @@ const settingsStyles = `
|
|
|
170
172
|
};
|
|
171
173
|
},
|
|
172
174
|
|
|
173
|
-
renderItem = ({ onDragStart, onDragEnter, onDragOver, onDragLeave, onDrop, onDown, onToggle, collapsed }) => (column, i) => {
|
|
175
|
+
renderItem = ({ onDragStart, onDragEnter, onDragOver, onDragLeave, onDrop, onDown, onToggle, collapsed, filters }) => (column, i) => {
|
|
174
176
|
const indeterminate = collapsed?.includes(column.name),
|
|
175
177
|
checked = !column.disabled && !indeterminate;
|
|
176
178
|
return html`
|
|
@@ -181,7 +183,7 @@ const settingsStyles = `
|
|
|
181
183
|
<button class="sort" mousedown="">
|
|
182
184
|
<svg viewBox="0 0 24 24" width="24"><path d="M20 9H4v2h16V9zM4 15h16v-2H4v2z"></path></svg>
|
|
183
185
|
</button>
|
|
184
|
-
<label class="title" ?has-filter=${
|
|
186
|
+
<label class="title" ?has-filter=${ !isEmpty(filters[column.name]?.filter) }>${ column.title }</label>
|
|
185
187
|
<input class="checkbox" type="checkbox" .checked=${ checked } @click=${ onToggle }
|
|
186
188
|
.indeterminate=${ indeterminate } .windeterminate=${ indeterminate }
|
|
187
189
|
>
|
|
@@ -205,7 +207,7 @@ const settingsStyles = `
|
|
|
205
207
|
},
|
|
206
208
|
|
|
207
209
|
Settings = host => {
|
|
208
|
-
const { settings, onSettings, onSave, onReset, collapsed, settingsId, hasChanges, badge } = host,
|
|
210
|
+
const { settings, onSettings, onSave, onReset, collapsed, settingsId, hasChanges, badge, filters } = host,
|
|
209
211
|
{ active, onFocus, onToggle } = useFocus(host),
|
|
210
212
|
anchor = useCallback(() => host.shadowRoot.querySelector('.anchor'), []);
|
|
211
213
|
|
|
@@ -230,7 +232,7 @@ const settingsStyles = `
|
|
|
230
232
|
position: absolute;
|
|
231
233
|
top: 1px;
|
|
232
234
|
right: -4px;
|
|
233
|
-
background-color: var(--
|
|
235
|
+
background-color: var(--cosmoz-omnitable-checkbox-checked-color, var(--primary-color));
|
|
234
236
|
width: 8px;
|
|
235
237
|
height: 8px;
|
|
236
238
|
border-radius: 100%;
|
|
@@ -244,6 +246,7 @@ const settingsStyles = `
|
|
|
244
246
|
? portal(html`<cosmoz-omnitable-settings-ui
|
|
245
247
|
tabindex="-1" .anchor=${ anchor } .settings=${ settings } .onSettings=${ onSettings } .collapsed=${ collapsed }
|
|
246
248
|
.settingsId=${ settingsId } .hasChanges=${ hasChanges } .onSave=${ onSave } .onReset=${ onReset }
|
|
249
|
+
.filters=${ filters }
|
|
247
250
|
@focusin=${ onFocus } @focusout=${ onFocus } data-dropdown>`)
|
|
248
251
|
: [] }
|
|
249
252
|
`;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { _ } from '@neovici/cosmoz-i18next';
|
|
2
|
+
import { PolymerElement } from '@polymer/polymer';
|
|
3
|
+
import { html } from 'lit-html';
|
|
4
|
+
import { ifDefined } from 'lit-html/directives/if-defined';
|
|
5
|
+
import { dateInputMixin } from './cosmoz-omnitable-date-input-mixin';
|
|
6
|
+
import { polymerHauntedRender } from './polymer-haunted-render-mixin';
|
|
7
|
+
|
|
8
|
+
class TimeRangeInput extends dateInputMixin(polymerHauntedRender(PolymerElement)) {
|
|
9
|
+
// eslint-disable-next-line max-lines-per-function
|
|
10
|
+
render() {
|
|
11
|
+
return html`
|
|
12
|
+
<style>
|
|
13
|
+
paper-dropdown-menu {
|
|
14
|
+
--iron-icon-width: 0;
|
|
15
|
+
display: block;
|
|
16
|
+
}
|
|
17
|
+
</style>
|
|
18
|
+
|
|
19
|
+
<cosmoz-clear-button @click=${ () => this.resetFilter() } ?visible=${ this.hasFilter() }></cosmoz-clear-button>
|
|
20
|
+
<paper-dropdown-menu
|
|
21
|
+
label=${ this.title }
|
|
22
|
+
placeholder=${ ifDefined(this._filterText) }
|
|
23
|
+
class="external-values-${ this.externalValues }"
|
|
24
|
+
title=${ this._tooltip }
|
|
25
|
+
horizontal-align="right"
|
|
26
|
+
?opened=${ this.headerFocused }
|
|
27
|
+
@opened-changed=${ event => this.set('headerFocused', event.detail.value) }>
|
|
28
|
+
>
|
|
29
|
+
<div class="dropdown-content" slot="dropdown-content" style="padding: 15px; min-width: 100px;">
|
|
30
|
+
<h3 style="margin: 0;">${ this.title }</h3>
|
|
31
|
+
<paper-input
|
|
32
|
+
type="time"
|
|
33
|
+
label=${ _('From time') }
|
|
34
|
+
step=${ this.filterStep }
|
|
35
|
+
.value=${ this._filterInput.min }
|
|
36
|
+
@value-changed=${ event => this.set('_filterInput.min', event.detail.value) }
|
|
37
|
+
></paper-input>
|
|
38
|
+
<paper-input
|
|
39
|
+
type="time"
|
|
40
|
+
label=${ _('Until time') }
|
|
41
|
+
step=${ this.filterStep }
|
|
42
|
+
.value=${ this._filterInput.max }
|
|
43
|
+
@value-changed=${ event => this.set('_filterInput.max', event.detail.value) }
|
|
44
|
+
></paper-input>
|
|
45
|
+
</div>
|
|
46
|
+
</paper-dropdown-menu>
|
|
47
|
+
`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get _fixedDate() {
|
|
51
|
+
return '1970-01-01';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Converts time to date optionaly limiting it.
|
|
56
|
+
*
|
|
57
|
+
* @param {Date|Number} value Date or Timestamp ( miliseconds since property _fixedDate ) to be converted
|
|
58
|
+
* @param {Date|Number} limit Optional value to limit the date.
|
|
59
|
+
* @param {Function} limitFunc Function used to limit the date (Math.min|Math.max)
|
|
60
|
+
* @returns {Date|void} Value converted to date optionaly limitated
|
|
61
|
+
*/
|
|
62
|
+
toDate(value, limit, limitFunc) {
|
|
63
|
+
// Most browsers use local timezone when no timezone is specified
|
|
64
|
+
// but Safari uses UTC, so we set it implicitly
|
|
65
|
+
// TODO: Consider removing this when/if Safari handles local timezone correctly
|
|
66
|
+
const date = typeof value === 'string' && value.length > 3 && value.length <= 9
|
|
67
|
+
? this.getAbsoluteISOString(this._fixedDate + 'T' + value)
|
|
68
|
+
: value;
|
|
69
|
+
return super.toDate(date, limit, limitFunc);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
_toInputString(value) {
|
|
73
|
+
const date = this.toValue(value);
|
|
74
|
+
if (date == null) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
return this._toLocalISOString(date).slice(11, 19);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get the comparable value of an item.
|
|
81
|
+
*
|
|
82
|
+
* @param {Object} item Item to be processed
|
|
83
|
+
* @param {String} valuePath Property path
|
|
84
|
+
* @returns {Number|void} Valid value or void
|
|
85
|
+
*/
|
|
86
|
+
getComparableValue(item, valuePath) {
|
|
87
|
+
if (item == null) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
let value = this._toInputString(valuePath == null ? item : this.get(valuePath, item));
|
|
91
|
+
if (value == null) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
value = this.toValue(this.getAbsoluteISOString(this._fixedDate + 'T' + value));
|
|
95
|
+
if (value == null) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
return this.toNumber(value.getTime());
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
_timeValueChanged(e) {
|
|
102
|
+
const input = e.target,
|
|
103
|
+
timeString = input.value,
|
|
104
|
+
item = e.model.item,
|
|
105
|
+
oldTime = this.toDate(item.date),
|
|
106
|
+
newTime = this.toDate(oldTime != null
|
|
107
|
+
? oldTime.toISOString().slice(0, 10) + 'T' + timeString
|
|
108
|
+
: timeString),
|
|
109
|
+
formatFn = value => value;
|
|
110
|
+
if (newTime != null) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
this.set(this.valuePath, newTime, item);
|
|
114
|
+
this._fireItemChangeEvent(item, this.valuePath, oldTime, formatFn.bind(this));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// OVERRIDES
|
|
118
|
+
|
|
119
|
+
_computeFormatter(locale) {
|
|
120
|
+
const timeFormatOption = {
|
|
121
|
+
hour: 'numeric',
|
|
122
|
+
minute: 'numeric',
|
|
123
|
+
second: 'numeric'
|
|
124
|
+
};
|
|
125
|
+
return new Intl.DateTimeFormat(locale || undefined, timeFormatOption);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
customElements.define('cosmoz-omnitable-time-range-input', TimeRangeInput);
|
package/lib/generic-sorter.js
CHANGED
package/lib/invoke.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const invoke = (fn, ...args) => typeof fn === 'function' ? fn(...args) : fn;
|
package/lib/memoize.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export const
|
|
2
|
+
memoize = fn => {
|
|
3
|
+
let
|
|
4
|
+
lastArg,
|
|
5
|
+
lastResult;
|
|
6
|
+
return function (arg) {
|
|
7
|
+
if (lastArg === arg) {
|
|
8
|
+
return lastResult;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const result = fn(arg);
|
|
12
|
+
lastResult = result;
|
|
13
|
+
lastArg = arg;
|
|
14
|
+
return result;
|
|
15
|
+
};
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
memooize = fn => {
|
|
19
|
+
let
|
|
20
|
+
lastArg1,
|
|
21
|
+
lastArg2,
|
|
22
|
+
lastResult;
|
|
23
|
+
return function (arg1, arg2) {
|
|
24
|
+
if (lastArg1 === arg1 && lastArg2 === arg2) {
|
|
25
|
+
return lastResult;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const result = fn(arg1, arg2);
|
|
29
|
+
lastResult = result;
|
|
30
|
+
lastArg1 = arg1;
|
|
31
|
+
lastArg2 = arg2;
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
memoooize = fn => {
|
|
37
|
+
let
|
|
38
|
+
lastArg1,
|
|
39
|
+
lastArg2,
|
|
40
|
+
lastArg3,
|
|
41
|
+
lastResult;
|
|
42
|
+
return function (arg1, arg2, arg3) {
|
|
43
|
+
if (lastArg1 === arg1 && lastArg2 === arg2 && lastArg3 === arg3) {
|
|
44
|
+
return lastResult;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const result = fn(arg1, arg2, arg3);
|
|
48
|
+
lastResult = result;
|
|
49
|
+
lastArg1 = arg1;
|
|
50
|
+
lastArg2 = arg2;
|
|
51
|
+
lastArg3 = arg3;
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const byName = name => item => item.name === name;
|
|
2
2
|
|
|
3
3
|
export const
|
|
4
|
-
columnSymbol = Symbol('column'),
|
|
5
4
|
normalizeSettings = (columns = [], settings = [], savedSettings = []) => {
|
|
6
5
|
const
|
|
7
6
|
cols = columns.filter(column => !settings.some(byName(column.name)) && !savedSettings.some(byName(column.name))),
|
|
@@ -20,8 +19,7 @@ export const
|
|
|
20
19
|
return {
|
|
21
20
|
...setting,
|
|
22
21
|
title: column.title,
|
|
23
|
-
minWidth: parseInt(column.minWidth, 10)
|
|
24
|
-
[columnSymbol]: column
|
|
22
|
+
minWidth: parseInt(column.minWidth, 10)
|
|
25
23
|
};
|
|
26
24
|
}),
|
|
27
25
|
...cols.map(column => {
|
|
@@ -32,8 +30,7 @@ export const
|
|
|
32
30
|
priority,
|
|
33
31
|
minWidth: parseInt(minWidth, 10),
|
|
34
32
|
width: parseInt(width, 10),
|
|
35
|
-
flex: parseInt(flex, 10)
|
|
36
|
-
[columnSymbol]: column
|
|
33
|
+
flex: parseInt(flex, 10)
|
|
37
34
|
};
|
|
38
35
|
})
|
|
39
36
|
];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
import { html } from '@polymer/polymer';
|
|
3
|
+
import { render } from 'lit-html';
|
|
4
|
+
|
|
5
|
+
export const polymerHauntedRender = base => class extends base {
|
|
6
|
+
static get template() {
|
|
7
|
+
return html`<div id="output" style="position:relative;"></div>`;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
connectedCallback() {
|
|
11
|
+
super.connectedCallback();
|
|
12
|
+
render(this.render(), this.$.output);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
_propertiesChanged(currentProps, changedProps, oldProps) {
|
|
16
|
+
super._propertiesChanged(currentProps, changedProps, oldProps);
|
|
17
|
+
requestAnimationFrame(() => render(this.render(), this.$.output));
|
|
18
|
+
}
|
|
19
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { saveAs } from 'file-saver-es';
|
|
2
|
+
|
|
3
|
+
const
|
|
4
|
+
makeCsvField = str => {
|
|
5
|
+
const result = str.replace(/"/gu, '""');
|
|
6
|
+
if (result.search(/("|,|\n)/gu) >= 0) {
|
|
7
|
+
return '"' + result + '"';
|
|
8
|
+
}
|
|
9
|
+
return str;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const
|
|
13
|
+
saveAsCsvAction = (columns, selectedItems, csvFilename) => {
|
|
14
|
+
const separator = ';',
|
|
15
|
+
lf = '\n',
|
|
16
|
+
header = columns.map(col => makeCsvField(col.title)).join(separator) + lf,
|
|
17
|
+
rows = selectedItems.map(item => {
|
|
18
|
+
return columns.map(column => {
|
|
19
|
+
const cell = column.getString(column, item);
|
|
20
|
+
if (cell === undefined || cell === null) {
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
return makeCsvField(String(cell));
|
|
24
|
+
}).join(separator) + lf;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
rows.unshift(header);
|
|
28
|
+
|
|
29
|
+
saveAs(new File(rows, csvFilename, {
|
|
30
|
+
type: 'text/csv;charset=utf-8'
|
|
31
|
+
}));
|
|
32
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { saveAs } from 'file-saver-es';
|
|
2
|
+
import { NullXlsx } from '@neovici/nullxlsx';
|
|
3
|
+
|
|
4
|
+
export const
|
|
5
|
+
prepareXlsxData = (columns, selectedItems) => {
|
|
6
|
+
const headers = columns.map(col => col.title),
|
|
7
|
+
data = selectedItems.map(item =>
|
|
8
|
+
columns.map(column => {
|
|
9
|
+
const value = column.toXlsxValue(column, item);
|
|
10
|
+
return value == null ? '' : value;
|
|
11
|
+
})
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
data.unshift(headers);
|
|
15
|
+
return data;
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
saveAsXlsxAction = (column, selectedItems, xlsxFilename, xlsxSheetname) => {
|
|
19
|
+
const data = prepareXlsxData(column, selectedItems),
|
|
20
|
+
xlsx = new NullXlsx(xlsxFilename).addSheetFromData(data, xlsxSheetname).generate();
|
|
21
|
+
|
|
22
|
+
saveAs(new File([xlsx], xlsxFilename, {
|
|
23
|
+
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
24
|
+
}));
|
|
25
|
+
};
|
package/lib/use-canvas-width.js
CHANGED
|
@@ -2,7 +2,7 @@ import { useState } from 'haunted';
|
|
|
2
2
|
import { useTrackSize } from './use-track-size';
|
|
3
3
|
|
|
4
4
|
export const useCanvasWidth = host => {
|
|
5
|
-
const [canvasWidth, setCanvasWidth] = useState(
|
|
5
|
+
const [canvasWidth, setCanvasWidth] = useState(() => host.getBoundingClientRect().width);
|
|
6
6
|
|
|
7
7
|
useTrackSize(host, setCanvasWidth);
|
|
8
8
|
|