/*
 * jQuery dragscrollable Plugin
 * version: 1.0 (25-Jun-2009)
 * Copyright (c) 2009 Miquel Herrera
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 */
;(function($) { // secure $ jQuery alias

    /**
    * Adds the ability to manage elements scroll by dragging
    * one or more of its descendant elements. Options parameter
    * allow to specifically select which inner elements will
    * respond to the drag events.
    * 
    * options properties:
    * ------------------------------------------------------------------------		
    *  dragSelector         | jquery selector to apply to each wrapped element 
    *                       | to find which will be the dragging elements. 
    *                       | Defaults to '>:first' which is the first child of 
    *                       | scrollable element
    * ------------------------------------------------------------------------		
    *  acceptPropagatedEvent| Will the dragging element accept propagated 
    *	                     | events? default is yes, a propagated mouse event 
    *	                     | on a inner element will be accepted and processed.
    *	                     | If set to false, only events originated on the
    *	                     | draggable elements will be processed.
    * ------------------------------------------------------------------------
    *  preventDefault       | Prevents the event to propagate further effectivey
    *                       | dissabling other default actions. Defaults to true
    * ------------------------------------------------------------------------
    *  
    *  usage examples:
    *
    *  To add the scroll by drag to the element id=viewport when dragging its 
    *  first child accepting any propagated events
    *	$('#viewport').dragscrollable(); 
    *
    *  To add the scroll by drag ability to any element div of class viewport
    *  when dragging its first descendant of class dragMe responding only to
    *  evcents originated on the '.dragMe' elements.
    *	$('div.viewport').dragscrollable({dragSelector:'.dragMe:first',
    *									  acceptPropagatedEvent: false});
    *
    *  Notice that some 'viewports' could be nested within others but events
    *  would not interfere as acceptPropagatedEvent is set to false.
    *		
    */
    $.fn.dragscrollable = function(options) {

        var settings = $.extend(
		{
		    dragSelector: '>:first',
		    acceptPropagatedEvent: true,
		    preventDefault: true
		}, options || {});


        var dragscroll = {
            mouseDownHandler: function(event) {
                // mousedown, left click, check propagation
                if (event.which != 1 ||
				(!event.data.acceptPropagatedEvent && event.target != this)) {
                    return false;
                }

                // Initial coordinates will be the last when dragging
                event.data.lastCoord = { left: event.clientX, top: event.clientY };

                //PY:
                window._dragscrollable = event.data.lastCoord;

                $.event.add(document, "mouseup",
						 dragscroll.mouseUpHandler, event.data);
                $.event.add(document, "mousemove",
						 dragscroll.mouseMoveHandler, event.data);
                if (event.data.preventDefault) {
                    event.preventDefault();
                    return false;
                }
            },
            mouseMoveHandler: function(event) { // User is dragging
                // How much did the mouse move?
                var delta = { left: (event.clientX - event.data.lastCoord.left),
                    top: (event.clientY - event.data.lastCoord.top)
                };

                // Set the scroll position relative to what ever the scroll is now
                event.data.scrollable.scrollLeft(
							event.data.scrollable.scrollLeft() - delta.left);
                event.data.scrollable.scrollTop(
							event.data.scrollable.scrollTop() - delta.top);

                // Save where the cursor is
                event.data.lastCoord = { left: event.clientX, top: event.clientY }
                if (event.data.preventDefault) {
                    event.preventDefault();
                    return false;
                }

            },
            mouseUpHandler: function(event) { // Stop scrolling

                //PY:
                var delta = { 
                    left: (event.clientX - window._dragscrollable.left),
                    top: (event.clientY - window._dragscrollable.top)
                };
                if (Math.pow(delta.left, 2) + Math.pow(delta.top, 2) > 25) {
                    window._dragscrollableWasScrolling = true;
                } else {
                    window._dragscrollableWasScrolling = false;
                }

                $.event.remove(document, "mousemove", dragscroll.mouseMoveHandler);
                $.event.remove(document, "mouseup", dragscroll.mouseUpHandler);
                if (event.data.preventDefault) {
                    event.preventDefault();
                    return false;
                }
            }
        }

        // set up the initial events
        this.each(function() {
            // closure object data for each scrollable element
            var data = { scrollable: $(this),
                acceptPropagatedEvent: settings.acceptPropagatedEvent,
                preventDefault: settings.preventDefault
            }
            // Set mouse initiating event on the desired descendant
            $(this).find(settings.dragSelector).
						bind('mousedown', data, dragscroll.mouseDownHandler);
        });
    }; //end plugin dragscrollable

})(jQuery);     // confine scope

