|
import * as util from'./util'; |
|
import define from './define'; |
|
import Collection from './collection'; |
|
import Core from './core'; |
|
import incExts from './extensions'; |
|
import * as is from './is'; |
|
import Emitter from './emitter'; |
|
|
|
|
|
let extensions = {}; |
|
|
|
|
|
let modules = {}; |
|
|
|
function setExtension( type, name, registrant ){ |
|
|
|
let ext = registrant; |
|
|
|
let overrideErr = function( field ){ |
|
util.warn( 'Can not register `' + name + '` for `' + type + '` since `' + field + '` already exists in the prototype and can not be overridden' ); |
|
}; |
|
|
|
if( type === 'core' ){ |
|
if( Core.prototype[ name ] ){ |
|
return overrideErr( name ); |
|
} else { |
|
Core.prototype[ name ] = registrant; |
|
} |
|
|
|
} else if( type === 'collection' ){ |
|
if( Collection.prototype[ name ] ){ |
|
return overrideErr( name ); |
|
} else { |
|
Collection.prototype[ name ] = registrant; |
|
} |
|
|
|
} else if( type === 'layout' ){ |
|
|
|
|
|
let Layout = function( options ){ |
|
this.options = options; |
|
|
|
registrant.call( this, options ); |
|
|
|
|
|
if( !is.plainObject( this._private ) ){ |
|
this._private = {}; |
|
} |
|
|
|
this._private.cy = options.cy; |
|
this._private.listeners = []; |
|
|
|
this.createEmitter(); |
|
}; |
|
|
|
let layoutProto = Layout.prototype = Object.create( registrant.prototype ); |
|
|
|
let optLayoutFns = []; |
|
|
|
for( let i = 0; i < optLayoutFns.length; i++ ){ |
|
let fnName = optLayoutFns[ i ]; |
|
|
|
layoutProto[ fnName ] = layoutProto[ fnName ] || function(){ return this; }; |
|
} |
|
|
|
|
|
if( layoutProto.start && !layoutProto.run ){ |
|
layoutProto.run = function(){ this.start(); return this; }; |
|
} else if( !layoutProto.start && layoutProto.run ){ |
|
layoutProto.start = function(){ this.run(); return this; }; |
|
} |
|
|
|
let regStop = registrant.prototype.stop; |
|
layoutProto.stop = function(){ |
|
let opts = this.options; |
|
|
|
if( opts && opts.animate ){ |
|
let anis = this.animations; |
|
|
|
if( anis ){ |
|
for( let i = 0; i < anis.length; i++ ){ |
|
anis[ i ].stop(); |
|
} |
|
} |
|
} |
|
|
|
if( regStop ){ |
|
regStop.call( this ); |
|
} else { |
|
this.emit( 'layoutstop' ); |
|
} |
|
|
|
return this; |
|
}; |
|
|
|
if( !layoutProto.destroy ){ |
|
layoutProto.destroy = function(){ |
|
return this; |
|
}; |
|
} |
|
|
|
layoutProto.cy = function(){ |
|
return this._private.cy; |
|
}; |
|
|
|
let getCy = layout => layout._private.cy; |
|
|
|
let emitterOpts = { |
|
addEventFields: function( layout, evt ){ |
|
evt.layout = layout; |
|
evt.cy = getCy(layout); |
|
evt.target = layout; |
|
}, |
|
bubble: function(){ return true; }, |
|
parent: function( layout ){ return getCy(layout); } |
|
}; |
|
|
|
util.assign( layoutProto, { |
|
createEmitter: function(){ |
|
this._private.emitter = new Emitter( emitterOpts, this ); |
|
|
|
return this; |
|
}, |
|
emitter: function(){ return this._private.emitter; }, |
|
on: function( evt, cb ){ this.emitter().on( evt, cb ); return this; }, |
|
one: function( evt, cb ){ this.emitter().one( evt, cb ); return this; }, |
|
once: function( evt, cb ){ this.emitter().one( evt, cb ); return this; }, |
|
removeListener: function( evt, cb ){ this.emitter().removeListener( evt, cb ); return this; }, |
|
removeAllListeners: function(){ this.emitter().removeAllListeners(); return this; }, |
|
emit: function( evt, params ){ this.emitter().emit( evt, params ); return this; } |
|
} ); |
|
|
|
define.eventAliasesOn( layoutProto ); |
|
|
|
ext = Layout; |
|
|
|
} else if( type === 'renderer' && name !== 'null' && name !== 'base' ){ |
|
|
|
|
|
let BaseRenderer = getExtension( 'renderer', 'base' ); |
|
let bProto = BaseRenderer.prototype; |
|
let RegistrantRenderer = registrant; |
|
let rProto = registrant.prototype; |
|
|
|
let Renderer = function(){ |
|
BaseRenderer.apply( this, arguments ); |
|
RegistrantRenderer.apply( this, arguments ); |
|
}; |
|
|
|
let proto = Renderer.prototype; |
|
|
|
for( let pName in bProto ){ |
|
let pVal = bProto[ pName ]; |
|
let existsInR = rProto[ pName ] != null; |
|
|
|
if( existsInR ){ |
|
return overrideErr( pName ); |
|
} |
|
|
|
proto[ pName ] = pVal; |
|
} |
|
|
|
for( let pName in rProto ){ |
|
proto[ pName ] = rProto[ pName ]; |
|
} |
|
|
|
bProto.clientFunctions.forEach( function( name ){ |
|
proto[ name ] = proto[ name ] || function(){ |
|
util.error( 'Renderer does not implement `renderer.' + name + '()` on its prototype' ); |
|
}; |
|
} ); |
|
|
|
ext = Renderer; |
|
|
|
} else if (type === '__proto__' || type === 'constructor' || type === 'prototype'){ |
|
|
|
return util.error( type + ' is an illegal type to be registered, possibly lead to prototype pollutions' ); |
|
} |
|
|
|
return util.setMap( { |
|
map: extensions, |
|
keys: [ type, name ], |
|
value: ext |
|
} ); |
|
} |
|
|
|
function getExtension( type, name ){ |
|
return util.getMap( { |
|
map: extensions, |
|
keys: [ type, name ] |
|
} ); |
|
} |
|
|
|
function setModule( type, name, moduleType, moduleName, registrant ){ |
|
return util.setMap( { |
|
map: modules, |
|
keys: [ type, name, moduleType, moduleName ], |
|
value: registrant |
|
} ); |
|
} |
|
|
|
function getModule( type, name, moduleType, moduleName ){ |
|
return util.getMap( { |
|
map: modules, |
|
keys: [ type, name, moduleType, moduleName ] |
|
} ); |
|
} |
|
|
|
let extension = function(){ |
|
|
|
if( arguments.length === 2 ){ |
|
return getExtension.apply( null, arguments ); |
|
} |
|
|
|
|
|
else if( arguments.length === 3 ){ |
|
return setExtension.apply( null, arguments ); |
|
} |
|
|
|
|
|
else if( arguments.length === 4 ){ |
|
return getModule.apply( null, arguments ); |
|
} |
|
|
|
|
|
else if( arguments.length === 5 ){ |
|
return setModule.apply( null, arguments ); |
|
} |
|
|
|
else { |
|
util.error( 'Invalid extension access syntax' ); |
|
} |
|
|
|
}; |
|
|
|
|
|
Core.prototype.extension = extension; |
|
|
|
|
|
incExts.forEach( function( group ){ |
|
group.extensions.forEach( function( ext ){ |
|
setExtension( group.type, ext.name, ext.impl ); |
|
} ); |
|
} ); |
|
|
|
export default extension; |
|
|