@iamproperty/components 4.1.0-beta-2 → 4.1.0

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 (131) hide show
  1. package/assets/css/components/accordion.css.map +1 -1
  2. package/assets/css/components/actionbar-global.css +1 -1
  3. package/assets/css/components/actionbar-global.css.map +1 -1
  4. package/assets/css/components/address-lookup.css +1 -0
  5. package/assets/css/components/address-lookup.css.map +1 -0
  6. package/assets/css/components/admin-panel.css +1 -1
  7. package/assets/css/components/admin-panel.css.map +1 -1
  8. package/assets/css/components/dialog.css +1 -1
  9. package/assets/css/components/dialog.css.map +1 -1
  10. package/assets/css/components/fileupload.css +1 -1
  11. package/assets/css/components/fileupload.css.map +1 -1
  12. package/assets/css/components/forms.css +1 -1
  13. package/assets/css/components/forms.css.map +1 -1
  14. package/assets/css/components/header.css +1 -1
  15. package/assets/css/components/header.css.map +1 -1
  16. package/assets/css/components/lists.css +1 -1
  17. package/assets/css/components/lists.css.map +1 -1
  18. package/assets/css/components/nav-global.css +1 -1
  19. package/assets/css/components/nav-global.css.map +1 -1
  20. package/assets/css/components/nav.css +1 -1
  21. package/assets/css/components/nav.css.map +1 -1
  22. package/assets/css/components/nav.old.css +1 -1
  23. package/assets/css/components/nav.old.css.map +1 -1
  24. package/assets/css/components/notification.css +1 -1
  25. package/assets/css/components/notification.css.map +1 -1
  26. package/assets/css/components/pagination.css +1 -1
  27. package/assets/css/components/pagination.css.map +1 -1
  28. package/assets/css/components/property-searchbar.css +1 -1
  29. package/assets/css/components/property-searchbar.css.map +1 -1
  30. package/assets/css/components/table.css +1 -1
  31. package/assets/css/components/table.css.map +1 -1
  32. package/assets/css/components/table.extras.css +1 -0
  33. package/assets/css/components/table.extras.css.map +1 -0
  34. package/assets/css/components/table.global.css +1 -0
  35. package/assets/css/components/table.global.css.map +1 -0
  36. package/assets/css/components/tabs.css +1 -1
  37. package/assets/css/components/tabs.css.map +1 -1
  38. package/assets/css/core.min.css +1 -1
  39. package/assets/css/core.min.css.map +1 -1
  40. package/assets/css/style.min.css +1 -1
  41. package/assets/css/style.min.css.map +1 -1
  42. package/assets/js/components/accordion/accordion.component.min.js +1 -1
  43. package/assets/js/components/actionbar/actionbar.component.min.js +3 -3
  44. package/assets/js/components/actionbar/actionbar.component.min.js.map +1 -1
  45. package/assets/js/components/address-lookup/address-lookup.component.js +172 -0
  46. package/assets/js/components/address-lookup/address-lookup.component.min.js +36 -0
  47. package/assets/js/components/address-lookup/address-lookup.component.min.js.map +1 -0
  48. package/assets/js/components/applied-filters/applied-filters.component.min.js +2 -2
  49. package/assets/js/components/applied-filters/applied-filters.component.min.js.map +1 -1
  50. package/assets/js/components/card/card.component.min.js +1 -1
  51. package/assets/js/components/collapsible-side/collapsible-side.component.min.js +1 -1
  52. package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
  53. package/assets/js/components/header/header.component.min.js +2 -2
  54. package/assets/js/components/nav/nav.component.min.js +2 -2
  55. package/assets/js/components/notification/notification.component.min.js +4 -4
  56. package/assets/js/components/notification/notification.component.min.js.map +1 -1
  57. package/assets/js/components/pagination/pagination.component.js +152 -7
  58. package/assets/js/components/pagination/pagination.component.min.js +38 -12
  59. package/assets/js/components/pagination/pagination.component.min.js.map +1 -1
  60. package/assets/js/components/table/table.component.js +95 -69
  61. package/assets/js/components/table/table.component.min.js +9 -13
  62. package/assets/js/components/table/table.component.min.js.map +1 -1
  63. package/assets/js/components/tabs/tabs.component.js +3 -1
  64. package/assets/js/components/tabs/tabs.component.min.js +7 -5
  65. package/assets/js/components/tabs/tabs.component.min.js.map +1 -1
  66. package/assets/js/dynamic.min.js +5 -5
  67. package/assets/js/dynamic.min.js.map +1 -1
  68. package/assets/js/modules/applied-filters.js +3 -4
  69. package/assets/js/modules/dialogs.js +15 -3
  70. package/assets/js/modules/dynamicEvents.js +116 -0
  71. package/assets/js/modules/helpers.js +9 -0
  72. package/assets/js/modules/pagination.js +7 -10
  73. package/assets/js/modules/table.js +51 -52
  74. package/assets/js/modules/tabs.js +10 -1
  75. package/assets/js/scripts.bundle.js +53 -25
  76. package/assets/js/scripts.bundle.js.map +1 -1
  77. package/assets/js/scripts.bundle.min.js +2 -2
  78. package/assets/js/scripts.bundle.min.js.map +1 -1
  79. package/assets/js/tests/table.spec.js +0 -57
  80. package/assets/sass/_components.scss +2 -0
  81. package/assets/sass/_corefiles.scss +6 -2
  82. package/assets/sass/_functions/variables.scss +5 -1
  83. package/assets/sass/components/actionbar-global.scss +11 -2
  84. package/assets/sass/components/address-lookup.scss +22 -0
  85. package/assets/sass/components/admin-panel.scss +4 -0
  86. package/assets/sass/components/dialog.scss +22 -13
  87. package/assets/sass/components/fileupload.scss +2 -0
  88. package/assets/sass/components/forms.scss +231 -71
  89. package/assets/sass/components/lists.scss +119 -1
  90. package/assets/sass/components/nav-global.scss +1 -0
  91. package/assets/sass/components/notification.scss +6 -1
  92. package/assets/sass/components/pagination.scss +192 -100
  93. package/assets/sass/components/table.extras.scss +650 -0
  94. package/assets/sass/components/table.global.scss +103 -0
  95. package/assets/sass/components/table.scss +41 -565
  96. package/assets/sass/components/tabs.scss +95 -32
  97. package/assets/sass/foundations/brand.scss +4 -0
  98. package/assets/sass/foundations/buttons.scss +14 -12
  99. package/assets/sass/foundations/links.scss +2 -1
  100. package/assets/sass/helpers/dynamic.scss +3 -0
  101. package/assets/sass/templates/form.scss +84 -0
  102. package/assets/svg/logo.svg +7 -0
  103. package/assets/ts/components/address-lookup/address-lookup.component.ts +215 -0
  104. package/assets/ts/components/pagination/README.md +11 -0
  105. package/assets/ts/components/pagination/pagination.component.ts +182 -8
  106. package/assets/ts/components/table/README.md +4 -2
  107. package/assets/ts/components/table/table.component.ts +134 -83
  108. package/assets/ts/components/tabs/README.md +6 -5
  109. package/assets/ts/components/tabs/tabs.component.ts +3 -1
  110. package/assets/ts/modules/applied-filters.ts +5 -8
  111. package/assets/ts/modules/dialogs.ts +19 -4
  112. package/assets/ts/modules/dynamicEvents.ts +145 -0
  113. package/assets/ts/modules/helpers.ts +16 -1
  114. package/assets/ts/modules/pagination.ts +7 -10
  115. package/assets/ts/modules/table.ts +70 -57
  116. package/assets/ts/modules/tabs.ts +21 -10
  117. package/assets/ts/tests/table.spec.ts +1 -61
  118. package/dist/components.es.js +1123 -1008
  119. package/dist/components.umd.js +165 -80
  120. package/dist/style.css +1 -1
  121. package/package.json +3 -2
  122. package/src/components/AddressLookup/AddressLookup.vue +27 -0
  123. package/src/components/Pagination/README.md +11 -0
  124. package/src/components/Table/README.md +4 -3
  125. package/src/components/Table/Table.vue +4 -0
  126. package/src/components/Tabs/README.md +10 -7
  127. package/src/components/Tabs/Tab.vue +7 -8
  128. package/src/components/Tabs/Tabs.vue +0 -1
  129. package/src/index.js +1 -0
  130. package/assets/js/tests/pagination.spec.js +0 -15
  131. package/assets/ts/tests/pagination.spec.ts +0 -21
@@ -0,0 +1,145 @@
1
+ // @ts-nocheck
2
+
3
+ // Create the event listeners
4
+ const createDynamicEvents = () => {
5
+
6
+ // Change event
7
+ document.addEventListener('change', (event) => {
8
+ if (event && event.target instanceof HTMLElement && event.target.closest('[data-change-events]'))
9
+ readMatches(event.target,event.target.closest('[data-change-events]').getAttribute('data-change-events'));
10
+ });
11
+ document.addEventListener('change', (event) => {
12
+ if (event && event.target instanceof HTMLElement && event.target.closest('[data-change-events]'))
13
+ readMatches(event.target,event.target.closest('[data-change-events]').getAttribute('data-change-events'));
14
+ });
15
+ document.addEventListener('keyup', (event) => {
16
+ if (event && event.target instanceof HTMLElement && event.target.closest('[data-change-events]'))
17
+ readMatches(event.target,event.target.closest('[data-change-events]').getAttribute('data-change-events'));
18
+ });
19
+
20
+ // Click event
21
+ document.addEventListener('click', (event) => {
22
+ if (event && event.target instanceof HTMLElement && event.target.closest('[data-click-events]'))
23
+ readMatches(event.target,event.target.closest('[data-click-events]').getAttribute('data-click-events'));
24
+ });
25
+ };
26
+
27
+ // Parse the JSON and trigger the events, this may be singular or multiple set of events
28
+ const readMatches = (element,events) => {
29
+
30
+ // an empty events will trigger looking up the dom chain for
31
+ if(!events){
32
+ events = element.parentNode.getAttribute('data-change-events');
33
+ }
34
+
35
+ // If still empty bail out
36
+ if(!events)
37
+ return false;
38
+
39
+ // Split out each event
40
+ Array.from(JSON.parse(events)).forEach((event, index) => {
41
+ checkMatch(element,event);
42
+ });
43
+ };
44
+
45
+ const checkMatch = (element,event) => {
46
+
47
+ if("matches" in event){
48
+ if(event['matches'] == 'any')
49
+ runEvent(element,event,'if');
50
+ else if(element.value == event.matches)
51
+ runEvent(element,event,'if');
52
+ else
53
+ runEvent(element,event,'else');
54
+
55
+ return false;
56
+ }
57
+ else if("in-list" in event){
58
+ if(document.querySelector(`${event['in-list']} option[value="${element.value}"]`)){
59
+ let match = document.querySelector(`${event['in-list']} option[value="${element.value}"]`);
60
+ runEvent(element,event,'if',match);
61
+ }
62
+ else
63
+ runEvent(element,event,'else');
64
+
65
+ return false;
66
+ }
67
+ else if("event" in event){
68
+ runEvent(element,event,'event');
69
+ }
70
+ };
71
+
72
+ const runEvent = (element,event,eventType,match) => {
73
+
74
+ if(eventType in event == false)
75
+ return false;
76
+
77
+ switch (event[eventType]){
78
+ case "hide":
79
+
80
+ let hideElement = document.querySelector(event['target'])
81
+ hideElement.classList.add('js-hide');
82
+
83
+ Array.from(hideElement.querySelectorAll('[data-required]')).forEach((input, index) => {
84
+
85
+ input.removeAttribute('required');
86
+ });
87
+ break;
88
+ case "show":
89
+
90
+ let showElement = document.querySelector(event['target'])
91
+ showElement.classList.remove('js-hide');
92
+
93
+ Array.from(showElement.querySelectorAll('[data-required]')).forEach((input, index) => {
94
+
95
+ if(!input.closest('.js-hide'))
96
+ input.setAttribute('required','true');
97
+ });
98
+ break;
99
+ case "populate-form":
100
+ populateForm(element,event,match);
101
+ break;
102
+ case "setAttribute":
103
+ document.querySelector(`${event['target']}`).setAttribute(event['attribute'],event['value']);
104
+ break;
105
+ case "removeAttribute":
106
+ document.querySelector(`${event['target']}`).removeAttribute(event['attribute']);
107
+ break;
108
+ case "updateValue":
109
+ document.querySelector(`${event['target']}`).value = event['value'] ? event['value'] : "";
110
+
111
+ let changeEvent = new Event('change');
112
+ document.querySelector(`${event['target']}`).dispatchEvent(changeEvent);
113
+ break;
114
+ default:
115
+ break;
116
+ }
117
+ }
118
+
119
+ const populateForm = function (element,event,match) {
120
+
121
+ let response = JSON.parse(match.getAttribute('data-values'));
122
+ let form = document.querySelector(event['target']);
123
+
124
+ Object.keys(response).forEach((field, index) => {
125
+
126
+ if(document.getElementById(field) && document.getElementById(field).tagName == "SPAN")
127
+ document.getElementById(field).innerHTML = response[field];
128
+
129
+ if(form.querySelector(`input[name="${field}"][type="radio"][value="${response[field]}"]`)){
130
+
131
+ Array.from(form.querySelectorAll(`input[name="${field}"][type="radio"]`)).forEach(function(input,index){
132
+ input.disabled = true;
133
+ });
134
+
135
+ form.querySelector(`input[name="${field}"][type="radio"][value="${response[field]}"]`).checked = true;
136
+ form.querySelector(`input[name="${field}"][type="radio"][value="${response[field]}"]`).disabled = false;
137
+ }
138
+ else if(form.querySelector(`input[name="${field}"]`)){
139
+ form.querySelector(`input[name="${field}"]`).value = response[field];
140
+ form.querySelector(`input[name="${field}"]`).setAttribute('readonly','true');
141
+ }
142
+ });
143
+ }
144
+
145
+ export default createDynamicEvents;
@@ -25,7 +25,7 @@ export const addBodyClasses = (body) => {
25
25
  * @param {HTMLElement} body Dom element, this doesn't have to be the body but it is recommended.
26
26
  */
27
27
  export const addGlobalEvents = (body) => {
28
-
28
+
29
29
  const checkElements = function(hash){
30
30
 
31
31
  const label = document.querySelector(`label[for="${hash.replace('#','')}"]`);
@@ -60,6 +60,21 @@ export const addGlobalEvents = (body) => {
60
60
  }
61
61
  });
62
62
 
63
+ document.addEventListener("submit", (event) => {
64
+
65
+ if (event && event.target instanceof HTMLElement && event.target.matches('form')){
66
+
67
+ let form = event.target;
68
+
69
+ if(form.querySelector(':invalid')){
70
+
71
+ form.classList.add('was-validated');
72
+ event.preventDefault();
73
+ }
74
+ }
75
+
76
+ });
77
+
63
78
  return null
64
79
  }
65
80
 
@@ -18,21 +18,18 @@ const createPaginationButttons = function(controller: any,pagination: any){
18
18
  return false;
19
19
  }
20
20
 
21
- let strButtons = '';
21
+ let strOptions = '';
22
22
 
23
23
  for (let i = 1; i <= numberPages; i++) {
24
24
 
25
- if(i == currentPage)
26
- strButtons += `<li class="page-item active" aria-current="page"><span class="page-link">${i}</span></li>`;
27
- else
28
- strButtons += `<li class="page-item"><a href="?page=${i}" class="page-link" data-page="${i}">${i}</a></li>`;
25
+ strOptions += `<option value="${i}" ${i == currentPage ? 'selected' : ''}>${i}</option>`;
29
26
  }
30
27
 
31
- pagination.innerHTML = `<ul class="pagination mb-0 d-none d-sm-flex">
32
- ${currentPage == 1 ? `<li class="page-item disabled"><span class="page-link">Previous</span></li>` : `<li class="page-item"><a href="?page=${parseInt(currentPage)-1}" class="page-link" data-page="${parseInt(currentPage)-1}">Previous</a></li>`}
33
- ${strButtons}
34
- ${currentPage == numberPages ? `<li class="page-item disabled"><span class="page-link">Next</span></li>` : `<li class="page-item"><a href="?page=${parseInt(currentPage)+1}" class="page-link" data-page="${parseInt(currentPage)+1}">Next</a></li>`}
35
- </ul>`;
28
+ pagination.innerHTML = `<div class="pagination mb-0 d-none d-sm-flex">
29
+ <div><select>${strOptions}</select></div>
30
+ <button class="prev" ${currentPage == 1 ?'disabled':''} data-page="${parseInt(currentPage)-1}">Previous</button>
31
+ <button class="next" ${currentPage == numberPages ?'disabled':''} data-page="${parseInt(currentPage)+1}">Next</button>
32
+ </div>`;
36
33
  pagination.innerHTML += `<div class="d-sm-none text-center">
37
34
  <span class="d-block pb-2">You've viewed ${showRows} of ${numberRows} results</span>
38
35
  <a href="?show=${parseInt(showRows)+parseInt(addRows)}" class="btn btn-primary w-100 m-0" data-show="${parseInt(showRows)+parseInt(addRows)}">Load more results</a>
@@ -1,6 +1,5 @@
1
1
  // @ts-nocheck
2
2
  import { zeroPad, isNumeric, ucfirst } from "./helpers";
3
- import createPaginationButttons from "./pagination";
4
3
 
5
4
  // Basic functionality needed
6
5
  export const addDataAttributes = (table) => {
@@ -60,44 +59,50 @@ export const getLargestLastColWidth = (table) => {
60
59
  return largestWidth;
61
60
  }
62
61
 
63
- export const createMobileButton = (table) => {
62
+ export const createMobileButton = (table, wrapper) => {
64
63
 
65
- if(table.closest('.table--fullwidth'))
64
+
65
+ if(wrapper.classList.contains('.table--fullwidth') && !wrapper.hasAttribute('data-expandable'))
66
66
  return false;
67
67
 
68
- if(table.querySelectorAll('thead tr th').length < 4)
68
+ if(table.querySelectorAll('thead tr th').length < 4 && !wrapper.hasAttribute('data-expandable'))
69
69
  return false;
70
70
 
71
- Array.from(table.querySelectorAll('tbody tr')).forEach((row, index) => {
72
- let firstCol = row.querySelector(':scope > :is(td,th):first-child');
73
71
 
74
- let colContent = firstCol.textContent;
72
+ Array.from(table.querySelectorAll('thead tr')).forEach((row,index) => {
73
+
74
+ row.insertAdjacentHTML(
75
+ 'afterbegin',
76
+ `<th class="th--fixed expand-button-heading"></th>`
77
+ );
78
+ });
75
79
 
76
- if(colContent != "")
77
- firstCol.innerHTML =`<span class="td__content">${colContent}</span><button type="button" class="d-none">${colContent}</button>`;
78
- else {
79
- let secondCol = row.querySelector(':scope > :is(td,th):nth-child(2)');
80
- let secondColContent = secondCol.textContent;
81
- secondCol.innerHTML =`<span class="td__content">${secondColContent}</span><button type="button" class="d-none">${secondColContent}</button>`;
82
- }
80
+ Array.from(table.querySelectorAll('tbody tr')).forEach((row,index) => {
81
+
82
+ row.insertAdjacentHTML(
83
+ 'afterbegin',
84
+ `<td class="td--fixed td--expand"><button class="btn btn-compact btn-secondary" data-expand-button>Expand</button></td>`
85
+ );
83
86
  });
87
+
88
+
84
89
  }
85
90
 
86
91
  export const addTableEventListeners = (table) => {
87
92
 
88
93
  table.addEventListener('click', (event) => {
89
94
 
90
- if (event && event.target instanceof HTMLElement && event.target.closest('tr > :is(td,th):first-child button')){
95
+ if (event && event.target instanceof HTMLElement && event.target.closest('[data-expand-button]')){
91
96
 
92
- let firstCol = event.target.closest('tr > :is(td,th):first-child button');
93
- let tableRow = firstCol.parentNode.closest('tr');
97
+ let button = event.target.closest('[data-expand-button]');
98
+ let tableRow = button.closest('tr');
94
99
 
95
100
  if(tableRow.getAttribute('data-view') == "full")
96
101
  tableRow.setAttribute('data-view','default');
97
102
  else
98
103
  tableRow.setAttribute('data-view','full');
99
104
 
100
- firstCol.blur();
105
+ button.blur();
101
106
  };
102
107
  });
103
108
  }
@@ -185,7 +190,6 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
185
190
  form.submit();
186
191
  else {
187
192
  filterTable(table, form, wrapper);
188
- createPaginationButttons(wrapper,pagination);
189
193
  populateDataQueries(table,form);
190
194
  }
191
195
 
@@ -232,7 +236,6 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
232
236
  if (event && event.target instanceof HTMLElement && event.target.closest('[data-filter][data-no-ajax]')){ // Allow for input fields to filter the current results without a new ajax call
233
237
 
234
238
  filterTable(table, form, wrapper);
235
- createPaginationButttons(wrapper,pagination);
236
239
  populateDataQueries(table,form);
237
240
  }
238
241
  else if (event && event.target instanceof HTMLElement && event.target.closest('[data-filter]') && event.target.closest('form .dialog__wrapper > dialog')){
@@ -276,7 +279,7 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
276
279
  }
277
280
 
278
281
  if (event && event.target instanceof HTMLElement && event.target.closest('[data-clear]')){
279
-
282
+
280
283
  form.classList.add('processing');
281
284
  // Make sure any applied filters have been removed
282
285
  Array.from(form.querySelectorAll('.applied-filters')).forEach((filters,index) => {
@@ -300,7 +303,17 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
300
303
  case "checkbox":
301
304
  if (frm_elements[i].checked)
302
305
  {
303
- frm_elements[i].checked = false;
306
+ let input = frm_elements[i];
307
+ let id = input.getAttribute('id');
308
+ let label = document.querySelector(`[for="${id}"`);
309
+
310
+ if(label.querySelector('iam-card')){
311
+ let card = label.querySelector('iam-card');
312
+ let clickEvent = new Event('click');
313
+ card.dispatchEvent(clickEvent);
314
+ }
315
+
316
+ input.checked = false;
304
317
  }
305
318
  break;
306
319
  case "select-one":
@@ -313,11 +326,6 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
313
326
  }
314
327
  }
315
328
 
316
- Array.from(form.querySelectorAll('label iam-card')).forEach((card,index) => {
317
- let clickEvent = new Event('click');
318
- card.dispatchEvent(clickEvent);
319
- });
320
-
321
329
  form.classList.remove('processing');
322
330
 
323
331
  if(!form.hasAttribute('data-submit'))
@@ -666,10 +674,9 @@ export const filterTable = (table, form, wrapper) => {
666
674
  });
667
675
 
668
676
  if(wrapper){
669
- wrapper.setAttribute('data-page',page);
670
- wrapper.setAttribute('data-pages',Math.ceil(matched/showRows));
671
677
  wrapper.setAttribute('data-total',matched);
672
678
  wrapper.setAttribute('data-show',showRows);
679
+ wrapper.setAttribute('data-page',page);
673
680
  }
674
681
 
675
682
  }
@@ -742,40 +749,40 @@ export const populateDataQueries = (table,form,wrapper) => {
742
749
  // Pagination
743
750
  export const addPaginationEventListeners = function(table, form, pagination, wrapper){
744
751
 
745
- pagination.addEventListener('click', (event) => {
752
+ pagination.addEventListener('update-page', (event) => {
746
753
 
747
- if (event && event.target instanceof HTMLElement && event.target.closest('[data-page]')){
748
-
749
- event.preventDefault();
754
+ let paginationInput = form.querySelector('[data-pagination]');
755
+ let newPage = event.detail.page;
750
756
 
751
- let paginationInput = form.querySelector('[data-pagination]');
752
- let newPage = event.target.closest('[data-page]').getAttribute('data-page');
753
- paginationInput.value = newPage;
754
- wrapper.setAttribute('data-page', newPage);
755
- form.dispatchEvent(new Event("paginate"));
757
+ // Set the filter value
758
+ paginationInput.value = newPage;
759
+ form.dispatchEvent(new Event("paginate"));
756
760
 
757
- if(table.hasAttribute('data-show-history')){
758
-
759
- const url = new URL(location);
760
- url.searchParams.set("page", newPage);
761
- history.pushState({'type':'pagination','form':form.getAttribute('id'),'page':newPage}, "", url)
762
- }
761
+ // Reset the data attribute
762
+ wrapper.setAttribute('data-page',newPage);
763
+
764
+ if(table.hasAttribute('data-show-history')){
765
+
766
+ const url = new URL(location);
767
+ url.searchParams.set("page", newPage);
768
+ history.pushState({'type':'pagination','form':form.getAttribute('id'),'page':newPage}, "", url)
769
+ }
763
770
 
764
- // scroll back to the top of the table
771
+ // scroll back to the top of the table
772
+ if(!wrapper.hasAttribute('data-no-scroll')){
765
773
  const yOffset = -250;
766
774
  const y = table.getBoundingClientRect().top + window.pageYOffset + yOffset;
767
775
  window.scrollTo({top: y, behavior: 'smooth'});
768
776
  }
777
+ });
769
778
 
770
- if (event && event.target instanceof HTMLElement && event.target.closest('[data-show]')){
779
+ pagination.addEventListener('update-show', (event) => {
771
780
 
772
- event.preventDefault();
773
- let showInput = form.querySelector('[data-show]');
774
- let showRows = event.target.closest('[data-show]').getAttribute('data-show');
775
- showInput.value = showRows;
776
- wrapper.setAttribute('data-show', showRows);
777
- form.dispatchEvent(new Event("submit"));
778
- }
781
+ let showInput = form.querySelector('[data-show]');
782
+ let showRows = event.detail.show;
783
+ showInput.value = showRows;
784
+ wrapper.setAttribute('data-show', showRows);
785
+ form.dispatchEvent(new Event("submit"));
779
786
  });
780
787
  }
781
788
 
@@ -839,7 +846,7 @@ export const exportAsCSV = function(table){
839
846
  export const makeTableFunctional = function(table, form, pagination, wrapper){
840
847
 
841
848
  addDataAttributes(table);
842
- createMobileButton(table);
849
+ createMobileButton(table, wrapper);
843
850
  populateDataQueries(table, form, wrapper);
844
851
 
845
852
  // Work out the largest width of the CTA's in the last column
@@ -941,6 +948,10 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper){
941
948
  window.controller[ajaxURL] = new AbortController();
942
949
  const { signal } = controller[ajaxURL];
943
950
 
951
+ // Set loading on the pagination
952
+ pagination.setAttribute('data-loading','true');
953
+ form.classList.add('processing');
954
+
944
955
  try {
945
956
  await fetch(ajaxURL+'?'+queryString, {
946
957
  signal: signal,
@@ -958,7 +969,7 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper){
958
969
  let totalNumberSchema = form.hasAttribute('data-schema-total') ? form.getAttribute('data-schema-total') : 'meta.total';
959
970
  let currentPageSchema = form.hasAttribute('data-schema-page') ? form.getAttribute('data-schema-page') : 'meta.current_page';
960
971
 
961
- let totalNumber = resolvePath(response, totalNumberSchema, 1);
972
+ let totalNumber = resolvePath(response, totalNumberSchema, 15);
962
973
  let currentPage = resolvePath(response, currentPageSchema, 1);
963
974
  let data = resolvePath(response, schema);
964
975
  let emptyMsg = wrapper.hasAttribute('data-empty-msg') ? wrapper.getAttribute('data-empty-msg') : "No results found";
@@ -1032,11 +1043,9 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper){
1032
1043
  // Add data to the pagination
1033
1044
  wrapper.setAttribute('data-total', parseInt(totalNumber));
1034
1045
  wrapper.setAttribute('data-page', parseInt(currentPage));
1035
- wrapper.setAttribute('data-pages', Math.ceil(wrapper.getAttribute('data-total') / wrapper.getAttribute('data-show')));
1036
1046
 
1037
1047
 
1038
1048
  makeTableFunctional(table, form, pagination, wrapper);
1039
- createPaginationButttons(wrapper, pagination);
1040
1049
 
1041
1050
  Array.from(form.querySelectorAll('[data-ajax-query]')).forEach((queryElement, index) => {
1042
1051
 
@@ -1064,6 +1073,10 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper){
1064
1073
  else {
1065
1074
  tbody.innerHTML = '<tr><td colspan="100%"><span>Error loading table</span></td></tr>';
1066
1075
  }
1076
+
1077
+ // Remove loading on the pagination
1078
+ pagination.removeAttribute('data-loading');
1079
+ form.classList.remove('processing');
1067
1080
  });
1068
1081
  } catch (error) {
1069
1082
  console.log(error);
@@ -12,23 +12,29 @@ export const createTabsLinks = function(tabsElement: Element) {
12
12
  tabLinks = document.createElement('div');
13
13
  tabLinks.classList.add('tabs__links');
14
14
 
15
- tabsElement.prepend(tabLinks);
15
+ let tabLinksWrapper = document.createElement('div');
16
+ tabLinksWrapper.classList.add('tabs__links__wrapper');
17
+
18
+ tabLinksWrapper.prepend(tabLinks);
19
+ tabsElement.prepend(tabLinksWrapper);
16
20
  }
17
21
 
18
22
  // Create the tab buttons from the summary titles
19
23
  details.forEach((detail, index) => {
20
24
 
21
25
  let summary = detail.querySelector(':scope > summary');
26
+ let isDisabled = summary.classList.contains('disabled')
27
+
22
28
  summary.classList.add('visually-hidden');
23
29
 
24
30
  let button = document.createElement('button');
25
- if(detail.hasAttribute('id')){
26
-
31
+
32
+ if (detail.hasAttribute('id')) {
27
33
  button = document.createElement('a');
28
34
  button.setAttribute('href',`#${detail.getAttribute('id')}`);
29
35
  }
30
36
 
31
- if(detail.hasAttribute('open')){
37
+ if (detail.hasAttribute('open')) {
32
38
  button.setAttribute('aria-pressed',true);
33
39
  }
34
40
 
@@ -37,6 +43,10 @@ export const createTabsLinks = function(tabsElement: Element) {
37
43
  button.setAttribute('data-index',index);
38
44
  button.setAttribute('tabindex','-1');
39
45
 
46
+ if (isDisabled) {
47
+ button.classList.add('disabled')
48
+ }
49
+
40
50
  tabLinks.appendChild(button);
41
51
  });
42
52
 
@@ -55,15 +65,17 @@ export const setTabsEventHandlers = function(tabsElement: Element){
55
65
  buttons.forEach((button) => {
56
66
 
57
67
  button.addEventListener("click", (e) => {
58
-
59
68
  e.preventDefault();
60
- buttons.forEach((buttonLoopItem) => {
61
69
 
70
+ if (button.classList.contains('disabled'))
71
+ return false
72
+
73
+ buttons.forEach((buttonLoopItem) => {
62
74
  let buttonPressed = buttonLoopItem == button ? true : false;
63
75
  buttonLoopItem.setAttribute('aria-pressed', buttonPressed);
64
76
  });
77
+
65
78
  details.forEach((detail, detailsIndex) => {
66
-
67
79
  let detailsOpen = button.getAttribute('data-index') == detailsIndex ? true : false;
68
80
 
69
81
  if(detailsOpen)
@@ -90,15 +102,15 @@ export const setTabsEventHandlers = function(tabsElement: Element){
90
102
 
91
103
  // Maintain the focus on the summary element but visually highlight the tab button
92
104
  summary.addEventListener("focus", (e) => {
93
-
94
105
  buttons.forEach((button) => {
95
106
 
96
107
  button.classList.remove('focus');
97
108
  });
109
+
98
110
  buttons[index].classList.add('focus');
99
111
  });
100
- summary.addEventListener("click", (e) => {
101
112
 
113
+ summary.addEventListener("click", (e) => {
102
114
  e.preventDefault();
103
115
  buttons[index].click();
104
116
  });
@@ -128,7 +140,6 @@ export const openFirstTab = function(tabsElement: Element){
128
140
  }
129
141
 
130
142
  const tabs = function(tabsElement: Element){
131
-
132
143
  createTabsLinks(tabsElement);
133
144
  setTabsEventHandlers(tabsElement);
134
145
  openFirstTab(tabsElement);
@@ -69,50 +69,6 @@ describe('addDataAttributes', () => {
69
69
 
70
70
  });
71
71
 
72
- /* TODO: This unit test doesn't work as puppeteer seems to have an issue with query selector all
73
- describe('getLargestLastColWidth', () => {
74
-
75
- test('should return the width of the largest last column content', async() => {
76
-
77
- const browser = await puppeteer.launch({});
78
- try {
79
- const page = await browser.newPage();
80
- await page.exposeFunction("getLargestLastColWidth", tableModule.getLargestLastColWidth);
81
- await page.setContent(`<table id="table">${basicTable}</table>`);
82
- await page.waitForSelector('#table tr');
83
-
84
- const largestWidth = await page.evaluate(`getLargestLastColWidth(document.querySelector("#table"))`);
85
-
86
- //const links = await page.$$eval('#table', e=>getLargestLastColWidth(e))
87
- console.log(await largestWidth)
88
-
89
-
90
- } catch (e) {
91
- console.error(e);
92
- } finally {
93
- await browser.close();
94
- }
95
-
96
-
97
- });
98
-
99
- });
100
- */
101
-
102
- describe('createMobileButton', () => {
103
-
104
- const table = document.createElement('table');
105
- table.innerHTML = basicTable;
106
-
107
- tableModule.createMobileButton(table);
108
-
109
- test('should add a button to the first cell in a column', () => {
110
-
111
- expect(table.querySelector('tbody td:nth-child(1) button').textContent).toEqual('Cell 1');
112
- expect(table.querySelector('tbody td:nth-child(1) span').textContent).toEqual('Cell 1');
113
- });
114
- });
115
-
116
72
  describe('createSearchDataList', () => {
117
73
 
118
74
  const table = document.createElement('table');
@@ -162,6 +118,7 @@ describe('sortTable', () => {
162
118
 
163
119
  });
164
120
 
121
+
165
122
  describe('filterTable', () => {
166
123
 
167
124
  const table = document.createElement('table');
@@ -177,25 +134,8 @@ describe('filterTable', () => {
177
134
  expect(table.querySelectorAll('tbody tr.filtered--matched').length).toEqual(1);
178
135
  });
179
136
  });
180
- /*
181
- describe('populateDataQueries', () => {
182
137
 
183
- const table = document.createElement('table');
184
- table.innerHTML = basicTable;
185
- const form = document.createElement('form');
186
- form.innerHTML += `<div><input name="heading" value="Low" data-filter="Heading 2" /><span data-query="total"></span><span data-query="Heading 2 == Low"></span></div>`;
187
-
188
- tableModule.addDataAttributes(table);
189
- tableModule.filterTable(table, form, document.createElement('div'));
190
- tableModule.populateDataQueries(table, form);
191
138
 
192
- test('should populate elements with the data-query attribute with the result of the corresponding query', () => {
193
-
194
- //expect(form.querySelector('[data-query="total"]').textContent).toEqual('4');
195
- //expect(form.querySelector('[data-query="Heading 2 == Low"]').textContent).toEqual('2');
196
- });
197
- });
198
- */
199
139
  describe('formatCell', () => {
200
140
 
201
141
  test('should format the text correctly', () => {