// ==UserScript==
// @name mlmb
// @namespace http://thinkingoutquiet.wordpress.com/
// @description Media Lens Message Board - add-on to improve the usability of the board
// @include http://members5.boardhost.com/medialens/
// @include http://members5.boardhost.com/medialens/index*
// @include http://members5.boardhost.com/medialens/thread*
// @include http://members5.boardhost.com/medialens/msg*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_listValues
// @version 4.1
// @require http://code.jquery.com/jquery-1.7.2.min.js
// ==/UserScript==
// Global variables
var url = window.location.href;
var indexPage = (url == "http://members5.boardhost.com/medialens/" || url.substr(0,45) == "http://members5.boardhost.com/medialens/index");
var threadPage = (url.substr(0,46) == "http://members5.boardhost.com/medialens/thread");
var msgPage = (url.substr(0,43) == "http://members5.boardhost.com/medialens/msg");
var threadName = '';
var threadSubList = '';
var threadList = '';
var filter = GM_getValue("var-filter","all");
var option_filter_enabled = GM_getValue("var-option-filter-enabled",true);
GM_setValue("var-option-filter-enabled",option_filter_enabled);
var option_markers_enabled = GM_getValue("var-option-markers-enabled",true);
GM_setValue("var-option-markers-enabled",option_markers_enabled);
var option_hide_quoted_text = GM_getValue("var-option-hide-quoted-text",true);
GM_setValue("var-option-hide-quoted-text",option_hide_quoted_text);
var option_collapse_threads = GM_getValue("var-option-collapse-threads",true);
GM_setValue("var-option-collapse-threads",option_collapse_threads);
var option_collapse_sub_threads = GM_getValue("var-option-collapse-sub-threads",true);
GM_setValue("var-option-collapse-sub-threads",option_collapse_sub_threads);
var option_collapse_read_messages = GM_getValue("var-option-collapse-read-messages",true);
GM_setValue("var-option-collapse-read-messages",option_collapse_read_messages);
var option_highlight_all_read = GM_getValue("var-option-highlight-all-read",true);
GM_setValue("var-option-highlight-all-read",option_highlight_all_read);
var option_view_thread_link = GM_getValue("var-option-view-thread-link",true);
GM_setValue("var-option-view-thread-link",option_view_thread_link);
// Styles
var styles = '<style>' +
'div#mlmb_options {display:none; position:fixed; left:50%; width:450px; margin-left:-225px; top:100px; border:2px solid #000; background-color:#cef; padding:5px; font-family:sans-serif;}' +
'div#mlmb_options a.close {padding:2px 4px; float:right; text-decoration:none; border:1px solid #000; font-weight:bold;}' +
'div#mlmb_options p {margin:0 0 4px 0;}' +
'div#mlmb_options p.sub {margin-left:16px;}' +
'div#mlmb_options a.reload {font-weight:bold;}' +
'div#mlmb_options a:visited.reload {color:#00f;}';
if (indexPage) {
styles += 'body {background-color:#eee; margin-left:30px; }' +
'table#linkstable table td {vertical-align:top;}' +
'span.collapseButton {font-size:12px; margin-right:8px; padding: 0 5px; background-color:#f88; border:1px solid #000; cursor:pointer;}' +
'span.expandButton {font-size:12px; margin-right:8px; padding: 0 5px; background-color:#8f8; border:1px solid #000; cursor:pointer;}' +
'form.threadFilter {margin-right:8px;}' +
'div.threadButtons {position:absolute; left:-74px; width:62px;}' +
'div.threadButtons span {float:right; margin-right:4px; padding:0 5px;}' +
'span.toggleButton {background-color:#8f8; border:1px solid #000; cursor:pointer; font-weight:bold;}' +
'span.markRead {color:#fff;}' +
'span.closed {background-color:#f88;}' +
'span.viewThreadLink {padding-left:20px; display:none;}' +
'span.starButton {color:#999; width:10px; text-align:center; background-color:#fff; border:1px solid #777; cursor:pointer;}' +
'span.starred {background-color:#07f; color:#fff; border-color:#000;}' +
'span.ignored {background-color:#999; color:#fff;}' +
'table#linkstable + ul > table > tbody > tr > td > font > li {position:relative; list-style: none; background-color:#fff; margin-bottom:8px; padding:6px; border-left:8px solid #fff; border-right:8px solid #fff;}' +
'table#linkstable + ul > table > tbody > tr > td > font > li.posted {border-left-color: #f00; border-right-color: #f00;}' +
'table#linkstable + ul > table > tbody > tr > td > font > li.starred {border-left-color: #07f;}' +
'table#linkstable + ul > table > tbody > tr > td > font > li.ignored {border-left-color:#eee; border-right-color:#eee; background-color:#eee;}';
}
styles += 'span.subCollapse {background-color:#8f8;padding-left:4px;padding-right:4px;cursor:pointer;}' +
'span.subClosed {background-color:#f88;}';
if (threadPage || msgPage) {
styles += 'div.toggleQuotedButton {font-size: 11px; cursor:pointer; background-color:#f88; display:inline-block; border:1px solid #000; padding: 2px 4px; margin: 4px 0 8px 0;}' +
'.quoteBlock {display:none;}';
}
if (threadPage) {
styles += 'div#fullThreadControls {font-family:sans-serif; position:fixed; top:10px; right: 10px;}' +
'div.collapseButton {font-size:14px; margin-bottom:6px; padding: 0 5px; background-color:#f88; border:1px solid #000; cursor:pointer;}' +
'div.expandButton {font-size:14px; margin-bottom:6px; padding: 0 5px; background-color:#8f8; border:1px solid #000; cursor:pointer;}';
}
styles += '</style>';
// Functions
function getThreadInfo(t) { // t is a button span
threadName = t.parent().next('a').attr('name');
threadSubList = t.parent().parent().children("ul");
threadList = t.parent().parent();
}
function toggleThread(t) {
getThreadInfo(t);
threadSubList.toggle();
t.toggleClass("closed");
t.parent().parent().find("span.viewThreadLink").toggle();
GM_setValue(threadName, !t.hasClass("closed"));
}
function restoreMarkers(t) {
getThreadInfo(t);
var star = GM_getValue(threadName + "-star", "");
switch (star) { // restores starred & ignored threads
case "*":
t.addClass("starred");
t.html("*");
threadList.addClass('starred');
break;
case "i":
t.addClass("ignored");
t.html("i");
threadList.addClass('ignored');
break;
}
}
function restoreThread(t) {
getThreadInfo(t);
if (!GM_getValue(threadName, true)) { // assumes thread is open, and (potentially) closes it
threadSubList.toggle();
t.toggleClass("closed");
t.parent().parent().find("span.viewThreadLink").toggle();
};
}
function collapseThread(t) {
getThreadInfo(t);
threadSubList.hide();
t.addClass("closed");
t.parent().parent().find("span.viewThreadLink").show();
GM_setValue(threadName, false);
}
function expandThread(t) {
getThreadInfo(t);
threadSubList.show();
t.removeClass("closed");
t.parent().parent().find("span.viewThreadLink").hide();
GM_setValue(threadName, true);
}
function cycleStarred(t) {
getThreadInfo(t);
if (t.hasClass("starred")) { // cycle to ignored
threadList.addClass('ignored').removeClass('starred');
t.addClass('ignored').removeClass('starred');
t.html("i");
GM_setValue(threadName + "-star", "i");
}
else if (t.hasClass("ignored")) { // cycle to neutral
threadList.removeClass('ignored');
t.removeClass('ignored');
t.html(" ");
GM_deleteValue(threadName + "-star");
}
else { // cycle to starred
threadList.addClass('starred');
t.addClass('starred');
t.html("*");
GM_setValue(threadName + "-star", "*");
}
}
function changeFilter(t) {
filter = t.attr("value");
GM_setValue("var-filter", filter);
$("span.starButton").each(function() {applyFilter($(this))});
$("form.threadFilter select").blur();
}
function applyFilter(t) {
var list = t.parent().parent();
switch (filter) {
case "all":
list.show();
break;
case "hide_ignored":
if (list.hasClass("ignored")) {
list.hide();
}
else {
list.show();
}
break;
case "starred":
if (list.hasClass("starred")) {
list.show();
}
else {
list.hide();
}
break;
case "contributed":
if (list.hasClass("posted")) {
list.show();
}
else {
list.hide();
}
break;
}
}
// Main code
$(document).ready(function() {
// Add global styles
$("head").append(styles);
// Options
$("body center font[size=2]").html($("body center font[size=2]").html().replace(']','| <a href="" id="mlmb_options_link">add-on options</a> ]'));
$("a#mlmb_options_link").click(function() {$("#mlmb_options").toggle(); return false;});
var options = '<div id="mlmb_options"><form><a href="" class="close">X</a>' +
'<p><b>mlmb script v4.1 options</b> | <a href="http://thinkingoutquiet.wordpress.com/mlmb-add-on/" target="_blank">see website for details</a></p><hr>' +
'<p><input type="checkbox" name="collapse-threads"> Enable thread collapsing</p>' +
'<p class="sub"><input type="checkbox" name="collapse-sub-threads"> Enable sub-thread collapsing</p>' +
'<p class="sub"><input type="checkbox" name="view-thread-link"> Add \'View thread\' link when collapsed</p>' +
'<p class="sub"><input type="checkbox" name="highlight-all-read"> Highlight when thread is fully read</p><hr>' +
'<p><input type="checkbox" name="markers-enabled"> Enable thread markers (star/ignore/author)</p>' +
'<p class="sub"><input type="checkbox" name="filter-enabled"> Enable thread filtering</p><hr>' +
'<p><input type="checkbox" name="hide-quoted-text"> Hide quoted text</p><hr>' +
'<p><input type="checkbox" name="collapse-read-messages"> Collapse read messages in thread view</p><hr>' +
'<p><a href="" class="reload">Reload page to see changes</a></p>' +
'</form></div>';
$("body").append(options);
$("#mlmb_options input").change(function() {
setting = ($(this).attr("checked") == "checked");
GM_setValue("var-option-" + $(this).attr("name"), setting);
if ($(this).attr("name") == "collapse-threads" && setting == false && $('input[name="collapse-sub-threads"]').attr("checked") == "checked") {
$('input[name="collapse-sub-threads"]').trigger("click");
}
if ($(this).attr("name") == "collapse-sub-threads" && setting == true && $('input[name="collapse-threads"]').attr("checked") != "checked") {
$('input[name="collapse-threads"]').trigger("click");
}
if ($(this).attr("name") == "collapse-threads" && setting == false && $('input[name="view-thread-link"]').attr("checked") == "checked") {
$('input[name="view-thread-link"]').trigger("click");
}
if ($(this).attr("name") == "view-thread-link" && setting == true && $('input[name="collapse-threads"]').attr("checked") != "checked") {
$('input[name="collapse-threads"]').trigger("click");
}
if ($(this).attr("name") == "collapse-threads" && setting == false && $('input[name="highlight-all-read"]').attr("checked") == "checked") {
$('input[name="highlight-all-read"]').trigger("click");
}
if ($(this).attr("name") == "highlight-all-read" && setting == true && $('input[name="collapse-threads"]').attr("checked") != "checked") {
$('input[name="collapse-threads"]').trigger("click");
}
if ($(this).attr("name") == "markers-enabled" && setting == false && $('input[name="filter-enabled"]').attr("checked") == "checked") {
$('input[name="filter-enabled"]').trigger("click");
}
if ($(this).attr("name") == "filter-enabled" && setting == true && $('input[name="markers-enabled"]').attr("checked") != "checked") {
$('input[name="markers-enabled"]').trigger("click");
}
});
$("#mlmb_options input").each(function() {
if (GM_getValue("var-option-" + $(this).attr("name"),false) == true) {$(this).attr("checked","checked");}
});
$("#mlmb_options a.close").click(function() {$("#mlmb_options").hide(); return false;});
$("#mlmb_options a.reload").click(function() {location.reload(true);});
// Delete old saved thread states, to avoid filling up Firefox store
var numKeysToSave = 3000;
var keys = GM_listValues();
keys.sort();
for (var i = 0; i < (keys.length - numKeysToSave); i++) {
GM_deleteValue(keys[i]);
}
if (indexPage) {
// Insert thread toggle buttons & star buttons
// $("table#linkstable + ul > li").each(function() {
$("table#linkstable + ul > table > tbody > tr > td > font > li").each(function() {
var starButton = '';
var toggleButton = '';
var length;
var markRead = '';
length = $(this).find('li').length + 1;
if (option_collapse_threads) {
if (option_highlight_all_read) {
if ($(this).find('a[style="color: #999999;"]').length == length) {
markRead = " markRead";
}
}
toggleButton = '<span class="toggleButton' + markRead + '">' + length + '</span>';
if (option_view_thread_link) {
viewThread = '<span class="viewThreadLink"><font size="1"><a style="text-decoration: none;" href="thread/' + $(this).find('a').first().attr('name') + '.html"><font color="#000080">View thread</font></a> <font color="999999">»</font></font></span>';
$(this).find('i').first().after(viewThread);
}
}
if (option_markers_enabled) {
starButton = '<span class="starButton"> </span>';
}
$(this).prepend('<div class="threadButtons">' + toggleButton + starButton + '</div>');
});
if (option_collapse_threads) {
// Insert 'collapse all' & 'expand all' buttons
$("table#linkstable table tr").prepend('<td><span class="expandButton">Expand all</span></td>');
$("table#linkstable table tr").prepend('<td><span class="collapseButton">Collapse all</span></td>');
// Enable 'collapse all' and 'expand all' buttons click events
$("span.collapseButton").click(function() {
$("span.toggleButton").each(function() {collapseThread($(this))})
});
$("span.expandButton").click(function() {
$("span.toggleButton").each(function() {expandThread($(this))})
});
// Enable toggle button click event
$("span.toggleButton").click(function() {toggleThread($(this))});
// Restore saved thread collapse states
$("span.toggleButton").each(function() {restoreThread($(this))});
}
// Star, etc markers
if (option_markers_enabled) {
// Enable starred button click event
$("span.starButton").click(function() {cycleStarred($(this))});
// Flag threads with contributions from user
var username1 = $("table#logininfo div#cookiegreeting b").html();
var username2 = $("table#logininfo a[target=user_info] font").html();
$("li b:contains('" + username1 + "')").closest('table#linkstable + ul > li').addClass('posted');
$("li b:contains('" + username2 + "')").closest('table#linkstable + ul > li').addClass('posted');
// Restore saved thread marker states
$("span.starButton").each(function() {restoreMarkers($(this))});
}
// Filter
if (option_filter_enabled) {
// Insert filter drop-down
var filterOptions = '<option value="all">Show All Threads</option>' +
'<option value="hide_ignored">All Except Ignored</option>' +
'<option value="starred">Only Starred *</option>' +
'<option value="contributed">Only Contributed</option>';
$("table#linkstable table tr").prepend('<td><form class="threadFilter"><select>' + filterOptions + '</select></form></td>');
// Enable filter drop-down change event
$("form.threadFilter select").change(function() {changeFilter($(this))});
// Apply filter
$("form.threadFilter select").attr("value",filter);
$("span.starButton").each(function() {applyFilter($(this))});
}
} // end of if indexPage
// Collapse sub-threads
if (indexPage && option_collapse_sub_threads) { // Ideally want this on msg page, but click event not working... ??
if (indexPage) {selector = $("table#linkstable + ul > li li > ul > li");}
if (msgPage) {selector = $("ul ul").first().find("li > ul > li");}
selector.parent().parent().each(function() {
var subThreadId = $(this).children("a").first().attr('href').replace(/[^0-9]/g,'');
if (GM_getValue(subThreadId, true)) {
$closed = '">-';
}
else {
$closed = ' subClosed">+';
$(this).find("ul").first().hide();
}
$(this).prepend('<span name="' + subThreadId +'" class="subCollapse' + $closed + '</span> ');
$(this).css('list-style-type','none');
$(this).css('margin-left','-18px');
});
$("span.subCollapse").click(function() {
$(this).parent().find("ul").first().toggle();
$(this).toggleClass("subClosed");
if ($(this).hasClass("subClosed")) {
$(this).html('+');
GM_setValue($(this).attr('name'), false);
}
else {
$(this).html('-');
GM_setValue($(this).attr('name'), true);
}
});
} // End of Collapse Sub Threads
// Hide Quoted Text
if ((threadPage || msgPage) && (option_hide_quoted_text)) {
$("td > font").each(function() {
var a = $(this).html();
if (!a.match(/<object/)) { // don't process text with embedded video
a = a.replace('<p></p>','<br>'); // Make line-break before signature in br
var htmlArray = a.split('<br>');
var inQuoteBlock = false;
var quoteCount = 0;
var finishOnQuote = false;
var inSignature = false;
for (var i = 0; i < htmlArray.length; i++) {
if (htmlArray[i].match(/<hr/)) { inSignature = true; }
if (htmlArray[i].charAt(0) == ":") {
if (!inQuoteBlock) { // First line of a quote block
quoteCount += 1;
htmlArray[i] = '<span class="dummyQuoteBlock' + quoteCount + '">' + htmlArray[i];
inQuoteBlock = true;
finishOnQuote = true;
inSignature = false;
}
}
else {
if (inQuoteBlock) { // End of a quote block
if ((htmlArray[i].length > 2) && (inSignature == false)) {
finishOnQuote = false;
}
htmlArray[i] = '</span>' + htmlArray[i];
inQuoteBlock = false;
}
else {
if (inSignature == false) { finishOnQuote = false; }
inQuoteBlock = false;
}
}
}
var htmlDone;
if (finishOnQuote) { // Hide final quote
htmlDone = htmlArray.join('<br>');
htmlDone = htmlDone.replace('<span class="dummyQuoteBlock' + quoteCount + '">', '<div class="toggleQuotedButton">: Show Quoted Text</div><span class="quoteBlock"><br>');
}
else { // Don't hide any quotes
htmlDone = a;
}
$(this).html(htmlDone);
}
});
// Enable Show/Hide Quote buttons
$("div.toggleQuotedButton").click(function() {
var block = $(this).next();
block.toggleClass("quoteBlock");
if (block.hasClass("quoteBlock")) {
$(this).html(": Show Quoted Text");
$(this).css("background-color","#f88");
}
else {
$(this).html(": Hide Quoted Text");
$(this).css("background-color","#8f8");
}
});
} // End of Hide Quoted Text
// Message Collapsing in Full Thread View
if (threadPage && option_collapse_read_messages) {
$("body").append('<div id="fullThreadControls"><div class="collapseButton">Collapse all</div><div class="expandButton">Expand all</div><div style="font-size:14px;"><i>Click titles to<br>toggle individual<br>messages</i></div></div>');
$("body").css("background-color","#eee");
$("table p font[size=4]").parent().parent().css("background-color","#fff");
$("table p font[size=4]").parent().parent().css("padding","5px");
$("table p font[size=4][color=#999999]").parent().parent().find("p:eq(1)").nextAll().hide();
$("table p font[size=4]").css("cursor","pointer");
$("table p font[size=4]").click(function() {
$(this).parent().parent().find("p:eq(1)").nextAll().toggle();
});
// Enable 'collapse all' and 'expand all' buttons click events
$("div.collapseButton").click(function() { $("table p font[size=4]").parent().parent().find("p:eq(1)").nextAll().hide(); });
$("div.expandButton").click(function() { $("table p font[size=4]").parent().parent().find("p:eq(1)").nextAll().show(); });
} // End of Message Collapsing in Full Thread View
});