NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Jira add descriptive link
// @description Adds a copyable link with issue name and key, ready for pasting into messages etc.
// @namespace https://openuserjs.org/users/floodmeadows
// @copyright 2021, floodmeadows (https://openuserjs.org/users/floodmeadows)
// @license MIT
// @version 1.1
// @include https://*/browse/*
// @include https://*/projects/*
// @updateURL https://openuserjs.org/meta/floodmeadows/Jira_add_descriptive_link.meta.js
// @downloadURL https://openuserjs.org/src/scripts/floodmeadows/Jira_add_descriptive_link.user.js
// @grant none
// ==/UserScript==
/* jshint esversion: 11 */
(function () {
'use strict';
// -----------------------------
// CONFIGURATION
// -----------------------------
const markerId = 'copy-descriptive-link-button-added';
let issueKey = "";
let issueName = "";
let issueUrl = "";
// -----------------------------
// INITIALISE
// -----------------------------
function init() {
issueKey = document.getElementById('key-val')?.textContent.trim();
issueName = getIssueName();
issueUrl = document.URL;
checkIfButtonNeedsAdding();
}
function checkIfButtonNeedsAdding() {
console.log("start called")
setTimeout(() => {
const target = document.getElementById('key-val').parentElement.parentElement; //<ol>
if (!target) {
console.log("Target element not found. Can't add button.")
return
}
if (document.getElementById(markerId)) {
console.log("Marker element not found. Returning without adding button.")
return;
}
console.log("Injecting button...");
const marker = document.createElement('span');
marker.id = markerId;
target.after(marker);
addButton(target, "Copy descriptive link", copyTextToClipboard);
applyAdditionalFormatting();
}, 500); // delay to allow DOM to settle
}
function addButton(target, buttonText, callbackFunction) {
const button = document.createElement("button");
button.addEventListener("click", callbackFunction);
button.setAttribute("id","copy-descriptive-link");
button.setAttribute("class","aui-button");
target.after(button);
const textNode = document.createTextNode(buttonText);
button.appendChild(textNode);
}
function applyAdditionalFormatting() {
document.getElementById('key-val').parentElement.parentElement.style.display = "inline-block";
document.getElementById('summary-val').style.display = "block";
document.getElementById('copy-descriptive-link').style.display = "inline-block";
document.getElementById('copy-descriptive-link').style.border = "none";
document.getElementById('copy-descriptive-link').style.padding = "0.4em 0.8em";
}
function getIssueName() {
let issueNameH1 = document.querySelector('h1#summary-val')
let issueNameDiv = document.querySelector('div#summary-val')
let issueNameH2 = document.querySelector('h2#summary-val')
let issueName = ''
if (issueNameH1 !== null) {
issueName = issueNameH1.childNodes[0].nodeValue;
} else if (issueNameDiv !== null) {
issueName = issueNameDiv.childNodes[0].childNodes[0].nodeValue
} else if (issueNameH2 !== null) {
issueName = issueNameH2.childNodes[0].nodeValue
}
return issueName
}
function constructTextForClipboard() {
var textForClipboard = new Object();
textForClipboard.text = `'${issueName}' (${issueUrl})`;
textForClipboard.html = `<a href="${issueUrl}">'${issueName}' (${issueKey})</a>`;
return textForClipboard;
}
function copyTextToClipboard() {
console.log("copyTextToClipboard() called.");
const textForClipboard = constructTextForClipboard();
const contentTypeText = "text/plain";
const contentTypeHtml = "text/html";
const blobText = new Blob([textForClipboard.text], { type: contentTypeText });
const blobHtml = new Blob([textForClipboard.html], { type: contentTypeHtml });
const data = new ClipboardItem({
[contentTypeText]: blobText,
[contentTypeHtml]: blobHtml
});
navigator.clipboard
.write([data])
.then(
(response) => {
console.log("Success writing to the clipboard.");
console.log(new Array(textForClipboard.text, textForClipboard.html));
},
(response) => {
console.log("Error writing to the clipboard: " + response.text);
}
);
}
// -----------------------------
// OBSERVER TO HANDLE DOM CHANGES
// -----------------------------
const observer = new MutationObserver((mutationsList, observer) => {
console.log("DOM changed, checking buttons...");
checkIfButtonNeedsAdding();
});
observer.observe(document.body, { childList: true, subtree: true });
window.__observerActive = true;
console.log("MutationObserver started");
// Run on initial load
init();
})();