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