mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
AddToCampaign save message, Submitting indicator on FormAction button
This commit is contained in:
parent
d7663e850e
commit
b9624994ac
2
admin/client/dist/js/AddToCampaignForm.js
vendored
2
admin/client/dist/js/AddToCampaignForm.js
vendored
@ -22,7 +22,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
_jQuery2.default.entwine('ss', function ($) {
|
_jQuery2.default.entwine('ss', function ($) {
|
||||||
$('.add-to-campaign-action, #add-to-campaign__action').entwine({
|
$('#add-to-campaign__dialog .add-to-campaign-action,' + '.cms-content-actions .add-to-campaign-action,' + '#add-to-campaign__action').entwine({
|
||||||
onclick: function onclick() {
|
onclick: function onclick() {
|
||||||
var dialog = $('#add-to-campaign__dialog');
|
var dialog = $('#add-to-campaign__dialog');
|
||||||
|
|
||||||
|
@ -2,24 +2,47 @@ import React from 'react';
|
|||||||
import { Modal } from 'react-bootstrap-4';
|
import { Modal } from 'react-bootstrap-4';
|
||||||
import SilverStripeComponent from 'lib/SilverStripeComponent';
|
import SilverStripeComponent from 'lib/SilverStripeComponent';
|
||||||
import FormBuilder from 'components/FormBuilder/FormBuilder';
|
import FormBuilder from 'components/FormBuilder/FormBuilder';
|
||||||
import Config from 'lib/Config';
|
|
||||||
|
|
||||||
class AddToCampaignModal extends SilverStripeComponent {
|
class AddToCampaignModal extends SilverStripeComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.handleSubmit = this.handleSubmit.bind(this);
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
response: null,
|
||||||
|
error: false,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(event, fieldValues, submitFn) {
|
handleSubmit(event, fieldValues, submitFn) {
|
||||||
|
let promise = null;
|
||||||
if (typeof this.props.handleSubmit === 'function') {
|
if (typeof this.props.handleSubmit === 'function') {
|
||||||
this.props.handleSubmit(event, fieldValues, submitFn);
|
promise = this.props.handleSubmit(event, fieldValues, submitFn);
|
||||||
return;
|
} else {
|
||||||
|
event.preventDefault();
|
||||||
|
promise = submitFn();
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
if (promise) {
|
||||||
submitFn();
|
promise
|
||||||
|
.then((response) => {
|
||||||
|
// show response
|
||||||
|
if (typeof response === 'string' || response.response.ok) {
|
||||||
|
this.setState({
|
||||||
|
response,
|
||||||
|
error: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
response: `${response.name}: ${response.message}`,
|
||||||
|
error: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
getBody() {
|
getBody() {
|
||||||
@ -28,25 +51,60 @@ class AddToCampaignModal extends SilverStripeComponent {
|
|||||||
return <FormBuilder schemaUrl={schemaUrl} handleSubmit={this.handleSubmit} />;
|
return <FormBuilder schemaUrl={schemaUrl} handleSubmit={this.handleSubmit} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getResponse() {
|
||||||
|
if (!this.state.response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let className = 'add-to-campaign__response';
|
||||||
|
|
||||||
|
if (this.state.error) {
|
||||||
|
className += ' add-to-campaign__response--error';
|
||||||
|
} else {
|
||||||
|
className += ' add-to-campaign__response--good';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
<span>{this.state.response}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearResponse() {
|
||||||
|
// TODO to be used with "Try again" and other options later
|
||||||
|
this.setState({
|
||||||
|
response: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const body = this.getBody();
|
const body = this.getBody();
|
||||||
|
const response = this.getResponse();
|
||||||
|
|
||||||
return <Modal show={this.props.show} onHide={this.props.handleHide} container={document.getElementsByClassName('cms-container')[0]}>
|
return (
|
||||||
<Modal.Header closeButton>
|
<Modal
|
||||||
<Modal.Title>{this.props.title + ' - Test'}</Modal.Title>
|
show={this.props.show}
|
||||||
</Modal.Header>
|
onHide={this.props.handleHide}
|
||||||
<Modal.Body>
|
container={document.getElementsByClassName('cms-container')[0]}
|
||||||
{body}
|
>
|
||||||
</Modal.Body>
|
<Modal.Header closeButton>
|
||||||
</Modal>;
|
<Modal.Title>{this.props.title}</Modal.Title>
|
||||||
|
</Modal.Header>
|
||||||
|
<Modal.Body>
|
||||||
|
{body}
|
||||||
|
{response}
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddToCampaignModal.propTypes = {
|
AddToCampaignModal.propTypes = {
|
||||||
show: React.PropTypes.bool.isRequired,
|
show: React.PropTypes.bool.isRequired,
|
||||||
title: React.PropTypes.string,
|
title: React.PropTypes.string,
|
||||||
handleHide: React.PropTypes.func,
|
handleHide: React.PropTypes.func,
|
||||||
schemaUrl: React.PropTypes.string,
|
schemaUrl: React.PropTypes.string,
|
||||||
handleSubmit: React.PropTypes.func,
|
handleSubmit: React.PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
/* global jest, describe, beforeEach, it, expect */
|
||||||
|
|
||||||
|
jest.unmock('react');
|
||||||
|
jest.unmock('react-addons-test-utils');
|
||||||
|
jest.unmock('../AddToCampaignModal');
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import ReactTestUtils from 'react-addons-test-utils';
|
||||||
|
import AddToCampaignModal from '../AddToCampaignModal';
|
||||||
|
|
||||||
|
describe('AddToCampaignModal', () => {
|
||||||
|
let props;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
props = {
|
||||||
|
title: '',
|
||||||
|
show: false,
|
||||||
|
handleHide: jest.genMockFunction(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getResponse()', () => {
|
||||||
|
let addToCampaignModal;
|
||||||
|
let response;
|
||||||
|
let message;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
addToCampaignModal = ReactTestUtils.renderIntoDocument(
|
||||||
|
<AddToCampaignModal {...props} />
|
||||||
|
);
|
||||||
|
response = addToCampaignModal.getResponse();
|
||||||
|
message = 'My message';
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show no response initially', () => {
|
||||||
|
expect(response).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show error message', () => {
|
||||||
|
message = 'This is an error';
|
||||||
|
|
||||||
|
addToCampaignModal.state = {
|
||||||
|
response: message,
|
||||||
|
error: true,
|
||||||
|
};
|
||||||
|
const responseDom = ReactTestUtils.renderIntoDocument(addToCampaignModal.getResponse());
|
||||||
|
expect(responseDom.classList.contains('add-to-campaign__response--error')).toBe(true);
|
||||||
|
expect(responseDom.textContent).toBe(message);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show success message', () => {
|
||||||
|
message = 'This is a success';
|
||||||
|
|
||||||
|
addToCampaignModal.state = {
|
||||||
|
response: message,
|
||||||
|
error: false,
|
||||||
|
};
|
||||||
|
const responseDom = ReactTestUtils.renderIntoDocument(addToCampaignModal.getResponse());
|
||||||
|
expect(responseDom.classList.contains('add-to-campaign__response--good')).toBe(true);
|
||||||
|
expect(responseDom.textContent).toBe(message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -44,9 +44,9 @@ class FormAction extends SilverStripeComponent {
|
|||||||
const buttonClasses = ['btn'];
|
const buttonClasses = ['btn'];
|
||||||
|
|
||||||
// Add 'type' class
|
// Add 'type' class
|
||||||
const bootstrapStyle = this.getBootstrapButtonStyle();
|
const style = this.getButtonStyle();
|
||||||
if (bootstrapStyle) {
|
if (style) {
|
||||||
buttonClasses.push(`btn-${bootstrapStyle}`);
|
buttonClasses.push(`btn-${style}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is no text
|
// If there is no text
|
||||||
@ -82,13 +82,22 @@ class FormAction extends SilverStripeComponent {
|
|||||||
*
|
*
|
||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
getBootstrapButtonStyle() {
|
getButtonStyle() {
|
||||||
// Add 'type' class
|
// Add 'type' class
|
||||||
if (typeof this.props.bootstrapButtonStyle !== 'undefined') {
|
if (typeof this.props.data.buttonStyle !== 'undefined') {
|
||||||
return this.props.bootstrapButtonStyle;
|
return this.props.data.buttonStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.name === 'action_save') {
|
const extraClasses = this.props.extraClass.split(' ');
|
||||||
|
|
||||||
|
// defined their own `btn-${something}` class
|
||||||
|
if (extraClasses.find((className) => className.indexOf('btn-') > -1)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.name === 'action_save' ||
|
||||||
|
extraClasses.find((className) => className === 'ss-ui-action-constructive')
|
||||||
|
) {
|
||||||
return 'primary';
|
return 'primary';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,9 +143,7 @@ class FormAction extends SilverStripeComponent {
|
|||||||
if (typeof this.props.handleClick === 'function') {
|
if (typeof this.props.handleClick === 'function') {
|
||||||
this.props.handleClick(event, this.props.name || this.props.id);
|
this.props.handleClick(event, this.props.name || this.props.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FormAction.propTypes = {
|
FormAction.propTypes = {
|
||||||
@ -148,7 +155,12 @@ FormAction.propTypes = {
|
|||||||
loading: React.PropTypes.bool,
|
loading: React.PropTypes.bool,
|
||||||
icon: React.PropTypes.string,
|
icon: React.PropTypes.string,
|
||||||
disabled: React.PropTypes.bool,
|
disabled: React.PropTypes.bool,
|
||||||
bootstrapButtonStyle: React.PropTypes.string,
|
data: React.PropTypes.oneOfType([
|
||||||
|
React.PropTypes.array,
|
||||||
|
React.PropTypes.shape({
|
||||||
|
buttonStyle: React.PropTypes.string,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
extraClass: React.PropTypes.string,
|
extraClass: React.PropTypes.string,
|
||||||
attributes: React.PropTypes.object,
|
attributes: React.PropTypes.object,
|
||||||
};
|
};
|
||||||
@ -156,6 +168,7 @@ FormAction.propTypes = {
|
|||||||
FormAction.defaultProps = {
|
FormAction.defaultProps = {
|
||||||
title: '',
|
title: '',
|
||||||
icon: '',
|
icon: '',
|
||||||
|
extraClass: '',
|
||||||
attributes: {},
|
attributes: {},
|
||||||
data: {},
|
data: {},
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
@ -172,9 +172,10 @@ export class FormBuilderComponent extends SilverStripeComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAction(event, name) {
|
handleAction(event, submitAction) {
|
||||||
|
this.props.formActions.setSubmitAction(this.getFormId(), submitAction);
|
||||||
if (typeof this.props.handleAction === 'function') {
|
if (typeof this.props.handleAction === 'function') {
|
||||||
this.props.handleAction(event, name);
|
this.props.handleAction(event, submitAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,12 +228,11 @@ export class FormBuilderComponent extends SilverStripeComponent {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (typeof this.props.handleSubmit !== 'undefined') {
|
if (typeof this.props.handleSubmit !== 'undefined') {
|
||||||
this.props.handleSubmit(event, fieldValues, submitFn);
|
return this.props.handleSubmit(event, fieldValues, submitFn);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
submitFn();
|
return submitFn();
|
||||||
}
|
}
|
||||||
|
|
||||||
buildComponent(field, extraProps = {}) {
|
buildComponent(field, extraProps = {}) {
|
||||||
@ -288,9 +288,16 @@ export class FormBuilderComponent extends SilverStripeComponent {
|
|||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
mapActionsToComponents(actions) {
|
mapActionsToComponents(actions) {
|
||||||
|
const form = this.props.form[this.getFormId()];
|
||||||
|
|
||||||
return actions.map((action) => {
|
return actions.map((action) => {
|
||||||
|
const loading = (form && form.submitting && form.submitAction === action.name);
|
||||||
// Events
|
// Events
|
||||||
const extraProps = { handleClick: this.handleAction };
|
const extraProps = {
|
||||||
|
handleClick: this.handleAction,
|
||||||
|
loading,
|
||||||
|
disabled: loading || action.disabled,
|
||||||
|
};
|
||||||
|
|
||||||
// Build child nodes
|
// Build child nodes
|
||||||
if (action.children) {
|
if (action.children) {
|
||||||
|
@ -4,10 +4,6 @@ Generates a `<select><option></option></select>`
|
|||||||
|
|
||||||
## Props
|
## Props
|
||||||
|
|
||||||
### leftTitle
|
|
||||||
|
|
||||||
The label text to display with the field.
|
|
||||||
|
|
||||||
### extraClass
|
### extraClass
|
||||||
|
|
||||||
Addition CSS classes to apply to the `<select>` element.
|
Addition CSS classes to apply to the `<select>` element.
|
||||||
@ -22,20 +18,32 @@ Handler function called when the field's value changes.
|
|||||||
|
|
||||||
### value
|
### value
|
||||||
|
|
||||||
The field's value.
|
The field's selected value.
|
||||||
|
|
||||||
### source (required)
|
### source (required)
|
||||||
|
|
||||||
The list of possible values that could be selected
|
The list of possible values that could be selected
|
||||||
|
|
||||||
### disabled
|
#### value
|
||||||
|
|
||||||
A list of values within `source` that can be seen but not selected
|
The value for this option.
|
||||||
|
|
||||||
### hasEmptyDefault
|
#### title
|
||||||
|
|
||||||
|
The title or label displayed for users.
|
||||||
|
|
||||||
|
#### disabled
|
||||||
|
|
||||||
|
This option is shown but disabled from being selected.
|
||||||
|
|
||||||
|
### data
|
||||||
|
|
||||||
|
Additional field specific data
|
||||||
|
|
||||||
|
#### hasEmptyDefault
|
||||||
|
|
||||||
If true, create an empty value option first
|
If true, create an empty value option first
|
||||||
|
|
||||||
### emptyString
|
#### emptyString
|
||||||
|
|
||||||
When `hasEmptyDefault` is true, this sets the label for the option
|
When `hasEmptyDefault` is true, this sets the label for the option
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SilverStripeComponent from 'lib/SilverStripeComponent';
|
import SilverStripeComponent from 'lib/SilverStripeComponent';
|
||||||
|
//import fieldHolder from 'components/FieldHolder/FieldHolder';
|
||||||
|
import i18n from 'i18n';
|
||||||
|
|
||||||
class SingleSelectField extends SilverStripeComponent {
|
class SingleSelectField extends SilverStripeComponent {
|
||||||
|
|
||||||
@ -10,10 +12,6 @@ class SingleSelectField extends SilverStripeComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const labelText = this.props.leftTitle !== null
|
|
||||||
? this.props.leftTitle
|
|
||||||
: this.props.title;
|
|
||||||
|
|
||||||
let field = null;
|
let field = null;
|
||||||
if (this.props.readOnly) {
|
if (this.props.readOnly) {
|
||||||
field = this.getReadonlyField;
|
field = this.getReadonlyField;
|
||||||
@ -21,22 +19,7 @@ class SingleSelectField extends SilverStripeComponent {
|
|||||||
field = this.getSelectField();
|
field = this.getSelectField();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The extraClass property is defined on both the holder and element
|
return field;
|
||||||
// for legacy reasons (same behaviour as PHP rendering)
|
|
||||||
const classNames = ['form-group', this.props.extraClass].join(' ');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNames}>
|
|
||||||
{labelText &&
|
|
||||||
<label className="form__field-label" htmlFor={`gallery_${this.props.name}`}>
|
|
||||||
{labelText}
|
|
||||||
</label>
|
|
||||||
}
|
|
||||||
<div className="form__field-holder">
|
|
||||||
{field}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,9 +28,9 @@ class SingleSelectField extends SilverStripeComponent {
|
|||||||
* @returns ReactComponent
|
* @returns ReactComponent
|
||||||
*/
|
*/
|
||||||
getReadonlyField() {
|
getReadonlyField() {
|
||||||
let label = this.props.source[this.props.value];
|
let label = this.props.source.find((item) => item.value === this.props.value);
|
||||||
|
|
||||||
label = label !== null
|
label = label !== undefined
|
||||||
? label
|
? label
|
||||||
: this.props.value;
|
: this.props.value;
|
||||||
|
|
||||||
@ -65,16 +48,23 @@ class SingleSelectField extends SilverStripeComponent {
|
|||||||
if (this.props.hasEmptyDefault) {
|
if (this.props.hasEmptyDefault) {
|
||||||
options.unshift({
|
options.unshift({
|
||||||
value: '',
|
value: '',
|
||||||
title: this.props.emptyString
|
title: this.props.emptyString,
|
||||||
|
disabled: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return <select {...this.getInputProps()}>
|
return (
|
||||||
{ options.map((item) => {
|
<select {...this.getInputProps()}>
|
||||||
const key = `${this.props.name}-${item.value || 'null'}`;
|
{ options.map((item) => {
|
||||||
|
const key = `${this.props.name}-${item.value || 'null'}`;
|
||||||
|
|
||||||
return <option key={key} value={item.value} disabled={item.disabled}>{item.title}</option>;
|
return (
|
||||||
}) }
|
<option key={key} value={item.value} disabled={item.disabled}>
|
||||||
</select>;
|
{item.title}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}) }
|
||||||
|
</select>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,10 +77,10 @@ class SingleSelectField extends SilverStripeComponent {
|
|||||||
// The extraClass property is defined on both the holder and element
|
// The extraClass property is defined on both the holder and element
|
||||||
// for legacy reasons (same behaviour as PHP rendering)
|
// for legacy reasons (same behaviour as PHP rendering)
|
||||||
className: ['form-control', this.props.extraClass].join(' '),
|
className: ['form-control', this.props.extraClass].join(' '),
|
||||||
id: this.props.id,
|
id: this.props.id,
|
||||||
name: this.props.name,
|
name: this.props.name,
|
||||||
onChange: this.handleChange,
|
onChange: this.handleChange,
|
||||||
value: this.props.value,
|
value: this.props.value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,25 +94,23 @@ class SingleSelectField extends SilverStripeComponent {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.onChange(event, {id: this.props.id, value: event.target.value});
|
this.props.onChange(event, { id: this.props.id, value: event.target.value });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SingleSelectField.propTypes = {
|
SingleSelectField.propTypes = {
|
||||||
leftTitle: React.PropTypes.string,
|
id: React.PropTypes.string,
|
||||||
extraClass: React.PropTypes.string,
|
name: React.PropTypes.string.isRequired,
|
||||||
id: React.PropTypes.string,
|
onChange: React.PropTypes.func,
|
||||||
name: React.PropTypes.string.isRequired,
|
value: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
|
||||||
onChange: React.PropTypes.func,
|
readOnly: React.PropTypes.bool,
|
||||||
value: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
|
source: React.PropTypes.arrayOf(React.PropTypes.shape({
|
||||||
readOnly: React.PropTypes.bool,
|
|
||||||
source: React.PropTypes.arrayOf(React.PropTypes.shape({
|
|
||||||
value: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
|
value: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]),
|
||||||
title: React.PropTypes.string,
|
title: React.PropTypes.string,
|
||||||
disabled: React.PropTypes.bool,
|
disabled: React.PropTypes.bool,
|
||||||
})),
|
})),
|
||||||
hasEmptyDefault: React.PropTypes.bool,
|
hasEmptyDefault: React.PropTypes.bool,
|
||||||
emptyString: React.PropTypes.string,
|
emptyString: React.PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
SingleSelectField.defaultProps = {
|
SingleSelectField.defaultProps = {
|
||||||
|
@ -28,7 +28,7 @@ class TextField extends SilverStripeComponent {
|
|||||||
* @returns Object properties
|
* @returns Object properties
|
||||||
*/
|
*/
|
||||||
getInputProps() {
|
getInputProps() {
|
||||||
// @todo Merge with 'attributes' from formfield schema
|
// TODO Merge with 'attributes' from formfield schema
|
||||||
return {
|
return {
|
||||||
// The extraClass property is defined on both the holder and element
|
// The extraClass property is defined on both the holder and element
|
||||||
// for legacy reasons (same behaviour as PHP rendering)
|
// for legacy reasons (same behaviour as PHP rendering)
|
||||||
@ -56,8 +56,6 @@ class TextField extends SilverStripeComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TextField.propTypes = {
|
TextField.propTypes = {
|
||||||
leftTitle: React.PropTypes.string,
|
|
||||||
title: React.PropTypes.string,
|
|
||||||
extraClass: React.PropTypes.string,
|
extraClass: React.PropTypes.string,
|
||||||
id: React.PropTypes.string,
|
id: React.PropTypes.string,
|
||||||
name: React.PropTypes.string.isRequired,
|
name: React.PropTypes.string.isRequired,
|
||||||
|
@ -1,63 +1,65 @@
|
|||||||
import jQuery from 'jQuery';
|
import jQuery from 'jQuery';
|
||||||
|
|
||||||
jQuery.entwine('ss', ($) => {
|
jQuery.entwine('ss', ($) => {
|
||||||
$('#add-to-campaign__dialog .add-to-campaign-action, .cms-content-actions .add-to-campaign-action, #add-to-campaign__action').entwine({
|
$('#add-to-campaign__dialog .add-to-campaign-action,' +
|
||||||
onclick() {
|
'.cms-content-actions .add-to-campaign-action,' +
|
||||||
let dialog = $('#add-to-campaign__dialog');
|
'#add-to-campaign__action').entwine({
|
||||||
|
onclick() {
|
||||||
|
let dialog = $('#add-to-campaign__dialog');
|
||||||
|
|
||||||
if (dialog.length) {
|
if (dialog.length) {
|
||||||
dialog.open();
|
dialog.open();
|
||||||
} else {
|
} else {
|
||||||
dialog = $('<div id="add-to-campaign__dialog" class="add-to-campaign__dialog" />');
|
dialog = $('<div id="add-to-campaign__dialog" class="add-to-campaign__dialog" />');
|
||||||
$('body').append(dialog);
|
$('body').append(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dialog.children().length === 0) dialog.addClass('loading');
|
if (dialog.children().length === 0) dialog.addClass('loading');
|
||||||
|
|
||||||
const form = this.closest('form');
|
const form = this.closest('form');
|
||||||
const button = this;
|
const button = this;
|
||||||
|
|
||||||
const formData = form.serializeArray();
|
const formData = form.serializeArray();
|
||||||
formData.push({
|
formData.push({
|
||||||
name: button.attr('name'),
|
name: button.attr('name'),
|
||||||
value: '1',
|
value: '1',
|
||||||
});
|
});
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: form.attr('action'),
|
url: form.attr('action'),
|
||||||
data: formData,
|
data: formData,
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
global: false,
|
global: false,
|
||||||
complete() {
|
complete() {
|
||||||
dialog.removeClass('loading');
|
dialog.removeClass('loading');
|
||||||
},
|
},
|
||||||
success(data, status, xhr) {
|
success(data, status, xhr) {
|
||||||
if (xhr.getResponseHeader('Content-Type').indexOf('text/plain') === 0) {
|
if (xhr.getResponseHeader('Content-Type').indexOf('text/plain') === 0) {
|
||||||
|
const container = $(
|
||||||
|
'<div class="add-to-campaign__response add-to-campaign__response--good">' +
|
||||||
|
'<span></span></div>'
|
||||||
|
);
|
||||||
|
container.find('span').text(data);
|
||||||
|
dialog.append(container);
|
||||||
|
} else {
|
||||||
|
dialog.html(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error(xhr) {
|
||||||
|
const error = xhr.responseText
|
||||||
|
|| 'Something went wrong. Please try again in a few minutes.';
|
||||||
const container = $(
|
const container = $(
|
||||||
'<div class="add-to-campaign__response add-to-campaign__response--good">' +
|
'<div class="add-to-campaign__response add-to-campaign__response--error">' +
|
||||||
'<span></span></div>'
|
'<span></span></div>'
|
||||||
);
|
);
|
||||||
container.find('span').text(data);
|
container.find('span').text(error);
|
||||||
dialog.append(container);
|
dialog.append(container);
|
||||||
} else {
|
},
|
||||||
dialog.html(data);
|
});
|
||||||
}
|
|
||||||
},
|
|
||||||
error(xhr) {
|
|
||||||
const error = xhr.responseText
|
|
||||||
|| 'Something went wrong. Please try again in a few minutes.';
|
|
||||||
const container = $(
|
|
||||||
'<div class="add-to-campaign__response add-to-campaign__response--error">' +
|
|
||||||
'<span></span></div>'
|
|
||||||
);
|
|
||||||
container.find('span').text(error);
|
|
||||||
dialog.append(container);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#add-to-campaign__dialog').entwine({
|
$('#add-to-campaign__dialog').entwine({
|
||||||
onadd() {
|
onadd() {
|
||||||
|
@ -5,4 +5,5 @@ export const ACTION_TYPES = {
|
|||||||
SUBMIT_FORM_REQUEST: 'SUBMIT_FORM_REQUEST',
|
SUBMIT_FORM_REQUEST: 'SUBMIT_FORM_REQUEST',
|
||||||
SUBMIT_FORM_SUCCESS: 'SUBMIT_FORM_SUCCESS',
|
SUBMIT_FORM_SUCCESS: 'SUBMIT_FORM_SUCCESS',
|
||||||
UPDATE_FIELD: 'UPDATE_FIELD',
|
UPDATE_FIELD: 'UPDATE_FIELD',
|
||||||
|
SET_SUBMIT_ACTION: 'SET_SUBMIT_ACTION',
|
||||||
};
|
};
|
||||||
|
@ -83,3 +83,12 @@ export function submitForm(submitApi, formId, fieldValues) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setSubmitAction(formId, submitAction) {
|
||||||
|
return (dispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTION_TYPES.SET_SUBMIT_ACTION,
|
||||||
|
payload: { formId, submitAction },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -64,6 +64,11 @@ function formReducer(state = initialState, action) {
|
|||||||
submitting: false,
|
submitting: false,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
case ACTION_TYPES.SET_SUBMIT_ACTION:
|
||||||
|
return deepFreeze(updateForm(action.payload.formId, {
|
||||||
|
submitAction: action.payload.submitAction,
|
||||||
|
}));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
|
|
||||||
|
@ -21,7 +21,9 @@ class AddToCampaignHandler_FormAction extends FormAction
|
|||||||
function __construct()
|
function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct('addtocampaign', _t('CAMPAIGNS.ADDTOCAMPAIGN', 'Add to campaign'));
|
parent::__construct('addtocampaign', _t('CAMPAIGNS.ADDTOCAMPAIGN', 'Add to campaign'));
|
||||||
|
$this->setUseButtonTag(false);
|
||||||
$this->addExtraClass('add-to-campaign-action');
|
$this->addExtraClass('add-to-campaign-action');
|
||||||
$this->setValidationExempt(true);
|
$this->setValidationExempt(true);
|
||||||
|
$this->addExtraClass('btn-primary');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ class FormAction extends FormField {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables the use of <button> instead of <input>
|
* Enables the use of <button> instead of <input>
|
||||||
* in {@link Field()} - for more customizeable styling.
|
* in {@link Field()} - for more customisable styling.
|
||||||
*
|
*
|
||||||
* @var boolean
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user