1;(()=>{ 2 'use strict'; 3 // Only Run Once. 4 if (window.PLEStickyState) return; 5 /** 6 * The Globally Available PLEStickyElements Meta information. 7 * Note: this is intentionally var, as we are defining a global. 8 * @var {WeakMap.<HTMLElement, StickyState>} PLEStickyElements 9 */ 10 window.PLEStickyElements ??= new WeakMap(); 11 12 // Detect a new HTML Standard that may have added these properties to the constructors. 13 const depPropConflict = { 14 isSticky: 'isSticky' in HTMLElement.prototype || 'isSticky' in Element.prototype 15 , exTop: 'exTop' in HTMLElement.prototype || 'exTop' in Element.prototype 16 }; 17 if (depPropConflict.isSticky || depPropConflict.exTop) { 18 console.error( 19 ` 20<hr/><hr/><hr/> 21exTop and isSticky have been found on HTMLElement or Element, conflicting with our deprecated properties!<br/> 22isSticky: ${depPropConflict.isSticky}<br/> 23exTop: ${depPropConflict.exTop}<br/> 24Any Non-migrated Sticky functionallity is now broken!!! 25<hr/><hr/><hr/> 26` 27 ); 28 } 29 30 class StickyState { 31 /** @type {WeakMap.<HTMLElement, StickyState>} */ 32 static states = window.PLEStickyElements; 33 /** @readonly */ 34 static stickySectionSelector = '.ple_module_sticky'; 35 /** @readonly */ 36 static containerSelector = '.container'; 37 38 /** 39 * @param {HTMLElement|StickyHTMLElement} el 40 * @return {StickyState} 41 */ 42 static findOrNew = (el) => { 43 let stickyState = this.states.get(el); 44 if (!stickyState) { 45 stickyState = new StickyState(); 46 this.states.set(el, stickyState); 47 } 48 // Copy Deprecated symbols if something was using this externally. 49 if ('isSticky' in el && !depPropConflict.isSticky && el.isSticky != null) stickyState.isSticky = el.isSticky; 50 if ('exTop' in el && !depPropConflict.exTop && el.exTop != null) stickyState.top = el.exTop; 51 52 return stickyState; 53 }; 54 55 static getStickySectionElements = () => document.querySelectorAll(this.stickySectionSelector); 56 57 static getStickySectionsHeight = () => { 58 const {stickySectionSelector, containerSelector} = this; 59 const {innerHeight, innerWidth, scrollY} = window; 60 const baseOffsetTop = scrollY - document.documentElement.clientTop; 61 const editMode = !!document.querySelectorAll('.isEditor').length; 62 // calculating and returning the sticky sections total height 63 let moduleStickyHeight = 0; 64 const stickyContainers = []; 65 for (const el of document.querySelectorAll(stickySectionSelector)) { 66 const containerElList = el.querySelectorAll(containerSelector); 67 const stickyState = PLEStickyState.findOrNew(el); 68 if (!stickyState.isSticky) { 69 // check if the sticky section is visible in the viewport, if yes set offset and sticky true 70 const bounding = el.getBoundingClientRect(); 71 if (bounding.top >= 0 && bounding.left >= 0 && bounding.right <= innerWidth && bounding.bottom <= innerHeight) { 72 for (const containerEl of containerElList) { 73 containerEl.dataset.inViewport = 'true'; 74 } 75 stickyState.top = bounding.top + baseOffsetTop; 76 stickyState.isSticky = true; 77 } 78 } else { 79 for (const containerEl of containerElList) { 80 delete containerEl.dataset.inViewport; 81 } 82 } 83 84 if (stickyState.isSticky) stickyContainers.push(...containerElList); 85 } 86 for (const containerEl of stickyContainers) { 87 const height = $(containerEl).outerHeight(true); 88 // when the browser scroll is triggered, get only the sticky
88sections that are visible in the view 89 moduleStickyHeight += height; 90 91 // for the in viewport sticky elements but still not in sticky mode double the element offset height 92 // only in Editor Mode for the Live Preview sticky sections are hidden by default 93 if (editMode && containerEl.dataset.inViewport === 'true') { 94 moduleStickyHeight += height; 95 } 96 } 97 98 if (moduleStickyHeight === 0) { 99 moduleStickyHeight = $('.mobileHeader-container').height(); 100 } else { 101 moduleStickyHeight += $('.se__navbar-fixed .nav-bar').outerHeight(true); 102 } 103 104 return moduleStickyHeight; 105 }; 106 107 /** 108 * @description Is the sticky-able element currently sticky. 109 * @type {boolean} 110 */ 111 isSticky = undefined; 112 /** 113 * @description The Sticky state inital origin point. 114 * @type {number} 115 */ 116 top = undefined; 117 } 118 119 /** 120 * The Globally Available PLEStickyElements Meta information. 121 * Note: this is intentionally var, as we are defining a global. 122 * @var {typeof StickyState} PLEStickyState 123 */ 124 window.PLEStickyState = StickyState; 125 126$(() => { 127 'use strict'; 128 const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); 129 const isEditor$ref = $('.isEditor'); 130 const isLiveSite = !isEditor$ref.length; 131 132 const stickyStates = StickyState.states ; 133 /** @type {NodeListOf<HTMLElement>} */ 134 const initialStickyElements = StickyState.getStickySectionElements(); 135 for (const el of initialStickyElements) { 136 stickyStates.set(el, new StickyState()); 137 } 138 if (isLiveSite) for (const el of initialStickyElements) Object.assign(el.style, { 139 maxHeight: '0' 140 , opacity: '0' 141 }); 142 143 /** @type {NodeListOf<HTMLElement>|null} */ 144 let stickySections = null; 145 if ('onscrollend' in window) { 146 addEventListener('scroll', ()=>{ 147 positionSticky(stickySections ??= StickyState.getStickySectionElements()); 148 }); 149 addEventListener('scrollend', ()=>{ 150 stickySections = null; 151 }); 152 } else { 153 /** @type {number} */ 154 let fallingEdge= 0; 155 addEventListener('scroll', () => { 156 positionSticky(stickySections ??= StickyState.getStickySectionElements()); 157 if (fallingEdge) clearTimeout(fallingEdge); 158 fallingEdge = setTimeout(()=>{ 159 stickySections = null; 160 fallingEdge = 0; 161 }, 300); 162 }); 163 } 164 165 166 167 /** 168 * @param {NodeListOf<HTMLElement>} stickySections 169 */ 170 const positionSticky = (stickySections) => { 171 if (!stickySections.length) return; 172 const {scrollY} = window; 173 let scrollTop = scrollY; 174 if (scrollTop <= 0) { 175 let opacity = '', maxHeight = '', transition = ''; 176 if (isLiveSite) { 177 opacity = '0'; 178 maxHeight = '0'; 179 transition = 'opacity 0s linear'; 180 } 181 182 $(stickySections).css({ 183 position: 'relative', 184 zIndex: 'auto', 185 maxHeight, 186 transition, 187 opacity, 188 top: '0px', 189 width: '100%' 190 }); 191 return; 192 } 193 194 195 let stickyHeightTotal = 0; 196 const baseOffsetTop = scrollY - document.documentElement.clientTop; 197 198 for (/** @type {StickyHTMLElement} */const el of stickySections) { 199 const myStartingTop = stickyHeightTotal; 200 201 const box = el.getBoundingClientRect(); 202 const height = box.height; 203 stickyHeightTotal += height; 204 const offsetTop = box.top + baseOffsetTop; 205 206 const stickyState = StickyState.findOrNew(el); 207 208 const isRelative = (stickyState.isSticky && scrollTop <= stickyState.top); 209 const isSticky = (offsetTop <= scrollTop); 210 211 let position = ''; 212 let maxHeight = ''; 213 let transition = ''; 214 let opacity = ''; 215 let zIndex = 1; 216 let top = 0; 217 218 if (isLiveSite) { 219 opacity = '0'; 220 maxHeight = '0'; 221 } 222 223 if (isRelative) { 224 stickyState.isSticky = false;
225 position = 'relative'; 226 zIndex = 1; 227 228 } else if (isSticky) { 229 // Handle sticky state change. 230 if (!stickyState.isSticky) { 231 stickyState.isSticky = true; 232 stickyState.top = offsetTop; 233 } 234 zIndex = 103; 235 top += myStartingTop; 236 237 if (isLiveSite) { 238 position = 'fixed'; 239 opacity = '1'; 240 maxHeight = '99999px'; 241 transition = 'opacity 0.3s linear'; 242 } else { 243 // we have issues with css sticky not working in edit mode 244 position = isSafari ? '-webkit-sticky' : /*'sticky'*/ 'fixed'; 245 } 246 247 scrollTop += height; 248 } 249 250 $(el).css({ 251 position, 252 zIndex, 253 maxHeight, 254 transition, 255 opacity, 256 top: `${top}px`, 257 width: '100%' 258 }); 259 260 // Handle deprecated migration issue. 261 // FIXME: Remove after all isSticky and exTop places ave been handled 262 try { 263 if (depPropConflict.isSticky) el.isSticky = stickyState.isSticky; 264 if (depPropConflict.exTop) el.exTop = stickyState.top; 265 } catch (e) { 266 console.error(e); 267 } 268 } 269 270 }; 271}); 272 273 274pleAppHooks: { 275 // FIXME: This will break when a Section Settings is converted to Vue. This should really be handled from within PLE ONLY. 276 const onStickyButtonClick = () => { 277 const sections = document.querySelectorAll(`.section:not(.ple_module_sticky)`); 278 for (const el of sections) el.removeAttribute('style'); 279 }; 280 281 const disableStickyButton = () => { 282 const buttons = document.querySelectorAll(`button[data-ple-id="$stickyBtnDisable"]`); 283 for (const button of buttons) button.addEventListener('click', onStickyButtonClick); 284 }; 285 286 addEventListener('load', disableStickyButton, {once: true}); 287} 288})();
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.