@pendo/agent 2.315.0 → 2.316.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.
@@ -2891,6 +2891,17 @@ var ConfigReader = (function () {
2891
2891
  */
2892
2892
  addOption('dataHost', [SNIPPET_SRC, PENDO_CONFIG_SRC]);
2893
2893
  addOption('disableAutoInitialize');
2894
+ /**
2895
+ * If set to `true` the web SDK will wait for the host application to be both loaded and visible before
2896
+ * starting the initialization process.
2897
+ *
2898
+ * @access public
2899
+ * @category Config/Core
2900
+ * @name initializeWhenVisible
2901
+ * @default false
2902
+ * @type {boolean}
2903
+ */
2904
+ addOption('initializeWhenVisible', [SNIPPET_SRC, PENDO_CONFIG_SRC], false);
2894
2905
  /**
2895
2906
  * Although the name refers to cookies, if set to `true` the web SDK will not persist any data in local
2896
2907
  * storage or cookies and will rely only on memory.
@@ -3945,8 +3956,8 @@ let SERVER = '';
3945
3956
  let ASSET_HOST = '';
3946
3957
  let ASSET_PATH = '';
3947
3958
  let DESIGNER_SERVER = '';
3948
- let VERSION = '2.315.0_';
3949
- let PACKAGE_VERSION = '2.315.0';
3959
+ let VERSION = '2.316.0_';
3960
+ let PACKAGE_VERSION = '2.316.0';
3950
3961
  let LOADER = 'xhr';
3951
3962
  /* eslint-enable web-sdk-eslint-rules/no-gulp-env-references */
3952
3963
  /**
@@ -11866,13 +11877,10 @@ var messageValidator = function (msg) {
11866
11877
  var data = typeof msg.data === 'string' ? JSON.parse(msg.data) : msg.data;
11867
11878
  var origin = msg.origin;
11868
11879
  var source = msg.source;
11869
- if (data.action || data.mutation) {
11870
- return; // Ignore action messages
11871
- }
11872
- if (!data.type || typeof data.type !== 'string') {
11873
- log.debug('Invalid Message: Missing \'type\' in data format');
11880
+ if (data.action || data.mutation)
11881
+ return;
11882
+ if (!data.type || typeof data.type !== 'string')
11874
11883
  return;
11875
- }
11876
11884
  return { data, origin, source };
11877
11885
  }
11878
11886
  catch (e) {
@@ -14098,6 +14106,22 @@ var whenLoadedCall = function (callback, win) {
14098
14106
  }
14099
14107
  return _.noop;
14100
14108
  };
14109
+ const whenVisibleCall = (callback, win = window) => {
14110
+ const { document } = win;
14111
+ const waitForVis = ConfigReader.get('initializeWhenVisible', false);
14112
+ if (!waitForVis || document.visibilityState === 'visible') {
14113
+ callback();
14114
+ return _.noop;
14115
+ }
14116
+ const stopVisListener = attachEventInternal(document, 'visibilitychange', () => {
14117
+ if (document.visibilityState === 'visible') {
14118
+ callback();
14119
+ // need to shut this down immediately as visibility can continue to change
14120
+ stopVisListener();
14121
+ }
14122
+ });
14123
+ return stopVisListener;
14124
+ };
14101
14125
 
14102
14126
  /**
14103
14127
  * Returns the normalized URL sent from the backend. This won't always
@@ -26082,7 +26106,7 @@ var loadGuideJs = function (apiKey, params) {
26082
26106
  var guideRequestId = _.uniqueId();
26083
26107
  var deferred = q.defer();
26084
26108
  if (mostRecentGuideRequest && mostRecentGuideRequest.deferred) {
26085
- mostRecentGuideRequest.deferred.reject('newRequest'); // make sure that we don't leave open any promises if multiple guide requests are made in quick succession
26109
+ mostRecentGuideRequest.deferred.resolve(); // make sure that we don't leave open any promises if multiple guide requests are made in quick succession
26086
26110
  }
26087
26111
  mostRecentGuideRequest = {
26088
26112
  id: guideRequestId,
@@ -26368,11 +26392,6 @@ var loadGuides = function (apiKey, visitorId, page, callback) {
26368
26392
  }
26369
26393
  }
26370
26394
  }).catch(function (err) {
26371
- if (err === 'newRequest') {
26372
- log.info('Guide load cancelled due to new request');
26373
- deferred.resolve('Guide load cancelled due to new request');
26374
- return;
26375
- }
26376
26395
  log.info(`Error in loadGuideJs, shutting down guides, err: ${_.get(err, 'message', err || 'Unknown error')}`);
26377
26396
  Events.guidesFailed.trigger();
26378
26397
  deferred.reject(err);
@@ -28166,6 +28185,344 @@ var GuideActivity = (function () {
28166
28185
  }
28167
28186
  })();
28168
28187
 
28188
+ function arrayEquals(array1, array2) {
28189
+ if (array1.length != array2.length)
28190
+ return false;
28191
+ return _.all(array1, function (item, i) {
28192
+ return item === array2[i];
28193
+ });
28194
+ }
28195
+ class DOMActivationPhase {
28196
+ constructor(DOMActivation) {
28197
+ this.maxTargets = 50;
28198
+ this.domActivation = DOMActivation;
28199
+ this.name = 'dom';
28200
+ this.queue = [];
28201
+ }
28202
+ markDirty() {
28203
+ this.queue.push.apply(this.queue, this.domActivation.guides);
28204
+ }
28205
+ process(monitor) {
28206
+ var domActivationGuide = this.queue.shift();
28207
+ if (!domActivationGuide)
28208
+ return;
28209
+ monitor.saveContext(domActivationGuide);
28210
+ var targets;
28211
+ try {
28212
+ targets = SizzleProxy(domActivationGuide.selector);
28213
+ }
28214
+ catch (e) {
28215
+ targets = [];
28216
+ }
28217
+ if (targets.length > this.maxTargets) {
28218
+ targets.length = this.maxTargets;
28219
+ }
28220
+ if (!arrayEquals(targets, domActivationGuide.targets)) {
28221
+ domActivationGuide.targets = targets;
28222
+ this.domActivation.detach(domActivationGuide, this.domActivation.targets);
28223
+ _.each(targets, function (target) {
28224
+ this.domActivation.attach(target, domActivationGuide, this.domActivation.targets);
28225
+ }, this);
28226
+ }
28227
+ }
28228
+ handleProcessTimeExceeded(monitor) {
28229
+ const ctx = monitor.getContext();
28230
+ if (ctx) {
28231
+ log.warn('Element activated guide (' + ctx.id + ') timeout exceeded');
28232
+ }
28233
+ }
28234
+ cancel() {
28235
+ this.queue.length = 0;
28236
+ }
28237
+ isComplete() {
28238
+ return !this.queue.length;
28239
+ }
28240
+ }
28241
+ var DOMActivation = (function () {
28242
+ var keyAttr = 'pendoTargetId';
28243
+ var pluginApi;
28244
+ /*
28245
+ domActivatedGuides = [
28246
+ {
28247
+ id: 'aGuideId',
28248
+ events: ['click', 'mouseover'],
28249
+ selector: '.selector .for .target',
28250
+ targets: [array, of, dom, references]
28251
+ }
28252
+ ]
28253
+ */
28254
+ var domActivatedGuides = [];
28255
+ /*
28256
+ activationTargets = {
28257
+ aGuideId: 'aTargetId',
28258
+ aTargetId: {
28259
+ target: {{referenceToDomElement}},
28260
+ events: {
28261
+ click: {
28262
+ guideIds: {
28263
+ aGuideId: 1,
28264
+ anotherGuideId: 1
28265
+ },
28266
+ fn: {{partial(eventHandler, guideIds)}}
28267
+ },
28268
+ mouseover: {{same format as click}}
28269
+ }
28270
+ }
28271
+ {{more guide and target ids...}}
28272
+ }
28273
+ */
28274
+ var activationTargets = {};
28275
+ var domPhase;
28276
+ return {
28277
+ name: 'DOMActivation',
28278
+ key: keyAttr,
28279
+ guides: domActivatedGuides,
28280
+ targets: activationTargets,
28281
+ reset,
28282
+ init,
28283
+ attach: attachGuideToTarget,
28284
+ detach: detachGuideFromTarget,
28285
+ handler: eventHandler,
28286
+ activates,
28287
+ prefetch,
28288
+ initialize,
28289
+ teardown
28290
+ };
28291
+ function initialize(pendo, PluginAPI) {
28292
+ pluginApi = PluginAPI;
28293
+ PluginAPI.Events.on('deliverablesLoaded', reset);
28294
+ PluginAPI.Events.on('guideListChanged', handleGuideListChanged);
28295
+ PluginAPI.Events.on('guidesLoaded', handleGuidesLoaded);
28296
+ domPhase = new DOMActivationPhase(DOMActivation);
28297
+ addUpdatePhase(domPhase);
28298
+ }
28299
+ function teardown() {
28300
+ removeUpdatePhase(domPhase);
28301
+ pluginApi.Events.off('deliverablesLoaded', reset);
28302
+ pluginApi.Events.off('guideListChanged', handleGuideListChanged);
28303
+ pluginApi.Events.off('guidesLoaded', handleGuidesLoaded);
28304
+ }
28305
+ function handleGuideListChanged() {
28306
+ reset();
28307
+ init(getLocalActiveGuides());
28308
+ }
28309
+ function handleGuidesLoaded() {
28310
+ prefetch(getLocalActiveGuides());
28311
+ }
28312
+ function attachGuideToTarget(target, domActivationGuide, activationTargets) {
28313
+ var targetKey = target[keyAttr];
28314
+ var handler = targetKey ? activationTargets[targetKey] : null;
28315
+ if (!handler) {
28316
+ targetKey = targetKey || 'target' + _.uniqueId();
28317
+ handler = {
28318
+ target,
28319
+ events: {}
28320
+ };
28321
+ activationTargets[targetKey] = handler;
28322
+ target[keyAttr] = targetKey;
28323
+ }
28324
+ var targetList = activationTargets[domActivationGuide.id] || [];
28325
+ targetList.push(targetKey);
28326
+ activationTargets[domActivationGuide.id] = targetList;
28327
+ _.each(domActivationGuide.events, function (eventType) {
28328
+ var eventTypeHandler = handler.events[eventType];
28329
+ if (!eventTypeHandler) {
28330
+ eventTypeHandler = {
28331
+ guideIds: {}
28332
+ };
28333
+ eventTypeHandler.fn = _.partial(eventHandler, _, eventTypeHandler.guideIds);
28334
+ if (eventType === 'mouseover') {
28335
+ eventType = 'mouseenter';
28336
+ }
28337
+ attachEvent(target, eventType, eventTypeHandler.fn);
28338
+ handler.events[eventType] = eventTypeHandler;
28339
+ }
28340
+ eventTypeHandler.guideIds[domActivationGuide.id] = 1;
28341
+ });
28342
+ }
28343
+ function detachGuideFromTarget(domActivationGuide, activationTargets) {
28344
+ _.each(activationTargets[domActivationGuide.id], function (targetKey) {
28345
+ var handler = targetKey ? activationTargets[targetKey] : null;
28346
+ if (handler) {
28347
+ _.each(handler.events, function (eventTypeHandler, eventType) {
28348
+ if (eventTypeHandler && eventTypeHandler.guideIds) {
28349
+ delete eventTypeHandler.guideIds[domActivationGuide.id];
28350
+ if (_.size(eventTypeHandler.guideIds) <= 0) {
28351
+ if (eventType === 'mouseover') {
28352
+ eventType = 'mouseenter';
28353
+ }
28354
+ detachEvent(handler.target, eventType, eventTypeHandler.fn);
28355
+ delete handler.events[eventType];
28356
+ }
28357
+ }
28358
+ });
28359
+ if (_.size(handler.events) <= 0) {
28360
+ delete handler.target[keyAttr];
28361
+ handler.target = null;
28362
+ delete activationTargets[targetKey];
28363
+ }
28364
+ }
28365
+ });
28366
+ delete activationTargets[domActivationGuide.id];
28367
+ }
28368
+ function eventHandler(e, guideIds) {
28369
+ if (e.pendoActivatedGuide || dom.data.get(e, 'advanced')) {
28370
+ return;
28371
+ }
28372
+ var prioritizeAdoptGuides = ConfigReader.get('adoptPrioritizeAdoptGuides');
28373
+ var guides = _.compact(_.map(_.keys(guideIds), function (id) {
28374
+ return findGuideById(id);
28375
+ }));
28376
+ guides = _.filter(guides, function (guide) {
28377
+ if (!guide.steps || !guide.steps.length) {
28378
+ return false;
28379
+ }
28380
+ if (_.get(guide, 'attributes.dom.isOnlyShowOnce')) {
28381
+ return !guide.steps[0].hasBeenSeen();
28382
+ }
28383
+ return true;
28384
+ });
28385
+ guides = _(guides).chain()
28386
+ .sortBy(function (guide) {
28387
+ return guide.state === 'staged' ? 0 : 1;
28388
+ })
28389
+ .sortBy(function (guide) {
28390
+ var isAdoptGuide = guide.isTraining;
28391
+ if (prioritizeAdoptGuides) {
28392
+ return isAdoptGuide ? 0 : 1;
28393
+ }
28394
+ return isAdoptGuide ? 1 : 0;
28395
+ })
28396
+ .value();
28397
+ var activatedGuide = _.find(guides, function (guide) {
28398
+ var firstStep = _.first(guide.steps);
28399
+ var isResourceCenter = _.get(guide, 'attributes.resourceCenter', false);
28400
+ if (isResourceCenter && guide.isShown()) {
28401
+ return BuildingBlockResourceCenter.dismissResourceCenter();
28402
+ }
28403
+ if (!firstStep.canShow())
28404
+ return false;
28405
+ if (guide.isShown())
28406
+ return true;
28407
+ return showGuide(firstStep, 'dom');
28408
+ });
28409
+ if (activatedGuide) {
28410
+ e.pendoActivatedGuide = activatedGuide.id;
28411
+ }
28412
+ }
28413
+ function reset() {
28414
+ _.each(domActivatedGuides, function (domActivationGuide) {
28415
+ detachGuideFromTarget(domActivationGuide, activationTargets);
28416
+ domActivationGuide.targets = [];
28417
+ });
28418
+ domActivatedGuides.length = 0;
28419
+ }
28420
+ function activates(guide) {
28421
+ if (!guide.id || !guide.steps || !guide.steps.length || !guide.hasLaunchMethod('dom'))
28422
+ return;
28423
+ if (!guide.steps[0].canShowOnPage(getNormalizedUrl()))
28424
+ return;
28425
+ var events = _.get(guide, 'attributes.activation.event', []);
28426
+ if (!events || !events.length)
28427
+ return;
28428
+ var selector = getActivationSelector(guide);
28429
+ if (!selector)
28430
+ return;
28431
+ return {
28432
+ id: guide.id,
28433
+ events,
28434
+ selector,
28435
+ targets: []
28436
+ };
28437
+ }
28438
+ function init(guideList) {
28439
+ _.each(guideList, function (guide) {
28440
+ var domActivatedGuide = activates(guide);
28441
+ if (domActivatedGuide) {
28442
+ domActivatedGuides.push(domActivatedGuide);
28443
+ }
28444
+ });
28445
+ }
28446
+ function prefetch(guides) {
28447
+ if (ConfigReader.get('disablePrefetch')) {
28448
+ return;
28449
+ }
28450
+ _.each(guides, function (guide) {
28451
+ if (!_.isFunction(guide.hasLaunchMethod) || !guide.hasLaunchMethod('dom'))
28452
+ return;
28453
+ if (!guide.steps || !guide.steps.length || !_.isFunction(guide.steps[0].fetchContent))
28454
+ return;
28455
+ guide.steps[0].fetchContent(true);
28456
+ });
28457
+ }
28458
+ })();
28459
+
28460
+ function AdvanceTrigger(element, method, step) {
28461
+ this.element = element;
28462
+ if (method == 'element') {
28463
+ this.method = 'click';
28464
+ }
28465
+ else if (method == 'hover') {
28466
+ this.method = 'mouseover';
28467
+ }
28468
+ else {
28469
+ this.method = method;
28470
+ }
28471
+ this.step = step;
28472
+ this.guide = step.getGuide();
28473
+ }
28474
+ AdvanceTrigger.prototype.add = function () {
28475
+ if (_.indexOf(this.guide.steps, this.step) === 0 && !AdvanceTrigger.shouldAttachHandler(this.guide, this.method))
28476
+ return;
28477
+ if (!isBadge(this.guide) || isWalkthrough(this.guide)) {
28478
+ this.setupElementEvent(this.element, this.method);
28479
+ }
28480
+ };
28481
+ AdvanceTrigger.prototype.remove = function () {
28482
+ this.teardownElementEvent(this.element, this.method);
28483
+ };
28484
+ // HTBD: (aka Here There Be Dragons)
28485
+ // Instead of detaching on hide, we're going to leave the
28486
+ // attach live until it's either advanced, dismissed or
28487
+ // re-rendered. The reason for this is it's too easy for
28488
+ // a race case to happen where the hide for this guide can
28489
+ // happen before the element click event happens and thus we
28490
+ // never get the onguideadvanced action being called.
28491
+ AdvanceTrigger.prototype.setupElementEvent = function (element, evt) {
28492
+ if (!this.advanceFn) {
28493
+ this.advanceFn = _.compose(_.bind(this.teardownElementEvent, this, element, evt), _.bind(this.step.advance, this.step));
28494
+ }
28495
+ AdvanceTrigger.attach(this.step, element, evt, this.advanceFn);
28496
+ };
28497
+ AdvanceTrigger.prototype.teardownElementEvent = function (element, evt) {
28498
+ log.info('detach onGuideAdvanced', { contexts: ['guide'] });
28499
+ detachEvent(element, evt, this.advanceFn, true);
28500
+ this.step.removeTrigger(this);
28501
+ };
28502
+ AdvanceTrigger.shouldAttachHandler = function shouldAttachHandler(guide, method) {
28503
+ return !guide.isActivatedByEvent(method) ||
28504
+ DOMActivation.activates(guide) ||
28505
+ (guide.attributes.activation.selector !== guide.steps[0].elementPathRule &&
28506
+ !!guide.attributes.activation.selector);
28507
+ };
28508
+ AdvanceTrigger.attach = function (step, element, evt, advanceFn) {
28509
+ if (!step)
28510
+ return;
28511
+ var handlers = AdvanceTrigger.handlers = AdvanceTrigger.handlers || {};
28512
+ var stepHandlers = handlers[step.id] = handlers[step.id] || [];
28513
+ for (var i = 0; i < stepHandlers.length; ++i) {
28514
+ var handler = stepHandlers[i];
28515
+ if (element === handler[0] && evt === handler[1]) {
28516
+ detachEvent(element, evt, handler[2], true);
28517
+ stepHandlers.splice(_.indexOf(stepHandlers, handler), 1);
28518
+ i--;
28519
+ }
28520
+ }
28521
+ stepHandlers.push([element, evt, advanceFn]);
28522
+ detachEvent(element, evt, advanceFn, true);
28523
+ attachEvent(element, evt, advanceFn, true);
28524
+ };
28525
+
28169
28526
  var registeredPlugins = [];
28170
28527
  var initialized$1 = false;
28171
28528
  const PluginAPI = {
@@ -28216,7 +28573,8 @@ const PluginAPI = {
28216
28573
  registerDisplayableGuides,
28217
28574
  removeDisplayableGuides,
28218
28575
  GuideFactory,
28219
- GuideStepFactory
28576
+ GuideStepFactory,
28577
+ AdvanceTrigger
28220
28578
  },
28221
28579
  hosts: {
28222
28580
  SERVER
@@ -28965,7 +29323,7 @@ function autoInitialize() {
28965
29323
  }
28966
29324
  flushCallQueue();
28967
29325
  }
28968
- function startup(callQueue, autoInitialize, whenLoadedCall) {
29326
+ function startup(callQueue, autoInitialize) {
28969
29327
  const disableAutoInitialize = ConfigReader.get('disableAutoInitialize');
28970
29328
  if (disableAutoInitialize)
28971
29329
  return;
@@ -28975,7 +29333,9 @@ function startup(callQueue, autoInitialize, whenLoadedCall) {
28975
29333
  autoInitialize();
28976
29334
  }
28977
29335
  else {
28978
- teardownFns.push(whenLoadedCall(autoInitialize));
29336
+ teardownFns.push(whenLoadedCall(() => {
29337
+ teardownFns.push(whenVisibleCall(autoInitialize));
29338
+ }));
28979
29339
  }
28980
29340
  }
28981
29341
  /**
@@ -34831,6 +35191,8 @@ const IFrameMonitor = (function () {
34831
35191
  return true;
34832
35192
  if (frame.pendo && (frame.pendo.initialize || frame.pendo.iframeWaiting))
34833
35193
  return true;
35194
+ if (frame.document && frame.document.body && !frame.document.body.hasChildNodes())
35195
+ return true;
34834
35196
  return scriptExists(frame);
34835
35197
  }
34836
35198
  function appendScriptTagToFrame(frame, agentUrl) {
@@ -34928,278 +35290,6 @@ const IFrameMonitor = (function () {
34928
35290
  }
34929
35291
  })();
34930
35292
 
34931
- function arrayEquals(array1, array2) {
34932
- if (array1.length != array2.length)
34933
- return false;
34934
- return _.all(array1, function (item, i) {
34935
- return item === array2[i];
34936
- });
34937
- }
34938
- class DOMActivationPhase {
34939
- constructor(DOMActivation) {
34940
- this.maxTargets = 50;
34941
- this.domActivation = DOMActivation;
34942
- this.name = 'dom';
34943
- this.queue = [];
34944
- }
34945
- markDirty() {
34946
- this.queue.push.apply(this.queue, this.domActivation.guides);
34947
- }
34948
- process(monitor) {
34949
- var domActivationGuide = this.queue.shift();
34950
- if (!domActivationGuide)
34951
- return;
34952
- monitor.saveContext(domActivationGuide);
34953
- var targets;
34954
- try {
34955
- targets = SizzleProxy(domActivationGuide.selector);
34956
- }
34957
- catch (e) {
34958
- targets = [];
34959
- }
34960
- if (targets.length > this.maxTargets) {
34961
- targets.length = this.maxTargets;
34962
- }
34963
- if (!arrayEquals(targets, domActivationGuide.targets)) {
34964
- domActivationGuide.targets = targets;
34965
- this.domActivation.detach(domActivationGuide, this.domActivation.targets);
34966
- _.each(targets, function (target) {
34967
- this.domActivation.attach(target, domActivationGuide, this.domActivation.targets);
34968
- }, this);
34969
- }
34970
- }
34971
- handleProcessTimeExceeded(monitor) {
34972
- const ctx = monitor.getContext();
34973
- if (ctx) {
34974
- log.warn('Element activated guide (' + ctx.id + ') timeout exceeded');
34975
- }
34976
- }
34977
- cancel() {
34978
- this.queue.length = 0;
34979
- }
34980
- isComplete() {
34981
- return !this.queue.length;
34982
- }
34983
- }
34984
- var DOMActivation = (function () {
34985
- var keyAttr = 'pendoTargetId';
34986
- var pluginApi;
34987
- /*
34988
- domActivatedGuides = [
34989
- {
34990
- id: 'aGuideId',
34991
- events: ['click', 'mouseover'],
34992
- selector: '.selector .for .target',
34993
- targets: [array, of, dom, references]
34994
- }
34995
- ]
34996
- */
34997
- var domActivatedGuides = [];
34998
- /*
34999
- activationTargets = {
35000
- aGuideId: 'aTargetId',
35001
- aTargetId: {
35002
- target: {{referenceToDomElement}},
35003
- events: {
35004
- click: {
35005
- guideIds: {
35006
- aGuideId: 1,
35007
- anotherGuideId: 1
35008
- },
35009
- fn: {{partial(eventHandler, guideIds)}}
35010
- },
35011
- mouseover: {{same format as click}}
35012
- }
35013
- }
35014
- {{more guide and target ids...}}
35015
- }
35016
- */
35017
- var activationTargets = {};
35018
- var domPhase;
35019
- return {
35020
- name: 'DOMActivation',
35021
- key: keyAttr,
35022
- guides: domActivatedGuides,
35023
- targets: activationTargets,
35024
- reset,
35025
- init,
35026
- attach: attachGuideToTarget,
35027
- detach: detachGuideFromTarget,
35028
- handler: eventHandler,
35029
- activates,
35030
- prefetch,
35031
- initialize,
35032
- teardown
35033
- };
35034
- function initialize(pendo, PluginAPI) {
35035
- pluginApi = PluginAPI;
35036
- PluginAPI.Events.on('deliverablesLoaded', reset);
35037
- PluginAPI.Events.on('guideListChanged', handleGuideListChanged);
35038
- PluginAPI.Events.on('guidesLoaded', handleGuidesLoaded);
35039
- domPhase = new DOMActivationPhase(DOMActivation);
35040
- addUpdatePhase(domPhase);
35041
- }
35042
- function teardown() {
35043
- removeUpdatePhase(domPhase);
35044
- pluginApi.Events.off('deliverablesLoaded', reset);
35045
- pluginApi.Events.off('guideListChanged', handleGuideListChanged);
35046
- pluginApi.Events.off('guidesLoaded', handleGuidesLoaded);
35047
- }
35048
- function handleGuideListChanged() {
35049
- reset();
35050
- init(getLocalActiveGuides());
35051
- }
35052
- function handleGuidesLoaded() {
35053
- prefetch(getLocalActiveGuides());
35054
- }
35055
- function attachGuideToTarget(target, domActivationGuide, activationTargets) {
35056
- var targetKey = target[keyAttr];
35057
- var handler = targetKey ? activationTargets[targetKey] : null;
35058
- if (!handler) {
35059
- targetKey = targetKey || 'target' + _.uniqueId();
35060
- handler = {
35061
- target,
35062
- events: {}
35063
- };
35064
- activationTargets[targetKey] = handler;
35065
- target[keyAttr] = targetKey;
35066
- }
35067
- var targetList = activationTargets[domActivationGuide.id] || [];
35068
- targetList.push(targetKey);
35069
- activationTargets[domActivationGuide.id] = targetList;
35070
- _.each(domActivationGuide.events, function (eventType) {
35071
- var eventTypeHandler = handler.events[eventType];
35072
- if (!eventTypeHandler) {
35073
- eventTypeHandler = {
35074
- guideIds: {}
35075
- };
35076
- eventTypeHandler.fn = _.partial(eventHandler, _, eventTypeHandler.guideIds);
35077
- if (eventType === 'mouseover') {
35078
- eventType = 'mouseenter';
35079
- }
35080
- attachEvent(target, eventType, eventTypeHandler.fn);
35081
- handler.events[eventType] = eventTypeHandler;
35082
- }
35083
- eventTypeHandler.guideIds[domActivationGuide.id] = 1;
35084
- });
35085
- }
35086
- function detachGuideFromTarget(domActivationGuide, activationTargets) {
35087
- _.each(activationTargets[domActivationGuide.id], function (targetKey) {
35088
- var handler = targetKey ? activationTargets[targetKey] : null;
35089
- if (handler) {
35090
- _.each(handler.events, function (eventTypeHandler, eventType) {
35091
- if (eventTypeHandler && eventTypeHandler.guideIds) {
35092
- delete eventTypeHandler.guideIds[domActivationGuide.id];
35093
- if (_.size(eventTypeHandler.guideIds) <= 0) {
35094
- if (eventType === 'mouseover') {
35095
- eventType = 'mouseenter';
35096
- }
35097
- detachEvent(handler.target, eventType, eventTypeHandler.fn);
35098
- delete handler.events[eventType];
35099
- }
35100
- }
35101
- });
35102
- if (_.size(handler.events) <= 0) {
35103
- delete handler.target[keyAttr];
35104
- handler.target = null;
35105
- delete activationTargets[targetKey];
35106
- }
35107
- }
35108
- });
35109
- delete activationTargets[domActivationGuide.id];
35110
- }
35111
- function eventHandler(e, guideIds) {
35112
- if (e.pendoActivatedGuide || dom.data.get(e, 'advanced')) {
35113
- return;
35114
- }
35115
- var prioritizeAdoptGuides = ConfigReader.get('adoptPrioritizeAdoptGuides');
35116
- var guides = _.compact(_.map(_.keys(guideIds), function (id) {
35117
- return findGuideById(id);
35118
- }));
35119
- guides = _.filter(guides, function (guide) {
35120
- if (!guide.steps || !guide.steps.length) {
35121
- return false;
35122
- }
35123
- if (_.get(guide, 'attributes.dom.isOnlyShowOnce')) {
35124
- return !guide.steps[0].hasBeenSeen();
35125
- }
35126
- return true;
35127
- });
35128
- guides = _(guides).chain()
35129
- .sortBy(function (guide) {
35130
- return guide.state === 'staged' ? 0 : 1;
35131
- })
35132
- .sortBy(function (guide) {
35133
- var isAdoptGuide = guide.isTraining;
35134
- if (prioritizeAdoptGuides) {
35135
- return isAdoptGuide ? 0 : 1;
35136
- }
35137
- return isAdoptGuide ? 1 : 0;
35138
- })
35139
- .value();
35140
- var activatedGuide = _.find(guides, function (guide) {
35141
- var firstStep = _.first(guide.steps);
35142
- var isResourceCenter = _.get(guide, 'attributes.resourceCenter', false);
35143
- if (isResourceCenter && guide.isShown()) {
35144
- return BuildingBlockResourceCenter.dismissResourceCenter();
35145
- }
35146
- if (!firstStep.canShow())
35147
- return false;
35148
- if (guide.isShown())
35149
- return true;
35150
- return showGuide(firstStep, 'dom');
35151
- });
35152
- if (activatedGuide) {
35153
- e.pendoActivatedGuide = activatedGuide.id;
35154
- }
35155
- }
35156
- function reset() {
35157
- _.each(domActivatedGuides, function (domActivationGuide) {
35158
- detachGuideFromTarget(domActivationGuide, activationTargets);
35159
- domActivationGuide.targets = [];
35160
- });
35161
- domActivatedGuides.length = 0;
35162
- }
35163
- function activates(guide) {
35164
- if (!guide.id || !guide.steps || !guide.steps.length || !guide.hasLaunchMethod('dom'))
35165
- return;
35166
- if (!guide.steps[0].canShowOnPage(getNormalizedUrl()))
35167
- return;
35168
- var events = _.get(guide, 'attributes.activation.event', []);
35169
- if (!events || !events.length)
35170
- return;
35171
- var selector = getActivationSelector(guide);
35172
- if (!selector)
35173
- return;
35174
- return {
35175
- id: guide.id,
35176
- events,
35177
- selector,
35178
- targets: []
35179
- };
35180
- }
35181
- function init(guideList) {
35182
- _.each(guideList, function (guide) {
35183
- var domActivatedGuide = activates(guide);
35184
- if (domActivatedGuide) {
35185
- domActivatedGuides.push(domActivatedGuide);
35186
- }
35187
- });
35188
- }
35189
- function prefetch(guides) {
35190
- if (ConfigReader.get('disablePrefetch')) {
35191
- return;
35192
- }
35193
- _.each(guides, function (guide) {
35194
- if (!_.isFunction(guide.hasLaunchMethod) || !guide.hasLaunchMethod('dom'))
35195
- return;
35196
- if (!guide.steps || !guide.steps.length || !_.isFunction(guide.steps[0].fetchContent))
35197
- return;
35198
- guide.steps[0].fetchContent(true);
35199
- });
35200
- }
35201
- })();
35202
-
35203
35293
  var designer;
35204
35294
  function designerExports() {
35205
35295
  return {
@@ -35569,72 +35659,6 @@ var PromoteMetadata = (function () {
35569
35659
  }
35570
35660
  })();
35571
35661
 
35572
- function AdvanceTrigger(element, method, step) {
35573
- this.element = element;
35574
- if (method == 'element') {
35575
- this.method = 'click';
35576
- }
35577
- else if (method == 'hover') {
35578
- this.method = 'mouseover';
35579
- }
35580
- else {
35581
- this.method = method;
35582
- }
35583
- this.step = step;
35584
- this.guide = step.getGuide();
35585
- }
35586
- AdvanceTrigger.prototype.add = function () {
35587
- if (_.indexOf(this.guide.steps, this.step) === 0 && !AdvanceTrigger.shouldAttachHandler(this.guide, this.method))
35588
- return;
35589
- if (!isBadge(this.guide) || isWalkthrough(this.guide)) {
35590
- this.setupElementEvent(this.element, this.method);
35591
- }
35592
- };
35593
- AdvanceTrigger.prototype.remove = function () {
35594
- this.teardownElementEvent(this.element, this.method);
35595
- };
35596
- // HTBD: (aka Here There Be Dragons)
35597
- // Instead of detaching on hide, we're going to leave the
35598
- // attach live until it's either advanced, dismissed or
35599
- // re-rendered. The reason for this is it's too easy for
35600
- // a race case to happen where the hide for this guide can
35601
- // happen before the element click event happens and thus we
35602
- // never get the onguideadvanced action being called.
35603
- AdvanceTrigger.prototype.setupElementEvent = function (element, evt) {
35604
- if (!this.advanceFn) {
35605
- this.advanceFn = _.compose(_.bind(this.teardownElementEvent, this, element, evt), _.bind(this.step.advance, this.step));
35606
- }
35607
- AdvanceTrigger.attach(this.step, element, evt, this.advanceFn);
35608
- };
35609
- AdvanceTrigger.prototype.teardownElementEvent = function (element, evt) {
35610
- log.info('detach onGuideAdvanced', { contexts: ['guide'] });
35611
- detachEvent(element, evt, this.advanceFn, true);
35612
- this.step.removeTrigger(this);
35613
- };
35614
- AdvanceTrigger.shouldAttachHandler = function shouldAttachHandler(guide, method) {
35615
- return !guide.isActivatedByEvent(method) ||
35616
- DOMActivation.activates(guide) ||
35617
- (guide.attributes.activation.selector !== guide.steps[0].elementPathRule &&
35618
- !!guide.attributes.activation.selector);
35619
- };
35620
- AdvanceTrigger.attach = function (step, element, evt, advanceFn) {
35621
- if (!step)
35622
- return;
35623
- var handlers = AdvanceTrigger.handlers = AdvanceTrigger.handlers || {};
35624
- var stepHandlers = handlers[step.id] = handlers[step.id] || [];
35625
- for (var i = 0; i < stepHandlers.length; ++i) {
35626
- var handler = stepHandlers[i];
35627
- if (element === handler[0] && evt === handler[1]) {
35628
- detachEvent(element, evt, handler[2], true);
35629
- stepHandlers.splice(_.indexOf(stepHandlers, handler), 1);
35630
- i--;
35631
- }
35632
- }
35633
- stepHandlers.push([element, evt, advanceFn]);
35634
- detachEvent(element, evt, advanceFn, true);
35635
- attachEvent(element, evt, advanceFn, true);
35636
- };
35637
-
35638
35662
  var TOOLTIP_DEFAULT_WIDTH = 430;
35639
35663
  var TOOLTIP_DEFAULT_HEIGHT = 200;
35640
35664
  var TOOLTIP_ARROW_SIZE = 15;
@@ -40646,7 +40670,7 @@ function initAgent(pendo, PendoConfig) {
40646
40670
  populatePendoObject(pendo);
40647
40671
  log.addEventListener('log', _.partial(store.dispatch, 'errorLog/write'));
40648
40672
  registerBuiltInPlugins();
40649
- startup(pendo._q, autoInitialize, whenLoadedCall);
40673
+ startup(pendo._q, autoInitialize);
40650
40674
  return true;
40651
40675
  }
40652
40676
 
@@ -54401,7 +54425,15 @@ class SessionRecorder {
54401
54425
  this._startRecordingForVisitor(visitorConfig);
54402
54426
  }).catch((e) => {
54403
54427
  this.restartPtm();
54404
- this.api.log.critical('Failed to fetch recording config', { error: e });
54428
+ if (e && /Failed to fetch/.test(e.toString())) {
54429
+ return;
54430
+ }
54431
+ this.api.log.critical('Failed to fetch recording config', {
54432
+ error: e,
54433
+ visitorId: this.visitorId,
54434
+ accountId: this.accountId,
54435
+ url: this.pendo.url.get()
54436
+ });
54405
54437
  this.logStopReason('VISITOR_CONFIG_ERROR');
54406
54438
  });
54407
54439
  }
@@ -55458,8 +55490,10 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
55458
55490
 
55459
55491
  const ONE_HUNDRED_MB_IN_BYTES = 100 * 1024 * 1024;
55460
55492
  function matchHostedResources(recordingEvent, stringifiedRecordingPayload) {
55461
- const fontURLRegex = /https:\/\/[^\s]+?\.(woff2?|ttf|otf|eot)(\?[^\s]*)?\b/g;
55462
- const hostedResources = stringifiedRecordingPayload.match(fontURLRegex);
55493
+ const fontURLRegex = /https:\/\/[^"\\\s]+?\.(woff2?|ttf|otf|eot)(\?[^"\\\s]*)?\b/g;
55494
+ const matches = stringifiedRecordingPayload.match(fontURLRegex);
55495
+ // de-duplicate matches
55496
+ const hostedResources = matches ? Array.from(new Set(matches)) : [];
55463
55497
  return {
55464
55498
  type: 'recording',
55465
55499
  visitorId: recordingEvent.visitorId,
@@ -55474,7 +55508,7 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
55474
55508
  recordingPayloadMetadata: [],
55475
55509
  sequence: 0,
55476
55510
  recordingPayloadCount: 0,
55477
- hostedResources: hostedResources || []
55511
+ hostedResources
55478
55512
  };
55479
55513
  }
55480
55514
  // keep in mind changes here may need addressing in the extension worker proxy as well
@@ -56739,6 +56773,17 @@ var ConfigReader = (function () {
56739
56773
  */
56740
56774
  addOption('dataHost', [SNIPPET_SRC, PENDO_CONFIG_SRC]);
56741
56775
  addOption('disableAutoInitialize');
56776
+ /**
56777
+ * If set to `true` the web SDK will wait for the host application to be both loaded and visible before
56778
+ * starting the initialization process.
56779
+ *
56780
+ * @access public
56781
+ * @category Config/Core
56782
+ * @name initializeWhenVisible
56783
+ * @default false
56784
+ * @type {boolean}
56785
+ */
56786
+ addOption('initializeWhenVisible', [SNIPPET_SRC, PENDO_CONFIG_SRC], false);
56742
56787
  /**
56743
56788
  * Although the name refers to cookies, if set to `true` the web SDK will not persist any data in local
56744
56789
  * storage or cookies and will rely only on memory.
@@ -58931,7 +58976,7 @@ const PREDICT_STEP_REGEX = /\$\$predict\$\$/;
58931
58976
  const DRAG_THRESHOLD = 5;
58932
58977
  const STYLE_ID = 'pendo-predict-plugin-styles';
58933
58978
  const PREDICT_BASE_URL = 'https://predict.pendo.io';
58934
- const BUTTON_CLASS_IDENTIFIER = '._pendo-button-primaryButton:contains("token")';
58979
+ const GUIDE_BUTTON_IDENTIFIER = 'button:contains("token")';
58935
58980
  const pluginVersion = '1.0.0';
58936
58981
  const $ = (id) => document.getElementById(id);
58937
58982
  const createElement = (tag, attrs = {}, parent = null) => {
@@ -58950,10 +58995,13 @@ const createElement = (tag, attrs = {}, parent = null) => {
58950
58995
  parent.appendChild(el);
58951
58996
  return el;
58952
58997
  };
58953
- const injectStyles = (pendoContainerId) => {
58998
+ const injectStyles = (pendoContainerId, log = () => { }) => {
58954
58999
  const styleId = `${STYLE_ID}-${pendoContainerId}`;
58955
- if ($(styleId))
59000
+ if ($(styleId)) {
59001
+ log(`[predict] style already exists, skipping: ${styleId}`);
58956
59002
  return;
59003
+ }
59004
+ log(`[predict] injecting styles: ${styleId}`);
58957
59005
  createElement('style', {
58958
59006
  id: styleId,
58959
59007
  textContent: `
@@ -59002,10 +59050,12 @@ const injectStyles = (pendoContainerId) => {
59002
59050
  `
59003
59051
  }, document.head);
59004
59052
  };
59005
- const getRecordIdFromUrl = (recordRegex) => {
59053
+ const getRecordIdFromUrl = (recordRegex, log = () => { }) => {
59006
59054
  var _a;
59007
59055
  const match = window.location.href.match(recordRegex);
59008
- return (_a = match === null || match === void 0 ? void 0 : match[1]) !== null && _a !== void 0 ? _a : null;
59056
+ const recordId = (_a = match === null || match === void 0 ? void 0 : match[1]) !== null && _a !== void 0 ? _a : null;
59057
+ log(`[predict] recordId found: ${recordId}`);
59058
+ return recordId;
59009
59059
  };
59010
59060
  const safeStringify = (value, fallback) => {
59011
59061
  try {
@@ -59015,11 +59065,12 @@ const safeStringify = (value, fallback) => {
59015
59065
  return fallback !== null && fallback !== void 0 ? fallback : '';
59016
59066
  }
59017
59067
  };
59018
- const safeParse = (value, fallback) => {
59068
+ const safeParse = (value, fallback, log = () => { }) => {
59019
59069
  try {
59020
59070
  return JSON.parse(value);
59021
59071
  }
59022
59072
  catch (error) {
59073
+ log(`[predict] JSON parse error: ${error}`);
59023
59074
  return fallback;
59024
59075
  }
59025
59076
  };
@@ -59163,10 +59214,9 @@ const createFloatingModal = ({ recordId, configuration }) => {
59163
59214
  }, container);
59164
59215
  container.dragHandle = setupDragAndDrop(dragHandle, container);
59165
59216
  return () => {
59166
- var _a, _b, _c;
59217
+ var _a, _b;
59167
59218
  (_b = (_a = container.dragHandle) === null || _a === void 0 ? void 0 : _a.cleanup) === null || _b === void 0 ? void 0 : _b.call(_a);
59168
59219
  container.remove();
59169
- const flatIds = (_c = configuration.analysisIds) === null || _c === void 0 ? void 0 : _c.flat(Infinity);
59170
59220
  for (let i = 0; i < flatIds.length; i++) {
59171
59221
  const frame = $(`frameExplanation-${flatIds[i]}`);
59172
59222
  if (frame)
@@ -59258,23 +59308,33 @@ const setupMessageListener = ({ token, cleanup, pendo }) => {
59258
59308
  window.addEventListener('message', messageHandler);
59259
59309
  return () => window.removeEventListener('message', messageHandler);
59260
59310
  };
59261
- const predictGuidesScript = ({ step, pendo, cleanupArray, cleanup }) => {
59311
+ const predictGuidesScript = ({ step, pendo, cleanupArray, cleanup, log }) => {
59262
59312
  var _a;
59263
- if (cleanupArray.length > 0)
59313
+ log('[predict] initializing');
59314
+ // Before anything else, inject styles so that the guide will be hidden
59315
+ const pendoContainerId = step === null || step === void 0 ? void 0 : step.containerId;
59316
+ injectStyles(pendoContainerId, log);
59317
+ if (cleanupArray.length > 0) {
59318
+ log('[predict] cleanupArray is not empty');
59264
59319
  return;
59320
+ }
59265
59321
  // ----- Extract Configuration -----
59266
- const pendoButtonPrimaryButton = (_a = step.guideElement.find(BUTTON_CLASS_IDENTIFIER)) === null || _a === void 0 ? void 0 : _a[0];
59267
- if (!pendoButtonPrimaryButton)
59322
+ const guideButton = (_a = step.guideElement.find(GUIDE_BUTTON_IDENTIFIER)) === null || _a === void 0 ? void 0 : _a[0];
59323
+ if (!guideButton) {
59324
+ log('[predict] no guide button found, aborting');
59268
59325
  return;
59269
- const _b = safeParse(pendoButtonPrimaryButton.textContent, null), { token } = _b, configuration = __rest(_b, ["token"]);
59270
- if (!configuration)
59326
+ }
59327
+ const _b = safeParse(guideButton.textContent, {}, log), { token } = _b, configuration = __rest(_b, ["token"]);
59328
+ if (!configuration || !token) {
59329
+ log('[predict] no configuration found, aborting');
59271
59330
  return;
59272
- const pendoContainerId = step === null || step === void 0 ? void 0 : step.containerId;
59273
- injectStyles(pendoContainerId);
59274
- const recordRegex = new RegExp(`/${configuration.recordRegexName}/([a-zA-Z0-9]{15,18})(?:/|$)`);
59275
- const recordId = getRecordIdFromUrl(recordRegex);
59276
- if (!recordId)
59331
+ }
59332
+ const recordRegex = new RegExp(`/${configuration.recordRegexName}/([a-zA-Z0-9]+)(?:/|$)`);
59333
+ const recordId = getRecordIdFromUrl(recordRegex, log);
59334
+ if (!recordId) {
59335
+ log('[predict] no recordId found in URL, aborting');
59277
59336
  return;
59337
+ }
59278
59338
  cleanupArray.push(setupMessageListener({ token, cleanup, pendo }));
59279
59339
  cleanupArray.push(createFloatingModal({ recordId, configuration }));
59280
59340
  };
@@ -59283,11 +59343,13 @@ const PredictGuides = () => {
59283
59343
  let pluginApiRef = null;
59284
59344
  let cleanupArray = [];
59285
59345
  const cleanup = () => {
59346
+ var _a;
59347
+ (_a = pluginApiRef === null || pluginApiRef === void 0 ? void 0 : pluginApiRef.log) === null || _a === void 0 ? void 0 : _a.debug('[predict] cleaning up');
59286
59348
  for (let i = 0; i < cleanupArray.length; i++) {
59287
59349
  try {
59288
59350
  cleanupArray[i]();
59289
59351
  }
59290
- catch (_a) { }
59352
+ catch (_b) { }
59291
59353
  }
59292
59354
  cleanupArray = [];
59293
59355
  };
@@ -59302,11 +59364,12 @@ const PredictGuides = () => {
59302
59364
  const predictGuidesEnabled = configReader.get(PREDICT_GUIDES_CONFIG);
59303
59365
  if (!predictGuidesEnabled)
59304
59366
  return;
59367
+ const log = PluginAPI.log.debug.bind(PluginAPI.log);
59305
59368
  pluginApiRef.Events.urlChanged.on(cleanup);
59306
59369
  const script = {
59307
59370
  name: 'PredictFrameScript',
59308
59371
  script(step, _guide, pendo) {
59309
- predictGuidesScript({ step, pendo, cleanupArray, cleanup });
59372
+ predictGuidesScript({ step, pendo, cleanupArray, cleanup, log });
59310
59373
  this.on('unmounted', (evt) => {
59311
59374
  if (evt.reason !== 'hidden')
59312
59375
  cleanup();