PageSourceSearch

https://www.eby.ee/wp-content/plugins/wp-analytify/assets/js/scrolldepth.js?ver=9.1.1

js eby.ee collected 2026-10-08 07:03:33 UTC 6,420 bytes, 241 lines download raw bytes

1(function ($) {
2
3	(function (factory) {
4		if (typeof define === 'function' && define.amd) {
5			// AMD
6			define(['jquery'], factory);
7		} else if (typeof module === 'object' && module.exports) {
8			// CommonJS
9			module.exports = factory(require('jquery'));
10		} else {
11			// Browser globals
12			factory(jQuery);
13		}
14	}(function ($) {
15
16		'use strict';
17
18		const defaults = {
19			percentage: true
20		};
21
22		const $window = $(window);
23
24		// Change these from const to let so they can be reassigned
25		let cache = [];
26		let scrollEventBound = false;
27		let lastPixelDepth = 0;
28
29		$.scrollDepth = function (options) {
30
31			const startTime = +new Date();
32
33			options = $.extend({}, defaults, options);
34
35			function sendEvent( page_link, percentage, scrollDistance, timing ) {
36				// Always use gtag for GA4 (since UA is deprecated)
37				if ( typeof gtag !== 'undefined' ) {
38					// Send scroll depth event for GA4
39					gtag('event', 'scroll_depth', {
40						'wpa_category': 'Analytify Scroll Depth',
41						'wpa_percentage': percentage,
42						'non_interaction': true
43					});
44
45					// Send timing event - always include timing data
46					const eventTiming = timing || (+new Date - startTime);
47					gtag('event', 'timing_complete', {
48						'event_category': 'Analytify Scroll Depth',
49						'event_label': page_link + ' - ' + percentage + '%',
50						'value': eventTiming,
51						'non_interaction': true
52					});
53				}
54			}
55
56			function calculateMarks(docHeight) {
57				return {
58					'25': parseInt(docHeight * 0.25, 10),
59					'50': parseInt(docHeight * 0.50, 10),
60					'75': parseInt(docHeight * 0.75, 10),
61					/* Cushion to trigger 100% event in iOS */
62					'100': docHeight - 5
63				};
64			}
65
66			function checkMarks(marks, scrollDistance, timing) {
67				/* Check each active mark */
68				$.each(marks, function (key, val) {
69					if ($.inArray(key, cache) === -1 && scrollDistance >= val) {
70						const permalink = ( typeof analytifyScroll !== 'undefined' && analytifyScroll.permalink ) ? analytifyScroll.permalink : window.location.href;
71						sendEvent(permalink, key, scrollDistance, timing);
72						cache.push(key);
73					}
74				});
75			}
76
77			function rounded(scrollDistance) {
78				/* Returns String */
79				return (Math.floor(scrollDistance / 250) * 250).toString();
80			}
81
82			function init() {
83				bindScrollDepth();
84
85				// Fire 100% event on load when content fits in the viewport
86				const docHeight = $(document).height();
87				const winHeight = window.innerHeight ? window.innerHeight : $window.height();
88				if (winHeight >= docHeight) {
89					const timing = +new Date - startTime;
90					const permalink = ( typeof analytifyScroll !== 'undefined' && analytifyScroll.permalink ) ? analytifyScroll.permalink : window.location.href;
91					// Avoid duplicate 100% event
92					if ($.inArray('100', cache) === -1) {
93						sendEvent(permalink, '100', docHeight, timing);
94						cache.push('100');
95					}
96				}
97			}
98
99
100			/* Reset Scroll Depth with the originally initialized options */
101			$.scrollDepth.reset = function () {
102				cache = [];
103				lastPixelDepth = 0;
104				$window.off('scroll.scrollDepth');
105				bindScrollDepth();
106			};
107
108			/* Add DOM elements to be tracked */
109			$.scrollDepth.addElements = function (elems) {
110
111				if (typeof elems == 'undefined' || ! $.isArray(elems)) {
112					return;
113				}
114
115				$.merge(options.elements, elems);
116
117				/* If scroll event has been unbound from window, rebind */
118				if (! scrollEventBound) {
119					bindScrollDepth();
120				}
121
122			};
123
124			/* Remove DOM elements currently tracked */
125			$.scrollDepth.removeElements = function (elems) {
126
127				if (typeof elems == 'undefined' || ! $.isArray(elems)) {
128					return;
129				}
130
131				$.each(elems, function (index, elem) {
132
133					const inElementsArray = $.inArray(elem, options.elements);
134					const inCacheArray = $.inArray(elem, cache);
135
136					if (inElementsArray != -1) {
137						options.elements.splice(inElementsArray, 1);
138					}
139
140					if (inCacheArray != -1) {
141						cache.splice(inCacheArray, 1);
142					}
143
144				});
145
146			};
147
148			function throttle(func, wait) {
149				let timeout = null;
150				let previous = 0;
151				return function () {
152					const context = this;
153					const args = arguments;
154					const now = new Date;
155					if (! previous) { previous = now; }
156					const remaining = wait - (now - previous);
157
158					if (remaining <= 0) {
159						clearTimeout(timeout);
160						timeout = null;
161						previous = now;
162						func.apply(context, args);
163					} else if (! timeout) {
164						timeout = setTimeout(function () {
165							previous = new Date;
166							timeout = null;
167							func.apply(context, args);
168						}, remaining);
169					}
170				};
171			}
172
173			/*
174			* Scroll Event
175			*/
176
177			function bindScrollDepth() {
178
179				scrollEventBound = true;
180
181				$window.on('scroll.scrollDepth', throttle(function () {
182				/*
183				* We calculate document and window height on each scroll event to
184				* account for dynamic DOM changes.
185				*/
186
187					const docHeight = $(document).height(),
188						winHeight = window.innerHeight ? window.innerHeight : $window.height(),
189						scrollDistance = $window.scrollTop() + winHeight,
190
191						/* Recalculate percentage marks */
192						marks = calculateMarks(docHeight),
193
194						/* Timing */
195						timing = +new Date - startTime;
196
197					checkMarks(marks, scrollDistance, timing);
198				}, 500));
199
200			}
201
202			init();
203		};
204
205		/* UMD export */
206		return $.scrollDepth;
207
208	}));
209
210	// Wait for gtag to be available before initializing scroll depth tracking
211	function initScrollDepth() {
212
213		// Check if gtag is available (either directly or via dataLayer)
214		if ( typeof gtag !== 'undefined' || ( typeof window.dataLayer !== 'undefined' && typeof window.dataLayer.push === 'function' ) ) {
215			$.scrollDepth();
216		} else {
217			// Retry after a short delay if gtag is not yet available (max 5 seconds)
218			const maxRetries = 50;
219			let retryCount = 0;
220			const checkInterval = setInterval( function () {
221				retryCount++;
222				if ( typeof gtag !== 'undefined' || ( typeof window.dataLayer !== 'undefined' && typeof window.dataLayer.push === 'function' ) ) {
223					clearInterval( checkInterval );
224					$.scrollDepth();
225				} else if ( retryCount >= maxRetries ) {
226					clearInterval( checkInterval );
227					// Initialize anyway - gtag might be loaded later
228					$.scrollDepth();
229				}
230			}, 100 );
231		}
232	}
233
234	// Initialize when DOM is ready
235	if ( document.readyState === 'loading' ) {
236		document.addEventListener( 'DOMContentLoaded', initScrollDepth );
237	} else {
238		initScrollDepth();
239	}
240
241})(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.