@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.
Files changed (126) hide show
  1. package/assets/css/components/actionbar.component.css +1 -1
  2. package/assets/css/components/actionbar.component.css.map +1 -1
  3. package/assets/css/components/actionbar.global.css +1 -1
  4. package/assets/css/components/actionbar.global.css.map +1 -1
  5. package/assets/css/components/barchart.component.css +1 -1
  6. package/assets/css/components/barchart.component.css.map +1 -1
  7. package/assets/css/components/card.component.css +1 -1
  8. package/assets/css/components/card.component.css.map +1 -1
  9. package/assets/css/components/carousel.component.css +1 -1
  10. package/assets/css/components/carousel.component.css.map +1 -1
  11. package/assets/css/components/doughnutchart.component.css +1 -1
  12. package/assets/css/components/doughnutchart.component.css.map +1 -1
  13. package/assets/css/components/pagination.css +1 -1
  14. package/assets/css/components/pagination.css.map +1 -1
  15. package/assets/css/components/table-basic.component.css +1 -0
  16. package/assets/css/components/table-basic.component.css.map +1 -0
  17. package/assets/css/components/table-basic.global.css +1 -0
  18. package/assets/css/components/table-basic.global.css.map +1 -0
  19. package/assets/css/components/table.component.css +1 -1
  20. package/assets/css/components/table.component.css.map +1 -1
  21. package/assets/css/components/table.global.css +1 -1
  22. package/assets/css/components/table.global.css.map +1 -1
  23. package/assets/css/components/tabs.config.css +1 -0
  24. package/assets/css/components/tabs.config.css.map +1 -0
  25. package/assets/css/components/tabs.css +1 -1
  26. package/assets/css/components/tabs.css.map +1 -1
  27. package/assets/css/core.min.css +1 -1
  28. package/assets/css/core.min.css.map +1 -1
  29. package/assets/css/mobile-core.min.css +1 -1
  30. package/assets/css/mobile-core.min.css.map +1 -1
  31. package/assets/css/mobile.min.css +1 -1
  32. package/assets/css/mobile.min.css.map +1 -1
  33. package/assets/css/style.min.css +1 -1
  34. package/assets/css/style.min.css.map +1 -1
  35. package/assets/js/components/accordion/accordion.component.min.js +1 -1
  36. package/assets/js/components/actionbar/actionbar.component.min.js +4 -4
  37. package/assets/js/components/address-lookup/address-lookup.component.min.js +1 -1
  38. package/assets/js/components/applied-filters/applied-filters.component.min.js +1 -1
  39. package/assets/js/components/barchart/barchart.component.min.js +2 -2
  40. package/assets/js/components/barchart/barchart.component.min.js.map +1 -1
  41. package/assets/js/components/bento-grid/bento-grid.component.min.js +1 -1
  42. package/assets/js/components/card/card.component.min.js +2 -2
  43. package/assets/js/components/carousel/carousel.component.min.js +2 -2
  44. package/assets/js/components/collapsible-side/collapsible-side.component.min.js +1 -1
  45. package/assets/js/components/doughnutchart/doughnutchart.component.min.js +2 -2
  46. package/assets/js/components/doughnutchart/doughnutchart.component.min.js.map +1 -1
  47. package/assets/js/components/fileupload/fileupload.component.min.js +1 -1
  48. package/assets/js/components/filter-card/filter-card.component.min.js +1 -1
  49. package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
  50. package/assets/js/components/header/header.component.min.js +1 -1
  51. package/assets/js/components/inline-edit/inline-edit.component.min.js +1 -1
  52. package/assets/js/components/marketing/marketing.component.min.js +1 -1
  53. package/assets/js/components/menu/menu.component.min.js +1 -1
  54. package/assets/js/components/multi-step/multi-step.component.min.js +1 -1
  55. package/assets/js/components/multiselect/multiselect.component.min.js +1 -1
  56. package/assets/js/components/nav/nav.component.min.js +1 -1
  57. package/assets/js/components/notification/notification.component.min.js +1 -1
  58. package/assets/js/components/pagination/pagination.component.js +11 -4
  59. package/assets/js/components/pagination/pagination.component.min.js +5 -5
  60. package/assets/js/components/pagination/pagination.component.min.js.map +1 -1
  61. package/assets/js/components/record-card/record-card.component.min.js +1 -1
  62. package/assets/js/components/search/search.component.min.js +1 -1
  63. package/assets/js/components/search/search.component.min.js.map +1 -1
  64. package/assets/js/components/slider/slider.component.min.js +1 -1
  65. package/assets/js/components/table/table.component.js +36 -198
  66. package/assets/js/components/table/table.component.min.js +13 -23
  67. package/assets/js/components/table/table.component.min.js.map +1 -1
  68. package/assets/js/components/table-ajax/table-ajax.component.js +46 -0
  69. package/assets/js/components/table-ajax/table-ajax.component.min.js +22 -0
  70. package/assets/js/components/table-ajax/table-ajax.component.min.js.map +1 -0
  71. package/assets/js/components/table-basic/table-basic.component.js +46 -0
  72. package/assets/js/components/table-basic/table-basic.component.min.js +22 -0
  73. package/assets/js/components/table-basic/table-basic.component.min.js.map +1 -0
  74. package/assets/js/components/table-no-submit/table-no-submit.component.js +77 -0
  75. package/assets/js/components/table-no-submit/table-no-submit.component.min.js +22 -0
  76. package/assets/js/components/table-no-submit/table-no-submit.component.min.js.map +1 -0
  77. package/assets/js/components/table-submit/table-submit.component.js +55 -0
  78. package/assets/js/components/table-submit/table-submit.component.min.js +22 -0
  79. package/assets/js/components/table-submit/table-submit.component.min.js.map +1 -0
  80. package/assets/js/components/tabs/tabs.component.js +2 -0
  81. package/assets/js/components/tabs/tabs.component.min.js +6 -4
  82. package/assets/js/components/tabs/tabs.component.min.js.map +1 -1
  83. package/assets/js/components/video-card/video-card.component.min.js +1 -1
  84. package/assets/js/modules/helpers.js +4 -0
  85. package/assets/js/modules/table.js +544 -294
  86. package/assets/js/modules/tabs.js +43 -13
  87. package/assets/js/scripts.bundle.js +3 -3
  88. package/assets/js/scripts.bundle.js.map +1 -1
  89. package/assets/js/scripts.bundle.min.js +2 -2
  90. package/assets/js/scripts.bundle.min.js.map +1 -1
  91. package/assets/js/scripts.js +31 -24
  92. package/assets/js/tests/table.spec.js +0 -31
  93. package/assets/sass/_components.scss +3 -0
  94. package/assets/sass/components/actionbar.component.scss +1 -0
  95. package/assets/sass/components/actionbar.global.scss +0 -70
  96. package/assets/sass/components/pagination.scss +2 -1
  97. package/assets/sass/components/table-basic.component.scss +132 -0
  98. package/assets/sass/components/table-basic.global.scss +365 -0
  99. package/assets/sass/components/table.component.scss +2 -133
  100. package/assets/sass/components/table.global.scss +175 -434
  101. package/assets/sass/components/tabs.config.scss +27 -0
  102. package/assets/sass/components/tabs.scss +33 -1
  103. package/assets/sass/elements/buttons--global.scss +2 -1
  104. package/assets/sass/elements/table.element.scss +9 -7
  105. package/assets/sass/foundations/root.scss +1 -1
  106. package/assets/ts/components/pagination/pagination.component.ts +17 -4
  107. package/assets/ts/components/table/table.component.ts +49 -243
  108. package/assets/ts/components/table-ajax/table-ajax.component.ts +64 -0
  109. package/assets/ts/components/table-basic/README.md +40 -0
  110. package/assets/ts/components/table-basic/table-basic.component.ts +56 -0
  111. package/assets/ts/components/table-no-submit/table-no-submit.component.ts +134 -0
  112. package/assets/ts/components/table-submit/table-submit.component.ts +64 -0
  113. package/assets/ts/components/tabs/tabs.component.ts +2 -0
  114. package/assets/ts/modules/helpers.ts +6 -0
  115. package/assets/ts/modules/table.ts +656 -328
  116. package/assets/ts/modules/tabs.ts +54 -12
  117. package/assets/ts/scripts.ts +5 -3
  118. package/assets/ts/tests/table.spec.ts +0 -38
  119. package/dist/components.es.js +138 -136
  120. package/dist/components.umd.js +108 -116
  121. package/package.json +1 -1
  122. package/src/components/Table/TableAjax.vue +34 -0
  123. package/src/components/Table/TableBasic.vue +34 -0
  124. package/src/components/Table/TableNoSubmit.vue +34 -0
  125. package/src/components/Table/TableSubmit.vue +34 -0
  126. 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
- 'error',
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 getLargestLastColWidth = (table): number => {
58
- let largestWidth = 0;
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 largestWidth;
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
- export const addTableEventListeners = (table, wrapper): void => {
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
- } else if (event && event.target instanceof HTMLElement && event.target.closest('[data-sort]')) {
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
- const component = heading.closest('iam-table');
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 (!wrapper.hasAttribute('data-submit')) {
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
- // Filters
151
- export const createSearchDataList = (table, form): void => {
152
- const searchInput = form.querySelector('input[data-search]');
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
- searchableColumns.forEach((columnHeading) => {
162
- Array.from(table.querySelectorAll('td[data-label="' + columnHeading.trim() + '"]')).forEach((td) => {
163
- if (td.querySelector('.td__content'))
164
- searchableTerms[td.querySelector('.td__content').textContent] = td.querySelector('.td__content').textContent;
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 addFilterEventListeners = (table, form, pagination, wrapper, savedTableBody): void => {
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
- if (form.hasAttribute('data-ajax')) {
216
- // Default back to page 1
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 (form.querySelector('iam-actionbar[data-search]')) {
242
- form.querySelector('iam-actionbar[data-search]').addEventListener('search-submit', (event) => {
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="${form.querySelector('iam-actionbar[data-search]').getAttribute('data-search')}" value="${event.detail.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, wrapper);
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 sortTable = (table, form, savedTableBody): void | boolean => {
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
- searchColumns.forEach((column) => {
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 (wrapper) {
752
- wrapper.setAttribute('data-total', matched);
753
- wrapper.setAttribute('data-show', showRows);
754
- wrapper.setAttribute('data-page', page);
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, wrapper): void | boolean => {
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 (wrapper.hasAttribute('data-total')) numberOfMatchedRows = wrapper.getAttribute('data-total');
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
- // Pagination
820
- export const addPaginationEventListeners = function (table, form, pagination, wrapper): void | boolean {
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
- pagination.addEventListener('update-show', (event) => {
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
- // Export CSV Data
860
- export const addExportEventListeners = (button, table): void | boolean => {
861
- if (!button) {
862
- return false;
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
- export const exportAsCSV = function (table): void {
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
- // Create CSV file object and feed our csvData into it
893
- const CSVFile = new Blob([csvData], {
894
- type: 'text/csv',
895
- });
1226
+ // #endregion
896
1227
 
897
- // Create to temporary link to initiate download process
898
- const tempLink = document.createElement('a');
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
- // This link should not be displayed
904
- tempLink.style.display = 'none';
905
- document.body.appendChild(tempLink);
1231
+ const actionbar = component.querySelector('iam-actionbar');
906
1232
 
907
- // Automatically click the link to trigger download
908
- tempLink.click();
909
- document.body.removeChild(tempLink);
910
- };
1233
+ form.addEventListener('submit', (event) => {
1234
+ loadAjaxTable(component, table, form, pagination);
911
1235
 
912
- // After table is loaded
913
- export const makeTableFunctional = function (table, form, pagination, wrapper): void {
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
- new ResizeObserver(outputsize).observe(table);
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
- const filterFilters = function (form): object {
935
- const filters = new Object();
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
- if (!filters[dataFilter]) filters[dataFilter] = [];
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
- filters[dataFilter].push(filterValue);
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
- return filters;
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
- export const loadAjaxTable = async function (table, form, pagination, wrapper): void {
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
- wrapper.classList.add('table--loading');
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 = wrapper.hasAttribute('data-empty-msg')
1036
- ? wrapper.getAttribute('data-empty-msg')
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
- createSearchDataList(table, form);
1106
- // Add data to the pagination
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
- makeTableFunctional(table, form, pagination, wrapper);
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
- wrapper.classList.remove('table--loading');
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
- export const formatCell = (format, cellOutput): any => {
1145
- switch (format) {
1146
- case 'datetime':
1147
- return (
1148
- new Date(cellOutput).toLocaleDateString('en-gb', {
1149
- weekday: 'short',
1150
- year: '2-digit',
1151
- month: 'long',
1152
- day: 'numeric',
1153
- }) +
1154
- ' ' +
1155
- new Date(cellOutput).toLocaleTimeString('en-gb', { hour: '2-digit', minute: '2-digit' })
1156
- );
1157
- case 'date':
1158
- return new Date(cellOutput).toLocaleDateString('en-gb', {
1159
- day: 'numeric',
1160
- month: 'long',
1161
- year: '2-digit',
1162
- });
1163
- case 'capitalise':
1164
- return (cellOutput = ucfirst(cellOutput));
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
+ */