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