@grafana/faro-web-sdk
Version:
Faro instrumentations, metas, transports for web.
138 lines • 6.09 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MESSAGE_TYPE_URL_CHANGE = void 0;
exports.monitorUrlChanges = monitorUrlChanges;
exports.__resetUrlChangeMonitorForTests = __resetUrlChangeMonitorForTests;
var faro_core_1 = require("@grafana/faro-core");
exports.MESSAGE_TYPE_URL_CHANGE = 'url-change';
var urlChangeObservable;
var isInstrumented = false;
var lastHref;
var originalPushState;
var originalReplaceState;
var onPopStateHandler;
var onHashChangeHandler;
var onNavigateHandler;
var originalNavigateEventIntercept;
function monitorUrlChanges() {
if (!urlChangeObservable) {
urlChangeObservable = new faro_core_1.Observable();
lastHref = location.href;
}
function emit(trigger, toOverride) {
var next = toOverride !== null && toOverride !== void 0 ? toOverride : location.href;
if (next !== lastHref) {
urlChangeObservable.notify({ type: exports.MESSAGE_TYPE_URL_CHANGE, from: lastHref, to: next, trigger: trigger });
lastHref = next;
}
}
if (!isInstrumented) {
var hasNavigation = 'navigation' in window && 'NavigateEvent' in window;
if (hasNavigation) {
// Prefer Navigation API when supported: do not patch history or add popstate/hashchange listeners
onNavigateHandler = function (e) {
try {
var destination = e === null || e === void 0 ? void 0 : e.destination;
if ((destination === null || destination === void 0 ? void 0 : destination.sameDocument) && typeof destination.url === 'string') {
emit('navigate', destination.url);
}
}
catch (_err) {
// Swallow to avoid impacting host app
}
};
window.navigation.addEventListener('navigate', onNavigateHandler);
var NavigateEventConstructor = window.NavigateEvent;
if (NavigateEventConstructor &&
NavigateEventConstructor.prototype &&
typeof NavigateEventConstructor.prototype.intercept === 'function') {
if (!originalNavigateEventIntercept) {
originalNavigateEventIntercept = NavigateEventConstructor.prototype.intercept;
}
// Wrap intercept to detect soft navigations (cross-document turned same-document)
NavigateEventConstructor.prototype.intercept = function (options) {
try {
var canIntercept = !!(this === null || this === void 0 ? void 0 : this.canIntercept);
var destination = this === null || this === void 0 ? void 0 : this.destination;
if (canIntercept &&
destination &&
destination.sameDocument === false &&
typeof destination.url === 'string') {
emit('navigate-intercept', destination.url);
}
}
catch (_err) {
// ignore
}
return originalNavigateEventIntercept.call(this, options);
};
}
isInstrumented = true;
}
else {
// Fallback: history API patching + popstate/hashchange
if (!originalPushState) {
originalPushState = window.history.pushState;
}
window.history.pushState = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var result = originalPushState.apply(window.history, args);
emit('pushState');
return result;
};
if (!originalReplaceState) {
originalReplaceState = window.history.replaceState;
}
window.history.replaceState = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var result = originalReplaceState.apply(window.history, args);
emit('replaceState');
return result;
};
onPopStateHandler = function () { return emit('popstate'); };
onHashChangeHandler = function () { return emit('hashchange'); };
window.addEventListener('popstate', onPopStateHandler);
window.addEventListener('hashchange', onHashChangeHandler);
isInstrumented = true;
}
}
return urlChangeObservable;
}
// Test-only utility to reset state between tests
function __resetUrlChangeMonitorForTests() {
var _a, _b;
if (onPopStateHandler) {
window.removeEventListener('popstate', onPopStateHandler);
}
if (onHashChangeHandler) {
window.removeEventListener('hashchange', onHashChangeHandler);
}
if (onNavigateHandler && ((_a = window.navigation) === null || _a === void 0 ? void 0 : _a.removeEventListener)) {
window.navigation.removeEventListener('navigate', onNavigateHandler);
}
if (originalPushState) {
window.history.pushState = originalPushState;
}
if (originalReplaceState) {
window.history.replaceState = originalReplaceState;
}
if (originalNavigateEventIntercept && ((_b = window.NavigateEvent) === null || _b === void 0 ? void 0 : _b.prototype)) {
window.NavigateEvent.prototype.intercept = originalNavigateEventIntercept;
}
urlChangeObservable = undefined;
isInstrumented = false;
lastHref = undefined;
onPopStateHandler = undefined;
onHashChangeHandler = undefined;
onNavigateHandler = undefined;
originalPushState = undefined;
originalReplaceState = undefined;
originalNavigateEventIntercept = undefined;
}
//# sourceMappingURL=urlChangeMonitor.js.map