Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@wittman
Created November 29, 2009 07:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wittman/244842 to your computer and use it in GitHub Desktop.
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
// ==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 = '|&nbsp;';
//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&nbsp;Wiki</strong> &nbsp; </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&nbsp; </span>';
}
//Jeff
if(found_atwood){
dashHtml += '<span style="font-weight:bold">' + sep + 'Hey,&nbsp;it\'s&nbsp;<strong><a style="color:blue" href="http://meta.stackoverflow.com/users/1/jeff-atwood">Jeff</a></strong> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </span>';
}
}
function mod_earlyadopter(){
//Early Adopter
if(found_earlyadopter){
dashHtml += '<span style="color:#E0A385">' + sep + '<strong>Early&nbsp;Adopter</strong>&nbsp; </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>&nbsp;Vote&nbsp;Answer&nbsp; </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>&nbsp;Comment&nbsp; </span>';
found_count++;
}
if($('td.comment-score > span.hot:first').length > 0){
dashHtml += '<span class="hot">' + sep + '<strong>Hot</strong>&nbsp;Comment&nbsp; </span>';
found_count++;
}
if($('td.comment-score > span.warm:first').length > 0){
dashHtml += '<span class="warm">' + sep + '<strong>Warm</strong>&nbsp;Comment&nbsp; </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> &nbsp; </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>&nbsp;User&nbsp; </span>';
dashHtml += user10kHtml;
}else if(found_user_1k){
var user1kHtml = '<span style="color:#FF8A14">' + sep + '1k+&nbsp;User&nbsp; </span>';
dashHtml += user1kHtml;
}
if(found_user_noob){
var userNoobHtml = '<span class="cool">' + sep + '<strong>Help&nbsp;a&nbsp;Noobie</strong>&nbsp; </span>';
dashHtml += userNoobHtml;
}
}
function setMeHtml(){
var userMeHtml = '<span style="color:#525252">' + sep + '<strong>Me</strong>&nbsp; </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