zent
Version:
一套前端设计语言和基于React的实现
531 lines (430 loc) • 19.8 kB
JavaScript
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'];
;