jquery.dad.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*!
  2. * jquery.dad.js v1 (http://konsolestudio.com/dad)
  3. * Author William Lima
  4. */
  5. (function ($) {
  6. 'use strict';
  7. var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;
  8. $.fn.dad = function (opts) {
  9. var _this = this;
  10. var defaults = {
  11. target: '>div',
  12. draggable: false,
  13. placeholder: '',
  14. callback: false,
  15. containerClass: 'dad-container',
  16. childrenClass: 'dads-children',
  17. cloneClass: 'dads-children-clone',
  18. active: true,
  19. };
  20. var options = $.extend({}, defaults, opts);
  21. $(this).each(function () {
  22. var active = options.active;
  23. var $daddy = $(this);
  24. var childrenClass = options.childrenClass;
  25. var cloneClass = options.cloneClass;
  26. var jQclass = '.' + childrenClass;
  27. var $target = $daddy.find(options.target);
  28. var placeholder = options.placeholder;
  29. var callback = options.callback;
  30. var dragClass = 'dad-draggable-area';
  31. var holderClass = 'dads-children-placeholder';
  32. // HANDLE MOUSE
  33. var mouse = {
  34. x: 0,
  35. y: 0,
  36. target: false,
  37. clone: false,
  38. placeholder: false,
  39. cloneoffset: {
  40. x: 0,
  41. y: 0,
  42. },
  43. updatePosition: function (e) {
  44. this.x = e.pageX;
  45. this.y = e.pageY;
  46. },
  47. move: function (e) {
  48. this.updatePosition(e);
  49. if (this.clone !== false && _this.target !== false) {
  50. this.clone.css({
  51. left: this.x - this.cloneoffset.x,
  52. top: this.y - this.cloneoffset.y,
  53. });
  54. }
  55. },
  56. };
  57. $(window).on('mousemove touchmove', function (e) {
  58. var ev = e;
  59. if (mouse.clone !== false && mouse.target !== false) e.preventDefault();
  60. if (supportsTouch && e.type == 'touchmove') {
  61. ev = e.originalEvent.touches[0];
  62. var mouseTarget = document.elementFromPoint(ev.clientX, ev.clientY);
  63. $(mouseTarget).trigger('touchenter');
  64. }
  65. mouse.move(ev);
  66. });
  67. $daddy.addClass(options.containerClass);
  68. if (!$daddy.hasClass('dad-active') && active === true) {
  69. $daddy.addClass('dad-active');
  70. };
  71. _this.addDropzone = function (selector, func) {
  72. $(selector).on('mouseenter touchenter', function () {
  73. if (mouse.target !== false) {
  74. mouse.placeholder.css({ display: 'none' });
  75. mouse.target.css({ display: 'none' });
  76. $(this).addClass('active');
  77. }
  78. }).on('mouseup touchend', function () {
  79. if (mouse.target != false) {
  80. mouse.placeholder.css({ display: 'block' });
  81. mouse.target.css({ display: 'block' });
  82. func(mouse.target);
  83. dadEnd();
  84. };
  85. $(this).removeClass('active');
  86. }).on('mouseleave touchleave', function () {
  87. if (mouse.target !== false) {
  88. mouse.placeholder.css({ display: 'block' });
  89. mouse.target.css({ display: 'block' });
  90. }
  91. $(this).removeClass('active');
  92. });
  93. };
  94. // GET POSITION FUNCTION
  95. _this.getPosition = function () {
  96. var positionArray = [];
  97. $(this).find(jQclass).each(function () {
  98. positionArray[$(this).attr('data-dad-id')] = parseInt($(this).attr('data-dad-position'));
  99. });
  100. return positionArray;
  101. };
  102. _this.activate = function () {
  103. active = true;
  104. if (!$daddy.hasClass('dad-active')) {
  105. $daddy.addClass('dad-active');
  106. }
  107. return _this;
  108. };
  109. // DEACTIVATE FUNCTION
  110. _this.deactivate = function () {
  111. active = false;
  112. $daddy.removeClass('dad-active');
  113. return _this;
  114. };
  115. // DEFAULT DROPPING
  116. $daddy.on('DOMNodeInserted', function (e) {
  117. var $thisTarget = $(e.target);
  118. if (!$thisTarget.hasClass(childrenClass) && !$thisTarget.hasClass(holderClass)) {
  119. $thisTarget.addClass(childrenClass);
  120. }
  121. });
  122. $(document).on('mouseup touchend', function () {
  123. dadEnd();
  124. });
  125. // ORDER ELEMENTS
  126. var order = 1;
  127. $target.addClass(childrenClass).each(function () {
  128. if ($(this).data('dad-id') == undefined) {
  129. $(this).attr('data-dad-id', order);
  130. }
  131. $(this).attr('data-dad-position', order);
  132. order++;
  133. });
  134. // CREATE REORDER FUNCTION
  135. function updatePosition(e) {
  136. var order = 1;
  137. e.find(jQclass).each(function () {
  138. $(this).attr('data-dad-position', order);
  139. order++;
  140. });
  141. }
  142. // END EVENT
  143. function dadEnd() {
  144. if (mouse.target != false && mouse.clone != false) {
  145. if (callback != false) {
  146. callback(mouse.target);
  147. }
  148. var appear = mouse.target;
  149. var desappear = mouse.clone;
  150. var holder = mouse.placeholder;
  151. var bLeft = 0;
  152. var bTop = 0;
  153. // Maybe we will use this in the future
  154. //Math.floor(parseFloat($daddy.css('border-left-width')));
  155. //Math.floor(parseFloat($daddy.css('border-top-width')));
  156. if ($.contains($daddy[0], mouse.target[0])) {
  157. mouse.clone.animate({
  158. top: mouse.target.offset().top - $daddy.offset().top - bTop,
  159. left: mouse.target.offset().left - $daddy.offset().left - bLeft,
  160. }, 300, function () {
  161. appear.css({
  162. visibility: 'visible',
  163. }).removeClass('active');
  164. desappear.remove();
  165. });
  166. } else {
  167. mouse.clone.fadeOut(300, function () {
  168. desappear.remove();
  169. });
  170. }
  171. holder.remove();
  172. mouse.clone = false;
  173. mouse.placeholder = false;
  174. mouse.target = false;
  175. updatePosition($daddy);
  176. }
  177. $('html, body').removeClass('dad-noSelect');
  178. }
  179. // UPDATE EVENT
  180. function dadUpdate(obj) {
  181. if (mouse.target !== false && mouse.clone !== false) {
  182. var $origin = $('<span style="display:none"></span>');
  183. var $newplace = $('<span style="display:none"></span>');
  184. if (obj.prevAll().hasClass('active')) {
  185. obj.after($newplace);
  186. } else {
  187. obj.before($newplace);
  188. }
  189. mouse.target.before($origin);
  190. $newplace.before(mouse.target);
  191. // UPDATE PLACEHOLDER
  192. mouse.placeholder.css({
  193. top: mouse.target.offset().top - $daddy.offset().top,
  194. left: mouse.target.offset().left - $daddy.offset().left,
  195. width: mouse.target.outerWidth() - 10,
  196. height: mouse.target.outerHeight() - 10,
  197. });
  198. $origin.remove();
  199. $newplace.remove();
  200. }
  201. }
  202. // GRABBING EVENT
  203. var jq = (options.draggable !== false) ? options.draggable : jQclass;
  204. $daddy.find(jq).addClass(dragClass);
  205. $daddy.on('mousedown touchstart', jq, function (e) {
  206. // For touchstart we must update "mouse" position
  207. if (e.type == 'touchstart') {
  208. mouse.updatePosition(e.originalEvent.touches[0]);
  209. }
  210. if (mouse.target == false && active == true && (e.which == 1 || e.type == 'touchstart')) {
  211. var $self = $(this);
  212. // GET TARGET
  213. if (options.draggable !== false) {
  214. mouse.target = $daddy.find(jQclass).has(this);
  215. } else {
  216. mouse.target = $self;
  217. }
  218. // ADD CLONE
  219. mouse.clone = mouse.target.clone();
  220. mouse.target.css({ visibility: 'hidden' }).addClass('active');
  221. mouse.clone.addClass(cloneClass);
  222. $daddy.append(mouse.clone);
  223. // ADD PLACEHOLDER
  224. var $placeholder = $('<div></div>');
  225. mouse.placeholder = $placeholder;
  226. mouse.placeholder.addClass(holderClass);
  227. mouse.placeholder.css({
  228. top: mouse.target.offset().top - $daddy.offset().top,
  229. left: mouse.target.offset().left - $daddy.offset().left,
  230. width: mouse.target.outerWidth() - 10,
  231. height: mouse.target.outerHeight() - 10,
  232. lineHeight: mouse.target.height() - 18 + 'px',
  233. textAlign: 'center',
  234. }).text(placeholder);
  235. $daddy.append(mouse.placeholder);
  236. // GET OFFSET FOR CLONE
  237. var bLeft = Math.floor(parseFloat($daddy.css('border-left-width')));
  238. var bTop = Math.floor(parseFloat($daddy.css('border-top-width')));
  239. var difx = mouse.x - mouse.target.offset().left + $daddy.offset().left + bLeft;
  240. var dify = mouse.y - mouse.target.offset().top + $daddy.offset().top + bTop;
  241. mouse.cloneoffset.x = difx;
  242. mouse.cloneoffset.y = dify;
  243. // REMOVE THE CHILDREN DAD CLASS AND SET THE POSITION ON SCREEN
  244. mouse.clone.removeClass(childrenClass).css({
  245. position: 'absolute',
  246. top: mouse.y - mouse.cloneoffset.y,
  247. left: mouse.x - mouse.cloneoffset.x,
  248. });
  249. // UNABLE THE TEXT SELECTION AND SET THE GRAB CURSOR
  250. $('html,body').addClass('dad-noSelect');
  251. }
  252. });
  253. $daddy.on('mouseenter touchenter', jQclass, function () {
  254. dadUpdate($(this));
  255. });
  256. });
  257. return this;
  258. };
  259. })(jQuery);