// ljwho user script // version 0.21 BETA! // // 2006-11-26 // Copyright (c) 2006, Thomas Boutell and Boutell.Com, Inc. // Released under the GPL license // http://www.gnu.org/copyleft/gpl.html // // -------------------------------------------------------------------- // // This is a Greasemonkey user script. // // To install, you need Greasemonkey: http://greasemonkey.mozdev.org/ // Then restart Firefox and revisit this script. // Under Tools, there will be a new menu item to "Install User Script". // Accept the default configuration and install. // // To uninstall, go to Tools/Manage User Scripts, // select "ljwho", and click Uninstall. // // WHAT'S NEW (changelog): // // Version 0.21: // Correctly handles more than one _ in a name. // // Version 0.2: // Allow _ as well as - in names. // Allow community.livejournal.com. // Allow syndicated.livejournal.com. // Ignore links that don't contain the username in text. This // prevents most unnecessary RN's from appearing. // // -------------------------------------------------------------------- // // ==UserScript== // @name ljwho // @namespace http://www.boutell.com/greasemonkey/ // @description Attach private real-name notes to LJ usernames. Notes are stored on YOUR drive, NO ONE ELSE can see them. // @include http://livejournal.com/* // @include http://*.livejournal.com/* // ==/UserScript== var allLinks, thisLink; allLinks = document.evaluate( '//a[@href]', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < allLinks.snapshotLength; i++) { var thisLink = allLinks.snapshotItem(i); var who = getLJNameFromLink(thisLink); if (who) { var realName = GM_getValue("realnames:" + who); if (realName == "") { realName = null; } if (realName) { thisLink.setAttribute("title", realName); } var parent = thisLink.parentNode; var child = document.createElement('span'); child.setAttribute("class", "ljwhospan"); child.setAttribute("ljwhoname", who); var color = "#88FF88;"; if (!realName) { color = "#FF8888"; } child.setAttribute("style", "cursor: pointer; " + "margin: 4px; font-weight: bold; font-size: 8px; " + "background-color: black; color: " + color + ";"); if (realName) { child.setAttribute("title", realName); } var text = "RN"; var textNode = document.createTextNode(text); child.appendChild(textNode); parent.insertBefore(child, thisLink.nextSibling); child.addEventListener("click", editRealName, true); } } function getLJNameFromLink(link) { var href = link.getAttribute("href"); var who; if (href) { matched = href.match(/([\w\-\_]+)\.livejournal.com\/?$/); if (matched) { who = matched[1]; } else { matched = href.match(/^http\:\/\/(livejournal.com\/users|www.livejournal.com\/users|community.livejournal.com|syndicated.livejournal.com)\/([\w\_\-]+)\/?$/); if (matched) { who = matched[2]; } } // Undoubtedly this list is too short if (who && (who != 'www') && (who != 'stat') && (who != 'my') && (who != 'news')) { // 0.2: make sure there's a text child node that // contains the username. If there isn't, this is // a usericon next to a separate username link, or // an "my lj" link, "entries" link, etc. // so displaying RN would be redundant. text = getCompleteText(link); // Work around LJ's _/- equivalence // 0.21: global for multi-underscore names like foo_bar_blam text = text.replace(/_/g, "-"); whoC = who.replace(/_/g, "-"); if (text.search(whoC) != -1) { return who; } } } return null; } function getCompleteText(node) { var i; var text = ""; for (i = 0; (i < node.childNodes.length); i++) { var c = node.childNodes[i]; if (c.nodeName == "#text") { text += c.nodeValue; } else { text += getCompleteText(c); } } return text; } function editRealName() { var who = this.getAttribute("ljwhoname"); var realName; if (who) { realName = GM_getValue("realnames:" + who); } if (!realName) { // Prettier than "Undefined" realName = ""; } realName = prompt("Real name for " + who + ":", realName); if (realName != null) { GM_setValue("realnames:" + who, realName); var allLinks, thisLink; allLinks = document.evaluate( '//a[@href]', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < allLinks.snapshotLength; i++) { var thisLink = allLinks.snapshotItem(i); var linkWho = getLJNameFromLink(thisLink); if (who == linkWho) { thisLink.setAttribute("title", realName); } } var allSpans, thisSpan; allSpans = document.evaluate( "//span[@class='ljwhospan']", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < allSpans.snapshotLength; i++) { var thisSpan = allSpans.snapshotItem(i); var spanWho = thisSpan.getAttribute('ljwhoname'); if (who == spanWho) { thisSpan.setAttribute("title", realName); if (realName != "") { thisSpan.style.color = "#88FF88;"; } else { thisSpan.style.color = "#FF8888"; } } } } }