hbp-quickfire
Version:
A library of useful user-interface components built with React on top of React Bootstrap and MobX
167 lines (137 loc) • 16.1 kB
JavaScript
var _createClass = function () {function defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}return function (Constructor, protoProps, staticProps) {if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;};}();var _dec, _dec2, _class;function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}function _possibleConstructorReturn(self, call) {if (!self) {throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return call && (typeof call === "object" || typeof call === "function") ? call : self;}function _inherits(subClass, superClass) {if (typeof superClass !== "function" && superClass !== null) {throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);}subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;} /*
* Copyright (c) Human Brain Project
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from "react";
import { Provider, inject, observer } from "mobx-react";
import injectStyles from "react-jss";import Button from "react-bootstrap/lib/Button";import isFunction from "lodash/isFunction";
import FormStore from "../Stores/FormStore";
import FieldLabel from "./FieldLabel";
/**
* Allows the implementation of a nested field structure
* @class NestedField
* @memberof FormFields
* @namespace NestedField
*/
var styles = {
buttonArea: {
marginBottom: "1em" } };var
NestedField = (_dec = inject("formStore"), _dec2 = injectStyles(styles), _dec(_class = _dec2(_class = observer(_class = function (_React$Component) {_inherits(NestedField, _React$Component);function NestedField() {var _ref;var _temp, _this, _ret;_classCallCheck(this, NestedField);for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {args[_key] = arguments[_key];}return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = NestedField.__proto__ || Object.getPrototypeOf(NestedField)).call.apply(_ref, [this].concat(args))), _this), _this.
triggerOnChange = function () {
Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set.
call(_this.hiddenInputRef, JSON.stringify(_this.props.field.getValue(false)));
var event = new Event("input", { bubbles: true });
_this.hiddenInputRef.dispatchEvent(event);
}, _this.
handleAdd = function () {
var field = _this.props.field;
if (field.disabled || field.readOnly) {
return;
}
if (field.value.length < field.max) {
if (isFunction(_this.props.onBeforeAddInstance)) {
_this.props.onBeforeAddInstance(function () {field.addInstance();}, field);
} else {
field.addInstance();
}
_this.triggerOnChange();
}
}, _this.
handleRemove = function (index) {
var field = _this.props.field;
if (field.disabled || field.readOnly) {
return;
}
if (field.value.length > field.min) {
if (isFunction(_this.props.onBeforeRemoveInstance)) {
_this.props.onBeforeRemoveInstance(function () {field.removeInstance(index);}, field, field.value[index]);
} else {
field.removeInstance(index);
}
_this.triggerOnChange();
}
}, _this.
handleMoveUp = function (index) {
var field = _this.props.field;
if (field.disabled || field.readOnly) {
return;
}
if (isFunction(_this.props.onBeforeMoveUpInstance)) {
_this.props.onBeforeMoveUpInstance(function () {field.moveInstance(index, index - 1);}, field, field.value[index]);
} else {
field.moveInstance(index, index - 1);
}
_this.triggerOnChange();
}, _this.
handleMoveDown = function (index) {
var field = _this.props.field;
if (field.disabled || field.readOnly) {
return;
}
if (isFunction(_this.props.onBeforeMoveDownInstance)) {
_this.props.onBeforeMoveDownInstance(function () {field.moveInstance(index, index + 1);}, field, field.value[index]);
} else {
field.moveInstance(index, index + 1);
}
_this.triggerOnChange();
}, _this.
handleDuplicate = function (index) {
var field = _this.props.field;
if (field.disabled || field.readOnly) {
return;
}
if (field.value.length < field.max) {
if (isFunction(_this.props.onBeforeDuplicateInstance)) {
_this.props.onBeforeDuplicateInstance(function () {field.duplicateInstance(index);}, field, field.value[index]);
} else {
field.duplicateInstance(index);
}
_this.triggerOnChange();
}
}, _temp), _possibleConstructorReturn(_this, _ret);} //The only way to trigger an onChange event in React is to do the following
//Basically changing the field value, bypassing the react setter and dispatching an "input"
// event on a proper html input node
//See for example the discussion here : https://stackoverflow.com/a/46012210/9429503
_createClass(NestedField, [{ key: "render", value: function render() {var _this2 = this;var _props = this.props,classes = _props.classes,children = _props.children;var _props$field = this.props.field,path = _props$field.path,disabled = _props$field.disabled,readOnly = _props$field.readOnly,readMode = _props$field.readMode,min = _props$field.min,max = _props$field.max,value = _props$field.value,buttonLabel = _props$field.buttonLabel,topAddButton = _props$field.topAddButton,bottomAddButton = _props$field.bottomAddButton;
var childrenStructure = [];
var numberOfChildInstances = value ?
value.length :
0;
for (var i = 0; i < numberOfChildInstances; i++) {
childrenStructure.push(
React.cloneElement(React.createElement("div", null, children)));
}
var addButton =
React.createElement("div", { className: "quickfire-nested-add " + classes.buttonArea },
React.createElement(Button, { bsStyle: "primary",
bsSize: "xsmall",
disabled: disabled || value.length >= max,
readOnly: readOnly,
onClick: this.handleAdd,
className: disabled || readOnly ? "disabled" : "" }, buttonLabel));
//No button will show at all if the nested fields have a min and max === 1
var showButton = !this.props.formStore.readMode && !readMode && (min !== 1 || max !== 1);
return (
React.createElement("div", { className: "quickfire-field-nested " + (this.props.formStore.readMode || readMode ? " quickfire-readmode" : "") + " " + (!numberOfChildInstances ? "quickfire-empty-field" : "") + " " + (disabled ? "quickfire-field-disabled" : "") + " " + (readOnly ? "quickfire-field-readonly" : "") },
React.createElement(FieldLabel, { field: this.props.field }),
showButton && topAddButton && addButton,
React.createElement("input", { style: { display: "none" }, type: "text", ref: function ref(_ref2) {return _this2.hiddenInputRef = _ref2;} }),
React.createElement("div", null,
childrenStructure.map(function (child, index) {
return (
React.createElement(Provider, {
key: _this2.props.formStore.getGeneratedKey(value[index], "quickfire-nested-child"),
parentPath: path + FormStore.getPathNodeSeparator() + index,
nestedField: _this2.props.field,
nestedFieldIndex: index,
onRemove: _this2.handleRemove,
onMoveUp: _this2.handleMoveUp,
onMoveDown: _this2.handleMoveDown,
onDuplicate: _this2.handleDuplicate,
suppressChangedStoreWarning: true },
child));
})),
showButton && bottomAddButton && (value.length !== 0 || !topAddButton) && addButton));
} }]);return NestedField;}(React.Component)) || _class) || _class) || _class);export { NestedField as default };