API Docs for: 3.17.2
Show:

File: dd/js/ddm-drop.js

  1.  
  2. /**
  3. * Extends the dd-ddm Class to add support for the placement of Drop Target
  4. * shims inside the viewport shim. It also handles all Drop Target related events and interactions.
  5. * @module dd
  6. * @submodule dd-ddm-drop
  7. * @for DDM
  8. * @namespace DD
  9. */
  10.  
  11. //TODO CSS class name for the bestMatch..
  12. Y.mix(Y.DD.DDM, {
  13. /**
  14. * This flag turns off the use of the mouseover/mouseout shim. It should not be used unless you know what you are doing.
  15. * @private
  16. * @property _noShim
  17. * @type {Boolean}
  18. */
  19. _noShim: false,
  20. /**
  21. * Placeholder for all active shims on the page
  22. * @private
  23. * @property _activeShims
  24. * @type {Array}
  25. */
  26. _activeShims: [],
  27. /**
  28. * This method checks the _activeShims Object to see if there is a shim active.
  29. * @private
  30. * @method _hasActiveShim
  31. * @return {Boolean}
  32. */
  33. _hasActiveShim: function() {
  34. if (this._noShim) {
  35. return true;
  36. }
  37. return this._activeShims.length;
  38. },
  39. /**
  40. * Adds a Drop Target to the list of active shims
  41. * @private
  42. * @method _addActiveShim
  43. * @param {Object} d The Drop instance to add to the list.
  44. */
  45. _addActiveShim: function(d) {
  46. this._activeShims.push(d);
  47. },
  48. /**
  49. * Removes a Drop Target to the list of active shims
  50. * @private
  51. * @method _removeActiveShim
  52. * @param {Object} d The Drop instance to remove from the list.
  53. */
  54. _removeActiveShim: function(d) {
  55. var s = [];
  56. Y.Array.each(this._activeShims, function(v) {
  57. if (v._yuid !== d._yuid) {
  58. s.push(v);
  59. }
  60.  
  61. });
  62. this._activeShims = s;
  63. },
  64. /**
  65. * This method will sync the position of the shims on the Drop Targets that are currently active.
  66. * @method syncActiveShims
  67. * @param {Boolean} force Resize/sync all Targets.
  68. */
  69. syncActiveShims: function(force) {
  70. Y.later(0, this, function(force) {
  71. var drops = ((force) ? this.targets : this._lookup());
  72. Y.Array.each(drops, function(v) {
  73. v.sizeShim.call(v);
  74. }, this);
  75. }, force);
  76. },
  77. /**
  78. * The mode that the drag operations will run in 0 for Point, 1 for Intersect, 2 for Strict
  79. * @private
  80. * @property mode
  81. * @type Number
  82. */
  83. mode: 0,
  84. /**
  85. * In point mode, a Drop is targeted by the cursor being over the Target
  86. * @private
  87. * @property POINT
  88. * @type Number
  89. */
  90. POINT: 0,
  91. /**
  92. * In intersect mode, a Drop is targeted by "part" of the drag node being over the Target
  93. * @private
  94. * @property INTERSECT
  95. * @type Number
  96. */
  97. INTERSECT: 1,
  98. /**
  99. * In strict mode, a Drop is targeted by the "entire" drag node being over the Target
  100. * @private
  101. * @property STRICT
  102. * @type Number
  103. */
  104. STRICT: 2,
  105. /**
  106. * Should we only check targets that are in the viewport on drags (for performance), default: true
  107. * @property useHash
  108. * @type {Boolean}
  109. */
  110. useHash: true,
  111. /**
  112. * A reference to the active Drop Target
  113. * @property activeDrop
  114. * @type {Object}
  115. */
  116. activeDrop: null,
  117. /**
  118. * An array of the valid Drop Targets for this interaction.
  119. * @property validDrops
  120. * @type {Array}
  121. */
  122. //TODO Change array/object literals to be in sync..
  123. validDrops: [],
  124. /**
  125. * An object literal of Other Drop Targets that we encountered during this interaction (in the case of overlapping Drop Targets)
  126. * @property otherDrops
  127. * @type {Object}
  128. */
  129. otherDrops: {},
  130. /**
  131. * All of the Targets
  132. * @property targets
  133. * @type {Array}
  134. */
  135. targets: [],
  136. /**
  137. * Add a Drop Target to the list of Valid Targets. This list get's regenerated on each new drag operation.
  138. * @private
  139. * @method _addValid
  140. * @param {Object} drop
  141. * @chainable
  142. */
  143. _addValid: function(drop) {
  144. this.validDrops.push(drop);
  145. return this;
  146. },
  147. /**
  148. * Removes a Drop Target from the list of Valid Targets. This list get's regenerated on each new drag operation.
  149. * @private
  150. * @method _removeValid
  151. * @param {Object} drop
  152. * @chainable
  153. */
  154. _removeValid: function(drop) {
  155. var drops = [];
  156. Y.Array.each(this.validDrops, function(v) {
  157. if (v !== drop) {
  158. drops.push(v);
  159. }
  160. });
  161.  
  162. this.validDrops = drops;
  163. return this;
  164. },
  165. /**
  166. * Check to see if the Drag element is over the target, method varies on current mode
  167. * @method isOverTarget
  168. * @param {Object} drop The drop to check against
  169. * @return {Boolean}
  170. */
  171. isOverTarget: function(drop) {
  172. if (this.activeDrag && drop) {
  173. var xy = this.activeDrag.mouseXY, r, dMode = this.activeDrag.get('dragMode'),
  174. aRegion, node = drop.shim;
  175. if (xy && this.activeDrag) {
  176. aRegion = this.activeDrag.region;
  177. if (dMode === this.STRICT) {
  178. return this.activeDrag.get('dragNode').inRegion(drop.region, true, aRegion);
  179. }
  180. if (drop && drop.shim) {
  181. if ((dMode === this.INTERSECT) && this._noShim) {
  182. r = aRegion || this.activeDrag.get('node');
  183. return drop.get('node').intersect(r, drop.region).inRegion;
  184. }
  185.  
  186. if (this._noShim) {
  187. node = drop.get('node');
  188. }
  189. return node.intersect({
  190. top: xy[1],
  191. bottom: xy[1],
  192. left: xy[0],
  193. right: xy[0]
  194. }, drop.region).inRegion;
  195. }
  196. }
  197. }
  198. return false;
  199. },
  200. /**
  201. * Clears the cache data used for this interaction.
  202. * @method clearCache
  203. */
  204. clearCache: function() {
  205. this.validDrops = [];
  206. this.otherDrops = {};
  207. this._activeShims = [];
  208. },
  209. /**
  210. * Clear the cache and activate the shims of all the targets
  211. * @private
  212. * @method _activateTargets
  213. */
  214. _activateTargets: function() {
  215. this._noShim = true;
  216. this.clearCache();
  217. Y.Array.each(this.targets, function(v) {
  218. v._activateShim([]);
  219. if (v.get('noShim') === true) {
  220. this._noShim = false;
  221. }
  222. }, this);
  223. this._handleTargetOver();
  224.  
  225. },
  226. /**
  227. * This method will gather the area for all potential targets and see which has the hightest covered area and return it.
  228. * @method getBestMatch
  229. * @param {Array} drops An Array of drops to scan for the best match.
  230. * @param {Boolean} all If present, it returns an Array. First item is best match, second is an Array of the other items in the original Array.
  231. * @return {Object or Array}
  232. */
  233. getBestMatch: function(drops, all) {
  234. var biggest = null, area = 0, out;
  235.  
  236. Y.Object.each(drops, function(v) {
  237. var inter = this.activeDrag.get('dragNode').intersect(v.get('node'));
  238. v.region.area = inter.area;
  239.  
  240. if (inter.inRegion) {
  241. if (inter.area > area) {
  242. area = inter.area;
  243. biggest = v;
  244. }
  245. }
  246. }, this);
  247. if (all) {
  248. out = [];
  249. //TODO Sort the others in numeric order by area covered..
  250. Y.Object.each(drops, function(v) {
  251. if (v !== biggest) {
  252. out.push(v);
  253. }
  254. }, this);
  255. return [biggest, out];
  256. }
  257. return biggest;
  258. },
  259. /**
  260. * This method fires the drop:hit, drag:drophit, drag:dropmiss methods and deactivates the shims..
  261. * @private
  262. * @method _deactivateTargets
  263. */
  264. _deactivateTargets: function() {
  265. var other = [], tmp,
  266. activeDrag = this.activeDrag,
  267. activeDrop = this.activeDrop;
  268.  
  269. //TODO why is this check so hard??
  270. if (activeDrag && activeDrop && this.otherDrops[activeDrop]) {
  271. if (!activeDrag.get('dragMode')) {
  272. //TODO otherDrops -- private..
  273. other = this.otherDrops;
  274. delete other[activeDrop];
  275. } else {
  276. tmp = this.getBestMatch(this.otherDrops, true);
  277. activeDrop = tmp[0];
  278. other = tmp[1];
  279. }
  280. activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over');
  281. if (activeDrop) {
  282. activeDrop.fire('drop:hit', { drag: activeDrag, drop: activeDrop, others: other });
  283. activeDrag.fire('drag:drophit', { drag: activeDrag, drop: activeDrop, others: other });
  284. }
  285. } else if (activeDrag && activeDrag.get('dragging')) {
  286. activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over');
  287. activeDrag.fire('drag:dropmiss', { pageX: activeDrag.lastXY[0], pageY: activeDrag.lastXY[1] });
  288. }
  289.  
  290. this.activeDrop = null;
  291.  
  292. Y.Array.each(this.targets, function(v) {
  293. v._deactivateShim([]);
  294. }, this);
  295. },
  296. /**
  297. * This method is called when the move method is called on the Drag Object.
  298. * @private
  299. * @method _dropMove
  300. */
  301. _dropMove: function() {
  302. if (this._hasActiveShim()) {
  303. this._handleTargetOver();
  304. } else {
  305. Y.Object.each(this.otherDrops, function(v) {
  306. v._handleOut.apply(v, []);
  307. });
  308. }
  309. },
  310. /**
  311. * Filters the list of Drops down to those in the viewport.
  312. * @private
  313. * @method _lookup
  314. * @return {Array} The valid Drop Targets that are in the viewport.
  315. */
  316. _lookup: function() {
  317. if (!this.useHash || this._noShim) {
  318. return this.validDrops;
  319. }
  320. var drops = [];
  321. //Only scan drop shims that are in the Viewport
  322. Y.Array.each(this.validDrops, function(v) {
  323. if (v.shim && v.shim.inViewportRegion(false, v.region)) {
  324. drops.push(v);
  325. }
  326. });
  327. return drops;
  328.  
  329. },
  330. /**
  331. * This method execs _handleTargetOver on all valid Drop Targets
  332. * @private
  333. * @method _handleTargetOver
  334. */
  335. _handleTargetOver: function() {
  336. var drops = this._lookup();
  337. Y.Array.each(drops, function(v) {
  338. v._handleTargetOver.call(v);
  339. }, this);
  340. },
  341. /**
  342. * Add the passed in Target to the targets collection
  343. * @private
  344. * @method _regTarget
  345. * @param {Object} t The Target to add to the targets collection
  346. */
  347. _regTarget: function(t) {
  348. this.targets.push(t);
  349. },
  350. /**
  351. * Remove the passed in Target from the targets collection
  352. * @private
  353. * @method _unregTarget
  354. * @param {Object} drop The Target to remove from the targets collection
  355. */
  356. _unregTarget: function(drop) {
  357. var targets = [], vdrops;
  358. Y.Array.each(this.targets, function(v) {
  359. if (v !== drop) {
  360. targets.push(v);
  361. }
  362. }, this);
  363. this.targets = targets;
  364.  
  365. vdrops = [];
  366. Y.Array.each(this.validDrops, function(v) {
  367. if (v !== drop) {
  368. vdrops.push(v);
  369. }
  370. });
  371.  
  372. this.validDrops = vdrops;
  373. },
  374. /**
  375. * Get a valid Drop instance back from a Node or a selector string, false otherwise
  376. * @method getDrop
  377. * @param {String/Object} node The Node instance or Selector string to check for a valid Drop Object
  378. * @return {Object}
  379. */
  380. getDrop: function(node) {
  381. var drop = false,
  382. n = Y.one(node);
  383. if (n instanceof Y.Node) {
  384. Y.Array.each(this.targets, function(v) {
  385. if (n.compareTo(v.get('node'))) {
  386. drop = v;
  387. }
  388. });
  389. }
  390. return drop;
  391. }
  392. }, true);
  393.  
  394.  
  395.