Implementing Inspector validation, in progress

This commit is contained in:
alekseybobkov 2015-10-08 21:59:02 -07:00
parent aee247727a
commit 6095303b54
11 changed files with 387 additions and 86 deletions

View File

@ -29,7 +29,7 @@
this.parentGroup = group
this.group = null // Group created by a grouped editor, for example by the set editor
this.childInspector = null
this.validators = []
this.validationSet = null
Base.call(this)
@ -40,7 +40,7 @@
BaseEditor.prototype.constructor = Base
BaseEditor.prototype.dispose = function() {
this.disposeValidators()
this.disposeValidation()
if (this.childInspector) {
this.childInspector.dispose()
@ -53,7 +53,7 @@
this.childInspector = null
this.parentGroup = null
this.group = null
this.validators = null
this.validationSet = null
BaseProto.dispose.call(this)
}
@ -61,7 +61,7 @@
BaseEditor.prototype.init = function() {
this.build()
this.registerHandlers()
this.createValidators()
this.initValidation()
}
BaseEditor.prototype.build = function() {
@ -104,77 +104,29 @@
// Validation
//
BaseEditor.prototype.createValidators = function() {
// Handle legacy validation syntax properties:
//
// - required
// - validationPattern
// - validationMessage
if ((this.propertyDefinition.required !== undefined ||
this.propertyDefinition.validationPattern !== undefined ||
this.propertyDefinition.validationMessage !== undefined) &&
this.propertyDefinition.validation !== undefined) {
this.throwError('Legacy and new validation syntax should not be mixed.')
}
if (this.propertyDefinition.required !== undefined) {
var validator = new $.oc.inspector.validators.required({
message: this.propertyDefinition.validationMessage
})
this.validators.push(validator)
}
if (this.propertyDefinition.validationPattern !== undefined) {
var validator = new $.oc.inspector.validators.regex({
message: this.propertyDefinition.validationMessage,
pattern: this.propertyDefinition.validationPattern
})
this.validators.push(validator)
}
//
// Handle new validation syntax
//
if (this.propertyDefinition.validation === undefined) {
return
}
for (var validatorName in this.propertyDefinition.validation) {
if ($.oc.inspector.validators[validatorName] == undefined) {
this.throwError('Inspector validator "' + validatorName + '" is not found in the $.oc.inspector.validators namespace.')
}
var validator = new $.oc.inspector.validators[validatorName](
this.propertyDefinition.validation[validatorName]
)
this.validators.push(validator)
}
BaseEditor.prototype.initValidation = function() {
this.validationSet = new $.oc.inspector.validationSet(this.propertyDefinition, this.propertyDefinition.property)
}
BaseEditor.prototype.disposeValidators = function() {
for (var i = 0, len = this.validators.length; i < len; i++) {
this.validators[i].dispose()
}
BaseEditor.prototype.disposeValidation = function() {
this.validationSet.dispose()
}
BaseEditor.prototype.getValueToValidate = function() {
return this.inspector.getPropertyValue(this.propertyDefinition.property)
}
BaseEditor.prototype.validate = function() {
for (var i = 0, len = this.validators.length; i < len; i++) {
var validator = this.validators[i],
value = this.inspector.getPropertyValue(this.propertyDefinition.property)
var value = this.getValueToValidate()
if (value === undefined) {
value = this.getUndefinedValue()
}
if (value === undefined) {
value = this.getUndefinedValue()
}
if (!validator.isValid(value)) {
$.oc.flashMsg({text: validator.getMessage(), 'class': 'error', 'interval': 5})
return false
}
var validationResult = this.validationSet.validate(value)
if (validationResult !== null) {
$.oc.flashMsg({text: validationResult, 'class': 'error', 'interval': 5})
return false
}
return true

View File

@ -104,7 +104,6 @@
return true
}
ObjectEditor.prototype.getUndefinedValue = function() {
var result = {}
@ -120,6 +119,19 @@
return this.getValueOrRemove(result)
}
ObjectEditor.prototype.validate = function() {
var values = values = this.childInspector.getValues()
if (this.cleanUpValue(values) === $.oc.inspector.removedProperty) {
// Ignore any validation rules if the object's required
// property is empty (ignoreIfPropertyEmpty)
return true
}
return this.childInspector.validate()
}
//
// Event handlers
//

View File

@ -75,7 +75,7 @@
}
StringEditor.prototype.onInputKeyUp = function() {
var value = this.getInput().value
var value = $.trim(this.getInput().value)
this.inspector.setPropertyValue(this.propertyDefinition.property, value)
}

View File

@ -0,0 +1,119 @@
/*
* Inspector validation set class.
*/
+function ($) { "use strict";
// NAMESPACES
// ============================
if ($.oc.inspector.validators === undefined)
$.oc.inspector.validators = {}
// CLASS DEFINITION
// ============================
var Base = $.oc.foundation.base,
BaseProto = Base.prototype
var ValidationSet = function(options, propertyName) {
this.validators = []
this.options = options
this.propertyName = propertyName
Base.call(this)
this.createValidators()
}
ValidationSet.prototype = Object.create(BaseProto)
ValidationSet.prototype.constructor = Base
ValidationSet.prototype.dispose = function() {
this.disposeValidators()
this.validators = null
BaseProto.dispose.call(this)
}
ValidationSet.prototype.disposeValidators = function() {
for (var i = 0, len = this.validators.length; i < len; i++) {
this.validators[i].dispose()
}
}
ValidationSet.prototype.throwError = function(errorMessage) {
throw new Error(errorMessage + ' Property: ' + this.propertyName)
}
ValidationSet.prototype.createValidators = function() {
// Handle legacy validation syntax properties:
//
// - required
// - validationPattern
// - validationMessage
if ((this.options.required !== undefined ||
this.options.validationPattern !== undefined ||
this.options.validationMessage !== undefined) &&
this.options.validation !== undefined) {
this.throwError('Legacy and new validation syntax should not be mixed.')
}
if (this.options.required !== undefined) {
var validator = new $.oc.inspector.validators.required({
message: this.options.validationMessage
})
this.validators.push(validator)
}
if (this.options.validationPattern !== undefined) {
var validator = new $.oc.inspector.validators.regex({
message: this.options.validationMessage,
pattern: this.options.validationPattern
})
this.validators.push(validator)
}
//
// Handle new validation syntax
//
if (this.options.validation === undefined) {
return
}
for (var validatorName in this.options.validation) {
if ($.oc.inspector.validators[validatorName] == undefined) {
this.throwError('Inspector validator "' + validatorName + '" is not found in the $.oc.inspector.validators namespace.')
}
var validator = new $.oc.inspector.validators[validatorName](
this.options.validation[validatorName]
)
this.validators.push(validator)
}
}
ValidationSet.prototype.validate = function(value) {
try {
for (var i = 0, len = this.validators.length; i < len; i++) {
var validator = this.validators[i],
errorMessage = validator.isValid(value)
if (typeof errorMessage === 'string') {
return errorMessage
}
}
return null
}
catch (err) {
this.throwError(err)
}
}
$.oc.inspector.validationSet = ValidationSet
}(window.jQuery);

View File

@ -17,7 +17,9 @@
var BaseValidator = function(options) {
this.options = options
this.defaultMessage = 'Invalid property value'
this.defaultMessage = 'Invalid property value.'
Base.call(this)
}
BaseValidator.prototype = Object.create(BaseProto)
@ -29,9 +31,14 @@
BaseProto.dispose.call(this)
}
BaseValidator.prototype.getMessage = function() {
if (this.options.message !== undefined)
BaseValidator.prototype.getMessage = function(defaultMessage) {
if (this.options.message !== undefined) {
return this.options.message
}
if (defaultMessage !== undefined) {
return defaultMessage
}
return this.defaultMessage
}
@ -49,7 +56,7 @@
}
BaseValidator.prototype.isValid = function(value) {
return true
return null
}
$.oc.inspector.validators.base = BaseValidator

View File

@ -0,0 +1,43 @@
/*
* Base class for Inspector numeric validators.
*/
+function ($) { "use strict";
var Base = $.oc.inspector.validators.base,
BaseProto = Base.prototype
var BaseNumber = function(options) {
Base.call(this, options)
}
BaseNumber.prototype = Object.create(BaseProto)
BaseNumber.prototype.constructor = Base
BaseNumber.prototype.doCommonChecks = function(value) {
if (this.options.min !== undefined || this.options.max !== undefined) {
if (this.options.min !== undefined) {
if (this.options.min.value === undefined)
throw new Error('The min.value parameter is not defined in the Inspector validator configuration')
if (value < this.options.min.value) {
return this.options.min.message !== undefined ?
this.options.min.message :
"The value should not be less than " + this.options.min.value
}
}
if (this.options.max !== undefined) {
if (this.options.max.value === undefined)
throw new Error('The max.value parameter is not defined in the table Inspector validator configuration')
if (value > this.options.max.value) {
return this.options.max.message !== undefined ?
this.options.max.message :
"The value should not be greater than " + this.options.max.value
}
}
}
}
$.oc.inspector.validators.baseNumber = BaseNumber
}(window.jQuery);

View File

@ -0,0 +1,47 @@
/*
* Inspector float validator.
*/
+function ($) { "use strict";
var Base = $.oc.inspector.validators.baseNumber,
BaseProto = Base.prototype
var FloatValidator = function(options) {
Base.call(this, options)
}
FloatValidator.prototype = Object.create(BaseProto)
FloatValidator.prototype.constructor = Base
FloatValidator.prototype.isValid = function(value) {
if (!this.isScalar(value) || typeof value == 'boolean') {
this.throwError('The Float Inspector validator can only be used with string values.')
}
if (value === undefined || value === null) {
return null
}
var string = $.trim(String(value))
if (string.length === 0) {
return null
}
var testResult = this.options.allowNegative ?
/^[-]?([0-9]+\.[0-9]+|[0-9]+)$/.test(string) :
/^([0-9]+\.[0-9]+|[0-9]+)$/.test(string)
if (!testResult) {
var defaultMessage = this.options.allowNegative ?
'The value should be a floating point number.' :
'The value should be a positive floating point number.';
return this.getMessage(defaultMessage)
}
return this.doCommonChecks(parseFloat(string))
}
$.oc.inspector.validators.float = FloatValidator
}(window.jQuery);

View File

@ -0,0 +1,47 @@
/*
* Inspector integer validator.
*/
+function ($) { "use strict";
var Base = $.oc.inspector.validators.baseNumber,
BaseProto = Base.prototype
var IntegerValidator = function(options) {
Base.call(this, options)
}
IntegerValidator.prototype = Object.create(BaseProto)
IntegerValidator.prototype.constructor = Base
IntegerValidator.prototype.isValid = function(value) {
if (!this.isScalar(value) || typeof value == 'boolean') {
this.throwError('The Integer Inspector validator can only be used with string values.')
}
if (value === undefined || value === null) {
return null
}
var string = $.trim(String(value))
if (string.length === 0) {
return null
}
var testResult = this.options.allowNegative ?
/^\-?[0-9]*$/.test(string) :
/^[0-9]*$/.test(string)
if (!testResult) {
var defaultMessage = this.options.allowNegative ?
'The value should be an integer.' :
'The value should be a positive integer.';
return this.getMessage(defaultMessage)
}
return this.doCommonChecks(parseInt(string))
}
$.oc.inspector.validators.integer = IntegerValidator
}(window.jQuery);

View File

@ -0,0 +1,71 @@
/*
* Inspector length validator.
*/
+function ($) { "use strict";
var Base = $.oc.inspector.validators.base,
BaseProto = Base.prototype
var LengthValidator = function(options) {
Base.call(this, options)
}
LengthValidator.prototype = Object.create(BaseProto)
LengthValidator.prototype.constructor = Base
LengthValidator.prototype.isValid = function(value) {
if (value === undefined || value === null) {
return null
}
if (typeof value == 'boolean') {
this.throwError('The Length Inspector validator cannot work with Boolean values.')
}
var length = null
if(Object.prototype.toString.call(value) === '[object Array]' || typeof value === 'string') {
length = value.length
}
else if (typeof value === 'object') {
length = this.getObjectLength(value)
}
if (this.options.min !== undefined || this.options.max !== undefined) {
if (this.options.min !== undefined) {
if (this.options.min.value === undefined)
throw new Error('The min.value parameter is not defined in the Length Inspector validator configuration.')
if (length < this.options.min.value) {
return this.options.min.message !== undefined ?
this.options.min.message :
"The value should not be shorter than " + this.options.min.value
}
}
if (this.options.max !== undefined) {
if (this.options.max.value === undefined)
throw new Error('The max.value parameter is not defined in the Length Inspector validator configuration.')
if (length > this.options.max.value) {
return this.options.max.message !== undefined ?
this.options.max.message :
"The value should not be longer than " + this.options.max.value
}
}
}
}
LengthValidator.prototype.getObjectLength = function(value) {
var result = 0
for (var key in value) {
result++
}
return result
}
$.oc.inspector.validators.length = LengthValidator
}(window.jQuery);

View File

@ -14,26 +14,27 @@
RegexValidator.prototype.constructor = Base
RegexValidator.prototype.isValid = function(value) {
if (this.options.pattern === undefined) {
this.throwError('The pattern parameter is not defined in the Regex Inspector validator configuration.')
}
if (!this.isScalar(value)) {
this.throwError('The Regex Inspector validator can only be used with string values.')
}
if (value === undefined || value === null) {
return true
return null
}
var string = String(value)
var string = $.trim(String(value))
if (string.length == 0)
return
if (this.options.pattern === undefined) {
this.throwError('The pattern parameter is not defined in the Regex Inspector validator configuration.')
if (string.length === 0) {
return null
}
var regexObj = new RegExp(this.options.pattern, this.options.modifiers)
return regexObj.test(string)
return regexObj.test(string) ? null : this.getMessage()
}
$.oc.inspector.validators.regex = RegexValidator

View File

@ -8,6 +8,8 @@
var RequiredValidator = function(options) {
Base.call(this, options)
this.defaultMessage = 'The property is required.'
}
RequiredValidator.prototype = Object.create(BaseProto)
@ -15,18 +17,18 @@
RequiredValidator.prototype.isValid = function(value) {
if (value === undefined || value === null) {
return false
return this.getMessage()
}
if (typeof value === 'boolean') {
return value
return value ? null : this.getMessage()
}
if (typeof value === 'object') {
return !$.isEmptyObject(value)
return !$.isEmptyObject(value) ? null : this.getMessage()
}
return $.trim(String(value)).length > 0
return $.trim(String(value)).length > 0 ? null : this.getMessage()
}
$.oc.inspector.validators.required = RequiredValidator