@iamproperty/components 3.7.0 → 3.7.2

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 (34) hide show
  1. package/assets/css/components/table.css +1 -1
  2. package/assets/css/components/table.css.map +1 -1
  3. package/assets/css/core.min.css +1 -1
  4. package/assets/css/core.min.css.map +1 -1
  5. package/assets/css/style.min.css +1 -1
  6. package/assets/css/style.min.css.map +1 -1
  7. package/assets/js/components/accordion/accordion.component.min.js +1 -1
  8. package/assets/js/components/card/card.component.min.js +1 -1
  9. package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
  10. package/assets/js/components/header/header.component.min.js +1 -1
  11. package/assets/js/components/table/table.component.js +8 -1
  12. package/assets/js/components/table/table.component.min.js +13 -13
  13. package/assets/js/components/table/table.component.min.js.map +1 -1
  14. package/assets/js/components/tabs/tabs.component.min.js +1 -1
  15. package/assets/js/dynamic.min.js +2 -2
  16. package/assets/js/dynamic.min.js.map +1 -1
  17. package/assets/js/modules/applied-filters.js +1 -1
  18. package/assets/js/modules/dialogs.js +12 -1
  19. package/assets/js/modules/table.js +202 -65
  20. package/assets/js/scripts.bundle.js +21 -21
  21. package/assets/js/scripts.bundle.js.map +1 -1
  22. package/assets/js/scripts.bundle.min.js +2 -2
  23. package/assets/js/scripts.bundle.min.js.map +1 -1
  24. package/assets/js/tests/table.spec.js +19 -13
  25. package/assets/sass/components/table.scss +125 -75
  26. package/assets/sass/foundations/reboot.scss +7 -3
  27. package/assets/ts/components/table/table.component.ts +12 -1
  28. package/assets/ts/modules/applied-filters.ts +1 -1
  29. package/assets/ts/modules/dialogs.ts +16 -5
  30. package/assets/ts/modules/table.ts +244 -69
  31. package/assets/ts/tests/table.spec.ts +6 -6
  32. package/dist/components.es.js +904 -839
  33. package/dist/components.umd.js +21 -21
  34. package/package.json +1 -1
@@ -1,3 +1,12 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  // @ts-nocheck
2
11
  import { zeroPad, isNumeric, ucfirst } from "./helpers.js";
3
12
  import createPaginationButttons from "./pagination.js";
@@ -7,7 +16,7 @@ export const addDataAttributes = (table) => {
7
16
  const colRows = Array.from(table.querySelectorAll('tbody tr'));
8
17
  colRows.forEach((row, index) => {
9
18
  const cells = Array.from(row.querySelectorAll('th, td'));
10
- const statuses = ['Low', 'Medium', 'High', 'N/A', 'Pending', 'Verified', 'Incomplete', 'Completed', 'Requires approval'];
19
+ const statuses = ['0', 'low', 'medium', 'high', 'unknown', 'n/a', 'pending', 'verified', 'incomplete', 'completed', 'requires approval'];
11
20
  cells.forEach((cell, cellIndex) => {
12
21
  const heading = colHeadings[cellIndex];
13
22
  if (typeof heading != "undefined") {
@@ -19,10 +28,10 @@ export const addDataAttributes = (table) => {
19
28
  cell.setAttribute('class', heading.getAttribute('data-td-class'));
20
29
  if (heading.hasAttribute('data-format')) {
21
30
  cell.setAttribute('data-format', heading.getAttribute('data-format'));
22
- cell.innerHTML = formatCell('date', cell.textContent.trim()); //Make sure date format is consistent
31
+ cell.innerHTML = formatCell(heading.getAttribute('data-format'), cell.textContent.trim()); //Make sure date format is consistent
23
32
  }
24
- if (statuses.includes(cell.textContent.trim())) {
25
- cell.setAttribute('data-content', cell.textContent.trim());
33
+ if (statuses.includes(cell.textContent.trim().toLowerCase())) {
34
+ cell.setAttribute('data-content', cell.textContent.trim().toLowerCase());
26
35
  }
27
36
  }
28
37
  });
@@ -100,9 +109,16 @@ export const createSearchDataList = (table, form) => {
100
109
  export const addFilterEventListeners = (table, form, pagination, wrapper, savedTableBody) => {
101
110
  var timer;
102
111
  // Check what conditions are set on the table to see what the form actions are
103
- let formSubmit = function () {
104
- if (form.hasAttribute('data-ajax'))
112
+ let formSubmit = function (paginate = false) {
113
+ if (form.hasAttribute('data-ajax')) {
114
+ // Default back to page 1
115
+ if (!paginate) {
116
+ let paginationInput = form.querySelector('[data-pagination]');
117
+ paginationInput.value = 1;
118
+ wrapper.setAttribute('data-page', 1);
119
+ }
105
120
  loadAjaxTable(table, form, pagination, wrapper);
121
+ }
106
122
  else if (form.hasAttribute('data-submit'))
107
123
  form.submit();
108
124
  else {
@@ -139,6 +155,9 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
139
155
  if (event && event.target instanceof HTMLElement && event.target.closest('[data-show]')) {
140
156
  formSubmit();
141
157
  }
158
+ if (event && event.target instanceof HTMLElement && event.target.closest('[data-mimic]')) {
159
+ formSubmit();
160
+ }
142
161
  });
143
162
  form.addEventListener('click', (event) => {
144
163
  clearTimeout(timer);
@@ -168,6 +187,58 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
168
187
  form.addEventListener('force', (event) => {
169
188
  formSubmit();
170
189
  });
190
+ form.addEventListener('paginate', (event) => {
191
+ formSubmit(true);
192
+ });
193
+ // Mmimic fields
194
+ let forms = [];
195
+ let fields = [];
196
+ // Collect the forms that we need to add an event listener for.
197
+ Array.from(form.querySelectorAll('[data-mimic]')).forEach((input, index) => {
198
+ let mimicField = input.getAttribute('data-mimic');
199
+ Array.from(document.querySelectorAll(`[name="${mimicField}"]`)).forEach((mimicInput, index) => {
200
+ let parentForm = mimicInput.closest('form');
201
+ if (!forms.includes(parentForm))
202
+ forms.push(parentForm);
203
+ if (!fields.includes(mimicField))
204
+ fields.push(mimicField);
205
+ });
206
+ });
207
+ // For each form add change listener
208
+ forms.forEach((parentForm, index) => {
209
+ const updateMimicInput = function () {
210
+ let mimickedAlready = [];
211
+ let formData = new FormData(parentForm);
212
+ let i = 1;
213
+ for (const [key, value] of formData) {
214
+ if (document.querySelector(`[data-mimic="${key}"]`) && !mimickedAlready.includes(key)) {
215
+ mimickedAlready.push(key);
216
+ document.querySelector(`[data-mimic="${key}"]`).value = value;
217
+ }
218
+ else if (document.querySelector(`[data-mimic="${key}"]`))
219
+ document.querySelector(`[data-mimic="${key}"]`).value += "," + value;
220
+ i++;
221
+ }
222
+ for (const value of mimickedAlready) {
223
+ const event = new Event("force");
224
+ form.dispatchEvent(event);
225
+ }
226
+ // Check for empties
227
+ for (const field of fields) {
228
+ if (!formData.has(field) && parentForm.querySelector(`[name="${field}"]`)) {
229
+ document.querySelector(`[data-mimic="${field}"]`).value = "";
230
+ const event = new Event("force");
231
+ form.dispatchEvent(event);
232
+ }
233
+ }
234
+ };
235
+ parentForm.addEventListener('force', (event) => {
236
+ updateMimicInput();
237
+ });
238
+ parentForm.addEventListener('change', (event) => {
239
+ updateMimicInput();
240
+ });
241
+ });
171
242
  };
172
243
  export const sortTable = (table, form, savedTableBody) => {
173
244
  if (form.getAttribute('data-ajax')) {
@@ -248,10 +319,11 @@ export const filterTable = (table, form, wrapper) => {
248
319
  filters[filterInput.getAttribute('data-filter')].push(value);
249
320
  }
250
321
  }
251
- else if (filterInput.value) {
252
- if (!filters[filterInput.getAttribute('data-filter')])
253
- filters[filterInput.getAttribute('data-filter')] = new Array();
254
- filters[filterInput.getAttribute('data-filter')].push(filterInput.value);
322
+ else if (filterInput && filterInput.value) {
323
+ let dataFilter = filterInput.getAttribute('data-filter');
324
+ if (!filters[dataFilter])
325
+ filters[dataFilter] = new Array();
326
+ filters[dataFilter].push(filterInput.value);
255
327
  }
256
328
  });
257
329
  // Add search columns too
@@ -364,13 +436,16 @@ export const filterTable = (table, form, wrapper) => {
364
436
  wrapper.setAttribute('data-show', showRows);
365
437
  }
366
438
  };
367
- export const populateDataQueries = (table, form) => {
439
+ export const populateDataQueries = (table, form, wrapper) => {
368
440
  const dataQueries = Array.from(form.querySelectorAll('[data-query]'));
369
441
  dataQueries.forEach((queryElement, index) => {
370
442
  let query = queryElement.getAttribute('data-query');
371
443
  let numberOfMatchedRows;
372
444
  if (query == 'total') {
373
- numberOfMatchedRows = table.classList.contains('table--filtered') ? table.querySelectorAll('tbody tr').length : table.querySelectorAll('tbody tr').length;
445
+ if (wrapper.hasAttribute('data-total'))
446
+ numberOfMatchedRows = wrapper.getAttribute('data-total');
447
+ else
448
+ numberOfMatchedRows = table.classList.contains('table--filtered') ? table.querySelectorAll('tbody tr').length : table.querySelectorAll('tbody tr').length;
374
449
  }
375
450
  else if (!query.includes(' == ') && query.includes(' & ')) {
376
451
  let queries = query.split(' & ');
@@ -416,7 +491,7 @@ export const addPaginationEventListeners = function (table, form, pagination, wr
416
491
  let newPage = event.target.closest('[data-page]').getAttribute('data-page');
417
492
  paginationInput.value = newPage;
418
493
  wrapper.setAttribute('data-page', newPage);
419
- form.dispatchEvent(new Event("submit"));
494
+ form.dispatchEvent(new Event("paginate"));
420
495
  if (table.hasAttribute('data-show-history')) {
421
496
  const url = new URL(location);
422
497
  url.searchParams.set("page", newPage);
@@ -477,9 +552,9 @@ export const exportAsCSV = function (table) {
477
552
  };
478
553
  // After table is loaded
479
554
  export const makeTableFunctional = function (table, form, pagination, wrapper) {
480
- createMobileButton(table);
481
555
  addDataAttributes(table);
482
- populateDataQueries(table, form);
556
+ createMobileButton(table);
557
+ populateDataQueries(table, form, wrapper);
483
558
  // Work out the largest width of the CTA's in the last column
484
559
  if (wrapper && wrapper.classList.contains('table--cta')) {
485
560
  const largestWidth = getLargestLastColWidth(table);
@@ -487,65 +562,127 @@ export const makeTableFunctional = function (table, form, pagination, wrapper) {
487
562
  }
488
563
  };
489
564
  export const loadAjaxTable = function (table, form, pagination, wrapper) {
490
- const resolvePath = (object, path, defaultValue) => path.split(/[\.\[\]\'\"]/).filter(p => p).reduce((o, p) => o ? o[p] : defaultValue, object);
491
- let queryString = new URLSearchParams(new FormData(form)).toString();
492
- let columns = table.querySelectorAll('thead tr th');
493
- let tbody = table.querySelector('tbody');
494
- fetch(form.getAttribute('data-ajax'), {
495
- method: 'get',
496
- credentials: 'same-origin',
497
- headers: new Headers({
498
- 'Content-Type': 'application/json',
499
- Accept: 'application/json',
500
- 'X-Requested-With': 'XMLHttpRequest'
501
- })
502
- }).then((response) => response.json()).then((response) => {
503
- if (response.data) {
504
- tbody.innerHTML = '';
505
- response.data.forEach((row, index) => {
506
- var table_row = document.createElement('tr');
507
- columns.forEach((col, index) => {
508
- let cellOutput = '';
509
- var table_cell = document.createElement('td');
510
- // Add some data to help with the mobile layout design
511
- table_cell.setAttribute('data-label', col.innerText);
512
- if (col.getAttribute('data-output')) {
513
- var cellTemplate = col.getAttribute('data-output');
514
- // Use a regex to replace {var} with actual values from the json data
515
- cellOutput = cellTemplate.replace(new RegExp(/{(.*?)}/, "gm"), function (matched) { return resolvePath(row, matched.replace('{', '').replace('}', '')); });
565
+ return __awaiter(this, void 0, void 0, function* () {
566
+ const resolvePath = (object, path, defaultValue) => path.split(/[\.\[\]\'\"]/).filter(p => p).reduce((o, p) => o ? o[p] : defaultValue, object);
567
+ let formData = new FormData(form);
568
+ let queryString = new URLSearchParams(formData).toString();
569
+ let columns = table.querySelectorAll('thead tr th');
570
+ let tbody = table.querySelector('tbody');
571
+ let ajaxURL = form.getAttribute('data-ajax');
572
+ wrapper.classList.add('table--loading');
573
+ // Setup controller vars if not already set
574
+ if (!window.controller)
575
+ window.controller = [];
576
+ // Abort if controller already present for this url
577
+ if (window.controller[ajaxURL])
578
+ window.controller[ajaxURL].abort();
579
+ // Create a new controller so it can be aborted if new fetch made
580
+ window.controller[ajaxURL] = new AbortController();
581
+ const { signal } = controller[ajaxURL];
582
+ try {
583
+ yield fetch(ajaxURL + '?' + queryString, {
584
+ signal: signal,
585
+ method: 'get',
586
+ credentials: 'same-origin',
587
+ headers: new Headers({
588
+ 'Content-Type': 'application/json',
589
+ Accept: 'application/json',
590
+ 'X-Requested-With': 'XMLHttpRequest'
591
+ })
592
+ })
593
+ .then((response) => response.json()).then((response) => {
594
+ let schema = form.hasAttribute('data-schema') ? form.getAttribute('data-schema') : 'data';
595
+ let totalNumberSchema = form.hasAttribute('data-schema-total') ? form.getAttribute('data-schema-total') : 'meta.total';
596
+ let currentPageSchema = form.hasAttribute('data-schema-page') ? form.getAttribute('data-schema-page') : 'meta.current_page';
597
+ let totalNumber = resolvePath(response, totalNumberSchema, 1);
598
+ let currentPage = resolvePath(response, currentPageSchema, 1);
599
+ let data = resolvePath(response, schema);
600
+ let emptyMsg = wrapper.hasAttribute('data-empty-msg') ? wrapper.getAttribute('data-empty-msg') : "No results found";
601
+ if (data) {
602
+ tbody.innerHTML = '';
603
+ data.forEach((row, index) => {
604
+ var table_row = document.createElement('tr');
605
+ columns.forEach((col, index) => {
606
+ let cellOutput = '';
607
+ var table_cell = document.createElement('td');
608
+ // Add some data to help with the mobile layout design
609
+ table_cell.setAttribute('data-label', col.innerText);
610
+ if (col.getAttribute('data-output')) {
611
+ var cellTemplate = col.getAttribute('data-output');
612
+ // Use a regex to replace {var} with actual values from the json data
613
+ cellOutput = cellTemplate.replace(new RegExp(/{(.*?)}/, "gm"), function (matched) { return resolvePath(row, matched.replace('{', '').replace('}', '')); });
614
+ }
615
+ // If an output array is defined then the content is going to made of of multiple values from an array
616
+ if (col.hasAttribute('data-output-array')) {
617
+ var cellTemplate = col.getAttribute('data-output');
618
+ let arrValue = resolvePath(row, cellTemplate.replace('{', '').replace('}', ''));
619
+ cellOutput = "";
620
+ arrValue.forEach((rowValue, i) => {
621
+ let cellTemplateValue = col.getAttribute('data-output-array');
622
+ let cellOutputValue = "";
623
+ // If we need to transform some of the data
624
+ if (col.hasAttribute('data-output-array-property') && col.hasAttribute('data-output-array-transform')) {
625
+ const propertyValue = resolvePath(rowValue, col.getAttribute('data-output-array-property'));
626
+ const transforms = JSON.parse(col.getAttribute('data-output-array-transform'));
627
+ const transformValue = transforms[propertyValue];
628
+ cellOutputValue = cellTemplateValue.replace(`{${col.getAttribute('data-output-array-property')}}`, transformValue);
629
+ }
630
+ cellOutputValue = cellOutputValue.replace(new RegExp(/{(.*?)}/, "gm"), function (matched) { return resolvePath(rowValue, matched.replace('{', '').replace('}', '')); });
631
+ cellOutput += cellOutputValue;
632
+ });
633
+ }
634
+ if (col.hasAttribute('data-transform')) {
635
+ const transforms = JSON.parse(col.getAttribute('data-transform'));
636
+ cellOutput = transforms[cellOutput];
637
+ if (!cellOutput && col.hasAttribute('data-default'))
638
+ cellOutput = col.getAttribute('data-default');
639
+ }
640
+ table_cell.innerHTML = cellOutput;
641
+ table_row.appendChild(table_cell);
642
+ });
643
+ tbody.appendChild(table_row);
644
+ });
645
+ createSearchDataList(table, form);
646
+ // Add data to the pagination
647
+ wrapper.setAttribute('data-total', parseInt(totalNumber));
648
+ wrapper.setAttribute('data-page', parseInt(currentPage));
649
+ wrapper.setAttribute('data-pages', Math.ceil(wrapper.getAttribute('data-total') / wrapper.getAttribute('data-show')));
650
+ makeTableFunctional(table, form, pagination, wrapper);
651
+ createPaginationButttons(wrapper, pagination);
652
+ if (parseInt(totalNumber) == 0) {
653
+ tbody.innerHTML = `<tr><td colspan="100%"><span>${emptyMsg}</span></td></tr>`;
516
654
  }
517
- if (col.hasAttribute('data-format')) {
518
- cellOutput = formatCell(col.getAttribute('data-format'), cellOutput);
519
- }
520
- table_cell.innerHTML = cellOutput;
521
- table_row.appendChild(table_cell);
522
- });
523
- tbody.appendChild(table_row);
655
+ wrapper.classList.remove('table--loading');
656
+ window.dataLayer = window.dataLayer || [];
657
+ window.dataLayer.push({
658
+ "event": "Ajax table loaded",
659
+ "url": ajaxURL,
660
+ "formData": queryString
661
+ });
662
+ }
663
+ else {
664
+ tbody.innerHTML = '<tr><td colspan="100%"><span>Error loading table</span></td></tr>';
665
+ }
666
+ // Pass post data back to the page
667
+ if (form.hasAttribute('data-ajax-post')) {
668
+ const http = new XMLHttpRequest();
669
+ http.open('GET', `${window.location.href}?ajax=true&${queryString}`);
670
+ http.send();
671
+ }
524
672
  });
525
- createSearchDataList(table, form);
526
- // Add data to the pagination
527
- makeTableFunctional(table, form, pagination, wrapper);
528
- wrapper.setAttribute('data-total', (response.meta.total ? response.meta.total : 1));
529
- wrapper.setAttribute('data-page', (response.meta.current_page ? response.meta.current_page : 1));
530
- wrapper.setAttribute('data-pages', Math.ceil(wrapper.getAttribute('data-total') / wrapper.getAttribute('data-show')));
531
- createPaginationButttons(wrapper, pagination);
532
- if (response.data.length == 0) {
533
- tbody.innerHTML = '<tr><td colspan="100%"><span class="h4 m-0">No results found</span></td></tr>';
534
- }
535
673
  }
536
- else {
537
- tbody.innerHTML = '<tr><td colspan="100%"><span class="h6 m-0">Error loading table</span></td></tr>';
674
+ catch (error) {
675
+ console.log(error);
538
676
  }
539
677
  });
540
678
  };
541
679
  export const formatCell = (format, cellOutput) => {
542
680
  switch (format) {
681
+ case 'datetime':
682
+ return new Date(cellOutput).toLocaleDateString('en-gb', { weekday: 'short', year: "2-digit", month: "long", day: "numeric", }) + " " + new Date(cellOutput).toLocaleTimeString("en-gb", { hour: "2-digit", minute: "2-digit" });
543
683
  case 'date':
544
- cellOutput = new Date(cellOutput).toLocaleDateString('en-gb', { year: "2-digit", month: "long", day: "numeric" });
545
- break;
684
+ return new Date(cellOutput).toLocaleDateString('en-gb', { year: "2-digit", month: "long", day: "numeric" });
546
685
  case 'capitalise':
547
- cellOutput = ucfirst(cellOutput);
548
- break;
686
+ return cellOutput = ucfirst(cellOutput);
549
687
  }
550
- return cellOutput;
551
688
  };