diff --git a/ajax/libs/gas/1.11.0/gas.js b/ajax/libs/gas/1.11.0/gas.js new file mode 100644 index 000000000..c55b022e0 --- /dev/null +++ b/ajax/libs/gas/1.11.0/gas.js @@ -0,0 +1,1779 @@ +/** + * @preserve Copyright 2011, Cardinal Path and DigitalInc. + * + * GAS - Google Analytics on Steroids + * https://github.com/CardinalPath/gas + * + * @author Eduardo Cereto + * 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 + */ + +/** + * GasHelper singleton class + * + * Should be called when ga.js is loaded to get the pageTracker. + * + * @constructor + */ +/*jshint -W079*/ +var GasHelper = function () { + this._setDummyTracker(); +}; +/*jshint +W079*/ + +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; +}; + +/** + * 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) { + var el = me.target; + + while (el && el.nodeName && el.nodeName.toUpperCase() !== 'HTML') + { + if (gh.inArray(tag, el.nodeName)) { + ofunc.call(el, me); + break; + } + el = el.parentNode; + } + + }, 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; + function cb() { + if (cb.done) return; + cb.done = true; + callback.apply(scp, arguments); + } + if (/^(interactive|complete)/.test(document.readyState)) return cb(); + this._addEventListener(document, 'DOMContentLoaded', cb, false); + this._addEventListener(window, 'load', cb, false); +}; + + +/** + * GAS - Google Analytics on Steroids + * + * Copyright 2011, Cardinal Path and Direct Performance + * Licensed under the MIT license. + * + * @author Eduardo Cereto + */ + /*global document:true*/ + +/** + * 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 +/*jshint -W079*/ +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; +/*jshint +W079*/ +/** + * GAS Sigleton + * @constructor + */ +function GAS() { + var self = this; + self['version'] = '1.11.0'; + 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 + */ +/*global _gas:true*/ +window['_gas'] = _gas = new GAS(); +/*global _gas:false*/ + + +/** + * 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 + */ + +/** + * 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 false; + } + 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]); + + +/** + * GAS - Google Analytics on Steroids + * + * Ecommerce Meta + * + * Copyright 2012, Cardinal Path and Direct Performance + * Licensed under the GPLv3 license. + * + * @author Eduardo Cereto + */ + +function _gasMetaEcommerce() { + var i, meta, + f_trans = 0, + f_item = 0, + metas = document.getElementsByTagName('meta'); + for (i = 0; i < metas.length; i++) { + if (metas[i].name === 'ga_trans') { + // Fire transaction + meta = metas[i].content.split('^'); + if (meta.length < 3) { + // 3 is the minimum for transaction + break; + } + // Add default values for remaining params + while (meta.length < 8) { + meta.push(''); + } + _gas.push(['_addTrans', + meta[0], + meta[1], + meta[2], + meta[3], + meta[4], + meta[5], + meta[6], + meta[7] + ]); + f_trans++; + } + else if (metas[i].name === 'ga_item') { + // Fire item + meta = metas[i].content.split('^'); + if (meta.length === 6) { + _gas.push(['_addItem', + meta[0], + meta[1], + meta[2], + meta[3], + meta[4], + meta[5] + ]); + f_item++; + } + } + } + if (f_trans > 0 && f_item > 0) { + _gas.push(['_trackTrans']); + //_gas.push(['_clearTrans']); + } + return false; +} + +_gas.push(['_addHook', '_gasMetaEcommerce', _gasMetaEcommerce]); + + +/** + * 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] = Math.round(args[3]); + } + 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 + */ + +/** + * 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 false; + } + 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); + } + } + }); + return false; +}; + +_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 + */ + +/** + * 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); + return false; +}; + +var _trackVideo = function () { + if (!this._videoTracked) { + this._videoTracked = true; + } else { + //Oops double tracking detected. + return; + } + return _trackMedia.call(this, 'video'); +}; + +var _trackAudio = function () { + if (!this._audioTracked) { + this._audioTracked = true; + } else { + //Oops double tracking detected. + return; + } + 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 + * + * HTML Markup Plugin + * + * Copyright 2012, Cardinal Path and Direct Performance + * Licensed under the GPLv3 license. + * + * @author Eduardo Cereto + */ + +/** + * Sets Default pagename and Custom Vars based on Meta + * + * If a meta name='ga_vpv' is availalbe on the page use that as a page + * replacement if the pageview is not passed as parameter. + * + * If meta name="ga_custom_var" the 4 values for a custom var must be on + * content separated by a caret (^). + */ +function _gasMeta() { + var i, meta, + metas = document.getElementsByTagName('meta'); + for (i = 0; i < metas.length; i++) { + if (metas[i].name === 'ga_vpv') { + meta = metas[i].content; + (function (vpv) { + window._gas.push(['_addHook', '_trackPageview', function (p) { + if (p === undefined) { + return [vpv]; + } + }]); + }(meta)); + } else if (metas[i].name === 'ga_custom_var') { + meta = metas[i].content.split('^'); + if (meta.length === 4) { + window._gas.push(['_setCustomVar', + parseInt(meta[0], 10), + meta[1], + meta[2], + parseInt(meta[3], 10) + ]); + } + } + } + return false; +} + +/** + * Listens to all clicks and looks for a tagged element on it. + * + * Events have the following params: + * x-ga-event-category (required) – The category of the event specified in + * the solution design document + * x-ga-event-action (required) – The action of the event specified in the + * solution design document + * x-ga-event-label (optional) – The label of the event specified in the + * solution design document. If no label is specified in the solution design + * document, this attribute can be omitted + * x-ga-event-value (optional) – The value (integer) of the event specified + * in the solution design document. If no value is specified in the solution + * design document, this attribute can be omitted + * x-ga-event-noninteractive (optional) – Boolean (true/false) value + * specified in the solution design document. If the non-interactive value is + * not specified, this attribute can be omitted + * + * Social Actions have the following params: + * x-ga-social-network (required) – The network of the social interaction + * specified in the solution design document + * x-ga-social-action (required) – The action of the social interaction + * specified in the solution design document + * x-ga-social-target (optional) – The target of the social interaction + * specified in the solution design document. If no target is specified, this + * attribute can be omitted + * x-ga-social-pagepath (optional) – The page path of the social interaction + * specified in the solution design document. If no page path is specified, + * this attribute can be omitted + */ +function _gasHTMLMarkup() { + var gh = this; + + gh._addEventListener(document, 'mousedown', function (me) { + var el; + for (el = me.target; el.nodeName !== 'HTML'; + el = el.parentNode) { + if (el.getAttribute('x-ga-event-category')) { + // Event element clicked, fire the _trackEvent + window._gas.push(['_trackEvent', + el.getAttribute('x-ga-event-category'), + el.getAttribute('x-ga-event-action'), + el.getAttribute('x-ga-event-label') || undefined, + parseInt(el.getAttribute('x-ga-event-value'), 10) || 0, + el.getAttribute('x-ga-event-noninteractive') === 'true' ? true : false + ]); + } + if (el.getAttribute('x-ga-social-network')) { + // Social Action Clicked fire _trackSocial + window._gas.push(['_trackSocial', + el.getAttribute('x-ga-social-network'), + el.getAttribute('x-ga-social-action'), + el.getAttribute('x-ga-social-target') || undefined, + el.getAttribute('x-ga-social-pagepath') || undefined + ]); + } + + if (el.parentNode === null) { + break; + } + } + }, true); + + return false; +} + +_gas.push(['_addHook', '_gasMeta', _gasMeta]); +_gas.push(['_addHook', '_gasHTMLMarkup', _gasHTMLMarkup]); + + +/** + * 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 false; + } + + 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 + */ + +var _maxScrollOpts; + +/** + * 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 + ]); +} + +/** + * 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 false; + } + _maxScrollOpts = opts || {}; + _maxScrollOpts['category'] = _maxScrollOpts['category'] || 'Max Scroll'; + + this._addEventListener(window, 'scroll', _update_scroll_percentage); + this._addEventListener(window, 'beforeunload', _sendMaxScroll); + + return false; +} + +_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 + */ + +/** + * 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.} + */ +var _external_domains = []; + +/** + * Store the internal domain name + * + * @type string + */ +var _internal_domain; + +/** + * _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) { + if (this.target && this.target === '_blank') { + window.open( + gh['tracker']['_getLinkerUrl']( + this.href, _gas._allowAnchor + ) + ); + } else { + _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); + if (gh && gh._DOMReady) { + gh._DOMReady(function () { + track_links.apply(gh, args); + }); + } + return false; +}; + +/** + * 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 + */ + +/** + * 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, + 0, + true + ]); + } + + }); + return false; +}; + +_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 + */ + +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. + */ +/*jshint latedef:false*/ +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]]); + } + } + +} +/*jshint latedef:true*/ + +/** + * 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 + */ + +/** + * 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 _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['getVideoUrl'](); + if (_ytPoolMaps[h] && _ytPoolMaps[h].timer) { + _ytPool(target, h); // Pool one last time before clearing it. + clearTimeout(_ytPoolMaps[h].timer); + } +} + +function _ytStartPool(target) { + if (_ytTimeTriggers && _ytTimeTriggers.length) { + var h = target['getVideoUrl'](); + if (_ytPoolMaps[h]) { + _ytStopPool(target); + } else { + _ytPoolMaps[h] = {}; + _ytPoolMaps[h].timeTriggers = slice.call(_ytTimeTriggers); + } + _ytPoolMaps[h].timer = setTimeout(_ytPool, 1000, target, h); + } +} + + +/** + * 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 (typeof window._gat === 'undefined') { + (function () { + var gasScript = document.getElementById('gas-script'); + var ga = document.createElement('script'); + ga.type = 'text/javascript'; + ga.async = true; + if (gasScript !== null && gasScript.getAttribute('data-use-dcjs') === 'true') { + ga.src = ( + 'https:' === document.location.protocol ? + 'https://' : 'http://') + + 'stats.g.doubleclick.net/dc.js'; + } else { + 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); diff --git a/ajax/libs/gas/1.11.0/gas.min.js b/ajax/libs/gas/1.11.0/gas.min.js new file mode 100644 index 000000000..38a9abe57 --- /dev/null +++ b/ajax/libs/gas/1.11.0/gas.min.js @@ -0,0 +1,10 @@ +/** + * @preserve Copyright 2011, Cardinal Path and DigitalInc. + * + * GAS - Google Analytics on Steroids + * https://github.com/CardinalPath/gas + * + * @author Eduardo Cereto + * Licensed under the GPLv3 license. + */ +!function(a,b){function c(){var a=this;a.version="1.11.0",a._accounts={},a._accounts_length=0,a._queue=F,a._default_tracker="_gas1",a.gh={},a._hooks={_addHook:[a._addHook]},a.push(function(){a.gh=new E})}function d(a){return a===_gas._default_tracker?"":a+"."}function e(b){if(_gas.debug_mode)try{console.log(b)}catch(c){}return a._gaq.push(b)}function f(a,b){if("string"!=typeof a)return!1;var c=a.split("?")[0];return c=c.split("."),c=c[c.length-1],c&&this.inArray(b,c)?c:!1}function g(){var a,b,c=0,d=0,e=G.getElementsByTagName("meta");for(a=0;a0&&d>0&&_gas.push(["_trackTrans"]),!1}function h(a){for(;a&&"HTML"!==a.nodeName&&"FORM"!==a.nodeName;)a=a.parentNode;return"FORM"===a.nodeName?a.name||a.id||"none":"none"}function i(a){_gas.push(["_trackEvent",this.tagName,a.type,this.currentSrc])}function j(){var c,d,e=G.getElementsByTagName("meta");for(c=0;c=U||U>100)){var a=(U>10?1:0)*(10*Math.floor((U-1)/10)+1);a=String(a)+"-"+String(10*Math.ceil(U/10)),_gas.push(["_trackEvent",S.category,K,a,Math.floor(U),!0])}}function r(b){return this._maxScrollTracked?!1:(this._maxScrollTracked=!0,S=b||{},S.category=S.category||"Max Scroll",this._addEventListener(a,"scroll",p),this._addEventListener(a,"beforeunload",q),!1)}function s(b){if(!this._multidomainTracked){this._multidomainTracked=!0;var c,d,e,f=G.location.hostname,g=this,h=G.getElementsByTagName("a");for("now"!==b&&"mousedown"!==b&&(b="click"),c=0;c=0)continue;for(d=0;d=0&&("now"===b?e.href=g.tracker._getLinkerUrl(e.href,_gas._allowAnchor):"click"===b?this._addEventListener(e,b,function(b){return this.target&&"_blank"===this.target?a.open(g.tracker._getLinkerUrl(this.href,_gas._allowAnchor)):_gas.push(["_link",this.href,_gas._allowAnchor]),b.preventDefault?b.preventDefault():b.returnValue=!1,!1}):this._addEventListener(e,b,function(){this.href=g.tracker._getLinkerUrl(this.href,_gas._allowAnchor)}))}return!1}}function t(a){if(_[a.player_id]||(_[a.player_id]={},_[a.player_id].timeTriggers=I.call($)),_[a.player_id].timeTriggers.length>0&&100*a.data.percent>=_[a.player_id].timeTriggers[0]){var b=_[a.player_id].timeTriggers.shift();_gas.push(["_trackEvent","Vimeo Video",b+"%",ab[a.player_id]])}}function u(a,b,c){if(!c.contentWindow||!c.contentWindow.postMessage||!JSON)return!1;var d=c.getAttribute("src").split("?")[0],e=JSON.stringify({method:a,value:b});return c.contentWindow.postMessage(e,d),!0}function v(a){if(J.call(a.origin,"//player.vimeo.com")>-1){var b=JSON.parse(a.data);"ready"===b.event?w.call(_gas.gh):b.method?"getVideoUrl"===b.method&&(ab[b.player_id]=b.value):"playProgress"===b.event?t(b):_gas.push(["_trackEvent",Z.category,b.event,ab[b.player_id]])}}function w(){for(var b,c,d,e=G.getElementsByTagName("iframe"),f=0,g=Z.force,h=Z.percentages,i=0;i-1){if(b="gas_vimeo_"+i,c=e[i].src,d="?",J.call(c,"?")>-1&&(d="&"),J.call(c,"api=1")<0){if(!g)continue;c+=d+"api=1&player_id="+b}else J.call(c,"player_id=")<-1&&(c+=d+"player_id="+b);if(f++,e[i].id=b,e[i].src!==c){e[i].src=c;break}u("getVideoUrl","",e[i]),u("addEventListener","play",e[i]),u("addEventListener","pause",e[i]),u("addEventListener","finish",e[i]),h&&($=h,u("addEventListener","playProgress",e[i]))}f>0&&bb===!1&&(this._addEventListener(a,"message",v,!1),bb=!0)}function x(a,c){if(fb[c]===b||fb[c].timeTriggers.length<=0)return!1;var d=a.getCurrentTime()/a.getDuration()*100;if(d>=fb[c].timeTriggers[0]){var e=fb[c].timeTriggers.shift();_gas.push(["_trackEvent",db.category,e+"%",a.getVideoUrl()])}fb[c].timer=setTimeout(x,1e3,a,c)}function y(a){var b=a.getVideoUrl();fb[b]&&fb[b].timer&&(x(a,b),clearTimeout(fb[b].timer))}function z(a){if(eb&&eb.length){var b=a.getVideoUrl();fb[b]?y(a):(fb[b]={},fb[b].timeTriggers=I.call(eb)),fb[b].timer=setTimeout(x,1e3,a,b)}}function A(a){var b="";switch(a.data){case 0:b="finish",y(a.target);break;case 1:b="play",z(a.target);break;case 2:b="pause",y(a.target)}b&&_gas.push(["_trackEvent",db.category,b,a.target.getVideoUrl()])}function B(a){_gas.push(["_trackEvent",db.category,"error ("+a.data+")",a.target.getVideoUrl()])}function C(){for(var a,b,c,d=G.getElementsByTagName("object"),e=/(https?:\/\/www\.youtube(-nocookie)?\.com[^\/]*).*\/v\/([^&?]+)/,f=0;f-1){if(J.call(g[h].src,"enablejsapi=1")<0){if(!c)continue;g[h].src+=J.call(g[h].src,"?")<0?"?enablejsapi=1":"&enablejsapi=1"}f.push(g[h])}if(f.length>0){d&&d.length&&(eb=d),a.onYouTubePlayerAPIReady=function(){for(var b,c=0;c0&&(this.tracker=b[0])}},E.prototype.inArray=function(a,b){if(a&&a.length)for(var c=0;c=0)){var G=a.document,H=(Object.prototype.toString,Object.prototype.hasOwnProperty),I=(Array.prototype.push,Array.prototype.slice),J=(String.prototype.trim,String.prototype.indexOf),K=G.location.href,L=G.documentElement;c.prototype._addHook=function(a,b){return"string"==typeof a&&"function"==typeof b&&("undefined"==typeof _gas._hooks[a]&&(_gas._hooks[a]=[]),_gas._hooks[a].push(b)),!1},c.prototype._execute=function(){var a,c,f,g,h,i=I.call(arguments),j=this,k=i.shift(),l=!0,m=0;if("function"==typeof k)return e(function(a,b){return function(){a.call(b)}}(k,j.gh));if("object"==typeof k&&k.length>0){if(c=k.shift(),J.call(c,".")>=0?(g=c.split(".")[0],c=c.split(".")[1]):g=b,f=j._hooks[c],f&&f.length>0)for(a=0;a0&&(k=h)}catch(n){"_trackException"!==c&&j.push(["_trackException",n])}if(l===!1)return 1;if("_setAccount"===c){for(a in j._accounts)if(j._accounts[a]===k[0]&&g===b)return 1;return g=g||"_gas"+String(j._accounts_length+1),"undefined"==typeof j._accounts._gas1&&-1!==J.call(g,"_gas")&&(g="_gas1"),j._accounts[g]=k[0],j._accounts_length+=1,g=d(g),m=e([g+c,k[0]]),j.gh._setDummyTracker(),m}if("_link"===c||"_linkByPost"===c||"_require"===c||"_anonymizeIp"===c)return i=I.call(k),i.unshift(c),e(i);var o;if(g&&j._accounts[g])return o=d(g)+c,i=I.call(k),i.unshift(o),e(i);if(!(j._accounts_length>0))return i=I.call(k),i.unshift(c),e(i);for(a in j._accounts)H.call(j._accounts,a)&&(o=d(a)+c,i=I.call(k),i.unshift(o),m+=e(i));return m?1:0}},c.prototype.push=function(){for(var b=this,c=I.call(arguments),d=0;d=2&&"string"==typeof a[0]&&"string"==typeof a[1]?[{page:a[0],title:a[1]}]:a}]);var M=function(a){var b=this;if(b._downloadTracked)return!1;b._downloadTracked=!0,a?"string"==typeof a?a={extensions:a.split(",")}:a.length>=1&&(a={extensions:a}):a={extensions:[]},a.category=a.category||"Download";var c="xls,xlsx,doc,docx,ppt,pptx,pdf,txt,zip";return c+=",rar,7z,exe,wma,mov,avi,wmv,mp3,csv,tsv",c=c.split(","),a.extensions=a.extensions.concat(c),b._liveEvent("a","mousedown",function(){var c=this;if(c.href){var d=f.call(b,c.href,a.extensions);d&&_gas.push(["_trackEvent",a.category,d,c.href])}}),!1};_gas.push(["_addHook","_gasTrackDownloads",M]),_gas.push(["_addHook","_trackDownloads",M]),_gas.push(["_addHook","_gasMetaEcommerce",g]),_gas.push(["_addHook","_trackEvent",function(){var a=I.call(arguments);return a[3]&&(a[3]=Math.round(a[3])),a}]);var N=function(a){if(this._formTracked)return!1;this._formTracked=!0;var b=this;"object"!=typeof a&&(a={}),a.category=a.category||"Form Tracking";var c=function(b){var c=b.target,d=c.name||c.id||c.type||c.nodeName,e=h(c),f="form ("+e+")",g=d+" ("+b.type+")";_gas.push(["_trackEvent",a.category,f,g])};return b._DOMReady(function(){var a,d,e=["input","select","textarea","hidden"],f=["form"],g=[];for(a=0;a0;)_gas.push(_gas._queue.shift());"undefined"==typeof a._gat&&!function(){var a=G.getElementById("gas-script"),b=G.createElement("script");b.type="text/javascript",b.async=!0,b.src=null!==a&&"true"===a.getAttribute("data-use-dcjs")?("https:"===G.location.protocol?"https://":"http://")+"stats.g.doubleclick.net/dc.js":("https:"===G.location.protocol?"https://ssl":"http://www")+".google-analytics.com/ga.js";var c=G.getElementsByTagName("script")[0];c.parentNode.insertBefore(b,c)}()}}(window); \ No newline at end of file diff --git a/ajax/libs/gas/package.json b/ajax/libs/gas/package.json index 5a0a6276e..94f176775 100644 --- a/ajax/libs/gas/package.json +++ b/ajax/libs/gas/package.json @@ -3,7 +3,7 @@ "name": "gas", "filename": "gas.min.js", "description": "Google Analytics on Steroids, a Google Analytics implementation with extra features.", - "version": "1.10.1", + "version": "1.11.0", "homepage": "https://github.com/CardinalPath/gas", "keywords": [ "Google Analytics",