This repository has been archived by the owner. It is now read-only.
Permalink
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Jan 15, 2015
Newer
100644
20420 lines (16784 sloc)
439 KB
1
(function umd(require){
3
module.exports = require('1');
5
define(function(){ return require('1'); });
6
} else {
7
this['analytics'] = require('1');
8
}
9
})((function outer(modules, cache, entries){
10
11
/**
12
* Global
13
*/
14
15
var global = (function(){ return this; })();
16
17
/**
18
* Require `name`.
19
*
20
* @param {String} name
21
* @api public
22
*/
23
25
if (cache[name]) return cache[name].exports;
26
if (modules[name]) return call(name, require);
27
throw new Error('cannot find module "' + name + '"');
28
}
29
30
/**
31
* Call module `id` and cache it.
32
*
33
* @param {Number} id
34
* @param {Function} require
35
* @return {Function}
36
* @api private
37
*/
38
39
function call(id, require){
41
var mod = modules[id];
42
var name = mod[2];
43
var fn = mod[0];
44
var threw = true;
45
46
try {
47
fn.call(m.exports, function(req){
48
var dep = modules[id][1][req];
49
return require(dep || req);
50
}, m, m.exports, outer, modules, cache, entries);
51
threw = false;
52
} finally {
53
if (threw) {
54
delete cache[id];
55
} else if (name) {
56
// expose as 'name'.
57
cache[name] = cache[id];
58
}
59
}
60
61
return cache[id].exports;
62
}
63
64
/**
65
* Require all entries exposing them on global if needed.
66
*/
67
68
for (var id in entries) {
69
if (entries[id]) {
70
global[entries[id]] = require(id);
71
} else {
72
require(id);
73
}
74
}
75
76
/**
77
* Duo flag.
78
*/
79
80
require.duo = true;
81
82
/**
83
* Expose cache.
84
*/
85
86
require.cache = cache;
87
88
/**
89
* Expose modules
90
*/
91
92
require.modules = modules;
93
94
/**
95
* Return newest require.
96
*/
97
98
return require;
99
})({
100
1: [function(require, module, exports) {
101
102
/**
103
* Analytics.js
104
*
106
*/
107
110
var each = require('each');
111
112
/**
114
*/
115
117
118
/**
120
*/
121
122
analytics.require = require;
123
124
/**
125
* Expose `VERSION`.
126
*/
127
129
130
/**
131
* Add integrations.
132
*/
133
135
analytics.use(Integration);
136
});
137
138
}, {"segmentio/analytics.js-core":2,"./integrations":3,"each":4,"../bower.json":5}],
139
2: [function(require, module, exports) {
140
141
/**
142
* Analytics.js
143
*
144
* (C) 2013 Segment.io Inc.
145
*/
146
147
var Analytics = require('./analytics');
148
149
/**
150
* Expose the `analytics` singleton.
151
*/
152
153
var analytics = module.exports = exports = new Analytics();
154
155
/**
156
* Expose require
157
*/
158
159
analytics.require = require;
160
161
/**
162
* Expose `VERSION`.
163
*/
164
165
exports.VERSION = require('../bower.json').version;
166
167
}, {"./analytics":6,"../bower.json":7}],
168
6: [function(require, module, exports) {
169
170
/**
171
* Module dependencies.
172
*/
173
174
var _analytics = window.analytics;
175
var Emitter = require('emitter');
176
var Facade = require('facade');
177
var after = require('after');
178
var bind = require('bind');
179
var callback = require('callback');
180
var clone = require('clone');
181
var cookie = require('./cookie');
182
var debug = require('debug');
183
var defaults = require('defaults');
184
var each = require('each');
185
var group = require('./group');
186
var is = require('is');
187
var isMeta = require('is-meta');
188
var keys = require('object').keys;
189
var memory = require('./memory');
190
var normalize = require('./normalize');
191
var on = require('event').bind;
192
var pageDefaults = require('./pageDefaults');
193
var pick = require('pick');
194
var prevent = require('prevent');
195
var querystring = require('querystring');
196
var size = require('object').length;
197
var store = require('./store');
198
var user = require('./user');
199
var Alias = Facade.Alias;
200
var Group = Facade.Group;
201
var Identify = Facade.Identify;
202
var Page = Facade.Page;
203
var Track = Facade.Track;
204
205
/**
207
*/
208
210
211
/**
213
*/
214
218
219
/**
221
*/
222
223
function Analytics() {
224
this._options({});
225
this.Integrations = {};
226
this._integrations = {};
227
this._readied = false;
228
this._timeout = 300;
229
// XXX: BACKWARDS COMPATIBILITY
230
this._user = user;
231
this.log = debug('analytics.js');
232
bind.all(this);
233
234
var self = this;
235
this.on('initialize', function(settings, options){
236
if (options.initialPageview) self.page();
237
self._parseQuery();
238
});
239
}
240
241
/**
243
*/
244
246
247
/**
249
*
252
*/
253
254
Analytics.prototype.use = function(plugin) {
255
plugin(this);
256
return this;
257
};
258
259
/**
261
*
264
*/
265
266
Analytics.prototype.addIntegration = function(Integration) {
267
var name = Integration.prototype.name;
268
if (!name) throw new TypeError('attempted to add an invalid integration');
269
this.Integrations[name] = Integration;
270
return this;
271
};
272
273
/**
275
*
276
* Aliased to `init` for convenience.
277
*
278
* @param {Object} [settings={}]
279
* @param {Object} [options={}]
280
* @return {Analytics}
281
*/
282
283
Analytics.prototype.init = Analytics.prototype.initialize = function(settings, options) {
284
settings = settings || {};
285
options = options || {};
286
289
290
// clean unknown integrations from settings
291
var self = this;
292
each(settings, function(name) {
293
var Integration = self.Integrations[name];
294
if (!Integration) delete settings[name];
295
});
296
297
// add integrations
298
each(settings, function(name, opts) {
299
var Integration = self.Integrations[name];
300
var integration = new Integration(clone(opts));
301
self.log('initialize %o - %o', name, opts);
302
self.add(integration);
303
});
304
306
310
311
// make ready callback
312
var ready = after(size(integrations), function() {
313
self._readied = true;
314
self.emit('ready');
315
});
316
317
// initialize integrations, passing ready
318
each(integrations, function(name, integration) {
319
if (options.initialPageview && integration.options.initialPageview === false) {
320
integration.page = after(2, integration.page);
321
}
322
323
integration.analytics = self;
324
integration.once('ready', ready);
325
integration.initialize();
326
});
327
328
// backwards compat with angular plugin.
329
// TODO: remove
330
this.initialized = true;
336
/**
340
*/
341
342
Analytics.prototype.setAnonymousId = function(id){
343
this.user().anonymousId(id);
344
return this;
345
};
346
347
/**
349
*
351
*/
352
353
Analytics.prototype.add = function(integration){
354
this._integrations[integration.name] = integration;
355
return this;
356
};
357
358
/**
360
*
361
* @param {string} [id=user.id()] User ID.
362
* @param {Object} [traits=null] User traits.
363
* @param {Object} [options=null]
364
* @param {Function} [fn]
365
* @return {Analytics}
366
*/
367
368
Analytics.prototype.identify = function(id, traits, options, fn) {
369
// Argument reshuffling.
370
/* eslint-disable no-unused-expressions, no-sequences */
371
if (is.fn(options)) fn = options, options = null;
372
if (is.fn(traits)) fn = traits, options = null, traits = null;
373
if (is.object(id)) options = traits, traits = id, id = user.id();
374
/* eslint-enable no-unused-expressions, no-sequences */
375
376
// clone traits before we manipulate so we don't do anything uncouth, and take
377
// from `user` so that we carryover anonymous traits
378
user.identify(id, traits);
379
380
var msg = this.normalize({
381
options: options,
382
traits: user.traits(),
383
userId: user.id()
384
});
385
386
this._invoke('identify', new Identify(msg));
387
388
// emit
389
this.emit('identify', id, traits, options);
390
this._callback(fn);
391
return this;
392
};
393
394
/**
396
*
398
*/
399
402
};
403
404
/**
405
* Identify a group by optional `id` and `traits`. Or, if no arguments are
406
* supplied, return the current group.
407
*
408
* @param {string} [id=group.id()] Group ID.
409
* @param {Object} [traits=null] Group traits.
410
* @param {Object} [options=null]
411
* @param {Function} [fn]
412
* @return {Analytics|Object}
413
*/
414
415
Analytics.prototype.group = function(id, traits, options, fn) {
416
/* eslint-disable no-unused-expressions, no-sequences */
417
if (!arguments.length) return group;
418
if (is.fn(options)) fn = options, options = null;
419
if (is.fn(traits)) fn = traits, options = null, traits = null;
420
if (is.object(id)) options = traits, traits = id, id = group.id();
421
/* eslint-enable no-unused-expressions, no-sequences */
422
423
424
// grab from group again to make sure we're taking from the source
425
group.identify(id, traits);
426
427
var msg = this.normalize({
428
options: options,
429
traits: group.traits(),
430
groupId: group.id()
431
});
432
435
this.emit('group', id, traits, options);
436
this._callback(fn);
437
return this;
438
};
440
/**
442
*
443
* @param {string} event
444
* @param {Object} [properties=null]
445
* @param {Object} [options=null]
446
* @param {Function} [fn]
447
* @return {Analytics}
448
*/
449
450
Analytics.prototype.track = function(event, properties, options, fn) {
451
// Argument reshuffling.
452
/* eslint-disable no-unused-expressions, no-sequences */
453
if (is.fn(options)) fn = options, options = null;
454
if (is.fn(properties)) fn = properties, options = null, properties = null;
455
/* eslint-enable no-unused-expressions, no-sequences */
457
// figure out if the event is archived.
458
var plan = this.options.plan || {};
459
var events = plan.track || {};
460
461
// normalize
462
var msg = this.normalize({
463
properties: properties,
464
options: options,
465
event: event
466
});
467
468
// plan.
469
plan = events[event];
470
if (plan) {
471
this.log('plan %o - %o', event, plan);
472
if (plan.enabled === false) return this._callback(fn);
473
defaults(msg.integrations, plan.integrations || {});
474
}
475
477
478
this.emit('track', event, properties, options);
479
this._callback(fn);
480
return this;
481
};
482
483
/**
484
* Helper method to track an outbound link that would normally navigate away
485
* from the page before the analytics calls were sent.
486
*
487
* BACKWARDS COMPATIBILITY: aliased to `trackClick`.
488
*
489
* @param {Element|Array} links
490
* @param {string|Function} event
491
* @param {Object|Function} properties (optional)
492
* @return {Analytics}
493
*/
494
495
Analytics.prototype.trackClick = Analytics.prototype.trackLink = function(links, event, properties) {
496
if (!links) return this;
497
// always arrays, handles jquery
498
if (is.element(links)) links = [links];
499
500
var self = this;
501
each(links, function(el) {
502
if (!is.element(el)) throw new TypeError('Must pass HTMLElement to `analytics.trackLink`.');
503
on(el, 'click', function(e) {
504
var ev = is.fn(event) ? event(el) : event;
505
var props = is.fn(properties) ? properties(el) : properties;
506
var href = el.getAttribute('href')
507
|| el.getAttributeNS('http://www.w3.org/1999/xlink', 'href')
508
|| el.getAttribute('xlink:href');
509
511
512
if (href && el.target !== '_blank' && !isMeta(e)) {
513
prevent(e);
514
self._callback(function() {
515
window.location.href = href;
516
});
517
}
518
});
519
});
520
523
524
/**
525
* Helper method to track an outbound form that would normally navigate away
526
* from the page before the analytics calls were sent.
527
*
528
* BACKWARDS COMPATIBILITY: aliased to `trackSubmit`.
529
*
530
* @param {Element|Array} forms
531
* @param {string|Function} event
532
* @param {Object|Function} properties (optional)
533
* @return {Analytics}
534
*/
535
536
Analytics.prototype.trackSubmit = Analytics.prototype.trackForm = function(forms, event, properties) {
537
if (!forms) return this;
538
// always arrays, handles jquery
539
if (is.element(forms)) forms = [forms];
540
541
var self = this;
542
each(forms, function(el) {
543
if (!is.element(el)) throw new TypeError('Must pass HTMLElement to `analytics.trackForm`.');
544
function handler(e) {
545
prevent(e);
546
547
var ev = is.fn(event) ? event(el) : event;
548
var props = is.fn(properties) ? properties(el) : properties;
549
self.track(ev, props);
550
555
556
// Support the events happening through jQuery or Zepto instead of through
557
// the normal DOM API, because `el.submit` doesn't bubble up events...
558
var $ = window.jQuery || window.Zepto;
559
if ($) {
560
$(el).submit(handler);
561
} else {
562
on(el, 'submit', handler);
563
}
564
});
565
566
return this;
567
};
568
569
/**
570
* Trigger a pageview, labeling the current page with an optional `category`,
571
* `name` and `properties`.
572
*
573
* @param {string} [category]
574
* @param {string} [name]
575
* @param {Object|string} [properties] (or path)
576
* @param {Object} [options]
577
* @param {Function} [fn]
578
* @return {Analytics}
579
*/
580
581
Analytics.prototype.page = function(category, name, properties, options, fn) {
582
// Argument reshuffling.
583
/* eslint-disable no-unused-expressions, no-sequences */
584
if (is.fn(options)) fn = options, options = null;
585
if (is.fn(properties)) fn = properties, options = properties = null;
586
if (is.fn(name)) fn = name, options = properties = name = null;
587
if (is.object(category)) options = name, properties = category, name = category = null;
588
if (is.object(name)) options = properties, properties = name, name = null;
589
if (is.string(category) && !is.string(name)) name = category, category = null;
590
/* eslint-enable no-unused-expressions, no-sequences */
591
592
properties = clone(properties) || {};
593
if (name) properties.name = name;
594
if (category) properties.category = category;
595
596
// Ensure properties has baseline spec properties.
597
// TODO: Eventually move these entirely to `options.context.page`
598
var defs = pageDefaults();
599
defaults(properties, defs);
600
601
// Mirror user overrides to `options.context.page` (but exclude custom properties)
602
// (Any page defaults get applied in `this.normalize` for consistency.)
603
// Weird, yeah--moving special props to `context.page` will fix this in the long term.
604
var overrides = pick(keys(defs), properties);
605
if (!is.empty(overrides)) {
606
options = options || {};
607
options.context = options.context || {};
608
options.context.page = overrides;
609
}
611
var msg = this.normalize({
612
properties: properties,
613
category: category,
614
options: options,
615
name: name
616
});
617
618
this._invoke('page', new Page(msg));
619
620
this.emit('page', category, name, properties, options);
621
this._callback(fn);
622
return this;
623
};
626
* FIXME: BACKWARDS COMPATIBILITY: convert an old `pageview` to a `page` call.
627
*
628
* @param {string} [url]
629
* @return {Analytics}
630
* @api private
633
Analytics.prototype.pageview = function(url) {
634
var properties = {};
635
if (url) properties.path = url;
636
this.page(properties);
637
return this;
638
};
643
* @param {string} to
644
* @param {string} from (optional)
645
* @param {Object} options (optional)
646
* @param {Function} fn (optional)
647
* @return {Analytics}
650
Analytics.prototype.alias = function(to, from, options, fn) {
651
// Argument reshuffling.
652
/* eslint-disable no-unused-expressions, no-sequences */
653
if (is.fn(options)) fn = options, options = null;
654
if (is.fn(from)) fn = from, options = null, from = null;
655
if (is.object(from)) options = from, from = null;
656
/* eslint-enable no-unused-expressions, no-sequences */
658
var msg = this.normalize({
659
options: options,
660
previousId: from,
661
userId: to
662
});
663
664
this._invoke('alias', new Alias(msg));
665
666
this.emit('alias', to, from, options);
667
this._callback(fn);
668
return this;
669
};
678
Analytics.prototype.ready = function(fn) {
679
if (is.fn(fn)) {
680
if (this._readied) {
681
callback.async(fn);
682
} else {
683
this.once('ready', fn);
684
}
685
}
686
return this;
690
* Set the `timeout` (in milliseconds) used for callbacks.
691
*
692
* @param {Number} timeout
695
Analytics.prototype.timeout = function(timeout) {
696
this._timeout = timeout;
697
};
705
Analytics.prototype.debug = function(str){
706
if (!arguments.length || str) {
707
debug.enable('analytics:' + (str || '*'));
708
} else {
709
debug.disable();
712
713
/**
714
* Apply options.
715
*
716
* @param {Object} options
717
* @return {Analytics}
718
* @api private
719
*/
720
721
Analytics.prototype._options = function(options) {
722
options = options || {};
723
this.options = options;
724
cookie.options(options.cookie);
725
store.options(options.localStorage);
726
user.options(options.user);
727
group.options(options.group);
728
return this;
729
};
730
731
/**
732
* Callback a `fn` after our defined timeout period.
733
*
734
* @param {Function} fn
735
* @return {Analytics}
736
* @api private
737
*/
738
739
Analytics.prototype._callback = function(fn) {
740
callback.async(fn, this._timeout);
741
return this;
742
};
743
744
/**
746
*
747
* @param {string} method
748
* @param {Facade} facade
749
* @return {Analytics}
750
* @api private
751
*/
752
753
Analytics.prototype._invoke = function(method, facade) {
754
this.emit('invoke', facade);
755
756
each(this._integrations, function(name, integration) {
757
if (!facade.enabled(name)) return;
758
integration.invoke.call(integration, method, facade);
759
});
760
763
770
771
Analytics.prototype.push = function(args){
772
var method = args.shift();
773
if (!this[method]) return;
774
this[method].apply(this, args);
775
};
776
777
/**
781
*/
782
783
Analytics.prototype.reset = function(){
784
this.user().logout();
785
this.group().logout();
786
};
787
788
/**
789
* Parse the query string for callable methods.
790
*
791
* @return {Analytics}
792
* @api private
793
*/
794
795
Analytics.prototype._parseQuery = function() {
796
// Identify and track any `ajs_uid` and `ajs_event` parameters in the URL.
797
var q = querystring.parse(window.location.search);
798
if (q.ajs_uid) this.identify(q.ajs_uid);
799
if (q.ajs_event) this.track(q.ajs_event);
800
if (q.ajs_aid) user.anonymousId(q.ajs_aid);
801
return this;
802
};
803
804
/**
809
*/
810
811
Analytics.prototype.normalize = function(msg){
812
msg = normalize(msg, keys(this._integrations));
813
if (msg.anonymousId) user.anonymousId(msg.anonymousId);
814
msg.anonymousId = user.anonymousId();
815
816
// Ensure all outgoing requests include page data in their contexts.
817
msg.context.page = defaults(msg.context.page || {}, pageDefaults());
818
819
return msg;
820
};
821
822
/**
824
*/
825
826
Analytics.prototype.noConflict = function(){
827
window.analytics = _analytics;
828
return this;
829
};
830
831
832
}, {"emitter":8,"facade":9,"after":10,"bind":11,"callback":12,"clone":13,"./cookie":14,"debug":15,"defaults":16,"each":4,"./group":17,"is":18,"is-meta":19,"object":20,"./memory":21,"./normalize":22,"event":23,"./pageDefaults":24,"pick":25,"prevent":26,"querystring":27,"./store":28,"./user":29}],
833
8: [function(require, module, exports) {
834
835
/**
837
*/
838
840
841
/**
843
*/
844
846
847
/**