1/* 2jQuery grab 3https://github.com/jussi-kalliokoski/jQuery.grab 4Ported from Jin.js::gestures 5https://github.com/jussi-kalliokoski/jin.js/ 6Created by Jussi Kalliokoski 7Licensed under MIT License. 8 9Includes fix for IE 10*/ 11 12 13(function($){ 14 var extend = $.extend, 15 mousedown = 'mousedown', 16 mousemove = 'mousemove', 17 mouseup = 'mouseup', 18 touchstart = 'touchstart', 19 touchmove = 'touchmove', 20 touchend = 'touchend', 21 touchcancel = 'touchcancel'; 22 23 function unbind(elem, type, func){ 24 if (type.substr(0,5) !== 'touch'){ // A temporary fix for IE8 data passing problem in Jin. 25 return $(elem).unbind(type, func); 26 } 27 var fnc, i; 28 for (i=0; i<bind._binds.length; i++){ 29 if (bind._binds[i].elem === elem && bind._binds[i].type === type && bind._binds[i].func === func){ 30 if (document.addEventListener){ 31 elem.removeEventListener(type, bind._binds[i].fnc, false); 32 } else { 33 elem.detachEvent('on'+type, bind._binds[i].fnc); 34 } 35 bind._binds.splice(i--, 1); 36 } 37 } 38 } 39 40 function bind(elem, type, func, pass){ 41 if (type.substr(0,5) !== 'touch'){ // A temporary fix for IE8 data passing problem in Jin. 42 return $(elem).bind(type, pass, func); 43 } 44 var fnc, i; 45 if (bind[type]){ 46 return bind[type].bind(elem, type, func, pass); 47 } 48 fnc = function(e){ 49 if (!e){ // Fix some ie bugs... 50 e = window.event; 51 } 52 if (!e.stopPropagation){ 53 e.stopPropagation = function(){ this.cancelBubble = true; }; 54 } 55 e.data = pass; 56 func.call(elem, e); 57 }; 58 if (document.addEventListener){ 59 elem.addEventListener(type, fnc, false); 60 } else { 61 elem.attachEvent('on' + type, fnc); 62 } 63 bind._binds.push({elem: elem, type: type, func: func, fnc: fnc}); 64 } 65 66 function grab(elem, options) 67 { 68 var data = { 69 move: {x: 0, y: 0}, 70 offset: {x: 0, y: 0}, 71 position: {x: 0, y: 0}, 72 start: {x: 0, y: 0}, 73 affects: document.documentElement, 74 stopPropagation: false, 75 preventDefault: true, 76 touch: true // Implementation unfinished, and doesn't support multitouch 77 }; 78 extend(data, options); 79 data.element = elem; 80 bind(elem, mousedown, mouseDown, data); 81 if (data.touch){ 82 bind(elem, touchstart, touchStart, data); 83 } 84 } 85 function ungrab(elem){ 86 unbind(elem, mousedown, mousedown); 87 } 88 function mouseDown(e){ 89 e.data.position.x = e.pageX; 90 e.data.position.y = e.pageY; 91 e.data.start.x = e.pageX; 92 e.data.start.y = e.pageY; 93 e.data.event = e; 94 if (e.data.onstart && e.data.onstart.call(e.data.element, e.data)){ 95 return; 96 } 97 if (e.preventDefault && e.data.preventDefault){ 98 e.preventDefault(); 99 } 100 if (e.stopPropagation && e.data.stopPropagation){ 101 e.stopPropagation(); 102 } 103 bind(e.data.affects, mousemove, mouseMove, e.data); 104 bind(e.data.affects, mouseup, mouseUp, e.data); 105 } 106 function mouseMove(e){ 107 if (e.preventDefault && e.data.preventDefault){ 108 e.preventDefault(); 109 } 110 if (e.stopPropagation && e.data.preventDefault){ 111 e.stopPropagation(); 112 } 113 e.data.move.x = e.pageX - e.data.position.x; 114 e.data.move.y = e.pageY - e.data.position.y; 115 e.data.position.x = e.pageX; 116 e.data.position.y = e.pageY; 117 e.data.offset.x = e.pageX - e.data.start.x; 118 e.data.offset.y = e.pageY - e.data.start.y; 119 e.data.event = e; 120 if (e.data.onmove){ 121 e.data.onmove.call(e.data.element, e.data); 122 } 123 } 124 function mouseUp(e){ 125 if (e.preventDefault && e.data.preventDefault){ 126 e.preventDefault(); 127 } 128 if (e.stopPropagation && e.data.stopPropagation){ 129 e.stopPropagation(); 130 } 131 unbind(e.data.affects, mousemove, mouseMove); 132 unbind(e.data.affects, mouseup, mouseUp); 133 e.data.event = e; 134 if (e.data.onfinish){ 135 e.data.onfinish.call(e.data.element, e.data); 136 } 137 } 138 function touchStart(e){ 139 e.data.position.x = e.touches[0].pageX; 140 e.data.position.y = e.touches[0].pageY; 141 e.data.start.x = e.touches[0].pageX; 142 e.data.start.y = e.touches[0].pageY; 143 e.data.event = e; 144 if (e.data.onstart && e.data.onstart.call(e.data.element, e.data)){ 145 return; 146 } 147 if (e.preventDefault && e.data.preventDefault){ 148 e.preventDefault(); 149 } 150 if (e.stopPropagation && e.data.stopPropagation){ 151 e.stopPropagation(); 152 } 153 bind(e.data.affects, touchmove, touchMove, e.data); 154 bind(e.data.affects, touchend, touchEnd, e.data); 155 } 156 function touchMove(e){ 157 if (e.preventDefault && e.data.preventDefault){ 158 e.preventDefault(); 159 } 160 if (e.stopPropagation && e.data.stopPropagation){ 161 e.stopPropagation(); 162 } 163 e.data.move.x = e.touches[0].pageX - e.data.position.x; 164 e.data.move.y = e.touches[0].pageY - e.data.position.y; 165 e.data.position.x = e.touches[0].pageX; 166 e.data.position.y = e.touches[0].pageY; 167 e.data.offset.x = e.touches[0].pageX - e.data.start.x; 168 e.data.offset.y = e.touches[0].pageY - e.data.start.y; 169 e.data.event = e; 170 if (e.data.onmove){ 171 e.data.onmove.call(e.data.elem, e.data); 172 } 173 } 174 function touchEnd(e){ 175 if (e.preventDefault && e.data.preventDefault){ 176 e.preventDefault(); 177 } 178 if (e.stopPropagation && e.data.stopPropagation){ 179 e.stopPropagation(); 180 } 181 unbind(e.data.affects, touchmove, touchMove); 182 unbind(e.data.affects, touchend, touchEnd); 183 e.data.event = e; 184 if (e.data.onfinish){ 185 e.data.onfinish.call(e.data.element, e.data); 186 } 187 } 188 189 bind._binds = []; 190 191 $.fn.grab = function(a, b){ 192 return this.each(function(){ 193 return grab(this, a, b); 194 }); 195 }; 196 $.fn.ungrab = function(a){ 197 return this.each(function(){ 198 return ungrab(this, a); 199 }); 200 }; 201})(jQuery);