PageSourceSearch

https://eoipsocommunications.com/wp-content/plugins/greyd-plugin/s…/animations/scroll-observer.js?ver=2.15.0

js eoipsocommunications.com collected 2026-10-04 20:17:58 UTC 7,413 bytes, 260 lines download raw bytes

1/**
2 * Greyd public scroll event handler.
3 * 
4 * This script can handle scroll events globally to save ressources.
5 * Elements can be observed entering and/or leaving the viewport
6 * or while they are in the viewport.
7 * You can easily add elements to be observed using this function:
8 * @see greyd.scrollObserver.observeElement()
9 * 
10 * @since 1.6.0
11 * @namespace greyd
12 * 
13 * @note This script is not loaded by default. Currently it is only used
14 * inside the animation feature and therefore stil located here.
15 * @todo Move this script to a more appropriate location as soon
16 * as it is used in other features as well.
17 * 
18 * @todo IntersectionObserver polyfill:
19 * We still need to add a polyfill for backwards compatiblity with
20 * older browsers, even though support for it is above 95% as of
21 * January 2023.
22 * @link https://caniuse.com/intersectionobserver
23 */
24var greyd = greyd || {};
25
26greyd.scrollObserver = new function () {
27
28	/**
29	 * This class defines the way observed target elements are saved.
30	 * @param {documentElement} target
31	 * @param {function} callback
32	 * @param {string} type
33	 * 
34	 * @see greyd.scrollObserver.observeElement() for more details.
35	 */
36	class observedElement {
37		constructor ( target, callback, type ) {
38			this.target = target;
39			this.callback = callback;
40			this.type = typeof type === 'undefined' ? 'once' : type;
41		}
42	}
43
44	/**
45	 * Holds all targets to be observed.
46	 * @var {observedElement[]}
47	 */
48	this.allObservedElements = [];
49
50	/**
51	 * Holds all observed targets that are currently in the viewport.
52	 * @var {documentElement[]}
53	 */
54	this.allViewportElements = [];
55
56	/**
57	 * Holds the IntersectionObserver.
58	 * @link https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
59	 * @var {object}
60	 */
61	this.intersectionObserver;
62
63	/**
64	 * Holds the configuration for the IntersectionObserver.
65	 */
66	this.intersectionObserverConfig = {
67		root: null, // The element used as the viewport for checking visibility
68		rootMargin: '0px', // Margin around the root. Can have values similar to the CSS
69		threshold: 0  // what percentage of the target is visible
70	};
71
72	/**
73	 * Init the observer.
74	 * This function is automatically called once the first element
75	 * is registered using `greyd.scrollObserver.observeElement()`
76	 */
77	this.init = function () {
78
79		// define the IntersectionObserver
80		if ( "IntersectionObserver" in window ) {
81			this.intersectionObserver = new IntersectionObserver(
82				( entries ) => {
83					entries.forEach( ( entry ) => {
84						if ( entry.intersectionRatio >= 0 ) {
85							this.entersViewport( entry.target );
86						} else {
87							this.leavesViewport( entry.target );
88						}
89					} );
90				},
91				this.intersectionObserverConfig
92			);
93		} else {
94			/** @todo fallback for IntersectionObserver  */
95		}
96
97		// define scroll event listener
98		document.addEventListener( 'scroll', this.onScroll );
99	};
100
101	/**
102	 * Start observing an element.
103	 * @param {documentElement} target DOM element.
104	 * @param {function} callback      Callback function. Called with target as argument.
105	 *      @argument {documentElement} target
106	 *      @argument {object} event
107	 *      @argument {bool} inViewport
108	 * @param {string} type            How to observe the element:
109	 *      @value once    Callback is called one time as soon as the target is in the viewport.
110	 *                     After that the element is no longer observed.
111	 *      @value change  Target stays observed and callback is fired each time the target
112	 *                     enters or leaves the viewport.
113	 *      @value always  Target stays observed and callback is fired on every scroll event
114	 *                     while the element is in the viewport.
115	 */
116	this.observeElement = function ( target, callback, type ) {
117
118		// init the observer
119		if ( ! this.intersectionObserver ) {
120			this.init();
121		}
122
123		this.intersectionObserver.observe( target );
124		this.allObservedElements.push(
125			new observedElement( target, callback, type )
126		);
127	};
128
129	/**
130	 * Stop observing an element.
131	 * @param {documentElement} target DOM element.
132	 */
133	this.unobserveElement = function ( target ) {
134		this.intersectionObserver.unobserve( target );
135
136		// remove target from current observed elements
137		let index = this.allObservedElements.indexOf( target );
138		if ( index > -1 ) {
139			this.allObservedElements.splice( index, 1 );
140		}
141
142		// remove target from current viewport elements
143		index = this.allViewportElements.indexOf( target );
144		if ( index > -1 ) {
145			this.allViewportElements.splice( index, 1 );
146		}
147	};
148
149	/**
150	 * A target element enters the viewport.
151	 * @param {documentElement} target DOM element.
152	 */
153	this.entersViewport = function ( target ) {
154
155		var elements = this.getObservedElements( target );
156		if ( elements ) elements.forEach( ( element ) => {
157				
158			const { callback, type } = element;
159
160			if ( type === 'always' ) {
161				// add target to current viewport elements.
162				this.allViewportElements.push( target );
163			}
164			else if ( type === 'once' ) {
165				// unobserve, because we no longer need to watch it.
166				this.unobserveElement( target );
167			}
168
169			callback( target, null, true );
170			
171		} );
172
173	};
174
175	/**
176	 * A target element leaves the viewport.
177	 * @param {documentElement} target DOM element.
178	 */
179	this.leavesViewport = function ( target ) {
180	
181		// remove target from current viewport elements
182		const index = this.allViewportElements.indexOf( target );
183		if ( index > -1 ) {
184			this.allViewportElements.splice( index, 1 );
185		}
186
187		var elements = this.getObservedElements( target );
188		if ( elements ) elements.forEach( ( element ) => {
189				
190			const { callback, type } = element;
191
192			if ( type === 'change' ) {
193				// trigger change
194				callback( target, null, false );
195			}
196
197		} );
198
199	};
200
201	/**
202	 * A target element is in the viewport.
203	 * @param {documentElement} target DOM element.
204	 * @param {object} e Scroll event.
205	 */
206	this.whileInViewport = function ( target, e ) {
207
208		var elements = this.getObservedElements( target );
209		if ( elements ) elements.forEach( ( element ) => {
210
211			const { callback } = element;
212
213			callback( target, e, true );
214
215		} );
216
217	};
218
219	/**
220	 * User scrolls.
221	 * @param {object} e Scroll event.
222	 */
223	this.onScroll = function ( e ) {
224
225		if ( this.allViewportElements.length === 0 ) return;
226
227		this.allViewportElements.forEach(
228			target => this.whileInViewport( target, e )
229		)
230	};
231
232	/**
233	 * Get the observedElement objects of the current target.
234	 * @since 1.13.0
235	 * return array instead of single element to allow
236	 * multiple callbacks on one observed element.
237	 * 
238	 * @param {documentElement} target DOM element.
239	 * @returns {observedElement[]}
240	 */
241	this.getObservedElements = function ( target ) {
242		const result = this.allObservedElements.filter( obj => {
243			return obj.target === target;
244		} );
245		return result.length ? result : null;
246	};
247
248
249	/**
250	 * bind keyword "this" inside functions to the class object
251	 */
252	this.init                   = this.init.bind( this );
253	this.observeElement         = this.observeElement.bind( this );
254	this.unobserveElement       = this.unobserveElement.bind( this );
255	this.entersViewport         = this.entersViewport.bind( this );
256	this.leavesViewport         = this.leavesViewport.bind( this );
257	this.onScroll               = this.onScroll.bind( this );
258	this.whileInViewport        = this.whileInViewport.bind( this );
259	this.getObservedElements    = this.getObservedElements.bind( this );
260};

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.