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([
'react',
'react-dom',
'jquery',
'underscore',
'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');
}
import React from 'react';
import jQuery from 'jquery';
import _ from 'underscore';
import 'react-dom';
import 'select2';
if (this.isSelect2Initialized() &&
(this.getFieldId(this.props) !== this.getFieldId(prevProps)) &&
this.props.field.resetSelect2OnUpdate !== undefined
) {
this.resetSelect2();
}
},
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();
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();
},
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
}
},
componentDidUpdate: function componentDidUpdate(prevProps) {
if ((this.props.item !== undefined && prevProps.item !== undefined)
&& (this.props.item.id !== prevProps.item.id)
) {
jQuery(`#${this.select.id}`)
.find('option:not(.default)')
.remove();
.val(this.getSelectedValues())
.trigger('change');
}
// unbind events (https://select2.org/programmatic-control/methods#event-unbinding)
jQuery(`#${this.select.id}`)
.off('select2:unselecting')
.off('select2:opening');
},
setupSelect2: function setupSelect2() {
if (this.isSelect2Initialized()) {
return;
}
if (this.isSelect2Initialized() &&
(this.getFieldId(this.props) !== this.getFieldId(prevProps)) &&
this.props.field.resetSelect2OnUpdate !== undefined
) {
this.resetSelect2();
}
},
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 = {
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;
} else if (item.title) {
return item.title;
}
return item.text;
},
};
// unbind events (https://select2.org/programmatic-control/methods#event-unbinding)
jQuery(`#${this.select.id}`)
.off('select2:unselecting')
.off('select2:opening');
},
setupSelect2: function setupSelect2() {
if (this.isSelect2Initialized()) {
return;
}
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) {
return {
results: response.data.map(item => (
{ id: item.id || item.value, text: item.name || item.text }
)),
};
},
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;
} else 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) {
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 (
<option
key={`option-${index}`}
className="default"
value={value}
title={searchLabel}
selected={value === selectedValues}
>
{ label }
</option>
);
});
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,
},
});
},
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 (
<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}
<option
key={`option-${item.id}`}
className="default"
value={value}
title={searchLabel}
selected={value === selectedValues}
>
{ this.insertEmptyOption() }
{ options }
</select>
{ label }
</option>
);
},
});
});
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;