1function norm4_InputReset(obj) { 2 this.obj = obj; 3 this.position = 0; 4 this.default = ''; 5 this.type = ''; 6 this.followUpClickSuppressor = null; 7 8 this.blockClearEvent = function(event) { 9 if (!event) return false; 10 event.preventDefault(); 11 event.stopPropagation(); 12 if (event.stopImmediatePropagation) event.stopImmediatePropagation(); 13 return false; 14 } 15 16 this.suppressFollowUpClick = function() { 17 var that = this; 18 var suppress = function(event) { 19 that.blockClearEvent(event); 20 document.removeEventListener("click", suppress, true); 21 that.followUpClickSuppressor = null; 22 }; 23 24 if (this.followUpClickSuppressor) { 25 document.removeEventListener("click", this.followUpClickSuppressor, true); 26 } 27 28 this.followUpClickSuppressor = suppress; 29 document.addEventListener("click", suppress, true); 30 setTimeout(function() { 31 if (that.followUpClickSuppressor === suppress) { 32 document.removeEventListener("click", suppress, true); 33 that.followUpClickSuppressor = null; 34 } 35 }, 500); 36 } 37 38 this.activate = function() { 39 var that = this; 40 if (this.obj.parent().find(".deactivate_inputreset").length > 0) return; 41 this.obj.parent().append('<span class="deactivate_inputreset position' + this.position + ' form-control-clear"></span>'); 42 this.obj.parent().find(".deactivate_inputreset") 43 .on("pointerdown touchstart mousedown", function(event) { 44 return that.blockClearEvent(event); 45 }) 46 .on("pointerup touchend click", function(event) { 47 that.blockClearEvent(event); 48 if (that.clearHandledAt && Date.now() - that.clearHandledAt < 500) return false; 49 that.clearHandledAt = Date.now(); 50 if (event.type !== "click") that.suppressFollowUpClick(); 51 that.deactivate(); 52 $('#currentPage').val(1); 53 return false; 54 }); 55 this.obj.parent().addClass("has-clear"); 56 if (this.type == 'selectpicker') { 57 this.obj.selectpicker('refresh'); 58 } 59 60 } 61 this.deactivate = function() { 62 63 this.obj.closest(".has-clear").find(".deactivate_inputreset").remove(); 64 this.obj.closest(".has-clear").removeClass("has-clear"); 65 var bugfix = $(window).scrollTop();//unerklärliches scrolling at monuments 66 67 this.setDefault(); 68 if (this.type == 'selectpicker') this.obj.trigger("changed.bs.select"); 69 if (this.type != 'input') this.obj.trigger("change"); 70 if (this.type == 'input') this.obj.keyup(); 71 if (this.obj.closest(".tx-nc-monuments")) $(window).scrollTop(bugfix); 72 } 73 74 this.reset = function() { 75 76 this.obj.closest(".has-clear").find(".deactivate_inputreset").remove(); 77 this.obj.closest(".has-clear").removeClass("has-clear"); 78 var bugfix = $(window).scrollTop();//unerklärliches scrolling at monuments 79 this.setDefault(); 80 if (this.obj.closest(".tx-nc-monuments")) $(window).scrollTop(bugfix); 81 } 82 83 this.update = function() { 84 if (this.default != this.getValue()) this.activate(); 85 else { 86 this.obj.closest(".has-clear").find(".deactivate_inputreset").remove(); 87 this.obj.closest(".has-clear").removeClass("has-clear"); 88 if (this.type == 'selectpicker') { 89 this.obj.selectpicker('refresh'); 90 } 91 } 92 } 93 94 this.normalizeValue = function(value) { 95 if (Array.isArray(value)) { 96 return value.map(function(v) { return String(v).trim(); }).sort().join(","); 97 } 98 if (value === null || typeof value === "undefined") return ""; 99 return String(value).trim(); 100 } 101 102 103 this.setDefault = function() { 104 if (this.obj.data("inputreset-clear")) { 105 eval(this.obj.data("inputreset-clear")); 106 return; 107 } 108 109 switch (this.type) { 110 case 'input': 111 this.obj.val(this.default); break; 112 case 'easepick': 113 eval(this.obj.data("inputreset-clear")); 114 break; 115 case 'selectpicker': 116 var values = this.default === "" ? [] : String(this.default).split(","); 117 if (this.default === "" && this.obj.prop("multiple") && this.obj.find("option").length > 0) { 118 var firstOption = this.obj.find("option").first(); 119 var firstValue = String(firstOption.val()).trim(); 120 var firstText = String(firstOption.text()).trim(); 121 if (/^Alle\b/.test(firstText) || ["", "0", "-1"].indexOf(firstValue) >= 0) { 122 values = [firstValue]; 123 } 124 } 125 this.obj.selectpicker('val', this.obj.prop("multiple") ? values : this.default); 126 this.obj.selectpicker('refresh'); 127 break; 128 case 'select': 129 this.obj.prop("selectedIndex", this.default); break; 130 131 } 132 133 } 134 135 this.getValue = function() { 136 137 switch (this.type) { 138 case 'input': 139 case 'easepick': 140 return this.obj.val(); 141 case 'selectpicker': 142 return this.normalizeValue(this.obj.val() || []); 143 case 'select': 144 return this.obj.prop("selectedIndex"); 145 146 } 147 148 149 } 150 151 152 this.setType = function() { 153 if (this.obj.is('input')) { 154 if (this.obj.attr("id") == 'easepick' || this.obj.hasClass("easepick")) 155 this.type = 'easepick'; 156 else this.type = 'input'; 157 158 } else if (this.obj.is('select')) { 159 if (this.obj.hasClass("selectpicker")) 160 this.type = 'selectpicker'; 161 else this.type = 'select'; 162 } 163 } 164 165 166 this.setChange = function() { 167 var that = this; 168 switch (this.type) { 169 case 'input': 170 this.obj.keyup(function() { 171 if (that.getValue() != that.default) { that.activate(); } else { that.reset();} 172 }); 173 break; 174 case 'selectpicker': 175 case 'select': 176 case 'selectpicker': 177 this.obj.change(function() { 178 if (that.getValue() != that.default) { that.activate(); } else { that.reset(); } 179 }); break; 180 case 'easepick': 181 this.obj.change(function() { 182 if (that.getValue() != that.default) { that.activate(); } else { that.reset(); } 183 }); break; 184 185 } 186 187 } 188 189 this.init = function() { 190 var existing = this.obj.data("norm4InputReset"); 191 if (existing && typeof existing.update === "function") {
192 existing.update(); 193 return; 194 } 195 196 this.position = this.obj.data("inputreset"); 197 this.setType(); 198 if (undefined !== this.obj.attr("data-default")) 199 this.default = this.obj.data("default"); 200 else this.default = this.getValue(); 201 202 this.setChange(); 203 this.obj.data("norm4InputReset", this); 204 this.update(); 205 206 207 } 208 this.init(); 209} 210 211$(document).ready(function() { 212 213 function getSelectpickerValues($select) { 214 var values = ($.fn.selectpicker && $select.data("selectpicker")) ? $select.selectpicker("val") : $select.val(); 215 if (!Array.isArray(values)) values = values || values === 0 ? [values] : []; 216 return values.map(function(value) { return String(value).trim(); }); 217 } 218 219 function getAllOptionInfo($select) { 220 var $firstOption = $select.find("option").first(); 221 if ($firstOption.length === 0) return null; 222 223 var text = String($firstOption.text() || "").trim(); 224 if (!/^Alle\b/i.test(text)) return null; 225 226 return { 227 index: $select.find("option").index($firstOption), 228 value: String($firstOption.val()).trim() 229 }; 230 } 231 232 function closeSelectpickerDropdown($select) { 233 var $wrapper = $select.closest(".bootstrap-select"); 234 var $button = $wrapper.children("button.dropdown-toggle"); 235 236 if ($.fn.dropdown && $button.length > 0) { 237 $button.dropdown("hide"); 238 return; 239 } 240 241 $wrapper.removeClass("show"); 242 $wrapper.children(".dropdown-menu").removeClass("show"); 243 $button.attr("aria-expanded", "false"); 244 } 245 246 function getVisibleHeight(selector) { 247 var element = document.querySelector(selector); 248 if (!element) return 0; 249 250 var style = window.getComputedStyle(element); 251 if (style.display === "none" || style.visibility === "hidden") return 0; 252 253 var rect = element.getBoundingClientRect(); 254 return Math.max(0, Math.ceil(rect.height)); 255 } 256 257 function getVisibleViewportBottom(selector) { 258 var element = document.querySelector(selector); 259 if (!element) return 0; 260 261 var style = window.getComputedStyle(element); 262 if (style.display === "none" || style.visibility === "hidden") return 0; 263 264 var rect = element.getBoundingClientRect(); 265 if (rect.bottom <= 0 || rect.top >= window.innerHeight) return 0; 266 267 return Math.max(0, Math.ceil(Math.min(window.innerHeight, rect.bottom))); 268 } 269 270 function getSelectpickerHeaderOffset() { 271 var rootStyle = getComputedStyle(document.documentElement); 272 var headerOffset = parseFloat(rootStyle.getPropertyValue("--sticky-header-height")) || 75; 273 var extraOffset = parseFloat(rootStyle.getPropertyValue("--sticky-filter-extra-offset")) || 0; 274 headerOffset = Math.max( 275 headerOffset, 276 getVisibleHeight(".sticky-header.smaller"), 277 getVisibleViewportBottom("header .sticky-header") 278 ); 279 280 if (extraOffset === 0 && window.innerWidth < 769) { 281 var helper = document.querySelector(".menu-sidebar-helper.d-md-none"); 282 if (helper) { 283 var helperStyle = window.getComputedStyle(helper); 284 if (helperStyle.display !== "none" && helperStyle.visibility !== "hidden") { 285 var helperRect = helper.getBoundingClientRect(); 286 extraOffset = helperRect.height > 0 ? Math.max(0, Math.ceil(helperRect.bottom - headerOffset)) : 0; 287 } 288 } 289 } 290 291 return headerOffset + extraOffset; 292 } 293 294 function getSelectpickerWindowPadding() { 295 var topPadding = Math.ceil(getSelectpickerHeaderOffset() + 44); 296 return [topPadding, 8, 16, 8]; 297 } 298 299 function updateSelectpickerMenuSize($select) { 300 if (!$.fn.selectpicker || !$select.data("selectpicker")) return; 301 302 var selectpicker = $select.data("selectpicker"); 303 selectpicker.options.windowPadding = getSelectpickerWindowPadding(); 304 305 if (typeof selectpicker.setSize === "function") { 306 selectpicker.setSize(true); 307 } else if (typeof selectpicker.setMenuSize === "function") { 308 selectpicker.setMenuSize(); 309 } 310 311 restoreSelectpickerAllOption($select); 312 } 313 314 function restoreSelectpickerAllOption($select) { 315 if (!$.fn.selectpicker || !$select.data("selectpicker")) return; 316 317 var firstOption = getAllOptionInfo($select); 318 if (!firstOption) return; 319 320 var selectpicker = $select.data("selectpicker"); 321 var firstData = selectpicker.selectpicker && selectpicker.selectpicker.main && selectpicker.selectpicker.main.data && selectpicker.selectpicker.main.data[firstOption.index]; 322 var firstElement = firstData && firstData.element; 323 var menuInner = selectpicker.$menuInner && selectpicker.$menuInner.get(0); 324 var list = menuInner && menuInner.querySelector("ul.dropdown-menu"); 325 326 if (!firstElement || !list) return; 327
328 var firstRenderedItem = list.querySelector("li"); 329 var firstRenderedText = firstRenderedItem ? String(firstRenderedItem.innerText || firstRenderedItem.textContent || "").trim() : ""; 330 var firstOptionText = String($select.find("option").eq(firstOption.index).text() || "").trim(); 331 if (firstRenderedText === firstOptionText) return; 332 333 list.insertBefore(firstElement, list.firstElementChild); 334 } 335 336 function clampSelectpickerMenuToViewport($select) { 337 if (!$.fn.selectpicker || !$select.data("selectpicker")) return; 338 339 var selectpicker = $select.data("selectpicker"); 340 if (!selectpicker.$menu || !selectpicker.$menuInner) return; 341 342 var menu = selectpicker.$menu.get(0); 343 var inner = selectpicker.$menuInner.get(0); 344 if (!menu || !inner || !selectpicker.$menu.hasClass("show")) return; 345 346 var safeTop = Math.ceil(getSelectpickerHeaderOffset() + 12); 347 var safeBottom = Math.floor(window.innerHeight - 16); 348 var menuRect = menu.getBoundingClientRect(); 349 var innerRect = inner.getBoundingClientRect(); 350 var overflowTop = Math.ceil(safeTop - menuRect.top); 351 var overflowBottom = Math.ceil(menuRect.bottom - safeBottom); 352 var reduction = Math.max(overflowTop, overflowBottom, 0); 353 354 if (reduction <= 0) return; 355 356 var menuMaxHeight = parseFloat(menu.style.maxHeight) || menuRect.height; 357 var innerMaxHeight = parseFloat(inner.style.maxHeight) || innerRect.height; 358 var minMenuHeight = Math.min(140, Math.max(80, safeBottom - safeTop)); 359 360 selectpicker.$menu.css("max-height", Math.max(minMenuHeight, menuMaxHeight - reduction) + "px"); 361 selectpicker.$menuInner.css("max-height", Math.max(1, innerMaxHeight - reduction) + "px"); 362 363 if (selectpicker.dropdown && selectpicker.dropdown._popper && typeof selectpicker.dropdown._popper.update === "function") { 364 selectpicker.dropdown._popper.update(); 365 } 366 } 367 368 function scheduleSelectpickerMenuSizeUpdate($select) { 369 updateSelectpickerMenuSize($select); 370 clampSelectpickerMenuToViewport($select); 371 372 if (window.requestAnimationFrame) { 373 window.requestAnimationFrame(function() { 374 updateSelectpickerMenuSize($select); 375 clampSelectpickerMenuToViewport($select); 376 window.requestAnimationFrame(function() { 377 clampSelectpickerMenuToViewport($select); 378 }); 379 }); 380 } 381 } 382 383 function updateOpenSelectpickerMenus() { 384 $("select.selectpicker").each(function() { 385 var $select = $(this); 386 var $wrapper = $select.closest(".bootstrap-select"); 387 var selectpicker = $select.data("selectpicker"); 388 var hasOpenMenu = selectpicker && selectpicker.$menu && selectpicker.$menu.hasClass("show"); 389 if (!$wrapper.hasClass("show") && !$wrapper.children(".dropdown-menu").hasClass("show") && !hasOpenMenu) return; 390 391 updateSelectpickerMenuSize($select); 392 clampSelectpickerMenuToViewport($select); 393 }); 394 } 395 396 var selectpickerMenuSizeFrame = null; 397 398 function scheduleOpenSelectpickerMenuSizeUpdate() { 399 if (selectpickerMenuSizeFrame !== null) return; 400 401 if (window.requestAnimationFrame) { 402 selectpickerMenuSizeFrame = window.requestAnimationFrame(function() { 403 selectpickerMenuSizeFrame = null; 404 updateOpenSelectpickerMenus(); 405 }); 406 return; 407 } 408 409 selectpickerMenuSizeFrame = window.setTimeout(function() { 410 selectpickerMenuSizeFrame = null; 411 updateOpenSelectpickerMenus(); 412 }, 0); 413 } 414 415 $(document).on("changed.bs.select", "select.selectpicker[multiple]", function() { 416 var $select = $(this); 417 if (!$.fn.selectpicker || !$select.data("selectpicker")) return; 418 419 var allOption = getAllOptionInfo($select); 420 if (!allOption) return; 421 422 setTimeout(function() { 423 var values = getSelectpickerValues($select); 424 if (values.length !== 1 || values[0] !== allOption.value) return; 425 closeSelectpickerDropdown($select); 426 }, 0); 427 }); 428 429 $(document).on("show.bs.select shown.bs.select", "select.selectpicker", function() { 430 var $selectpicker = $(this).closest(".bootstrap-select"); 431 $selectpicker.addClass("selectpicker-open"); 432 $selectpicker.closest(".sticky-filter-wrapper").addClass("filter-dropdown-open"); 433 scheduleSelectpickerMenuSizeUpdate($(this)); 434 }); 435 436 $(document).on("hide.bs.select hidden.bs.select", "select.selectpicker", function() { 437 var $selectpicker = $(this).closest(".bootstrap-select"); 438 var $filterWrapper = $selectpicker.closest(".sticky-filter-wrapper"); 439 $selectpicker.removeClass("selectpicker-open"); 440 if ($filterWrapper.find(".bootstrap-select.selectpicker-open").length === 0) { 441 $filterWrapper.removeClass("filter-dropdown-open"); 442 } 443 }); 444 445 $(window).on("resize orientationchange scroll", scheduleOpenSelectpickerMenuSizeUpdate); 446 447 function initMobileRevealStickyFilters() { 448 var maxMobileWidth = 768; 449 var revealDelta = 50; 450 var hideDelta = 50; 451 var protectionReserve = 32; 452 var $filters = $(".sticky-filter-wrapper"); 453 var lastScrollY = Math.max(0, Math.round(window.scrollY || window.pageYOffset || 0)); 454 var lastDirection = 0; 455 var directionDelta = 0; 456 var ticking = false;
457 var resizeFrame = null; 458 var touchStartY = null; 459 460 function isMobileFilterViewport() { 461 return window.matchMedia && window.matchMedia("(max-width: " + maxMobileWidth + "px)").matches; 462 } 463 464 function isMobileStickyFilterEnabled() { 465 var root = document.documentElement; 466 var body = document.body; 467 468 // Customer switch: set window.norm4DisableMobileStickyFilter = true to disable mobile filter reveal. 469 return window.norm4MobileStickyFilterEnabled !== false 470 && window.norm4DisableMobileStickyFilter !== true 471 && (!root || root.getAttribute("data-mobile-sticky-filter") !== "0") 472 && (!body || body.getAttribute("data-mobile-sticky-filter") !== "0"); 473 } 474 475 function getScrollY() { 476 return Math.max(0, Math.round(window.scrollY || window.pageYOffset || 0)); 477 } 478 479 function refreshFilters() { 480 $filters = $(".sticky-filter-wrapper"); 481 if (!isMobileStickyFilterEnabled()) { 482 resetFilters(); 483 return; 484 } 485 $filters.addClass("mobile-filter-scroll-ready"); 486 updateFilters(true); 487 } 488 489 function resetFilters() { 490 $filters.removeClass("mobile-filter-scroll-ready mobile-filter-sticky mobile-filter-control-active mobile-filter-slide-in mobile-filter-slide-out mobile-filter-shadow mobile-filter-force-relative"); 491 } 492 493 function releaseMobileStickyFilters(scope) { 494 if (!isMobileFilterViewport()) return; 495 var $targetFilters = scope ? $(scope).closest(".sticky-filter-wrapper") : $filters; 496 if (scope && $targetFilters.length === 0) $targetFilters = $(scope).find(".sticky-filter-wrapper"); 497 if ($targetFilters.length === 0) return; 498 499 $targetFilters.each(function() { 500 if (this.contains(document.activeElement) && document.activeElement && typeof document.activeElement.blur === "function") { 501 document.activeElement.blur(); 502 } 503 clearSlideOutTimer(this); 504 this.classList.add("mobile-filter-force-relative"); 505 this.classList.remove("mobile-filter-sticky"); 506 this.classList.remove("mobile-filter-control-active"); 507 this.classList.remove("mobile-filter-slide-in"); 508 this.classList.remove("mobile-filter-slide-out"); 509 this.classList.remove("mobile-filter-shadow"); 510 this.classList.remove("filter-dropdown-open"); 511 $(this).find(".selectpicker-open").removeClass("selectpicker-open"); 512 this.mobileFilterReturnZoneReached = false; 513 updateNaturalFilterPosition(this, getScrollY()); 514 }); 515 516 lastScrollY = getScrollY(); 517 lastDirection = 0; 518 directionDelta = 0; 519 } 520 521 function clearControlActiveFilters() { 522 $filters.removeClass("mobile-filter-control-active"); 523 } 524 525 function clearSlideOutTimer(element) { 526 if (!element.mobileFilterSlideOutTimer) return; 527 window.clearTimeout(element.mobileFilterSlideOutTimer); 528 element.mobileFilterSlideOutTimer = null; 529 } 530 531 function finishSlideOut(element) { 532 clearSlideOutTimer(element); 533 element.classList.remove("mobile-filter-sticky"); 534 element.classList.remove("mobile-filter-slide-in"); 535 element.classList.remove("mobile-filter-slide-out"); 536 element.classList.remove("mobile-filter-shadow"); 537 element.mobileFilterReturnZoneReached = false; 538 } 539 540 function startSlideOut(element) { 541 if (!element.classList.contains("mobile-filter-sticky")) { 542 finishSlideOut(element); 543 return; 544 } 545 546 if (element.classList.contains("mobile-filter-slide-out")) return; 547 548 element.classList.remove("mobile-filter-slide-in"); 549 element.classList.add("mobile-filter-slide-out"); 550 clearSlideOutTimer(element); 551 element.mobileFilterSlideOutTimer = window.setTimeout(function() { 552 if (element.classList.contains("mobile-filter-slide-out")) finishSlideOut(element); 553 }, 560); 554 } 555 556 function cancelSlideOut(element) { 557 clearSlideOutTimer(element); 558 element.classList.remove("mobile-filter-slide-out"); 559 } 560 561 function hasOpenDropdown(element) { 562 return element.classList.contains("filter-dropdown-open") 563 || element.querySelector(".selectpicker-open") 564 || element.querySelector(".bootstrap-select.show") 565 || element.querySelector(".bootstrap-select.dropup.show") 566 || element.querySelector(".bootstrap-select > .dropdown-menu.show"); 567 } 568 569 function hasFocusedControl(element) { 570 return element.contains(document.activeElement); 571 } 572 573 function hasActiveFilters(element) { 574 var activeFilter = element.querySelector(".filter.has-active-filters"); 575 var resetButton = element.querySelector(".filter-reset-button"); 576 return !!activeFilter || !!(resetButton && resetButton.getAttribute("aria-disabled") === "fal
576se"); 577 } 578 579 function updateNaturalFilterPosition(element, scrollY) { 580 if (element.classList.contains("mobile-filter-sticky") || element.classList.contains("mobile-filter-slide-in") || element.classList.contains("mobile-filter-slide-out")) return; 581 var rect = element.getBoundingClientRect(); 582 element.mobileFilterNaturalTopY = rect.top + scrollY; 583 element.mobileFilterNaturalBottomY = rect.bottom + scrollY; 584 } 585 586 function updateStickyShadow(element, scrollY) { 587 if (!element.classList.contains("mobile-filter-sticky")) { 588 element.classList.remove("mobile-filter-shadow"); 589 return; 590 } 591 592 if (typeof element.mobileFilterNaturalBottomY === "undefined") { 593 element.classList.add("mobile-filter-shadow"); 594 return; 595 } 596 597 var shadowEndY = Math.max(0, Math.ceil(element.mobileFilterNaturalBottomY - getSelectpickerHeaderOffset())); 598 element.classList.toggle("mobile-filter-shadow", scrollY > shadowEndY); 599 } 600 601 function hasReachedNaturalFilterArea(element, scrollY) { 602 if (typeof element.mobileFilterNaturalBottomY === "undefined") return false; 603 return element.mobileFilterNaturalBottomY - scrollY > getSelectpickerHeaderOffset(); 604 } 605 606 function isPastFilterRevealDistance(element, scrollY) { 607 updateNaturalFilterPosition(element, scrollY); 608 var rect = element.getBoundingClientRect(); 609 var filterBottomY = typeof element.mobileFilterNaturalBottomY === "undefined" ? rect.bottom + scrollY : element.mobileFilterNaturalBottomY; 610 var revealDistance = Math.max(0, Math.ceil(rect.height * 2)); 611 var headerOffset = getSelectpickerHeaderOffset(); 612 return scrollY >= Math.ceil(filterBottomY + revealDistance + headerOffset); 613 } 614 615 function getFilterProtectionZone(element) { 616 var rect = element.getBoundingClientRect(); 617 return Math.ceil(rect.height + getSelectpickerHeaderOffset() + protectionReserve); 618 } 619 620 function getRevealThreshold(element) { 621 return Math.max(revealDelta, getFilterProtectionZone(element)); 622 } 623 624 function getHideThreshold(element) { 625 return Math.max(hideDelta, getFilterProtectionZone(element)); 626 } 627 628 function updateFilters(force) { 629 ticking = false; 630 if ($filters.length === 0) return; 631 632 if (!isMobileStickyFilterEnabled() || !isMobileFilterViewport()) { 633 resetFilters(); 634 return; 635 } 636 637 var scrollY = getScrollY(); 638 var scrollDiff = scrollY - lastScrollY; 639 var direction = scrollDiff > 0 ? 1 : (scrollDiff < 0 ? -1 : lastDirection); 640 641 if (direction !== 0) { 642 if (direction !== lastDirection) { 643 directionDelta = Math.abs(scrollDiff); 644 lastDirection = direction; 645 } else { 646 directionDelta += Math.abs(scrollDiff); 647 } 648 } 649 lastScrollY = scrollY; 650 651 $filters.each(function() { 652 var element = this; 653 element.classList.add("mobile-filter-scroll-ready"); 654 updateNaturalFilterPosition(element, scrollY); 655 656 if (scrollY <= 0) { 657 clearSlideOutTimer(element); 658 element.classList.remove("mobile-filter-sticky"); 659 element.classList.remove("mobile-filter-control-active"); 660 element.classList.remove("mobile-filter-slide-in"); 661 element.classList.remove("mobile-filter-slide-out"); 662 element.classList.remove("mobile-filter-shadow"); 663 element.classList.remove("mobile-filter-force-relative"); 664 element.mobileFilterReturnZoneReached = false; 665 return; 666 } 667 668 if (element.classList.contains("mobile-filter-force-relative")) { 669 if (direction > 0 && isPastFilterRevealDistance(element, scrollY)) { 670 element.classList.remove("mobile-filter-force-relative"); 671 } else { 672 clearSlideOutTimer(element); 673 element.classList.remove("mobile-filter-sticky"); 674 element.classList.remove("mobile-filter-control-active"); 675 element.classList.remove("mobile-filter-slide-in"); 676 element.classList.remove("mobile-filter-slide-out"); 677 element.classList.remove("mobile-filter-shadow"); 678 return; 679 } 680 } 681 682 if (!force && direction > 0 && element.classList.contains("mobile-filter-sticky") && element.mobileFilterReturnZoneReached && !hasOpenDropdown(element) && !hasFocusedControl(element)) { 683 finishSlideOut(element); 684 return; 685 } 686 687 if (!force && direction > 0 && directionDelta >= getHideThreshold(element) && isPastFilterRevealDistance(element, scrollY) && !hasOpenDropdown(element) && !hasFocusedControl(element)) { 688 if (element.classList.contains("mobile-filter-control-active")) { 689 cancelSlideOut(element); 690 element.classList.add("mobile-filter-sticky");
691 updateStickyShadow(element, scrollY); 692 return; 693 } 694 startSlideOut(element); 695 updateStickyShadow(element, scrollY); 696 return; 697 } 698 699 if (element.classList.contains("mobile-filter-control-active") || hasOpenDropdown(element) || hasFocusedControl(element)) { 700 cancelSlideOut(element); 701 element.classList.add("mobile-filter-sticky"); 702 element.classList.remove("mobile-filter-slide-in"); 703 updateStickyShadow(element, scrollY); 704 return; 705 } 706 707 if (!force && direction < 0 && directionDelta >= getRevealThreshold(element)) { 708 if (element.classList.contains("mobile-filter-sticky")) { 709 if (hasReachedNaturalFilterArea(element, scrollY)) element.mobileFilterReturnZoneReached = true; 710 cancelSlideOut(element); 711 updateStickyShadow(element, scrollY); 712 return; 713 } 714 715 if (!hasActiveFilters(element)) { 716 element.classList.remove("mobile-filter-slide-in"); 717 element.classList.remove("mobile-filter-slide-out"); 718 element.classList.remove("mobile-filter-shadow"); 719 return; 720 } 721 722 if (!isPastFilterRevealDistance(element, scrollY)) { 723 element.classList.remove("mobile-filter-slide-in"); 724 element.classList.remove("mobile-filter-slide-out"); 725 element.classList.remove("mobile-filter-shadow"); 726 return; 727 } 728 729 cancelSlideOut(element); 730 element.classList.remove("mobile-filter-slide-in"); 731 void element.offsetWidth; 732 element.classList.add("mobile-filter-slide-in"); 733 element.classList.add("mobile-filter-sticky"); 734 element.mobileFilterReturnZoneReached = false; 735 updateStickyShadow(element, scrollY); 736 } 737 738 if (!force && direction > 0 && directionDelta >= getHideThreshold(element) && isPastFilterRevealDistance(element, scrollY)) { 739 startSlideOut(element); 740 updateStickyShadow(element, scrollY); 741 } 742 }); 743 } 744 745 function requestUpdate() { 746 if (ticking) return; 747 ticking = true; 748 if (window.requestAnimationFrame) { 749 window.requestAnimationFrame(function() { 750 updateFilters(false); 751 }); 752 return; 753 } 754 window.setTimeout(function() { 755 updateFilters(false); 756 }, 0); 757 } 758 759 function requestRefresh() { 760 if (resizeFrame !== null) return; 761 var callback = function() { 762 resizeFrame = null; 763 refreshFilters(); 764 }; 765 if (window.requestAnimationFrame) { 766 resizeFrame = window.requestAnimationFrame(callback); 767 return; 768 } 769 resizeFrame = window.setTimeout(callback, 0); 770 } 771 772 if ($filters.length === 0) return; 773 window.norm4ReleaseMobileStickyFilters = releaseMobileStickyFilters; 774 refreshFilters(); 775 window.addEventListener("scroll", requestUpdate, { passive: true }); 776 window.addEventListener("resize", requestRefresh); 777 window.addEventListener("orientationchange", requestRefresh); 778 $(document).on("animationend", ".sticky-filter-wrapper.mobile-filter-slide-in, .sticky-filter-wrapper.mobile-filter-slide-out", function(event) { 779 if (event.originalEvent && event.originalEvent.animationName === "mobileFilterSlideOut") { 780 finishSlideOut(this); 781 return; 782 } 783 this.classList.remove("mobile-filter-slide-in"); 784 }); 785 window.addEventListener("touchstart", function(event) { 786 if (!isMobileStickyFilterEnabled() || !isMobileFilterViewport() || !event.touches || event.touches.length === 0) return; 787 touchStartY = event.touches[0].clientY; 788 }, { passive: true }); 789 window.addEventListener("touchmove", function(event) { 790 if (!isMobileStickyFilterEnabled() || !isMobileFilterViewport() || touchStartY === null || !event.touches || event.touches.length === 0) return; 791 var currentY = event.touches[0].clientY; 792 if (touchStartY - currentY > 8) clearControlActiveFilters(); 793 touchStartY = currentY; 794 }, { passive: true }); 795 window.addEventListener("wheel", function(event) { 796 if (isMobileStickyFilterEnabled() && isMobileFilterViewport() && event.deltaY > 0) clearControlActiveFilters(); 797 }, { passive: true }); 798 $(document).on("shown.bs.select hidden.bs.select", ".sticky-filter-wrapper select.selectpicker", requestUpdate); 799 $(document).on("change keyup", ".sticky-filter-wrapper select, .sticky-filter-wrapper input", function() { 800 var $filterWrapper = $(this).closest(".sticky-filter-wrapper"); 801 if (isMobileStickyFilterEnabled() && isMobileFilterViewport() && getScrollY() > 0 && !$filterWrapper.hasClass("mobile-filter-force-relative")) { 802 $filterWrapper.addClass("mobile-filter-sticky mobile-filter-control-active"); 803 } 804 }); 805 } 806 807 initMobileRevealStickyFilters(); 808 809 $.each($("select[data-inputreset],input[data-inputreset]"), function(index, value) { 810 new norm4_InputReset($(value)); 811 }); 812 813 814 815});
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.