
/*
    SiteComponents version:
    6.7.0, tag SC_6_7_0, created Thu Jan 07 10:17:49 +0100 2010

    Disclaimer
    
    While we make every effort to ensure that this code is fit for its intended
    purpose, we make no guarantees as to its functionality. CoreTrek AS will
    accept no responsibility for the loss of data or any other damage or
    financial loss caused by use of this code.


    Copyright
    
    This programming code is copyright of CoreTrek AS. Permission to run this
    code is given to approved users of CoreTrek's publishing system CorePublish.
    
    This source code may not be copied, modified or otherwise repurposed for use
    by a third party without the written permission of CoreTrek AS.
    
    Contact webmaster@coretrek.com for information.
    
*/

/*jslint laxbreak: true, sub: true, white: false, browser: true,
onevar: false, nomen: false, noindent: true, eqeqeq: false, plusplus: false,
forin: true, regex: false */
/*global siteComponentsConfig: false, getSiteComponentsConfig: false,
Ajax: false, $$: false, $: false, Element: false, window: false, Class: false,
Effect: false, PeriodicalExecuter: false, Event: false,
CtCookie: false, cpKeywords: false, CtTooltip: false, Prototype: false,
cpWriteMediaObject: false, Prototype: false */

/*

    ============================================================================
    IMPORTANT! This javascript is dependent on Prototype.
    ============================================================================

    SiteComponents Lightbox

    Displays a given URL or HTML snippet in a modal layer. All anchor tags that
    is set with the css-class "lightbox" will be opened in a lightbox. Just
    include this js-file, or the compressed lib.js, to enable.

    * Important SiteComponents requirements: *
    The requirements needs to be of the same version as this JavaScript file!

      - Kjapp lightbox style definitions
      - File html/images/lightbox/ff-overlay-img.png
      - File html/history-frame.php
      - Also remember to set the html/body height to 100% in your CSS

    If you want to programmatically open a lightbox, this can be done using
    the lightbox objects show or showHtml methods like this:

    lightbox.show('http://coretrek.no/cms/corepublish/webpublisering/');
    (If the URL is an image, the image will be opened in an image tag inside
    the lightbox)
    
    lightbox.showHtml("<h1>I'm in a lightbox!</h1>");
    
    The lightbox will fire the following custom events:
    
    - lightbox:contentDimensionChanged
      Fired when the content dimensions of a visible lightbox is changed
      
    - lightbox:contentUpdated
      Fired when the content of the lightbox is updated
      
    - lightbox:doShowFinished
      Fired aften the lightbox is displayed on screen

*/


// ----------------------------------------------------------------------------

// Initialization of lightbox var is done at the bottom to keep jslint happy
var lightbox;


var Lightbox = Class.create({

    // =====  PUBLIC METHODS  =================================================

    /**
     * Use this method to display a given HTML snippet inside a lightbox.
     * If you have a regular HTML (prototype) element, use it's innerHTML
     * property to get the HTML to display.
     */
    showHtml: function(html, setVisible) {
        this.prepareToShow();
        this.content.update(html);
        this.lightbox.fire('lightbox:contentUpdated');
        
        if(Object.isUndefined(setVisible) || setVisible === true) {
            this.doShow();
        }
    },

    /**
     * Use this if the content to be displayed inside the lightbox is avaliable
     * at an URL. All content from the URL will be fetched using Ajax and
     * inserted into the lightbox.
     *
     * Please note that because of Ajax limitations, the URL must be on the
     * same host as the rest of the site.
     *
     * Images will be opened using an image tag, inside the lightbox.
     *
     * A.lightbox links is rewritten to call this function with the href
     * property as contentUrl.
     */
    show: function(contentUrl) {
        this.prepareToShow();
        lightbox.getAndShowContentFromUrl(contentUrl);
    },

    /**
     * Use this to hide an open lightbox.
     */
    hide: function() {
        if(this.historyPolling !== null) {
            this.historyPolling.stop();
        }
        
        // Hide the lightbox
        this.lightbox.hide();
        this.content.hide();
        this.overlay.hide();
        this.spinner.hide();
        
        // Reset the original overflow definition on html
        this.htmlElement.setStyle({ overflow: this.htmlOverflowStyle });
        
        // Stop the content size sampler and remove the resize listeners
        this.contentDimensionChangedRunner.stop();
        Event.stopObserving(window, 'resize', this.windowResizeListenerObj);
        
        this.content.stopObserving('lightbox:contentDimensionChanged', this.windowResizeListenerObj);
        this.lightbox.stopObserving('lightbox:contentUpdated');
        
        // Reenable the invisibe persistent objects
        this.showPersistentObjects(true);
        
        // Clear the lightbox content (" ")
        this.content.update();
        
        if(window.location.hash == "#modal") {
            history.go(-1);
        }
        
        // Reset the lightbox container width to the original size
        this.container.setStyle({ width: this.originalContainerWidth + 'px'});
    },

    /**
     * This function initializes all a.lightbox links and add the
     * lightbox.show() method as the click action. If the optional element
     * parameter is provided, the function will only rewrite anchors that
     * is a decendant of the element.
     */
    initializeLightboxAnchors: function(element) {
        var elements = [];
        if(Object.isUndefined(element)) {
            elements = $$('a.lightbox');
        } else {
            elements = element.select('a.lightbox');
        }
        
        elements.each(function (element) {
            element.observe('click', function (event) {
                event.stop();
                
                var element = Event.findElement(event, 'a');
                if(element != document) {
                    lightbox.activeElement = element;
                    lightbox.show(element.getAttribute('href'));
                }
            });
        });

        if(Object.isUndefined(element)) {
            elements = $$('area.lightbox');
        } else {
            elements = element.select('area.lightbox');
        }

        elements.each(function (element) {
            element.observe('click', function (event) {
                event.stop();

                var element = Event.findElement(event, 'area');
                if(element != document) {
                    lightbox.activeElement = element;
                    lightbox.show(element.getAttribute('href'));
                }
            });
        });

        if(Object.isUndefined(element)) {
            elements = $$('select.lightbox');
        } else {
            elements = element.select('select.lightbox');
        }

        elements.each(function (element) {
            element.observe('change', function (event) {
                event.stop();

                var element = Event.findElement(event, 'select');
                if(element != document) {
                    lightbox.activeElement = element;
                    lightbox.show(element.getValue());
                }
            });
        });
    },
    
    /**
     * Used to check if the lightbox is visible.
     */
    isVisible: function() {
       return this.lightbox.visible();
    },
    
    /**
     * Constructor: initializes and inserts the lightbox into the document.
     */
    initialize: function() {
        this.history = {};
        this.historyPolling = null;
        
        this.htmlElement = $$('html').first();
        var objBody = $$('body').first();
        
        // Add history frame for Internet Explorer
        if(Prototype.Browser.IE) {
            var objHistoryFrame = document.createElement('iframe');
            
            objHistoryFrame.setAttribute('id', 'lightbox-history-frame');
            objHistoryFrame.src = "/history-frame.php";
            
            objHistoryFrame.style.display = 'block';
            objHistoryFrame.style.visibility = 'hidden';
            objHistoryFrame.style.position = 'absolute';
            objHistoryFrame.style.top = '0';
            objHistoryFrame.style.left = '0';
            objHistoryFrame.style.width = '1px';
            objHistoryFrame.style.height = '1px';
            
            objBody.appendChild(objHistoryFrame);
            this.historyFrame = objHistoryFrame;
        }

        objBody.insert({ bottom: '<div id="lightbox"></div><div id="lightbox-spinner"></div>' });
        
        var lightboxElement = $('lightbox');
        lightboxElement.setStyle({ display: 'none' });
        lightboxElement.update('<div id="lightbox-overlay"></div><div id="lightbox-container"></div>');
        
        var container = $('lightbox-container');
        
        container.update('<div id="lightbox-close-container"><a href="#" id="lightbox-close"><span>Close</span></a></div>');
        container.insert({ bottom: '<div id="lightbox-default-focus" style="display:none;"><input type="text" name="lightbox-default-focus"/></div>' });
        container.insert({ bottom: '<div id="lightbox-start"><div class="left"></div><div class="right"></div></div><div id="lightbox-content-left"></div><div id="lightbox-content-right"></div><div id="lightbox-outer-content"><div id="lightbox-content"></div></div><div id="lightbox-end"><div class="left"></div><div class="right"></div></div>'});
        
        this.content = $('lightbox-content');
        this.lightbox = $('lightbox');
        this.container = $('lightbox-container');
        this.overlay = $('lightbox-overlay');
        this.spinner = $('lightbox-spinner');
        // we're only interrested in the default focus input item
        this.defaultFocusElement = $('lightbox-default-focus').down();
        
        this.spinner.setStyle({
            position: 'absolute',
            zIndex: 1000,
            display: 'none'
        });
        
        
        this.containerTop = Element.getDimensionFromStyle(this.container, 'top');
        
        // Set opacity on overlay layer. Because of a bug in Firefox, causing
        // fixed positioned layers (behind a flash) to render the flash
        // invisible. This has to be done with a semitransparent png on this
        // browser. Make sure that the png has the same design as the css
        // styled overlay layer has on the other browsers.
        if(Prototype.Browser.Gecko) {
            this.overlay.setStyle({
                background: 'url(/images/lightbox/ff-overlay-img.png)'
            });
        } else {
            this.overlay.setStyle({
                opacity: 0.5
            });
        }
        
        // Add some required listeners
        document.observe('keydown', this.keydownListener.bindAsEventListener(this));
        this.lightbox.observe('click', this.lightboxClickListener.bindAsEventListener(this));
        
        // Add observers to close lightbox if overlay or close button is clicked
        $('lightbox-close').observe('click', this.clickToCloseListener.bindAsEventListener(this));
        this.overlay.observe('click', this.clickToCloseListener.bindAsEventListener(this));
        
        this.lightbox.observe('lightbox:contentReady', this.contentReadyListener.bindAsEventListener(this));
        this.lightbox.observe('lightbox:cpWriteMediaObjectRun', this.cpWriteMediaObjectRunListener.bindAsEventListener(this));
        
        // IE6 & 7 has a buggy z-index bug causing nested z-indexed elements to
        // behave a bit frustrating. We need to fix using JavaScript. Detect IE
        // versions below IE8 (in strict mode) and fix z-index
        // Ref: http://richa.avasthi.name/blogs/tepumpkin/2008/01/11/ie7-lessons-learned/
        if(Prototype.Browser.IE && (typeof document.documentMode == 'undefined' || document.documentMode == 7)) {
            var zi = 1000;
            this.container.select('div').each(function(element) {
                element.style.zIndex = zi--;
            });
        }
    },
    
    
    // =====  PRIVATE METHODS =================================================
    
    /**
     * Gets the accumulated horizontal padding between the content and outer
     * edge of the container. When resizing to content size we set the container
     * width to be this padding + the width of the content.
     * 
     * @protected
     */
    getContainerHorizontalPadding: function() {
        if(typeof this.containerPadding == 'undefined') {
            var current = this.content;
            var padding = 0;
            var i = 0;
            
            while(current !== null && current != this.container && i < 50) {
                padding += Element.getDimensionFromStyle(current, 'padding-left');
                padding += Element.getDimensionFromStyle(current, 'padding-right');
                padding += Element.getDimensionFromStyle(current, 'margin-left');
                padding += Element.getDimensionFromStyle(current, 'margin-right');
                
                var oldCurrent = current;
                current = current.getOffsetParent();
                
                if(current == oldCurrent) {
                    alert('Error: Could not resolve offsetParent - does the stylesheet contain all required styles?');
                    break;
                }
            }
            
            this.containerPadding = padding;
        }
        
        return this.containerPadding;
    },
    
    /**
     * Function add the HTML and listeners needed to handle closing the
     * lightbox on back navigation.
     * 
     * @protected
     */
    prepareHistory: function() {
        if(Prototype.Browser.IE) {
            this.historyFrame.src = "/history-frame.php?modal";
        } else {
            window.location.hash = "#modal";
        }

        this.historyPolling = new PeriodicalExecuter(function(pe) {
            var close = false;
            if(Prototype.Browser.IE) {
                var frameTitle = this.historyFrame.contentWindow.document.title;
                if(frameTitle.indexOf("?modal") < 0) {
                    close = true;
                }
            } else {
                var hash = window.location.hash;
                if(window.location.hash != "#modal") {
                    close = true;
                }
            }
            
            if(close) {
                pe.stop();
                if(this.isVisible()) {
                    this.hide();
                }
            }
        }.bind(this), 0.5);
    },
    
    /**
     * In IE6/IE7 and Opera some items will always show on top of the lightbox.
     * This function used to hide these elements.
     * 
     * @protected
     */
    showPersistentObjects: function(show) {
        $$('select', 'embed', 'object').each(function(element) {
            if(show) {
                element.style.visibility = 'visible';
            } else {
                element.style.visibility = 'hidden';
            }
        });
    },
    
    /**
     * Prepare to show the lightbox. This will initialize the lightbox and start
     * the spinner.
     *
     * @protected
     */ 
    prepareToShow: function() {
        if(!this.prepared) {
            // If lightbox is already visible, hide it
            if(this.isVisible()) {
                this.hide();
            }
            
            this.prepareHistory();
            
            this.content.hide();
            this.showPersistentObjects(false);
            
            this.overlay.show();
            this.container.hide();
            this.lightbox.show();
            
            // Disable scrollbars for main window
            this.scolloffset = document.viewport.getScrollOffsets();
            this.htmlOverflowStyle = this.htmlElement.getStyle('overflow');
            this.htmlElement.setStyle({ overflow: 'hidden' });
            
            // Reposition the lightbox and overlay. Show spinner
            this.repositionLightboxAndOverlay();
            this.repositionSpinner();
            this.spinner.show();
            
            this.prepared = true;
        }
    },
    
    /**
     * Function will reposition the lightbox and overlay correctly inside
     * the visible viewport. The function do not do anything with the lightbox
     * itself. This is done when the lightbox content is ready to be displayed.
     *
     * @protected
     */
    repositionLightboxAndOverlay: function() {
        var viewportOffsets = document.viewport.getScrollOffsets();
        var viewportDim = document.viewport.getDimensions();
        var containerDim = this.container.getDimensions();
        
        // Get the lightbox width and height. The lightbox will always fill 
        // the document viewpor
        var lightboxHeight = [containerDim['height'] + this.containerTop, viewportDim['height']].max();
        var lightboxWidth = [containerDim['width'], viewportDim['width']].max();
        
        // Position the lightbox inside the viewport
        this.lightbox.setStyle({
            top: viewportOffsets['top'] + 'px',
            left: viewportOffsets['left'] + 'px',
            width: viewportDim['width'] + 'px',
            height: viewportDim['height'] + 'px'
        });
        
        // Resize overlay to fill the visible viewport
        this.overlay.setStyle({
            left: '0px',
            top: '0px',
            height: lightboxHeight + 'px',
            width: lightboxWidth + 'px'
        });
    },
    
    /**
     * Internal method to actually set the lightbox to be visible. This method
     * needs the lightbox content to be set before it is called.
     * 
     * @protected
     */
    doShow: function() {
        if(!this.prepared) {
            this.prepareToShow();
        }
        
        // Reset the preparedToShow parameter as early as possible. Just in
        // case another show is initialized
        this.prepared = false;
        
        this.content.show();
        
        this.container.setStyle({
            visibility: 'hidden'
        });
        
        this.container.show();
        
        if(Object.isUndefined(this.originalContainerWidth) || this.originalContainerWidth === null) {
            this.originalContainerWidth = this.container.getWidth();
        }
        
        // We need to reposition the lightbox and overlay if the window or
        // lightbox content dimensions is changed. Lets add a few observers for
        // this.
        this.windowResizeListenerObj = this.windowResizeListener.bindAsEventListener(this);
        Event.observe(window, 'resize', this.windowResizeListenerObj);
        this.content.observe('lightbox:contentDimensionChanged', this.windowResizeListenerObj);
        
        // There is no predefined event for resized element content. This
        // happens in the lightbox when e.g. there are images that gets
        // displayed after the lightbox is displayed (because of loading time).
        // We add a PeriodicalExecuter that samples the content dimensions, and
        // fire a custom event if the size is changed.
        this.lastContentDimensions = this.content.getDimensions();
        this.contentDimensionChangedRunner = new PeriodicalExecuter(function(pe) {
            var contentDim = this.content.getDimensions();
            if(contentDim['height'] != this.lastContentDimensions['height'] ||
               contentDim['width'] != this.lastContentDimensions['width']) {
                this.content.fire('lightbox:contentDimensionChanged');
            }
            this.lastContentDimensions = this.content.getDimensions();
        }.bind(this), 0.5);
        
        // Lets adjust the lightbox content width if the lightbox contains an
        // element with a css-defined width, or the first element is an image or
        // a flash.
        var contentWidth = -1;
        var contentReady = false;
        
        var firstDiv = this.content.down('div');
        
        if(typeof firstDiv != 'undefined' && firstDiv.identify() != 'lightbox_flash_container' && firstDiv.getWidth() > 0) {
            this.setContentWidth(firstDiv.getWidth());
            contentReady = true;
        } else {
            var firstElement = this.content.down();
            var imageWidth;
            
            if(firstElement !== null && typeof firstElement != 'undefined') {
                if(firstElement.tagName == 'IMG') {
                    imageWidth = firstElement.getWidth();
                    // If image has not finished loading, it's width will be 0.
                    // Add an observer to resize content when image has loaded 
                    if(imageWidth > 0) {
                        this.setContentWidth(imageWidth);
                        contentReady = true;
                    } else {
                        firstElement.observe('load', this.resizeContentToImageSizeListener.bindAsEventListener(this));
                        // Content is not ready yet, content ready event will
                        // be triggered by the resizeContentToImageSizeListener
                    }
                } else if(firstElement.identify() == 'lightbox_flash_container' && firstElement.down() !== null) {
                    if(firstElement.down() !== null) {
                        var flashWidth = firstElement.down().getDimensionFromStyle('width');
                        if(flashWidth > 0) {
                            this.setContentWidth(flashWidth);
                            contentReady = true;
                        }
                    } else {
                        // The flash width is not available. The flash insert
                        // routine will resize the lightbox to flash width
                        // whenever possible without us doing anything here
                    }
                } else {
                    // There first element cannot be used to resolve width
                    contentReady = true;
                }
            } else {
                // There is no element to resolve with from
                contentReady = true;
            }
        }
        
        if(contentReady) {
            this.lightbox.fire('lightbox:contentReady');
        }
        
        this.lightbox.fire('lightbox:doShowFinished');
    },
    
    /**
     * Fetch content from a given url, and display this in the lightbox. This is
     * only intended for internal use (by this class). Use the method 
     * lightbox.show(contentUrl) instead.
     * 
     * @protected
     */
    getAndShowContentFromUrl: function(contentUrl) {
        if(contentUrl === null) {
            alert("No URL provided");
            return;
        }
        
        // If the URL is for a jpg, jpeg, png og gif file we generate an img tag
        // and display the image in the lightbox
        if(contentUrl.match(/\.(jpg|jpeg|png|gif)$/)) {
            // Lets preload the image while the loading state is running. This
            // will not work if the browser has disabled cache
            var image = new Image();
            
            // Show the image when the image is preloaded and ready
            Event.observe(image, 'load', function(event) {
                this.showHtml('<img src="' + contentUrl + '" alt=""/>');
            }.bindAsEventListener(this));
            
            image.src = contentUrl;
        }
        // If the URL is for a flash file (swf) or flash movie (flv) we
        // automatically embed the flash in the lightbox
        else if(contentUrl.match(/\.(swf|flv)/)) {
            // src, sessionName, width, height, mimeType, loop, autoplay, controller, objId, flashVars) {
            var html = '<div id="lightbox_flash_container"></div>';
            
            var width;
            var height;
            
            // There is no good automatic way to detect flv/swf dimensions
            // using JavaScript. The author have to have provided the 
            // dimensions to use, using the link name attribute. The
            // dimensions needs to be set in a widthXXXheightYYY string in
            // the name attribute of the link. If this is not set, we default
            // to a width of 500px and a height of 500px
            var defaultWidth = 500;
            var defaultHeight = 300;
            if(typeof this.activeElement != 'undefined') {
                var name = this.activeElement.readAttribute('name');
                if(name !== null && name.match(/width\d+height\d/)) {
                    width = name.match(/width(\d+)/).last();
                    height = name.match(/height(\d+)/).last();
                }
            }
            
            var extension = contentUrl.match(/\.(swf|flv)$/).last();
            var mimeType = '';
            switch(extension) {
                case 'swf':
                    mimeType = 'application/x-shockwave-flash';
                    
                    var flashvars = { };
                    break;
                case 'flv':
                    mimeType = 'video/flv';
                    
                    // We want the controls to float over the video
                    var flashVars = { floatingcontrols: 'true' };
                    break;
            }
            
            // Run the cpWriteMediaObject method when the flash container is
            // inserted and available
           this.lightbox.observe('lightbox:contentUpdated', function(event) {
               // If width is provided in link name we simply insert the obj
               if(typeof width != 'undefined' && typeof height != 'undefined') {
                   this.insertMediaObject(contentUrl, width, height, mimeType, flashVars);
               }
               // If dimensions is unavailable we try getting file dimensions
               // from the mmarchive.fileinfo service. If this fails we use
               // the default dimensions
               else {
                   var params = {
                       service: 'mmarchive.fileinfo',
                       fileUrl: contentUrl
                   };
                   
                   new Ajax.Request('/xmlhttprequest.php', {
                       parameters: params,
                       onSuccess: function(res) {
                           var info = res.responseText.evalJSON();
                           this.insertMediaObject(contentUrl, info.width, info.height, mimeType, flashVars);
                       }.bind(this),
                       onFailure: function() {
                           this.insertMediaObject(contentUrl, defaultWidth, defaultHeight, mimeType, flashVars);
                       }.bind(this)
                   });
               }
           }.bindAsEventListener(this));
           
           // We do not want the showHtml method to set the flash container
           // visible before the media object is inserted.
           this.showHtml(html, false);
        }
        
        // Other content is read and inserted into the lightbox
        else {
            new Ajax.Request(contentUrl, {
                method: 'get',
                
                onSuccess: function(transport) {
                    var content = transport.responseText;
                    
                    // Try extracting the real content. This uses a rather
                    // complex regexp matching. The reason for this is the
                    // differences in DOM XML parsing in different browsers.
                    // And when using XML parsing, some elements (e.g. textarea)
                    // is rewritten to it's short open/close type (e.g
                    // <textarea ... />. This do not work in XHTML.
                    // The regexp assumes that the regular SiteComponents
                    // placeholde-content(-no-right) is used!
                    
                    if(content.match(/<body\b/)) {
                        var match = content.match(/<div id="placeholder-content">([\s\S]*?)<div id="placeholder-/);
                        
                        if(match === null) {
                            match = content.match(/<div id="placeholder-content-no-right">([\s\S]*?)<div id="placeholder-/);
                        }
                        
                        if(match !== null) {
                            var newContent = match.first();
                            match = newContent.match(/([\s\S]*)<\/div>/);
                            
                            content = match.first();
                            
                            content = content.replace(/placeholder-content(-no-right)?/, 'lightbox-placeholder-content');
                        }
                    }
                    
                    this.content.update(content);
                    
                    // Lets append all tile classes from the inserted content,
                    // onto the placeholder. This allows us to style each tile
                    // independantly inside the lightbox
                    var contentDiv = this.content.select('div[id=lightbox-placeholder-content]').first();
                    var contentTiles = contentDiv.select('div.tile-common');
                    contentTiles.each(function(tile) {
                        tile.classNames().each(function(className) {
                            if(className == 'tile-common') {
                                return; // skip to next
                            }
                            contentDiv.addClassName(className + '-lightbox');
                        });
                    });
                    
                    this.lightbox.fire('lightbox:contentUpdated');
                    this.doShow();
                }.bind(this),
                
                onFailure: function(request) {
                    this.hide();
                    alert("Could not connect to URL");
                }.bind(this)
            });
        }
    },
    
    /**
     *
     * @protected
     */
    insertMediaObject: function(url, width, height, mimeType, flashVars) {
        cpWriteMediaObject(url, 'null', width, height, mimeType, 0, 1, 'null', 'lightbox_flash_container', flashVars, true);
        this.lightbox.fire('lightbox:cpWriteMediaObjectRun');
    },
    
    /**
     * Repositions the spinner at the center of the visible viewport.
     * 
     * @protected
     */
    repositionSpinner: function() {
        var offsets = document.viewport.getScrollOffsets();
        var dimensions = document.viewport.getDimensions();
        
        this.spinner.setStyle({
            top: offsets.top + 'px',
            left: offsets.left + 'px',
            width: dimensions.width + 'px',
            height: dimensions.height + 'px'
        });
    },
    
    /**
     * Internal function used to set the width of the content
     *
     * @protected
     */
    setContentWidth: function(width) {
        this.container.setStyle({
            width: width + this.getContainerHorizontalPadding() + 'px'
        });
    },
    
    /**
     * Internal function used to set the default focus in lightbox.
     *
     * @protected
     */
    setDefaultFocus: function() {
        // IE6 does not allow us to set focus to a non-visible element. We simply
        // catch the error and ignore it for now
        try {
            this.defaultFocusElement.focus();
        } catch (err) { }
    },
    
    // =====  EVENT LISTENERS =================================================
    
    contentReadyListener: function(event) {
        lightbox.initializeLightboxAnchors(this.content);
        
        this.container.setStyle({
            visibility: 'visible'
        });
        
        this.spinner.hide();
        this.repositionLightboxAndOverlay();
        
        // Move focus away from the item that was clicked to open lightbox
        this.setDefaultFocus();
    },
    
    /**
     * Handle the window resizing.
     * 
     * @protected
     */
    windowResizeListener: function(event) {
        this.repositionLightboxAndOverlay();
    },
    
    /**
     * This listener will resize the lightbox content to an image. If the
     * lightbox contains a single image, this listener is triggered when the
     * image is finished loading.
     * 
     * @protected
     */
    resizeContentToImageSizeListener: function(event) {
        this.setContentWidth(event.element().getHiddenElementDimensions().width);
        this.lightbox.fire('lightbox:contentReady');
    },
    
    cpWriteMediaObjectRunListener: function(event) {
        var el = $('lightbox_flash_container').down();
        if(el !== null) {
            this.setContentWidth(el.getDimensionFromStyle('width'));
            this.lightbox.fire('lightbox:contentReady');
        }
        this.doShow();
    },
    
    /**
     * The listener has two usages:
     *  1. Close the lightbox if escape is pressed
     *  2. Cancel tab and space events originating outside the lightbox. These
     *     events can submit or input tab elements outside the lightbox if not
     *     handled properly.
     */
    keydownListener: function(event) {
        if(lightbox.isVisible()) {
            if(event.keyCode == Event.KEY_ESC) {
                this.clickToCloseListener(event);
            }
            
            // Stop space, enter and tab events (keyCode 32 == space)
            if([32, Event.KEY_RETURN, Event.KEY_TAB, Event.KEY_UP, Event.KEY_DOWN].indexOf(event.keyCode) > -1) {
                if(!event.element().descendantOf(this.lightbox)) {
                    event.stop();
                }
            }
        }
    },
    
    /**
     * We do not want clicks for non input items bubbeling outside the lightbox.
     * The reason for this is that a click inside the lightbox, will be
     * interpreted as a click on the background element, if it is not handled
     * inside the lightbox. If the lightbox is positioned above an input element
     * click on the lightbox above this element will result in the element
     * gaining focus. This can scroll the document, leaving the lightbox
     * floating. To prevent this we listen for clicks in the top lightbox
     * element. If the click is originating on a non input item, the event is
     * cancelled.
     */
    lightboxClickListener: function(event) {
        var element = event.element();
        var anchor = event.findElement('a');
        if(['INPUT', 'BUTTON', 'A'].indexOf(element.nodeName) == -1 && Object.isUndefined(anchor)) {
            event.stop();
        }
        anchor = event.findElement('area');
        if(['INPUT', 'BUTTON', 'A'].indexOf(element.nodeName) == -1 && Object.isUndefined(anchor)) {
            event.stop();
        }
    },
    
    /**
     * If a close command should be issued to the lightbox in case of a mouse
     * click (e.g. click on overlay, click on close button). This is the
     * listener that should be attached to the elements. The listener will
     * cancel the event to stop event bubbling.
     *
     * @protected
     */
    clickToCloseListener: function(event) {
        event.stop();
        this.hide();
    }

});


document.observe('dom:loaded', function(event) {
    lightbox = new Lightbox();
    lightbox.initializeLightboxAnchors();
});

