Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 72 additions & 95 deletions ZendeskWindowTitle.user.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,123 +4,100 @@
// @description Improves the browser window title when using zendesk agent by adding info like ticket id.
// @match https://*.zendesk.com/agent/*
// @grant none
// @version 1.8
// @copyright 2014-2024 software architects gmbh
// @version 1.9
// @copyright 2014-2026 software architects gmbh
// @author Simon
// ==/UserScript==

var currentSection = null;
var isSectionPresent = false;
var initialWindowTitle = null;

function getTitle() {
(function () {
"use strict";

var tabs = $("div[data-test-id='header-toolbar']");
if (tabs.length === 1) {
var selectedTabs = tabs.find("div[data-selected='true']");
if (selectedTabs.length === 1) {
var tabHeader = selectedTabs.find("div[data-test-id='header-tab-title']");
if (tabHeader.length === 1) {
return tabHeader[0].innerText;
function getVisibleWorkspace() {
// #main_panes is not unique anymore and cached workspaces are hidden via visibility/opacity, not display
var workspaces = document.querySelectorAll('main#main_panes div.workspace');
for (var i = 0; i < workspaces.length; i++) {
var ws = workspaces[i];
if (!ws.classList.contains('is-cached') && window.getComputedStyle(ws).visibility !== 'hidden') {
return ws;
}
} else {
console.debug('ZendeskWindowTitle: getTitle: selected tab not found');
}
} else {
console.debug('ZendeskWindowTitle: getTitle: tabs not found');

return null;
}

return null;
}
function getTicketInformation() {
var workspace = getVisibleWorkspace();
if (!workspace) {
console.debug('ZendeskWindowTitle: getTicketInformation: workspace not found');
return null;
}

function getTicketInformation() {
"use strict";
var nav = workspace.querySelector("nav[aria-label='Ticket page location']");
if (!nav) {
console.debug('ZendeskWindowTitle: getTicketInformation: nav not found');
return null;
}

var title = null;
var user = null;
var org = null;

var mainPanes = $('#main_panes');
if (mainPanes.length === 1) {
var div = mainPanes.children('div.ember-view.workspace').not('[style*="none"]');
if (div.length === 1) {
var nav = div.find('nav.ember-view.btn-group');
if (nav.length === 1) {
var buttons = nav.children('span.btn');
if (buttons.length === 3) {
user = $(buttons[1]).text().trim();
if (!$(buttons[0]).hasClass('create')) {
org = $(buttons[0]).text().trim();
} else {
console.debug('ZendeskWindowTitle: getTicketInformation: no org');
}

title = getTitle();
} else {
console.debug('ZendeskWindowTitle: getTicketInformation: buttons not found');
}
} else {
console.debug('ZendeskWindowTitle: getTicketInformation: nav not found');
}
} else {
console.debug('ZendeskWindowTitle: getTicketInformation: div not found');
var userButton = nav.querySelector("[data-test-id='tabs-nav-item-users']");
var orgButton = nav.querySelector("[data-test-id='tabs-nav-item-organizations']");
var user = userButton ? userButton.textContent.trim() : null;
var org = orgButton ? orgButton.textContent.trim() : null;

if (!org) {
console.debug('ZendeskWindowTitle: getTicketInformation: no org');
}
} else {
console.debug('ZendeskWindowTitle: getTicketInformation: main panes not found');
}

if (title && user) {
if (org) {
return title + ' - ' + user + ' - ' + org;
} else {
return title + ' - ' + user;
if (user) {
// the subject is already part of zendesk's own window title
return org ? user + ' - ' + org : user;
}

return null;
}

return null;
}
function getSection() {
// e.g. /agent/tickets/123 -> tickets/123, /agent/home/tickets -> home/tickets
var match = /^\/agent\/(.*?)\/*$/.exec(window.location.pathname);
return match ? match[1] : '';
}

function updateWindowTitle() {
"use strict";
if (!isSectionPresent) {
function buildSuffix() {
var section = getSection();
if (!section) {
return '';
}

var ticket = /^tickets\/(\d+)/.exec(section);
if (ticket) {
var id = ticket[1];
var info = getTicketInformation();
return info ? ' - #' + id + ' - ' + info : ' - #' + id;
}

return ' - ' + section;
}

function updateWindowTitle() {
// zendesk shows a dummy title while loading
if (window.document.title === 'Zendesk...') {
console.debug('ZendeskWindowTitle: dummy window title present');
return;
} else if (Zd.hasOwnProperty('section')) {
isSectionPresent = true;
initialWindowTitle = window.document.title;
console.debug('ZendeskWindowTitle: section present');
} else {
console.debug('ZendeskWindowTitle: section still missing');
return;
}
}

if (Zd.section !== currentSection) {
if (!Zd.section) {
currentSection = Zd.section;
console.debug('ZendeskWindowTitle: empty section');
window.document.title = initialWindowTitle;
} else if (Zd.section.indexOf('tickets/') === 0) {
var id = Zd.section.substring(8);
console.debug('ZendeskWindowTitle: focused ticket: ' + id);
// if the title is not the one we set last, zendesk changed it (navigation, notification count, ...)
if (window.document.title !== lastSetTitle) {
baseTitle = window.document.title;
}

var info = getTicketInformation();
if (info) {
currentSection = Zd.section;
window.document.title = initialWindowTitle + ' - #' + id + ' - ' + info;
} else {
// something did not check out, ensure that we query again
currentSection = null;
window.document.title = initialWindowTitle + ' - #' + id;
}
} else {
currentSection = Zd.section;
console.debug('ZendeskWindowTitle: focused: ' + Zd.section);
window.document.title = initialWindowTitle + ' - ' + currentSection;
// derived from scratch on every tick, so late loading data and edits are picked up
var desired = baseTitle + buildSuffix();
if (desired !== window.document.title) {
window.document.title = desired;
}
lastSetTitle = desired;
}
}

window.setInterval(updateWindowTitle, 1000);
var baseTitle = null;
var lastSetTitle = null;

window.setInterval(updateWindowTitle, 1000);
})();
Loading