Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dd-drop.js 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. /*
  2. Copyright (c) 2010, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.com/yui/license.html
  5. version: 3.4.0
  6. build: nightly
  7. */
  8. YUI.add('dd-drop', function(Y) {
  9. /**
  10. * Provides the ability to create a Drop Target.
  11. * @module dd
  12. * @submodule dd-drop
  13. */
  14. /**
  15. * Provides the ability to create a Drop Target.
  16. * @class Drop
  17. * @extends Base
  18. * @constructor
  19. * @namespace DD
  20. */
  21. var NODE = 'node',
  22. DDM = Y.DD.DDM,
  23. OFFSET_HEIGHT = 'offsetHeight',
  24. OFFSET_WIDTH = 'offsetWidth',
  25. /**
  26. * @event drop:over
  27. * @description Fires when a drag element is over this target.
  28. * @param {EventFacade} event An Event Facade object with the following specific property added:
  29. * <dl>
  30. * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
  31. * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
  32. * </dl>
  33. * @bubbles DDM
  34. * @type {CustomEvent}
  35. */
  36. EV_DROP_OVER = 'drop:over',
  37. /**
  38. * @event drop:enter
  39. * @description Fires when a drag element enters this target.
  40. * @param {EventFacade} event An Event Facade object with the following specific property added:
  41. * <dl>
  42. * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
  43. * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
  44. * </dl>
  45. * @bubbles DDM
  46. * @type {CustomEvent}
  47. */
  48. EV_DROP_ENTER = 'drop:enter',
  49. /**
  50. * @event drop:exit
  51. * @description Fires when a drag element exits this target.
  52. * @param {EventFacade} event An Event Facade object
  53. * @bubbles DDM
  54. * @type {CustomEvent}
  55. */
  56. EV_DROP_EXIT = 'drop:exit',
  57. /**
  58. * @event drop:hit
  59. * @description Fires when a draggable node is dropped on this Drop Target. (Fired from dd-ddm-drop)
  60. * @param {EventFacade} event An Event Facade object with the following specific property added:
  61. * <dl>
  62. * <dt>drop</dt><dd>The best guess on what was dropped on.</dd>
  63. * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
  64. * <dt>others</dt><dd>An array of all the other drop targets that was dropped on.</dd>
  65. * </dl>
  66. * @bubbles DDM
  67. * @type {CustomEvent}
  68. */
  69. Drop = function() {
  70. this._lazyAddAttrs = false;
  71. Drop.superclass.constructor.apply(this, arguments);
  72. //DD init speed up.
  73. Y.on('domready', Y.bind(function() {
  74. Y.later(100, this, this._createShim);
  75. }, this));
  76. DDM._regTarget(this);
  77. /* TODO
  78. if (Dom.getStyle(this.el, 'position') == 'fixed') {
  79. Event.on(window, 'scroll', function() {
  80. this.activateShim();
  81. }, this, true);
  82. }
  83. */
  84. };
  85. Drop.NAME = 'drop';
  86. Drop.ATTRS = {
  87. /**
  88. * @attribute node
  89. * @description Y.Node instanace to use as the element to make a Drop Target
  90. * @type Node
  91. */
  92. node: {
  93. setter: function(node) {
  94. var n = Y.one(node);
  95. if (!n) {
  96. Y.error('DD.Drop: Invalid Node Given: ' + node);
  97. }
  98. return n;
  99. }
  100. },
  101. /**
  102. * @attribute groups
  103. * @description Array of groups to add this drop into.
  104. * @type Array
  105. */
  106. groups: {
  107. value: ['default'],
  108. setter: function(g) {
  109. this._groups = {};
  110. Y.each(g, function(v, k) {
  111. this._groups[v] = true;
  112. }, this);
  113. return g;
  114. }
  115. },
  116. /**
  117. * @attribute padding
  118. * @description CSS style padding to make the Drop Target bigger than the node.
  119. * @type String
  120. */
  121. padding: {
  122. value: '0',
  123. setter: function(p) {
  124. return DDM.cssSizestoObject(p);
  125. }
  126. },
  127. /**
  128. * @attribute lock
  129. * @description Set to lock this drop element.
  130. * @type Boolean
  131. */
  132. lock: {
  133. value: false,
  134. setter: function(lock) {
  135. if (lock) {
  136. this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-locked');
  137. } else {
  138. this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-locked');
  139. }
  140. return lock;
  141. }
  142. },
  143. /**
  144. * @deprecated
  145. * @attribute bubbles
  146. * @description Controls the default bubble parent for this Drop instance. Default: Y.DD.DDM. Set to false to disable bubbling. Use bubbleTargets in config.
  147. * @type Object
  148. */
  149. bubbles: {
  150. setter: function(t) {
  151. this.addTarget(t);
  152. return t;
  153. }
  154. },
  155. /**
  156. * @deprecated
  157. * @attribute useShim
  158. * @description Use the Drop shim. Default: true
  159. * @type Boolean
  160. */
  161. useShim: {
  162. value: true,
  163. setter: function(v) {
  164. Y.DD.DDM._noShim = !v;
  165. return v;
  166. }
  167. }
  168. };
  169. Y.extend(Drop, Y.Base, {
  170. /**
  171. * @private
  172. * @property _bubbleTargets
  173. * @description The default bubbleTarget for this object. Default: Y.DD.DDM
  174. */
  175. _bubbleTargets: Y.DD.DDM,
  176. /**
  177. * @method addToGroup
  178. * @description Add this Drop instance to a group, this should be used for on-the-fly group additions.
  179. * @param {String} g The group to add this Drop Instance to.
  180. * @return {Self}
  181. * @chainable
  182. */
  183. addToGroup: function(g) {
  184. this._groups[g] = true;
  185. return this;
  186. },
  187. /**
  188. * @method removeFromGroup
  189. * @description Remove this Drop instance from a group, this should be used for on-the-fly group removals.
  190. * @param {String} g The group to remove this Drop Instance from.
  191. * @return {Self}
  192. * @chainable
  193. */
  194. removeFromGroup: function(g) {
  195. delete this._groups[g];
  196. return this;
  197. },
  198. /**
  199. * @private
  200. * @method _createEvents
  201. * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
  202. */
  203. _createEvents: function() {
  204. var ev = [
  205. EV_DROP_OVER,
  206. EV_DROP_ENTER,
  207. EV_DROP_EXIT,
  208. 'drop:hit'
  209. ];
  210. Y.each(ev, function(v, k) {
  211. this.publish(v, {
  212. type: v,
  213. emitFacade: true,
  214. preventable: false,
  215. bubbles: true,
  216. queuable: false,
  217. prefix: 'drop'
  218. });
  219. }, this);
  220. },
  221. /**
  222. * @private
  223. * @property _valid
  224. * @description Flag for determining if the target is valid in this operation.
  225. * @type Boolean
  226. */
  227. _valid: null,
  228. /**
  229. * @private
  230. * @property _groups
  231. * @description The groups this target belongs to.
  232. * @type Array
  233. */
  234. _groups: null,
  235. /**
  236. * @property shim
  237. * @description Node reference to the targets shim
  238. * @type {Object}
  239. */
  240. shim: null,
  241. /**
  242. * @property region
  243. * @description A region object associated with this target, used for checking regions while dragging.
  244. * @type Object
  245. */
  246. region: null,
  247. /**
  248. * @property overTarget
  249. * @description This flag is tripped when a drag element is over this target.
  250. * @type Boolean
  251. */
  252. overTarget: null,
  253. /**
  254. * @method inGroup
  255. * @description Check if this target is in one of the supplied groups.
  256. * @param {Array} groups The groups to check against
  257. * @return Boolean
  258. */
  259. inGroup: function(groups) {
  260. this._valid = false;
  261. var ret = false;
  262. Y.each(groups, function(v, k) {
  263. if (this._groups[v]) {
  264. ret = true;
  265. this._valid = true;
  266. }
  267. }, this);
  268. return ret;
  269. },
  270. /**
  271. * @private
  272. * @method initializer
  273. * @description Private lifecycle method
  274. */
  275. initializer: function(cfg) {
  276. Y.later(100, this, this._createEvents);
  277. var node = this.get(NODE), id;
  278. if (!node.get('id')) {
  279. id = Y.stamp(node);
  280. node.set('id', id);
  281. }
  282. node.addClass(DDM.CSS_PREFIX + '-drop');
  283. //Shouldn't have To Do this..
  284. this.set('groups', this.get('groups'));
  285. },
  286. /**
  287. * @private
  288. * @method destructor
  289. * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners
  290. */
  291. destructor: function() {
  292. DDM._unregTarget(this);
  293. if (this.shim && (this.shim !== this.get(NODE))) {
  294. this.shim.detachAll();
  295. this.shim.remove();
  296. this.shim = null;
  297. }
  298. this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop');
  299. this.detachAll();
  300. },
  301. /**
  302. * @private
  303. * @method _deactivateShim
  304. * @description Removes classes from the target, resets some flags and sets the shims deactive position [-999, -999]
  305. */
  306. _deactivateShim: function() {
  307. if (!this.shim) {
  308. return false;
  309. }
  310. this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
  311. this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
  312. this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
  313. if (this.get('useShim')) {
  314. this.shim.setStyles({
  315. top: '-999px',
  316. left: '-999px',
  317. zIndex: '1'
  318. });
  319. }
  320. this.overTarget = false;
  321. },
  322. /**
  323. * @private
  324. * @method _activateShim
  325. * @description Activates the shim and adds some interaction CSS classes
  326. */
  327. _activateShim: function() {
  328. if (!DDM.activeDrag) {
  329. return false; //Nothing is dragging, no reason to activate.
  330. }
  331. if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
  332. return false;
  333. }
  334. if (this.get('lock')) {
  335. return false;
  336. }
  337. var node = this.get(NODE);
  338. //TODO Visibility Check..
  339. //if (this.inGroup(DDM.activeDrag.get('groups')) && this.get(NODE).isVisible()) {
  340. if (this.inGroup(DDM.activeDrag.get('groups'))) {
  341. node.removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
  342. node.addClass(DDM.CSS_PREFIX + '-drop-active-valid');
  343. DDM._addValid(this);
  344. this.overTarget = false;
  345. if (!this.get('useShim')) {
  346. this.shim = this.get(NODE);
  347. }
  348. this.sizeShim();
  349. } else {
  350. DDM._removeValid(this);
  351. node.removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
  352. node.addClass(DDM.CSS_PREFIX + '-drop-active-invalid');
  353. }
  354. },
  355. /**
  356. * @method sizeShim
  357. * @description Positions and sizes the shim with the raw data from the node, this can be used to programatically adjust the Targets shim for Animation..
  358. */
  359. sizeShim: function() {
  360. if (!DDM.activeDrag) {
  361. return false; //Nothing is dragging, no reason to activate.
  362. }
  363. if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
  364. return false;
  365. }
  366. //if (this.get('lock') || !this.get('useShim')) {
  367. if (this.get('lock')) {
  368. return false;
  369. }
  370. if (!this.shim) {
  371. Y.later(100, this, this.sizeShim);
  372. return false;
  373. }
  374. var node = this.get(NODE),
  375. nh = node.get(OFFSET_HEIGHT),
  376. nw = node.get(OFFSET_WIDTH),
  377. xy = node.getXY(),
  378. p = this.get('padding'),
  379. dd, dH, dW;
  380. //Apply padding
  381. nw = nw + p.left + p.right;
  382. nh = nh + p.top + p.bottom;
  383. xy[0] = xy[0] - p.left;
  384. xy[1] = xy[1] - p.top;
  385. if (DDM.activeDrag.get('dragMode') === DDM.INTERSECT) {
  386. //Intersect Mode, make the shim bigger
  387. dd = DDM.activeDrag;
  388. dH = dd.get(NODE).get(OFFSET_HEIGHT);
  389. dW = dd.get(NODE).get(OFFSET_WIDTH);
  390. nh = (nh + dH);
  391. nw = (nw + dW);
  392. xy[0] = xy[0] - (dW - dd.deltaXY[0]);
  393. xy[1] = xy[1] - (dH - dd.deltaXY[1]);
  394. }
  395. if (this.get('useShim')) {
  396. //Set the style on the shim
  397. this.shim.setStyles({
  398. height: nh + 'px',
  399. width: nw + 'px',
  400. top: xy[1] + 'px',
  401. left: xy[0] + 'px'
  402. });
  403. }
  404. //Create the region to be used by intersect when a drag node is over us.
  405. this.region = {
  406. '0': xy[0],
  407. '1': xy[1],
  408. area: 0,
  409. top: xy[1],
  410. right: xy[0] + nw,
  411. bottom: xy[1] + nh,
  412. left: xy[0]
  413. };
  414. },
  415. /**
  416. * @private
  417. * @method _createShim
  418. * @description Creates the Target shim and adds it to the DDM's playground..
  419. */
  420. _createShim: function() {
  421. //No playground, defer
  422. if (!DDM._pg) {
  423. Y.later(10, this, this._createShim);
  424. return;
  425. }
  426. //Shim already here, cancel
  427. if (this.shim) {
  428. return;
  429. }
  430. var s = this.get('node');
  431. if (this.get('useShim')) {
  432. s = Y.Node.create('<div id="' + this.get(NODE).get('id') + '_shim"></div>');
  433. s.setStyles({
  434. height: this.get(NODE).get(OFFSET_HEIGHT) + 'px',
  435. width: this.get(NODE).get(OFFSET_WIDTH) + 'px',
  436. backgroundColor: 'yellow',
  437. opacity: '.5',
  438. zIndex: '1',
  439. overflow: 'hidden',
  440. top: '-900px',
  441. left: '-900px',
  442. position: 'absolute'
  443. });
  444. DDM._pg.appendChild(s);
  445. s.on('mouseover', Y.bind(this._handleOverEvent, this));
  446. s.on('mouseout', Y.bind(this._handleOutEvent, this));
  447. }
  448. this.shim = s;
  449. },
  450. /**
  451. * @private
  452. * @method _handleOverTarget
  453. * @description This handles the over target call made from this object or from the DDM
  454. */
  455. _handleTargetOver: function() {
  456. if (DDM.isOverTarget(this)) {
  457. this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-over');
  458. DDM.activeDrop = this;
  459. DDM.otherDrops[this] = this;
  460. if (this.overTarget) {
  461. DDM.activeDrag.fire('drag:over', { drop: this, drag: DDM.activeDrag });
  462. this.fire(EV_DROP_OVER, { drop: this, drag: DDM.activeDrag });
  463. } else {
  464. //Prevent an enter before a start..
  465. if (DDM.activeDrag.get('dragging')) {
  466. this.overTarget = true;
  467. this.fire(EV_DROP_ENTER, { drop: this, drag: DDM.activeDrag });
  468. DDM.activeDrag.fire('drag:enter', { drop: this, drag: DDM.activeDrag });
  469. DDM.activeDrag.get(NODE).addClass(DDM.CSS_PREFIX + '-drag-over');
  470. //TODO - Is this needed??
  471. //DDM._handleTargetOver();
  472. }
  473. }
  474. } else {
  475. this._handleOut();
  476. }
  477. },
  478. /**
  479. * @private
  480. * @method _handleOverEvent
  481. * @description Handles the mouseover DOM event on the Target Shim
  482. */
  483. _handleOverEvent: function() {
  484. this.shim.setStyle('zIndex', '999');
  485. DDM._addActiveShim(this);
  486. },
  487. /**
  488. * @private
  489. * @method _handleOutEvent
  490. * @description Handles the mouseout DOM event on the Target Shim
  491. */
  492. _handleOutEvent: function() {
  493. this.shim.setStyle('zIndex', '1');
  494. DDM._removeActiveShim(this);
  495. },
  496. /**
  497. * @private
  498. * @method _handleOut
  499. * @description Handles out of target calls/checks
  500. */
  501. _handleOut: function(force) {
  502. if (!DDM.isOverTarget(this) || force) {
  503. if (this.overTarget) {
  504. this.overTarget = false;
  505. if (!force) {
  506. DDM._removeActiveShim(this);
  507. }
  508. if (DDM.activeDrag) {
  509. this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
  510. DDM.activeDrag.get(NODE).removeClass(DDM.CSS_PREFIX + '-drag-over');
  511. this.fire(EV_DROP_EXIT);
  512. DDM.activeDrag.fire('drag:exit', { drop: this });
  513. delete DDM.otherDrops[this];
  514. }
  515. }
  516. }
  517. }
  518. });
  519. Y.DD.Drop = Drop;
  520. }, '3.4.0' ,{skinnable:false, requires:['dd-ddm-drop', 'dd-drag']});