PageSourceSearch

https://liberty-intl.org/wp-content/themes/charix/assets/js/vendor/sticky.js?ver=1.1.0

js liberty-intl.org collected 2026-09-24 06:33:51 UTC 7,976 bytes, 179 lines download raw bytes

1(function ($, elementorFrontend, elementorModules) {
2    'use strict';
3    var _sticky = elementorModules.frontend.handlers.Base.extend({
4        currentConfig: {},
5        debouncedReactivate: null,
6        bindEvents() {
7            elementorFrontend.addListenerOnce(this.getUniqueHandlerID() + 'sticky', 'resize', this.reactivateOnResize);
8        },
9        unbindEvents() {
10            elementorFrontend.removeListeners(this.getUniqueHandlerID() + 'sticky', 'resize', this.reactivateOnResize);
11        },
12        isStickyInstanceActive() {
13            return undefined !== this.$element.data('sticky');
14        },
15        /**
16         * Get the current active setting value for a responsive control.
17         *
18         * @param {string} setting
19         * @return {any} - Setting value.
20         */
21        getResponsiveSetting(setting) {
22            const elementSettings = this.getElementSettings();
23            return elementorFrontend.getCurrentDeviceSetting(elementSettings, setting);
24        },
25        /**
26         * Return an array of settings names for responsive control (e.g. `settings`, `setting_tablet`, `setting_mobile` ).
27         *
28         * @param {string} setting
29         * @return {string[]} - List of settings.
30         */
31        getResponsiveSettingList(setting) {
32            const breakpoints = Object.keys(elementorFrontend.config.responsive.activeBreakpoints);
33            return ['', ...breakpoints].map(suffix => {
34                return suffix ? `${setting}_${suffix}` : setting;
35            });
36        },
37        getConfig() {
38            const elementSettings = this.getElementSettings(),
39                stickyOptions = {
40                    to: elementSettings.sticky,
41                    offset: this.getResponsiveSetting('sticky_offset'),
42                    effectsOffset: this.getResponsiveSetting('sticky_effects_offset'),
43                    classes: {
44                        sticky: 'elementor-sticky',
45                        stickyActive: 'elementor-sticky--active elementor-section--handles-inside',
46                        stickyEffects: 'elementor-sticky--effects',
47                        spacer: 'elementor-sticky__spacer'
48                    },
49                    isRTL: elementorFrontend.config.is_rtl,
50                    // In edit mode, since the preview is an iframe, the scrollbar is on the left. The scrollbar width is
51                    // compensated for in this case.
52                    handleScrollbarWidth: elementorFrontend.isEditMode()
53                },
54                $wpAdminBar = elementorFrontend.elements.$wpAdminBar,
55                isParentContainer = this.isContainerElement(this.$element[0]) && !this.isContainerElement(this.$element[0].parentElement);
56            if ($wpAdminBar.length && 'top' === elementSettings.sticky && 'fixed' === $wpAdminBar.css('position')) {
57                stickyOptions.offset += $wpAdminBar.height();
58            }
59
60            // The `stickyOptions.parent` value should only be applied to inner elements, and not to top level containers.
61            if (elementSettings.sticky_parent && !isParentContainer) {
62                // TODO: The e-container classes should be removed in the next update.
63                stickyOptions.parent = '.e-container, .e-container__inner, .e-con, .e-con-inner, .elementor-widget-wrap';
64            }
65            return stickyOptions;
66        },
67        activate() {
68            this.currentConfig = this.getConfig();
69            this.$element.sticky(this.currentConfig);
70        },
71        deactivate() {
72            if (!this.isStickyInstanceActive()) {
73                return;
74            }
75            this.$element.sticky('destroy');
76        },
77        run(refresh) {
78            if (!this.getElementSettings('sticky')) {
79                this.deactivate();
80                return;
81            }
82            var currentDeviceMode = elementorFrontend.getCurrentDeviceMode(),
83                activeDevices = this.getElementSettings('sticky_on');
84            if (-1 !== activeDevices.indexOf(currentDeviceMode)) {
85                if (true === refresh) {
86                    this.reactivate();
87                } else if (!this.isStickyInstanceActive()) {
88                    this.activate();
89                }
90            } else {
91                this.deactivate();
92            }
93        },
94        /**
95         * Reactivate the sticky instance on resize only if the new sticky config is different from the current active one,
96         * in order to avoid re-initializing the sticky when not needed, and avoid layout shifts.
97         * The config can be different between devices, so this need to be checked on each screen resize to make sure that
98         * the current screen size uses the appropriate Sticky config.
99         *
100         * @return {void}
101         */
102        reactivateOnResize() {
103            clearTimeout(this.debouncedReactivate);
104            this.debouncedReactivate = setTimeout(() => {
105                const config = this.getConfig(),
106                    isDifferentConfig = JSON.stringify(config) !== JSON.stringify(this.currentConfig);
107                if (isDifferentConfig) {
108                    this.run(true);
109                }
110            }, 300);
111        },
112        reactivate() {
113            this.deactivate();
114            this.activate();
115        },
116        onElementChange(settingKey) {
117            if (-1 !== ['sticky', 'sticky_on'].indexOf(settingKey)) {
118                this.run(true);
119            }
120
121            // Settings that trigger a re-activation when changed.
122            const settings = [...this.getResponsiveSettingList('sticky_offset'), ...this.getResponsiveSettingList('sticky_effects_offset'), 'sticky_parent'];
123            if (-1 !== settings.indexOf(settingKey)) {
124                this.reactivate();
125            }
126        },
127        /**
128         * Listen to device mode changes and re-initialize the sticky.
129         *
130         * @return {void}
131         */
132        onDeviceModeChange() {
133            // Wait for the call stack to be empty.
134            // The `run` function requests the current device mode from the CSS so it's not ready immediately.
135            // (need to wait for the `deviceMode` event to change the CSS).
136            // See `elementorFrontend.getCurrentDeviceMode()` for reference.
137            setTimeout(() => this.run(true));
138        },
139        onInit() {
140            elementorModules.frontend.handlers.Base.prototype.onInit.apply(this, arguments);
141            if (elementorFrontend.isEditMode()) {
142                elementor.listenTo(elementor.channels.deviceMode, 'change', () => this.onDeviceModeChange());
143            }
144            this.run();
145        },
146        onDestroy() {
147            elementorModules.frontend.handlers.Base.prototype.onDestroy.apply(this, arguments);
148            this.deactivate();
149        },
150        /**
151         *
152         * @param {HTMLElement|null|undefined} element
153         * @return {boolean} Is the passed element a container.
154         */
155        isContainerElement(element) {
156            const containerClasses = [
157                // TODO: The e-container classes should be removed in the next update.
158                'e-container', 'e-container__inner', 'e-con', 'e-con-inner'];
159            return containerClasses.some(containerClass => {
160                return element?.classList.contains(containerClass);
161            });
162        }
163    });
164
165
166
167    $( window ).on( 'elementor/frontend/init', () => {
168        const addHandler = ( $element ) => {
169            elementorFrontend.elementsHandler.addHandler( _sticky, {
170                $element,
171            } );
172        };
173
174        elementorFrontend.hooks.addAction( 'frontend/element_ready/section', addHandler );
175        elementorFrontend.hooks.addAction( 'frontend/element_ready/container', addHandler );
176        elementorFrontend.hooks.addAction( 'frontend/element_ready/widget', addHandler );
177    } );
178
179}(jQuery, window.elementorFrontend, window.elementorModules));

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.