reservation plugin - unbound request (unclean
[unfold.git] / portal / static / unbound_reservation_static / src / dom-adapter.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 base functionality for DOM type adapters. 
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 ;(function() {
20     
21                 var canvasAvailable = !!document.createElement('canvas').getContext,
22                 svgAvailable = !!window.SVGAngle || document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"),
23                 // http://stackoverflow.com/questions/654112/how-do-you-detect-support-for-vml-or-svg-in-a-browser
24                 vmlAvailable = function() {                 
25             if (vmlAvailable.vml === undefined) { 
26                 var a = document.body.appendChild(document.createElement('div'));
27                 a.innerHTML = '<v:shape id="vml_flag1" adj="1" />';
28                 var b = a.firstChild;
29                 if (b != null && b.style != null) {
30                         b.style.behavior = "url(#default#VML)";
31                         vmlAvailable.vml = b ? typeof b.adj == "object": true;
32                     }
33                     else
34                         vmlAvailable.vml = false;
35                 a.parentNode.removeChild(a);
36             }
37             return vmlAvailable.vml;
38                 };
39         
40     /**
41                 Manages dragging for some instance of jsPlumb.
42         */
43         var DragManager = function(_currentInstance) {          
44                 var _draggables = {}, _dlist = [], _delements = {}, _elementsWithEndpoints = {},                        
45                         // elementids mapped to the draggable to which they belong.
46                         _draggablesForElements = {};                    
47
48         /**
49             register some element as draggable.  right now the drag init stuff is done elsewhere, and it is
50             possible that will continue to be the case.
51         */
52                 this.register = function(el) {
53             var jpcl = jsPlumb.CurrentLibrary,
54                 _el = jpcl.getElementObject(el),
55                 id = _currentInstance.getId(el),                
56                 parentOffset = jpcl.getOffset(_el);
57                     
58             if (!_draggables[id]) {
59                 _draggables[id] = el;
60                 _dlist.push(el);
61                 _delements[id] = {};
62             }
63                                 
64                         // look for child elements that have endpoints and register them against this draggable.
65                         var _oneLevel = function(p, startOffset) {
66                 if (p) {                                                                                        
67                     for (var i = 0; i < p.childNodes.length; i++) {
68                         if (p.childNodes[i].nodeType != 3 && p.childNodes[i].nodeType != 8) {
69                             var cEl = jpcl.getElementObject(p.childNodes[i]),
70                                 cid = _currentInstance.getId(p.childNodes[i], null, true);
71                             if (cid && _elementsWithEndpoints[cid] && _elementsWithEndpoints[cid] > 0) {
72                                 var cOff = jpcl.getOffset(cEl);
73                                 _delements[id][cid] = {
74                                     id:cid,
75                                     offset:{
76                                         left:cOff.left - parentOffset.left,
77                                         top:cOff.top - parentOffset.top
78                                     }
79                                 };
80                                 _draggablesForElements[cid] = id;
81                             }
82                             _oneLevel(p.childNodes[i]);
83                         }       
84                     }
85                 }
86                         };
87
88                         _oneLevel(el);
89                 };
90                 
91                 // refresh the offsets for child elements of this element. 
92                 this.updateOffsets = function(elId) {
93                         var jpcl = jsPlumb.CurrentLibrary,
94                                 el = jpcl.getElementObject(elId),
95                                 domEl = jpcl.getDOMElement(el),
96                                 id = _currentInstance.getId(domEl),
97                                 children = _delements[id],
98                                 parentOffset = jpcl.getOffset(el);
99                                 
100                         if (children) {
101                                 for (var i in children) {
102                                         var cel = jpcl.getElementObject(i),
103                                                 cOff = jpcl.getOffset(cel);
104                                                 
105                                         _delements[id][i] = {
106                                                 id:i,
107                                                 offset:{
108                                                         left:cOff.left - parentOffset.left,
109                                                         top:cOff.top - parentOffset.top
110                                                 }
111                                         };
112                                         _draggablesForElements[i] = id;
113                                 }
114                         }
115                 };
116
117                 /**
118                         notification that an endpoint was added to the given el.  we go up from that el's parent
119                         node, looking for a parent that has been registered as a draggable. if we find one, we add this
120                         el to that parent's list of elements to update on drag (if it is not there already)
121                 */
122                 this.endpointAdded = function(el) {
123                         var jpcl = jsPlumb.CurrentLibrary, b = document.body, id = _currentInstance.getId(el), 
124                                 c = jpcl.getElementObject(el), 
125                                 cLoc = jsPlumb.CurrentLibrary.getOffset(c),
126                                 p = el.parentNode, done = p == b;
127
128                         _elementsWithEndpoints[id] = _elementsWithEndpoints[id] ? _elementsWithEndpoints[id] + 1 : 1;
129
130                         while (p != null && p != b) {
131                                 var pid = _currentInstance.getId(p, null, true);
132                                 if (pid && _draggables[pid]) {
133                                         var idx = -1, pEl = jpcl.getElementObject(p), pLoc = jpcl.getOffset(pEl);
134                                         
135                                         if (_delements[pid][id] == null) {                                              
136                                                 _delements[pid][id] = {
137                                                         id:id,
138                                                         offset:{
139                                                                 left:cLoc.left - pLoc.left,
140                                                                 top:cLoc.top - pLoc.top
141                                                         }
142                                                 };
143                                                 _draggablesForElements[id] = pid;
144                                         }
145                                         break;
146                                 }
147                                 p = p.parentNode;
148                         }       
149                 };
150
151                 this.endpointDeleted = function(endpoint) {
152                         if (_elementsWithEndpoints[endpoint.elementId]) {
153                                 _elementsWithEndpoints[endpoint.elementId]--;
154                                 if (_elementsWithEndpoints[endpoint.elementId] <= 0) {
155                                         for (var i in _delements) {
156                                                 if (_delements[i]) {
157                             delete _delements[i][endpoint.elementId];
158                             delete _draggablesForElements[endpoint.elementId];
159                         }
160                                         }
161                                 }
162                         }               
163                 };      
164                 
165                 this.changeId = function(oldId, newId) {                                
166                         _delements[newId] = _delements[oldId];                  
167                         _delements[oldId] = {};
168                         _draggablesForElements[newId] = _draggablesForElements[oldId];
169                         _draggablesForElements[oldId] = null;                   
170                 };
171
172                 this.getElementsForDraggable = function(id) {
173                         return _delements[id];  
174                 };
175
176                 this.elementRemoved = function(elementId) {
177                         var elId = _draggablesForElements[elementId];
178                         if (elId) {
179                                 delete _delements[elId][elementId];
180                                 delete _draggablesForElements[elementId];
181                         }
182                 };
183
184                 this.reset = function() {
185                         _draggables = {};
186                         _dlist = [];
187                         _delements = {};
188                         _elementsWithEndpoints = {};
189                 };
190
191                 //
192                 // notification drag ended. from 1.5.5 we check automatically if need to update some
193                 // ancestor's offsets.
194                 //
195                 this.dragEnded = function(el) {                 
196                         var id = _currentInstance.getId(el),
197                                 ancestor = _draggablesForElements[id];
198
199                         if (ancestor) this.updateOffsets(ancestor);
200                 };
201
202                 this.setParent = function(el, elId, p, pId) {
203                         var current = _draggablesForElements[elId];
204                         if (current) {
205                                 if (!_delements[pId])
206                                         _delements[pId] = {};
207                                 _delements[pId][elId] = _delements[current][elId];
208                                 delete _delements[current][elId];
209                                 var pLoc = jsPlumb.CurrentLibrary.getOffset(p),
210                                         cLoc = jsPlumb.CurrentLibrary.getOffset(el);
211                                 _delements[pId][elId].offset = {
212                                         left:cLoc.left - pLoc.left,
213                                         top:cLoc.top - pLoc.top
214                                 };                              
215                                 _draggablesForElements[elId] = pId;
216                         }                       
217                 };
218                 
219         };
220         
221     // for those browsers that dont have it.  they still don't have it! but at least they won't crash.
222         if (!window.console)
223                 window.console = { time:function(){}, timeEnd:function(){}, group:function(){}, groupEnd:function(){}, log:function(){} };
224             
225     window.jsPlumbAdapter = {
226         
227         headless:false,
228
229         getAttribute:function(el, attName) {
230                 return el.getAttribute(attName);
231         },
232
233         setAttribute:function(el, a, v) {
234                 el.setAttribute(a, v);
235         },
236         
237         appendToRoot : function(node) {
238             document.body.appendChild(node);
239         },
240         getRenderModes : function() {
241             return [ "canvas", "svg", "vml" ];
242         },
243         isRenderModeAvailable : function(m) {
244             return {
245                 "canvas":canvasAvailable,
246                 "svg":svgAvailable,
247                 "vml":vmlAvailable()
248             }[m];
249         },
250         getDragManager : function(_jsPlumb) {
251             return new DragManager(_jsPlumb);
252         },
253         setRenderMode : function(mode) {
254             var renderMode;
255             
256             if (mode) {
257                                 mode = mode.toLowerCase();            
258                                     
259                 var canvasAvailable = this.isRenderModeAvailable("canvas"),
260                     svgAvailable = this.isRenderModeAvailable("svg"),
261                     vmlAvailable = this.isRenderModeAvailable("vml");
262                 
263                 // now test we actually have the capability to do this.                                         
264                 if (mode === "svg") {
265                     if (svgAvailable) renderMode = "svg";
266                     else if (canvasAvailable) renderMode = "canvas";
267                     else if (vmlAvailable) renderMode = "vml";
268                 }
269                 else if (mode === "canvas" && canvasAvailable) renderMode = "canvas";
270                 else if (vmlAvailable) renderMode = "vml";
271             }
272
273                         return renderMode;
274         }
275     };
276     
277
278     /*
279
280     addClass:
281
282     add: function( elem, classNames ) {
283     jQuery.each((classNames || "").split(/\s+/), function(i, className){
284         if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
285             elem.className += (elem.className ? " " : "") + className;
286         });
287     },
288     */
289
290     /*
291
292         removeClass:
293
294     elem.className = classNames !== undefined ?
295         jQuery.grep(elem.className.split(/\s+/), function(className){
296                 return !jQuery.className.has( classNames, className );
297         }).join(" ") :
298
299 */
300
301 })();