@neovici/cosmoz-omnitable 7.3.0 → 8.0.0-beta.4
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 +25 -0
- package/cosmoz-omnitable-column-amount.js +89 -320
- package/cosmoz-omnitable-column-autocomplete.js +36 -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 +133 -140
- package/cosmoz-omnitable-column-list.js +19 -28
- package/cosmoz-omnitable-column-mixin.js +69 -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 +1 -5
- package/cosmoz-omnitable.js +74 -770
- 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 -123
- package/lib/cosmoz-omnitable-settings.js +7 -4
- 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/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 +138 -0
- package/lib/use-fast-layout.js +21 -2
- package/lib/use-hash-state.js +59 -0
- package/lib/use-layout.js +1 -1
- package/lib/use-omnitable.js +26 -14
- package/lib/use-processed-items.js +132 -0
- package/lib/use-sort-and-group-options.js +30 -0
- package/lib/utils-amount.js +147 -0
- package/lib/utils-data.js +36 -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 -1
- 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,25 +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
|
-
if (value == null) {
|
|
253
|
-
return false;
|
|
254
|
-
}
|
|
255
|
-
const min = this.getComparableValue(filter, 'min'),
|
|
256
|
-
max = this.getComparableValue(filter, 'max');
|
|
257
|
-
return !(value < min || value > max);
|
|
258
|
-
}
|
|
259
222
|
|
|
260
223
|
_computeFilterText(change) {
|
|
261
224
|
if (change.base == null) {
|
|
@@ -303,12 +266,12 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
303
266
|
}
|
|
304
267
|
|
|
305
268
|
/**
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
+
*/
|
|
312
275
|
_filterInputChanged(change, autoupdate) {
|
|
313
276
|
const path = change.path.split('.')[1];
|
|
314
277
|
this.__inputChangePath = path || null;
|
|
@@ -391,9 +354,10 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
391
354
|
|
|
392
355
|
|
|
393
356
|
/**
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
357
|
+
* Debounced function called by `_filterInputChanged` when `_filterInput` changes.
|
|
358
|
+
*
|
|
359
|
+
* @returns {void}
|
|
360
|
+
*/
|
|
397
361
|
_limitInput() {
|
|
398
362
|
const input = this._filterInput,
|
|
399
363
|
path = this.__inputChangePath,
|
|
@@ -432,15 +396,12 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
432
396
|
max = this._fromInputString(input.max, 'max');
|
|
433
397
|
|
|
434
398
|
if (this.getComparableValue(min) === this.getComparableValue(filter, 'min')
|
|
435
|
-
|
|
399
|
+
&& this.getComparableValue(max) === this.getComparableValue(filter, 'max')
|
|
436
400
|
) {
|
|
437
401
|
return;
|
|
438
402
|
}
|
|
439
403
|
|
|
440
|
-
this.set('filter', {
|
|
441
|
-
min,
|
|
442
|
-
max
|
|
443
|
-
});
|
|
404
|
+
this.set('filter', { min, max });
|
|
444
405
|
}
|
|
445
406
|
|
|
446
407
|
_filterChanged(change) {
|
|
@@ -453,7 +414,7 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
453
414
|
max = this._fromInputString(input.max, 'max');
|
|
454
415
|
|
|
455
416
|
if (this.getComparableValue(min) === this.getComparableValue(filter, 'min')
|
|
456
|
-
|
|
417
|
+
&& this.getComparableValue(max) === this.getComparableValue(filter, 'max')
|
|
457
418
|
) {
|
|
458
419
|
return;
|
|
459
420
|
}
|
|
@@ -468,53 +429,14 @@ export const rangeColumnMixin = dedupingMixin(base => // eslint-disable-line max
|
|
|
468
429
|
}
|
|
469
430
|
|
|
470
431
|
hasFilter() {
|
|
471
|
-
const filter = this.filter
|
|
472
|
-
|
|
473
|
-
if (!isSet) {
|
|
432
|
+
const filter = this.filter;
|
|
433
|
+
if (filter == null) {
|
|
474
434
|
return false;
|
|
475
435
|
}
|
|
476
436
|
return this.toValue(filter.min) != null || this.toValue(filter.max) != null;
|
|
477
437
|
}
|
|
478
438
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
return;
|
|
482
|
-
}
|
|
483
|
-
const min = this.toValue(filter.min),
|
|
484
|
-
max = this.toValue(filter.max);
|
|
485
|
-
|
|
486
|
-
if (min == null && max == null) {
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
return this._toHashString(min) + '~' + this._toHashString(max);
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
_deserializeFilter(obj) {
|
|
493
|
-
if (obj == null || obj === '') {
|
|
494
|
-
return null;
|
|
495
|
-
}
|
|
496
|
-
const matches = obj.match(/^([^~]+)?~([^~]+)?/iu);
|
|
497
|
-
|
|
498
|
-
if (!Array.isArray(matches)) {
|
|
499
|
-
return null;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
return {
|
|
503
|
-
min: this._fromHashString(matches[1], 'min'),
|
|
504
|
-
max: this._fromHashString(matches[2], 'max')
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
_toHashString(value) {
|
|
509
|
-
const string = this._toInputString(value);
|
|
510
|
-
if (string == null) {
|
|
511
|
-
return '';
|
|
512
|
-
}
|
|
513
|
-
return string;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
_fromHashString(value, property) {
|
|
517
|
-
return this._fromInputString(value, property);
|
|
439
|
+
resetFilter() {
|
|
440
|
+
this.filter = this._getDefaultFilter();
|
|
518
441
|
}
|
|
519
|
-
}
|
|
520
|
-
);
|
|
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
|
|
|
@@ -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
|
+
};
|
|
@@ -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
|
|