// ==UserScript== // @name gmx - show new unread // @name:fr gmx - marquer nouveaux messages // @name:de gmx - zeige neues ungelesenes // @name:es gmx - mostrar nuevos no leídos // @namespace https://github.com/Procyon-b // @version 0.5.6.1 // @description Mark folders with new unread messages // @description:fr Marque les dossiers contenant de nouveaux messages // @description:de Markieren Sie Ordner mit neuen ungelesenen Nachrichten // @description:es Marcar carpetas con nuevos mensajes no leídos // @author Achernar // @match https://3c.gmx.net/mail/client/* // @match https://3c-bap.gmx.net/mail/client/* // @include https://3c-bs.gmx.tld/mail/client/* // @match https://navigator.gmx.net/* // @match https://bap.navigator.gmx.net/* // @include https://navigator-bs.gmx.tld/* // @grant GM_setValue // @grant GM_getValue // @downloadURL none // ==/UserScript== (function() { "use strict"; var h=location.host.split('.'); window.addEventListener('blur', function(ev) { window.top.postMessage({blur:1},'*'); }); window.addEventListener('focus', function(ev) { window.top.postMessage({focus:1},'*'); }); let f=document.hasFocus(); window.top.postMessage({focus:f, NOblur:!f},'*'); // main frame (top) if (location.host.startsWith('navigator') || location.host.startsWith('bap.navigator') ) { var TO, marked, TOb, focus=false, mailFrame, data=document.getElementById('user-data'); try { if (data) data=JSON.parse(data.text); }catch(e){}; window.addEventListener('message', function(ev) { if (typeof ev.data != 'object') return; if (ev.data.getUserId) { ev.source.window.postMessage({userId:data.hashedUasAccountId}, ev.origin); mailFrame={w:ev.source.window, origin:ev.origin}; return; } if (ev.data.focus) { focus=true; if (TOb) {clearTimeout(TOb); TOb=null;} else if (marked) onF(); } if (ev.data.blur) { focus=false; if (TO) { TOb=setTimeout(function(){ TOb=null; onB(); }, 1000); } } mailFrame && mailFrame.w.postMessage({focus:focus, blur:!focus}, mailFrame.origin); function onF() { onB(); TO=setTimeout( function(){ TO=null; marked=false; document.title=document.title.replace(/^\(.*?\) */,''); }, 3000); } function onB() { if (TO) {clearTimeout(TO); TO=null;} } if (!focus && ev.data.new) { marked=true; document.title='(*) '+document.title.replace(/^\(.*?\) */,''); } }, false); return; } // folders frame if (location.pathname.startsWith('/mail/client/') ) { var e=document.querySelector('#navigation'); if (!e) return; // call top to get userid window.top.postMessage({getUserId:true},'*'); var focus=false, userId, folders, ignore=['vfol3','vfol2']; window.addEventListener('message', function(ev){ if (typeof ev.data != 'object') return; if (ev.data.userId) { userId=ev.data.userId; let sFolders=GM_getValue(userId,{}); folders={userId:userId}; // find all folders let a=document.querySelectorAll('#navigation NOul, #navigation li > .folder'), lvl=[], L, t, id, panel, New=false; for (let i=0,e; e=a[i]; i++) { L= parseInt( (L=/lvl(\d+)/.exec(e.parentNode.parentNode.classList)) && L[1] ); lvl[L]=id=e.id; if (L==1) { panel= (panel=e.closest('.navigation')) && (panel=panel.querySelector(':scope > .panel-head')); if (panel && panel.title && panel.querySelector('.badge') ) panel=panel.title; else panel=''; } let badge=e.querySelector('.badge'); folders[id]={lvl:L, ur:badge && parseInt(badge.innerText)}; if (ignore.includes(id)) folders[id].ignore=1; // the 3 default folders without badge if (!badge) folders[id].nobadge=1; let label=e.querySelector('.label'); if (label) { folders[id].name=label.innerText.trim(); // fix for closed folders if ( /\((\d+)\/\d+\)$/.exec(label.title) ) folders[id].ur=parseInt(RegExp.$1); } // is part of panel with badge if (panel) folders[id].panel=panel; // is subfolder if (t=lvl[L-1]) { folders[id].p=t; folders[t].sub=1; } if (sFolders[id]) { if (t=sFolders[id].mark) folders[id].mark=t; if (folders[id].ur > sFolders[id].ur) { folders[id].mark=1; New=true; } if (!folders[id].ur || !badge) delete folders[id].mark; } } GM_setValue(userId, folders); buildCSS(); if (!f && New) window.top.postMessage({new:1},'*'); return; } if (ev.data.focus) focus=true; if (ev.data.blur) focus=false; }, false); function buildCSS(ret) { var s='/*userscript test*/', fol={}, pan={}, i; for (i in folders) { let f=folders[i]; if (f.ignore) continue; if (f.mark || f.fmark) { s+='div.nav-item[id="'+i+'"] .badge{background-color: red !important; color: white !important;}'; while (f.p) { if (!f.ignore) fol[f.p]=1; f=folders[f.p]; } if (f.panel) { pan[f.panel]=1; } } } for (i in fol) { s+='div.nav-item[id="'+i+'"]:not(.open) .badge{background-color: red;}'; } for (i in pan) { s+='div.navigation > div.panel-head[title="'+i+'"] .badge{background-color: red;}'; } if (ret) return s; style.innerText=s; } var st={}, options={attributes: false, subtree: true, childList: true }; var style=document.createElement('style'); if (style.styleSheet) style.styleSheet.cssText = ''; else style.appendChild(document.createTextNode('')); (document.head || document.documentElement).appendChild(style); buildCSS(); const obs = new MutationObserver(function(mutL){ let n, o, t, save=false, New=false; for (let mut of mutL) { if ( (t=mut.target) && (t.className=='badge') ) { if ( (n=mut.addedNodes[0]) && (n.nodeType==3) ) { var div=t.closest('div.nav-item.folder'), id=div && (id=div.id), q=parseInt(n.data); if (!id) continue; if (folders[id].sub) { let cl=div.classList.contains('open') ? false:true; if (cl) { var tit= (tit=div.querySelector('.label')) && tit.title; let qt=-1; if ( /\((\d+)\/\d+\)$/.exec(tit) ) qt=parseInt(RegExp.$1); if (qt>=0) q=qt; } } if (folders[id].ur == q) continue; if (q <= folders[id].ur) delete folders[id].mark; else { folders[id].mark=1; New=true; } folders[id].ur=q; save=true; } } } if (save) { buildCSS(); GM_setValue(userId, folders); } if (!focus && New) window.top.postMessage({new:1},'*'); }); obs.observe(e, options); e.addEventListener('click', function(ev){ if (ev.target.classList.contains('folder-config')) { if (ev.ctrlKey) { let fol=ev.target.closest('div.nav-item.folder'); if (!fol || fol.classList.contains('has-open-flyout')) return; ev.stopPropagation(); if (folders[fol.id].mark) { delete folders[fol.id].mark; buildCSS(); GM_setValue(userId, folders); } return false; } } },true); } })();