@pendo/agent 2.290.2 → 2.291.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.
@@ -2992,7 +2992,8 @@ var ConfigReader = (function () {
2992
2992
  /**
2993
2993
  * Use this setting when using `preferMutationObserver` with an application that has Shadow DOM elements.
2994
2994
  * On page load, the Agent will run a full document scan for shadow roots and attach a MutationObserver to
2995
- * all results.
2995
+ * all results. This setting also allows the agent to run CSS selectors in all shadow roots, so CSS selectors
2996
+ * can be written without specifying the full path through all shadow roots with the `::shadow` pseudo-class.
2996
2997
  *
2997
2998
  * @access public
2998
2999
  * @category Config/Core
@@ -3903,8 +3904,8 @@ var SERVER = '';
3903
3904
  var ASSET_HOST = '';
3904
3905
  var ASSET_PATH = '';
3905
3906
  var DESIGNER_SERVER = '';
3906
- var VERSION = '2.290.2_';
3907
- var PACKAGE_VERSION = '2.290.2';
3907
+ var VERSION = '2.291.1_';
3908
+ var PACKAGE_VERSION = '2.291.1';
3908
3909
  var LOADER = 'xhr';
3909
3910
  /* eslint-enable agent-eslint-rules/no-gulp-env-references */
3910
3911
  /**
@@ -6131,6 +6132,16 @@ function isElementShadowRoot(elem, _win) {
6131
6132
  function getParent(elem, _win) {
6132
6133
  return isElementShadowRoot(elem, _win) ? elem.host : elem.parentNode;
6133
6134
  }
6135
+ function contains(context, elem, _win) {
6136
+ let parent = elem;
6137
+ while (parent) {
6138
+ if (parent === context) {
6139
+ return true;
6140
+ }
6141
+ parent = getParent(parent, _win);
6142
+ }
6143
+ return false;
6144
+ }
6134
6145
 
6135
6146
  var shadowAPI = (function () {
6136
6147
  function isShadowSelector(selector) {
@@ -6163,10 +6174,19 @@ var shadowAPI = (function () {
6163
6174
  isElementShadowRoot: isElementShadowRoot,
6164
6175
  getParent: getParent,
6165
6176
  isShadowSelector,
6166
- wrapSizzle(Sizzle) {
6177
+ wrapSizzle(Sizzle, shadowDomManager) {
6167
6178
  Sizzle.intercept(function (Sizzle, selection, context, results, seed) {
6168
6179
  if (!isShadowSelector(selection)) {
6169
- return Sizzle(selection, context, results, seed);
6180
+ const queryResults = Sizzle(selection, context, results, seed);
6181
+ if (shadowDomManager.cache.size > 0) {
6182
+ // eslint-disable-next-line agent-eslint-rules/no-array-foreach
6183
+ shadowDomManager.cache.forEach(shadowRoot => {
6184
+ if (!context || context === document || contains(context, shadowRoot)) {
6185
+ queryResults.push(...Sizzle(selection, shadowRoot, results, seed));
6186
+ }
6187
+ });
6188
+ }
6189
+ return queryResults;
6170
6190
  }
6171
6191
  if (!_.isFunction(document.documentElement.attachShadow)) {
6172
6192
  return Sizzle(selection.replace(shadowAPI.PSEUDO_REGEX, ''), context, results, seed);
@@ -10041,15 +10061,15 @@ var setStyles = function (element, style) {
10041
10061
  }
10042
10062
  });
10043
10063
  };
10044
- var getScreenDimensions = function () {
10064
+ var getScreenDimensions = function (win = window) {
10045
10065
  if (isBrowserInQuirksmode()) {
10046
10066
  return {
10047
- width: document.documentElement.offsetWidth || 0,
10048
- height: document.documentElement.offsetHeight || 0
10067
+ width: win.document.documentElement.offsetWidth || 0,
10068
+ height: win.document.documentElement.offsetHeight || 0
10049
10069
  };
10050
10070
  }
10051
- var w = window.innerWidth || document.documentElement.clientWidth;
10052
- var h = window.innerHeight || document.documentElement.clientHeight;
10071
+ var w = win.innerWidth || win.document.documentElement.clientWidth;
10072
+ var h = win.innerHeight || win.document.documentElement.clientHeight;
10053
10073
  return { width: w, height: h };
10054
10074
  };
10055
10075
  var _isInViewport = function (elemPos) {
@@ -10185,32 +10205,34 @@ function getSiblings(node) {
10185
10205
  * @param {HTMLElement} element
10186
10206
  * @returns {boolean}
10187
10207
  */
10188
- function isInDocument(element) {
10189
- if (SizzleProxy.contains(document, element))
10208
+ function isInDocument(element, doc = document) {
10209
+ if (SizzleProxy.contains(doc, element))
10190
10210
  return true;
10191
10211
  while (element && element.parentNode || shadowAPI.isElementShadowRoot(element)) {
10192
10212
  element = shadowAPI.getParent(element);
10193
10213
  }
10194
- return element === document;
10214
+ return element === doc;
10195
10215
  }
10196
10216
  var getClientRect = function (element) {
10197
- var pbody = getBody();
10198
- if (element === null) {
10217
+ if (element == null) {
10199
10218
  return;
10200
10219
  }
10201
- else if ((element === document || element === window)) {
10220
+ var doc = element.ownerDocument || document;
10221
+ var win = doc.defaultView || window;
10222
+ var pbody = getBody(doc);
10223
+ if ((element === doc || element === win)) {
10202
10224
  var viewport = {
10203
- left: window.pageXOffset || pbody.scrollLeft,
10204
- top: window.pageYOffset || pbody.scrollTop,
10205
- width: window.innerWidth,
10206
- height: window.innerHeight
10225
+ left: win.pageXOffset || pbody.scrollLeft,
10226
+ top: win.pageYOffset || pbody.scrollTop,
10227
+ width: win.innerWidth,
10228
+ height: win.innerHeight
10207
10229
  };
10208
10230
  viewport.right = viewport.left + viewport.width;
10209
10231
  viewport.bottom = viewport.top + viewport.height;
10210
10232
  return viewport;
10211
10233
  }
10212
10234
  else {
10213
- var clientRect = getOffsetPosition(element);
10235
+ var clientRect = getOffsetPosition(element, win);
10214
10236
  clientRect.right = clientRect.left + clientRect.width;
10215
10237
  clientRect.bottom = clientRect.top + clientRect.height;
10216
10238
  return clientRect;
@@ -11015,7 +11037,7 @@ DomQuery.$ = {
11015
11037
  if (target && target.parentNode) {
11016
11038
  target.parentNode.insertBefore(this[0], target);
11017
11039
  // Execute scripts (if any) when the fragment enters the document
11018
- if (isInDocument(document)) {
11040
+ if (isInDocument(document, this)) {
11019
11041
  _.each(SizzleProxy('script', this[0]), evalScript);
11020
11042
  }
11021
11043
  }
@@ -13763,7 +13785,7 @@ function treatAsMobileDevice() {
13763
13785
  }
13764
13786
  return sniffer.isMobileUserAgent();
13765
13787
  }
13766
- function getGuideAttachPoint() {
13788
+ function getGuideAttachPoint(doc = document) {
13767
13789
  var attachPoint = getGuideAttachPoint.attachPoint;
13768
13790
  if (attachPoint == null) {
13769
13791
  var attachPointSelector = ConfigReader.get('guides.attachPoint');
@@ -13786,7 +13808,7 @@ function getGuideAttachPoint() {
13786
13808
  }
13787
13809
  getGuideAttachPoint.attachPoint = attachPoint;
13788
13810
  }
13789
- return attachPoint || getBody();
13811
+ return attachPoint || getBody(doc);
13790
13812
  }
13791
13813
  var findBadgeForStep = function (step) {
13792
13814
  var badge = badgesShown[step.guideId];
@@ -13809,7 +13831,7 @@ var findBadgeForStep = function (step) {
13809
13831
  * where do we render? find destination for that.
13810
13832
  */
13811
13833
  // this is used for rendering
13812
- var getElementForGuideStep = function (step) {
13834
+ var getElementForGuideStep = function (step, doc) {
13813
13835
  if (!step) {
13814
13836
  log.info('Can\'t get element for null step');
13815
13837
  return null;
@@ -13820,20 +13842,20 @@ var getElementForGuideStep = function (step) {
13820
13842
  if (!step.overrideElement && canSetOverrideElement) {
13821
13843
  step.overrideElement = findBadgeForStep(step);
13822
13844
  }
13823
- step.targetElement = getElementForTargeting(step);
13845
+ step.targetElement = getElementForTargeting(step, doc);
13824
13846
  if (step.overrideElement) {
13825
13847
  return step.overrideElement;
13826
13848
  }
13827
13849
  return step.targetElement;
13828
13850
  };
13829
- var getElementForTargeting = function (step) {
13851
+ var getElementForTargeting = function (step, doc) {
13830
13852
  var selector = step.elementPathRule || null;
13831
13853
  var results;
13832
13854
  if (selector) {
13833
- results = SizzleProxy(selector);
13855
+ results = SizzleProxy(selector, doc);
13834
13856
  }
13835
13857
  else {
13836
- results = [getBody()];
13858
+ results = [getBody(doc)];
13837
13859
  }
13838
13860
  if (results.length === 0) {
13839
13861
  return null;
@@ -16027,7 +16049,7 @@ var BuildingBlockTooltips = (function () {
16027
16049
  const guideContainer = providedGuideContainer || getGuideContainer(step);
16028
16050
  if (!guideContainer)
16029
16051
  return;
16030
- const element = step.element || getElementForGuideStep(step);
16052
+ const element = step.element || getElementForGuideStep(step, guideContainer.ownerDocument || document);
16031
16053
  if (!element)
16032
16054
  return;
16033
16055
  const width = guideContainer.style.width;
@@ -16052,9 +16074,11 @@ var BuildingBlockTooltips = (function () {
16052
16074
  return treatAsMobileDevice() ? MOBILE_TOOLTIP_CSS_NAME : TOOLTIP_CSS_NAME;
16053
16075
  }
16054
16076
  function getTooltipPositioningContext(step, element, json, guideContainer) {
16055
- var elementPos = getOffsetPosition(element);
16077
+ var targetDocument = element.ownerDocument || document;
16078
+ var targetWindow = targetDocument.defaultView || window;
16079
+ var elementPos = getOffsetPosition(element, targetWindow);
16056
16080
  var screenPos = getScreenPosition(element);
16057
- var screenDimensions = getScreenDimensions();
16081
+ var screenDimensions = getScreenDimensions(targetWindow);
16058
16082
  var layoutDir = step.attributes.layoutDir || 'auto';
16059
16083
  // RETURN IF THE FOUND ELEMENT IS NOT VISIBLE ON THE SCREEN.
16060
16084
  if (elementPos.height === 0 && elementPos.width === 0) {
@@ -16102,7 +16126,7 @@ var BuildingBlockTooltips = (function () {
16102
16126
  var tooltipDiv = step.guideElement;
16103
16127
  tooltipDiv.addClass(buildTooltipCSSName());
16104
16128
  attachBBAdvanceActions(step);
16105
- var tooltipDimensions = getBBTooltipDimensions(elementPos, { height: tooltipSizes.height, width: tooltipSizes.width }, caretDimensions, step.attributes.layoutDir, screenPos);
16129
+ var tooltipDimensions = getBBTooltipDimensions(elementPos, { height: tooltipSizes.height, width: tooltipSizes.width }, caretDimensions, step.attributes.layoutDir, screenPos, tooltipContext.screenDimensions);
16106
16130
  if (step) {
16107
16131
  step.dim = tooltipDimensions;
16108
16132
  }
@@ -16181,8 +16205,7 @@ var BuildingBlockTooltips = (function () {
16181
16205
  }
16182
16206
  }
16183
16207
  }
16184
- function getBBTooltipDimensions(elementPos, tooltipSizes, caretSizes, layoutDir, screenPos) {
16185
- var screenDimensions = getScreenDimensions();
16208
+ function getBBTooltipDimensions(elementPos, tooltipSizes, caretSizes, layoutDir, screenPos, screenDimensions) {
16186
16209
  var layoutDirection = layoutDir || 'auto';
16187
16210
  var tooltipDimensions = {
16188
16211
  width: Math.min(tooltipSizes.width, screenDimensions.width),
@@ -16312,23 +16335,23 @@ var BuildingBlockTooltips = (function () {
16312
16335
  else if (layoutDirection === 'top') {
16313
16336
  tooltipPosition.top = elementPosition.top - height;
16314
16337
  }
16315
- const boundaries = getBoundaries();
16338
+ const boundaries = getBoundaries(screenDimensions);
16316
16339
  if (horizontalBias === 'right') {
16317
16340
  tooltipPosition.left = calculateRightBiasPosition(elementPosition, tooltipDimensions, caretSizes, screenDimensions, boundaries.right, boundaries.left);
16318
16341
  }
16319
16342
  else if (horizontalBias === 'left') {
16320
- tooltipPosition.left = calculateLeftBiasPosition(elementPosition, tooltipDimensions, caretSizes, boundaries.right, boundaries.left);
16343
+ tooltipPosition.left = calculateLeftBiasPosition(elementPosition, tooltipDimensions, caretSizes, screenDimensions, boundaries.right, boundaries.left);
16321
16344
  }
16322
16345
  else {
16323
16346
  // ASSUME CENTER
16324
- tooltipPosition.left = calculateCenterBiasPosition(elementPosition, tooltipDimensions, boundaries.right, boundaries.left);
16347
+ tooltipPosition.left = calculateCenterBiasPosition(elementPosition, tooltipDimensions, screenDimensions, boundaries.right, boundaries.left);
16325
16348
  }
16326
16349
  return tooltipPosition;
16327
16350
  }
16328
- function getBoundaries() {
16351
+ function getBoundaries(screenDimensions) {
16329
16352
  return {
16330
- right: window.innerWidth * TOOLTIP_CONSTANTS.BOUNDARY_MARGIN_RIGHT,
16331
- left: window.innerWidth * TOOLTIP_CONSTANTS.BOUNDARY_MARGIN_LEFT
16353
+ right: screenDimensions.width * TOOLTIP_CONSTANTS.BOUNDARY_MARGIN_RIGHT,
16354
+ left: screenDimensions.width * TOOLTIP_CONSTANTS.BOUNDARY_MARGIN_LEFT
16332
16355
  };
16333
16356
  }
16334
16357
  function calculateCaretPadding(caretSizes) {
@@ -16349,7 +16372,7 @@ var BuildingBlockTooltips = (function () {
16349
16372
  if (tooltipRight > rightBoundary) {
16350
16373
  const overflow = tooltipRight - rightBoundary;
16351
16374
  if (leftVal - overflow < leftBoundary) {
16352
- return spaceEvenly(leftVal, width);
16375
+ return spaceEvenly(leftVal, width, screenDimensions);
16353
16376
  }
16354
16377
  else {
16355
16378
  return leftVal - overflow;
@@ -16357,7 +16380,7 @@ var BuildingBlockTooltips = (function () {
16357
16380
  }
16358
16381
  return leftVal;
16359
16382
  }
16360
- function calculateLeftBiasPosition(elementPosition, tooltipDimensions, caretSizes, rightBoundary, leftBoundary) {
16383
+ function calculateLeftBiasPosition(elementPosition, tooltipDimensions, caretSizes, screenDimensions, rightBoundary, leftBoundary) {
16361
16384
  const caretPadding = calculateCaretPadding(caretSizes);
16362
16385
  const width = tooltipDimensions.width;
16363
16386
  var leftVal = elementPosition.left - width + (elementPosition.width / 2) + caretPadding;
@@ -16365,7 +16388,7 @@ var BuildingBlockTooltips = (function () {
16365
16388
  const overflow = leftBoundary - leftVal;
16366
16389
  const tooltipRight = leftVal + width;
16367
16390
  if (tooltipRight + overflow > rightBoundary) {
16368
- return spaceEvenly(leftVal, width);
16391
+ return spaceEvenly(leftVal, width, screenDimensions);
16369
16392
  }
16370
16393
  else {
16371
16394
  return leftVal + overflow;
@@ -16373,7 +16396,7 @@ var BuildingBlockTooltips = (function () {
16373
16396
  }
16374
16397
  return leftVal;
16375
16398
  }
16376
- function calculateCenterBiasPosition(elementPosition, tooltipDimensions, rightBoundary, leftBoundary) {
16399
+ function calculateCenterBiasPosition(elementPosition, tooltipDimensions, screenDimensions, rightBoundary, leftBoundary) {
16377
16400
  const width = tooltipDimensions.width;
16378
16401
  var leftVal = elementPosition.left + (elementPosition.width / 2) - (width / 2);
16379
16402
  let tooltipRight = leftVal + width;
@@ -16381,7 +16404,7 @@ var BuildingBlockTooltips = (function () {
16381
16404
  const overflow = tooltipRight - rightBoundary;
16382
16405
  leftVal -= overflow;
16383
16406
  if (leftVal < leftBoundary) {
16384
- return spaceEvenly(leftVal, width);
16407
+ return spaceEvenly(leftVal, width, screenDimensions);
16385
16408
  }
16386
16409
  }
16387
16410
  else if (leftVal < leftBoundary) {
@@ -16389,14 +16412,14 @@ var BuildingBlockTooltips = (function () {
16389
16412
  leftVal += overflow;
16390
16413
  let tooltipRight = leftVal + width;
16391
16414
  if (tooltipRight > rightBoundary) {
16392
- return spaceEvenly(leftVal, width);
16415
+ return spaceEvenly(leftVal, width, screenDimensions);
16393
16416
  }
16394
16417
  }
16395
16418
  return leftVal;
16396
16419
  }
16397
- function spaceEvenly(leftVal, width) {
16420
+ function spaceEvenly(leftVal, width, screenDimensions) {
16398
16421
  const availableLeftSpace = leftVal;
16399
- const availableRightSpace = window.innerWidth - (leftVal + width);
16422
+ const availableRightSpace = screenDimensions.width - (leftVal + width);
16400
16423
  if (availableLeftSpace > availableRightSpace) {
16401
16424
  return leftVal - (availableLeftSpace - availableRightSpace) / 2;
16402
16425
  }
@@ -16619,8 +16642,10 @@ var BuildingBlockTooltips = (function () {
16619
16642
  var guideContainer = providedGuideContainer || getGuideContainer(step);
16620
16643
  if (!guideContainer)
16621
16644
  return;
16622
- var element = step.element || getElementForGuideStep(step);
16623
- var elPos = getOffsetPosition(element);
16645
+ var targetDocument = guideContainer.ownerDocument || document;
16646
+ var targetWindow = targetDocument.defaultView || window;
16647
+ var element = step.element || getElementForGuideStep(step, targetDocument);
16648
+ var elPos = getOffsetPosition(element, targetWindow);
16624
16649
  // If display:none then don't re-position
16625
16650
  if (getComputedStyle_safe(step.elements[0]).display === 'none')
16626
16651
  return;
@@ -16642,7 +16667,7 @@ var BuildingBlockTooltips = (function () {
16642
16667
  borderColor: ttContainerStyles.borderColor,
16643
16668
  borderWidth: parseInt(ttContainerStyles.borderWidth, 10) || 0
16644
16669
  };
16645
- var tooltipDimensions = this.getBBTooltipDimensions(elPos, tooltipSizes, caretStyles, layoutDir, screenPos);
16670
+ var tooltipDimensions = this.getBBTooltipDimensions(elPos, tooltipSizes, caretStyles, layoutDir, screenPos, getScreenDimensions(targetWindow));
16646
16671
  if (caretStyles.height && caretStyles.width) {
16647
16672
  var caretDiv = ttdiv.find('.pendo-tooltip-caret')[0];
16648
16673
  var borderCaret = ttdiv.find('.pendo-tooltip-caret-border')[0];
@@ -20009,6 +20034,9 @@ var GuideStateModule = (function () {
20009
20034
  }
20010
20035
  context.commit('setLastGuideStepSeen', lastGuideStepSeen);
20011
20036
  pendo$1.lastGuideStepSeen = lastGuideStepSeen;
20037
+ if (guideCache) {
20038
+ guideCache.update(lastGuideStepSeen);
20039
+ }
20012
20040
  },
20013
20041
  updateThrottlingState(context, state) {
20014
20042
  context.commit('setThrottlingState', state);
@@ -21343,6 +21371,16 @@ Badge.behaviors = [
21343
21371
  ShowOnHover
21344
21372
  ];
21345
21373
  function InlinePosition() {
21374
+ function getShadowDomAdjustedTarget(target) {
21375
+ try {
21376
+ if (target.shadowRoot && !target.shadowRoot.querySelector('slot')) {
21377
+ return target.shadowRoot;
21378
+ }
21379
+ }
21380
+ catch (e) {
21381
+ }
21382
+ return target;
21383
+ }
21346
21384
  if (this.position === 'inline' || this.position === 'inline-right' || this.position === 'inline-left') {
21347
21385
  this.before('show', function () {
21348
21386
  var targetElem = this.target();
@@ -21355,18 +21393,19 @@ function InlinePosition() {
21355
21393
  }
21356
21394
  if (targetElem && targetElem.tagName) {
21357
21395
  var tagName = targetElem.tagName.toLowerCase();
21396
+ var shadowDomAdjustedTarget = getShadowDomAdjustedTarget(targetElem);
21358
21397
  if (/br|input|img|select|textarea/.test(tagName)) {
21359
21398
  if (badgeElem.parentNode === targetElem.parentNode)
21360
21399
  return;
21361
21400
  // Insert after if targetElem cannot have children
21362
21401
  targetElem.parentNode.insertBefore(badgeElem, targetElem.nextSibling);
21363
21402
  }
21364
- else if (badgeElem.parentNode !== targetElem) {
21403
+ else if (badgeElem.parentNode !== shadowDomAdjustedTarget) {
21365
21404
  if (this.position === 'inline' || this.position === 'inline-right') {
21366
- targetElem.appendChild(badgeElem);
21405
+ shadowDomAdjustedTarget.appendChild(badgeElem);
21367
21406
  }
21368
21407
  else if (this.position === 'inline-left') {
21369
- targetElem.prepend(badgeElem);
21408
+ shadowDomAdjustedTarget.prepend(badgeElem);
21370
21409
  }
21371
21410
  }
21372
21411
  }
@@ -23210,7 +23249,7 @@ var BuildingBlockWatermark = (function () {
23210
23249
  }
23211
23250
  function buildWatermark(options, buildNodeFromJSON) {
23212
23251
  options = options || {};
23213
- if (!options.isTraining)
23252
+ if (!options.isTraining || options.isEmbedded)
23214
23253
  return;
23215
23254
  var watermarkGuide = options.targetAccount ? findWatermarkByTargetAccount(options.targetAccount) : findWatermarkByAppId(options.appId);
23216
23255
  if (!watermarkGuide || !watermarkGuide.steps)
@@ -23783,6 +23822,149 @@ function testGuideGifEndpoint(loader, apiKey) {
23783
23822
  });
23784
23823
  }
23785
23824
 
23825
+ function deepClone(obj) {
23826
+ return JSON.parse(JSON.stringify(obj));
23827
+ }
23828
+ class GuideCache {
23829
+ constructor(apiKey, ConfigReader) {
23830
+ this.apiKey = apiKey;
23831
+ this.cacheGuides = ConfigReader.get('cacheGuides');
23832
+ this.cacheGuidesTimeout = ConfigReader.get('cacheGuidesTimeout');
23833
+ this.cacheGuidesPersistent = ConfigReader.get('cacheGuidesPersistent');
23834
+ this.cache = null;
23835
+ this.db = null;
23836
+ }
23837
+ openDB(apiKey, indexedDB = window.indexedDB) {
23838
+ if (!this.cacheGuidesPersistent)
23839
+ return q.resolve();
23840
+ if (this.db)
23841
+ return q.resolve(this.db);
23842
+ const deferred = q.defer();
23843
+ const request = indexedDB.open(`pendo-${apiKey}`, 1);
23844
+ request.onerror = () => {
23845
+ log.warn('Error opening guide database');
23846
+ this.cacheGuidesPersistent = false;
23847
+ deferred.resolve();
23848
+ };
23849
+ request.onsuccess = (event) => {
23850
+ const db = event.target.result;
23851
+ this.db = db;
23852
+ deferred.resolve(db);
23853
+ };
23854
+ request.onupgradeneeded = (event) => {
23855
+ const db = event.target.result;
23856
+ const objectStore = db.createObjectStore('guides', { keyPath: 'guide.id' });
23857
+ objectStore.transaction.oncomplete = () => {
23858
+ this.db = db;
23859
+ deferred.resolve(db);
23860
+ };
23861
+ };
23862
+ return deferred.promise;
23863
+ }
23864
+ load(now = getNow()) {
23865
+ if (this.cache)
23866
+ return q.resolve(this.cache);
23867
+ this.cache = {};
23868
+ if (!this.db)
23869
+ return q.resolve(this.cache);
23870
+ const deferred = q.defer();
23871
+ const objectStore = this.db.transaction(['guides'], 'readwrite').objectStore('guides');
23872
+ const request = objectStore.getAll();
23873
+ request.onerror = () => {
23874
+ log.warn('Error loading guide cache');
23875
+ this.cacheGuidesPersistent = false;
23876
+ this.db = null;
23877
+ deferred.resolve(this.cache);
23878
+ };
23879
+ request.onsuccess = (event) => {
23880
+ const cachedGuides = event.target.result;
23881
+ _.each(cachedGuides, (cachedGuide) => {
23882
+ if (cachedGuide.expires > now) {
23883
+ this.cache[cachedGuide.guide.id] = cachedGuide;
23884
+ }
23885
+ else {
23886
+ objectStore.delete(cachedGuide.guide.id);
23887
+ }
23888
+ });
23889
+ deferred.resolve(this.cache);
23890
+ };
23891
+ return deferred.promise;
23892
+ }
23893
+ add(guide, visitorId, now = getNow()) {
23894
+ if (!this.cacheGuides)
23895
+ return;
23896
+ if (!this.cache)
23897
+ return;
23898
+ const cachedGuide = {
23899
+ expires: now + this.cacheGuidesTimeout,
23900
+ visitorId,
23901
+ guide: deepClone(guide)
23902
+ };
23903
+ this.cache[guide.id] = cachedGuide;
23904
+ return this.save(cachedGuide);
23905
+ }
23906
+ save(cachedGuide) {
23907
+ if (!this.db)
23908
+ return;
23909
+ const objectStore = this.db.transaction(['guides'], 'readwrite').objectStore('guides');
23910
+ const deferred = q.defer();
23911
+ const update = objectStore.put(cachedGuide);
23912
+ update.onerror = () => {
23913
+ log.warn(`Error saving guide to cache ${cachedGuide.guide.id}`);
23914
+ deferred.resolve();
23915
+ };
23916
+ update.onsuccess = () => {
23917
+ deferred.resolve();
23918
+ };
23919
+ return deferred.promise;
23920
+ }
23921
+ update(lastGuideStepSeen) {
23922
+ if (!this.cache)
23923
+ return;
23924
+ const cachedGuide = this.cache[lastGuideStepSeen.guideId];
23925
+ if (!cachedGuide)
23926
+ return;
23927
+ const cachedStep = _.find(cachedGuide.guide.steps, (s) => s.id === lastGuideStepSeen.guideStepId);
23928
+ if (!cachedStep)
23929
+ return;
23930
+ cachedStep.seenState = lastGuideStepSeen.state;
23931
+ cachedStep.seenReason = lastGuideStepSeen.seenReason;
23932
+ cachedStep.dismissCount = lastGuideStepSeen.dismissCount;
23933
+ cachedStep.snoozeEndTime = lastGuideStepSeen.snoozeEndTime;
23934
+ return this.save(cachedGuide);
23935
+ }
23936
+ list(visitorId, now = getNow()) {
23937
+ if (!this.cacheGuides)
23938
+ return q.resolve([]);
23939
+ return this.openDB(this.apiKey).then(() => {
23940
+ return this.load(now);
23941
+ }).then(() => {
23942
+ const list = [];
23943
+ _.each(this.cache, (cachedGuide) => {
23944
+ if (cachedGuide.expires > now && cachedGuide.visitorId === visitorId) {
23945
+ list.push(_.pick(cachedGuide.guide, 'id', 'lastUpdatedAt', 'language'));
23946
+ }
23947
+ else {
23948
+ delete this.cache[cachedGuide.guide.id];
23949
+ }
23950
+ });
23951
+ return list;
23952
+ });
23953
+ }
23954
+ get(guideId) {
23955
+ if (this.cache && this.cache[guideId]) {
23956
+ return deepClone(this.cache[guideId].guide);
23957
+ }
23958
+ }
23959
+ clear() {
23960
+ this.cache = {};
23961
+ if (this.db) {
23962
+ const objectStore = this.db.transaction(['guides'], 'readwrite').objectStore('guides');
23963
+ objectStore.clear();
23964
+ }
23965
+ }
23966
+ }
23967
+
23786
23968
  const pendoLocalStorage$1 = agentStorage.getLocal();
23787
23969
  var guideEvtCache = [];
23788
23970
  var controlGuideLogMessage = 'Guide was not shown because this visitor is in a control group of an active experiment for the guide';
@@ -25024,14 +25206,6 @@ function handleDoNotProcess() {
25024
25206
  store.commit('debugger/doNotProcess', true);
25025
25207
  log.info('not tracking visitor due to 451 response');
25026
25208
  }
25027
- function resetCachedGuide(guide) {
25028
- _.each(guide.steps, function (step) {
25029
- if (_.get(step, 'attributes.stayHidden')) {
25030
- delete step.attributes.stayHidden;
25031
- }
25032
- });
25033
- return guide;
25034
- }
25035
25209
  function guidesPayload(guidesJson) {
25036
25210
  if (!mostRecentGuideRequest)
25037
25211
  return;
@@ -25041,13 +25215,13 @@ function guidesPayload(guidesJson) {
25041
25215
  }
25042
25216
  if (_.isString(guidesJson.id) && guidesJson.id !== mostRecentGuideRequest.id)
25043
25217
  return;
25044
- const cachedGuides = _.indexBy(pendo$1.guides, 'id');
25045
25218
  _.extend(pendo$1, guidesJson);
25046
25219
  pendo$1.guides = _.map(pendo$1.guides, function (guide) {
25047
25220
  if (_.keys(guide).length == 1 && guide.id) {
25048
- return resetCachedGuide(cachedGuides[guide.id]);
25221
+ return guideCache.get(guide.id);
25049
25222
  }
25050
25223
  else {
25224
+ guideCache.add(guide, get_visitor_id());
25051
25225
  return guide;
25052
25226
  }
25053
25227
  });
@@ -25082,48 +25256,53 @@ var loadGuideJs = function (apiKey, params) {
25082
25256
  log.info('no metadata to send', { contexts: ['guides', 'metadata'] });
25083
25257
  }
25084
25258
  }
25085
- var jzb = compress(params);
25086
- var queryString = {
25087
- id: guideRequestId,
25088
- jzb,
25089
- v: VERSION,
25090
- ct: (new Date()).getTime()
25091
- };
25092
- if (isAdoptPartner && params.accountId && params.accountId !== 'ACCOUNT-UNIQUE-ID') {
25093
- queryString.acc = base64EncodeString(params.accountId);
25094
- }
25095
- if (isDebuggingEnabled()) {
25096
- // Include debug info from server
25097
- queryString.debug = true;
25098
- }
25099
- var url = buildBaseDataUrl(guideLoaderImpl.endpoint(), apiKey, queryString);
25100
- var loadingPromise;
25101
- var jwtOptions = JWT.get();
25102
- if (url.length > URL_MAX_LENGTH || !_.isEmpty(jwtOptions)) {
25103
- delete queryString.jzb;
25104
- url = buildBaseDataUrl('guide.json', apiKey, queryString);
25105
- var payload = _.extend({ events: jzb }, jwtOptions);
25106
- loadingPromise = guideLoaderImpl.post(url, payload, pendo$1, _.noop);
25107
- }
25108
- else {
25109
- loadingPromise = guideLoaderImpl.load(url, pendo$1, _.noop);
25110
- }
25111
- return q.all([
25112
- // eslint-disable-next-line dot-notation
25113
- loadingPromise['catch'](function (result) {
25114
- if (result.status === 451) {
25115
- handleDoNotProcess();
25116
- }
25117
- // passthrough rejections to subscribers
25118
- return q.reject(result);
25119
- }),
25120
- deferred.promise,
25121
- testGuideGifEndpoint(guideLoaderImpl, apiKey)
25122
- ]).then(function ([, , testGuideGifResult]) {
25123
- setGuidesBlocked(testGuideGifResult);
25124
- if (!testGuideGifResult.success) {
25125
- return q.reject();
25259
+ return guideCache.list(params.visitorId).then(cachedGuides => {
25260
+ if (cachedGuides.length > 0) {
25261
+ params.cachedGuides = cachedGuides;
25262
+ }
25263
+ var jzb = compress(params);
25264
+ var queryString = {
25265
+ id: guideRequestId,
25266
+ jzb,
25267
+ v: VERSION,
25268
+ ct: (new Date()).getTime()
25269
+ };
25270
+ if (isAdoptPartner && params.accountId && params.accountId !== 'ACCOUNT-UNIQUE-ID') {
25271
+ queryString.acc = base64EncodeString(params.accountId);
25272
+ }
25273
+ if (isDebuggingEnabled()) {
25274
+ // Include debug info from server
25275
+ queryString.debug = true;
25276
+ }
25277
+ var url = buildBaseDataUrl(guideLoaderImpl.endpoint(), apiKey, queryString);
25278
+ var jwtOptions = JWT.get();
25279
+ let loadingPromise;
25280
+ if (url.length > URL_MAX_LENGTH || !_.isEmpty(jwtOptions)) {
25281
+ delete queryString.jzb;
25282
+ url = buildBaseDataUrl('guide.json', apiKey, queryString);
25283
+ var payload = _.extend({ events: jzb }, jwtOptions);
25284
+ loadingPromise = guideLoaderImpl.post(url, payload, pendo$1, _.noop);
25126
25285
  }
25286
+ else {
25287
+ loadingPromise = guideLoaderImpl.load(url, pendo$1, _.noop);
25288
+ }
25289
+ return q.all([
25290
+ // eslint-disable-next-line dot-notation
25291
+ loadingPromise['catch'](function (result) {
25292
+ if (result.status === 451) {
25293
+ handleDoNotProcess();
25294
+ }
25295
+ // passthrough rejections to subscribers
25296
+ return q.reject(result);
25297
+ }),
25298
+ deferred.promise,
25299
+ testGuideGifEndpoint(guideLoaderImpl, apiKey)
25300
+ ]).then(function ([, , testGuideGifResult]) {
25301
+ setGuidesBlocked(testGuideGifResult);
25302
+ if (!testGuideGifResult.success) {
25303
+ return q.reject();
25304
+ }
25305
+ });
25127
25306
  });
25128
25307
  };
25129
25308
  var guideLoaderImpl = XHRGuideLoader;
@@ -25236,18 +25415,6 @@ function shouldLoadGuides(visitorId, callback) {
25236
25415
  }
25237
25416
  return true;
25238
25417
  }
25239
- function getCachedGuideList(pendo, cacheInfo, now = getNow()) {
25240
- let cachedGuides = [];
25241
- if (ConfigReader.get('cacheGuides')) {
25242
- if (now - (cacheInfo.lastUncached || 0) < ConfigReader.get('cacheGuidesTimeout')) {
25243
- cachedGuides = _.map(pendo.guides, guide => _.pick(guide, 'id', 'lastUpdatedAt', 'language'));
25244
- }
25245
- if (!cachedGuides.length) {
25246
- cacheInfo.lastUncached = now;
25247
- }
25248
- }
25249
- return cachedGuides;
25250
- }
25251
25418
  /**
25252
25419
  * Manually load guides for current visitor and URL. This is typically handled automatically by the Agent
25253
25420
  * whenever the host Application changes its URL. In rare circumstances, a host Application may chose to
@@ -25282,10 +25449,6 @@ var loadGuides = function (apiKey, visitorId, page, callback) {
25282
25449
  url: page,
25283
25450
  oldVisitorId: get_old_visitor_id()
25284
25451
  };
25285
- const cachedGuides = getCachedGuideList(pendo$1, loadGuides);
25286
- if (cachedGuides.length && !visitorChanged) {
25287
- params.cachedGuides = cachedGuides;
25288
- }
25289
25452
  const reqId = _.uniqueId();
25290
25453
  loadGuides.reqId = reqId;
25291
25454
  loadGuideJs(apiKey, params).then(function () {
@@ -25570,6 +25733,7 @@ function securityPolicyViolationFn(evt) {
25570
25733
  forceGuideReload();
25571
25734
  }
25572
25735
  }
25736
+ let guideCache;
25573
25737
  /**
25574
25738
  * Resets and starts guide loop
25575
25739
  *
@@ -25578,11 +25742,12 @@ function securityPolicyViolationFn(evt) {
25578
25742
  * @example
25579
25743
  * pendo.initGuides()
25580
25744
  */
25581
- var initGuides = function () {
25745
+ var initGuides = function (observer) {
25582
25746
  const teardownFns = [];
25583
25747
  teardownFns.push(initGuideAnalytics({
25584
25748
  localStorageUnload: ConfigReader.get('analytics.localStorageUnload')
25585
25749
  }));
25750
+ guideCache = new GuideCache(pendo$1.apiKey, ConfigReader);
25586
25751
  GuideMonitor.run();
25587
25752
  teardownFns.push(GuideMonitor.stop);
25588
25753
  Events.appUnloaded.on(function () {
@@ -25642,8 +25807,8 @@ var initGuides = function () {
25642
25807
  teardownFns.push(attachEventInternal(window, 'gestureend', adjustGuidesOnGestureEnd, true));
25643
25808
  teardownFns.push(attachEventInternal(window, 'securitypolicyviolation', securityPolicyViolationFn));
25644
25809
  teardownFns.push(createVideoFullScreenListeners());
25645
- if (ConfigReader.get('preferMutationObserver') && sniffer.MutationObserver) {
25646
- var updateGuide = function (event) {
25810
+ if (observer.observing) {
25811
+ var updateGuide = function () {
25647
25812
  store.dispatch('guideUpdate/documentChanged');
25648
25813
  };
25649
25814
  const debouncedUpdate = _.debounce(updateGuide, 50);
@@ -25651,10 +25816,8 @@ var initGuides = function () {
25651
25816
  teardownFns.push(attachEvent(window, 'animationend', debouncedUpdate));
25652
25817
  teardownFns.push(attachEvent(window, 'transitionend', debouncedUpdate));
25653
25818
  teardownFns.push(attachEvent(window, 'mouseover', debouncedUpdate));
25819
+ store.commit('guideUpdate/setObserver', observer);
25654
25820
  store.commit('guideUpdate/setUseObserver');
25655
- if (ConfigReader.get('observeShadowRoots')) {
25656
- store.commit('guideUpdate/setObserveShadowRoots');
25657
- }
25658
25821
  teardownFns.push(() => store.dispatch('guideUpdate/stopObserver'));
25659
25822
  }
25660
25823
  /**
@@ -25700,6 +25863,7 @@ var initGuides = function () {
25700
25863
  agentStorage.registry.addLocal(AD_BLOCK_STORAGE_KEY, { duration: 14400000 }); // 4 hours default duration
25701
25864
  GuideRuntime.initialize();
25702
25865
  return () => {
25866
+ guideCache = null;
25703
25867
  reloadGuides.reset();
25704
25868
  resetPendoUI();
25705
25869
  cancelGuideRequest();
@@ -27035,6 +27199,168 @@ const isReady = (pendoObj) => {
27035
27199
  return pendoObj.doesExist(pendoObj.apiKey);
27036
27200
  };
27037
27201
 
27202
+ class ShadowDomManager extends EventTarget {
27203
+ constructor() {
27204
+ super();
27205
+ this.cache = new Set();
27206
+ this.foundShadowRoots = false;
27207
+ this.stoppedSearchEarly = false;
27208
+ }
27209
+ updateCache() {
27210
+ // eslint-disable-next-line agent-eslint-rules/no-array-foreach
27211
+ this.cache.forEach(shadowRoot => {
27212
+ if (!isInDocument(shadowRoot)) {
27213
+ this.cache.delete(shadowRoot);
27214
+ this.dispatchEvent({
27215
+ type: 'detachShadow',
27216
+ shadowRoot
27217
+ });
27218
+ }
27219
+ });
27220
+ }
27221
+ patchAttachShadow(Element) {
27222
+ const original = Element.prototype.attachShadow;
27223
+ const self = this;
27224
+ Element.prototype.attachShadow = function (options) {
27225
+ const shadowRoot = original.call(this, options);
27226
+ if (this.shadowRoot) {
27227
+ self.triggerAttachShadow(this.shadowRoot);
27228
+ }
27229
+ return shadowRoot;
27230
+ };
27231
+ Element.prototype.attachShadow.toString = function () {
27232
+ return original.toString();
27233
+ };
27234
+ return () => {
27235
+ Element.prototype.attachShadow = original;
27236
+ };
27237
+ }
27238
+ initialize() {
27239
+ this.unpatchAttachShadow = this.patchAttachShadow(Element);
27240
+ this.findShadowRoots(document);
27241
+ }
27242
+ triggerAttachShadow(shadowRoot) {
27243
+ this.cache.add(shadowRoot);
27244
+ this.dispatchEvent({
27245
+ type: 'attachShadow',
27246
+ shadowRoot
27247
+ });
27248
+ }
27249
+ findShadowRoots(document, maxPerSearch = 5000) {
27250
+ if (!_.isFunction(document.createNodeIterator))
27251
+ return;
27252
+ let nodesChecked = 0;
27253
+ let queue = [getBody(document)];
27254
+ let currentNode;
27255
+ function eachShadowRoot(iterator) {
27256
+ do {
27257
+ if (!iterator) {
27258
+ iterator = document.createNodeIterator(queue.pop(), NodeFilter.SHOW_ELEMENT);
27259
+ }
27260
+ if (!iterator || !iterator.nextNode)
27261
+ break;
27262
+ while ((currentNode = iterator.nextNode())) {
27263
+ nodesChecked++;
27264
+ if (currentNode && currentNode.shadowRoot) {
27265
+ this.triggerAttachShadow(currentNode.shadowRoot);
27266
+ queue.push(currentNode.shadowRoot);
27267
+ this.foundShadowRoots = true;
27268
+ }
27269
+ if (nodesChecked % maxPerSearch === 0)
27270
+ break;
27271
+ }
27272
+ if (currentNode)
27273
+ break;
27274
+ iterator = null;
27275
+ } while (queue.length);
27276
+ if (currentNode && this.foundShadowRoots) {
27277
+ this.findTimeout = setTimeout$1(() => {
27278
+ this.findTimeout = null;
27279
+ eachShadowRoot.call(this, iterator);
27280
+ }, 50);
27281
+ }
27282
+ if (nodesChecked === maxPerSearch && !this.foundShadowRoots) {
27283
+ this.stoppedSearchEarly = true;
27284
+ }
27285
+ }
27286
+ eachShadowRoot.call(this);
27287
+ }
27288
+ teardown() {
27289
+ this.cache.clear();
27290
+ if (_.isFunction(this.unpatchAttachShadow)) {
27291
+ this.unpatchAttachShadow();
27292
+ this.unpatchAttachShadow = null;
27293
+ }
27294
+ if (this.findTimeout) {
27295
+ clearTimeout(this.findTimeout);
27296
+ this.findTimeout = null;
27297
+ }
27298
+ }
27299
+ }
27300
+
27301
+ class UberMutationObserver extends EventTarget {
27302
+ constructor(observerClass = getZoneSafeMethod('MutationObserver')) {
27303
+ super();
27304
+ this.ObserverClass = observerClass;
27305
+ this.observing = false;
27306
+ this.observers = new Map();
27307
+ this.triggerMutation = this.dispatchMutationEvent;
27308
+ this.shadowDom = new ShadowDomManager();
27309
+ this.shadowDom.addEventListener('attachShadow', _.bind(this.handleAttachShadow, this));
27310
+ this.shadowDom.addEventListener('detachShadow', _.bind(this.handleDetachShadow, this));
27311
+ this.addEventListener('mutation', () => {
27312
+ this.shadowDom.updateCache();
27313
+ });
27314
+ }
27315
+ initialize(pendo, PluginAPI) {
27316
+ const configReader = PluginAPI.ConfigReader;
27317
+ if (!configReader.get('preferMutationObserver') || !pendo.sniffer.MutationObserver) {
27318
+ return;
27319
+ }
27320
+ this.observeShadowRoots = configReader.get('observeShadowRoots');
27321
+ this.startObserver(document.documentElement);
27322
+ this.observing = true;
27323
+ if (this.observeShadowRoots) {
27324
+ this.shadowDom.initialize();
27325
+ }
27326
+ }
27327
+ startObserver(target) {
27328
+ const observer = new this.ObserverClass(mutation => this.triggerMutation(mutation));
27329
+ this.observers.set(target, observer);
27330
+ observer.observe(target, {
27331
+ subtree: true,
27332
+ attributes: true,
27333
+ childList: true,
27334
+ characterData: true
27335
+ });
27336
+ }
27337
+ teardown() {
27338
+ this.observers.clear();
27339
+ this.shadowDom.teardown();
27340
+ }
27341
+ dispatchMutationEvent(mutation) {
27342
+ this.dispatchEvent({
27343
+ type: 'mutation',
27344
+ mutation
27345
+ });
27346
+ }
27347
+ triggerMutationOnce(mutation) {
27348
+ this.triggerMutation = _.noop;
27349
+ queueMicrotask(() => {
27350
+ this.dispatchMutationEvent(mutation);
27351
+ this.triggerMutation = this.triggerMutationOnce;
27352
+ });
27353
+ }
27354
+ handleAttachShadow({ shadowRoot }) {
27355
+ this.triggerMutation = this.triggerMutationOnce;
27356
+ this.startObserver(shadowRoot);
27357
+ }
27358
+ handleDetachShadow({ shadowRoot }) {
27359
+ this.observers.delete(shadowRoot);
27360
+ }
27361
+ }
27362
+ var observer = new UberMutationObserver();
27363
+
27038
27364
  // ---------------------------------------------------------------------------
27039
27365
  function registerEventHandlers({ events = [] }) {
27040
27366
  _.each(events, (callback, eventName) => {
@@ -27145,6 +27471,9 @@ const initialize = makeSafe(function (options) {
27145
27471
  teardownFns.push(initializeEventBuffer({
27146
27472
  localStorageUnload: localStorageUnloadEnabled
27147
27473
  }));
27474
+ // needs to happen before initGuides
27475
+ observer.initialize(pendo$1, PluginAPI);
27476
+ teardownFns.push(() => observer.teardown());
27148
27477
  if (pendoCore) {
27149
27478
  /**
27150
27479
  * Current visitor id for pendo installation, either anonymous or identified. Used to determine
@@ -27184,21 +27513,12 @@ const initialize = makeSafe(function (options) {
27184
27513
  * @label OPTIONS_HASH_KEY_NAME
27185
27514
  */
27186
27515
  agentStorage.registry.addLocal(OPTIONS_HASH_KEY_NAME);
27187
- /**
27188
- * Stores debugging configuration and state for the Pendo debugger.
27189
- *
27190
- * @name debug-enabled
27191
- * @category Cookies/localStorage
27192
- * @access public
27193
- * @label debugEnabled
27194
- */
27195
- agentStorage.registry.addLocal(debugEnabled, { isPlain: true, serializer: JSON.stringify, deserializer: SafeJsonDeserializer });
27196
27516
  // Disable content pre-fetch for guide center
27197
27517
  pendo$1.disableGuideCenterContentSearch = options.disableGuideCenterContentSearch;
27198
27518
  // Register handlers passed through pendo_options
27199
27519
  teardownFns.push(forwardInternalEvents(Events));
27200
27520
  registerEventHandlers(options);
27201
- teardownFns.push(initGuides()); // this is safe. loadGuides actually does the loading.
27521
+ teardownFns.push(initGuides(observer)); // this is safe. loadGuides actually does the loading.
27202
27522
  initIdentityEvents(); // setup identify and meta event listeners
27203
27523
  teardownFns.push(wirePage());
27204
27524
  teardownFns.push(initializePlugins());
@@ -27489,6 +27809,7 @@ var BuildingBlockGuides = (function () {
27489
27809
  }
27490
27810
  }
27491
27811
  function renderGuideFromJSON(json, step, guides, options) {
27812
+ options = options || {};
27492
27813
  var guide = step.getGuide();
27493
27814
  var containerJSON = findGuideContainerJSON(json);
27494
27815
  var isResourceCenter = _.get(guide, 'attributes.resourceCenter');
@@ -27500,7 +27821,7 @@ var BuildingBlockGuides = (function () {
27500
27821
  var isAnnouncementModule = _.get(guide, 'attributes.resourceCenter.moduleId') === 'AnnouncementsModule';
27501
27822
  step.hasEscapeListener = false;
27502
27823
  step.containerId = containerJSON && containerJSON.props && containerJSON.props.id;
27503
- step.element = getElementForGuideStep(step);
27824
+ step.element = getElementForGuideStep(step, options.document);
27504
27825
  var guideToAppend = BuildingBlockGuides.buildNodeFromJSON(json, step, guides);
27505
27826
  step.guideElement = guideToAppend;
27506
27827
  var guideContainer = guideToAppend.find('#' + step.containerId);
@@ -27519,19 +27840,20 @@ var BuildingBlockGuides = (function () {
27519
27840
  // between re-renders
27520
27841
  guideContainer.css({ visibility: 'hidden' });
27521
27842
  guideToAppend.css({ visibility: 'hidden' });
27843
+ const embedConfig = _.get(guide, 'attributes.embedConfig', null);
27522
27844
  var watermark = BuildingBlockWatermark.buildWatermark({
27523
27845
  appId: guide.appId,
27524
27846
  targetAccount: guide.targetAccount,
27525
27847
  isTraining: guide.isTraining,
27526
- isBottomAligned: guideContainer.attr(verticalAlignmentAttr) === 'Bottom Aligned'
27848
+ isBottomAligned: guideContainer.attr(verticalAlignmentAttr) === 'Bottom Aligned',
27849
+ isEmbedded: !!embedConfig
27527
27850
  }, BuildingBlockGuides.buildNodeFromJSON);
27528
27851
  if (watermark) {
27529
27852
  guideContainer.append(watermark);
27530
27853
  }
27531
27854
  var hasImageCount = step && step.attributes && step.attributes.imgCount;
27532
27855
  // Do conditional Guide Rendering Things
27533
- var parent = getGuideAttachPoint();
27534
- const embedConfig = _.get(guide, 'attributes.embedConfig', null);
27856
+ var parent = getGuideAttachPoint(options.document);
27535
27857
  if (embedConfig) {
27536
27858
  const guideContainerId = 'pendo-guide-container';
27537
27859
  const baseContainerId = 'pendo-base';
@@ -32144,75 +32466,6 @@ function updateMasterGuideList(state) {
32144
32466
  }
32145
32467
  }
32146
32468
 
32147
- function addShadowObserver(shadowRoot, observerCallback) {
32148
- const MutationObserver = getZoneSafeMethod('MutationObserver');
32149
- const shadowObserver = new MutationObserver(observerCallback);
32150
- shadowObserver.observe(shadowRoot, {
32151
- subtree: true,
32152
- attributes: true,
32153
- childList: true,
32154
- characterData: true
32155
- });
32156
- }
32157
- function patchAttachShadow(observerCallback) {
32158
- const original = Element.prototype.attachShadow;
32159
- Element.prototype.attachShadow = function (options) {
32160
- const shadowRoot = original.call(this, options);
32161
- if (this.shadowRoot) {
32162
- addShadowObserver(this.shadowRoot, observerCallback);
32163
- }
32164
- return shadowRoot;
32165
- };
32166
- Element.prototype.attachShadow.toString = function () {
32167
- return original.toString();
32168
- };
32169
- }
32170
- function startObserver(observerCallback) {
32171
- patchAttachShadow(observerCallback);
32172
- if (!_.isFunction(document.createNodeIterator))
32173
- return;
32174
- const maxPerSearch = 5000;
32175
- let nodesChecked = 0;
32176
- let queue = [getBody()];
32177
- let currentNode;
32178
- function eachShadowRoot(iterator) {
32179
- do {
32180
- if (!iterator) {
32181
- iterator = document.createNodeIterator(queue.pop(), NodeFilter.SHOW_ELEMENT);
32182
- }
32183
- if (!iterator || !iterator.nextNode)
32184
- break;
32185
- while ((currentNode = iterator.nextNode())) {
32186
- nodesChecked++;
32187
- if (currentNode && currentNode.shadowRoot) {
32188
- addShadowObserver(currentNode.shadowRoot, observerCallback);
32189
- queue.push(currentNode.shadowRoot);
32190
- shadowDomManager.foundShadowRoots = true;
32191
- }
32192
- if (nodesChecked % maxPerSearch === 0)
32193
- break;
32194
- }
32195
- if (currentNode)
32196
- break;
32197
- iterator = null;
32198
- } while (queue.length);
32199
- if (currentNode && shadowDomManager.foundShadowRoots) {
32200
- setTimeout$1(() => {
32201
- eachShadowRoot(iterator);
32202
- }, 50);
32203
- }
32204
- if (nodesChecked === maxPerSearch && !shadowDomManager.foundShadowRoots) {
32205
- shadowDomManager.stoppedSearchEarly = true;
32206
- }
32207
- }
32208
- eachShadowRoot();
32209
- }
32210
- const shadowDomManager = {
32211
- startObserver,
32212
- foundShadowRoots: false,
32213
- stoppedSearchEarly: false
32214
- };
32215
-
32216
32469
  var GuideUpdateModule = (function () {
32217
32470
  var observer;
32218
32471
  function observerCallback() {
@@ -32223,7 +32476,6 @@ var GuideUpdateModule = (function () {
32223
32476
  }
32224
32477
  var state = {
32225
32478
  useObserver: false,
32226
- observeShadowRoots: false,
32227
32479
  observing: false,
32228
32480
  needsUpdate: false,
32229
32481
  scheduledUpdate: null,
@@ -32254,43 +32506,31 @@ var GuideUpdateModule = (function () {
32254
32506
  context.commit('setScheduledUpdate', null);
32255
32507
  }
32256
32508
  },
32257
- startObserverIfNeeded(context, observerClass) {
32509
+ startObserverIfNeeded(context) {
32258
32510
  if (context.state.useObserver) {
32259
- var observerInstance = context.getters.observer();
32260
- if (!observerInstance) {
32261
- observerInstance = new (observerClass || getZoneSafeMethod('MutationObserver'))(observerCallback);
32262
- observer = observerInstance;
32263
- }
32264
32511
  if (!context.state.observing) {
32265
- observerInstance.observe(document.documentElement, {
32266
- subtree: true,
32267
- attributes: true,
32268
- childList: true,
32269
- characterData: true
32270
- });
32271
- if (context.state.observeShadowRoots) {
32272
- shadowDomManager.startObserver(observerCallback);
32273
- }
32512
+ const observer = context.getters.observer();
32513
+ observer.addEventListener('mutation', observerCallback);
32274
32514
  context.commit('setObserving', true);
32275
32515
  }
32276
32516
  }
32277
32517
  },
32278
32518
  stopObserver(context) {
32279
- var observerInstance = context.getters.observer();
32280
- if (observerInstance && _.isFunction(observerInstance.disconnect)) {
32281
- observerInstance.disconnect();
32519
+ const observer = context.getters.observer();
32520
+ if (observer) {
32521
+ observer.removeEventListener('mutation', observerCallback);
32282
32522
  }
32283
32523
  context.commit('setObserving', false);
32284
32524
  context.dispatch('stopScheduledUpdate');
32285
32525
  }
32286
32526
  };
32287
32527
  var mutations = {
32528
+ setObserver(state, _observer) {
32529
+ observer = _observer;
32530
+ },
32288
32531
  setUseObserver(state) {
32289
32532
  state.useObserver = true;
32290
32533
  },
32291
- setObserveShadowRoots(state) {
32292
- state.observeShadowRoots = true;
32293
- },
32294
32534
  setObserving(state, observing) {
32295
32535
  state.observing = observing;
32296
32536
  },
@@ -36205,7 +36445,9 @@ function debuggerExports() {
36205
36445
  isStagingServer,
36206
36446
  AutoDisplay,
36207
36447
  isLeader,
36208
- Events
36448
+ Events,
36449
+ observer,
36450
+ guideCache
36209
36451
  };
36210
36452
  }
36211
36453
  function startDebuggingModuleIfEnabled() {
@@ -38565,6 +38807,15 @@ function isConfiguredForMV3(config) {
38565
38807
  return config && config.useAssetHostForDesigner;
38566
38808
  }
38567
38809
  function initAgent(pendo, PendoConfig) {
38810
+ /**
38811
+ * Stores debugging configuration and state for the Pendo debugger.
38812
+ *
38813
+ * @name debug-enabled
38814
+ * @category Cookies/localStorage
38815
+ * @access public
38816
+ * @label debugEnabled
38817
+ */
38818
+ agentStorage.registry.addLocal(debugEnabled, { isPlain: true, serializer: JSON.stringify, deserializer: SafeJsonDeserializer });
38568
38819
  setPendoConfig(PendoConfig);
38569
38820
  overwriteBuiltConfigWithPendoConfig();
38570
38821
  if (!loadAsModule(PendoConfig) && loadAlternateAgent(PendoConfig, pendo, isDebuggingEnabled()))
@@ -38584,7 +38835,7 @@ function initAgent(pendo, PendoConfig) {
38584
38835
  AsyncContent.reset();
38585
38836
  store.dispatch('frames/init');
38586
38837
  logPublic.init();
38587
- shadowAPI.wrapSizzle(SizzleProxy);
38838
+ shadowAPI.wrapSizzle(SizzleProxy, observer.shadowDom);
38588
38839
  SizzleProxy.intercept(sizzleAttachPointInterceptor);
38589
38840
  populatePendoObject(pendo);
38590
38841
  log.addEventListener('log', _.partial(store.dispatch, 'errorLog/write'));
@@ -38678,7 +38929,8 @@ function TextCapture() {
38678
38929
  }
38679
38930
  function isTextCapturable(text) {
38680
38931
  var trimmedText = pluginAPI.util.trim.call(text);
38681
- return isEnabled() || pendoGlobal._.has(whitelist, trimmedText) || pendoGlobal._.has(whitelist, text);
38932
+ // pass the text as an array so that our toPath override doesn't try to split it on `.`
38933
+ return isEnabled() || pendoGlobal._.has(whitelist, [trimmedText]) || pendoGlobal._.has(whitelist, [text]);
38682
38934
  }
38683
38935
  function hasWhitelist() {
38684
38936
  return pendoGlobal._.size(whitelist) > 0;
@@ -47274,7 +47526,8 @@ class SessionRecorder {
47274
47526
  }, SEND_INTERVAL$1);
47275
47527
  var config = this.recordingConfig(visitorConfig);
47276
47528
  this._stop = this.record(this.pendo._.extend({
47277
- emit: bind(this.emit, this)
47529
+ emit: bind(this.emit, this),
47530
+ errorHandler: bind(this.errorHandler, this)
47278
47531
  }, config));
47279
47532
  this._refreshIds();
47280
47533
  this.onRecordingStart();
@@ -47386,6 +47639,9 @@ class SessionRecorder {
47386
47639
  return null;
47387
47640
  }
47388
47641
  }
47642
+ errorHandler(error) {
47643
+ this.logStopReason('RRWEB_ERROR', error);
47644
+ }
47389
47645
  /**
47390
47646
  * Handle new rrweb events coming in. This will also make sure that we are properly sending a "keyframe"
47391
47647
  * as the BE expects it. A "keyframe" should consist of only the events needed to start a recording. This includes
@@ -47489,6 +47745,10 @@ class SessionRecorder {
47489
47745
  this.sendHostedResources(hostedResourcesEvent);
47490
47746
  break;
47491
47747
  }
47748
+ case 'emptyPayload': {
47749
+ this.logStopReason('EMPTY_PAYLOAD');
47750
+ break;
47751
+ }
47492
47752
  case 'missingData': {
47493
47753
  this.logStopReason(`MISSING_${messageData.missingData}`);
47494
47754
  break;
@@ -48298,6 +48558,11 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
48298
48558
  }
48299
48559
  if (e.data.url && e.data.payload) {
48300
48560
  let { url, payload, shouldCacheResources } = e.data;
48561
+ if (Object.keys(payload).length === 0) {
48562
+ postMessage({
48563
+ type: 'emptyPayload'
48564
+ });
48565
+ }
48301
48566
  const { sequence } = payload;
48302
48567
  const stringifiedRecordingPayload = JSON.stringify(payload.recordingPayload);
48303
48568
  // calculate and post back the recording payload size before the payload is compressed
@@ -51511,7 +51776,8 @@ var ConfigReader = (function () {
51511
51776
  /**
51512
51777
  * Use this setting when using `preferMutationObserver` with an application that has Shadow DOM elements.
51513
51778
  * On page load, the Agent will run a full document scan for shadow roots and attach a MutationObserver to
51514
- * all results.
51779
+ * all results. This setting also allows the agent to run CSS selectors in all shadow roots, so CSS selectors
51780
+ * can be written without specifying the full path through all shadow roots with the `::shadow` pseudo-class.
51515
51781
  *
51516
51782
  * @access public
51517
51783
  * @category Config/Core