react-editable-json-tree
Version:
React Editable Json Tree
561 lines (494 loc) • 20.9 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _JsonNode = require('./JsonNode');
var _JsonNode2 = _interopRequireDefault(_JsonNode);
var _JsonAddValue = require('./JsonAddValue');
var _JsonAddValue2 = _interopRequireDefault(_JsonAddValue);
var _objectTypes = require('../utils/objectTypes');
var _deltaTypes = require('../types/deltaTypes');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* ************************************* */
/* ******** VARIABLES ******** */
/* ************************************* */
// Prop types
/*
* Author: Alexandre Havrileck (Oxyno-zeta)
* Date: 20/10/16
* Licence: See Readme
*/
/* ************************************* */
/* ******** IMPORTS ******** */
/* ************************************* */
var propTypes = {
data: _propTypes2.default.array.isRequired,
name: _propTypes2.default.string.isRequired,
isCollapsed: _propTypes2.default.func.isRequired,
keyPath: _propTypes2.default.array,
deep: _propTypes2.default.number,
handleRemove: _propTypes2.default.func,
onUpdate: _propTypes2.default.func.isRequired,
onDeltaUpdate: _propTypes2.default.func.isRequired,
readOnly: _propTypes2.default.func.isRequired,
dataType: _propTypes2.default.string,
getStyle: _propTypes2.default.func.isRequired,
addButtonElement: _propTypes2.default.element,
cancelButtonElement: _propTypes2.default.element,
editButtonElement: _propTypes2.default.element,
inputElementGenerator: _propTypes2.default.func.isRequired,
textareaElementGenerator: _propTypes2.default.func.isRequired,
minusMenuElement: _propTypes2.default.element,
plusMenuElement: _propTypes2.default.element,
beforeRemoveAction: _propTypes2.default.func,
beforeAddAction: _propTypes2.default.func,
beforeUpdateAction: _propTypes2.default.func,
logger: _propTypes2.default.object.isRequired,
onSubmitValueParser: _propTypes2.default.func.isRequired
};
// Default props
var defaultProps = {
keyPath: [],
deep: 0,
minusMenuElement: _react2.default.createElement(
'span',
null,
' - '
),
plusMenuElement: _react2.default.createElement(
'span',
null,
' + '
)
};
/* ************************************* */
/* ******** COMPONENT ******** */
/* ************************************* */
var JsonArray = function (_Component) {
(0, _inherits3.default)(JsonArray, _Component);
function JsonArray(props) {
(0, _classCallCheck3.default)(this, JsonArray);
var _this = (0, _possibleConstructorReturn3.default)(this, (JsonArray.__proto__ || (0, _getPrototypeOf2.default)(JsonArray)).call(this, props));
var keyPath = [].concat((0, _toConsumableArray3.default)(props.keyPath), [props.name]);
_this.state = {
data: props.data,
name: props.name,
keyPath: keyPath,
deep: props.deep,
nextDeep: props.deep + 1,
collapsed: props.isCollapsed(keyPath, props.deep, props.data),
addFormVisible: false
};
// Bind
_this.handleCollapseMode = _this.handleCollapseMode.bind(_this);
_this.handleRemoveItem = _this.handleRemoveItem.bind(_this);
_this.handleAddMode = _this.handleAddMode.bind(_this);
_this.handleAddValueAdd = _this.handleAddValueAdd.bind(_this);
_this.handleAddValueCancel = _this.handleAddValueCancel.bind(_this);
_this.handleEditValue = _this.handleEditValue.bind(_this);
_this.onChildUpdate = _this.onChildUpdate.bind(_this);
_this.renderCollapsed = _this.renderCollapsed.bind(_this);
_this.renderNotCollapsed = _this.renderNotCollapsed.bind(_this);
return _this;
}
(0, _createClass3.default)(JsonArray, [{
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
this.setState({
data: nextProps.data
});
}
}, {
key: 'onChildUpdate',
value: function onChildUpdate(childKey, childData) {
var _state = this.state,
data = _state.data,
keyPath = _state.keyPath;
// Update data
data[childKey] = childData;
// Put new data
this.setState({
data: data
});
// Spread
var onUpdate = this.props.onUpdate;
var size = keyPath.length;
onUpdate(keyPath[size - 1], data);
}
}, {
key: 'handleAddMode',
value: function handleAddMode() {
this.setState({
addFormVisible: true
});
}
}, {
key: 'handleCollapseMode',
value: function handleCollapseMode() {
this.setState({
collapsed: !this.state.collapsed
});
}
}, {
key: 'handleRemoveItem',
value: function handleRemoveItem(index) {
var _this2 = this;
return function () {
var _props = _this2.props,
beforeRemoveAction = _props.beforeRemoveAction,
logger = _props.logger;
var _state2 = _this2.state,
data = _state2.data,
keyPath = _state2.keyPath,
deep = _state2.nextDeep;
var oldValue = data[index];
// Before Remove Action
beforeRemoveAction(index, keyPath, deep, oldValue).then(function () {
var objType = (0, _objectTypes.getObjectType)(data[index]);
var deltaUpdateResult = {
keyPath: keyPath,
deep: deep,
key: index,
oldValue: oldValue
};
if (objType === 'Object' || objType === 'Array') {
deltaUpdateResult.type = _deltaTypes.UPDATE_DELTA_TYPE;
deltaUpdateResult.newValue = null;
data[index] = null;
} else {
deltaUpdateResult.type = _deltaTypes.REMOVE_DELTA_TYPE;
data.splice(index, 1);
}
_this2.setState({
data: data
});
// Spread new update
var _props2 = _this2.props,
onUpdate = _props2.onUpdate,
onDeltaUpdate = _props2.onDeltaUpdate;
onUpdate(keyPath[keyPath.length - 1], data);
// Spread delta update
onDeltaUpdate(deltaUpdateResult);
}).catch(logger.error);
};
}
}, {
key: 'handleAddValueAdd',
value: function handleAddValueAdd(_ref) {
var _this3 = this;
var newValue = _ref.newValue;
var _state3 = this.state,
data = _state3.data,
keyPath = _state3.keyPath,
deep = _state3.nextDeep;
var _props3 = this.props,
beforeAddAction = _props3.beforeAddAction,
logger = _props3.logger;
beforeAddAction(data.length, keyPath, deep, newValue).then(function () {
// Update data
var newData = [].concat((0, _toConsumableArray3.default)(data), [newValue]);
_this3.setState({
data: newData
});
// Cancel add to close
_this3.handleAddValueCancel();
// Spread new update
var _props4 = _this3.props,
onUpdate = _props4.onUpdate,
onDeltaUpdate = _props4.onDeltaUpdate;
onUpdate(keyPath[keyPath.length - 1], newData);
// Spread delta update
onDeltaUpdate({
type: _deltaTypes.ADD_DELTA_TYPE,
keyPath: keyPath,
deep: deep,
key: newData.length - 1,
newValue: newValue
});
}).catch(logger.error);
}
}, {
key: 'handleAddValueCancel',
value: function handleAddValueCancel() {
this.setState({
addFormVisible: false
});
}
}, {
key: 'handleEditValue',
value: function handleEditValue(_ref2) {
var _this4 = this;
var key = _ref2.key,
value = _ref2.value;
return new _promise2.default(function (resolve, reject) {
var beforeUpdateAction = _this4.props.beforeUpdateAction;
var _state4 = _this4.state,
data = _state4.data,
keyPath = _state4.keyPath,
deep = _state4.nextDeep;
// Old value
var oldValue = data[key];
// Before update action
beforeUpdateAction(key, keyPath, deep, oldValue, value).then(function () {
// Update value
data[key] = value;
// Set state
_this4.setState({
data: data
});
// Spread new update
var _props5 = _this4.props,
onUpdate = _props5.onUpdate,
onDeltaUpdate = _props5.onDeltaUpdate;
onUpdate(keyPath[keyPath.length - 1], data);
// Spread delta update
onDeltaUpdate({
type: _deltaTypes.UPDATE_DELTA_TYPE,
keyPath: keyPath,
deep: deep,
key: key,
newValue: value,
oldValue: oldValue
});
// Resolve
resolve();
}).catch(reject);
});
}
}, {
key: 'renderCollapsed',
value: function renderCollapsed() {
var _state5 = this.state,
name = _state5.name,
data = _state5.data,
keyPath = _state5.keyPath,
deep = _state5.deep;
var _props6 = this.props,
handleRemove = _props6.handleRemove,
readOnly = _props6.readOnly,
getStyle = _props6.getStyle,
dataType = _props6.dataType,
minusMenuElement = _props6.minusMenuElement;
var _getStyle = getStyle(name, data, keyPath, deep, dataType),
minus = _getStyle.minus,
collapsed = _getStyle.collapsed;
var collapseValue = ' [...]';
var numberOfItems = data.length;
var minusElement = null;
// Check if readOnly is activated
if (!readOnly(name, data, keyPath, deep, dataType)) {
var minusMenuLayout = _react2.default.cloneElement(minusMenuElement, {
onClick: handleRemove,
className: 'rejt-minus-menu',
style: minus
});
minusElement = deep !== -1 ? minusMenuLayout : null;
}
var itemName = numberOfItems > 1 ? 'items' : 'item';
/* eslint-disable jsx-a11y/no-static-element-interactions */
return _react2.default.createElement(
'span',
{ className: 'rejt-collapsed' },
_react2.default.createElement(
'span',
{ className: 'rejt-collapsed-text', style: collapsed, onClick: this.handleCollapseMode },
collapseValue,
' ',
numberOfItems,
' ',
itemName
),
minusElement
);
/* eslint-enable */
}
}, {
key: 'renderNotCollapsed',
value: function renderNotCollapsed() {
var _this5 = this;
var _state6 = this.state,
name = _state6.name,
data = _state6.data,
keyPath = _state6.keyPath,
deep = _state6.deep,
addFormVisible = _state6.addFormVisible,
nextDeep = _state6.nextDeep;
var _props7 = this.props,
isCollapsed = _props7.isCollapsed,
handleRemove = _props7.handleRemove,
onDeltaUpdate = _props7.onDeltaUpdate,
readOnly = _props7.readOnly,
getStyle = _props7.getStyle,
dataType = _props7.dataType,
addButtonElement = _props7.addButtonElement,
cancelButtonElement = _props7.cancelButtonElement,
editButtonElement = _props7.editButtonElement,
inputElementGenerator = _props7.inputElementGenerator,
textareaElementGenerator = _props7.textareaElementGenerator,
minusMenuElement = _props7.minusMenuElement,
plusMenuElement = _props7.plusMenuElement,
beforeRemoveAction = _props7.beforeRemoveAction,
beforeAddAction = _props7.beforeAddAction,
beforeUpdateAction = _props7.beforeUpdateAction,
logger = _props7.logger,
onSubmitValueParser = _props7.onSubmitValueParser;
var _getStyle2 = getStyle(name, data, keyPath, deep, dataType),
minus = _getStyle2.minus,
plus = _getStyle2.plus,
delimiter = _getStyle2.delimiter,
ul = _getStyle2.ul,
addForm = _getStyle2.addForm;
var minusElement = null;
var readOnlyResult = readOnly(name, data, keyPath, deep, dataType);
// Check if readOnly is activated
if (!readOnlyResult) {
var minusMenuLayout = _react2.default.cloneElement(minusMenuElement, {
onClick: handleRemove,
className: 'rejt-minus-menu',
style: minus
});
minusElement = deep !== -1 ? minusMenuLayout : null;
}
var list = data.map(function (item, index) {
return _react2.default.createElement(_JsonNode2.default, {
key: index,
name: '' + index,
data: item,
keyPath: keyPath,
deep: nextDeep,
isCollapsed: isCollapsed,
handleRemove: _this5.handleRemoveItem(index),
handleUpdateValue: _this5.handleEditValue,
onUpdate: _this5.onChildUpdate,
onDeltaUpdate: onDeltaUpdate,
readOnly: readOnly,
getStyle: getStyle,
addButtonElement: addButtonElement,
cancelButtonElement: cancelButtonElement,
editButtonElement: editButtonElement,
inputElementGenerator: inputElementGenerator,
textareaElementGenerator: textareaElementGenerator,
minusMenuElement: minusMenuElement,
plusMenuElement: plusMenuElement,
beforeRemoveAction: beforeRemoveAction,
beforeAddAction: beforeAddAction,
beforeUpdateAction: beforeUpdateAction,
logger: logger,
onSubmitValueParser: onSubmitValueParser
});
});
var onlyValue = true;
var menu = null;
// Check if readOnly is activated
if (!readOnlyResult) {
var plusMenuLayout = _react2.default.cloneElement(plusMenuElement, {
onClick: this.handleAddMode,
className: 'rejt-plus-menu',
style: plus
});
menu = addFormVisible ? _react2.default.createElement(
'span',
{ className: 'rejt-add-form', style: addForm },
_react2.default.createElement(_JsonAddValue2.default, {
handleAdd: this.handleAddValueAdd,
handleCancel: this.handleAddValueCancel,
onlyValue: onlyValue,
addButtonElement: addButtonElement,
cancelButtonElement: cancelButtonElement,
inputElementGenerator: inputElementGenerator,
keyPath: keyPath,
deep: deep,
onSubmitValueParser: onSubmitValueParser
})
) : _react2.default.createElement(
'span',
null,
plusMenuLayout,
' ',
minusElement
);
}
var startObject = '[';
var endObject = ']';
return _react2.default.createElement(
'span',
{ className: 'rejt-not-collapsed' },
_react2.default.createElement(
'span',
{ className: 'rejt-not-collapsed-delimiter', style: delimiter },
startObject
),
_react2.default.createElement(
'ul',
{ className: 'rejt-not-collapsed-list', style: ul },
list
),
_react2.default.createElement(
'span',
{ className: 'rejt-not-collapsed-delimiter', style: delimiter },
endObject
),
menu
);
}
}, {
key: 'render',
value: function render() {
var _state7 = this.state,
name = _state7.name,
collapsed = _state7.collapsed,
data = _state7.data,
keyPath = _state7.keyPath,
deep = _state7.deep;
var _props8 = this.props,
dataType = _props8.dataType,
getStyle = _props8.getStyle;
var value = collapsed ? this.renderCollapsed() : this.renderNotCollapsed();
var style = getStyle(name, data, keyPath, deep, dataType);
/* eslint-disable jsx-a11y/no-static-element-interactions */
return _react2.default.createElement(
'div',
{ className: 'rejt-array-node' },
_react2.default.createElement(
'span',
{ onClick: this.handleCollapseMode },
_react2.default.createElement(
'span',
{ className: 'rejt-name', style: style.name },
name,
' : '
)
),
value
);
/* eslint-enable */
}
}]);
return JsonArray;
}(_react.Component);
// Add prop types
JsonArray.propTypes = propTypes;
// Add default props
JsonArray.defaultProps = defaultProps;
/* ************************************* */
/* ******** EXPORTS ******** */
/* ************************************* */
exports.default = JsonArray;