PageSourceSearch

https://parqueinnovacionba.com/wp-content/plugins/elementor-pro/assets/lib/sticky/jquery.sticky.js?ver=3.31.2

js parqueinnovacionba.com collected 2026-10-02 11:38:23 UTC 10,019 bytes, 395 lines download raw bytes

1/*
2 * By Elementor Team
3 */
4( function( $ ) {
5	var Sticky = function( element, userSettings ) {
6		var $element,
7			isSticky = false,
8			isFollowingParent = false,
9			isReachedEffectsPoint = false,
10			elements = {},
11			settings,
12			elementOffsetValue,
13			elementWidth;
14
15		var defaultSettings = {
16			to: 'top',
17			offset: 0,
18			effectsOffset: 0,
19			parent: false,
20			classes: {
21				sticky: 'sticky',
22				stickyActive: 'sticky-active',
23				stickyEffects: 'sticky-effects',
24				spacer: 'sticky-spacer',
25			},
26			isRTL: false,
27			isScrollSnapActive: false,
28			handleScrollbarWidth: false,
29		};
30
31		var initElements = function() {
32			$element = $( element ).addClass( settings.classes.sticky );
33
34			elements.$window = $( window );
35			elements.$body = $( document ).find( 'body' );
36
37			if ( settings.parent ) {
38				elements.$parent = $element.parent();
39
40				if ( 'parent' !== settings.parent ) {
41					elements.$parent = elements.$parent.closest( settings.parent );
42				}
43			}
44		};
45
46		var initSettings = function() {
47			settings = jQuery.extend( true, defaultSettings, userSettings );
48		};
49
50		var bindEvents = function() {
51			elements.$window.on( 'resize', onWindowResize );
52
53			if ( settings.isScrollSnapActive ) {
54				elements.$body.on( 'scroll', onWindowScroll );
55			} else {
56				elements.$window.on( 'scroll', onWindowScroll );
57			}
58		};
59
60		var unbindEvents = function() {
61			elements.$window
62				.off( 'scroll', onWindowScroll )
63				.off( 'resize', onWindowResize );
64
65			elements.$body.off( 'scroll', onWindowScroll );
66		};
67
68		var init = function() {
69			initSettings();
70
71			initElements();
72
73			bindEvents();
74
75			checkPosition();
76		};
77
78		var backupCSS = function( $elementBackupCSS, backupState, properties ) {
79			var css = {},
80				elementStyle = $elementBackupCSS[ 0 ].style;
81
82			properties.forEach( function( property ) {
83				css[ property ] = undefined !== elementStyle[ property ] ? elementStyle[ property ] : '';
84			} );
85
86			$elementBackupCSS.data( 'css-backup-' + backupState, css );
87		};
88
89		var getCSSBackup = function( $elementCSSBackup, backupState ) {
90			return $elementCSSBackup.data( 'css-backup-' + backupState );
91		};
92
93		const updateElementSizesData = () => {
94			elementWidth = getElementOuterSize( $element, 'width' );
95			elementOffsetValue = $element.offset().left;
96
97			if ( settings.isRTL ) {
98				// `window.innerWidth` includes the scrollbar while `document.body.offsetWidth` doesn't.
99				const documentWidth = settings.handleScrollbarWidth ? window.innerWidth : document.body.offsetWidth;
100
101				elementOffsetValue = Math.max( documentWidth - elementWidth - elementOffsetValue, 0 );
102			}
103		}
104
105		var addSpacer = function() {
106			elements.$spacer = $element.clone()
107				.addClass( settings.classes.spacer )
108				.css( {
109					visibility: 'hidden',
110					transition: 'none',
111					animation: 'none',
112				} );
113
114			$element.after( elements.$spacer );
115		};
116
117		var removeSpacer = function() {
118			elements.$spacer.remove();
119		};
120
121		var stickElement = function() {
122			backupCSS( $element, 'unsticky', [ 'position', 'width', 'margin-top', 'margin-bottom', 'top', 'bottom', 'inset-inline-start' ] );
123
124			const css = {
125				position: 'fixed',
126				width: elementWidth,
127				marginTop: 0,
128				marginBottom: 0,
129			};
130
131			css[ settings.to ] = settings.offset;
132			css[ 'top' === settings.to ? 'bottom' : 'top' ] = '';
133
134			if ( elementOffsetValue ) {
135				css[ 'inset-inline-start' ] = elementOffsetValue + 'px';
136			}
137
138			$element
139				.css( css )
140				.addClass( settings.classes.stickyActive );
141		};
142
143		var unstickElement = function() {
144			$element
145				.css( getCSSBackup( $element, 'unsticky' ) )
146				.removeClass( settings.classes.stickyActive );
147		};
148
149		var followParent = function() {
150			backupCSS( elements.$parent, 'childNotFollowing', [ 'position' ] );
151
152			elements.$parent.css( 'position', 'relative' );
153
154			backupCSS( $element, 'notFollowing', [ 'position', 'inset-inline-start', 'top', 'bottom' ] );
155
156			const css = {
157				position: 'absolute',
158			};
159
160			elementOffsetValue = elements.$spacer.position().left;
161
162			if ( settings.isRTL ) {
163				const parentWidth = $element.parent().outerWidth(),
164					elementOffsetValueLeft = elements.$spacer.position().left;
165
166				elementWidth = elements.$spacer.outerWidth();
167				elementOffsetValue = Math.max( parentWidth - elementWidth - elementOffsetValueLeft, 0 );
168			}
169
170			css[ 'inset-inline-start' ] = elementOffsetValue + 'px';
171
172			css[ settings.to ] = '';
173
174			css[ 'top' === settings.to ? 'bottom' : 'top' ] = 0;
175
176			$element.css( css );
177
178			isFollowingParent = true;
179		};
180
181		var unfollowParent = function() {
182			elements.$parent.css( getCSSBackup( elements.$parent, 'childNotFollowing' ) );
183
184			$element.css( getCSSBackup( $element, 'notFollowing' ) );
185
186			isFollowingParent = false;
187		};
188
189		var getElementOuterSize = function( $elementOuterSize, dimension, includeMargins ) {
190			var computedStyle = getComputedStyle( $elementOuterSize[ 0 ] ),
191				elementSize = parseFloat( computedStyle[ dimension ] ),
192				sides = 'height' === dimension ? [ 'top', 'bottom' ] : [ 'left', 'right' ],
193				propertiesToAdd = [];
194
195			if ( 'border-box' !== computedStyle.boxSizing ) {
196				propertiesToAdd.push( 'border', 'padding' );
197			}
198
199			if ( includeMargins ) {
200				propertiesToAdd.push( 'margin' );
201			}
202
203			propertiesToAdd.forEach( function( property ) {
204				sides.forEach( function( side ) {
205					elementSize += parseFloat( computedStyle[ property + '-' + side ] );
206				} );
207			} );
208
209			return elementSize;
210		};
211
212		var getElementViewportOffset = function( $elementViewportOffset ) {
213			var windowScrollTop = elements.$window.scrollTop(),
214				elementHeight = getElementOuterSize( $elementViewportOffset, 'height' ),
215				viewportHeight = innerHeight,
216				elementOffsetFromTop = $elementViewportOffset.offset().top,
217				distanceFromTop = elementOffsetFromTop - windowScrollTop,
218				topFromBottom = distanceFromTop - viewportHeight;
219
220			return {
221				top: {
222					fromTop: distanceFromTop,
223					fromBottom: topFromBottom,
224				},
225				bottom: {
226					fromTop: distanceFromTop + elementHeight,
227					fromBottom: topFromBottom + elementHeight,
228				},
229			};
230		};
231
232		var stick = function() {
233			updateElementSizesData();
234
235			addSpacer();
236
237			stickElement();
238
239			isSticky = true;
240
241			$element.trigger( 'sticky:stick' );
242		};
243
244		var unstick = function() {
245			unstickElement();
246
247			removeSpacer();
248
249			isSticky = false;
250
251			$element.trigger( 'sticky:unstick' );
252		};
253
254		var checkParent = function() {
255			var elementOffset = getElementViewportOffset( $element ),
256				isTop = 'top' === settings.to;
257
258			if ( isFollowingParent ) {
259				var isNeedUnfollowing = isTop ? elementOffset.top.fromTop > settings.offset : elementOffset.bottom.fromBottom < -settings.offset;
260
261				if ( isNeedUnfollowing ) {
262					unfollowParent();
263				}
264			} else {
265				var parentOffset = getElementViewportOffset( elements.$parent ),
266					parentStyle = getComputedStyle( elements.$parent[ 0 ] ),
267					borderWidthToDecrease = parseFloat( parentStyle[ isTop ? 'borderBottomWidth' : 'borderTopWidth' ] ),
268					parentViewportDistance = isTop ? parentOffset.bottom.fromTop - borderWidthToDecrease : parentOffset.top.fromBottom + borderWidthToDecrease,
269					isNeedFollowing = isTop ? parentViewportDistance <= elementOffset.bottom.fromTop : parentViewportDistance >= elementOffset.top.fromBottom;
270
271				if ( isNeedFollowing ) {
272					followParent();
273				}
274			}
275		};
276
277		var checkEffectsPoint = function( distanceFromTriggerPoint ) {
278			if ( isReachedEffectsPoint && -distanceFromTriggerPoint < settings.effectsOffset ) {
279				$element.removeClass( settings.classes.stickyEffects );
280
281				isReachedEffectsPoint = false;
282			} else if ( ! isReachedEffectsPoint && -distanceFromTriggerPoint >= settings.effectsOffset ) {
283				$element.addClass( settings.classes.stickyEffects );
284
285				isReachedEffectsPoint = true;
286			}
287		};
288
289		var checkPosition = function() {
290			var offset = settings.offset,
291				distanceFromTriggerPoint;
292
293			if ( isSticky ) {
294				var spacerViewportOffset = getElementViewportOffset( elements.$spacer );
295
296				distanceFromTriggerPoint = 'top' === settings.to ? spacerViewportOffset.top.fromTop - offset : -spacerViewportOffset.bottom.fromBottom - offset;
297
298				if ( settings.parent ) {
299					checkParent();
300				}
301
302				if ( distanceFromTriggerPoint > 0 ) {
303					unstick();
304				}
305			} else {
306				var elementViewportOffset = getElementViewportOffset( $element );
307
308				distanceFromTriggerPoint = 'top' === settings.to ? elementViewportOffset.top.fromTop - offset : -elementViewportOffset.bottom.fromBottom - offset;
309
310				if ( distanceFromTriggerPoint <= 0 ) {
311					stick();
312
313					if ( settings.parent ) {
314						checkParent();
315					}
316				}
317			}
318
319			checkEffectsPoint( distanceFromTriggerPoint );
320		};
321
322		var onWindowScroll = function() {
323			checkPosition();
324		};
325
326		var onWindowResize = function() {
327			if ( ! isSticky ) {
328				return;
329			}
330
331			unstickElement();
332
333			removeSpacer();
334
335			updateElementSizesData();
336
337			addSpacer();
338
339			stickElement();
340
341			if ( settings.parent ) {
342				// Force recalculation of the relation between the element and its parent.
343				isFollowingParent = false;
344
345				checkParent();
346			}
347		};
348
349		this.destroy = function() {
350			if ( isSticky ) {
351				unstick();
352			}
353
354			unbindEvents();
355
356			$element.removeClass( settings.classes.sticky );
357		};
358
359		init();
360	};
361
362	$.fn.sticky = function( settings ) {
363		var isCommand = 'string' === typeof settings;
364
365		this.each( function() {
366			var $this = $( this );
367
368			if ( ! isCommand ) {
369				$this.data( 'sticky', new Sticky( this, settings ) );
370
371				return;
372			}
373
374			var instance = $this.data( 'sticky' );
375
376			if ( ! instance ) {
377				throw Error( 'Trying to perform the `' + settings + '` method prior to initialization' );
378			}
379
380			if ( ! instance[ settings ] ) {
381				throw ReferenceError( 'Method `' + settings + '` not found in sticky instance' );
382			}
383
384			instance[ settings ].apply( instance, Array.prototype.slice.call( arguments, 1 ) );
385
386			if ( 'destroy' === settings ) {
387				$this.removeData( 'sticky' );
388			}
389		} );
390
391		return this;
392	};
393
394	window.Sticky = Sticky;
395} )( jQuery );

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.