PageSourceSearch

https://www.oceanviewanimalhospital.com/plugins/editor/cms/compone…/assets/js/sticky.js?v.1.257

js oceanviewanimalhospital.com collected 2026-09-29 16:30:04 UTC 10,579 bytes, 288 lines download raw bytes

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.