1/** 2 * 3 */ 4(function ($, drupalSettings, Vue) { 5 'use strict'; 6 const msInDay = 1000 * 60 * 60 * 24; 7 var d = new Date(); 8 // Bucketed to bound route-cache key cardinality (~10^16 -> 100 distinct 9 // values); the seed is stripped from the module's own cache key anyway, 10 // so this only affects Drupal's route cache. See issue #390. 11 var random = Math.floor(Math.random() * 100) / 100; 12 Vue.config.devtools = true; 13 14 $('[data-cbis-product-list]').each(function () { 15 var $this = $(this); 16 var nodeId = $this.data('cbis-product-list'); 17 var facilityGroupsOperatorBetweenGroups = $this.data('facility-groups-operator-between-groups') || 'AND'; 18 var facilityGroupsOperatorBetweenFacilitiesInSameGroup = $this.data('facility-groups-operator-between-facilities-in-same-group') || 'AND'; 19 var settings = drupalSettings.productList[nodeId]; 20 var occasionsSelectType = $this.data('occasions-select-type') ?? null; 21 var oneValuePerCustomFacilititesFilter = $this.data('one-per-custom-facilities-filter') ?? null; 22 var occasionsDefaultValue = null; 23 24 switch ($this.data('occasions-default-value')) { 25 case 'today': 26 occasionsDefaultValue = new Date(); 27 break; 28 case 'tomorrow': 29 occasionsDefaultValue = new Date(+new Date() + 86400000); 30 break; 31 } 32 if (settings.viewMode.substring(0, 4) !== 'list' && !settings.viewMode.includes('slideshow')) { 33 return; 34 } 35 new Vue({ 36 el: this, 37 delimiters: ['<%', '%>'], 38 data: { 39 node: nodeId, 40 payload: null, 41 busy: false, // Prevent multiple simultaneous loads 42 allProductsLoaded: false, 43 page: -1, 44 pageSize: settings.viewMode.includes('slideshow') ? 20 : null, // Only set pageSize for slideshow modes 45 fail: false, 46 items: [], 47 order: settings.order, 48 flyingXhr: null, 49 categoryTree: settings.categoryTree, 50 unfilteredCategoryTree: settings.unfilteredCategoryTree || {children: []}, 51 monthData: settings.monthData, 52 geoTree: settings.geoTree, 53 arenas: settings.arenas, 54 arenaFilter: settings.arenaFilter, 55 facilities: settings.facilities, 56 maxProducts: settings.maxProducts, 57 showOccasionChooser: settings.showOccasionChooser, 58 totalFilter: 0, 59 totalCount: 0, 60 occasionCount: 0, 61 isDesktop: false, 62 isExplorer: false, 63 linkTitle: settings.linkTitle || null, 64 linkUrl: settings.linkUrl || null, 65 filter: { 66 categories: [], 67 geos: [], 68 arenas: [], 69 facilities: [], 70 search: '', 71 }, 72 showFilter: { 73 all: false, 74 categories: false, 75 geos: false, 76 arenas: false, 77 facilities: false,
78 facilityMonths: false, 79 occasions: false, 80 extraFilter1: false, 81 extraFilter2: false, 82 extraFilter3: false, 83 extraFilter4: false, 84 extraFilter5: false, 85 extraFilter6: false, 86 extraFilter7: false, 87 }, 88 facilityMonths: [], 89 facilityWithoutMonths: [], 90 filteredFacilitySelection: [], 91 drag: null, 92 swiper: null, // Store swiper instance 93 isAutoplayPaused: false, // Track autoplay state for pause/play button 94 adItemAdded: false, // Track if ad item has been added 95 occasions: occasionsDefaultValue ?? null, 96 formats: { 97 input: 'D MMM', 98 }, 99 occasionsSelectType: occasionsSelectType, 100 iticketAvailabilityDates: {}, 101 occasionsDefaultValue: occasionsDefaultValue, 102 oneValuePerCustomFacilititesFilter: oneValuePerCustomFacilititesFilter, 103 }, 104 created: function () { 105 this.handleWindowResize(); 106 this.extractMonthsFromFacilitiesAndSort(); 107 this.extractFacilitiesWithoutMonths(); 108 if (this.detectBrowser()) { 109 this.isExplorer = true; 110 } 111 }, 112 mounted: function () { 113 this.loadFilter(); 114 this.loadMore(); 115 window.addEventListener('resize', this.handleWindowResize); 116 117 if (settings.viewMode !== 'list') { 118 this.swiper11Init(); 119 } 120 }, 121 computed: { 122 daySpan: function () { 123 const days = this.getDaySpan(this.drag || this.occasions); 124 return days ? days + ' days' : ''; 125 }, 126 orderByCurrentMonth: function () { 127 var m = d.getMonth(); 128 var currentYear = d.getFullYear(); 129 var oneYearPlus = d.getFullYear() + 1; 130 var fromMonth = this.facilityMonths.splice(m); 131 for (var i = 0; i < fromMonth.length; i++) { 132 fromMonth[i]['year'] = currentYear; 133 } 134 for (var j = 0; j < this.facilityMonths.length; j++) { 135 this.facilityMonths[j]['year'] = oneYearPlus; 136 } 137 return fromMonth.concat(this.facilityMonths); 138 }, 139 skeletonLoaderCount: function () { 140 // Determine how many skeleton loaders to show based on viewport and settings 141 if (this.isDesktop) { 142 // Desktop: use the configured itemsPerSlide or default to 4 143 return settings.itemsPerSlide ? parseInt(settings.itemsPerSlide) : 4; 144 } else if (document.documentElement.clientWidth >= 640) { 145 // Medium devices (tablets): use itemsPerSlideMediumDevice or fallback 146 return settings.itemsPerSlideMediumDevice ? parseInt(settings.itemsPerSlideMediumDevice) : settings.itemsPerSlide > 1 ? 2 : 1; 147 } else { 148 // Small devices (mobile): use itemsPerSlideSmallDevice or default to 1 149 return settings.itemsPerSlideSmallDevice ? parseInt(settings.itemsPerSlideSmallDevice) : 1; 150 } 151 }, 152 }, 153 watch: { 154 filter: { 155 handler: function () { 156 this.reset(); 157 this.loadMore(); 158 this.saveFilter(); 159 this.totalFilter = this.filter.categories.length + this.filter.geos.length + this.filter.arenas.length + this.filter.facilities.length + this.occasionCount; 160 }, 161 deep: true, 162 }, 163 occasions: function () { 164 this.reset(); 165 this.loadMore(); 166 this.saveFilter(); 167 if (this.occasions && !this.occasionCount) { 168 this.occasionCount = 1; 169 } 170 this.totalFilter = this.filter.categories.length + this.filter.geos.length + this.filter.arenas.length + this.filter.facilities.length + this.occasionCount; 171 }, 172 iticketAvailabilityDates: function (newVal) { 173 this.reset(); 174 this.loadMore(); 175 this.saveFilter(); 176 }, 177 items: function () { 178 if (this.swiper && settings.viewMode !== 'list') { 179 this.$nextTick(() => { 180 // Update Swiper to recognize new slides
181 this.swiper.update(); 182 183 if (settings.autoPlay) { 184 this.swiper.autoplay.start(); 185 } 186 }); 187 188 // Add pause/play button if autoplay is enabled and items are loaded (only once) 189 if (settings.autoPlay && this.items.length > 0 && !this.autoplayControlButton) { 190 this.addAutoplayControl(); 191 } 192 } 193 }, 194 }, 195 196 methods: { 197 swiper11Init: function () { 198 // Target only the product list swiper using specific class 199 const swiperEl = this.$el.querySelector('.product-list-swiper'); 200 if (!swiperEl) { 201 return; 202 } 203 204 const vue = this; 205 206 // Build Swiper configuration 207 const swiperConfig = { 208 draggable: true, 209 slidesPerView: settings.slidesPerViewAuto ? 'auto' : settings.itemsPerSlideSmallDevice ? parseFloat(settings.itemsPerSlideSmallDevice) : 1, 210 slidesPerColumn: 1, 211 spaceBetween: settings.spaceBetweenSmall ? parseInt(settings.spaceBetweenSmall) : settings.spaceBetween ? parseInt(settings.spaceBetween) : 0, 212 watchOverflow: true, 213 autoplay: settings.autoPlay 214 ? { 215 delay: settings.autoPlayDuration || 3000, 216 disableOnInteraction: false, 217 pauseOnMouseEnter: true, 218 } 219 : false, 220 // Loop mode (Swiper 4.5.3) silently drops slideNext() calls made 221 // while a transition is still animating, so repeated clicks on 222 // the next arrow skip products instead of advancing one-by-one. 223 // Keep autoplay's own advancing, but don't wrap end-to-start. 224 loop: false, 225 breakpoints: { 226 1024: { 227 slidesPerView: settings.slidesPerViewAuto ? 'auto' : settings.itemsPerSlide ? parseFloat(settings.itemsPerSlide) : 3, 228 spaceBetween: settings.spaceBetween ? parseInt(settings.spaceBetween) : 0, 229 slidesPerColumn: settings.slidesPerColumn ? parseInt(settings.slidesPerColumn) : 1, 230 }, 231 640: { 232 slidesPerView: settings.slidesPerViewAuto ? 'auto' : settings.itemsPerSlideMediumDevice ? parseFloat(settings.itemsPerSlideMediumDevice) : settings.itemsPerSlide > 1 ? 2 : 1, 233 spaceBetween: settings.spaceBetweenMedium ? parseInt(settings.spaceBetweenMedium) : settings.spaceBetween ? parseInt(settings.spaceBetween) : 0, 234 }, 235 }, 236 pagination: { 237 el: '.swiper-pagination', 238 dynamicBullets: true, 239 clickable: true, 240 type: settings.paginationType ? settings.paginationType : 'bullets', 241 }, 242 navigation: { 243 nextEl: '.swiper-button-next', 244 prevEl: '.swiper-button-prev', 245 }, 246 a11y: { 247 prevSlideMessage: Drupal.t('Previous slide'), 248 nextSlideMessage: Drupal.t('Next slide'), 249 }, 250 on: { 251 slideChange: function () { 252 // Check if we've reached max products limit 253 if (settings.maxProducts && vue.items.length >= settings.maxProducts) { 254 return; 255 } 256 257 // Check if already loading or all products loaded 258 if (vue.busy || vue.allProductsLoaded) { 259 return; 260 } 261 262 // Get the number of slides currently visible 263 const slidesPerView = this.params.slidesPerView === 'auto' ? 1 : this.params.slidesPerView; 264 265 // In loop mode, realIndex gives us the actual slide position (not the duplicated ones) 266 const actualIndex = this.params.loop ? this.realIndex : this.activeIndex; 267 268 // Calculate how many actual items we have vs displayed slides 269 const actualItemCount = vue.items.length; 270 const slidesFromEnd = actualItemCount - (actualIndex + slidesPerView); 271 272 // Load more when we're within one full view of the end of actual items 273 if (slidesFromEnd <= slidesPerView && slidesFromEnd >= 0) { 274 vue.loadMoreSlides(this); 275 } 276 }, 277 reachEnd: function () { 278 // In loop mode, this event might not fire properly, rely on slideChange 279 if (!settings.autoPlay && !vue.busy) { 280 vue.loadMoreSlides(this); 281 } 282 }, 283 }, 284 }; 285 286 const swiper = new Swiper(swiperEl, swiperConfig); 287 288 vue.swiper = swiper; 289 }, 290
291 loadMoreSlides: function (swiper) { 292 if (!swiper) { 293 return; 294 } 295 296 // Check if we've reached max products limit 297 if (this.maxProducts && this.items.length >= this.maxProducts) { 298 return; 299 } 300 301 if (this.busy || this.allProductsLoaded) { 302 return; 303 } 304 305 // Load more slides logic here 306 this.loadMore(); 307 }, 308 309 addAutoplayControl: function () { 310 const vue = this; 311 const swiperEl = this.$el.querySelector('.swiper') || this.$el.querySelector('.swiper-container'); 312 if (!swiperEl) { 313 return; 314 } 315 316 // Create pause/play button 317 const controlButton = document.createElement('button'); 318 controlButton.className = 'btn btn-primary swiper-autoplay-control-btn'; 319 controlButton.setAttribute('aria-label', Drupal.t('Pause slideshow')); 320 controlButton.innerHTML = 321 '<span class="sr-only">' + Drupal.t('Pause slideshow') + '</span><svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>'; 322 323 // Find pagination element to position button next to it 324 const paginationEl = swiperEl.querySelector('.swiper-pagination'); 325 let buttonPosition = 'right: 15px;'; 326 327 if (paginationEl) { 328 // Position button to the right of pagination 329 buttonPosition = 'left: calc(50% + 70px);'; // Adjust positioning relative to centered pagination 330 } 331 332 controlButton.style.cssText = ` 333 ${buttonPosition} 334 `; 335 336 // Add click handler 337 controlButton.addEventListener('click', function () { 338 vue.toggleAutoplay(); 339 }); 340 341 // Append to swiper container 342 swiperEl.appendChild(controlButton); 343 vue.autoplayControlButton = controlButton; 344 }, 345 346 toggleAutoplay: function () { 347 if (!this.swiper || !settings.autoPlay) { 348 return; 349 } 350 351 if (this.isAutoplayPaused) { 352 this.swiper.autoplay.start(); 353 this.isAutoplayPaused = false; 354 this.updateAutoplayButton(); 355 } else { 356 this.swiper.autoplay.stop(); 357 this.isAutoplayPaused = true; 358 this.updateAutoplayButton(); 359 } 360 }, 361 362 updateAutoplayButton: function () { 363 if (!this.autoplayControlButton) { 364 return; 365 } 366 367 if (this.isAutoplayPaused) { 368 this.autoplayControlButton.setAttribute('aria-label', Drupal.t('Play slideshow')); 369 this.autoplayControlButton.innerHTML = 370 '<span class="sr-only">' + Drupal.t('Play slideshow') + '</span><svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>'; 371 } else { 372 this.autoplayControlButton.setAttribute('aria-label', Drupal.t('Pause slideshow')); 373 this.autoplayControlButton.innerHTML = 374 '<span class="sr-only">' + Drupal.t('Pause slideshow') + '</span><svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>'; 375 } 376 }, 377 378 extractMonthsFromFacilitiesAndSort: function () { 379 if (!this.monthData) { 380 this.facilityMonths = this.facilities 381 .filter(function (key) { 382 return key.id >= 100847 && key.id <= 100858; 383 }) 384 .sort(function (a, b) { 385 return a.id - b.id; 386 }); 387 } else { 388 this.facilityMonths = this.monthData; 389 } 390 }, 391 extractFacilitiesWithoutMonths: function () { 392 this.facilityWithoutMonths = this.facilities.filter(function (key) { 393 return key.id < 100847 || key.id > 100858; 394 }); 395 }, 396 formatOccasionObject: function () { 397 let occasionObject = null; 398 let vue = this; 399 if (vue.occasionsSelectType == 'singleDate') { 400 occasionObject = { 401 from: vue.formatOccasionDate(vue.occasions) ?? '', 402 to: vue.formatOccasionDate(vue.occasions) ?? '', 403 }; 404 } else { 405 occasionObject = { 406 from: vue.occasions ? vue.formatOccasionDate(vue.occasions.start) : '', 407 to: vue.occasions ? vue.formatOccasionDate(vue.occasions.end) : '', 408 }; 409 } 410 return occasionObject; 411 },
412 loadMore: function () { 413 var vue = this; 414 if (this.maxProducts && this.items.length >= this.maxProducts) { 415 return; 416 } 417 if (vue.busy || vue.allProductsLoaded || vue.fail) { 418 return; 419 } 420 vue.busy = true; 421 if (vue.flyingXhr) { 422 vue.flyingXhr.abort(); 423 } 424 var url = (settings.host || '').replace('http://', '//').replace('https://', '//') + '/' + drupalSettings.path.pathPrefix + 'api/cbis-product-list'; 425 426 let occasionObject = vue.formatOccasionObject(); 427 428 vue.payload = null; 429 430 vue.payload = { 431 nodeId: vue.node, 432 page: vue.page + 1, 433 facilityGroupsOperatorBetweenGroups: facilityGroupsOperatorBetweenGroups, 434 facilityGroupsOperatorBetweenFacilitiesInSameGroup: facilityGroupsOperatorBetweenFacilitiesInSameGroup, 435 categories: vue.filter.categories, 436 geos: vue.filter.geos, 437 arenas: vue.filter.arenas, 438 facilities: vue.filter.facilities, 439 search: vue.filter.search, 440 order: vue.order, 441 randomSeed: random, 442 occasion: occasionObject, 443 imagetag: settings.imagetag, 444 iticketAvailabilityDates: vue.iticketAvailabilityDates, 445 }; 446 447 // Only include pageSize for slideshow view modes 448 if (vue.pageSize !== null) { 449 vue.payload.pageSize = vue.pageSize; 450 } 451 452 vue.flyingXhr = $.getJSON(url, vue.payload, function (data) { 453 // var items = data.items; 454 var totalCount = data.totalCount; 455 if (data.items.length) { 456 data.items.forEach(function (item, index) { 457 // After 1 loop - go and create appendAdItem 458 if (index == 1 && settings.adItemNumber && !vue.adItemAdded) { 459 vue.appendAdItem(); 460 vue.adItemAdded = true; 461 } 462 463 vue.items.push(item); 464 }); 465 vue.page++; 466 } else { 467 vue.allProductsLoaded = true; 468 } 469 /* Add if all products loaded at once*/ 470 if (vue.items.length === data.totalCount) { 471 vue.allProductsLoaded = true; 472 } 473 /* if (vue.linkTitle && vue.linkUrl && (vue.items.length === parseInt(vue.maxProducts)) && settings.viewMode === 'slideshow') { 474 vue.appendSlide(); // Append a slide last in the slideshow (Dalarna) 475 } // Removed from Dalarna - if we want it again, add another setting? 476 */ 477 vue.totalCount = totalCount; 478 vue.busy = false; 479 480 // @TODO: create an event for these, and fire when items are created 481 // e.g: 482 // let event = new Event("cbis_product_list_loaded") 483 // document.dispatchEvent(event); 484 485 if (typeof FavouriteNode != 'undefined') { 486 setTimeout(FavouriteNode.update, 300); 487 } 488 489 if (typeof Iticket != 'undefined') { 490 let startingAfterOccasion = occasionObject && typeof occasionObject.from != 'undefined' ? occasionObject.from : null; 491 let startingUntilOccasion = occasionObject && typeof occasionObject.to != 'undefined' ? occasionObject.to : null; 492 493 let iTicketDates = { 494 StartingAfter: vue.iticketAvailabilityDates && typeof vue.iticketAvailabilityDates.from != 'undefined' ? vue.iticketAvailabilityDates.from : startingAfterOccasion, 495 StartingUntil: vue.iticketAvailabilityDates && typeof vue.iticketAvailabilityDates.to != 'undefined' ? vue.iticketAvailabilityDates.to : startingUntilOccasion, 496 }; 497 498 setTimeout(function () { 499 Iticket.updateAll('cbis-product-teaser', vue.node, iTicketDates); 500 }, 300); 501 } 502 }) 503 .fail(function () { 504 vue.busy = false; 505 vue.fail = true; 506 }) 507 .always(function () { 508 vue.flyingXhr = null; 509 }); 510 }, 511 appendSlide: function () { 512 if (this.items.length === parseInt(this.maxProducts)) { 513 this.items.push( 514 '<div class="view-more-items">' + 515 ' <a href="' + 516 this.linkUrl + 517 '" rel="bookmark">' + 518 ' <div class="more-items">' + 519 this.linkTitle + 520 ' <i class="fas fa-angle-right"></i>' + 521 ' </div>' +
522 ' </a>' + 523 '</div>' 524 ); 525 } 526 }, 527 528 /** Camping ads */ 529 appendAdItem: function () { 530 let adItemNumber = settings.adItemNumber || 'swipe1'; 531 let isMobile = window.innerWidth < 980; // Bootstrap lg breakpoint 532 let divId = isMobile ? 'mobile-' + adItemNumber : 'desktop-' + adItemNumber; 533 let style = isMobile ? 'min-width: 250px; min-height: 360px;' : 'min-width: 250px; min-height: 360px;'; 534 535 this.items.push( 536 '<div class="ads-teaser ads-wrapper-list-' + 537 adItemNumber + 538 '" style=\'' + 539 style + 540 "'>\n" + 541 ' <div id="' + 542 divId + 543 '" style="' + 544 style + 545 '"></div>\n' + 546 ' <strong class="ads-teaser-label">' + 547 Drupal.t('Advertisement') + 548 '</strong>\n' + 549 '</div>' 550 ); 551 }, 552 553 detectBrowser: function () { 554 var ua = window.navigator.userAgent; 555 var trident = ua.indexOf('Trident/'); 556 if (trident > 0) { 557 // IE 11 => return version number 558 var rv = ua.indexOf('rv:'); 559 return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); 560 } else { 561 return 0; 562 } 563 }, 564 reset: function () { 565 if (this.flyingXhr) { 566 this.flyingXhr.abort(); 567 this.flyingXhr = null; 568 } 569 this.busy = false; 570 this.fail = false; 571 this.page = -1; 572 this.items = []; 573 this.allProductsLoaded = false; 574 this.adItemAdded = false; // Reset ad item flag when resetting 575 }, 576 loadFilter: function () { 577 var vue = this; 578 var key = vue.cookieKey(); 579 var value = Cookies.get(key) || ''; 580 if (0 === value.length) { 581 return; 582 } 583 var filter = JSON.parse(value); 584 vue.filter = { 585 categories: filter.categories || [], 586 geos: filter.geos || [], 587 arenas: filter.arenas || [], 588 facilities: filter.facilities || [], 589 }; 590 591 if (oneValuePerCustomFacilititesFilter) { 592 this.loadFilterOneValuePerCustomFacility(); 593 } 594 }, 595 loadFilterOneValuePerCustomFacility: function () { 596 var vue = this; 597 var filteredFacilityGroupkey = vue.cookieFilteredFacilityKey(); 598 var filteredFacilityGroupValue = Cookies.get(filteredFacilityGroupkey) || ''; 599 if (0 === filteredFacilityGroupValue.length) { 600 return; 601 } 602 vue.filteredFacilitySelection = JSON.parse(filteredFacilityGroupValue); 603 }, 604 saveFilter: function () { 605 var vue = this; 606 var key = vue.cookieKey(); 607 var value = JSON.stringify(vue.filter); 608 Cookies.set(key, value); 609 }, 610 handleWindowResize: function (event) { 611 // whenever the document is resized, re-set the 'fullHeight' variable 612 if (document.documentElement.clientWidth > 1024) { 613 this.isDesktop = true; 614 } else { 615 this.isDesktop = false; 616 } 617 }, 618 clearFilters: function () { 619 this.filter = { 620 categories: [], 621 geos: [], 622 arenas: [], 623 facilities: [], 624 search: '', 625 }; 626 this.occasions = null; 627 this.occasionCount = null; 628 this.showFilter = { 629 all: false, 630 categories: false, 631 geos: false, 632 arenas: false, 633 facilities: false,
634 facilityMonths: false, 635 occasions: false, 636 extraFilter1: false, 637 extraFilter2: false, 638 extraFilter3: false, 639 extraFilter4: false, 640 extraFilter5: false, 641 extraFilter6: false, 642 extraFilter7: false, 643 }; 644 }, 645 clearFilter: function (type) { 646 switch (type) { 647 case 'facilities': 648 this.filter.facilities = {}; 649 break; 650 case 'categories': 651 this.filter.categories = []; 652 break; 653 case 'geos': 654 this.filter.geos = []; 655 break; 656 case 'arenas': 657 this.filter.arenas = []; 658 break; 659 case 'informationFields': 660 this.filter.informationFields = []; 661 break; 662 default: 663 return; 664 } 665 }, 666 toggleFilter: function (filterType) { 667 if (filterType == 'categories') { 668 this.showFilter = { 669 all: false, 670 categories: !this.showFilter.categories, 671 geos: false, 672 arenas: false, 673 facilities: false,
674 facilityMonths: false, 675 occasions: false, 676 extraFilter1: false, 677 extraFilter2: false, 678 extraFilter3: false, 679 extraFilter4: false, 680 extraFilter5: false, 681 extraFilter6: false, 682 extraFilter7: false, 683 }; 684 } else if (filterType == 'facilities') { 685 this.showFilter = { 686 all: false, 687 categories: false, 688 geos: false, 689 arenas: false, 690 facilities: !this.showFilter.facilities, 691 facilityMonths: false, 692 occasions: false, 693 extraFilter1: false, 694 extraFilter2: false, 695 extraFilter3: false, 696 extraFilter4: false, 697 extraFilter5: false, 698 extraFilter6: false, 699 extraFilter7: false, 700 }; 701 } else if (filterType == 'facilityMonths') { 702 this.showFilter = { 703 all: false, 704 categories: false, 705 geos: false, 706 arenas: false, 707 facilities: false, 708 facilityMonths: !this.showFilter.facilityMonths, 709 occasions: false, 710 extraFilter1: false, 711 extraFilter2: false, 712 extraFilter3: false, 713 extraFilter4: false, 714 extraFilter5: false, 715 extraFilter6: false, 716 extraFilter7: false, 717 }; 718 } else if (filterType == 'extraFilter1') { 719 this.showFilter = { 720 all: false, 721 categories: false, 722 geos: false, 723 arenas: false, 724 facilities: false,
725 facilityMonths: false, 726 occasions: false, 727 extraFilter1: !this.showFilter.extraFilter1, 728 extraFilter2: false, 729 extraFilter3: false, 730 extraFilter4: false, 731 extraFilter5: false, 732 extraFilter6: false, 733 extraFilter7: false, 734 }; 735 } else if (filterType == 'extraFilter2') { 736 this.showFilter = { 737 all: false, 738 categories: false, 739 geos: false, 740 arenas: false, 741 facilities: false, 742 facilityMonths: false, 743 occasions: false, 744 extraFilter1: false, 745 extraFilter2: !this.showFilter.extraFilter2, 746 extraFilter3: false, 747 extraFilter4: false, 748 extraFilter5: false, 749 extraFilter6: false, 750 extraFilter7: false, 751 }; 752 } else if (filterType == 'extraFilter3') { 753 this.showFilter = { 754 all: false, 755 categories: false, 756 geos: false, 757 arenas: false, 758 facilities: false,
759 facilityMonths: false, 760 occasions: false, 761 extraFilter1: false, 762 extraFilter2: false, 763 extraFilter3: !this.showFilter.extraFilter3, 764 extraFilter4: false, 765 extraFilter5: false, 766 extraFilter6: false, 767 extraFilter7: false, 768 }; 769 } else if (filterType == 'extraFilter4') { 770 this.showFilter = { 771 all: false, 772 categories: false, 773 geos: false, 774 arenas: false, 775 facilities: false, 776 facilityMonths: false, 777 occasions: false, 778 extraFilter1: false, 779 extraFilter2: false, 780 extraFilter3: false, 781 extraFilter4: !this.showFilter.extraFilter4, 782 extraFilter5: false, 783 extraFilter6: false, 784 extraFilter7: false, 785 }; 786 } else if (filterType == 'extraFilter5') { 787 this.showFilter = { 788 all: false, 789 categories: false, 790 geos: false, 791 arenas: false, 792 facilities: false,
793 facilityMonths: false, 794 occasions: false, 795 extraFilter1: false, 796 extraFilter2: false, 797 extraFilter3: false, 798 extraFilter4: false, 799 extraFilter5: !this.showFilter.extraFilter5, 800 extraFilter6: false, 801 extraFilter7: false, 802 }; 803 } else if (filterType == 'extraFilter6') { 804 this.showFilter = { 805 all: false, 806 categories: false, 807 geos: false, 808 arenas: false, 809 facilities: false, 810 facilityMonths: false, 811 occasions: false, 812 extraFilter1: false, 813 extraFilter2: false, 814 extraFilter3: false, 815 extraFilter4: false, 816 extraFilter5: false, 817 extraFilter6: !this.showFilter.extraFilter6, 818 extraFilter7: false, 819 }; 820 } else if (filterType == 'extraFilter7') { 821 this.showFilter = { 822 all: false, 823 categories: false, 824 geos: false, 825 arenas: false, 826 facilities: false,
827 facilityMonths: false, 828 occasions: false, 829 extraFilter1: false, 830 extraFilter2: false, 831 extraFilter3: false, 832 extraFilter4: false, 833 extraFilter5: false, 834 extraFilter6: false, 835 extraFilter7: !this.showFilter.extraFilter7, 836 }; 837 } else if (filterType == 'geos') { 838 this.showFilter = { 839 all: false, 840 categories: false, 841 geos: !this.showFilter.geos, 842 facilities: false, 843 facilityMonths: false, 844 occasions: false, 845 extraFilter1: false, 846 extraFilter2: false, 847 extraFilter3: false, 848 extraFilter4: false, 849 extraFilter5: false, 850 extraFilter6: false, 851 extraFilter7: false, 852 }; 853 } else if (filterType == 'arenas') { 854 this.showFilter = { 855 all: false, 856 categories: false, 857 geos: false, 858 arenas: !this.showFilter.arenas, 859 facilities: false,
860 facilityMonths: false, 861 occasions: false, 862 extraFilter1: false, 863 extraFilter2: false, 864 extraFilter3: false, 865 extraFilter4: false, 866 extraFilter5: false, 867 extraFilter6: false, 868 extraFilter7: false, 869 }; 870 } else if (filterType == 'all') { 871 this.showFilter = { 872 all: !this.showFilter.all, 873 categories: !!(this.categoryTree && Object.keys(this.categoryTree.children).length > 0), 874 geos: !!(this.categoryTree && Object.keys(this.categoryTree.children).length == 0) && this.geoTree && Object.keys(this.geoTree.children).length > 0, 875 arenas: !!this.arenas, 876 facilities: !!(this.categoryTree && Object.keys(this.categoryTree.children).length == 0) && this.geoTree && Object.keys(this.geoTree.children).length == 0 && this.facilities, 877 facilityMonths: false, 878 occasions: !!this.occasions, 879 extraFilter1: false, 880 extraFilter2: false, 881 extraFilter3: false, 882 extraFilter4: false, 883 extraFilter5: false, 884 extraFilter6: false, 885 extraFilter7: false, 886 }; 887 } 888 }, 889 toggleMobileFilter: function (filterType) { 890 if (filterType == 'categories') { 891 this.showFilter = { 892 all: true, 893 categories: true, 894 geos: false, 895 arenas: false, 896 facilities: false,
897 facilityMonths: false, 898 occasions: false, 899 extraFilter1: false, 900 extraFilter2: false, 901 extraFilter3: false, 902 extraFilter4: false, 903 extraFilter5: false, 904 extraFilter6: false, 905 extraFilter7: false, 906 }; 907 } else if (filterType == 'facilities') { 908 this.showFilter = { 909 all: true, 910 categories: false, 911 geos: false, 912 arenas: false, 913 facilities: true, 914 facilityMonths: false, 915 occasions: false, 916 extraFilter1: false, 917 extraFilter2: false, 918 extraFilter3: false, 919 extraFilter4: false, 920 extraFilter5: false, 921 extraFilter6: false, 922 extraFilter7: false, 923 }; 924 } else if (filterType == 'geos') { 925 //this.showFilter.all = false; 926 this.showFilter = { 927 all: true, 928 categories: false, 929 geos: true, 930 arenas: false, 931 facilities: false,
932 facilityMonths: false, 933 occasions: false, 934 extraFilter1: false, 935 extraFilter2: false, 936 extraFilter3: false, 937 extraFilter4: false, 938 extraFilter5: false, 939 extraFilter6: false, 940 extraFilter7: false, 941 }; 942 } else if (filterType == 'arenas') { 943 //this.showFilter.all = false; 944 this.showFilter = { 945 all: true, 946 categories: false, 947 geos: false, 948 arenas: true, 949 facilities: false, 950 facilityMonths: false, 951 occasions: false, 952 extraFilter1: false, 953 extraFilter2: false, 954 extraFilter3: false, 955 extraFilter4: false, 956 extraFilter5: false, 957 extraFilter6: false, 958 extraFilter7: false, 959 }; 960 } else if (filterType == 'extraFilter1') { 961 //this.showFilter.all = false; 962 this.showFilter = { 963 all: true, 964 categories: false, 965 geos: false, 966 arenas: false, 967 facilities: false,
968 facilityMonths: false, 969 occasions: false, 970 extraFilter1: true, 971 extraFilter2: false, 972 extraFilter3: false, 973 extraFilter4: false, 974 extraFilter5: false, 975 extraFilter6: false, 976 extraFilter7: false, 977 }; 978 } else if (filterType == 'extraFilter2') { 979 //this.showFilter.all = false; 980 this.showFilter = { 981 all: true, 982 categories: false, 983 geos: false, 984 arenas: false, 985 facilities: false, 986 facilityMonths: false, 987 occasions: false, 988 extraFilter1: false, 989 extraFilter2: true, 990 extraFilter3: false, 991 extraFilter4: false, 992 extraFilter5: false, 993 extraFilter6: false, 994 extraFilter7: false, 995 }; 996 } else if (filterType == 'extraFilter3') { 997 //this.showFilter.all = false; 998 this.showFilter = { 999 all: true, 1000 categories: false, 1001 geos: false, 1002 arenas: false, 1003 facilities: false,
1004 facilityMonths: false, 1005 occasions: false, 1006 extraFilter1: false, 1007 extraFilter2: false, 1008 extraFilter3: true, 1009 extraFilter4: false, 1010 extraFilter5: false, 1011 extraFilter6: false, 1012 extraFilter7: false, 1013 }; 1014 } else if (filterType == 'extraFilter4') { 1015 //this.showFilter.all = false; 1016 this.showFilter = { 1017 all: true, 1018 categories: false, 1019 geos: false, 1020 arenas: false, 1021 facilities: false, 1022 facilityMonths: false, 1023 occasions: false, 1024 extraFilter1: false, 1025 extraFilter2: false, 1026 extraFilter3: false, 1027 extraFilter4: true, 1028 extraFilter5: false, 1029 extraFilter6: false, 1030 extraFilter7: false, 1031 }; 1032 } else if (filterType == 'extraFilter5') { 1033 //this.showFilter.all = false; 1034 this.showFilter = { 1035 all: true, 1036 categories: false, 1037 geos: false, 1038 arenas: false, 1039 facilities: false,
1040 facilityMonths: false, 1041 occasions: false, 1042 extraFilter1: false, 1043 extraFilter2: false, 1044 extraFilter3: false, 1045 extraFilter4: false, 1046 extraFilter5: true, 1047 extraFilter6: false, 1048 extraFilter7: false, 1049 }; 1050 } else if (filterType == 'extraFilter6') { 1051 //this.showFilter.all = false; 1052 this.showFilter = { 1053 all: true, 1054 categories: false, 1055 geos: false, 1056 arenas: false, 1057 facilities: false, 1058 facilityMonths: false, 1059 occasions: false, 1060 extraFilter1: false, 1061 extraFilter2: false, 1062 extraFilter3: false, 1063 extraFilter4: false, 1064 extraFilter5: false, 1065 extraFilter6: true, 1066 extraFilter7: false, 1067 }; 1068 } else if (filterType == 'extraFilter7') { 1069 //this.showFilter.all = false; 1070 this.showFilter = { 1071 all: true, 1072 categories: false, 1073 geos: false, 1074 arenas: false, 1075 facilities: false,
1076 facilityMonths: false, 1077 occasions: false, 1078 extraFilter1: false, 1079 extraFilter2: false, 1080 extraFilter3: false, 1081 extraFilter4: false, 1082 extraFilter5: false, 1083 extraFilter6: false, 1084 extraFilter7: true, 1085 }; 1086 } else if (filterType == 'apply') { 1087 this.showFilter = { 1088 all: false, 1089 categories: false, 1090 geos: false, 1091 arenas: false, 1092 facilities: false, 1093 facilityMonths: false, 1094 occasions: false, 1095 extraFilter1: false, 1096 extraFilter2: false, 1097 extraFilter3: false, 1098 extraFilter4: false, 1099 extraFilter5: false, 1100 extraFilter6: false, 1101 extraFilter7: false, 1102 }; 1103 } else if (filterType == 'occasions') { 1104 // this.showFilter.all = false; 1105 this.showFilter = { 1106 all: true, 1107 categories: false, 1108 geos: false, 1109 arenas: false, 1110 facilities: false,
1111 facilityMonths: false, 1112 occasions: true, 1113 extraFilter1: false, 1114 extraFilter2: false, 1115 extraFilter3: false, 1116 extraFilter4: false, 1117 extraFilter5: false, 1118 extraFilter6: false, 1119 extraFilter7: false, 1120 }; 1121 } 1122 }, 1123 clearDate: function () { 1124 this.occasions = null; 1125 this.occasionCount = null; 1126 }, 1127 1128 clearSearch: function () { 1129 this.filter.search = ''; 1130 }, 1131 1132 formatOccasionDate: function (d) { 1133 if (!d) { 1134 return ''; 1135 } 1136 var month = '' + (d.getMonth() + 1), 1137 day = '' + d.getDate(), 1138 year = d.getFullYear(); 1139 if (month.length < 2) { 1140 month = '0' + month; 1141 } 1142 if (day.length < 2) { 1143 day = '0' + day; 1144 } 1145 return [year, month, day].join('-'); 1146 }, 1147 getDaySpan: function (range) { 1148 if (!range) return 0; 1149 return Math.round((range.end - range.start) / msInDay + 1); 1150 }, 1151 categoryById: function (id) { 1152 id = parseInt(id); 1153 var found = this.categoryTree.children.find(function (c) { return parseInt(c.id) === id; }) 1154 || this.unfilteredCategoryTree.children.find(function (c) { return parseInt(c.id) === id; }); 1155 return found || { id: id, text: '' }; 1156 }, 1157 geoById: function (id) { 1158 var found = null; 1159 id = parseInt(id); 1160 this.geoTree.children.forEach(function (geo) { 1161 if (parseInt(geo.id) === id) { 1162 found = geo; 1163 } 1164 }); 1165 return found; 1166 }, 1167 arenaById: function (id) { 1168 var found = null; 1169 id = parseInt(id); 1170 this.arenas.forEach(function (arena) { 1171 if (parseInt(arena.id) === id) { 1172 found = arena; 1173 } 1174 }); 1175 return found; 1176 }, 1177 facilityById: function (id) { 1178 var found = null; 1179 id = parseInt(id); 1180 this.facilities.forEach(function (facility) { 1181 if (parseInt(facility.id) === id) { 1182 found = facility; 1183 } 1184 }); 1185 return found; 1186 }, 1187 facilityIdExists: function (values) { 1188 var found = false; 1189 this.facilities.forEach(function (facility) { 1190 if (values.indexOf(parseInt(facility.id)) !== -1) { 1191 found = true; 1192 } 1193 }); 1194 return found; 1195 }, 1196 removeFilter: function (type, index) { 1197 switch (type) { 1198 case 'facilities': 1199 this.filter.facilities.splice(index, 1); 1200 break; 1201 case 'categories': 1202 this.filter.categories.splice(index, 1); 1203 break; 1204 case 'geos': 1205 this.filter.geos.splice(index, 1); 1206 break; 1207 case 'arenas': 1208 this.filter.arenas.splice(index, 1); 1209 break; 1210 default: 1211 return; 1212 } 1213 }, 1214 1215 /** 1216 * Following fve functions are used together with the functionality for oneValuePerCustomFacilititesFilter, 1217 * which makes the custom facilities filters act like radio buttons. 1218 * If not passing a value for group and group = 'default', multiple custom facilities groups will not work properly, 1219 * Please pass a unique group value to make multiple custom facilities filters work. 1220 */ 1221 selectOneFacilityPerGroup: function (facility, group = 'default') { 1222 if (!this.filteredFacilitySelection.some((item) => item.groupKey === group)) { 1223 this.filteredFacilitySelection.push({ id: facility.id, groupKey: group, label: facility.label }); 1224 } else { 1225 var existingItem = this.filteredFacilitySelection.find((item) => item.groupKey === group); 1226 if (existingItem && existingItem.id === facility.id) { 1227 this.clearOneFacilityFilterGroup(group); 1228 } else if (existingItem) { 1229 existingItem.id = facility.id; 1230 existingItem.label = facility.label; 1231 } 1232 } 1233 this.filter.facilities = this.filteredFacilitySelection.map((item) => item.id); 1234 this.storefilteredFacilitySelection(); 1235 }, 1236 isFilterGroupSelected: function (groupKey = 'default') { 1237 var existingItem = this.filteredFacilitySelection.find((item) => item.groupKey === groupKey); 1238 return typeof existingItem !== 'undefined'; 1239 }, 1240 clearOneFacilityFilterGroup: function (group = 'default') { 1241 this.filteredFacilitySelection = this.filteredFacilitySelection.filter((item) => item.groupKey !== group); 1242 this.filter.facilities = this.filteredFacilitySelection.map((item) => item.id); 1243 }, 1244 storefilteredFacilitySelection: function () { 1245 var vue = this; 1246 var key = vue.cookieFilteredFacilityKey(); 1247 var value = JSON.stringify(vue.filteredFacilitySelection); 1248 Cookies.set(key, value); 1249 }, 1250 cookieFilteredFacilityKey: function () { 1251 return 'cbis-product-list-selected-filter-' + (drupalSettings.cssJsQueryString || '') + '-' + nodeId; 1252 }, 1253 1254 cookieKey: function () { 1255 return 'cbis-product-list-filter-' + (drupalSettings.cssJsQueryString || '') + '-' + nodeId; 1256 }, 1257 outsideCategories: function (e) {
1258 this.showFilter.categories = false; 1259 }, 1260 outsideFacilities: function (e) { 1261 this.showFilter.facilities = false; 1262 }, 1263 outsideGeo: function (e) { 1264 this.showFilter.geos = false; 1265 }, 1266 outsideArena: function (e) { 1267 this.showFilter.arenas = false; 1268 }, 1269 outsideExtraFilter1: function (e) { 1270 this.showFilter.extraFilter1 = false; 1271 }, 1272 outsideExtraFilter2: function (e) { 1273 this.showFilter.extraFilter2 = false; 1274 }, 1275 outsideExtraFilter3: function () { 1276 this.showFilter.extraFilter3 = false; 1277 }, 1278 outsideExtraFilter4: function () { 1279 this.showFilter.extraFilter4 = false; 1280 }, 1281 outsideExtraFilter5: function () { 1282 this.showFilter.extraFilter5 = false; 1283 }, 1284 outsideExtraFilter6: function () { 1285 this.showFilter.extraFilter6 = false; 1286 }, 1287 outsideExtraFilter7: function () { 1288 this.showFilter.extraFilter7 = false; 1289 }, 1290 }, 1291 directives: { 1292 'click-outside': { 1293 bind: function (el, binding, vNode) { 1294 // Provided expression must evaluate to a function. 1295 if (typeof binding.value !== 'function') { 1296 const compName = vNode.context.name; 1297 /*let warn = `[Vue-click-outside:] provided expression '${binding.expression}' is not a function, but has to be` 1298 if (compName) { warn += `Found in component '${compName}'` }*/ 1299 console.warn(warn); 1300 } 1301 // Define Handler and cache it on the element 1302 const bubble = binding.modifiers.bubble; 1303 const handler = function (e) { 1304 if (bubble || (!el.contains(e.target) && el !== e.target)) { 1305 binding.value(e); 1306 } 1307 }; 1308 el.__vueClickOutside__ = handler; 1309 // add Event Listeners 1310 document.addEventListener('click', handler); 1311 }, 1312 unbind: function (el, binding) { 1313 // Remove Event Listeners 1314 document.removeEventListener('click', el.__vueClickOutside__); 1315 el.__vueClickOutside__ = null; 1316 }, 1317 }, 1318 }, 1319 }); 1320 }); 1321})(jQuery, drupalSettings, Vue);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.