// pixpls: a tiny "lightbox" work-alike
// pesco 2010, isc license
// -/\- khjk.org

// MINI-README:
// mark image links ('<a>' tags) with 'rel="pic"',
// provide captions with 'title="text"',
// include 'pixpls.js' (no other files needed).
// optional: customize margins and sizes by setting 'pp_' variables (see below)
//     in a preceding '<script>' tag.
// optional: customize css (see below) in a later '<style>' tag.

(function () {      // anon namespace pls
    // config vars
    var cfg = function (d,v) {
        return eval("typeof "+v) === "undefined" ? d : eval(v);
    }
    var mrg = cfg(10, "pp_margin");     // margin to leave around zoom window
    var pad = cfg(10, "pp_padding");    // margin inside of zoom window
    var brd = cfg(1,  "pp_border");     // border width around zoom window
    var th  = cfg(32, "pp_footheight"); // height of text area below img
    var tm  = cfg(5,  "pp_footmargin"); // top margin of text area
    var nf  = cfg(26, "pp_buttonsize"); // font size for nav icons < >

    var css = "\
        #PPbak { background-color:white;\
                 opacity:0.5;\
                 position:fixed;\
                 top:0px;\
                 left:0px;\
                 width:100%;\
                 height:100%; }\
        #PPwin { background-color:white;\
                 border:" + brd + "px solid black;\
                 padding:" + pad + "px;\
                 position:fixed; }\
        #PPtxt { font-size:small;\
                 color:gray;\
                 position:relative;\
                 height:" + th +"px;\
                 margin-top:" + tm + "px;\
                 text-align:center; }\
        #PPcap { position:absolute;\
                 top:0px;\
                 left:0px;\
                 font-style:italic; }\
        #PPnum { position:absolute;\
                 bottom:0px;\
                 right:0px; }\
        #PPdnl { position:absolute;\
                 top:0px;\
                 right:0px; }\
        #PPthr { position:absolute;\
                 width:100%; }\
        .PPfat { font-size:" + nf + "px;\
                 font-weight:bold; }\
        .PPbtn { text-decoration:none; }";

    // image list
    var pics = [];

    // active elements
    var bak;        // shaded background div
    var div;        // our zoom window
    var img;        // the pic inside
    var jmg = null; // the next pic (currently loading)
    var cap;        // caption
    var num;        // image number
    var dlk;        // download link
    var siz;        // image size text
    var prv;        // prev button
    var nxt;        // next button
    var thr;        // throbber <div>

    var tbr = null; // currently running throbber (if any)


    var zclose = function () {
        div.style.visibility = "hidden";
        bak.style.visibility = "hidden";
    };

    var zopen = function (i) {
        var a = pics[i];
        var title = a.getAttribute("title");

        // image metadata
        cap.data = title;
        dlk.href = a.href;
        num.data = (i+1) + "/" + pics.length;

        // nav buttons
        if (i>0) {
            prv.onclick = function () {zopen(i-1); return false;};
            prv.style.opacity = 1;
        } else {
            prv.onclick = function () {return false;};
            prv.style.opacity = 0.5;
        }
        if (i<pics.length-1) {
            nxt.onclick = function () {zopen(i+1); return false;};
            nxt.style.opacity = 1;
        } else {
            nxt.onclick = function () {return false;};
            nxt.style.opacity = 0.5;
        }

        img.style.visibility = "hidden";
        bak.style.visibility = "visible";
        div.style.visibility = "visible";

        // start loading new image
        if (jmg !== null) { jmg.src = null; jmg.onload = null; }
        jmg = document.createElement("img");
        jmg.src = a.href;
        jmg.onclick = zclose;

        tbr = tbr || throbber();

        // switch to image when loaded
        jmg.onload = function () {
            siz.data = jmg.width + "x" + jmg.height;        // show resolution
            var s = Math.round(zshape(jmg) * 100);          // resize window
            cap.data = title + " (scale " + s + "%)";       // show scale

            tbr.stop(); tbr = null;
            div.replaceChild(jmg, img);
            img = jmg; jmg = null;
        }
    };

    var zshape = function (im) {
        var winw,winh;  // browser window dimensions
        var divw,divh;  // zoom window dimensions
        var oriw,orih;  // zoom window dimensions
        var maxw,maxh;  // maximum image dimensions (wrt margins etc.)
        var imgw,imgh;  // scaled image dimensions
        var r;          // image aspect ratio (w/h)
        var x,y;        // zoom window position

        winw = window.innerWidth;
        winh = window.innerHeight;
        oriw = im.width;
        orih = im.height;
        r = oriw / orih;
        maxw = winw - mrg*2 - pad*2 - brd*2;
        maxh = winh - mrg*2 - pad*2 - brd*2 - th - tm;
        imgw = Math.min(oriw, maxw, maxh*r);
        imgh = Math.min(orih, maxh, maxw/r);
        divw = imgw + pad*2 + brd*2;
        divh = imgh + pad*2 + brd*2 + th + tm;
        x = (winw - divw) / 2;
        y = (winh - divh) / 2;

        div.style.top = y + "px";
        div.style.left = x + "px";
        im.width = imgw;
        im.height = imgh;

        return (imgw / oriw);
    };

    var throbber = function () {
        var timer;
        var stopfun;
        var throbfun;
        var t = 0;
        var x;

        thr.style.opacity = "1";
        thr.style.top = (0-img.height/2) + "px";
        thr.style.visibility = "visible";
        throbfun = function () {
            t += 0.015;
            x = (t%2-1); x=x*x;
            thr.style.opacity = 0.5 + 0.5*x;
        };
        timer = window.setInterval(throbfun, 10);

        stopfun = function () {
            window.clearInterval(timer);
            thr.style.visibility = "hidden";
        };
        return {stop:stopfun};
    };

    var zinit = function () {
        var body = document.getElementsByTagName("body")[0];
        var i,j;

        // insert <div> into body
        bak.style.visibility = "hidden";
        div.style.visibility = "hidden";
        body.appendChild(bak);
        body.appendChild(div);

        // get access to <div>'s active subelements
        img = document.getElementById("PPimg");
        cap = document.getElementById("PPcap").firstChild;  // text
        dlk = document.getElementById("PPdlk");             // <a>
        siz = document.getElementById("PPsiz").firstChild   // text
        num = document.getElementById("PPnum").firstChild;  // text
        prv = document.getElementById("PPprv");             // <a>
        nxt = document.getElementById("PPnxt");             // <a>
        thr = document.getElementById("PPthr");

        img.width=400; img.height=300; zshape(img);

        // hook up thumbnail click handlers
        for (i=0,j=0; i<document.links.length; i++) (function () {
            var a = document.links[i];
            var myj = j;                // goes into closure below

            if (a.rel === "pic") {
                pics[j] = a;
                j = j+1;
                a.onclick = function () {zopen(myj); return false;};
            }
        }());
    };


    // insert <style> into head
    (function () {
        var head = document.getElementsByTagName("head")[0];
        var sty = document.createElement("style");

        sty.type = "text/css";
        sty.appendChild(document.createTextNode(css));
        head.appendChild(sty);
    }());

    // create the <div>
    (function () {
        bak = document.createElement("div"); bak.id = "PPbak";
        div = document.createElement("div"); div.id = "PPwin";
        div.innerHTML = "\
            <img id='PPimg'/>\
            <div id='PPtxt'>\
                <span id='PPcap'> </span>\
                <span id='PPdnl'>\
                    <span id='PPsiz'> </span>\
                    <a id='PPdlk'>download</a>\
                </span>\
                <span id='PPnum'> </span>\
                <div id='PPnav' class='PPfat'>\
                    <a id='PPprv' class='PPbtn' href=''>&lt;</a>\
                    <a id='PPnxt' class='PPbtn' href=''>&gt;</a>\
                </div>\
                <div id='PPthr' class='PPfat'>~</div>\
            </div>";
    }());

    // insert <div> into body and hook up click handlers when dom is loaded
    document.addEventListener("DOMContentLoaded", zinit, false);
}());

// vim: ts=4 sw=4 et

