floodmeadows / Jira add descriptive link

// ==UserScript==
// @name         Jira add descriptive link
// @namespace    https://openuserjs.org/users/floodmeadows
// @description  Adds a copyable link with issue name and key, ready for pasting into messages etc.
// @copyright    2021, floodmeadows (https://openuserjs.org/users/floodmeadows)
// @license      MIT
// @version      0.3
// @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: 6 */

(function () {
  'use strict';
  setTimeout(start, 1000); // delay is needed for /projects/XYZ/issues/* URLs to load in the relevant DOM elements
})();

function start() {
  addLink()

  const target = document.getElementById('key-val').parentElement.parentElement; //<ol>
  addButton("Copy descriptive link", target, copyTextToClipboard);
  applyAdditionalFormatting();
}

function getIssueKey() {
    return document.getElementById("key-val").childNodes[0].nodeValue;
}

function getIssueName() {
    let issueNameH1 = document.querySelector('h1#summary-val')
    let issueNameH2 = document.querySelector('div#summary-val')
    let issueName = ''
    if (issueNameH1 !== null) {
        issueName = issueNameH1.childNodes[0].nodeValue;
    } else if (issueNameH2 !== null) {
        issueName = issueNameH2.childNodes[0].childNodes[0].nodeValue
    }

    return issueName
}

function addLink() {
    const issueKey = getIssueKey()
    const issueName = getIssueName()

    const newElement = document.createElement("div");
    const h = '<a href="' + document.URL + '">' + issueKey + ' (' + issueName + ')</a>';
    newElement.innerHTML = h;
    const target = document.getElementById('summary-val');
    target.parentNode.appendChild(newElement);
}

function constructTextForClipboard() {
    const issueKey = getIssueKey()
    const issueName = getIssueName()

    var textForClipboard = new Object();
    textForClipboard.text = `'${issueName}' (${document.URL})`;
    textForClipboard.html = `<a href="${document.URL}">'${issueName}' (${issueKey})</a>`;

    return textForClipboard;
}

function addButton(buttonText, target, 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 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);
          }
      );
}