rittenhop-dev/versions/5.94.2/node_modules/@sentry/utils/esm/browser.js

194 lines
5.5 KiB
JavaScript
Raw Normal View History

2024-09-23 19:40:12 -04:00
import { isString } from './is.js';
import { getGlobalObject } from './worldwide.js';
// eslint-disable-next-line deprecation/deprecation
const WINDOW = getGlobalObject();
const DEFAULT_MAX_STRING_LENGTH = 80;
/**
* Given a child DOM element, returns a query-selector statement describing that
* and its ancestors
* e.g. [HTMLElement] => body > div > input#foo.btn[name=baz]
* @returns generated DOM path
*/
function htmlTreeAsString(
elem,
options = {},
) {
if (!elem) {
return '<unknown>';
}
// try/catch both:
// - accessing event.target (see getsentry/raven-js#838, #768)
// - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly
// - can throw an exception in some circumstances.
try {
let currentElem = elem ;
const MAX_TRAVERSE_HEIGHT = 5;
const out = [];
let height = 0;
let len = 0;
const separator = ' > ';
const sepLength = separator.length;
let nextStr;
const keyAttrs = Array.isArray(options) ? options : options.keyAttrs;
const maxStringLength = (!Array.isArray(options) && options.maxStringLength) || DEFAULT_MAX_STRING_LENGTH;
while (currentElem && height++ < MAX_TRAVERSE_HEIGHT) {
nextStr = _htmlElementAsString(currentElem, keyAttrs);
// bail out if
// - nextStr is the 'html' element
// - the length of the string that would be created exceeds maxStringLength
// (ignore this limit if we are on the first iteration)
if (nextStr === 'html' || (height > 1 && len + out.length * sepLength + nextStr.length >= maxStringLength)) {
break;
}
out.push(nextStr);
len += nextStr.length;
currentElem = currentElem.parentNode;
}
return out.reverse().join(separator);
} catch (_oO) {
return '<unknown>';
}
}
/**
* Returns a simple, query-selector representation of a DOM element
* e.g. [HTMLElement] => input#foo.btn[name=baz]
* @returns generated DOM path
*/
function _htmlElementAsString(el, keyAttrs) {
const elem = el
;
const out = [];
let className;
let classes;
let key;
let attr;
let i;
if (!elem || !elem.tagName) {
return '';
}
// @ts-expect-error WINDOW has HTMLElement
if (WINDOW.HTMLElement) {
// If using the component name annotation plugin, this value may be available on the DOM node
if (elem instanceof HTMLElement && elem.dataset && elem.dataset['sentryComponent']) {
return elem.dataset['sentryComponent'];
}
}
out.push(elem.tagName.toLowerCase());
// Pairs of attribute keys defined in `serializeAttribute` and their values on element.
const keyAttrPairs =
keyAttrs && keyAttrs.length
? keyAttrs.filter(keyAttr => elem.getAttribute(keyAttr)).map(keyAttr => [keyAttr, elem.getAttribute(keyAttr)])
: null;
if (keyAttrPairs && keyAttrPairs.length) {
keyAttrPairs.forEach(keyAttrPair => {
out.push(`[${keyAttrPair[0]}="${keyAttrPair[1]}"]`);
});
} else {
if (elem.id) {
out.push(`#${elem.id}`);
}
// eslint-disable-next-line prefer-const
className = elem.className;
if (className && isString(className)) {
classes = className.split(/\s+/);
for (i = 0; i < classes.length; i++) {
out.push(`.${classes[i]}`);
}
}
}
const allowedAttrs = ['aria-label', 'type', 'name', 'title', 'alt'];
for (i = 0; i < allowedAttrs.length; i++) {
key = allowedAttrs[i];
attr = elem.getAttribute(key);
if (attr) {
out.push(`[${key}="${attr}"]`);
}
}
return out.join('');
}
/**
* A safe form of location.href
*/
function getLocationHref() {
try {
return WINDOW.document.location.href;
} catch (oO) {
return '';
}
}
/**
* Gets a DOM element by using document.querySelector.
*
* This wrapper will first check for the existance of the function before
* actually calling it so that we don't have to take care of this check,
* every time we want to access the DOM.
*
* Reason: DOM/querySelector is not available in all environments.
*
* We have to cast to any because utils can be consumed by a variety of environments,
* and we don't want to break TS users. If you know what element will be selected by
* `document.querySelector`, specify it as part of the generic call. For example,
* `const element = getDomElement<Element>('selector');`
*
* @param selector the selector string passed on to document.querySelector
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getDomElement(selector) {
if (WINDOW.document && WINDOW.document.querySelector) {
return WINDOW.document.querySelector(selector) ;
}
return null;
}
/**
* Given a DOM element, traverses up the tree until it finds the first ancestor node
* that has the `data-sentry-component` attribute. This attribute is added at build-time
* by projects that have the component name annotation plugin installed.
*
* @returns a string representation of the component for the provided DOM element, or `null` if not found
*/
function getComponentName(elem) {
// @ts-expect-error WINDOW has HTMLElement
if (!WINDOW.HTMLElement) {
return null;
}
let currentElem = elem ;
const MAX_TRAVERSE_HEIGHT = 5;
for (let i = 0; i < MAX_TRAVERSE_HEIGHT; i++) {
if (!currentElem) {
return null;
}
if (currentElem instanceof HTMLElement && currentElem.dataset['sentryComponent']) {
return currentElem.dataset['sentryComponent'];
}
currentElem = currentElem.parentNode;
}
return null;
}
export { getComponentName, getDomElement, getLocationHref, htmlTreeAsString };
//# sourceMappingURL=browser.js.map