﻿// Shadowbox Basevar Shadowbox={};Shadowbox.lib=function(){var F={};var C=/(-[a-z])/gi;var B=function(H,I){return I.charAt(1).toUpperCase()};var G=function(I){var H;if(!(H=F[I])){H=F[I]=I.replace(C,B)}return H};var A=document.defaultView;var E=/alpha\([^\)]*\)/gi;var D=function(J,H){var I=J.style;if(window.ActiveXObject){I.zoom=1;I.filter=(I.filter||"").replace(E,"")+(H==1?"":" alpha(opacity="+(H*100)+")")}else{I.opacity=H}};return{adapter:"standalone",getStyle:function(){return A&&A.getComputedStyle?function(L,K){var H,J,I;if(K=="float"){K="cssFloat"}if(H=L.style[K]){return H}if(J=A.getComputedStyle(L,"")){return J[G(K)]}return null}:function(M,L){var I,K,J;if(L=="opacity"){if(typeof M.style.filter=="string"){var H=M.style.filter.match(/alpha\(opacity=(.+)\)/i);if(H){var N=parseFloat(H[1]);if(!isNaN(N)){return(N?N/100:0)}}}return 1}else{if(L=="float"){L="styleFloat"}}var J=G(L);if(I=M.style[J]){return I}if(K=M.currentStyle){return K[J]}return null}}(),setStyle:function(K,J,L){if(typeof J=="string"){var H=G(J);if(H=="opacity"){D(K,L)}else{K.style[H]=L}}else{for(var I in J){this.setStyle(K,I,J[I])}}},get:function(H){return typeof H=="string"?document.getElementById(H):H},remove:function(H){H.parentNode.removeChild(H)},getTarget:function(I){var H=I.target?I.target:I.srcElement;return H.nodeType==3?H.parentNode:H},getPageXY:function(I){var H=I.pageX||(I.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft));var J=I.pageY||(I.clientY+(document.documentElement.scrollTop||document.body.scrollTop));return[H,J]},preventDefault:function(H){if(H.preventDefault){H.preventDefault()}else{H.returnValue=false}},keyCode:function(H){return H.which?H.which:H.keyCode},addEvent:function(J,H,I){if(J.addEventListener){J.addEventListener(H,I,false)}else{if(J.attachEvent){J.attachEvent("on"+H,I)}}},removeEvent:function(J,H,I){if(J.removeEventListener){J.removeEventListener(H,I,false)}else{if(J.detachEvent){J.detachEvent("on"+H,I)}}},append:function(J,I){if(J.insertAdjacentHTML){J.insertAdjacentHTML("BeforeEnd",I)}else{if(J.lastChild){var H=J.ownerDocument.createRange();H.setStartAfter(J.lastChild);var K=H.createContextualFragment(I);J.appendChild(K)}else{J.innerHTML=I}}}}}();// Shadowbox Classif(typeof Shadowbox == 'undefined'){ throw 'Unable to load Shadowbox, no base library adapter found'; }(function(){var version = '2.0';var options = {animate:            true, //animations besides fadesanimateFade:        true, //fade animations.animSequence:       'wh', //sequence of the height and width animations. May be 'wh' (width then height), 'hw' (height then width), or 'sync' (both at the same time). Of course this will only work if animate is true.flvPlayer:          'player.swf', //path to flvplayer.swf. (player.swf default name for vs 4.1)modal:              false,  // Listen to the overlay for clicks. If the user clicks the overlay, it will trigger Shadowbox.close()overlayColor:       '#000', //color to use for the modal overlay (in hex).overlayOpacity:     0.8, //ppacity to use for the modal overlay.flashBgColor:       '#000000',//default background color to use for Flash movies (in hex).autoplayMovies:     false, //automatically play movies. showMovieControls:  true, // movie controllers on movie players.slideshowDelay:     0, //delay (in seconds) to use for slideshows.resizeDuration:     0.55, //duration of the resizing animations (in seconds).fadeDuration:       0.35, //duration of the fading animations (in seconds).displayNav:         true, //show the navigation controls.continuous:         false, //continuous galleries. When this is true, users will be able to skip to the first gallery image from the last using next and vice versa.displayCounter:     true, //display the gallery counter.counterType:        'default', //'default' or 'skip'. simple '1 of 5' message. The skip counter displays a link for each piece in the gallery that enables a user to skip directly to any piece.counterLimit:       10, //limits the number of counter links that will be displayed in a "skip" style counter.viewportPadding:    20, //amount of padding to maintain around the viewport edge (in pixels). This only applies when the image is very large and takes up the entire viewport.handleOversize:     'resize',//how to handle content that is too large to display in its entirety (and is resizable). A value of 'resize' will resize the content while preserving aspect ratio and display it at the smaller resolution. If the content is an image, a value of 'drag' will display the image at its original resolution but it will be draggable within Shadowbox. A value of 'none' will display the content at its original resolution but it may be cropped.handleException:    null, //exception handling function that will be called whenever Shadowbox should throw an exception. Will be passed the error message as its first argument.handleUnsupported:  'link', //mode to use when handling unsupported media. May be either 'remove' or 'link'. If it is 'remove', the unsupported gallery item will merely be removed from the gallery. If it is the only item in the gallery, the link will simply be followed. If it is 'link', a link will be provided to the appropriate plugin page in place of the gallery element.initialHeight:      160, //initial height of Shadowbox (in pixels).initialWidth:       320, //initial width of Shadowbox (in pixels).enableKeys:         true, //keyboard control.onOpen:             null, //hook function to be fired when Shadowbox opens. The single argument will be the current gallery element.onFinish:           null, //hook function to be fired when Shadowbox finishes loading its content. The single argument will be the current gallery element on display.onChange:           null, //hook function to be fired when Shadowbox changes from one gallery element to the next. The single argument will be the current gallery element that is about to be displayed.onClose:            null, //hook function that will be fired when Shadowbox closes. The single argument will be the gallery element most recently displayed.skipSetup:          false, //skips calling Shadowbox.setup() in init(). This means that it must be called later manually.errors:		{//An object containing names of plugins and links to their respective download pages.	fla:        { name: 'Flash', url: 'http://www.adobe.com/products/flashplayer/'},	qt:         { name: 'QuickTime', url: 'http://www.apple.com/quicktime/download/'},	wmp:        { name: 'Windows Media Player', url: 'http://www.microsoft.com/windows/windowsmedia/'},	f4m:        { name: 'Flip4Mac', url: 'http://www.flip4mac.com/wmv_download.htm'}			},//map of players to the file extensions they support. Each member ofthis object is the name of a player (with one exception), whose value is an array of file extensions that player will "play". The one exception to this rule is the "qtwmp" member, which contains extensions that may be played using either QuickTime or Windows Media Player.// - img: Image file extensions// - swf: Flash SWF file extensions// - flv: Flash video file extensions (will be played by JW FLV player) // - qt: Movie file extensions supported by QuickTime// - wmp: Movie file extensions supported by Windows Media Player// - qtwmp: Movie file extensions supported by both QuickTime and Windows Media Player// - iframe: File extensions that will be display in an iframe// IMPORTANT: If this object is to be modified, it must be copied in its entirety and tweaked because it is not merged recursively with the default. Also, any modifications must be passed into Shadowbox.init for speed reasons.ext:     {	img:    ['png', 'jpg', 'jpeg', 'gif', 'bmp'],	swf:    ['swf'],	flv:    ['flv'],	qt:     ['dv', 'mov', 'moov', 'movie', 'mp4'],	wmp:    ['asf', 'wm', 'wmv'],	qtwmp:  ['avi', 'mpg', 'mpeg'],	iframe: ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'pl', 'php','php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml', 'shtml', 'txt', 'vbs']        }    };    // shorthand    var SB = Shadowbox;    var SL = SB.lib;    /**     * Stores the default set of options in case a custom set of options is used     * on a link-by-link basis so we can restore them later.     *     */    var default_options;    /**     * An object containing some regular expressions we'll need later. Compiled     * up front for speed.     *     */    var RE = {        domain:         /:\/\/(.*?)[:\/]/, // domain prefix        inline:         /#(.+)$/, // inline element id        rel:            /^(light|shadow)box/i, // rel attribute format        gallery:        /^(light|shadow)box\[(.*?)\]/i, // rel attribute format for gallery link        unsupported:    /^unsupported-(\w+)/, // unsupported media type        param:          /\s*([a-z_]*?)\s*=\s*(.+)\s*/, // rel string parameter        empty:          /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i // elements that don't have children    };    var cache = [];    var gallery;    var current;    var content;    var content_id = 'shadowbox_content';	 /**     * Holds the current dimensions of Shadowbox as calculated by     * setDimensions(). Contains the following properties:     *     * - height: The total height of #shadowbox     * - width: The total width of #shadowbox     * - inner_h: The height of #shadowbox_body     * - inner_w: The width of #shadowbox_body     * - top: The top to use for #shadowbox     * - resize_h: The height to use for resizable content     * - resize_w: The width to use for resizable content     * - drag: True if dragging should be enabled (oversized image)     *     */    var dims;    var initialized = false;    var activated = false;    var slide_timer;    var slide_start;    var slide_delay = 0;        var ua = navigator.userAgent.toLowerCase();    var client = {        isStrict:   document.compatMode == 'CSS1Compat',        isOpera:    ua.indexOf('opera') > -1,        isIE:       ua.indexOf('msie') > -1,        isIE7:      ua.indexOf('msie 7') > -1,        isSafari:   /webkit|khtml/.test(ua),        isWindows:  ua.indexOf('windows') != -1 || ua.indexOf('win32') != -1,        isMac:      ua.indexOf('macintosh') != -1 || ua.indexOf('mac os x') != -1,        isLinux:    ua.indexOf('linux') != -1    };    client.isBorderBox = client.isIE && !client.isStrict;    client.isSafari3 = client.isSafari && !!(document.evaluate);    client.isGecko = ua.indexOf('gecko') != -1 && !client.isSafari;    var ltIE7 = client.isIE && !client.isIE7;    var plugins;    // detect plugin support    if(navigator.plugins && navigator.plugins.length){        var detectPlugin = function(plugin_name){            var detected = false;            for (var i = 0, len = navigator.plugins.length; i < len; ++i){                if(navigator.plugins[i].name.indexOf(plugin_name) > -1){                    detected = true;                    break;                }            }            return detected;        };        var f4m = detectPlugin('Flip4Mac');        plugins = {            fla:    detectPlugin('Shockwave Flash'),            qt:     detectPlugin('QuickTime'),            wmp:    !f4m && detectPlugin('Windows Media'), // if it's Flip4Mac, it's not really WMP            f4m:    f4m        };    }else{        var detectPlugin = function(plugin_name){            var detected = false;            try{                var axo = new ActiveXObject(plugin_name);                if(axo) detected = true;            }catch(e){}            return detected;        };        plugins = {            fla:    detectPlugin('ShockwaveFlash.ShockwaveFlash'),            qt:     detectPlugin('QuickTime.QuickTime'),            wmp:    detectPlugin('wmplayer.ocx'),            f4m:    false        };    }    var apply = function(o, e){        for(var p in e) o[p] = e[p];        return o;    };    // Determines if the given object is an anchor/area element.    var isLink = function(el){        return el && typeof el.tagName == 'string' && (el.tagName.toUpperCase() == 'A' || el.tagName.toUpperCase() == 'AREA');    };    // Gets the height of the viewport in pixels. Note: This function includes scrollbars in Safari 3.    SL.getViewportHeight = function(){        var h = window.innerHeight; // Safari        var mode = document.compatMode;        if((mode || client.isIE) && !client.isOpera){            h = client.isStrict ? document.documentElement.clientHeight : document.body.clientHeight;        }        return h;    };    // Gets the width of the viewport in pixels. Note: This function includes scrollbars in Safari 3.    SL.getViewportWidth = function(){        var w = window.innerWidth; // Safari        var mode = document.compatMode;        if(mode || client.isIE){            w = client.isStrict ? document.documentElement.clientWidth : document.body.clientWidth;        }        return w;    };    // Creates an HTML string from an object representing HTML elements. Based on Ext.DomHelper's createHtml.    SL.createHTML = function(obj){        var html = '<' + obj.tag;        for(var attr in obj){            if(attr == 'tag' || attr == 'html' || attr == 'children') continue;            if(attr == 'cls'){                html += ' class="' + obj['cls'] + '"';            }else{                html += ' ' + attr + '="' + obj[attr] + '"';            }        }        if(RE.empty.test(obj.tag)){            html += '/>';        }else{            html += '>';            var cn = obj.children;            if(cn){                for(var i = 0, len = cn.length; i < len; ++i){                    html += this.createHTML(cn[i]);                }            }            if(obj.html) html += obj.html;            html += '</' + obj.tag + '>';        }        return html;    };    // Easing function used for animations. Based on a cubic polynomial.    var ease = function(x){        return 1 + Math.pow(x - 1, 3);    };    // Animates any numeric (not color) style of the given element from its current state to the given value. Defaults to using pixel-based measurements. (seconds) animation completes    var animate = function(el, p, to, d, cb){        var from = parseFloat(SL.getStyle(el, p));        if(isNaN(from)) from = 0;        if(from == to){            if(typeof cb == 'function') cb();            return; // nothing to animate        }        var delta = to - from;        var op = p == 'opacity';        var unit = op ? '' : 'px'; // default unit is px        var fn = function(ease){            SL.setStyle(el, p, from + ease * delta + unit);        };        // cancel the animation here if set in the options        if(!options.animate && !op || op && !options.animateFade){            fn(1);            if(typeof cb == 'function') cb();            return;        }        d *= 1000; // convert to milliseconds        var begin = new Date().getTime();        var end = begin + d;        var timer = setInterval(function(){            var time = new Date().getTime();            if(time >= end){ // end of animation                clearInterval(timer);                fn(1);                if(typeof cb == 'function') cb();            }else{                fn(ease((time - begin) / d));            }        }, 10); // 10 ms interval is minimum on WebKit    };    // A utility function used by the fade functions to clear the opacity style setting of the given element. Required in some cases for IE.    var clearOpacity = function(el){        var s = el.style;        if(client.isIE){            if(typeof s.filter == 'string' && (/alpha/i).test(s.filter)){                // careful not to overwrite other filters!                s.filter = s.filter.replace(/[\w\.]*alpha\(.*?\);?/i, '');            }        }else{            s.opacity = '';            s['-moz-opacity'] = '';            s['-khtml-opacity'] = '';        }    };    // Gets the computed height of the given element, including padding and borders.    var getComputedHeight = function(el){        var h = Math.max(el.offsetHeight, el.clientHeight);        if(!h){            h = parseInt(SL.getStyle(el, 'height'), 10) || 0;            if(!client.isBorderBox){                h += parseInt(SL.getStyle(el, 'padding-top'), 10)                    + parseInt(SL.getStyle(el, 'padding-bottom'), 10)                    + parseInt(SL.getStyle(el, 'border-top-width'), 10)                    + parseInt(SL.getStyle(el, 'border-bottom-width'), 10);            }        }        return h;    };    // Determines the player needed to display the file at the given URL. If the file type is not supported, the return value will be 'unsupported'.    // If the file type is not supported but the correct player can be determined, the return value will be 'unsupported-*' where * will be the player abbreviation (e.g. 'qt' = QuickTime).    var getPlayer = function(url){        var m = url.match(RE.domain);        var d = m && document.domain == m[1]; // same domain        if(url.indexOf('#') > -1 && d) return 'inline';        var q = url.indexOf('?');        if(q > -1) url = url.substring(0, q); // strip query string for player detection purposes        if(RE.img.test(url)) return 'img';        if(RE.swf.test(url)) return plugins.fla ? 'swf' : 'unsupported-swf';        if(RE.flv.test(url)) return plugins.fla ? 'flv' : 'unsupported-flv';        if(RE.qt.test(url)) return plugins.qt ? 'qt' : 'unsupported-qt';        if(RE.wmp.test(url)){            if(plugins.wmp) return 'wmp';            if(plugins.f4m) return 'qt';            if(client.isMac) return plugins.qt ? 'unsupported-f4m' : 'unsupported-qtf4m';            return 'unsupported-wmp';        }else if(RE.qtwmp.test(url)){            if(plugins.qt) return 'qt';            if(plugins.wmp) return 'wmp';            return client.isMac ? 'unsupported-qt' : 'unsupported-qtwmp';        }else if(!d || RE.iframe.test(url)){            return 'iframe';        }        return 'unsupported'; // same domain, not supported    };    // Handles all clicks on links that have been set up to work with Shadowbox and cancels the default event behavior when appropriate.    var handleClick = function(ev){        // get anchor/area element        var link;        if(isLink(this)){            link = this; // jQuery, Prototype, YUI        }else{            link = SL.getTarget(ev); // Ext, standalone            while(!isLink(link) && link.parentNode){                link = link.parentNode;            }        }        //SL.preventDefault(ev); // good for debugging        if(link){            SB.open(link);            if(gallery.length) SL.preventDefault(ev); // stop event        }    };    // Toggles the display of the nav control with the given id on and off.    var toggleNav = function(id, on){        var el = SL.get('shadowbox_nav_' + id);        if(el) el.style.display = on ? '' : 'none';    };    // Builds the content for the title and information bars. bars are built    var buildBars = function(cb){        var obj = gallery[current];        var title_i = SL.get('shadowbox_title_inner');        // build the title        //changed obj.title to obj.descr to build description with html tags from obj.name (avoiding the hover tooltip mess from title tags)        title_i.innerHTML = obj.name || '';        // build the nav        var nav = SL.get('shadowbox_nav');        if(nav){            var c, n, pl, pa, p;            // need to build the nav?            if(options.displayNav){                c = true;                // next & previous links                var len = gallery.length;                if(len > 1){                    if(options.continuous){                        n = p = true; // show both                    }else{                        n = (len - 1) > current; // not last in gallery, show next                        p = current > 0; // not first in gallery, show previous                    }                }                // in a slideshow?                if(options.slideshowDelay > 0 && hasNext()){                    pa = slide_timer != 'paused';                    pl = !pa;                }            }else{                c = n = pl = pa = p = false;            }            toggleNav('close', c);            toggleNav('next', n);            toggleNav('play', pl);            toggleNav('pause', pa);            toggleNav('previous', p);        }        // build the counter        var counter = SL.get('shadowbox_counter');        if(counter){            var co = '';            // need to build the counter?            if(options.displayCounter && gallery.length > 1){                if(options.counterType == 'skip'){                    // limit the counter?                    var i = 0, len = gallery.length, end = len;                    var limit = parseInt(options.counterLimit);                    if(limit < len){ // support large galleries                        var h = Math.round(limit / 2);                        i = current - h;                        if(i < 0) i += len;                        end = current + (limit - h);                        if(end > len) end -= len;                    }                    while(i != end){                        if(i == len) i = 0;                        co += '<a onclick="Shadowbox.change(' + i + ');"';                        if(i == current) co += ' class="shadowbox_counter_current"';                        co += '>' + (++i) + '</a>';                    }                }else{ // default                    co = (current + 1) + ' ' + SB.LANG.of + ' ' + len;                }            }            counter.innerHTML = co;        }        cb();    };    // Hides the title and info bars. animation completes    var hideBars = function(anim, cb){        var obj = gallery[current];        var title = SL.get('shadowbox_title');        var info = SL.get('shadowbox_info');        var title_i = SL.get('shadowbox_title_inner');        var info_i = SL.get('shadowbox_info_inner');        // build bars after they are hidden        var fn = function(){            buildBars(cb);        };        var title_h = getComputedHeight(title);        var info_h = getComputedHeight(info) * -1;        if(anim){            // animate the transition            animate(title_i, 'margin-top', title_h, 0.35);            animate(info_i, 'margin-top', info_h, 0.35, fn);        }else{            SL.setStyle(title_i, 'margin-top', title_h + 'px');            SL.setStyle(info_i, 'margin-top', info_h + 'px');            fn();        }    };    // Shows the title and info bars. animation completes    var showBars = function(cb){        var title_i = SL.get('shadowbox_title_inner');        var info_i = SL.get('shadowbox_info_inner');        var t = title_i.innerHTML != ''; // is there a title to display?        if(t) animate(title_i, 'margin-top', 0, 0.35);        animate(info_i, 'margin-top', 0, 0.35, cb);    };    //  Loads the Shadowbox with the current piece.    var loadContent = function(){        var obj = gallery[current];        if(!obj) return; // invalid        var changing = false;        if(content){            content.remove(); // remove old content first            changing = true; // changing from some previous content        }        // determine player, inline is really just HTML        var p = obj.player == 'inline' ? 'html' : obj.player;        // make sure player is loaded        if(typeof SB[p] != 'function'){            SB.raise('Unknown player ' + obj.player);        }        content = new SB[p](content_id, obj); // instantiate new content object        listenKeys(false); // disable the keyboard temporarily        toggleLoading(true);        hideBars(changing, function(){ // if changing, animate the bars transition            if(!content) return;            // if opening, clear #shadowbox display            if(!changing){                 SL.get('shadowbox').style.display = '';            }            var fn = function(){                resizeContent(function(){                    if(!content) return;                    showBars(function(){                        if(!content) return;                        // append content just before hiding the loading layer                        SL.get('shadowbox_body_inner').innerHTML = SL.createHTML(content.markup(dims));                        toggleLoading(false, function(){                            if(!content) return;                            if(typeof content.onLoad == 'function'){                                content.onLoad(); // call onLoad callback if present                            }                            if(options.onFinish && typeof options.onFinish == 'function'){                                options.onFinish(gallery[current]); // fire onFinish handler                            }                            if(slide_timer != 'paused'){                                SB.play(); // kick off next slide                            }                            listenKeys(true); // re-enable the keyboard                        });                    });                });            };            if(typeof content.ready != 'undefined'){ // does the object have a ready property?                var id = setInterval(function(){ // if so, wait for the object to be ready                    if(content){                        if(content.ready){                            clearInterval(id); // clean up                            id = null;                            fn();                        }                    }else{ // content has been removed                        clearInterval(id);                        id = null;                    }                }, 100);            }else{                fn();            }        });        // preload neighboring gallery images        if(gallery.length > 1){            var next = gallery[current + 1] || gallery[0];            if(next.player == 'img'){                var a = new Image();                a.src = next.content;            }            var prev = gallery[current - 1] || gallery[gallery.length - 1];            if(prev.player == 'img'){                var b = new Image();                b.src = prev.content;            }        }    };    /**     * Calculates the dimensions for Shadowbox, taking into account the borders     * and surrounding elements of the shadowbox_body. If the height/width     * combination is too large for Shadowbox and handleOversize option is set     * to 'resize', the resized dimensions will be returned (preserving the     * original aspect ratio). Otherwise, the originally calculated dimensions     * will be used. Stores all dimensions in the private dims variable.     *     *                                  resized. Defaults to false.     */    var setDimensions = function(height, width, resizable){        resizable = resizable || false;        var sb = SL.get('shadowbox_body');        var h = height = parseInt(height);        var w = width = parseInt(width);        var view_h = SL.getViewportHeight();        var view_w = SL.getViewportWidth();        // calculate the max width        var border_w = parseInt(SL.getStyle(sb, 'border-left-width'), 10)            + parseInt(SL.getStyle(sb, 'border-right-width'), 10);        var extra_w = border_w + 2 * options.viewportPadding;        if(w + extra_w >= view_w){            w = view_w - extra_w;        }        // calculate the max height        var border_h = parseInt(SL.getStyle(sb, 'border-top-width'), 10)            + parseInt(SL.getStyle(sb, 'border-bottom-width'), 10);        var bar_h = getComputedHeight(SL.get('shadowbox_title'))            + getComputedHeight(SL.get('shadowbox_info'));        var extra_h = border_h + 2 * options.viewportPadding + bar_h;        if(h + extra_h >= view_h){            h = view_h - extra_h;        }        // handle oversized content        var drag = false;        var resize_h = height;        var resize_w = width;        var handle = options.handleOversize;        if(resizable && (handle == 'resize' || handle == 'drag')){            var change_h = (height - h) / height;            var change_w = (width - w) / width;            if(handle == 'resize'){                if(change_h > change_w){                    w = Math.round((width / height) * h);                }else if(change_w > change_h){                    h = Math.round((height / width) * w);                }                // adjust resized height or width accordingly                resize_w = w;                resize_h = h;            }else{                // drag on oversized images only                var link = gallery[current];                if(link) drag = link.player == 'img' && (change_h > 0 || change_w > 0);            }        }        // update dims        dims = {            height:     h + border_h + bar_h,            width:      w + border_w,            inner_h:    h,            inner_w:    w,            top:        (view_h - (h + extra_h)) / 2 + options.viewportPadding,            resize_h:   resize_h,            resize_w:   resize_w,            drag:       drag        };    };    /**     * Resizes Shadowbox to the given height and width. If the callback     * parameter is given, the transition will be animated and the callback     * function will be called when the animation completes. Note: The private     * content variable must be updated before calling this function.     *     *                              content has been resized     */    var resizeContent = function(cb){        if(!content) return; // no content        // set new dimensions        setDimensions(content.height, content.width, content.resizable);        if(cb){            switch(options.animSequence){                case 'hw':                    adjustHeight(dims.inner_h, dims.top, true, function(){                        adjustWidth(dims.width, true, cb);                    });                    break;                case 'wh':                    adjustWidth(dims.width, true, function(){                        adjustHeight(dims.inner_h, dims.top, true, cb);                    });                    break;                case 'sync':                default:                    adjustWidth(dims.width, true);                    adjustHeight(dims.inner_h, dims.top, true, cb);            }        }else{ // window resize            adjustWidth(dims.width, false);            adjustHeight(dims.inner_h, dims.top, false);            var c = SL.get(content_id);            if(c){                // resize resizable content when in resize mode                if(content.resizable && options.handleOversize == 'resize'){                    c.height = dims.resize_h;                    c.width = dims.resize_w;                }                // fix draggable positioning if enlarging viewport                if(gallery[current].player == 'img' && options.handleOversize == 'drag'){                    var top = parseInt(SL.getStyle(c, 'top'));                    if(top + content.height < dims.inner_h){                        SL.setStyle(c, 'top', dims.inner_h - content.height + 'px');                    }                    var left = parseInt(SL.getStyle(c, 'left'));                    if(left + content.width < dims.inner_w){                        SL.setStyle(c, 'left', dims.inner_w - content.width + 'px');                    }                }            }        }    };    // Adjusts the height of #shadowbox_body and centers #shadowbox vertically in the viewport. completes    var adjustHeight = function(height, top, anim, cb){        height = parseInt(height);        // adjust the height        var sb = SL.get('shadowbox_body');        if(anim){            animate(sb, 'height', height, options.resizeDuration);        }else{            SL.setStyle(sb, 'height', height + 'px');        }        // adjust the top        var s = SL.get('shadowbox');        if(anim){            animate(s, 'top', top, options.resizeDuration, cb);        }else{            SL.setStyle(s, 'top', top + 'px');            if(typeof cb == 'function') cb();        }    };    // Adjusts the width of #shadowbox. completes    var adjustWidth = function(width, anim, cb){        width = parseInt(width);        // adjust the width        var s = SL.get('shadowbox');        if(anim){            animate(s, 'width', width, options.resizeDuration, cb);        }else{            SL.setStyle(s, 'width', width + 'px');            if(typeof cb == 'function') cb();        }    };    // Sets up a listener on the document for keystrokes. it off    var listenKeys = function(on){        if(!options.enableKeys) return;        SL[(on ? 'add' : 'remove') + 'Event'](document, 'keydown', handleKey);    };    // A listener function that is fired when a key is pressed.    var handleKey = function(e){        var code = SL.keyCode(e);        // attempt to prevent default key action        SL.preventDefault(e);        if(code == 81 || code == 88 || code == 27){ // q, x, or esc            SB.close();        }else if(code == 37){ // left arrow            SB.previous();        }else if(code == 39){ // right arrow            SB.next();        }else if(code == 32){ // space bar            SB[(typeof slide_timer == 'number' ? 'pause' : 'play')]();        }    };    // Toggles the visibility of the "loading" layer. completes    var toggleLoading = function(on, cb){        var loading = SL.get('shadowbox_loading');        if(on){            loading.style.display = '';            if(typeof cb == 'function') cb();        }else{            var p = gallery[current].player;            var anim = (p == 'img' || p == 'html'); // fade on images & html            var fn = function(){                loading.style.display = 'none';                clearOpacity(loading);                if(typeof cb == 'function') cb();            };            if(anim){                animate(loading, 'opacity', 0, options.fadeDuration, fn);            }else{                fn();            }        }    };    // Sets the top of the container element. This is only necessary in IE6 where the container uses absolute positioning instead of fixed.    var fixTop = function(){        SL.get('shadowbox_container').style.top = document.documentElement.scrollTop + 'px';    };    // Sets the height of the overlay element to the full viewport height. This is only necessary in IE6 where the container uses absolute positioning instead of fixed, thus restricting the size of the overlay element.    var fixHeight = function(){        SL.get('shadowbox_overlay').style.height = SL.getViewportHeight() + 'px';    };    /**     * Determines if there is a next piece to display in the current gallery.     *     */    var hasNext = function(){        return gallery.length > 1 && (current != gallery.length - 1 || options.continuous);    };    /**     * Toggles the visibility of #shadowbox_container and sets its size (if on     * IE6). Also toggles the visibility of elements (<select>, <object>, and     * <embed>) that are troublesome for semi-transparent modal overlays. IE has     * problems with <select> elements, while Firefox has trouble with     * <object>s.     *     *                              when toggling off     */    var toggleVisible = function(cb){        var els, v = (cb) ? 'hidden' : 'visible';        var hide = ['select', 'object', 'embed']; // tags to hide        for(var i = 0; i < hide.length; ++i){            els = document.getElementsByTagName(hide[i]);            for(var j = 0, len = els.length; j < len; ++j){                els[j].style.visibility = v;            }        }        // resize & show container        var so = SL.get('shadowbox_overlay');        var sc = SL.get('shadowbox_container');        var sb = SL.get('shadowbox');        if(cb){            // set overlay color/opacity            SL.setStyle(so, {                backgroundColor: options.overlayColor,                opacity: 0            });            if(!options.modal) SL.addEvent(so, 'click', SB.close);            if(ltIE7){                // fix container top & overlay height before showing                fixTop();                fixHeight();                SL.addEvent(window, 'scroll', fixTop);            }            // fade in animation            sb.style.display = 'none'; // will be cleared in loadContent()            sc.style.visibility = 'visible';            animate(so, 'opacity', parseFloat(options.overlayOpacity), options.fadeDuration, cb);        }else{            SL.removeEvent(so, 'click', SB.close);            if(ltIE7) SL.removeEvent(window, 'scroll', fixTop);            // fade out effect            sb.style.display = 'none';            animate(so, 'opacity', 0, options.fadeDuration, function(){                sc.style.visibility = 'hidden';                sb.style.display = '';                clearOpacity(so);            });        }    };    // Initializes the Shadowbox environment. Loads the skin (if necessary), compiles the player matching regular expressions, and sets up the window resize listener.    Shadowbox.init = function(opts){        // don't initialize twice        if(initialized) return;        // make sure language is loaded        if(typeof SB.LANG == 'undefined'){            SB.raise('No Shadowbox language loaded');            return;        }        // make sure skin is loaded        if(typeof SB.SKIN == 'undefined'){            SB.raise('No Shadowbox skin loaded');            return;        }        // apply custom options        apply(options, opts || {});        // add markup        var markup = SB.SKIN.markup.replace(/\{(\w+)\}/g, function(m, p){            return SB.LANG[p];        });        var bd = document.body || document.documentElement;        SL.append(bd, markup);        // several fixes for IE6        if(ltIE7){            // give the container absolute positioning            SL.setStyle(SL.get('shadowbox_container'), 'position', 'absolute');            // give shadowbox_body "layout"...whatever that is            SL.get('shadowbox_body').style.zoom = 1;            // use AlphaImageLoader for transparent PNG support            var png = SB.SKIN.png_fix;            if(png && png.constructor == Array){                for(var i = 0; i < png.length; ++i){                    var el = SL.get(png[i]);                    if(el){                        var match = SL.getStyle(el, 'background-image').match(/url\("(.*\.png)"\)/);                        if(match){                            SL.setStyle(el, {                                backgroundImage: 'none',                                filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,src=' + match[1] + ',sizingMethod=scale);'                            });                        }                    }                }            }        }        // compile file type regular expressions here for speed        for(var e in options.ext){            RE[e] = new RegExp('\.(' + options.ext[e].join('|') + ')\s*$', 'i');        }        // set up window resize event handler        var id;        SL.addEvent(window, 'resize', function(){            // use 50 ms event buffering to prevent jerky window resizing            if(id){                clearTimeout(id);                id = null;            }            id = setTimeout(function(){                if(ltIE7) fixHeight();                resizeContent();            }, 50);        });        if(!options.skipSetup) SB.setup();        initialized = true;    };    /**     * Dynamically loads the specified skin for use with Shadowbox. If the skin     * is included already in the page via the appropriate <script> and <link>     * tags, this function does not need to be called. Otherwise, this function     * must be called before window.onload.     *     *                                  files are located     */    Shadowbox.loadSkin = function(skin, dir){        if(!(/\/$/.test(dir))) dir += '/';        skin = dir + skin + '/';        // Safari 2.0 fails using DOM, use document.write instead        document.write('<link rel="stylesheet" type="text/css" href="' + skin + 'skin.css">');        document.write('<scr' + 'ipt type="text/javascript" src="' + skin + 'skin.js"><\/script>');    };    /**     * Dynamically loads the specified language file to be used with Shadowbox.     * If the language file is included already in the page via the appropriate     * <script> tag, this function does not need to be called. Otherwise, this     * function must be called before window.onload.     *     *                                  language file(s) is located     */    Shadowbox.loadLanguage = function(lang, dir){        if(!(/\/$/.test(dir))) dir += '/';        // Safari 2.0 fails using DOM, use document.write instead        document.write('<scr' + 'ipt type="text/javascript" src="' + dir + 'shadowbox-' + lang + '.js"><\/script>');    };    /**     * Dynamically loads the specified player(s) to be used with Shadowbox. If     * the needed player(s) is already included in the page via the appropriate     * <script> tag(s), this function does not need to be called. Otherwise,     * this function must be called before window.onload.     *     *                                  file(s) is located     */    Shadowbox.loadPlayer = function(players, dir){        if(typeof players == 'string') players = [players];        if(!(/\/$/.test(dir))) dir += '/';        for(var i = 0, len = players.length; i < len; ++i){            // Safari 2.0 fails using DOM, use document.write instead            document.write('<scr' + 'ipt type="text/javascript" src="' + dir + 'shadowbox-' + players[i] + '.js"><\/script>');        }    };    /**     * Sets up listeners on the given links that will trigger Shadowbox. If no     * links are given, this method will set up every anchor element on the page     * with the appropriate rel attribute. Note: Because AREA elements do not     * support the rel attribute, they must be explicitly passed to this method.     *     *                                  and/or area elements to set up     */    Shadowbox.setup = function(links, opts){        // get links if none specified        if(!links){            var links = [];            var a = document.getElementsByTagName('a'), rel;            for(var i = 0, len = a.length; i < len; ++i){                rel = a[i].getAttribute('rel');                if(rel && RE.rel.test(rel)) links[links.length] = a[i];            }        }else if(!links.length){            links = [links]; // one link        }        var link;        for(var i = 0, len = links.length; i < len; ++i){            link = links[i];            if(typeof link.shadowboxCacheKey == 'undefined'){                // assign cache key expando                // use integer primitive to avoid memory leak in IE                link.shadowboxCacheKey = cache.length;                SL.addEvent(link, 'click', handleClick); // add listener            }            cache[link.shadowboxCacheKey] = this.buildCacheObj(link, opts);        }    };    /**     * Builds an object from the original link element data to store in cache.     * These objects contain (most of) the following keys:     *     * - el: the link element     * - title: the linked file title     * - player: the player to use for the linked file     * - content: the linked file's URL     * - gallery: the gallery the file belongs to (optional)     * - height: the height of the linked file (only necessary for movies)     * - width: the width of the linked file (only necessary for movies)     * - options: custom options to use (optional)     *     */    Shadowbox.buildCacheObj = function(link, opts){        var href = link.href; // don't use getAttribute() here        var o = {            el:         link,            title:      link.getAttribute('title'),            name:      link.getAttribute('name'),//get name attribute with full html description            player:     getPlayer(href),            options:    apply({}, opts || {}), // break the reference            content:    href        };        // remove link-level options from top-level options        var opt, l_opts = ['player', 'title', 'height', 'width', 'gallery'];        for(var i = 0, len = l_opts.length; i < len; ++i){            opt = l_opts[i];            if(typeof o.options[opt] != 'undefined'){                o[opt] = o.options[opt];                delete o.options[opt];            }        }        // HTML options always trump JavaScript options, so do these last        var rel = link.getAttribute('rel');        if(rel){            // extract gallery name from shadowbox[name] format            var match = rel.match(RE.gallery);            if(match) o.gallery = escape(match[2]);            // other parameters            var params = rel.split(';');            for(var i = 0, len = params.length; i < len; ++i){                match = params[i].match(RE.param);                if(match){                    if(match[1] == 'options'){                        eval('apply(o.options, ' + match[2] + ')');                    }else{                        o[match[1]] = match[2];                    }                }            }        }        return o;    };    /**     * Applies the given set of options to those currently in use. Note: Options     * will be reset on Shadowbox.open() so this function is only useful after     * it has already been called (while Shadowbox is open).     *     */    Shadowbox.applyOptions = function(opts){        if(opts){            // use apply here to break references            default_options = apply({}, options); // store default options            options = apply(options, opts); // apply options        }    };    /**     * Reverts Shadowbox' options to the last default set in use before     * Shadowbox.applyOptions() was called.     *     */    Shadowbox.revertOptions = function(){        if(default_options){            options = default_options; // revert to default options            default_options = null; // erase for next time        }    };    /**     * Opens the given object in Shadowbox. This object may be either an     * anchor/area element, or an object similar to the one created by     * Shadowbox.buildCacheObj().     *     *                                  what to display     */    Shadowbox.open = function(obj, opts){        // revert options        this.revertOptions();        // is it a link?        if(isLink(obj)){            if(typeof obj.shadowboxCacheKey == 'undefined' || typeof cache[obj.shadowboxCacheKey] == 'undefined'){                // link element that hasn't been set up before                // create on-the-fly object                obj = this.buildCacheObj(obj, opts);            }else{                // link element that has been set up before, get from cache                obj = cache[obj.shadowboxCacheKey];            }        }        // is it already a gallery?        if(obj.constructor == Array){            gallery = obj;            current = 0;        }else{            // create a copy so it doesn't get modified later            var copy = apply({}, obj);            // is it part of a gallery?            if(!obj.gallery){ // single item, no gallery                gallery = [copy];                current = 0;            }else{                current = null; // reset current                gallery = []; // clear the current gallery                var ci;                for(var i = 0, len = cache.length; i < len; ++i){                    ci = cache[i];                    if(ci.gallery){                        if(ci.content == obj.content                            && ci.gallery == obj.gallery                            && ci.title == obj.title){ // compare content, gallery, & title                                current = gallery.length; // key element found                        }                        if(ci.gallery == obj.gallery){                            gallery.push(apply({}, ci));                        }                    }                }                // if not found in cache, prepend to front of gallery                if(current == null){                    gallery.unshift(copy);                    current = 0;                }            }        }        obj = gallery[current];        // apply custom options        if(obj.options || opts){            // use apply here to break references            this.applyOptions(apply(apply({}, obj.options || {}), opts || {}));        }        // filter gallery for unsupported elements        var match, r;        for(var i = 0, len = gallery.length; i < len; ++i){            r = false; // remove the element?            if(gallery[i].player == 'unsupported'){ // don't support this at all                r = true;            }else if(match = RE.unsupported.exec(gallery[i].player)){ // handle unsupported elements                if(options.handleUnsupported == 'link'){                    gallery[i].player = 'html';                    // generate a link to the appropriate plugin download page(s)                    var s, a, oe = options.errors;                    switch(match[1]){                        case 'qtwmp':                            s = 'either';                            a = [oe.qt.url, oe.qt.name, oe.wmp.url, oe.wmp.name];                        break;                        case 'qtf4m':                            s = 'shared';                            a = [oe.qt.url, oe.qt.name, oe.f4m.url, oe.f4m.name];                        break;                        default:                            s = 'single';                            if(match[1] == 'swf' || match[1] == 'flv') match[1] = 'fla';                            a = [oe[match[1]].url, oe[match[1]].name];                    }                    var msg = SB.LANG.errors[s].replace(/\{(\d+)\}/g, function(m, i){                        return a[i];                    });                    gallery[i].content = '<div class="shadowbox_message">' + msg + '</div>';                }else{                    r = true;                }            }else if(gallery[i].player == 'inline'){ // handle inline elements                // retrieve the innerHTML of the inline element                var match = RE.inline.exec(gallery[i].content);                if(match){                    var el;                    if(el = SL.get(match[1])){                        gallery[i].content = el.innerHTML;                    }else{                        SB.raise('Cannot find element with id ' + match[1]);                    }                }else{                    SB.raise('Cannot find element id for inline content');                }            }            if(r){                gallery.splice(i, 1); // remove the element from the gallery                if(i < current){                    --current;                }else if(i == current){                    // if current is unsupported, look for supported neighbor                    current = i > 0 ? current - 1 : i;                }                --i; // decrement to account for splice                len = gallery.length; // gallery.length has changed!            }        }        // anything left?        if(gallery.length){            // fire onOpen hook            if(options.onOpen && typeof options.onOpen == 'function'){                options.onOpen(obj);            }            if(!activated){                // set initial dimensions & load                setDimensions(options.initialHeight, options.initialWidth);                adjustHeight(dims.inner_h, dims.top, false);                adjustWidth(dims.width, false);                toggleVisible(loadContent);            } else {                loadContent();            }            activated = true;        }    };    // Jumps to the piece in the current gallery with index num.    Shadowbox.change = function(num){        if(!gallery) return; // no current gallery        if(!gallery[num]){ // index does not exist            if(!options.continuous){                return;            }else{                num = num < 0 ? (gallery.length - 1) : 0; // loop            }        }        if(typeof slide_timer == 'number'){            clearTimeout(slide_timer);            slide_timer = null;            slide_delay = slide_start = 0; // reset slideshow variables        }        current = num; // update current        if(options.onChange && typeof options.onChange == 'function'){            options.onChange(gallery[current]); // fire onChange handler        }        loadContent();    };    // Jumps to the next piece in the gallery.    Shadowbox.next = function(){        this.change(current + 1);    };    // Jumps to the previous piece in the gallery.    Shadowbox.previous = function(){        this.change(current - 1);    };    // Sets the timer for the next image in the slideshow to be displayed.    Shadowbox.play = function(){        if(!hasNext()) return;        if(!slide_delay) slide_delay = options.slideshowDelay * 1000;        if(slide_delay){            slide_start = new Date().getTime();            slide_timer = setTimeout(function(){                slide_delay = slide_start = 0; // reset slideshow                SB.next();            }, slide_delay);            // change play nav to pause            toggleNav('play', false);            toggleNav('pause', true);        }    };    // Pauses the current slideshow.    Shadowbox.pause = function(){        if(typeof slide_timer == 'number'){            var time = new Date().getTime();            slide_delay = Math.max(0, slide_delay - (time - slide_start));            // any delay left on current slide? if so, stop the timer            if(slide_delay){                clearTimeout(slide_timer);                slide_timer = 'paused';            }            // change pause nav to play            toggleNav('pause', false);            toggleNav('play', true);        }    };    // Deactivates Shadowbox.    Shadowbox.close = function(){        if(!activated) return; // already closed        // stop listening for keys        listenKeys(false);        // hide        toggleVisible(false);        // remove the content        if(content){            content.remove();            content = null;        }        // clear slideshow variables        if(typeof slide_timer == 'number') clearTimeout(slide_timer);        slide_timer = null;        slide_delay = 0;        // fire onClose handler        if(options.onClose && typeof options.onClose == 'function'){            options.onClose(gallery[current]);        }        activated = false;    };    /**     * Clears Shadowbox' cache and removes listeners and expandos from all     * cached link elements. May be used to completely reset Shadowbox in case     * links on a page change.     */    Shadowbox.clearCache = function(){        for(var i = 0, len = cache.length; i < len; ++i){            if(cache[i].el){                SL.removeEvent(cache[i].el, 'click', handleClick);                delete cache[i].el.shadowboxCacheKey; // remove expando            }        }        cache = [];    };    /**     * Gets an object that lists which plugins are supported by the client. The keys of this object will be:     * - fla: Adobe Flash Player     * - qt: QuickTime Player     * - wmp: Windows Media Player     * - f4m: Flip4Mac QuickTime Player     */    Shadowbox.getPlugins = function(){        return plugins;    };    /**     * Gets the current options object in use.     *     */    Shadowbox.getOptions = function(){        return options;    };    //Gets the current gallery object.    Shadowbox.getCurrent = function(){        return gallery[current];    };    // Gets the current version number of Shadowbox.    Shadowbox.getVersion = function(){        return version;    };    //Returns an object containing information about the current client configuration.    Shadowbox.getClient = function(){        return client;    };    // Returns the current content object in use.    Shadowbox.getContent = function(){        return content;    };    // Gets the current dimensions of Shadowbox as calculated by setDimensions().    Shadowbox.getDimensions = function(){        return dims;    };    //Handles all Shadowbox exceptions (errors). Calls the exception handler callback if one is present (see handleException option) or throws a new exception.    Shadowbox.raise = function(e){        if(typeof options.handleException == 'function'){            options.handleException(e);        }else{            throw e;        }    };})();
