﻿
//************************************************************************************
// Name:        SlideShow
//
// Written:     April-2008
//
// Author:      Russell Stitt
//
// Purpose:     Rotates a prerendered list of slides organised into divs with 
//              custom content, urls, an image and buttons to step through the
//              'slides'. 
//
// Requires:    Requires an count of slide objects. 
//  
// Method:      Since the divs of images and their controls are prerendered, the
//              script has a Start method which initiates the timer to switch slides.
//              The activation mechanism is through a stylesheet class called denoted
//              'active. By default slides are hidden.
//              Originally the images were visible only after a separate loading routine
//              had received 'load' events, but in the current incarnation, that 
//              technique was not required.
//
// Dependencies: 
//              - A precreated stylesheet (slideshow.css)
//
// Modified     Modified By     Explanation
//

function SlideShow(slideCount,slidePrefix,imageDelay, defaultIndex)
{          
        // The number of slides
        var slideCount = slideCount;
        
        // A prefix for the slide div ids - required for use with .net
        var slidePrefix = slidePrefix;
        
        // A delay in milliseconds to wait between slide changes      
        var imageDelay=imageDelay;   
         
        // The index of the currently visible slide 
        var currentSlideIndex=defaultIndex; 
        
        // The index of the last displayed slide.
        var previousSlideIndex=defaultIndex;
        
        // A handle to the slide timer
        var slideShowTimerId=0;                                 
                   
        //----------------------------------------------------------------------------
        // Main point of entry for the slide show.
        // Initialises the script and handlers for the manual slide display and starts
        // the slide rotation.
          
        this.Start = function()
        {              
            AttachButtonHandlers();   
                       
            StartSlideShow();         
        }
                         
        //----------------------------------------------------------------------------      
        // Primary point of entry to start the slide show. If there are problems with
        // latency then an image loader could be implemented to stop the slide show 
        // and to restart after all images are cached.
                
        function StartSlideShow()
        {            
            ShowSlides();
        }
        
        //----------------------------------------------------------------------------
        // Main loop to switch slides automatically. Uses a timer with a preset delay
        // to hide and show slides. On first rendering to the page, switching of slides
        // is avoided so that the default slide can be shown. This will be set in the 
        // .net control that renders the html and script. This method calls itself.
        
        function ShowSlides()
        {      
            if (slideShowTimerId>0)
            {
                clearTimeout(slideShowTimerId);
                GoNext();
            }
                                      
            ShowCurrentSlide(); 
            
            slideShowTimerId = setTimeout(function(){ ShowSlides(); }, imageDelay); 
        }
        
        //----------------------------------------------------------------------------
        // Method that will be called by button handlers to stop the slide show
        // and allow manual step-through of the slides.
        
        function KillSlideShow()
        {
            clearTimeout(slideShowTimerId);
        }  
        
        //----------------------------------------------------------------------------
        // A parameterless method to call into the framework to ensure the current
        // slide is shown and the previous slide is hidden
        
        function ShowCurrentSlide()
        {
               ShowThisSlide(previousSlideIndex, currentSlideIndex);
        }
        
        //----------------------------------------------------------------------------
        // Primary mechanism to hide the previous slide and activate the current.
        // Method works by switching classes on the divs as below. The 'active'
        // style is specified in the stylesheet.
        
        function ShowThisSlide(previousSlideIndex, currentSlideIndex)
        {
            var prevSlide = document.getElementById(GetSlideId(previousSlideIndex));
            var currentSlide = document.getElementById(GetSlideId(currentSlideIndex));
                                          
            if (prevSlide && currentSlide)
            {               
                prevSlide.className='slide';
                currentSlide.className='slide active';            
            }
        }
                        
        //----------------------------------------------------------------------------
        // A method to get the id of slide div corresponding to a given slide index.
        // The slidePrefix is required where the div is part of a .net parent control,
        // otherwise the prefix can be set as empty on initialisation.
        
        function GetSlideId(slideIndex)
        {
            return slidePrefix+'slide'+(slideIndex+1);
        }
        
        //----------------------------------------------------------------------------
        // A method that acts as a point of entry for manually stepping through the 
        // slides. It stops the slide show timer and taking the direction as parameter,
        // moves the slide index forward or backward and calls ShowCurrentSlide to
        // update the style on the (now) previous and (newly) current slide.
        // Where an invalid direction parameter is being passed, the slide show is 
        // restarted.
        
        function SelectNextSlide(direction)
        {
            KillSlideShow();
            
            if(direction=='back')
            {              
               GoBack();
                
               ShowCurrentSlide();            
            }
            else if (direction=='next')
            {
            
               GoNext();
                
               ShowCurrentSlide();
            }
            else
            {
               StartSlideShow();
            }
        }   
        
        //----------------------------------------------------------------------------------
        // Adjusts the current slide index forward taking into account the number of slides
        
        function GoNext()
        {
            previousSlideIndex=currentSlideIndex;
            currentSlideIndex=(currentSlideIndex+1)%slideCount;
        } 
        
        //----------------------------------------------------------------------------------
        // Adjusts the current slide index backward taking into account the number of slides
        // Also records the previous slide. This was required because of an implementation 
        // using an image fader
        
        function GoBack()
        {
            previousSlideIndex=currentSlideIndex;
            currentSlideIndex--;
            if (currentSlideIndex<0)
                currentSlideIndex = slideCount-1;
          
        }
           
        //---------------------------------------------------------------------------------
        // Attach javascript handlers for the two buttons in each of the 'controls' divs.
        // Current method cycles through each of the slide divs, finds the div that holds
        // the controls and then gets references to the two buttons, then attachs the
        // onclick handlers.
        
        function AttachButtonHandlers()
        {
            for(var i=0;i<slideCount;i++)
            {
                var div = GetControlDiv(i);
                
                if (div)
                {
                   
                    var prev = GetControlElement(div,'BUTTON','back');
                    var next = GetControlElement(div,'BUTTON','next');
                    
                    if (prev)
                    {                        
                        prev.onclick = function(){ SelectNextSlide('back'); return (false);} 
                        prev.style.visibility='visible';
                        prev.style.display='inline';
                                               
                    }
                    
                    if (next)
                    { 
                        next.onclick = function() { SelectNextSlide('next'); return (false);}
                        next.style.visibility='visible';
                        next.style.display='inline';
                    }
             
                }                
            
            }
        
        }
        
       //---------------------------------------------------------------------------------
       //  Returns the div with class 'controls' for the current slide
       //  This will be used in order to attach events on the two buttons on each
       //  control div, and was originally required to be able to update
       //  the inner span ie. '1 of 6' where slides weren't yet loaded     
        
        function GetControlDiv(currentIndex)
        {
             var slideDiv = document.getElementById(GetSlideId(currentIndex));
                    
             if (!slideDiv)
                return;
             else
             {  
               var div;
               for(var divIndex=0 ;divIndex< slideDiv.childNodes.length,div=slideDiv.childNodes[1].childNodes[divIndex];divIndex++)
                  if (div.tagName)                  
                     if (div.tagName=='DIV' && div.className=='controls')
                        return div;
             }
             
             return null;               
        
        }
           
        //-------------------------------------------------------------------------------
        // Returns an element with a given tag and/or class within another element 
        // Typically used to retrieve a reference to the back and next buttons or the
        // span within one of the 'controls' divs.
         
        function GetControlElement(parentElement,tagName, className)
        {
            var element;
            for(var elementIndex=0;elementIndex<parentElement.childNodes.length, element=parentElement.childNodes[elementIndex];elementIndex++)
            {
                if(element.tagName)
                    if (element.tagName==tagName && !className)
                    {                       
                        return element;
                    }
                    else if (element.tagName==tagName && element.className==className)
                    {
                        return element;
                    }
            }
        
        }
}
