benzBrake / FirefoxCustomize

Ryan 收集的 Firefox 个性化相关资源
153 stars 34 forks source link

Suggestion: Improving the way Firefox display new messages alert on the tabs #2

Closed ericpa06 closed 2 years ago

ericpa06 commented 2 years ago

Hi, I end up knowing your work with Firefox mods through your script (BookmarkOpt.uc.js) that adds an option to copy the page title of itens on history sidebar, thank you very much again. I use it a lot :)

I would like to suggest you a script. Some pages show a number between parentheses to indicate that there is a new message on that given tab. Like this for instance: "(1) New Message – Facebook Messenger" "(13) Message – Whatsapp, etc..." This is not a exclusively behavior of Firefox, practically all browsers have this behavior, Chrome, Brave, etc:

image

The problem is that if you pin that given tab this number won't appear, but rather you will receive some generic indication that there is a new message, but it won't show how many: is it 1, 2, 3, 10 new messages? You don't see this information right away.

image

This problem though doesn't happen on Vivaldi, which always shows the number between parenthesis as a indication on the top of the favicon, like this, similar to the little icon that indicates whether or not that tab is playing a song. Actually it always shows the number between parenthesis as a sort of flying favicon notification:

image image

This way you can see how many messages there are on that tab even when you pinned that tab. I think it would be interesting a script that would change this functionality and copies Vivaldi behavior. I think it shouldn't be that complicate to implement some feature like this, some script that extract the number between parenthesis in the beginning of the title and puts it and its own html element on Firefox interface should do the trick, I think, but I might be wrong.

Also, to avoid false positives, such as the script turning on a page that just happens to have a title that begins with "(some number)" , such as: "(2000) The New Millennium – Wikipedia", maybe the script could first wait for some modification on the page title, and if there is a modification on the page title, more specifically on the numbers between the parenthesis, it would know that that number isn't some static part of title but rather that it probably indicates some sort of notification, since the page title was updated.

Thank you very much for your attention.

benzBrake commented 2 years ago

I've quickly make this script for you, but I have no idea to judge if the tab is dynamic title right now.

// ==UserScript==
// @name            tabNotifitionBadge.uc.js
// @license         MIT License
// @charset         UTF-8
// @include         chrome://browser/content/browser.xhtml
// @homepageURL     https://github.com/benzBrake/FirefoxCustomize/tree/master/userChromeJS
// ==/UserScript==
(function (css) {
    class tabNotifitionBadge {
        constructor() {
            gBrowser.tabs.forEach(t => this.getNumFromTab(t));
            gBrowser.tabContainer.addEventListener('TabAttrModified', this, false);
            this.MAX_NUM = 99;
            this.style = addStyle(css);
        }
        handleEvent(event) {
            let tab = event.target;
            let num = this.getNumFromTab(tab);
            let badge = tab.querySelector('.tab-badge');
            if (!badge) {
                badge = this.createBadge(0);
                tab.querySelector(".tab-icon-stack").appendChild(badge);
            }
            if (num > this.MAX_NUM) num = 0;
            badge.setAttribute('num', num);
            badge.innerHTML = num;
        }
        getNumFromTab(tab) {
            let title = tab.querySelector(".tab-text").innerHTML;
            let matches = title.match(/^\((\d+)\+?\)/);
            if (matches && matches.length === 2 && matches[1] < this.MAX_NUM) {
                return matches[1];
            }
            return 0;
        }
        createBadge(num) {
            let badge = this.createElementNS(null, 'html:label', {
                class: 'tab-badge toolbarbutton-badge',
                num: num,
            });
            badge.innerHTML = num;
            return badge;
        }
        createElementNS(namespace, type, props) {
            if (!type) return null;
            namespace || (namespace = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
            if (type.startsWith("html:") && typeof namespace !== "string") namespace = "http://www.w3.org/1999/xhtml";
            let el = document.createElementNS(namespace, type);
            for (let prop in props) {
                el.setAttribute(prop, props[prop])
            }
            return el;
        }
    }

    function addStyle(css) {
        var pi = document.createProcessingInstruction(
            'xml-stylesheet',
            'type="text/css" href="data:text/css;utf-8,' + encodeURIComponent(css) + '"'
        );
        return document.insertBefore(pi, document.documentElement);
    }

    if (gBrowserInit.delayedStartupFinished) window.tabNotifitionBadge = new tabNotifitionBadge();
    else {
        let delayedListener = (subject, topic) => {
            if (topic == "browser-delayed-startup-finished" && subject == window) {
                Services.obs.removeObserver(delayedListener, topic);
                window.tabNotifitionBadge = new tabNotifitionBadge();
            }
        };
        Services.obs.addObserver(delayedListener, "browser-delayed-startup-finished");
    }
})(`
.tabbrowser-tab .tab-icon-stack .tab-badge[num="0"] {
    visibility: collapse;
}
.tabbrowser-tab .tab-icon-stack .tab-badge {
    margin-inline-end: 0px !important;
    /* write your style here */
}
`);
ericpa06 commented 2 years ago

First of all, thank you so much!!! I was able to make the script work but I think there might be some minor issue.

If I just the put the script on my script folder.. it didn't run. But whenever I copied the same javascript code, expect for the first lines, right into developer mode console, it worked, like this: image

I will test more, it's probably just me doing something wrong.

benzBrake commented 2 years ago

If I just the put the script on my script folder.. it didn't run. But whenever I copied the same javascript code, expect for the first lines, right into developer mode console, it worked, like this:

May be the script can not work with other ucjs loader? I'm using xiaoxiaoflood's loader . And you need to save the script with utf-8 encoding,

ericpa06 commented 2 years ago

Thank you, I was saving with wrong encoding 😂 Now that I saved as utf-8 it's working flawlessly 👍

ericpa06 commented 2 years ago

Hi, sorry to bother you again. I swear it is the last time 😂:

I noticed that when using this script, if you are listing to some audio on that given tab and there is also a notification, you when end you up the "song indicator " (I don't know what the exact name of this) on top of the new message notification indicator that the scripts creates. Like this:

image

I was wondering if there is anyway to hide this "song indicator ", but only when there is a notification? Like if there is a "new message notification indicator " and a "song indicator " show only the "new message notification"?

Again, sorry to bother you and thank you very much.

benzBrake commented 2 years ago
// ==UserScript==
// @name            tabNotifitionBadge.uc.js
// @license         MIT License
// @charset         UTF-8
// @include         chrome://browser/content/browser.xhtml
// @homepageURL     https://github.com/benzBrake/FirefoxCustomize/tree/master/userChromeJS
// ==/UserScript==
(function (css) {
    class tabNotifitionBadge {
        constructor() {
            gBrowser.tabs.forEach(t => this.getNumFromTab(t));
            gBrowser.tabContainer.addEventListener('TabAttrModified', this, false);
            this.MAX_NUM = 100;
            this.style = addStyle(css);
        }
        handleEvent(event) {
            let tab = event.target;
            let num = this.getNumFromTab(tab);
            let badge = tab.querySelector('.tab-badge');
            if (!badge) {
                badge = this.createBadge(0);
                tab.querySelector(".tab-icon-stack").appendChild(badge);
                tab.setAttribute('notifition', 0);
            }
            if (num > this.MAX_NUM) return;
            badge.setAttribute('num', num);
            badge.innerHTML = num;
            tab.setAttribute('notifition', num);
        }
        getNumFromTab(tab) {
            let title = tab.querySelector(".tab-text").innerHTML;
            let matches = title.match(/^\((\d+)\+?\)/);
            if (matches && matches.length === 2 && matches[1] < this.MAX_NUM) {
                return matches[1];
            }
            return 0;
        }
        createBadge(num) {
            let badge = this.createElementNS(null, 'html:label', {
                class: 'tab-badge toolbarbutton-badge',
                num: num,
            });
            badge.innerHTML = num;
            return badge;
        }
        createElementNS(namespace, type, props) {
            if (!type) return null;
            namespace || (namespace = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
            if (type.startsWith("html:") && typeof namespace !== "string") namespace = "http://www.w3.org/1999/xhtml";
            let el = document.createElementNS(namespace, type);
            for (let prop in props) {
                el.setAttribute(prop, props[prop])
            }
            return el;
        }
    }

    function addStyle(css) {
        var pi = document.createProcessingInstruction(
            'xml-stylesheet',
            'type="text/css" href="data:text/css;utf-8,' + encodeURIComponent(css) + '"'
        );
        return document.insertBefore(pi, document.documentElement);
    }

    if (gBrowserInit.delayedStartupFinished) window.tabNotifitionBadge = new tabNotifitionBadge();
    else {
        let delayedListener = (subject, topic) => {
            if (topic == "browser-delayed-startup-finished" && subject == window) {
                Services.obs.removeObserver(delayedListener, topic);
                window.tabNotifitionBadge = new tabNotifitionBadge();
            }
        };
        Services.obs.addObserver(delayedListener, "browser-delayed-startup-finished");
    }
})(`
.tabbrowser-tab[pinned="true"][soundplaying="true"]:not([notifition="0"]) .tab-icon-overlay {
    visibility: collapse;
}
/* ↓ remove the block comment to hide sound indicator on unpinned tabs.↓ */
/*
.tabbrowser-tab[soundplaying="true"]:not([pinned="true"]):not([notifition="0"]) .tab-icon-overlay {
    visibility: collapse;
}
.tabbrowser-tab[soundplaying="true"]:not([pinned="true"]):not([notifition="0"]) :not(.tab-icon-overlay) {
    opacity: 1 !important;
}
*/
.tabbrowser-tab .tab-icon-stack .tab-badge[num="0"] {
    visibility: collapse;
}
.tabbrowser-tab .tab-icon-stack .tab-badge {
    margin-inline-end: 0px !important;
    /* write your style here */
}
`);
ericpa06 commented 2 years ago

Hello, thank you very much. I have been playing a little bit with the code, would it be possible to make the script to also detect when the pattern is: [1] instead of (1)? I assume the part of the code responsible for this is the one here:

let matches = title.match(/^\((\d+)\+?\)/);

I be been trying something like:

let matches = title.match(/^\((\d+)\+?\)|\[(\d+)\+?\)/);

But with no lucky 😂

benzBrake commented 2 years ago
let matches = title.match(/^[\(\[](\d+)\+?[\)\]]/);
ericpa06 commented 2 years ago

Thanks! :)