@pendo/agent 2.326.0 → 2.327.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dom.esm.js +51 -50
- package/dist/pendo.module.js +632 -219
- package/dist/pendo.module.min.js +10 -10
- package/dist/servers.json +7 -7
- package/package.json +1 -1
package/dist/pendo.module.js
CHANGED
|
@@ -2707,11 +2707,11 @@ var underscoreExports = underscore.exports;
|
|
|
2707
2707
|
var _ = /*@__PURE__*/getDefaultExportFromCjs(underscoreExports);
|
|
2708
2708
|
|
|
2709
2709
|
/**
|
|
2710
|
-
* Utility function to check if passed value exists. Returns false for `null` and `undefined`.
|
|
2710
|
+
* Utility function to check if the passed value exists. Returns false for `null` and `undefined`.
|
|
2711
2711
|
*
|
|
2712
2712
|
* @access public
|
|
2713
2713
|
* @category Utility
|
|
2714
|
-
* @param {any} value
|
|
2714
|
+
* @param {any} arg value to type check
|
|
2715
2715
|
* @returns {Boolean}
|
|
2716
2716
|
* @example
|
|
2717
2717
|
* pendo.doesExist(null) => false
|
|
@@ -2964,7 +2964,7 @@ var ConfigReader = (function () {
|
|
|
2964
2964
|
*
|
|
2965
2965
|
* @access public
|
|
2966
2966
|
* @category Config/Core
|
|
2967
|
-
* @name
|
|
2967
|
+
* @name forcedLeader
|
|
2968
2968
|
* @default false
|
|
2969
2969
|
* @type {boolean}
|
|
2970
2970
|
*/
|
|
@@ -3151,7 +3151,7 @@ var ConfigReader = (function () {
|
|
|
3151
3151
|
* An array of exact strings that can still be included in event data if text capture is disabled
|
|
3152
3152
|
* (`excludeAllText`). This will not override any allow list specified by your application settings but will apply if none is provided.
|
|
3153
3153
|
* These are not selectors but are equality checks (the string 'Bug' will allow links that have 'Bug' as the
|
|
3154
|
-
* text to be captured but not ones like 'Bug Report')
|
|
3154
|
+
* text to be captured but not ones like 'Bug Report').
|
|
3155
3155
|
*
|
|
3156
3156
|
* @access public
|
|
3157
3157
|
* @category Config/Analytics
|
|
@@ -3249,7 +3249,7 @@ var ConfigReader = (function () {
|
|
|
3249
3249
|
/**
|
|
3250
3250
|
* By default, the web SDK will also attempt to intercept calls to `stopPropagation` and
|
|
3251
3251
|
* `stopImmediatePropagation` for click, focus, submit, and change events in order to ensure that Pendo can
|
|
3252
|
-
* still
|
|
3252
|
+
* still properly recognize these events. In the case of this causing duplicate events or other issues, this
|
|
3253
3253
|
* functionality can be disabled.
|
|
3254
3254
|
*
|
|
3255
3255
|
* @access public
|
|
@@ -3312,7 +3312,7 @@ var ConfigReader = (function () {
|
|
|
3312
3312
|
*/
|
|
3313
3313
|
addOption('cacheGuides', [SNIPPET_SRC, PENDO_CONFIG_SRC], false);
|
|
3314
3314
|
/**
|
|
3315
|
-
* How often to clear the guides cache (in milliseconds)
|
|
3315
|
+
* How often to clear the guides cache (in milliseconds).
|
|
3316
3316
|
*
|
|
3317
3317
|
* @access public
|
|
3318
3318
|
* @category Config/Guides
|
|
@@ -3346,7 +3346,7 @@ var ConfigReader = (function () {
|
|
|
3346
3346
|
addOption('disableGlobalCSS', [SNIPPET_SRC, PENDO_CONFIG_SRC], false);
|
|
3347
3347
|
/**
|
|
3348
3348
|
* Building block guides use an inline style tag for various pseudo styles (e.g. hover, carets, animations).
|
|
3349
|
-
* These can be turned off using this flag for
|
|
3349
|
+
* These can be turned off using this flag for applications with more restrictive CSP settings but will
|
|
3350
3350
|
* require custom effort to reach style parity.
|
|
3351
3351
|
*
|
|
3352
3352
|
* @access public
|
|
@@ -3372,7 +3372,7 @@ var ConfigReader = (function () {
|
|
|
3372
3372
|
* cookies, localStorage, click tracking, and metadata. Only displays guides
|
|
3373
3373
|
* that have been configured explicitly to show to this visitor.
|
|
3374
3374
|
*
|
|
3375
|
-
* @access
|
|
3375
|
+
* @access private
|
|
3376
3376
|
* @category Config/Guides
|
|
3377
3377
|
* @name doNotTrackGuides
|
|
3378
3378
|
* @default false
|
|
@@ -3380,7 +3380,7 @@ var ConfigReader = (function () {
|
|
|
3380
3380
|
*/
|
|
3381
3381
|
addOption('doNotTrackGuides', [SNIPPET_SRC, PENDO_CONFIG_SRC]);
|
|
3382
3382
|
/**
|
|
3383
|
-
* If `true`, the web SDK will listen for `alt+shift+8` on the keyboard and try to launch the designer
|
|
3383
|
+
* If `true`, the web SDK will listen for `alt+shift+8` on the keyboard and try to launch the designer. The
|
|
3384
3384
|
* keyboard shortcut requires the guide launch modal of Engage to be open in another tab showing the shortcut.
|
|
3385
3385
|
*
|
|
3386
3386
|
* @access public
|
|
@@ -3458,7 +3458,7 @@ var ConfigReader = (function () {
|
|
|
3458
3458
|
*/
|
|
3459
3459
|
addOption('guides.disabled', [SNIPPET_SRC], false, undefined, ['disableGuides']);
|
|
3460
3460
|
/**
|
|
3461
|
-
* If
|
|
3461
|
+
* If `true`, guides with slow selectors will be removed from guide display processing.
|
|
3462
3462
|
* This will improve application performance, but slow guides will not be shown to users.
|
|
3463
3463
|
*
|
|
3464
3464
|
* @access public
|
|
@@ -3514,7 +3514,7 @@ var ConfigReader = (function () {
|
|
|
3514
3514
|
*/
|
|
3515
3515
|
addOption('inlineStyleNonce', [SNIPPET_SRC]);
|
|
3516
3516
|
/**
|
|
3517
|
-
* Formerly `leaderKey
|
|
3517
|
+
* Formerly `leaderKey`. Specify a preferred publicAppId to lead the multi-application iframe installation to make decisions about automatic
|
|
3518
3518
|
* guide display. In installations with more than 2 publicAppIds, the leaderApplication can be specified as a priority
|
|
3519
3519
|
* list (e.g. `leaderApplication: ['key1', 'key2', ...]`). Either all frames must agree on the leaderApplication setting,
|
|
3520
3520
|
* or only one frame should specify the leaderApplication. If neither of these conditions are met, the default leader
|
|
@@ -3544,7 +3544,7 @@ var ConfigReader = (function () {
|
|
|
3544
3544
|
addOption('storage.allowKeys', [SNIPPET_SRC], '*');
|
|
3545
3545
|
// Feedback
|
|
3546
3546
|
/**
|
|
3547
|
-
* If Feedback is
|
|
3547
|
+
* If Feedback is set up for your subscription, this option can be used to selectively disable Feedback.
|
|
3548
3548
|
*
|
|
3549
3549
|
* @access public
|
|
3550
3550
|
* @category Config/Core
|
|
@@ -3557,8 +3557,8 @@ var ConfigReader = (function () {
|
|
|
3557
3557
|
addOption('feedbackSettings', [PENDO_CONFIG_SRC], {});
|
|
3558
3558
|
addOption('pendoFeedback', [PENDO_CONFIG_SRC], false);
|
|
3559
3559
|
/**
|
|
3560
|
-
* If set, the web SDK will use this as the suffix when writing last step advanced key into the
|
|
3561
|
-
* This supports cross
|
|
3560
|
+
* If set, the web SDK will use this as the suffix when writing the last step advanced key into the visitor's cookie.
|
|
3561
|
+
* This supports cross-app guides by having a shared accessible location for different apps on the same effective level domain.
|
|
3562
3562
|
*
|
|
3563
3563
|
* @access public
|
|
3564
3564
|
* @category Config/Core
|
|
@@ -3979,12 +3979,12 @@ let SERVER = '';
|
|
|
3979
3979
|
let ASSET_HOST = '';
|
|
3980
3980
|
let ASSET_PATH = '';
|
|
3981
3981
|
let DESIGNER_SERVER = '';
|
|
3982
|
-
let VERSION = '2.
|
|
3983
|
-
let PACKAGE_VERSION = '2.
|
|
3982
|
+
let VERSION = '2.327.1_';
|
|
3983
|
+
let PACKAGE_VERSION = '2.327.1';
|
|
3984
3984
|
let LOADER = 'xhr';
|
|
3985
3985
|
/* eslint-enable web-sdk-eslint-rules/no-gulp-env-references */
|
|
3986
3986
|
/**
|
|
3987
|
-
* Returns current version of the Pendo Web SDK as a string. Also directly accessible at `pendo.VERSION`.
|
|
3987
|
+
* Returns the current version of the Pendo Web SDK as a string. Also directly accessible at `pendo.VERSION`.
|
|
3988
3988
|
*
|
|
3989
3989
|
* @access public
|
|
3990
3990
|
* @category Core
|
|
@@ -4703,7 +4703,7 @@ var agentStorage = (function () {
|
|
|
4703
4703
|
function read(name, isPlain, cookieSuffix) {
|
|
4704
4704
|
isPlain = registry.getKeyConfig(name, 'isPlain', isPlain);
|
|
4705
4705
|
cookieSuffix = registry.getKeyConfig(name, 'cookieSuffix', cookieSuffix);
|
|
4706
|
-
let keyLocalStorageOnly = registry.getKeyConfig(name, 'localStorageOnly'
|
|
4706
|
+
let keyLocalStorageOnly = registry.getKeyConfig(name, 'localStorageOnly');
|
|
4707
4707
|
var key = !isPlain ? getPendoCookieKey(name, cookieSuffix) : name;
|
|
4708
4708
|
let rawValue;
|
|
4709
4709
|
const deserialize = registry.getKeyDeserializer(name);
|
|
@@ -4773,7 +4773,7 @@ var agentStorage = (function () {
|
|
|
4773
4773
|
isPlain = registry.getKeyConfig(name, 'isPlain', isPlain);
|
|
4774
4774
|
isSecure = registry.getKeyConfig(name, 'isSecure', isSecure);
|
|
4775
4775
|
cookieSuffix = registry.getKeyConfig(name, 'cookieSuffix', cookieSuffix);
|
|
4776
|
-
let keyLocalStorageOnly = registry.getKeyConfig(name, 'localStorageOnly'
|
|
4776
|
+
let keyLocalStorageOnly = registry.getKeyConfig(name, 'localStorageOnly');
|
|
4777
4777
|
val = registry.getKeySerializer(name)(val);
|
|
4778
4778
|
var key = !isPlain ? getPendoCookieKey(name, cookieSuffix) : name;
|
|
4779
4779
|
resetCache(storageAvailable);
|
|
@@ -4814,7 +4814,7 @@ var agentStorage = (function () {
|
|
|
4814
4814
|
function clear(name, isPlain, cookieSuffix) {
|
|
4815
4815
|
isPlain = registry.getKeyConfig(name, 'isPlain', isPlain);
|
|
4816
4816
|
cookieSuffix = registry.getKeyConfig(name, 'cookieSuffix', cookieSuffix);
|
|
4817
|
-
let keyLocalStorageOnly = registry.getKeyConfig(name, 'localStorageOnly'
|
|
4817
|
+
let keyLocalStorageOnly = registry.getKeyConfig(name, 'localStorageOnly');
|
|
4818
4818
|
var key = !isPlain ? getPendoCookieKey(name, cookieSuffix) : name;
|
|
4819
4819
|
if (storageIsDisabled()) {
|
|
4820
4820
|
delete inMemoryStorage[key];
|
|
@@ -5925,7 +5925,7 @@ const ACCOUNT_ID_KEY = 'accountId';
|
|
|
5925
5925
|
*
|
|
5926
5926
|
* @access public
|
|
5927
5927
|
* @category Identity
|
|
5928
|
-
* @param {string} prefix string to prepend to the unique id
|
|
5928
|
+
* @param {string} [prefix] string to prepend to the unique id
|
|
5929
5929
|
* @returns {string}
|
|
5930
5930
|
* @example
|
|
5931
5931
|
* pendo.generate_unique_id('user-') => 'user-RaPiWJ5M53Y'
|
|
@@ -6042,7 +6042,7 @@ function findVisitorId() {
|
|
|
6042
6042
|
}
|
|
6043
6043
|
/**
|
|
6044
6044
|
* Returns the id for the visitor currently being applied to any events being sent to Pendo.
|
|
6045
|
-
* Will always be set either by host application or as an anonymous generated ID.
|
|
6045
|
+
* Will always be set either by the host application or as an anonymous generated ID.
|
|
6046
6046
|
*
|
|
6047
6047
|
* @access public
|
|
6048
6048
|
* @alias getVisitorId
|
|
@@ -6072,8 +6072,8 @@ function get_visitor_id_public() {
|
|
|
6072
6072
|
return get_visitor_id() || generate_anonymous_visitor_id();
|
|
6073
6073
|
}
|
|
6074
6074
|
/**
|
|
6075
|
-
* Sets visitor id for the web SDK. Requires a valid visitor id string. This will not change
|
|
6076
|
-
* or clear existing visitor metadata
|
|
6075
|
+
* Sets the visitor id for the web SDK. Requires a valid visitor id string. This will not change
|
|
6076
|
+
* or clear existing visitor metadata.
|
|
6077
6077
|
*
|
|
6078
6078
|
* @access public
|
|
6079
6079
|
* @category Identity
|
|
@@ -6115,8 +6115,8 @@ var get_account_id = function () {
|
|
|
6115
6115
|
return pendo$1.accountId;
|
|
6116
6116
|
};
|
|
6117
6117
|
/**
|
|
6118
|
-
* Sets account id for the web SDK without changing existing metadata. However,
|
|
6119
|
-
*
|
|
6118
|
+
* Sets the account id for the web SDK without changing existing metadata. However,
|
|
6119
|
+
* an invalid account id or an explicit `null` value will clear the current account id
|
|
6120
6120
|
* and account metadata.
|
|
6121
6121
|
*
|
|
6122
6122
|
* @access public
|
|
@@ -6167,7 +6167,7 @@ function clearAccount() {
|
|
|
6167
6167
|
}
|
|
6168
6168
|
}
|
|
6169
6169
|
/**
|
|
6170
|
-
* Removes current visitor id and account id. Triggers an identify event and reloads
|
|
6170
|
+
* Removes the current visitor id and account id. Triggers an identify event and reloads
|
|
6171
6171
|
* with a new anonymous visitor.
|
|
6172
6172
|
*
|
|
6173
6173
|
* @access public
|
|
@@ -8902,16 +8902,17 @@ var SizzleProxy = wrapSizzle(Sizzle);
|
|
|
8902
8902
|
* pendo.dom('h1')[0].remove()
|
|
8903
8903
|
* @example
|
|
8904
8904
|
* pendo.dom('.left').css({ 'text-align': 'center' })
|
|
8905
|
-
*/
|
|
8906
|
-
|
|
8907
|
-
*
|
|
8908
|
-
*
|
|
8909
|
-
* @
|
|
8910
|
-
* @
|
|
8911
|
-
* @
|
|
8912
|
-
* @
|
|
8913
|
-
*
|
|
8914
|
-
|
|
8905
|
+
*/
|
|
8906
|
+
/**
|
|
8907
|
+
* Creates new DOM elements from HTML text.
|
|
8908
|
+
*
|
|
8909
|
+
* @param {string} htmlString HTML syntax used to produce new DOM elements
|
|
8910
|
+
* @returns {DomQuery} array with the newly created elements
|
|
8911
|
+
* @access public
|
|
8912
|
+
* @category DOM
|
|
8913
|
+
* @example
|
|
8914
|
+
* pendo.dom('<div><span>this should create an unattached DOM node</span></div>');
|
|
8915
|
+
*/
|
|
8915
8916
|
function dom(selection, context) {
|
|
8916
8917
|
var self = this;
|
|
8917
8918
|
var nodes;
|
|
@@ -9673,7 +9674,7 @@ var objectToQueryString = function (obj) {
|
|
|
9673
9674
|
}, '');
|
|
9674
9675
|
};
|
|
9675
9676
|
/**
|
|
9676
|
-
* URL getter that
|
|
9677
|
+
* URL getter that returns the URL used by the web SDK to describe all data events
|
|
9677
9678
|
* collected for this app and for Guide requests. This URL can differ from the browser's URL based on
|
|
9678
9679
|
* customizations made by the host application. The URL customizations can be learned about [here](https://agent.pendo.io/advanced/location).
|
|
9679
9680
|
*
|
|
@@ -10108,7 +10109,7 @@ var locked = false;
|
|
|
10108
10109
|
* @category Events
|
|
10109
10110
|
* @example
|
|
10110
10111
|
* $ pendo.stopSendingEvents()
|
|
10111
|
-
* > Pendo Web SDK locked.
|
|
10112
|
+
* > Pendo Web SDK locked. No more events will be written.
|
|
10112
10113
|
*/
|
|
10113
10114
|
var lockEvents = function () {
|
|
10114
10115
|
var fireEvent = isUnlocked();
|
|
@@ -10125,7 +10126,7 @@ var lockEvents = function () {
|
|
|
10125
10126
|
* @category Events
|
|
10126
10127
|
* @example
|
|
10127
10128
|
* $ pendo.startSendingEvents()
|
|
10128
|
-
* > Pendo Web SDK unlocked.
|
|
10129
|
+
* > Pendo Web SDK unlocked. Events will be written.
|
|
10129
10130
|
*/
|
|
10130
10131
|
var unlockEvents = function () {
|
|
10131
10132
|
var fireEvent = !isUnlocked();
|
|
@@ -10155,8 +10156,8 @@ var isUnlocked = function () {
|
|
|
10155
10156
|
* Check if the Element has this classname.
|
|
10156
10157
|
*
|
|
10157
10158
|
* @alias hasClass
|
|
10158
|
-
* @param {element}
|
|
10159
|
-
* @param {String}
|
|
10159
|
+
* @param {element} ele The Element to test for the classname
|
|
10160
|
+
* @param {String} cls The classname to look for on the element
|
|
10160
10161
|
* @returns {Boolean}
|
|
10161
10162
|
* @access public
|
|
10162
10163
|
* @category DOM
|
|
@@ -10196,7 +10197,7 @@ var _addClass = function (ele, cls) {
|
|
|
10196
10197
|
}
|
|
10197
10198
|
};
|
|
10198
10199
|
/**
|
|
10199
|
-
* Remove a classname from an
|
|
10200
|
+
* Remove a classname from an Element's classlist.
|
|
10200
10201
|
*
|
|
10201
10202
|
* @alias removeClass
|
|
10202
10203
|
* @param {element} ele The Element from which the class will be removed
|
|
@@ -10219,7 +10220,7 @@ var _removeClass = function (ele, cls) {
|
|
|
10219
10220
|
}
|
|
10220
10221
|
};
|
|
10221
10222
|
/**
|
|
10222
|
-
* Sets the classname
|
|
10223
|
+
* Sets the classname for an Element.
|
|
10223
10224
|
*
|
|
10224
10225
|
* @alias setClass
|
|
10225
10226
|
* @param {element} ele The Element that will get the new classlist.
|
|
@@ -11031,8 +11032,8 @@ DomQuery.$ = {
|
|
|
11031
11032
|
return newDom;
|
|
11032
11033
|
},
|
|
11033
11034
|
/**
|
|
11034
|
-
* Iterate over each element in the DomQuery list and call the
|
|
11035
|
-
*
|
|
11035
|
+
* Iterate over each element in the DomQuery list and call the provided callback function passing in the
|
|
11036
|
+
* element as the argument.
|
|
11036
11037
|
*
|
|
11037
11038
|
* @function each
|
|
11038
11039
|
* @param {function} callback The callback to be called for each element in the list
|
|
@@ -11054,7 +11055,7 @@ DomQuery.$ = {
|
|
|
11054
11055
|
* Iterate over each element in the DomQuery list and create and append the Elements represented by the HTML string provided.
|
|
11055
11056
|
*
|
|
11056
11057
|
* @function html
|
|
11057
|
-
* @param {String}
|
|
11058
|
+
* @param {String} content String representing html to be created as dom Elements for each of the Elements in the list.
|
|
11058
11059
|
* @returns {DomQuery}
|
|
11059
11060
|
* @category DOMQuery
|
|
11060
11061
|
* @access public
|
|
@@ -11075,7 +11076,7 @@ DomQuery.$ = {
|
|
|
11075
11076
|
* Iterate over each element in the DomQuery list and add the text provided as innerText on the element.
|
|
11076
11077
|
*
|
|
11077
11078
|
* @function text
|
|
11078
|
-
* @param {String} content String to be added as innerText
|
|
11079
|
+
* @param {String} content String to be added as innerText.
|
|
11079
11080
|
* @returns {DomQuery}
|
|
11080
11081
|
* @access public
|
|
11081
11082
|
* @category DOMQuery
|
|
@@ -11140,7 +11141,7 @@ DomQuery.$ = {
|
|
|
11140
11141
|
});
|
|
11141
11142
|
},
|
|
11142
11143
|
/**
|
|
11143
|
-
* Iterate over each element and
|
|
11144
|
+
* Iterate over each element and check for each class name. Returns true if all elements have each classname.
|
|
11144
11145
|
*
|
|
11145
11146
|
* @function hasClass
|
|
11146
11147
|
* @param {String} classNames Space separated string of classnames.
|
|
@@ -11163,7 +11164,7 @@ DomQuery.$ = {
|
|
|
11163
11164
|
return allElemsHaveClass;
|
|
11164
11165
|
},
|
|
11165
11166
|
/**
|
|
11166
|
-
* Iterate over each element and toggle each class name on or off depending on
|
|
11167
|
+
* Iterate over each element and toggle each class name on or off depending on
|
|
11167
11168
|
* the current state of the element.
|
|
11168
11169
|
*
|
|
11169
11170
|
* @function toggleClass
|
|
@@ -11191,7 +11192,7 @@ DomQuery.$ = {
|
|
|
11191
11192
|
* Iterate over each element and apply the styles object.
|
|
11192
11193
|
*
|
|
11193
11194
|
* @function css
|
|
11194
|
-
* @param {Object} styles Object containing style
|
|
11195
|
+
* @param {Object} styles Object containing style attribute names and values.
|
|
11195
11196
|
* @returns {DomQuery}
|
|
11196
11197
|
* @access public
|
|
11197
11198
|
* @category DOMQuery
|
|
@@ -11245,7 +11246,7 @@ DomQuery.$ = {
|
|
|
11245
11246
|
return self;
|
|
11246
11247
|
},
|
|
11247
11248
|
/**
|
|
11248
|
-
* Add all elements in the list as
|
|
11249
|
+
* Add all elements in the list as topmost child nodes of the first element found for the given selector.
|
|
11249
11250
|
*
|
|
11250
11251
|
* @function prependTo
|
|
11251
11252
|
* @param {String} selector CSS selector to identify the target parent element
|
|
@@ -11260,10 +11261,10 @@ DomQuery.$ = {
|
|
|
11260
11261
|
return this;
|
|
11261
11262
|
},
|
|
11262
11263
|
/**
|
|
11263
|
-
* Add all children from the selector as
|
|
11264
|
+
* Add all children from the selector as topmost children of the first element in this list.
|
|
11264
11265
|
*
|
|
11265
11266
|
* @function prepend
|
|
11266
|
-
* @param {String} selector CSS selector to identify
|
|
11267
|
+
* @param {String} selector CSS selector to identify topmost child element(s)
|
|
11267
11268
|
* @returns {DomQuery}
|
|
11268
11269
|
* @access public
|
|
11269
11270
|
* @category DOMQuery
|
|
@@ -11287,7 +11288,7 @@ DomQuery.$ = {
|
|
|
11287
11288
|
return self;
|
|
11288
11289
|
},
|
|
11289
11290
|
/**
|
|
11290
|
-
* Return the parent node of the first element in this list
|
|
11291
|
+
* Return the parent node of the first element in this list.
|
|
11291
11292
|
*
|
|
11292
11293
|
* @function getParent
|
|
11293
11294
|
* @returns {element}
|
|
@@ -11304,7 +11305,7 @@ DomQuery.$ = {
|
|
|
11304
11305
|
},
|
|
11305
11306
|
/**
|
|
11306
11307
|
* For the first element in this list, insert the first element from the selector before it
|
|
11307
|
-
* in parent element's child nodes list.
|
|
11308
|
+
* in the parent element's child nodes list.
|
|
11308
11309
|
*
|
|
11309
11310
|
* @function insertBefore
|
|
11310
11311
|
* @param {String} selector CSS selector for the element to be inserted before this element
|
|
@@ -11343,7 +11344,7 @@ DomQuery.$ = {
|
|
|
11343
11344
|
return this;
|
|
11344
11345
|
},
|
|
11345
11346
|
/**
|
|
11346
|
-
* Iterate over each element and set the attribute name to the specified value
|
|
11347
|
+
* Iterate over each element and set the attribute name to the specified value.
|
|
11347
11348
|
*
|
|
11348
11349
|
* @function attr
|
|
11349
11350
|
* @param {String} attrName Name of attribute to set
|
|
@@ -11404,10 +11405,10 @@ DomQuery.$ = {
|
|
|
11404
11405
|
return dom(this[index]);
|
|
11405
11406
|
},
|
|
11406
11407
|
/**
|
|
11407
|
-
* Set the height or unset the height for the first element in the list
|
|
11408
|
+
* Set the height or unset the height for the first element in the list.
|
|
11408
11409
|
*
|
|
11409
11410
|
* @function height
|
|
11410
|
-
* @param {Number} height The new height to set. Undefined will remove the height allow it to auto determined.
|
|
11411
|
+
* @param {Number} height The new height to set. Undefined will remove the height and allow it to be auto determined.
|
|
11411
11412
|
* @returns {DomQuery}
|
|
11412
11413
|
* @access public
|
|
11413
11414
|
* @category DOMQuery
|
|
@@ -11428,10 +11429,10 @@ DomQuery.$ = {
|
|
|
11428
11429
|
}
|
|
11429
11430
|
},
|
|
11430
11431
|
/**
|
|
11431
|
-
* Set the width or unset the width for the first element in the list
|
|
11432
|
+
* Set the width or unset the width for the first element in the list.
|
|
11432
11433
|
*
|
|
11433
11434
|
* @function width
|
|
11434
|
-
* @param {Number} width The new width to set. Undefined will remove the width allow it to auto determined.
|
|
11435
|
+
* @param {Number} width The new width to set. Undefined will remove the width and allow it to be auto determined.
|
|
11435
11436
|
* @returns {DomQuery}
|
|
11436
11437
|
* @access public
|
|
11437
11438
|
* @category DOMQuery
|
|
@@ -11452,7 +11453,7 @@ DomQuery.$ = {
|
|
|
11452
11453
|
}
|
|
11453
11454
|
},
|
|
11454
11455
|
/**
|
|
11455
|
-
* For each element in the list, call the element's focus method if it exists
|
|
11456
|
+
* For each element in the list, call the element's focus method if it exists.
|
|
11456
11457
|
*
|
|
11457
11458
|
* @function focus
|
|
11458
11459
|
* @returns {DomQuery}
|
|
@@ -12203,12 +12204,14 @@ function callLater(callback, n) {
|
|
|
12203
12204
|
*
|
|
12204
12205
|
* @access public
|
|
12205
12206
|
* @category Events
|
|
12206
|
-
* @param {
|
|
12207
|
+
* @param {Object} [options] - Options passed through to each queue's flush method
|
|
12208
|
+
* @param {boolean} [options.unload] - signals the page is unloading; drains the send queue using sendBeacon or sync XHR for reliable last-chance delivery
|
|
12209
|
+
* @param {boolean} [options.hidden] - signals the page is being hidden; drains the send queue immediately rather than waiting for the next timer tick
|
|
12207
12210
|
* @returns {void}
|
|
12208
12211
|
* @example
|
|
12209
12212
|
* pendo.flushNow()
|
|
12210
12213
|
*/
|
|
12211
|
-
function flushNow(
|
|
12214
|
+
function flushNow(options) {
|
|
12212
12215
|
try {
|
|
12213
12216
|
_.each(queues, function (queue) {
|
|
12214
12217
|
if (queue.flush) {
|
|
@@ -12221,14 +12224,14 @@ function flushNow(force, options) {
|
|
|
12221
12224
|
}
|
|
12222
12225
|
}
|
|
12223
12226
|
/*
|
|
12224
|
-
* Queue
|
|
12225
|
-
*
|
|
12227
|
+
* Queue {flushNow} for {n} ticks of the event loop, deferring CPU-intensive
|
|
12228
|
+
* compression until the main thread is free.
|
|
12226
12229
|
*/
|
|
12227
12230
|
function flushLater(n) {
|
|
12228
|
-
return callLater(
|
|
12231
|
+
return callLater(flushNow, n);
|
|
12229
12232
|
}
|
|
12230
12233
|
/**
|
|
12231
|
-
* Force a full flush
|
|
12234
|
+
* Force a full flush on {n} ticks
|
|
12232
12235
|
*
|
|
12233
12236
|
* @access private
|
|
12234
12237
|
* @param {number} n ticks to call {flushNow} on
|
|
@@ -12470,6 +12473,22 @@ class SendQueue {
|
|
|
12470
12473
|
|
|
12471
12474
|
const UNSENT_EVENTS_KEY = 'unsentEvents';
|
|
12472
12475
|
const UNSENT_EVENTS_MAX_AGE = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
12476
|
+
function mergeEvents(target, source) {
|
|
12477
|
+
_.each(source, (requests, key) => {
|
|
12478
|
+
target[key] = (target[key] || []).concat(requests);
|
|
12479
|
+
});
|
|
12480
|
+
return target;
|
|
12481
|
+
}
|
|
12482
|
+
function migrateLegacyCookieEvents(events) {
|
|
12483
|
+
const cookieValue = get_pendo_cookie(UNSENT_EVENTS_KEY);
|
|
12484
|
+
if (cookieValue) {
|
|
12485
|
+
try {
|
|
12486
|
+
mergeEvents(events, JSON.parse(cookieValue));
|
|
12487
|
+
}
|
|
12488
|
+
catch (e) { }
|
|
12489
|
+
clearCookie(getPendoCookieKey(UNSENT_EVENTS_KEY));
|
|
12490
|
+
}
|
|
12491
|
+
}
|
|
12473
12492
|
class LocalStorageEventBuffer {
|
|
12474
12493
|
constructor() {
|
|
12475
12494
|
this.events = {};
|
|
@@ -12492,7 +12511,7 @@ class LocalStorageEventBuffer {
|
|
|
12492
12511
|
}
|
|
12493
12512
|
read(storage) {
|
|
12494
12513
|
/**
|
|
12495
|
-
* If enabled, Pendo will write pending events to
|
|
12514
|
+
* If enabled, Pendo will write pending events to localStorage before unloading the page
|
|
12496
12515
|
* rather than attempting to send them. The events will be sent the next time the page is loaded.
|
|
12497
12516
|
*
|
|
12498
12517
|
* @name _pendo_unsentEvents
|
|
@@ -12500,14 +12519,18 @@ class LocalStorageEventBuffer {
|
|
|
12500
12519
|
* @access public
|
|
12501
12520
|
* @label UNSENT_EVENTS_KEY
|
|
12502
12521
|
*/
|
|
12503
|
-
storage.registry.addLocal(UNSENT_EVENTS_KEY
|
|
12522
|
+
storage.registry.addLocal(UNSENT_EVENTS_KEY, {
|
|
12523
|
+
localStorageOnly: true,
|
|
12524
|
+
duration: UNSENT_EVENTS_MAX_AGE
|
|
12525
|
+
});
|
|
12504
12526
|
try {
|
|
12505
12527
|
this.events = JSON.parse(storage.read(UNSENT_EVENTS_KEY) || '{}');
|
|
12506
|
-
storage.clear(UNSENT_EVENTS_KEY);
|
|
12507
12528
|
}
|
|
12508
12529
|
catch (e) {
|
|
12509
12530
|
this.events = {};
|
|
12510
12531
|
}
|
|
12532
|
+
migrateLegacyCookieEvents(this.events);
|
|
12533
|
+
storage.clear(UNSENT_EVENTS_KEY);
|
|
12511
12534
|
}
|
|
12512
12535
|
write(storage) {
|
|
12513
12536
|
if (_.size(this.events) > 0) {
|
|
@@ -13408,6 +13431,7 @@ var makeSafe = function (method, noLogging) {
|
|
|
13408
13431
|
* @function
|
|
13409
13432
|
* @category URL
|
|
13410
13433
|
* @param {string} [url] if not provided, defaults to the current URL from the browser
|
|
13434
|
+
* @returns {boolean | undefined} true if the URL changed and a load event was sent, otherwise undefined
|
|
13411
13435
|
* @example
|
|
13412
13436
|
* pendo.pageLoad()
|
|
13413
13437
|
*/
|
|
@@ -13447,7 +13471,7 @@ pageLoad.reset = function () {
|
|
|
13447
13471
|
|
|
13448
13472
|
/**
|
|
13449
13473
|
* Returns the normalized URL sent from the backend. This won't always
|
|
13450
|
-
* match the desired output from the customer's
|
|
13474
|
+
* match the desired output from the customer's URL customizations if using the location API.
|
|
13451
13475
|
*
|
|
13452
13476
|
* @access public
|
|
13453
13477
|
* @category URL
|
|
@@ -13574,13 +13598,13 @@ function createChannelMatcher(options = {}) {
|
|
|
13574
13598
|
}
|
|
13575
13599
|
/**
|
|
13576
13600
|
* Returns an array of all guides available on the current page to the current user.
|
|
13577
|
-
* If multiple frames on a
|
|
13601
|
+
* If there are multiple frames on a page, `pendo.getActiveGuides()` will return the list of eligible
|
|
13578
13602
|
* guides across all frames. If no frames, this will be the same as `pendo.guides`.
|
|
13579
13603
|
*
|
|
13580
13604
|
* @access public
|
|
13581
13605
|
* @category Guides
|
|
13582
|
-
* @param {object} options - Options for filtering guides
|
|
13583
|
-
* @param {string} options.channel - Channel to filter guides by
|
|
13606
|
+
* @param {object} [options] - Options for filtering guides
|
|
13607
|
+
* @param {string} [options.channel] - Channel to filter guides by
|
|
13584
13608
|
* @returns {Guide[]}
|
|
13585
13609
|
* @example
|
|
13586
13610
|
* pendo.getActiveGuides() => [{ Pendo Guide Object }, ...]
|
|
@@ -13642,7 +13666,7 @@ function findGuideBy(field, value) {
|
|
|
13642
13666
|
*
|
|
13643
13667
|
* @access public
|
|
13644
13668
|
* @category Guides
|
|
13645
|
-
* @param {string}
|
|
13669
|
+
* @param {string} guideId id of the guide as a string
|
|
13646
13670
|
* @returns {Guide | null} JSON guide object or null if no guide found
|
|
13647
13671
|
* @example
|
|
13648
13672
|
* pendo.findGuideById('guide_id')
|
|
@@ -18239,7 +18263,7 @@ var updateVisitorOptions = function (options = {}) {
|
|
|
18239
18263
|
};
|
|
18240
18264
|
};
|
|
18241
18265
|
/**
|
|
18242
|
-
* Updates metadata object for the Pendo Web SDK. Can include visitor and/or account updates, along
|
|
18266
|
+
* Updates the metadata object for the Pendo Web SDK. Can include visitor and/or account updates, along
|
|
18243
18267
|
* with customer-defined metadata values. Changes to identity information will potentially fire
|
|
18244
18268
|
* identity and metadata events, in turn evaluating guide eligibility for the new user and displaying
|
|
18245
18269
|
* any matching guides automatically.
|
|
@@ -18257,11 +18281,11 @@ var updateOptions = makeSafe(function (options) {
|
|
|
18257
18281
|
});
|
|
18258
18282
|
/**
|
|
18259
18283
|
* This function accepts either a string for just the visitor id or it accepts an Object that will contain at least
|
|
18260
|
-
* a visitor object with at least an id field.
|
|
18261
|
-
* visitor object. Also,
|
|
18262
|
-
* also contain other account
|
|
18284
|
+
* a visitor object with at least an id field. It may also contain other visitor-related Key/Value pairs in the
|
|
18285
|
+
* visitor object. Also, the options object may contain an account object that will contain at least an id field. It may
|
|
18286
|
+
* also contain other account-related Key/Value pairs. This will potentially send an identify event and a metadata event.
|
|
18263
18287
|
*
|
|
18264
|
-
* Identifying a visitor will send an event to Pendo and begin loading eligible guides
|
|
18288
|
+
* Identifying a visitor will send an event to Pendo and begin loading eligible guides for the identified user. To remove
|
|
18265
18289
|
* visitor identity use `pendo.clearSession()`.
|
|
18266
18290
|
*
|
|
18267
18291
|
* @access public
|
|
@@ -20677,7 +20701,7 @@ var clearLoopTimer = function () {
|
|
|
20677
20701
|
store.dispatch('guideUpdate/stopScheduledUpdate');
|
|
20678
20702
|
};
|
|
20679
20703
|
/**
|
|
20680
|
-
*
|
|
20704
|
+
* Clears any showing guides and prevents any loaded guides from rendering.
|
|
20681
20705
|
* Loaded guides remain in memory, so calling startGuides will work just fine
|
|
20682
20706
|
* after a stopGuides call.
|
|
20683
20707
|
*
|
|
@@ -20700,7 +20724,7 @@ var stopGuides = function () {
|
|
|
20700
20724
|
};
|
|
20701
20725
|
/**
|
|
20702
20726
|
* Starts the process that loops over all currently loaded guides and
|
|
20703
|
-
* determines what to show. Checks
|
|
20727
|
+
* determines what to show. Checks multi-step guide continuation,
|
|
20704
20728
|
* auto-display guides, launcher guides, and badges.
|
|
20705
20729
|
*
|
|
20706
20730
|
* @access public
|
|
@@ -21968,12 +21992,12 @@ function interceptPreventDefault(EventConstructor, eventList) {
|
|
|
21968
21992
|
*
|
|
21969
21993
|
* @access public
|
|
21970
21994
|
* @category Events
|
|
21971
|
-
* @param {HTMLElement} element DOM element to attach listener
|
|
21995
|
+
* @param {HTMLElement} element DOM element to attach listener to
|
|
21972
21996
|
* @param {string} evt type of DOM event
|
|
21973
21997
|
* @param {Function} fn callback function
|
|
21974
21998
|
* @param {Boolean} useCapture use capture phase instead of bubble
|
|
21975
21999
|
* @example
|
|
21976
|
-
* pendo.attachEvent(pendo.dom("h1")[0], 'click', helloWorld = () => { console.log(Hello World") });
|
|
22000
|
+
* pendo.attachEvent(pendo.dom("h1")[0], 'click', helloWorld = () => { console.log("Hello World") });
|
|
21977
22001
|
*/
|
|
21978
22002
|
function attachEvent(element, evt, fn, useCapture) {
|
|
21979
22003
|
if (!(element && evt && fn)) {
|
|
@@ -21989,12 +22013,12 @@ function attachEvent(element, evt, fn, useCapture) {
|
|
|
21989
22013
|
});
|
|
21990
22014
|
}
|
|
21991
22015
|
/**
|
|
21992
|
-
* Pendo Web SDK's version of detaching event listeners.
|
|
21993
|
-
*
|
|
22016
|
+
* Pendo Web SDK's version of detaching event listeners. The callback must be a named function; anonymous
|
|
22017
|
+
* functions cannot be removed.
|
|
21994
22018
|
*
|
|
21995
22019
|
* @access public
|
|
21996
22020
|
* @category Events
|
|
21997
|
-
* @param {HTMLElement} element DOM element to
|
|
22021
|
+
* @param {HTMLElement} element DOM element to detach listener from
|
|
21998
22022
|
* @param {string} evt type of DOM event
|
|
21999
22023
|
* @param {Function} fn callback function
|
|
22000
22024
|
* @param {Boolean} useCapture use capture phase instead of bubble
|
|
@@ -22975,7 +22999,7 @@ function advanceGuide(eventType, step, pendo) {
|
|
|
22975
22999
|
step.attachEvent(btn, eventType, onEvent);
|
|
22976
23000
|
}
|
|
22977
23001
|
function attachBBAdvanceActions(step, pendo) {
|
|
22978
|
-
let advanceActions = pendo._.get(step, 'attributes.advanceActions', {});
|
|
23002
|
+
let advanceActions = pendo._.get(step, 'attributes.advanceActions', {}) || {};
|
|
22979
23003
|
if (advanceActions.elementHover) {
|
|
22980
23004
|
advanceGuide('mouseover', step, pendo);
|
|
22981
23005
|
}
|
|
@@ -23303,7 +23327,7 @@ var controlGuideLogMessage = 'Guide was not shown because this visitor is in a c
|
|
|
23303
23327
|
/**
|
|
23304
23328
|
* @constant defaultCssUrl {String}
|
|
23305
23329
|
*
|
|
23306
|
-
* Readonly
|
|
23330
|
+
* Readonly property that provides the default CSS URL based on the customer's Apps configuration with Pendo.
|
|
23307
23331
|
*
|
|
23308
23332
|
* @access public
|
|
23309
23333
|
* @category Guides
|
|
@@ -23398,7 +23422,7 @@ var getStepIdFromElement = function (element) {
|
|
|
23398
23422
|
* In most cases, `pendo.stopGuides()` is preferred since it will stop the loop and guides will not redisplay until `pendo.startGuides()` is called.
|
|
23399
23423
|
*
|
|
23400
23424
|
* Manually hide any active Guides. An argument of an Object containing the property stayHidden set to true needs to be
|
|
23401
|
-
* provided in order for the guides
|
|
23425
|
+
* provided in order for the hidden guides to stay hidden.
|
|
23402
23426
|
*
|
|
23403
23427
|
* @param {Object} - Optional JS Object containing boolean property `stayHidden`
|
|
23404
23428
|
* @access public
|
|
@@ -23481,7 +23505,7 @@ function shouldAffectThrottling(guide, seenReason) {
|
|
|
23481
23505
|
* Hides the current guide and invokes the `guideDismissed` event. Dismissed guides will not
|
|
23482
23506
|
* be re-displayed by default unless they have a recurrence setting or can be reactivated
|
|
23483
23507
|
* with an element. They can always be redisplayed via onGuideAdvanced or onGuidePrevious.
|
|
23484
|
-
|
|
23508
|
+
*
|
|
23485
23509
|
* @access public
|
|
23486
23510
|
* @category Guides
|
|
23487
23511
|
* @example
|
|
@@ -23545,7 +23569,7 @@ var onGuideDismissed = function (evt, step) {
|
|
|
23545
23569
|
};
|
|
23546
23570
|
/**
|
|
23547
23571
|
* Snoozes the current guide. If another guide is eligible to be shown automatically, it will show after snooze.
|
|
23548
|
-
*
|
|
23572
|
+
* The guide will redisplay after one day by default, or a custom `snoozeDuration` can be set in milliseconds as the third argument.
|
|
23549
23573
|
*
|
|
23550
23574
|
* @access public
|
|
23551
23575
|
* @category Guides
|
|
@@ -23660,7 +23684,7 @@ var goToStep = function (evt) {
|
|
|
23660
23684
|
};
|
|
23661
23685
|
/**
|
|
23662
23686
|
* Proceeds to the next step in a multi-step guide and sends a `guideAdvanced` event.
|
|
23663
|
-
* Can
|
|
23687
|
+
* Can advance multiple steps or beyond a specific step by passing optional parameters.
|
|
23664
23688
|
* Lastly, sends a `guideSeen` event for the resulting displayed step.
|
|
23665
23689
|
*
|
|
23666
23690
|
* @access public
|
|
@@ -24222,7 +24246,7 @@ var getNextStepInMultistep = function (lastSeen, urlToCheck) {
|
|
|
24222
24246
|
};
|
|
24223
24247
|
/**
|
|
24224
24248
|
* Returns the normalized URL sent from the backend with the guides payload. This won't always
|
|
24225
|
-
* match the desired output from the customer's
|
|
24249
|
+
* match the desired output from the customer's URL customizations if using the location API.
|
|
24226
24250
|
*
|
|
24227
24251
|
* @access public
|
|
24228
24252
|
* @alias getCurrentUrl
|
|
@@ -24234,6 +24258,7 @@ var getNextStepInMultistep = function (lastSeen, urlToCheck) {
|
|
|
24234
24258
|
* pendo.normalizedUrl
|
|
24235
24259
|
* @example
|
|
24236
24260
|
* pendo.getCurrentUrl()
|
|
24261
|
+
*/
|
|
24237
24262
|
/**
|
|
24238
24263
|
* Activates the Guide for the given name, if loaded. If it is not in the payload,
|
|
24239
24264
|
* this function will return false.
|
|
@@ -24241,7 +24266,7 @@ var getNextStepInMultistep = function (lastSeen, urlToCheck) {
|
|
|
24241
24266
|
* @access public
|
|
24242
24267
|
* @category Guides
|
|
24243
24268
|
* @param {string} name name of the guide to display
|
|
24244
|
-
* @param {string} reason optional reason for the display
|
|
24269
|
+
* @param {string} [reason] optional reason for the display
|
|
24245
24270
|
* @example
|
|
24246
24271
|
* pendo.showGuideByName('guide_name')
|
|
24247
24272
|
*/
|
|
@@ -24263,7 +24288,7 @@ var showGuideByName = function (name, reason) {
|
|
|
24263
24288
|
* @access public
|
|
24264
24289
|
* @category Guides
|
|
24265
24290
|
* @param {string} id id of the guide to display
|
|
24266
|
-
* @param {string} reason optional reason for the display
|
|
24291
|
+
* @param {string} [reason] optional reason for the display
|
|
24267
24292
|
* @example
|
|
24268
24293
|
* pendo.showGuideById('guide_id')
|
|
24269
24294
|
*/
|
|
@@ -24290,7 +24315,7 @@ var resetPendoUI = function () {
|
|
|
24290
24315
|
*
|
|
24291
24316
|
* @access public
|
|
24292
24317
|
* @name doNotProcess
|
|
24293
|
-
* @type {
|
|
24318
|
+
* @type {boolean}
|
|
24294
24319
|
* @category Events
|
|
24295
24320
|
* @example
|
|
24296
24321
|
* pendo.doNotProcess => true
|
|
@@ -24515,8 +24540,8 @@ function shouldLoadGuides(visitorId, callback) {
|
|
|
24515
24540
|
return true;
|
|
24516
24541
|
}
|
|
24517
24542
|
/**
|
|
24518
|
-
* Manually load guides for current visitor and URL. This is typically handled automatically by the web SDK
|
|
24519
|
-
* whenever the host Application changes its URL. In rare circumstances, a host Application may
|
|
24543
|
+
* Manually load guides for the current visitor and URL. This is typically handled automatically by the web SDK
|
|
24544
|
+
* whenever the host Application changes its URL. In rare circumstances, a host Application may choose to
|
|
24520
24545
|
* force the load of Guides programmatically. One reason may be in order to get any guides designed for a visitor
|
|
24521
24546
|
* immediately after using a specific part of the Application that doesn't cause a URL change.
|
|
24522
24547
|
*
|
|
@@ -24818,7 +24843,7 @@ function securityPolicyViolationFn(evt) {
|
|
|
24818
24843
|
}
|
|
24819
24844
|
let guideCache;
|
|
24820
24845
|
/**
|
|
24821
|
-
* Resets and starts guide loop
|
|
24846
|
+
* Resets and starts the guide loop.
|
|
24822
24847
|
*
|
|
24823
24848
|
* @access public
|
|
24824
24849
|
* @category Guides
|
|
@@ -24924,7 +24949,7 @@ var initGuides = function (observer) {
|
|
|
24924
24949
|
*/
|
|
24925
24950
|
agentStorage.registry.addLocal(THROTTLING_STATE.SNOOZED);
|
|
24926
24951
|
/**
|
|
24927
|
-
* Used to determine if guides have been blocked
|
|
24952
|
+
* Used to determine if guides have been blocked by the user, an ad blocker, or a failed guide request.
|
|
24928
24953
|
* This will prevent additional guide requests and display attempts, to optimize page performance and
|
|
24929
24954
|
* user experience in cases where guides cannot be loaded.
|
|
24930
24955
|
*
|
|
@@ -24950,7 +24975,7 @@ var initGuides = function (observer) {
|
|
|
24950
24975
|
};
|
|
24951
24976
|
};
|
|
24952
24977
|
/**
|
|
24953
|
-
* Returns true or false
|
|
24978
|
+
* Returns true or false depending on whether the client has disabled guides in the snippet or via a command.
|
|
24954
24979
|
*
|
|
24955
24980
|
* @access public
|
|
24956
24981
|
* @category Guides
|
|
@@ -24962,7 +24987,7 @@ var areGuidesDisabled = function () {
|
|
|
24962
24987
|
return ConfigReader.get('guides.disabled', false) || !pendoCore;
|
|
24963
24988
|
};
|
|
24964
24989
|
/**
|
|
24965
|
-
* Returns true or false
|
|
24990
|
+
* Returns true or false depending on whether the client has delayed guides in the snippet or via a command.
|
|
24966
24991
|
*
|
|
24967
24992
|
* @access public
|
|
24968
24993
|
* @category Guides
|
|
@@ -26418,7 +26443,7 @@ function insertOriginContentHash(originalHash, url, extensionStr, sha256Hash) {
|
|
|
26418
26443
|
}
|
|
26419
26444
|
|
|
26420
26445
|
/**
|
|
26421
|
-
* Formerly `apiKey`.
|
|
26446
|
+
* Formerly `apiKey`. The public app ID associated with the current Pendo installation as a string.
|
|
26422
26447
|
*
|
|
26423
26448
|
* @access public
|
|
26424
26449
|
* @name publicAppId
|
|
@@ -26428,7 +26453,7 @@ function insertOriginContentHash(originalHash, url, extensionStr, sha256Hash) {
|
|
|
26428
26453
|
* pendo.publicAppId => 'PUBLIC_APP_ID'
|
|
26429
26454
|
*/
|
|
26430
26455
|
/**
|
|
26431
|
-
* Formerly `additionalApiKeys`.
|
|
26456
|
+
* Formerly `additionalApiKeys`. An array of additional app IDs that are set in the config. If no primary app ID is set,
|
|
26432
26457
|
* the first in this array will be assigned to `pendo.publicAppId`.
|
|
26433
26458
|
*
|
|
26434
26459
|
* @access public
|
|
@@ -27197,7 +27222,7 @@ var P2AutoLaunch = (function () {
|
|
|
27197
27222
|
function launchDesignerOrPreview(options) {
|
|
27198
27223
|
/**
|
|
27199
27224
|
* Application state while viewing a guide in preview mode. Used while preview mode is active
|
|
27200
|
-
* to track step, status, etc
|
|
27225
|
+
* to track step, status, etc., and cleared when preview mode is exited.
|
|
27201
27226
|
*
|
|
27202
27227
|
* @name pendo-preview
|
|
27203
27228
|
* @category Cookies/localStorage
|
|
@@ -27207,7 +27232,7 @@ function launchDesignerOrPreview(options) {
|
|
|
27207
27232
|
agentStorage.registry.addLocal(pendoPreview$1);
|
|
27208
27233
|
/**
|
|
27209
27234
|
* Application state while previewing a guide from the designer. Used while designer preview is active
|
|
27210
|
-
* to track step, status, etc
|
|
27235
|
+
* to track step, status, etc., and cleared when designer preview is exited.
|
|
27211
27236
|
*
|
|
27212
27237
|
* @name current-guide-preview
|
|
27213
27238
|
* @category Cookies/localStorage
|
|
@@ -28762,7 +28787,7 @@ var ResourceCenterActivity = (function () {
|
|
|
28762
28787
|
})();
|
|
28763
28788
|
|
|
28764
28789
|
/**
|
|
28765
|
-
* Returns boolean representing whether the Pendo Web SDK is fully loaded and has an API key.
|
|
28790
|
+
* Returns a boolean representing whether the Pendo Web SDK is fully loaded and has an API key.
|
|
28766
28791
|
*
|
|
28767
28792
|
* @access public
|
|
28768
28793
|
* @category Core
|
|
@@ -28977,7 +29002,7 @@ const initializeImmediately = 'initializeImmediately';
|
|
|
28977
29002
|
* @function
|
|
28978
29003
|
* @category Core
|
|
28979
29004
|
* @name initialize
|
|
28980
|
-
* @param {object} options identity metadata and configuration to initialize web SDK
|
|
29005
|
+
* @param {object} options identity metadata and configuration to initialize the web SDK
|
|
28981
29006
|
* @see {@link https://support.pendo.io/hc/en-us/articles/360046272771-Developer-s-guide-to-installing-Pendo#what-installation-involves-0-2 | Pendo Installation}
|
|
28982
29007
|
* @example
|
|
28983
29008
|
* pendo.initialize({
|
|
@@ -29080,7 +29105,7 @@ function initialize(options) {
|
|
|
29080
29105
|
teardownFns.push(() => observer.teardown());
|
|
29081
29106
|
if (pendoCore) {
|
|
29082
29107
|
/**
|
|
29083
|
-
* Current visitor id for
|
|
29108
|
+
* Current visitor id for the Pendo installation, either anonymous or identified. Used to determine
|
|
29084
29109
|
* a visitor's guide experience, settings, and associated data.
|
|
29085
29110
|
*
|
|
29086
29111
|
* @name _pendo_visitorId
|
|
@@ -29090,7 +29115,7 @@ function initialize(options) {
|
|
|
29090
29115
|
*/
|
|
29091
29116
|
agentStorage.registry.addLocal(VISITOR_ID_KEY);
|
|
29092
29117
|
/**
|
|
29093
|
-
* Often an anonymous visitor id that is replaced by a logged
|
|
29118
|
+
* Often an anonymous visitor id that is replaced by a logged-in user.
|
|
29094
29119
|
*
|
|
29095
29120
|
* @name _pendo_oldVisitorId
|
|
29096
29121
|
* @category Cookies/localStorage
|
|
@@ -29099,7 +29124,7 @@ function initialize(options) {
|
|
|
29099
29124
|
*/
|
|
29100
29125
|
agentStorage.registry.addLocal(OLD_VISITOR_ID_KEY);
|
|
29101
29126
|
/**
|
|
29102
|
-
* The current account id for
|
|
29127
|
+
* The current account id for the Pendo installation provided in the `pendo.initialize()` call.
|
|
29103
29128
|
*
|
|
29104
29129
|
* @name _pendo_accountId
|
|
29105
29130
|
* @category Cookies/localStorage
|
|
@@ -29135,12 +29160,12 @@ function initialize(options) {
|
|
|
29135
29160
|
teardownFns.push(performanceMonitor.initialize());
|
|
29136
29161
|
}
|
|
29137
29162
|
const flushOnAppHidden = () => {
|
|
29138
|
-
flushNow(
|
|
29163
|
+
flushNow({ hidden: true });
|
|
29139
29164
|
};
|
|
29140
29165
|
Events.appHidden.on(flushOnAppHidden);
|
|
29141
29166
|
teardownFns.push(() => Events.appHidden.off(flushOnAppHidden));
|
|
29142
29167
|
const flushOnAppUnloaded = () => {
|
|
29143
|
-
flushNow(
|
|
29168
|
+
flushNow({ unload: true });
|
|
29144
29169
|
if (localStorageUnloadEnabled) {
|
|
29145
29170
|
localStorageEventBuffer.write(agentStorage);
|
|
29146
29171
|
}
|
|
@@ -29756,13 +29781,20 @@ var BuildingBlockGuides = (function () {
|
|
|
29756
29781
|
detachEvent(targetElement, 'focus', targetElementFocusCallback);
|
|
29757
29782
|
});
|
|
29758
29783
|
}
|
|
29784
|
+
function getTargetElementForStep(step) {
|
|
29785
|
+
if (step.element && step.element !== getBody()) {
|
|
29786
|
+
return step.element;
|
|
29787
|
+
}
|
|
29788
|
+
return null;
|
|
29789
|
+
}
|
|
29759
29790
|
function trapFocusStep(step, guideContainer) {
|
|
29760
|
-
var
|
|
29761
|
-
|
|
29791
|
+
var guideContainerElement = guideContainer.find('#pendo-guide-container');
|
|
29792
|
+
var targetElement = _.get(step, 'attributes.blockOutUI.enabled') && getTargetElementForStep(step);
|
|
29793
|
+
trapFocus(guideContainerElement, targetElement);
|
|
29762
29794
|
}
|
|
29763
29795
|
function getSelectedPollElementForFocus(focusableChildren, bumperElement) {
|
|
29764
29796
|
let elementToFocus;
|
|
29765
|
-
if (bumperElement.getAttribute('type') === 'radio') {
|
|
29797
|
+
if (bumperElement.getAttribute('type') === 'radio' && bumperElement.getAttribute('data-pendo-poll-id')) {
|
|
29766
29798
|
const pollId = bumperElement.getAttribute('data-pendo-poll-id');
|
|
29767
29799
|
elementToFocus = _.find(focusableChildren, function (child) {
|
|
29768
29800
|
const childPollId = child.getAttribute('data-pendo-poll-id');
|
|
@@ -29771,8 +29803,42 @@ var BuildingBlockGuides = (function () {
|
|
|
29771
29803
|
}
|
|
29772
29804
|
return elementToFocus || bumperElement;
|
|
29773
29805
|
}
|
|
29774
|
-
function
|
|
29775
|
-
|
|
29806
|
+
function collectTargetFocusables(targetElement) {
|
|
29807
|
+
if (!targetElement)
|
|
29808
|
+
return [];
|
|
29809
|
+
var focusables = _.toArray(targetElement.querySelectorAll(FOCUSABLE_SELECTORS));
|
|
29810
|
+
if (targetElement.matches(FOCUSABLE_SELECTORS)) {
|
|
29811
|
+
focusables.unshift(targetElement);
|
|
29812
|
+
}
|
|
29813
|
+
return focusables;
|
|
29814
|
+
}
|
|
29815
|
+
function createTargetBumper(className) {
|
|
29816
|
+
var bumper = document.createElement('div');
|
|
29817
|
+
bumper.setAttribute('tabIndex', 0);
|
|
29818
|
+
bumper.setAttribute('class', className);
|
|
29819
|
+
bumper.setAttribute('aria-hidden', 'true');
|
|
29820
|
+
bumper.style.cssText = 'position:absolute !important;width:0 !important;height:0 !important;overflow:hidden !important;outline:none !important;border:none !important;padding:0 !important;margin:0 !important;';
|
|
29821
|
+
return bumper;
|
|
29822
|
+
}
|
|
29823
|
+
function insertTargetBumpers(targetElement) {
|
|
29824
|
+
if (!targetElement || !targetElement.parentNode)
|
|
29825
|
+
return null;
|
|
29826
|
+
var before = createTargetBumper('pendo-before-target-focus-bumper');
|
|
29827
|
+
var after = createTargetBumper('pendo-after-target-focus-bumper');
|
|
29828
|
+
targetElement.parentNode.insertBefore(before, targetElement);
|
|
29829
|
+
targetElement.parentNode.insertBefore(after, targetElement.nextSibling);
|
|
29830
|
+
return { before, after };
|
|
29831
|
+
}
|
|
29832
|
+
function removeTargetBumpers(targetBumpers) {
|
|
29833
|
+
if (!targetBumpers)
|
|
29834
|
+
return;
|
|
29835
|
+
_.each([targetBumpers.before, targetBumpers.after], function (bumper) {
|
|
29836
|
+
if (bumper && bumper.parentNode)
|
|
29837
|
+
bumper.parentNode.removeChild(bumper);
|
|
29838
|
+
});
|
|
29839
|
+
}
|
|
29840
|
+
function trapFocus(guideContainerElement, targetElement) {
|
|
29841
|
+
var containerNode = guideContainerElement[0];
|
|
29776
29842
|
if (!containerNode) {
|
|
29777
29843
|
return;
|
|
29778
29844
|
}
|
|
@@ -29792,43 +29858,75 @@ var BuildingBlockGuides = (function () {
|
|
|
29792
29858
|
// some quirks
|
|
29793
29859
|
'iframe'
|
|
29794
29860
|
].join(', ');
|
|
29795
|
-
var focusableChildren = _.toArray(
|
|
29861
|
+
var focusableChildren = _.toArray(guideContainerElement.find(selectors));
|
|
29796
29862
|
if (!focusableChildren.length) {
|
|
29797
29863
|
return;
|
|
29798
29864
|
}
|
|
29799
29865
|
var firstFocusableEl = focusableChildren[0];
|
|
29800
29866
|
var lastFocusableEl = focusableChildren[focusableChildren.length - 1];
|
|
29801
29867
|
// insert bumpers after the above selectors run for content
|
|
29802
|
-
var bumpers = insertTrapFocusBumpers(
|
|
29868
|
+
var bumpers = insertTrapFocusBumpers(guideContainerElement);
|
|
29803
29869
|
var startFocusBumper = bumpers[0];
|
|
29804
29870
|
var endFocusBumper = bumpers[1];
|
|
29871
|
+
var targetFocusables = collectTargetFocusables(targetElement);
|
|
29872
|
+
var firstTargetFocusable = targetFocusables[0];
|
|
29873
|
+
var lastTargetFocusable = targetFocusables[targetFocusables.length - 1];
|
|
29874
|
+
// Insert bumpers as siblings of the target so we can catch focus crossings even when focus moves through a
|
|
29875
|
+
// cross-origin iframe inside the target (our keydown listener can't see events inside the iframe, but it can
|
|
29876
|
+
// see focus landing on a bumper in the parent document afterwards).
|
|
29877
|
+
var targetBumpers = targetFocusables.length ? insertTargetBumpers(targetElement) : null;
|
|
29878
|
+
var beforeTargetBumper = targetBumpers && targetBumpers.before;
|
|
29879
|
+
var afterTargetBumper = targetBumpers && targetBumpers.after;
|
|
29880
|
+
var targetRoot = targetElement && dom.getRootNode(targetElement);
|
|
29881
|
+
var wrapForward = firstTargetFocusable || firstFocusableEl;
|
|
29882
|
+
var wrapBackward = lastTargetFocusable || lastFocusableEl;
|
|
29805
29883
|
var trapFocusCallback = function (e) {
|
|
29806
|
-
|
|
29807
|
-
var isShiftPressed = e.shiftKey;
|
|
29808
|
-
if (!isTabPressed) {
|
|
29884
|
+
if (!isTabEvent(e)) {
|
|
29809
29885
|
return;
|
|
29810
29886
|
}
|
|
29887
|
+
const isShiftPressed = e.shiftKey;
|
|
29888
|
+
const isKeydown = e.type === 'keydown';
|
|
29811
29889
|
// Check if focus is on the body (clicked on the backdrop), the guide container (starts there when guide opens), or on the focus bumpers
|
|
29812
29890
|
const activeElement = dom.getRootNode(containerNode).activeElement;
|
|
29813
29891
|
const containerActive = activeElement === containerNode;
|
|
29814
29892
|
const bodyActive = document.activeElement === document.body; // if the guide is in a shadow root but you click on the backdrop, the active element is the body of the main document
|
|
29815
|
-
|
|
29893
|
+
const startBumperActive = activeElement === startFocusBumper;
|
|
29894
|
+
const endBumperActive = activeElement === endFocusBumper;
|
|
29895
|
+
const targetActiveElement = targetRoot && targetRoot.activeElement;
|
|
29896
|
+
const beforeTargetBumperActive = !!beforeTargetBumper && targetActiveElement === beforeTargetBumper;
|
|
29897
|
+
const afterTargetBumperActive = !!afterTargetBumper && targetActiveElement === afterTargetBumper;
|
|
29898
|
+
const onLastTargetFocusable = isKeydown && !!lastTargetFocusable && targetActiveElement === lastTargetFocusable;
|
|
29899
|
+
const onFirstTargetFocusable = isKeydown && !!firstTargetFocusable && targetActiveElement === firstTargetFocusable;
|
|
29900
|
+
let elementToFocus;
|
|
29816
29901
|
if (isShiftPressed) {
|
|
29817
|
-
|
|
29818
|
-
|
|
29819
|
-
|
|
29820
|
-
elementToFocus
|
|
29821
|
-
|
|
29822
|
-
|
|
29823
|
-
|
|
29902
|
+
if (onFirstTargetFocusable)
|
|
29903
|
+
elementToFocus = lastFocusableEl;
|
|
29904
|
+
else if (beforeTargetBumperActive)
|
|
29905
|
+
elementToFocus = lastFocusableEl;
|
|
29906
|
+
else if (afterTargetBumperActive)
|
|
29907
|
+
elementToFocus = lastTargetFocusable;
|
|
29908
|
+
else if (startBumperActive || containerActive || bodyActive)
|
|
29909
|
+
elementToFocus = wrapBackward;
|
|
29824
29910
|
}
|
|
29825
29911
|
else {
|
|
29826
|
-
|
|
29827
|
-
|
|
29828
|
-
|
|
29829
|
-
elementToFocus
|
|
29830
|
-
|
|
29831
|
-
|
|
29912
|
+
if (onLastTargetFocusable)
|
|
29913
|
+
elementToFocus = firstFocusableEl;
|
|
29914
|
+
else if (afterTargetBumperActive)
|
|
29915
|
+
elementToFocus = firstFocusableEl;
|
|
29916
|
+
else if (beforeTargetBumperActive)
|
|
29917
|
+
elementToFocus = firstTargetFocusable;
|
|
29918
|
+
else if (endBumperActive)
|
|
29919
|
+
elementToFocus = wrapForward;
|
|
29920
|
+
else if (containerActive || bodyActive)
|
|
29921
|
+
elementToFocus = firstFocusableEl;
|
|
29922
|
+
}
|
|
29923
|
+
if (elementToFocus) {
|
|
29924
|
+
const resolved = getSelectedPollElementForFocus(focusableChildren, elementToFocus);
|
|
29925
|
+
resolved.focus();
|
|
29926
|
+
if (dom.getRootNode(resolved).activeElement !== resolved) {
|
|
29927
|
+
(isShiftPressed ? lastFocusableEl : firstFocusableEl).focus();
|
|
29928
|
+
}
|
|
29929
|
+
e.preventDefault();
|
|
29832
29930
|
}
|
|
29833
29931
|
};
|
|
29834
29932
|
// attaching to both events helps some edge cases such as breakout by long-pressing the tab
|
|
@@ -29837,6 +29935,7 @@ var BuildingBlockGuides = (function () {
|
|
|
29837
29935
|
Events.one('unmounted', () => {
|
|
29838
29936
|
detachEvent(document, 'keyup', trapFocusCallback);
|
|
29839
29937
|
detachEvent(document, 'keydown', trapFocusCallback);
|
|
29938
|
+
removeTargetBumpers(targetBumpers);
|
|
29840
29939
|
});
|
|
29841
29940
|
}
|
|
29842
29941
|
// bumpers are divs with a tabindex to allow them to be focused, but which should immediately
|
|
@@ -30056,7 +30155,7 @@ var shouldWeLog = function (contexts) {
|
|
|
30056
30155
|
return (!!logOverride || !!isDebuggingEnabled());
|
|
30057
30156
|
};
|
|
30058
30157
|
/**
|
|
30059
|
-
* Logs
|
|
30158
|
+
* Logs output to the console as the [Pendo Web SDK].
|
|
30060
30159
|
*
|
|
30061
30160
|
* @access public
|
|
30062
30161
|
* @category Debugging
|
|
@@ -30174,12 +30273,12 @@ function collectEventHelper({ type, name, props, eventProperties }) {
|
|
|
30174
30273
|
collectEvent(type, correctedProps, url, name, correctedEventProperties);
|
|
30175
30274
|
}
|
|
30176
30275
|
/**
|
|
30177
|
-
* Method to manually track events. Requires a non-empty name string to collect event.
|
|
30276
|
+
* Method to manually track events. Requires a non-empty name string to collect the event.
|
|
30178
30277
|
*
|
|
30179
30278
|
* @access public
|
|
30180
30279
|
* @category Events
|
|
30181
30280
|
* @param {string} name name of the collected event
|
|
30182
|
-
* @param {Object} [props] optional properties object to collect with
|
|
30281
|
+
* @param {Object} [props] optional properties object to collect with the event
|
|
30183
30282
|
* @param {Object} [eventProperties] optional key-value map stored on the event as top-level event properties
|
|
30184
30283
|
* @example
|
|
30185
30284
|
* pendo.track('scroll')
|
|
@@ -30196,7 +30295,7 @@ const privacyFilterCache = new Map();
|
|
|
30196
30295
|
*
|
|
30197
30296
|
* @access public
|
|
30198
30297
|
* @category Events
|
|
30199
|
-
* @param {string} type type of the collected agentic event
|
|
30298
|
+
* @param {string} type type of the collected agentic event (e.g. 'prompt', 'agent_response', 'user_reaction')
|
|
30200
30299
|
* @param {Object} props event-specific properties object
|
|
30201
30300
|
* @param {Object} [eventProperties] optional key-value map stored on the event as top-level event properties (same as pendo.track)
|
|
30202
30301
|
* @example
|
|
@@ -30272,7 +30371,7 @@ function getCachedRegex(filterPattern) {
|
|
|
30272
30371
|
}
|
|
30273
30372
|
|
|
30274
30373
|
/**
|
|
30275
|
-
* Checks visitor and account metadata in the current Pendo installation. Either logs to console
|
|
30374
|
+
* Checks visitor and account metadata in the current Pendo installation. Either logs to the console
|
|
30276
30375
|
* or returns an array with the results of validation.
|
|
30277
30376
|
*
|
|
30278
30377
|
* @access public
|
|
@@ -30534,7 +30633,7 @@ var validateBuiltInGlobals = function (skipLogging) {
|
|
|
30534
30633
|
}
|
|
30535
30634
|
};
|
|
30536
30635
|
/**
|
|
30537
|
-
* Checks current URL of the browser for customized or sanitized
|
|
30636
|
+
* Checks the current URL of the browser for strings customized or sanitized by the application.
|
|
30538
30637
|
*
|
|
30539
30638
|
* @access public
|
|
30540
30639
|
* @category Validation
|
|
@@ -30623,6 +30722,7 @@ const validatePluginsAndExtensions = (skipLogging) => {
|
|
|
30623
30722
|
*
|
|
30624
30723
|
* @access public
|
|
30625
30724
|
* @category Validation
|
|
30725
|
+
* @param {boolean} [skipLogging] does not log output to console if true, returning the environment object instead
|
|
30626
30726
|
* @example
|
|
30627
30727
|
* pendo.validateEnvironment()
|
|
30628
30728
|
*/
|
|
@@ -31111,7 +31211,7 @@ const DEFAULT_GUIDE_SEEN_TIMEOUT_LENGTH = 10000;
|
|
|
31111
31211
|
* @constant guideSeenTimeoutLength {number}
|
|
31112
31212
|
*
|
|
31113
31213
|
* Readonly number that indicates how long a guide will try to show before sending an error.
|
|
31114
|
-
* Defaults to 10 seconds.
|
|
31214
|
+
* Defaults to 10 seconds (10000 ms).
|
|
31115
31215
|
*
|
|
31116
31216
|
* @access public
|
|
31117
31217
|
* @category Guides
|
|
@@ -31229,9 +31329,7 @@ function exportPublicApi(pendo) {
|
|
|
31229
31329
|
pendo.VERSION = VERSION;
|
|
31230
31330
|
pendo.LOADER = LOADER;
|
|
31231
31331
|
// cache.js
|
|
31232
|
-
pendo.flushNow = exportPendoCoreOnly(
|
|
31233
|
-
return flushNow(true, options);
|
|
31234
|
-
});
|
|
31332
|
+
pendo.flushNow = exportPendoCoreOnly(flushNow);
|
|
31235
31333
|
pendo.teardown = makeSafe(teardown);
|
|
31236
31334
|
// guides.js
|
|
31237
31335
|
pendo.initGuides = exportPendoCoreOnly(initGuides);
|
|
@@ -31374,7 +31472,7 @@ function exportPublicApi(pendo) {
|
|
|
31374
31472
|
pendo.receiveDomStructureJson = exportPendoCoreOnly(ContentLoader.receiveDomStructureJson);
|
|
31375
31473
|
pendo.addExtension = addExtension;
|
|
31376
31474
|
/**
|
|
31377
|
-
* Retrieve a configuration value from the web
|
|
31475
|
+
* Retrieve a configuration value from the web SDK's config. Available configuration keys can be
|
|
31378
31476
|
* found in the [configuration section](/config).
|
|
31379
31477
|
*
|
|
31380
31478
|
* @access public
|
|
@@ -31624,7 +31722,7 @@ function Guide() {
|
|
|
31624
31722
|
return true;
|
|
31625
31723
|
};
|
|
31626
31724
|
/**
|
|
31627
|
-
* Returns a Boolean value to indicate if the Guide can
|
|
31725
|
+
* Returns a Boolean value to indicate if the Guide can show at this time.
|
|
31628
31726
|
*
|
|
31629
31727
|
* @access public
|
|
31630
31728
|
* @category Guides
|
|
@@ -31657,13 +31755,13 @@ function Guide() {
|
|
|
31657
31755
|
return promise;
|
|
31658
31756
|
};
|
|
31659
31757
|
/**
|
|
31660
|
-
|
|
31661
|
-
|
|
31662
|
-
|
|
31663
|
-
|
|
31664
|
-
|
|
31665
|
-
|
|
31666
|
-
|
|
31758
|
+
* Attempt to show the Guide. The Guide will still honor any constraints like
|
|
31759
|
+
* requiring a DOM element to be present if it was configured for that.
|
|
31760
|
+
*
|
|
31761
|
+
* @access public
|
|
31762
|
+
* @category Guides
|
|
31763
|
+
* @returns {void}
|
|
31764
|
+
*/
|
|
31667
31765
|
this.show = function (reason) {
|
|
31668
31766
|
var guide = this;
|
|
31669
31767
|
return joinShowPromises(_.map(guide.steps, function (step) {
|
|
@@ -31677,7 +31775,7 @@ function Guide() {
|
|
|
31677
31775
|
*
|
|
31678
31776
|
* @access public
|
|
31679
31777
|
* @category Guides
|
|
31680
|
-
* @returns {
|
|
31778
|
+
* @returns {void}
|
|
31681
31779
|
* @example
|
|
31682
31780
|
* guide.hide({stayHidden: true});
|
|
31683
31781
|
*/
|
|
@@ -32774,7 +32872,7 @@ function GuideStep(guide) {
|
|
|
32774
32872
|
removeStyleElementsForIdFromHead(this.id);
|
|
32775
32873
|
};
|
|
32776
32874
|
/**
|
|
32777
|
-
*
|
|
32875
|
+
* Attempts to show the step.
|
|
32778
32876
|
*
|
|
32779
32877
|
* @access public
|
|
32780
32878
|
* @category Guides
|
|
@@ -32955,7 +33053,7 @@ function GuideStep(guide) {
|
|
|
32955
33053
|
/**
|
|
32956
33054
|
* Hides the Step if shown. Use an argument of an Object containing a
|
|
32957
33055
|
* key of `stayHidden` set to `true` to make sure to keep the Step hidden
|
|
32958
|
-
* if the Guide it belongs to is designated as
|
|
33056
|
+
* if the Guide it belongs to is designated as automatically shown.
|
|
32959
33057
|
*
|
|
32960
33058
|
* @access public
|
|
32961
33059
|
* @category Guides
|
|
@@ -33006,7 +33104,7 @@ function GuideStep(guide) {
|
|
|
33006
33104
|
*
|
|
33007
33105
|
* @access public
|
|
33008
33106
|
* @category Guides
|
|
33009
|
-
* @returns {
|
|
33107
|
+
* @returns {void}
|
|
33010
33108
|
*/
|
|
33011
33109
|
this.dismiss = function () {
|
|
33012
33110
|
if (this.seenState === 'dismissed' && !this.isRendered())
|
|
@@ -33032,9 +33130,9 @@ function GuideStep(guide) {
|
|
|
33032
33130
|
* Allows for an eventListener to be created that will automatically get cleaned up when this
|
|
33033
33131
|
* Step is torn down.
|
|
33034
33132
|
*
|
|
33035
|
-
* @param element {Element} - The DOM element to attach the listener.
|
|
33133
|
+
* @param element {Element} - The DOM element to attach the listener to.
|
|
33036
33134
|
* @param type {String} - The type of event: 'click', 'mousedown', 'keypress', etc...
|
|
33037
|
-
* @param fn {function} - A function that will be called when an event
|
|
33135
|
+
* @param fn {function} - A function that will be called when an event of the specified type occurs.
|
|
33038
33136
|
*
|
|
33039
33137
|
* @access public
|
|
33040
33138
|
* @category Guides
|
|
@@ -33192,7 +33290,7 @@ class CloneDetection {
|
|
|
33192
33290
|
return;
|
|
33193
33291
|
/**
|
|
33194
33292
|
* Randomly generated ID used to detect when sessionStorage has been cloned
|
|
33195
|
-
* from another browser
|
|
33293
|
+
* from another browser tab.
|
|
33196
33294
|
*
|
|
33197
33295
|
* @name pendo_cd
|
|
33198
33296
|
* @category Cookies/sessionStorage
|
|
@@ -33309,7 +33407,7 @@ var FramesModule = (function () {
|
|
|
33309
33407
|
if (state.initialized)
|
|
33310
33408
|
return;
|
|
33311
33409
|
/**
|
|
33312
|
-
* Randomly generated string that identifies a browser
|
|
33410
|
+
* Randomly generated string that identifies a browser tab.
|
|
33313
33411
|
*
|
|
33314
33412
|
* @name pendo_tabId
|
|
33315
33413
|
* @category Cookies/sessionStorage
|
|
@@ -33318,7 +33416,7 @@ var FramesModule = (function () {
|
|
|
33318
33416
|
*/
|
|
33319
33417
|
agentStorage.registry.addSession(TAB_ID);
|
|
33320
33418
|
/**
|
|
33321
|
-
* When a browser
|
|
33419
|
+
* When a browser tab is cloned, the `pendo_tabId` is copied to the new tab.
|
|
33322
33420
|
* The Pendo Web SDK detects this, creates a new `pendo_tabId`, and stores the old
|
|
33323
33421
|
* `pendo_tabId` in `pendo_parentTabId`.
|
|
33324
33422
|
*
|
|
@@ -35397,7 +35495,7 @@ function addDebuggingFunctions() {
|
|
|
35397
35495
|
pendo$1.debugging = debugging;
|
|
35398
35496
|
}
|
|
35399
35497
|
/**
|
|
35400
|
-
* Loads Pendo Debugger and extends the global pendo object with additional functionality
|
|
35498
|
+
* Loads the Pendo Debugger and extends the global `pendo` object with additional functionality
|
|
35401
35499
|
* for debugging purposes.
|
|
35402
35500
|
*
|
|
35403
35501
|
* @access public
|
|
@@ -35424,7 +35522,7 @@ function enableDebugging(andChain) {
|
|
|
35424
35522
|
return 'debugging enabled';
|
|
35425
35523
|
}
|
|
35426
35524
|
/**
|
|
35427
|
-
* Removes Pendo Debugger extension.
|
|
35525
|
+
* Removes the Pendo Debugger extension.
|
|
35428
35526
|
*
|
|
35429
35527
|
* @access public
|
|
35430
35528
|
* @category Debugging
|
|
@@ -35503,7 +35601,7 @@ const DebuggerLauncher = (function () {
|
|
|
35503
35601
|
}
|
|
35504
35602
|
globalPendo = pendo;
|
|
35505
35603
|
/**
|
|
35506
|
-
* Returns a string indicating debugging status. Pass an optional value of true to get result as a boolean.
|
|
35604
|
+
* Returns a string indicating debugging status. Pass an optional value of true to get the result as a boolean.
|
|
35507
35605
|
*
|
|
35508
35606
|
* @access public
|
|
35509
35607
|
* @category Debugging
|
|
@@ -36081,7 +36179,7 @@ const EmbeddedGuides = (function () {
|
|
|
36081
36179
|
}
|
|
36082
36180
|
})();
|
|
36083
36181
|
/**
|
|
36084
|
-
* Returns a list of embedded guides eligible
|
|
36182
|
+
* Returns a list of embedded guides eligible for the active visitor on the active page.
|
|
36085
36183
|
*
|
|
36086
36184
|
* @access public
|
|
36087
36185
|
* @category Guides
|
|
@@ -36093,7 +36191,7 @@ function getEmbeddedGuides() {
|
|
|
36093
36191
|
return EmbeddedGuides.activeEmbeddedGuides;
|
|
36094
36192
|
}
|
|
36095
36193
|
/**
|
|
36096
|
-
* Returns a list of embedded guides that are rendered on the page
|
|
36194
|
+
* Returns a list of embedded guides that are rendered on the page.
|
|
36097
36195
|
*
|
|
36098
36196
|
* @access public
|
|
36099
36197
|
* @category Guides
|
|
@@ -39031,7 +39129,7 @@ var doesLauncherHaveGuides = function () {
|
|
|
39031
39129
|
return dom('._pendo-launcher-item_').length > 0;
|
|
39032
39130
|
};
|
|
39033
39131
|
/**
|
|
39034
|
-
* Closes Pendo Guide Center (launcher) if open on page.
|
|
39132
|
+
* Closes the Pendo Guide Center (launcher) if open on the page.
|
|
39035
39133
|
*
|
|
39036
39134
|
* @access public
|
|
39037
39135
|
* @category Classic Guides
|
|
@@ -39049,7 +39147,7 @@ var collapseLauncherList = function () {
|
|
|
39049
39147
|
}
|
|
39050
39148
|
};
|
|
39051
39149
|
/**
|
|
39052
|
-
* Opens Pendo Guide Center (launcher) if present on page.
|
|
39150
|
+
* Opens the Pendo Guide Center (launcher) if present on the page.
|
|
39053
39151
|
*
|
|
39054
39152
|
* @access public
|
|
39055
39153
|
* @category Classic Guides
|
|
@@ -39162,7 +39260,7 @@ var initLauncherPlugin = function (pendo, PluginAPI) {
|
|
|
39162
39260
|
PluginAPI.GuideLoop.addUpdatePhase(launcherProc);
|
|
39163
39261
|
registerLoadGuideJobs(loadLauncherContentHandler);
|
|
39164
39262
|
/**
|
|
39165
|
-
* Written when the classic guide center is closed. Legacy guide center only
|
|
39263
|
+
* Written when the classic guide center is closed. Legacy guide center only; not used for the resource center.
|
|
39166
39264
|
*
|
|
39167
39265
|
* @name _pendo_launcher-closed
|
|
39168
39266
|
* @category Cookies/localStorage
|
|
@@ -39367,7 +39465,7 @@ var PromoteMetadata = (function () {
|
|
|
39367
39465
|
promotedAgentMetadata = PluginAPI.ConfigReader.get(PROMOTED_AGENT_METADATA);
|
|
39368
39466
|
schemaGroup = {};
|
|
39369
39467
|
/**
|
|
39370
|
-
* Stores the historical metadata fields for the current visitor
|
|
39468
|
+
* Stores the historical metadata fields for the current visitor when enabled in an application.
|
|
39371
39469
|
* This is turned on by an admin in Pendo's Data Mappings and used to track metadata changes over time.
|
|
39372
39470
|
*
|
|
39373
39471
|
* @name _pendo___sg__
|
|
@@ -39972,6 +40070,299 @@ class DOMPrompt {
|
|
|
39972
40070
|
}
|
|
39973
40071
|
}
|
|
39974
40072
|
|
|
40073
|
+
const ASSISTANT_MESSAGE = 'assistantMessage';
|
|
40074
|
+
const CONVERSATION_ID_URL_PATTERN = 'conversationIdUrlPattern';
|
|
40075
|
+
const MESSAGE_ID_ATTR = 'messageIdAttr';
|
|
40076
|
+
const MODEL_USED_ATTR = 'modelUsedAttr';
|
|
40077
|
+
const REACTION_ACTIVE = 'reactionActive';
|
|
40078
|
+
const STREAMING_ACTIVE = 'streamingActive';
|
|
40079
|
+
const STREAMING_ACTIVE_ATTR = 'streamingActiveAttr';
|
|
40080
|
+
const THUMB_DOWN = 'thumbDown';
|
|
40081
|
+
const THUMB_UP = 'thumbUp';
|
|
40082
|
+
const TURN_CONTAINER = 'turnContainer';
|
|
40083
|
+
const TURN_ATTR = 'turnAttr';
|
|
40084
|
+
const USER_MESSAGE = 'userMessage';
|
|
40085
|
+
const REQUIRED_SELECTORS = [
|
|
40086
|
+
ASSISTANT_MESSAGE,
|
|
40087
|
+
CONVERSATION_ID_URL_PATTERN,
|
|
40088
|
+
MESSAGE_ID_ATTR,
|
|
40089
|
+
STREAMING_ACTIVE,
|
|
40090
|
+
TURN_CONTAINER,
|
|
40091
|
+
TURN_ATTR,
|
|
40092
|
+
USER_MESSAGE
|
|
40093
|
+
];
|
|
40094
|
+
const STREAMING_END_SETTLE_MS = 500;
|
|
40095
|
+
class DOMConversation {
|
|
40096
|
+
// Returns the list of required selector types that are missing or empty
|
|
40097
|
+
// in the given cssSelectors config. An empty array means the config is
|
|
40098
|
+
// valid for instantiation.
|
|
40099
|
+
static validateConfig(cssSelectors) {
|
|
40100
|
+
if (!Array.isArray(cssSelectors)) {
|
|
40101
|
+
return REQUIRED_SELECTORS.slice();
|
|
40102
|
+
}
|
|
40103
|
+
const present = new Set();
|
|
40104
|
+
for (const cfg of cssSelectors) {
|
|
40105
|
+
if (!cfg || !cfg.type || !cfg.cssSelector)
|
|
40106
|
+
continue;
|
|
40107
|
+
if (cfg.type === CONVERSATION_ID_URL_PATTERN) {
|
|
40108
|
+
try {
|
|
40109
|
+
RegExp(cfg.cssSelector);
|
|
40110
|
+
}
|
|
40111
|
+
catch (e) {
|
|
40112
|
+
continue;
|
|
40113
|
+
}
|
|
40114
|
+
}
|
|
40115
|
+
present.add(cfg.type);
|
|
40116
|
+
}
|
|
40117
|
+
return REQUIRED_SELECTORS.filter((r) => !present.has(r));
|
|
40118
|
+
}
|
|
40119
|
+
static supportedPreset(preset) {
|
|
40120
|
+
return preset === 'chatgpt-full';
|
|
40121
|
+
}
|
|
40122
|
+
constructor(pendo, PluginAPI, id, privacyFilters, cssSelectors) {
|
|
40123
|
+
this.selectors = {};
|
|
40124
|
+
this.listeners = [];
|
|
40125
|
+
this.isActive = true;
|
|
40126
|
+
this.observers = [];
|
|
40127
|
+
this.wasStreaming = false;
|
|
40128
|
+
this.streamingEndTimer = null;
|
|
40129
|
+
this.requestNode = null;
|
|
40130
|
+
this.conversationIdRegex = null;
|
|
40131
|
+
this.lastReturnedMessageId = null;
|
|
40132
|
+
this.dom = pendo.dom;
|
|
40133
|
+
this._ = pendo._;
|
|
40134
|
+
this.api = PluginAPI;
|
|
40135
|
+
this.Sizzle = pendo.Sizzle;
|
|
40136
|
+
this.id = id;
|
|
40137
|
+
this.setFilters(privacyFilters);
|
|
40138
|
+
if (!this._.isArray(cssSelectors)) {
|
|
40139
|
+
this.api.log.error(`cssSelectors must be an array, received: ${typeof cssSelectors}`);
|
|
40140
|
+
cssSelectors = [];
|
|
40141
|
+
}
|
|
40142
|
+
this._.each(cssSelectors, (cfg) => {
|
|
40143
|
+
if (cfg && cfg.type) {
|
|
40144
|
+
this.selectors[cfg.type] = cfg.cssSelector;
|
|
40145
|
+
}
|
|
40146
|
+
});
|
|
40147
|
+
this.conversationIdRegex = new RegExp(this.selectors[CONVERSATION_ID_URL_PATTERN]);
|
|
40148
|
+
this.root = document.body;
|
|
40149
|
+
this.setupReactionListener();
|
|
40150
|
+
this.setupStreamingObserver();
|
|
40151
|
+
}
|
|
40152
|
+
setupReactionListener() {
|
|
40153
|
+
if (!this.findSelector(THUMB_UP) && !this.findSelector(THUMB_DOWN))
|
|
40154
|
+
return;
|
|
40155
|
+
this.reactionClickHandler = this.handleReactionClick.bind(this);
|
|
40156
|
+
this.root.addEventListener('click', this.reactionClickHandler, true);
|
|
40157
|
+
}
|
|
40158
|
+
handleReactionClick(evt) {
|
|
40159
|
+
const target = evt.target;
|
|
40160
|
+
if (!target || target.nodeType !== 1)
|
|
40161
|
+
return;
|
|
40162
|
+
const upSelector = this.findSelector(THUMB_UP);
|
|
40163
|
+
const downSelector = this.findSelector(THUMB_DOWN);
|
|
40164
|
+
const thumb = this.dom(target).closest(`${upSelector}, ${downSelector}`);
|
|
40165
|
+
if (!thumb.length)
|
|
40166
|
+
return;
|
|
40167
|
+
const isUp = this.Sizzle.matchesSelector(thumb[0], upSelector);
|
|
40168
|
+
const activeSelector = this.findSelector(REACTION_ACTIVE);
|
|
40169
|
+
const wasPressed = activeSelector && this.Sizzle.matchesSelector(thumb[0], activeSelector);
|
|
40170
|
+
const direction = isUp ? 'positive' : 'negative';
|
|
40171
|
+
const content = wasPressed ? 'unreact' : direction;
|
|
40172
|
+
const assistantNode = thumb.closest(this.findSelector(TURN_CONTAINER))
|
|
40173
|
+
.find(this.findSelector(ASSISTANT_MESSAGE));
|
|
40174
|
+
this.emit('user_reaction', {
|
|
40175
|
+
agentId: this.id,
|
|
40176
|
+
messageId: this.getMessageId(assistantNode),
|
|
40177
|
+
content,
|
|
40178
|
+
privacyFilterApplied: false
|
|
40179
|
+
});
|
|
40180
|
+
}
|
|
40181
|
+
// observe the streaming indicator
|
|
40182
|
+
setupStreamingObserver() {
|
|
40183
|
+
this.wasStreaming = this.select(STREAMING_ACTIVE).length > 0;
|
|
40184
|
+
this.stopStreamingEndTimer();
|
|
40185
|
+
const MutationObserver = getZoneSafeMethod('MutationObserver');
|
|
40186
|
+
const observer = new MutationObserver(this.handleMutation.bind(this));
|
|
40187
|
+
const attrName = this.findSelector(STREAMING_ACTIVE_ATTR);
|
|
40188
|
+
observer.observe(this.root, {
|
|
40189
|
+
childList: true,
|
|
40190
|
+
subtree: true,
|
|
40191
|
+
attributes: true,
|
|
40192
|
+
attributeFilter: attrName ? [attrName] : undefined
|
|
40193
|
+
});
|
|
40194
|
+
this.observers.push(observer);
|
|
40195
|
+
}
|
|
40196
|
+
// look for changes in the state of the streaming indicator.
|
|
40197
|
+
// streaming started -> a prompt has been submitted
|
|
40198
|
+
// streaming ended -> got a response
|
|
40199
|
+
// we don't send the prompt immediately when it's submitted because it might not have a
|
|
40200
|
+
// conversation id yet.
|
|
40201
|
+
// we don't send the agent_response immediately when the streaming indicator is cleared
|
|
40202
|
+
// because it clears slightly before the final text chunk is committed to the DOM so the
|
|
40203
|
+
// end-handling is deferred by a short settle window
|
|
40204
|
+
handleMutation() {
|
|
40205
|
+
const isStreaming = this.select(STREAMING_ACTIVE).length > 0;
|
|
40206
|
+
if (isStreaming === this.wasStreaming)
|
|
40207
|
+
return;
|
|
40208
|
+
if (isStreaming) { // started streaming
|
|
40209
|
+
if (!this.streamingEndTimer) {
|
|
40210
|
+
this.onSubmissionStart();
|
|
40211
|
+
}
|
|
40212
|
+
else {
|
|
40213
|
+
// stream restarted during the settle window (multi-phase response).
|
|
40214
|
+
// treat as a continuation of the prior request, not a new submission.
|
|
40215
|
+
// we'll handle it next time streaming stops
|
|
40216
|
+
this.stopStreamingEndTimer();
|
|
40217
|
+
}
|
|
40218
|
+
}
|
|
40219
|
+
else { // finished streaming
|
|
40220
|
+
this.startStreamingEndTimer();
|
|
40221
|
+
}
|
|
40222
|
+
this.wasStreaming = isStreaming;
|
|
40223
|
+
}
|
|
40224
|
+
onSubmissionStart() {
|
|
40225
|
+
this.requestNode = this.findLastRequestNode();
|
|
40226
|
+
if (this.requestNode) {
|
|
40227
|
+
this.handleUserMessage(this.requestNode);
|
|
40228
|
+
}
|
|
40229
|
+
}
|
|
40230
|
+
onSubmissionEnd() {
|
|
40231
|
+
this.streamingEndTimer = null;
|
|
40232
|
+
let requestNode = this.requestNode;
|
|
40233
|
+
this.requestNode = null;
|
|
40234
|
+
if (!requestNode) {
|
|
40235
|
+
// onSubmissionStart didn't send, send it now
|
|
40236
|
+
requestNode = this.findLastRequestNode();
|
|
40237
|
+
if (!requestNode)
|
|
40238
|
+
return;
|
|
40239
|
+
this.handleUserMessage(requestNode);
|
|
40240
|
+
}
|
|
40241
|
+
const requestTurn = this.findTurnNumber(requestNode);
|
|
40242
|
+
if (requestTurn === null)
|
|
40243
|
+
return;
|
|
40244
|
+
const assistantNodes = this.select(ASSISTANT_MESSAGE);
|
|
40245
|
+
const toEmit = [];
|
|
40246
|
+
for (let i = assistantNodes.length - 1; i >= 0; i--) {
|
|
40247
|
+
const n = this.findTurnNumber(this.dom(assistantNodes[i]));
|
|
40248
|
+
if (n === null)
|
|
40249
|
+
continue;
|
|
40250
|
+
if (n <= requestTurn)
|
|
40251
|
+
break;
|
|
40252
|
+
toEmit.push(assistantNodes[i]);
|
|
40253
|
+
}
|
|
40254
|
+
// emit in chronological order (reverse of collection order)
|
|
40255
|
+
for (let i = toEmit.length - 1; i >= 0; i--) {
|
|
40256
|
+
this.handleAssistantMessage(this.dom(toEmit[i]));
|
|
40257
|
+
}
|
|
40258
|
+
}
|
|
40259
|
+
extractContent(node) {
|
|
40260
|
+
const rawContent = node.text().trim();
|
|
40261
|
+
const content = this.applyPrivacyFilter(rawContent);
|
|
40262
|
+
return { content, privacyFilterApplied: content !== rawContent };
|
|
40263
|
+
}
|
|
40264
|
+
getMessageId(node) {
|
|
40265
|
+
return node.attr(this.findSelector(MESSAGE_ID_ATTR));
|
|
40266
|
+
}
|
|
40267
|
+
handleUserMessage(node) {
|
|
40268
|
+
this.emit('prompt', Object.assign({ agentId: this.id, messageId: this.getMessageId(node) }, this.extractContent(node)));
|
|
40269
|
+
}
|
|
40270
|
+
handleAssistantMessage(node) {
|
|
40271
|
+
const modelUsedAttr = this.findSelector(MODEL_USED_ATTR);
|
|
40272
|
+
const modelUsed = modelUsedAttr && node.attr(modelUsedAttr);
|
|
40273
|
+
this.emit('agent_response', Object.assign({ agentId: this.id, messageId: this.getMessageId(node), agentModelsUsed: modelUsed ? [modelUsed] : [] }, this.extractContent(node)));
|
|
40274
|
+
}
|
|
40275
|
+
findLastRequestNode() {
|
|
40276
|
+
if (!this.getConversationId())
|
|
40277
|
+
return null;
|
|
40278
|
+
const node = this._.last(this.select(USER_MESSAGE));
|
|
40279
|
+
if (!node)
|
|
40280
|
+
return null;
|
|
40281
|
+
const $node = this.dom(node);
|
|
40282
|
+
const messageId = this.getMessageId($node);
|
|
40283
|
+
if (!messageId)
|
|
40284
|
+
return null;
|
|
40285
|
+
if (messageId === this.lastReturnedMessageId)
|
|
40286
|
+
return null;
|
|
40287
|
+
this.lastReturnedMessageId = messageId;
|
|
40288
|
+
return $node;
|
|
40289
|
+
}
|
|
40290
|
+
findTurnNumber(node) {
|
|
40291
|
+
const turnSelector = this.findSelector(TURN_CONTAINER);
|
|
40292
|
+
const turnAttr = this.findSelector(TURN_ATTR);
|
|
40293
|
+
const turn = node.closest(turnSelector).attr(turnAttr);
|
|
40294
|
+
if (!turn)
|
|
40295
|
+
return null;
|
|
40296
|
+
const seqMatch = String(turn).match(/\d+/);
|
|
40297
|
+
return seqMatch ? parseInt(seqMatch[0], 10) : null;
|
|
40298
|
+
}
|
|
40299
|
+
findSelector(type) {
|
|
40300
|
+
return this.selectors[type];
|
|
40301
|
+
}
|
|
40302
|
+
select(type) {
|
|
40303
|
+
return this.dom(this.findSelector(type), this.root);
|
|
40304
|
+
}
|
|
40305
|
+
getConversationId() {
|
|
40306
|
+
const m = location.href.match(this.conversationIdRegex);
|
|
40307
|
+
if (!m)
|
|
40308
|
+
return null;
|
|
40309
|
+
return m[1] !== undefined ? m[1] : m[0];
|
|
40310
|
+
}
|
|
40311
|
+
setFilters(candidateFilter) {
|
|
40312
|
+
if (!candidateFilter) {
|
|
40313
|
+
this.privacyFilters = null;
|
|
40314
|
+
return null;
|
|
40315
|
+
}
|
|
40316
|
+
try {
|
|
40317
|
+
this.privacyFilters = new RegExp(candidateFilter, 'gmi');
|
|
40318
|
+
}
|
|
40319
|
+
catch (e) {
|
|
40320
|
+
this.privacyFilters = null;
|
|
40321
|
+
this.api.log.error(e);
|
|
40322
|
+
}
|
|
40323
|
+
return this.privacyFilters;
|
|
40324
|
+
}
|
|
40325
|
+
applyPrivacyFilter(candidateValue, filters = null) {
|
|
40326
|
+
const filtersToUse = filters || this.privacyFilters;
|
|
40327
|
+
if (!filtersToUse || !this._.isRegExp(filtersToUse))
|
|
40328
|
+
return candidateValue;
|
|
40329
|
+
return candidateValue.replace(filtersToUse, 'redacted');
|
|
40330
|
+
}
|
|
40331
|
+
onSubmit(callback) {
|
|
40332
|
+
this.listeners.push(callback);
|
|
40333
|
+
}
|
|
40334
|
+
emit(eventType, eventPayload) {
|
|
40335
|
+
eventPayload.conversationId = this.getConversationId();
|
|
40336
|
+
this._.each(this.listeners, (cb) => cb(eventType, eventPayload));
|
|
40337
|
+
}
|
|
40338
|
+
startStreamingEndTimer() {
|
|
40339
|
+
this.stopStreamingEndTimer();
|
|
40340
|
+
this.streamingEndTimer = setTimeout$1(this.onSubmissionEnd.bind(this), STREAMING_END_SETTLE_MS);
|
|
40341
|
+
}
|
|
40342
|
+
stopStreamingEndTimer() {
|
|
40343
|
+
if (!this.streamingEndTimer)
|
|
40344
|
+
return;
|
|
40345
|
+
clearTimeout(this.streamingEndTimer);
|
|
40346
|
+
this.streamingEndTimer = null;
|
|
40347
|
+
}
|
|
40348
|
+
suspend() {
|
|
40349
|
+
this.isActive = false;
|
|
40350
|
+
}
|
|
40351
|
+
resume() {
|
|
40352
|
+
this.isActive = true;
|
|
40353
|
+
}
|
|
40354
|
+
teardown() {
|
|
40355
|
+
this._.each(this.observers, (o) => o && o.disconnect && o.disconnect());
|
|
40356
|
+
this.observers = [];
|
|
40357
|
+
if (this.reactionClickHandler && this.root) {
|
|
40358
|
+
this.root.removeEventListener('click', this.reactionClickHandler, true);
|
|
40359
|
+
this.reactionClickHandler = null;
|
|
40360
|
+
}
|
|
40361
|
+
this.stopStreamingEndTimer();
|
|
40362
|
+
this.listeners = [];
|
|
40363
|
+
}
|
|
40364
|
+
}
|
|
40365
|
+
|
|
39975
40366
|
/*
|
|
39976
40367
|
* Prompt Analytics Plugin
|
|
39977
40368
|
*
|
|
@@ -40136,18 +40527,31 @@ class PromptPlugin {
|
|
|
40136
40527
|
}
|
|
40137
40528
|
}
|
|
40138
40529
|
observePrompt(config) {
|
|
40139
|
-
const { id, cssSelectors, privacyFilters } = config;
|
|
40530
|
+
const { id, cssSelectors, privacyFilters, preset } = config;
|
|
40140
40531
|
// Check if agent already exists
|
|
40141
40532
|
const existingPrompt = this._.find(this.prompts, prompt => prompt.id === id);
|
|
40142
40533
|
if (existingPrompt) {
|
|
40143
40534
|
return;
|
|
40144
40535
|
}
|
|
40536
|
+
if (DOMConversation.supportedPreset(preset)) {
|
|
40537
|
+
const missing = DOMConversation.validateConfig(cssSelectors);
|
|
40538
|
+
if (missing.length) {
|
|
40539
|
+
this.api.log.error('aiAgent config missing required selectors', { agentId: id, missing });
|
|
40540
|
+
return;
|
|
40541
|
+
}
|
|
40542
|
+
const conversation = new DOMConversation(this.pendo, this.api, id, privacyFilters, cssSelectors);
|
|
40543
|
+
conversation.onSubmit((eventType, payload) => {
|
|
40544
|
+
this.sendConversationEvent(eventType, payload);
|
|
40545
|
+
});
|
|
40546
|
+
this.prompts.push(conversation);
|
|
40547
|
+
return;
|
|
40548
|
+
}
|
|
40145
40549
|
let inputCssSelectors, submitCssSelectors;
|
|
40146
40550
|
inputCssSelectors = this.parseCssSelector('input', cssSelectors);
|
|
40147
40551
|
submitCssSelectors = this.parseCssSelector('submit', cssSelectors);
|
|
40148
40552
|
const prompt = new DOMPrompt(this.pendo, this.api, id, privacyFilters, inputCssSelectors, submitCssSelectors);
|
|
40149
40553
|
prompt.onSubmit((promptPayload) => {
|
|
40150
|
-
this.
|
|
40554
|
+
this.sendPromptEvent(promptPayload);
|
|
40151
40555
|
});
|
|
40152
40556
|
this.prompts.push(prompt);
|
|
40153
40557
|
}
|
|
@@ -40156,7 +40560,7 @@ class PromptPlugin {
|
|
|
40156
40560
|
const selectors = this._.map(filtered, cfg => cfg.cssSelector);
|
|
40157
40561
|
return selectors;
|
|
40158
40562
|
}
|
|
40159
|
-
|
|
40563
|
+
sendPromptEvent(promptEvent) {
|
|
40160
40564
|
// Block event if the prompt is suspended
|
|
40161
40565
|
const prompt = this._.find(this.prompts, p => p.id === promptEvent.agentId);
|
|
40162
40566
|
if (prompt && !prompt.isActive) {
|
|
@@ -40168,6 +40572,15 @@ class PromptPlugin {
|
|
|
40168
40572
|
}, promptEvent);
|
|
40169
40573
|
this.api.analytics.collectEvent('prompt', event, undefined, 'agentic');
|
|
40170
40574
|
}
|
|
40575
|
+
sendConversationEvent(eventType, eventPayload) {
|
|
40576
|
+
// Block event if the prompt is suspended
|
|
40577
|
+
const conv = this._.find(this.prompts, p => p.id === eventPayload.agentId);
|
|
40578
|
+
if (conv && !conv.isActive) {
|
|
40579
|
+
return;
|
|
40580
|
+
}
|
|
40581
|
+
eventPayload = this._.extend({ agentType: 'conversation' }, eventPayload);
|
|
40582
|
+
this.api.analytics.collectEvent(eventType, eventPayload, undefined, 'agentic');
|
|
40583
|
+
}
|
|
40171
40584
|
teardown() {
|
|
40172
40585
|
this._.each(this.prompts, (prompt) => prompt.teardown());
|
|
40173
40586
|
if (this.agentsCache) {
|
|
@@ -40235,7 +40648,7 @@ class SessionManager {
|
|
|
40235
40648
|
this.suffix = this.api.ConfigReader.get('identityStorageSuffix');
|
|
40236
40649
|
/**
|
|
40237
40650
|
* Randomly generated string that identifies a session. This is similar to `pendo_tabId`,
|
|
40238
|
-
* but identifies the entire browser
|
|
40651
|
+
* but identifies the entire browser session rather than individual tabs.
|
|
40239
40652
|
*
|
|
40240
40653
|
* @name sessionId
|
|
40241
40654
|
* @category Cookies/localStorage
|
|
@@ -49290,9 +49703,9 @@ var Transport = /** @class */ (function () {
|
|
|
49290
49703
|
return Transport;
|
|
49291
49704
|
}());
|
|
49292
49705
|
|
|
49293
|
-
|
|
49294
|
-
|
|
49295
|
-
|
|
49706
|
+
const ELEMENT_NODE = 1;
|
|
49707
|
+
const INPUT_MASK = '*'.repeat(10);
|
|
49708
|
+
const NUMBER_INPUT_MASK = '0'.repeat(10);
|
|
49296
49709
|
function isElementNode(node) {
|
|
49297
49710
|
if (!node)
|
|
49298
49711
|
return false;
|
|
@@ -49301,12 +49714,10 @@ function isElementNode(node) {
|
|
|
49301
49714
|
return true;
|
|
49302
49715
|
}
|
|
49303
49716
|
function getParent(elem) {
|
|
49304
|
-
|
|
49717
|
+
const isElementShadowRoot = typeof window.ShadowRoot !== 'undefined' && elem instanceof window.ShadowRoot && elem.host;
|
|
49305
49718
|
return isElementShadowRoot ? elem.host : elem.parentNode;
|
|
49306
49719
|
}
|
|
49307
|
-
function distanceToMatch(node, selector, limit, distance) {
|
|
49308
|
-
if (limit === void 0) { limit = Infinity; }
|
|
49309
|
-
if (distance === void 0) { distance = 0; }
|
|
49720
|
+
function distanceToMatch(node, selector, limit = Infinity, distance = 0) {
|
|
49310
49721
|
if (distance > limit)
|
|
49311
49722
|
return -1;
|
|
49312
49723
|
if (!node)
|
|
@@ -49320,13 +49731,13 @@ function distanceToMatch(node, selector, limit, distance) {
|
|
|
49320
49731
|
return distanceToMatch(getParent(node), selector, limit, distance + 1);
|
|
49321
49732
|
}
|
|
49322
49733
|
function shouldMask(node, options) {
|
|
49323
|
-
|
|
49734
|
+
const { maskAllText, maskTextSelector, unmaskTextSelector } = options;
|
|
49324
49735
|
try {
|
|
49325
|
-
|
|
49736
|
+
const el = isElementNode(node) ? node : node.parentElement;
|
|
49326
49737
|
if (el === null)
|
|
49327
49738
|
return false;
|
|
49328
|
-
|
|
49329
|
-
|
|
49739
|
+
let maskDistance = -1;
|
|
49740
|
+
let unmaskDistance = -1;
|
|
49330
49741
|
if (maskAllText) {
|
|
49331
49742
|
unmaskDistance = distanceToMatch(el, unmaskTextSelector);
|
|
49332
49743
|
if (unmaskDistance < 0) {
|
|
@@ -49359,8 +49770,8 @@ function isNumberInput(element) {
|
|
|
49359
49770
|
}
|
|
49360
49771
|
function shouldMaskInput(element, maskInputOptions) {
|
|
49361
49772
|
if (maskInputOptions && isElementNode(element)) {
|
|
49362
|
-
|
|
49363
|
-
|
|
49773
|
+
const tagName = (element.tagName || '').toLowerCase();
|
|
49774
|
+
const type = (element.type || '').toLowerCase();
|
|
49364
49775
|
if (maskInputOptions[tagName] || maskInputOptions[type]) {
|
|
49365
49776
|
return true;
|
|
49366
49777
|
}
|
|
@@ -49467,7 +49878,7 @@ class SessionRecorder {
|
|
|
49467
49878
|
// https://github.com/pendo-io/pendo-browser-extension/blob/master/src/common/agent-loader.js
|
|
49468
49879
|
cf.addOption(RECORDING_CONFIG_ON_RECORDING_STOP, [cf.sources.SNIPPET_SRC, cf.sources.PENDO_CONFIG_SRC], undefined);
|
|
49469
49880
|
/**
|
|
49470
|
-
* Used when self
|
|
49881
|
+
* Used when self-hosting the replay web worker. Specifies the URL that points to the self-hosted web worker.
|
|
49471
49882
|
*
|
|
49472
49883
|
* @access public
|
|
49473
49884
|
* @category Config/Replay
|
|
@@ -49575,7 +49986,7 @@ class SessionRecorder {
|
|
|
49575
49986
|
this.subscriptions.push(this.api.attachEvent(this.api.Events, 'ready', bind(this.ready, this)));
|
|
49576
49987
|
}
|
|
49577
49988
|
/**
|
|
49578
|
-
* Randomly generated string that identifies a session. This is
|
|
49989
|
+
* Randomly generated string that identifies a session. This is similar to `pendo_sessionId`, but
|
|
49579
49990
|
* meant specifically for session recording.
|
|
49580
49991
|
*
|
|
49581
49992
|
* @name pendo_srId
|
|
@@ -49740,6 +50151,7 @@ class SessionRecorder {
|
|
|
49740
50151
|
* Used to start collecting replay data.
|
|
49741
50152
|
*
|
|
49742
50153
|
* @function start
|
|
50154
|
+
* @alias recording.start
|
|
49743
50155
|
* @category Replay
|
|
49744
50156
|
* @access public
|
|
49745
50157
|
* @example
|
|
@@ -50853,12 +51265,12 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
|
|
|
50853
51265
|
}
|
|
50854
51266
|
}
|
|
50855
51267
|
|
|
50856
|
-
|
|
51268
|
+
const ONE_HUNDRED_MB_IN_BYTES = 100 * 1024 * 1024;
|
|
50857
51269
|
function matchHostedResources(recordingEvent, stringifiedRecordingPayload) {
|
|
50858
|
-
|
|
50859
|
-
|
|
51270
|
+
const fontURLRegex = /https:\/\/[^"\\\s]+?\.(woff2?|ttf|otf|eot)(\?[^"\\\s]*)?\b/g;
|
|
51271
|
+
const matches = stringifiedRecordingPayload.match(fontURLRegex);
|
|
50860
51272
|
// de-duplicate matches
|
|
50861
|
-
|
|
51273
|
+
const hostedResources = matches ? Array.from(new Set(matches)) : [];
|
|
50862
51274
|
return {
|
|
50863
51275
|
type: 'recording',
|
|
50864
51276
|
visitorId: recordingEvent.visitorId,
|
|
@@ -50873,7 +51285,7 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
|
|
|
50873
51285
|
recordingPayloadMetadata: [],
|
|
50874
51286
|
sequence: 0,
|
|
50875
51287
|
recordingPayloadCount: 0,
|
|
50876
|
-
hostedResources
|
|
51288
|
+
hostedResources
|
|
50877
51289
|
};
|
|
50878
51290
|
}
|
|
50879
51291
|
// keep in mind changes here may need addressing in the extension worker proxy as well
|
|
@@ -50881,69 +51293,69 @@ var WorkerFactory = /*#__PURE__*/createInlineWorkerFactory(/* rollup-plugin-web-
|
|
|
50881
51293
|
try {
|
|
50882
51294
|
if (e.data.type === 'init' && e.data.lockID) {
|
|
50883
51295
|
if (navigator.locks) {
|
|
50884
|
-
navigator.locks.request(e.data.lockID,
|
|
51296
|
+
navigator.locks.request(e.data.lockID, () => {
|
|
50885
51297
|
postMessage({ ready: true });
|
|
50886
51298
|
// This unresolved promise keeps the lock held with the worker until the worker is
|
|
50887
51299
|
// terminated at which point the lock is released.
|
|
50888
|
-
return new Promise$2(
|
|
51300
|
+
return new Promise$2(() => { });
|
|
50889
51301
|
});
|
|
50890
51302
|
}
|
|
50891
51303
|
return;
|
|
50892
51304
|
}
|
|
50893
51305
|
if (e.data.url && e.data.payload) {
|
|
50894
|
-
|
|
51306
|
+
let { url, payload, shouldCacheResources } = e.data;
|
|
50895
51307
|
if (Object.keys(payload).length === 0) {
|
|
50896
51308
|
postMessage({
|
|
50897
51309
|
type: 'emptyPayload'
|
|
50898
51310
|
});
|
|
50899
51311
|
}
|
|
50900
|
-
|
|
50901
|
-
|
|
51312
|
+
const { sequence } = payload;
|
|
51313
|
+
const stringifiedRecordingPayload = JSON.stringify(payload.recordingPayload);
|
|
50902
51314
|
// calculate and post back the recording payload size before the payload is compressed
|
|
50903
|
-
|
|
50904
|
-
|
|
51315
|
+
const recordingPayloadSize = new TextEncoder().encode(stringifiedRecordingPayload).length;
|
|
51316
|
+
const exceedsPayloadSizeLimit = recordingPayloadSize >= ONE_HUNDRED_MB_IN_BYTES;
|
|
50905
51317
|
postMessage({
|
|
50906
51318
|
type: 'recordingPayloadSize',
|
|
50907
|
-
recordingPayloadSize
|
|
50908
|
-
exceedsPayloadSizeLimit
|
|
51319
|
+
recordingPayloadSize,
|
|
51320
|
+
exceedsPayloadSizeLimit
|
|
50909
51321
|
});
|
|
50910
51322
|
// don't attempt to send the payload if it exceeds the allowed limit
|
|
50911
51323
|
if (exceedsPayloadSizeLimit)
|
|
50912
51324
|
return;
|
|
50913
51325
|
if (shouldCacheResources) {
|
|
50914
|
-
|
|
51326
|
+
const hostedResourcesEvent = matchHostedResources(payload, stringifiedRecordingPayload);
|
|
50915
51327
|
if (hostedResourcesEvent.hostedResources.length) {
|
|
50916
51328
|
postMessage({
|
|
50917
51329
|
type: 'hostedResources',
|
|
50918
|
-
hostedResourcesEvent
|
|
51330
|
+
hostedResourcesEvent
|
|
50919
51331
|
});
|
|
50920
51332
|
}
|
|
50921
51333
|
}
|
|
50922
51334
|
payload.recordingSize = recordingPayloadSize;
|
|
50923
|
-
|
|
51335
|
+
const body = compress(payload, 'binary');
|
|
50924
51336
|
// we want to calculate ct (current time) as close as we can to the actual POST request
|
|
50925
51337
|
// so that it's as accurate as possible
|
|
50926
|
-
url =
|
|
51338
|
+
url = `${url}&ct=${new Date().getTime()}`;
|
|
50927
51339
|
fetch(url, {
|
|
50928
51340
|
method: 'POST',
|
|
50929
|
-
body
|
|
51341
|
+
body
|
|
50930
51342
|
}).then(function (response) {
|
|
50931
51343
|
if (response.status < 200 || response.status >= 300) {
|
|
50932
51344
|
postMessage({
|
|
50933
|
-
error: new Error(
|
|
51345
|
+
error: new Error(`received status code ${response.status}: ${response.statusText}`),
|
|
50934
51346
|
status: response.status,
|
|
50935
|
-
sequence
|
|
51347
|
+
sequence
|
|
50936
51348
|
});
|
|
50937
51349
|
}
|
|
50938
51350
|
else {
|
|
50939
51351
|
postMessage({
|
|
50940
|
-
sequence
|
|
51352
|
+
sequence
|
|
50941
51353
|
});
|
|
50942
51354
|
}
|
|
50943
|
-
})
|
|
51355
|
+
}).catch(function (e) {
|
|
50944
51356
|
postMessage({
|
|
50945
51357
|
error: e,
|
|
50946
|
-
sequence
|
|
51358
|
+
sequence
|
|
50947
51359
|
});
|
|
50948
51360
|
});
|
|
50949
51361
|
}
|
|
@@ -52090,6 +52502,7 @@ function NetworkCapture() {
|
|
|
52090
52502
|
* Use RegExp for flexible or partial matching.
|
|
52091
52503
|
*
|
|
52092
52504
|
* Example: `['https://example.com', new RegExp('https://test\\.com\\/.*'), /.*\\.domain\\.com/]`
|
|
52505
|
+
*
|
|
52093
52506
|
* @access public
|
|
52094
52507
|
* @category Config/Network Logs
|
|
52095
52508
|
* @name networkLogs.excludeRequestUrls
|