Listing & form

- improved Listing in order to make it more DRY
- form builder with all field types
- added support for data array in ValidModel->set()
- updated models to comply with Listing & Form methods
This commit is contained in:
Jonathan Labreuille
2015-09-14 19:07:41 +02:00
parent e471d45827
commit 79f1896cf3
19 changed files with 451 additions and 272 deletions

View File

@@ -3,17 +3,191 @@ define(
'react',
'mailpoet',
'classnames',
'react-router'
'react-router',
'react-checkbox-group'
],
function(
React,
MailPoet,
classNames,
Router
Router,
CheckboxGroup
) {
var FormFieldSelect = React.createClass({
render: function() {
var options =
Object.keys(this.props.field.values).map(function(value, index) {
return (
<option
key={ 'option-' + index }
value={ value }>
{ this.props.field.values[value] }
</option>
);
}.bind(this)
);
return (
<select
name={ this.props.field.name }
id={ 'field_'+this.props.field.name }
value={ this.props.item[this.props.field.name] }
onChange={ this.props.onValueChange } >
{options}
</select>
);
}
});
var FormFieldRadio = React.createClass({
render: function() {
var selected_value = this.props.item[this.props.field.name];
var count = Object.keys(this.props.field.values).length;
var options = Object.keys(this.props.field.values).map(
function(value, index) {
return (
<p key={ 'radio-' + index }>
<label>
<input
type="radio"
checked={ selected_value === value }
value={ value }
onChange={ this.props.onValueChange }
name={ this.props.field.name } />
&nbsp;{ this.props.field.values[value] }
</label>
</p>
);
}.bind(this)
);
return (
<div>
{ options }
</div>
);
}
});
var FormFieldCheckbox = React.createClass({
render: function() {
var selected_values = this.props.item[this.props.field.name] || '';
if(
selected_values !== undefined
&& selected_values.constructor !== Array
) {
selected_values = selected_values.split(';').map(function(value) {
return value.trim();
});
}
var count = Object.keys(this.props.field.values).length;
var options = Object.keys(this.props.field.values).map(
function(value, index) {
return (
<p key={ 'checkbox-' + index }>
<label>
<input type="checkbox" value={ value } />
&nbsp;{ this.props.field.values[value] }
</label>
</p>
);
}.bind(this)
);
return (
<CheckboxGroup
name={ this.props.field.name }
value={ selected_values }
ref={ this.props.field.name }
onChange={ this.handleValueChange }>
{ options }
</CheckboxGroup>
);
},
handleValueChange: function() {
var field = this.props.field.name;
var group = this.refs[field];
var selected_values = [];
if(group !== undefined) {
selected_values = group.getCheckedValues();
}
return this.props.onValueChange({
target: {
name: field,
value: selected_values.join(';')
}
});
}
});
var FormFieldText = React.createClass({
render: function() {
return (
<input
type="text"
className="regular-text"
name={ this.props.field.name }
id={ 'field_'+this.props.field.name }
value={ this.props.item[this.props.field.name] }
onChange={ this.props.onValueChange } />
);
}
});
var FormFieldTextarea = React.createClass({
render: function() {
return (
<textarea
type="text"
className="regular-text"
name={ this.props.field.name }
id={ 'field_'+this.props.field.name }
value={ this.props.item[this.props.field.name] }
onChange={ this.props.onValueChange } />
);
}
});
var FormField = React.createClass({
render: function() {
var description = false;
if(this.props.field.description) {
description = (
<p className="description">{ this.props.field.description }</p>
);
}
var field = false;
switch(this.props.field.type) {
case 'text':
field = (<FormFieldText {...this.props} />);
break;
case 'textarea':
field = (<FormFieldTextarea {...this.props} />);
break;
case 'select':
field = (<FormFieldSelect {...this.props} />);
break;
case 'radio':
field = (<FormFieldRadio {...this.props} />);
break;
case 'checkbox':
field = (<FormFieldCheckbox {...this.props} />);
break;
}
return (
<tr>
<th scope="row">
@@ -22,12 +196,8 @@ define(
>{ this.props.field.label }</label>
</th>
<td>
<input
type="text"
name={ this.props.field.name }
id={ 'field_'+this.props.field.name }
value={ this.props.item[this.props.field.name] }
onChange={ this.props.onValueChange } />
{ field }
{ description }
</td>
</tr>
);
@@ -66,7 +236,7 @@ define(
this.setState({ loading: true });
MailPoet.Ajax.post({
endpoint: 'subscribers',
endpoint: this.props.endpoint,
action: 'get',
data: { id: id }
}).done(function(response) {
@@ -91,7 +261,7 @@ define(
this.setState({ loading: true });
MailPoet.Ajax.post({
endpoint: 'subscribers',
endpoint: this.props.endpoint,
action: 'save',
data: this.state.item
}).done(function(response) {
@@ -100,19 +270,21 @@ define(
if(response === true) {
this.transitionTo('/');
if(this.props.params.id !== undefined) {
MailPoet.Notice.success('Subscriber succesfully updated!');
this.props.messages['updated']();
} else {
MailPoet.Notice.success('Subscriber succesfully added!');
this.props.messages['created']();
}
} else {
this.setState({ errors: response });
}
}.bind(this));
},
handleValueChange: function(e) {
var item = this.state.item;
item[e.target.name] = e.target.value;
var item = this.state.item,
field = e.target.name;
item[field] = e.target.value;
this.setState({
item: item
});
@@ -121,7 +293,9 @@ define(
render: function() {
var errors = this.state.errors.map(function(error, index) {
return (
<p key={'error-'+index} className="mailpoet_error">{ error }</p>
<p key={ 'error-'+index } className="mailpoet_error">
{ error }
</p>
);
});