@neovici/cosmoz-omnitable 7.2.1 → 8.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +23 -0
  2. package/cosmoz-omnitable-column-amount.js +89 -320
  3. package/cosmoz-omnitable-column-autocomplete.js +36 -47
  4. package/cosmoz-omnitable-column-boolean.js +107 -209
  5. package/cosmoz-omnitable-column-date.js +89 -102
  6. package/cosmoz-omnitable-column-datetime.js +86 -119
  7. package/cosmoz-omnitable-column-list-data.js +4 -1
  8. package/cosmoz-omnitable-column-list-horizontal.js +20 -38
  9. package/cosmoz-omnitable-column-list-mixin.js +133 -140
  10. package/cosmoz-omnitable-column-list.js +19 -28
  11. package/cosmoz-omnitable-column-mixin.js +69 -447
  12. package/cosmoz-omnitable-column-number.js +91 -183
  13. package/cosmoz-omnitable-column-time.js +77 -162
  14. package/cosmoz-omnitable-column.js +49 -93
  15. package/cosmoz-omnitable-group-row.js +1 -5
  16. package/cosmoz-omnitable-header-row.js +9 -6
  17. package/cosmoz-omnitable-item-expand.js +0 -3
  18. package/cosmoz-omnitable-item-row.js +5 -8
  19. package/cosmoz-omnitable-styles.js +1 -5
  20. package/cosmoz-omnitable.js +72 -763
  21. package/lib/cosmoz-omnitable-amount-range-input.js +295 -0
  22. package/{cosmoz-omnitable-column-date-mixin.js → lib/cosmoz-omnitable-date-input-mixin.js} +4 -26
  23. package/lib/cosmoz-omnitable-date-range-input.js +81 -0
  24. package/lib/cosmoz-omnitable-datetime-range-input.js +75 -0
  25. package/lib/cosmoz-omnitable-number-range-input.js +159 -0
  26. package/{cosmoz-omnitable-column-range-mixin.js → lib/cosmoz-omnitable-range-input-mixin.js} +45 -123
  27. package/lib/cosmoz-omnitable-settings.js +7 -4
  28. package/lib/cosmoz-omnitable-time-range-input.js +130 -0
  29. package/lib/generic-sorter.js +2 -2
  30. package/lib/invoke.js +1 -0
  31. package/lib/memoize.js +54 -0
  32. package/lib/polymer-haunted-render-mixin.js +19 -0
  33. package/lib/save-as-csv-action.js +32 -0
  34. package/lib/save-as-xlsx-action.js +25 -0
  35. package/lib/use-canvas-width.js +1 -1
  36. package/lib/use-dom-columns.js +133 -0
  37. package/lib/use-hash-state.js +59 -0
  38. package/lib/use-layout.js +1 -1
  39. package/lib/use-omnitable.js +26 -14
  40. package/lib/use-processed-items.js +132 -0
  41. package/lib/use-sort-and-group-options.js +30 -0
  42. package/lib/utils-amount.js +147 -0
  43. package/lib/utils-data.js +36 -0
  44. package/lib/utils-date.js +204 -0
  45. package/lib/utils-datetime.js +71 -0
  46. package/lib/utils-number.js +112 -0
  47. package/lib/utils-time.js +115 -0
  48. package/package.json +1 -1
  49. package/lib/use-force-render.js +0 -8
  50. package/lib/use-render-on-column-updates.js +0 -18
@@ -3,161 +3,128 @@ import '@polymer/paper-dropdown-menu/paper-dropdown-menu';
3
3
  import '@neovici/cosmoz-datetime-input';
4
4
  import './ui-helpers/cosmoz-clear-button';
5
5
 
6
- import { dateColumnMixin } from './cosmoz-omnitable-column-date-mixin';
7
6
  import { columnMixin } from './cosmoz-omnitable-column-mixin';
8
- import {
9
- translatable, _
10
- } from '@neovici/cosmoz-i18next';
11
7
  import { PolymerElement } from '@polymer/polymer/polymer-element';
12
8
  import { html } from 'lit-html';
13
- import { ifDefined } from 'lit-html/directives/if-defined';
14
- window.Cosmoz = window.Cosmoz || {};
9
+ import { fromHashString, getString, toHashString, toXlsxValue } from './lib/utils-datetime';
10
+ import { applySingleFilter, fromInputString, getComparableValue, toDate } from './lib/utils-date';
11
+ import { valuesFrom } from './lib/utils-data';
12
+ import './lib/cosmoz-omnitable-datetime-range-input';
15
13
 
16
14
  /**
17
15
  * @polymer
18
16
  * @customElement
19
- * @appliesMixin dateColumnMixin
20
17
  * @appliesMixin columnMixin
21
18
  */
22
- class OmnitableColumnDatetime extends
23
- dateColumnMixin(
24
- columnMixin(
25
- translatable(PolymerElement)
26
- )
27
- ) {
19
+ class OmnitableColumnDatetime extends columnMixin(PolymerElement) {
28
20
  static get is() {
29
21
  return 'cosmoz-omnitable-column-datetime';
30
22
  }
31
23
 
32
24
  static get properties() {
33
25
  return {
34
- filterStep: {
35
- type: Number,
36
- value: 1
37
- },
38
-
39
- width: {
40
- type: String,
41
- value: '210px'
42
- },
43
-
44
- editWidth: {
45
- type: String,
46
- value: '320px'
47
- },
48
-
49
- minWidth: {
50
- type: String,
51
- value: '128px'
52
- },
53
-
54
- editMinWidth: {
55
- type: String,
56
- value: '128px'
57
- },
58
-
59
- headerCellClass: {
60
- type: String,
61
- value: 'datetime-header-cell'
62
- }
26
+ min: { type: Number, value: null, notify: true },
27
+ max: { type: Number, value: null, notify: true },
28
+ locale: { type: String, value: null, notify: true },
29
+ headerCellClass: { type: String, value: 'datetime-header-cell' },
30
+ width: { type: String, value: '210px' },
31
+ minWidth: { type: String, value: '128px' },
32
+ flex: { type: String, value: '0' },
33
+ filterStep: { type: Number, value: 1 }
63
34
  };
64
35
  }
65
36
 
66
- renderCell(column, { item }) {
67
- return column.getString(item, column.valuePath, column.formatter);
37
+ getFilterFn(column, filter) {
38
+ const
39
+ min = getComparableValue(filter, 'min', column),
40
+ max = getComparableValue(filter, 'max', column);
41
+
42
+ if (min == null && max == null) {
43
+ return;
44
+ }
45
+ return applySingleFilter(column, filter);
68
46
  }
69
47
 
70
- renderEditCell(column, { item }) {
71
- const onChange = event => {
72
- event.model = { item };
73
- return column._dateValueChanged(event);
74
- };
48
+ getString(column, item) {
49
+ return getString(column, item);
50
+ }
75
51
 
76
- return html`<cosmoz-datetime-input
77
- no-label-float
78
- @value-changed=${ onChange }
79
- .value=${ column.getInputString(item, column.valuePath) }
80
- ></cosmoz-datetime-input>`;
52
+ toXlsxValue(column, item) {
53
+ return toXlsxValue(column, item);
81
54
  }
82
55
 
83
- renderHeader(column) {
84
- return html`
85
- <cosmoz-clear-button @click=${ event => column.resetFilter(event) } ?visible=${ column.hasFilter() }></cosmoz-clear-button>
86
- <paper-dropdown-menu
87
- label=${ column.title }
88
- placeholder=${ ifDefined(column._filterText) }
89
- class="external-values-${ column.externalValues }"
90
- title=${ column._tooltip }
91
- horizontal-align=${ column.preferredDropdownHorizontalAlign }
92
- ?opened=${ column.headerFocused }
93
- @opened-changed=${ event => column.headerFocused = event.detail.value }>
94
- <div class="dropdown-content" slot="dropdown-content" style="padding: 15px; min-width: 100px;">
95
- <h3 style="margin: 0;">${ column.title }</h3>
96
- <cosmoz-datetime-input
97
- date-label=${ _('From date') }
98
- time-label=${ _('From time') }
99
- min=${ column._toInputString(column._limit.fromMin) }
100
- max=${ column._toInputString(column._limit.fromMax) }
101
- step=${ column.filterStep }
102
- .value=${ column._filterInput.min }
103
- @value-changed=${ event => column.set('_filterInput.min', event.detail.value) }
104
- ></cosmoz-datetime-input>
105
- <cosmoz-datetime-input
106
- date-label=${ _('To date') }
107
- time-label=${ _('To time') }
108
- min=${ column._toInputString(column._limit.toMin) }
109
- max=${ column._toInputString(column._limit.toMax) }
110
- step=${ column.filterStep }
111
- .value=${ column._filterInput.max }
112
- @value-changed=${ event => column.set('_filterInput.max', event.detail.value) }
113
- ></cosmoz-datetime-input>
114
- </div>
115
- </paper-dropdown-menu>
116
- `;
56
+ cellTitleFn(column, item) {
57
+ return getString(column, item);
117
58
  }
118
59
 
119
- _toInputString(value) {
120
- const date = this.toValue(value);
121
- if (date == null) {
122
- return;
123
- }
124
- return this._toLocalISOString(date).slice(0, 19);
60
+ getComparableValue(item, valuePath, column) {
61
+ return getComparableValue(item, valuePath, column);
125
62
  }
126
63
 
127
- _toHashString(value) {
128
- const date = this.toValue(value);
129
- if (date == null) {
130
- return '';
64
+ serializeFilter(column, filter) {
65
+ if (filter == null) {
66
+ return;
131
67
  }
132
- //Use utc in hash
133
- return date.toISOString().slice(0, 19).replace(/:/gu, '.');
134
- }
68
+ const min = toDate(filter.min),
69
+ max = toDate(filter.max);
135
70
 
136
- _fromHashString(value) {
137
- if (value == null || value === '') {
71
+ if (min == null && max == null) {
138
72
  return;
139
73
  }
140
- //Parse utc from hash string
141
- return this.toValue(value.replace(/\./gu, ':') + 'Z');
74
+ return toHashString(min) + '~' + toHashString(max);
142
75
  }
143
76
 
144
- toXlsxValue(item, valuePath = this.valuePath) {
145
- if (!valuePath) {
146
- return '';
77
+ deserializeFilter(column, filter) {
78
+ if (filter == null || filter === '') {
79
+ return null;
147
80
  }
148
- return this.get(valuePath, item);
149
- }
81
+ const matches = filter.match(/^([^~]+)?~([^~]+)?/iu);
150
82
 
151
- // OVERRIDES
152
- _computeFormatter(locale) {
153
- const timeFormatOption = {
154
- year: 'numeric',
155
- month: 'numeric',
156
- day: 'numeric',
157
- hour: 'numeric',
158
- minute: 'numeric'
83
+ if (!Array.isArray(matches)) {
84
+ return null;
85
+ }
86
+
87
+ return {
88
+ min: fromHashString(matches[1]),
89
+ max: fromHashString(matches[2])
159
90
  };
160
- return new Intl.DateTimeFormat(locale || undefined, timeFormatOption);
91
+ }
92
+
93
+ renderCell(column, { item }) {
94
+ return getString(column, item);
95
+ }
96
+
97
+ renderEditCell(column, { item }, onItemChange) {
98
+ const onChange = event => onItemChange(fromInputString(event.target.value));
99
+ return html`<paper-input no-label-float type="text" @change=${ onChange } .value=${ getString(column, item) }></paper-input>`;
100
+ }
101
+
102
+ // eslint-disable-next-line max-lines-per-function
103
+ renderHeader(
104
+ { title,
105
+ min,
106
+ max,
107
+ locale,
108
+ filterStep },
109
+ { filter },
110
+ setState,
111
+ source
112
+ ) {
113
+ return html`<cosmoz-omnitable-datetime-range-input
114
+ .title=${ title }
115
+ .filter=${ filter }
116
+ .values=${ source }
117
+ .min=${ min }
118
+ .max=${ max }
119
+ .locale=${ locale }
120
+ .filterStep=${ filterStep }
121
+ @filter-changed=${ ({ detail: { value }}) => setState(state => ({ ...state, filter: value })) }
122
+ @header-focused-changed=${ ({ detail: { value }}) => setState(state => ({ ...state, headerFocused: value })) }
123
+ ></cosmoz-omnitable-datetime-range-input>`;
124
+ }
125
+
126
+ computeSource({ valuePath }, data) {
127
+ return valuesFrom(data, valuePath);
161
128
  }
162
129
  }
163
130
 
@@ -66,7 +66,10 @@ class OmnitableColumnListData extends translatable(mixin(Template, PolymerElemen
66
66
  static get properties() {
67
67
  return {
68
68
  items: {
69
- type: Array
69
+ type: Array,
70
+ observer() {
71
+ this.dispatchEvent(new CustomEvent('iron-resize', { bubbles: true }));
72
+ }
70
73
  },
71
74
 
72
75
  _expanded: {
@@ -5,9 +5,8 @@ import {
5
5
  html, nothing
6
6
  } from 'lit-html';
7
7
 
8
- import { translatable } from '@neovici/cosmoz-i18next';
9
8
  import { columnMixin } from './cosmoz-omnitable-column-mixin';
10
- import { listColumnMixin } from './cosmoz-omnitable-column-list-mixin';
9
+ import { getTexts, listColumnMixin, onChange, onFocus, onText } from './cosmoz-omnitable-column-list-mixin';
11
10
 
12
11
  /**
13
12
  * @polymer
@@ -15,23 +14,14 @@ import { listColumnMixin } from './cosmoz-omnitable-column-list-mixin';
15
14
  * @appliesMixin listColumnMixin
16
15
  * @appliesMixin columnMixin
17
16
  */
18
- class OmnitableColumnListHorizontal extends listColumnMixin(
19
- columnMixin(
20
- translatable(
21
- PolymerElement
22
- )
23
- )
24
- ) {
25
- static get is() {
26
- return 'cosmoz-omnitable-column-list-horizontal';
27
- }
28
-
29
- renderCell(column, { item }) {
30
- const list = column.getTexts(item, column.valuePath, column.textProperty).map(item => html`<li>${ item }</li>`);
17
+ class OmnitableColumnListHorizontal extends listColumnMixin(columnMixin(PolymerElement)) {
18
+ renderCell({ valuePath, textProperty }, { item }) {
19
+ const list = getTexts(item, valuePath, textProperty).map(item => html`<li>${ item }</li>`);
31
20
 
32
21
  return html`
33
22
  <style>
34
23
  ul {
24
+ padding: 0;
35
25
  display: inline;
36
26
  list-style: none;
37
27
  }
@@ -45,41 +35,33 @@ class OmnitableColumnListHorizontal extends listColumnMixin(
45
35
  content: "";
46
36
  }
47
37
  </style>
48
- <ul>${ list }</ul>
38
+ <ul>${ list }</ul>
49
39
  `;
50
40
  }
51
41
 
52
- renderEditCell(column, { item }) {
53
- const onChange = event => {
54
- event.model = { item };
55
- return column._valueChanged(event);
56
- };
57
-
58
- return html`<paper-input no-label-float type="text" @change=${ onChange } .value=${ column.getString(item, column.valuePath) }></paper-input>`;
42
+ renderEditCell() {
43
+ return 'not implemented';
59
44
  }
60
45
 
61
- renderHeader(column) {
62
- const spinner = column.loading
63
- ? html`<paper-spinner-lite style="width: 20px; height: 20px;" suffix slot="suffix" active></paper-spinner-lite>`
64
- : nothing;
65
-
46
+ renderHeader(column, { filter, query }, setState, source) {
47
+ const
48
+ spinner = column.loading
49
+ ? html`<paper-spinner-lite style="width: 20px; height: 20px;" suffix slot="suffix" active></paper-spinner-lite>`
50
+ : nothing;
66
51
  return html`<cosmoz-autocomplete-ui
67
52
  class="external-values-${ column.externalValues }"
68
53
  .label=${ column.title }
69
- .source=${ column._source }
54
+ .source=${ source }
70
55
  .textProperty=${ column.textProperty }
71
- .value=${ column._computeValue(column.filter, column._source) }
72
- .text=${ column.query }
73
- .onChange=${ column._onChange }
74
- .onFocus=${ column._onFocus }
75
- .onText=${ column._onText }
56
+ .value=${ filter }
57
+ .text=${ query }
58
+ .onChange=${ onChange(setState) }
59
+ .onFocus=${ onFocus(setState) }
60
+ .onText=${ onText(setState) }
76
61
  >${ spinner }</cosmoz-autocomplete-ui>
77
62
  `;
78
63
  }
79
64
 
80
65
  }
81
66
 
82
- customElements.define(
83
- OmnitableColumnListHorizontal.is,
84
- OmnitableColumnListHorizontal
85
- );
67
+ customElements.define('cosmoz-omnitable-column-list-horizontal', OmnitableColumnListHorizontal);
@@ -1,113 +1,54 @@
1
- import { dedupingMixin } from '@polymer/polymer/lib/utils/mixin';
2
1
  import {
3
2
  prop, array
4
3
  } from '@neovici/cosmoz-autocomplete/lib/utils';
4
+ import { get } from '@polymer/polymer/lib/utils/path';
5
+ import { valuesFrom } from './lib/utils-data';
5
6
 
6
- /**
7
- * @polymer
8
- * @mixinFunction
9
- */
10
- // eslint-disable-next-line max-lines-per-function
11
- export const listColumnMixin = dedupingMixin(base => class extends base {
12
- static get properties() {
13
- return {
14
- /**
15
- * Ask for a list of values
16
- */
17
- bindValues: {
18
- type: Boolean,
19
- readOnly: true,
20
- value: true
21
- },
22
-
23
- filter: {
24
- type: Array,
25
- notify: true,
26
- value() {
27
- return this._getDefaultFilter();
7
+ const
8
+ unique = (values, valueProperty) => {
9
+ if (!Array.isArray(values)) {
10
+ return;
11
+ }
12
+ const used = [];
13
+ return values
14
+ .reduce((acc, cur) => {
15
+ if (Array.isArray(cur)) {
16
+ cur.forEach(subcur => {
17
+ acc.push(subcur);
18
+ });
19
+ return acc;
28
20
  }
29
- },
30
-
31
- textProperty: {
32
- type: String
33
- },
34
-
35
- valueProperty: {
36
- type: String
37
- },
38
-
39
- query: {
40
- type: String,
41
- notify: true
42
- },
43
-
44
- emptyLabel: {
45
- type: String
46
- },
47
- emptyValue: {
48
- type: Object
49
- },
50
-
51
- _source: {
52
- type: Array,
53
- computed: '_computeSource(values, valueProperty, textProperty, emptyLabel, emptyValue)'
54
- }
55
- };
56
- }
57
- constructor() {
58
- super();
59
- this._onFocus = this._onFocus.bind(this);
60
- this._onChange = this._onChange.bind(this);
61
- this._onText = this._onText.bind(this);
62
- }
63
-
64
- getString(item, valuePath = this.valuePath, textProperty = this.textProperty) {
65
- return this.getTexts(item, valuePath, textProperty)
66
- .filter(i => i != null)
67
- .join(', ');
68
- }
69
-
70
- getTexts(item, valuePath = this.valuePath, textProperty = this.textProperty) {
71
- return array(valuePath && this.get(valuePath, item)).map(prop(textProperty));
72
- }
73
-
74
- toXlsxValue(item, valuePath = this.valuePath) {
75
- return this.getString(item, valuePath);
76
- }
77
-
78
- /**
79
- * Get the comparable value of an item.
80
- *
81
- * @param {Object} item Item to be processed
82
- * @param {String} valuePath Property path
83
- * @returns {String|void} Valid value or void
84
- */
85
- getComparableValue(item, valuePath = this.valuePath) {
86
- const value = super.getComparableValue(item, valuePath);
87
- if (this.valueProperty == null) {
88
- return value;
21
+ acc.push(cur);
22
+ return acc;
23
+ }, [])
24
+ .filter((item, index, array) => {
25
+ if (array.indexOf(item) !== index) {
26
+ return false;
27
+ }
28
+ if (valueProperty) {
29
+ const value = get(item, valueProperty);
30
+ if (used.indexOf(value) !== -1) {
31
+ return false;
32
+ }
33
+ used.push(value);
34
+ }
35
+ return true;
36
+ });
37
+ },
38
+
39
+ toAutocompleteSource = (values, valueProperty, textProperty) => {
40
+ if (values == null) {
41
+ return [];
42
+ }
43
+
44
+ if (Array.isArray(values)) {
45
+ return unique(values, valueProperty);
89
46
  }
90
- const subValues = array(value).reduce((acc, subItem) => {
91
- acc.push(this.get(this.valueProperty, subItem));
92
- return acc;
93
- }, []);
94
- return subValues.sort().join(' ');
95
- }
96
-
97
- _getDefaultFilter() {
98
- return [];
99
- }
100
47
 
101
- _getSource(values, valueProperty = this.valueProperty, textProperty = this.textProperty) {
102
- if (values != null && !Array.isArray(values) && typeof values === 'object') {
103
- const valProp = valueProperty ?? 'id',
48
+ if (typeof values === 'object') {
49
+ const
50
+ valProp = valueProperty ?? 'id',
104
51
  textProp = textProperty ?? 'label';
105
- if (valueProperty == null) {
106
- this.valueProperty = valProp;
107
- }
108
- if (textProperty == null) {
109
- this.textProperty = textProp;
110
- }
111
52
  return Object
112
53
  .entries(values)
113
54
  .map(([id, label]) => ({
@@ -124,51 +65,103 @@ export const listColumnMixin = dedupingMixin(base => class extends base {
124
65
  return 0;
125
66
  });
126
67
  }
127
- return this._unique(values, valueProperty) || [];
128
- }
129
68
 
130
- _computeSource(values, valueProperty, textProperty, emptyLabel, emptyValue) {
131
- if (typeof values === 'function') {
132
- return values;
133
- }
69
+ return [];
70
+ },
71
+
72
+ getTexts = (item, valuePath, textProperty) =>
73
+ array(valuePath && get(item, valuePath)).map(prop(textProperty)),
74
+
75
+ getString = ({ valuePath, textProperty }, item) => {
76
+ return getTexts(item, valuePath, textProperty)
77
+ .filter(i => i != null)
78
+ .join(', ');
79
+ },
80
+
81
+ toXlsxValue = getString,
82
+
83
+ applyMultiFilter = ({ valueProperty, valuePath, emptyValue }, filters) => item => {
84
+ const val = prop(valueProperty),
85
+ values = array(get(item, valuePath));
86
+ return filters.some(filter =>
87
+ values.length === 0 && val(filter) === emptyValue || values.some(value => val(value) === val(filter))
88
+ );
89
+ },
90
+
91
+ onChange = setState => value => setState(state => ({ ...state, filter: value })),
92
+ onFocus = setState => focused => setState(state => ({ ...state, headerFocused: focused })),
93
+ onText = setState => text => setState(state => ({ ...state, query: text })),
94
+
95
+ computeSource = (
96
+ { valuePath, valueProperty, textProperty, emptyLabel, emptyValue },
97
+ data
98
+ ) => {
99
+ const values = valuesFrom(data, valuePath),
100
+ source = toAutocompleteSource(values, valueProperty, textProperty);
134
101
 
135
- const source = this._getSource(values, valueProperty, textProperty);
136
- if (!emptyLabel || emptyValue === undefined || source.length < 0) {
102
+ if (!emptyLabel || emptyValue === undefined || !textProperty || !valueProperty || source.length < 0) {
137
103
  return source;
138
104
  }
139
105
  return [{
140
- [this.textProperty]: emptyLabel,
141
- [this.valueProperty]: emptyValue
106
+ [textProperty]: emptyLabel,
107
+ [valueProperty]: emptyValue
142
108
  }, ...source];
143
- }
109
+ },
110
+
111
+ listColumnMixin = base => class extends base {
112
+ static get properties() {
113
+ return {
114
+ textProperty: { type: String },
115
+ valueProperty: { type: String },
116
+ emptyLabel: { type: String },
117
+ emptyValue: { type: Object }
118
+ };
119
+ }
144
120
 
121
+ getString(column, item) {
122
+ return getString(column, item);
123
+ }
145
124
 
146
- _applyMultiFilter(filters, item) {
147
- const val = prop(this.valueProperty),
148
- values = array(this.get(this.valuePath, item));
149
- return filters.some(
150
- filter => values.length === 0 && val(filter) === this.emptyValue || values.some(value => val(value) === val(filter))
151
- );
152
- }
125
+ toXlsxValue(column, item) {
126
+ return toXlsxValue(column, item);
127
+ }
153
128
 
154
- _computeValue(filters, source = [], valueProperty = this.valueProperty) {
155
- if ((filters?.length || 0) < 1) {
156
- return;
129
+ cellTitleFn(column, item) {
130
+ return getString(column, item);
157
131
  }
158
- const val = prop(valueProperty),
159
- sourced = typeof source === 'function' ? [] : source.filter(item => filters.some(filter => val(filter) === val(item)));
160
- return filters.map(filter => sourced.find(item => val(item) === val(filter)) || filter);
161
- }
162
-
163
- _onChange(value) {
164
- this.filter = value;
165
- }
166
-
167
- _onFocus(focused) {
168
- this.headerFocused = focused;
169
- }
170
-
171
- _onText(text) {
172
- this.query = text;
173
- }
174
- });
132
+
133
+ getComparableValue(item, valuePath, { valueProperty }) {
134
+ const value = get(item, valuePath);
135
+ if (valueProperty == null) {
136
+ return value;
137
+ }
138
+ const subValues = array(value).reduce((acc, subItem) => {
139
+ acc.push(get(subItem, valueProperty));
140
+ return acc;
141
+ }, []);
142
+ return subValues.sort().join(' ');
143
+ }
144
+
145
+ getFilterFn(column, filters) {
146
+ if (!filters || !Array.isArray(filters) || filters.length === 0) {
147
+ return;
148
+ }
149
+
150
+ return applyMultiFilter(column, filters);
151
+ }
152
+
153
+ serializeFilter(column, filter) {
154
+ // TODO: drop the double-encoding
155
+ return filter.length === 0 ? null : encodeURIComponent(JSON.stringify(filter));
156
+ }
157
+
158
+ deserializeFilter(column, filter) {
159
+ return JSON.parse(decodeURIComponent(filter));
160
+ }
161
+
162
+ computeSource(column, data) {
163
+ return computeSource(column, data);
164
+ }
165
+ };
166
+
167
+ export { unique, getTexts, getString, toXlsxValue, applyMultiFilter, onChange, onFocus, onText, computeSource, toAutocompleteSource, listColumnMixin };