dragresize.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. DragResize v1.1
  3. (c) 2005-2006 Angus Turnbull, TwinHelix Designs http://www.twinhelix.com
  4. Licensed under the CC-GNU LGPL, version 2.1 or later:
  5. http://creativecommons.org/licenses/LGPL/2.1/
  6. This is distributed WITHOUT ANY WARRANTY; without even the implied
  7. warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. Simplified and modified for Converse.js by JC Brand https://opkode.com
  9. */
  10. (function (root, factory) {
  11. if (typeof define === 'function' && define.amd) {
  12. define("dragresize", [], function() { return factory(); });
  13. } else {
  14. root.DragResize = factory();
  15. }
  16. }(this, function () {
  17. function cancelEvent(e, c) {
  18. e.returnValue = false;
  19. if (e.preventDefault) {
  20. e.preventDefault();
  21. }
  22. if (c) {
  23. e.cancelBubble = true;
  24. if (e.stopPropagation) {
  25. e.stopPropagation();
  26. }
  27. }
  28. }
  29. // *** DRAG/RESIZE CODE ***
  30. function DragResize(myName, config) {
  31. var props = {
  32. myName: myName, // Name of the object.
  33. enabled: true, // Global toggle of drag/resize.
  34. handles: ['tl', 'tm', 'tr',
  35. 'ml', 'mr', 'bl', 'bm', 'br'], // Array of drag handles: top/mid/bot/right.
  36. isElement: null, // Function ref to test for an element.
  37. element: null, // The currently selected element.
  38. handle: null, // Active handle reference of the element.
  39. minWidth: 10, minHeight: 10, // Minimum pixel size of elements.
  40. zIndex: 1, // The highest Z-Index yet allocated.
  41. lastMouseX: 0, lastMouseY: 0, // Last processed mouse positions.
  42. mOffX: 0, mOffY: 0, // A known offset between position & mouse.
  43. elmW: 0, elmH: 0, // Element size.
  44. allowBlur: true, // Whether to allow automatic blur onclick.
  45. ondragfocus: null, // Event handler functions.
  46. ondragstart: null,
  47. ondragend: null,
  48. ondragblur: null
  49. };
  50. for (var p in props) {
  51. this[p] = (typeof config[p] == 'undefined') ? props[p] : config[p];
  52. }
  53. };
  54. DragResize.prototype.apply = function(node) {
  55. /* Adds object event handlers to the specified DOM node */
  56. $(node).bind('mousedown', this.mouseDown.bind(this));
  57. $(node).bind('mousemove', this.mouseMove.bind(this));
  58. $(node).bind('mouseup', this.mouseUp.bind(this));
  59. };
  60. DragResize.prototype.select = function(newElement) {
  61. with (this) {
  62. // Selects an element for dragging.
  63. if (!document.getElementById || !enabled) return;
  64. // Activate and record our new dragging element.
  65. if (newElement && (newElement != element) && enabled) {
  66. element = newElement;
  67. // Elevate it
  68. element.style.zIndex = ++zIndex;
  69. // Record element attributes for mouseMove().
  70. elmW = element.offsetWidth;
  71. elmH = element.offsetHeight;
  72. if (ondragfocus) this.ondragfocus();
  73. }
  74. }
  75. };
  76. DragResize.prototype.deselect = function(delHandles) {
  77. with (this) {
  78. // Immediately stops dragging an element. If 'delHandles' is true, this
  79. // remove the handles from the element and clears the element flag,
  80. // completely resetting the .
  81. if (!document.getElementById || !enabled) return;
  82. if (delHandles) {
  83. if (ondragblur) this.ondragblur();
  84. element = null;
  85. }
  86. handle = null;
  87. mOffX = 0;
  88. mOffY = 0;
  89. }
  90. };
  91. DragResize.prototype.mouseDown = function(e) {
  92. with (this) {
  93. // Suitable elements are selected for drag/resize on mousedown.
  94. // We also initialise the resize boxes, and drag parameters like mouse position etc.
  95. if (!document.getElementById || !enabled) return true;
  96. var elm = e.target || e.srcElement,
  97. newElement = null,
  98. newHandle = null,
  99. hRE = new RegExp(myName + '-([trmbl]{2})', '');
  100. while (elm) {
  101. // Loop up the DOM looking for matching elements. Remember one if found.
  102. if (elm.className) {
  103. if (!newHandle && (hRE.test(elm.className))) newHandle = elm;
  104. if (isElement(elm)) { newElement = elm; break }
  105. }
  106. elm = elm.parentNode;
  107. }
  108. // If this isn't on the last dragged element, call deselect(),
  109. // which will hide its handles and clear element.
  110. if (element && (element != newElement) && allowBlur) deselect(true);
  111. // If we have a new matching element, call select().
  112. if (newElement && (!element || (newElement == element))) {
  113. // Stop mouse selections if we're dragging a handle.
  114. if (newHandle) cancelEvent(e);
  115. select(newElement, newHandle);
  116. handle = newHandle;
  117. if (handle && ondragstart) this.ondragstart(hRE.test(handle.className));
  118. }
  119. }
  120. };
  121. DragResize.prototype.updateMouseCoordinates = function (e) {
  122. /* Update last processed mouse positions */
  123. this.mOffX = this.mOffY = 0;
  124. this.lastMouseX = e.pageX || e.clientX + document.documentElement.scrollLeft;
  125. this.lastMouseY = e.pageY || e.clientY + document.documentElement.scrollTop;
  126. };
  127. DragResize.prototype.operaHack = function (e) {
  128. // Evil, dirty, hackish Opera select-as-you-drag fix.
  129. if (window.opera && document.documentElement) {
  130. var oDF = document.getElementById('op-drag-fix');
  131. if (!oDF) {
  132. var oDF = document.createElement('input');
  133. oDF.id = 'op-drag-fix';
  134. oDF.style.display = 'none';
  135. document.body.appendChild(oDF);
  136. }
  137. oDF.focus();
  138. }
  139. };
  140. DragResize.prototype.resizeElement = function (e) {
  141. // Let it create an object representing the drag offsets.
  142. var resize = this.resizeHandleDrag(e) ? true : false;
  143. // Assign new info back to the element, with minimum dimensions.
  144. this.element.style.width = this.elmW + 'px';
  145. this.element.style.height = this.elmH + 'px';
  146. this.operaHack();
  147. return e;
  148. };
  149. DragResize.prototype.mouseMove = function (e) {
  150. /* Continuously offsets the dragged element by the difference between the
  151. * previous mouse position and the current mouse position.
  152. */
  153. if (!this.enabled) return true;
  154. if (!this.handle) {
  155. // We're not dragging anything
  156. this.updateMouseCoordinates(e);
  157. return true;
  158. }
  159. cancelEvent(this.resizeElement(e));
  160. };
  161. DragResize.prototype.mouseUp = function(e) {
  162. with (this) {
  163. // On mouseup, stop dragging, but don't reset handler visibility.
  164. if (!document.getElementById || !enabled) return;
  165. var hRE = new RegExp(myName + '-([trmbl]{2})', '');
  166. if (handle && ondragend) this.ondragend(hRE.test(handle.className));
  167. deselect(false);
  168. }
  169. };
  170. DragResize.prototype.resizeHandleDrag = function(e) {
  171. /* Checks to see whether the
  172. * drag is from a resize handle created above; if so, it changes the stored
  173. * elm* dimensions and mOffX/Y.
  174. */
  175. var x = e.pageX || e.clientX + document.documentElement.scrollLeft;
  176. var y = e.pageY || e.clientY + document.documentElement.scrollTop;
  177. var diffX = x - this.lastMouseX + this.mOffX;
  178. var diffY = y - this.lastMouseY + this.mOffY;
  179. var hClass = this.handle &&
  180. this.handle.className &&
  181. this.handle.className.match(new RegExp(this.myName + '-([tmblr]{2})')) ? RegExp.$1 : '';
  182. with (this) {
  183. // If the hClass is one of the resize handles, resize one or two dimensions.
  184. // Bounds checking is the hard bit -- basically for each edge, check that the
  185. // element doesn't go under minimum size, and doesn't go beyond its boundary.
  186. var dY = diffY, dX = diffX, processed = false;
  187. if (hClass.indexOf('t') >= 0) {
  188. rs = 1;
  189. if (elmH - dY < minHeight) mOffY = (dY - (diffY = elmH - minHeight));
  190. elmH -= diffY;
  191. processed = true;
  192. }
  193. if (hClass.indexOf('b') >= 0) {
  194. rs = 1;
  195. if (elmH + dY < minHeight) mOffY = (dY - (diffY = minHeight - elmH));
  196. elmH += diffY;
  197. processed = true;
  198. }
  199. this.updateMouseCoordinates(e);
  200. return processed;
  201. }
  202. };
  203. return DragResize;
  204. }));