@pendo/agent 2.290.2 → 2.291.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.
@@ -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.0_';
3908
+ var PACKAGE_VERSION = '2.291.0';
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);
16031
16053
  if (!element)
16032
16054
  return;
16033
16055
  const width = guideContainer.style.width;
@@ -16052,9 +16074,10 @@ 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 targetWindow = element.ownerDocument.defaultView;
16078
+ var elementPos = getOffsetPosition(element, targetWindow);
16056
16079
  var screenPos = getScreenPosition(element);
16057
- var screenDimensions = getScreenDimensions();
16080
+ var screenDimensions = getScreenDimensions(targetWindow);
16058
16081
  var layoutDir = step.attributes.layoutDir || 'auto';
16059
16082
  // RETURN IF THE FOUND ELEMENT IS NOT VISIBLE ON THE SCREEN.
16060
16083
  if (elementPos.height === 0 && elementPos.width === 0) {
@@ -16102,7 +16125,7 @@ var BuildingBlockTooltips = (function () {
16102
16125
  var tooltipDiv = step.guideElement;
16103
16126
  tooltipDiv.addClass(buildTooltipCSSName());
16104
16127
  attachBBAdvanceActions(step);
16105
- var tooltipDimensions = getBBTooltipDimensions(elementPos, { height: tooltipSizes.height, width: tooltipSizes.width }, caretDimensions, step.attributes.layoutDir, screenPos);
16128
+ var tooltipDimensions = getBBTooltipDimensions(elementPos, { height: tooltipSizes.height, width: tooltipSizes.width }, caretDimensions, step.attributes.layoutDir, screenPos, tooltipContext.screenDimensions);
16106
16129
  if (step) {
16107
16130
  step.dim = tooltipDimensions;
16108
16131
  }
@@ -16181,8 +16204,7 @@ var BuildingBlockTooltips = (function () {
16181
16204
  }
16182
16205
  }
16183
16206
  }
16184
- function getBBTooltipDimensions(elementPos, tooltipSizes, caretSizes, layoutDir, screenPos) {
16185
- var screenDimensions = getScreenDimensions();
16207
+ function getBBTooltipDimensions(elementPos, tooltipSizes, caretSizes, layoutDir, screenPos, screenDimensions) {
16186
16208
  var layoutDirection = layoutDir || 'auto';
16187
16209
  var tooltipDimensions = {
16188
16210
  width: Math.min(tooltipSizes.width, screenDimensions.width),
@@ -16312,23 +16334,23 @@ var BuildingBlockTooltips = (function () {
16312
16334
  else if (layoutDirection === 'top') {
16313
16335
  tooltipPosition.top = elementPosition.top - height;
16314
16336
  }
16315
- const boundaries = getBoundaries();
16337
+ const boundaries = getBoundaries(screenDimensions);
16316
16338
  if (horizontalBias === 'right') {
16317
16339
  tooltipPosition.left = calculateRightBiasPosition(elementPosition, tooltipDimensions, caretSizes, screenDimensions, boundaries.right, boundaries.left);
16318
16340
  }
16319
16341
  else if (horizontalBias === 'left') {
16320
- tooltipPosition.left = calculateLeftBiasPosition(elementPosition, tooltipDimensions, caretSizes, boundaries.right, boundaries.left);
16342
+ tooltipPosition.left = calculateLeftBiasPosition(elementPosition, tooltipDimensions, caretSizes, screenDimensions, boundaries.right, boundaries.left);
16321
16343
  }
16322
16344
  else {
16323
16345
  // ASSUME CENTER
16324
- tooltipPosition.left = calculateCenterBiasPosition(elementPosition, tooltipDimensions, boundaries.right, boundaries.left);
16346
+ tooltipPosition.left = calculateCenterBiasPosition(elementPosition, tooltipDimensions, screenDimensions, boundaries.right, boundaries.left);
16325
16347
  }
16326
16348
  return tooltipPosition;
16327
16349
  }
16328
- function getBoundaries() {
16350
+ function getBoundaries(screenDimensions) {
16329
16351
  return {
16330
- right: window.innerWidth * TOOLTIP_CONSTANTS.BOUNDARY_MARGIN_RIGHT,
16331
- left: window.innerWidth * TOOLTIP_CONSTANTS.BOUNDARY_MARGIN_LEFT
16352
+ right: screenDimensions.width * TOOLTIP_CONSTANTS.BOUNDARY_MARGIN_RIGHT,
16353
+ left: screenDimensions.width * TOOLTIP_CONSTANTS.BOUNDARY_MARGIN_LEFT
16332
16354
  };
16333
16355
  }
16334
16356
  function calculateCaretPadding(caretSizes) {
@@ -16349,7 +16371,7 @@ var BuildingBlockTooltips = (function () {
16349
16371
  if (tooltipRight > rightBoundary) {
16350
16372
  const overflow = tooltipRight - rightBoundary;
16351
16373
  if (leftVal - overflow < leftBoundary) {
16352
- return spaceEvenly(leftVal, width);
16374
+ return spaceEvenly(leftVal, width, screenDimensions);
16353
16375
  }
16354
16376
  else {
16355
16377
  return leftVal - overflow;
@@ -16357,7 +16379,7 @@ var BuildingBlockTooltips = (function () {
16357
16379
  }
16358
16380
  return leftVal;
16359
16381
  }
16360
- function calculateLeftBiasPosition(elementPosition, tooltipDimensions, caretSizes, rightBoundary, leftBoundary) {
16382
+ function calculateLeftBiasPosition(elementPosition, tooltipDimensions, caretSizes, screenDimensions, rightBoundary, leftBoundary) {
16361
16383
  const caretPadding = calculateCaretPadding(caretSizes);
16362
16384
  const width = tooltipDimensions.width;
16363
16385
  var leftVal = elementPosition.left - width + (elementPosition.width / 2) + caretPadding;
@@ -16365,7 +16387,7 @@ var BuildingBlockTooltips = (function () {
16365
16387
  const overflow = leftBoundary - leftVal;
16366
16388
  const tooltipRight = leftVal + width;
16367
16389
  if (tooltipRight + overflow > rightBoundary) {
16368
- return spaceEvenly(leftVal, width);
16390
+ return spaceEvenly(leftVal, width, screenDimensions);
16369
16391
  }
16370
16392
  else {
16371
16393
  return leftVal + overflow;
@@ -16373,7 +16395,7 @@ var BuildingBlockTooltips = (function () {
16373
16395
  }
16374
16396
  return leftVal;
16375
16397
  }
16376
- function calculateCenterBiasPosition(elementPosition, tooltipDimensions, rightBoundary, leftBoundary) {
16398
+ function calculateCenterBiasPosition(elementPosition, tooltipDimensions, screenDimensions, rightBoundary, leftBoundary) {
16377
16399
  const width = tooltipDimensions.width;
16378
16400
  var leftVal = elementPosition.left + (elementPosition.width / 2) - (width / 2);
16379
16401
  let tooltipRight = leftVal + width;
@@ -16381,7 +16403,7 @@ var BuildingBlockTooltips = (function () {
16381
16403
  const overflow = tooltipRight - rightBoundary;
16382
16404
  leftVal -= overflow;
16383
16405
  if (leftVal < leftBoundary) {
16384
- return spaceEvenly(leftVal, width);
16406
+ return spaceEvenly(leftVal, width, screenDimensions);
16385
16407
  }
16386
16408
  }
16387
16409
  else if (leftVal < leftBoundary) {
@@ -16389,14 +16411,14 @@ var BuildingBlockTooltips = (function () {
16389
16411
  leftVal += overflow;
16390
16412
  let tooltipRight = leftVal + width;
16391
16413
  if (tooltipRight > rightBoundary) {
16392
- return spaceEvenly(leftVal, width);
16414
+ return spaceEvenly(leftVal, width, screenDimensions);
16393
16415
  }
16394
16416
  }
16395
16417
  return leftVal;
16396
16418
  }
16397
- function spaceEvenly(leftVal, width) {
16419
+ function spaceEvenly(leftVal, width, screenDimensions) {
16398
16420
  const availableLeftSpace = leftVal;
16399
- const availableRightSpace = window.innerWidth - (leftVal + width);
16421
+ const availableRightSpace = screenDimensions.width - (leftVal + width);
16400
16422
  if (availableLeftSpace > availableRightSpace) {
16401
16423
  return leftVal - (availableLeftSpace - availableRightSpace) / 2;
16402
16424
  }
@@ -16619,8 +16641,10 @@ var BuildingBlockTooltips = (function () {
16619
16641
  var guideContainer = providedGuideContainer || getGuideContainer(step);
16620
16642
  if (!guideContainer)
16621
16643
  return;
16622
- var element = step.element || getElementForGuideStep(step);
16623
- var elPos = getOffsetPosition(element);
16644
+ var targetDocument = guideContainer.ownerDocument;
16645
+ var targetWindow = targetDocument.defaultView;
16646
+ var element = step.element || getElementForGuideStep(step, targetDocument);
16647
+ var elPos = getOffsetPosition(element, targetWindow);
16624
16648
  // If display:none then don't re-position
16625
16649
  if (getComputedStyle_safe(step.elements[0]).display === 'none')
16626
16650
  return;
@@ -16642,7 +16666,7 @@ var BuildingBlockTooltips = (function () {
16642
16666
  borderColor: ttContainerStyles.borderColor,
16643
16667
  borderWidth: parseInt(ttContainerStyles.borderWidth, 10) || 0
16644
16668
  };
16645
- var tooltipDimensions = this.getBBTooltipDimensions(elPos, tooltipSizes, caretStyles, layoutDir, screenPos);
16669
+ var tooltipDimensions = this.getBBTooltipDimensions(elPos, tooltipSizes, caretStyles, layoutDir, screenPos, getScreenDimensions(targetWindow));
16646
16670
  if (caretStyles.height && caretStyles.width) {
16647
16671
  var caretDiv = ttdiv.find('.pendo-tooltip-caret')[0];
16648
16672
  var borderCaret = ttdiv.find('.pendo-tooltip-caret-border')[0];
@@ -20009,6 +20033,9 @@ var GuideStateModule = (function () {
20009
20033
  }
20010
20034
  context.commit('setLastGuideStepSeen', lastGuideStepSeen);
20011
20035
  pendo$1.lastGuideStepSeen = lastGuideStepSeen;
20036
+ if (guideCache) {
20037
+ guideCache.update(lastGuideStepSeen);
20038
+ }
20012
20039
  },
20013
20040
  updateThrottlingState(context, state) {
20014
20041
  context.commit('setThrottlingState', state);
@@ -21343,6 +21370,16 @@ Badge.behaviors = [
21343
21370
  ShowOnHover
21344
21371
  ];
21345
21372
  function InlinePosition() {
21373
+ function getShadowDomAdjustedTarget(target) {
21374
+ try {
21375
+ if (target.shadowRoot && !target.shadowRoot.querySelector('slot')) {
21376
+ return target.shadowRoot;
21377
+ }
21378
+ }
21379
+ catch (e) {
21380
+ }
21381
+ return target;
21382
+ }
21346
21383
  if (this.position === 'inline' || this.position === 'inline-right' || this.position === 'inline-left') {
21347
21384
  this.before('show', function () {
21348
21385
  var targetElem = this.target();
@@ -21355,18 +21392,19 @@ function InlinePosition() {
21355
21392
  }
21356
21393
  if (targetElem && targetElem.tagName) {
21357
21394
  var tagName = targetElem.tagName.toLowerCase();
21395
+ var shadowDomAdjustedTarget = getShadowDomAdjustedTarget(targetElem);
21358
21396
  if (/br|input|img|select|textarea/.test(tagName)) {
21359
21397
  if (badgeElem.parentNode === targetElem.parentNode)
21360
21398
  return;
21361
21399
  // Insert after if targetElem cannot have children
21362
21400
  targetElem.parentNode.insertBefore(badgeElem, targetElem.nextSibling);
21363
21401
  }
21364
- else if (badgeElem.parentNode !== targetElem) {
21402
+ else if (badgeElem.parentNode !== shadowDomAdjustedTarget) {
21365
21403
  if (this.position === 'inline' || this.position === 'inline-right') {
21366
- targetElem.appendChild(badgeElem);
21404
+ shadowDomAdjustedTarget.appendChild(badgeElem);
21367
21405
  }
21368
21406
  else if (this.position === 'inline-left') {
21369
- targetElem.prepend(badgeElem);
21407
+ shadowDomAdjustedTarget.prepend(badgeElem);
21370
21408
  }
21371
21409
  }
21372
21410
  }
@@ -23210,7 +23248,7 @@ var BuildingBlockWatermark = (function () {
23210
23248
  }
23211
23249
  function buildWatermark(options, buildNodeFromJSON) {
23212
23250
  options = options || {};
23213
- if (!options.isTraining)
23251
+ if (!options.isTraining || options.isEmbedded)
23214
23252
  return;
23215
23253
  var watermarkGuide = options.targetAccount ? findWatermarkByTargetAccount(options.targetAccount) : findWatermarkByAppId(options.appId);
23216
23254
  if (!watermarkGuide || !watermarkGuide.steps)
@@ -23783,6 +23821,149 @@ function testGuideGifEndpoint(loader, apiKey) {
23783
23821
  });
23784
23822
  }
23785
23823
 
23824
+ function deepClone(obj) {
23825
+ return JSON.parse(JSON.stringify(obj));
23826
+ }
23827
+ class GuideCache {
23828
+ constructor(apiKey, ConfigReader) {
23829
+ this.apiKey = apiKey;
23830
+ this.cacheGuides = ConfigReader.get('cacheGuides');
23831
+ this.cacheGuidesTimeout = ConfigReader.get('cacheGuidesTimeout');
23832
+ this.cacheGuidesPersistent = ConfigReader.get('cacheGuidesPersistent');
23833
+ this.cache = null;
23834
+ this.db = null;
23835
+ }
23836
+ openDB(apiKey, indexedDB = window.indexedDB) {
23837
+ if (!this.cacheGuidesPersistent)
23838
+ return q.resolve();
23839
+ if (this.db)
23840
+ return q.resolve(this.db);
23841
+ const deferred = q.defer();
23842
+ const request = indexedDB.open(`pendo-${apiKey}`, 1);
23843
+ request.onerror = () => {
23844
+ log.warn('Error opening guide database');
23845
+ this.cacheGuidesPersistent = false;
23846
+ deferred.resolve();
23847
+ };
23848
+ request.onsuccess = (event) => {
23849
+ const db = event.target.result;
23850
+ this.db = db;
23851
+ deferred.resolve(db);
23852
+ };
23853
+ request.onupgradeneeded = (event) => {
23854
+ const db = event.target.result;
23855
+ const objectStore = db.createObjectStore('guides', { keyPath: 'guide.id' });
23856
+ objectStore.transaction.oncomplete = () => {
23857
+ this.db = db;
23858
+ deferred.resolve(db);
23859
+ };
23860
+ };
23861
+ return deferred.promise;
23862
+ }
23863
+ load(now = getNow()) {
23864
+ if (this.cache)
23865
+ return q.resolve(this.cache);
23866
+ this.cache = {};
23867
+ if (!this.db)
23868
+ return q.resolve(this.cache);
23869
+ const deferred = q.defer();
23870
+ const objectStore = this.db.transaction(['guides'], 'readwrite').objectStore('guides');
23871
+ const request = objectStore.getAll();
23872
+ request.onerror = () => {
23873
+ log.warn('Error loading guide cache');
23874
+ this.cacheGuidesPersistent = false;
23875
+ this.db = null;
23876
+ deferred.resolve(this.cache);
23877
+ };
23878
+ request.onsuccess = (event) => {
23879
+ const cachedGuides = event.target.result;
23880
+ _.each(cachedGuides, (cachedGuide) => {
23881
+ if (cachedGuide.expires > now) {
23882
+ this.cache[cachedGuide.guide.id] = cachedGuide;
23883
+ }
23884
+ else {
23885
+ objectStore.delete(cachedGuide.guide.id);
23886
+ }
23887
+ });
23888
+ deferred.resolve(this.cache);
23889
+ };
23890
+ return deferred.promise;
23891
+ }
23892
+ add(guide, visitorId, now = getNow()) {
23893
+ if (!this.cacheGuides)
23894
+ return;
23895
+ if (!this.cache)
23896
+ return;
23897
+ const cachedGuide = {
23898
+ expires: now + this.cacheGuidesTimeout,
23899
+ visitorId,
23900
+ guide: deepClone(guide)
23901
+ };
23902
+ this.cache[guide.id] = cachedGuide;
23903
+ return this.save(cachedGuide);
23904
+ }
23905
+ save(cachedGuide) {
23906
+ if (!this.db)
23907
+ return;
23908
+ const objectStore = this.db.transaction(['guides'], 'readwrite').objectStore('guides');
23909
+ const deferred = q.defer();
23910
+ const update = objectStore.put(cachedGuide);
23911
+ update.onerror = () => {
23912
+ log.warn(`Error saving guide to cache ${cachedGuide.guide.id}`);
23913
+ deferred.resolve();
23914
+ };
23915
+ update.onsuccess = () => {
23916
+ deferred.resolve();
23917
+ };
23918
+ return deferred.promise;
23919
+ }
23920
+ update(lastGuideStepSeen) {
23921
+ if (!this.cache)
23922
+ return;
23923
+ const cachedGuide = this.cache[lastGuideStepSeen.guideId];
23924
+ if (!cachedGuide)
23925
+ return;
23926
+ const cachedStep = _.find(cachedGuide.guide.steps, (s) => s.id === lastGuideStepSeen.guideStepId);
23927
+ if (!cachedStep)
23928
+ return;
23929
+ cachedStep.seenState = lastGuideStepSeen.state;
23930
+ cachedStep.seenReason = lastGuideStepSeen.seenReason;
23931
+ cachedStep.dismissCount = lastGuideStepSeen.dismissCount;
23932
+ cachedStep.snoozeEndTime = lastGuideStepSeen.snoozeEndTime;
23933
+ return this.save(cachedGuide);
23934
+ }
23935
+ list(visitorId, now = getNow()) {
23936
+ if (!this.cacheGuides)
23937
+ return q.resolve([]);
23938
+ return this.openDB(this.apiKey).then(() => {
23939
+ return this.load(now);
23940
+ }).then(() => {
23941
+ const list = [];
23942
+ _.each(this.cache, (cachedGuide) => {
23943
+ if (cachedGuide.expires > now && cachedGuide.visitorId === visitorId) {
23944
+ list.push(_.pick(cachedGuide.guide, 'id', 'lastUpdatedAt', 'language'));
23945
+ }
23946
+ else {
23947
+ delete this.cache[cachedGuide.guide.id];
23948
+ }
23949
+ });
23950
+ return list;
23951
+ });
23952
+ }
23953
+ get(guideId) {
23954
+ if (this.cache && this.cache[guideId]) {
23955
+ return deepClone(this.cache[guideId].guide);
23956
+ }
23957
+ }
23958
+ clear() {
23959
+ this.cache = {};
23960
+ if (this.db) {
23961
+ const objectStore = this.db.transaction(['guides'], 'readwrite').objectStore('guides');
23962
+ objectStore.clear();
23963
+ }
23964
+ }
23965
+ }
23966
+
23786
23967
  const pendoLocalStorage$1 = agentStorage.getLocal();
23787
23968
  var guideEvtCache = [];
23788
23969
  var controlGuideLogMessage = 'Guide was not shown because this visitor is in a control group of an active experiment for the guide';
@@ -25024,14 +25205,6 @@ function handleDoNotProcess() {
25024
25205
  store.commit('debugger/doNotProcess', true);
25025
25206
  log.info('not tracking visitor due to 451 response');
25026
25207
  }
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
25208
  function guidesPayload(guidesJson) {
25036
25209
  if (!mostRecentGuideRequest)
25037
25210
  return;
@@ -25041,13 +25214,13 @@ function guidesPayload(guidesJson) {
25041
25214
  }
25042
25215
  if (_.isString(guidesJson.id) && guidesJson.id !== mostRecentGuideRequest.id)
25043
25216
  return;
25044
- const cachedGuides = _.indexBy(pendo$1.guides, 'id');
25045
25217
  _.extend(pendo$1, guidesJson);
25046
25218
  pendo$1.guides = _.map(pendo$1.guides, function (guide) {
25047
25219
  if (_.keys(guide).length == 1 && guide.id) {
25048
- return resetCachedGuide(cachedGuides[guide.id]);
25220
+ return guideCache.get(guide.id);
25049
25221
  }
25050
25222
  else {
25223
+ guideCache.add(guide, get_visitor_id());
25051
25224
  return guide;
25052
25225
  }
25053
25226
  });
@@ -25082,48 +25255,53 @@ var loadGuideJs = function (apiKey, params) {
25082
25255
  log.info('no metadata to send', { contexts: ['guides', 'metadata'] });
25083
25256
  }
25084
25257
  }
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();
25258
+ return guideCache.list(params.visitorId).then(cachedGuides => {
25259
+ if (cachedGuides.length > 0) {
25260
+ params.cachedGuides = cachedGuides;
25261
+ }
25262
+ var jzb = compress(params);
25263
+ var queryString = {
25264
+ id: guideRequestId,
25265
+ jzb,
25266
+ v: VERSION,
25267
+ ct: (new Date()).getTime()
25268
+ };
25269
+ if (isAdoptPartner && params.accountId && params.accountId !== 'ACCOUNT-UNIQUE-ID') {
25270
+ queryString.acc = base64EncodeString(params.accountId);
25271
+ }
25272
+ if (isDebuggingEnabled()) {
25273
+ // Include debug info from server
25274
+ queryString.debug = true;
25275
+ }
25276
+ var url = buildBaseDataUrl(guideLoaderImpl.endpoint(), apiKey, queryString);
25277
+ var jwtOptions = JWT.get();
25278
+ let loadingPromise;
25279
+ if (url.length > URL_MAX_LENGTH || !_.isEmpty(jwtOptions)) {
25280
+ delete queryString.jzb;
25281
+ url = buildBaseDataUrl('guide.json', apiKey, queryString);
25282
+ var payload = _.extend({ events: jzb }, jwtOptions);
25283
+ loadingPromise = guideLoaderImpl.post(url, payload, pendo$1, _.noop);
25126
25284
  }
25285
+ else {
25286
+ loadingPromise = guideLoaderImpl.load(url, pendo$1, _.noop);
25287
+ }
25288
+ return q.all([
25289
+ // eslint-disable-next-line dot-notation
25290
+ loadingPromise['catch'](function (result) {
25291
+ if (result.status === 451) {
25292
+ handleDoNotProcess();
25293
+ }
25294
+ // passthrough rejections to subscribers
25295
+ return q.reject(result);
25296
+ }),
25297
+ deferred.promise,
25298
+ testGuideGifEndpoint(guideLoaderImpl, apiKey)
25299
+ ]).then(function ([, , testGuideGifResult]) {
25300
+ setGuidesBlocked(testGuideGifResult);
25301
+ if (!testGuideGifResult.success) {
25302
+ return q.reject();
25303
+ }
25304
+ });
25127
25305
  });
25128
25306
  };
25129
25307
  var guideLoaderImpl = XHRGuideLoader;
@@ -25236,18 +25414,6 @@ function shouldLoadGuides(visitorId, callback) {
25236
25414
  }
25237
25415
  return true;
25238
25416
  }
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
25417
  /**
25252
25418
  * Manually load guides for current visitor and URL. This is typically handled automatically by the Agent
25253
25419
  * whenever the host Application changes its URL. In rare circumstances, a host Application may chose to
@@ -25282,10 +25448,6 @@ var loadGuides = function (apiKey, visitorId, page, callback) {
25282
25448
  url: page,
25283
25449
  oldVisitorId: get_old_visitor_id()
25284
25450
  };
25285
- const cachedGuides = getCachedGuideList(pendo$1, loadGuides);
25286
- if (cachedGuides.length && !visitorChanged) {
25287
- params.cachedGuides = cachedGuides;
25288
- }
25289
25451
  const reqId = _.uniqueId();
25290
25452
  loadGuides.reqId = reqId;
25291
25453
  loadGuideJs(apiKey, params).then(function () {
@@ -25570,6 +25732,7 @@ function securityPolicyViolationFn(evt) {
25570
25732
  forceGuideReload();
25571
25733
  }
25572
25734
  }
25735
+ let guideCache;
25573
25736
  /**
25574
25737
  * Resets and starts guide loop
25575
25738
  *
@@ -25578,11 +25741,12 @@ function securityPolicyViolationFn(evt) {
25578
25741
  * @example
25579
25742
  * pendo.initGuides()
25580
25743
  */
25581
- var initGuides = function () {
25744
+ var initGuides = function (observer) {
25582
25745
  const teardownFns = [];
25583
25746
  teardownFns.push(initGuideAnalytics({
25584
25747
  localStorageUnload: ConfigReader.get('analytics.localStorageUnload')
25585
25748
  }));
25749
+ guideCache = new GuideCache(pendo$1.apiKey, ConfigReader);
25586
25750
  GuideMonitor.run();
25587
25751
  teardownFns.push(GuideMonitor.stop);
25588
25752
  Events.appUnloaded.on(function () {
@@ -25642,8 +25806,8 @@ var initGuides = function () {
25642
25806
  teardownFns.push(attachEventInternal(window, 'gestureend', adjustGuidesOnGestureEnd, true));
25643
25807
  teardownFns.push(attachEventInternal(window, 'securitypolicyviolation', securityPolicyViolationFn));
25644
25808
  teardownFns.push(createVideoFullScreenListeners());
25645
- if (ConfigReader.get('preferMutationObserver') && sniffer.MutationObserver) {
25646
- var updateGuide = function (event) {
25809
+ if (observer.observing) {
25810
+ var updateGuide = function () {
25647
25811
  store.dispatch('guideUpdate/documentChanged');
25648
25812
  };
25649
25813
  const debouncedUpdate = _.debounce(updateGuide, 50);
@@ -25651,10 +25815,8 @@ var initGuides = function () {
25651
25815
  teardownFns.push(attachEvent(window, 'animationend', debouncedUpdate));
25652
25816
  teardownFns.push(attachEvent(window, 'transitionend', debouncedUpdate));
25653
25817
  teardownFns.push(attachEvent(window, 'mouseover', debouncedUpdate));
25818
+ store.commit('guideUpdate/setObserver', observer);
25654
25819
  store.commit('guideUpdate/setUseObserver');
25655
- if (ConfigReader.get('observeShadowRoots')) {
25656
- store.commit('guideUpdate/setObserveShadowRoots');
25657
- }
25658
25820
  teardownFns.push(() => store.dispatch('guideUpdate/stopObserver'));
25659
25821
  }
25660
25822
  /**
@@ -25700,6 +25862,7 @@ var initGuides = function () {
25700
25862
  agentStorage.registry.addLocal(AD_BLOCK_STORAGE_KEY, { duration: 14400000 }); // 4 hours default duration
25701
25863
  GuideRuntime.initialize();
25702
25864
  return () => {
25865
+ guideCache = null;
25703
25866
  reloadGuides.reset();
25704
25867
  resetPendoUI();
25705
25868
  cancelGuideRequest();
@@ -27035,6 +27198,168 @@ const isReady = (pendoObj) => {
27035
27198
  return pendoObj.doesExist(pendoObj.apiKey);
27036
27199
  };
27037
27200
 
27201
+ class ShadowDomManager extends EventTarget {
27202
+ constructor() {
27203
+ super();
27204
+ this.cache = new Set();
27205
+ this.foundShadowRoots = false;
27206
+ this.stoppedSearchEarly = false;
27207
+ }
27208
+ updateCache() {
27209
+ // eslint-disable-next-line agent-eslint-rules/no-array-foreach
27210
+ this.cache.forEach(shadowRoot => {
27211
+ if (!isInDocument(shadowRoot)) {
27212
+ this.cache.delete(shadowRoot);
27213
+ this.dispatchEvent({
27214
+ type: 'detachShadow',
27215
+ shadowRoot
27216
+ });
27217
+ }
27218
+ });
27219
+ }
27220
+ patchAttachShadow(Element) {
27221
+ const original = Element.prototype.attachShadow;
27222
+ const self = this;
27223
+ Element.prototype.attachShadow = function (options) {
27224
+ const shadowRoot = original.call(this, options);
27225
+ if (this.shadowRoot) {
27226
+ self.triggerAttachShadow(this.shadowRoot);
27227
+ }
27228
+ return shadowRoot;
27229
+ };
27230
+ Element.prototype.attachShadow.toString = function () {
27231
+ return original.toString();
27232
+ };
27233
+ return () => {
27234
+ Element.prototype.attachShadow = original;
27235
+ };
27236
+ }
27237
+ initialize() {
27238
+ this.unpatchAttachShadow = this.patchAttachShadow(Element);
27239
+ this.findShadowRoots(document);
27240
+ }
27241
+ triggerAttachShadow(shadowRoot) {
27242
+ this.cache.add(shadowRoot);
27243
+ this.dispatchEvent({
27244
+ type: 'attachShadow',
27245
+ shadowRoot
27246
+ });
27247
+ }
27248
+ findShadowRoots(document, maxPerSearch = 5000) {
27249
+ if (!_.isFunction(document.createNodeIterator))
27250
+ return;
27251
+ let nodesChecked = 0;
27252
+ let queue = [getBody(document)];
27253
+ let currentNode;
27254
+ function eachShadowRoot(iterator) {
27255
+ do {
27256
+ if (!iterator) {
27257
+ iterator = document.createNodeIterator(queue.pop(), NodeFilter.SHOW_ELEMENT);
27258
+ }
27259
+ if (!iterator || !iterator.nextNode)
27260
+ break;
27261
+ while ((currentNode = iterator.nextNode())) {
27262
+ nodesChecked++;
27263
+ if (currentNode && currentNode.shadowRoot) {
27264
+ this.triggerAttachShadow(currentNode.shadowRoot);
27265
+ queue.push(currentNode.shadowRoot);
27266
+ this.foundShadowRoots = true;
27267
+ }
27268
+ if (nodesChecked % maxPerSearch === 0)
27269
+ break;
27270
+ }
27271
+ if (currentNode)
27272
+ break;
27273
+ iterator = null;
27274
+ } while (queue.length);
27275
+ if (currentNode && this.foundShadowRoots) {
27276
+ this.findTimeout = setTimeout$1(() => {
27277
+ this.findTimeout = null;
27278
+ eachShadowRoot.call(this, iterator);
27279
+ }, 50);
27280
+ }
27281
+ if (nodesChecked === maxPerSearch && !this.foundShadowRoots) {
27282
+ this.stoppedSearchEarly = true;
27283
+ }
27284
+ }
27285
+ eachShadowRoot.call(this);
27286
+ }
27287
+ teardown() {
27288
+ this.cache.clear();
27289
+ if (_.isFunction(this.unpatchAttachShadow)) {
27290
+ this.unpatchAttachShadow();
27291
+ this.unpatchAttachShadow = null;
27292
+ }
27293
+ if (this.findTimeout) {
27294
+ clearTimeout(this.findTimeout);
27295
+ this.findTimeout = null;
27296
+ }
27297
+ }
27298
+ }
27299
+
27300
+ class UberMutationObserver extends EventTarget {
27301
+ constructor(observerClass = getZoneSafeMethod('MutationObserver')) {
27302
+ super();
27303
+ this.ObserverClass = observerClass;
27304
+ this.observing = false;
27305
+ this.observers = new Map();
27306
+ this.triggerMutation = this.dispatchMutationEvent;
27307
+ this.shadowDom = new ShadowDomManager();
27308
+ this.shadowDom.addEventListener('attachShadow', _.bind(this.handleAttachShadow, this));
27309
+ this.shadowDom.addEventListener('detachShadow', _.bind(this.handleDetachShadow, this));
27310
+ this.addEventListener('mutation', () => {
27311
+ this.shadowDom.updateCache();
27312
+ });
27313
+ }
27314
+ initialize(pendo, PluginAPI) {
27315
+ const configReader = PluginAPI.ConfigReader;
27316
+ if (!configReader.get('preferMutationObserver') || !pendo.sniffer.MutationObserver) {
27317
+ return;
27318
+ }
27319
+ this.observeShadowRoots = configReader.get('observeShadowRoots');
27320
+ this.startObserver(document.documentElement);
27321
+ this.observing = true;
27322
+ if (this.observeShadowRoots) {
27323
+ this.shadowDom.initialize();
27324
+ }
27325
+ }
27326
+ startObserver(target) {
27327
+ const observer = new this.ObserverClass(mutation => this.triggerMutation(mutation));
27328
+ this.observers.set(target, observer);
27329
+ observer.observe(target, {
27330
+ subtree: true,
27331
+ attributes: true,
27332
+ childList: true,
27333
+ characterData: true
27334
+ });
27335
+ }
27336
+ teardown() {
27337
+ this.observers.clear();
27338
+ this.shadowDom.teardown();
27339
+ }
27340
+ dispatchMutationEvent(mutation) {
27341
+ this.dispatchEvent({
27342
+ type: 'mutation',
27343
+ mutation
27344
+ });
27345
+ }
27346
+ triggerMutationOnce(mutation) {
27347
+ this.triggerMutation = _.noop;
27348
+ queueMicrotask(() => {
27349
+ this.dispatchMutationEvent(mutation);
27350
+ this.triggerMutation = this.triggerMutationOnce;
27351
+ });
27352
+ }
27353
+ handleAttachShadow({ shadowRoot }) {
27354
+ this.triggerMutation = this.triggerMutationOnce;
27355
+ this.startObserver(shadowRoot);
27356
+ }
27357
+ handleDetachShadow({ shadowRoot }) {
27358
+ this.observers.delete(shadowRoot);
27359
+ }
27360
+ }
27361
+ var observer = new UberMutationObserver();
27362
+
27038
27363
  // ---------------------------------------------------------------------------
27039
27364
  function registerEventHandlers({ events = [] }) {
27040
27365
  _.each(events, (callback, eventName) => {
@@ -27145,6 +27470,9 @@ const initialize = makeSafe(function (options) {
27145
27470
  teardownFns.push(initializeEventBuffer({
27146
27471
  localStorageUnload: localStorageUnloadEnabled
27147
27472
  }));
27473
+ // needs to happen before initGuides
27474
+ observer.initialize(pendo$1, PluginAPI);
27475
+ teardownFns.push(() => observer.teardown());
27148
27476
  if (pendoCore) {
27149
27477
  /**
27150
27478
  * Current visitor id for pendo installation, either anonymous or identified. Used to determine
@@ -27184,21 +27512,12 @@ const initialize = makeSafe(function (options) {
27184
27512
  * @label OPTIONS_HASH_KEY_NAME
27185
27513
  */
27186
27514
  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
27515
  // Disable content pre-fetch for guide center
27197
27516
  pendo$1.disableGuideCenterContentSearch = options.disableGuideCenterContentSearch;
27198
27517
  // Register handlers passed through pendo_options
27199
27518
  teardownFns.push(forwardInternalEvents(Events));
27200
27519
  registerEventHandlers(options);
27201
- teardownFns.push(initGuides()); // this is safe. loadGuides actually does the loading.
27520
+ teardownFns.push(initGuides(observer)); // this is safe. loadGuides actually does the loading.
27202
27521
  initIdentityEvents(); // setup identify and meta event listeners
27203
27522
  teardownFns.push(wirePage());
27204
27523
  teardownFns.push(initializePlugins());
@@ -27489,6 +27808,7 @@ var BuildingBlockGuides = (function () {
27489
27808
  }
27490
27809
  }
27491
27810
  function renderGuideFromJSON(json, step, guides, options) {
27811
+ options = options || {};
27492
27812
  var guide = step.getGuide();
27493
27813
  var containerJSON = findGuideContainerJSON(json);
27494
27814
  var isResourceCenter = _.get(guide, 'attributes.resourceCenter');
@@ -27500,7 +27820,7 @@ var BuildingBlockGuides = (function () {
27500
27820
  var isAnnouncementModule = _.get(guide, 'attributes.resourceCenter.moduleId') === 'AnnouncementsModule';
27501
27821
  step.hasEscapeListener = false;
27502
27822
  step.containerId = containerJSON && containerJSON.props && containerJSON.props.id;
27503
- step.element = getElementForGuideStep(step);
27823
+ step.element = getElementForGuideStep(step, options.document);
27504
27824
  var guideToAppend = BuildingBlockGuides.buildNodeFromJSON(json, step, guides);
27505
27825
  step.guideElement = guideToAppend;
27506
27826
  var guideContainer = guideToAppend.find('#' + step.containerId);
@@ -27519,19 +27839,20 @@ var BuildingBlockGuides = (function () {
27519
27839
  // between re-renders
27520
27840
  guideContainer.css({ visibility: 'hidden' });
27521
27841
  guideToAppend.css({ visibility: 'hidden' });
27842
+ const embedConfig = _.get(guide, 'attributes.embedConfig', null);
27522
27843
  var watermark = BuildingBlockWatermark.buildWatermark({
27523
27844
  appId: guide.appId,
27524
27845
  targetAccount: guide.targetAccount,
27525
27846
  isTraining: guide.isTraining,
27526
- isBottomAligned: guideContainer.attr(verticalAlignmentAttr) === 'Bottom Aligned'
27847
+ isBottomAligned: guideContainer.attr(verticalAlignmentAttr) === 'Bottom Aligned',
27848
+ isEmbedded: !!embedConfig
27527
27849
  }, BuildingBlockGuides.buildNodeFromJSON);
27528
27850
  if (watermark) {
27529
27851
  guideContainer.append(watermark);
27530
27852
  }
27531
27853
  var hasImageCount = step && step.attributes && step.attributes.imgCount;
27532
27854
  // Do conditional Guide Rendering Things
27533
- var parent = getGuideAttachPoint();
27534
- const embedConfig = _.get(guide, 'attributes.embedConfig', null);
27855
+ var parent = getGuideAttachPoint(options.document);
27535
27856
  if (embedConfig) {
27536
27857
  const guideContainerId = 'pendo-guide-container';
27537
27858
  const baseContainerId = 'pendo-base';
@@ -32144,75 +32465,6 @@ function updateMasterGuideList(state) {
32144
32465
  }
32145
32466
  }
32146
32467
 
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
32468
  var GuideUpdateModule = (function () {
32217
32469
  var observer;
32218
32470
  function observerCallback() {
@@ -32223,7 +32475,6 @@ var GuideUpdateModule = (function () {
32223
32475
  }
32224
32476
  var state = {
32225
32477
  useObserver: false,
32226
- observeShadowRoots: false,
32227
32478
  observing: false,
32228
32479
  needsUpdate: false,
32229
32480
  scheduledUpdate: null,
@@ -32254,43 +32505,31 @@ var GuideUpdateModule = (function () {
32254
32505
  context.commit('setScheduledUpdate', null);
32255
32506
  }
32256
32507
  },
32257
- startObserverIfNeeded(context, observerClass) {
32508
+ startObserverIfNeeded(context) {
32258
32509
  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
32510
  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
- }
32511
+ const observer = context.getters.observer();
32512
+ observer.addEventListener('mutation', observerCallback);
32274
32513
  context.commit('setObserving', true);
32275
32514
  }
32276
32515
  }
32277
32516
  },
32278
32517
  stopObserver(context) {
32279
- var observerInstance = context.getters.observer();
32280
- if (observerInstance && _.isFunction(observerInstance.disconnect)) {
32281
- observerInstance.disconnect();
32518
+ const observer = context.getters.observer();
32519
+ if (observer) {
32520
+ observer.removeEventListener('mutation', observerCallback);
32282
32521
  }
32283
32522
  context.commit('setObserving', false);
32284
32523
  context.dispatch('stopScheduledUpdate');
32285
32524
  }
32286
32525
  };
32287
32526
  var mutations = {
32527
+ setObserver(state, _observer) {
32528
+ observer = _observer;
32529
+ },
32288
32530
  setUseObserver(state) {
32289
32531
  state.useObserver = true;
32290
32532
  },
32291
- setObserveShadowRoots(state) {
32292
- state.observeShadowRoots = true;
32293
- },
32294
32533
  setObserving(state, observing) {
32295
32534
  state.observing = observing;
32296
32535
  },
@@ -36205,7 +36444,9 @@ function debuggerExports() {
36205
36444
  isStagingServer,
36206
36445
  AutoDisplay,
36207
36446
  isLeader,
36208
- Events
36447
+ Events,
36448
+ observer,
36449
+ guideCache
36209
36450
  };
36210
36451
  }
36211
36452
  function startDebuggingModuleIfEnabled() {
@@ -38565,6 +38806,15 @@ function isConfiguredForMV3(config) {
38565
38806
  return config && config.useAssetHostForDesigner;
38566
38807
  }
38567
38808
  function initAgent(pendo, PendoConfig) {
38809
+ /**
38810
+ * Stores debugging configuration and state for the Pendo debugger.
38811
+ *
38812
+ * @name debug-enabled
38813
+ * @category Cookies/localStorage
38814
+ * @access public
38815
+ * @label debugEnabled
38816
+ */
38817
+ agentStorage.registry.addLocal(debugEnabled, { isPlain: true, serializer: JSON.stringify, deserializer: SafeJsonDeserializer });
38568
38818
  setPendoConfig(PendoConfig);
38569
38819
  overwriteBuiltConfigWithPendoConfig();
38570
38820
  if (!loadAsModule(PendoConfig) && loadAlternateAgent(PendoConfig, pendo, isDebuggingEnabled()))
@@ -38584,7 +38834,7 @@ function initAgent(pendo, PendoConfig) {
38584
38834
  AsyncContent.reset();
38585
38835
  store.dispatch('frames/init');
38586
38836
  logPublic.init();
38587
- shadowAPI.wrapSizzle(SizzleProxy);
38837
+ shadowAPI.wrapSizzle(SizzleProxy, observer.shadowDom);
38588
38838
  SizzleProxy.intercept(sizzleAttachPointInterceptor);
38589
38839
  populatePendoObject(pendo);
38590
38840
  log.addEventListener('log', _.partial(store.dispatch, 'errorLog/write'));
@@ -38678,7 +38928,8 @@ function TextCapture() {
38678
38928
  }
38679
38929
  function isTextCapturable(text) {
38680
38930
  var trimmedText = pluginAPI.util.trim.call(text);
38681
- return isEnabled() || pendoGlobal._.has(whitelist, trimmedText) || pendoGlobal._.has(whitelist, text);
38931
+ // pass the text as an array so that our toPath override doesn't try to split it on `.`
38932
+ return isEnabled() || pendoGlobal._.has(whitelist, [trimmedText]) || pendoGlobal._.has(whitelist, [text]);
38682
38933
  }
38683
38934
  function hasWhitelist() {
38684
38935
  return pendoGlobal._.size(whitelist) > 0;
@@ -47274,7 +47525,8 @@ class SessionRecorder {
47274
47525
  }, SEND_INTERVAL$1);
47275
47526
  var config = this.recordingConfig(visitorConfig);
47276
47527
  this._stop = this.record(this.pendo._.extend({
47277
- emit: bind(this.emit, this)
47528
+ emit: bind(this.emit, this),
47529
+ errorHandler: bind(this.errorHandler, this)
47278
47530
  }, config));
47279
47531
  this._refreshIds();
47280
47532
  this.onRecordingStart();
@@ -47386,6 +47638,9 @@ class SessionRecorder {
47386
47638
  return null;
47387
47639
  }
47388
47640
  }
47641
+ errorHandler(error) {
47642
+ this.logStopReason('RRWEB_ERROR', error);
47643
+ }
47389
47644
  /**
47390
47645
  * Handle new rrweb events coming in. This will also make sure that we are properly sending a "keyframe"
47391
47646
  * as the BE expects it. A "keyframe" should consist of only the events needed to start a recording. This includes
@@ -47489,6 +47744,10 @@ class SessionRecorder {
47489
47744
  this.sendHostedResources(hostedResourcesEvent);
47490
47745
  break;
47491
47746
  }
47747
+ case 'emptyPayload': {
47748
+ this.logStopReason('EMPTY_PAYLOAD');
47749
+ break;
47750
+ }
47492
47751
  case 'missingData': {
47493
47752
  this.logStopReason(`MISSING_${messageData.missingData}`);
47494
47753
  break;
@@ -48298,6 +48557,11 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
48298
48557
  }
48299
48558
  if (e.data.url && e.data.payload) {
48300
48559
  let { url, payload, shouldCacheResources } = e.data;
48560
+ if (Object.keys(payload).length === 0) {
48561
+ postMessage({
48562
+ type: 'emptyPayload'
48563
+ });
48564
+ }
48301
48565
  const { sequence } = payload;
48302
48566
  const stringifiedRecordingPayload = JSON.stringify(payload.recordingPayload);
48303
48567
  // calculate and post back the recording payload size before the payload is compressed
@@ -51511,7 +51775,8 @@ var ConfigReader = (function () {
51511
51775
  /**
51512
51776
  * Use this setting when using `preferMutationObserver` with an application that has Shadow DOM elements.
51513
51777
  * On page load, the Agent will run a full document scan for shadow roots and attach a MutationObserver to
51514
- * all results.
51778
+ * all results. This setting also allows the agent to run CSS selectors in all shadow roots, so CSS selectors
51779
+ * can be written without specifying the full path through all shadow roots with the `::shadow` pseudo-class.
51515
51780
  *
51516
51781
  * @access public
51517
51782
  * @category Config/Core