// ==UserScript== // @name so-tag-votes // @namespace so // @description Stack Overflow tag votes count // @include http://stackoverflow.com/ // ==/UserScript== var cssjson = { ".small-multiplier":{ "font-size":"90%", }, ".vote-selector":{ "color":"#808185", "font-size":"70%", "font-weight":"bold", "margin-right":"4px" }, ".vote-selected":{ "color":"#444444", "font-size":"110%" }, ".tag-rank":{ "color":"#808185", "font-size":"80%", "margin-right":"4px" }, ".popular-tag": { "font-weight":"bold", "font-size":"90%" }, ".popular-tag.tag-rank-0": { "color":"#E9D07C"// }, ".popular-tag.tag-rank-1": { "color":"silver" }, ".popular-tag.tag-rank-2": { "color":"#CD7F32" }, ".vote-selected":{ "color":"#444444", "font-size":"120%" } } var styleStr = ""; for(var i in cssjson){ styleStr += i + " {\n" for(var j in cssjson[i]){ styleStr += "\t" + j + ":" + cssjson[i][j] + ";\n" } styleStr += "}\n" } var style = window.document.createElement('style'); style.type = 'text/css'; style.innerHTML = styleStr document.getElementsByTagName("HEAD")[0].appendChild(style); (function(){ function GM_init() { if(typeof unsafeWindow.jQuery == 'undefined') { window.setTimeout(GM_wait,100); } else { jQueryInit(unsafeWindow.jQuery); } } GM_init(); unsafeWindow.updateVotes = function(allTagVotes) { window.setTimeout(function() { GM_setValue(allTagVotes.host+"_tag_votes", allTagVotes.toSource()); }, 0); }; function getRanking(count) { if(count === "") { return "?"; } if(count < 3 || count > 19) { if(count %10 === 0) { return (count + 1) + "st"; } else if(count %10 === 1) { return (count + 1) + "nd"; } else if(count %10 === 2) { return (count + 1) + "rd"; } } return (count + 1) + "th"; } function jQueryInit($) { var userId = $("link[rel=canonical]").attr("href").split("/")[4]; var currentUserId = $("#hlinks a[href^='/users/recent/']").attr("href").split("/")[3]; if (currentUserId != userId) { return ; } //Looking at someone else's page, cancel /// var host = window.location.host; host = host.substring(0, host.indexOf('.')); var threshold = 20; var popularThreshold = 500; var silverThreshold = 400; var currentTime = new Date().getHours(); var allTagVotes = eval(GM_getValue(host+"_tag_votes", {tagData:[], host:host})); var index = 0; $('.user-stats-table:eq(3) .post-tag').each(function() { $(this).next("span").after(''); $(this).next("span").addClass("small-multiplier"); }); function getTotalQuestions(data) { var totalQuestions = $('div.summarycount:eq(2)', data).html(); var arr = totalQuestions.split(","); totalQuestions = ''; $.each(arr, function(count, item) { totalQuestions += item; }); return parseInt(totalQuestions); } function getTagClass(totalQuestions, votes) { return ((totalQuestions > popularThreshold || votes > silverThreshold)?'popular-tag':''); } function updateTag(tagVotes, tagIndex) { $('.user-stats-table:eq(3) .tag-container-'+tagIndex+':first').html(''+tagVotes.votes+' ('+getRanking(tagVotes.rank)+')'); } function getTagVotes(tagIndex, tagName) { if(allTagVotes.length <= tagIndex || !allTagVotes[tagIndex] || tagName !== allTagVotes[tagIndex].name || currentTime !== allTagVotes[tagIndex].lastUpdated) { allTagVotes[tagIndex] = {rank:"", votes:"", name:tagName, totalQuestions:"", lastUpdated:"-1"}; } return allTagVotes[tagIndex]; } function tagCallback(data, tagName, tagIndex) { var allTimeList = $('div#questions > div:eq(1) tr', data) for (var count=0; count < allTimeList.length; count++) { if(userId === $('div.user-details a', allTimeList[count]).attr("href").split("/")[2]) { var tagCount = $('span.top-count:first', allTimeList[count]).html(); var totalQuestions = getTotalQuestions(data); var tagVotes = {rank:count, votes:tagCount, name:tagName, totalQuestions:totalQuestions, lastUpdated:new Date().getHours()}; allTagVotes[tagIndex] = tagVotes; updateTag(tagVotes, tagIndex); unsafeWindow.updateVotes(allTagVotes); return; } }; }; //used to escape tag names for css classes function customEscape(tag) { tag = tag.replace("\.", "[").replace("\.", "["); tag = escape( encodeURIComponent( tag ) ); tag = tag.replace("%", "_").replace("%", "_"); tag = queryEscape(tag); return tag; } function queryEscape(tag) { tag = escape(tag); tag = tag.replace("+", "%2b").replace("+", "%2b"); return tag; } function updateVoteLink(tagName, lastPage, voteCount, tagIndex) { var content = voteCount;//"▶ "+voteCount; if(!lastPage) { content = content + ''; $(".votes-"+customEscape(tagName)).html(content); $(".votes-"+customEscape(tagName)).addClass('vote-selected'); } else { allTagVotes[tagIndex] = {rank:"", votes:voteCount, name:tagName, totalQuestions:"", lastUpdated:new Date().getHours()}; updateTag(allTagVotes[tagIndex], tagIndex) unsafeWindow.updateVotes(allTagVotes); } } var SerialAjaxExecuter = function( onComplete, delay ) { this.requests = []; this.results = []; this.delay = delay || 1; this.onComplete = onComplete; } SerialAjaxExecuter.prototype.addRequest = function( method, url, data, callback, format ) { var self = this; this.requests.push( { "method" : method , "url" : url , "data" : data , "format" : format , "callback" : callback } ); var numRequests = this.requests.length; if ( numRequests > 1 ) { this.requests[numRequests-2].callback = function( nextRequest, completionCallback ) { return function( data ) { completionCallback( data ); setTimeout( function(){ self.execute( nextRequest ); }, self.delay ); } }( this.requests[numRequests-1], this.requests[numRequests-2].callback ) } } SerialAjaxExecuter.prototype.execute = function( request ) { var self = this; if ( 'undefined' == typeof request ) { request = this.requests[0]; var lastRequest = this.requests[this.requests.length-1]; lastRequest.callback = function( completionCallback ) { return function( data ) { completionCallback( data ) self.onComplete( self.results ); } }( lastRequest.callback ) } request.method( request.url, request.data, function( r ) { return function( data ) { self.results.push( data ); r.callback( data ); } }( request ) ) } function firstpageCallback(data, tagName,tagIndex) { var voteCount = 0; var pages = $(".page-numbers", data).length - 6; var totalPages = 0; if(pages > 0) { totalPages = $(".page-numbers:eq("+pages+")", data).html(); } else if(pages > -2) { //exactly 1 answer totalPages = 1; } function countPageVotes(data,lastPage, tagIndex){ var pageVoteCount = 0; $(".vote-count-post > strong", data).each(function(){ //$(this).parent("span").parent("div").parent("div").next("div") var curr = $(this).parents('.stats:first'); var answer =$(curr).children(".status:first"); if(answer.html() === "") { pageVoteCount += parseInt($(this).html()); } }); voteCount += pageVoteCount; updateVoteLink(tagName, lastPage, voteCount, tagIndex); } countPageVotes(data, (totalPages <= 1), tagIndex); $(function(){ var se = new SerialAjaxExecuter( function( results ) { console.log( results ); }, 1500 ); for (var pageCount=1; pageCount < totalPages; pageCount++) { (function delayTranche() { var page = pageCount; var lastPage = (page === (totalPages - 1)); se.addRequest( $.get, "/search?q=user%3A"+userId+"+wiki%3A0+votes%3a1+[" + queryEscape(tagName) + "]&pagesize=50&page="+(page+1)+"&tab=newest", {n:pageCount}, function(data){countPageVotes(data, lastPage, tagIndex)}, "html" ); })(); } se.execute(); }); } function loadTagRankings() { $(function(){ var se = new SerialAjaxExecuter( function( results ) { console.log( results ); }, 1000 ); var postTags = $('.user-stats-table:eq(3) .post-tag'); for (var j=0; j < postTags.length; j++) {//1; j++){// var currentTag = postTags[j].toString().split("[")[1].split("]")[0]; var tagCount = $(".user-stats-table:eq(3) a[href*='["+currentTag+"]']").next(); if(tagCount.html().length > 0) { tagCount = tagCount.html().substring(7); if(tagCount >= threshold) { var tagVotes = getTagVotes(j, currentTag); //first set any cached value, then check for updates if(tagVotes.lastUpdated != -1) { updateTag(tagVotes, j); } if(currentTime !== tagVotes.lastUpdated) { (function() { var tagIndex = j; var tagName = currentTag; se.addRequest( $.get, "/questions/tagged?tagnames="+tagName+"&sort=stats", {n:tagCount}, function(data){tagCallback(data, tagName, tagIndex)}, "html" ); })(); } } } } se.execute(); }); } loadTagRankings(); var badgeTable = $('.user-stats-table:eq(4)'); index = 0; $('.user-stats-table:eq(3) .post-tag').each(function(){ var tagName = $.trim($(this).text()); //there will be 0, 1 or 2 badges, 1 means silver, 2 means gold var badgeType = $(".badge", badgeTable).map(function() { var type = $(this).children("span:first").attr("class"); var text = $(this).html().split(" ")[1]; if(text === tagName) { return text; } }); if(badgeType.length > 0) { $(this).addClass("badge"); $(this).html(' ' + tagName); } var tagDom = $('.user-stats-table:eq(3) .tag-container-'+ index +':first'); if(tagDom.html() === "") { (function() { var tagIndex=index; tagDom.html(''); $('a', tagDom).click(function(){ updateVoteLink(tagName, false, "", tagIndex); $.get("/search?q=user%3A"+userId+"+wiki%3A0+votes%3a1+[" + queryEscape(tagName) + "]&pagesize=50&tab=newest", function(data){firstpageCallback(data, tagName, tagIndex)}, "html"); return false; }); })(); } index++; }); } })();