/**
 * Draggable - jQuery 拖拽组件
 * @Copyright 	: Copyright 2011, phpwind.com
 * @Descript	: 拖拽功能组件
 * @Author		: chaoren1641@gmail.com, wengqianshan@me.com
 * @Depend		: jquery.js(1.7 or later)
 * 
 * ==================== 使用方法 ====================
 * 
 * 1. 基础用法 - 使元素可拖拽
 *    HTML:
 *    <div id="dragBox" style="width: 200px; height: 200px; background: #ccc;">
 *        <div class="handle" style="height: 30px; background: #999;">拖拽手柄</div>
 *        <div>内容区域</div>
 *    </div>
 *    
 *    JavaScript:
 *    $('#dragBox').draggable({
 *        handle: '.handle'  // 指定拖拽手柄
 *    });
 * 
 * 2. 限制拖拽范围（默认限制在可视区域内）
 *    $('#dragBox').draggable({
 *        handle: '.handle',
 *        limit: true  // 限制不超出窗口边界（默认）
 *    });
 * 
 * 3. 不限制拖拽范围
 *    $('#dragBox').draggable({
 *        handle: '.handle',
 *        limit: false  // 可以拖拽到窗口外部
 *    });
 * 
 * 4. 拖拽回调函数
 *    $('#dragBox').draggable({
 *        handle: '.handle',
 *        mousedown: function(element) {
 *            // 鼠标按下时触发
 *            console.log('开始拖拽', element);
 *        },
 *        mousemove: function(element, left, top) {
 *            // 拖拽过程中触发
 *            console.log('拖拽中', left, top);
 *        },
 *        mouseup: function(element) {
 *            // 鼠标释放时触发
 *            console.log('结束拖拽', element);
 *        }
 *    });
 * 
 * 5. 模态框拖拽示例
 *    HTML:
 *    <div id="modal" style="position: fixed; width: 400px; height: 300px;">
 *        <div class="modal-header" style="cursor: move;">标题栏</div>
 *        <div class="modal-body">内容</div>
 *    </div>
 *    
 *    JavaScript:
 *    $('#modal').draggable({
 *        handle: '.modal-header'
 *    });
 * 
 * 6. 动态创建的元素拖拽
 *    // 对于动态添加的元素，需要重新初始化
 *    $('<div id="newBox"><span class="handle">拖我</span></div>')
 *        .appendTo('body')
 *        .draggable({ handle: '.handle' });
 * 
 * ==================== 配置参数 ====================
 * 
 * @param {string} handle       - 拖拽手柄选择器（默认: '.handle'）
 * @param {boolean} limit       - 是否限制在可视区域内（默认: true）
 * @param {function} mousedown  - 鼠标按下回调（可选）
 * @param {function} mousemove  - 拖拽中回调（可选）
 * @param {function} mouseup    - 鼠标释放回调（可选）
 * 
 * ==================== 注意事项 ====================
 * 
 * 1. 被拖拽元素需要有 position: absolute 或 position: fixed
 * 2. 如果没有指定 handle，整个元素都可以拖拽
 * 3. 拖拽手柄需要有 cursor: move 样式提示用户可拖拽
 * 4. 按 ESC 键可以停止拖拽
 * 
 * ==================== 浏览器兼容性 ====================
 * 
 * - Chrome 所有版本
 * - Firefox 所有版本
 * - Safari 所有版本
 * - Edge 所有版本
 * 
 */
;(function ( $, window, document, undefined ) {
    var pluginName = 'draggable';
    var defaults = {
		handle	: '.handle',	// 要拖拽的手柄
		limit	: true
    };
	var lastMouseX,lastMouseY;

	//当前窗口内捕获鼠标操作

    function getMousePosition(e) {
		var posx = 0,
			posy = 0,
			db = document.body,
			dd = document.documentElement,
			e = e || window.event;

		if (e.pageX || e.pageY) {
			posx = e.pageX;
			posy = e.pageY;
		}
		else if (e.clientX || e.clientY) {
			posx = e.clientX + db.scrollLeft + dd.scrollLeft;
			posy = e.clientY + db.scrollTop  + dd.scrollTop;
		}
		return { 'x': posx, 'y': posy };
	}

	function Plugin(element,options) {
        this.element = element;
        this.options = $.extend( {}, defaults, options) ;
        this.handle = element.find(options.handle);
        this.init();
	}

    Plugin.prototype.init = function() {

    	var handle = this.handle,
    		options = this.options,
    		element = this.element,
    		winWidth,
			winHeight,
			docScrollTop = 0,
			docScrollLeft = 0,
    		POS_X = 0,
    		POS_Y = 0,
    		elemHeight = element.outerHeight(),
    		elemWidth = element.outerWidth();
    	handle.css({cursor:'move'});
    var el = $(document);
        handle.on('mousedown',function(e) {
        	 if(options.mousedown) {
		         options.mousedown(element);
		        }
        	e.preventDefault();

        	//获取窗口尺寸和滚动条状态
		    winWidth = $(window).width();
		    winHeight = $(window).height();
		    docScrollTop = $(document).scrollTop();
		    docScrollLeft = $(document).scrollLeft();

        	//获取鼠标的初始偏移值
		    var offset = element.offset();
		    var mousePostion = getMousePosition(e);
		    //记录鼠标相对窗口的位置偏移
		    if(element.css('position') === 'fixed'){
		    	POS_X = mousePostion.x - offset.left + docScrollLeft;
		    	POS_Y = mousePostion.y - offset.top + docScrollTop;
		    }else{
		    	POS_X = mousePostion.x - offset.left;
		    	POS_Y = mousePostion.y - offset.top;
		    }

		    el.on('mousemove',function(e) {
		    	e.preventDefault();
		    	window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
		    	//获取鼠标位置、窗口目标位置和移动范围
	        	var mousePostion = getMousePosition(e),
	            	mouseY = mousePostion.y,
	            	mouseX = mousePostion.x,
		            currentLeft = mouseX - POS_X,
		            currentTop = mouseY - POS_Y;

			    //限制弹窗可移动范围，默认不超出可视区域
				if(options.limit){
					var maxLeft = winWidth - elemWidth + docScrollLeft,
			        	maxTop = winHeight - elemHeight + docScrollTop;
			        if(currentLeft < docScrollLeft){
			        	currentLeft = docScrollLeft;
			        }
			        if(currentTop < docScrollTop){
			        	currentTop = docScrollTop;
			        }
			        if(currentLeft > maxLeft){
			        	currentLeft = maxLeft;
			        }
			        if(currentTop > maxTop){
			        	currentTop = maxTop;
			        }
		        }
		        //设置窗口位置
		        element.css({ left : currentLeft + "px", top : currentTop + "px" });
		        if(options.mousemove) {
		        	options.mousemove(element, left, top);
		        }
       		}).on('mouseup.d keydown',function (e) {
    			//ESC停止拖拽
    			if(e.type === 'keydown' && e.keyCode !== 27) {
    				return;
    			}
            $(el).off('mousemove').off('mouseup.d');
            if(options.mouseup) {
	        	options.mouseup(element);
	        }
		});
        });
	}

    $.fn[pluginName] = Wind[pluginName]= function ( options ) {
        return this.each(function () {
            if (!$.data(this, 'plugin_' + pluginName)) {
                $.data(this, 'plugin_' + pluginName, new Plugin( $(this), options ));
            }
        });
    }

})( jQuery, window, document );
