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