ii-block

ii-block.user.js
// ==UserScript==
// @name            ii-block
// @namespace       http://enquirer.improbableisland.com/dokuwiki/doku.php?id=greasemonkey
// @author          Full Metal Lion
// @description     Blocks a user in chat
// @version         2.1
// @match           *://*.improbableisland.com/*
// @exclude         *://enquirer.improbableisland.com/*
// @icon            http://improbableisland.com/favicon.ico
// @grant           none
// ==/UserScript==
 
//USER-SET VARIABLES:
var blockedUserIDs = []; //put users ids here, separated by commas (eg [100001,47,201])
var showBlankLines = true; //set this to false if you want no indication that a message was blocked
 
//INTERNAL PROGRAM LOGIC:
 
//helper function
function delL(element){
  if(element && element.className != "singlecomment"){
    delL(element.previousSibling);
    element.remove();
  }
}
 
//the actual function of interest
function removeBlockedMessages(){
  for (var x of blockedUserIDs){
    for (var m of document.querySelectorAll("a[href='bio.php?char="+x+"']")){
      //you'd think that we could just call .parent.remove() on the things we find
      // but actually the chat html is hot garbage and nested improperly, so we have to do this
      delL(m.previousSibling);
      if(showBlankLines && m.innerHTML){ //there are actually two elements per comment, one empty.
        //we only want one (else we'd get double spacing) so we pick the nonempty one.
        m.before(document.createElement('p'));
      }
    }
    for (var p of ps){
      var re = RegExp('<a href="bio\\.php\\?char='+x+'" target="_blank" class="commentarymouseoverlink">[\\w\\W]*?</a>[\\w\\W]*?<br>','gi');
      var egregiousExtraMouseoverLink = RegExp('<a href="bio\\.php\\?char='+x+'" target="_blank" class="commentarymouseoverlink"><!--le--></a></span>','gi');
      var html = p.innerHTML.replace(egregiousExtraMouseoverLink,'');
      p.innerHTML = html.replace(re,'');
    }
  }
}
 
var ps = []; //find chat areas on page load
for (var c of document.getElementsByClassName("singlecomment")){
  var p = c.parentNode;
  if(p&&!ps.includes(p)&&p.className!="singlecomment"){
    ps.push(p);
  }
}
 
removeBlockedMessages(); //invoke function when page loads
 
//run removeBlockedMessages whenever an ajax chat auto-update completes)
//(This is the part that doesn't work in greasemonkey without later shenanigans)
//adapted from from https://stackoverflow.com/a/29293383 :
(function(open) {
  window.XMLHttpRequest.prototype.open = function() {
    this.addEventListener("readystatechange", function() {
      if(this.readyState == 4 && this.responseURL.startsWith("https://www.improbableisland.com/ajaxchat.php")){
        removeBlockedMessages();
      }
    }, false);
    open.apply(this, arguments);
  };
})(window.XMLHttpRequest.prototype.open);
 
 
//If we're running on a system that supports @grant none, then we're done.
//However, the greasemonkey extension on Firefox does not
//so we must do something special to support it
//Here I use the Content Scope Runner as found in
//https://wiki.greasespot.net/index.php?title=Content_Scope_Runner&oldid=7215
if ('undefined' == typeof __PAGE_SCOPE_RUN_II_BLOCK_) {
  (function page_scope_runner() {
    // If we're _not_ already running in the page, grab the full source
    // of this script.
    var my_src = "(" + page_scope_runner.caller.toString() + ")();";
 
    // Create a script node holding this script, plus a marker that lets us
    // know we are running in the page scope (not the Greasemonkey sandbox).
    // Note that we are intentionally *not* scope-wrapping here.
    var script = document.createElement('script');
    script.setAttribute("type", "text/javascript");
    script.textContent = "var __PAGE_SCOPE_RUN_II_BLOCK_ = true;\n" + my_src;
 
    // Insert the script node into the page, so it will run, and immediately
    // remove it to clean up.  Use setTimeout to force execution "outside" of
    // the user script scope completely.
    setTimeout(function() {
      document.body.appendChild(script);
      document.body.removeChild(script);
    }, 0);
  })();
 
  // Stop running, because we know Greasemonkey actually runs us in
  // an anonymous wrapper.
  return;
}