'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties'); var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2); var _defineProperty2 = require('babel-runtime/helpers/defineProperty'); var _defineProperty3 = _interopRequireDefault(_defineProperty2); var _extends5 = require('babel-runtime/helpers/extends'); var _extends6 = _interopRequireDefault(_extends5); var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray'); var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _createReactClass = require('create-react-class'); var _createReactClass2 = _interopRequireDefault(_createReactClass); var _unsafeLifecyclesPolyfill = require('rc-util/lib/unsafeLifecyclesPolyfill'); var _unsafeLifecyclesPolyfill2 = _interopRequireDefault(_unsafeLifecyclesPolyfill); var _asyncValidator = require('async-validator'); var _asyncValidator2 = _interopRequireDefault(_asyncValidator); var _warning = require('warning'); var _warning2 = _interopRequireDefault(_warning); var _get = require('lodash/get'); var _get2 = _interopRequireDefault(_get); var _set = require('lodash/set'); var _set2 = _interopRequireDefault(_set); var _eq = require('lodash/eq'); var _eq2 = _interopRequireDefault(_eq); var _createFieldsStore = require('./createFieldsStore'); var _createFieldsStore2 = _interopRequireDefault(_createFieldsStore); var _utils = require('./utils'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } /* eslint-disable react/prefer-es6-class */ /* eslint-disable prefer-promise-reject-errors */ var DEFAULT_TRIGGER = 'onChange'; function createBaseForm() { var option = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var mixins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; var validateMessages = option.validateMessages, onFieldsChange = option.onFieldsChange, onValuesChange = option.onValuesChange, _option$mapProps = option.mapProps, mapProps = _option$mapProps === undefined ? _utils.identity : _option$mapProps, mapPropsToFields = option.mapPropsToFields, fieldNameProp = option.fieldNameProp, fieldMetaProp = option.fieldMetaProp, fieldDataProp = option.fieldDataProp, _option$formPropName = option.formPropName, formPropName = _option$formPropName === undefined ? 'form' : _option$formPropName, formName = option.name, withRef = option.withRef; return function decorate(WrappedComponent) { var Form = (0, _createReactClass2['default'])({ displayName: 'Form', mixins: mixins, getInitialState: function getInitialState() { var _this = this; var fields = mapPropsToFields && mapPropsToFields(this.props); this.fieldsStore = (0, _createFieldsStore2['default'])(fields || {}); this.instances = {}; this.cachedBind = {}; this.clearedFieldMetaCache = {}; this.renderFields = {}; this.domFields = {}; // HACK: https://github.com/ant-design/ant-design/issues/6406 ['getFieldsValue', 'getFieldValue', 'setFieldsInitialValue', 'getFieldsError', 'getFieldError', 'isFieldValidating', 'isFieldsValidating', 'isFieldsTouched', 'isFieldTouched'].forEach(function (key) { _this[key] = function () { var _fieldsStore; if (process.env.NODE_ENV !== 'production') { (0, _warning2['default'])(false, 'you should not use `ref` on enhanced form, please use `wrappedComponentRef`. ' + 'See: https://github.com/react-component/form#note-use-wrappedcomponentref-instead-of-withref-after-rc-form140'); } return (_fieldsStore = _this.fieldsStore)[key].apply(_fieldsStore, arguments); }; }); return { submitting: false }; }, componentDidMount: function componentDidMount() { this.cleanUpUselessFields(); }, componentWillReceiveProps: function componentWillReceiveProps(nextProps) { if (mapPropsToFields) { this.fieldsStore.updateFields(mapPropsToFields(nextProps)); } }, componentDidUpdate: function componentDidUpdate() { this.cleanUpUselessFields(); }, onCollectCommon: function onCollectCommon(name, action, args) { var fieldMeta = this.fieldsStore.getFieldMeta(name); if (fieldMeta[action]) { fieldMeta[action].apply(fieldMeta, (0, _toConsumableArray3['default'])(args)); } else if (fieldMeta.originalProps && fieldMeta.originalProps[action]) { var _fieldMeta$originalPr; (_fieldMeta$originalPr = fieldMeta.originalProps)[action].apply(_fieldMeta$originalPr, (0, _toConsumableArray3['default'])(args)); } var value = fieldMeta.getValueFromEvent ? fieldMeta.getValueFromEvent.apply(fieldMeta, (0, _toConsumableArray3['default'])(args)) : _utils.getValueFromEvent.apply(undefined, (0, _toConsumableArray3['default'])(args)); if (onValuesChange && value !== this.fieldsStore.getFieldValue(name)) { var valuesAll = this.fieldsStore.getAllValues(); var valuesAllSet = {}; valuesAll[name] = value; Object.keys(valuesAll).forEach(function (key) { return (0, _set2['default'])(valuesAllSet, key, valuesAll[key]); }); onValuesChange((0, _extends6['default'])((0, _defineProperty3['default'])({}, formPropName, this.getForm()), this.props), (0, _set2['default'])({}, name, value), valuesAllSet); } var field = this.fieldsStore.getField(name); return { name: name, field: (0, _extends6['default'])({}, field, { value: value, touched: true }), fieldMeta: fieldMeta }; }, onCollect: function onCollect(name_, action) { for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { args[_key - 2] = arguments[_key]; } var _onCollectCommon = this.onCollectCommon(name_, action, args), name = _onCollectCommon.name, field = _onCollectCommon.field, fieldMeta = _onCollectCommon.fieldMeta; var validate = fieldMeta.validate; this.fieldsStore.setFieldsAsDirty(); var newField = (0, _extends6['default'])({}, field, { dirty: (0, _utils.hasRules)(validate) }); this.setFields((0, _defineProperty3['default'])({}, name, newField)); }, onCollectValidate: function onCollectValidate(name_, action) { for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { args[_key2 - 2] = arguments[_key2]; } var _onCollectCommon2 = this.onCollectCommon(name_, action, args), field = _onCollectCommon2.field, fieldMeta = _onCollectCommon2.fieldMeta; var newField = (0, _extends6['default'])({}, field, { dirty: true }); this.fieldsStore.setFieldsAsDirty(); this.validateFieldsInternal([newField], { action: action, options: { firstFields: !!fieldMeta.validateFirst } }); }, getCacheBind: function getCacheBind(name, action, fn) { if (!this.cachedBind[name]) { this.cachedBind[name] = {}; } var cache = this.cachedBind[name]; if (!cache[action] || cache[action].oriFn !== fn) { cache[action] = { fn: fn.bind(this, name, action), oriFn: fn }; } return cache[action].fn; }, getFieldDecorator: function getFieldDecorator(name, fieldOption) { var _this2 = this; var props = this.getFieldProps(name, fieldOption); return function (fieldElem) { // We should put field in record if it is rendered _this2.renderFields[name] = true; var fieldMeta = _this2.fieldsStore.getFieldMeta(name); var originalProps = fieldElem.props; if (process.env.NODE_ENV !== 'production') { var valuePropName = fieldMeta.valuePropName; (0, _warning2['default'])(!(valuePropName in originalProps), '`getFieldDecorator` will override `' + valuePropName + '`, ' + ('so please don\'t set `' + valuePropName + '` directly ') + 'and use `setFieldsValue` to set it.'); var defaultValuePropName = 'default' + valuePropName[0].toUpperCase() + valuePropName.slice(1); (0, _warning2['default'])(!(defaultValuePropName in originalProps), '`' + defaultValuePropName + '` is invalid ' + ('for `getFieldDecorator` will set `' + valuePropName + '`,') + ' please use `option.initialValue` instead.'); } fieldMeta.originalProps = originalProps; fieldMeta.ref = fieldElem.ref; return _react2['default'].cloneElement(fieldElem, (0, _extends6['default'])({}, props, _this2.fieldsStore.getFieldValuePropValue(fieldMeta))); }; }, getFieldProps: function getFieldProps(name) { var _this3 = this; var usersFieldOption = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (!name) { throw new Error('Must call `getFieldProps` with valid name string!'); } if (process.env.NODE_ENV !== 'production') { (0, _warning2['default'])(this.fieldsStore.isValidNestedFieldName(name), 'One field name cannot be part of another, e.g. `a` and `a.b`. Check field: ' + name); (0, _warning2['default'])(!('exclusive' in usersFieldOption), '`option.exclusive` of `getFieldProps`|`getFieldDecorator` had been remove.'); } delete this.clearedFieldMetaCache[name]; var fieldOption = (0, _extends6['default'])({ name: name, trigger: DEFAULT_TRIGGER, valuePropName: 'value', validate: [] }, usersFieldOption); var rules = fieldOption.rules, trigger = fieldOption.trigger, _fieldOption$validate = fieldOption.validateTrigger, validateTrigger = _fieldOption$validate === undefined ? trigger : _fieldOption$validate, validate = fieldOption.validate; var fieldMeta = this.fieldsStore.getFieldMeta(name); if ('initialValue' in fieldOption) { fieldMeta.initialValue = fieldOption.initialValue; } var inputProps = (0, _extends6['default'])({}, this.fieldsStore.getFieldValuePropValue(fieldOption), { ref: this.getCacheBind(name, name + '__ref', this.saveRef) }); if (fieldNameProp) { inputProps[fieldNameProp] = formName ? formName + '_' + name : name; } var validateRules = (0, _utils.normalizeValidateRules)(validate, rules, validateTrigger); var validateTriggers = (0, _utils.getValidateTriggers)(validateRules); validateTriggers.forEach(function (action) { if (inputProps[action]) return; inputProps[action] = _this3.getCacheBind(name, action, _this3.onCollectValidate); }); // make sure that the value will be collect if (trigger && validateTriggers.indexOf(trigger) === -1) { inputProps[trigger] = this.getCacheBind(name, trigger, this.onCollect); } var meta = (0, _extends6['default'])({}, fieldMeta, fieldOption, { validate: validateRules }); this.fieldsStore.setFieldMeta(name, meta); if (fieldMetaProp) { inputProps[fieldMetaProp] = meta; } if (fieldDataProp) { inputProps[fieldDataProp] = this.fieldsStore.getField(name); } // This field is rendered, record it this.renderFields[name] = true; return inputProps; }, getFieldInstance: function getFieldInstance(name) { return this.instances[name]; }, getRules: function getRules(fieldMeta, action) { var actionRules = fieldMeta.validate.filter(function (item) { return !action || item.trigger.indexOf(action) >= 0; }).map(function (item) { return item.rules; }); return (0, _utils.flattenArray)(actionRules); }, setFields: function setFields(maybeNestedFields, callback) { var _this4 = this; var fields = this.fieldsStore.flattenRegisteredFields(maybeNestedFields); this.fieldsStore.setFields(fields); if (onFieldsChange) { var changedFields = Object.keys(fields).reduce(function (acc, name) { return (0, _set2['default'])(acc, name, _this4.fieldsStore.getField(name)); }, {}); onFieldsChange((0, _extends6['default'])((0, _defineProperty3['default'])({}, formPropName, this.getForm()), this.props), changedFields, this.fieldsStore.getNestedAllFields()); } this.forceUpdate(callback); }, setFieldsValue: function setFieldsValue(changedValues, callback) { var fieldsMeta = this.fieldsStore.fieldsMeta; var values = this.fieldsStore.flattenRegisteredFields(changedValues); var newFields = Object.keys(values).reduce(function (acc, name) { var isRegistered = fieldsMeta[name]; if (process.env.NODE_ENV !== 'production') { (0, _warning2['default'])(isRegistered, 'Cannot use `setFieldsValue` until ' + 'you use `getFieldDecorator` or `getFieldProps` to register it.'); } if (isRegistered) { var value = values[name]; acc[name] = { value: value }; } return acc; }, {}); this.setFields(newFields, callback); if (onValuesChange) { var allValues = this.fieldsStore.getAllValues(); onValuesChange((0, _extends6['default'])((0, _defineProperty3['default'])({}, formPropName, this.getForm()), this.props), changedValues, allValues); } }, saveRef: function saveRef(name, _, component) { if (!component) { var _fieldMeta = this.fieldsStore.getFieldMeta(name); if (!_fieldMeta.preserve) { // after destroy, delete data this.clearedFieldMetaCache[name] = { field: this.fieldsStore.getField(name), meta: _fieldMeta }; this.clearField(name); } delete this.domFields[name]; return; } this.domFields[name] = true; this.recoverClearedField(name); var fieldMeta = this.fieldsStore.getFieldMeta(name); if (fieldMeta) { var ref = fieldMeta.ref; if (ref) { if (typeof ref === 'string') { throw new Error('can not set ref string for ' + name); } else if (typeof ref === 'function') { ref(component); } else if (Object.prototype.hasOwnProperty.call(ref, 'current')) { ref.current = component; } } } this.instances[name] = component; }, cleanUpUselessFields: function cleanUpUselessFields() { var _this5 = this; var fieldList = this.fieldsStore.getAllFieldsName(); var removedList = fieldList.filter(function (field) { var fieldMeta = _this5.fieldsStore.getFieldMeta(field); return !_this5.renderFields[field] && !_this5.domFields[field] && !fieldMeta.preserve; }); if (removedList.length) { removedList.forEach(this.clearField); } this.renderFields = {}; }, clearField: function clearField(name) { this.fieldsStore.clearField(name); delete this.instances[name]; delete this.cachedBind[name]; }, resetFields: function resetFields(ns) { var _this6 = this; var newFields = this.fieldsStore.resetFields(ns); if (Object.keys(newFields).length > 0) { this.setFields(newFields); } if (ns) { var names = Array.isArray(ns) ? ns : [ns]; names.forEach(function (name) { return delete _this6.clearedFieldMetaCache[name]; }); } else { this.clearedFieldMetaCache = {}; } }, recoverClearedField: function recoverClearedField(name) { if (this.clearedFieldMetaCache[name]) { this.fieldsStore.setFields((0, _defineProperty3['default'])({}, name, this.clearedFieldMetaCache[name].field)); this.fieldsStore.setFieldMeta(name, this.clearedFieldMetaCache[name].meta); delete this.clearedFieldMetaCache[name]; } }, validateFieldsInternal: function validateFieldsInternal(fields, _ref, callback) { var _this7 = this; var fieldNames = _ref.fieldNames, action = _ref.action, _ref$options = _ref.options, options = _ref$options === undefined ? {} : _ref$options; var allRules = {}; var allValues = {}; var allFields = {}; var alreadyErrors = {}; fields.forEach(function (field) { var name = field.name; if (options.force !== true && field.dirty === false) { if (field.errors) { (0, _set2['default'])(alreadyErrors, name, { errors: field.errors }); } return; } var fieldMeta = _this7.fieldsStore.getFieldMeta(name); var newField = (0, _extends6['default'])({}, field); newField.errors = undefined; newField.validating = true; newField.dirty = true; allRules[name] = _this7.getRules(fieldMeta, action); allValues[name] = newField.value; allFields[name] = newField; }); this.setFields(allFields); // in case normalize Object.keys(allValues).forEach(function (f) { allValues[f] = _this7.fieldsStore.getFieldValue(f); }); if (callback && (0, _utils.isEmptyObject)(allFields)) { callback((0, _utils.isEmptyObject)(alreadyErrors) ? null : alreadyErrors, this.fieldsStore.getFieldsValue(fieldNames)); return; } var validator = new _asyncValidator2['default'](allRules); if (validateMessages) { validator.messages(validateMessages); } validator.validate(allValues, options, function (errors) { var errorsGroup = (0, _extends6['default'])({}, alreadyErrors); if (errors && errors.length) { errors.forEach(function (e) { var errorFieldName = e.field; var fieldName = errorFieldName; // Handle using array validation rule. // ref: https://github.com/ant-design/ant-design/issues/14275 Object.keys(allRules).some(function (ruleFieldName) { var rules = allRules[ruleFieldName] || []; // Exist if match rule if (ruleFieldName === errorFieldName) { fieldName = ruleFieldName; return true; } // Skip if not match array type if (rules.every(function (_ref2) { var type = _ref2.type; return type !== 'array'; }) || errorFieldName.indexOf(ruleFieldName + '.') !== 0) { return false; } // Exist if match the field name var restPath = errorFieldName.slice(ruleFieldName.length + 1); if (/^\d+$/.test(restPath)) { fieldName = ruleFieldName; return true; } return false; }); var field = (0, _get2['default'])(errorsGroup, fieldName); if (typeof field !== 'object' || Array.isArray(field)) { (0, _set2['default'])(errorsGroup, fieldName, { errors: [] }); } var fieldErrors = (0, _get2['default'])(errorsGroup, fieldName.concat('.errors')); fieldErrors.push(e); }); } var expired = []; var nowAllFields = {}; Object.keys(allRules).forEach(function (name) { var fieldErrors = (0, _get2['default'])(errorsGroup, name); var nowField = _this7.fieldsStore.getField(name); // avoid concurrency problems if (!(0, _eq2['default'])(nowField.value, allValues[name])) { expired.push({ name: name }); } else { nowField.errors = fieldErrors && fieldErrors.errors; nowField.value = allValues[name]; nowField.validating = false; nowField.dirty = false; nowAllFields[name] = nowField; } }); _this7.setFields(nowAllFields); if (callback) { if (expired.length) { expired.forEach(function (_ref3) { var name = _ref3.name; var fieldErrors = [{ message: name + ' need to revalidate', field: name }]; (0, _set2['default'])(errorsGroup, name, { expired: true, errors: fieldErrors }); }); } callback((0, _utils.isEmptyObject)(errorsGroup) ? null : errorsGroup, _this7.fieldsStore.getFieldsValue(fieldNames)); } }); }, validateFields: function validateFields(ns, opt, cb) { var _this8 = this; var pending = new Promise(function (resolve, reject) { var _getParams = (0, _utils.getParams)(ns, opt, cb), names = _getParams.names, options = _getParams.options; var _getParams2 = (0, _utils.getParams)(ns, opt, cb), callback = _getParams2.callback; if (!callback || typeof callback === 'function') { var oldCb = callback; callback = function callback(errors, values) { if (oldCb) { oldCb(errors, values); } if (errors) { reject({ errors: errors, values: values }); } else { resolve(values); } }; } var fieldNames = names ? _this8.fieldsStore.getValidFieldsFullName(names) : _this8.fieldsStore.getValidFieldsName(); var fields = fieldNames.filter(function (name) { var fieldMeta = _this8.fieldsStore.getFieldMeta(name); return (0, _utils.hasRules)(fieldMeta.validate); }).map(function (name) { var field = _this8.fieldsStore.getField(name); field.value = _this8.fieldsStore.getFieldValue(name); return field; }); if (!fields.length) { callback(null, _this8.fieldsStore.getFieldsValue(fieldNames)); return; } if (!('firstFields' in options)) { options.firstFields = fieldNames.filter(function (name) { var fieldMeta = _this8.fieldsStore.getFieldMeta(name); return !!fieldMeta.validateFirst; }); } _this8.validateFieldsInternal(fields, { fieldNames: fieldNames, options: options }, callback); }); pending['catch'](function (e) { // eslint-disable-next-line no-console if (console.error && process.env.NODE_ENV !== 'production') { // eslint-disable-next-line no-console console.error(e); } return e; }); return pending; }, isSubmitting: function isSubmitting() { if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') { (0, _warning2['default'])(false, '`isSubmitting` is deprecated. ' + "Actually, it's more convenient to handle submitting status by yourself."); } return this.state.submitting; }, submit: function submit(callback) { var _this9 = this; if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') { (0, _warning2['default'])(false, '`submit` is deprecated. ' + "Actually, it's more convenient to handle submitting status by yourself."); } var fn = function fn() { _this9.setState({ submitting: false }); }; this.setState({ submitting: true }); callback(fn); }, render: function render() { var _props = this.props, wrappedComponentRef = _props.wrappedComponentRef, restProps = (0, _objectWithoutProperties3['default'])(_props, ['wrappedComponentRef']); // eslint-disable-line var formProps = (0, _defineProperty3['default'])({}, formPropName, this.getForm()); if (withRef) { if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') { (0, _warning2['default'])(false, '`withRef` is deprecated, please use `wrappedComponentRef` instead. ' + 'See: https://github.com/react-component/form#note-use-wrappedcomponentref-instead-of-withref-after-rc-form140'); } formProps.ref = 'wrappedComponent'; } else if (wrappedComponentRef) { formProps.ref = wrappedComponentRef; } var props = mapProps.call(this, (0, _extends6['default'])({}, formProps, restProps)); return _react2['default'].createElement(WrappedComponent, props); } }); return (0, _utils.argumentContainer)((0, _unsafeLifecyclesPolyfill2['default'])(Form), WrappedComponent); }; } exports['default'] = createBaseForm; module.exports = exports['default'];