reservation plugin - unbound request (unclean
[unfold.git] / portal / static / unbound_reservation_static / src / mootools.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 MooTools 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 ;(function() {
21         
22         /*
23          * overrides the FX class to inject 'step' functionality, which MooTools does not
24          * offer, and which makes me sad.  they don't seem keen to add it, either, despite
25          * the fact that it could be useful:
26          * 
27          * https://mootools.lighthouseapp.com/projects/2706/tickets/668
28          * 
29          */
30         var jsPlumbMorph = new Class({
31                 Extends:Fx.Morph,
32                 onStep : null,
33                 initialize : function(el, options) {
34                         this.parent(el, options);
35                         if (options.onStep) {
36                                 this.onStep = options.onStep;
37                         }
38                 },
39                 step : function(now) {
40                         this.parent(now);
41                         if (this.onStep) { 
42                                 try { this.onStep(); } 
43                                 catch(e) { } 
44                         }
45                 }
46         });
47         
48         var _droppables = {},
49         _droppableOptions = {},
50         _draggablesByScope = {},
51         _draggablesById = {},
52         _droppableScopesById = {};
53         /*
54          * 
55          */
56         var _executeDroppableOption = function(el, dr, event, originalEvent) {
57                 if (dr) {
58                         var id = dr.get("id");
59                         if (id) {
60                                 var options = _droppableOptions[id];
61                                 if (options) {
62                                         if (options[event]) {
63                                                 options[event](el, dr, originalEvent);
64                                         }
65                                 }
66                         }
67                 }
68         };      
69         
70         var _checkHover = function(el, entering) {
71                 if (el) {
72                         var id = el.get("id");
73                         if (id) {
74                                 var options = _droppableOptions[id];
75                                 if (options) {
76                                         if (options.hoverClass) {
77                                                 if (entering) el.addClass(options.hoverClass);
78                                                 else el.removeClass(options.hoverClass);
79                                         }
80                                 }
81                         }
82                 }
83         };
84
85         /**
86          * adds the given value to the given list, with the given scope. creates the scoped list
87          * if necessary.
88          * used by initDraggable and initDroppable.
89          */
90         var _add = function(list, _scope, value) {
91                 var l = list[_scope];
92                 if (!l) {
93                         l = [];
94                         list[_scope] = l;
95                 }
96                 l.push(value);
97         };
98         
99         /*
100          * gets an "element object" from the given input.  this means an object that is used by the
101          * underlying library on which jsPlumb is running.  'el' may already be one of these objects,
102          * in which case it is returned as-is.  otherwise, 'el' is a String, the library's lookup 
103          * function is used to find the element, using the given String as the element's id.
104          */
105         var _getElementObject = function(el) {
106           return $(el);
107         };
108                 
109         jsPlumb.CurrentLibrary = {                              
110                 
111                 /**
112                  * adds the given class to the element object.
113                  */
114                 addClass : function(el, clazz) {
115                         el = jsPlumb.CurrentLibrary.getElementObject(el);
116                         try {
117                                 if (el.className.constructor == SVGAnimatedString) {
118                                         jsPlumbUtil.svg.addClass(el, clazz);
119                                 }
120                                 else el.addClass(clazz);
121                         }
122                         catch (e) {                             
123                                 // SVGAnimatedString not supported; no problem.
124                                 el.addClass(clazz);
125                         }                                               
126                 },      
127                         
128                 animate : function(el, properties, options) {                   
129                         var m = new jsPlumbMorph(el, options);
130                         m.start(properties);
131                 },
132                 
133                 appendElement : function(child, parent) {
134                         _getElementObject(parent).grab(child);                  
135                 },
136                 
137                 bind : function(el, event, callback) {
138                         var els = jsPlumbUtil.isString(el) || typeof el.length == "undefined" ? [ _getElementObject(el) ] : $$(el);
139                         //el = _getElementObject(el);
140                         for (var i = 0; i < els.length; i++)
141                                 els[i].addEvent(event, callback);
142                 },
143
144                 destroyDraggable : function(el) {
145                         // TODO
146                         var id = jsPlumb.getId(el), d = _draggablesById[id];
147                         if (d) {
148                                 for (var i = 0; i < d.length; i++)
149                                         d[i].detach();
150
151                                 delete _draggablesById[id];
152                         }
153                 },
154
155                 destroyDroppable : function(el) {
156                         // TODO
157                 },
158                 
159                 dragEvents : {
160                         'start':'onStart', 'stop':'onComplete', 'drag':'onDrag', 'step':'onStep',
161                         'over':'onEnter', 'out':'onLeave','drop':'onDrop', 'complete':'onComplete'
162                 },
163
164                 /*
165                  * wrapper around the library's 'extend' functionality (which it hopefully has.
166                  * otherwise you'll have to do it yourself). perhaps jsPlumb could do this for you
167                  * instead.  it's not like its hard.
168                  */
169                 extend : function(o1, o2) {
170                         return $extend(o1, o2);
171                 },
172                 
173                 getClientXY : function(eventObject) {
174                         return [eventObject.event.clientX, eventObject.event.clientY];
175                 },
176                 
177                 getDragObject : function(eventArgs) {
178                         return eventArgs[0];
179                 },
180                 
181                 getDragScope : function(el) {
182                         var id = jsPlumb.getId(el),
183                             drags = _draggablesById[id];
184                         return drags[0].scope;
185                 },
186         
187                 getDropEvent : function(args) {                 
188                         return args[2];
189                 },
190                 
191                 getDropScope : function(el) {
192                         var id = jsPlumb.getId(el);
193                         return _droppableScopesById[id];
194                 },
195                 
196                 getDOMElement : function(el) { 
197                         if (el == null) return null;
198                         // MooTools just decorates the DOM elements. so we have either an ID or an Element here.
199                         return typeof(el) == "string" ? document.getElementById(el) : el; 
200                 },
201                                                         
202                 getElementObject : _getElementObject,
203                 
204                 /*
205                   gets the offset for the element object.  this should return a js object like this:
206                   
207                   { left:xxx, top: xxx}
208                  */
209                 getOffset : function(el) {
210                         var p = el.getPosition();
211                         return { left:p.x, top:p.y };
212                 },      
213                 
214                 getOriginalEvent : function(e) {
215                         return e.event;
216                 },                      
217                 
218                 getPageXY : function(eventObject) {
219                         return [eventObject.event.pageX, eventObject.event.pageY];
220                 },
221                 
222                 getParent : function(el) {
223                         return jsPlumb.CurrentLibrary.getElementObject(el).getParent();
224                 },
225                 
226                 getScrollLeft : function(el) {
227                         return null;
228                 },
229                 
230                 getScrollTop : function(el) {
231                         return null;
232                 },
233                 
234                 getSelector : function(context, spec) {
235             if (arguments.length == 2) {
236                 return jsPlumb.CurrentLibrary.getElementObject(context).getElements(spec);
237             }
238             else
239                              return $$(context);
240                 },
241                 
242                 getSize : function(el) {
243                         var s = el.getSize();
244                         return [s.x, s.y];
245                 },
246
247         getTagName : function(el) {
248             var e = jsPlumb.CurrentLibrary.getElementObject(el);
249             return e != null ? e.tagName : null;
250         },
251                 
252                 /*
253                  * takes the args passed to an event function and returns you an object that gives the
254                  * position of the object being moved, as a js object with the same params as the result of
255                  * getOffset, ie: { left: xxx, top: xxx }.
256                  */
257                 getUIPosition : function(eventArgs, zoom) {
258                   var ui = eventArgs[0],
259                           el = jsPlumb.CurrentLibrary.getElementObject(ui),
260                           p = el.getPosition();
261                         
262                   zoom = zoom || 1;               
263                         
264                   return { left:p.x / zoom, top:p.y / zoom};
265                 },              
266                 
267                 hasClass : function(el, clazz) {
268                         return el.hasClass(clazz);
269                 },
270                 
271                 initDraggable : function(el, options, isPlumbedComponent, _jsPlumb) {
272                         var id = jsPlumb.getId(el);
273                         var drag = _draggablesById[id];
274                         if (!drag) {
275                                 var originalZIndex = 0,
276                     originalCursor = null,
277                                     dragZIndex = jsPlumb.Defaults.DragOptions.zIndex || 2000;
278                 
279                                 options.onStart = jsPlumbUtil.wrap(options.onStart, function() {
280                     originalZIndex = this.element.getStyle('z-index');
281                                         this.element.setStyle('z-index', dragZIndex);
282                     drag.originalZIndex = originalZIndex;
283                                         if (jsPlumb.Defaults.DragOptions.cursor) {
284                                                 originalCursor = this.element.getStyle('cursor');
285                                                 this.element.setStyle('cursor', jsPlumb.Defaults.DragOptions.cursor);
286                                         }
287                                         $(document.body).addClass(_jsPlumb.dragSelectClass);
288                                 });
289                                 
290                                 options.onComplete = jsPlumbUtil.wrap(options.onComplete, function() {
291                                         this.element.setStyle('z-index', originalZIndex);
292                                         if (originalCursor) {
293                                                 this.element.setStyle('cursor', originalCursor);
294                                         }                    
295                                         $(document.body).removeClass(_jsPlumb.dragSelectClass);
296                                 });
297                                 
298                                 // DROPPABLES - only relevant if this is a plumbed component, ie. not just the result of the user making some DOM element
299                 // draggable.  this is the only library adapter that has to care about this parameter.
300                                 var scope = "" + (options.scope || jsPlumb.Defaults.Scope),
301                                     filterFunc = function(entry) {
302                                             return entry.get("id") != el.get("id");
303                                     },
304                                     droppables = _droppables[scope] ? _droppables[scope].filter(filterFunc) : [];
305
306                 if (isPlumbedComponent) {
307
308                                     options.droppables = droppables;
309                                     options.onLeave = jsPlumbUtil.wrap(options.onLeave, function(el, dr) {
310                                         if (dr) {
311                                                 _checkHover(dr, false);
312                                                 _executeDroppableOption(el, dr, 'onLeave');
313                                             }
314                                     });
315                                     options.onEnter = jsPlumbUtil.wrap(options.onEnter, function(el, dr) {
316                                             if (dr) {
317                                                     _checkHover(dr, true);
318                                                     _executeDroppableOption(el, dr, 'onEnter');
319                                             }
320                                     });
321                                     options.onDrop = function(el, dr, event) {
322                                             if (dr) {
323                                                     _checkHover(dr, false);
324                                                     _executeDroppableOption(el, dr, 'onDrop', event);
325                                             }
326                                     };
327                 }
328                 else
329                     options.droppables = [];
330                                 
331                                 drag = new Drag.Move(el, options);
332                                 drag.scope = scope;
333                 drag.originalZIndex = originalZIndex;
334                 _add(_draggablesById, el.get("id"), drag);
335                                 // again, only keep a record of this for scope stuff if this is a plumbed component (an endpoint)
336                 if (isPlumbedComponent) {
337                                     _add(_draggablesByScope, scope, drag);
338                 }
339                                 // test for disabled.
340                                 if (options.disabled) drag.detach();
341                         }
342                         return drag;
343                 },
344                 
345                 initDroppable : function(el, options, isPlumbedComponent, isPermanent) {
346                         var scope = options.scope;
347             _add(_droppables, scope, el);
348                         var id = jsPlumb.getId(el);
349
350             el.setAttribute("_isPermanentDroppable", isPermanent);  // we use this to clear out droppables on drag complete.
351                         _droppableOptions[id] = options;
352                         _droppableScopesById[id] = scope;
353                         var filterFunc = function(entry) { return entry.element != el; },
354                             draggables = _draggablesByScope[scope] ? _draggablesByScope[scope].filter(filterFunc) : [];
355                         for (var i = 0; i < draggables.length; i++) {
356                                 draggables[i].droppables.push(el);
357                         }
358                 },
359                 
360                 isAlreadyDraggable : function(el) {
361                         return _draggablesById[jsPlumb.getId(el)] != null;
362                 },                                                                              
363                 
364                 isDragSupported : function(el, options) {
365                         return typeof Drag != 'undefined' ;
366                 },      
367                 
368                 /*
369                  * you need Drag.Move imported to make drop work.
370                  */
371                 isDropSupported : function(el, options) {
372                         return (typeof Drag !== undefined && typeof Drag.Move !== undefined);
373                 },
374                 
375                 /**
376                  * removes the given class from the element object.
377                  */
378                 removeClass : function(el, clazz) {
379                         el = jsPlumb.CurrentLibrary.getElementObject(el);
380                         try {
381                                 if (el.className.constructor == SVGAnimatedString) {
382                                         jsPlumbUtil.svg.removeClass(el, clazz);
383                                 }
384                                 else el.removeClass(clazz);
385                         }
386                         catch (e) {                             
387                                 // SVGAnimatedString not supported; no problem.
388                                 el.removeClass(clazz);
389                         }
390                 },
391                 
392                 removeElement : function(element, parent) {
393             var el = _getElementObject(element);
394                         if (el) el.dispose();  // ??
395                 },
396
397                 setDragFilter : function(el, filter) {
398                         jsPlumbUtil.log("NOT IMPLEMENTED: setDragFilter");
399                 },
400                 
401                 setDraggable : function(el, draggable) {
402                         var draggables = _draggablesById[el.get("id")];
403                         if (draggables) {
404                                 draggables.each(function(d) {
405                                         if (draggable) d.attach(); else d.detach();
406                                 });
407                         }
408                 },
409                 
410                 setDragScope : function(el, scope) {
411                         var drag = _draggablesById[el.get("id")];
412                         var filterFunc = function(entry) {
413                                 return entry.get("id") != el.get("id");
414                         };
415                         var droppables = _droppables[scope] ? _droppables[scope].filter(filterFunc) : [];
416                         drag[0].droppables = droppables;
417                 },
418                 
419                 setOffset : function(el, o) {
420                         _getElementObject(el).setPosition({x:o.left, y:o.top});
421                 },
422
423         stopDrag : function() {
424             for (var i in _draggablesById) {
425                 for (var j = 0; j < _draggablesById[i].length; j++) {
426                     var d = _draggablesById[i][j];
427                     d.stop();
428                     if (d.originalZIndex !== 0)
429                         d.element.setStyle("z-index", d.originalZIndex);
430                 }
431             }
432         },
433                 
434                 /**
435                  * note that jquery ignores the name of the event you wanted to trigger, and figures it out for itself.
436                  * the other libraries do not.  yui, in fact, cannot even pass an original event.  we have to pull out stuff
437                  * from the originalEvent to put in an options object for YUI. 
438                  * @param el
439                  * @param event
440                  * @param originalEvent
441                  */
442                 trigger : function(el, event, originalEvent) {
443                         originalEvent.stopPropagation();
444                         _getElementObject(el).fireEvent(event, originalEvent);
445                 },
446                 
447                 unbind : function(el, event, callback) {
448                         el = _getElementObject(el);
449                         el.removeEvent(event, callback);
450                 }
451         };
452         
453         window.addEvent('domready', jsPlumb.init);
454 })();