jquery.event.drag.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Source: https://github.com/devongovett/jquery.event.drag/blob/451d90e1a737f49f613d0966082ce67582b0afd1/drag/jquery.event.drag.js
  2. //
  3. // Warning! Make sure the hijack() is patch to work with any jquery version:
  4. //
  5. // ($.event.dispatch || $.event.handle).call( elem, event );
  6. //
  7. /*!
  8. jquery.event.drag.js ~ v1.6 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com)
  9. Liscensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt
  10. */
  11. ;(function($){ // secure $ jQuery alias
  12. /*******************************************************************************************/
  13. // Created: 2008-06-04 | Updated: 2009-04-21
  14. /*******************************************************************************************/
  15. // Events: drag, dragstart, dragend
  16. /*******************************************************************************************/
  17. // jquery method
  18. $.fn.drag = function( fn1, fn2, fn3 ){
  19. if ( fn2 ) this.bind('dragstart', fn1 ); // 2+ args
  20. if ( fn3 ) this.bind('dragend', fn3 ); // 3 args
  21. return !fn1 ? this.trigger('drag') // 0 args
  22. : this.bind('drag', fn2 ? fn2 : fn1 ); // 1+ args
  23. };
  24. // local refs
  25. var $event = $.event, $special = $event.special,
  26. // special event configuration
  27. drag = $special.drag = {
  28. not: ':input', // don't begin to drag on event.targets that match this selector
  29. distance: 0, // distance dragged before dragstart
  30. which: 1, // mouse button pressed to start drag sequence
  31. drop: false, // false to suppress drop events
  32. dragging: false, // hold the active target element
  33. setup: function( data ){
  34. data = $.extend({
  35. distance: drag.distance,
  36. which: drag.which,
  37. not: drag.not,
  38. drop: drag.drop
  39. }, data || {});
  40. data.distance = squared( data.distance ); // x² + y² = distance²
  41. $event.add( this, "mousedown", handler, data );
  42. if ( this.attachEvent ) this.attachEvent("ondragstart", dontStart ); // prevent image dragging in IE...
  43. },
  44. teardown: function(){
  45. $event.remove( this, "mousedown", handler );
  46. if ( this === drag.dragging ) drag.dragging = drag.proxy = false; // deactivate element
  47. selectable( this, true ); // enable text selection
  48. if ( this.detachEvent ) this.detachEvent("ondragstart", dontStart ); // prevent image dragging in IE...
  49. }
  50. };
  51. // prevent normal event binding...
  52. $special.dragstart = $special.dragend = { setup:function(){}, teardown:function(){} };
  53. // handle drag-releatd DOM events
  54. function handler ( event ){
  55. var elem = this, returned, data = event.data || {};
  56. // mousemove or mouseup
  57. if ( data.elem ){
  58. // update event properties...
  59. elem = event.dragTarget = data.elem; // drag source element
  60. event.dragProxy = drag.proxy || elem; // proxy element or source
  61. event.cursorOffsetX = data.pageX - data.left; // mousedown offset
  62. event.cursorOffsetY = data.pageY - data.top; // mousedown offset
  63. event.offsetX = event.pageX - event.cursorOffsetX; // element offset
  64. event.offsetY = event.pageY - event.cursorOffsetY; // element offset
  65. }
  66. // mousedown, check some initial props to avoid the switch statement
  67. else if ( drag.dragging || ( data.which>0 && event.which!=data.which ) ||
  68. $( event.target ).is( data.not ) ) return;
  69. // handle various events
  70. switch ( event.type ){
  71. // mousedown, left click, event.target is not restricted, init dragging
  72. case 'mousedown':
  73. $.extend( data, $( elem ).offset(), {
  74. elem: elem, target: event.target,
  75. pageX: event.pageX, pageY: event.pageY
  76. }); // store some initial attributes
  77. $event.add( document, "mousemove mouseup", handler, data );
  78. selectable( elem, false ); // disable text selection
  79. drag.dragging = null; // pending state
  80. break; // prevents text selection in safari
  81. // mousemove, check distance, start dragging
  82. case !drag.dragging && 'mousemove':
  83. if ( squared( event.pageX-data.pageX )
  84. + squared( event.pageY-data.pageY ) // x² + y² = distance²
  85. < data.distance ) break; // distance tolerance not reached
  86. event.target = data.target; // force target from "mousedown" event (fix distance issue)
  87. returned = hijack( event, "dragstart", elem ); // trigger "dragstart", return proxy element
  88. if ( returned !== false ){ // "dragstart" not rejected
  89. drag.dragging = elem; // activate element
  90. drag.proxy = event.dragProxy = $( returned || elem )[0]; // set proxy
  91. }
  92. // mousemove, dragging
  93. case 'mousemove':
  94. if ( drag.dragging ){
  95. returned = hijack( event, "drag", elem ); // trigger "drag"
  96. if ( data.drop && $special.drop ){ // manage drop events
  97. $special.drop.allowed = ( returned !== false ); // prevent drop
  98. $special.drop.handler( event ); // "dropstart", "dropend"
  99. }
  100. if ( returned !== false ) break; // "drag" not rejected, stop
  101. event.type = "mouseup"; // helps "drop" handler behave
  102. }
  103. // mouseup, stop dragging
  104. case 'mouseup':
  105. $event.remove( document, "mousemove mouseup", handler ); // remove page events
  106. if ( drag.dragging ){
  107. if ( data.drop && $special.drop ) $special.drop.handler( event ); // "drop"
  108. hijack( event, "dragend", elem ); // trigger "dragend"
  109. }
  110. selectable( elem, true ); // enable text selection
  111. drag.dragging = drag.proxy = data.elem = false; // deactivate element
  112. break;
  113. }
  114. };
  115. // set event type to custom value, and handle it
  116. function hijack ( event, type, elem ){
  117. event.type = type; // force the event type
  118. var result = ($.event.dispatch || $.event.handle).call( elem, event );
  119. return result===false ? false : result || event.result;
  120. };
  121. // return the value squared
  122. function squared ( value ){ return Math.pow( value, 2 ); };
  123. // suppress default dragstart IE events...
  124. function dontStart(){ return ( drag.dragging === false ); };
  125. // toggles text selection attributes
  126. function selectable ( elem, bool ){
  127. if ( !elem ) return; // maybe element was removed ?
  128. elem = elem.ownerDocument ? elem.ownerDocument : elem;
  129. elem.unselectable = bool ? "off" : "on"; // IE
  130. if ( elem.style ) elem.style.MozUserSelect = bool ? "" : "none"; // FF
  131. $.event[ bool ? "remove" : "add" ]( elem, "selectstart mousedown", dontStart ); // IE/Opera
  132. };
  133. /*******************************************************************************************/
  134. })( jQuery ); // confine scope