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`);
    }
})();