/*
** Blockswap 0.1.3
*/

(function ($) {
    /*
    ** Declare z-index layers
    */
    
    // Background or basic level
    var BACK = 2;
    
    // Level of items
    var ITEM = 5;
    
    // Controls
    var CONTROL = 10;
    
    /*
    ** Blockswap
    ** Framework for swapping items in a block
    ** Suitable for slideshows, carousels, galleries, or anything where one item is given the focus
    */
    
    // Build a block using a new root element, ready to add items by code
    var blockswap = function (block_class, options) {
        // Create the block with an empty root element
        var block = new block_class(options);
        
        return block;
    };
    
    // Build a block using items from an element, and replace that element with the root element
    var blockswap_collector = function (block_class, options) {
        // Create the block
        var block = new block_class(options);
        
        // Collect items from this element, and replace with new root element
        block.collect( $(this) );
        
        return block;
    };
    
    
    // Register the plain blockswap object with jQuery
    // This will hold the block definitions
    $.extend({
        blockswap: blockswap
    });
    
    // Register the 
    $.extend($.fn, {
        blockswap: blockswap_collector
    });
    
    
    /*
    ** Block: Default type
    */
    
    // Constructor; call this.setOptions(options), then this.init()
    blockswap.block = function (options) {
        this.setOptions(options)
        this.init();
    };
    blockswap.block.prototype = {
        /*
        ** Variables
        */
        
        // Default options
        defaults: {
            // Collect details and items from the element, and replace it with a new one
            // Example: if you want to turn a <ul> into a block
            // If you know that the content is already in the required DOM structure, this can be set to false
            collect:        true,
            
            // Collect the ID and class attributes from the element being replaced, and add them to the new one
            collectAttr:    true,
            
            // Selector to collect items from the specified element, using $().find()
            // If not set, will just select all level children, using $().children()
            collectItems:   undefined,
            
            // Whether or not next/previous should loop at the end
            loop:           true,
            
            // Basic colours
            background:     '#111',
            foreground:     '#eee',
            
            // Opacity for faded elements
            opacityFade:    0.7,
            
            // Time to display an item
            // If not set, the item will not be advanced automatically
            // This may be overridden by linking - see docs on linking
            displayTime:    undefined,
            
            // Pause playing when the user clicks next or previous
            // Any other user actions should check this too (buttons to jump etc) - obviously excluding pause and play
            pauseOnAction:  false,
            
            // Callback when the item has changed
            // Will be called in the context of the current block (this === block)
            // Will be passed two arguments: toIndex, fromIndex
            changed:        undefined
        },
        
        // Root element
        $root:      undefined,
        
        // Element under the root which holds the items
        $items:     undefined,
        
        // jQuery collection of the item containers ($root and $items)
        $containers:    undefined,
        
        // Index of currently selected element
        current:    undefined,
        
        // Playing status - whether or not to advance automatically, depending on options.displayTime
        playing:    false,
        
        // Timer for playing
        playTimer:  undefined,
        
        // Autonomous state - if false, this block must supress any autonomous activity (timers etc)
        // This is for linking blocks as slaves; transitions, user actions etc are still allowed
        autonomous: true,
        
        
        /*
        ** Methods
        */
        
        // Store options
        setOptions: function (options) {
            this.options = $.extend({}, this.defaults, options);
        },
        
        // Initialise the root element
        init: function () {
            this.$root = $('<div/>')
                .css('background', this.options.background)
                .css('color', this.options.foreground)
            ;
            this.$items = $('<div/>').appendTo(this.$root);
            this.$containers = this.$root.add(this.$items);
        },
        
        // Collect the items from the page
        // Only called if the block is being generated by blockswap_collector()
        collect: function ($el) {
            // If not collecting, store element as root element
            if (!this.options.collect) {
                this.$root = $el;
                return;
            }
            
            // Store for closures
            var thisblock = this;
            
            // Apply ID and class to root element
            if (this.options.collectAttr) {
                this.$root.attr('id', $el.attr('id'));
                this.$root.attr('class', $el.attr('class'));
            }
            
            // Find elements
            var $items;
            if (this.options.collectItems) {
                $items = $el.find( this.options.collectItems );
            } else {
                $items = $el.children();
            }
            $items.detach();
            
            // Replace element with root element
            $el.replaceWith(this.$root);
            
            // Add items
            $items.each(function () {
                thisblock.addItem($(this).contents());
            });
            
        },
        
        // Prepare the specified item or items
        prepare: function ($items) {
            // Simply hide all
            $items.hide();
        },
        
        // Add an item to the root element
        // Takes a jQuery object holding the content for this item
        addItem: function ($content) {
            var as = '<div/>';
            var $item = $(as).append($content);
            $item.appendTo( this.$items );
            
            // Prepare the specific item
            this.prepare($item)
        },
        
        // Get the current number of items
        itemCount: function () {
            return this.$items.children().length;
        },
        
        // Get the item at the specified index
        getItem: function (index) {
            if (index === undefined) {
                return undefined;
            }
            return this.$items.children().eq(index);
        },
        
        
        /*
        ** Control and Navigation
        */
        
        play: function (no_jump) {
            // Do nothing if already playing
            if (this.playing) {
                return;
            }
            
            // Mark as playing
            this.playing = true;
            
            // Raise event so linked blocks find out
            this.$root.trigger('play.blockswap');
            
            // Take no action if we're not allowed to jump (ie called by an event from a linked block)
            if (no_jump) {
                return;
            }
            
            // Play the next or first item
            if (this.current === undefined) {
                this.jump(0);
            } else {
                this.jump(this.current + 1);
            }
        },
        pause: function () {
            // Do nothing if already paused
            if (!this.playing) {
                return;
            }
            
            // Mark as paused
            this.playing = false;
            
            // Clear any active play timer
            if (this.playTimer) {
                clearTimeout(this.playTimer);
            }
            
            // Raise event so linked blocks find out
            this.$root.trigger('pause.blockswap');
        },
        
        // Whether calling next() will do anything
        // Use to determine whether or not to enable the next button
        canNext: function () {
            var count = this.itemCount();
            
            // Can't go next if there's nothing to go to
            // Can't go next if not looping and already at the end
            if (count <= 1 || (!this.options.loop && this.current >= count)) {
                return false;
            }
            
            // Can loop
            return true;
        },
        
        // Whether calling previous() will do anything
        // Use to determine whether or not to enable the previous button
        canPrevious: function () {
            // Can't go previous if there's nothing to go to
            // Can't go previous if not looping and already at start
            if (this.itemCount() <= 1 || (!this.options.loop && this.current == 0)) {
                return false;
            }
            
            // Can loop
            return true;
        },
        
        // Jump to the next item
        next: function () {
            if (this.options.pauseOnAction) {
                this.pause();
            }
            this.jump(this.current + 1);
        },
        
        // Jump to the previous item
        previous: function () {
            if (this.options.pauseOnAction) {
                this.pause();
            }
            this.jump(this.current - 1);
        },
        
        // Impose limits and call animate(to, from)
        // Note: This must not trigger the `jump.blockswap` event if `to`==`this.current`, to avoid infinite loops
        jump: function (to, autonomous) {
            // Make sure we're jumping to a number
            to = parseInt(to);
            
            // Clear the timer, in case we were called by the timer
            if (this.playTimer) {
                clearTimeout(this.playTimer);
            }
            
            var from = this.current;
            
            // Impose limits
            var count = this.itemCount();
            
            // If nowhere to go, take no action
            if (count == 0) {
                return;
            }
            
            // Impose limit
            if (to >= count) {
                // Loop or limit
                to = (this.options.loop) ? to % count : count - 1;
            } else if (to < 0) {
                to = (this.options.loop) ? count + (to % count) : 0;
            }
            
            // If from == to, take no action
            if (from == to) {
                return;
            }
            
            // Change the current image
            this.current = to;
            
            // Raise event so linked blocks find out
            this.$root.trigger('jump.blockswap', [to, autonomous]);
            
            // Render
            this.render(to, from);
        },
        
        // Render the item, animating as necessary
        render: function (to, from) {
            // Basic swap
            this.getItem(from).hide();
            this.getItem(to).show();
            
            // Finish
            this.renderComplete(to);
        },
        renderComplete: function (to, from) {
            // Callback
            if (this.options.changed) {
                this.options.changed.call(this, to, from);
            }
            
            // Advance
            if (this.playing && this.options.displayTime) {
                if (this.playTimer) {
                    clearTimeout(this.playTimer);
                }
                
                // Add a new timer to jump to the next item
                if (this.autonomous) {
                    var thisBlock = this;
                    var next = thisBlock.current + 1;
                    this.playTimer = setTimeout(function () {
                        // Call the jump with autonomous=true
                        thisBlock.jump(next, true);
                    }, this.options.displayTime);
                }
            }
        },
        
        // Redraw the current state
        // Can be used to recover from incorrect renderings when hidden
        redraw: function () {
            this.render(this.current);
        },
        
        
        /*
        ** Linkage
        */
        
        // Link another block to this one
        // This will tell each block to listen to the other for blockswap.jump events
        // If the `no_reciprocal` flag is set, no reciprocal link will be set up on `block`; usually for internal use, to complete second half of the link
        link: function (block, no_reciprocal) {
            // Listen to custom events on the block
            var thisBlock = this;
            block.$root.bind('jump.blockswap', function (e, to, autonomous) {
                thisBlock.jump(to, autonomous);
            });
            block.$root.bind('play.blockswap', function (e) {
                // Call play with no_jump==true
                thisBlock.play(true);
            });
            block.$root.bind('pause.blockswap', function (e) {
                thisBlock.pause();
            });
            
            // Set up reciprocal link
            if (!no_reciprocal) {
                // Call link with no_reciprocal to avoid loop
                block.link(this, true);
            }
        },
        
        // Link this block to another block, with this as a slave
        // Exactly the same as `link(block)`, only `this.autonomous` will be set to false to supress any autonomous activity (timers etc)
        slave: function (block) {
            this.link(block);
            this.autonomous = false;
        }
    };
    
    
    /*
    ** Block: Slideshow
    */
    
    blockswap.slideshow = function (options) {
        blockswap.block.call(this, options);
    };
    blockswap.slideshow.prototype = $.extend({}, blockswap.block.prototype, {
        // Button jQuery objects
        $next:      undefined,
        $previous:  undefined,
        $play:      undefined,
        $pause:     undefined,
        
        // List of buttons
        $buttons:   undefined,
        
        // Object containing css styles for buttons; build from options
        buttonStyle: undefined,
        
        // Filmstrip block
        filmstrip:  undefined,
        
        // Caption block
        caption:    undefined,
        
        init: function () {
            // Super
            blockswap.block.prototype.init.call(this);
            
            // Style
            this.$containers
                .css('position', 'relative')
                .css('overflow', 'hidden')
            ;
            if (this.options.width) {
                this.$containers.css('width', this.options.width);
            }
            if (this.options.height) {
                this.$containers
                    .css('height', this.options.height)
                ;
            }
        },
        prepare: function ($items) {
            // Set CSS on the child elements, then hide them
            $items.css({
                'z-index':  BACK,
                'position': 'absolute',
                'width':    '100%',
                'top':      0,
                'left':     0
            }).hide();
            
            if (this.options.height) {
                $items.css('height', '100%');
            }
            
            // Rescale images
            var $images = $items.find('img')
            if (this.options.rescaleImages) {
                if (this.options.width) {
                    $images.css('max-width', this.options.width);
                }
                if (this.options.height) {
                    $images.css('max-height', this.options.height);
                }
            }
            
            // Autocenter images
            if (this.options.centerImages) {
                $images
                    .css('display', 'block')
                    .css('margin-left', 'auto')
                    .css('margin-right', 'auto')
                ;
            }
        },
        render: function (to, from) {
            // Look up items
            var $to = this.getItem(to);
            var $from = this.getItem(from);
            
            // Find transition type and speed
            var type = this.options.transitionType;
            var speed = this.options.transitionSpeed;
            
            // Build callback function for when the transition is complete
            var thisBlock = this;
            var completeFn = function () {
                thisBlock.renderComplete(to, from);
            };
            
            // If the root element is hidden, avoid using jQuery effects
            if (this.$root.is(':hidden')) {
                type = '';
            }
            
            // Perform the transition
            if (type == 'fade') {
                if ($from) {
                    $from.fadeOut(speed);
                    $to.fadeIn(speed, completeFn);
                } else {
                    $to.show();
                    completeFn();
                }
            } else if (type == 'slide') {
                if ($from) {
                    $from.slideUp(speed);
                    $to.slideDown(speed, completeFn);
                } else {
                    $to.show();
                    completeFn();
                }
            } else {
                if ($from) {
                    $from.hide();
                }
                $to.show();
                completeFn();
            }
            
            // Change the height, if not static
            if (!this.options.height) {
                this.$containers.animate({
                    height: $to.height()
                });
            }
        },
        
        /*
        ** Custom slideshow functions
        */
        
        // Add buttons
        addButtons: function (options) {
            // Apply defaults
            options = $.extend({}, this.options.addButtons, options);
            this.buttonStyle = $.extend({}, this.options.addButtons.style, options.style || {});
            var thisBlock = this;
                
            // Build and bind buttons
            function build(name) {
                var $name = '$'+name;
                if (options[name] && !thisBlock[$name]) {
                    return thisBlock[$name] = thisBlock.styleButton(
                            $('<a href="#">' + options[name + 'Content'] + '</a>')
                        )
                        .appendTo(thisBlock.$root)
                        .hide()
                        .click(function (e) {
                            e.preventDefault();
                            thisBlock[name]();
                        })
                    ;
                }
                return $();
            }
            
            // Build and style side buttons
            build('next')
                .css('right',       '0')
            ;
            build('previous')
                .css('left',        '0')
            ;
            
            
            // Build and style mid buttons
            build('play');
            build('pause')
                .add(this.$play)
                    .css('left',        '50%')
                    .css('margin-left', '-1em')
            ;
            
            // Add hover effect to show the buttons
            this.$buttons = this.$root.children('a');
            var currentButtons = this.$buttons;
            this.$root
                .hover(function () {
                    thisBlock.$buttons.hide();
                    currentButtons = thisBlock.$buttons.not(
                        thisBlock.playing ? thisBlock.$play : thisBlock.$pause 
                    )
                        .fadeTo('fast', thisBlock.options.opacityFade)
                    ;
                }, function () {
                    currentButtons.fadeOut('fast');
                })
                .click(function () {
                    thisBlock.$buttons.hide();
                    currentButtons = thisBlock.$buttons.not(
                        thisBlock.playing ? thisBlock.$play : thisBlock.$pause 
                    )
                        .show()
                    ;
                })
            ;
        },
        styleButton: function ($el, style) {
            style = (style) ? $.extend({}, this.buttonStyle, style) : (this.buttonStyle || {});
            return $el.css(style);
        },
        
        // Add a filmstrip
        // Filmstrip images are the first image in each item
        // Options:
        //      above   false
        //      carousel    Options for carousel
        //                  Defaults:
        //                      width   Width of slideshow
        //                      clickJump   True
        addFilmstrip: function (options) {
            options = $.extend({
                'above':    false,
                'carousel': {}
            }, options);
            
            // Filmstrip is a carousel
            var filmstrip = this.filmstrip = $.blockswap(
                $.blockswap.carousel,
                $.extend({}, {
                    clickJump: true,
                    width:  this.options.width
                }, options.carousel)
            );
            
            // Add items
            this.$items.children().each( function () {
                filmstrip.addItem(
                    $(this).find('img').first().clone()
                );
            });
            
            // Link as a slave
            filmstrip.slave(this);
            
            // Try to add to page
            if (this.$root.parent()) {
                if (options.above) {
                    this.$root.before(filmstrip.$root);
                } else {
                    this.$root.after(filmstrip.$root);
                }
            }
        },
        
        // Add a caption bar
        // Optional first argument declares the block to use for the captions
        // Otherwise builds a new caption block using the title of the first image in each item
        addCaptions: function (caption) {
            if (!caption) {
                // Build a new block if necessary
                // Caption block is a slideshow
                caption = $.blockswap(
                    $.blockswap.slideshow, {
                        height: null
                    }
                );
                    
                // Add items
                this.$items.children().each( function () {
                    caption.addItem(
                        $('<div/>')
                            .text( $(this).find('img').attr('title') || '')
                            .css('padding', '2px 4px')
                    );
                });
            }
            this.caption = caption;
            
            // Link as a slave
            caption.slave(this);
            
            // Add to the root and style
            caption.$root
                .appendTo(this.$root)
                .css('position',    'absolute')
                .css('z-index',     ITEM + 1)
                .css('bottom',      '0')
                .css('left',        '0')
                .css('background',  'rgba(0,0,0, ' + this.options.opacityFade + ')')
            ;
        }
    });
    
    // Extend options
    blockswap.slideshow.prototype.defaults = $.extend({}, blockswap.block.prototype.defaults, {
        // Width of the root element
        width:  550,
        
        // Height of the root element, optional
        // If no height, the root element will auto-adjust to the height necessary for the item being shown
        height: 350,
        
        // Rescale images down to match the width and height of the container
        // It uses CSS max-width and max-height, so will not work in IE6
        rescaleImages:      true,
        
        // Center images
        centerImages:       true,
        
        // Time to display an item
        displayTime:        3000,
        
        // Type of transition; one of 'fade', 'slide', or anything else to switch immediately
        transitionType:     'fade',
        
        // Speed of transition - any valid jQuery speed
        transitionSpeed:    'normal',
        
        // Defaults for addButtons
        addButtons: {
            next:           true,
            nextContent:    '&raquo;',
            previous:       true,
            previousContent:'&laquo;',
            play:           true,
            playContent:    '&gt;',
            pause:          true,
            pauseContent:   '||',
            style: {
                'position':        'absolute',
                'display':         'block',
                'z-index':         CONTROL,
                'background':      '#000',
                'color':           '#fff',
                'font-size':       '2em',
                'padding':         '0.5em',
                'text-decoration': 'none',
                'text-align':      'center',
                'width':           '1em',
                'height':          '1em',
                'line-height':     '1em',
                'top':             '50%',
                'margin-top':      '-1em'
            }
        }
        
    });
    
    
    /*
    ** Block: Carousel
    */
    
    blockswap.carousel = function (options) {
        blockswap.block.call(this, options);
    };
    blockswap.carousel.prototype = $.extend({}, blockswap.block.prototype, {
        // Highlighter element
        $highlighter: undefined,
        
        init: function () {
            // Super
            blockswap.block.prototype.init.call(this);
            
            // Style
            this.$root
                .css('position', 'relative')
            ;
            
            // Scrolling
            if (this.options.scrollbar) {
                this.$root.css('overflow-x', 'scroll');
                this.$root.css('overflow-y', 'hidden');
            } else {
                this.$root.css('overflow', 'hidden');
            }
            
            this.$items
                .css('position', 'relative')
            ;
            if (this.options.width) {
                this.$root.css('width', this.options.width);
            }
            if (this.options.height) {
                this.$items.height(this.options.height);
            }
            
            // Sanity check the options
            if (!this.options.itemWidth && !this.options.itemHeight) {
                // Can't rescale images if we don't know the size to rescale to
                this.options.rescaleImages = false;
            }
            
            // Add highlighter
            this.$highlighter = $('<div/>')
                .css('position', 'absolute')
                .css('border', '1px solid #eee')
                .appendTo(this.$root)
            ;
        },
        
        addItem: function ($content) {
            var as = '<div/>';
            var $item = $(as).append($content);
            $item.appendTo( this.$items );
            
            // Give each item a reference to its block item index
            $item.attr('data-blockswap-index', this.$items.children().length - 1);
            
            // Prepare the specific item
            this.prepare($item)
        },
        prepare: function ($items) {
            // Style items
            $items
                .css('float', 'left')
                .css('border', '1px solid #111')
                .css('margin', '4px 2px')
                .fadeTo(0, this.options.opacityFade)
            ;
            
            // Bind the click event
            if (this.options.clickJump) {
                var thisBlock = this;
                $items
                    .css('cursor', 'pointer')
                    .click( function (e) {
                        thisBlock.jump(
                            $(this).attr('data-blockswap-index')
                        );
                    })
                    .hover( function () {
                        var $t = $(this);
                        
                        // Don't highlight if already highlighted
                        if ($t.attr('data-blockswap-index') == thisBlock.current) {
                            return;
                        }
                        
                        // Stop any existing animation and fade in
                        $t.stop(true).fadeTo('fast', 1);
                        
                    }, function () {
                        var $t = $(this);
                        if ($t.attr('data-blockswap-index') == thisBlock.current) {
                            return;
                        }
                        $t.stop(true).fadeTo('fast', thisBlock.options.opacityFade);
                    })
                ;
            }
            
            // Set dimensions
            if (this.options.itemWidth) {
                $items.width(this.options.itemWidth);
            }
            if (this.options.itemHeight) {
                $items.height(this.options.itemHeight);
            }
            
            
            // Rescale images
            var $images = $items.find('img');
            if (this.options.rescaleImages) {
                if (this.options.itemWidth) {
                    $images.css('max-width', this.options.itemWidth);
                }
                if (this.options.itemHeight) {
                    $images.css('max-height', this.options.itemHeight);
                }
            }
            
            // Autocenter images
            if (this.options.centerImages) {
                $images
                    .css('display', 'block')
                    .css('margin-left', 'auto')
                    .css('margin-right', 'auto')
                ;
            }
            
            // Resize items container
            this.itemsResize();
            
            // If we don't know the sizes yet, register a load event to resize
            if (!this.options.itemWidth) {
                thisBlock = this;
                $items.find('img').load(function () {
                    thisBlock.itemsResize();
                });
            }
        },
        itemsResize: function () {
            // Calculate outer width
            // $.outerWidth(true) is unreliable: it misses the internal width and border if the element is not visible
            // This may be fixed in future versions of jQuery, but until then we must calculate it ourselves
            // If no width found, estimate a worst-case width by returning the width of the carousel
            var thisBlock = this;
            function outerWidth($el) {
                var outerWidth = $el.width();
                if (!outerWidth) {
                    return thisBlock.options.width;
                }
                var fields = ['padding-left', 'padding-right', 'margin-left', 'margin-right', 'borderLeftWidth', 'borderRightWidth'];
                for (var i=0; i<fields.length; i++) {
                    outerWidth += parseInt( $el.css(fields[i]) );
                }
                return outerWidth;
            }
            
            // Grow items container
            var width = 0;
            if (this.options.itemWidth) {
                var children = this.$items.children();
                width = outerWidth(children.first()) * children.length;
            } else {
                this.$items.children().each(function () {
                    width += outerWidth($(this));
                });
                // If there is a width, set it, with an extra pixel for rounding error
                if (width > 0) {
                    width++;
                }
            }
            this.$items.width(width);
        },
        render: function (to, from) {
            // Build callback function for when the transition is complete
            var thisBlock = this;
            var completeFn = function () {
                thisBlock.renderComplete(to, from);
            };
            
            var $to = this.getItem(to);
            var $from = this.getItem(from);
            
            // Catch nothing to render
            if ($to.length == 0) {
                return;
            }
            
            // Highlight the current image
            if ($from) {
                $from
                    .fadeTo(this.options.selectionSpeed, this.options.opacityFade)
                ;
            }
            $to
                .fadeTo(this.options.selectionSpeed, 1, completeFn)
            ;
            
            // Move the highlighter to the same size as the element, within its margin
            var pos = $to.position();
            this.$highlighter.animate({
                top:    pos.top + ( ($to.outerHeight(true) - $to.outerHeight()) / 2 ),
                left:   pos.left + ( ($to.outerWidth(true) - $to.outerWidth()) / 2 ),
                height: $to.height(),
                width:  $to.width()
            });
            
            // Scroll the container
            var contMid = this.$root.width() / 2;
            var itemMid = $to.outerWidth(true) / 2;
            var scrollLeft = (pos.left + itemMid) - contMid;
            if (this.options.transitionType == 'slide') {
                this.$root.animate({scrollLeft: scrollLeft}, this.options.transitionSpeed);
            } else {
                this.$root.scrollLeft(scrollLeft);
            }
        },
        
        // Redraw the current state
        // Can be used to recover from incorrect renderings when hidden
        redraw: function () {
            this.itemsResize();
            this.render(this.current);
        }
    });
    
    // Extend options
    blockswap.carousel.prototype.defaults = $.extend({}, blockswap.block.prototype.defaults, {
        // Dimensions for the root element
        width:  550,
        height: 77,
        
        // Dimensions for the item elements
        // If the item width is not set here, the width of the elements must be known when being added, for itemsResize to get it right
        // If the width is not set and not known, itemsResize must be called once it is known
        itemWidth: 120,
        itemHeight: 77,
        
        // Rescale images down to match the width and height of the container
        // It uses CSS max-width and max-height, so will not work in IE6
        rescaleImages:      true,
        
        // Center images
        centerImages:       true,
        
        // Time to display an item
        displayTime:        3000,
        
        // Speed of selection change (fading)
        selectionSpeed:     'normal',
        
        // Type of transition; 'slide', or anything else to switch immediately
        transitionType:     'slide',
        
        // Speed of transition - any valid jQuery speed
        transitionSpeed:    'normal',
        
        // Display scrollbar
        scrollbar:          true,
        
        // Click an element to jump to it
        clickJump:          false
    });
    
})(jQuery);

