PageRenderTime 57ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/vendor/angular/angular-dragdrop.js

https://github.com/tarek-salah/banana
JavaScript | 304 lines | 260 code | 36 blank | 8 comment | 75 complexity | e2945745a59e22f6e6cf018518fe3763 MD5 | raw file
Possible License(s): Apache-2.0
  1. /*
  2. This has been modified from the default angular-draganddrop to provide the original
  3. model and some other stuff as the 'data' arguement to callEventCallback
  4. */
  5. (function (window, angular, undefined) {
  6. 'use strict';
  7. var jqyoui = angular.module('ngDragDrop', []).service('ngDragDropService', ['$timeout', '$parse', function($timeout, $parse) {
  8. this.callEventCallback = function (scope, callbackName, event, ui, data) {
  9. if (!callbackName) {
  10. return;
  11. }
  12. var args = [event, ui, data];
  13. var match = callbackName.match(/^(.+)\((.+)\)$/);
  14. if (match !== null) {
  15. callbackName = match[1];
  16. var values = eval('[' + match[0].replace(/^(.+)\(/, '').replace(/\)/, '') + ']');
  17. args.push.apply(args, values);
  18. }
  19. if(scope[callbackName]) {
  20. scope[callbackName].apply(scope, args);
  21. }
  22. };
  23. this.invokeDrop = function ($draggable, $droppable, event, ui) {
  24. var dragModel = '',
  25. dropModel = '',
  26. dragSettings = {},
  27. dropSettings = {},
  28. jqyoui_pos = null,
  29. dragItem = {},
  30. dropItem = {},
  31. dragModelValue,
  32. dropModelValue,
  33. $droppableDraggable = null,
  34. droppableScope = $droppable.scope(),
  35. draggableScope = $draggable.scope(),
  36. data = {};
  37. dragModel = $draggable.ngattr('ng-model');
  38. dropModel = $droppable.ngattr('ng-model');
  39. dragModelValue = draggableScope.$eval(dragModel);
  40. dropModelValue = droppableScope.$eval(dropModel);
  41. $droppableDraggable = $droppable.find('[jqyoui-draggable]:last');
  42. dropSettings = droppableScope.$eval($droppable.attr('jqyoui-droppable')) || [];
  43. dragSettings = draggableScope.$eval($draggable.attr('jqyoui-draggable')) || [];
  44. // Helps pick up the right item
  45. dragSettings.index = this.fixIndex(draggableScope, dragSettings, dragModelValue);
  46. dropSettings.index = this.fixIndex(droppableScope, dropSettings, dropModelValue);
  47. jqyoui_pos = angular.isArray(dragModelValue) ? dragSettings.index : null;
  48. dragItem = angular.isArray(dragModelValue) ? dragModelValue[jqyoui_pos] : dragModelValue;
  49. if (angular.isArray(dropModelValue) && dropSettings && dropSettings.index !== undefined) {
  50. dropItem = dropModelValue[dropSettings.index];
  51. } else if (!angular.isArray(dropModelValue)) {
  52. dropItem = dropModelValue;
  53. } else {
  54. dropItem = {};
  55. }
  56. data = {
  57. dragModel: dragModel,
  58. dropModel: dropModel,
  59. dragSettings: dragSettings,
  60. dropSettings: dropSettings,
  61. jqyoui_pos: jqyoui_pos,
  62. dragItem: dragItem,
  63. dropItem: dropItem,
  64. dragModelValue: dragModelValue,
  65. dropModelValue: dropModelValue,
  66. droppableScope: $droppable.scope(),
  67. draggableScope: $draggable.scope()
  68. };
  69. if (dragSettings.animate === true) {
  70. this.move($draggable, $droppableDraggable.length > 0 ? $droppableDraggable : $droppable, null, 'fast', dropSettings, null);
  71. this.move($droppableDraggable.length > 0 && !dropSettings.multiple ? $droppableDraggable : [], $draggable.parent('[jqyoui-droppable]'), jqyoui.startXY, 'fast', dropSettings, function() {
  72. $timeout(function() {
  73. // Do not move this into move() to avoid flickering issue
  74. $draggable.css({'position': 'relative', 'left': '', 'top': ''});
  75. $droppableDraggable.css({'position': 'relative', 'left': '', 'top': ''});
  76. if(dragSettings.mutate !== false) {
  77. this.mutateDraggable(draggableScope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable);
  78. }
  79. if(dropSettings.mutate !== false) {
  80. this.mutateDroppable(droppableScope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos);
  81. }
  82. this.callEventCallback(droppableScope, dropSettings.onDrop, event, ui, data);
  83. }.bind(this));
  84. }.bind(this));
  85. } else {
  86. $timeout(function() {
  87. if(dragSettings.mutate !== false) {
  88. this.mutateDraggable(draggableScope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable);
  89. }
  90. if(dropSettings.mutate !== false) {
  91. this.mutateDroppable(droppableScope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos);
  92. }
  93. this.callEventCallback(droppableScope, dropSettings.onDrop, event, ui, data);
  94. }.bind(this));
  95. }
  96. };
  97. this.move = function($fromEl, $toEl, toPos, duration, dropSettings, callback) {
  98. if ($fromEl.length === 0) {
  99. if (callback) {
  100. window.setTimeout(function() {
  101. callback();
  102. }, 300);
  103. }
  104. return false;
  105. }
  106. var zIndex = 9999,
  107. fromPos = $fromEl.offset(),
  108. wasVisible = $toEl && $toEl.is(':visible');
  109. if (toPos === null && $toEl.length > 0) {
  110. if ($toEl.attr('jqyoui-draggable') !== undefined && $toEl.ngattr('ng-model') !== undefined && $toEl.is(':visible') && dropSettings && dropSettings.multiple) {
  111. toPos = $toEl.offset();
  112. if (dropSettings.stack === false) {
  113. toPos.left+= $toEl.outerWidth(true);
  114. } else {
  115. toPos.top+= $toEl.outerHeight(true);
  116. }
  117. } else {
  118. toPos = $toEl.css({'visibility': 'hidden', 'display': 'block'}).offset();
  119. $toEl.css({'visibility': '','display': wasVisible ? '' : 'none'});
  120. }
  121. }
  122. $fromEl.css({'position': 'absolute', 'z-index': zIndex})
  123. .css(fromPos)
  124. .animate(toPos, duration, function() {
  125. if (callback) callback();
  126. });
  127. };
  128. this.mutateDroppable = function(scope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos) {
  129. var dropModelValue = scope.$eval(dropModel);
  130. scope.__dragItem = dragItem;
  131. if (angular.isArray(dropModelValue)) {
  132. if (dropSettings && dropSettings.index >= 0) {
  133. dropModelValue[dropSettings.index] = dragItem;
  134. } else {
  135. dropModelValue.push(dragItem);
  136. }
  137. if (dragSettings && dragSettings.placeholder === true) {
  138. dropModelValue[dropModelValue.length - 1]['jqyoui_pos'] = jqyoui_pos;
  139. }
  140. } else {
  141. $parse(dropModel + ' = __dragItem')(scope);
  142. if (dragSettings && dragSettings.placeholder === true) {
  143. dropModelValue['jqyoui_pos'] = jqyoui_pos;
  144. }
  145. }
  146. };
  147. this.mutateDraggable = function(scope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable) {
  148. var isEmpty = angular.equals(angular.copy(dropItem), {}),
  149. dragModelValue = scope.$eval(dragModel);
  150. scope.__dropItem = dropItem;
  151. if (dragSettings && dragSettings.placeholder) {
  152. if (dragSettings.placeholder != 'keep'){
  153. if (angular.isArray(dragModelValue) && dragSettings.index !== undefined) {
  154. dragModelValue[dragSettings.index] = dropItem;
  155. } else {
  156. $parse(dragModel + ' = __dropItem')(scope);
  157. }
  158. }
  159. } else {
  160. if (angular.isArray(dragModelValue)) {
  161. if (isEmpty) {
  162. if (dragSettings && ( dragSettings.placeholder !== true && dragSettings.placeholder !== 'keep' )) {
  163. dragModelValue.splice(dragSettings.index, 1);
  164. }
  165. } else {
  166. dragModelValue[dragSettings.index] = dropItem;
  167. }
  168. } else {
  169. // Fix: LIST(object) to LIST(array) - model does not get updated using just scope[dragModel] = {...}
  170. // P.S.: Could not figure out why it happened
  171. $parse(dragModel + ' = __dropItem')(scope);
  172. if (scope.$parent) {
  173. $parse(dragModel + ' = __dropItem')(scope.$parent);
  174. }
  175. }
  176. }
  177. $draggable.css({'z-index': '', 'left': '', 'top': ''});
  178. };
  179. this.fixIndex = function(scope, settings, modelValue) {
  180. if (settings.applyFilter && angular.isArray(modelValue) && modelValue.length > 0) {
  181. var dragModelValueFiltered = scope[settings.applyFilter](),
  182. lookup = dragModelValueFiltered[settings.index],
  183. actualIndex = undefined;
  184. modelValue.forEach(function(item, i) {
  185. if (angular.equals(item, lookup)) {
  186. actualIndex = i;
  187. }
  188. });
  189. return actualIndex;
  190. }
  191. return settings.index;
  192. };
  193. }]).directive('jqyouiDraggable', ['ngDragDropService', function(ngDragDropService) {
  194. return {
  195. require: '?jqyouiDroppable',
  196. restrict: 'A',
  197. link: function(scope, element, attrs) {
  198. var dragSettings, zIndex;
  199. var updateDraggable = function(newValue, oldValue) {
  200. if (newValue) {
  201. dragSettings = scope.$eval(element.attr('jqyoui-draggable')) || [];
  202. element
  203. .draggable({disabled: false})
  204. .draggable(scope.$eval(attrs.jqyouiOptions) || {})
  205. .draggable({
  206. start: function(event, ui) {
  207. zIndex = angular.element(this).css('z-index');
  208. angular.element(this).css('z-index', 99999);
  209. jqyoui.startXY = angular.element(this).offset();
  210. ngDragDropService.callEventCallback(scope, dragSettings.onStart, event, ui);
  211. },
  212. stop: function(event, ui) {
  213. angular.element(this).css('z-index', zIndex);
  214. ngDragDropService.callEventCallback(scope, dragSettings.onStop, event, ui);
  215. },
  216. drag: function(event, ui) {
  217. ngDragDropService.callEventCallback(scope, dragSettings.onDrag, event, ui);
  218. }
  219. });
  220. } else {
  221. element.draggable({disabled: true});
  222. }
  223. };
  224. scope.$watch(function() { return scope.$eval(attrs.drag); }, updateDraggable);
  225. updateDraggable();
  226. }
  227. };
  228. }]).directive('jqyouiDroppable', ['ngDragDropService', function(ngDragDropService) {
  229. return {
  230. restrict: 'A',
  231. priority: 1,
  232. link: function(scope, element, attrs) {
  233. var updateDroppable = function(newValue, oldValue) {
  234. if (newValue) {
  235. element
  236. .droppable({disabled: false})
  237. .droppable(scope.$eval(attrs.jqyouiOptions) || {})
  238. .droppable({
  239. over: function(event, ui) {
  240. var dropSettings = scope.$eval(angular.element(this).attr('jqyoui-droppable')) || [];
  241. ngDragDropService.callEventCallback(scope, dropSettings.onOver, event, ui);
  242. },
  243. out: function(event, ui) {
  244. var dropSettings = scope.$eval(angular.element(this).attr('jqyoui-droppable')) || [];
  245. ngDragDropService.callEventCallback(scope, dropSettings.onOut, event, ui);
  246. },
  247. drop: function(event, ui) {
  248. if (angular.element(ui.draggable).ngattr('ng-model') && attrs.ngModel) {
  249. ngDragDropService.invokeDrop(angular.element(ui.draggable), angular.element(this), event, ui);
  250. } else {
  251. ngDragDropService.callEventCallback(scope, (scope.$eval(angular.element(this).attr('jqyoui-droppable')) || []).onDrop, event, ui);
  252. }
  253. }
  254. });
  255. } else {
  256. element.droppable({disabled: true});
  257. }
  258. };
  259. scope.$watch(function() { return scope.$eval(attrs.drop); }, updateDroppable);
  260. updateDroppable();
  261. }
  262. };
  263. }]);
  264. $.fn.ngattr = function(name, value) {
  265. var element = angular.element(this).get(0);
  266. return element.getAttribute(name) || element.getAttribute('data-' + name);
  267. };
  268. })(window, window.angular);