jquery.sortable-table.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. "use strict";
  2. function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  3. /**
  4. * This file is internal to phpMyAdmin.
  5. * @license see the main phpMyAdmin license.
  6. *
  7. * @fileoverview A jquery plugin that allows drag&drop sorting in tables.
  8. * Coded because JQuery UI sortable doesn't support tables. Also it has no animation
  9. *
  10. * @name Sortable Table JQuery plugin
  11. *
  12. * @requires jQuery
  13. */
  14. /**
  15. * Options:
  16. *
  17. * $('table').sortableTable({
  18. * ignoreRect: { top, left, width, height } - Relative coordinates on each element. If the user clicks
  19. * in this area, it is not seen as a drag&drop request. Useful for toolbars etc.
  20. * events: {
  21. * start: callback function when the user starts dragging
  22. * drop: callback function after an element has been dropped
  23. * }
  24. * })
  25. */
  26. /**
  27. * Commands:
  28. *
  29. * $('table').sortableTable('init') - equivalent to $('table').sortableTable()
  30. * $('table').sortableTable('refresh') - if the table has been changed, refresh correctly assigns all events again
  31. * $('table').sortableTable('destroy') - removes all events from the table
  32. */
  33. /**
  34. * Setup:
  35. *
  36. * Can be applied on any table, there is just one convention.
  37. * Each cell (<td>) has to contain one and only one element (preferably div or span)
  38. * which is the actually draggable element.
  39. */
  40. (function ($) {
  41. jQuery.fn.sortableTable = function (method) {
  42. var methods = {
  43. init: function init(options) {
  44. var tb = new SortableTableInstance(this, options);
  45. tb.init();
  46. $(this).data('sortableTable', tb);
  47. },
  48. refresh: function refresh() {
  49. $(this).data('sortableTable').refresh();
  50. },
  51. destroy: function destroy() {
  52. $(this).data('sortableTable').destroy();
  53. }
  54. };
  55. if (methods[method]) {
  56. return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  57. } else if (_typeof(method) === 'object' || !method) {
  58. return methods.init.apply(this, arguments);
  59. } else {
  60. $.error('Method ' + method + ' does not exist on jQuery.sortableTable');
  61. }
  62. function SortableTableInstance(table) {
  63. var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  64. var down = false;
  65. var $draggedEl;
  66. var oldCell;
  67. var previewMove;
  68. var id;
  69. /* Mouse handlers on the child elements */
  70. var onMouseUp = function onMouseUp(e) {
  71. dropAt(e.pageX, e.pageY);
  72. };
  73. var onMouseDown = function onMouseDown(e) {
  74. $draggedEl = $(this).children();
  75. if ($draggedEl.length === 0) {
  76. return;
  77. }
  78. if (options.ignoreRect && insideRect({
  79. x: e.pageX - $draggedEl.offset().left,
  80. y: e.pageY - $draggedEl.offset().top
  81. }, options.ignoreRect)) {
  82. return;
  83. }
  84. down = true;
  85. oldCell = this;
  86. if (options.events && options.events.start) {
  87. options.events.start(this);
  88. }
  89. return false;
  90. };
  91. var globalMouseMove = function globalMouseMove(e) {
  92. if (down) {
  93. move(e.pageX, e.pageY);
  94. if (inside($(oldCell), e.pageX, e.pageY)) {
  95. if (previewMove !== null) {
  96. moveTo(previewMove);
  97. previewMove = null;
  98. }
  99. } else {
  100. $(table).find('td').each(function () {
  101. if (inside($(this), e.pageX, e.pageY)) {
  102. if ($(previewMove).attr('class') !== $(this).children().first().attr('class')) {
  103. if (previewMove !== null) {
  104. moveTo(previewMove);
  105. }
  106. previewMove = $(this).children().first();
  107. if (previewMove.length > 0) {
  108. moveTo($(previewMove), {
  109. pos: {
  110. top: $(oldCell).offset().top - $(previewMove).parent().offset().top,
  111. left: $(oldCell).offset().left - $(previewMove).parent().offset().left
  112. }
  113. });
  114. }
  115. }
  116. return false;
  117. }
  118. });
  119. }
  120. }
  121. return false;
  122. };
  123. var globalMouseOut = function globalMouseOut() {
  124. if (down) {
  125. down = false;
  126. if (previewMove) {
  127. moveTo(previewMove);
  128. }
  129. moveTo($draggedEl);
  130. previewMove = null;
  131. }
  132. }; // Initialize sortable table
  133. this.init = function () {
  134. id = 1; // Add some required css to each child element in the <td>s
  135. $(table).find('td').children().each(function () {
  136. // Remove any old occurrences of our added draggable-num class
  137. $(this).attr('class', $(this).attr('class').replace(/\s*draggable-\d+/g, ''));
  138. $(this).addClass('draggable-' + id++);
  139. }); // Mouse events
  140. $(table).find('td').on('mouseup', onMouseUp);
  141. $(table).find('td').on('mousedown', onMouseDown);
  142. $(document).on('mousemove', globalMouseMove);
  143. $(document).on('mouseleave', globalMouseOut);
  144. }; // Call this when the table has been updated
  145. this.refresh = function () {
  146. this.destroy();
  147. this.init();
  148. };
  149. this.destroy = function () {
  150. // Add some required css to each child element in the <td>s
  151. $(table).find('td').children().each(function () {
  152. // Remove any old occurrences of our added draggable-num class
  153. $(this).attr('class', $(this).attr('class').replace(/\s*draggable-\d+/g, ''));
  154. }); // Mouse events
  155. $(table).find('td').off('mouseup', onMouseUp);
  156. $(table).find('td').off('mousedown', onMouseDown);
  157. $(document).off('mousemove', globalMouseMove);
  158. $(document).off('mouseleave', globalMouseOut);
  159. };
  160. function switchElement(drag, dropTo) {
  161. var dragPosDiff = {
  162. left: $(drag).children().first().offset().left - $(dropTo).offset().left,
  163. top: $(drag).children().first().offset().top - $(dropTo).offset().top
  164. };
  165. var dropPosDiff = null;
  166. if ($(dropTo).children().length > 0) {
  167. dropPosDiff = {
  168. left: $(dropTo).children().first().offset().left - $(drag).offset().left,
  169. top: $(dropTo).children().first().offset().top - $(drag).offset().top
  170. };
  171. }
  172. /* I love you append(). It moves the DOM Elements so gracefully <3 */
  173. // Put the element in the way to old place
  174. $(drag).append($(dropTo).children().first()).children().stop(true, true).on('mouseup', onMouseUp);
  175. if (dropPosDiff) {
  176. $(drag).append($(dropTo).children().first()).children().css('left', dropPosDiff.left + 'px').css('top', dropPosDiff.top + 'px');
  177. } // Put our dragged element into the space we just freed up
  178. $(dropTo).append($(drag).children().first()).children().on('mouseup', onMouseUp).css('left', dragPosDiff.left + 'px').css('top', dragPosDiff.top + 'px');
  179. moveTo($(dropTo).children().first(), {
  180. duration: 100
  181. });
  182. moveTo($(drag).children().first(), {
  183. duration: 100
  184. });
  185. if (options.events && options.events.drop) {
  186. // Drop event. The drag child element is moved into the drop element
  187. // and vice versa. So the parameters are switched.
  188. // Calculate row and column index
  189. var colIdx = $(dropTo).prevAll().length;
  190. var rowIdx = $(dropTo).parent().prevAll().length;
  191. options.events.drop(drag, dropTo, {
  192. col: colIdx,
  193. row: rowIdx
  194. });
  195. }
  196. }
  197. function move(x, y) {
  198. $draggedEl.offset({
  199. top: Math.min($(document).height(), Math.max(0, y - $draggedEl.height() / 2)),
  200. left: Math.min($(document).width(), Math.max(0, x - $draggedEl.width() / 2))
  201. });
  202. }
  203. function inside($el, x, y) {
  204. var off = $el.offset();
  205. return y >= off.top && x >= off.left && x < off.left + $el.width() && y < off.top + $el.height();
  206. }
  207. function insideRect(pos, r) {
  208. return pos.y > r.top && pos.x > r.left && pos.y < r.top + r.height && pos.x < r.left + r.width;
  209. }
  210. function dropAt(x, y) {
  211. if (!down) {
  212. return;
  213. }
  214. down = false;
  215. var switched = false;
  216. $(table).find('td').each(function () {
  217. if ($(this).children().first().attr('class') !== $(oldCell).children().first().attr('class') && inside($(this), x, y)) {
  218. switchElement(oldCell, this);
  219. switched = true;
  220. }
  221. });
  222. if (!switched) {
  223. if (previewMove) {
  224. moveTo(previewMove);
  225. }
  226. moveTo($draggedEl);
  227. }
  228. previewMove = null;
  229. }
  230. function moveTo(elem) {
  231. var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  232. if (!opts.pos) {
  233. opts.pos = {
  234. left: 0,
  235. top: 0
  236. };
  237. }
  238. if (!opts.duration) {
  239. opts.duration = 200;
  240. }
  241. $(elem).css('position', 'relative');
  242. $(elem).animate({
  243. top: opts.pos.top,
  244. left: opts.pos.left
  245. }, {
  246. duration: opts.duration,
  247. complete: function complete() {
  248. if (opts.pos.left === 0 && opts.pos.top === 0) {
  249. $(elem).css('position', '').css('left', '').css('top', '');
  250. }
  251. }
  252. });
  253. }
  254. }
  255. };
  256. })(jQuery);