mixpanel-browser 2.41.0 → 2.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/tests.yml +25 -0
- package/CHANGELOG.md +18 -0
- package/README.md +4 -2
- package/dist/mixpanel-jslib-snippet.min.js +3 -3
- package/dist/mixpanel-jslib-snippet.min.test.js +3 -3
- package/dist/mixpanel.amd.js +975 -2843
- package/dist/mixpanel.cjs.js +975 -2843
- package/dist/mixpanel.globals.js +975 -2843
- package/dist/mixpanel.min.js +100 -149
- package/dist/mixpanel.umd.js +975 -2843
- package/doc/build-docs.js +16 -0
- package/doc/readme.io/javascript-full-api-reference.md +18 -0
- package/mixpanel-jslib-snippet.js +2 -2
- package/package.json +3 -3
- package/src/config.js +1 -1
- package/src/mixpanel-core.js +76 -129
- package/src/mixpanel-group.js +4 -0
- package/src/mixpanel-persistence.js +0 -21
- package/src/request-batcher.js +47 -10
- package/src/request-queue.js +55 -18
- package/src/utils.js +2 -71
- package/tunnel.log +0 -0
- package/.travis.yml +0 -6
- package/src/mixpanel-notification.js +0 -1309
- package/src/property-filters.js +0 -508
package/dist/mixpanel.cjs.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var Config = {
|
|
4
4
|
DEBUG: false,
|
|
5
|
-
LIB_VERSION: '2.
|
|
5
|
+
LIB_VERSION: '2.45.0'
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
|
|
@@ -36,11 +36,11 @@ var slice = ArrayProto.slice;
|
|
|
36
36
|
var toString = ObjProto.toString;
|
|
37
37
|
var hasOwnProperty = ObjProto.hasOwnProperty;
|
|
38
38
|
var windowConsole = window$1.console;
|
|
39
|
-
var navigator
|
|
39
|
+
var navigator = window$1.navigator;
|
|
40
40
|
var document$1 = window$1.document;
|
|
41
41
|
var windowOpera = window$1.opera;
|
|
42
42
|
var screen = window$1.screen;
|
|
43
|
-
var userAgent = navigator
|
|
43
|
+
var userAgent = navigator.userAgent;
|
|
44
44
|
var nativeBind = FuncProto.bind;
|
|
45
45
|
var nativeForEach = ArrayProto.forEach;
|
|
46
46
|
var nativeIndexOf = ArrayProto.indexOf;
|
|
@@ -152,14 +152,6 @@ _.bind = function(func, context) {
|
|
|
152
152
|
return bound;
|
|
153
153
|
};
|
|
154
154
|
|
|
155
|
-
_.bind_instance_methods = function(obj) {
|
|
156
|
-
for (var func in obj) {
|
|
157
|
-
if (typeof(obj[func]) === 'function') {
|
|
158
|
-
obj[func] = _.bind(obj[func], obj);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
|
|
163
155
|
/**
|
|
164
156
|
* @param {*=} obj
|
|
165
157
|
* @param {function(...*)=} iterator
|
|
@@ -188,19 +180,6 @@ _.each = function(obj, iterator, context) {
|
|
|
188
180
|
}
|
|
189
181
|
};
|
|
190
182
|
|
|
191
|
-
_.escapeHTML = function(s) {
|
|
192
|
-
var escaped = s;
|
|
193
|
-
if (escaped && _.isString(escaped)) {
|
|
194
|
-
escaped = escaped
|
|
195
|
-
.replace(/&/g, '&')
|
|
196
|
-
.replace(/</g, '<')
|
|
197
|
-
.replace(/>/g, '>')
|
|
198
|
-
.replace(/"/g, '"')
|
|
199
|
-
.replace(/'/g, ''');
|
|
200
|
-
}
|
|
201
|
-
return escaped;
|
|
202
|
-
};
|
|
203
|
-
|
|
204
183
|
_.extend = function(obj) {
|
|
205
184
|
_.each(slice.call(arguments, 1), function(source) {
|
|
206
185
|
for (var prop in source) {
|
|
@@ -376,33 +355,6 @@ _.formatDate = function(d) {
|
|
|
376
355
|
pad(d.getUTCSeconds());
|
|
377
356
|
};
|
|
378
357
|
|
|
379
|
-
_.safewrap = function(f) {
|
|
380
|
-
return function() {
|
|
381
|
-
try {
|
|
382
|
-
return f.apply(this, arguments);
|
|
383
|
-
} catch (e) {
|
|
384
|
-
console.critical('Implementation error. Please turn on debug and contact support@mixpanel.com.');
|
|
385
|
-
if (Config.DEBUG){
|
|
386
|
-
console.critical(e);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
_.safewrap_class = function(klass, functions) {
|
|
393
|
-
for (var i = 0; i < functions.length; i++) {
|
|
394
|
-
klass.prototype[functions[i]] = _.safewrap(klass.prototype[functions[i]]);
|
|
395
|
-
}
|
|
396
|
-
};
|
|
397
|
-
|
|
398
|
-
_.safewrap_instance_methods = function(obj) {
|
|
399
|
-
for (var func in obj) {
|
|
400
|
-
if (typeof(obj[func]) === 'function') {
|
|
401
|
-
obj[func] = _.safewrap(obj[func]);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
};
|
|
405
|
-
|
|
406
358
|
_.strip_empty_properties = function(p) {
|
|
407
359
|
var ret = {};
|
|
408
360
|
_.each(p, function(v, k) {
|
|
@@ -944,10 +896,12 @@ _.UUID = (function() {
|
|
|
944
896
|
// This is to block various web spiders from executing our JS and
|
|
945
897
|
// sending false tracking data
|
|
946
898
|
var BLOCKED_UA_STRS = [
|
|
899
|
+
'ahrefsbot',
|
|
947
900
|
'baiduspider',
|
|
948
901
|
'bingbot',
|
|
949
902
|
'bingpreview',
|
|
950
903
|
'facebookexternal',
|
|
904
|
+
'petalbot',
|
|
951
905
|
'pinterest',
|
|
952
906
|
'screaming frog',
|
|
953
907
|
'yahoo! slurp',
|
|
@@ -1644,13 +1598,13 @@ _.info = {
|
|
|
1644
1598
|
properties: function() {
|
|
1645
1599
|
return _.extend(_.strip_empty_properties({
|
|
1646
1600
|
'$os': _.info.os(),
|
|
1647
|
-
'$browser': _.info.browser(userAgent, navigator
|
|
1601
|
+
'$browser': _.info.browser(userAgent, navigator.vendor, windowOpera),
|
|
1648
1602
|
'$referrer': document$1.referrer,
|
|
1649
1603
|
'$referring_domain': _.info.referringDomain(document$1.referrer),
|
|
1650
1604
|
'$device': _.info.device(userAgent)
|
|
1651
1605
|
}), {
|
|
1652
1606
|
'$current_url': window$1.location.href,
|
|
1653
|
-
'$browser_version': _.info.browserVersion(userAgent, navigator
|
|
1607
|
+
'$browser_version': _.info.browserVersion(userAgent, navigator.vendor, windowOpera),
|
|
1654
1608
|
'$screen_height': screen.height,
|
|
1655
1609
|
'$screen_width': screen.width,
|
|
1656
1610
|
'mp_lib': 'web',
|
|
@@ -1663,9 +1617,9 @@ _.info = {
|
|
|
1663
1617
|
people_properties: function() {
|
|
1664
1618
|
return _.extend(_.strip_empty_properties({
|
|
1665
1619
|
'$os': _.info.os(),
|
|
1666
|
-
'$browser': _.info.browser(userAgent, navigator
|
|
1620
|
+
'$browser': _.info.browser(userAgent, navigator.vendor, windowOpera)
|
|
1667
1621
|
}), {
|
|
1668
|
-
'$browser_version': _.info.browserVersion(userAgent, navigator
|
|
1622
|
+
'$browser_version': _.info.browserVersion(userAgent, navigator.vendor, windowOpera)
|
|
1669
1623
|
});
|
|
1670
1624
|
},
|
|
1671
1625
|
|
|
@@ -1673,7 +1627,7 @@ _.info = {
|
|
|
1673
1627
|
return _.strip_empty_properties({
|
|
1674
1628
|
'mp_page': page,
|
|
1675
1629
|
'mp_referrer': document$1.referrer,
|
|
1676
|
-
'mp_browser': _.info.browser(userAgent, navigator
|
|
1630
|
+
'mp_browser': _.info.browser(userAgent, navigator.vendor, windowOpera),
|
|
1677
1631
|
'mp_platform': _.info.os()
|
|
1678
1632
|
});
|
|
1679
1633
|
}
|
|
@@ -1684,28 +1638,6 @@ var cheap_guid = function(maxlen) {
|
|
|
1684
1638
|
return maxlen ? guid.substring(0, maxlen) : guid;
|
|
1685
1639
|
};
|
|
1686
1640
|
|
|
1687
|
-
/**
|
|
1688
|
-
* Check deterministically whether to include or exclude from a feature rollout/test based on the
|
|
1689
|
-
* given string and the desired percentage to include.
|
|
1690
|
-
* @param {String} str - string to run the check against (for instance a project's token)
|
|
1691
|
-
* @param {String} feature - name of feature (for inclusion in hash, to ensure different results
|
|
1692
|
-
* for different features)
|
|
1693
|
-
* @param {Number} percent_allowed - percentage chance that a given string will be included
|
|
1694
|
-
* @returns {Boolean} whether the given string should be included
|
|
1695
|
-
*/
|
|
1696
|
-
var determine_eligibility = _.safewrap(function(str, feature, percent_allowed) {
|
|
1697
|
-
str = str + feature;
|
|
1698
|
-
|
|
1699
|
-
// Bernstein's hash: http://www.cse.yorku.ca/~oz/hash.html#djb2
|
|
1700
|
-
var hash = 5381;
|
|
1701
|
-
for (var i = 0; i < str.length; i++) {
|
|
1702
|
-
hash = ((hash << 5) + hash) + str.charCodeAt(i);
|
|
1703
|
-
hash = hash & hash;
|
|
1704
|
-
}
|
|
1705
|
-
var dart = (hash >>> 0) % 100;
|
|
1706
|
-
return dart < percent_allowed;
|
|
1707
|
-
});
|
|
1708
|
-
|
|
1709
1641
|
// naive way to extract domain name (example.com) from full hostname (my.sub.example.com)
|
|
1710
1642
|
var SIMPLE_DOMAIN_MATCH_REGEX = /[a-z0-9][a-z0-9-]*\.[a-z]+$/i;
|
|
1711
1643
|
// this next one attempts to account for some ccSLDs, e.g. extracting oxford.ac.uk from www.oxford.ac.uk
|
|
@@ -2077,6 +2009,7 @@ var RequestQueue = function(storageKey, options) {
|
|
|
2077
2009
|
options = options || {};
|
|
2078
2010
|
this.storageKey = storageKey;
|
|
2079
2011
|
this.storage = options.storage || window.localStorage;
|
|
2012
|
+
this.reportError = options.errorReporter || _.bind(logger$1.error, logger$1);
|
|
2080
2013
|
this.lock = new SharedLock(storageKey, {storage: this.storage});
|
|
2081
2014
|
|
|
2082
2015
|
this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
|
|
@@ -2114,18 +2047,18 @@ RequestQueue.prototype.enqueue = function(item, flushInterval, cb) {
|
|
|
2114
2047
|
this.memQueue.push(queueEntry);
|
|
2115
2048
|
}
|
|
2116
2049
|
} catch(err) {
|
|
2117
|
-
|
|
2050
|
+
this.reportError('Error enqueueing item', item);
|
|
2118
2051
|
succeeded = false;
|
|
2119
2052
|
}
|
|
2120
2053
|
if (cb) {
|
|
2121
2054
|
cb(succeeded);
|
|
2122
2055
|
}
|
|
2123
|
-
}, this), function lockFailure(err) {
|
|
2124
|
-
|
|
2056
|
+
}, this), _.bind(function lockFailure(err) {
|
|
2057
|
+
this.reportError('Error acquiring storage lock', err);
|
|
2125
2058
|
if (cb) {
|
|
2126
2059
|
cb(false);
|
|
2127
2060
|
}
|
|
2128
|
-
}, this.pid);
|
|
2061
|
+
}, this), this.pid);
|
|
2129
2062
|
};
|
|
2130
2063
|
|
|
2131
2064
|
/**
|
|
@@ -2185,25 +2118,61 @@ RequestQueue.prototype.removeItemsByID = function(ids, cb) {
|
|
|
2185
2118
|
_.each(ids, function(id) { idSet[id] = true; });
|
|
2186
2119
|
|
|
2187
2120
|
this.memQueue = filterOutIDsAndInvalid(this.memQueue, idSet);
|
|
2188
|
-
|
|
2121
|
+
|
|
2122
|
+
var removeFromStorage = _.bind(function() {
|
|
2189
2123
|
var succeeded;
|
|
2190
2124
|
try {
|
|
2191
2125
|
var storedQueue = this.readFromStorage();
|
|
2192
2126
|
storedQueue = filterOutIDsAndInvalid(storedQueue, idSet);
|
|
2193
2127
|
succeeded = this.saveToStorage(storedQueue);
|
|
2128
|
+
|
|
2129
|
+
// an extra check: did storage report success but somehow
|
|
2130
|
+
// the items are still there?
|
|
2131
|
+
if (succeeded) {
|
|
2132
|
+
storedQueue = this.readFromStorage();
|
|
2133
|
+
for (var i = 0; i < storedQueue.length; i++) {
|
|
2134
|
+
var item = storedQueue[i];
|
|
2135
|
+
if (item['id'] && !!idSet[item['id']]) {
|
|
2136
|
+
this.reportError('Item not removed from storage');
|
|
2137
|
+
return false;
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2194
2141
|
} catch(err) {
|
|
2195
|
-
|
|
2142
|
+
this.reportError('Error removing items', ids);
|
|
2196
2143
|
succeeded = false;
|
|
2197
2144
|
}
|
|
2145
|
+
return succeeded;
|
|
2146
|
+
}, this);
|
|
2147
|
+
|
|
2148
|
+
this.lock.withLock(function lockAcquired() {
|
|
2149
|
+
var succeeded = removeFromStorage();
|
|
2198
2150
|
if (cb) {
|
|
2199
2151
|
cb(succeeded);
|
|
2200
2152
|
}
|
|
2201
|
-
},
|
|
2202
|
-
|
|
2153
|
+
}, _.bind(function lockFailure(err) {
|
|
2154
|
+
var succeeded = false;
|
|
2155
|
+
this.reportError('Error acquiring storage lock', err);
|
|
2156
|
+
if (!localStorageSupported(this.storage, true)) {
|
|
2157
|
+
// Looks like localStorage writes have stopped working sometime after
|
|
2158
|
+
// initialization (probably full), and so nobody can acquire locks
|
|
2159
|
+
// anymore. Consider it temporarily safe to remove items without the
|
|
2160
|
+
// lock, since nobody's writing successfully anyway.
|
|
2161
|
+
succeeded = removeFromStorage();
|
|
2162
|
+
if (!succeeded) {
|
|
2163
|
+
// OK, we couldn't even write out the smaller queue. Try clearing it
|
|
2164
|
+
// entirely.
|
|
2165
|
+
try {
|
|
2166
|
+
this.storage.removeItem(this.storageKey);
|
|
2167
|
+
} catch(err) {
|
|
2168
|
+
this.reportError('Error clearing queue', err);
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2203
2172
|
if (cb) {
|
|
2204
|
-
cb(
|
|
2173
|
+
cb(succeeded);
|
|
2205
2174
|
}
|
|
2206
|
-
}, this.pid);
|
|
2175
|
+
}, this), this.pid);
|
|
2207
2176
|
};
|
|
2208
2177
|
|
|
2209
2178
|
// internal helper for RequestQueue.updatePayloads
|
|
@@ -2238,18 +2207,18 @@ RequestQueue.prototype.updatePayloads = function(itemsToUpdate, cb) {
|
|
|
2238
2207
|
storedQueue = updatePayloads(storedQueue, itemsToUpdate);
|
|
2239
2208
|
succeeded = this.saveToStorage(storedQueue);
|
|
2240
2209
|
} catch(err) {
|
|
2241
|
-
|
|
2210
|
+
this.reportError('Error updating items', itemsToUpdate);
|
|
2242
2211
|
succeeded = false;
|
|
2243
2212
|
}
|
|
2244
2213
|
if (cb) {
|
|
2245
2214
|
cb(succeeded);
|
|
2246
2215
|
}
|
|
2247
|
-
}, this), function lockFailure(err) {
|
|
2248
|
-
|
|
2216
|
+
}, this), _.bind(function lockFailure(err) {
|
|
2217
|
+
this.reportError('Error acquiring storage lock', err);
|
|
2249
2218
|
if (cb) {
|
|
2250
2219
|
cb(false);
|
|
2251
2220
|
}
|
|
2252
|
-
}, this.pid);
|
|
2221
|
+
}, this), this.pid);
|
|
2253
2222
|
};
|
|
2254
2223
|
|
|
2255
2224
|
/**
|
|
@@ -2263,12 +2232,12 @@ RequestQueue.prototype.readFromStorage = function() {
|
|
|
2263
2232
|
if (storageEntry) {
|
|
2264
2233
|
storageEntry = JSONParse(storageEntry);
|
|
2265
2234
|
if (!_.isArray(storageEntry)) {
|
|
2266
|
-
|
|
2235
|
+
this.reportError('Invalid storage entry:', storageEntry);
|
|
2267
2236
|
storageEntry = null;
|
|
2268
2237
|
}
|
|
2269
2238
|
}
|
|
2270
2239
|
} catch (err) {
|
|
2271
|
-
|
|
2240
|
+
this.reportError('Error retrieving queue', err);
|
|
2272
2241
|
storageEntry = null;
|
|
2273
2242
|
}
|
|
2274
2243
|
return storageEntry || [];
|
|
@@ -2282,7 +2251,7 @@ RequestQueue.prototype.saveToStorage = function(queue) {
|
|
|
2282
2251
|
this.storage.setItem(this.storageKey, JSONStringify(queue));
|
|
2283
2252
|
return true;
|
|
2284
2253
|
} catch (err) {
|
|
2285
|
-
|
|
2254
|
+
this.reportError('Error saving queue', err);
|
|
2286
2255
|
return false;
|
|
2287
2256
|
}
|
|
2288
2257
|
};
|
|
@@ -2309,17 +2278,23 @@ var logger = console_with_prefix('batch');
|
|
|
2309
2278
|
* @constructor
|
|
2310
2279
|
*/
|
|
2311
2280
|
var RequestBatcher = function(storageKey, options) {
|
|
2312
|
-
this.
|
|
2281
|
+
this.errorReporter = options.errorReporter;
|
|
2282
|
+
this.queue = new RequestQueue(storageKey, {
|
|
2283
|
+
errorReporter: _.bind(this.reportError, this),
|
|
2284
|
+
storage: options.storage
|
|
2285
|
+
});
|
|
2313
2286
|
|
|
2314
2287
|
this.libConfig = options.libConfig;
|
|
2315
2288
|
this.sendRequest = options.sendRequestFunc;
|
|
2316
2289
|
this.beforeSendHook = options.beforeSendHook;
|
|
2290
|
+
this.stopAllBatching = options.stopAllBatchingFunc;
|
|
2317
2291
|
|
|
2318
2292
|
// seed variable batch size + flush interval with configured values
|
|
2319
2293
|
this.batchSize = this.libConfig['batch_size'];
|
|
2320
2294
|
this.flushInterval = this.libConfig['batch_flush_interval_ms'];
|
|
2321
2295
|
|
|
2322
2296
|
this.stopped = !this.libConfig['batch_autostart'];
|
|
2297
|
+
this.consecutiveRemovalFailures = 0;
|
|
2323
2298
|
};
|
|
2324
2299
|
|
|
2325
2300
|
/**
|
|
@@ -2335,6 +2310,7 @@ RequestBatcher.prototype.enqueue = function(item, cb) {
|
|
|
2335
2310
|
*/
|
|
2336
2311
|
RequestBatcher.prototype.start = function() {
|
|
2337
2312
|
this.stopped = false;
|
|
2313
|
+
this.consecutiveRemovalFailures = 0;
|
|
2338
2314
|
this.flush();
|
|
2339
2315
|
};
|
|
2340
2316
|
|
|
@@ -2439,14 +2415,14 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
2439
2415
|
res.error === 'timeout' &&
|
|
2440
2416
|
new Date().getTime() - startTime >= timeoutMS
|
|
2441
2417
|
) {
|
|
2442
|
-
|
|
2418
|
+
this.reportError('Network timeout; retrying');
|
|
2443
2419
|
this.flush();
|
|
2444
2420
|
} else if (
|
|
2445
2421
|
_.isObject(res) &&
|
|
2446
2422
|
res.xhr_req &&
|
|
2447
|
-
(res.xhr_req['status'] >= 500 || res.xhr_req['status']
|
|
2423
|
+
(res.xhr_req['status'] >= 500 || res.xhr_req['status'] === 429 || res.error === 'timeout')
|
|
2448
2424
|
) {
|
|
2449
|
-
// network or API error, retry
|
|
2425
|
+
// network or API error, or 429 Too Many Requests, retry
|
|
2450
2426
|
var retryMS = this.flushInterval * 2;
|
|
2451
2427
|
var headers = res.xhr_req['responseHeaders'];
|
|
2452
2428
|
if (headers) {
|
|
@@ -2456,17 +2432,17 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
2456
2432
|
}
|
|
2457
2433
|
}
|
|
2458
2434
|
retryMS = Math.min(MAX_RETRY_INTERVAL_MS, retryMS);
|
|
2459
|
-
|
|
2435
|
+
this.reportError('Error; retry in ' + retryMS + ' ms');
|
|
2460
2436
|
this.scheduleFlush(retryMS);
|
|
2461
2437
|
} else if (_.isObject(res) && res.xhr_req && res.xhr_req['status'] === 413) {
|
|
2462
2438
|
// 413 Payload Too Large
|
|
2463
2439
|
if (batch.length > 1) {
|
|
2464
2440
|
var halvedBatchSize = Math.max(1, Math.floor(currentBatchSize / 2));
|
|
2465
2441
|
this.batchSize = Math.min(this.batchSize, halvedBatchSize, batch.length - 1);
|
|
2466
|
-
|
|
2442
|
+
this.reportError('413 response; reducing batch size to ' + this.batchSize);
|
|
2467
2443
|
this.resetFlush();
|
|
2468
2444
|
} else {
|
|
2469
|
-
|
|
2445
|
+
this.reportError('Single-event request too large; dropping', batch);
|
|
2470
2446
|
this.resetBatchSize();
|
|
2471
2447
|
removeItemsFromQueue = true;
|
|
2472
2448
|
}
|
|
@@ -2479,12 +2455,25 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
2479
2455
|
if (removeItemsFromQueue) {
|
|
2480
2456
|
this.queue.removeItemsByID(
|
|
2481
2457
|
_.map(batch, function(item) { return item['id']; }),
|
|
2482
|
-
_.bind(
|
|
2458
|
+
_.bind(function(succeeded) {
|
|
2459
|
+
if (succeeded) {
|
|
2460
|
+
this.consecutiveRemovalFailures = 0;
|
|
2461
|
+
this.flush(); // handle next batch if the queue isn't empty
|
|
2462
|
+
} else {
|
|
2463
|
+
this.reportError('Failed to remove items from queue');
|
|
2464
|
+
if (++this.consecutiveRemovalFailures > 5) {
|
|
2465
|
+
this.reportError('Too many queue failures; disabling batching system.');
|
|
2466
|
+
this.stopAllBatching();
|
|
2467
|
+
} else {
|
|
2468
|
+
this.resetFlush();
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
}, this)
|
|
2483
2472
|
);
|
|
2484
2473
|
}
|
|
2485
2474
|
|
|
2486
2475
|
} catch(err) {
|
|
2487
|
-
|
|
2476
|
+
this.reportError('Error handling API response', err);
|
|
2488
2477
|
this.resetFlush();
|
|
2489
2478
|
}
|
|
2490
2479
|
}, this);
|
|
@@ -2501,11 +2490,28 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
2501
2490
|
this.sendRequest(dataForRequest, requestOptions, batchSendCallback);
|
|
2502
2491
|
|
|
2503
2492
|
} catch(err) {
|
|
2504
|
-
|
|
2493
|
+
this.reportError('Error flushing request queue', err);
|
|
2505
2494
|
this.resetFlush();
|
|
2506
2495
|
}
|
|
2507
2496
|
};
|
|
2508
2497
|
|
|
2498
|
+
/**
|
|
2499
|
+
* Log error to global logger and optional user-defined logger.
|
|
2500
|
+
*/
|
|
2501
|
+
RequestBatcher.prototype.reportError = function(msg, err) {
|
|
2502
|
+
logger.error.apply(logger.error, arguments);
|
|
2503
|
+
if (this.errorReporter) {
|
|
2504
|
+
try {
|
|
2505
|
+
if (!(err instanceof Error)) {
|
|
2506
|
+
err = new Error(msg);
|
|
2507
|
+
}
|
|
2508
|
+
this.errorReporter(msg, err);
|
|
2509
|
+
} catch(err) {
|
|
2510
|
+
logger.error(err);
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
};
|
|
2514
|
+
|
|
2509
2515
|
/**
|
|
2510
2516
|
* A function used to track a Mixpanel event (e.g. MixpanelLib.track)
|
|
2511
2517
|
* @callback trackFunction
|
|
@@ -3016,9 +3022,13 @@ MixpanelGroup.prototype.union = addOptOutCheckMixpanelGroup(function(list_name,
|
|
|
3016
3022
|
* Permanently delete a group.
|
|
3017
3023
|
*
|
|
3018
3024
|
* ### Usage:
|
|
3025
|
+
*
|
|
3019
3026
|
* mixpanel.get_group('company', 'mixpanel').delete();
|
|
3027
|
+
*
|
|
3028
|
+
* @param {Function} [callback] If provided, the callback will be called after the tracking event
|
|
3020
3029
|
*/
|
|
3021
3030
|
MixpanelGroup.prototype['delete'] = addOptOutCheckMixpanelGroup(function(callback) {
|
|
3031
|
+
// bracket notation above prevents a minification error related to reserved words
|
|
3022
3032
|
var data = this.delete_action();
|
|
3023
3033
|
return this._send_request(data, callback);
|
|
3024
3034
|
});
|
|
@@ -3073,2755 +3083,929 @@ MixpanelGroup.prototype['union'] = MixpanelGroup.prototype.union;
|
|
|
3073
3083
|
MixpanelGroup.prototype['unset'] = MixpanelGroup.prototype.unset;
|
|
3074
3084
|
MixpanelGroup.prototype['toString'] = MixpanelGroup.prototype.toString;
|
|
3075
3085
|
|
|
3076
|
-
/*
|
|
3077
|
-
* Constants
|
|
3078
|
-
*/
|
|
3079
|
-
/** @const */ var SET_QUEUE_KEY = '__mps';
|
|
3080
|
-
/** @const */ var SET_ONCE_QUEUE_KEY = '__mpso';
|
|
3081
|
-
/** @const */ var UNSET_QUEUE_KEY = '__mpus';
|
|
3082
|
-
/** @const */ var ADD_QUEUE_KEY = '__mpa';
|
|
3083
|
-
/** @const */ var APPEND_QUEUE_KEY = '__mpap';
|
|
3084
|
-
/** @const */ var REMOVE_QUEUE_KEY = '__mpr';
|
|
3085
|
-
/** @const */ var UNION_QUEUE_KEY = '__mpu';
|
|
3086
|
-
// This key is deprecated, but we want to check for it to see whether aliasing is allowed.
|
|
3087
|
-
/** @const */ var PEOPLE_DISTINCT_ID_KEY = '$people_distinct_id';
|
|
3088
|
-
/** @const */ var ALIAS_ID_KEY = '__alias';
|
|
3089
|
-
/** @const */ var CAMPAIGN_IDS_KEY = '__cmpns';
|
|
3090
|
-
/** @const */ var EVENT_TIMERS_KEY = '__timers';
|
|
3091
|
-
/** @const */ var RESERVED_PROPERTIES = [
|
|
3092
|
-
SET_QUEUE_KEY,
|
|
3093
|
-
SET_ONCE_QUEUE_KEY,
|
|
3094
|
-
UNSET_QUEUE_KEY,
|
|
3095
|
-
ADD_QUEUE_KEY,
|
|
3096
|
-
APPEND_QUEUE_KEY,
|
|
3097
|
-
REMOVE_QUEUE_KEY,
|
|
3098
|
-
UNION_QUEUE_KEY,
|
|
3099
|
-
PEOPLE_DISTINCT_ID_KEY,
|
|
3100
|
-
ALIAS_ID_KEY,
|
|
3101
|
-
CAMPAIGN_IDS_KEY,
|
|
3102
|
-
EVENT_TIMERS_KEY
|
|
3103
|
-
];
|
|
3104
|
-
|
|
3105
3086
|
/**
|
|
3106
|
-
* Mixpanel
|
|
3087
|
+
* Mixpanel People Object
|
|
3107
3088
|
* @constructor
|
|
3108
3089
|
*/
|
|
3109
|
-
var
|
|
3110
|
-
this['props'] = {};
|
|
3111
|
-
this.campaign_params_saved = false;
|
|
3112
|
-
|
|
3113
|
-
if (config['persistence_name']) {
|
|
3114
|
-
this.name = 'mp_' + config['persistence_name'];
|
|
3115
|
-
} else {
|
|
3116
|
-
this.name = 'mp_' + config['token'] + '_mixpanel';
|
|
3117
|
-
}
|
|
3118
|
-
|
|
3119
|
-
var storage_type = config['persistence'];
|
|
3120
|
-
if (storage_type !== 'cookie' && storage_type !== 'localStorage') {
|
|
3121
|
-
console.critical('Unknown persistence type ' + storage_type + '; falling back to cookie');
|
|
3122
|
-
storage_type = config['persistence'] = 'cookie';
|
|
3123
|
-
}
|
|
3124
|
-
|
|
3125
|
-
if (storage_type === 'localStorage' && _.localStorage.is_supported()) {
|
|
3126
|
-
this.storage = _.localStorage;
|
|
3127
|
-
} else {
|
|
3128
|
-
this.storage = _.cookie;
|
|
3129
|
-
}
|
|
3090
|
+
var MixpanelPeople = function() {};
|
|
3130
3091
|
|
|
3131
|
-
|
|
3132
|
-
this.update_config(config);
|
|
3133
|
-
this.upgrade(config);
|
|
3134
|
-
this.save();
|
|
3135
|
-
};
|
|
3092
|
+
_.extend(MixpanelPeople.prototype, apiActions);
|
|
3136
3093
|
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
// Filter out reserved properties
|
|
3140
|
-
_.each(this['props'], function(v, k) {
|
|
3141
|
-
if (!_.include(RESERVED_PROPERTIES, k)) {
|
|
3142
|
-
p[k] = v;
|
|
3143
|
-
}
|
|
3144
|
-
});
|
|
3145
|
-
return p;
|
|
3094
|
+
MixpanelPeople.prototype._init = function(mixpanel_instance) {
|
|
3095
|
+
this._mixpanel = mixpanel_instance;
|
|
3146
3096
|
};
|
|
3147
3097
|
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3098
|
+
/*
|
|
3099
|
+
* Set properties on a user record.
|
|
3100
|
+
*
|
|
3101
|
+
* ### Usage:
|
|
3102
|
+
*
|
|
3103
|
+
* mixpanel.people.set('gender', 'm');
|
|
3104
|
+
*
|
|
3105
|
+
* // or set multiple properties at once
|
|
3106
|
+
* mixpanel.people.set({
|
|
3107
|
+
* 'Company': 'Acme',
|
|
3108
|
+
* 'Plan': 'Premium',
|
|
3109
|
+
* 'Upgrade date': new Date()
|
|
3110
|
+
* });
|
|
3111
|
+
* // properties can be strings, integers, dates, or lists
|
|
3112
|
+
*
|
|
3113
|
+
* @param {Object|String} prop If a string, this is the name of the property. If an object, this is an associative array of names and values.
|
|
3114
|
+
* @param {*} [to] A value to set on the given property name
|
|
3115
|
+
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3116
|
+
*/
|
|
3117
|
+
MixpanelPeople.prototype.set = addOptOutCheckMixpanelPeople(function(prop, to, callback) {
|
|
3118
|
+
var data = this.set_action(prop, to);
|
|
3119
|
+
if (_.isObject(prop)) {
|
|
3120
|
+
callback = to;
|
|
3155
3121
|
}
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
var upgrade_from_old_lib = config['upgrade'],
|
|
3160
|
-
old_cookie_name,
|
|
3161
|
-
old_cookie;
|
|
3162
|
-
|
|
3163
|
-
if (upgrade_from_old_lib) {
|
|
3164
|
-
old_cookie_name = 'mp_super_properties';
|
|
3165
|
-
// Case where they had a custom cookie name before.
|
|
3166
|
-
if (typeof(upgrade_from_old_lib) === 'string') {
|
|
3167
|
-
old_cookie_name = upgrade_from_old_lib;
|
|
3168
|
-
}
|
|
3169
|
-
|
|
3170
|
-
old_cookie = this.storage.parse(old_cookie_name);
|
|
3171
|
-
|
|
3172
|
-
// remove the cookie
|
|
3173
|
-
this.storage.remove(old_cookie_name);
|
|
3174
|
-
this.storage.remove(old_cookie_name, true);
|
|
3175
|
-
|
|
3176
|
-
if (old_cookie) {
|
|
3177
|
-
this['props'] = _.extend(
|
|
3178
|
-
this['props'],
|
|
3179
|
-
old_cookie['all'],
|
|
3180
|
-
old_cookie['events']
|
|
3181
|
-
);
|
|
3182
|
-
}
|
|
3122
|
+
// make sure that the referrer info has been updated and saved
|
|
3123
|
+
if (this._get_config('save_referrer')) {
|
|
3124
|
+
this._mixpanel['persistence'].update_referrer_info(document.referrer);
|
|
3183
3125
|
}
|
|
3184
3126
|
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3127
|
+
// update $set object with default people properties
|
|
3128
|
+
data[SET_ACTION] = _.extend(
|
|
3129
|
+
{},
|
|
3130
|
+
_.info.people_properties(),
|
|
3131
|
+
this._mixpanel['persistence'].get_referrer_info(),
|
|
3132
|
+
data[SET_ACTION]
|
|
3133
|
+
);
|
|
3134
|
+
return this._send_request(data, callback);
|
|
3135
|
+
});
|
|
3194
3136
|
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3137
|
+
/*
|
|
3138
|
+
* Set properties on a user record, only if they do not yet exist.
|
|
3139
|
+
* This will not overwrite previous people property values, unlike
|
|
3140
|
+
* people.set().
|
|
3141
|
+
*
|
|
3142
|
+
* ### Usage:
|
|
3143
|
+
*
|
|
3144
|
+
* mixpanel.people.set_once('First Login Date', new Date());
|
|
3145
|
+
*
|
|
3146
|
+
* // or set multiple properties at once
|
|
3147
|
+
* mixpanel.people.set_once({
|
|
3148
|
+
* 'First Login Date': new Date(),
|
|
3149
|
+
* 'Starting Plan': 'Premium'
|
|
3150
|
+
* });
|
|
3151
|
+
*
|
|
3152
|
+
* // properties can be strings, integers or dates
|
|
3153
|
+
*
|
|
3154
|
+
* @param {Object|String} prop If a string, this is the name of the property. If an object, this is an associative array of names and values.
|
|
3155
|
+
* @param {*} [to] A value to set on the given property name
|
|
3156
|
+
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3157
|
+
*/
|
|
3158
|
+
MixpanelPeople.prototype.set_once = addOptOutCheckMixpanelPeople(function(prop, to, callback) {
|
|
3159
|
+
var data = this.set_once_action(prop, to);
|
|
3160
|
+
if (_.isObject(prop)) {
|
|
3161
|
+
callback = to;
|
|
3199
3162
|
}
|
|
3163
|
+
return this._send_request(data, callback);
|
|
3164
|
+
});
|
|
3200
3165
|
|
|
3201
|
-
|
|
3202
|
-
|
|
3166
|
+
/*
|
|
3167
|
+
* Unset properties on a user record (permanently removes the properties and their values from a profile).
|
|
3168
|
+
*
|
|
3169
|
+
* ### Usage:
|
|
3170
|
+
*
|
|
3171
|
+
* mixpanel.people.unset('gender');
|
|
3172
|
+
*
|
|
3173
|
+
* // or unset multiple properties at once
|
|
3174
|
+
* mixpanel.people.unset(['gender', 'Company']);
|
|
3175
|
+
*
|
|
3176
|
+
* @param {Array|String} prop If a string, this is the name of the property. If an array, this is a list of property names.
|
|
3177
|
+
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3178
|
+
*/
|
|
3179
|
+
MixpanelPeople.prototype.unset = addOptOutCheckMixpanelPeople(function(prop, callback) {
|
|
3180
|
+
var data = this.unset_action(prop);
|
|
3181
|
+
return this._send_request(data, callback);
|
|
3182
|
+
});
|
|
3203
3183
|
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
}
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
// remove both domain and subdomain cookies
|
|
3229
|
-
this.storage.remove(this.name, false, this.cookie_domain);
|
|
3230
|
-
this.storage.remove(this.name, true, this.cookie_domain);
|
|
3231
|
-
};
|
|
3232
|
-
|
|
3233
|
-
// removes the storage entry and deletes all loaded data
|
|
3234
|
-
// forced name for tests
|
|
3235
|
-
MixpanelPersistence.prototype.clear = function() {
|
|
3236
|
-
this.remove();
|
|
3237
|
-
this['props'] = {};
|
|
3238
|
-
};
|
|
3239
|
-
|
|
3240
|
-
/**
|
|
3241
|
-
* @param {Object} props
|
|
3242
|
-
* @param {*=} default_value
|
|
3243
|
-
* @param {number=} days
|
|
3184
|
+
/*
|
|
3185
|
+
* Increment/decrement numeric people analytics properties.
|
|
3186
|
+
*
|
|
3187
|
+
* ### Usage:
|
|
3188
|
+
*
|
|
3189
|
+
* mixpanel.people.increment('page_views', 1);
|
|
3190
|
+
*
|
|
3191
|
+
* // or, for convenience, if you're just incrementing a counter by
|
|
3192
|
+
* // 1, you can simply do
|
|
3193
|
+
* mixpanel.people.increment('page_views');
|
|
3194
|
+
*
|
|
3195
|
+
* // to decrement a counter, pass a negative number
|
|
3196
|
+
* mixpanel.people.increment('credits_left', -1);
|
|
3197
|
+
*
|
|
3198
|
+
* // like mixpanel.people.set(), you can increment multiple
|
|
3199
|
+
* // properties at once:
|
|
3200
|
+
* mixpanel.people.increment({
|
|
3201
|
+
* counter1: 1,
|
|
3202
|
+
* counter2: 6
|
|
3203
|
+
* });
|
|
3204
|
+
*
|
|
3205
|
+
* @param {Object|String} prop If a string, this is the name of the property. If an object, this is an associative array of names and numeric values.
|
|
3206
|
+
* @param {Number} [by] An amount to increment the given property
|
|
3207
|
+
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3244
3208
|
*/
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3209
|
+
MixpanelPeople.prototype.increment = addOptOutCheckMixpanelPeople(function(prop, by, callback) {
|
|
3210
|
+
var data = {};
|
|
3211
|
+
var $add = {};
|
|
3212
|
+
if (_.isObject(prop)) {
|
|
3213
|
+
_.each(prop, function(v, k) {
|
|
3214
|
+
if (!this._is_reserved_property(k)) {
|
|
3215
|
+
if (isNaN(parseFloat(v))) {
|
|
3216
|
+
console.error('Invalid increment value passed to mixpanel.people.increment - must be a number');
|
|
3217
|
+
return;
|
|
3218
|
+
} else {
|
|
3219
|
+
$add[k] = v;
|
|
3220
|
+
}
|
|
3253
3221
|
}
|
|
3254
3222
|
}, this);
|
|
3223
|
+
callback = by;
|
|
3224
|
+
} else {
|
|
3225
|
+
// convenience: mixpanel.people.increment('property'); will
|
|
3226
|
+
// increment 'property' by 1
|
|
3227
|
+
if (_.isUndefined(by)) {
|
|
3228
|
+
by = 1;
|
|
3229
|
+
}
|
|
3230
|
+
$add[prop] = by;
|
|
3231
|
+
}
|
|
3232
|
+
data[ADD_ACTION] = $add;
|
|
3255
3233
|
|
|
3256
|
-
|
|
3234
|
+
return this._send_request(data, callback);
|
|
3235
|
+
});
|
|
3257
3236
|
|
|
3258
|
-
|
|
3237
|
+
/*
|
|
3238
|
+
* Append a value to a list-valued people analytics property.
|
|
3239
|
+
*
|
|
3240
|
+
* ### Usage:
|
|
3241
|
+
*
|
|
3242
|
+
* // append a value to a list, creating it if needed
|
|
3243
|
+
* mixpanel.people.append('pages_visited', 'homepage');
|
|
3244
|
+
*
|
|
3245
|
+
* // like mixpanel.people.set(), you can append multiple
|
|
3246
|
+
* // properties at once:
|
|
3247
|
+
* mixpanel.people.append({
|
|
3248
|
+
* list1: 'bob',
|
|
3249
|
+
* list2: 123
|
|
3250
|
+
* });
|
|
3251
|
+
*
|
|
3252
|
+
* @param {Object|String} list_name If a string, this is the name of the property. If an object, this is an associative array of names and values.
|
|
3253
|
+
* @param {*} [value] value An item to append to the list
|
|
3254
|
+
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3255
|
+
*/
|
|
3256
|
+
MixpanelPeople.prototype.append = addOptOutCheckMixpanelPeople(function(list_name, value, callback) {
|
|
3257
|
+
if (_.isObject(list_name)) {
|
|
3258
|
+
callback = value;
|
|
3259
3259
|
}
|
|
3260
|
-
|
|
3261
|
-
|
|
3260
|
+
var data = this.append_action(list_name, value);
|
|
3261
|
+
return this._send_request(data, callback);
|
|
3262
|
+
});
|
|
3262
3263
|
|
|
3263
|
-
|
|
3264
|
-
*
|
|
3265
|
-
*
|
|
3264
|
+
/*
|
|
3265
|
+
* Remove a value from a list-valued people analytics property.
|
|
3266
|
+
*
|
|
3267
|
+
* ### Usage:
|
|
3268
|
+
*
|
|
3269
|
+
* mixpanel.people.remove('School', 'UCB');
|
|
3270
|
+
*
|
|
3271
|
+
* @param {Object|String} list_name If a string, this is the name of the property. If an object, this is an associative array of names and values.
|
|
3272
|
+
* @param {*} [value] value Item to remove from the list
|
|
3273
|
+
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3266
3274
|
*/
|
|
3267
|
-
|
|
3268
|
-
if (_.isObject(
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
_.extend(this['props'], props);
|
|
3272
|
-
|
|
3273
|
-
this.save();
|
|
3274
|
-
|
|
3275
|
-
return true;
|
|
3275
|
+
MixpanelPeople.prototype.remove = addOptOutCheckMixpanelPeople(function(list_name, value, callback) {
|
|
3276
|
+
if (_.isObject(list_name)) {
|
|
3277
|
+
callback = value;
|
|
3276
3278
|
}
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
+
var data = this.remove_action(list_name, value);
|
|
3280
|
+
return this._send_request(data, callback);
|
|
3281
|
+
});
|
|
3279
3282
|
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3283
|
+
/*
|
|
3284
|
+
* Merge a given list with a list-valued people analytics property,
|
|
3285
|
+
* excluding duplicate values.
|
|
3286
|
+
*
|
|
3287
|
+
* ### Usage:
|
|
3288
|
+
*
|
|
3289
|
+
* // merge a value to a list, creating it if needed
|
|
3290
|
+
* mixpanel.people.union('pages_visited', 'homepage');
|
|
3291
|
+
*
|
|
3292
|
+
* // like mixpanel.people.set(), you can append multiple
|
|
3293
|
+
* // properties at once:
|
|
3294
|
+
* mixpanel.people.union({
|
|
3295
|
+
* list1: 'bob',
|
|
3296
|
+
* list2: 123
|
|
3297
|
+
* });
|
|
3298
|
+
*
|
|
3299
|
+
* // like mixpanel.people.append(), you can append multiple
|
|
3300
|
+
* // values to the same list:
|
|
3301
|
+
* mixpanel.people.union({
|
|
3302
|
+
* list1: ['bob', 'billy']
|
|
3303
|
+
* });
|
|
3304
|
+
*
|
|
3305
|
+
* @param {Object|String} list_name If a string, this is the name of the property. If an object, this is an associative array of names and values.
|
|
3306
|
+
* @param {*} [value] Value / values to merge with the given property
|
|
3307
|
+
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3308
|
+
*/
|
|
3309
|
+
MixpanelPeople.prototype.union = addOptOutCheckMixpanelPeople(function(list_name, values, callback) {
|
|
3310
|
+
if (_.isObject(list_name)) {
|
|
3311
|
+
callback = values;
|
|
3284
3312
|
}
|
|
3285
|
-
|
|
3313
|
+
var data = this.union_action(list_name, values);
|
|
3314
|
+
return this._send_request(data, callback);
|
|
3315
|
+
});
|
|
3286
3316
|
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3317
|
+
/*
|
|
3318
|
+
* Record that you have charged the current user a certain amount
|
|
3319
|
+
* of money. Charges recorded with track_charge() will appear in the
|
|
3320
|
+
* Mixpanel revenue report.
|
|
3321
|
+
*
|
|
3322
|
+
* ### Usage:
|
|
3323
|
+
*
|
|
3324
|
+
* // charge a user $50
|
|
3325
|
+
* mixpanel.people.track_charge(50);
|
|
3326
|
+
*
|
|
3327
|
+
* // charge a user $30.50 on the 2nd of january
|
|
3328
|
+
* mixpanel.people.track_charge(30.50, {
|
|
3329
|
+
* '$time': new Date('jan 1 2012')
|
|
3330
|
+
* });
|
|
3331
|
+
*
|
|
3332
|
+
* @param {Number} amount The amount of money charged to the current user
|
|
3333
|
+
* @param {Object} [properties] An associative array of properties associated with the charge
|
|
3334
|
+
* @param {Function} [callback] If provided, the callback will be called when the server responds
|
|
3335
|
+
*/
|
|
3336
|
+
MixpanelPeople.prototype.track_charge = addOptOutCheckMixpanelPeople(function(amount, properties, callback) {
|
|
3337
|
+
if (!_.isNumber(amount)) {
|
|
3338
|
+
amount = parseFloat(amount);
|
|
3339
|
+
if (isNaN(amount)) {
|
|
3340
|
+
console.error('Invalid value passed to mixpanel.people.track_charge - must be a number');
|
|
3341
|
+
return;
|
|
3296
3342
|
}
|
|
3297
3343
|
}
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3344
|
+
|
|
3345
|
+
return this.append('$transactions', _.extend({
|
|
3346
|
+
'$amount': amount
|
|
3347
|
+
}, properties), callback);
|
|
3301
3348
|
});
|
|
3302
3349
|
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3350
|
+
/*
|
|
3351
|
+
* Permanently clear all revenue report transactions from the
|
|
3352
|
+
* current user's people analytics profile.
|
|
3353
|
+
*
|
|
3354
|
+
* ### Usage:
|
|
3355
|
+
*
|
|
3356
|
+
* mixpanel.people.clear_charges();
|
|
3357
|
+
*
|
|
3358
|
+
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3359
|
+
*/
|
|
3360
|
+
MixpanelPeople.prototype.clear_charges = function(callback) {
|
|
3361
|
+
return this.set('$transactions', [], callback);
|
|
3362
|
+
};
|
|
3363
|
+
|
|
3364
|
+
/*
|
|
3365
|
+
* Permanently deletes the current people analytics profile from
|
|
3366
|
+
* Mixpanel (using the current distinct_id).
|
|
3367
|
+
*
|
|
3368
|
+
* ### Usage:
|
|
3369
|
+
*
|
|
3370
|
+
* // remove the all data you have stored about the current user
|
|
3371
|
+
* mixpanel.people.delete_user();
|
|
3372
|
+
*
|
|
3373
|
+
*/
|
|
3374
|
+
MixpanelPeople.prototype.delete_user = function() {
|
|
3375
|
+
if (!this._identify_called()) {
|
|
3376
|
+
console.error('mixpanel.people.delete_user() requires you to call identify() first');
|
|
3377
|
+
return;
|
|
3307
3378
|
}
|
|
3379
|
+
var data = {'$delete': this._mixpanel.get_distinct_id()};
|
|
3380
|
+
return this._send_request(data);
|
|
3308
3381
|
};
|
|
3309
3382
|
|
|
3310
|
-
|
|
3311
|
-
this.
|
|
3383
|
+
MixpanelPeople.prototype.toString = function() {
|
|
3384
|
+
return this._mixpanel.toString() + '.people';
|
|
3312
3385
|
};
|
|
3313
3386
|
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
this.
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3387
|
+
MixpanelPeople.prototype._send_request = function(data, callback) {
|
|
3388
|
+
data['$token'] = this._get_config('token');
|
|
3389
|
+
data['$distinct_id'] = this._mixpanel.get_distinct_id();
|
|
3390
|
+
var device_id = this._mixpanel.get_property('$device_id');
|
|
3391
|
+
var user_id = this._mixpanel.get_property('$user_id');
|
|
3392
|
+
var had_persisted_distinct_id = this._mixpanel.get_property('$had_persisted_distinct_id');
|
|
3393
|
+
if (device_id) {
|
|
3394
|
+
data['$device_id'] = device_id;
|
|
3395
|
+
}
|
|
3396
|
+
if (user_id) {
|
|
3397
|
+
data['$user_id'] = user_id;
|
|
3398
|
+
}
|
|
3399
|
+
if (had_persisted_distinct_id) {
|
|
3400
|
+
data['$had_persisted_distinct_id'] = had_persisted_distinct_id;
|
|
3401
|
+
}
|
|
3322
3402
|
|
|
3323
|
-
|
|
3324
|
-
return _.strip_empty_properties({
|
|
3325
|
-
'$initial_referrer': this['props']['$initial_referrer'],
|
|
3326
|
-
'$initial_referring_domain': this['props']['$initial_referring_domain']
|
|
3327
|
-
});
|
|
3328
|
-
};
|
|
3403
|
+
var date_encoded_data = _.encodeDates(data);
|
|
3329
3404
|
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3405
|
+
if (!this._identify_called()) {
|
|
3406
|
+
this._enqueue(data);
|
|
3407
|
+
if (!_.isUndefined(callback)) {
|
|
3408
|
+
if (this._get_config('verbose')) {
|
|
3409
|
+
callback({status: -1, error: null});
|
|
3410
|
+
} else {
|
|
3411
|
+
callback(-1);
|
|
3412
|
+
}
|
|
3337
3413
|
}
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
return props;
|
|
3341
|
-
};
|
|
3342
|
-
|
|
3343
|
-
MixpanelPersistence.prototype.update_config = function(config) {
|
|
3344
|
-
this.default_expiry = this.expire_days = config['cookie_expiration'];
|
|
3345
|
-
this.set_disabled(config['disable_persistence']);
|
|
3346
|
-
this.set_cookie_domain(config['cookie_domain']);
|
|
3347
|
-
this.set_cross_site(config['cross_site_cookie']);
|
|
3348
|
-
this.set_cross_subdomain(config['cross_subdomain_cookie']);
|
|
3349
|
-
this.set_secure(config['secure_cookie']);
|
|
3350
|
-
};
|
|
3351
|
-
|
|
3352
|
-
MixpanelPersistence.prototype.set_disabled = function(disabled) {
|
|
3353
|
-
this.disabled = disabled;
|
|
3354
|
-
if (this.disabled) {
|
|
3355
|
-
this.remove();
|
|
3356
|
-
} else {
|
|
3357
|
-
this.save();
|
|
3358
|
-
}
|
|
3359
|
-
};
|
|
3360
|
-
|
|
3361
|
-
MixpanelPersistence.prototype.set_cookie_domain = function(cookie_domain) {
|
|
3362
|
-
if (cookie_domain !== this.cookie_domain) {
|
|
3363
|
-
this.remove();
|
|
3364
|
-
this.cookie_domain = cookie_domain;
|
|
3365
|
-
this.save();
|
|
3414
|
+
return _.truncate(date_encoded_data, 255);
|
|
3366
3415
|
}
|
|
3367
|
-
};
|
|
3368
3416
|
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
this.
|
|
3373
|
-
this.
|
|
3374
|
-
}
|
|
3417
|
+
return this._mixpanel._track_or_batch({
|
|
3418
|
+
type: 'people',
|
|
3419
|
+
data: date_encoded_data,
|
|
3420
|
+
endpoint: this._get_config('api_host') + '/engage/',
|
|
3421
|
+
batcher: this._mixpanel.request_batchers.people
|
|
3422
|
+
}, callback);
|
|
3375
3423
|
};
|
|
3376
3424
|
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
this.cross_subdomain = cross_subdomain;
|
|
3380
|
-
this.remove();
|
|
3381
|
-
this.save();
|
|
3382
|
-
}
|
|
3425
|
+
MixpanelPeople.prototype._get_config = function(conf_var) {
|
|
3426
|
+
return this._mixpanel.get_config(conf_var);
|
|
3383
3427
|
};
|
|
3384
3428
|
|
|
3385
|
-
|
|
3386
|
-
return this.
|
|
3429
|
+
MixpanelPeople.prototype._identify_called = function() {
|
|
3430
|
+
return this._mixpanel._flags.identify_called === true;
|
|
3387
3431
|
};
|
|
3388
3432
|
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
this.
|
|
3393
|
-
|
|
3433
|
+
// Queue up engage operations if identify hasn't been called yet.
|
|
3434
|
+
MixpanelPeople.prototype._enqueue = function(data) {
|
|
3435
|
+
if (SET_ACTION in data) {
|
|
3436
|
+
this._mixpanel['persistence']._add_to_people_queue(SET_ACTION, data);
|
|
3437
|
+
} else if (SET_ONCE_ACTION in data) {
|
|
3438
|
+
this._mixpanel['persistence']._add_to_people_queue(SET_ONCE_ACTION, data);
|
|
3439
|
+
} else if (UNSET_ACTION in data) {
|
|
3440
|
+
this._mixpanel['persistence']._add_to_people_queue(UNSET_ACTION, data);
|
|
3441
|
+
} else if (ADD_ACTION in data) {
|
|
3442
|
+
this._mixpanel['persistence']._add_to_people_queue(ADD_ACTION, data);
|
|
3443
|
+
} else if (APPEND_ACTION in data) {
|
|
3444
|
+
this._mixpanel['persistence']._add_to_people_queue(APPEND_ACTION, data);
|
|
3445
|
+
} else if (REMOVE_ACTION in data) {
|
|
3446
|
+
this._mixpanel['persistence']._add_to_people_queue(REMOVE_ACTION, data);
|
|
3447
|
+
} else if (UNION_ACTION in data) {
|
|
3448
|
+
this._mixpanel['persistence']._add_to_people_queue(UNION_ACTION, data);
|
|
3449
|
+
} else {
|
|
3450
|
+
console.error('Invalid call to _enqueue():', data);
|
|
3394
3451
|
}
|
|
3395
3452
|
};
|
|
3396
3453
|
|
|
3397
|
-
|
|
3398
|
-
var
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
set_once_q = this._get_or_create_queue(SET_ONCE_ACTION),
|
|
3402
|
-
unset_q = this._get_or_create_queue(UNSET_ACTION),
|
|
3403
|
-
add_q = this._get_or_create_queue(ADD_ACTION),
|
|
3404
|
-
union_q = this._get_or_create_queue(UNION_ACTION),
|
|
3405
|
-
remove_q = this._get_or_create_queue(REMOVE_ACTION, []),
|
|
3406
|
-
append_q = this._get_or_create_queue(APPEND_ACTION, []);
|
|
3454
|
+
MixpanelPeople.prototype._flush_one_queue = function(action, action_method, callback, queue_to_params_fn) {
|
|
3455
|
+
var _this = this;
|
|
3456
|
+
var queued_data = _.extend({}, this._mixpanel['persistence']._get_queue(action));
|
|
3457
|
+
var action_params = queued_data;
|
|
3407
3458
|
|
|
3408
|
-
if (
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
_.each(q_data, function(v, k) {
|
|
3421
|
-
if (!(k in set_once_q)) {
|
|
3422
|
-
set_once_q[k] = v;
|
|
3459
|
+
if (!_.isUndefined(queued_data) && _.isObject(queued_data) && !_.isEmptyObject(queued_data)) {
|
|
3460
|
+
_this._mixpanel['persistence']._pop_from_people_queue(action, queued_data);
|
|
3461
|
+
if (queue_to_params_fn) {
|
|
3462
|
+
action_params = queue_to_params_fn(queued_data);
|
|
3463
|
+
}
|
|
3464
|
+
action_method.call(_this, action_params, function(response, data) {
|
|
3465
|
+
// on bad response, we want to add it back to the queue
|
|
3466
|
+
if (response === 0) {
|
|
3467
|
+
_this._mixpanel['persistence']._add_to_people_queue(action, queued_data);
|
|
3468
|
+
}
|
|
3469
|
+
if (!_.isUndefined(callback)) {
|
|
3470
|
+
callback(response, data);
|
|
3423
3471
|
}
|
|
3424
3472
|
});
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
_.each(q_data, function(prop) {
|
|
3473
|
+
}
|
|
3474
|
+
};
|
|
3428
3475
|
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
delete append_obj[prop];
|
|
3438
|
-
}
|
|
3439
|
-
});
|
|
3476
|
+
// Flush queued engage operations - order does not matter,
|
|
3477
|
+
// and there are network level race conditions anyway
|
|
3478
|
+
MixpanelPeople.prototype._flush = function(
|
|
3479
|
+
_set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback
|
|
3480
|
+
) {
|
|
3481
|
+
var _this = this;
|
|
3482
|
+
var $append_queue = this._mixpanel['persistence']._get_queue(APPEND_ACTION);
|
|
3483
|
+
var $remove_queue = this._mixpanel['persistence']._get_queue(REMOVE_ACTION);
|
|
3440
3484
|
|
|
3441
|
-
|
|
3485
|
+
this._flush_one_queue(SET_ACTION, this.set, _set_callback);
|
|
3486
|
+
this._flush_one_queue(SET_ONCE_ACTION, this.set_once, _set_once_callback);
|
|
3487
|
+
this._flush_one_queue(UNSET_ACTION, this.unset, _unset_callback, function(queue) { return _.keys(queue); });
|
|
3488
|
+
this._flush_one_queue(ADD_ACTION, this.increment, _add_callback);
|
|
3489
|
+
this._flush_one_queue(UNION_ACTION, this.union, _union_callback);
|
|
3442
3490
|
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
if (
|
|
3449
|
-
|
|
3450
|
-
} else {
|
|
3451
|
-
// If it doesn't exist, update the add
|
|
3452
|
-
// queue
|
|
3453
|
-
if (!(k in add_q)) {
|
|
3454
|
-
add_q[k] = 0;
|
|
3455
|
-
}
|
|
3456
|
-
add_q[k] += v;
|
|
3491
|
+
// we have to fire off each $append individually since there is
|
|
3492
|
+
// no concat method server side
|
|
3493
|
+
if (!_.isUndefined($append_queue) && _.isArray($append_queue) && $append_queue.length) {
|
|
3494
|
+
var $append_item;
|
|
3495
|
+
var append_callback = function(response, data) {
|
|
3496
|
+
if (response === 0) {
|
|
3497
|
+
_this._mixpanel['persistence']._add_to_people_queue(APPEND_ACTION, $append_item);
|
|
3457
3498
|
}
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
} else if (q_key === UNION_QUEUE_KEY) {
|
|
3461
|
-
_.each(q_data, function(v, k) {
|
|
3462
|
-
if (_.isArray(v)) {
|
|
3463
|
-
if (!(k in union_q)) {
|
|
3464
|
-
union_q[k] = [];
|
|
3465
|
-
}
|
|
3466
|
-
// We may send duplicates, the server will dedup them.
|
|
3467
|
-
union_q[k] = union_q[k].concat(v);
|
|
3499
|
+
if (!_.isUndefined(_append_callback)) {
|
|
3500
|
+
_append_callback(response, data);
|
|
3468
3501
|
}
|
|
3469
|
-
}
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3502
|
+
};
|
|
3503
|
+
for (var i = $append_queue.length - 1; i >= 0; i--) {
|
|
3504
|
+
$append_item = $append_queue.pop();
|
|
3505
|
+
if (!_.isEmptyObject($append_item)) {
|
|
3506
|
+
_this.append($append_item, append_callback);
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
// Save the shortened append queue
|
|
3510
|
+
_this._mixpanel['persistence'].save();
|
|
3477
3511
|
}
|
|
3478
3512
|
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) {
|
|
3486
|
-
var q = this._get_queue(queue);
|
|
3487
|
-
if (!_.isUndefined(q)) {
|
|
3488
|
-
_.each(data, function(v, k) {
|
|
3489
|
-
if (queue === APPEND_ACTION || queue === REMOVE_ACTION) {
|
|
3490
|
-
// list actions: only remove if both k+v match
|
|
3491
|
-
// e.g. remove should not override append in a case like
|
|
3492
|
-
// append({foo: 'bar'}); remove({foo: 'qux'})
|
|
3493
|
-
_.each(q, function(queued_action) {
|
|
3494
|
-
if (queued_action[k] === v) {
|
|
3495
|
-
delete queued_action[k];
|
|
3496
|
-
}
|
|
3497
|
-
});
|
|
3498
|
-
} else {
|
|
3499
|
-
delete q[k];
|
|
3513
|
+
// same for $remove
|
|
3514
|
+
if (!_.isUndefined($remove_queue) && _.isArray($remove_queue) && $remove_queue.length) {
|
|
3515
|
+
var $remove_item;
|
|
3516
|
+
var remove_callback = function(response, data) {
|
|
3517
|
+
if (response === 0) {
|
|
3518
|
+
_this._mixpanel['persistence']._add_to_people_queue(REMOVE_ACTION, $remove_item);
|
|
3500
3519
|
}
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
} else if (queue === UNSET_ACTION) {
|
|
3513
|
-
return UNSET_QUEUE_KEY;
|
|
3514
|
-
} else if (queue === ADD_ACTION) {
|
|
3515
|
-
return ADD_QUEUE_KEY;
|
|
3516
|
-
} else if (queue === APPEND_ACTION) {
|
|
3517
|
-
return APPEND_QUEUE_KEY;
|
|
3518
|
-
} else if (queue === REMOVE_ACTION) {
|
|
3519
|
-
return REMOVE_QUEUE_KEY;
|
|
3520
|
-
} else if (queue === UNION_ACTION) {
|
|
3521
|
-
return UNION_QUEUE_KEY;
|
|
3522
|
-
} else {
|
|
3523
|
-
console.error('Invalid queue:', queue);
|
|
3520
|
+
if (!_.isUndefined(_remove_callback)) {
|
|
3521
|
+
_remove_callback(response, data);
|
|
3522
|
+
}
|
|
3523
|
+
};
|
|
3524
|
+
for (var j = $remove_queue.length - 1; j >= 0; j--) {
|
|
3525
|
+
$remove_item = $remove_queue.pop();
|
|
3526
|
+
if (!_.isEmptyObject($remove_item)) {
|
|
3527
|
+
_this.remove($remove_item, remove_callback);
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
_this._mixpanel['persistence'].save();
|
|
3524
3531
|
}
|
|
3525
3532
|
};
|
|
3526
3533
|
|
|
3527
|
-
|
|
3528
|
-
return
|
|
3529
|
-
};
|
|
3530
|
-
MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val) {
|
|
3531
|
-
var key = this._get_queue_key(queue);
|
|
3532
|
-
default_val = _.isUndefined(default_val) ? {} : default_val;
|
|
3533
|
-
|
|
3534
|
-
return this['props'][key] || (this['props'][key] = default_val);
|
|
3535
|
-
};
|
|
3536
|
-
|
|
3537
|
-
MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) {
|
|
3538
|
-
var timers = this['props'][EVENT_TIMERS_KEY] || {};
|
|
3539
|
-
timers[event_name] = timestamp;
|
|
3540
|
-
this['props'][EVENT_TIMERS_KEY] = timers;
|
|
3541
|
-
this.save();
|
|
3534
|
+
MixpanelPeople.prototype._is_reserved_property = function(prop) {
|
|
3535
|
+
return prop === '$distinct_id' || prop === '$token' || prop === '$device_id' || prop === '$user_id' || prop === '$had_persisted_distinct_id';
|
|
3542
3536
|
};
|
|
3543
3537
|
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3538
|
+
// MixpanelPeople Exports
|
|
3539
|
+
MixpanelPeople.prototype['set'] = MixpanelPeople.prototype.set;
|
|
3540
|
+
MixpanelPeople.prototype['set_once'] = MixpanelPeople.prototype.set_once;
|
|
3541
|
+
MixpanelPeople.prototype['unset'] = MixpanelPeople.prototype.unset;
|
|
3542
|
+
MixpanelPeople.prototype['increment'] = MixpanelPeople.prototype.increment;
|
|
3543
|
+
MixpanelPeople.prototype['append'] = MixpanelPeople.prototype.append;
|
|
3544
|
+
MixpanelPeople.prototype['remove'] = MixpanelPeople.prototype.remove;
|
|
3545
|
+
MixpanelPeople.prototype['union'] = MixpanelPeople.prototype.union;
|
|
3546
|
+
MixpanelPeople.prototype['track_charge'] = MixpanelPeople.prototype.track_charge;
|
|
3547
|
+
MixpanelPeople.prototype['clear_charges'] = MixpanelPeople.prototype.clear_charges;
|
|
3548
|
+
MixpanelPeople.prototype['delete_user'] = MixpanelPeople.prototype.delete_user;
|
|
3549
|
+
MixpanelPeople.prototype['toString'] = MixpanelPeople.prototype.toString;
|
|
3553
3550
|
|
|
3554
3551
|
/*
|
|
3555
|
-
*
|
|
3552
|
+
* Constants
|
|
3556
3553
|
*/
|
|
3554
|
+
/** @const */ var SET_QUEUE_KEY = '__mps';
|
|
3555
|
+
/** @const */ var SET_ONCE_QUEUE_KEY = '__mpso';
|
|
3556
|
+
/** @const */ var UNSET_QUEUE_KEY = '__mpus';
|
|
3557
|
+
/** @const */ var ADD_QUEUE_KEY = '__mpa';
|
|
3558
|
+
/** @const */ var APPEND_QUEUE_KEY = '__mpap';
|
|
3559
|
+
/** @const */ var REMOVE_QUEUE_KEY = '__mpr';
|
|
3560
|
+
/** @const */ var UNION_QUEUE_KEY = '__mpu';
|
|
3561
|
+
// This key is deprecated, but we want to check for it to see whether aliasing is allowed.
|
|
3562
|
+
/** @const */ var PEOPLE_DISTINCT_ID_KEY = '$people_distinct_id';
|
|
3563
|
+
/** @const */ var ALIAS_ID_KEY = '__alias';
|
|
3564
|
+
/** @const */ var EVENT_TIMERS_KEY = '__timers';
|
|
3565
|
+
/** @const */ var RESERVED_PROPERTIES = [
|
|
3566
|
+
SET_QUEUE_KEY,
|
|
3567
|
+
SET_ONCE_QUEUE_KEY,
|
|
3568
|
+
UNSET_QUEUE_KEY,
|
|
3569
|
+
ADD_QUEUE_KEY,
|
|
3570
|
+
APPEND_QUEUE_KEY,
|
|
3571
|
+
REMOVE_QUEUE_KEY,
|
|
3572
|
+
UNION_QUEUE_KEY,
|
|
3573
|
+
PEOPLE_DISTINCT_ID_KEY,
|
|
3574
|
+
ALIAS_ID_KEY,
|
|
3575
|
+
EVENT_TIMERS_KEY
|
|
3576
|
+
];
|
|
3557
3577
|
|
|
3558
|
-
|
|
3559
|
-
*
|
|
3578
|
+
/**
|
|
3579
|
+
* Mixpanel Persistence Object
|
|
3580
|
+
* @constructor
|
|
3560
3581
|
*/
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
/** @const */ var WINDOW_KEY = 'window';
|
|
3565
|
-
/** @const */ var UNIT_KEY = 'unit';
|
|
3566
|
-
/** @const */ var VALUE_KEY = 'value';
|
|
3567
|
-
/** @const */ var HOUR_KEY = 'hour';
|
|
3568
|
-
/** @const */ var DAY_KEY = 'day';
|
|
3569
|
-
/** @const */ var WEEK_KEY = 'week';
|
|
3570
|
-
/** @const */ var MONTH_KEY = 'month';
|
|
3571
|
-
|
|
3572
|
-
// Operands
|
|
3573
|
-
/** @const */ var EVENT_PROPERTY = 'event';
|
|
3574
|
-
/** @const */ var LITERAL_PROPERTY = 'literal';
|
|
3575
|
-
|
|
3576
|
-
// Binary Operators
|
|
3577
|
-
/** @const */ var AND_OPERATOR = 'and';
|
|
3578
|
-
/** @const */ var OR_OPERATOR = 'or';
|
|
3579
|
-
/** @const */ var IN_OPERATOR = 'in';
|
|
3580
|
-
/** @const */ var NOT_IN_OPERATOR = 'not in';
|
|
3581
|
-
/** @const */ var PLUS_OPERATOR = '+';
|
|
3582
|
-
/** @const */ var MINUS_OPERATOR = '-';
|
|
3583
|
-
/** @const */ var MUL_OPERATOR = '*';
|
|
3584
|
-
/** @const */ var DIV_OPERATOR = '/';
|
|
3585
|
-
/** @const */ var MOD_OPERATOR = '%';
|
|
3586
|
-
/** @const */ var EQUALS_OPERATOR = '==';
|
|
3587
|
-
/** @const */ var NOT_EQUALS_OPERATOR = '!=';
|
|
3588
|
-
/** @const */ var GREATER_OPERATOR = '>';
|
|
3589
|
-
/** @const */ var LESS_OPERATOR = '<';
|
|
3590
|
-
/** @const */ var GREATER_EQUAL_OPERATOR = '>=';
|
|
3591
|
-
/** @const */ var LESS_EQUAL_OPERATOR = '<=';
|
|
3592
|
-
|
|
3593
|
-
// Typecast Operators
|
|
3594
|
-
/** @const */ var BOOLEAN_OPERATOR = 'boolean';
|
|
3595
|
-
/** @const */ var DATETIME_OPERATOR = 'datetime';
|
|
3596
|
-
/** @const */ var LIST_OPERATOR = 'list';
|
|
3597
|
-
/** @const */ var NUMBER_OPERATOR = 'number';
|
|
3598
|
-
/** @const */ var STRING_OPERATOR = 'string';
|
|
3599
|
-
|
|
3600
|
-
// Unary Operators
|
|
3601
|
-
/** @const */ var NOT_OPERATOR = 'not';
|
|
3602
|
-
/** @const */ var DEFINED_OPERATOR = 'defined';
|
|
3603
|
-
/** @const */ var NOT_DEFINED_OPERATOR = 'not defined';
|
|
3604
|
-
|
|
3605
|
-
// Special literals
|
|
3606
|
-
/** @const */ var NOW_LITERAL = 'now';
|
|
3607
|
-
|
|
3608
|
-
// Type cast functions
|
|
3609
|
-
function toNumber(value) {
|
|
3610
|
-
if (value === null) {
|
|
3611
|
-
return null;
|
|
3612
|
-
}
|
|
3582
|
+
var MixpanelPersistence = function(config) {
|
|
3583
|
+
this['props'] = {};
|
|
3584
|
+
this.campaign_params_saved = false;
|
|
3613
3585
|
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
}
|
|
3619
|
-
return null;
|
|
3620
|
-
case 'boolean':
|
|
3621
|
-
return Number(value);
|
|
3622
|
-
case 'number':
|
|
3623
|
-
return value;
|
|
3624
|
-
case 'string':
|
|
3625
|
-
value = Number(value);
|
|
3626
|
-
if (!isNaN(value)) {
|
|
3627
|
-
return value;
|
|
3628
|
-
}
|
|
3629
|
-
return 0;
|
|
3586
|
+
if (config['persistence_name']) {
|
|
3587
|
+
this.name = 'mp_' + config['persistence_name'];
|
|
3588
|
+
} else {
|
|
3589
|
+
this.name = 'mp_' + config['token'] + '_mixpanel';
|
|
3630
3590
|
}
|
|
3631
|
-
return null;
|
|
3632
|
-
}
|
|
3633
3591
|
|
|
3634
|
-
|
|
3635
|
-
if (
|
|
3636
|
-
|
|
3592
|
+
var storage_type = config['persistence'];
|
|
3593
|
+
if (storage_type !== 'cookie' && storage_type !== 'localStorage') {
|
|
3594
|
+
console.critical('Unknown persistence type ' + storage_type + '; falling back to cookie');
|
|
3595
|
+
storage_type = config['persistence'] = 'cookie';
|
|
3637
3596
|
}
|
|
3638
3597
|
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
if (value === null) {
|
|
3644
|
-
return false;
|
|
3598
|
+
if (storage_type === 'localStorage' && _.localStorage.is_supported()) {
|
|
3599
|
+
this.storage = _.localStorage;
|
|
3600
|
+
} else {
|
|
3601
|
+
this.storage = _.cookie;
|
|
3645
3602
|
}
|
|
3646
3603
|
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
case 'string':
|
|
3653
|
-
return value.length > 0;
|
|
3654
|
-
case 'object':
|
|
3655
|
-
if (_.isArray(value) && value.length > 0) {
|
|
3656
|
-
return true;
|
|
3657
|
-
}
|
|
3658
|
-
if (_.isDate(value) && value.getTime() > 0) {
|
|
3659
|
-
return true;
|
|
3660
|
-
}
|
|
3661
|
-
if (_.isObject(value) && !_.isEmptyObject(value)) {
|
|
3662
|
-
return true;
|
|
3663
|
-
}
|
|
3664
|
-
return false;
|
|
3665
|
-
}
|
|
3666
|
-
return false;
|
|
3667
|
-
}
|
|
3604
|
+
this.load();
|
|
3605
|
+
this.update_config(config);
|
|
3606
|
+
this.upgrade(config);
|
|
3607
|
+
this.save();
|
|
3608
|
+
};
|
|
3668
3609
|
|
|
3669
|
-
function
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3610
|
+
MixpanelPersistence.prototype.properties = function() {
|
|
3611
|
+
var p = {};
|
|
3612
|
+
// Filter out reserved properties
|
|
3613
|
+
_.each(this['props'], function(v, k) {
|
|
3614
|
+
if (!_.include(RESERVED_PROPERTIES, k)) {
|
|
3615
|
+
p[k] = v;
|
|
3616
|
+
}
|
|
3617
|
+
});
|
|
3618
|
+
return p;
|
|
3619
|
+
};
|
|
3673
3620
|
|
|
3674
|
-
|
|
3675
|
-
}
|
|
3621
|
+
MixpanelPersistence.prototype.load = function() {
|
|
3622
|
+
if (this.disabled) { return; }
|
|
3676
3623
|
|
|
3677
|
-
|
|
3678
|
-
if (!op['operator'] || op['operator'] !== DATETIME_OPERATOR || !op['children'] || op['children'].length !== 1) {
|
|
3679
|
-
throw ('Invalid cast operator: datetime ' + op);
|
|
3680
|
-
}
|
|
3624
|
+
var entry = this.storage.parse(this.name);
|
|
3681
3625
|
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
return null;
|
|
3626
|
+
if (entry) {
|
|
3627
|
+
this['props'] = _.extend({}, entry);
|
|
3685
3628
|
}
|
|
3629
|
+
};
|
|
3686
3630
|
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
if (isNaN(d.getTime())) {
|
|
3692
|
-
return null;
|
|
3693
|
-
}
|
|
3694
|
-
return d;
|
|
3695
|
-
case 'object':
|
|
3696
|
-
if (_.isDate(v)) {
|
|
3697
|
-
return v;
|
|
3698
|
-
}
|
|
3699
|
-
}
|
|
3631
|
+
MixpanelPersistence.prototype.upgrade = function(config) {
|
|
3632
|
+
var upgrade_from_old_lib = config['upgrade'],
|
|
3633
|
+
old_cookie_name,
|
|
3634
|
+
old_cookie;
|
|
3700
3635
|
|
|
3701
|
-
|
|
3702
|
-
|
|
3636
|
+
if (upgrade_from_old_lib) {
|
|
3637
|
+
old_cookie_name = 'mp_super_properties';
|
|
3638
|
+
// Case where they had a custom cookie name before.
|
|
3639
|
+
if (typeof(upgrade_from_old_lib) === 'string') {
|
|
3640
|
+
old_cookie_name = upgrade_from_old_lib;
|
|
3641
|
+
}
|
|
3703
3642
|
|
|
3704
|
-
|
|
3705
|
-
if (!op['operator'] || op['operator'] !== LIST_OPERATOR || !op['children'] || op['children'].length !== 1) {
|
|
3706
|
-
throw ('Invalid cast operator: list ' + op);
|
|
3707
|
-
}
|
|
3643
|
+
old_cookie = this.storage.parse(old_cookie_name);
|
|
3708
3644
|
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
}
|
|
3645
|
+
// remove the cookie
|
|
3646
|
+
this.storage.remove(old_cookie_name);
|
|
3647
|
+
this.storage.remove(old_cookie_name, true);
|
|
3713
3648
|
|
|
3714
|
-
|
|
3715
|
-
|
|
3649
|
+
if (old_cookie) {
|
|
3650
|
+
this['props'] = _.extend(
|
|
3651
|
+
this['props'],
|
|
3652
|
+
old_cookie['all'],
|
|
3653
|
+
old_cookie['events']
|
|
3654
|
+
);
|
|
3655
|
+
}
|
|
3716
3656
|
}
|
|
3717
3657
|
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
throw ('Invalid cast operator: string ' + op);
|
|
3724
|
-
}
|
|
3658
|
+
if (!config['cookie_name'] && config['name'] !== 'mixpanel') {
|
|
3659
|
+
// special case to handle people with cookies of the form
|
|
3660
|
+
// mp_TOKEN_INSTANCENAME from the first release of this library
|
|
3661
|
+
old_cookie_name = 'mp_' + config['token'] + '_' + config['name'];
|
|
3662
|
+
old_cookie = this.storage.parse(old_cookie_name);
|
|
3725
3663
|
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
if (_.isDate(v)) {
|
|
3730
|
-
return v.toJSON();
|
|
3731
|
-
}
|
|
3732
|
-
return JSON.stringify(v);
|
|
3733
|
-
}
|
|
3734
|
-
return String(v);
|
|
3735
|
-
}
|
|
3664
|
+
if (old_cookie) {
|
|
3665
|
+
this.storage.remove(old_cookie_name);
|
|
3666
|
+
this.storage.remove(old_cookie_name, true);
|
|
3736
3667
|
|
|
3737
|
-
//
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3668
|
+
// Save the prop values that were in the cookie from before -
|
|
3669
|
+
// this should only happen once as we delete the old one.
|
|
3670
|
+
this.register_once(old_cookie);
|
|
3671
|
+
}
|
|
3741
3672
|
}
|
|
3742
3673
|
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
function evaluateOr(op, properties) {
|
|
3747
|
-
if (!op['operator'] || op['operator'] !== OR_OPERATOR || !op['children'] || op['children'].length !== 2) {
|
|
3748
|
-
throw ('Invalid operator: OR ' + op);
|
|
3749
|
-
}
|
|
3674
|
+
if (this.storage === _.localStorage) {
|
|
3675
|
+
old_cookie = _.cookie.parse(this.name);
|
|
3750
3676
|
|
|
3751
|
-
|
|
3752
|
-
|
|
3677
|
+
_.cookie.remove(this.name);
|
|
3678
|
+
_.cookie.remove(this.name, true);
|
|
3753
3679
|
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3680
|
+
if (old_cookie) {
|
|
3681
|
+
this.register_once(old_cookie);
|
|
3682
|
+
}
|
|
3757
3683
|
}
|
|
3758
|
-
|
|
3759
|
-
var rightValue = evaluateSelector(op['children'][1], properties);
|
|
3684
|
+
};
|
|
3760
3685
|
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3686
|
+
MixpanelPersistence.prototype.save = function() {
|
|
3687
|
+
if (this.disabled) { return; }
|
|
3688
|
+
this.storage.set(
|
|
3689
|
+
this.name,
|
|
3690
|
+
_.JSONEncode(this['props']),
|
|
3691
|
+
this.expire_days,
|
|
3692
|
+
this.cross_subdomain,
|
|
3693
|
+
this.secure,
|
|
3694
|
+
this.cross_site,
|
|
3695
|
+
this.cookie_domain
|
|
3696
|
+
);
|
|
3697
|
+
};
|
|
3764
3698
|
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
}
|
|
3699
|
+
MixpanelPersistence.prototype.remove = function() {
|
|
3700
|
+
// remove both domain and subdomain cookies
|
|
3701
|
+
this.storage.remove(this.name, false, this.cookie_domain);
|
|
3702
|
+
this.storage.remove(this.name, true, this.cookie_domain);
|
|
3703
|
+
};
|
|
3771
3704
|
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
var r = evaluateSelector(op['children'][1], properties);
|
|
3778
|
-
|
|
3779
|
-
if (typeof l === 'number' && typeof r === 'number') {
|
|
3780
|
-
return l + r;
|
|
3781
|
-
}
|
|
3782
|
-
if (typeof l === 'string' && typeof r === 'string') {
|
|
3783
|
-
return l + r;
|
|
3784
|
-
}
|
|
3785
|
-
return null;
|
|
3786
|
-
}
|
|
3787
|
-
|
|
3788
|
-
function evaluateArithmetic(op, properties) {
|
|
3789
|
-
if (!op['operator'] || [MINUS_OPERATOR, MUL_OPERATOR, DIV_OPERATOR, MOD_OPERATOR].indexOf(op['operator']) === -1 ||
|
|
3790
|
-
!op['children'] || op['children'].length < 2) {
|
|
3791
|
-
throw ('Invalid arithmetic operator ' + op);
|
|
3792
|
-
}
|
|
3793
|
-
|
|
3794
|
-
var l = evaluateSelector(op['children'][0], properties);
|
|
3795
|
-
var r = evaluateSelector(op['children'][1], properties);
|
|
3796
|
-
|
|
3797
|
-
if (typeof l === 'number' && typeof r === 'number') {
|
|
3798
|
-
switch (op['operator']) {
|
|
3799
|
-
case MINUS_OPERATOR:
|
|
3800
|
-
return l - r;
|
|
3801
|
-
case MUL_OPERATOR:
|
|
3802
|
-
return l * r;
|
|
3803
|
-
case DIV_OPERATOR:
|
|
3804
|
-
if (r !== 0) {
|
|
3805
|
-
return l / r;
|
|
3806
|
-
}
|
|
3807
|
-
return null;
|
|
3808
|
-
case MOD_OPERATOR:
|
|
3809
|
-
if (r === 0) {
|
|
3810
|
-
return null;
|
|
3811
|
-
}
|
|
3812
|
-
if (l === 0) {
|
|
3813
|
-
return 0;
|
|
3814
|
-
}
|
|
3815
|
-
if ((l < 0 && r > 0) || (l > 0 && r < 0)) {
|
|
3816
|
-
/* Mimic python modulo - result takes sign of the divisor
|
|
3817
|
-
* if one operand is negative. */
|
|
3818
|
-
return -(Math.floor(l / r) * r - l);
|
|
3819
|
-
}
|
|
3820
|
-
return l % r;
|
|
3821
|
-
default:
|
|
3822
|
-
throw('Unknown operator: ' + op['operator']);
|
|
3823
|
-
}
|
|
3824
|
-
}
|
|
3825
|
-
|
|
3826
|
-
return null;
|
|
3827
|
-
}
|
|
3828
|
-
|
|
3829
|
-
function _isArrayEqual(l, r) {
|
|
3830
|
-
if (l === r) return true;
|
|
3831
|
-
if (l === null || r === null) return false;
|
|
3832
|
-
if (l.length !== r.length) return false;
|
|
3833
|
-
|
|
3834
|
-
for (var i = 0; i < l.length; i++) {
|
|
3835
|
-
if (l[i] !== r[i]) {
|
|
3836
|
-
return false;
|
|
3837
|
-
}
|
|
3838
|
-
}
|
|
3839
|
-
|
|
3840
|
-
return true;
|
|
3841
|
-
}
|
|
3842
|
-
|
|
3843
|
-
function _isEqual(l, r) {
|
|
3844
|
-
if ( l === null && l === r ) {
|
|
3845
|
-
return true;
|
|
3846
|
-
}
|
|
3847
|
-
if (typeof l === typeof r) {
|
|
3848
|
-
switch (typeof l) {
|
|
3849
|
-
case 'number':
|
|
3850
|
-
case 'string':
|
|
3851
|
-
case 'boolean':
|
|
3852
|
-
return l === r;
|
|
3853
|
-
case 'object':
|
|
3854
|
-
if (_.isArray(l) && _.isArray(r)) {
|
|
3855
|
-
return _isArrayEqual(l, r);
|
|
3856
|
-
}
|
|
3857
|
-
if (_.isDate(l) && _.isDate(r)) {
|
|
3858
|
-
return l.getTime() === r.getTime();
|
|
3859
|
-
}
|
|
3860
|
-
if (_.isObject(l) && _.isObject(r)) {
|
|
3861
|
-
return JSON.stringify(l) === JSON.stringify(r);
|
|
3862
|
-
}
|
|
3863
|
-
}
|
|
3864
|
-
}
|
|
3865
|
-
return false;
|
|
3866
|
-
}
|
|
3867
|
-
|
|
3868
|
-
function evaluateEquality(op, properties) {
|
|
3869
|
-
if (!op['operator'] || [EQUALS_OPERATOR, NOT_EQUALS_OPERATOR].indexOf(op['operator']) === -1 || !op['children'] || op['children'].length !== 2) {
|
|
3870
|
-
throw ('Invalid equality operator ' + op);
|
|
3871
|
-
}
|
|
3872
|
-
|
|
3873
|
-
var v = _isEqual(evaluateSelector(op['children'][0], properties), evaluateSelector(op['children'][1], properties));
|
|
3874
|
-
|
|
3875
|
-
switch (op['operator']) {
|
|
3876
|
-
case EQUALS_OPERATOR:
|
|
3877
|
-
return v;
|
|
3878
|
-
case NOT_EQUALS_OPERATOR:
|
|
3879
|
-
return !v;
|
|
3880
|
-
}
|
|
3881
|
-
}
|
|
3882
|
-
|
|
3883
|
-
function evaluateComparison(op, properties) {
|
|
3884
|
-
if (!op['operator'] ||
|
|
3885
|
-
[GREATER_OPERATOR, GREATER_EQUAL_OPERATOR, LESS_OPERATOR, LESS_EQUAL_OPERATOR].indexOf(op['operator']) === -1 ||
|
|
3886
|
-
!op['children'] || op['children'].length !== 2) {
|
|
3887
|
-
throw ('Invalid comparison operator ' + op);
|
|
3888
|
-
}
|
|
3889
|
-
var l = evaluateSelector(op['children'][0], properties);
|
|
3890
|
-
var r = evaluateSelector(op['children'][1], properties);
|
|
3891
|
-
|
|
3892
|
-
if (typeof(l) === typeof(r)) {
|
|
3893
|
-
if (typeof(r) === 'number' || _.isDate(r)) {
|
|
3894
|
-
l = toNumber(l);
|
|
3895
|
-
r = toNumber(r);
|
|
3896
|
-
switch (op['operator']) {
|
|
3897
|
-
case GREATER_OPERATOR:
|
|
3898
|
-
return l > r;
|
|
3899
|
-
case GREATER_EQUAL_OPERATOR:
|
|
3900
|
-
return l >= r;
|
|
3901
|
-
case LESS_OPERATOR:
|
|
3902
|
-
return l < r;
|
|
3903
|
-
case LESS_EQUAL_OPERATOR:
|
|
3904
|
-
return l <= r;
|
|
3905
|
-
}
|
|
3906
|
-
} else if (typeof(r) === 'string') {
|
|
3907
|
-
var compare = l.localeCompare(r);
|
|
3908
|
-
switch (op['operator']) {
|
|
3909
|
-
case GREATER_OPERATOR:
|
|
3910
|
-
return compare > 0;
|
|
3911
|
-
case GREATER_EQUAL_OPERATOR:
|
|
3912
|
-
return compare >= 0;
|
|
3913
|
-
case LESS_OPERATOR:
|
|
3914
|
-
return compare < 0;
|
|
3915
|
-
case LESS_EQUAL_OPERATOR:
|
|
3916
|
-
return compare <= 0;
|
|
3917
|
-
}
|
|
3918
|
-
}
|
|
3919
|
-
}
|
|
3920
|
-
|
|
3921
|
-
return null;
|
|
3922
|
-
}
|
|
3923
|
-
|
|
3924
|
-
function evaluateDefined(op, properties) {
|
|
3925
|
-
if (!op['operator'] || [DEFINED_OPERATOR, NOT_DEFINED_OPERATOR].indexOf(op['operator']) === -1 ||
|
|
3926
|
-
!op['children'] || op['children'].length !== 1) {
|
|
3927
|
-
throw ('Invalid defined/not defined operator: ' + op);
|
|
3928
|
-
}
|
|
3929
|
-
|
|
3930
|
-
var b = evaluateSelector(op['children'][0], properties) !== null;
|
|
3931
|
-
if (op['operator'] === NOT_DEFINED_OPERATOR) {
|
|
3932
|
-
return !b;
|
|
3933
|
-
}
|
|
3934
|
-
|
|
3935
|
-
return b;
|
|
3936
|
-
}
|
|
3937
|
-
|
|
3938
|
-
function evaluateNot(op, properties) {
|
|
3939
|
-
if (!op['operator'] || op['operator'] !== NOT_OPERATOR || !op['children'] || op['children'].length !== 1) {
|
|
3940
|
-
throw ('Invalid not operator: ' + op);
|
|
3941
|
-
}
|
|
3942
|
-
|
|
3943
|
-
var v = evaluateSelector(op['children'][0], properties);
|
|
3944
|
-
if (v === null) {
|
|
3945
|
-
return true;
|
|
3946
|
-
}
|
|
3947
|
-
|
|
3948
|
-
if (typeof(v) === 'boolean') {
|
|
3949
|
-
return !v;
|
|
3950
|
-
}
|
|
3951
|
-
|
|
3952
|
-
return null;
|
|
3953
|
-
}
|
|
3954
|
-
|
|
3955
|
-
function evaluateOperator(op, properties) {
|
|
3956
|
-
if (!op['operator']) {
|
|
3957
|
-
throw ('Invalid operator: operator key missing ' + op);
|
|
3958
|
-
}
|
|
3959
|
-
|
|
3960
|
-
switch (op['operator']) {
|
|
3961
|
-
case AND_OPERATOR:
|
|
3962
|
-
return evaluateAnd(op, properties);
|
|
3963
|
-
case OR_OPERATOR:
|
|
3964
|
-
return evaluateOr(op, properties);
|
|
3965
|
-
case IN_OPERATOR:
|
|
3966
|
-
case NOT_IN_OPERATOR:
|
|
3967
|
-
return evaluateIn(op, properties);
|
|
3968
|
-
case PLUS_OPERATOR:
|
|
3969
|
-
return evaluatePlus(op, properties);
|
|
3970
|
-
case MINUS_OPERATOR:
|
|
3971
|
-
case MUL_OPERATOR:
|
|
3972
|
-
case DIV_OPERATOR:
|
|
3973
|
-
case MOD_OPERATOR:
|
|
3974
|
-
return evaluateArithmetic(op, properties);
|
|
3975
|
-
case EQUALS_OPERATOR:
|
|
3976
|
-
case NOT_EQUALS_OPERATOR:
|
|
3977
|
-
return evaluateEquality(op, properties);
|
|
3978
|
-
case GREATER_OPERATOR:
|
|
3979
|
-
case LESS_OPERATOR:
|
|
3980
|
-
case GREATER_EQUAL_OPERATOR:
|
|
3981
|
-
case LESS_EQUAL_OPERATOR:
|
|
3982
|
-
return evaluateComparison(op, properties);
|
|
3983
|
-
case BOOLEAN_OPERATOR:
|
|
3984
|
-
return evaluateBoolean(op, properties);
|
|
3985
|
-
case DATETIME_OPERATOR:
|
|
3986
|
-
return evaluateDateTime(op, properties);
|
|
3987
|
-
case LIST_OPERATOR:
|
|
3988
|
-
return evaluateList(op, properties);
|
|
3989
|
-
case NUMBER_OPERATOR:
|
|
3990
|
-
return evaluateNumber(op, properties);
|
|
3991
|
-
case STRING_OPERATOR:
|
|
3992
|
-
return evaluateString(op, properties);
|
|
3993
|
-
case DEFINED_OPERATOR:
|
|
3994
|
-
case NOT_DEFINED_OPERATOR:
|
|
3995
|
-
return evaluateDefined(op, properties);
|
|
3996
|
-
case NOT_OPERATOR:
|
|
3997
|
-
return evaluateNot(op, properties);
|
|
3998
|
-
}
|
|
3999
|
-
}
|
|
4000
|
-
|
|
4001
|
-
function evaluateWindow(value) {
|
|
4002
|
-
var win = value[WINDOW_KEY];
|
|
4003
|
-
if (!win || !win[UNIT_KEY] || !win[VALUE_KEY]) {
|
|
4004
|
-
throw('Invalid window: missing required keys ' + JSON.stringify(value));
|
|
4005
|
-
}
|
|
4006
|
-
var out = new Date();
|
|
4007
|
-
switch (win[UNIT_KEY]) {
|
|
4008
|
-
case HOUR_KEY:
|
|
4009
|
-
out.setTime(out.getTime() + (win[VALUE_KEY]*-1*60*60*1000));
|
|
4010
|
-
break;
|
|
4011
|
-
case DAY_KEY:
|
|
4012
|
-
out.setTime(out.getTime() + (win[VALUE_KEY]*-1*24*60*60*1000));
|
|
4013
|
-
break;
|
|
4014
|
-
case WEEK_KEY:
|
|
4015
|
-
out.setTime(out.getTime() + (win[VALUE_KEY]*-1*7*24*60*60*1000));
|
|
4016
|
-
break;
|
|
4017
|
-
case MONTH_KEY:
|
|
4018
|
-
out.setTime(out.getTime() + (win[VALUE_KEY]*-1*30*24*60*60*1000));
|
|
4019
|
-
break;
|
|
4020
|
-
default:
|
|
4021
|
-
throw('Invalid unit: ' + win[UNIT_KEY]);
|
|
4022
|
-
}
|
|
4023
|
-
|
|
4024
|
-
return out;
|
|
4025
|
-
}
|
|
4026
|
-
|
|
4027
|
-
function evaluateOperand(op, properties) {
|
|
4028
|
-
if (!op['property'] || !op['value']) {
|
|
4029
|
-
throw('Invalid operand: missing required keys ' + op);
|
|
4030
|
-
}
|
|
4031
|
-
switch (op['property']) {
|
|
4032
|
-
case EVENT_PROPERTY:
|
|
4033
|
-
if (properties[op['value']] !== undefined) {
|
|
4034
|
-
return properties[op['value']];
|
|
4035
|
-
}
|
|
4036
|
-
return null;
|
|
4037
|
-
case LITERAL_PROPERTY:
|
|
4038
|
-
if (op['value'] === NOW_LITERAL) {
|
|
4039
|
-
return new Date();
|
|
4040
|
-
}
|
|
4041
|
-
if (typeof(op['value']) === 'object') {
|
|
4042
|
-
return evaluateWindow(op['value']);
|
|
4043
|
-
}
|
|
4044
|
-
return op['value'];
|
|
4045
|
-
default:
|
|
4046
|
-
throw('Invalid operand: Invalid property type ' + op['property']);
|
|
4047
|
-
}
|
|
4048
|
-
}
|
|
4049
|
-
|
|
4050
|
-
function evaluateSelector(filters, properties) {
|
|
4051
|
-
if (filters[PROPERTY_KEY]) {
|
|
4052
|
-
return evaluateOperand(filters, properties);
|
|
4053
|
-
}
|
|
4054
|
-
if (filters[OPERATOR_KEY]) {
|
|
4055
|
-
return evaluateOperator(filters, properties);
|
|
4056
|
-
}
|
|
4057
|
-
}
|
|
4058
|
-
|
|
4059
|
-
// Internal class for notification display
|
|
4060
|
-
|
|
4061
|
-
var MixpanelNotification = function(notif_data, mixpanel_instance) {
|
|
4062
|
-
_.bind_instance_methods(this);
|
|
4063
|
-
|
|
4064
|
-
this.mixpanel = mixpanel_instance;
|
|
4065
|
-
this.persistence = this.mixpanel['persistence'];
|
|
4066
|
-
this.resource_protocol = this.mixpanel.get_config('inapp_protocol');
|
|
4067
|
-
this.cdn_host = this.mixpanel.get_config('cdn');
|
|
4068
|
-
|
|
4069
|
-
this.campaign_id = _.escapeHTML(notif_data['id']);
|
|
4070
|
-
this.message_id = _.escapeHTML(notif_data['message_id']);
|
|
4071
|
-
|
|
4072
|
-
this.body = (_.escapeHTML(notif_data['body']) || '').replace(/\n/g, '<br/>');
|
|
4073
|
-
this.cta = _.escapeHTML(notif_data['cta']) || 'Close';
|
|
4074
|
-
this.notif_type = _.escapeHTML(notif_data['type']) || 'takeover';
|
|
4075
|
-
this.style = _.escapeHTML(notif_data['style']) || 'light';
|
|
4076
|
-
this.title = _.escapeHTML(notif_data['title']) || '';
|
|
4077
|
-
this.video_width = MixpanelNotification.VIDEO_WIDTH;
|
|
4078
|
-
this.video_height = MixpanelNotification.VIDEO_HEIGHT;
|
|
4079
|
-
|
|
4080
|
-
this.display_triggers = notif_data['display_triggers'] || [];
|
|
4081
|
-
|
|
4082
|
-
// These fields are url-sanitized in the backend already.
|
|
4083
|
-
this.dest_url = notif_data['cta_url'] || null;
|
|
4084
|
-
this.image_url = notif_data['image_url'] || null;
|
|
4085
|
-
this.thumb_image_url = notif_data['thumb_image_url'] || null;
|
|
4086
|
-
this.video_url = notif_data['video_url'] || null;
|
|
4087
|
-
|
|
4088
|
-
if (this.thumb_image_url && this.thumb_image_url.indexOf('//') === 0) {
|
|
4089
|
-
this.thumb_image_url = this.thumb_image_url.replace('//', this.resource_protocol);
|
|
4090
|
-
}
|
|
4091
|
-
|
|
4092
|
-
this.clickthrough = true;
|
|
4093
|
-
if (!this.dest_url) {
|
|
4094
|
-
this.dest_url = '#dismiss';
|
|
4095
|
-
this.clickthrough = false;
|
|
4096
|
-
}
|
|
4097
|
-
|
|
4098
|
-
this.mini = this.notif_type === 'mini';
|
|
4099
|
-
if (!this.mini) {
|
|
4100
|
-
this.notif_type = 'takeover';
|
|
4101
|
-
}
|
|
4102
|
-
this.notif_width = !this.mini ? MixpanelNotification.NOTIF_WIDTH : MixpanelNotification.NOTIF_WIDTH_MINI;
|
|
4103
|
-
|
|
4104
|
-
this._set_client_config();
|
|
4105
|
-
this.imgs_to_preload = this._init_image_html();
|
|
4106
|
-
this._init_video();
|
|
4107
|
-
};
|
|
4108
|
-
|
|
4109
|
-
MixpanelNotification.ANIM_TIME = 200;
|
|
4110
|
-
MixpanelNotification.MARKUP_PREFIX = 'mixpanel-notification';
|
|
4111
|
-
MixpanelNotification.BG_OPACITY = 0.6;
|
|
4112
|
-
MixpanelNotification.NOTIF_TOP = 25;
|
|
4113
|
-
MixpanelNotification.NOTIF_START_TOP = 200;
|
|
4114
|
-
MixpanelNotification.NOTIF_WIDTH = 388;
|
|
4115
|
-
MixpanelNotification.NOTIF_WIDTH_MINI = 420;
|
|
4116
|
-
MixpanelNotification.NOTIF_HEIGHT_MINI = 85;
|
|
4117
|
-
MixpanelNotification.THUMB_BORDER_SIZE = 5;
|
|
4118
|
-
MixpanelNotification.THUMB_IMG_SIZE = 60;
|
|
4119
|
-
MixpanelNotification.THUMB_OFFSET = Math.round(MixpanelNotification.THUMB_IMG_SIZE / 2);
|
|
4120
|
-
MixpanelNotification.VIDEO_WIDTH = 595;
|
|
4121
|
-
MixpanelNotification.VIDEO_HEIGHT = 334;
|
|
4122
|
-
|
|
4123
|
-
MixpanelNotification.prototype.show = function() {
|
|
4124
|
-
var self = this;
|
|
4125
|
-
this._set_client_config();
|
|
4126
|
-
|
|
4127
|
-
// don't display until HTML body exists
|
|
4128
|
-
if (!this.body_el) {
|
|
4129
|
-
setTimeout(function() { self.show(); }, 300);
|
|
4130
|
-
return;
|
|
4131
|
-
}
|
|
4132
|
-
|
|
4133
|
-
this._init_styles();
|
|
4134
|
-
this._init_notification_el();
|
|
4135
|
-
|
|
4136
|
-
// wait for any images to load before showing notification
|
|
4137
|
-
this._preload_images(this._attach_and_animate);
|
|
4138
|
-
};
|
|
4139
|
-
|
|
4140
|
-
MixpanelNotification.prototype.dismiss = _.safewrap(function() {
|
|
4141
|
-
if (!this.marked_as_shown) {
|
|
4142
|
-
// unexpected condition: user interacted with notif even though we didn't consider it
|
|
4143
|
-
// visible (see _mark_as_shown()); send tracking signals to mark delivery
|
|
4144
|
-
this._mark_delivery({'invisible': true});
|
|
4145
|
-
}
|
|
4146
|
-
|
|
4147
|
-
var exiting_el = this.showing_video ? this._get_el('video') : this._get_notification_display_el();
|
|
4148
|
-
if (this.use_transitions) {
|
|
4149
|
-
this._remove_class('bg', 'visible');
|
|
4150
|
-
this._add_class(exiting_el, 'exiting');
|
|
4151
|
-
setTimeout(this._remove_notification_el, MixpanelNotification.ANIM_TIME);
|
|
4152
|
-
} else {
|
|
4153
|
-
var notif_attr, notif_start, notif_goal;
|
|
4154
|
-
if (this.mini) {
|
|
4155
|
-
notif_attr = 'right';
|
|
4156
|
-
notif_start = 20;
|
|
4157
|
-
notif_goal = -100;
|
|
4158
|
-
} else {
|
|
4159
|
-
notif_attr = 'top';
|
|
4160
|
-
notif_start = MixpanelNotification.NOTIF_TOP;
|
|
4161
|
-
notif_goal = MixpanelNotification.NOTIF_START_TOP + MixpanelNotification.NOTIF_TOP;
|
|
4162
|
-
}
|
|
4163
|
-
this._animate_els([
|
|
4164
|
-
{
|
|
4165
|
-
el: this._get_el('bg'),
|
|
4166
|
-
attr: 'opacity',
|
|
4167
|
-
start: MixpanelNotification.BG_OPACITY,
|
|
4168
|
-
goal: 0.0
|
|
4169
|
-
},
|
|
4170
|
-
{
|
|
4171
|
-
el: exiting_el,
|
|
4172
|
-
attr: 'opacity',
|
|
4173
|
-
start: 1.0,
|
|
4174
|
-
goal: 0.0
|
|
4175
|
-
},
|
|
4176
|
-
{
|
|
4177
|
-
el: exiting_el,
|
|
4178
|
-
attr: notif_attr,
|
|
4179
|
-
start: notif_start,
|
|
4180
|
-
goal: notif_goal
|
|
4181
|
-
}
|
|
4182
|
-
], MixpanelNotification.ANIM_TIME, this._remove_notification_el);
|
|
4183
|
-
}
|
|
4184
|
-
});
|
|
4185
|
-
|
|
4186
|
-
MixpanelNotification.prototype._add_class = _.safewrap(function(el, class_name) {
|
|
4187
|
-
class_name = MixpanelNotification.MARKUP_PREFIX + '-' + class_name;
|
|
4188
|
-
if (typeof el === 'string') {
|
|
4189
|
-
el = this._get_el(el);
|
|
4190
|
-
}
|
|
4191
|
-
if (!el.className) {
|
|
4192
|
-
el.className = class_name;
|
|
4193
|
-
} else if (!~(' ' + el.className + ' ').indexOf(' ' + class_name + ' ')) {
|
|
4194
|
-
el.className += ' ' + class_name;
|
|
4195
|
-
}
|
|
4196
|
-
});
|
|
4197
|
-
MixpanelNotification.prototype._remove_class = _.safewrap(function(el, class_name) {
|
|
4198
|
-
class_name = MixpanelNotification.MARKUP_PREFIX + '-' + class_name;
|
|
4199
|
-
if (typeof el === 'string') {
|
|
4200
|
-
el = this._get_el(el);
|
|
4201
|
-
}
|
|
4202
|
-
if (el.className) {
|
|
4203
|
-
el.className = (' ' + el.className + ' ')
|
|
4204
|
-
.replace(' ' + class_name + ' ', '')
|
|
4205
|
-
.replace(/^[\s\xA0]+/, '')
|
|
4206
|
-
.replace(/[\s\xA0]+$/, '');
|
|
4207
|
-
}
|
|
4208
|
-
});
|
|
4209
|
-
|
|
4210
|
-
MixpanelNotification.prototype._animate_els = _.safewrap(function(anims, mss, done_cb, start_time) {
|
|
4211
|
-
var self = this,
|
|
4212
|
-
in_progress = false,
|
|
4213
|
-
ai, anim,
|
|
4214
|
-
cur_time = 1 * new Date(), time_diff;
|
|
4215
|
-
|
|
4216
|
-
start_time = start_time || cur_time;
|
|
4217
|
-
time_diff = cur_time - start_time;
|
|
4218
|
-
|
|
4219
|
-
for (ai = 0; ai < anims.length; ai++) {
|
|
4220
|
-
anim = anims[ai];
|
|
4221
|
-
if (typeof anim.val === 'undefined') {
|
|
4222
|
-
anim.val = anim.start;
|
|
4223
|
-
}
|
|
4224
|
-
if (anim.val !== anim.goal) {
|
|
4225
|
-
in_progress = true;
|
|
4226
|
-
var anim_diff = anim.goal - anim.start,
|
|
4227
|
-
anim_dir = anim.goal >= anim.start ? 1 : -1;
|
|
4228
|
-
anim.val = anim.start + anim_diff * time_diff / mss;
|
|
4229
|
-
if (anim.attr !== 'opacity') {
|
|
4230
|
-
anim.val = Math.round(anim.val);
|
|
4231
|
-
}
|
|
4232
|
-
if ((anim_dir > 0 && anim.val >= anim.goal) || (anim_dir < 0 && anim.val <= anim.goal)) {
|
|
4233
|
-
anim.val = anim.goal;
|
|
4234
|
-
}
|
|
4235
|
-
}
|
|
4236
|
-
}
|
|
4237
|
-
if (!in_progress) {
|
|
4238
|
-
if (done_cb) {
|
|
4239
|
-
done_cb();
|
|
4240
|
-
}
|
|
4241
|
-
return;
|
|
4242
|
-
}
|
|
4243
|
-
|
|
4244
|
-
for (ai = 0; ai < anims.length; ai++) {
|
|
4245
|
-
anim = anims[ai];
|
|
4246
|
-
if (anim.el) {
|
|
4247
|
-
var suffix = anim.attr === 'opacity' ? '' : 'px';
|
|
4248
|
-
anim.el.style[anim.attr] = String(anim.val) + suffix;
|
|
4249
|
-
}
|
|
4250
|
-
}
|
|
4251
|
-
setTimeout(function() { self._animate_els(anims, mss, done_cb, start_time); }, 10);
|
|
4252
|
-
});
|
|
4253
|
-
|
|
4254
|
-
MixpanelNotification.prototype._attach_and_animate = _.safewrap(function() {
|
|
4255
|
-
var self = this;
|
|
4256
|
-
|
|
4257
|
-
// no possibility to double-display
|
|
4258
|
-
if (this.shown || this._get_shown_campaigns()[this.campaign_id]) {
|
|
4259
|
-
return;
|
|
4260
|
-
}
|
|
4261
|
-
this.shown = true;
|
|
4262
|
-
|
|
4263
|
-
this.body_el.appendChild(this.notification_el);
|
|
4264
|
-
setTimeout(function() {
|
|
4265
|
-
var notif_el = self._get_notification_display_el();
|
|
4266
|
-
if (self.use_transitions) {
|
|
4267
|
-
if (!self.mini) {
|
|
4268
|
-
self._add_class('bg', 'visible');
|
|
4269
|
-
}
|
|
4270
|
-
self._add_class(notif_el, 'visible');
|
|
4271
|
-
self._mark_as_shown();
|
|
4272
|
-
} else {
|
|
4273
|
-
var notif_attr, notif_start, notif_goal;
|
|
4274
|
-
if (self.mini) {
|
|
4275
|
-
notif_attr = 'right';
|
|
4276
|
-
notif_start = -100;
|
|
4277
|
-
notif_goal = 20;
|
|
4278
|
-
} else {
|
|
4279
|
-
notif_attr = 'top';
|
|
4280
|
-
notif_start = MixpanelNotification.NOTIF_START_TOP + MixpanelNotification.NOTIF_TOP;
|
|
4281
|
-
notif_goal = MixpanelNotification.NOTIF_TOP;
|
|
4282
|
-
}
|
|
4283
|
-
self._animate_els([
|
|
4284
|
-
{
|
|
4285
|
-
el: self._get_el('bg'),
|
|
4286
|
-
attr: 'opacity',
|
|
4287
|
-
start: 0.0,
|
|
4288
|
-
goal: MixpanelNotification.BG_OPACITY
|
|
4289
|
-
},
|
|
4290
|
-
{
|
|
4291
|
-
el: notif_el,
|
|
4292
|
-
attr: 'opacity',
|
|
4293
|
-
start: 0.0,
|
|
4294
|
-
goal: 1.0
|
|
4295
|
-
},
|
|
4296
|
-
{
|
|
4297
|
-
el: notif_el,
|
|
4298
|
-
attr: notif_attr,
|
|
4299
|
-
start: notif_start,
|
|
4300
|
-
goal: notif_goal
|
|
4301
|
-
}
|
|
4302
|
-
], MixpanelNotification.ANIM_TIME, self._mark_as_shown);
|
|
4303
|
-
}
|
|
4304
|
-
}, 100);
|
|
4305
|
-
_.register_event(self._get_el('cancel'), 'click', function(e) {
|
|
4306
|
-
e.preventDefault();
|
|
4307
|
-
self.dismiss();
|
|
4308
|
-
});
|
|
4309
|
-
var click_el = self._get_el('button') ||
|
|
4310
|
-
self._get_el('mini-content');
|
|
4311
|
-
_.register_event(click_el, 'click', function(e) {
|
|
4312
|
-
e.preventDefault();
|
|
4313
|
-
if (self.show_video) {
|
|
4314
|
-
self._track_event('$campaign_open', {'$resource_type': 'video'});
|
|
4315
|
-
self._switch_to_video();
|
|
4316
|
-
} else {
|
|
4317
|
-
self.dismiss();
|
|
4318
|
-
if (self.clickthrough) {
|
|
4319
|
-
var tracking_cb = null;
|
|
4320
|
-
if (self.mixpanel.get_config('inapp_link_new_window')) {
|
|
4321
|
-
window.open(self.dest_url);
|
|
4322
|
-
} else {
|
|
4323
|
-
tracking_cb = function() {
|
|
4324
|
-
window.location.href = self.dest_url;
|
|
4325
|
-
};
|
|
4326
|
-
}
|
|
4327
|
-
self._track_event('$campaign_open', {'$resource_type': 'link'}, tracking_cb);
|
|
4328
|
-
}
|
|
4329
|
-
}
|
|
4330
|
-
});
|
|
4331
|
-
});
|
|
4332
|
-
|
|
4333
|
-
MixpanelNotification.prototype._get_el = function(id) {
|
|
4334
|
-
return document.getElementById(MixpanelNotification.MARKUP_PREFIX + '-' + id);
|
|
4335
|
-
};
|
|
4336
|
-
|
|
4337
|
-
MixpanelNotification.prototype._get_notification_display_el = function() {
|
|
4338
|
-
return this._get_el(this.notif_type);
|
|
4339
|
-
};
|
|
4340
|
-
|
|
4341
|
-
MixpanelNotification.prototype._get_shown_campaigns = function() {
|
|
4342
|
-
return this.persistence['props'][CAMPAIGN_IDS_KEY] || (this.persistence['props'][CAMPAIGN_IDS_KEY] = {});
|
|
4343
|
-
};
|
|
4344
|
-
|
|
4345
|
-
MixpanelNotification.prototype._matches_event_data = _.safewrap(function(event_data) {
|
|
4346
|
-
var event_name = event_data['event'] || '';
|
|
4347
|
-
for (var i = 0; i < this.display_triggers.length; i++) {
|
|
4348
|
-
var display_trigger = this.display_triggers[i];
|
|
4349
|
-
var match_event = display_trigger['event'] || '';
|
|
4350
|
-
if (match_event === '$any_event' || event_name === display_trigger['event']) {
|
|
4351
|
-
if (display_trigger['selector'] && !_.isEmptyObject(display_trigger['selector'])) {
|
|
4352
|
-
if (evaluateSelector(display_trigger['selector'], event_data['properties'])) {
|
|
4353
|
-
return true;
|
|
4354
|
-
}
|
|
4355
|
-
} else {
|
|
4356
|
-
return true;
|
|
4357
|
-
}
|
|
4358
|
-
}
|
|
4359
|
-
}
|
|
4360
|
-
return false;
|
|
4361
|
-
});
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
MixpanelNotification.prototype._browser_lte = function(browser, version) {
|
|
4365
|
-
return this.browser_versions[browser] && this.browser_versions[browser] <= version;
|
|
4366
|
-
};
|
|
4367
|
-
|
|
4368
|
-
MixpanelNotification.prototype._init_image_html = function() {
|
|
4369
|
-
var imgs_to_preload = [];
|
|
4370
|
-
|
|
4371
|
-
if (!this.mini) {
|
|
4372
|
-
if (this.image_url) {
|
|
4373
|
-
imgs_to_preload.push(this.image_url);
|
|
4374
|
-
this.img_html = '<img id="img" src="' + this.image_url + '"/>';
|
|
4375
|
-
} else {
|
|
4376
|
-
this.img_html = '';
|
|
4377
|
-
}
|
|
4378
|
-
if (this.thumb_image_url) {
|
|
4379
|
-
imgs_to_preload.push(this.thumb_image_url);
|
|
4380
|
-
this.thumb_img_html =
|
|
4381
|
-
'<div id="thumbborder-wrapper"><div id="thumbborder"></div></div>' +
|
|
4382
|
-
'<img id="thumbnail"' +
|
|
4383
|
-
' src="' + this.thumb_image_url + '"' +
|
|
4384
|
-
' width="' + MixpanelNotification.THUMB_IMG_SIZE + '"' +
|
|
4385
|
-
' height="' + MixpanelNotification.THUMB_IMG_SIZE + '"' +
|
|
4386
|
-
'/>' +
|
|
4387
|
-
'<div id="thumbspacer"></div>';
|
|
4388
|
-
} else {
|
|
4389
|
-
this.thumb_img_html = '';
|
|
4390
|
-
}
|
|
4391
|
-
} else {
|
|
4392
|
-
this.thumb_image_url = this.thumb_image_url || (this.cdn_host + '/site_media/images/icons/notifications/mini-news-dark.png');
|
|
4393
|
-
imgs_to_preload.push(this.thumb_image_url);
|
|
4394
|
-
}
|
|
4395
|
-
|
|
4396
|
-
return imgs_to_preload;
|
|
4397
|
-
};
|
|
4398
|
-
|
|
4399
|
-
MixpanelNotification.prototype._init_notification_el = function() {
|
|
4400
|
-
var notification_html = '';
|
|
4401
|
-
var video_src = '';
|
|
4402
|
-
var video_html = '';
|
|
4403
|
-
var cancel_html = '<div id="cancel">' +
|
|
4404
|
-
'<div id="cancel-icon"></div>' +
|
|
4405
|
-
'</div>';
|
|
4406
|
-
|
|
4407
|
-
this.notification_el = document.createElement('div');
|
|
4408
|
-
this.notification_el.id = MixpanelNotification.MARKUP_PREFIX + '-wrapper';
|
|
4409
|
-
if (!this.mini) {
|
|
4410
|
-
// TAKEOVER notification
|
|
4411
|
-
var close_html = (this.clickthrough || this.show_video) ? '' : '<div id="button-close"></div>',
|
|
4412
|
-
play_html = this.show_video ? '<div id="button-play"></div>' : '';
|
|
4413
|
-
if (this._browser_lte('ie', 7)) {
|
|
4414
|
-
close_html = '';
|
|
4415
|
-
play_html = '';
|
|
4416
|
-
}
|
|
4417
|
-
notification_html =
|
|
4418
|
-
'<div id="takeover">' +
|
|
4419
|
-
this.thumb_img_html +
|
|
4420
|
-
'<div id="mainbox">' +
|
|
4421
|
-
cancel_html +
|
|
4422
|
-
'<div id="content">' +
|
|
4423
|
-
this.img_html +
|
|
4424
|
-
'<div id="title">' + this.title + '</div>' +
|
|
4425
|
-
'<div id="body">' + this.body + '</div>' +
|
|
4426
|
-
'<div id="tagline">' +
|
|
4427
|
-
'<a href="http://mixpanel.com?from=inapp" target="_blank">POWERED BY MIXPANEL</a>' +
|
|
4428
|
-
'</div>' +
|
|
4429
|
-
'</div>' +
|
|
4430
|
-
'<div id="button">' +
|
|
4431
|
-
close_html +
|
|
4432
|
-
'<a id="button-link" href="' + this.dest_url + '">' + this.cta + '</a>' +
|
|
4433
|
-
play_html +
|
|
4434
|
-
'</div>' +
|
|
4435
|
-
'</div>' +
|
|
4436
|
-
'</div>';
|
|
4437
|
-
} else {
|
|
4438
|
-
// MINI notification
|
|
4439
|
-
notification_html =
|
|
4440
|
-
'<div id="mini">' +
|
|
4441
|
-
'<div id="mainbox">' +
|
|
4442
|
-
cancel_html +
|
|
4443
|
-
'<div id="mini-content">' +
|
|
4444
|
-
'<div id="mini-icon">' +
|
|
4445
|
-
'<div id="mini-icon-img"></div>' +
|
|
4446
|
-
'</div>' +
|
|
4447
|
-
'<div id="body">' +
|
|
4448
|
-
'<div id="body-text"><div>' + this.body + '</div></div>' +
|
|
4449
|
-
'</div>' +
|
|
4450
|
-
'</div>' +
|
|
4451
|
-
'</div>' +
|
|
4452
|
-
'<div id="mini-border"></div>' +
|
|
4453
|
-
'</div>';
|
|
4454
|
-
}
|
|
4455
|
-
if (this.youtube_video) {
|
|
4456
|
-
video_src = this.resource_protocol + 'www.youtube.com/embed/' + this.youtube_video +
|
|
4457
|
-
'?wmode=transparent&showinfo=0&modestbranding=0&rel=0&autoplay=1&loop=0&vq=hd1080';
|
|
4458
|
-
if (this.yt_custom) {
|
|
4459
|
-
video_src += '&enablejsapi=1&html5=1&controls=0';
|
|
4460
|
-
video_html =
|
|
4461
|
-
'<div id="video-controls">' +
|
|
4462
|
-
'<div id="video-progress" class="video-progress-el">' +
|
|
4463
|
-
'<div id="video-progress-total" class="video-progress-el"></div>' +
|
|
4464
|
-
'<div id="video-elapsed" class="video-progress-el"></div>' +
|
|
4465
|
-
'</div>' +
|
|
4466
|
-
'<div id="video-time" class="video-progress-el"></div>' +
|
|
4467
|
-
'</div>';
|
|
4468
|
-
}
|
|
4469
|
-
} else if (this.vimeo_video) {
|
|
4470
|
-
video_src = this.resource_protocol + 'player.vimeo.com/video/' + this.vimeo_video + '?autoplay=1&title=0&byline=0&portrait=0';
|
|
4471
|
-
}
|
|
4472
|
-
if (this.show_video) {
|
|
4473
|
-
this.video_iframe =
|
|
4474
|
-
'<iframe id="' + MixpanelNotification.MARKUP_PREFIX + '-video-frame" ' +
|
|
4475
|
-
'width="' + this.video_width + '" height="' + this.video_height + '" ' +
|
|
4476
|
-
' src="' + video_src + '"' +
|
|
4477
|
-
' frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen="1" scrolling="no"' +
|
|
4478
|
-
'></iframe>';
|
|
4479
|
-
video_html =
|
|
4480
|
-
'<div id="video-' + (this.flip_animate ? '' : 'no') + 'flip">' +
|
|
4481
|
-
'<div id="video">' +
|
|
4482
|
-
'<div id="video-holder"></div>' +
|
|
4483
|
-
video_html +
|
|
4484
|
-
'</div>' +
|
|
4485
|
-
'</div>';
|
|
4486
|
-
}
|
|
4487
|
-
var main_html = video_html + notification_html;
|
|
4488
|
-
if (this.flip_animate) {
|
|
4489
|
-
main_html =
|
|
4490
|
-
(this.mini ? notification_html : '') +
|
|
4491
|
-
'<div id="flipcontainer"><div id="flipper">' +
|
|
4492
|
-
(this.mini ? video_html : main_html) +
|
|
4493
|
-
'</div></div>';
|
|
4494
|
-
}
|
|
4495
|
-
|
|
4496
|
-
this.notification_el.innerHTML =
|
|
4497
|
-
('<div id="overlay" class="' + this.notif_type + '">' +
|
|
4498
|
-
'<div id="campaignid-' + this.campaign_id + '">' +
|
|
4499
|
-
'<div id="bgwrapper">' +
|
|
4500
|
-
'<div id="bg"></div>' +
|
|
4501
|
-
main_html +
|
|
4502
|
-
'</div>' +
|
|
4503
|
-
'</div>' +
|
|
4504
|
-
'</div>')
|
|
4505
|
-
.replace(/class="/g, 'class="' + MixpanelNotification.MARKUP_PREFIX + '-')
|
|
4506
|
-
.replace(/id="/g, 'id="' + MixpanelNotification.MARKUP_PREFIX + '-');
|
|
4507
|
-
};
|
|
4508
|
-
|
|
4509
|
-
MixpanelNotification.prototype._init_styles = function() {
|
|
4510
|
-
if (this.style === 'dark') {
|
|
4511
|
-
this.style_vals = {
|
|
4512
|
-
bg: '#1d1f25',
|
|
4513
|
-
bg_actions: '#282b32',
|
|
4514
|
-
bg_hover: '#3a4147',
|
|
4515
|
-
bg_light: '#4a5157',
|
|
4516
|
-
border_gray: '#32353c',
|
|
4517
|
-
cancel_opacity: '0.4',
|
|
4518
|
-
mini_hover: '#2a3137',
|
|
4519
|
-
text_title: '#fff',
|
|
4520
|
-
text_main: '#9498a3',
|
|
4521
|
-
text_tagline: '#464851',
|
|
4522
|
-
text_hover: '#ddd'
|
|
4523
|
-
};
|
|
4524
|
-
} else {
|
|
4525
|
-
this.style_vals = {
|
|
4526
|
-
bg: '#fff',
|
|
4527
|
-
bg_actions: '#e7eaee',
|
|
4528
|
-
bg_hover: '#eceff3',
|
|
4529
|
-
bg_light: '#f5f5f5',
|
|
4530
|
-
border_gray: '#e4ecf2',
|
|
4531
|
-
cancel_opacity: '1.0',
|
|
4532
|
-
mini_hover: '#fafafa',
|
|
4533
|
-
text_title: '#5c6578',
|
|
4534
|
-
text_main: '#8b949b',
|
|
4535
|
-
text_tagline: '#ced9e6',
|
|
4536
|
-
text_hover: '#7c8598'
|
|
4537
|
-
};
|
|
4538
|
-
}
|
|
4539
|
-
var shadow = '0px 0px 35px 0px rgba(45, 49, 56, 0.7)',
|
|
4540
|
-
video_shadow = shadow,
|
|
4541
|
-
mini_shadow = shadow,
|
|
4542
|
-
thumb_total_size = MixpanelNotification.THUMB_IMG_SIZE + MixpanelNotification.THUMB_BORDER_SIZE * 2,
|
|
4543
|
-
anim_seconds = (MixpanelNotification.ANIM_TIME / 1000) + 's';
|
|
4544
|
-
if (this.mini) {
|
|
4545
|
-
shadow = 'none';
|
|
4546
|
-
}
|
|
4547
|
-
|
|
4548
|
-
// don't display on small viewports
|
|
4549
|
-
var notif_media_queries = {},
|
|
4550
|
-
min_width = MixpanelNotification.NOTIF_WIDTH_MINI + 20;
|
|
4551
|
-
notif_media_queries['@media only screen and (max-width: ' + (min_width - 1) + 'px)'] = {
|
|
4552
|
-
'#overlay': {
|
|
4553
|
-
'display': 'none'
|
|
4554
|
-
}
|
|
4555
|
-
};
|
|
4556
|
-
var notif_styles = {
|
|
4557
|
-
'.flipped': {
|
|
4558
|
-
'transform': 'rotateY(180deg)'
|
|
4559
|
-
},
|
|
4560
|
-
'#overlay': {
|
|
4561
|
-
'position': 'fixed',
|
|
4562
|
-
'top': '0',
|
|
4563
|
-
'left': '0',
|
|
4564
|
-
'width': '100%',
|
|
4565
|
-
'height': '100%',
|
|
4566
|
-
'overflow': 'auto',
|
|
4567
|
-
'text-align': 'center',
|
|
4568
|
-
'z-index': '10000',
|
|
4569
|
-
'font-family': '"Helvetica", "Arial", sans-serif',
|
|
4570
|
-
'-webkit-font-smoothing': 'antialiased',
|
|
4571
|
-
'-moz-osx-font-smoothing': 'grayscale'
|
|
4572
|
-
},
|
|
4573
|
-
'#overlay.mini': {
|
|
4574
|
-
'height': '0',
|
|
4575
|
-
'overflow': 'visible'
|
|
4576
|
-
},
|
|
4577
|
-
'#overlay a': {
|
|
4578
|
-
'width': 'initial',
|
|
4579
|
-
'padding': '0',
|
|
4580
|
-
'text-decoration': 'none',
|
|
4581
|
-
'text-transform': 'none',
|
|
4582
|
-
'color': 'inherit'
|
|
4583
|
-
},
|
|
4584
|
-
'#bgwrapper': {
|
|
4585
|
-
'position': 'relative',
|
|
4586
|
-
'width': '100%',
|
|
4587
|
-
'height': '100%'
|
|
4588
|
-
},
|
|
4589
|
-
'#bg': {
|
|
4590
|
-
'position': 'fixed',
|
|
4591
|
-
'top': '0',
|
|
4592
|
-
'left': '0',
|
|
4593
|
-
'width': '100%',
|
|
4594
|
-
'height': '100%',
|
|
4595
|
-
'min-width': this.doc_width * 4 + 'px',
|
|
4596
|
-
'min-height': this.doc_height * 4 + 'px',
|
|
4597
|
-
'background-color': 'black',
|
|
4598
|
-
'opacity': '0.0',
|
|
4599
|
-
'-ms-filter': 'progid:DXImageTransform.Microsoft.Alpha(Opacity=60)', // IE8
|
|
4600
|
-
'filter': 'alpha(opacity=60)', // IE5-7
|
|
4601
|
-
'transition': 'opacity ' + anim_seconds
|
|
4602
|
-
},
|
|
4603
|
-
'#bg.visible': {
|
|
4604
|
-
'opacity': MixpanelNotification.BG_OPACITY
|
|
4605
|
-
},
|
|
4606
|
-
'.mini #bg': {
|
|
4607
|
-
'width': '0',
|
|
4608
|
-
'height': '0',
|
|
4609
|
-
'min-width': '0'
|
|
4610
|
-
},
|
|
4611
|
-
'#flipcontainer': {
|
|
4612
|
-
'perspective': '1000px',
|
|
4613
|
-
'position': 'absolute',
|
|
4614
|
-
'width': '100%'
|
|
4615
|
-
},
|
|
4616
|
-
'#flipper': {
|
|
4617
|
-
'position': 'relative',
|
|
4618
|
-
'transform-style': 'preserve-3d',
|
|
4619
|
-
'transition': '0.3s'
|
|
4620
|
-
},
|
|
4621
|
-
'#takeover': {
|
|
4622
|
-
'position': 'absolute',
|
|
4623
|
-
'left': '50%',
|
|
4624
|
-
'width': MixpanelNotification.NOTIF_WIDTH + 'px',
|
|
4625
|
-
'margin-left': Math.round(-MixpanelNotification.NOTIF_WIDTH / 2) + 'px',
|
|
4626
|
-
'backface-visibility': 'hidden',
|
|
4627
|
-
'transform': 'rotateY(0deg)',
|
|
4628
|
-
'opacity': '0.0',
|
|
4629
|
-
'top': MixpanelNotification.NOTIF_START_TOP + 'px',
|
|
4630
|
-
'transition': 'opacity ' + anim_seconds + ', top ' + anim_seconds
|
|
4631
|
-
},
|
|
4632
|
-
'#takeover.visible': {
|
|
4633
|
-
'opacity': '1.0',
|
|
4634
|
-
'top': MixpanelNotification.NOTIF_TOP + 'px'
|
|
4635
|
-
},
|
|
4636
|
-
'#takeover.exiting': {
|
|
4637
|
-
'opacity': '0.0',
|
|
4638
|
-
'top': MixpanelNotification.NOTIF_START_TOP + 'px'
|
|
4639
|
-
},
|
|
4640
|
-
'#thumbspacer': {
|
|
4641
|
-
'height': MixpanelNotification.THUMB_OFFSET + 'px'
|
|
4642
|
-
},
|
|
4643
|
-
'#thumbborder-wrapper': {
|
|
4644
|
-
'position': 'absolute',
|
|
4645
|
-
'top': (-MixpanelNotification.THUMB_BORDER_SIZE) + 'px',
|
|
4646
|
-
'left': (MixpanelNotification.NOTIF_WIDTH / 2 - MixpanelNotification.THUMB_OFFSET - MixpanelNotification.THUMB_BORDER_SIZE) + 'px',
|
|
4647
|
-
'width': thumb_total_size + 'px',
|
|
4648
|
-
'height': (thumb_total_size / 2) + 'px',
|
|
4649
|
-
'overflow': 'hidden'
|
|
4650
|
-
},
|
|
4651
|
-
'#thumbborder': {
|
|
4652
|
-
'position': 'absolute',
|
|
4653
|
-
'width': thumb_total_size + 'px',
|
|
4654
|
-
'height': thumb_total_size + 'px',
|
|
4655
|
-
'border-radius': thumb_total_size + 'px',
|
|
4656
|
-
'background-color': this.style_vals.bg_actions,
|
|
4657
|
-
'opacity': '0.5'
|
|
4658
|
-
},
|
|
4659
|
-
'#thumbnail': {
|
|
4660
|
-
'position': 'absolute',
|
|
4661
|
-
'top': '0px',
|
|
4662
|
-
'left': (MixpanelNotification.NOTIF_WIDTH / 2 - MixpanelNotification.THUMB_OFFSET) + 'px',
|
|
4663
|
-
'width': MixpanelNotification.THUMB_IMG_SIZE + 'px',
|
|
4664
|
-
'height': MixpanelNotification.THUMB_IMG_SIZE + 'px',
|
|
4665
|
-
'overflow': 'hidden',
|
|
4666
|
-
'z-index': '100',
|
|
4667
|
-
'border-radius': MixpanelNotification.THUMB_IMG_SIZE + 'px'
|
|
4668
|
-
},
|
|
4669
|
-
'#mini': {
|
|
4670
|
-
'position': 'absolute',
|
|
4671
|
-
'right': '20px',
|
|
4672
|
-
'top': MixpanelNotification.NOTIF_TOP + 'px',
|
|
4673
|
-
'width': this.notif_width + 'px',
|
|
4674
|
-
'height': MixpanelNotification.NOTIF_HEIGHT_MINI * 2 + 'px',
|
|
4675
|
-
'margin-top': 20 - MixpanelNotification.NOTIF_HEIGHT_MINI + 'px',
|
|
4676
|
-
'backface-visibility': 'hidden',
|
|
4677
|
-
'opacity': '0.0',
|
|
4678
|
-
'transform': 'rotateX(90deg)',
|
|
4679
|
-
'transition': 'opacity 0.3s, transform 0.3s, right 0.3s'
|
|
4680
|
-
},
|
|
4681
|
-
'#mini.visible': {
|
|
4682
|
-
'opacity': '1.0',
|
|
4683
|
-
'transform': 'rotateX(0deg)'
|
|
4684
|
-
},
|
|
4685
|
-
'#mini.exiting': {
|
|
4686
|
-
'opacity': '0.0',
|
|
4687
|
-
'right': '-150px'
|
|
4688
|
-
},
|
|
4689
|
-
'#mainbox': {
|
|
4690
|
-
'border-radius': '4px',
|
|
4691
|
-
'box-shadow': shadow,
|
|
4692
|
-
'text-align': 'center',
|
|
4693
|
-
'background-color': this.style_vals.bg,
|
|
4694
|
-
'font-size': '14px',
|
|
4695
|
-
'color': this.style_vals.text_main
|
|
4696
|
-
},
|
|
4697
|
-
'#mini #mainbox': {
|
|
4698
|
-
'height': MixpanelNotification.NOTIF_HEIGHT_MINI + 'px',
|
|
4699
|
-
'margin-top': MixpanelNotification.NOTIF_HEIGHT_MINI + 'px',
|
|
4700
|
-
'border-radius': '3px',
|
|
4701
|
-
'transition': 'background-color ' + anim_seconds
|
|
4702
|
-
},
|
|
4703
|
-
'#mini-border': {
|
|
4704
|
-
'height': (MixpanelNotification.NOTIF_HEIGHT_MINI + 6) + 'px',
|
|
4705
|
-
'width': (MixpanelNotification.NOTIF_WIDTH_MINI + 6) + 'px',
|
|
4706
|
-
'position': 'absolute',
|
|
4707
|
-
'top': '-3px',
|
|
4708
|
-
'left': '-3px',
|
|
4709
|
-
'margin-top': MixpanelNotification.NOTIF_HEIGHT_MINI + 'px',
|
|
4710
|
-
'border-radius': '6px',
|
|
4711
|
-
'opacity': '0.25',
|
|
4712
|
-
'background-color': '#fff',
|
|
4713
|
-
'z-index': '-1',
|
|
4714
|
-
'box-shadow': mini_shadow
|
|
4715
|
-
},
|
|
4716
|
-
'#mini-icon': {
|
|
4717
|
-
'position': 'relative',
|
|
4718
|
-
'display': 'inline-block',
|
|
4719
|
-
'width': '75px',
|
|
4720
|
-
'height': MixpanelNotification.NOTIF_HEIGHT_MINI + 'px',
|
|
4721
|
-
'border-radius': '3px 0 0 3px',
|
|
4722
|
-
'background-color': this.style_vals.bg_actions,
|
|
4723
|
-
'background': 'linear-gradient(135deg, ' + this.style_vals.bg_light + ' 0%, ' + this.style_vals.bg_actions + ' 100%)',
|
|
4724
|
-
'transition': 'background-color ' + anim_seconds
|
|
4725
|
-
},
|
|
4726
|
-
'#mini:hover #mini-icon': {
|
|
4727
|
-
'background-color': this.style_vals.mini_hover
|
|
4728
|
-
},
|
|
4729
|
-
'#mini:hover #mainbox': {
|
|
4730
|
-
'background-color': this.style_vals.mini_hover
|
|
4731
|
-
},
|
|
4732
|
-
'#mini-icon-img': {
|
|
4733
|
-
'position': 'absolute',
|
|
4734
|
-
'background-image': 'url(' + this.thumb_image_url + ')',
|
|
4735
|
-
'width': '48px',
|
|
4736
|
-
'height': '48px',
|
|
4737
|
-
'top': '20px',
|
|
4738
|
-
'left': '12px'
|
|
4739
|
-
},
|
|
4740
|
-
'#content': {
|
|
4741
|
-
'padding': '30px 20px 0px 20px'
|
|
4742
|
-
},
|
|
4743
|
-
'#mini-content': {
|
|
4744
|
-
'text-align': 'left',
|
|
4745
|
-
'height': MixpanelNotification.NOTIF_HEIGHT_MINI + 'px',
|
|
4746
|
-
'cursor': 'pointer'
|
|
4747
|
-
},
|
|
4748
|
-
'#img': {
|
|
4749
|
-
'width': '328px',
|
|
4750
|
-
'margin-top': '30px',
|
|
4751
|
-
'border-radius': '5px'
|
|
4752
|
-
},
|
|
4753
|
-
'#title': {
|
|
4754
|
-
'max-height': '600px',
|
|
4755
|
-
'overflow': 'hidden',
|
|
4756
|
-
'word-wrap': 'break-word',
|
|
4757
|
-
'padding': '25px 0px 20px 0px',
|
|
4758
|
-
'font-size': '19px',
|
|
4759
|
-
'font-weight': 'bold',
|
|
4760
|
-
'color': this.style_vals.text_title
|
|
4761
|
-
},
|
|
4762
|
-
'#body': {
|
|
4763
|
-
'max-height': '600px',
|
|
4764
|
-
'margin-bottom': '25px',
|
|
4765
|
-
'overflow': 'hidden',
|
|
4766
|
-
'word-wrap': 'break-word',
|
|
4767
|
-
'line-height': '21px',
|
|
4768
|
-
'font-size': '15px',
|
|
4769
|
-
'font-weight': 'normal',
|
|
4770
|
-
'text-align': 'left'
|
|
4771
|
-
},
|
|
4772
|
-
'#mini #body': {
|
|
4773
|
-
'display': 'inline-block',
|
|
4774
|
-
'max-width': '250px',
|
|
4775
|
-
'margin': '0 0 0 30px',
|
|
4776
|
-
'height': MixpanelNotification.NOTIF_HEIGHT_MINI + 'px',
|
|
4777
|
-
'font-size': '16px',
|
|
4778
|
-
'letter-spacing': '0.8px',
|
|
4779
|
-
'color': this.style_vals.text_title
|
|
4780
|
-
},
|
|
4781
|
-
'#mini #body-text': {
|
|
4782
|
-
'display': 'table',
|
|
4783
|
-
'height': MixpanelNotification.NOTIF_HEIGHT_MINI + 'px'
|
|
4784
|
-
},
|
|
4785
|
-
'#mini #body-text div': {
|
|
4786
|
-
'display': 'table-cell',
|
|
4787
|
-
'vertical-align': 'middle'
|
|
4788
|
-
},
|
|
4789
|
-
'#tagline': {
|
|
4790
|
-
'margin-bottom': '15px',
|
|
4791
|
-
'font-size': '10px',
|
|
4792
|
-
'font-weight': '600',
|
|
4793
|
-
'letter-spacing': '0.8px',
|
|
4794
|
-
'color': '#ccd7e0',
|
|
4795
|
-
'text-align': 'left'
|
|
4796
|
-
},
|
|
4797
|
-
'#tagline a': {
|
|
4798
|
-
'color': this.style_vals.text_tagline,
|
|
4799
|
-
'transition': 'color ' + anim_seconds
|
|
4800
|
-
},
|
|
4801
|
-
'#tagline a:hover': {
|
|
4802
|
-
'color': this.style_vals.text_hover
|
|
4803
|
-
},
|
|
4804
|
-
'#cancel': {
|
|
4805
|
-
'position': 'absolute',
|
|
4806
|
-
'right': '0',
|
|
4807
|
-
'width': '8px',
|
|
4808
|
-
'height': '8px',
|
|
4809
|
-
'padding': '10px',
|
|
4810
|
-
'border-radius': '20px',
|
|
4811
|
-
'margin': '12px 12px 0 0',
|
|
4812
|
-
'box-sizing': 'content-box',
|
|
4813
|
-
'cursor': 'pointer',
|
|
4814
|
-
'transition': 'background-color ' + anim_seconds
|
|
4815
|
-
},
|
|
4816
|
-
'#mini #cancel': {
|
|
4817
|
-
'margin': '7px 7px 0 0'
|
|
4818
|
-
},
|
|
4819
|
-
'#cancel-icon': {
|
|
4820
|
-
'width': '8px',
|
|
4821
|
-
'height': '8px',
|
|
4822
|
-
'overflow': 'hidden',
|
|
4823
|
-
'background-image': 'url(' + this.cdn_host + '/site_media/images/icons/notifications/cancel-x.png)',
|
|
4824
|
-
'opacity': this.style_vals.cancel_opacity
|
|
4825
|
-
},
|
|
4826
|
-
'#cancel:hover': {
|
|
4827
|
-
'background-color': this.style_vals.bg_hover
|
|
4828
|
-
},
|
|
4829
|
-
'#button': {
|
|
4830
|
-
'display': 'block',
|
|
4831
|
-
'height': '60px',
|
|
4832
|
-
'line-height': '60px',
|
|
4833
|
-
'text-align': 'center',
|
|
4834
|
-
'background-color': this.style_vals.bg_actions,
|
|
4835
|
-
'border-radius': '0 0 4px 4px',
|
|
4836
|
-
'overflow': 'hidden',
|
|
4837
|
-
'cursor': 'pointer',
|
|
4838
|
-
'transition': 'background-color ' + anim_seconds
|
|
4839
|
-
},
|
|
4840
|
-
'#button-close': {
|
|
4841
|
-
'display': 'inline-block',
|
|
4842
|
-
'width': '9px',
|
|
4843
|
-
'height': '60px',
|
|
4844
|
-
'margin-right': '8px',
|
|
4845
|
-
'vertical-align': 'top',
|
|
4846
|
-
'background-image': 'url(' + this.cdn_host + '/site_media/images/icons/notifications/close-x-' + this.style + '.png)',
|
|
4847
|
-
'background-repeat': 'no-repeat',
|
|
4848
|
-
'background-position': '0px 25px'
|
|
4849
|
-
},
|
|
4850
|
-
'#button-play': {
|
|
4851
|
-
'display': 'inline-block',
|
|
4852
|
-
'width': '30px',
|
|
4853
|
-
'height': '60px',
|
|
4854
|
-
'margin-left': '15px',
|
|
4855
|
-
'background-image': 'url(' + this.cdn_host + '/site_media/images/icons/notifications/play-' + this.style + '-small.png)',
|
|
4856
|
-
'background-repeat': 'no-repeat',
|
|
4857
|
-
'background-position': '0px 15px'
|
|
4858
|
-
},
|
|
4859
|
-
'a#button-link': {
|
|
4860
|
-
'display': 'inline-block',
|
|
4861
|
-
'vertical-align': 'top',
|
|
4862
|
-
'text-align': 'center',
|
|
4863
|
-
'font-size': '17px',
|
|
4864
|
-
'font-weight': 'bold',
|
|
4865
|
-
'overflow': 'hidden',
|
|
4866
|
-
'word-wrap': 'break-word',
|
|
4867
|
-
'color': this.style_vals.text_title,
|
|
4868
|
-
'transition': 'color ' + anim_seconds
|
|
4869
|
-
},
|
|
4870
|
-
'#button:hover': {
|
|
4871
|
-
'background-color': this.style_vals.bg_hover,
|
|
4872
|
-
'color': this.style_vals.text_hover
|
|
4873
|
-
},
|
|
4874
|
-
'#button:hover a': {
|
|
4875
|
-
'color': this.style_vals.text_hover
|
|
4876
|
-
},
|
|
4877
|
-
|
|
4878
|
-
'#video-noflip': {
|
|
4879
|
-
'position': 'relative',
|
|
4880
|
-
'top': (-this.video_height * 2) + 'px'
|
|
4881
|
-
},
|
|
4882
|
-
'#video-flip': {
|
|
4883
|
-
'backface-visibility': 'hidden',
|
|
4884
|
-
'transform': 'rotateY(180deg)'
|
|
4885
|
-
},
|
|
4886
|
-
'#video': {
|
|
4887
|
-
'position': 'absolute',
|
|
4888
|
-
'width': (this.video_width - 1) + 'px',
|
|
4889
|
-
'height': this.video_height + 'px',
|
|
4890
|
-
'top': MixpanelNotification.NOTIF_TOP + 'px',
|
|
4891
|
-
'margin-top': '100px',
|
|
4892
|
-
'left': '50%',
|
|
4893
|
-
'margin-left': Math.round(-this.video_width / 2) + 'px',
|
|
4894
|
-
'overflow': 'hidden',
|
|
4895
|
-
'border-radius': '5px',
|
|
4896
|
-
'box-shadow': video_shadow,
|
|
4897
|
-
'transform': 'translateZ(1px)', // webkit rendering bug http://stackoverflow.com/questions/18167981/clickable-link-area-unexpectedly-smaller-after-css-transform
|
|
4898
|
-
'transition': 'opacity ' + anim_seconds + ', top ' + anim_seconds
|
|
4899
|
-
},
|
|
4900
|
-
'#video.exiting': {
|
|
4901
|
-
'opacity': '0.0',
|
|
4902
|
-
'top': this.video_height + 'px'
|
|
4903
|
-
},
|
|
4904
|
-
'#video-holder': {
|
|
4905
|
-
'position': 'absolute',
|
|
4906
|
-
'width': (this.video_width - 1) + 'px',
|
|
4907
|
-
'height': this.video_height + 'px',
|
|
4908
|
-
'overflow': 'hidden',
|
|
4909
|
-
'border-radius': '5px'
|
|
4910
|
-
},
|
|
4911
|
-
'#video-frame': {
|
|
4912
|
-
'margin-left': '-1px',
|
|
4913
|
-
'width': this.video_width + 'px'
|
|
4914
|
-
},
|
|
4915
|
-
'#video-controls': {
|
|
4916
|
-
'opacity': '0',
|
|
4917
|
-
'transition': 'opacity 0.5s'
|
|
4918
|
-
},
|
|
4919
|
-
'#video:hover #video-controls': {
|
|
4920
|
-
'opacity': '1.0'
|
|
4921
|
-
},
|
|
4922
|
-
'#video .video-progress-el': {
|
|
4923
|
-
'position': 'absolute',
|
|
4924
|
-
'bottom': '0',
|
|
4925
|
-
'height': '25px',
|
|
4926
|
-
'border-radius': '0 0 0 5px'
|
|
4927
|
-
},
|
|
4928
|
-
'#video-progress': {
|
|
4929
|
-
'width': '90%'
|
|
4930
|
-
},
|
|
4931
|
-
'#video-progress-total': {
|
|
4932
|
-
'width': '100%',
|
|
4933
|
-
'background-color': this.style_vals.bg,
|
|
4934
|
-
'opacity': '0.7'
|
|
4935
|
-
},
|
|
4936
|
-
'#video-elapsed': {
|
|
4937
|
-
'width': '0',
|
|
4938
|
-
'background-color': '#6cb6f5',
|
|
4939
|
-
'opacity': '0.9'
|
|
4940
|
-
},
|
|
4941
|
-
'#video #video-time': {
|
|
4942
|
-
'width': '10%',
|
|
4943
|
-
'right': '0',
|
|
4944
|
-
'font-size': '11px',
|
|
4945
|
-
'line-height': '25px',
|
|
4946
|
-
'color': this.style_vals.text_main,
|
|
4947
|
-
'background-color': '#666',
|
|
4948
|
-
'border-radius': '0 0 5px 0'
|
|
4949
|
-
}
|
|
4950
|
-
};
|
|
4951
|
-
|
|
4952
|
-
// IE hacks
|
|
4953
|
-
if (this._browser_lte('ie', 8)) {
|
|
4954
|
-
_.extend(notif_styles, {
|
|
4955
|
-
'* html #overlay': {
|
|
4956
|
-
'position': 'absolute'
|
|
4957
|
-
},
|
|
4958
|
-
'* html #bg': {
|
|
4959
|
-
'position': 'absolute'
|
|
4960
|
-
},
|
|
4961
|
-
'html, body': {
|
|
4962
|
-
'height': '100%'
|
|
4963
|
-
}
|
|
4964
|
-
});
|
|
4965
|
-
}
|
|
4966
|
-
if (this._browser_lte('ie', 7)) {
|
|
4967
|
-
_.extend(notif_styles, {
|
|
4968
|
-
'#mini #body': {
|
|
4969
|
-
'display': 'inline',
|
|
4970
|
-
'zoom': '1',
|
|
4971
|
-
'border': '1px solid ' + this.style_vals.bg_hover
|
|
4972
|
-
},
|
|
4973
|
-
'#mini #body-text': {
|
|
4974
|
-
'padding': '20px'
|
|
4975
|
-
},
|
|
4976
|
-
'#mini #mini-icon': {
|
|
4977
|
-
'display': 'none'
|
|
4978
|
-
}
|
|
4979
|
-
});
|
|
4980
|
-
}
|
|
4981
|
-
|
|
4982
|
-
// add vendor-prefixed style rules
|
|
4983
|
-
var VENDOR_STYLES = [
|
|
4984
|
-
'backface-visibility', 'border-radius', 'box-shadow', 'opacity',
|
|
4985
|
-
'perspective', 'transform', 'transform-style', 'transition'
|
|
4986
|
-
],
|
|
4987
|
-
VENDOR_PREFIXES = ['khtml', 'moz', 'ms', 'o', 'webkit'];
|
|
4988
|
-
for (var selector in notif_styles) {
|
|
4989
|
-
for (var si = 0; si < VENDOR_STYLES.length; si++) {
|
|
4990
|
-
var prop = VENDOR_STYLES[si];
|
|
4991
|
-
if (prop in notif_styles[selector]) {
|
|
4992
|
-
var val = notif_styles[selector][prop];
|
|
4993
|
-
for (var pi = 0; pi < VENDOR_PREFIXES.length; pi++) {
|
|
4994
|
-
notif_styles[selector]['-' + VENDOR_PREFIXES[pi] + '-' + prop] = val;
|
|
4995
|
-
}
|
|
4996
|
-
}
|
|
4997
|
-
}
|
|
4998
|
-
}
|
|
4999
|
-
|
|
5000
|
-
var inject_styles = function(styles, media_queries) {
|
|
5001
|
-
var create_style_text = function(style_defs) {
|
|
5002
|
-
var st = '';
|
|
5003
|
-
for (var selector in style_defs) {
|
|
5004
|
-
var mp_selector = selector
|
|
5005
|
-
.replace(/#/g, '#' + MixpanelNotification.MARKUP_PREFIX + '-')
|
|
5006
|
-
.replace(/\./g, '.' + MixpanelNotification.MARKUP_PREFIX + '-');
|
|
5007
|
-
st += '\n' + mp_selector + ' {';
|
|
5008
|
-
var props = style_defs[selector];
|
|
5009
|
-
for (var k in props) {
|
|
5010
|
-
st += k + ':' + props[k] + ';';
|
|
5011
|
-
}
|
|
5012
|
-
st += '}';
|
|
5013
|
-
}
|
|
5014
|
-
return st;
|
|
5015
|
-
};
|
|
5016
|
-
var create_media_query_text = function(mq_defs) {
|
|
5017
|
-
var mqt = '';
|
|
5018
|
-
for (var mq in mq_defs) {
|
|
5019
|
-
mqt += '\n' + mq + ' {' + create_style_text(mq_defs[mq]) + '\n}';
|
|
5020
|
-
}
|
|
5021
|
-
return mqt;
|
|
5022
|
-
};
|
|
5023
|
-
|
|
5024
|
-
var style_text = create_style_text(styles) + create_media_query_text(media_queries),
|
|
5025
|
-
head_el = document.head || document.getElementsByTagName('head')[0] || document.documentElement,
|
|
5026
|
-
style_el = document.createElement('style');
|
|
5027
|
-
head_el.appendChild(style_el);
|
|
5028
|
-
style_el.setAttribute('type', 'text/css');
|
|
5029
|
-
if (style_el.styleSheet) { // IE
|
|
5030
|
-
style_el.styleSheet.cssText = style_text;
|
|
5031
|
-
} else {
|
|
5032
|
-
style_el.textContent = style_text;
|
|
5033
|
-
}
|
|
5034
|
-
};
|
|
5035
|
-
inject_styles(notif_styles, notif_media_queries);
|
|
5036
|
-
};
|
|
5037
|
-
|
|
5038
|
-
MixpanelNotification.prototype._init_video = _.safewrap(function() {
|
|
5039
|
-
if (!this.video_url) {
|
|
5040
|
-
return;
|
|
5041
|
-
}
|
|
5042
|
-
var self = this;
|
|
5043
|
-
|
|
5044
|
-
// Youtube iframe API compatibility
|
|
5045
|
-
self.yt_custom = 'postMessage' in window;
|
|
5046
|
-
|
|
5047
|
-
self.dest_url = self.video_url;
|
|
5048
|
-
var youtube_match = self.video_url.match(
|
|
5049
|
-
// http://stackoverflow.com/questions/2936467/parse-youtube-video-id-using-preg-match
|
|
5050
|
-
/(?:youtube(?:-nocookie)?\.com\/(?:[^/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?/ ]{11})/i
|
|
5051
|
-
),
|
|
5052
|
-
vimeo_match = self.video_url.match(
|
|
5053
|
-
/vimeo\.com\/.*?(\d+)/i
|
|
5054
|
-
);
|
|
5055
|
-
if (youtube_match) {
|
|
5056
|
-
self.show_video = true;
|
|
5057
|
-
self.youtube_video = youtube_match[1];
|
|
5058
|
-
|
|
5059
|
-
if (self.yt_custom) {
|
|
5060
|
-
window['onYouTubeIframeAPIReady'] = function() {
|
|
5061
|
-
if (self._get_el('video-frame')) {
|
|
5062
|
-
self._yt_video_ready();
|
|
5063
|
-
}
|
|
5064
|
-
};
|
|
5065
|
-
|
|
5066
|
-
// load Youtube iframe API; see https://developers.google.com/youtube/iframe_api_reference
|
|
5067
|
-
var tag = document.createElement('script');
|
|
5068
|
-
tag.src = self.resource_protocol + 'www.youtube.com/iframe_api';
|
|
5069
|
-
var firstScriptTag = document.getElementsByTagName('script')[0];
|
|
5070
|
-
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
|
5071
|
-
}
|
|
5072
|
-
} else if (vimeo_match) {
|
|
5073
|
-
self.show_video = true;
|
|
5074
|
-
self.vimeo_video = vimeo_match[1];
|
|
5075
|
-
}
|
|
5076
|
-
|
|
5077
|
-
// IE <= 7, FF <= 3: fall through to video link rather than embedded player
|
|
5078
|
-
if (self._browser_lte('ie', 7) || self._browser_lte('firefox', 3)) {
|
|
5079
|
-
self.show_video = false;
|
|
5080
|
-
self.clickthrough = true;
|
|
5081
|
-
}
|
|
5082
|
-
});
|
|
5083
|
-
|
|
5084
|
-
MixpanelNotification.prototype._mark_as_shown = _.safewrap(function() {
|
|
5085
|
-
// click on background to dismiss
|
|
5086
|
-
var self = this;
|
|
5087
|
-
_.register_event(self._get_el('bg'), 'click', function() {
|
|
5088
|
-
self.dismiss();
|
|
5089
|
-
});
|
|
5090
|
-
|
|
5091
|
-
var get_style = function(el, style_name) {
|
|
5092
|
-
var styles = {};
|
|
5093
|
-
if (document.defaultView && document.defaultView.getComputedStyle) {
|
|
5094
|
-
styles = document.defaultView.getComputedStyle(el, null); // FF3 requires both args
|
|
5095
|
-
} else if (el.currentStyle) { // IE
|
|
5096
|
-
styles = el.currentStyle;
|
|
5097
|
-
}
|
|
5098
|
-
return styles[style_name];
|
|
5099
|
-
};
|
|
5100
|
-
|
|
5101
|
-
if (this.campaign_id) {
|
|
5102
|
-
var notif_el = this._get_el('overlay');
|
|
5103
|
-
if (notif_el && get_style(notif_el, 'visibility') !== 'hidden' && get_style(notif_el, 'display') !== 'none') {
|
|
5104
|
-
this._mark_delivery();
|
|
5105
|
-
}
|
|
5106
|
-
}
|
|
5107
|
-
});
|
|
5108
|
-
|
|
5109
|
-
MixpanelNotification.prototype._mark_delivery = _.safewrap(function(extra_props) {
|
|
5110
|
-
if (!this.marked_as_shown) {
|
|
5111
|
-
this.marked_as_shown = true;
|
|
5112
|
-
|
|
5113
|
-
if (this.campaign_id) {
|
|
5114
|
-
// mark notification shown (local cache)
|
|
5115
|
-
this._get_shown_campaigns()[this.campaign_id] = 1 * new Date();
|
|
5116
|
-
this.persistence.save();
|
|
5117
|
-
}
|
|
5118
|
-
|
|
5119
|
-
// track delivery
|
|
5120
|
-
this._track_event('$campaign_delivery', extra_props);
|
|
5121
|
-
|
|
5122
|
-
// mark notification shown (mixpanel property)
|
|
5123
|
-
this.mixpanel['people']['append']({
|
|
5124
|
-
'$campaigns': this.campaign_id,
|
|
5125
|
-
'$notifications': {
|
|
5126
|
-
'campaign_id': this.campaign_id,
|
|
5127
|
-
'message_id': this.message_id,
|
|
5128
|
-
'type': 'web',
|
|
5129
|
-
'time': new Date()
|
|
5130
|
-
}
|
|
5131
|
-
});
|
|
5132
|
-
}
|
|
5133
|
-
});
|
|
5134
|
-
|
|
5135
|
-
MixpanelNotification.prototype._preload_images = function(all_loaded_cb) {
|
|
5136
|
-
var self = this;
|
|
5137
|
-
if (this.imgs_to_preload.length === 0) {
|
|
5138
|
-
all_loaded_cb();
|
|
5139
|
-
return;
|
|
5140
|
-
}
|
|
5141
|
-
|
|
5142
|
-
var preloaded_imgs = 0;
|
|
5143
|
-
var img_objs = [];
|
|
5144
|
-
var onload = function() {
|
|
5145
|
-
preloaded_imgs++;
|
|
5146
|
-
if (preloaded_imgs === self.imgs_to_preload.length && all_loaded_cb) {
|
|
5147
|
-
all_loaded_cb();
|
|
5148
|
-
all_loaded_cb = null;
|
|
5149
|
-
}
|
|
5150
|
-
};
|
|
5151
|
-
for (var i = 0; i < this.imgs_to_preload.length; i++) {
|
|
5152
|
-
var img = new Image();
|
|
5153
|
-
img.onload = onload;
|
|
5154
|
-
img.src = this.imgs_to_preload[i];
|
|
5155
|
-
if (img.complete) {
|
|
5156
|
-
onload();
|
|
5157
|
-
}
|
|
5158
|
-
img_objs.push(img);
|
|
5159
|
-
}
|
|
5160
|
-
|
|
5161
|
-
// IE6/7 doesn't fire onload reliably
|
|
5162
|
-
if (this._browser_lte('ie', 7)) {
|
|
5163
|
-
setTimeout(function() {
|
|
5164
|
-
var imgs_loaded = true;
|
|
5165
|
-
for (i = 0; i < img_objs.length; i++) {
|
|
5166
|
-
if (!img_objs[i].complete) {
|
|
5167
|
-
imgs_loaded = false;
|
|
5168
|
-
}
|
|
5169
|
-
}
|
|
5170
|
-
if (imgs_loaded && all_loaded_cb) {
|
|
5171
|
-
all_loaded_cb();
|
|
5172
|
-
all_loaded_cb = null;
|
|
5173
|
-
}
|
|
5174
|
-
}, 500);
|
|
5175
|
-
}
|
|
5176
|
-
};
|
|
5177
|
-
|
|
5178
|
-
MixpanelNotification.prototype._remove_notification_el = _.safewrap(function() {
|
|
5179
|
-
window.clearInterval(this._video_progress_checker);
|
|
5180
|
-
this.notification_el.style.visibility = 'hidden';
|
|
5181
|
-
this.body_el.removeChild(this.notification_el);
|
|
5182
|
-
});
|
|
5183
|
-
|
|
5184
|
-
MixpanelNotification.prototype._set_client_config = function() {
|
|
5185
|
-
var get_browser_version = function(browser_ex) {
|
|
5186
|
-
var match = navigator.userAgent.match(browser_ex);
|
|
5187
|
-
return match && match[1];
|
|
5188
|
-
};
|
|
5189
|
-
this.browser_versions = {};
|
|
5190
|
-
this.browser_versions['chrome'] = get_browser_version(/Chrome\/(\d+)/);
|
|
5191
|
-
this.browser_versions['firefox'] = get_browser_version(/Firefox\/(\d+)/);
|
|
5192
|
-
this.browser_versions['ie'] = get_browser_version(/MSIE (\d+).+/);
|
|
5193
|
-
if (!this.browser_versions['ie'] && !(window.ActiveXObject) && 'ActiveXObject' in window) {
|
|
5194
|
-
this.browser_versions['ie'] = 11;
|
|
5195
|
-
}
|
|
5196
|
-
|
|
5197
|
-
this.body_el = document.body || document.getElementsByTagName('body')[0];
|
|
5198
|
-
if (this.body_el) {
|
|
5199
|
-
this.doc_width = Math.max(
|
|
5200
|
-
this.body_el.scrollWidth, document.documentElement.scrollWidth,
|
|
5201
|
-
this.body_el.offsetWidth, document.documentElement.offsetWidth,
|
|
5202
|
-
this.body_el.clientWidth, document.documentElement.clientWidth
|
|
5203
|
-
);
|
|
5204
|
-
this.doc_height = Math.max(
|
|
5205
|
-
this.body_el.scrollHeight, document.documentElement.scrollHeight,
|
|
5206
|
-
this.body_el.offsetHeight, document.documentElement.offsetHeight,
|
|
5207
|
-
this.body_el.clientHeight, document.documentElement.clientHeight
|
|
5208
|
-
);
|
|
5209
|
-
}
|
|
5210
|
-
|
|
5211
|
-
// detect CSS compatibility
|
|
5212
|
-
var ie_ver = this.browser_versions['ie'];
|
|
5213
|
-
var sample_styles = document.createElement('div').style,
|
|
5214
|
-
is_css_compatible = function(rule) {
|
|
5215
|
-
if (rule in sample_styles) {
|
|
5216
|
-
return true;
|
|
5217
|
-
}
|
|
5218
|
-
if (!ie_ver) {
|
|
5219
|
-
rule = rule[0].toUpperCase() + rule.slice(1);
|
|
5220
|
-
var props = ['O' + rule, 'Webkit' + rule, 'Moz' + rule];
|
|
5221
|
-
for (var i = 0; i < props.length; i++) {
|
|
5222
|
-
if (props[i] in sample_styles) {
|
|
5223
|
-
return true;
|
|
5224
|
-
}
|
|
5225
|
-
}
|
|
5226
|
-
}
|
|
5227
|
-
return false;
|
|
5228
|
-
};
|
|
5229
|
-
this.use_transitions = this.body_el &&
|
|
5230
|
-
is_css_compatible('transition') &&
|
|
5231
|
-
is_css_compatible('transform');
|
|
5232
|
-
this.flip_animate = (this.browser_versions['chrome'] >= 33 || this.browser_versions['firefox'] >= 15) &&
|
|
5233
|
-
this.body_el &&
|
|
5234
|
-
is_css_compatible('backfaceVisibility') &&
|
|
5235
|
-
is_css_compatible('perspective') &&
|
|
5236
|
-
is_css_compatible('transform');
|
|
5237
|
-
};
|
|
5238
|
-
|
|
5239
|
-
MixpanelNotification.prototype._switch_to_video = _.safewrap(function() {
|
|
5240
|
-
var self = this,
|
|
5241
|
-
anims = [
|
|
5242
|
-
{
|
|
5243
|
-
el: self._get_notification_display_el(),
|
|
5244
|
-
attr: 'opacity',
|
|
5245
|
-
start: 1.0,
|
|
5246
|
-
goal: 0.0
|
|
5247
|
-
},
|
|
5248
|
-
{
|
|
5249
|
-
el: self._get_notification_display_el(),
|
|
5250
|
-
attr: 'top',
|
|
5251
|
-
start: MixpanelNotification.NOTIF_TOP,
|
|
5252
|
-
goal: -500
|
|
5253
|
-
},
|
|
5254
|
-
{
|
|
5255
|
-
el: self._get_el('video-noflip'),
|
|
5256
|
-
attr: 'opacity',
|
|
5257
|
-
start: 0.0,
|
|
5258
|
-
goal: 1.0
|
|
5259
|
-
},
|
|
5260
|
-
{
|
|
5261
|
-
el: self._get_el('video-noflip'),
|
|
5262
|
-
attr: 'top',
|
|
5263
|
-
start: -self.video_height * 2,
|
|
5264
|
-
goal: 0
|
|
5265
|
-
}
|
|
5266
|
-
];
|
|
5267
|
-
|
|
5268
|
-
if (self.mini) {
|
|
5269
|
-
var bg = self._get_el('bg'),
|
|
5270
|
-
overlay = self._get_el('overlay');
|
|
5271
|
-
bg.style.width = '100%';
|
|
5272
|
-
bg.style.height = '100%';
|
|
5273
|
-
overlay.style.width = '100%';
|
|
5274
|
-
|
|
5275
|
-
self._add_class(self._get_notification_display_el(), 'exiting');
|
|
5276
|
-
self._add_class(bg, 'visible');
|
|
5277
|
-
|
|
5278
|
-
anims.push({
|
|
5279
|
-
el: self._get_el('bg'),
|
|
5280
|
-
attr: 'opacity',
|
|
5281
|
-
start: 0.0,
|
|
5282
|
-
goal: MixpanelNotification.BG_OPACITY
|
|
5283
|
-
});
|
|
5284
|
-
}
|
|
5285
|
-
|
|
5286
|
-
var video_el = self._get_el('video-holder');
|
|
5287
|
-
video_el.innerHTML = self.video_iframe;
|
|
5288
|
-
|
|
5289
|
-
var video_ready = function() {
|
|
5290
|
-
if (window['YT'] && window['YT']['loaded']) {
|
|
5291
|
-
self._yt_video_ready();
|
|
5292
|
-
}
|
|
5293
|
-
self.showing_video = true;
|
|
5294
|
-
self._get_notification_display_el().style.visibility = 'hidden';
|
|
5295
|
-
};
|
|
5296
|
-
if (self.flip_animate) {
|
|
5297
|
-
self._add_class('flipper', 'flipped');
|
|
5298
|
-
setTimeout(video_ready, MixpanelNotification.ANIM_TIME);
|
|
5299
|
-
} else {
|
|
5300
|
-
self._animate_els(anims, MixpanelNotification.ANIM_TIME, video_ready);
|
|
5301
|
-
}
|
|
5302
|
-
});
|
|
5303
|
-
|
|
5304
|
-
MixpanelNotification.prototype._track_event = function(event_name, properties, cb) {
|
|
5305
|
-
if (this.campaign_id) {
|
|
5306
|
-
properties = properties || {};
|
|
5307
|
-
properties = _.extend(properties, {
|
|
5308
|
-
'campaign_id': this.campaign_id,
|
|
5309
|
-
'message_id': this.message_id,
|
|
5310
|
-
'message_type': 'web_inapp',
|
|
5311
|
-
'message_subtype': this.notif_type
|
|
5312
|
-
});
|
|
5313
|
-
this.mixpanel['track'](event_name, properties, cb);
|
|
5314
|
-
} else if (cb) {
|
|
5315
|
-
cb.call();
|
|
5316
|
-
}
|
|
3705
|
+
// removes the storage entry and deletes all loaded data
|
|
3706
|
+
// forced name for tests
|
|
3707
|
+
MixpanelPersistence.prototype.clear = function() {
|
|
3708
|
+
this.remove();
|
|
3709
|
+
this['props'] = {};
|
|
5317
3710
|
};
|
|
5318
3711
|
|
|
5319
|
-
MixpanelNotification.prototype._yt_video_ready = _.safewrap(function() {
|
|
5320
|
-
var self = this;
|
|
5321
|
-
if (self.video_inited) {
|
|
5322
|
-
return;
|
|
5323
|
-
}
|
|
5324
|
-
self.video_inited = true;
|
|
5325
|
-
|
|
5326
|
-
var progress_bar = self._get_el('video-elapsed'),
|
|
5327
|
-
progress_time = self._get_el('video-time'),
|
|
5328
|
-
progress_el = self._get_el('video-progress');
|
|
5329
|
-
|
|
5330
|
-
new window['YT']['Player'](MixpanelNotification.MARKUP_PREFIX + '-video-frame', {
|
|
5331
|
-
'events': {
|
|
5332
|
-
'onReady': function(event) {
|
|
5333
|
-
var ytplayer = event['target'],
|
|
5334
|
-
video_duration = ytplayer['getDuration'](),
|
|
5335
|
-
pad = function(i) {
|
|
5336
|
-
return ('00' + i).slice(-2);
|
|
5337
|
-
},
|
|
5338
|
-
update_video_time = function(current_time) {
|
|
5339
|
-
var secs = Math.round(video_duration - current_time),
|
|
5340
|
-
mins = Math.floor(secs / 60),
|
|
5341
|
-
hours = Math.floor(mins / 60);
|
|
5342
|
-
secs -= mins * 60;
|
|
5343
|
-
mins -= hours * 60;
|
|
5344
|
-
progress_time.innerHTML = '-' + (hours ? hours + ':' : '') + pad(mins) + ':' + pad(secs);
|
|
5345
|
-
};
|
|
5346
|
-
update_video_time(0);
|
|
5347
|
-
self._video_progress_checker = window.setInterval(function() {
|
|
5348
|
-
var current_time = ytplayer['getCurrentTime']();
|
|
5349
|
-
progress_bar.style.width = (current_time / video_duration * 100) + '%';
|
|
5350
|
-
update_video_time(current_time);
|
|
5351
|
-
}, 250);
|
|
5352
|
-
_.register_event(progress_el, 'click', function(e) {
|
|
5353
|
-
var clickx = Math.max(0, e.pageX - progress_el.getBoundingClientRect().left);
|
|
5354
|
-
ytplayer['seekTo'](video_duration * clickx / progress_el.clientWidth, true);
|
|
5355
|
-
});
|
|
5356
|
-
}
|
|
5357
|
-
}
|
|
5358
|
-
});
|
|
5359
|
-
});
|
|
5360
|
-
|
|
5361
3712
|
/**
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
var MixpanelPeople = function() {};
|
|
5366
|
-
|
|
5367
|
-
_.extend(MixpanelPeople.prototype, apiActions);
|
|
5368
|
-
|
|
5369
|
-
MixpanelPeople.prototype._init = function(mixpanel_instance) {
|
|
5370
|
-
this._mixpanel = mixpanel_instance;
|
|
5371
|
-
};
|
|
5372
|
-
|
|
5373
|
-
/*
|
|
5374
|
-
* Set properties on a user record.
|
|
5375
|
-
*
|
|
5376
|
-
* ### Usage:
|
|
5377
|
-
*
|
|
5378
|
-
* mixpanel.people.set('gender', 'm');
|
|
5379
|
-
*
|
|
5380
|
-
* // or set multiple properties at once
|
|
5381
|
-
* mixpanel.people.set({
|
|
5382
|
-
* 'Company': 'Acme',
|
|
5383
|
-
* 'Plan': 'Premium',
|
|
5384
|
-
* 'Upgrade date': new Date()
|
|
5385
|
-
* });
|
|
5386
|
-
* // properties can be strings, integers, dates, or lists
|
|
5387
|
-
*
|
|
5388
|
-
* @param {Object|String} prop If a string, this is the name of the property. If an object, this is an associative array of names and values.
|
|
5389
|
-
* @param {*} [to] A value to set on the given property name
|
|
5390
|
-
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
5391
|
-
*/
|
|
5392
|
-
MixpanelPeople.prototype.set = addOptOutCheckMixpanelPeople(function(prop, to, callback) {
|
|
5393
|
-
var data = this.set_action(prop, to);
|
|
5394
|
-
if (_.isObject(prop)) {
|
|
5395
|
-
callback = to;
|
|
5396
|
-
}
|
|
5397
|
-
// make sure that the referrer info has been updated and saved
|
|
5398
|
-
if (this._get_config('save_referrer')) {
|
|
5399
|
-
this._mixpanel['persistence'].update_referrer_info(document.referrer);
|
|
5400
|
-
}
|
|
5401
|
-
|
|
5402
|
-
// update $set object with default people properties
|
|
5403
|
-
data[SET_ACTION] = _.extend(
|
|
5404
|
-
{},
|
|
5405
|
-
_.info.people_properties(),
|
|
5406
|
-
this._mixpanel['persistence'].get_referrer_info(),
|
|
5407
|
-
data[SET_ACTION]
|
|
5408
|
-
);
|
|
5409
|
-
return this._send_request(data, callback);
|
|
5410
|
-
});
|
|
5411
|
-
|
|
5412
|
-
/*
|
|
5413
|
-
* Set properties on a user record, only if they do not yet exist.
|
|
5414
|
-
* This will not overwrite previous people property values, unlike
|
|
5415
|
-
* people.set().
|
|
5416
|
-
*
|
|
5417
|
-
* ### Usage:
|
|
5418
|
-
*
|
|
5419
|
-
* mixpanel.people.set_once('First Login Date', new Date());
|
|
5420
|
-
*
|
|
5421
|
-
* // or set multiple properties at once
|
|
5422
|
-
* mixpanel.people.set_once({
|
|
5423
|
-
* 'First Login Date': new Date(),
|
|
5424
|
-
* 'Starting Plan': 'Premium'
|
|
5425
|
-
* });
|
|
5426
|
-
*
|
|
5427
|
-
* // properties can be strings, integers or dates
|
|
5428
|
-
*
|
|
5429
|
-
* @param {Object|String} prop If a string, this is the name of the property. If an object, this is an associative array of names and values.
|
|
5430
|
-
* @param {*} [to] A value to set on the given property name
|
|
5431
|
-
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
5432
|
-
*/
|
|
5433
|
-
MixpanelPeople.prototype.set_once = addOptOutCheckMixpanelPeople(function(prop, to, callback) {
|
|
5434
|
-
var data = this.set_once_action(prop, to);
|
|
5435
|
-
if (_.isObject(prop)) {
|
|
5436
|
-
callback = to;
|
|
5437
|
-
}
|
|
5438
|
-
return this._send_request(data, callback);
|
|
5439
|
-
});
|
|
5440
|
-
|
|
5441
|
-
/*
|
|
5442
|
-
* Unset properties on a user record (permanently removes the properties and their values from a profile).
|
|
5443
|
-
*
|
|
5444
|
-
* ### Usage:
|
|
5445
|
-
*
|
|
5446
|
-
* mixpanel.people.unset('gender');
|
|
5447
|
-
*
|
|
5448
|
-
* // or unset multiple properties at once
|
|
5449
|
-
* mixpanel.people.unset(['gender', 'Company']);
|
|
5450
|
-
*
|
|
5451
|
-
* @param {Array|String} prop If a string, this is the name of the property. If an array, this is a list of property names.
|
|
5452
|
-
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
5453
|
-
*/
|
|
5454
|
-
MixpanelPeople.prototype.unset = addOptOutCheckMixpanelPeople(function(prop, callback) {
|
|
5455
|
-
var data = this.unset_action(prop);
|
|
5456
|
-
return this._send_request(data, callback);
|
|
5457
|
-
});
|
|
5458
|
-
|
|
5459
|
-
/*
|
|
5460
|
-
* Increment/decrement numeric people analytics properties.
|
|
5461
|
-
*
|
|
5462
|
-
* ### Usage:
|
|
5463
|
-
*
|
|
5464
|
-
* mixpanel.people.increment('page_views', 1);
|
|
5465
|
-
*
|
|
5466
|
-
* // or, for convenience, if you're just incrementing a counter by
|
|
5467
|
-
* // 1, you can simply do
|
|
5468
|
-
* mixpanel.people.increment('page_views');
|
|
5469
|
-
*
|
|
5470
|
-
* // to decrement a counter, pass a negative number
|
|
5471
|
-
* mixpanel.people.increment('credits_left', -1);
|
|
5472
|
-
*
|
|
5473
|
-
* // like mixpanel.people.set(), you can increment multiple
|
|
5474
|
-
* // properties at once:
|
|
5475
|
-
* mixpanel.people.increment({
|
|
5476
|
-
* counter1: 1,
|
|
5477
|
-
* counter2: 6
|
|
5478
|
-
* });
|
|
5479
|
-
*
|
|
5480
|
-
* @param {Object|String} prop If a string, this is the name of the property. If an object, this is an associative array of names and numeric values.
|
|
5481
|
-
* @param {Number} [by] An amount to increment the given property
|
|
5482
|
-
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
5483
|
-
*/
|
|
5484
|
-
MixpanelPeople.prototype.increment = addOptOutCheckMixpanelPeople(function(prop, by, callback) {
|
|
5485
|
-
var data = {};
|
|
5486
|
-
var $add = {};
|
|
5487
|
-
if (_.isObject(prop)) {
|
|
5488
|
-
_.each(prop, function(v, k) {
|
|
5489
|
-
if (!this._is_reserved_property(k)) {
|
|
5490
|
-
if (isNaN(parseFloat(v))) {
|
|
5491
|
-
console.error('Invalid increment value passed to mixpanel.people.increment - must be a number');
|
|
5492
|
-
return;
|
|
5493
|
-
} else {
|
|
5494
|
-
$add[k] = v;
|
|
5495
|
-
}
|
|
5496
|
-
}
|
|
5497
|
-
}, this);
|
|
5498
|
-
callback = by;
|
|
5499
|
-
} else {
|
|
5500
|
-
// convenience: mixpanel.people.increment('property'); will
|
|
5501
|
-
// increment 'property' by 1
|
|
5502
|
-
if (_.isUndefined(by)) {
|
|
5503
|
-
by = 1;
|
|
5504
|
-
}
|
|
5505
|
-
$add[prop] = by;
|
|
5506
|
-
}
|
|
5507
|
-
data[ADD_ACTION] = $add;
|
|
5508
|
-
|
|
5509
|
-
return this._send_request(data, callback);
|
|
5510
|
-
});
|
|
5511
|
-
|
|
5512
|
-
/*
|
|
5513
|
-
* Append a value to a list-valued people analytics property.
|
|
5514
|
-
*
|
|
5515
|
-
* ### Usage:
|
|
5516
|
-
*
|
|
5517
|
-
* // append a value to a list, creating it if needed
|
|
5518
|
-
* mixpanel.people.append('pages_visited', 'homepage');
|
|
5519
|
-
*
|
|
5520
|
-
* // like mixpanel.people.set(), you can append multiple
|
|
5521
|
-
* // properties at once:
|
|
5522
|
-
* mixpanel.people.append({
|
|
5523
|
-
* list1: 'bob',
|
|
5524
|
-
* list2: 123
|
|
5525
|
-
* });
|
|
5526
|
-
*
|
|
5527
|
-
* @param {Object|String} list_name If a string, this is the name of the property. If an object, this is an associative array of names and values.
|
|
5528
|
-
* @param {*} [value] value An item to append to the list
|
|
5529
|
-
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
5530
|
-
*/
|
|
5531
|
-
MixpanelPeople.prototype.append = addOptOutCheckMixpanelPeople(function(list_name, value, callback) {
|
|
5532
|
-
if (_.isObject(list_name)) {
|
|
5533
|
-
callback = value;
|
|
5534
|
-
}
|
|
5535
|
-
var data = this.append_action(list_name, value);
|
|
5536
|
-
return this._send_request(data, callback);
|
|
5537
|
-
});
|
|
5538
|
-
|
|
5539
|
-
/*
|
|
5540
|
-
* Remove a value from a list-valued people analytics property.
|
|
5541
|
-
*
|
|
5542
|
-
* ### Usage:
|
|
5543
|
-
*
|
|
5544
|
-
* mixpanel.people.remove('School', 'UCB');
|
|
5545
|
-
*
|
|
5546
|
-
* @param {Object|String} list_name If a string, this is the name of the property. If an object, this is an associative array of names and values.
|
|
5547
|
-
* @param {*} [value] value Item to remove from the list
|
|
5548
|
-
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
5549
|
-
*/
|
|
5550
|
-
MixpanelPeople.prototype.remove = addOptOutCheckMixpanelPeople(function(list_name, value, callback) {
|
|
5551
|
-
if (_.isObject(list_name)) {
|
|
5552
|
-
callback = value;
|
|
5553
|
-
}
|
|
5554
|
-
var data = this.remove_action(list_name, value);
|
|
5555
|
-
return this._send_request(data, callback);
|
|
5556
|
-
});
|
|
5557
|
-
|
|
5558
|
-
/*
|
|
5559
|
-
* Merge a given list with a list-valued people analytics property,
|
|
5560
|
-
* excluding duplicate values.
|
|
5561
|
-
*
|
|
5562
|
-
* ### Usage:
|
|
5563
|
-
*
|
|
5564
|
-
* // merge a value to a list, creating it if needed
|
|
5565
|
-
* mixpanel.people.union('pages_visited', 'homepage');
|
|
5566
|
-
*
|
|
5567
|
-
* // like mixpanel.people.set(), you can append multiple
|
|
5568
|
-
* // properties at once:
|
|
5569
|
-
* mixpanel.people.union({
|
|
5570
|
-
* list1: 'bob',
|
|
5571
|
-
* list2: 123
|
|
5572
|
-
* });
|
|
5573
|
-
*
|
|
5574
|
-
* // like mixpanel.people.append(), you can append multiple
|
|
5575
|
-
* // values to the same list:
|
|
5576
|
-
* mixpanel.people.union({
|
|
5577
|
-
* list1: ['bob', 'billy']
|
|
5578
|
-
* });
|
|
5579
|
-
*
|
|
5580
|
-
* @param {Object|String} list_name If a string, this is the name of the property. If an object, this is an associative array of names and values.
|
|
5581
|
-
* @param {*} [value] Value / values to merge with the given property
|
|
5582
|
-
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3713
|
+
* @param {Object} props
|
|
3714
|
+
* @param {*=} default_value
|
|
3715
|
+
* @param {number=} days
|
|
5583
3716
|
*/
|
|
5584
|
-
|
|
5585
|
-
if (_.isObject(
|
|
5586
|
-
|
|
3717
|
+
MixpanelPersistence.prototype.register_once = function(props, default_value, days) {
|
|
3718
|
+
if (_.isObject(props)) {
|
|
3719
|
+
if (typeof(default_value) === 'undefined') { default_value = 'None'; }
|
|
3720
|
+
this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days;
|
|
3721
|
+
|
|
3722
|
+
_.each(props, function(val, prop) {
|
|
3723
|
+
if (!this['props'].hasOwnProperty(prop) || this['props'][prop] === default_value) {
|
|
3724
|
+
this['props'][prop] = val;
|
|
3725
|
+
}
|
|
3726
|
+
}, this);
|
|
3727
|
+
|
|
3728
|
+
this.save();
|
|
3729
|
+
|
|
3730
|
+
return true;
|
|
5587
3731
|
}
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
});
|
|
3732
|
+
return false;
|
|
3733
|
+
};
|
|
5591
3734
|
|
|
5592
|
-
|
|
5593
|
-
*
|
|
5594
|
-
*
|
|
5595
|
-
* Mixpanel revenue report.
|
|
5596
|
-
*
|
|
5597
|
-
* ### Usage:
|
|
5598
|
-
*
|
|
5599
|
-
* // charge a user $50
|
|
5600
|
-
* mixpanel.people.track_charge(50);
|
|
5601
|
-
*
|
|
5602
|
-
* // charge a user $30.50 on the 2nd of january
|
|
5603
|
-
* mixpanel.people.track_charge(30.50, {
|
|
5604
|
-
* '$time': new Date('jan 1 2012')
|
|
5605
|
-
* });
|
|
5606
|
-
*
|
|
5607
|
-
* @param {Number} amount The amount of money charged to the current user
|
|
5608
|
-
* @param {Object} [properties] An associative array of properties associated with the charge
|
|
5609
|
-
* @param {Function} [callback] If provided, the callback will be called when the server responds
|
|
3735
|
+
/**
|
|
3736
|
+
* @param {Object} props
|
|
3737
|
+
* @param {number=} days
|
|
5610
3738
|
*/
|
|
5611
|
-
|
|
5612
|
-
if (
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
3739
|
+
MixpanelPersistence.prototype.register = function(props, days) {
|
|
3740
|
+
if (_.isObject(props)) {
|
|
3741
|
+
this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days;
|
|
3742
|
+
|
|
3743
|
+
_.extend(this['props'], props);
|
|
3744
|
+
|
|
3745
|
+
this.save();
|
|
3746
|
+
|
|
3747
|
+
return true;
|
|
3748
|
+
}
|
|
3749
|
+
return false;
|
|
3750
|
+
};
|
|
3751
|
+
|
|
3752
|
+
MixpanelPersistence.prototype.unregister = function(prop) {
|
|
3753
|
+
if (prop in this['props']) {
|
|
3754
|
+
delete this['props'][prop];
|
|
3755
|
+
this.save();
|
|
5618
3756
|
}
|
|
3757
|
+
};
|
|
5619
3758
|
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
3759
|
+
MixpanelPersistence.prototype.update_campaign_params = function() {
|
|
3760
|
+
if (!this.campaign_params_saved) {
|
|
3761
|
+
this.register_once(_.info.campaignParams());
|
|
3762
|
+
this.campaign_params_saved = true;
|
|
3763
|
+
}
|
|
3764
|
+
};
|
|
5624
3765
|
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
* current user's people analytics profile.
|
|
5628
|
-
*
|
|
5629
|
-
* ### Usage:
|
|
5630
|
-
*
|
|
5631
|
-
* mixpanel.people.clear_charges();
|
|
5632
|
-
*
|
|
5633
|
-
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
5634
|
-
*/
|
|
5635
|
-
MixpanelPeople.prototype.clear_charges = function(callback) {
|
|
5636
|
-
return this.set('$transactions', [], callback);
|
|
3766
|
+
MixpanelPersistence.prototype.update_search_keyword = function(referrer) {
|
|
3767
|
+
this.register(_.info.searchInfo(referrer));
|
|
5637
3768
|
};
|
|
5638
3769
|
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
3770
|
+
// EXPORTED METHOD, we test this directly.
|
|
3771
|
+
MixpanelPersistence.prototype.update_referrer_info = function(referrer) {
|
|
3772
|
+
// If referrer doesn't exist, we want to note the fact that it was type-in traffic.
|
|
3773
|
+
this.register_once({
|
|
3774
|
+
'$initial_referrer': referrer || '$direct',
|
|
3775
|
+
'$initial_referring_domain': _.info.referringDomain(referrer) || '$direct'
|
|
3776
|
+
}, '');
|
|
3777
|
+
};
|
|
3778
|
+
|
|
3779
|
+
MixpanelPersistence.prototype.get_referrer_info = function() {
|
|
3780
|
+
return _.strip_empty_properties({
|
|
3781
|
+
'$initial_referrer': this['props']['$initial_referrer'],
|
|
3782
|
+
'$initial_referring_domain': this['props']['$initial_referring_domain']
|
|
3783
|
+
});
|
|
3784
|
+
};
|
|
3785
|
+
|
|
3786
|
+
// safely fills the passed in object with stored properties,
|
|
3787
|
+
// does not override any properties defined in both
|
|
3788
|
+
// returns the passed in object
|
|
3789
|
+
MixpanelPersistence.prototype.safe_merge = function(props) {
|
|
3790
|
+
_.each(this['props'], function(val, prop) {
|
|
3791
|
+
if (!(prop in props)) {
|
|
3792
|
+
props[prop] = val;
|
|
3793
|
+
}
|
|
3794
|
+
});
|
|
3795
|
+
|
|
3796
|
+
return props;
|
|
3797
|
+
};
|
|
3798
|
+
|
|
3799
|
+
MixpanelPersistence.prototype.update_config = function(config) {
|
|
3800
|
+
this.default_expiry = this.expire_days = config['cookie_expiration'];
|
|
3801
|
+
this.set_disabled(config['disable_persistence']);
|
|
3802
|
+
this.set_cookie_domain(config['cookie_domain']);
|
|
3803
|
+
this.set_cross_site(config['cross_site_cookie']);
|
|
3804
|
+
this.set_cross_subdomain(config['cross_subdomain_cookie']);
|
|
3805
|
+
this.set_secure(config['secure_cookie']);
|
|
3806
|
+
};
|
|
3807
|
+
|
|
3808
|
+
MixpanelPersistence.prototype.set_disabled = function(disabled) {
|
|
3809
|
+
this.disabled = disabled;
|
|
3810
|
+
if (this.disabled) {
|
|
3811
|
+
this.remove();
|
|
3812
|
+
} else {
|
|
3813
|
+
this.save();
|
|
5653
3814
|
}
|
|
5654
|
-
var data = {'$delete': this._mixpanel.get_distinct_id()};
|
|
5655
|
-
return this._send_request(data);
|
|
5656
3815
|
};
|
|
5657
3816
|
|
|
5658
|
-
|
|
5659
|
-
|
|
3817
|
+
MixpanelPersistence.prototype.set_cookie_domain = function(cookie_domain) {
|
|
3818
|
+
if (cookie_domain !== this.cookie_domain) {
|
|
3819
|
+
this.remove();
|
|
3820
|
+
this.cookie_domain = cookie_domain;
|
|
3821
|
+
this.save();
|
|
3822
|
+
}
|
|
5660
3823
|
};
|
|
5661
3824
|
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
var had_persisted_distinct_id = this._mixpanel.get_property('$had_persisted_distinct_id');
|
|
5668
|
-
if (device_id) {
|
|
5669
|
-
data['$device_id'] = device_id;
|
|
3825
|
+
MixpanelPersistence.prototype.set_cross_site = function(cross_site) {
|
|
3826
|
+
if (cross_site !== this.cross_site) {
|
|
3827
|
+
this.cross_site = cross_site;
|
|
3828
|
+
this.remove();
|
|
3829
|
+
this.save();
|
|
5670
3830
|
}
|
|
5671
|
-
|
|
5672
|
-
|
|
3831
|
+
};
|
|
3832
|
+
|
|
3833
|
+
MixpanelPersistence.prototype.set_cross_subdomain = function(cross_subdomain) {
|
|
3834
|
+
if (cross_subdomain !== this.cross_subdomain) {
|
|
3835
|
+
this.cross_subdomain = cross_subdomain;
|
|
3836
|
+
this.remove();
|
|
3837
|
+
this.save();
|
|
5673
3838
|
}
|
|
5674
|
-
|
|
5675
|
-
|
|
3839
|
+
};
|
|
3840
|
+
|
|
3841
|
+
MixpanelPersistence.prototype.get_cross_subdomain = function() {
|
|
3842
|
+
return this.cross_subdomain;
|
|
3843
|
+
};
|
|
3844
|
+
|
|
3845
|
+
MixpanelPersistence.prototype.set_secure = function(secure) {
|
|
3846
|
+
if (secure !== this.secure) {
|
|
3847
|
+
this.secure = secure ? true : false;
|
|
3848
|
+
this.remove();
|
|
3849
|
+
this.save();
|
|
5676
3850
|
}
|
|
3851
|
+
};
|
|
5677
3852
|
|
|
5678
|
-
|
|
3853
|
+
MixpanelPersistence.prototype._add_to_people_queue = function(queue, data) {
|
|
3854
|
+
var q_key = this._get_queue_key(queue),
|
|
3855
|
+
q_data = data[queue],
|
|
3856
|
+
set_q = this._get_or_create_queue(SET_ACTION),
|
|
3857
|
+
set_once_q = this._get_or_create_queue(SET_ONCE_ACTION),
|
|
3858
|
+
unset_q = this._get_or_create_queue(UNSET_ACTION),
|
|
3859
|
+
add_q = this._get_or_create_queue(ADD_ACTION),
|
|
3860
|
+
union_q = this._get_or_create_queue(UNION_ACTION),
|
|
3861
|
+
remove_q = this._get_or_create_queue(REMOVE_ACTION, []),
|
|
3862
|
+
append_q = this._get_or_create_queue(APPEND_ACTION, []);
|
|
5679
3863
|
|
|
5680
|
-
if (
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
3864
|
+
if (q_key === SET_QUEUE_KEY) {
|
|
3865
|
+
// Update the set queue - we can override any existing values
|
|
3866
|
+
_.extend(set_q, q_data);
|
|
3867
|
+
// if there was a pending increment, override it
|
|
3868
|
+
// with the set.
|
|
3869
|
+
this._pop_from_people_queue(ADD_ACTION, q_data);
|
|
3870
|
+
// if there was a pending union, override it
|
|
3871
|
+
// with the set.
|
|
3872
|
+
this._pop_from_people_queue(UNION_ACTION, q_data);
|
|
3873
|
+
this._pop_from_people_queue(UNSET_ACTION, q_data);
|
|
3874
|
+
} else if (q_key === SET_ONCE_QUEUE_KEY) {
|
|
3875
|
+
// only queue the data if there is not already a set_once call for it.
|
|
3876
|
+
_.each(q_data, function(v, k) {
|
|
3877
|
+
if (!(k in set_once_q)) {
|
|
3878
|
+
set_once_q[k] = v;
|
|
3879
|
+
}
|
|
3880
|
+
});
|
|
3881
|
+
this._pop_from_people_queue(UNSET_ACTION, q_data);
|
|
3882
|
+
} else if (q_key === UNSET_QUEUE_KEY) {
|
|
3883
|
+
_.each(q_data, function(prop) {
|
|
3884
|
+
|
|
3885
|
+
// undo previously-queued actions on this key
|
|
3886
|
+
_.each([set_q, set_once_q, add_q, union_q], function(enqueued_obj) {
|
|
3887
|
+
if (prop in enqueued_obj) {
|
|
3888
|
+
delete enqueued_obj[prop];
|
|
3889
|
+
}
|
|
3890
|
+
});
|
|
3891
|
+
_.each(append_q, function(append_obj) {
|
|
3892
|
+
if (prop in append_obj) {
|
|
3893
|
+
delete append_obj[prop];
|
|
3894
|
+
}
|
|
3895
|
+
});
|
|
3896
|
+
|
|
3897
|
+
unset_q[prop] = true;
|
|
3898
|
+
|
|
3899
|
+
});
|
|
3900
|
+
} else if (q_key === ADD_QUEUE_KEY) {
|
|
3901
|
+
_.each(q_data, function(v, k) {
|
|
3902
|
+
// If it exists in the set queue, increment
|
|
3903
|
+
// the value
|
|
3904
|
+
if (k in set_q) {
|
|
3905
|
+
set_q[k] += v;
|
|
5685
3906
|
} else {
|
|
5686
|
-
|
|
3907
|
+
// If it doesn't exist, update the add
|
|
3908
|
+
// queue
|
|
3909
|
+
if (!(k in add_q)) {
|
|
3910
|
+
add_q[k] = 0;
|
|
3911
|
+
}
|
|
3912
|
+
add_q[k] += v;
|
|
5687
3913
|
}
|
|
5688
|
-
}
|
|
5689
|
-
|
|
3914
|
+
}, this);
|
|
3915
|
+
this._pop_from_people_queue(UNSET_ACTION, q_data);
|
|
3916
|
+
} else if (q_key === UNION_QUEUE_KEY) {
|
|
3917
|
+
_.each(q_data, function(v, k) {
|
|
3918
|
+
if (_.isArray(v)) {
|
|
3919
|
+
if (!(k in union_q)) {
|
|
3920
|
+
union_q[k] = [];
|
|
3921
|
+
}
|
|
3922
|
+
// We may send duplicates, the server will dedup them.
|
|
3923
|
+
union_q[k] = union_q[k].concat(v);
|
|
3924
|
+
}
|
|
3925
|
+
});
|
|
3926
|
+
this._pop_from_people_queue(UNSET_ACTION, q_data);
|
|
3927
|
+
} else if (q_key === REMOVE_QUEUE_KEY) {
|
|
3928
|
+
remove_q.push(q_data);
|
|
3929
|
+
this._pop_from_people_queue(APPEND_ACTION, q_data);
|
|
3930
|
+
} else if (q_key === APPEND_QUEUE_KEY) {
|
|
3931
|
+
append_q.push(q_data);
|
|
3932
|
+
this._pop_from_people_queue(UNSET_ACTION, q_data);
|
|
5690
3933
|
}
|
|
5691
3934
|
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
data: date_encoded_data,
|
|
5695
|
-
endpoint: this._get_config('api_host') + '/engage/',
|
|
5696
|
-
batcher: this._mixpanel.request_batchers.people
|
|
5697
|
-
}, callback);
|
|
5698
|
-
};
|
|
3935
|
+
console.log('MIXPANEL PEOPLE REQUEST (QUEUED, PENDING IDENTIFY):');
|
|
3936
|
+
console.log(data);
|
|
5699
3937
|
|
|
5700
|
-
|
|
5701
|
-
return this._mixpanel.get_config(conf_var);
|
|
3938
|
+
this.save();
|
|
5702
3939
|
};
|
|
5703
3940
|
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
3941
|
+
MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) {
|
|
3942
|
+
var q = this._get_queue(queue);
|
|
3943
|
+
if (!_.isUndefined(q)) {
|
|
3944
|
+
_.each(data, function(v, k) {
|
|
3945
|
+
if (queue === APPEND_ACTION || queue === REMOVE_ACTION) {
|
|
3946
|
+
// list actions: only remove if both k+v match
|
|
3947
|
+
// e.g. remove should not override append in a case like
|
|
3948
|
+
// append({foo: 'bar'}); remove({foo: 'qux'})
|
|
3949
|
+
_.each(q, function(queued_action) {
|
|
3950
|
+
if (queued_action[k] === v) {
|
|
3951
|
+
delete queued_action[k];
|
|
3952
|
+
}
|
|
3953
|
+
});
|
|
3954
|
+
} else {
|
|
3955
|
+
delete q[k];
|
|
3956
|
+
}
|
|
3957
|
+
}, this);
|
|
5707
3958
|
|
|
5708
|
-
|
|
5709
|
-
MixpanelPeople.prototype._enqueue = function(data) {
|
|
5710
|
-
if (SET_ACTION in data) {
|
|
5711
|
-
this._mixpanel['persistence']._add_to_people_queue(SET_ACTION, data);
|
|
5712
|
-
} else if (SET_ONCE_ACTION in data) {
|
|
5713
|
-
this._mixpanel['persistence']._add_to_people_queue(SET_ONCE_ACTION, data);
|
|
5714
|
-
} else if (UNSET_ACTION in data) {
|
|
5715
|
-
this._mixpanel['persistence']._add_to_people_queue(UNSET_ACTION, data);
|
|
5716
|
-
} else if (ADD_ACTION in data) {
|
|
5717
|
-
this._mixpanel['persistence']._add_to_people_queue(ADD_ACTION, data);
|
|
5718
|
-
} else if (APPEND_ACTION in data) {
|
|
5719
|
-
this._mixpanel['persistence']._add_to_people_queue(APPEND_ACTION, data);
|
|
5720
|
-
} else if (REMOVE_ACTION in data) {
|
|
5721
|
-
this._mixpanel['persistence']._add_to_people_queue(REMOVE_ACTION, data);
|
|
5722
|
-
} else if (UNION_ACTION in data) {
|
|
5723
|
-
this._mixpanel['persistence']._add_to_people_queue(UNION_ACTION, data);
|
|
5724
|
-
} else {
|
|
5725
|
-
console.error('Invalid call to _enqueue():', data);
|
|
3959
|
+
this.save();
|
|
5726
3960
|
}
|
|
5727
3961
|
};
|
|
5728
3962
|
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
}
|
|
5747
|
-
});
|
|
3963
|
+
MixpanelPersistence.prototype._get_queue_key = function(queue) {
|
|
3964
|
+
if (queue === SET_ACTION) {
|
|
3965
|
+
return SET_QUEUE_KEY;
|
|
3966
|
+
} else if (queue === SET_ONCE_ACTION) {
|
|
3967
|
+
return SET_ONCE_QUEUE_KEY;
|
|
3968
|
+
} else if (queue === UNSET_ACTION) {
|
|
3969
|
+
return UNSET_QUEUE_KEY;
|
|
3970
|
+
} else if (queue === ADD_ACTION) {
|
|
3971
|
+
return ADD_QUEUE_KEY;
|
|
3972
|
+
} else if (queue === APPEND_ACTION) {
|
|
3973
|
+
return APPEND_QUEUE_KEY;
|
|
3974
|
+
} else if (queue === REMOVE_ACTION) {
|
|
3975
|
+
return REMOVE_QUEUE_KEY;
|
|
3976
|
+
} else if (queue === UNION_ACTION) {
|
|
3977
|
+
return UNION_QUEUE_KEY;
|
|
3978
|
+
} else {
|
|
3979
|
+
console.error('Invalid queue:', queue);
|
|
5748
3980
|
}
|
|
5749
3981
|
};
|
|
5750
3982
|
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
)
|
|
5756
|
-
|
|
5757
|
-
var $append_queue = this._mixpanel['persistence']._get_queue(APPEND_ACTION);
|
|
5758
|
-
var $remove_queue = this._mixpanel['persistence']._get_queue(REMOVE_ACTION);
|
|
5759
|
-
|
|
5760
|
-
this._flush_one_queue(SET_ACTION, this.set, _set_callback);
|
|
5761
|
-
this._flush_one_queue(SET_ONCE_ACTION, this.set_once, _set_once_callback);
|
|
5762
|
-
this._flush_one_queue(UNSET_ACTION, this.unset, _unset_callback, function(queue) { return _.keys(queue); });
|
|
5763
|
-
this._flush_one_queue(ADD_ACTION, this.increment, _add_callback);
|
|
5764
|
-
this._flush_one_queue(UNION_ACTION, this.union, _union_callback);
|
|
5765
|
-
|
|
5766
|
-
// we have to fire off each $append individually since there is
|
|
5767
|
-
// no concat method server side
|
|
5768
|
-
if (!_.isUndefined($append_queue) && _.isArray($append_queue) && $append_queue.length) {
|
|
5769
|
-
var $append_item;
|
|
5770
|
-
var append_callback = function(response, data) {
|
|
5771
|
-
if (response === 0) {
|
|
5772
|
-
_this._mixpanel['persistence']._add_to_people_queue(APPEND_ACTION, $append_item);
|
|
5773
|
-
}
|
|
5774
|
-
if (!_.isUndefined(_append_callback)) {
|
|
5775
|
-
_append_callback(response, data);
|
|
5776
|
-
}
|
|
5777
|
-
};
|
|
5778
|
-
for (var i = $append_queue.length - 1; i >= 0; i--) {
|
|
5779
|
-
$append_item = $append_queue.pop();
|
|
5780
|
-
if (!_.isEmptyObject($append_item)) {
|
|
5781
|
-
_this.append($append_item, append_callback);
|
|
5782
|
-
}
|
|
5783
|
-
}
|
|
5784
|
-
// Save the shortened append queue
|
|
5785
|
-
_this._mixpanel['persistence'].save();
|
|
5786
|
-
}
|
|
3983
|
+
MixpanelPersistence.prototype._get_queue = function(queue) {
|
|
3984
|
+
return this['props'][this._get_queue_key(queue)];
|
|
3985
|
+
};
|
|
3986
|
+
MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val) {
|
|
3987
|
+
var key = this._get_queue_key(queue);
|
|
3988
|
+
default_val = _.isUndefined(default_val) ? {} : default_val;
|
|
5787
3989
|
|
|
5788
|
-
|
|
5789
|
-
if (!_.isUndefined($remove_queue) && _.isArray($remove_queue) && $remove_queue.length) {
|
|
5790
|
-
var $remove_item;
|
|
5791
|
-
var remove_callback = function(response, data) {
|
|
5792
|
-
if (response === 0) {
|
|
5793
|
-
_this._mixpanel['persistence']._add_to_people_queue(REMOVE_ACTION, $remove_item);
|
|
5794
|
-
}
|
|
5795
|
-
if (!_.isUndefined(_remove_callback)) {
|
|
5796
|
-
_remove_callback(response, data);
|
|
5797
|
-
}
|
|
5798
|
-
};
|
|
5799
|
-
for (var j = $remove_queue.length - 1; j >= 0; j--) {
|
|
5800
|
-
$remove_item = $remove_queue.pop();
|
|
5801
|
-
if (!_.isEmptyObject($remove_item)) {
|
|
5802
|
-
_this.remove($remove_item, remove_callback);
|
|
5803
|
-
}
|
|
5804
|
-
}
|
|
5805
|
-
_this._mixpanel['persistence'].save();
|
|
5806
|
-
}
|
|
3990
|
+
return this['props'][key] || (this['props'][key] = default_val);
|
|
5807
3991
|
};
|
|
5808
3992
|
|
|
5809
|
-
|
|
5810
|
-
|
|
3993
|
+
MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) {
|
|
3994
|
+
var timers = this['props'][EVENT_TIMERS_KEY] || {};
|
|
3995
|
+
timers[event_name] = timestamp;
|
|
3996
|
+
this['props'][EVENT_TIMERS_KEY] = timers;
|
|
3997
|
+
this.save();
|
|
5811
3998
|
};
|
|
5812
3999
|
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
MixpanelPeople.prototype['clear_charges'] = MixpanelPeople.prototype.clear_charges;
|
|
5823
|
-
MixpanelPeople.prototype['delete_user'] = MixpanelPeople.prototype.delete_user;
|
|
5824
|
-
MixpanelPeople.prototype['toString'] = MixpanelPeople.prototype.toString;
|
|
4000
|
+
MixpanelPersistence.prototype.remove_event_timer = function(event_name) {
|
|
4001
|
+
var timers = this['props'][EVENT_TIMERS_KEY] || {};
|
|
4002
|
+
var timestamp = timers[event_name];
|
|
4003
|
+
if (!_.isUndefined(timestamp)) {
|
|
4004
|
+
delete this['props'][EVENT_TIMERS_KEY][event_name];
|
|
4005
|
+
this.save();
|
|
4006
|
+
}
|
|
4007
|
+
return timestamp;
|
|
4008
|
+
};
|
|
5825
4009
|
|
|
5826
4010
|
/*
|
|
5827
4011
|
* Mixpanel JS Library
|
|
@@ -5859,6 +4043,8 @@ var IDENTITY_FUNC = function(x) {return x;};
|
|
|
5859
4043
|
var NOOP_FUNC = function() {};
|
|
5860
4044
|
|
|
5861
4045
|
/** @const */ var PRIMARY_INSTANCE_NAME = 'mixpanel';
|
|
4046
|
+
/** @const */ var PAYLOAD_TYPE_BASE64 = 'base64';
|
|
4047
|
+
/** @const */ var PAYLOAD_TYPE_JSON = 'json';
|
|
5862
4048
|
|
|
5863
4049
|
|
|
5864
4050
|
/*
|
|
@@ -5875,10 +4061,10 @@ var ENQUEUE_REQUESTS = !USE_XHR && (userAgent.indexOf('MSIE') === -1) && (userAg
|
|
|
5875
4061
|
|
|
5876
4062
|
// save reference to navigator.sendBeacon so it can be minified
|
|
5877
4063
|
var sendBeacon = null;
|
|
5878
|
-
if (navigator
|
|
4064
|
+
if (navigator['sendBeacon']) {
|
|
5879
4065
|
sendBeacon = function() {
|
|
5880
4066
|
// late reference to navigator.sendBeacon to allow patching/spying
|
|
5881
|
-
return navigator
|
|
4067
|
+
return navigator['sendBeacon'].apply(navigator, arguments);
|
|
5882
4068
|
};
|
|
5883
4069
|
}
|
|
5884
4070
|
|
|
@@ -5889,10 +4075,12 @@ var DEFAULT_CONFIG = {
|
|
|
5889
4075
|
'api_host': 'https://api-js.mixpanel.com',
|
|
5890
4076
|
'api_method': 'POST',
|
|
5891
4077
|
'api_transport': 'XHR',
|
|
4078
|
+
'api_payload_format': PAYLOAD_TYPE_BASE64,
|
|
5892
4079
|
'app_host': 'https://mixpanel.com',
|
|
5893
4080
|
'cdn': 'https://cdn.mxpnl.com',
|
|
5894
4081
|
'cross_site_cookie': false,
|
|
5895
4082
|
'cross_subdomain_cookie': true,
|
|
4083
|
+
'error_reporter': NOOP_FUNC,
|
|
5896
4084
|
'persistence': 'cookie',
|
|
5897
4085
|
'persistence_name': '',
|
|
5898
4086
|
'cookie_domain': '',
|
|
@@ -5917,10 +4105,8 @@ var DEFAULT_CONFIG = {
|
|
|
5917
4105
|
'opt_out_tracking_cookie_prefix': null,
|
|
5918
4106
|
'property_blacklist': [],
|
|
5919
4107
|
'xhr_headers': {}, // { header: value, header2: value }
|
|
5920
|
-
'inapp_protocol': '//',
|
|
5921
|
-
'inapp_link_new_window': false,
|
|
5922
4108
|
'ignore_dnt': false,
|
|
5923
|
-
'batch_requests':
|
|
4109
|
+
'batch_requests': true,
|
|
5924
4110
|
'batch_size': 50,
|
|
5925
4111
|
'batch_flush_interval_ms': 5000,
|
|
5926
4112
|
'batch_request_timeout_ms': 90000,
|
|
@@ -5960,8 +4146,6 @@ var create_mplib = function(token, config, name) {
|
|
|
5960
4146
|
}
|
|
5961
4147
|
|
|
5962
4148
|
instance._cached_groups = {}; // cache groups in a pool
|
|
5963
|
-
instance._user_decide_check_complete = false;
|
|
5964
|
-
instance._events_tracked_before_user_decide_check_complete = [];
|
|
5965
4149
|
|
|
5966
4150
|
instance._init(token, config, name);
|
|
5967
4151
|
|
|
@@ -5984,12 +4168,6 @@ var create_mplib = function(token, config, name) {
|
|
|
5984
4168
|
return instance;
|
|
5985
4169
|
};
|
|
5986
4170
|
|
|
5987
|
-
var encode_data_for_request = function(data) {
|
|
5988
|
-
var json_data = _.JSONEncode(data);
|
|
5989
|
-
var encoded_data = _.base64Encode(json_data);
|
|
5990
|
-
return {'data': encoded_data};
|
|
5991
|
-
};
|
|
5992
|
-
|
|
5993
4171
|
// Initialization methods
|
|
5994
4172
|
|
|
5995
4173
|
/**
|
|
@@ -6010,11 +4188,11 @@ var encode_data_for_request = function(data) {
|
|
|
6010
4188
|
*/
|
|
6011
4189
|
MixpanelLib.prototype.init = function (token, config, name) {
|
|
6012
4190
|
if (_.isUndefined(name)) {
|
|
6013
|
-
|
|
4191
|
+
this.report_error('You must name your new library: init(token, config, name)');
|
|
6014
4192
|
return;
|
|
6015
4193
|
}
|
|
6016
4194
|
if (name === PRIMARY_INSTANCE_NAME) {
|
|
6017
|
-
|
|
4195
|
+
this.report_error('You must initialize the main mixpanel object right after you include the Mixpanel js snippet');
|
|
6018
4196
|
return;
|
|
6019
4197
|
}
|
|
6020
4198
|
|
|
@@ -6037,16 +4215,15 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
6037
4215
|
|
|
6038
4216
|
this['__loaded'] = true;
|
|
6039
4217
|
this['config'] = {};
|
|
6040
|
-
this['_triggered_notifs'] = [];
|
|
6041
4218
|
|
|
6042
|
-
// rollout: enable batch_requests by default for 60% of projects
|
|
6043
|
-
// (only if they have not specified a value in their init config
|
|
6044
|
-
// and they aren't using a custom API host)
|
|
6045
4219
|
var variable_features = {};
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
if (!('
|
|
6049
|
-
|
|
4220
|
+
|
|
4221
|
+
// default to JSON payload for standard mixpanel.com API hosts
|
|
4222
|
+
if (!('api_payload_format' in config)) {
|
|
4223
|
+
var api_host = config['api_host'] || DEFAULT_CONFIG['api_host'];
|
|
4224
|
+
if (api_host.match(/\.mixpanel\.com$/)) {
|
|
4225
|
+
variable_features['api_payload_format'] = PAYLOAD_TYPE_JSON;
|
|
4226
|
+
}
|
|
6050
4227
|
}
|
|
6051
4228
|
|
|
6052
4229
|
this.set_config(_.extend({}, DEFAULT_CONFIG, variable_features, config, {
|
|
@@ -6075,15 +4252,32 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
6075
4252
|
} else {
|
|
6076
4253
|
this.init_batchers();
|
|
6077
4254
|
if (sendBeacon && window$1.addEventListener) {
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
4255
|
+
// Before page closes or hides (user tabs away etc), attempt to flush any events
|
|
4256
|
+
// queued up via navigator.sendBeacon. Since sendBeacon doesn't report success/failure,
|
|
4257
|
+
// events will not be removed from the persistent store; if the site is loaded again,
|
|
4258
|
+
// the events will be flushed again on startup and deduplicated on the Mixpanel server
|
|
4259
|
+
// side.
|
|
4260
|
+
// There is no reliable way to capture only page close events, so we lean on the
|
|
4261
|
+
// visibilitychange and pagehide events as recommended at
|
|
4262
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event#usage_notes.
|
|
4263
|
+
// These events fire when the user clicks away from the current page/tab, so will occur
|
|
4264
|
+
// more frequently than page unload, but are the only mechanism currently for capturing
|
|
4265
|
+
// this scenario somewhat reliably.
|
|
4266
|
+
var flush_on_unload = _.bind(function() {
|
|
6083
4267
|
if (!this.request_batchers.events.stopped) {
|
|
6084
4268
|
this.request_batchers.events.flush({unloading: true});
|
|
6085
4269
|
}
|
|
6086
|
-
}, this)
|
|
4270
|
+
}, this);
|
|
4271
|
+
window$1.addEventListener('pagehide', function(ev) {
|
|
4272
|
+
if (ev['persisted']) {
|
|
4273
|
+
flush_on_unload();
|
|
4274
|
+
}
|
|
4275
|
+
});
|
|
4276
|
+
window$1.addEventListener('visibilitychange', function() {
|
|
4277
|
+
if (document$1['visibilityState'] === 'hidden') {
|
|
4278
|
+
flush_on_unload();
|
|
4279
|
+
}
|
|
4280
|
+
});
|
|
6087
4281
|
}
|
|
6088
4282
|
}
|
|
6089
4283
|
}
|
|
@@ -6139,7 +4333,7 @@ MixpanelLib.prototype._dom_loaded = function() {
|
|
|
6139
4333
|
|
|
6140
4334
|
MixpanelLib.prototype._track_dom = function(DomClass, args) {
|
|
6141
4335
|
if (this.get_config('img')) {
|
|
6142
|
-
|
|
4336
|
+
this.report_error('You can\'t use DOM tracking functions with img = true.');
|
|
6143
4337
|
return false;
|
|
6144
4338
|
}
|
|
6145
4339
|
|
|
@@ -6241,6 +4435,7 @@ MixpanelLib.prototype._send_request = function(url, data, options, callback) {
|
|
|
6241
4435
|
|
|
6242
4436
|
url += '?' + _.HTTPBuildQuery(data);
|
|
6243
4437
|
|
|
4438
|
+
var lib = this;
|
|
6244
4439
|
if ('img' in data) {
|
|
6245
4440
|
var img = document$1.createElement('img');
|
|
6246
4441
|
img.src = url;
|
|
@@ -6249,7 +4444,7 @@ MixpanelLib.prototype._send_request = function(url, data, options, callback) {
|
|
|
6249
4444
|
try {
|
|
6250
4445
|
succeeded = sendBeacon(url, body_data);
|
|
6251
4446
|
} catch (e) {
|
|
6252
|
-
|
|
4447
|
+
lib.report_error(e);
|
|
6253
4448
|
succeeded = false;
|
|
6254
4449
|
}
|
|
6255
4450
|
try {
|
|
@@ -6257,7 +4452,7 @@ MixpanelLib.prototype._send_request = function(url, data, options, callback) {
|
|
|
6257
4452
|
callback(succeeded ? 1 : 0);
|
|
6258
4453
|
}
|
|
6259
4454
|
} catch (e) {
|
|
6260
|
-
|
|
4455
|
+
lib.report_error(e);
|
|
6261
4456
|
}
|
|
6262
4457
|
} else if (USE_XHR) {
|
|
6263
4458
|
try {
|
|
@@ -6289,7 +4484,7 @@ MixpanelLib.prototype._send_request = function(url, data, options, callback) {
|
|
|
6289
4484
|
try {
|
|
6290
4485
|
response = _.JSONDecode(req.responseText);
|
|
6291
4486
|
} catch (e) {
|
|
6292
|
-
|
|
4487
|
+
lib.report_error(e);
|
|
6293
4488
|
if (options.ignore_json_errors) {
|
|
6294
4489
|
response = req.responseText;
|
|
6295
4490
|
} else {
|
|
@@ -6312,7 +4507,7 @@ MixpanelLib.prototype._send_request = function(url, data, options, callback) {
|
|
|
6312
4507
|
} else {
|
|
6313
4508
|
error = 'Bad HTTP status: ' + req.status + ' ' + req.statusText;
|
|
6314
4509
|
}
|
|
6315
|
-
|
|
4510
|
+
lib.report_error(error);
|
|
6316
4511
|
if (callback) {
|
|
6317
4512
|
if (verbose_mode) {
|
|
6318
4513
|
callback({status: 0, error: error, xhr_req: req});
|
|
@@ -6325,7 +4520,7 @@ MixpanelLib.prototype._send_request = function(url, data, options, callback) {
|
|
|
6325
4520
|
};
|
|
6326
4521
|
req.send(body_data);
|
|
6327
4522
|
} catch (e) {
|
|
6328
|
-
|
|
4523
|
+
lib.report_error(e);
|
|
6329
4524
|
succeeded = false;
|
|
6330
4525
|
}
|
|
6331
4526
|
} else {
|
|
@@ -6408,14 +4603,16 @@ MixpanelLib.prototype.init_batchers = function() {
|
|
|
6408
4603
|
sendRequestFunc: _.bind(function(data, options, cb) {
|
|
6409
4604
|
this._send_request(
|
|
6410
4605
|
this.get_config('api_host') + attrs.endpoint,
|
|
6411
|
-
|
|
4606
|
+
this._encode_data_for_request(data),
|
|
6412
4607
|
options,
|
|
6413
4608
|
this._prepare_callback(cb, data)
|
|
6414
4609
|
);
|
|
6415
4610
|
}, this),
|
|
6416
4611
|
beforeSendHook: _.bind(function(item) {
|
|
6417
4612
|
return this._run_hook('before_send_' + attrs.type, item);
|
|
6418
|
-
}, this)
|
|
4613
|
+
}, this),
|
|
4614
|
+
errorReporter: this.get_config('error_reporter'),
|
|
4615
|
+
stopAllBatchingFunc: _.bind(this.stop_batch_senders, this)
|
|
6419
4616
|
}
|
|
6420
4617
|
);
|
|
6421
4618
|
}, this);
|
|
@@ -6482,6 +4679,14 @@ MixpanelLib.prototype.disable = function(events) {
|
|
|
6482
4679
|
}
|
|
6483
4680
|
};
|
|
6484
4681
|
|
|
4682
|
+
MixpanelLib.prototype._encode_data_for_request = function(data) {
|
|
4683
|
+
var encoded_data = _.JSONEncode(data);
|
|
4684
|
+
if (this.get_config('api_payload_format') === PAYLOAD_TYPE_BASE64) {
|
|
4685
|
+
encoded_data = _.base64Encode(encoded_data);
|
|
4686
|
+
}
|
|
4687
|
+
return {'data': encoded_data};
|
|
4688
|
+
};
|
|
4689
|
+
|
|
6485
4690
|
// internal method for handling track vs batch-enqueue logic
|
|
6486
4691
|
MixpanelLib.prototype._track_or_batch = function(options, callback) {
|
|
6487
4692
|
var truncated_data = _.truncate(options.data, 255);
|
|
@@ -6501,7 +4706,7 @@ MixpanelLib.prototype._track_or_batch = function(options, callback) {
|
|
|
6501
4706
|
console.log(truncated_data);
|
|
6502
4707
|
return this._send_request(
|
|
6503
4708
|
endpoint,
|
|
6504
|
-
|
|
4709
|
+
this._encode_data_for_request(truncated_data),
|
|
6505
4710
|
send_request_options,
|
|
6506
4711
|
this._prepare_callback(callback, truncated_data)
|
|
6507
4712
|
);
|
|
@@ -6564,7 +4769,7 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro
|
|
|
6564
4769
|
}
|
|
6565
4770
|
|
|
6566
4771
|
if (_.isUndefined(event_name)) {
|
|
6567
|
-
|
|
4772
|
+
this.report_error('No event name provided to mixpanel.track');
|
|
6568
4773
|
return;
|
|
6569
4774
|
}
|
|
6570
4775
|
|
|
@@ -6605,7 +4810,7 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro
|
|
|
6605
4810
|
delete properties[blacklisted_prop];
|
|
6606
4811
|
});
|
|
6607
4812
|
} else {
|
|
6608
|
-
|
|
4813
|
+
this.report_error('Invalid value for property_blacklist config: ' + property_blacklist);
|
|
6609
4814
|
}
|
|
6610
4815
|
|
|
6611
4816
|
var data = {
|
|
@@ -6621,8 +4826,6 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro
|
|
|
6621
4826
|
send_request_options: options
|
|
6622
4827
|
}, callback);
|
|
6623
4828
|
|
|
6624
|
-
this._check_and_handle_triggered_notifications(data);
|
|
6625
|
-
|
|
6626
4829
|
return ret;
|
|
6627
4830
|
});
|
|
6628
4831
|
|
|
@@ -6850,7 +5053,7 @@ MixpanelLib.prototype.track_forms = function() {
|
|
|
6850
5053
|
*/
|
|
6851
5054
|
MixpanelLib.prototype.time_event = function(event_name) {
|
|
6852
5055
|
if (_.isUndefined(event_name)) {
|
|
6853
|
-
|
|
5056
|
+
this.report_error('No event name provided to mixpanel.time_event');
|
|
6854
5057
|
return;
|
|
6855
5058
|
}
|
|
6856
5059
|
|
|
@@ -7033,7 +5236,6 @@ MixpanelLib.prototype.identify = function(
|
|
|
7033
5236
|
this.unregister(ALIAS_ID_KEY);
|
|
7034
5237
|
this.register({'distinct_id': new_distinct_id});
|
|
7035
5238
|
}
|
|
7036
|
-
this._check_and_handle_notifications(this.get_distinct_id());
|
|
7037
5239
|
this._flags.identify_called = true;
|
|
7038
5240
|
// Flush any queued up people requests
|
|
7039
5241
|
this['people']._flush(_set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback);
|
|
@@ -7123,7 +5325,7 @@ MixpanelLib.prototype.alias = function(alias, original) {
|
|
|
7123
5325
|
// mixpanel.people.identify() call made for this user. It is VERY BAD to make an alias with
|
|
7124
5326
|
// this ID, as it will duplicate users.
|
|
7125
5327
|
if (alias === this.get_property(PEOPLE_DISTINCT_ID_KEY)) {
|
|
7126
|
-
|
|
5328
|
+
this.report_error('Attempting to create alias for existing People user - aborting.');
|
|
7127
5329
|
return -2;
|
|
7128
5330
|
}
|
|
7129
5331
|
|
|
@@ -7143,7 +5345,7 @@ MixpanelLib.prototype.alias = function(alias, original) {
|
|
|
7143
5345
|
_this.identify(alias);
|
|
7144
5346
|
});
|
|
7145
5347
|
} else {
|
|
7146
|
-
|
|
5348
|
+
this.report_error('alias matches current distinct_id - skipping api call.');
|
|
7147
5349
|
this.identify(alias);
|
|
7148
5350
|
return -1;
|
|
7149
5351
|
}
|
|
@@ -7270,14 +5472,6 @@ MixpanelLib.prototype.name_tag = function(name_tag) {
|
|
|
7270
5472
|
* // the format {'Header-Name': value}
|
|
7271
5473
|
* xhr_headers: {}
|
|
7272
5474
|
*
|
|
7273
|
-
* // protocol for fetching in-app message resources, e.g.
|
|
7274
|
-
* // 'https://' or 'http://'; defaults to '//' (which defers to the
|
|
7275
|
-
* // current page's protocol)
|
|
7276
|
-
* inapp_protocol: '//'
|
|
7277
|
-
*
|
|
7278
|
-
* // whether to open in-app message link in new tab/window
|
|
7279
|
-
* inapp_link_new_window: false
|
|
7280
|
-
*
|
|
7281
5475
|
* // whether to ignore or respect the web browser's Do Not Track setting
|
|
7282
5476
|
* ignore_dnt: false
|
|
7283
5477
|
* }
|
|
@@ -7326,7 +5520,7 @@ MixpanelLib.prototype.get_config = function(prop_name) {
|
|
|
7326
5520
|
MixpanelLib.prototype._run_hook = function(hook_name) {
|
|
7327
5521
|
var ret = (this['config']['hooks'][hook_name] || IDENTITY_FUNC).apply(this, slice.call(arguments, 1));
|
|
7328
5522
|
if (typeof ret === 'undefined') {
|
|
7329
|
-
|
|
5523
|
+
this.report_error(hook_name + ' hook did not return a value');
|
|
7330
5524
|
ret = null;
|
|
7331
5525
|
}
|
|
7332
5526
|
return ret;
|
|
@@ -7368,75 +5562,6 @@ MixpanelLib.prototype._event_is_disabled = function(event_name) {
|
|
|
7368
5562
|
_.include(this.__disabled_events, event_name);
|
|
7369
5563
|
};
|
|
7370
5564
|
|
|
7371
|
-
MixpanelLib.prototype._check_and_handle_triggered_notifications = addOptOutCheckMixpanelLib(function(event_data) {
|
|
7372
|
-
if (!this._user_decide_check_complete) {
|
|
7373
|
-
this._events_tracked_before_user_decide_check_complete.push(event_data);
|
|
7374
|
-
} else {
|
|
7375
|
-
var arr = this['_triggered_notifs'];
|
|
7376
|
-
for (var i = 0; i < arr.length; i++) {
|
|
7377
|
-
var notif = new MixpanelNotification(arr[i], this);
|
|
7378
|
-
if (notif._matches_event_data(event_data)) {
|
|
7379
|
-
this._show_notification(arr[i]);
|
|
7380
|
-
return;
|
|
7381
|
-
}
|
|
7382
|
-
}
|
|
7383
|
-
}
|
|
7384
|
-
});
|
|
7385
|
-
|
|
7386
|
-
MixpanelLib.prototype._check_and_handle_notifications = addOptOutCheckMixpanelLib(function(distinct_id) {
|
|
7387
|
-
if (
|
|
7388
|
-
!distinct_id ||
|
|
7389
|
-
this._flags.identify_called ||
|
|
7390
|
-
this.get_config('disable_notifications')
|
|
7391
|
-
) {
|
|
7392
|
-
return;
|
|
7393
|
-
}
|
|
7394
|
-
|
|
7395
|
-
console.log('MIXPANEL NOTIFICATION CHECK');
|
|
7396
|
-
|
|
7397
|
-
var data = {
|
|
7398
|
-
'verbose': true,
|
|
7399
|
-
'version': '3',
|
|
7400
|
-
'lib': 'web',
|
|
7401
|
-
'token': this.get_config('token'),
|
|
7402
|
-
'distinct_id': distinct_id
|
|
7403
|
-
};
|
|
7404
|
-
this._send_request(
|
|
7405
|
-
this.get_config('api_host') + '/decide/',
|
|
7406
|
-
data,
|
|
7407
|
-
{method: 'GET', transport: 'XHR'},
|
|
7408
|
-
this._prepare_callback(_.bind(function(result) {
|
|
7409
|
-
if (result['notifications'] && result['notifications'].length > 0) {
|
|
7410
|
-
this['_triggered_notifs'] = [];
|
|
7411
|
-
var notifications = [];
|
|
7412
|
-
_.each(result['notifications'], function(notif) {
|
|
7413
|
-
(notif['display_triggers'] && notif['display_triggers'].length > 0 ? this['_triggered_notifs'] : notifications).push(notif);
|
|
7414
|
-
}, this);
|
|
7415
|
-
if (notifications.length > 0) {
|
|
7416
|
-
this._show_notification.call(this, notifications[0]);
|
|
7417
|
-
}
|
|
7418
|
-
}
|
|
7419
|
-
this._handle_user_decide_check_complete();
|
|
7420
|
-
}, this))
|
|
7421
|
-
);
|
|
7422
|
-
});
|
|
7423
|
-
|
|
7424
|
-
MixpanelLib.prototype._handle_user_decide_check_complete = function() {
|
|
7425
|
-
this._user_decide_check_complete = true;
|
|
7426
|
-
|
|
7427
|
-
// check notifications against events that were tracked before decide call completed
|
|
7428
|
-
var events = this._events_tracked_before_user_decide_check_complete;
|
|
7429
|
-
while (events.length > 0) {
|
|
7430
|
-
var data = events.shift(); // replay in the same order they came in
|
|
7431
|
-
this._check_and_handle_triggered_notifications(data);
|
|
7432
|
-
}
|
|
7433
|
-
};
|
|
7434
|
-
|
|
7435
|
-
MixpanelLib.prototype._show_notification = function(notif_data) {
|
|
7436
|
-
var notification = new MixpanelNotification(notif_data, this);
|
|
7437
|
-
notification.show();
|
|
7438
|
-
};
|
|
7439
|
-
|
|
7440
5565
|
// perform some housekeeping around GDPR opt-in/out state
|
|
7441
5566
|
MixpanelLib.prototype._gdpr_init = function() {
|
|
7442
5567
|
var is_localStorage_requested = this.get_config('opt_out_tracking_persistence_type') === 'localStorage';
|
|
@@ -7682,6 +5807,18 @@ MixpanelLib.prototype.clear_opt_in_out_tracking = function(options) {
|
|
|
7682
5807
|
this._gdpr_update_persistence(options);
|
|
7683
5808
|
};
|
|
7684
5809
|
|
|
5810
|
+
MixpanelLib.prototype.report_error = function(msg, err) {
|
|
5811
|
+
console.error.apply(console.error, arguments);
|
|
5812
|
+
try {
|
|
5813
|
+
if (!err && !(msg instanceof Error)) {
|
|
5814
|
+
msg = new Error(msg);
|
|
5815
|
+
}
|
|
5816
|
+
this.get_config('error_reporter')(msg, err);
|
|
5817
|
+
} catch(err) {
|
|
5818
|
+
console.error(err);
|
|
5819
|
+
}
|
|
5820
|
+
};
|
|
5821
|
+
|
|
7685
5822
|
// EXPORTS (for closure compiler)
|
|
7686
5823
|
|
|
7687
5824
|
// MixpanelLib Exports
|
|
@@ -7704,9 +5841,6 @@ MixpanelLib.prototype['get_config'] = MixpanelLib.protot
|
|
|
7704
5841
|
MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property;
|
|
7705
5842
|
MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id;
|
|
7706
5843
|
MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString;
|
|
7707
|
-
MixpanelLib.prototype['_check_and_handle_notifications'] = MixpanelLib.prototype._check_and_handle_notifications;
|
|
7708
|
-
MixpanelLib.prototype['_handle_user_decide_check_complete'] = MixpanelLib.prototype._handle_user_decide_check_complete;
|
|
7709
|
-
MixpanelLib.prototype['_show_notification'] = MixpanelLib.prototype._show_notification;
|
|
7710
5844
|
MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking;
|
|
7711
5845
|
MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking;
|
|
7712
5846
|
MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking;
|
|
@@ -7727,8 +5861,6 @@ MixpanelPersistence.prototype['update_referrer_info'] = MixpanelPersistence.pro
|
|
|
7727
5861
|
MixpanelPersistence.prototype['get_cross_subdomain'] = MixpanelPersistence.prototype.get_cross_subdomain;
|
|
7728
5862
|
MixpanelPersistence.prototype['clear'] = MixpanelPersistence.prototype.clear;
|
|
7729
5863
|
|
|
7730
|
-
_.safewrap_class(MixpanelLib, ['identify', '_check_and_handle_notifications', '_show_notification']);
|
|
7731
|
-
|
|
7732
5864
|
|
|
7733
5865
|
var instances = {};
|
|
7734
5866
|
var extend_mp = function() {
|