@@ -13,7 +13,7 @@ import {
13
13
} from 'underscore' ;
14
14
import { shallowDiff , capitalize , isEmptyObj , isObject , toLowerCase } from '../../utils/mixins' ;
15
15
import StyleableModel , { StyleProps , UpdateStyleOptions } from '../../domain_abstract/model/StyleableModel' ;
16
- import { Model } from 'backbone' ;
16
+ import { Model , ModelDestroyOptions } from 'backbone' ;
17
17
import Components from './Components' ;
18
18
import Selector from '../../selector_manager/model/Selector' ;
19
19
import Selectors from '../../selector_manager/model/Selectors' ;
@@ -51,14 +51,17 @@ import {
51
51
updateSymbolComps ,
52
52
updateSymbolProps ,
53
53
} from './SymbolUtils' ;
54
- import TraitDataVariable from '../../data_sources/model/TraitDataVariable' ;
55
- import { ConditionalVariableType , DataCondition } from '../../data_sources/model/conditional_variables/DataCondition' ;
56
- import { isDynamicValue , isDynamicValueDefinition } from '../../data_sources/model/utils' ;
54
+ import { ComponentDynamicValueWatcher } from './ComponentDynamicValueWatcher' ;
55
+ import { DynamicValueWatcher } from './DynamicValueWatcher' ;
57
56
import { DynamicValueDefinition } from '../../data_sources/types' ;
58
57
59
58
export interface IComponent extends ExtractMethods < Component > { }
60
-
61
- export interface SetAttrOptions extends SetOptions , UpdateStyleOptions { }
59
+ export interface DynamicWatchersOptions {
60
+ skipWatcherUpdates ?: boolean ;
61
+ fromDataSource ?: boolean ;
62
+ }
63
+ export interface SetAttrOptions extends SetOptions , UpdateStyleOptions , DynamicWatchersOptions { }
64
+ export interface ComponentSetOptions extends SetOptions , DynamicWatchersOptions { }
62
65
63
66
const escapeRegExp = ( str : string ) => {
64
67
return str . replace ( / [ | \\ { } ( ) [ \] ^ $ + * ? . ] / g, '\\$&' ) ;
@@ -72,7 +75,6 @@ export const keySymbol = '__symbol';
72
75
export const keySymbolOvrd = '__symbol_ovrd' ;
73
76
export const keyUpdate = ComponentsEvents . update ;
74
77
export const keyUpdateInside = ComponentsEvents . updateInside ;
75
- export const dynamicAttrKey = 'attributes-dynamic-value' ;
76
78
77
79
/**
78
80
* The Component object represents a single node of our template structure, so when you update its properties the changes are
@@ -260,9 +262,13 @@ export default class Component extends StyleableModel<ComponentProperties> {
260
262
* @private
261
263
* @ts -ignore */
262
264
collection ! : Components ;
265
+ componentDVListener : ComponentDynamicValueWatcher ;
263
266
264
267
constructor ( props : ComponentProperties = { } , opt : ComponentOptions ) {
265
268
super ( props , opt ) ;
269
+ this . componentDVListener = new ComponentDynamicValueWatcher ( this , opt . em ) ;
270
+ this . componentDVListener . addProps ( props ) ;
271
+
266
272
bindAll ( this , '__upSymbProps' , '__upSymbCls' , '__upSymbComps' ) ;
267
273
const em = opt . em ;
268
274
@@ -289,7 +295,7 @@ export default class Component extends StyleableModel<ComponentProperties> {
289
295
this . opt = opt ;
290
296
this . em = em ! ;
291
297
this . config = opt . config || { } ;
292
- this . set ( 'attributes' , {
298
+ this . setAttributes ( {
293
299
...( result ( this , 'defaults' ) . attributes || { } ) ,
294
300
...( this . get ( 'attributes' ) || { } ) ,
295
301
} ) ;
@@ -331,6 +337,36 @@ export default class Component extends StyleableModel<ComponentProperties> {
331
337
}
332
338
}
333
339
340
+ set < A extends string > (
341
+ keyOrAttributes : A | Partial < ComponentProperties > ,
342
+ valueOrOptions ?: ComponentProperties [ A ] | ComponentSetOptions ,
343
+ optionsOrUndefined ?: ComponentSetOptions ,
344
+ ) : this {
345
+ let attributes : Partial < ComponentProperties > ;
346
+ let options : ComponentSetOptions = { skipWatcherUpdates : false , fromDataSource : false } ;
347
+ if ( typeof keyOrAttributes === 'object' ) {
348
+ attributes = keyOrAttributes ;
349
+ options = valueOrOptions || ( options as ComponentSetOptions ) ;
350
+ } else if ( typeof keyOrAttributes === 'string' ) {
351
+ attributes = { [ keyOrAttributes as string ] : valueOrOptions } ;
352
+ options = optionsOrUndefined || options ;
353
+ } else {
354
+ attributes = { } ;
355
+ options = optionsOrUndefined || options ;
356
+ }
357
+
358
+ // @ts -ignore
359
+ const em = this . em || options . em ;
360
+ const evaluatedAttributes = DynamicValueWatcher . getStaticValues ( attributes , em ) ;
361
+
362
+ const shouldSkipWatcherUpdates = options . skipWatcherUpdates || options . fromDataSource ;
363
+ if ( ! shouldSkipWatcherUpdates ) {
364
+ this . componentDVListener ?. addProps ( attributes ) ;
365
+ }
366
+
367
+ return super . set ( evaluatedAttributes , options ) ;
368
+ }
369
+
334
370
__postAdd ( opts : { recursive ?: boolean } = { } ) {
335
371
const { em } = this ;
336
372
const um = em ?. UndoManager ;
@@ -648,8 +684,16 @@ export default class Component extends StyleableModel<ComponentProperties> {
648
684
* @example
649
685
* component.setAttributes({ id: 'test', 'data-key': 'value' });
650
686
*/
651
- setAttributes ( attrs : ObjectAny , opts : SetAttrOptions = { } ) {
652
- this . set ( 'attributes' , { ...attrs } , opts ) ;
687
+ setAttributes ( attrs : ObjectAny , opts : SetAttrOptions = { skipWatcherUpdates : false , fromDataSource : false } ) {
688
+ // @ts -ignore
689
+ const em = this . em || opts . em ;
690
+ const evaluatedAttributes = DynamicValueWatcher . getStaticValues ( attrs , em ) ;
691
+ const shouldSkipWatcherUpdates = opts . skipWatcherUpdates || opts . fromDataSource ;
692
+ if ( ! shouldSkipWatcherUpdates ) {
693
+ this . componentDVListener . setAttributes ( attrs ) ;
694
+ }
695
+ this . set ( 'attributes' , { ...evaluatedAttributes } , opts ) ;
696
+
653
697
return this ;
654
698
}
655
699
@@ -662,9 +706,11 @@ export default class Component extends StyleableModel<ComponentProperties> {
662
706
* component.addAttributes({ 'data-key': 'value' });
663
707
*/
664
708
addAttributes ( attrs : ObjectAny , opts : SetAttrOptions = { } ) {
709
+ const dynamicAttributes = this . componentDVListener . getDynamicAttributesDefs ( ) ;
665
710
return this . setAttributes (
666
711
{
667
712
...this . getAttributes ( { noClass : true } ) ,
713
+ ...dynamicAttributes ,
668
714
...attrs ,
669
715
} ,
670
716
opts ,
@@ -682,6 +728,8 @@ export default class Component extends StyleableModel<ComponentProperties> {
682
728
*/
683
729
removeAttributes ( attrs : string | string [ ] = [ ] , opts : SetOptions = { } ) {
684
730
const attrArr = Array . isArray ( attrs ) ? attrs : [ attrs ] ;
731
+ this . componentDVListener . removeAttributes ( attrArr ) ;
732
+
685
733
const compAttr = this . getAttributes ( ) ;
686
734
attrArr . map ( ( i ) => delete compAttr [ i ] ) ;
687
735
return this . setAttributes ( compAttr , opts ) ;
@@ -773,29 +821,6 @@ export default class Component extends StyleableModel<ComponentProperties> {
773
821
}
774
822
}
775
823
776
- const attrDataVariable = this . get ( dynamicAttrKey ) as {
777
- [ key : string ] : TraitDataVariable | DynamicValueDefinition ;
778
- } ;
779
- if ( attrDataVariable ) {
780
- Object . entries ( attrDataVariable ) . forEach ( ( [ key , value ] ) => {
781
- let dataVariable : TraitDataVariable | DataCondition ;
782
- if ( isDynamicValue ( value ) ) {
783
- dataVariable = value ;
784
- } else if ( isDynamicValueDefinition ( value ) ) {
785
- const type = value . type ;
786
-
787
- if ( type === ConditionalVariableType ) {
788
- const { condition, ifTrue, ifFalse } = value ;
789
- dataVariable = new DataCondition ( condition , ifTrue , ifFalse , { em } ) ;
790
- } else {
791
- dataVariable = new TraitDataVariable ( value , { em } ) ;
792
- }
793
- }
794
-
795
- attributes [ key ] = dataVariable ! . getDataValue ( ) ;
796
- } ) ;
797
- }
798
-
799
824
// Check if we need an ID on the component
800
825
if ( ! has ( attributes , 'id' ) ) {
801
826
let addId = false ;
@@ -934,7 +959,6 @@ export default class Component extends StyleableModel<ComponentProperties> {
934
959
this . off ( event , this . initTraits ) ;
935
960
this . __loadTraits ( ) ;
936
961
const attrs = { ...this . get ( 'attributes' ) } ;
937
- const traitDynamicValueAttr : ObjectAny = { } ;
938
962
const traits = this . traits ;
939
963
traits . each ( ( trait ) => {
940
964
const name = trait . getName ( ) ;
@@ -945,13 +969,13 @@ export default class Component extends StyleableModel<ComponentProperties> {
945
969
} else {
946
970
if ( name && value ) attrs [ name ] = value ;
947
971
}
948
-
949
- if ( trait . dynamicVariable ) {
950
- traitDynamicValueAttr [ name ] = trait . dynamicVariable ;
951
- }
952
972
} ) ;
953
- traits . length && this . set ( 'attributes' , attrs ) ;
954
- Object . keys ( traitDynamicValueAttr ) . length && this . set ( dynamicAttrKey , traitDynamicValueAttr ) ;
973
+ const dynamicAttributes = this . componentDVListener . getDynamicAttributesDefs ( ) ;
974
+ traits . length &&
975
+ this . setAttributes ( {
976
+ ...attrs ,
977
+ ...dynamicAttributes ,
978
+ } ) ;
955
979
this . on ( event , this . initTraits ) ;
956
980
changed && em && em . trigger ( 'component:toggled' ) ;
957
981
return this ;
@@ -1147,7 +1171,6 @@ export default class Component extends StyleableModel<ComponentProperties> {
1147
1171
traits . setTarget ( this ) ;
1148
1172
1149
1173
if ( traitsI . length ) {
1150
- traitsI . forEach ( ( tr ) => tr . attributes && delete tr . attributes . value ) ;
1151
1174
traits . add ( traitsI ) ;
1152
1175
}
1153
1176
@@ -1294,12 +1317,15 @@ export default class Component extends StyleableModel<ComponentProperties> {
1294
1317
* @ts -ignore */
1295
1318
clone ( opt : { symbol ?: boolean ; symbolInv ?: boolean } = { } ) : this {
1296
1319
const em = this . em ;
1297
- const attr = { ...this . attributes } ;
1320
+ const attr = {
1321
+ ...this . componentDVListener . getPropsDefsOrValues ( this . attributes ) ,
1322
+ } ;
1298
1323
const opts = { ...this . opt } ;
1299
1324
const id = this . getId ( ) ;
1300
1325
const cssc = em ?. Css ;
1301
- attr . attributes = { ...attr . attributes } ;
1302
- delete attr . attributes . id ;
1326
+ attr . attributes = {
1327
+ ...( attr . attributes ? this . componentDVListener . getAttributesDefsOrValues ( attr . attributes ) : undefined ) ,
1328
+ } ;
1303
1329
// @ts -ignore
1304
1330
attr . components = [ ] ;
1305
1331
// @ts -ignore
@@ -1554,8 +1580,10 @@ export default class Component extends StyleableModel<ComponentProperties> {
1554
1580
* @private
1555
1581
*/
1556
1582
toJSON ( opts : ObjectAny = { } ) : ComponentDefinition {
1557
- const obj = Model . prototype . toJSON . call ( this , opts ) ;
1558
- obj . attributes = this . getAttributes ( ) ;
1583
+ let obj = Model . prototype . toJSON . call ( this , opts ) ;
1584
+ obj = { ...obj , ...this . componentDVListener . getDynamicPropsDefs ( ) } ;
1585
+ obj . attributes = this . componentDVListener . getAttributesDefsOrValues ( this . getAttributes ( ) ) ;
1586
+ delete obj . componentDVListener ;
1559
1587
delete obj . attributes . class ;
1560
1588
delete obj . toolbar ;
1561
1589
delete obj . traits ;
@@ -1789,6 +1817,11 @@ export default class Component extends StyleableModel<ComponentProperties> {
1789
1817
return this ;
1790
1818
}
1791
1819
1820
+ destroy ( options ?: ModelDestroyOptions | undefined ) : false | JQueryXHR {
1821
+ this . componentDVListener . destroy ( ) ;
1822
+ return super . destroy ( options ) ;
1823
+ }
1824
+
1792
1825
/**
1793
1826
* Move the component to another destination component
1794
1827
* @param {Component } component Destination component (so the current one will be appended as a child)
0 commit comments