@pendo/agent 2.328.1 → 2.329.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/dist/dom.esm.js +11 -3
- package/dist/pendo.module.js +1136 -873
- package/dist/pendo.module.min.js +106 -8
- package/dist/servers.json +7 -7
- package/index.js +1 -1
- package/package.json +1 -1
package/dist/pendo.module.js
CHANGED
|
@@ -2916,7 +2916,15 @@ var ConfigReader = (function () {
|
|
|
2916
2916
|
addOption('disableAutoInitialize');
|
|
2917
2917
|
/**
|
|
2918
2918
|
* If set to `true` the web SDK will wait for the host application to be both loaded and visible before
|
|
2919
|
-
* starting the initialization process.
|
|
2919
|
+
* starting the initialization process. Only the first call to `initialize` is honored while waiting
|
|
2920
|
+
* for visibility; subsequent calls are rejected and logged. This setting takes precedence over
|
|
2921
|
+
* `initializeImmediately`.
|
|
2922
|
+
*
|
|
2923
|
+
* This is a server-delivered setting and cannot be provided through the options passed to
|
|
2924
|
+
* `pendo.initialize`: the visibility gate runs before those options are read.
|
|
2925
|
+
*
|
|
2926
|
+
* This relies on the Page Visibility API. In browsers that do not support `document.visibilityState`,
|
|
2927
|
+
* enabling this option will defer initialization indefinitely.
|
|
2920
2928
|
*
|
|
2921
2929
|
* @access public
|
|
2922
2930
|
* @category Config/Core
|
|
@@ -2924,7 +2932,7 @@ var ConfigReader = (function () {
|
|
|
2924
2932
|
* @default false
|
|
2925
2933
|
* @type {boolean}
|
|
2926
2934
|
*/
|
|
2927
|
-
addOption('initializeWhenVisible', [
|
|
2935
|
+
addOption('initializeWhenVisible', [PENDO_CONFIG_SRC], false);
|
|
2928
2936
|
/**
|
|
2929
2937
|
* Although the name refers to cookies, if set to `true` the web SDK will not persist any data in local
|
|
2930
2938
|
* storage or cookies and will rely only on memory.
|
|
@@ -4002,8 +4010,8 @@ let SERVER = '';
|
|
|
4002
4010
|
let ASSET_HOST = '';
|
|
4003
4011
|
let ASSET_PATH = '';
|
|
4004
4012
|
let DESIGNER_SERVER = '';
|
|
4005
|
-
let VERSION = '2.
|
|
4006
|
-
let PACKAGE_VERSION = '2.
|
|
4013
|
+
let VERSION = '2.329.0_';
|
|
4014
|
+
let PACKAGE_VERSION = '2.329.0';
|
|
4007
4015
|
let LOADER = 'xhr';
|
|
4008
4016
|
/* eslint-enable web-sdk-eslint-rules/no-gulp-env-references */
|
|
4009
4017
|
/**
|
|
@@ -20089,6 +20097,7 @@ var GuideStateModule = (function () {
|
|
|
20089
20097
|
storageKey: LAST_STEP_ADVANCED_COOKIE,
|
|
20090
20098
|
guideRequestExpiration: 60 * 60 * 1000,
|
|
20091
20099
|
scopedStorageKey: null,
|
|
20100
|
+
scopedThrottlingStorageKeys: {},
|
|
20092
20101
|
receivedStateChangeAt: null,
|
|
20093
20102
|
receivedLastGuideStepSeen: null,
|
|
20094
20103
|
lastGuideStepSeen: null,
|
|
@@ -20111,6 +20120,11 @@ var GuideStateModule = (function () {
|
|
|
20111
20120
|
*/
|
|
20112
20121
|
context.getters.storage().registry.addLocal(LAST_STEP_ADVANCED_COOKIE);
|
|
20113
20122
|
context.commit('setScopedStorageKey', getPendoCookieKey(context.state.storageKey));
|
|
20123
|
+
var scopedThrottlingStorageKeys = {};
|
|
20124
|
+
_.each(THROTTLING_STATE, function (throttlingStorageKey) {
|
|
20125
|
+
scopedThrottlingStorageKeys[throttlingStorageKey] = getPendoCookieKey(throttlingStorageKey);
|
|
20126
|
+
});
|
|
20127
|
+
context.commit('setScopedThrottlingStorageKeys', scopedThrottlingStorageKeys);
|
|
20114
20128
|
Events.identify.on(function (evt) {
|
|
20115
20129
|
if (wasSessionCleared(evt)) {
|
|
20116
20130
|
removeIdentificationCookies([LAST_STEP_ADVANCED_COOKIE]);
|
|
@@ -20149,11 +20163,21 @@ var GuideStateModule = (function () {
|
|
|
20149
20163
|
});
|
|
20150
20164
|
}
|
|
20151
20165
|
}
|
|
20166
|
+
context.dispatch('loadThrottling');
|
|
20167
|
+
},
|
|
20168
|
+
loadThrottling(context) {
|
|
20169
|
+
const storage = context.getters.storage();
|
|
20152
20170
|
_.each(THROTTLING_STATE, function (throttlingStorageKey) {
|
|
20153
20171
|
const value = storage.read(throttlingStorageKey);
|
|
20154
20172
|
context.dispatch('updateThrottlingState', { name: throttlingStorageKey, value });
|
|
20155
20173
|
});
|
|
20156
20174
|
},
|
|
20175
|
+
applyThrottling(context) {
|
|
20176
|
+
_.each(THROTTLING_STATE, function (throttlingStorageKey) {
|
|
20177
|
+
pendo$1[throttlingStorageKey] = applyTimerCache(pendo$1[throttlingStorageKey], context.state[throttlingStorageKey]);
|
|
20178
|
+
context.dispatch('updateThrottlingState', { name: throttlingStorageKey, value: pendo$1[throttlingStorageKey] });
|
|
20179
|
+
});
|
|
20180
|
+
},
|
|
20157
20181
|
forceExpire(context) {
|
|
20158
20182
|
_.each(context.state.steps, function (stepState, stepId) {
|
|
20159
20183
|
context.commit('expireStepState', stepId);
|
|
@@ -20229,10 +20253,7 @@ var GuideStateModule = (function () {
|
|
|
20229
20253
|
if (mostRecentLastGuideStepSeen) {
|
|
20230
20254
|
context.dispatch('updateLastGuideStepSeen', _.extend({}, context.state.lastGuideStepSeen, mostRecentLastGuideStepSeen));
|
|
20231
20255
|
}
|
|
20232
|
-
|
|
20233
|
-
pendo$1[throttlingStorageKey] = applyTimerCache(pendo$1[throttlingStorageKey], context.state[throttlingStorageKey]);
|
|
20234
|
-
context.dispatch('updateThrottlingState', { name: throttlingStorageKey, value: pendo$1[throttlingStorageKey] });
|
|
20235
|
-
});
|
|
20256
|
+
context.dispatch('applyThrottling');
|
|
20236
20257
|
},
|
|
20237
20258
|
receiveLastGuideStepSeen(context, lastGuideStepSeen) {
|
|
20238
20259
|
context.commit('setReceivedLastGuideStepSeen', lastGuideStepSeen);
|
|
@@ -20295,6 +20316,10 @@ var GuideStateModule = (function () {
|
|
|
20295
20316
|
}
|
|
20296
20317
|
}
|
|
20297
20318
|
}
|
|
20319
|
+
else if (_.contains(_.values(context.state.scopedThrottlingStorageKeys), storageEvent.key)) {
|
|
20320
|
+
context.dispatch('loadThrottling');
|
|
20321
|
+
context.dispatch('applyThrottling');
|
|
20322
|
+
}
|
|
20298
20323
|
},
|
|
20299
20324
|
regainFocus(context) {
|
|
20300
20325
|
var tabLostFocus = context.getters.tabLostFocus();
|
|
@@ -20322,6 +20347,9 @@ var GuideStateModule = (function () {
|
|
|
20322
20347
|
setScopedStorageKey(state, scopedStorageKey) {
|
|
20323
20348
|
state.scopedStorageKey = scopedStorageKey;
|
|
20324
20349
|
},
|
|
20350
|
+
setScopedThrottlingStorageKeys(state, scopedThrottlingStorageKeys) {
|
|
20351
|
+
state.scopedThrottlingStorageKeys = scopedThrottlingStorageKeys;
|
|
20352
|
+
},
|
|
20325
20353
|
setLastGuideStepSeen(state, lastGuideStepSeen) {
|
|
20326
20354
|
state.lastGuideStepSeen = lastGuideStepSeen;
|
|
20327
20355
|
},
|
|
@@ -22089,22 +22117,6 @@ var whenLoadedCall = function (callback, win) {
|
|
|
22089
22117
|
}
|
|
22090
22118
|
return _.noop;
|
|
22091
22119
|
};
|
|
22092
|
-
const whenVisibleCall = (callback, win = window) => {
|
|
22093
|
-
const { document } = win;
|
|
22094
|
-
const waitForVis = ConfigReader.get('initializeWhenVisible', false);
|
|
22095
|
-
if (!waitForVis || document.visibilityState === 'visible') {
|
|
22096
|
-
callback();
|
|
22097
|
-
return _.noop;
|
|
22098
|
-
}
|
|
22099
|
-
const stopVisListener = attachEventInternal(document, 'visibilitychange', () => {
|
|
22100
|
-
if (document.visibilityState === 'visible') {
|
|
22101
|
-
callback();
|
|
22102
|
-
// need to shut this down immediately as visibility can continue to change
|
|
22103
|
-
stopVisListener();
|
|
22104
|
-
}
|
|
22105
|
-
});
|
|
22106
|
-
return stopVisListener;
|
|
22107
|
-
};
|
|
22108
22120
|
|
|
22109
22121
|
class GuideTypeIdentifier {
|
|
22110
22122
|
constructor(identificationFn, typeName) {
|
|
@@ -23578,13 +23590,13 @@ var onGuideDismissed = function (evt, step) {
|
|
|
23578
23590
|
var seenReason = firstStep && firstStep.seenReason;
|
|
23579
23591
|
var language = currentGuide && currentGuide.language;
|
|
23580
23592
|
var dismissCount = _.get(step, 'dismissCount', 0) + 1;
|
|
23581
|
-
dismissedGuide(guideId, stepId, get_visitor_id(), seenReason, language, dismissCount);
|
|
23582
23593
|
var now = getNow();
|
|
23583
|
-
|
|
23584
|
-
// maintain latestDismissedAutoAt client-side
|
|
23594
|
+
// maintain latestDismissedAutoAt client-side before guideDismissed writes lastStepAdvanced
|
|
23585
23595
|
if (shouldAffectThrottling(currentGuide, seenReason)) {
|
|
23586
23596
|
writeThrottlingStateCache(now, THROTTLING_STATE.DISMISSED);
|
|
23587
23597
|
}
|
|
23598
|
+
dismissedGuide(guideId, stepId, get_visitor_id(), seenReason, language, dismissCount);
|
|
23599
|
+
_updateGuideStepStatus(guideId, stepId, 'dismissed', now, dismissCount);
|
|
23588
23600
|
step.hide();
|
|
23589
23601
|
if (!isGuideShown()) {
|
|
23590
23602
|
stopGuides();
|
|
@@ -23640,12 +23652,12 @@ var onGuideSnoozed = function (evt, step, snoozeDuration) {
|
|
|
23640
23652
|
log.info('snoozing guide for ' + snoozeDuration + ' ms');
|
|
23641
23653
|
var snoozeEndTime = now + snoozeDuration;
|
|
23642
23654
|
step.snoozeEndTime = snoozeEndTime;
|
|
23643
|
-
|
|
23644
|
-
_updateGuideStepStatus(guideId, stepId, 'snoozed', now);
|
|
23645
|
-
// maintain latestSnoozedAutoAt client-side
|
|
23655
|
+
// maintain latestSnoozedAutoAt client-side before guideSnoozed writes lastStepAdvanced
|
|
23646
23656
|
if (shouldAffectThrottling(guide, seenReason)) {
|
|
23647
23657
|
writeThrottlingStateCache(now, THROTTLING_STATE.SNOOZED);
|
|
23648
23658
|
}
|
|
23659
|
+
snoozedGuide(guideId, stepId, visitorId, seenReason, language, snoozeDuration);
|
|
23660
|
+
_updateGuideStepStatus(guideId, stepId, 'snoozed', now);
|
|
23649
23661
|
step.hide();
|
|
23650
23662
|
if (!isGuideShown()) {
|
|
23651
23663
|
stopGuides();
|
|
@@ -23794,15 +23806,15 @@ var onGuideAdvanced = function (evt, step, isIntermediateStep) {
|
|
|
23794
23806
|
if (currentGuide && _.last(currentGuide.steps).id === stepId) {
|
|
23795
23807
|
dismissCount = _.get(step, 'dismissCount', 0) + 1;
|
|
23796
23808
|
}
|
|
23797
|
-
log.info('advancing guide');
|
|
23798
|
-
advancedGuide(guideId, stepId, get_visitor_id(), seenReason, language, isIntermediateStep, destinationStepId, dismissCount);
|
|
23799
|
-
log.info('update guide status');
|
|
23800
23809
|
var now = new Date().getTime();
|
|
23801
|
-
|
|
23802
|
-
// maintain finalAdvancedAutoAt client-side
|
|
23810
|
+
// maintain finalAdvancedAutoAt client-side before guideAdvanced writes lastStepAdvanced
|
|
23803
23811
|
if (shouldAffectThrottling(currentGuide, seenReason)) {
|
|
23804
23812
|
writeThrottlingStateCache(now, THROTTLING_STATE.ADVANCED);
|
|
23805
23813
|
}
|
|
23814
|
+
log.info('advancing guide');
|
|
23815
|
+
advancedGuide(guideId, stepId, get_visitor_id(), seenReason, language, isIntermediateStep, destinationStepId, dismissCount);
|
|
23816
|
+
log.info('update guide status');
|
|
23817
|
+
_updateGuideStepStatus(guideId, stepId, 'advanced', now, dismissCount, destinationStepId);
|
|
23806
23818
|
log.info('stop guide');
|
|
23807
23819
|
stopGuides();
|
|
23808
23820
|
log.info('start guides');
|
|
@@ -26043,7 +26055,7 @@ function getWhiteLabelSettings(config) {
|
|
|
26043
26055
|
var whiteLabelSettings = ConfigReader.get('whiteLabelSettings');
|
|
26044
26056
|
if (!whiteLabelSettings && config && config.ux === 'novus') {
|
|
26045
26057
|
whiteLabelSettings = {
|
|
26046
|
-
logoUrl: 'https://novus.pendo.io/novus-
|
|
26058
|
+
logoUrl: 'https://novus.pendo.io/branding/novus-vector-white.svg',
|
|
26047
26059
|
logoStyle: {
|
|
26048
26060
|
maxWidth: '40px',
|
|
26049
26061
|
maxHeight: '40px'
|
|
@@ -28513,6 +28525,7 @@ const PluginAPI = {
|
|
|
28513
28525
|
trim,
|
|
28514
28526
|
base64EncodeString,
|
|
28515
28527
|
parseUrl,
|
|
28528
|
+
testPageRule,
|
|
28516
28529
|
addInlineStyles: _.partial(addInlineStyles, ConfigReader),
|
|
28517
28530
|
getNow,
|
|
28518
28531
|
escapeRegExp
|
|
@@ -29016,6 +29029,44 @@ function applyDoNotTrackConfigOverrides(options) {
|
|
|
29016
29029
|
// ----------------------------------------------------------------------------------
|
|
29017
29030
|
let initializeCounter = 0;
|
|
29018
29031
|
const initializeImmediately = 'initializeImmediately';
|
|
29032
|
+
const initializeWhenVisible = 'initializeWhenVisible';
|
|
29033
|
+
const teardownFns = [];
|
|
29034
|
+
// State for the visibility gate. Only the first gated initialize() call is
|
|
29035
|
+
// honored — it attaches the single visibilitychange listener and its arguments
|
|
29036
|
+
// replay once the document becomes visible. Any later calls while the gate is
|
|
29037
|
+
// pending are rejected and ignored. Must live at module scope so later
|
|
29038
|
+
// initialize() calls can see a gate is active; null when no gate is active.
|
|
29039
|
+
let pendingInitializeArgs = null;
|
|
29040
|
+
function shouldGateOnVisibility() {
|
|
29041
|
+
return ConfigReader.get(initializeWhenVisible, false) &&
|
|
29042
|
+
typeof document !== 'undefined' &&
|
|
29043
|
+
document.visibilityState !== 'visible';
|
|
29044
|
+
}
|
|
29045
|
+
function gateInitializeOnVisibility(args) {
|
|
29046
|
+
if (pendingInitializeArgs !== null) {
|
|
29047
|
+
log.warn('pendo.initialize call rejected: an earlier call is already waiting for the document to become visible.');
|
|
29048
|
+
return;
|
|
29049
|
+
}
|
|
29050
|
+
pendingInitializeArgs = args;
|
|
29051
|
+
let stopVisibilityListener = attachEvent(document, 'visibilitychange', () => {
|
|
29052
|
+
if (document.visibilityState !== 'visible')
|
|
29053
|
+
return;
|
|
29054
|
+
if (stopVisibilityListener) {
|
|
29055
|
+
stopVisibilityListener();
|
|
29056
|
+
stopVisibilityListener = null;
|
|
29057
|
+
}
|
|
29058
|
+
const pendingArgs = pendingInitializeArgs;
|
|
29059
|
+
pendingInitializeArgs = null;
|
|
29060
|
+
initialize.apply(null, pendingArgs);
|
|
29061
|
+
});
|
|
29062
|
+
teardownFns.push(() => {
|
|
29063
|
+
if (stopVisibilityListener) {
|
|
29064
|
+
stopVisibilityListener();
|
|
29065
|
+
stopVisibilityListener = null;
|
|
29066
|
+
}
|
|
29067
|
+
pendingInitializeArgs = null;
|
|
29068
|
+
});
|
|
29069
|
+
}
|
|
29019
29070
|
/**
|
|
29020
29071
|
* Initializes the Pendo Web SDK in a browser window. This function only needs to be called once per page load. Any subsequent calls, without first having called `teardown`, will be ignored.
|
|
29021
29072
|
* Once the web SDK has been initialized, any updates to identity or metadata should be done using `identify` or `updateOptions`.
|
|
@@ -29048,8 +29099,16 @@ const initializeImmediately = 'initializeImmediately';
|
|
|
29048
29099
|
}
|
|
29049
29100
|
});
|
|
29050
29101
|
*/
|
|
29051
|
-
const teardownFns = [];
|
|
29052
29102
|
function initialize(options) {
|
|
29103
|
+
if (shouldGateOnVisibility()) {
|
|
29104
|
+
try {
|
|
29105
|
+
gateInitializeOnVisibility(_.toArray(arguments));
|
|
29106
|
+
}
|
|
29107
|
+
catch (e) {
|
|
29108
|
+
log.critical('pendo.initialize failed while gating on visibility.', e);
|
|
29109
|
+
}
|
|
29110
|
+
return;
|
|
29111
|
+
}
|
|
29053
29112
|
if (document.readyState !== 'complete' && !(_.get(options, initializeImmediately) || ConfigReader.get(initializeImmediately))) {
|
|
29054
29113
|
try {
|
|
29055
29114
|
enqueueCall(pendo$1, 'initialize', arguments);
|
|
@@ -29303,9 +29362,7 @@ function startup(callQueue, autoInitialize) {
|
|
|
29303
29362
|
autoInitialize();
|
|
29304
29363
|
}
|
|
29305
29364
|
else {
|
|
29306
|
-
teardownFns.push(whenLoadedCall(
|
|
29307
|
-
teardownFns.push(whenVisibleCall(autoInitialize));
|
|
29308
|
-
}));
|
|
29365
|
+
teardownFns.push(whenLoadedCall(autoInitialize));
|
|
29309
29366
|
}
|
|
29310
29367
|
}
|
|
29311
29368
|
/**
|
|
@@ -40212,364 +40269,6 @@ class DOMPrompt {
|
|
|
40212
40269
|
}
|
|
40213
40270
|
}
|
|
40214
40271
|
|
|
40215
|
-
const ASSISTANT_MESSAGE = 'assistantMessage';
|
|
40216
|
-
const CONVERSATION_ID_URL_PATTERN = 'conversationIdUrlPattern';
|
|
40217
|
-
const MESSAGE_ID_ATTR = 'messageIdAttr';
|
|
40218
|
-
const MODEL_USED_ATTR = 'modelUsedAttr';
|
|
40219
|
-
const REACTION_ACTIVE = 'reactionActive';
|
|
40220
|
-
const STREAMING_ACTIVE = 'streamingActive';
|
|
40221
|
-
const STREAMING_ACTIVE_ATTR = 'streamingActiveAttr';
|
|
40222
|
-
const THUMB_DOWN = 'thumbDown';
|
|
40223
|
-
const THUMB_UP = 'thumbUp';
|
|
40224
|
-
const TURN_CONTAINER = 'turnContainer';
|
|
40225
|
-
const TURN_ATTR = 'turnAttr';
|
|
40226
|
-
const USER_MESSAGE = 'userMessage';
|
|
40227
|
-
const CUSTOM_AGENT_ID_URL_PATTERN = 'customAgentIdUrlPattern';
|
|
40228
|
-
const CUSTOM_AGENT_NAME = 'customAgentName';
|
|
40229
|
-
const REQUIRED_SELECTORS = [
|
|
40230
|
-
ASSISTANT_MESSAGE,
|
|
40231
|
-
CONVERSATION_ID_URL_PATTERN,
|
|
40232
|
-
MESSAGE_ID_ATTR,
|
|
40233
|
-
STREAMING_ACTIVE,
|
|
40234
|
-
TURN_CONTAINER,
|
|
40235
|
-
TURN_ATTR,
|
|
40236
|
-
USER_MESSAGE
|
|
40237
|
-
];
|
|
40238
|
-
const STREAMING_END_SETTLE_MS = 500;
|
|
40239
|
-
const SUBMISSION_START_RETRY_MS = 1000;
|
|
40240
|
-
const SUBMISSION_START_MAX_ATTEMPTS = 4;
|
|
40241
|
-
class DOMConversation {
|
|
40242
|
-
// Returns the list of required selector types that are missing or empty
|
|
40243
|
-
// in the given cssSelectors config. An empty array means the config is
|
|
40244
|
-
// valid for instantiation.
|
|
40245
|
-
static validateConfig(cssSelectors) {
|
|
40246
|
-
if (!Array.isArray(cssSelectors)) {
|
|
40247
|
-
return REQUIRED_SELECTORS.slice();
|
|
40248
|
-
}
|
|
40249
|
-
const present = new Set();
|
|
40250
|
-
for (const cfg of cssSelectors) {
|
|
40251
|
-
if (!cfg || !cfg.type || !cfg.cssSelector)
|
|
40252
|
-
continue;
|
|
40253
|
-
if (cfg.type === CONVERSATION_ID_URL_PATTERN) {
|
|
40254
|
-
try {
|
|
40255
|
-
RegExp(cfg.cssSelector);
|
|
40256
|
-
}
|
|
40257
|
-
catch (e) {
|
|
40258
|
-
continue;
|
|
40259
|
-
}
|
|
40260
|
-
}
|
|
40261
|
-
present.add(cfg.type);
|
|
40262
|
-
}
|
|
40263
|
-
return REQUIRED_SELECTORS.filter((r) => !present.has(r));
|
|
40264
|
-
}
|
|
40265
|
-
static supportedPreset(preset) {
|
|
40266
|
-
return preset === 'chatgpt-full';
|
|
40267
|
-
}
|
|
40268
|
-
constructor(pendo, PluginAPI, id, privacyFilters, cssSelectors) {
|
|
40269
|
-
this.selectors = {};
|
|
40270
|
-
this.listeners = [];
|
|
40271
|
-
this.isActive = true;
|
|
40272
|
-
this.observers = [];
|
|
40273
|
-
this.wasStreaming = false;
|
|
40274
|
-
this.streamingEndTimer = null;
|
|
40275
|
-
this.submissionStartRetryTimer = null;
|
|
40276
|
-
this.requestNode = null;
|
|
40277
|
-
this.conversationIdRegex = null;
|
|
40278
|
-
this.customAgentIdRegex = null;
|
|
40279
|
-
this.lastReturnedMessageId = null;
|
|
40280
|
-
this.dom = pendo.dom;
|
|
40281
|
-
this._ = pendo._;
|
|
40282
|
-
this.api = PluginAPI;
|
|
40283
|
-
this.Sizzle = pendo.Sizzle;
|
|
40284
|
-
this.id = id;
|
|
40285
|
-
this.setFilters(privacyFilters);
|
|
40286
|
-
if (!this._.isArray(cssSelectors)) {
|
|
40287
|
-
this.api.log.error(`cssSelectors must be an array, received: ${typeof cssSelectors}`);
|
|
40288
|
-
cssSelectors = [];
|
|
40289
|
-
}
|
|
40290
|
-
this._.each(cssSelectors, (cfg) => {
|
|
40291
|
-
if (cfg && cfg.type) {
|
|
40292
|
-
this.selectors[cfg.type] = cfg.cssSelector;
|
|
40293
|
-
}
|
|
40294
|
-
});
|
|
40295
|
-
this.conversationIdRegex = new RegExp(this.selectors[CONVERSATION_ID_URL_PATTERN]);
|
|
40296
|
-
const customAgentIdUrlPattern = this.selectors[CUSTOM_AGENT_ID_URL_PATTERN];
|
|
40297
|
-
if (customAgentIdUrlPattern) { // this is optional
|
|
40298
|
-
try {
|
|
40299
|
-
this.customAgentIdRegex = new RegExp(customAgentIdUrlPattern);
|
|
40300
|
-
}
|
|
40301
|
-
catch (error) {
|
|
40302
|
-
this.api.log.error(`bad customAgentIdUrlPattern ${customAgentIdUrlPattern}`, { error });
|
|
40303
|
-
}
|
|
40304
|
-
}
|
|
40305
|
-
this.root = document.body;
|
|
40306
|
-
this.setupReactionListener();
|
|
40307
|
-
this.setupStreamingObserver();
|
|
40308
|
-
}
|
|
40309
|
-
setupReactionListener() {
|
|
40310
|
-
if (!this.findSelector(THUMB_UP) && !this.findSelector(THUMB_DOWN))
|
|
40311
|
-
return;
|
|
40312
|
-
this.reactionClickHandler = this.handleReactionClick.bind(this);
|
|
40313
|
-
this.root.addEventListener('click', this.reactionClickHandler, true);
|
|
40314
|
-
}
|
|
40315
|
-
handleReactionClick(evt) {
|
|
40316
|
-
const target = evt.target;
|
|
40317
|
-
if (!target || target.nodeType !== 1)
|
|
40318
|
-
return;
|
|
40319
|
-
const upSelector = this.findSelector(THUMB_UP);
|
|
40320
|
-
const downSelector = this.findSelector(THUMB_DOWN);
|
|
40321
|
-
const thumb = this.dom(target).closest(`${upSelector}, ${downSelector}`);
|
|
40322
|
-
if (!thumb.length)
|
|
40323
|
-
return;
|
|
40324
|
-
const isUp = this.Sizzle.matchesSelector(thumb[0], upSelector);
|
|
40325
|
-
const activeSelector = this.findSelector(REACTION_ACTIVE);
|
|
40326
|
-
const wasPressed = activeSelector && this.Sizzle.matchesSelector(thumb[0], activeSelector);
|
|
40327
|
-
const direction = isUp ? 'positive' : 'negative';
|
|
40328
|
-
const content = wasPressed ? 'unreact' : direction;
|
|
40329
|
-
const assistantNode = thumb.closest(this.findSelector(TURN_CONTAINER))
|
|
40330
|
-
.find(this.findSelector(ASSISTANT_MESSAGE));
|
|
40331
|
-
this.emit('user_reaction', {
|
|
40332
|
-
agentId: this.id,
|
|
40333
|
-
messageId: this.getMessageId(assistantNode),
|
|
40334
|
-
content,
|
|
40335
|
-
privacyFilterApplied: false
|
|
40336
|
-
});
|
|
40337
|
-
}
|
|
40338
|
-
// observe the streaming indicator
|
|
40339
|
-
setupStreamingObserver() {
|
|
40340
|
-
this.wasStreaming = this.select(STREAMING_ACTIVE).length > 0;
|
|
40341
|
-
this.stopStreamingEndTimer();
|
|
40342
|
-
const MutationObserver = getZoneSafeMethod('MutationObserver');
|
|
40343
|
-
const observer = new MutationObserver(this.handleMutation.bind(this));
|
|
40344
|
-
const attrName = this.findSelector(STREAMING_ACTIVE_ATTR);
|
|
40345
|
-
observer.observe(this.root, {
|
|
40346
|
-
childList: true,
|
|
40347
|
-
subtree: true,
|
|
40348
|
-
attributes: true,
|
|
40349
|
-
attributeFilter: attrName ? [attrName] : undefined
|
|
40350
|
-
});
|
|
40351
|
-
this.observers.push(observer);
|
|
40352
|
-
}
|
|
40353
|
-
// look for changes in the state of the streaming indicator.
|
|
40354
|
-
// streaming started -> a prompt has been submitted
|
|
40355
|
-
// streaming ended -> got a response
|
|
40356
|
-
// we don't send the prompt immediately when it's submitted because it might not have a
|
|
40357
|
-
// conversation id yet.
|
|
40358
|
-
// we don't send the agent_response immediately when the streaming indicator is cleared
|
|
40359
|
-
// because it clears slightly before the final text chunk is committed to the DOM so the
|
|
40360
|
-
// end-handling is deferred by a short settle window
|
|
40361
|
-
handleMutation() {
|
|
40362
|
-
const isStreaming = this.select(STREAMING_ACTIVE).length > 0;
|
|
40363
|
-
if (isStreaming === this.wasStreaming)
|
|
40364
|
-
return;
|
|
40365
|
-
if (isStreaming) { // started streaming
|
|
40366
|
-
if (!this.streamingEndTimer) {
|
|
40367
|
-
this.onSubmissionStart();
|
|
40368
|
-
}
|
|
40369
|
-
else {
|
|
40370
|
-
// stream restarted during the settle window (multi-phase response).
|
|
40371
|
-
// treat as a continuation of the prior request, not a new submission.
|
|
40372
|
-
// we'll handle it next time streaming stops
|
|
40373
|
-
this.stopStreamingEndTimer();
|
|
40374
|
-
}
|
|
40375
|
-
}
|
|
40376
|
-
else { // finished streaming
|
|
40377
|
-
this.startStreamingEndTimer();
|
|
40378
|
-
}
|
|
40379
|
-
this.wasStreaming = isStreaming;
|
|
40380
|
-
}
|
|
40381
|
-
onSubmissionStart(attempt = 1) {
|
|
40382
|
-
this.requestNode = this.findLastRequestNode();
|
|
40383
|
-
if (this.requestNode) {
|
|
40384
|
-
this.handleUserMessage(this.requestNode);
|
|
40385
|
-
return;
|
|
40386
|
-
}
|
|
40387
|
-
// URL hasn't flipped yet to include the conversation id on a fresh chat
|
|
40388
|
-
// retry, if that still fails, onSubmissionEnd handles it
|
|
40389
|
-
if (attempt < SUBMISSION_START_MAX_ATTEMPTS) {
|
|
40390
|
-
this.startSubmissionStartRetryTimer(attempt + 1);
|
|
40391
|
-
}
|
|
40392
|
-
}
|
|
40393
|
-
onSubmissionEnd() {
|
|
40394
|
-
this.stopSubmissionStartRetryTimer();
|
|
40395
|
-
let requestNode = this.requestNode;
|
|
40396
|
-
this.requestNode = null;
|
|
40397
|
-
if (!requestNode) {
|
|
40398
|
-
// onSubmissionStart didn't send, send it now
|
|
40399
|
-
requestNode = this.findLastRequestNode();
|
|
40400
|
-
if (!requestNode)
|
|
40401
|
-
return;
|
|
40402
|
-
this.handleUserMessage(requestNode);
|
|
40403
|
-
}
|
|
40404
|
-
const requestTurn = this.findTurnNumber(requestNode);
|
|
40405
|
-
if (requestTurn === null)
|
|
40406
|
-
return;
|
|
40407
|
-
const assistantNodes = this.select(ASSISTANT_MESSAGE);
|
|
40408
|
-
const toEmit = [];
|
|
40409
|
-
for (let i = assistantNodes.length - 1; i >= 0; i--) {
|
|
40410
|
-
const n = this.findTurnNumber(this.dom(assistantNodes[i]));
|
|
40411
|
-
if (n === null)
|
|
40412
|
-
continue;
|
|
40413
|
-
if (n <= requestTurn)
|
|
40414
|
-
break;
|
|
40415
|
-
toEmit.push(assistantNodes[i]);
|
|
40416
|
-
}
|
|
40417
|
-
// emit in chronological order (reverse of collection order)
|
|
40418
|
-
for (let i = toEmit.length - 1; i >= 0; i--) {
|
|
40419
|
-
this.handleAssistantMessage(this.dom(toEmit[i]));
|
|
40420
|
-
}
|
|
40421
|
-
}
|
|
40422
|
-
extractContent(node) {
|
|
40423
|
-
const rawContent = node.text().trim();
|
|
40424
|
-
const content = this.applyPrivacyFilter(rawContent);
|
|
40425
|
-
return { content, privacyFilterApplied: content !== rawContent };
|
|
40426
|
-
}
|
|
40427
|
-
getMessageId(node) {
|
|
40428
|
-
return node.attr(this.findSelector(MESSAGE_ID_ATTR));
|
|
40429
|
-
}
|
|
40430
|
-
handleUserMessage(node) {
|
|
40431
|
-
this.emit('prompt', Object.assign({ agentId: this.id, messageId: this.getMessageId(node) }, this.extractContent(node)));
|
|
40432
|
-
}
|
|
40433
|
-
handleAssistantMessage(node) {
|
|
40434
|
-
const modelUsedAttr = this.findSelector(MODEL_USED_ATTR);
|
|
40435
|
-
const modelUsed = modelUsedAttr && node.attr(modelUsedAttr);
|
|
40436
|
-
this.emit('agent_response', Object.assign({ agentId: this.id, messageId: this.getMessageId(node), agentModelsUsed: modelUsed ? [modelUsed] : [] }, this.extractContent(node)));
|
|
40437
|
-
}
|
|
40438
|
-
findLastRequestNode() {
|
|
40439
|
-
if (!this.getConversationId())
|
|
40440
|
-
return null;
|
|
40441
|
-
const node = this._.last(this.select(USER_MESSAGE));
|
|
40442
|
-
if (!node)
|
|
40443
|
-
return null;
|
|
40444
|
-
const $node = this.dom(node);
|
|
40445
|
-
const messageId = this.getMessageId($node);
|
|
40446
|
-
if (!messageId)
|
|
40447
|
-
return null;
|
|
40448
|
-
if (messageId === this.lastReturnedMessageId)
|
|
40449
|
-
return null;
|
|
40450
|
-
this.lastReturnedMessageId = messageId;
|
|
40451
|
-
return $node;
|
|
40452
|
-
}
|
|
40453
|
-
findTurnNumber(node) {
|
|
40454
|
-
const turnSelector = this.findSelector(TURN_CONTAINER);
|
|
40455
|
-
const turnAttr = this.findSelector(TURN_ATTR);
|
|
40456
|
-
const turn = node.closest(turnSelector).attr(turnAttr);
|
|
40457
|
-
if (!turn)
|
|
40458
|
-
return null;
|
|
40459
|
-
const seqMatch = String(turn).match(/\d+/);
|
|
40460
|
-
return seqMatch ? parseInt(seqMatch[0], 10) : null;
|
|
40461
|
-
}
|
|
40462
|
-
findSelector(type) {
|
|
40463
|
-
return this.selectors[type];
|
|
40464
|
-
}
|
|
40465
|
-
select(type) {
|
|
40466
|
-
return this.dom(this.findSelector(type), this.root);
|
|
40467
|
-
}
|
|
40468
|
-
getConversationId() {
|
|
40469
|
-
const m = location.href.match(this.conversationIdRegex);
|
|
40470
|
-
if (!m)
|
|
40471
|
-
return null;
|
|
40472
|
-
return m[1] !== undefined ? m[1] : m[0];
|
|
40473
|
-
}
|
|
40474
|
-
getCustomAgentId() {
|
|
40475
|
-
if (!this.customAgentIdRegex)
|
|
40476
|
-
return undefined;
|
|
40477
|
-
const m = location.href.match(this.customAgentIdRegex);
|
|
40478
|
-
if (!m)
|
|
40479
|
-
return undefined;
|
|
40480
|
-
return m[1] !== undefined ? m[1] : m[0];
|
|
40481
|
-
}
|
|
40482
|
-
getCustomAgentName() {
|
|
40483
|
-
if (!this.findSelector(CUSTOM_AGENT_NAME))
|
|
40484
|
-
return '';
|
|
40485
|
-
const node = this.select(CUSTOM_AGENT_NAME);
|
|
40486
|
-
if (!node.length)
|
|
40487
|
-
return '';
|
|
40488
|
-
return node.text().trim();
|
|
40489
|
-
}
|
|
40490
|
-
addCustomAgentInfo(eventPayload) {
|
|
40491
|
-
const customAgentId = this.getCustomAgentId();
|
|
40492
|
-
if (!customAgentId)
|
|
40493
|
-
return;
|
|
40494
|
-
eventPayload.customAgentId = customAgentId;
|
|
40495
|
-
const customAgentName = this.getCustomAgentName();
|
|
40496
|
-
if (customAgentName) {
|
|
40497
|
-
eventPayload.customAgentName = customAgentName;
|
|
40498
|
-
}
|
|
40499
|
-
}
|
|
40500
|
-
setFilters(candidateFilter) {
|
|
40501
|
-
if (!candidateFilter) {
|
|
40502
|
-
this.privacyFilters = null;
|
|
40503
|
-
return null;
|
|
40504
|
-
}
|
|
40505
|
-
try {
|
|
40506
|
-
this.privacyFilters = new RegExp(candidateFilter, 'gmi');
|
|
40507
|
-
}
|
|
40508
|
-
catch (e) {
|
|
40509
|
-
this.privacyFilters = null;
|
|
40510
|
-
this.api.log.error(e);
|
|
40511
|
-
}
|
|
40512
|
-
return this.privacyFilters;
|
|
40513
|
-
}
|
|
40514
|
-
applyPrivacyFilter(candidateValue, filters = null) {
|
|
40515
|
-
const filtersToUse = filters || this.privacyFilters;
|
|
40516
|
-
if (!filtersToUse || !this._.isRegExp(filtersToUse))
|
|
40517
|
-
return candidateValue;
|
|
40518
|
-
return candidateValue.replace(filtersToUse, 'redacted');
|
|
40519
|
-
}
|
|
40520
|
-
onSubmit(callback) {
|
|
40521
|
-
this.listeners.push(callback);
|
|
40522
|
-
}
|
|
40523
|
-
emit(eventType, eventPayload) {
|
|
40524
|
-
eventPayload.conversationId = this.getConversationId();
|
|
40525
|
-
this.addCustomAgentInfo(eventPayload);
|
|
40526
|
-
this._.each(this.listeners, (cb) => cb(eventType, eventPayload));
|
|
40527
|
-
}
|
|
40528
|
-
startStreamingEndTimer() {
|
|
40529
|
-
this.stopStreamingEndTimer();
|
|
40530
|
-
this.streamingEndTimer = setTimeout$1(() => {
|
|
40531
|
-
this.streamingEndTimer = null;
|
|
40532
|
-
this.onSubmissionEnd();
|
|
40533
|
-
}, STREAMING_END_SETTLE_MS);
|
|
40534
|
-
}
|
|
40535
|
-
stopStreamingEndTimer() {
|
|
40536
|
-
if (!this.streamingEndTimer)
|
|
40537
|
-
return;
|
|
40538
|
-
clearTimeout(this.streamingEndTimer);
|
|
40539
|
-
this.streamingEndTimer = null;
|
|
40540
|
-
}
|
|
40541
|
-
startSubmissionStartRetryTimer(attempt) {
|
|
40542
|
-
this.stopSubmissionStartRetryTimer();
|
|
40543
|
-
this.submissionStartRetryTimer = setTimeout$1(() => {
|
|
40544
|
-
this.submissionStartRetryTimer = null;
|
|
40545
|
-
this.onSubmissionStart(attempt);
|
|
40546
|
-
}, SUBMISSION_START_RETRY_MS);
|
|
40547
|
-
}
|
|
40548
|
-
stopSubmissionStartRetryTimer() {
|
|
40549
|
-
if (!this.submissionStartRetryTimer)
|
|
40550
|
-
return;
|
|
40551
|
-
clearTimeout(this.submissionStartRetryTimer);
|
|
40552
|
-
this.submissionStartRetryTimer = null;
|
|
40553
|
-
}
|
|
40554
|
-
suspend() {
|
|
40555
|
-
this.isActive = false;
|
|
40556
|
-
}
|
|
40557
|
-
resume() {
|
|
40558
|
-
this.isActive = true;
|
|
40559
|
-
}
|
|
40560
|
-
teardown() {
|
|
40561
|
-
this._.each(this.observers, (o) => o && o.disconnect && o.disconnect());
|
|
40562
|
-
this.observers = [];
|
|
40563
|
-
if (this.reactionClickHandler && this.root) {
|
|
40564
|
-
this.root.removeEventListener('click', this.reactionClickHandler, true);
|
|
40565
|
-
this.reactionClickHandler = null;
|
|
40566
|
-
}
|
|
40567
|
-
this.stopStreamingEndTimer();
|
|
40568
|
-
this.stopSubmissionStartRetryTimer();
|
|
40569
|
-
this.listeners = [];
|
|
40570
|
-
}
|
|
40571
|
-
}
|
|
40572
|
-
|
|
40573
40272
|
/*
|
|
40574
40273
|
* Prompt Analytics Plugin
|
|
40575
40274
|
*
|
|
@@ -40654,6 +40353,9 @@ class PromptPlugin {
|
|
|
40654
40353
|
});
|
|
40655
40354
|
const currentlyActiveIds = this._.map(this._.filter(this.prompts, prompt => prompt.isActive), prompt => prompt.id);
|
|
40656
40355
|
this._.each(allAgents, aiAgent => {
|
|
40356
|
+
if (this.isConversationAgent(aiAgent)) {
|
|
40357
|
+
return;
|
|
40358
|
+
}
|
|
40657
40359
|
const isCurrentlyActive = this._.contains(currentlyActiveIds, aiAgent.id);
|
|
40658
40360
|
const shouldBeActive = this.testPageRule(aiAgent.pageRule, currentUrl, aiAgent.id);
|
|
40659
40361
|
if (shouldBeActive && !isCurrentlyActive) {
|
|
@@ -40672,6 +40374,10 @@ class PromptPlugin {
|
|
|
40672
40374
|
return candidateValue;
|
|
40673
40375
|
return candidateValue.replace(filters, 'redacted');
|
|
40674
40376
|
}
|
|
40377
|
+
// conversation agents, owned by the ConversationAnalytics plugin.
|
|
40378
|
+
isConversationAgent(agent) {
|
|
40379
|
+
return agent.preset && agent.preset != 'chatgpt';
|
|
40380
|
+
}
|
|
40675
40381
|
onConfigLoaded(aiAgents = []) {
|
|
40676
40382
|
if (!aiAgents || !this._.isArray(aiAgents) || aiAgents.length === 0) {
|
|
40677
40383
|
return;
|
|
@@ -40679,6 +40385,9 @@ class PromptPlugin {
|
|
|
40679
40385
|
const networkAgents = [];
|
|
40680
40386
|
const domAgents = [];
|
|
40681
40387
|
for (const agent of aiAgents) {
|
|
40388
|
+
if (this.isConversationAgent(agent)) {
|
|
40389
|
+
continue;
|
|
40390
|
+
}
|
|
40682
40391
|
if (agent.trackingMethod === 'network') {
|
|
40683
40392
|
networkAgents.push(agent);
|
|
40684
40393
|
}
|
|
@@ -40734,25 +40443,12 @@ class PromptPlugin {
|
|
|
40734
40443
|
}
|
|
40735
40444
|
}
|
|
40736
40445
|
observePrompt(config) {
|
|
40737
|
-
const { id, cssSelectors, privacyFilters
|
|
40446
|
+
const { id, cssSelectors, privacyFilters } = config;
|
|
40738
40447
|
// Check if agent already exists
|
|
40739
40448
|
const existingPrompt = this._.find(this.prompts, prompt => prompt.id === id);
|
|
40740
40449
|
if (existingPrompt) {
|
|
40741
40450
|
return;
|
|
40742
40451
|
}
|
|
40743
|
-
if (DOMConversation.supportedPreset(preset)) {
|
|
40744
|
-
const missing = DOMConversation.validateConfig(cssSelectors);
|
|
40745
|
-
if (missing.length) {
|
|
40746
|
-
this.api.log.error('aiAgent config missing required selectors', { agentId: id, missing });
|
|
40747
|
-
return;
|
|
40748
|
-
}
|
|
40749
|
-
const conversation = new DOMConversation(this.pendo, this.api, id, privacyFilters, cssSelectors);
|
|
40750
|
-
conversation.onSubmit((eventType, payload) => {
|
|
40751
|
-
this.sendConversationEvent(eventType, payload);
|
|
40752
|
-
});
|
|
40753
|
-
this.prompts.push(conversation);
|
|
40754
|
-
return;
|
|
40755
|
-
}
|
|
40756
40452
|
let inputCssSelectors, submitCssSelectors;
|
|
40757
40453
|
inputCssSelectors = this.parseCssSelector('input', cssSelectors);
|
|
40758
40454
|
submitCssSelectors = this.parseCssSelector('submit', cssSelectors);
|
|
@@ -40779,15 +40475,6 @@ class PromptPlugin {
|
|
|
40779
40475
|
}, promptEvent);
|
|
40780
40476
|
this.api.analytics.collectEvent('prompt', event, undefined, 'agentic');
|
|
40781
40477
|
}
|
|
40782
|
-
sendConversationEvent(eventType, eventPayload) {
|
|
40783
|
-
// Block event if the prompt is suspended
|
|
40784
|
-
const conv = this._.find(this.prompts, p => p.id === eventPayload.agentId);
|
|
40785
|
-
if (conv && !conv.isActive) {
|
|
40786
|
-
return;
|
|
40787
|
-
}
|
|
40788
|
-
eventPayload = this._.extend({ agentType: 'conversation' }, eventPayload);
|
|
40789
|
-
this.api.analytics.collectEvent(eventType, eventPayload, undefined, 'agentic');
|
|
40790
|
-
}
|
|
40791
40478
|
teardown() {
|
|
40792
40479
|
this._.each(this.prompts, (prompt) => prompt.teardown());
|
|
40793
40480
|
if (this.agentsCache) {
|
|
@@ -41174,10 +40861,7 @@ class WebAnalytics {
|
|
|
41174
40861
|
PluginAPI.attachEvent(PluginAPI.Events, 'eventCaptured', bind(this.addUtmToEvent, this)),
|
|
41175
40862
|
PluginAPI.attachEvent(PluginAPI.Events, 'sessionChanged', bind(this.sessionChanged, this))
|
|
41176
40863
|
];
|
|
41177
|
-
|
|
41178
|
-
if (!params || pendo._.isEmpty(params)) {
|
|
41179
|
-
params = this.extractParameters(window.location.href, document.referrer);
|
|
41180
|
-
}
|
|
40864
|
+
this.suffix = this.api.ConfigReader.get('identityStorageSuffix');
|
|
41181
40865
|
/**
|
|
41182
40866
|
* Stores UTM parameters that were present in the URL when the visitor loaded the application.
|
|
41183
40867
|
*
|
|
@@ -41186,9 +40870,12 @@ class WebAnalytics {
|
|
|
41186
40870
|
* @access public
|
|
41187
40871
|
* @label WEB_ANALYTICS_STORAGE_KEY
|
|
41188
40872
|
*/
|
|
41189
|
-
this.api.agentStorage.registry.addLocal(WEB_ANALYTICS_STORAGE_KEY);
|
|
40873
|
+
this.api.agentStorage.registry.addLocal(WEB_ANALYTICS_STORAGE_KEY, { cookieSuffix: this.suffix, isSecure: true });
|
|
40874
|
+
let params = this.loadParameters(PluginAPI.agentStorage);
|
|
40875
|
+
if (!params || pendo._.isEmpty(params)) {
|
|
40876
|
+
params = this.extractParameters(window.location.href, document.referrer);
|
|
40877
|
+
}
|
|
41190
40878
|
this.storeParameters(params, PluginAPI.agentStorage);
|
|
41191
|
-
this.suffix = this.api.ConfigReader.get('identityStorageSuffix');
|
|
41192
40879
|
}
|
|
41193
40880
|
extractParameters(url, referrer) {
|
|
41194
40881
|
const locationUrl = new URL(url);
|
|
@@ -41243,12 +40930,12 @@ class WebAnalytics {
|
|
|
41243
40930
|
}
|
|
41244
40931
|
storeParameters(params, storage) {
|
|
41245
40932
|
if (this.pendo._.size(params) > 0) {
|
|
41246
|
-
storage.write(WEB_ANALYTICS_STORAGE_KEY, JSON.stringify(params)
|
|
40933
|
+
storage.write(WEB_ANALYTICS_STORAGE_KEY, JSON.stringify(params));
|
|
41247
40934
|
}
|
|
41248
40935
|
}
|
|
41249
40936
|
loadParameters(storage) {
|
|
41250
|
-
const storedParamsJson = storage.read(WEB_ANALYTICS_STORAGE_KEY
|
|
41251
|
-
storage.read(WEB_ANALYTICS_STORAGE_KEY);
|
|
40937
|
+
const storedParamsJson = storage.read(WEB_ANALYTICS_STORAGE_KEY) ||
|
|
40938
|
+
storage.read(WEB_ANALYTICS_STORAGE_KEY, false, '');
|
|
41252
40939
|
if (storedParamsJson)
|
|
41253
40940
|
return JSON.parse(storedParamsJson);
|
|
41254
40941
|
return null;
|
|
@@ -41274,7 +40961,7 @@ class WebAnalytics {
|
|
|
41274
40961
|
sessionChanged() {
|
|
41275
40962
|
const agentStorage = this.api.agentStorage;
|
|
41276
40963
|
agentStorage.clear(WEB_ANALYTICS_STORAGE_KEY);
|
|
41277
|
-
agentStorage.clear(WEB_ANALYTICS_STORAGE_KEY, false,
|
|
40964
|
+
agentStorage.clear(WEB_ANALYTICS_STORAGE_KEY, false, '');
|
|
41278
40965
|
const params = this.extractParameters(window.location.href, document.referrer);
|
|
41279
40966
|
this.storeParameters(params, agentStorage);
|
|
41280
40967
|
}
|
|
@@ -41607,20 +41294,20 @@ function getZoneSafeMethod(_, method, target) {
|
|
|
41607
41294
|
}
|
|
41608
41295
|
|
|
41609
41296
|
// Does not support submit and go to
|
|
41610
|
-
|
|
41611
|
-
|
|
41297
|
+
const goToRegex = new RegExp(guideMarkdownUtil.goToString);
|
|
41298
|
+
const PollBranching = {
|
|
41612
41299
|
name: 'PollBranching',
|
|
41613
|
-
script
|
|
41614
|
-
|
|
41615
|
-
|
|
41300
|
+
script(step, guide, pendo) {
|
|
41301
|
+
let isAdvanceIntercepted = false;
|
|
41302
|
+
const branchingQuestions = initialBranchingSetup(step, pendo);
|
|
41616
41303
|
if (branchingQuestions) {
|
|
41617
41304
|
// If there are too many branching questions saved, exit and run the guide normally.
|
|
41618
41305
|
if (pendo._.size(branchingQuestions) > 1)
|
|
41619
41306
|
return;
|
|
41620
|
-
this.on('beforeAdvance',
|
|
41621
|
-
|
|
41622
|
-
|
|
41623
|
-
|
|
41307
|
+
this.on('beforeAdvance', (evt) => {
|
|
41308
|
+
const noResponseSelected = step.guideElement.find('[branching] .pendo-radio:checked').length === 0;
|
|
41309
|
+
const responseLabel = step.guideElement.find('[branching] .pendo-radio:checked + label')[0];
|
|
41310
|
+
let noGotoLabel;
|
|
41624
41311
|
if (responseLabel) {
|
|
41625
41312
|
noGotoLabel = pendo._.isNull(responseLabel.getAttribute('goToStep'));
|
|
41626
41313
|
}
|
|
@@ -41631,58 +41318,58 @@ var PollBranching = {
|
|
|
41631
41318
|
});
|
|
41632
41319
|
}
|
|
41633
41320
|
},
|
|
41634
|
-
test
|
|
41321
|
+
test(step, guide, pendo) {
|
|
41635
41322
|
var _a;
|
|
41636
|
-
|
|
41323
|
+
let branchingQuestions = (_a = step.guideElement) === null || _a === void 0 ? void 0 : _a.find('._pendo-multi-choice-poll-question:contains("{branching/}")');
|
|
41637
41324
|
return !pendo._.isUndefined(branchingQuestions) && pendo._.size(branchingQuestions);
|
|
41638
41325
|
},
|
|
41639
|
-
designerListener
|
|
41640
|
-
|
|
41641
|
-
|
|
41326
|
+
designerListener(pendo) {
|
|
41327
|
+
const target = pendo.dom.getBody();
|
|
41328
|
+
const config = {
|
|
41642
41329
|
attributeFilter: ['data-layout'],
|
|
41643
41330
|
attributes: true,
|
|
41644
41331
|
childList: true,
|
|
41645
41332
|
characterData: true,
|
|
41646
41333
|
subtree: true
|
|
41647
41334
|
};
|
|
41648
|
-
|
|
41649
|
-
|
|
41335
|
+
const MutationObserver = getZoneSafeMethod(pendo._, 'MutationObserver');
|
|
41336
|
+
const observer = new MutationObserver(applyBranchingIndicators);
|
|
41650
41337
|
observer.observe(target, config);
|
|
41651
41338
|
function applyBranchingIndicators(mutations) {
|
|
41652
41339
|
pendo._.each(mutations, function (mutation) {
|
|
41653
41340
|
var _a;
|
|
41654
|
-
|
|
41341
|
+
const nodeHasQuerySelector = pendo._.isFunction((_a = mutation.addedNodes[0]) === null || _a === void 0 ? void 0 : _a.querySelector);
|
|
41655
41342
|
if (mutation.addedNodes.length && nodeHasQuerySelector) {
|
|
41656
41343
|
if (mutation.addedNodes[0].querySelector('._pendo-multi-choice-poll-select-border')) {
|
|
41657
41344
|
if (pendo._.size(pendo.dom('._pendo-multi-choice-poll-question:contains("{branching/}")'))) {
|
|
41658
41345
|
pendo
|
|
41659
41346
|
.dom('._pendo-multi-choice-poll-question:contains("{branching/}")')
|
|
41660
|
-
.each(
|
|
41661
|
-
pendo._.each(pendo.dom(
|
|
41347
|
+
.each((question, index) => {
|
|
41348
|
+
pendo._.each(pendo.dom(`#${question.id} *`), (element) => {
|
|
41662
41349
|
guideMarkdownUtil.removeMarkdownSyntax(element, '{branching/}', '', pendo);
|
|
41663
41350
|
});
|
|
41664
41351
|
pendo
|
|
41665
|
-
.dom(
|
|
41352
|
+
.dom(`#${question.id} p`)
|
|
41666
41353
|
.css({ display: 'inline-block !important' })
|
|
41667
41354
|
.append(branchingIcon('#999', '20px'))
|
|
41668
41355
|
.attr({ title: 'Custom Branching Added' });
|
|
41669
|
-
|
|
41670
|
-
if (pendo.dom(
|
|
41356
|
+
let dataPendoPollId = question.getAttribute('data-pendo-poll-id');
|
|
41357
|
+
if (pendo.dom(`._pendo-multi-choice-poll-question[data-pendo-poll-id=${dataPendoPollId}]`)[0]) {
|
|
41671
41358
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
41672
41359
|
pendo
|
|
41673
|
-
.dom(
|
|
41360
|
+
.dom(`._pendo-multi-choice-poll-question[data-pendo-poll-id=${dataPendoPollId}]`)[0]
|
|
41674
41361
|
.textContent.trim();
|
|
41675
41362
|
}
|
|
41676
|
-
|
|
41363
|
+
let pollLabels = pendo.dom(`label[for*=${dataPendoPollId}]`);
|
|
41677
41364
|
if (pendo._.size(pollLabels)) {
|
|
41678
|
-
pendo._.forEach(pollLabels,
|
|
41365
|
+
pendo._.forEach(pollLabels, (label) => {
|
|
41679
41366
|
if (goToRegex.test(label.textContent)) {
|
|
41680
|
-
|
|
41367
|
+
let labelTitle = goToRegex.exec(label.textContent)[2];
|
|
41681
41368
|
guideMarkdownUtil.removeMarkdownSyntax(label, goToRegex, '', pendo);
|
|
41682
41369
|
pendo
|
|
41683
41370
|
.dom(label)
|
|
41684
41371
|
.append(branchingIcon('#999', '14px'))
|
|
41685
|
-
.attr({ title:
|
|
41372
|
+
.attr({ title: `Branching to step ${labelTitle}` });
|
|
41686
41373
|
}
|
|
41687
41374
|
});
|
|
41688
41375
|
}
|
|
@@ -41690,9 +41377,9 @@ var PollBranching = {
|
|
|
41690
41377
|
pendo
|
|
41691
41378
|
.dom(question)
|
|
41692
41379
|
.append(branchingErrorHTML(question.dataset.pendoPollId));
|
|
41693
|
-
pendo.dom(
|
|
41380
|
+
pendo.dom(`#${question.id} #pendo-ps-branching-svg`).remove();
|
|
41694
41381
|
pendo
|
|
41695
|
-
.dom(
|
|
41382
|
+
.dom(`#${question.id} p`)
|
|
41696
41383
|
.css({ display: 'inline-block !important' })
|
|
41697
41384
|
.append(branchingIcon('red', '20px'))
|
|
41698
41385
|
.attr({ title: 'Unsupported Branching configuration' });
|
|
@@ -41704,31 +41391,49 @@ var PollBranching = {
|
|
|
41704
41391
|
});
|
|
41705
41392
|
}
|
|
41706
41393
|
function branchingErrorHTML(dataPendoPollId) {
|
|
41707
|
-
return
|
|
41394
|
+
return `<div style="text-align:lrft; font-size: 14px; color: red;
|
|
41395
|
+
font-style: italic; margin-top: 0px;" class="branching-wrapper"
|
|
41396
|
+
name="${dataPendoPollId}">
|
|
41397
|
+
* Branching Error: Multiple branching polls not supported</div>`;
|
|
41708
41398
|
}
|
|
41709
41399
|
function branchingIcon(color, size) {
|
|
41710
|
-
return
|
|
41400
|
+
return `<svg id="pendo-ps-branching-svg" viewBox="0 0 24 24" fill="none"
|
|
41401
|
+
style="margin-left: 5px;
|
|
41402
|
+
height:${size}; width:${size}; display:inline; vertical-align:middle;" xmlns="http://www.w3.org/2000/svg">
|
|
41403
|
+
<g stroke-width="0"></g>
|
|
41404
|
+
<g stroke-linecap="round" stroke-linejoin="round"></g>
|
|
41405
|
+
<g> <circle cx="4" cy="7" r="2" stroke="${color}"
|
|
41406
|
+
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></circle>
|
|
41407
|
+
<circle cx="20" cy="7" r="2" stroke="${color}"
|
|
41408
|
+
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></circle>
|
|
41409
|
+
<circle cx="20" cy="17" r="2" stroke="${color}" stroke-width="2"
|
|
41410
|
+
stroke-linecap="round" stroke-linejoin="round"></circle>
|
|
41411
|
+
<path d="M18 7H6" stroke="${color}" stroke-width="2"
|
|
41412
|
+
stroke-linecap="round" stroke-linejoin="round"></path>
|
|
41413
|
+
<path d="M7 7V7C8.65685 7 10 8.34315 10 10V15C10 16.1046 10.8954 17 12 17H18"
|
|
41414
|
+
stroke="${color}" stroke-width="2" stroke-linecap="round"
|
|
41415
|
+
stroke-linejoin="round"></path> </g></svg>`;
|
|
41711
41416
|
}
|
|
41712
41417
|
}
|
|
41713
41418
|
};
|
|
41714
41419
|
function initialBranchingSetup(step, pendo) {
|
|
41715
|
-
|
|
41716
|
-
pendo._.forEach(questions,
|
|
41717
|
-
|
|
41718
|
-
pendo._.each(step.guideElement.find(
|
|
41420
|
+
const questions = step.guideElement.find('._pendo-multi-choice-poll-question:contains("{branching/}")');
|
|
41421
|
+
pendo._.forEach(questions, (question) => {
|
|
41422
|
+
let dataPendoPollId = question.getAttribute('data-pendo-poll-id');
|
|
41423
|
+
pendo._.each(step.guideElement.find(`#${question.id} *`), (element) => {
|
|
41719
41424
|
guideMarkdownUtil.removeMarkdownSyntax(element, '{branching/}', '', pendo);
|
|
41720
41425
|
});
|
|
41721
|
-
|
|
41722
|
-
pendo._.forEach(pollLabels,
|
|
41426
|
+
let pollLabels = step.guideElement.find(`label[for*=${dataPendoPollId}]`);
|
|
41427
|
+
pendo._.forEach(pollLabels, (label) => {
|
|
41723
41428
|
if (pendo._.isNull(goToRegex.exec(label.textContent))) {
|
|
41724
41429
|
return;
|
|
41725
41430
|
}
|
|
41726
|
-
|
|
41727
|
-
|
|
41431
|
+
let gotoSubstring = goToRegex.exec(label.textContent)[1];
|
|
41432
|
+
let gotoIndex = goToRegex.exec(label.textContent)[2];
|
|
41728
41433
|
label.setAttribute('goToStep', gotoIndex);
|
|
41729
41434
|
guideMarkdownUtil.removeMarkdownSyntax(label, gotoSubstring, '', pendo);
|
|
41730
41435
|
});
|
|
41731
|
-
|
|
41436
|
+
let pollChoiceContainer = step.guideElement.find(`[data-pendo-poll-id=${dataPendoPollId}]._pendo-multi-choice-poll-select-border`);
|
|
41732
41437
|
if (pollChoiceContainer && pollChoiceContainer.length) {
|
|
41733
41438
|
pollChoiceContainer[0].setAttribute('branching', '');
|
|
41734
41439
|
}
|
|
@@ -41737,24 +41442,39 @@ function initialBranchingSetup(step, pendo) {
|
|
|
41737
41442
|
}
|
|
41738
41443
|
function branchingGoToStep(event, step, guide, pendo) {
|
|
41739
41444
|
var _a;
|
|
41740
|
-
|
|
41741
|
-
|
|
41742
|
-
|
|
41743
|
-
|
|
41445
|
+
let checkedPollInputId = (_a = step.guideElement.find('[branching] input.pendo-radio[data-pendo-poll-id]:checked')[0]) === null || _a === void 0 ? void 0 : _a.id;
|
|
41446
|
+
let checkedPollLabel = step.guideElement.find(`label[for="${checkedPollInputId}"]`)[0];
|
|
41447
|
+
let checkedPollLabelStepIndex = checkedPollLabel === null || checkedPollLabel === void 0 ? void 0 : checkedPollLabel.getAttribute('goToStep');
|
|
41448
|
+
let pollStepIndex = checkedPollLabelStepIndex - 1;
|
|
41744
41449
|
if (pollStepIndex < 0)
|
|
41745
41450
|
return;
|
|
41746
|
-
|
|
41451
|
+
const destinationObject = {
|
|
41747
41452
|
destinationStepId: guide.steps[pollStepIndex].id,
|
|
41748
|
-
step
|
|
41453
|
+
step
|
|
41749
41454
|
};
|
|
41750
41455
|
pendo.goToStep(destinationObject);
|
|
41751
41456
|
event.cancel = true;
|
|
41752
41457
|
}
|
|
41753
41458
|
|
|
41754
|
-
var
|
|
41459
|
+
var DANGEROUS_URL_SCHEME = /^\s*(javascript|data|vbscript):/i;
|
|
41460
|
+
function encodeMetadataForUrl(value, urlBeforePlaceholder) {
|
|
41461
|
+
if (urlBeforePlaceholder === void 0) { urlBeforePlaceholder = ''; }
|
|
41462
|
+
var str = value === undefined || value === null ? '' : String(value);
|
|
41463
|
+
var inUrlComponent = urlBeforePlaceholder.indexOf('?') !== -1 || urlBeforePlaceholder.indexOf('#') !== -1;
|
|
41464
|
+
if (inUrlComponent) {
|
|
41465
|
+
return window.encodeURIComponent(str);
|
|
41466
|
+
}
|
|
41467
|
+
var schemeAlreadySet = urlBeforePlaceholder.indexOf(':') !== -1;
|
|
41468
|
+
if (!schemeAlreadySet && DANGEROUS_URL_SCHEME.test(str)) {
|
|
41469
|
+
return '';
|
|
41470
|
+
}
|
|
41471
|
+
return window.encodeURI(str);
|
|
41472
|
+
}
|
|
41473
|
+
|
|
41474
|
+
const MetadataSubstitution = {
|
|
41755
41475
|
name: 'MetadataSubstitution',
|
|
41756
|
-
script
|
|
41757
|
-
|
|
41476
|
+
script(step, guide, pendo) {
|
|
41477
|
+
const placeholderData = findSubstitutableElements(pendo);
|
|
41758
41478
|
if (step.domJson) {
|
|
41759
41479
|
findSubstitutableUrlsInJson(step.domJson, placeholderData, pendo);
|
|
41760
41480
|
}
|
|
@@ -41762,22 +41482,22 @@ var MetadataSubstitution = {
|
|
|
41762
41482
|
pendo._.each(placeholderData, function (placeholder) {
|
|
41763
41483
|
processPlaceholder(placeholder, pendo);
|
|
41764
41484
|
});
|
|
41765
|
-
|
|
41766
|
-
|
|
41767
|
-
updateGuideContainer(containerId,
|
|
41485
|
+
const containerId = `pendo-g-${step.id}`;
|
|
41486
|
+
const context = step.guideElement;
|
|
41487
|
+
updateGuideContainer(containerId, context, pendo);
|
|
41768
41488
|
}
|
|
41769
41489
|
},
|
|
41770
|
-
designerListener
|
|
41771
|
-
|
|
41490
|
+
designerListener(pendo) {
|
|
41491
|
+
const target = pendo.dom.getBody();
|
|
41772
41492
|
if (pendo.designerv2) {
|
|
41773
41493
|
pendo.designerv2.runMetadataSubstitutionForDesignerPreview = function runMetadataSubstitutionForDesignerPreview() {
|
|
41774
41494
|
var _a;
|
|
41775
41495
|
if (!document.querySelector(guideMarkdownUtil.containerSelector))
|
|
41776
41496
|
return;
|
|
41777
|
-
|
|
41497
|
+
const step = (_a = pendo.designerv2.currentlyPreviewedGuide) === null || _a === void 0 ? void 0 : _a.steps[0];
|
|
41778
41498
|
if (!step)
|
|
41779
41499
|
return;
|
|
41780
|
-
|
|
41500
|
+
const placeholderData = findSubstitutableElements(pendo);
|
|
41781
41501
|
if (step.buildingBlocks) {
|
|
41782
41502
|
findSubstitutableUrlsInJson(step.buildingBlocks, placeholderData, pendo);
|
|
41783
41503
|
}
|
|
@@ -41787,32 +41507,32 @@ var MetadataSubstitution = {
|
|
|
41787
41507
|
return;
|
|
41788
41508
|
processPlaceholder(placeholder, pendo);
|
|
41789
41509
|
});
|
|
41790
|
-
|
|
41791
|
-
|
|
41792
|
-
updateGuideContainer(containerId,
|
|
41510
|
+
const containerId = `pendo-g-${step.id}`;
|
|
41511
|
+
const context = step.guideElement;
|
|
41512
|
+
updateGuideContainer(containerId, context, pendo);
|
|
41793
41513
|
}
|
|
41794
41514
|
};
|
|
41795
41515
|
}
|
|
41796
|
-
|
|
41516
|
+
const config = {
|
|
41797
41517
|
attributeFilter: ['data-layout'],
|
|
41798
41518
|
attributes: true,
|
|
41799
41519
|
childList: true,
|
|
41800
41520
|
characterData: true,
|
|
41801
41521
|
subtree: true
|
|
41802
41522
|
};
|
|
41803
|
-
|
|
41804
|
-
|
|
41523
|
+
const MutationObserver = getZoneSafeMethod(pendo._, 'MutationObserver');
|
|
41524
|
+
const observer = new MutationObserver(applySubstitutionIndicators);
|
|
41805
41525
|
observer.observe(target, config);
|
|
41806
41526
|
function applySubstitutionIndicators(mutations) {
|
|
41807
41527
|
pendo._.each(mutations, function (mutation) {
|
|
41808
41528
|
var _a;
|
|
41809
41529
|
if (mutation.addedNodes.length) {
|
|
41810
41530
|
if (document.querySelector(guideMarkdownUtil.containerSelector)) {
|
|
41811
|
-
|
|
41812
|
-
|
|
41531
|
+
const placeholderData = findSubstitutableElements(pendo);
|
|
41532
|
+
const step = (_a = pendo.designerv2.currentlyPreviewedGuide) === null || _a === void 0 ? void 0 : _a.steps[0];
|
|
41813
41533
|
if (!step)
|
|
41814
41534
|
return;
|
|
41815
|
-
|
|
41535
|
+
const pendoBlocks = step.buildingBlocks;
|
|
41816
41536
|
if (!pendo._.isUndefined(pendoBlocks)) {
|
|
41817
41537
|
findSubstitutableUrlsInJson(pendoBlocks, placeholderData, pendo);
|
|
41818
41538
|
}
|
|
@@ -41822,9 +41542,9 @@ var MetadataSubstitution = {
|
|
|
41822
41542
|
return;
|
|
41823
41543
|
processPlaceholder(placeholder, pendo);
|
|
41824
41544
|
});
|
|
41825
|
-
|
|
41826
|
-
|
|
41827
|
-
updateGuideContainer(containerId,
|
|
41545
|
+
const containerId = `pendo-g-${step.id}`;
|
|
41546
|
+
const context = step.guideElement;
|
|
41547
|
+
updateGuideContainer(containerId, context, pendo);
|
|
41828
41548
|
}
|
|
41829
41549
|
}
|
|
41830
41550
|
}
|
|
@@ -41833,18 +41553,18 @@ var MetadataSubstitution = {
|
|
|
41833
41553
|
}
|
|
41834
41554
|
};
|
|
41835
41555
|
function processPlaceholder(placeholder, pendo) {
|
|
41836
|
-
|
|
41837
|
-
|
|
41838
|
-
|
|
41556
|
+
let match;
|
|
41557
|
+
const { data, target } = placeholder;
|
|
41558
|
+
const subRegex = new RegExp(guideMarkdownUtil.substitutionRegex);
|
|
41839
41559
|
while ((match = matchPlaceholder(placeholder, subRegex))) {
|
|
41840
|
-
|
|
41841
|
-
|
|
41560
|
+
const usedArrayPath = Array.isArray(match) && match.length >= 2;
|
|
41561
|
+
const currentStr = target === 'textContent'
|
|
41842
41562
|
? data[target]
|
|
41843
41563
|
: decodeURI((data.getAttribute && (target === 'href' || target === 'value') ? (data.getAttribute(target) || '') : data[target]));
|
|
41844
|
-
|
|
41564
|
+
const matched = usedArrayPath ? match : subRegex.exec(currentStr);
|
|
41845
41565
|
if (!matched)
|
|
41846
41566
|
continue;
|
|
41847
|
-
|
|
41567
|
+
const mdValue = getSubstituteValue(matched, pendo);
|
|
41848
41568
|
substituteMetadataByTarget(data, target, mdValue, matched);
|
|
41849
41569
|
}
|
|
41850
41570
|
}
|
|
@@ -41853,49 +41573,51 @@ function matchPlaceholder(placeholder, regex) {
|
|
|
41853
41573
|
return placeholder.data[placeholder.target].match(regex);
|
|
41854
41574
|
}
|
|
41855
41575
|
else {
|
|
41856
|
-
|
|
41576
|
+
const raw = placeholder.data.getAttribute && (placeholder.target === 'href' || placeholder.target === 'value')
|
|
41857
41577
|
? (placeholder.data.getAttribute(placeholder.target) || '')
|
|
41858
41578
|
: placeholder.data[placeholder.target];
|
|
41859
41579
|
return decodeURI(raw).match(regex);
|
|
41860
41580
|
}
|
|
41861
41581
|
}
|
|
41862
41582
|
function getMetadataValueCaseInsensitive(metadata, type, property) {
|
|
41863
|
-
|
|
41583
|
+
const kind = metadata && metadata[type];
|
|
41864
41584
|
if (!kind || typeof kind !== 'object')
|
|
41865
41585
|
return undefined;
|
|
41866
|
-
|
|
41586
|
+
const direct = Object.prototype.hasOwnProperty.call(kind, property) ? kind[property] : undefined;
|
|
41867
41587
|
if (direct !== undefined) {
|
|
41868
41588
|
return direct;
|
|
41869
41589
|
}
|
|
41870
|
-
|
|
41871
|
-
|
|
41872
|
-
|
|
41590
|
+
const propLower = property.toLowerCase();
|
|
41591
|
+
const key = Object.keys(kind).find(k => k.toLowerCase() === propLower);
|
|
41592
|
+
const value = key !== undefined ? kind[key] : undefined;
|
|
41873
41593
|
return value;
|
|
41874
41594
|
}
|
|
41875
41595
|
function getSubstituteValue(match, pendo) {
|
|
41876
41596
|
if (pendo._.isUndefined(match[1]) || pendo._.isUndefined(match[2])) {
|
|
41877
41597
|
return;
|
|
41878
41598
|
}
|
|
41879
|
-
|
|
41880
|
-
|
|
41881
|
-
|
|
41599
|
+
let type = match[1];
|
|
41600
|
+
let property = match[2];
|
|
41601
|
+
let defaultValue = match[3];
|
|
41882
41602
|
if (pendo._.isUndefined(type) || pendo._.isUndefined(property)) {
|
|
41883
41603
|
return;
|
|
41884
41604
|
}
|
|
41885
|
-
|
|
41886
|
-
|
|
41605
|
+
const metadata = pendo.getSerializedMetadata();
|
|
41606
|
+
let mdValue = getMetadataValueCaseInsensitive(metadata, type, property);
|
|
41887
41607
|
if (mdValue === undefined || mdValue === null)
|
|
41888
41608
|
mdValue = defaultValue || '';
|
|
41889
41609
|
return mdValue;
|
|
41890
41610
|
}
|
|
41891
41611
|
function substituteMetadataByTarget(data, target, mdValue, matched) {
|
|
41892
|
-
|
|
41893
|
-
|
|
41612
|
+
const isElement = data && typeof data.getAttribute === 'function';
|
|
41613
|
+
const current = (target === 'href' || target === 'value') && isElement
|
|
41894
41614
|
? (data.getAttribute(target) || '')
|
|
41895
41615
|
: data[target];
|
|
41896
41616
|
if (target === 'href' || target === 'value') {
|
|
41897
|
-
|
|
41898
|
-
|
|
41617
|
+
const decodedUrl = decodeURI(current);
|
|
41618
|
+
const urlBeforePlaceholder = decodedUrl.slice(0, decodedUrl.indexOf(matched[0]));
|
|
41619
|
+
const safeValue = encodeMetadataForUrl(mdValue, urlBeforePlaceholder);
|
|
41620
|
+
data[target] = decodedUrl.replace(matched[0], safeValue);
|
|
41899
41621
|
}
|
|
41900
41622
|
else {
|
|
41901
41623
|
data[target] = current.replace(matched[0], mdValue);
|
|
@@ -41908,9 +41630,8 @@ function updateGuideContainer(containerId, context, pendo) {
|
|
|
41908
41630
|
pendo.flexElement(pendo.dom(guideMarkdownUtil.containerSelector));
|
|
41909
41631
|
pendo.BuildingBlocks.BuildingBlockGuides.recalculateGuideHeight(containerId, context);
|
|
41910
41632
|
}
|
|
41911
|
-
function findSubstitutableUrlsInJson(originalData, placeholderData, pendo) {
|
|
41912
|
-
|
|
41913
|
-
var subRegex = new RegExp(guideMarkdownUtil.substitutionRegex);
|
|
41633
|
+
function findSubstitutableUrlsInJson(originalData, placeholderData = [], pendo) {
|
|
41634
|
+
const subRegex = new RegExp(guideMarkdownUtil.substitutionRegex);
|
|
41914
41635
|
if ((originalData.name === 'url' || originalData.name === 'href') && originalData.value) {
|
|
41915
41636
|
if (subRegex.test(originalData.value)) {
|
|
41916
41637
|
placeholderData.push({
|
|
@@ -41920,37 +41641,37 @@ function findSubstitutableUrlsInJson(originalData, placeholderData, pendo) {
|
|
|
41920
41641
|
}
|
|
41921
41642
|
}
|
|
41922
41643
|
if (originalData.properties && originalData.id === 'href_link_block') {
|
|
41923
|
-
pendo._.each(originalData.properties,
|
|
41644
|
+
pendo._.each(originalData.properties, (prop) => {
|
|
41924
41645
|
findSubstitutableUrlsInJson(prop, placeholderData, pendo);
|
|
41925
41646
|
});
|
|
41926
41647
|
}
|
|
41927
41648
|
if (originalData.views) {
|
|
41928
|
-
pendo._.each(originalData.views,
|
|
41649
|
+
pendo._.each(originalData.views, (view) => {
|
|
41929
41650
|
findSubstitutableUrlsInJson(view, placeholderData, pendo);
|
|
41930
41651
|
});
|
|
41931
41652
|
}
|
|
41932
41653
|
if (originalData.parameters) {
|
|
41933
|
-
pendo._.each(originalData.parameters,
|
|
41654
|
+
pendo._.each(originalData.parameters, (param) => {
|
|
41934
41655
|
findSubstitutableUrlsInJson(param, placeholderData, pendo);
|
|
41935
41656
|
});
|
|
41936
41657
|
}
|
|
41937
41658
|
if (originalData.actions) {
|
|
41938
|
-
pendo._.each(originalData.actions,
|
|
41659
|
+
pendo._.each(originalData.actions, (action) => {
|
|
41939
41660
|
findSubstitutableUrlsInJson(action, placeholderData, pendo);
|
|
41940
41661
|
});
|
|
41941
41662
|
}
|
|
41942
41663
|
if (originalData.children) {
|
|
41943
|
-
pendo._.each(originalData.children,
|
|
41664
|
+
pendo._.each(originalData.children, (child) => {
|
|
41944
41665
|
findSubstitutableUrlsInJson(child, placeholderData, pendo);
|
|
41945
41666
|
});
|
|
41946
41667
|
}
|
|
41947
41668
|
return placeholderData;
|
|
41948
41669
|
}
|
|
41949
41670
|
function findSubstitutableElements(pendo) {
|
|
41950
|
-
|
|
41671
|
+
let elements = pendo.dom(`${guideMarkdownUtil.containerSelector} *:not(.pendo-inline-ui)`);
|
|
41951
41672
|
return pendo._.chain(elements)
|
|
41952
41673
|
.filter(function (placeholder) {
|
|
41953
|
-
|
|
41674
|
+
const subRegex = new RegExp(guideMarkdownUtil.substitutionRegex);
|
|
41954
41675
|
if (placeholder.localName === 'a') {
|
|
41955
41676
|
return subRegex.test(decodeURI(placeholder.href)) || subRegex.test(placeholder.textContent);
|
|
41956
41677
|
}
|
|
@@ -42006,25 +41727,51 @@ function findSubstitutableElements(pendo) {
|
|
|
42006
41727
|
.value();
|
|
42007
41728
|
}
|
|
42008
41729
|
function substitutionIcon(color, size) {
|
|
42009
|
-
return (
|
|
42010
|
-
|
|
42011
|
-
|
|
42012
|
-
|
|
42013
|
-
|
|
42014
|
-
|
|
41730
|
+
return (`<div title="Metadata Substitution added">
|
|
41731
|
+
<svg id="pendo-ps-substitution-icon" viewBox="0 0 24 24"
|
|
41732
|
+
preserveAspectRatio="xMidYMid meet"
|
|
41733
|
+
height=${size} width=${size} title="Metadata Substitution"
|
|
41734
|
+
style="bottom:5px; right:10px; position: absolute;"
|
|
41735
|
+
fill="none" xmlns="http://www.w3.org/2000/svg" stroke="${color}"
|
|
41736
|
+
transform="matrix(1, 0, 0, 1, 0, 0)rotate(0)">
|
|
41737
|
+
<g stroke-width="0"></g>
|
|
41738
|
+
<g stroke-linecap="round" stroke-linejoin="round"
|
|
41739
|
+
stroke="${color}" stroke-width="0.528"></g>
|
|
41740
|
+
<g><path fill-rule="evenodd" clip-rule="evenodd"
|
|
41741
|
+
d="M5 5.5C4.17157 5.5 3.5 6.17157 3.5 7V10C3.5 10.8284
|
|
41742
|
+
4.17157 11.5 5 11.5H8C8.82843 11.5 9.5 10.8284 9.5
|
|
41743
|
+
10V9H17V11C17 11.2761 17.2239 11.5 17.5 11.5C17.7761
|
|
41744
|
+
11.5 18 11.2761 18 11V8.5C18 8.22386 17.7761 8 17.5
|
|
41745
|
+
8H9.5V7C9.5 6.17157 8.82843 5.5 8 5.5H5ZM8.5 7C8.5
|
|
41746
|
+
6.72386 8.27614 6.5 8 6.5H5C4.72386 6.5 4.5 6.72386
|
|
41747
|
+
4.5 7V10C4.5 10.2761 4.72386 10.5 5 10.5H8C8.27614
|
|
41748
|
+
10.5 8.5 10.2761 8.5 10V7Z" fill="${color}"></path>
|
|
41749
|
+
<path fill-rule="evenodd" clip-rule="evenodd"
|
|
41750
|
+
d="M7 13C7 12.7239 6.77614 12.5 6.5 12.5C6.22386 12.5
|
|
41751
|
+
6 12.7239 6 13V15.5C6 15.7761 6.22386 16 6.5
|
|
41752
|
+
16H14.5V17C14.5 17.8284 15.1716 18.5 16 18.5H19C19.8284
|
|
41753
|
+
18.5 20.5 17.8284 20.5 17V14C20.5 13.1716 19.8284 12.5
|
|
41754
|
+
19 12.5H16C15.1716 12.5 14.5 13.1716 14.5
|
|
41755
|
+
14V15H7V13ZM15.5 17C15.5 17.2761 15.7239 17.5 16
|
|
41756
|
+
17.5H19C19.2761 17.5 19.5 17.2761 19.5 17V14C19.5
|
|
41757
|
+
13.7239 19.2761 13.5 19 13.5H16C15.7239 13.5 15.5
|
|
41758
|
+
13.7239 15.5 14V17Z" fill="${color}"></path> </g></svg></div>`);
|
|
41759
|
+
}
|
|
41760
|
+
|
|
41761
|
+
const requiredElement = '<span class="_pendo-required-indicator" style="color:red; font-style:italic;" title="Question is required"> *</span>';
|
|
41762
|
+
const requiredSyntax = '{required/}';
|
|
41763
|
+
const RequiredQuestions = {
|
|
42015
41764
|
name: 'RequiredQuestions',
|
|
42016
|
-
script
|
|
41765
|
+
script(step, guide, pendo) {
|
|
42017
41766
|
var _a;
|
|
42018
|
-
|
|
42019
|
-
|
|
42020
|
-
|
|
42021
|
-
});
|
|
42022
|
-
var requiredQuestions = processRequiredQuestions();
|
|
41767
|
+
let requiredPollIds = [];
|
|
41768
|
+
let submitButtons = (_a = guideMarkdownUtil.lookupGuideButtons(step.domJson)) === null || _a === void 0 ? void 0 : _a.filter(button => button.actions.find(action => action.action === 'submitPoll' || action.action === 'submitPollAndGoToStep'));
|
|
41769
|
+
const requiredQuestions = processRequiredQuestions();
|
|
42023
41770
|
if (requiredQuestions) {
|
|
42024
|
-
pendo._.forEach(requiredQuestions,
|
|
41771
|
+
pendo._.forEach(requiredQuestions, (question) => {
|
|
42025
41772
|
if (question.classList.contains('_pendo-open-text-poll-question')) {
|
|
42026
|
-
|
|
42027
|
-
step.attachEvent(step.guideElement.find(
|
|
41773
|
+
let pollId = question.dataset.pendoPollId;
|
|
41774
|
+
step.attachEvent(step.guideElement.find(`[data-pendo-poll-id=${pollId}]._pendo-open-text-poll-input`)[0], 'input', function () {
|
|
42028
41775
|
evaluateRequiredQuestions(requiredQuestions);
|
|
42029
41776
|
});
|
|
42030
41777
|
}
|
|
@@ -42036,13 +41783,11 @@ var RequiredQuestions = {
|
|
|
42036
41783
|
});
|
|
42037
41784
|
}
|
|
42038
41785
|
function getEligibleQuestions() {
|
|
42039
|
-
|
|
42040
|
-
|
|
42041
|
-
|
|
42042
|
-
|
|
42043
|
-
|
|
42044
|
-
var allQuestions = pendo._.uniq(pollQuestions.concat(surveyQuestions));
|
|
42045
|
-
return pendo._.reduce(allQuestions, function (eligibleQuestions, question) {
|
|
41786
|
+
const pollQuestions = pendo._.toArray(step.guideElement.find(`[class*=-poll-question]:contains(${requiredSyntax})`));
|
|
41787
|
+
const surveyMatches = pendo._.toArray(step.guideElement.find(`[data-pendo-poll-id]:contains(${requiredSyntax})`));
|
|
41788
|
+
const surveyQuestions = pendo._.filter(surveyMatches, (candidate) => !pendo._.some(surveyMatches, (other) => other !== candidate && candidate.contains(other)));
|
|
41789
|
+
const allQuestions = pendo._.uniq(pollQuestions.concat(surveyQuestions));
|
|
41790
|
+
return pendo._.reduce(allQuestions, (eligibleQuestions, question) => {
|
|
42046
41791
|
if (question.classList.contains('_pendo-yes-no-poll-question'))
|
|
42047
41792
|
return eligibleQuestions;
|
|
42048
41793
|
eligibleQuestions.push(question);
|
|
@@ -42050,24 +41795,22 @@ var RequiredQuestions = {
|
|
|
42050
41795
|
}, []);
|
|
42051
41796
|
}
|
|
42052
41797
|
function ownsRequiredText(element) {
|
|
42053
|
-
return pendo._.some(element.childNodes,
|
|
42054
|
-
return node.nodeType === 3 && node.nodeValue && node.nodeValue.indexOf(requiredSyntax) !== -1;
|
|
42055
|
-
});
|
|
41798
|
+
return pendo._.some(element.childNodes, (node) => node.nodeType === 3 && node.nodeValue && node.nodeValue.indexOf(requiredSyntax) !== -1);
|
|
42056
41799
|
}
|
|
42057
41800
|
function processRequiredQuestions() {
|
|
42058
|
-
|
|
41801
|
+
let questions = getEligibleQuestions();
|
|
42059
41802
|
if (questions) {
|
|
42060
|
-
pendo._.forEach(questions,
|
|
42061
|
-
|
|
41803
|
+
pendo._.forEach(questions, question => {
|
|
41804
|
+
let dataPendoPollId = question.getAttribute('data-pendo-poll-id');
|
|
42062
41805
|
requiredPollIds.push(dataPendoPollId);
|
|
42063
|
-
|
|
42064
|
-
|
|
42065
|
-
pendo._.each(candidates,
|
|
41806
|
+
const candidates = step.guideElement.find(`#${question.id} *, #${question.id}`);
|
|
41807
|
+
const textHost = pendo._.find(candidates, ownsRequiredText) || question;
|
|
41808
|
+
pendo._.each(candidates, (element) => {
|
|
42066
41809
|
guideMarkdownUtil.removeMarkdownSyntax(element, requiredSyntax, '', pendo);
|
|
42067
41810
|
});
|
|
42068
|
-
|
|
41811
|
+
const textHostEl = pendo.dom(textHost);
|
|
42069
41812
|
if (textHostEl.find('._pendo-required-indicator').length === 0) {
|
|
42070
|
-
|
|
41813
|
+
const questionParagraph = textHostEl.find('p');
|
|
42071
41814
|
if (questionParagraph && questionParagraph.length) {
|
|
42072
41815
|
pendo.dom(questionParagraph[0]).append(requiredElement);
|
|
42073
41816
|
}
|
|
@@ -42078,7 +41821,15 @@ var RequiredQuestions = {
|
|
|
42078
41821
|
});
|
|
42079
41822
|
}
|
|
42080
41823
|
if (pendo._.size(requiredPollIds)) {
|
|
42081
|
-
|
|
41824
|
+
const disabledButtonStyles = `<style type=text/css
|
|
41825
|
+
id=_pendo-guide-required-disabled>
|
|
41826
|
+
._pendo-button:disabled, ._pendo-buttons[disabled] {
|
|
41827
|
+
border: 1px solid #999999 !important;
|
|
41828
|
+
background-color: #cccccc !important;
|
|
41829
|
+
color: #666666 !important;
|
|
41830
|
+
pointer-events: none !important;
|
|
41831
|
+
}
|
|
41832
|
+
</style>`;
|
|
42082
41833
|
if (pendo.dom('#_pendo-guide-required-disabled').length === 0) {
|
|
42083
41834
|
pendo.dom('head').append(disabledButtonStyles);
|
|
42084
41835
|
}
|
|
@@ -42089,11 +41840,15 @@ var RequiredQuestions = {
|
|
|
42089
41840
|
function evaluateRequiredQuestions(questions) {
|
|
42090
41841
|
if (questions.length === 0)
|
|
42091
41842
|
return;
|
|
42092
|
-
|
|
42093
|
-
|
|
42094
|
-
responses = responses.concat(pendo._.map(questions,
|
|
42095
|
-
|
|
42096
|
-
|
|
41843
|
+
let allRequiredComplete = true;
|
|
41844
|
+
let responses = [];
|
|
41845
|
+
responses = responses.concat(pendo._.map(questions, (question) => {
|
|
41846
|
+
let pollId = question.getAttribute('data-pendo-poll-id');
|
|
41847
|
+
let input = step.guideElement.find(`
|
|
41848
|
+
[data-pendo-poll-id=${pollId}] textarea,
|
|
41849
|
+
[data-pendo-poll-id=${pollId}] input:text,
|
|
41850
|
+
[data-pendo-poll-id=${pollId}] select,
|
|
41851
|
+
[data-pendo-poll-id=${pollId}] input:radio:checked`);
|
|
42097
41852
|
if (input && input.length && input[0].value) {
|
|
42098
41853
|
return input[0].value;
|
|
42099
41854
|
}
|
|
@@ -42110,50 +41865,50 @@ var RequiredQuestions = {
|
|
|
42110
41865
|
}
|
|
42111
41866
|
function disableEligibleButtons(buttons) {
|
|
42112
41867
|
pendo._.each(buttons, function (button) {
|
|
42113
|
-
if (step.guideElement.find(
|
|
42114
|
-
step.guideElement.find(
|
|
42115
|
-
step.guideElement.find(
|
|
41868
|
+
if (step.guideElement.find(`#${button.props.id}`)[0]) {
|
|
41869
|
+
step.guideElement.find(`#${button.props.id}`)[0].disabled = true;
|
|
41870
|
+
step.guideElement.find(`#${button.props.id}`)[0].parentElement.title = 'Please complete all required questions.';
|
|
42116
41871
|
}
|
|
42117
41872
|
});
|
|
42118
41873
|
}
|
|
42119
41874
|
function enableEligibleButtons(buttons) {
|
|
42120
41875
|
pendo._.each(buttons, function (button) {
|
|
42121
|
-
if (step.guideElement.find(
|
|
42122
|
-
step.guideElement.find(
|
|
42123
|
-
step.guideElement.find(
|
|
41876
|
+
if (step.guideElement.find(`#${button.props.id}`)[0]) {
|
|
41877
|
+
step.guideElement.find(`#${button.props.id}`)[0].disabled = false;
|
|
41878
|
+
step.guideElement.find(`#${button.props.id}`)[0].parentElement.title = '';
|
|
42124
41879
|
}
|
|
42125
41880
|
});
|
|
42126
41881
|
}
|
|
42127
41882
|
},
|
|
42128
|
-
test
|
|
41883
|
+
test(step, guide, pendo) {
|
|
42129
41884
|
var _a, _b;
|
|
42130
|
-
|
|
42131
|
-
|
|
41885
|
+
const pollQuestions = (_a = step.guideElement) === null || _a === void 0 ? void 0 : _a.find(`[class*=-poll-question]:contains(${requiredSyntax})`);
|
|
41886
|
+
const surveyQuestions = (_b = step.guideElement) === null || _b === void 0 ? void 0 : _b.find(`[data-pendo-poll-id]:contains(${requiredSyntax})`);
|
|
42132
41887
|
return (!pendo._.isUndefined(pollQuestions) && pendo._.size(pollQuestions)) ||
|
|
42133
41888
|
(!pendo._.isUndefined(surveyQuestions) && pendo._.size(surveyQuestions));
|
|
42134
41889
|
},
|
|
42135
|
-
designerListener
|
|
42136
|
-
|
|
42137
|
-
|
|
42138
|
-
|
|
41890
|
+
designerListener(pendo) {
|
|
41891
|
+
const requiredQuestions = [];
|
|
41892
|
+
const target = pendo.dom.getBody();
|
|
41893
|
+
const config = {
|
|
42139
41894
|
attributeFilter: ['data-layout'],
|
|
42140
41895
|
attributes: true,
|
|
42141
41896
|
childList: true,
|
|
42142
41897
|
characterData: true,
|
|
42143
41898
|
subtree: true
|
|
42144
41899
|
};
|
|
42145
|
-
|
|
42146
|
-
|
|
41900
|
+
const MutationObserver = getZoneSafeMethod(pendo._, 'MutationObserver');
|
|
41901
|
+
const observer = new MutationObserver(applyRequiredIndicators);
|
|
42147
41902
|
observer.observe(target, config);
|
|
42148
41903
|
function applyRequiredIndicators(mutations) {
|
|
42149
41904
|
pendo._.each(mutations, function (mutation) {
|
|
42150
41905
|
var _a;
|
|
42151
|
-
|
|
41906
|
+
const nodeHasQuerySelector = pendo._.isFunction((_a = mutation.addedNodes[0]) === null || _a === void 0 ? void 0 : _a.querySelectorAll);
|
|
42152
41907
|
if (mutation.addedNodes.length && nodeHasQuerySelector) {
|
|
42153
|
-
|
|
41908
|
+
let eligiblePolls = mutation.addedNodes[0].querySelectorAll('[class*=-poll-wrapper], [class*=-poll-select-border], [id^=survey-item-wrapper__]');
|
|
42154
41909
|
if (eligiblePolls) {
|
|
42155
41910
|
pendo._.each(eligiblePolls, function (poll) {
|
|
42156
|
-
|
|
41911
|
+
let dataPendoPollId;
|
|
42157
41912
|
if (poll.classList.contains('_pendo-open-text-poll-wrapper') ||
|
|
42158
41913
|
poll.classList.contains('_pendo-number-scale-poll-wrapper')) {
|
|
42159
41914
|
dataPendoPollId = poll.getAttribute('name');
|
|
@@ -42161,31 +41916,31 @@ var RequiredQuestions = {
|
|
|
42161
41916
|
else {
|
|
42162
41917
|
dataPendoPollId = poll.getAttribute('data-pendo-poll-id');
|
|
42163
41918
|
}
|
|
42164
|
-
|
|
42165
|
-
|
|
42166
|
-
pendo.dom(
|
|
41919
|
+
let questionText;
|
|
41920
|
+
const questionElement = pendo.dom(`[class*="-poll-question"][data-pendo-poll-id=${dataPendoPollId}]`)[0] ||
|
|
41921
|
+
pendo.dom(`.bb-text[data-pendo-poll-id=${dataPendoPollId}]`)[0];
|
|
42167
41922
|
if (questionElement) {
|
|
42168
41923
|
questionText = questionElement.textContent;
|
|
42169
41924
|
}
|
|
42170
|
-
|
|
41925
|
+
const requiredSyntaxIndex = questionText ? questionText.indexOf(requiredSyntax) : -1;
|
|
42171
41926
|
if (requiredSyntaxIndex > -1) {
|
|
42172
|
-
pendo._.each(pendo.dom(
|
|
42173
|
-
pendo._.each(pendo.dom(
|
|
41927
|
+
pendo._.each(pendo.dom(`[data-pendo-poll-id=${dataPendoPollId}]:not(.pendo-radio)`), (element) => {
|
|
41928
|
+
pendo._.each(pendo.dom(`#${element.id} *:not(".pendo-radio"), #${element.id}:not(".pendo-radio")`), (item) => {
|
|
42174
41929
|
guideMarkdownUtil.removeMarkdownSyntax(item, requiredSyntax, '', pendo);
|
|
42175
41930
|
});
|
|
42176
41931
|
});
|
|
42177
|
-
|
|
42178
|
-
|
|
42179
|
-
|
|
42180
|
-
|
|
42181
|
-
pendo._.each(pendo.dom(
|
|
42182
|
-
pendo._.each(el.childNodes,
|
|
41932
|
+
const pollTextSelector = `.bb-text[data-pendo-poll-id=${dataPendoPollId}]`;
|
|
41933
|
+
const pollParagraphSelector = `${pollTextSelector} p`;
|
|
41934
|
+
const pollListItemSelector = `${pollTextSelector} li`;
|
|
41935
|
+
const pollIndicatorSelector = `${pollTextSelector} ._pendo-required-indicator`;
|
|
41936
|
+
pendo._.each(pendo.dom(`${pollParagraphSelector}, ${pollListItemSelector}`), (el) => {
|
|
41937
|
+
pendo._.each(el.childNodes, (node) => {
|
|
42183
41938
|
if (node.nodeType === 3 && node.nodeValue.indexOf(requiredSyntax) !== -1) {
|
|
42184
41939
|
node.nodeValue = node.nodeValue.split(requiredSyntax).join('');
|
|
42185
41940
|
}
|
|
42186
41941
|
});
|
|
42187
41942
|
});
|
|
42188
|
-
|
|
41943
|
+
const hasIndicator = pendo.dom(pollIndicatorSelector).length !== 0;
|
|
42189
41944
|
if (!hasIndicator) {
|
|
42190
41945
|
if (pendo.dom(pollParagraphSelector).length !== 0 || pendo.dom(pollListItemSelector).length !== 0) {
|
|
42191
41946
|
pendo.dom(pollParagraphSelector).append(requiredElement);
|
|
@@ -42196,7 +41951,7 @@ var RequiredQuestions = {
|
|
|
42196
41951
|
}
|
|
42197
41952
|
}
|
|
42198
41953
|
if (pendo._.contains(requiredQuestions, dataPendoPollId)) {
|
|
42199
|
-
|
|
41954
|
+
let questionIndex = requiredQuestions.indexOf(dataPendoPollId);
|
|
42200
41955
|
if (questionIndex !== -1) {
|
|
42201
41956
|
requiredQuestions.splice(questionIndex, 1);
|
|
42202
41957
|
}
|
|
@@ -42207,7 +41962,7 @@ var RequiredQuestions = {
|
|
|
42207
41962
|
}
|
|
42208
41963
|
else {
|
|
42209
41964
|
if (pendo._.contains(requiredQuestions, dataPendoPollId)) {
|
|
42210
|
-
|
|
41965
|
+
let index = requiredQuestions.indexOf(dataPendoPollId);
|
|
42211
41966
|
if (index !== -1) {
|
|
42212
41967
|
requiredQuestions.splice(index, 1);
|
|
42213
41968
|
}
|
|
@@ -42221,54 +41976,54 @@ var RequiredQuestions = {
|
|
|
42221
41976
|
}
|
|
42222
41977
|
};
|
|
42223
41978
|
|
|
42224
|
-
|
|
42225
|
-
|
|
42226
|
-
script
|
|
42227
|
-
|
|
42228
|
-
|
|
42229
|
-
|
|
42230
|
-
|
|
42231
|
-
|
|
41979
|
+
const skipStepRegex = new RegExp(guideMarkdownUtil.skipStepString);
|
|
41980
|
+
const SkipToEligibleStep = {
|
|
41981
|
+
script(step, guide, pendo) {
|
|
41982
|
+
let isAdvanceIntercepted = false;
|
|
41983
|
+
let isPreviousIntercepted = false;
|
|
41984
|
+
let guideContainer = step.guideElement.find(guideMarkdownUtil.containerSelector);
|
|
41985
|
+
let guideContainerAriaLabel = guideContainer.attr('aria-label');
|
|
41986
|
+
let stepNumberOrAuto = skipStepRegex.exec(guideContainerAriaLabel)[1];
|
|
42232
41987
|
if (guideContainer) {
|
|
42233
41988
|
guideContainer.attr({ 'aria-label': guideContainer.attr('aria-label').replace(skipStepRegex, '') });
|
|
42234
41989
|
}
|
|
42235
|
-
this.on('beforeAdvance',
|
|
41990
|
+
this.on('beforeAdvance', (evt) => {
|
|
42236
41991
|
if (guide.getPositionOfStep(step) === guide.steps.length || pendo._.isUndefined(stepNumberOrAuto))
|
|
42237
41992
|
return; // exit on the last step of a guide or when we don't have an argument
|
|
42238
|
-
|
|
41993
|
+
let eligibleStep = findEligibleSkipStep(stepNumberOrAuto, 'next');
|
|
42239
41994
|
if (!isAdvanceIntercepted && stepNumberOrAuto) {
|
|
42240
41995
|
isAdvanceIntercepted = true;
|
|
42241
|
-
pendo.goToStep({ destinationStepId: eligibleStep.id, step
|
|
41996
|
+
pendo.goToStep({ destinationStepId: eligibleStep.id, step });
|
|
42242
41997
|
evt.cancel = true;
|
|
42243
41998
|
}
|
|
42244
41999
|
});
|
|
42245
|
-
this.on('beforePrevious',
|
|
42000
|
+
this.on('beforePrevious', (evt) => {
|
|
42246
42001
|
if (pendo._.isUndefined(stepNumberOrAuto))
|
|
42247
42002
|
return;
|
|
42248
|
-
|
|
42003
|
+
let eligibleStep = findEligibleSkipStep(stepNumberOrAuto, 'previous');
|
|
42249
42004
|
if (!isPreviousIntercepted && stepNumberOrAuto) {
|
|
42250
42005
|
isPreviousIntercepted = true;
|
|
42251
|
-
pendo.goToStep({ destinationStepId: eligibleStep.id, step
|
|
42006
|
+
pendo.goToStep({ destinationStepId: eligibleStep.id, step });
|
|
42252
42007
|
evt.cancel = true;
|
|
42253
42008
|
}
|
|
42254
42009
|
});
|
|
42255
42010
|
function findEligibleSkipStep(stepNumber, direction) {
|
|
42256
42011
|
// Find the next eligible step by using getPosition of step (1 based)
|
|
42257
42012
|
// getPosition - 2 gives the previous step
|
|
42258
|
-
|
|
42259
|
-
|
|
42013
|
+
let skipForwardStep = findStepOnPage(guide.getPositionOfStep(step), 'next', stepNumber);
|
|
42014
|
+
let skipPreviousStep = findStepOnPage(guide.getPositionOfStep(step) - 2, 'previous', stepNumber);
|
|
42260
42015
|
if (skipForwardStep && direction == 'next') {
|
|
42261
|
-
pendo.goToStep({ destinationStepId: skipForwardStep, step
|
|
42016
|
+
pendo.goToStep({ destinationStepId: skipForwardStep, step });
|
|
42262
42017
|
}
|
|
42263
42018
|
if (skipPreviousStep && direction == 'previous') {
|
|
42264
|
-
pendo.goToStep({ destinationStepId: skipPreviousStep, step
|
|
42019
|
+
pendo.goToStep({ destinationStepId: skipPreviousStep, step });
|
|
42265
42020
|
}
|
|
42266
42021
|
return direction === 'next' ? skipForwardStep : skipPreviousStep;
|
|
42267
42022
|
}
|
|
42268
42023
|
function findStepOnPage(stepIndex, direction, stepNumber) {
|
|
42269
42024
|
if (pendo._.isNaN(stepIndex))
|
|
42270
42025
|
return;
|
|
42271
|
-
|
|
42026
|
+
let $step = guide.steps[stepIndex];
|
|
42272
42027
|
if ($step && !$step.canShow()) {
|
|
42273
42028
|
if (stepNumber !== 'auto') {
|
|
42274
42029
|
return guide.steps[stepNumber - 1];
|
|
@@ -42285,34 +42040,34 @@ var SkipToEligibleStep = {
|
|
|
42285
42040
|
}
|
|
42286
42041
|
}
|
|
42287
42042
|
},
|
|
42288
|
-
test
|
|
42043
|
+
test(step, guide, pendo) {
|
|
42289
42044
|
var _a;
|
|
42290
|
-
|
|
42045
|
+
const guideContainerAriaLabel = (_a = step.guideElement) === null || _a === void 0 ? void 0 : _a.find(guideMarkdownUtil.containerSelector).attr('aria-label');
|
|
42291
42046
|
return pendo._.isString(guideContainerAriaLabel) && guideContainerAriaLabel.indexOf('{skipStep') !== -1;
|
|
42292
42047
|
},
|
|
42293
|
-
designerListener
|
|
42294
|
-
|
|
42295
|
-
|
|
42048
|
+
designerListener(pendo) {
|
|
42049
|
+
const target = pendo.dom.getBody();
|
|
42050
|
+
const config = {
|
|
42296
42051
|
attributeFilter: ['data-layout'],
|
|
42297
42052
|
attributes: true,
|
|
42298
42053
|
childList: true,
|
|
42299
42054
|
characterData: true,
|
|
42300
42055
|
subtree: true
|
|
42301
42056
|
};
|
|
42302
|
-
|
|
42303
|
-
|
|
42057
|
+
const MutationObserver = getZoneSafeMethod(pendo._, 'MutationObserver');
|
|
42058
|
+
const observer = new MutationObserver(applySkipStepIndicator);
|
|
42304
42059
|
observer.observe(target, config);
|
|
42305
42060
|
// create an observer instance
|
|
42306
42061
|
function applySkipStepIndicator(mutations) {
|
|
42307
42062
|
pendo._.each(mutations, function (mutation) {
|
|
42308
42063
|
var _a, _b;
|
|
42309
|
-
|
|
42064
|
+
const nodeHasQuerySelector = pendo._.isFunction((_a = mutation.addedNodes[0]) === null || _a === void 0 ? void 0 : _a.querySelectorAll);
|
|
42310
42065
|
if (mutation.addedNodes.length && nodeHasQuerySelector) {
|
|
42311
|
-
|
|
42312
|
-
|
|
42066
|
+
let guideContainer = mutation.addedNodes[0].querySelectorAll(guideMarkdownUtil.containerSelector);
|
|
42067
|
+
let guideContainerAriaLabel = (_b = guideContainer[0]) === null || _b === void 0 ? void 0 : _b.getAttribute('aria-label');
|
|
42313
42068
|
if (guideContainerAriaLabel) {
|
|
42314
42069
|
if (guideContainerAriaLabel.match(skipStepRegex)) {
|
|
42315
|
-
|
|
42070
|
+
let fullSkipStepString = guideContainerAriaLabel.match(skipStepRegex)[0];
|
|
42316
42071
|
guideContainerAriaLabel.replace(fullSkipStepString, '');
|
|
42317
42072
|
if (!pendo.dom('#_pendoSkipIcon').length) {
|
|
42318
42073
|
pendo.dom(guideMarkdownUtil.containerSelector).append(skipIcon('#999', '30px').trim());
|
|
@@ -42323,30 +42078,48 @@ var SkipToEligibleStep = {
|
|
|
42323
42078
|
});
|
|
42324
42079
|
}
|
|
42325
42080
|
function skipIcon(color, size) {
|
|
42326
|
-
return (
|
|
42081
|
+
return (`<div title="Skip step added"><svg id="_pendoSkipIcon" version="1.0" xmlns="http://www.w3.org/2000/svg"
|
|
42082
|
+
width="${size}" height="${size}" viewBox="0 0 512.000000 512.000000"
|
|
42083
|
+
preserveAspectRatio="xMidYMid meet" style="bottom:5px; right:10px; position: absolute;">
|
|
42084
|
+
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
|
|
42085
|
+
fill="${color}" stroke="none">
|
|
42086
|
+
<path d="M2185 4469 c-363 -38 -739 -186 -1034 -407 -95 -71 -273 -243 -357
|
|
42087
|
+
-343 -205 -246 -364 -577 -429 -897 -25 -121 -45 -288 -45 -373 l0 -49 160 0
|
|
42088
|
+
160 0 0 48 c0 26 5 88 10 137 68 593 417 1103 940 1374 1100 570 2418 -137
|
|
42089
|
+
2560 -1374 5 -49 10 -111 10 -137 l0 -47 -155 -3 -155 -3 235 -235 235 -236
|
|
42090
|
+
235 236 235 235 -155 3 -155 3 0 48 c0 27 -5 95 -10 152 -100 989 -878 1767
|
|
42091
|
+
-1869 1868 -117 12 -298 12 -416 0z"/>
|
|
42092
|
+
<path d="M320 1440 l0 -160 160 0 160 0 0 160 0 160 -160 0 -160 0 0 -160z"/>
|
|
42093
|
+
<path d="M960 1440 l0 -160 160 0 160 0 0 160 0 160 -160 0 -160 0 0 -160z"/>
|
|
42094
|
+
<path d="M1600 1440 l0 -160 160 0 160 0 0 160 0 160 -160 0 -160 0 0 -160z"/>
|
|
42095
|
+
<path d="M2240 1440 l0 -160 160 0 160 0 0 160 0 160 -160 0 -160 0 0 -160z"/>
|
|
42096
|
+
<path d="M2880 1440 l0 -160 160 0 160 0 0 160 0 160 -160 0 -160 0 0 -160z"/>
|
|
42097
|
+
<path d="M3840 1440 l0 -160 480 0 480 0 0 160 0 160 -480 0 -480 0 0 -160z"/>
|
|
42098
|
+
</g></svg></div>
|
|
42099
|
+
`);
|
|
42327
42100
|
}
|
|
42328
42101
|
}
|
|
42329
42102
|
};
|
|
42330
42103
|
|
|
42331
42104
|
function GuideMarkdown() {
|
|
42332
|
-
|
|
42333
|
-
|
|
42334
|
-
|
|
42105
|
+
let guideMarkdown;
|
|
42106
|
+
let pluginApi;
|
|
42107
|
+
let globalPendo;
|
|
42335
42108
|
return {
|
|
42336
42109
|
name: 'GuideMarkdown',
|
|
42337
42110
|
initialize: init,
|
|
42338
|
-
teardown
|
|
42111
|
+
teardown
|
|
42339
42112
|
};
|
|
42340
42113
|
function init(pendo, PluginAPI) {
|
|
42341
42114
|
globalPendo = pendo;
|
|
42342
42115
|
pluginApi = PluginAPI;
|
|
42343
|
-
|
|
42344
|
-
|
|
42116
|
+
const configReader = PluginAPI.ConfigReader;
|
|
42117
|
+
const GUIDEMARKDOWN_CONFIG = 'guideMarkdown';
|
|
42345
42118
|
configReader.addOption(GUIDEMARKDOWN_CONFIG, [
|
|
42346
42119
|
configReader.sources.SNIPPET_SRC,
|
|
42347
42120
|
configReader.sources.PENDO_CONFIG_SRC
|
|
42348
42121
|
], false);
|
|
42349
|
-
|
|
42122
|
+
const markdownScriptsEnabled = configReader.get(GUIDEMARKDOWN_CONFIG);
|
|
42350
42123
|
if (!markdownScriptsEnabled)
|
|
42351
42124
|
return;
|
|
42352
42125
|
guideMarkdown = [PollBranching, MetadataSubstitution, RequiredQuestions, SkipToEligibleStep];
|
|
@@ -43385,8 +43158,8 @@ function Feedback() {
|
|
|
43385
43158
|
var widgetLoaded = false;
|
|
43386
43159
|
var feedbackAllowedProductId = '';
|
|
43387
43160
|
var initialized = false;
|
|
43388
|
-
|
|
43389
|
-
|
|
43161
|
+
const PING_COOKIE = 'feedback_ping_sent';
|
|
43162
|
+
const PING_COOKIE_EXPIRATION = 1000 * 60 * 60;
|
|
43390
43163
|
var overflowMediaQuery = '@media only screen and (max-device-width:1112px){#feedback-widget{overflow-y:scroll}}';
|
|
43391
43164
|
var slideIn = '@-webkit-keyframes pendoFeedbackSlideIn{from{opacity:0;transform:translate(145px,0) rotate(270deg) translateY(-50%)}to{opacity:1;transform:translate(50%,0) rotate(270deg) translateY(-50%)}}@keyframes pendoFeedbackSlideIn{from{opacity:0;transform:translate(145px,0) rotate(270deg) translateY(-50%)}to{opacity:1;transform:translate(50%,0) rotate(270deg) translateY(-50%)}}';
|
|
43392
43165
|
var slideInLeft = '@-webkit-keyframes pendoFeedbackSlideIn-left{from{opacity:0;transform:rotate(270deg) translateX(-55%) translateY(-55%)}to{opacity:1;transform:rotate(270deg) translateX(-55%) translateY(0)}}@keyframes pendoFeedbackSlideIn-left{from{opacity:0;transform:rotate(270deg) translateX(-55%) translateY(-55%)}to{opacity:1;transform:rotate(270deg) translateX(-55%) translateY(0)}}';
|
|
@@ -43406,28 +43179,28 @@ function Feedback() {
|
|
|
43406
43179
|
feedbackStyles: 'pendo-feedback-styles',
|
|
43407
43180
|
feedbackFrameStyles: 'pendo-feedback-visible-buttons-styles'
|
|
43408
43181
|
};
|
|
43409
|
-
|
|
43410
|
-
|
|
43182
|
+
let globalPendo;
|
|
43183
|
+
let pluginApi;
|
|
43411
43184
|
return {
|
|
43412
43185
|
name: 'Feedback',
|
|
43413
|
-
initialize
|
|
43414
|
-
teardown
|
|
43415
|
-
validate
|
|
43186
|
+
initialize,
|
|
43187
|
+
teardown,
|
|
43188
|
+
validate
|
|
43416
43189
|
};
|
|
43417
43190
|
function initialize(pendo, PluginAPI) {
|
|
43418
43191
|
globalPendo = pendo;
|
|
43419
43192
|
pluginApi = PluginAPI;
|
|
43420
43193
|
var publicFeedback = {
|
|
43421
|
-
ping
|
|
43422
|
-
init
|
|
43194
|
+
ping,
|
|
43195
|
+
init,
|
|
43423
43196
|
initialized: getInitialized,
|
|
43424
|
-
loginAndRedirect
|
|
43425
|
-
openFeedback
|
|
43426
|
-
initializeFeedbackOnce
|
|
43427
|
-
isFeedbackLoaded
|
|
43428
|
-
convertPendoToFeedbackOptions
|
|
43197
|
+
loginAndRedirect,
|
|
43198
|
+
openFeedback,
|
|
43199
|
+
initializeFeedbackOnce,
|
|
43200
|
+
isFeedbackLoaded,
|
|
43201
|
+
convertPendoToFeedbackOptions,
|
|
43429
43202
|
isUnsupportedIE: pendo._.partial(isUnsupportedIE, PluginAPI),
|
|
43430
|
-
removeFeedbackWidget
|
|
43203
|
+
removeFeedbackWidget
|
|
43431
43204
|
};
|
|
43432
43205
|
pendo.feedback = publicFeedback;
|
|
43433
43206
|
pendo.getFeedbackSettings = getFeedbackSettings;
|
|
@@ -43455,7 +43228,7 @@ function Feedback() {
|
|
|
43455
43228
|
*/
|
|
43456
43229
|
PluginAPI.agentStorage.registry.addLocal(PING_COOKIE, { duration: PING_COOKIE_EXPIRATION });
|
|
43457
43230
|
return {
|
|
43458
|
-
validate
|
|
43231
|
+
validate
|
|
43459
43232
|
};
|
|
43460
43233
|
}
|
|
43461
43234
|
function teardown() {
|
|
@@ -43475,18 +43248,18 @@ function Feedback() {
|
|
|
43475
43248
|
return result;
|
|
43476
43249
|
}
|
|
43477
43250
|
function pingOrInitialize() {
|
|
43478
|
-
|
|
43251
|
+
const options = getPendoOptions();
|
|
43479
43252
|
if (initialized) {
|
|
43480
|
-
|
|
43253
|
+
const feedbackOptions = convertPendoToFeedbackOptions(options);
|
|
43481
43254
|
ping(feedbackOptions);
|
|
43482
43255
|
}
|
|
43483
43256
|
else if (shouldInitializeFeedback() && !globalPendo._.isEmpty(options)) {
|
|
43484
|
-
|
|
43485
|
-
init(options, settings)
|
|
43257
|
+
const settings = pluginApi.ConfigReader.get('feedbackSettings');
|
|
43258
|
+
init(options, settings).catch(globalPendo._.noop);
|
|
43486
43259
|
}
|
|
43487
43260
|
}
|
|
43488
43261
|
function handleIdentityChange(event) {
|
|
43489
|
-
|
|
43262
|
+
const visitorId = globalPendo._.get(event, 'data.0.visitor_id') || globalPendo._.get(event, 'data.0.options.visitor.id');
|
|
43490
43263
|
if (globalPendo.isAnonymousVisitor(visitorId)) {
|
|
43491
43264
|
removeFeedbackWidget();
|
|
43492
43265
|
return;
|
|
@@ -43556,9 +43329,9 @@ function Feedback() {
|
|
|
43556
43329
|
if (toSend.data && toSend.data !== '{}' && toSend.data !== 'null') {
|
|
43557
43330
|
return globalPendo.ajax
|
|
43558
43331
|
.postJSON(getFullUrl('/widget/pendo_ping'), toSend)
|
|
43559
|
-
.then(
|
|
43332
|
+
.then((response) => {
|
|
43560
43333
|
onWidgetPingResponse(response);
|
|
43561
|
-
})
|
|
43334
|
+
}).catch(() => { onPingFailure(); });
|
|
43562
43335
|
}
|
|
43563
43336
|
}
|
|
43564
43337
|
return pluginApi.q.resolve();
|
|
@@ -43692,10 +43465,10 @@ function Feedback() {
|
|
|
43692
43465
|
return globalPendo.ajax.postJSON(getFullUrl('/analytics'), toSend);
|
|
43693
43466
|
}
|
|
43694
43467
|
function addOverlay() {
|
|
43695
|
-
|
|
43468
|
+
const widget = globalPendo.dom(`#${elemIds.feedbackWidget}`);
|
|
43696
43469
|
if (!widget)
|
|
43697
43470
|
return;
|
|
43698
|
-
|
|
43471
|
+
const overlayStyles = {
|
|
43699
43472
|
'position': 'fixed',
|
|
43700
43473
|
'top': '0',
|
|
43701
43474
|
'right': '0',
|
|
@@ -43707,7 +43480,7 @@ function Feedback() {
|
|
|
43707
43480
|
'animation': 'pendoFeedbackFadeIn 0.5s 0s 1 alternate both',
|
|
43708
43481
|
'-webkit-animation': 'pendoFeedbackFadeIn 0.5s 0s 1 alternate both'
|
|
43709
43482
|
};
|
|
43710
|
-
|
|
43483
|
+
const overlayElement = globalPendo.dom(document.createElement('div'));
|
|
43711
43484
|
overlayElement.attr('id', 'feedback-overlay');
|
|
43712
43485
|
overlayElement.css(overlayStyles);
|
|
43713
43486
|
overlayElement.appendTo(widget.getParent());
|
|
@@ -43812,22 +43585,22 @@ function Feedback() {
|
|
|
43812
43585
|
}
|
|
43813
43586
|
}
|
|
43814
43587
|
function buildOuterTriggerDiv(positionInfo) {
|
|
43815
|
-
|
|
43816
|
-
|
|
43817
|
-
|
|
43588
|
+
const horizontalStyles = getHorizontalPositionStyles(positionInfo);
|
|
43589
|
+
const verticalStyles = getVerticalPositionStyles(positionInfo);
|
|
43590
|
+
const styles = globalPendo._.extend({
|
|
43818
43591
|
'position': 'fixed',
|
|
43819
43592
|
'height': '43px',
|
|
43820
43593
|
'opacity': '1 !important',
|
|
43821
43594
|
'z-index': '9001'
|
|
43822
43595
|
}, horizontalStyles, verticalStyles);
|
|
43823
|
-
|
|
43596
|
+
const outerTrigger = globalPendo.dom(document.createElement('div'));
|
|
43824
43597
|
outerTrigger.attr('id', elemIds.feedbackTrigger);
|
|
43825
43598
|
outerTrigger.css(styles);
|
|
43826
43599
|
outerTrigger.attr('data-turbolinks-permanent', '');
|
|
43827
43600
|
return outerTrigger;
|
|
43828
43601
|
}
|
|
43829
43602
|
function buildNotification() {
|
|
43830
|
-
|
|
43603
|
+
const styles = {
|
|
43831
43604
|
'background-color': '#D85039',
|
|
43832
43605
|
'color': '#fff',
|
|
43833
43606
|
'border-radius': '50%',
|
|
@@ -43844,20 +43617,20 @@ function Feedback() {
|
|
|
43844
43617
|
'animation-delay': '1s',
|
|
43845
43618
|
'animation-iteration-count': '1'
|
|
43846
43619
|
};
|
|
43847
|
-
|
|
43620
|
+
const notification = globalPendo.dom(document.createElement('span'));
|
|
43848
43621
|
notification.attr('id', 'feedback-trigger-notification');
|
|
43849
43622
|
notification.css(styles);
|
|
43850
43623
|
return notification;
|
|
43851
43624
|
}
|
|
43852
43625
|
function buildTriggerButton(settings, positionInfo) {
|
|
43853
|
-
|
|
43626
|
+
let borderRadius;
|
|
43854
43627
|
if (positionInfo.horizontalPosition === 'left') {
|
|
43855
43628
|
borderRadius = '0 0 5px 5px';
|
|
43856
43629
|
}
|
|
43857
43630
|
else {
|
|
43858
43631
|
borderRadius = '3px 3px 0 0';
|
|
43859
43632
|
}
|
|
43860
|
-
|
|
43633
|
+
const styles = {
|
|
43861
43634
|
'border': 'none',
|
|
43862
43635
|
'padding': '11px 18px 14px 18px',
|
|
43863
43636
|
'background-color': settings.triggerColor,
|
|
@@ -43868,21 +43641,32 @@ function Feedback() {
|
|
|
43868
43641
|
'cursor': 'pointer',
|
|
43869
43642
|
'text-align': 'left'
|
|
43870
43643
|
};
|
|
43871
|
-
|
|
43644
|
+
const triggerButton = globalPendo.dom(document.createElement('button'));
|
|
43872
43645
|
triggerButton.attr('id', elemIds.feedbackTriggerButton);
|
|
43873
43646
|
triggerButton.css(styles);
|
|
43874
43647
|
triggerButton.text(settings.triggerText);
|
|
43875
43648
|
return triggerButton;
|
|
43876
43649
|
}
|
|
43877
43650
|
function addTriggerPseudoStyles() {
|
|
43878
|
-
|
|
43651
|
+
const pseudoStyles = `
|
|
43652
|
+
#feedback-trigger button:hover {
|
|
43653
|
+
box-shadow: 0 -5px 20px rgba(0,0,0,.19) !important;
|
|
43654
|
+
outline: none !important;
|
|
43655
|
+
background: #3e566f !important;
|
|
43656
|
+
}
|
|
43657
|
+
#feedback-trigger button:focus {
|
|
43658
|
+
box-shadow: 0 -5px 20px rgba(0,0,0,.19) !important;
|
|
43659
|
+
outline: none !important;
|
|
43660
|
+
background: #3e566f !important;
|
|
43661
|
+
}
|
|
43662
|
+
`;
|
|
43879
43663
|
pluginApi.util.addInlineStyles('pendo-feedback-trigger-styles', pseudoStyles);
|
|
43880
43664
|
}
|
|
43881
43665
|
function createTrigger(settings, positionInfo) {
|
|
43882
43666
|
addTriggerPseudoStyles();
|
|
43883
|
-
|
|
43884
|
-
|
|
43885
|
-
|
|
43667
|
+
const triggerElement = buildOuterTriggerDiv(positionInfo);
|
|
43668
|
+
const notificationElement = buildNotification();
|
|
43669
|
+
const triggerButtonElement = buildTriggerButton(settings, positionInfo);
|
|
43886
43670
|
triggerElement.append(notificationElement);
|
|
43887
43671
|
triggerElement.append(triggerButtonElement);
|
|
43888
43672
|
triggerElement.appendTo(globalPendo.dom.getBody());
|
|
@@ -43906,7 +43690,7 @@ function Feedback() {
|
|
|
43906
43690
|
iframeWrapper.css(getWidgetOriginalStyles());
|
|
43907
43691
|
iframeWrapper.attr('id', elemIds.feedbackWidget);
|
|
43908
43692
|
iframeWrapper.attr('data-turbolinks-permanent', 'true');
|
|
43909
|
-
iframeWrapper.addClass(
|
|
43693
|
+
iframeWrapper.addClass(`buttonIs-${horizontalPosition}`);
|
|
43910
43694
|
return iframeWrapper;
|
|
43911
43695
|
}
|
|
43912
43696
|
function buildIframeContainer() {
|
|
@@ -43923,13 +43707,22 @@ function Feedback() {
|
|
|
43923
43707
|
return iframeContainer;
|
|
43924
43708
|
}
|
|
43925
43709
|
function addWidgetVisibleButtonStyles(buttonStylePosition) {
|
|
43926
|
-
|
|
43927
|
-
|
|
43710
|
+
let side = buttonStylePosition === 'left' ? 'left' : 'right'; // just in case something was not left or right for some reason
|
|
43711
|
+
const styles = `
|
|
43712
|
+
.buttonIs-${side}.visible {
|
|
43713
|
+
${side}: 0 !important;
|
|
43714
|
+
width: 470px !important;
|
|
43715
|
+
animation-direction: alternate-reverse !important;
|
|
43716
|
+
animation: pendoFeedbackSlideFrom-${side} 0.5s 0s 1 alternate both !important;
|
|
43717
|
+
-webkit-animation: pendoFeedbackSlideFrom-${side} 0.5s 0s 1 alternate both !important;
|
|
43718
|
+
z-index: 9002 !important;
|
|
43719
|
+
}
|
|
43720
|
+
`;
|
|
43928
43721
|
pluginApi.util.addInlineStyles(elemIds.feedbackFrameStyles, styles);
|
|
43929
43722
|
}
|
|
43930
43723
|
function initialiseWidgetFrame(horizontalPosition) {
|
|
43931
43724
|
addWidgetVisibleButtonStyles(horizontalPosition);
|
|
43932
|
-
|
|
43725
|
+
const iframeElement = buildIframeWrapper(horizontalPosition);
|
|
43933
43726
|
iframeElement.append(buildIframeContainer());
|
|
43934
43727
|
iframeElement.appendTo(globalPendo.dom.getBody());
|
|
43935
43728
|
subscribeToIframeMessages();
|
|
@@ -43953,7 +43746,7 @@ function Feedback() {
|
|
|
43953
43746
|
return widgetLoaded;
|
|
43954
43747
|
}
|
|
43955
43748
|
function getPendoOptions() {
|
|
43956
|
-
|
|
43749
|
+
let options = pluginApi.ConfigReader.getLocalConfig();
|
|
43957
43750
|
if (!globalPendo._.isObject(options))
|
|
43958
43751
|
options = {};
|
|
43959
43752
|
if (!globalPendo._.isObject(options.visitor))
|
|
@@ -43981,7 +43774,7 @@ function Feedback() {
|
|
|
43981
43774
|
return true;
|
|
43982
43775
|
}
|
|
43983
43776
|
function getQueryParam(url, paramName) {
|
|
43984
|
-
|
|
43777
|
+
const results = new RegExp('[?&]' + paramName + '=([^&#]*)').exec(url);
|
|
43985
43778
|
if (results == null) {
|
|
43986
43779
|
return null;
|
|
43987
43780
|
}
|
|
@@ -43998,13 +43791,13 @@ function Feedback() {
|
|
|
43998
43791
|
return pluginApi.q.reject();
|
|
43999
43792
|
if (!canInitFeedback(pendoOptions))
|
|
44000
43793
|
return pluginApi.q.reject();
|
|
44001
|
-
|
|
43794
|
+
const feedbackOptions = convertPendoToFeedbackOptions(pendoOptions);
|
|
44002
43795
|
try {
|
|
44003
|
-
|
|
44004
|
-
if (
|
|
43796
|
+
const fdbkDst = getQueryParam(globalPendo.url.get(), 'fdbkDst');
|
|
43797
|
+
if (fdbkDst && fdbkDst.startsWith('case')) {
|
|
44005
43798
|
initialized = true;
|
|
44006
43799
|
getFeedbackLoginUrl().then(function (loginUrl) {
|
|
44007
|
-
|
|
43800
|
+
const destinationUrl = loginUrl + '&fdbkDst=' + fdbkDst;
|
|
44008
43801
|
window.location.href = destinationUrl;
|
|
44009
43802
|
});
|
|
44010
43803
|
return;
|
|
@@ -44053,7 +43846,7 @@ function Feedback() {
|
|
|
44053
43846
|
function convertPendoToFeedbackOptions(options) {
|
|
44054
43847
|
var jwtOptions = pluginApi.agent.getJwtInfoCopy();
|
|
44055
43848
|
if (globalPendo._.isEmpty(jwtOptions)) {
|
|
44056
|
-
|
|
43849
|
+
const feedbackOptions = {};
|
|
44057
43850
|
feedbackOptions.user = globalPendo._.pick(options.visitor, 'id', 'full_name', 'firstName', 'lastName', 'email', 'tags', 'custom_allowed_products');
|
|
44058
43851
|
globalPendo._.extend(feedbackOptions.user, { allowed_products: [{ id: feedbackAllowedProductId }] });
|
|
44059
43852
|
feedbackOptions.account = globalPendo._.pick(options.account, 'id', 'name', 'monthly_value', 'is_paying', 'tags');
|
|
@@ -49643,17 +49436,6 @@ var SessionRecorderBuffer = /** @class */ (function () {
|
|
|
49643
49436
|
return SessionRecorderBuffer;
|
|
49644
49437
|
}());
|
|
49645
49438
|
|
|
49646
|
-
var __assign = function() {
|
|
49647
|
-
__assign = Object.assign || function __assign(t) {
|
|
49648
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
49649
|
-
s = arguments[i];
|
|
49650
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
|
49651
|
-
}
|
|
49652
|
-
return t;
|
|
49653
|
-
};
|
|
49654
|
-
return __assign.apply(this, arguments);
|
|
49655
|
-
};
|
|
49656
|
-
|
|
49657
49439
|
function __rest(s, e) {
|
|
49658
49440
|
var t = {};
|
|
49659
49441
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
@@ -51818,7 +51600,7 @@ function includes(str, substring) {
|
|
|
51818
51600
|
function getResourceType(blockedURI, directive) {
|
|
51819
51601
|
if (!directive || typeof directive !== 'string')
|
|
51820
51602
|
return 'resource';
|
|
51821
|
-
|
|
51603
|
+
const d = directive.toLowerCase();
|
|
51822
51604
|
if (blockedURI === 'inline') {
|
|
51823
51605
|
if (includes(d, 'script-src-attr')) {
|
|
51824
51606
|
return 'inline event handler';
|
|
@@ -51877,12 +51659,11 @@ function getResourceType(blockedURI, directive) {
|
|
|
51877
51659
|
function getDirective(policy, directiveName) {
|
|
51878
51660
|
if (!policy || !directiveName)
|
|
51879
51661
|
return '';
|
|
51880
|
-
|
|
51881
|
-
for (
|
|
51882
|
-
|
|
51883
|
-
|
|
51884
|
-
|
|
51885
|
-
if (lower === needle || lower.startsWith("".concat(needle, " "))) {
|
|
51662
|
+
const needle = directiveName.toLowerCase();
|
|
51663
|
+
for (const directive of policy.split(';')) {
|
|
51664
|
+
const trimmed = directive.trim();
|
|
51665
|
+
const lower = trimmed.toLowerCase();
|
|
51666
|
+
if (lower === needle || lower.startsWith(`${needle} `)) {
|
|
51886
51667
|
return trimmed;
|
|
51887
51668
|
}
|
|
51888
51669
|
}
|
|
@@ -51904,7 +51685,7 @@ function getDirective(policy, directiveName) {
|
|
|
51904
51685
|
function getArticle(phrase) {
|
|
51905
51686
|
if (!phrase || typeof phrase !== 'string')
|
|
51906
51687
|
return 'A';
|
|
51907
|
-
|
|
51688
|
+
const c = phrase.trim().charAt(0).toLowerCase();
|
|
51908
51689
|
return includes('aeiou', c) ? 'An' : 'A';
|
|
51909
51690
|
}
|
|
51910
51691
|
/**
|
|
@@ -51947,47 +51728,46 @@ function createCspViolationMessage(blockedURI, directive, isReportOnly, original
|
|
|
51947
51728
|
return 'Content Security Policy: Unknown violation occurred.';
|
|
51948
51729
|
}
|
|
51949
51730
|
try {
|
|
51950
|
-
|
|
51731
|
+
const reportOnlyText = isReportOnly ? ' (Report-Only)' : '';
|
|
51951
51732
|
// special case for frame-ancestors since it doesn't fit our template at all
|
|
51952
51733
|
if ((directive === null || directive === void 0 ? void 0 : directive.toLowerCase()) === 'frame-ancestors') {
|
|
51953
|
-
return
|
|
51734
|
+
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}".`;
|
|
51954
51735
|
}
|
|
51955
|
-
|
|
51956
|
-
|
|
51957
|
-
|
|
51958
|
-
|
|
51959
|
-
|
|
51960
|
-
|
|
51961
|
-
return
|
|
51736
|
+
const resourceType = getResourceType(blockedURI, directive);
|
|
51737
|
+
const article = getArticle(resourceType);
|
|
51738
|
+
const source = formatBlockedUri(blockedURI);
|
|
51739
|
+
const directiveValue = getDirective(originalPolicy, directive);
|
|
51740
|
+
const policyDisplay = directiveValue || directive;
|
|
51741
|
+
const resourceDescription = `${article} ${resourceType}${source ? ` from ${source}` : ''}`;
|
|
51742
|
+
return `Content Security Policy${reportOnlyText}: ${resourceDescription} was blocked by your site's \`${policyDisplay}\` policy.\nCurrent CSP: "${originalPolicy}".`;
|
|
51962
51743
|
}
|
|
51963
51744
|
catch (error) {
|
|
51964
|
-
return
|
|
51745
|
+
return `Content Security Policy: Error formatting violation message: ${error.message}`;
|
|
51965
51746
|
}
|
|
51966
51747
|
}
|
|
51967
51748
|
|
|
51968
|
-
|
|
51969
|
-
|
|
51749
|
+
const MAX_LENGTH = 1000;
|
|
51750
|
+
const PII_PATTERN = {
|
|
51970
51751
|
ip: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g,
|
|
51971
51752
|
ssn: /\b\d{3}-\d{2}-\d{4}\b/g,
|
|
51972
51753
|
creditCard: /\b(?:\d[ -]?){12,18}\d\b/g,
|
|
51973
51754
|
httpsUrls: /https:\/\/[^\s]+/g,
|
|
51974
51755
|
email: /[\w._+-]+@[\w.-]+\.\w+/g
|
|
51975
51756
|
};
|
|
51976
|
-
|
|
51977
|
-
|
|
51978
|
-
|
|
51979
|
-
|
|
51980
|
-
|
|
51757
|
+
const PII_REPLACEMENT = '*'.repeat(10);
|
|
51758
|
+
const JSON_PII_KEYS = ['password', 'email', 'key', 'token', 'auth', 'authentication', 'phone', 'address', 'ssn'];
|
|
51759
|
+
const UNABLE_TO_DISPLAY_BODY = '[Unable to display body: detected PII could not be redacted]';
|
|
51760
|
+
const joinedKeys = JSON_PII_KEYS.join('|');
|
|
51761
|
+
const keyPattern = `"([^"]*(?:${joinedKeys})[^"]*)"`;
|
|
51981
51762
|
// only scrub strings, numbers, and booleans
|
|
51982
|
-
|
|
51763
|
+
const acceptedValues = '("([^"\\\\]*(?:\\\\.[^"\\\\]*)*")|(\\d+)|(true|false))';
|
|
51983
51764
|
/**
|
|
51984
51765
|
* Truncates a string to the max length
|
|
51985
51766
|
* @access private
|
|
51986
51767
|
* @param {String} string
|
|
51987
51768
|
* @returns {String}
|
|
51988
51769
|
*/
|
|
51989
|
-
function truncate(string, includeEllipsis) {
|
|
51990
|
-
if (includeEllipsis === void 0) { includeEllipsis = false; }
|
|
51770
|
+
function truncate(string, includeEllipsis = false) {
|
|
51991
51771
|
if (string.length <= MAX_LENGTH)
|
|
51992
51772
|
return string;
|
|
51993
51773
|
if (includeEllipsis) {
|
|
@@ -52004,7 +51784,7 @@ function truncate(string, includeEllipsis) {
|
|
|
52004
51784
|
* @returns {String}
|
|
52005
51785
|
*/
|
|
52006
51786
|
function generateLogKey(methodName, message, stackTrace) {
|
|
52007
|
-
return
|
|
51787
|
+
return `${methodName}|${message}|${stackTrace}`;
|
|
52008
51788
|
}
|
|
52009
51789
|
/**
|
|
52010
51790
|
* Checks if a string has 2 or more digits, a https URL, or an email address
|
|
@@ -52021,13 +51801,12 @@ function mightContainPII(string) {
|
|
|
52021
51801
|
* @param {String} string
|
|
52022
51802
|
* @returns {String}
|
|
52023
51803
|
*/
|
|
52024
|
-
function scrubPII(
|
|
52025
|
-
var string = _a.string, _ = _a._;
|
|
51804
|
+
function scrubPII({ string, _ }) {
|
|
52026
51805
|
if (!string || typeof string !== 'string')
|
|
52027
51806
|
return string;
|
|
52028
51807
|
if (!mightContainPII(string))
|
|
52029
51808
|
return string;
|
|
52030
|
-
return _.reduce(_.values(PII_PATTERN),
|
|
51809
|
+
return _.reduce(_.values(PII_PATTERN), (str, pattern) => str.replace(pattern, PII_REPLACEMENT), string);
|
|
52031
51810
|
}
|
|
52032
51811
|
/**
|
|
52033
51812
|
* Scrub PII from a stringified JSON object
|
|
@@ -52036,14 +51815,12 @@ function scrubPII(_a) {
|
|
|
52036
51815
|
* @returns {String}
|
|
52037
51816
|
*/
|
|
52038
51817
|
function scrubJsonPII(string) {
|
|
52039
|
-
|
|
51818
|
+
const fullScrubRegex = new RegExp(`${keyPattern}\\s*:\\s*[\\{\\[]`, 'i');
|
|
52040
51819
|
if (fullScrubRegex.test(string)) {
|
|
52041
51820
|
return UNABLE_TO_DISPLAY_BODY;
|
|
52042
51821
|
}
|
|
52043
|
-
|
|
52044
|
-
return string.replace(keyValueScrubRegex,
|
|
52045
|
-
return "\"".concat(key, "\":\"").concat(PII_REPLACEMENT, "\"");
|
|
52046
|
-
});
|
|
51822
|
+
const keyValueScrubRegex = new RegExp(`${keyPattern}\\s*:\\s*${acceptedValues}`, 'gi');
|
|
51823
|
+
return string.replace(keyValueScrubRegex, (match, key) => `"${key}":"${PII_REPLACEMENT}"`);
|
|
52047
51824
|
}
|
|
52048
51825
|
/**
|
|
52049
51826
|
* Checks if a string is a JSON object
|
|
@@ -52055,7 +51832,7 @@ function scrubJsonPII(string) {
|
|
|
52055
51832
|
function mightContainJson(string, contentType) {
|
|
52056
51833
|
if (!string || typeof string !== 'string')
|
|
52057
51834
|
return false;
|
|
52058
|
-
|
|
51835
|
+
const firstChar = string.charAt(0);
|
|
52059
51836
|
if (contentType && contentType.indexOf('application/json') !== -1) {
|
|
52060
51837
|
return true;
|
|
52061
51838
|
}
|
|
@@ -52068,20 +51845,19 @@ function mightContainJson(string, contentType) {
|
|
|
52068
51845
|
* @param {String} contentType
|
|
52069
51846
|
* @returns {String}
|
|
52070
51847
|
*/
|
|
52071
|
-
function maskSensitiveFields(
|
|
52072
|
-
var string = _a.string, contentType = _a.contentType, _ = _a._;
|
|
51848
|
+
function maskSensitiveFields({ string, contentType, _ }) {
|
|
52073
51849
|
if (!string || typeof string !== 'string')
|
|
52074
51850
|
return string;
|
|
52075
51851
|
if (mightContainJson(string, contentType)) {
|
|
52076
51852
|
string = scrubJsonPII(string);
|
|
52077
51853
|
}
|
|
52078
51854
|
if (mightContainPII(string)) {
|
|
52079
|
-
string = scrubPII({ string
|
|
51855
|
+
string = scrubPII({ string, _ });
|
|
52080
51856
|
}
|
|
52081
51857
|
return string;
|
|
52082
51858
|
}
|
|
52083
51859
|
|
|
52084
|
-
|
|
51860
|
+
const DEV_LOG_TYPE = 'devlog';
|
|
52085
51861
|
function createDevLogEnvelope(pluginAPI, globalPendo) {
|
|
52086
51862
|
return {
|
|
52087
51863
|
browser_time: pluginAPI.util.getNow(),
|
|
@@ -52092,12 +51868,12 @@ function createDevLogEnvelope(pluginAPI, globalPendo) {
|
|
|
52092
51868
|
};
|
|
52093
51869
|
}
|
|
52094
51870
|
|
|
52095
|
-
|
|
52096
|
-
|
|
52097
|
-
|
|
52098
|
-
|
|
52099
|
-
|
|
52100
|
-
|
|
51871
|
+
const TOKEN_MAX_SIZE = 100;
|
|
51872
|
+
const TOKEN_REFILL_RATE = 10;
|
|
51873
|
+
const TOKEN_REFRESH_INTERVAL = 1000;
|
|
51874
|
+
const MAX_UNCOMPRESSED_SIZE = 125000; // 125KB
|
|
51875
|
+
class DevlogBuffer {
|
|
51876
|
+
constructor(pendo, pluginAPI) {
|
|
52101
51877
|
this.pendo = pendo;
|
|
52102
51878
|
this.pluginAPI = pluginAPI;
|
|
52103
51879
|
this.events = [];
|
|
@@ -52108,36 +51884,36 @@ var DevlogBuffer = /** @class */ (function () {
|
|
|
52108
51884
|
this.lastRefillTime = this.pluginAPI.util.getNow();
|
|
52109
51885
|
this.nextRefillTime = this.lastRefillTime + TOKEN_REFRESH_INTERVAL;
|
|
52110
51886
|
}
|
|
52111
|
-
|
|
51887
|
+
isEmpty() {
|
|
52112
51888
|
return this.events.length === 0 && this.payloads.length === 0;
|
|
52113
|
-
}
|
|
52114
|
-
|
|
52115
|
-
|
|
51889
|
+
}
|
|
51890
|
+
refillTokens() {
|
|
51891
|
+
const now = this.pluginAPI.util.getNow();
|
|
52116
51892
|
if (now >= this.nextRefillTime) {
|
|
52117
|
-
|
|
52118
|
-
|
|
52119
|
-
|
|
51893
|
+
const timeSinceLastRefill = now - this.lastRefillTime;
|
|
51894
|
+
const secondsSinceLastRefill = Math.floor(timeSinceLastRefill / TOKEN_REFRESH_INTERVAL);
|
|
51895
|
+
const tokensToRefill = secondsSinceLastRefill * TOKEN_REFILL_RATE;
|
|
52120
51896
|
this.tokens = Math.min(this.tokens + tokensToRefill, TOKEN_MAX_SIZE);
|
|
52121
51897
|
this.lastRefillTime = now;
|
|
52122
51898
|
this.nextRefillTime = now + TOKEN_REFRESH_INTERVAL;
|
|
52123
51899
|
}
|
|
52124
|
-
}
|
|
52125
|
-
|
|
51900
|
+
}
|
|
51901
|
+
clear() {
|
|
52126
51902
|
this.events = [];
|
|
52127
51903
|
this.lastEvent = null;
|
|
52128
51904
|
this.uncompressedSize = 0;
|
|
52129
|
-
}
|
|
52130
|
-
|
|
51905
|
+
}
|
|
51906
|
+
hasTokenAvailable() {
|
|
52131
51907
|
this.refillTokens();
|
|
52132
51908
|
return this.tokens > 0;
|
|
52133
|
-
}
|
|
52134
|
-
|
|
51909
|
+
}
|
|
51910
|
+
estimateEventSize(event) {
|
|
52135
51911
|
return JSON.stringify(event).length;
|
|
52136
|
-
}
|
|
52137
|
-
|
|
51912
|
+
}
|
|
51913
|
+
push(event) {
|
|
52138
51914
|
if (!this.hasTokenAvailable())
|
|
52139
51915
|
return false;
|
|
52140
|
-
|
|
51916
|
+
const eventSize = this.estimateEventSize(event);
|
|
52141
51917
|
if (this.uncompressedSize + eventSize > MAX_UNCOMPRESSED_SIZE) {
|
|
52142
51918
|
this.compressCurrentChunk();
|
|
52143
51919
|
}
|
|
@@ -52146,55 +51922,54 @@ var DevlogBuffer = /** @class */ (function () {
|
|
|
52146
51922
|
this.events.push(event);
|
|
52147
51923
|
this.tokens = Math.max(this.tokens - 1, 0);
|
|
52148
51924
|
return true;
|
|
52149
|
-
}
|
|
52150
|
-
|
|
51925
|
+
}
|
|
51926
|
+
compressCurrentChunk() {
|
|
52151
51927
|
if (this.events.length === 0)
|
|
52152
51928
|
return;
|
|
52153
|
-
|
|
51929
|
+
const jzb = this.pendo.compress(this.events);
|
|
52154
51930
|
this.payloads.push(jzb);
|
|
52155
51931
|
this.clear();
|
|
52156
|
-
}
|
|
52157
|
-
|
|
52158
|
-
|
|
51932
|
+
}
|
|
51933
|
+
generateUrl() {
|
|
51934
|
+
const queryParams = {
|
|
52159
51935
|
v: this.pendo.VERSION,
|
|
52160
51936
|
ct: this.pluginAPI.util.getNow()
|
|
52161
51937
|
};
|
|
52162
51938
|
return this.pluginAPI.transmit.buildBaseDataUrl(DEV_LOG_TYPE, this.pendo.apiKey, queryParams);
|
|
52163
|
-
}
|
|
52164
|
-
|
|
51939
|
+
}
|
|
51940
|
+
pack() {
|
|
52165
51941
|
if (this.isEmpty())
|
|
52166
51942
|
return;
|
|
52167
|
-
|
|
51943
|
+
const url = this.generateUrl();
|
|
52168
51944
|
this.compressCurrentChunk();
|
|
52169
|
-
|
|
52170
|
-
jzb
|
|
52171
|
-
url
|
|
52172
|
-
})
|
|
51945
|
+
const payloads = this.pendo._.map(this.payloads, (jzb) => ({
|
|
51946
|
+
jzb,
|
|
51947
|
+
url
|
|
51948
|
+
}));
|
|
52173
51949
|
this.payloads = [];
|
|
52174
51950
|
return payloads;
|
|
52175
|
-
}
|
|
52176
|
-
|
|
52177
|
-
}());
|
|
51951
|
+
}
|
|
51952
|
+
}
|
|
52178
51953
|
|
|
52179
|
-
|
|
52180
|
-
|
|
51954
|
+
class DevlogTransport {
|
|
51955
|
+
constructor(globalPendo, pluginAPI) {
|
|
52181
51956
|
this.pendo = globalPendo;
|
|
52182
51957
|
this.pluginAPI = pluginAPI;
|
|
52183
51958
|
}
|
|
52184
|
-
|
|
52185
|
-
|
|
51959
|
+
buildGetUrl(baseUrl, jzb) {
|
|
51960
|
+
const params = {};
|
|
52186
51961
|
if (this.pluginAPI.agent.treatAsAdoptPartner()) {
|
|
52187
51962
|
this.pluginAPI.agent.addAccountIdParams(params, this.pendo.get_account_id(), this.pluginAPI.ConfigReader.get('oemAccountId'));
|
|
52188
51963
|
}
|
|
52189
|
-
|
|
51964
|
+
const jwtOptions = this.pluginAPI.agent.getJwtInfoCopy();
|
|
52190
51965
|
if (!this.pendo._.isEmpty(jwtOptions)) {
|
|
52191
51966
|
this.pendo._.extend(params, jwtOptions);
|
|
52192
51967
|
}
|
|
52193
51968
|
params.jzb = jzb;
|
|
52194
|
-
|
|
52195
|
-
return
|
|
52196
|
-
}
|
|
52197
|
-
|
|
51969
|
+
const queryString = this.pendo._.map(params, (value, key) => `${key}=${value}`).join('&');
|
|
51970
|
+
return `${baseUrl}${baseUrl.indexOf('?') !== -1 ? '&' : '?'}${queryString}`;
|
|
51971
|
+
}
|
|
51972
|
+
get(url, options) {
|
|
52198
51973
|
options.method = 'GET';
|
|
52199
51974
|
if (this.pluginAPI.transmit.fetchKeepalive.supported()) {
|
|
52200
51975
|
return this.pluginAPI.transmit.fetchKeepalive(url, options);
|
|
@@ -52202,90 +51977,86 @@ var DevlogTransport = /** @class */ (function () {
|
|
|
52202
51977
|
else {
|
|
52203
51978
|
return this.pendo.ajax.get(url);
|
|
52204
51979
|
}
|
|
52205
|
-
}
|
|
52206
|
-
|
|
52207
|
-
|
|
52208
|
-
var getUrl = this.buildGetUrl(url, jzb);
|
|
51980
|
+
}
|
|
51981
|
+
sendRequestWithGet({ url, jzb }) {
|
|
51982
|
+
const getUrl = this.buildGetUrl(url, jzb);
|
|
52209
51983
|
return this.get(getUrl, {
|
|
52210
51984
|
headers: {
|
|
52211
51985
|
'Content-Type': 'application/octet-stream'
|
|
52212
51986
|
}
|
|
52213
51987
|
});
|
|
52214
|
-
}
|
|
52215
|
-
|
|
51988
|
+
}
|
|
51989
|
+
post(url, options) {
|
|
52216
51990
|
options.method = 'POST';
|
|
52217
51991
|
if (options.keepalive && this.pluginAPI.transmit.fetchKeepalive.supported()) {
|
|
52218
51992
|
return this.pluginAPI.transmit.fetchKeepalive(url, options);
|
|
52219
51993
|
}
|
|
52220
51994
|
else if (options.keepalive && this.pluginAPI.transmit.sendBeacon.supported()) {
|
|
52221
|
-
|
|
51995
|
+
const result = this.pluginAPI.transmit.sendBeacon(url, new Blob([options.body]));
|
|
52222
51996
|
return result ? Promise$2.resolve() : Promise$2.reject(new Error('sendBeacon failed to send devlog data'));
|
|
52223
51997
|
}
|
|
52224
51998
|
else {
|
|
52225
51999
|
return this.pendo.ajax.post(url, options.body);
|
|
52226
52000
|
}
|
|
52227
|
-
}
|
|
52228
|
-
|
|
52229
|
-
|
|
52230
|
-
|
|
52231
|
-
var bodyPayload = {
|
|
52001
|
+
}
|
|
52002
|
+
sendRequestWithPost({ url, jzb }, isUnload) {
|
|
52003
|
+
const jwtOptions = this.pluginAPI.agent.getJwtInfoCopy();
|
|
52004
|
+
const bodyPayload = {
|
|
52232
52005
|
events: jzb,
|
|
52233
52006
|
browser_time: this.pluginAPI.util.getNow()
|
|
52234
52007
|
};
|
|
52235
52008
|
if (this.pluginAPI.agent.treatAsAdoptPartner()) {
|
|
52236
52009
|
this.pluginAPI.agent.addAccountIdParams(bodyPayload, this.pendo.get_account_id(), this.pluginAPI.ConfigReader.get('oemAccountId'));
|
|
52237
52010
|
}
|
|
52238
|
-
|
|
52011
|
+
const body = JSON.stringify(this.pendo._.extend(bodyPayload, jwtOptions));
|
|
52239
52012
|
return this.post(url, {
|
|
52240
|
-
body
|
|
52013
|
+
body,
|
|
52241
52014
|
headers: {
|
|
52242
52015
|
'Content-Type': 'application/json'
|
|
52243
52016
|
},
|
|
52244
52017
|
keepalive: isUnload
|
|
52245
52018
|
});
|
|
52246
|
-
}
|
|
52247
|
-
|
|
52248
|
-
|
|
52249
|
-
var compressedLength = jzb.length;
|
|
52019
|
+
}
|
|
52020
|
+
sendRequest({ url, jzb }, isUnload) {
|
|
52021
|
+
const compressedLength = jzb.length;
|
|
52250
52022
|
if (compressedLength <= this.pluginAPI.constants.ENCODED_EVENT_MAX_LENGTH && !this.pluginAPI.ConfigReader.get('sendEventsWithPostOnly')) {
|
|
52251
|
-
return this.sendRequestWithGet({ url
|
|
52023
|
+
return this.sendRequestWithGet({ url, jzb });
|
|
52252
52024
|
}
|
|
52253
|
-
return this.sendRequestWithPost({ url
|
|
52254
|
-
}
|
|
52255
|
-
|
|
52256
|
-
}());
|
|
52025
|
+
return this.sendRequestWithPost({ url, jzb }, isUnload);
|
|
52026
|
+
}
|
|
52027
|
+
}
|
|
52257
52028
|
|
|
52258
52029
|
function ConsoleCapture() {
|
|
52259
|
-
|
|
52260
|
-
|
|
52261
|
-
|
|
52262
|
-
|
|
52263
|
-
|
|
52264
|
-
|
|
52265
|
-
|
|
52266
|
-
|
|
52267
|
-
|
|
52268
|
-
|
|
52269
|
-
|
|
52270
|
-
|
|
52030
|
+
let pluginAPI;
|
|
52031
|
+
let _;
|
|
52032
|
+
let globalPendo;
|
|
52033
|
+
let buffer;
|
|
52034
|
+
let sendQueue;
|
|
52035
|
+
let sendInterval;
|
|
52036
|
+
let transport;
|
|
52037
|
+
let isPtmPaused;
|
|
52038
|
+
let isCapturingConsoleLogs = false;
|
|
52039
|
+
const CAPTURE_CONSOLE_CONFIG = 'captureConsoleLogs';
|
|
52040
|
+
const CONSOLE_METHODS = ['log', 'warn', 'error', 'info'];
|
|
52041
|
+
const DEV_LOG_SUB_TYPE = 'console';
|
|
52271
52042
|
// deduplicate logs
|
|
52272
|
-
|
|
52043
|
+
let lastLogKey = '';
|
|
52273
52044
|
return {
|
|
52274
52045
|
name: 'ConsoleCapture',
|
|
52275
|
-
initialize
|
|
52276
|
-
teardown
|
|
52277
|
-
addIntercepts
|
|
52278
|
-
createConsoleEvent
|
|
52279
|
-
captureStackTrace
|
|
52280
|
-
send
|
|
52281
|
-
setCaptureState
|
|
52282
|
-
recordingStarted
|
|
52283
|
-
recordingStopped
|
|
52284
|
-
onAppHidden
|
|
52285
|
-
onAppUnloaded
|
|
52286
|
-
onPtmPaused
|
|
52287
|
-
onPtmUnpaused
|
|
52288
|
-
securityPolicyViolationFn
|
|
52046
|
+
initialize,
|
|
52047
|
+
teardown,
|
|
52048
|
+
addIntercepts,
|
|
52049
|
+
createConsoleEvent,
|
|
52050
|
+
captureStackTrace,
|
|
52051
|
+
send,
|
|
52052
|
+
setCaptureState,
|
|
52053
|
+
recordingStarted,
|
|
52054
|
+
recordingStopped,
|
|
52055
|
+
onAppHidden,
|
|
52056
|
+
onAppUnloaded,
|
|
52057
|
+
onPtmPaused,
|
|
52058
|
+
onPtmUnpaused,
|
|
52059
|
+
securityPolicyViolationFn,
|
|
52289
52060
|
get isCapturingConsoleLogs() {
|
|
52290
52061
|
return isCapturingConsoleLogs;
|
|
52291
52062
|
},
|
|
@@ -52302,16 +52073,16 @@ function ConsoleCapture() {
|
|
|
52302
52073
|
function initialize(pendo, PluginAPI) {
|
|
52303
52074
|
_ = pendo._;
|
|
52304
52075
|
pluginAPI = PluginAPI;
|
|
52305
|
-
|
|
52076
|
+
const { ConfigReader } = pluginAPI;
|
|
52306
52077
|
ConfigReader.addOption(CAPTURE_CONSOLE_CONFIG, [ConfigReader.sources.PENDO_CONFIG_SRC], false);
|
|
52307
|
-
|
|
52078
|
+
const captureConsoleEnabled = ConfigReader.get(CAPTURE_CONSOLE_CONFIG);
|
|
52308
52079
|
if (!captureConsoleEnabled)
|
|
52309
52080
|
return;
|
|
52310
52081
|
globalPendo = pendo;
|
|
52311
52082
|
buffer = new DevlogBuffer(pendo, pluginAPI);
|
|
52312
52083
|
transport = new DevlogTransport(pendo, pluginAPI);
|
|
52313
52084
|
sendQueue = new pluginAPI.SendQueue(transport.sendRequest.bind(transport));
|
|
52314
|
-
sendInterval = setInterval(
|
|
52085
|
+
sendInterval = setInterval(() => {
|
|
52315
52086
|
if (!sendQueue.failed()) {
|
|
52316
52087
|
send();
|
|
52317
52088
|
}
|
|
@@ -52337,19 +52108,17 @@ function ConsoleCapture() {
|
|
|
52337
52108
|
function onPtmUnpaused() {
|
|
52338
52109
|
isPtmPaused = false;
|
|
52339
52110
|
if (!buffer.isEmpty()) {
|
|
52340
|
-
for (
|
|
52341
|
-
|
|
52342
|
-
pluginAPI.Events.eventCaptured.trigger(event_1);
|
|
52111
|
+
for (const event of buffer.events) {
|
|
52112
|
+
pluginAPI.Events.eventCaptured.trigger(event);
|
|
52343
52113
|
}
|
|
52344
52114
|
send();
|
|
52345
52115
|
}
|
|
52346
52116
|
}
|
|
52347
|
-
function setCaptureState(
|
|
52348
|
-
var _b = _a === void 0 ? {} : _a, _c = _b.shouldCapture, shouldCapture = _c === void 0 ? false : _c, _d = _b.reason, reason = _d === void 0 ? '' : _d;
|
|
52117
|
+
function setCaptureState({ shouldCapture = false, reason = '' } = {}) {
|
|
52349
52118
|
if (shouldCapture === isCapturingConsoleLogs)
|
|
52350
52119
|
return;
|
|
52351
52120
|
isCapturingConsoleLogs = shouldCapture;
|
|
52352
|
-
pluginAPI.log.info(
|
|
52121
|
+
pluginAPI.log.info(`[ConsoleCapture] Console log capture ${shouldCapture ? 'started' : 'stopped'}${reason ? `: ${reason}` : ''}`);
|
|
52353
52122
|
}
|
|
52354
52123
|
function recordingStarted() {
|
|
52355
52124
|
setCaptureState({ shouldCapture: true, reason: 'recording started' });
|
|
@@ -52369,12 +52138,12 @@ function ConsoleCapture() {
|
|
|
52369
52138
|
}
|
|
52370
52139
|
function addIntercepts() {
|
|
52371
52140
|
_.each(CONSOLE_METHODS, function (methodName) {
|
|
52372
|
-
|
|
52141
|
+
const originalMethod = console[methodName];
|
|
52373
52142
|
if (!originalMethod)
|
|
52374
52143
|
return;
|
|
52375
52144
|
console[methodName] = _.wrap(originalMethod, function (originalFn) {
|
|
52376
52145
|
// slice 1 to omit originalFn
|
|
52377
|
-
|
|
52146
|
+
const args = _.toArray(arguments).slice(1);
|
|
52378
52147
|
originalFn.apply(console, args);
|
|
52379
52148
|
createConsoleEvent(args, methodName);
|
|
52380
52149
|
});
|
|
@@ -52386,10 +52155,10 @@ function ConsoleCapture() {
|
|
|
52386
52155
|
function securityPolicyViolationFn(evt) {
|
|
52387
52156
|
if (!evt || typeof evt !== 'object')
|
|
52388
52157
|
return;
|
|
52389
|
-
|
|
52390
|
-
|
|
52391
|
-
|
|
52392
|
-
|
|
52158
|
+
const { blockedURI, violatedDirective, effectiveDirective, disposition, originalPolicy } = evt;
|
|
52159
|
+
const directive = violatedDirective || effectiveDirective;
|
|
52160
|
+
const isReportOnly = disposition === 'report';
|
|
52161
|
+
const message = createCspViolationMessage(blockedURI, directive, isReportOnly, originalPolicy);
|
|
52393
52162
|
if (isReportOnly) {
|
|
52394
52163
|
createConsoleEvent([message], 'warn', { skipStackTrace: true, skipScrubPII: true });
|
|
52395
52164
|
}
|
|
@@ -52397,13 +52166,12 @@ function ConsoleCapture() {
|
|
|
52397
52166
|
createConsoleEvent([message], 'error', { skipStackTrace: true, skipScrubPII: true });
|
|
52398
52167
|
}
|
|
52399
52168
|
}
|
|
52400
|
-
function createConsoleEvent(args, methodName,
|
|
52401
|
-
var _b = _a === void 0 ? {} : _a, _c = _b.skipStackTrace, skipStackTrace = _c === void 0 ? false : _c, _d = _b.skipScrubPII, skipScrubPII = _d === void 0 ? false : _d;
|
|
52169
|
+
function createConsoleEvent(args, methodName, { skipStackTrace = false, skipScrubPII = false } = {}) {
|
|
52402
52170
|
if (!isCapturingConsoleLogs || !args || args.length === 0 || !_.contains(CONSOLE_METHODS, methodName))
|
|
52403
52171
|
return;
|
|
52404
52172
|
// stringify args
|
|
52405
|
-
|
|
52406
|
-
|
|
52173
|
+
let message = _.compact(_.map(args, arg => {
|
|
52174
|
+
let stringifiedArg;
|
|
52407
52175
|
try {
|
|
52408
52176
|
stringifiedArg = stringify(arg);
|
|
52409
52177
|
}
|
|
@@ -52415,22 +52183,22 @@ function ConsoleCapture() {
|
|
|
52415
52183
|
if (!message)
|
|
52416
52184
|
return;
|
|
52417
52185
|
// capture stack trace
|
|
52418
|
-
|
|
52186
|
+
let stackTrace = '';
|
|
52419
52187
|
if (!skipStackTrace) {
|
|
52420
|
-
|
|
52188
|
+
const maxStackFrames = methodName === 'error' ? 4 : 1;
|
|
52421
52189
|
stackTrace = captureStackTrace(maxStackFrames);
|
|
52422
52190
|
}
|
|
52423
52191
|
// truncate message and stack trace
|
|
52424
52192
|
message = truncate(message);
|
|
52425
52193
|
stackTrace = truncate(stackTrace);
|
|
52426
52194
|
// de-duplicate log
|
|
52427
|
-
|
|
52195
|
+
const logKey = generateLogKey(methodName, message, stackTrace);
|
|
52428
52196
|
if (isExistingDuplicateLog(logKey)) {
|
|
52429
52197
|
buffer.lastEvent.devLogCount++;
|
|
52430
52198
|
return;
|
|
52431
52199
|
}
|
|
52432
|
-
|
|
52433
|
-
|
|
52200
|
+
const devLogEnvelope = createDevLogEnvelope(pluginAPI, globalPendo);
|
|
52201
|
+
const consoleEvent = Object.assign(Object.assign({}, devLogEnvelope), { subType: DEV_LOG_SUB_TYPE, devLogLevel: methodName === 'log' ? 'info' : methodName, devLogMessage: skipScrubPII ? message : scrubPII({ string: message, _ }), devLogTrace: stackTrace, devLogCount: 1 });
|
|
52434
52202
|
if (!buffer.hasTokenAvailable())
|
|
52435
52203
|
return consoleEvent;
|
|
52436
52204
|
if (!isPtmPaused) {
|
|
@@ -52442,8 +52210,8 @@ function ConsoleCapture() {
|
|
|
52442
52210
|
}
|
|
52443
52211
|
function captureStackTrace(maxStackFrames) {
|
|
52444
52212
|
try {
|
|
52445
|
-
|
|
52446
|
-
return _.map(stackFrames,
|
|
52213
|
+
const stackFrames = ErrorStackParser.parse(new Error(), maxStackFrames);
|
|
52214
|
+
return _.map(stackFrames, frame => frame.toString()).join('\n');
|
|
52447
52215
|
}
|
|
52448
52216
|
catch (error) {
|
|
52449
52217
|
return '';
|
|
@@ -52455,22 +52223,21 @@ function ConsoleCapture() {
|
|
|
52455
52223
|
function updateLastLog(logKey) {
|
|
52456
52224
|
lastLogKey = logKey;
|
|
52457
52225
|
}
|
|
52458
|
-
function send(
|
|
52459
|
-
var _b = _a === void 0 ? {} : _a, _c = _b.unload, unload = _c === void 0 ? false : _c, _d = _b.hidden, hidden = _d === void 0 ? false : _d;
|
|
52226
|
+
function send({ unload = false, hidden = false } = {}) {
|
|
52460
52227
|
if (!buffer || buffer.isEmpty())
|
|
52461
52228
|
return;
|
|
52462
52229
|
if (!globalPendo.isSendingEvents()) {
|
|
52463
52230
|
buffer.clear();
|
|
52464
52231
|
return;
|
|
52465
52232
|
}
|
|
52466
|
-
|
|
52233
|
+
const payloads = buffer.pack();
|
|
52467
52234
|
if (!payloads || payloads.length === 0)
|
|
52468
52235
|
return;
|
|
52469
52236
|
if (unload || hidden) {
|
|
52470
52237
|
sendQueue.drain(payloads, unload);
|
|
52471
52238
|
}
|
|
52472
52239
|
else {
|
|
52473
|
-
sendQueue.push
|
|
52240
|
+
sendQueue.push(...payloads);
|
|
52474
52241
|
}
|
|
52475
52242
|
}
|
|
52476
52243
|
function teardown() {
|
|
@@ -52494,7 +52261,7 @@ function ConsoleCapture() {
|
|
|
52494
52261
|
_.each(CONSOLE_METHODS, function (methodName) {
|
|
52495
52262
|
if (!console[methodName])
|
|
52496
52263
|
return _.noop;
|
|
52497
|
-
|
|
52264
|
+
const unwrap = console[methodName]._pendoUnwrap;
|
|
52498
52265
|
if (_.isFunction(unwrap)) {
|
|
52499
52266
|
unwrap();
|
|
52500
52267
|
}
|
|
@@ -53285,4 +53052,500 @@ const PredictGuides = () => {
|
|
|
53285
53052
|
};
|
|
53286
53053
|
};
|
|
53287
53054
|
|
|
53288
|
-
|
|
53055
|
+
const ASSISTANT_MESSAGE = 'assistantMessage';
|
|
53056
|
+
const CONVERSATION_ID_URL_PATTERN = 'conversationIdUrlPattern';
|
|
53057
|
+
const MESSAGE_ID_ATTR = 'messageIdAttr';
|
|
53058
|
+
const MODEL_USED_ATTR = 'modelUsedAttr';
|
|
53059
|
+
const REACTION_ACTIVE = 'reactionActive';
|
|
53060
|
+
const STREAMING_ACTIVE = 'streamingActive';
|
|
53061
|
+
const STREAMING_ACTIVE_ATTR = 'streamingActiveAttr';
|
|
53062
|
+
const THUMB_DOWN = 'thumbDown';
|
|
53063
|
+
const THUMB_UP = 'thumbUp';
|
|
53064
|
+
const TURN_CONTAINER = 'turnContainer';
|
|
53065
|
+
const TURN_ATTR = 'turnAttr';
|
|
53066
|
+
const USER_MESSAGE = 'userMessage';
|
|
53067
|
+
const CUSTOM_AGENT_ID_URL_PATTERN = 'customAgentIdUrlPattern';
|
|
53068
|
+
const CUSTOM_AGENT_NAME = 'customAgentName';
|
|
53069
|
+
const REQUIRED_SELECTORS = [
|
|
53070
|
+
ASSISTANT_MESSAGE,
|
|
53071
|
+
CONVERSATION_ID_URL_PATTERN,
|
|
53072
|
+
MESSAGE_ID_ATTR,
|
|
53073
|
+
STREAMING_ACTIVE,
|
|
53074
|
+
TURN_CONTAINER,
|
|
53075
|
+
TURN_ATTR,
|
|
53076
|
+
USER_MESSAGE
|
|
53077
|
+
];
|
|
53078
|
+
const STREAMING_END_SETTLE_MS = 500;
|
|
53079
|
+
const SUBMISSION_START_RETRY_MS = 1000;
|
|
53080
|
+
const SUBMISSION_START_MAX_ATTEMPTS = 4;
|
|
53081
|
+
class DOMConversation {
|
|
53082
|
+
// Returns the list of required selector types that are missing or empty
|
|
53083
|
+
// in the given cssSelectors config. An empty array means the config is
|
|
53084
|
+
// valid for instantiation.
|
|
53085
|
+
static validateConfig(cssSelectors) {
|
|
53086
|
+
if (!Array.isArray(cssSelectors)) {
|
|
53087
|
+
return REQUIRED_SELECTORS.slice();
|
|
53088
|
+
}
|
|
53089
|
+
const present = new Set();
|
|
53090
|
+
for (const cfg of cssSelectors) {
|
|
53091
|
+
if (!cfg || !cfg.type || !cfg.cssSelector)
|
|
53092
|
+
continue;
|
|
53093
|
+
if (cfg.type === CONVERSATION_ID_URL_PATTERN) {
|
|
53094
|
+
try {
|
|
53095
|
+
RegExp(cfg.cssSelector);
|
|
53096
|
+
}
|
|
53097
|
+
catch (e) {
|
|
53098
|
+
continue;
|
|
53099
|
+
}
|
|
53100
|
+
}
|
|
53101
|
+
present.add(cfg.type);
|
|
53102
|
+
}
|
|
53103
|
+
return REQUIRED_SELECTORS.filter((r) => !present.has(r));
|
|
53104
|
+
}
|
|
53105
|
+
static supportedPreset(preset) {
|
|
53106
|
+
return preset === 'chatgpt-full';
|
|
53107
|
+
}
|
|
53108
|
+
constructor(pendo, PluginAPI, id, privacyFilters, cssSelectors) {
|
|
53109
|
+
this.selectors = {};
|
|
53110
|
+
this.listeners = [];
|
|
53111
|
+
this.isActive = true;
|
|
53112
|
+
this.observers = [];
|
|
53113
|
+
this.wasStreaming = false;
|
|
53114
|
+
this.streamingEndTimer = null;
|
|
53115
|
+
this.submissionStartRetryTimer = null;
|
|
53116
|
+
this.requestNode = null;
|
|
53117
|
+
this.conversationIdRegex = null;
|
|
53118
|
+
this.customAgentIdRegex = null;
|
|
53119
|
+
this.lastReturnedMessageId = null;
|
|
53120
|
+
this.dom = pendo.dom;
|
|
53121
|
+
this._ = pendo._;
|
|
53122
|
+
this.api = PluginAPI;
|
|
53123
|
+
this.Sizzle = pendo.Sizzle;
|
|
53124
|
+
this.id = id;
|
|
53125
|
+
this.setFilters(privacyFilters);
|
|
53126
|
+
if (!this._.isArray(cssSelectors)) {
|
|
53127
|
+
this.api.log.error(`cssSelectors must be an array, received: ${typeof cssSelectors}`);
|
|
53128
|
+
cssSelectors = [];
|
|
53129
|
+
}
|
|
53130
|
+
this._.each(cssSelectors, (cfg) => {
|
|
53131
|
+
if (cfg && cfg.type) {
|
|
53132
|
+
this.selectors[cfg.type] = cfg.cssSelector;
|
|
53133
|
+
}
|
|
53134
|
+
});
|
|
53135
|
+
this.conversationIdRegex = new RegExp(this.selectors[CONVERSATION_ID_URL_PATTERN]);
|
|
53136
|
+
const customAgentIdUrlPattern = this.selectors[CUSTOM_AGENT_ID_URL_PATTERN];
|
|
53137
|
+
if (customAgentIdUrlPattern) { // this is optional
|
|
53138
|
+
try {
|
|
53139
|
+
this.customAgentIdRegex = new RegExp(customAgentIdUrlPattern);
|
|
53140
|
+
}
|
|
53141
|
+
catch (error) {
|
|
53142
|
+
this.api.log.error(`bad customAgentIdUrlPattern ${customAgentIdUrlPattern}`, { error });
|
|
53143
|
+
}
|
|
53144
|
+
}
|
|
53145
|
+
this.root = document.body;
|
|
53146
|
+
this.setupReactionListener();
|
|
53147
|
+
this.setupStreamingObserver();
|
|
53148
|
+
}
|
|
53149
|
+
setupReactionListener() {
|
|
53150
|
+
if (!this.findSelector(THUMB_UP) && !this.findSelector(THUMB_DOWN))
|
|
53151
|
+
return;
|
|
53152
|
+
this.reactionClickHandler = this.handleReactionClick.bind(this);
|
|
53153
|
+
this.root.addEventListener('click', this.reactionClickHandler, true);
|
|
53154
|
+
}
|
|
53155
|
+
handleReactionClick(evt) {
|
|
53156
|
+
const target = evt.target;
|
|
53157
|
+
if (!target || target.nodeType !== 1)
|
|
53158
|
+
return;
|
|
53159
|
+
const upSelector = this.findSelector(THUMB_UP);
|
|
53160
|
+
const downSelector = this.findSelector(THUMB_DOWN);
|
|
53161
|
+
const thumb = this.dom(target).closest(`${upSelector}, ${downSelector}`);
|
|
53162
|
+
if (!thumb.length)
|
|
53163
|
+
return;
|
|
53164
|
+
const isUp = this.Sizzle.matchesSelector(thumb[0], upSelector);
|
|
53165
|
+
const activeSelector = this.findSelector(REACTION_ACTIVE);
|
|
53166
|
+
const wasPressed = activeSelector && this.Sizzle.matchesSelector(thumb[0], activeSelector);
|
|
53167
|
+
const direction = isUp ? 'positive' : 'negative';
|
|
53168
|
+
const content = wasPressed ? 'unreact' : direction;
|
|
53169
|
+
const assistantNode = thumb.closest(this.findSelector(TURN_CONTAINER))
|
|
53170
|
+
.find(this.findSelector(ASSISTANT_MESSAGE));
|
|
53171
|
+
this.emit('user_reaction', {
|
|
53172
|
+
agentId: this.id,
|
|
53173
|
+
messageId: this.getMessageId(assistantNode),
|
|
53174
|
+
content,
|
|
53175
|
+
privacyFilterApplied: false
|
|
53176
|
+
});
|
|
53177
|
+
}
|
|
53178
|
+
// observe the streaming indicator
|
|
53179
|
+
setupStreamingObserver() {
|
|
53180
|
+
this.wasStreaming = this.select(STREAMING_ACTIVE).length > 0;
|
|
53181
|
+
this.stopStreamingEndTimer();
|
|
53182
|
+
const MutationObserver = getZoneSafeMethod(this._, 'MutationObserver');
|
|
53183
|
+
const observer = new MutationObserver(this.handleMutation.bind(this));
|
|
53184
|
+
const attrName = this.findSelector(STREAMING_ACTIVE_ATTR);
|
|
53185
|
+
observer.observe(this.root, {
|
|
53186
|
+
childList: true,
|
|
53187
|
+
subtree: true,
|
|
53188
|
+
attributes: true,
|
|
53189
|
+
attributeFilter: attrName ? [attrName] : undefined
|
|
53190
|
+
});
|
|
53191
|
+
this.observers.push(observer);
|
|
53192
|
+
}
|
|
53193
|
+
// look for changes in the state of the streaming indicator.
|
|
53194
|
+
// streaming started -> a prompt has been submitted
|
|
53195
|
+
// streaming ended -> got a response
|
|
53196
|
+
// we don't send the prompt immediately when it's submitted because it might not have a
|
|
53197
|
+
// conversation id yet.
|
|
53198
|
+
// we don't send the agent_response immediately when the streaming indicator is cleared
|
|
53199
|
+
// because it clears slightly before the final text chunk is committed to the DOM so the
|
|
53200
|
+
// end-handling is deferred by a short settle window
|
|
53201
|
+
handleMutation() {
|
|
53202
|
+
const isStreaming = this.select(STREAMING_ACTIVE).length > 0;
|
|
53203
|
+
if (isStreaming === this.wasStreaming)
|
|
53204
|
+
return;
|
|
53205
|
+
if (isStreaming) { // started streaming
|
|
53206
|
+
if (!this.streamingEndTimer) {
|
|
53207
|
+
this.onSubmissionStart();
|
|
53208
|
+
}
|
|
53209
|
+
else {
|
|
53210
|
+
// stream restarted during the settle window (multi-phase response).
|
|
53211
|
+
// treat as a continuation of the prior request, not a new submission.
|
|
53212
|
+
// we'll handle it next time streaming stops
|
|
53213
|
+
this.stopStreamingEndTimer();
|
|
53214
|
+
}
|
|
53215
|
+
}
|
|
53216
|
+
else { // finished streaming
|
|
53217
|
+
this.startStreamingEndTimer();
|
|
53218
|
+
}
|
|
53219
|
+
this.wasStreaming = isStreaming;
|
|
53220
|
+
}
|
|
53221
|
+
onSubmissionStart(attempt = 1) {
|
|
53222
|
+
this.requestNode = this.findLastRequestNode();
|
|
53223
|
+
if (this.requestNode) {
|
|
53224
|
+
this.handleUserMessage(this.requestNode);
|
|
53225
|
+
return;
|
|
53226
|
+
}
|
|
53227
|
+
// URL hasn't flipped yet to include the conversation id on a fresh chat
|
|
53228
|
+
// retry, if that still fails, onSubmissionEnd handles it
|
|
53229
|
+
if (attempt < SUBMISSION_START_MAX_ATTEMPTS) {
|
|
53230
|
+
this.startSubmissionStartRetryTimer(attempt + 1);
|
|
53231
|
+
}
|
|
53232
|
+
}
|
|
53233
|
+
onSubmissionEnd() {
|
|
53234
|
+
this.stopSubmissionStartRetryTimer();
|
|
53235
|
+
let requestNode = this.requestNode;
|
|
53236
|
+
this.requestNode = null;
|
|
53237
|
+
if (!requestNode) {
|
|
53238
|
+
// onSubmissionStart didn't send, send it now
|
|
53239
|
+
requestNode = this.findLastRequestNode();
|
|
53240
|
+
if (!requestNode)
|
|
53241
|
+
return;
|
|
53242
|
+
this.handleUserMessage(requestNode);
|
|
53243
|
+
}
|
|
53244
|
+
const requestTurn = this.findTurnNumber(requestNode);
|
|
53245
|
+
if (requestTurn === null)
|
|
53246
|
+
return;
|
|
53247
|
+
const assistantNodes = this.select(ASSISTANT_MESSAGE);
|
|
53248
|
+
const toEmit = [];
|
|
53249
|
+
for (let i = assistantNodes.length - 1; i >= 0; i--) {
|
|
53250
|
+
const n = this.findTurnNumber(this.dom(assistantNodes[i]));
|
|
53251
|
+
if (n === null)
|
|
53252
|
+
continue;
|
|
53253
|
+
if (n <= requestTurn)
|
|
53254
|
+
break;
|
|
53255
|
+
toEmit.push(assistantNodes[i]);
|
|
53256
|
+
}
|
|
53257
|
+
// emit in chronological order (reverse of collection order)
|
|
53258
|
+
for (let i = toEmit.length - 1; i >= 0; i--) {
|
|
53259
|
+
this.handleAssistantMessage(this.dom(toEmit[i]));
|
|
53260
|
+
}
|
|
53261
|
+
}
|
|
53262
|
+
extractContent(node) {
|
|
53263
|
+
const rawContent = node.text().trim();
|
|
53264
|
+
const content = this.applyPrivacyFilter(rawContent);
|
|
53265
|
+
return { content, privacyFilterApplied: content !== rawContent };
|
|
53266
|
+
}
|
|
53267
|
+
getMessageId(node) {
|
|
53268
|
+
return node.attr(this.findSelector(MESSAGE_ID_ATTR));
|
|
53269
|
+
}
|
|
53270
|
+
handleUserMessage(node) {
|
|
53271
|
+
this.emit('prompt', Object.assign({ agentId: this.id, messageId: this.getMessageId(node) }, this.extractContent(node)));
|
|
53272
|
+
}
|
|
53273
|
+
handleAssistantMessage(node) {
|
|
53274
|
+
const modelUsedAttr = this.findSelector(MODEL_USED_ATTR);
|
|
53275
|
+
const modelUsed = modelUsedAttr && node.attr(modelUsedAttr);
|
|
53276
|
+
this.emit('agent_response', Object.assign({ agentId: this.id, messageId: this.getMessageId(node), agentModelsUsed: modelUsed ? [modelUsed] : [] }, this.extractContent(node)));
|
|
53277
|
+
}
|
|
53278
|
+
findLastRequestNode() {
|
|
53279
|
+
if (!this.getConversationId())
|
|
53280
|
+
return null;
|
|
53281
|
+
const node = this._.last(this.select(USER_MESSAGE));
|
|
53282
|
+
if (!node)
|
|
53283
|
+
return null;
|
|
53284
|
+
const $node = this.dom(node);
|
|
53285
|
+
const messageId = this.getMessageId($node);
|
|
53286
|
+
if (!messageId)
|
|
53287
|
+
return null;
|
|
53288
|
+
if (messageId === this.lastReturnedMessageId)
|
|
53289
|
+
return null;
|
|
53290
|
+
this.lastReturnedMessageId = messageId;
|
|
53291
|
+
return $node;
|
|
53292
|
+
}
|
|
53293
|
+
findTurnNumber(node) {
|
|
53294
|
+
const turnSelector = this.findSelector(TURN_CONTAINER);
|
|
53295
|
+
const turnAttr = this.findSelector(TURN_ATTR);
|
|
53296
|
+
const turn = node.closest(turnSelector).attr(turnAttr);
|
|
53297
|
+
if (!turn)
|
|
53298
|
+
return null;
|
|
53299
|
+
const seqMatch = String(turn).match(/\d+/);
|
|
53300
|
+
return seqMatch ? parseInt(seqMatch[0], 10) : null;
|
|
53301
|
+
}
|
|
53302
|
+
findSelector(type) {
|
|
53303
|
+
return this.selectors[type];
|
|
53304
|
+
}
|
|
53305
|
+
select(type) {
|
|
53306
|
+
return this.dom(this.findSelector(type), this.root);
|
|
53307
|
+
}
|
|
53308
|
+
getConversationId() {
|
|
53309
|
+
const m = location.href.match(this.conversationIdRegex);
|
|
53310
|
+
if (!m)
|
|
53311
|
+
return null;
|
|
53312
|
+
return m[1] !== undefined ? m[1] : m[0];
|
|
53313
|
+
}
|
|
53314
|
+
getCustomAgentId() {
|
|
53315
|
+
if (!this.customAgentIdRegex)
|
|
53316
|
+
return undefined;
|
|
53317
|
+
const m = location.href.match(this.customAgentIdRegex);
|
|
53318
|
+
if (!m)
|
|
53319
|
+
return undefined;
|
|
53320
|
+
return m[1] !== undefined ? m[1] : m[0];
|
|
53321
|
+
}
|
|
53322
|
+
getCustomAgentName() {
|
|
53323
|
+
if (!this.findSelector(CUSTOM_AGENT_NAME))
|
|
53324
|
+
return '';
|
|
53325
|
+
const node = this.select(CUSTOM_AGENT_NAME);
|
|
53326
|
+
if (!node.length)
|
|
53327
|
+
return '';
|
|
53328
|
+
return node.text().trim();
|
|
53329
|
+
}
|
|
53330
|
+
addCustomAgentInfo(eventPayload) {
|
|
53331
|
+
const customAgentId = this.getCustomAgentId();
|
|
53332
|
+
if (!customAgentId)
|
|
53333
|
+
return;
|
|
53334
|
+
eventPayload.customAgentId = customAgentId;
|
|
53335
|
+
const customAgentName = this.getCustomAgentName();
|
|
53336
|
+
if (customAgentName) {
|
|
53337
|
+
eventPayload.customAgentName = customAgentName;
|
|
53338
|
+
}
|
|
53339
|
+
}
|
|
53340
|
+
setFilters(candidateFilter) {
|
|
53341
|
+
if (!candidateFilter) {
|
|
53342
|
+
this.privacyFilters = null;
|
|
53343
|
+
return null;
|
|
53344
|
+
}
|
|
53345
|
+
try {
|
|
53346
|
+
this.privacyFilters = new RegExp(candidateFilter, 'gmi');
|
|
53347
|
+
}
|
|
53348
|
+
catch (e) {
|
|
53349
|
+
this.privacyFilters = null;
|
|
53350
|
+
this.api.log.error(e);
|
|
53351
|
+
}
|
|
53352
|
+
return this.privacyFilters;
|
|
53353
|
+
}
|
|
53354
|
+
applyPrivacyFilter(candidateValue, filters = null) {
|
|
53355
|
+
const filtersToUse = filters || this.privacyFilters;
|
|
53356
|
+
if (!filtersToUse || !this._.isRegExp(filtersToUse))
|
|
53357
|
+
return candidateValue;
|
|
53358
|
+
return candidateValue.replace(filtersToUse, 'redacted');
|
|
53359
|
+
}
|
|
53360
|
+
onSubmit(callback) {
|
|
53361
|
+
this.listeners.push(callback);
|
|
53362
|
+
}
|
|
53363
|
+
emit(eventType, eventPayload) {
|
|
53364
|
+
eventPayload.conversationId = this.getConversationId();
|
|
53365
|
+
this.addCustomAgentInfo(eventPayload);
|
|
53366
|
+
this._.each(this.listeners, (cb) => cb(eventType, eventPayload));
|
|
53367
|
+
}
|
|
53368
|
+
startStreamingEndTimer() {
|
|
53369
|
+
this.stopStreamingEndTimer();
|
|
53370
|
+
this.streamingEndTimer = setTimeout$1(() => {
|
|
53371
|
+
this.streamingEndTimer = null;
|
|
53372
|
+
this.onSubmissionEnd();
|
|
53373
|
+
}, STREAMING_END_SETTLE_MS);
|
|
53374
|
+
}
|
|
53375
|
+
stopStreamingEndTimer() {
|
|
53376
|
+
if (!this.streamingEndTimer)
|
|
53377
|
+
return;
|
|
53378
|
+
clearTimeout(this.streamingEndTimer);
|
|
53379
|
+
this.streamingEndTimer = null;
|
|
53380
|
+
}
|
|
53381
|
+
startSubmissionStartRetryTimer(attempt) {
|
|
53382
|
+
this.stopSubmissionStartRetryTimer();
|
|
53383
|
+
this.submissionStartRetryTimer = setTimeout$1(() => {
|
|
53384
|
+
this.submissionStartRetryTimer = null;
|
|
53385
|
+
this.onSubmissionStart(attempt);
|
|
53386
|
+
}, SUBMISSION_START_RETRY_MS);
|
|
53387
|
+
}
|
|
53388
|
+
stopSubmissionStartRetryTimer() {
|
|
53389
|
+
if (!this.submissionStartRetryTimer)
|
|
53390
|
+
return;
|
|
53391
|
+
clearTimeout(this.submissionStartRetryTimer);
|
|
53392
|
+
this.submissionStartRetryTimer = null;
|
|
53393
|
+
}
|
|
53394
|
+
suspend() {
|
|
53395
|
+
this.isActive = false;
|
|
53396
|
+
}
|
|
53397
|
+
resume() {
|
|
53398
|
+
this.isActive = true;
|
|
53399
|
+
}
|
|
53400
|
+
teardown() {
|
|
53401
|
+
this._.each(this.observers, (o) => o && o.disconnect && o.disconnect());
|
|
53402
|
+
this.observers = [];
|
|
53403
|
+
if (this.reactionClickHandler && this.root) {
|
|
53404
|
+
this.root.removeEventListener('click', this.reactionClickHandler, true);
|
|
53405
|
+
this.reactionClickHandler = null;
|
|
53406
|
+
}
|
|
53407
|
+
this.stopStreamingEndTimer();
|
|
53408
|
+
this.stopSubmissionStartRetryTimer();
|
|
53409
|
+
this.listeners = [];
|
|
53410
|
+
}
|
|
53411
|
+
}
|
|
53412
|
+
|
|
53413
|
+
/*
|
|
53414
|
+
* Conversation Analytics Plugin
|
|
53415
|
+
*
|
|
53416
|
+
* Independent plugin that tracks AI-agent conversations rendered in the DOM.
|
|
53417
|
+
*
|
|
53418
|
+
* The sibling built-in PromptAnalytics plugin owns the network + DOMPrompt AI-agents
|
|
53419
|
+
*/
|
|
53420
|
+
function ConversationAnalytics() {
|
|
53421
|
+
let pendo;
|
|
53422
|
+
let api;
|
|
53423
|
+
let _;
|
|
53424
|
+
let log;
|
|
53425
|
+
let conversations = [];
|
|
53426
|
+
let agentsCache = new Map();
|
|
53427
|
+
const CONFIG_NAME = 'aiAgents';
|
|
53428
|
+
return {
|
|
53429
|
+
name: 'ConversationAnalytics',
|
|
53430
|
+
initialize,
|
|
53431
|
+
teardown,
|
|
53432
|
+
onConfigLoaded,
|
|
53433
|
+
observeConversation,
|
|
53434
|
+
sendConversationEvent,
|
|
53435
|
+
reEvaluatePageRules
|
|
53436
|
+
};
|
|
53437
|
+
function initialize(pendoGlobal, PluginAPI) {
|
|
53438
|
+
var _a;
|
|
53439
|
+
pendo = pendoGlobal;
|
|
53440
|
+
api = PluginAPI;
|
|
53441
|
+
_ = pendo._;
|
|
53442
|
+
log = api.log;
|
|
53443
|
+
const { ConfigReader } = api;
|
|
53444
|
+
ConfigReader.addOption(CONFIG_NAME, [
|
|
53445
|
+
ConfigReader.sources.PENDO_CONFIG_SRC,
|
|
53446
|
+
ConfigReader.sources.SNIPPET_SRC
|
|
53447
|
+
]);
|
|
53448
|
+
onConfigLoaded(ConfigReader.get(CONFIG_NAME));
|
|
53449
|
+
// Listen for URL changes to re-evaluate page rules
|
|
53450
|
+
// Listening on guidesLoaded since normalizedUrl comes back from the guides playload
|
|
53451
|
+
(_a = api.Events.guidesLoaded) === null || _a === void 0 ? void 0 : _a.on(reEvaluatePageRules);
|
|
53452
|
+
}
|
|
53453
|
+
// Test if the current URL matches the page rule for an agent. The raw matcher lives in core
|
|
53454
|
+
// and is reached through PluginAPI (independent plugins cannot import it directly); it falls
|
|
53455
|
+
// back to the normalized URL internally when no URL is passed.
|
|
53456
|
+
function testPageRule(pageRule, agentId = 'unknown') {
|
|
53457
|
+
// Convert //*/agent pattern to work with full URLs
|
|
53458
|
+
let fixedPageRule = pageRule;
|
|
53459
|
+
if (Array.isArray(pageRule)) {
|
|
53460
|
+
const validRules = _.filter(pageRule, rule => rule && rule.trim() !== '');
|
|
53461
|
+
fixedPageRule = _.map(validRules, rule => rule.startsWith('//*/') ? rule.substring(1) : rule);
|
|
53462
|
+
}
|
|
53463
|
+
else if (typeof pageRule === 'string' && pageRule.startsWith('//*/')) {
|
|
53464
|
+
fixedPageRule = pageRule.substring(1);
|
|
53465
|
+
}
|
|
53466
|
+
return api.util.testPageRule(fixedPageRule, undefined, {
|
|
53467
|
+
logger: log,
|
|
53468
|
+
context: 'agent',
|
|
53469
|
+
id: agentId
|
|
53470
|
+
});
|
|
53471
|
+
}
|
|
53472
|
+
function reEvaluatePageRules() {
|
|
53473
|
+
_.each(conversations, conversation => {
|
|
53474
|
+
const agent = findAgentById(conversation.id);
|
|
53475
|
+
const shouldBeActive = agent && testPageRule(agent.pageRule, agent.id);
|
|
53476
|
+
if (shouldBeActive) {
|
|
53477
|
+
conversation.resume();
|
|
53478
|
+
}
|
|
53479
|
+
else {
|
|
53480
|
+
conversation.suspend();
|
|
53481
|
+
}
|
|
53482
|
+
});
|
|
53483
|
+
const currentlyActiveIds = _.map(_.filter(conversations, conversation => conversation.isActive), conversation => conversation.id);
|
|
53484
|
+
const allAgents = api.ConfigReader.get(CONFIG_NAME) || [];
|
|
53485
|
+
_.each(allAgents, aiAgent => {
|
|
53486
|
+
if (!isConversationAgent(aiAgent)) {
|
|
53487
|
+
return;
|
|
53488
|
+
}
|
|
53489
|
+
const isCurrentlyActive = _.contains(currentlyActiveIds, aiAgent.id);
|
|
53490
|
+
const shouldBeActive = testPageRule(aiAgent.pageRule, aiAgent.id);
|
|
53491
|
+
if (shouldBeActive && !isCurrentlyActive) {
|
|
53492
|
+
observeConversation(aiAgent);
|
|
53493
|
+
}
|
|
53494
|
+
});
|
|
53495
|
+
}
|
|
53496
|
+
function findAgentById(agentId) {
|
|
53497
|
+
return agentsCache.get(agentId);
|
|
53498
|
+
}
|
|
53499
|
+
// Only conversation agents belong to this plugin; the rest are owned
|
|
53500
|
+
// by the built-in PromptAnalytics plugin.
|
|
53501
|
+
function isConversationAgent(agent) {
|
|
53502
|
+
return DOMConversation.supportedPreset(agent.preset);
|
|
53503
|
+
}
|
|
53504
|
+
function onConfigLoaded(aiAgents = []) {
|
|
53505
|
+
if (!aiAgents || !_.isArray(aiAgents) || aiAgents.length === 0) {
|
|
53506
|
+
return;
|
|
53507
|
+
}
|
|
53508
|
+
agentsCache.clear();
|
|
53509
|
+
_.each(aiAgents, aiAgent => {
|
|
53510
|
+
if (!isConversationAgent(aiAgent)) {
|
|
53511
|
+
return;
|
|
53512
|
+
}
|
|
53513
|
+
agentsCache.set(aiAgent.id, aiAgent);
|
|
53514
|
+
if (testPageRule(aiAgent.pageRule, aiAgent.id)) {
|
|
53515
|
+
observeConversation(aiAgent);
|
|
53516
|
+
}
|
|
53517
|
+
});
|
|
53518
|
+
}
|
|
53519
|
+
function observeConversation(config) {
|
|
53520
|
+
const { id, cssSelectors, privacyFilters } = config;
|
|
53521
|
+
// Check if this agent is already being tracked
|
|
53522
|
+
const existing = _.find(conversations, conversation => conversation.id === id);
|
|
53523
|
+
if (existing) {
|
|
53524
|
+
return;
|
|
53525
|
+
}
|
|
53526
|
+
const missing = DOMConversation.validateConfig(cssSelectors);
|
|
53527
|
+
if (missing.length) {
|
|
53528
|
+
log.error('aiAgent config missing required selectors', { agentId: id, missing });
|
|
53529
|
+
return;
|
|
53530
|
+
}
|
|
53531
|
+
const conversation = new DOMConversation(pendo, api, id, privacyFilters, cssSelectors);
|
|
53532
|
+
conversation.onSubmit(sendConversationEvent);
|
|
53533
|
+
conversations.push(conversation);
|
|
53534
|
+
}
|
|
53535
|
+
function sendConversationEvent(eventType, eventPayload) {
|
|
53536
|
+
// Block event if the conversation is suspended
|
|
53537
|
+
const conversation = _.find(conversations, c => c.id === eventPayload.agentId);
|
|
53538
|
+
if (conversation && !conversation.isActive) {
|
|
53539
|
+
return;
|
|
53540
|
+
}
|
|
53541
|
+
eventPayload = _.extend({ agentType: 'conversation' }, eventPayload);
|
|
53542
|
+
api.analytics.collectEvent(eventType, eventPayload, undefined, 'agentic');
|
|
53543
|
+
}
|
|
53544
|
+
function teardown() {
|
|
53545
|
+
_.each(conversations, conversation => conversation.teardown());
|
|
53546
|
+
conversations = [];
|
|
53547
|
+
agentsCache.clear();
|
|
53548
|
+
}
|
|
53549
|
+
}
|
|
53550
|
+
|
|
53551
|
+
export { ConsoleCapture, ConversationAnalytics, Feedback, GuideMarkdown, NetworkCapture, PredictGuides, createReplayPlugin as Replay, TextCapture, VocPortal, loadAgent };
|