193 lines
6.3 KiB
JavaScript
193 lines
6.3 KiB
JavaScript
/*
|
|
* JavaScript tracker for Snowplow: queue.js
|
|
*
|
|
* Significant portions copyright 2010 Anthon Pang. Remainder copyright
|
|
* 2012-2014 Snowplow Analytics Ltd. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
|
|
* names of their contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
;(function() {
|
|
|
|
var
|
|
map = require('lodash/map'),
|
|
isUndefined = require('lodash/isUndefined'),
|
|
isFunction = require('lodash/isFunction'),
|
|
helpers = require('./lib/helpers'),
|
|
|
|
object = typeof exports !== 'undefined' ? exports : this; // For eventual node.js environment support
|
|
|
|
/************************************************************
|
|
* Proxy object
|
|
* - this allows the caller to continue push()'ing to _snaq
|
|
* after the Tracker has been initialized and loaded
|
|
************************************************************/
|
|
|
|
object.InQueueManager = function(TrackerConstructor, version, mutSnowplowState, asyncQueue, functionName) {
|
|
|
|
// Page view ID should be shared between all tracker instances
|
|
var trackerDictionary = {};
|
|
|
|
/**
|
|
* Get an array of trackers to which a function should be applied.
|
|
*
|
|
* @param array names List of namespaces to use. If empty, use all namespaces.
|
|
*/
|
|
function getNamedTrackers(names) {
|
|
var namedTrackers = [];
|
|
|
|
if (!names || names.length === 0) {
|
|
namedTrackers = map(trackerDictionary);
|
|
} else {
|
|
for (var i = 0; i < names.length; i++) {
|
|
if (trackerDictionary.hasOwnProperty(names[i])) {
|
|
namedTrackers.push(trackerDictionary[names[i]]);
|
|
} else {
|
|
helpers.warn('Warning: Tracker namespace "' + names[i] + '" not configured');
|
|
}
|
|
}
|
|
}
|
|
|
|
if (namedTrackers.length === 0) {
|
|
helpers.warn('Warning: No tracker configured');
|
|
}
|
|
|
|
return namedTrackers;
|
|
}
|
|
|
|
/**
|
|
* Legacy support for input of the form _snaq.push(['setCollectorCf', 'd34uzc5hjrimh8'])
|
|
*
|
|
* @param string f Either 'setCollectorCf' or 'setCollectorUrl'
|
|
* @param string endpoint
|
|
* @param string namespace Optional tracker name
|
|
*
|
|
* TODO: remove this in 2.1.0
|
|
*/
|
|
function legacyCreateNewNamespace(f, endpoint, namespace) {
|
|
helpers.warn(f + ' is deprecated. Set the collector when a new tracker instance using newTracker.');
|
|
|
|
var name;
|
|
|
|
if (isUndefined(namespace)) {
|
|
name = 'sp';
|
|
} else {
|
|
name = namespace;
|
|
}
|
|
|
|
createNewNamespace(name);
|
|
trackerDictionary[name][f](endpoint);
|
|
}
|
|
|
|
/**
|
|
* Initiate a new tracker namespace
|
|
*
|
|
* @param string namespace
|
|
* @param string endpoint Of the form d3rkrsqld9gmqf.cloudfront.net
|
|
*/
|
|
function createNewNamespace(namespace, endpoint, argmap) {
|
|
argmap = argmap || {};
|
|
|
|
if (!trackerDictionary.hasOwnProperty(namespace)) {
|
|
trackerDictionary[namespace] = new TrackerConstructor(functionName, namespace, version, mutSnowplowState, argmap);
|
|
trackerDictionary[namespace].setCollectorUrl(endpoint);
|
|
} else {
|
|
helpers.warn('Tracker namespace ' + namespace + ' already exists.');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Output an array of the form ['functionName', [trackerName1, trackerName2, ...]]
|
|
*
|
|
* @param string inputString
|
|
*/
|
|
function parseInputString(inputString) {
|
|
var separatedString = inputString.split(':'),
|
|
extractedFunction = separatedString[0],
|
|
extractedNames = (separatedString.length > 1) ? separatedString[1].split(';') : [];
|
|
|
|
return [extractedFunction, extractedNames];
|
|
}
|
|
|
|
/**
|
|
* apply wrapper
|
|
*
|
|
* @param array parameterArray An array comprising either:
|
|
* [ 'methodName', optional_parameters ]
|
|
* or:
|
|
* [ functionObject, optional_parameters ]
|
|
*/
|
|
function applyAsyncFunction() {
|
|
var i, j, f, parameterArray, input, parsedString, names, namedTrackers;
|
|
|
|
// Outer loop in case someone push'es in zarg of arrays
|
|
for (i = 0; i < arguments.length; i += 1) {
|
|
parameterArray = arguments[i];
|
|
|
|
// Arguments is not an array, so we turn it into one
|
|
input = Array.prototype.shift.call(parameterArray);
|
|
|
|
// Custom callback rather than tracker method, called with trackerDictionary as the context
|
|
if (isFunction(input)) {
|
|
input.apply(trackerDictionary, parameterArray);
|
|
continue;
|
|
}
|
|
|
|
parsedString = parseInputString(input);
|
|
f = parsedString[0];
|
|
names = parsedString[1];
|
|
|
|
if (f === 'newTracker') {
|
|
createNewNamespace(parameterArray[0], parameterArray[1], parameterArray[2]);
|
|
continue;
|
|
}
|
|
|
|
if ((f === 'setCollectorCf' || f === 'setCollectorUrl') && (!names || names.length === 0)) {
|
|
legacyCreateNewNamespace(f, parameterArray[0], parameterArray[1]);
|
|
continue;
|
|
}
|
|
|
|
namedTrackers = getNamedTrackers(names);
|
|
|
|
for (j = 0; j < namedTrackers.length; j++) {
|
|
namedTrackers[j][f].apply(namedTrackers[j], parameterArray);
|
|
}
|
|
}
|
|
}
|
|
|
|
// We need to manually apply any events collected before this initialization
|
|
for (var i = 0; i < asyncQueue.length; i++) {
|
|
applyAsyncFunction(asyncQueue[i]);
|
|
}
|
|
|
|
return {
|
|
push: applyAsyncFunction
|
|
};
|
|
};
|
|
|
|
}());
|