Zendesk — Page Event Detector latest version (currently v1.0.1)
← Back to User Scripts
Script Content
// ==UserScript==
// @name Zendesk: Page Event Detector
// @namespace https://www.timhilton.xyz/user-scripts
// @version 1.0.1
// @description Tests techniques for detecting Zendesk page events using the Navigation API and MutationObserver.
// @author Tim Hilton using GitHub Copilot
// @match https://*.zendesk.com/agent/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const LOG_PREFIX = '[Zendesk: Page Event Detector]';
console.debug(`${LOG_PREFIX} Script initialised`);
function getPageType(url) {
if (/\/agent\/tickets\/\d+/.test(url)) {
return 'ticket';
}
if (/\/agent\/(filters|views)\/\d+/.test(url)) {
return 'filter';
}
return 'other';
}
let ticketObserverCallCount = 0;
let filterObserverCallCount = 0;
function waitForTicketLoad(url) {
const mainEl = document.querySelector('main') || document.body;
let callCount = 0;
const observer = new MutationObserver((_mutations, obs) => {
callCount++;
ticketObserverCallCount++;
console.debug(`${LOG_PREFIX} Ticket MutationObserver fired (call #${callCount}, total #${ticketObserverCallCount})`);
if (document.querySelector('div[data-ticket-id]')) {
const ticketId = url.match(/\/tickets\/(\d+)/)?.[1] ?? 'unknown';
console.log(`${LOG_PREFIX} ✅ Ticket page fully loaded — ticket ID: ${ticketId}, observer fired ${callCount} time(s): ${url}`);
obs.disconnect();
console.debug(`${LOG_PREFIX} Ticket MutationObserver disconnected`);
}
});
observer.observe(mainEl, { childList: true, subtree: true });
console.debug(`${LOG_PREFIX} Ticket MutationObserver registered on <${mainEl.tagName.toLowerCase()}>`);
}
function waitForFilterLoad(url) {
const mainEl = document.querySelector('main') || document.body;
let callCount = 0;
const observer = new MutationObserver((_mutations, obs) => {
callCount++;
filterObserverCallCount++;
console.debug(`${LOG_PREFIX} Filter MutationObserver fired (call #${callCount}, total #${filterObserverCallCount})`);
if (document.querySelector('[data-test-id="views-list"], [data-garden-id="tables.table"]')) {
console.log(`${LOG_PREFIX} ✅ Filter page fully loaded — observer fired ${callCount} time(s): ${url}`);
obs.disconnect();
console.debug(`${LOG_PREFIX} Filter MutationObserver disconnected`);
}
});
observer.observe(mainEl, { childList: true, subtree: true });
console.debug(`${LOG_PREFIX} Filter MutationObserver registered on <${mainEl.tagName.toLowerCase()}>`);
}
function handleNavigation(url) {
const pageType = getPageType(url);
console.debug(`${LOG_PREFIX} Handling navigation to ${pageType} page: ${url}`);
console.log(`${LOG_PREFIX} 📍 Page type: ${pageType} — ${url}`);
if (pageType === 'ticket') {
waitForTicketLoad(url);
} else if (pageType === 'filter') {
waitForFilterLoad(url);
}
}
console.debug(`${LOG_PREFIX} Processing initial page URL: ${window.location.href}`);
handleNavigation(window.location.href);
if (window.navigation) {
console.debug(`${LOG_PREFIX} Navigation API available, registering listener`);
window.navigation.addEventListener('navigate', (event) => {
const url = event.destination.url;
console.debug(`${LOG_PREFIX} Navigation API event fired for: ${url}`);
handleNavigation(url);
});
console.log(`${LOG_PREFIX} ✅ Navigation API listener registered`);
} else {
console.log(`${LOG_PREFIX} ❌ Navigation API not available in this browser`);
}
})();