Created
November 29, 2009 07:55
-
-
Save wittman/244842 to your computer and use it in GitHub Desktop.
stackoverflowQdashboard - Userscript (Greasemonkey/Greasekit) - Question Dashboard for stackoverflow.com (and related) - page analyzed and indicators shown for key information
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name stackoverflowQdashboard | |
// @namespace http://wittman.org/projects/stackoverflowqdashboard | |
// @description Question Dashboard for stackoverflow.com (and related) - page analyzed and indicators shown for key information | |
// @author Micah Wittman <http://wittman.org> | |
// @include http://*stackoverflow.com/questions/* | |
// @include http://serverfault.com/questions/* | |
// @include http://superuser.com/questions/* | |
// @version 0.17 | |
// ==/UserScript== | |
/************************************************************* | |
Copyright (C) 2009 Micah Wittman | http://wittman.org/ | stackoverflow.m[a][t]wittman.org | http://stackoverflow.com/users/11181/micahwittman | http://twitter.com/micahwittman | |
Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL (http://www.gnu.org/licenses/) licenses. | |
Repositories: | |
http://wittman.org/projects/stackoverflowqdashboard/stackoverflowQdashboard.user.js | |
http://gist.github.com/gists/244842 | |
Versions: | |
* 2009-11-30 - version 0.17 - Warm Comment indicator html, due to refactoring typo, was not being appended to dashHtml output var | |
* 2009-11-30 - version 0.16 - Moved indicator placement of "Me" so it doesn't come after any track display | |
* 2009-11-30 - version 0.15 - A forgotten console.log() removed | |
* 2009-11-30 - version 0.14 - Community Wiki detect now checks Question section too | |
* 2009-11-30 - version 0.13 - Noobie detect now looks in Answers and Question | |
* 2009-11-30 - version 0.12 - Community Wiki detect logic not working - needs to look for no uses with rep displayed | |
* 2009-11-29 - version 0.11 - Added Repository URLs for stackoverflowQdashboard in header comments | |
* 2009-11-28 - version 0.10 - Initial Release. Greasemonkey (Firefox) and GreaseKit (Safari) compatible. | |
*************************************************************/ | |
/*** Configuration ************************/ | |
//Modules and Other Options | |
// Easteregg Users | |
var mod_eastereggUsersEnabled = true; //If true then indicates if specific users are found (could be considered an easter egg - the three Js and the author of this user script) | |
// Early Adopter User | |
var mod_earlyadopterEnabled = true; //If true then indicates if an early adopter user is found (based on configuration var earlyadopter_threshold) | |
var earlyadopter_threshold = 12000; //Early Adopter Threshold (minimum user id integer value) at which point users there and lower are considered early adopters of SO | |
// Answer Vote Count | |
var mod_answerVotecountEnabled = true; //If true then indicates the answer with the greatest vote-count on the page | |
// Comments | |
var mod_commentsEnabled = true; //If true then indicates if one or more comments from Warm to Supernova (thresholds of comment-vote-count) are found. | |
// User Reputation | |
var mod_userRepEnabled = true; //If true then indicates if one or more users that meet a certain threshold are found (10k+ User and "Help a Noobie" (user with rep in the single digits) | |
var userRep10kEnabled = true; //[Config var mod_userRepEnabled must be true to enable] If true then indicates if at least one user with 10,000 rep value is found | |
var userRep1kEnabled = true; //[Config var mod_userRepEnabled must be true to enable] If true then indicates if at least one user with 1,000 rep value is found | |
var userRepNoobEnabled = true; //[Config var mod_userRepEnabled must be true to enable] If true then indicates "Help a Noobie" if at least one user with rep value 1 to 9 is found | |
// Track (words/phrases to be detected are text in the question page) | |
var mod_trackEnabled = true; //Set true to enable tracking words/phrases | |
var trackArr = ['cobol', 'forth', 'lisp', 'best practices', 'Babbage']; //If trackEnabled is true, then this array of words/phrases (case insensitive) is tracked (if found on question page, indicated in Question Dashboard. A regex is used, so there's a performance consideration, but the advantage is there shouldn't be much substring false positives (e.g. var trackArr = ['.NET', 'C#']; ~~~ Given 'The .NET framework blah blah blah' then '.NET' WILL match ~~~ Given: 'Use www.example.net as an example site.' then '.net' WILL NOT match. | |
// Other Options | |
var subdashboardEnabled = true; //If true then the Sub Question Dashboard rendered (it is a copy of the Question Dashboard located above the Answer Paging controls ([1][2]...Next) | |
var communityWikiIndicatorEnabled = true; //If true then indicates if Question is a Community Wiki | |
var extraIndicatorEnabled = false; //Left border of main content section gets set to dotted gray if Community Wiki, or orange if regular question and some component for Question Dashboard is detected. | |
var meEnabled = true; //If true, indicate if I (the logged-in user) is found in the Answer section | |
/*****************************************/ | |
/*** Body of Script **********************/ | |
//Global Setup | |
// User SO's jQuery object that's conveniently available as $ with the pageload | |
if(typeof unsafeWindow != 'undefined'){ | |
$ = unsafeWindow.$; //Greasemonkey context, so set $ from unsafeWindow | |
} | |
var trackFoundArr = []; | |
var my_user_uri = ''; | |
var my_id = 0; | |
var dashHtml = ''; | |
var found_count = 0; | |
var found_me = false; | |
var found_earlyadopter = false; | |
var found_user_10k = false; | |
var found_user_1k = false; | |
var found_user_noob = false; | |
var found_skeet = false; | |
var found_atwood = false; | |
var found_spolsky = false; | |
var found_author = false; | |
var sep = '| '; | |
//Functions | |
function runQdashboard(){ | |
//Establish point of reference for inserting Question Dashboard into DOM | |
var anchorpoint = $('#question-header'); | |
//Check to make sure there's only one anchorpoint and Question Dashboard not already inserted | |
if(anchorpoint.length == 1 && $('._dashboard_').length == 0 ){ | |
/*** Set Global Vars **********/ | |
// Set Logged-in user | |
my_user_uri = $("#topbar > #hlinks a:eq(1)").attr('href'); | |
my_id = parseInt(my_user_uri.split('/')[2]); | |
/*** Make Question Dashboard **********************/ | |
// Precursor code for 'Easteregg Users' and/or 'Early Adopter User' modules | |
if(mod_eastereggUsersEnabled || mod_earlyadopterEnabled || meEnabled){ | |
shared_users(); | |
} | |
// Easteregg Users | |
if(mod_eastereggUsersEnabled){ | |
mod_eastereggUsers(); | |
} | |
// Early Adopter User | |
if(mod_earlyadopterEnabled){ | |
mod_earlyadopter(); | |
} | |
// Question | |
if($("#answers .user-details .reputation-score:first, #question .user-details .reputation-score:first").length == 0){ | |
//Community Wiki Question | |
if(extraIndicatorEnabled){ | |
$('#mainbar').css('border-left','1px dotted gray'); | |
} | |
if(communityWikiIndicatorEnabled){ | |
dashHtml += '<span style="color:darkgray">' + sep + '<strong>Community Wiki</strong> </span>'; | |
found_count++; | |
} | |
}else{ | |
//Regular Question | |
if(extraIndicatorEnabled){ | |
$('#mainbar').css('border-left','1px solid darkorange'); | |
} | |
if(mod_userRepEnabled){ | |
mod_userRep(); | |
} | |
} | |
// Answer Vote Count | |
if(mod_answerVotecountEnabled){ | |
mod_answerVotecount(); | |
} | |
// Comments | |
if(mod_commentsEnabled){ | |
mod_comments(); | |
} | |
// Me (currently logged in user) | |
if(meEnabled && found_me){ | |
setMeHtml(); | |
} | |
// Tracks (found word/phrases) | |
if(mod_trackEnabled){ | |
mod_track(); | |
} | |
// Insert Question Dashboard (all prerequisite modules have run | |
if(found_count > 0){ | |
anchorpoint.append('<div class="_dashboard_" style="line-height:1.3em;width:75%;padding:2px 2px 10px 2px;"></div><br /><br />'); | |
var dash = $('._dashboard_'); | |
dash.append(dashHtml); | |
} | |
/*****************************************/ | |
} | |
} | |
function trackMatched(text){ | |
var word; | |
var matched = false; | |
var matchedIndex; | |
var re; | |
for(var i = 0; i < trackArr.length; i++){ | |
word = trackArr[i]; | |
if( $.inArray(word, trackFoundArr) == -1 ){ | |
re = new RegExp('^' + word +'|([^a-z]' + word + '[^a-z])|([^a-z]' + word + '$)', 'i'); | |
matchedIndex = text.match(re); | |
if(matchedIndex != null) | |
{ | |
trackFoundArr.push(word); | |
matched = true; | |
} | |
} | |
} | |
return matched; | |
} | |
function shared_users(){ | |
$('.user-details > a, a.comment-user').each(function(){ | |
var id = parseInt(this.href.split('/')[4]); | |
if(this.href.indexOf('/users/22656/') > -1 ){ | |
found_skeet = true; | |
found_count++; | |
}else if(this.href.indexOf('/users/1/') > -1){ | |
found_atwood = true; | |
found_count++; | |
}else if(this.href.indexOf('/users/4/') > -1){ | |
found_spolsky = true; | |
}else if(this.href.indexOf('/users/11181/') > -1){ | |
found_author = true; | |
} | |
if(id != my_id && id < earlyadopter_threshold){ | |
found_earlyadopter = true; | |
found_count++; | |
} | |
if(meEnabled && id == my_id){ | |
found_me = true; | |
} | |
}); | |
} | |
function mod_eastereggUsers(){ | |
//Jon | |
if(found_skeet){ | |
dashHtml += '<span style="font-weight:bold">' + sep + '<strong><a style="color:blue" href="http://meta.stackoverflow.com/questions/9134/jon-skeet-facts">Jon Skeet</a></strong> on deck </span>'; | |
} | |
//Jeff | |
if(found_atwood){ | |
dashHtml += '<span style="font-weight:bold">' + sep + 'Hey, it\'s <strong><a style="color:blue" href="http://meta.stackoverflow.com/users/1/jeff-atwood">Jeff</a></strong> </span>'; | |
} | |
//Joel | |
if(found_spolsky){ | |
dashHtml += '<span style="font-weight:bold">' + sep + '<strong><a style="color:blue" href="http://stackoverflow.com/users/4/joel-spolsky">Joel</a></strong> be here<sup><a href="http://www.fogcreek.com/FogBugz/" title="Report as bug">[1]</a></sup> </span>'; | |
} | |
//Author | |
if(found_author){ | |
dashHtml += '<span style="font-weight:bold">' + sep + '<strong><a style="color:blue" href="http://stackoverflow.com/users/11181/micahwittman">Author</a> present</strong> </span>'; | |
} | |
if(found_skeet && found_atwood && found_spolsky){ | |
dashHtml += '<span class="supernova">' + sep + '<strong><em>The 3 Js are in the house!</em> Look for this Q mentioned on a <a style="border-bottom:dotted 1px" href="http://blog.stackoverflow.com/index.php?feed=podcast">podcast</a> near you.</strong> </span>'; | |
} | |
} | |
function mod_earlyadopter(){ | |
//Early Adopter | |
if(found_earlyadopter){ | |
dashHtml += '<span style="color:#E0A385">' + sep + '<strong>Early Adopter</strong> </span>'; | |
} | |
} | |
function mod_answerVotecount(){ | |
topAnswerCount = 0; | |
$('div#answers span.vote-count-post').each(function(){ | |
var vc = parseInt($.trim($(this).text())); | |
if(vc >= 10){ | |
if(vc > topAnswerCount){ | |
topAnswerCount = vc; | |
} | |
} | |
}); | |
if(topAnswerCount > 0){ | |
dashHtml += '<span style="color:red">' + sep + '<strong>(' + topAnswerCount + ')</strong> Vote Answer </span>'; | |
found_count++; | |
} | |
} | |
function mod_comments(){ | |
//Comments with Warm to Supernova classification | |
if($('td.comment-score > span.supernova:first').length > 0){ | |
dashHtml += '<span class="supernova">' + sep + '<strong>Supernova</strong> Comment </span>'; | |
found_count++; | |
} | |
if($('td.comment-score > span.hot:first').length > 0){ | |
dashHtml += '<span class="hot">' + sep + '<strong>Hot</strong> Comment </span>'; | |
found_count++; | |
} | |
if($('td.comment-score > span.warm:first').length > 0){ | |
dashHtml += '<span class="warm">' + sep + '<strong>Warm</strong> Comment </span>'; | |
found_count++; | |
} | |
} | |
function mod_track(){ | |
//Tracks | |
var matched = false; | |
$('.post-text *, .comment-text').each(function(){ | |
trackMatched($(this).text()); | |
}); | |
if(trackFoundArr.length > 0){ | |
dashHtml += '<br /><br /><span style="border:rgb(210,210,210) 1px solid;padding:1px 1px 2px 1px" class="warm">' + sep + '<strong>Tracks Found: [<span style="color:maroon;font-weight:bold">' + trackFoundArr.join(', ') + '</span>]</strong> </span>'; | |
} | |
} | |
function mod_userRep(){ | |
//User with rep thresholds in Answers (check within Answers only) | |
$("#answers .user-details .reputation-score").each(function(){ | |
var rep = $.trim($(this).text()); | |
var user_uri = $(this).parent().children('a:first').attr('href'); | |
if(userRepNoobEnabled && user_uri != my_user_uri){ | |
if(rep.length == 1){ //single digit rep, aka Noobie | |
found_user_noob = true; | |
found_count++; | |
} | |
} | |
//Indicate 10k user found, or if not then if a 1k user found | |
if(userRep10kEnabled && user_uri != my_user_uri){ | |
if(rep.indexOf('k') > -1){ //10k+ | |
found_user_10k = true; | |
found_count++; | |
}else{ | |
if(userRep1kEnabled && user_uri != my_user_uri){ | |
if(rep.indexOf(',') > -1){ //1k+ | |
found_user_1k = true; | |
found_count++; | |
} | |
} | |
} | |
} | |
if(found_user_noob && found_user_10k){ | |
return false; //exit .each() loop | |
} | |
}); | |
//Look for noob in Question (already looked in Answers) | |
if(!found_user_noob){ | |
$("#question .user-details .reputation-score:last").each(function(){ | |
var rep = $.trim($(this).text()); | |
var user_uri = $(this).parent().children('a:first').attr('href'); | |
if(userRepNoobEnabled && user_uri != my_user_uri){ | |
if(rep.length == 1){ //single digit rep, aka Noobie | |
found_user_noob = true; | |
found_count++; | |
} | |
} | |
if(found_user_noob){ | |
return false; //exit .each() loop | |
} | |
}); | |
} | |
if(found_user_10k){ | |
var user10kHtml = '<span style="color:#FF8A14">' + sep + '<strong>10k+</strong> User </span>'; | |
dashHtml += user10kHtml; | |
}else if(found_user_1k){ | |
var user1kHtml = '<span style="color:#FF8A14">' + sep + '1k+ User </span>'; | |
dashHtml += user1kHtml; | |
} | |
if(found_user_noob){ | |
var userNoobHtml = '<span class="cool">' + sep + '<strong>Help a Noobie</strong> </span>'; | |
dashHtml += userNoobHtml; | |
} | |
} | |
function setMeHtml(){ | |
var userMeHtml = '<span style="color:#525252">' + sep + '<strong>Me</strong> </span>'; | |
dashHtml += userMeHtml; | |
} | |
function subdashboard(){ | |
$('._subdashboard_').remove(); | |
var subdashHtml = '<div class="_subdashboard_" style="line-height:1.3em;width:75%;padding:2px 2px 10px 2px;">' + dashHtml + '</div>'; | |
$('#answers .answer-paging:first').after(subdashHtml); | |
} | |
/*****************************************/ | |
/*** RUN Script **************************************/ | |
$(document).ready(function(){ | |
//Init | |
runQdashboard(); | |
if(subdashboardEnabled && window.location.href.indexOf('page=') > -1){ | |
subdashboard(); | |
} | |
}); | |
/*****************************************/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment