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