|
1 /* |
|
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved. |
|
3 Code licensed under the BSD License: |
|
4 http://developer.yahoo.net/yui/license.txt |
|
5 version: 3.0.0b1 |
|
6 build: 1163 |
|
7 */ |
|
8 YUI.add('dd-ddm-base', function(Y) { |
|
9 |
|
10 |
|
11 /** |
|
12 * Provides the base Drag Drop Manger required for making a Node draggable. |
|
13 * @module dd |
|
14 * @submodule dd-ddm-base |
|
15 */ |
|
16 /** |
|
17 * Provides the base Drag Drop Manger required for making a Node draggable. |
|
18 * @class DDM |
|
19 * @extends Base |
|
20 * @constructor |
|
21 * @namespace DD |
|
22 */ |
|
23 |
|
24 var DDMBase = function() { |
|
25 DDMBase.superclass.constructor.apply(this, arguments); |
|
26 }; |
|
27 |
|
28 DDMBase.NAME = 'ddm'; |
|
29 |
|
30 DDMBase.ATTRS = { |
|
31 /** |
|
32 * @attribute dragCursor |
|
33 * @description The cursor to apply when dragging, if shimmed the shim will get the cursor. |
|
34 * @type String |
|
35 */ |
|
36 dragCursor: { |
|
37 value: 'move' |
|
38 }, |
|
39 /** |
|
40 * @attribute clickPixelThresh |
|
41 * @description The number of pixels to move to start a drag operation, default is 3. |
|
42 * @type Number |
|
43 */ |
|
44 clickPixelThresh: { |
|
45 value: 3 |
|
46 }, |
|
47 /** |
|
48 * @attribute clickTimeThresh |
|
49 * @description The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000. |
|
50 * @type Number |
|
51 */ |
|
52 clickTimeThresh: { |
|
53 value: 1000 |
|
54 }, |
|
55 /** |
|
56 * @attribute dragMode |
|
57 * @description This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of all future Drag instances. |
|
58 * @type String |
|
59 */ |
|
60 dragMode: { |
|
61 value: 'point', |
|
62 setter: function(mode) { |
|
63 this._setDragMode(mode); |
|
64 return mode; |
|
65 } |
|
66 } |
|
67 |
|
68 }; |
|
69 |
|
70 Y.extend(DDMBase, Y.Base, { |
|
71 /** |
|
72 * @property _active |
|
73 * @description flag set when we activate our first drag, so DDM can start listening for events. |
|
74 * @type {Boolean} |
|
75 */ |
|
76 _active: null, |
|
77 /** |
|
78 * @private |
|
79 * @method _setDragMode |
|
80 * @description Handler for dragMode attribute setter. |
|
81 * @param String/Number The Number value or the String for the DragMode to default all future drag instances to. |
|
82 * @return Number The Mode to be set |
|
83 */ |
|
84 _setDragMode: function(mode) { |
|
85 if (mode === null) { |
|
86 mode = Y.DD.DDM.get('dragMode'); |
|
87 } |
|
88 switch (mode) { |
|
89 case 1: |
|
90 case 'intersect': |
|
91 return 1; |
|
92 case 2: |
|
93 case 'strict': |
|
94 return 2; |
|
95 case 0: |
|
96 case 'point': |
|
97 return 0; |
|
98 } |
|
99 return 0; |
|
100 }, |
|
101 /** |
|
102 * @property CSS_PREFIX |
|
103 * @description The PREFIX to attach to all DD CSS class names |
|
104 * @type {String} |
|
105 */ |
|
106 CSS_PREFIX: 'yui-dd', |
|
107 _activateTargets: function() {}, |
|
108 /** |
|
109 * @private |
|
110 * @property _drags |
|
111 * @description Holder for all registered drag elements. |
|
112 * @type {Array} |
|
113 */ |
|
114 _drags: [], |
|
115 /** |
|
116 * @property activeDrag |
|
117 * @description A reference to the currently active draggable object. |
|
118 * @type {Drag} |
|
119 */ |
|
120 activeDrag: false, |
|
121 /** |
|
122 * @private |
|
123 * @method _regDrag |
|
124 * @description Adds a reference to the drag object to the DDM._drags array, called in the constructor of Drag. |
|
125 * @param {Drag} d The Drag object |
|
126 */ |
|
127 _regDrag: function(d) { |
|
128 this._drags[this._drags.length] = d; |
|
129 if (!this._active) { |
|
130 this._setupListeners(); |
|
131 } |
|
132 }, |
|
133 /** |
|
134 * @private |
|
135 * @method _unregDrag |
|
136 * @description Remove this drag object from the DDM._drags array. |
|
137 * @param {Drag} d The drag object. |
|
138 */ |
|
139 _unregDrag: function(d) { |
|
140 var tmp = []; |
|
141 Y.each(this._drags, function(n, i) { |
|
142 if (n !== d) { |
|
143 tmp[tmp.length] = n; |
|
144 } |
|
145 }); |
|
146 this._drags = tmp; |
|
147 }, |
|
148 /** |
|
149 * @private |
|
150 * @method _setupListeners |
|
151 * @description Add the document listeners. |
|
152 */ |
|
153 _setupListeners: function() { |
|
154 this._active = true; |
|
155 var doc = Y.get(document); |
|
156 doc.on('mousemove', Y.bind(this._move, this)); |
|
157 //Y.Event.nativeAdd(document, 'mousemove', Y.bind(this._move, this)); |
|
158 doc.on('mouseup', Y.bind(this._end, this)); |
|
159 }, |
|
160 /** |
|
161 * @private |
|
162 * @method _start |
|
163 * @description Internal method used by Drag to signal the start of a drag operation |
|
164 * @param {Number} x The x position of the drag element |
|
165 * @param {Number} y The y position of the drag element |
|
166 * @param {Number} w The width of the drag element |
|
167 * @param {Number} h The height of the drag element |
|
168 */ |
|
169 _start: function(x, y, w, h) { |
|
170 this.fire('ddm:start'); |
|
171 this._startDrag.apply(this, arguments); |
|
172 }, |
|
173 /** |
|
174 * @private |
|
175 * @method _startDrag |
|
176 * @description Factory method to be overwritten by other DDM's |
|
177 * @param {Number} x The x position of the drag element |
|
178 * @param {Number} y The y position of the drag element |
|
179 * @param {Number} w The width of the drag element |
|
180 * @param {Number} h The height of the drag element |
|
181 */ |
|
182 _startDrag: function() {}, |
|
183 /** |
|
184 * @private |
|
185 * @method _endDrag |
|
186 * @description Factory method to be overwritten by other DDM's |
|
187 */ |
|
188 _endDrag: function() {}, |
|
189 _dropMove: function() {}, |
|
190 /** |
|
191 * @private |
|
192 * @method _end |
|
193 * @description Internal method used by Drag to signal the end of a drag operation |
|
194 */ |
|
195 _end: function() { |
|
196 //@TODO - Here we can get a (click - drag - click - release) interaction instead of a (mousedown - drag - mouseup - release) interaction |
|
197 //Add as a config option?? |
|
198 if (this.activeDrag) { |
|
199 this._endDrag(); |
|
200 this.fire('ddm:end'); |
|
201 this.activeDrag.end.call(this.activeDrag); |
|
202 this.activeDrag = null; |
|
203 } |
|
204 }, |
|
205 /** |
|
206 * @method stopDrag |
|
207 * @description Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag. |
|
208 * @return {Self} |
|
209 * @chainable |
|
210 */ |
|
211 stopDrag: function() { |
|
212 if (this.activeDrag) { |
|
213 this._end(); |
|
214 } |
|
215 return this; |
|
216 }, |
|
217 /** |
|
218 * @private |
|
219 * @method _move |
|
220 * @description Internal listener for the mousemove DOM event to pass to the Drag's move method. |
|
221 * @param {Event.Facade} ev The Dom mousemove Event |
|
222 */ |
|
223 _move: function(ev) { |
|
224 if (this.activeDrag) { |
|
225 this.activeDrag._move.call(this.activeDrag, ev); |
|
226 this._dropMove(); |
|
227 } |
|
228 }, |
|
229 /** |
|
230 * //TODO Private, rename??... |
|
231 * @private |
|
232 * @method cssSizestoObject |
|
233 * @description Helper method to use to set the gutter from the attribute setter. |
|
234 * @param {String} gutter CSS style string for gutter: '5 0' (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px) |
|
235 * @return {Object} The gutter Object Literal. |
|
236 */ |
|
237 cssSizestoObject: function(gutter) { |
|
238 var x = gutter.split(' '); |
|
239 |
|
240 switch (x.length) { |
|
241 case 1: x[1] = x[2] = x[3] = x[0]; break; |
|
242 case 2: x[2] = x[0]; x[3] = x[1]; break; |
|
243 case 3: x[3] = x[1]; break; |
|
244 } |
|
245 |
|
246 return { |
|
247 top : parseInt(x[0],10), |
|
248 right : parseInt(x[1],10), |
|
249 bottom: parseInt(x[2],10), |
|
250 left : parseInt(x[3],10) |
|
251 }; |
|
252 }, |
|
253 /** |
|
254 * @method getDrag |
|
255 * @description Get a valid Drag instance back from a Node or a selector string, false otherwise |
|
256 * @param {String/Object} node The Node instance or Selector string to check for a valid Drag Object |
|
257 * @return {Object} |
|
258 */ |
|
259 getDrag: function(node) { |
|
260 var drag = false, |
|
261 n = Y.get(node); |
|
262 if (n instanceof Y.Node) { |
|
263 Y.each(this._drags, function(v, k) { |
|
264 if (n.compareTo(v.get('node'))) { |
|
265 drag = v; |
|
266 } |
|
267 }); |
|
268 } |
|
269 return drag; |
|
270 } |
|
271 }); |
|
272 |
|
273 Y.namespace('DD'); |
|
274 Y.DD.DDM = new DDMBase(); |
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
|
280 }, '3.0.0b1' ,{requires:['node', 'base'], skinnable:false}); |
|
281 YUI.add('dd-ddm', function(Y) { |
|
282 |
|
283 |
|
284 /** |
|
285 * Extends the dd-ddm-base Class to add support for the viewport shim to allow a draggable node to drag to be dragged over an iframe or any other node that traps mousemove events. |
|
286 * It is also required to have Drop Targets enabled, as the viewport shim will contain the shims for the Drop Targets. |
|
287 * @module dd |
|
288 * @submodule dd-ddm |
|
289 * @for DDM |
|
290 * @namespace DD |
|
291 */ |
|
292 Y.mix(Y.DD.DDM, { |
|
293 /** |
|
294 * @private |
|
295 * @property _pg |
|
296 * @description The shim placed over the screen to track the mousemove event. |
|
297 * @type {Node} |
|
298 */ |
|
299 _pg: null, |
|
300 /** |
|
301 * @private |
|
302 * @property _debugShim |
|
303 * @description Set this to true to set the shims opacity to .5 for debugging it, default: false. |
|
304 * @type {Boolean} |
|
305 */ |
|
306 _debugShim: false, |
|
307 _activateTargets: function() {}, |
|
308 _deactivateTargets: function() {}, |
|
309 _startDrag: function() { |
|
310 if (this.activeDrag.get('useShim')) { |
|
311 this._pg_activate(); |
|
312 this._activateTargets(); |
|
313 } |
|
314 }, |
|
315 _endDrag: function() { |
|
316 this._pg_deactivate(); |
|
317 this._deactivateTargets(); |
|
318 }, |
|
319 /** |
|
320 * @private |
|
321 * @method _pg_deactivate |
|
322 * @description Deactivates the shim |
|
323 */ |
|
324 _pg_deactivate: function() { |
|
325 this._pg.setStyle('display', 'none'); |
|
326 }, |
|
327 /** |
|
328 * @private |
|
329 * @method _pg_activate |
|
330 * @description Activates the shim |
|
331 */ |
|
332 _pg_activate: function() { |
|
333 var ah = this.activeDrag.get('activeHandle'), cur = 'auto'; |
|
334 if (ah) { |
|
335 cur = ah.getStyle('cursor'); |
|
336 } |
|
337 if (cur == 'auto') { |
|
338 cur = this.get('dragCursor'); |
|
339 } |
|
340 |
|
341 this._pg_size(); |
|
342 this._pg.setStyles({ |
|
343 top: 0, |
|
344 left: 0, |
|
345 display: 'block', |
|
346 opacity: ((this._debugShim) ? '.5' : '0'), |
|
347 cursor: cur |
|
348 }); |
|
349 }, |
|
350 /** |
|
351 * @private |
|
352 * @method _pg_size |
|
353 * @description Sizes the shim on: activatation, window:scroll, window:resize |
|
354 */ |
|
355 _pg_size: function() { |
|
356 if (this.activeDrag) { |
|
357 var b = Y.get('body'), |
|
358 h = b.get('docHeight'), |
|
359 w = b.get('docWidth'); |
|
360 this._pg.setStyles({ |
|
361 height: h + 'px', |
|
362 width: w + 'px' |
|
363 }); |
|
364 } |
|
365 }, |
|
366 /** |
|
367 * @private |
|
368 * @method _createPG |
|
369 * @description Creates the shim and adds it's listeners to it. |
|
370 */ |
|
371 _createPG: function() { |
|
372 var pg = Y.Node.create('<div></div>'), |
|
373 bd = Y.get('body'); |
|
374 pg.setStyles({ |
|
375 top: '0', |
|
376 left: '0', |
|
377 position: 'absolute', |
|
378 zIndex: '9999', |
|
379 overflow: 'hidden', |
|
380 backgroundColor: 'red', |
|
381 display: 'none', |
|
382 height: '5px', |
|
383 width: '5px' |
|
384 }); |
|
385 pg.set('id', Y.stamp(pg)); |
|
386 pg.addClass('yui-dd-shim'); |
|
387 if (bd.get('firstChild')) { |
|
388 bd.insertBefore(pg, bd.get('firstChild')); |
|
389 } else { |
|
390 bd.appendChild(pg); |
|
391 } |
|
392 this._pg = pg; |
|
393 this._pg.on('mouseup', Y.bind(this._end, this)); |
|
394 this._pg.on('mousemove', Y.bind(this._move, this)); |
|
395 |
|
396 var win = Y.get(window); |
|
397 win.on('resize', Y.bind(this._pg_size, this)); |
|
398 win.on('scroll', Y.bind(this._pg_size, this)); |
|
399 } |
|
400 }, true); |
|
401 |
|
402 Y.on('domready', Y.bind(Y.DD.DDM._createPG, Y.DD.DDM)); |
|
403 |
|
404 |
|
405 |
|
406 |
|
407 |
|
408 }, '3.0.0b1' ,{requires:['dd-ddm-base'], skinnable:false}); |
|
409 YUI.add('dd-ddm-drop', function(Y) { |
|
410 |
|
411 |
|
412 /** |
|
413 * Extends the dd-ddm Class to add support for the placement of Drop Target shims inside the viewport shim. It also handles all Drop Target related events and interactions. |
|
414 * @module dd |
|
415 * @submodule dd-ddm-drop |
|
416 * @for DDM |
|
417 * @namespace DD |
|
418 */ |
|
419 |
|
420 //TODO CSS class name for the bestMatch.. |
|
421 Y.mix(Y.DD.DDM, { |
|
422 /** |
|
423 * @private |
|
424 * @property _noShim |
|
425 * @description This flag turns off the use of the mouseover/mouseout shim. It should not be used unless you know what you are doing. |
|
426 * @type {Boolean} |
|
427 */ |
|
428 _noShim: false, |
|
429 /** |
|
430 * @private |
|
431 * @property _activeShims |
|
432 * @description Placeholder for all active shims on the page |
|
433 * @type {Array} |
|
434 */ |
|
435 _activeShims: [], |
|
436 /** |
|
437 * @private |
|
438 * @method _hasActiveShim |
|
439 * @description This method checks the _activeShims Object to see if there is a shim active. |
|
440 * @return {Boolean} |
|
441 */ |
|
442 _hasActiveShim: function() { |
|
443 if (this._noShim) { |
|
444 return true; |
|
445 } |
|
446 return this._activeShims.length; |
|
447 }, |
|
448 /** |
|
449 * @private |
|
450 * @method _addActiveShim |
|
451 * @description Adds a Drop Target to the list of active shims |
|
452 * @param {Object} d The Drop instance to add to the list. |
|
453 */ |
|
454 _addActiveShim: function(d) { |
|
455 this._activeShims[this._activeShims.length] = d; |
|
456 }, |
|
457 /** |
|
458 * @private |
|
459 * @method _removeActiveShim |
|
460 * @description Removes a Drop Target to the list of active shims |
|
461 * @param {Object} d The Drop instance to remove from the list. |
|
462 */ |
|
463 _removeActiveShim: function(d) { |
|
464 var s = []; |
|
465 Y.each(this._activeShims, function(v, k) { |
|
466 if (v._yuid !== d._yuid) { |
|
467 s[s.length] = v; |
|
468 } |
|
469 |
|
470 }); |
|
471 this._activeShims = s; |
|
472 }, |
|
473 /** |
|
474 * @method syncActiveShims |
|
475 * @description This method will sync the position of the shims on the Drop Targets that are currently active. |
|
476 * @param {Boolean} force Resize/sync all Targets. |
|
477 */ |
|
478 syncActiveShims: function(force) { |
|
479 Y.later(0, this, function(force) { |
|
480 var drops = ((force) ? this.targets : this._lookup()); |
|
481 Y.each(drops, function(v, k) { |
|
482 v.sizeShim.call(v); |
|
483 }, this); |
|
484 }, force); |
|
485 }, |
|
486 /** |
|
487 * @private |
|
488 * @property mode |
|
489 * @description The mode that the drag operations will run in 0 for Point, 1 for Intersect, 2 for Strict |
|
490 * @type Number |
|
491 */ |
|
492 mode: 0, |
|
493 /** |
|
494 * @private |
|
495 * @property POINT |
|
496 * @description In point mode, a Drop is targeted by the cursor being over the Target |
|
497 * @type Number |
|
498 */ |
|
499 POINT: 0, |
|
500 /** |
|
501 * @private |
|
502 * @property INTERSECT |
|
503 * @description In intersect mode, a Drop is targeted by "part" of the drag node being over the Target |
|
504 * @type Number |
|
505 */ |
|
506 INTERSECT: 1, |
|
507 /** |
|
508 * @private |
|
509 * @property STRICT |
|
510 * @description In strict mode, a Drop is targeted by the "entire" drag node being over the Target |
|
511 * @type Number |
|
512 */ |
|
513 STRICT: 2, |
|
514 /** |
|
515 * @property useHash |
|
516 * @description Should we only check targets that are in the viewport on drags (for performance), default: true |
|
517 * @type {Boolean} |
|
518 */ |
|
519 useHash: true, |
|
520 /** |
|
521 * @property activeDrop |
|
522 * @description A reference to the active Drop Target |
|
523 * @type {Object} |
|
524 */ |
|
525 activeDrop: null, |
|
526 /** |
|
527 * @property validDrops |
|
528 * @description An array of the valid Drop Targets for this interaction. |
|
529 * @type {Array} |
|
530 */ |
|
531 //TODO Change array/object literals to be in sync.. |
|
532 validDrops: [], |
|
533 /** |
|
534 * @property otherDrops |
|
535 * @description An object literal of Other Drop Targets that we encountered during this interaction (in the case of overlapping Drop Targets) |
|
536 * @type {Object} |
|
537 */ |
|
538 otherDrops: {}, |
|
539 /** |
|
540 * @property targets |
|
541 * @description All of the Targets |
|
542 * @type {Array} |
|
543 */ |
|
544 targets: [], |
|
545 /** |
|
546 * @private |
|
547 * @method _addValid |
|
548 * @description Add a Drop Target to the list of Valid Targets. This list get's regenerated on each new drag operation. |
|
549 * @param {Object} drop |
|
550 * @return {Self} |
|
551 * @chainable |
|
552 */ |
|
553 _addValid: function(drop) { |
|
554 this.validDrops[this.validDrops.length] = drop; |
|
555 return this; |
|
556 }, |
|
557 /** |
|
558 * @private |
|
559 * @method _removeValid |
|
560 * @description Removes a Drop Target from the list of Valid Targets. This list get's regenerated on each new drag operation. |
|
561 * @param {Object} drop |
|
562 * @return {Self} |
|
563 * @chainable |
|
564 */ |
|
565 _removeValid: function(drop) { |
|
566 var drops = []; |
|
567 Y.each(this.validDrops, function(v, k) { |
|
568 if (v !== drop) { |
|
569 drops[drops.length] = v; |
|
570 } |
|
571 }); |
|
572 |
|
573 this.validDrops = drops; |
|
574 return this; |
|
575 }, |
|
576 /** |
|
577 * @method isOverTarget |
|
578 * @description Check to see if the Drag element is over the target, method varies on current mode |
|
579 * @param {Object} drop The drop to check against |
|
580 * @return {Boolean} |
|
581 */ |
|
582 isOverTarget: function(drop) { |
|
583 if (this.activeDrag && drop) { |
|
584 var xy = this.activeDrag.mouseXY; |
|
585 if (xy) { |
|
586 if (this.activeDrag.get('dragMode') == this.STRICT) { |
|
587 return this.activeDrag.get('dragNode').inRegion(drop.region, true, this.activeDrag.region); |
|
588 } else { |
|
589 if (drop && drop.shim) { |
|
590 return drop.shim.intersect({ |
|
591 top: xy[1], |
|
592 bottom: xy[1], |
|
593 left: xy[0], |
|
594 right: xy[0] |
|
595 }, drop.region).inRegion; |
|
596 } else { |
|
597 return false; |
|
598 } |
|
599 } |
|
600 } else { |
|
601 return false; |
|
602 } |
|
603 } else { |
|
604 return false; |
|
605 } |
|
606 }, |
|
607 /** |
|
608 * @method clearCache |
|
609 * @description Clears the cache data used for this interaction. |
|
610 */ |
|
611 clearCache: function() { |
|
612 this.validDrops = []; |
|
613 this.otherDrops = {}; |
|
614 this._activeShims = []; |
|
615 }, |
|
616 /** |
|
617 * @private |
|
618 * @method _activateTargets |
|
619 * @description Clear the cache and activate the shims of all the targets |
|
620 */ |
|
621 _activateTargets: function() { |
|
622 this.clearCache(); |
|
623 Y.each(this.targets, function(v, k) { |
|
624 v._activateShim.apply(v, []); |
|
625 }, this); |
|
626 this._handleTargetOver(); |
|
627 |
|
628 }, |
|
629 /** |
|
630 * @method getBestMatch |
|
631 * @description This method will gather the area for all potential targets and see which has the hightest covered area and return it. |
|
632 * @param {Array} drops An Array of drops to scan for the best match. |
|
633 * @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. |
|
634 * @return {Object or Array} |
|
635 */ |
|
636 getBestMatch: function(drops, all) { |
|
637 var biggest = null, area = 0, out; |
|
638 |
|
639 Y.each(drops, function(v, k) { |
|
640 var inter = this.activeDrag.get('dragNode').intersect(v.get('node')); |
|
641 v.region.area = inter.area; |
|
642 |
|
643 if (inter.inRegion) { |
|
644 if (inter.area > area) { |
|
645 area = inter.area; |
|
646 biggest = v; |
|
647 } |
|
648 } |
|
649 }, this); |
|
650 if (all) { |
|
651 out = []; |
|
652 //TODO Sort the others in numeric order by area covered.. |
|
653 Y.each(drops, function(v, k) { |
|
654 if (v !== biggest) { |
|
655 out[out.length] = v; |
|
656 } |
|
657 }, this); |
|
658 return [biggest, out]; |
|
659 } else { |
|
660 return biggest; |
|
661 } |
|
662 }, |
|
663 /** |
|
664 * @private |
|
665 * @method _deactivateTargets |
|
666 * @description This method fires the drop:hit, drag:drophit, drag:dropmiss methods and deactivates the shims.. |
|
667 */ |
|
668 _deactivateTargets: function() { |
|
669 var other = [], tmp, |
|
670 activeDrag = this.activeDrag, |
|
671 activeDrop = this.activeDrop; |
|
672 |
|
673 //TODO why is this check so hard?? |
|
674 if (activeDrag && activeDrop && this.otherDrops[activeDrop]) { |
|
675 if (!activeDrag.get('dragMode')) { |
|
676 //TODO otherDrops -- private.. |
|
677 other = this.otherDrops; |
|
678 delete other[activeDrop]; |
|
679 } else { |
|
680 tmp = this.getBestMatch(this.otherDrops, true); |
|
681 activeDrop = tmp[0]; |
|
682 other = tmp[1]; |
|
683 } |
|
684 activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over'); |
|
685 if (activeDrop) { |
|
686 activeDrop.fire('drop:hit', { drag: activeDrag, drop: activeDrop, others: other }); |
|
687 activeDrag.fire('drag:drophit', { drag: activeDrag, drop: activeDrop, others: other }); |
|
688 } |
|
689 } else if (activeDrag) { |
|
690 activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over'); |
|
691 activeDrag.fire('drag:dropmiss', { pageX: activeDrag.lastXY[0], pageY: activeDrag.lastXY[1] }); |
|
692 } else { |
|
693 } |
|
694 |
|
695 this.activeDrop = null; |
|
696 |
|
697 Y.each(this.targets, function(v, k) { |
|
698 v._deactivateShim.apply(v, []); |
|
699 }, this); |
|
700 }, |
|
701 /** |
|
702 * @private |
|
703 * @method _dropMove |
|
704 * @description This method is called when the move method is called on the Drag Object. |
|
705 */ |
|
706 _dropMove: function() { |
|
707 if (this._hasActiveShim()) { |
|
708 this._handleTargetOver(); |
|
709 } else { |
|
710 Y.each(this.otherDrops, function(v, k) { |
|
711 v._handleOut.apply(v, []); |
|
712 }); |
|
713 } |
|
714 }, |
|
715 /** |
|
716 * @private |
|
717 * @method _lookup |
|
718 * @description Filters the list of Drops down to those in the viewport. |
|
719 * @return {Array} The valid Drop Targets that are in the viewport. |
|
720 */ |
|
721 _lookup: function() { |
|
722 if (!this.useHash || this._noShim) { |
|
723 return this.validDrops; |
|
724 } |
|
725 var drops = []; |
|
726 //Only scan drop shims that are in the Viewport |
|
727 Y.each(this.validDrops, function(v, k) { |
|
728 if (v.shim && v.shim.inViewportRegion(false, v.region)) { |
|
729 drops[drops.length] = v; |
|
730 } |
|
731 }); |
|
732 return drops; |
|
733 |
|
734 }, |
|
735 /** |
|
736 * @private |
|
737 * @method _handleTargetOver |
|
738 * @description This method execs _handleTargetOver on all valid Drop Targets |
|
739 */ |
|
740 _handleTargetOver: function() { |
|
741 var drops = this._lookup(); |
|
742 Y.each(drops, function(v, k) { |
|
743 v._handleTargetOver.call(v); |
|
744 }, this); |
|
745 }, |
|
746 /** |
|
747 * @private |
|
748 * @method _regTarget |
|
749 * @description Add the passed in Target to the targets collection |
|
750 * @param {Object} t The Target to add to the targets collection |
|
751 */ |
|
752 _regTarget: function(t) { |
|
753 this.targets[this.targets.length] = t; |
|
754 }, |
|
755 /** |
|
756 * @private |
|
757 * @method _unregTarget |
|
758 * @description Remove the passed in Target from the targets collection |
|
759 * @param {Object} drop The Target to remove from the targets collection |
|
760 */ |
|
761 _unregTarget: function(drop) { |
|
762 var targets = [], vdrops; |
|
763 Y.each(this.targets, function(v, k) { |
|
764 if (v != drop) { |
|
765 targets[targets.length] = v; |
|
766 } |
|
767 }, this); |
|
768 this.targets = targets; |
|
769 |
|
770 vdrops = []; |
|
771 Y.each(this.validDrops, function(v, k) { |
|
772 if (v !== drop) { |
|
773 vdrops[vdrops.length] = v; |
|
774 } |
|
775 }); |
|
776 |
|
777 this.validDrops = vdrops; |
|
778 }, |
|
779 /** |
|
780 * @method getDrop |
|
781 * @description Get a valid Drop instance back from a Node or a selector string, false otherwise |
|
782 * @param {String/Object} node The Node instance or Selector string to check for a valid Drop Object |
|
783 * @return {Object} |
|
784 */ |
|
785 getDrop: function(node) { |
|
786 var drop = false, |
|
787 n = Y.Node.get(node); |
|
788 if (n instanceof Y.Node) { |
|
789 Y.each(this.targets, function(v, k) { |
|
790 if (n.compareTo(v.get('node'))) { |
|
791 drop = v; |
|
792 } |
|
793 }); |
|
794 } |
|
795 return drop; |
|
796 } |
|
797 }, true); |
|
798 |
|
799 |
|
800 |
|
801 |
|
802 |
|
803 |
|
804 |
|
805 }, '3.0.0b1' ,{requires:['dd-ddm'], skinnable:false}); |
|
806 YUI.add('dd-drag', function(Y) { |
|
807 |
|
808 |
|
809 /** |
|
810 * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic. |
|
811 * @module dd |
|
812 * @submodule dd-drag |
|
813 */ |
|
814 /** |
|
815 * This class provides the ability to drag a Node. |
|
816 * @class Drag |
|
817 * @extends Base |
|
818 * @constructor |
|
819 * @namespace DD |
|
820 */ |
|
821 |
|
822 var DDM = Y.DD.DDM, |
|
823 NODE = 'node', |
|
824 DRAGGING = 'dragging', |
|
825 DRAG_NODE = 'dragNode', |
|
826 OFFSET_HEIGHT = 'offsetHeight', |
|
827 OFFSET_WIDTH = 'offsetWidth', |
|
828 MOUSE_UP = 'mouseup', |
|
829 MOUSE_DOWN = 'mousedown', |
|
830 DRAG_START = 'dragstart', |
|
831 /** |
|
832 * @event drag:mouseDown |
|
833 * @description Handles the mousedown DOM event, checks to see if you have a valid handle then starts the drag timers. |
|
834 * @preventable _defMouseDownFn |
|
835 * @param {Event.Facade} ev The mousedown event. |
|
836 * @bubbles DDM |
|
837 * @type {Event.Custom} |
|
838 */ |
|
839 EV_MOUSE_DOWN = 'drag:mouseDown', |
|
840 /** |
|
841 * @event drag:afterMouseDown |
|
842 * @description Fires after the mousedown event has been cleared. |
|
843 * @param {Event.Facade} ev The mousedown event. |
|
844 * @bubbles DDM |
|
845 * @type {Event.Custom} |
|
846 */ |
|
847 EV_AFTER_MOUSE_DOWN = 'drag:afterMouseDown', |
|
848 /** |
|
849 * @event drag:removeHandle |
|
850 * @description Fires after a handle is removed. |
|
851 * @bubbles DDM |
|
852 * @type {Event.Custom} |
|
853 */ |
|
854 EV_REMOVE_HANDLE = 'drag:removeHandle', |
|
855 /** |
|
856 * @event drag:addHandle |
|
857 * @description Fires after a handle is added. |
|
858 * @bubbles DDM |
|
859 * @type {Event.Custom} |
|
860 */ |
|
861 EV_ADD_HANDLE = 'drag:addHandle', |
|
862 /** |
|
863 * @event drag:removeInvalid |
|
864 * @description Fires after an invalid selector is removed. |
|
865 * @bubbles DDM |
|
866 * @type {Event.Custom} |
|
867 */ |
|
868 EV_REMOVE_INVALID = 'drag:removeInvalid', |
|
869 /** |
|
870 * @event drag:addInvalid |
|
871 * @description Fires after an invalid selector is added. |
|
872 * @bubbles DDM |
|
873 * @type {Event.Custom} |
|
874 */ |
|
875 EV_ADD_INVALID = 'drag:addInvalid', |
|
876 /** |
|
877 * @event drag:start |
|
878 * @description Fires at the start of a drag operation. |
|
879 * @bubbles DDM |
|
880 * @type {Event.Custom} |
|
881 */ |
|
882 EV_START = 'drag:start', |
|
883 /** |
|
884 * @event drag:end |
|
885 * @description Fires at the end of a drag operation. |
|
886 * @bubbles DDM |
|
887 * @type {Event.Custom} |
|
888 */ |
|
889 EV_END = 'drag:end', |
|
890 /** |
|
891 * @event drag:drag |
|
892 * @description Fires every mousemove during a drag operation. |
|
893 * @bubbles DDM |
|
894 * @type {Event.Custom} |
|
895 */ |
|
896 EV_DRAG = 'drag:drag', |
|
897 /** |
|
898 * @event drag:align |
|
899 * @preventable _defAlignFn |
|
900 * @description Fires when this node is aligned. |
|
901 * @bubbles DDM |
|
902 * @type {Event.Custom} |
|
903 */ |
|
904 EV_ALIGN = 'drag:align', |
|
905 /** |
|
906 * @event drag:over |
|
907 * @description Fires when this node is over a Drop Target. (Fired from dd-drop) |
|
908 * @bubbles DDM |
|
909 * @type {Event.Custom} |
|
910 */ |
|
911 /** |
|
912 * @event drag:enter |
|
913 * @description Fires when this node enters a Drop Target. (Fired from dd-drop) |
|
914 * @bubbles DDM |
|
915 * @type {Event.Custom} |
|
916 */ |
|
917 /** |
|
918 * @event drag:exit |
|
919 * @description Fires when this node exits a Drop Target. (Fired from dd-drop) |
|
920 * @bubbles DDM |
|
921 * @type {Event.Custom} |
|
922 */ |
|
923 /** |
|
924 * @event drag:drophit |
|
925 * @description Fires when this node is dropped on a valid Drop Target. (Fired from dd-ddm-drop) |
|
926 * @bubbles DDM |
|
927 * @type {Event.Custom} |
|
928 */ |
|
929 /** |
|
930 * @event drag:dropmiss |
|
931 * @description Fires when this node is dropped on an invalid Drop Target. (Fired from dd-ddm-drop) |
|
932 * @bubbles DDM |
|
933 * @type {Event.Custom} |
|
934 */ |
|
935 |
|
936 Drag = function() { |
|
937 this._lazyAddAttrs = false; |
|
938 Drag.superclass.constructor.apply(this, arguments); |
|
939 |
|
940 DDM._regDrag(this); |
|
941 }; |
|
942 |
|
943 Drag.NAME = 'drag'; |
|
944 |
|
945 Drag.ATTRS = { |
|
946 /** |
|
947 * @attribute node |
|
948 * @description Y.Node instanace to use as the element to initiate a drag operation |
|
949 * @type Node |
|
950 */ |
|
951 node: { |
|
952 setter: function(node) { |
|
953 var n = Y.get(node); |
|
954 if (!n) { |
|
955 Y.error('DD.Drag: Invalid Node Given: ' + node); |
|
956 } else { |
|
957 n = n.item(0); |
|
958 } |
|
959 return n; |
|
960 } |
|
961 }, |
|
962 /** |
|
963 * @attribute dragNode |
|
964 * @description Y.Node instanace to use as the draggable element, defaults to node |
|
965 * @type Node |
|
966 */ |
|
967 dragNode: { |
|
968 setter: function(node) { |
|
969 var n = Y.Node.get(node); |
|
970 if (!n) { |
|
971 Y.error('DD.Drag: Invalid dragNode Given: ' + node); |
|
972 } |
|
973 return n; |
|
974 } |
|
975 }, |
|
976 /** |
|
977 * @attribute offsetNode |
|
978 * @description Offset the drag element by the difference in cursor position: default true |
|
979 * @type Boolean |
|
980 */ |
|
981 offsetNode: { |
|
982 value: true |
|
983 }, |
|
984 /** |
|
985 * @attribute clickPixelThresh |
|
986 * @description The number of pixels to move to start a drag operation, default is 3. |
|
987 * @type Number |
|
988 */ |
|
989 clickPixelThresh: { |
|
990 value: DDM.get('clickPixelThresh') |
|
991 }, |
|
992 /** |
|
993 * @attribute clickTimeThresh |
|
994 * @description The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000. |
|
995 * @type Number |
|
996 */ |
|
997 clickTimeThresh: { |
|
998 value: DDM.get('clickTimeThresh') |
|
999 }, |
|
1000 /** |
|
1001 * @attribute lock |
|
1002 * @description Set to lock this drag element so that it can't be dragged: default false. |
|
1003 * @type Boolean |
|
1004 */ |
|
1005 lock: { |
|
1006 value: false, |
|
1007 setter: function(lock) { |
|
1008 if (lock) { |
|
1009 this.get(NODE).addClass(DDM.CSS_PREFIX + '-locked'); |
|
1010 } else { |
|
1011 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-locked'); |
|
1012 } |
|
1013 return lock; |
|
1014 } |
|
1015 }, |
|
1016 /** |
|
1017 * @attribute data |
|
1018 * @description A payload holder to store arbitrary data about this drag object, can be used to store any value. |
|
1019 * @type Mixed |
|
1020 */ |
|
1021 data: { |
|
1022 value: false |
|
1023 }, |
|
1024 /** |
|
1025 * @attribute move |
|
1026 * @description If this is false, the drag element will not move with the cursor: default true. Can be used to "resize" the element. |
|
1027 * @type Boolean |
|
1028 */ |
|
1029 move: { |
|
1030 value: true |
|
1031 }, |
|
1032 /** |
|
1033 * @attribute useShim |
|
1034 * @description Use the protective shim on all drag operations: default true. Only works with dd-ddm, not dd-ddm-base. |
|
1035 * @type Boolean |
|
1036 */ |
|
1037 useShim: { |
|
1038 value: true |
|
1039 }, |
|
1040 /** |
|
1041 * @attribute activeHandle |
|
1042 * @description This config option is set by Drag to inform you of which handle fired the drag event (in the case that there are several handles): default false. |
|
1043 * @type Node |
|
1044 */ |
|
1045 activeHandle: { |
|
1046 value: false |
|
1047 }, |
|
1048 /** |
|
1049 * @attribute primaryButtonOnly |
|
1050 * @description By default a drag operation will only begin if the mousedown occurred with the primary mouse button. Setting this to false will allow for all mousedown events to trigger a drag. |
|
1051 * @type Boolean |
|
1052 */ |
|
1053 primaryButtonOnly: { |
|
1054 value: true |
|
1055 }, |
|
1056 /** |
|
1057 * @attribute dragging |
|
1058 * @description This attribute is not meant to be used by the implementor, it is meant to be used as an Event tracker so you can listen for it to change. |
|
1059 * @type Boolean |
|
1060 */ |
|
1061 dragging: { |
|
1062 value: false |
|
1063 }, |
|
1064 parent: { |
|
1065 value: false |
|
1066 }, |
|
1067 /** |
|
1068 * @attribute target |
|
1069 * @description This attribute only works if the dd-drop module has been loaded. It will make this node a drop target as well as draggable. |
|
1070 * @type Boolean |
|
1071 */ |
|
1072 target: { |
|
1073 value: false, |
|
1074 setter: function(config) { |
|
1075 this._handleTarget(config); |
|
1076 return config; |
|
1077 } |
|
1078 }, |
|
1079 /** |
|
1080 * @attribute dragMode |
|
1081 * @description This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of this Drag instance. |
|
1082 * @type String |
|
1083 */ |
|
1084 dragMode: { |
|
1085 value: null, |
|
1086 setter: function(mode) { |
|
1087 return DDM._setDragMode(mode); |
|
1088 } |
|
1089 }, |
|
1090 /** |
|
1091 * @attribute groups |
|
1092 * @description Array of groups to add this drag into. |
|
1093 * @type Array |
|
1094 */ |
|
1095 groups: { |
|
1096 value: ['default'], |
|
1097 getter: function() { |
|
1098 if (!this._groups) { |
|
1099 this._groups = {}; |
|
1100 } |
|
1101 var ret = []; |
|
1102 Y.each(this._groups, function(v, k) { |
|
1103 ret[ret.length] = k; |
|
1104 }); |
|
1105 return ret; |
|
1106 }, |
|
1107 setter: function(g) { |
|
1108 this._groups = {}; |
|
1109 Y.each(g, function(v, k) { |
|
1110 this._groups[v] = true; |
|
1111 }, this); |
|
1112 return g; |
|
1113 } |
|
1114 }, |
|
1115 /** |
|
1116 * @attribute handles |
|
1117 * @description Array of valid handles to add. Adding something here will set all handles, even if previously added with addHandle |
|
1118 * @type Array |
|
1119 */ |
|
1120 handles: { |
|
1121 value: null, |
|
1122 setter: function(g) { |
|
1123 if (g) { |
|
1124 this._handles = {}; |
|
1125 Y.each(g, function(v, k) { |
|
1126 this._handles[v] = true; |
|
1127 }, this); |
|
1128 } else { |
|
1129 this._handles = null; |
|
1130 } |
|
1131 return g; |
|
1132 } |
|
1133 }, |
|
1134 /** |
|
1135 * @attribute bubbles |
|
1136 * @description Controls the default bubble parent for this Drag instance. Default: Y.DD.DDM. Set to false to disable bubbling. |
|
1137 * @type Object |
|
1138 */ |
|
1139 bubbles: { |
|
1140 writeOnce: true, |
|
1141 value: Y.DD.DDM |
|
1142 } |
|
1143 }; |
|
1144 |
|
1145 Y.extend(Drag, Y.Base, { |
|
1146 /** |
|
1147 * @method addToGroup |
|
1148 * @description Add this Drag instance to a group, this should be used for on-the-fly group additions. |
|
1149 * @param {String} g The group to add this Drag Instance to. |
|
1150 * @return {Self} |
|
1151 * @chainable |
|
1152 */ |
|
1153 addToGroup: function(g) { |
|
1154 this._groups[g] = true; |
|
1155 DDM._activateTargets(); |
|
1156 return this; |
|
1157 }, |
|
1158 /** |
|
1159 * @method removeFromGroup |
|
1160 * @description Remove this Drag instance from a group, this should be used for on-the-fly group removals. |
|
1161 * @param {String} g The group to remove this Drag Instance from. |
|
1162 * @return {Self} |
|
1163 * @chainable |
|
1164 */ |
|
1165 removeFromGroup: function(g) { |
|
1166 delete this._groups[g]; |
|
1167 DDM._activateTargets(); |
|
1168 return this; |
|
1169 }, |
|
1170 /** |
|
1171 * @property target |
|
1172 * @description This will be a reference to the Drop instance associated with this drag if the target: true config attribute is set.. |
|
1173 * @type {Object} |
|
1174 */ |
|
1175 target: null, |
|
1176 /** |
|
1177 * @private |
|
1178 * @method _handleTarget |
|
1179 * @description Attribute handler for the target config attribute. |
|
1180 * @param {Boolean/Object} |
|
1181 * @return {Boolean/Object} |
|
1182 */ |
|
1183 _handleTarget: function(config) { |
|
1184 if (Y.DD.Drop) { |
|
1185 if (config === false) { |
|
1186 if (this.target) { |
|
1187 DDM._unregTarget(this.target); |
|
1188 this.target = null; |
|
1189 } |
|
1190 return false; |
|
1191 } else { |
|
1192 if (!Y.Lang.isObject(config)) { |
|
1193 config = {}; |
|
1194 } |
|
1195 config.bubbles = ('bubbles' in config) ? config.bubbles : this.get('bubbles'); |
|
1196 config.node = this.get(NODE); |
|
1197 config.groups = config.groups || this.get('groups'); |
|
1198 this.target = new Y.DD.Drop(config); |
|
1199 } |
|
1200 } else { |
|
1201 return false; |
|
1202 } |
|
1203 }, |
|
1204 /** |
|
1205 * @private |
|
1206 * @property _groups |
|
1207 * @description Storage Array for the groups this drag belongs to. |
|
1208 * @type {Array} |
|
1209 */ |
|
1210 _groups: null, |
|
1211 /** |
|
1212 * @private |
|
1213 * @method _createEvents |
|
1214 * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling. |
|
1215 */ |
|
1216 _createEvents: function() { |
|
1217 |
|
1218 this.publish(EV_MOUSE_DOWN, { |
|
1219 defaultFn: this._defMouseDownFn, |
|
1220 queuable: false, |
|
1221 emitFacade: true, |
|
1222 bubbles: true, |
|
1223 prefix: 'drag' |
|
1224 }); |
|
1225 |
|
1226 this.publish(EV_ALIGN, { |
|
1227 defaultFn: this._defAlignFn, |
|
1228 queuable: false, |
|
1229 emitFacade: true, |
|
1230 bubbles: true, |
|
1231 prefix: 'drag' |
|
1232 }); |
|
1233 |
|
1234 this.publish(EV_DRAG, { |
|
1235 defaultFn: this._defDragFn, |
|
1236 queuable: false, |
|
1237 emitFacade: true, |
|
1238 bubbles: true, |
|
1239 prefix: 'drag' |
|
1240 }); |
|
1241 |
|
1242 this.publish(EV_END, { |
|
1243 preventedFn: this._prevEndFn, |
|
1244 queuable: false, |
|
1245 emitFacade: true, |
|
1246 bubbles: true, |
|
1247 prefix: 'drag' |
|
1248 }); |
|
1249 |
|
1250 var ev = [ |
|
1251 EV_AFTER_MOUSE_DOWN, |
|
1252 EV_REMOVE_HANDLE, |
|
1253 EV_ADD_HANDLE, |
|
1254 EV_REMOVE_INVALID, |
|
1255 EV_ADD_INVALID, |
|
1256 EV_START, |
|
1257 'drag:drophit', |
|
1258 'drag:dropmiss', |
|
1259 'drag:over', |
|
1260 'drag:enter', |
|
1261 'drag:exit' |
|
1262 ]; |
|
1263 |
|
1264 Y.each(ev, function(v, k) { |
|
1265 this.publish(v, { |
|
1266 type: v, |
|
1267 emitFacade: true, |
|
1268 bubbles: true, |
|
1269 preventable: false, |
|
1270 queuable: false, |
|
1271 prefix: 'drag' |
|
1272 }); |
|
1273 }, this); |
|
1274 |
|
1275 if (this.get('bubbles')) { |
|
1276 this.addTarget(this.get('bubbles')); |
|
1277 } |
|
1278 |
|
1279 |
|
1280 }, |
|
1281 /** |
|
1282 * @private |
|
1283 * @property _ev_md |
|
1284 * @description A private reference to the mousedown DOM event |
|
1285 * @type {Event.Facade} |
|
1286 */ |
|
1287 _ev_md: null, |
|
1288 /** |
|
1289 * @private |
|
1290 * @property _startTime |
|
1291 * @description The getTime of the mousedown event. Not used, just here in case someone wants/needs to use it. |
|
1292 * @type Date |
|
1293 */ |
|
1294 _startTime: null, |
|
1295 /** |
|
1296 * @private |
|
1297 * @property _endTime |
|
1298 * @description The getTime of the mouseup event. Not used, just here in case someone wants/needs to use it. |
|
1299 * @type Date |
|
1300 */ |
|
1301 _endTime: null, |
|
1302 /** |
|
1303 * @private |
|
1304 * @property _handles |
|
1305 * @description A private hash of the valid drag handles |
|
1306 * @type {Object} |
|
1307 */ |
|
1308 _handles: null, |
|
1309 /** |
|
1310 * @private |
|
1311 * @property _invalids |
|
1312 * @description A private hash of the invalid selector strings |
|
1313 * @type {Object} |
|
1314 */ |
|
1315 _invalids: null, |
|
1316 /** |
|
1317 * @private |
|
1318 * @property _invalidsDefault |
|
1319 * @description A private hash of the default invalid selector strings: {'textarea': true, 'input': true, 'a': true, 'button': true} |
|
1320 * @type {Object} |
|
1321 */ |
|
1322 _invalidsDefault: {'textarea': true, 'input': true, 'a': true, 'button': true}, |
|
1323 /** |
|
1324 * @private |
|
1325 * @property _dragThreshMet |
|
1326 * @description Private flag to see if the drag threshhold was met |
|
1327 * @type {Boolean} |
|
1328 */ |
|
1329 _dragThreshMet: null, |
|
1330 /** |
|
1331 * @private |
|
1332 * @property _fromTimeout |
|
1333 * @description Flag to determine if the drag operation came from a timeout |
|
1334 * @type {Boolean} |
|
1335 */ |
|
1336 _fromTimeout: null, |
|
1337 /** |
|
1338 * @private |
|
1339 * @property _clickTimeout |
|
1340 * @description Holder for the setTimeout call |
|
1341 * @type {Boolean} |
|
1342 */ |
|
1343 _clickTimeout: null, |
|
1344 /** |
|
1345 * @property deltaXY |
|
1346 * @description The offset of the mouse position to the element's position |
|
1347 * @type {Array} |
|
1348 */ |
|
1349 deltaXY: null, |
|
1350 /** |
|
1351 * @property startXY |
|
1352 * @description The initial mouse position |
|
1353 * @type {Array} |
|
1354 */ |
|
1355 startXY: null, |
|
1356 /** |
|
1357 * @property nodeXY |
|
1358 * @description The initial element position |
|
1359 * @type {Array} |
|
1360 */ |
|
1361 nodeXY: null, |
|
1362 /** |
|
1363 * @property lastXY |
|
1364 * @description The position of the element as it's moving (for offset calculations) |
|
1365 * @type {Array} |
|
1366 */ |
|
1367 lastXY: null, |
|
1368 /** |
|
1369 * @property actXY |
|
1370 * @description The xy that the node will be set to. Changing this will alter the position as it's dragged. |
|
1371 * @type {Array} |
|
1372 */ |
|
1373 actXY: null, |
|
1374 /** |
|
1375 * @property realXY |
|
1376 * @description The real xy position of the node. |
|
1377 * @type {Array} |
|
1378 */ |
|
1379 realXY: null, |
|
1380 /** |
|
1381 * @property mouseXY |
|
1382 * @description The XY coords of the mousemove |
|
1383 * @type {Array} |
|
1384 */ |
|
1385 mouseXY: null, |
|
1386 /** |
|
1387 * @property region |
|
1388 * @description A region object associated with this drag, used for checking regions while dragging. |
|
1389 * @type Object |
|
1390 */ |
|
1391 region: null, |
|
1392 /** |
|
1393 * @private |
|
1394 * @method _handleMouseUp |
|
1395 * @description Handler for the mouseup DOM event |
|
1396 * @param {Event.Facade} |
|
1397 */ |
|
1398 _handleMouseUp: function(ev) { |
|
1399 this._fixIEMouseUp(); |
|
1400 if (DDM.activeDrag) { |
|
1401 DDM._end(); |
|
1402 } |
|
1403 }, |
|
1404 /** |
|
1405 * @private |
|
1406 * @method _fixDragStart |
|
1407 * @description The function we use as the ondragstart handler when we start a drag in Internet Explorer. This keeps IE from blowing up on images as drag handles. |
|
1408 */ |
|
1409 _fixDragStart: function(e) { |
|
1410 e.preventDefault(); |
|
1411 }, |
|
1412 /** |
|
1413 * @private |
|
1414 * @method _ieSelectFix |
|
1415 * @description The function we use as the onselectstart handler when we start a drag in Internet Explorer |
|
1416 */ |
|
1417 _ieSelectFix: function() { |
|
1418 return false; |
|
1419 }, |
|
1420 /** |
|
1421 * @private |
|
1422 * @property _ieSelectBack |
|
1423 * @description We will hold a copy of the current "onselectstart" method on this property, and reset it after we are done using it. |
|
1424 */ |
|
1425 _ieSelectBack: null, |
|
1426 /** |
|
1427 * @private |
|
1428 * @method _fixIEMouseDown |
|
1429 * @description This method copies the onselectstart listner on the document to the _ieSelectFix property |
|
1430 */ |
|
1431 _fixIEMouseDown: function() { |
|
1432 if (Y.UA.ie) { |
|
1433 this._ieSelectBack = Y.config.doc.body.onselectstart; |
|
1434 Y.config.doc.body.onselectstart = this._ieSelectFix; |
|
1435 } |
|
1436 }, |
|
1437 /** |
|
1438 * @private |
|
1439 * @method _fixIEMouseUp |
|
1440 * @description This method copies the _ieSelectFix property back to the onselectstart listner on the document. |
|
1441 */ |
|
1442 _fixIEMouseUp: function() { |
|
1443 if (Y.UA.ie) { |
|
1444 Y.config.doc.body.onselectstart = this._ieSelectBack; |
|
1445 } |
|
1446 }, |
|
1447 /** |
|
1448 * @private |
|
1449 * @method _handleMouseDownEvent |
|
1450 * @description Handler for the mousedown DOM event |
|
1451 * @param {Event.Facade} |
|
1452 */ |
|
1453 _handleMouseDownEvent: function(ev) { |
|
1454 this.fire(EV_MOUSE_DOWN, { ev: ev }); |
|
1455 }, |
|
1456 /** |
|
1457 * @private |
|
1458 * @method _defMouseDownFn |
|
1459 * @description Handler for the mousedown DOM event |
|
1460 * @param {Event.Facade} |
|
1461 */ |
|
1462 _defMouseDownFn: function(e) { |
|
1463 var ev = e.ev; |
|
1464 this._dragThreshMet = false; |
|
1465 this._ev_md = ev; |
|
1466 |
|
1467 if (this.get('primaryButtonOnly') && ev.button > 1) { |
|
1468 return false; |
|
1469 } |
|
1470 if (this.validClick(ev)) { |
|
1471 this._fixIEMouseDown(); |
|
1472 ev.halt(); |
|
1473 this._setStartPosition([ev.pageX, ev.pageY]); |
|
1474 |
|
1475 DDM.activeDrag = this; |
|
1476 |
|
1477 this._clickTimeout = Y.later(this.get('clickTimeThresh'), this, this._timeoutCheck); |
|
1478 } |
|
1479 this.fire(EV_AFTER_MOUSE_DOWN, { ev: ev }); |
|
1480 }, |
|
1481 /** |
|
1482 * @method validClick |
|
1483 * @description Method first checks to see if we have handles, if so it validates the click against the handle. Then if it finds a valid handle, it checks it against the invalid handles list. Returns true if a good handle was used, false otherwise. |
|
1484 * @param {Event.Facade} |
|
1485 * @return {Boolean} |
|
1486 */ |
|
1487 validClick: function(ev) { |
|
1488 var r = false, n = false, |
|
1489 tar = ev.target, |
|
1490 hTest = null, |
|
1491 els = null, |
|
1492 set = false; |
|
1493 if (this._handles) { |
|
1494 Y.each(this._handles, function(i, n) { |
|
1495 if (Y.Lang.isString(n)) { |
|
1496 //Am I this or am I inside this |
|
1497 if (tar.test(n + ', ' + n + ' *') && !hTest) { |
|
1498 hTest = n; |
|
1499 r = true; |
|
1500 } |
|
1501 } |
|
1502 }); |
|
1503 } else { |
|
1504 n = this.get(NODE) |
|
1505 if (n.contains(tar) || n.compareTo(tar)) { |
|
1506 r = true; |
|
1507 } |
|
1508 } |
|
1509 if (r) { |
|
1510 if (this._invalids) { |
|
1511 Y.each(this._invalids, function(i, n) { |
|
1512 if (Y.Lang.isString(n)) { |
|
1513 //Am I this or am I inside this |
|
1514 if (tar.test(n + ', ' + n + ' *')) { |
|
1515 r = false; |
|
1516 } |
|
1517 } |
|
1518 }); |
|
1519 } |
|
1520 } |
|
1521 if (r) { |
|
1522 if (hTest) { |
|
1523 els = ev.currentTarget.queryAll(hTest); |
|
1524 set = false; |
|
1525 els.each(function(n, i) { |
|
1526 if ((n.contains(tar) || n.compareTo(tar)) && !set) { |
|
1527 set = true; |
|
1528 this.set('activeHandle', n); |
|
1529 } |
|
1530 }, this); |
|
1531 } else { |
|
1532 this.set('activeHandle', this.get(NODE)); |
|
1533 } |
|
1534 } |
|
1535 return r; |
|
1536 }, |
|
1537 /** |
|
1538 * @private |
|
1539 * @method _setStartPosition |
|
1540 * @description Sets the current position of the Element and calculates the offset |
|
1541 * @param {Array} xy The XY coords to set the position to. |
|
1542 */ |
|
1543 _setStartPosition: function(xy) { |
|
1544 this.startXY = xy; |
|
1545 |
|
1546 this.nodeXY = this.lastXY = this.realXY = this.get(NODE).getXY(); |
|
1547 |
|
1548 if (this.get('offsetNode')) { |
|
1549 this.deltaXY = [(this.startXY[0] - this.nodeXY[0]), (this.startXY[1] - this.nodeXY[1])]; |
|
1550 } else { |
|
1551 this.deltaXY = [0, 0]; |
|
1552 } |
|
1553 }, |
|
1554 /** |
|
1555 * @private |
|
1556 * @method _timeoutCheck |
|
1557 * @description The method passed to setTimeout to determine if the clickTimeThreshold was met. |
|
1558 */ |
|
1559 _timeoutCheck: function() { |
|
1560 if (!this.get('lock') && !this._dragThreshMet) { |
|
1561 this._fromTimeout = this._dragThreshMet = true; |
|
1562 this.start(); |
|
1563 this._alignNode([this._ev_md.pageX, this._ev_md.pageY], true); |
|
1564 } |
|
1565 }, |
|
1566 /** |
|
1567 * @method removeHandle |
|
1568 * @description Remove a Selector added by addHandle |
|
1569 * @param {String} str The selector for the handle to be removed. |
|
1570 * @return {Self} |
|
1571 * @chainable |
|
1572 */ |
|
1573 removeHandle: function(str) { |
|
1574 if (this._handles[str]) { |
|
1575 delete this._handles[str]; |
|
1576 this.fire(EV_REMOVE_HANDLE, { handle: str }); |
|
1577 } |
|
1578 return this; |
|
1579 }, |
|
1580 /** |
|
1581 * @method addHandle |
|
1582 * @description Add a handle to a drag element. Drag only initiates when a mousedown happens on this element. |
|
1583 * @param {String} str The selector to test for a valid handle. Must be a child of the element. |
|
1584 * @return {Self} |
|
1585 * @chainable |
|
1586 */ |
|
1587 addHandle: function(str) { |
|
1588 if (!this._handles) { |
|
1589 this._handles = {}; |
|
1590 } |
|
1591 if (Y.Lang.isString(str)) { |
|
1592 this._handles[str] = true; |
|
1593 this.fire(EV_ADD_HANDLE, { handle: str }); |
|
1594 } |
|
1595 return this; |
|
1596 }, |
|
1597 /** |
|
1598 * @method removeInvalid |
|
1599 * @description Remove an invalid handle added by addInvalid |
|
1600 * @param {String} str The invalid handle to remove from the internal list. |
|
1601 * @return {Self} |
|
1602 * @chainable |
|
1603 */ |
|
1604 removeInvalid: function(str) { |
|
1605 if (this._invalids[str]) { |
|
1606 this._invalids[str] = null; |
|
1607 delete this._invalids[str]; |
|
1608 this.fire(EV_REMOVE_INVALID, { handle: str }); |
|
1609 } |
|
1610 return this; |
|
1611 }, |
|
1612 /** |
|
1613 * @method addInvalid |
|
1614 * @description Add a selector string to test the handle against. If the test passes the drag operation will not continue. |
|
1615 * @param {String} str The selector to test against to determine if this is an invalid drag handle. |
|
1616 * @return {Self} |
|
1617 * @chainable |
|
1618 */ |
|
1619 addInvalid: function(str) { |
|
1620 if (Y.Lang.isString(str)) { |
|
1621 this._invalids[str] = true; |
|
1622 this.fire(EV_ADD_INVALID, { handle: str }); |
|
1623 } |
|
1624 return this; |
|
1625 }, |
|
1626 /** |
|
1627 * @private |
|
1628 * @method initializer |
|
1629 * @description Internal init handler |
|
1630 */ |
|
1631 initializer: function() { |
|
1632 this.get(NODE).dd = this; |
|
1633 |
|
1634 if (!this.get(NODE).get('id')) { |
|
1635 var id = Y.stamp(this.get(NODE)); |
|
1636 this.get(NODE).set('id', id); |
|
1637 } |
|
1638 |
|
1639 this.actXY = []; |
|
1640 |
|
1641 this._invalids = Y.clone(this._invalidsDefault, true); |
|
1642 |
|
1643 this._createEvents(); |
|
1644 |
|
1645 if (!this.get(DRAG_NODE)) { |
|
1646 this.set(DRAG_NODE, this.get(NODE)); |
|
1647 } |
|
1648 this._prep(); |
|
1649 this._dragThreshMet = false; |
|
1650 //Shouldn't have to do this.. |
|
1651 this.set('groups', this.get('groups')); |
|
1652 }, |
|
1653 /** |
|
1654 * @private |
|
1655 * @method _prep |
|
1656 * @description Attach event listners and add classname |
|
1657 */ |
|
1658 _prep: function() { |
|
1659 var node = this.get(NODE); |
|
1660 node.addClass(DDM.CSS_PREFIX + '-draggable'); |
|
1661 node.on(MOUSE_DOWN, Y.bind(this._handleMouseDownEvent, this)); |
|
1662 node.on(MOUSE_UP, Y.bind(this._handleMouseUp, this)); |
|
1663 node.on(DRAG_START, Y.bind(this._fixDragStart, this)); |
|
1664 }, |
|
1665 /** |
|
1666 * @private |
|
1667 * @method _unprep |
|
1668 * @description Detach event listeners and remove classname |
|
1669 */ |
|
1670 _unprep: function() { |
|
1671 var node = this.get(NODE); |
|
1672 node.removeClass(DDM.CSS_PREFIX + '-draggable'); |
|
1673 node.detachAll(); |
|
1674 }, |
|
1675 /** |
|
1676 * @method start |
|
1677 * @description Starts the drag operation |
|
1678 * @return {Self} |
|
1679 * @chainable |
|
1680 */ |
|
1681 start: function() { |
|
1682 if (!this.get('lock') && !this.get(DRAGGING)) { |
|
1683 var node = this.get(NODE), ow = node.get(OFFSET_WIDTH), oh = node.get(OFFSET_HEIGHT); |
|
1684 this._startTime = (new Date()).getTime(); |
|
1685 |
|
1686 DDM._start(this.deltaXY, [oh, ow]); |
|
1687 node.addClass(DDM.CSS_PREFIX + '-dragging'); |
|
1688 this.fire(EV_START, { |
|
1689 pageX: this.nodeXY[0], |
|
1690 pageY: this.nodeXY[1], |
|
1691 startTime: this._startTime |
|
1692 }); |
|
1693 var xy = this.nodeXY; |
|
1694 |
|
1695 |
|
1696 this.region = { |
|
1697 '0': xy[0], |
|
1698 '1': xy[1], |
|
1699 area: 0, |
|
1700 top: xy[1], |
|
1701 right: xy[0] + ow, |
|
1702 bottom: xy[1] + oh, |
|
1703 left: xy[0] |
|
1704 }; |
|
1705 this.set(DRAGGING, true); |
|
1706 } |
|
1707 return this; |
|
1708 }, |
|
1709 /** |
|
1710 * @method end |
|
1711 * @description Ends the drag operation |
|
1712 * @return {Self} |
|
1713 * @chainable |
|
1714 */ |
|
1715 end: function() { |
|
1716 this._endTime = (new Date()).getTime(); |
|
1717 if (this._clickTimeout) { |
|
1718 this._clickTimeout.cancel(); |
|
1719 } |
|
1720 this._dragThreshMet = false; |
|
1721 this._fromTimeout = false; |
|
1722 if (!this.get('lock') && this.get(DRAGGING)) { |
|
1723 this.fire(EV_END, { |
|
1724 pageX: this.lastXY[0], |
|
1725 pageY: this.lastXY[1], |
|
1726 startTime: this._startTime, |
|
1727 endTime: this._endTime |
|
1728 }); |
|
1729 } |
|
1730 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-dragging'); |
|
1731 this.set(DRAGGING, false); |
|
1732 this.deltaXY = [0, 0]; |
|
1733 |
|
1734 return this; |
|
1735 }, |
|
1736 /** |
|
1737 * @private |
|
1738 * @method _prevEndFn |
|
1739 * @description Handler for preventing the drag:end event. It will reset the node back to it's start position |
|
1740 */ |
|
1741 _prevEndFn: function(e) { |
|
1742 //Bug #1852577 |
|
1743 this.get(DRAG_NODE).setXY(this.nodeXY); |
|
1744 }, |
|
1745 /** |
|
1746 * @private |
|
1747 * @method _align |
|
1748 * @description Calculates the offsets and set's the XY that the element will move to. |
|
1749 * @param {Array} xy The xy coords to align with. |
|
1750 */ |
|
1751 _align: function(xy) { |
|
1752 this.fire(EV_ALIGN, {pageX: xy[0], pageY: xy[1] }); |
|
1753 }, |
|
1754 /** |
|
1755 * @private |
|
1756 * @method _defAlignFn |
|
1757 * @description Calculates the offsets and set's the XY that the element will move to. |
|
1758 * @param {Event.Facade} e The drag:align event. |
|
1759 */ |
|
1760 _defAlignFn: function(e) { |
|
1761 this.actXY = [e.pageX - this.deltaXY[0], e.pageY - this.deltaXY[1]]; |
|
1762 }, |
|
1763 /** |
|
1764 * @private |
|
1765 * @method _alignNode |
|
1766 * @description This method performs the alignment before the element move. |
|
1767 * @param {Array} eXY The XY to move the element to, usually comes from the mousemove DOM event. |
|
1768 */ |
|
1769 _alignNode: function(eXY) { |
|
1770 this._align(eXY); |
|
1771 this._moveNode(); |
|
1772 }, |
|
1773 /** |
|
1774 * @private |
|
1775 * @method _moveNode |
|
1776 * @description This method performs the actual element move. |
|
1777 */ |
|
1778 _moveNode: function(scroll) { |
|
1779 //if (!this.get(DRAGGING)) { |
|
1780 // return; |
|
1781 //} |
|
1782 var diffXY = [], diffXY2 = [], startXY = this.nodeXY, xy = this.actXY; |
|
1783 |
|
1784 diffXY[0] = (xy[0] - this.lastXY[0]); |
|
1785 diffXY[1] = (xy[1] - this.lastXY[1]); |
|
1786 |
|
1787 diffXY2[0] = (xy[0] - this.nodeXY[0]); |
|
1788 diffXY2[1] = (xy[1] - this.nodeXY[1]); |
|
1789 |
|
1790 |
|
1791 this.region = { |
|
1792 '0': xy[0], |
|
1793 '1': xy[1], |
|
1794 area: 0, |
|
1795 top: xy[1], |
|
1796 right: xy[0] + this.get(DRAG_NODE).get(OFFSET_WIDTH), |
|
1797 bottom: xy[1] + this.get(DRAG_NODE).get(OFFSET_HEIGHT), |
|
1798 left: xy[0] |
|
1799 }; |
|
1800 |
|
1801 this.fire(EV_DRAG, { |
|
1802 pageX: xy[0], |
|
1803 pageY: xy[1], |
|
1804 scroll: scroll, |
|
1805 info: { |
|
1806 start: startXY, |
|
1807 xy: xy, |
|
1808 delta: diffXY, |
|
1809 offset: diffXY2 |
|
1810 } |
|
1811 }); |
|
1812 |
|
1813 this.lastXY = xy; |
|
1814 }, |
|
1815 /** |
|
1816 * @private |
|
1817 * @method _defDragFn |
|
1818 * @description Default function for drag:drag. Fired from _moveNode. |
|
1819 * @param {Event.Facade} ev The drag:drag event |
|
1820 */ |
|
1821 _defDragFn: function(e) { |
|
1822 if (this.get('move')) { |
|
1823 if (e.scroll) { |
|
1824 e.scroll.node.set('scrollTop', e.scroll.top); |
|
1825 e.scroll.node.set('scrollLeft', e.scroll.left); |
|
1826 } |
|
1827 this.get(DRAG_NODE).setXY([e.pageX, e.pageY]); |
|
1828 this.realXY = [e.pageX, e.pageY]; |
|
1829 } |
|
1830 }, |
|
1831 /** |
|
1832 * @private |
|
1833 * @method _move |
|
1834 * @description Fired from DragDropMgr (DDM) on mousemove. |
|
1835 * @param {Event.Facade} ev The mousemove DOM event |
|
1836 */ |
|
1837 _move: function(ev) { |
|
1838 if (this.get('lock')) { |
|
1839 return false; |
|
1840 } else { |
|
1841 this.mouseXY = [ev.pageX, ev.pageY]; |
|
1842 if (!this._dragThreshMet) { |
|
1843 var diffX = Math.abs(this.startXY[0] - ev.pageX), |
|
1844 diffY = Math.abs(this.startXY[1] - ev.pageY); |
|
1845 if (diffX > this.get('clickPixelThresh') || diffY > this.get('clickPixelThresh')) { |
|
1846 this._dragThreshMet = true; |
|
1847 this.start(); |
|
1848 this._alignNode([ev.pageX, ev.pageY]); |
|
1849 } |
|
1850 } else { |
|
1851 if (this._clickTimeout) { |
|
1852 this._clickTimeout.cancel(); |
|
1853 } |
|
1854 this._alignNode([ev.pageX, ev.pageY]); |
|
1855 } |
|
1856 } |
|
1857 }, |
|
1858 /** |
|
1859 * @method stopDrag |
|
1860 * @description Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag. |
|
1861 * @return {Self} |
|
1862 * @chainable |
|
1863 */ |
|
1864 stopDrag: function() { |
|
1865 if (this.get(DRAGGING)) { |
|
1866 DDM._end(); |
|
1867 } |
|
1868 return this; |
|
1869 }, |
|
1870 /** |
|
1871 * @private |
|
1872 * @method destructor |
|
1873 * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners |
|
1874 */ |
|
1875 destructor: function() { |
|
1876 this._unprep(); |
|
1877 this.detachAll(); |
|
1878 if (this.target) { |
|
1879 this.target.destroy(); |
|
1880 } |
|
1881 DDM._unregDrag(this); |
|
1882 } |
|
1883 }); |
|
1884 Y.namespace('DD'); |
|
1885 Y.DD.Drag = Drag; |
|
1886 |
|
1887 |
|
1888 |
|
1889 |
|
1890 |
|
1891 }, '3.0.0b1' ,{requires:['dd-ddm-base'], skinnable:false}); |
|
1892 YUI.add('dd-proxy', function(Y) { |
|
1893 |
|
1894 |
|
1895 /** |
|
1896 * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic. |
|
1897 * @module dd |
|
1898 * @submodule dd-proxy |
|
1899 */ |
|
1900 /** |
|
1901 * This plugin for dd-drag is for creating a proxy drag node, instead of dragging the original node. |
|
1902 * @class DDProxy |
|
1903 * @extends Base |
|
1904 * @constructor |
|
1905 * @namespace Plugin |
|
1906 */ |
|
1907 var DDM = Y.DD.DDM, |
|
1908 NODE = 'node', |
|
1909 DRAG_NODE = 'dragNode', |
|
1910 HOST = 'host', |
|
1911 TRUE = true; |
|
1912 |
|
1913 var P = function(config) { |
|
1914 P.superclass.constructor.apply(this, arguments); |
|
1915 }; |
|
1916 |
|
1917 P.NAME = 'DDProxy'; |
|
1918 /** |
|
1919 * @property proxy |
|
1920 * @description The Proxy instance will be placed on the Drag instance under the proxy namespace. |
|
1921 * @type {String} |
|
1922 */ |
|
1923 P.NS = 'proxy'; |
|
1924 |
|
1925 P.ATTRS = { |
|
1926 host: { |
|
1927 }, |
|
1928 /** |
|
1929 * @attribute moveOnEnd |
|
1930 * @description Move the original node at the end of the drag. Default: true |
|
1931 * @type Boolean |
|
1932 */ |
|
1933 moveOnEnd: { |
|
1934 value: TRUE |
|
1935 }, |
|
1936 /** |
|
1937 * @attribute resizeFrame |
|
1938 * @description Make the Proxy node assume the size of the original node. Default: true |
|
1939 * @type Boolean |
|
1940 */ |
|
1941 resizeFrame: { |
|
1942 value: TRUE |
|
1943 }, |
|
1944 /** |
|
1945 * @attribute positionProxy |
|
1946 * @description Make the Proxy node appear in the same place as the original node. Default: true |
|
1947 * @type Boolean |
|
1948 */ |
|
1949 positionProxy: { |
|
1950 value: TRUE |
|
1951 }, |
|
1952 /** |
|
1953 * @attribute borderStyle |
|
1954 * @description The default border style for the border of the proxy. Default: 1px solid #808080 |
|
1955 * @type Boolean |
|
1956 */ |
|
1957 borderStyle: { |
|
1958 value: '1px solid #808080' |
|
1959 } |
|
1960 }; |
|
1961 |
|
1962 var proto = { |
|
1963 /** |
|
1964 * @private |
|
1965 * @property _hands |
|
1966 * @description Holds the event handles for setting the proxy |
|
1967 */ |
|
1968 _hands: null, |
|
1969 /** |
|
1970 * @private |
|
1971 * @method _init |
|
1972 * @description Handler for the proxy config attribute |
|
1973 */ |
|
1974 _init: function() { |
|
1975 if (!DDM._proxy) { |
|
1976 Y.on('domready', Y.bind(this._init, this)); |
|
1977 return; |
|
1978 } |
|
1979 if (!this._hands) { |
|
1980 this._hands = []; |
|
1981 } |
|
1982 var i, h, h1, host = this.get(HOST), dnode = host.get(DRAG_NODE); |
|
1983 if (dnode.compareTo(host.get(NODE))) { |
|
1984 if (DDM._proxy) { |
|
1985 host.set(DRAG_NODE, DDM._proxy); |
|
1986 } |
|
1987 } |
|
1988 for (i in this._hands) { |
|
1989 this._hands[i].detach(); |
|
1990 } |
|
1991 h = DDM.on('ddm:start', Y.bind(function() { |
|
1992 if (DDM.activeDrag === host) { |
|
1993 DDM._setFrame(host); |
|
1994 } |
|
1995 }, this)); |
|
1996 h1 = DDM.on('ddm:end', Y.bind(function() { |
|
1997 if (host.get('dragging')) { |
|
1998 if (this.get('moveOnEnd')) { |
|
1999 host.get(NODE).setXY(host.lastXY); |
|
2000 } |
|
2001 host.get(DRAG_NODE).setStyle('display', 'none'); |
|
2002 } |
|
2003 }, this)); |
|
2004 this._hands = [h, h1]; |
|
2005 }, |
|
2006 initializer: function() { |
|
2007 this._init(); |
|
2008 }, |
|
2009 destructor: function() { |
|
2010 var host = this.get(HOST); |
|
2011 for (var i in this._hands) { |
|
2012 this._hands[i].detach(); |
|
2013 } |
|
2014 host.set(DRAG_NODE, host.get(NODE)); |
|
2015 } |
|
2016 }; |
|
2017 |
|
2018 Y.namespace('Plugin'); |
|
2019 Y.extend(P, Y.Base, proto); |
|
2020 Y.Plugin.DDProxy = P; |
|
2021 |
|
2022 //Add a couple of methods to the DDM |
|
2023 Y.mix(DDM, { |
|
2024 /** |
|
2025 * @private |
|
2026 * @for DDM |
|
2027 * @namespace DD |
|
2028 * @method _createFrame |
|
2029 * @description Create the proxy element if it doesn't already exist and set the DD.DDM._proxy value |
|
2030 */ |
|
2031 _createFrame: function() { |
|
2032 if (!DDM._proxy) { |
|
2033 DDM._proxy = TRUE; |
|
2034 |
|
2035 var p = Y.Node.create('<div></div>'), |
|
2036 b = Y.Node.get('body'); |
|
2037 |
|
2038 p.setStyles({ |
|
2039 position: 'absolute', |
|
2040 display: 'none', |
|
2041 zIndex: '999', |
|
2042 top: '-999px', |
|
2043 left: '-999px' |
|
2044 }); |
|
2045 |
|
2046 b.insertBefore(p, b.get('firstChild')); |
|
2047 p.set('id', Y.stamp(p)); |
|
2048 p.addClass(DDM.CSS_PREFIX + '-proxy'); |
|
2049 DDM._proxy = p; |
|
2050 } |
|
2051 }, |
|
2052 /** |
|
2053 * @private |
|
2054 * @for DDM |
|
2055 * @namespace DD |
|
2056 * @method _setFrame |
|
2057 * @description If resizeProxy is set to true (default) it will resize the proxy element to match the size of the Drag Element. |
|
2058 * If positionProxy is set to true (default) it will position the proxy element in the same location as the Drag Element. |
|
2059 */ |
|
2060 _setFrame: function(drag) { |
|
2061 var n = drag.get(NODE), d = drag.get(DRAG_NODE), ah, cur = 'auto'; |
|
2062 if (drag.proxy.get('resizeFrame')) { |
|
2063 DDM._proxy.setStyles({ |
|
2064 height: n.get('offsetHeight') + 'px', |
|
2065 width: n.get('offsetWidth') + 'px' |
|
2066 }); |
|
2067 } |
|
2068 |
|
2069 ah = DDM.activeDrag.get('activeHandle'); |
|
2070 if (ah) { |
|
2071 cur = ah.getStyle('cursor'); |
|
2072 } |
|
2073 if (cur == 'auto') { |
|
2074 cur = DDM.get('dragCursor'); |
|
2075 } |
|
2076 |
|
2077 |
|
2078 d.setStyles({ |
|
2079 visibility: 'hidden', |
|
2080 display: 'block', |
|
2081 cursor: cur, |
|
2082 border: drag.proxy.get('borderStyle') |
|
2083 }); |
|
2084 |
|
2085 |
|
2086 |
|
2087 if (drag.proxy.get('positionProxy')) { |
|
2088 d.setXY(drag.nodeXY); |
|
2089 } |
|
2090 d.setStyle('visibility', 'visible'); |
|
2091 } |
|
2092 }); |
|
2093 |
|
2094 //Create the frame when DOM is ready |
|
2095 Y.on('domready', Y.bind(DDM._createFrame, DDM)); |
|
2096 |
|
2097 |
|
2098 |
|
2099 }, '3.0.0b1' ,{requires:['dd-ddm', 'dd-drag'], skinnable:false}); |
|
2100 YUI.add('dd-constrain', function(Y) { |
|
2101 |
|
2102 |
|
2103 /** |
|
2104 * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic. |
|
2105 * @module dd |
|
2106 * @submodule dd-constrain |
|
2107 */ |
|
2108 /** |
|
2109 * This is a plugin for the dd-drag module to add the constraining methods to it. It supports constraining to a renodenode or viewport. It anode* supports tick based moves and XY axis constraints. |
|
2110 * @class DragConstrained |
|
2111 * @extends Base |
|
2112 * @constructor |
|
2113 * @namespace Plugin |
|
2114 */ |
|
2115 |
|
2116 var DRAG_NODE = 'dragNode', |
|
2117 OFFSET_HEIGHT = 'offsetHeight', |
|
2118 OFFSET_WIDTH = 'offsetWidth', |
|
2119 HOST = 'host', |
|
2120 CON_2_REGION = 'constrain2region', |
|
2121 CON_2_NODE = 'constrain2node', |
|
2122 TICK_X_ARRAY = 'tickXArray', |
|
2123 TICK_Y_ARRAY = 'tickYArray', |
|
2124 DDM = Y.DD.DDM, |
|
2125 TOP = 'top', |
|
2126 RIGHT = 'right', |
|
2127 BOTTOM = 'bottom', |
|
2128 LEFT = 'left', |
|
2129 proto = null; |
|
2130 |
|
2131 var C = function(config) { |
|
2132 C.superclass.constructor.apply(this, arguments); |
|
2133 }; |
|
2134 |
|
2135 C.NAME = 'DragConstrained'; |
|
2136 /** |
|
2137 * @property con |
|
2138 * @description The Constrained instance will be placed on the Drag instance under the con namespace. |
|
2139 * @type {String} |
|
2140 */ |
|
2141 C.NS = 'con'; |
|
2142 |
|
2143 C.ATTRS = { |
|
2144 host: { |
|
2145 }, |
|
2146 /** |
|
2147 * @attribute stickX |
|
2148 * @description Stick the drag movement to the X-Axis. Default: false |
|
2149 * @type Boolean |
|
2150 */ |
|
2151 stickX: { |
|
2152 value: false |
|
2153 }, |
|
2154 /** |
|
2155 * @attribute stickY |
|
2156 * @description Stick the drag movement to the Y-Axis |
|
2157 * @type Boolean |
|
2158 */ |
|
2159 stickY: { |
|
2160 value: false |
|
2161 }, |
|
2162 /** |
|
2163 * @attribute tickX |
|
2164 * @description The X tick offset the drag node should snap to on each drag move. False for no ticks. Default: false |
|
2165 * @type Number/false |
|
2166 */ |
|
2167 tickX: { |
|
2168 value: false |
|
2169 }, |
|
2170 /** |
|
2171 * @attribute tickY |
|
2172 * @description The Y tick offset the drag node should snap to on each drag move. False for no ticks. Default: false |
|
2173 * @type Number/false |
|
2174 */ |
|
2175 tickY: { |
|
2176 value: false |
|
2177 }, |
|
2178 /** |
|
2179 * @attribute tickXArray |
|
2180 * @description An array of page coordinates to use as X ticks for drag movement. |
|
2181 * @type Array |
|
2182 */ |
|
2183 tickXArray: { |
|
2184 value: false |
|
2185 }, |
|
2186 /** |
|
2187 * @attribute tickYArray |
|
2188 * @description An array of page coordinates to use as Y ticks for drag movement. |
|
2189 * @type Array |
|
2190 */ |
|
2191 tickYArray: { |
|
2192 value: false |
|
2193 }, |
|
2194 /** |
|
2195 * @attribute constrain2region |
|
2196 * @description An Object Literal containing a valid region (top, right, bottom, left) of page positions to constrain the drag node to. |
|
2197 * @type Object |
|
2198 */ |
|
2199 constrain2region: { |
|
2200 value: false, |
|
2201 getter: function(r) { |
|
2202 if (Y.Lang.isObject(r)) { |
|
2203 var o = {}; |
|
2204 Y.mix(o, r); |
|
2205 return o; |
|
2206 } else { |
|
2207 return false; |
|
2208 } |
|
2209 }, |
|
2210 setter: function (r) { |
|
2211 if (Y.Lang.isObject(r)) { |
|
2212 if (Y.Lang.isNumber(r[TOP]) && Y.Lang.isNumber(r[RIGHT]) && Y.Lang.isNumber(r[LEFT]) && Y.Lang.isNumber(r[BOTTOM])) { |
|
2213 var o = {}; |
|
2214 Y.mix(o, r); |
|
2215 return o; |
|
2216 } else { |
|
2217 return false; |
|
2218 } |
|
2219 } else if (r !== false) { |
|
2220 return false; |
|
2221 } |
|
2222 return r; |
|
2223 } |
|
2224 }, |
|
2225 /** |
|
2226 * @attribute gutter |
|
2227 * @description CSS style string for the gutter of a region (supports negative values): '5 0' (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px) |
|
2228 * @type String |
|
2229 */ |
|
2230 gutter: { |
|
2231 value: '0', |
|
2232 setter: function(gutter) { |
|
2233 return Y.DD.DDM.cssSizestoObject(gutter); |
|
2234 } |
|
2235 }, |
|
2236 /** |
|
2237 * @attribute constrain2node |
|
2238 * @description Will attempt to constrain the drag node to the bounderies of this node. |
|
2239 * @type Object |
|
2240 */ |
|
2241 constrain2node: { |
|
2242 value: false, |
|
2243 setter: function(n) { |
|
2244 if (!this.get(CON_2_REGION)) { |
|
2245 var node = Y.Node.get(n); |
|
2246 if (node) { |
|
2247 return node; |
|
2248 } |
|
2249 } else if (this.get(CON_2_REGION) !== false) { |
|
2250 } |
|
2251 return false; |
|
2252 } |
|
2253 }, |
|
2254 /** |
|
2255 * @attribute constrain2view |
|
2256 * @description Will attempt to constrain the drag node to the bounderies of the viewport region. |
|
2257 * @type Object |
|
2258 */ |
|
2259 constrain2view: { |
|
2260 value: false |
|
2261 } |
|
2262 }; |
|
2263 |
|
2264 proto = { |
|
2265 initializer: function() { |
|
2266 this.get(HOST).on('drag:start', Y.bind(this._handleStart, this)); |
|
2267 this.get(HOST).after('drag:align', Y.bind(this.align, this)); |
|
2268 }, |
|
2269 /** |
|
2270 * @private |
|
2271 * @method _handleStart |
|
2272 * @description Fires on drag:start and clears the _regionCache |
|
2273 */ |
|
2274 _handleStart: function() { |
|
2275 this._regionCache = null; |
|
2276 }, |
|
2277 /** |
|
2278 * @private |
|
2279 * @property _regionCache |
|
2280 * @description Store a cache of the region that we are constraining to |
|
2281 * @type Object |
|
2282 */ |
|
2283 _regionCache: null, |
|
2284 /** |
|
2285 * @private |
|
2286 * @method _cacheRegion |
|
2287 * @description Get's the region and caches it, called from window.resize and when the cache is null |
|
2288 */ |
|
2289 _cacheRegion: function() { |
|
2290 this._regionCache = this.get(CON_2_NODE).get('region'); |
|
2291 }, |
|
2292 /** |
|
2293 * @method getRegion |
|
2294 * @description Get the active region: viewport, node, custom region |
|
2295 * @param {Boolean} inc Include the node's height and width |
|
2296 * @return {Object} |
|
2297 */ |
|
2298 getRegion: function(inc) { |
|
2299 var r = {}, oh = null, ow = null, |
|
2300 g = this.get('gutter'), |
|
2301 host = this.get(HOST); |
|
2302 |
|
2303 if (this.get(CON_2_NODE)) { |
|
2304 if (!this._regionCache) { |
|
2305 Y.on('resize', Y.bind(this._cacheRegion, this), window); |
|
2306 this._cacheRegion(); |
|
2307 } |
|
2308 r = Y.clone(this._regionCache); |
|
2309 } else if (this.get(CON_2_REGION)) { |
|
2310 r = this.get(CON_2_REGION); |
|
2311 } else if (this.get('constrain2view')) { |
|
2312 r = host.get(DRAG_NODE).get('viewportRegion'); |
|
2313 } else { |
|
2314 return false; |
|
2315 } |
|
2316 |
|
2317 Y.each(g, function(i, n) { |
|
2318 if ((n == RIGHT) || (n == BOTTOM)) { |
|
2319 r[n] -= i; |
|
2320 } else { |
|
2321 r[n] += i; |
|
2322 } |
|
2323 }); |
|
2324 if (inc) { |
|
2325 oh = host.get(DRAG_NODE).get(OFFSET_HEIGHT); |
|
2326 ow = host.get(DRAG_NODE).get(OFFSET_WIDTH); |
|
2327 r[RIGHT] = r[RIGHT] - ow; |
|
2328 r[BOTTOM] = r[BOTTOM] - oh; |
|
2329 } |
|
2330 return r; |
|
2331 }, |
|
2332 /** |
|
2333 * @private |
|
2334 * @method _checkRegion |
|
2335 * @description Check if xy is inside a given region, if not change to it be inside. |
|
2336 * @param {Array} _xy The XY to check if it's in the current region, if it isn't inside the region, it will reset the xy array to be inside the region. |
|
2337 * @return {Array} The new XY that is inside the region |
|
2338 */ |
|
2339 _checkRegion: function(_xy) { |
|
2340 var oxy = _xy, |
|
2341 r = this.getRegion(), |
|
2342 host = this.get(HOST), |
|
2343 oh = host.get(DRAG_NODE).get(OFFSET_HEIGHT), |
|
2344 ow = host.get(DRAG_NODE).get(OFFSET_WIDTH); |
|
2345 |
|
2346 if (oxy[1] > (r[BOTTOM] - oh)) { |
|
2347 _xy[1] = (r[BOTTOM] - oh); |
|
2348 } |
|
2349 if (r[TOP] > oxy[1]) { |
|
2350 _xy[1] = r[TOP]; |
|
2351 |
|
2352 } |
|
2353 if (oxy[0] > (r[RIGHT] - ow)) { |
|
2354 _xy[0] = (r[RIGHT] - ow); |
|
2355 } |
|
2356 if (r[LEFT] > oxy[0]) { |
|
2357 _xy[0] = r[LEFT]; |
|
2358 } |
|
2359 |
|
2360 return _xy; |
|
2361 }, |
|
2362 /** |
|
2363 * @method inRegion |
|
2364 * @description Checks if the XY passed or the dragNode is inside the active region. |
|
2365 * @param {Array} xy Optional XY to check, if not supplied this.get('dragNode').getXY() is used. |
|
2366 * @return {Boolean} True if the XY is inside the region, false otherwise. |
|
2367 */ |
|
2368 inRegion: function(xy) { |
|
2369 xy = xy || this.get(HOST).get(DRAG_NODE).getXY(); |
|
2370 |
|
2371 var _xy = this._checkRegion([xy[0], xy[1]]), |
|
2372 inside = false; |
|
2373 if ((xy[0] === _xy[0]) && (xy[1] === _xy[1])) { |
|
2374 inside = true; |
|
2375 } |
|
2376 return inside; |
|
2377 }, |
|
2378 /** |
|
2379 * @method align |
|
2380 * @description Modifies the Drag.actXY method from the after drag:align event. This is where the constraining happens. |
|
2381 */ |
|
2382 align: function() { |
|
2383 var host = this.get(HOST), |
|
2384 _xy = host.actXY, |
|
2385 r = this.getRegion(true); |
|
2386 |
|
2387 if (this.get('stickX')) { |
|
2388 _xy[1] = (host.startXY[1] - host.deltaXY[1]); |
|
2389 } |
|
2390 if (this.get('stickY')) { |
|
2391 _xy[0] = (host.startXY[0] - host.deltaXY[0]); |
|
2392 } |
|
2393 |
|
2394 if (r) { |
|
2395 _xy = this._checkRegion(_xy); |
|
2396 } |
|
2397 |
|
2398 _xy = this._checkTicks(_xy, r); |
|
2399 host.actXY = _xy; |
|
2400 }, |
|
2401 /** |
|
2402 * @private |
|
2403 * @method _checkTicks |
|
2404 * @description This method delegates the proper helper method for tick calculations |
|
2405 * @param {Array} xy The XY coords for the Drag |
|
2406 * @param {Object} r The optional region that we are bound to. |
|
2407 * @return {Array} The calced XY coords |
|
2408 */ |
|
2409 _checkTicks: function(xy, r) { |
|
2410 var host = this.get(HOST), |
|
2411 lx = (host.startXY[0] - host.deltaXY[0]), |
|
2412 ly = (host.startXY[1] - host.deltaXY[1]), |
|
2413 xt = this.get('tickX'), |
|
2414 yt = this.get('tickY'); |
|
2415 if (xt && !this.get(TICK_X_ARRAY)) { |
|
2416 xy[0] = DDM._calcTicks(xy[0], lx, xt, r[LEFT], r[RIGHT]); |
|
2417 } |
|
2418 if (yt && !this.get(TICK_Y_ARRAY)) { |
|
2419 xy[1] = DDM._calcTicks(xy[1], ly, yt, r[TOP], r[BOTTOM]); |
|
2420 } |
|
2421 if (this.get(TICK_X_ARRAY)) { |
|
2422 xy[0] = DDM._calcTickArray(xy[0], this.get(TICK_X_ARRAY), r[LEFT], r[RIGHT]); |
|
2423 } |
|
2424 if (this.get(TICK_Y_ARRAY)) { |
|
2425 xy[1] = DDM._calcTickArray(xy[1], this.get(TICK_Y_ARRAY), r[TOP], r[BOTTOM]); |
|
2426 } |
|
2427 |
|
2428 return xy; |
|
2429 } |
|
2430 }; |
|
2431 |
|
2432 Y.namespace('Plugin'); |
|
2433 Y.extend(C, Y.Base, proto); |
|
2434 Y.Plugin.DDConstrained = C; |
|
2435 |
|
2436 Y.mix(DDM, { |
|
2437 /** |
|
2438 * @for DDM |
|
2439 * @namespace DD |
|
2440 * @private |
|
2441 * @method _calcTicks |
|
2442 * @description Helper method to calculate the tick offsets for a given position |
|
2443 * @param {Number} pos The current X or Y position |
|
2444 * @param {Number} start The start X or Y position |
|
2445 * @param {Number} tick The X or Y tick increment |
|
2446 * @param {Number} off1 The min offset that we can't pass (region) |
|
2447 * @param {Number} off2 The max offset that we can't pass (region) |
|
2448 * @return {Number} The new position based on the tick calculation |
|
2449 */ |
|
2450 _calcTicks: function(pos, start, tick, off1, off2) { |
|
2451 var ix = ((pos - start) / tick), |
|
2452 min = Math.floor(ix), |
|
2453 max = Math.ceil(ix); |
|
2454 if ((min !== 0) || (max !== 0)) { |
|
2455 if ((ix >= min) && (ix <= max)) { |
|
2456 pos = (start + (tick * min)); |
|
2457 if (off1 && off2) { |
|
2458 if (pos < off1) { |
|
2459 pos = (start + (tick * (min + 1))); |
|
2460 } |
|
2461 if (pos > off2) { |
|
2462 pos = (start + (tick * (min - 1))); |
|
2463 } |
|
2464 } |
|
2465 } |
|
2466 } |
|
2467 return pos; |
|
2468 }, |
|
2469 /** |
|
2470 * @for DDM |
|
2471 * @namespace DD |
|
2472 * @private |
|
2473 * @method _calcTickArray |
|
2474 * @description This method is used with the tickXArray and tickYArray config options |
|
2475 * @param {Number} pos The current X or Y position |
|
2476 * @param {Number} ticks The array containing our custom tick positions. |
|
2477 * @param {Number} off1 The min offset that we can't pass (region) |
|
2478 * @param {Number} off2 The max offset that we can't pass (region) |
|
2479 * @return The tick position |
|
2480 */ |
|
2481 _calcTickArray: function(pos, ticks, off1, off2) { |
|
2482 var i = 0, len = ticks.length, next = 0, |
|
2483 diff1, diff2, ret; |
|
2484 |
|
2485 if (!ticks || (ticks.length === 0)) { |
|
2486 return pos; |
|
2487 } else if (ticks[0] >= pos) { |
|
2488 return ticks[0]; |
|
2489 } else { |
|
2490 for (i = 0; i < len; i++) { |
|
2491 next = (i + 1); |
|
2492 if (ticks[next] && ticks[next] >= pos) { |
|
2493 diff1 = pos - ticks[i]; |
|
2494 diff2 = ticks[next] - pos; |
|
2495 ret = (diff2 > diff1) ? ticks[i] : ticks[next]; |
|
2496 if (off1 && off2) { |
|
2497 if (ret > off2) { |
|
2498 if (ticks[i]) { |
|
2499 ret = ticks[i]; |
|
2500 } else { |
|
2501 ret = ticks[len - 1]; |
|
2502 } |
|
2503 } |
|
2504 } |
|
2505 return ret; |
|
2506 } |
|
2507 |
|
2508 } |
|
2509 return ticks[ticks.length - 1]; |
|
2510 } |
|
2511 } |
|
2512 }); |
|
2513 |
|
2514 |
|
2515 |
|
2516 |
|
2517 }, '3.0.0b1' ,{requires:['dd-drag'], skinnable:false}); |
|
2518 YUI.add('dd-scroll', function(Y) { |
|
2519 |
|
2520 |
|
2521 /** |
|
2522 * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic. |
|
2523 * @module dd |
|
2524 * @submodule dd-scroll |
|
2525 */ |
|
2526 /** |
|
2527 * This class is the base scroller class used to create the Plugin.DDNodeScroll and Plugin.DDWinScroll. |
|
2528 * This class should not be called on it's own, it's designed to be a plugin. |
|
2529 * @class Scroll |
|
2530 * @extends Base |
|
2531 * @namespace DD |
|
2532 * @constructor |
|
2533 */ |
|
2534 |
|
2535 var S = function() { |
|
2536 S.superclass.constructor.apply(this, arguments); |
|
2537 |
|
2538 }, |
|
2539 HOST = 'host', |
|
2540 BUFFER = 'buffer', |
|
2541 PARENT_SCROLL = 'parentScroll', |
|
2542 WINDOW_SCROLL = 'windowScroll', |
|
2543 SCROLL_TOP = 'scrollTop', |
|
2544 SCROLL_LEFT = 'scrollLeft', |
|
2545 OFFSET_WIDTH = 'offsetWidth', |
|
2546 OFFSET_HEIGHT = 'offsetHeight'; |
|
2547 |
|
2548 |
|
2549 S.ATTRS = { |
|
2550 /** |
|
2551 * @attribute parentScroll |
|
2552 * @description Internal config option to hold the node that we are scrolling. Should not be set by the developer. |
|
2553 * @type Node |
|
2554 */ |
|
2555 parentScroll: { |
|
2556 value: false, |
|
2557 setter: function(node) { |
|
2558 if (node) { |
|
2559 return node; |
|
2560 } |
|
2561 return false; |
|
2562 } |
|
2563 }, |
|
2564 /** |
|
2565 * @attribute buffer |
|
2566 * @description The number of pixels from the edge of the screen to turn on scrolling. Default: 30 |
|
2567 * @type Number |
|
2568 */ |
|
2569 buffer: { |
|
2570 value: 30 |
|
2571 }, |
|
2572 /** |
|
2573 * @attribute scrollDelay |
|
2574 * @description The number of milliseconds delay to pass to the auto scroller. Default: 235 |
|
2575 * @type Number |
|
2576 */ |
|
2577 scrollDelay: { |
|
2578 value: 235 |
|
2579 }, |
|
2580 /** |
|
2581 * @attribute host |
|
2582 * @description The host we are plugged into. |
|
2583 * @type Object |
|
2584 */ |
|
2585 host: { |
|
2586 value: null |
|
2587 }, |
|
2588 /** |
|
2589 * @attribute windowScroll |
|
2590 * @description Turn on window scroll support, default: false |
|
2591 * @type Boolean |
|
2592 */ |
|
2593 windowScroll: { |
|
2594 value: false |
|
2595 }, |
|
2596 /** |
|
2597 * @attribute vertical |
|
2598 * @description Allow vertical scrolling, default: true. |
|
2599 * @type Boolean |
|
2600 */ |
|
2601 vertical: { |
|
2602 value: true |
|
2603 }, |
|
2604 /** |
|
2605 * @attribute horizontal |
|
2606 * @description Allow horizontal scrolling, default: true. |
|
2607 * @type Boolean |
|
2608 */ |
|
2609 horizontal: { |
|
2610 value: true |
|
2611 } |
|
2612 }; |
|
2613 |
|
2614 Y.extend(S, Y.Base, { |
|
2615 /** |
|
2616 * @private |
|
2617 * @property _scrolling |
|
2618 * @description Tells if we are actively scrolling or not. |
|
2619 * @type Boolean |
|
2620 */ |
|
2621 _scrolling: null, |
|
2622 /** |
|
2623 * @private |
|
2624 * @property _vpRegionCache |
|
2625 * @description Cache of the Viewport dims. |
|
2626 * @type Object |
|
2627 */ |
|
2628 _vpRegionCache: null, |
|
2629 /** |
|
2630 * @private |
|
2631 * @property _dimCache |
|
2632 * @description Cache of the dragNode dims. |
|
2633 * @type Object |
|
2634 */ |
|
2635 _dimCache: null, |
|
2636 /** |
|
2637 * @private |
|
2638 * @property _scrollTimer |
|
2639 * @description Holder for the Timer object returned from Y.later. |
|
2640 * @type {Y.later} |
|
2641 */ |
|
2642 _scrollTimer: null, |
|
2643 /** |
|
2644 * @private |
|
2645 * @method _getVPRegion |
|
2646 * @description Sets the _vpRegionCache property with an Object containing the dims from the viewport. |
|
2647 */ |
|
2648 _getVPRegion: function() { |
|
2649 var r = {}; |
|
2650 //if (!this._vpRegionCache) { |
|
2651 var n = this.get(PARENT_SCROLL), |
|
2652 b = this.get(BUFFER), |
|
2653 ws = this.get(WINDOW_SCROLL), |
|
2654 xy = ((ws) ? [] : n.getXY()), |
|
2655 w = ((ws) ? 'winWidth' : OFFSET_WIDTH), |
|
2656 h = ((ws) ? 'winHeight' : OFFSET_HEIGHT), |
|
2657 t = ((ws) ? n.get(SCROLL_TOP) : xy[1]), |
|
2658 l = ((ws) ? n.get(SCROLL_LEFT) : xy[0]); |
|
2659 |
|
2660 r = { |
|
2661 top: t + b, |
|
2662 right: (n.get(w) + l) - b, |
|
2663 bottom: (n.get(h) + t) - b, |
|
2664 left: l + b |
|
2665 }; |
|
2666 this._vpRegionCache = r; |
|
2667 //} else { |
|
2668 // r = this._vpRegionCache; |
|
2669 //} |
|
2670 return r; |
|
2671 }, |
|
2672 initializer: function() { |
|
2673 var h = this.get(HOST); |
|
2674 h.after('drag:start', Y.bind(this.start, this)); |
|
2675 h.after('drag:end', Y.bind(this.end, this)); |
|
2676 h.on('drag:align', Y.bind(this.align, this)); |
|
2677 |
|
2678 //TODO - This doesn't work yet?? |
|
2679 Y.get(window).on('scroll', Y.bind(function() { |
|
2680 this._vpRegionCache = null; |
|
2681 }, this)); |
|
2682 }, |
|
2683 /** |
|
2684 * @private |
|
2685 * @method _checkWinScroll |
|
2686 * @description Check to see if we need to fire the scroll timer. If scroll timer is running this will scroll the window. |
|
2687 * @param {Boolean} move Should we move the window. From Y.later |
|
2688 */ |
|
2689 _checkWinScroll: function(move) { |
|
2690 var r = this._getVPRegion(), |
|
2691 ho = this.get(HOST), |
|
2692 ws = this.get(WINDOW_SCROLL), |
|
2693 xy = ho.lastXY, |
|
2694 scroll = false, |
|
2695 b = this.get(BUFFER), |
|
2696 win = this.get(PARENT_SCROLL), |
|
2697 sTop = win.get(SCROLL_TOP), |
|
2698 sLeft = win.get(SCROLL_LEFT), |
|
2699 w = this._dimCache.w, |
|
2700 h = this._dimCache.h, |
|
2701 bottom = xy[1] + h, |
|
2702 top = xy[1], |
|
2703 right = xy[0] + w, |
|
2704 left = xy[0], |
|
2705 nt = top, |
|
2706 nl = left, |
|
2707 st = sTop, |
|
2708 sl = sLeft; |
|
2709 |
|
2710 if (this.get('horizontal')) { |
|
2711 if (left <= r.left) { |
|
2712 scroll = true; |
|
2713 nl = xy[0] - ((ws) ? b : 0); |
|
2714 sl = sLeft - b; |
|
2715 } |
|
2716 if (right >= r.right) { |
|
2717 scroll = true; |
|
2718 nl = xy[0] + ((ws) ? b : 0); |
|
2719 sl = sLeft + b; |
|
2720 } |
|
2721 } |
|
2722 if (this.get('vertical')) { |
|
2723 if (bottom >= r.bottom) { |
|
2724 scroll = true; |
|
2725 nt = xy[1] + ((ws) ? b : 0); |
|
2726 st = sTop + b; |
|
2727 |
|
2728 } |
|
2729 if (top <= r.top) { |
|
2730 scroll = true; |
|
2731 nt = xy[1] - ((ws) ? b : 0); |
|
2732 st = sTop - b; |
|
2733 } |
|
2734 } |
|
2735 |
|
2736 if (st < 0) { |
|
2737 st = 0; |
|
2738 nt = xy[1]; |
|
2739 } |
|
2740 |
|
2741 if (sl < 0) { |
|
2742 sl = 0; |
|
2743 nl = xy[0]; |
|
2744 } |
|
2745 |
|
2746 if (nt < 0) { |
|
2747 nt = xy[1]; |
|
2748 } |
|
2749 if (nl < 0) { |
|
2750 nl = xy[0]; |
|
2751 } |
|
2752 if (move) { |
|
2753 ho.actXY = [nl, nt]; |
|
2754 ho._moveNode({ node: win, top: st, left: sl}); |
|
2755 if (!st && !sl) { |
|
2756 this._cancelScroll(); |
|
2757 } |
|
2758 } else { |
|
2759 if (scroll) { |
|
2760 this._initScroll(); |
|
2761 } else { |
|
2762 this._cancelScroll(); |
|
2763 } |
|
2764 } |
|
2765 }, |
|
2766 /** |
|
2767 * @private |
|
2768 * @method _initScroll |
|
2769 * @description Cancel a previous scroll timer and init a new one. |
|
2770 */ |
|
2771 _initScroll: function() { |
|
2772 this._cancelScroll(); |
|
2773 this._scrollTimer = Y.Lang.later(this.get('scrollDelay'), this, this._checkWinScroll, [true], true); |
|
2774 |
|
2775 }, |
|
2776 /** |
|
2777 * @private |
|
2778 * @method _cancelScroll |
|
2779 * @description Cancel a currently running scroll timer. |
|
2780 */ |
|
2781 _cancelScroll: function() { |
|
2782 this._scrolling = false; |
|
2783 if (this._scrollTimer) { |
|
2784 this._scrollTimer.cancel(); |
|
2785 delete this._scrollTimer; |
|
2786 } |
|
2787 }, |
|
2788 /** |
|
2789 * @method align |
|
2790 * @description Called from the drag:align event to determine if we need to scroll. |
|
2791 */ |
|
2792 align: function(e) { |
|
2793 if (this._scrolling) { |
|
2794 this._cancelScroll(); |
|
2795 e.preventDefault(); |
|
2796 } |
|
2797 if (!this._scrolling) { |
|
2798 this._checkWinScroll(); |
|
2799 } |
|
2800 }, |
|
2801 /** |
|
2802 * @private |
|
2803 * @method _setDimCache |
|
2804 * @description Set the cache of the dragNode dims. |
|
2805 */ |
|
2806 _setDimCache: function() { |
|
2807 var node = this.get(HOST).get('dragNode'); |
|
2808 this._dimCache = { |
|
2809 h: node.get(OFFSET_HEIGHT), |
|
2810 w: node.get(OFFSET_WIDTH) |
|
2811 }; |
|
2812 }, |
|
2813 /** |
|
2814 * @method start |
|
2815 * @description Called from the drag:start event |
|
2816 */ |
|
2817 start: function() { |
|
2818 this._setDimCache(); |
|
2819 }, |
|
2820 /** |
|
2821 * @method end |
|
2822 * @description Called from the drag:end event |
|
2823 */ |
|
2824 end: function(xy) { |
|
2825 this._dimCache = null; |
|
2826 this._cancelScroll(); |
|
2827 }, |
|
2828 /** |
|
2829 * @method toString |
|
2830 * @description General toString method for logging |
|
2831 * @return String name for the object |
|
2832 */ |
|
2833 toString: function() { |
|
2834 return S.NAME + ' #' + this.get('node').get('id'); |
|
2835 } |
|
2836 }); |
|
2837 |
|
2838 Y.namespace('Plugin'); |
|
2839 |
|
2840 |
|
2841 /** |
|
2842 * Extends the Scroll class to make the window scroll while dragging. |
|
2843 * @class DDWindowScroll |
|
2844 * @extends DD.Scroll |
|
2845 * @namespace Plugin |
|
2846 * @constructor |
|
2847 */ |
|
2848 var WS = function() { |
|
2849 WS.superclass.constructor.apply(this, arguments); |
|
2850 }; |
|
2851 WS.ATTRS = Y.merge(S.ATTRS, { |
|
2852 /** |
|
2853 * @attribute windowScroll |
|
2854 * @description Turn on window scroll support, default: true |
|
2855 * @type Boolean |
|
2856 */ |
|
2857 windowScroll: { |
|
2858 value: true, |
|
2859 setter: function(scroll) { |
|
2860 if (scroll) { |
|
2861 this.set(PARENT_SCROLL, Y.get(window)); |
|
2862 } |
|
2863 return scroll; |
|
2864 } |
|
2865 } |
|
2866 }); |
|
2867 Y.extend(WS, S, { |
|
2868 //Shouldn't have to do this.. |
|
2869 initializer: function() { |
|
2870 this.set('windowScroll', this.get('windowScroll')); |
|
2871 } |
|
2872 }); |
|
2873 WS.NAME = WS.NS = 'winscroll'; |
|
2874 Y.Plugin.DDWinScroll = WS; |
|
2875 |
|
2876 |
|
2877 /** |
|
2878 * Extends the Scroll class to make a parent node scroll while dragging. |
|
2879 * @class DDNodeScroll |
|
2880 * @extends DD.Scroll |
|
2881 * @namespace Plugin |
|
2882 * @constructor |
|
2883 */ |
|
2884 var NS = function() { |
|
2885 NS.superclass.constructor.apply(this, arguments); |
|
2886 |
|
2887 }; |
|
2888 NS.ATTRS = Y.merge(S.ATTRS, { |
|
2889 /** |
|
2890 * @attribute node |
|
2891 * @description The node we want to scroll. Used to set the internal parentScroll attribute. |
|
2892 * @type Node |
|
2893 */ |
|
2894 node: { |
|
2895 value: false, |
|
2896 setter: function(node) { |
|
2897 var n = Y.get(node); |
|
2898 if (!n) { |
|
2899 if (node !== false) { |
|
2900 Y.error('DDNodeScroll: Invalid Node Given: ' + node); |
|
2901 } |
|
2902 } else { |
|
2903 n = n.item(0); |
|
2904 this.set(PARENT_SCROLL, n); |
|
2905 } |
|
2906 return n; |
|
2907 } |
|
2908 } |
|
2909 }); |
|
2910 Y.extend(NS, S, { |
|
2911 //Shouldn't have to do this.. |
|
2912 initializer: function() { |
|
2913 this.set('node', this.get('node')); |
|
2914 } |
|
2915 }); |
|
2916 NS.NAME = NS.NS = 'nodescroll'; |
|
2917 Y.Plugin.DDNodeScroll = NS; |
|
2918 |
|
2919 Y.DD.Scroll = S; |
|
2920 |
|
2921 |
|
2922 |
|
2923 }, '3.0.0b1' ,{skinnable:false, requires:['dd-drag'], optional:['dd-proxy']}); |
|
2924 YUI.add('dd-plugin', function(Y) { |
|
2925 |
|
2926 |
|
2927 /** |
|
2928 * This is a simple Drag plugin that can be attached to a Node via the plug method. |
|
2929 * @module dd |
|
2930 * @submodule dd-plugin |
|
2931 */ |
|
2932 /** |
|
2933 * This is a simple Drag plugin that can be attached to a Node via the plug method. |
|
2934 * @class Drag |
|
2935 * @extends DD.Drag |
|
2936 * @constructor |
|
2937 * @namespace Plugin |
|
2938 */ |
|
2939 |
|
2940 |
|
2941 var Drag = function(config) { |
|
2942 config.node = config.host; |
|
2943 Drag.superclass.constructor.apply(this, arguments); |
|
2944 }; |
|
2945 |
|
2946 /** |
|
2947 * @property NAME |
|
2948 * @description dd-plugin |
|
2949 * @type {String} |
|
2950 */ |
|
2951 Drag.NAME = "dd-plugin"; |
|
2952 |
|
2953 /** |
|
2954 * @property NS |
|
2955 * @description The Drag instance will be placed on the Node instance under the dd namespace. It can be accessed via Node.dd; |
|
2956 * @type {String} |
|
2957 */ |
|
2958 Drag.NS = "dd"; |
|
2959 |
|
2960 |
|
2961 Y.extend(Drag, Y.DD.Drag); |
|
2962 Y.namespace('Plugin'); |
|
2963 Y.Plugin.Drag = Drag; |
|
2964 |
|
2965 |
|
2966 |
|
2967 |
|
2968 |
|
2969 }, '3.0.0b1' ,{skinnable:false, requires:['dd-drag'], optional:['dd-constrain', 'dd-proxy']}); |
|
2970 YUI.add('dd-drop', function(Y) { |
|
2971 |
|
2972 |
|
2973 /** |
|
2974 * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic. |
|
2975 * @module dd |
|
2976 * @submodule dd-drop |
|
2977 */ |
|
2978 /** |
|
2979 * This class provides the ability to create a Drop Target. |
|
2980 * @class Drop |
|
2981 * @extends Base |
|
2982 * @constructor |
|
2983 * @namespace DD |
|
2984 */ |
|
2985 |
|
2986 var NODE = 'node', |
|
2987 DDM = Y.DD.DDM, |
|
2988 OFFSET_HEIGHT = 'offsetHeight', |
|
2989 OFFSET_WIDTH = 'offsetWidth', |
|
2990 /** |
|
2991 * @event drop:over |
|
2992 * @description Fires when a drag element is over this target. |
|
2993 * @bubbles DDM |
|
2994 * @type {Event.Custom} |
|
2995 */ |
|
2996 EV_DROP_OVER = 'drop:over', |
|
2997 /** |
|
2998 * @event drop:enter |
|
2999 * @description Fires when a drag element enters this target. |
|
3000 * @bubbles DDM |
|
3001 * @type {Event.Custom} |
|
3002 */ |
|
3003 EV_DROP_ENTER = 'drop:enter', |
|
3004 /** |
|
3005 * @event drop:exit |
|
3006 * @description Fires when a drag element exits this target. |
|
3007 * @bubbles DDM |
|
3008 * @type {Event.Custom} |
|
3009 */ |
|
3010 EV_DROP_EXIT = 'drop:exit', |
|
3011 |
|
3012 /** |
|
3013 * @event drop:hit |
|
3014 * @description Fires when a draggable node is dropped on this Drop Target. (Fired from dd-ddm-drop) |
|
3015 * @bubbles DDM |
|
3016 * @type {Event.Custom} |
|
3017 */ |
|
3018 |
|
3019 |
|
3020 Drop = function() { |
|
3021 this._lazyAddAttrs = false; |
|
3022 Drop.superclass.constructor.apply(this, arguments); |
|
3023 |
|
3024 |
|
3025 //DD init speed up. |
|
3026 Y.on('domready', Y.bind(function() { |
|
3027 Y.later(100, this, this._createShim); |
|
3028 }, this)); |
|
3029 DDM._regTarget(this); |
|
3030 |
|
3031 /* TODO |
|
3032 if (Dom.getStyle(this.el, 'position') == 'fixed') { |
|
3033 Event.on(window, 'scroll', function() { |
|
3034 this.activateShim(); |
|
3035 }, this, true); |
|
3036 } |
|
3037 */ |
|
3038 }; |
|
3039 |
|
3040 Drop.NAME = 'drop'; |
|
3041 |
|
3042 Drop.ATTRS = { |
|
3043 /** |
|
3044 * @attribute node |
|
3045 * @description Y.Node instanace to use as the element to make a Drop Target |
|
3046 * @type Node |
|
3047 */ |
|
3048 node: { |
|
3049 setter: function(node) { |
|
3050 var n = Y.Node.get(node); |
|
3051 if (!n) { |
|
3052 Y.error('DD.Drop: Invalid Node Given: ' + node); |
|
3053 } |
|
3054 return n; |
|
3055 } |
|
3056 }, |
|
3057 /** |
|
3058 * @attribute groups |
|
3059 * @description Array of groups to add this drop into. |
|
3060 * @type Array |
|
3061 */ |
|
3062 groups: { |
|
3063 value: ['default'], |
|
3064 setter: function(g) { |
|
3065 this._groups = {}; |
|
3066 Y.each(g, function(v, k) { |
|
3067 this._groups[v] = true; |
|
3068 }, this); |
|
3069 return g; |
|
3070 } |
|
3071 }, |
|
3072 /** |
|
3073 * @attribute padding |
|
3074 * @description CSS style padding to make the Drop Target bigger than the node. |
|
3075 * @type String |
|
3076 */ |
|
3077 padding: { |
|
3078 value: '0', |
|
3079 setter: function(p) { |
|
3080 return DDM.cssSizestoObject(p); |
|
3081 } |
|
3082 }, |
|
3083 /** |
|
3084 * @attribute lock |
|
3085 * @description Set to lock this drop element. |
|
3086 * @type Boolean |
|
3087 */ |
|
3088 lock: { |
|
3089 value: false, |
|
3090 setter: function(lock) { |
|
3091 if (lock) { |
|
3092 this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-locked'); |
|
3093 } else { |
|
3094 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-locked'); |
|
3095 } |
|
3096 return lock; |
|
3097 } |
|
3098 }, |
|
3099 /** |
|
3100 * @attribute bubbles |
|
3101 * @description Controls the default bubble parent for this Drop instance. Default: Y.DD.DDM. Set to false to disable bubbling. |
|
3102 * @type Object |
|
3103 */ |
|
3104 bubbles: { |
|
3105 writeOnce: true, |
|
3106 value: Y.DD.DDM |
|
3107 } |
|
3108 }; |
|
3109 |
|
3110 Y.extend(Drop, Y.Base, { |
|
3111 /** |
|
3112 * @private |
|
3113 * @method _createEvents |
|
3114 * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling. |
|
3115 */ |
|
3116 _createEvents: function() { |
|
3117 |
|
3118 var ev = [ |
|
3119 EV_DROP_OVER, |
|
3120 EV_DROP_ENTER, |
|
3121 EV_DROP_EXIT, |
|
3122 'drop:hit' |
|
3123 ]; |
|
3124 |
|
3125 Y.each(ev, function(v, k) { |
|
3126 this.publish(v, { |
|
3127 type: v, |
|
3128 emitFacade: true, |
|
3129 preventable: false, |
|
3130 bubbles: true, |
|
3131 queuable: false, |
|
3132 prefix: 'drop' |
|
3133 }); |
|
3134 }, this); |
|
3135 |
|
3136 if (this.get('bubbles')) { |
|
3137 this.addTarget(this.get('bubbles')); |
|
3138 } |
|
3139 |
|
3140 }, |
|
3141 /** |
|
3142 * @private |
|
3143 * @property _valid |
|
3144 * @description Flag for determining if the target is valid in this operation. |
|
3145 * @type Boolean |
|
3146 */ |
|
3147 _valid: null, |
|
3148 /** |
|
3149 * @private |
|
3150 * @property _groups |
|
3151 * @description The groups this target belongs to. |
|
3152 * @type Array |
|
3153 */ |
|
3154 _groups: null, |
|
3155 /** |
|
3156 * @property shim |
|
3157 * @description Node reference to the targets shim |
|
3158 * @type {Object} |
|
3159 */ |
|
3160 shim: null, |
|
3161 /** |
|
3162 * @property region |
|
3163 * @description A region object associated with this target, used for checking regions while dragging. |
|
3164 * @type Object |
|
3165 */ |
|
3166 region: null, |
|
3167 /** |
|
3168 * @property overTarget |
|
3169 * @description This flag is tripped when a drag element is over this target. |
|
3170 * @type Boolean |
|
3171 */ |
|
3172 overTarget: null, |
|
3173 /** |
|
3174 * @method inGroup |
|
3175 * @description Check if this target is in one of the supplied groups. |
|
3176 * @param {Array} groups The groups to check against |
|
3177 * @return Boolean |
|
3178 */ |
|
3179 inGroup: function(groups) { |
|
3180 this._valid = false; |
|
3181 var ret = false; |
|
3182 Y.each(groups, function(v, k) { |
|
3183 if (this._groups[v]) { |
|
3184 ret = true; |
|
3185 this._valid = true; |
|
3186 } |
|
3187 }, this); |
|
3188 return ret; |
|
3189 }, |
|
3190 /** |
|
3191 * @private |
|
3192 * @method initializer |
|
3193 * @description Private lifecycle method |
|
3194 */ |
|
3195 initializer: function() { |
|
3196 //this._createEvents(); |
|
3197 Y.later(100, this, this._createEvents); |
|
3198 |
|
3199 var node = this.get(NODE), id; |
|
3200 if (!node.get('id')) { |
|
3201 id = Y.stamp(node); |
|
3202 node.set('id', id); |
|
3203 } |
|
3204 node.addClass(DDM.CSS_PREFIX + '-drop'); |
|
3205 //Shouldn't have to do this.. |
|
3206 this.set('groups', this.get('groups')); |
|
3207 }, |
|
3208 /** |
|
3209 * @private |
|
3210 * @method destructor |
|
3211 * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners |
|
3212 */ |
|
3213 destructor: function() { |
|
3214 DDM._unregTarget(this); |
|
3215 if (this.shim) { |
|
3216 this.shim.detachAll(); |
|
3217 this.shim.get('parentNode').removeChild(this.shim); |
|
3218 this.shim = null; |
|
3219 } |
|
3220 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop'); |
|
3221 this.detachAll(); |
|
3222 }, |
|
3223 /** |
|
3224 * @private |
|
3225 * @method _deactivateShim |
|
3226 * @description Removes classes from the target, resets some flags and sets the shims deactive position [-999, -999] |
|
3227 */ |
|
3228 _deactivateShim: function() { |
|
3229 if (!this.shim) { |
|
3230 return false; |
|
3231 } |
|
3232 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-valid'); |
|
3233 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-invalid'); |
|
3234 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over'); |
|
3235 this.shim.setStyles({ |
|
3236 top: '-999px', |
|
3237 left: '-999px', |
|
3238 zIndex: '2' |
|
3239 }); |
|
3240 this.overTarget = false; |
|
3241 }, |
|
3242 /** |
|
3243 * @private |
|
3244 * @method _activateShim |
|
3245 * @description Activates the shim and adds some interaction CSS classes |
|
3246 */ |
|
3247 _activateShim: function() { |
|
3248 if (!DDM.activeDrag) { |
|
3249 return false; //Nothing is dragging, no reason to activate. |
|
3250 } |
|
3251 if (this.get(NODE) === DDM.activeDrag.get(NODE)) { |
|
3252 return false; |
|
3253 } |
|
3254 if (this.get('lock')) { |
|
3255 return false; |
|
3256 } |
|
3257 var node = this.get(NODE); |
|
3258 //TODO Visibility Check.. |
|
3259 //if (this.inGroup(DDM.activeDrag.get('groups')) && this.get(NODE).isVisible()) { |
|
3260 if (this.inGroup(DDM.activeDrag.get('groups'))) { |
|
3261 node.removeClass(DDM.CSS_PREFIX + '-drop-active-invalid'); |
|
3262 node.addClass(DDM.CSS_PREFIX + '-drop-active-valid'); |
|
3263 DDM._addValid(this); |
|
3264 this.overTarget = false; |
|
3265 this.sizeShim(); |
|
3266 } else { |
|
3267 DDM._removeValid(this); |
|
3268 node.removeClass(DDM.CSS_PREFIX + '-drop-active-valid'); |
|
3269 node.addClass(DDM.CSS_PREFIX + '-drop-active-invalid'); |
|
3270 } |
|
3271 }, |
|
3272 /** |
|
3273 * @method sizeShim |
|
3274 * @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.. |
|
3275 */ |
|
3276 sizeShim: function() { |
|
3277 if (!DDM.activeDrag) { |
|
3278 return false; //Nothing is dragging, no reason to activate. |
|
3279 } |
|
3280 if (this.get(NODE) === DDM.activeDrag.get(NODE)) { |
|
3281 return false; |
|
3282 } |
|
3283 if (this.get('lock')) { |
|
3284 return false; |
|
3285 } |
|
3286 if (!this.shim) { |
|
3287 Y.later(100, this, this.sizeShim); |
|
3288 return false; |
|
3289 } |
|
3290 var node = this.get(NODE), |
|
3291 nh = node.get(OFFSET_HEIGHT), |
|
3292 nw = node.get(OFFSET_WIDTH), |
|
3293 xy = node.getXY(), |
|
3294 p = this.get('padding'), |
|
3295 dd, dH, dW; |
|
3296 |
|
3297 |
|
3298 //Apply padding |
|
3299 nw = nw + p.left + p.right; |
|
3300 nh = nh + p.top + p.bottom; |
|
3301 xy[0] = xy[0] - p.left; |
|
3302 xy[1] = xy[1] - p.top; |
|
3303 |
|
3304 |
|
3305 if (DDM.activeDrag.get('dragMode') === DDM.INTERSECT) { |
|
3306 //Intersect Mode, make the shim bigger |
|
3307 dd = DDM.activeDrag; |
|
3308 dH = dd.get(NODE).get(OFFSET_HEIGHT); |
|
3309 dW = dd.get(NODE).get(OFFSET_WIDTH); |
|
3310 |
|
3311 nh = (nh + dH); |
|
3312 nw = (nw + dW); |
|
3313 xy[0] = xy[0] - (dW - dd.deltaXY[0]); |
|
3314 xy[1] = xy[1] - (dH - dd.deltaXY[1]); |
|
3315 |
|
3316 } |
|
3317 |
|
3318 //Set the style on the shim |
|
3319 this.shim.setStyles({ |
|
3320 height: nh + 'px', |
|
3321 width: nw + 'px', |
|
3322 top: xy[1] + 'px', |
|
3323 left: xy[0] + 'px' |
|
3324 }); |
|
3325 |
|
3326 //Create the region to be used by intersect when a drag node is over us. |
|
3327 this.region = { |
|
3328 '0': xy[0], |
|
3329 '1': xy[1], |
|
3330 area: 0, |
|
3331 top: xy[1], |
|
3332 right: xy[0] + nw, |
|
3333 bottom: xy[1] + nh, |
|
3334 left: xy[0] |
|
3335 }; |
|
3336 }, |
|
3337 /** |
|
3338 * @private |
|
3339 * @method _createShim |
|
3340 * @description Creates the Target shim and adds it to the DDM's playground.. |
|
3341 */ |
|
3342 _createShim: function() { |
|
3343 //No playground, defer |
|
3344 if (!DDM._pg) { |
|
3345 Y.later(10, this, this._createShim); |
|
3346 return; |
|
3347 } |
|
3348 //Shim already here, cancel |
|
3349 if (this.shim) { |
|
3350 return; |
|
3351 } |
|
3352 var s = Y.Node.create('<div id="' + this.get(NODE).get('id') + '_shim"></div>'); |
|
3353 |
|
3354 s.setStyles({ |
|
3355 height: this.get(NODE).get(OFFSET_HEIGHT) + 'px', |
|
3356 width: this.get(NODE).get(OFFSET_WIDTH) + 'px', |
|
3357 backgroundColor: 'yellow', |
|
3358 opacity: '.5', |
|
3359 zIndex: '1', |
|
3360 overflow: 'hidden', |
|
3361 top: '-900px', |
|
3362 left: '-900px', |
|
3363 position: 'absolute' |
|
3364 }); |
|
3365 DDM._pg.appendChild(s); |
|
3366 this.shim = s; |
|
3367 |
|
3368 s.on('mouseover', Y.bind(this._handleOverEvent, this)); |
|
3369 s.on('mouseout', Y.bind(this._handleOutEvent, this)); |
|
3370 }, |
|
3371 /** |
|
3372 * @private |
|
3373 * @method _handleOverTarget |
|
3374 * @description This handles the over target call made from this object or from the DDM |
|
3375 */ |
|
3376 _handleTargetOver: function() { |
|
3377 if (DDM.isOverTarget(this)) { |
|
3378 this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-over'); |
|
3379 DDM.activeDrop = this; |
|
3380 DDM.otherDrops[this] = this; |
|
3381 if (this.overTarget) { |
|
3382 DDM.activeDrag.fire('drag:over', { drop: this, drag: DDM.activeDrag }); |
|
3383 this.fire(EV_DROP_OVER, { drop: this, drag: DDM.activeDrag }); |
|
3384 } else { |
|
3385 this.overTarget = true; |
|
3386 this.fire(EV_DROP_ENTER, { drop: this, drag: DDM.activeDrag }); |
|
3387 DDM.activeDrag.fire('drag:enter', { drop: this, drag: DDM.activeDrag }); |
|
3388 DDM.activeDrag.get(NODE).addClass(DDM.CSS_PREFIX + '-drag-over'); |
|
3389 //TODO - Is this needed?? |
|
3390 //DDM._handleTargetOver(); |
|
3391 } |
|
3392 } else { |
|
3393 this._handleOut(); |
|
3394 } |
|
3395 }, |
|
3396 /** |
|
3397 * @private |
|
3398 * @method _handleOverEvent |
|
3399 * @description Handles the mouseover DOM event on the Target Shim |
|
3400 */ |
|
3401 _handleOverEvent: function() { |
|
3402 this.shim.setStyle('zIndex', '999'); |
|
3403 DDM._addActiveShim(this); |
|
3404 }, |
|
3405 /** |
|
3406 * @private |
|
3407 * @method _handleOutEvent |
|
3408 * @description Handles the mouseout DOM event on the Target Shim |
|
3409 */ |
|
3410 _handleOutEvent: function() { |
|
3411 this.shim.setStyle('zIndex', '1'); |
|
3412 DDM._removeActiveShim(this); |
|
3413 }, |
|
3414 /** |
|
3415 * @private |
|
3416 * @method _handleOut |
|
3417 * @description Handles out of target calls/checks |
|
3418 */ |
|
3419 _handleOut: function(force) { |
|
3420 if (!DDM.isOverTarget(this) || force) { |
|
3421 if (this.overTarget) { |
|
3422 this.overTarget = false; |
|
3423 if (!force) { |
|
3424 DDM._removeActiveShim(this); |
|
3425 } |
|
3426 if (DDM.activeDrag) { |
|
3427 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over'); |
|
3428 DDM.activeDrag.get(NODE).removeClass(DDM.CSS_PREFIX + '-drag-over'); |
|
3429 this.fire(EV_DROP_EXIT); |
|
3430 DDM.activeDrag.fire('drag:exit', { drop: this }); |
|
3431 delete DDM.otherDrops[this]; |
|
3432 //if (DDM.activeDrop === this) { |
|
3433 // DDM.activeDrop = null; |
|
3434 //} |
|
3435 } |
|
3436 } |
|
3437 } |
|
3438 } |
|
3439 }); |
|
3440 |
|
3441 Y.DD.Drop = Drop; |
|
3442 |
|
3443 |
|
3444 |
|
3445 |
|
3446 |
|
3447 }, '3.0.0b1' ,{requires:['dd-ddm-drop', 'dd-drag'], skinnable:false}); |
|
3448 YUI.add('dd-drop-plugin', function(Y) { |
|
3449 |
|
3450 |
|
3451 /** |
|
3452 * This is a simple Drop plugin that can be attached to a Node via the plug method. |
|
3453 * @module dd |
|
3454 * @submodule dd-drop-plugin |
|
3455 */ |
|
3456 /** |
|
3457 * This is a simple Drop plugin that can be attached to a Node via the plug method. |
|
3458 * @class Drop |
|
3459 * @extends DD.Drop |
|
3460 * @constructor |
|
3461 * @namespace Plugin |
|
3462 */ |
|
3463 |
|
3464 |
|
3465 var Drop = function(config) { |
|
3466 config.node = config.host; |
|
3467 Drop.superclass.constructor.apply(this, arguments); |
|
3468 }; |
|
3469 |
|
3470 /** |
|
3471 * @property NAME |
|
3472 * @description dd-drop-plugin |
|
3473 * @type {String} |
|
3474 */ |
|
3475 Drop.NAME = "dd-drop-plugin"; |
|
3476 /** |
|
3477 * @property NS |
|
3478 * @description The Drop instance will be placed on the Node instance under the drop namespace. It can be accessed via Node.drop; |
|
3479 * @type {String} |
|
3480 */ |
|
3481 Drop.NS = "drop"; |
|
3482 |
|
3483 |
|
3484 Y.extend(Drop, Y.DD.Drop); |
|
3485 Y.namespace('Plugin'); |
|
3486 Y.Plugin.Drop = Drop; |
|
3487 |
|
3488 |
|
3489 |
|
3490 |
|
3491 |
|
3492 }, '3.0.0b1' ,{requires:['dd-drop'], skinnable:false}); |
|
3493 |
|
3494 |
|
3495 YUI.add('dd', function(Y){}, '3.0.0b1' ,{use:['dd-ddm-base', 'dd-ddm', 'dd-ddm-drop', 'dd-drag', 'dd-proxy', 'dd-constrain', 'dd-plugin', 'dd-drop', 'dd-drop-plugin', 'dd-scroll'], skinnable:false}); |
|
3496 |