﻿/*
Soapbox v1.7 - Extension to the popular and all out wonderful Slimbox
Inspired by MediaBox Advance
    
Slimbox v1.64 - The ultimate lightweight soapbox clone
(c) 2007-2008 Christophe Beyls <http://www.digitalia.be>
MIT-style license.
	
mediaboxAdvanced v0.9.4 - The ultimate extension of Mediabox into an all-media script
(c) 2007-2007 John Einselen <http://iaian7.com>
	
Revisions
	
1.6
* Update to Mootools-More-1.2.2.1 for use of IframeShim
1.7
* Update to Mootools-More-1.2.2.2 and Mootools-Core-1.2.2
* Add Chaining to setting of content and animation of canvas
* Update animation method
	
Upcoming Revisions
	
1.8
* Move per media item options to querystring from rel attribute
* Update setContent to be more streamlined
* Fix some performance issues with large SWF's
*/

var Soapbox = (function() {

    // Global variables, accessible to Soapbox only
    // State values: 0 (closed or closing), 1 (open and ready), 2+ (open and busy with animation)
    var options, items, activeItem = -1, activeUrl, prevItem, nextItem, compatibleOverlay, middle, canvasWidth, canvasHeight, mediaChain,

    // DOM elements
	overlay, canvas, media, footer, bottom, navigation, prevLink, nextLink, closeLink, info, title, number, caption, shim,

    // Effects
    fxOverlay, fxResize, fxMedia, fxBottom;

    // Initialization

    window.addEvent("domready", function() {
        // Append the Soapbox HTML code at the bottom of the document
        $(document.body).adopt(
			$$(
				overlay = new Element("div", { id: "sbOverlay", events: { click: close} }),
				canvas = new Element("div", { id: "sbCanvas" }),
				footer = new Element("div", { id: "sbFooter" })
			).setStyle("display", "none")
		);

        media = new Element("div", { id: "sbMedia" }).injectInside(canvas);

        bottom = new Element("div", { id: "sbBottom" }).injectInside(footer).adopt(
		    navigation = new Element("div", { id: "sbNav" }),
		    info = new Element("div", { id: "sbInfo" })
		);

        navigation.adopt(
		    prevLink = new Element("a", { id: "sbPrevLink", href: "#", events: { click: previous} }),
			nextLink = new Element("a", { id: "sbNextLink", href: "#", events: { click: next} }),
			closeLink = new Element("a", { id: "sbCloseLink", href: "#", events: { click: close} }),
			new Element("div", { styles: { clear: "both"} })
		);

        info.adopt(
            title = new Element("div", { id: "sbTitle" }),
            number = new Element("div", { id: "sbNumber" }),
            new Element("div", { styles: { clear: "both"} }),
		    caption = new Element("div", { id: "sbCaption" })
		);
    });

    // Internal functions

    function position() {
        var scroll = window.getScroll(), size = window.getSize();
        $$(canvas, footer).setStyle("left", scroll.x + (size.x / 2));
        if (compatibleOverlay) overlay.setStyles({ left: scroll.x, top: scroll.y, width: size.x, height: size.y });
    }

    function setup(open) {
        // Use IframeShim instead of hiding IE Elements
        if (open) { shim = new IframeShim(overlay, { name: "navshim", display: true }); }
        else { shim.hide(); }

        overlay.style.display = open ? "" : "none";

        var fn = open ? "addEvent" : "removeEvent";
        window[fn]("scroll", position)[fn]("resize", position);
        document[fn]("keydown", keyDown);

        // Set text for navigation for accessibility
        prevLink.set('html', options.prevText);
        nextLink.set('html', options.nextText);
        closeLink.set('html', options.closeText);
    }

    function keyDown(event) {
        var code = event.code;

        // Prevent default keyboard action (like navigating inside the page)
        return options.closeKeys.contains(code) ? close()
            : options.nextKeys.contains(code) ? next()
            : options.previousKeys.contains(code) ? previous()
            : false;
    }

    function previous() {
        return changeItem(prevItem);
    }

    function next() {
        return changeItem(nextItem);
    }

    function changeItem(itemIndex) {
        if (itemIndex >= 0) {
            activeItem = itemIndex;
            activeUrl = items[itemIndex][0];
            prevItem = (activeItem || (options.loop ? items.length : 0)) - 1;
            nextItem = ((activeItem + 1) % items.length) || (options.loop ? 0 : -1);

            stop();
            canvas.className = "sbLoading";

            mediaChain = new Chain();
            mediaChain.chain(
                function() { setContent(); },
                function() { animateCanvas(); }
            );
            (function() { mediaChain.callChain(); }).delay(1000);
        }

        return false;
    }

    // set content area  / mod[eVolve]
    function setContent() {
        var type, obj, videoId, link = items[activeItem][0], hash = items[activeItem][2], elId = items[activeItem][3], vars = {}, params = {}, loaded = true, flash;

        // Extended options that can be set for each media item in the items collection
        var extOptions = $extend({
            modal: false,       // If false the overlay will close Soapbox / mod[eVolve]
            width: 400,
            height: 400,
            mediaPlayer: '/flash/player.swf',       // location of media player for flv, mp3, mp4, h.264, aac flv7, flv8 formats
            expressInstall: '/flash/expressinstall.swf',       // location of the expressinstall swf
            mediaPlayerSkin: '/flash/playerskins/modieus.swf',
            fullscreen: true,
            autoplay: true,
            controls: 'over',    // bottom | over | none
            bgcolor: '#000',
            wmode: 'opaque',
            version: 9.0,
            minor: 124.0
        });

        elId = (elId != '' ? elId : new Date().getTime());

        // set extOptions based on relcoptions (modal, wmode, fullscreen, controls, bgcolor, autoplay, width, height) / mod[eVolve]
        if (hash.get('modal') != null) { extOptions.modal = hash.get('modal'); }
        if (hash.get('wmode') != null) { extOptions.wmode = hash.get('wmode'); }
        if (hash.get('fullscreen') != null) { extOptions.fullscreen = hash.get('fullscreen'); }
        if (hash.get('controls') != null) { extOptions.controls = hash.get('controls'); }
        if (hash.get('bgcolor') != null) { extOptions.bgcolor = hash.get('bgcolor'); }
        if (hash.get('autoplay') != null) { extOptions.autoplay = hash.get('autoplay'); }
        if (hash.get('width') != null) { canvasWidth = extOptions.width = hash.get("width"); }
        if (hash.get('height') != null) { canvasHeight = extOptions.height = hash.get('height'); }
        if (hash.get('version') != null) { extOptions.version = hash.get('version'); }
        if (hash.get('minor') != null) { extOptions.minor = hash.get('minor'); }

        // Determine the type of media to be displayed
        if (link.match(/flickr\.com/i)) { type = 'flickr'; videoId = link.split('/')[5]; }
        else if (link.match(/google\.com\/videoplay/i)) { type = 'google'; videoId = link.split('=')[1]; }
        else if (link.match(/metacafe\.com\/watch/i)) { type = 'metacafe'; videoId = link.split('/')[4] + '/' + link.split('/')[5]; }
        else if (link.match(/myspacetv\.com/i) || link.match(/vids.myspace\.com/i)) { type = 'myspacetv'; videoId = link.split('=')[2]; }
        else if (link.match(/revver\.com/i)) { type = 'revver'; videoId = link.split('/')[4]; }
        else if (link.match(/youtube\.com\/v/i)) { type = 'youtube'; videoId = link.substr(link.lastIndexOf('/') + 1).toLowerCase(); }
        else if (link.match(/youtube\.com\/watch/i)) { type = 'youtube'; videoId = link.split('=')[1]; }
        else if (link.match(/veoh\.com/i)) { type = 'veoh'; videoId = link.split('/')[4]; }
        else if (link.match(/vimeo\.com/i)) { type = 'vimeo'; videoId = link.split('/')[3]; }
        else if (link.match(/\#box_/i)) { type = 'inline'; }
        else { type = link.substr(link.lastIndexOf('.') + 1).toLowerCase(); }

        // set item format based on extOptions
        if (!extOptions.modal) { overlay.setStyles({ cursor: 'pointer' }).removeEvent('click', close).addEvent('click', close); }  // Allow Overlay to not close soapbox / mod[eVolve]
        else { overlay.setStyles({ cursor: 'default' }).removeEvent('click', close); }      // Dis-Allow Overlay to not close soapbox / mod[eVolve]

        if (media.getChildren().length > 0) { media.empty(); }

        switch (type) {
            case 'jpg':
            case 'gif':
            case 'png':
            case 'bmp':
                flash = false;
                loaded = false;
                obj = new Image();

                obj.onload = function() {
                    loaded = true;
                    canvasWidth = obj.width;
                    canvasHeight = obj.height;
                }

                obj.src = link;
                obj.setAttribute('id', 'img_' + elId);
                break;
            case 'swf':
                flash = true;
                obj = new Swiff(link, { id: 'swf_' + elId, width: extOptions.width, height: extOptions.height, params: { wmode: extOptions.wmode, bgcolor: extOptions.bgcolor, allowfullscreen: extOptions.fullscreen }, vars: {} });
                break;
            case 'flv':
            case 'vp6':
            case 'mp3':
            case 'mp4':
            case 'aac':
            case 'f4v':
                flash = true;
                obj = new Swiff(extOptions.mediaPlayer, { id: 'flv_' + elId, width: extOptions.width, height: extOptions.height, params: { wmode: extOptions.wmode, bgcolor: extOptions.bgcolor, allowfullscreen: extOptions.fullscreen }, vars: { file: link, autostart: extOptions.autoplay, fullscreen: extOptions.fullscreen, controlbar: extOptions.controls, skin: extOptions.mediaPlayerSkin} });
                break;
            case 'inline':
                flash = false;
                var inlinearray = link.split('#');
                var inline = $(inlinearray[1]);
                if (inline == null) { obj = new Element('div', { id: 'sbInline_' + elId }).set('html', '<p>Error</p><p>The content cannot be found</p>'); }
                else { obj = new Element('div', { id: 'sbInline_' + elId }).set('html', inline.get('html')); }
                break;
            case 'ajax':
                flash = false;
                obj = new Element('div', { id: 'sbInline_' + elId }).set('html', '<div style="padding:10px;"><p>Error</p><p>Feature not yet implemented</p></div>');
                break;
            case 'mov':
                flash = true;
                obj = new Element('div', { id: 'sbInline_' + elId }).set('html', '<div style="padding:10px;"><p>Error</p><p>Feature not yet implemented</p></div>');
                break;
            case 'flickr':
                flash = true;
                obj = new Swiff('http://www.flickr.com/apps/video/stewart.swf', { id: 'flickr_' + elId, width: extOptions.width, height: extOptions.height, params: { wmode: extOptions.wmode, bgcolor: extOptions.bgcolor, allowfullscreen: extOptions.fullscreen }, vars: { photo_id: videoId} });
                break;
            case 'google':
                flash = true;
                obj = new Swiff('http://video.google.com/googleplayer.swf?docId=' + videoId + '&fs=' + extOptions.fullscreen + (extOptions.autoplay ? '&autoplay=true' : ''), { id: 'google_' + elId, width: extOptions.width, height: extOptions.height, params: { wmode: extOptions.wmode, bgcolor: extOptions.bgcolor, allowfullscreen: extOptions.fullscreen }, vars: {} });
                break;
            case 'metacafe':
                flash = true;
                obj = new Swiff('http://www.metacafe.com/fplayer/' + videoId + '.swf', { id: 'metacafe_' + elId, width: extOptions.width, height: extOptions.height, params: { wmode: extOptions.wmode, bgcolor: extOptions.bgcolor, allowfullscreen: extOptions.fullscreen }, vars: { playerVars: 'showStats=no|autoPlay=' + (extOptions.autoplay ? 'yes' : 'no')} });
                break;
            case 'myspacetv':
                flash = true;
                obj = new Swiff('http://mediaservices.myspace.com/services/media/embed.aspx/m=' + videoId + ',t=1,mt=video,ap=' + (extOptions.autoplay ? '1' : '0'), { id: 'myspacetv_' + elId, width: extOptions.width, height: extOptions.height, params: { wmode: extOptions.wmode, bgcolor: extOptions.bgcolor, allowfullscreen: extOptions.fullscreen }, vars: {} });
                break;
            case 'revver':
                flash = true;
                obj = new Swiff('http://flash.revver.com/player/1.0/player.swf?mediaId=' + videoId, { id: 'revver_' + elId, width: extOptions.width, height: extOptions.height, params: { wmode: extOptions.wmode, bgcolor: extOptions.bgcolor, allowfullscreen: extOptions.fullscreen }, vars: { allowFullScreen: extOptions.fullscreen, autoStart: extOptions.autoplay} });
                break;
            case 'youtube':
                flash = true;
                obj = new Swiff('http://www.youtube.com/v/' + videoId + '&autoplay=' + (extOptions.autoplay ? '1' : '0') + '&fs=' + (extOptions.fullscreen ? '1' : '0'), { id: 'youtube_' + elId, width: extOptions.width, height: extOptions.height, params: { wmode: extOptions.wmode, bgcolor: extOptions.bgcolor, allowfullscreen: extOptions.fullscreen }, vars: {} });
                break;
            case 'veoh':
                flash = true;
                obj = new Swiff('http://www.veoh.com/veohplayer.swf?permalinkId=' + videoId + '&videoAutoPlay=' + (extOptions.autoplay ? '1' : '0') + '&allowFullScreen=' + extOptions.fullscreen, { id: 'veoh_' + elId, width: extOptions.width, height: extOptions.height, params: { wmode: extOptions.wmode, bgcolor: extOptions.bgcolor, allowfullscreen: extOptions.fullscreen }, vars: { allowFullScreen: extOptions.fullscreen, autoStart: extOptions.autoplay} });
                break;
            case 'vimeo':
                flash = true;
                obj = new Swiff('http://www.vimeo.com/moogaloop.swf?clip_id=' + videoId + '&amp;server=www.vimeo.com&amp;fullscreen=' + (extOptions.fullscreen ? '1' : '0') + '&autoplay=' + (extOptions.autoplay ? '1' : '0'), { id: 'vimeo_' + elId, width: extOptions.width, height: extOptions.height, params: { wmode: extOptions.wmode, bgcolor: extOptions.bgcolor, allowfullscreen: extOptions.fullscreen }, vars: {} });
                break;
            default:    // iframe
                flash = false;
                obj = new Element('iframe', { id: 'sbFrame_' + elId, width: extOptions.width, height: extOptions.height, frameBorder: 0, scrolling: 'auto', src: link });
                break;
        }

        // if content is flash check version and if not high enough show express install
        if (flash && (Browser.Plugins.Flash.version < extOptions.version || (Browser.Plugins.Flash.version == extOptions.version && Browser.Plugins.Flash.number < extOptions.minor))) {
            obj = new Swiff(extOptions.expressInstall, { id: 'express', width: extOptions.width, height: extOptions.height, params: { wmode: extOptions.wmode, bgcolor: extOptions.bgcolor, allowfullscreen: extOptions.fullscreen }, vars: {} });
        }

        media.adopt(obj);

        // use setInterval to wait on content type of Image to load so we can get the correct width and height then call nextEffect
        iId = setInterval(function() {
            if (loaded) {
                clearInterval(iId);
                mediaChain.callChain();
            }
        }, 500);
    }

    function animateCanvas() {
        canvas.className = "";
        fxMedia.set(0);

        media.setStyles({ display: "", width: canvasWidth + "px", height: canvasHeight + "px" });

        // Set footer text information
        title.set('html', items[activeItem][1].split('|', 2)[0] || '');
        caption.set('html', items[activeItem][1].split('|', 2)[1] || '');
        number.set('html', (options.showCounter && (items.length > 1)) ? options.counterText.replace(/{x}/, activeItem + 1).replace(/{y}/, items.length) : '');

        canvasWidth = media.offsetWidth;
        canvasHeight = media.offsetHeight;

        var top = Math.max(0, middle - (canvasHeight / 1.5)), check = 0, fn;

        check = fxResize.start({
            height: canvasHeight,
            top: top
        }).chain(
            function() {
                this.start({
                    width: canvasWidth, 
                    marginLeft: -canvasWidth / 2
                });
            }
        );

        fn = function() {
            footer.setStyles({ width: canvasWidth, top: top + canvas.offsetHeight, marginLeft: -canvasWidth / 2, visibility: "hidden", display: "" });
            fxMedia.start(1);
        }

        if (check) {
            fxResize.chain(fn);
        }
        else {
            fn();
        }
    }

    function animateFooter() {
        if (prevItem >= 0) prevLink.style.display = "";
        if (nextItem >= 0) nextLink.style.display = "";
        fxBottom.set(-footer.offsetHeight).start(0);
        footer.style.visibility = "";
    }

    function stop() {
        fxResize.cancel();
        fxMedia.cancel();
        fxBottom.cancel();
        $$(prevLink, nextLink, media, footer).setStyle("display", "none");
    }

    function close() {
        if (activeItem >= 0) {
            stop();
            activeItem = prevItem = nextItem = -1;
            canvas.style.display = "none";
            fxOverlay.cancel().chain(setup).start(0);
            if (media.getChildren().length > 0) { media.empty(); }      // if item area has children clear / mod[eVolve]
        }

        return false;
    }

    // get hash of options passed in rel= / mod[eVolve]
    function getOptionHash(rel) {
        var hash = new Hash();
        var regex = '{[A-Za-z0-9,:]+}';
        var opt = rel.match(regex);

        if (opt != null) {
            var s = opt[0].replace(/^\{+|\}+$/g, '');

            var itemOptions = s.split(',');
            itemOptions.each(function(e) {
                var itemOptions2 = e.split(':');
                hash.set(itemOptions2[0], itemOptions2[1]);
            });
        }

        return hash;
    }

    // API

    Element.implement({
        soapbox: function(_options, linkMapper) {
            // The processing of a single element is similar to the processing of a collection with a single element
            $$(this).soapbox(_options, linkMapper);

            return this;
        }
    });

    Elements.implement({
        /*
        options:	    Optional options object, see Soapbox.open()
        linkMapper:	    Optional function taking a link DOM element and an index as arguments and returning an array containing 2 elements:
        the image URL and the image caption (may contain HTML)
        linksFilter:    Optional function taking a link DOM element and an index as arguments and returning true if the element is part of
        the image collection that will be shown on click, false if not. "this" refers to the element that was clicked.
        This function must always return true when the DOM element argument is "this".
        */
        soapbox: function(_options, linkMapper, linksFilter) {
            linkMapper = linkMapper || function(el) {
                return [el.href, el.title, getOptionHash(el.rel), el.id];
            };

            linksFilter = linksFilter || function() {
                return true;
            };

            var links = this;

            links.removeEvents("click").addEvent("click", function() {
                // Build the list of media that will be displayed
                var filteredLinks = links.filter(linksFilter, this);
                return Soapbox.open(filteredLinks.map(linkMapper), filteredLinks.indexOf(this), _options);
            });

            return links;
        }
    });

    return {
        open: function(_items, startItem, _options) {
            options = $extend({
                loop: false, 			        // Allows to navigate between first and last images
                overlayOpacity: 0.8, 		    // 1 is opaque, 0 is completely transparent (change the color in the CSS file)
                overlayFadeDuration: 400,       // Duration of the overlay fade-in and fade-out animations (in milliseconds)
                resizeDuration: 400, 		    // Duration of each of the box resize animations (in milliseconds)
                resizeTransition: false, 	    // false uses the mootools default transition
                initialWidth: 250, 		        // Initial width of the box (in pixels)
                initialHeight: 250, 		    // Initial height of the box (in pixels)
                mediaFadeDuration: 400,         // Duration of the media fade-in animation (in milliseconds)
                footerAnimationDuration: 400,   // Duration of the caption animation (in milliseconds)
                animateFooter: true,            // True animates the footer
                showCounter: true, 		        // If true, a counter will only be shown if there is more than 1 image to display
                counterText: "(Item {x} of {y})", 	// Translate or change as you wish
                prevText: "<span style=\"text-decoration:underline;\">P</span>REV",
                nextText: "<span style=\"text-decoration:underline;\">N</span>EXT",
                closeText: "<span style=\"text-decoration:underline;\">C</span>LOSE",
                closeKeys: [27, 88, 67], 	    // Array of keycodes to close Slimbox, default: Esc (27), 'x' (88), 'c' (67)
                previousKeys: [37, 80], 		// Array of keycodes to navigate to the previous image, default: Left arrow (37), 'p' (80)
                nextKeys: [39, 78]			    // Array of keycodes to navigate to the next image, default: Right arrow (39), 'n' (78)
            }, _options || {});

            // Setup effects
            fxOverlay = new Fx.Tween(overlay, { property: "opacity", duration: options.overlayFadeDuration });
            fxResize = new Fx.Morph(canvas, { duration: options.resizeDuration, link: "chain" }, options.resizeTransition ? { transition: options.resizeTransition} : {});
            fxMedia = new Fx.Tween(media, { property: "opacity", duration: options.mediaFadeDuration, onComplete: animateFooter });
            fxBottom = new Fx.Tween(bottom, { property: "margin-top", duration: options.footerAnimationDuration });

            if (typeof _items == "string") {
                _items = [[_items, startItem]];
                startItem = 0;
            }

            middle = window.getScrollTop() + (window.getHeight() / 2);
            canvasWidth = options.initialWidth;
            canvasHeight = options.initialHeight;

            canvas.setStyles({ top: Math.max(0, middle - (canvasHeight / 2)), width: canvasWidth, height: canvasHeight, marginLeft: -canvasWidth / 2, display: "" });

            //compatibleOverlay = Browser.Engine.trident4 || (overlay.currentStyle && (overlay.currentStyle.position != "fixed"));
            compatibleOverlay = true;
            if (compatibleOverlay) overlay.style.position = "absolute";

            fxOverlay.set(0).start(options.overlayOpacity);

            position();
            setup(true);

            items = _items;
            options.loop = options.loop && (items.length > 1);
            return changeItem(startItem);
        }
    };
})();

// AUTOLOAD CODE BLOCK (MAY BE CHANGED OR REMOVED)
Soapbox.scanPage = function() {
    $$(document.links).filter(function(el) {
        return el.rel && el.rel.test(/^soapbox/i);
    }).soapbox({
    // put custom options here
}, null, function(el) {
    return (this == el) || ((this.rel.length > 8) && (this.rel == el.rel));
});
};

window.addEvent("domready", Soapbox.scanPage);

//    var links = $$('a').filter(function(el) {
//        return el.rel && el.rel.test(/^soapbox/i);
//    });

//    $$(links).soapbox({/* Put custom options here */}, null, function(el) {
//    var regex = 'soapbox(\[[A-Za-z0-9]+\])?';  // regular expression to find soapbox and any grouping info / mod[eVolve]

//    // get array of matches, [0] is soapbox[group], [1] is [group] / mod[eVolve]
//    var open = this.rel.match(regex);       // clicked item    
//    var each = el.rel.match(regex);         // each item

//    // return item if same or arry of items that match with [group] / mod[eVolve]
//    return (this == el) || (open[0] != 'soapbox' && open[0] == each[0]);
//});
