UNPKG

keystone

Version:

Web Application Framework and Admin GUI / Content Management System built on Express.js and Mongoose

128 lines (111 loc) 3.41 kB
var React = require('react'); import _ from 'lodash'; import { findDOMNode } from 'react-dom'; var Button = require('elemental').Button; var FormField = require('elemental').FormField; var FormInput = require('elemental').FormInput; var lastId = 0; var ENTER_KEYCODE = 13; function newItem (value) { lastId = lastId + 1; return { key: 'i' + lastId, value: value }; } function reduceValues (values) { return values.map(i => i.value); } module.exports = { getInitialState: function () { return { values: Array.isArray(this.props.value) ? this.props.value.map(newItem) : [], }; }, componentWillReceiveProps: function (nextProps) { if (nextProps.value.join('|') !== reduceValues(this.state.values).join('|')) { this.setState({ values: nextProps.value.map(newItem), }); } }, addItem: function () { var newValues = this.state.values.concat(newItem('')); this.setState({ values: newValues, }, () => { if (!this.state.values.length) return; findDOMNode(this.refs['item_' + this.state.values.length]).focus(); }); this.valueChanged(reduceValues(newValues)); }, removeItem: function (i) { var newValues = _.without(this.state.values, i); this.setState({ values: newValues, }, function () { findDOMNode(this.refs.button).focus(); }); this.valueChanged(reduceValues(newValues)); }, updateItem: function (i, event) { var updatedValues = this.state.values; var updateIndex = updatedValues.indexOf(i); var newValue = event.value || event.target.value; if (this.isValid === undefined || this.isValid(newValue)) { updatedValues[updateIndex].value = this.cleanInput ? this.cleanInput(newValue) : newValue; } this.setState({ values: updatedValues, }); this.valueChanged(reduceValues(updatedValues)); }, valueChanged: function (values) { this.props.onChange({ path: this.props.path, value: values, }); }, renderField: function () { return ( <div> {this.state.values.map(this.renderItem)} <Button ref="button" onClick={this.addItem}>Add item</Button> </div> ); }, renderItem: function (item, index) { const Input = this.getInputComponent ? this.getInputComponent() : FormInput; const value = this.processInputValue ? this.processInputValue(item.value) : item.value; return ( <FormField key={item.key}> <Input ref={'item_' + (index + 1)} name={this.getInputName(this.props.path)} value={value} onChange={this.updateItem.bind(this, item)} onKeyDown={this.addItemOnEnter} autoComplete="off" /> <Button type="link-cancel" onClick={this.removeItem.bind(this, item)} className="keystone-relational-button"> <span className="octicon octicon-x" /> </Button> </FormField> ); }, renderValue: function () { const Input = this.getInputComponent ? this.getInputComponent() : FormInput; return ( <div> {this.state.values.map((item, i) => { const value = this.formatValue ? this.formatValue(item.value) : item.value; return ( <div key={i} style={i ? { marginTop: '1em' } : null}> <Input noedit value={value} /> </div> ); })} </div> ); }, // Override shouldCollapse to check for array length shouldCollapse: function () { return this.props.collapse && !this.props.value.length; }, addItemOnEnter: function (event) { if (event.keyCode === ENTER_KEYCODE) { this.addItem(); event.preventDefault(); } }, };