Mefi deleted posts

By Plutor Last update Oct 16, 2008 — Installed 6,004 times. Daily Installs: 4, 4, 5, 2, 3, 5, 1, 3, 6, 2, 1, 3, 1, 6, 7, 10, 1, 5, 3, 18, 3, 8, 4, 4, 4, 5, 18, 3, 1, 9, 8, 5

There are 3 previous versions of this script.

// ==UserScript==
// @name           Mefi deleted posts
// @namespace      http://plutor.org/
// @description    Shows deleted posts on the Metafilter front page
// @include        http://*.metafilter.com/
// @include        http://*.metafilter.com/daily.mefi/*
// @include        http://*.metafilter.com/index.cfm?*
// @include        http://*.metafilter.com/home/recentposts
// @exclude        http://music.metafilter.com/
// @exclude        http://music.metafilter.com/*
// @require        http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js
// ==/UserScript==
//
// DONE 2008-10-??
// * jQuery
// * AJAX to inline FPP text

var debug = 0;
var deletedbar = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAgCAYAAADaDrJgAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9gKEBI1LdBckgEAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAO0lEQVQoz2NkYGBg%2BH%2FmzH8GKGA0MWFEEYApYGLAAhjRVeIGMJXINLXMJKx9YN2JzY5BGJ6MdEsMRAMAp8dakMN66%2FQAAAAASUVORK5CYII%3D';

/*
 * mdp_init
 *
 * Finds the deleted threads on the page.
 */
function mdp_init() {
    var i = 0;
    var threadlist = new Array();
    var threadinfo = new Object();

    // First pass, collect all the thread objects and ids
    $("div[class=copy] span[class=smallcopy]:has(a[href*=/user/]) a:contains(comment)," +
      "div[class=copy] span[class=smallcopy]:has(a[href*=/user/]) a:contains(answer)")
        .each( function() {
            var url = $(this).attr('href');
            mdp_log("Checking " + url);
            var matches = url.match(/(http:\/\/([^\.]*\.)?metafilter\.com)?\/(\d+)\//i);
            if (matches && matches.length > 1) {
                var threadid = parseInt(matches[3]);
                mdp_log("Adding " + threadid + " to list of seen threads");
                var anon = $(this).parent().html().indexOf("/user/17564");

                threadlist.push(threadid);
                threadinfo[threadid] = { obj: $(this),
                                         anon: (anon != -1) };
            }
        } );

    // Second pass, find the deleted threads and do the needful
    var lastthread = 0;
    for (var i=0; i<threadlist.length; ++i) {
        var threadid = threadlist[i];

        if (!threadinfo[threadid] || threadinfo[threadid].anon) continue;
        var thread = threadinfo[threadid].obj;

        if ((lastthread > 0) && (threadid < lastthread - 1)) {
            var post = thread.parents("div[class=copy]");
            for (var j = lastthread - 1; j > threadid; --j) {
                if (threadinfo[j]) continue;

                mdp_handle_deleted( j, post );
            }
        }

        lastthread = threadid;
    }
}

/*
 * mdp_handle_deleted
 *
 * Given a thread id and the sibling to insert before, does the right thing for
 * a deleted thread
 */
function mdp_handle_deleted( threadid, nextSibling ) {
    mdp_log("Thread " + threadid + " was deleted");

    var content = GM_getValue('content_' + document.domain + '_' + threadid);
    try {
        content = eval(content);
    } catch(e) {
        mdp_log("Couldn't evaluate: " + e);
        content = null;
    }

    if (content != null) {
        mdp_log("Got content from cache: " + content.content.length + " bytes");
        nextSibling.before(
            '<div class="deletedpost copy" id="deletedpost_' + threadid + '">' +
            '</div><br>'
        );

        mdp_replace(threadid, content);
    } else {
        mdp_log("Requesting content for: " + threadid);

        nextSibling.before(
            '<div class="deletedpost copy" id="deletedpost_' + threadid + '">' +
            '<span class="smallcopy">' +
            'Getting deleted thread: <a href="/' + threadid + '/">' + threadid + '</a>' +
            '</span></div><br>'
        );
        $("#deletedpost_" + threadid + " span[class=smallcopy]").css('color', '#f99');

        mdp_getcontent(threadid);
    }
}

/*
 * mdp_getcontent
 *
 * Given a thread id, fires request for the thread, gets the post content,
 * deletion reason, and the reason's background color from the response.
 * Caches the data and calls mdp_replace.
 */
function mdp_getcontent(threadid) {
    $.get('/' + threadid + '/', {}, function(data, textStatus) {
        mdp_log("Got data for " + threadid + ": " + data.length + " bytes");

        // XXX - I want to use jQuery for this, but it doesn't seem to be
        // totally comfortable parsing whole AJAX-ed HTML
        var matches;

        // Get the reason
        var reason = "";
        matches = data.match(/<p class="reason"[^>]*>(.*?)<\/p>/);
        if (matches && matches.length == 2) reason = matches[1];
        mdp_log("Got reason text: '" + reason + "'");

        // Get the post content
        var post = "";
        matches = data.match(/<div class="copy"[^>]*>([\s\S]*?)<\/?(div|span)/);
        if (matches && matches.length == 3) {
            post = matches[1];
            if (matches[2] == 'div') // There was more inside
                post += '<span class="smallcopy">'
                      + '[<a href="/' + threadid + '/">more inside</a>]'
                      + '</span><br>';
        }
        mdp_log("Got post text: '" + post + "'");

        // Get the footer
        var foot = ""
        matches = data.match(/<div class="copy"[^>]*>([\s\S]*?)<span class="smallcopy"[^>]*>([\s\S]*?)<\/span>/);
        if (matches && matches.length == 3) foot = matches[2];
        mdp_log("Got foot text: '" + foot + "'");

        // Get the stamp
        var stamp = ""
        matches = data.match(/<span class="smallcopy"[^>]*>\S* \d*, \d* (\d*:\d* [AP]M)/);
        if (matches && matches.length == 2) stamp = matches[1];
        mdp_log("Got stamp: '" + stamp + "'");

        // Cache it
        var content = {
            'content': post,
            'foot': foot,
            'url': '/' + threadid + '/',
            'stamp': stamp,
            'reason': reason,
        };
        GM_setValue('content_' + document.domain + '_' + threadid, content.toSource());

        // Show it
        mdp_replace(threadid, content);
    }, "html");
}

/*
 * mdp_replace
 *
 * Given a thread id and a content hash, replaces the content of the deleted
 * post empty div with the "right" stuff.
 */
function mdp_replace(threadid, content) {
    // Make the footer look a little more like the normal page
    if (content.foot.match(/ \((\d* comments?) total\)/)) {
        content.foot = content.foot.replace(
            / \(\d* comments? total\)[\s\S]*/,
            ' at ' + content.stamp + ' - ' +
            '<a href="' + content.url + '">' +
            RegExp.$1 + '</a>'
        );
    }

    // Build the post and insert it into the dom
    var postcontent = '<div class="deletedpost_show">' + content.content
                    + '<span class="smallcopy">' + content.foot + '</span>'
                    + '<br><br>'
                    + '<span class="smallcopy">' + content.reason + '</span></div>'
                    + '<div class="deletedpost_hide">Deleted thread: <a href="' + content.url + '">' + threadid + '</a></div>';

    $("#deletedpost_" + threadid)
        .empty().append(postcontent)
        .css( {
            background: 'transparent url(' + deletedbar + ') repeat-y left',
            color: '#f99',
            padding: '0.5em 0.5em 0.5em 1em'
        } )
        .find("span[class=smallcopy]").css('color', '#f99');

    // Add the hide button
    $("#deletedpost_" + threadid)
        .append('<div class="smallcopy hidebutton">Hide</div>')
        .hover(
            function() {
                var t = $(this);
                var b = $(this).children('.hidebutton');
                var hidey = t.offset().top - 5;
                var hidex = t.offset().left - b.width() - 9;
                b.show().css({
                    'left': hidex + 'px',
                    'top': hidey + 'px',
                    'height': (t.height() - 10) + 'px'
                });
            },
            function() {
                $(this).children('.hidebutton').hide();
            }
        )
        .children('.hidebutton')
        .css({
            'color': '#ccc',
            'position': 'absolute',
            'font-size': '80%',
            'padding': '5px',
            'cursor': 'pointer'
        })
        .hide()
        .click( function() {
            $(".deletedpost").each( function() {
                $(this).children('.deletedpost_show').toggle();
                $(this).children('.deletedpost_hide').toggle();
                if ($(this).children('.hidebutton').html() == "Hide") {
                    $(this).children('.hidebutton').hide().html("Show");
                    GM_setValue("hideall", 1);
                } else {
                    $(this).children('.hidebutton').hide().html("Hide");
                    GM_setValue("hideall", 0);
                }
            } );
        });

    // Show or hide?
    var hide = GM_getValue("hideall");
    if (hide) {
        $("#deletedpost_" + threadid + ' .deletedpost_show').hide();
        $("#deletedpost_" + threadid + ' .hidebutton').html("Show");
    } else {
        $("#deletedpost_" + threadid + ' .deletedpost_hide').hide();
    }
}

function mdp_log(t) {
    if (debug)
        GM_log(t);
}

mdp_init();