@pendo/agent 2.293.1 → 2.295.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/bin/cli.js +6 -6
- package/dist/debugger-plugin.min.js +1 -1
- package/dist/dom.esm.js +21 -21
- package/dist/pendo.debugger.min.js +8 -8
- package/dist/pendo.module.js +590 -188
- package/dist/pendo.module.min.js +10 -8
- package/dist/pendo.preview.min.js +3 -3
- package/dist/servers.json +60 -24
- package/package.json +1 -1
- package/setup.js +4 -10
package/dist/pendo.module.js
CHANGED
|
@@ -3658,7 +3658,6 @@ var ConfigReader = (function () {
|
|
|
3658
3658
|
/* eslint-enable no-console */
|
|
3659
3659
|
})();
|
|
3660
3660
|
|
|
3661
|
-
var PROD = 'prod';
|
|
3662
3661
|
var EXTENSION_INSTALL_TYPE = 'extension';
|
|
3663
3662
|
var NATIVE_INSTALL_TYPE = 'native';
|
|
3664
3663
|
function getInstallType() {
|
|
@@ -3668,23 +3667,6 @@ function getInstallType() {
|
|
|
3668
3667
|
function isExtensionAgent() {
|
|
3669
3668
|
return getInstallType() === EXTENSION_INSTALL_TYPE;
|
|
3670
3669
|
}
|
|
3671
|
-
function subscriptionBucketPrefix(env) {
|
|
3672
|
-
if (env === PROD) {
|
|
3673
|
-
return 'pendo-static';
|
|
3674
|
-
}
|
|
3675
|
-
return globalBucket(env);
|
|
3676
|
-
}
|
|
3677
|
-
function globalBucket(env) {
|
|
3678
|
-
if (env === PROD) {
|
|
3679
|
-
return 'pendo-io-static';
|
|
3680
|
-
}
|
|
3681
|
-
if (env === 'prod-jp') {
|
|
3682
|
-
return 'pendo-jp-prod-static';
|
|
3683
|
-
}
|
|
3684
|
-
var match = /^prod-(.+)$/.exec(env);
|
|
3685
|
-
var envId = match && match.length > 1 ? match[1] : env;
|
|
3686
|
-
return 'pendo-' + envId + '-static';
|
|
3687
|
-
}
|
|
3688
3670
|
|
|
3689
3671
|
function isNativeCode(fn) { return /native/.test(fn); }
|
|
3690
3672
|
const detectNativeBrowserAPI = (name) => {
|
|
@@ -3692,11 +3674,11 @@ const detectNativeBrowserAPI = (name) => {
|
|
|
3692
3674
|
return (fn && isNativeCode(fn));
|
|
3693
3675
|
};
|
|
3694
3676
|
|
|
3695
|
-
|
|
3677
|
+
function isOldIE(olderThan, tVersion) {
|
|
3696
3678
|
olderThan = olderThan || 10;
|
|
3697
3679
|
tVersion = isNaN(trident) ? false : (tVersion ? (trident < tVersion) : true);
|
|
3698
3680
|
return (tVersion && (msie < olderThan));
|
|
3699
|
-
}
|
|
3681
|
+
}
|
|
3700
3682
|
// "borrowed" from angular.js
|
|
3701
3683
|
// https://github.com/angular/angular.js/blob/v1.2.27/src/ng/sniffer.js
|
|
3702
3684
|
// NOTE:
|
|
@@ -3710,11 +3692,12 @@ var isOldIE = function (olderThan, tVersion) {
|
|
|
3710
3692
|
// we've added trident to track this actual version of IE so we can
|
|
3711
3693
|
// attempt to handle these cases too.
|
|
3712
3694
|
// holds major version number for IE or NaN for real browsers
|
|
3713
|
-
|
|
3695
|
+
const msie = determineMSIE(getUA());
|
|
3696
|
+
const trident = determineTrident(getUA(), msie);
|
|
3714
3697
|
function pint(str) { return parseInt(str, 10); }
|
|
3715
|
-
|
|
3698
|
+
function lowercase(string) { return _.isString(string) ? string.toLowerCase() : string; }
|
|
3716
3699
|
function isMinimumIEVersion(minVersion) {
|
|
3717
|
-
|
|
3700
|
+
const sniffer = this;
|
|
3718
3701
|
if (isNaN(sniffer.msie) || sniffer.msie == null)
|
|
3719
3702
|
return true;
|
|
3720
3703
|
return sniffer.msie >= minVersion;
|
|
@@ -3724,36 +3707,34 @@ function getUA() {
|
|
|
3724
3707
|
}
|
|
3725
3708
|
// IE 11 changed the format of the UserAgent string.
|
|
3726
3709
|
// See http://msdn.microsoft.com/en-us/library/ms537503.aspx
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
if (isNaN(
|
|
3730
|
-
|
|
3731
|
-
}
|
|
3732
|
-
return
|
|
3733
|
-
}
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
};
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
var animations = false;
|
|
3753
|
-
var match;
|
|
3710
|
+
function determineMSIE(userAgent) {
|
|
3711
|
+
let version = pint((/msie (\d+)/.exec(lowercase(userAgent)) || [])[1]);
|
|
3712
|
+
if (isNaN(version)) {
|
|
3713
|
+
version = pint((/trident\/.*; rv:(\d+)/.exec(lowercase(userAgent)) || [])[1]);
|
|
3714
|
+
}
|
|
3715
|
+
return version;
|
|
3716
|
+
}
|
|
3717
|
+
function determineTrident(userAgent, ieVersion) {
|
|
3718
|
+
let version = pint((/trident\/(\d+)/.exec(lowercase(userAgent)) || [])[1]);
|
|
3719
|
+
if (isNaN(version) && ieVersion == 7) {
|
|
3720
|
+
version = 3;
|
|
3721
|
+
}
|
|
3722
|
+
return version;
|
|
3723
|
+
}
|
|
3724
|
+
const eventSupport = {};
|
|
3725
|
+
const android = pint((/android (\d+)/.exec(lowercase(getUA())) || [])[1]);
|
|
3726
|
+
const boxee = /Boxee/i.test(getUA());
|
|
3727
|
+
const pdocument = window.document || {};
|
|
3728
|
+
const documentMode = pdocument.documentMode;
|
|
3729
|
+
let vendorPrefix;
|
|
3730
|
+
const vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/;
|
|
3731
|
+
const bodyStyle = pdocument.body && pdocument.body.style;
|
|
3732
|
+
let transitions = false;
|
|
3733
|
+
let animations = false;
|
|
3734
|
+
let match;
|
|
3754
3735
|
if (bodyStyle) {
|
|
3755
3736
|
// eslint-disable-next-line guard-for-in
|
|
3756
|
-
for (
|
|
3737
|
+
for (const prop in bodyStyle) {
|
|
3757
3738
|
match = vendorRegex.exec(prop);
|
|
3758
3739
|
if (match) {
|
|
3759
3740
|
vendorPrefix = match[0];
|
|
@@ -3771,7 +3752,7 @@ if (bodyStyle) {
|
|
|
3771
3752
|
animations = _.isString(pdocument.body.style.webkitAnimation);
|
|
3772
3753
|
}
|
|
3773
3754
|
}
|
|
3774
|
-
|
|
3755
|
+
const isChromeExtension = window.chrome && window.chrome.runtime && window.chrome.runtime.id;
|
|
3775
3756
|
// Android has history.pushState, but it does not update location correctly
|
|
3776
3757
|
// so let's not use the history API at all.
|
|
3777
3758
|
// http://code.google.com/p/android/issues/detail?id=17471
|
|
@@ -3779,28 +3760,28 @@ var isChromeExtension = window.chrome && window.chrome.runtime && window.chrome.
|
|
|
3779
3760
|
// older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
|
|
3780
3761
|
// so let's not use the history API also
|
|
3781
3762
|
// We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3763
|
+
const shouldWrapNativeHistory = _.memoize(function shouldWrapNativeHistory() {
|
|
3764
|
+
const hasNativeHistory = window.history && window.history.pushState && window.history.replaceState;
|
|
3765
|
+
const isHistoryFrozen = window.history && _.isFunction(Object.isFrozen) && Object.isFrozen(window.history);
|
|
3766
|
+
const historyDescriptors = window.history && _.isFunction(Object.getOwnPropertyDescriptors) && Object.getOwnPropertyDescriptors(window.history);
|
|
3767
|
+
const isHistoryWriteable = historyDescriptors && _.get(historyDescriptors, 'pushState.writable', true) && _.get(historyDescriptors, 'replaceState.writable', true);
|
|
3768
|
+
const hasAndroidSupport = !(android < 4);
|
|
3788
3769
|
return !!(hasNativeHistory && !isHistoryFrozen && isHistoryWriteable && hasAndroidSupport && !boxee && !isExtensionAgent());
|
|
3789
3770
|
});
|
|
3790
3771
|
function shouldWrapHashChange() {
|
|
3791
|
-
|
|
3772
|
+
const hasNativeHashChange = 'onhashchange' in window;
|
|
3792
3773
|
// IE8 compatible mode lies
|
|
3793
|
-
|
|
3774
|
+
const hasSupportedDocMode = (!documentMode || documentMode > 7);
|
|
3794
3775
|
return !!(hasNativeHashChange && hasSupportedDocMode && !isExtensionAgent());
|
|
3795
3776
|
}
|
|
3796
3777
|
function isMobileUserAgent() {
|
|
3797
3778
|
return (/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i).test(getUA());
|
|
3798
3779
|
}
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3780
|
+
function isSafari(userAgent = getUA()) {
|
|
3781
|
+
return userAgent.indexOf('Safari') >= 0 && !userAgent.indexOf('Chrome') >= 0;
|
|
3782
|
+
}
|
|
3783
|
+
const sniffer = {
|
|
3802
3784
|
supportsHistoryApi: shouldWrapNativeHistory,
|
|
3803
|
-
// jshint +W018
|
|
3804
3785
|
supportsHashChange: shouldWrapHashChange,
|
|
3805
3786
|
hasEvent(event) {
|
|
3806
3787
|
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
|
|
@@ -3809,7 +3790,7 @@ var sniffer = {
|
|
|
3809
3790
|
if (event == 'input' && msie == 9)
|
|
3810
3791
|
return false;
|
|
3811
3792
|
if (_.isUndefined(eventSupport[event])) {
|
|
3812
|
-
|
|
3793
|
+
const divElm = pdocument.createElement('div');
|
|
3813
3794
|
eventSupport[event] = 'on' + event in divElm;
|
|
3814
3795
|
}
|
|
3815
3796
|
return eventSupport[event];
|
|
@@ -3820,7 +3801,7 @@ var sniffer = {
|
|
|
3820
3801
|
android,
|
|
3821
3802
|
msie,
|
|
3822
3803
|
msieDocumentMode: documentMode,
|
|
3823
|
-
safari:
|
|
3804
|
+
safari: isSafari(),
|
|
3824
3805
|
sri: ('integrity' in document.createElement('script')),
|
|
3825
3806
|
addEventListener: _.isFunction(window.addEventListener),
|
|
3826
3807
|
MutationObserver: isNativeCode(window.MutationObserver),
|
|
@@ -3903,14 +3884,16 @@ var buildArrowDimensionsQM = function (dim, elementPos) {
|
|
|
3903
3884
|
// If in module mode, all injected values will be empty.
|
|
3904
3885
|
// In that case, we'll overwrite them on initAgent via overwriteBuiltConfigWithPendoConfig
|
|
3905
3886
|
/* eslint-disable agent-eslint-rules/no-gulp-env-references */
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3887
|
+
let ENV = '';
|
|
3888
|
+
let GLOBAL_BUCKET = '';
|
|
3889
|
+
let SUBSCRIPTION_BUCKET = '';
|
|
3890
|
+
let SERVER = '';
|
|
3891
|
+
let ASSET_HOST = '';
|
|
3892
|
+
let ASSET_PATH = '';
|
|
3893
|
+
let DESIGNER_SERVER = '';
|
|
3894
|
+
let VERSION = '2.295.0_';
|
|
3895
|
+
let PACKAGE_VERSION = '2.295.0';
|
|
3896
|
+
let LOADER = 'xhr';
|
|
3914
3897
|
/* eslint-enable agent-eslint-rules/no-gulp-env-references */
|
|
3915
3898
|
/**
|
|
3916
3899
|
* Returns current version of the Agent as a string. Also directly accessible at `pendo.VERSION`.
|
|
@@ -3921,26 +3904,31 @@ var LOADER = 'xhr';
|
|
|
3921
3904
|
* @example
|
|
3922
3905
|
* pendo.getVersion() => '2.150.0'
|
|
3923
3906
|
*/
|
|
3924
|
-
|
|
3907
|
+
const getVersion = function () {
|
|
3925
3908
|
if (isBrowserInQuirksmode()) {
|
|
3926
3909
|
return VERSION + '+quirksmode';
|
|
3927
3910
|
}
|
|
3928
3911
|
return VERSION;
|
|
3929
3912
|
};
|
|
3930
|
-
|
|
3913
|
+
const overwriteBuiltConfigWithPendoConfig = function () {
|
|
3931
3914
|
ENV = getPendoConfigValue('env') || ENV;
|
|
3932
3915
|
SERVER = getPendoConfigValue('server') || SERVER;
|
|
3933
3916
|
ASSET_HOST = getPendoConfigValue('assetHost') || ASSET_HOST;
|
|
3934
3917
|
ASSET_PATH = getPendoConfigValue('assetPath') || ASSET_PATH;
|
|
3935
3918
|
DESIGNER_SERVER = getPendoConfigValue('designerServer') || DESIGNER_SERVER;
|
|
3936
|
-
|
|
3919
|
+
GLOBAL_BUCKET = getPendoConfigValue('globalBucket') || GLOBAL_BUCKET;
|
|
3920
|
+
SUBSCRIPTION_BUCKET = getPendoConfigValue('subscriptionBucket') || SUBSCRIPTION_BUCKET;
|
|
3921
|
+
const versionSuffix = isExtensionAgent() ? ENV + '_ext' : ENV;
|
|
3937
3922
|
VERSION = PACKAGE_VERSION + '_' + versionSuffix;
|
|
3938
3923
|
};
|
|
3939
3924
|
function isProdAgent() {
|
|
3940
3925
|
return ENV.indexOf('prod') !== -1;
|
|
3941
3926
|
}
|
|
3942
|
-
function
|
|
3943
|
-
return
|
|
3927
|
+
function isRCAgent() {
|
|
3928
|
+
return ENV.indexOf('rc') !== -1;
|
|
3929
|
+
}
|
|
3930
|
+
function isBetaAgent(config) {
|
|
3931
|
+
return !isProdAgent() || isStagingServer(config);
|
|
3944
3932
|
}
|
|
3945
3933
|
|
|
3946
3934
|
var rtrim = /^\s+|\s+$/g;
|
|
@@ -11424,25 +11412,17 @@ function isTrustedOrigin(host) {
|
|
|
11424
11412
|
return true;
|
|
11425
11413
|
if (host === getAssetHost())
|
|
11426
11414
|
return true;
|
|
11427
|
-
// Domains that Pendo owns
|
|
11428
|
-
|
|
11429
|
-
/^https:\/\/(app|via|adopt)(\.eu
|
|
11430
|
-
/^https:\/\/(
|
|
11431
|
-
/^https:\/\/(
|
|
11432
|
-
/^https:\/\/
|
|
11433
|
-
/^https:\/\/
|
|
11434
|
-
/^https:\/\/(
|
|
11435
|
-
|
|
11436
|
-
|
|
11437
|
-
|
|
11438
|
-
/^https:\/\/([a-zA-Z0-9-]+\.)*pendo-dev\.com$/,
|
|
11439
|
-
/^https:\/\/([a-zA-Z0-9-]+-dot-)?pendo-(dev|test|io|us1|govramp|jp-prod|hsbc|au|batman|magic|atlas|wildlings|ionchef|mobile-guides|mobile-hummus|mobile-fbi|mobile-plat|eu|eu-dev|apollo|security|perfserf|freeze|armada|voc|mcfly|calypso|dap|scrum-ops|ml|helix|uat)\.appspot\.com$/,
|
|
11440
|
-
/^https:\/\/via\.pendo\.local:\d{4}$/,
|
|
11441
|
-
/^https:\/\/adopt\.pendo\.local:\d{4}$/,
|
|
11442
|
-
/^https:\/\/local\.pendo\.io:\d{4}$/,
|
|
11443
|
-
new RegExp('^https://pendo-' + ENV + '-static\\.storage\\.googleapis\\.com$')
|
|
11444
|
-
]);
|
|
11445
|
-
}
|
|
11415
|
+
// Domains that Pendo owns, will be swapped in by build patches
|
|
11416
|
+
const patterns = [
|
|
11417
|
+
/^https:\/\/(adopt\.)?((us1)\.)?(app|via|adopt|cdn)(\.(au|eu|gov|hsbc|jpn))?\.pendo\.io$/,
|
|
11418
|
+
/^https:\/\/([0-9]{8}t[0-9]{4}-dot-)pendo-(au|eu|govramp|hsbc|io|jp-prod|us1)\.appspot\.com$/,
|
|
11419
|
+
/^https:\/\/hotfix-(ops|app)-([0-9]+-dot-)pendo-(au|eu|govramp|hsbc|io|jp-prod|us1)\.appspot\.com$/,
|
|
11420
|
+
/^https:\/\/pendo-(au|eu|govramp|hsbc|io|jp-prod|us1)-static\.storage\.googleapis\.com$/,
|
|
11421
|
+
/^https:\/\/([a-zA-Z0-9-]+\.?)*\.pendo-dev\.com$/,
|
|
11422
|
+
/^https:\/\/([a-zA-Z0-9-]+-dot-)?pendo-(apollo|armada|atlas|batman|calypso|dap|dev|dr-us-east1|eu-dev|freeze|helix|link|magic|mcfly|ml|mobile-fbi|mobile-guides|mobile-hummus|mobile-plat|perfserf|voc|wildlings|ionchef|scrum-ops|security|test|uat|au|eu|govramp|hsbc|io|jp-prod|us1)\.appspot\.com$/,
|
|
11423
|
+
/^https:\/\/(via|adopt|local)\.pendo\.(local|io):\d{4}$/,
|
|
11424
|
+
/^https:\/\/pendo-(apollo|armada|atlas|batman|calypso|dap|dev|dr-us-east1|eu-dev|freeze|helix|link|magic|mcfly|ml|mobile-fbi|mobile-guides|mobile-hummus|mobile-plat|perfserf|voc|wildlings|ionchef|scrum-ops|security|test|uat)-static\.storage\.googleapis\.com$/
|
|
11425
|
+
]; // eslint-disable-line agent-eslint-rules/no-gulp-env-references
|
|
11446
11426
|
var adoptHost = ConfigReader.get('adoptHost');
|
|
11447
11427
|
if (adoptHost) {
|
|
11448
11428
|
var fullHostname = 'https://' + adoptHost;
|
|
@@ -11491,7 +11471,7 @@ function addIntegrityAttribute(element, url) {
|
|
|
11491
11471
|
var trustedOriginForLoadResource = function (origin) {
|
|
11492
11472
|
var noAllowedOriginServers = ConfigReader.get('allowedOriginServers', []).length === 0;
|
|
11493
11473
|
var isAdoptPartner = treatAsAdoptPartner();
|
|
11494
|
-
if (noAllowedOriginServers || isAdoptPartner || !isBetaAgent(
|
|
11474
|
+
if (noAllowedOriginServers || isAdoptPartner || !isBetaAgent(getPendoConfig())) {
|
|
11495
11475
|
return true;
|
|
11496
11476
|
}
|
|
11497
11477
|
return isTrustedOrigin(origin);
|
|
@@ -12231,6 +12211,7 @@ class PerformanceMonitor {
|
|
|
12231
12211
|
return detectNativeBrowserAPI('performance.mark') &&
|
|
12232
12212
|
detectNativeBrowserAPI('performance.measure') &&
|
|
12233
12213
|
detectNativeBrowserAPI('performance.getEntries') &&
|
|
12214
|
+
detectNativeBrowserAPI('performance.getEntriesByName') &&
|
|
12234
12215
|
detectNativeBrowserAPI('performance.clearMarks') &&
|
|
12235
12216
|
detectNativeBrowserAPI('performance.clearMeasures');
|
|
12236
12217
|
}
|
|
@@ -12250,8 +12231,10 @@ class PerformanceMonitor {
|
|
|
12250
12231
|
name = `pendo-${name}`;
|
|
12251
12232
|
const startMark = `${name}-start`;
|
|
12252
12233
|
const stopMark = `${name}-stop`;
|
|
12253
|
-
performance.
|
|
12254
|
-
|
|
12234
|
+
if (performance.getEntriesByName(startMark).length && performance.getEntriesByName(stopMark).length) {
|
|
12235
|
+
performance.measure(name, startMark, stopMark);
|
|
12236
|
+
this._count(this._measures, name);
|
|
12237
|
+
}
|
|
12255
12238
|
}
|
|
12256
12239
|
_count(registry, name) {
|
|
12257
12240
|
if (!registry[name]) {
|
|
@@ -13304,6 +13287,7 @@ var getValidTarget = function (node) {
|
|
|
13304
13287
|
*/
|
|
13305
13288
|
var handle_event = function (evt) {
|
|
13306
13289
|
try {
|
|
13290
|
+
PerformanceMonitor$1.startTimer('event-captured');
|
|
13307
13291
|
if (dom.data.get(evt, 'counted'))
|
|
13308
13292
|
return;
|
|
13309
13293
|
dom.data.set(evt, 'counted', true);
|
|
@@ -13343,6 +13327,9 @@ var handle_event = function (evt) {
|
|
|
13343
13327
|
catch (e) {
|
|
13344
13328
|
log.critical('pendo.io while handling event', { error: e });
|
|
13345
13329
|
}
|
|
13330
|
+
finally {
|
|
13331
|
+
PerformanceMonitor$1.stopTimer('event-captured');
|
|
13332
|
+
}
|
|
13346
13333
|
};
|
|
13347
13334
|
function getClickEventProperties(target) {
|
|
13348
13335
|
const eventPropertyHandler = getEventPropertyHandler(target);
|
|
@@ -14608,11 +14595,11 @@ function replaceWithContentHost(str) {
|
|
|
14608
14595
|
var contentHost = ConfigReader.getLocalConfig('contentHost');
|
|
14609
14596
|
if (!contentHost || !str)
|
|
14610
14597
|
return str;
|
|
14611
|
-
var subBucketPattern = new RegExp(
|
|
14612
|
-
var globalBucketPattern = new RegExp(
|
|
14598
|
+
var subBucketPattern = new RegExp(`(https:)?\\/\\/${SUBSCRIPTION_BUCKET}-\\d+\\.storage\\.googleapis\\.com`, 'g');
|
|
14599
|
+
var globalBucketPattern = new RegExp(`(https:)?\\/\\/${GLOBAL_BUCKET}\\.storage\\.googleapis\\.com`, 'g');
|
|
14613
14600
|
return str.replace(subBucketPattern, contentHost)
|
|
14614
14601
|
.replace(globalBucketPattern, contentHost)
|
|
14615
|
-
.replace(new RegExp(
|
|
14602
|
+
.replace(new RegExp(`(https:)?\\/\\/${escapeRegExp(ASSET_HOST)}`, 'g'), contentHost);
|
|
14616
14603
|
}
|
|
14617
14604
|
function replaceObjectWithContentHost(obj) {
|
|
14618
14605
|
var contentHost = ConfigReader.getLocalConfig('contentHost');
|
|
@@ -17866,6 +17853,9 @@ function getAllowedAttributes(attributeKeyValueMap, stepId, guideId, type) {
|
|
|
17866
17853
|
function buildNodeFromJSON(json, step, guides) {
|
|
17867
17854
|
step = step || { id: 'unknown', guideId: 'unknown' };
|
|
17868
17855
|
json.props = getAllowedAttributes(json.props, step.id, step.guideId, json.type);
|
|
17856
|
+
if (step.isDarkMode && json.darkModeProps) {
|
|
17857
|
+
json.darkModeProps = getAllowedAttributes(json.darkModeProps, step.id, step.guideId, json.type);
|
|
17858
|
+
}
|
|
17869
17859
|
var curNode = dom(document.createElement(json.type));
|
|
17870
17860
|
// APP-81040 calling code in the pendo app (and possibly elsewhere) depends on
|
|
17871
17861
|
// curNode.getParent() returning non-null in some cases. The fact that it used to
|
|
@@ -17885,7 +17875,11 @@ function buildNodeFromJSON(json, step, guides) {
|
|
|
17885
17875
|
}
|
|
17886
17876
|
_.each(json.props, function (propValue, propKey) {
|
|
17887
17877
|
if (propKey === 'style') {
|
|
17888
|
-
|
|
17878
|
+
let nodeStyle = json.props.style;
|
|
17879
|
+
if (step.isDarkMode && json.darkModeProps) {
|
|
17880
|
+
nodeStyle = Object.assign(Object.assign({}, json.props.style), json.darkModeProps.style);
|
|
17881
|
+
}
|
|
17882
|
+
curNode.css(nodeStyle);
|
|
17889
17883
|
}
|
|
17890
17884
|
else if (propKey === 'data-pendo-code-block' && propValue === true && !ConfigReader.get('preventCodeInjection')) {
|
|
17891
17885
|
const htmlString = step.getContent();
|
|
@@ -17910,13 +17904,23 @@ function buildNodeFromJSON(json, step, guides) {
|
|
|
17910
17904
|
if (nonce) {
|
|
17911
17905
|
curNode.attr('nonce', nonce);
|
|
17912
17906
|
}
|
|
17907
|
+
let css = json.css;
|
|
17908
|
+
if (json.forDarkMode) {
|
|
17909
|
+
const darkModeSelector = _.get(step, 'attributes.darkMode.selector', '');
|
|
17910
|
+
css = _.map(css, function (rule) {
|
|
17911
|
+
return {
|
|
17912
|
+
styles: rule.styles,
|
|
17913
|
+
selector: `${darkModeSelector} ${rule.selector}`
|
|
17914
|
+
};
|
|
17915
|
+
});
|
|
17916
|
+
}
|
|
17913
17917
|
// TODO: make this render building-block pseudo-styles properly for IE7-8. This current functionality allows guides to render in IE but there are lots of styling problems.
|
|
17914
17918
|
// `curNode.text` specifically breaks in IE8 since style tags text attributes are read only. From researching `node.styleSheet.cssText` is the correct way to do it.
|
|
17915
17919
|
if (curNode.styleSheet) {
|
|
17916
|
-
curNode.styleSheet.cssText = buildStyleTagContent(
|
|
17920
|
+
curNode.styleSheet.cssText = buildStyleTagContent(css);
|
|
17917
17921
|
}
|
|
17918
17922
|
else {
|
|
17919
|
-
curNode.text(buildStyleTagContent(
|
|
17923
|
+
curNode.text(buildStyleTagContent(css));
|
|
17920
17924
|
}
|
|
17921
17925
|
}
|
|
17922
17926
|
if (json.svgWidgetId) {
|
|
@@ -20614,6 +20618,21 @@ class AutoDisplayPhase {
|
|
|
20614
20618
|
}
|
|
20615
20619
|
}
|
|
20616
20620
|
|
|
20621
|
+
function syncColorMode(step, rerender = false) {
|
|
20622
|
+
const darkModeSelector = _.get(step, 'attributes.darkMode.selector', '');
|
|
20623
|
+
if (!darkModeSelector)
|
|
20624
|
+
return;
|
|
20625
|
+
const isDarkMode = pendo$1.Sizzle(darkModeSelector).length > 0;
|
|
20626
|
+
const darkModeChanged = step.isDarkMode !== isDarkMode;
|
|
20627
|
+
if (darkModeChanged) {
|
|
20628
|
+
step.isDarkMode = isDarkMode;
|
|
20629
|
+
if (rerender) {
|
|
20630
|
+
step.hide();
|
|
20631
|
+
step.show(step.seenReason);
|
|
20632
|
+
}
|
|
20633
|
+
}
|
|
20634
|
+
}
|
|
20635
|
+
|
|
20617
20636
|
/*
|
|
20618
20637
|
* Guide Loop
|
|
20619
20638
|
*
|
|
@@ -20812,6 +20831,7 @@ function stepShowingProc(guide, step) {
|
|
|
20812
20831
|
step.attributes.currentTextZoomFontSize = currentBrowserFontSize;
|
|
20813
20832
|
}
|
|
20814
20833
|
}
|
|
20834
|
+
syncColorMode(step, true);
|
|
20815
20835
|
if (step.elementPathRule && targetElement && !SizzleProxy.matchesSelector(targetElement, step.elementPathRule)) {
|
|
20816
20836
|
step.hide();
|
|
20817
20837
|
return;
|
|
@@ -21887,6 +21907,11 @@ function startPreviewMode(window) {
|
|
|
21887
21907
|
enableCookies(false);
|
|
21888
21908
|
buffers.lock();
|
|
21889
21909
|
setGuideLoader(PreviewGuideLoader);
|
|
21910
|
+
// This is to allow for data urls when previewing from the designer
|
|
21911
|
+
if (isInDesignerPreviewMode()) {
|
|
21912
|
+
const pendoConfig = getPendoConfig();
|
|
21913
|
+
pendoConfig.allowedOriginServers = [];
|
|
21914
|
+
}
|
|
21890
21915
|
Events.startPreview.trigger();
|
|
21891
21916
|
Events.leaderChanged.on(function (e) {
|
|
21892
21917
|
store.dispatch('preview/write');
|
|
@@ -26340,53 +26365,152 @@ class NetworkRequestIntercept {
|
|
|
26340
26365
|
extractXHRHeaders(xhr) {
|
|
26341
26366
|
return xhr[PENDO_HEADERS_KEY] || {};
|
|
26342
26367
|
}
|
|
26343
|
-
|
|
26368
|
+
generateRequestId() {
|
|
26369
|
+
const $stringLength = 8;
|
|
26370
|
+
return 'req_' + Date.now() + '_' + pendo$1.randomString($stringLength);
|
|
26371
|
+
}
|
|
26372
|
+
safelyReadResponse(response) {
|
|
26373
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
26374
|
+
try {
|
|
26375
|
+
const contentType = response.headers.get('content-type') || '';
|
|
26376
|
+
if (contentType.indexOf('application/json') !== -1) {
|
|
26377
|
+
return yield response.json();
|
|
26378
|
+
}
|
|
26379
|
+
else if (contentType.indexOf('text/') !== -1) {
|
|
26380
|
+
return yield response.text();
|
|
26381
|
+
}
|
|
26382
|
+
else {
|
|
26383
|
+
// For binary or unknown content types, just capture metadata
|
|
26384
|
+
return `[Binary content: ${contentType}]`;
|
|
26385
|
+
}
|
|
26386
|
+
}
|
|
26387
|
+
catch (e) {
|
|
26388
|
+
return '[Unable to read response body]';
|
|
26389
|
+
}
|
|
26390
|
+
});
|
|
26391
|
+
}
|
|
26392
|
+
extractResponseHeaders(response) {
|
|
26393
|
+
let headers = {};
|
|
26394
|
+
if (response.headers) {
|
|
26395
|
+
const headerEntries = Array.from(response.headers.entries());
|
|
26396
|
+
headers = this.entriesToObject(headerEntries);
|
|
26397
|
+
}
|
|
26398
|
+
return headers;
|
|
26399
|
+
}
|
|
26400
|
+
parseXHRResponseHeaders(headerString) {
|
|
26401
|
+
const headers = {};
|
|
26402
|
+
if (!headerString)
|
|
26403
|
+
return headers;
|
|
26404
|
+
const lines = headerString.split('\r\n');
|
|
26405
|
+
_.each(lines, line => {
|
|
26406
|
+
const parts = line.split(': ');
|
|
26407
|
+
if (parts.length === 2) {
|
|
26408
|
+
headers[parts[0]] = parts[1];
|
|
26409
|
+
}
|
|
26410
|
+
});
|
|
26411
|
+
return headers;
|
|
26412
|
+
}
|
|
26413
|
+
patchFetch() {
|
|
26344
26414
|
const networkInterceptor = this;
|
|
26345
|
-
if (networkInterceptor._networkPatched)
|
|
26346
|
-
return;
|
|
26347
|
-
networkInterceptor._networkPatched = true;
|
|
26348
|
-
networkInterceptor._originalSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
26349
|
-
XMLHttpRequest.prototype.setRequestHeader = function (header, value) {
|
|
26350
|
-
this[PENDO_HEADERS_KEY] = this[PENDO_HEADERS_KEY] || {};
|
|
26351
|
-
this[PENDO_HEADERS_KEY][header] = value;
|
|
26352
|
-
return networkInterceptor._originalSetRequestHeader.apply(this, arguments);
|
|
26353
|
-
};
|
|
26354
26415
|
networkInterceptor._originalFetch = window.fetch;
|
|
26355
26416
|
window.fetch = function (...args) {
|
|
26356
26417
|
return __awaiter(this, void 0, void 0, function* () {
|
|
26357
26418
|
const [url, config = {}] = args;
|
|
26358
26419
|
const method = config.method || 'GET';
|
|
26420
|
+
const requestId = networkInterceptor.generateRequestId();
|
|
26421
|
+
// Capture request data
|
|
26359
26422
|
try {
|
|
26360
26423
|
const headers = networkInterceptor.extractHeaders(config.headers);
|
|
26361
26424
|
const body = networkInterceptor.safelySerializeBody(config.body);
|
|
26362
26425
|
_.each(networkInterceptor.callbackFns, ({ request }) => {
|
|
26363
26426
|
if (_.isFunction(request))
|
|
26364
|
-
request({ method, url, body, headers });
|
|
26427
|
+
request({ requestId, method, url, body, headers });
|
|
26365
26428
|
});
|
|
26366
26429
|
}
|
|
26367
26430
|
catch (e) {
|
|
26368
26431
|
_.each(networkInterceptor.callbackFns, ({ error }) => {
|
|
26369
26432
|
if (_.isFunction(error))
|
|
26370
|
-
error({ context: '
|
|
26433
|
+
error({ context: 'fetchRequest', error: e });
|
|
26371
26434
|
});
|
|
26372
26435
|
}
|
|
26373
|
-
|
|
26436
|
+
// Make the actual fetch call and capture response
|
|
26437
|
+
try {
|
|
26438
|
+
const res = yield networkInterceptor._originalFetch.apply(this, args);
|
|
26439
|
+
// Clone the response to avoid consuming the body
|
|
26440
|
+
const responseClone = res.clone();
|
|
26441
|
+
try {
|
|
26442
|
+
// Capture response data
|
|
26443
|
+
const responseBody = yield networkInterceptor.safelyReadResponse(responseClone);
|
|
26444
|
+
const { status, statusText } = res;
|
|
26445
|
+
const headers = networkInterceptor.extractResponseHeaders(res);
|
|
26446
|
+
_.each(networkInterceptor.callbackFns, ({ response }) => {
|
|
26447
|
+
if (_.isFunction(response)) {
|
|
26448
|
+
response({
|
|
26449
|
+
requestId,
|
|
26450
|
+
status,
|
|
26451
|
+
statusText,
|
|
26452
|
+
body: responseBody,
|
|
26453
|
+
headers,
|
|
26454
|
+
url,
|
|
26455
|
+
method
|
|
26456
|
+
});
|
|
26457
|
+
}
|
|
26458
|
+
});
|
|
26459
|
+
}
|
|
26460
|
+
catch (e) {
|
|
26461
|
+
_.each(networkInterceptor.callbackFns, ({ error }) => {
|
|
26462
|
+
if (_.isFunction(error))
|
|
26463
|
+
error({ context: 'fetchResponse', error: e });
|
|
26464
|
+
});
|
|
26465
|
+
}
|
|
26466
|
+
return res;
|
|
26467
|
+
}
|
|
26468
|
+
catch (error) {
|
|
26469
|
+
// Handle network errors
|
|
26470
|
+
_.each(networkInterceptor.callbackFns, ({ response }) => {
|
|
26471
|
+
if (_.isFunction(response)) {
|
|
26472
|
+
response({
|
|
26473
|
+
requestId,
|
|
26474
|
+
status: 0,
|
|
26475
|
+
statusText: 'Network Error',
|
|
26476
|
+
headers: {},
|
|
26477
|
+
body: null,
|
|
26478
|
+
url,
|
|
26479
|
+
method,
|
|
26480
|
+
error: error.message
|
|
26481
|
+
});
|
|
26482
|
+
}
|
|
26483
|
+
});
|
|
26484
|
+
throw error;
|
|
26485
|
+
}
|
|
26374
26486
|
});
|
|
26375
26487
|
};
|
|
26488
|
+
}
|
|
26489
|
+
patchXHR() {
|
|
26490
|
+
const networkInterceptor = this;
|
|
26491
|
+
networkInterceptor._originalSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
26376
26492
|
networkInterceptor._originalXHROpen = XMLHttpRequest.prototype.open;
|
|
26377
26493
|
networkInterceptor._originalXHRSend = XMLHttpRequest.prototype.send;
|
|
26494
|
+
XMLHttpRequest.prototype.setRequestHeader = function (header, value) {
|
|
26495
|
+
this[PENDO_HEADERS_KEY] = this[PENDO_HEADERS_KEY] || {};
|
|
26496
|
+
this[PENDO_HEADERS_KEY][header] = value;
|
|
26497
|
+
return networkInterceptor._originalSetRequestHeader.apply(this, arguments);
|
|
26498
|
+
};
|
|
26378
26499
|
XMLHttpRequest.prototype.open = function (method, url) {
|
|
26379
|
-
this._method = method;
|
|
26500
|
+
this._method = method;
|
|
26380
26501
|
this._url = url;
|
|
26502
|
+
this._requestId = networkInterceptor.generateRequestId();
|
|
26381
26503
|
return networkInterceptor._originalXHROpen.apply(this, arguments);
|
|
26382
26504
|
};
|
|
26383
26505
|
XMLHttpRequest.prototype.send = function (body) {
|
|
26506
|
+
const xhr = this;
|
|
26507
|
+
const headers = networkInterceptor.extractXHRHeaders(this);
|
|
26508
|
+
const safeBody = networkInterceptor.safelySerializeBody(body);
|
|
26384
26509
|
try {
|
|
26385
|
-
const headers = networkInterceptor.extractXHRHeaders(this);
|
|
26386
|
-
const safeBody = networkInterceptor.safelySerializeBody(body);
|
|
26387
26510
|
_.each(networkInterceptor.callbackFns, ({ request }) => {
|
|
26388
26511
|
if (_.isFunction(request)) {
|
|
26389
26512
|
request({
|
|
26513
|
+
requestId: this._requestId,
|
|
26390
26514
|
method: this._method || 'GET',
|
|
26391
26515
|
url: this._url,
|
|
26392
26516
|
body: safeBody,
|
|
@@ -26398,7 +26522,7 @@ class NetworkRequestIntercept {
|
|
|
26398
26522
|
catch (e) {
|
|
26399
26523
|
_.each(networkInterceptor.callbackFns, ({ error }) => {
|
|
26400
26524
|
if (_.isFunction(error))
|
|
26401
|
-
error({ context: '
|
|
26525
|
+
error({ context: 'xhrRequest', error: e });
|
|
26402
26526
|
});
|
|
26403
26527
|
}
|
|
26404
26528
|
// Clean up custom headers after the request completes
|
|
@@ -26407,9 +26531,49 @@ class NetworkRequestIntercept {
|
|
|
26407
26531
|
delete this[PENDO_HEADERS_KEY];
|
|
26408
26532
|
}, { once: true });
|
|
26409
26533
|
}
|
|
26534
|
+
// Set up response tracking
|
|
26535
|
+
const originalOnReadyStateChange = xhr.onreadystatechange;
|
|
26536
|
+
xhr.onreadystatechange = function () {
|
|
26537
|
+
if (xhr.readyState === 4) { // Request completed
|
|
26538
|
+
try {
|
|
26539
|
+
const headers = networkInterceptor.parseXHRResponseHeaders(xhr.getAllResponseHeaders());
|
|
26540
|
+
const { status, statusText, responseText: body, _url } = xhr;
|
|
26541
|
+
_.each(networkInterceptor.callbackFns, ({ response }) => {
|
|
26542
|
+
if (_.isFunction(response)) {
|
|
26543
|
+
response({
|
|
26544
|
+
requestId: xhr._requestId,
|
|
26545
|
+
status,
|
|
26546
|
+
statusText,
|
|
26547
|
+
headers,
|
|
26548
|
+
body,
|
|
26549
|
+
url: _url,
|
|
26550
|
+
method: xhr._method || 'GET'
|
|
26551
|
+
});
|
|
26552
|
+
}
|
|
26553
|
+
});
|
|
26554
|
+
}
|
|
26555
|
+
catch (e) {
|
|
26556
|
+
_.each(networkInterceptor.callbackFns, ({ error }) => {
|
|
26557
|
+
if (_.isFunction(error))
|
|
26558
|
+
error({ context: 'xhrResponse', error: e });
|
|
26559
|
+
});
|
|
26560
|
+
}
|
|
26561
|
+
}
|
|
26562
|
+
if (originalOnReadyStateChange) {
|
|
26563
|
+
originalOnReadyStateChange.apply(this, arguments);
|
|
26564
|
+
}
|
|
26565
|
+
};
|
|
26410
26566
|
return networkInterceptor._originalXHRSend.apply(this, arguments);
|
|
26411
26567
|
};
|
|
26412
26568
|
}
|
|
26569
|
+
patchNetwork() {
|
|
26570
|
+
const networkInterceptor = this;
|
|
26571
|
+
if (networkInterceptor._networkPatched)
|
|
26572
|
+
return;
|
|
26573
|
+
networkInterceptor._networkPatched = true;
|
|
26574
|
+
networkInterceptor.patchFetch();
|
|
26575
|
+
networkInterceptor.patchXHR();
|
|
26576
|
+
}
|
|
26413
26577
|
on({ request, response, error } = {}) {
|
|
26414
26578
|
if (!this.callbackFns) {
|
|
26415
26579
|
this.callbackFns = [];
|
|
@@ -26417,7 +26581,7 @@ class NetworkRequestIntercept {
|
|
|
26417
26581
|
if (_.isFunction(request) || _.isFunction(response) || _.isFunction(error)) {
|
|
26418
26582
|
this.callbackFns.push({ request, response, error });
|
|
26419
26583
|
}
|
|
26420
|
-
if (!this._networkPatched
|
|
26584
|
+
if (!this._networkPatched) {
|
|
26421
26585
|
this.patchNetwork();
|
|
26422
26586
|
}
|
|
26423
26587
|
return this;
|
|
@@ -27023,6 +27187,14 @@ var GuideActivity = (function () {
|
|
|
27023
27187
|
function isEventOnTextLink(appData) {
|
|
27024
27188
|
return !!getTextLink(appData);
|
|
27025
27189
|
}
|
|
27190
|
+
function getStepIdFromAppData(appData) {
|
|
27191
|
+
if (!appData)
|
|
27192
|
+
return;
|
|
27193
|
+
if (/^pendo-g-/.test(appData.id)) {
|
|
27194
|
+
return appData.id.replace(/^pendo-g-/, '');
|
|
27195
|
+
}
|
|
27196
|
+
return getStepIdFromAppData(appData.parentElem);
|
|
27197
|
+
}
|
|
27026
27198
|
function getTextLink(appData) {
|
|
27027
27199
|
if (appData.tag === 'A') {
|
|
27028
27200
|
return { type: appData.tag, id: appData.id };
|
|
@@ -27220,7 +27392,19 @@ var GuideActivity = (function () {
|
|
|
27220
27392
|
if (guide)
|
|
27221
27393
|
return guide;
|
|
27222
27394
|
}
|
|
27223
|
-
|
|
27395
|
+
const stepId = getStepIdFromAppData(appData);
|
|
27396
|
+
const activeGuide = getActiveGuide();
|
|
27397
|
+
if (stepId && activeGuide && activeGuide.step && stepId != activeGuide.step.id) {
|
|
27398
|
+
let step;
|
|
27399
|
+
const guide = _.find(getLocalActiveGuides(), function (guide) {
|
|
27400
|
+
step = _.find(guide.steps, (step) => step.id === stepId);
|
|
27401
|
+
return !!step;
|
|
27402
|
+
});
|
|
27403
|
+
if (guide && step) {
|
|
27404
|
+
return { guide, step };
|
|
27405
|
+
}
|
|
27406
|
+
}
|
|
27407
|
+
return activeGuide;
|
|
27224
27408
|
}
|
|
27225
27409
|
})();
|
|
27226
27410
|
|
|
@@ -27237,6 +27421,8 @@ const PluginAPI = {
|
|
|
27237
27421
|
collectEvent
|
|
27238
27422
|
},
|
|
27239
27423
|
attachEvent,
|
|
27424
|
+
attachEventInternal,
|
|
27425
|
+
detachEventInternal,
|
|
27240
27426
|
ConfigReader,
|
|
27241
27427
|
Events,
|
|
27242
27428
|
EventTracer,
|
|
@@ -28201,6 +28387,9 @@ var BuildingBlockGuides = (function () {
|
|
|
28201
28387
|
function renderGuideFromJSON(json, step, guides, options) {
|
|
28202
28388
|
options = options || {};
|
|
28203
28389
|
var guide = step.getGuide();
|
|
28390
|
+
if (step.isDarkMode === undefined) {
|
|
28391
|
+
syncColorMode(step);
|
|
28392
|
+
}
|
|
28204
28393
|
var containerJSON = findGuideContainerJSON(json);
|
|
28205
28394
|
var isResourceCenter = _.get(guide, 'attributes.resourceCenter');
|
|
28206
28395
|
if (isResourceCenter) {
|
|
@@ -28733,13 +28922,13 @@ var logHistory = [];
|
|
|
28733
28922
|
var errorHistory = [];
|
|
28734
28923
|
const LOG_ENABLED = 'log-enabled';
|
|
28735
28924
|
const ACTIVE_CONTEXTS = 'active-contexts';
|
|
28736
|
-
var getDefaultLogOverride = function (
|
|
28925
|
+
var getDefaultLogOverride = function () {
|
|
28737
28926
|
var isEnabledCookie = agentStorage.read(LOG_ENABLED, true);
|
|
28738
28927
|
if (isEnabledCookie !== null) {
|
|
28739
28928
|
return isEnabledCookie == 'true';
|
|
28740
28929
|
}
|
|
28741
28930
|
// add welcome message and list logging status + contexts
|
|
28742
|
-
return !
|
|
28931
|
+
return !isProdAgent() && !isRCAgent();
|
|
28743
28932
|
};
|
|
28744
28933
|
var getDefaultActiveContexts = function () {
|
|
28745
28934
|
var ac = agentStorage.read(ACTIVE_CONTEXTS, true);
|
|
@@ -28784,7 +28973,7 @@ var disableLogging = function () {
|
|
|
28784
28973
|
};
|
|
28785
28974
|
function initLogging() {
|
|
28786
28975
|
activeContexts = getDefaultActiveContexts();
|
|
28787
|
-
logOverride = getDefaultLogOverride(
|
|
28976
|
+
logOverride = getDefaultLogOverride();
|
|
28788
28977
|
log.addEventListener('log', writeLog);
|
|
28789
28978
|
/**
|
|
28790
28979
|
* Stores console logging status, set with `pendo.enableLogging()` or `pendo.disableLogging()`.
|
|
@@ -29777,7 +29966,7 @@ function LocationPublic(cmd) {
|
|
|
29777
29966
|
}
|
|
29778
29967
|
_.extend(LocationPublic, {
|
|
29779
29968
|
getHref() {
|
|
29780
|
-
return
|
|
29969
|
+
return pendoDotUrl.get();
|
|
29781
29970
|
},
|
|
29782
29971
|
clearTransforms() {
|
|
29783
29972
|
store.commit('location/clearTransforms');
|
|
@@ -31068,6 +31257,10 @@ var GuideDisplay = (function () {
|
|
|
31068
31257
|
if (step.type !== 'whatsnew' && !step.isShown()) {
|
|
31069
31258
|
return false;
|
|
31070
31259
|
}
|
|
31260
|
+
if (isGuideRequestPending()) {
|
|
31261
|
+
log.info('guides are loading.', { contexts: ['guides', 'loading'] });
|
|
31262
|
+
return false;
|
|
31263
|
+
}
|
|
31071
31264
|
step.unlock();
|
|
31072
31265
|
step._show(reason);
|
|
31073
31266
|
return step.isShown();
|
|
@@ -31552,6 +31745,7 @@ function GuideStep(guide) {
|
|
|
31552
31745
|
step.seenState = 'active';
|
|
31553
31746
|
setSeenTime(getNow());
|
|
31554
31747
|
var seenProps = {
|
|
31748
|
+
color_mode: step.isDarkMode ? 'dark' : 'default',
|
|
31555
31749
|
last_updated_at: step.lastUpdatedAt
|
|
31556
31750
|
};
|
|
31557
31751
|
var pollTypes = this.getStepPollTypes(guide, step);
|
|
@@ -33243,7 +33437,7 @@ const DebuggerModule = (() => {
|
|
|
33243
33437
|
location: { type: SYNC_TYPES.BOTTOM_UP, defaultValue: {} }
|
|
33244
33438
|
};
|
|
33245
33439
|
const actions = {
|
|
33246
|
-
init: (context) => {
|
|
33440
|
+
init: (context, buffer) => {
|
|
33247
33441
|
context.commit('setFrameId', EventTracer.getFrameId());
|
|
33248
33442
|
context.commit('setTabId', EventTracer.getTabId());
|
|
33249
33443
|
context.commit('setInstallType', getInstallType());
|
|
@@ -33263,6 +33457,7 @@ const DebuggerModule = (() => {
|
|
|
33263
33457
|
frameId: context.state.frameId
|
|
33264
33458
|
});
|
|
33265
33459
|
}
|
|
33460
|
+
_.each(buffer.events, (event) => eventCapturedFn(event));
|
|
33266
33461
|
},
|
|
33267
33462
|
join: (context, data) => {
|
|
33268
33463
|
if (context.state.frameId === data.frameId)
|
|
@@ -33418,6 +33613,9 @@ const DebuggerModule = (() => {
|
|
|
33418
33613
|
// Unlike eligibility, here we're collecting all events into a singular list
|
|
33419
33614
|
// this list is reverse chronological order
|
|
33420
33615
|
state.eventsCaptured.unshift(event);
|
|
33616
|
+
if (state.eventsCaptured.length > 100) {
|
|
33617
|
+
state.eventsCaptured.pop();
|
|
33618
|
+
}
|
|
33421
33619
|
},
|
|
33422
33620
|
enableEventLogging(state, enabled) {
|
|
33423
33621
|
state.enableEventLogging = enabled;
|
|
@@ -36956,12 +37154,18 @@ function disableDebugging() {
|
|
|
36956
37154
|
_.extend(debug, debugging);
|
|
36957
37155
|
|
|
36958
37156
|
const waitForLeader = (Events, store, q) => {
|
|
37157
|
+
const buffer = {
|
|
37158
|
+
events: []
|
|
37159
|
+
};
|
|
37160
|
+
Events.on('eventCaptured', (evt) => {
|
|
37161
|
+
buffer.events.push(evt);
|
|
37162
|
+
});
|
|
36959
37163
|
if (store.getters['frames/leaderExists']()) {
|
|
36960
|
-
return q.resolve();
|
|
37164
|
+
return q.resolve(buffer);
|
|
36961
37165
|
}
|
|
36962
37166
|
const deferred = q.defer();
|
|
36963
37167
|
Events.on('leaderChanged', () => {
|
|
36964
|
-
deferred.resolve();
|
|
37168
|
+
deferred.resolve(buffer);
|
|
36965
37169
|
});
|
|
36966
37170
|
return deferred.promise;
|
|
36967
37171
|
};
|
|
@@ -36976,8 +37180,8 @@ const DebuggerLauncher = (function () {
|
|
|
36976
37180
|
function initialize(pendo, PluginAPI) {
|
|
36977
37181
|
const { Events, q } = PluginAPI;
|
|
36978
37182
|
store = PluginAPI.store;
|
|
36979
|
-
waitForLeader(Events, store, q).then(() => {
|
|
36980
|
-
store.dispatch('debugger/init');
|
|
37183
|
+
waitForLeader(Events, store, q).then((buffer) => {
|
|
37184
|
+
store.dispatch('debugger/init', buffer);
|
|
36981
37185
|
if (store.getters['frames/isLeader']()) {
|
|
36982
37186
|
startDebuggingModuleIfEnabled();
|
|
36983
37187
|
}
|
|
@@ -44343,13 +44547,15 @@ class MutationBuffer {
|
|
|
44343
44547
|
index.childNodes(textarea),
|
|
44344
44548
|
(cn) => index.textContent(cn) || ""
|
|
44345
44549
|
).join("");
|
|
44550
|
+
const needsMask = needMaskingText(textarea, this.maskTextClass, this.maskTextSelector, true);
|
|
44346
44551
|
item.attributes.value = maskInputValue({
|
|
44347
44552
|
element: textarea,
|
|
44348
44553
|
maskInputOptions: this.maskInputOptions,
|
|
44349
44554
|
tagName: textarea.tagName,
|
|
44350
44555
|
type: getInputType(textarea),
|
|
44351
44556
|
value,
|
|
44352
|
-
maskInputFn: this.maskInputFn
|
|
44557
|
+
maskInputFn: this.maskInputFn,
|
|
44558
|
+
needsMask
|
|
44353
44559
|
});
|
|
44354
44560
|
});
|
|
44355
44561
|
__publicField(this, "processMutation", (m) => {
|
|
@@ -52555,6 +52761,12 @@ class SessionRecorder {
|
|
|
52555
52761
|
return;
|
|
52556
52762
|
clearTimeout(this._changeIdentityTimer);
|
|
52557
52763
|
if (this.isRecording()) {
|
|
52764
|
+
this.logStopReason('IDENTITY_CHANGED', {
|
|
52765
|
+
previousVisitorId: this.visitorId,
|
|
52766
|
+
newVisitorId: identifyEvent.data[0].visitor_id,
|
|
52767
|
+
previousAccountId: this.accountId,
|
|
52768
|
+
newAccountId: identifyEvent.data[0].account_id
|
|
52769
|
+
});
|
|
52558
52770
|
this.stop();
|
|
52559
52771
|
}
|
|
52560
52772
|
this.visitorId = identifyEvent.data[0].visitor_id;
|
|
@@ -52650,7 +52862,7 @@ class SessionRecorder {
|
|
|
52650
52862
|
this._start();
|
|
52651
52863
|
}
|
|
52652
52864
|
_markEvents(events) {
|
|
52653
|
-
if (!this.recordingId)
|
|
52865
|
+
if (!this.recordingId || !this.isRecording())
|
|
52654
52866
|
return;
|
|
52655
52867
|
for (var e of events) {
|
|
52656
52868
|
if ((e.visitor_id === this.visitorId || e.visitorId === this.visitorId) && e.type !== 'identify') {
|
|
@@ -52968,6 +53180,8 @@ class SessionRecorder {
|
|
|
52968
53180
|
}
|
|
52969
53181
|
}
|
|
52970
53182
|
addRecordingId(event) {
|
|
53183
|
+
if (!this.isRecording())
|
|
53184
|
+
return;
|
|
52971
53185
|
if (!this.recordingId || !event || !event.data || !event.data.length)
|
|
52972
53186
|
return;
|
|
52973
53187
|
var capturedEvent = event.data[0];
|
|
@@ -52976,6 +53190,10 @@ class SessionRecorder {
|
|
|
52976
53190
|
if (capturedEvent.visitor_id !== this.visitorId && capturedEvent.visitorId !== this.visitorId) {
|
|
52977
53191
|
// visitor id has already diverged from the agent, we'll stop sending events and just return here
|
|
52978
53192
|
this.api.log.warn('Visitor id has diverged from agent');
|
|
53193
|
+
this.logStopReason('VISITOR_ID_DIVERGED', {
|
|
53194
|
+
agentVisitorId: capturedEvent.visitor_id || capturedEvent.visitorId,
|
|
53195
|
+
recordingVisitorId: this.visitorId
|
|
53196
|
+
});
|
|
52979
53197
|
this.stop();
|
|
52980
53198
|
return;
|
|
52981
53199
|
}
|
|
@@ -54155,6 +54373,168 @@ function scrubPII(string) {
|
|
|
54155
54373
|
return Object.values(PII_PATTERN).reduce((str, pattern) => str.replace(pattern, PII_REPLACEMENT), string);
|
|
54156
54374
|
}
|
|
54157
54375
|
|
|
54376
|
+
/**
|
|
54377
|
+
* Determines the type of resource that was blocked based on the blocked URI and CSP directive.
|
|
54378
|
+
*
|
|
54379
|
+
* @param {string} blockedURI - The URI that was blocked by the CSP policy (can be 'inline', 'eval', or a URL)
|
|
54380
|
+
* @param {string} directive - The CSP directive that caused the violation (e.g., 'script-src', 'style-src')
|
|
54381
|
+
* @returns {string} A human-readable description of the resource type
|
|
54382
|
+
*
|
|
54383
|
+
* @example
|
|
54384
|
+
* getResourceType('inline', 'script-src') // returns 'inline script'
|
|
54385
|
+
* getResourceType('https://example.com/script.js', 'script-src') // returns 'script'
|
|
54386
|
+
* getResourceType('https://example.com/image.jpg', 'img-src') // returns 'image'
|
|
54387
|
+
* getResourceType('https://example.com/worker.js', 'worker-src') // returns 'worker'
|
|
54388
|
+
*/
|
|
54389
|
+
function getResourceType(blockedURI, directive) {
|
|
54390
|
+
if (!directive || typeof directive !== 'string')
|
|
54391
|
+
return 'resource';
|
|
54392
|
+
const d = directive.toLowerCase();
|
|
54393
|
+
if (blockedURI === 'inline') {
|
|
54394
|
+
if (d.includes('script-src-attr')) {
|
|
54395
|
+
return 'inline event handler';
|
|
54396
|
+
}
|
|
54397
|
+
if (d.includes('style-src-attr')) {
|
|
54398
|
+
return 'inline style attribute';
|
|
54399
|
+
}
|
|
54400
|
+
if (d.includes('script')) {
|
|
54401
|
+
return 'inline script';
|
|
54402
|
+
}
|
|
54403
|
+
if (d.includes('style')) {
|
|
54404
|
+
return 'inline style';
|
|
54405
|
+
}
|
|
54406
|
+
}
|
|
54407
|
+
if (blockedURI === 'eval') {
|
|
54408
|
+
return 'eval script execution';
|
|
54409
|
+
}
|
|
54410
|
+
if (d.includes('worker'))
|
|
54411
|
+
return 'worker';
|
|
54412
|
+
if (d.includes('script')) {
|
|
54413
|
+
return d.includes('elem') ? 'script element' : 'script';
|
|
54414
|
+
}
|
|
54415
|
+
if (d.includes('style')) {
|
|
54416
|
+
return d.includes('elem') ? 'style element' : 'stylesheet';
|
|
54417
|
+
}
|
|
54418
|
+
if (d.includes('img'))
|
|
54419
|
+
return 'image';
|
|
54420
|
+
if (d.includes('font'))
|
|
54421
|
+
return 'font';
|
|
54422
|
+
if (d.includes('connect'))
|
|
54423
|
+
return 'network request';
|
|
54424
|
+
if (d.includes('media'))
|
|
54425
|
+
return 'media resource';
|
|
54426
|
+
if (d.includes('frame-ancestors'))
|
|
54427
|
+
return 'display of your page in a frame';
|
|
54428
|
+
if (d.includes('frame'))
|
|
54429
|
+
return 'frame';
|
|
54430
|
+
if (d.includes('manifest'))
|
|
54431
|
+
return 'manifest';
|
|
54432
|
+
if (d.includes('base-uri'))
|
|
54433
|
+
return 'base URI';
|
|
54434
|
+
if (d.includes('form-action'))
|
|
54435
|
+
return 'form submission';
|
|
54436
|
+
return 'resource';
|
|
54437
|
+
}
|
|
54438
|
+
/**
|
|
54439
|
+
* Finds a specific directive in a CSP policy string and returns it with its value.
|
|
54440
|
+
*
|
|
54441
|
+
* @param {string} policy - The complete original CSP policy string (semicolon-separated directives)
|
|
54442
|
+
* @param {string} directiveName - The name of the directive to find (e.g., 'script-src', 'style-src')
|
|
54443
|
+
* @returns {string} The complete directive with its value if found, empty string otherwise
|
|
54444
|
+
*
|
|
54445
|
+
* @example
|
|
54446
|
+
* getDirective('script-src \'self\'; style-src \'self\'', 'script-src') // returns 'script-src \'self\''
|
|
54447
|
+
*/
|
|
54448
|
+
function getDirective(policy, directiveName) {
|
|
54449
|
+
if (!policy || !directiveName)
|
|
54450
|
+
return '';
|
|
54451
|
+
const needle = directiveName.toLowerCase();
|
|
54452
|
+
for (const directive of policy.split(';')) {
|
|
54453
|
+
const trimmed = directive.trim();
|
|
54454
|
+
const lower = trimmed.toLowerCase();
|
|
54455
|
+
if (lower === needle || lower.startsWith(`${needle} `)) {
|
|
54456
|
+
return trimmed;
|
|
54457
|
+
}
|
|
54458
|
+
}
|
|
54459
|
+
return '';
|
|
54460
|
+
}
|
|
54461
|
+
/**
|
|
54462
|
+
* Determines the appropriate article (A/An) for a given phrase based on its first letter.
|
|
54463
|
+
*
|
|
54464
|
+
* @param {string} phrase - The phrase to determine the article for
|
|
54465
|
+
* @returns {string} Either 'A' or 'An' based on whether the phrase starts with a vowel sound
|
|
54466
|
+
*
|
|
54467
|
+
* @example
|
|
54468
|
+
* getArticle('script') // returns 'A'
|
|
54469
|
+
* getArticle('image') // returns 'An'
|
|
54470
|
+
* getArticle('stylesheet') // returns 'A'
|
|
54471
|
+
* getArticle('') // returns 'A' (fallback for empty string)
|
|
54472
|
+
* getArticle(undefined) // returns 'A' (fallback for undefined)
|
|
54473
|
+
*/
|
|
54474
|
+
function getArticle(phrase) {
|
|
54475
|
+
if (!phrase || typeof phrase !== 'string')
|
|
54476
|
+
return 'A';
|
|
54477
|
+
const c = phrase.trim().charAt(0).toLowerCase();
|
|
54478
|
+
return 'aeiou'.includes(c) ? 'An' : 'A';
|
|
54479
|
+
}
|
|
54480
|
+
/**
|
|
54481
|
+
* Returns the original blocked URI when it looks like a URL or scheme,
|
|
54482
|
+
* otherwise returns an empty string for special cases.
|
|
54483
|
+
*
|
|
54484
|
+
* @param {string} blockedURI - The URI that was blocked (can be 'inline', 'eval', or a URL/scheme)
|
|
54485
|
+
* @returns {string} The blocked URI or an empty string for special cases like 'inline' or 'eval'
|
|
54486
|
+
*
|
|
54487
|
+
* @example
|
|
54488
|
+
* formatBlockedUri('https://example.com/script.js') // returns 'https://example.com/script.js'
|
|
54489
|
+
* formatBlockedUri('inline') // returns ''
|
|
54490
|
+
* formatBlockedUri('blob') // returns 'blob'
|
|
54491
|
+
*/
|
|
54492
|
+
function formatBlockedUri(blockedURI) {
|
|
54493
|
+
if (!blockedURI || blockedURI === 'inline' || blockedURI === 'eval')
|
|
54494
|
+
return '';
|
|
54495
|
+
return blockedURI;
|
|
54496
|
+
}
|
|
54497
|
+
/**
|
|
54498
|
+
* Formats a CSP violation message for console output.
|
|
54499
|
+
*
|
|
54500
|
+
* @param {string} blockedURI - The URI that was blocked by the CSP policy (can be 'inline', 'eval', or a URL)
|
|
54501
|
+
* @param {string} directive - The CSP directive that caused the violation (e.g., 'script-src', 'frame-ancestors')
|
|
54502
|
+
* @param {boolean} isReportOnly - Whether this is a report-only policy violation (adds " (Report-Only)" to message)
|
|
54503
|
+
* @param {string} originalPolicy - The complete CSP policy that was violated
|
|
54504
|
+
* @returns {string} A formatted readable CSP violation message
|
|
54505
|
+
*
|
|
54506
|
+
* @example
|
|
54507
|
+
* createCspViolationMessage(
|
|
54508
|
+
* 'https://example.com/script.js',
|
|
54509
|
+
* 'script-src',
|
|
54510
|
+
* false,
|
|
54511
|
+
* 'script-src \'self\'; style-src \'self\''
|
|
54512
|
+
* )
|
|
54513
|
+
* // returns: "Content Security Policy: A script from https://example.com/script.js was blocked by your site's `script-src 'self'` policy.\nCurrent CSP: \"script-src 'self'; style-src 'self'\"."
|
|
54514
|
+
*/
|
|
54515
|
+
function createCspViolationMessage(blockedURI, directive, isReportOnly, originalPolicy) {
|
|
54516
|
+
if (!directive || typeof directive !== 'string') {
|
|
54517
|
+
return 'Content Security Policy: Unknown violation occurred.';
|
|
54518
|
+
}
|
|
54519
|
+
try {
|
|
54520
|
+
const reportOnlyText = isReportOnly ? ' (Report-Only)' : '';
|
|
54521
|
+
// special case for frame-ancestors since it doesn't fit our template at all
|
|
54522
|
+
if ((directive === null || directive === void 0 ? void 0 : directive.toLowerCase()) === 'frame-ancestors') {
|
|
54523
|
+
return `Content Security Policy${reportOnlyText}: The display of ${blockedURI} in a frame was blocked because an ancestor violates your site's frame-ancestors policy.\nCurrent CSP: "${originalPolicy}".`;
|
|
54524
|
+
}
|
|
54525
|
+
const resourceType = getResourceType(blockedURI, directive);
|
|
54526
|
+
const article = getArticle(resourceType);
|
|
54527
|
+
const source = formatBlockedUri(blockedURI);
|
|
54528
|
+
const directiveValue = getDirective(originalPolicy, directive);
|
|
54529
|
+
const policyDisplay = directiveValue || directive;
|
|
54530
|
+
const resourceDescription = `${article} ${resourceType}${source ? ` from ${source}` : ''}`;
|
|
54531
|
+
return `Content Security Policy${reportOnlyText}: ${resourceDescription} was blocked by your site's \`${policyDisplay}\` policy.\nCurrent CSP: "${originalPolicy}".`;
|
|
54532
|
+
}
|
|
54533
|
+
catch (error) {
|
|
54534
|
+
return `Content Security Policy: Error formatting violation message: ${error.message}`;
|
|
54535
|
+
}
|
|
54536
|
+
}
|
|
54537
|
+
|
|
54158
54538
|
const DEV_LOG_LEVELS = ['info', 'warn', 'error'];
|
|
54159
54539
|
const TOKEN_MAX_SIZE = 100;
|
|
54160
54540
|
const TOKEN_REFILL_RATE = 10;
|
|
@@ -55699,11 +56079,12 @@ function isNativeCode(fn) { return /native/.test(fn); }
|
|
|
55699
56079
|
// we've added trident to track this actual version of IE so we can
|
|
55700
56080
|
// attempt to handle these cases too.
|
|
55701
56081
|
// holds major version number for IE or NaN for real browsers
|
|
55702
|
-
|
|
56082
|
+
const msie = determineMSIE(getUA());
|
|
56083
|
+
determineTrident(getUA(), msie);
|
|
55703
56084
|
function pint(str) { return parseInt(str, 10); }
|
|
55704
|
-
|
|
56085
|
+
function lowercase(string) { return _.isString(string) ? string.toLowerCase() : string; }
|
|
55705
56086
|
function isMinimumIEVersion(minVersion) {
|
|
55706
|
-
|
|
56087
|
+
const sniffer = this;
|
|
55707
56088
|
if (isNaN(sniffer.msie) || sniffer.msie == null)
|
|
55708
56089
|
return true;
|
|
55709
56090
|
return sniffer.msie >= minVersion;
|
|
@@ -55713,36 +56094,34 @@ function getUA() {
|
|
|
55713
56094
|
}
|
|
55714
56095
|
// IE 11 changed the format of the UserAgent string.
|
|
55715
56096
|
// See http://msdn.microsoft.com/en-us/library/ms537503.aspx
|
|
55716
|
-
|
|
55717
|
-
|
|
55718
|
-
if (isNaN(
|
|
55719
|
-
|
|
55720
|
-
}
|
|
55721
|
-
return
|
|
55722
|
-
}
|
|
55723
|
-
|
|
55724
|
-
|
|
55725
|
-
|
|
55726
|
-
|
|
55727
|
-
|
|
55728
|
-
|
|
55729
|
-
|
|
55730
|
-
};
|
|
55731
|
-
|
|
55732
|
-
|
|
55733
|
-
|
|
55734
|
-
|
|
55735
|
-
|
|
55736
|
-
|
|
55737
|
-
|
|
55738
|
-
|
|
55739
|
-
|
|
55740
|
-
|
|
55741
|
-
var animations = false;
|
|
55742
|
-
var match;
|
|
56097
|
+
function determineMSIE(userAgent) {
|
|
56098
|
+
let version = pint((/msie (\d+)/.exec(lowercase(userAgent)) || [])[1]);
|
|
56099
|
+
if (isNaN(version)) {
|
|
56100
|
+
version = pint((/trident\/.*; rv:(\d+)/.exec(lowercase(userAgent)) || [])[1]);
|
|
56101
|
+
}
|
|
56102
|
+
return version;
|
|
56103
|
+
}
|
|
56104
|
+
function determineTrident(userAgent, ieVersion) {
|
|
56105
|
+
let version = pint((/trident\/(\d+)/.exec(lowercase(userAgent)) || [])[1]);
|
|
56106
|
+
if (isNaN(version) && ieVersion == 7) {
|
|
56107
|
+
version = 3;
|
|
56108
|
+
}
|
|
56109
|
+
return version;
|
|
56110
|
+
}
|
|
56111
|
+
const eventSupport = {};
|
|
56112
|
+
const android = pint((/android (\d+)/.exec(lowercase(getUA())) || [])[1]);
|
|
56113
|
+
const boxee = /Boxee/i.test(getUA());
|
|
56114
|
+
const pdocument = window.document || {};
|
|
56115
|
+
const documentMode = pdocument.documentMode;
|
|
56116
|
+
let vendorPrefix;
|
|
56117
|
+
const vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/;
|
|
56118
|
+
const bodyStyle = pdocument.body && pdocument.body.style;
|
|
56119
|
+
let transitions = false;
|
|
56120
|
+
let animations = false;
|
|
56121
|
+
let match;
|
|
55743
56122
|
if (bodyStyle) {
|
|
55744
56123
|
// eslint-disable-next-line guard-for-in
|
|
55745
|
-
for (
|
|
56124
|
+
for (const prop in bodyStyle) {
|
|
55746
56125
|
match = vendorRegex.exec(prop);
|
|
55747
56126
|
if (match) {
|
|
55748
56127
|
vendorPrefix = match[0];
|
|
@@ -55760,7 +56139,7 @@ if (bodyStyle) {
|
|
|
55760
56139
|
animations = _.isString(pdocument.body.style.webkitAnimation);
|
|
55761
56140
|
}
|
|
55762
56141
|
}
|
|
55763
|
-
|
|
56142
|
+
const isChromeExtension = window.chrome && window.chrome.runtime && window.chrome.runtime.id;
|
|
55764
56143
|
// Android has history.pushState, but it does not update location correctly
|
|
55765
56144
|
// so let's not use the history API at all.
|
|
55766
56145
|
// http://code.google.com/p/android/issues/detail?id=17471
|
|
@@ -55768,28 +56147,28 @@ var isChromeExtension = window.chrome && window.chrome.runtime && window.chrome.
|
|
|
55768
56147
|
// older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
|
|
55769
56148
|
// so let's not use the history API also
|
|
55770
56149
|
// We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
|
|
55771
|
-
|
|
55772
|
-
|
|
55773
|
-
|
|
55774
|
-
|
|
55775
|
-
|
|
55776
|
-
|
|
56150
|
+
const shouldWrapNativeHistory = _.memoize(function shouldWrapNativeHistory() {
|
|
56151
|
+
const hasNativeHistory = window.history && window.history.pushState && window.history.replaceState;
|
|
56152
|
+
const isHistoryFrozen = window.history && _.isFunction(Object.isFrozen) && Object.isFrozen(window.history);
|
|
56153
|
+
const historyDescriptors = window.history && _.isFunction(Object.getOwnPropertyDescriptors) && Object.getOwnPropertyDescriptors(window.history);
|
|
56154
|
+
const isHistoryWriteable = historyDescriptors && _.get(historyDescriptors, 'pushState.writable', true) && _.get(historyDescriptors, 'replaceState.writable', true);
|
|
56155
|
+
const hasAndroidSupport = !(android < 4);
|
|
55777
56156
|
return !!(hasNativeHistory && !isHistoryFrozen && isHistoryWriteable && hasAndroidSupport && !boxee && !isExtensionAgent());
|
|
55778
56157
|
});
|
|
55779
56158
|
function shouldWrapHashChange() {
|
|
55780
|
-
|
|
56159
|
+
const hasNativeHashChange = 'onhashchange' in window;
|
|
55781
56160
|
// IE8 compatible mode lies
|
|
55782
|
-
|
|
56161
|
+
const hasSupportedDocMode = (!documentMode || documentMode > 7);
|
|
55783
56162
|
return !!(hasNativeHashChange && hasSupportedDocMode && !isExtensionAgent());
|
|
55784
56163
|
}
|
|
55785
56164
|
function isMobileUserAgent() {
|
|
55786
56165
|
return (/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i).test(getUA());
|
|
55787
56166
|
}
|
|
55788
|
-
|
|
55789
|
-
|
|
55790
|
-
|
|
56167
|
+
function isSafari(userAgent = getUA()) {
|
|
56168
|
+
return userAgent.indexOf('Safari') >= 0 && !userAgent.indexOf('Chrome') >= 0;
|
|
56169
|
+
}
|
|
56170
|
+
const sniffer = {
|
|
55791
56171
|
supportsHistoryApi: shouldWrapNativeHistory,
|
|
55792
|
-
// jshint +W018
|
|
55793
56172
|
supportsHashChange: shouldWrapHashChange,
|
|
55794
56173
|
hasEvent(event) {
|
|
55795
56174
|
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
|
|
@@ -55798,7 +56177,7 @@ var sniffer = {
|
|
|
55798
56177
|
if (event == 'input' && msie == 9)
|
|
55799
56178
|
return false;
|
|
55800
56179
|
if (_.isUndefined(eventSupport[event])) {
|
|
55801
|
-
|
|
56180
|
+
const divElm = pdocument.createElement('div');
|
|
55802
56181
|
eventSupport[event] = 'on' + event in divElm;
|
|
55803
56182
|
}
|
|
55804
56183
|
return eventSupport[event];
|
|
@@ -55809,7 +56188,7 @@ var sniffer = {
|
|
|
55809
56188
|
android,
|
|
55810
56189
|
msie,
|
|
55811
56190
|
msieDocumentMode: documentMode,
|
|
55812
|
-
safari:
|
|
56191
|
+
safari: isSafari(),
|
|
55813
56192
|
sri: ('integrity' in document.createElement('script')),
|
|
55814
56193
|
addEventListener: _.isFunction(window.addEventListener),
|
|
55815
56194
|
MutationObserver: isNativeCode(window.MutationObserver),
|
|
@@ -56289,6 +56668,7 @@ function ConsoleCapture() {
|
|
|
56289
56668
|
onAppUnloaded,
|
|
56290
56669
|
onPtmPaused,
|
|
56291
56670
|
onPtmUnpaused,
|
|
56671
|
+
securityPolicyViolationFn,
|
|
56292
56672
|
get buffer() {
|
|
56293
56673
|
return buffer;
|
|
56294
56674
|
},
|
|
@@ -56317,7 +56697,7 @@ function ConsoleCapture() {
|
|
|
56317
56697
|
}
|
|
56318
56698
|
}, SEND_INTERVAL);
|
|
56319
56699
|
sendQueue.start();
|
|
56320
|
-
pluginAPI.Events.ready.on(
|
|
56700
|
+
pluginAPI.Events.ready.on(readyHandler);
|
|
56321
56701
|
pluginAPI.Events.appUnloaded.on(onAppUnloaded);
|
|
56322
56702
|
pluginAPI.Events.appHidden.on(onAppHidden);
|
|
56323
56703
|
pluginAPI.Events['ptm:paused'].on(onPtmPaused);
|
|
@@ -56352,6 +56732,10 @@ function ConsoleCapture() {
|
|
|
56352
56732
|
url: globalPendo.url.get()
|
|
56353
56733
|
};
|
|
56354
56734
|
}
|
|
56735
|
+
function readyHandler() {
|
|
56736
|
+
addIntercepts();
|
|
56737
|
+
pluginAPI.attachEventInternal(window, 'securitypolicyviolation', securityPolicyViolationFn);
|
|
56738
|
+
}
|
|
56355
56739
|
function addIntercepts() {
|
|
56356
56740
|
_.each(CONSOLE_METHODS, function (methodName) {
|
|
56357
56741
|
const originalMethod = console[methodName];
|
|
@@ -56368,7 +56752,21 @@ function ConsoleCapture() {
|
|
|
56368
56752
|
};
|
|
56369
56753
|
});
|
|
56370
56754
|
}
|
|
56371
|
-
function
|
|
56755
|
+
function securityPolicyViolationFn(evt) {
|
|
56756
|
+
if (!evt || typeof evt !== 'object')
|
|
56757
|
+
return;
|
|
56758
|
+
const { blockedURI, violatedDirective, effectiveDirective, disposition, originalPolicy } = evt;
|
|
56759
|
+
const directive = violatedDirective || effectiveDirective;
|
|
56760
|
+
const isReportOnly = disposition === 'report';
|
|
56761
|
+
const message = createCspViolationMessage(blockedURI, directive, isReportOnly, originalPolicy);
|
|
56762
|
+
if (isReportOnly) {
|
|
56763
|
+
createConsoleEvent([message], 'warn', { skipStackTrace: true, skipScrubPII: true });
|
|
56764
|
+
}
|
|
56765
|
+
else {
|
|
56766
|
+
createConsoleEvent([message], 'error', { skipStackTrace: true, skipScrubPII: true });
|
|
56767
|
+
}
|
|
56768
|
+
}
|
|
56769
|
+
function createConsoleEvent(args, methodName, { skipStackTrace = false, skipScrubPII = false } = {}) {
|
|
56372
56770
|
if (!args || args.length === 0)
|
|
56373
56771
|
return;
|
|
56374
56772
|
// stringify args
|
|
@@ -56385,8 +56783,11 @@ function ConsoleCapture() {
|
|
|
56385
56783
|
if (!message)
|
|
56386
56784
|
return;
|
|
56387
56785
|
// capture stack trace
|
|
56388
|
-
|
|
56389
|
-
|
|
56786
|
+
let stackTrace = '';
|
|
56787
|
+
if (!skipStackTrace) {
|
|
56788
|
+
const maxStackFrames = methodName === 'error' ? 4 : 1;
|
|
56789
|
+
stackTrace = captureStackTrace(maxStackFrames);
|
|
56790
|
+
}
|
|
56390
56791
|
// truncate message and stack trace
|
|
56391
56792
|
message = truncate(message);
|
|
56392
56793
|
stackTrace = truncate(stackTrace);
|
|
@@ -56397,7 +56798,7 @@ function ConsoleCapture() {
|
|
|
56397
56798
|
return;
|
|
56398
56799
|
}
|
|
56399
56800
|
const devLogEnvelope = createDevLogEnvelope();
|
|
56400
|
-
const consoleEvent = Object.assign(Object.assign({}, devLogEnvelope), { devLogLevel: methodName === 'log' ? 'info' : methodName, devLogMessage: scrubPII(message), devLogTrace: stackTrace, devLogCount: 1 });
|
|
56801
|
+
const consoleEvent = Object.assign(Object.assign({}, devLogEnvelope), { devLogLevel: methodName === 'log' ? 'info' : methodName, devLogMessage: skipScrubPII ? message : scrubPII(message), devLogTrace: stackTrace, devLogCount: 1 });
|
|
56401
56802
|
const wasAccepted = buffer.push(consoleEvent);
|
|
56402
56803
|
if (wasAccepted) {
|
|
56403
56804
|
if (!isPtmPaused) {
|
|
@@ -56459,6 +56860,7 @@ function ConsoleCapture() {
|
|
|
56459
56860
|
pluginAPI.Events.appUnloaded.off(onAppUnloaded);
|
|
56460
56861
|
pluginAPI.Events['ptm:paused'].off(onPtmPaused);
|
|
56461
56862
|
pluginAPI.Events['ptm:unpaused'].off(onPtmUnpaused);
|
|
56863
|
+
pluginAPI.detachEventInternal(window, 'securitypolicyviolation', securityPolicyViolationFn);
|
|
56462
56864
|
_.each(CONSOLE_METHODS, function (methodName) {
|
|
56463
56865
|
if (!console[methodName])
|
|
56464
56866
|
return _.noop;
|