// ==UserScript==
// @name allmusic.com - All Music Table Expander
// @author Jeff Prout 
// @namespace http://userjs.org/ 
// @version 1.0
// @description  Fixes allmusic.com's expandable tables so they display
//			properly in Opera.
// @ujs:category site: fixes
// @ujs:published 2005-05-29 21:22
// @ujs:modified 2005-09-19 09:19
// @ujs:documentation http://userjs.org/scripts/site/fixes/allmusic-table-expander 
// @ujs:download http://userjs.org/scripts/download/site/fixes/allmusic-com-table-expander.js
// ==/UserScript==


/* 
 * Creative Commons Attribution-NonCommercial 2.0
 * http://creativecommons.org/licenses/by-nc/2.0/
 */

if (location.hostname.match(/allmusic\.com$/i)){
    document.addEventListener('load', function(ev) {
    
        document.cobblepot_showTimer;
        document.cobblepot_hideTimer;
        document.cobblepot_last;
        
        var rows = document.getElementsByTagName("tr");
        var row;
        for (var i = 0; row = rows[i]; i++) {
            var detailRow, details;
            
            // In discography tables, 'expand' rows directly follow 'visible' rows,
            //   but in album overview tables, text elements come between them.
            nextRow = row.nextSibling;
            if (nextRow && nextRow.nodeType == 3) nextRow = nextRow.nextSibling;

            // Some visible rows don't have matching details.
            if (nextRow && nextRow.nodeType == 1 && nextRow.getAttribute("id") == "trlink"
                    && nextRow.getAttribute("class") == "expand")
            {
                row.addEventListener('mouseover', function() { timerShowDetails(this) }, false)
                row.addEventListener('mouseout', function() { timerHideDetails(this) }, false)

                nextRow.addEventListener('mouseover', function() { timerShow(this) }, false)
                nextRow.addEventListener('mouseout', function() { timerHide(this) }, false)

                // give rows unique and mappable id's
                nextRow.setAttribute("id", "cobblepot_details_" + i);
                row.setAttribute("id", "cobblepot_visible_" + i);

                // hide row containing details
                nextRow.style.display = "none";
            }
        }
    }, false);


// clears previous timers and sets timer to hide given details
timerHide = function(e) {    
    clearTimeout(window.cobblepot_showTimer);
    clearTimeout(window.cobblepot_hideTimer);

    cobblepot_hideTimer = window.setTimeout(function() { hide(e) } , 700);
}


// hides details corresponding to visible row after a delay
timerHideDetails = function(e) {
    var node = findMatch(e, "cobblepot_visible_", "cobblepot_details_");
    if (node) window.timerHide(node);
}


// hides given details
hide = function(e) {

    clearTimeout(window.cobblepot_showTimer);
    clearTimeout(window.cobblepot_hideTimer);

    if (e.getAttribute("class") == "expand") {
        e.style.display = "none";
        var node = findMatch(e, "cobblepot_details_", "cobblepot_visible_");
        if (node) node.setAttribute("class", "visible");
    }

    // hide last shown details
    if (window.cobblepot_last) {
        var temp = window.cobblepot_last;
        window.cobblepot_last = null;
        hide(temp);
    }
}


// shows details corresponding to visible row
timerShowDetails = function(e) {

    var node = findMatch(e, "cobblepot_visible_", "cobblepot_details_");
    if (node) window.timerShow(node);
}


// clears previous timers and sets timer to show particular details
timerShow = function(e) {

    clearTimeout(window.cobblepot_showTimer);
    clearTimeout(window.cobblepot_hideTimer);
    if (e) cobblepot_showTimer = window.setTimeout(function() { show(e) } , 700);
}


// shows particular details
show = function(e) {
    clearTimeout(window.cobblepot_showTimer);
    clearTimeout(window.cobblepot_hideTimer);

    e.style.display = "table-row";

    // hide last (and only) shown details if they aren't
    //   what we want to display
    if (window.cobblepot_last && e != window.cobblepot_last) {        
        window.hide(window.cobblepot_last);
    }

    // adding 'highlight' to class of 'visible' row keeps it highlighted
    //   even while the mouse is over its details
    var node = findMatch(e, "cobblepot_details_", "cobblepot_visible_");
    if (node) node.setAttribute("class", "highlight visible");

    // remember currently displayed details
    window.cobblepot_last = e;
}


// Given a node and two patterns, this function attempts
//    to find the given node's partner based on their ids.
findMatch = function(node, pattern1, pattern2) {
    var attr = node.getAttribute("id");

    // concatenates pattern2 with the remainder of node's id
    //   after pattern1 has been removed from it
    //   Then returns the element with this id.
    if (attr && attr.length >= pattern1.length && attr.substring(0, pattern1.length) == pattern1) {
        var id = pattern2 + attr.substring(pattern1.length, attr.length);
        return document.getElementById(id);
    }

    return null;
}


// prevent amg's javascript from implementing its version
//   of the expandable tables
window.opera.defineMagicFunction(
    'InitializeTable',
    function ( oRealFunc, oThis, oParam1 ) {
        return;
    }
);


// Eliminate a persistent console error
window.opera.defineMagicFunction('tokenFlashPass',function () {});

}

