1 /*
  2  * code review by Pavel Yaschenko
  3  * 
  4  * No event's unbindings when component would be destroyed 
  5  * Hint: easy way to unbind - use namespaces when bind event handlers
  6  * 
  7  */
  8 
  9 (function ($, rf) {
 10 
 11     rf.ui = rf.ui || {};
 12 
 13     var defaultIndicatorClasses = {
 14         rejectClass : "rf-ind-rejt",
 15         acceptClass : "rf-ind-acpt",
 16         draggingClass : "rf-ind-drag"
 17     };
 18 
 19     rf.ui.Draggable = function(id, options) {
 20         this.options = {};
 21         $.extend(this.options, defaultOptions, options || {});
 22         $super.constructor.call(this, id);
 23 
 24         this.id = id;
 25 
 26         this.namespace = this.namespace || "."
 27             + rf.Event.createNamespace(this.name, this.id);
 28 
 29         this.parentId = this.options.parentId;
 30         this.attachToDom(this.parentId);
 31         this.dragElement = $(document.getElementById(this.options.parentId));
 32         this.dragElement.draggable();
 33 
 34         if (options.indicator) {
 35             var element = $(document.getElementById(options.indicator));
 36             var clone = element.clone();
 37             $("*[id]", clone).andSelf().each(function() {
 38                 $(this).removeAttr("id");
 39             });
 40             if (element.attr("id")) {
 41                 clone.attr("id", element.attr("id") + "Clone");
 42             }
 43             
 44             this.dragElement.data("indicator", true);
 45             this.dragElement.draggable("option", "helper", function() {
 46                 return clone;
 47             });
 48         } else {
 49             this.dragElement.data("indicator", false);
 50             this.dragElement.draggable("option", "helper", 'clone');
 51         }
 52 
 53         this.dragElement.draggable("option", "addClasses", false);
 54         this.dragElement.draggable( "option", "appendTo", "body" );
 55         
 56 
 57         this.dragElement.data('type', this.options.type);
 58         this.dragElement.data("init", true);
 59         this.dragElement.data("id", this.id);
 60         rf.Event.bind(this.dragElement, 'dragstart' + this.namespace, this.dragStart, this);
 61         rf.Event.bind(this.dragElement, 'drag' + this.namespace, this.drag, this);
 62     };
 63 
 64     rf.BaseNonVisualComponent.extend(rf.ui.Draggable);
 65 
 66     // define super class link
 67     var $super = rf.ui.Draggable.$super;
 68 
 69     var defaultOptions = {
 70     };
 71 
 72     $.extend(rf.ui.Draggable.prototype, ( function () {
 73         return {
 74             name : "Draggable",
 75             dragStart: function(e) {
 76                 var ui = e.rf.data;
 77                 var element = ui.helper[0];
 78                 this.parentElement = element.parentNode;
 79 
 80                 if (this.__isCustomDragIndicator()) {
 81                     ui.helper.detach().appendTo("body").show();
 82                     
 83                     // move cursor to the center of custom dragIndicator;
 84                     var left = (ui.helper.width() / 2);
 85                     var top = (ui.helper.height() / 2);
 86                     this.dragElement.data('ui-draggable').offset.click.left = left;
 87                     this.dragElement.data('ui-draggable').offset.click.top = top;
 88                     
 89                 }
 90             },
 91 
 92             drag: function(e) {
 93                 var ui = e.rf.data;
 94                 if (this.__isCustomDragIndicator()) {
 95                     var indicator = rf.component(this.options.indicator);
 96                     if (indicator) {
 97                         ui.helper.addClass(indicator.getDraggingClass());
 98                     } else {
 99                         ui.helper.addClass(defaultIndicatorClasses.draggingClass);
100                     }
101                 }
102                 this.__clearDraggableCss(ui.helper);
103             },
104 
105             __isCustomDragIndicator: function() {
106                 return this.dragElement.data("indicator");
107             },
108 
109             __clearDraggableCss: function(element) {
110                 if (element && element.removeClass) {
111                     //draggable 'addClasses: false' doesn't work so clear jQuery style
112                     element.removeClass("ui-draggable-dragging");
113                 }
114             },
115 
116             destroy : function() {
117                 // clean up code here
118                 this.detach(this.parentId);
119                 rf.Event.unbind(this.dragElement, this.namespace);
120                 // call parent's destroy method
121                 $super.destroy.call(this);
122             }
123         }
124     })());
125 })(RichFaces.jQuery, window.RichFaces);
126