Discussions » Creation Requests

Twitter - to include the unread notifications count in the tab title

§
Posted: 2015/04/09
Edited: 2015/04/17

Twitter - to include the unread notifications count in the tab title

Currently having a (background) tab with Twitter timeline (htttps://twitter.com)
it shows in the tab title the number of unread tweets:
Imgur

It would be great to have a script to include the notifications count (and direct messages count) in tab title.
ie. instead of
(1) Twitter, to be
3 | 2 | (1) Twitter
where, 3 (in bold) are the unread notifications count, and 2 the unread DMs count.

I've made a script myself, but it's too basic:

function Testing() {
  tabTitle = document.title;
  notifications = document.querySelector('.count > span:nth-child(1)').innerHTML;
  dms = document.querySelector('.dm-new > span:nth-child(1)').innerHTML;
  document.title = dms + ' | ' + notifications + ' | '  + tabTitle;  
};
setInterval(Testing, 1 * 60 * 1000);

It runs every 1 min , and appends the two counts in the tab title.

It has 2 issues:

  1. Twitter fetches new tweets every 10 sec (I've checked using Network Monitor in Firefox).
    Once my script changes the tab title, then, on new unread tweets, their count doesn't re-appear in the title.
  2. I've noticed that the count values
    (in the CSS selectors used .count > span:nth-child(1) and .dm-new > span:nth-child(1))
    don't become 0 when you read them. Therefore, the script keeps on displaying the previous notifications count.
    Ideally, the tab title should only show the notifications and DMS count, only when there are unread times
    eg (1) Twitter and not 0 | 0 | (1) Twitter
woxxomMod
§
Posted: 2015/04/09

I'd try MutationObserver:

new MutationObserver(function(mutations){
  for (var m in mutations)
    if (mutations[m].target.localName == 'title') {
      document.title = "new title"
    }
}).observe(document.head, {characterData:true, childList:true, subtree:true});
§
Posted: 2015/04/09
Edited: 2015/04/09

Thank you for the suggestion.

I've came to this :

var lastvalue = document.querySelector('.count > span:nth-child(1)').innerHTML;
document.title = lastvalue + '|' + document.title;

new MutationObserver(function(mutations){
  for (var m in mutations)
    if (mutations[m].target.nodeValue != lastvalue) {
      document.title = document.querySelector('.count > span:nth-child(1)').innerHTML + '|' + document.title;
      lastvalue = document.querySelector('.count > span:nth-child(1)').innerHTML;
    }
}).observe(document.querySelector('.count > span:nth-child(1)'), {characterData:true, childList:true, subtree:true});

new MutationObserver(function(mutations){
  for (var m in mutations)
    if (mutations[m].target.localName == 'title') {
      document.title = document.querySelector('.count > span:nth-child(1)').innerHTML + '|' + document.title;
      lastvalue = document.querySelector('.count > span:nth-child(1)').innerHTML;
    }
}).observe(document.head, {characterData:true, childList:true, subtree:true});

which supposedly:
initially inserts the notifications count to the tab title,
and then,

  • for every tab title change (whenever there are unread tweets) and,
  • for every time the notifications count changes (whenever there are unread notifications)

it re-edits the tab title.

But unfortunately it leads browser to a hang.

woxxomMod
§
Posted: 2015/04/09

Supposedly it hangs because the changes you make inside the observer are triggering it again and again. Only change the title if it actually needs an update (for example, it has no |).

§
Posted: 2015/04/10
Edited: 2015/04/10

Ok. So:

var lastvalue = document.querySelector('.count > span:nth-child(1)').innerHTML;
document.title = lastvalue + '|' + document.title;

var target = document.querySelector('head > title');

var observer = new MutationObserver(function (mutations) {
  mutations.forEach(function (mutation) {
    if (document.title.indexOf('|') == -1 && 
        document.querySelector('.count > span:nth-child(1)').innerHTML != '0' ) {
      document.title = document.querySelector('.count > span:nth-child(1)').innerHTML + '|' + document.title;
      lastvalue = document.querySelector('.count > span:nth-child(1)').innerHTML;
    }
  });
})

var config = { attributes: true,  childList: true, characterData: true }
observer.observe(target, config);
observer.disconnect();

It initially inserts the notifications count to the tab title,
and then, whenever there is a change in the tab title (that's checked via the mutation observer)
if the tab title doesn't contain "|" AND the notifications count is not equal to '0' then re-edit the tab title.

I hoped it should work ok now,
but unfortunately on new unread tweets , the count doesn't re-appear in the tab title.

woxxomMod
§
Posted: 2015/04/10

Maybe document.title.indexOf('|') > -1 should have == instead?

§
Posted: 2015/04/10

Yes, I missed that! Thank you. (I edited my previous post)
Unfortunately, on new unread tweets the count still doesn't re-appear, though.

woxxomMod
§
Posted: 2015/04/10

Uhm... I haven't noticed you've changed my sample. Remove the line that disconnects the observer right after it's connected. This observer should run as long as the tab is open.

§
Posted: 2015/04/10
Edited: 2015/04/10

Thank you very much for your valuable help! Now it works!
I uploaded it here

§
Posted: 2015/04/17
Edited: 2015/04/17

Some more help please:
as I've written in the initial post,
the count value in the CSS selector .count > span:nth-child(1)
doesn't become 0 after you read the notifications.
eg. if it's 1, then, after you read the notification, it's value remains 1.

Therefore, the script keeps on displaying the previous notifications count.

I thought that maybe some CSS rule is applied to it, that makes the count hidden So, I tried disabling the relevant rules for the selector, but it wasn't the case.
(But, if I refresh the page (F5) then the count is 0 zero again, and so the script doesn't display the count).

How could I change the script so that it doesn't display the count after there are no more unread notifications left ?

woxxomMod
§
Posted: 2015/04/17

I have a twitter account but I don't use it so I have no notifications. Maybe you can provide a link to a very frequently updated hashtag/stream (each minute preferably)?

woxxomMod
§
Posted: 2015/04/18

Seems like Twitter has no built-in "mark as read" functionality, so I guess you'll have to implement it yourself:

  1. attach a global document mutation observer, watch for the new tweets added, set an attribute "unread"
  2. add a "click" event listener and if the clicked element has the "unread" attribute, clear the attribute and decrement the unread count
§
Posted: 2015/04/18
Edited: 2015/04/18

Thanks a lot for the guidance.

I've come to the following script, but unfortunately it hangs on line 38:

/// ---------------------------------
// Initial display of counter
/// ---------------------------------
var nCount = document.querySelector('.count > span:nth-child(1)').innerHTML;
if (nCount != '0') {
  document.title = nCount + '|' + document.title;
};

/// ---------------------------------
/// 1st mutation observer -monitors the tab title- 
/// (if tab title doesn't contain '|' and nCount not 0, then display counter)
/// ---------------------------------

var target1 = document.querySelector('head > title');

var observer1 = new MutationObserver(function (mutations) {
  mutations.forEach(function (mutation) {
    nCount = document.querySelector('.count > span:nth-child(1)').innerHTML;
    if (document.title.indexOf('|') == - 1 && nCount != '0') {
      document.title = nCount + '|' + document.title;
    }
  });
})

var config = { attributes: true, childList: true, characterData: true }

observer1.observe(target1, config);


/// ---------------------------------
/// 2st mutation observer -monitors the HTML notification counter value- 
/// (on every value change, add a class Attribute with the name "unread")
/// ---------------------------------

var target2 = document.querySelector('.count > span:nth-child(1)');

var observer2 = new MutationObserver(function (mutations) {
  mutations.forEach(function (mutation) {    
    target2.setAttribute("class", "unread");    
  });
})

// var config = { attributes: true, childList: true, characterData: true }

observer2.observe(target2, config);


/// ---------------------------------
/// A "click" event listener, attached on the "Notifications" button
/// (if the clicked element has the "unread" attribute, 
/// then clear the attribute and decrement the unread count-make it 0 again)
/// ---------------------------------

var target3 = document.querySelector('.people');
target3.addEventListener("click", decrementCounter, false);

function decrementCounter(){
  counter = document.querySelector('.count > span:nth-child(1)');
  if (counter.getAttribute(unread) !== null){    
    counter.removeAttribute('unread');
    counter.innerHTML = 0;  
  }
}
woxxomMod
§
Posted: 2015/04/18

Apparently it hangs because the mutation observer is invoked when you change the attribute. Check first if the attribute exists:

if (!target2.unread)
  target2.unread = true
  if (counter.unread){    
    delete counter.unread;
§
Posted: 2015/04/18

It works great now.
I'm grateful for all your help :)

/// ---------------------------------
// Initial display of counter
/// ---------------------------------
var nCount = document.querySelector('.count > span:nth-child(1)').innerHTML;
if (nCount != '0') {
  document.title = nCount + '|' + document.title;
  document.querySelector('.count > span:nth-child(1)').unread = true;
};

/// ---------------------------------
/// 1st mutation observer -monitors the tab title- (if tab title doesn't contain '|' and nCount not 0 and unread flag is true, then display counter)
/// ---------------------------------
var target1 = document.querySelector('head > title');

var observer1 = new MutationObserver(function (mutations) {
  mutations.forEach(function (mutation) {
    nCount = document.querySelector('.count > span:nth-child(1)').innerHTML;
    if (document.title.indexOf('|') == -1 
        && nCount != '0'
        && document.querySelector('.count > span:nth-child(1)').unread) {
      document.title = nCount + '|' + document.title;
    }
  });
})

var config = { attributes: true, childList: true, characterData: true }

observer1.observe(target1, config);


/// ---------------------------------
/// 2st mutation observer -monitors the HTML notification counter value- 
/// (on every value change, add a class Attribute with the name "unread")
/// ---------------------------------
var target2 = document.querySelector('.count > span:nth-child(1)');

var observer2 = new MutationObserver(function (mutations) {
  mutations.forEach(function (mutation) {
    if (!target2.unread)
      target2.unread = true;      
  });
})

// var config = { attributes: true, childList: true, characterData: true }

observer2.observe(target2, config);


/// ---------------------------------
/// Three "click" event listeners, attached on the "Notifications" button (one for each of it's 3 parts)
/// (if the clicked element has the "unread" attribute, then clear the attribute and decrement the unread count-make it 0 again)
/// ---------------------------------
var target3a = document.querySelector('.Icon--notifications');
var target3b = document.querySelector('.people > a:nth-child(1) > span:nth-child(2)');
var target3c = document.querySelector('.people > a:nth-child(1)');
target3a.addEventListener("click", decrementCounter, false);
target3b.addEventListener("click", decrementCounter, false);
target3c.addEventListener("click", decrementCounter, false);

function decrementCounter(){
  counter = document.querySelector('.count > span:nth-child(1)');
  if (counter.unread)    
     delete counter.unread; 
  document.querySelector('.count > span:nth-child(1)').innerHTML = '0';
  document.title = "Twitter";    
}

§
Posted: 2015/07/23

Hey guys, this is awesome...any progress?

woxxomMod
§
Posted: 2015/07/23

What progress? The script is there.

ivh
§
Posted: 2016/03/12

Hi! This was an interesting read, thanks. I stumbled upon it trying to stop Twitter from changing the title (I find it distracting). I tried this but for some reason nothing happens when I add it to Greasemonkey. Any hints?

Post reply

Sign in to post a reply.