Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spike using textarea instead of codemirror #107

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ node_modules
/live
/demo/test.html
/build-docs
/build
.DS_Store
.tern-port
*~
Expand Down
173 changes: 173 additions & 0 deletions build/lib/components/fields/array.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// # array component

/*
Render a field to edit array values.
*/

'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _createReactClass = require('create-react-class');

var _createReactClass2 = _interopRequireDefault(_createReactClass);

var _classnames = require('classnames');

var _classnames2 = _interopRequireDefault(_classnames);

var _field = require('../../mixins/field');

var _field2 = _interopRequireDefault(_field);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

exports.default = (0, _createReactClass2.default)({

displayName: 'Array',

mixins: [_field2.default],

nextLookupId: 0,

getInitialState: function getInitialState() {

// Need to create artificial keys for the array. Indexes are not good keys,
// since they change. So, map each position to an artificial key
var lookups = [];

var items = this.props.field.value;
if (!Array.isArray(items)) {
if (items !== null && items !== undefined) {
items = [items];
} else {
items = [];
}
}

items.forEach(function (item, i) {
lookups[i] = '_' + this.nextLookupId;
this.nextLookupId++;
}.bind(this));

return {
lookups: lookups
};
},

componentWillReceiveProps: function componentWillReceiveProps(newProps) {

var lookups = this.state.lookups;

var items = newProps.field.value;

// Need to set artificial keys for new array items.
if (items.length > lookups.length) {
for (var i = lookups.length; i < items.length; i++) {
lookups[i] = '_' + this.nextLookupId;
this.nextLookupId++;
}
}

this.setState({
lookups: lookups
});
},

onChange: function onChange(i, newValue, info) {
var newArrayValue = this.props.field.value.slice(0);
newArrayValue[i] = newValue;
this.onBubbleValue(newArrayValue, info);
},

onAppend: function onAppend(itemChoiceIndex) {
var config = this.props.config;
var field = this.props.field;

var newValue = config.createNewChildFieldValue(field, itemChoiceIndex);

var items = field.value;

items = items.concat(newValue);

this.onChangeValue(items);
},

onRemove: function onRemove(i) {
var lookups = this.state.lookups;
lookups.splice(i, 1);
this.setState({
lookups: lookups
});
var newItems = this.props.field.value.slice(0);
newItems.splice(i, 1);
this.onChangeValue(newItems);
},

onMove: function onMove(fromIndex, toIndex) {
var lookups = this.state.lookups;
var fromId = lookups[fromIndex];
var toId = lookups[toIndex];
lookups[fromIndex] = toId;
lookups[toIndex] = fromId;
this.setState({
lookups: lookups
});

var newItems = this.props.field.value.slice(0);
if (fromIndex !== toIndex && fromIndex >= 0 && fromIndex < newItems.length && toIndex >= 0 && toIndex < newItems.length) {
newItems.splice(toIndex, 0, newItems.splice(fromIndex, 1)[0]);
}
this.onChangeValue(newItems);
},

render: function render() {
return this.renderWithConfig();
},

renderDefault: function renderDefault() {

var config = this.props.config;
var field = this.props.field;

var fields = config.createChildFields(field);

var arrayControl = void 0;
if (!config.fieldIsReadOnly(field)) {
arrayControl = config.createElement('array-control', { field: field, onAppend: this.onAppend });
}

var tabIndex = this.isReadOnly() ? null : this.props.tabIndex || 0;

var numItems = field.value.length;

var content = config.cssTransitionWrapper(fields.map(function (childField, i) {
return config.createElement('array-item', {
key: this.state.lookups[i],
field: childField,
index: i,
numItems: numItems,
onMove: this.onMove,
onRemove: this.onRemove,
onChange: this.onChange,
onAction: this.onBubbleAction
});
}.bind(this)));

return config.createElement('field', {
field: field,
plain: this.props.plain
}, _react2.default.createElement(
'div',
{ className: (0, _classnames2.default)(this.props.classes), tabIndex: tabIndex },
content,
arrayControl
));
}
});
170 changes: 170 additions & 0 deletions build/lib/components/fields/assoc-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// # object component

/*
Render a field to edit a array of key / value objects, where duplicate keys are allowed.
*/

'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _createReactClass = require('create-react-class');

var _createReactClass2 = _interopRequireDefault(_createReactClass);

var _classnames = require('classnames');

var _classnames2 = _interopRequireDefault(_classnames);

var _immutabilityHelper = require('immutability-helper');

var _immutabilityHelper2 = _interopRequireDefault(_immutabilityHelper);

var _field = require('../../mixins/field');

var _field2 = _interopRequireDefault(_field);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var keyCountsByKey = function keyCountsByKey(assocList) {
var counts = {};
assocList.forEach(function (row) {
if (!counts[row.key]) {
counts[row.key] = 0;
}
counts[row.key] += 1;
});
return counts;
};

exports.default = (0, _createReactClass2.default)({

displayName: 'AssocList',

mixins: [_field2.default],

nextLookupId: 0,

getNextLookupId: function getNextLookupId() {
return '_' + this.nextLookupId++;
},
getInitialState: function getInitialState() {
var _this = this;

var field = this.props.field;

// maintain artificial keys, keyed by row index, to have persistent key
var lookups = [];
field.value.forEach(function (row, i) {
lookups[i] = _this.getNextLookupId();
});

return { lookups: lookups };
},
componentWillReceiveProps: function componentWillReceiveProps(newProps) {
var rows = newProps.field.value;

// set artificial keys for new rows
if (rows.length > this.state.lookups.length) {
var lookupsToPush = [];
for (var i = this.state.lookups.length; i < rows.length; i++) {
lookupsToPush.push(this.getNextLookupId());
}
var lookups = (0, _immutabilityHelper2.default)(this.state.lookups, {
$push: lookupsToPush
});
this.setState({ lookups: lookups });
}
},
onChange: function onChange(index, newValue) {
var field = this.props.field;

var updatedRow = { key: field.value[index].key, value: newValue };
var rows = (0, _immutabilityHelper2.default)(field.value, {
$splice: [[index, 1, updatedRow]]
});

// this.onBubbleValue(rows, info);
this.onChangeValue(rows);
},
onAppend: function onAppend() {
var field = this.props.field;

var newRow = { key: '', value: '' };
var rows = (0, _immutabilityHelper2.default)(field.value, {
$push: [newRow]
});

// componentWillReceiveProps will add the new artificial key to lookups
this.onChangeValue(rows);
},
onRemove: function onRemove(index) {
var field = this.props.field;

// componentWillReceiveProps can't know which item was deleted, so
// put new artificial key in lookups here
var lookups = (0, _immutabilityHelper2.default)(this.state.lookups, {
$splice: [[index, 1]]
});
this.setState({ lookups: lookups });

var rows = (0, _immutabilityHelper2.default)(field.value, {
$splice: [[index, 1]]
});
this.onChangeValue(rows);
},
onChangeKey: function onChangeKey(index, newKey) {
var field = this.props.field;

var updatedRow = { key: newKey, value: field.value[index].value };
var rows = (0, _immutabilityHelper2.default)(field.value, {
$splice: [[index, 1, updatedRow]]
});

this.onChangeValue(rows);
},
render: function render() {
return this.renderWithConfig();
},
renderDefault: function renderDefault() {
var config = this.props.config;
var field = this.props.field;
var fields = config.createChildFields(field);
var keyCounts = keyCountsByKey(field.value);

var content = config.cssTransitionWrapper(field.value.map(function (row, i) {
return config.createElement('assoc-list-item', {
key: this.state.lookups[i],
index: i,
displayKey: row.key,
field: fields[i],
isDuplicateKey: keyCounts[row.key] > 1,
onChangeKey: this.onChangeKey,
onChange: this.onChange,
onRemove: this.onRemove,
onAction: this.onBubbleAction
});
}.bind(this)));

var assocList = config.createElement('assoc-list-control', {
field: field,
onAppend: this.onAppend
});

return config.createElement('field', {
field: field,
plain: this.props.plain
}, _react2.default.createElement(
'div',
{ className: (0, _classnames2.default)(this.props.classes) },
content,
assocList
));
}
});
Loading