/*! Touch Draggable - v0.0.1 - 2012-08-16 * https://github.com/royriojas/touch-draggable * Copyright (c) 2012 Roy Riojas; Licensed MIT, GPL */ ;(function ($, window) { var Modernizr = window.Modernizr; var r3m = { now : function () { var fn = Date.now; if (fn) { return Date.now(); } return (new Date()).getTime(); }, support : { pointerEnabled:!!window.navigator.msPointerEnabled, touch : Modernizr ? Modernizr.touch : ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch }, /** * debounce returns a new function than when called will * execute the function and prevent any other calls to be executed * if they happen inside the threshold * * This is useful to execute just the first call of a series of calls inside a * threshold * * @param {Function} f the function to debounce * @param {Integer} ms the number of miliseconds to wait. If any other call * is made before that theshold it will be discarded. * @param {Object} ctx the context on which this function will be executed * (the this object inside the function wil be set to this context) */ debounce: function(f, ms, ctx){ //just return the wrapper function return function(){ //if this is the first time of the sequence of calls to this function if (f.timer == null) { //store the original arguments used to call this function var args = arguments; //execute it inmediately (function () { //call the function with the ctx and the original arguments f.apply(ctx, args); //set the timer f.timer = setTimeout(function () { //to make sure the next set of calls will be executing the first call as soon as possible f.timer = null; }, ms || 1); })(); } }; }, /** * throttle returns a new function than when called will cancel any previous not executed * call reseting the timer again for a new period of time. * * This is usfeful to execute only the last call of a series of call within a time interval * * @param {Object} f * @param {Object} ms * @param {Object} ctx */ throttle: function(f, ms, ctx){ return function(){ var args = arguments; clearTimeout(f.timer); f.timer = setTimeout(function(){ f.timer = null; f.apply(ctx, args); }, ms || 0); } }, /** * define a namespace object * @param {Object} ns */ ns: function(ns){ if (!ns) return; var nsParts = ns.split("."); var root = window; for (var i = 0, len = nsParts.length; i < len; i++) { if (typeof root[nsParts[i]] == "undefined") { root[nsParts[i]] = {}; } root = root[nsParts[i]]; } return root; }, isNull : function (val) { return typeof val == "undefined" || val == null; }, /** * return a random number between a min and a max value */ rand : function() { var min, max, args = arguments; //if only one argument is provided we are expecting to have a value between 0 and max if (args.length == 1) { max = args[0]; min = 0; } //two arguments provided mean we are expecting to have a number between min and max if (args.length >= 2) { min = args[0]; max = args[1] if (min > max) { min = args[1]; max = args[0]; } } return min + Math.floor(Math.random() * (max - min)); } }; var touch = r3m.support.touch, pEnabled = r3m.support.pointerEnabled, isNull = r3m.isNull, b = $.browser, isWebkit = b.webkit, isMoz = b.mozilla; $.extend(r3m, { format : function () { var pattern = /\{(\d+)\}/g; //safer way to convert a pseudo array to an object array var args = Array.prototype.slice.call(arguments); var s = args.shift(); return s.replace(pattern, function(c, d) { var replacement = args[d] ; if (isNull(replacement)) { replacement = ""; } return replacement; }); }, pointer : { down : touch ? 'touchstart' : pEnabled ? 'MSPointerDown' : 'mousedown', move : touch ? 'touchmove' : pEnabled ? 'MSPointerMove' : 'mousemove', up : touch ? 'touchend' : pEnabled ? 'MSPointerUp' : 'mouseup', cancel : touch ? 'touchcancel' : 'MSPointerCancel', tap : touch ? 'click' : pEnabled ? 'MSGestureTap' : 'click' //consider including the tap special event from }, gesture : { start : touch ? 'gesturestart' : 'MSGestureStart', change : touch ? 'gesturechange' : 'MSGestureChange', end : touch ? 'gestureend' : 'MSGestureEnd' }, css : { //TODO find a better way to detect the name of the prefixed property transform : isWebkit ? '-webkit-transform' : isMoz ? '-moz-transform' : pEnabled ? '-ms-transform' : 'transform' }, transition : { end : isWebkit ? 'webkitTransitionEnd' : 'transitionend' }, animation : { end : isWebkit ? 'webkitAnimationEnd' : 'animationend' } }); window.r3m = r3m; })(jQuery, window); ;(function ($, r3m, window) { var touch = r3m.support.touch; var pEnabled = r3m.support.pointerEnabled; $.getOriginalEvent = function (e) { var evt = e.originalEvent; evt.preventDefault(); if (touch) { evt = evt.touches[0]; } if (pEnabled) { //TODO: investigate how to get the pointerList for the IE10 case return evt; } return evt; }; $.getTransformString = function (ele) { //TODO handle the IE10 case return window.getComputedStyle(ele).webkitTransform; }; $.getMatrix = function (transformString) { //TODO handle the IE10 case return new WebKitCSSMatrix(transformString); }; })(jQuery, window.r3m, window); ;(function($, r3m, window, undefined) { 'use strict'; var events = r3m.pointer, pDown = events.down, pUp = events.up, pMove = events.move, $doc = $(document), debounce = r3m.debounce, getOriginalEvent = $.getOriginalEvent, format = r3m.format, transformProp = r3m.css.transform, getTransformString = $.getTransformString, getMatrix = $.getMatrix, draggableInstance = 0, now = r3m.now; $.widget('r3m.touchDraggable', { /** * Creates the ui and initialize dependencies */ _create:function () { var me = this, $target = me.element; if ($target.length == 0) return; var opts = me.options, helper = opts.helper, curId = me.id = format('{0}_{1}', draggableInstance++, now()), instanceNS = me.instanceNS = format('.td_{0}', curId), ele = $target[0], addClasses = opts.addClasses && $.trim(opts.draggableClass) !== ''; addClasses && $target.addClass(opts.draggableClass); //borrowed from the original jquery ui draggable if (helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) { $target.css('position', 'relative'); } me._processPMove = debounce(me._processPMove,0, me); $target.on(format('{0}.touchdraggable',pDown), function (e) { me._processPDown(e, $target, ele, opts); $doc.on(format('{0}{1}', pMove, instanceNS),function (e) { me._processPMove(e, $target, ele, opts); }).on(format('{0}{1}', pUp, instanceNS), function (e) { me._processPUp(e, $target, ele, opts); $doc.off(instanceNS); }); }); }, _processPUp : function (e, $target, ele, opts) { var me = this, addClasses = opts.addClasses && $.trim(opts.draggingClass) !== ''; me.isDragging = false; me.lastX = null; me.lastY = null; if (me.dragHappen == true && me.startPosition) { var css = me.startPosition; console.log('startpos' , me.startPosition.left, me.startPosition.top); var transform = getTransformString(ele); var matrix, x, y; if (transform != 'none') { matrix = getMatrix(transform); x = matrix.e; y = matrix.f; } else { x = 0; y = 0; } css.left += x; css.top += y; if (css) { css[transformProp] = ''; $target.css(css); } me.startPosition = null; } me._trigger('stop', {}); if (me.firstMoveHappen) { me.firstMoveHappen = false; addClasses && $target.removeClass(opts.draggingClass); } me.dragHappen = false; }, _processPMove : function (e, $target,ele, opts) { var me = this, addClasses = opts.addClasses && $.trim(opts.draggingClass) !== ''; try { if (!me.isDragging) return; if (!ele) return; var evt = getOriginalEvent(e); me.x = evt.clientX; me.y = evt.clientY; var lastX = me.lastX || me.x, lastY = me.lastY || me.y, dx = lastX - me.x, dy = lastY - me.y; var transform = getTransformString(ele); var matrix, x, y; if (transform != 'none') { matrix = getMatrix(transform); matrix.e -= dx; matrix.f -= dy; x = matrix.e; y = matrix.f; } else { x = 0; y = 0; } $target.css(transformProp, format('translate3d({0}px,{1}px,0)', x, y)); me.lastX = me.x; me.lastY = me.y; me.dragHappen = true; if (!me.firstMoveHappen) { me.firstMoveHappen = true; addClasses && $target.addClass(opts.draggingClass); } me._trigger('drag', {}); } catch (e) { //console.error('move', e.message); } }, _processPDown : function (e, $target, ele, opts) { if (e.which > 1) return; var me = this, handle = $.trim(opts.handle); if (handle == '' || $(e.target).closest(handle).length > 0) { var style = ele.style; me.startPosition = $target.position(); if (!(/(fixed|absolute)/).test($target.css("position"))) { if ($.trim(style.top) === '') { me.startPosition = { top:0, left:0 }; } else { me.startPosition = { top: parseInt(style.top, 10), left: parseInt(style.left, 10) } } } $target.css(me.startPosition); me._trigger('start', {}); me.isDragging = true; e.stopPropagation(); } }, destroy:function () { this.element.off('.touchdraggable'); $doc.off(this.instanceNS); }, /* defaults */ options:{ handle : null, helper : 'original', addClasses : true, draggableClass : 'ui-draggable', draggingClass : 'ui-draggable-dragging' } }); })(jQuery, window.r3m, window);