reservation plugin - unbound request (unclean
[unfold.git] / portal / static / unbound_reservation_static / src / yui.jsPlumb.js
1 /*
2  * jsPlumb
3  * 
4  * Title:jsPlumb 1.5.5
5  * 
6  * Provides a way to visually connect elements on an HTML page, using either SVG, Canvas
7  * elements, or VML.  
8  * 
9  * This file contains the YUI3 adapter.
10  *
11  * Copyright (c) 2010 - 2013 Simon Porritt (http://jsplumb.org)
12  * 
13  * http://jsplumb.org
14  * http://github.com/sporritt/jsplumb
15  * http://code.google.com/p/jsplumb
16  * 
17  * Dual licensed under the MIT and GPL2 licenses.
18  */
19
20 /**
21  * addClass                             adds a class to the given element
22  * animate                              calls the underlying library's animate functionality
23  * appendElement                appends a child element to a parent element.
24  * bind                                 binds some event to an element
25  * dragEvents                   a dictionary of event names
26  * extend                               extend some js object with another.  probably not overly necessary; jsPlumb could just do this internally.
27  * getDragObject                gets the object that is being dragged, by extracting it from the arguments passed to a drag callback
28  * getDragScope                 gets the drag scope for a given element.
29  * getElementObject             turns an id or dom element into an element object of the underlying library's type.
30  * getOffset                    gets an element's offset
31  * getOriginalEvent     gets the original browser event from some wrapper event.
32  * getScrollLeft                gets an element's scroll left.  TODO: is this actually used?  will it be?
33  * getScrollTop                 gets an element's scroll top.  TODO: is this actually used?  will it be?
34  * getSize                              gets an element's size.
35  * getUIPosition                gets the position of some element that is currently being dragged, by extracting it from the arguments passed to a drag callback.
36  * initDraggable                initializes an element to be draggable 
37  * initDroppable                initializes an element to be droppable
38  * isDragSupported              returns whether or not drag is supported for some element.
39  * isDropSupported              returns whether or not drop is supported for some element.
40  * removeClass                  removes a class from a given element.
41  * removeElement                removes some element completely from the DOM.
42  * setDraggable                 sets whether or not some element should be draggable.
43  * setDragScope                 sets the drag scope for a given element.
44  * setOffset                    sets the offset of some element.
45  */
46 (function() {
47         
48         if (!Array.prototype.indexOf) {
49                 Array.prototype.indexOf = function( v, b, s ) {
50                         for( var i = +b || 0, l = this.length; i < l; i++ ) {
51                                 if( this[i]===v || s && this[i]==v ) { return i; }
52                         }
53                         return -1;
54                 };
55         }
56         
57         var Y;
58         
59         YUI().use('node', 'dd', 'dd-constrain', 'anim', 'node-event-simulate', function(_Y) {
60                 Y = _Y; 
61                 Y.on("domready", function() { jsPlumb.init(); });
62         });
63         
64         /**
65          * adds the given value to the given list, with the given scope. creates the scoped list
66          * if necessary.
67          * used by initDraggable and initDroppable.
68          */
69         var _add = function(list, scope, value) {
70                 var l = list[scope];
71                 if (!l) {
72                         l = [];
73                         list[scope] = l;
74                 }
75                 l.push(value);
76         },      
77         ddEvents = [ "drag:mouseDown", "drag:afterMouseDown", "drag:mouseup",
78              "drag:align", "drag:removeHandle", "drag:addHandle", "drag:removeInvalid", "drag:addInvalid",
79              "drag:start", "drag:end", "drag:drag", "drag:over", "drag:enter",
80              "drag:exit", "drag:drophit", "drag:dropmiss", "drop:over", "drop:enter", "drop:exit", "drop:hit"                          
81         ],      
82         animEvents = [ "tween" ],       
83         /**
84          * helper function to curry callbacks for some element. 
85          */
86         _wrapper = function(fn) {
87                 return function() {
88                         try {
89                                 return fn.apply(this, arguments);
90                         }
91                         catch (e) { }
92                 };
93         },      
94         /**
95          * extracts options from the given options object, leaving out event handlers.
96          */
97         _getDDOptions = function(options) {
98                 var o = {};
99                 for (var i in options) if (ddEvents.indexOf(i) == -1) o[i] = options[i];
100                 return o;
101         },      
102         /**
103          * attaches all event handlers found in options to the given dragdrop object, and registering
104          * the given el as the element of interest.
105          */
106         _attachListeners = function(dd, options, eventList) {   
107             for (var ev in options) {
108                 if (eventList.indexOf(ev) != -1) {
109                         var w = _wrapper(options[ev]);
110                         dd.on(ev, w);
111                 }
112             }
113         },
114         _droppables = {},
115         _droppableOptions = {},
116         _draggablesByScope = {},
117         _draggablesById = {},
118         _droppableScopesById = {},
119         _checkHover = function(el, entering) {
120                 if (el) {
121                         var id = el.get("id");
122                         if (id) {
123                                 var options = _droppableOptions[id];
124                                 if (options) {
125                                         if (options.hoverClass) {
126                                                 if (entering) el.addClass(options.hoverClass);
127                                                 else el.removeClass(options.hoverClass);
128                                         }
129                                 }
130                         }
131                 }
132         },
133         _lastDragObject = null,
134         _extend = function(o1, o2) {
135                 for (var i in o2)
136                         o1[i] = o2[i];
137                 return o1;
138         },
139         _getAttribute = function(el, attributeId) {
140                 return el.getAttribute(attributeId);
141         },
142         _getElementObject = function(el) {
143                 if (el == null) return null;
144                 var eee = null;
145         eee = typeof el == 'string' ? Y.one('#' + el) : el._node ? el : Y.one(el);        
146         return eee;
147         };
148         
149         jsPlumb.CurrentLibrary = {
150                         
151                 addClass : function(el, clazz) {
152                         jsPlumb.CurrentLibrary.getElementObject(el).addClass(clazz);
153                 },      
154                 
155                 /**
156                  * animates the given element.
157                  */
158                 animate : function(el, properties, options) {
159                         var o = _extend({node:el, to:properties}, options),                     
160                                 id = _getAttribute(el, "id");
161                         o.tween = jsPlumbUtil.wrap(properties.tween, function() {
162                                 // TODO should use a current instance.
163                                 jsPlumb.repaint(id);
164                         });
165                         var a = new Y.Anim(o);
166                         _attachListeners(a, o, animEvents);
167                         a.run();
168                 },
169                 
170                 appendElement : function(child, parent) {
171                         _getElementObject (parent).append(child);                       
172                 },
173                 
174                 /**
175                  * event binding wrapper.  
176                  */
177                 bind : function(el, event, callback) {
178                         var els = jsPlumbUtil.isString(el) || typeof el.length == "undefined" ? [ _getElementObject(el) ] : Y.all(el)._nodes;
179                         for (var i = 0; i < els.length; i++)
180                                 Y.one(els[i]).on(event, callback);
181                 },
182
183                 destroyDraggable : function(el) {
184                         var id = jsPlumb.getId(el),
185                                 dd = _draggablesById[id];
186
187                         if (dd) {
188                                 dd.destroy();
189                                 delete _draggablesById[id];
190                         }
191                 },
192
193                 destroyDroppable : function(el) {
194                         // TODO
195                 },
196                         
197                 dragEvents : {
198                         "start":"drag:start", "stop":"drag:end", "drag":"drag:drag", "step":"step",
199                         "over":"drop:enter", "out":"drop:exit", "drop":"drop:hit"
200                 },                                                              
201                         
202                 extend : _extend,                       
203                 
204                 getClientXY : function(eventObject) {
205                         return [eventObject.clientX, eventObject.clientY];
206                 },
207                 
208                 /**
209                  * takes the args passed to an event function and returns you an object representing that which is being dragged.
210                  */
211                 getDragObject : function(eventArgs) {
212                         // this is a workaround for the unfortunate fact that in YUI3, the 'drop:exit' event does
213                         // not contain a reference to the drag that just exited.  single-threaded js to the 
214                         // rescue: we'll just keep it for ourselves.
215                         if (eventArgs[0].drag) _lastDragObject = eventArgs[0].drag.el;
216                         return _lastDragObject;
217                 },
218                 
219                 getDragScope : function(el) {
220                         var id = jsPlumb.getId(el),
221                                 dd = _draggablesById[id];
222                         return dd.scope;
223                 },
224
225                 getDropEvent : function(args) {
226                         return args[0];
227                 },
228                 
229                 getDropScope : function(el) {
230                         var id = jsPlumb.getId(el);
231                         return _droppableScopesById[id];
232                 },
233                 
234                 getDOMElement : function(el) {  
235                         if (el == null) return null;            
236                         if (typeof(el) == "string") 
237                                 return document.getElementById(el);
238                         else if (el._node) 
239                                 return el._node;
240                         else return el;
241                 },
242                 
243                 getElementObject : _getElementObject,
244                 
245                 getOffset : function(el) {                      
246                         var o = Y.DOM.getXY(el._node);
247                         return {left:o[0], top:o[1]};
248                 },
249
250                 getOriginalEvent : function(e) {
251                         return e._event;
252                 },
253                 
254                 getPageXY : function(eventObject) {
255                         return [eventObject.pageX, eventObject.pageY];
256                 },
257                 
258                 getParent : function(el) {
259                         return jsPlumb.CurrentLibrary.getElementObject(el).get("parentNode");
260                 },
261                 
262                 getScrollLeft : function(el) {
263                         return 0; 
264                 },
265                 
266                 getScrollTop : function(el) {
267                         return 0;
268                 },
269                 
270                 getSelector : function(context, spec) {
271                         var _convert = function(s) { return s && s ._nodes ? s._nodes : []; };
272             
273             if (arguments.length == 2) {            
274                 return _convert(jsPlumb.CurrentLibrary.getElementObject(context).all(spec));
275             }
276             else {
277                              return _convert(Y.all(context));
278             }            
279                 },
280                 
281                 getSize : function(el) {
282                         return [ el._node.offsetWidth, el._node.offsetHeight ];
283                 },
284
285         getTagName : function(el) {
286             var e = jsPlumb.CurrentLibrary.getElementObject(el);
287             return e != null && e._node != null ? e._node.tagName : null;
288         },
289                 
290                 getUIPosition : function(args, zoom) {
291                         zoom = zoom || 1;
292                         var el = args[0].currentTarget.el._node || args[0].currentTarget.el;
293                         var o = Y.DOM.getXY(el);
294                         return {left:o[0] / zoom, top:o[1] / zoom };
295                 },              
296                 
297                 hasClass : function(el, clazz) {
298                         return el.hasClass(clazz);
299                 },
300                                 
301                 initDraggable : function(el, options, isPlumbedComponent, _jsPlumb) {
302                         var _opts = _getDDOptions(options),
303                                 id = _jsPlumb.getId(el);
304                         _opts.node = "#" + id;  
305                         options["drag:start"] = jsPlumbUtil.wrap(options["drag:start"], function() {
306                                 Y.one(document.body).addClass(_jsPlumb.dragSelectClass);                                
307                         }, false);      
308                         options["drag:end"] = jsPlumbUtil.wrap(options["drag:end"], function() {
309                                 Y.one(document.body).removeClass(_jsPlumb.dragSelectClass);
310                         });     
311                         var dd = new Y.DD.Drag(_opts), 
312                 containment = options.constrain2node || options.containment;
313
314                         dd.el = el;     
315             
316             if (containment) {
317                 dd.plug(Y.Plugin.DDConstrained, {
318                     constrain2node: containment
319                 });
320             }
321                         
322                         if (isPlumbedComponent) {
323                                 var scope = options.scope || _jsPlumb.Defaults.Scope;
324                                 dd.scope = scope;
325                                 _add(_draggablesByScope, scope, dd);
326                         }
327                         
328                         _draggablesById[id] = dd;                                               
329                         _attachListeners(dd, options, ddEvents);
330                 },
331                 
332                 initDroppable : function(el, options) {
333                         var _opts = _getDDOptions(options),
334                                 id = jsPlumb.getId(el);
335                         _opts.node = "#" + id;                  
336                         var dd = new Y.DD.Drop(_opts);
337                         
338                         _droppableOptions[id] = options;
339                         
340                         options = _extend({}, options);
341                         var scope = options.scope || jsPlumb.Defaults.Scope;                                    
342                         _droppableScopesById[id] = scope;
343                         
344                         options["drop:enter"] = jsPlumbUtil.wrap(options["drop:enter"], function(e) {
345                                 if (e.drag.scope !== scope) return true;
346                                 _checkHover(el, true);
347                         }, true);
348                         options["drop:exit"] = jsPlumbUtil.wrap(options["drop:exit"], function(e) {
349                                 _checkHover(el, false);
350                         });
351                         options["drop:hit"] = jsPlumbUtil.wrap(options["drop:hit"], function(e) {
352                                 if (e.drag.scope !== scope) return true;
353                                 _checkHover(el, false);
354                         }, true);
355                         
356                         _attachListeners(dd, options, ddEvents);
357                 },
358                 
359                 isAlreadyDraggable : function(el) {
360                         el = _getElementObject(el);
361                         return el.hasClass("yui3-dd-draggable");
362                 },
363                 
364                 isDragSupported : function(el) { return true; },                
365                 isDropSupported : function(el) { return true; },                                                                                
366                 removeClass : function(el, clazz) { 
367                         jsPlumb.CurrentLibrary.getElementObject(el).removeClass(clazz); 
368                 },              
369                 removeElement : function(el) { _getElementObject(el).remove(); },               
370
371                 setDragFilter : function(el, filter) {
372                         jsPlumb.log("NOT IMPLEMENTED: setDragFilter");
373                 },
374                 
375                 /**
376                  * sets the draggable state for the given element
377                  */
378                 setDraggable : function(el, draggable) {
379                         var id = jsPlumb.getId(el),
380                                 dd = _draggablesById[id];
381                         if (dd) dd.set("lock", !draggable);
382                 },
383                 
384                 setDragScope : function(el, scope) {
385                         var id = jsPlumb.getId(el),
386                                 dd = _draggablesById[id];
387                         if (dd) dd.scope = scope;
388                 },
389                 
390                 setOffset : function(el, o) {
391                         el = _getElementObject(el);
392                         el.set("top", o.top);
393                         el.set("left", o.left);
394                 },
395
396         stopDrag : function() {
397             Y.DD.DDM.stopDrag();
398         },
399                 
400                 trigger : function(el, event, originalEvent) {
401                         originalEvent.stopPropagation();
402                         _getElementObject(el).simulate(event, {
403                                 pageX:originalEvent.pageX, 
404                                 pageY:originalEvent.pageY, 
405                                 clientX:originalEvent.clientX, 
406                                 clientY:originalEvent.clientY
407                         });                     
408                 },
409                 
410                 /**
411                  * event unbinding wrapper.  
412                  */
413                 unbind : function(el, event, callback) {
414                         _getElementObject(el).detach(event, callback);
415                 }
416         };                              
417 })();