@iamproperty/components 7.2.0 → 7.2.1--beta1
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/assets/css/components/actionbar.component.css +1 -1
- package/assets/css/components/actionbar.component.css.map +1 -1
- package/assets/css/components/actionbar.global.css +1 -1
- package/assets/css/components/actionbar.global.css.map +1 -1
- package/assets/css/components/barchart.component.css +1 -1
- package/assets/css/components/barchart.component.css.map +1 -1
- package/assets/css/components/card.component.css +1 -1
- package/assets/css/components/card.component.css.map +1 -1
- package/assets/css/components/carousel.component.css +1 -1
- package/assets/css/components/carousel.component.css.map +1 -1
- package/assets/css/components/doughnutchart.component.css +1 -1
- package/assets/css/components/doughnutchart.component.css.map +1 -1
- package/assets/css/components/pagination.css +1 -1
- package/assets/css/components/pagination.css.map +1 -1
- package/assets/css/components/table-basic.component.css +1 -0
- package/assets/css/components/table-basic.component.css.map +1 -0
- package/assets/css/components/table-basic.global.css +1 -0
- package/assets/css/components/table-basic.global.css.map +1 -0
- package/assets/css/components/table.component.css +1 -1
- package/assets/css/components/table.component.css.map +1 -1
- package/assets/css/components/table.global.css +1 -1
- package/assets/css/components/table.global.css.map +1 -1
- package/assets/css/components/tabs.config.css +1 -0
- package/assets/css/components/tabs.config.css.map +1 -0
- package/assets/css/components/tabs.css +1 -1
- package/assets/css/components/tabs.css.map +1 -1
- package/assets/css/core.min.css +1 -1
- package/assets/css/core.min.css.map +1 -1
- package/assets/css/mobile-core.min.css +1 -1
- package/assets/css/mobile-core.min.css.map +1 -1
- package/assets/css/mobile.min.css +1 -1
- package/assets/css/mobile.min.css.map +1 -1
- package/assets/css/style.min.css +1 -1
- package/assets/css/style.min.css.map +1 -1
- package/assets/js/components/accordion/accordion.component.min.js +1 -1
- package/assets/js/components/actionbar/actionbar.component.min.js +4 -4
- package/assets/js/components/address-lookup/address-lookup.component.min.js +1 -1
- package/assets/js/components/applied-filters/applied-filters.component.min.js +1 -1
- package/assets/js/components/barchart/barchart.component.min.js +2 -2
- package/assets/js/components/barchart/barchart.component.min.js.map +1 -1
- package/assets/js/components/bento-grid/bento-grid.component.min.js +1 -1
- package/assets/js/components/card/card.component.min.js +2 -2
- package/assets/js/components/carousel/carousel.component.min.js +2 -2
- package/assets/js/components/collapsible-side/collapsible-side.component.min.js +1 -1
- package/assets/js/components/doughnutchart/doughnutchart.component.min.js +2 -2
- package/assets/js/components/doughnutchart/doughnutchart.component.min.js.map +1 -1
- package/assets/js/components/fileupload/fileupload.component.min.js +1 -1
- package/assets/js/components/filter-card/filter-card.component.min.js +1 -1
- package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
- package/assets/js/components/header/header.component.min.js +1 -1
- package/assets/js/components/inline-edit/inline-edit.component.min.js +1 -1
- package/assets/js/components/marketing/marketing.component.min.js +1 -1
- package/assets/js/components/menu/menu.component.min.js +1 -1
- package/assets/js/components/multi-step/multi-step.component.min.js +1 -1
- package/assets/js/components/multiselect/multiselect.component.min.js +1 -1
- package/assets/js/components/nav/nav.component.min.js +1 -1
- package/assets/js/components/notification/notification.component.min.js +1 -1
- package/assets/js/components/pagination/pagination.component.js +11 -4
- package/assets/js/components/pagination/pagination.component.min.js +5 -5
- package/assets/js/components/pagination/pagination.component.min.js.map +1 -1
- package/assets/js/components/record-card/record-card.component.min.js +1 -1
- package/assets/js/components/search/search.component.min.js +1 -1
- package/assets/js/components/search/search.component.min.js.map +1 -1
- package/assets/js/components/slider/slider.component.min.js +1 -1
- package/assets/js/components/table/table.component.js +35 -198
- package/assets/js/components/table/table.component.min.js +13 -23
- package/assets/js/components/table/table.component.min.js.map +1 -1
- package/assets/js/components/table-ajax/table-ajax.component.js +46 -0
- package/assets/js/components/table-ajax/table-ajax.component.min.js +22 -0
- package/assets/js/components/table-ajax/table-ajax.component.min.js.map +1 -0
- package/assets/js/components/table-basic/table-basic.component.js +46 -0
- package/assets/js/components/table-basic/table-basic.component.min.js +22 -0
- package/assets/js/components/table-basic/table-basic.component.min.js.map +1 -0
- package/assets/js/components/table-no-submit/table-no-submit.component.js +77 -0
- package/assets/js/components/table-no-submit/table-no-submit.component.min.js +22 -0
- package/assets/js/components/table-no-submit/table-no-submit.component.min.js.map +1 -0
- package/assets/js/components/table-submit/table-submit.component.js +55 -0
- package/assets/js/components/table-submit/table-submit.component.min.js +22 -0
- package/assets/js/components/table-submit/table-submit.component.min.js.map +1 -0
- package/assets/js/components/tabs/tabs.component.js +2 -0
- package/assets/js/components/tabs/tabs.component.min.js +6 -4
- package/assets/js/components/tabs/tabs.component.min.js.map +1 -1
- package/assets/js/components/video-card/video-card.component.min.js +1 -1
- package/assets/js/modules/helpers.js +4 -0
- package/assets/js/modules/table.js +543 -294
- package/assets/js/modules/tabs.js +43 -13
- package/assets/js/scripts.bundle.js +3 -3
- package/assets/js/scripts.bundle.js.map +1 -1
- package/assets/js/scripts.bundle.min.js +2 -2
- package/assets/js/scripts.bundle.min.js.map +1 -1
- package/assets/js/scripts.js +31 -24
- package/assets/js/tests/table.spec.js +0 -31
- package/assets/sass/_components.scss +3 -0
- package/assets/sass/components/actionbar.component.scss +1 -0
- package/assets/sass/components/actionbar.global.scss +0 -70
- package/assets/sass/components/pagination.scss +2 -1
- package/assets/sass/components/table-basic.component.scss +128 -0
- package/assets/sass/components/table-basic.global.scss +355 -0
- package/assets/sass/components/table.component.scss +2 -133
- package/assets/sass/components/table.global.scss +175 -434
- package/assets/sass/components/tabs.config.scss +27 -0
- package/assets/sass/components/tabs.scss +33 -1
- package/assets/sass/elements/buttons--global.scss +2 -1
- package/assets/sass/elements/table.element.scss +9 -7
- package/assets/sass/foundations/root.scss +1 -1
- package/assets/ts/components/pagination/pagination.component.ts +17 -4
- package/assets/ts/components/table/table.component.ts +48 -243
- package/assets/ts/components/table-ajax/table-ajax.component.ts +64 -0
- package/assets/ts/components/table-basic/README.md +40 -0
- package/assets/ts/components/table-basic/table-basic.component.ts +56 -0
- package/assets/ts/components/table-no-submit/table-no-submit.component.ts +134 -0
- package/assets/ts/components/table-submit/table-submit.component.ts +64 -0
- package/assets/ts/components/tabs/tabs.component.ts +2 -0
- package/assets/ts/modules/helpers.ts +6 -0
- package/assets/ts/modules/table.ts +655 -328
- package/assets/ts/modules/tabs.ts +54 -12
- package/assets/ts/scripts.ts +5 -3
- package/assets/ts/tests/table.spec.ts +0 -38
- package/dist/components.es.js +138 -136
- package/dist/components.umd.js +108 -116
- package/package.json +1 -1
- package/src/components/Table/TableAjax.vue +34 -0
- package/src/components/Table/TableBasic.vue +34 -0
- package/src/components/Table/TableNoSubmit.vue +34 -0
- package/src/components/Table/TableSubmit.vue +34 -0
- package/src/components/Table/Table.spec.js +0 -47
|
@@ -1,6 +1,210 @@
|
|
|
1
|
-
import { zeroPad, isNumeric, ucfirst, resolvePath } from './helpers';
|
|
1
|
+
import { zeroPad, isNumeric, ucfirst, resolvePath, uniqueID } from './helpers';
|
|
2
|
+
|
|
3
|
+
// #region Helpers
|
|
4
|
+
export const formatCell = (format, cellOutput): any => {
|
|
5
|
+
switch (format) {
|
|
6
|
+
case 'datetime':
|
|
7
|
+
return (
|
|
8
|
+
new Date(cellOutput).toLocaleDateString('en-gb', {
|
|
9
|
+
weekday: 'short',
|
|
10
|
+
year: '2-digit',
|
|
11
|
+
month: 'long',
|
|
12
|
+
day: 'numeric',
|
|
13
|
+
}) +
|
|
14
|
+
' ' +
|
|
15
|
+
new Date(cellOutput).toLocaleTimeString('en-gb', { hour: '2-digit', minute: '2-digit' })
|
|
16
|
+
);
|
|
17
|
+
case 'date':
|
|
18
|
+
return new Date(cellOutput).toLocaleDateString('en-gb', {
|
|
19
|
+
day: 'numeric',
|
|
20
|
+
month: 'long',
|
|
21
|
+
year: '2-digit',
|
|
22
|
+
});
|
|
23
|
+
case 'capitalise':
|
|
24
|
+
return (cellOutput = ucfirst(cellOutput));
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const filterFilters = function (form): object {
|
|
29
|
+
const filters = new Object();
|
|
30
|
+
|
|
31
|
+
// Filter
|
|
32
|
+
const filterInputs = Array.from(form.querySelectorAll('[data-filter]'));
|
|
33
|
+
|
|
34
|
+
filterInputs.forEach((filterInput) => {
|
|
35
|
+
// Ignore uncked radio inputs
|
|
36
|
+
if (filterInput.type == 'radio' && !filterInput.checked) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (filterInput.type == 'checkbox' && !filterInput.checked) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (filterInput && filterInput.value) {
|
|
45
|
+
const dataFilter = filterInput.getAttribute('data-filter');
|
|
46
|
+
let filterValue = filterInput.value;
|
|
47
|
+
|
|
48
|
+
if (filterInput.hasAttribute('data-date-from')) filterValue += '-date-from';
|
|
49
|
+
|
|
50
|
+
if (filterInput.hasAttribute('data-date-to')) filterValue += '-date-to';
|
|
51
|
+
|
|
52
|
+
if (!filters[dataFilter]) filters[dataFilter] = [];
|
|
53
|
+
|
|
54
|
+
filters[dataFilter].push(filterValue);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return filters;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const moveAttributesToComponents = (component): void => {
|
|
62
|
+
let form = document.createElement('form');
|
|
63
|
+
|
|
64
|
+
if (component.hasAttribute('data-filterby')) {
|
|
65
|
+
form = document.querySelector(`#${component.getAttribute('data-filterby')}`);
|
|
66
|
+
} else if (component.closest('form')) {
|
|
67
|
+
form = component.closest('form');
|
|
68
|
+
} else {
|
|
69
|
+
table.parentNode.insertBefore(form, table.nextSibling);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (form.hasAttribute('data-ajax')) component.setAttribute('data-ajax', form.getAttribute('data-ajax'));
|
|
73
|
+
|
|
74
|
+
if (form.hasAttribute('data-schema')) component.setAttribute('data-schema', form.getAttribute('data-schema'));
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const paginateTable = (component, table, form, pagination, callback): void => {
|
|
78
|
+
if (!form.querySelector('[name=show]'))
|
|
79
|
+
form.insertAdjacentHTML(
|
|
80
|
+
'beforeend',
|
|
81
|
+
`<input name="show" type="hidden" value="${component.getAttribute('data-show')}" />`
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
if (!form.querySelector('[name=page]'))
|
|
85
|
+
form.insertAdjacentHTML(
|
|
86
|
+
'beforeend',
|
|
87
|
+
`<input name="page" type="hidden" value="${component.getAttribute('data-page')}" />`
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
pagination.addEventListener('update-show', (event) => {
|
|
91
|
+
if (form.querySelector('[name=show]').value != event.detail.show) {
|
|
92
|
+
form.querySelector('[name=show]').value = event.detail.show;
|
|
93
|
+
|
|
94
|
+
const updateEvent = new CustomEvent('update-show', { detail: { show: event.detail.show } });
|
|
95
|
+
component.dispatchEvent(updateEvent);
|
|
96
|
+
|
|
97
|
+
updateAttributes(component, pagination);
|
|
98
|
+
|
|
99
|
+
callback();
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
pagination.addEventListener('update-page', (event) => {
|
|
104
|
+
if (form.querySelector('[name=page]').value != event.detail.page) {
|
|
105
|
+
form.querySelector('[name=page]').value = event.detail.page;
|
|
106
|
+
|
|
107
|
+
const updateEvent = new CustomEvent('update-page', { detail: { page: event.detail.page } });
|
|
108
|
+
component.dispatchEvent(updateEvent);
|
|
109
|
+
|
|
110
|
+
updateAttributes(component, pagination);
|
|
111
|
+
|
|
112
|
+
callback();
|
|
113
|
+
|
|
114
|
+
// scroll back to the top of the table
|
|
115
|
+
if (!component.hasAttribute('data-no-scroll')) {
|
|
116
|
+
const yOffset = -250;
|
|
117
|
+
const y = table.getBoundingClientRect().top + window.pageYOffset + yOffset;
|
|
118
|
+
window.scrollTo({ top: y, behavior: 'smooth' });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const findForm = (component, table): HTMLElement => {
|
|
125
|
+
let form = document.createElement('form');
|
|
126
|
+
|
|
127
|
+
if (component.hasAttribute('data-filterby')) {
|
|
128
|
+
form = document.querySelector(`#${component.getAttribute('data-filterby')}`);
|
|
129
|
+
} else if (component.closest('form')) {
|
|
130
|
+
form = component.closest('form');
|
|
131
|
+
} else {
|
|
132
|
+
table.parentNode.insertBefore(form, table.nextSibling);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return form;
|
|
136
|
+
};
|
|
137
|
+
// #endregion
|
|
138
|
+
|
|
139
|
+
export const setupBasicTable = (component, table, form, pagination): void => {
|
|
140
|
+
const tableWrapper = component.shadowRoot.querySelector('.table__wrapper');
|
|
141
|
+
|
|
142
|
+
if (!component.hasAttribute('data-total'))
|
|
143
|
+
component.setAttribute('data-total', component.querySelectorAll('tbody tr').length);
|
|
144
|
+
if (!component.hasAttribute('data-page')) component.setAttribute('data-page', 1);
|
|
145
|
+
if (!component.hasAttribute('data-show')) component.setAttribute('data-show', 5);
|
|
146
|
+
if (!component.hasAttribute('data-increment'))
|
|
147
|
+
component.setAttribute('data-increment', component.getAttribute('data-show'));
|
|
148
|
+
|
|
149
|
+
transferAttributes(component, pagination);
|
|
150
|
+
|
|
151
|
+
addDataAttributes(table);
|
|
152
|
+
createMobileButton(component, table);
|
|
153
|
+
|
|
154
|
+
// Max height
|
|
155
|
+
if (component.classList.contains('mh-sm')) tableWrapper.classList.add('mh-sm');
|
|
156
|
+
if (component.classList.contains('mh-md')) tableWrapper.classList.add('mh-md');
|
|
157
|
+
if (component.classList.contains('mh-lg')) tableWrapper.classList.add('mh-lg');
|
|
158
|
+
|
|
159
|
+
if (component.classList.contains('table--cta')) {
|
|
160
|
+
getLargestLastColWidth(component, table);
|
|
161
|
+
getRowHeight(component, table);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// #region Basic table fnctions
|
|
166
|
+
export const transferAttributes = (component, pagination): void => {
|
|
167
|
+
if (component.hasAttribute('data-total')) pagination.setAttribute('data-total', component.getAttribute('data-total'));
|
|
168
|
+
if (component.hasAttribute('data-page')) pagination.setAttribute('data-page', component.getAttribute('data-page'));
|
|
169
|
+
if (component.hasAttribute('data-show')) pagination.setAttribute('data-show', component.getAttribute('data-show'));
|
|
170
|
+
if (component.hasAttribute('data-increment'))
|
|
171
|
+
pagination.setAttribute('data-increment', component.getAttribute('data-show'));
|
|
172
|
+
|
|
173
|
+
if (component.hasAttribute('data-page-jump')) pagination.setAttribute('data-page-jump', 'true');
|
|
174
|
+
if (component.hasAttribute('data-per-page')) pagination.setAttribute('data-per-page', 'true');
|
|
175
|
+
if (component.hasAttribute('data-item-count')) pagination.setAttribute('data-item-count', 'true');
|
|
176
|
+
if (component.hasAttribute('data-loading')) pagination.setAttribute('data-loading', 'true');
|
|
177
|
+
|
|
178
|
+
if (component.classList.contains('table--fullwidth')) pagination.setAttribute('data-minimal', 'true');
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export const updateAttributes = (component, pagination): void => {
|
|
182
|
+
component.setAttribute('data-total', pagination.getAttribute('data-total'));
|
|
183
|
+
component.setAttribute('data-page', pagination.getAttribute('data-page'));
|
|
184
|
+
component.setAttribute('data-show', pagination.getAttribute('data-show'));
|
|
185
|
+
component.setAttribute('data-increment', pagination.getAttribute('data-show'));
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export const paginateRows = (component): void => {
|
|
189
|
+
const total = component.getAttribute('data-total');
|
|
190
|
+
const page = component.getAttribute('data-page');
|
|
191
|
+
const show = component.getAttribute('data-show');
|
|
192
|
+
const increment = component.getAttribute('data-increment');
|
|
193
|
+
|
|
194
|
+
const table = component.querySelector('table');
|
|
195
|
+
|
|
196
|
+
const end = page * show;
|
|
197
|
+
const start = end - show;
|
|
198
|
+
|
|
199
|
+
Array.from(table.querySelectorAll('tbody tr')).forEach((row, index) => {
|
|
200
|
+
if (index >= start && index < end) {
|
|
201
|
+
row.classList.add('show');
|
|
202
|
+
} else {
|
|
203
|
+
row.classList.remove('show');
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
};
|
|
2
207
|
|
|
3
|
-
// Basic functionality needed
|
|
4
208
|
export const addDataAttributes = (table): void => {
|
|
5
209
|
const colHeadings = Array.from(table.querySelectorAll('thead th'));
|
|
6
210
|
const colRows = Array.from(table.querySelectorAll('tbody tr'));
|
|
@@ -28,7 +232,8 @@ export const addDataAttributes = (table): void => {
|
|
|
28
232
|
'on track',
|
|
29
233
|
'not started',
|
|
30
234
|
'warning',
|
|
31
|
-
'
|
|
235
|
+
'successful',
|
|
236
|
+
'failed',
|
|
32
237
|
];
|
|
33
238
|
|
|
34
239
|
cells.forEach((cell, cellIndex) => {
|
|
@@ -54,46 +259,29 @@ export const addDataAttributes = (table): void => {
|
|
|
54
259
|
});
|
|
55
260
|
};
|
|
56
261
|
|
|
57
|
-
export const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Array.from(table.querySelectorAll('tbody tr')).forEach((row) => {
|
|
61
|
-
const htmlStyles = window.getComputedStyle(document.querySelector('html'));
|
|
62
|
-
const lastColChild = row.querySelector(':scope > *:last-child > *:first-child');
|
|
63
|
-
|
|
64
|
-
if (lastColChild) {
|
|
65
|
-
lastColChild.classList.add('text-nowrap');
|
|
66
|
-
let responsiveWidth = lastColChild.offsetWidth / parseFloat(htmlStyles.fontSize);
|
|
67
|
-
responsiveWidth += 1.7;
|
|
68
|
-
largestWidth = largestWidth > responsiveWidth ? largestWidth : responsiveWidth;
|
|
69
|
-
}
|
|
70
|
-
});
|
|
262
|
+
export const createMobileButton = (component, table): void => {
|
|
263
|
+
if (component.classList.contains('table--fullwidth') && !component.hasAttribute('data-expandable')) return false;
|
|
71
264
|
|
|
72
|
-
return
|
|
73
|
-
};
|
|
265
|
+
if (table.querySelectorAll('thead tr th').length < 4 && !component.hasAttribute('data-expandable')) return false;
|
|
74
266
|
|
|
75
|
-
export const createMobileButton = (table, wrapper): void => {
|
|
76
|
-
if (wrapper.classList.contains('table--fullwidth') && !wrapper.hasAttribute('data-expandable')) return false;
|
|
77
267
|
|
|
78
|
-
if (table.querySelectorAll('thead tr th').length < 4 && !wrapper.hasAttribute('data-expandable')) return false;
|
|
79
268
|
|
|
80
269
|
//If the expand column already exists we don't need to add a new one.
|
|
81
270
|
Array.from(table.querySelectorAll('thead tr')).forEach((row) => {
|
|
82
271
|
if (!table.querySelectorAll('thead tr th.expand-button-heading').length) {
|
|
83
|
-
row.insertAdjacentHTML('afterbegin', `<th class="th--fixed expand-button-heading"></th>`);
|
|
272
|
+
row.insertAdjacentHTML('afterbegin', `<th class="${component.hasAttribute('data-expandable') ? 'th--fixed ' : '' }expand-button-heading"></th>`);
|
|
84
273
|
}
|
|
85
274
|
});
|
|
86
275
|
|
|
87
|
-
Array.from(table.querySelectorAll('tbody tr')).forEach((row) => {
|
|
276
|
+
Array.from(table.querySelectorAll('tbody tr')).forEach((row, index) => {
|
|
88
277
|
const preExpanded = row.getAttribute('data-view') === 'full' ? 'aria-expanded' : '';
|
|
89
278
|
row.insertAdjacentHTML(
|
|
90
279
|
'afterbegin',
|
|
91
|
-
`<td class="td--fixed td--expand"><button class="btn btn-compact btn-secondary" data-expand-button ${preExpanded}>Expand</button></td>`
|
|
280
|
+
`<td class="${component.hasAttribute('data-expandable') ? 'td--fixed ' : '' }td--expand"><button class="btn btn-compact btn-secondary btn-sm" data-expand-button ${preExpanded} data-index="${index}">Expand</button></td>`
|
|
92
281
|
);
|
|
93
282
|
});
|
|
94
|
-
};
|
|
95
283
|
|
|
96
|
-
|
|
284
|
+
|
|
97
285
|
table.addEventListener('click', (event) => {
|
|
98
286
|
if (event && event.target instanceof HTMLElement && event.target.closest('[data-expand-button]')) {
|
|
99
287
|
const button = event.target.closest('[data-expand-button]');
|
|
@@ -105,7 +293,215 @@ export const addTableEventListeners = (table, wrapper): void => {
|
|
|
105
293
|
else tableRow.setAttribute('data-view', 'full');
|
|
106
294
|
|
|
107
295
|
button.blur();
|
|
108
|
-
|
|
296
|
+
|
|
297
|
+
component.dispatchEvent(new CustomEvent('row-expanded', { detail: { row: button.getAttribute('data-index') } }));
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
export const getLargestLastColWidth = (component, table): void => {
|
|
303
|
+
let largestWidth = 0;
|
|
304
|
+
|
|
305
|
+
Array.from(table.querySelectorAll('tbody tr')).forEach((row) => {
|
|
306
|
+
const htmlStyles = window.getComputedStyle(document.querySelector('html'));
|
|
307
|
+
const lastColChild = row.querySelector(':scope > *:last-child > *:first-child');
|
|
308
|
+
|
|
309
|
+
if (lastColChild) {
|
|
310
|
+
lastColChild.classList.add('text-nowrap');
|
|
311
|
+
let responsiveWidth = lastColChild.offsetWidth / parseFloat(htmlStyles.fontSize);
|
|
312
|
+
responsiveWidth += 1.8;
|
|
313
|
+
largestWidth = largestWidth > responsiveWidth ? largestWidth : responsiveWidth;
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
component.style.setProperty('--cta-width', `${largestWidth}rem`);
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
export const getRowHeight = (component, table): void => {
|
|
321
|
+
function outputsize(): void {
|
|
322
|
+
Array.from(table.querySelectorAll('tr')).forEach((row) => {
|
|
323
|
+
const rowHeight = row.offsetHeight;
|
|
324
|
+
|
|
325
|
+
row.style.setProperty('--row-height', `${rowHeight}px`);
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
new ResizeObserver(outputsize).observe(table);
|
|
330
|
+
};
|
|
331
|
+
// #endregion
|
|
332
|
+
|
|
333
|
+
export const setupAdvancedTable = (component, table): void => {
|
|
334
|
+
if (
|
|
335
|
+
component.querySelector('iam-actionbar[data-selectall]') ||
|
|
336
|
+
document.querySelector(`iam-actionbar[data-for='${component.getAttribute('id')}']`)
|
|
337
|
+
) {
|
|
338
|
+
const actionbar = component.querySelector('iam-actionbar[data-selectall]')
|
|
339
|
+
? component.querySelector('iam-actionbar[data-selectall]')
|
|
340
|
+
: document.querySelector(`iam-actionbar[data-for='${component.getAttribute('id')}']`);
|
|
341
|
+
|
|
342
|
+
addSelectboxes(component, table, actionbar);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
component.querySelectorAll('.dialog__wrapper .btn-compact').forEach((btn) => {
|
|
346
|
+
btn.classList.add('btn-sm');
|
|
347
|
+
btn.classList.add('m-0');
|
|
348
|
+
|
|
349
|
+
const tr = btn.closest('tr');
|
|
350
|
+
const td = btn.closest('td');
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
const trChildren = Array.prototype.slice.call( tr.children );
|
|
355
|
+
const cellIndex = trChildren.indexOf( td );
|
|
356
|
+
|
|
357
|
+
td.classList.add('td--fixed');
|
|
358
|
+
table.querySelector(`thead tr th:nth-child(${cellIndex+1})`).classList.add('th--fixed');
|
|
359
|
+
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
};
|
|
365
|
+
// #region Advanced table functions
|
|
366
|
+
export const addSelectboxes = (component, table, actionbar): void => {
|
|
367
|
+
Array.from(table.querySelectorAll('thead tr')).forEach((row) => {
|
|
368
|
+
if (row.querySelector('.expand-button-heading'))
|
|
369
|
+
row.querySelector('.expand-button-heading').insertAdjacentHTML('afterend', `<th class="th--fixed"></th>`);
|
|
370
|
+
else row.insertAdjacentHTML('afterbegin', `<th class="th--fixed"></th>`);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
Array.from(table.querySelectorAll('tbody tr')).forEach((row, index) => {
|
|
374
|
+
row.setAttribute('data-index', index + 1);
|
|
375
|
+
if (!row.querySelector('.selectrow')) {
|
|
376
|
+
const rowID = `row${uniqueID(index)}`;
|
|
377
|
+
|
|
378
|
+
if (row.querySelector('.td--expand'))
|
|
379
|
+
row
|
|
380
|
+
.querySelector('.td--expand')
|
|
381
|
+
.insertAdjacentHTML(
|
|
382
|
+
'afterend',
|
|
383
|
+
`<td class="td--fixed selectrow selected"><input type="checkbox" name="row" id="${rowID}" ${row.hasAttribute('data-selected') ? `checked="true"` : ''}/><label for="${rowID}"><span class="visually-hidden">Select row</span></label></td>`
|
|
384
|
+
);
|
|
385
|
+
else
|
|
386
|
+
row.insertAdjacentHTML(
|
|
387
|
+
'afterbegin',
|
|
388
|
+
`<td class="td--fixed selectrow selected"><input type="checkbox" name="row" id="${rowID}" ${row.hasAttribute('data-selected') ? `checked="true"` : ''}/><label for="${rowID}"><span class="visually-hidden">Select row</span></label></td>`
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
table.addEventListener('change', (event) => {
|
|
394
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('.selectrow input')) {
|
|
395
|
+
const input = event.target.closest('.selectrow input');
|
|
396
|
+
const row = event.target.closest('tr');
|
|
397
|
+
|
|
398
|
+
const count = table.querySelectorAll('.selectrow input[type="checkbox"]').length;
|
|
399
|
+
const countChecked = table.querySelectorAll('.selectrow input[type="checkbox"]:checked').length;
|
|
400
|
+
|
|
401
|
+
actionbar.setAttribute('data-selected', count == countChecked ? 'all' : countChecked);
|
|
402
|
+
|
|
403
|
+
const dispatchedEvent = new CustomEvent('row-selected', {
|
|
404
|
+
detail: {
|
|
405
|
+
rowIndex: row.getAttribute('data-index'),
|
|
406
|
+
checked: input.checked ? true : false,
|
|
407
|
+
},
|
|
408
|
+
});
|
|
409
|
+
component.dispatchEvent(dispatchedEvent);
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
actionbar.addEventListener('selected', (event) => {
|
|
414
|
+
if (event.detail.selected == '0') {
|
|
415
|
+
Array.from(table.querySelectorAll('.selectrow input[type="checkbox"]')).forEach((input) => {
|
|
416
|
+
input.checked = false;
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
const dispatchedEvent = new CustomEvent('all-rows-unselected');
|
|
420
|
+
component.dispatchEvent(dispatchedEvent);
|
|
421
|
+
} else if (event.detail.selected == 'all') {
|
|
422
|
+
Array.from(table.querySelectorAll('.selectrow input[type="checkbox"]')).forEach((input) => {
|
|
423
|
+
input.checked = true;
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
const dispatchedEvent = new CustomEvent('all-rows-selected');
|
|
427
|
+
component.dispatchEvent(dispatchedEvent);
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
// Export CSV Data
|
|
433
|
+
export const addExportEventListeners = (button, table): void | boolean => {
|
|
434
|
+
if (!button) {
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
button.addEventListener('click', () => {
|
|
439
|
+
exportAsCSV(table);
|
|
440
|
+
});
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
export const exportAsCSV = function (table): void {
|
|
444
|
+
let csvData = [];
|
|
445
|
+
// Get each row data
|
|
446
|
+
const rows = table.getElementsByTagName('tr');
|
|
447
|
+
for (let i = 0; i < rows.length; i++) {
|
|
448
|
+
// Get each column data
|
|
449
|
+
const cols = rows[i].querySelectorAll('td,th');
|
|
450
|
+
|
|
451
|
+
// Stores each csv row data
|
|
452
|
+
const csvRow = [];
|
|
453
|
+
for (let j = 0; j < cols.length; j++) {
|
|
454
|
+
// Get the text data of each cell of a row and push it to csvrow
|
|
455
|
+
csvRow.push(`"${cols[j].textContent}"`);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Combine each column value with comma
|
|
459
|
+
csvData.push(csvRow.join(','));
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Combine each row data with new line character
|
|
463
|
+
csvData = csvData.join('\n');
|
|
464
|
+
|
|
465
|
+
// Create CSV file object and feed our csvData into it
|
|
466
|
+
const CSVFile = new Blob([csvData], {
|
|
467
|
+
type: 'text/csv',
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
// Create to temporary link to initiate download process
|
|
471
|
+
const tempLink = document.createElement('a');
|
|
472
|
+
tempLink.download = 'export.csv';
|
|
473
|
+
const url = window.URL.createObjectURL(CSVFile);
|
|
474
|
+
tempLink.href = url;
|
|
475
|
+
|
|
476
|
+
// This link should not be displayed
|
|
477
|
+
tempLink.style.display = 'none';
|
|
478
|
+
document.body.appendChild(tempLink);
|
|
479
|
+
|
|
480
|
+
// Automatically click the link to trigger download
|
|
481
|
+
tempLink.click();
|
|
482
|
+
document.body.removeChild(tempLink);
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
// #endregion
|
|
486
|
+
|
|
487
|
+
export const setupNoSubmitTable = (component, table, form, pagination, savedTableBody): void => {
|
|
488
|
+
sortViaHeaders(component, table);
|
|
489
|
+
|
|
490
|
+
createSearchDataList(component, table);
|
|
491
|
+
|
|
492
|
+
form.addEventListener('change', (event) => {
|
|
493
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('[data-sort]')) {
|
|
494
|
+
sortTable(table, form, savedTableBody);
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
addFilterEventListeners(component, table, form, pagination, savedTableBody);
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
// #region No submit table functions
|
|
502
|
+
export const sortViaHeaders = (component, table): void => {
|
|
503
|
+
table.addEventListener('click', (event) => {
|
|
504
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('[data-sort]')) {
|
|
109
505
|
const heading = event.target.closest('[data-sort]');
|
|
110
506
|
heading.setAttribute('data-sort', 'true');
|
|
111
507
|
|
|
@@ -134,36 +530,35 @@ export const addTableEventListeners = (table, wrapper): void => {
|
|
|
134
530
|
ref: heading.getAttribute('data-ref'),
|
|
135
531
|
},
|
|
136
532
|
});
|
|
137
|
-
|
|
533
|
+
|
|
138
534
|
component.dispatchEvent(dispatchedEvent);
|
|
139
535
|
|
|
140
536
|
const sortBy = heading.textContent.trim();
|
|
141
537
|
const order = heading.getAttribute('data-order-by');
|
|
142
538
|
|
|
143
|
-
if (!
|
|
539
|
+
if (!component.hasAttribute('data-submit')) {
|
|
540
|
+
// TODO
|
|
144
541
|
sortTableByValues(table, sortBy, order);
|
|
145
542
|
}
|
|
146
543
|
}
|
|
147
544
|
});
|
|
148
545
|
};
|
|
149
546
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
547
|
+
export const createSearchDataList = (component, table): void => {
|
|
548
|
+
const actionbar = component.querySelector('iam-actionbar');
|
|
549
|
+
if (!actionbar) return false;
|
|
153
550
|
|
|
551
|
+
const searchInput = actionbar.shadowRoot?.querySelector('input#search');
|
|
154
552
|
if (!searchInput) return false;
|
|
155
553
|
|
|
156
554
|
const searchID = searchInput.getAttribute('id');
|
|
157
|
-
const searchableColumns = searchInput.getAttribute('data-search').split(',');
|
|
158
555
|
const inputWrapper = searchInput.parentNode;
|
|
159
556
|
|
|
160
557
|
const searchableTerms = {};
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
else searchableTerms[td.textContent] = td.textContent;
|
|
166
|
-
});
|
|
558
|
+
table.querySelectorAll('tbody td:not(.td--fixed)').forEach((td) => {
|
|
559
|
+
if (td.querySelector('.td__content'))
|
|
560
|
+
searchableTerms[td.querySelector('.td__content').textContent] = td.querySelector('.td__content').textContent;
|
|
561
|
+
else searchableTerms[td.textContent] = td.textContent;
|
|
167
562
|
});
|
|
168
563
|
|
|
169
564
|
searchInput.setAttribute('list', `${searchID}_list`);
|
|
@@ -176,15 +571,94 @@ export const createSearchDataList = (table, form): void => {
|
|
|
176
571
|
.join('')}`;
|
|
177
572
|
};
|
|
178
573
|
|
|
179
|
-
export const
|
|
574
|
+
export const sortTable = (table, form, savedTableBody): void | boolean => {
|
|
575
|
+
if (form.getAttribute('data-ajax')) {
|
|
576
|
+
return false;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const tbody = table.querySelector('tbody');
|
|
580
|
+
|
|
581
|
+
let selectedOption = form.querySelector(`input[type="radio"][data-sort]:checked`);
|
|
582
|
+
|
|
583
|
+
if (form.querySelector('select[data-sort]')) {
|
|
584
|
+
const select = form.querySelector('select[data-sort]');
|
|
585
|
+
selectedOption = form.querySelector(`select[data-sort] option:nth-child(${select.selectedIndex + 1})`);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
const sortBy = selectedOption.getAttribute('data-sort');
|
|
589
|
+
const order = selectedOption.getAttribute('data-order');
|
|
590
|
+
const format = selectedOption.getAttribute('data-format');
|
|
591
|
+
|
|
592
|
+
if (!sortBy) {
|
|
593
|
+
tbody.innerHTML = savedTableBody.innerHTML;
|
|
594
|
+
addDataAttributes(table);
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
sortTableByValues(table, sortBy, order, format);
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
export const sortTableByValues = (table, sortBy, order, format = ''): void => {
|
|
602
|
+
const tbody = table.querySelector('tbody');
|
|
603
|
+
|
|
604
|
+
let orderArray = [];
|
|
605
|
+
if (!['asc', 'desc', 'descending'].includes(order)) {
|
|
606
|
+
orderArray = order.split(',');
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Create an array from the table rows, the index created is then used to sort the array
|
|
610
|
+
let tableArr = [];
|
|
611
|
+
Array.from(tbody.querySelectorAll('tr')).forEach((tableRow) => {
|
|
612
|
+
let rowIndex = tableRow
|
|
613
|
+
.querySelector('td[data-label="' + sortBy + '"], th[data-label="' + sortBy + '"]')
|
|
614
|
+
.textContent.trim();
|
|
615
|
+
|
|
616
|
+
if (tableRow.querySelector('[data-label="' + sortBy + '"] .td__content')) {
|
|
617
|
+
rowIndex = tableRow.querySelector('[data-label="' + sortBy + '"] .td__content').textContent.trim();
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// If a predefined order set replace the search term with an ordered numeric value so it can be sorted
|
|
621
|
+
if (orderArray.length && orderArray.includes(rowIndex)) {
|
|
622
|
+
rowIndex = orderArray.indexOf(rowIndex);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
if (isNumeric(rowIndex)) {
|
|
626
|
+
rowIndex = zeroPad(rowIndex, 10);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// If the sort format is date then lets transform the index to a sortable date (this is never displayed)
|
|
630
|
+
if (format && format == 'date') {
|
|
631
|
+
rowIndex = new Date(rowIndex);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const dataRow = {
|
|
635
|
+
index: rowIndex,
|
|
636
|
+
row: tableRow,
|
|
637
|
+
};
|
|
638
|
+
tableArr.push(dataRow);
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
// Sort array alphabetically
|
|
642
|
+
tableArr.sort((a, b) => (a.index > b.index ? 1 : -1));
|
|
643
|
+
|
|
644
|
+
// Reverse if descending
|
|
645
|
+
if (order == 'descending' || order == 'desc') {
|
|
646
|
+
tableArr = tableArr.reverse();
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// Create a string to return and populate the tbody
|
|
650
|
+
let strTbody = '';
|
|
651
|
+
tableArr.forEach((tableRow) => {
|
|
652
|
+
strTbody += tableRow.row.outerHTML;
|
|
653
|
+
});
|
|
654
|
+
tbody.innerHTML = strTbody;
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
export const addFilterEventListeners = (component, table, form, pagination, savedTableBody): void => {
|
|
180
658
|
let timer;
|
|
181
659
|
|
|
182
660
|
// Check what conditions are set on the table to see what the form actions are
|
|
183
661
|
const formSubmit = function (event, paginate = false): void | boolean {
|
|
184
|
-
if (wrapper.hasAttribute('data-no-submit')) {
|
|
185
|
-
return false;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
662
|
if (form.classList.contains('processing')) return false;
|
|
189
663
|
|
|
190
664
|
Array.from(form.querySelectorAll('iam-applied-filters')).forEach((element) => {
|
|
@@ -212,22 +686,10 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
|
|
|
212
686
|
form.classList.remove('processing');
|
|
213
687
|
}
|
|
214
688
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (!paginate) {
|
|
218
|
-
const paginationInput = form.querySelector('[data-pagination]');
|
|
219
|
-
paginationInput.value = 1;
|
|
220
|
-
wrapper.setAttribute('data-page', 1);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
loadAjaxTable(table, form, pagination, wrapper);
|
|
224
|
-
} else if (form.hasAttribute('data-submit')) {
|
|
225
|
-
form.submit();
|
|
226
|
-
} else {
|
|
227
|
-
filterTable(table, form, wrapper);
|
|
228
|
-
populateDataQueries(table, form);
|
|
229
|
-
}
|
|
689
|
+
filterTable(component, table, form, pagination);
|
|
690
|
+
populateDataQueries(component, table, form);
|
|
230
691
|
|
|
692
|
+
/*
|
|
231
693
|
// Pass post data back to the page
|
|
232
694
|
if (form.hasAttribute('data-ajax-post')) {
|
|
233
695
|
const formData = new FormData(form);
|
|
@@ -236,24 +698,44 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
|
|
|
236
698
|
http.open('GET', `${window.location.href}?ajax=true&${queryString}`);
|
|
237
699
|
http.send();
|
|
238
700
|
}
|
|
701
|
+
*/
|
|
239
702
|
};
|
|
240
703
|
|
|
241
|
-
if (
|
|
242
|
-
|
|
704
|
+
if (component.querySelector('iam-actionbar[data-search]')) {
|
|
705
|
+
component.querySelector('iam-actionbar[data-search]').addEventListener('search-submit', (event) => {
|
|
243
706
|
if (form.querySelector('input[data-search]')) {
|
|
244
707
|
form.querySelector('input[data-search]').value = event.detail.search;
|
|
245
708
|
} else {
|
|
246
709
|
form.insertAdjacentHTML(
|
|
247
710
|
'beforeend',
|
|
248
|
-
`<input type="hidden" name="search" data-search="${
|
|
711
|
+
`<input type="hidden" name="search" data-search="${component.querySelector('iam-actionbar[data-search]').getAttribute('data-search')}" value="${event.detail.search}"/>`
|
|
249
712
|
);
|
|
250
713
|
}
|
|
251
714
|
|
|
715
|
+
const submitEvent = new CustomEvent('search-submit', {
|
|
716
|
+
detail: event.details,
|
|
717
|
+
});
|
|
718
|
+
component.dispatchEvent(submitEvent);
|
|
719
|
+
|
|
252
720
|
clearTimeout(timer);
|
|
253
721
|
formSubmit(event);
|
|
254
722
|
});
|
|
255
723
|
}
|
|
256
724
|
|
|
725
|
+
if (component.querySelector('iam-actionbar') && !component.querySelector('iam-actionbar').closest('form')) {
|
|
726
|
+
component.querySelector('iam-actionbar').addEventListener('change', (event) => {
|
|
727
|
+
if (!form.querySelector('.duplicate-actionbar')) {
|
|
728
|
+
form.insertAdjacentHTML(
|
|
729
|
+
'beforeend',
|
|
730
|
+
`<div class="duplicate-actionbar" style="visibility: hidden; pointer-events: none; position: absolute;"></div>`
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
form.querySelector('.duplicate-actionbar').innerHTML = component.querySelector('iam-actionbar').innerHTML;
|
|
735
|
+
filterTable(component, table, form, pagination);
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
|
|
257
739
|
form.addEventListener('keyup', (event) => {
|
|
258
740
|
clearTimeout(timer);
|
|
259
741
|
|
|
@@ -265,15 +747,7 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
|
|
|
265
747
|
});
|
|
266
748
|
|
|
267
749
|
form.addEventListener('change', (event) => {
|
|
268
|
-
clearTimeout(timer);
|
|
269
|
-
|
|
270
|
-
if (event && event.target instanceof HTMLElement && event.target.closest('[data-sort]')) {
|
|
271
|
-
if (!form.hasAttribute('data-submit')) {
|
|
272
|
-
sortTable(table, form, savedTableBody);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
formSubmit(event);
|
|
276
|
-
}
|
|
750
|
+
clearTimeout(timer);
|
|
277
751
|
|
|
278
752
|
if (event && event.target instanceof HTMLElement && event.target.closest('input[data-search]')) {
|
|
279
753
|
formSubmit(event);
|
|
@@ -282,7 +756,7 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
|
|
|
282
756
|
if (event && event.target instanceof HTMLElement && event.target.closest('[data-filter][data-no-ajax]')) {
|
|
283
757
|
// Allow for input fields to filter the current results without a new ajax call
|
|
284
758
|
|
|
285
|
-
filterTable(table, form,
|
|
759
|
+
filterTable(component, table, form, pagination);
|
|
286
760
|
populateDataQueries(table, form);
|
|
287
761
|
} else if (
|
|
288
762
|
event &&
|
|
@@ -469,90 +943,7 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
|
|
|
469
943
|
});
|
|
470
944
|
};
|
|
471
945
|
|
|
472
|
-
export const
|
|
473
|
-
if (form.getAttribute('data-ajax')) {
|
|
474
|
-
return false;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
const tbody = table.querySelector('tbody');
|
|
478
|
-
|
|
479
|
-
let selectedOption = form.querySelector(`input[type="radio"][data-sort]:checked`);
|
|
480
|
-
|
|
481
|
-
if (form.querySelector('select[data-sort]')) {
|
|
482
|
-
const select = form.querySelector('select[data-sort]');
|
|
483
|
-
selectedOption = form.querySelector(`select[data-sort] option:nth-child(${select.selectedIndex + 1})`);
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
const sortBy = selectedOption.getAttribute('data-sort');
|
|
487
|
-
const order = selectedOption.getAttribute('data-order');
|
|
488
|
-
const format = selectedOption.getAttribute('data-format');
|
|
489
|
-
|
|
490
|
-
if (!sortBy) {
|
|
491
|
-
tbody.innerHTML = savedTableBody.innerHTML;
|
|
492
|
-
addDataAttributes(table);
|
|
493
|
-
return false;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
sortTableByValues(table, sortBy, order, format);
|
|
497
|
-
};
|
|
498
|
-
|
|
499
|
-
export const sortTableByValues = (table, sortBy, order, format = ''): void => {
|
|
500
|
-
const tbody = table.querySelector('tbody');
|
|
501
|
-
|
|
502
|
-
let orderArray = [];
|
|
503
|
-
if (!['asc', 'desc', 'descending'].includes(order)) {
|
|
504
|
-
orderArray = order.split(',');
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
// Create an array from the table rows, the index created is then used to sort the array
|
|
508
|
-
let tableArr = [];
|
|
509
|
-
Array.from(tbody.querySelectorAll('tr')).forEach((tableRow) => {
|
|
510
|
-
let rowIndex = tableRow
|
|
511
|
-
.querySelector('td[data-label="' + sortBy + '"], th[data-label="' + sortBy + '"]')
|
|
512
|
-
.textContent.trim();
|
|
513
|
-
|
|
514
|
-
if (tableRow.querySelector('[data-label="' + sortBy + '"] .td__content')) {
|
|
515
|
-
rowIndex = tableRow.querySelector('[data-label="' + sortBy + '"] .td__content').textContent.trim();
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// If a predefined order set replace the search term with an ordered numeric value so it can be sorted
|
|
519
|
-
if (orderArray.length && orderArray.includes(rowIndex)) {
|
|
520
|
-
rowIndex = orderArray.indexOf(rowIndex);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
if (isNumeric(rowIndex)) {
|
|
524
|
-
rowIndex = zeroPad(rowIndex, 10);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
// If the sort format is date then lets transform the index to a sortable date (this is never displayed)
|
|
528
|
-
if (format && format == 'date') {
|
|
529
|
-
rowIndex = new Date(rowIndex);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
const dataRow = {
|
|
533
|
-
index: rowIndex,
|
|
534
|
-
row: tableRow,
|
|
535
|
-
};
|
|
536
|
-
tableArr.push(dataRow);
|
|
537
|
-
});
|
|
538
|
-
|
|
539
|
-
// Sort array alphabetically
|
|
540
|
-
tableArr.sort((a, b) => (a.index > b.index ? 1 : -1));
|
|
541
|
-
|
|
542
|
-
// Reverse if descending
|
|
543
|
-
if (order == 'descending' || order == 'desc') {
|
|
544
|
-
tableArr = tableArr.reverse();
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// Create a string to return and populate the tbody
|
|
548
|
-
let strTbody = '';
|
|
549
|
-
tableArr.forEach((tableRow) => {
|
|
550
|
-
strTbody += tableRow.row.outerHTML;
|
|
551
|
-
});
|
|
552
|
-
tbody.innerHTML = strTbody;
|
|
553
|
-
};
|
|
554
|
-
|
|
555
|
-
export const filterTable = (table, form, wrapper): void => {
|
|
946
|
+
export const filterTable = (component, table, form, pagination): void => {
|
|
556
947
|
table.classList.remove('table--filtered');
|
|
557
948
|
|
|
558
949
|
const filters = filterFilters(form);
|
|
@@ -573,10 +964,10 @@ export const filterTable = (table, form, wrapper): void => {
|
|
|
573
964
|
// Add search columns too
|
|
574
965
|
if (form.querySelector('input[data-search]')) {
|
|
575
966
|
const searchInput = form.querySelector('input[data-search]');
|
|
576
|
-
const searchColumns = form.querySelector('input[data-search]').getAttribute('data-search').split(',');
|
|
967
|
+
//const searchColumns = form.querySelector('input[data-search],[part="search-input"]').getAttribute('data-search').split(',');
|
|
577
968
|
|
|
578
|
-
|
|
579
|
-
searches.push({ column: `${column.trim()}`, value: `${searchInput.value}` });
|
|
969
|
+
table.querySelectorAll('thead tr th').forEach((column) => {
|
|
970
|
+
searches.push({ column: `${column.textContent.trim()}`, value: `${searchInput.value}` });
|
|
580
971
|
});
|
|
581
972
|
}
|
|
582
973
|
|
|
@@ -748,14 +1139,14 @@ export const filterTable = (table, form, wrapper): void => {
|
|
|
748
1139
|
}
|
|
749
1140
|
});
|
|
750
1141
|
|
|
751
|
-
if (
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
1142
|
+
if (pagination) {
|
|
1143
|
+
pagination.setAttribute('data-total', matched);
|
|
1144
|
+
pagination.setAttribute('data-show', showRows);
|
|
1145
|
+
pagination.setAttribute('data-page', page);
|
|
755
1146
|
}
|
|
756
1147
|
};
|
|
757
1148
|
|
|
758
|
-
export const populateDataQueries = (table, form
|
|
1149
|
+
export const populateDataQueries = (component, table, form): void | boolean => {
|
|
759
1150
|
const dataQueries = Array.from(form.querySelectorAll('[data-query]'));
|
|
760
1151
|
|
|
761
1152
|
dataQueries.forEach((queryElement) => {
|
|
@@ -763,7 +1154,7 @@ export const populateDataQueries = (table, form, wrapper): void | boolean => {
|
|
|
763
1154
|
let numberOfMatchedRows = 0;
|
|
764
1155
|
|
|
765
1156
|
if (query == 'total') {
|
|
766
|
-
if (
|
|
1157
|
+
if (component.hasAttribute('data-total')) numberOfMatchedRows = component.getAttribute('data-total');
|
|
767
1158
|
else
|
|
768
1159
|
numberOfMatchedRows = table.classList.contains('table--filtered')
|
|
769
1160
|
? table.querySelectorAll('tbody tr').length
|
|
@@ -815,163 +1206,80 @@ export const populateDataQueries = (table, form, wrapper): void | boolean => {
|
|
|
815
1206
|
}
|
|
816
1207
|
});
|
|
817
1208
|
};
|
|
1209
|
+
// #endregion
|
|
818
1210
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
if (wrapper.hasAttribute('data-no-submit')) {
|
|
822
|
-
return false;
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
pagination.addEventListener('update-page', (event) => {
|
|
826
|
-
const paginationInput = form.querySelector('[data-pagination]');
|
|
827
|
-
const newPage = event.detail.page;
|
|
828
|
-
|
|
829
|
-
// Set the filter value
|
|
830
|
-
paginationInput.value = newPage;
|
|
831
|
-
form.dispatchEvent(new Event('paginate'));
|
|
832
|
-
|
|
833
|
-
// Reset the data attribute
|
|
834
|
-
wrapper.setAttribute('data-page', newPage);
|
|
835
|
-
|
|
836
|
-
if (table.hasAttribute('data-show-history')) {
|
|
837
|
-
const url = new URL(location);
|
|
838
|
-
url.searchParams.set('page', newPage);
|
|
839
|
-
history.pushState({ type: 'pagination', form: form.getAttribute('id'), page: newPage }, '', url);
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
// scroll back to the top of the table
|
|
843
|
-
if (!wrapper.hasAttribute('data-no-scroll')) {
|
|
844
|
-
const yOffset = -250;
|
|
845
|
-
const y = table.getBoundingClientRect().top + window.pageYOffset + yOffset;
|
|
846
|
-
window.scrollTo({ top: y, behavior: 'smooth' });
|
|
847
|
-
}
|
|
848
|
-
});
|
|
1211
|
+
export const setupSubmitTable = (component, table, form, pagination): void => {
|
|
1212
|
+
form.setAttribute('method', 'get');
|
|
849
1213
|
|
|
850
|
-
|
|
851
|
-
const showInput = form.querySelector('[data-show]');
|
|
852
|
-
const showRows = event.detail.show;
|
|
853
|
-
showInput.value = showRows;
|
|
854
|
-
wrapper.setAttribute('data-show', showRows);
|
|
855
|
-
form.dispatchEvent(new Event('submit'));
|
|
856
|
-
});
|
|
857
|
-
};
|
|
1214
|
+
const actionbar = component.querySelector('iam-actionbar');
|
|
858
1215
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1216
|
+
if (actionbar) {
|
|
1217
|
+
actionbar.addEventListener('change', (event) => {
|
|
1218
|
+
form.submit();
|
|
1219
|
+
});
|
|
863
1220
|
}
|
|
864
|
-
|
|
865
|
-
button.addEventListener('click', () => {
|
|
866
|
-
exportAsCSV(table);
|
|
867
|
-
});
|
|
868
1221
|
};
|
|
869
1222
|
|
|
870
|
-
|
|
871
|
-
let csvData = [];
|
|
872
|
-
// Get each row data
|
|
873
|
-
const rows = table.getElementsByTagName('tr');
|
|
874
|
-
for (let i = 0; i < rows.length; i++) {
|
|
875
|
-
// Get each column data
|
|
876
|
-
const cols = rows[i].querySelectorAll('td,th');
|
|
877
|
-
|
|
878
|
-
// Stores each csv row data
|
|
879
|
-
const csvRow = [];
|
|
880
|
-
for (let j = 0; j < cols.length; j++) {
|
|
881
|
-
// Get the text data of each cell of a row and push it to csvrow
|
|
882
|
-
csvRow.push(`"${cols[j].textContent}"`);
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
// Combine each column value with comma
|
|
886
|
-
csvData.push(csvRow.join(','));
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
// Combine each row data with new line character
|
|
890
|
-
csvData = csvData.join('\n');
|
|
1223
|
+
// #region submit tables functions
|
|
891
1224
|
|
|
892
|
-
|
|
893
|
-
const CSVFile = new Blob([csvData], {
|
|
894
|
-
type: 'text/csv',
|
|
895
|
-
});
|
|
1225
|
+
// #endregion
|
|
896
1226
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
tempLink.download = 'export.csv';
|
|
900
|
-
const url = window.URL.createObjectURL(CSVFile);
|
|
901
|
-
tempLink.href = url;
|
|
1227
|
+
export const setupAjaxTable = (component, table, form, pagination): void => {
|
|
1228
|
+
loadAjaxTable(component, table, form, pagination);
|
|
902
1229
|
|
|
903
|
-
|
|
904
|
-
tempLink.style.display = 'none';
|
|
905
|
-
document.body.appendChild(tempLink);
|
|
1230
|
+
const actionbar = component.querySelector('iam-actionbar');
|
|
906
1231
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
document.body.removeChild(tempLink);
|
|
910
|
-
};
|
|
1232
|
+
form.addEventListener('submit', (event) => {
|
|
1233
|
+
loadAjaxTable(component, table, form, pagination);
|
|
911
1234
|
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
addDataAttributes(table);
|
|
915
|
-
createMobileButton(table, wrapper);
|
|
916
|
-
populateDataQueries(table, form, wrapper);
|
|
917
|
-
|
|
918
|
-
// Work out the largest width of the CTA's in the last column
|
|
919
|
-
if (wrapper && wrapper.classList.contains('table--cta')) {
|
|
920
|
-
const largestWidth = getLargestLastColWidth(table);
|
|
921
|
-
wrapper.style.setProperty('--cta-width', `${largestWidth}rem`);
|
|
922
|
-
|
|
923
|
-
function outputsize(): void {
|
|
924
|
-
Array.from(table.querySelectorAll('tr')).forEach((row) => {
|
|
925
|
-
const rowHeight = row.offsetHeight;
|
|
926
|
-
row.style.setProperty('--row-height', `${rowHeight}px`);
|
|
927
|
-
});
|
|
928
|
-
}
|
|
1235
|
+
event.preventDefault();
|
|
1236
|
+
});
|
|
929
1237
|
|
|
930
|
-
|
|
1238
|
+
if (actionbar) {
|
|
1239
|
+
actionbar.addEventListener('change', (event) => {
|
|
1240
|
+
loadAjaxTable(component, table, form, pagination);
|
|
1241
|
+
});
|
|
931
1242
|
}
|
|
932
1243
|
};
|
|
1244
|
+
// #region ajax tables functions
|
|
1245
|
+
|
|
1246
|
+
export const loadAjaxTable = async function (component, table, form, pagination): void {
|
|
1247
|
+
// Add actionbar inputs into form
|
|
1248
|
+
if (component.querySelector('iam-actionbar') && !component.querySelector('iam-actionbar').closest('form')) {
|
|
1249
|
+
if (!form.querySelector('.duplicate-actionbar'))
|
|
1250
|
+
form.insertAdjacentHTML(
|
|
1251
|
+
'beforeend',
|
|
1252
|
+
`<div class="duplicate-actionbar" style="visibility: hidden; pointer-events: none; position: absolute;"></div>`
|
|
1253
|
+
);
|
|
933
1254
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
// Filter
|
|
938
|
-
const filterInputs = Array.from(form.querySelectorAll('[data-filter]'));
|
|
939
|
-
|
|
940
|
-
filterInputs.forEach((filterInput) => {
|
|
941
|
-
// Ignore uncked radio inputs
|
|
942
|
-
if (filterInput.type == 'radio' && !filterInput.checked) {
|
|
943
|
-
return;
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
if (filterInput.type == 'checkbox' && !filterInput.checked) {
|
|
947
|
-
return;
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
if (filterInput && filterInput.value) {
|
|
951
|
-
const dataFilter = filterInput.getAttribute('data-filter');
|
|
952
|
-
let filterValue = filterInput.value;
|
|
953
|
-
|
|
954
|
-
if (filterInput.hasAttribute('data-date-from')) filterValue += '-date-from';
|
|
955
|
-
|
|
956
|
-
if (filterInput.hasAttribute('data-date-to')) filterValue += '-date-to';
|
|
1255
|
+
form.querySelector('.duplicate-actionbar').innerHTML = component.querySelector('iam-actionbar').innerHTML;
|
|
1256
|
+
}
|
|
957
1257
|
|
|
958
|
-
|
|
1258
|
+
// Add pagination inputs into form
|
|
1259
|
+
if (!form.querySelector('input[name=show]'))
|
|
1260
|
+
form.insertAdjacentHTML(
|
|
1261
|
+
'beforeend',
|
|
1262
|
+
`<input name="show" type="hidden" value="${component.getAttribute('data-show')}" />`
|
|
1263
|
+
);
|
|
959
1264
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1265
|
+
if (!form.querySelector('input[name=page]'))
|
|
1266
|
+
form.insertAdjacentHTML(
|
|
1267
|
+
'beforeend',
|
|
1268
|
+
`<input name="page" type="hidden" value="${component.getAttribute('data-page')}" />`
|
|
1269
|
+
);
|
|
963
1270
|
|
|
964
|
-
|
|
965
|
-
|
|
1271
|
+
form.querySelector('input[name=page]').value = component.getAttribute('data-page');
|
|
1272
|
+
form.querySelector('input[name=show]').value = component.getAttribute('data-show');
|
|
966
1273
|
|
|
967
|
-
|
|
1274
|
+
// Construct form data to send to api
|
|
968
1275
|
const formData = new FormData(form);
|
|
1276
|
+
|
|
969
1277
|
const queryString = new URLSearchParams(formData).toString();
|
|
970
1278
|
const columns = table.querySelectorAll('thead tr th:not(.expand-button-heading)');
|
|
971
1279
|
const tbody = table.querySelector('tbody');
|
|
972
1280
|
const ajaxURL = form.getAttribute('data-ajax');
|
|
973
1281
|
|
|
974
|
-
|
|
1282
|
+
component.classList.add('table--loading');
|
|
975
1283
|
|
|
976
1284
|
// Display the filter count
|
|
977
1285
|
const filters = filterFilters(form);
|
|
@@ -1032,8 +1340,8 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper):
|
|
|
1032
1340
|
const totalNumber = resolvePath(response, totalNumberSchema, 15);
|
|
1033
1341
|
const currentPage = resolvePath(response, currentPageSchema, 1);
|
|
1034
1342
|
const data = resolvePath(response, schema);
|
|
1035
|
-
const emptyMsg =
|
|
1036
|
-
?
|
|
1343
|
+
const emptyMsg = component.hasAttribute('data-empty-msg')
|
|
1344
|
+
? component.getAttribute('data-empty-msg')
|
|
1037
1345
|
: 'No results found';
|
|
1038
1346
|
|
|
1039
1347
|
if (data) {
|
|
@@ -1102,12 +1410,11 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper):
|
|
|
1102
1410
|
tbody.appendChild(table_row);
|
|
1103
1411
|
});
|
|
1104
1412
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
wrapper.setAttribute('data-total', parseInt(totalNumber));
|
|
1108
|
-
wrapper.setAttribute('data-page', parseInt(currentPage));
|
|
1413
|
+
component.setAttribute('data-total', parseInt(totalNumber));
|
|
1414
|
+
component.setAttribute('data-page', parseInt(currentPage));
|
|
1109
1415
|
|
|
1110
|
-
|
|
1416
|
+
pagination.setAttribute('data-total', totalNumber);
|
|
1417
|
+
pagination.setAttribute('data-page', currentPage);
|
|
1111
1418
|
|
|
1112
1419
|
Array.from(form.querySelectorAll('[data-ajax-query]')).forEach((queryElement) => {
|
|
1113
1420
|
const totalNumber = resolvePath(response, queryElement.getAttribute('data-ajax-query'), '');
|
|
@@ -1120,7 +1427,7 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper):
|
|
|
1120
1427
|
tbody.innerHTML = `<tr><td colspan="100%"><span>${emptyMsg}</span></td></tr>`;
|
|
1121
1428
|
}
|
|
1122
1429
|
|
|
1123
|
-
|
|
1430
|
+
component.classList.remove('table--loading');
|
|
1124
1431
|
|
|
1125
1432
|
window.dataLayer = window.dataLayer || [];
|
|
1126
1433
|
window.dataLayer.push({
|
|
@@ -1128,6 +1435,9 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper):
|
|
|
1128
1435
|
url: ajaxURL,
|
|
1129
1436
|
formData: queryString,
|
|
1130
1437
|
});
|
|
1438
|
+
|
|
1439
|
+
setupBasicTable(component, table, form, pagination);
|
|
1440
|
+
setupAdvancedTable(component, table, form, pagination);
|
|
1131
1441
|
} else {
|
|
1132
1442
|
tbody.innerHTML = '<tr><td colspan="100%"><span>Error loading table</span></td></tr>';
|
|
1133
1443
|
}
|
|
@@ -1140,27 +1450,44 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper):
|
|
|
1140
1450
|
console.log(error);
|
|
1141
1451
|
}
|
|
1142
1452
|
};
|
|
1453
|
+
// #endregion
|
|
1143
1454
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1455
|
+
/*
|
|
1456
|
+
// Pagination - still needed?
|
|
1457
|
+
export const addPaginationEventListeners = function (component, table, form, pagination): void | boolean {
|
|
1458
|
+
|
|
1459
|
+
|
|
1460
|
+
pagination.addEventListener('update-page', (event) => {
|
|
1461
|
+
const paginationInput = form.querySelector('[data-pagination]');
|
|
1462
|
+
const newPage = event.detail.page;
|
|
1463
|
+
|
|
1464
|
+
// Set the filter value
|
|
1465
|
+
paginationInput.value = newPage;
|
|
1466
|
+
form.dispatchEvent(new Event('paginate'));
|
|
1467
|
+
|
|
1468
|
+
// Reset the data attribute
|
|
1469
|
+
component.setAttribute('data-page', newPage);
|
|
1470
|
+
|
|
1471
|
+
if (table.hasAttribute('data-show-history')) {
|
|
1472
|
+
const url = new URL(location);
|
|
1473
|
+
url.searchParams.set('page', newPage);
|
|
1474
|
+
history.pushState({ type: 'pagination', form: form.getAttribute('id'), page: newPage }, '', url);
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
// scroll back to the top of the table
|
|
1478
|
+
if (!component.hasAttribute('data-no-scroll')) {
|
|
1479
|
+
const yOffset = -250;
|
|
1480
|
+
const y = table.getBoundingClientRect().top + window.pageYOffset + yOffset;
|
|
1481
|
+
window.scrollTo({ top: y, behavior: 'smooth' });
|
|
1482
|
+
}
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
pagination.addEventListener('update-show', (event) => {
|
|
1486
|
+
const showInput = form.querySelector('[data-show]');
|
|
1487
|
+
const showRows = event.detail.show;
|
|
1488
|
+
showInput.value = showRows;
|
|
1489
|
+
component.setAttribute('data-show', showRows);
|
|
1490
|
+
form.dispatchEvent(new Event('submit'));
|
|
1491
|
+
});
|
|
1166
1492
|
};
|
|
1493
|
+
*/
|