przemyslaw / GZ issue prefiller

// ==UserScript==
// @name           GZ issue prefiller
// @description    Allows prefilling of URTracker fields based on selected criteria during issue creation.
// @match          https://fwtrack.tpv-tech.com/Pts/CreateIssue.aspx?*
// @match          https://fwtrack.tpv-tech.com/pts/CreateIssue.aspx?*
// @license        MIT
// @version        0.1.84
// ==/UserScript==

/**
 * Add the necessary CSS stylesheet.
 */
const style = document.createElement('style');
style.textContent = '#ctl00_CP1_pe_problemTable>tbody{display:flex;flex-direction:column}#ctl00_CP1_pe_problemTable tr.required{order:-1}#ctl00_CP1_pe_problemTable .ItemName{width:15vw}#ctl00_CP1_pe_problemTable td:last-child{width:80%}#prefiller{background-color:#d2e5f8;bottom:0;padding:1ex;position:fixed;right:0}#prefiller td:first-child{text-align:right}#prefiller input[type=text]{width:8.5em}#prefiller tr:last-child td{text-align:center}#cke_50>span{font:125%/19px Arial;text-align:center}';
document.head.appendChild(style);

/**
 * Move the problem table's required fields to the top (by the means of adding a class with an associated styling)
 */
[...document.querySelectorAll('#ctl00_CP1_pe_problemTable td:first-child > font')]
    .forEach(font => font.closest('tr').classList.add('required'));

/**
 * Add a prefiller table and define variables and constants used further in the code.
 */
let prefillerTable = document.createElement('table');
document.body.appendChild(prefillerTable);
prefillerTable.outerHTML = `<table id="prefiller"><tbody><tr><td>Stress:</td><td><input type="checkbox" name="stress"/></td></tr><tr><td>ORT script:</td><td><input type="checkbox" name="ort"/></td></tr><tr><td>CET:</td><td><input type="checkbox" name="cet"/></td></tr><tr><td>Version:</td><td><input type="text" name="version"/></td></tr><tr><td colspan="2"><button id="set">Set</button></td></tr></tbody></table>`;
prefillerTable = document.querySelector('#prefiller');
const [stress, ort, cet, version] = [...prefillerTable.querySelectorAll('input')];

/**
 * Set a <select> element to a particular <option> by their value.
 * @param  {Node}   el   A <select> element
 * @param  {String} text Text value of an <option> to select
 */
const selectOption = (el, text) => {
    if (el === undefined) { return; }
    [...el.children].find(opt => opt.textContent === text).selected = true;
};

/**
 * Get <input> or <select> of a field by its name.
 * @param  {String} label Field name, e.g. 'Subject'
 */
const trs = [...document.querySelectorAll('#ctl00_CP1_pe_problemTable tr')];
const findInputByLabel = label => {
    const tr = trs.find(tr => tr.children[0].textContent.endsWith(label));
    return tr === undefined ? undefined : tr.querySelector('input, select');
};

/**
 * Set problem table's fields to values passed as a parameter.
 * @param  {Object} obj Object defining desired values for particular fields. {subject, type, category}.
 */
const setFields = obj => {
  (findInputByLabel('Subject') || {}).value = obj.subject + ' ';
  (findInputByLabel('Issue Version') || {}).value = version.value;
  selectOption(findInputByLabel('Type'), obj.type);
  selectOption(findInputByLabel('Test Category'), obj.category);
};

/**
 * Fill problem table on prefiller's set button click.
 */
const setData = () => {
  const store = JSON.parse(window.localStorage.getItem('prefiller')) || {};
  [store.cet, store.version] = [cet.checked, version.value];
  window.localStorage.setItem('prefiller', JSON.stringify(store)); // Save some values to store
  if (!cet.checked) {
    if (stress.checked) {
      return ort.checked
      ? setFields({subject: '[GZ_ORT]', type: 'GZ-ORT', category: 'Stability Testing'})
      : setFields({subject: '[GZ_Stress]', type: 'GZ-QE', category: 'Stability Testing'});
    }
    return setFields({subject: '[GZ]', type: 'GZ-QE', category: 'S/W Product Validation'});
  }
  return stress.checked
  ? setFields({subject: `[GZ_Stress][${version.value.replace(/^[^\d]+/, '')}]`, type: 'GZ-QE', category: 'NSO/Home Test'})
  : setFields({subject: `[GZ_CET][${version.value.replace(/^[^\d]+/, '')}]`, type: 'GZ-QE', category: 'NSO/Home Test'});
};
document.querySelector('#set').addEventListener('click', setData);

/**
 * Set prefiller's cet and version fields and fill the problem table's fields according to the stored data.
 */
const store = JSON.parse(window.localStorage.getItem('prefiller')); // data saved in local storage
if (store !== null) {
    [cet.checked, version.value] = [store.cet, store.version];
    setData();
    CKEDITOR.on('instanceReady', () => {
        if (store.description) {
            const iframe = document.querySelector('#cke_1_contents iframe');
            if (iframe) { iframe.contentDocument.body.innerHTML = store.description; }
        }
    });
}

/**
 * Adds the "save the current description as default" functionality.
 */
let hasAlreadyRun = false;
CKEDITOR.on('instanceReady', () => {
    if (hasAlreadyRun) { return; }
    hasAlreadyRun = true;
    const saveButton = document.createElement('span');
    document.querySelector('#cke_1_toolbox > span').appendChild(saveButton);
    saveButton.outerHTML = '<span id="cke_49" class="cke_toolbar" role="toolbar"><span class="cke_toolbar_start"></span><span class="cke_toolgroup" role="presentation"><a id="cke_50" class="cke_button cke_button__about  cke_button_off" title="Save the current text as default" tabindex="-1" hidefocus="true" role="button" aria-haspopup="false"><span class="cke_button_icon"> S</span></a></span><span class="cke_toolbar_end"></span></span>';

    document.querySelector('#cke_50').addEventListener('click', () => { // Store the current description
        const store = JSON.parse(window.localStorage.getItem('prefiller')) || {};
        const iframe = document.querySelector('#cke_1_contents iframe');
        if (iframe) { store.description = iframe.contentDocument.body.innerHTML; }
        window.localStorage.setItem('prefiller', JSON.stringify(store));
    });
});