@iamproperty/components 7.2.0 → 7.2.1--beta1

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