﻿/**
* jQuery.smoothDivScroll - Smooth div scrolling using jQuery.
* This plugin is for turning a set of DIV's into a smooth scrolling area.
*
* Copyright (c) 2009 Thomas Kahn - thomas.kahn(at)karnhuset(dot)net
*
* This plugin is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This plugin is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details. <http://www.gnu.org/licenses/>.
*
* Date: 2009-03-30
* @author Thomas Kahn
* @version 0.7
*
* Changelog
* ---------------------------------------------
* 0.7.1 - Updated CSS for better browser compatibility.
*
* 0.7   - Added support for autoscrolling after the page has loaded.
*         Added support for making the hot spots visible at start for X number of seconds
*         or visible all the time.
*
* 0.6   - First version.
*/

(function($) {
    jQuery.fn.smoothDivScroll = function(options){

        var defaults = {
        scrollingHotSpotLeft: "div.scrollingHotSpotLeft", // The hot spot that triggers scrolling left
        scrollingHotSpotRight: "div.scrollingHotSpotRight", // The hot spot that triggers scrolling right
        scrollWrapper: "div.scrollWrapper", // The wrapper element that surrounds the scrollable area
        scrollableArea: "div.scrollableArea", // The actual element that is scrolled left or right
        hiddenOnStart: false, // True or false. Determines whether the element should be visible or hidden on start
        ajaxContentURL: "", // Optional. If supplied, content is fetched through AJAX using the supplied URL
        countOnlyClass: "", // Optional. If supplied, the function that calculates the width of the scrollable area will only count elements of this class
        mouseDownSpeedBooster: 1, // 1 is normal speed (no speed boost), 2 is twice as fast, 3 is three times as fast, and so on
        autoScrollOnStart: true, // True or false. Determines if scrolling right should start automatically after the page has loaded . The scrollable area will keep on scrolling until the user moves the mouse over the left or right hot spot
        autoScrollSpeed: 1, //  1-2 = slow, 3-4 = medium, 5-13 = fast -- anything higher = superfast
        visibleHotSpots: "", // Optional. Leave it blank for invisible hot spots. Otherwise use the values onstart or always. Onstart makes the hot spots visible for X-number of seconds after tha page has loaded and then they become invisible. Always is for making them visible all the time.
        hotSpotsVisibleTime: 5 // If you have selected onstart, you set the number of seconds that you want the hot spots to be visible. After this time they will become invisible again.
        };

        var turn = true; /* 往復フラグ true:left false:right*/

        options = $.extend(defaults, options);

        /* Identify global variables so JSLint won't raise errors when verifying the code */
        /*global autoScrollInterval, autoScrollRight, clearInterval, doScrollLeft, doScrollRight, hideHotSpotBackgrounds, hideHotSpotBackgroundsInterval, hideLeftHotSpot, hideRightHotSpot, jQuery, makeHotSpotBackgroundsVisible, setHotSpotHeightForIE, setInterval, showHideHotSpots, window, windowIsResized */


        // Iterate and reformat each matched element
        return this.each(function() {

            // Create a variable for the current "mother element"
            var $mom = $(this);

            // Load the content of the scrollable area using the optional URL.
            // If no ajaxContentURL is supplied, we assume that the content of
            // the scrolling area is already in place.
            if(options.ajaxContentURL.length !== 0){
                $mom.scrollableAreaWidth = 0;
                $mom.find(options.scrollableArea).load((options.ajaxContentURL), function(){
                    $mom.find(options.scrollableArea).children((options.countOnlyClass)).each(function() {
                        $mom.scrollableAreaWidth = $mom.scrollableAreaWidth + $(this).outerWidth(true);
                    });

                    // Set the width of the scrollable area
                    $mom.find(options.scrollableArea).css("width", ($mom.scrollableAreaWidth + "px"));

                    // Hide the mother element if it shouldn't be visible on start
                    if(options.hiddenOnStart) {
                        $mom.hide();
                    }

                    windowIsResized();

                    setHotSpotHeightForIE();
                });
            }

            // Some variables used for working with the scrolling
            var scrollXpos;
            var booster;

            // The left offset of the container on which you place
            // the scrolling behavior.
            // This offset is used when calculating the mouse x-position
            // in relation to scroll hot spots
            var motherElementOffset = $mom.offset().left;

            // A variable used for storing the current hot spot width.
            // It is used when calculating the scroll speed
            var hotSpotWidth = 0;

            // Set the booster value to normal (doesn't change until the user
            // holds down the mouse button over one of the hot spots)
            booster = 0.3;

            // Stuff to do once on load
            $(window).one("load",function(){
                // If the content of the scrolling area is not loaded through ajax,
                // we assume it's already there and can run the code to calculate
                // the width of the scrolling area, resize it to that width
                if(options.ajaxContentURL.length === 0) {
                    $mom.scrollableAreaWidth = 0;
                    $mom.find(options.scrollableArea).children((options.countOnlyClass)).each(function() {
                        $mom.scrollableAreaWidth = $mom.scrollableAreaWidth + $(this).outerWidth(true);
                    });

                    $mom.find(options.scrollableArea).css("width", $mom.scrollableAreaWidth + "px");

                    if(options.hiddenOnStart) {
                        $mom.hide();
                    }
                }

                // If the user has set the option autoScrollOnStart, the scollable area will
                // start scrolling automatically
                if(options.autoScrollOnStart)
                {
                    autoScrollInterval = setInterval(autoScrollRight, 15);
                }

                // If the user wants to have visible hot spots, here is where it's taken care of
                switch(options.visibleHotSpots)
                {
                    case "always":
                        makeHotSpotBackgroundsVisible();
                        break;
                    case "onstart":
                        makeHotSpotBackgroundsVisible();
                        hideHotSpotBackgroundsInterval = setInterval(hideHotSpotBackgrounds, (options.hotSpotsVisibleTime * 1000));
                        break;
                    default:
                        break;
                }

            });

            // If autoScrollOnStart is on, here's where it's stopped
            // when the user positions the mouse over one of the hot spots
            $mom.find(options.scrollingHotSpotRight).one('mouseover',function(){
                if(options.autoScrollOnStart)
                {
                    turn=false;
                    clearInterval(autoScrollInterval);
                }
            });

            $mom.find(options.scrollingHotSpotLeft).one('mouseover',function(){
                if(options.autoScrollOnStart)
                {
                    turn=true;
                    clearInterval(autoScrollInterval);
                }
            });

            // Function for making the hot spot background visible
            function makeHotSpotBackgroundsVisible()
            {
                // Alter the CSS (SmoothDivScroll.css) if you want to customize
                // the look'n'feel of the visible hot spots

                // The left hot spot
                $mom.find(options.scrollingHotSpotLeft).addClass("scrollingHotSpotLeftVisible");

                // The right hot spot
                $mom.find(options.scrollingHotSpotRight).addClass("scrollingHotSpotRightVisible");
            }

            // Hide the hot spot backgrounds.
            function hideHotSpotBackgrounds()
            {
                clearInterval(hideHotSpotBackgroundsInterval);

                // The left hot spot
                $mom.find(options.scrollingHotSpotLeft).fadeTo("slow", 0.0, function(){
                    $mom.find(options.scrollingHotSpotLeft).removeClass("scrollingHotSpotLeftVisible");
                });

                // The right hot spot
                $mom.find(options.scrollingHotSpotRight).fadeTo("slow", 0.0, function(){
                    $mom.find(options.scrollingHotSpotRight).removeClass("scrollingHotSpotRightVisible");
                });
            }

            // EVENT - window resize
            $(window).bind("resize",function(){
                windowIsResized();
            });

            // A function for doing the stuff that needs to be
            // done when the browser window is resized
            function windowIsResized()
            {
                // If the scrollable area is not hidden on start, reset and recalculate the
                // width of the scrollable area
                if(!(options.hiddenOnStart))
                {
                    $mom.scrollableAreaWidth = 0;
                    $mom.find(options.scrollableArea).children((options.countOnlyClass)).each(function() {
                        $mom.scrollableAreaWidth = $mom.scrollableAreaWidth + $(this).outerWidth(true);
                    });

                    $mom.find(options.scrollableArea).css("width", $mom.scrollableAreaWidth + 'px');
                }

                // Reset the left offset of the scroll wrapper
                $mom.find(options.scrollWrapper).scrollLeft("0");

                // Get the width of the page (body)
                var bodyWidth = $("body").innerWidth();

                // If the scrollable area is shorter than the current
                // window width, both scroll hot spots should be hidden.
                // Otherwise, check which hot spots should be shown.
                if($mom.scrollableAreaWidth < bodyWidth)
                {
                    hideLeftHotSpot();
                    hideRightHotSpot();
                }
                else
                {
                    showHideHotSpots();
                }
            }

            // HELPER FUNCTIONS FOR SHOWING AND HIDING HOT SPOTS
            function hideLeftHotSpot(){
                $mom.find(options.scrollingHotSpotLeft).hide();
            }

            function hideRightHotSpot(){
                $mom.find(options.scrollingHotSpotRight).hide();
            }

            function showLeftHotSpot(){
                $mom.find(options.scrollingHotSpotLeft).show();
                // Recalculate the hot spot width. Do it here because you can
                // be sure that the hot spot is visible and has a width
                if(hotSpotWidth <= 0)
                {
                    hotSpotWidth = $mom.find(options.scrollingHotSpotLeft).width();
                }
            }

            function showRightHotSpot(){
                $mom.find(options.scrollingHotSpotRight).show();
                // Recalculate the hot spot width. Do it here because you can
                // be sure that the hot spot is visible and has a width
                if(hotSpotWidth <= 0)
                {
                    hotSpotWidth = $mom.find(options.scrollingHotSpotRight).width();
                }
            }

            function setHotSpotHeightForIE()
            {
                // Some bugfixing for IE 6
                jQuery.each(jQuery.browser, function(i, val) {
                    if(i=="msie" && jQuery.browser.version.substr(0,1)=="6")
                    {
                        $mom.find(options.scrollingHotSpotLeft).css("height", ($mom.find(options.scrollableArea).innerHeight()));
                        $mom.find(options.scrollingHotSpotRight).css("height", ($mom.find(options.scrollableArea).innerHeight()));
                    }
                });
            }

            // EVENTS - scroll right
            var rightScrollInterval;

            $mom.find(options.scrollingHotSpotRight).bind('mousemove',function(e){
                var x = e.pageX - (this.offsetLeft + motherElementOffset);
                x = Math.round(x/(hotSpotWidth/15));
                scrollXpos = x;
            });

            // mouseover right hot spot
            $mom.find(options.scrollingHotSpotRight).bind('mouseover',function(e){
                if(options.autoScrollOnStart)
                {
                    clearInterval(autoScrollInterval);
                    turn=true;
                }
                rightScrollInterval = setInterval(doScrollRight, 15);
            });

            // mouseout right hot spot
            $mom.find(options.scrollingHotSpotRight).bind('mouseout',function(e){
                clearInterval(rightScrollInterval);

                scrollXpos = 0;

                if(options.autoScrollOnStart)
                {
                    autoScrollInterval = setInterval(autoScrollRight, 15);
                }

            });

            // scrolling speed booster right
            $mom.find(options.scrollingHotSpotRight).bind('mousedown',function(e){
                booster = options.mouseDownSpeedBooster;
            });

            // stop boosting the scrolling speed
            $("*").bind('mouseup',function(e){
                booster = 0.3;
            });

            // The function that does the actual scrolling right
            var doScrollRight = function()
            {
                $mom.find(options.scrollWrapper).scrollLeft($mom.find(options.scrollWrapper).scrollLeft() + (scrollXpos*booster));
                showHideHotSpots();
            };

            // The function that autoscrolls right
            var autoScrollRight = function()
            {
                if( turn == true )
                {
                    $mom.find(options.scrollWrapper).scrollLeft($mom.find(options.scrollWrapper).scrollLeft() + options.autoScrollSpeed);
                }
                else
                {
                    $mom.find(options.scrollWrapper).scrollLeft($mom.find(options.scrollWrapper).scrollLeft() - options.autoScrollSpeed);
                }

                if(($mom.scrollableAreaWidth) == ($mom.find(options.scrollWrapper).innerWidth() + $mom.find(options.scrollWrapper).scrollLeft()))
                {
                    turn=false;
                }
                else if(($mom.find(options.scrollWrapper).scrollLeft()) <= 0)
                {
                    turn=true;
                }

                showHideHotSpots();
            };

            // EVENTS - scroll left
            var leftScrollInterval;

            // mousemove left hot spot
            $mom.find(options.scrollingHotSpotLeft).bind('mousemove',function(e){
                var x = $mom.find(options.scrollingHotSpotLeft).innerWidth() - (e.pageX - motherElementOffset);
                x = Math.round(x/(hotSpotWidth/15));
                scrollXpos = x;
            });

            // mouseover left hot spot
            $mom.find(options.scrollingHotSpotLeft).bind('mouseover',function(e){
                if(options.autoScrollOnStart)
                {
                    clearInterval(autoScrollInterval);
                    turn=false;
                }
                leftScrollInterval = setInterval(doScrollLeft, 15);
            });

            // mouseout left hot spot
            $mom.find(options.scrollingHotSpotLeft).bind('mouseout',function(e){
                clearInterval(leftScrollInterval);

                scrollXpos = 0;

                if(options.autoScrollOnStart)
                {
                    autoScrollInterval = setInterval(autoScrollRight, 15);
                }
            });

            // scrolling speed booster left
            $mom.find(options.scrollingHotSpotLeft).bind('mousedown',function(e){
                booster = options.mouseDownSpeedBooster;
            });

            // The function that does the actual scrolling left
            var doScrollLeft = function()
            {
                $mom.find(options.scrollWrapper).scrollLeft($mom.find(options.scrollWrapper).scrollLeft() - (scrollXpos*booster));
                showHideHotSpots();
            };

            // Function for showing and hiding hot spots depending on the
            // offset of the scrolling
            function showHideHotSpots()
            {
                // When you can't scroll further left
                // the left scroll hot spot should be hidden
                // and the right hot spot visible
                if($mom.find(options.scrollWrapper).scrollLeft() === 0)
                {
                    hideLeftHotSpot();
                    showRightHotSpot();
                }
                // When you can't scroll further right
                // the right scroll hot spot should be hidden
                // and the left hot spot visible
                else if(($mom.scrollableAreaWidth) <= ($mom.find(options.scrollWrapper).innerWidth() + $mom.find(options.scrollWrapper).scrollLeft()))
                {
                    hideRightHotSpot();
                    showLeftHotSpot();
                }
                // If you are somewhere in the middle of your
                // scrolling, both hot spots should be visible
                else
                {
                    showRightHotSpot();
                    showLeftHotSpot();
                }

            }
    });
};

})(jQuery);

