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