1(function () { 2 const { mergeObjects } = BreakdanceFrontend.utils; 3 4 const isSelectorValid = (selector) => { 5 const queryCheck = (s) => 6 document.createDocumentFragment().querySelector(s); 7 8 try { 9 queryCheck(selector); 10 } catch { 11 return false; 12 } 13 return true; 14 }; 15 16 class BreakdanceBackToTop { 17 defaultOptions = { 18 type: "progress", 19 show: "always", 20 advanced: { 21 scroll_offset: 0, 22 scroll_to_selector: null, 23 }, 24 }; 25 26 constructor(selector, options) { 27 this.selector = selector; 28 this.element = document.querySelector(`${this.selector}`); 29 this.button = document.querySelector( 30 `${this.selector} .js-ee-back-to-top` 31 ); 32 this.rootElement = document.documentElement; 33 this.options = mergeObjects(this.defaultOptions, options); 34 this.init(); 35 } 36 37 destroy() { 38 this.button.removeEventListener("click", this.handleClick); 39 document.removeEventListener("scroll", this.handleScroll); 40 if (this.options.type === "progress") { 41 document.removeEventListener("scroll", this.handlePercentageScroll); 42 } 43 } 44 45 init() { 46 // handle button events 47 this.handleClick = this.clickHandler.bind(this); 48 this.button.addEventListener("click", this.handleClick); 49 // handle scroll animations 50 this.handleScroll = this.scrollHandler.bind(this); 51 document.addEventListener("scroll", this.handleScroll); 52 this.handleScroll(); 53 // handle scroll indicator 54 if (this.options.type === "progress") { 55 this.initIndicator(); 56 this.handlePercentageScroll = this.updateScrollPercent.bind(this); 57 document.addEventListener("scroll", this.handlePercentageScroll); 58 } 59 } 60 61 update() { 62 this.destroy(); 63 this.init(); 64 } 65 66 updateScrollPercent() { 67 const heightOfWindow = window.innerHeight; 68 const contentScrolled = window.pageYOffset; 69 const bodyHeight = document.body.offsetHeight; 70 let percentageVal = 0; 71 72 if (bodyHeight - contentScrolled <= heightOfWindow) { 73 percentageVal = 100; 74 } else { 75 const total = bodyHeight - heightOfWindow; 76 const got = contentScrolled; 77 percentageVal = parseInt((got / total) * 100); 78 } 79 const pathLength = this.progressPath.getTotalLength(); 80 const progress = pathLength - (percentageVal / 100) * pathLength; 81 this.progressPath.style.strokeDashoffset = progress; 82 } 83 84 calculateOffset() { 85 const offset = this.options.advanced.scroll_offset; 86 const customSelector = this.options.advanced.scroll_to_selector; 87 88 if (customSelector !== null && isSelectorValid(customSelector)) { 89 const element = document.querySelector(customSelector); 90 if (!element) return offset; 91 const bodyRect = document.body.getBoundingClientRect().top; 92 const elementRect = element.getBoundingClientRect().top; 93 const elementPosition = elementRect - bodyRect; 94 return elementPosition - offset; 95 } else { 96 return offset; 97 } 98 } 99 100 initIndicator() { 101 this.progressPath = this.element.querySelector( 102 ".js-progress-svg path.tracker" 103 ); 104 105 const pathLength = this.progressPath.getTotalLength(); 106 this.progressPath.style.transition = 107 this.progressPath.style.WebkitTransition = "none"; 108 this.progressPath.style.strokeDasharray = pathLength + " " + pathLength; 109 this.progressPath.style.strokeDashoffset = pathLength; 110 this.progressPath.getBoundingClientRect(); 111 this.progressPath.style.transition = 112 this.progressPath.style.WebkitTransition = 113 "stroke-dashoffset 10ms linear"; 114 } 115 116 clickHandler() { 117 const offsetPosition = this.calculateOffset(); 118 119 this.rootElement.scrollTo({ 120 top: offsetPosition, 121 behavior: "smooth", 122 }); 123 } 124 125 scrollHandler() { 126 const offsetBottom = this.options.show === "half" ? 0.5 : 0.8; 127 const scrollTotal = 128 this.rootElement.scrollHeight - this.rootElement.clientHeight; 129 if (this.rootElement.scrollTop / scrollTotal > offsetBottom) { 130 this.button.classList.add("is-visible"); 131 } else if (this.rootElement.scrollTop === 0) { 132 this.button.classList.add("is-top"); 133 } else { 134 this.button.classList.remove("is-visible"); 135 this.button.classList.remove("is-top"); 136 } 137 } 138 } 139 window.BreakdanceBackToTop = BreakdanceBackToTop; 140})();
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.