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