Blogger comment moderation

By Jeremy Dunck Last update Jan 15, 2006 — Installed 1,006 times.
// version 0.1 2006-01-15
// Copyright (c) 2006, Jeremy Dunck
// 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 "Hello World", and click Uninstall.
//
// --------------------------------------------------------------------
// ==UserScript==
// @name           Blogger comment moderation
// @namespace      http://dunck.us/code/greasemonkey
// @description    Check off comments to delete, then blast them all at the same time.  Use with Checkrange for extra fun.
// @include        http://*.blogspot.com/*
// @include        http://www.blogger.com/comment.g?*
// ==/UserScript==

//FIXME: replace getelms w/ xpath?

function t(name) {
   return document.getElementsByTagName(name);
}

function $(elm) {
   if (isString(elm)) {
      return document.getElementById(elm);
   } else {
      return elm;
   }
}

function randomURL(url) {
   return  url + (url.indexOf('?') == -1 ?
    '?' : '&') + 'cachemiss=' + 
      Math.floor(Math.random() *10000);
}

function getURLParam(location, key) {
   var pairs = location.search.substring(1).split('&');

   for (var i=0, pair; pair=pairs[i];i++) {
      if (pair.indexOf(key) == 0) {
         return pair.split('=')[1];
      }
   }
   return '';
}

function hasClass(elm, classToCheck) {
   return (' ' + elm.getAttribute('class') + ' ').indexOf(classToCheck) != -1;
}

function addClass(elm, classToAdd) {
   if (!hasClass(elm, classToAdd)) {
      elm.setAttribute('class', elm.getAttribute('class') + ' ' + classToAdd);
   }
}

function hasAttrValue(elm, attr, value) {
   return elm.getAttribute(attr) == value;
}

function newNode(type) {
   return document.createElement(type);
}

function newText(s) {
   return document.createTextNode(s);
}

function isString(wh) {
	return (wh instanceof String || typeof wh == "string");
}


String.prototype.startsWith = function(pref) { 
   return this.indexOf(pref) == 0; 
} 

var buttons = [];
function buttonFiddle(doSomething) {
   for (var button,i=0;button=buttons[i];i++) {
      doSomething(button);
   }
}

function getBlogID() {
   var blogID = getURLParam(window.location, 'blogID');
   
   if (blogID) {
      return blogID;
   }
   var links = t('link');
   for (var i=0;link=links[i];i++) {
      if (hasAttrValue(link, 'rel', 'EditURI')) {
         var url = link.getAttribute('href');
         //<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://www.blogger.com/rsd.g?blogID=11645460">
         blogID = url.substring(url.indexOf('?blogID=') + '?blogID='.length)
         break;
      }
   }
   return blogID;
}

function getCommentID(url) {
   //http://www.blogger.com/delete-comment.g?blogID=11645460&postID=113059419079568966
   return url.substring(url.indexOf('&postID=') + '&postID='.length)
}

if (!document.body.hasChildNodes()) { //sometimes after mass delete, even though
                                       //I'm waiting a bit for blogger to process them,
                                       // the reloaded page is borked.
                                       //If that happens, we'll just reload it again.
   window.location.href = randomURL(window.location.href);
   return;
}

var blogID = getBlogID();
var links = t('a');
var delCheck;
var foundDelLinks = false;
var CHECK_CLASS = 'gm_commentDeleteCheck';
var CHECK_LABEL = 'Delete?';
var BUTTON_PREFIX = 'gm_deleteComments_';
var BUTTON_PROMPT = 'Delete. Forever.';

for (var link, i=0; link=links[i];i++) {
   if (link.href.startsWith('http://www.blogger.com/delete-comment.g?')) { //is delete comment link.
      foundDelLinks = true;
      delCont = newNode('span');
      delCheck = newNode('input');
      delCheck.setAttribute('type', 'checkbox');
      delCheck.setAttribute('value', link.href);
      addClass(delCheck, CHECK_CLASS);
      
      delCont.appendChild(delCheck);
      delCont.appendChild(newText(CHECK_LABEL));
      link.parentNode.replaceChild(delCont.cloneNode(true), link); 
   }
}

if (foundDelLinks) { //serves as the check for whether we have rights to delete comments.
   var commentsDiv = $('comments-block');
   var delButton = newNode('button');
   var delAction = function() {
      var inputs = t('input');
      var selDeletes = [];
      var deleteSuccessCounter = 0;
      var deleteFailureCounter = 0;
      
      for (var i=0,input; input=inputs[i];i++) {
         if (hasClass(input, CHECK_CLASS) && input.checked) {
            selDeletes.push(input);
         }
      }
      if (selDeletes.length == 0) {
         alert('No comments selected for deletion.');  //FIXME: just disable the button when nothing selected?
         return;
      } else {
         var confirmMsg = 'You\'re about to delete ' + selDeletes.length + ' comments.  \nAre you ';
         var howSure = Math.min(Math.floor(selDeletes.length/10), 3);
         for (var i=0;i<howSure;i++) {
            confirmMsg += 'really ';
         }
         confirmMsg += 'sure?'
         if (!confirm(confirmMsg)) { //FIXME: pluralize properly
            return;
         }
      }

      buttonFiddle(function(button){
         button.disabled = true;
      })

      var commentID;
      for (var i=0,input; input=selDeletes[i];i++) {
         commentID = getCommentID(input.getAttribute('value'));
         GM_xmlhttpRequest({
            method:'get',
            url:'http://www.blogger.com/delete-comment.do?' + 'blogID=' + blogID + '&postID=' + commentID + '&scribble=&removeForeverCheckbox=1', 
            headers:{
               'referer':window.location.href
            },
            onload:function(details) {
               if (details.status == 200) {
                  deleteSuccessCounter++;               
               } else {
                  deleteFailureCounter++;                              
               }

               buttonFiddle(function(button){ 
                  var text;
                  if (deleteSuccessCounter + deleteFailureCounter >= selDeletes.length) {
                     text = 'One clean page, comin\' up!';
                     setTimeout(function() { //hackish setTimeout to let blogger process the deletes before reloading.
                        window.location.href = randomURL(window.location.href);
                     }, 1500); 
                  } else {
                     text = '' + deleteSuccessCounter + ' of ' + selDeletes.length + ' deleted.';                     
                     if (deleteFailureCounter > 0) {
                        text += '  ' + deleteFailureCounter + ' failures.'; //FIXME: pluralize
                     }
                  }
                  button.firstChild.data = text;
               });
            }
         }); //end GM_xhr
      } //end for input=selDeletes[i]
   }; //end delAction
   
   delButton.setAttribute('type', 'button');
   delButton.setAttribute('class', 'siteprimary');
   delButton.setAttribute('id', BUTTON_PREFIX+'top')
   delButton.appendChild(newText(BUTTON_PROMPT));
   delButton.addEventListener('click', delAction, false);
   commentsDiv.insertBefore(delButton, commentsDiv.firstChild);
   buttons.push(delButton);
   delButton = delButton.cloneNode(true); 
   delButton.setAttribute('id', BUTTON_PREFIX+'bottom')
   delButton.addEventListener('click', delAction, false); //have to hook again because clone doesn't include listeners.
   commentsDiv.appendChild(delButton);
   buttons.push(delButton);

} //end del links found