@iamproperty/components 3.4.6 → 3.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/css/components/accordion.css.map +1 -1
- package/assets/css/components/applied-filters.css +1 -0
- package/assets/css/components/applied-filters.css.map +1 -0
- package/assets/css/components/card.css +1 -1
- package/assets/css/components/card.css.map +1 -1
- package/assets/css/components/charts.css +1 -1
- package/assets/css/components/charts.css.map +1 -1
- package/assets/css/components/container.css +1 -1
- package/assets/css/components/container.css.map +1 -1
- package/assets/css/components/dialog.css +1 -0
- package/assets/css/components/dialog.css.map +1 -0
- package/assets/css/components/forms.css +1 -1
- package/assets/css/components/forms.css.map +1 -1
- package/assets/css/components/lists.css +1 -1
- package/assets/css/components/lists.css.map +1 -1
- package/assets/css/components/nav.css +1 -1
- package/assets/css/components/nav.css.map +1 -1
- package/assets/css/components/pagination.css +1 -0
- package/assets/css/components/pagination.css.map +1 -0
- package/assets/css/components/table.css +1 -0
- package/assets/css/components/table.css.map +1 -0
- package/assets/css/core.min.css +1 -1
- package/assets/css/core.min.css.map +1 -1
- package/assets/css/style.min.css +1 -1
- package/assets/css/style.min.css.map +1 -1
- package/assets/js/bundle.js +18 -11
- package/assets/js/components/accordion/accordion.component.js +6 -0
- package/assets/js/components/accordion/accordion.component.min.js +3 -3
- package/assets/js/components/accordion/accordion.component.min.js.map +1 -1
- package/assets/js/components/applied-filters/applied-filters.component.js +26 -0
- package/assets/js/components/card/card.component.js +91 -0
- package/assets/js/components/card/card.component.min.js +21 -0
- package/assets/js/components/card/card.component.min.js.map +1 -0
- package/assets/js/components/filterlist/filterlist.component.js +49 -0
- package/assets/js/components/filterlist/filterlist.component.min.js +23 -0
- package/assets/js/components/filterlist/filterlist.component.min.js.map +1 -0
- package/assets/js/components/header/header.component.js +6 -0
- package/assets/js/components/header/header.component.min.js +2 -2
- package/assets/js/components/header/header.component.min.js.map +1 -1
- package/assets/js/components/pagination/pagination.component.js +34 -0
- package/assets/js/components/table/table.component.js +104 -0
- package/assets/js/components/table/table.component.min.js +24 -0
- package/assets/js/components/table/table.component.min.js.map +1 -0
- package/assets/js/components/tabs/tabs.component.js +6 -0
- package/assets/js/components/tabs/tabs.component.min.js +17 -0
- package/assets/js/components/tabs/tabs.component.min.js.map +1 -0
- package/assets/js/dynamic.js +7 -18
- package/assets/js/dynamic.min.js +2 -53
- package/assets/js/dynamic.min.js.map +1 -1
- package/assets/js/flat-components.js +27 -9
- package/assets/js/modules/applied-filters.js +100 -0
- package/assets/js/modules/data-layer.js +45 -0
- package/assets/js/modules/filterlist.js +32 -0
- package/assets/js/modules/helpers.js +77 -49
- package/assets/js/modules/pagination.js +33 -0
- package/assets/js/modules/table.js +507 -420
- package/assets/js/modules/tabs.js +6 -0
- package/assets/js/modules/youtubevideo.js +53 -61
- package/assets/js/scripts.bundle.js +77 -62
- package/assets/js/scripts.bundle.js.map +1 -1
- package/assets/js/scripts.bundle.min.js +2 -2
- package/assets/js/scripts.bundle.min.js.map +1 -1
- package/assets/js/tests/filterlist.spec.js +22 -0
- package/assets/js/tests/pagination.spec.js +15 -0
- package/assets/js/tests/table.spec.js +147 -0
- package/assets/sass/_components.scss +1 -2
- package/assets/sass/_corefiles.scss +5 -4
- package/assets/sass/_functions/utilities.scss +16 -0
- package/assets/sass/_functions/variables.scss +32 -18
- package/assets/sass/_tests/colours.spec.scss +1 -1
- package/assets/sass/components/applied-filters.scss +65 -0
- package/assets/sass/components/card.scss +177 -233
- package/assets/sass/components/charts.scss +4 -0
- package/assets/sass/components/container.scss +7 -2
- package/assets/sass/components/dialog.scss +202 -0
- package/assets/sass/components/forms.scss +37 -5
- package/assets/sass/components/lists.scss +15 -0
- package/assets/sass/components/nav.scss +5 -1
- package/assets/sass/components/pagination.scss +140 -0
- package/assets/sass/components/table.scss +419 -0
- package/assets/sass/foundations/icons.scss +1 -1
- package/assets/sass/{components → foundations}/links.scss +26 -0
- package/assets/sass/foundations/reboot.scss +19 -13
- package/assets/svg/illustrations/table.svg +165 -0
- package/assets/ts/bundle.ts +23 -12
- package/assets/ts/components/accordion/accordion.component.ts +7 -0
- package/assets/ts/components/applied-filters/README.md +5 -0
- package/assets/ts/components/applied-filters/applied-filters.component.ts +33 -0
- package/assets/ts/components/card/README.md +22 -0
- package/assets/ts/components/card/card.component.ts +117 -0
- package/assets/ts/components/filterlist/README.md +17 -0
- package/assets/ts/components/filterlist/filterlist.component.ts +60 -0
- package/assets/ts/components/header/header.component.ts +8 -0
- package/assets/ts/components/pagination/README.md +11 -0
- package/assets/ts/components/pagination/pagination.component.ts +45 -0
- package/assets/ts/components/table/README.md +23 -0
- package/assets/ts/components/table/table.component.ts +128 -0
- package/assets/ts/components/tabs/tabs.component.ts +7 -0
- package/assets/ts/dynamic.ts +12 -19
- package/assets/ts/flat-components.ts +37 -9
- package/assets/ts/modules/applied-filters.ts +146 -0
- package/assets/ts/modules/data-layer.ts +58 -0
- package/assets/ts/modules/filterlist.ts +46 -0
- package/assets/ts/modules/helpers.ts +90 -60
- package/assets/ts/modules/pagination.ts +44 -0
- package/assets/ts/modules/table.ts +598 -433
- package/assets/ts/modules/tabs.ts +8 -1
- package/assets/ts/modules/youtubevideo.ts +58 -63
- package/assets/ts/tests/filterlist.spec.ts +29 -0
- package/assets/ts/tests/pagination.spec.ts +21 -0
- package/assets/ts/tests/table.spec.ts +191 -0
- package/dist/components.es.js +1264 -1296
- package/dist/components.umd.js +70 -65
- package/dist/style.css +1 -1
- package/package.json +7 -5
- package/src/components/AppliedFilters/AppliedFilters.vue +20 -0
- package/src/components/AppliedFilters/README.md +5 -0
- package/src/components/Card/Card.vue +11 -112
- package/src/components/Card/README.md +16 -18
- package/src/components/Carousel/Carousel.vue +49 -10
- package/src/components/Chart/Chart.vue +46 -4
- package/src/components/Filterlist/Filterlist.vue +20 -0
- package/src/components/Filterlist/README.md +17 -0
- package/src/components/Pagination/Pagination.vue +30 -0
- package/src/components/Pagination/README.md +11 -0
- package/src/components/Table/README.md +29 -44
- package/src/components/Table/Table.spec.js +5 -37
- package/src/components/Table/Table.vue +16 -91
- package/src/foundations/YoutubeVideo/YoutubeVideo.vue +1 -1
- package/src/index.js +3 -2
- package/assets/css/components/cardDeck.css +0 -1
- package/assets/css/components/cardDeck.css.map +0 -1
- package/assets/css/components/links.css +0 -1
- package/assets/css/components/links.css.map +0 -1
- package/assets/css/components/modal.css +0 -1
- package/assets/css/components/modal.css.map +0 -1
- package/assets/css/components/tables.css +0 -1
- package/assets/css/components/tables.css.map +0 -1
- package/assets/js/modules/modal.js +0 -69
- package/assets/sass/components/cardDeck.scss +0 -108
- package/assets/sass/components/modal.scss +0 -136
- package/assets/sass/components/tables.scss +0 -291
- package/assets/ts/modules/modal.ts +0 -91
- package/src/components/CardDeck/CardDeck.spec.js +0 -99
- package/src/components/CardDeck/CardDeck.vue +0 -77
- package/src/components/CardDeck/README.md +0 -25
- package/src/components/Modal/Modal.spec.js +0 -22
- package/src/components/Modal/Modal.vue +0 -43
- package/src/components/Modal/README.md +0 -20
|
@@ -1,586 +1,751 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
import { zeroPad, isNumeric } from "./helpers";
|
|
2
|
+
import { zeroPad, isNumeric, ucfirst } from "./helpers";
|
|
3
|
+
import createPaginationButttons from "./pagination";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
// Basic functionality needed
|
|
6
|
+
export const addDataAttributes = (table) => {
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
const colHeadings = Array.from(table.querySelectorAll('thead th'));
|
|
9
|
+
const colRows = Array.from(table.querySelectorAll('tbody tr'));
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
const tbody = tableElement.querySelector('tbody');
|
|
11
|
-
const storedData = tbody.cloneNode(true);
|
|
12
|
-
const sortedEvent = new Event('sorted');
|
|
13
|
-
const filteredEvent = new Event('filtered');
|
|
14
|
-
const reorderedEvent = new Event('reordered');
|
|
15
|
-
const randID = 'table_'+Math.random().toString(36).substr(2, 9); // Random to make sure IDs created are unique
|
|
16
|
-
let draggedRow;
|
|
11
|
+
colRows.forEach((row, index) => {
|
|
17
12
|
|
|
18
|
-
|
|
13
|
+
const cells = Array.from(row.querySelectorAll('th, td'));
|
|
14
|
+
const statuses = ['Low','Medium','High','N/A','Pending','Verified','Incomplete','Completed','Requires approval'];
|
|
15
|
+
|
|
16
|
+
cells.forEach((cell, cellIndex) => {
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
const heading = colHeadings[cellIndex];
|
|
19
|
+
if(typeof heading != "undefined"){
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
let tempDiv = document.createElement("div");
|
|
22
|
+
tempDiv.innerHTML = heading.innerHTML;
|
|
23
|
+
let headingText = tempDiv.textContent || tempDiv.innerText || "";
|
|
24
|
+
cell.setAttribute('data-label',headingText);
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
if(heading.hasAttribute('class'))
|
|
27
|
+
cell.setAttribute('class',heading.getAttribute('class'))
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
if(heading.hasAttribute('data-format')){
|
|
30
|
+
cell.setAttribute('data-format',heading.getAttribute('data-format'))
|
|
31
|
+
cell.innerHTML = formatCell('date',cell.textContent.trim()); //Make sure date format is consistent
|
|
32
|
+
}
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
if(statuses.includes(cell.textContent.trim())){
|
|
35
|
+
cell.setAttribute('data-content',cell.textContent.trim());
|
|
36
|
+
}
|
|
35
37
|
}
|
|
36
|
-
tableArr.push(dataRow);
|
|
37
38
|
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
export const getLargestLastColWidth = (table) => {
|
|
43
|
+
|
|
44
|
+
let largestWidth = 0;
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
if(sort == "descending")
|
|
44
|
-
tableArr = tableArr.reverse();
|
|
46
|
+
Array.from(table.querySelectorAll('tr')).forEach((row, index) => {
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
let
|
|
48
|
-
tableArr.forEach((tableRow, index) => {
|
|
49
|
-
strTbody += tableRow.row.outerHTML;
|
|
50
|
-
});
|
|
51
|
-
tbody.innerHTML = strTbody;
|
|
48
|
+
let htmlStyles = window.getComputedStyle(document.querySelector('html'));
|
|
49
|
+
let lastColChild = row.querySelector(':scope > *:last-child > *:first-child');
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
tableElement.dispatchEvent(sortedEvent);
|
|
55
|
-
}
|
|
51
|
+
if(lastColChild){
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
let responsiveWidth = lastColChild.offsetWidth/parseFloat(htmlStyles.fontSize);
|
|
54
|
+
responsiveWidth += 1.5;
|
|
55
|
+
largestWidth = largestWidth > responsiveWidth ? largestWidth : responsiveWidth;
|
|
56
|
+
}
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
let rowHeight = row.offsetHeight/parseFloat(htmlStyles.fontSize);
|
|
59
|
+
row.style.setProperty("--row-height", `${rowHeight}rem`);
|
|
60
|
+
});
|
|
64
61
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
col.setAttribute('aria-sort','none');
|
|
68
|
-
});
|
|
62
|
+
return largestWidth;
|
|
63
|
+
}
|
|
69
64
|
|
|
70
|
-
|
|
71
|
-
target.setAttribute('aria-sort', sort);
|
|
65
|
+
export const createMobileButton = (table) => {
|
|
72
66
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
67
|
+
Array.from(table.querySelectorAll('tbody tr')).forEach((row, index) => {
|
|
68
|
+
let firstCol = row.querySelector(':scope > :is(td,th):first-child');
|
|
69
|
+
let colContent = firstCol.textContent;
|
|
70
|
+
firstCol.innerHTML =`<span class="td__content">${colContent}</span><button type="button" class="d-none">${colContent}</button>`;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
76
73
|
|
|
77
|
-
|
|
78
|
-
sortTable(target.textContent, sort);
|
|
74
|
+
export const addTableEventListeners = (table) => {
|
|
79
75
|
|
|
80
|
-
|
|
76
|
+
table.addEventListener('click', (event) => {
|
|
81
77
|
|
|
82
|
-
|
|
83
|
-
});
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}, false);
|
|
78
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('tr > :is(td,th):first-child button')){
|
|
88
79
|
|
|
89
|
-
|
|
90
|
-
|
|
80
|
+
let firstCol = event.target.closest('tr > :is(td,th):first-child button');
|
|
81
|
+
let tableRow = firstCol.parentNode.closest('tr');
|
|
91
82
|
|
|
92
|
-
|
|
83
|
+
if(tableRow.getAttribute('data-view') == "full")
|
|
84
|
+
tableRow.setAttribute('data-view','default');
|
|
85
|
+
else
|
|
86
|
+
tableRow.setAttribute('data-view','full');
|
|
93
87
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
}
|
|
88
|
+
firstCol.blur();
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
}
|
|
101
92
|
|
|
102
|
-
|
|
93
|
+
// Filters
|
|
94
|
+
export const createSearchDataList = (table, form) => {
|
|
103
95
|
|
|
104
|
-
|
|
105
|
-
const createFilterForm = function(count){
|
|
96
|
+
let searchInput = form.querySelector('[data-search]');
|
|
106
97
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
form.classList.add('table__filters');
|
|
110
|
-
form.classList.add('row');
|
|
111
|
-
form.classList.add('pt-1');
|
|
112
|
-
form.classList.add('pb-3');
|
|
98
|
+
if(!searchInput)
|
|
99
|
+
return false;
|
|
113
100
|
|
|
114
|
-
|
|
115
|
-
|
|
101
|
+
const searchID = searchInput.getAttribute('id');
|
|
102
|
+
const searchableColumns = searchInput.getAttribute('data-search').split(',');
|
|
103
|
+
let inputWrapper = searchInput.parentNode;
|
|
116
104
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
filterColumns.forEach((columnHeading, index) => {
|
|
120
|
-
Array.from(tableElement.querySelectorAll('td[data-label="'+columnHeading.textContent+'"]')).forEach((label, index) => {
|
|
105
|
+
let searchableTerms = {};
|
|
106
|
+
searchableColumns.forEach((columnHeading, index) => {
|
|
121
107
|
|
|
122
|
-
|
|
123
|
-
|
|
108
|
+
Array.from(table.querySelectorAll('td[data-label="'+columnHeading.trim()+'"]')).forEach((td, index) => {
|
|
109
|
+
|
|
110
|
+
if(td.querySelector('.td__content'))
|
|
111
|
+
searchableTerms[td.querySelector('.td__content').textContent] = td.querySelector('.td__content').textContent;
|
|
112
|
+
else
|
|
113
|
+
searchableTerms[td.textContent] = td.textContent;
|
|
124
114
|
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
searchInput.setAttribute('list',`${searchID}_list`);
|
|
118
|
+
searchInput.setAttribute('autocomplete','off');
|
|
119
|
+
|
|
120
|
+
if(!inputWrapper.querySelector('datalist'))
|
|
121
|
+
inputWrapper.innerHTML += `<datalist id="${searchID}_list"></datalist>`;
|
|
122
|
+
|
|
123
|
+
inputWrapper.querySelector('datalist').innerHTML = `${Object.keys(searchableTerms).map(term => `<option value="${term}"></option>`).join("")}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const addFilterEventListeners = (table, form, pagination, wrapper, savedTableBody) => {
|
|
125
127
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
<div class="col-md-8 align-items-center pb-3 ${checkboxClass}">
|
|
140
|
-
${`<span class="pe-3 text-nowrap h5 mb-0">Filter by: </span>` + filterColumns.map(column => `<div class="form-check pe-3 mt-0 mb-0"><input class="form-check-input" type="checkbox" id="${randID}_${column.textContent.replace(' ','_').toLowerCase()}" checked="checked" /><label class="form-check-label text-nowrap" for="${randID}_${column.textContent.replace(' ','_').toLowerCase()}">${column.textContent}</label></div>`).join("")}
|
|
141
|
-
</div>`;
|
|
142
|
-
|
|
143
|
-
// Add before the actual table
|
|
144
|
-
tableElement.prepend(form)
|
|
128
|
+
var timer;
|
|
129
|
+
|
|
130
|
+
// Check what conditions are set on the table to see what the form actions are
|
|
131
|
+
let formSubmit = function(){
|
|
132
|
+
|
|
133
|
+
if(form.hasAttribute('data-ajax'))
|
|
134
|
+
loadAjaxTable(table, form, pagination,wrapper);
|
|
135
|
+
else if(form.hasAttribute('data-submit'))
|
|
136
|
+
form.submit();
|
|
137
|
+
else {
|
|
138
|
+
filterTable(table, form, wrapper);
|
|
139
|
+
createPaginationButttons(wrapper,pagination);
|
|
140
|
+
}
|
|
145
141
|
}
|
|
146
142
|
|
|
147
|
-
|
|
143
|
+
form.addEventListener('keyup', (event) => {
|
|
148
144
|
|
|
149
|
-
|
|
150
|
-
let tableArr = [];
|
|
151
|
-
Array.from(storedData.querySelectorAll('tr')).forEach((tableRow, index) => {
|
|
145
|
+
clearTimeout(timer);
|
|
152
146
|
|
|
153
|
-
|
|
154
|
-
let rowSearchString = '';
|
|
155
|
-
Array.from(tableElement.querySelectorAll('[type="checkbox"]:checked + label')).forEach((label, index) => {
|
|
156
|
-
rowSearchString += tableRow.querySelector('td[data-label="'+label.textContent+'"]').textContent+' | ';
|
|
157
|
-
});
|
|
147
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('[data-search]')){
|
|
158
148
|
|
|
159
|
-
|
|
160
|
-
|
|
149
|
+
timer = setTimeout(function(){
|
|
150
|
+
formSubmit();
|
|
151
|
+
}, 500);
|
|
152
|
+
};
|
|
153
|
+
});
|
|
161
154
|
|
|
162
|
-
|
|
163
|
-
tableArr.push(dataRow);
|
|
164
|
-
}
|
|
165
|
-
});
|
|
155
|
+
form.addEventListener('change', (event) => {
|
|
166
156
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
157
|
+
clearTimeout(timer);
|
|
158
|
+
|
|
159
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('[data-sort]')){
|
|
160
|
+
|
|
161
|
+
if(!form.hasAttribute('data-submit'))
|
|
162
|
+
sortTable(table, form, savedTableBody);
|
|
173
163
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
164
|
+
formSubmit();
|
|
165
|
+
}
|
|
177
166
|
|
|
178
|
-
|
|
167
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('[data-search]')){
|
|
168
|
+
|
|
169
|
+
formSubmit();
|
|
170
|
+
}
|
|
179
171
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
});
|
|
172
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('[data-filter]') && !event.target.closest('form dialog')){
|
|
173
|
+
|
|
174
|
+
formSubmit();
|
|
175
|
+
}
|
|
185
176
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
});
|
|
192
|
-
});
|
|
177
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('[data-show]')){
|
|
178
|
+
|
|
179
|
+
formSubmit();
|
|
180
|
+
}
|
|
181
|
+
});
|
|
193
182
|
|
|
194
|
-
// Rebuild the list
|
|
195
|
-
let dataList = tableElement.querySelector('datalist');
|
|
196
|
-
dataList.innerHTML = Object.keys(searchableTerms).map(term => `<option value="${term}"></option>`).join("");
|
|
197
|
-
}
|
|
198
183
|
|
|
199
|
-
|
|
200
|
-
if(Array.from(tableElement.querySelectorAll('[data-filterable]')).length){
|
|
184
|
+
form.addEventListener('click', (event) => {
|
|
201
185
|
|
|
202
|
-
|
|
203
|
-
|
|
186
|
+
clearTimeout(timer);
|
|
187
|
+
|
|
188
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('dialog button:not([type="button"])')){
|
|
189
|
+
|
|
190
|
+
let button = event.target.closest('dialog button:not([type="button"])');
|
|
191
|
+
let modal = button.closest('dialog');
|
|
204
192
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
for (var target = e.target; target && target != this; target = target.parentNode) {
|
|
208
|
-
if (target.matches('input[type="search"]')) {
|
|
193
|
+
modal.close();
|
|
194
|
+
}
|
|
209
195
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
196
|
+
// Prevent the form from submitting
|
|
197
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('.dialog__close')){
|
|
198
|
+
|
|
199
|
+
event.preventDefault();
|
|
200
|
+
event.stopPropagation();
|
|
201
|
+
}
|
|
215
202
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
203
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('[data-clear]')){
|
|
204
|
+
|
|
205
|
+
form.reset();
|
|
219
206
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
});
|
|
207
|
+
if(!form.hasAttribute('data-submit'))
|
|
208
|
+
sortTable(table, form, savedTableBody);
|
|
225
209
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
210
|
+
formSubmit();
|
|
211
|
+
}
|
|
212
|
+
});
|
|
229
213
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
214
|
+
form.addEventListener('submit', (event) => {
|
|
215
|
+
|
|
216
|
+
clearTimeout(timer);
|
|
217
|
+
|
|
218
|
+
if(!form.hasAttribute('data-submit'))
|
|
219
|
+
event.preventDefault();
|
|
220
|
+
|
|
221
|
+
formSubmit();
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export const sortTable = (table, form, savedTableBody) => {
|
|
226
|
+
|
|
227
|
+
if(form.getAttribute('data-ajax')){
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
let tbody = table.querySelector('tbody');
|
|
232
|
+
let select = form.querySelector('[data-sort]');
|
|
233
|
+
let selectedOption = select.querySelector(`option:nth-child(${select.selectedIndex + 1})`);
|
|
234
|
+
|
|
235
|
+
let sortBy = selectedOption.getAttribute('data-sort');
|
|
236
|
+
let order = selectedOption.getAttribute('data-order');
|
|
237
|
+
let format = selectedOption.getAttribute('data-format');
|
|
238
|
+
|
|
239
|
+
if(!sortBy){
|
|
240
|
+
|
|
241
|
+
tbody.innerHTML = savedTableBody.innerHTML;
|
|
242
|
+
addDataAttributes(table);
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let orderArray = [];
|
|
247
|
+
if(!['asc','desc','descending'].includes(order)){
|
|
248
|
+
orderArray = order.split(',');
|
|
236
249
|
}
|
|
237
|
-
// #endregion Filters
|
|
238
250
|
|
|
239
|
-
//
|
|
240
|
-
|
|
251
|
+
// Create an array from the table rows, the index created is then used to sort the array
|
|
252
|
+
let tableArr = [];
|
|
253
|
+
Array.from(tbody.querySelectorAll('tr')).forEach((tableRow, index) => {
|
|
241
254
|
|
|
242
|
-
|
|
243
|
-
let style = document.getElementById(randID+'_style');
|
|
255
|
+
let rowIndex = tableRow.querySelector('td[data-label="'+sortBy+'"], th[data-label="'+sortBy+'"]').textContent.trim();
|
|
244
256
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
257
|
+
// If a predefined order set replace the search term with an ordered numeric value so it can be sorted
|
|
258
|
+
if(orderArray.length && orderArray.includes(rowIndex)){
|
|
259
|
+
rowIndex = orderArray.indexOf(rowIndex);
|
|
248
260
|
}
|
|
249
261
|
|
|
250
|
-
|
|
251
|
-
|
|
262
|
+
if(isNumeric(rowIndex))
|
|
263
|
+
rowIndex = zeroPad(rowIndex,10)
|
|
264
|
+
|
|
265
|
+
// If the sort format is date then lets transform the index to a sortable date (this is never displayed)
|
|
266
|
+
if(format && format == "date")
|
|
267
|
+
rowIndex = new Date(rowIndex);
|
|
268
|
+
|
|
269
|
+
const dataRow = {
|
|
270
|
+
index: rowIndex,
|
|
271
|
+
row: tableRow
|
|
272
|
+
}
|
|
273
|
+
tableArr.push(dataRow);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Sort array alphabetically
|
|
277
|
+
tableArr.sort((a, b) => (a.index > b.index) ? 1 : -1)
|
|
278
|
+
|
|
279
|
+
// Reverse if descending
|
|
280
|
+
if(order == "descending" || order == "desc")
|
|
281
|
+
tableArr = tableArr.reverse();
|
|
282
|
+
|
|
283
|
+
// Create a string to return and populate the tbody
|
|
284
|
+
let strTbody = '';
|
|
285
|
+
tableArr.forEach((tableRow, index) => {
|
|
286
|
+
strTbody += tableRow.row.outerHTML;
|
|
287
|
+
});
|
|
288
|
+
tbody.innerHTML = strTbody;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export const filterTable = (table, form, wrapper) => {
|
|
252
292
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
293
|
+
table.classList.remove('table--filtered');
|
|
294
|
+
|
|
295
|
+
let filters = [];
|
|
296
|
+
let searches = [];
|
|
297
|
+
let matched = 0;
|
|
298
|
+
let page = form.querySelector('[data-pagination]') ? parseInt(form.querySelector('[data-pagination]').value) : 1;
|
|
299
|
+
let showRows = form.querySelector('[data-show]') ? parseInt(form.querySelector('[data-show]').value) : 15;
|
|
300
|
+
|
|
301
|
+
// Filter
|
|
302
|
+
let filterInputs = Array.from(form.querySelectorAll('[data-filter]'));
|
|
303
|
+
|
|
304
|
+
filterInputs.forEach((filterInput, index) => {
|
|
305
|
+
|
|
306
|
+
// Ignore uncked radio inputs
|
|
307
|
+
if(filterInput.type == 'radio' && !filterInput.checked){
|
|
308
|
+
return;
|
|
256
309
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
310
|
+
|
|
311
|
+
if(filterInput.type == 'checkbox' && !filterInput.checked){
|
|
312
|
+
return;
|
|
260
313
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
if(filterInput.getAttribute('data-filter') == "multi"){
|
|
317
|
+
|
|
318
|
+
for (const [key, value] of Object.entries(JSON.parse(filterInput.value))) {
|
|
319
|
+
filters[filterInput.getAttribute('data-filter')].push(value);
|
|
265
320
|
}
|
|
266
321
|
}
|
|
267
|
-
|
|
268
|
-
|
|
322
|
+
else if (filterInput.value) {
|
|
323
|
+
|
|
324
|
+
if(!filters[filterInput.getAttribute('data-filter')])
|
|
325
|
+
filters[filterInput.getAttribute('data-filter')] = new Array();
|
|
326
|
+
|
|
327
|
+
filters[filterInput.getAttribute('data-filter')].push(filterInput.value);
|
|
269
328
|
}
|
|
270
|
-
`;
|
|
271
329
|
|
|
272
|
-
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
// Add search columns too
|
|
334
|
+
if(form.querySelector('[data-search]')){
|
|
335
|
+
let searchInput = form.querySelector('[data-search]');
|
|
336
|
+
let searchColumns = form.querySelector('[data-search]').getAttribute('data-search').split(',');
|
|
337
|
+
|
|
338
|
+
searchColumns.forEach((column, index) => {
|
|
339
|
+
|
|
340
|
+
searches.push({'column':`${column.trim()}`,'value':`${searchInput.value}`});
|
|
341
|
+
});
|
|
273
342
|
}
|
|
274
343
|
|
|
275
|
-
//
|
|
276
|
-
|
|
344
|
+
//Display the filter count
|
|
345
|
+
Array.from(form.querySelectorAll('[data-filter-count]')).forEach((element, index) => {
|
|
346
|
+
element.innerHTML = '';
|
|
347
|
+
});
|
|
348
|
+
if(filters.length) {
|
|
349
|
+
|
|
350
|
+
Array.from(form.querySelectorAll('[data-filter-count]')).forEach((element, index) => {
|
|
351
|
+
element.innerHTML += `(${filters.length})`;
|
|
352
|
+
});
|
|
353
|
+
}
|
|
277
354
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
355
|
+
// Stop function if no filters identified
|
|
356
|
+
if(!searches.length && !filters.length)
|
|
357
|
+
return false;
|
|
358
|
+
|
|
359
|
+
table.classList.add('table--filtered');
|
|
360
|
+
|
|
361
|
+
// Reset
|
|
362
|
+
Array.from(table.querySelectorAll('tbody tr')).forEach((row, index) => {
|
|
363
|
+
row.classList.remove('filtered');
|
|
364
|
+
row.classList.remove('filtered--matched');
|
|
365
|
+
row.classList.remove('filtered--show');
|
|
366
|
+
|
|
367
|
+
row.removeAttribute('data-filtered-by');
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// Filter the table
|
|
371
|
+
|
|
372
|
+
for (const [key, filterValue] of Object.entries(filters)) {
|
|
373
|
+
|
|
374
|
+
console.log(filterValue)
|
|
375
|
+
Array.from(table.querySelectorAll('tbody tr:not(.filtered)')).forEach((row, index) => {
|
|
376
|
+
|
|
377
|
+
let isMatched = false;
|
|
378
|
+
filterValue.forEach((filter, index) => {
|
|
379
|
+
|
|
380
|
+
let filterTd = row.querySelector(`[data-label="${key}"]`)
|
|
381
|
+
|
|
382
|
+
// Dynamic values
|
|
383
|
+
if(filter && filter == "$today")
|
|
384
|
+
filter = formatCell('date', new Date());
|
|
385
|
+
else if(filter && filter == "$yesterday"){
|
|
386
|
+
|
|
387
|
+
let yesterday = new Date();
|
|
388
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
389
|
+
filter = formatCell('date', yesterday);
|
|
390
|
+
}
|
|
391
|
+
else if(filter && (filter == "$thisWeek" || filter == "$lastWeek")){
|
|
281
392
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
393
|
+
let today = new Date();
|
|
394
|
+
let mondayThisWeek = new Date(today.setDate(today.getDate() - (today.getDay()-1)));
|
|
395
|
+
let sundayThisWeek = new Date(today.setDate(today.getDate() - today.getDay() + 7));
|
|
396
|
+
let checkDate = new Date(filterTd.textContent.toLowerCase());
|
|
286
397
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
398
|
+
today.setHours(0, 0, 0, 0);
|
|
399
|
+
mondayThisWeek.setHours(0, 0, 0, 0);
|
|
400
|
+
sundayThisWeek.setHours(0, 0, 0, 0);
|
|
401
|
+
checkDate.setHours(0, 0, 0, 0);
|
|
290
402
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
tableElement.setAttribute('data-show',target.value)
|
|
403
|
+
if(filter == "$thisWeek"){
|
|
404
|
+
isMatched = (checkDate >= mondayThisWeek && checkDate <= sundayThisWeek);
|
|
294
405
|
}
|
|
295
|
-
|
|
296
|
-
|
|
406
|
+
else {
|
|
407
|
+
let mondayLastWeek = new Date(mondayThisWeek.setDate(mondayThisWeek.getDate() - 7));
|
|
408
|
+
let sundayLastWeek = new Date(sundayThisWeek.setDate(sundayThisWeek.getDate() - 7));
|
|
297
409
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (target.matches('.page-item:not(.active):not(.disabled) .page-link')) {
|
|
410
|
+
mondayLastWeek.setHours(0, 0, 0, 0);
|
|
411
|
+
sundayLastWeek.setHours(0, 0, 0, 0);
|
|
301
412
|
|
|
302
|
-
|
|
303
|
-
createPaginationButttons(randID,tableElement,tableElement.getAttribute('data-show'),target.getAttribute('data-page'),totalRows);
|
|
413
|
+
isMatched = (checkDate >= mondayLastWeek && checkDate <= sundayLastWeek);
|
|
304
414
|
}
|
|
305
415
|
}
|
|
306
|
-
|
|
416
|
+
else if(filter && filter == "$thisMonth"){
|
|
307
417
|
|
|
308
|
-
|
|
309
|
-
for (var target = e.target; target && target != this; target = target.parentNode) {
|
|
310
|
-
if (target.matches('.table__pagination select')) {
|
|
418
|
+
let today = new Date(), year = today.getFullYear(), month = today.getMonth();
|
|
311
419
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
420
|
+
var firstDayMonth = new Date(year, month, 1);
|
|
421
|
+
var lastDayMonth = new Date(year, month + 1, 0);
|
|
422
|
+
let checkDate = new Date(filterTd.textContent.toLowerCase());
|
|
423
|
+
|
|
424
|
+
firstDayMonth.setHours(0, 0, 0, 0);
|
|
425
|
+
lastDayMonth.setHours(0, 0, 0, 0);
|
|
426
|
+
checkDate.setHours(0, 0, 0, 0);
|
|
427
|
+
|
|
428
|
+
isMatched = (checkDate >= firstDayMonth && checkDate <= lastDayMonth);
|
|
315
429
|
}
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
// #endregion Pagination
|
|
320
|
-
|
|
321
|
-
// #region Reorderable
|
|
322
|
-
// Set the row thats being dragged and copy the row
|
|
323
|
-
function setDraggedRow(e) {
|
|
324
|
-
e.dataTransfer.setData("text/plain", e.target.id);
|
|
325
|
-
draggedRow = e.target;
|
|
326
|
-
e.target.classList.add('tr--dragging');
|
|
327
|
-
}
|
|
430
|
+
else if(filter && filter == "$lastMonth"){
|
|
328
431
|
|
|
329
|
-
|
|
330
|
-
const setReorderRows = function(){
|
|
432
|
+
let today = new Date(), year = today.getFullYear(), month = today.getMonth();
|
|
331
433
|
|
|
332
|
-
|
|
434
|
+
var firstDayLastMonth = new Date(year, month - 1, 1);
|
|
435
|
+
var lastDayLastMonth = new Date(year, month, 0);
|
|
436
|
+
let checkDate = new Date(filterTd.textContent.toLowerCase());
|
|
333
437
|
|
|
334
|
-
|
|
335
|
-
|
|
438
|
+
firstDayLastMonth.setHours(0, 0, 0, 0);
|
|
439
|
+
lastDayLastMonth.setHours(0, 0, 0, 0);
|
|
440
|
+
checkDate.setHours(0, 0, 0, 0);
|
|
336
441
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
442
|
+
isMatched = (checkDate >= firstDayLastMonth && checkDate <= lastDayLastMonth);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if(filterTd && filterTd.textContent.toLowerCase().includes(filter.toLowerCase())){
|
|
446
|
+
isMatched = true;
|
|
447
|
+
}
|
|
342
448
|
|
|
343
|
-
|
|
344
|
-
tableRow.setAttribute('id',randID+'_row_'+(index+1));
|
|
345
|
-
tableRow.setAttribute('data-order',index+1);
|
|
346
|
-
tableRow.setAttribute('draggable','true');
|
|
347
|
-
tableRow.addEventListener("dragstart", setDraggedRow);
|
|
348
|
-
});
|
|
349
|
-
}
|
|
449
|
+
});
|
|
350
450
|
|
|
351
|
-
|
|
451
|
+
if(!isMatched){
|
|
352
452
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
453
|
+
row.classList.add('filtered');
|
|
454
|
+
row.setAttribute('data-filtered-by',key)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
// Search whats left of the table after filtering
|
|
460
|
+
Array.from(table.querySelectorAll('tbody tr:not(.filtered)')).forEach((row, index) => {
|
|
461
|
+
|
|
462
|
+
let isSearched = searches.length > 0 && searches[0].value.length >= 3 ? false : true;
|
|
463
|
+
|
|
464
|
+
searches.forEach((search, index) => {
|
|
359
465
|
|
|
360
|
-
|
|
466
|
+
let searchTd = row.querySelector(`[data-label="${search.column}"]`);
|
|
361
467
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
if (target.matches('.table-order-reset')) {
|
|
468
|
+
if(searchTd && search.value.length >= 3 && searchTd.textContent.toLowerCase().includes(search.value.toLowerCase())){
|
|
469
|
+
isSearched = true;
|
|
470
|
+
}
|
|
366
471
|
|
|
367
|
-
|
|
368
|
-
Array.from(tableElement.querySelectorAll('[data-sortable]')).forEach((col, index) => {
|
|
369
|
-
col.setAttribute('aria-sort','none');
|
|
370
|
-
});
|
|
472
|
+
});
|
|
371
473
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
474
|
+
if(!isSearched)
|
|
475
|
+
row.classList.add('filtered');
|
|
476
|
+
});
|
|
375
477
|
|
|
376
|
-
|
|
377
|
-
|
|
478
|
+
// Work out what to display after pagination
|
|
479
|
+
Array.from(table.querySelectorAll('tbody tr:not(.filtered')).forEach((row, index) => {
|
|
378
480
|
|
|
379
|
-
|
|
481
|
+
matched++;
|
|
380
482
|
|
|
381
|
-
|
|
382
|
-
|
|
483
|
+
row.classList.add('filtered--matched');
|
|
484
|
+
// pagination bit
|
|
485
|
+
if(Math.ceil(matched/showRows) == parseInt(page))
|
|
486
|
+
row.classList.add('filtered--show');
|
|
487
|
+
});
|
|
383
488
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
489
|
+
if(wrapper){
|
|
490
|
+
wrapper.setAttribute('data-page',page);
|
|
491
|
+
wrapper.setAttribute('data-pages',Math.ceil(matched/showRows));
|
|
492
|
+
wrapper.setAttribute('data-total',matched);
|
|
493
|
+
wrapper.setAttribute('data-show',showRows);
|
|
494
|
+
}
|
|
388
495
|
|
|
496
|
+
populateDataQueries(table,form);
|
|
497
|
+
}
|
|
389
498
|
|
|
390
|
-
|
|
391
|
-
// prevent default to allow drop
|
|
392
|
-
e.preventDefault();
|
|
393
|
-
}, false);
|
|
499
|
+
export const populateDataQueries = (table,form) => {
|
|
394
500
|
|
|
395
|
-
|
|
396
|
-
// prevent default to allow drop
|
|
397
|
-
e.preventDefault();
|
|
398
|
-
e.dataTransfer.dropEffect = "move";
|
|
501
|
+
const dataQueries = Array.from(form.querySelectorAll('[data-query]'));
|
|
399
502
|
|
|
400
|
-
|
|
401
|
-
if (target.matches('[data-reorder] tbody tr')) {
|
|
503
|
+
dataQueries.forEach((queryElement, index) => {
|
|
402
504
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
}
|
|
406
|
-
}, false);
|
|
505
|
+
let query = queryElement.getAttribute('data-query');
|
|
506
|
+
let numberOfMatchedRows: 0;
|
|
407
507
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
if (target.matches('[data-reorder] tbody tr')) {
|
|
508
|
+
if(query == 'total'){
|
|
509
|
+
numberOfMatchedRows = table.classList.contains('table--filtered') ? table.querySelectorAll('tbody tr:not(.filtered)').length : table.querySelectorAll('tbody tr').length;
|
|
510
|
+
}
|
|
511
|
+
else if(!query.includes(' == ') && query.includes(' & ')){
|
|
413
512
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
417
|
-
}, false);
|
|
513
|
+
let queries = query.split(' & ');
|
|
514
|
+
let selector = '';
|
|
418
515
|
|
|
419
|
-
|
|
516
|
+
queries.forEach(element => {
|
|
517
|
+
selector += `:not([data-filtered-by="${element}"])`;
|
|
518
|
+
});
|
|
420
519
|
|
|
421
|
-
|
|
520
|
+
console.log(selector)
|
|
521
|
+
numberOfMatchedRows = Array.from(table.querySelectorAll(`tbody tr${selector}`)).length;
|
|
522
|
+
}
|
|
523
|
+
else if(!query.includes(' == ')){
|
|
422
524
|
|
|
423
|
-
|
|
424
|
-
|
|
525
|
+
numberOfMatchedRows = Array.from(table.querySelectorAll(`tbody tr:not([data-filtered-by="${query}"])`)).length;
|
|
526
|
+
}
|
|
527
|
+
else if(query.includes(' && ')){
|
|
425
528
|
|
|
426
|
-
|
|
529
|
+
let queries = query.split(' && ');
|
|
427
530
|
|
|
428
|
-
|
|
531
|
+
numberOfMatchedRows = Array.from(table.querySelectorAll(`tbody tr:not(.filtered)`)).filter(function(row){
|
|
429
532
|
|
|
430
|
-
|
|
431
|
-
target.parentNode.insertBefore(draggedRow, target);
|
|
432
|
-
else
|
|
433
|
-
target.parentNode.insertBefore(draggedRow, target.nextElementSibling);
|
|
533
|
+
let matched = true;
|
|
434
534
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
tableRowOrder.classList.remove('tr--dropable')
|
|
439
|
-
tableRowOrder.querySelector('th').innerHTML = index + 1;
|
|
440
|
-
tableRowOrder.setAttribute('data-order',index+1);
|
|
441
|
-
});
|
|
535
|
+
for (const [index, value] of Object.entries(queries)) {
|
|
536
|
+
|
|
537
|
+
let queryParts = value.split(' == ');
|
|
442
538
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
break;
|
|
539
|
+
if(!row.querySelector(`td[data-label="${queryParts[0]}"]`) || row.querySelector(`td[data-label="${queryParts[0]}"]`).textContent != `${queryParts[1]}`)
|
|
540
|
+
matched = false;
|
|
446
541
|
}
|
|
447
|
-
}
|
|
448
|
-
}, false);
|
|
449
542
|
|
|
450
|
-
|
|
451
|
-
|
|
543
|
+
return matched;
|
|
544
|
+
|
|
545
|
+
}).length;
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
452
548
|
|
|
453
|
-
|
|
454
|
-
|
|
549
|
+
let queryParts = query.split(' == ');
|
|
550
|
+
console.log(queryParts[0]);
|
|
551
|
+
numberOfMatchedRows = Array.from(table.querySelectorAll(`tbody tr.filtered--matched td[data-label="${queryParts[0]}"], tbody tr[data-filtered-by="${queryParts[0]}"] td[data-label="${queryParts[0]}"]`)).filter(function(element){
|
|
552
|
+
return element.textContent === queryParts[1];
|
|
553
|
+
}).length;
|
|
554
|
+
}
|
|
455
555
|
|
|
456
|
-
if(
|
|
457
|
-
|
|
556
|
+
if(queryElement.hasAttribute('data-total'))
|
|
557
|
+
queryElement.setAttribute('data-total', numberOfMatchedRows);
|
|
558
|
+
else
|
|
559
|
+
queryElement.innerHTML = numberOfMatchedRows;
|
|
560
|
+
});
|
|
561
|
+
}
|
|
458
562
|
|
|
459
|
-
|
|
563
|
+
// Pagination
|
|
564
|
+
export const addPaginationEventListeners = function(table, form, pagination, wrapper){
|
|
460
565
|
|
|
461
|
-
|
|
462
|
-
const totalRows = tableElement.querySelectorAll('tbody tr').length;
|
|
463
|
-
const tablePagination = tableElement.querySelector('.table__pagination');
|
|
566
|
+
pagination.addEventListener('click', (event) => {
|
|
464
567
|
|
|
465
|
-
|
|
466
|
-
|
|
568
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('[data-page]')){
|
|
569
|
+
|
|
570
|
+
event.preventDefault();
|
|
467
571
|
|
|
468
|
-
|
|
572
|
+
let paginationInput = form.querySelector('[data-pagination]');
|
|
573
|
+
let newPage = event.target.closest('[data-page]').getAttribute('data-page');
|
|
574
|
+
paginationInput.value = newPage;
|
|
575
|
+
wrapper.setAttribute('data-page', newPage);
|
|
576
|
+
form.dispatchEvent(new Event("submit"));
|
|
469
577
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
}
|
|
578
|
+
const url = new URL(location);
|
|
579
|
+
url.searchParams.set("page", newPage);
|
|
580
|
+
history.pushState({'type':'pagination','form':form.getAttribute('id'),'page':newPage}, "", url)
|
|
474
581
|
}
|
|
475
582
|
|
|
476
|
-
if(
|
|
583
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('[data-show]')){
|
|
477
584
|
|
|
478
|
-
|
|
585
|
+
event.preventDefault();
|
|
586
|
+
let showInput = form.querySelector('[data-show]');
|
|
587
|
+
let showRows = event.target.closest('[data-show]').getAttribute('data-show');
|
|
588
|
+
showInput.value = showRows;
|
|
589
|
+
wrapper.setAttribute('data-show', showRows);
|
|
590
|
+
form.dispatchEvent(new Event("submit"));
|
|
479
591
|
}
|
|
480
|
-
}
|
|
592
|
+
});
|
|
593
|
+
}
|
|
481
594
|
|
|
482
|
-
|
|
595
|
+
// Export CSV Data
|
|
596
|
+
export const addExportEventListeners = (button, table) => {
|
|
483
597
|
|
|
484
|
-
|
|
598
|
+
if(!button)
|
|
599
|
+
return false;
|
|
485
600
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
}
|
|
601
|
+
button.addEventListener('click', (event) => {
|
|
602
|
+
exportAsCSV(table);
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
export const exportAsCSV = function(table){
|
|
607
|
+
|
|
608
|
+
var csvData = [];
|
|
609
|
+
// Get each row data
|
|
610
|
+
var rows = table.getElementsByTagName('tr');
|
|
611
|
+
for (var i = 0; i < rows.length; i++) {
|
|
489
612
|
|
|
490
|
-
|
|
613
|
+
// Get each column data
|
|
614
|
+
var cols = rows[i].querySelectorAll('td,th');
|
|
491
615
|
|
|
492
|
-
|
|
493
|
-
|
|
616
|
+
// Stores each csv row data
|
|
617
|
+
var csvRow = [];
|
|
618
|
+
for (var j = 0; j < cols.length; j++) {
|
|
494
619
|
|
|
495
|
-
|
|
496
|
-
|
|
620
|
+
// Get the text data of each cell of a row and push it to csvrow
|
|
621
|
+
csvRow.push(`"${cols[j].textContent}"`);
|
|
622
|
+
}
|
|
497
623
|
|
|
498
|
-
|
|
499
|
-
|
|
624
|
+
// Combine each column value with comma
|
|
625
|
+
csvData.push(csvRow.join(","));
|
|
626
|
+
}
|
|
500
627
|
|
|
501
|
-
|
|
502
|
-
|
|
628
|
+
// Combine each row data with new line character
|
|
629
|
+
csvData = csvData.join('\n');
|
|
630
|
+
|
|
631
|
+
// Create CSV file object and feed our csvData into it
|
|
632
|
+
let CSVFile = new Blob([csvData], {
|
|
633
|
+
type: "text/csv"
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
// Create to temporary link to initiate download process
|
|
637
|
+
var tempLink = document.createElement('a');
|
|
638
|
+
tempLink.download = "export.csv";
|
|
639
|
+
var url = window.URL.createObjectURL(CSVFile);
|
|
640
|
+
tempLink.href = url;
|
|
641
|
+
|
|
642
|
+
// This link should not be displayed
|
|
643
|
+
tempLink.style.display = "none";
|
|
644
|
+
document.body.appendChild(tempLink);
|
|
645
|
+
|
|
646
|
+
// Automatically click the link to trigger download
|
|
647
|
+
tempLink.click();
|
|
648
|
+
document.body.removeChild(tempLink);
|
|
503
649
|
}
|
|
504
650
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
form
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
</div>
|
|
519
|
-
<datalist id="${randID}_pagination">
|
|
520
|
-
<option value="5">5</option>
|
|
521
|
-
${totalRows > 10 ? `<option value="10">10</option>` : ''}
|
|
522
|
-
${totalRows > 20 ? `<option value="20">20</option>` : ''}
|
|
523
|
-
<option value="${totalRows}">${totalRows}</option>
|
|
524
|
-
</datalist>
|
|
525
|
-
</div>
|
|
526
|
-
<div class="col mw-fit-content me-auto d-flex align-items-center mb-3"><span class="label">per page</span></div>
|
|
527
|
-
<div class="col mw-fit-content d-sm-flex justify-content-end align-items-center" id="${randID}_paginationBtns"></div>`;
|
|
528
|
-
|
|
529
|
-
// Add after the actual table
|
|
530
|
-
tableElement.append(form)
|
|
651
|
+
// After table is loaded
|
|
652
|
+
export const makeTableFunctional = function(table, form, pagination, wrapper){
|
|
653
|
+
|
|
654
|
+
createMobileButton(table);
|
|
655
|
+
addDataAttributes(table);
|
|
656
|
+
populateDataQueries(table, form);
|
|
657
|
+
|
|
658
|
+
// Work out the largest width of the CTA's in the last column
|
|
659
|
+
if(wrapper && wrapper.classList.contains('table--cta')){
|
|
660
|
+
|
|
661
|
+
const largestWidth = getLargestLastColWidth(table);
|
|
662
|
+
wrapper.style.setProperty("--cta-width", `${largestWidth}rem`);
|
|
663
|
+
}
|
|
531
664
|
}
|
|
532
665
|
|
|
533
|
-
export const
|
|
666
|
+
export const loadAjaxTable = function (table, form, pagination, wrapper){
|
|
534
667
|
|
|
535
|
-
const
|
|
668
|
+
const resolvePath = (object, path, defaultValue) => path.split(/[\.\[\]\'\"]/).filter(p => p).reduce((o, p) => o ? o[p] : defaultValue, object);
|
|
536
669
|
|
|
537
|
-
|
|
538
|
-
|
|
670
|
+
let queryString = new URLSearchParams(new FormData(form)).toString();
|
|
671
|
+
let columns = table.querySelectorAll('thead tr th');
|
|
672
|
+
let tbody = table.querySelector('tbody');
|
|
539
673
|
|
|
540
|
-
|
|
674
|
+
fetch(form.getAttribute('data-ajax'), {
|
|
675
|
+
method: 'get',
|
|
676
|
+
credentials: 'same-origin',
|
|
677
|
+
headers: new Headers({
|
|
678
|
+
'Content-Type': 'application/json',
|
|
679
|
+
Accept: 'application/json',
|
|
680
|
+
'X-Requested-With': 'XMLHttpRequest'
|
|
681
|
+
})
|
|
682
|
+
}).then((response) => response.json()).then((response) => {
|
|
541
683
|
|
|
542
|
-
|
|
543
|
-
paginationButtonsWrapper.innerHTML = '';
|
|
544
|
-
}
|
|
545
|
-
else if(numberPages < 5){ // If less than 5 pages (which fits comfortably on mobile) we display buttons
|
|
684
|
+
if (response.data) {
|
|
546
685
|
|
|
547
|
-
|
|
686
|
+
tbody.innerHTML = '';
|
|
548
687
|
|
|
549
|
-
|
|
688
|
+
response.data.forEach((row, index) => {
|
|
550
689
|
|
|
551
|
-
|
|
552
|
-
strButtons += `<li class="page-item active" aria-current="page"><span class="page-link">${i}</span></li>`;
|
|
553
|
-
else
|
|
554
|
-
strButtons += `<li class="page-item"><button class="page-link" data-page="${i}">${i}</button></li>`;
|
|
555
|
-
}
|
|
690
|
+
var table_row = document.createElement('tr');
|
|
556
691
|
|
|
557
|
-
|
|
558
|
-
${page == 1 ? `<li class="page-item disabled"><span class="page-link">Previous</span></li>` : `<li class="page-item"><button class="page-link" data-page="${parseInt(page)-1}">Previous</button></li>`}
|
|
559
|
-
${strButtons}
|
|
560
|
-
${page == numberPages ? `<li class="page-item disabled"><span class="page-link">Next</span></li>` : `<li class="page-item"><button class="page-link" data-page="${parseInt(page)+1}">Next</button></li>`}
|
|
561
|
-
</ul>`;
|
|
692
|
+
columns.forEach((col, index) => {
|
|
562
693
|
|
|
563
|
-
|
|
564
|
-
|
|
694
|
+
let cellOutput = '';
|
|
695
|
+
var table_cell = document.createElement('td');
|
|
696
|
+
// Add some data to help with the mobile layout design
|
|
697
|
+
table_cell.setAttribute('data-label',col.innerText);
|
|
565
698
|
|
|
566
|
-
|
|
699
|
+
if(col.getAttribute('data-output')){
|
|
700
|
+
var cellTemplate = col.getAttribute('data-output');
|
|
701
|
+
// Use a regex to replace {var} with actual values from the json data
|
|
702
|
+
cellOutput = cellTemplate.replace( new RegExp(/{(.*?)}/,"gm"), function(matched){ return resolvePath(row, matched.replace('{','').replace('}','')); });
|
|
703
|
+
}
|
|
567
704
|
|
|
568
|
-
|
|
705
|
+
if(col.hasAttribute('data-format')){
|
|
706
|
+
cellOutput = formatCell(col.getAttribute('data-format'),cellOutput);
|
|
707
|
+
}
|
|
569
708
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
709
|
+
table_cell.innerHTML = cellOutput;
|
|
710
|
+
table_row.appendChild(table_cell)
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
tbody.appendChild(table_row)
|
|
714
|
+
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
createSearchDataList(table, form)
|
|
718
|
+
// Add data to the pagination
|
|
719
|
+
makeTableFunctional(table, form, pagination, wrapper);
|
|
720
|
+
|
|
721
|
+
wrapper.setAttribute('data-total', (response.meta.total ? response.meta.total : 1));
|
|
722
|
+
wrapper.setAttribute('data-page', (response.meta.current_page ? response.meta.current_page : 1));
|
|
723
|
+
wrapper.setAttribute('data-pages', Math.ceil(wrapper.getAttribute('data-total') / wrapper.getAttribute('data-show')));
|
|
724
|
+
|
|
725
|
+
createPaginationButttons(wrapper, pagination);
|
|
726
|
+
|
|
727
|
+
if(response.data.length == 0){
|
|
728
|
+
tbody.innerHTML = '<tr><td colspan="100%"><span class="h4 m-0">No results found</span></td></tr>';
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
tbody.innerHTML = '<tr><td colspan="100%"><span class="h6 m-0">Error loading table</span></td></tr>';
|
|
574
734
|
}
|
|
575
735
|
|
|
576
|
-
|
|
577
|
-
<div class="form-control__wrapper page-number mb-2">
|
|
578
|
-
<select class="form-select">
|
|
579
|
-
${strOptions}
|
|
580
|
-
</select>
|
|
581
|
-
</div>
|
|
582
|
-
`;
|
|
583
|
-
}
|
|
736
|
+
});
|
|
584
737
|
}
|
|
585
738
|
|
|
586
|
-
export
|
|
739
|
+
export const formatCell = (format, cellOutput) => {
|
|
740
|
+
|
|
741
|
+
switch (format) {
|
|
742
|
+
case 'date':
|
|
743
|
+
cellOutput = new Date(cellOutput).toLocaleDateString('en-gb', { year:"2-digit", month:"long", day: "numeric"});
|
|
744
|
+
break;
|
|
745
|
+
case 'capitalise':
|
|
746
|
+
cellOutput = ucfirst(cellOutput);
|
|
747
|
+
break;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
return cellOutput;
|
|
751
|
+
}
|