Просмотр исходного кода

Merge pull request #5116 from overleaf/jpa-event-tracking-de-ng

[web] event-tracking: implement sprinkle using the ng attributes

GitOrigin-RevId: 5195d827b590ee32e86ba2ffe365ad7cab65750b
Jakob Ackermann 5 лет назад
Родитель
Сommit
94a46c3c40

+ 75 - 0
services/web/frontend/js/features/event-tracking/index.js

@@ -0,0 +1,75 @@
+import _ from 'lodash'
+import * as eventTracking from '../../infrastructure/event-tracking'
+
+function isInViewport(element) {
+  const elTop = $(element).offset().top
+  const elBtm = elTop + $(element).outerHeight()
+
+  const viewportTop = $(window).scrollTop()
+  const viewportBtm = viewportTop + $(window).height()
+
+  return elBtm > viewportTop && elTop < viewportBtm
+}
+
+function setupEventTracking(el) {
+  const key = el.getAttribute('event-tracking')
+  const action = el.getAttribute('event-tracking-action') || key
+  const label = el.getAttribute('event-tracking-label') || ''
+  const gaCategory = el.getAttribute('event-tracking-ga')
+  const sendMB = el.getAttribute('event-tracking-mb')
+  const trigger = el.getAttribute('event-tracking-trigger')
+  const sendOnce = el.getAttribute('event-tracking-send-once')
+  const segmentation = JSON.parse(el.getAttribute('event-segmentation') || '{}')
+  segmentation.page = window.location.pathname
+
+  function submit() {
+    if (sendMB) {
+      if (sendOnce) {
+        eventTracking.sendMBOnce(key, segmentation)
+      } else {
+        eventTracking.sendMB(key, segmentation)
+      }
+    }
+    if (gaCategory) {
+      if (sendOnce) {
+        eventTracking.sendOnce(gaCategory, action, label)
+      } else {
+        eventTracking.send(gaCategory, action, label)
+      }
+    }
+  }
+
+  let handler
+  let timer
+  let timeoutAmt = 500
+  switch (trigger) {
+    case 'load':
+      submit()
+      break
+    case 'click':
+      el.addEventListener('click', () => submit())
+      break
+    case 'hover':
+      if (el.getAttribute('event-hover-amt')) {
+        timeoutAmt = parseInt(el.getAttribute('event-hover-amt'), 10)
+      }
+      el.addEventListener('mouseenter', () => {
+        timer = setTimeout(() => submit(), timeoutAmt)
+      })
+      el.addEventListener('mouseleave', () => clearTimeout(timer))
+      break
+    case 'scroll':
+      handler = _.throttle(() => {
+        if (isInViewport(el)) {
+          submit()
+          window.removeEventListener('scroll', handler)
+          window.removeEventListener('resize', handler)
+        }
+      }, 500)
+      window.addEventListener('scroll', handler)
+      window.addEventListener('resize', handler)
+      break
+  }
+}
+
+document.querySelectorAll('[event-tracking]').forEach(setupEventTracking)

+ 21 - 14
services/web/frontend/js/infrastructure/event-tracking.js

@@ -2,31 +2,38 @@ import sessionStorage from '../infrastructure/session-storage'
 
 const CACHE_KEY = 'mbEvents'
 
+function alreadySent(key) {
+  const eventCache = sessionStorage.getItem(CACHE_KEY) || {}
+  return !!eventCache[key]
+}
+function markAsSent(key) {
+  const eventCache = sessionStorage.getItem(CACHE_KEY) || {}
+  eventCache[key] = true
+  sessionStorage.setItem(CACHE_KEY, eventCache)
+}
+
 export function send(category, action, label, value) {
   if (typeof window.ga === 'function') {
     window.ga('send', 'event', category, action, label, value)
   }
 }
 
+export function sendOnce(category, action, label, value) {
+  if (alreadySent(category)) return
+  if (typeof window.ga !== 'function') return
+
+  window.ga('send', 'event', category, action, label, value)
+  markAsSent(category)
+}
+
 export function sendMB(key, segmentation = {}) {
   sendBeacon(key, segmentation)
 }
 
 export function sendMBOnce(key, segmentation = {}) {
-  let eventCache = sessionStorage.getItem(CACHE_KEY)
-
-  // Initialize as an empy object if the event cache is still empty.
-  if (eventCache == null) {
-    eventCache = {}
-    sessionStorage.setItem(CACHE_KEY, eventCache)
-  }
-
-  const isEventInCache = eventCache[key] || false
-  if (!isEventInCache) {
-    eventCache[key] = true
-    sessionStorage.setItem(CACHE_KEY, eventCache)
-    sendMB(key, segmentation)
-  }
+  if (alreadySent(key)) return
+  sendMB(key, segmentation)
+  markAsSent()
 }
 
 export function sendMBSampled(key, body = {}, rate = 0.01) {

+ 1 - 0
services/web/frontend/js/marketing.js

@@ -3,5 +3,6 @@ import 'jquery'
 import 'bootstrap'
 import './features/form-helpers/hydrate-form'
 import './features/contact-form'
+import './features/event-tracking'
 
 $('[data-ol-lang-selector-tooltip]').tooltip({ trigger: 'hover' })