ES6 assets/js/src/form/fields/selection.jsx

This commit is contained in:
Amine Ben hammou
2018-04-18 15:53:11 +02:00
parent bcb1f7e289
commit 788362f5b8

View File

@@ -1,269 +1,261 @@
define([ import React from 'react';
'react', import jQuery from 'jquery';
'react-dom', import _ from 'underscore';
'jquery', import 'react-dom';
'underscore', import 'select2';
'select2',
],
(
React,
ReactDOM,
jQuery,
_
) => {
const Selection = React.createClass({
allowMultipleValues: function allowMultipleValues() {
return (this.props.field.multiple === true);
},
isSelect2Initialized: function isSelect2Initialized() {
return (jQuery(`#${this.select.id}`).hasClass('select2-hidden-accessible') === true);
},
isSelect2Component: function isSelect2Component() {
return this.allowMultipleValues() || this.props.field.forceSelect2;
},
componentDidMount: function componentDidMount() {
if (this.isSelect2Component()) {
this.setupSelect2();
}
},
componentDidUpdate: function componentDidUpdate(prevProps) {
if ((this.props.item !== undefined && prevProps.item !== undefined)
&& (this.props.item.id !== prevProps.item.id)
) {
jQuery(`#${this.select.id}`)
.val(this.getSelectedValues())
.trigger('change');
}
if (this.isSelect2Initialized() && const Selection = React.createClass({
(this.getFieldId(this.props) !== this.getFieldId(prevProps)) && allowMultipleValues: function allowMultipleValues() {
this.props.field.resetSelect2OnUpdate !== undefined return (this.props.field.multiple === true);
) { },
this.resetSelect2(); isSelect2Initialized: function isSelect2Initialized() {
} return (jQuery(`#${this.select.id}`).hasClass('select2-hidden-accessible') === true);
}, },
componentWillUnmount: function componentWillUnmount() { isSelect2Component: function isSelect2Component() {
if (this.isSelect2Component()) { return this.allowMultipleValues() || this.props.field.forceSelect2;
this.destroySelect2(); },
} componentDidMount: function componentDidMount() {
}, if (this.isSelect2Component()) {
getFieldId: function getFieldId(data) {
const props = data || this.props;
return props.field.id || props.field.name;
},
resetSelect2: function resetSelect2() {
this.destroySelect2();
this.setupSelect2(); this.setupSelect2();
}, }
destroySelect2: function destroySelect2() { },
if (this.isSelect2Initialized()) { componentDidUpdate: function componentDidUpdate(prevProps) {
jQuery(`#${this.select.id}`).select2('destroy'); if ((this.props.item !== undefined && prevProps.item !== undefined)
this.cleanupAfterSelect2(); && (this.props.item.id !== prevProps.item.id)
} ) {
},
cleanupAfterSelect2: function cleanupAfterSelect2() {
// remove DOM elements created by Select2 that are not tracked by React
jQuery(`#${this.select.id}`) jQuery(`#${this.select.id}`)
.find('option:not(.default)') .val(this.getSelectedValues())
.remove(); .trigger('change');
}
// unbind events (https://select2.org/programmatic-control/methods#event-unbinding) if (this.isSelect2Initialized() &&
jQuery(`#${this.select.id}`) (this.getFieldId(this.props) !== this.getFieldId(prevProps)) &&
.off('select2:unselecting') this.props.field.resetSelect2OnUpdate !== undefined
.off('select2:opening'); ) {
}, this.resetSelect2();
setupSelect2: function setupSelect2() { }
if (this.isSelect2Initialized()) { },
return; componentWillUnmount: function componentWillUnmount() {
} if (this.isSelect2Component()) {
this.destroySelect2();
}
},
getFieldId: function getFieldId(data) {
const props = data || this.props;
return props.field.id || props.field.name;
},
resetSelect2: function resetSelect2() {
this.destroySelect2();
this.setupSelect2();
},
destroySelect2: function destroySelect2() {
if (this.isSelect2Initialized()) {
jQuery(`#${this.select.id}`).select2('destroy');
this.cleanupAfterSelect2();
}
},
cleanupAfterSelect2: function cleanupAfterSelect2() {
// remove DOM elements created by Select2 that are not tracked by React
jQuery(`#${this.select.id}`)
.find('option:not(.default)')
.remove();
let select2Options = { // unbind events (https://select2.org/programmatic-control/methods#event-unbinding)
disabled: this.props.disabled || false, jQuery(`#${this.select.id}`)
width: (this.props.width || ''), .off('select2:unselecting')
placeholder: { .off('select2:opening');
id: '', // the value of the option },
text: this.props.field.placeholder, setupSelect2: function setupSelect2() {
}, if (this.isSelect2Initialized()) {
templateResult: function templateResult(item) { return;
if (item.element && item.element.selected) { }
return null;
} else if (item.title) {
return item.title;
}
return item.text;
},
};
const remoteQuery = this.props.field.remoteQuery || null; let select2Options = {
if (remoteQuery) { disabled: this.props.disabled || false,
select2Options = Object.assign(select2Options, { width: (this.props.width || ''),
ajax: { placeholder: {
url: window.ajaxurl, id: '', // the value of the option
type: 'POST', text: this.props.field.placeholder,
dataType: 'json', },
data: function data(params) { templateResult: function templateResult(item) {
return { if (item.element && item.element.selected) {
action: 'mailpoet', return null;
api_version: window.mailpoet_api_version, } else if (item.title) {
token: window.mailpoet_token, return item.title;
endpoint: remoteQuery.endpoint, }
method: remoteQuery.method, return item.text;
data: Object.assign( },
remoteQuery.data, };
{ query: params.term }
), const remoteQuery = this.props.field.remoteQuery || null;
}; if (remoteQuery) {
}, select2Options = Object.assign(select2Options, {
processResults: function processResults(response) { ajax: {
return { url: window.ajaxurl,
results: response.data.map(item => ( type: 'POST',
{ id: item.id || item.value, text: item.name || item.text } 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) {
return {
results: response.data.map(item => (
{ id: item.id || item.value, text: item.name || item.text }
)),
};
}, },
minimumInputLength: remoteQuery.minimumInputLength || 2,
});
}
if (this.props.field.extendSelect2Options !== undefined) {
select2Options = Object.assign(select2Options, this.props.field.extendSelect2Options);
}
const select2 = jQuery(`#${this.select.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);
},
getSelectedValues: function getSelectedValues() {
if (this.props.field.selected !== undefined) {
return this.props.field.selected(this.props.item);
} else 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: function 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;
},
handleChange: function handleChange(e) {
if (this.props.onValueChange === undefined) return;
const valueTextPair = jQuery(`#${this.select.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,
}, },
minimumInputLength: remoteQuery.minimumInputLength || 2,
}); });
}, }
getLabel: function getLabel(item) {
if (this.props.field.getLabel !== undefined) {
return this.props.field.getLabel(item, this.props.item);
}
return item.name;
},
getSearchLabel: function getSearchLabel(item) {
if (this.props.field.getSearchLabel !== undefined) {
return this.props.field.getSearchLabel(item, this.props.item);
}
return null;
},
getValue: function getValue(item) {
if (this.props.field.getValue !== undefined) {
return this.props.field.getValue(item, this.props.item);
}
return item.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: function transformChangedValue(value, textValuePair) {
if (typeof this.props.field.transformChangedValue === 'function') {
return this.props.field.transformChangedValue.call(this, value, textValuePair);
}
return value;
},
insertEmptyOption: function 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" />);
return undefined;
},
render: function render() {
const items = this.getItems(this.props.field);
const selectedValues = this.getSelectedValues();
const options = items.map((item, index) => {
const label = this.getLabel(item);
const searchLabel = this.getSearchLabel(item);
const value = this.getValue(item);
return ( if (this.props.field.extendSelect2Options !== undefined) {
<option select2Options = Object.assign(select2Options, this.props.field.extendSelect2Options);
key={`option-${index}`} }
className="default"
value={value} const select2 = jQuery(`#${this.select.id}`).select2(select2Options);
title={searchLabel}
selected={value === selectedValues} let hasRemoved = false;
> select2.on('select2:unselecting', () => {
{ label } hasRemoved = true;
</option> });
); select2.on('select2:opening', (e) => {
}); if (hasRemoved === true) {
hasRemoved = false;
e.preventDefault();
}
});
select2.on('change', this.handleChange);
},
getSelectedValues: function getSelectedValues() {
if (this.props.field.selected !== undefined) {
return this.props.field.selected(this.props.item);
} else 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: function 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;
},
handleChange: function handleChange(e) {
if (this.props.onValueChange === undefined) return;
const valueTextPair = jQuery(`#${this.select.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,
},
});
},
getLabel: function getLabel(item) {
if (this.props.field.getLabel !== undefined) {
return this.props.field.getLabel(item, this.props.item);
}
return item.name;
},
getSearchLabel: function getSearchLabel(item) {
if (this.props.field.getSearchLabel !== undefined) {
return this.props.field.getSearchLabel(item, this.props.item);
}
return null;
},
getValue: function getValue(item) {
if (this.props.field.getValue !== undefined) {
return this.props.field.getValue(item, this.props.item);
}
return item.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: function transformChangedValue(value, textValuePair) {
if (typeof this.props.field.transformChangedValue === 'function') {
return this.props.field.transformChangedValue.call(this, value, textValuePair);
}
return value;
},
insertEmptyOption: function 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" />);
return undefined;
},
render: function 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 ( return (
<select <option
id={this.getFieldId()} key={`option-${item.id}`}
ref={(c) => { this.select = c; }} className="default"
disabled={this.props.field.disabled} value={value}
data-placeholder={this.props.field.placeholder} title={searchLabel}
multiple={this.props.field.multiple} selected={value === selectedValues}
defaultValue={selectedValues}
{...this.props.field.validation}
> >
{ this.insertEmptyOption() } { label }
{ options } </option>
</select>
); );
}, });
});
return Selection; return (
<select
id={this.getFieldId()}
ref={(c) => { this.select = c; }}
disabled={this.props.field.disabled}
data-placeholder={this.props.field.placeholder}
multiple={this.props.field.multiple}
defaultValue={selectedValues}
{...this.props.field.validation}
>
{ this.insertEmptyOption() }
{ options }
</select>
);
},
}); });
export default Selection;