| @@ -1,7 +1,7 @@ | ||
| 1 | -// jquery.event.move | |
| 1 | +// DOM.event.move | |
| 2 | 2 | // |
| 3 | -// 1.3.6 | |
| 3 | +// 2.0.1 | |
| 4 | 4 | // |
| 5 | 5 | // Stephen Band |
| 6 | 6 | // |
| 7 | 7 | // Triggers 'movestart', 'move' and 'moveend' events after |
| @@ -10,87 +10,143 @@ | ||
| 10 | 10 | // Move events are throttled to animation frames. Move event objects |
| 11 | 11 | // have the properties: |
| 12 | 12 | // |
| 13 | 13 | // pageX: |
| 14 | -// pageY: Page coordinates of pointer. | |
| 14 | +// pageY: Page coordinates of pointer. | |
| 15 | 15 | // startX: |
| 16 | -// startY: Page coordinates of pointer at movestart. | |
| 16 | +// startY: Page coordinates of pointer at movestart. | |
| 17 | 17 | // distX: |
| 18 | -// distY: Distance the pointer has moved since movestart. | |
| 18 | +// distY: Distance the pointer has moved since movestart. | |
| 19 | 19 | // deltaX: |
| 20 | -// deltaY: Distance the finger has moved since last event. | |
| 20 | +// deltaY: Distance the finger has moved since last event. | |
| 21 | 21 | // velocityX: |
| 22 | -// velocityY: Average velocity over last few events. | |
| 22 | +// velocityY: Average velocity over last few events. | |
| 23 | 23 | |
| 24 | 24 | |
| 25 | -(function (module) { | |
| 25 | +(function(fn) { | |
| 26 | 26 | if (typeof define === 'function' && define.amd) { |
| 27 | - // AMD. Register as an anonymous module. | |
| 28 | - define(['jquery'], module); | |
| 27 | + define([], fn); | |
| 28 | + } else if ((typeof module !== "undefined" && module !== null) && module.exports) { | |
| 29 | + module.exports = fn; | |
| 29 | 30 | } else { |
| 30 | - // Browser globals | |
| 31 | - module(jQuery); | |
| 31 | + fn(); | |
| 32 | 32 | } |
| 33 | -})(function(jQuery, undefined){ | |
| 33 | +})(function(){ | |
| 34 | + var assign = Object.assign || window.jQuery && jQuery.extend; | |
| 34 | 35 | |
| 35 | - var // Number of pixels a pressed pointer travels before movestart | |
| 36 | - // event is fired. | |
| 37 | - threshold = 6, | |
| 38 | - | |
| 39 | - add = jQuery.event.add, | |
| 40 | - | |
| 41 | - remove = jQuery.event.remove, | |
| 36 | + // Number of pixels a pressed pointer travels before movestart | |
| 37 | + // event is fired. | |
| 38 | + var threshold = 8; | |
| 42 | 39 | |
| 43 | - // Just sugar, so we can have arguments in the same order as | |
| 44 | - // add and remove. | |
| 45 | - trigger = function(node, type, data) { | |
| 46 | - jQuery.event.trigger(type, data, node); | |
| 47 | - }, | |
| 40 | + // Shim for requestAnimationFrame, falling back to timer. See: | |
| 41 | + // see http://paulirish.com/2011/requestanimationframe-for-smart-animating/ | |
| 42 | + var requestFrame = (function(){ | |
| 43 | + return ( | |
| 44 | + window.requestAnimationFrame || | |
| 45 | + window.webkitRequestAnimationFrame || | |
| 46 | + window.mozRequestAnimationFrame || | |
| 47 | + window.oRequestAnimationFrame || | |
| 48 | + window.msRequestAnimationFrame || | |
| 49 | + function(fn, element){ | |
| 50 | + return window.setTimeout(function(){ | |
| 51 | + fn(); | |
| 52 | + }, 25); | |
| 53 | + } | |
| 54 | + ); | |
| 55 | + })(); | |
| 48 | 56 | |
| 49 | - // Shim for requestAnimationFrame, falling back to timer. See: | |
| 50 | - // see http://paulirish.com/2011/requestanimationframe-for-smart-animating/ | |
| 51 | - requestFrame = (function(){ | |
| 52 | - return ( | |
| 53 | - window.requestAnimationFrame || | |
| 54 | - window.webkitRequestAnimationFrame || | |
| 55 | - window.mozRequestAnimationFrame || | |
| 56 | - window.oRequestAnimationFrame || | |
| 57 | - window.msRequestAnimationFrame || | |
| 58 | - function(fn, element){ | |
| 59 | - return window.setTimeout(function(){ | |
| 60 | - fn(); | |
| 61 | - }, 25); | |
| 62 | - } | |
| 63 | - ); | |
| 64 | - })(), | |
| 65 | - | |
| 66 | - ignoreTags = { | |
| 67 | - textarea: true, | |
| 68 | - input: true, | |
| 69 | - select: true, | |
| 70 | - button: true | |
| 71 | - }, | |
| 72 | - | |
| 73 | - mouseevents = { | |
| 74 | - move: 'mousemove', | |
| 75 | - cancel: 'mouseup dragstart', | |
| 76 | - end: 'mouseup' | |
| 77 | - }, | |
| 78 | - | |
| 79 | - touchevents = { | |
| 80 | - move: 'touchmove', | |
| 81 | - cancel: 'touchend', | |
| 82 | - end: 'touchend' | |
| 83 | - }; | |
| 57 | + var ignoreTags = { | |
| 58 | + textarea: true, | |
| 59 | + input: true, | |
| 60 | + select: true, | |
| 61 | + button: true | |
| 62 | + }; | |
| 84 | 63 | |
| 64 | + var mouseevents = { | |
| 65 | + move: 'mousemove', | |
| 66 | + cancel: 'mouseup dragstart', | |
| 67 | + end: 'mouseup' | |
| 68 | + }; | |
| 85 | 69 | |
| 70 | + var touchevents = { | |
| 71 | + move: 'touchmove', | |
| 72 | + cancel: 'touchend', | |
| 73 | + end: 'touchend' | |
| 74 | + }; | |
| 75 | + | |
| 76 | + var rspaces = /\s+/; | |
| 77 | + | |
| 78 | + | |
| 79 | + // DOM Events | |
| 80 | + | |
| 81 | + var eventOptions = { bubbles: true, cancelable: true }; | |
| 82 | + | |
| 83 | + var eventsSymbol = Symbol('events'); | |
| 84 | + | |
| 85 | + function createEvent(type) { | |
| 86 | + return new CustomEvent(type, eventOptions); | |
| 87 | + } | |
| 88 | + | |
| 89 | + function getEvents(node) { | |
| 90 | + return node[eventsSymbol] || (node[eventsSymbol] = {}); | |
| 91 | + } | |
| 92 | + | |
| 93 | + function on(node, types, fn, data, selector) { | |
| 94 | + types = types.split(rspaces); | |
| 95 | + | |
| 96 | + var events = getEvents(node); | |
| 97 | + var i = types.length; | |
| 98 | + var handlers, type; | |
| 99 | + | |
| 100 | + function handler(e) { fn(e, data); } | |
| 101 | + | |
| 102 | + while (i--) { | |
| 103 | + type = types[i]; | |
| 104 | + handlers = events[type] || (events[type] = []); | |
| 105 | + handlers.push([fn, handler]); | |
| 106 | + node.addEventListener(type, handler); | |
| 107 | + } | |
| 108 | + } | |
| 109 | + | |
| 110 | + function off(node, types, fn, selector) { | |
| 111 | + types = types.split(rspaces); | |
| 112 | + | |
| 113 | + var events = getEvents(node); | |
| 114 | + var i = types.length; | |
| 115 | + var type, handlers, k; | |
| 116 | + | |
| 117 | + if (!events) { return; } | |
| 118 | + | |
| 119 | + while (i--) { | |
| 120 | + type = types[i]; | |
| 121 | + handlers = events[type]; | |
| 122 | + if (!handlers) { continue; } | |
| 123 | + k = handlers.length; | |
| 124 | + while (k--) { | |
| 125 | + if (handlers[k][0] === fn) { | |
| 126 | + node.removeEventListener(type, handlers[k][1]); | |
| 127 | + handlers.splice(k, 1); | |
| 128 | + } | |
| 129 | + } | |
| 130 | + } | |
| 131 | + } | |
| 132 | + | |
| 133 | + function trigger(node, type, properties) { | |
| 134 | + // Don't cache events. It prevents you from triggering an event of a | |
| 135 | + // given type from inside the handler of another event of that type. | |
| 136 | + var event = createEvent(type); | |
| 137 | + if (properties) { assign(event, properties); } | |
| 138 | + node.dispatchEvent(event); | |
| 139 | + } | |
| 140 | + | |
| 141 | + | |
| 86 | 142 | // Constructors |
| 87 | - | |
| 143 | + | |
| 88 | 144 | function Timer(fn){ |
| 89 | 145 | var callback = fn, |
| 90 | 146 | active = false, |
| 91 | 147 | running = false; |
| 92 | - | |
| 148 | + | |
| 93 | 149 | function trigger(time) { |
| 94 | 150 | if (active){ |
| 95 | 151 | callback(); |
| 96 | 152 | requestFrame(trigger); |
| @@ -100,19 +156,19 @@ | ||
| 100 | 156 | else { |
| 101 | 157 | running = false; |
| 102 | 158 | } |
| 103 | 159 | } |
| 104 | - | |
| 160 | + | |
| 105 | 161 | this.kick = function(fn) { |
| 106 | 162 | active = true; |
| 107 | 163 | if (!running) { trigger(); } |
| 108 | 164 | }; |
| 109 | - | |
| 165 | + | |
| 110 | 166 | this.end = function(fn) { |
| 111 | 167 | var cb = callback; |
| 112 | - | |
| 168 | + | |
| 113 | 169 | if (!fn) { return; } |
| 114 | - | |
| 170 | + | |
| 115 | 171 | // If the timer is not running, simply call the end callback. |
| 116 | 172 | if (!running) { |
| 117 | 173 | fn(); |
| 118 | 174 | } |
| @@ -120,11 +176,11 @@ | ||
| 120 | 176 | // queue up the current callback and the end callback, otherwise |
| 121 | 177 | // just the end callback. |
| 122 | 178 | else { |
| 123 | 179 | callback = active ? |
| 124 | - function(){ cb(); fn(); } : | |
| 180 | + function(){ cb(); fn(); } : | |
| 125 | 181 | fn ; |
| 126 | - | |
| 182 | + | |
| 127 | 183 | active = true; |
| 128 | 184 | } |
| 129 | 185 | }; |
| 130 | 186 | } |
| @@ -130,29 +186,20 @@ | ||
| 130 | 186 | } |
| 131 | 187 | |
| 132 | 188 | |
| 133 | 189 | // Functions |
| 134 | - | |
| 135 | - function returnTrue() { | |
| 136 | - return true; | |
| 137 | - } | |
| 138 | - | |
| 139 | - function returnFalse() { | |
| 140 | - return false; | |
| 141 | - } | |
| 142 | - | |
| 190 | + | |
| 191 | + function noop() {} | |
| 192 | + | |
| 143 | 193 | function preventDefault(e) { |
| 144 | 194 | e.preventDefault(); |
| 145 | 195 | } |
| 146 | - | |
| 147 | - function preventIgnoreTags(e) { | |
| 148 | - // Don't prevent interaction with form elements. | |
| 149 | - if (ignoreTags[ e.target.tagName.toLowerCase() ]) { return; } | |
| 150 | - | |
| 151 | - e.preventDefault(); | |
| 196 | + | |
| 197 | + function isIgnoreTag(e) { | |
| 198 | + return !!ignoreTags[e.target.tagName.toLowerCase()]; | |
| 152 | 199 | } |
| 153 | 200 | |
| 154 | - function isLeftButton(e) { | |
| 201 | + function isPrimaryButton(e) { | |
| 155 | 202 | // Ignore mousedowns on any button other than the left (or primary) |
| 156 | 203 | // mouse button, or when a modifier key is pressed. |
| 157 | 204 | return (e.which === 1 && !e.ctrlKey && !e.altKey); |
| 158 | 205 | } |
| @@ -162,15 +209,15 @@ | ||
| 162 | 209 | |
| 163 | 210 | if (touchList.identifiedTouch) { |
| 164 | 211 | return touchList.identifiedTouch(id); |
| 165 | 212 | } |
| 166 | - | |
| 213 | + | |
| 167 | 214 | // touchList.identifiedTouch() does not exist in |
| 168 | 215 | // webkit yet… we must do the search ourselves... |
| 169 | - | |
| 216 | + | |
| 170 | 217 | i = -1; |
| 171 | 218 | l = touchList.length; |
| 172 | - | |
| 219 | + | |
| 173 | 220 | while (++i < l) { |
| 174 | 221 | if (touchList[i].identifier === id) { |
| 175 | 222 | return touchList[i]; |
| 176 | 223 | } |
| @@ -176,10 +223,10 @@ | ||
| 176 | 223 | } |
| 177 | 224 | } |
| 178 | 225 | } |
| 179 | 226 | |
| 180 | - function changedTouch(e, event) { | |
| 181 | - var touch = identifiedTouch(e.changedTouches, event.identifier); | |
| 227 | + function changedTouch(e, data) { | |
| 228 | + var touch = identifiedTouch(e.changedTouches, data.identifier); | |
| 182 | 229 | |
| 183 | 230 | // This isn't the touch you're looking for. |
| 184 | 231 | if (!touch) { return; } |
| 185 | 232 | |
| @@ -185,9 +232,9 @@ | ||
| 185 | 232 | |
| 186 | 233 | // Chrome Android (at least) includes touches that have not |
| 187 | 234 | // changed in e.changedTouches. That's a bit annoying. Check |
| 188 | 235 | // that this touch has changed. |
| 189 | - if (touch.pageX === event.pageX && touch.pageY === event.pageY) { return; } | |
| 236 | + if (touch.pageX === data.pageX && touch.pageY === data.pageY) { return; } | |
| 190 | 237 | |
| 191 | 238 | return touch; |
| 192 | 239 | } |
| 193 | 240 | |
| @@ -192,187 +239,159 @@ | ||
| 192 | 239 | } |
| 193 | 240 | |
| 194 | 241 | |
| 195 | 242 | // Handlers that decide when the first movestart is triggered |
| 196 | - | |
| 243 | + | |
| 197 | 244 | function mousedown(e){ |
| 198 | - var data; | |
| 245 | + // Ignore non-primary buttons | |
| 246 | + if (!isPrimaryButton(e)) { return; } | |
| 199 | 247 | |
| 200 | - if (!isLeftButton(e)) { return; } | |
| 248 | + // Ignore form and interactive elements | |
| 249 | + if (isIgnoreTag(e)) { return; } | |
| 201 | 250 | |
| 202 | - data = { | |
| 203 | - target: e.target, | |
| 204 | - startX: e.pageX, | |
| 205 | - startY: e.pageY, | |
| 206 | - timeStamp: e.timeStamp | |
| 207 | - }; | |
| 208 | - | |
| 209 | - add(document, mouseevents.move, mousemove, data); | |
| 210 | - add(document, mouseevents.cancel, mouseend, data); | |
| 251 | + on(document, mouseevents.move, mousemove, e); | |
| 252 | + on(document, mouseevents.cancel, mouseend, e); | |
| 211 | 253 | } |
| 212 | 254 | |
| 213 | - function mousemove(e){ | |
| 214 | - var data = e.data; | |
| 215 | - | |
| 255 | + function mousemove(e, data){ | |
| 216 | 256 | checkThreshold(e, data, e, removeMouse); |
| 217 | 257 | } |
| 218 | 258 | |
| 219 | - function mouseend(e) { | |
| 259 | + function mouseend(e, data) { | |
| 220 | 260 | removeMouse(); |
| 221 | 261 | } |
| 222 | 262 | |
| 223 | 263 | function removeMouse() { |
| 224 | - remove(document, mouseevents.move, mousemove); | |
| 225 | - remove(document, mouseevents.cancel, mouseend); | |
| 264 | + off(document, mouseevents.move, mousemove); | |
| 265 | + off(document, mouseevents.cancel, mouseend); | |
| 226 | 266 | } |
| 227 | 267 | |
| 228 | 268 | function touchstart(e) { |
| 229 | - var touch, template; | |
| 269 | + // Don't get in the way of interaction with form elements | |
| 270 | + if (ignoreTags[e.target.tagName.toLowerCase()]) { return; } | |
| 230 | 271 | |
| 231 | - // Don't get in the way of interaction with form elements. | |
| 232 | - if (ignoreTags[ e.target.tagName.toLowerCase() ]) { return; } | |
| 272 | + var touch = e.changedTouches[0]; | |
| 233 | 273 | |
| 234 | - touch = e.changedTouches[0]; | |
| 235 | - | |
| 236 | 274 | // iOS live updates the touch objects whereas Android gives us copies. |
| 237 | 275 | // That means we can't trust the touchstart object to stay the same, |
| 238 | 276 | // so we must copy the data. This object acts as a template for |
| 239 | 277 | // movestart, move and moveend event objects. |
| 240 | - template = { | |
| 241 | - target: touch.target, | |
| 242 | - startX: touch.pageX, | |
| 243 | - startY: touch.pageY, | |
| 244 | - timeStamp: e.timeStamp, | |
| 245 | - identifier: touch.identifier | |
| 278 | + var data = { | |
| 279 | + target: touch.target, | |
| 280 | + pageX: touch.pageX, | |
| 281 | + pageY: touch.pageY, | |
| 282 | + identifier: touch.identifier, | |
| 283 | + | |
| 284 | + // The only way to make handlers individually unbindable is by | |
| 285 | + // making them unique. | |
| 286 | + touchmove: function(e, data) { touchmove(e, data); }, | |
| 287 | + touchend: function(e, data) { touchend(e, data); } | |
| 246 | 288 | }; |
| 247 | 289 | |
| 248 | - // Use the touch identifier as a namespace, so that we can later | |
| 249 | - // remove handlers pertaining only to this touch. | |
| 250 | - add(document, touchevents.move + '.' + touch.identifier, touchmove, template); | |
| 251 | - add(document, touchevents.cancel + '.' + touch.identifier, touchend, template); | |
| 290 | + on(document, touchevents.move, data.touchmove, data); | |
| 291 | + on(document, touchevents.cancel, data.touchend, data); | |
| 252 | 292 | } |
| 253 | 293 | |
| 254 | - function touchmove(e){ | |
| 255 | - var data = e.data, | |
| 256 | - touch = changedTouch(e, data); | |
| 257 | - | |
| 294 | + function touchmove(e, data) { | |
| 295 | + var touch = changedTouch(e, data); | |
| 258 | 296 | if (!touch) { return; } |
| 259 | - | |
| 260 | 297 | checkThreshold(e, data, touch, removeTouch); |
| 261 | 298 | } |
| 262 | 299 | |
| 263 | - function touchend(e) { | |
| 264 | - var template = e.data, | |
| 265 | - touch = identifiedTouch(e.changedTouches, template.identifier); | |
| 266 | - | |
| 300 | + function touchend(e, data) { | |
| 301 | + var touch = identifiedTouch(e.changedTouches, data.identifier); | |
| 267 | 302 | if (!touch) { return; } |
| 268 | - | |
| 269 | - removeTouch(template.identifier); | |
| 303 | + removeTouch(data); | |
| 270 | 304 | } |
| 271 | 305 | |
| 272 | - function removeTouch(identifier) { | |
| 273 | - remove(document, '.' + identifier, touchmove); | |
| 274 | - remove(document, '.' + identifier, touchend); | |
| 306 | + function removeTouch(data) { | |
| 307 | + off(document, touchevents.move, data.touchmove); | |
| 308 | + off(document, touchevents.cancel, data.touchend); | |
| 275 | 309 | } |
| 276 | 310 | |
| 311 | + function checkThreshold(e, data, touch, fn) { | |
| 312 | + var distX = touch.pageX - data.pageX; | |
| 313 | + var distY = touch.pageY - data.pageY; | |
| 277 | 314 | |
| 278 | - // Logic for deciding when to trigger a movestart. | |
| 279 | - | |
| 280 | - function checkThreshold(e, template, touch, fn) { | |
| 281 | - var distX = touch.pageX - template.startX, | |
| 282 | - distY = touch.pageY - template.startY; | |
| 283 | - | |
| 284 | 315 | // Do nothing if the threshold has not been crossed. |
| 285 | 316 | if ((distX * distX) + (distY * distY) < (threshold * threshold)) { return; } |
| 286 | 317 | |
| 287 | - triggerStart(e, template, touch, distX, distY, fn); | |
| 318 | + triggerStart(e, data, touch, distX, distY, fn); | |
| 288 | 319 | } |
| 289 | 320 | |
| 290 | - function handled() { | |
| 291 | - // this._handled should return false once, and after return true. | |
| 292 | - this._handled = returnTrue; | |
| 293 | - return false; | |
| 294 | - } | |
| 321 | + function triggerStart(e, data, touch, distX, distY, fn) { | |
| 322 | + var touches = e.targetTouches; | |
| 323 | + var time = e.timeStamp - data.timeStamp; | |
| 295 | 324 | |
| 296 | - function flagAsHandled(e) { | |
| 297 | - e._handled(); | |
| 298 | - } | |
| 299 | - | |
| 300 | - function triggerStart(e, template, touch, distX, distY, fn) { | |
| 301 | - var node = template.target, | |
| 302 | - touches, time; | |
| 303 | - | |
| 304 | - touches = e.targetTouches; | |
| 305 | - time = e.timeStamp - template.timeStamp; | |
| 306 | - | |
| 307 | 325 | // Create a movestart object with some special properties that |
| 308 | 326 | // are passed only to the movestart handlers. |
| 309 | - template.type = 'movestart'; | |
| 310 | - template.distX = distX; | |
| 311 | - template.distY = distY; | |
| 312 | - template.deltaX = distX; | |
| 313 | - template.deltaY = distY; | |
| 314 | - template.pageX = touch.pageX; | |
| 315 | - template.pageY = touch.pageY; | |
| 316 | - template.velocityX = distX / time; | |
| 317 | - template.velocityY = distY / time; | |
| 318 | - template.targetTouches = touches; | |
| 319 | - template.finger = touches ? | |
| 320 | - touches.length : | |
| 321 | - 1 ; | |
| 322 | - | |
| 323 | - // The _handled method is fired to tell the default movestart | |
| 324 | - // handler that one of the move events is bound. | |
| 325 | - template._handled = handled; | |
| 326 | - | |
| 327 | - // Pass the touchmove event so it can be prevented if or when | |
| 328 | - // movestart is handled. | |
| 329 | - template._preventTouchmoveDefault = function() { | |
| 330 | - e.preventDefault(); | |
| 327 | + var template = { | |
| 328 | + altKey: e.altKey, | |
| 329 | + ctrlKey: e.ctrlKey, | |
| 330 | + shiftKey: e.shiftKey, | |
| 331 | + startX: data.pageX, | |
| 332 | + startY: data.pageY, | |
| 333 | + distX: distX, | |
| 334 | + distY: distY, | |
| 335 | + deltaX: distX, | |
| 336 | + deltaY: distY, | |
| 337 | + pageX: touch.pageX, | |
| 338 | + pageY: touch.pageY, | |
| 339 | + velocityX: distX / time, | |
| 340 | + velocityY: distY / time, | |
| 341 | + identifier: data.identifier, | |
| 342 | + targetTouches: touches, | |
| 343 | + finger: touches ? touches.length : 1, | |
| 344 | + enableMove: function() { | |
| 345 | + this.moveEnabled = true; | |
| 346 | + this.enableMove = noop; | |
| 347 | + e.preventDefault(); | |
| 348 | + } | |
| 331 | 349 | }; |
| 332 | 350 | |
| 333 | 351 | // Trigger the movestart event. |
| 334 | - trigger(template.target, template); | |
| 352 | + trigger(data.target, 'movestart', template); | |
| 335 | 353 | |
| 336 | 354 | // Unbind handlers that tracked the touch or mouse up till now. |
| 337 | - fn(template.identifier); | |
| 355 | + fn(data); | |
| 338 | 356 | } |
| 339 | 357 | |
| 340 | 358 | |
| 341 | 359 | // Handlers that control what happens following a movestart |
| 342 | 360 | |
| 343 | - function activeMousemove(e) { | |
| 344 | - var timer = e.data.timer; | |
| 361 | + function activeMousemove(e, data) { | |
| 362 | + var timer = data.timer; | |
| 345 | 363 | |
| 346 | - e.data.touch = e; | |
| 347 | - e.data.timeStamp = e.timeStamp; | |
| 364 | + data.touch = e; | |
| 365 | + data.timeStamp = e.timeStamp; | |
| 348 | 366 | timer.kick(); |
| 349 | 367 | } |
| 350 | 368 | |
| 351 | - function activeMouseend(e) { | |
| 352 | - var event = e.data.event, | |
| 353 | - timer = e.data.timer; | |
| 354 | - | |
| 369 | + function activeMouseend(e, data) { | |
| 370 | + var target = data.target; | |
| 371 | + var event = data.event; | |
| 372 | + var timer = data.timer; | |
| 373 | + | |
| 355 | 374 | removeActiveMouse(); |
| 356 | 375 | |
| 357 | - endEvent(event, timer, function() { | |
| 376 | + endEvent(target, event, timer, function() { | |
| 358 | 377 | // Unbind the click suppressor, waiting until after mouseup |
| 359 | 378 | // has been handled. |
| 360 | 379 | setTimeout(function(){ |
| 361 | - remove(event.target, 'click', returnFalse); | |
| 380 | + off(target, 'click', preventDefault); | |
| 362 | 381 | }, 0); |
| 363 | 382 | }); |
| 364 | 383 | } |
| 365 | 384 | |
| 366 | - function removeActiveMouse(event) { | |
| 367 | - remove(document, mouseevents.move, activeMousemove); | |
| 368 | - remove(document, mouseevents.end, activeMouseend); | |
| 385 | + function removeActiveMouse() { | |
| 386 | + off(document, mouseevents.move, activeMousemove); | |
| 387 | + off(document, mouseevents.end, activeMouseend); | |
| 369 | 388 | } |
| 370 | 389 | |
| 371 | - function activeTouchmove(e) { | |
| 372 | - var event = e.data.event, | |
| 373 | - timer = e.data.timer, | |
| 374 | - touch = changedTouch(e, event); | |
| 390 | + function activeTouchmove(e, data) { | |
| 391 | + var event = data.event; | |
| 392 | + var timer = data.timer; | |
| 393 | + var touch = changedTouch(e, event); | |
| 375 | 394 | |
| 376 | 395 | if (!touch) { return; } |
| 377 | 396 | |
| 378 | 397 | // Stop the interface from gesturing |
| @@ -378,42 +397,43 @@ | ||
| 378 | 397 | // Stop the interface from gesturing |
| 379 | 398 | e.preventDefault(); |
| 380 | 399 | |
| 381 | 400 | event.targetTouches = e.targetTouches; |
| 382 | - e.data.touch = touch; | |
| 383 | - e.data.timeStamp = e.timeStamp; | |
| 401 | + data.touch = touch; | |
| 402 | + data.timeStamp = e.timeStamp; | |
| 403 | + | |
| 384 | 404 | timer.kick(); |
| 385 | 405 | } |
| 386 | 406 | |
| 387 | - function activeTouchend(e) { | |
| 388 | - var event = e.data.event, | |
| 389 | - timer = e.data.timer, | |
| 390 | - touch = identifiedTouch(e.changedTouches, event.identifier); | |
| 407 | + function activeTouchend(e, data) { | |
| 408 | + var target = data.target; | |
| 409 | + var event = data.event; | |
| 410 | + var timer = data.timer; | |
| 411 | + var touch = identifiedTouch(e.changedTouches, event.identifier); | |
| 391 | 412 | |
| 392 | 413 | // This isn't the touch you're looking for. |
| 393 | 414 | if (!touch) { return; } |
| 394 | 415 | |
| 395 | - removeActiveTouch(event); | |
| 396 | - endEvent(event, timer); | |
| 416 | + removeActiveTouch(data); | |
| 417 | + endEvent(target, event, timer); | |
| 397 | 418 | } |
| 398 | 419 | |
| 399 | - function removeActiveTouch(event) { | |
| 400 | - remove(document, '.' + event.identifier, activeTouchmove); | |
| 401 | - remove(document, '.' + event.identifier, activeTouchend); | |
| 420 | + function removeActiveTouch(data) { | |
| 421 | + off(document, touchevents.move, data.activeTouchmove); | |
| 422 | + off(document, touchevents.end, data.activeTouchend); | |
| 402 | 423 | } |
| 403 | 424 | |
| 404 | 425 | |
| 405 | 426 | // Logic for triggering move and moveend events |
| 406 | 427 | |
| 407 | - function updateEvent(event, touch, timeStamp, timer) { | |
| 428 | + function updateEvent(event, touch, timeStamp) { | |
| 408 | 429 | var time = timeStamp - event.timeStamp; |
| 409 | 430 | |
| 410 | - event.type = 'move'; | |
| 411 | 431 | event.distX = touch.pageX - event.startX; |
| 412 | 432 | event.distY = touch.pageY - event.startY; |
| 413 | 433 | event.deltaX = touch.pageX - event.pageX; |
| 414 | 434 | event.deltaY = touch.pageY - event.pageY; |
| 415 | - | |
| 435 | + | |
| 416 | 436 | // Average the velocity of the last few events using a decay |
| 417 | 437 | // curve to even out spurious jumps in values. |
| 418 | 438 | event.velocityX = 0.3 * event.velocityX + 0.7 * event.deltaX / time; |
| 419 | 439 | event.velocityY = 0.3 * event.velocityY + 0.7 * event.deltaY / time; |
| @@ -420,167 +440,145 @@ | ||
| 420 | 440 | event.pageX = touch.pageX; |
| 421 | 441 | event.pageY = touch.pageY; |
| 422 | 442 | } |
| 423 | 443 | |
| 424 | - function endEvent(event, timer, fn) { | |
| 444 | + function endEvent(target, event, timer, fn) { | |
| 425 | 445 | timer.end(function(){ |
| 426 | - event.type = 'moveend'; | |
| 427 | - | |
| 428 | - trigger(event.target, event); | |
| 429 | - | |
| 446 | + trigger(target, 'moveend', event); | |
| 430 | 447 | return fn && fn(); |
| 431 | 448 | }); |
| 432 | 449 | } |
| 433 | 450 | |
| 434 | 451 | |
| 435 | - // jQuery special event definition | |
| 452 | + // Set up the DOM | |
| 436 | 453 | |
| 437 | - function setup(data, namespaces, eventHandle) { | |
| 438 | - // Stop the node from being dragged | |
| 439 | - //add(this, 'dragstart.move drag.move', preventDefault); | |
| 440 | - | |
| 441 | - // Prevent text selection and touch interface scrolling | |
| 442 | - //add(this, 'mousedown.move', preventIgnoreTags); | |
| 443 | - | |
| 444 | - // Tell movestart default handler that we've handled this | |
| 445 | - add(this, 'movestart.move', flagAsHandled); | |
| 454 | + function movestart(e) { | |
| 455 | + if (e.defaultPrevented) { return; } | |
| 456 | + if (!e.moveEnabled) { return; } | |
| 446 | 457 | |
| 447 | - // Don't bind to the DOM. For speed. | |
| 448 | - return true; | |
| 449 | - } | |
| 450 | - | |
| 451 | - function teardown(namespaces) { | |
| 452 | - remove(this, 'dragstart drag', preventDefault); | |
| 453 | - remove(this, 'mousedown touchstart', preventIgnoreTags); | |
| 454 | - remove(this, 'movestart', flagAsHandled); | |
| 455 | - | |
| 456 | - // Don't bind to the DOM. For speed. | |
| 457 | - return true; | |
| 458 | - } | |
| 459 | - | |
| 460 | - function addMethod(handleObj) { | |
| 461 | - // We're not interested in preventing defaults for handlers that | |
| 462 | - // come from internal move or moveend bindings | |
| 463 | - if (handleObj.namespace === "move" || handleObj.namespace === "moveend") { | |
| 464 | - return; | |
| 458 | + var event = { | |
| 459 | + startX: e.startX, | |
| 460 | + startY: e.startY, | |
| 461 | + pageX: e.pageX, | |
| 462 | + pageY: e.pageY, | |
| 463 | + distX: e.distX, | |
| 464 | + distY: e.distY, | |
| 465 | + deltaX: e.deltaX, | |
| 466 | + deltaY: e.deltaY, | |
| 467 | + velocityX: e.velocityX, | |
| 468 | + velocityY: e.velocityY, | |
| 469 | + identifier: e.identifier, | |
| 470 | + targetTouches: e.targetTouches, | |
| 471 | + finger: e.finger | |
| 472 | + }; | |
| 473 | + | |
| 474 | + var data = { | |
| 475 | + target: e.target, | |
| 476 | + event: event, | |
| 477 | + timer: new Timer(update), | |
| 478 | + touch: undefined, | |
| 479 | + timeStamp: e.timeStamp | |
| 480 | + }; | |
| 481 | + | |
| 482 | + function update(time) { | |
| 483 | + updateEvent(event, data.touch, data.timeStamp); | |
| 484 | + trigger(data.target, 'move', event); | |
| 465 | 485 | } |
| 466 | - | |
| 467 | - // Stop the node from being dragged | |
| 468 | - add(this, 'dragstart.' + handleObj.guid + ' drag.' + handleObj.guid, preventDefault, undefined, handleObj.selector); | |
| 469 | - | |
| 470 | - // Prevent text selection and touch interface scrolling | |
| 471 | - add(this, 'mousedown.' + handleObj.guid, preventIgnoreTags, undefined, handleObj.selector); | |
| 472 | - } | |
| 473 | - | |
| 474 | - function removeMethod(handleObj) { | |
| 475 | - if (handleObj.namespace === "move" || handleObj.namespace === "moveend") { | |
| 476 | - return; | |
| 486 | + | |
| 487 | + if (e.identifier === undefined) { | |
| 488 | + // We're dealing with a mouse event. | |
| 489 | + // Stop clicks from propagating during a move | |
| 490 | + on(e.target, 'click', preventDefault); | |
| 491 | + on(document, mouseevents.move, activeMousemove, data); | |
| 492 | + on(document, mouseevents.end, activeMouseend, data); | |
| 477 | 493 | } |
| 478 | - | |
| 479 | - remove(this, 'dragstart.' + handleObj.guid + ' drag.' + handleObj.guid); | |
| 480 | - remove(this, 'mousedown.' + handleObj.guid); | |
| 494 | + else { | |
| 495 | + // In order to unbind correct handlers they have to be unique | |
| 496 | + data.activeTouchmove = function(e, data) { activeTouchmove(e, data); }; | |
| 497 | + data.activeTouchend = function(e, data) { activeTouchend(e, data); }; | |
| 498 | + | |
| 499 | + // We're dealing with a touch. | |
| 500 | + on(document, touchevents.move, data.activeTouchmove, data); | |
| 501 | + on(document, touchevents.end, data.activeTouchend, data); | |
| 502 | + } | |
| 481 | 503 | } |
| 482 | - | |
| 483 | - jQuery.event.special.movestart = { | |
| 484 | - setup: setup, | |
| 485 | - teardown: teardown, | |
| 486 | - add: addMethod, | |
| 487 | - remove: removeMethod, | |
| 488 | 504 | |
| 489 | - _default: function(e) { | |
| 490 | - var event, data; | |
| 491 | - | |
| 492 | - // If no move events were bound to any ancestors of this | |
| 493 | - // target, high tail it out of here. | |
| 494 | - if (!e._handled()) { return; } | |
| 505 | + on(document, 'mousedown', mousedown); | |
| 506 | + on(document, 'touchstart', touchstart); | |
| 507 | + on(document, 'movestart', movestart); | |
| 495 | 508 | |
| 496 | - function update(time) { | |
| 497 | - updateEvent(event, data.touch, data.timeStamp); | |
| 498 | - trigger(e.target, event); | |
| 509 | + | |
| 510 | + // jQuery special events | |
| 511 | + // | |
| 512 | + // jQuery event objects are copies of DOM event objects. They need | |
| 513 | + // a little help copying the move properties across. | |
| 514 | + | |
| 515 | + if (!window.jQuery) { return; } | |
| 516 | + | |
| 517 | + var properties = ("startX startY pageX pageY distX distY deltaX deltaY velocityX velocityY").split(' '); | |
| 518 | + | |
| 519 | + function enableMove1(e) { e.enableMove(); } | |
| 520 | + function enableMove2(e) { e.enableMove(); } | |
| 521 | + function enableMove3(e) { e.enableMove(); } | |
| 522 | + | |
| 523 | + function add(handleObj) { | |
| 524 | + var handler = handleObj.handler; | |
| 525 | + | |
| 526 | + handleObj.handler = function(e) { | |
| 527 | + // Copy move properties across from originalEvent | |
| 528 | + var i = properties.length; | |
| 529 | + var property; | |
| 530 | + | |
| 531 | + while(i--) { | |
| 532 | + property = properties[i]; | |
| 533 | + e[property] = e.originalEvent[property]; | |
| 499 | 534 | } |
| 500 | 535 | |
| 501 | - event = { | |
| 502 | - target: e.target, | |
| 503 | - startX: e.startX, | |
| 504 | - startY: e.startY, | |
| 505 | - pageX: e.pageX, | |
| 506 | - pageY: e.pageY, | |
| 507 | - distX: e.distX, | |
| 508 | - distY: e.distY, | |
| 509 | - deltaX: e.deltaX, | |
| 510 | - deltaY: e.deltaY, | |
| 511 | - velocityX: e.velocityX, | |
| 512 | - velocityY: e.velocityY, | |
| 513 | - timeStamp: e.timeStamp, | |
| 514 | - identifier: e.identifier, | |
| 515 | - targetTouches: e.targetTouches, | |
| 516 | - finger: e.finger | |
| 517 | - }; | |
| 536 | + handler.apply(this, arguments); | |
| 537 | + }; | |
| 538 | + } | |
| 518 | 539 | |
| 519 | - data = { | |
| 520 | - event: event, | |
| 521 | - timer: new Timer(update), | |
| 522 | - touch: undefined, | |
| 523 | - timeStamp: undefined | |
| 524 | - }; | |
| 525 | - | |
| 526 | - if (e.identifier === undefined) { | |
| 527 | - // We're dealing with a mouse | |
| 528 | - // Stop clicks from propagating during a move | |
| 529 | - add(e.target, 'click', returnFalse); | |
| 530 | - add(document, mouseevents.move, activeMousemove, data); | |
| 531 | - add(document, mouseevents.end, activeMouseend, data); | |
| 532 | - } | |
| 533 | - else { | |
| 534 | - // We're dealing with a touch. Stop touchmove doing | |
| 535 | - // anything defaulty. | |
| 536 | - e._preventTouchmoveDefault(); | |
| 537 | - add(document, touchevents.move + '.' + e.identifier, activeTouchmove, data); | |
| 538 | - add(document, touchevents.end + '.' + e.identifier, activeTouchend, data); | |
| 539 | - } | |
| 540 | - } | |
| 540 | + jQuery.event.special.movestart = { | |
| 541 | + setup: function() { | |
| 542 | + // Movestart must be enabled to allow other move events | |
| 543 | + on(this, 'movestart', enableMove1); | |
| 544 | + | |
| 545 | + // Do listen to DOM events | |
| 546 | + return false; | |
| 547 | + }, | |
| 548 | + | |
| 549 | + teardown: function() { | |
| 550 | + off(this, 'movestart', enableMove1); | |
| 551 | + return false; | |
| 552 | + }, | |
| 553 | + | |
| 554 | + add: add | |
| 541 | 555 | }; |
| 542 | 556 | |
| 543 | 557 | jQuery.event.special.move = { |
| 544 | 558 | setup: function() { |
| 545 | - // Bind a noop to movestart. Why? It's the movestart | |
| 546 | - // setup that decides whether other move events are fired. | |
| 547 | - add(this, 'movestart.move', jQuery.noop); | |
| 559 | + on(this, 'movestart', enableMove2); | |
| 560 | + return false; | |
| 548 | 561 | }, |
| 549 | - | |
| 562 | + | |
| 550 | 563 | teardown: function() { |
| 551 | - remove(this, 'movestart.move', jQuery.noop); | |
| 552 | - } | |
| 564 | + off(this, 'movestart', enableMove2); | |
| 565 | + return false; | |
| 566 | + }, | |
| 567 | + | |
| 568 | + add: add | |
| 553 | 569 | }; |
| 554 | - | |
| 570 | + | |
| 555 | 571 | jQuery.event.special.moveend = { |
| 556 | 572 | setup: function() { |
| 557 | - // Bind a noop to movestart. Why? It's the movestart | |
| 558 | - // setup that decides whether other move events are fired. | |
| 559 | - add(this, 'movestart.moveend', jQuery.noop); | |
| 573 | + on(this, 'movestart', enableMove3); | |
| 574 | + return false; | |
| 560 | 575 | }, |
| 561 | - | |
| 576 | + | |
| 562 | 577 | teardown: function() { |
| 563 | - remove(this, 'movestart.moveend', jQuery.noop); | |
| 564 | - } | |
| 565 | - }; | |
| 578 | + off(this, 'movestart', enableMove3); | |
| 579 | + return false; | |
| 580 | + }, | |
| 566 | 581 | |
| 567 | - add(document, 'mousedown.move', mousedown); | |
| 568 | - add(document, 'touchstart.move', touchstart); | |
| 569 | - | |
| 570 | - // Make jQuery copy touch event properties over to the jQuery event | |
| 571 | - // object, if they are not already listed. But only do the ones we | |
| 572 | - // really need. IE7/8 do not have Array#indexOf(), but nor do they | |
| 573 | - // have touch events, so let's assume we can ignore them. | |
| 574 | - if (typeof Array.prototype.indexOf === 'function') { | |
| 575 | - (function(jQuery, undefined){ | |
| 576 | - var props = ["changedTouches", "targetTouches"], | |
| 577 | - l = props.length; | |
| 578 | - | |
| 579 | - while (l--) { | |
| 580 | - if (jQuery.event.props.indexOf(props[l]) === -1) { | |
| 581 | - jQuery.event.props.push(props[l]); | |
| 582 | - } | |
| 583 | - } | |
| 584 | - })(jQuery); | |
| 582 | + add: add | |
| 585 | 583 | }; |
| 586 | 584 | }); |