      1 /**
      2  * @ignore
      3  */
      4 var Ozone = Ozone ? Ozone : {};
      5
      6 /**
      7  * @ignore
      8  * @namespace
      9  */
     10 Ozone.dragAndDrop = Ozone.dragAndDrop ? Ozone.dragAndDrop : {};
     11
     12 /**
     13  * @deprecated Since OWF 3.7.0  You should use <a href="#.getInstance">Ozone.dragAndDrop.WidgetDragAndDrop.getInstance</a>
     14  * @constructor
     15  * @param {Object} cfg config object see below for properties
     16  * @param {Object} [cfg.widgetEventingController]  The widgetEventingController.
     17  * @param {Boolean} [cfg.autoInit]  True to automatically call init(), False otherwise.  The default is True if left undefined
     18  * @param {Object} [cfg.callbacks]  Object with callbacks who's names match drag and drop events.  Alternatively one could
     19  * use the <a href="#addCallback">addCallback</a> function
     20  * @description The Ozone.dragAndDrop.WidgetDragAndDrop object manages the drag and drop for an individual widget.
     21  * @requires owfdojo which is a custom version of dojo for OWF
     22  * @requires <a href="Ozone.eventing.Widget.html">Ozone.eventing.Widget</a> for eventing
     23  * @see <a href="#addCallback">addCallback</a>
     24  * @example
     25  *
     26  * var wdd = new Ozone.dragAndDrop.WidgetDragAndDrop({
     27  *                   widgetEventingController: this.widgetEventingController
     28  *               });
     29  *
     30  */
     31 Ozone.dragAndDrop.WidgetDragAndDrop = function(cfg) {
     32
     33     this.listeners = {};
     34     this.callbacks = {};
     35     this.dragging = false;
     36     this.dropEnabledFlag = false;
     37     this.dropZoneHandlers = [];
     38
     39     cfg = cfg || {};
     40
     41     //set initial drag text
     42     this.dragIndicatorText = cfg.dragIndicatorText ? cfg.dragIndicatorText : 'Dragging Data';
     43
     44     if (cfg.callbacks != null && owfdojo.isObject(cfg.callbacks)) {
     45       owfdojo.mixin(this.callbacks, cfg.callbacks)
     46     }
     47
     48     //create drag indicator
     49     this.dragIndicator = this.createDragIndicator();
     50     this.dragIndicatorTextNode = owfdojo.query('span.ddText', this.dragIndicator)[0];
     51
     52     this.widgetEventingController = cfg.widgetEventingController || Ozone.eventing.Widget.instance;
     53
     54     if (cfg.keepMouseListenersAttached === undefined && owfdojo.isIE) {
     55         cfg.keepMouseListenersAttached = true;
     56     }
     57
     58     if (cfg.autoInit || cfg.autoInit === undefined) {
     59         this.init(cfg);
     60     }
     61
     62     function fireMouseEvent(el, type, msg) {
     63         var evt;
     64         if(document.createEvent) {
     65             evt = document.createEvent('MouseEvents');
     66             evt.initMouseEvent(type, true, true, window, 1,
     67                 msg.screenX, msg.screenY, msg.pageX, msg.pageY,
     68                 false, false, false, false, null, null
     69             );
     70             el.dispatchEvent(evt);
     71         } else if( document.createEventObject ) {
     72             evt = document.createEventObject();
     73             el.fireEvent('on' + type, evt);
     74         }
     75     }
     76
     77     gadgets.rpc.register('_fire_mouse_move', owfdojo.hitch(this, function(msg) {
     78
     79         var el = document.elementFromPoint(msg.pageX, msg.pageY);
     80
     81         if(this.getFlashWidgetId()) {
     82             if(msg.sender !== this.widgetEventingController.getWidgetId()) {
     83                 Ozone.util.getFlashApp().dispatchExternalMouseEvent(msg.pageX, msg.pageY);
     84             }
     85             this.mouseMove(msg, true);
     86         }
     87         else {
     88             if(!arguments.callee.lastEl) {
     89                 arguments.callee.lastEl = el;
     90                 fireMouseEvent(el, 'mouseover', msg);
     91             }
     92             else if(arguments.callee.lastEl !== el) {
     93                 //console.log('lastEl ', arguments.callee.lastEl);
     94                 //console.log('el ', el);
     95                 fireMouseEvent(arguments.callee.lastEl, 'mouseout', msg);
     96                 fireMouseEvent(el, 'mouseover', msg);
     97                 arguments.callee.lastEl = el;
     98             }
     99
    100             fireMouseEvent(el, 'mousemove', msg);
    101         }
    102
    103     }));
    104
    105     gadgets.rpc.register('_fire_mouse_up', owfdojo.hitch(this, function(msg) {
    106         var el = document.elementFromPoint(msg.pageX, msg.pageY);
    107         if(el && el.nodeName === 'OBJECT') {
    108             this.mouseUp(msg, true);
    109         }
    110         else {
    111             fireMouseEvent(el, 'mouseup', msg);
    112         }
    113     }));
    114
    115     Ozone.dragAndDrop.WidgetDragAndDrop.instance = this;
    116     return this;
    117 };
    118
    119 Ozone.dragAndDrop.WidgetDragAndDrop.prototype = {
    120
    121   //public events
    122   /**
    123    * @field
    124    * @description dragStart is the name of the event when a drag is started.  Use 'dragStart' with the addCallback function
    125    * to add a callback function when a dragStart event occurs
    126    * @see <a href="#addCallback">addCallback</a>
    127    * @example
    128    *
    129    *  //this.wdd is a initialized WidgetDragAndDrop object
    130    *  this.wdd.addCallback('dragStart',function() {
    131    *    //use this function to change styles or change state when a drag is initiated
    132    *    cmp.dragging = true;
    133    *    cmp.getView().scroller.addCls('ddOver');
    134    *  });
    135    *
    136    */
    137   dragStart: 'dragStart',
    138
    139   /**
    140    * @field
    141    * @description dragStop is the name of the event when a drag is stopped.  Use 'dragStop' with the addCallback function
    142    * to add a callback function when a dragStop event occurs
    143    * @see <a href="#addCallback">addCallback</a>
    144    * @example
    145    *
    146    *  //this.wdd is a initialized WidgetDragAndDrop object
    147    *  this.wdd.addCallback('dragStop',function() {
    148    *    //use this function to change styles or change state when a drag is stopped
    149    *    cmp.dragging = false;
    150    *    cmp.getView().scroller.removeCls('ddOver');
    151    *  });
    152    *
    153    */
    154   dragStop: 'dragStop',
    155
    156   /**
    157    * @field
    158    * @description dropReceive is the name of the event when a drop occurs on this widget.  This event indicates a successful
    159    * drag and drop and data will be passed to the callback function.  Use 'dropReceive' with the addCallback function
    160    * to add a callback function when a dropReceive event occurs.  This callback function for this event will be called for
    161    * all successful drops.  To support multiple drop zones use <a href="#addDropZoneHandler">addDropZoneHandler</a>
    162    * @see <a href="#addCallback">addCallback</a>
    163    * @example
    164    *
    165    *  //this.wdd is a initialized WidgetDragAndDrop object
    166    *   this.wdd.addCallback('dropReceive',function(msg) {
    167    *      //msg.dragDropData contains the data - this example the data is a channel name that will be subscribed to
    168    *      this.subscribeToChannel(msg.dragDropData);
    169    *   }.bind(this));
    170    */
    171   dropReceive: 'dropReceive',
    172
    173   //private events
    174   dragStartName: '_dragStart',
    175   dragOverWidgetName: '_dragOverWidget',
    176   dragOutName: '_dragOutName',
    177   dragStopInContainerName: '_dragStopInContainer',
    178   dragStopInWidgetName: '_dragStopInWidget',
    179   dragSendDataName: "_dragSendData",
    180   dropReceiveDataName: "_dropReceiveData",
    181
    182   /**
    183    * @field
    184    * @description version number
    185    */
    186   version: Ozone.version.owfversion + Ozone.version.dragAndDrop,
    187
    188   /**
    189    * @description Initializes the WidgetDragAndDrop object.  Using this function is only required if autoInit config is false
    190    * in the constructor.  This function is sometimes useful when it is necessary to defer drag and drop event handling after
    191    * creating the Ozone.dragAndDrop.WidgetDragAndDrop object
    192    * @param {Object} [cfg] config object
    193    * @see <a href="#constructor">constructor</a>
    194    */
    195   init : function (cfg) {
    196     cfg = cfg || {};
    197
    198     //subscribe to channels
    199     this.widgetEventingController.subscribe(this.dragStartName, owfdojo.hitch(this, this.onStartDrag));
    200     this.widgetEventingController.subscribe(this.dragOutName, owfdojo.hitch(this, this.onDragOut));
    201     this.widgetEventingController.subscribe(this.dragStopInContainerName, owfdojo.hitch(this, this.onDragStopInContainer));
    202     this.widgetEventingController.subscribe(this.dropReceiveDataName, owfdojo.hitch(this, this.dropReceiveData));
    203
    204     if (cfg.keepMouseListenersAttached === true) {
    205       this.keepMouseListenersAttached = true;
    206
    207       //hook mouse move and mouse up
    208       if (this.listeners.onmousemove == null) {
    209         this.listeners.onmousemove = owfdojo.connect(document, 'onmousemove', this, this.mouseMove);
    210       }
    211       if (this.listeners.onmouseup == null) {
    212         this.listeners.onmouseup = owfdojo.connect(document, 'onmouseup', this, this.mouseUp);
    213       }
    214     }
    215   },
    216
    217   /**
    218    * @private
    219    */
    220   createDragIndicator: function () {
    221     return owfdojo.create('span', {
    222       className: 'ddBox ddBoxCannotDrop',
    223       style: {display: 'none'},
    224       innerHTML: '<span class="ddText">' + this.dragIndicatorText + '</span>'
    225     },
    226     owfdojo.body()
    227     );
    228   },
    229
    230   /**
    231    * @description Starts a drag.  The config object passed in describes the drag and contains the data to be passed to the drop.
    232    * @param {Object} cfg config object see below
    233    * @param {String} cfg.dragDropLabel Name to be used as text for the dragDrop indicator
    234    * @param {Object} cfg.dragDropData Data to be sent on a successful drag and drop.  This property is only sent to the
    235    * successful recipient of the drag (the dropReceive event).  It will not be sent for other events.
    236    * @param {Object} cfg.dragZone dom node which presents a dragZone which is associated with this drag.  This property is
    237    * only saved and used locally to the widget to identify whether a dragZone is in fact the node as a dropZone.  It will not be
    238    * sent to other events callbacks.
    239    * @param {Object} cfg.* other custom properties may be specified, these will be passed along to event handlers
    240    * @example
    241    *
    242    *  //add handler to text field for dragging
    243    *  owfdojo.connect(document.getElementById('dragSource'),'onmousedown',this,function(e) {
    244    *      e.preventDefault();
    245    *      var data = document.getElementById('InputChannel').value;
    246    *      if (data != null && data != '') {
    247    *        this.wdd.doStartDrag({
    248    *            dragDropLabel: data,
    249    *            dragZone:  document.getElementById('dragZone'),
    250    *            dragDropGroup: 'location',  //extra property to pass along
    251    *            dragDropData: data
    252    *        });
    253    *      }
    254    *  });
    255    */
    256   doStartDrag : function (cfg) {
    257
    258     var dragStartCfg = {
    259       dragSourceId: this.widgetEventingController.getWidgetId()
    260     };
    261
    262     this.dragZone = cfg.dragZone;
    263
    264     //allow caller to pass extra properties to dragStart
    265     //be sure to not send the dragDropData
    266     owfdojo.mixin(dragStartCfg,cfg);
    267     delete dragStartCfg.dragDropData;
    268     delete dragStartCfg.dragZone;
    269
    270     //start drag
    271     this.onStartDrag(this.widgetEventingController.getWidgetId(),dragStartCfg);
    272
    273     //send message to start dragging for other widgets - unsubscribe so we don't repeat onstartdrag
    274     this.widgetEventingController.unsubscribe(this.dragStartName);
    275     this.widgetEventingController.publish(this.dragStartName, dragStartCfg);
    276     this.widgetEventingController.subscribe(this.dragStartName, owfdojo.hitch(this, this.onStartDrag));
    277
    278     //send data to container
    279     this.widgetEventingController.publish(this.dragSendDataName, owfdojo.mixin({
    280       dragSourceId: this.widgetEventingController.getWidgetId()
    281     },cfg),'..');
    282
    283   },
    284
    285   /**
    286    * @private
    287    */
    288   onStartDrag : function(sender, msg) {
    289
    290     this.dragging = true;
    291
    292     this.dragStartData = msg;
    293
    294     if (owfdojo.isFunction(this.callbacks[this.dragStart])) {
    295       //execute callback if false is returned don't continue
    296       if (this.callbacks[this.dragStart](sender,msg) === false) {
    297         this.dragging = false;
    298         return;
    299       }
    300     }
    301
    302     //prevent IE bug where text is dragged instead of the node
    303     if (owfdojo.isIE) {
    304       document.onselectstart = function() {
    305         return false;
    306       };
    307       document.ondragstart = function () {
    308         return false;
    309       };
    310     }
    311
    312     this.dragIndicatorText = msg.dragDropLabel;
    313     this.dragIndicatorTextNode.innerHTML = this.dragIndicatorText;
    314
    315     //hook mouse move and mouse up
    316     if (this.listeners.onmousemove == null) {
    317       this.listeners.onmousemove = owfdojo.connect(document, 'onmousemove', this, this.mouseMove);
    318     }
    319     if (this.listeners.onmouseup == null) {
    320       this.listeners.onmouseup = owfdojo.connect(document, 'onmouseup', this, this.mouseUp);
    321     }
    322   },
    323
    324   /**
    325    * @private
    326    */
    327   onDragOut : function(sender, msg) {
    328     owfdojo.style(this.dragIndicator, {
    329       display: 'none'
    330     });
    331   },
    332
    333   /**
    334    * @private
    335    */
    336   getMouseCoordinates: function (e) {
    337     var returnValue = null;
    338     if (e.pageX || e.pageY) {
    339       returnValue = {
    340         x : e.pageX,
    341         y : e.pageY
    342       };
    343     }
    344     else {
    345       returnValue = {
    346         x : e.clientX + document.body.scrollLeft - document.body.clientLeft,
    347         y : e.clientY + document.body.scrollTop - document.body.clientTop
    348       };
    349     }
    350     return returnValue;
    351   },
    352
    353     /**
    354     * @private
    355     */
    356     mouseMove : function (e, fake) {
    357         //only show the indicator if we are currenlty dragging
    358         if (this.dragging === true) {
    359
    360             // if this is a flex widget, event is not faked and current dashboard layout is tabbed, fake
    361             // mouse events as soon as the drag starts
    362             if(this.getFlashWidgetId() && fake !== true && Ozone.Widget.getDashboardLayout() === 'tabbed') {
    363                  gadgets.rpc.call('..', '_fake_mouse_move', null, {
    364                     sender: this.widgetEventingController.getWidgetId(),
    365                     pageX: e.pageX,
    366                     pageY: e.pageY,
    367                     screenX: e.screenX,
    368                     screenY: e.screenY
    369                 });
    370                 return;
    371             }
    372
    373             var clientWidth = null;
    374             var clientHeight = null;
    375             var mousePosition = this.getMouseCoordinates(e);
    376             var leftWidth = mousePosition.x;
    377             var topHeight = mousePosition.y;
    378
    379             // Hide the drag indicator box while we move it
    380             owfdojo.style(this.dragIndicator, {
    381                 display: 'none'
    382             });
    383
    384             if (e === undefined) {
    385                 e = window.event;
    386             }
    387
    388             if (owfdojo.isIE) {
    389                 clientWidth = document.body.clientWidth;
    390                 clientHeight = document.body.clientHeight;
    391             }
    392             else {
    393                 clientWidth = window.innerWidth;
    394                 clientHeight = window.innerHeight;
    395             }
    396
    397             if((owfdojo.isFF && owfdojo.isFF >= 4) || this.getFlashWidgetId()) {
    398
    399                 if(e.clientX < 0 || e.clientX > clientWidth ||
    400                     e.clientY < 0 || e.clientY > clientHeight) {
    401
    402                     // set variable on function to keep track if we faked an event
    403                     // so that we can fake mouseout later when mouseover the current widget
    404                     if(!arguments.callee._fakeEventCounter)
    405                         arguments.callee._fakeEventCounter = 1;
    406                     else
    407                         arguments.callee._fakeEventCounter += 1;
    408
    409                     gadgets.rpc.call('..', '_fake_mouse_move', null, {
    410                         sender: this.widgetEventingController.getWidgetId(),
    411                         pageX: e.pageX,
    412                         pageY: e.pageY,
    413                         screenX: e.screenX,
    414                         screenY: e.screenY
    415                     });
    416                     return;
    417                 }
    418                 else if( arguments.callee._fakeEventCounter ) {
    419                     // we had faked a mousemove event before
    420                     // now fake mouseout event on the container
    421                     arguments.callee._fakeEventCounter = null;
    422                     gadgets.rpc.call('..', '_fake_mouse_out');
    423                 }
    424             }
    425
    426             // flipping mechanism when the cursor reaches the right or bottom edge of the widget
    427             this.dragIndicator.style.top = topHeight + 19 + "px";
    428
    429             var rightLimit = clientWidth - 100;
    430             if ((leftWidth < clientWidth) && (leftWidth > rightLimit)) {
    431                 this.dragIndicator.style.left = leftWidth - 88 + "px";
    432             }
    433             else {
    434                 this.dragIndicator.style.left = leftWidth + 12 + "px";
    435             }
    436             var bottomLimit = clientHeight - 40;
    437             if ((topHeight > bottomLimit) && (topHeight < clientHeight)) {
    438                 this.dragIndicator.style.top = topHeight - 30 + "px";
    439             }
    440
    441             // set text on indicator
    442             this.dragIndicatorTextNode.innerHTML = this.dragIndicatorText;
    443             owfdojo.style(this.dragIndicator, {
    444                 display: 'block'
    445             });
    446
    447         }
    448     },
    449
    450   /**
    451    * @private
    452    */
    453   onDragStopInContainer : function(sender, msg) {
    454     owfdojo.style(this.dragIndicator, {
    455       display: 'none'
    456     });
    457     //disconnect listeners
    458     if (!this.keepMouseListenersAttached) {
    459       for (l in this.listeners) {
    460         owfdojo.disconnect(this.listeners[l]);
    461         this.listeners[l] = null;
    462       }
    463     }
    464
    465     this.dragging = false;
    466     this.dragStartData = null;
    467     this.dragZone = null;
    468     this.setDropEnabled(false);
    469
    470     if (owfdojo.isFunction(this.callbacks[this.dragStop])) {
    471       this.callbacks[this.dragStop](this.dropTarget);
    472     }
    473   },
    474
    475   /**
    476    * @private
    477    */
    478   mouseUp : function (e, fake) {
    479     if (this.dragging === true) {
    480       this.dragging = false;
    481
    482       //prevent IE bug where text is dragged instead of the node
    483       if (owfdojo.isIE) {
    484         document.onselectstart = function() {
    485           return true;
    486         };
    487         document.ondragstart = function () {
    488           return true;
    489         };
    490       }
    491
    492       owfdojo.style(this.dragIndicator, {
    493         display: 'none'
    494       });
    495
    496       if(this.getFlashWidgetId()) {
    497
    498           var clientWidth = null;
    499           var clientHeight = null;
    500           if (owfdojo.isIE) {
    501               clientWidth = document.body.clientWidth;
    502               clientHeight = document.body.clientHeight;
    503           }
    504           else {
    505               clientWidth = window.innerWidth;
    506               clientHeight = window.innerHeight;
    507           }
    508
    509           if((e.clientX < 0 || e.clientX > clientWidth ||
    510                 e.clientY < 0 || e.clientY > clientHeight
    511                 || Ozone.Widget.getDashboardLayout() === 'tabbed')
    512                 && fake !== true) {
    513
    514               gadgets.rpc.call('..', '_fake_mouse_up', null, {
    515                   sender: this.widgetEventingController.getWidgetId(),
    516                   pageX: e.pageX,
    517                   pageY: e.pageY,
    518                   screenX: e.screenX,
    519                   screenY: e.screenY
    520               });
    521               return;
    522           }
    523       }
    524
    525       //disconnect listeners
    526       for (l in this.listeners) {
    527         owfdojo.disconnect(this.listeners[l]);
    528         this.listeners[l] = null;
    529       }
    530
    531       //save dropzone info
    532       this.dropTarget = e.target;
    533
    534       //send message
    535       this.widgetEventingController.publish(this.dragStopInWidgetName, this.widgetEventingController.getWidgetId());
    536
    537   //    if (owfdojo.isFunction(this.callbacks[this.dragStop])) {
    538   //      this.callbacks[this.dragStop](this.dropTarget);
    539   //    }
    540       }
    541   },
    542
    543   /**
    544    * @private
    545    */
    546   dropReceiveData : function (sender, msg, channel) {
    547
    548     //only if the mouse is over a drop zone
    549     if (this.dropEnabledFlag) {
    550       if (this.dropTarget) {
    551         msg.dropTarget = this.dropTarget;
    552
    553         //find if we have any dropzone handlers for the dropzone used and execute
    554         for (var i = 0; i < this.dropZoneHandlers.length; i++) {
    555           //match either on id or class or is target node a child of the dropZone
    556           //also make sure the dropZone is not the same as the dragZone
    557           if (((this.dropTarget.id == this.dropZoneHandlers[i].id && this.dropTarget.id != null)
    558                   || (owfdojo.hasClass(this.dropTarget, this.dropZoneHandlers[i].className))
    559                   || (owfdojo.isDescendant(this.dropTarget, this.dropZoneHandlers[i].dropZone)))
    560                   && this.dragZone != this.dropZoneHandlers[i].dropZone
    561                   ) {
    562             this.dropZoneHandlers[i].handler(msg);
    563           }
    564         }
    565
    566         //clear dropTarget because the drop is over
    567         this.dropTarget = null;
    568       }
    569
    570       //notify that a drop has happened and send the data
    571       if (owfdojo.isFunction(this.callbacks[this.dropReceive])) {
    572         this.callbacks[this.dropReceive](msg);
    573       }
    574     }
    575   },
    576
    577   /**
    578    * @description Adds a function as a callback to Drag and Drop events.  This function supports multiple callbacks for
    579    * the same event by allowing the user call it more than once with different callback functions
    580    * @param {String} eventName The event name.
    581    * @param {Function} cb The function to execute as a callback.
    582    * @see <a href="#dragStart">dragStart Event</a> -
    583    * the callback for the dragStart event is called with the same config object used in the <a href="#doStartDrag">doStartDrag</a> function
    584    * with the exception of the dragDropData and the dragZone properties.
    585    * @see <a href="#dragStop">dragStop Event</a> -
    586    * If the drag stopped in the same widget that started the drag the callback for dragStop will be called with the dropTarget
    587    * HTML node otherwise the first argument will be null.
    588    * @see <a href="#dropReceive">dropReceive Event</a> -
    589    * the callback for the dropReceive event is called for any drop that occurs on a widget.  If one has multiple dropZones
    590    * in a widget it is easier to use <a href="#addDropZoneHandler">addDropZoneHandler</a>
    591    * @example
    592    * //example dragStart handler which highlights an Ext Grid when a drag occurs
    593    * this.wdd.addCallback('dragStart', (function(sender, msg){
    594    *      //get the Ext Grid
    595    *      var grid = this.getComponent(this.gridId);
    596    *
    597    *      //check custom dragDropGroup property to see if the drag is meant for this grid
    598    *      //if so highlight the grid by adding the ddOver class
    599    *      if (grid && msg != null && msg.dragDropGroup == 'users') {
    600    *          grid.getView().scroller.addClass('ddOver');
    601    *      }
    602    *  }).createDelegate(this));  //createDelegate is an Ext function which sets the scope
    603    *
    604    *  //this.wdd is a initialized WidgetDragAndDrop object
    605    *   this.wdd.addCallback('dropReceive',owfdojo.hitch(this,function(msg) {
    606    *      //msg.dragDropData contains the data
    607    *      //this example the data is a channel name that will be subscribed to
    608    *      this.subscribeToChannel(msg.dragDropData);
    609    *   }));
    610    */
    611   addCallback : function(eventName, cb) {
    612
    613     if (this.callbacks[eventName] == null) {
    614       //put dummy function in
    615       this.callbacks[eventName] = cb;
    616     }
    617     else {
    618       //callback already exists chain the subsequent callbacks to the first
    619       owfdojo.connect(this.callbacks,eventName,cb);
    620     }
    621   },
    622   /**
    623    * @description Adds a new drop zone to be managed.  The handler function defined in the cfg object will be called when
    624    * a drop occurs over a dom node which matches the id or the className or is equal to or a child of the dropTarget node
    625    * @see doStartDrag
    626    * @param {Object} cfg config object see below
    627    * @param {className} cfg.class class of the dropZone
    628    * @param {String} cfg.id Id of the dropZone
    629    * @param {Node} cfg.dropZone HTML node which represents the dropZone
    630    * @param {Function} cfg.handler function to be called when a drop occurs over the dropZone.  A msg object will be passed in
    631    *
    632    * @example
    633    * //Example cfg Object
    634    * {
    635    *  id: 'mygrid-1',
    636    *  className: 'mygridClass',
    637    *  dropZone: document.getElementById('dropZone'),
    638    *  handler: function(msg) {
    639    *    //some code here to handle the msg and respond
    640    *  }
    641    * }
    642    *
    643    * //Example usage of addDropZoneHandler which handles a drop that occurs over an Ext Grid and inserts new data into
    644    * //that grid based on the dragged data
    645    * //this.wdd is the WidgetDragAndDrop Object
    646    * this.wdd.addDropZoneHandler({
    647    *   //dom node of an Ext grid
    648    *   dropZone:grid.getView().scroller.dom,
    649    *
    650    *   //this function is called only when a drop occurs over the grid (i.e. the mouse was released over the grid)
    651    *   handler: (function(msg){
    652    *
    653    *     var store = grid.getStore();
    654    *     var processedSelections = [];
    655    *     var errorMsg = null;
    656    *
    657    *     //loop through msg.dragDropData which is an array and check for dupes versus the destination store
    658    *     for (var i = 0; i < msg.dragDropData.length; i++) {
    659    *       //get data for one possible new record in the dragDropData
    660    *       var recData = msg.dragDropData[i];
    661    *
    662    *       //is it already in the dest Ext Store?
    663    *       if (store.findExact('id',recData.id) >= 0) {
    664    *         //found the record already in the store
    665    *       }
    666    *       else {
    667    *         //add new record based on the dragDropData
    668    *         var newRec = new store.recordType(recData);
    669    *         //calling an external function to decide whether to add the new rec
    670    *         var rs = displayPanel.validateRecordOnAdd(newRec);
    671    *         if (rs.success) {
    672    *           processedSelections.push(newRec);
    673    *         }
    674    *         else {
    675    *           errorMsg = rs.msg;
    676    *         }
    677    *       }
    678    *     }
    679    *
    680    *     if (errorMsg) {
    681    *       Ext.Msg.alert('Error', errorMsg);
    682    *     }
    683    *
    684    *     //actually insert into the store which adds it the new recs to the grid
    685    *     if (processedSelections.length > 0) {
    686    *       store.insert(0, processedSelections);
    687    *     }
    688    *
    689    * }).createDelegate(grid)});   //createDelegate is an Ext function which sets the scope of the callback
    690    *
    691    *
    692    */
    693   addDropZoneHandler: function(cfg) {
    694     this.dropZoneHandlers.push(cfg)
    695   },
    696   /**
    697    * @description returns whether the a drop is enabled (this is only true when the mouse is over a drop zone)
    698    */
    699   getDropEnabled : function() {
    700     return this.dropEnabledFlag;
    701   },
    702
    703   /**
    704    * @description returns whether a drag is in progress
    705    */
    706   isDragging : function() {
    707     return this.dragging;
    708   },
    709
    710   /**
    711    * @description returns data sent when a drag was started
    712    */
    713   getDragStartData : function() {
    714     return owfdojo.mixin(this.dragStartData,{dragZone:this.dragZone});
    715   },
    716
    717   /**
    718    * @description toggles the dragIndicator to indicate successful or unsuccessful drop
    719    * @param {Boolean} dropEnabled true to enable a drop, false to indicate a unsuccessful drop
    720    * @example
    721    *
    722    *  //attach mouseover callback to a particular area. If the mouse is here allow a drop
    723    *  cmp.getView().scroller.on('mouseover',function(e,t,o) {
    724    *    if (cmp.dragging) {
    725    *      this.wdd.setDropEnabled(true);
    726    *    }
    727    *  },this);
    728    *
    729    *  //attach a mouse out callback to a particular area. If the mouse leaves disable drop
    730    *  cmp.getView().scroller.on('mouseout',function(e,t,o) {
    731    *    if (cmp.dragging) {
    732    *      this.wdd.setDropEnabled(false);
    733    *    }
    734    *  },this);
    735    */
    736   setDropEnabled : function(dropEnabled) {
    737     if (dropEnabled) {
    738       this.dropEnabledFlag = true;
    739       owfdojo.removeClass(this.dragIndicator, 'ddBoxCannotDrop');
    740       owfdojo.addClass(this.dragIndicator, 'ddBoxCanDrop');
    741     }
    742     else {
    743       this.dropEnabledFlag = false;
    744       owfdojo.removeClass(this.dragIndicator, 'ddBoxCanDrop');
    745       owfdojo.addClass(this.dragIndicator, 'ddBoxCannotDrop');
    746     }
    747   },
    748
    749   setFlashWidgetId: function(id) {
    750     this.flashWidgetId = id;
    751   },
    752
    753   getFlashWidgetId: function(id) {
    754     return this.flashWidgetId;
    755   }
    756 };
    757
    758 /**
    759  * @description Retrieves Ozone.dragAndDrop.WidgetDragAndDrop Singleton instance. Manages the drag and drop for an individual widget.
    760  * @param {Object} cfg config object see below for properties
    761  * @param {Object} [cfg.widgetEventingController]  The widgetEventingController
    762  * @param {Boolean} [cfg.autoInit]  True to automatically call init(), False otherwise.  The default is True if left undefined
    763  * @param {Object} [cfg.callbacks]  Object with callbacks who's names match drag and drop events.  Alternatively one could
    764  * use the <a href="#addCallback">addCallback</a> function
    765  * @requires owfdojo which is a custom version of dojo for OWF
    766  * @requires <a href="Ozone.eventing.Widget.html">Ozone.eventing.Widget</a> for eventing
    767  * @see <a href="#addCallback">addCallback</a>
    768  * @example
    769  *
    770  * var wdd = Ozone.dragAndDrop.WidgetDragAndDrop.getInstance({
    771  *                   widgetEventingController: this.widgetEventingController
    772  *               });
    773  *
    774  */
    775 Ozone.dragAndDrop.WidgetDragAndDrop.getInstance = function(cfg) {
    776   if (Ozone.dragAndDrop.WidgetDragAndDrop.instance == null) {
    777     Ozone.dragAndDrop.WidgetDragAndDrop.instance = new Ozone.dragAndDrop.WidgetDragAndDrop(cfg);
    778   }
    779   return owfdojo.mixin(Ozone.dragAndDrop.WidgetDragAndDrop.instance, cfg);
    780 };
    781
    782