NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Jira Task Navigation Buttons
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Add "Previous Task" and "Next Task" buttons to Jira Cloud.
// @author JombY
// @license Apache-2.0
// @match https://*.atlassian.net/browse/*
// @icon https://www.google.com/s2/favicons?domain=jira.com
// @grant none
// ==/UserScript==
/* jshint esversion: 8 */
(function () {
'use strict';
const createNavigationButton = (text, icon) => {
const button = document.createElement('button');
button.innerHTML = `<span style="font-size: 16px; margin-right: 5px;">${icon}</span> ${text}`;
button.style.position = 'relative'; // Change to 'relative' from 'fixed'
button.style.marginBottom = '10px'; // Add margin to separate buttons
button.style.zIndex = '1'; // Ensure the buttons are above other elements
return button;
};
const navigateToTask = (direction) => {
const taskNumMatch = window.location.href.match(/([A-Z]+-\d+)/);
if (taskNumMatch) {
const [, prefix, number] = taskNumMatch[1].match(/([A-Z]+)-(\d+)/);
const newTaskNumber = direction === 'previous' ? Number(number) - 1 : Number(number) + 1;
if (newTaskNumber > 0) {
const newTaskUrl = `${prefix}-${newTaskNumber}`;
window.location.href = window.location.href.replace(taskNumMatch[1], newTaskUrl);
}
}
};
const addButtonToNav = () => {
const navElement = document.querySelector('#jira-issue-header > div > div > div > nav');
if (navElement && !navElement.classList.contains('task-navigation-buttons-added')) {
const previousTaskButton = createNavigationButton('Previous Task', '⟵');
previousTaskButton.addEventListener('click', () => navigateToTask('previous'));
navElement.appendChild(previousTaskButton);
const nextTaskButton = createNavigationButton('Next Task', '⟶');
nextTaskButton.addEventListener('click', () => navigateToTask('next'));
navElement.appendChild(nextTaskButton);
navElement.classList.add('task-navigation-buttons-added');
}
};
const observerConfig = { childList: true, subtree: true };
const observerCallback = (mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
addButtonToNav();
}
}
};
const observer = new MutationObserver(observerCallback);
// Wait for the DOM to be fully loaded
if (document.readyState === 'complete' || document.readyState === 'interactive') {
addButtonToNav();
} else {
document.addEventListener('DOMContentLoaded', addButtonToNav);
}
// Start observing changes in the DOM
observer.observe(document.body, observerConfig);
})();