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 | cleanStyle: function(){
|
119 | let cy = this.cy();
|
120 |
|
121 | if( !cy.styleEnabled() ){ return; }
|
122 |
|
123 | for( let i = 0; i < this.length; i++ ){
|
124 | let ele = this[i];
|
125 |
|
126 | if( ele._private.styleDirty ){
|
127 |
|
128 | ele._private.styleDirty = false;
|
129 |
|
130 | cy.style().apply(ele);
|
131 | }
|
132 | }
|
133 | },
|
134 |
|
135 |
|
136 | parsedStyle: function( property, includeNonDefault = true ){
|
137 | let ele = this[0];
|
138 | let cy = ele.cy();
|
139 |
|
140 | if( !cy.styleEnabled() ){ return; }
|
141 |
|
142 | if( ele ){
|
143 | this.cleanStyle();
|
144 |
|
145 | let overriddenStyle = ele._private.style[ property ];
|
146 |
|
147 | if( overriddenStyle != null ){
|
148 | return overriddenStyle;
|
149 | } else if( includeNonDefault ){
|
150 | return cy.style().getDefaultProperty( property );
|
151 | } else {
|
152 | return null;
|
153 | }
|
154 | }
|
155 | },
|
156 |
|
157 | numericStyle: function( property ){
|
158 | let ele = this[0];
|
159 |
|
160 | if( !ele.cy().styleEnabled() ){ return; }
|
161 |
|
162 | if( ele ){
|
163 | let pstyle = ele.pstyle( property );
|
164 |
|
165 | return pstyle.pfValue !== undefined ? pstyle.pfValue : pstyle.value;
|
166 | }
|
167 | },
|
168 |
|
169 | numericStyleUnits: function( property ){
|
170 | let ele = this[0];
|
171 |
|
172 | if( !ele.cy().styleEnabled() ){ return; }
|
173 |
|
174 | if( ele ){
|
175 | return ele.pstyle( property ).units;
|
176 | }
|
177 | },
|
178 |
|
179 |
|
180 |
|
181 | renderedStyle: function( property ){
|
182 | let cy = this.cy();
|
183 | if( !cy.styleEnabled() ){ return this; }
|
184 |
|
185 | let ele = this[0];
|
186 |
|
187 | if( ele ){
|
188 | return cy.style().getRenderedStyle( ele, property );
|
189 | }
|
190 | },
|
191 |
|
192 |
|
193 | style: function( name, value ){
|
194 | let cy = this.cy();
|
195 |
|
196 | if( !cy.styleEnabled() ){ return this; }
|
197 |
|
198 | let updateTransitions = false;
|
199 | let style = cy.style();
|
200 |
|
201 | if( is.plainObject( name ) ){
|
202 | let props = name;
|
203 | style.applyBypass( this, props, updateTransitions );
|
204 |
|
205 | this.emitAndNotify( 'style' );
|
206 |
|
207 | } else if( is.string( name ) ){
|
208 |
|
209 | if( value === undefined ){
|
210 | let ele = this[0];
|
211 |
|
212 | if( ele ){
|
213 | return style.getStylePropertyValue( ele, name );
|
214 | } else {
|
215 | return;
|
216 | }
|
217 |
|
218 | } else {
|
219 | style.applyBypass( this, name, value, updateTransitions );
|
220 |
|
221 | this.emitAndNotify( 'style' );
|
222 | }
|
223 |
|
224 | } else if( name === undefined ){
|
225 | let ele = this[0];
|
226 |
|
227 | if( ele ){
|
228 | return style.getRawStyle( ele );
|
229 | } else {
|
230 | return;
|
231 | }
|
232 | }
|
233 |
|
234 | return this;
|
235 | },
|
236 |
|
237 | removeStyle: function( names ){
|
238 | let cy = this.cy();
|
239 |
|
240 | if( !cy.styleEnabled() ){ return this; }
|
241 |
|
242 | let updateTransitions = false;
|
243 | let style = cy.style();
|
244 | let eles = this;
|
245 |
|
246 | if( names === undefined ){
|
247 | for( let i = 0; i < eles.length; i++ ){
|
248 | let ele = eles[ i ];
|
249 |
|
250 | style.removeAllBypasses( ele, updateTransitions );
|
251 | }
|
252 | } else {
|
253 | names = names.split( /\s+/ );
|
254 |
|
255 | for( let i = 0; i < eles.length; i++ ){
|
256 | let ele = eles[ i ];
|
257 |
|
258 | style.removeBypasses( ele, names, updateTransitions );
|
259 | }
|
260 | }
|
261 |
|
262 | this.emitAndNotify( 'style' );
|
263 |
|
264 | return this;
|
265 | },
|
266 |
|
267 | show: function(){
|
268 | this.css( 'display', 'element' );
|
269 | return this;
|
270 | },
|
271 |
|
272 | hide: function(){
|
273 | this.css( 'display', 'none' );
|
274 | return this;
|
275 | },
|
276 |
|
277 | effectiveOpacity: function(){
|
278 | let cy = this.cy();
|
279 | if( !cy.styleEnabled() ){ return 1; }
|
280 |
|
281 | let hasCompoundNodes = cy.hasCompoundNodes();
|
282 | let ele = this[0];
|
283 |
|
284 | if( ele ){
|
285 | let _p = ele._private;
|
286 | let parentOpacity = ele.pstyle( 'opacity' ).value;
|
287 |
|
288 | if( !hasCompoundNodes ){ return parentOpacity; }
|
289 |
|
290 | let parents = !_p.data.parent ? null : ele.parents();
|
291 |
|
292 | if( parents ){
|
293 | for( let i = 0; i < parents.length; i++ ){
|
294 | let parent = parents[ i ];
|
295 | let opacity = parent.pstyle( 'opacity' ).value;
|
296 |
|
297 | parentOpacity = opacity * parentOpacity;
|
298 | }
|
299 | }
|
300 |
|
301 | return parentOpacity;
|
302 | }
|
303 | },
|
304 |
|
305 | transparent: function(){
|
306 | let cy = this.cy();
|
307 | if( !cy.styleEnabled() ){ return false; }
|
308 |
|
309 | let ele = this[0];
|
310 | let hasCompoundNodes = ele.cy().hasCompoundNodes();
|
311 |
|
312 | if( ele ){
|
313 | if( !hasCompoundNodes ){
|
314 | return ele.pstyle( 'opacity' ).value === 0;
|
315 | } else {
|
316 | return ele.effectiveOpacity() === 0;
|
317 | }
|
318 | }
|
319 | },
|
320 |
|
321 | backgrounding: function(){
|
322 | let cy = this.cy();
|
323 | if( !cy.styleEnabled() ){ return false; }
|
324 |
|
325 | let ele = this[0];
|
326 |
|
327 | return ele._private.backgrounding ? true : false;
|
328 | }
|
329 |
|
330 | });
|
331 |
|
332 | function checkCompound( ele, parentOk ){
|
333 | let _p = ele._private;
|
334 | let parents = _p.data.parent ? ele.parents() : null;
|
335 |
|
336 | if( parents ){ for( let i = 0; i < parents.length; i++ ){
|
337 | let parent = parents[ i ];
|
338 |
|
339 | if( !parentOk( parent ) ){ return false; }
|
340 | } }
|
341 |
|
342 | return true;
|
343 | }
|
344 |
|
345 | function defineDerivedStateFunction( specs ){
|
346 | let ok = specs.ok;
|
347 | let edgeOkViaNode = specs.edgeOkViaNode || specs.ok;
|
348 | let parentOk = specs.parentOk || specs.ok;
|
349 |
|
350 | return function(){
|
351 | let cy = this.cy();
|
352 | if( !cy.styleEnabled() ){ return true; }
|
353 |
|
354 | let ele = this[0];
|
355 | let hasCompoundNodes = cy.hasCompoundNodes();
|
356 |
|
357 | if( ele ){
|
358 | let _p = ele._private;
|
359 |
|
360 | if( !ok( ele ) ){ return false; }
|
361 |
|
362 | if( ele.isNode() ){
|
363 | return !hasCompoundNodes || checkCompound( ele, parentOk );
|
364 | } else {
|
365 | let src = _p.source;
|
366 | let tgt = _p.target;
|
367 |
|
368 | return ( edgeOkViaNode(src) && (!hasCompoundNodes || checkCompound(src, edgeOkViaNode)) ) &&
|
369 | ( src === tgt || ( edgeOkViaNode(tgt) && (!hasCompoundNodes || checkCompound(tgt, edgeOkViaNode)) ) );
|
370 | }
|
371 | }
|
372 | };
|
373 | }
|
374 |
|
375 | let eleTakesUpSpace = cacheStyleFunction( 'eleTakesUpSpace', function( ele ){
|
376 | return (
|
377 | ele.pstyle( 'display' ).value === 'element'
|
378 | && ele.width() !== 0
|
379 | && ( ele.isNode() ? ele.height() !== 0 : true )
|
380 | );
|
381 | } );
|
382 |
|
383 | elesfn.takesUpSpace = cachePrototypeStyleFunction( 'takesUpSpace', defineDerivedStateFunction({
|
384 | ok: eleTakesUpSpace
|
385 | }) );
|
386 |
|
387 | let eleInteractive = cacheStyleFunction( 'eleInteractive', function( ele ){
|
388 | return (
|
389 | ele.pstyle('events').value === 'yes'
|
390 | && ele.pstyle('visibility').value === 'visible'
|
391 | && eleTakesUpSpace( ele )
|
392 | );
|
393 | } );
|
394 |
|
395 | let parentInteractive = cacheStyleFunction( 'parentInteractive', function( parent ){
|
396 | return (
|
397 | parent.pstyle('visibility').value === 'visible'
|
398 | && eleTakesUpSpace( parent )
|
399 | );
|
400 | } );
|
401 |
|
402 | elesfn.interactive = cachePrototypeStyleFunction( 'interactive', defineDerivedStateFunction({
|
403 | ok: eleInteractive,
|
404 | parentOk: parentInteractive,
|
405 | edgeOkViaNode: eleTakesUpSpace
|
406 | }) );
|
407 |
|
408 | elesfn.noninteractive = function(){
|
409 | let ele = this[0];
|
410 |
|
411 | if( ele ){
|
412 | return !ele.interactive();
|
413 | }
|
414 | };
|
415 |
|
416 | let eleVisible = cacheStyleFunction( 'eleVisible', function( ele ){
|
417 | return (
|
418 | ele.pstyle( 'visibility' ).value === 'visible'
|
419 | && ele.pstyle( 'opacity' ).pfValue !== 0
|
420 | && eleTakesUpSpace( ele )
|
421 | );
|
422 | } );
|
423 |
|
424 | let edgeVisibleViaNode = eleTakesUpSpace;
|
425 |
|
426 | elesfn.visible = cachePrototypeStyleFunction( 'visible', defineDerivedStateFunction({
|
427 | ok: eleVisible,
|
428 | edgeOkViaNode: edgeVisibleViaNode
|
429 | }) );
|
430 |
|
431 | elesfn.hidden = function(){
|
432 | let ele = this[0];
|
433 |
|
434 | if( ele ){
|
435 | return !ele.visible();
|
436 | }
|
437 | };
|
438 |
|
439 | elesfn.isBundledBezier = cachePrototypeStyleFunction('isBundledBezier', function(){
|
440 | if( !this.cy().styleEnabled() ){ return false; }
|
441 |
|
442 | return !this.removed() && this.pstyle('curve-style').value === 'bezier' && this.takesUpSpace();
|
443 | });
|
444 |
|
445 | elesfn.bypass = elesfn.css = elesfn.style;
|
446 | elesfn.renderedCss = elesfn.renderedStyle;
|
447 | elesfn.removeBypass = elesfn.removeCss = elesfn.removeStyle;
|
448 | elesfn.pstyle = elesfn.parsedStyle;
|
449 |
|
450 | export default elesfn;
|