UNPKG

hc-components-test

Version:

基于react的通用组件库

317 lines (293 loc) 9.1 kB
/** * # 通用校验模块 * 1. 通过定义校验规则用于校验数据合法 * 2. 集成antd-form,校验表单合法 */ import AsyncValidator from 'async-validator'; const noop = () => {}; import hoistNonReactStatics from 'hoist-non-react-statics'; import Form from 'antd/lib/form'; import message from 'antd/lib/message'; // + 把promise封装成Deferred,参考jQuery.Deffered // > see: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred export function Deferred() { // #! update 062115 for typeof if (typeof(Promise) != 'undefined' && Promise.defer) { //#! need import of Promise.jsm for example: Cu.import('resource:/gree/modules/Promise.jsm'); return Promise.defer(); } else if (typeof(PromiseUtils) != 'undefined' && PromiseUtils.defer) { //#! need import of PromiseUtils.jsm for example: Cu.import('resource:/gree/modules/PromiseUtils.jsm'); return PromiseUtils.defer(); } else { /* A method to resolve the associated Promise with the value passed. * If the promise is already settled it does nothing. * * @param {anything} value : This value is used to resolve the promise * If the value is a Promise then the associated promise assumes the state * of Promise passed as value. */ this.resolve = null; /* A method to reject the assocaited Promise with the value passed. * If the promise is already settled it does nothing. * * @param {anything} reason: The reason for the rejection of the Promise. * Generally its an Error object. If however a Promise is passed, then the Promise * itself will be the reason for rejection no matter the state of the Promise. */ this.reject = null; /* A newly created Pomise object. * Initially in pending state. */ this.promise = new Promise(function(resolve, reject) { this.resolve = resolve; this.reject = reject; }.bind(this)); Object.freeze(this); } } /** * + async-validator@1.6.6 * > see: https://github.com/yiminghe/async-validator */ export class Validator { static enhanceForm = (option) => BaseComponent => { const Component = Form.create(Object.assign(option || {}, {withRef: true}))(BaseComponent); Component.prototype.getRealInstance = function () { return this.refs.wrappedComponent.refs.formWrappedComponent; } return hoistNonReactStatics(Component, BaseComponent); } static validate = (rules, source, callback) => { const descriptor = {}; for (let key in rules) { if (typeof rules[key] === 'boolean') { descriptor[key] = { type: 'string', required: rules[key] } } else { descriptor[key] = rules[key]; } fields[key] = source[key]; } const validator = new AsyncValidator(descriptor); validator.validate(source, callback); } static templates = { pattern: { // #! 中英字母数字下划线 legal: /^[A-Za-z0-9_\u4e00-\u9fa5]*$/, // #! 必须是字母数字、下划线、中划线以及 light_legal: /^[A-Za-z0-9\._\-]*$/, // #! 以字母开头,不能包含中文或特殊字符 light_light_legal: /^[a-zA-Z]\w*$/, // #! 中英字母数字下划线 dark_legal: /^[A-Za-z0-9\_\u4e00-\u9fa5]*$/, // #! 必须是中英字母数字下划线以及. dark_dark_legal: /^[A-Za-z0-9\._\u4e00-\u9fa5]*$/ } } /** * + 校验规则 * ``` * fieldRules = [{ * [fieldName]: { * type: ['string', 'number', 'boolean', 'method', 'regexp', 'integer', 'float', 'array', 'object', 'enum', 'date', 'url', 'hex', 'email'], * required, * pattern, * whitespace, * transform, * message, * validator, * [range(min, max): 'string' | 'array' | 'integer'], * [length: 'string' | 'array'] * [enum: 'enum'], * [fields: 'deep rules'], * [defaultField: 'array' | 'object'] * } * },...] * ``` */ static $inject = ['props', 'validateRules']; constructor(props, validateRules) { for (let key in validateRules) { validateRules[key] = this.pack(validateRules[key]); } this._validateRules = validateRules || {}; this._handleSubmit = (errors, values) => { if (errors) { return false; } else { return values; } }; this._submitting = false; this._validating = false; } isSubmitting(){ return this._submitting; } isValidating(){ return this._validating; } pack(rule) { if (Array.isArray(rule)) { rule = rule.map(item => { if (typeof item.pattern === 'string') { item.pattern = Validator.templates.pattern[item.pattern]; } return item; }); } else { if (typeof rule.pattern === 'string') { rule.pattern = Validator.templates.pattern[rule.pattern]; } } return rule; } setForm(form, validateRules, submitCallback) { this._form = form; if (submitCallback) { this._handleSubmit = submitCallback; if (validateRules) { for (let key in validateRules) { validateRules[key] = this.pack(validateRules[key]); } this._validateRules = validateRules; } } else if (validateRules) { this._handleSubmit = validateRules; } } reset() { this ._form .resetFields(); } getProps(fieldName, rule) { if (this._validateRules[fieldName]) { return assignDeep(this._validateRules[fieldName], rule && this.pack(rule)); } else { return rule && this.pack(rule); } } // #! for antd-form getFieldProps(fieldName, option) { if (!option.rules && option.rule) { option.rules = [option.rule]; } if (this._validateRules[fieldName]) { // option.rules = assignDeep([].concat(this._validateRules[fieldName]), // option.rules && this.pack(option.rules) || []); option.rules = [].concat(this._validateRules[fieldName], option.rules && this.pack(option.rules) || []) } else if (option.rules) { option.rules = this.pack(option.rules); } return this ._form .getFieldProps(fieldName, option); } getFieldDecorator(fieldName, option) { if (!option.rules && option.rule) { option.rules = [option.rule]; } if (this._validateRules[fieldName]) { // option.rules = assignDeep([].concat(this._validateRules[fieldName]), // option.rules && this.pack(option.rules) || []); option.rules = [].concat(this._validateRules[fieldName], option.rules && this.pack(option.rules) || []) } else if (option.rules) { option.rules = this.pack(option.rules); } return this ._form .getFieldDecorator(fieldName, option); } _validate(opt) { const defer = new Deferred(); this._validating = true; this._form.setFields(); opt.preCallback && opt.preCallback(); const callback = (errors, values) => { this._validating = false; const postCallback = () => { opt.postCallback && opt.postCallback(); this._form.setFields(); } if(errors){ if(opt.catchError){ opt.catchError(errors); }else{ message.error('表单校验失败'); } postCallback(); return defer.reject(false); } const result = opt.callback && opt.callback(errors, values); if (result && result.then) { result.then(defer.resolve, defer.reject); } else if (result === false) { defer.reject(false); } else { defer.resolve(result); } defer.promise.then(postCallback, postCallback); } if(opt.source){ new AsyncValidator(this._validateRules).validate(opt.source, callback); }else{ this._form[opt.method](callback); } return defer.promise; } validateFields(callback, catchError) { return this._validate({ method: 'validateFields', callback: callback, catchError: catchError }); } validateFieldsAndScroll(callback, catchError) { return this._validate({ method: 'validateFieldsAndScroll', callback: callback, catchError: catchError }); } validate(source, callback, catchError) { return this._validate({ source: source, callback: callback, catchError: catchError }); } submit(callback, catchError) { return this._validate({ method: 'validateFieldsAndScroll', callback: callback, preCallback: () => { this._submitting = true; }, postCallback: () => { this._submitting = false; }, callback: (errors, values) => { values = this._handleSubmit(errors, values); if (values === false) { return false; } else { return callback(values); } }, catchError: catchError }); } } function assignDeep(obj, newObj) { if (Array.isArray(obj)) { return obj.map((item, index) => { return assignDeep(item, newObj[index]); }); } else { return Object.assign(obj, newObj); } }