greasemonkey script for thread filtering (based on user or subject) for kawf-based forums
at master 109 lines 4.3 kB view raw
1// $Id: kawfilter.user.js,v 1.4 2009/04/06 19:30:19 jcs Exp $ 2// 3// ==UserScript== 4// @name kawfilter 5// @namespace http://jcs.org/code/ 6// @description hide posts and threads made by certain users, or matching certain subjects 7// @include http://forums.wayot.org/other/ 8// @include http://forums.wayot.org/other/pages/* 9// @include http://f.wayot.org/other/ 10// @include http://f.wayot.org/other/pages/* 11// @author joshua stein <jcs@jcs.org> 12// ==/UserScript== 13// 14// Copyright (c) 2008-2009 joshua stein <jcs@jcs.org> 15// 16// Redistribution and use in source and binary forms, with or without 17// modification, are permitted provided that the following conditions 18// are met: 19// 20// 1. Redistributions of source code must retain the above copyright 21// notice, this list of conditions and the following disclaimer. 22// 2. Redistributions in binary form must reproduce the above copyright 23// notice, this list of conditions and the following disclaimer in the 24// documentation and/or other materials provided with the distribution. 25// 3. The name of the author may not be used to endorse or promote products 26// derived from this software without specific prior written permission. 27// 28// THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 29// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 30// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 31// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 32// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 33// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 35// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 37// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38// 39 40// both of these searches are case insensitive and may contain regexp wildcards 41// so be sure to escape regexp metachars (such as \*+?|{[()]^$.) with a 42// backslash, but since they are in quotes, you have to escape the backslash 43// 44// "username (blah)" has to be "username \\(blah\\)" 45// or just use single quotes for such things and write 'username \(blah\)' 46 47// usernames to filter, must match entire username (case insensitive) 48var usernames = [ "username 1", "troll.*" ]; 49 50// posts to filter by subject, only needs to match start of subject line 51var subjects = [ "meal post" ]; 52 53 54// make this false to show replies under hidden posts 55var hide_replies = true; 56 57// make this true to completely kill matching lines instead of collapsing 58var hide_matches = false; 59 60 61var head = document.getElementsByTagName("head")[0]; 62var style = document.createElement("style"); 63style.type = "text/css"; 64style.innerHTML = ".filtered a { font-size: smaller; color: gray; " + 65 "text-decoration: none; }"; 66head.appendChild(style); 67 68var ureg = new RegExp('href="([^"]+)".*&nbsp;&nbsp;(<b>(' + usernames.join('|') 69 + ')<\/b>.*)', 'i'); 70var sreg = new RegExp('href="([^"]+)">(' + subjects.join('|') + 71 ').*&nbsp;&nbsp;<b>(.+)<\/b>(.*)', 'i'); 72 73var lis = document.evaluate("//li", document.body, null, 74 XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); 75for (var i = 0; i < lis.snapshotLength; i++) { 76 a = lis.snapshotItem(i); 77 78 match = false; 79 if (usernames.length > 0 && (m = a.innerHTML.match(ureg))) { 80 a.innerHTML = "<span class=\"filtered\"><a href=\"" + m[1] + 81 "\">post by filtered user " + m[2].replace(/<\/?b>/, "") + 82 "</a></span>"; 83 84 match = true; 85 } else if (subjects.length > 0 && (m = a.innerHTML.match(sreg))) { 86 a.innerHTML = "<span class=\"filtered\"><a href=\"" + m[1] + 87 "\">post by " + m[2].replace(/<\/?b>/, "") + " with " + 88 "filtered subject '" + subjects[j] + "' " + m[3] + 89 "</a></span>"; 90 91 match = true; 92 } 93 94 if (match) { 95 if (hide_replies && a.parentNode) 96 for (var c = 0; c < a.parentNode.childNodes.length; c++) 97 if (a.parentNode.childNodes[c] == a) 98 /* next node should be text, then a <ul> for the reply */ 99 for (var ch = c + 2; ch < a.parentNode.childNodes.length; 100 ch += 2) 101 if (z = a.parentNode.childNodes[ch]) 102 z.style.display = "none"; 103 104 if (hide_matches) { 105 a.style.display = "none"; 106 continue; 107 } 108 } 109}