Duplicate date and selection form fields for Form Editor, where we don't use redesigned components
[MAILPOET-2787]
This commit is contained in:
324
assets/js/src/form_editor/blocks/custom_date/date.jsx
Normal file
324
assets/js/src/form_editor/blocks/custom_date/date.jsx
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import moment from 'moment';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
function FormFieldDateYear(props) {
|
||||||
|
const yearsRange = 100;
|
||||||
|
const years = [];
|
||||||
|
|
||||||
|
if (props.placeholder !== undefined) {
|
||||||
|
years.push((
|
||||||
|
<option value="" key={0}>{ props.placeholder }</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentYear = moment().year();
|
||||||
|
for (let i = currentYear; i >= currentYear - yearsRange; i -= 1) {
|
||||||
|
years.push((
|
||||||
|
<option
|
||||||
|
key={i}
|
||||||
|
value={i}
|
||||||
|
>
|
||||||
|
{ i }
|
||||||
|
</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
name={`${props.name}[year]`}
|
||||||
|
value={props.year}
|
||||||
|
onChange={props.onValueChange}
|
||||||
|
className={classnames({ mailpoet_date_year: props.addDefaultClasses })}
|
||||||
|
>
|
||||||
|
{ years }
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FormFieldDateYear.propTypes = {
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
placeholder: PropTypes.string.isRequired,
|
||||||
|
onValueChange: PropTypes.func.isRequired,
|
||||||
|
year: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.number,
|
||||||
|
]).isRequired,
|
||||||
|
addDefaultClasses: PropTypes.bool.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
function FormFieldDateMonth(props) {
|
||||||
|
const months = [];
|
||||||
|
|
||||||
|
if (props.placeholder !== undefined) {
|
||||||
|
months.push((
|
||||||
|
<option value="" key={0}>{ props.placeholder }</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 1; i <= 12; i += 1) {
|
||||||
|
months.push((
|
||||||
|
<option
|
||||||
|
key={i}
|
||||||
|
value={i}
|
||||||
|
>
|
||||||
|
{ props.monthNames[i - 1] }
|
||||||
|
</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
name={`${props.name}[month]`}
|
||||||
|
value={props.month}
|
||||||
|
onChange={props.onValueChange}
|
||||||
|
className={classnames({ mailpoet_date_month: props.addDefaultClasses })}
|
||||||
|
>
|
||||||
|
{ months }
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FormFieldDateMonth.propTypes = {
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
placeholder: PropTypes.string.isRequired,
|
||||||
|
onValueChange: PropTypes.func.isRequired,
|
||||||
|
month: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.number,
|
||||||
|
]).isRequired,
|
||||||
|
monthNames: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||||
|
addDefaultClasses: PropTypes.bool.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
function FormFieldDateDay(props) {
|
||||||
|
const days = [];
|
||||||
|
|
||||||
|
if (props.placeholder !== undefined) {
|
||||||
|
days.push((
|
||||||
|
<option value="" key={0}>{ props.placeholder }</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 1; i <= 31; i += 1) {
|
||||||
|
days.push((
|
||||||
|
<option
|
||||||
|
key={i}
|
||||||
|
value={i}
|
||||||
|
>
|
||||||
|
{ i }
|
||||||
|
</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
name={`${props.name}[day]`}
|
||||||
|
value={props.day}
|
||||||
|
onChange={props.onValueChange}
|
||||||
|
className={classnames({ mailpoet_date_day: props.addDefaultClasses })}
|
||||||
|
>
|
||||||
|
{ days }
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FormFieldDateDay.propTypes = {
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
placeholder: PropTypes.string.isRequired,
|
||||||
|
onValueChange: PropTypes.func.isRequired,
|
||||||
|
day: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.number,
|
||||||
|
]).isRequired,
|
||||||
|
addDefaultClasses: PropTypes.bool.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
class FormFieldDate extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
year: '',
|
||||||
|
month: '',
|
||||||
|
day: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onValueChange = this.onValueChange.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.extractDateParts();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
if (
|
||||||
|
(this.props.item !== undefined && prevProps.item !== undefined)
|
||||||
|
&& (this.props.item.id !== prevProps.item.id)
|
||||||
|
) {
|
||||||
|
this.extractDateParts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onValueChange(e) {
|
||||||
|
// extract property from name
|
||||||
|
const matches = e.target.name.match(/(.*?)\[(.*?)\]/);
|
||||||
|
let field = null;
|
||||||
|
let property = null;
|
||||||
|
|
||||||
|
if (matches !== null && matches.length === 3) {
|
||||||
|
[, field, property] = matches;
|
||||||
|
|
||||||
|
const value = Number(e.target.value);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
[`${property}`]: value,
|
||||||
|
}, () => {
|
||||||
|
this.props.onValueChange({
|
||||||
|
target: {
|
||||||
|
name: field,
|
||||||
|
value: this.formatValue(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formatValue() {
|
||||||
|
const dateType = this.props.field.params.date_type;
|
||||||
|
|
||||||
|
let value;
|
||||||
|
|
||||||
|
switch (dateType) {
|
||||||
|
case 'year_month_day':
|
||||||
|
value = {
|
||||||
|
year: this.state.year,
|
||||||
|
month: this.state.month,
|
||||||
|
day: this.state.day,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'year_month':
|
||||||
|
value = {
|
||||||
|
year: this.state.year,
|
||||||
|
month: this.state.month,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'month':
|
||||||
|
value = {
|
||||||
|
month: this.state.month,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'year':
|
||||||
|
value = {
|
||||||
|
year: this.state.year,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value = {
|
||||||
|
value: 'invalid type',
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
extractDateParts() {
|
||||||
|
const value = (this.props.item[this.props.field.name] !== undefined)
|
||||||
|
? this.props.item[this.props.field.name].trim()
|
||||||
|
: '';
|
||||||
|
|
||||||
|
if (value === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dateTime = moment(value);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
year: dateTime.format('YYYY'),
|
||||||
|
month: dateTime.format('M'),
|
||||||
|
day: dateTime.format('D'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const monthNames = window.mailpoet_month_names || [];
|
||||||
|
const dateFormats = window.mailpoet_date_formats || {};
|
||||||
|
const dateType = this.props.field.params.date_type;
|
||||||
|
let dateFormat = dateFormats[dateType][0];
|
||||||
|
if (this.props.field.params.date_format) {
|
||||||
|
dateFormat = this.props.field.params.date_format;
|
||||||
|
}
|
||||||
|
const dateSelects = dateFormat.split('/');
|
||||||
|
|
||||||
|
const fields = dateSelects.map((type) => {
|
||||||
|
switch (type) {
|
||||||
|
case 'YYYY':
|
||||||
|
return (
|
||||||
|
<FormFieldDateYear
|
||||||
|
onValueChange={this.onValueChange}
|
||||||
|
key="year"
|
||||||
|
name={this.props.field.name}
|
||||||
|
addDefaultClasses={this.props.addDefaultClasses}
|
||||||
|
year={this.state.year}
|
||||||
|
placeholder={this.props.field.year_placeholder}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
case 'MM':
|
||||||
|
return (
|
||||||
|
<FormFieldDateMonth
|
||||||
|
onValueChange={this.onValueChange}
|
||||||
|
key="month"
|
||||||
|
name={this.props.field.name}
|
||||||
|
addDefaultClasses={this.props.addDefaultClasses}
|
||||||
|
month={this.state.month}
|
||||||
|
monthNames={monthNames}
|
||||||
|
placeholder={this.props.field.month_placeholder}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
case 'DD':
|
||||||
|
return (
|
||||||
|
<FormFieldDateDay
|
||||||
|
onValueChange={this.onValueChange}
|
||||||
|
key="day"
|
||||||
|
name={this.props.field.name}
|
||||||
|
addDefaultClasses={this.props.addDefaultClasses}
|
||||||
|
day={this.state.day}
|
||||||
|
placeholder={this.props.field.day_placeholder}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return <div>Invalid date type</div>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{fields}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FormFieldDate.propTypes = {
|
||||||
|
item: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||||
|
field: PropTypes.shape({
|
||||||
|
name: PropTypes.string,
|
||||||
|
day_placeholder: PropTypes.string,
|
||||||
|
month_placeholder: PropTypes.string,
|
||||||
|
year_placeholder: PropTypes.string,
|
||||||
|
params: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||||
|
}).isRequired,
|
||||||
|
onValueChange: PropTypes.func.isRequired,
|
||||||
|
addDefaultClasses: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
FormFieldDate.defaultProps = {
|
||||||
|
addDefaultClasses: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FormFieldDate;
|
@@ -12,7 +12,7 @@ import { useDispatch, useSelect } from '@wordpress/data';
|
|||||||
|
|
||||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||||
import CustomFieldSettings from './custom_field_settings.jsx';
|
import CustomFieldSettings from './custom_field_settings.jsx';
|
||||||
import FormFieldDate from '../../../form/fields/date.jsx';
|
import FormFieldDate from './date.jsx';
|
||||||
import formatLabel from '../label_formatter.jsx';
|
import formatLabel from '../label_formatter.jsx';
|
||||||
import mapCustomFieldFormData from '../map_custom_field_form_data.jsx';
|
import mapCustomFieldFormData from '../map_custom_field_form_data.jsx';
|
||||||
|
|
||||||
|
@@ -12,7 +12,7 @@ import React from 'react';
|
|||||||
import MailPoet from 'mailpoet';
|
import MailPoet from 'mailpoet';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Selection from '../../../form/fields/selection.jsx';
|
import Selection from './selection.jsx';
|
||||||
import FormTitle from '../form_title';
|
import FormTitle from '../form_title';
|
||||||
|
|
||||||
const BasicSettingsPanel = ({ onToggle, isOpened }) => {
|
const BasicSettingsPanel = ({ onToggle, isOpened }) => {
|
||||||
|
330
assets/js/src/form_editor/components/form_settings/selection.jsx
Normal file
330
assets/js/src/form_editor/components/form_settings/selection.jsx
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import jQuery from 'jquery';
|
||||||
|
import _ from 'underscore';
|
||||||
|
import 'react-dom';
|
||||||
|
import 'select2';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
class Selection extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.selectRef = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.isSelect2Component()) {
|
||||||
|
this.setupSelect2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
if ((this.props.item !== undefined && prevProps.item !== undefined)
|
||||||
|
&& (this.props.item.id !== prevProps.item.id)
|
||||||
|
) {
|
||||||
|
jQuery(`#${this.selectRef.current.id}`)
|
||||||
|
.val(this.getSelectedValues())
|
||||||
|
.trigger('change');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isSelect2Initialized()
|
||||||
|
&& (this.getFieldId(this.props) !== this.getFieldId(prevProps))
|
||||||
|
&& this.props.field.resetSelect2OnUpdate !== undefined
|
||||||
|
) {
|
||||||
|
this.resetSelect2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (this.isSelect2Component()) {
|
||||||
|
this.destroySelect2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getFieldId = (data) => {
|
||||||
|
const props = data || this.props;
|
||||||
|
return props.field.id || props.field.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
getSelectedValues = () => {
|
||||||
|
if (this.props.field.selected !== undefined) {
|
||||||
|
return this.props.field.selected(this.props.item);
|
||||||
|
}
|
||||||
|
if (this.props.item !== undefined && this.props.field.name !== undefined) {
|
||||||
|
if (this.allowMultipleValues()) {
|
||||||
|
if (_.isArray(this.props.item[this.props.field.name])) {
|
||||||
|
return this.props.item[this.props.field.name].map((item) => item.id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.props.item[this.props.field.name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
getItems = () => {
|
||||||
|
let items;
|
||||||
|
if (typeof (window[`mailpoet_${this.props.field.endpoint}`]) !== 'undefined') {
|
||||||
|
items = window[`mailpoet_${this.props.field.endpoint}`];
|
||||||
|
} else if (this.props.field.values !== undefined) {
|
||||||
|
items = this.props.field.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isArray(items)) {
|
||||||
|
if (this.props.field.filter !== undefined) {
|
||||||
|
items = items.filter(this.props.field.filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
};
|
||||||
|
|
||||||
|
getLabel = (item) => {
|
||||||
|
if (this.props.field.getLabel !== undefined) {
|
||||||
|
return this.props.field.getLabel(item, this.props.item);
|
||||||
|
}
|
||||||
|
return item.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
getSearchLabel = (item) => {
|
||||||
|
if (this.props.field.getSearchLabel !== undefined) {
|
||||||
|
return this.props.field.getSearchLabel(item, this.props.item);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
getValue = (item) => {
|
||||||
|
if (this.props.field.getValue !== undefined) {
|
||||||
|
return this.props.field.getValue(item, this.props.item);
|
||||||
|
}
|
||||||
|
return item.id;
|
||||||
|
};
|
||||||
|
|
||||||
|
setupSelect2 = () => {
|
||||||
|
if (this.isSelect2Initialized()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let select2Options = {
|
||||||
|
disabled: this.props.disabled || false,
|
||||||
|
width: (this.props.width || ''),
|
||||||
|
placeholder: {
|
||||||
|
id: '', // the value of the option
|
||||||
|
text: this.props.field.placeholder,
|
||||||
|
},
|
||||||
|
templateResult: function templateResult(item) {
|
||||||
|
if (item.element && item.element.selected) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (item.title) {
|
||||||
|
return item.title;
|
||||||
|
}
|
||||||
|
return item.text;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const remoteQuery = this.props.field.remoteQuery || null;
|
||||||
|
if (remoteQuery) {
|
||||||
|
select2Options = Object.assign(select2Options, {
|
||||||
|
ajax: {
|
||||||
|
url: window.ajaxurl,
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
data: function data(params) {
|
||||||
|
return {
|
||||||
|
action: 'mailpoet',
|
||||||
|
api_version: window.mailpoet_api_version,
|
||||||
|
token: window.mailpoet_token,
|
||||||
|
endpoint: remoteQuery.endpoint,
|
||||||
|
method: remoteQuery.method,
|
||||||
|
data: Object.assign(
|
||||||
|
remoteQuery.data,
|
||||||
|
{ query: params.term }
|
||||||
|
),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
processResults: function processResults(response) {
|
||||||
|
let results;
|
||||||
|
if (!_.has(response, 'data')) {
|
||||||
|
results = [];
|
||||||
|
} else {
|
||||||
|
results = response.data.map((item) => {
|
||||||
|
const id = item.id || item.value;
|
||||||
|
const text = item.name || item.text;
|
||||||
|
return { id, text };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return { results };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
minimumInputLength: remoteQuery.minimumInputLength || 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.field.extendSelect2Options !== undefined) {
|
||||||
|
select2Options = Object.assign(select2Options, this.props.field.extendSelect2Options);
|
||||||
|
}
|
||||||
|
|
||||||
|
const select2 = jQuery(`#${this.selectRef.current.id}`).select2(select2Options);
|
||||||
|
|
||||||
|
let hasRemoved = false;
|
||||||
|
select2.on('select2:unselecting', () => {
|
||||||
|
hasRemoved = true;
|
||||||
|
});
|
||||||
|
select2.on('select2:opening', (e) => {
|
||||||
|
if (hasRemoved === true) {
|
||||||
|
hasRemoved = false;
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
select2.on('change', this.handleChange);
|
||||||
|
};
|
||||||
|
|
||||||
|
resetSelect2 = () => {
|
||||||
|
this.destroySelect2();
|
||||||
|
this.setupSelect2();
|
||||||
|
};
|
||||||
|
|
||||||
|
destroySelect2 = () => {
|
||||||
|
if (this.isSelect2Initialized()) {
|
||||||
|
jQuery(`#${this.selectRef.current.id}`).select2('destroy');
|
||||||
|
this.cleanupAfterSelect2();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
cleanupAfterSelect2 = () => {
|
||||||
|
// remove DOM elements created by Select2 that are not tracked by React
|
||||||
|
jQuery(`#${this.selectRef.current.id}`)
|
||||||
|
.find('option:not(.default)')
|
||||||
|
.remove();
|
||||||
|
|
||||||
|
// unbind events (https://select2.org/programmatic-control/methods#event-unbinding)
|
||||||
|
jQuery(`#${this.selectRef.current.id}`)
|
||||||
|
.off('select2:unselecting')
|
||||||
|
.off('select2:opening');
|
||||||
|
};
|
||||||
|
|
||||||
|
allowMultipleValues = () => (this.props.field.multiple === true);
|
||||||
|
|
||||||
|
isSelect2Initialized = () => (jQuery(`#${this.selectRef.current.id}`).hasClass('select2-hidden-accessible') === true);
|
||||||
|
|
||||||
|
isSelect2Component = () => this.allowMultipleValues() || this.props.field.forceSelect2;
|
||||||
|
|
||||||
|
handleChange = (e) => {
|
||||||
|
if (this.props.onValueChange === undefined) return;
|
||||||
|
|
||||||
|
const valueTextPair = jQuery(`#${this.selectRef.current.id}`).children(':selected').map(function element() {
|
||||||
|
return { id: jQuery(this).val(), text: jQuery(this).text() };
|
||||||
|
});
|
||||||
|
const value = (this.props.field.multiple) ? _.pluck(valueTextPair, 'id') : _.pluck(valueTextPair, 'id').toString();
|
||||||
|
const transformedValue = this.transformChangedValue(value, valueTextPair);
|
||||||
|
|
||||||
|
this.props.onValueChange({
|
||||||
|
target: {
|
||||||
|
value: transformedValue,
|
||||||
|
name: this.props.field.name,
|
||||||
|
id: e.target.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// When it's impossible to represent the desired value in DOM,
|
||||||
|
// this function may be used to transform the placeholder value into
|
||||||
|
// desired value.
|
||||||
|
transformChangedValue = (value, textValuePair) => {
|
||||||
|
if (typeof this.props.field.transformChangedValue === 'function') {
|
||||||
|
return this.props.field.transformChangedValue.call(this, value, textValuePair);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
insertEmptyOption = () => {
|
||||||
|
// https://select2.org/placeholders
|
||||||
|
// For single selects only, in order for the placeholder value to appear,
|
||||||
|
// we must have a blank <option> as the first option in the <select> control.
|
||||||
|
if (this.allowMultipleValues()) return undefined;
|
||||||
|
if (this.props.field.placeholder) {
|
||||||
|
return (
|
||||||
|
<option className="default" /> // eslint-disable-line jsx-a11y/control-has-associated-label
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const items = this.getItems(this.props.field);
|
||||||
|
const selectedValues = this.getSelectedValues();
|
||||||
|
const options = items.map((item) => {
|
||||||
|
const label = this.getLabel(item);
|
||||||
|
const searchLabel = this.getSearchLabel(item);
|
||||||
|
const value = this.getValue(item);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<option
|
||||||
|
key={`option-${item.id}`}
|
||||||
|
className="default"
|
||||||
|
value={value}
|
||||||
|
title={searchLabel}
|
||||||
|
>
|
||||||
|
{ label }
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
id={this.getFieldId()}
|
||||||
|
ref={this.selectRef}
|
||||||
|
disabled={this.props.field.disabled}
|
||||||
|
data-placeholder={this.props.field.placeholder}
|
||||||
|
multiple={this.props.field.multiple}
|
||||||
|
defaultValue={selectedValues}
|
||||||
|
{...this.props.field.validation}// eslint-disable-line react/jsx-props-no-spreading
|
||||||
|
>
|
||||||
|
{ this.insertEmptyOption() }
|
||||||
|
{ options }
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Selection.propTypes = {
|
||||||
|
onValueChange: PropTypes.func,
|
||||||
|
field: PropTypes.shape({
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
values: PropTypes.oneOfType([
|
||||||
|
PropTypes.object,
|
||||||
|
PropTypes.array,
|
||||||
|
]),
|
||||||
|
getLabel: PropTypes.func,
|
||||||
|
resetSelect2OnUpdate: PropTypes.bool,
|
||||||
|
selected: PropTypes.func,
|
||||||
|
endpoint: PropTypes.string,
|
||||||
|
filter: PropTypes.func,
|
||||||
|
getSearchLabel: PropTypes.func,
|
||||||
|
getValue: PropTypes.func,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
remoteQuery: PropTypes.object,
|
||||||
|
extendSelect2Options: PropTypes.object,
|
||||||
|
multiple: PropTypes.bool,
|
||||||
|
forceSelect2: PropTypes.bool,
|
||||||
|
transformChangedValue: PropTypes.func,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
validation: PropTypes.object,
|
||||||
|
}).isRequired,
|
||||||
|
item: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
width: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
Selection.defaultProps = {
|
||||||
|
onValueChange: function onValueChange() {
|
||||||
|
// no-op
|
||||||
|
},
|
||||||
|
disabled: false,
|
||||||
|
width: '',
|
||||||
|
item: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default Selection;
|
Reference in New Issue
Block a user