Search code examples
javascripthtmljquerygmailtampermonkey

How to stop gmail from opening the email when I click the button I added to it with tampermonkey?


I did this tampermonkey script to parse my gmail inbox items and add a button linking to our Redmine Issue Tracker, so I can open the thread without having to open the email. This button I added, immediately open a new tab and switch focus to it. enter image description here

It works fine, except that every time I click the button, it also opens the email on the Gmail page/browser tab. To fix this, I added a setTimeout(function() { window.history.go(-1); }, 1000) to jump back after opening the link.

The problem is that this does not allow me to open several issues at once, i.e., by holding the Ctrl+Click because it opens the email and jumps back (big flickering).

How could I stop the email from opening when I click on the button I added?

I tried setting the timeout to 0, i.e., setTimeout(function() { window.history.go(-1); }, 0), but this does not helps because GMail opens the email both, in the current browser tab/page and in a new page (along with my Redmine page), then I have 2 new pages opened when I click my button with Ctrl+Click.

  1. Is there something I could add to setTimeout(..., 0) which could cancel the email opening before it starts? (So I can open several tabs at once by Holding the Ctrl button)
  2. Or is there a way to remove the click event from opening the email when I click on the button I just added? (So I can open several tabs at once by Holding the Ctrl button)
// ==UserScript==
// @name         GMail Redmine Link to Redmine
// @namespace    *
// @version      0.1
// @description  Redmine button to jump directly to redmine thread
// @author       user
//
// @include https://mail.google.com/*
// @require http://code.jquery.com/jquery-3.4.1.min.js
// ==/UserScript==

(function() {
    'use strict';

    let keepclosing = async () => {
        let elementid = `div[role="link"] span[data-thread-id]`;
        let viewedbar = $(elementid).not('span[data-donot-process-this-again]');
        if(viewedbar.length)
        {
            $(viewedbar).each(function(index, item)
            {
                let newitem = $(item).text();
                let redmineregex = /\#(\d+)/g;
                let regeresult = redmineregex.exec(newitem);

                if(regeresult && regeresult.length) {
                    let redminecase = regeresult[1];
                    let previousItem = function() {
                        window.open(`https://redmine.com/issues/${redminecase}`);
                        setTimeout(function() { window.history.go(-1); }, 1000);
                        return false;
                    };
                    let mybutt = document.createElement("input");
                    mybutt.type = "button";
                    mybutt.id = `OpenRedmineCaseButton${redminecase}`;
                    mybutt.value = `#${redminecase}`;
                    mybutt.onclick = previousItem;

                    $($($($(item).parent()).parent()).parent()).prepend(mybutt);
                }
                $(item).attr('data-donot-process-this-again', true);
            })
        }
        setTimeout(keepclosing, 500);
    }
    setTimeout(keepclosing, 500);
})();

Observation: The image I posted has colors because the full code also has to part I removed to simplify the question:

let LatestIssues = 44000;
...
let casenumber = parseInt(redminecase);
if( casenumber > LatestIssues ) {
    mybutt.style.background = '#ffe0e0';
}
else if( casenumber > LatestIssues - 2000 ) {
    mybutt.style.background = '#faffd4';
}
else {
    mybutt.style.background = '#cfe9ff';
}

// This is something I used to add the button more above, but did not worked
// $($($($($($($(item).parent()).parent()).parent()).parent()).parent()).parent()).prepend(mybutt);

Solution

  • Simply preventing the event from propagating up to Gmail's click listener on the row does the trick:

    let previousItem = function(e) {
        e.stopPropagation();
        window.open(`https://redmine.com/issues/${redminecase}`);
    };
    

    IMO, a simpler approach would be:

    'use strict';
    
    const processed = new Set();
    const addButtons = () => {
        const parentSelector = `div[role="link"] > div`;
        for (const parent of document.querySelectorAll(parentSelector)) {
            const row = parent.children[0];
            if (processed.has(row)) continue;
            processed.add(row);
            const caseNumber = row.querySelector('span[data-thread-id]')?.textContent.match(/$(\d+)/)?.[1];
            if (!caseNumber) continue;
            const button = row.insertAdjacentElement('afterbegin', document.createElement('input'));
            button.type = 'button';
            button.onclick = (e) => {
                e.stopPropagation();
                window.open(`https://redmine.com/issues/${caseNumber}`);
            };
            button.value = `#${caseNumber}`;
        }
    };
    setInterval(addButtons, 500);