// ==UserScript== // @name Admiral Backbar // @namespace http://rephrase.net/box/user-js/ // @description Apply unobtrusive "backbars" to indicate the relative scores of rated content, e.g. Reddit links // @include http://*.metafilter.com/* // @include http://metafilter.com/* // @include http://www.reddit.com/* // @author Sam Angove // ==/UserScript== /* Based on the tr?s cool "Backbars on social link-sites" script: Author: Eliazar Parra http://elzr.com/posts/backbars-on-social-link-sites/ Why rewrite? I don't like the external dependencies on jQuery and, worse, images hosted on the author's site. This version trades that for absurd ineffiency by generating(!) its own bitmaps. Site backbar definitions consist of four-element arrays: 0 - regular expression used to match against the URL 1 - xpath expression to find item nodes 2 - a function called on the item nodes returned by the xpath expression; it should return a 2-item array containing the item's score and the DOM node to apply the backbar on 3 - the colour to make the backbar Changelog --------- 2010-02-02 - * Work in Safari * Accept string or function for colour 2009-12-01 - * "No Favourites November" is over - * Improve MeFi comments expression 2009-11-05 - * Handle MeFi "No Favourites November" * Work when logged in to MeFi * Support ask./projects./music./metatalk./podcast.mefi 2009-06-23 - Initial release. */ (function(){ function getAncestor(node, predicate) { if (typeof node.parentNode == 'undefined' || node.parentNode == null) return false; if (!predicate(node.parentNode)) return getAncestor(node.parentNode, predicate); return node.parentNode; } function mefiSubdomainColour() { var sites = { 'ask.': '537857', 'metatalk.': '777777', 'podcast.': '777777', 'projects.': '3E6B6B', 'music.': '444444' }; var site = window.location.href.match(/http:\/\/([^.]+\.)?metafilter\.com/)[1]; return (typeof sites[site] == 'undefined') ? '2288bb' : sites[site]; } var backbars = [ // MeFi comment pages [ /([^.]+\.)?metafilter.com\/\d+/, '//div[@class="comments"]//a[contains(@href, "/favorited/")]', function(e) { var v = e.childNodes[0].nodeValue.replace(/[^0-9]/g, ""); return [ v ? parseFloat(v) : 0.0, getAncestor(e, function(p) { return p.className == "smallcopy"; }) ]; }, mefiSubdomainColour ], // MeFi front page [ /([^.]+\.)?metafilter.com\/$/, '//div[@class="copy"]/span[@class="smallcopy"]/a[@class="more"]', function(e) { return [ parseFloat(e.childNodes[0].nodeValue), getAncestor(e, function(p) { return p.className = "smallcopy"; }) ]; }, mefiSubdomainColour ], // MeFi popular favorites [ /([^.]+\.)?metafilter.com\/home\/popularfavorites$/, '//a[contains(@href, "/favorited/")]', function(e) { return [ parseFloat(e.childNodes[0].nodeValue), getAncestor(e, function(p) { return p.className = "smallcopy"; }) ]; }, mefiSubdomainColour ], // Reddit comment page [ /(www\.)?reddit.com\/r\/.*?\/comments/, '//div[@class="noncollapsed"]//span[@class="score unvoted"]', function(e) { return [parseFloat(e.childNodes[0].nodeValue), e.parentNode]; }, 'eeeeee' ], // Reddit front page / subreddit [ /(www\.)?reddit.com\/(r\/.*?\/)?$/, '//div[@class="score unvoted"]', function(e) { return [parseFloat(e.childNodes[0].nodeValue), e.parentNode.nextSibling.firstChild]; }, 'eeeeee' ] ]; for (var i=0; i> (i * 8)) & 0xff)); return o.join(""); } /* Apply backbars to listed items. For each node specified by XPath expression `exp`, call function `fn` to get the score and the node the backbar should be applied to, then add backbar of `colour`. */ function apply_backbars(exp, fn, colour) { if (typeof colour == 'function') colour = colour(); var scores = [], top = 0, base_width = 0; var a = document.evaluate(exp, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var nodes, scorenode, stylenode, score; for(var elm = null, i = 0; (elm = a.snapshotItem(i)); i++) { nodes = fn(elm); score = nodes[0], stylenode = nodes[1]; if (!stylenode) continue; stylenode.style.display = 'block'; if (stylenode.offsetWidth > base_width) base_width = stylenode.offsetWidth; if (score > top) top = score; scores.push([score, stylenode]); } var bg = "url(data:image/bmp;base64," + encodeURIComponent(window.btoa(bmpblock(base_width, 30, colour))) + ')'; var count = scores.length; for (i=0; i