// ==UserScript== // @name OdooTasksLinks // @original https://greasyfork.org/es/scripts/390531-tgithub // @author Eduardo de Miguel // @version 16.0.3 // @grant none // @run-at document-idle // @namespace moduon // @include /^https?:\/\/(?:www\.)?github\.com\/?.*$/ // @include /^https?:\/\/(?:www\.)?gitlab\.com\/?.*$/ // @include /^https?:\/\/(?:www\.)?gitlab\.moduon\.team\/?.*$/ // @include /^https?:\/\/(?:www\.)?moduon\.team\/?.*$/ // @include /^https?:\/\/(?:www\.)?loom\.com\/?.*$/ // @include /^https?:\/\/(?:www\.)?youtube\.com\/?.*$/ // @include /^https?:\/\/(?:www\.)?odoo\.com\/?.*$/ // @description Adds some features on github.com, gitlab.com, moduon.team, loom.com and youtube.com to integrate it with Moduon Team and Odoo // @downloadURL https://update.greasyfork.icu/scripts/439410/OdooTasksLinks.user.js // @updateURL https://update.greasyfork.icu/scripts/439410/OdooTasksLinks.meta.js // ==/UserScript== /* jshint esversion: 6 */ (function (window) { "use strict"; var MTTaskLinks = { ODOO_SERVER: 'https://www.moduon.team', COMPANY_NAME: 'Moduon', COPY_REF_BUTTON_ID: 'OTL_copy_ref', MENU_ID: 256, ACTION_ID: 387, REGEX_TEMPLATES: {}, QUERY_SELECTORS: { 'github': ['.markdown-body'], 'gitlab': ['.note-text', '.description', '.commit-box>.commit-description'], 'moduon': ['.o_Message_prettyBody', '.o_Activity_summary', '.o_Activity_note'], // '.o_field_html:not(:has(> lt-highlighter))' 'loom': ['.below-video>span>span'], 'youtube': ['div[id="title"]>h1.ytd-watch-metadata>yt-formatted-string.ytd-watch-metadata', 'span[id="plain-snippet-text"]', 'yt-formatted-string[id="content-text"]'], 'odoo': ['div#card_body'], // Unable to track messages due to post-load of page }, COMMON_QUERY_SELECTORS: '.commit-description,', init: function () { this._addRegexTemplate('MT', new RegExp(/\bMT-(\d+)/gi), `${this.COMPANY_NAME} - Task #$1`); this._addRegexTemplate('OPW', new RegExp(/\bOPW-(\d+)/gi), `Odoo - Ticket #$1`); this._replaceTask(); if (this._isLocationHost('github')) { this._ghAddNavbarOptions(); }else if (this._isLocationHost('moduon')) { this._moduonAddNavbarOptions(); } }, /* CORE FUNCTIONS */ _isLocationHost: function (host) { return this._getLocationHost().includes(host); }, _getLocationHost: function() { return document.location.host.toLowerCase(); }, _addRegexTemplate: function (templateName, regex, html) { this.REGEX_TEMPLATES[templateName] = { regex: regex, html: html }; }, _executeRegexReplace: function (templateName, text) { if (templateName in this.REGEX_TEMPLATES && text.match(this.REGEX_TEMPLATES[templateName].regex)) { return text.replace(this.REGEX_TEMPLATES[templateName].regex, this.REGEX_TEMPLATES[templateName].html); } return false; }, /* COMMON FUNCTIONS */ _replaceTask: function () { const searchAndParse = () => { var hostQuerySelector = this.QUERY_SELECTORS[this._getLocationHost()] ? this.QUERY_SELECTORS[this._getLocationHost()].join(',') : Object.values(this.QUERY_SELECTORS).map(function(v){return v.join(',')}).join(','); // Replace Company Links document.querySelectorAll(this.COMMON_QUERY_SELECTORS + hostQuerySelector).forEach((elm) => { const htmlTemplate = this._executeRegexReplace('MT', elm.innerHTML); if (htmlTemplate) { elm.innerHTML = htmlTemplate; } }); // Replace Odoo Links document.querySelectorAll(this.COMMON_QUERY_SELECTORS + hostQuerySelector).forEach((elm) => { const htmlTemplate = this._executeRegexReplace('OPW', elm.innerHTML); if (htmlTemplate) { elm.innerHTML = htmlTemplate; } }); }; // Mutation Observer if (typeof this.observer === 'undefined') { let targetNode; if (this._isLocationHost('github')) { targetNode = document.getElementsByTagName('main')[0]; } else if (this._isLocationHost('gitlab')) { targetNode = document.getElementById('notes-list'); if (!targetNode){ targetNode = document.getElementsByClassName('js-pipeline-container')[0]; // Pipelines } } else if (this._isLocationHost('moduon')) { targetNode = document.getElementsByClassName('o_web_client')[0]; } else if (this._isLocationHost('loom')) { targetNode = document.getElementsByClassName('mainContent')[0]; } else if (this._isLocationHost('youtube')) { targetNode = document.getElementById('content'); } if (typeof targetNode !== 'undefined') { this.observer = new MutationObserver(searchAndParse); this.observer.observe(targetNode, { childList: true, subtree: true }); } } searchAndParse(); }, /* GITHUB FUNCTIONS */ _ghAddNavbarOptions: function () { const targetNode = document.getElementsByTagName('nav')[0]; if (typeof targetNode !== 'undefined') { const exampleItem = targetNode.querySelector("a[href^='/pulls']"); const menuItem = document.createElement("A"); menuItem.className = exampleItem.className; menuItem.style.cssText = exampleItem.style.cssText menuItem.textContent = this.COMPANY_NAME; menuItem.href = `/pulls?q=is%3Aopen+is%3Apr+archived%3Afalse+involves%3A${this.COMPANY_NAME}`; targetNode.insertAdjacentElement('afterbegin', menuItem); } }, _moduonAddNavbarOptions: function () { let moduonObserver = new MutationObserver((mutations) => { const in_project_task = window.location.href.includes("model=project.task"); const is_project_task = window.location.href.includes("id="); if (in_project_task && is_project_task) { mutations.forEach((mutation) => { if (!mutation.addedNodes) return for (let i = 0; i < mutation.addedNodes.length; i++) { try { if (mutation.addedNodes[i].querySelector(".o_statusbar_buttons")) { if (document.getElementById(this.COPY_REF_BUTTON_ID)) return const statusBar = document.getElementsByClassName("o_statusbar_buttons")[0]; const copyButton = document.createElement("button"); copyButton.className = 'btn btn-light'; copyButton.type = 'button'; copyButton.title = 'Copy Task Reference'; copyButton.id = this.COPY_REF_BUTTON_ID; copyButton.innerHTML = "Copiar MT"; copyButton.onclick = function(){ let params = window.location.hash.replaceAll("#", "").split("&"); for (let p of params) { if (p.startsWith("id=")){ navigator.clipboard.writeText("MT-" + p.slice(3)); break; } } this.innerHTML = "¡Copiado!"; } statusBar.insertAdjacentElement('afterbegin', copyButton); this.moduonObserver.disconnect(); } } catch (e) {} } }) } }) moduonObserver.observe(document.body, { childList: true, subtree: true, attributes: false, characterData: false }) }, }; MTTaskLinks.init(); })(window)