您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Injects elements into a codepen IDE for demonstration purposes
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/438329/1112003/Online%20IDE%20Support%20JS.js
// import moment from 'moment.min.js'; // Math.seedrandom !function (f, a, c) { var s, l = 256, p = "random", d = c.pow(l, 6), g = c.pow(2, 52), y = 2 * g, h = l - 1; function n(n, t, r) { function e() { for (var n = u.g(6), t = d, r = 0; n < g;)n = (n + r) * l, t *= l, r = u.g(1); for (; y <= n;)n /= 2, t /= 2, r >>>= 1; return (n + r) / t } var o = [], i = j(function n(t, r) { var e, o = [], i = typeof t; if (r && "object" == i) for (e in t) try { o.push(n(t[e], r - 1)) } catch (n) { } return o.length ? o : "string" == i ? t : t + "\0" }((t = 1 == t ? { entropy: !0 } : t || {}).entropy ? [n, S(a)] : null == n ? function () { try { var n; return s && (n = s.randomBytes) ? n = n(l) : (n = new Uint8Array(l), (f.crypto || f.msCrypto).getRandomValues(n)), S(n) } catch (n) { var t = f.navigator, r = t && t.plugins; return [+new Date, f, r, f.screen, S(a)] } }() : n, 3), o), u = new m(o); return e.int32 = function () { return 0 | u.g(4) }, e.quick = function () { return u.g(4) / 4294967296 }, e.double = e, j(S(u.S), a), (t.pass || r || function (n, t, r, e) { return e && (e.S && v(e, u), n.state = function () { return v(u, {}) }), r ? (c[p] = n, t) : n })(e, i, "global" in t ? t.global : this == c, t.state) } function m(n) { var t, r = n.length, u = this, e = 0, o = u.i = u.j = 0, i = u.S = []; for (r || (n = [r++]); e < l;)i[e] = e++; for (e = 0; e < l; e++)i[e] = i[o = h & o + n[e % r] + (t = i[e])], i[o] = t; (u.g = function (n) { for (var t, r = 0, e = u.i, o = u.j, i = u.S; n--;)t = i[e = h & e + 1], r = r * l + i[h & (i[e] = i[o = h & o + t]) + (i[o] = t)]; return u.i = e, u.j = o, r })(l) } function v(n, t) { return t.i = n.i, t.j = n.j, t.S = n.S.slice(), t } function j(n, t) { for (var r, e = n + "", o = 0; o < e.length;)t[h & o] = h & (r ^= 19 * t[h & o]) + e.charCodeAt(o++); return S(t) } function S(n) { return String.fromCharCode.apply(0, n) } if (j(c.random(), a), "object" == typeof module && module.exports) { module.exports = n; try { s = require("crypto") } catch (n) { } } else "function" == typeof define && define.amd ? define(function () { return n }) : c["seed" + p] = n }("undefined" != typeof self ? self : this, [], Math); chrome.storage.sync.get("global", (data) => { let global = data.global; var areTmClassesAdded = false; var isTamperClickAdded = false; var defaultTamperlabelBkgd = 'radial-gradient(circle, rgba(63,94,251,1) 0%, rgba(0,0,0,0) 50%)'; const LogStyle = { base: [ "color: #fff", "background-color: #444", "padding: 2px 4px", "border-radius: 2px" ], warning: [ "color: #eee", "background-color: red" ], success: [ "background-color: green" ] }; var monkey = { addGlobalStyle: function (css) { var head, style; head = document.getElementsByTagName('head')[0]; if (!head) { return; } style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = css; head.appendChild(style); }, log: (msg, extra = []) => { let style = LogStyle.base.join(';') + ';'; style += extra.join(';'); // Add any additional styles if (typeof msg === 'string') { console.log(`%c${msg}`, style); } else { console.log(msg); } }, selectText: function (targetClass) { var textToCopy, range; try { if (document.selection) { range = document.body.createTextRange(); range.moveToElementText(document.getElementsByClassName(targetClass)[0]); range.select(); } else if (window.getSelection) { var selection = window.getSelection(); range = document.createRange(); range.selectNode(document.getElementsByClassName(targetClass)[0]); selection.removeAllRanges(); selection.addRange(range); } } catch (err) { monkey.log('Failed to select text'); } }, ping: function (ip, callback) { // via http://jsfiddle.net/GSSCD/203/ if (!this.inUse) { this.status = 'unchecked'; this.inUse = true; this.callback = callback; this.ip = ip; var _that = this; this.img = new Image(); this.img.onload = function () { _that.inUse = false; _that.callback('responded'); }; this.img.onerror = function (e) { if (_that.inUse) { _that.inUse = false; _that.callback('error', e); } }; this.start = new Date().getTime(); this.img.src = "http://" + this.ip; this.timer = setTimeout(function () { if (_that.inUse) { _that.inUse = false; _that.callback('timeout'); } }, 1500); } }, isTagIn: function (targetString, tags) { var isFound = false; _.each(tags, function scanTarget(tag) { if (targetString.toLowerCase().indexOf(tag.toLowerCase()) > -1) { isFound = true; } }); return isFound; }, copyTextToClipboard: function (text) { var copyFrom = document.createElement("textarea"); copyFrom.textContent = text; var body = document.getElementsByTagName('body')[0]; body.appendChild(copyFrom); copyFrom.select(); document.execCommand('copy'); body.removeChild(copyFrom); }, waitTimers: [], getElementsByText: function (str, tag) { var tagIndex = 0, foundElements, tagRange = ['a', 'button', 'input', 'div', 'span'], checkTag = function (checkStr, checkTag) { utils.log('checkTag( ' + checkStr + ', ' + checkTag + ')'); return Array.prototype.slice.call(document.getElementsByTagName(checkTag)).filter(el => el.textContent.trim() === checkStr.trim()); }; if (tag != null) { return checkTag(str, tag); } else { while ((foundElements == null || foundElements.length === 0) && tagIndex < tagRange.length) { foundElements = checkTag(str, tagRange[tagIndex]); tagIndex++; }; return foundElements; } }, initNotes: function (global) { if (global.notes == null) { global.notes = { messages: [], notifiedCount: 0 }; } }, getContainer: function (opts) { var options = { id: opts.id ? opts.id : opts.el.replace(/[ (:)]/g, ''), el: opts.el, try: 0, max: opts.max ? opts.max : 20, spd: opts.spd ? opts.spd : 500 }; clearTimeout(monkey.waitTimers[options.id]); return new Promise(function (resolve, reject) { monkey.waitForContainerElement(resolve, options); }); }, waitForContainerElement: function (resolve, options) { var $configElement = document.querySelector(options.el); if ($configElement.length === 0) { options.try++; if (options.try < options.max) { monkey.waitTimers[options.id] = setTimeout(monkey.waitForContainerElement.bind(this, resolve, options), options.spd); } else { console.error(`maximum searches reached - monkey.waitForContainerElement`); } } else { resolve($configElement); } }, }; let debugPassFail = []; const avatarHost = global.prefs.users.avatars.hostUrl; const pingPhoto = global.prefs.users.avatars.noImageName; const imageExt = global.prefs.users.avatars.imageExtension; (function () { const observers = { /** * handler to process user-defined callback when element is located in DOM * @param {NodeList} elements - All elements found matching the user-defined selector in "observerDefs" * @return {void} */ handleFound: (elements, observerDef) => { elements.forEach((element) => { observerDef.callback(element, observerDef); // if (!foundEls.includes(element.id)) { // foundEls.push(element.id); // } }); }, /** * Creates a single-use observer to await the existance of a DOM element * @param {Array<ObserverDef>} observerDefs - an array of elements to await * @return {Array<observer} observers - an array of all MutationObservers created */ create: (observerDefs) => { // As assistance for delayed initialization, define an observer to watch for changes var observerList = []; observerDefs.forEach(function (obd) { if (obd.single == null) { obd.single = true; } observerList.push( new MutationObserver(function (mutations, me) { var targetElems = document.querySelectorAll(obd.selector); if (targetElems.length > 0) { observers.handleFound(targetElems, obd); if (obd.single) { me.disconnect(); // stop observing } return; } }) ); }); // start observing observerList.forEach(function (observer) { observer.observe(document, { childList: true, subtree: true }); }); return observerList; } } const report = { start: (id) => { if (debugPassFail.length > 0) { utils.debug([`Reporting Error!`, debugPassFail, id]); } debugPassFail = []; debugPassFail.push({ id: id, step: `start`, pass: true, }); }, abort: () => { report.step(`not needed`); report.finish(); }, step: (step, pass = true) => { let thisId = debugPassFail[0] ? debugPassFail[0].id : `???`; debugPassFail.push({ id: thisId, step: step, pass: pass, }); }, finish: () => { const pass = []; const fail = []; if (debugPassFail.length === 0) { return; } if (debugPassFail.length === 1) { report.step(`did nothing`, false); } debugPassFail.forEach(pf => { if (pf.pass) { pass.push(pf); }; if (!pf.pass) { fail.push(pf); }; }); if (fail.length > 0) { utils.debug({ iAm: fail[0].id, ...fail }); } else if (pass.length > 0 && !global.prefs.account.debug.debugIgnores.includes(`pass`)) { utils.debug({ iAm: pass[0].id, ...pass }); } debugPassFail = []; }, }; const utils = { acronym: (str = '') => { const strArr = str.split(' '); let res = ''; strArr.forEach(el => { const [char] = el; if (char === char.toUpperCase() && char !== char.toLowerCase()) { res += char; }; }); return res; }, capitalize: (cap) => { if (!cap) { return; } return cap.charAt(0).toUpperCase() + cap.slice(1); }, createElement: (a, b) => { var d = document.createElement(a); if (b && "object" == typeof b) { var e; for (e in b) { if ("innerHTML" === e) { d.innerHTML = b[e]; } else if ("innerText" === e) { d.innerText = b[e]; } else { if (e.slice(0, 5) === "aria_" || e.slice(0, 5) === "data_") { var attr = e.slice(0, 4) + "-" + e.slice(5); d.setAttribute(attr, b[e]); } else { d.setAttribute(e, b[e]); } } } } return d; }, debug: (msg) => { const iAm = msg.iAm ? msg.iAm : debugPassFail[0] ? debugPassFail[0].id : `undefined`; let shouldIgnore = false; let userSelectedIgnore = [iAm].filter(function (iAmCheck) { return global.prefs.account.debug.debugIgnores.some(function (match) { return iAmCheck.toLowerCase().indexOf(match.toLowerCase()) !== -1; }); }); shouldIgnore = userSelectedIgnore.length > 0; if (utils.stringToBoolean(global.prefs.account.debug.useDebug) && !shouldIgnore) { if (typeof msg === 'object') { let hasSource = false; if (msg.constructor === Array) { msg.includes("iAm") && (hasSource = true); shouldIgnore = global.prefs.account.debug.debugIgnores.includes(msg.find(id => id === "iAm")); } else { const keys = Object.keys(msg); keys.forEach((key) => { !hasSource && (hasSource = key === "iAm"); }); shouldIgnore = global.prefs.account.debug.debugIgnores.includes(msg.iAm); } if (hasSource) { !shouldIgnore && monkey.log(msg); } else { monkey.log({ 'iAm': iAm, ...msg }); } } else { monkey.log({ 'iAm': iAm, 're': msg }); } } }, delayUntil: function (id, condition, callback) { const repeat = (id, co, ca) => { setTimeout(() => { utils.delayUntil(id, co, ca); }, global.constants.TIMEOUT * 2); }; if (!global.states.delays.find((x) => x.delayId === id)) { global.states.delays.push({ delayId: id, delayCount: 0 }); } global.states.delays.find((x) => x.delayId === id).delayCount++; if (global.states.delays.find((x) => x.delayId === id).delayCount > 20) { global.states.delays.find((x) => x.delayId === id).delayCount === 0; return; } try { if (!condition()) { utils.debug('delay WAIT called by ' + id); repeat(id, condition, callback); } else { utils.debug('delay PASS for ' + id); callback(); } } catch (e) { utils.debug('delay WAIT called by ' + id + ' TRIED\n ' + e); repeat(id, condition, callback); } }, getElementByTextContent: (text, tagName = `span`) => { var spanList = document.getElementsByTagName(tagName); for (var i = 0, len = spanList.length; i < len; i++) { if (spanList[i].textContent === text) { return spanList[i]; } } }, getElementsByTextContent: (text, tagName = `span`) => { const spanList = document.getElementsByTagName(tagName); const returnList = []; for (var i = 0, len = spanList.length; i < len; i++) { if (spanList[i].textContent === text) { returnList.push(spanList[i]); } } return returnList; }, initScript: () => { Object.keys(global.constants.initalizeOnElements).forEach((key) => { const trigger = global.constants.initalizeOnElements[key]; monkey.getContainer({ 'el': trigger, 'max': 100, 'spd': 1000 }).then(function () { page.initialize(); }); }); }, isEmpty: (obj) => { return Object.keys(obj).every(key => obj[key] === undefined); }, isNumeric: (n) => { return !isNaN(parseFloat(n)) && isFinite(n); }, listenOnce: (element, event, handler) => { element.addEventListener( event, function tempHandler(e) { handler(e); element.removeEventListener(event, tempHandler, false); }, false ); }, shuffle: (array) => { var date = new Date(); var dateString = "" + date.getFullYear() + date.getMonth() + date.getDate() + "1"; var p = new Math.seedrandom(dateString); var currentIndex = array.length, temporaryValue, randomIndex; // While there remain elements to shuffle... while (0 !== currentIndex) { // Pick a remaining element... randomIndex = Math.floor(p() * currentIndex); currentIndex -= 1; // And swap it with the current element. temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; }, stringToBoolean: (thisState) => { if (typeof thisState === `boolean`) { return thisState; } if (thisState === `1` || thisState === `true`) { return true; } return false; }, user: { chat: (idName, messageName, email) => { const chatLink = 'https://teams.microsoft.com/l/chat/0/0?users='; idName = email || utils.user.renameIndexedToEmail(idName) + '@dell.com'; var message = messageName ? '&message=' + messageName : ''; window.open(chatLink + idName + message); }, renameIndexedToEmail: (userName) => { const commaIndex = userName.indexOf(`, `); if (commaIndex <= 0) { return; } const lName = userName.substr(0, commaIndex); const fName = userName.replace(lName, ``).replace(`, `, ``); return `${fName}_${lName}`; }, properName: (thisName) => { if (!thisName) { return; } var firstName = '', lastName = '', midName = ''; thisName = thisName .replace('https://gitlab.dell.com/', '') .replace(' - Dell Team', '') .replace('User profile for ', '') .replace('\'s avatar', '') .replace('Assigned to ', '') .replace('Avatar for ', '') .replace('Assignee:', '') .replace(`Uploaded image for project: `, ``) .replace(/(<table>).*(<\/table>)/gi, '') .replace(/dell\.com/gi, '') .replace(/dellteam\.com/gi, '') .replace(/'/g, '') .replace('@', '') .replace(/@/g, '') .replace(/\//g, '') .replace(/Review requested from /g, '') .replace(/_/g, '-'); firstName = thisName.substring(0, thisName.indexOf('-')); lastName = thisName.substring(thisName.indexOf('-') + 1, thisName.length); if ((firstName.length === 0 && lastName.length === 0)) { return; } if (firstName.length > 0 && lastName.length > 0 && thisName.indexOf(',') < 0) { thisName = lastName + ', ' + firstName; } if (thisName.indexOf('-') > 0) { midName = thisName.substring(0, thisName.indexOf('-')); thisName = thisName.substring(thisName.indexOf('-') + 1, thisName.length); thisName = thisName + ' ' + midName; } while (thisName.indexOf(' ') > 0) { thisName = thisName.replace(/\s\s/, ''); // no double spaces } thisName = thisName .replace(/(\r\n\t|\n|\r\t)/gm, '') // no line breaks or tabs .replace(/ ,/, ',') // no spaces before commas .replace(/\%20/, '') // no %20 characters .replace(/Americas/g, '') .trim(); // seriously, no extra spaces thisName = thisName.replace(',', ', ').replace(' ', ' '); // there's probably a less-stupid way of REALLY making sure it's always "COMMA SPACE" return thisName; }, updateImg: function (img, thisName) { if (thisName && thisName.length > 0 && thisName !== ', ') { const src = img.getAttribute(`src`); if (src.match(/(!none|jira|gravatar)/gi)) { img.setAttribute("data-previous", src); const nameDivider = (thisName.indexOf(',') < 0) ? ' ' : ', '; const thisNameSpaceIndex = thisName.indexOf(' ') + 1; let thisNameFirst = thisName.indexOf(' ') < 0 ? thisName : nameDivider === ' ' ? thisName.substr(0, thisName.indexOf(thisNameSpaceIndex) - 1) : thisName.substr(thisNameSpaceIndex, thisName.length - thisNameSpaceIndex); if (thisNameFirst.length === 0) { thisNameFirst = thisName; } if (!global.states.avatarPingFailed && global.prefs.users.avatars.avatarsSources[0] === 'localhost') { // look at why there's a difference handling localhost vs. the other avatar servers img.setAttribute('src', 'http://' + avatarHost + thisName + imageExt); } else if (global.prefs.users.avatars.avatarsSources[0] !== 'localhost') { let templateSrc = global.templates.default.replace(/IMGID/g, thisName).replace(/IMGALT/g, thisName); if (global.prefs.users.avatars.avatarsType === `gender`) { // aw, this won't work for free for more than 1000 const finishUpdating = (genRes) => { genRes = JSON.parse(genRes); const result = genRes.gender ? genRes.gender : `initials`; templateSrc = templateSrc.replace(global.prefs.users.avatars.avatarsType, result); templateSrc = encodeURI(templateSrc.substr(templateSrc.indexOf('http'), (templateSrc.indexOf('alt=') - templateSrc.indexOf('http')) - 2)); img.setAttribute('src', templateSrc); }; utils.xhrAction(`updateImg`, null, `GET`, `https://api.genderize.io/?name=${thisNameFirst}`, null, finishUpdating); } else { templateSrc = encodeURI(templateSrc.substr(templateSrc.indexOf('http'), (templateSrc.indexOf('alt=') - templateSrc.indexOf('http')) - 2)); img.setAttribute('src', templateSrc); } } } } else { utils.debug('updateImg: invalid user name for ' + img.src + ': ' + thisName + '(' + thisName.length + ' chars)'); } }, }, xhrRequest: (method, url, data = {}, token) => { const xhr = new XMLHttpRequest(); return new Promise(resolve => { xhr.open(method, url, true); xhr.onload = () => resolve({ status: xhr.status, response: xhr.responseText }); xhr.onerror = () => resolve({ status: xhr.status, response: xhr.responseText }); if (method != 'GET') { xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); } if (token != null) { xhr.setRequestHeader('X-Jsio-Token', token); } data != {} ? xhr.send(JSON.stringify(data)) : xhr.send(); }) }, xhrAction: (iAm, token, xhrType, urlPath, params, callback, alwaysCallback) => { // deprecate? if (!iAm || !xhrType || !urlPath || !callback) { utils.debug('improper xhr setup'); return; } utils.debug({ 'id': iAm, 'xhrType': xhrType, 'urlPath': urlPath, 'params': params, 'callback': callback, 'alwaysCallback': alwaysCallback }); // Set up our HTTP request const xhr = new XMLHttpRequest(); // Setup our listener to process completed requests xhr.onload = function () { global.states.xhrBusy = false; // Process our return data if (xhr.status >= 200 && xhr.status < 300) { // What do when the request is successful const resp = xhr.response; if (resp) { // resp = JSON.parse(resp).slice().reverse(); utils.debug({ 'id': 'xhrAction', 're': { 'urlPath': urlPath, ...JSON.parse(resp) } }); callback(resp); } } else { // What do when the request fails utils.debug('XHR Call for ' + iAm + ' failed!'); } if (alwaysCallback) { alwaysCallback(); } }; xhr.open(xhrType, urlPath); if (token) { xhr.setRequestHeader('Authorization', 'Bearer ' + token); } if (params != null) { xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); xhr.send(JSON.stringify(params)); } else { xhr.send(); } }, }; global = { ...global, constants: { TIMEOUT: 750, initalizeOnElements: ['body'], // .content }, ids: { scriptName: 'JiraMods', prefsName: 'JiraPrefs', memsName: 'JiraMems', }, states: { areClassesAdded: false, avatarPingFailed: false, isMouseMoved: false, areStepsAnnounced: false, observingAvatars: false, observingChatAdds: false, }, mems: {}, templates: { default: null, localhost: `<img src="http://' + avatarHost + 'IMGID.png" alt="IMGALT" title="IMGALT" class="avatar s40" data-email="">`, dicebear: `<img src="https://avatars.dicebear.com/api/${global.prefs.users.avatars.avatarsType}/IMGID.svg" alt="IMGALT" title="IMGALT" class="avatar s40" data-email="">`, boring: `https://source.boringavatars.com/beam/120/IMGID?colors=264653,2a9d8f,e9c46a,f4a261,e76f51`, } }; switch (global.prefs.users.avatars.avatarsSources[0]) { case 'boring': global.templates.default = global.templates.boring; break; case 'dicebear': global.templates.default = global.templates.dicebear; break; default: global.templates.default = global.templates.localhost; break; } const page = { initialize: function () { page.setMems(); const stepsRun = []; const steps = [ page.addClasses, ]; Object.keys(mods).forEach(catkey => { Object.keys(mods[catkey]).forEach(stepkey => { steps.push(mods[catkey][stepkey]); }); }); steps.forEach((step, index) => { if (!global.states.areStepsAnnounced) { stepsRun.push(step); } setTimeout(() => { step(); }, index * 10); }); if (!global.states.areStepsAnnounced) { utils.debug([`INIT`, stepsRun]); global.states.areStepsAnnounced = true; } }, setMems: function () { var currentMems; // = GM_getValue(global.ids.memsName); if (currentMems == null || utils.isEmpty(JSON.parse(currentMems))) { global.mems = {}; // monkey.savePreferences(global.ids.memsName, global.mems); } else { global.mems = JSON.parse(currentMems); } }, addClasses: function () { report.start(`page.addClasses`); if (!global.states.areClassesAdded) { global.states.areClassesAdded = true; report.step(`classes added`); const ddsCss = [ `https://dds.dell.com/components/2.13.0/css/dds-reboot.min.css`, `https://dds.dell.com/components/2.13.0/css/dds-fonts.min.css`, `https://dds.dell.com/components/2.13.0/css/dds-icons.min.css`, `https://dds.dell.com/components/2.13.0/css/dds-helpers.min.css`, `https://dds.dell.com/components/2.13.0/css/dds-main.min.css` ]; ddsCss.forEach(cssUrl => { report.step(`adding ${cssUrl}`); const link = utils.createElement(`link`, { href: cssUrl, type: `text/css`, rel: `stylesheet`, }); document.getElementsByTagName("head")[0].appendChild(link); }); if (global.prefs.customize.comments.commentsMove) { monkey.addGlobalStyle(` .changehistory td { display: flex; line-height: 0.8rem; font-family: monospace; font-size: 0.8rem; }`); } if (global.prefs.customize.lists.listsShorten) { monkey.addGlobalStyle(` span.issue-link-key { margin-right: 0.625rem; } .issue-content-container { display: flex; font-size: 0.8rem; }`); } // Make certain sections pop if (global.prefs.customize.highlights.highlightsDetails) { monkey.addGlobalStyle(` #detail-repro, #customfield_10208-val, #description-val, #customfield_10217-val { background: aliceblue; border: 0.2rem dotted; border-radius: 0.625rem; }`); } // add custom hide-the-button-on-dds__notifications classes monkey.addGlobalStyle(` .ddsc__notification--button-primary-none .dds__notification__body .dds__button--primary { display: none !important; } `) monkey.addGlobalStyle(` .ddsc__notification--button-secondary-none .dds__notification__body .dds__button--secondary { display: none !important; } `) // add custom class for template modal monkey.addGlobalStyle(` .ddsc__modal { z-index: 3050; } `) // header removed buttons monkey.addGlobalStyle(` .removedLink { display:none !important; }`); // header favorite buttons monkey.addGlobalStyle(` .faveLink { margin-left: 0.625rem; margin-right: 0 !important; padding: 0.5rem; }`); // dashboard days-remaining monkey.addGlobalStyle(` #gadget-11556 { height: inherit !important; } .sprint-days-remaining-dashboard-item .ghx-remaining-value { font-family: fantasy; opacity: 0.5; top: 1.3rem; position: relative; }`); // fit images to size monkey.addGlobalStyle(` .activity-comment img { max-width: 100%; }`); // adjustments for DDS classes monkey.addGlobalStyle(` #structure .celldiv { height: inherit; max-height: inherit; } .aui-button-primary { font-weight: inherit; } .dds__button { margin-right: 0.625rem; } h1 { font-size: 2rem; line-height: 2rem; } h2 { font-size: 1.5rem; line-height: 1.5rem; } h3 { font-size: 1rem; line-height: 1rem; } blockquote { font-size: 1.05rem; line-height: 130%; }`); // Copy Issue as Markdown styling monkey.addGlobalStyle(` .copyLink { margin-left: 0.625rem; cursor: pointer; } .ghx-column .copyLink { position: absolute; bottom: 1rem; right: 1rem; }`); if (global.prefs.customize.backlog.backlogMove) { // Adjusting Backlog to be alongside TODO list monkey.addGlobalStyle(` #ghx-content-group { display: flex !important; } .ghx-backlog-container { margin-top: 0px !important; margin-left: 1rem; } .ghx-sprint-group, .ghx-backlog-group { width: 50%; max-height: 72vh !important; overflow-y: scroll; border-bottom: 2px dotted dodgerblue; } .js-sprint-container:not(:first-child) { margin-top: 2rem !important; }`); } if (global.prefs.append.scrumButtons.scrumButtonsAdd) { monkey.addGlobalStyle(` .nextPeepButton { padding-right: 0.7rem; padding-left: 0.3rem; padding-bottom: 0.3rem; position: relative; left: -0.4rem; height: 2.15rem; } `) } if (global.prefs.account.user.customCss) { monkey.addGlobalStyle(global.prefs.account.user.customCss); } } else { report.step(`already added`); } report.finish(); }, }; const mods = { user: { addChat: () => { report.start(`user.addChat`); if (!global.prefs.users.chatLinks.chatAdd) { report.step(`declined via prefs`); report.abort(); return; } if (global.states.observingChatAdds) { report.step(`already observing`); report.abort(); return; } global.states.observingChatAdds = true; const obdSelector = `.user-hover-details`; const obdCallback = () => { const chatEl = document.querySelector(`.user-chat-link`); const userEl = document.querySelector(`.user-hover-details`); const avatarEl = document.querySelector(`#avatar-full-name-link`); const summaryEl = document.getElementById(`summary-val`); const subnavEl = document.getElementById(`subnav-title`); const emailEl = document.getElementById(`user-hover-email`); let chatRef = summaryEl ? summaryEl.innerText : subnavEl ? subnavEl.innerText : ``; if (chatRef) { chatRef = `[${chatRef}](${window.location.href})`; } if (!userEl) { // report.abort(); return; } if (!chatEl) { const displayName = utils.user.properName(avatarEl.innerText); const chatLink = utils.createElement(`a`, { href: `sip:${emailEl.innerText}`, class: `user-chat-link` }); chatLink.innerText = `Chat with ${displayName}`; // chatLink.addEventListener(`click`, () => { // utils.user.chat(displayName, chatRef, emailEl.innerText); // }); userEl.appendChild(chatLink); // report.step(`added chat link`); }let demo; let sources; let initCounter = 10; const deprecatedEvents = { dropdown: [`getValue`] }; const pen = { actions: { log: (msg) => { if (demo.log !== `off`) { const logEl = pen.elements.logContent; pen.elements.logLabel.classList.add(`highlight`); setTimeout(() => { pen.elements.logLabel.classList.remove(`highlight`); }, 500); logEl.innerText = `${msg}\n${logEl.innerText}`; if (msg) console.log(msg); } }, api: { addButton: (lText, lAction) => { if (typeof lText === `string`) { const newButton = pen.utils.createElement(`button`, { role: `button`, type: `button`, class: `dds__btn dds__btn-primary dds__btn-sm dds__button dds__button--mini dds__text-truncate`, text: lText }); newButton.addEventListener(`click`, (e) => { let actionResponse; setTimeout(() => { if (lAction.length > 0) { try { actionResponse = lAction(document.querySelector(`.dds__side-nav__item`)); } catch (e) { try { actionResponse = lAction("0"); } catch (e) { try { actionResponse = lAction(["0"]); } catch (e) { try { actionResponse = lAction([0]); } catch (e) { try { actionResponse = lAction(new Date()); } catch (e) { try { actionResponse = lAction({ "alignment": "end" }); } catch (e) { try { actionResponse = lAction(0); } catch (e) { try { actionResponse = lAction(0, `descending`); } catch (e) { try { actionResponse = lAction("1"); } catch (e) { console.error(e); actionResponse = lAction(); } } } } } } } } } } else { actionResponse = lAction(); } }); if (actionResponse) pen.actions.log(actionResponse); }); pen.elements.apiContent.appendChild(newButton); } else { // presume we are moving an existing element to the pen nav pen.elements.apiContent.appendChild(lText); } } }, }, elements: { logId: `log`, apiId: `api`, }, utils: { addStyle: (styles) => { /* Create style document */ var css = document.createElement('style'); css.type = 'text/css'; if (css.styleSheet) css.styleSheet.cssText = styles; else css.appendChild(document.createTextNode(styles)); /* Append style to the tag name */ document.getElementsByTagName("head")[0].appendChild(css); }, /** * converts camelCased words into dashed-cased ones * @param {string} key - a string with some number of capitalized letters * @return {string} a dashed version of whatever string was entered */ camelDash: (key) => { return key.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()); }, /** * converts kebab-case words into camelCase ones * @param {string} key - a string with some number of dashes * @return {string} a camelCase version of whatever string was entered */ dashCamel: function (key) { return key.replace(/-[a-z]/g, (m) => m.toUpperCase().replace(/-/gi, "")); }, capitalize: (what) => { return what.charAt(0).toUpperCase() + what.slice(1); }, createElement: (nodeType, props) => { const domNode = document.createElement(nodeType); if (props && "object" === typeof props) { for (const prop in props) { if (prop === "html") { domNode.innerHTML = props[prop]; } else if (prop === "text") { domNode.textContent = props[prop]; } else { if (prop.slice(0, 5) === "aria_" || prop.slice(0, 4) === "data_") { const attr = prop.slice(0, 4) + "-" + prop.slice(5); domNode.setAttribute(attr, props[prop]); } else { domNode.setAttribute(prop, props[prop]); } } // Set attributes on the element if passed if (["role", "aria-label"].includes(prop)) domNode.setAttribute(prop, props[prop]); } } return domNode; }, random: (min = 100000000, max = 999999999) => { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min) + min); }, load: (script) => { document.write('<'+'script src="'+script+'" type="text/javascript"><' + '/script>'); }, }, initialize: () => { if (demo == null) { setTimeout(() => { initCounter--; if (initCounter > 0) { pen.initialize(); } }, 50); if (initCounter === 1) { document.getElementById(`penlay`).remove(); demo = { version: `2.14.1` }; sources = pen.addLinks(); } return; } if (demo.version) { sources = pen.addLinks(); } setTimeout(() => { document.getElementById(`penlay`).remove(); demo.components = []; const method = pen.utils.capitalize(pen.utils.dashCamel(demo.selector)); document.querySelectorAll(`[data-dds="${demo.selector}"]`).forEach((element) => { if (!element[method]) { demo.components.push(DDS[method](element, demo.options)); } else { demo.components.push(element[method]); } }); Object.keys(pen.elements).forEach(key => { if (key.indexOf(`Id`) > 0) { const elString = key.replace(`Id`, ``); pen.elements[elString] = pen.utils.createElement(`div`, { id: elString, }); if (elString === 'log' && (demo.log == null || demo.log !== `open`)) { pen.elements[elString].classList.add(`closed`); } if (elString === 'log' && (demo.log === `off` || demo.log === false)) { pen.elements[elString].classList.add(`pen__none`); } if (elString === 'api' && (demo.api == null || demo.api !== `open`)) { pen.elements[elString].classList.add(`closed`); } pen.elements[`${elString}Label`] = pen.utils.createElement(`div`, { class: `label` }); pen.elements[`${elString}Label`].innerText = elString; pen.elements[`${elString}Content`] = pen.utils.createElement(`div`, { class: `content` }); } }); Object.keys(pen.elements).forEach(key => { if (!key.match(/(Id|Label|Content)/g)) { document.querySelector(`body`).appendChild(pen.elements[key]); pen.elements[key].appendChild(pen.elements[`${key}Label`]); pen.elements[key].appendChild(pen.elements[`${key}Content`]); } if (key.indexOf(`Label`) > 0) { pen.elements[key].addEventListener(`click`, () => { pen.elements[key.replace(`Label`, ``)].classList.toggle(`closed`); }); } }); let hasDispose = false; const comp = demo.components[0]; if (comp != null) { Object.keys(comp).forEach(key => { const method = pen.utils.capitalize(pen.utils.dashCamel(demo.selector)); const selectorScript = `document.querySelector('[data-dds="${demo.selector}"]').${method}`; if (typeof comp[key] === `function`) { if (key !== `dispose`) { if (!deprecatedEvents[demo.selector] || !deprecatedEvents[demo.selector].includes(key)) { const parameterCount = comp[key].length; let comment = parameterCount > 0 ? ` // takes ${parameterCount} parameters` : ``; pen.actions.api.addButton(key, comp[key]); pen.actions.log(`${selectorScript}.${key}();${comment}`); } } else { hasDispose = true; pen.actions.log(`${selectorScript}.dispose()`); } } else { pen.actions.log(`${selectorScript}.${key} = ${comp[key]}`); } }); } pen.actions.log(`:::::::::::::::::::::::::::::::::::::::::::::::::::`); pen.actions.log(`\n\n${demo.selector} properties / methods:::::::::::::::::::::::`); hasDispose && (pen.actions.api.addButton(`dispose`, () => { comp[`dispose`](); pen.elements.api.querySelectorAll(`button`).forEach(b => b.disabled = `true`); })); demo.events.forEach((ev) => { pen.actions.log(` document.addEventListener('${ev}', (event) => { console.log(event.detail); })`); document.addEventListener(ev, (e) => { let output; pen.actions.log(`${ev} was fired with {event}.detail = ${JSON.stringify(e.detail)}`); try { output = JSON.stringify(e); pen.actions.log(output); } catch (error) { output = e; console.error(ev, output); } }); }); pen.actions.log(`::::::::::::::::::::::::::::::::::::::`); pen.actions.log(`\n${demo.selector} events:::::::::::::::::::::::`); // BEGIN LOGGING INITIALIZATION pen.actions.log(` let components = []; document.querySelectorAll('[data-dds="${demo.selector}"]').forEach((element) => { components.push(DDS.${method}(element)); }); `); sources.scripts.forEach(scrp => { pen.actions.log(`<script src="${scrp}"></script>`); }) sources.styles.forEach(styl => { pen.actions.log(`<link rel="stylesheet" crossorigin href="${styl}" />`); }) pen.actions.log(`::::::::::::::::::::::::::::::::::::::`); pen.actions.log(`\n INITIALIZATION :::::::::::::::::::::::`); }, 500); }, addLinks: () => { const links = [ `https://dds.dell.com/components/${demo.version}/css/dds-reboot.min.css`, `https://dds.dell.com/components/${demo.version}/css/dds-fonts.min.css`, `https://dds.dell.com/components/${demo.version}/css/dds-icons.min.css`, `https://dds.dell.com/components/${demo.version}/css/dds-helpers.min.css`, `https://dds.dell.com/components/${demo.version}/css/dds-main.min.css`, ]; links.forEach((href) => { let link = pen.utils.createElement(`link`, { rel: 'stylesheet', crossorigin: '', href: href, 'data-dds': 'stylesheet', }); document.querySelector(`head`).appendChild(link); }); // DOESN'T WORK pen.utils.load(`https://dds.dell.com/components/${demo.version}/js/index.min.js`); const scripts = [`https://dds.dell.com/components/${demo.version}/js/index.min.js`]; scripts.forEach((href) => { let scrp = pen.utils.createElement(`script`, { type: `text/javascript`, src: href, 'data-dds': 'script', }); document.querySelector(`head`).appendChild(scrp); }); pen.ready = true; return { styles: links, scripts: scripts, } }, removeLinks: () => { document.querySelectorAll(`[data-dds="stylesheet"]`).forEach(stylesheet => { stylesheet.remove(); }); document.querySelectorAll(`[data-dds="script"]`).forEach(script => { script.remove(); }); }, addCss: () => { pen.utils.addStyle(` body { max-width: 1900px !important; padding: 5rem 4rem !important; } #log, #api { transition: all 0.5s ease-in-out; position: absolute; z-index: 9999; height: 49vh; width: 80%; top: 50%; margin-left: 5%; color: white; background: black; font-size: 0.7rem; font-family: monospace; line-height: 0.9rem; padding: 1rem; border-bottom-right-radius: 0.625rem; } #log .label, #api .label { font-family: Roboto; background: black; color: white; position: relative; float: right; top: .7rem; left: 4rem; max-width: 6rem; min-width: 5.25rem; text-align: center; padding: 0.5rem 0.625rem; transform: rotate(-90deg); cursor: pointer; border-bottom-right-radius: 0.625rem; border-bottom-left-radius: 0.625rem; white-space: nowrap; } #log .content { position: relative; top: -2rem; width: 98%; max-height: 46vh; overflow: auto; } .highlight { background: rgb(2,0,36) !important; background: linear-gradient(180deg, rgba(2,0,36,1) 0%, rgba(9,9,121,1) 35%, rgba(0,212,255,1) 100%) !important; } #api { top: 0; height: unset; min-height: 4.55rem; background: aliceblue; padding: 0.625rem; } #api button { margin-left: 0.3rem; margin-bottom: 0.1rem; } #api .label { top: 0; background: aliceblue; color: black; font-weight: bold; } .closed { transform: translateX(-110%); } .pen__none { display: none; } .content::-webkit-scrollbar { width: 15px; } .content::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.1); border-radius: 15px; } .content::-webkit-scrollbar-thumb { border-radius: 15px; background: rgba(255, 255, 255, 0.15); } `); }, addButton: (options = { label: `label`, callback: () => {console.log(`callback`);}, target: undefined, class: undefined }, deprecated1, deprecated2, ) => { if (typeof options == `string`) { options = { label: options, callback: deprecated1, target: deprecated2, } } if (typeof options.target === 'string') { options.target = document.querySelector(options.target); } if (!options.class) { options.class = `dds__button--mini`; } const btnId = options.label.replace(/[^0-9a-zA-Z]+/, ``); const newBtn = pen.utils.createElement(`button`, { id: btnId, role: `button`, type: `button`, class: `dds__btn dds__btn-primary dds__btn-sm dds__button ${options.class} dds__text-truncate`, text: options.label, style: `margin-right: 0.625rem; margin-bottom: 0.625rem;`, }); newBtn.addEventListener(`click`, options.callback); if (!document.getElementById(btnId)) { if (options.target) { options.target.appendChild(newBtn); } else { document.querySelector(`body`).prepend(newBtn); } } }, whenReady: (callback) => { if (!pen.ready) { setTimeout(() => { pen.whenReady(callback); }, 100); } else { callback(); } }, reset: () => { const method = pen.utils.capitalize(pen.utils.dashCamel(demo.selector)); // remove element properties document.querySelectorAll(`[data-dds="${demo.selector}"]`).forEach((element) => { element[method] = undefined; }); // dispose of components demo.components.forEach(cmp => { cmp.dispose(); }); demo.components = []; // dispose of library DDS = undefined; // remove pen elements document.getElementById("log").remove(); document.getElementById("api").remove(); pen.removeLinks(); pen.ready = false; pen.showLoader(); }, showLoader: () => { const penlay = pen.utils.createElement(`div`, { id: `penlay`, style: ` background-color: white; overflow:hidden; position:absolute; top:0px; right:0px; bottom:0px; left:0px; z-index: 99999999; ` }); penlay.innerHTML = `<div class="dds__loading-indicator"> <div class="dds__loading-indicator__spinner"></div> </div>`; document.querySelector(`body`).appendChild(penlay); } }; pen.showLoader(); (() => { pen.addCss(); setTimeout(() => { pen.initialize(); }, 1000) })(); }; observers.create([{ single: false, selector: obdSelector, callback: obdCallback }]); report.finish(); }, avatars: () => { report.start(`user.avatars`); if (!global.prefs.users.avatars.avatarsMod) { report.step(`declined via prefs`); report.abort(); return; } if (global.states.observingAvatars) { report.step(`already observing`); report.abort(); return; } global.states.observingAvatars = true; if (!global.states.avatarPingFailed && pingPhoto != null && global.prefs.users.avatars.avatarsSources[0] === `localhost`) { report.step(`Using localhost avatars`); monkey.ping(avatarHost + pingPhoto + imageExt, function callback(response) { if (response === `responded`) { global.states.avatarPingFailed = false; } else { report.step(`avatar ping failed`, false); global.states.avatarPingFailed = true; } // global.mems.avatarPingTimer = moment(); // monkey.savePreferences(global.ids.memsName, global.mems); }); } let thisName = `none`; const swapAvatar = (element, avatar) => { let inst = element.tagName === `IMG` ? element : avatar.getImgSource(avatar.element); thisName = utils.user.properName(avatar.getNameSource(inst)); thisName && utils.user.updateImg(inst, thisName); inst.onerror = () => { const prevSrc = inst.getAttribute(`data-previous`); const noSrc = `http://${avatarHost}!none${imageExt}` inst.src = prevSrc || noSrc; } inst.src = inst.src; }; const guessName = (el) => { if (!el) return null; if (el.alt) return el.alt; if (el.getAttribute(`alt`)) return el.getAttribute(`alt`); if (el.getAttribute(`title`)) return el.getAttribute(`title`); if (el.getAttribute(`data-tooltip`)) return el.getAttribute(`data-tooltip`); if (el.innerText) return el.innerText; if (el.parentElement.innerText) return el.parentElement.innerText; if (document.getElementById(`up-user-title-name`)) return document.getElementById(`up-user-title-name`).innerText; }; const observerDefinitions = [{ single: false, meta: `Hover menu avatars (ie those who voted)`, selector: `.user-hover img`, getImgSource: null, getNameSource: guessName, callback: swapAvatar, }, { single: false, meta: `Releases Page`, selector: `.author-avatar-wrapper img`, getImgSource: null, getNameSource: guessName, callback: swapAvatar, }, { single: false, meta: `Backlog Avatars`, selector: `.ghx-avatar-img`, getImgSource: null, getNameSource: guessName, callback: swapAvatar, }, { single: false, meta: `Item small avatars`, selector: `.aui-avatar-inner img`, getImgSource: null, getNameSource: guessName, callback: swapAvatar, }, { single: false, meta: `Profile Page Edit Avatar`, selector: `#avatar-owner-id`, getImgSource: (el) => { return document.querySelector(`${el} img`); }, getNameSource: guessName, callback: swapAvatar, }, { single: false, meta: `User details page, User Icon in Activity Feed`, selector: `span.user-icon img`, getImgSource: null, getNameSource: guessName, callback: swapAvatar, }, { single: false, meta: `User Avatar in Tooltip`, selector: `.avatar-image`, getImgSource: null, getNameSource: guessName, callback: swapAvatar, }]; observerDefinitions.forEach(obd => { report.step(`Observing ${obd.selector}`); document.querySelectorAll(obd.selector).forEach(el => { swapAvatar(el, obd); }) }); observers.create(observerDefinitions); report.finish(); }, }, customize: { addFaves: () => { report.start(`customize.addFaves`); if (!global.prefs.customize.mainMenu.menuAdd || !global.prefs.customize.mainMenu.menuAdditions || global.prefs.customize.mainMenu.menuAdditions.length === 0) { report.step(`declined via prefs`); report.abort(); return; } const header = document.querySelector(`.aui-header-inner`); if (header && header.querySelectorAll(`.faveLink`).length > 0) { report.step(`already performed`); report.abort(); return; } global.prefs.customize.mainMenu.menuAdditions.forEach(fave => { const fButton = utils.createElement(`button`, { 'class': `dds__button dds__button--sm faveLink ${fave.class}`, 'aria-label': fave.name, 'title': fave.name, }); fButton.innerHTML = fave.icon ? `<i class="dds__icon dds__icon--${fave.icon}"></i>` : fave.name; fButton.addEventListener(`click`, (e) => { document.location.href = fave.url; }); if (header) { header.appendChild(fButton); } }) report.finish(); }, modMainLogo: () => { report.start(`customize.modMainLogo`); if (!global.prefs.customize.mainLogo.logoMod || global.prefs.customize.mainLogo.logoSrc.length === 0) { report.step(`declined via prefs`); report.abort(); return; } const logoEl = document.querySelector(`#logo`); const logoImg = document.querySelector(`#logo img`); if (logoEl.classList.contains(`modModified`)) { report.step(`already performed`); report.abort(); return; } logoEl.classList.add(`modModified`); logoEl.style.marginRight = `0`; logoImg.style.width = `32px`; logoImg.src = global.prefs.customize.mainLogo.logoSrc; report.step(`modified main logo`); report.finish(); }, modMainMenu: () => { report.start(`customize.modMainMenu`); if (!global.prefs.customize.mainMenu.menuMod || (global.prefs.customize.mainMenu.menuModifications && global.prefs.customize.mainMenu.menuModifications.length < 1)) { report.step(`declined via prefs`); report.abort(); return; } const moddedMenus = document.querySelectorAll(`.aui-header-primary a.aui-dropdown2-trigger .modModified`); const menus = document.querySelectorAll(`.aui-header-primary a.aui-dropdown2-trigger:not(.modModified)`); if (menus.length === 0 || moddedMenus.length > 0) { report.step(`already performed`); report.abort(); return; } menus.forEach(ahref => { ahref.classList.add(`modModified`); global.prefs.customize.mainMenu.menuModifications.forEach(iconSwap => { if (ahref.innerText.trim().toLowerCase() === iconSwap.text.toLowerCase()) { const newIcon = utils.createElement(`i`, { class: `dds__icon dds__icon--${iconSwap.icon}`, title: ahref.innerText, }); ahref.innerText = ``; ahref.appendChild(newIcon); report.step(`added icon for ${iconSwap.text}`) } }); }) report.finish(); }, moveComments: () => { report.start(`customize.moveComments`); if (!global.prefs.customize.comments.commentsMove) { report.step(`declined via prefs`); report.abort(); return; } const activityId = `activitymodule`; const addCommentId = `addcomment`; const sidebarId = `viewissuesidebar`; const peopleModuleId = `peoplemodule`; const addComment = document.querySelector(`#${addCommentId}`); const activity = document.querySelector(`#${activityId}`); const sidebar = document.querySelector(`#${sidebarId}`); const peopleModule = document.querySelector(`#${peopleModuleId}`); if (sidebar && !sidebar.querySelector(`#${addCommentId}`)) { sidebar.prepend(addComment); sidebar.prepend(activity); sidebar.prepend(peopleModule); report.step(`comments/activity moved`); } else if (sidebar && sidebar.querySelector(`#${addCommentId}`)) { report.step(`already successful`); } else if (!sidebar) { report.step(`nothing to rearrange`); } report.finish(); }, removeLinks: () => { report.start(`customize.removeLinks`); if (!global.prefs.customize.mainMenu.menuRemove || !global.prefs.customize.mainMenu.menuRemovals || global.prefs.customize.mainMenu.menuRemovals.length === 0) { report.step(`declined via prefs`); report.abort(); return; } const header = document.querySelector(`.aui-header-inner`); if (header && header.querySelectorAll(`.removedLink`).length > 0) { report.step(`already performed`); report.abort(); return; } global.prefs.customize.mainMenu.menuRemovals.forEach(fave => { const removalEl = utils.getElementByTextContent(fave, `a`); if (removalEl) { removalEl.classList.add(`removedLink`); report.step(`removed ${fave}`); } }) report.finish(); }, shortLists: () => { report.start(`customize.shortLists`); if (!global.prefs.customize.lists.listsShorten) { report.step(`declined via prefs`); report.abort(); return; } if (!global.prefs.account.project.code) { report.step(`Project Code not set up in option`, false); report.abort(); return; } const listEls = document.querySelectorAll(`span.issue-link-key`); if (listEls.length > 0) { report.step(`adjusting list display`); listEls.forEach(il => { il.innerText = il.innerText.replace(`${global.prefs.account.project.code}-`, ``); }); } else { report.step(`no lists to modify`); } report.finish(); }, collapseBotPosts: () => { report.start(`customize.collapseBotPosts`); if (!global.prefs.customize.posts.postsCloseBots) { report.step(`declined via prefs`); report.abort(); return; } const posts = document.querySelectorAll(`.activity-comment.expanded`); report.step(`Found ${posts.length} posts`); let moddedCount = 0; posts.forEach(p => { if (!p.classList.contains(`autoCollapsed`) && p.innerText.indexOf(`svc_prddeveloperexp`) > -1) { try { p.querySelector(`button`).click(); report.step(`collapsing botPost`); p.classList.add(`autoCollapsed`); moddedCount++; } catch (e) { report.step(`Couldn't collapse. ${e}`); } } }) report.step(`Modded ${moddedCount} posts`); report.finish(); }, filterTitles: () => { report.start(`customize.filterTitles`); if (!global.prefs.customize.posts.filterTitles) { report.step(`declined via prefs`); report.abort(); return; } const filterTitle = (nModule) => { const iconsToAdd = []; let customColor = `#e31c79`; // a hot pink because yes global.prefs.customize.posts.filterTitlesPairs.forEach(pair => { if (pair.color) { customColor = pair.color; } if (nModule.innerText.indexOf(pair.match) > -1) { if (pair.icon) { nModule.innerText = nModule.innerText.replace(pair.match, ``); iconsToAdd.push(utils.createElement(`i`, { class: `dds__icon dds__icon--${pair.icon} dds__mr-1`, title: pair.match, style: `color: ${customColor};`, })); } else { nModule.innerText = nModule.innerText.replace(pair.match, pair.replace); } } }); iconsToAdd.forEach(icon => { nModule.prepend(icon); }) }; const selectors = [ `.ghx-summary`, `.ghx-detail-description`, `#summary-val`, `.ghx-description`, ]; selectors.forEach(selector => { document.querySelectorAll(selector).forEach(nModule => { filterTitle(nModule); }); }); report.finish(); }, epicPills: () => { report.start(`customize.epicPills`); if (!global.prefs.customize.posts.epicPills) { report.step(`declined via prefs`); report.abort(); return; } document.querySelectorAll(`.ghx-label:not(.pill)`).forEach(nodeMod => { let acro = utils.acronym(nodeMod.innerText); let version = nodeMod.innerText.match(/(\d{1,}).*(\d{1,})/g); if (!version) version = ``; if (acro.length > 3) { acro = acro.substring(0, 3); } nodeMod.classList.add(`pill`); nodeMod.innerText = acro + version; }) report.finish(); }, keyLinkPills: () => { report.start(`customize.keyLinkPills`); if (!global.prefs.customize.posts.keyLinkPills) { report.step(`declined via prefs`); report.abort(); return; } const notPills = document.querySelectorAll(`.js-key-link:not(.pill)`); notPills.forEach(nodeMod => { let inrText = nodeMod.innerText; nodeMod.classList.add(`pill`); const badge = utils.createElement(`span`, { class: `dds__badge dds__badge--sm dds__badge--gray`, }); const label = utils.createElement(`span`, { class: `dds__badge__label`, }); label.innerText = inrText.replace(`${global.prefs.account.project.code}-`, ``); nodeMod.innerText = ``; badge.appendChild(label) nodeMod.appendChild(badge) }) report.finish(); }, }, autofill: { defect: () => { report.start(`autofill.defect`); let fields = []; if (!global.prefs.automation.forms.formsFill || global.prefs.automation.forms.formsSelectors.length === 0) { report.step(`declined via prefs`); report.abort(); return; } global.prefs.automation.forms.formsSelectors.forEach(afill => { if (!afill.identifier || document.querySelector(afill.identifier)) { fields = [ ...fields, ...afill.fields, ] } else { report.step(`${afill.identifier} not open at this time`); } }); if (fields.length > 0) { fields.forEach(field => { const fieldEl = document.getElementById(field.id); if (fieldEl && (fieldEl.value.length === 0 || fieldEl.value === `-1`)) { fieldEl.value = field.value; } else { report.step(`already done for ${field.id}`); } }); } report.finish(); }, searchbar: () => { report.start(`autofill.searchbar`); if (!global.prefs.automation.searchbar.searchFill) { report.step(`declined via prefs`); report.abort(); return; } if (!global.prefs.account.project.name) { report.step(`Project Name not set up in option`, false); report.abort(); return; } if (window.location.href.indexOf(`issues/`) < 0) { report.step(`No need to run on this page`); report.abort(); return; } const projectEl = document.querySelector(`div[data-id="project"]:not(.active)`); if (projectEl && projectEl.innerText.match(/All/g)) { report.step(`populating project selection`); projectEl.click(); setTimeout(() => { const projectOptionEl = document.querySelector(`label[title="${global.prefs.account.project.name}"]`); projectOptionEl.click(); projectEl.click(); }, 500); } else { report.step(`Unable to set project selection`, false); } report.finish(); }, }, append: { addKeys: () => { report.start(`interface.addKeys`); if (!global.prefs.append.keys.useKeys) { report.step(`declined via prefs`); report.abort(); return; } if (global.states.keysAdded) { report.step(`already added`); report.abort(); return; } global.states.keysAdded = true; let modalApi; let dropdownApi; const handleDropdownChange = (e) => { if (!e.detail.value) { return; } monkey.copyTextToClipboard(e.detail.value); dropdownApi.clearSelection(); modalApi.close(); }; const defineShortcut = (userDefinedShortcut) => { let keyMeta = { ctrl: undefined, // only used to parse, later control: false, shift: false, alt: false, }; let shortcut = userDefinedShortcut; if (shortcut.match(/control/gi)) { keyMeta.control = true; } if (shortcut.match(/ctrl/gi)) { keyMeta.control = true; } if (shortcut.match(/shift/gi)) { keyMeta.shift = true; } if (shortcut.match(/alt/gi)) { keyMeta.alt = true; } Object.keys(keyMeta).forEach(key => { // const regcheck = new RegExp(key, 'gi'); // if (shortcut.match(regcheck)) { // keyMeta[key] = true; // } shortcut = shortcut.toUpperCase().replace(key.toUpperCase(), ``); }); shortcut = shortcut.replace(/-/gi, ``); shortcut = shortcut.replace(/\+/gi, ``).trim(); shortcut = shortcut.charCodeAt(0); return { value: shortcut, ...keyMeta, }; }; const showTemplateMenu = () => { modalApi.open(); }; const addTemplateModal = () => { const sId = `templatesModal`; const sModal = utils.createElement(`div`, { id: sId, role: `dialog`, class: `dds__modal ddsc__modal`, 'aria-labelledby': `${sId}-header` }); const sContent = utils.createElement(`div`, { class: `dds__modal__content`, }); const sHeader = utils.createElement(`div`, { class: `dds__modal__header`, }); const sH3 = utils.createElement(`h3`, { id: `${sId}-header`, class: `dds__modal__title`, innerText: `Select a template to copy`, }); const sBody = utils.createElement(`div`, { id: `${sId}-body`, class: `dds__modal__body`, style: `min-height: 50vh;`, }); addTemplateDropdown().then((newDropdown) => { sModal.appendChild(sContent); sContent.appendChild(sHeader); sContent.appendChild(sBody); sHeader.appendChild(sH3); sBody.appendChild(newDropdown); document.querySelector(`body`).appendChild(sModal); setTimeout(() => { const el = document.getElementById(sId).querySelector(`[data-dds="dropdown"]`); dropdownApi = DDS.Dropdown(el); modalApi = DDS.Modal(document.getElementById(sId)); dropdownApi.element.addEventListener(`ddsDropdownSelectionChangeEvent`, handleDropdownChange) }); }); }; const addTemplateDropdown = async () => { const dId = `templateDropdown`; const dDropdown = utils.createElement(`div`, { id: dId, class: `dds__dropdown`, 'data-dds': `dropdown`, 'data-selection': `single`, }); const dContainer = utils.createElement(`div`, { class: `dds__dropdown__input-container`, }); const dLabel = utils.createElement(`label`, { id: `${dId}-label`, for: `${dId}-input`, innerText: `Select a template`, }); const dInputWrapper = utils.createElement(`div`, { class: `dds__dropdown__input-wrapper`, autocomplete: `off`, role: `combobox`, 'aria-haspopup': `listbox`, 'aria-controls': `${dId}-popup`, 'aria-expanded': `false`, }); const dInput = utils.createElement(`input`, { id: `${dId}-input`, name: `${dId}-name`, type: `text`, class: `dds__dropdown__input-field`, autocomplete: `off`, 'aria-labelledby': `${dId}-label ${dId}-helper`, 'aria-expanded': `false`, 'aria-controls': `${dId}-list`, }); const dSmall = utils.createElement(`small`, { id: `${dId}-helper`, class: `dds__input-text__helper`, }); const dPopup = utils.createElement(`div`, { id: `${dId}-popup`, class: `dds__dropdown__popup dds__dropdown__popup--hidden`, role: `presentation`, tabindex: `-1`, }); const templateDropdown = addTemplateOptions(dId).then((responseEl) => { dDropdown.appendChild(dContainer); dContainer.appendChild(dLabel); dContainer.appendChild(dInputWrapper); dInputWrapper.appendChild(dInput); dInputWrapper.appendChild(dSmall); // dInputWrapper.appendChild(dFeedback); dContainer.appendChild(dPopup); dPopup.appendChild(responseEl); return dDropdown; }); return templateDropdown; }; const addTemplateOptions = async (dropdownId) => { const dUl = utils.createElement(`ul`, { id: `${dropdownId}-list`, class: `dds__dropdown__list`, role: `listbox`, tabindex: `-1`, }); const dansJsonServerToken = `3579afef7ef98a51d0c37ac6de3e2c93`; const urlPart = `jiradork`; const xhrRequest = await utils.xhrRequest(`GET`, `https://api.jsonserver.io/${urlPart}`, undefined, dansJsonServerToken); JSON.parse(xhrRequest.response).templates.forEach(template => { let templateOption = template.option.replace(`INVALID_EXPRESSION: `, ``); let templateSnippet = template.snippet.replace(`INVALID_EXPRESSION: `, ``); const dLi = utils.createElement(`li`, { class: `dds__dropdown__item`, role: `none`, }); const dButton = utils.createElement(`button`, { type: `button`, class: `dds__dropdown__item-option`, role: `option`, tabindex: `-1`, 'data-selected': `false`, 'data-value': templateSnippet, }); const dSpan = utils.createElement(`span`, { class: `dds__dropdown__item-label`, innerText: templateOption, }); dUl.appendChild(dLi); dLi.appendChild(dButton); dButton.appendChild(dSpan); }); /* const finishUpdating = (genRes) => { genRes = JSON.parse(genRes); const result = genRes.gender ? genRes.gender : `initials`; templateSrc = templateSrc.replace(global.prefs.users.avatars.avatarsType, result); templateSrc = encodeURI(templateSrc.substr(templateSrc.indexOf('http'), (templateSrc.indexOf('alt=') - templateSrc.indexOf('http')) - 2)); img.setAttribute('src', templateSrc); }; */ return dUl; }; const handleKeyUp = (e) => { const thisKey = defineShortcut(global.prefs.append.keys.templateMenu); var keyCodes = [ { value: thisKey.value, ctrl: thisKey.control, alt: thisKey.alt, shift: thisKey.shift, method: showTemplateMenu, } ]; keyCodes.forEach(code => { if (e.keyCode === code.value && e.ctrlKey === code.ctrl && e.altKey === code.alt) { code.method.call(); }; }); }; addTemplateModal(); document.removeEventListener(`keyup`, handleKeyUp); document.addEventListener(`keyup`, handleKeyUp); report.finish(); }, copyLink: () => { report.start(`append.copyLink`); if (!global.prefs.append.copyLinks.copyLinksAdd) { report.step(`declined via prefs`); report.abort(); return; } const linkSelectors = [ `.aui-nav-breadcrumbs .issue-link`, `.issuerow .summary .issue-link`, `a.js-key-link`, `a[title="View this issue"]` ]; const links = []; linkSelectors.forEach(linkSelector => { const linkElement = document.querySelectorAll(linkSelector); links.push(linkElement); }); const appendLink = (ilink) => { if (ilink.parentElement.querySelectorAll(`.copyLink`).length > 0) { report.step(`Already added for ${ilink.classList}`); return; } const cicon = utils.createElement(`i`, { class: `dds__icon dds__icon--copy-alt` }); const clink = utils.createElement(`span`, { class: `copyLink`, title: `Copy link as Markdown. Double-click to copy for Gitlab TEXT`, }); clink.appendChild(cicon); clink.addEventListener(`click`, (e) => { const liEl = e.target.closest(`li`); const breadcrumbEl = e.target.closest(`.aui-nav-breadcrumbs`); const summaryEl = document.getElementById(`summary-val`); const sidebarEl = e.target.closest(`#ghx-detail-contents`); const cardEl = e.target.closest(`.js-issue`); const inSidebar = sidebarEl != null; const inDraggable = cardEl != null; const onDetailPage = window.location.href.indexOf(`browse`) > -1 || window.location.href.indexOf(`issues/`) > -1; let linkText; if ((onDetailPage && liEl && liEl.querySelector(`#parent_issue_summary`)) && ilink.getAttribute(`title`)) { linkText = ilink.getAttribute(`title`); // parent issue (ie we're looking at a Task of a Story) } else if (summaryEl && (onDetailPage || inSidebar)) { linkText = summaryEl.innerText; } else if (inDraggable) { linkText = cardEl.querySelector(`.ghx-summary`).innerText; } else { linkText = ilink.innerText; } linkText = linkText.replace(/\[/g, `#`).replace(/]/g, ``); // convert bracketed text to #tags const textToCopy = `[${linkText}](${ilink.href})`; monkey.copyTextToClipboard(textToCopy); }); clink.addEventListener(`dblclick`, () => { let linkText = `JIRA#${ilink.innerText};`; const linkTextSpaceIndex = linkText.indexOf(` `); if (linkTextSpaceIndex > -1) { linkText = linkText.substring(0, linkTextSpaceIndex) + `;`; } const textToCopy = linkText; // `[${linkText}](${ilink.href})`; monkey.copyTextToClipboard(textToCopy); }); ilink.parentElement.appendChild(clink); report.step(`added copyLink for ${ilink}`); }; links.forEach(nodeList => { nodeList.forEach(ilink => appendLink(ilink)); }); if (links.length === 0) { report.step(`no link modification needed`); } report.finish(); }, swimButtons: () => { report.start(`append.swimButtons`); if (!global.prefs.append.collapseButtons.collapseButtonsAdd) { report.step(`declined via prefs`); report.abort(); return; } document.querySelectorAll(`.monkeyButton`).forEach(mb => { mb.classList.remove(`dds__d-none`); }); if (window.location.href.indexOf(`chart=`) > 0) { document.querySelectorAll(`.monkeyButton`).forEach(mb => { mb.classList.add(`dds__d-none`); }); report.step(`not needed on chart page`); report.abort(); return; } if (document.querySelector(`.collapseAllLanes`)) { report.step(`swimlane controls already created`); report.abort(); return; } // ADD COLLAPSE BUTTON const filterControlEl = document.querySelector(`#ghx-operations`); if (!filterControlEl) { report.step(`nothing to attach controls`); report.abort(); return } const btnCollapseLanes = utils.createElement(`button`, { class: `dds__button dds__button--sm monkeyButton collapseAllLanes`, }); btnCollapseLanes.innerText = `Collapse`; const handleCollapse = () => { document.querySelectorAll(`.ghx-swimlane:not(.ghx-closed)`).forEach(lane => { lane.querySelector(`.ghx-heading-expander`).click(); }); document.querySelectorAll(`.ghx-expander:not([aria-expanded="false"]`).forEach(sprint => { sprint.click(); }); }; btnCollapseLanes.addEventListener(`click`, handleCollapse); filterControlEl.prepend(btnCollapseLanes); // ADD EXPAND BUTTON const btnExpandLanes = utils.createElement(`button`, { class: `dds__button dds__button--sm monkeyButton expandAllLanes`, }); btnExpandLanes.innerText = `Expand`; const handleExpand = () => { document.querySelectorAll(`.ghx-closed`).forEach(lane => { lane.querySelector(`.ghx-heading-expander`).click(); }); document.querySelectorAll(`.ghx-expander:not([aria-expanded="true"]`).forEach(sprint => { sprint.click(); }); }; btnExpandLanes.addEventListener(`click`, handleExpand); filterControlEl.prepend(btnExpandLanes); report.finish(); }, voteButtons: () => { report.start(`append.voteButtons`); if (!global.prefs.append.voteButtons.voteButtonsAdd) { report.step(`declined via prefs`); report.abort(); return; } const issueRows = document.querySelectorAll(`.issuerow`); if (issueRows.length === 0) { report.step(`no rows to add vote buttons to`); report.abort(); return; } issueRows.forEach(row => { const rowActionCell = row.querySelector(`.qrf-issue-actions`); const issueId = row.getAttribute(`data-issue-key`); if (rowActionCell && !rowActionCell.querySelector(`.addVoteBtn`)) { const btnIcon = utils.createElement(`i`, { class: `dds__icon dds__icon--add-cir`, style: `pointer-events: none;`, title: `Add your vote for this issue`, }); const btn = utils.createElement(`button`, { class: `dds__button dds__button--mini addVoteBtn`, }); btn.appendChild(btnIcon); btn.addEventListener(`click`, (e) => { const dotMenu = e.target.parentElement.querySelector(`.qrf-issue-actions-trigger`); dotMenu.click(); setTimeout(() => { monkey.getContainer({ 'el': `.qrf-ia-vote-issue`, 'max': 100, 'spd': 1000 }).then(function (el) { el.click(); }); }, 500); }); rowActionCell.appendChild(btn); } else { report.step(`already added vote buttons`); } }); report.finish(); }, scrumButtons: () => { report.start(`append.scrumButtons`); if (!global.prefs.append.scrumButtons.scrumButtonsAdd) { report.step(`declined via prefs`); report.abort(); return; } const filterControlEl = document.querySelector(`#ghx-operations`); if (!filterControlEl) { report.step(`nothing to attach controls`); report.abort(); return } if (document.querySelector(`.scrumButton`)) { report.step(`already added`); report.abort(); return; } let currentPeep = 0; let peeps = []; let todaysPeeps = []; const selectNextPeep = () => { if (currentPeep === todaysPeeps.length && todaysPeeps.length > 0) { stopScrum(); return; } if (document.querySelectorAll(`[data-scrum="${currentPeep}"]`).length === 0) { clearOtherFilters(); } let finalDelay = 0; let msDelay = 400; const peepEls = document.querySelectorAll(`[title^="assignee"]`); const activePeepEls = document.querySelectorAll(`.ghx-active[title^="assignee"]`); if (peeps.length === 0) { peepEls.forEach(el => { peeps.push(el.innerText.trim()); }); } if (todaysPeeps.length === 0) { todaysPeeps = utils.shuffle(peeps); todaysPeeps.forEach((peep, i) => { peepEls.forEach(el => { if (el.innerText.trim() === peep) { const numspan = utils.createElement(`span`, { innerText: ` ${i + 1}`, class: `peepNumber`, }); el.appendChild(numspan); el.setAttribute(`data-scrum`, i); } }); }) } activePeepEls.forEach((b, i) => { // deselect all active setTimeout(() => { b.click(); }, i * msDelay); finalDelay++; }); setTimeout(() => { const currentPeepButton = document.querySelector(`[data-scrum="${currentPeep}"]`) addCurrentPeepNextButton(currentPeep); currentPeepButton.click(); currentPeep++; }, finalDelay * msDelay); }; const addCurrentPeepNextButton = (currentPeep) => { const currentPeepButton = document.querySelector(`[data-scrum="${currentPeep}"]`); const isAtEnd = currentPeep === document.querySelectorAll(`[title^="assignee"]`).length - 1; const btnIcon = isAtEnd ? `close-x` : `chevron-right`; document.querySelectorAll(`.nextPeepButton`).forEach(npb => npb.remove()); const newNextPeepButton = utils.createElement(`button`, { class: `dds__button dds__button--sm nextPeepButton`, }); const npbIcon = utils.createElement(`i`, { class: `dds__icon dds__icon--${btnIcon}`, style: `min-height: 1.5rem; padding: 0.3rem 0.3rem 0 0.3rem;` }); newNextPeepButton.appendChild(npbIcon); currentPeepButton.parentElement.appendChild(newNextPeepButton); if (!isAtEnd) { newNextPeepButton.addEventListener(`click`, selectNextPeep); } else { newNextPeepButton.addEventListener(`click`, stopScrum); } }; const clearOtherFilters = () => { let msDelay = 40; const activeFilters = document.querySelectorAll(`.ghx-active:not([title^="assignee"])`); activeFilters.forEach((el, i) => { setTimeout(() => { el.click(); }, i * msDelay); }); }; const stopScrum = () => { document.querySelector(`.nextPeepButton`).remove(); document.querySelectorAll(`.peepNumber`).forEach(el => el.remove()); document.querySelectorAll(`[title^="assignee"]`).forEach(el => { if (el.classList.contains(`ghx-active`)) { el.click(); } el.removeAttribute(`data-scrum`); }); currentPeep = 0; peeps = []; todaysPeeps = []; } const btnScrum = utils.createElement(`button`, { class: `dds__button dds__button--sm scrumButton`, }); btnScrum.innerText = `Scrum`; const iconScrum = utils.createElement(`i`, { class: `dds__icon dds__icon--refresh-spin`, style: `min-height: 1.5rem; padding: 0.3rem 0.3rem 0 0.3rem;` }); btnScrum.appendChild(iconScrum); btnScrum.addEventListener(`click`, selectNextPeep); filterControlEl.prepend(btnScrum); report.finish(); }, } }; (function () { // Global Functions let runOnThisSite = false; global.prefs.account.urls.runOn.forEach(runUrl => { if (window.location.href.indexOf(runUrl) > -1) { runOnThisSite = true; } }); if (runOnThisSite) { document.onmousemove = function () { if (!global.states.isMouseMoved) { global.states.isMouseMoved = true; setTimeout(function () { global.states.isMouseMoved = false; }, global.constants.TIMEOUT * 2); if (global.prefs.account.enabled.isEnabled) { utils.initScript(); } } }; } })(); // Global Functions })(); });