reservation plugin - unbound request (unclean
[unfold.git] / portal / static / unbound_reservation_static / src / connection.js
1 ;(function() {
2
3     var makeConnector = function(_jsPlumb, renderMode, connectorName, connectorArgs) {
4             if (!_jsPlumb.Defaults.DoNotThrowErrors && jsPlumb.Connectors[renderMode][connectorName] == null)
5                     throw { msg:"jsPlumb: unknown connector type '" + connectorName + "'" };
6
7             return new jsPlumb.Connectors[renderMode][connectorName](connectorArgs);  
8         },
9         _makeAnchor = function(anchorParams, elementId, _jsPlumb) {
10             return (anchorParams) ? _jsPlumb.makeAnchor(anchorParams, elementId, _jsPlumb) : null;
11         },
12         prepareEndpoint = function(_jsPlumb, _newEndpoint, conn, existing, index, params, element, elementId, connectorPaintStyle, connectorHoverPaintStyle) {
13             var e;
14             if (existing) {
15                 conn.endpoints[index] = existing;
16                 existing.addConnection(conn);                   
17             } else {
18                 if (!params.endpoints) params.endpoints = [ null, null ];
19                 var ep = params.endpoints[index]  || params.endpoint || _jsPlumb.Defaults.Endpoints[index] || jsPlumb.Defaults.Endpoints[index] || _jsPlumb.Defaults.Endpoint || jsPlumb.Defaults.Endpoint;
20                 if (!params.endpointStyles) params.endpointStyles = [ null, null ];
21                 if (!params.endpointHoverStyles) params.endpointHoverStyles = [ null, null ];
22                 var es = params.endpointStyles[index] || params.endpointStyle || _jsPlumb.Defaults.EndpointStyles[index] || jsPlumb.Defaults.EndpointStyles[index] || _jsPlumb.Defaults.EndpointStyle || jsPlumb.Defaults.EndpointStyle;
23                 // Endpoints derive their fillStyle from the connector's strokeStyle, if no fillStyle was specified.
24                 if (es.fillStyle == null && connectorPaintStyle != null)
25                     es.fillStyle = connectorPaintStyle.strokeStyle;
26                 
27                 // TODO: decide if the endpoint should derive the connection's outline width and color.  currently it does:
28                 //*
29                 if (es.outlineColor == null && connectorPaintStyle != null) 
30                     es.outlineColor = connectorPaintStyle.outlineColor;
31                 if (es.outlineWidth == null && connectorPaintStyle != null) 
32                     es.outlineWidth = connectorPaintStyle.outlineWidth;
33                 //*/
34                 
35                 var ehs = params.endpointHoverStyles[index] || params.endpointHoverStyle || _jsPlumb.Defaults.EndpointHoverStyles[index] || jsPlumb.Defaults.EndpointHoverStyles[index] || _jsPlumb.Defaults.EndpointHoverStyle || jsPlumb.Defaults.EndpointHoverStyle;
36                 // endpoint hover fill style is derived from connector's hover stroke style.  TODO: do we want to do this by default? for sure?
37                 if (connectorHoverPaintStyle != null) {
38                     if (ehs == null) ehs = {};
39                     if (ehs.fillStyle == null) {
40                         ehs.fillStyle = connectorHoverPaintStyle.strokeStyle;
41                     }
42                 }
43                 var a = params.anchors ? params.anchors[index] : 
44                         params.anchor ? params.anchor :
45                         _makeAnchor(_jsPlumb.Defaults.Anchors[index], elementId, _jsPlumb) || 
46                         _makeAnchor(jsPlumb.Defaults.Anchors[index], elementId,_jsPlumb) || 
47                         _makeAnchor(_jsPlumb.Defaults.Anchor, elementId,_jsPlumb) || 
48                         _makeAnchor(jsPlumb.Defaults.Anchor, elementId, _jsPlumb),                  
49                     u = params.uuids ? params.uuids[index] : null;
50                     e = _newEndpoint({ 
51                         paintStyle : es,  hoverPaintStyle:ehs,  endpoint : ep,  connections : [ conn ], 
52                         uuid : u,  anchor : a,  source : element, scope  : params.scope, container:params.container,
53                         reattach:params.reattach || _jsPlumb.Defaults.ReattachConnections,
54                         detachable:params.detachable || _jsPlumb.Defaults.ConnectionsDetachable
55                     });
56                 conn.endpoints[index] = e;
57                 
58                 if (params.drawEndpoints === false) e.setVisible(false, true, true);
59                                     
60             }
61             return e;
62         };
63     
64     jsPlumb.Connection = function(params) {
65         var _newConnection = params.newConnection,
66             _newEndpoint = params.newEndpoint,
67             jpcl = jsPlumb.CurrentLibrary,
68             _att = jpcl.getAttribute,
69             _gel = jpcl.getElementObject,
70             _dom = jpcl.getDOMElement,
71             _ju = jsPlumbUtil,
72             _getOffset = jpcl.getOffset;
73
74         this.connector = null;                        
75         this.idPrefix = "_jsplumb_c_";
76         this.defaultLabelLocation = 0.5;
77         this.defaultOverlayKeys = ["Overlays", "ConnectionOverlays"];
78         this.parent = params.parent;
79         // if a new connection is the result of moving some existing connection, params.previousConnection
80         // will have that Connection in it. listeners for the jsPlumbConnection event can look for that
81         // member and take action if they need to.
82         this.previousConnection = params.previousConnection;
83         this.source = _dom(params.source);
84         this.target = _dom(params.target);
85         // sourceEndpoint and targetEndpoint override source/target, if they are present. but 
86         // source is not overridden if the Endpoint has declared it is not the final target of a connection;
87         // instead we use the source that the Endpoint declares will be the final source element.
88         if (params.sourceEndpoint) this.source = params.sourceEndpoint.endpointWillMoveTo || params.sourceEndpoint.getElement();            
89         if (params.targetEndpoint) this.target = params.targetEndpoint.getElement();        
90
91         OverlayCapableJsPlumbUIComponent.apply(this, arguments);
92
93         this.sourceId = this._jsPlumb.instance.getId(this.source);
94         this.targetId = this._jsPlumb.instance.getId(this.target);
95         this.scope = params.scope; // scope may have been passed in to the connect call. if it wasn't, we will pull it from the source endpoint, after having initialised the endpoints.            
96         this.endpoints = [];
97         this.endpointStyles = [];
98             
99         var _jsPlumb = this._jsPlumb.instance;    
100         this._jsPlumb.visible = true;
101         this._jsPlumb.editable = params.editable === true;    
102         this._jsPlumb.params = {
103             parent:params.parent,
104             cssClass:params.cssClass,
105             container:params.container,
106             "pointer-events":params["pointer-events"],
107             editorParams:params.editorParams
108         };   
109         this._jsPlumb.lastPaintedAt = null;              
110         this.getDefaultType = function() {
111             return {
112                 parameters:{},
113                 scope:null,
114                 detachable:this._jsPlumb.instance.Defaults.ConnectionsDetachable,
115                 rettach:this._jsPlumb.instance.Defaults.ReattachConnections,
116                 paintStyle:this._jsPlumb.instance.Defaults.PaintStyle || jsPlumb.Defaults.PaintStyle,
117                 connector:this._jsPlumb.instance.Defaults.Connector || jsPlumb.Defaults.Connector,
118                 hoverPaintStyle:this._jsPlumb.instance.Defaults.HoverPaintStyle || jsPlumb.Defaults.HoverPaintStyle,                            
119                 overlays:this._jsPlumb.instance.Defaults.ConnectorOverlays || jsPlumb.Defaults.ConnectorOverlays
120             };
121         };
122         
123 // INITIALISATION CODE                  
124                             
125         // wrapped the main function to return null if no input given. this lets us cascade defaults properly.
126         
127         var eS = prepareEndpoint(_jsPlumb, _newEndpoint, this, params.sourceEndpoint, 0, params, this.source, this.sourceId, params.paintStyle, params.hoverPaintStyle);                        
128         if (eS) _ju.addToList(params.endpointsByElement, this.sourceId, eS);                                            
129         var eT = prepareEndpoint(_jsPlumb, _newEndpoint, this, params.targetEndpoint, 1, params, this.target, this.targetId, params.paintStyle, params.hoverPaintStyle);
130         if (eT) _ju.addToList(params.endpointsByElement, this.targetId, eT);
131         // if scope not set, set it to be the scope for the source endpoint.
132         if (!this.scope) this.scope = this.endpoints[0].scope;          
133                 
134         // if explicitly told to (or not to) delete endpoints on detach, override endpoint's preferences
135         if (params.deleteEndpointsOnDetach != null) {
136             this.endpoints[0]._deleteOnDetach = params.deleteEndpointsOnDetach;
137             this.endpoints[1]._deleteOnDetach = params.deleteEndpointsOnDetach;
138         }
139         else {
140             // otherwise, unless the endpoints say otherwise, mark them for deletion.
141             if (!this.endpoints[0]._doNotDeleteOnDetach) this.endpoints[0]._deleteOnDetach = true;
142             if (!this.endpoints[1]._doNotDeleteOnDetach) this.endpoints[1]._deleteOnDetach = true;
143         }   
144                     
145         // TODO these could surely be refactored into some method that tries them one at a time until something exists
146         this.setConnector(this.endpoints[0].connector || 
147                           this.endpoints[1].connector || 
148                           params.connector || 
149                           _jsPlumb.Defaults.Connector || 
150                           jsPlumb.Defaults.Connector, true);
151
152         if (params.path)
153             this.connector.setPath(params.path);
154         
155         this.setPaintStyle(this.endpoints[0].connectorStyle || 
156                            this.endpoints[1].connectorStyle || 
157                            params.paintStyle || 
158                            _jsPlumb.Defaults.PaintStyle || 
159                            jsPlumb.Defaults.PaintStyle, true);
160                     
161         this.setHoverPaintStyle(this.endpoints[0].connectorHoverStyle || 
162                                 this.endpoints[1].connectorHoverStyle || 
163                                 params.hoverPaintStyle || 
164                                 _jsPlumb.Defaults.HoverPaintStyle || 
165                                 jsPlumb.Defaults.HoverPaintStyle, true);
166         
167         this._jsPlumb.paintStyleInUse = this.getPaintStyle();
168         
169         var _suspendedAt = _jsPlumb.getSuspendedAt();
170         _jsPlumb.updateOffset( { elId : this.sourceId, timestamp:_suspendedAt });
171         _jsPlumb.updateOffset( { elId : this.targetId, timestamp:_suspendedAt });
172
173 //*
174         if(!_jsPlumb.isSuspendDrawing()) {                    
175             // paint the endpoints
176             var myInfo = _jsPlumb.getCachedData(this.sourceId),
177                 myOffset = myInfo.o, myWH = myInfo.s,
178                 otherInfo = _jsPlumb.getCachedData(this.targetId),
179                 otherOffset = otherInfo.o,
180                 otherWH = otherInfo.s,
181                 initialTimestamp = _suspendedAt || _jsPlumb.timestamp(),
182                 anchorLoc = this.endpoints[0].anchor.compute( {
183                     xy : [ myOffset.left, myOffset.top ], wh : myWH, element : this.endpoints[0],
184                     elementId:this.endpoints[0].elementId,
185                     txy : [ otherOffset.left, otherOffset.top ], twh : otherWH, tElement : this.endpoints[1],
186                     timestamp:initialTimestamp
187                 });
188
189             this.endpoints[0].paint( { anchorLoc : anchorLoc, timestamp:initialTimestamp });
190
191             anchorLoc = this.endpoints[1].anchor.compute( {
192                 xy : [ otherOffset.left, otherOffset.top ], wh : otherWH, element : this.endpoints[1],
193                 elementId:this.endpoints[1].elementId,                          
194                 txy : [ myOffset.left, myOffset.top ], twh : myWH, tElement : this.endpoints[0],
195                 timestamp:initialTimestamp                              
196             });
197             this.endpoints[1].paint({ anchorLoc : anchorLoc, timestamp:initialTimestamp });
198         }
199         //*/
200                                 
201 // END INITIALISATION CODE                      
202         
203 // DETACHABLE                           
204         this._jsPlumb.detachable = _jsPlumb.Defaults.ConnectionsDetachable;
205         if (params.detachable === false) this._jsPlumb.detachable = false;
206         if(this.endpoints[0].connectionsDetachable === false) this._jsPlumb.detachable = false;
207         if(this.endpoints[1].connectionsDetachable === false) this._jsPlumb.detachable = false;                
208 // REATTACH
209         this._jsPlumb.reattach = params.reattach || this.endpoints[0].reattachConnections || this.endpoints[1].reattachConnections || _jsPlumb.Defaults.ReattachConnections;
210 // COST + DIRECTIONALITY
211         // if cost not supplied, try to inherit from source endpoint
212         this._jsPlumb.cost = params.cost || this.endpoints[0].getConnectionCost();                              
213         this._jsPlumb.directed = params.directed;
214         // inherit directed flag if set no source endpoint
215         if (params.directed == null) this._jsPlumb.directed = this.endpoints[0].areConnectionsDirected();        
216 // END COST + DIRECTIONALITY
217                     
218 // PARAMETERS                                           
219         // merge all the parameters objects into the connection.  parameters set
220         // on the connection take precedence; then source endpoint params, then
221         // finally target endpoint params.
222         // TODO jsPlumb.extend could be made to take more than two args, and it would
223         // apply the second through nth args in order.
224         var _p = jsPlumb.extend({}, this.endpoints[1].getParameters());
225         jsPlumb.extend(_p, this.endpoints[0].getParameters());
226         jsPlumb.extend(_p, this.getParameters());
227         this.setParameters(_p);
228 // END PARAMETERS
229
230 // PAINTING
231                   
232         // the very last thing we do is apply types, if there are any.
233         var _types = [params.type, this.endpoints[0].connectionType, this.endpoints[1].connectionType ].join(" ");
234         if (/[a-zA-Z]/.test(_types))
235             this.addType(_types, params.data, true);        
236
237         
238 // END PAINTING    
239     };
240
241     jsPlumbUtil.extend(jsPlumb.Connection, OverlayCapableJsPlumbUIComponent, {
242         applyType : function(t, doNotRepaint) {            
243             if (t.detachable != null) this.setDetachable(t.detachable);
244             if (t.reattach != null) this.setReattach(t.reattach);
245             if (t.scope) this.scope = t.scope;
246             //editable = t.editable;  // TODO
247             this.setConnector(t.connector, doNotRepaint);
248         },
249         getTypeDescriptor : function() { return "connection"; },
250         getAttachedElements : function() {
251             return this.endpoints;
252         },
253         addClass : function(c, informEndpoints) {        
254             if (informEndpoints) {
255                 this.endpoints[0].addClass(c);
256                 this.endpoints[1].addClass(c); 
257                 if (this.suspendedEndpoint) this.suspendedEndpoint.addClass(c);                   
258             }
259             if (this.connector) {
260                 this.connector.addClass(c);
261             }
262         },
263         removeClass : function(c, informEndpoints) {            
264             if (informEndpoints) {
265                 this.endpoints[0].removeClass(c);
266                 this.endpoints[1].removeClass(c);                    
267                 if (this.suspendedEndpoint) this.suspendedEndpoint.removeClass(c);
268             }
269             if (this.connector) {
270                 this.connector.removeClass(c);
271             }
272         },
273         isVisible : function() { return this._jsPlumb.visible; },
274         setVisible : function(v) {
275             this._jsPlumb.visible = v;
276             //this[v ? "showOverlays" : "hideOverlays"]();
277             if (this.connector) 
278                 this.connector.setVisible(v);
279             this.repaint();
280         },
281
282         /* TODO move to connecto editors; it should put these on the prototype.
283
284         setEditable : function(e) {
285             if (this.connector && this.connector.isEditable())
286                 this._jsPlumb.editable = e;
287             
288             return this._jsPlumb.editable;
289         },
290         isEditable : function() { return this._jsPlumb.editable; },
291         editStarted : function() {  
292             this.setSuspendEvents(true);
293             this.fire("editStarted", {
294                 path:this.connector.getPath()
295             });            
296             this._jsPlumb.instance.setHoverSuspended(true);
297         },
298         editCompleted : function() {            
299             this.fire("editCompleted", {
300                 path:this.connector.getPath()
301             });       
302             this.setSuspendEvents(false);
303             this.setHover(false);     
304             this._jsPlumb.instance.setHoverSuspended(false);
305         },
306         editCanceled : function() {
307             this.fire("editCanceled", {
308                 path:this.connector.getPath()
309             });
310             this.setHover(false);
311             this._jsPlumb.instance.setHoverSuspended(false);
312         },
313
314 */
315
316         cleanup:function() {
317             //this.endpointsToDeleteOnDetach = null;
318             this.endpoints = null;
319             this.source = null;
320             this.target = null;                    
321             if (this.connector != null) {
322                 this.connector.cleanup();            
323                 this.connector.destroy();
324             }
325             this.connector = null;
326         },
327         isDetachable : function() {
328             return this._jsPlumb.detachable === true;
329         },
330         setDetachable : function(detachable) {
331           this._jsPlumb.detachable = detachable === true;
332         },
333         isReattach : function() {
334             return this._jsPlumb.reattach === true;
335         },        
336         setReattach : function(reattach) {
337           this._jsPlumb.reattach = reattach === true;
338         },
339         setHover : function(state) {
340             if (this.connector && this._jsPlumb && !this._jsPlumb.instance.isConnectionBeingDragged()) {
341                 this.connector.setHover(state);
342                 jsPlumb.CurrentLibrary[state ? "addClass" : "removeClass"](this.source, this._jsPlumb.instance.hoverSourceClass);
343                 jsPlumb.CurrentLibrary[state ? "addClass" : "removeClass"](this.target, this._jsPlumb.instance.hoverTargetClass);
344             }
345         },
346         getCost : function() { return this._jsPlumb.cost; },
347         setCost : function(c) { this._jsPlumb.cost = c; },
348         isDirected : function() { return this._jsPlumb.directed === true; },
349         //
350         // changes the parent element of this connection to newParent.  not exposed for the public API.
351         //
352         // TODO ensure moveParent method still works (the overlay stuff in particular)
353         moveParent : function(newParent) {
354             var jpcl = jsPlumb.CurrentLibrary, curParent = jpcl.getParent(this.connector.canvas);               
355             if (this.connector.bgCanvas) {
356                 jpcl.removeElement(this.connector.bgCanvas);
357                 jpcl.appendElement(this.connector.bgCanvas, newParent);
358             }
359             jpcl.removeElement(this.connector.canvas);
360             jpcl.appendElement(this.connector.canvas, newParent);                
361             // this only applies for DOMOverlays
362             for (var i = 0; i < this._jsPlumb.overlays.length; i++) {
363                 if (this._jsPlumb.overlays[i].isAppendedAtTopLevel) {
364                     jpcl.removeElement(this._jsPlumb.overlays[i].canvas);
365                     jpcl.appendElement(this._jsPlumb.overlays[i].canvas, newParent);
366                     if (this._jsPlumb.overlays[i].reattachListeners) 
367                         this._jsPlumb.overlays[i].reattachListeners(this.connector);
368                 }
369             }
370             if (this.connector.reattachListeners)       // this is for SVG/VML; change an element's parent and you have to reinit its listeners.
371                 this.connector.reattachListeners();     // the Canvas implementation doesn't have to care about this
372         },
373         getConnector : function() { return this.connector; },
374         setConnector : function(connectorSpec, doNotRepaint) {
375             var _ju = jsPlumbUtil;
376             if (this.connector != null) {
377                 this.connector.cleanup();
378                 this.connector.destroy();
379             }
380
381             var connectorArgs = { 
382                     _jsPlumb:this._jsPlumb.instance, 
383                     parent:this._jsPlumb.params.parent, 
384                     cssClass:this._jsPlumb.params.cssClass, 
385                     container:this._jsPlumb.params.container,                 
386                     "pointer-events":this._jsPlumb.params["pointer-events"]
387                 },
388                 renderMode = this._jsPlumb.instance.getRenderMode();
389             
390             if (_ju.isString(connectorSpec)) 
391                 this.connector = makeConnector(this._jsPlumb.instance, renderMode, connectorSpec, connectorArgs); // lets you use a string as shorthand.
392             else if (_ju.isArray(connectorSpec)) {
393                 if (connectorSpec.length == 1)
394                     this.connector = makeConnector(this._jsPlumb.instance, renderMode, connectorSpec[0], connectorArgs);
395                 else
396                     this.connector = makeConnector(this._jsPlumb.instance, renderMode, connectorSpec[0], _ju.merge(connectorSpec[1], connectorArgs));
397             }
398             // binds mouse listeners to the current connector.
399             this.bindListeners(this.connector, this, function(state) {                
400                 this.setHover(state, false);                
401             }.bind(this));
402             
403             this.canvas = this.connector.canvas;
404
405             if (this._jsPlumb.editable && jsPlumb.ConnectorEditors != null && jsPlumb.ConnectorEditors[this.connector.type] && this.connector.isEditable()) {
406                 new jsPlumb.ConnectorEditors[this.connector.type]({
407                     connector:this.connector,
408                     connection:this,
409                     params:this._jsPlumb.params.editorParams || { }
410                 });
411             }
412             else {                    
413                 this._jsPlumb.editable = false;
414             }                
415                 
416             if (!doNotRepaint) this.repaint();
417         },
418         paint : function(params) {
419                     
420             if (!this._jsPlumb.instance.isSuspendDrawing() && this._jsPlumb.visible) {
421                     
422                 params = params || {};
423                 var elId = params.elId, ui = params.ui, recalc = params.recalc, timestamp = params.timestamp,
424                     // if the moving object is not the source we must transpose the two references.
425                     swap = false,
426                     tId = swap ? this.sourceId : this.targetId, sId = swap ? this.targetId : this.sourceId,                    
427                     tIdx = swap ? 0 : 1, sIdx = swap ? 1 : 0;
428
429                 if (timestamp == null || timestamp != this._jsPlumb.lastPaintedAt) {                        
430                     var sourceInfo = this._jsPlumb.instance.updateOffset( { elId : sId, offset : ui, recalc : recalc, timestamp : timestamp }).o,
431                         targetInfo = this._jsPlumb.instance.updateOffset( { elId : tId, timestamp : timestamp }).o, // update the target if this is a forced repaint. otherwise, only the source has been moved.
432                         sE = this.endpoints[sIdx], tE = this.endpoints[tIdx];
433
434                     if (params.clearEdits) {
435                         this._jsPlumb.overlayPositions = null;
436                         sE.anchor.clearUserDefinedLocation();
437                         tE.anchor.clearUserDefinedLocation();
438                         this.connector.setEdited(false);
439                     }
440                     
441                     var sAnchorP = sE.anchor.getCurrentLocation({xy:[sourceInfo.left,sourceInfo.top], wh:[sourceInfo.width, sourceInfo.height], element:sE, timestamp:timestamp}),              
442                         tAnchorP = tE.anchor.getCurrentLocation({xy:[targetInfo.left,targetInfo.top], wh:[targetInfo.width, targetInfo.height], element:tE, timestamp:timestamp});                                                 
443                         
444                     this.connector.resetBounds();
445
446                     this.connector.compute({
447                         sourcePos:sAnchorP,
448                         targetPos:tAnchorP, 
449                         sourceEndpoint:this.endpoints[sIdx],
450                         targetEndpoint:this.endpoints[tIdx],
451                         lineWidth:this._jsPlumb.paintStyleInUse.lineWidth,                                          
452                         sourceInfo:sourceInfo,
453                         targetInfo:targetInfo,
454                         clearEdits:params.clearEdits === true
455                     });                                                                                        
456
457                     var overlayExtents = { minX:Infinity, minY:Infinity, maxX:-Infinity, maxY:-Infinity };
458                                         
459                     // compute overlays. we do this first so we can get their placements, and adjust the
460                     // container if needs be (if an overlay would be clipped)
461                     for ( var i = 0; i < this._jsPlumb.overlays.length; i++) {
462                         var o = this._jsPlumb.overlays[i];
463                         if (o.isVisible()) {                            
464                             this._jsPlumb.overlayPlacements[i] = o.draw(this.connector, this._jsPlumb.paintStyleInUse, this.getAbsoluteOverlayPosition(o));
465                             overlayExtents.minX = Math.min(overlayExtents.minX, this._jsPlumb.overlayPlacements[i].minX);
466                             overlayExtents.maxX = Math.max(overlayExtents.maxX, this._jsPlumb.overlayPlacements[i].maxX);
467                             overlayExtents.minY = Math.min(overlayExtents.minY, this._jsPlumb.overlayPlacements[i].minY);
468                             overlayExtents.maxY = Math.max(overlayExtents.maxY, this._jsPlumb.overlayPlacements[i].maxY);
469                         }
470                     }
471
472                     var lineWidth = parseFloat(this._jsPlumb.paintStyleInUse.lineWidth || 1) / 2,
473                         outlineWidth = parseFloat(this._jsPlumb.paintStyleInUse.lineWidth || 0),
474                         extents = {
475                             xmin : Math.min(this.connector.bounds.minX - (lineWidth + outlineWidth), overlayExtents.minX),
476                             ymin : Math.min(this.connector.bounds.minY - (lineWidth + outlineWidth), overlayExtents.minY),
477                             xmax : Math.max(this.connector.bounds.maxX + (lineWidth + outlineWidth), overlayExtents.maxX),
478                             ymax : Math.max(this.connector.bounds.maxY + (lineWidth + outlineWidth), overlayExtents.maxY)
479                         };
480
481                     // paint the connector.
482                     this.connector.paint(this._jsPlumb.paintStyleInUse, null, extents);  
483                     // and then the overlays
484                     for ( var j = 0; j < this._jsPlumb.overlays.length; j++) {
485                         var p = this._jsPlumb.overlays[j];
486                         if (p.isVisible()) {
487                             p.paint(this._jsPlumb.overlayPlacements[j], extents);    
488                         }
489                     }                                                                          
490                 }
491                 this._jsPlumb.lastPaintedAt = timestamp;                        
492             }       
493         },
494         /*
495          * Function: repaint
496          * Repaints the Connection. No parameters exposed to public API.
497          */
498         repaint : function(params) {
499             params = params || {};            
500             this.paint({ elId : this.sourceId, recalc : !(params.recalc === false), timestamp:params.timestamp, clearEdits:params.clearEdits });
501         }
502         
503     }); // END Connection class            
504 })();