ETI Archive Quoter

Adds a 'Quote' button to posts in the archives

// ==UserScript==
// @name           ETI Archive Quoter
// @description    Adds a 'Quote' button to posts in the archives
// @namespace      pendevin
// @include        http://boards.endoftheinter.net/showmessages.php*
// @include        http://archives.endoftheinter.net/showmessages.php*
// @include        https://boards.endoftheinter.net/showmessages.php*
// @include        https://archives.endoftheinter.net/showmessages.php*
// @require        http://code.jquery.com/jquery-2.1.4.min.js
// @version        2.1
// ==/UserScript==

//ll breaks without noconflict jquery
this.$ = this.jQuery = jQuery.noConflict(true);

//adds a style to a document and returns the style object *JQUERY
//css is a string, id is an optional string that determines the object's id
function addStyle(css, id) {
    //create a style
    var style = $('<style type="text/css">');
    //add the css data to it
    style.html(css);
    if (id) {
        //remove any style that has our id
        $('#' + id).remove();
        //give our style the id after removing the other stuff. idk if it matters, but i'm too lazy to find out
        style.attr('id', id);
    }
    //add the style into the head
    $('head').append(style);
    //we're outta here
    return style;
}

//finds the last index of a regular expression value
//takes a string and a regex object
//kinda slow :(
function reLastIndex(string, regex) {
    var index = -1;
    //we're going backwards from the end and searching for the first occurrence we find
    for (var i = string.length - 1; i > 0; i--) {
        //once we find it, we're outta here
        if (string.substring(i).search(regex) != -1) {
            index = i;
            break;
        }
    }
    return index;
}

//puts the message body of any quoted-message in its own message div like normal messages for easier styling(hiding)
//livelinks ready *JQUERY
function rearrangeQuotes(container) {
    //this is a for loop or something
    $(container).find('.quoted-message').each(function(i, quote) {
        quote = $(quote);
        //create message div for quote
        var quoteBody = $('<div class="message">');
        //add everything but the message-top to the message div
        quote.contents().each(function(i2, node) {
            node = $(node);
            if (!node.hasClass('message-top') && !node.hasClass('message')) {
                quoteBody.append(node);
            }
        });
        //add the new message div to the quoted-message if it's got anything in it
        if (quoteBody.contents()[0]) {
            quote.append(quoteBody);
        }
    });
}

//add in those pesky triggers
function addQuoteLinks() {
    //i'm lazy so rearrange the quotes
    $('#u0_1 .message-container').each(function(i, container) {
        rearrangeQuotes(container);
    });

    //make sure this topic is closed
    if (location.hostname == 'archives.endoftheinter.net' || $('em').text().match(/This topic has been closed/)) {
        $('#u0_1 .message-container>.message-top').each(function(i, top) {
            top = $(top);
            //message detail link
            var messageDetail = top.children('[href^="/message.php"]');
            //new quote link
            var link = $('<span class="linky quote">Quote</span>');
            messageDetail.after('&nbsp;|&nbsp;', link);
            //oh look we got quoted
            link.on(
                'click',
                top.next().find('.message:first'),
                function(e) {
                    postToText(e.data);
                }
            );
        });
    }
}

//takes a post and returns the text required to get it
function postToText(post) {
    post = $(post);
    var text = $('<div>' + post.html() + '</div>');

    //get rid of sigs
    //if people fuck with the sig belt, this probably won't work
    var lastIndex = reLastIndex(text.html(), /(<br>|<\/div>)?\n?---\n?<br>/g);
    if (lastIndex != -1) {
        text.html(text.html().substring(0, lastIndex));
    }
    //in case of sig parser
    text.find('.sig').remove();

    //deal with spoilers
    text.find('.spoiler_closed').each(function(i, spoiler) {
        spoiler = $(spoiler);
        //build our spoiler notation
        var pointA = spoiler.find('span>a>b').text();
        var pointB = spoiler.find('.spoiler_on_open').html();
        var spoiled = '<spoiler' + (pointA != '<spoiler />' ? ' caption="' + pointA.slice(1, -3) + '">' : '>') + pointB.substring(pointB.indexOf('</a>') + 4, pointB.lastIndexOf('<a class="caption"')) + '</spoiler>';
        //replace the old spoiler
        spoiler.replaceWith(spoiled);
    });

    //deal with quotes
    //this guy only handles rearranged quotes
    //go in reverse order so it can handle nested quotes
    $(text.find('.quoted-message').get().reverse()).each(function(i, quote) {
        quote = $(quote);
        //build our quote notation
        var msgID = quote.attr('msgid');
        //quoted text omitted
        var omitted = (quote.children(':last-child').children(':last-child').text() == ('[quoted text omitted]'));
        //quoting empty posts
        var quoteContent = quote.children(':last-child').html() != undefined ? quote.children(':last-child').html() : '';
        //remove trailing linebreaks
        quoteContent = quoteContent.replace(/(\n|<br>)+$/g, '');
        var quoted = '<quote' + (msgID != '' ? ' msgid="' + msgID + '"' : '') + (!omitted ? '>' + quoteContent + '</quote>' : ' />');
        //replace the old quote
        quote.replaceWith(quoted);
        //if next element is a br, get rid of it
        if (quoted.nextSibling && quoted.nextSibling.nodeName == 'BR') {
            $(quoted).next().remove();
        }
    });

    //deal with images
    //works with all image settings don't worry
    text.find('.imgs').each(function(i, imgs) {
        imgs = $(imgs);
        //there's possibly a bunch of images per div
        imgs.children('a').each(function(i2, img) {
            img = $(img);
            //stick all the images after the imgs div
            var imged = $('<img src="' + img.attr('imgsrc') + '">');
            imgs.before(imged);
        });
        //get rid of the imgs div and replace with a br
        imgs.replaceWith('<br>');
    });

    //deal with links
    //the selector takes care of youtube video embed
    text.find('a:not([href^="javascript"])').each(function(i, a) {
        a = $(a);
        //just need the href to make a link
        a.replaceWith(a.attr('href'));
    });

    //deal with pre tags
    text.find('.pr').each(function(i, pre) {
        pre = $(pre);
        //replacing pre tags so easy
        var post = $('<pre>' + pre.html() + '</pre>');
        pre.replaceWith(post);
    });

    //if you have the userpics script, get rid of the userpic
    text.find('.photo-album-image').remove();

    //if you have my youtube embed script or something similar
    text.find('a[href="javascript:void(0);"]').each(function(i, thing) {
        thing = $(thing);
        //remove that thingy
        thing.parent().remove()
        console.log(thing.attr('href'));
    });

    //final clean-up and display
    var alert = text.html();
    //remove trailing newlines
    alert = alert.replace(/(\n|<br>)+$/g, '');
    //add quote thingy and replace brs for newlines
    alert = '<quote msgid="' + post.attr('msgid') + '">' + alert + '</quote>\n';
    alert = alert.replace(/<br>\n?/g, '\n');
    //create shadow
    var shadow = $('<div id="AQshadowbox">');
    //create textbox to go on top of shadow
    var light = $('<textarea id="AQtextarea">' + alert + '</textarea>');
    //add these guys to the document
    $('body').append(shadow, light);
    //listen for removal
    shadow.on(
        'click',
        function(e) {
            shadow.remove();
            light.remove();
        }
    );
}

//styles
addStyle('\
	#AQshadowbox{\
		position:fixed;\
		top:0px;\
		left:0px;\
		width:100%;\
		height:100%;\
		background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA9JREFUeNpiYGBgaAAIMAAAhQCB69VMmQAAAABJRU5ErkJggg==);\
	}\
	#AQtextarea{\
		position:fixed;\
		top:0px;\
		left:0px;\
		width:70%;\
		height:70%;\
		margin:15%;\
		border:4px solid;\
	}\
', 'archive-quoter');
addStyle('.linky{cursor:pointer;text-decoration:underline;}', 'linky');
//initialize
addQuoteLinks();