From 8bdc251445fcabab98c24168f1ee1246f0ca33c7 Mon Sep 17 00:00:00 2001 From: Vlad Balin Date: Wed, 6 Jan 2016 17:15:56 -0500 Subject: [PATCH 1/3] added sketch for cdocorator --- src/decorator.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/decorator.js diff --git a/src/decorator.js b/src/decorator.js new file mode 100644 index 0000000..65c9d9c --- /dev/null +++ b/src/decorator.js @@ -0,0 +1,53 @@ + + +Object.extend.attach( React.Component ); +Object.assign( React.Component, Events ); + +React.Component.extend({ + Model : null, + autobind : null, + + constructor: function( props ){ + React.Component.call( this, props ); + + if( this.Model ){ + this.state = new this.Model(); + } + + var autobind = this.autobind; + if( autobind ){ + for( var i = 0; i < autobind.length; i++ ){ + var name = autobind[ i ], + fun = this[ name ]; + + if( fun ){ + this[ name ] = fun.bind( this ); + } + } + } + } +}); + +React.define = function( options ){ + return function( Class ){ + var spec = {}; + + if( options.props ){ + var propSpec = parseProps( options.props ); + Class.propTypes = propSpec.propTypes; + Class.defaultProps = propSpec.defaultProps; + } + + if( options.autobind ){ + spec.autobind = options.autobind.split( /\s+/ ); + } + + + var mixins = options.mixins || []; + if( options.state ){ + mixins.push( StateMixin ); + } + + attachMixins( Class.prototype, mixins ); + } +}; \ No newline at end of file From a5d1d0aab0f64816dc0ae7a701131730ecf221d8 Mon Sep 17 00:00:00 2001 From: Vlad Balin Date: Wed, 6 Jan 2016 18:20:00 -0500 Subject: [PATCH 2/3] added type information extraction --- src/decorator.js | 52 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/src/decorator.js b/src/decorator.js index 65c9d9c..78e25b6 100644 --- a/src/decorator.js +++ b/src/decorator.js @@ -1,13 +1,14 @@ - +var React = require( 'react' ), + Nested = require( 'nestedtypes' ); Object.extend.attach( React.Component ); Object.assign( React.Component, Events ); -React.Component.extend({ - Model : null, +React.Component.extend( { + Model : null, autobind : null, - constructor: function( props ){ + constructor : function( props ){ React.Component.call( this, props ); if( this.Model ){ @@ -18,7 +19,7 @@ React.Component.extend({ if( autobind ){ for( var i = 0; i < autobind.length; i++ ){ var name = autobind[ i ], - fun = this[ name ]; + fun = this[ name ]; if( fun ){ this[ name ] = fun.bind( this ); @@ -26,15 +27,50 @@ React.Component.extend({ } } } -}); +} ); + +function convertType( Type ){ + switch( Type ){ + case String : + return PropTypes.string; + case Number : + return PropTypes.number; + case Integer : + return PropTypes.number; + case Boolean : + return PropTypes.bool; + case Function : + return PropTypes.func; + case Array : + return PropTypes.array; + case Object : + return PropTypes.object; + default : + return Type.prototype ? PropTypes.instanceOf( Type ) : Type; + } +} + +function parseProps( spec ){ + var PropsModel = Model.defaults( spec ), + propTypes = {}, + defaultProps = {}; + + PropsModel.prototype.forEachAttr( PropsModel.prototype.__attributes, function( spec, name ){ + if( spec.value ){ + defaultProps[ name ] = spec.value; + } + + propTypes[ name ] = convertType( spec.type ); + } ); +} React.define = function( options ){ return function( Class ){ var spec = {}; if( options.props ){ - var propSpec = parseProps( options.props ); - Class.propTypes = propSpec.propTypes; + var propSpec = parseProps( options.props ); + Class.propTypes = propSpec.propTypes; Class.defaultProps = propSpec.defaultProps; } From 0fc1c3529dc89b6a63be61935c39c4fcc03024af Mon Sep 17 00:00:00 2001 From: Vlad Balin Date: Mon, 15 Feb 2016 15:35:13 -0500 Subject: [PATCH 3/3] es6 sketches --- src/createClass.js | 2 +- src/decorator.js | 76 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/src/createClass.js b/src/createClass.js index 5a37fad..fafc8aa 100644 --- a/src/createClass.js +++ b/src/createClass.js @@ -47,7 +47,7 @@ var ModelState = { // reference global store to fix model's store locator getStore : function(){ - this.model._defaultStore; + return this.model._defaultStore; }, componentDidMount : function(){ diff --git a/src/decorator.js b/src/decorator.js index 78e25b6..57f062a 100644 --- a/src/decorator.js +++ b/src/decorator.js @@ -1,18 +1,31 @@ +/** + * ES6 class Decorator, design based on base class + * (trying to manage without mixins). + * + * TODO: What to do with inheritance? + * - state: extend attributes? Common sense tells us we need to inherit model. + * - props: inherit props? Likely, we need it too. + * Ok, so we inherit both props and state attributes. + * Both cases will be handled by model inheritance. + */ + var React = require( 'react' ), Nested = require( 'nestedtypes' ); Object.extend.attach( React.Component ); -Object.assign( React.Component, Events ); +Object.assign( React.Component.prototype, Events ); -React.Component.extend( { +var Component = React.Component.extend( { Model : null, autobind : null, + listenToProps : null, constructor : function( props ){ React.Component.call( this, props ); if( this.Model ){ - this.state = new this.Model(); + this.state = this.model = new this.Model(); + this.model._owner = this; } var autobind = this.autobind; @@ -26,6 +39,63 @@ React.Component.extend( { } } } + }, + + getStore : function(){ + return this.model._defaultStore; + }, + + componentWillReceiveProps : function( nextProps ){ + var updateOn = this.listenToProps; + + // if there are any subscription to prop changes, + // make sure that it's up to date. + if( updateOn ){ + var props = this.props; + + for( var i = 0; i < updateOn.length; i++ ){ + var name = updateOn[ i ], + prev = props[ name ], + next = nextProps[ name ]; + + if( prev !== next ){ + prev && this.stopListening( prev ); + next && this.listenTo( next, next.triggerWhenChanged, forceUpdate ); + } + } + } + }, + + componentDidMount : function(){ + var model = this.model, + updateOn = this.listenToProps; + + // If component has state, subscribe for state changes... + // Likely it has, otherwise stateless component will be used. + if( model ){ + this.listenTo( model, 'change', forceUpdate ); + } + + // If we're watching for prop changes, take care. + if( updateOn ){ + var props = this.props; + + for( var i = 0; i < updateOn.length; i++ ){ + var emitter = props[ updateOn[ i ] ]; + emitter && this.listenTo( emitter, emitter.triggerWhenChanged, forceUpdate ); + } + } + }, + + componentWillUnmount : function(){ + // remove owner from the model... + var model = this.model; + model && ( model._owner = null ); + + //TODO: Should I call dispose to our state? + + // unsubscribe from all events... + this.stopListening(); } } );