// ----- Yahoo Email Client ------ // @url http://mail.yahoo.com // @include http://us.mg3.mail.yahoo.com/* // @name Yahoo! // @desc Notifies about new/unread emails. // version 1.0 /* * Revision History: * version 1.0 * - NEW: Complete redesign of the notification message. * version 0.7 * - FIX: When unchecking "Notify when new email arrives" in prefsPane, emails still * notified. * - FIX: Fixed context menu shortcuts for the "Inbox" and "Compose New" resulted from the * API change. * - FIX: Bubbles window restores and notification closes when user clicks somewhere in * the notification area except the close button. * version 0.6 * - First release */ var checkEmailInterval = 20; // Interval in seconds between checks of new email arrival. var iconsURL = "http://bubbleshq.com/client/icons/"; var imagesURL = "http://bubbleshq.com/client/yahooNotification"; // Uncomment to open console. Set to off/error/info/debug for different debug levels. //SSB.console.init("debug","iframe"); //SSB.console.init("info"); SSB.setIcon(iconsURL+"yahoo.ico"); // Create Context Menu SSB.contextMenu.add("Inbox",viewInbox); SSB.contextMenu.add("Compose New Email",composeNew); // Initialization of configurable parameters prefsPane. // isNotifyEnabled is user configurable parameter, indicates if the user want to be // notified on new emails arrival. SSB.prefs.pane.addPrefs([{type:'bool', name:'isNotifyEnabled', defVal:true, title:'Notify when new email arrives'}]); // Run checkForURL every checkEmailInterval seconds. window.setInterval(checkForURL, checkEmailInterval*1000); /** * Simulates onclick event on the inbox button. */ function viewInbox() { var inboxSpan = document.getElementById("_test_Inbox"); SSB.console.debug("Got inbox span element with id = "+inboxSpan.id); inboxSpan.fireEvent("onclick"); } /** * Yahoo has a shortcut key for key "n" that opens new email tab. * This function fires onkeydown event with keyCode = 78 = "n" */ function composeNew() { var eventObj = document.createEventObject(); eventObj.keyCode = 78; document.fireEvent("onkeydown",eventObj); } /** * Check if notify is enabled, then check if we are in yahoo email page. * If we are, check for unread emails. */ function checkForURL() { SSB.console.debug("-------- checkForURL() --------"); var URL = new String(window.location); if( URL.indexOf("http://us.mg3.mail.yahoo.com") != -1 ); { checkUnreadEmails(); } } /** * Get the isNotifyEnabled preference value, and return it. * If this value was not set before, then it will be the default one defined in * SSB.prefs.pane.addPrefs. */ function isNotifyEnabled() { // User configurable parameter, if he want to be notified of new emails. var isNotifyEnabled = SSB.prefs.getValue("isNotifyEnabled"); // isNotifyEnabled can't be null as it set with SSB.prefs.pane.addPrefs and uses // defVal:true; SSB.console.debug("Get isNotifyEnabled="+isNotifyEnabled); return isNotifyEnabled; } /** * Parses #number in inbox(#number) and checks if number of unread emails is larger than * previous number of unread emails. */ function checkUnreadEmails() { SSB.console.debug("---- checkUnreadEmails() ----"); // get current number of unread emails var curUnread = bblsGetCurUnread(); SSB.console.debug("curUnread = " + curUnread); // get previous number of unread emails var prevUnread = SSB.prefs.getValue("prevUnread"); SSB.console.debug("Got prevUnread = " + prevUnread); // set previous number of unread emails to current number of unread emails SSB.prefs.setValue("prevUnread",curUnread + ""); SSB.console.debug("Set prevUnread to " + curUnread); // if previous number of unread emails was not defined set it to zero. if (!prevUnread) prevUnread = 0; else prevUnread = parseInt(prevUnread); SSB.console.debug("Parsed prevUnread as integer, prevUnread = " + prevUnread); // if current number of unread emails is greater than previous number of unread emails // then pop up the notification. if ((curUnread > prevUnread) && isNotifyEnabled()) { SSB.console.info("curUnread = " + curUnread + " > prevUnread = " + prevUnread); var msgData = parseUnreadEmailsData(curUnread); SSB.console.info(msgData); var html = getStringFromFunction(notificationHTML); html = html.replace(/__IMAGES_URL__/g, imagesURL); html = html.replace(/__msgJSON__/, msgData); SSB.notify(html, 342, 123, 10); } /* update icon (icons are caches so we can give direct url) */ SSB.setIcon(iconsURL+'yahoo' + (curUnread != 0 ? '_unread' : '') + '.ico'); } /** * Parse email header data (from, subject, time, etc.) from emails table. * Uses curUnread value to stop iteration when all unread emails are found. * @param number of current unread emails * @return string - " form:\n1. Danny\n2. Anna\n3. Max\nand from 2 others */ function parseUnreadEmailsData(curUnread) { try { SSB.console.debug("--- parseUnreadEmailsData("+curUnread+") --"); var msgTableHeaders = document.getElementById("msgTableHeaders"); var ptvc = nextSiblingElement(msgTableHeaders); var ptvtab = ptvc.getElementsByTagName("table")[0]; var ptvtabbod = ptvtab.getElementsByTagName("tbody")[1]; var messageRows = ptvtabbod.getElementsByTagName("tr"); var unansweredEmailsFound = 0; var from, subject, date; var msgData = new Array(); for (i = 0; i < messageRows.length && unansweredEmailsFound < curUnread; i++) { message = messageRows[i]; // if the email is unread email if (message.getAttribute("isRead") == false) { unansweredEmailsFound++; fields = message.getElementsByTagName("td"); from = fields[3].innerText; subject = fields[5].innerText; date = fields[6].innerText; // with all of the data the notification looks shrinky. so I will use only the from field. // until the notification balloon will use HTML SSB.console.debug("Parsed unread email - From: " + from + " Subject: " + subject + " Date: " + date); msgData.push({"from":from,"subject":subject,"date":date}); } } return bubblesJSON.stringify(msgData); } catch (e) { SSB.console.error(e.name + ": " + e.message); return ""; }; } /** * The inbox button composed of three spans: * Inbox,(2) * The comma span and indicator of unread emails can be hidden if there is no * unread emails in the inbox. But the span elements are there so we can check * their text content. */ function bblsGetCurUnread() { SSB.console.debug("bblsGetCurUnread()"); var inboxSpan = document.getElementById("_test_Inbox"); SSB.console.debug("got inboxSpan with id: " + inboxSpan.id); var commaSpan = nextSiblingElement(inboxSpan); var numOfUnreadSpan = nextSiblingElement(commaSpan); var numOfUnread = numOfUnreadSpan.innerText.match(/\(([\d]+)\)/); SSB.console.debug("numOfUnread = " + numOfUnread); if (numOfUnread) return numOfUnread[1]; else return 0; } /** * Function that receives an element node as a parameter and returns first child element node * of that element. If the element does not have child elements node the method returns null. * * @param {elementNode} element for which to search first child element. */ function firstChildElement(element) { for (var i = 0; i < element.childNodes.length; i++) if ( element.childNodes[i].nodeType == 1 ) return element.childNodes[i]; return null; } /** * Function that receives an element node as a parameter and returns next sibling element node of that element. * If the element does not have next sibiling element node the method returns null. * * @param {elementNode} element for which to search next sibling element. */ function nextSiblingElement(element) { var currentElement = element.nextSibling; while ( currentElement ) { if ( currentElement.nodeType == 1 ) return currentElement; currentElement = currentElement.nextSibling; } return null; } /* * Gets function reference and returns string of first matched text between commented * block just like this one. */ function getStringFromFunction(fnc) { var string = fnc.toString(); return string.match(/\/\*([\s\S]*)\*\//)[1]; } function notificationHTML() {/*