<!DOCTYPE html>
<html ng-app="rmaApp">
<head>
<link data-require="bootstrap-css@3.1.1" data-semver="3.1.1" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
<script data-require="angular.js@1.4.5" data-semver="1.4.5" src="https://code.angularjs.org/1.4.5/angular.js"></script>
<script data-require="angular-resource@1.4.5" data-semver="1.4.5" src="https://code.angularjs.org/1.4.5/angular-resource.js"></script>
<script src="autovalidate.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div class="form-group">
<sel-phone-number label="Country Code and Phone Number" name="technicalContactPhone" id="technicalContactPhone" ng-model="technicalContactPhone" required="true"></sel-phone-number>
</div>
</body>
</html>
(function() {
'use strict';
var app = angular.module('rmaApp', ['jcs-autoValidate','ngResource']);
app.run(['$q', '$rootScope', 'validator', 'defaultErrorMessageResolver',
function($q, $rootScope, validator, defaultErrorMessageResolver) {
// turn off angular auto validate icons.
validator.setValidElementStyling(false);
defaultErrorMessageResolver.getErrorMessages().then(function(errorMessages) {
errorMessages.phone = 'Please enter a valid phone number, including Country Calling Code and Area Code';
});
}
]);
app.factory('validatePhoneService', validatePhoneService);
validatePhoneService.$inject = ['$q', '$resource'];
function validatePhoneService($q, $resource) {
var phoneService = {
countryCallingCode: '',
phone: '',
checkPhone: checkPhone,
parsePhone: parsePhone
};
return phoneService;
// Checks the phone to see if it is valid by passing it to the server where it is ran against the phone number validator from Google.
function checkPhone(countryCallingCode, phone) {
var deferred = $q.defer();
if (angular.isDefined(phone) && phone.length > 0) {
var parsedPhone = parsePhone(countryCallingCode, phone);
console.log('checking phone via service');
return $resource('https://www1.selinc.com/api/phone/validate/:phoneccc/:phone/').get({
phoneccc: parsedPhone.countryCallingCode,
phone: parsedPhone.phone
}).$promise.then(function(data) {
if (data.valid) {
phoneService.countryCallingCode = data.countryCallingCode;
phoneService.phone = data.phone;
deferred.resolve();
return deferred.promise;
} else {
console.log("data not valid", data);
deferred.reject();
return deferred.promise;
}
}, function(error) {
console.log(error);
deferred.reject(error);
return deferred.promise;
});
} else {
deferred.reject();
return deferred.promise;
}
}
// Parse a phone number country calling code and phone number body into an object.
// If there is no phone number country calling code, attempt to find it in the body.
function parsePhone(countryCallingCode, phone) {
// Split the phone number up into an array for later use.
// The delimiter
var d = '',
phoneArray = [],
result = {
countryCallingCode: '',
phone: phone
};
// What delimiter is being used.
if (phone.indexOf(' ') > -1) {
d = ' ';
}
if (phone.indexOf('.') > -1) {
d = '.';
}
if (phone.indexOf('-') > -1) {
d = '-';
}
// Split the phone number into an array by the delimiter
phoneArray = phone.split(d);
// Try to set country calling code to the form value
result.countryCallingCode = countryCallingCode;
if (angular.isDefined(result.countryCallingCode) && result.countryCallingCode !== '') {
// Remove the + from the ccc if there.
result.countryCallingCode = result.countryCallingCode.replace('+', '');
} else {
// Set ccc to the first element in the array, that should be the country calling code
result.countryCallingCode = phoneArray[0];
if (angular.isDefined(result.countryCallingCode) && result.countryCallingCode !== '') {
// Get rid of the + if it is there.
result.countryCallingCode = result.countryCallingCode.replace('+', '');
// Remove the ccc from the phone array then rejoin it using a period and set it to the element
phoneArray.splice(0, 1);
result.phone = phoneArray.join('.');
}
}
return result;
}
}
app.directive('selPhoneNumber', selPhoneNumber);
selPhoneNumber.$inject = ['validatePhoneService'];
function selPhoneNumber(validatePhoneService) {
// Usage:
// <sel-phone-number id="SomeId" ng-model="{countryCallingCode: '', phone:''}" required="true"></sel-phone-number>
// Creates:
//
var directive = {
scope: {
label: "@",
id: "@",
required: "=?" // Are fields required.
},
link: link,
restrict: 'E',
require: 'ngModel',
template: '<div class="form-group"><label class="control-label" for="{{id}}">{{label}}</label><div class="input-group"> <input type="text" name="country-code" class="form-control" style="width:60px" ng-model="countryCallingCode" ng-required="required" uib-tooltip="Country Calling Code. Example: +1 for US" tooltip-trigger="focus" tooltip-placement="top" readonly onfocus="this.removeAttribute(\'readonly\');"> <span class="input-group-addon" style="width:0; border-left: 0; border-right: 0;"><b>.</b></span> <input type="tel" name="phone" class="form-control" id="{{id}}" ng-model="phone" ng-required="required" uib-tooltip="Phone Number. Example: 123.555.1212" tooltip-trigger="focus" tooltip-placement="top"> </div></div>'
};
return directive;
function link(scope, element, attrs, ctrl) {
// If user does not pass in required, then assume it is not required (if we don't do this, it will be undefined)
if (scope.required === undefined) {
scope.required = false;
}
scope.countryCallingCode = '';
scope.phone = '';
// Checks the phone values when there is a data load into the field.
ctrl.$render = function() {
if (ctrl.$viewValue !== undefined && ctrl.$viewValue !== null) {
scope.countryCallingCode = ctrl.$viewValue.countryCallingCode;
scope.phone = ctrl.$viewValue.phone;
}
};
scope.$watch("phone", function() {
console.log("checking from watch");
checkPhone();
});
function checkPhone() {
console.log("checking");
if (!angular.isDefined(scope.phone) || scope.phone.length === 0) {
return;
}
validatePhoneService.checkPhone(scope.countryCallingCode, scope.phone).then(function() {
scope.countryCallingCode = validatePhoneService.countryCallingCode;
scope.phone = validatePhoneService.phone;
ctrl.$setViewValue({
countryCallingCode: scope.countryCallingCode,
phone: scope.phone
});
ctrl.removeExternalValidation('phone');
}, function() {
ctrl.setExternalValidation('phone', 'validateSelPhone');
});
}
}
}
})();
/* Styles go here */
/*
* angular-auto-validate - v1.19.3 - 2015-11-30
* https://github.com/jonsamwell/angular-auto-validate
* Copyright (c) 2015 Jon Samwell (http://www.jonsamwell.com)
*/
(function (String, angular) {
'use strict';
angular.module('jcs-autoValidate', []);
function ValidatorFn() {
var elementStateModifiers = {},
enableValidElementStyling = true,
enableInvalidElementStyling = true,
enableFirstInvalidElementScrollingOnSubmit = false,
validationEnabled = true,
toBoolean = function (value) {
var v;
if (value && value.length !== 0) {
v = value.toLowerCase();
value = !(v === 'f' || v === '0' || v === 'false');
} else {
value = false;
}
return value;
},
getAttributeValue = function (el, attrName) {
var val;
if (el !== undefined) {
val = el.attr(attrName) || el.attr('data-' + attrName);
}
return val;
},
attributeExists = function (el, attrName) {
var exists;
if (el !== undefined) {
exists = el.attr(attrName) !== undefined || el.attr('data-' + attrName) !== undefined;
}
return exists;
},
getBooleanAttributeValue = function (el, attrName) {
return toBoolean(getAttributeValue(el, attrName));
},
validElementStylingEnabled = function (el) {
return enableValidElementStyling && !getBooleanAttributeValue(el, 'disable-valid-styling');
},
autoValidateEnabledOnControl = function (el) {
return !getBooleanAttributeValue(el, 'disable-auto-validate');
},
invalidElementStylingEnabled = function (el) {
return enableInvalidElementStyling && !getBooleanAttributeValue(el, 'disable-invalid-styling');
};
/**
* @ngdoc function
* @name validator#enable
* @methodOf validator
*
* @description
* By default auto validate will validate all forms and elements with an ngModel directive on. By
* setting enabled to false you will explicitly have to opt in to enable validation on forms and child
* elements.
*
* Note: this can be overridden by add the 'auto-validate-enabled="true/false' attribute to a form.
*
* Example:
* <pre>
* app.config(function (validator) {
* validator.enable(false);
* });
* </pre>
*
* @param {Boolean} isEnabled true to enable, false to disable.
*/
this.enable = function (isEnabled) {
validationEnabled = isEnabled;
};
/**
* @ngdoc function
* @name validator#isEnabled
* @methodOf validator
*
* @description
* Returns true if the library is enabeld.
*
* @return {Boolean} true if enabled, otherwise false.
*/
this.isEnabled = function () {
return validationEnabled;
};
/**
* @ngdoc function
* @name validator#setDefaultElementModifier
* @methodOf validator
*
* @description
* Sets the default element modifier that will be used by the validator
* to change an elements UI state. Please ensure the modifier has been registered
* before setting it as default.
*
* Note: this can be changed by setting the
* element modifier attribute on the input element 'data-element-modifier="myCustomModifier"'
*
* Example:
* <pre>
* app.config(function (validator) {
* validator.setDefaultElementModifier('myCustomModifier');
* });
* </pre>
*
* @param {string} key The key name of the modifier.
*/
this.setDefaultElementModifier = function (key) {
if (elementStateModifiers[key] === undefined) {
throw new Error('Element modifier not registered: ' + key);
}
this.defaultElementModifier = key;
};
/**
* @ngdoc function
* @name validator#registerDomModifier
* @methodOf validator
*
* @description
* Registers an object that adheres to the elementModifier interface and is
* able to modifier an elements dom so that appears valid / invalid for a specific
* scenario i.e. the Twitter Bootstrap css framework, Foundation CSS framework etc.
*
* Example:
* <pre>
* app.config(function (validator) {
* validator.registerDomModifier('customDomModifier', {
* makeValid: function (el) {
* el.removeClass(el, 'invalid');
* el.addClass(el, 'valid');
* },
* makeInvalid: function (el, err, domManipulator) {
* el.removeClass(el, 'valid');
* el.addClass(el, 'invalid');
* }
* });
* });
* </pre>
*
* @param {string} key The key name of the modifier
* @param {object} modifier An object which implements the elementModifier interface
*/
this.registerDomModifier = function (key, modifier) {
elementStateModifiers[key] = modifier;
};
/**
* @ngdoc function
* @name validator#setErrorMessageResolver
* @methodOf validator
*
* @description
* Registers an object that adheres to the elementModifier interface and is
* able to modifier an elements dom so that appears valid / invalid for a specific
* scenario i.e. the Twitter Bootstrap css framework, Foundation CSS framework etc.
*
* Example:
* <pre>
* app.config(function (validator) {
* validator.setErrorMessageResolver(function (errorKey, el) {
* var defer = $q.defer();
* // resolve the correct error from the given key and resolve the returned promise.
* return defer.promise();
* });
* });
* </pre>
*
* @param {function} resolver A method that returns a promise with the resolved error message in.
*/
this.setErrorMessageResolver = function (resolver) {
this.errorMessageResolver = resolver;
};
/**
* @ngdoc function
* @name validator#getErrorMessage
* @methodOf validator
*
* @description
* Resolves the error message for the given error type.
*
* @param {String} errorKey The error type.
* @param {Element} el The UI element that is the focus of the error.
* It is provided as the error message may need information from the element i.e. ng-min (the min allowed value).
*/
this.getErrorMessage = function (errorKey, el) {
var defer;
if (this.errorMessageResolver === undefined) {
throw new Error('Please set an error message resolver via the setErrorMessageResolver function before attempting to resolve an error message.');
}
if (attributeExists(el, 'disable-validation-message')) {
defer = angular.injector(['ng']).get('$q').defer();
defer.resolve('');
return defer.promise;
} else {
return this.errorMessageResolver(errorKey, el);
}
};
/**
* @ngdoc function
* @name validator#setValidElementStyling
* @methodOf validator
*
* @description
* Globally enables valid element visual styling. This is enabled by default.
*
* @param {Boolean} enabled True to enable style otherwise false.
*/
this.setValidElementStyling = function (enabled) {
enableValidElementStyling = enabled;
};
/**
* @ngdoc function
* @name validator#setInvalidElementStyling
* @methodOf validator
*
* @description
* Globally enables invalid element visual styling. This is enabled by default.
*
* @param {Boolean} enabled True to enable style otherwise false.
*/
this.setInvalidElementStyling = function (enabled) {
enableInvalidElementStyling = enabled;
};
/**
* @ngdoc function
* @name validator#setFirstInvalidElementScrollingOnSubmit
* @methodOf validator
*
* @description
* Globally enables first invalid element scrolling on form submit. This is disabled by default.
*
* @param enabled {Boolean} enabled True to enable scrolling otherwise false.
*/
this.setFirstInvalidElementScrollingOnSubmit = function (enabled) {
enableFirstInvalidElementScrollingOnSubmit = enabled;
};
this.firstInvalidElementScrollingOnSubmitEnabled = function () {
return enableFirstInvalidElementScrollingOnSubmit;
};
this.getDomModifier = function (el) {
var modifierKey = (el !== undefined ? el.attr('element-modifier') : this.defaultElementModifier) ||
(el !== undefined ? el.attr('data-element-modifier') : this.defaultElementModifier) ||
this.defaultElementModifier;
if (modifierKey === undefined) {
throw new Error('Please set a default dom modifier via the setDefaultElementModifier method on the validator class.');
}
return elementStateModifiers[modifierKey];
};
this.makeValid = function (el) {
if (autoValidateEnabledOnControl(el)) {
if (validElementStylingEnabled(el)) {
this.getDomModifier(el).makeValid(el);
} else {
this.makeDefault(el);
}
}
};
this.makeInvalid = function (el, errorMsg) {
if (autoValidateEnabledOnControl(el)) {
if (invalidElementStylingEnabled(el)) {
this.getDomModifier(el).makeInvalid(el, errorMsg);
} else {
this.makeDefault(el);
}
}
};
this.makeDefault = function (el) {
if (autoValidateEnabledOnControl(el)) {
var dm = this.getDomModifier(el);
if (dm.makeDefault) {
dm.makeDefault(el);
}
}
};
this.waitForAsyncValidators = function (el) {
if (autoValidateEnabledOnControl(el)) {
var dm = this.getDomModifier(el);
if (dm.waitForAsyncValidators) {
dm.waitForAsyncValidators(el);
}
}
};
this.defaultFormValidationOptions = {
forceValidation: false,
disabled: false,
validateNonVisibleControls: false,
removeExternalValidationErrorsOnSubmit: true,
validateOnFormSubmit: false,
waitForAsyncValidators: true
};
this.$get = [
function () {
return this;
}
];
}
angular.module('jcs-autoValidate').provider('validator', ValidatorFn);
function Bootstrap3ElementModifierFn($log) {
var customCss = [
'<style>' +
'.glyphicon-spin-jcs {' +
'-webkit-animation: spin 1000ms infinite linear;' +
'animation: spin 1000ms infinite linear;' +
'}' +
'@-webkit-keyframes spin {' +
'0% {' +
'-webkit-transform: rotate(0deg);' +
'transform: rotate(0deg);' +
'}' +
'100% {' +
'-webkit-transform: rotate(359deg);' +
'transform: rotate(359deg);' +
'}' +
'}' +
'@keyframes spin {' +
'0% {' +
'-webkit-transform: rotate(0deg);' +
'transform: rotate(0deg);' +
'}' +
'100% {' +
'-webkit-transform: rotate(359deg);' +
'transform: rotate(359deg);' +
'}' +
'}' +
'</style>'
].join('');
angular.element(document.body).append(angular.element(customCss));
var reset = function (el) {
angular.forEach(el.find('span'), function (spanEl) {
spanEl = angular.element(spanEl);
if (spanEl.hasClass('error-msg') || spanEl.hasClass('form-control-feedback') || spanEl.hasClass('control-feedback')) {
spanEl.remove();
}
});
el.removeClass('has-success has-error has-feedback');
},
findWithClassElementAsc = function (el, klass) {
var returnEl,
parent = el;
for (var i = 0; i <= 10; i += 1) {
if (parent !== undefined && parent.hasClass(klass)) {
returnEl = parent;
break;
} else if (parent !== undefined) {
parent = parent.parent();
}
}
return returnEl;
},
findWithClassElementDesc = function (el, klass) {
var child;
for (var i = 0; i < el.children.length; i += 1) {
child = el.children[i];
if (child !== undefined && angular.element(child).hasClass(klass)) {
break;
} else if (child.children !== undefined) {
child = findWithClassElementDesc(child, klass);
if (child.length > 0) {
break;
}
}
}
return angular.element(child);
},
findFormGroupElement = function (el) {
return findWithClassElementAsc(el, 'form-group');
},
findInputGroupElement = function (el) {
return findWithClassElementDesc(el, 'input-group');
},
insertAfter = function (referenceNode, newNode) {
referenceNode[0].parentNode.insertBefore(newNode[0], referenceNode[0].nextSibling);
},
/**
* @ngdoc property
* @name bootstrap3ElementModifier#addValidationStateIcons
* @propertyOf bootstrap3ElementModifier
* @returns {bool} True if an state icon will be added to the element in the valid and invalid control
* states. The default is false.
*/
addValidationStateIcons = false,
/**
* @ngdoc function
* @name bootstrap3ElementModifier#enableValidationStateIcons
* @methodOf bootstrap3ElementModifier
*
* @description
* Makes an element appear invalid by apply an icon to the input element.
*
* @param {bool} enable - True to enable the icon otherwise false.
*/
enableValidationStateIcons = function (enable) {
addValidationStateIcons = enable;
},
/**
* @ngdoc function
* @name bootstrap3ElementModifier#makeValid
* @methodOf bootstrap3ElementModifier
*
* @description
* Makes an element appear valid by apply bootstrap 3 specific styles and child elements. If the service
* property 'addValidationStateIcons' is true it will also append validation glyphicon to the element.
* See: http://getbootstrap.com/css/#forms-control-validation
*
* @param {Element} el - The input control element that is the target of the validation.
*/
makeValid = function (el) {
var frmGroupEl = findFormGroupElement(el),
inputGroupEl;
if (frmGroupEl) {
reset(frmGroupEl);
inputGroupEl = findInputGroupElement(frmGroupEl[0]);
frmGroupEl.addClass('has-success ' + (inputGroupEl.length > 0 || addValidationStateIcons === false ? '' : 'has-feedback'));
if (addValidationStateIcons) {
var iconElText = '<span class="glyphicon glyphicon-ok form-control-feedback"></span>';
if (inputGroupEl.length > 0) {
iconElText = iconElText.replace('form-', '');
iconElText = '<span class="input-group-addon control-feedback">' + iconElText + '</span';
}
insertAfter(el, angular.element(iconElText));
}
} else {
$log.error('Angular-auto-validate: invalid bs3 form structure elements must be wrapped by a form-group class');
}
},
/**
* @ngdoc function
* @name bootstrap3ElementModifier#makeInvalid
* @methodOf bootstrap3ElementModifier
*
* @description
* Makes an element appear invalid by apply bootstrap 3 specific styles and child elements. If the service
* property 'addValidationStateIcons' is true it will also append validation glyphicon to the element.
* See: http://getbootstrap.com/css/#forms-control-validation
*
* @param {Element} el - The input control element that is the target of the validation.
*/
makeInvalid = function (el, errorMsg) {
var frmGroupEl = findFormGroupElement(el),
helpTextEl = angular.element('<span class="help-block has-error error-msg">' + errorMsg + '</span>'),
inputGroupEl;
if (frmGroupEl) {
reset(frmGroupEl);
inputGroupEl = findInputGroupElement(frmGroupEl[0]);
frmGroupEl.addClass('has-error ' + (inputGroupEl.length > 0 || addValidationStateIcons === false ? '' : 'has-feedback'));
insertAfter(inputGroupEl.length > 0 ? inputGroupEl : getCorrectElementToPlaceErrorElementAfter(el), helpTextEl);
if (addValidationStateIcons) {
var iconElText = '<span class="glyphicon glyphicon-remove form-control-feedback"></span>';
if (inputGroupEl.length > 0) {
iconElText = iconElText.replace('form-', '');
iconElText = '<span class="input-group-addon control-feedback">' + iconElText + '</span>';
}
insertAfter(getCorrectElementToPlaceErrorElementAfter(el), angular.element(iconElText));
}
} else {
$log.error('Angular-auto-validate: invalid bs3 form structure elements must be wrapped by a form-group class');
}
},
getCorrectElementToPlaceErrorElementAfter = function (el) {
var correctEl = el,
elType = el[0].type ? el[0].type.toLowerCase() : '';
if ((elType === 'checkbox' || elType === 'radio') && el.parent()[0].nodeName.toLowerCase() === 'label') {
correctEl = el.parent();
}
return correctEl;
},
/**
* @ngdoc function
* @name bootstrap3ElementModifier#makeDefault
* @methodOf bootstrap3ElementModifier
*
* @description
* Makes an element appear in its default visual state by apply bootstrap 3 specific styles and child elements.
*
* @param {Element} el - The input control element that is the target of the validation.
*/
makeDefault = function (el) {
var frmGroupEl = findFormGroupElement(el);
if (frmGroupEl) {
reset(frmGroupEl);
} else {
$log.error('Angular-auto-validate: invalid bs3 form structure elements must be wrapped by a form-group class');
}
},
waitForAsyncValidators = function (el) {
var frmGroupEl = findFormGroupElement(el),
inputGroupEl;
if (frmGroupEl) {
reset(frmGroupEl);
inputGroupEl = findInputGroupElement(frmGroupEl[0]);
frmGroupEl.addClass('has-feedback ' + (inputGroupEl.length > 0 || addValidationStateIcons === false ? '' : 'has-feedback'));
if (addValidationStateIcons) {
var iconElText = '<span class="glyphicon glyphicon-repeat glyphicon-spin-jcs form-control-feedback"></span>';
if (inputGroupEl.length > 0) {
iconElText = iconElText.replace('form-', '');
iconElText = '<span class="input-group-addon control-feedback">' + iconElText + '</span>';
}
insertAfter(el, angular.element(iconElText));
}
} else {
$log.error('Angular-auto-validate: invalid bs3 form structure elements must be wrapped by a form-group class');
}
};
return {
makeValid: makeValid,
makeInvalid: makeInvalid,
makeDefault: makeDefault,
waitForAsyncValidators: waitForAsyncValidators,
enableValidationStateIcons: enableValidationStateIcons,
key: 'bs3'
};
}
Bootstrap3ElementModifierFn.$inject = [
'$log'
];
angular.module('jcs-autoValidate').factory('bootstrap3ElementModifier', Bootstrap3ElementModifierFn);
/*
* Taken from https://github.com/angular/angular.js/issues/2690#issue-14462164 (with added tests of course!)
*/
function JCSDebounceFn($timeout) {
var debounce = function (func, wait, immediate) {
var timeout;
return function () {
var context = this;
var args = arguments;
var later = function () {
timeout = null;
if (!immediate) {
func.apply(context, args);
}
};
var callNow = immediate && !timeout;
$timeout.cancel(timeout);
timeout = $timeout(later, wait, false);
if (callNow) {
func.apply(context, args);
}
};
};
return {
debounce: debounce
};
}
JCSDebounceFn.$inject = [
'$timeout'
];
angular.module('jcs-autoValidate').factory('jcs-debounce', JCSDebounceFn);
/**
* Replaces string placeholders with corresponding template string
*/
if (!('format' in String.prototype)) {
String.prototype.format = function () {
var args = arguments;
return this.replace(/{(\d+)}/g, function (match, number) {
return typeof args[number] !== undefined ? args[number] : match;
});
};
}
angular.autoValidate = angular.autoValidate || {
errorMessages: {}
};
angular.autoValidate.errorMessages['default'] = {
defaultMsg: 'Please add error message for {0}',
email: 'Please enter a valid email address',
minlength: 'Please enter at least {0} characters',
maxlength: 'You have entered more than the maximum {0} characters',
min: 'Please enter the minimum number of {0}',
max: 'Please enter the maximum number of {0}',
required: 'This field is required',
date: 'Please enter a valid date',
pattern: 'Please ensure the entered information adheres to this pattern {0}',
number: 'Please enter a valid number',
url: 'Please enter a valid URL in the format of http(s)://www.google.com'
};
function DefaultErrorMessageResolverFn($q, $http) {
var currentCulture = 'default',
i18nFileRootPath = 'js/angular-auto-validate/dist/lang',
cultureRetrievalPromise,
loadRemoteCulture = function (culture) {
cultureRetrievalPromise = $http.get('{0}/jcs-auto-validate_{1}.json'.format(i18nFileRootPath, culture.toLowerCase()));
return cultureRetrievalPromise;
},
/**
* @ngdoc function
* @name defaultErrorMessageResolver#setI18nFileRootPath
* @methodOf defaultErrorMessageResolver
*
* @description
* Set the root path to the il8n files on the server
*
* @param {String} rootPath - The root path on the server to the il8n file - this defaults
* to 'js/angular-auto-validate/lang/'
*/
setI18nFileRootPath = function (rootPath) {
i18nFileRootPath = rootPath;
},
/**
* @ngdoc function
* @name defaultErrorMessageResolver#setCulture
* @methodOf defaultErrorMessageResolver
*
* @description
* Set the culture for the error messages by loading an the correct culture resource file.
*
* @param {String} culture - The new culture in the format of 'en-gb' etc.
* @param {Function} cultureLoadingFn - A optional function to load the culture resolve which should
* return a promise which is resolved with the culture errorMessage object. If a function is not specified
* the culture file is loaded from the **i18nFileRootPath**.
* @returns {Promise} - A promise which is resolved with the loaded culture error messages object.
*/
setCulture = function (culture, cultureLoadingFn) {
var defer = $q.defer();
cultureLoadingFn = cultureLoadingFn || loadRemoteCulture;
currentCulture = culture.toLowerCase();
if (angular.autoValidate.errorMessages[currentCulture] === undefined) {
cultureRetrievalPromise = cultureLoadingFn(culture);
cultureRetrievalPromise.then(function (response) {
cultureRetrievalPromise = undefined;
angular.autoValidate.errorMessages[currentCulture] = response.data;
defer.resolve(angular.autoValidate.errorMessages[currentCulture]);
}, function (err) {
angular.autoValidate.errorMessages[currentCulture] = {
defaultMsg: 'Loading culture failed!'
};
cultureRetrievalPromise = null;
defer.reject(err);
});
} else {
defer.resolve(angular.autoValidate.errorMessages[currentCulture]);
}
return defer.promise;
},
getErrorMessages = function (culture) {
var defer = $q.defer();
culture = culture === undefined ? currentCulture : culture.toLowerCase();
if (cultureRetrievalPromise !== undefined) {
cultureRetrievalPromise.then(function () {
defer.resolve(angular.autoValidate.errorMessages[culture]);
}, function (err) {
defer.reject(err);
});
} else {
defer.resolve(angular.autoValidate.errorMessages[culture]);
}
return defer.promise;
},
getMessageTypeOverride = function (errorType, el) {
var overrideKey;
if (el) {
// try and find an attribute which overrides the given error type in the form of errorType-err-type="someMsgKey"
errorType += '-err-type';
overrideKey = el.attr('ng-' + errorType);
if (overrideKey === undefined) {
overrideKey = el.attr('data-ng-' + errorType) || el.attr(errorType);
}
if (overrideKey) {
overrideKey = overrideKey.replace(/[\W]/g, '');
}
}
return overrideKey;
},
/**
* @ngdoc function
* @name defaultErrorMessageResolver#resolve
* @methodOf defaultErrorMessageResolver
*
* @description
* Resolves a validate error type into a user validation error message
*
* @param {String} errorType - The type of validation error that has occurred.
* @param {Element} el - The input element that is the source of the validation error.
* @returns {Promise} A promise that is resolved when the validation message has been produced.
*/
resolve = function (errorType, el) {
var defer = $q.defer(),
errMsg,
parameters = [],
parameter,
messageTypeOverride;
if (cultureRetrievalPromise !== undefined) {
cultureRetrievalPromise.then(function () {
resolve(errorType, el).then(function (msg) {
defer.resolve(msg);
});
});
} else {
errMsg = angular.autoValidate.errorMessages[currentCulture][errorType];
messageTypeOverride = getMessageTypeOverride(errorType, el);
if (messageTypeOverride) {
errMsg = angular.autoValidate.errorMessages[currentCulture][messageTypeOverride];
}
if (errMsg === undefined && messageTypeOverride !== undefined) {
errMsg = angular.autoValidate.errorMessages[currentCulture].defaultMsg.format(messageTypeOverride);
} else if (errMsg === undefined) {
errMsg = angular.autoValidate.errorMessages[currentCulture].defaultMsg.format(errorType);
}
if (el && el.attr) {
try {
parameter = el.attr('ng-' + errorType);
if (parameter === undefined) {
parameter = el.attr('data-ng-' + errorType) || el.attr(errorType);
}
parameters.push(parameter || '');
errMsg = errMsg.format(parameters);
} catch (e) {}
}
defer.resolve(errMsg);
}
return defer.promise;
};
return {
setI18nFileRootPath: setI18nFileRootPath,
setCulture: setCulture,
getErrorMessages: getErrorMessages,
resolve: resolve
};
}
DefaultErrorMessageResolverFn.$inject = [
'$q',
'$http'
];
angular.module('jcs-autoValidate').factory('defaultErrorMessageResolver', DefaultErrorMessageResolverFn);
function Foundation5ElementModifierFn() {
var reset = function (el, inputEl) {
angular.forEach(el.find('small'), function (smallEl) {
if (angular.element(smallEl).hasClass('error')) {
angular.element(smallEl).remove();
}
});
inputEl.removeClass('error');
},
findParentColumn = function (el) {
var parent = el;
for (var i = 0; i <= 3; i += 1) {
if (parent !== undefined && (parent.hasClass('columns') || parent.hasClass('column'))) {
break;
} else if (parent !== undefined) {
parent = parent.parent();
}
}
return parent;
},
/**
* @ngdoc function
* @name foundation5ElementModifier#makeValid
* @methodOf foundation5ElementModifier
*
* @description
* Makes an element appear valid by apply Foundation 5 specific styles and child elements.
* See: http://foundation.zurb.com/docs/components/forms.html
*
* @param {Element} el - The input control element that is the target of the validation.
*/
makeValid = function (el) {
var parentColumn = findParentColumn(el);
reset(parentColumn && parentColumn.length > 0 ? parentColumn : el, el);
},
/**
* @ngdoc function
* @name foundation5ElementModifier#makeInvalid
* @methodOf foundation5ElementModifier
*
* @description
* Makes an element appear invalid by apply Foundation 5 specific styles and child elements.
* See: http://foundation.zurb.com/docs/components/forms.html
*
* @param {Element} el - The input control element that is the target of the validation.
*/
makeInvalid = function (el, errorMsg) {
var parentColumn = findParentColumn(el),
helpTextEl;
reset(parentColumn || el, el);
el.addClass('error');
if (parentColumn) {
helpTextEl = angular.element('<small class="error">' + errorMsg + '</small>');
parentColumn.append(helpTextEl);
}
},
/**
* @ngdoc function
* @name foundation5ElementModifier#makeDefault
* @methodOf foundation5ElementModifier
*
* @description
* Makes an element appear in its default visual state by apply foundation 5 specific styles and child elements.
*
* @param {Element} el - The input control element that is the target of the validation.
*/
makeDefault = function (el) {
makeValid(el);
};
return {
makeValid: makeValid,
makeInvalid: makeInvalid,
makeDefault: makeDefault,
key: 'foundation5'
};
}
angular.module('jcs-autoValidate').factory('foundation5ElementModifier', Foundation5ElementModifierFn);
function ElementUtilsFn() {
var isElementVisible = function (el) {
return el[0].offsetWidth > 0 && el[0].offsetHeight > 0;
};
return {
isElementVisible: isElementVisible
};
}
function ValidationManagerFn(validator, elementUtils, $anchorScroll) {
var elementTypesToValidate = ['input', 'textarea', 'select', 'form'],
elementIsVisible = function (el) {
return elementUtils.isElementVisible(el);
},
getFormOptions = function (el) {
var frmCtrl = angular.element(el).controller('form'),
options;
if (frmCtrl !== undefined && frmCtrl !== null) {
options = frmCtrl.autoValidateFormOptions;
} else {
options = validator.defaultFormValidationOptions;
}
return options;
},
/**
* Only validate if the element is present, it is visible, if it is not a comment,
* it is either a valid user input control (input, select, textare, form) or
* it is a custom control register by the developer.
* @param el
* @param formOptions The validation options of the parent form
* @returns {boolean} true to indicate it should be validated
*/
shouldValidateElement = function (el, formOptions, formSubmitted) {
var elementExists = el && el.length > 0,
isElementAComment = elementExists && el[0].nodeName.toLowerCase() === '#comment',
correctVisibilityToValidate,
correctTypeToValidate,
correctPhaseToValidate;
if (elementExists && isElementAComment === false) {
correctVisibilityToValidate = elementIsVisible(el) || formOptions.validateNonVisibleControls;
correctTypeToValidate = elementTypesToValidate.indexOf(el[0].nodeName.toLowerCase()) > -1 ||
el[0].hasAttribute('register-custom-form-control');
correctPhaseToValidate = formOptions.validateOnFormSubmit === false ||
(formOptions.validateOnFormSubmit === true && formSubmitted === true);
}
return elementExists && !isElementAComment && correctVisibilityToValidate && correctTypeToValidate && correctPhaseToValidate;
},
/**
* @ngdoc validateElement
* @name validation#validateElement
* @param {object} modelCtrl holds the information about the element e.g. $invalid, $valid
* @param {options}
* - forceValidation if set to true forces the validation even if the element is pristine
* - disabled if set to true forces the validation is disabled and will return true
* - validateNonVisibleControls if set to true forces the validation of non visible element i.e. display:block
* @description
* Validate the form element and make invalid/valid element model status.
*
* As of v1.17.22:
* BREAKING CHANGE to validateElement on the validationManger. The third parameter is now the parent form's
* autoValidateFormOptions object on the form controller. This can be left blank and will be found by the
* validationManager.
*/
validateElement = function (modelCtrl, el, options) {
var isValid = true,
frmOptions = options || getFormOptions(el),
needsValidation = modelCtrl.$pristine === false || frmOptions.forceValidation,
errorType,
findErrorType = function ($errors) {
var keepGoing = true,
errorTypeToReturn;
angular.forEach($errors, function (status, errortype) {
if (keepGoing && status) {
keepGoing = false;
errorTypeToReturn = errortype;
}
});
return errorTypeToReturn;
};
if (frmOptions.disabled === false) {
if ((frmOptions.forceValidation ||
(shouldValidateElement(el, frmOptions, frmOptions.getFormController().$submitted) &&
modelCtrl &&
needsValidation))) {
isValid = !modelCtrl.$invalid;
if (frmOptions.removeExternalValidationErrorsOnSubmit && modelCtrl.removeAllExternalValidation) {
modelCtrl.removeAllExternalValidation();
}
if (modelCtrl.$pending !== undefined && options.waitForAsyncValidators === true) {
// we have pending async validators
validator.waitForAsyncValidators(el);
} else {
if (isValid) {
validator.makeValid(el);
} else {
errorType = findErrorType(modelCtrl.$errors || modelCtrl.$error);
if (errorType === undefined) {
// we have a weird situation some users are encountering where a custom control
// is valid but the ngModel is report it isn't and thus no valid error type can be found
isValid = true;
} else {
validator.getErrorMessage(errorType, el).then(function (errorMsg) {
validator.makeInvalid(el, errorMsg);
});
}
}
}
}
}
return isValid;
},
resetElement = function (element) {
validator.makeDefault(element);
},
resetForm = function (frmElement) {
angular.forEach((frmElement[0].all || frmElement[0].elements) || frmElement[0], function (element) {
var controller,
ctrlElement = angular.element(element);
controller = ctrlElement.controller('ngModel');
if (controller !== undefined) {
if (ctrlElement[0].nodeName.toLowerCase() === 'form') {
// we probably have a sub form
resetForm(ctrlElement);
} else {
controller.$setPristine();
}
}
});
},
validateForm = function (frmElement) {
var frmValid = true,
frmCtrl = frmElement ? angular.element(frmElement).controller('form') : undefined,
processElement = function (ctrlElement, force, formOptions) {
var controller, isValid, ctrlFormOptions, originalForceValue;
ctrlElement = angular.element(ctrlElement);
controller = ctrlElement.controller('ngModel');
if (controller !== undefined && (force || shouldValidateElement(ctrlElement, formOptions, frmCtrl.$submitted))) {
if (ctrlElement[0].nodeName.toLowerCase() === 'form') {
// we probably have a sub form
validateForm(ctrlElement);
} else {
// we need to get the options for the element rather than use the passed in as the
// element could be an ng-form and have different options to the parent form.
ctrlFormOptions = getFormOptions(ctrlElement);
originalForceValue = ctrlFormOptions.forceValidation;
ctrlFormOptions.forceValidation = force;
try {
isValid = validateElement(controller, ctrlElement, ctrlFormOptions);
if (validator.firstInvalidElementScrollingOnSubmitEnabled() && !isValid && frmValid) {
var ctrlElementId = ctrlElement.attr('id');
if (ctrlElementId) {
$anchorScroll(ctrlElementId);
}
}
frmValid = frmValid && isValid;
} finally {
ctrlFormOptions.forceValidation = originalForceValue;
}
}
}
},
clonedOptions;
if (frmElement === undefined || (frmCtrl !== undefined && frmCtrl.autoValidateFormOptions.disabled)) {
return frmElement !== undefined;
}
//force the validation of controls
clonedOptions = angular.copy(frmCtrl.autoValidateFormOptions);
clonedOptions.forceValidation = true;
// IE8 holds the child controls collection in the all property
// Firefox in the elements and chrome as a child iterator
angular.forEach((frmElement[0].elements || frmElement[0].all) || frmElement[0], function (ctrlElement) {
processElement(ctrlElement, true, clonedOptions);
});
// If you have a custom form control that should be validated i.e.
// <my-custom-element>...</my-custom-element> it will not be part of the forms
// HTMLFormControlsCollection and thus won't be included in the above element iteration although
// it will be on the Angular FormController (if it has a name attribute). So adding the directive
// register-custom-form-control="" to the control root and autoValidate will include it in this
// iteration.
if (frmElement[0].customHTMLFormControlsCollection) {
angular.forEach(frmElement[0].customHTMLFormControlsCollection, function (ctrlElement) {
// need to force the validation as the element might not be a known form input type
// so the normal validation process will ignore it.
processElement(ctrlElement, true, clonedOptions);
});
}
return frmValid;
},
setElementValidationError = function (element, errorMsgKey, errorMsg) {
if (errorMsgKey) {
validator.getErrorMessage(errorMsgKey, element).then(function (msg) {
validator.makeInvalid(element, msg);
});
} else {
validator.makeInvalid(element, errorMsg);
}
};
return {
setElementValidationError: setElementValidationError,
validateElement: validateElement,
validateForm: validateForm,
resetElement: resetElement,
resetForm: resetForm
};
}
ValidationManagerFn.$inject = [
'validator',
'jcs-elementUtils',
'$anchorScroll'
];
angular.module('jcs-autoValidate').factory('jcs-elementUtils', ElementUtilsFn);
angular.module('jcs-autoValidate').factory('validationManager', ValidationManagerFn);
function parseBooleanAttributeValue(val, defaultValue) {
if ((val === undefined || val === null) && defaultValue !== undefined) {
return defaultValue;
} else {
return val !== 'false';
}
}
function parseOptions(ctrl, validator, attrs) {
var opts = ctrl.autoValidateFormOptions = ctrl.autoValidateFormOptions || angular.copy(validator.defaultFormValidationOptions);
// needed to stop circular ref in json serialisation
opts.getFormController = function () {
return ctrl;
};
opts.waitForAsyncValidators = parseBooleanAttributeValue(attrs.waitForAsyncValidators, opts.waitForAsyncValidators);
opts.forceValidation = false;
opts.disabled = !validator.isEnabled() || parseBooleanAttributeValue(attrs.disableDynamicValidation, opts.disabled);
opts.validateNonVisibleControls = parseBooleanAttributeValue(attrs.validateNonVisibleControls, opts.validateNonVisibleControls);
opts.validateOnFormSubmit = parseBooleanAttributeValue(attrs.validateOnFormSubmit, opts.validateOnFormSubmit);
opts.removeExternalValidationErrorsOnSubmit = attrs.removeExternalValidationErrorsOnSubmit === undefined ?
opts.removeExternalValidationErrorsOnSubmit :
parseBooleanAttributeValue(attrs.removeExternalValidationErrorsOnSubmit, opts.removeExternalValidationErrorsOnSubmit);
// the library might be globally disabled but enabled on a particular form so check the
// disableDynamicValidation attribute is on the form
if (validator.isEnabled() === false && attrs.disableDynamicValidation === 'false') {
opts.disabled = false;
}
}
angular.module('jcs-autoValidate').directive('form', [
'validator',
function (validator) {
return {
restrict: 'E',
require: 'form',
priority: 9999,
compile: function () {
return {
pre: function (scope, element, attrs, ctrl) {
parseOptions(ctrl, validator, attrs);
}
};
}
};
}
]);
angular.module('jcs-autoValidate').directive('ngForm', [
'validator',
function (validator) {
return {
restrict: 'EA',
require: 'form',
priority: 9999,
compile: function () {
return {
pre: function (scope, element, attrs, ctrl) {
parseOptions(ctrl, validator, attrs);
}
};
}
};
}
]);
function FormResetDirectiveFn(validationManager) {
return {
restrict: 'E',
link: function (scope, el) {
var formController = el.controller('form');
function resetFn() {
validationManager.resetForm(el);
if (formController.$setPristine) {
formController.$setPristine();
}
if (formController.$setUntouched) {
formController.$setUntouched();
}
}
if (formController !== undefined &&
formController.autoValidateFormOptions &&
formController.autoValidateFormOptions.disabled === false) {
el.on('reset', resetFn);
scope.$on('$destroy', function () {
el.off('reset', resetFn);
});
}
}
};
}
FormResetDirectiveFn.$inject = [
'validationManager'
];
angular.module('jcs-autoValidate').directive('form', FormResetDirectiveFn);
function RegisterCustomFormControlFn() {
var findParentForm = function (el) {
var parent = el;
for (var i = 0; i <= 50; i += 1) {
if (parent !== undefined && parent.nodeName.toLowerCase() === 'form') {
break;
} else if (parent !== undefined) {
parent = angular.element(parent).parent()[0];
}
}
return parent;
};
return {
restrict: 'A',
link: function (scope, element) {
var frmEl = findParentForm(element.parent()[0]);
if (frmEl) {
frmEl.customHTMLFormControlsCollection = frmEl.customHTMLFormControlsCollection || [];
frmEl.customHTMLFormControlsCollection.push(element[0]);
}
}
};
}
angular.module('jcs-autoValidate').directive('registerCustomFormControl', RegisterCustomFormControlFn);
function SubmitDecorator($delegate, $parse, validationManager) {
$delegate[0].compile = function ($element, attrs) {
var fn = $parse(attrs.ngSubmit),
force = attrs.ngSubmitForce === 'true';
return function (scope, element) {
var formController = element.controller('form'),
resetListenerOffFn;
function handlerFn(event) {
scope.$apply(function () {
if (formController !== undefined &&
formController !== null &&
formController.autoValidateFormOptions &&
formController.autoValidateFormOptions.disabled === true) {
fn(scope, {
$event: event
});
} else {
if (formController.$setSubmitted === undefined) {
// we probably have angular <= 1.2
formController.$submitted = true;
}
if (validationManager.validateForm(element) || force === true) {
fn(scope, {
$event: event
});
}
}
});
}
function resetFormFn() {
if (element[0].reset) {
element[0].reset();
} else {
validationManager.resetForm(element);
}
}
if (formController && formController.autoValidateFormOptions) {
// allow the form to be reset programatically or via raising the event
// form:formName:reset
formController.autoValidateFormOptions.resetForm = resetFormFn;
if (formController.$name !== undefined && formController.$name !== '') {
resetListenerOffFn = scope.$on('form:' + formController.$name + ':reset', resetFormFn);
}
}
element.on('submit', handlerFn);
scope.$on('$destroy', function () {
element.off('submit', handlerFn);
if (resetListenerOffFn) {
resetListenerOffFn();
}
});
};
};
return $delegate;
}
SubmitDecorator.$inject = [
'$delegate',
'$parse',
'validationManager'
];
function ProviderFn($provide) {
$provide.decorator('ngSubmitDirective', SubmitDecorator);
}
ProviderFn.$inject = [
'$provide'
];
angular.module('jcs-autoValidate').config(ProviderFn);
angular.module('jcs-autoValidate').config(['$provide',
function ($provide) {
$provide.decorator('ngModelDirective', [
'$timeout',
'$delegate',
'validationManager',
'jcs-debounce',
function ($timeout, $delegate, validationManager, debounce) {
var directive = $delegate[0],
link = directive.link || directive.compile;
directive.compile = function (el) {
var supportsNgModelOptions = angular.version.major >= 1 && angular.version.minor >= 3,
originalLink = link;
// in the RC of 1.3 there is no directive.link only the directive.compile which
// needs to be invoked to get at the link functions.
if (supportsNgModelOptions && angular.isFunction(link)) {
originalLink = link(el);
}
return {
pre: function (scope, element, attrs, ctrls) {
var ngModelCtrl = ctrls[0],
frmCtrl = ctrls[1],
ngModelOptions = attrs.ngModelOptions === undefined ? undefined : scope.$eval(attrs.ngModelOptions),
setValidity = ngModelCtrl.$setValidity,
setPristine = ngModelCtrl.$setPristine,
setValidationState = debounce.debounce(function () {
var validateOptions = frmCtrl !== undefined && frmCtrl !== null ? frmCtrl.autoValidateFormOptions : undefined;
validationManager.validateElement(ngModelCtrl, element, validateOptions);
}, 100);
if (attrs.formnovalidate === undefined &&
(frmCtrl !== undefined && frmCtrl !== null && frmCtrl.autoValidateFormOptions &&
frmCtrl.autoValidateFormOptions.disabled === false)) {
// if the version of angular supports ng-model-options let angular handle the element.on bit
// fixes issue with async validators
if (supportsNgModelOptions ||
(!supportsNgModelOptions || ngModelOptions === undefined || ngModelOptions.updateOn === undefined || ngModelOptions.updateOn === '')) {
ngModelCtrl.$setValidity = function (validationErrorKey, isValid) {
setValidity.call(ngModelCtrl, validationErrorKey, isValid);
setValidationState();
};
} else {
element.on(ngModelOptions.updateOn, function () {
setValidationState();
});
scope.$on('$destroy', function () {
element.off(ngModelOptions.updateOn);
});
}
// We override this so we can reset the element state when it is called.
ngModelCtrl.$setPristine = function () {
setPristine.call(ngModelCtrl);
validationManager.resetElement(element);
};
ngModelCtrl.autoValidated = true;
}
ngModelCtrl.setExternalValidation = function (errorMsgKey, errorMessage, addToModelErrors) {
if (addToModelErrors) {
var collection = ngModelCtrl.$error || ngModelCtrl.$errors;
collection[errorMsgKey] = false;
}
ngModelCtrl.externalErrors = ngModelCtrl.externalErrors || {};
ngModelCtrl.externalErrors[errorMsgKey] = false;
validationManager.setElementValidationError(element, errorMsgKey, errorMessage);
};
ngModelCtrl.removeExternalValidation = function (errorMsgKey, addToModelErrors) {
if (addToModelErrors) {
var collection = ngModelCtrl.$error || ngModelCtrl.$errors;
delete collection[errorMsgKey];
}
if (ngModelCtrl.externalErrors) {
delete ngModelCtrl.externalErrors[errorMsgKey];
}
validationManager.resetElement(element);
};
ngModelCtrl.removeAllExternalValidation = function () {
if (ngModelCtrl.externalErrors) {
var errorCollection = ngModelCtrl.$error || ngModelCtrl.$errors;
angular.forEach(ngModelCtrl.externalErrors, function (value, key) {
delete errorCollection[key];
});
ngModelCtrl.externalErrors = {};
validationManager.resetElement(element);
}
};
if (frmCtrl) {
frmCtrl.setExternalValidation = function (modelProperty, errorMsgKey, errorMessageOverride, addToModelErrors) {
var success = false;
if (frmCtrl[modelProperty]) {
frmCtrl[modelProperty].setExternalValidation(errorMsgKey, errorMessageOverride, addToModelErrors);
success = true;
}
return success;
};
frmCtrl.removeExternalValidation = function (modelProperty, errorMsgKey, errorMessageOverride, addToModelErrors) {
var success = false;
if (frmCtrl[modelProperty]) {
frmCtrl[modelProperty].removeExternalValidation(errorMsgKey, addToModelErrors);
success = true;
}
return success;
};
}
return originalLink.pre ?
originalLink.pre.apply(this, arguments) :
this;
},
post: function (scope, element, attrs, ctrls) {
return originalLink.post ?
originalLink.post.apply(this, arguments) :
originalLink.apply(this, arguments);
}
};
};
return $delegate;
}
]);
}
]);
function AutoValidateRunFn(validator, defaultErrorMessageResolver, bootstrap3ElementModifier, foundation5ElementModifier) {
validator.setErrorMessageResolver(defaultErrorMessageResolver.resolve);
validator.registerDomModifier(bootstrap3ElementModifier.key, bootstrap3ElementModifier);
validator.registerDomModifier(foundation5ElementModifier.key, foundation5ElementModifier);
validator.setDefaultElementModifier(bootstrap3ElementModifier.key);
}
AutoValidateRunFn.$inject = [
'validator',
'defaultErrorMessageResolver',
'bootstrap3ElementModifier',
'foundation5ElementModifier'
];
angular.module('jcs-autoValidate').run(AutoValidateRunFn);
}(String, angular));