Source: modules/ui/SuiValidator.jsxinc

BX.use('brixy', 'modules/es/types.jsxinc');

/**
* Validator object.
* 
* @module 'brixy.ui.SuiValidator'
*/
BX.module.define('brixy.ui.SuiValidator', function() {
	var types = BX.module('brixy.es.types');
	
	/*
	* Rule object holds settings for Validators methods.
	* @class
	* @param {ScriptUIcontrol} element - Tested element.
	* @param {function} validator - Validator method.
	* @param {boolean} negate - Negate the rule.
	* @param {string} property - Tested property of the element.
	* @param {Array} args - Additional parameters that will be passed to validator method. The last may be a custom error message.
	*/
	function Rule(element, validator, negate, property, args) {
		this.element = element;
		this.validator = validator;
		this.negate = negate;
		this.property = property;
		this.args = args;
	}
	
	/*
	* Returns a string representation of the object.
	* @method
	* @return {string}
	*/
	Rule.prototype.toString = BX.toString;
	
	/*
	* Gets an array of arguments for validator callback.
	* @return {Array}
	*/
	Rule.prototype.getArgs = function() {
		return [].concat(this.negate, this.element[this.property], this.args);
	};

	
	/*
	* CustomRule object holds settings for custom validator method.
	* @class
	* @param {ScriptUIcontrol} element - Tested element.
	* @param {function} validator - Validator method.
	* @param {Array} args - Additional parameters that will be passed to validator method.
	*/
	function CustomRule(element, validator, args) {
		this.element = element;
		this.validator = validator;
		this.args = args;
	}
	
	/*
	* Returns a string representation of the object.
	* @method
	* @return {string}
	*/
	CustomRule.prototype.toString = BX.toString;
	
	/*
	* Gets an array of arguments for validator callback.
	* @return {Array}
	*/
	CustomRule.prototype.getArgs = function() {
		return this.args;
	};
	
	/**
	* SuiValidator object.
	* @class
	* @alias module:'brixy.ui.SuiValidator'~SuiValidator
	*/
	function SuiValidator() {
		this._rules = [];
	}
	
	/**
	* Returns a string representation of the object.
	* @method
	* @return {string}
	*/
	SuiValidator.prototype.toString = BX.toString;
	
	/**
	* Validate all rules.
	* @return {boolean} Result of the validation.
	*/
	SuiValidator.prototype.validate = function() {
		try{
			for (var i = 0, n = this._rules.length; i < n; i++) {
				if (!this._validateRule(this._rules[i]))
					return false;
			}
		}
		catch(e){
			alert('Validation failed. ' + e);
			return false;
		}
		
		return true;
	};
	
	/*
	* Validates a rule.
	* @param {Rule} rule - Tested rule.
	* @return {boolean} Result of the validation.
	* @throws {string} Exception if validation failed.
	*/
	SuiValidator.prototype._validateRule = function(rule) {
		try {
			rule.validator.apply(rule.element, rule.getArgs());
		}
		catch (e) {
			alert(e || 'Validation failed.');
				
			if (rule.element.visible && ('active' in rule.element))
				rule.element.active = true;
			
			return false;
		}
	
		return true;
	};
	
	/**
	* Adds new rule.
	* @param {ScriptUIcontrol} element - Tested element.
	* @param {string|function} validator - Validator method.
	* @param {Array} [args] - Additional parameters will be passed to validator method. (optional)
	* @throws {string} Exception if a validator rule cannot be set.
	*/
	SuiValidator.prototype.addRule = function(element, validator, args) {
		// element
		if (!element || typeof element !== 'object')
			throw Error('Element is not defined.');
			
		var ctype = types.className(validator),
			negate = false,
			property = '';
		
		// validator is a string
		if (ctype === 'String') {
			validator = validator.toLowerCase();
			
			if (validator.length > 1) {
				negate = validator[0] === '!';
				if (negate)
					validator = validator.substring(1);
			}
			
			if (validator in Validators)
				validator = Validators[validator];
			else
				throw Error('Validator "' + validator + '" was not found.');
				
			// tested property
			if (!args || !args.length) { // not defined, try to find a 'text' or 'value' property
				if ('text' in element)
					property = 'text';
				else if ('value' in element)
					property = 'value';
				else
					throw Error('Tested property of the ' + element + ' is not defined.');
			}
			else
				property = args[0];
				
			if (!(property in element))
				throw Error('The tested property ' + element + '.' + property + ' is not defined. Please specify the property name as the second parameter.');
			
			// add rule
			this._rules.push(new Rule(element, validator, negate, property, [].slice.call(args, 1)));
		}
		// validator is a function
		else if (ctype === 'Function') {
			// add rule
			this._rules.push(new CustomRule(element, validator, [].concat(args)));
		}
		else
			throw Error('Validator method should be a function.');
	};
	
	
	// Static validator methods:
	
	/**
	* Validators namespace.
	* @namespace
	* @memberOf module:'brixy.ui.SuiValidator'
	*/
	var Validators = {
		
		/**
		* Tests if the value equals to the required value.
		* @param {boolean} negate - Negate the condition.
		* @param {*} value - Tested value.
		* @param {*} required - Required value.
		* @param {string} [message] - Custom error message. (optional)
		*/
		equal: function(negate, value, required, message) {
			if (!!negate !== (value == required))
				return;
			
			if (message)
				throw message;
				
			if (negate)
				throw 'This field should not be equal to ' + required + '.';
			
			throw 'Please enter ' + required + '.';
		},
		
		/**
		* Tests if the value has the required length.
		* @param {boolean} negate - Negate the condition.
		* @param {*} value - Tested value.
		* @param {int} [min=0] - Minimum length of the value. (optional)
		* @param {int} [max=min] - Maximum length of the value. (optional)
		* @param {string} [message] - Custom error message. (optional)
		*/
		haslength: function(negate, value, min, max, message) {
			var n = (value != undefined && value.length != undefined) ? value.length : 0;
			
			min = (min == undefined) ? 0 : min - 0;
			max = (max == undefined || max < min) ? min : max - 0;
			
			if (!!negate !== (n >= min && n <= max))
				return;
				
			if (message)
				throw message;
				
			if (min == max) {
				if (negate)
					throw 'A length should not be ' + min + '.';
				else
					throw 'A length should be ' + min + '.';
			}
			else {
				if (negate)
					throw 'A length should be less than ' + min + ' or greater than ' + max + '.';
				else
					throw 'A length should be between ' + min + ' and ' + max + '.';
			}
		},
		
		/**
		* Tests if the value occurs in the array.
		* @param {boolean} negate - Negate the condition.
		* @param {*} value - Tested value.
		* @param {Array} array - Array of values.
		* @param {string} [message] - Custom error message. (optional)
		*/
		inarray: function(negate, value, array, message) {
			var arr = (array == undefined) ? [] : [].concat(array),
				i = 0,
				n = arr.length,
				r = false;
			
			for ( ; i < n; i++) {
				if (value == arr[i]) {
					r = true;
					break;
				}
			}
			
			if (!!negate !== r)
				return;
				
			if (message)
				throw message;
				
			throw 'Please fill in a suitable value.';
		},
		
		/**
		* Tests if the value is decimal. Exponential notation is not allowed (e.g. 1.2e+25).
		* @param {boolean} negate - Negate the condition.
		* @param {*} value - Tested value.
		* @param {string} [decimalPoint=$.decimalPoint] - Decimal separator. (optional)
		* @param {string} [message] - Custom error message. (optional)
		*/
		isdecimal: function(negate, value, decimalPoint, message) {
			var dp = (!decimalPoint) ? $.decimalPoint : decimalPoint,
				reg = RegExp('^\\s*[-+]?\\d+(?:' + types.escapeRegexpStr(dp) + '\\d*)?\\s*$');
				
			if (!!negate !== reg.test(value))
				return;
				
			if (message)
				throw message;
				
			if (negate)
				throw 'Value should not be a decimal.';
			
			throw 'Please fill in a decimal value.';
		},
		
		/**
		* Tests if the value is integer. Exponential notation is not allowed (e.g. 1e+25).
		* @param {boolean} negate - Negate the condition.
		* @param {*} value - Tested value.
		* @param {string} [message] - Custom error message. (optional)
		*/
		isinteger: function(negate, value, message) {
			if (!!negate !== /^\s*[-+]?\d+\s*$/.test(value))
				return;
				
			if (message)
				throw message;
				
			if (negate)
				throw 'Value should not be an integer.';
			
			throw 'Please fill in an integer value.';
		},
		
		/**
		* Tests if the array contains a checked or selected item.
		* 
		* @example
		* column().validator('itemselected', 'children')
		* listBox().validator('itemselected', 'items')
		* // or:
		* listBox().validator('required', 'selection')
		* 
		* @param {boolean} negate - Negate the condition.
		* @param {Array} value - Tested array.
		* @param {string} [message] - Custom error message. (optional)
		*/
		itemselected: function(negate, value, message) {
			var i,
				n,
				v,
				r = false;
			
			if (value != undefined && value.length) {
				for (i = 0, n = value.length; i < n; i++) {
					v = value[i];
					if (v && (typeof v === 'object') && (v.value || v.selected)) {
						r = true;
						break;
					}
				}
			}
			
			if (!!negate !== r)
				return;
				
			if (message)
				throw message;
				
			if (negate)
				throw 'Items should not be selected.';
			
			throw 'Please select an item.';
		},

		/**
		 * Tests if the number is lesser than or equal to a given limit.
		 * @param {boolean} negate - Negate the condition.
		 * @param {*} value - Tested value.
		 * @param {*} [max=0] - Maximum value. (optional)
		 * @param {string} [message] - Custom error message. (optional)
		 */
		maximum: function(negate, value, max, message) {
			max = (max == undefined) ? 0 : max - 0;

			if (!!negate !== value <= max)
				return;

			if (message)
				throw message;

			if (negate)
				throw 'Please enter a value greater than ' + max + '.';
			else
				throw 'Please enter a value less than or equal to ' + max + '.';
		},

		/**
		* Tests if the value has maximum length.
		* @param {boolean} negate - Negate the condition.
		* @param {*} value - Tested value.
		* @param {int} [max=0] - Maximum length of the value. (optional)
		* @param {string} [message] - Custom error message. (optional)
		*/
		maxlength: function(negate, value, max, message) {
			Validators.haslength.call(this, negate, value, Number.MIN_VALUE, max, message);
		},

		/**
		 * Tests if the number is greater than or equal to a given limit.
		 * @param {boolean} negate - Negate the condition.
		 * @param {*} value - Tested value.
		 * @param {*} [min=0] - Minimum value. (optional)
		 * @param {string} [message] - Custom error message. (optional)
		 */
		minimum: function(negate, value, min, message) {
			min = (min == undefined) ? 0 : min - 0;

			if (!!negate !== value >= min)
				return;

			if (message)
				throw message;

			if (negate)
				throw 'Please enter a value lesser than ' + min + '.';
			else
				throw 'Please enter a value greater than or equal to ' + min + '.';
		},

		/**
		* Tests if the value has minimum length.
		* @param {boolean} negate - Negate the condition.
		* @param {*} value - Tested value.
		* @param {int} [min=0] - Minimum length of the value. (optional)
		* @param {string} [message] - Custom error message. (optional)
		*/
		minlength: function(negate, value, min, message) {
			Validators.haslength.call(this, negate, value, min, Number.MAX_VALUE, message);
		},
		
		/**
		* Tests if value matches the regular expression. Uses the Extend Script RegExp object.
		* @param {boolean} negate - Negate the condition.
		* @param {*} value - Tested value.
		* @param {RegExp|string} regexp - Regular expression or string. In case of string, the doubling of backslashles is necessary.
		* @param {string} [message] - Custom error message. (optional)
		*/
		pattern: function(negate, value, regexp, message) {
			var reg = (regexp instanceof RegExp) ? regexp : RegExp(regexp);
			
			if (!!negate !== reg.test(value))
				return;
				
			if (message)
				throw message;
				
			throw 'Please fill in the suitable value.';
		},
		
		/**
		* Tests if the value is in required range.
		* @param {boolean} negate - Negate the condition.
		* @param {*} value - Tested value.
		* @param {*} [min=0] - Minimum value. (optional)
		* @param {*} [max=min] - Maximum value. (optional)
		* @param {string} [message] - Custom error message. (optional)
		*/
		range: function(negate, value, min, max, message) {
			min = (min == undefined) ? 0 : min - 0;
			max = (max == undefined || max < min) ? min : max - 0;

			if (!!negate !== (value >= min && value <= max))
				return;
				
			if (message)
				throw message;
				
			if (min == max) {
				if (negate)
					throw 'A value should not be ' + min + '.';
				else
					throw 'Please enter ' + min + '.';
			}
			else {
				if (negate)
					throw 'Please enter a value less than ' + min + ' or greater than ' + max + '.';
				else
					throw 'Please enter a value between ' + min + ' and ' + max + '.';
			}
		},
		
		/**
		* Tests if the value is defined and is not empty string. Boolean values (true or false) are both OK.
		* 
		* @example
		* dropDownList().validator('required', 'selection')
		* editText().validator('required') // tests 'text' property
		* 
		* @param {boolean} negate - Negate the condition.
		* @param {*} value - Tested value.
		* @param {string} [message] - Custom error message. (optional)
		*/
		required: function(negate, value, message) {
			if (!!negate !== (value != undefined && value !== ''))
				return;
				
			if (message)
				throw message;
				
			if (negate)
				throw 'This field should be empty.';
				
			throw 'Please fill in the required value.';
		}
		
	};
	
	
	// publish
	return {
		Validators: Validators,
		/** 
		* SuiValidator class.
		* @memberOf module:'brixy.ui.SuiValidator'
		* @type {module:'brixy.ui.SuiValidator'~SuiValidator}
		*/
		Me: SuiValidator
	};
});