validation_engine.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /**
  2. * DevExtreme (ui/validation_engine.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var Class = require("../core/class");
  11. var extend = require("../core/utils/extend").extend;
  12. var inArray = require("../core/utils/array").inArray;
  13. var each = require("../core/utils/iterator").each;
  14. var EventsMixin = require("../core/events_mixin");
  15. var errors = require("../core/errors");
  16. var commonUtils = require("../core/utils/common");
  17. var typeUtils = require("../core/utils/type");
  18. var numberLocalization = require("../localization/number");
  19. var messageLocalization = require("../localization/message");
  20. var BaseRuleValidator = Class.inherit({
  21. NAME: "base",
  22. defaultMessage: function(value) {
  23. return messageLocalization.getFormatter("validation-" + this.NAME)(value)
  24. },
  25. defaultFormattedMessage: function(value) {
  26. return messageLocalization.getFormatter("validation-" + this.NAME + "-formatted")(value)
  27. },
  28. _isValueEmpty: function(value) {
  29. return !rulesValidators.required.validate(value, {})
  30. },
  31. validate: function(value, rule) {
  32. var valueArray = Array.isArray(value) ? value : [value];
  33. var result = true;
  34. if (valueArray.length) {
  35. valueArray.every(function(itemValue) {
  36. result = this._validate(itemValue, rule);
  37. return result
  38. }, this)
  39. } else {
  40. result = this._validate(null, rule)
  41. }
  42. return result
  43. }
  44. });
  45. var RequiredRuleValidator = BaseRuleValidator.inherit({
  46. NAME: "required",
  47. _validate: function(value, rule) {
  48. if (!typeUtils.isDefined(value)) {
  49. return false
  50. }
  51. if (false === value) {
  52. return false
  53. }
  54. value = String(value);
  55. if (rule.trim || !typeUtils.isDefined(rule.trim)) {
  56. value = value.trim()
  57. }
  58. return "" !== value
  59. }
  60. });
  61. var NumericRuleValidator = BaseRuleValidator.inherit({
  62. NAME: "numeric",
  63. _validate: function(value, rule) {
  64. if (false !== rule.ignoreEmptyValue && this._isValueEmpty(value)) {
  65. return true
  66. }
  67. if (rule.useCultureSettings && typeUtils.isString(value)) {
  68. return !isNaN(numberLocalization.parse(value))
  69. } else {
  70. return typeUtils.isNumeric(value)
  71. }
  72. }
  73. });
  74. var RangeRuleValidator = BaseRuleValidator.inherit({
  75. NAME: "range",
  76. _validate: function(value, rule) {
  77. if (false !== rule.ignoreEmptyValue && this._isValueEmpty(value)) {
  78. return true
  79. }
  80. var validNumber = rulesValidators.numeric.validate(value, rule);
  81. var validValue = typeUtils.isDefined(value) && "" !== value;
  82. var number = validNumber ? parseFloat(value) : validValue && value.valueOf();
  83. var min = rule.min;
  84. var max = rule.max;
  85. if (!(validNumber || typeUtils.isDate(value)) && !validValue) {
  86. return false
  87. }
  88. if (typeUtils.isDefined(min)) {
  89. if (typeUtils.isDefined(max)) {
  90. return number >= min && number <= max
  91. }
  92. return number >= min
  93. } else {
  94. if (typeUtils.isDefined(max)) {
  95. return number <= max
  96. } else {
  97. throw errors.Error("E0101")
  98. }
  99. }
  100. }
  101. });
  102. var StringLengthRuleValidator = BaseRuleValidator.inherit({
  103. NAME: "stringLength",
  104. _validate: function(value, rule) {
  105. value = typeUtils.isDefined(value) ? String(value) : "";
  106. if (rule.trim || !typeUtils.isDefined(rule.trim)) {
  107. value = value.trim()
  108. }
  109. if (rule.ignoreEmptyValue && this._isValueEmpty(value)) {
  110. return true
  111. }
  112. return rulesValidators.range.validate(value.length, extend({}, rule))
  113. }
  114. });
  115. var CustomRuleValidator = BaseRuleValidator.inherit({
  116. NAME: "custom",
  117. validate: function(value, rule) {
  118. if (rule.ignoreEmptyValue && this._isValueEmpty(value)) {
  119. return true
  120. }
  121. var validator = rule.validator;
  122. var dataGetter = validator && typeUtils.isFunction(validator.option) && validator.option("dataGetter");
  123. var data = typeUtils.isFunction(dataGetter) && dataGetter();
  124. var params = {
  125. value: value,
  126. validator: validator,
  127. rule: rule
  128. };
  129. if (data) {
  130. params.data = data
  131. }
  132. return rule.validationCallback(params)
  133. }
  134. });
  135. var CompareRuleValidator = BaseRuleValidator.inherit({
  136. NAME: "compare",
  137. _validate: function(value, rule) {
  138. if (!rule.comparisonTarget) {
  139. throw errors.Error("E0102")
  140. }
  141. if (rule.ignoreEmptyValue && this._isValueEmpty(value)) {
  142. return true
  143. }
  144. extend(rule, {
  145. reevaluate: true
  146. });
  147. var otherValue = rule.comparisonTarget();
  148. var type = rule.comparisonType || "==";
  149. switch (type) {
  150. case "==":
  151. return value == otherValue;
  152. case "!=":
  153. return value != otherValue;
  154. case "===":
  155. return value === otherValue;
  156. case "!==":
  157. return value !== otherValue;
  158. case ">":
  159. return value > otherValue;
  160. case ">=":
  161. return value >= otherValue;
  162. case "<":
  163. return value < otherValue;
  164. case "<=":
  165. return value <= otherValue
  166. }
  167. }
  168. });
  169. var PatternRuleValidator = BaseRuleValidator.inherit({
  170. NAME: "pattern",
  171. _validate: function(value, rule) {
  172. if (false !== rule.ignoreEmptyValue && this._isValueEmpty(value)) {
  173. return true
  174. }
  175. var pattern = rule.pattern;
  176. if (typeUtils.isString(pattern)) {
  177. pattern = new RegExp(pattern)
  178. }
  179. return pattern.test(value)
  180. }
  181. });
  182. var EmailRuleValidator = BaseRuleValidator.inherit({
  183. NAME: "email",
  184. _validate: function(value, rule) {
  185. if (false !== rule.ignoreEmptyValue && this._isValueEmpty(value)) {
  186. return true
  187. }
  188. return rulesValidators.pattern.validate(value, extend({}, rule, {
  189. pattern: /^[\d\w._-]+@[\d\w._-]+\.[\w]+$/i
  190. }))
  191. }
  192. });
  193. var rulesValidators = {
  194. required: new RequiredRuleValidator,
  195. numeric: new NumericRuleValidator,
  196. range: new RangeRuleValidator,
  197. stringLength: new StringLengthRuleValidator,
  198. custom: new CustomRuleValidator,
  199. compare: new CompareRuleValidator,
  200. pattern: new PatternRuleValidator,
  201. email: new EmailRuleValidator
  202. };
  203. var GroupConfig = Class.inherit({
  204. ctor: function(group) {
  205. this.group = group;
  206. this.validators = []
  207. },
  208. validate: function() {
  209. var result = {
  210. isValid: true,
  211. brokenRules: [],
  212. validators: []
  213. };
  214. each(this.validators, function(_, validator) {
  215. var validatorResult = validator.validate();
  216. result.isValid = result.isValid && validatorResult.isValid;
  217. if (validatorResult.brokenRule) {
  218. result.brokenRules.push(validatorResult.brokenRule)
  219. }
  220. result.validators.push(validator)
  221. });
  222. this.fireEvent("validated", [{
  223. validators: result.validators,
  224. brokenRules: result.brokenRules,
  225. isValid: result.isValid
  226. }]);
  227. return result
  228. },
  229. reset: function() {
  230. each(this.validators, function(_, validator) {
  231. validator.reset()
  232. })
  233. }
  234. }).include(EventsMixin);
  235. var ValidationEngine = {
  236. groups: [],
  237. getGroupConfig: function(group) {
  238. var result = commonUtils.grep(this.groups, function(config) {
  239. return config.group === group
  240. });
  241. if (result.length) {
  242. return result[0]
  243. }
  244. },
  245. initGroups: function() {
  246. this.groups = [];
  247. this.addGroup()
  248. },
  249. addGroup: function(group) {
  250. var config = this.getGroupConfig(group);
  251. if (!config) {
  252. config = new GroupConfig(group);
  253. this.groups.push(config)
  254. }
  255. return config
  256. },
  257. removeGroup: function(group) {
  258. var config = this.getGroupConfig(group);
  259. var index = inArray(config, this.groups);
  260. if (index > -1) {
  261. this.groups.splice(index, 1)
  262. }
  263. return config
  264. },
  265. _setDefaultMessage: function(rule, validator, name) {
  266. if (!typeUtils.isDefined(rule.message)) {
  267. if (validator.defaultFormattedMessage && typeUtils.isDefined(name)) {
  268. rule.message = validator.defaultFormattedMessage(name)
  269. } else {
  270. rule.message = validator.defaultMessage()
  271. }
  272. }
  273. },
  274. validate: function(value, rules, name) {
  275. var result = {
  276. name: name,
  277. value: value,
  278. brokenRule: null,
  279. isValid: true,
  280. validationRules: rules
  281. };
  282. var that = this;
  283. each(rules || [], function(_, rule) {
  284. var ruleValidator = rulesValidators[rule.type];
  285. var ruleValidationResult;
  286. if (ruleValidator) {
  287. if (typeUtils.isDefined(rule.isValid) && rule.value === value && !rule.reevaluate) {
  288. if (!rule.isValid) {
  289. result.isValid = false;
  290. result.brokenRule = rule;
  291. return false
  292. }
  293. return true
  294. }
  295. rule.value = value;
  296. ruleValidationResult = ruleValidator.validate(value, rule);
  297. rule.isValid = ruleValidationResult;
  298. if (!ruleValidationResult) {
  299. result.isValid = false;
  300. that._setDefaultMessage(rule, ruleValidator, name);
  301. result.brokenRule = rule
  302. }
  303. if (!rule.isValid) {
  304. return false
  305. }
  306. } else {
  307. throw errors.Error("E0100")
  308. }
  309. });
  310. return result
  311. },
  312. registerValidatorInGroup: function(group, validator) {
  313. var groupConfig = ValidationEngine.addGroup(group);
  314. if (inArray(validator, groupConfig.validators) < 0) {
  315. groupConfig.validators.push(validator)
  316. }
  317. },
  318. _shouldRemoveGroup: function(group, validatorsInGroup) {
  319. var isDefaultGroup = void 0 === group;
  320. var isValidationGroupInstance = group && "dxValidationGroup" === group.NAME;
  321. return !isDefaultGroup && !isValidationGroupInstance && !validatorsInGroup.length
  322. },
  323. removeRegisteredValidator: function(group, validator) {
  324. var config = ValidationEngine.getGroupConfig(group);
  325. var validatorsInGroup = config && config.validators;
  326. var index = inArray(validator, validatorsInGroup);
  327. if (index > -1) {
  328. validatorsInGroup.splice(index, 1);
  329. if (this._shouldRemoveGroup(group, validatorsInGroup)) {
  330. this.removeGroup(group)
  331. }
  332. }
  333. },
  334. validateGroup: function(group) {
  335. var groupConfig = ValidationEngine.getGroupConfig(group);
  336. if (!groupConfig) {
  337. throw errors.Error("E0110")
  338. }
  339. return groupConfig.validate()
  340. },
  341. resetGroup: function(group) {
  342. var groupConfig = ValidationEngine.getGroupConfig(group);
  343. if (!groupConfig) {
  344. throw errors.Error("E0110")
  345. }
  346. return groupConfig.reset()
  347. }
  348. };
  349. ValidationEngine.initGroups();
  350. module.exports = ValidationEngine;
  351. module.exports.default = module.exports;