File size: 5,583 Bytes
6778ee0 | 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 187 | import { config } from './config'
import { sendRequest } from './networking'
/* Engagement tracking variables and functions */
// Multiple pageviews might be sent by the same script when the page
// uses client-side routing (e.g. hash or history-based). This flag
// prevents registering multiple listeners in those cases.
var listeningOnEngagement = false
var currentEngagementIgnored
var currentEngagementURL = location.href
var currentEngagementProps = {}
var currentEngagementMaxScrollDepth = -1
// Timestamp indicating when this particular page last became visible.
// Reset during pageviews, set to 0 when page is closed.
var runningEngagementStart = 0
// When page is hidden, this 'engaged' time is saved to this variable
var currentEngagementTime = 0
export function prePageviewTrack() {
if (listeningOnEngagement) {
// If we're listening on engagement already, at least one pageview
// has been sent by the current script (i.e. it's most likely a SPA).
// Trigger an engagement marking the "exit from the previous page".
triggerEngagement()
currentDocumentHeight = getDocumentHeight()
maxScrollDepthPx = getCurrentScrollDepthPx()
}
}
export function postPageviewTrack(payload) {
currentEngagementIgnored = false
currentEngagementURL = payload.u
currentEngagementProps = payload.p
currentEngagementMaxScrollDepth = -1
currentEngagementTime = 0
runningEngagementStart = Date.now()
registerEngagementListener()
}
export function onPageviewIgnored() {
currentEngagementIgnored = true
}
function triggerEngagement() {
var engagementTime = getEngagementTime()
/*
We send engagements if there's new relevant engagement information to share:
- If the user has scrolled more than the previously sent max scroll depth.
- If the user has been engaged for more than 3 seconds since the last engagement event.
The first engagement event is always sent due to containing at least the initial scroll depth.
Also, we don't send engagements if the current pageview is ignored (onIgnoredEvent)
*/
if (
!currentEngagementIgnored &&
(currentEngagementMaxScrollDepth < maxScrollDepthPx ||
engagementTime >= 3000)
) {
currentEngagementMaxScrollDepth = maxScrollDepthPx
var payload = {
n: 'engagement',
sd: Math.round((maxScrollDepthPx / currentDocumentHeight) * 100),
d: config.domain,
u: currentEngagementURL,
p: currentEngagementProps,
e: engagementTime,
v: COMPILE_TRACKER_SCRIPT_VERSION
}
// Reset current engagement time metrics. They will restart upon when page becomes visible or the next SPA pageview
runningEngagementStart = 0
currentEngagementTime = 0
if (COMPILE_HASH && (!COMPILE_CONFIG || config.hashBasedRouting)) {
payload.h = 1
}
sendRequest(config.endpoint, payload)
}
}
function onVisibilityChange() {
if (
document.visibilityState === 'visible' &&
document.hasFocus() &&
runningEngagementStart === 0
) {
runningEngagementStart = Date.now()
} else if (document.visibilityState === 'hidden' || !document.hasFocus()) {
// Tab went back to background or lost focus. Save the engaged time so far
currentEngagementTime = getEngagementTime()
runningEngagementStart = 0
triggerEngagement()
}
}
function registerEngagementListener() {
if (!listeningOnEngagement) {
// Only register visibilitychange listener only after initial page load and pageview
document.addEventListener('visibilitychange', onVisibilityChange)
window.addEventListener('blur', onVisibilityChange)
window.addEventListener('focus', onVisibilityChange)
listeningOnEngagement = true
}
}
function getEngagementTime() {
if (runningEngagementStart) {
return currentEngagementTime + (Date.now() - runningEngagementStart)
} else {
return currentEngagementTime
}
}
var currentDocumentHeight
var maxScrollDepthPx
function getDocumentHeight() {
var body = document.body || {}
var el = document.documentElement || {}
return Math.max(
body.scrollHeight || 0,
body.offsetHeight || 0,
body.clientHeight || 0,
el.scrollHeight || 0,
el.offsetHeight || 0,
el.clientHeight || 0
)
}
function getCurrentScrollDepthPx() {
var viewportHeight, scrollTop
if (COMPILE_COMPAT) {
var el = document.documentElement || {}
var body = document.body || {}
viewportHeight = window.innerHeight || el.clientHeight || 0
scrollTop =
window.scrollY ||
window.pageYOffset ||
el.scrollTop ||
body.scrollTop ||
0
} else {
viewportHeight = window.innerHeight
scrollTop = window.scrollY
}
return currentDocumentHeight <= viewportHeight
? currentDocumentHeight
: scrollTop + viewportHeight
}
export function init() {
currentDocumentHeight = getDocumentHeight()
maxScrollDepthPx = getCurrentScrollDepthPx()
if (COMPILE_COMPAT) {
window.addEventListener('load', function () {
currentDocumentHeight = getDocumentHeight()
var count = 0
var interval = setInterval(function () {
currentDocumentHeight = getDocumentHeight()
if (++count === 15) clearInterval(interval)
}, 200)
})
} else {
new ResizeObserver(function () {
currentDocumentHeight = getDocumentHeight()
}).observe(document.documentElement)
}
document.addEventListener('scroll', function () {
var currentScrollDepthPx = getCurrentScrollDepthPx()
if (currentScrollDepthPx > maxScrollDepthPx) {
maxScrollDepthPx = currentScrollDepthPx
}
})
}
|