[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 Joomla = window.Joomla || {}; 2 3 (Joomla => { 4 /** 5 * Method that resets the filter inputs and submits the relative form 6 * 7 * @param {HTMLElement} element The element that initiates the call 8 * @returns {void} 9 * @since 4.0.0 10 */ 11 12 Joomla.resetFilters = element => { 13 const { 14 form 15 } = element; 16 17 if (!form) { 18 throw new Error('Element must be inside a form!'); 19 } 20 21 const elementsArray = [].slice.call(form.elements); 22 23 if (elementsArray.length) { 24 const newElementsArray = []; 25 elementsArray.forEach(elem => { 26 // Skip the token, the task, the boxchecked and the calling element 27 if (elem.getAttribute('name') === 'task' || elem.getAttribute('name') === 'boxchecked' || elem.value === '1' && /^[0-9A-F]{32}$/i.test(elem.name) || elem === element) { 28 return; 29 } 30 31 newElementsArray.push(elem); 32 }); // Reset all filters 33 34 newElementsArray.forEach(elem => { 35 elem.value = ''; 36 }); 37 form.submit(); 38 } 39 }; 40 41 class Searchtools { 42 constructor(elem, options) { 43 const defaults = { 44 // Form options 45 formSelector: '.js-stools-form', 46 // Search 47 searchFieldSelector: '.js-stools-field-search', 48 clearBtnSelector: '.js-stools-btn-clear', 49 // Global container 50 mainContainerSelector: '.js-stools', 51 // Filter fields 52 searchBtnSelector: '.js-stools-btn-search', 53 filterBtnSelector: '.js-stools-btn-filter', 54 filterContainerSelector: '.js-stools-container-filters', 55 filtersHidden: true, 56 // List fields 57 listBtnSelector: '.js-stools-btn-list', 58 listContainerSelector: '.js-stools-container-list', 59 listHidden: true, 60 // Ordering specific 61 orderColumnSelector: '.js-stools-column-order', 62 orderBtnSelector: '.js-stools-btn-order', 63 orderFieldSelector: '.js-stools-field-order', 64 orderFieldName: 'list[fullordering]', 65 limitFieldSelector: '.js-stools-field-limit', 66 defaultLimit: 20, 67 activeOrder: null, 68 activeDirection: 'ASC', 69 // Extra 70 clearListOptions: false 71 }; 72 this.element = elem; 73 this.options = Joomla.extend(defaults, options); // Initialise selectors 74 75 this.theForm = document.querySelector(this.options.formSelector); // Filters 76 77 this.filterButton = document.querySelector(`$this.options.formSelector} $this.options.filterBtnSelector}`); 78 this.filterContainer = document.querySelector(`$this.options.formSelector} $this.options.filterContainerSelector}`) ? document.querySelector(`$this.options.formSelector} $this.options.filterContainerSelector}`) : ''; 79 this.filtersHidden = this.options.filtersHidden; // List fields 80 81 this.listButton = document.querySelector(this.options.listBtnSelector); 82 this.listContainer = document.querySelector(`$this.options.formSelector} $this.options.listContainerSelector}`); 83 this.listHidden = this.options.listHidden; // Main container 84 85 this.mainContainer = document.querySelector(this.options.mainContainerSelector); // Search 86 87 this.searchButton = document.querySelector(`$this.options.formSelector} $this.options.searchBtnSelector}`); 88 this.searchField = document.querySelector(`$this.options.formSelector} $this.options.searchFieldSelector}`); 89 this.searchString = null; 90 this.clearButton = document.querySelector(this.options.clearBtnSelector); // Ordering 91 92 this.orderCols = Array.prototype.slice.call(document.querySelectorAll(`$this.options.formSelector} $this.options.orderColumnSelector}`)); 93 this.orderField = document.querySelector(`$this.options.formSelector} $this.options.orderFieldSelector}`); // Limit 94 95 this.limitField = document.querySelector(`$this.options.formSelector} $this.options.limitFieldSelector}`); // Init trackers 96 97 this.activeColumn = null; 98 this.activeDirection = this.options.activeDirection; 99 this.activeOrder = this.options.activeOrder; 100 this.activeLimit = null; // Extra options 101 102 this.clearListOptions = this.options.clearListOptions; 103 const self = this; // Get values 104 105 this.searchString = this.searchField ? this.searchField.value : ''; // Do some binding 106 107 this.showFilters = this.showFilters.bind(this); 108 this.hideFilters = this.hideFilters.bind(this); 109 this.showList = this.showList.bind(this); 110 this.hideList = this.hideList.bind(this); 111 this.toggleFilters = this.toggleFilters.bind(this); 112 this.toggleList = this.toggleList.bind(this); 113 this.checkFilter = this.checkFilter.bind(this); 114 this.clear = this.clear.bind(this); 115 this.createOrderField = this.createOrderField.bind(this); 116 this.checkActiveStatus = this.checkActiveStatus.bind(this); 117 this.activeFilter = this.activeFilter.bind(this); 118 this.deactiveFilter = this.deactiveFilter.bind(this); 119 this.getFilterFields = this.getFilterFields.bind(this); 120 this.getListFields = this.getListFields.bind(this); 121 this.hideContainer = this.hideContainer.bind(this); 122 this.showContainer = this.showContainer.bind(this); 123 this.toggleContainer = this.toggleContainer.bind(this); 124 this.toggleDirection = this.toggleDirection.bind(this); 125 this.updateFieldValue = this.updateFieldValue.bind(this); 126 this.findOption = this.findOption.bind(this); 127 128 if (this.filterContainer && this.filterContainer.classList.contains('js-stools-container-filters-visible')) { 129 this.showFilters(); 130 this.showList(); 131 } else { 132 this.hideFilters(); 133 this.hideList(); 134 } 135 136 if (this.filterButton) { 137 this.filterButton.addEventListener('click', e => { 138 self.toggleFilters(); 139 e.stopPropagation(); 140 e.preventDefault(); 141 }); 142 } 143 144 if (this.listButton) { 145 this.listButton.addEventListener('click', e => { 146 self.toggleList(); 147 e.stopPropagation(); 148 e.preventDefault(); 149 }); 150 } // Do we need to add to mark filter as enabled? 151 152 153 this.getFilterFields().forEach(i => { 154 self.checkFilter(i); 155 i.addEventListener('change', () => { 156 self.checkFilter(i); 157 }); 158 }); 159 160 if (this.clearButton) { 161 this.clearButton.addEventListener('click', self.clear); 162 } // Check/create ordering field 163 164 165 this.createOrderField(); 166 this.orderCols.forEach(item => { 167 item.addEventListener('click', ({ 168 target 169 }) => { 170 const element = target.tagName.toLowerCase() === 'span' ? target.parentNode : target; // Order to set 171 172 const newOrderCol = element.getAttribute('data-order'); 173 const newDirection = element.getAttribute('data-direction'); 174 const newOrdering = `$newOrderCol} $newDirection}`; // The data-order attribute is required 175 176 if (newOrderCol.length) { 177 self.activeColumn = newOrderCol; 178 179 if (newOrdering !== self.activeOrder) { 180 self.activeDirection = newDirection; 181 self.activeOrder = newOrdering; // Update the order field 182 183 self.updateFieldValue(self.orderField, newOrdering); 184 } else { 185 self.toggleDirection(); 186 } 187 188 self.theForm.submit(); 189 } 190 }); 191 }); 192 this.checkActiveStatus(this); 193 } 194 195 checkFilter(element) { 196 if (element.tagName.toLowerCase() === 'select') { 197 const option = element.querySelector('option:checked'); 198 199 if (option) { 200 if (option.value !== '') { 201 this.activeFilter(element, this); 202 } else { 203 this.deactiveFilter(element, this); 204 } 205 } 206 } else if (element.value !== '') { 207 this.activeFilter(element, this); 208 } else { 209 this.deactiveFilter(element, this); 210 } 211 } 212 213 clear() { 214 const self = this; 215 216 if (self.searchField) { 217 self.searchField.value = ''; 218 } 219 220 self.getFilterFields().forEach(i => { 221 i.value = ''; 222 self.checkFilter(i); 223 224 if (window.jQuery && window.jQuery.chosen) { 225 window.jQuery(i).trigger('chosen:updated'); 226 } 227 }); 228 229 if (self.clearListOptions) { 230 self.getListFields().forEach(i => { 231 i.value = ''; 232 self.checkFilter(i); 233 234 if (window.jQuery && window.jQuery.chosen) { 235 window.jQuery(i).trigger('chosen:updated'); 236 } 237 }); // Special case to limit box to the default config limit 238 239 document.querySelector('#list_limit').value = self.options.defaultLimit; 240 241 if (window.jQuery && window.jQuery.chosen) { 242 window.jQuery('#list_limit').trigger('chosen:updated'); 243 } 244 } 245 246 self.theForm.submit(); 247 } // eslint-disable-next-line class-methods-use-this 248 249 250 updateFilterCount(count) { 251 if (this.clearButton) { 252 this.clearButton.disabled = count === 0 && !this.searchString.length; 253 } 254 } // eslint-disable-next-line class-methods-use-this 255 256 257 checkActiveStatus(cont) { 258 let activeFilterCount = 0; 259 this.getFilterFields().forEach(item => { 260 if (item.classList.contains('active')) { 261 activeFilterCount += 1; 262 cont.filterButton.classList.remove('btn-secondary'); 263 cont.filterButton.classList.add('btn-primary'); 264 } 265 }); // If there are no active filters - remove the filtered caption area from the table 266 267 if (activeFilterCount === 0) { 268 const filteredByCaption = document.getElementById('filteredBy'); 269 270 if (filteredByCaption) { 271 filteredByCaption.parentNode.removeChild(filteredByCaption); 272 } 273 } // Disable clear button when no filter is active and search is empty 274 275 276 if (this.clearButton) { 277 this.clearButton.disabled = activeFilterCount === 0 && !this.searchString.length; 278 } 279 } // eslint-disable-next-line class-methods-use-this 280 281 282 activeFilter(element) { 283 element.classList.add('active'); 284 const chosenId = `#$element.getAttribute('id')}`; 285 const tmpEl = element.querySelector(chosenId); 286 287 if (tmpEl) { 288 tmpEl.classList.add('active'); 289 } // Add all active filters to the table caption for screen-readers 290 291 292 const filteredByCaption = document.getElementById('filteredBy'); 293 const isHidden = Object.prototype.hasOwnProperty.call(element.attributes, 'type') && element.attributes.type.value === 'hidden'; // The caption won't exist if no items match the filters so check for the element first 294 295 if (filteredByCaption && !isHidden) { 296 let captionContent = ''; 297 298 if (element.tagName.toLowerCase() === 'select') { 299 if (element.multiple === true) { 300 const selectedOptions = element.querySelectorAll('option:checked'); 301 const selectedTextValues = [].slice.call(selectedOptions).map(el => el.text); 302 captionContent = `$element.labels[0].textContent} - $selectedTextValues.join()}`; 303 } else { 304 captionContent = `$element.labels[0].textContent} - $element.options[element.selectedIndex].text}`; 305 } 306 } else { 307 captionContent = `$element.labels[0].textContent} - $element.value}`; 308 } 309 310 filteredByCaption.textContent += captionContent; 311 } 312 } // eslint-disable-next-line class-methods-use-this 313 314 315 deactiveFilter(element) { 316 element.classList.remove('active'); 317 const chosenId = `#$element.getAttribute('id')}`; 318 const tmpEl = element.querySelector(chosenId); 319 320 if (tmpEl) { 321 tmpEl.classList.remove('active'); 322 } 323 } // eslint-disable-next-line consistent-return 324 325 326 getFilterFields() { 327 if (this.filterContainer) { 328 return Array.prototype.slice.call(this.filterContainer.querySelectorAll('select,input')); 329 } 330 331 return []; 332 } 333 334 getListFields() { 335 return Array.prototype.slice.call(this.listContainer.querySelectorAll('select')); 336 } // Common container functions 337 // eslint-disable-next-line class-methods-use-this 338 339 340 hideContainer(container) { 341 if (container) { 342 container.classList.remove('js-stools-container-filters-visible'); 343 document.body.classList.remove('filters-shown'); 344 } 345 } // eslint-disable-next-line class-methods-use-this 346 347 348 showContainer(container) { 349 container.classList.add('js-stools-container-filters-visible'); 350 document.body.classList.add('filters-shown'); 351 } 352 353 toggleContainer(container) { 354 if (container.classList.contains('js-stools-container-filters-visible')) { 355 this.hideContainer(container); 356 } else { 357 this.showContainer(container); 358 } 359 } // List container management 360 361 362 hideList() { 363 this.hideContainer(this.filterContainer); 364 } 365 366 showList() { 367 this.showContainer(this.filterContainer); 368 } 369 370 toggleList() { 371 this.toggleContainer(this.filterContainer); 372 } // Filters container management 373 374 375 hideFilters() { 376 this.hideContainer(this.filterContainer); 377 } 378 379 showFilters() { 380 this.showContainer(this.filterContainer); 381 } 382 383 toggleFilters() { 384 this.toggleContainer(this.filterContainer); 385 } 386 387 toggleDirection() { 388 const self = this; 389 let newDirection = 'ASC'; 390 391 if (self.activeDirection.toUpperCase() === 'ASC') { 392 newDirection = 'DESC'; 393 } 394 395 self.activeDirection = newDirection; 396 self.activeOrder = `$self.activeColumn} $newDirection}`; 397 self.updateFieldValue(self.orderField, self.activeOrder); 398 } 399 400 createOrderField() { 401 const self = this; 402 403 if (!this.orderField) { 404 this.orderField = document.createElement('input'); 405 this.orderField.setAttribute('type', 'hidden'); 406 this.orderField.setAttribute('id', 'js-stools-field-order'); 407 this.orderField.setAttribute('class', 'js-stools-field-order'); 408 this.orderField.setAttribute('name', self.options.orderFieldName); 409 this.orderField.setAttribute('value', `$self.activeOrder} $this.activeDirection}`); 410 this.theForm.append(this.orderField); 411 } // Add missing columns to the order select 412 413 414 if (this.orderField.tagName.toLowerCase() === 'select') { 415 const allOptions = [].slice.call(this.orderField.options); 416 allOptions.forEach(option => { 417 let value = option.getAttribute('data-order'); 418 const name = option.getAttribute('data-name'); 419 const direction = option.getAttribute('data-direction'); 420 421 if (value && value.length) { 422 value = `$value} $direction}`; 423 let $option = self.findOption(self.orderField, value); 424 425 if (!$option.length) { 426 $option = document.createElement('option'); 427 $option.text = name; 428 $option.value = value; // If it is the active option select it 429 430 if (option.classList.contains('active')) { 431 $option.setAttribute('selected', 'selected'); 432 } // Append the option and repopulate the chosen field 433 434 435 this.orderFieldName.innerHTML += Joomla.sanitizeHtml($option); 436 } 437 } 438 }); 439 440 if (window.jQuery && window.jQuery.chosen) { 441 window.jQuery(this.orderField).trigger('chosen:updated'); 442 } 443 } 444 445 this.activeOrder = this.orderField.value; 446 } // eslint-disable-next-line class-methods-use-this 447 448 449 updateFieldValue(field, newValue) { 450 const type = field.getAttribute('type'); 451 452 if (type === 'hidden' || type === 'text') { 453 field.setAttribute('value', newValue); 454 } else if (field.tagName.toLowerCase() === 'select') { 455 const allOptions = [].slice.call(field.options); 456 let desiredOption; // Select the option result 457 458 allOptions.forEach(option => { 459 if (option.value === newValue) { 460 desiredOption = option; 461 } 462 }); 463 464 if (desiredOption && desiredOption.length) { 465 desiredOption.setAttribute('selected', 'selected'); 466 } else { 467 // If the option does not exist create it on the fly 468 const option = document.createElement('option'); 469 option.text = newValue; 470 option.value = newValue; 471 option.setAttribute('selected', 'selected'); // Append the option and repopulate the chosen field 472 473 field.appendChild(option); 474 } 475 476 field.value = newValue; // Trigger the chosen update 477 478 if (window.jQuery && window.jQuery.chosen) { 479 field.trigger('chosen:updated'); 480 } 481 } 482 } // eslint-disable-next-line class-methods-use-this,consistent-return 483 484 485 findOption(select, value) { 486 // eslint-disable-next-line no-plusplus 487 for (let i = 0, l = select.length; l > i; i++) { 488 if (select[i].value === value) { 489 return select[i]; 490 } 491 } 492 } 493 494 } 495 496 const onBoot = () => { 497 if (Joomla.getOptions('searchtools')) { 498 const options = Joomla.getOptions('searchtools'); 499 const element = document.querySelector(options.selector); // eslint-disable-next-line no-new 500 501 new Searchtools(element, options); 502 } 503 504 const sort = document.getElementById('sorted'); 505 const order = document.getElementById('orderedBy'); 506 507 if (sort && sort.hasAttribute('data-caption') && order) { 508 const orderedBy = sort.getAttribute('data-caption'); 509 order.textContent += orderedBy; 510 } 511 512 if (sort && sort.hasAttribute('data-sort')) { 513 const ariasort = sort.getAttribute('data-sort'); 514 sort.parentNode.setAttribute('aria-sort', ariasort); 515 } // Cleanup 516 517 518 document.removeEventListener('DOMContentLoaded', onBoot); 519 }; // Execute on DOM Loaded Event 520 521 522 document.addEventListener('DOMContentLoaded', onBoot); 523 })(Joomla);
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |