/* --------------------------------------------------------------
validator.js 2016-10-14
Gambio GmbH
http://www.gambio.de
Copyright (c) 2016 Gambio GmbH
Released under the GNU General Public License (Version 2)
[http://www.gnu.org/licenses/gpl-2.0.html]
--------------------------------------------------------------
*/
/**
* ## Validator Extension
*
* Validate form elements for common rules such as required fields, email addresses and other useful
* pre-defined types. You can add new validation types by appending the list in the end of this file.
*
* ### Methods
*
* ```javascript
* $parent.trigger('validator.validate'); // Trigger validation manually.
* $parent.trigger('validator.reset'); // Reset validator state.
* ```
*
* ### Example Usage
*
* The following element will be validated as a required field and the value must be a valid email
* address (two validation rules).
*
* ```html
* <div id="parent" data-gx-extension="validator">
* <input type="email" class="validate" data-validator-validate="required email" />
* </div>
*```
*
* The following script demonstrates how to check if there are currently invalid elements in the form.
*
* ```javascript
* // Trigger validation manually:
* $('#parent').trigger('validator.validate');
*
* // Check for invalid field values.
* if ($('#parent .error').length > 0) {
* // Invalid elements have the ".error" class.
* } else {
* // Valid input elements have the ".valid" class.
* }
* ```
*
* @todo Remove fallback code from this module and create a $.fn.validator API.
*
* @module JSE/Extensions/validator
*/
jse.extensions.module(
'validator',
['fallback'],
/** @lends module:Extensions/validator */
function (data) {
'use strict';
// ------------------------------------------------------------------------
// VARIABLE DEFINITION
// ------------------------------------------------------------------------
var
/**
* Extension Reference
*
* @type {object}
*/
$this = $(this),
perform = {
/**
* Validate required fields.
*/
required: function ($element, value, type, opt) {
switch (type) {
case 'select':
return (parseInt(value, 10) === -1) ? false : true;
case 'checkbox':
return (parseInt(value, 10) === -1) ? false : true;
case 'radio':
return false;
default:
return (value) ? true : false;
}
},
/**
* Validate email addresses (you should also validate emails at server side before storing).
*/
email: function ($element, value, type, opt) {
if (value === '' && opt.validate.indexOf('required') === -1) {
$element.removeClass('error valid');
return null; // Do not validate empty strings (that are not required).
}
var match = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return match.test(value);
},
/**
* Use this type along with the "required" to check if a CKEditor element is
* empty or not. In case that it has the ".error" class you must find you own
* way to display that the field is invalid because you cannot display a red
* border directly to the validated textarea (CKEditor adds many HTML elements
* to the page).
*/
ckeditor: function ($element, value, type, opt) {
var id = $element.attr('id');
if (id === undefined) {
throw 'Cannot validate CKEditor for element without id attribute.';
}
return (CKEDITOR.instances[id].getData() !== '') ? true : false;
}
},
/**
* Default Options for Extension
*
* @type {object}
*/
defaults = {},
/**
* Final Extension Options
*
* @type {object}
*/
options = $.extend(true, {}, defaults, data),
/**
* Meta Object
*
* @type {object}
*/
module = {};
// ------------------------------------------------------------------------
// FUNCTIONALITY
// ------------------------------------------------------------------------
/**
* Set State
*
* @param {object} $element Validated element selector.
* @param {string} state Describes current state ("valid", "error").
*/
var _setState = function ($element, state) {
switch (state) {
case 'valid':
$element
.removeClass('error')
.addClass('valid');
break;
case 'error':
$element
.removeClass('valid')
.addClass('error');
break;
default:
$element.removeClass('valid error');
break;
}
};
/**
* Validate Item
*
* @return {boolean} Returns the validation result.
*/
var _validateItem = function () {
var $self = $(this),
settings = jse.libs.fallback._data($self, 'validator'),
validate = (settings.validate) ? settings.validate.split(' ') : [],
type = $self.prop('tagName').toLowerCase(),
result = true;
type = (type !== 'input') ? type : $self.attr('type').toLowerCase();
$.each(validate, function (index, validationType) {
var isValid = perform[validationType]($self, $self.val(), type, settings);
if (isValid !== null) {
_setState($self, (isValid) ? 'valid' : 'error');
result = (!result) ? false : isValid;
}
});
return result;
};
/**
* Validate Multiple Items
*
* @param {object} event Contains the event information.
* @param {object} deferred Defines the deferred object.
*/
var _validateItems = function (event, deferred) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
var $self = event ? $(event.target) : $this,
valid = true;
$self
.filter('.validate')
.add($self.find('.validate'))
.each(function () {
var current = _validateItem.call($(this));
valid = (!valid) ? false : current;
});
if (deferred && deferred.deferred) {
if (valid) {
deferred.deferred.resolve();
} else {
deferred.deferred.reject();
}
}
return valid;
};
/**
* Reset Validator Elements
*/
var _resetValidator = function () {
$this
.filter('.validate')
.add($this.find('.validate'))
.each(function () {
_setState($(this), 'reset');
});
};
// ------------------------------------------------------------------------
// INITIALIZATION
// ------------------------------------------------------------------------
/**
* Init function of the extension, called by the engine.
*/
module.init = function (done) {
$this
.on('change', '.validate:text:visible', _validateItem)
.on('validator.validate', _validateItems)
.on('validator.reset', _resetValidator)
.on('submit', function (event) {
if (!_validateItems()) {
event.preventDefault();
}
});
done();
};
// Return data to module engine.
return module;
});