PageRenderTime 61ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/ajax/libs/jquery-scrolldepth/0.7.1/jquery.scrolldepth.js

https://gitlab.com/Mirros/cdnjs
JavaScript | 260 lines | 157 code | 60 blank | 43 comment | 46 complexity | e37d6b7fcd5668bb4b27e47304262624 MD5 | raw file
  1. /*!
  2. * @preserve
  3. * jquery.scrolldepth.js | v0.7.1
  4. * Copyright (c) 2014 Rob Flaherty (@robflaherty)
  5. * Licensed under the MIT and GPL licenses.
  6. */
  7. ;(function ( $, window, document, undefined ) {
  8. "use strict";
  9. var defaults = {
  10. minHeight: 0,
  11. elements: [],
  12. percentage: true,
  13. userTiming: true,
  14. pixelDepth: true,
  15. nonInteraction: true
  16. };
  17. var $window = $(window),
  18. cache = [],
  19. lastPixelDepth = 0,
  20. universalGA,
  21. classicGA,
  22. standardEventHandler;
  23. /*
  24. * Plugin
  25. */
  26. $.scrollDepth = function(options) {
  27. var startTime = +new Date;
  28. options = $.extend({}, defaults, options);
  29. // Return early if document height is too small
  30. if ( $(document).height() < options.minHeight ) {
  31. return;
  32. }
  33. /*
  34. * Determine which version of GA is being used
  35. * "ga", "_gaq", and "dataLayer" are the possible globals
  36. */
  37. if (typeof ga === "function") {
  38. universalGA = true;
  39. }
  40. if (typeof _gaq !== "undefined" && typeof _gaq.push === "function") {
  41. classicGA = true;
  42. }
  43. if (typeof options.eventHandler === "function") {
  44. standardEventHandler = options.eventHandler;
  45. } else if (typeof dataLayer !== "undefined" && typeof dataLayer.push === "function") {
  46. standardEventHandler = dataLayer.push;
  47. }
  48. if (options.percentage) {
  49. // Establish baseline (0% scroll)
  50. sendBaseline('Percentage');
  51. } else if (options.elements) {
  52. sendBaseline('Elements');
  53. }
  54. /*
  55. * Functions
  56. */
  57. /*
  58. * Putting this in a separate function because the Baseline event may soon be removed entirely
  59. */
  60. function sendBaseline(action, label) {
  61. if (standardEventHandler) {
  62. standardEventHandler({'event': 'ScrollDistance', 'eventCategory': 'Scroll Depth', 'eventAction': action, 'eventLabel': 'Baseline', 'eventValue': 1, 'eventNonInteraction': true });
  63. } else {
  64. if (universalGA) {
  65. ga('send', 'event', 'Scroll Depth', action, 'Baseline', 1, {'nonInteraction': true });
  66. }
  67. if (classicGA) {
  68. _gaq.push(['_trackEvent', 'Scroll Depth', action, 'Baseline', 1, true]);
  69. }
  70. }
  71. }
  72. function sendEvent(action, label, scrollDistance, timing) {
  73. if (standardEventHandler) {
  74. standardEventHandler({'event': 'ScrollDistance', 'eventCategory': 'Scroll Depth', 'eventAction': action, 'eventLabel': label, 'eventValue': 1, 'eventNonInteraction': options.nonInteraction});
  75. if (options.pixelDepth && arguments.length > 2 && scrollDistance > lastPixelDepth) {
  76. lastPixelDepth = scrollDistance;
  77. standardEventHandler({'event': 'ScrollDistance', 'eventCategory': 'Scroll Depth', 'eventAction': 'Pixel Depth', 'eventLabel': rounded(scrollDistance), 'eventValue': 1, 'eventNonInteraction': options.nonInteraction});
  78. }
  79. if (options.userTiming && arguments.length > 3) {
  80. standardEventHandler({'event': 'ScrollTiming', 'eventCategory': 'Scroll Depth', 'eventAction': action, 'eventLabel': label, 'eventTiming': timing});
  81. }
  82. } else {
  83. if (universalGA) {
  84. ga('send', 'event', 'Scroll Depth', action, label, 1, {'nonInteraction': options.nonInteraction});
  85. if (options.pixelDepth && arguments.length > 2 && scrollDistance > lastPixelDepth) {
  86. lastPixelDepth = scrollDistance;
  87. ga('send', 'event', 'Scroll Depth', 'Pixel Depth', rounded(scrollDistance), 1, {'nonInteraction': options.nonInteraction});
  88. }
  89. if (options.userTiming && arguments.length > 3) {
  90. ga('send', 'timing', 'Scroll Depth', action, timing, label);
  91. }
  92. }
  93. if (classicGA) {
  94. _gaq.push(['_trackEvent', 'Scroll Depth', action, label, 1, options.nonInteraction]);
  95. if (options.pixelDepth && arguments.length > 2 && scrollDistance > lastPixelDepth) {
  96. lastPixelDepth = scrollDistance;
  97. _gaq.push(['_trackEvent', 'Scroll Depth', 'Pixel Depth', rounded(scrollDistance), 1, options.nonInteraction]);
  98. }
  99. if (options.userTiming && arguments.length > 3) {
  100. _gaq.push(['_trackTiming', 'Scroll Depth', action, timing, label, 100]);
  101. }
  102. }
  103. }
  104. }
  105. function calculateMarks(docHeight) {
  106. return {
  107. '25%' : parseInt(docHeight * 0.25, 10),
  108. '50%' : parseInt(docHeight * 0.50, 10),
  109. '75%' : parseInt(docHeight * 0.75, 10),
  110. // 1px cushion to trigger 100% event in iOS
  111. '100%': docHeight - 5
  112. };
  113. }
  114. function checkMarks(marks, scrollDistance, timing) {
  115. // Check each active mark
  116. $.each(marks, function(key, val) {
  117. if ( $.inArray(key, cache) === -1 && scrollDistance >= val ) {
  118. sendEvent('Percentage', key, scrollDistance, timing);
  119. cache.push(key);
  120. }
  121. });
  122. }
  123. function checkElements(elements, scrollDistance, timing) {
  124. $.each(elements, function(index, elem) {
  125. if ( $.inArray(elem, cache) === -1 && $(elem).length ) {
  126. if ( scrollDistance >= $(elem).offset().top ) {
  127. sendEvent('Elements', elem, scrollDistance, timing);
  128. cache.push(elem);
  129. }
  130. }
  131. });
  132. }
  133. function rounded(scrollDistance) {
  134. // Returns String
  135. return (Math.floor(scrollDistance/250) * 250).toString();
  136. }
  137. /*
  138. * Throttle function borrowed from:
  139. * Underscore.js 1.5.2
  140. * http://underscorejs.org
  141. * (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
  142. * Underscore may be freely distributed under the MIT license.
  143. */
  144. function throttle(func, wait) {
  145. var context, args, result;
  146. var timeout = null;
  147. var previous = 0;
  148. var later = function() {
  149. previous = new Date;
  150. timeout = null;
  151. result = func.apply(context, args);
  152. };
  153. return function() {
  154. var now = new Date;
  155. if (!previous) previous = now;
  156. var remaining = wait - (now - previous);
  157. context = this;
  158. args = arguments;
  159. if (remaining <= 0) {
  160. clearTimeout(timeout);
  161. timeout = null;
  162. previous = now;
  163. result = func.apply(context, args);
  164. } else if (!timeout) {
  165. timeout = setTimeout(later, remaining);
  166. }
  167. return result;
  168. };
  169. }
  170. /*
  171. * Scroll Event
  172. */
  173. $window.on('scroll.scrollDepth', throttle(function() {
  174. /*
  175. * We calculate document and window height on each scroll event to
  176. * account for dynamic DOM changes.
  177. */
  178. var docHeight = $(document).height(),
  179. winHeight = window.innerHeight ? window.innerHeight : $window.height(),
  180. scrollDistance = $window.scrollTop() + winHeight,
  181. // Recalculate percentage marks
  182. marks = calculateMarks(docHeight),
  183. // Timing
  184. timing = +new Date - startTime;
  185. // If all marks already hit, unbind scroll event
  186. if (cache.length >= 4 + options.elements.length) {
  187. $window.off('scroll.scrollDepth');
  188. return;
  189. }
  190. // Check specified DOM elements
  191. if (options.elements) {
  192. checkElements(options.elements, scrollDistance, timing);
  193. }
  194. // Check standard marks
  195. if (options.percentage) {
  196. checkMarks(marks, scrollDistance, timing);
  197. }
  198. }, 500));
  199. };
  200. })( jQuery, window, document );