1 | import * as util from'./util';
|
2 | import define from './define';
|
3 | import Collection from './collection';
|
4 | import Core from './core';
|
5 | import incExts from './extensions';
|
6 | import * as is from './is';
|
7 | import Emitter from './emitter';
|
8 |
|
9 |
|
10 | let extensions = {};
|
11 |
|
12 |
|
13 | let modules = {};
|
14 |
|
15 | function setExtension( type, name, registrant ){
|
16 |
|
17 | let ext = registrant;
|
18 |
|
19 | let overrideErr = function( field ){
|
20 | util.warn( 'Can not register `' + name + '` for `' + type + '` since `' + field + '` already exists in the prototype and can not be overridden' );
|
21 | };
|
22 |
|
23 | if( type === 'core' ){
|
24 | if( Core.prototype[ name ] ){
|
25 | return overrideErr( name );
|
26 | } else {
|
27 | Core.prototype[ name ] = registrant;
|
28 | }
|
29 |
|
30 | } else if( type === 'collection' ){
|
31 | if( Collection.prototype[ name ] ){
|
32 | return overrideErr( name );
|
33 | } else {
|
34 | Collection.prototype[ name ] = registrant;
|
35 | }
|
36 |
|
37 | } else if( type === 'layout' ){
|
38 |
|
39 |
|
40 | let Layout = function( options ){
|
41 | this.options = options;
|
42 |
|
43 | registrant.call( this, options );
|
44 |
|
45 |
|
46 | if( !is.plainObject( this._private ) ){
|
47 | this._private = {};
|
48 | }
|
49 |
|
50 | this._private.cy = options.cy;
|
51 | this._private.listeners = [];
|
52 |
|
53 | this.createEmitter();
|
54 | };
|
55 |
|
56 | let layoutProto = Layout.prototype = Object.create( registrant.prototype );
|
57 |
|
58 | let optLayoutFns = [];
|
59 |
|
60 | for( let i = 0; i < optLayoutFns.length; i++ ){
|
61 | let fnName = optLayoutFns[ i ];
|
62 |
|
63 | layoutProto[ fnName ] = layoutProto[ fnName ] || function(){ return this; };
|
64 | }
|
65 |
|
66 |
|
67 | if( layoutProto.start && !layoutProto.run ){
|
68 | layoutProto.run = function(){ this.start(); return this; };
|
69 | } else if( !layoutProto.start && layoutProto.run ){
|
70 | layoutProto.start = function(){ this.run(); return this; };
|
71 | }
|
72 |
|
73 | let regStop = registrant.prototype.stop;
|
74 | layoutProto.stop = function(){
|
75 | let opts = this.options;
|
76 |
|
77 | if( opts && opts.animate ){
|
78 | let anis = this.animations;
|
79 |
|
80 | if( anis ){
|
81 | for( let i = 0; i < anis.length; i++ ){
|
82 | anis[ i ].stop();
|
83 | }
|
84 | }
|
85 | }
|
86 |
|
87 | if( regStop ){
|
88 | regStop.call( this );
|
89 | } else {
|
90 | this.emit( 'layoutstop' );
|
91 | }
|
92 |
|
93 | return this;
|
94 | };
|
95 |
|
96 | if( !layoutProto.destroy ){
|
97 | layoutProto.destroy = function(){
|
98 | return this;
|
99 | };
|
100 | }
|
101 |
|
102 | layoutProto.cy = function(){
|
103 | return this._private.cy;
|
104 | };
|
105 |
|
106 | let getCy = layout => layout._private.cy;
|
107 |
|
108 | let emitterOpts = {
|
109 | addEventFields: function( layout, evt ){
|
110 | evt.layout = layout;
|
111 | evt.cy = getCy(layout);
|
112 | evt.target = layout;
|
113 | },
|
114 | bubble: function(){ return true; },
|
115 | parent: function( layout ){ return getCy(layout); }
|
116 | };
|
117 |
|
118 | util.assign( layoutProto, {
|
119 | createEmitter: function(){
|
120 | this._private.emitter = new Emitter( emitterOpts, this );
|
121 |
|
122 | return this;
|
123 | },
|
124 | emitter: function(){ return this._private.emitter; },
|
125 | on: function( evt, cb ){ this.emitter().on( evt, cb ); return this; },
|
126 | one: function( evt, cb ){ this.emitter().one( evt, cb ); return this; },
|
127 | once: function( evt, cb ){ this.emitter().one( evt, cb ); return this; },
|
128 | removeListener: function( evt, cb ){ this.emitter().removeListener( evt, cb ); return this; },
|
129 | removeAllListeners: function(){ this.emitter().removeAllListeners(); return this; },
|
130 | emit: function( evt, params ){ this.emitter().emit( evt, params ); return this; }
|
131 | } );
|
132 |
|
133 | define.eventAliasesOn( layoutProto );
|
134 |
|
135 | ext = Layout;
|
136 |
|
137 | } else if( type === 'renderer' && name !== 'null' && name !== 'base' ){
|
138 |
|
139 |
|
140 | let BaseRenderer = getExtension( 'renderer', 'base' );
|
141 | let bProto = BaseRenderer.prototype;
|
142 | let RegistrantRenderer = registrant;
|
143 | let rProto = registrant.prototype;
|
144 |
|
145 | let Renderer = function(){
|
146 | BaseRenderer.apply( this, arguments );
|
147 | RegistrantRenderer.apply( this, arguments );
|
148 | };
|
149 |
|
150 | let proto = Renderer.prototype;
|
151 |
|
152 | for( let pName in bProto ){
|
153 | let pVal = bProto[ pName ];
|
154 | let existsInR = rProto[ pName ] != null;
|
155 |
|
156 | if( existsInR ){
|
157 | return overrideErr( pName );
|
158 | }
|
159 |
|
160 | proto[ pName ] = pVal;
|
161 | }
|
162 |
|
163 | for( let pName in rProto ){
|
164 | proto[ pName ] = rProto[ pName ];
|
165 | }
|
166 |
|
167 | bProto.clientFunctions.forEach( function( name ){
|
168 | proto[ name ] = proto[ name ] || function(){
|
169 | util.error( 'Renderer does not implement `renderer.' + name + '()` on its prototype' );
|
170 | };
|
171 | } );
|
172 |
|
173 | ext = Renderer;
|
174 |
|
175 | } else if (type === '__proto__' || type === 'constructor' || type === 'prototype'){
|
176 |
|
177 | return util.error( type + ' is an illegal type to be registered, possibly lead to prototype pollutions' );
|
178 | }
|
179 |
|
180 | return util.setMap( {
|
181 | map: extensions,
|
182 | keys: [ type, name ],
|
183 | value: ext
|
184 | } );
|
185 | }
|
186 |
|
187 | function getExtension( type, name ){
|
188 | return util.getMap( {
|
189 | map: extensions,
|
190 | keys: [ type, name ]
|
191 | } );
|
192 | }
|
193 |
|
194 | function setModule( type, name, moduleType, moduleName, registrant ){
|
195 | return util.setMap( {
|
196 | map: modules,
|
197 | keys: [ type, name, moduleType, moduleName ],
|
198 | value: registrant
|
199 | } );
|
200 | }
|
201 |
|
202 | function getModule( type, name, moduleType, moduleName ){
|
203 | return util.getMap( {
|
204 | map: modules,
|
205 | keys: [ type, name, moduleType, moduleName ]
|
206 | } );
|
207 | }
|
208 |
|
209 | let extension = function(){
|
210 |
|
211 | if( arguments.length === 2 ){
|
212 | return getExtension.apply( null, arguments );
|
213 | }
|
214 |
|
215 |
|
216 | else if( arguments.length === 3 ){
|
217 | return setExtension.apply( null, arguments );
|
218 | }
|
219 |
|
220 |
|
221 | else if( arguments.length === 4 ){
|
222 | return getModule.apply( null, arguments );
|
223 | }
|
224 |
|
225 |
|
226 | else if( arguments.length === 5 ){
|
227 | return setModule.apply( null, arguments );
|
228 | }
|
229 |
|
230 | else {
|
231 | util.error( 'Invalid extension access syntax' );
|
232 | }
|
233 |
|
234 | };
|
235 |
|
236 |
|
237 | Core.prototype.extension = extension;
|
238 |
|
239 |
|
240 | incExts.forEach( function( group ){
|
241 | group.extensions.forEach( function( ext ){
|
242 | setExtension( group.type, ext.name, ext.impl );
|
243 | } );
|
244 | } );
|
245 |
|
246 | export default extension;
|