// --
// Copyright (C) 2001-2020 OTRS AG, https://otrs.com/
// --
// This software comes with ABSOLUTELY NO WARRANTY. For details, see
// the enclosed file COPYING for license information (GPL). If you
// did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
// --
"use strict";
var Core = Core || {};
Core.Form = Core.Form || {};
/**
* @namespace Core.Form.Validate
* @memberof Core.Form
* @author OTRS AG
* @description
* This namespace contains all validation functions.
*/
Core.Form.Validate = (function (TargetNS) {
/**
* @private
* @name Options
* @memberof Core.Form.Validate
* @member {Object}
* @description
* Default options.
*/
var Options = {
FormClass: 'Validate',
ErrorClass: 'Error',
ErrorLabelClass: 'LabelError',
ServerErrorClass: 'ServerError',
ServerLabelClass: 'ServerLabelError',
IgnoreClass: 'ValidationIgnore',
SubmitFunction: {}
};
/*
* check dependencies first
*/
if (!Core.Debug.CheckDependency('Core.Form.Validate', 'Core.UI.Accessibility', 'Core.UI.Accessibility')) {
return false;
}
if (!Core.Debug.CheckDependency('Core.Form.Validate', 'Core.UI.Dialog', 'Core.UI.Dialog')) {
return false;
}
if (!Core.Debug.CheckDependency('Core.Form.Validate', 'Core.Form', 'Core.Form')) {
return false;
}
if (!Core.Debug.CheckDependency('Core.Form.Validate', 'Core.UI.RichTextEditor', 'Core.UI.RichTextEditor')) {
return false;
}
if (!Core.Debug.CheckDependency('Core.Form.Validate', 'Core.Form.ErrorTooltips', 'Core.Form.ErrorTooltips')) {
return false;
}
if (!Core.Debug.CheckDependency('Core.Form.Validate', 'Core.App', 'Core.App')) {
return false;
}
/**
* @name HighlightError
* @memberof Core.Form.Validate
* @function
* @returns {Boolean} False if error is already highlighted
* @param {DOMObject} Element - The DOM object of the form or any element.
* @param {String} ErrorType - The error type (a class that identifies the error type).
* @description
* Shows an error on the element.
*/
TargetNS.HighlightError = function (Element, ErrorType) {
var $Element = $(Element),
InputErrorMessageHTML,
InputErrorMessageText;
// Check error type and correct it, if necessary
if (ErrorType !== 'Error' && ErrorType !== 'ServerError') {
ErrorType = 'Error';
}
// If the element, which has an validation error, is a richtext element, than manually trigger the focus event
if (Core.UI.RichTextEditor.IsEnabled($Element)) {
window.setTimeout(function () {
$Element.focus();
}, 0);
}
// If the element is an Input Field, than manually trigger the focus event
if (Core.UI.InputFields.IsEnabled($Element)) {
window.setTimeout(function () {
$('#' + $Element.data('modernized')).focus();
}, 0);
}
// Check if the element has already an error class
// (that means, this function call is an additional call)
if ($Element.hasClass(Options.ErrorClass)) {
return false;
}
// Add error class to field and its label
$Element.addClass(Options.ErrorClass).triggerHandler('error.InputField');
$(Element.form).find("label[for=" + Core.App.EscapeSelector(Element.id) + "]").addClass(Options.ErrorLabelClass);
// mark field as invalid for screenreader users
$Element.attr('aria-invalid', true);
// save value of element for a later check if field value was changed.
// if the field has a servererror class and the value was not changed,
// keep the error class.
if ($Element.is('input[type="checkbox"], input[type="radio"]')) {
$Element.data('ValidateOldValue', $Element.prop('checked'));
}
else {
$Element.data('ValidateOldValue', $Element.val());
}
// Get the target element and find the associated hidden div with the
// error message.
InputErrorMessageHTML = $('#' + Core.App.EscapeSelector($Element.attr('id')) + ErrorType).html();
InputErrorMessageText = $('#' + Core.App.EscapeSelector($Element.attr('id')) + ErrorType).text();
if (InputErrorMessageHTML && InputErrorMessageHTML.length) {
// If error field is a RTE, it is a little bit more difficult.
if ($('#cke_' + Core.App.EscapeSelector(Element.id)).length) {
Core.Form.ErrorTooltips.InitRTETooltip($Element, InputErrorMessageHTML);
}
// If server error field is RTE, action must be subscribed and loaded when event is finished because RTE is not loaded yet.
else if ($Element.hasClass('RichText') && parseInt(Core.Config.Get('RichTextSet'), 10) === 1)
{
Core.App.Subscribe('Event.UI.RichTextEditor.InstanceReady', function () {
Core.Form.ErrorTooltips.InitRTETooltip($Element, InputErrorMessageHTML);
});
}
else {
Core.Form.ErrorTooltips.InitTooltip($Element, InputErrorMessageHTML);
}
}
// speak the error message for screen reader users
Core.UI.Accessibility.AudibleAlert(InputErrorMessageText);
// if the element is within a collapsed widget, expand that widget to show the error message to the user
if ($Element.closest('.WidgetSimple.Collapsed').find('.WidgetAction.Toggle > a').length) {
$Element.closest('.WidgetSimple.Collapsed').find('.WidgetAction.Toggle > a').trigger('click');
}
};
/**
* @name UnHighlightError
* @memberof Core.Form.Validate
* @function
* @param {Object} Element - The object of the form or any element within this form.
* @description
* Remove error classes from element and its label.
*/
TargetNS.UnHighlightError = function (Element) {
var $Element = $(Element),
ElementValue,
RemoveError = true;
// check ServerError
// if the field value has not changed, do not remove error class
if ($Element.hasClass(Options.ServerErrorClass)) {
if ($Element.is('input[type="checkbox"], input[type="radio"]')) {
ElementValue = $Element.prop('checked');
}
else {
ElementValue = $Element.val();
}
if ($Element.data('ValidateOldValue') === ElementValue) {
RemoveError = false;
}
else {
$Element.removeData('ValidateOldValue');
}
}
if (RemoveError) {
// remove error classes from element and its label
$Element.removeClass(Options.ErrorClass).removeClass(Options.ServerErrorClass).triggerHandler('error.InputField');
if (Element.id && Element.id.length) {
$(Element.form).find("label[for=" + Core.App.EscapeSelector(Element.id) + "]").removeClass(Options.ErrorLabelClass);
}
// mark field as valid for screenreader users
$Element.attr('aria-invalid', false);
// if error field is a RTE, it is a little bit more difficult
if ($('#cke_' + Core.App.EscapeSelector(Element.id)).length) {
Core.Form.ErrorTooltips.RemoveRTETooltip($Element);
} else {
Core.Form.ErrorTooltips.RemoveTooltip($Element);
}
}
};
/**
* @private
* @name OnErrorElement
* @memberof Core.Form.Validate
* @function
* @returns {Boolean} Returns true.
* @description
* This function prevents the default placing of the error messages.
*/
function OnErrorElement() {
return true;
}
/**
* @private
* @name OnSubmit
* @memberof Core.Form.Validate
* @function
* @param {DOMObject} Form - The form object that should be submitted.
* @description
* This function performs the submit action for a form, allowing only be sent once.
*/
function OnSubmit(Form) {
$(Form).removeClass('ClientError').removeClass('LabelError');
if ($.isFunction(Options.SubmitFunction[Form.id])) {
Options.SubmitFunction[Form.id](Form);
}
else {
Form.submit();
}
if ($(Form).hasClass("PreventMultipleSubmits")) {
// fix for Safari: this "disable" comes to early after the submit, so that some fields are
// disabled before submitting and therefor are not submitted
window.setTimeout(function () {
Core.Form.DisableForm($(Form));
}, 0);
}
}
/**
* @private
* @name ValidatorMethodRequired
* @memberof Core.Form.Validate
* @function
* @returns {Boolean} True, if Value has a length, false otherwise.
* @param {String} Value
* @param {DOMObject} Element
* @description
* Validator method for checking if a value is present for
* different types of elements.
*/
function ValidatorMethodRequired(Value, Element) {
var Text,
$Element = $(Element);
// special treatment of <select> elements in OTRS
if (Element.nodeName.toLowerCase() === 'select') {
Text = $(Element).find('option:selected').text();
return (Text.length && Text !== '-');
}
// for richtextareas, get editor code and remove all tags and whitespace
// keep tags if images are embedded because of inline-images
// keep tags if codemirror plugin is used (for XSLT editor)
if (Core.UI.RichTextEditor.IsEnabled($Element)) {
Value = CKEDITOR.instances[Element.id].getData();
if (typeof CKEDITOR.instances[Element.id].config.codemirror === 'undefined' && !Value.match(/<img/)) {
Value = Value.replace(/\s+| |<\/?\w+[^>]*\/?>/g, '');
}
}
// checkable inputs
if ($Element.filter('input[type="checkbox"], input[type="radio"]').length) {
return $Element.filter(':checked').length > 0;
}
return $.trim(Value).length > 0;
}
/**
* @private
* @name ValidatorMethodDnDUpload
* @memberof Core.Form.Validate
* @function
* @returns {Boolean} True if a DnDUpload field has at least one uploaded attachment, false otherwise
* @param {String} Value
* @param {DOMObject} Element
* @description
* Validator method for checking if a value is present for
* different types of elements.
*/
function ValidatorMethodDnDUpload(Value, Element) {
var $AttachmentList = $(Element).prev('.AttachmentListContainer'),
AttachmentCount = $AttachmentList.find('table tbody tr').length;
return AttachmentCount;
}
/*
* Definitions of all OTRS specific rules and rule methods
*/
$.validator.addMethod("Validate_Required", ValidatorMethodRequired, "");
$.validator.addMethod("Validate_Number", $.validator.methods.digits, "");
$.validator.addMethod("Validate_DnDUpload", ValidatorMethodDnDUpload, "");
// There is a configuration option in OTRS that controls if email addresses
// should be validated or not.
// If email address should be validated, this function is overwritten in Init method
$.validator.addMethod("Validate_Email", ValidatorMethodRequired, "");
// Validates e-mail address in a field, but does not return an error if field is empty
$.validator.addMethod("Validate_Email_Optional", function (Value, Element) {
if (!Value.length) {
return true;
}
else {
return $.validator.methods.email.call(this, Value, Element);
}
}, "");
// Use the maxlength attribute to have a dynamic validation
// Textarea fields will need JS code to set the maxlength attribute since is not supported by
// XHTML
$.validator.addMethod("Validate_MaxLength", function (Value, Element) {
// JS takes new lines '\n\r' in textarea elements as 1 character '\n' for length
// calculation purposes therefore is needed to re-add the '\r' to get the correct length
// for validation and match to perl and database criteria
return (Value.replace(/\n\r?/g, "\n\r").length <= $(Element).data('maxlength'));
}, "");
$.validator.addMethod("Validate_DateYear", function (Value) {
return (parseInt(Value, 10) > 999 && parseInt(Value, 10) < 10000);
}, "");
$.validator.addMethod("Validate_DateMonth", function (Value) {
return (parseInt(Value, 10) > 0 && parseInt(Value, 10) < 13);
}, "");
/**
* @private
* @name DateValidator
* @memberof Core.Form.Validate
* @function
* @returns {Boolean} True for a valid date, false otherwise.
* @param {String} Value
* @param {DOMObject} Element
* @param {Object} [DateOptions]
* @param {Boolean} [DateOptions.DateInFuture]
* @param {Boolean} [DateOptions.DateNotInFuture]
* @param {String} [DateOptions.DateAfterPrefix] - Check if the value is after the supplied field prefix
* @param {String} [DateOptions.DateAfterValue] - Check if the value is after the supplied date
* @param {String} [DateOptions.DateBeforePrefix] - Check if the value is before the supplied field prefix
* @param {String} [DateOptions.DateBeforeValue] - Check if the value is before the supplied date
* @description
* Validator method for dates.
*/
function DateValidator (Value, Element, DateOptions) {
var Classes = $(Element).attr('class'),
DateObject,
RegExYear,
RegExMonth,
RegExHour,
RegExMinute,
YearElement = '',
MonthElement = '',
HourElement = '',
MinuteElement = '',
DateYearClassPrefix = 'Validate_DateYear_',
DateMonthClassPrefix = 'Validate_DateMonth_',
DateHourClassPrefix = 'Validate_DateHour_',
DateMinuteClassPrefix = 'Validate_DateMinute_',
DateAfterBefore,
DateCheck,
$UsedObj;
// Skip validation if field is not used (bug#12210)
$UsedObj = $(Element).siblings('input.DynamicFieldText[id*="Used"][type="checkbox"]');
if ($UsedObj.length > 0 && $UsedObj.is(':checked') === false) {
return true;
}
RegExYear = new RegExp(DateYearClassPrefix);
RegExMonth = new RegExp(DateMonthClassPrefix);
RegExHour = new RegExp(DateHourClassPrefix);
RegExMinute = new RegExp(DateMinuteClassPrefix);
$.each(Classes.split(' '), function (Index, ClassValue) {
if (RegExYear.test(ClassValue)) {
YearElement = ClassValue.replace(DateYearClassPrefix, '');
}
if (RegExMonth.test(ClassValue)) {
MonthElement = ClassValue.replace(DateMonthClassPrefix, '');
}
if (RegExHour.test(ClassValue)) {
HourElement = ClassValue.replace(DateHourClassPrefix, '');
}
if (RegExMinute.test(ClassValue)) {
MinuteElement = ClassValue.replace(DateMinuteClassPrefix, '');
}
});
if (YearElement.length && MonthElement.length && $('#' + Core.App.EscapeSelector(YearElement)).length && $('#' + Core.App.EscapeSelector(MonthElement)).length) {
DateObject = new Date($('#' + Core.App.EscapeSelector(YearElement)).val(), $('#' + Core.App.EscapeSelector(MonthElement)).val() - 1, Value);
if (DateObject.getFullYear() === parseInt($('#' + Core.App.EscapeSelector(YearElement)).val(), 10) &&
DateObject.getMonth() + 1 === parseInt($('#' + Core.App.EscapeSelector(MonthElement)).val(), 10) &&
DateObject.getDate() === parseInt(Value, 10)) {
DateCheck = new Date();
if (MinuteElement.length && HourElement.length) {
DateObject.setHours($('#' + Core.App.EscapeSelector(HourElement)).val(), $('#' + Core.App.EscapeSelector(MinuteElement)).val(), 0, 0);
}
else {
DateCheck.setHours(0, 0, 0, 0);
}
if (DateOptions.DateInFuture) {
if (DateObject >= DateCheck) {
return true;
}
}
else if (DateOptions.DateNotInFuture) {
if (DateObject <= DateCheck) {
return true;
}
}
else if (
DateOptions.DateAfterPrefix || DateOptions.DateBeforePrefix
|| DateOptions.DateAfterValue || DateOptions.DateBeforeValue
)
{
DateAfterBefore = DateOptions.DateAfterPrefix || DateOptions.DateBeforePrefix
|| DateOptions.DateAfterValue || DateOptions.DateBeforeValue;
if (DateOptions.DateAfterPrefix || DateOptions.DateBeforePrefix) {
DateAfterBefore = Core.App.EscapeSelector(DateAfterBefore);
if (
$('#' + DateAfterBefore + 'Year').length &&
$('#' + DateAfterBefore + 'Month').length &&
$('#' + DateAfterBefore + 'Day').length
)
{
DateCheck = new Date(
$('#' + DateAfterBefore + 'Year').val(),
$('#' + DateAfterBefore + 'Month').val() - 1,
$('#' + DateAfterBefore + 'Day').val()
);
if (
$('#' + DateAfterBefore + 'Hour').length &&
$('#' + DateAfterBefore + 'Minute').length
)
{
DateCheck.setHours(
$('#' + DateAfterBefore + 'Hour').val(),
$('#' + DateAfterBefore + 'Minute').val(),
0,
0
);
}
else {
DateCheck.setHours(0, 0, 0, 0);
}
}
} else {
DateCheck = new Date(DateAfterBefore);
}
if (DateOptions.DateAfterPrefix || DateOptions.DateAfterValue) {
if (DateObject >= DateCheck) {
return true;
}
} else if (DateOptions.DateBeforePrefix || DateOptions.DateBeforeValue) {
if (DateObject <= DateCheck) {
return true;
}
}
}
else {
return true;
}
}
}
return false;
}
$.validator.addMethod("Validate_DateDay", function (Value, Element) {
return DateValidator(Value, Element, {});
}, "");
$.validator.addMethod("Validate_DateInFuture", function (Value, Element) {
var $DateSelection = $(Element).parent().find('input[type=checkbox].DateSelection, input[type=radio].DateSelection');
// do not do this check for unchecked date/datetime fields
// check first if the field exists to regard the check for the pending reminder field
if ($DateSelection.length && !$DateSelection.prop("checked")) {
return true;
}
return DateValidator(Value, Element, { DateInFuture: true });
}, "");
$.validator.addMethod("Validate_DateNotInFuture", function (Value, Element) {
var $DateSelection = $(Element).parent().find('input[type=checkbox].DateSelection, input[type=radio].DateSelection');
// do not do this check for unchecked date/datetime fields
// check first if the field exists to regard the check for the pending reminder field
if ($DateSelection.length && !$DateSelection.prop("checked")) {
return true;
}
return DateValidator(Value, Element, { DateNotInFuture: true });
}, "");
$.validator.addMethod("Validate_DateAfter", function (Value, Element) {
var $DateSelection = $(Element).parent().find('input[type=checkbox].DateSelection');
// do not do this check for unchecked date/datetime fields
// check first if the field exists to regard the check for the pending reminder field
if ($DateSelection.length && !$DateSelection.prop("checked")) {
return true;
}
if ($(Element).data('validate-date-after')) {
return DateValidator(Value, Element, { DateAfterValue: $(Element).data('validate-date-after') });
}
return DateValidator(Value, Element, {
DateAfterPrefix: $.grep(Element.className.split(" "), function(ClassName){
return ClassName.indexOf('Validate_DateAfter_') === 0;
}).join().substring(19)
});
}, "");
$.validator.addMethod("Validate_DateBefore", function (Value, Element) {
var $DateSelection = $(Element).parent().find('input[type=checkbox].DateSelection');
// do not do this check for unchecked date/datetime fields
// check first if the field exists to regard the check for the pending reminder field
if ($DateSelection.length && !$DateSelection.prop("checked")) {
return true;
}
if ($(Element).data('validate-date-before')) {
return DateValidator(Value, Element, { DateBeforeValue: $(Element).data('validate-date-before') });
}
return DateValidator(Value, Element, {
DateBeforePrefix: $.grep(Element.className.split(" "), function(ClassName){
return ClassName.indexOf('Validate_DateBefore_') === 0;
}).join().substring(20)
});
}, "");
$.validator.addMethod("Validate_DateHour", function (Value) {
return (parseInt(Value, 10) >= 0 && parseInt(Value, 10) < 24);
}, "");
$.validator.addMethod("Validate_DateMinute", function (Value) {
return (parseInt(Value, 10) >= 0 && parseInt(Value, 10) < 60);
}, "");
$.validator.addMethod("Validate_TimeUnits", function (Value) {
return (Value === "" || /^-{0,1}\d+?((\.|,){0,1}\d+?){0,1}$/.test(Value));
}, "");
/*
* Adds a generic method to compare if the given fields are equal
*/
$.validator.addMethod("Validate_Equal", function (Value, Element) {
var Classes = $(Element).attr('class'),
EqualElements = [],
ApplyRule = 0,
EqualClassPrefix = 'Validate_Equal_',
RegExEqual,
I;
RegExEqual = new RegExp(EqualClassPrefix);
$.each(Classes.split(' '), function (Index, ClassValue) {
if (RegExEqual.test(ClassValue)) {
EqualElements.push(ClassValue.replace(EqualClassPrefix, ''));
}
});
if (EqualElements.length) {
for (I = 0; I < EqualElements.length; I++) {
if ($('#' + $.trim(EqualElements[I])).val() === Value) {
ApplyRule++;
}
}
return (ApplyRule === EqualElements.length);
}
});
/*
* Adds a generic method to compare if the given fields are not equal
*/
$.validator.addMethod("Validate_NotEqual", function (Value, Element) {
var Classes = $(Element).attr('class'),
GroupClass = '',
ApplyRule = 1,
EqualClassPrefix = 'Validate_NotEqual_',
RegExEqual;
RegExEqual = new RegExp(EqualClassPrefix);
$.each(Classes.split(' '), function (Index, ClassValue) {
if (RegExEqual.test(ClassValue)) {
GroupClass = ClassValue;
}
});
if (GroupClass !== '') {
$(Element).closest('fieldset fieldset.TableLike').find('.' + GroupClass).each(function () {
if ($(Element).attr('id') !== $(this).attr('id') && $(this).val() === Value) {
ApplyRule = 0;
}
});
}
return ApplyRule;
});
/*eslint-disable camelcase */
$.validator.addClassRules("Validate_Required", {
Validate_Required: true
});
$.validator.addClassRules("Validate_DnDUpload", {
Validate_DnDUpload: true
});
$.validator.addClassRules("Validate_Number", {
Validate_Number: true
});
$.validator.addClassRules("Validate_Email", {
Validate_Email: true
});
$.validator.addClassRules("Validate_Email_Optional", {
Validate_Email_Optional: true
});
$.validator.addClassRules("Validate_MaxLength", {
Validate_MaxLength: true
});
// Backwards compatibility: these methods are deprecated, do not use them!
// They will be removed in OTRS 3.1.
$.validator.addClassRules("Validate_RequiredDropdown", {
Validate_Required: true
});
$.validator.addClassRules("Validate_RequiredRichText", {
Validate_Required: true
});
$.validator.addClassRules("Validate_DateYear", {
Validate_DateYear: true
});
$.validator.addClassRules("Validate_DateMonth", {
Validate_DateMonth: true
});
$.validator.addClassRules("Validate_DateDay", {
Validate_DateDay: true
});
$.validator.addClassRules("Validate_DateHour", {
Validate_DateHour: true
});
$.validator.addClassRules("Validate_DateMinute", {
Validate_DateMinute: true
});
$.validator.addClassRules("Validate_TimeUnits", {
Validate_TimeUnits: true
});
$.validator.addClassRules("Validate_Equal", {
Validate_Equal: true
});
$.validator.addClassRules("Validate_NotEqual", {
Validate_NotEqual: true
});
/*eslint-enable camelcase */
/**
* @private
* @name GetDependentElements
* @memberof Core.Form.Validate
* @function
* @returns {Array} List of DOM IDs of dependent elements.
* @param {DOMObject} Element
* @description
* Get depending elements, based on the 'Validate_Depending' class.
*/
function GetDependentElements(Element) {
var Classes = $(Element).attr('class'),
DependentElementIDs = [],
RegEx,
DependingClassPrefix = 'Validate_Depending_';
RegEx = new RegExp(DependingClassPrefix);
$.each(Classes.split(' '), function (Index, Value) {
if (RegEx.test(Value)) {
DependentElementIDs.push(Value.replace(DependingClassPrefix, ''));
}
});
return DependentElementIDs;
}
/*
* Adds a generic "depending required" rule:
* The element needs a list of IDs in the class attribute. This element is required, if one of the given IDs is a element, which contains content itself (logical AND).
*/
$.validator.addMethod("Validate_DependingRequiredAND", function (Value, Element) {
var I,
DependentElementIDs = [],
$DependentElement;
DependentElementIDs = GetDependentElements(Element);
for (I = 0; I < DependentElementIDs.length; I++) {
$DependentElement = $('#' + $.trim(DependentElementIDs[I]));
if ($DependentElement.length && ValidatorMethodRequired($DependentElement.val(), $DependentElement[0])) {
return ValidatorMethodRequired(Value, Element);
}
}
return true;
}, "");
$.validator.addClassRules("Validate_DependingRequiredAND", {
/*eslint-disable camelcase */
Validate_DependingRequiredAND: true
/*eslint-enable camelcase */
});
/*
* Adds another generic "depending required" rule:
* The element needs a list of IDs in the class attribute. One of the elements (this one or the ones given by ID) is required (logical OR).
*/
$.validator.addMethod("Validate_DependingRequiredOR", function (Value, Element) {
var I,
DependentElementIDs = [],
$DependentElement;
DependentElementIDs = GetDependentElements(Element);
for (I = 0; I < DependentElementIDs.length; I++) {
$DependentElement = $('#' + $.trim(DependentElementIDs[I]));
if ($DependentElement.length && ValidatorMethodRequired($DependentElement.val(), $DependentElement[0])) {
return true;
}
}
return ValidatorMethodRequired(Value, Element);
}, "");
$.validator.addClassRules("Validate_DependingRequiredOR", {
/*eslint-disable camelcase */
Validate_DependingRequiredOR: true
/*eslint-enable camelcase */
});
$.validator.addMethod("Validate_Regex", ValidatorMethodRegex, "");
/**
* @private
* @name ValidatorMethodRegex
* @memberof Core.Form.Validate
* @function
* @returns {Boolean} True, if Value has a length, false otherwise.
* @param {String} Value
* @param {DOMObject} Element
* @description
* Validator method for checking if a value satisfies regex expression.
*/
function ValidatorMethodRegex(Value, Element) {
var Regex = $(Element).attr("data-regex");
if (Value.match(Regex)) {
return true;
}
return false;
}
/**
* @name Init
* @memberof Core.Form.Validate
* @function
* @description
* This function initializes the validation on all forms on the page which have a class named "Validate".
*/
TargetNS.Init = function () {
var FormSelector,
$ServerErrors,
ServerErrorDialogCloseFunction,
ChangedStateID = parseInt($('#ComposeStateID, #NewStateID, #NextStateID').val(), 10),
PendingStateIDs = Core.Config.Get('PendingStateIDs') || [],
Index;
if (Options.FormClass) {
FormSelector = 'form.' + Options.FormClass;
}
else {
FormSelector = 'form';
}
// There is a configuration option in OTRS that controls if email addresses
// should be validated or not.
if (parseInt(Core.Config.Get('CheckEmailAddresses'), 10)) {
$.validator.addMethod("Validate_Email", $.validator.methods.email, "");
}
// Init all forms separately, the validate plugin can
// only handle one at a time.
$(FormSelector).each(function(){
$(this).validate({
ignoreTitle: true,
errorClass: Options.ErrorClass,
highlight: TargetNS.HighlightError,
unhighlight: TargetNS.UnHighlightError,
errorPlacement: OnErrorElement,
submitHandler: OnSubmit,
ignore: '.' + Options.IgnoreClass
});
});
/*
* If on document load there are Error classes present, there were validation errors on server side.
* Show an alert message and initialize the tooltips.
*/
$ServerErrors = $('input.' + Options.ServerErrorClass)
.add('textarea.' + Options.ServerErrorClass)
.add('select.' + Options.ServerErrorClass);
if ($ServerErrors.length) {
$ServerErrors.each(function () {
// Show fields with errors that might be in a collapsed box.
$(this).parents('.WidgetSimple.Collapsed').toggleClass('Collapsed Expanded');
// Highlight error fields.
TargetNS.HighlightError(this, 'ServerError');
});
// When the dialog closes, focus the first element which had a server error
// so that a tooltip will be shown to the user.
ServerErrorDialogCloseFunction = function() {
Core.UI.Dialog.CloseDialog($('.Dialog:visible'));
$ServerErrors.eq(0).focus();
};
Core.UI.Dialog.ShowAlert(Core.Language.Translate('Error'), Core.Language.Translate('One or more errors occurred!'), ServerErrorDialogCloseFunction);
}
// Convert PendingStateIDs array elements to integer.
for (Index = 0; Index < PendingStateIDs.length; Index++) {
PendingStateIDs[Index] = parseInt(PendingStateIDs[Index], 10);
}
// Remove validation on pending fields for non pending states on load.
if (PendingStateIDs.indexOf(ChangedStateID) === -1) {
$('#Day').removeClass('Validate_DateInFuture');
}
// Change event on next state selection.
$('#ComposeStateID, #NewStateID, #NextStateID').on('change', function() {
ChangedStateID = parseInt($(this).val(), 10);
if (PendingStateIDs.indexOf(ChangedStateID) > -1) {
$('#Day').addClass('Validate_DateInFuture');
}
else {
$('#Day').removeClass('Validate_DateInFuture');
}
})
};
/**
* @name ValidateElement
* @memberof Core.Form.Validate
* @function
* @returns {Boolean} True, if element validates, false otherwise.
* @param {jQueryObject} $Element
* @description
* Validate a single element.
*/
TargetNS.ValidateElement = function ($Element) {
if (isJQueryObject($Element)) {
return $Element.closest('form').validate().element($Element);
}
return false;
};
/**
* @name SetSubmitFunction
* @memberof Core.Form.Validate
* @function
* @returns {Boolean} Returns false, if $Form is not a jQueryObject.
* @param {jQueryObject} $Form - The form, for which this submit function is used.
* @param {Function} Func - The function, which is executed on successful submitting the form. Gets the submitted form as a parameter.
* @description
* This function defines the function which is executed when validation was successful on submitting the form.
*/
TargetNS.SetSubmitFunction = function ($Form, Func) {
if (!isJQueryObject($Form)) {
return false;
}
if ($.isFunction(Func) && $Form.length) {
Options.SubmitFunction[$Form.attr('id')] = Func;
}
};
/**
* @name AddDependingValidation
* @memberof Core.Form.Validate
* @function
* @param {String} Name - The name of the rule aka the name of the class attribute used.
* @param {String} Basis - The rule which should be applied.
* @param {Function} Depends - This function defines, if the given basis rule should be checked or not
* (parameter: the element which should be checked; returns true, if rule should be checked)
* @description
* This function adds special validation methods, which check a special rule only, if another depending method returns true.
*/
TargetNS.AddDependingValidation = function (Name, Basis, Depends) {
var RuleHash = {};
RuleHash[Basis] = {
depends: Depends
};
$.validator.addClassRules(Name, RuleHash);
};
/**
* @name AddMethod
* @memberof Core.Form.Validate
* @function
* @param {String} Name - The name of the method.
* @param {Function} Function - This function defines the specific validation method (parameter: value, element, params). Returns true if the element is valid.
* @description
* This function is used to add special validation methods. The name can be used to define new rules.
*/
TargetNS.AddMethod = function (Name, Function) {
if (Name && $.isFunction(Function)) {
$.validator.addMethod(Name, Function, "");
}
};
/**
* @name AddRule
* @memberof Core.Form.Validate
* @function
* @param {String} Name - The name of the rule.
* @param {Object} MethodHash - This JS object defines, which methods should be included in this rule, e.g. { OTRS_Validate_Required: true, OTRS-Validate_MinLength: 2 }.
* @description
* This function is used to add special validation rules. The name is also the class name you can use in the HTML.
*/
TargetNS.AddRule = function (Name, MethodHash) {
if (Name && typeof MethodHash === "object") {
$.validator.addClassRules(Name, MethodHash);
}
};
/**
* @name DisableValidation
* @memberof Core.Form.Validate
* @function
* @param {jQueryObject} $Form - The form object that should be disabled.
* @description
* This function is used to disable all the elements of a Form object.
*/
TargetNS.DisableValidation = function ($Form) {
// If no form is given, disable validation in all form elements on the complete site
if (!isJQueryObject($Form)) {
$Form = $('body');
}
$Form
.find("input:not([type='hidden']), textarea, select")
.addClass(Options.IgnoreClass);
};
/**
* @name EnableValidation
* @memberof Core.Form.Validate
* @function
* @param {jQueryObject} $Form - The form object that should be enabled.
* @description
* This function is used to enable all the elements of a Form object.
*/
TargetNS.EnableValidation = function ($Form) {
// If no form is given, disable validation in all form elements on the complete site
if (!isJQueryObject($Form)) {
$Form = $('body');
}
$Form
.find("input:not([type='hidden']), textarea, select")
.removeClass(Options.IgnoreClass);
};
Core.Init.RegisterNamespace(TargetNS, 'APP_GLOBAL');
return TargetNS;
}(Core.Form.Validate || {}));