Skip to content

Instantly share code, notes, and snippets.

@th507
Last active December 27, 2015 09:19
Show Gist options
  • Save th507/7302586 to your computer and use it in GitHub Desktop.
Save th507/7302586 to your computer and use it in GitHub Desktop.
logging offline visits across sessions
# logging offline visits across sessions
# for in-house tracking and Google Analytics
# See my blog for more information (Chinese)
# http://ljw.me/2013/07/24/logging-offline-visits.html
#
# Usage:
#
# var tracker = new FTCTracker(beaconURLPrefix)
# tracker.push(url)
#
# A nice side-effect is that you could use
# `tracker.isAccessible()` to get the latest network status.
# This is more reliable than `navigator.onLine`
class FTCTracker
# just declare within ftcTracker scope
# array of untracked page visits
log = []
# beacon image url prefix
prefix = ""
# is it in the process of sending report?
isBusy = false
# ballpark network status for a start
accessible = navigator.onLine
save = (key, value) ->
try
localStorage.setItem key, value
load = (key) ->
try
return localStorage.getItem key
catch e
return null
setAccessible = (_bool) ->
accessible = _bool
offlinePageView = "offlinePageView"
getOfflinePageView = -> load offlinePageView
saveOfflinePageView = ->
# reduce the number of localStorage writes
saved = getOfflinePageView()
unsaved = JSON.stringify log
# only save log when we change something
if unsaved isnt saved
save offlinePageView, unsaved
# part of a simple implementation of Deferred
isBusy = false
getTrackerURL = (url) ->
prefix +
'&url=' + encodeURIComponent(url) +
'&rnd=' + Math.random().toFixed(5)
sendToGA = (url) -> q.push(['_trackPageview', url]) if q = window._gaq
resolve = ->
return unless log
return unless log.length
return if isBusy
isBusy = true
url = log[0]
# strip invalid entries
while !url or url is "undefined" or url is "null"
log.shift()
url = log[0]
tracker = new Image()
tracker.onload = ->
setAccessible true
sendToGA url
log.shift()
saveOfflinePageView() # this also set isBusy to false
if log.length
resolve()
tracker.onerror = ->
setAccessible false
saveOfflinePageView()
tracker.src = getTrackerURL url
constructor: (beaconURLPrefix) ->
prefix = beaconURLPrefix
log = [].concat(JSON.parse(getOfflinePageView()))
# helper method, returns network status
isAccessible: -> accessible
# when user is in private/incognito mode,
# valueOf and toString yields different result
# toString would return null when localStorage is inaccessible
valueOf: -> log
toString: -> getOfflinePageView()
# sending page visit
push: (url) ->
return if !url
log.push url
resolve()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment