@ -2104,14 +2104,9 @@
sel = k . getSelection ( ) ,
dPos = this . params . getPosition ( dragEl ) ;
if ( sel . length > 0 ) {
for ( var i = 0 ; i < sel . length ; i ++ ) {
var p = this . params . getPosition ( sel [ i ] . el ) ;
positions . push ( [ sel [ i ] . el , { left : p [ 0 ] , top : p [ 1 ] } , sel [ i ] ] ) ;
}
}
else {
positions . push ( [ dragEl , { left : dPos [ 0 ] , top : dPos [ 1 ] } , this ] ) ;
for ( var i = 0 ; i < sel . length ; i ++ ) {
var p = this . params . getPosition ( sel [ i ] . el ) ;
positions . push ( [ sel [ i ] . el , { left : p [ 0 ] , top : p [ 1 ] } , sel [ i ] ] ) ;
}
_dispatch ( "stop" , {
@ -3540,6 +3535,231 @@
} ) . call ( typeof window !== 'undefined' ? window : this ) ;
; ( function ( ) {
var DEFAULT _OPTIONS = {
deriveAnchor : function ( edge , index , ep , conn ) {
return {
top : [ "TopRight" , "TopLeft" ] ,
bottom : [ "BottomRight" , "BottomLeft" ]
} [ edge ] [ index ] ;
}
} ;
var root = this ;
var ListManager = function ( jsPlumbInstance ) {
this . count = 0 ;
this . instance = jsPlumbInstance ;
this . lists = { } ;
this . instance . addList = function ( el , options ) {
return this . listManager . addList ( el , options ) ;
} ;
this . instance . removeList = function ( el ) {
this . listManager . removeList ( el ) ;
} ;
this . instance . bind ( "manageElement" , function ( p ) {
//look for [jtk-scrollable-list] elements and attach scroll listeners if necessary
var scrollableLists = this . instance . getSelector ( p . el , "[jtk-scrollable-list]" ) ;
for ( var i = 0 ; i < scrollableLists . length ; i ++ ) {
this . addList ( scrollableLists [ i ] ) ;
}
} . bind ( this ) ) ;
this . instance . bind ( "unmanageElement" , function ( p ) {
this . removeList ( p . el ) ;
} ) ;
this . instance . bind ( "connection" , function ( c , evt ) {
if ( evt == null ) {
// not added by mouse. look for an ancestor of the source and/or target element that is a scrollable list, and run
// its scroll method.
this . _maybeUpdateParentList ( c . source ) ;
this . _maybeUpdateParentList ( c . target ) ;
}
} . bind ( this ) ) ;
} ;
root . jsPlumbListManager = ListManager ;
ListManager . prototype = {
addList : function ( el , options ) {
var dp = this . instance . extend ( { } , DEFAULT _OPTIONS ) ;
options = this . instance . extend ( dp , options || { } ) ;
var id = [ this . instance . getInstanceIndex ( ) , this . count ++ ] . join ( "_" ) ;
this . lists [ id ] = new List ( this . instance , el , options , id ) ;
} ,
removeList : function ( el ) {
var list = this . lists [ el . _jsPlumbList ] ;
if ( list ) {
list . destroy ( ) ;
delete this . lists [ el . _jsPlumbList ] ;
}
} ,
_maybeUpdateParentList : function ( el ) {
var parent = el . parentNode , container = this . instance . getContainer ( ) ;
while ( parent != null && parent !== container ) {
if ( parent . _jsPlumbList != null && this . lists [ parent . _jsPlumbList ] != null ) {
parent . _jsPlumbScrollHandler ( ) ;
return
}
parent = parent . parentNode ;
}
}
} ;
var List = function ( instance , el , options , id ) {
el [ "_jsPlumbList" ] = id ;
//
// Derive an anchor to use for the current situation. In contrast to the way we derive an endpoint, here we use `anchor` from the options, if present, as
// our first choice, and then `deriveAnchor` as our next choice. There is a default `deriveAnchor` implementation that uses TopRight/TopLeft for top and
// BottomRight/BottomLeft for bottom.
//
// edge - "top" or "bottom"
// index - 0 when endpoint is connection source, 1 when endpoint is connection target
// ep - the endpoint that is being proxied
// conn - the connection that is being proxied
//
function deriveAnchor ( edge , index , ep , conn ) {
return options . anchor ? options . anchor : options . deriveAnchor ( edge , index , ep , conn ) ;
}
//
// Derive an endpoint to use for the current situation. We'll use a `deriveEndpoint` function passed in to the options as our first choice,
// followed by `endpoint` (an endpoint spec) from the options, and failing either of those we just use the `type` of the endpoint that is being proxied.
//
// edge - "top" or "bottom"
// index - 0 when endpoint is connection source, 1 when endpoint is connection target
// endpoint - the endpoint that is being proxied
// connection - the connection that is being proxied
//
function deriveEndpoint ( edge , index , ep , conn ) {
return options . deriveEndpoint ? options . deriveEndpoint ( edge , index , ep , conn ) : options . endpoint ? options . endpoint : ep . type ;
}
//
// look for a parent of the given scrollable list that is draggable, and then update the child offsets for it. this should not
// be necessary in the delegated drag stuff from the upcoming 3.0.0 release.
//
function _maybeUpdateDraggable ( el ) {
var parent = el . parentNode , container = instance . getContainer ( ) ;
while ( parent != null && parent !== container ) {
if ( instance . hasClass ( parent , "jtk-managed" ) ) {
instance . recalculateOffsets ( parent ) ;
return
}
parent = parent . parentNode ;
}
}
var scrollHandler = function ( e ) {
var children = instance . getSelector ( el , ".jtk-managed" ) ;
var elId = instance . getId ( el ) ;
for ( var i = 0 ; i < children . length ; i ++ ) {
if ( children [ i ] . offsetTop < el . scrollTop ) {
if ( ! children [ i ] . _jsPlumbProxies ) {
children [ i ] . _jsPlumbProxies = children [ i ] . _jsPlumbProxies || [ ] ;
instance . select ( { source : children [ i ] } ) . each ( function ( c ) {
instance . proxyConnection ( c , 0 , el , elId , function ( ) {
return deriveEndpoint ( "top" , 0 , c . endpoints [ 0 ] , c ) ;
} , function ( ) {
return deriveAnchor ( "top" , 0 , c . endpoints [ 0 ] , c ) ;
} ) ;
children [ i ] . _jsPlumbProxies . push ( [ c , 0 ] ) ;
} ) ;
instance . select ( { target : children [ i ] } ) . each ( function ( c ) {
instance . proxyConnection ( c , 1 , el , elId , function ( ) {
return deriveEndpoint ( "top" , 1 , c . endpoints [ 1 ] , c ) ;
} , function ( ) {
return deriveAnchor ( "top" , 1 , c . endpoints [ 1 ] , c ) ;
} ) ;
children [ i ] . _jsPlumbProxies . push ( [ c , 1 ] ) ;
} ) ;
}
}
//
else if ( children [ i ] . offsetTop > el . scrollTop + el . offsetHeight ) {
if ( ! children [ i ] . _jsPlumbProxies ) {
children [ i ] . _jsPlumbProxies = children [ i ] . _jsPlumbProxies || [ ] ;
instance . select ( { source : children [ i ] } ) . each ( function ( c ) {
instance . proxyConnection ( c , 0 , el , elId , function ( ) {
return deriveEndpoint ( "bottom" , 0 , c . endpoints [ 0 ] , c ) ;
} , function ( ) {
return deriveAnchor ( "bottom" , 0 , c . endpoints [ 0 ] , c ) ;
} ) ;
children [ i ] . _jsPlumbProxies . push ( [ c , 0 ] ) ;
} ) ;
instance . select ( { target : children [ i ] } ) . each ( function ( c ) {
instance . proxyConnection ( c , 1 , el , elId , function ( ) {
return deriveEndpoint ( "bottom" , 1 , c . endpoints [ 1 ] , c ) ;
} , function ( ) {
return deriveAnchor ( "bottom" , 1 , c . endpoints [ 1 ] , c ) ;
} ) ;
children [ i ] . _jsPlumbProxies . push ( [ c , 1 ] ) ;
} ) ;
}
} else if ( children [ i ] . _jsPlumbProxies ) {
for ( var j = 0 ; j < children [ i ] . _jsPlumbProxies . length ; j ++ ) {
instance . unproxyConnection ( children [ i ] . _jsPlumbProxies [ j ] [ 0 ] , children [ i ] . _jsPlumbProxies [ j ] [ 1 ] , elId ) ;
}
delete children [ i ] . _jsPlumbProxies ;
}
instance . revalidate ( children [ i ] ) ;
}
_maybeUpdateDraggable ( el ) ;
} ;
instance . setAttribute ( el , "jtk-scrollable-list" , "true" ) ;
el . _jsPlumbScrollHandler = scrollHandler ;
instance . on ( el , "scroll" , scrollHandler ) ;
scrollHandler ( ) ; // run it once; there may be connections already.
this . destroy = function ( ) {
instance . off ( el , "scroll" , scrollHandler ) ;
delete el . _jsPlumbScrollHandler ;
var children = instance . getSelector ( el , ".jtk-managed" ) ;
var elId = instance . getId ( el ) ;
for ( var i = 0 ; i < children . length ; i ++ ) {
if ( children [ i ] . _jsPlumbProxies ) {
for ( var j = 0 ; j < children [ i ] . _jsPlumbProxies . length ; j ++ ) {
instance . unproxyConnection ( children [ i ] . _jsPlumbProxies [ j ] [ 0 ] , children [ i ] . _jsPlumbProxies [ j ] [ 1 ] , elId ) ;
}
delete children [ i ] . _jsPlumbProxies ;
}
}
} ;
} ;
} ) . call ( typeof window !== 'undefined' ? window : this ) ;
/ *
* This file contains the core code .
*
@ -4006,7 +4226,7 @@
var jsPlumbInstance = root . jsPlumbInstance = function ( _defaults ) {
this . version = "2. 9.3 ";
this . version = "2. 10.0 ";
this . Defaults = {
Anchor : "Bottom" ,
@ -5470,6 +5690,7 @@
managedElements [ id ] . info = _updateOffset ( { elId : id , timestamp : _suspendedAt } ) ;
_currentInstance . addClass ( element , "jtk-managed" ) ;
if ( ! _transient ) {
_currentInstance . fire ( "manageElement" , { id : id , info : managedElements [ id ] . info , el : element } ) ;
}
@ -5480,9 +5701,10 @@
var _unmanage = _currentInstance . unmanage = function ( id ) {
if ( managedElements [ id ] ) {
_currentInstance . removeClass ( managedElements [ id ] . el , "jtk-managed" ) ;
var el = managedElements [ id ] . el ;
_currentInstance . removeClass ( el , "jtk-managed" ) ;
delete managedElements [ id ] ;
_currentInstance . fire ( "unmanageElement" , id ) ;
_currentInstance . fire ( "unmanageElement" , { id : id , el : el } ) ;
}
} ;
@ -6619,6 +6841,8 @@
this . getFloatingConnectionFor = function ( id ) {
return floatingConnections [ id ] ;
} ;
this . listManager = new root . jsPlumbListManager ( this ) ;
} ;
_ju . extend ( root . jsPlumbInstance , _ju . EventGenerator , {
@ -6709,6 +6933,86 @@
floatingConnections : { } ,
getFloatingAnchorIndex : function ( jpc ) {
return jpc . endpoints [ 0 ] . isFloating ( ) ? 0 : jpc . endpoints [ 1 ] . isFloating ( ) ? 1 : - 1 ;
} ,
proxyConnection : function ( connection , index , proxyEl , proxyElId , endpointGenerator , anchorGenerator ) {
var proxyEp ,
originalElementId = connection . endpoints [ index ] . elementId ,
originalEndpoint = connection . endpoints [ index ] ;
connection . proxies = connection . proxies || [ ] ;
if ( connection . proxies [ index ] ) {
proxyEp = connection . proxies [ index ] . ep ;
} else {
proxyEp = this . addEndpoint ( proxyEl , {
endpoint : endpointGenerator ( connection , index ) ,
anchor : anchorGenerator ( connection , index ) ,
parameters : {
isProxyEndpoint : true
}
} ) ;
}
proxyEp . setDeleteOnEmpty ( true ) ;
// for this index, stash proxy info: the new EP, the original EP.
connection . proxies [ index ] = { ep : proxyEp , originalEp : originalEndpoint } ;
// and advise the anchor manager
if ( index === 0 ) {
// TODO why are there two differently named methods? Why is there not one method that says "some end of this
// connection changed (you give the index), and here's the new element and element id."
this . anchorManager . sourceChanged ( originalElementId , proxyElId , connection , proxyEl ) ;
}
else {
this . anchorManager . updateOtherEndpoint ( connection . endpoints [ 0 ] . elementId , originalElementId , proxyElId , connection ) ;
connection . target = proxyEl ;
connection . targetId = proxyElId ;
}
// detach the original EP from the connection.
originalEndpoint . detachFromConnection ( connection , null , true ) ;
// set the proxy as the new ep
proxyEp . connections = [ connection ] ;
connection . endpoints [ index ] = proxyEp ;
originalEndpoint . setVisible ( false ) ;
connection . setVisible ( true ) ;
this . revalidate ( proxyEl ) ;
} ,
unproxyConnection : function ( connection , index , proxyElId ) {
// if connection cleaned up, no proxies, or none for this end of the connection, abort.
if ( connection . _jsPlumb == null || connection . proxies == null || connection . proxies [ index ] == null ) {
return ;
}
var originalElement = connection . proxies [ index ] . originalEp . element ,
originalElementId = connection . proxies [ index ] . originalEp . elementId ;
connection . endpoints [ index ] = connection . proxies [ index ] . originalEp ;
// and advise the anchor manager
if ( index === 0 ) {
// TODO why are there two differently named methods? Why is there not one method that says "some end of this
// connection changed (you give the index), and here's the new element and element id."
this . anchorManager . sourceChanged ( proxyElId , originalElementId , connection , originalElement ) ;
}
else {
this . anchorManager . updateOtherEndpoint ( connection . endpoints [ 0 ] . elementId , proxyElId , originalElementId , connection ) ;
connection . target = originalElement ;
connection . targetId = originalElementId ;
}
// detach the proxy EP from the connection (which will cause it to be removed as we no longer need it)
connection . proxies [ index ] . ep . detachFromConnection ( connection , null ) ;
connection . proxies [ index ] . originalEp . addConnection ( connection ) ;
if ( connection . isVisible ( ) ) {
connection . proxies [ index ] . originalEp . setVisible ( true ) ;
}
// cleanup
delete connection . proxies [ index ] ;
}
} ) ;
@ -10183,15 +10487,15 @@
} ,
_path = function ( segments ) {
var anchorsPerFace = anchorCount / segments . length , a = [ ] ,
_computeFace = function ( x1 , y1 , x2 , y2 , fractionalLength ) {
_computeFace = function ( x1 , y1 , x2 , y2 , fractionalLength , ox , oy ) {
anchorsPerFace = anchorCount * fractionalLength ;
var dx = ( x2 - x1 ) / anchorsPerFace , dy = ( y2 - y1 ) / anchorsPerFace ;
for ( var i = 0 ; i < anchorsPerFace ; i ++ ) {
a . push ( [
x1 + ( dx * i ) ,
y1 + ( dy * i ) ,
0 ,
0
ox == null ? 0 : ox ,
oy == null ? 0 : oy
] ) ;
}
} ;
@ -10205,16 +10509,16 @@
_shape = function ( faces ) {
var s = [ ] ;
for ( var i = 0 ; i < faces . length ; i ++ ) {
s . push ( [ faces [ i ] [ 0 ] , faces [ i ] [ 1 ] , faces [ i ] [ 2 ] , faces [ i ] [ 3 ] , 1 / faces . length ]) ;
s . push ( [ faces [ i ] [ 0 ] , faces [ i ] [ 1 ] , faces [ i ] [ 2 ] , faces [ i ] [ 3 ] , 1 / faces . length , faces [ i ] [ 4 ] , faces [ i ] [ 5 ] ]) ;
}
return _path ( s ) ;
} ,
_rectangle = function ( ) {
return _shape ( [
[ 0 , 0 , 1 , 0 ] ,
[ 1 , 0 , 1 , 1 ] ,
[ 1 , 1 , 0 , 1 ] ,
[ 0 , 1 , 0 , 0 ]
[ 0 , 0 , 1 , 0 , 0 , - 1 ] ,
[ 1 , 0 , 1 , 1 , 1 , 0 ] ,
[ 1 , 1 , 0 , 1 , 0 , 1 ] ,
[ 0 , 1 , 0 , 0 , - 1 , 0 ]
] ) ;
} ;
@ -12115,11 +12419,11 @@
c . setVisible ( false ) ;
if ( c . endpoints [ oidx ] . element . _jsPlumbGroup === group ) {
c . endpoints [ oidx ] . setVisible ( false ) ;
self. expandConnection( c , oidx , group ) ;
_ expandConnection( c , oidx , group ) ;
}
else {
c . endpoints [ index ] . setVisible ( false ) ;
self. collapseConnection( c , index , group ) ;
_ collapseConnection( c , index , group ) ;
}
} ) ;
} ;
@ -12203,54 +12507,16 @@
}
}
var _collapseConnection = this . collapseConnection = function ( c , index , group ) {
var proxyEp , groupEl = group . getEl ( ) , groupElId = _jsPlumb . getId ( groupEl ) ,
originalElementId = c . endpoints [ index ] . elementId ;
var _collapseConnection = function ( c , index , group ) {
var otherEl = c . endpoints [ index === 0 ? 1 : 0 ] . element ;
if ( otherEl [ GROUP ] && ( ! otherEl [ GROUP ] . shouldProxy ( ) && otherEl [ GROUP ] . collapsed ) ) {
return ;
}
c . proxies = c . proxies || [ ] ;
if ( c . proxies [ index ] ) {
proxyEp = c . proxies [ index ] . ep ;
} else {
proxyEp = _jsPlumb . addEndpoint ( groupEl , {
endpoint : group . getEndpoint ( c , index ) ,
anchor : group . getAnchor ( c , index ) ,
parameters : {
isProxyEndpoint : true
}
} ) ;
}
proxyEp . setDeleteOnEmpty ( true ) ;
// for this index, stash proxy info: the new EP, the original EP.
c . proxies [ index ] = { ep : proxyEp , originalEp : c . endpoints [ index ] } ;
// and advise the anchor manager
if ( index === 0 ) {
// TODO why are there two differently named methods? Why is there not one method that says "some end of this
// connection changed (you give the index), and here's the new element and element id."
_jsPlumb . anchorManager . sourceChanged ( originalElementId , groupElId , c , groupEl ) ;
}
else {
_jsPlumb . anchorManager . updateOtherEndpoint ( c . endpoints [ 0 ] . elementId , originalElementId , groupElId , c ) ;
c . target = groupEl ;
c . targetId = groupElId ;
}
// detach the original EP from the connection.
c . proxies [ index ] . originalEp . detachFromConnection ( c , null , true ) ;
// set the proxy as the new ep
proxyEp . connections = [ c ] ;
c . endpoints [ index ] = proxyEp ;
var groupEl = group . getEl ( ) , groupElId = _jsPlumb . getId ( groupEl ) ;
c. setVisible ( true ) ;
_jsPlumb . proxyConnection ( c , index , groupEl , groupElId , function ( c , index ) { return group . getEndpoint ( c , index ) ; } , function ( c , index ) { return group . getAnchor ( c , index ) ; } ) ;
} ;
this . collapseGroup = function ( group ) {
@ -12287,37 +12553,8 @@
_jsPlumb . fire ( EVT _COLLAPSE , { group : group } ) ;
} ;
var _expandConnection = this . expandConnection = function ( c , index , group ) {
// if no proxies or none for this end of the connection, abort.
if ( c . proxies == null || c . proxies [ index ] == null ) {
return ;
}
var groupElId = _jsPlumb . getId ( group . getEl ( ) ) ,
originalElement = c . proxies [ index ] . originalEp . element ,
originalElementId = c . proxies [ index ] . originalEp . elementId ;
c . endpoints [ index ] = c . proxies [ index ] . originalEp ;
// and advise the anchor manager
if ( index === 0 ) {
// TODO why are there two differently named methods? Why is there not one method that says "some end of this
// connection changed (you give the index), and here's the new element and element id."
_jsPlumb . anchorManager . sourceChanged ( groupElId , originalElementId , c , originalElement ) ;
}
else {
_jsPlumb . anchorManager . updateOtherEndpoint ( c . endpoints [ 0 ] . elementId , groupElId , originalElementId , c ) ;
c . target = originalElement ;
c . targetId = originalElementId ;
}
// detach the proxy EP from the connection (which will cause it to be removed as we no longer need it)
c . proxies [ index ] . ep . detachFromConnection ( c , null ) ;
c . proxies [ index ] . originalEp . addConnection ( c ) ;
// cleanup
delete c . proxies [ index ] ;
var _expandConnection = function ( c , index , group ) {
_jsPlumb . unproxyConnection ( c , index , _jsPlumb . getId ( group . getEl ( ) ) ) ;
} ;
this . expandGroup = function ( group , doNotFireEvent ) {