UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

721 lines (637 loc) • 19.3 kB
"use strict"; var Class = require("../core/class"), extend = require("../core/utils/extend").extend, inArray = require("../core/utils/array").inArray, each = require("../core/utils/iterator").each, EventsMixin = require("../core/events_mixin"), errors = require("../core/errors"), commonUtils = require("../core/utils/common"), typeUtils = require("../core/utils/type"), numberLocalization = require("../localization/number"), messageLocalization = require("../localization/message"); var BaseRuleValidator = Class.inherit({ NAME: "base", defaultMessage: function defaultMessage(value) { return messageLocalization.getFormatter("validation-" + this.NAME)(value); }, defaultFormattedMessage: function defaultFormattedMessage(value) { return messageLocalization.getFormatter("validation-" + this.NAME + "-formatted")(value); }, validate: function validate(value, rule) { var valueArray = Array.isArray(value) ? value : [value], result = true; if (valueArray.length) { valueArray.every(function (itemValue) { result = this._validate(itemValue, rule); return result; }, this); } else { result = this._validate(null, rule); } return result; } }); var RequiredRuleValidator = BaseRuleValidator.inherit({ NAME: "required", /** * @name requiredRule.type * @publicName type * @type Enums.ValidationRuleType */ /** * @name requiredRule.trim * @publicName trim * @type boolean * @default true */ /** * @name requiredRule.message * @publicName message * @type string * @default 'Required' */ _validate: function _validate(value, rule) { if (!typeUtils.isDefined(value)) return false; if (value === false) { return false; } value = String(value); if (rule.trim || !typeUtils.isDefined(rule.trim)) { value = value.trim(); } return value !== ""; } }); var NumericRuleValidator = BaseRuleValidator.inherit({ NAME: "numeric", /** * @name numericRule.type * @publicName type * @type Enums.ValidationRuleType */ /** * @name numericRule.message * @publicName message * @type string * @default 'Value should be a number' */ _validate: function _validate(value, rule) { if (!rulesValidators.required.validate(value, {})) { return true; } if (rule.useCultureSettings && typeUtils.isString(value)) { return !isNaN(numberLocalization.parse(value)); } else { return typeUtils.isNumeric(value); } } }); var RangeRuleValidator = BaseRuleValidator.inherit({ NAME: "range", /** * @name rangeRule.type * @publicName type * @type Enums.ValidationRuleType */ /** * @name rangeRule.min * @publicName min * @type datetime|number */ /** * @name rangeRule.max * @publicName max * @type datetime|number */ /** * @name rangeRule.message * @publicName message * @type string * @default 'Value is out of range' */ /** * @name rangeRule.reevaluate * @publicName reevaluate * @type boolean * @default false */ _validate: function _validate(value, rule) { if (!rulesValidators.required.validate(value, {})) { return true; } var validNumber = rulesValidators["numeric"].validate(value, rule), validValue = typeUtils.isDefined(value), number = validNumber ? parseFloat(value) : validValue && value.valueOf(), min = rule.min, max = rule.max; if (!(validNumber || typeUtils.isDate(value)) && !validValue) { return false; } if (typeUtils.isDefined(min)) { if (typeUtils.isDefined(max)) { return number >= min && number <= max; } return number >= min; } else { if (typeUtils.isDefined(max)) { return number <= max; } else { throw errors.Error("E0101"); } } } }); var StringLengthRuleValidator = BaseRuleValidator.inherit({ NAME: "stringLength", /** * @name stringLengthRule.type * @publicName type * @type Enums.ValidationRuleType */ /** * @name stringLengthRule.min * @publicName min * @type number */ /** * @name stringLengthRule.max * @publicName max * @type number */ /** * @name stringLengthRule.trim * @publicName trim * @type boolean * @default true */ /** * @name stringLengthRule.message * @publicName message * @type string * @default 'The length of the value is not correct' */ _validate: function _validate(value, rule) { value = typeUtils.isDefined(value) ? String(value) : ""; if (rule.trim || !typeUtils.isDefined(rule.trim)) { value = value.trim(); } return rulesValidators.range.validate(value.length, extend({}, rule)); } }); var CustomRuleValidator = BaseRuleValidator.inherit({ NAME: "custom", /** * @name customRule.type * @publicName type * @type Enums.ValidationRuleType */ /** * @name customRule.validationCallback * @publicName validationCallback * @type function * @type_function_return boolean * @type_function_param1 options:object * @type_function_param1_field1 value:string|number * @type_function_param1_field2 rule:object * @type_function_param1_field3 validator:object * @type_function_param1_field4 data:object */ /** * @name customRule.message * @publicName message * @type string * @default 'Value is invalid' */ /** * @name customRule.reevaluate * @publicName reevaluate * @type boolean * @default false */ validate: function validate(value, rule) { var validator = rule.validator, dataGetter = validator && typeUtils.isFunction(validator.option) && validator.option("dataGetter"), data = typeUtils.isFunction(dataGetter) && dataGetter(), params = { value: value, validator: validator, rule: rule }; if (data) { params.data = data; } return rule.validationCallback(params); } }); var CompareRuleValidator = BaseRuleValidator.inherit({ NAME: "compare", /** * @name compareRule.type * @publicName type * @type Enums.ValidationRuleType */ /** * @name compareRule.comparisonTarget * @publicName comparisonTarget * @type function * @type_function_return object */ /** * @name compareRule.comparisonType * @publicName comparisonType * @type Enums.ComparisonOperator * @default '==' */ /** * @name compareRule.message * @publicName message * @type string * @default 'Values do not match' */ /** * @name compareRule.reevaluate * @publicName reevaluate * @type boolean * @default true */ _validate: function _validate(value, rule) { if (!rule.comparisonTarget) { throw errors.Error("E0102"); } extend(rule, { reevaluate: true }); var otherValue = rule.comparisonTarget(), type = rule.comparisonType || "=="; switch (type) { case "==": return value == otherValue; // jshint ignore:line case "!=": return value != otherValue; // jshint ignore:line case "===": return value === otherValue; case "!==": return value !== otherValue; case ">": return value > otherValue; case ">=": return value >= otherValue; case "<": return value < otherValue; case "<=": return value <= otherValue; } } }); var PatternRuleValidator = BaseRuleValidator.inherit({ NAME: "pattern", /** * @name patternRule.type * @publicName type * @type Enums.ValidationRuleType */ /** * @name patternRule.pattern * @publicName pattern * @type regexp|string */ /** * @name patternRule.message * @publicName message * @type string * @default 'Value does not match pattern' */ _validate: function _validate(value, rule) { if (!rulesValidators.required.validate(value, {})) { return true; } var pattern = rule.pattern; if (typeUtils.isString(pattern)) { pattern = new RegExp(pattern); } return pattern.test(value); } }); var EmailRuleValidator = BaseRuleValidator.inherit({ NAME: "email", /** * @name emailRule.type * @publicName type * @type Enums.ValidationRuleType */ /** * @name emailRule.message * @publicName message * @type string * @default 'Email is invalid' */ _validate: function _validate(value, rule) { if (!rulesValidators.required.validate(value, {})) { return true; } return rulesValidators.pattern.validate(value, extend({}, rule, { pattern: /^[\d\w\._\-]+@([\d\w\._\-]+\.)+[\w]+$/i })); } }); var rulesValidators = { /** * @name requiredRule * @publicName RequiredRule * @section dxValidator * @type object */ "required": new RequiredRuleValidator(), /** * @name numericRule * @publicName NumericRule * @section dxValidator * @type object */ "numeric": new NumericRuleValidator(), /** * @name rangeRule * @publicName RangeRule * @section dxValidator * @type object */ "range": new RangeRuleValidator(), /** * @name stringLengthRule * @publicName StringLengthRule * @section dxValidator * @type object */ "stringLength": new StringLengthRuleValidator(), /** * @name customRule * @publicName CustomRule * @section dxValidator * @type object */ "custom": new CustomRuleValidator(), /** * @name compareRule * @publicName CompareRule * @section dxValidator * @type object */ "compare": new CompareRuleValidator(), /** * @name patternRule * @publicName PatternRule * @section dxValidator * @type object */ "pattern": new PatternRuleValidator(), /** * @name emailRule * @publicName EmailRule * @section dxValidator * @type object */ "email": new EmailRuleValidator() }; var GroupConfig = Class.inherit({ ctor: function ctor(group) { this.group = group; this.validators = []; }, validate: function validate() { /** * @name dxValidationGroupResult * @publicName dxValidationGroupResult * @type Object */ var result = { /** * @name dxValidationGroupResult.isValid * @publicName isValid * @type boolean */ isValid: true, /** * @name dxValidationGroupResult.brokenRules * @publicName brokenRules * @type Array<RequiredRule,NumericRule,RangeRule,StringLengthRule,CustomRule,CompareRule,PatternRule,EmailRule> */ brokenRules: [], /** * @name dxValidationGroupResult.validators * @publicName validators * @type Array<Object> */ validators: [] }; each(this.validators, function (_, validator) { var validatorResult = validator.validate(); result.isValid = result.isValid && validatorResult.isValid; if (validatorResult.brokenRule) { result.brokenRules.push(validatorResult.brokenRule); } result.validators.push(validator); }); this.fireEvent("validated", [{ validators: result.validators, brokenRules: result.brokenRules, isValid: result.isValid }]); return result; }, reset: function reset() { each(this.validators, function (_, validator) { validator.reset(); }); } }).include(EventsMixin); /** * @name validationEngine * @section Core * @publicName validationEngine * @namespace DevExpress * @module ui/validation_engine * @export default */ var ValidationEngine = { groups: [], /** * @name validationEngineMethods.getGroupConfig * @section Core * @publicName getGroupConfig(group) * @param1 group:string|object * @return object * @static */ /** * @name validationEngineMethods.getGroupConfig * @section Core * @publicName getGroupConfig() * @return object * @static */ getGroupConfig: function getGroupConfig(group) { var result = commonUtils.grep(this.groups, function (config) { return config.group === group; }); if (result.length) { return result[0]; } // TODO: consider throwing exception here, as it causes quite strange and hardly diagnostable behaviour }, initGroups: function initGroups() { this.groups = []; this.addGroup(); }, addGroup: function addGroup(group) { var config = this.getGroupConfig(group); if (!config) { config = new GroupConfig(group); this.groups.push(config); } return config; }, removeGroup: function removeGroup(group) { var config = this.getGroupConfig(group), index = inArray(config, this.groups); if (index > -1) { this.groups.splice(index, 1); } return config; }, _setDefaultMessage: function _setDefaultMessage(rule, validator, name) { if (!typeUtils.isDefined(rule.message)) { if (validator.defaultFormattedMessage && typeUtils.isDefined(name)) { rule.message = validator.defaultFormattedMessage(name); } else { rule.message = validator.defaultMessage(); } } }, validate: function validate(value, rules, name) { /** * @name dxValidatorResult * @publicName dxValidatorResult * @type Object */ var result = { name: name, /** * @name dxValidatorResult.value * @publicName value * @type any */ value: value, /** * @name dxValidatorResult.brokenRule * @publicName brokenRule * @type RequiredRule|NumericRule|RangeRule|StringLengthRule|CustomRule|CompareRule|PatternRule|EmailRule */ brokenRule: null, /** * @name dxValidatorResult.isValid * @publicName isValid * @type boolean */ isValid: true, /** * @name dxValidatorResult.validationRules * @publicName validationRules * @type Array<RequiredRule,NumericRule,RangeRule,StringLengthRule,CustomRule,CompareRule,PatternRule,EmailRule> */ validationRules: rules }, that = this; each(rules || [], function (_, rule) { var ruleValidator = rulesValidators[rule.type], ruleValidationResult; if (ruleValidator) { if (typeUtils.isDefined(rule.isValid) && rule.value === value && !rule.reevaluate) { if (!rule.isValid) { result.isValid = false; result.brokenRule = rule; return false; } return true; } rule.value = value; ruleValidationResult = ruleValidator.validate(value, rule); rule.isValid = ruleValidationResult; if (!ruleValidationResult) { result.isValid = false; that._setDefaultMessage(rule, ruleValidator, name); result.brokenRule = rule; } if (!rule.isValid) { return false; } } else { throw errors.Error("E0100"); } }); return result; }, registerValidatorInGroup: function registerValidatorInGroup(group, validator) { var groupConfig = ValidationEngine.addGroup(group); if (inArray(validator, groupConfig.validators) < 0) { groupConfig.validators.push(validator); } }, _shouldRemoveGroup: function _shouldRemoveGroup(group, validatorsInGroup) { var isDefaultGroup = group === undefined, isValidationGroupInstance = group && group.NAME === "dxValidationGroup"; return !isDefaultGroup && !isValidationGroupInstance && !validatorsInGroup.length; }, removeRegisteredValidator: function removeRegisteredValidator(group, validator) { var config = ValidationEngine.getGroupConfig(group), validatorsInGroup = config && config.validators; var index = inArray(validator, validatorsInGroup); if (index > -1) { validatorsInGroup.splice(index, 1); if (this._shouldRemoveGroup(group, validatorsInGroup)) { this.removeGroup(group); } } }, /** * @name validationEngineMethods.validateGroup * @section Core * @publicName validateGroup(group) * @param1 group:string|object * @return dxValidationGroupResult * @static */ /** * @name validationEngineMethods.validateGroup * @section Core * @publicName validateGroup() * @return dxValidationGroupResult * @static */ validateGroup: function validateGroup(group) { var groupConfig = ValidationEngine.getGroupConfig(group); if (!groupConfig) { throw errors.Error("E0110"); } return groupConfig.validate(); }, /** * @name validationEngineMethods.resetGroup * @section Core * @publicName resetGroup(group) * @param1 group:string|object * @static */ /** * @name validationEngineMethods.resetGroup * @section Core * @publicName resetGroup() * @static */ resetGroup: function resetGroup(group) { var groupConfig = ValidationEngine.getGroupConfig(group); if (!groupConfig) { throw errors.Error("E0110"); } return groupConfig.reset(); } }; ValidationEngine.initGroups(); module.exports = ValidationEngine;