@pendo/agent 2.334.1 → 2.335.1
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 +15 -9
- package/dist/pendo.module.js +330 -70
- package/dist/pendo.module.min.js +10 -10
- package/dist/servers.json +8 -8
- package/package.json +1 -1
package/dist/pendo.module.js
CHANGED
|
@@ -4029,8 +4029,8 @@ let SERVER = '';
|
|
|
4029
4029
|
let ASSET_HOST = '';
|
|
4030
4030
|
let ASSET_PATH = '';
|
|
4031
4031
|
let DESIGNER_SERVER = '';
|
|
4032
|
-
let VERSION = '2.
|
|
4033
|
-
let PACKAGE_VERSION = '2.
|
|
4032
|
+
let VERSION = '2.335.1_';
|
|
4033
|
+
let PACKAGE_VERSION = '2.335.1';
|
|
4034
4034
|
let LOADER = 'xhr';
|
|
4035
4035
|
/* eslint-enable web-sdk-eslint-rules/no-gulp-env-references */
|
|
4036
4036
|
/**
|
|
@@ -11704,7 +11704,7 @@ function trimSurrogate(s) {
|
|
|
11704
11704
|
class ElementGetter {
|
|
11705
11705
|
constructor(cssSelector) {
|
|
11706
11706
|
this.listeners = {}; // callbacks to be called when an event of type occurs
|
|
11707
|
-
this.events = []; //
|
|
11707
|
+
this.events = []; // [{ type, capture }] events this element listens for
|
|
11708
11708
|
this.cssSelector = cssSelector;
|
|
11709
11709
|
}
|
|
11710
11710
|
get() {
|
|
@@ -11719,8 +11719,8 @@ class ElementGetter {
|
|
|
11719
11719
|
if (!el) {
|
|
11720
11720
|
return undefined;
|
|
11721
11721
|
}
|
|
11722
|
-
_.each(this.events, (
|
|
11723
|
-
el.addEventListener(
|
|
11722
|
+
_.each(this.events, ({ type, capture }) => {
|
|
11723
|
+
el.addEventListener(type, (e) => this.onEvent(e), capture);
|
|
11724
11724
|
});
|
|
11725
11725
|
this.elRef = new WeakRef(el);
|
|
11726
11726
|
return el;
|
|
@@ -11729,12 +11729,13 @@ class ElementGetter {
|
|
|
11729
11729
|
// XXX not sure about size limit
|
|
11730
11730
|
return getTextValue(this.get(), limit);
|
|
11731
11731
|
}
|
|
11732
|
-
addEventListener(event, callback) {
|
|
11732
|
+
addEventListener(event, callback, capture = false) {
|
|
11733
11733
|
const el = this.get();
|
|
11734
|
-
|
|
11735
|
-
|
|
11734
|
+
const alreadyRegistered = _.find(this.events, (e) => e.type === event && e.capture === capture);
|
|
11735
|
+
if (!alreadyRegistered) {
|
|
11736
|
+
this.events.push({ type: event, capture });
|
|
11736
11737
|
if (el) {
|
|
11737
|
-
el.addEventListener(event, (e) => this.onEvent(e));
|
|
11738
|
+
el.addEventListener(event, (e) => this.onEvent(e), capture);
|
|
11738
11739
|
}
|
|
11739
11740
|
}
|
|
11740
11741
|
this.listeners[event] = this.listeners[event] || [];
|
|
@@ -11746,7 +11747,7 @@ class ElementGetter {
|
|
|
11746
11747
|
}
|
|
11747
11748
|
teardown(el = this.get()) {
|
|
11748
11749
|
if (el) {
|
|
11749
|
-
_.each(this.events, (
|
|
11750
|
+
_.each(this.events, ({ type, capture }) => el.removeEventListener(type, this.onEvent, capture));
|
|
11750
11751
|
}
|
|
11751
11752
|
}
|
|
11752
11753
|
}
|
|
@@ -13925,6 +13926,27 @@ function calculateScrollAmount(combinedPos, screenDim, tooltipLayoutDir, bodyOve
|
|
|
13925
13926
|
}
|
|
13926
13927
|
return scrollAmt;
|
|
13927
13928
|
}
|
|
13929
|
+
var VALID_UI_ELEMENT_TYPES = ['BUTTON', 'A', 'IMG'];
|
|
13930
|
+
var VALID_TRACK_ACTIONS = [
|
|
13931
|
+
'advanceGuide',
|
|
13932
|
+
'previousStep',
|
|
13933
|
+
'dismissGuide',
|
|
13934
|
+
'openLink',
|
|
13935
|
+
'showGuide',
|
|
13936
|
+
'launchGuide',
|
|
13937
|
+
'guideSnoozed',
|
|
13938
|
+
'goToStep',
|
|
13939
|
+
'submitPoll',
|
|
13940
|
+
'submitPollAndGoToStep',
|
|
13941
|
+
'confirmation'
|
|
13942
|
+
];
|
|
13943
|
+
function normalizeUiElementType(elementType) {
|
|
13944
|
+
var type = _.isString(elementType) ? elementType.toUpperCase() : '';
|
|
13945
|
+
return _.contains(VALID_UI_ELEMENT_TYPES, type) ? type : 'BUTTON';
|
|
13946
|
+
}
|
|
13947
|
+
function isValidTrackedAction(action) {
|
|
13948
|
+
return _.isObject(action) && _.isString(action.action) && _.contains(VALID_TRACK_ACTIONS, action.action);
|
|
13949
|
+
}
|
|
13928
13950
|
function sizzleAttachPointInterceptor(Sizzle, selection, context, results, seed) {
|
|
13929
13951
|
var args = _.toArray(arguments).slice(1);
|
|
13930
13952
|
var resultList = Sizzle.apply(this, args);
|
|
@@ -15278,7 +15300,7 @@ var BuildingBlockTemplates = (function () {
|
|
|
15278
15300
|
function generateResourceCenterModuleList(templateJson, step, guides, buildNodeFromJSON) {
|
|
15279
15301
|
var children = templateJson.templateChildren;
|
|
15280
15302
|
return _.reduce(children, function (acc, childConfig, index) {
|
|
15281
|
-
var homeView = BuildingBlockResourceCenter.findResourceCenterHomeView(guides);
|
|
15303
|
+
var homeView = pendo$1.BuildingBlocks.BuildingBlockResourceCenter.findResourceCenterHomeView(guides);
|
|
15282
15304
|
var guide = _.find(guides, function (singleGuide) {
|
|
15283
15305
|
return singleGuide.id === childConfig.id;
|
|
15284
15306
|
});
|
|
@@ -15463,7 +15485,7 @@ var BuildingBlockTemplates = (function () {
|
|
|
15463
15485
|
});
|
|
15464
15486
|
recursivelyPopulateTemplateChildrenForTaskList(templateJson, children);
|
|
15465
15487
|
}
|
|
15466
|
-
BuildingBlockResourceCenter.updatePseudoStyleSelectors(templateJson);
|
|
15488
|
+
pendo$1.BuildingBlocks.BuildingBlockResourceCenter.updatePseudoStyleSelectors(templateJson);
|
|
15467
15489
|
const taskListBlocks = buildNodeFromJSON(templateJson, step, guides);
|
|
15468
15490
|
return [taskListBlocks];
|
|
15469
15491
|
}
|
|
@@ -15583,7 +15605,7 @@ var BuildingBlockTemplates = (function () {
|
|
|
15583
15605
|
});
|
|
15584
15606
|
if (!allAnnouncementsHaveContent)
|
|
15585
15607
|
return [];
|
|
15586
|
-
var resourceCenter = BuildingBlockResourceCenter.getResourceCenter();
|
|
15608
|
+
var resourceCenter = pendo$1.BuildingBlocks.BuildingBlockResourceCenter.getResourceCenter();
|
|
15587
15609
|
var bubbleConfig = _.get(resourceCenter, 'attributes.notificationBubble');
|
|
15588
15610
|
if (bubbleConfig) {
|
|
15589
15611
|
delete bubbleConfig.dir;
|
|
@@ -15641,7 +15663,7 @@ var BuildingBlockTemplates = (function () {
|
|
|
15641
15663
|
var guideTopPadding = parseInt(containerDomJson.props.style['padding-top'], 10);
|
|
15642
15664
|
miniBubble.props.style.top = guideTopPadding + containerTopPadding + 5 + 'px';
|
|
15643
15665
|
}
|
|
15644
|
-
if (!BuildingBlockResourceCenter.hasAnnouncementBeenSeen(guide) && miniBubble) {
|
|
15666
|
+
if (!pendo$1.BuildingBlocks.BuildingBlockResourceCenter.hasAnnouncementBeenSeen(guide) && miniBubble) {
|
|
15645
15667
|
listItem.props.class += ' pendo-unseen-announcement';
|
|
15646
15668
|
listItem.children.unshift(miniBubble);
|
|
15647
15669
|
}
|
|
@@ -15667,7 +15689,7 @@ var BuildingBlockTemplates = (function () {
|
|
|
15667
15689
|
miniBubble = generateUnreadAnnouncementMiniBubble(bubbleConfig);
|
|
15668
15690
|
miniBubble.props.style.top = '20px';
|
|
15669
15691
|
}
|
|
15670
|
-
if (!BuildingBlockResourceCenter.hasAnnouncementBeenSeen(guide) && miniBubble) {
|
|
15692
|
+
if (!pendo$1.BuildingBlocks.BuildingBlockResourceCenter.hasAnnouncementBeenSeen(guide) && miniBubble) {
|
|
15671
15693
|
listItem.props.class += ' pendo-unseen-announcement';
|
|
15672
15694
|
listItem.children = [miniBubble];
|
|
15673
15695
|
}
|
|
@@ -19829,13 +19851,13 @@ var BuildingBlockResourceCenter = (function () {
|
|
|
19829
19851
|
// If a module is currently shown, dismiss that first.
|
|
19830
19852
|
if (shownModule) {
|
|
19831
19853
|
var firstModuleStep = _.first(shownModule.steps);
|
|
19832
|
-
onGuideDismissed(firstModuleStep);
|
|
19854
|
+
pendo$1.onGuideDismissed(firstModuleStep);
|
|
19833
19855
|
}
|
|
19834
19856
|
// Finally, dismiss the homeView
|
|
19835
19857
|
var resourceCenterHomeView = _.get(guideToDismiss, 'attributes.resourceCenter.isTopLevel', false)
|
|
19836
19858
|
? guideToDismiss : BuildingBlockResourceCenter.findResourceCenterHomeView(getLocalActiveGuides());
|
|
19837
19859
|
var homeViewFirstStep = resourceCenterHomeView.steps[0];
|
|
19838
|
-
return onGuideDismissed(homeViewFirstStep);
|
|
19860
|
+
return pendo$1.onGuideDismissed(homeViewFirstStep);
|
|
19839
19861
|
}
|
|
19840
19862
|
function repositionResourceCenter() {
|
|
19841
19863
|
var resourceCenterContainer = BuildingBlockResourceCenter.getResourceCenterContainer();
|
|
@@ -24508,7 +24530,9 @@ var loadGuideJs = function (apiKey, params) {
|
|
|
24508
24530
|
if (treatAsAdoptPartner()) {
|
|
24509
24531
|
addAccountIdParams(queryString, params.accountId, ConfigReader.get('oemAccountId'));
|
|
24510
24532
|
}
|
|
24511
|
-
|
|
24533
|
+
// Also check persisted storage: the store's debuggingEnabled flag is only
|
|
24534
|
+
// committed after leader election, which the first guide request usually beats.
|
|
24535
|
+
if (isDebuggingEnabled() || getDebuggingStorage().enabled === true) {
|
|
24512
24536
|
// Include debug info from server
|
|
24513
24537
|
queryString.debug = true;
|
|
24514
24538
|
}
|
|
@@ -25667,10 +25691,13 @@ function connectChannelToStore(channel, store) {
|
|
|
25667
25691
|
var closed = false;
|
|
25668
25692
|
const waitingRequests = [];
|
|
25669
25693
|
channel.addEventListener('message', function (message) {
|
|
25694
|
+
// connect-channel only routes inbound messages to the store; it never
|
|
25695
|
+
// re-runs the guide loop. Anything that changes what guides display
|
|
25696
|
+
// re-arms the loop from the specific store action that makes the change
|
|
25697
|
+
// (see scheduleGuideUpdate in frames.module). Re-running on every
|
|
25698
|
+
// inbound message instead made two framed guide loops wake each other
|
|
25699
|
+
// forever even when idle (APP-162302).
|
|
25670
25700
|
messageHandler(message.data);
|
|
25671
|
-
if (store.state.guideUpdate.useObserver) {
|
|
25672
|
-
store.dispatch('guideUpdate/documentChanged');
|
|
25673
|
-
}
|
|
25674
25701
|
});
|
|
25675
25702
|
return {
|
|
25676
25703
|
postMessage,
|
|
@@ -33302,6 +33329,59 @@ function GuideStep(guide) {
|
|
|
33302
33329
|
return;
|
|
33303
33330
|
onGuideDismissed(this);
|
|
33304
33331
|
};
|
|
33332
|
+
/**
|
|
33333
|
+
* Records a `guideActivity` analytics event for this Step. Intended for
|
|
33334
|
+
* code-block guides to report UI interactions (button clicks,
|
|
33335
|
+
* link opens, poll submissions) that the automatic click-capture path cannot
|
|
33336
|
+
* resolve from `domJson`. This only reports analytics;
|
|
33337
|
+
*
|
|
33338
|
+
* Because the details originate from customer-authored guide content, they are
|
|
33339
|
+
* validated before staging: a missing or non-string `elementId` drops the event,
|
|
33340
|
+
* an unrecognized `elementType` falls back to `'BUTTON'`, and malformed action
|
|
33341
|
+
* entries are filtered out (no event when none remain valid).
|
|
33342
|
+
*
|
|
33343
|
+
* @access public
|
|
33344
|
+
* @category Guides
|
|
33345
|
+
* @example
|
|
33346
|
+
* step.trackAction({
|
|
33347
|
+
* elementId: 'pendo-button-advance-btn',
|
|
33348
|
+
* elementType: 'BUTTON',
|
|
33349
|
+
* actions: [{ action: 'advanceGuide' }]
|
|
33350
|
+
* })
|
|
33351
|
+
* @param {Object} details
|
|
33352
|
+
* @param {string} details.elementId DOM id of the interacted element. Required; a missing or
|
|
33353
|
+
* non-string value drops the event.
|
|
33354
|
+
* @param {string} [details.elementType] Element type/tag. Coerced to one of BUTTON/A/IMG,
|
|
33355
|
+
* defaulting to 'BUTTON' when missing or unrecognized.
|
|
33356
|
+
* @param {Array<Object>} details.actions Action objects, e.g. `[{ action: 'advanceGuide' }]`. Entries
|
|
33357
|
+
* whose `action` is not a recognized guideActivity action name are dropped.
|
|
33358
|
+
* @returns {void}
|
|
33359
|
+
*/
|
|
33360
|
+
this.trackAction = function (details) {
|
|
33361
|
+
details = details || {};
|
|
33362
|
+
if (!details.elementId || !_.isString(details.elementId))
|
|
33363
|
+
return;
|
|
33364
|
+
var actions = _.isArray(details.actions)
|
|
33365
|
+
? details.actions
|
|
33366
|
+
: (details.action ? [_.omit(details, 'elementId', 'elementType', 'actions')] : []);
|
|
33367
|
+
actions = _.filter(actions, isValidTrackedAction);
|
|
33368
|
+
actions = _.map(actions, function (action) {
|
|
33369
|
+
if (action.action === 'openLink' && action.url) {
|
|
33370
|
+
return _.extend({}, action, { url: sanitizeUrl(action.url) });
|
|
33371
|
+
}
|
|
33372
|
+
return action;
|
|
33373
|
+
});
|
|
33374
|
+
var eventProps = {
|
|
33375
|
+
type: 'guideActivity',
|
|
33376
|
+
guideId: guide.id,
|
|
33377
|
+
stepId: this.id,
|
|
33378
|
+
ui_element_id: details.elementId,
|
|
33379
|
+
ui_element_type: normalizeUiElementType(details.elementType),
|
|
33380
|
+
ui_element_actions: actions,
|
|
33381
|
+
language: guide.language
|
|
33382
|
+
};
|
|
33383
|
+
stageGuideEvent(createGuideEvent(eventProps));
|
|
33384
|
+
};
|
|
33305
33385
|
this.isPoweredByEnabled = function () {
|
|
33306
33386
|
return this.hideCredits !== true;
|
|
33307
33387
|
};
|
|
@@ -33655,6 +33735,7 @@ var FramesModule = (function () {
|
|
|
33655
33735
|
context.commit('setGuidesLoaded');
|
|
33656
33736
|
}
|
|
33657
33737
|
updateMasterGuideList(context.state);
|
|
33738
|
+
scheduleGuideUpdate();
|
|
33658
33739
|
},
|
|
33659
33740
|
join(context) {
|
|
33660
33741
|
if (context.state.disabled)
|
|
@@ -33898,6 +33979,7 @@ var FramesModule = (function () {
|
|
|
33898
33979
|
stepId: payload.stepId,
|
|
33899
33980
|
shown: payload.isShown
|
|
33900
33981
|
});
|
|
33982
|
+
scheduleGuideUpdate();
|
|
33901
33983
|
},
|
|
33902
33984
|
hideGuides(context, guideIdsToHide) {
|
|
33903
33985
|
guideIdsToHide = _.isArray(guideIdsToHide) ? guideIdsToHide : [];
|
|
@@ -33918,6 +34000,7 @@ var FramesModule = (function () {
|
|
|
33918
34000
|
hideGuides();
|
|
33919
34001
|
}
|
|
33920
34002
|
context.commit('hideGuides');
|
|
34003
|
+
scheduleGuideUpdate();
|
|
33921
34004
|
},
|
|
33922
34005
|
guideStepHiddenInFrame(context, payload) {
|
|
33923
34006
|
var wasShown = context.getters.isShownInFrame()(context.state.frameId, { id: payload.stepId });
|
|
@@ -33944,6 +34027,7 @@ var FramesModule = (function () {
|
|
|
33944
34027
|
stepId: payload.stepId,
|
|
33945
34028
|
shown: false
|
|
33946
34029
|
});
|
|
34030
|
+
scheduleGuideUpdate();
|
|
33947
34031
|
},
|
|
33948
34032
|
fixDoubleDisplay(context, payload) {
|
|
33949
34033
|
_.each(context.state.frames, function (frame, frameId) {
|
|
@@ -33967,6 +34051,7 @@ var FramesModule = (function () {
|
|
|
33967
34051
|
if (!step)
|
|
33968
34052
|
return;
|
|
33969
34053
|
step.hide();
|
|
34054
|
+
scheduleGuideUpdate();
|
|
33970
34055
|
},
|
|
33971
34056
|
changeLastGuideStepSeen(context, lastGuideStepSeen) {
|
|
33972
34057
|
crossFrameChannel.postMessage({
|
|
@@ -34099,6 +34184,7 @@ var FramesModule = (function () {
|
|
|
34099
34184
|
},
|
|
34100
34185
|
receiveFrameVisibility(context, message) {
|
|
34101
34186
|
context.commit('setFrameVisibility', message);
|
|
34187
|
+
scheduleGuideUpdate();
|
|
34102
34188
|
},
|
|
34103
34189
|
addSelectionModeToFrames(context, message) {
|
|
34104
34190
|
var options = message.options;
|
|
@@ -34504,6 +34590,18 @@ var FramesModule = (function () {
|
|
|
34504
34590
|
return _.map(guides, cloneGuide);
|
|
34505
34591
|
}
|
|
34506
34592
|
})();
|
|
34593
|
+
// Nudge the guide loop after a cross-frame change that affects what can
|
|
34594
|
+
// display. Guarded on useObserver: when the mutation observer drives the loop
|
|
34595
|
+
// it idles while the page is quiet and needs an explicit nudge to react to
|
|
34596
|
+
// cross-frame state; when the observer is off the loop already polls on its
|
|
34597
|
+
// own. This is called only from the frames actions that actually change
|
|
34598
|
+
// display state (not from every inbound message), which is what lets two
|
|
34599
|
+
// framed guide loops go fully idle instead of pinging each other (APP-162302).
|
|
34600
|
+
function scheduleGuideUpdate() {
|
|
34601
|
+
if (store.state.guideUpdate.useObserver) {
|
|
34602
|
+
store.dispatch('guideUpdate/documentChanged');
|
|
34603
|
+
}
|
|
34604
|
+
}
|
|
34507
34605
|
function updateMasterGuideList(state) {
|
|
34508
34606
|
var guidesInThisFrame = _.indexBy(_.filter(getActiveGuides(), function (guide) {
|
|
34509
34607
|
return !guide.isFrameProxy;
|
|
@@ -35918,6 +36016,11 @@ function startDebuggingModuleIfEnabled() {
|
|
|
35918
36016
|
if (!debugging.enabled || !isLeader())
|
|
35919
36017
|
return;
|
|
35920
36018
|
store.commit('debugger/debuggingEnabled', true);
|
|
36019
|
+
if (pendo$1.guides && _.isUndefined(pendo$1.excludedGuides)) {
|
|
36020
|
+
// The current guide payload was requested without debug=true (e.g. debugging
|
|
36021
|
+
// was just enabled), so it lacks exclusion data; re-fetch to include it.
|
|
36022
|
+
forceGuideReload();
|
|
36023
|
+
}
|
|
35921
36024
|
addDebuggingFunctions();
|
|
35922
36025
|
if (dom('#pendo-client-debugger').length)
|
|
35923
36026
|
return;
|
|
@@ -36248,10 +36351,19 @@ var DesignerConnect = (function () {
|
|
|
36248
36351
|
}
|
|
36249
36352
|
function launchDesignerListener(data, msg) {
|
|
36250
36353
|
var token = msg.data.token;
|
|
36251
|
-
if (!token)
|
|
36354
|
+
if (!token) {
|
|
36355
|
+
globalPendo.log('Designer launch request received with no token. Ignoring launch request.');
|
|
36356
|
+
postLaunchError(msg, 'missingToken');
|
|
36252
36357
|
return;
|
|
36358
|
+
}
|
|
36253
36359
|
if (token.publicAppId && token.publicAppId !== globalPendo.publicAppId) {
|
|
36254
36360
|
globalPendo.log(`Designer launch information received was for public app ID ${token.publicAppId}, which does not match the current app ID ${globalPendo.publicAppId}. Ignoring launch request.`);
|
|
36361
|
+
postLaunchError(msg, 'appIdMismatch');
|
|
36362
|
+
return;
|
|
36363
|
+
}
|
|
36364
|
+
if (token.preferredAgentInstallType && token.preferredAgentInstallType !== getInstallType()) {
|
|
36365
|
+
globalPendo.log(`Designer launch information received was for install type ${token.preferredAgentInstallType}, which does not match the current install type ${getInstallType()}. Ignoring launch request.`);
|
|
36366
|
+
postLaunchError(msg, 'installTypeMismatch');
|
|
36255
36367
|
return;
|
|
36256
36368
|
}
|
|
36257
36369
|
tempLaunchToken = token;
|
|
@@ -36293,6 +36405,11 @@ var DesignerConnect = (function () {
|
|
|
36293
36405
|
pluginAPI.store.dispatch('frames/startPreview');
|
|
36294
36406
|
}
|
|
36295
36407
|
}
|
|
36408
|
+
function postLaunchError(msg, reason) {
|
|
36409
|
+
if (msg.source && globalPendo._.isFunction(msg.source.postMessage)) {
|
|
36410
|
+
msg.source.postMessage({ type: 'pendo-designer-launch::error', reason }, msg.origin);
|
|
36411
|
+
}
|
|
36412
|
+
}
|
|
36296
36413
|
function removeListeners() {
|
|
36297
36414
|
if (window.removeEventListener) {
|
|
36298
36415
|
window.removeEventListener('message', messageReceiver, false);
|
|
@@ -39128,30 +39245,6 @@ function doSearch(guides, srchTxt) {
|
|
|
39128
39245
|
.value();
|
|
39129
39246
|
}
|
|
39130
39247
|
|
|
39131
|
-
var lastLauncherHash;
|
|
39132
|
-
var launcherProc = function () {
|
|
39133
|
-
const guidesList = getActiveGuides();
|
|
39134
|
-
if (isLeader()) {
|
|
39135
|
-
if (!pendo$1.guideWidget || !pendo$1.guideWidget.enabled)
|
|
39136
|
-
return;
|
|
39137
|
-
// filter list down to launcher based guides
|
|
39138
|
-
var launcherGuides = getLauncherGuideList(guidesList);
|
|
39139
|
-
// add all launcher based guides
|
|
39140
|
-
updateLauncher(launcherGuides, true);
|
|
39141
|
-
}
|
|
39142
|
-
else {
|
|
39143
|
-
hideLauncher();
|
|
39144
|
-
// Check for changes to what should display in the launcher
|
|
39145
|
-
var frameGuides = frameLocalGuides(guidesList);
|
|
39146
|
-
var launchers = getLauncherGuideList(frameGuides);
|
|
39147
|
-
var launcherHash = computeLauncherHash(launchers);
|
|
39148
|
-
if (launcherHash !== lastLauncherHash) {
|
|
39149
|
-
store.dispatch('frames/changeGuideList', frameGuides);
|
|
39150
|
-
}
|
|
39151
|
-
lastLauncherHash = launcherHash;
|
|
39152
|
-
}
|
|
39153
|
-
};
|
|
39154
|
-
|
|
39155
39248
|
var LAUNCHER_DEFAULT_WIDTH = 330;
|
|
39156
39249
|
var LAUNCHER_DEFAULT_HEIGHT = 310;
|
|
39157
39250
|
var LAUNCHER_CLOSED = 'launcher-closed';
|
|
@@ -39954,6 +40047,29 @@ var debuggerLaunched = function () {
|
|
|
39954
40047
|
var loadLauncherContentHandler = function (activeGuides) {
|
|
39955
40048
|
return loadLauncherContent(upgradeLauncher(pendo$1.guideWidget, activeGuides));
|
|
39956
40049
|
};
|
|
40050
|
+
var lastLauncherHash;
|
|
40051
|
+
var launcherProc = function () {
|
|
40052
|
+
const guidesList = getActiveGuides();
|
|
40053
|
+
if (isLeader()) {
|
|
40054
|
+
if (!pendo$1.guideWidget || !pendo$1.guideWidget.enabled)
|
|
40055
|
+
return;
|
|
40056
|
+
// filter list down to launcher based guides
|
|
40057
|
+
var launcherGuides = getLauncherGuideList(guidesList);
|
|
40058
|
+
// add all launcher based guides
|
|
40059
|
+
updateLauncher(launcherGuides, true);
|
|
40060
|
+
}
|
|
40061
|
+
else {
|
|
40062
|
+
hideLauncher();
|
|
40063
|
+
// Check for changes to what should display in the launcher
|
|
40064
|
+
var frameGuides = frameLocalGuides(guidesList);
|
|
40065
|
+
var launchers = getLauncherGuideList(frameGuides);
|
|
40066
|
+
var launcherHash = computeLauncherHash(launchers);
|
|
40067
|
+
if (launcherHash !== lastLauncherHash) {
|
|
40068
|
+
store.dispatch('frames/changeGuideList', frameGuides);
|
|
40069
|
+
}
|
|
40070
|
+
lastLauncherHash = launcherHash;
|
|
40071
|
+
}
|
|
40072
|
+
};
|
|
39957
40073
|
var initLauncherPlugin = function (pendo, PluginAPI) {
|
|
39958
40074
|
loadLauncherPublicFunctions(pendo);
|
|
39959
40075
|
PluginAPI.Events.on('guidesLoaded', guidesLoaded);
|
|
@@ -40584,7 +40700,7 @@ class DOMPrompt {
|
|
|
40584
40700
|
return evt.isComposing !== undefined ? evt.isComposing : isComposingFromState;
|
|
40585
40701
|
}
|
|
40586
40702
|
isEnterKey(evt) {
|
|
40587
|
-
return evt.code === 'Enter' || evt.key === 'Enter' || evt.keyCode === 13;
|
|
40703
|
+
return (evt.code === 'Enter' || evt.key === 'Enter' || evt.keyCode === 13) && !evt.shiftKey;
|
|
40588
40704
|
}
|
|
40589
40705
|
setupInputListeners() {
|
|
40590
40706
|
this._.each(this.inputEls, (inputEl) => {
|
|
@@ -52348,6 +52464,7 @@ function maskSensitiveFields({ string, contentType, _ }) {
|
|
|
52348
52464
|
}
|
|
52349
52465
|
|
|
52350
52466
|
const DEV_LOG_TYPE = 'devlog';
|
|
52467
|
+
const DEV_LOG_SEND_INTERVAL = 5000;
|
|
52351
52468
|
function createDevLogEnvelope(pluginAPI, globalPendo) {
|
|
52352
52469
|
return {
|
|
52353
52470
|
browser_time: pluginAPI.util.getNow(),
|
|
@@ -52576,7 +52693,7 @@ function ConsoleCapture() {
|
|
|
52576
52693
|
if (!sendQueue.failed()) {
|
|
52577
52694
|
send();
|
|
52578
52695
|
}
|
|
52579
|
-
},
|
|
52696
|
+
}, DEV_LOG_SEND_INTERVAL);
|
|
52580
52697
|
sendQueue.start();
|
|
52581
52698
|
pluginAPI.Events.ready.on(readyHandler);
|
|
52582
52699
|
pluginAPI.Events['recording:unpaused'].on(recordingStarted);
|
|
@@ -52864,7 +52981,7 @@ function NetworkCapture() {
|
|
|
52864
52981
|
if (!sendQueue.failed()) {
|
|
52865
52982
|
send();
|
|
52866
52983
|
}
|
|
52867
|
-
},
|
|
52984
|
+
}, DEV_LOG_SEND_INTERVAL);
|
|
52868
52985
|
sendQueue.start();
|
|
52869
52986
|
pluginAPI.Events.ready.on(startCapture);
|
|
52870
52987
|
pluginAPI.Events['recording:unpaused'].on(recordingStarted);
|
|
@@ -55214,6 +55331,46 @@ var _ = /*@__PURE__*/getDefaultExportFromCjs(underscoreExports);
|
|
|
55214
55331
|
|
|
55215
55332
|
var encodeURIComponent = _.isFunction(window.encodeURIComponent) ? window.encodeURIComponent : _.identity;
|
|
55216
55333
|
|
|
55334
|
+
const WIDGET_SETTINGS_API = '/external/widget/settings';
|
|
55335
|
+
class PredictApiService {
|
|
55336
|
+
constructor({ baseUrl, token }) {
|
|
55337
|
+
this.performRequest = (url, options) => __awaiter(this, void 0, void 0, function* () {
|
|
55338
|
+
const response = yield fetch(url, options);
|
|
55339
|
+
const body = response.ok ? yield response.json() : null;
|
|
55340
|
+
return { ok: response.ok, status: response.status, body };
|
|
55341
|
+
});
|
|
55342
|
+
this.getWidgetSettingsById = (id, log) => __awaiter(this, void 0, void 0, function* () {
|
|
55343
|
+
var _a, _b;
|
|
55344
|
+
if (!id) {
|
|
55345
|
+
log('[predict] no id provided');
|
|
55346
|
+
return null;
|
|
55347
|
+
}
|
|
55348
|
+
try {
|
|
55349
|
+
const { ok, status, body } = yield this.performRequest(`${this.baseUrl}${WIDGET_SETTINGS_API}/${id}`, {
|
|
55350
|
+
method: 'GET',
|
|
55351
|
+
headers: { 'Content-Type': 'application/json', 'Authorization': this.token }
|
|
55352
|
+
});
|
|
55353
|
+
if (!ok) {
|
|
55354
|
+
log(`[predict] error getting widget settings by id: ${status}`);
|
|
55355
|
+
return null;
|
|
55356
|
+
}
|
|
55357
|
+
const data = body;
|
|
55358
|
+
if ((_a = data === null || data === void 0 ? void 0 : data.errors) === null || _a === void 0 ? void 0 : _a.length) {
|
|
55359
|
+
log(`[predict] error getting widget settings by id: ${data.errors}`);
|
|
55360
|
+
return null;
|
|
55361
|
+
}
|
|
55362
|
+
return (_b = data === null || data === void 0 ? void 0 : data.data) !== null && _b !== void 0 ? _b : null;
|
|
55363
|
+
}
|
|
55364
|
+
catch (error) {
|
|
55365
|
+
log(`[predict] error getting widget settings by id: ${error}`);
|
|
55366
|
+
return null;
|
|
55367
|
+
}
|
|
55368
|
+
});
|
|
55369
|
+
this.baseUrl = baseUrl;
|
|
55370
|
+
this.token = token;
|
|
55371
|
+
}
|
|
55372
|
+
}
|
|
55373
|
+
|
|
55217
55374
|
const PREDICT_STEP_REGEX = /\$\$predict\$\$/;
|
|
55218
55375
|
const DRAG_THRESHOLD = 5;
|
|
55219
55376
|
const STYLE_ID = 'pendo-predict-plugin-styles';
|
|
@@ -55221,6 +55378,7 @@ const GUIDE_BUTTON_IDENTIFIER = 'button:contains("token")';
|
|
|
55221
55378
|
const pluginVersion = '1.0.1';
|
|
55222
55379
|
const PREDICT_SANDBOX_PAGE = 'predict-sandbox.html';
|
|
55223
55380
|
const getPredictBaseUrl = (designerServer) => designerServer.replace('app', 'predict');
|
|
55381
|
+
const getPredictApiBaseUrl = (predictBaseUrl) => predictBaseUrl.replace('predict', 'predict-api');
|
|
55224
55382
|
const EXTENSION_ORIGIN_REGEX = /^(chrome|moz|safari-web)-extension:\/\//;
|
|
55225
55383
|
/**
|
|
55226
55384
|
* When running inside the Pendo Launcher extension, a host page's CSP `frame-src`
|
|
@@ -55324,6 +55482,50 @@ const getRecordIdFromUrl = (recordRegex, log = () => { }) => {
|
|
|
55324
55482
|
log(`[predict] recordId found: ${recordId}`);
|
|
55325
55483
|
return recordId;
|
|
55326
55484
|
};
|
|
55485
|
+
const escapeRegexKeyword = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
55486
|
+
// Builds the generalized keyword matcher: a simple keyword (single- or
|
|
55487
|
+
// multi-segment, e.g. "Company" or "lightning/r/Opportunity") that works
|
|
55488
|
+
// whether the id lives in the path or the query string. The keyword is escaped
|
|
55489
|
+
// so metacharacters are treated literally, a boundary avoids substring hijacks,
|
|
55490
|
+
// and the id ends naturally at any delimiter.
|
|
55491
|
+
const buildRecordRegex = (keyword) => new RegExp(`(?:^|[/?&=.#])${escapeRegexKeyword(keyword)}[/.=:_-]([a-zA-Z0-9-]+)`, 'i');
|
|
55492
|
+
// Resolves the record id from the current URL using three tiers, returning the
|
|
55493
|
+
// first non-null result:
|
|
55494
|
+
// 1. recordRegexPattern - an advanced, author-supplied full regex.
|
|
55495
|
+
// 2. recordRegexName - the generalized keyword matcher (path + query).
|
|
55496
|
+
// 3. legacy fallback - the original strict `/name/id` template, so every
|
|
55497
|
+
// pre-existing config keeps working with no migration.
|
|
55498
|
+
const resolveRecordId = (configuration, log = () => { }) => {
|
|
55499
|
+
var _a, _b, _c, _d;
|
|
55500
|
+
const { recordRegexPattern, recordRegexName } = configuration;
|
|
55501
|
+
// Tier 1: advanced full pattern (matched against the full href).
|
|
55502
|
+
if (recordRegexPattern) {
|
|
55503
|
+
try {
|
|
55504
|
+
const advancedId = (_b = (_a = window.location.href.match(new RegExp(recordRegexPattern))) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : null;
|
|
55505
|
+
if (advancedId) {
|
|
55506
|
+
log(`[predict] recordId found via recordRegexPattern: ${advancedId}`);
|
|
55507
|
+
return advancedId;
|
|
55508
|
+
}
|
|
55509
|
+
}
|
|
55510
|
+
catch (error) {
|
|
55511
|
+
log(`[predict] invalid recordRegexPattern, skipping: ${error}`);
|
|
55512
|
+
}
|
|
55513
|
+
}
|
|
55514
|
+
if (!recordRegexName) {
|
|
55515
|
+
return null;
|
|
55516
|
+
}
|
|
55517
|
+
// Tier 2: generalized keyword matcher against path + query + hash only
|
|
55518
|
+
// (host excluded to avoid subdomain false matches).
|
|
55519
|
+
const { pathname, search, hash } = window.location;
|
|
55520
|
+
const keywordId = (_d = (_c = `${pathname}${search}${hash}`.match(buildRecordRegex(recordRegexName))) === null || _c === void 0 ? void 0 : _c[1]) !== null && _d !== void 0 ? _d : null;
|
|
55521
|
+
if (keywordId) {
|
|
55522
|
+
log(`[predict] recordId found via recordRegexName: ${keywordId}`);
|
|
55523
|
+
return keywordId;
|
|
55524
|
+
}
|
|
55525
|
+
// Tier 3: legacy template fallback (preserves pre-existing configs).
|
|
55526
|
+
const legacyRegex = new RegExp(`/${recordRegexName}/([a-zA-Z0-9]+)(?:/|$)`);
|
|
55527
|
+
return getRecordIdFromUrl(legacyRegex, log);
|
|
55528
|
+
};
|
|
55327
55529
|
const safeStringify = (value, fallback) => {
|
|
55328
55530
|
try {
|
|
55329
55531
|
return JSON.stringify(value);
|
|
@@ -55341,13 +55543,25 @@ const safeParse = (value, fallback, log = () => { }) => {
|
|
|
55341
55543
|
return fallback;
|
|
55342
55544
|
}
|
|
55343
55545
|
};
|
|
55546
|
+
const getAvailableParams = (params) => {
|
|
55547
|
+
// No need to pass the full configuration when widgetId is present
|
|
55548
|
+
if (params.widgetId) {
|
|
55549
|
+
return {
|
|
55550
|
+
widgetId: params.widgetId,
|
|
55551
|
+
pipeVersion: params.pipeVersion,
|
|
55552
|
+
forceAccountId: params.forceAccountId
|
|
55553
|
+
};
|
|
55554
|
+
}
|
|
55555
|
+
return params;
|
|
55556
|
+
};
|
|
55344
55557
|
const buildQueryParams = (params) => {
|
|
55345
55558
|
const urlParams = new URLSearchParams();
|
|
55346
|
-
const
|
|
55559
|
+
const availableParams = getAvailableParams(params);
|
|
55560
|
+
const entries = Object.entries(availableParams);
|
|
55347
55561
|
urlParams.set('pluginVersion', pluginVersion);
|
|
55348
55562
|
for (let i = 0; i < entries.length; i++) {
|
|
55349
55563
|
const [key, value] = entries[i];
|
|
55350
|
-
if (value
|
|
55564
|
+
if (value !== undefined && value !== null) {
|
|
55351
55565
|
urlParams.set(key, typeof value === 'object' ? safeStringify(value) : String(value));
|
|
55352
55566
|
}
|
|
55353
55567
|
}
|
|
@@ -55453,10 +55667,16 @@ const createExplanationIframe = ({ analysisId, recordId, configuration, predictB
|
|
|
55453
55667
|
};
|
|
55454
55668
|
// ----- Floating Modal Creation -----
|
|
55455
55669
|
const createFloatingModal = ({ recordId, configuration, predictBaseUrl, wrapperBase = '' }) => {
|
|
55456
|
-
var _a;
|
|
55457
|
-
const flatIds = (_a = configuration.analysisIds) === null || _a === void 0 ? void 0 : _a.flat(Infinity);
|
|
55670
|
+
var _a, _b;
|
|
55671
|
+
const flatIds = ((_b = (_a = configuration.analysisIds) === null || _a === void 0 ? void 0 : _a.flat(Infinity)) !== null && _b !== void 0 ? _b : []);
|
|
55458
55672
|
for (let i = 0; i < flatIds.length; i++) {
|
|
55459
|
-
createExplanationIframe({
|
|
55673
|
+
createExplanationIframe({
|
|
55674
|
+
analysisId: flatIds[i],
|
|
55675
|
+
recordId,
|
|
55676
|
+
configuration,
|
|
55677
|
+
predictBaseUrl,
|
|
55678
|
+
wrapperBase
|
|
55679
|
+
});
|
|
55460
55680
|
}
|
|
55461
55681
|
const container = createElement('div', { id: 'floatingModalContainer', className: 'floating-modal-container' }, document.body);
|
|
55462
55682
|
const dragHandle = createElement('div', {
|
|
@@ -55530,7 +55750,14 @@ const setupMessageListener = ({ token, forceAccountId, cleanup, pendo, predictBa
|
|
|
55530
55750
|
}
|
|
55531
55751
|
const visitorId = (_a = pendo === null || pendo === void 0 ? void 0 : pendo.getVisitorId) === null || _a === void 0 ? void 0 : _a.call(pendo);
|
|
55532
55752
|
const accountId = forceAccountId !== null && forceAccountId !== void 0 ? forceAccountId : (_b = pendo === null || pendo === void 0 ? void 0 : pendo.getAccountId) === null || _b === void 0 ? void 0 : _b.call(pendo);
|
|
55533
|
-
(_c = iframe.contentWindow) === null || _c === void 0 ? void 0 : _c.postMessage({
|
|
55753
|
+
(_c = iframe.contentWindow) === null || _c === void 0 ? void 0 : _c.postMessage({
|
|
55754
|
+
type: 'TOKEN_RECEIVED',
|
|
55755
|
+
token,
|
|
55756
|
+
idToken,
|
|
55757
|
+
extensionAPIKeys,
|
|
55758
|
+
visitorId,
|
|
55759
|
+
accountId
|
|
55760
|
+
}, frameTargetOrigin);
|
|
55534
55761
|
}
|
|
55535
55762
|
},
|
|
55536
55763
|
OPEN_EXPLANATION: () => {
|
|
@@ -55578,8 +55805,24 @@ const setupMessageListener = ({ token, forceAccountId, cleanup, pendo, predictBa
|
|
|
55578
55805
|
window.addEventListener('message', messageHandler);
|
|
55579
55806
|
return () => window.removeEventListener('message', messageHandler);
|
|
55580
55807
|
};
|
|
55581
|
-
const
|
|
55582
|
-
|
|
55808
|
+
const mapAnalysisIds = (analysesHierarchy) => analysesHierarchy === null || analysesHierarchy === void 0 ? void 0 : analysesHierarchy.map(hierarchy => hierarchy.map(item => item.analysisId));
|
|
55809
|
+
// Loads the widget's stored settings from the predict API, which override
|
|
55810
|
+
// whatever was inlined in the guide button. Any failure logs and returns the inline configuration.
|
|
55811
|
+
const fetchWidgetConfiguration = (_a) => __awaiter(void 0, void 0, void 0, function* () {
|
|
55812
|
+
var _b;
|
|
55813
|
+
var { token, predictBaseUrl, log } = _a, inlineConfiguration = __rest(_a, ["token", "predictBaseUrl", "log"]);
|
|
55814
|
+
const predictApiService = new PredictApiService({
|
|
55815
|
+
baseUrl: getPredictApiBaseUrl(predictBaseUrl),
|
|
55816
|
+
token
|
|
55817
|
+
});
|
|
55818
|
+
const widgetSettings = yield predictApiService.getWidgetSettingsById((_b = inlineConfiguration.widgetId) !== null && _b !== void 0 ? _b : '', log);
|
|
55819
|
+
if (!widgetSettings) {
|
|
55820
|
+
return inlineConfiguration;
|
|
55821
|
+
}
|
|
55822
|
+
return Object.assign(Object.assign({}, inlineConfiguration), { analysisIds: mapAnalysisIds(widgetSettings.analysesHierarchy), recordRegexPattern: widgetSettings.recordRegexPattern, recordRegexName: widgetSettings.recordRegexKeyword });
|
|
55823
|
+
});
|
|
55824
|
+
const predictGuidesScript = ({ step, pendo, cleanupArray, cleanup, log, designerServer }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
55825
|
+
var _c;
|
|
55583
55826
|
log('[predict] initializing');
|
|
55584
55827
|
// Before anything else, inject styles so that the guide will be hidden
|
|
55585
55828
|
const pendoContainerId = step === null || step === void 0 ? void 0 : step.containerId;
|
|
@@ -55588,33 +55831,47 @@ const predictGuidesScript = ({ step, pendo, cleanupArray, cleanup, log, designer
|
|
|
55588
55831
|
log('[predict] cleanupArray is not empty');
|
|
55589
55832
|
return;
|
|
55590
55833
|
}
|
|
55834
|
+
if (!designerServer) {
|
|
55835
|
+
log('[predict] no designerServer found, aborting');
|
|
55836
|
+
return;
|
|
55837
|
+
}
|
|
55838
|
+
const predictBaseUrl = getPredictBaseUrl(designerServer);
|
|
55591
55839
|
// ----- Extract Configuration -----
|
|
55592
|
-
const guideButton = (
|
|
55840
|
+
const guideButton = (_c = step.guideElement.find(GUIDE_BUTTON_IDENTIFIER)) === null || _c === void 0 ? void 0 : _c[0];
|
|
55593
55841
|
if (!guideButton) {
|
|
55594
55842
|
log('[predict] no guide button found, aborting');
|
|
55595
55843
|
return;
|
|
55596
55844
|
}
|
|
55597
|
-
const
|
|
55598
|
-
if (!
|
|
55845
|
+
const _d = safeParse(guideButton.textContent, {}, log), { token } = _d, inlineConfiguration = __rest(_d, ["token"]);
|
|
55846
|
+
if (!inlineConfiguration || !token) {
|
|
55599
55847
|
log('[predict] no configuration found, aborting');
|
|
55600
55848
|
return;
|
|
55601
55849
|
}
|
|
55602
|
-
|
|
55603
|
-
|
|
55850
|
+
// Widget-backed guides load their settings from the predict API; those
|
|
55851
|
+
// override whatever was inlined in the guide button. Non-widget guides use
|
|
55852
|
+
// the inlined configuration as-is.
|
|
55853
|
+
const configuration = (inlineConfiguration === null || inlineConfiguration === void 0 ? void 0 : inlineConfiguration.widgetId)
|
|
55854
|
+
? yield fetchWidgetConfiguration(Object.assign(Object.assign({}, inlineConfiguration), { token,
|
|
55855
|
+
predictBaseUrl,
|
|
55856
|
+
log }))
|
|
55857
|
+
: inlineConfiguration;
|
|
55858
|
+
const recordId = resolveRecordId(configuration, log);
|
|
55604
55859
|
if (!recordId) {
|
|
55605
55860
|
log('[predict] no recordId found in URL, aborting');
|
|
55606
55861
|
return;
|
|
55607
55862
|
}
|
|
55608
|
-
if (!designerServer) {
|
|
55609
|
-
log('[predict] no designerServer found, aborting');
|
|
55610
|
-
return;
|
|
55611
|
-
}
|
|
55612
|
-
const predictBaseUrl = getPredictBaseUrl(designerServer);
|
|
55613
55863
|
const wrapperBase = getFrameWrapperBase(pendo);
|
|
55614
55864
|
log(`[predict] predictBaseUrl: ${predictBaseUrl}${wrapperBase ? `, wrapping via ${wrapperBase}` : ''}`);
|
|
55615
|
-
cleanupArray.push(setupMessageListener({
|
|
55865
|
+
cleanupArray.push(setupMessageListener({
|
|
55866
|
+
token,
|
|
55867
|
+
forceAccountId: configuration.forceAccountId,
|
|
55868
|
+
cleanup,
|
|
55869
|
+
pendo,
|
|
55870
|
+
predictBaseUrl,
|
|
55871
|
+
wrapperBase
|
|
55872
|
+
}));
|
|
55616
55873
|
cleanupArray.push(createFloatingModal({ recordId, configuration, predictBaseUrl, wrapperBase }));
|
|
55617
|
-
};
|
|
55874
|
+
});
|
|
55618
55875
|
|
|
55619
55876
|
const PredictGuides = () => {
|
|
55620
55877
|
let pluginApiRef = null;
|
|
@@ -55649,7 +55906,10 @@ const PredictGuides = () => {
|
|
|
55649
55906
|
var _a, _b;
|
|
55650
55907
|
const designerServer = ((_a = pendo === null || pendo === void 0 ? void 0 : pendo.getConfigValue) === null || _a === void 0 ? void 0 : _a.call(pendo, 'designerServer')) ||
|
|
55651
55908
|
((_b = pendo === null || pendo === void 0 ? void 0 : pendo.getConfigValue) === null || _b === void 0 ? void 0 : _b.call(pendo, 'server'));
|
|
55652
|
-
predictGuidesScript({ step, pendo, cleanupArray, cleanup, log, designerServer })
|
|
55909
|
+
Promise$2.resolve(predictGuidesScript({ step, pendo, cleanupArray, cleanup, log, designerServer })).catch((error) => {
|
|
55910
|
+
log(`[predict] predictGuidesScript crashed, tearing down: ${error}`);
|
|
55911
|
+
cleanup();
|
|
55912
|
+
});
|
|
55653
55913
|
this.on('unmounted', (evt) => {
|
|
55654
55914
|
if (evt.reason !== 'hidden')
|
|
55655
55915
|
cleanup();
|