Created
August 15, 2012 19:46
-
-
Save tomfuertes/3363007 to your computer and use it in GitHub Desktop.
Ensighten Helper Update
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Helper Functions | |
(function(window, document, undefined) { | |
window.gaGetParameterByName = function(name) { | |
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search); | |
return match && decodeURIComponent(match[1].replace(/\+/g, ' ')); | |
}; | |
window.gaGetElementsByClassName = function(e) { | |
var tags = this.all || this.getElementsByTagName('*'); | |
var matchArray = {}; | |
var re1 = new RegExp('(?:^|\\s)' + e + '(?:\\s|$)'); | |
for (var i = 0; i < tags.length; i++) { | |
if (re1.test(tags[i].className)) { | |
matchArray[matchArray.length] = tags[i]; | |
} | |
} | |
return matchArray; | |
}; | |
window.gaSetCookie = function(name, value, minutes, hostname) { | |
var expires = ""; | |
if (minutes) { | |
var date = new Date(); | |
date.setTime(date.getTime() + (minutes * 60 * 1000)); | |
expires = "; expires=" + date.toGMTString(); | |
} | |
document.cookie = name + "=" + value + expires + "; path=/; domain=" + hostname + ";"; | |
}; | |
window.gaReadCookie = function(name) { | |
var nameEQ = name + "="; | |
var ca = document.cookie.split(';'); | |
for (var i = 0; i < ca.length; i++) { | |
var c = ca[i]; | |
while (c.charAt(0) == ' ') c = c.substring(1, c.length); | |
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); | |
} | |
return undefined; | |
}; | |
})(this, this.document); | |
/** | |
* @preserve Copyright 2011, Cardinal Path and DigitalInc. | |
* | |
* GAS - Google Analytics on Steroids | |
* https://github.com/CardinalPath/gas | |
* | |
* @author Eduardo Cereto <eduardocereto@gmail.com> | |
* Licensed under the GPLv3 license. | |
*/ | |
(function(window, undefined) { | |
/** | |
* GAS - Google Analytics on Steroids | |
* | |
* Helper Functions | |
* | |
* Copyright 2011, Cardinal Path and Direct Performance | |
* Licensed under the MIT license. | |
* | |
* @author Eduardo Cereto <eduardocereto@gmail.com> | |
*/ | |
/** | |
* GasHelper singleton class | |
* | |
* Should be called when ga.js is loaded to get the pageTracker. | |
* | |
* @constructor | |
*/ | |
var GasHelper = function() { | |
this._setDummyTracker(); | |
}; | |
GasHelper.prototype._setDummyTracker = function() { | |
if (!this['tracker']) { | |
var trackers = window['_gat']['_getTrackers'](); | |
if (trackers.length > 0) { | |
this['tracker'] = trackers[0]; | |
} | |
} | |
}; | |
/** | |
* Returns true if the element is found in the Array, false otherwise. | |
* | |
* @param {Array} obj Array to search at. | |
* @param {object} item Item to search form. | |
* @return {boolean} true if contains. | |
*/ | |
GasHelper.prototype.inArray = function(obj, item) { | |
if (obj && obj.length) { | |
for (var i = 0; i < obj.length; i++) { | |
if (obj[i] === item) { | |
return true; | |
} | |
} | |
} | |
return false; | |
}; | |
/** | |
* Removes special characters and Lowercase String | |
* | |
* @param {string} str to be sanitized. | |
* @param {boolean} strict_opt If we should remove any non ascii char. | |
* @return {string} Sanitized string. | |
*/ | |
GasHelper.prototype._sanitizeString = function(str, strict_opt) { | |
str = str.toLowerCase().replace(/^\ +/, '').replace(/\ +$/, '').replace(/\s+/g, '_').replace(/[áàâãåäæª]/g, 'a').replace(/[éèêëЄ€]/g, 'e').replace(/[íìîï]/g, 'i').replace(/[óòôõöøº]/g, 'o').replace(/[úùûü]/g, 'u').replace(/[碩]/g, 'c'); | |
if (strict_opt) { | |
str = str.replace(/[^a-z0-9_-]/g, '_'); | |
} | |
return str.replace(/_+/g, '_'); | |
}; | |
/** | |
* Cross Browser helper to addEventListener. | |
* | |
* ga_next.js currently have a _addEventListener directive. So _gas will | |
* allways prefer that if available, and will use this one only as a fallback | |
* | |
* @param {HTMLElement} obj The Element to attach event to. | |
* @param {string} evt The event that will trigger the binded function. | |
* @param {function(event)} ofnc The function to bind to the element. | |
* @param {boolean} bubble true if event should be fired at bubble phase. | |
* Defaults to false. Works only on W3C compliant browser. MSFT don't support | |
* it. | |
* @return {boolean} true if it was successfuly binded. | |
*/ | |
GasHelper.prototype._addEventListener = function(obj, evt, ofnc, bubble) { | |
var fnc = function(event) { | |
if (!event || !event.target) { | |
event = window.event; | |
event.target = event.srcElement; | |
} | |
return ofnc.call(obj, event); | |
}; | |
// W3C model | |
if (obj.addEventListener) { | |
obj.addEventListener(evt, fnc, !! bubble); | |
return true; | |
} | |
// M$ft model | |
else if (obj.attachEvent) { | |
return obj.attachEvent('on' + evt, fnc); | |
} | |
// Browser doesn't support W3C or M$ft model. Time to go old school | |
else { | |
evt = 'on' + evt; | |
if (typeof obj[evt] === 'function') { | |
// Object already has a function on traditional | |
// Let's wrap it with our own function inside another function | |
fnc = (function(f1, f2) { | |
return function() { | |
f1.apply(this, arguments); | |
f2.apply(this, arguments); | |
} | |
})(obj[evt], fnc); | |
} | |
obj[evt] = fnc; | |
return true; | |
} | |
}; | |
/** | |
* Cross Browser Helper to emulate jQuery.live | |
* | |
* Binds to the document root. Listens to all events of the specific type. | |
* If event don't bubble it won't catch | |
*/ | |
GasHelper.prototype._liveEvent = function(tag, evt, ofunc) { | |
var gh = this; | |
tag = tag.toUpperCase(); | |
tag = tag.split(','); | |
gh._addEventListener(document, evt, function(me) { | |
for (var el = me.target; el.nodeName !== 'HTML'; | |
el = el.parentNode) { | |
if (gh.inArray(tag, el.nodeName) || el.parentNode === null) { | |
break; | |
} | |
} | |
if (el && gh.inArray(tag, el.nodeName)) { | |
ofunc.call(el, me); | |
} | |
}, true); | |
}; | |
/** | |
* Cross Browser DomReady function. | |
* | |
* Inspired by: http://dean.edwards.name/weblog/2006/06/again/#comment367184 | |
* | |
* @param {function(Event)} callback DOMReady callback. | |
* @return {boolean} Ignore return value. | |
*/ | |
GasHelper.prototype._DOMReady = function(callback) { | |
var scp = this; | |
if (/^(interactive|complete)/.test(document.readyState)) return cb(); | |
this._addEventListener(document, 'DOMContentLoaded', cb, false); | |
this._addEventListener(window, 'load', cb, false); | |
function cb() { | |
if (cb.done) return; | |
cb.done = true; | |
callback.apply(scp, arguments); | |
} | |
}; | |
/** | |
* GAS - Google Analytics on Steroids | |
* | |
* Copyright 2011, Cardinal Path and Direct Performance | |
* Licensed under the MIT license. | |
* | |
* @author Eduardo Cereto <eduardocereto@gmail.com> | |
*/ | |
/** | |
* Google Analytics original _gaq. | |
* | |
* This never tries to do something that is not supposed to. So it won't break | |
* in the future. | |
*/ | |
window['_gaq'] = window['_gaq'] || []; | |
var _prev_gas = window['_gas'] || []; | |
// Avoid duplicate definition | |
if (_prev_gas._accounts_length >= 0) { | |
return; | |
} | |
//Shortcuts, these speed up and compress the code | |
var document = window.document, | |
toString = Object.prototype.toString, | |
hasOwn = Object.prototype.hasOwnProperty, | |
push = Array.prototype.push, | |
slice = Array.prototype.slice, | |
trim = String.prototype.trim, | |
sindexOf = String.prototype.indexOf, | |
url = document.location.href, | |
documentElement = document.documentElement; | |
/** | |
* GAS Sigleton | |
* @constructor | |
*/ | |
function GAS() { | |
var self = this; | |
self['version'] = '1.9'; | |
self._accounts = {}; | |
self._accounts_length = 0; | |
self._queue = _prev_gas; | |
self._default_tracker = '_gas1'; | |
self.gh = {}; | |
self._hooks = { | |
'_addHook': [self._addHook] | |
}; | |
// Need to be pushed to make sure tracker is done | |
// Sets up helpers, very first thing pushed into gas | |
self.push(function() { | |
self.gh = new GasHelper(); | |
}); | |
} | |
/** | |
* First standard Hook that is responsible to add next Hooks | |
* | |
* _addHook calls always reurn false so they don't get pushed to _gaq | |
* @param {string} fn The function you wish to add a Hook to. | |
* @param {function()} cb The callback function to be appended to hooks. | |
* @return {boolean} Always false. | |
*/ | |
GAS.prototype._addHook = function(fn, cb) { | |
if (typeof fn === 'string' && typeof cb === 'function') { | |
if (typeof _gas._hooks[fn] === 'undefined') { | |
_gas._hooks[fn] = []; | |
} | |
_gas._hooks[fn].push(cb); | |
} | |
return false; | |
}; | |
/** | |
* Construct the correct account name to be used on _gaq calls. | |
* | |
* The account name for the first unamed account pushed to _gas is the standard | |
* account name. It's pushed without the account name to _gaq, so if someone | |
* calls directly _gaq it works as expected. | |
* @param {string} acct Account name. | |
* @return {string} Correct account name to be used already with trailling dot. | |
*/ | |
function _build_acct_name(acct) { | |
return acct === _gas._default_tracker ? '' : acct + '.'; | |
} | |
function _gaq_push(arr) { | |
if (_gas.debug_mode) { | |
try { | |
console.log(arr); | |
} catch (e) {} | |
} | |
return window['_gaq'].push(arr); | |
} | |
/** | |
* Everything pushed to _gas is executed by this call. | |
* | |
* This function should not be called directly. Instead use _gas.push | |
* @return {number} This is the same return as _gaq.push calls. | |
*/ | |
GAS.prototype._execute = function() { | |
var args = slice.call(arguments), | |
self = this, | |
sub = args.shift(), | |
gaq_execute = true, | |
i, foo, hooks, acct_name, repl_sub, return_val = 0; | |
if (typeof sub === 'function') { | |
// Pushed functions are executed right away | |
return _gaq_push( | |
(function(s, gh) { | |
return function() { | |
// pushed functions receive helpers through this object | |
s.call(gh); | |
}; | |
})(sub, self.gh)); | |
} else if (typeof sub === 'object' && sub.length > 0) { | |
foo = sub.shift(); | |
if (sindexOf.call(foo, '.') >= 0) { | |
acct_name = foo.split('.')[0]; | |
foo = foo.split('.')[1]; | |
} else { | |
acct_name = undefined; | |
} | |
// Execute hooks | |
hooks = self._hooks[foo]; | |
if (hooks && hooks.length > 0) { | |
for (i = 0; i < hooks.length; i++) { | |
try { | |
repl_sub = hooks[i].apply(self.gh, sub); | |
if (repl_sub === false) { | |
// Returning false from a hook cancel the call | |
gaq_execute = false; | |
} else { | |
if (repl_sub && repl_sub.length > 0) { | |
// Returning an array changes the call parameters | |
sub = repl_sub; | |
} | |
} | |
} catch (e) { | |
if (foo !== '_trackException') { | |
self.push(['_trackException', e]); | |
} | |
} | |
} | |
} | |
// Cancel execution on _gaq if any hook returned false | |
if (gaq_execute === false) { | |
return 1; | |
} | |
// Intercept _setAccount calls | |
if (foo === '_setAccount') { | |
for (i in self._accounts) { | |
if (self._accounts[i] == sub[0]) { | |
// Repeated account | |
if (acct_name === undefined) { | |
return 1; | |
} | |
} | |
} | |
acct_name = acct_name || '_gas' + String(self._accounts_length + 1); | |
// Force that the first unamed account is _gas1 | |
if (typeof self._accounts['_gas1'] == 'undefined' && sindexOf.call(acct_name, '_gas') != -1) { | |
acct_name = '_gas1'; | |
} | |
self._accounts[acct_name] = sub[0]; | |
self._accounts_length += 1; | |
acct_name = _build_acct_name(acct_name); | |
return_val = _gaq_push([acct_name + foo, sub[0]]); | |
// Must try t get the tracker if it's a _setAccount | |
self.gh._setDummyTracker(); | |
return return_val; | |
} | |
// Intercept functions that can only be called once. | |
if (foo === '_link' || foo === '_linkByPost' || foo === '_require' || foo === '_anonymizeIp') { | |
args = slice.call(sub); | |
args.unshift(foo); | |
return _gaq_push(args); | |
} | |
// If user provides account than trigger event for just that account. | |
var acc_foo; | |
if (acct_name && self._accounts[acct_name]) { | |
acc_foo = _build_acct_name(acct_name) + foo; | |
args = slice.call(sub); | |
args.unshift(acc_foo); | |
return _gaq_push(args); | |
} | |
// Call Original _gaq, for all accounts | |
if (self._accounts_length > 0) { | |
for (i in self._accounts) { | |
if (hasOwn.call(self._accounts, i)) { | |
acc_foo = _build_acct_name(i) + foo; | |
args = slice.call(sub); | |
args.unshift(acc_foo); | |
return_val += _gaq_push(args); | |
} | |
} | |
} else { | |
// If there are no accounts we just push it to _gaq | |
args = slice.call(sub); | |
args.unshift(foo); | |
return _gaq_push(args); | |
} | |
return return_val ? 1 : 0; | |
} | |
}; | |
/** | |
* Standard method to execute GA commands. | |
* | |
* Everything pushed to _gas is in fact pushed back to _gaq. So Helpers are | |
* ready for hooks. This creates _gaq as a series of functions that call | |
* _gas._execute() with the same arguments. | |
*/ | |
GAS.prototype.push = function() { | |
var self = this; | |
var args = slice.call(arguments); | |
for (var i = 0; i < args.length; i++) { | |
(function(arr, self) { | |
window['_gaq'].push(function() { | |
self._execute.call(self, arr); | |
}); | |
})(args[i], self); | |
} | |
}; | |
/** | |
* _gas main object. | |
* | |
* It's supposed to be used just like _gaq but here we extend it. In it's core | |
* everything pushed to _gas is run through possible hooks and then pushed to | |
* _gaq | |
*/ | |
window['_gas'] = _gas = new GAS(); | |
/** | |
* Hook for _trackException | |
* | |
* Watchout for circular calls | |
*/ | |
_gas.push(['_addHook', '_trackException', function(exception, message) { | |
_gas.push(['_trackEvent', 'Exception ' + (exception.name || 'Error'), message || exception.message || exception, url]); | |
return false; | |
}]); | |
/** | |
* Hook to enable Debug Mode | |
*/ | |
_gas.push(['_addHook', '_setDebug', function(set_debug) { | |
_gas.debug_mode = !! set_debug; | |
}]); | |
/** | |
* Hook to Remove other Hooks | |
* | |
* It will remove the last inserted hook from a _gas function. | |
* | |
* @param {string} func _gas Function Name to remove Hooks from. | |
* @return {boolean} Always returns false. | |
*/ | |
_gas.push(['_addHook', '_popHook', function(func) { | |
var arr = _gas._hooks[func]; | |
if (arr && arr.pop) { | |
arr.pop(); | |
} | |
return false; | |
}]); | |
/** | |
* Hook to set the default tracker. | |
* | |
* The default tracker is the nameless tracker that is pushed into _gaq_push | |
*/ | |
_gas.push(['_addHook', '_gasSetDefaultTracker', function(tname) { | |
_gas._default_tracker = tname; | |
return false; | |
}]); | |
/** | |
* This is kept just for backward compatibility since it's now supported | |
* natively in _gaq. | |
*/ | |
_gas.push(['_addHook', '_trackPageview', function() { | |
var args = slice.call(arguments); | |
if (args.length >= 2 && typeof args[0] === 'string' && typeof args[1] === 'string') { | |
return [{ | |
'page': args[0], | |
'title': args[1] | |
}]; | |
} | |
return args; | |
}]); | |
/** | |
* GAS - Google Analytics on Steroids | |
* | |
* Download Tracking Plugin | |
* | |
* Copyright 2011, Cardinal Path and Direct Performance | |
* Licensed under the GPLv3 license. | |
* | |
* @author Eduardo Cereto <eduardocereto@gmail.com> | |
*/ | |
/** | |
* Extracts the file extension and check it against a list | |
* | |
* Will extract the extensions from a url and check if it matches one of | |
* possible options. Used to verify if a url corresponds to a download link. | |
* | |
* @this {GasHelper} GA Helper object. | |
* @param {string} src The url to check. | |
* @param {Array} extensions an Array with strings containing the possible | |
* extensions. | |
* @return {boolean|string} the file extension or false. | |
*/ | |
function _checkFile(src, extensions) { | |
if (typeof src !== 'string') { | |
return false; | |
} | |
var ext = src.split('?')[0]; | |
ext = ext.split('.'); | |
ext = ext[ext.length - 1]; | |
if (ext && this.inArray(extensions, ext)) { | |
return ext; | |
} | |
return false; | |
} | |
/** | |
* Register the event to listen to downloads | |
* | |
* @this {GasHelper} GA Helper object. | |
* @param {Array|object} opts List of possible extensions for download | |
* links. | |
*/ | |
var _trackDownloads = function(opts) { | |
var gh = this; | |
if (!gh._downloadTracked) { | |
gh._downloadTracked = true; | |
} else { | |
//Oops double tracking detected. | |
return; | |
} | |
if (!opts) { | |
opts = { | |
'extensions': [] | |
}; | |
} else if (typeof opts === 'string') { | |
// support legacy opts as String of extensions | |
opts = { | |
'extensions': opts.split(',') | |
}; | |
} else if (opts.length >= 1) { | |
// support legacy opts Array of extensions | |
opts = { | |
'extensions': opts | |
}; | |
} | |
opts['category'] = opts['category'] || 'Download'; | |
var ext = 'xls,xlsx,doc,docx,ppt,pptx,pdf,txt,zip'; | |
ext += ',rar,7z,exe,wma,mov,avi,wmv,mp3,csv,tsv'; | |
ext = ext.split(','); | |
opts['extensions'] = opts['extensions'].concat(ext); | |
gh._liveEvent('a', 'mousedown', function(e) { | |
var el = this; | |
if (el.href) { | |
var ext = _checkFile.call(gh, el.href, opts['extensions']); | |
if (ext) { | |
_gas.push(['_trackEvent', opts['category'], ext, el.href]); | |
} | |
} | |
}); | |
return false; | |
}; | |
/** | |
* GAA Hook, receive the extensions to extend default extensions. And trigger | |
* the binding of the events. | |
* | |
* @param {string|Array|object} opts GAs Options. Also backward compatible | |
* with array or string of extensions. | |
*/ | |
_gas.push(['_addHook', '_gasTrackDownloads', _trackDownloads]); | |
// Old API to be deprecated on v2.0 | |
_gas.push(['_addHook', '_trackDownloads', _trackDownloads]); | |
/** | |
* Hook to sanity check trackEvents | |
* | |
* The value is rounded and parsed to integer. | |
* Negative values are sent as zero. | |
* If val is NaN than it is sent as zero. | |
*/ | |
_gas.push(['_addHook', '_trackEvent', function() { | |
var args = slice.call(arguments); | |
if (args[3]) { | |
args[3] = (args[3] < 0 ? 0 : Math.round(args[3])) || 0; | |
} | |
return args; | |
}]); | |
/** | |
* GAS - Google Analytics on Steroids | |
* | |
* Form Tracking Plugin | |
* | |
* Copyright 2011, Cardinal Path and Direct Performance | |
* Licensed under the GPLv3 license. | |
* | |
* @author Eduardo Cereto <eduardocereto@gmail.com> | |
*/ | |
/** | |
* get the form name for a specific elemet | |
* | |
* @param {DOMElemet} el Dom Element. | |
* @return {String} Form Name or Id. | |
*/ | |
function getFormName(el) { | |
while (el && el.nodeName !== 'HTML') { | |
if (el.nodeName === 'FORM') { | |
break; | |
} | |
el = el.parentNode; | |
} | |
if (el.nodeName === 'FORM') { | |
return el.name || el.id || 'none'; | |
} | |
return 'none'; | |
} | |
var _gasTrackForms = function(opts) { | |
if (!this._formTracked) { | |
this._formTracked = true; | |
} else { | |
//Oops double tracking detected. | |
return; | |
} | |
var scp = this; | |
if (typeof opts !== 'object') { | |
opts = {}; | |
} | |
// Make sure required attrs are defined or fallback to default | |
opts['category'] = opts['category'] || 'Form Tracking'; | |
//opts['live'] = opts['live'] || true; //Ignored | |
var trackField = function(e) { | |
var el = e.target, | |
el_name = el.name || el.id || el.type || el.nodeName, | |
form_name = getFormName(el), | |
action = 'form (' + form_name + ')', | |
label = el_name + ' (' + e.type + ')'; | |
_gas.push(['_trackEvent', opts['category'], action, label]); | |
} | |
scp._DOMReady(function() { | |
var changeTags = ['input', 'select', 'textarea', 'hidden']; | |
var submitTags = ['form']; | |
var elements = []; | |
var i, j; | |
for (i = 0; i < changeTags.length; i++) { | |
elements = document.getElementsByTagName(changeTags[i]); | |
for (j = 0; j < elements.length; j++) { | |
scp._addEventListener(elements[j], 'change', trackField); | |
} | |
} | |
for (i = 0; i < submitTags.length; i++) { | |
elements = document.getElementsByTagName(submitTags[i]); | |
for (j = 0; j < elements.length; j++) { | |
scp._addEventListener(elements[j], 'submit', trackField); | |
} | |
} | |
}); | |
}; | |
_gas.push(['_addHook', '_gasTrackForms', _gasTrackForms]); | |
// Old API to be deprecated on v2.0 | |
_gas.push(['_addHook', '_trackForms', _gasTrackForms]); | |
/** | |
* GAS - Google Analytics on Steroids | |
* | |
* HTML5 Video Tracking Plugin | |
* | |
* Copyright 2011, Cardinal Path | |
* Licensed under the GPLv3 license. | |
* | |
* @author Eduardo Cereto <eduardocereto@gmail.com> | |
*/ | |
/** | |
* Triggers the actual video/audio GA events | |
* | |
* To be used as a callback for the HTML5 media events | |
* | |
* @param {Event} e A reference to the HTML event fired. | |
* @this {HTMLMediaElement} The HTML element firing the event | |
*/ | |
function _trackMediaElement(e) { | |
_gas.push(['_trackEvent', this.tagName, e.type, this.currentSrc]); | |
} | |
/** | |
* Triggers the HTML5 Video Tracking on the page | |
* @param {String} tag Either 'audio' or 'video'. | |
* @this {GasHelper} GA Helper object. | |
*/ | |
var _trackMedia = function(tag) { | |
var self = this; | |
self._liveEvent(tag, 'play', _trackMediaElement); | |
self._liveEvent(tag, 'pause', _trackMediaElement); | |
self._liveEvent(tag, 'ended', _trackMediaElement); | |
}; | |
var _trackVideo = function() { | |
if (!this._videoTracked) { | |
this._videoTracked = true; | |
} else { | |
//Oops double tracking detected. | |
return; | |
} | |
_trackMedia.call(this, 'video'); | |
}; | |
var _trackAudio = function() { | |
if (!this._audioTracked) { | |
this._audioTracked = true; | |
} else { | |
//Oops double tracking detected. | |
return; | |
} | |
_trackMedia.call(this, 'audio'); | |
}; | |
_gas.push(['_addHook', '_gasTrackVideo', _trackVideo]); | |
_gas.push(['_addHook', '_gasTrackAudio', _trackAudio]); | |
// Old API to be deprecated on v2.0 | |
_gas.push(['_addHook', '_trackVideo', _trackVideo]); | |
_gas.push(['_addHook', '_trackAudio', _trackAudio]); | |
/** | |
* GAS - Google Analytics on Steroids | |
* | |
* MailTo tracking plugin | |
* | |
* Copyright 2011, Cardinal Path and Direct Performance | |
* Licensed under the GPLv3 license. | |
*/ | |
/** | |
* GAS plugin to track mailto: links | |
* | |
* @param {object} opts GAS Options. | |
*/ | |
var _gasTrackMailto = function(opts) { | |
if (!this._mailtoTracked) { | |
this._mailtoTracked = true; | |
} else { | |
//Oops double tracking detected. | |
return; | |
} | |
if (!opts) { | |
opts = {}; | |
} | |
opts['category'] = opts['category'] || 'Mailto'; | |
this._liveEvent('a', 'mousedown', function(e) { | |
var el = e.target; | |
if (el && el.href && el.href.toLowerCase && sindexOf.call(el.href.toLowerCase(), 'mailto:') === 0) { | |
_gas.push(['_trackEvent', opts['category'], el.href.substr(7)]); | |
} | |
}); | |
return false; | |
}; | |
_gas.push(['_addHook', '_gasTrackMailto', _gasTrackMailto]); | |
// Old API to be deprecated on v2.0 | |
_gas.push(['_addHook', '_trackMailto', _gasTrackMailto]); | |
/** | |
* GAS - Google Analytics on Steroids | |
* | |
* Max-Scroll Tracking Plugin | |
* | |
* Copyright 2011, Cardinal Path and Direct Performance | |
* Licensed under the GPLv3 license. | |
* | |
* @author Eduardo Cereto <eduardocereto@gmail.com> | |
*/ | |
/** | |
* Get current browser viewpane heigtht | |
* | |
* @return {number} height. | |
*/ | |
function _get_window_height() { | |
return window.innerHeight || documentElement.clientHeight || document.body.clientHeight || 0; | |
} | |
/** | |
* Get current absolute window scroll position | |
* | |
* @return {number} YScroll. | |
*/ | |
function _get_window_Yscroll() { | |
return window.pageYOffset || document.body.scrollTop || documentElement.scrollTop || 0; | |
} | |
/** | |
* Get current absolute document height | |
* | |
* @return {number} Current document height. | |
*/ | |
function _get_doc_height() { | |
return Math.max( | |
document.body.scrollHeight || 0, documentElement.scrollHeight || 0, document.body.offsetHeight || 0, documentElement.offsetHeight || 0, document.body.clientHeight || 0, documentElement.clientHeight || 0); | |
} | |
/** | |
* Get current vertical scroll percentage | |
* | |
* @return {number} Current vertical scroll percentage. | |
*/ | |
function _get_scroll_percentage() { | |
return ( | |
(_get_window_Yscroll() + _get_window_height()) / _get_doc_height()) * 100; | |
} | |
var _t = null; | |
var _max_scroll = 0; | |
function _update_scroll_percentage(now) { | |
if (_t) { | |
clearTimeout(_t); | |
} | |
if (now === true) { | |
_max_scroll = Math.max(_get_scroll_percentage(), _max_scroll); | |
return; | |
} | |
_t = setTimeout(function() { | |
_max_scroll = Math.max(_get_scroll_percentage(), _max_scroll); | |
}, 400); | |
} | |
function _sendMaxScroll() { | |
_update_scroll_percentage(true); | |
_max_scroll = Math.floor(_max_scroll); | |
if (_max_scroll <= 0 || _max_scroll > 100) return; | |
var bucket = (_max_scroll > 10 ? 1 : 0) * ( | |
Math.floor((_max_scroll - 1) / 10) * 10 + 1); | |
bucket = String(bucket) + '-' + String(Math.ceil(_max_scroll / 10) * 10); | |
_gas.push(['_trackEvent', _maxScrollOpts['category'], url, bucket, Math.floor(_max_scroll), true // non-interactive | |
]); | |
} | |
var _maxScrollOpts; | |
/** | |
* Tracks the max Scroll on the page. | |
* | |
* @param {object} opts GAS Options to be used. | |
* @this {GasHelper} The Ga Helper object | |
*/ | |
function _trackMaxScroll(opts) { | |
if (!this._maxScrollTracked) { | |
this._maxScrollTracked = true; | |
} else { | |
//Oops double tracking detected. | |
return; | |
} | |
_maxScrollOpts = opts || {}; | |
_maxScrollOpts['category'] = _maxScrollOpts['category'] || 'Max Scroll'; | |
this._addEventListener(window, 'scroll', _update_scroll_percentage); | |
this._addEventListener(window, 'beforeunload', _sendMaxScroll); | |
} | |
_gas.push(['_addHook', '_gasTrackMaxScroll', _trackMaxScroll]); | |
// Old API to be deprecated on v2.0 | |
_gas.push(['_addHook', '_trackMaxScroll', _trackMaxScroll]); | |
/** | |
* GAS - Google Analytics on Steroids | |
* | |
* Multi-Domain Tracking Plugin | |
* | |
* Copyright 2011, Cardinal Path and Direct Performance | |
* Licensed under the GPLv3 license. | |
* | |
* @author Eduardo Cereto <eduardocereto@gmail.com> | |
*/ | |
/** | |
* Private variable to store allowAnchor choice | |
*/ | |
_gas._allowAnchor = false; | |
/** | |
* _setAllowAnchor Hook to store choice for easier use of Anchor | |
* | |
* This stored value is used on _getLinkerUrl, _link and _linkByPost so it's | |
* used the same by default | |
*/ | |
_gas.push(['_addHook', '_setAllowAnchor', function(val) { | |
_gas._allowAnchor = !! val; | |
}]); | |
/** | |
* _link Hook to use stored allowAnchor value. | |
*/ | |
_gas.push(['_addHook', '_link', function(url, use_anchor) { | |
if (use_anchor === undefined) { | |
use_anchor = _gas._allowAnchor; | |
} | |
return [url, use_anchor]; | |
}]); | |
/** | |
* _linkByPost Hook to use stored allowAnchor value. | |
*/ | |
_gas.push(['_addHook', '_linkByPost', function(url, use_anchor) { | |
if (use_anchor === undefined) { | |
use_anchor = _gas._allowAnchor; | |
} | |
return [url, use_anchor]; | |
}]); | |
/** | |
* Store all domains pushed by _setDomainName that don't match current domain. | |
* | |
* @type {Array.<string>} | |
*/ | |
var _external_domains = []; | |
/** | |
* Store the internal domain name | |
* | |
* @type string | |
*/ | |
var _internal_domain = undefined; | |
/** | |
* _setDomainName Hook to add pushed domains to _external_domains if it doesn't | |
* match current domain. | |
* | |
* This Hook let you call _setDomainName multiple times. So _gas will only | |
* apply the one that matches the current domain and the other ones will be | |
* used to track external domains with cookie data. | |
*/ | |
_gas.push(['_addHook', '_setDomainName', function(domainName) { | |
if (sindexOf.call('.' + document.location.hostname, domainName) < 0) { | |
_external_domains.push(domainName); | |
return false; | |
} | |
_internal_domain = domainName; | |
}]); | |
/** | |
* _addExternalDomainName Hook. | |
* | |
* This hook let you add external domains so that urls on current page to this | |
* domain are marked to send cookies. | |
* You should use _setDomainName for this in most of the cases. | |
*/ | |
_gas.push(['_addHook', '_addExternalDomainName', function(domainName) { | |
_external_domains.push(domainName); | |
return false; | |
}]); | |
/** | |
* Function to mark links on the current pages to send links | |
* | |
* This function is used to make it easy to implement multi-domain-tracking. | |
* @param {string} event_used Should be 'now', 'click' or 'mousedown'. Default | |
* 'click'. | |
* @this {GasHelper} GAS Helper functions | |
* @return {boolean} Returns false to avoid this is puhed to _gaq. | |
*/ | |
function track_links(event_used) { | |
if (!this._multidomainTracked) { | |
this._multidomainTracked = true; | |
} else { | |
//Oops double tracking detected. | |
return; | |
} | |
var internal = document.location.hostname, | |
gh = this, | |
i, j, el, links = document.getElementsByTagName('a'); | |
if (event_used !== 'now' && event_used !== 'mousedown') { | |
event_used = 'click'; | |
} | |
for (i = 0; i < links.length; i++) { | |
el = links[i]; | |
if (sindexOf.call(el.href, 'http') === 0) { | |
// Check to see if it's a internal link | |
if (el.hostname == internal || sindexOf.call(el.hostname, _internal_domain) >= 0) { | |
continue; | |
} | |
// Tag external Links either now or on mouse event. | |
for (j = 0; j < _external_domains.length; j++) { | |
if (sindexOf.call(el.hostname, _external_domains[j]) >= 0) { | |
if (event_used === 'now') { | |
el.href = gh['tracker']['_getLinkerUrl']( | |
el.href, _gas._allowAnchor); | |
} else { | |
if (event_used === 'click') { | |
this._addEventListener(el, event_used, function(e) { | |
_gas.push( | |
['_link', this.href, _gas._allowAnchor]); | |
if (e.preventDefault) e.preventDefault(); | |
else e.returnValue = false; | |
return false; //needed for ie7 | |
}); | |
} else { | |
this._addEventListener(el, event_used, function() { | |
this.href = gh['tracker']['_getLinkerUrl']( | |
this.href, _gas._allowAnchor); | |
}); | |
} | |
} | |
} | |
} | |
} | |
} | |
return false; | |
} | |
var _gasMultiDomain = function() { | |
var gh = this; | |
var args = slice.call(arguments); | |
gh._DOMReady(function() { | |
track_links.apply(gh, args); | |
}); | |
}; | |
/** | |
* Registers Hook to _setMultiDomain | |
*/ | |
_gas.push(['_addHook', '_gasMultiDomain', _gasMultiDomain]); | |
// Old API to be deprecated on v2.0 | |
_gas.push(['_addHook', '_setMultiDomain', _gasMultiDomain]); | |
/** | |
* GAS - Google Analytics on Steroids | |
* | |
* Outbound Link Tracking Plugin | |
* | |
* Copyright 2011, Cardinal Path and Direct Performance | |
* Licensed under the GPLv3 license. | |
* | |
* @author Eduardo Cereto <eduardocereto@gmail.com> | |
*/ | |
/** | |
* Triggers the Outbound Link Tracking on the page | |
* | |
* @this {object} GA Helper object. | |
* @param {object} opts Custom options for Outbound Links. | |
*/ | |
var _gasTrackOutboundLinks = function(opts) { | |
if (!this._outboundTracked) { | |
this._outboundTracked = true; | |
} else { | |
//Oops double tracking detected. | |
return; | |
} | |
var gh = this; | |
if (!opts) { | |
opts = {}; | |
} | |
opts['category'] = opts['category'] || 'Outbound'; | |
gh._liveEvent('a', 'mousedown', function(e) { | |
var l = this; | |
if ( | |
(l.protocol == 'http:' || l.protocol == 'https:') && sindexOf.call(l.hostname, document.location.hostname) === -1) { | |
var path = (l.pathname + l.search + ''), | |
utm = sindexOf.call(path, '__utm'); | |
if (utm !== -1) { | |
path = path.substring(0, utm); | |
} | |
_gas.push(['_trackEvent', opts['category'], l.hostname, path]); | |
} | |
}); | |
}; | |
_gas.push(['_addHook', '_gasTrackOutboundLinks', _gasTrackOutboundLinks]); | |
// Old API to be deprecated on v2.0 | |
_gas.push(['_addHook', '_trackOutboundLinks', _gasTrackOutboundLinks]); | |
/** | |
* GAS - Google Analytics on Steroids | |
* | |
* Vimeo Video Tracking Plugin | |
* | |
* Copyright 2011, Cardinal Path and Direct Performance | |
* Licensed under the GPLv3 license. | |
* | |
* @author Eduardo Cereto <eduardocereto@gmail.com> | |
*/ | |
var _vimeoTimeTriggers = []; | |
var _vimeoPoolMaps = {}; | |
/** | |
* Cached urls for vimeo players on the page. | |
* | |
* @type {object} | |
*/ | |
var _vimeo_urls = {}; | |
function _vimeoPool(data) { | |
if (!_vimeoPoolMaps[data.player_id]) { | |
_vimeoPoolMaps[data.player_id] = {}; | |
_vimeoPoolMaps[data.player_id].timeTriggers = slice.call( | |
_vimeoTimeTriggers); | |
} | |
if (_vimeoPoolMaps[data.player_id].timeTriggers.length > 0) { | |
if (data.data.percent * 100 >= _vimeoPoolMaps[data.player_id].timeTriggers[0]) { | |
var action = _vimeoPoolMaps[data.player_id].timeTriggers.shift(); | |
_gas.push(['_trackEvent', 'Vimeo Video', action + '%', _vimeo_urls[data.player_id]]); | |
} | |
} | |
} | |
/** | |
* Helper function to post messages to a vimeo player | |
* | |
* @param {string} method The method from the vimeo API. | |
* @param {string} params to be passed as the value of the method. | |
* @param {object} target Iframe DOM Element for the Vimeo player. | |
* @return {boolean} true if it worked or false otherwise. | |
*/ | |
function _vimeoPostMessage(method, params, target) { | |
if (!target.contentWindow || !target.contentWindow.postMessage || !JSON) { | |
return false; | |
} | |
var url = target.getAttribute('src').split('?')[0], | |
data = JSON.stringify({ | |
method: method, | |
value: params | |
}); | |
target.contentWindow.postMessage(data, url); | |
return true; | |
} | |
/** | |
* Flag that indicates if the global listener has been bind to the window | |
* @type {boolean} | |
*/ | |
var _has_vimeo_window_event = false; | |
var _vimeoOpts; | |
/** | |
* postMessage Listener | |
* @param {Object} event The Vimeo API return event. | |
*/ | |
function _vimeoPostMessageListener(event) { | |
if (sindexOf.call(event.origin, '//player.vimeo.com') > -1) { | |
var data = JSON.parse(event.data); | |
if (data.event === 'ready') { | |
_trackVimeo.call(_gas.gh); // Force rerun since a player is ready | |
} else if (data.method) { | |
if (data.method == 'getVideoUrl') { | |
_vimeo_urls[data.player_id] = data.value; | |
} | |
} else if (data.event === 'playProgress') { | |
_vimeoPool(data); | |
} else { | |
_gas.push(['_trackEvent', _vimeoOpts['category'], data.event, _vimeo_urls[data.player_id]]); | |
} | |
} | |
} | |
/** | |
* Triggers the Vimeo Tracking on the page | |
* | |
* Only works for the Universal Tag from Vimeo (iframe). The video must have | |
* the parameter api=1 on the url in order to make the tracking work. | |
* | |
* @this {GasHelper} GA Helper object. | |
*/ | |
function _trackVimeo() { | |
var iframes = document.getElementsByTagName('iframe'); | |
var vimeo_videos = 0; | |
var player_id; | |
var player_src; | |
var separator; | |
var force = _vimeoOpts['force']; | |
var partials = _vimeoOpts['percentages']; | |
for (var i = 0; i < iframes.length; i++) { | |
if (sindexOf.call(iframes[i].src, '//player.vimeo.com') > -1) { | |
player_id = 'gas_vimeo_' + i; | |
player_src = iframes[i].src; | |
separator = '?'; | |
if (sindexOf.call(player_src, '?') > -1) { | |
separator = '&'; | |
} | |
if (sindexOf.call(player_src, 'api=1') < 0) { | |
if (force) { | |
// Reload the video enabling the api | |
player_src += separator + 'api=1&player_id=' + player_id; | |
} else { | |
// We won't track players that don't have api enabled. | |
continue; | |
} | |
} else { | |
if (sindexOf.call(player_src, 'player_id=') < -1) { | |
player_src += separator + 'player_id=' + player_id; | |
} | |
} | |
vimeo_videos++; | |
iframes[i].id = player_id; | |
if (iframes[i].src !== player_src) { | |
iframes[i].src = player_src; | |
break; // break to wait until it is ready since we reloaded it. | |
} | |
// We need to cache the video url since vimeo won't provide it | |
// in the event | |
_vimeoPostMessage('getVideoUrl', '', iframes[i]); | |
_vimeoPostMessage('addEventListener', 'play', iframes[i]); | |
_vimeoPostMessage('addEventListener', 'pause', iframes[i]); | |
_vimeoPostMessage('addEventListener', 'finish', iframes[i]); | |
if (partials) { | |
_vimeoTimeTriggers = partials; | |
_vimeoPostMessage('addEventListener', 'playProgress', iframes[i]); | |
} | |
} | |
} | |
if (vimeo_videos > 0 && _has_vimeo_window_event === false) { | |
this._addEventListener(window, 'message', _vimeoPostMessageListener, false); | |
_has_vimeo_window_event = true; | |
} | |
} | |
var _gasTrackVimeo = function(opts) { | |
var gh = this; | |
// Support | |
if (typeof opts === 'boolean' || opts === 'force') { | |
opts = { | |
'force': !! opts | |
}; | |
} | |
opts = opts || {}; | |
opts['category'] = opts['category'] || 'Vimeo Video'; | |
opts['percentages'] = opts['percentages'] || []; | |
opts['force'] = opts['force'] || false; | |
_vimeoOpts = opts; | |
gh._DOMReady(function() { | |
_trackVimeo.call(gh); | |
}); | |
return false; | |
}; | |
_gas.push(['_addHook', '_gasTrackVimeo', _gasTrackVimeo]); | |
// Old API to be deprecated on v2.0 | |
_gas.push(['_addHook', '_trackVimeo', _gasTrackVimeo]); | |
/** | |
* GAS - Google Analytics on Steroids | |
* | |
* YouTube Video Tracking Plugin | |
* | |
* Copyright 2011, Cardinal Path and Direct Performance | |
* Licensed under the GPLv3 license. | |
* | |
* @author Eduardo Cereto <eduardocereto@gmail.com> | |
*/ | |
/** | |
* Array of percentage to fire events. | |
*/ | |
var _ytTimeTriggers = []; | |
var _ytOpts; | |
/** | |
* Used to map each vid to a set of timeTriggers and it's pool timer | |
*/ | |
var _ytPoolMaps = {}; | |
function _ytStartPool(target) { | |
if (_ytTimeTriggers && _ytTimeTriggers.length) { | |
var h = target['getVideoData']()['video_id']; | |
if (_ytPoolMaps[h]) { | |
_ytStopPool(target); | |
} else { | |
_ytPoolMaps[h] = {}; | |
_ytPoolMaps[h].timeTriggers = slice.call(_ytTimeTriggers); | |
} | |
_ytPoolMaps[h].timer = setTimeout(_ytPool, 1000, target, h); | |
} | |
} | |
function _ytPool(target, hash) { | |
if (_ytPoolMaps[hash] == undefined || _ytPoolMaps[hash].timeTriggers.length <= 0) { | |
return false; | |
} | |
var p = target['getCurrentTime']() / target['getDuration']() * 100; | |
if (p >= _ytPoolMaps[hash].timeTriggers[0]) { | |
var action = _ytPoolMaps[hash].timeTriggers.shift(); | |
_gas.push(['_trackEvent', _ytOpts['category'], action + '%', target['getVideoUrl']()]); | |
} | |
_ytPoolMaps[hash].timer = setTimeout(_ytPool, 1000, target, hash); | |
} | |
function _ytStopPool(target) { | |
var h = target['getVideoData']()['video_id']; | |
if (_ytPoolMaps[h] && _ytPoolMaps[h].timer) { | |
_ytPool(target, h); // Pool one last time before clearing it. | |
clearTimeout(_ytPoolMaps[h].timer); | |
} | |
} | |
/** | |
* Called when the Video State changes | |
* | |
* We are currently tracking only finish, play and pause events | |
* | |
* @param {Object} event the event passed by the YT api. | |
*/ | |
function _ytStateChange(event) { | |
var action = ''; | |
switch (event['data']) { | |
case 0: | |
action = 'finish'; | |
_ytStopPool(event['target']); | |
break; | |
case 1: | |
action = 'play'; | |
_ytStartPool(event['target']); | |
break; | |
case 2: | |
action = 'pause'; | |
_ytStopPool(event['target']); | |
break; | |
} | |
if (action) { | |
_gas.push(['_trackEvent', _ytOpts['category'], action, event['target']['getVideoUrl']()]); | |
} | |
} | |
/** | |
* Called when the player fires an Error Event | |
* | |
* @param {Object} event the event passed by the YT api. | |
*/ | |
function _ytError(event) { | |
_gas.push(['_trackEvent', _ytOpts['category'], 'error (' + event['data'] + ')', event['target']['getVideoUrl']()]); | |
} | |
/** | |
* Looks for object/embed youtube videos and migrate them to the iframe method | |
* so it tries to track them | |
*/ | |
function _ytMigrateObjectEmbed() { | |
var objs = document.getElementsByTagName('object'); | |
var pars, ifr, ytid; | |
var r = /(https?:\/\/www\.youtube(-nocookie)?\.com[^/]*).*\/v\/([^&?]+)/; | |
for (var i = 0; i < objs.length; i++) { | |
pars = objs[i].getElementsByTagName('param'); | |
for (var j = 0; j < pars.length; j++) { | |
if (pars[j].name == 'movie' && pars[j].value) { | |
// Replace the object with an iframe | |
ytid = pars[j].value.match(r); | |
if (ytid && ytid[1] && ytid[3]) { | |
ifr = document.createElement('iframe'); | |
ifr.src = ytid[1] + '/embed/' + ytid[3] + '?enablejsapi=1'; | |
ifr.width = objs[i].width; | |
ifr.height = objs[i].height; | |
ifr.setAttribute('frameBorder', '0'); | |
ifr.setAttribute('allowfullscreen', ''); | |
objs[i].parentNode.insertBefore(ifr, objs[i]); | |
objs[i].parentNode.removeChild(objs[i]); | |
// Since we removed the object the Array changed | |
i--; | |
} | |
break; | |
} | |
} | |
} | |
} | |
/** | |
* Triggers the YouTube Tracking on the page | |
* | |
* Only works for the iframe tag. The video must have the parameter | |
* enablejsapi=1 on the url in order to make the tracking work. | |
* | |
* @param {(object)} opts GAS Options object. | |
*/ | |
function _trackYoutube(opts) { | |
var force = opts['force']; | |
var opt_timeTriggers = opts['percentages']; | |
if (force) { | |
try { | |
_ytMigrateObjectEmbed(); | |
} catch (e) { | |
_gas.push(['_trackException', e, 'GAS Error on youtube.js:_ytMigrateObjectEmbed']); | |
} | |
} | |
var youtube_videos = []; | |
var iframes = document.getElementsByTagName('iframe'); | |
for (var i = 0; i < iframes.length; i++) { | |
if (sindexOf.call(iframes[i].src, '//www.youtube.com/embed') > -1) { | |
if (sindexOf.call(iframes[i].src, 'enablejsapi=1') < 0) { | |
if (force) { | |
// Reload the video enabling the api | |
if (sindexOf.call(iframes[i].src, '?') < 0) { | |
iframes[i].src += '?enablejsapi=1'; | |
} else { | |
iframes[i].src += '&enablejsapi=1'; | |
} | |
} else { | |
// We can't track players that don't have api enabled. | |
continue; | |
} | |
} | |
youtube_videos.push(iframes[i]); | |
} | |
} | |
if (youtube_videos.length > 0) { | |
if (opt_timeTriggers && opt_timeTriggers.length) { | |
_ytTimeTriggers = opt_timeTriggers; | |
} | |
// this function will be called when the youtube api loads | |
window['onYouTubePlayerAPIReady'] = function() { | |
var p; | |
for (var i = 0; i < youtube_videos.length; i++) { | |
p = new window['YT']['Player'](youtube_videos[i]); | |
p.addEventListener('onStateChange', _ytStateChange); | |
p.addEventListener('onError', _ytError); | |
} | |
}; | |
// load the youtube player api | |
var tag = document.createElement('script'); | |
//XXX use document.location.protocol | |
var protocol = 'http:'; | |
if (document.location.protocol === 'https:') { | |
protocol = 'https:'; | |
} | |
tag.src = protocol + '//www.youtube.com/player_api'; | |
tag.type = 'text/javascript'; | |
tag.async = true; | |
var firstScriptTag = document.getElementsByTagName('script')[0]; | |
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); | |
} | |
} | |
var _gasTrackYoutube = function(opts) { | |
// Support for legacy parameters | |
var args = slice.call(arguments); | |
if (args[0] && (typeof args[0] === 'boolean' || args[0] === 'force')) { | |
opts = { | |
'force': !! args[0] | |
}; | |
if (args[1] && args[1].length) { | |
opts['percentages'] = args[1]; | |
} | |
} | |
opts = opts || {}; | |
opts['force'] = opts['force'] || false; | |
opts['category'] = opts['category'] || 'YouTube Video'; | |
opts['percentages'] = opts['percentages'] || []; | |
_ytOpts = opts; | |
var gh = this; | |
gh._DOMReady(function() { | |
_trackYoutube.call(gh, opts); | |
}); | |
return false; | |
}; | |
_gas.push(['_addHook', '_gasTrackYoutube', _gasTrackYoutube]); | |
// Old API to be deprecated on v2.0 | |
_gas.push(['_addHook', '_trackYoutube', _gasTrackYoutube]); | |
/** | |
* Wrap-up | |
*/ | |
// Execute previous functions | |
while (_gas._queue.length > 0) { | |
_gas.push(_gas._queue.shift()); | |
} | |
// Import ga.js | |
if (_gaq && _gaq.length >= 0) { | |
(function() { | |
var ga = document.createElement('script'); | |
ga.type = 'text/javascript'; | |
ga.async = true; | |
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | |
var s = document.getElementsByTagName('script')[0]; | |
s.parentNode.insertBefore(ga, s); | |
})(); | |
} | |
})(window); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Helper Functions | |
function gaGetParameterByName(name) { | |
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search); | |
return match && decodeURIComponent(match[1].replace(/\+/g, ' ')); | |
} | |
function gaGetElementsByClassName(e) { | |
var tags = this.all || this.getElementsByTagName('*'); | |
var matchArray = {}; | |
var re1 = new RegExp('(?:^|\\s)'+e+'(?:\\s|$)'); | |
for (var i = 0; i < tags.length; i++) { | |
if (re1.test(tags[i].className)) { | |
matchArray[matchArray.length] = tags[i]; | |
} | |
} | |
return matchArray; | |
} | |
function gaSetCookie(name,value,minutes,hostname) { | |
if (minutes) { | |
var date = new Date(); | |
date.setTime(date.getTime()+(minutes*60*1000)); | |
var expires = "; expires="+date.toGMTString(); | |
} | |
else var expires = ""; | |
document.cookie = name+"="+value+expires+"; path=/; domain="+hostname+";"; | |
} | |
function gaReadCookie(name) { | |
var nameEQ = name + "="; | |
var ca = document.cookie.split(';'); | |
for(var i=0;i < ca.length;i++) { | |
var c = ca[i]; | |
while (c.charAt(0)==' ') c = c.substring(1,c.length); | |
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); | |
} | |
return undefined; | |
} | |
//GAS Utility Code | |
(function(h,n){function p(){this.tracker=h._gat._getTrackers()[0]}function r(){var a=this;a.b={};a.h=0;a.l=z;a.f="_gas1";a.i={};a.d={_addHook:[a.m]};a.push(function(){a.i=new p})}function q(a){if(_gas.o)try{console.log(a)}catch(b){}return h._gaq.push(a)}function I(a,b){if(typeof a!=="string")return!1;var c=a.split("?")[0],c=c.split(".");return(c=c[c.length-1])&&this.g(b,c)?c:!1}function J(a){for(var b=this,c=f.getElementsByTagName("a"),d=0;d<c.length;d++)this.a(c[d],"mousedown",function(c){if(c.target&& | |
c.target.tagName==="A"){var d=I.call(b,c.target.href,a);d&&_gas.push(["_trackEvent","Download",d,c.target.href])}})}function K(a,b){function c(b){var c=b.target,c=c.name||c.id||c.type||c.nodeName,b=b.type,d=a.name||a.id||n;_gas.push(["_trackEvent","Form Tracking","form"+(d?" ("+d+")":""),c+" ("+b+")"])}var d=this;if(b)d.a(h,"click",function(a){try{var b=a.target;a.type=="click"&&d.g(["button","submit","image","reset"],b.type.toLowerCase())&&c(a)}catch(g){}}),d.a(f.body,"change",function(a){try{var b= | |
a.target;a.type=="change"&&d.g(["input","select","textarea","hidden"],b.nodeName.toLowerCase())&&c(a)}catch(g){}});else{var e,g;if(!a.elements||!a.elements.length)return!1;for(e=0;e<a.elements.length;e++)g=a.elements[e],d.g(["button","submit","image","reset"],g.type)?d.a(g,"click",c):d.a(g,"change",c);d.a(a,"submit",c)}}function v(a){_gas.push(["_trackEvent",this.tagName,a.type,this.currentSrc])}function A(a){var b=this;b.e(function(){for(var c=f.getElementsByTagName(a),d=0;d<c.length;d++)b.a(c[d], | |
"play",v),b.a(c[d],"ended",v),b.a(c[d],"pause",v)})}function B(){return Math.max(f.body.scrollHeight||0,o.scrollHeight||0,f.body.offsetHeight||0,o.offsetHeight||0,f.body.clientHeight||0,o.clientHeight||0)}function C(a){w&&clearTimeout(w);a===!0?k=Math.max(((h.pageYOffset||f.body.scrollTop||o.scrollTop||0)+(h.innerHeight||o.clientHeight||f.body.clientHeight||0))/B()*100,k):w=setTimeout(function(){k=Math.max(((h.pageYOffset||f.body.scrollTop||o.scrollTop||0)+(h.innerHeight||o.clientHeight||f.body.clientHeight|| | |
0))/B()*100,k)},400)}function L(){C(!0);k=Math.floor(k);if(!(k<=0||k>100)){var a=(k>10?1:0)*(Math.floor((k-1)/10)*10+1),a=String(a)+"-"+String(Math.ceil(k/10)*10);_gas.push(["_trackEvent","Max Scroll",D,a,Math.floor(k),!0])}}function s(a,b,c){if(c.contentWindow&&c.contentWindow.postMessage){var d=c.getAttribute("src").split("?")[0],a=JSON.stringify({method:a,value:b});c.contentWindow.postMessage(a,d)}}function E(a){for(var b=f.getElementsByTagName("iframe"),c=0,d,e,g,j=0;j<b.length;j++)if(i.call(b[j].src, | |
"//player.vimeo.com")>-1){d="gas_vimeo_"+j;e=b[j].src;g="?";i.call(e,"?")>-1&&(g="&");if(i.call(e,"api=1")<0)if(a)e+=g+"api=1&player_id="+d;else break;else i.call(e,"player_id=")<-1&&(e+=g+"player_id="+d);c++;b[j].id=d;if(b[j].src!==e){b[j].src=e;break}s("getVideoUrl","",b[j]);s("addEventListener","play",b[j]);s("addEventListener","pause",b[j]);s("addEventListener","finish",b[j])}c>0&&F===!1&&(this.a(h,"message",function(a){if(i.call(a.origin,"//player.vimeo.com")>-1)if(a=JSON.parse(a.data),a.event=== | |
"ready")E();else if(a.method){if(a.method=="getVideoUrl")G[a.q]=a.value}else _gas.push(["_trackEvent","Vimeo Video",a.event,G[a.q]])},!1),F=!0)}function x(a,b){if(l[b]==n||l[b].j.length<=0)return!1;if(a.getCurrentTime()/a.getDuration()*100>=l[b].j[0]){var c=l[b].j.shift();_gas.push(["_trackEvent","YouTube Video",c+"%",a.getVideoUrl()])}l[b].k=setTimeout(x,1E3,a,b)}function y(a){var b=a.getVideoData().video_id;l[b]&&l[b].k&&(x(a,b),clearTimeout(l[b].k))}function M(a){var b="";switch(a.data){case 0:b= | |
"finish";y(a.target);break;case 1:var b="play",c=a.target;if(t&&t.length){var d=c.getVideoData().video_id;l[d]?y(c):(l[d]={},l[d].j=m.call(t));l[d].k=setTimeout(x,1E3,c,d)}break;case 2:b="pause",y(a.target)}b&&_gas.push(["_trackEvent","YouTube Video",b,a.target.getVideoUrl()])}function N(a){_gas.push(["_trackEvent","YouTube Video","error ("+a.data+")",a.target.getVideoUrl()])}function O(a,b){for(var c=[],d=f.getElementsByTagName("iframe"),e=0;e<d.length;e++)if(i.call(d[e].src,"//www.youtube.com/embed")> | |
-1){if(i.call(d[e].src,"enablejsapi=1")<0)if(a)d[e].src+=i.call(d[e].src,"?")<0?"?enablejsapi=1":"&enablejsapi=1";else continue;c.push(d[e])}if(c.length>0)b&&b.length&&(t=b),h.onYouTubePlayerAPIReady=function(){for(var a,b=0;b<c.length;b++)a=new h.YT.Player(c[b]),a.addEventListener("onStateChange",M),a.addEventListener("onError",N)},d=f.createElement("script"),d.src="http://www.youtube.com/player_api",d.type="text/javascript",d.async=!0,e=f.getElementsByTagName("script")[0],e.parentNode.insertBefore(d, | |
e)}p.prototype.g=function(a,b){if(a&&a.length)for(var c=0;c<a.length;c++)if(a[c]===b)return!0;return!1};p.prototype.isArray=function(a){return P.call(a)==="[object Array]"};p.prototype.a=function(a,b,c,d){function e(b){if(!b||!b.target)b=h.event,b.target=b.srcElement;return c.call(a,b)}a.addEventListener?a.addEventListener(b,e,!!d):a.attachEvent?a.attachEvent("on"+b,e):(b="on"+b,typeof a[b]==="function"&&(e=function(a,b){return function(){a.apply(this,arguments);b.apply(this,arguments)}}(a[b],e)), | |
a[b]=e)};p.prototype.e=function(a){function b(){if(!arguments.callee.p)arguments.callee.p=!0,a.apply(c,arguments)}var c=this;/^(interactive|complete)/.test(f.readyState)?b():(this.a(f,"DOMContentLoaded",b,!1),this.a(h,"load",b,!1))};h._gaq=h._gaq||[];var z=h._gas||[];if(!(z.h>=0)){var f=h.document,P=Object.prototype.toString,Q=Object.prototype.hasOwnProperty,m=Array.prototype.slice,i=String.prototype.indexOf,D=f.location.href,o=f.documentElement;r.prototype.m=function(a,b){typeof a==="string"&&typeof b=== | |
"function"&&(typeof _gas.d[a]==="undefined"&&(_gas.d[a]=[]),_gas.d[a].push(b));return!1};r.prototype.n=function(){var a=m.call(arguments),b=a.shift(),a=!0,c,d,e,g,f;if(typeof b==="function")return q(function(a,b){return function(){a.call(b)}}(b,this.i));else if(typeof b==="object"&&b.length>0){d=b.shift();i.call(d,".")>=0?(g=d.split(".")[0],d=d.split(".")[1]):g=n;if((e=this.d[d])&&e.length>0)for(c=0;c<e.length;c++)try{f=e[c].apply(this.i,b),f===!1?a=!1:f&&f.length>0&&(b=f)}catch(h){d!=="_trackException"&& | |
this.push(["_trackException",h])}if(a===!1)return 1;if(d==="_setAccount"){for(c in this.b)if(this.b[c]==b[0]&&g===n)return 1;g=g||"_gas"+String(this.h+1);typeof this.b._gas1=="undefined"&&i.call(g,"_gas")!=-1&&(g="_gas1");this.b[g]=b[0];this.h+=1;g=g===_gas.f?"":g+".";return q([g+d,b[0]])}if(d==="_link"||d==="_linkByPost")return a=m.call(b),a.unshift(d),q(a);if(g&&this.b[g])return f=(g===_gas.f?"":g+".")+d,a=m.call(b),a.unshift(f),q(a);e=0;for(c in this.b)Q.call(this.b,c)&&(f=(c===_gas.f?"":c+".")+ | |
d,a=m.call(b),a.unshift(f),e+=q(a));return e?1:0}};r.prototype.push=function(){for(var a=m.call(arguments),b=0;b<a.length;b++)(function(a,b){h._gaq.push(function(){b.n.call(b,a)})})(a[b],this)};h._gas=_gas=new r;_gas.push(["_addHook","_trackException",function(a,b){_gas.push(["_trackEvent","Exception "+(a.name||"Error"),b||a.message||a,D]);return!1}]);_gas.push(["_addHook","_setDebug",function(a){_gas.o=!!a}]);_gas.push(["_addHook","_popHook",function(a){(a=_gas.d[a])&&a.pop&&a.pop();return!1}]); | |
_gas.push(["_addHook","_setDefaultTracker",function(a){_gas.f=a}]);_gas.push(["_addHook","_trackPageview",function(a,b){if(b&&typeof b==="string"){var c=f.title;h.r.push(function(){f.title=b},["_trackPageview",a],function(){f.title=c});return!1}return[a]}]);_gas.push(["_addHook","_trackDownloads",function(a){var b="xls,xlsx,doc,docx,ppt,pptx,pdf,txt,zip";b+=",rar,7z,exe,wma,mov,avi,wmv,mp3,csv,tsv";b=b.split(",");typeof a==="string"?b=b.concat(a.split(",")):this.isArray(a)&&(b=b.concat(a));J.call(this, | |
b);return!1}]);_gas.push(["_addHook","_trackEvent",function(){var a=m.call(arguments);a[3]&&(a[3]=(a[3]<0?0:Math.round(a[3]))||0);return a}]);_gas.push(["_addHook","_trackForms",function(a){var b=this;this.e(function(){for(var c=f.getElementsByTagName("form"),d=0;d<c.length;d++){try{K.call(b,c[d],a)}catch(e){}if(a)break}return!1})}]);_gas.push(["_addHook","_trackVideo",function(){A.call(this,"video")}]);_gas.push(["_addHook","_trackAudio",function(){A.call(this,"audio")}]);var w=null,k=0;_gas.push(["_addHook", | |
"_trackMaxScroll",function(){this.a(h,"scroll",C);this.a(h,"beforeunload",L)}]);_gas.c=!1;_gas.push(["_addHook","_setAllowAnchor",function(a){_gas.c=!!a}]);_gas.push(["_addHook","_link",function(a,b){if(b===n)b=_gas.c;return[a,b]}]);_gas.push(["_addHook","_linkByPost",function(a,b){if(b===n)b=_gas.c;return[a,b]}]);var u=[],H=n;_gas.push(["_addHook","_setDomainName",function(a){if(i.call("."+f.location.hostname,a)<0)return u.push(a),!1;H=a}]);_gas.push(["_addHook","_addExternalDomainName",function(a){u.push(a); | |
return!1}]);_gas.push(["_addHook","_setMultiDomain",function(a){var b=f.location.hostname,c=this,d,e,g,h=f.getElementsByTagName("a");a!=="now"&&a!=="mousedown"&&(a="click");for(d=0;d<h.length;d++)if(g=h[d],i.call(g.href,"http")===0&&!(g.hostname==b||i.call(g.hostname,H)>=0))for(e=0;e<u.length;e++)if(i.call(g.hostname,u[e])>=0)a==="now"?g.href=c.tracker._getLinkerUrl(g.href,_gas.c):a==="click"?this.a(g,a,function(a){_gas.push(["_link",this.href,_gas.c]);a.preventDefault?a.preventDefault():a.returnValue= | |
!1}):this.a(g,a,function(){this.href=c.tracker._getLinkerUrl(this.href,_gas.c)});return!1}]);_gas.push(["_addHook","_trackOutboundLinks",function(){for(var a=f.getElementsByTagName("a"),b=0;b<a.length;b++)this.a(a[b],"mousedown",function(a){a=a.target;if((a.protocol=="http:"||a.protocol=="https:")&&i.call(a.href,f.location.hostname)===-1){var b=a.pathname+a.search+"",e=i.call(b,"__utm");e!==-1&&(b=b.substring(0,e));_gas.push(["_trackEvent","Outbound",a.hostname,b])}})}]);var G={},F=!1;_gas.push(["_addHook", | |
"_trackVimeo",function(a){var b=this;b.e(function(){E.call(b,a)});return!1}]);var t=[],l={};for(_gas.push(["_addHook","_trackYoutube",function(){var a=m.call(arguments),b=this;b.e(function(){O.apply(b,a)});return!1}]);_gas.l.length>0;)_gas.push(_gas.l.shift());_gaq&&_gaq.length>=0&&function(){var a=f.createElement("script");a.type="text/javascript";a.async=!0;a.src=("https:"==f.location.protocol?"https://ssl":"http://www")+".google-analytics.com/ga.js";var b=f.getElementsByTagName("script")[0];b.parentNode.insertBefore(a, | |
b)}()}})(window); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment