Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
7f6ad0dd3c
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
19624 lines (16069 sloc) 418 KB
(function umd(require){
if ('object' == typeof exports) {
module.exports = require('1');
} else if ('function' == typeof define && define.amd) {
define(function(){ return require('1'); });
} else {
this['analytics'] = require('1');
}
})((function outer(modules, cache, entries){
/**
* Global
*/
var global = (function(){ return this; })();
/**
* Require `name`.
*
* @param {String} name
* @param {Boolean} jumped
* @api public
*/
function require(name, jumped){
if (cache[name]) return cache[name].exports;
if (modules[name]) return call(name, require);
throw new Error('cannot find module "' + name + '"');
}
/**
* Call module `id` and cache it.
*
* @param {Number} id
* @param {Function} require
* @return {Function}
* @api private
*/
function call(id, require){
var m = cache[id] = { exports: {} };
var mod = modules[id];
var name = mod[2];
var fn = mod[0];
fn.call(m.exports, function(req){
var dep = modules[id][1][req];
return require(dep ? dep : req);
}, m, m.exports, outer, modules, cache, entries);
// expose as `name`.
if (name) cache[name] = cache[id];
return cache[id].exports;
}
/**
* Require all entries exposing them on global if needed.
*/
for (var id in entries) {
if (entries[id]) {
global[entries[id]] = require(id);
} else {
require(id);
}
}
/**
* Duo flag.
*/
require.duo = true;
/**
* Expose cache.
*/
require.cache = cache;
/**
* Expose modules
*/
require.modules = modules;
/**
* Return newest require.
*/
return require;
})({
1: [function(require, module, exports) {
/**
* Analytics.js
*
* (C) 2013 Segment.io Inc.
*/
var _analytics = window.analytics;
var Integrations = require('analytics.js-integrations');
var Analytics = require('./analytics');
var each = require('each');
/**
* Expose the `analytics` singleton.
*/
var analytics = module.exports = exports = new Analytics();
/**
* Expose require
*/
analytics.require = require;
/**
* Expose `VERSION`.
*/
exports.VERSION = require('../bower.json').version;
/**
* Add integrations.
*/
each(Integrations, function (name, Integration) {
analytics.use(Integration);
});
}, {"analytics.js-integrations":2,"./analytics":3,"each":4,"../bower.json":5}],
2: [function(require, module, exports) {
/**
* Module dependencies.
*/
var each = require('each');
var plugins = require('./integrations.js');
/**
* Expose the integrations, using their own `name` from their `prototype`.
*/
each(plugins, function(plugin){
var name = (plugin.Integration || plugin).prototype.name;
exports[name] = plugin;
});
}, {"each":4,"./integrations.js":6}],
4: [function(require, module, exports) {
/**
* Module dependencies.
*/
var type = require('type');
/**
* HOP reference.
*/
var has = Object.prototype.hasOwnProperty;
/**
* Iterate the given `obj` and invoke `fn(val, i)`.
*
* @param {String|Array|Object} obj
* @param {Function} fn
* @api public
*/
module.exports = function(obj, fn){
switch (type(obj)) {
case 'array':
return array(obj, fn);
case 'object':
if ('number' == typeof obj.length) return array(obj, fn);
return object(obj, fn);
case 'string':
return string(obj, fn);
}
};
/**
* Iterate string chars.
*
* @param {String} obj
* @param {Function} fn
* @api private
*/
function string(obj, fn) {
for (var i = 0; i < obj.length; ++i) {
fn(obj.charAt(i), i);
}
}
/**
* Iterate object keys.
*
* @param {Object} obj
* @param {Function} fn
* @api private
*/
function object(obj, fn) {
for (var key in obj) {
if (has.call(obj, key)) {
fn(key, obj[key]);
}
}
}
/**
* Iterate array-ish.
*
* @param {Array|Object} obj
* @param {Function} fn
* @api private
*/
function array(obj, fn) {
for (var i = 0; i < obj.length; ++i) {
fn(obj[i], i);
}
}
}, {"type":7}],
7: [function(require, module, exports) {
/**
* toString ref.
*/
var toString = Object.prototype.toString;
/**
* Return the type of `val`.
*
* @param {Mixed} val
* @return {String}
* @api public
*/
module.exports = function(val){
switch (toString.call(val)) {
case '[object Date]': return 'date';
case '[object RegExp]': return 'regexp';
case '[object Arguments]': return 'arguments';
case '[object Array]': return 'array';
case '[object Error]': return 'error';
}
if (val === null) return 'null';
if (val === undefined) return 'undefined';
if (val !== val) return 'nan';
if (val && val.nodeType === 1) return 'element';
val = val.valueOf
? val.valueOf()
: Object.prototype.valueOf.apply(val)
return typeof val;
};
}, {}],
6: [function(require, module, exports) {
/**
* DON'T EDIT THIS FILE. It's automatically generated!
*/
module.exports = [
require('./lib/adroll'),
require('./lib/adwords'),
require('./lib/alexa'),
require('./lib/amplitude'),
require('./lib/appcues'),
require('./lib/atatus'),
require('./lib/autosend'),
require('./lib/awesm'),
require('./lib/bing-ads'),
require('./lib/blueshift'),
require('./lib/bronto'),
require('./lib/bugherd'),
require('./lib/bugsnag'),
require('./lib/chameleon'),
require('./lib/chartbeat'),
require('./lib/clicktale'),
require('./lib/clicky'),
require('./lib/comscore'),
require('./lib/crazy-egg'),
require('./lib/curebit'),
require('./lib/customerio'),
require('./lib/drip'),
require('./lib/errorception'),
require('./lib/evergage'),
require('./lib/extole'),
require('./lib/facebook-conversion-tracking'),
require('./lib/foxmetrics'),
require('./lib/frontleaf'),
require('./lib/fullstory'),
require('./lib/gauges'),
require('./lib/get-satisfaction'),
require('./lib/google-analytics'),
require('./lib/google-tag-manager'),
require('./lib/gosquared'),
require('./lib/heap'),
require('./lib/hellobar'),
require('./lib/hittail'),
require('./lib/hubspot'),
require('./lib/improvely'),
require('./lib/insidevault'),
require('./lib/inspectlet'),
require('./lib/intercom'),
require('./lib/keen-io'),
require('./lib/kenshoo'),
require('./lib/kissmetrics'),
require('./lib/klaviyo'),
require('./lib/livechat'),
require('./lib/lucky-orange'),
require('./lib/lytics'),
require('./lib/mixpanel'),
require('./lib/mojn'),
require('./lib/mouseflow'),
require('./lib/mousestats'),
require('./lib/navilytics'),
require('./lib/nudgespot'),
require('./lib/olark'),
require('./lib/optimizely'),
require('./lib/outbound'),
require('./lib/perfect-audience'),
require('./lib/pingdom'),
require('./lib/piwik'),
require('./lib/preact'),
require('./lib/qualaroo'),
require('./lib/quantcast'),
require('./lib/rollbar'),
require('./lib/saasquatch'),
require('./lib/satismeter'),
require('./lib/segmentio'),
require('./lib/sentry'),
require('./lib/snapengage'),
require('./lib/spinnakr'),
require('./lib/supporthero'),
require('./lib/tapstream'),
require('./lib/trakio'),
require('./lib/twitter-ads'),
require('./lib/userlike'),
require('./lib/uservoice'),
require('./lib/vero'),
require('./lib/visual-website-optimizer'),
require('./lib/webengage'),
require('./lib/woopra'),
require('./lib/yandex-metrica')
];
}, {"./lib/adroll":8,"./lib/adwords":9,"./lib/alexa":10,"./lib/amplitude":11,"./lib/appcues":12,"./lib/atatus":13,"./lib/autosend":14,"./lib/awesm":15,"./lib/bing-ads":16,"./lib/blueshift":17,"./lib/bronto":18,"./lib/bugherd":19,"./lib/bugsnag":20,"./lib/chameleon":21,"./lib/chartbeat":22,"./lib/clicktale":23,"./lib/clicky":24,"./lib/comscore":25,"./lib/crazy-egg":26,"./lib/curebit":27,"./lib/customerio":28,"./lib/drip":29,"./lib/errorception":30,"./lib/evergage":31,"./lib/extole":32,"./lib/facebook-conversion-tracking":33,"./lib/foxmetrics":34,"./lib/frontleaf":35,"./lib/fullstory":36,"./lib/gauges":37,"./lib/get-satisfaction":38,"./lib/google-analytics":39,"./lib/google-tag-manager":40,"./lib/gosquared":41,"./lib/heap":42,"./lib/hellobar":43,"./lib/hittail":44,"./lib/hubspot":45,"./lib/improvely":46,"./lib/insidevault":47,"./lib/inspectlet":48,"./lib/intercom":49,"./lib/keen-io":50,"./lib/kenshoo":51,"./lib/kissmetrics":52,"./lib/klaviyo":53,"./lib/livechat":54,"./lib/lucky-orange":55,"./lib/lytics":56,"./lib/mixpanel":57,"./lib/mojn":58,"./lib/mouseflow":59,"./lib/mousestats":60,"./lib/navilytics":61,"./lib/nudgespot":62,"./lib/olark":63,"./lib/optimizely":64,"./lib/outbound":65,"./lib/perfect-audience":66,"./lib/pingdom":67,"./lib/piwik":68,"./lib/preact":69,"./lib/qualaroo":70,"./lib/quantcast":71,"./lib/rollbar":72,"./lib/saasquatch":73,"./lib/satismeter":74,"./lib/segmentio":75,"./lib/sentry":76,"./lib/snapengage":77,"./lib/spinnakr":78,"./lib/supporthero":79,"./lib/tapstream":80,"./lib/trakio":81,"./lib/twitter-ads":82,"./lib/userlike":83,"./lib/uservoice":84,"./lib/vero":85,"./lib/visual-website-optimizer":86,"./lib/webengage":87,"./lib/woopra":88,"./lib/yandex-metrica":89}],
8: [function(require, module, exports) {
/**
* Module dependencies.
*/
var integration = require('analytics.js-integration');
var snake = require('to-snake-case');
var useHttps = require('use-https');
var each = require('each');
var is = require('is');
var del = require('obj-case').del;
/**
* HOP
*/
var has = Object.prototype.hasOwnProperty;
/**
* Expose `AdRoll` integration.
*/
var AdRoll = module.exports = integration('AdRoll')
.assumesPageview()
.global('__adroll_loaded')
.global('adroll_adv_id')
.global('adroll_pix_id')
.global('adroll_custom_data')
.option('advId', '')
.option('pixId', '')
.tag('http', '<script src="http://a.adroll.com/j/roundtrip.js">')
.tag('https', '<script src="https://s.adroll.com/j/roundtrip.js">')
.mapping('events');
/**
* Initialize.
*
* http://support.adroll.com/getting-started-in-4-easy-steps/#step-one
* http://support.adroll.com/enhanced-conversion-tracking/
*
* @param {Object} page
*/
AdRoll.prototype.initialize = function(page){
window.adroll_adv_id = this.options.advId;
window.adroll_pix_id = this.options.pixId;
window.__adroll_loaded = true;
var name = useHttps() ? 'https' : 'http';
this.load(name, this.ready);
};
/**
* Loaded?
*
* @return {Boolean}
*/
AdRoll.prototype.loaded = function(){
return window.__adroll;
};
/**
* Page.
*
* http://support.adroll.com/segmenting-clicks/
*
* @param {Page} page
*/
AdRoll.prototype.page = function(page){
var name = page.fullName();
this.track(page.track(name));
};
/**
* Track.
*
* @param {Track} track
*/
AdRoll.prototype.track = function(track){
var event = track.event();
var user = this.analytics.user();
var events = this.events(event);
var total = track.revenue() || track.total() || 0;
var orderId = track.orderId() || 0;
var productId = track.id();
var sku = track.sku();
var customProps = track.properties();
var data = {};
if (user.id()) data.user_id = user.id();
if (orderId) data.order_id = orderId;
if (productId) data.product_id = productId;
if (sku) data.sku = sku;
if (total) data.adroll_conversion_value_in_dollars = total;
del(customProps, "revenue");
del(customProps, "total");
del(customProps, "orderId");
del(customProps, "id");
del(customProps, "sku");
if (!is.empty(customProps)) data.adroll_custom_data = customProps;
each(events, function(event){
// the adroll interface only allows for
// segment names which are snake cased.
data.adroll_segments = snake(event);
window.__adroll.record_user(data);
});
// no events found
if (!events.length) {
data.adroll_segments = snake(event);
window.__adroll.record_user(data);
}
};
}, {"analytics.js-integration":90,"to-snake-case":91,"use-https":92,"each":4,"is":93,"obj-case":94}],
90: [function(require, module, exports) {
/**
* Module dependencies.
*/
var bind = require('bind');
var callback = require('callback');
var clone = require('clone');
var debug = require('debug');
var defaults = require('defaults');
var protos = require('./protos');
var slug = require('slug');
var statics = require('./statics');
/**
* Expose `createIntegration`.
*/
module.exports = createIntegration;
/**
* Create a new `Integration` constructor.
*
* @param {String} name
* @return {Function} Integration
*/
function createIntegration(name){
/**
* Initialize a new `Integration`.
*
* @param {Object} options
*/
function Integration(options){
if (options && options.addIntegration) {
// plugin
return options.addIntegration(Integration);
}
this.debug = debug('analytics:integration:' + slug(name));
this.options = defaults(clone(options) || {}, this.defaults);
this._queue = [];
this.once('ready', bind(this, this.flush));
Integration.emit('construct', this);
this.ready = bind(this, this.ready);
this._wrapInitialize();
this._wrapPage();
this._wrapTrack();
}
Integration.prototype.defaults = {};
Integration.prototype.globals = [];
Integration.prototype.templates = {};
Integration.prototype.name = name;
for (var key in statics) Integration[key] = statics[key];
for (var key in protos) Integration.prototype[key] = protos[key];
return Integration;
}
}, {"bind":95,"callback":96,"clone":97,"debug":98,"defaults":99,"./protos":100,"slug":101,"./statics":102}],
95: [function(require, module, exports) {
var bind = require('bind')
, bindAll = require('bind-all');
/**
* Expose `bind`.
*/
module.exports = exports = bind;
/**
* Expose `bindAll`.
*/
exports.all = bindAll;
/**
* Expose `bindMethods`.
*/
exports.methods = bindMethods;
/**
* Bind `methods` on `obj` to always be called with the `obj` as context.
*
* @param {Object} obj
* @param {String} methods...
*/
function bindMethods (obj, methods) {
methods = [].slice.call(arguments, 1);
for (var i = 0, method; method = methods[i]; i++) {
obj[method] = bind(obj, obj[method]);
}
return obj;
}
}, {"bind":103,"bind-all":104}],
103: [function(require, module, exports) {
/**
* Slice reference.
*/
var slice = [].slice;
/**
* Bind `obj` to `fn`.
*
* @param {Object} obj
* @param {Function|String} fn or string
* @return {Function}
* @api public
*/
module.exports = function(obj, fn){
if ('string' == typeof fn) fn = obj[fn];
if ('function' != typeof fn) throw new Error('bind() requires a function');
var args = slice.call(arguments, 2);
return function(){
return fn.apply(obj, args.concat(slice.call(arguments)));
}
};
}, {}],
104: [function(require, module, exports) {
try {
var bind = require('bind');
var type = require('type');
} catch (e) {
var bind = require('bind-component');
var type = require('type-component');
}
module.exports = function (obj) {
for (var key in obj) {
var val = obj[key];
if (type(val) === 'function') obj[key] = bind(obj, obj[key]);
}
return obj;
};
}, {"bind":103,"type":7}],
96: [function(require, module, exports) {
var next = require('next-tick');
/**
* Expose `callback`.
*/
module.exports = callback;
/**
* Call an `fn` back synchronously if it exists.
*
* @param {Function} fn
*/
function callback (fn) {
if ('function' === typeof fn) fn();
}
/**
* Call an `fn` back asynchronously if it exists. If `wait` is ommitted, the
* `fn` will be called on next tick.
*
* @param {Function} fn
* @param {Number} wait (optional)
*/
callback.async = function (fn, wait) {
if ('function' !== typeof fn) return;
if (!wait) return next(fn);
setTimeout(fn, wait);
};
/**
* Symmetry.
*/
callback.sync = callback;
}, {"next-tick":105}],
105: [function(require, module, exports) {
"use strict"
if (typeof setImmediate == 'function') {
module.exports = function(f){ setImmediate(f) }
}
// legacy node.js
else if (typeof process != 'undefined' && typeof process.nextTick == 'function') {
module.exports = process.nextTick
}
// fallback for other environments / postMessage behaves badly on IE8
else if (typeof window == 'undefined' || window.ActiveXObject || !window.postMessage) {
module.exports = function(f){ setTimeout(f) };
} else {
var q = [];
window.addEventListener('message', function(){
var i = 0;
while (i < q.length) {
try { q[i++](); }
catch (e) {
q = q.slice(i);
window.postMessage('tic!', '*');
throw e;
}
}
q.length = 0;
}, true);
module.exports = function(fn){
if (!q.length) window.postMessage('tic!', '*');
q.push(fn);
}
}
}, {}],
97: [function(require, module, exports) {
/**
* Module dependencies.
*/
var type;
try {
type = require('type');
} catch(e){
type = require('type-component');
}
/**
* Module exports.
*/
module.exports = clone;
/**
* Clones objects.
*
* @param {Mixed} any object
* @api public
*/
function clone(obj){
switch (type(obj)) {
case 'object':
var copy = {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = clone(obj[key]);
}
}
return copy;
case 'array':
var copy = new Array(obj.length);
for (var i = 0, l = obj.length; i < l; i++) {
copy[i] = clone(obj[i]);
}
return copy;
case 'regexp':
// from millermedeiros/amd-utils - MIT
var flags = '';
flags += obj.multiline ? 'm' : '';
flags += obj.global ? 'g' : '';
flags += obj.ignoreCase ? 'i' : '';
return new RegExp(obj.source, flags);
case 'date':
return new Date(obj.getTime());
default: // string, number, boolean, …
return obj;
}
}
}, {"type":7}],
98: [function(require, module, exports) {
if ('undefined' == typeof window) {
module.exports = require('./lib/debug');
} else {
module.exports = require('./debug');
}
}, {"./lib/debug":106,"./debug":107}],
106: [function(require, module, exports) {
/**
* Module dependencies.
*/
var tty = require('tty');
/**
* Expose `debug()` as the module.
*/
module.exports = debug;
/**
* Enabled debuggers.
*/
var names = []
, skips = [];
(process.env.DEBUG || '')
.split(/[\s,]+/)
.forEach(function(name){
name = name.replace('*', '.*?');
if (name[0] === '-') {
skips.push(new RegExp('^' + name.substr(1) + '$'));
} else {
names.push(new RegExp('^' + name + '$'));
}
});
/**
* Colors.
*/
var colors = [6, 2, 3, 4, 5, 1];
/**
* Previous debug() call.
*/
var prev = {};
/**
* Previously assigned color.
*/
var prevColor = 0;
/**
* Is stdout a TTY? Colored output is disabled when `true`.
*/
var isatty = tty.isatty(2);
/**
* Select a color.
*
* @return {Number}
* @api private
*/
function color() {
return colors[prevColor++ % colors.length];
}
/**
* Humanize the given `ms`.
*
* @param {Number} m
* @return {String}
* @api private
*/
function humanize(ms) {
var sec = 1000
, min = 60 * 1000
, hour = 60 * min;
if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
if (ms >= min) return (ms / min).toFixed(1) + 'm';
if (ms >= sec) return (ms / sec | 0) + 's';
return ms + 'ms';
}
/**
* Create a debugger with the given `name`.
*
* @param {String} name
* @return {Type}
* @api public
*/
function debug(name) {
function disabled(){}
disabled.enabled = false;
var match = skips.some(function(re){
return re.test(name);
});
if (match) return disabled;
match = names.some(function(re){
return re.test(name);
});
if (!match) return disabled;
var c = color();
function colored(fmt) {
fmt = coerce(fmt);
var curr = new Date;
var ms = curr - (prev[name] || curr);
prev[name] = curr;
fmt = ' \u001b[9' + c + 'm' + name + ' '
+ '\u001b[3' + c + 'm\u001b[90m'
+ fmt + '\u001b[3' + c + 'm'
+ ' +' + humanize(ms) + '\u001b[0m';
console.error.apply(this, arguments);
}
function plain(fmt) {
fmt = coerce(fmt);
fmt = new Date().toUTCString()
+ ' ' + name + ' ' + fmt;
console.error.apply(this, arguments);
}
colored.enabled = plain.enabled = true;
return isatty || process.env.DEBUG_COLORS
? colored
: plain;
}
/**
* Coerce `val`.
*/
function coerce(val) {
if (val instanceof Error) return val.stack || val.message;
return val;
}
}, {}],
107: [function(require, module, exports) {
/**
* Expose `debug()` as the module.
*/
module.exports = debug;
/**
* Create a debugger with the given `name`.
*
* @param {String} name
* @return {Type}
* @api public
*/
function debug(name) {
if (!debug.enabled(name)) return function(){};
return function(fmt){
fmt = coerce(fmt);
var curr = new Date;
var ms = curr - (debug[name] || curr);
debug[name] = curr;
fmt = name
+ ' '
+ fmt
+ ' +' + debug.humanize(ms);
// This hackery is required for IE8
// where `console.log` doesn't have 'apply'
window.console
&& console.log
&& Function.prototype.apply.call(console.log, console, arguments);
}
}
/**
* The currently active debug mode names.
*/
debug.names = [];
debug.skips = [];
/**
* Enables a debug mode by name. This can include modes
* separated by a colon and wildcards.
*
* @param {String} name
* @api public
*/
debug.enable = function(name) {
try {
localStorage.debug = name;
} catch(e){}
var split = (name || '').split(/[\s,]+/)
, len = split.length;
for (var i = 0; i < len; i++) {
name = split[i].replace('*', '.*?');
if (name[0] === '-') {
debug.skips.push(new RegExp('^' + name.substr(1) + '$'));
}
else {
debug.names.push(new RegExp('^' + name + '$'));
}
}
};
/**
* Disable debug output.
*
* @api public
*/
debug.disable = function(){
debug.enable('');
};
/**
* Humanize the given `ms`.
*
* @param {Number} m
* @return {String}
* @api private
*/
debug.humanize = function(ms) {
var sec = 1000
, min = 60 * 1000
, hour = 60 * min;
if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
if (ms >= min) return (ms / min).toFixed(1) + 'm';
if (ms >= sec) return (ms / sec | 0) + 's';
return ms + 'ms';
};
/**
* Returns true if the given mode name is enabled, false otherwise.
*
* @param {String} name
* @return {Boolean}
* @api public
*/
debug.enabled = function(name) {
for (var i = 0, len = debug.skips.length; i < len; i++) {
if (debug.skips[i].test(name)) {
return false;
}
}
for (var i = 0, len = debug.names.length; i < len; i++) {
if (debug.names[i].test(name)) {
return true;
}
}
return false;
};
/**
* Coerce `val`.
*/
function coerce(val) {
if (val instanceof Error) return val.stack || val.message;
return val;
}
// persist
try {
if (window.localStorage) debug.enable(localStorage.debug);
} catch(e){}
}, {}],
99: [function(require, module, exports) {
'use strict';
/**
* Merge default values.
*
* @param {Object} dest
* @param {Object} defaults
* @return {Object}
* @api public
*/
var defaults = function (dest, src, recursive) {
for (var prop in src) {
if (recursive && dest[prop] instanceof Object && src[prop] instanceof Object) {
dest[prop] = defaults(dest[prop], src[prop], true);
} else if (! (prop in dest)) {
dest[prop] = src[prop];
}
}
return dest;
};
/**
* Expose `defaults`.
*/
module.exports = defaults;
}, {}],
100: [function(require, module, exports) {
/**
* Module dependencies.
*/
var loadScript = require('load-script');
var loadIframe = require('load-iframe');
var events = require('analytics-events');
var normalize = require('to-no-case');
var callback = require('callback');
var Emitter = require('emitter');
var tick = require('next-tick');
var after = require('after');
var each = require('each');
var type = require('type');
var fmt = require('fmt');
/**
* Noop.
*/
function noop(){}
/**
* Window defaults.
*/
var setTimeout = window.setTimeout;
var setInterval = window.setInterval;
var onerror = window.onerror;
var onload = null;
/**
* Mixin emitter.
*/
Emitter(exports);
/**
* Initialize.
*/
exports.initialize = function(){
var ready = this.ready;
tick(ready);
};
/**
* Loaded?
*
* @return {Boolean}
* @api private
*/
exports.loaded = function(){
return false;
};
/**
* Page.
*
* @param {Page} page
*/
exports.page = function(page){};
/**
* Track.
*
* @param {Track} track
*/
exports.track = function(track){};
/**
* Get events that match `str`.
*
* Examples:
*
* events = { my_event: 'a4991b88' }
* .map(events, 'My Event');
* // => ["a4991b88"]
* .map(events, 'whatever');
* // => []
*
* events = [{ key: 'my event', value: '9b5eb1fa' }]
* .map(events, 'my_event');
* // => ["9b5eb1fa"]
* .map(events, 'whatever');
* // => []
*
* @param {String} str
* @return {Array}
* @api public
*/
exports.map = function(obj, str){
var a = normalize(str);
var ret = [];
// noop
if (!obj) return ret;
// object
if ('object' == type(obj)) {
for (var k in obj) {
var item = obj[k];
var b = normalize(k);
if (b == a) ret.push(item);
}
}
// array
if ('array' == type(obj)) {
if (!obj.length) return ret;
if (!obj[0].key) return ret;
for (var i = 0; i < obj.length; ++i) {
var item = obj[i];
var b = normalize(item.key);
if (b == a) ret.push(item.value);
}
}
return ret;
};
/**
* Invoke a `method` that may or may not exist on the prototype with `args`,
* queueing or not depending on whether the integration is "ready". Don't
* trust the method call, since it contains integration party code.
*
* @param {String} method
* @param {Mixed} args...
* @api private
*/
exports.invoke = function(method){
if (!this[method]) return;
var args = [].slice.call(arguments, 1);
if (!this._ready) return this.queue(method, args);
var ret;
try {
this.debug('%s with %o', method, args);
ret = this[method].apply(this, args);
} catch (e) {
this.debug('error %o calling %s with %o', e, method, args);
}
return ret;
};
/**
* Queue a `method` with `args`. If the integration assumes an initial
* pageview, then let the first call to `page` pass through.
*
* @param {String} method
* @param {Array} args
* @api private
*/
exports.queue = function(method, args){
if ('page' == method && this._assumesPageview && !this._initialized) {
return this.page.apply(this, args);
}
this._queue.push({ method: method, args: args });
};
/**
* Flush the internal queue.
*
* @api private
*/
exports.flush = function(){
this._ready = true;
var call;
while (call = this._queue.shift()) this[call.method].apply(this, call.args);
};
/**
* Reset the integration, removing its global variables.
*
* @api private
*/
exports.reset = function(){
for (var i = 0, key; key = this.globals[i]; i++) window[key] = undefined;
window.setTimeout = setTimeout;
window.setInterval = setInterval;
window.onerror = onerror;
window.onload = onload;
};
/**
* Load a tag by `name`.
*
* @param {String} name
* @param {Function} [fn]
*/
exports.load = function(name, locals, fn){
if ('function' == typeof name) fn = name, locals = null, name = null;
if (name && 'object' == typeof name) fn = locals, locals = name, name = null;
if ('function' == typeof locals) fn = locals, locals = null;
name = name || 'library';
locals = locals || {};
locals = this.locals(locals);
var template = this.templates[name];
if (!template) throw new Error(fmt('template "%s" not defined.', name));
var attrs = render(template, locals);
var fn = fn || noop;
var self = this;
var el;
switch (template.type) {
case 'img':
attrs.width = 1;
attrs.height = 1;
el = loadImage(attrs, fn);
break;
case 'script':
el = loadScript(attrs, function(err){
if (!err) return fn();
self.debug('error loading "%s" error="%s"', self.name, err);
});
// TODO: hack until refactoring load-script
delete attrs.src;
each(attrs, function(key, val){
el.setAttribute(key, val);
});
break;
case 'iframe':
el = loadIframe(attrs, fn);
break;
}
return el;
};
/**
* Locals for tag templates.
*
* By default it includes a cache buster,
* and all of the options.
*
* @param {Object} [locals]
* @return {Object}
*/
exports.locals = function(locals){
locals = locals || {};
var cache = Math.floor(new Date().getTime() / 3600000);
if (!locals.hasOwnProperty('cache')) locals.cache = cache;
each(this.options, function(key, val){
if (!locals.hasOwnProperty(key)) locals[key] = val;
});
return locals;
};
/**
* Simple way to emit ready.
*/
exports.ready = function(){
this.emit('ready');
};
/**
* Wrap the initialize method in an exists check, so we don't have to do it for
* every single integration.
*
* @api private
*/
exports._wrapInitialize = function(){
var initialize = this.initialize;
this.initialize = function(){
this.debug('initialize');
this._initialized = true;
var ret = initialize.apply(this, arguments);
this.emit('initialize');
return ret;
};
if (this._assumesPageview) this.initialize = after(2, this.initialize);
};
/**
* Wrap the page method to call `initialize` instead if the integration assumes
* a pageview.
*
* @api private
*/
exports._wrapPage = function(){
var page = this.page;
this.page = function(){
if (this._assumesPageview && !this._initialized) {
return this.initialize.apply(this, arguments);
}
return page.apply(this, arguments);
};
};
/**
* Wrap the track method to call other ecommerce methods if
* available depending on the `track.event()`.
*
* @api private
*/
exports._wrapTrack = function(){
var t = this.track;
this.track = function(track){
var event = track.event();
var called;
var ret;
for (var method in events) {
var regexp = events[method];
if (!this[method]) continue;
if (!regexp.test(event)) continue;
ret = this[method].apply(this, arguments);
called = true;
break;
}
if (!called) ret = t.apply(this, arguments);
return ret;
};
};
function loadImage(attrs, fn) {
fn = fn || function(){};
var img = new Image;
img.onerror = error(fn, 'failed to load pixel', img);
img.onload = function(){ fn(); };
img.src = attrs.src;
img.width = 1;
img.height = 1;
return img;
}
function error(fn, message, img){
return function(e){
e = e || window.event;
var err = new Error(message);
err.event = e;
err.source = img;
fn(err);
};
}
/**
* Render template + locals into an `attrs` object.
*
* @param {Object} template
* @param {Object} locals
* @return {Object}
*/
function render(template, locals) {
var attrs = {};
each(template.attrs, function(key, val){
attrs[key] = val.replace(/\{\{\ *(\w+)\ *\}\}/g, function(_, $1){
return locals[$1];
});
});
return attrs;
}
}, {"load-script":108,"load-iframe":109,"analytics-events":110,"to-no-case":111,"callback":96,"emitter":112,"next-tick":105,"after":113,"each":114,"type":115,"fmt":116}],
108: [function(require, module, exports) {
/**
* Module dependencies.
*/
var onload = require('script-onload');
var tick = require('next-tick');
var type = require('type');
/**
* Expose `loadScript`.
*
* @param {Object} options
* @param {Function} fn
* @api public
*/
module.exports = function loadScript(options, fn){
if (!options) throw new Error('Cant load nothing...');
// Allow for the simplest case, just passing a `src` string.
if ('string' == type(options)) options = { src : options };
var https = document.location.protocol === 'https:' ||
document.location.protocol === 'chrome-extension:';
// If you use protocol relative URLs, third-party scripts like Google
// Analytics break when testing with `file:` so this fixes that.
if (options.src && options.src.indexOf('//') === 0) {
options.src = https ? 'https:' + options.src : 'http:' + options.src;
}
// Allow them to pass in different URLs depending on the protocol.
if (https && options.https) options.src = options.https;
else if (!https && options.http) options.src = options.http;
// Make the `<script>` element and insert it before the first script on the
// page, which is guaranteed to exist since this Javascript is running.
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = options.src;
// If we have a fn, attach event handlers, even in IE. Based off of
// the Third-Party Javascript script loading example:
// https://github.com/thirdpartyjs/thirdpartyjs-code/blob/master/examples/templates/02/loading-files/index.php
if ('function' == type(fn)) {
onload(script, fn);
}
tick(function(){
// Append after event listeners are attached for IE.
var firstScript = document.getElementsByTagName('script')[0];
firstScript.parentNode.insertBefore(script, firstScript);
});
// Return the script element in case they want to do anything special, like
// give it an ID or attributes.
return script;
};
}, {"script-onload":117,"next-tick":105,"type":7}],
117: [function(require, module, exports) {
// https://github.com/thirdpartyjs/thirdpartyjs-code/blob/master/examples/templates/02/loading-files/index.php
/**
* Invoke `fn(err)` when the given `el` script loads.
*
* @param {Element} el
* @param {Function} fn
* @api public
*/
module.exports = function(el, fn){
return el.addEventListener
? add(el, fn)
: attach(el, fn);
};
/**
* Add event listener to `el`, `fn()`.
*
* @param {Element} el
* @param {Function} fn
* @api private
*/
function add(el, fn){
el.addEventListener('load', function(_, e){ fn(null, e); }, false);
el.addEventListener('error', function(e){
var err = new Error('script error "' + el.src + '"');
err.event = e;
fn(err);
}, false);
}
/**
* Attach event.
*
* @param {Element} el
* @param {Function} fn
* @api private
*/
function attach(el, fn){
el.attachEvent('onreadystatechange', function(e){
if (!/complete|loaded/.test(el.readyState)) return;
fn(null, e);
});
el.attachEvent('onerror', function(e){
var err = new Error('failed to load the script "' + el.src + '"');
err.event = e || window.event;
fn(err);
});
}
}, {}],
109: [function(require, module, exports) {
/**
* Module dependencies.
*/
var onload = require('script-onload');
var tick = require('next-tick');
var type = require('type');
/**
* Expose `loadScript`.
*
* @param {Object} options
* @param {Function} fn
* @api public
*/
module.exports = function loadIframe(options, fn){
if (!options) throw new Error('Cant load nothing...');
// Allow for the simplest case, just passing a `src` string.
if ('string' == type(options)) options = { src : options };
var https = document.location.protocol === 'https:' ||
document.location.protocol === 'chrome-extension:';
// If you use protocol relative URLs, third-party scripts like Google
// Analytics break when testing with `file:` so this fixes that.
if (options.src && options.src.indexOf('//') === 0) {
options.src = https ? 'https:' + options.src : 'http:' + options.src;
}
// Allow them to pass in different URLs depending on the protocol.
if (https && options.https) options.src = options.https;
else if (!https && options.http) options.src = options.http;
// Make the `<iframe>` element and insert it before the first iframe on the
// page, which is guaranteed to exist since this Javaiframe is running.
var iframe = document.createElement('iframe');
iframe.src = options.src;
iframe.width = options.width || 1;
iframe.height = options.height || 1;
iframe.style.display = 'none';
// If we have a fn, attach event handlers, even in IE. Based off of
// the Third-Party Javascript script loading example:
// https://github.com/thirdpartyjs/thirdpartyjs-code/blob/master/examples/templates/02/loading-files/index.php
if ('function' == type(fn)) {
onload(iframe, fn);
}
tick(function(){
// Append after event listeners are attached for IE.
var firstScript = document.getElementsByTagName('script')[0];
firstScript.parentNode.insertBefore(iframe, firstScript);
});
// Return the iframe element in case they want to do anything special, like
// give it an ID or attributes.
return iframe;
};
}, {"script-onload":117,"next-tick":105,"type":7}],
110: [function(require, module, exports) {
module.exports = {
removedProduct: /^[ _]?removed[ _]?product[ _]?$/i,
viewedProduct: /^[ _]?viewed[ _]?product[ _]?$/i,
viewedProductCategory: /^[ _]?viewed[ _]?product[ _]?category[ _]?$/i,
addedProduct: /^[ _]?added[ _]?product[ _]?$/i,
completedOrder: /^[ _]?completed[ _]?order[ _]?$/i,
startedOrder: /^[ _]?started[ _]?order[ _]?$/i,
updatedOrder: /^[ _]?updated[ _]?order[ _]?$/i,
refundedOrder: /^[ _]?refunded?[ _]?order[ _]?$/i,
viewedProductDetails: /^[ _]?viewed[ _]?product[ _]?details?[ _]?$/i,
clickedProduct: /^[ _]?clicked[ _]?product[ _]?$/i,
viewedPromotion: /^[ _]?viewed[ _]?promotion?[ _]?$/i,
clickedPromotion: /^[ _]?clicked[ _]?promotion?[ _]?$/i,
viewedCheckoutStep: /^[ _]?viewed[ _]?checkout[ _]?step[ _]?$/i,
completedCheckoutStep: /^[ _]?completed[ _]?checkout[ _]?step[ _]?$/i
};
}, {}],
111: [function(require, module, exports) {
/**
* Expose `toNoCase`.
*/
module.exports = toNoCase;
/**
* Test whether a string is camel-case.
*/
var hasSpace = /\s/;
var hasSeparator = /[\W_]/;
/**
* Remove any starting case from a `string`, like camel or snake, but keep
* spaces and punctuation that may be important otherwise.
*
* @param {String} string
* @return {String}
*/
function toNoCase (string) {
if (hasSpace.test(string)) return string.toLowerCase();
if (hasSeparator.test(string)) return unseparate(string).toLowerCase();
return uncamelize(string).toLowerCase();
}
/**
* Separator splitter.
*/
var separatorSplitter = /[\W_]+(.|$)/g;
/**
* Un-separate a `string`.
*
* @param {String} string
* @return {String}
*/
function unseparate (string) {
return string.replace(separatorSplitter, function (m, next) {
return next ? ' ' + next : '';
});
}
/**
* Camelcase splitter.
*/
var camelSplitter = /(.)([A-Z]+)/g;
/**
* Un-camelcase a `string`.
*
* @param {String} string
* @return {String}
*/
function uncamelize (string) {
return string.replace(camelSplitter, function (m, previous, uppers) {
return previous + ' ' + uppers.toLowerCase().split('').join(' ');
});
}
}, {}],
112: [function(require, module, exports) {
/**
* Module dependencies.
*/
var index = require('indexof');
/**
* Expose `Emitter`.
*/
module.exports = Emitter;
/**
* Initialize a new `Emitter`.
*
* @api public
*/
function Emitter(obj) {
if (obj) return mixin(obj);
};
/**
* Mixin the emitter properties.
*
* @param {Object} obj
* @return {Object}
* @api private
*/
function mixin(obj) {
for (var key in Emitter.prototype) {
obj[key] = Emitter.prototype[key];
}
return obj;
}
/**
* Listen on the given `event` with `fn`.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.on =
Emitter.prototype.addEventListener = function(event, fn){
this._callbacks = this._callbacks || {};
(this._callbacks[event] = this._callbacks[event] || [])
.push(fn);
return this;
};
/**
* Adds an `event` listener that will be invoked a single
* time then automatically removed.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.once = function(event, fn){
var self = this;
this._callbacks = this._callbacks || {};
function on() {
self.off(event, on);
fn.apply(this, arguments);
}
fn._off = on;
this.on(event, on);
return this;
};
/**
* Remove the given callback for `event` or all
* registered callbacks.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.off =
Emitter.prototype.removeListener =
Emitter.prototype.removeAllListeners =
Emitter.prototype.removeEventListener = function(event, fn){
this._callbacks = this._callbacks || {};
// all
if (0 == arguments.length) {
this._callbacks = {};
return this;
}
// specific event
var callbacks = this._callbacks[event];
if (!callbacks) return this;
// remove all handlers
if (1 == arguments.length) {
delete this._callbacks[event];
return this;
}
// remove specific handler
var i = index(callbacks, fn._off || fn);
if (~i) callbacks.splice(i, 1);
return this;
};
/**
* Emit `event` with the given args.
*
* @param {String} event
* @param {Mixed} ...
* @return {Emitter}
*/
Emitter.prototype.emit = function(event){
this._callbacks = this._callbacks || {};
var args = [].slice.call(arguments, 1)
, callbacks = this._callbacks[event];
if (callbacks) {
callbacks = callbacks.slice(0);
for (var i = 0, len = callbacks.length; i < len; ++i) {
callbacks[i].apply(this, args);
}
}
return this;
};
/**
* Return array of callbacks for `event`.
*
* @param {String} event
* @return {Array}
* @api public
*/
Emitter.prototype.listeners = function(event){
this._callbacks = this._callbacks || {};
return this._callbacks[event] || [];
};
/**
* Check if this emitter has `event` handlers.
*
* @param {String} event
* @return {Boolean}
* @api public
*/
Emitter.prototype.hasListeners = function(event){
return !! this.listeners(event).length;
};
}, {"indexof":118}],
118: [function(require, module, exports) {
module.exports = function(arr, obj){
if (arr.indexOf) return arr.indexOf(obj);
for (var i = 0; i < arr.length; ++i) {
if (arr[i] === obj) return i;
}
return -1;
};
}, {}],
113: [function(require, module, exports) {
module.exports = function after (times, func) {
// After 0, really?
if (times <= 0) return func();
// That's more like it.
return function() {
if (--times < 1) {
return func.apply(this, arguments);
}
};
};
}, {}],
114: [function(require, module, exports) {
/**
* Module dependencies.
*/
try {
var type = require('type');
} catch (err) {
var type = require('component-type');
}
var toFunction = require('to-function');
/**
* HOP reference.
*/
var has = Object.prototype.hasOwnProperty;
/**
* Iterate the given `obj` and invoke `fn(val, i)`
* in optional context `ctx`.
*
* @param {String|Array|Object} obj
* @param {Function} fn
* @param {Object} [ctx]
* @api public
*/
module.exports = function(obj, fn, ctx){
fn = toFunction(fn);
ctx = ctx || this;
switch (type(obj)) {
case 'array':
return array(obj, fn, ctx);
case 'object':
if ('number' == typeof obj.length) return array(obj, fn, ctx);
return object(obj, fn, ctx);
case 'string':
return string(obj, fn, ctx);
}
};
/**
* Iterate string chars.
*
* @param {String} obj
* @param {Function} fn
* @param {Object} ctx
* @api private
*/
function string(obj, fn, ctx) {
for (var i = 0; i < obj.length; ++i) {
fn.call(ctx, obj.charAt(i), i);
}
}
/**
* Iterate object keys.
*
* @param {Object} obj
* @param {Function} fn
* @param {Object} ctx
* @api private
*/
function object(obj, fn, ctx) {
for (var key in obj) {
if (has.call(obj, key)) {
fn.call(ctx, key, obj[key]);
}
}
}
/**
* Iterate array-ish.
*
* @param {Array|Object} obj
* @param {Function} fn
* @param {Object} ctx
* @api private
*/
function array(obj, fn, ctx) {
for (var i = 0; i < obj.length; ++i) {
fn.call(ctx, obj[i], i);
}
}
}, {"type":115,"component-type":115,"to-function":119}],
115: [function(require, module, exports) {
/**
* toString ref.
*/
var toString = Object.prototype.toString;
/**
* Return the type of `val`.
*
* @param {Mixed} val
* @return {String}
* @api public
*/
module.exports = function(val){
switch (toString.call(val)) {
case '[object Function]': return 'function';
case '[object Date]': return 'date';
case '[object RegExp]': return 'regexp';
case '[object Arguments]': return 'arguments';
case '[object Array]': return 'array';
case '[object String]': return 'string';
}
if (val === null) return 'null';
if (val === undefined) return 'undefined';
if (val && val.nodeType === 1) return 'element';
if (val === Object(val)) return 'object';
return typeof val;
};
}, {}],
119: [function(require, module, exports) {
/**
* Module Dependencies
*/
var expr;
try {
expr = require('props');
} catch(e) {
expr = require('component-props');
}
/**
* Expose `toFunction()`.
*/
module.exports = toFunction;
/**
* Convert `obj` to a `Function`.
*
* @param {Mixed} obj
* @return {Function}
* @api private
*/
function toFunction(obj) {
switch ({}.toString.call(obj)) {
case '[object Object]':
return objectToFunction(obj);
case '[object Function]':
return obj;
case '[object String]':
return stringToFunction(obj);
case '[object RegExp]':
return regexpToFunction(obj);
default:
return defaultToFunction(obj);
}
}
/**
* Default to strict equality.
*
* @param {Mixed} val
* @return {Function}
* @api private
*/
function defaultToFunction(val) {
return function(obj){
return val === obj;
};
}
/**
* Convert `re` to a function.
*
* @param {RegExp} re
* @return {Function}
* @api private
*/
function regexpToFunction(re) {
return function(obj){
return re.test(obj);
};
}
/**
* Convert property `str` to a function.
*
* @param {String} str
* @return {Function}
* @api private
*/
function stringToFunction(str) {
// immediate such as "> 20"
if (/^ *\W+/.test(str)) return new Function('_', 'return _ ' + str);
// properties such as "name.first" or "age > 18" or "age > 18 && age < 36"
return new Function('_', 'return ' + get(str));
}
/**
* Convert `object` to a function.
*
* @param {Object} object
* @return {Function}
* @api private
*/
function objectToFunction(obj) {
var match = {};
for (var key in obj) {
match[key] = typeof obj[key] === 'string'
? defaultToFunction(obj[key])
: toFunction(obj[key]);
}
return function(val){
if (typeof val !== 'object') return false;
for (var key in match) {
if (!(key in val)) return false;
if (!match[key](val[key])) return false;
}
return true;
};
}
/**
* Built the getter function. Supports getter style functions
*
* @param {String} str
* @return {String}
* @api private
*/
function get(str) {
var props = expr(str);
if (!props.length) return '_.' + str;
var val, i, prop;
for (i = 0; i < props.length; i++) {
prop = props[i];
val = '_.' + prop;
val = "('function' == typeof " + val + " ? " + val + "() : " + val + ")";
// mimic negative lookbehind to avoid problems with nested properties
str = stripNested(prop, str, val);
}
return str;
}
/**
* Mimic negative lookbehind to avoid problems with nested properties.
*
* See: http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript
*
* @param {String} prop
* @param {String} str
* @param {String} val
* @return {String}
* @api private
*/
function stripNested (prop, str, val) {
return str.replace(new RegExp('(\\.)?' + prop, 'g'), function($0, $1) {
return $1 ? $0 : val;
});
}
}, {"props":120,"component-props":120}],
120: [function(require, module, exports) {
/**
* Global Names
*/
var globals = /\b(this|Array|Date|Object|Math|JSON)\b/g;
/**
* Return immediate identifiers parsed from `str`.
*
* @param {String} str
* @param {String|Function} map function or prefix
* @return {Array}
* @api public
*/
module.exports = function(str, fn){
var p = unique(props(str));
if (fn && 'string' == typeof fn) fn = prefixed(fn);
if (fn) return map(str, p, fn);
return p;
};
/**
* Return immediate identifiers in `str`.
*
* @param {String} str
* @return {Array}
* @api private
*/
function props(str) {
return str
.replace(/\.\w+|\w+ *\(|"[^"]*"|'[^']*'|\/([^/]+)\//g, '')
.replace(globals, '')
.match(/[$a-zA-Z_]\w*/g)
|| [];
}
/**
* Return `str` with `props` mapped with `fn`.
*
* @param {String} str
* @param {Array} props
* @param {Function} fn
* @return {String}
* @api private
*/
function map(str, props, fn) {
var re = /\.\w+|\w+ *\(|"[^"]*"|'[^']*'|\/([^/]+)\/|[a-zA-Z_]\w*/g;
return str.replace(re, function(_){
if ('(' == _[_.length - 1]) return fn(_);
if (!~props.indexOf(_)) return _;
return fn(_);
});
}
/**
* Return unique array.
*
* @param {Array} arr
* @return {Array}
* @api private
*/
function unique(arr) {
var ret = [];
for (var i = 0; i < arr.length; i++) {
if (~ret.indexOf(arr[i])) continue;
ret.push(arr[i]);
}
return ret;
}
/**
* Map with prefix `str`.
*/
function prefixed(str) {
return function(_){
return str + _;
};
}
}, {}],
116: [function(require, module, exports) {
/**
* toString.
*/
var toString = window.JSON
? JSON.stringify
: function(_){ return String(_); };
/**
* Export `fmt`
*/
module.exports = fmt;
/**
* Formatters
*/
fmt.o = toString;
fmt.s = String;
fmt.d = parseInt;
/**
* Format the given `str`.
*
* @param {String} str
* @param {...} args
* @return {String}
* @api public
*/
function fmt(str){
var args = [].slice.call(arguments, 1);
var j = 0;
return str.replace(/%([a-z])/gi, function(_, f){
return fmt[f]
? fmt[f](args[j++])
: _ + f;
});
}
}, {}],
101: [function(require, module, exports) {
/**
* Generate a slug from the given `str`.
*
* example:
*
* generate('foo bar');
* // > foo-bar
*
* @param {String} str
* @param {Object} options
* @config {String|RegExp} [replace] characters to replace, defaulted to `/[^a-z0-9]/g`
* @config {String} [separator] separator to insert, defaulted to `-`
* @return {String}
*/
module.exports = function (str, options) {
options || (options = {});
return str.toLowerCase()
.replace(options.replace || /[^a-z0-9]/g, ' ')
.replace(/^ +| +$/g, '')
.replace(/ +/g, options.separator || '-')
};
}, {}],
102: [function(require, module, exports) {
/**
* Module dependencies.
*/
var after = require('after');
var domify = require('domify');
var each = require('each');
var Emitter = require('emitter');
/**
* Mixin emitter.
*/
Emitter(exports);
/**
* Add a new option to the integration by `key` with default `value`.
*
* @param {String} key
* @param {Mixed} value
* @return {Integration}
*/
exports.option = function(key, value){
this.prototype.defaults[key] = value;
return this;
};
/**
* Add a new mapping option.
*
* This will create a method `name` that will return a mapping
* for you to use.
*
* Example:
*
* Integration('My Integration')
* .mapping('events');
*
* new MyIntegration().track('My Event');
*
* .track = function(track){
* var events = this.events(track.event());
* each(events, send);
* };
*
* @param {String} name
* @return {Integration}
*/
exports.mapping = function(name){
this.option(name, []);
this.prototype[name] = function(str){
return this.map(this.options[name], str);
};
return this;
};
/**
* Register a new global variable `key` owned by the integration, which will be
* used to test whether the integration is already on the page.
*
* @param {String} global
* @return {Integration}
*/
exports.global = function(key){
this.prototype.globals.push(key);
return this;
};
/**
* Mark the integration as assuming an initial pageview, so to defer loading
* the script until the first `page` call, noop the first `initialize`.
*
* @return {Integration}
*/
exports.assumesPageview = function(){
this.prototype._assumesPageview = true;
return this;
};
/**
* Mark the integration as being "ready" once `load` is called.
*
* @return {Integration}
*/
exports.readyOnLoad = function(){
this.prototype._readyOnLoad = true;
return this;
};
/**
* Mark the integration as being "ready" once `initialize` is called.
*
* @return {Integration}
*/
exports.readyOnInitialize = function(){
this.prototype._readyOnInitialize = true;
return this;
};
/**
* Define a tag to be loaded.
*
* @param {String} str DOM tag as string or URL
* @return {Integration}
*/
exports.tag = function(name, str){
if (null == str) {
str = name;
name = 'library';
}
this.prototype.templates[name] = objectify(str);
return this;
};
/**
* Given a string, give back DOM attributes.
*
* Do it in a way where the browser doesn't load images or iframes.
* It turns out, domify will load images/iframes, because
* whenever you construct those DOM elements,
* the browser immediately loads them.
*
* @param {String} str
* @return {Object}
*/
function objectify(str) {
// replace `src` with `data-src` to prevent image loading
str = str.replace(' src="', ' data-src="');
var el = domify(str);
var attrs = {};
each(el.attributes, function(attr){
// then replace it back
var name = 'data-src' == attr.name ? 'src' : attr.name;
if (!~str.indexOf(attr.name + '=')) return;
attrs[name] = attr.value;
});
return {
type: el.tagName.toLowerCase(),
attrs: attrs
};
}