UNPKG

zent

Version:

一套前端设计语言和基于React的实现

531 lines (430 loc) 19.8 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 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 _react = require('react'); var _omit = require('zent-utils/lodash/omit'); var _omit2 = _interopRequireDefault(_omit); var _find = require('zent-utils/lodash/find'); var _find2 = _interopRequireDefault(_find); var _noop = require('zent-utils/lodash/noop'); var _noop2 = _interopRequireDefault(_noop); var _assign = require('zent-utils/lodash/assign'); var _assign2 = _interopRequireDefault(_assign); var _isEqual = require('zent-utils/lodash/isEqual'); var _isEqual2 = _interopRequireDefault(_isEqual); var _some = require('zent-utils/lodash/some'); var _some2 = _interopRequireDefault(_some); var _isPromise = require('zent-utils/isPromise'); var _isPromise2 = _interopRequireDefault(_isPromise); var _utils = require('./utils'); var _validationRules = require('./validationRules'); var _validationRules2 = _interopRequireDefault(_validationRules); var _handleSubmit = require('./handleSubmit'); var _handleSubmit2 = _interopRequireDefault(_handleSubmit); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 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; } /* eslint-disable no-underscore-dangle */ var emptyArray = []; var checkSubmit = function checkSubmit(submit) { if (!submit || typeof submit !== 'function') { throw new Error('You must either pass handleSubmit() an onSubmit function or pass onSubmit as a prop'); } return submit; }; var createForm = function createForm() { var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var formValidations = config.formValidations; var validationRules = (0, _assign2['default'])({}, _validationRules2['default'], formValidations); return function (WrappedComponent) { var _class, _temp; return _temp = _class = function (_Component) { _inherits(Form, _Component); function Form(props) { _classCallCheck(this, Form); var _this = _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).call(this, props)); _this.submitCompleted = function (result) { delete _this.submitPromise; return result; }; _this.submitFailed = function (error) { delete _this.submitPromise; throw error; }; _this.listenToSubmit = function (promise) { if (!(0, _isPromise2['default'])(promise)) { return promise; } // 当submit是一个promise时,需要一个标识表明正在提交,提交结束后删除标识 _this.submitPromise = promise; return promise.then(_this.submitCompleted, _this.submitFailed); }; _this.submit = function (submitOrEvent) { var onSubmit = _this.props.onSubmit; // 在表单中手动调用handleSubmit或者把handleSubmit赋值给表单的onSubmit回调 // handleSubmit赋值给表单的onSubmit时,submitOrEvent是一个event对象 // handleSubmit的参数必须是function if (!submitOrEvent || (0, _utils.silenceEvent)(submitOrEvent)) { if (!_this.submitPromise) { // 调用props传入的onSubmit方法 return _this.listenToSubmit((0, _handleSubmit2['default'])(checkSubmit(onSubmit), _this)); } } else { // submitOrEvent是一个自定义submit函数,返回一个promise对象 return (0, _utils.silenceEvents)(function () { return !_this.submitPromise && _this.listenToSubmit((0, _handleSubmit2['default'])(checkSubmit(submitOrEvent), _this)); }); } }; _this.isSubmitting = function () { return _this.state.isSubmitting; }; _this.isValid = function () { return _this.state.isFormValid; }; _this.setFieldValidationErrors = function (errors) { _this.fields.forEach(function (field) { var name = field.props.name; field.setState({ _isValid: !(name in errors), _validationError: typeof errors[name] === 'string' ? [errors[name]] : errors[name] }); }); }; _this.setFieldExternalErrors = function (errors) { Object.keys(errors).forEach(function (name) { var field = (0, _find2['default'])(_this.fields, function (component) { return component.props.name === name; }); if (!field) { throw new Error('field ' + name + ' does not exits'); } field.setState({ _isValid: false, _externalError: typeof errors[name] === 'string' ? [errors[name]] : errors[name] }); }); }; _this.setFormPristine = function (isPristine) { _this.fields.forEach(function (field) { field.setState({ _isPristine: isPristine }); }); }; _this.resetFieldsValue = function (data) { _this.fields.forEach(function (field) { var name = field.props.name; if (data && data.hasOwnProperty(name)) { field.setValue(data[name]); } else { field.resetValue(); } }); }; _this.reset = function (data) { _this.setFormPristine(true); _this.resetFieldsValue(data); }; _this.isFieldTouched = function (name) { var field = _this.fields.find(function (component) { return component.props.name === name; }); if (!field) return false; return !field.isPristine(); }; _this.isFieldValidating = function (name) { var field = _this.fields.find(function (component) { return component.props.name === name; }); if (!field) return false; return field.isValidating(); }; _this.getFieldError = function (name) { var field = _this.fields.find(function (component) { return component.props.name === name; }); if (!field) return ''; return field.getErrorMessage(); }; _this.getFormValues = function () { return _this.fields.reduce(function (values, field) { var name = field.props.name; values[name] = field.getValue(); return values; }, {}); }; _this.getValidationErrors = function () { return _this.fields.reduce(function (errors, field) { var name = field.props.name; errors[name] = field.getErrorMessage(); return errors; }, {}); }; _this.getPristineValues = function () { return _this.fields.reduce(function (values, field) { var name = field.props.name; values[name] = field.getPristineValue(); return values; }, {}); }; _this.isChanged = function () { return !(0, _isEqual2['default'])(_this.getPristineValues(), _this.getFormValues()); }; _this.isValidating = function () { return (0, _some2['default'])(_this.fields, function (field) { return field.isValidating(); }); }; _this.isValidValue = function (field, value) { return _this.runValidation(field, value).isValid; }; _this.runValidation = function (field) { var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : field.getValue(); var formValidationErrors = _this.props.validationErrors; var _field$props = field.props, name = _field$props.name, validationError = _field$props.validationError, validationErrors = _field$props.validationErrors; var currentValues = _this.getFormValues(); var validationResults = _this.runRules(value, currentValues, field._validations); var isValid = !validationResults.failed.length && !(formValidationErrors && formValidationErrors[field.props.name]); return { isValid: isValid, error: function () { if (isValid) { return emptyArray; } if (validationResults.errors.length) { return validationResults.errors; } if (formValidationErrors && formValidationErrors[name]) { return typeof formValidationErrors[name] === 'string' ? [formValidationErrors[name]] : formValidationErrors[name]; } if (validationResults.failed.length) { return validationResults.failed.map(function (failed) { return validationErrors[failed] ? validationErrors[failed] : validationError; }).filter(function (x, pos, arr) { // Remove duplicates return arr.indexOf(x) === pos; }); } }() }; }; _this.runRules = function (value, currentValues) { var validations = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; var results = { errors: [], failed: [] }; function updateResults(validation, validationMethod) { // validation方法可以直接返回错误信息,否则需要返回布尔值表明校验是否成功 if (typeof validation === 'string') { results.errors.push(validation); results.failed.push(validationMethod); } else if (!validation) { results.failed.push(validationMethod); } } Object.keys(validations).forEach(function (validationMethod) { // validations中不指定function则必须是内置的rule if (!validationRules[validationMethod] && typeof validations[validationMethod] !== 'function') { throw new Error('does not have the validation rule: ' + validationMethod); } // 使用自定义校验方法或内置校验方法(可以按需添加) if (typeof validations[validationMethod] === 'function') { var validation = validations[validationMethod](currentValues, value); updateResults(validation, validationMethod); } else if (typeof validations[validationMethod] !== 'function') { var _validation = validationRules[validationMethod](currentValues, value, validations[validationMethod]); updateResults(_validation, validationMethod); } }); return results; }; _this.validate = function (field) { // 初始化时调用validate不触发onChange if (_this._isMounted) { _this.props.onChange(_this.getFormValues(), _this.isChanged()); } var validation = _this.runValidation(field); field.setState({ _isValid: validation.isValid, _validationError: validation.error, _externalError: null }, _this.validateForm); }; _this.asyncValidate = function (field, value) { var asyncValidation = field.props.asyncValidation; var values = _this.getFormValues(); if (field.state._validationError.length) return; field.setState({ _isValidating: true }); var promise = asyncValidation(values, value); if (!(0, _isPromise2['default'])(promise)) { throw new Error('asyncValidation function must return a promise'); } var handleResult = function handleResult(rejected) { return function (error) { field.setState({ _isValidating: false, _isValid: !rejected, _externalError: error ? [error] : null }); if (rejected) { _this.setState({ isFormValid: false }); } }; }; return promise.then(handleResult(false), handleResult(true)); }; _this.validateForm = function () { var onValidationComplete = function onValidationComplete() { var allIsValid = _this.fields.every(function (field) { return field.isValid(); }); _this.setState({ isFormValid: allIsValid }); if (allIsValid) { _this.props.onValid(); } else { _this.props.onInvalid(); } }; _this.fields.forEach(function (field, index) { var _externalError = field.state._externalError; var validation = _this.runValidation(field); if (validation.isValid && _externalError) { validation.isValid = false; } field.setState({ _isValid: validation.isValid, _validationError: validation.error, _externalError: !validation.isValid && _externalError ? _externalError : null }, index === _this.fields.length - 1 ? onValidationComplete : null); }); }; _this.attachToForm = function (field) { if (_this.fields.indexOf(field) < 0) { _this.fields.push(field); } // form初始化时不校验,后续动态添加的元素再校验 _this._isMounted && _this.validate(field); }; _this.detachFromForm = function (field) { var fieldPos = _this.fields.indexOf(field); if (fieldPos >= 0) { _this.fields.splice(fieldPos, 1); } _this.validateForm(); }; _this.state = { isFormValid: true, isSubmitting: false }; _this.fields = []; _this._isMounted = false; return _this; } _createClass(Form, [{ key: 'getChildContext', value: function getChildContext() { return { zentForm: { attachToForm: this.attachToForm, detachFromForm: this.detachFromForm, validate: this.validate, asyncValidate: this.asyncValidate, getFormValues: this.getFormValues, getFieldError: this.getFieldError, isValidValue: this.isValidValue, setFieldExternalErrors: this.setFieldExternalErrors, resetFieldsValue: this.resetFieldsValue, setFormPristine: this.setFormPristine, isValid: this.isValid, isSubmitting: this.isSubmitting } }; } }, { key: 'componentDidMount', value: function componentDidMount() { this.validateForm(); this._isMounted = true; } }, { key: 'componentWillUpdate', value: function componentWillUpdate() { this.prevFieldNames = this.fields.map(function (field) { return field.props.name; }); } }, { key: 'componentDidUpdate', value: function componentDidUpdate() { var validationErrors = this.props.validationErrors; if (validationErrors && (typeof validationErrors === 'undefined' ? 'undefined' : _typeof(validationErrors)) === 'object' && Object.keys(validationErrors).length > 0) { this.setFieldValidationErrors(validationErrors); } var newFieldNames = this.fields.map(function (field) { return field.props.name; }); if (!(0, _isEqual2['default'])(this.prevFieldNames, newFieldNames)) { this.validateForm(); } } // 设置服务端返回的错误信息 }, { key: 'render', value: function render() { var passableProps = (0, _omit2['default'])(this.props, ['validationErrors', 'handleSubmit', 'onChange']); return (0, _react.createElement)(WrappedComponent, _extends({}, passableProps, { handleSubmit: this.submit, zentForm: { getFormValues: this.getFormValues, getFieldError: this.getFieldError, setFieldExternalErrors: this.setFieldExternalErrors, resetFieldsValue: this.resetFieldsValue, setFormPristine: this.setFormPristine, isFieldTouched: this.isFieldTouched, isFieldValidating: this.isFieldValidating, isValid: this.isValid, isValidating: this.isValidating, isSubmitting: this.isSubmitting } })); } }]); return Form; }(_react.Component), _class.displayName = 'Form(' + (0, _utils.getDisplayName)(WrappedComponent) + ')', _class.WrappedComponent = WrappedComponent, _class.propTypes = { onSubmit: _react.PropTypes.func, onSubmitSuccess: _react.PropTypes.func, onSubmitFail: _react.PropTypes.func, onValid: _react.PropTypes.func, onInvalid: _react.PropTypes.func, onChange: _react.PropTypes.func, validationErrors: _react.PropTypes.object }, _class.defaultProps = { onSubmit: _noop2['default'], onSubmitSuccess: _noop2['default'], onSubmitFail: _noop2['default'], onValid: _noop2['default'], onInvalid: _noop2['default'], onChange: _noop2['default'], validationErrors: null }, _class.childContextTypes = { zentForm: _react.PropTypes.object }, _temp; }; }; exports['default'] = createForm; module.exports = exports['default'];