@iamproperty/components 1.0.12 → 2.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 (209) hide show
  1. package/README.md +120 -12
  2. package/assets/.DS_Store +0 -0
  3. package/assets/css/core.min.css +1 -0
  4. package/assets/css/core.min.css.map +1 -0
  5. package/assets/css/style.min.css +1 -0
  6. package/assets/css/style.min.css.map +1 -0
  7. package/assets/favicons/android-chrome-192x192.png +0 -0
  8. package/assets/favicons/android-chrome-512x512.png +0 -0
  9. package/assets/favicons/apple-touch-icon.png +0 -0
  10. package/assets/favicons/favicon-16x16.png +0 -0
  11. package/assets/favicons/favicon-32x32.png +0 -0
  12. package/assets/favicons/favicon.ico +0 -0
  13. package/assets/fonts/qanelas-medium-webfont.woff +0 -0
  14. package/assets/fonts/qanelas-medium-webfont.woff2 +0 -0
  15. package/assets/fonts/qanelassoft-extrabold-webfont.woff +0 -0
  16. package/assets/fonts/qanelassoft-extrabold-webfont.woff2 +0 -0
  17. package/assets/img/.DS_Store +0 -0
  18. package/{src/assets → assets}/img/logo.png +0 -0
  19. package/assets/js/main.js +62 -0
  20. package/assets/js/modules/accordion.js +36 -0
  21. package/assets/js/modules/carousel.js +102 -0
  22. package/assets/js/modules/drawer.js +16 -0
  23. package/assets/js/modules/form.js +49 -0
  24. package/assets/js/modules/helpers.js +93 -0
  25. package/assets/js/modules/modal.js +72 -0
  26. package/assets/js/modules/nav.js +27 -0
  27. package/assets/js/modules/table.js +573 -0
  28. package/assets/js/modules/testimonial.js +83 -0
  29. package/assets/js/scripts.bundle.js +1313 -0
  30. package/assets/js/scripts.bundle.js.map +1 -0
  31. package/assets/js/scripts.bundle.min.js +7 -0
  32. package/assets/js/scripts.bundle.min.js.map +1 -0
  33. package/assets/sass/.DS_Store +0 -0
  34. package/assets/sass/_components.scss +35 -0
  35. package/assets/sass/_corefiles.scss +58 -0
  36. package/assets/sass/_func.scss +9 -0
  37. package/assets/sass/_functions/functions.scss +95 -0
  38. package/assets/sass/_functions/mixins.scss +109 -0
  39. package/assets/sass/_functions/utilities.scss +198 -0
  40. package/assets/sass/_functions/variables.scss +365 -0
  41. package/assets/sass/components/accordion.scss +194 -0
  42. package/assets/sass/components/card.scss +168 -0
  43. package/assets/sass/components/cardDeck.scss +107 -0
  44. package/assets/sass/components/carousel.scss +265 -0
  45. package/assets/sass/components/charts.scss +562 -0
  46. package/assets/sass/components/drawer.scss +45 -0
  47. package/assets/sass/components/header.scss +57 -0
  48. package/assets/sass/components/modal.scss +133 -0
  49. package/assets/sass/components/nav.scss +619 -0
  50. package/assets/sass/components/property-searchbar.scss +138 -0
  51. package/assets/sass/components/snapshot.scss +69 -0
  52. package/assets/sass/components/tabs.scss +46 -0
  53. package/assets/sass/components/testimonial.scss +131 -0
  54. package/assets/sass/components/timeline.scss +93 -0
  55. package/assets/sass/core.scss +4 -0
  56. package/assets/sass/elements/buttons.scss +263 -0
  57. package/assets/sass/elements/container.scss +134 -0
  58. package/assets/sass/elements/forms.scss +128 -0
  59. package/assets/sass/elements/links.scss +95 -0
  60. package/assets/sass/elements/lists.scss +21 -0
  61. package/assets/sass/elements/media.scss +3 -0
  62. package/assets/sass/elements/tables.scss +247 -0
  63. package/assets/sass/elements/tooltips.scss +71 -0
  64. package/assets/sass/elements/type.scss +99 -0
  65. package/assets/sass/foundations/brand.scss +64 -0
  66. package/assets/sass/foundations/circles.scss +66 -0
  67. package/assets/sass/foundations/fonts.scss +17 -0
  68. package/assets/sass/foundations/icons.scss +46 -0
  69. package/assets/sass/foundations/reboot.scss +110 -0
  70. package/assets/sass/foundations/root.scss +42 -0
  71. package/assets/sass/main.scss +5 -0
  72. package/assets/svg/.DS_Store +0 -0
  73. package/assets/svg/flat/.DS_Store +0 -0
  74. package/assets/svg/flat/agreed.svg +1 -0
  75. package/assets/svg/flat/alert.svg +1 -0
  76. package/assets/svg/flat/asset-37.svg +1 -0
  77. package/assets/svg/flat/asset-73.svg +1 -0
  78. package/assets/svg/flat/asset-82.svg +1 -0
  79. package/assets/svg/flat/award.svg +1 -0
  80. package/assets/svg/flat/bath.svg +1 -0
  81. package/assets/svg/flat/bed.svg +1 -0
  82. package/assets/svg/flat/calculate.svg +1 -0
  83. package/assets/svg/flat/calendar.svg +1 -0
  84. package/assets/svg/flat/celebrate.svg +1 -0
  85. package/assets/svg/flat/chat-house.svg +1 -0
  86. package/assets/svg/flat/chat.svg +1 -0
  87. package/assets/svg/flat/circle.svg +1 -0
  88. package/assets/svg/flat/clean.svg +1 -0
  89. package/assets/svg/flat/clock.svg +1 -0
  90. package/assets/svg/flat/computer.svg +1 -0
  91. package/assets/svg/flat/down.svg +1 -0
  92. package/assets/svg/flat/edit.svg +1 -0
  93. package/assets/svg/flat/email.svg +1 -0
  94. package/assets/svg/flat/event.svg +1 -0
  95. package/assets/svg/flat/family.svg +1 -0
  96. package/assets/svg/flat/file.svg +1 -0
  97. package/assets/svg/flat/find.svg +1 -0
  98. package/assets/svg/flat/fireworks.svg +1 -0
  99. package/assets/svg/flat/fist-left.svg +1 -0
  100. package/assets/svg/flat/fist.svg +1 -0
  101. package/assets/svg/flat/folder.svg +1 -0
  102. package/assets/svg/flat/footprints.svg +1 -0
  103. package/assets/svg/flat/hand.svg +1 -0
  104. package/assets/svg/flat/hands.svg +1 -0
  105. package/assets/svg/flat/house-2.svg +1 -0
  106. package/assets/svg/flat/house.svg +1 -0
  107. package/assets/svg/flat/idea.svg +1 -0
  108. package/assets/svg/flat/judge-house.svg +1 -0
  109. package/assets/svg/flat/judge.svg +1 -0
  110. package/assets/svg/flat/keys-house.svg +1 -0
  111. package/assets/svg/flat/lock.svg +1 -0
  112. package/assets/svg/flat/mobile.svg +1 -0
  113. package/assets/svg/flat/money.svg +1 -0
  114. package/assets/svg/flat/monument.svg +1 -0
  115. package/assets/svg/flat/online-judgement.svg +1 -0
  116. package/assets/svg/flat/paint.svg +1 -0
  117. package/assets/svg/flat/person-2.svg +1 -0
  118. package/assets/svg/flat/person.svg +1 -0
  119. package/assets/svg/flat/phone.svg +1 -0
  120. package/assets/svg/flat/pin.svg +1 -0
  121. package/assets/svg/flat/pound.svg +1 -0
  122. package/assets/svg/flat/present.svg +1 -0
  123. package/assets/svg/flat/qualification.svg +1 -0
  124. package/assets/svg/flat/rocket.svg +1 -0
  125. package/assets/svg/flat/sale.svg +1 -0
  126. package/assets/svg/flat/save.svg +1 -0
  127. package/assets/svg/flat/scale.svg +1 -0
  128. package/assets/svg/flat/send.svg +1 -0
  129. package/assets/svg/flat/share.svg +1 -0
  130. package/assets/svg/flat/sofa.svg +1 -0
  131. package/assets/svg/flat/sold.svg +1 -0
  132. package/assets/svg/flat/star.svg +1 -0
  133. package/assets/svg/flat/stopwatch.svg +1 -0
  134. package/assets/svg/flat/task.svg +1 -0
  135. package/assets/svg/flat/telescope.svg +1 -0
  136. package/assets/svg/flat/thumb.svg +1 -0
  137. package/assets/svg/flat/time.svg +1 -0
  138. package/assets/svg/flat/up.svg +1 -0
  139. package/assets/svg/flat/valuation.svg +1 -0
  140. package/assets/svg/flat/value-house.svg +1 -0
  141. package/assets/svg/flat/warning.svg +1 -0
  142. package/assets/svg/flat/water.svg +1 -0
  143. package/assets/svg/icons.svg +51 -0
  144. package/assets/svg/illustrations/commuter1.svg +1 -0
  145. package/assets/svg/illustrations/commuter2.svg +1 -0
  146. package/assets/svg/illustrations/commuter3.svg +1 -0
  147. package/assets/svg/logo.svg +43 -0
  148. package/dist/components.common.js +8253 -328
  149. package/dist/components.common.js.map +1 -1
  150. package/dist/components.css +2 -1
  151. package/dist/components.css.map +1 -0
  152. package/dist/components.umd.js +8253 -328
  153. package/dist/components.umd.js.map +1 -1
  154. package/dist/components.umd.min.js +1 -1
  155. package/dist/components.umd.min.js.map +1 -1
  156. package/package.json +91 -57
  157. package/src/.DS_Store +0 -0
  158. package/src/components/Accordion/Accordion.vue +24 -0
  159. package/src/components/Accordion/AccordionItem.vue +43 -0
  160. package/src/components/Accordion/README.md +34 -0
  161. package/src/components/Banner/Banner.vue +38 -0
  162. package/src/components/Banner/README.md +24 -0
  163. package/src/components/Card/Card.vue +115 -0
  164. package/src/components/Card/README.md +24 -0
  165. package/src/components/CardDeck/CardDeck.vue +78 -0
  166. package/src/components/CardDeck/README.md +25 -0
  167. package/src/components/Carousel/Carousel.vue +86 -0
  168. package/src/components/Carousel/README.md +20 -0
  169. package/src/components/Chart/Chart.vue +246 -0
  170. package/src/components/Chart/README.md +18 -0
  171. package/src/components/Drawer/Drawer.vue +54 -0
  172. package/src/components/Drawer/README.md +23 -0
  173. package/src/components/Header/Header.vue +39 -0
  174. package/src/components/Header/README.md +28 -0
  175. package/src/components/Modal/Modal.vue +44 -0
  176. package/src/components/Modal/README.md +20 -0
  177. package/src/components/Nav/Nav.vue +129 -0
  178. package/src/components/Nav/README.md +23 -0
  179. package/src/components/PropertySearchbar/PropertySearchbar.vue +206 -0
  180. package/src/components/PropertySearchbar/README.md +26 -0
  181. package/src/components/Snapshot/README.md +21 -0
  182. package/src/components/Snapshot/Snapshot.vue +33 -0
  183. package/src/components/Tabs/README.md +27 -0
  184. package/src/components/Tabs/Tab.vue +17 -0
  185. package/src/components/Tabs/Tabs.vue +55 -0
  186. package/src/components/Testimonial/README.md +26 -0
  187. package/src/components/Testimonial/Testimonial.vue +61 -0
  188. package/src/components/Timeline/README.md +18 -0
  189. package/src/components/Timeline/Timeline.vue +25 -0
  190. package/src/elements/Input/Input.vue +236 -0
  191. package/src/elements/Input/README.md +18 -0
  192. package/src/elements/Table/README.md +55 -0
  193. package/src/elements/Table/Table.vue +112 -0
  194. package/src/foundations/Icon/Icon.vue +21 -0
  195. package/src/foundations/Icon/README.md +11 -0
  196. package/src/foundations/Logo/Logo.vue +39 -0
  197. package/src/foundations/Logo/README.md +20 -0
  198. package/src/helpers/strings.js +12 -0
  199. package/src/index.js +21 -4
  200. package/src/assets/css/default.css +0 -99
  201. package/src/assets/logo.png +0 -0
  202. package/src/assets/scss/_variables.scss +0 -13
  203. package/src/components/KeyFacts/KeyFact.vue +0 -45
  204. package/src/components/KeyFacts/KeyFactGroup.vue +0 -44
  205. package/src/components/KeyFacts/README.md +0 -23
  206. package/src/components/PropertyTaskIntro/PropertyTaskIntro.vue +0 -74
  207. package/src/components/PropertyTaskIntro/README.md +0 -27
  208. package/src/components/TaskTitle/README.md +0 -24
  209. package/src/components/TaskTitle/TaskTitle.vue +0 -68
@@ -0,0 +1,573 @@
1
+ import { zeroPad, isNumeric } from "./helpers";
2
+
3
+ function table(tableElement) {
4
+
5
+ if(typeof tableElement != "object")
6
+ return false;
7
+
8
+ const thead = tableElement.querySelector('thead');
9
+ const tbody = tableElement.querySelector('tbody');
10
+ const storedData = tbody.cloneNode(true);
11
+ const sortedEvent = new Event('sorted');
12
+ const filteredEvent = new Event('filtered');
13
+ const randID = 'tabe_'+Math.random().toString(36).substr(2, 9); // Random to make sure IDs created are unique
14
+ let draggedRow;
15
+
16
+ tableElement.setAttribute('id',randID)
17
+
18
+ // #region Sortable
19
+ const sortTable = function(sortBy,sort){
20
+
21
+ // Create an array from the table rows, the index created is then used to sort the array
22
+ let tableArr = [];
23
+ Array.from(tbody.querySelectorAll('tr')).forEach((tableRow, index) => {
24
+
25
+ let rowIndex = tableRow.querySelector('td[data-label="'+sortBy+'"], th[data-label="'+sortBy+'"]').textContent;
26
+
27
+ if(isNumeric(rowIndex))
28
+ rowIndex = zeroPad(rowIndex,10)
29
+
30
+ const dataRow = {
31
+ index: rowIndex,
32
+ row: tableRow
33
+ }
34
+ tableArr.push(dataRow);
35
+ });
36
+
37
+ // Sort array
38
+ tableArr.sort((a, b) => (a.index > b.index) ? 1 : -1)
39
+
40
+ // Reverse if descending
41
+ if(sort == "descending")
42
+ tableArr = tableArr.reverse();
43
+
44
+ // Create a string to return and populate the tbody
45
+ let strTbody = '';
46
+ tableArr.forEach((tableRow, index) => {
47
+ strTbody += tableRow.row.outerHTML;
48
+ });
49
+ tbody.innerHTML = strTbody;
50
+
51
+ // Dispatch the sortable event
52
+ tableElement.dispatchEvent(sortedEvent);
53
+ }
54
+
55
+ // Declare event handlers
56
+ tableElement.addEventListener('click', function(e){
57
+ for (var target = e.target; target && target != this; target = target.parentNode) {
58
+ if (target.matches('[data-sortable]')) {
59
+
60
+ // Get current sort order
61
+ let sort = target.getAttribute('aria-sort') == "ascending" ? "descending" : "ascending";
62
+
63
+ // unset sort attributes
64
+ Array.from(tableElement.querySelectorAll('[data-sortable]')).forEach((col, index) => {
65
+ col.setAttribute('aria-sort','none');
66
+ });
67
+
68
+ // Set the sort order attribute
69
+ target.setAttribute('aria-sort', sort);
70
+
71
+ // Save the sort options on the table element so that it can be re-sorted later
72
+ tableElement.setAttribute('data-sort', sort);
73
+ tableElement.setAttribute('data-sortBy', target.textContent);
74
+
75
+ // Sort the table
76
+ sortTable(target.textContent, sort);
77
+
78
+ Array.from(tableElement.querySelectorAll('tr[draggable]')).forEach((tableRow, index) => {
79
+
80
+ tableRow.removeAttribute('draggable');
81
+ });
82
+ break;
83
+ }
84
+ }
85
+ }, false);
86
+
87
+ // On page load check if the table should be pre-sorted, if so trigger a click
88
+ if(tableElement.getAttribute('data-sortBy')){
89
+
90
+ let sort = tableElement.getAttribute('data-sort') == "ascending" ? "descending" : "ascending";
91
+
92
+ Array.from(tableElement.querySelectorAll('[data-sortable]')).forEach((col, index) => {
93
+ if(col.textContent == tableElement.getAttribute('data-sortBy')){
94
+ col.setAttribute('aria-sort',sort)
95
+ col.click();
96
+ }
97
+ });
98
+ }
99
+
100
+ // #endregion Sortable
101
+
102
+ // #region Filters
103
+ const createFilterForm = function(count){
104
+
105
+ // Create wrapper div
106
+ const form = document.createElement("div");
107
+ form.classList.add('table__filters');
108
+ form.classList.add('row');
109
+ form.classList.add('pt-1');
110
+ form.classList.add('pb-3');
111
+
112
+ // Create the filter options array
113
+ const filterColumns = Array.from(tableElement.querySelectorAll('th[data-filterable]'));
114
+
115
+ // Populate a list of searchable terms from the cells of the columns that could be used as a filter
116
+ let searchableTerms = {};
117
+ filterColumns.forEach((columnHeading, index) => {
118
+ Array.from(tableElement.querySelectorAll('td[data-label="'+columnHeading.textContent+'"]')).forEach((label, index) => {
119
+
120
+ searchableTerms[label.textContent] = label.textContent;
121
+ });
122
+ });
123
+
124
+ // Create the form
125
+ const filterTitle = filterColumns.length == 1 ? "Filter by "+filterColumns[0].textContent : "Filter"; // Update title if only one filter is chosen
126
+ const checkboxClass = filterColumns.length == 1 ? "d-none" : "d-sm-flex"; // Hide controls when only one filter is chosen
127
+
128
+ form.innerHTML = `<div class="col-sm-6 col-md-4 pb-3">
129
+ <div class="form-control__wrapper form-control-inline mb-0">
130
+ <label for="${randID}_filter" class="form-label">${filterTitle}:</label>
131
+ <input type="search" name="${randID}_filter" id="${randID}_filter" class="form-control form-control-sm" placeholder="" list="${randID}_list" />
132
+ </div>
133
+ <datalist id="${randID}_list">
134
+ ${Object.keys(searchableTerms).map(term => `<option value="${term}"></option>`).join("")}
135
+ </datalist>
136
+ </div>
137
+ <div class="col-md-8 align-items-center pb-3 ${checkboxClass}">
138
+ ${`<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("")}
139
+ </div>`;
140
+
141
+ // Add before the actual table
142
+ tableElement.prepend(form)
143
+ }
144
+
145
+ const filterTable = function(searchTerm){
146
+
147
+ // Create an array of rows that match the search term
148
+ let tableArr = [];
149
+ Array.from(storedData.querySelectorAll('tr')).forEach((tableRow, index) => {
150
+
151
+ // We want one long search string per row including each filterable table cell
152
+ let rowSearchString = '';
153
+ Array.from(tableElement.querySelectorAll('[type="checkbox"]:checked + label')).forEach((label, index) => {
154
+ rowSearchString += tableRow.querySelector('td[data-label="'+label.textContent+'"]').textContent+' | ';
155
+ });
156
+
157
+ // Check if the table row search string contains the search term
158
+ if(rowSearchString.indexOf(searchTerm) >= 0){
159
+
160
+ const dataRow = { row: tableRow }
161
+ tableArr.push(dataRow);
162
+ }
163
+ });
164
+
165
+ // Create a string to return and populate the tbody
166
+ let strTbody = '';
167
+ tableArr.forEach((tableRow, index) => {
168
+ strTbody += tableRow.row.outerHTML;
169
+ });
170
+ tbody.innerHTML = strTbody;
171
+
172
+ // Dispatch the filter event.
173
+ tableElement.dispatchEvent(filteredEvent);
174
+ }
175
+
176
+ const createFilterList = function(){
177
+
178
+ // Check which options are checked
179
+ let filterOptions = [];
180
+ Array.from(tableElement.querySelectorAll('[type="checkbox"]:checked + label')).forEach((label, index) => {
181
+ filterOptions.push(label.textContent);
182
+ });
183
+
184
+ // Build up the list of searchable terms
185
+ let searchableTerms = [];
186
+ filterOptions.forEach((option, index) => {
187
+ Array.from(tableElement.querySelectorAll('td[data-label="'+option+'"]')).forEach((label, index) => {
188
+ searchableTerms[label.textContent] = label.textContent;
189
+ });
190
+ });
191
+
192
+ // Rebuild the list
193
+ let dataList = tableElement.querySelector('datalist');
194
+ dataList.innerHTML = Object.keys(searchableTerms).map(term => `<option value="${term}"></option>`).join("");
195
+ }
196
+
197
+ // On page load check if filters are needed
198
+ if(Array.from(tableElement.querySelectorAll('[data-filterable]')).length){
199
+
200
+ // Create the filter options
201
+ createFilterForm(tableElement,Array.from(tableElement.querySelectorAll('[data-filterable]')).length);
202
+
203
+ // Add event handlers for the filter options
204
+ tableElement.addEventListener('keyup', function(e){
205
+ for (var target = e.target; target && target != this; target = target.parentNode) {
206
+ if (target.matches('input[type="search"]')) {
207
+
208
+ const searchTerm = target.value;
209
+ filterTable(searchTerm)
210
+ }
211
+ }
212
+ });
213
+
214
+ tableElement.addEventListener('change', function(e){
215
+ for (var target = e.target; target && target != this; target = target.parentNode) {
216
+ if (target.matches('input[type="search"]')) {
217
+
218
+ const searchTerm = target.value;
219
+ filterTable(searchTerm)
220
+ }
221
+ }
222
+ });
223
+
224
+ tableElement.addEventListener('change', function(e){
225
+ for (var target = e.target; target && target != this; target = target.parentNode) {
226
+ if (target.matches('input[type="checkbox"]')) {
227
+
228
+ const searchTerm = tableElement.querySelector('input[type="search"]').value;
229
+ filterTable(searchTerm)
230
+ createFilterList()
231
+ }
232
+ }
233
+ });
234
+ }
235
+ // #endregion Filters
236
+
237
+ // #region Pagination
238
+ const paginateRows = function(show, page){
239
+
240
+ // Create some inline CSS to control what is viewed on the table, unline the filters we are just hiding the rable rows not removing them from the DOM.
241
+ let style = document.getElementById(randID+'_style');
242
+
243
+ if(style == null){
244
+ style = document.createElement("style");
245
+ style.setAttribute('id',randID+'_style')
246
+ }
247
+
248
+ const startShowing = (show*(page-1))+1;
249
+ const stopShowing = show*(page);
250
+
251
+ style.innerHTML = `
252
+ #${randID} tbody tr {
253
+ display: none;
254
+ }
255
+ #${randID} tbody tr:nth-child(${startShowing}),
256
+ #${randID} tbody tr:nth-child(${startShowing}) ~ tr{
257
+ display: table-row;
258
+ }
259
+ #${randID} tbody tr:nth-child(${stopShowing}) ~ tr{
260
+ display: none;
261
+ }
262
+ `;
263
+
264
+ tableElement.append(style);
265
+ }
266
+
267
+ const createPaginationForm = function(show,page,totalRows){
268
+
269
+ const form = document.createElement("div");
270
+ form.classList.add('table__pagination');
271
+ form.classList.add('row');
272
+ form.classList.add('pt-3');
273
+ form.classList.add('pb-3');
274
+
275
+ // Create the form and create a container div to hold the pagination buttons
276
+ form.innerHTML = `<div class="col-6 col-sm-3 col-md-2 mb-3">
277
+ <div class="form-control__wrapper form-control-inline mb-0">
278
+ <label for="${randID}_showing" class="form-label">Showing:</label>
279
+ <input type="number" name="${randID}_showing" id="${randID}_showing" class="form-control form-control-sm" placeholder="" list="${randID}_pagination" value="${show}" min="1" max="${totalRows}" />
280
+ </div>
281
+ <datalist id="${randID}_pagination">
282
+ <option value="5">5</option>
283
+ ${totalRows > 10 ? `<option value="10">10</option>` : ''}
284
+ ${totalRows > 20 ? `<option value="20">20</option>` : ''}
285
+ <option value="${totalRows}">${totalRows}</option>
286
+ </datalist>
287
+ </div>
288
+ <div class="col-6 col-sm-2 col-md-2 d-flex align-items-center mb-3"><span class="label">per page</span></div>
289
+ <div class="col-sm-7 col-md-8 d-sm-flex justify-content-end align-items-center mb-3" id="${randID}_paginationBtns"></div>`;
290
+
291
+ // Add after the actual table
292
+ tableElement.append(form)
293
+ }
294
+
295
+ const createPaginationButttons = function(show,page,totalRows){
296
+
297
+ const paginationButtonsWrapper = document.getElementById(randID+'_paginationBtns')
298
+
299
+ if(paginationButtonsWrapper == null)
300
+ return false;
301
+
302
+ const numberPages = Math.ceil(totalRows / show)
303
+
304
+ if(numberPages == 1){ // Remore the buttons or dont display any if we dont need them
305
+ paginationButtonsWrapper.innerHTML = '';
306
+ }
307
+ else if(numberPages < 5){ // If less than 5 pages (which fits comfortably on mobile) we display buttons
308
+
309
+ let strButtons = '';
310
+
311
+ for (let i = 1; i <= numberPages; i++) {
312
+
313
+ if(i == page)
314
+ strButtons += `<li class="page-item active" aria-current="page"><span class="page-link">${i}</span></li>`;
315
+ else
316
+ strButtons += `<li class="page-item"><button class="page-link" data-page="${i}">${i}</button></li>`;
317
+ }
318
+
319
+ paginationButtonsWrapper.innerHTML = `<span class="pe-2">Page: </span><ul class="pagination mb-0">
320
+ ${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>`}
321
+ ${strButtons}
322
+ ${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>`}
323
+ </ul>`;
324
+
325
+ }
326
+ else { // If more than 5 lets show a select field instead so that we dont have loads and loads of buttons
327
+
328
+ let strOptions = '';
329
+
330
+ for (let i = 1; i <= numberPages; i++) {
331
+
332
+ if(i == page)
333
+ strOptions += `<option value="${i}" selected>Page ${i}</option>`;
334
+ else
335
+ strOptions += `<option value="${i}">Page ${i}</option>`;
336
+ }
337
+
338
+ paginationButtonsWrapper.innerHTML = `
339
+ <select class="form-select mb-3">
340
+ ${strOptions}
341
+ </select>
342
+ `;
343
+ }
344
+ }
345
+
346
+ // On page load check if the table should be paginated
347
+ if(tableElement.getAttribute('data-show')){
348
+
349
+ const show = parseInt(tableElement.getAttribute('data-show'));
350
+ const page = parseInt(tableElement.getAttribute('data-page')) ? parseInt(tableElement.getAttribute('data-page')) : 1;
351
+ const totalRows = tableElement.querySelectorAll('tbody tr').length;
352
+
353
+ if(show < totalRows){
354
+ paginateRows(show,page);
355
+ createPaginationForm(show,page,totalRows);
356
+ createPaginationButttons(show,page,totalRows);
357
+
358
+ tableElement.addEventListener('change', function(e){
359
+ for (var target = e.target; target && target != this; target = target.parentNode) {
360
+ if (target.matches('.table__pagination input[type="number"]')) {
361
+
362
+ paginateRows(target.value,page);
363
+ createPaginationButttons(target.value,page,totalRows);
364
+ tableElement.setAttribute('data-show',target.value)
365
+ }
366
+ }
367
+ });
368
+
369
+ tableElement.addEventListener('click', function(e){
370
+ for (var target = e.target; target && target != this; target = target.parentNode) {
371
+ if (target.matches('.page-item:not(.active):not(.disabled) .page-link')) {
372
+
373
+ paginateRows(tableElement.getAttribute('data-show'),target.getAttribute('data-page'));
374
+ createPaginationButttons(tableElement.getAttribute('data-show'),target.getAttribute('data-page'),totalRows);
375
+ }
376
+ }
377
+ }, false);
378
+
379
+ tableElement.addEventListener('change', function(e){
380
+ for (var target = e.target; target && target != this; target = target.parentNode) {
381
+ if (target.matches('.table__pagination select')) {
382
+
383
+ paginateRows(tableElement.getAttribute('data-show'),target.value);
384
+ createPaginationButttons(tableElement.getAttribute('data-show'),target.value,totalRows);
385
+ }
386
+ }
387
+ });
388
+ }
389
+ }
390
+ // #endregion Pagination
391
+
392
+ // #region Reorderable
393
+ // Set the row thats being dragged and copy the row
394
+ function setDraggedRow(e) {
395
+ e.dataTransfer.setData("text/plain", e.target.id);
396
+ draggedRow = e.target;
397
+ e.target.classList.add('tr--dragging');
398
+ }
399
+
400
+ // Create the order column and event handler for rows
401
+ const setReorderRows = function(){
402
+
403
+ Array.from(tbody.querySelectorAll('tr')).forEach((tableRow, index) => {
404
+
405
+ // Create column if not already created
406
+ if(tableRow.querySelector('[data-label="Order"]') == null){
407
+
408
+ const orderColumn = document.createElement('th');
409
+ orderColumn.innerHTML = index + 1;
410
+ orderColumn.setAttribute('data-label','Order');
411
+ tableRow.prepend(orderColumn);
412
+ }
413
+
414
+ // Make draggable
415
+ tableRow.setAttribute('id',randID+'_row_'+(index+1));
416
+ tableRow.setAttribute('data-order',index+1);
417
+ tableRow.setAttribute('draggable','true');
418
+ tableRow.addEventListener("dragstart", setDraggedRow);
419
+ });
420
+ }
421
+
422
+ if(tableElement.getAttribute('data-reorder')){
423
+
424
+ // Add column heading
425
+ const orderHeading = document.createElement('th');
426
+ orderHeading.innerHTML = 'Order';
427
+ orderHeading.classList.add('table-order-reset');
428
+ thead.querySelector('tr').prepend(orderHeading);
429
+
430
+ setReorderRows();
431
+
432
+ // Reset order button
433
+ tableElement.addEventListener('click', function(e){
434
+ for (var target = e.target; target && target != this; target = target.parentNode) {
435
+ if (target.matches('.table-order-reset')) {
436
+
437
+ // unset sort attributes
438
+ Array.from(tableElement.querySelectorAll('[data-sortable]')).forEach((col, index) => {
439
+ col.setAttribute('aria-sort','none');
440
+ });
441
+
442
+ // Save the sort options on the table element so that it can be re-sorted later
443
+ tableElement.removeAttribute('data-sort');
444
+ tableElement.removeAttribute('data-sortBy');
445
+
446
+ // Sort the table
447
+ sortTable('Order', 'ascending');
448
+
449
+ Array.from(tableElement.querySelectorAll('tbody tr')).forEach((tableRow, index) => {
450
+
451
+ tableRow.setAttribute('draggable','true');
452
+ });
453
+
454
+ break;
455
+ }
456
+ }
457
+ }, false);
458
+
459
+
460
+ document.addEventListener("dragover", function( e ) {
461
+ // prevent default to allow drop
462
+ e.preventDefault();
463
+ }, false);
464
+
465
+ document.addEventListener("dragenter", function( e ) {
466
+ // prevent default to allow drop
467
+ e.preventDefault();
468
+ e.dataTransfer.dropEffect = "move";
469
+
470
+ for (var target = e.target; target && target != this; target = target.parentNode) {
471
+ if (target.matches('[data-reorder] tbody tr')) {
472
+
473
+ target.classList.add('tr--dropable')
474
+ }
475
+ }
476
+ }, false);
477
+
478
+ document.addEventListener("dragleave", function( e ) {
479
+ // prevent default to allow drop
480
+ e.preventDefault();
481
+ for (var target = e.target; target && target != this; target = target.parentNode) {
482
+ if (target.matches('[data-reorder] tbody tr')) {
483
+
484
+ target.classList.remove('tr--dropable')
485
+ }
486
+ }
487
+ }, false);
488
+
489
+ document.addEventListener("drop", function(e) {
490
+
491
+ e.preventDefault();
492
+
493
+ for (var target = e.target; target && target != this; target = target.parentNode) {
494
+ if (target.matches('[data-reorder] tbody tr')) {
495
+
496
+ if(target.parentNode != null && draggedRow.parentNode != null && target != draggedRow){
497
+
498
+ draggedRow.parentNode.removeChild( draggedRow );
499
+
500
+ if(draggedRow.getAttribute('data-order') > target.getAttribute('data-order'))
501
+ target.parentNode.insertBefore(draggedRow, target);
502
+ else
503
+ target.parentNode.insertBefore(draggedRow, target.nextElementSibling);
504
+
505
+ // Re label the rows
506
+ Array.from(tbody.querySelectorAll('tr')).forEach((tableRowOrder, index) => {
507
+ tableRowOrder.classList.remove('tr--dragging')
508
+ tableRowOrder.classList.remove('tr--dropable')
509
+ tableRowOrder.querySelector('th').innerHTML = index + 1;
510
+ tableRowOrder.setAttribute('data-order',index+1);
511
+ });
512
+ }
513
+ break;
514
+ }
515
+ }
516
+ }, false);
517
+
518
+ }
519
+ // #endregion Reorderable
520
+
521
+ // Watch for the filterable event and re-sort the tbody
522
+ tableElement.addEventListener('filtered', function (e) {
523
+
524
+ if(tableElement.getAttribute('data-sortBy') && tableElement.getAttribute('data-sort'))
525
+ sortTable(tableElement.getAttribute('data-sortBy'), tableElement.getAttribute('data-sort'));
526
+
527
+ if(tableElement.getAttribute('data-show')){
528
+
529
+ const show = parseInt(tableElement.getAttribute('data-show'));
530
+ const totalRows = tableElement.querySelectorAll('tbody tr').length;
531
+ const tablePagination = tableElement.querySelector('.table__pagination');
532
+
533
+ if(tablePagination != null)
534
+ tablePagination.remove();
535
+
536
+ if(show < totalRows){
537
+
538
+ paginateRows(show,1);
539
+ createPaginationForm(show,1,totalRows);
540
+ createPaginationButttons(show,1,totalRows);
541
+ }
542
+ }
543
+
544
+ if(tableElement.getAttribute('data-reorder')){
545
+
546
+ setReorderRows();
547
+ }
548
+ }, false);
549
+
550
+ tableElement.addEventListener('sorted', function (e) {
551
+
552
+ if(tableElement.getAttribute('data-reorder')){
553
+
554
+ setReorderRows();
555
+ }
556
+ }, false);
557
+
558
+ tableElement.addEventListener('populated', function (e) {
559
+
560
+ var tableFilter = tableElement.querySelector('.table__filters')
561
+ tableFilter.remove();
562
+
563
+ var tablePagination = tableElement.querySelector('.table__pagination')
564
+ tablePagination.remove();
565
+
566
+ var newTable = tableElement.cloneNode(true);
567
+ tableElement.parentNode.replaceChild(newTable, tableElement);
568
+
569
+ table(newTable);
570
+ }, false);
571
+ }
572
+
573
+ export default table
@@ -0,0 +1,83 @@
1
+ function testimonial(testimonialElement) {
2
+
3
+ var scrollTimeout;
4
+ const imagesCarousel = testimonialElement.querySelector('.testimonial__images');
5
+ const itemCount = imagesCarousel.querySelectorAll('img').length;
6
+
7
+ // If we only have 1 item lets not bother doing anything else
8
+ if(itemCount == 1){
9
+ return false;
10
+ }
11
+
12
+ testimonialElement.classList.add('testimonial--multi')
13
+
14
+ // Set where the buttons go to
15
+ const setButtons = function(scrollTo){
16
+
17
+ const nextButton = testimonialElement.querySelector('.btn-next');
18
+ const prevButton = testimonialElement.querySelector('.btn-prev');
19
+
20
+ nextButton.setAttribute('data-go',scrollTo+1);
21
+ prevButton.setAttribute('data-go',scrollTo-1);
22
+ nextButton.removeAttribute('disabled')
23
+ prevButton.removeAttribute('disabled')
24
+
25
+ if(scrollTo == 1)
26
+ prevButton.setAttribute('disabled',true);
27
+ else if(scrollTo == itemCount)
28
+ nextButton.setAttribute('disabled',true);
29
+ }
30
+
31
+ // On scroll we need to make sure the buttons get corrected and the next testimonial is shown
32
+ imagesCarousel.addEventListener('scroll', function(e){
33
+ clearTimeout(scrollTimeout);
34
+ scrollTimeout = setTimeout(function(){
35
+
36
+ let scrollWidth = imagesCarousel.scrollWidth;
37
+ let scrollHeight = imagesCarousel.scrollHeight;
38
+ let scrollLeft = imagesCarousel.scrollLeft;
39
+ let scrollDown = imagesCarousel.scrollTop;
40
+ let scrollTo = Math.round((scrollLeft / scrollWidth) * itemCount) + 1;
41
+
42
+ // Change in scroll direction
43
+ if(scrollLeft == 0 && scrollDown != 0)
44
+ scrollTo = Math.round((scrollDown / scrollHeight) * itemCount) + 1;
45
+
46
+ testimonialElement.setAttribute('data-show',scrollTo)
47
+ setButtons(scrollTo);
48
+ }, 300);
49
+
50
+ }, false);
51
+
52
+ // when the buttons are used we need to make sure the carousel scrolls to the correct place
53
+ testimonialElement.addEventListener('click', function(e){
54
+
55
+ for (var target = e.target; target && target != this; target = target.parentNode) {
56
+
57
+ if (target.matches('[data-go]')) {
58
+
59
+ let scrollTo = parseInt(target.getAttribute('data-go'));
60
+ let scrollDown = 0;
61
+ let scrollLeft = 0
62
+ let scrollWidth = imagesCarousel.scrollWidth;
63
+ let scrollHeight = imagesCarousel.scrollHeight;
64
+
65
+ if(scrollWidth > scrollHeight)
66
+ scrollLeft = Math.floor(scrollWidth * ((scrollTo-1) / itemCount))
67
+ else
68
+ scrollDown = Math.floor(scrollHeight * ((scrollTo-1) / itemCount))
69
+
70
+ // Trigger the scroll
71
+ imagesCarousel.scroll({
72
+ top: scrollDown,
73
+ left: scrollLeft,
74
+ behavior: 'smooth'
75
+ });
76
+
77
+ break;
78
+ }
79
+ }
80
+ }, false);
81
+ }
82
+
83
+ export default testimonial