PageSourceSearch

https://www.socceraid.org.uk/wp-content/themes/unicef/assets/js/src/scroll-tracking.js?ver=1.8.3

js socceraid.org.uk collected 2026-10-02 06:27:42 UTC 9,374 bytes, 325 lines download raw bytes

1/*!
2 * @preserve
3 * jquery.scrolldepth.js | v0.9.1
4 * Copyright (c) 2016 Rob Flaherty (@robflaherty)
5 * Licensed under the MIT and GPL licenses.
6 */
7
8/* Universal module definition */
9/* jshint ignore:start */
10(function(factory) {
11  if (typeof define === 'function' && define.amd) {
12    // AMD
13    define(['jquery'], factory);
14  } else if (typeof module === 'object' && module.exports) {
15    // CommonJS
16    module.exports = factory(require('jquery'));
17  } else {
18    // Browser globals
19    factory(jQuery);
20  }
21}(function($) {
22
23/* Scroll Depth */
24
25    "use strict";
26
27    var defaults = {
28      minHeight: 0,
29      elements: [],
30      percentage: true,
31      userTiming: false,
32      pixelDepth: true,
33      nonInteraction: true,
34      gaGlobal: false,
35      gtmOverride: false
36    };
37
38    var $window = $(window),
39      cache = [],
40      scrollEventBound = false,
41      lastPixelDepth = 0,
42      universalGA,
43      classicGA,
44      gaGlobal,
45      standardEventHandler;
46
47    /*
48     * Plugin
49     */
50
51    $.scrollDepth = function(options) {
52
53      var startTime = +new Date;
54
55      options = $.extend({}, defaults, options);
56
57      // Return early if document height is too small
58      if ( $(document).height() < options.minHeight ) {
59        return;
60      }
61
62      /*
63       * Determine which version of GA is being used
64       * "ga", "__gaTracker", _gaq", and "dataLayer" are the possible globals
65       */
66
67      if (options.gaGlobal) {
68        universalGA = true;
69        gaGlobal = options.gaGlobal;
70      } else if (typeof ga === "function") {
71        universalGA = true;
72        gaGlobal = 'ga';
73      } else if (typeof __gaTracker === "function") {
74        universalGA = true;
75        gaGlobal = '__gaTracker';
76      }
77
78      if (typeof _gaq !== "undefined" && typeof _gaq.push === "function") {
79        classicGA = true;
80      }
81
82      if (typeof options.eventHandler === "function") {
83        standardEventHandler = options.eventHandler;
84      } else if (typeof dataLayer !== "undefined" && typeof dataLayer.push === "function" && !options.gtmOverride) {
85
86        standardEventHandler = function(data) {
87          dataLayer.push(data);
88        };
89      }
90
91      /*
92       * Functions
93       */
94
95      function sendEvent(action, label, scrollDistance, timing) {
96
97        if (standardEventHandler) {
98
99          standardEventHandler({'event': 'ScrollDistance', 'eventCategory': 'Scroll Depth', 'eventAction': action, 'eventLabel': label, 'eventValue': 1, 'eventNonInteraction': options.nonInteraction, 'eventTiming': timing});
100
101          if (options.pixelDepth && arguments.length > 2 && scrollDistance > lastPixelDepth) {
102            lastPixelDepth = scrollDistance;
103            standardEventHandler({'event': 'ScrollDistance', 'eventCategory': 'Scroll Depth', 'eventAction': 'Pixel Depth', 'eventLabel': rounded(scrollDistance), 'eventValue': 1, 'eventNonInteraction': options.nonInteraction, 'eventTiming': timing});
104          }
105
106          if (options.userTiming && arguments.length > 3) {
107            standardEventHandler({'event': 'ScrollTiming', 'eventCategory': 'Scroll Depth', 'eventAction': action, 'eventLabel': label, 'eventTiming': timing});
108          }
109
110        } else {
111
112          if (universalGA) {
113
114            window[gaGlobal]('send', 'event', 'Scroll Depth', action, label, 1, {'nonInteraction': options.nonInteraction});
115
116            if (options.pixelDepth && arguments.length > 2 && scrollDistance > lastPixelDepth) {
117              lastPixelDepth = scrollDistance;
118              window[gaGlobal]('send', 'event', 'Scroll Depth', 'Pixel Depth', rounded(scrollDistance), 1, {'nonInteraction': options.nonInteraction});
119            }
120
121            if (options.userTiming && arguments.length > 3) {
122              window[gaGlobal]('send', 'timing', 'Scroll Depth', action, timing, label);
123            }
124
125          }
126
127          if (classicGA) {
128
129            _gaq.push(['_trackEvent', 'Scroll Depth', action, label, 1, options.nonInteraction]);
130
131            if (options.pixelDepth && arguments.length > 2 && scrollDistance > lastPixelDepth) {
132              lastPixelDepth = scrollDistance;
vendor: 4,508 bytes, lines 133-292
133              _gaq.push(['_trackEvent', 'Scroll Depth', 'Pixel Depth', rounded(scrollDistance), 1, options.nonInteraction]);
134            }
135
136            if (options.userTiming && arguments.length > 3) {
137              _gaq.push(['_trackTiming', 'Scroll Depth', action, timing, label, 100]);
138            }
139
140          }
141
142        }
143
144      }
145
146      function calculateMarks(docHeight) {
147        return {
148          '25%' : parseInt(docHeight * 0.25, 10),
149          '50%' : parseInt(docHeight * 0.50, 10),
150          '75%' : parseInt(docHeight * 0.75, 10),
151          // Cushion to trigger 100% event in iOS
152          '100%': docHeight - 5
153        };
154      }
155
156      function checkMarks(marks, scrollDistance, timing) {
157        // Check each active mark
158        $.each(marks, function(key, val) {
159          if ( $.inArray(key, cache) === -1 && scrollDistance >= val ) {
160            sendEvent('Percentage', key, scrollDistance, timing);
161            cache.push(key);
162          }
163        });
164      }
165
166      function checkElements(elements, scrollDistance, timing) {
167        $.each(elements, function(index, elem) {
168          if ( $.inArray(elem, cache) === -1 && $(elem).length ) {
169            if ( scrollDistance >= $(elem).offset().top ) {
170              sendEvent('Elements', elem, scrollDistance, timing);
171              cache.push(elem);
172            }
173          }
174        });
175      }
176
177      function rounded(scrollDistance) {
178        // Returns String
179        return (Math.floor(scrollDistance/250) * 250).toString();
180      }
181
182      function init() {
183        bindScrollDepth();
184      }
185
186      /*
187       * Public Methods
188       */
189
190      // Reset Scroll Depth with the originally initialized options
191      $.scrollDepth.reset = function() {
192        cache = [];
193        lastPixelDepth = 0;
194        $window.off('scroll.scrollDepth');
195        bindScrollDepth();
196      };
197
198      // Add DOM elements to be tracked
199      $.scrollDepth.addElements = function(elems) {
200
201        if (typeof elems == "undefined" || !$.isArray(elems)) {
202          return;
203        }
204
205        $.merge(options.elements, elems);
206
207        // If scroll event has been unbound from window, rebind
208        if (!scrollEventBound) {
209          bindScrollDepth();
210        }
211
212      };
213
214      // Remove DOM elements currently tracked
215      $.scrollDepth.removeElements = function(elems) {
216
217        if (typeof elems == "undefined" || !$.isArray(elems)) {
218          return;
219        }
220
221        $.each(elems, function(index, elem) {
222
223          var inElementsArray = $.inArray(elem, options.elements);
224          var inCacheArray = $.inArray(elem, cache);
225
226          if (inElementsArray != -1) {
227            options.elements.splice(inElementsArray, 1);
228          }
229
230          if (inCacheArray != -1) {
231            cache.splice(inCacheArray, 1);
232          }
233
234        });
235
236      };
237
238      /*
239       * Throttle function borrowed from:
240       * Underscore.js 1.5.2
241       * http://underscorejs.org
242       * (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
243       * Underscore may be freely distributed under the MIT license.
244       */
245
246      function throttle(func, wait) {
247        var context, args, result;
248        var timeout = null;
249        var previous = 0;
250        var later = function() {
251          previous = new Date;
252          timeout = null;
253          result = func.apply(context, args);
254        };
255        return function() {
256          var now = new Date;
257          if (!previous) previous = now;
258          var remaining = wait - (now - previous);
259          context = this;
260          args = arguments;
261          if (remaining <= 0) {
262            clearTimeout(timeout);
263            timeout = null;
264            previous = now;
265            result = func.apply(context, args);
266          } else if (!timeout) {
267            timeout = setTimeout(later, remaining);
268          }
269          return result;
270        };
271      }
272
273      /*
274       * Scroll Event
275       */
276
277      function bindScrollDepth() {
278
279        scrollEventBound = true;
280
281        $window.on('scroll.scrollDepth', throttle(function() {
282          /*
283           * We calculate document and window height on each scroll event to
284           * account for dynamic DOM changes.
285           */
286
287          var docHeight = $(document).height(),
288            winHeight = window.innerHeight ? window.innerHeight : $window.height(),
289            scrollDistance = $window.scrollTop() + winHeight,
290
291            // Recalculate percentage marks
292            marks = calculateMarks(docHeight),
293
294            // Timing
295            timing = +new Date - startTime;
296
297          // If all marks already hit, unbind scroll event
298          if (cache.length >= options.elements.length + (options.percentage ? 4:0)) {
299            $window.off('scroll.scrollDepth');
300            scrollEventBound = false;
301            return;
302          }
303
304          // Check specified DOM elements
305          if (options.elements) {
306            checkElements(options.elements, scrollDistance, timing);
307          }
308
309          // Check standard marks
310          if (options.percentage) {
311            checkMarks(marks, scrollDistance, timing);
312          }
313        }, 500));
314
315      }
316
317      init();
318
319    };
320
321}));
322jQuery(function() {
323  jQuery.scrollDepth();
324});
325/* jshint ignore:end */

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.