/b/ackwash

By tkirby Last update Feb 23, 2009 — Installed 5,238 times. Daily Installs: 2, 1, 3, 2, 1, 4, 1, 3, 1, 7, 1, 5, 9, 4, 3, 2, 3, 1, 2, 4, 4, 4, 2, 2, 1, 2, 1, 1, 3, 6, 2, 0

There are 15 previous versions of this script.

// ==UserScript==
// @name          /b/ackwash
// @description   Add tooltips to 4chan quote links (>>8675309).
// @version       2.4
// @author        tkirby, aeosynth, VIPPER
// @include       http://*.4chan.org/*/res/*.html*
// @include       http://4chanarchive.org/*/dspl_thread.php5*
// @include       http://suptg.thisisnotatrueending.com/archive/*
// @include       http://archive.easymodo.net/*/thread/*
// ==/UserScript==

// Copyright (c) 2008, Todd Kirby
// Released under the GNU General Public License
// http://www.gnu.org/copyleft/gpl.html

const TIP_X_OFFSET = 45, TIP_Y_OFFSET = 120;

const op = window.location.search.match(/\d+/) || window.location.pathname.match(/\/(\d+)/)[1];

const tip = document.createElement('div');
tip.id = 'backwash_tooltip';
tip.setAttribute('style', 'display: none; position:absolute; border:1px solid #AAA; background-color:#FFF');
tip.innerHTML = '<table><tr><td id="backwash_tipcell" style="padding: 10px"></td></tr></table>';
document.body.appendChild(tip);

const qts = document.evaluate("//a[@class='quotelink' or starts-with(@href, '#reply')]", document, 
        null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);

for(var i = 0, qt = null; qt = qts.snapshotItem(i++); ) {
    if (! (id = qt.hash.split('#')[1]) ) return;

    if (id == op) {
        qt.innerHTML += ' (OP)';
    } else if (!document.getElementById(id)) {
        qt.innerHTML += ' (Duckroll?)';
        continue;
    }

    qt.setAttribute('onmouseover', 'backwash_show(this, event)');
    qt.setAttribute('onmouseout', 'backwash_hide()');
    qt.setAttribute('onmousedown', 'backwash_hide()');
    qt.setAttribute('onmousemove', 'backwash_track(event)');
}

unsafeWindow.backwash_hide = function() { 
    document.getElementById('backwash_tooltip').style.display = 'none';
}

unsafeWindow.backwash_show = function(me, e) {
    const id = me.hash.split('#')[1];
    const td = document.getElementById('backwash_tipcell');

    [td.innerHTML, td.className] = id == op ? 
        [document.body.innerHTML.match(/<span class="filesize">[^]+?<\/blockquote>/), ''] :
        [document.getElementById(id).innerHTML, 'replyhl'];

    td.removeChild(td.getElementsByTagName('input')[0]);

    unsafeWindow.backwash_track(e);

    document.getElementById('backwash_tooltip').style.display = 'block';
}

unsafeWindow.backwash_track = function(e) {
    const tip = document.getElementById('backwash_tooltip');

    const tip_height = parseInt(
            document.defaultView.getComputedStyle(tip, '').getPropertyValue('height'));
    const cursor_rel_y = e.pageY - window.scrollY;
    const tip_abs_bottom = e.pageY - TIP_Y_OFFSET + tip_height;

    const vp_height = window.innerHeight;
    const vp_bottom = window.scrollY + vp_height;

    tip.style.top = cursor_rel_y < TIP_Y_OFFSET || tip_height > vp_height ? e.pageY -  cursor_rel_y :
                tip_abs_bottom > vp_bottom ? e.pageY - TIP_Y_OFFSET -(tip_abs_bottom - vp_bottom) : 
                e.pageY - TIP_Y_OFFSET + 'px';

    tip.style.left = e.pageX + TIP_X_OFFSET + 'px';
}