1 | import * as is from '../is';
|
2 | import * as util from '../util';
|
3 |
|
4 | function styleCache( key, fn, ele ){
|
5 | var _p = ele._private;
|
6 | var cache = _p.styleCache = _p.styleCache || [];
|
7 | var val;
|
8 |
|
9 | if( (val = cache[key]) != null ){
|
10 | return val;
|
11 | } else {
|
12 | val = cache[key] = fn( ele );
|
13 |
|
14 | return val;
|
15 | }
|
16 | }
|
17 |
|
18 | function cacheStyleFunction( key, fn ){
|
19 | key = util.hashString( key );
|
20 |
|
21 | return function cachedStyleFunction( ele ){
|
22 | return styleCache( key, fn, ele );
|
23 | };
|
24 | }
|
25 |
|
26 | function cachePrototypeStyleFunction( key, fn ){
|
27 | key = util.hashString( key );
|
28 |
|
29 | let selfFn = ele => fn.call( ele );
|
30 |
|
31 | return function cachedPrototypeStyleFunction(){
|
32 | var ele = this[0];
|
33 |
|
34 | if( ele ){
|
35 | return styleCache( key, selfFn, ele );
|
36 | }
|
37 | };
|
38 | }
|
39 |
|
40 | let elesfn = ({
|
41 |
|
42 | recalculateRenderedStyle: function( useCache ){
|
43 | let cy = this.cy();
|
44 | let renderer = cy.renderer();
|
45 | let styleEnabled = cy.styleEnabled();
|
46 |
|
47 | if( renderer && styleEnabled ){
|
48 | renderer.recalculateRenderedStyle( this, useCache );
|
49 | }
|
50 |
|
51 | return this;
|
52 | },
|
53 |
|
54 | dirtyStyleCache: function(){
|
55 | let cy = this.cy();
|
56 | let dirty = ele => ele._private.styleCache = null;
|
57 |
|
58 | if( cy.hasCompoundNodes() ){
|
59 | let eles;
|
60 |
|
61 | eles = this.spawnSelf()
|
62 | .merge( this.descendants() )
|
63 | .merge( this.parents() )
|
64 | ;
|
65 |
|
66 | eles.merge( eles.connectedEdges() );
|
67 |
|
68 | eles.forEach( dirty );
|
69 | } else {
|
70 | this.forEach( ele => {
|
71 | dirty( ele );
|
72 |
|
73 | ele.connectedEdges().forEach( dirty );
|
74 | } );
|
75 | }
|
76 |
|
77 | return this;
|
78 | },
|
79 |
|
80 |
|
81 | updateStyle: function( notifyRenderer ){
|
82 | let cy = this._private.cy;
|
83 |
|
84 | if( !cy.styleEnabled() ){ return this; }
|
85 |
|
86 | if( cy.batching() ){
|
87 | let bEles = cy._private.batchStyleEles;
|
88 |
|
89 | bEles.merge( this );
|
90 |
|
91 | return this;
|
92 | }
|
93 |
|
94 | let hasCompounds = cy.hasCompoundNodes();
|
95 | let updatedEles = this;
|
96 |
|
97 | notifyRenderer = notifyRenderer || notifyRenderer === undefined ? true : false;
|
98 |
|
99 | if( hasCompounds ){
|
100 | updatedEles = this.spawnSelf().merge( this.descendants() ).merge( this.parents() );
|
101 | }
|
102 |
|
103 |
|
104 | let changedEles = updatedEles;
|
105 |
|
106 | if( notifyRenderer ){
|
107 | changedEles.emitAndNotify( 'style' );
|
108 | } else {
|
109 | changedEles.emit( 'style' );
|
110 | }
|
111 |
|
112 | updatedEles.forEach(ele => ele._private.styleDirty = true);
|
113 |
|
114 | return this;
|
115 | },
|
116 |
|
117 |
|
118 | parsedStyle: function( property, includeNonDefault = true ){
|
119 | let ele = this[0];
|
120 | let cy = ele.cy();
|
121 |
|
122 | if( !cy.styleEnabled() ){ return; }
|
123 |
|
124 | if( ele ){
|
125 | if( ele._private.styleDirty ){
|
126 | ele._private.styleDirty = false;
|
127 |
|
128 | cy.style().apply(ele);
|
129 | ele.emitAndNotify('style');
|
130 | }
|
131 |
|
132 | let overriddenStyle = ele._private.style[ property ];
|
133 |
|
134 | if( overriddenStyle != null ){
|
135 | return overriddenStyle;
|
136 | } else if( includeNonDefault ){
|
137 | return cy.style().getDefaultProperty( property );
|
138 | } else {
|
139 | return null;
|
140 | }
|
141 | }
|
142 | },
|
143 |
|
144 | numericStyle: function( property ){
|
145 | let ele = this[0];
|
146 |
|
147 | if( !ele.cy().styleEnabled() ){ return; }
|
148 |
|
149 | if( ele ){
|
150 | let pstyle = ele.pstyle( property );
|
151 |
|
152 | return pstyle.pfValue !== undefined ? pstyle.pfValue : pstyle.value;
|
153 | }
|
154 | },
|
155 |
|
156 | numericStyleUnits: function( property ){
|
157 | let ele = this[0];
|
158 |
|
159 | if( !ele.cy().styleEnabled() ){ return; }
|
160 |
|
161 | if( ele ){
|
162 | return ele.pstyle( property ).units;
|
163 | }
|
164 | },
|
165 |
|
166 |
|
167 |
|
168 | renderedStyle: function( property ){
|
169 | let cy = this.cy();
|
170 | if( !cy.styleEnabled() ){ return this; }
|
171 |
|
172 | let ele = this[0];
|
173 |
|
174 | if( ele ){
|
175 | return cy.style().getRenderedStyle( ele, property );
|
176 | }
|
177 | },
|
178 |
|
179 |
|
180 | style: function( name, value ){
|
181 | let cy = this.cy();
|
182 |
|
183 | if( !cy.styleEnabled() ){ return this; }
|
184 |
|
185 | let updateTransitions = false;
|
186 | let style = cy.style();
|
187 |
|
188 | if( is.plainObject( name ) ){
|
189 | let props = name;
|
190 | style.applyBypass( this, props, updateTransitions );
|
191 |
|
192 | this.emitAndNotify( 'style' );
|
193 |
|
194 | } else if( is.string( name ) ){
|
195 |
|
196 | if( value === undefined ){
|
197 | let ele = this[0];
|
198 |
|
199 | if( ele ){
|
200 | return style.getStylePropertyValue( ele, name );
|
201 | } else {
|
202 | return;
|
203 | }
|
204 |
|
205 | } else {
|
206 | style.applyBypass( this, name, value, updateTransitions );
|
207 |
|
208 | this.emitAndNotify( 'style' );
|
209 | }
|
210 |
|
211 | } else if( name === undefined ){
|
212 | let ele = this[0];
|
213 |
|
214 | if( ele ){
|
215 | return style.getRawStyle( ele );
|
216 | } else {
|
217 | return;
|
218 | }
|
219 | }
|
220 |
|
221 | return this;
|
222 | },
|
223 |
|
224 | removeStyle: function( names ){
|
225 | let cy = this.cy();
|
226 |
|
227 | if( !cy.styleEnabled() ){ return this; }
|
228 |
|
229 | let updateTransitions = false;
|
230 | let style = cy.style();
|
231 | let eles = this;
|
232 |
|
233 | if( names === undefined ){
|
234 | for( let i = 0; i < eles.length; i++ ){
|
235 | let ele = eles[ i ];
|
236 |
|
237 | style.removeAllBypasses( ele, updateTransitions );
|
238 | }
|
239 | } else {
|
240 | names = names.split( /\s+/ );
|
241 |
|
242 | for( let i = 0; i < eles.length; i++ ){
|
243 | let ele = eles[ i ];
|
244 |
|
245 | style.removeBypasses( ele, names, updateTransitions );
|
246 | }
|
247 | }
|
248 |
|
249 | this.emitAndNotify( 'style' );
|
250 |
|
251 | return this;
|
252 | },
|
253 |
|
254 | show: function(){
|
255 | this.css( 'display', 'element' );
|
256 | return this;
|
257 | },
|
258 |
|
259 | hide: function(){
|
260 | this.css( 'display', 'none' );
|
261 | return this;
|
262 | },
|
263 |
|
264 | effectiveOpacity: function(){
|
265 | let cy = this.cy();
|
266 | if( !cy.styleEnabled() ){ return 1; }
|
267 |
|
268 | let hasCompoundNodes = cy.hasCompoundNodes();
|
269 | let ele = this[0];
|
270 |
|
271 | if( ele ){
|
272 | let _p = ele._private;
|
273 | let parentOpacity = ele.pstyle( 'opacity' ).value;
|
274 |
|
275 | if( !hasCompoundNodes ){ return parentOpacity; }
|
276 |
|
277 | let parents = !_p.data.parent ? null : ele.parents();
|
278 |
|
279 | if( parents ){
|
280 | for( let i = 0; i < parents.length; i++ ){
|
281 | let parent = parents[ i ];
|
282 | let opacity = parent.pstyle( 'opacity' ).value;
|
283 |
|
284 | parentOpacity = opacity * parentOpacity;
|
285 | }
|
286 | }
|
287 |
|
288 | return parentOpacity;
|
289 | }
|
290 | },
|
291 |
|
292 | transparent: function(){
|
293 | let cy = this.cy();
|
294 | if( !cy.styleEnabled() ){ return false; }
|
295 |
|
296 | let ele = this[0];
|
297 | let hasCompoundNodes = ele.cy().hasCompoundNodes();
|
298 |
|
299 | if( ele ){
|
300 | if( !hasCompoundNodes ){
|
301 | return ele.pstyle( 'opacity' ).value === 0;
|
302 | } else {
|
303 | return ele.effectiveOpacity() === 0;
|
304 | }
|
305 | }
|
306 | },
|
307 |
|
308 | backgrounding: function(){
|
309 | let cy = this.cy();
|
310 | if( !cy.styleEnabled() ){ return false; }
|
311 |
|
312 | let ele = this[0];
|
313 |
|
314 | return ele._private.backgrounding ? true : false;
|
315 | }
|
316 |
|
317 | });
|
318 |
|
319 | function checkCompound( ele, parentOk ){
|
320 | let _p = ele._private;
|
321 | let parents = _p.data.parent ? ele.parents() : null;
|
322 |
|
323 | if( parents ){ for( let i = 0; i < parents.length; i++ ){
|
324 | let parent = parents[ i ];
|
325 |
|
326 | if( !parentOk( parent ) ){ return false; }
|
327 | } }
|
328 |
|
329 | return true;
|
330 | }
|
331 |
|
332 | function defineDerivedStateFunction( specs ){
|
333 | let ok = specs.ok;
|
334 | let edgeOkViaNode = specs.edgeOkViaNode || specs.ok;
|
335 | let parentOk = specs.parentOk || specs.ok;
|
336 |
|
337 | return function(){
|
338 | let cy = this.cy();
|
339 | if( !cy.styleEnabled() ){ return true; }
|
340 |
|
341 | let ele = this[0];
|
342 | let hasCompoundNodes = cy.hasCompoundNodes();
|
343 |
|
344 | if( ele ){
|
345 | let _p = ele._private;
|
346 |
|
347 | if( !ok( ele ) ){ return false; }
|
348 |
|
349 | if( ele.isNode() ){
|
350 | return !hasCompoundNodes || checkCompound( ele, parentOk );
|
351 | } else {
|
352 | let src = _p.source;
|
353 | let tgt = _p.target;
|
354 |
|
355 | return ( edgeOkViaNode(src) && (!hasCompoundNodes || checkCompound(src, edgeOkViaNode)) ) &&
|
356 | ( src === tgt || ( edgeOkViaNode(tgt) && (!hasCompoundNodes || checkCompound(tgt, edgeOkViaNode)) ) );
|
357 | }
|
358 | }
|
359 | };
|
360 | }
|
361 |
|
362 | let eleTakesUpSpace = cacheStyleFunction( 'eleTakesUpSpace', function( ele ){
|
363 | return (
|
364 | ele.pstyle( 'display' ).value === 'element'
|
365 | && ele.width() !== 0
|
366 | && ( ele.isNode() ? ele.height() !== 0 : true )
|
367 | );
|
368 | } );
|
369 |
|
370 | elesfn.takesUpSpace = cachePrototypeStyleFunction( 'takesUpSpace', defineDerivedStateFunction({
|
371 | ok: eleTakesUpSpace
|
372 | }) );
|
373 |
|
374 | let eleInteractive = cacheStyleFunction( 'eleInteractive', function( ele ){
|
375 | return (
|
376 | ele.pstyle('events').value === 'yes'
|
377 | && ele.pstyle('visibility').value === 'visible'
|
378 | && eleTakesUpSpace( ele )
|
379 | );
|
380 | } );
|
381 |
|
382 | let parentInteractive = cacheStyleFunction( 'parentInteractive', function( parent ){
|
383 | return (
|
384 | parent.pstyle('visibility').value === 'visible'
|
385 | && eleTakesUpSpace( parent )
|
386 | );
|
387 | } );
|
388 |
|
389 | elesfn.interactive = cachePrototypeStyleFunction( 'interactive', defineDerivedStateFunction({
|
390 | ok: eleInteractive,
|
391 | parentOk: parentInteractive,
|
392 | edgeOkViaNode: eleTakesUpSpace
|
393 | }) );
|
394 |
|
395 | elesfn.noninteractive = function(){
|
396 | let ele = this[0];
|
397 |
|
398 | if( ele ){
|
399 | return !ele.interactive();
|
400 | }
|
401 | };
|
402 |
|
403 | let eleVisible = cacheStyleFunction( 'eleVisible', function( ele ){
|
404 | return (
|
405 | ele.pstyle( 'visibility' ).value === 'visible'
|
406 | && ele.pstyle( 'opacity' ).pfValue !== 0
|
407 | && eleTakesUpSpace( ele )
|
408 | );
|
409 | } );
|
410 |
|
411 | let edgeVisibleViaNode = eleTakesUpSpace;
|
412 |
|
413 | elesfn.visible = cachePrototypeStyleFunction( 'visible', defineDerivedStateFunction({
|
414 | ok: eleVisible,
|
415 | edgeOkViaNode: edgeVisibleViaNode
|
416 | }) );
|
417 |
|
418 | elesfn.hidden = function(){
|
419 | let ele = this[0];
|
420 |
|
421 | if( ele ){
|
422 | return !ele.visible();
|
423 | }
|
424 | };
|
425 |
|
426 | elesfn.isBundledBezier = cachePrototypeStyleFunction('isBundledBezier', function(){
|
427 | if( !this.cy().styleEnabled() ){ return false; }
|
428 |
|
429 | return !this.removed() && this.pstyle('curve-style').value === 'bezier' && this.takesUpSpace();
|
430 | });
|
431 |
|
432 | elesfn.bypass = elesfn.css = elesfn.style;
|
433 | elesfn.renderedCss = elesfn.renderedStyle;
|
434 | elesfn.removeBypass = elesfn.removeCss = elesfn.removeStyle;
|
435 | elesfn.pstyle = elesfn.parsedStyle;
|
436 |
|
437 | export default elesfn;
|