forked from Bounteous-Inc/scroll
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathluna-scroll-tracking.json
More file actions
186 lines (186 loc) · 18.1 KB
/
luna-scroll-tracking.json
File metadata and controls
186 lines (186 loc) · 18.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
{
"exportFormatVersion": 1.3,
"exportTime": "2015-10-16 20:33:36",
"containerVersion": {
"accountId": "28896164",
"containerId": "1607357",
"containerVersionId": "0",
"deleted": false,
"container": {
"accountId": "28896164",
"containerId": "1607357",
"name": "Scroll Tracking",
"publicId": "GTM-T7FDZT",
"timeZoneCountryId": "US",
"timeZoneId": "America/Los_Angeles",
"notes": "",
"usageContext": ["WEB"],
"fingerprint": "1445027600600",
"enabledBuiltInVariable": ["DEBUG_MODE"]
},
"tag": [{
"accountId": "28896164",
"containerId": "1607357",
"tagId": "19",
"name": "CU - Scroll Tracking - LunaMetrics Plugin",
"type": "html",
"liveOnly": false,
"parameter": [{
"type": "BOOLEAN",
"key": "supportDocumentWrite",
"value": "false"
}, {
"type": "TEMPLATE",
"key": "html",
"value": "<script type=\"text/javascript\" id=\"gtm-scroll-tracking\">\n;(function(document, window, config) {\n\n 'use strict';\n\n // Global cache we'll use to ensure no double-tracking occurs\n var MarksAlreadyTracked = {};\n \n // Backwards compatible with old every setting, which was single value\n if (config.distances.percentages && config.distances.percentages.every) {\n\n if (!isArray_(config.distances.percentages.every)) {\n\n config.distances.percentages.every = [config.distances.percentages.every];\n\n }\n\n }\n\n // Backwards compatible with old every setting, which was single value\n if (config.distances.pixels && config.distances.pixels.every) {\n\n if (!isArray_(config.distances.pixels.every)) {\n\n config.distances.pixels.every = [config.distances.pixels.every];\n\n }\n\n }\n\n // Get a hold of any relevant elements, if specified in config\n var elementDistances = (function(selectors) {\n\n // If no selectors specified, short circuit here\n if (!selectors) return;\n\n // Create a cache to store positions of elements temporarily\n var cache = {};\n var counter = 0;\n\n // Fetch latest positions\n _update();\n\n // Return a function that can be called to get a map of element positions\n return function () {\n\n // Clone here to prevent inheritance from getMarks step\n var shallowClone = {};\n var key;\n\n counter++;\n\n // If temp cache counter is greater than 10, re-poll elements\n if (counter > 10) {\n\n _update();\n counter = 0;\n\n }\n\n for (key in cache) {\n\n shallowClone[key] = cache[key];\n\n }\n\n return shallowClone;\n\n };\n\n function _update() {\n\n var selector,\n markName,\n els,\n el,\n y,\n i;\n // Clear current cache\n cache = {};\n\n if (selectors.each) {\n\n for (i = 0; i < selectors.each.length; i++) {\n \n selector = selectors.each[i];\n \n if (!MarksAlreadyTracked[selector]) {\n\n el = document.querySelector(selector); \n \n if (el) cache[selector] = getNodeDistanceFromTop(el);\n \n }\n\n }\n\n }\n\n if (selectors.every) {\n\n for (i = 0; i < selectors.every.length; i++) {\n\n selector = selectors.every[i];\n els = document.querySelectorAll(selector);\n\n // If the last item in the selected group has been tracked, we skip it\n if (els.length && !MarksAlreadyTracked[selector + ':' + (els.length - 1)]) {\n\n for (y = 0; y < els.length; y++) {\n\n markName = selector + ':' + y; \n\n // We also check at the individual element level\n if (!MarksAlreadyTracked[markName]) {\n\n el = els[y];\n cache[markName] = getNodeDistanceFromTop(el);\n\n }\n\n }\n\n }\n\n }\n\n }\n\n }\n\n })(config.distances.elements);\n\n // If our document is ready to go, fire straight away\n if(document.readyState !== 'loading') {\n\n init();\n\n } else {\n\n // On IE8 this fires on window.load, all other browsers will fire when DOM ready\n document.addEventListener ? \n addEvent(document, 'DOMContentLoaded', init) : \n addEvent(window, 'load', init);\n\n }\n\n function init() {\n\n // Browser dependencies, script fails silently\n if (!document.querySelector || !document.body.getBoundingClientRect) {\n\n return false;\n\n }\n\n // Set our dataLayer name for later\n config.dataLayerName = config.dataLayerName || 'dataLayer';\n\n // Initialize our distances, for later\n config.distances = config.distances || {};\n\n checkDepth();\n addEvent(window, 'scroll', throttle(checkDepth, 500));\n\n }\n\n function getMarks(_docHeight, _offset) {\n\n var marks = elementDistances() || {};\n var percents = [];\n var pixels = [];\n var everyPercent,\n everyPixel,\n i;\n\n if(config.distances.percentages) {\n\n if(config.distances.percentages.each) {\n\n percents = percents.concat(config.distances.percentages.each);\n\n }\n\n if(config.distances.percentages.every) {\n\n for (i = 0; i < config.distances.percentages.every.length; i++) {\n\n everyPercent = every_(config.distances.percentages.every[i], 100);\n percents = pixels.concat(everyPercent);\n\n }\n\n }\n\n }\n\n if(config.distances.pixels) {\n\n if(config.distances.pixels.each) {\n\n pixels = pixels.concat(config.distances.pixels.each);\n\n }\n\n if(config.distances.pixels.every) {\n\n for (i = 0; i < config.distances.pixels.every.length; i++) {\n\n everyPixel = every_(config.distances.pixels.every[i], _docHeight);\n pixels = pixels.concat(everyPixel);\n\n }\n\n }\n\n }\n\n marks = addMarks_(marks, percents, '%', _docHeight, _offset);\n marks = addMarks_(marks, pixels, 'px', _docHeight, _offset);\n\n return marks;\n\n }\n\n function addMarks_(marks, points, symbol, _docHeight, _offset) {\n\n var i;\n\n for(i = 0; i < points.length; i++) {\n\n var _point = parseInt(points[i], 10);\n var height = symbol !== '%' ? _point + _offset : _docHeight * (_point / 100) + _offset;\n var mark = _point + symbol;\n\n if(height <= _docHeight + _offset) {\n\n marks[mark] = height;\n\n }\n\n }\n\n return marks;\n\n }\n\n function every_(n, total) {\n\n var _n = parseInt(n, 10);\n var _num = total / _n;\n var arr = [];\n var i;\n \n for(i = 1; i < _num + 1; i++) {\n\n arr.push(i * _n);\n\n }\n\n return arr;\n\n }\n\n function checkDepth() {\n\n var _bottom = parseScrollBorder(config.bottom);\n var _top = parseScrollBorder(config.top);\n var height = docHeight(_bottom, _top);\n var marks = getMarks(height, (_top || 0));\n var _curr = currentPosition();\n var target,\n key;\n\n for(key in marks) {\n\n target = marks[key];\n\n // If we've scrolled past the mark, we haven't tracked it yet, and it's in range, track the mark\n if(\n _curr > target && \n !MarksAlreadyTracked[key] && \n target < (_bottom || Infinity) && \n target > (_top || 0)\n ) {\n\n MarksAlreadyTracked[key] = true;\n fireAnalyticsEvent(key);\n\n }\n\n }\n\n }\n\n function fireAnalyticsEvent(distance) {\n\n var _ga = window.GoogleAnalyticsObject;\n\n if(typeof window[config.dataLayerName] !== 'undefined' && !config.forceSyntax) { \n\n window[config.dataLayerName].push( {\n 'event': 'scrollTracking',\n 'attributes': {\n 'distance': distance,\n 'label': config.label\n }\n });\n\n } else if (typeof window[_ga] === 'function' && \n typeof window[_ga].getAll === 'function' && \n config.forceSyntax !== 2) \n {\n\n window[_ga]('send', 'event', config.category, distance, config.label, {'nonInteraction': 1});\n\n } else if(typeof window._gaq !== 'undefined' && config.forceSyntax !== 1) {\n\n window._gaq.push(['_trackEvent', config.category, distance, config.label, 0, true]);\n\n }\n\n }\n\n function parseScrollBorder(border) {\n\n if(typeof border === 'number' || parseInt(border, 10)) {\n\n return parseInt(border, 10);\n\n }\n\n try {\n\n // If we have an element or a query selector, poll getBoundingClientRect\n var el = border.nodeType === 1 ? border : document.querySelector(border);\n\n return getNodeDistanceFromTop(el); \n\n } catch (e) {\n\n return void(0);\n\n }\n\n }\n\n // Adapted from https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY\n function currentPosition() {\n\n var supportPageOffset = window.pageXOffset !== undefined;\n var isCSS1Compat = ((document.compatMode || \"\") === \"CSS1Compat\");\n\n var currScrollTop = supportPageOffset ?\n window.pageYOffset :\n isCSS1Compat ?\n document.documentElement.scrollTop :\n document.body.scrollTop;\n\n return parseInt(currScrollTop, 10) + parseInt(viewportHeight(), 10);\n\n }\n\n function viewportHeight() {\n\n var elem = (document.compatMode === \"CSS1Compat\") ?\n document.documentElement :\n document.body;\n\n return elem.clientHeight;\n\n }\n\n function docHeight(_bottom, _top) {\n\n var body = document.body;\n var html = document.documentElement;\n \n var height = Math.max(body.scrollHeight, body.offsetHeight, \n html.clientHeight, html.scrollHeight, html.offsetHeight);\n\n\n if(_top) {\n\n height = height - _top;\n\n }\n\n if(_bottom) {\n\n height = _bottom - (_top || 0);\n\n }\n\n return height - 5;\n\n }\n\n\n /*\n * Throttle function borrowed from:\n * Underscore.js 1.5.2\n * http://underscorejs.org\n * (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n * Underscore may be freely distributed under the MIT license.\n */\n function throttle(func, wait) {\n var context, args, result;\n var timeout = null;\n var previous = 0;\n var later = function() {\n previous = new Date;\n timeout = null;\n result = func.apply(context, args);\n };\n return function() {\n var now = new Date;\n if (!previous) previous = now;\n var remaining = wait - (now - previous);\n context = this;\n args = arguments;\n if (remaining <= 0) {\n clearTimeout(timeout);\n timeout = null;\n previous = now;\n result = func.apply(context, args);\n } else if (!timeout) {\n timeout = setTimeout(later, remaining);\n }\n return result;\n };\n }\n\n // Cross-browser compliant event listener\n function addEvent(el, evt, fn) {\n\n if (el.addEventListener) {\n\n el.addEventListener(evt, fn);\n\n } else if (el.attachEvent) {\n\n el.attachEvent('on' + evt, function(evt) {\n\n // Call the event to ensure uniform 'this' handling, pass it event\n fn.call(el, evt);\n\n });\n\n } else if (typeof el['on' + evt] === 'undefined' || el['on' + evt] === null) {\n\n el['on' + evt] = function(evt) {\n\n // Call the event to ensure uniform 'this' handling, pass it event\n fn.call(el, evt);\n\n };\n\n }\n\n }\n\n // Helper for fetching top of element\n function getNodeDistanceFromTop(node) {\n\n var nodeTop = node.getBoundingClientRect().top;\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollX\n var docTop = (window.pageYOffset !== undefined) ?\n window.pageYOffset :\n (document.documentElement || document.body.parentNode || document.body).scrollTop; \n\n return nodeTop + docTop;\n\n }\n\n // Helper to check if something is an Array\n function isArray_(thing) {\n\n return thing instanceof Array;\n\n }\n\n})(document, window, {\n // Use 2 to force Classic Analytics hits and 1 for Universal hits\n 'forceSyntax': false,\n // False if you just use the default dataLayer variable, otherwise enter it here\n 'dataLayerName': false,\n 'distances': {\n // Configure percentages of page you'd like to see if users scroll past\n 'percentages': {\n 'each': [10,90],\n 'every': [25]\n },\n // Configure for pixel measurements of page you'd like to see if users scroll past\n 'pixels': {\n 'each': [],\n 'every': []\n },\n // Configure elements you'd like to see users scroll past (using CSS Selectors)\n 'elements': {\n 'each': [],\n 'every': []\n }\n },\n // Accepts a number, DOM element, or query selector to determine the top of the scrolling area\n 'top': null,\n // Accepts a number, DOM element, or query selector to determine the bottom of the scrolling area\n 'bottom': null,\n // Text for Event Category\n 'category': 'Scroll Tracking',\n // Text for Event Label\n 'label': document.location.pathname\n});\n/*\n * v1.1.1\n * Created by the Google Analytics consultants at http://www.lunametrics.com/\n * Written by @notdanwilkerson\n * Documentation: https://github.com/lunametrics/gascroll/\n * Licensed under the MIT License\n */\n</script>"
}],
"fingerprint": "0",
"firingTriggerId": ["2147479553"],
"parentFolderId": "11",
"tagFiringOption": "ONCE_PER_EVENT"
}, {
"accountId": "28896164",
"containerId": "1607357",
"tagId": "20",
"name": "GA - Event - Scroll Tracking",
"type": "ua",
"liveOnly": false,
"parameter": [{
"type": "BOOLEAN",
"key": "enableEcommerce",
"value": "false"
}, {
"type": "BOOLEAN",
"key": "setTrackerName",
"value": "false"
}, {
"type": "LIST",
"key": "fieldsToSet",
"list": [{
"type": "MAP",
"map": [{
"type": "TEMPLATE",
"key": "fieldName",
"value": "cookieDomain"
}, {
"type": "TEMPLATE",
"key": "value",
"value": "auto"
}]
}]
}, {
"type": "BOOLEAN",
"key": "doubleClick",
"value": "false"
}, {
"type": "TEMPLATE",
"key": "useDebugVersion",
"value": "{{Debug Mode}}"
}, {
"type": "TEMPLATE",
"key": "trackingId",
"value": "{{YOUR_GA_TRACKING_ID}}"
}, {
"type": "TEMPLATE",
"key": "trackType",
"value": "TRACK_EVENT"
}, {
"type": "BOOLEAN",
"key": "nonInteraction",
"value": "true"
}, {
"type": "BOOLEAN",
"key": "enableLinkId",
"value": "false"
}, {
"type": "TEMPLATE",
"key": "eventLabel",
"value": "{{Scroll Label}}"
}, {
"type": "TEMPLATE",
"key": "eventAction",
"value": "{{Scroll Distance}}"
}, {
"type": "TEMPLATE",
"key": "eventCategory",
"value": "Scroll Tracking"
}],
"fingerprint": "0",
"firingTriggerId": ["10"],
"parentFolderId": "11",
"tagFiringOption": "ONCE_PER_EVENT"
}],
"fingerprint": "0",
"trigger": [{
"accountId": "28896164",
"containerId": "1607357",
"triggerId": "10",
"name": "Event - Scroll Tracking",
"type": "CUSTOM_EVENT",
"customEventFilter": [{
"type": "EQUALS",
"parameter": [{
"type": "TEMPLATE",
"key": "arg0",
"value": "{{_event}}"
}, {
"type": "TEMPLATE",
"key": "arg1",
"value": "scrollTracking"
}]
}],
"fingerprint": "1445027600600",
"parentFolderId": "11"
}],
"variable": [{
"accountId": "28896164",
"containerId": "1607357",
"variableId": "19",
"name": "Scroll Distance",
"type": "v",
"parameter": [{
"type": "BOOLEAN",
"key": "setDefaultValue",
"value": "false"
}, {
"type": "TEMPLATE",
"key": "name",
"value": "attributes.distance"
}, {
"type": "INTEGER",
"key": "dataLayerVersion",
"value": "2"
}],
"fingerprint": "0",
"parentFolderId": "11"
}, {
"accountId": "28896164",
"containerId": "1607357",
"variableId": "20",
"name": "Scroll Label",
"type": "v",
"parameter": [{
"type": "BOOLEAN",
"key": "setDefaultValue",
"value": "false"
}, {
"type": "TEMPLATE",
"key": "name",
"value": "attributes.label"
}, {
"type": "INTEGER",
"key": "dataLayerVersion",
"value": "2"
}],
"fingerprint": "0",
"parentFolderId": "11"
}],
"folder": [{
"accountId": "28896164",
"containerId": "1607357",
"folderId": "11",
"name": "LunaMetrics Scroll Tracking Plugin",
"fingerprint": "1445027599934"
}]
}
}