diff --git a/bower.json b/bower.json
index bc8a402..eac4e2e 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
{
"name": "angular-validation-ghiscoding",
- "version": "1.4.17",
+ "version": "1.4.18",
"author": "Ghislain B.",
"description": "Angular-Validation Directive and Service (ghiscoding)",
"main": [
diff --git a/changelog.txt b/changelog.txt
index bf13c67..fb380dc 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,6 @@
Angular-Validation change logs
+1.4.18 (2015-12-20) Fixed issue #91 interpolation problem with remove validation doesn't work twice. Enhancement #98 possibility to use one validation or another (tell how many Validators are required for field to become valid). Enhancement #97 possibility to validate even on empty text field (useful on `custom` and `remote` validation). Refined some Validators (IPV6 now include compressed/uncompressed addresses, added more Polish characters to other Validators)
1.4.17 (2015-12-15) Fixed issue #92 input name with '.', enhancement #94 Polish characters, issue #96 in_list wasn't accepting special characters.
1.4.16 (2015-12-11) Fixed issue #90 blinking error messages.
1.4.15 (2015-12-02) Fixed issue #86 implicit global variable on regex.
diff --git a/dist/angular-validation.min.js b/dist/angular-validation.min.js
index 68af793..ccbbd24 100644
--- a/dist/angular-validation.min.js
+++ b/dist/angular-validation.min.js
@@ -2,11 +2,11 @@
* Angular-Validation Directive and Service (ghiscoding)
* http://github.com/ghiscoding/angular-validation
* @author: Ghislain B.
- * @version: 1.4.17
+ * @version: 1.4.18
* @license: MIT
- * @build: Tue Dec 15 2015 00:44:43 GMT-0500 (Eastern Standard Time)
+ * @build: Sun Dec 20 2015 23:57:57 GMT-0500 (Eastern Standard Time)
*/
-angular.module("ghiscoding.validation",["pascalprecht.translate"]).directive("validation",["$q","$timeout","validationCommon",function(a,e,i){return{restrict:"A",require:"ngModel",link:function(n,t,r,l){function o(i,r){var o=a.defer(),d=!1,m="undefined"!=typeof r?r:V.typingLimit,s=V.getFormElementByName(l.$name);if(Array.isArray(i)){if(E=[],$="",m=0,i.length>0)return"function"==typeof s.ctrl.$setTouched&&s.ctrl.$setTouched(),u(i,typeof i);m=0}return i&&i.badInput?v():(V.validate(i,!1),V.isFieldRequired()||""!==i&&null!==i&&"undefined"!=typeof i?(s&&(s.isValidationCancelled=!1),(i||V.isFieldRequired())&&l.$setValidity("validation",!1),"SELECT"===t.prop("tagName").toUpperCase()?(d=V.validate(i,!0),l.$setValidity("validation",d),o.resolve({isFieldValid:d,formElmObj:s,value:i}),o.promise):("undefined"!=typeof i&&(0===r?(d=V.validate(i,!0),n.$evalAsync(l.$setValidity("validation",d)),o.resolve({isFieldValid:d,formElmObj:s,value:i}),e.cancel(b)):(V.updateErrorMsg(""),e.cancel(b),b=e(function(){d=V.validate(i,!0),n.$evalAsync(l.$setValidity("validation",d)),o.resolve({isFieldValid:d,formElmObj:s,value:i})},m))),o.promise)):(f(),o.resolve({isFieldValid:!0,formElmObj:s,value:i}),o.promise))}function d(a,e,i){var n=o(a,0);n&&"function"==typeof n.then&&(E.push(n),parseInt(e)===i-1&&E.forEach(function(a){a.then(function(a){switch(j){case"all":if(a.isFieldValid===!1){var e=V.getGlobalOptions();a.formElmObj.translatePromise.then(function(i){$.length>0&&e.displayOnlyLastErrorMsg?$="["+a.value+"] :: "+(a.formElmObj.validator&&a.formElmObj.validator.params?String.format(i,a.formElmObj.validator.params):i):$+=" ["+a.value+"] :: "+(a.formElmObj.validator&&a.formElmObj.validator.params?String.format(i,a.formElmObj.validator.params):i),V.updateErrorMsg($,{isValid:!1}),V.addToValidationSummary(a.formElmObj,$)})}break;case"one":default:a.isFieldValid===!0&&(l.$setValidity("validation",!0),f())}})}))}function m(a){var e=V.getFormElementByName(l.$name),i="undefined"!=typeof l.$modelValue?l.$modelValue:a.target.value;if(e.isValidationCancelled)l.$setValidity("validation",!0);else{var n=o(i,0);h&&V.runValidationCallbackOnPromise(n,h)}}function u(a,e){var i=a.length;if("string"===e)for(var n in a)d(a[n],n,i);else if("object"===e)for(var n in a)if(a.hasOwnProperty(n)){var t=a[n];for(var r in t)if(t.hasOwnProperty(r)){if(F&&r!==F)continue;d(t[r],n,i)}}}function s(){f(),V.removeFromValidationSummary(O);var a=V.arrayFindObject(g,"elmName",l.$name);a&&a.watcherHandler()}function f(){var a=V.getFormElementByName(l.$name);a&&(a.isValidationCancelled=!0),e.cancel(b),V.updateErrorMsg(""),l.$setValidity("validation",!0),p()}function v(){e.cancel(b);var a=V.getFormElementByName(l.$name);V.updateErrorMsg("INVALID_KEY_CHAR",{isValid:!1,translate:!0}),V.addToValidationSummary(a,"INVALID_KEY_CHAR",!0)}function c(){return!!t.prop("validity")&&t.prop("validity").badInput===!0}function y(){var a=l.$modelValue||"";Array.isArray(a)||l.$setValidity("validation",V.validate(a,!1));var e=V.getFormElementByName(l.$name);e&&(e.isValidationCancelled=!1),p(),t.bind("blur",m)}function p(){"function"==typeof m&&t.unbind("blur",m)}var b,V=new i(n,t,r,l),$="",E=[],g=[],O=r.name,h=r.hasOwnProperty("validationCallback")?r.validationCallback:null,j=r.hasOwnProperty("validArrayRequireHowMany")?r.validArrayRequireHowMany:"one",F=r.hasOwnProperty("validationArrayObjprop")?r.validationArrayObjprop:null,A=n.$watch(function(){return c()?{badInput:!0}:l.$modelValue},function(a){if(a&&a.badInput)return p(),v();var e=o(a);h&&V.runValidationCallbackOnPromise(e,h)},!0);g.push({elmName:O,watcherHandler:A}),r.$observe("disabled",function(a){a?(f(),V.removeFromValidationSummary(O)):y()}),t.on("$destroy",function(){s()}),n.$watch(function(){return t.attr("validation")},function(a){"undefined"==typeof a||""===a?s():(V.defineValidation(),y())}),t.bind("blur",m)}}}]);
-angular.module("ghiscoding.validation").factory("validationCommon",["$rootScope","$timeout","$translate","validationRules",function(e,t,a,r){function n(e,t,r){if("undefined"!=typeof e&&null!=e){var n=e.ctrl&&e.ctrl.$name?e.ctrl.$name:e.attrs&&e.attrs.name?e.attrs.name:e.elm.attr("name"),i=E(n,e),o=V(B,"field",n);if(o>=0&&""===t)B.splice(o,1);else if(""!==t){r&&(t=a.instant(t));var s=e.attrs&&e.friendlyName?a.instant(e.friendlyName):"",l={field:n,friendlyName:s,message:t,formName:i?i.$name:null};o>=0?B[o]=l:B.push(l)}if(e.scope.$validationSummary=B,i&&(i.$validationSummary=A(B,"formName",i.$name)),H&&H.controllerAs&&(H.controllerAs.$validationSummary=B,i&&i.$name)){var u=i.$name.indexOf(".")>=0?i.$name.split(".")[1]:i.$name,m=H.controllerAs[u]?H.controllerAs[u]:e.elm.controller()[u];m&&(m.$validationSummary=A(B,"formName",i.$name))}return B}}function i(){var e=this,t={};e.validators=[],e.typingLimit=I,e.validatorAttrs.hasOwnProperty("debounce")?e.typingLimit=parseInt(e.validatorAttrs.debounce,10):e.validatorAttrs.hasOwnProperty("typingLimit")?e.typingLimit=parseInt(e.validatorAttrs.typingLimit,10):H&&H.hasOwnProperty("debounce")&&(e.typingLimit=parseInt(H.debounce,10));var a=e.validatorAttrs.rules||e.validatorAttrs.validation;if(a.indexOf("pattern=/")>=0){var n=a.match(/pattern=(\/.*\/[igm]*)(:alt=(.*))?/);if(!n||n.length<3)throw'Regex validator within the validation needs to be define with an opening "/" and a closing "/", please review your validator.';var i=n[1],o=n[2]?n[2].replace(/\|(.*)/,""):"",s=i.match(new RegExp("^/(.*?)/([gimy]*)$")),l=new RegExp(s[1],s[2]);t={altMsg:o,message:o.replace(/:alt=/,""),pattern:l},a=a.replace("pattern="+i,"pattern")}else if(a.indexOf("regex:")>=0){var n=a.match("regex:(.*?):regex");if(n.length<2)throw'Regex validator within the validation needs to be define with an opening "regex:" and a closing ":regex", please review your validator.';var u=n[1].split(":=");t={message:u[0],pattern:u[1]},a=a.replace(n[0],"regex:")}var m=a.split("|");if(m){e.bFieldRequired=a.indexOf("required")>=0;for(var p=0,d=m.length;d>p;p++){var c=m[p].split(":"),f=m[p].indexOf("alt=")>=0;e.validators[p]=r.getElementValidators({altText:f===!0?2===c.length?c[1]:c[2]:"",customRegEx:t,rule:c[0],ruleParams:f&&2===c.length?null:c[1]})}}return e}function o(e){return S(P,"fieldName",e)}function s(e){return e?A(P,"formName",e):P}function l(){return H}function u(e,t,a,r){this.scope=e,this.elm=t,this.ctrl=r,this.validatorAttrs=a,$(t,a,r,e),this.defineValidation()}function m(){var e=this;return e.bFieldRequired}function p(e,t){var a={};for(var r in e)a[r]=e[r];for(var r in t)a[r]=t[r];return a}function d(e){var t=V(P,"fieldName",e);t>=0&&P.splice(t,1)}function c(e,t){var a=this,r=E(e,a),n=t||B,i=V(n,"field",e);if(i>=0&&n.splice(i,1),i=V(B,"field",e),i>=0&&B.splice(i,1),a.scope.$validationSummary=B,r&&(r.$validationSummary=A(B,"formName",r.$name)),H&&H.controllerAs&&(H.controllerAs.$validationSummary=B,r)){var o=r.$name.indexOf(".")>=0?r.$name.split(".")[1]:r.$name;H.controllerAs[o]&&(H.controllerAs[o].$validationSummary=A(B,"formName",r.$name))}return B}function f(e,t){var a;if(/\({1}.*\){1}/gi.test(t))a=e.scope.$eval(t);else{var r=N(e.scope,t,".");"function"==typeof r&&(a=r())}return a}function g(e,t){var a=this;"function"==typeof e.then&&e.then(function(){f(a,t)})}function v(e){H.displayOnlyLastErrorMsg=e}function h(e){var t=this;return H=p(H,e),t}function y(e,t){var r=this;t&&t.obj&&(r=t.obj,r.validatorAttrs=t.obj.attrs);var n=t&&t.elm?t.elm:r.elm,i=n&&n.attr("name")?n.attr("name"):null;if("undefined"==typeof i||null===i){var o=n?n.attr("ng-model"):"unknown";throw'Angular-Validation Service requires you to have a (name="") attribute on the element to validate... Your element is: ng-model="'+o+'"'}var s=t&&t.translate?a.instant(e):e,l=i.replace(/[|&;$%@"<>()+,\[\]\{\}]/g,"").replace(/\./g,"-"),u=null;if(r.validatorAttrs&&r.validatorAttrs.hasOwnProperty("validationErrorTo")){var m=r.validatorAttrs.validationErrorTo.charAt(0),p="."===m||"#"===m?r.validatorAttrs.validationErrorTo:"#"+r.validatorAttrs.validationErrorTo;u=angular.element(document.querySelector(p))}u&&0!==u.length||(u=angular.element(document.querySelector(".validation-"+l)));var d=t&&t.isSubmitted?t.isSubmitted:!1;!H.hideErrorUnderInputs&&t&&!t.isValid&&(d||r.ctrl.$dirty||r.ctrl.$touched)?u.length>0?u.html(s):n.after(''+s+""):u.html("")}function b(e,t){var r,i=this,s=!0,l=!0,u={message:""};"undefined"==typeof e&&(e="");for(var m=i.ctrl&&i.ctrl.$name?i.ctrl.$name:i.attrs&&i.attrs.name?i.attrs.name:i.elm.attr("name"),p=o(m),d=i.validatorAttrs.rules||i.validatorAttrs.validation,c=0,f=i.validators.length;f>c;c++){r=i.validators[c],"autoDetect"===r.type&&(r=M(r,e));var g=i.attrs?i.attrs.ngDisabled:i.validatorAttrs.ngDisabled;switch(r.type){case"conditionalDate":s=q(e,r,d);break;case"conditionalNumber":s=U(e,r);break;case"javascript":s=C(e,r,i,p,t,u);break;case"matching":s=j(e,r,i,u);break;case"remote":s=G(e,r,i,p,t,u);break;default:s=D(e,r,d,i)}(!i.bFieldRequired&&!e||i.elm.prop("disabled")||i.scope.$eval(g))&&(s=!0),s||(l=!1,function(e,r,n){var o=n.message;n.altText&&n.altText.length>0&&(o=n.altText.replace("alt=",""));var s=a(o);e.translatePromise=s,e.validator=n,s.then(function(a){u.message.length>0&&H.displayOnlyLastErrorMsg?u.message=" "+(n&&n.params?String.format(a,n.params):a):u.message+=" "+(n&&n.params?String.format(a,n.params):a),O(i,e,u.message,l,t)})["catch"](function(){n.altText&&n.altText.length>0&&(u.message.length>0&&H.displayOnlyLastErrorMsg?u.message=" "+o:u.message+=" "+o,O(i,e,u.message,l,t))})}(p,s,r))}return s&&(n(i,""),i.updateErrorMsg("",{isValid:s})),p&&(p.isValid=l,l&&(p.message="")),l}function $(e,t,r,n){var i=t.name?t.name:e.attr("name"),o=E(i,{scope:n}),s=t&&t.friendlyName?a.instant(t.friendlyName):"",l={fieldName:i,friendlyName:s,elm:e,attrs:t,ctrl:r,scope:n,isValid:!1,message:"",formName:o?o.$name:null},u=V(P,"fieldName",e.attr("name"));return u>=0?P[u]=l:P.push(l),P}function O(e,t,a,r,i){a=a.trim(),t&&t.isValidationCancelled===!0&&(a=""),n(t,a),(e.validatorAttrs.preValidateFormElements||H.preValidateFormElements)&&(t&&"function"==typeof e.ctrl.$setTouched&&t.ctrl.$setTouched(),e.ctrl.$dirty===!1&&y(a,{isSubmitted:!0,isValid:r,obj:t})),i&&t&&!t.isValid?e.updateErrorMsg(a,{isValid:r,obj:t}):t&&t.isValid&&n(t,"")}function S(e,t,a){if(e)for(var r=0;r=0?N(t.scope,o,"."):t.scope[o]))return"undefined"==typeof a.$name&&(a.$name=o),a}if(i){var o=i?i.getAttribute("name"):null;if(o){var s={$name:o,specialNote:"Created by Angular-Validation for Isolated Scope usage"};if(H&&H.controllerAs&&o.indexOf(".")>=0){var l=o.split(".");return t.scope[l[0]][l[1]]=s}return t.scope[o]=s}}return null}function w(e){return!isNaN(parseFloat(e))&&isFinite(e)}function N(e,t,a){for(var r=a?t.split(a):t,n=0,i=r.length;i>n;n++)e[r[n]]&&(e=e[r[n]]);return e}function x(e,t){var a="",r="-",n=[],i=[],o="",s="",l="";switch(t.toUpperCase()){case"EURO_LONG":case"EURO-LONG":a=e.substring(0,10),r=e.substring(2,3),n=R(a,r),l=n[0],s=n[1],o=n[2],i=e.length>8?e.substring(9).split(":"):null;break;case"UK":case"EURO":case"EURO_SHORT":case"EURO-SHORT":case"EUROPE":a=e.substring(0,8),r=e.substring(2,3),n=R(a,r),l=n[0],s=n[1],o=parseInt(n[2])<50?"20"+n[2]:"19"+n[2],i=e.length>8?e.substring(9).split(":"):null;break;case"US_LONG":case"US-LONG":a=e.substring(0,10),r=e.substring(2,3),n=R(a,r),s=n[0],l=n[1],o=n[2],i=e.length>8?e.substring(9).split(":"):null;break;case"US":case"US_SHORT":case"US-SHORT":a=e.substring(0,8),r=e.substring(2,3),n=R(a,r),s=n[0],l=n[1],o=parseInt(n[2])<50?"20"+n[2]:"19"+n[2],i=e.length>8?e.substring(9).split(":"):null;break;case"ISO":default:a=e.substring(0,10),r=e.substring(4,5),n=R(a,r),o=n[0],s=n[1],l=n[2],i=e.length>10?e.substring(11).split(":"):null}var u=i&&3===i.length?i[0]:0,m=i&&3===i.length?i[1]:0,p=i&&3===i.length?i[2]:0;return new Date(o,s-1,l,u,m,p)}function R(e,t){var a=[];switch(t){case"/":a=e.split("/");break;case".":a=e.split(".");break;case"-":default:a=e.split("-")}return a}function T(e,t,a){var r=!1;switch(e){case"<":r=a>t;break;case"<=":r=a>=t;break;case">":r=t>a;break;case">=":r=t>=a;break;case"!=":case"<>":r=t!=a;break;case"!==":r=t!==a;break;case"=":case"==":r=t==a;break;case"===":r=t===a;break;default:r=!1}return r}function F(){return this.replace(/^\s+|\s+$/g,"")}function k(){var e=Array.isArray(arguments[0])?arguments[0]:arguments;return this.replace(/{(\d+)}/g,function(t,a){return"undefined"!=typeof e[a]?e[a]:t})}function L(e){var t=Array.isArray(arguments[1])?arguments[1]:Array.prototype.slice.call(arguments,1);return e.replace(/{(\d+)}/g,function(e,a){return"undefined"!=typeof t[a]?t[a]:e})}function q(e,t,a){var r=!0,n=r=!1;if(e instanceof Date)n=!0;else{var i=new RegExp(t.pattern,t.patternFlag);n=(!t.pattern||"/\\S+/"===t.pattern.toString()||a&&"required"===t.pattern)&&null===e?!1:i.test(e)}if(n){var o=t.dateType,s=e instanceof Date?e:x(e,o).getTime();if(2==t.params.length){var l=x(t.params[0],o).getTime(),u=x(t.params[1],o).getTime(),m=T(t.condition[0],s,l),p=T(t.condition[1],s,u);r=m&&p}else{var d=x(t.params[0],o).getTime();r=T(t.condition,s,d)}}return r}function U(e,t){var a=!0;if(2==t.params.length){var r=T(t.condition[0],parseFloat(e),parseFloat(t.params[0])),n=T(t.condition[1],parseFloat(e),parseFloat(t.params[1]));a=r&&n}else a=T(t.condition,parseFloat(e),parseFloat(t.params[0]));return a}function C(e,a,r,n,i,o){var s=!0,l="Custom Javascript Validation requires an error message defined as 'alt=' in your validator or defined in your custom javascript function as { isValid: bool, message: 'your error' }",u="Custom Javascript Validation requires a declared function (in your Controller), please review your code.";if(e){var m=a.params[0],p=f(r,m);if("boolean"==typeof p)s=!!p;else{if("object"!=typeof p)throw u;s=!!p.isValid}if(s===!1?(n.isValid=!1,t(function(){var e=o.message+" ";if(p.message&&(e+=p.message)," "===e)throw l;O(r,n,e,!1,i)})):s===!0&&(n.isValid=!0,O(r,n,"",!0,i)),"undefined"==typeof p)throw u}return s}function j(e,t,r,n){var i=!0,s=t.params[0],l=r.scope.$eval(s),u=angular.element(document.querySelector('[name="'+s+'"]')),m=t,p=r.ctrl,d=o(r.ctrl.$name);return i=T(t.condition,e,l)&&!!e,u&&u.attr("friendly-name")?t.params[1]=u.attr("friendly-name"):t.params.length>1&&(t.params[1]=t.params[1]),r.scope.$watch(s,function(e,t){var i=T(m.condition,p.$viewValue,e);if(e!==t){if(i)O(r,d,"",!0,!0);else{d.isValid=!1;var o=m.message;m.altText&&m.altText.length>0&&(o=m.altText.replace("alt=","")),a(o).then(function(e){n.message=" "+(m&&m.params?String.format(e,m.params):e),O(r,d,n.message,i,!0)})}p.$setValidity("validation",i)}},!0),i}function G(e,t,a,r,n,i){var o=!0,s="Remote Javascript Validation requires an error message defined as 'alt=' in your validator or defined in your custom remote function as { isValid: bool, message: 'your error' }",l="Remote Validation requires a declared function (in your Controller) which also needs to return a Promise, please review your code.";if(e&&n){a.ctrl.$processing=!0;var u=t.params[0],m=f(a,u);if(_.length>1)for(;_.length>0;){var p=_.pop();"function"==typeof p.abort&&p.abort()}if(_.push(m),!m||"function"!=typeof m.then)throw l;a.ctrl.$setValidity("remote",!1),function(e){m.then(function(t){t=t.data||t,_.pop(),a.ctrl.$processing=!1;var u=i.message+" ";if("boolean"==typeof t)o=!!t;else{if("object"!=typeof t)throw l;o=!!t.isValid}if(o===!1){if(r.isValid=!1,u+=t.message||e," "===u)throw s;O(a,r,u,!1,n)}else o===!0&&(r.isValid=!0,a.ctrl.$setValidity("remote",!0),O(a,r,"",!0,n))})}(t.altText)}return o}function D(e,t,a,r){var n=!0,i=r.attrs?r.attrs.ngDisabled:r.validatorAttrs.ngDisabled;if(r.elm.prop("disabled")||r.scope.$eval(i))n=!0;else if("string"==typeof e&&""===e&&r.elm.prop("type")&&"NUMBER"===r.elm.prop("type").toUpperCase())n=!1;else{var o=new RegExp(t.pattern,t.patternFlag);n=(!t.pattern||"/\\S+/"===t.pattern.toString()||a&&"required"===t.pattern)&&null===e?!1:o.test(e)}return n}function M(e,t){return w(t)?{condition:e.conditionNum,message:e.messageNum,params:e.params,type:"conditionalNumber"}:{pattern:e.patternLength,message:e.messageLength,params:e.params,type:"regex"}}var I=1e3,P=[],H={resetGlobalOptionsOnRouteChange:!0},_=[],B=[];e.$on("$routeChangeStart",function(){H.resetGlobalOptionsOnRouteChange&&(H={displayOnlyLastErrorMsg:!1,hideErrorUnderInputs:!1,preValidateFormElements:!1,isolatedScope:null,scope:null,resetGlobalOptionsOnRouteChange:!0},P=[],B=[])});var J=function(e,t,a,r){this.bFieldRequired=!1,this.validators=[],this.typingLimit=I,this.scope=e,this.elm=t,this.ctrl=r,this.validatorAttrs=a,e&&e.$validationOptions&&(H=e.$validationOptions),e&&(H.isolatedScope||H.scope)&&(this.scope=H.isolatedScope||H.scope,H=p(e.$validationOptions,H)),"undefined"==typeof H.resetGlobalOptionsOnRouteChange&&(H.resetGlobalOptionsOnRouteChange=!0),this.elm&&this.validatorAttrs&&this.ctrl&&this.scope&&($(this.elm,this.validatorAttrs,this.ctrl,this.scope),this.defineValidation())};return J.prototype.addToValidationSummary=n,J.prototype.arrayFindObject=S,J.prototype.defineValidation=i,J.prototype.getFormElementByName=o,J.prototype.getFormElements=s,J.prototype.getGlobalOptions=l,J.prototype.isFieldRequired=m,J.prototype.initialize=u,J.prototype.mergeObjects=p,J.prototype.removeFromValidationSummary=c,J.prototype.removeFromFormElementObjectList=d,J.prototype.runValidationCallbackOnPromise=g,J.prototype.setDisplayOnlyLastErrorMsg=v,J.prototype.setGlobalOptions=h,J.prototype.updateErrorMsg=y,J.prototype.validate=b,String.prototype.trim=F,String.prototype.format=k,String.format=L,J}]);
-angular.module("ghiscoding.validation").factory("validationRules",[function(){function e(e){var a="undefined"!=typeof e.altText?e.altText.replace("alt=",""):null,t=e.hasOwnProperty("customRegEx")?e.customRegEx:null,s=e.hasOwnProperty("rule")?e.rule:null,n=e.hasOwnProperty("ruleParams")?e.ruleParams:null,r={};switch(s){case"accepted":r={pattern:/^(yes|on|1|true)$/i,message:"INVALID_ACCEPTED",type:"regex"};break;case"alpha":r={pattern:/^([a-zа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ])+$/i,message:"INVALID_ALPHA",type:"regex"};break;case"alphaSpaces":case"alpha_spaces":r={pattern:/^([a-zа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ\s])+$/i,message:"INVALID_ALPHA_SPACE",type:"regex"};break;case"alphaNum":case"alpha_num":r={pattern:/^([a-zа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9])+$/i,message:"INVALID_ALPHA_NUM",type:"regex"};break;case"alphaNumSpaces":case"alpha_num_spaces":r={pattern:/^([a-zа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9\s])+$/i,message:"INVALID_ALPHA_NUM_SPACE",type:"regex"};break;case"alphaDash":case"alpha_dash":r={pattern:/^([a-zа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9_-])+$/i,message:"INVALID_ALPHA_DASH",type:"regex"};break;case"alphaDashSpaces":case"alpha_dash_spaces":r={pattern:/^([a-zа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9\s_-])+$/i,message:"INVALID_ALPHA_DASH_SPACE",type:"regex"};break;case"between":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between:1,5";r={patternLength:"^(.|[\\r\\n]){"+_[0]+","+_[1]+"}$",messageLength:"INVALID_BETWEEN_CHAR",conditionNum:[">=","<="],messageNum:"INVALID_BETWEEN_NUM",params:[_[0],_[1]],type:"autoDetect"};break;case"betweenLen":case"between_len":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_len:1,5";r={pattern:"^(.|[\\r\\n]){"+_[0]+","+_[1]+"}$",message:"INVALID_BETWEEN_CHAR",params:[_[0],_[1]],type:"regex"};break;case"betweenNum":case"between_num":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_num:1,5";r={condition:[">=","<="],message:"INVALID_BETWEEN_NUM",params:[_[0],_[1]],type:"conditionalNumber"};break;case"boolean":r={pattern:/^(true|false|0|1)$/i,message:"INVALID_BOOLEAN",type:"regex"};break;case"checked":r={pattern:/^true$/i,message:"INVALID_CHECKBOX_SELECTED",type:"regex"};break;case"creditCard":case"credit_card":r={pattern:/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\d{3})\d{11})$/,message:"INVALID_CREDIT_CARD",type:"regex"};break;case"custom":case"javascript":r={message:"",params:[n],type:"javascript"};break;case"dateEuroLong":case"date_euro_long":r={pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_EURO_LONG",type:"regex"};break;case"dateEuroLongBetween":case"date_euro_long_between":case"betweenDateEuroLong":case"between_date_euro_long":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_euro_long:01-01-1990,31-12-2015";r={condition:[">=","<="],dateType:"EURO_LONG",params:[_[0],_[1]],pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_EURO_LONG_BETWEEN",type:"conditionalDate"};break;case"dateEuroLongMax":case"date_euro_long_max":case"maxDateEuroLong":case"max_date_euro_long":r={condition:"<=",dateType:"EURO_LONG",params:[n],pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_EURO_LONG_MAX",type:"conditionalDate"};break;case"dateEuroLongMin":case"date_euro_long_min":case"minDateEuroLong":case"min_date_euro_long":r={condition:">=",dateType:"EURO_LONG",params:[n],pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_EURO_LONG_MIN",type:"conditionalDate"};break;case"dateEuroShort":case"date_euro_short":r={pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.]\d\d$/,message:"INVALID_DATE_EURO_SHORT",type:"regex"};break;case"dateEuroShortBetween":case"date_euro_short_between":case"betweenDateEuroShort":case"between_date_euro_short":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_euro_short:01-01-90,31-12-15";r={condition:[">=","<="],dateType:"EURO_SHORT",params:[_[0],_[1]],pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.]\d\d$/,message:"INVALID_DATE_EURO_SHORT_BETWEEN",type:"conditionalDate"};break;case"dateEuroShortMax":case"date_euro_short_max":case"maxDateEuroShort":case"max_date_euro_short":r={condition:"<=",dateType:"EURO_SHORT",params:[n],pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.]\d\d$/,message:"INVALID_DATE_EURO_SHORT_MAX",type:"conditionalDate"};break;case"dateEuroShortMin":case"date_euro_short_min":case"minDateEuroShort":case"min_date_euro_short":r={condition:">=",dateType:"EURO_SHORT",params:[n],pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.]\d\d$/,message:"INVALID_DATE_EURO_SHORT_MIN",type:"conditionalDate"};break;case"dateIso":case"date_iso":r={pattern:/^(19|20)\d\d([-])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$/,message:"INVALID_DATE_ISO",type:"regex"};break;case"dateIsoBetween":case"date_iso_between":case"betweenDateIso":case"between_date_iso":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_iso:1990-01-01,2000-12-31";r={condition:[">=","<="],dateType:"ISO",params:[_[0],_[1]],pattern:/^(19|20)\d\d([-])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$/,message:"INVALID_DATE_ISO_BETWEEN",type:"conditionalDate"};break;case"dateIsoMax":case"date_iso_max":case"maxDateIso":case"max_date_iso":r={condition:"<=",dateType:"ISO",params:[n],pattern:/^(19|20)\d\d([-])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$/,message:"INVALID_DATE_ISO_MAX",type:"conditionalDate"};break;case"dateIsoMin":case"date_iso_min":case"minDateIso":case"min_date_iso":r={condition:">=",dateType:"ISO",params:[n],pattern:/^(19|20)\d\d([-])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$/,message:"INVALID_DATE_ISO_MIN",type:"conditionalDate"};break;case"dateUsLong":case"date_us_long":r={pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_US_LONG",type:"regex"};break;case"dateUsLongBetween":case"date_us_long_between":case"betweenDateUsLong":case"between_date_us_long":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_us_long:01/01/1990,12/31/2015";r={condition:[">=","<="],dateType:"US_LONG",params:[_[0],_[1]],pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_US_LONG_BETWEEN",type:"conditionalDate"};break;case"dateUsLongMax":case"date_us_long_max":case"maxDateUsLong":case"max_date_us_long":r={condition:"<=",dateType:"US_LONG",params:[n],pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_US_LONG_MAX",type:"conditionalDate"};break;case"dateUsLongMin":case"date_us_long_min":case"minDateUsLong":case"min_date_us_long":r={condition:">=",dateType:"US_LONG",params:[n],pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_US_LONG_MIN",type:"conditionalDate"};break;case"dateUsShort":case"date_us_short":r={pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.]\d\d$/,message:"INVALID_DATE_US_SHORT",type:"regex"};break;case"dateUsShortBetween":case"date_us_short_between":case"betweenDateUsShort":case"between_date_us_short":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_us_short:01/01/90,12/31/15";r={condition:[">=","<="],dateType:"US_SHORT",params:[_[0],_[1]],pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.]\d\d$/,message:"INVALID_DATE_US_SHORT_BETWEEN",type:"conditionalDate"};break;case"dateUsShortMax":case"date_us_short_max":case"maxDateUsShort":case"max_date_us_short":r={condition:"<=",dateType:"US_SHORT",params:[n],pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.]\d\d$/,message:"INVALID_DATE_US_SHORT_MAX",type:"conditionalDate"};break;case"dateUsShortMin":case"date_us_short_min":case"minDateUsShort":case"min_date_us_short":r={condition:">=",dateType:"US_SHORT",params:[n],pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.]\d\d$/,message:"INVALID_DATE_US_SHORT_MIN",type:"conditionalDate"};break;case"different":case"differentInput":case"different_input":var e=n.split(",");r={condition:"!=",message:"INVALID_INPUT_DIFFERENT",params:e,type:"matching"};break;case"digits":r={pattern:"^\\d{"+n+"}$",message:"INVALID_DIGITS",params:[n],type:"regex"};break;case"digitsBetween":case"digits_between":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: digits_between:1,5";r={pattern:"^\\d{"+_[0]+","+_[1]+"}$",message:"INVALID_DIGITS_BETWEEN",params:[_[0],_[1]],type:"regex"};break;case"email":r={pattern:/^[-\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ0-9#~!$%^&*_=+\/`\|}{\'?]+(\.[-\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ0-9#~!$%^&*_=+\/`\|}{\'?]+)*@([\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ0-9_][-\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ0-9_]*(\.[-\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ0-9_]+)*([\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ]+)|(\.[\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i,message:"INVALID_EMAIL",type:"regex"};break;case"exactLen":case"exact_len":r={pattern:"^(.|[\\r\\n]){"+n+"}$",message:"INVALID_EXACT_LEN",params:[n],type:"regex"};break;case"float":r={pattern:/^\d*\.{1}\d+$/,message:"INVALID_FLOAT",type:"regex"};break;case"floatSigned":case"float_signed":r={pattern:/^[-+]?\d*\.{1}\d+$/,message:"INVALID_FLOAT_SIGNED",type:"regex"};break;case"iban":r={pattern:/^[a-zA-Z]{2}\d{2}\s?([0-9a-zA-Z]{4}\s?){4}[0-9a-zA-Z]{2}$/i,message:"INVALID_IBAN",type:"regex"};break;case"in":case"inList":case"in_list":var c=RegExp().escape(n).replace(/,/g,"|");r={pattern:"^("+c+")$",patternFlag:"i",message:"INVALID_IN_LIST",params:[n],type:"regex"};break;case"int":case"integer":r={pattern:/^\d+$/,message:"INVALID_INTEGER",type:"regex"};break;case"intSigned":case"integerSigned":case"int_signed":case"integer_signed":r={pattern:/^[+-]?\d+$/,message:"INVALID_INTEGER_SIGNED",type:"regex"};break;case"ip":case"ipv4":r={pattern:/^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$/,message:"INVALID_IPV4",type:"regex"};break;case"ipv6":r={pattern:/^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/i,message:"INVALID_IPV6",type:"regex"};break;case"match":case"matchInput":case"match_input":case"same":var e=n.split(",");r={condition:"===",message:"INVALID_INPUT_MATCH",params:e,type:"matching"};break;case"max":r={patternLength:"^(.|[\\r\\n]){0,"+n+"}$",messageLength:"INVALID_MAX_CHAR",conditionNum:"<=",messageNum:"INVALID_MAX_NUM",params:[n],type:"autoDetect"};break;case"maxLen":case"max_len":r={pattern:"^(.|[\\r\\n]){0,"+n+"}$",message:"INVALID_MAX_CHAR",params:[n],type:"regex"};break;case"maxNum":case"max_num":r={condition:"<=",message:"INVALID_MAX_NUM",params:[n],type:"conditionalNumber"};break;case"min":r={patternLength:"^(.|[\\r\\n]){"+n+",}$",messageLength:"INVALID_MIN_CHAR",conditionNum:">=",messageNum:"INVALID_MIN_NUM",params:[n],type:"autoDetect"};break;case"minLen":case"min_len":r={pattern:"^(.|[\\r\\n]){"+n+",}$",message:"INVALID_MIN_CHAR",params:[n],type:"regex"};break;case"minNum":case"min_num":r={condition:">=",message:"INVALID_MIN_NUM",params:[n],type:"conditionalNumber"};break;case"notIn":case"not_in":case"notInList":case"not_in_list":var c=RegExp().escape(n).replace(/,/g,"|");r={pattern:"^((?!("+c+")).)+$",patternFlag:"i",message:"INVALID_NOT_IN_LIST",params:[n],type:"regex"};break;case"numeric":r={pattern:/^\d*\.?\d+$/,message:"INVALID_NUMERIC",type:"regex"};break;case"numericSigned":case"numeric_signed":r={pattern:/^[-+]?\d*\.?\d+$/,message:"INVALID_NUMERIC_SIGNED",type:"regex"};break;case"pattern":case"regex":r={pattern:t.pattern,message:"INVALID_PATTERN",params:[t.message],type:"regex"};break;case"remote":r={message:"",params:[n],type:"remote"};break;case"required":r={pattern:/\S+/,message:"INVALID_REQUIRED",type:"regex"};break;case"size":r={patternLength:"^(.|[\\r\\n]){"+n+"}$",messageLength:"INVALID_EXACT_LEN",conditionNum:"==",messageNum:"INVALID_EXACT_NUM",params:[n],type:"autoDetect"};break;case"url":r={pattern:/^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?/i,message:"INVALID_URL",type:"regex"};break;case"time":r={pattern:/^([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$/,message:"INVALID_TIME",type:"regex"}}return r.altText=a,r}var a={getElementValidators:e};return a}]),RegExp.prototype.escape=function(e){if(!arguments.callee.sRE){var a=["/",".","*","+","?","|","(",")","[","]","{","}","\\"];arguments.callee.sRE=new RegExp("(\\"+a.join("|\\")+")","g")}return e.replace(arguments.callee.sRE,"\\$1")};
-angular.module("ghiscoding.validation").service("validationService",["$interpolate","$q","$timeout","validationCommon",function(e,o,t,a){function n(o,a,n){var i=this,l={};if("string"==typeof o&&"string"==typeof a?(l.elmName=o,l.rules=a,l.friendlyName="string"==typeof n?n:""):l=o,"object"!=typeof l||!l.hasOwnProperty("elmName")||!l.hasOwnProperty("rules")||!l.hasOwnProperty("scope")&&"undefined"==typeof i.validationAttrs.scope)throw"Angular-Validation-Service requires at least the following 3 attributes: {elmName, rules, scope}";var m=l.scope?l.scope:i.validationAttrs.scope;if(l.elm=angular.element(document.querySelector('[name="'+l.elmName+'"]')),"object"!=typeof l.elm||0===l.elm.length)return i;if(new RegExp("{{(.*?)}}").test(l.elmName)&&(l.elmName=e(l.elmName)(m)),l.name=l.elmName,i.validationAttrs.isolatedScope){var r=m.$validationOptions||null;m=i.validationAttrs.isolatedScope,r&&(m.$validationOptions=r)}j=i.validationAttrs.hasOwnProperty("validationCallback")?i.validationAttrs.validationCallback:null,l.elm.bind("blur",O=function(e){var o=i.commonObj.getFormElementByName(l.elmName);if(o&&!o.isValidationCancelled){i.commonObj.initialize(m,l.elm,l,l.ctrl);var t=s(i,e.target.value,0);j&&i.commonObj.runValidationCallbackOnPromise(t,j)}}),l=i.commonObj.mergeObjects(i.validationAttrs,l),y(i,m,l),l.elm.on("$destroy",function(){var e=i.commonObj.getFormElementByName(i.commonObj.ctrl.$name);e&&(u(i,e),i.commonObj.removeFromValidationSummary(l.name))});var d=m.$watch(function(){return l.ctrl=angular.element(l.elm).controller("ngModel"),v(i,l.elmName)?{badInput:!0}:l.ctrl.$modelValue},function(e,o){if(e&&e.badInput){var a=i.commonObj.getFormElementByName(l.elmName);return b(i,a),f(i,l.name)}if(void 0===e&&void 0!==o&&!isNaN(o))return t.cancel(i.timer),void i.commonObj.ctrl.$setValidity("validation",i.commonObj.validate("",!0));l.ctrl=angular.element(l.elm).controller("ngModel"),l.value=e,i.commonObj.initialize(m,l.elm,l,l.ctrl);var n="undefined"==typeof e||"number"==typeof e&&isNaN(e)?0:void 0,r=s(i,e,n);j&&i.commonObj.runValidationCallbackOnPromise(r,j)},!0);return $.push({elmName:l.elmName,watcherHandler:d}),i}function i(e){var o=this,t="",a=!0;if("undefined"==typeof e||"undefined"==typeof e.$validationSummary)throw"checkFormValidity() requires a valid Angular Form or $scope/vm object passed as argument to work properly, for example:: fn($scope) OR fn($scope.form1) OR fn(vm) OR fn(vm.form1)";for(var n=0,i=e.$validationSummary.length;i>n;n++)if(a=!1,t=e.$validationSummary[n].field){var l=o.commonObj.getFormElementByName(t);l&&l.elm&&l.elm.length>0&&("function"==typeof l.ctrl.$setTouched&&l.ctrl.$setTouched(),o.commonObj.updateErrorMsg(e.$validationSummary[n].message,{isSubmitted:!0,isValid:l.isValid,obj:l}))}return a}function l(e){var o=this;if("undefined"==typeof e||"undefined"==typeof e.$validationSummary)throw"clearInvalidValidatorsInSummary() requires a valid Angular Form or $scope/vm object passed as argument to work properly, for example:: fn($scope) OR fn($scope.form1) OR fn(vm) OR fn(vm.form1)";for(var t=[],a=0,n=e.$validationSummary.length;n>a;a++)t.push(e.$validationSummary[a].field);for(a=0,n=t.length;n>a;a++)t[a]&&(o.commonObj.removeFromFormElementObjectList(t[a]),o.commonObj.removeFromValidationSummary(t[a],e.$validationSummary))}function m(e,o){var t,a=this;if("undefined"==typeof e||"undefined"==typeof e.$validationSummary)throw"removeValidator() only works with Validation that were defined by the Service (not by the Directive) and requires a valid Angular Form or $scope/vm object passed as argument to work properly, for example:: fn($scope) OR fn($scope.form1) OR fn(vm) OR fn(vm.form1)";if(o instanceof Array)for(var n=0,i=o.length;i>n;n++)t=a.commonObj.getFormElementByName(o[n]),t.elm.removeAttr("validation"),p(a,t,e.$validationSummary);else o instanceof Object&&o.formElmObj?(t=o.formElmObj,t.elm.removeAttr("validation"),p(o.self,t,e.$validationSummary)):(t=a.commonObj.getFormElementByName(o),t.elm.removeAttr("validation"),p(a,t,e.$validationSummary));return a}function r(e,o){var t,a=this,o=o||{},n="undefined"!=typeof o.removeAllValidators?o.removeAllValidators:!1,i="undefined"!=typeof o.emptyAllInputValues?o.emptyAllInputValues:!1;if("undefined"==typeof e||"undefined"==typeof e.$name)throw"resetForm() requires a valid Angular Form object passed as argument to work properly (ex.: $scope.form1).";var l=a.commonObj.getFormElements(e.$name);if(l instanceof Array)for(var r=0,d=l.length;d>r;r++)t=l[r],i&&t.elm.val(null),n?m(e,{self:a,formElmObj:t}):("function"==typeof t.ctrl.$setUntouched&&t.ctrl.$setUntouched(),t.ctrl.$setPristine(),a.commonObj.updateErrorMsg("",{isValid:!1,obj:t}))}function d(e){var o=this,t="boolean"==typeof e?e:!0;o.commonObj.setDisplayOnlyLastErrorMsg(t)}function c(e){var o=this;return o.validationAttrs=e,o.commonObj.setGlobalOptions(e),o}function s(e,a,n){var i=o.defer(),l=!1,m="undefined"!=typeof n?n:e.commonObj.typingLimit,r=e.commonObj.getFormElementByName(e.commonObj.ctrl.$name);return a&&a.badInput?f(e,attrs.name):(e.commonObj.validate(a,!1),e.commonObj.isFieldRequired()||""!==a&&null!==a&&"undefined"!=typeof a?(r.isValidationCancelled=!1,(e.commonObj.isFieldRequired()||a)&&e.commonObj.ctrl.$setValidity("validation",!1),""!==a&&"undefined"!=typeof a||"NUMBER"!==e.commonObj.elm.prop("type").toUpperCase()?"SELECT"===e.commonObj.elm.prop("tagName").toUpperCase()?(l=e.commonObj.validate(a,!0),e.commonObj.ctrl.$setValidity("validation",l),i.resolve({isFieldValid:l,formElmObj:r,value:a}),i.promise):("undefined"!=typeof a&&(0===n?(l=e.commonObj.validate(a,!0),e.commonObj.scope.$evalAsync(e.commonObj.ctrl.$setValidity("validation",l)),i.resolve({isFieldValid:l,formElmObj:r,value:a}),t.cancel(e.timer)):(e.commonObj.updateErrorMsg(""),t.cancel(e.timer),e.timer=t(function(){l=e.commonObj.validate(a,!0),e.commonObj.scope.$evalAsync(e.commonObj.ctrl.$setValidity("validation",l)),i.resolve({isFieldValid:l,formElmObj:r,value:a})},m))),i.promise):(t.cancel(e.timer),l=e.commonObj.validate(a,!0),i.resolve({isFieldValid:l,formElmObj:r,value:a}),i.promise)):(u(e,r),i.resolve({isFieldValid:!0,formElmObj:r,value:a}),i.promise))}function u(e,o){var a=o&&o.ctrl?o.ctrl:e.commonObj.ctrl;o&&(o.isValidationCancelled=!0),t.cancel(self.timer),a.$setValidity("validation",!0),e.commonObj.updateErrorMsg("",{isValid:!0,obj:o}),b(e,o)}function f(e,o){t.cancel(e.timer);var a=e.commonObj.getFormElementByName(o);e.commonObj.updateErrorMsg("INVALID_KEY_CHAR",{isValid:!1,translate:!0,obj:a}),e.commonObj.addToValidationSummary(a,"INVALID_KEY_CHAR",!0)}function v(e,o){var t=e.commonObj.getFormElementByName(o);return!!t&&!!t.elm.prop("validity")&&t.elm.prop("validity").badInput===!0}function p(e,o,t){var a=e.commonObj.scope?e.commonObj.scope:o.scope?o.scope:null;if("undefined"==typeof a)throw"removeValidator() requires a valid $scope object passed but unfortunately could not find it.";var n=e.commonObj.arrayFindObject($,"elmName",o.fieldName);n&&n.watcherHandler(),o.isValidationCancelled=!0,o.isValid=!0,o.attrs.validation="",u(e,o),"function"==typeof o.ctrl.$setUntouched&&o.ctrl.$setUntouched(),e.commonObj.scope=a,o.ctrl.$setPristine(),e.commonObj.removeFromValidationSummary(o.fieldName,t)}function b(e,o){if(o.isValidationCancelled=!0,"function"==typeof O){var t=o&&o.elm?o.elm:e.commonObj.elm;t.unbind("blur",O)}}function y(e,o,a){o.$watch(function(){return"undefined"==typeof a.elm.attr("ng-disabled")?null:o.$eval(a.elm.attr("ng-disabled"))},function(n){if("undefined"==typeof n||null===n)return null;a.ctrl=angular.element(a.elm).controller("ngModel"),e.commonObj.initialize(o,a.elm,a,a.ctrl);var i=e.commonObj.getFormElementByName(a.name);t(function(){if(n)a.ctrl.$setValidity("validation",!0),e.commonObj.updateErrorMsg("",{isValid:!0,obj:i}),e.commonObj.removeFromValidationSummary(a.name);else{var t=a.ctrl.$viewValue||"";e.commonObj.initialize(o,a.elm,a,a.ctrl),a.ctrl.$setValidity("validation",e.commonObj.validate(t,!1)),i&&(i.isValidationCancelled=!1),a.elm.bind("blur",O=function(o){if(i&&!i.isValidationCancelled){var t=s(e,o.target.value,10);j&&e.commonObj.runValidationCallbackOnPromise(t,j)}})}},0,!1),n&&("function"==typeof a.ctrl.$setUntouched&&a.ctrl.$setUntouched(),a.ctrl.$setValidity("validation",!0),e.commonObj.removeFromValidationSummary(a.name))})}var O,j,$=[],g=function(e){this.isValidationCancelled=!1,this.timer=null,this.validationAttrs={},this.commonObj=new a,e&&this.setGlobalOptions(e)};return g.prototype.addValidator=n,g.prototype.checkFormValidity=i,g.prototype.removeValidator=m,g.prototype.resetForm=r,g.prototype.setDisplayOnlyLastErrorMsg=d,g.prototype.setGlobalOptions=c,g.prototype.clearInvalidValidatorsInSummary=l,g}]);
\ No newline at end of file
+angular.module("ghiscoding.validation",["pascalprecht.translate"]).directive("validation",["$q","$timeout","validationCommon",function(a,e,i){return{restrict:"A",require:"ngModel",link:function(n,t,r,l){function o(i,r){var o=a.defer(),d=!1,m="undefined"!=typeof r?r:E.typingLimit,s=E.getFormElementByName(l.$name);if(Array.isArray(i)){if($=[],O="",m=0,i.length>0)return"function"==typeof s.ctrl.$setTouched&&s.ctrl.$setTouched(),u(i,typeof i);m=0}return i&&i.badInput?v():(E.validate(i,!1),E.isFieldRequired()||w||""!==i&&null!==i&&"undefined"!=typeof i?(s&&(s.isValidationCancelled=!1),(i||E.isFieldRequired()||w)&&l.$setValidity("validation",!1),"SELECT"===t.prop("tagName").toUpperCase()?(d=E.validate(i,!0),l.$setValidity("validation",d),o.resolve({isFieldValid:d,formElmObj:s,value:i}),o.promise):("undefined"!=typeof i&&(0===r?(d=E.validate(i,!0),n.$evalAsync(l.$setValidity("validation",d)),o.resolve({isFieldValid:d,formElmObj:s,value:i}),e.cancel(V)):(E.updateErrorMsg(""),e.cancel(V),V=e(function(){d=E.validate(i,!0),n.$evalAsync(l.$setValidity("validation",d)),o.resolve({isFieldValid:d,formElmObj:s,value:i})},m))),o.promise)):(f(),o.resolve({isFieldValid:!0,formElmObj:s,value:i}),o.promise))}function d(a,e,i){var n=o(a,0);n&&"function"==typeof n.then&&($.push(n),parseInt(e)===i-1&&$.forEach(function(a){a.then(function(a){switch(A){case"all":a.isFieldValid===!1&&a.formElmObj.translatePromise.then(function(e){O.length>0&&g.displayOnlyLastErrorMsg?O="["+a.value+"] :: "+(a.formElmObj.validator&&a.formElmObj.validator.params?String.format(e,a.formElmObj.validator.params):e):O+=" ["+a.value+"] :: "+(a.formElmObj.validator&&a.formElmObj.validator.params?String.format(e,a.formElmObj.validator.params):e),E.updateErrorMsg(O,{isValid:!1}),E.addToValidationSummary(a.formElmObj,O)});break;case"one":default:a.isFieldValid===!0&&(l.$setValidity("validation",!0),f())}})}))}function m(a){var e=E.getFormElementByName(l.$name),i="undefined"!=typeof l.$modelValue?l.$modelValue:a.target.value;if(e.isValidationCancelled)l.$setValidity("validation",!0);else{var n=o(i,0);F&&E.runValidationCallbackOnPromise(n,F)}}function u(a,e){var i=a.length;if("string"===e)for(var n in a)d(a[n],n,i);else if("object"===e)for(var n in a)if(a.hasOwnProperty(n)){var t=a[n];for(var r in t)if(t.hasOwnProperty(r)){if(C&&r!==C)continue;d(t[r],n,i)}}}function s(){f(),E.removeFromValidationSummary(j);var a=E.arrayFindObject(h,"elmName",l.$name);if(a&&"function"==typeof a.watcherHandler){{a.watcherHandler()}h.shift()}}function f(){var a=E.getFormElementByName(l.$name);a&&(a.isValidationCancelled=!0),e.cancel(V),E.updateErrorMsg(""),l.$setValidity("validation",!0),b()}function c(){return n.$watch(function(){return p()?{badInput:!0}:l.$modelValue},function(a){if(a&&a.badInput)return b(),v();var e=o(a);F&&E.runValidationCallbackOnPromise(e,F)},!0)}function v(){e.cancel(V);var a=E.getFormElementByName(l.$name);E.updateErrorMsg("INVALID_KEY_CHAR",{isValid:!1,translate:!0}),E.addToValidationSummary(a,"INVALID_KEY_CHAR",!0)}function p(){return!!t.prop("validity")&&t.prop("validity").badInput===!0}function y(){var a=l.$modelValue||"";Array.isArray(a)||l.$setValidity("validation",E.validate(a,!1));var e=E.getFormElementByName(l.$name);e&&(e.isValidationCancelled=!1),b(),t.bind("blur",m)}function b(){"function"==typeof m&&t.unbind("blur",m)}var V,E=new i(n,t,r,l),O="",$=[],h=[],g=E.getGlobalOptions(),j=r.name,F=r.hasOwnProperty("validationCallback")?r.validationCallback:null,w=r.hasOwnProperty("validateOnEmpty")?E.parseBool(r.validateOnEmpty):!!g.validateOnEmpty,A=r.hasOwnProperty("validArrayRequireHowMany")?r.validArrayRequireHowMany:"one",C=r.hasOwnProperty("validationArrayObjprop")?r.validationArrayObjprop:null;h.push({elmName:j,watcherHandler:c()}),r.$observe("disabled",function(a){a?(f(),E.removeFromValidationSummary(j)):y()}),t.on("$destroy",function(){s()}),n.$watch(function(){return t.attr("validation")},function(a){if("undefined"==typeof a||""===a)s();else{E.defineValidation(),y();var e=E.arrayFindObject(h,"elmName",l.$name);e||h.push({elmName:j,watcherHandler:c()})}}),t.bind("blur",m)}}}]);
+angular.module("ghiscoding.validation").factory("validationCommon",["$rootScope","$timeout","$translate","validationRules",function(e,t,a,r){function n(e,t,r){if("undefined"!=typeof e&&null!=e){var n=e.ctrl&&e.ctrl.$name?e.ctrl.$name:e.attrs&&e.attrs.name?e.attrs.name:e.elm.attr("name"),i=R(n,e),o=E(z,"field",n);if(o>=0&&""===t)z.splice(o,1);else if(""!==t){r&&(t=a.instant(t));var s=e.attrs&&e.friendlyName?a.instant(e.friendlyName):"",l={field:n,friendlyName:s,message:t,formName:i?i.$name:null};o>=0?z[o]=l:z.push(l)}if(e.scope.$validationSummary=z,i&&(i.$validationSummary=S(z,"formName",i.$name)),_&&_.controllerAs&&(_.controllerAs.$validationSummary=z,i&&i.$name)){var u=i.$name.indexOf(".")>=0?i.$name.split(".")[1]:i.$name,d=_.controllerAs[u]?_.controllerAs[u]:e.elm.controller()[u];d&&(d.$validationSummary=S(z,"formName",i.$name))}return z}}function i(){var e=this,t={};e.validators=[],e=A(e);var a=e.validatorAttrs.rules||e.validatorAttrs.validation;if(a.indexOf("pattern=/")>=0){var n=a.match(/pattern=(\/.*\/[igm]*)(:alt=(.*))?/);if(!n||n.length<3)throw'Regex validator within the validation needs to be define with an opening "/" and a closing "/", please review your validator.';var i=n[1],o=n[2]?n[2].replace(/\|(.*)/,""):"",s=i.match(new RegExp("^/(.*?)/([gimy]*)$")),l=new RegExp(s[1],s[2]);t={altMsg:o,message:o.replace(/:alt=/,""),pattern:l},a=a.replace("pattern="+i,"pattern")}else if(a.indexOf("regex:")>=0){var n=a.match("regex:(.*?):regex");if(n.length<2)throw'Regex validator within the validation needs to be define with an opening "regex:" and a closing ":regex", please review your validator.';var u=n[1].split(":=");t={message:u[0],pattern:u[1]},a=a.replace(n[0],"regex:")}var d=a.split("|");if(d){e.bFieldRequired=a.indexOf("required")>=0;for(var p=0,m=d.length;m>p;p++){var c=d[p].split(":"),f=d[p].indexOf("alt=")>=0;e.validators[p]=r.getElementValidators({altText:f===!0?2===c.length?c[1]:c[2]:"",customRegEx:t,rule:c[0],ruleParams:f&&2===c.length?null:c[1]})}}return e}function o(e){return w(B,"fieldName",e)}function s(e){return e?S(B,"formName",e):B}function l(){return _}function u(e,t,a,r){this.scope=e,this.elm=t,this.ctrl=r,this.validatorAttrs=a,O(t,a,r,e),this.defineValidation()}function d(){var e=this;return e.bFieldRequired}function p(e,t){var a={};for(var r in e)a[r]=e[r];for(var r in t)a[r]=t[r];return a}function m(e){var t=E(B,"fieldName",e);t>=0&&B.splice(t,1)}function c(e,t){var a=this,r=R(e,a),n=t||z,i=E(n,"field",e);if(i>=0&&n.splice(i,1),i=E(z,"field",e),i>=0&&z.splice(i,1),a.scope.$validationSummary=z,r&&(r.$validationSummary=S(z,"formName",r.$name)),_&&_.controllerAs&&(_.controllerAs.$validationSummary=z,r)){var o=r.$name.indexOf(".")>=0?r.$name.split(".")[1]:r.$name;_.controllerAs[o]&&(_.controllerAs[o].$validationSummary=S(z,"formName",r.$name))}return z}function f(e,t){var a;if(/\({1}.*\){1}/gi.test(t))a=e.scope.$eval(t);else{var r=N(e.scope,t,".");"function"==typeof r&&(a=r())}return a}function g(e,t){var a=this;"function"==typeof e.then&&e.then(function(){f(a,t)})}function v(e){_.displayOnlyLastErrorMsg=e}function y(e){var t=this;return _=p(_,e),t}function h(e,t){var r=this;t&&t.obj&&(r=t.obj,r.validatorAttrs=t.obj.attrs);var n=t&&t.elm?t.elm:r.elm,i=n&&n.attr("name")?n.attr("name"):null;if("undefined"==typeof i||null===i){var o=n?n.attr("ng-model"):"unknown";throw'Angular-Validation Service requires you to have a (name="") attribute on the element to validate... Your element is: ng-model="'+o+'"'}var s=t&&t.translate?a.instant(e):e,l=i.replace(/[|&;$%@"<>()+,\[\]\{\}]/g,"").replace(/\./g,"-"),u=null;if(r.validatorAttrs&&r.validatorAttrs.hasOwnProperty("validationErrorTo")){var d=r.validatorAttrs.validationErrorTo.charAt(0),p="."===d||"#"===d?r.validatorAttrs.validationErrorTo:"#"+r.validatorAttrs.validationErrorTo;u=angular.element(document.querySelector(p))}u&&0!==u.length||(u=angular.element(document.querySelector(".validation-"+l)));var m=t&&t.isSubmitted?t.isSubmitted:!1;!_.hideErrorUnderInputs&&t&&!t.isValid&&(m||r.ctrl.$dirty||r.ctrl.$touched)?u.length>0?u.html(s):n.after(''+s+""):u.html("")}function b(e,t){var r,i=this,s=!0,l=!0,u=0,d={message:""};"undefined"==typeof e&&(e="");for(var p=i.ctrl&&i.ctrl.$name?i.ctrl.$name:i.attrs&&i.attrs.name?i.attrs.name:i.elm.attr("name"),m=o(p),c=i.validatorAttrs.rules||i.validatorAttrs.validation,f=0,g=i.validators.length;g>f;f++){r=i.validators[f],"autoDetect"===r.type&&(r=D(r,e));var v=i.attrs?i.attrs.ngDisabled:i.validatorAttrs.ngDisabled;switch(r.type){case"conditionalDate":s=M(e,r,c);break;case"conditionalNumber":s=U(e,r);break;case"javascript":s=j(e,r,i,m,t,d);break;case"matching":s=G(e,r,i,d);break;case"remote":s=H(e,r,i,m,t,d);break;default:s=P(e,r,c,i)}if((!i.bFieldRequired&&!e&&!K||i.elm.prop("disabled")||i.scope.$eval(v))&&(s=!0),s||(l=!1,function(e,r,n){var o=n.message;n.altText&&n.altText.length>0&&(o=n.altText.replace("alt=",""));var s=a(o);e.translatePromise=s,e.validator=n,s.then(function(a){d.message.length>0&&_.displayOnlyLastErrorMsg?d.message=" "+(n&&n.params?String.format(a,n.params):a):d.message+=" "+(n&&n.params?String.format(a,n.params):a),$(i,e,d.message,l,t)})["catch"](function(){n.altText&&n.altText.length>0&&(d.message.length>0&&_.displayOnlyLastErrorMsg?d.message=" "+o:d.message+=" "+o,$(i,e,d.message,l,t))})}(m,s,r)),s&&u++,i.validRequireHowMany==u&&s){l=!0;break}}return s&&(n(i,""),i.updateErrorMsg("",{isValid:s})),m&&(m.isValid=l,l&&(m.message="")),l}function O(e,t,r,n){var i=t.name?t.name:e.attr("name"),o=R(i,{scope:n}),s=t&&t.friendlyName?a.instant(t.friendlyName):"",l={fieldName:i,friendlyName:s,elm:e,attrs:t,ctrl:r,scope:n,isValid:!1,message:"",formName:o?o.$name:null},u=E(B,"fieldName",e.attr("name"));return u>=0?B[u]=l:B.push(l),B}function $(e,t,a,r,i){a=a.trim(),t&&t.isValidationCancelled===!0&&(a=""),n(t,a),(e.validatorAttrs.preValidateFormElements||_.preValidateFormElements)&&(t&&"function"==typeof e.ctrl.$setTouched&&t.ctrl.$setTouched(),e.ctrl.$dirty===!1&&h(a,{isSubmitted:!0,isValid:r,obj:t})),i&&t&&!t.isValid?e.updateErrorMsg(a,{isValid:r,obj:t}):t&&t.isValid&&n(t,"")}function A(e){return e.typingLimit=I,e.validatorAttrs.hasOwnProperty("debounce")?e.typingLimit=parseInt(e.validatorAttrs.debounce,10):e.validatorAttrs.hasOwnProperty("typingLimit")?e.typingLimit=parseInt(e.validatorAttrs.typingLimit,10):_&&_.hasOwnProperty("debounce")&&(e.typingLimit=parseInt(_.debounce,10)),e.validRequireHowMany=e.validatorAttrs.hasOwnProperty("validRequireHowMany")?e.validatorAttrs.validRequireHowMany:_.validRequireHowMany,K=e.validatorAttrs.hasOwnProperty("validateOnEmpty")?x(e.validatorAttrs.validateOnEmpty):_.validateOnEmpty,e}function w(e,t,a){if(e)for(var r=0;r=0?N(t.scope,o,"."):t.scope[o]))return"undefined"==typeof a.$name&&(a.$name=o),a}if(i){var o=i?i.getAttribute("name"):null;if(o){var s={$name:o,specialNote:"Created by Angular-Validation for Isolated Scope usage"};if(_&&_.controllerAs&&o.indexOf(".")>=0){var l=o.split(".");return t.scope[l[0]][l[1]]=s}return t.scope[o]=s}}return null}function V(e){return!isNaN(parseFloat(e))&&isFinite(e)}function N(e,t,a){for(var r=a?t.split(a):t,n=0,i=r.length;i>n;n++)e[r[n]]&&(e=e[r[n]]);return e}function x(e){return"boolean"==typeof e||"number"==typeof e?e===!0||1===e:"string"==typeof e&&(e=e.replace(/^\s+|\s+$/g,"").toLowerCase(),"true"===e||"1"===e||"false"===e||"0"===e)?"true"===e||"1"===e:void 0}function T(e,t){var a="",r="-",n=[],i=[],o="",s="",l="";switch(t.toUpperCase()){case"EURO_LONG":case"EURO-LONG":a=e.substring(0,10),r=e.substring(2,3),n=q(a,r),l=n[0],s=n[1],o=n[2],i=e.length>8?e.substring(9).split(":"):null;break;case"UK":case"EURO":case"EURO_SHORT":case"EURO-SHORT":case"EUROPE":a=e.substring(0,8),r=e.substring(2,3),n=q(a,r),l=n[0],s=n[1],o=parseInt(n[2])<50?"20"+n[2]:"19"+n[2],i=e.length>8?e.substring(9).split(":"):null;break;case"US_LONG":case"US-LONG":a=e.substring(0,10),r=e.substring(2,3),n=q(a,r),s=n[0],l=n[1],o=n[2],i=e.length>8?e.substring(9).split(":"):null;break;case"US":case"US_SHORT":case"US-SHORT":a=e.substring(0,8),r=e.substring(2,3),n=q(a,r),s=n[0],l=n[1],o=parseInt(n[2])<50?"20"+n[2]:"19"+n[2],i=e.length>8?e.substring(9).split(":"):null;break;case"ISO":default:a=e.substring(0,10),r=e.substring(4,5),n=q(a,r),o=n[0],s=n[1],l=n[2],i=e.length>10?e.substring(11).split(":"):null}var u=i&&3===i.length?i[0]:0,d=i&&3===i.length?i[1]:0,p=i&&3===i.length?i[2]:0;return new Date(o,s-1,l,u,d,p)}function q(e,t){var a=[];switch(t){case"/":a=e.split("/");break;case".":a=e.split(".");break;case"-":default:a=e.split("-")}return a}function F(e,t,a){var r=!1;switch(e){case"<":r=a>t;break;case"<=":r=a>=t;break;case">":r=t>a;break;case">=":r=t>=a;break;case"!=":case"<>":r=t!=a;break;case"!==":r=t!==a;break;case"=":case"==":r=t==a;break;case"===":r=t===a;break;default:r=!1}return r}function k(){return this.replace(/^\s+|\s+$/g,"")}function L(){var e=Array.isArray(arguments[0])?arguments[0]:arguments;return this.replace(/{(\d+)}/g,function(t,a){return"undefined"!=typeof e[a]?e[a]:t})}function C(e){var t=Array.isArray(arguments[1])?arguments[1]:Array.prototype.slice.call(arguments,1);return e.replace(/{(\d+)}/g,function(e,a){return"undefined"!=typeof t[a]?t[a]:e})}function M(e,t,a){var r=!0,n=r=!1;if(e instanceof Date)n=!0;else{var i=new RegExp(t.pattern,t.patternFlag);n=(!t.pattern||"/\\S+/"===t.pattern.toString()||a&&"required"===t.pattern)&&null===e?!1:i.test(e)}if(n){var o=t.dateType,s=e instanceof Date?e:T(e,o).getTime();if(2==t.params.length){var l=T(t.params[0],o).getTime(),u=T(t.params[1],o).getTime(),d=F(t.condition[0],s,l),p=F(t.condition[1],s,u);r=d&&p}else{var m=T(t.params[0],o).getTime();r=F(t.condition,s,m)}}return r}function U(e,t){var a=!0;if(2==t.params.length){var r=F(t.condition[0],parseFloat(e),parseFloat(t.params[0])),n=F(t.condition[1],parseFloat(e),parseFloat(t.params[1]));a=r&&n}else a=F(t.condition,parseFloat(e),parseFloat(t.params[0]));return a}function j(e,a,r,n,i,o){var s=!0,l="Custom Javascript Validation requires an error message defined as 'alt=' in your validator or defined in your custom javascript function as { isValid: bool, message: 'your error' }",u="Custom Javascript Validation requires a declared function (in your Controller), please review your code.";if(e||K){var d=a.params[0],p=f(r,d);if("boolean"==typeof p)s=!!p;else{if("object"!=typeof p)throw u;s=!!p.isValid}if(s===!1?(n.isValid=!1,t(function(){var e=o.message+" ";if(p.message&&(e+=p.message)," "===e)throw l;$(r,n,e,!1,i)})):s===!0&&(n.isValid=!0,$(r,n,"",!0,i)),"undefined"==typeof p)throw u}return s}function G(e,t,r,n){var i=!0,s=t.params[0],l=r.scope.$eval(s),u=angular.element(document.querySelector('[name="'+s+'"]')),d=t,p=r.ctrl,m=o(r.ctrl.$name);return i=F(t.condition,e,l)&&!!e,u&&u.attr("friendly-name")?t.params[1]=u.attr("friendly-name"):t.params.length>1&&(t.params[1]=t.params[1]),r.scope.$watch(s,function(e,t){var i=F(d.condition,p.$viewValue,e);if(e!==t){if(i)$(r,m,"",!0,!0);else{m.isValid=!1;var o=d.message;d.altText&&d.altText.length>0&&(o=d.altText.replace("alt=","")),a(o).then(function(e){n.message=" "+(d&&d.params?String.format(e,d.params):e),$(r,m,n.message,i,!0)})}p.$setValidity("validation",i)}},!0),i}function H(e,t,a,r,n,i){var o=!0,s="Remote Javascript Validation requires an error message defined as 'alt=' in your validator or defined in your custom remote function as { isValid: bool, message: 'your error' }",l="Remote Validation requires a declared function (in your Controller) which also needs to return a Promise, please review your code.";if(e&&n||K){a.ctrl.$processing=!0;var u=t.params[0],d=f(a,u);if(J.length>1)for(;J.length>0;){var p=J.pop();"function"==typeof p.abort&&p.abort()}if(J.push(d),!d||"function"!=typeof d.then)throw l;a.ctrl.$setValidity("remote",!1),function(e){d.then(function(t){t=t.data||t,J.pop(),a.ctrl.$processing=!1;var u=i.message+" ";if("boolean"==typeof t)o=!!t;else{if("object"!=typeof t)throw l;o=!!t.isValid}if(o===!1){if(r.isValid=!1,u+=t.message||e," "===u)throw s;$(a,r,u,!1,n)}else o===!0&&(r.isValid=!0,a.ctrl.$setValidity("remote",!0),$(a,r,"",!0,n))})}(t.altText)}return o}function P(e,t,a,r){var n=!0,i=r.attrs?r.attrs.ngDisabled:r.validatorAttrs.ngDisabled;if(r.elm.prop("disabled")||r.scope.$eval(i))n=!0;else if("string"==typeof e&&""===e&&r.elm.prop("type")&&"NUMBER"===r.elm.prop("type").toUpperCase())n=!1;else{var o=new RegExp(t.pattern,t.patternFlag);n=(!t.pattern||"/\\S+/"===t.pattern.toString()||a&&"required"===t.pattern)&&null===e?!1:o.test(e)}return n}function D(e,t){return V(t)?{condition:e.conditionNum,message:e.messageNum,params:e.params,type:"conditionalNumber"}:{pattern:e.patternLength,message:e.messageLength,params:e.params,type:"regex"}}var I=1e3,B=[],_={resetGlobalOptionsOnRouteChange:!0},J=[],z=[],K=!1;e.$on("$routeChangeStart",function(){_.resetGlobalOptionsOnRouteChange&&(_={displayOnlyLastErrorMsg:!1,hideErrorUnderInputs:!1,preValidateFormElements:!1,isolatedScope:null,scope:null,validateOnEmpty:!1,validRequireHowMany:"all",resetGlobalOptionsOnRouteChange:!0},B=[],z=[])});var Y=function(e,t,a,r){this.bFieldRequired=!1,this.validators=[],this.typingLimit=I,this.scope=e,this.elm=t,this.ctrl=r,this.validatorAttrs=a,this.validateOnEmpty=!1,this.validRequireHowMany="all",e&&e.$validationOptions&&(_=e.$validationOptions),e&&(_.isolatedScope||_.scope)&&(this.scope=_.isolatedScope||_.scope,_=p(e.$validationOptions,_)),"undefined"==typeof _.resetGlobalOptionsOnRouteChange&&(_.resetGlobalOptionsOnRouteChange=!0),this.elm&&this.validatorAttrs&&this.ctrl&&this.scope&&(O(this.elm,this.validatorAttrs,this.ctrl,this.scope),this.defineValidation())};return Y.prototype.addToValidationSummary=n,Y.prototype.arrayFindObject=w,Y.prototype.defineValidation=i,Y.prototype.getFormElementByName=o,Y.prototype.getFormElements=s,Y.prototype.getGlobalOptions=l,Y.prototype.isFieldRequired=d,Y.prototype.initialize=u,Y.prototype.mergeObjects=p,Y.prototype.parseBool=x,Y.prototype.removeFromValidationSummary=c,Y.prototype.removeFromFormElementObjectList=m,Y.prototype.runValidationCallbackOnPromise=g,Y.prototype.setDisplayOnlyLastErrorMsg=v,Y.prototype.setGlobalOptions=y,Y.prototype.updateErrorMsg=h,Y.prototype.validate=b,String.prototype.trim=k,String.prototype.format=L,String.format=C,Y}]);
+angular.module("ghiscoding.validation").factory("validationRules",[function(){function e(e){var a="undefined"!=typeof e.altText?e.altText.replace("alt=",""):null,t=e.hasOwnProperty("customRegEx")?e.customRegEx:null,s=e.hasOwnProperty("rule")?e.rule:null,n=e.hasOwnProperty("ruleParams")?e.ruleParams:null,r={};switch(s){case"accepted":r={pattern:/^(yes|on|1|true)$/i,message:"INVALID_ACCEPTED",type:"regex"};break;case"alpha":r={pattern:/^([a-zа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ])+$/i,message:"INVALID_ALPHA",type:"regex"};break;case"alphaSpaces":case"alpha_spaces":r={pattern:/^([a-zа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ\s])+$/i,message:"INVALID_ALPHA_SPACE",type:"regex"};break;case"alphaNum":case"alpha_num":r={pattern:/^([a-zа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9])+$/i,message:"INVALID_ALPHA_NUM",type:"regex"};break;case"alphaNumSpaces":case"alpha_num_spaces":r={pattern:/^([a-zа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9\s])+$/i,message:"INVALID_ALPHA_NUM_SPACE",type:"regex"};break;case"alphaDash":case"alpha_dash":r={pattern:/^([a-zа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9_-])+$/i,message:"INVALID_ALPHA_DASH",type:"regex"};break;case"alphaDashSpaces":case"alpha_dash_spaces":r={pattern:/^([a-zа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9\s_-])+$/i,message:"INVALID_ALPHA_DASH_SPACE",type:"regex"};break;case"between":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between:1,5";r={patternLength:"^(.|[\\r\\n]){"+_[0]+","+_[1]+"}$",messageLength:"INVALID_BETWEEN_CHAR",conditionNum:[">=","<="],messageNum:"INVALID_BETWEEN_NUM",params:[_[0],_[1]],type:"autoDetect"};break;case"betweenLen":case"between_len":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_len:1,5";r={pattern:"^(.|[\\r\\n]){"+_[0]+","+_[1]+"}$",message:"INVALID_BETWEEN_CHAR",params:[_[0],_[1]],type:"regex"};break;case"betweenNum":case"between_num":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_num:1,5";r={condition:[">=","<="],message:"INVALID_BETWEEN_NUM",params:[_[0],_[1]],type:"conditionalNumber"};break;case"boolean":r={pattern:/^(true|false|0|1)$/i,message:"INVALID_BOOLEAN",type:"regex"};break;case"checked":r={pattern:/^true$/i,message:"INVALID_CHECKBOX_SELECTED",type:"regex"};break;case"creditCard":case"credit_card":r={pattern:/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\d{3})\d{11})$/,message:"INVALID_CREDIT_CARD",type:"regex"};break;case"custom":case"javascript":r={message:"",params:[n],type:"javascript"};break;case"dateEuroLong":case"date_euro_long":r={pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_EURO_LONG",type:"regex"};break;case"dateEuroLongBetween":case"date_euro_long_between":case"betweenDateEuroLong":case"between_date_euro_long":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_euro_long:01-01-1990,31-12-2015";r={condition:[">=","<="],dateType:"EURO_LONG",params:[_[0],_[1]],pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_EURO_LONG_BETWEEN",type:"conditionalDate"};break;case"dateEuroLongMax":case"date_euro_long_max":case"maxDateEuroLong":case"max_date_euro_long":r={condition:"<=",dateType:"EURO_LONG",params:[n],pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_EURO_LONG_MAX",type:"conditionalDate"};break;case"dateEuroLongMin":case"date_euro_long_min":case"minDateEuroLong":case"min_date_euro_long":r={condition:">=",dateType:"EURO_LONG",params:[n],pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_EURO_LONG_MIN",type:"conditionalDate"};break;case"dateEuroShort":case"date_euro_short":r={pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.]\d\d$/,message:"INVALID_DATE_EURO_SHORT",type:"regex"};break;case"dateEuroShortBetween":case"date_euro_short_between":case"betweenDateEuroShort":case"between_date_euro_short":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_euro_short:01-01-90,31-12-15";r={condition:[">=","<="],dateType:"EURO_SHORT",params:[_[0],_[1]],pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.]\d\d$/,message:"INVALID_DATE_EURO_SHORT_BETWEEN",type:"conditionalDate"};break;case"dateEuroShortMax":case"date_euro_short_max":case"maxDateEuroShort":case"max_date_euro_short":r={condition:"<=",dateType:"EURO_SHORT",params:[n],pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.]\d\d$/,message:"INVALID_DATE_EURO_SHORT_MAX",type:"conditionalDate"};break;case"dateEuroShortMin":case"date_euro_short_min":case"minDateEuroShort":case"min_date_euro_short":r={condition:">=",dateType:"EURO_SHORT",params:[n],pattern:/^(0[1-9]|[12][0-9]|3[01])[-\/\.](0[1-9]|1[012])[-\/\.]\d\d$/,message:"INVALID_DATE_EURO_SHORT_MIN",type:"conditionalDate"};break;case"dateIso":case"date_iso":r={pattern:/^(19|20)\d\d([-])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$/,message:"INVALID_DATE_ISO",type:"regex"};break;case"dateIsoBetween":case"date_iso_between":case"betweenDateIso":case"between_date_iso":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_iso:1990-01-01,2000-12-31";r={condition:[">=","<="],dateType:"ISO",params:[_[0],_[1]],pattern:/^(19|20)\d\d([-])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$/,message:"INVALID_DATE_ISO_BETWEEN",type:"conditionalDate"};break;case"dateIsoMax":case"date_iso_max":case"maxDateIso":case"max_date_iso":r={condition:"<=",dateType:"ISO",params:[n],pattern:/^(19|20)\d\d([-])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$/,message:"INVALID_DATE_ISO_MAX",type:"conditionalDate"};break;case"dateIsoMin":case"date_iso_min":case"minDateIso":case"min_date_iso":r={condition:">=",dateType:"ISO",params:[n],pattern:/^(19|20)\d\d([-])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$/,message:"INVALID_DATE_ISO_MIN",type:"conditionalDate"};break;case"dateUsLong":case"date_us_long":r={pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_US_LONG",type:"regex"};break;case"dateUsLongBetween":case"date_us_long_between":case"betweenDateUsLong":case"between_date_us_long":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_us_long:01/01/1990,12/31/2015";r={condition:[">=","<="],dateType:"US_LONG",params:[_[0],_[1]],pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_US_LONG_BETWEEN",type:"conditionalDate"};break;case"dateUsLongMax":case"date_us_long_max":case"maxDateUsLong":case"max_date_us_long":r={condition:"<=",dateType:"US_LONG",params:[n],pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_US_LONG_MAX",type:"conditionalDate"};break;case"dateUsLongMin":case"date_us_long_min":case"minDateUsLong":case"min_date_us_long":r={condition:">=",dateType:"US_LONG",params:[n],pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.](19|20)\d\d$/,message:"INVALID_DATE_US_LONG_MIN",type:"conditionalDate"};break;case"dateUsShort":case"date_us_short":r={pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.]\d\d$/,message:"INVALID_DATE_US_SHORT",type:"regex"};break;case"dateUsShortBetween":case"date_us_short_between":case"betweenDateUsShort":case"between_date_us_short":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_us_short:01/01/90,12/31/15";r={condition:[">=","<="],dateType:"US_SHORT",params:[_[0],_[1]],pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.]\d\d$/,message:"INVALID_DATE_US_SHORT_BETWEEN",type:"conditionalDate"};break;case"dateUsShortMax":case"date_us_short_max":case"maxDateUsShort":case"max_date_us_short":r={condition:"<=",dateType:"US_SHORT",params:[n],pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.]\d\d$/,message:"INVALID_DATE_US_SHORT_MAX",type:"conditionalDate"};break;case"dateUsShortMin":case"date_us_short_min":case"minDateUsShort":case"min_date_us_short":r={condition:">=",dateType:"US_SHORT",params:[n],pattern:/^(0[1-9]|1[012])[-\/\.](0[1-9]|[12][0-9]|3[01])[-\/\.]\d\d$/,message:"INVALID_DATE_US_SHORT_MIN",type:"conditionalDate"};break;case"different":case"differentInput":case"different_input":var e=n.split(",");r={condition:"!=",message:"INVALID_INPUT_DIFFERENT",params:e,type:"matching"};break;case"digits":r={pattern:"^\\d{"+n+"}$",message:"INVALID_DIGITS",params:[n],type:"regex"};break;case"digitsBetween":case"digits_between":var _=n.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: digits_between:1,5";r={pattern:"^\\d{"+_[0]+","+_[1]+"}$",message:"INVALID_DIGITS_BETWEEN",params:[_[0],_[1]],type:"regex"};break;case"email":r={pattern:/^[-\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9#~!$%^&*_=+\/`\|}{\'?]+(\.[-\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9#~!$%^&*_=+\/`\|}{\'?]+)*@([\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9_][-\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9_]*(\.[-\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9_]+)*([\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ]+)|(\.[\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i,message:"INVALID_EMAIL",type:"regex"};break;case"exactLen":case"exact_len":r={pattern:"^(.|[\\r\\n]){"+n+"}$",message:"INVALID_EXACT_LEN",params:[n],type:"regex"};break;case"float":r={pattern:/^\d*\.{1}\d+$/,message:"INVALID_FLOAT",type:"regex"};break;case"floatSigned":case"float_signed":r={pattern:/^[-+]?\d*\.{1}\d+$/,message:"INVALID_FLOAT_SIGNED",type:"regex"};break;case"iban":r={pattern:/^[a-zA-Z]{2}\d{2}\s?([0-9a-zA-Z]{4}\s?){4}[0-9a-zA-Z]{2}$/i,message:"INVALID_IBAN",type:"regex"};break;case"in":case"inList":case"in_list":var c=RegExp().escape(n).replace(/,/g,"|");r={pattern:"^("+c+")$",patternFlag:"i",message:"INVALID_IN_LIST",params:[n],type:"regex"};break;case"int":case"integer":r={pattern:/^\d+$/,message:"INVALID_INTEGER",type:"regex"};break;case"intSigned":case"integerSigned":case"int_signed":case"integer_signed":r={pattern:/^[+-]?\d+$/,message:"INVALID_INTEGER_SIGNED",type:"regex"};break;case"ip":case"ipv4":r={pattern:/^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$/,message:"INVALID_IPV4",type:"regex"};break;case"ipv6":r={pattern:/^(::|(([a-fA-F0-9]{1,4}):){7}(([a-fA-F0-9]{1,4}))|(:(:([a-fA-F0-9]{1,4})){1,6})|((([a-fA-F0-9]{1,4}):){1,6}:)|((([a-fA-F0-9]{1,4}):)(:([a-fA-F0-9]{1,4})){1,6})|((([a-fA-F0-9]{1,4}):){2}(:([a-fA-F0-9]{1,4})){1,5})|((([a-fA-F0-9]{1,4}):){3}(:([a-fA-F0-9]{1,4})){1,4})|((([a-fA-F0-9]{1,4}):){4}(:([a-fA-F0-9]{1,4})){1,3})|((([a-fA-F0-9]{1,4}):){5}(:([a-fA-F0-9]{1,4})){1,2}))$/i,message:"INVALID_IPV6",type:"regex"};break;case"match":case"matchInput":case"match_input":case"same":var e=n.split(",");r={condition:"===",message:"INVALID_INPUT_MATCH",params:e,type:"matching"};break;case"max":r={patternLength:"^(.|[\\r\\n]){0,"+n+"}$",messageLength:"INVALID_MAX_CHAR",conditionNum:"<=",messageNum:"INVALID_MAX_NUM",params:[n],type:"autoDetect"};break;case"maxLen":case"max_len":r={pattern:"^(.|[\\r\\n]){0,"+n+"}$",message:"INVALID_MAX_CHAR",params:[n],type:"regex"};break;case"maxNum":case"max_num":r={condition:"<=",message:"INVALID_MAX_NUM",params:[n],type:"conditionalNumber"};break;case"min":r={patternLength:"^(.|[\\r\\n]){"+n+",}$",messageLength:"INVALID_MIN_CHAR",conditionNum:">=",messageNum:"INVALID_MIN_NUM",params:[n],type:"autoDetect"};break;case"minLen":case"min_len":r={pattern:"^(.|[\\r\\n]){"+n+",}$",message:"INVALID_MIN_CHAR",params:[n],type:"regex"};break;case"minNum":case"min_num":r={condition:">=",message:"INVALID_MIN_NUM",params:[n],type:"conditionalNumber"};break;case"notIn":case"not_in":case"notInList":case"not_in_list":var c=RegExp().escape(n).replace(/,/g,"|");r={pattern:"^((?!("+c+")).)+$",patternFlag:"i",message:"INVALID_NOT_IN_LIST",params:[n],type:"regex"};break;case"numeric":r={pattern:/^\d*\.?\d+$/,message:"INVALID_NUMERIC",type:"regex"};break;case"numericSigned":case"numeric_signed":r={pattern:/^[-+]?\d*\.?\d+$/,message:"INVALID_NUMERIC_SIGNED",type:"regex"};break;case"pattern":case"regex":r={pattern:t.pattern,message:"INVALID_PATTERN",params:[t.message],type:"regex"};break;case"remote":r={message:"",params:[n],type:"remote"};break;case"required":r={pattern:/\S+/,message:"INVALID_REQUIRED",type:"regex"};break;case"size":r={patternLength:"^(.|[\\r\\n]){"+n+"}$",messageLength:"INVALID_EXACT_LEN",conditionNum:"==",messageNum:"INVALID_EXACT_NUM",params:[n],type:"autoDetect"};break;case"url":r={pattern:/^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?/i,message:"INVALID_URL",type:"regex"};break;case"time":r={pattern:/^([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$/,message:"INVALID_TIME",type:"regex"}}return r.altText=a,r}var a={getElementValidators:e};return a}]),RegExp.prototype.escape=function(e){if(!arguments.callee.sRE){var a=["/",".","*","+","?","|","(",")","[","]","{","}","\\"];arguments.callee.sRE=new RegExp("(\\"+a.join("|\\")+")","g")}return e.replace(arguments.callee.sRE,"\\$1")};
+angular.module("ghiscoding.validation").service("validationService",["$interpolate","$q","$timeout","validationCommon",function(e,o,t,a){function n(o,t,a){var n=this,i={};if("string"==typeof o&&"string"==typeof t?(i.elmName=o,i.rules=t,i.friendlyName="string"==typeof a?a:""):i=o,"object"!=typeof i||!i.hasOwnProperty("elmName")||!i.hasOwnProperty("rules")||!i.hasOwnProperty("scope")&&"undefined"==typeof n.validationAttrs.scope)throw"Angular-Validation-Service requires at least the following 3 attributes: {elmName, rules, scope}";var l=i.scope?i.scope:n.validationAttrs.scope;if(i.elm=angular.element(document.querySelector('[name="'+i.elmName+'"]')),"object"!=typeof i.elm||0===i.elm.length)return n;if(new RegExp("{{(.*?)}}").test(i.elmName)&&(i.elmName=e(i.elmName)(l)),i.name=i.elmName,n.validationAttrs.isolatedScope){var m=l.$validationOptions||null;l=n.validationAttrs.isolatedScope,m&&(l.$validationOptions=m)}return $=n.validationAttrs.hasOwnProperty("validationCallback")?n.validationAttrs.validationCallback:null,g=n.validationAttrs.hasOwnProperty("validateOnEmpty")?commonObj.parseBool(n.validationAttrs.validateOnEmpty):!!V.validateOnEmpty,i.elm.bind("blur",j=function(e){var o=n.commonObj.getFormElementByName(i.elmName);if(o&&!o.isValidationCancelled){n.commonObj.initialize(l,i.elm,i,i.ctrl);var t=s(n,e.target.value,0);$&&n.commonObj.runValidationCallbackOnPromise(t,$)}}),i=n.commonObj.mergeObjects(n.validationAttrs,i),O(n,l,i),i.elm.on("$destroy",function(){var e=n.commonObj.getFormElementByName(n.commonObj.ctrl.$name);e&&(u(n,e),n.commonObj.removeFromValidationSummary(i.name))}),h.push({elmName:i.elmName,watcherHandler:f(l,i,n)}),n}function i(e){var o=this,t="",a=!0;if("undefined"==typeof e||"undefined"==typeof e.$validationSummary)throw"checkFormValidity() requires a valid Angular Form or $scope/vm object passed as argument to work properly, for example:: fn($scope) OR fn($scope.form1) OR fn(vm) OR fn(vm.form1)";for(var n=0,i=e.$validationSummary.length;i>n;n++)if(a=!1,t=e.$validationSummary[n].field){var l=o.commonObj.getFormElementByName(t);l&&l.elm&&l.elm.length>0&&("function"==typeof l.ctrl.$setTouched&&l.ctrl.$setTouched(),o.commonObj.updateErrorMsg(e.$validationSummary[n].message,{isSubmitted:!0,isValid:l.isValid,obj:l}))}return a}function l(e){var o=this;if("undefined"==typeof e||"undefined"==typeof e.$validationSummary)throw"clearInvalidValidatorsInSummary() requires a valid Angular Form or $scope/vm object passed as argument to work properly, for example:: fn($scope) OR fn($scope.form1) OR fn(vm) OR fn(vm.form1)";for(var t=[],a=0,n=e.$validationSummary.length;n>a;a++)t.push(e.$validationSummary[a].field);for(a=0,n=t.length;n>a;a++)t[a]&&(o.commonObj.removeFromFormElementObjectList(t[a]),o.commonObj.removeFromValidationSummary(t[a],e.$validationSummary))}function m(e,o){var t,a=this;if("undefined"==typeof e||"undefined"==typeof e.$validationSummary)throw"removeValidator() only works with Validation that were defined by the Service (not by the Directive) and requires a valid Angular Form or $scope/vm object passed as argument to work properly, for example:: fn($scope) OR fn($scope.form1) OR fn(vm) OR fn(vm.form1)";if(o instanceof Array)for(var n=0,i=o.length;i>n;n++)t=a.commonObj.getFormElementByName(o[n]),t.elm.removeAttr("validation"),b(a,t,e.$validationSummary);else o instanceof Object&&o.formElmObj?(t=o.formElmObj,t.elm.removeAttr("validation"),b(o.self,t,e.$validationSummary)):(t=a.commonObj.getFormElementByName(o),t.elm.removeAttr("validation"),b(a,t,e.$validationSummary));return a}function r(e,o){var t,a=this,o=o||{},n="undefined"!=typeof o.removeAllValidators?o.removeAllValidators:!1,i="undefined"!=typeof o.emptyAllInputValues?o.emptyAllInputValues:!1;if("undefined"==typeof e||"undefined"==typeof e.$name)throw"resetForm() requires a valid Angular Form object passed as argument to work properly (ex.: $scope.form1).";var l=a.commonObj.getFormElements(e.$name);if(l instanceof Array)for(var r=0,d=l.length;d>r;r++)t=l[r],i&&t.elm.val(null),n?m(e,{self:a,formElmObj:t}):("function"==typeof t.ctrl.$setUntouched&&t.ctrl.$setUntouched(),t.ctrl.$setPristine(),a.commonObj.updateErrorMsg("",{isValid:!1,obj:t}))}function d(e){var o=this,t="boolean"==typeof e?e:!0;o.commonObj.setDisplayOnlyLastErrorMsg(t)}function c(e){var o=this;return o.validationAttrs=e,o.commonObj.setGlobalOptions(e),o}function s(e,a,n){var i=o.defer(),l=!1,m="undefined"!=typeof n?n:e.commonObj.typingLimit,r=e.commonObj.getFormElementByName(e.commonObj.ctrl.$name);return a&&a.badInput?v(e,attrs.name):(e.commonObj.validate(a,!1),e.commonObj.isFieldRequired()||g||""!==a&&null!==a&&"undefined"!=typeof a?(r.isValidationCancelled=!1,(a||e.commonObj.isFieldRequired()||g)&&e.commonObj.ctrl.$setValidity("validation",!1),""!==a&&"undefined"!=typeof a||"NUMBER"!==e.commonObj.elm.prop("type").toUpperCase()?"SELECT"===e.commonObj.elm.prop("tagName").toUpperCase()?(l=e.commonObj.validate(a,!0),e.commonObj.ctrl.$setValidity("validation",l),i.resolve({isFieldValid:l,formElmObj:r,value:a}),i.promise):("undefined"!=typeof a&&(0===n?(l=e.commonObj.validate(a,!0),e.commonObj.scope.$evalAsync(e.commonObj.ctrl.$setValidity("validation",l)),i.resolve({isFieldValid:l,formElmObj:r,value:a}),t.cancel(e.timer)):(e.commonObj.updateErrorMsg(""),t.cancel(e.timer),e.timer=t(function(){l=e.commonObj.validate(a,!0),e.commonObj.scope.$evalAsync(e.commonObj.ctrl.$setValidity("validation",l)),i.resolve({isFieldValid:l,formElmObj:r,value:a})},m))),i.promise):(t.cancel(e.timer),l=e.commonObj.validate(a,!0),i.resolve({isFieldValid:l,formElmObj:r,value:a}),i.promise)):(u(e,r),i.resolve({isFieldValid:!0,formElmObj:r,value:a}),i.promise))}function u(e,o){var a=o&&o.ctrl?o.ctrl:e.commonObj.ctrl;o&&(o.isValidationCancelled=!0),t.cancel(self.timer),a.$setValidity("validation",!0),e.commonObj.updateErrorMsg("",{isValid:!0,obj:o}),y(e,o)}function f(e,o,a){return e.$watch(function(){return o.ctrl=angular.element(o.elm).controller("ngModel"),p(a,o.elmName)?{badInput:!0}:o.ctrl.$modelValue},function(n,i){if(n&&n.badInput){var l=a.commonObj.getFormElementByName(o.elmName);return y(a,l),v(a,o.name)}if(void 0===n&&void 0!==i&&!isNaN(i))return t.cancel(a.timer),void a.commonObj.ctrl.$setValidity("validation",a.commonObj.validate("",!0));o.ctrl=angular.element(o.elm).controller("ngModel"),o.value=n,a.commonObj.initialize(e,o.elm,o,o.ctrl);var m="undefined"==typeof n||"number"==typeof n&&isNaN(n)?0:void 0,r=s(a,n,m);$&&a.commonObj.runValidationCallbackOnPromise(r,$)},!0)}function v(e,o){t.cancel(e.timer);var a=e.commonObj.getFormElementByName(o);e.commonObj.updateErrorMsg("INVALID_KEY_CHAR",{isValid:!1,translate:!0,obj:a}),e.commonObj.addToValidationSummary(a,"INVALID_KEY_CHAR",!0)}function p(e,o){var t=e.commonObj.getFormElementByName(o);return!!t&&!!t.elm.prop("validity")&&t.elm.prop("validity").badInput===!0}function b(e,o,t){var a=e.commonObj.scope?e.commonObj.scope:o.scope?o.scope:null;if("undefined"==typeof a)throw"removeValidator() requires a valid $scope object passed but unfortunately could not find it.";var n=e.commonObj.arrayFindObject(h,"elmName",o.fieldName);n&&(n.watcherHandler(),h.shift()),o.isValidationCancelled=!0,o.isValid=!0,o.attrs.validation="",u(e,o),"function"==typeof o.ctrl.$setUntouched&&o.ctrl.$setUntouched(),e.commonObj.scope=a,o.ctrl.$setPristine(),e.commonObj.removeFromValidationSummary(o.fieldName,t)}function y(e,o){if(o.isValidationCancelled=!0,"function"==typeof j){var t=o&&o.elm?o.elm:e.commonObj.elm;t.unbind("blur",j)}}function O(e,o,a){o.$watch(function(){return"undefined"==typeof a.elm.attr("ng-disabled")?null:o.$eval(a.elm.attr("ng-disabled"))},function(n){if("undefined"==typeof n||null===n)return null;a.ctrl=angular.element(a.elm).controller("ngModel"),e.commonObj.initialize(o,a.elm,a,a.ctrl);var i=e.commonObj.getFormElementByName(a.name);t(function(){if(n)a.ctrl.$setValidity("validation",!0),e.commonObj.updateErrorMsg("",{isValid:!0,obj:i}),e.commonObj.removeFromValidationSummary(a.name);else{var t=a.ctrl.$viewValue||"";e.commonObj.initialize(o,a.elm,a,a.ctrl),a.ctrl.$setValidity("validation",e.commonObj.validate(t,!1)),i&&(i.isValidationCancelled=!1),a.elm.bind("blur",j=function(o){if(i&&!i.isValidationCancelled){var t=s(e,o.target.value,10);$&&e.commonObj.runValidationCallbackOnPromise(t,$)}})}},0,!1),n&&("function"==typeof a.ctrl.$setUntouched&&a.ctrl.$setUntouched(),a.ctrl.$setValidity("validation",!0),e.commonObj.removeFromValidationSummary(a.name))})}var j,g,$,V,h=[],E=function(e){this.isValidationCancelled=!1,this.timer=null,this.validationAttrs={},this.commonObj=new a,e&&this.setGlobalOptions(e),V=this.commonObj.getGlobalOptions()};return E.prototype.addValidator=n,E.prototype.checkFormValidity=i,E.prototype.removeValidator=m,E.prototype.resetForm=r,E.prototype.setDisplayOnlyLastErrorMsg=d,E.prototype.setGlobalOptions=c,E.prototype.clearInvalidValidatorsInSummary=l,E}]);
\ No newline at end of file
diff --git a/more-examples/customValidationOnEmptyField/app.js b/more-examples/customValidationOnEmptyField/app.js
new file mode 100644
index 0000000..554b30c
--- /dev/null
+++ b/more-examples/customValidationOnEmptyField/app.js
@@ -0,0 +1,101 @@
+'use strict';
+
+var myApp = angular.module('emptyCustomValidation', ['ghiscoding.validation', 'pascalprecht.translate',
+ 'emptyCustomValidation.controllers']);
+// --
+// configuration
+myApp.config(['$compileProvider', function ($compileProvider) {
+ $compileProvider.debugInfoEnabled(false);
+ }])
+ .config(['$translateProvider', function ($translateProvider) {
+ $translateProvider.useStaticFilesLoader({
+ prefix: '../../locales/validation/',
+ suffix: '.json'
+ });
+ // load English ('en') table on startup
+ $translateProvider.preferredLanguage('en').fallbackLanguage('en');
+ $translateProvider.useSanitizeValueStrategy('escapeParameters');
+ }]);
+
+
+myApp.run(function ($rootScope) {
+ $rootScope.$validationOptions = { debounce: 0 };
+});
+
+angular.module('emptyCustomValidation.controllers', []).
+controller('myController', function($scope, validationService) {
+ $scope.existingEmployees = [
+ {
+ firstName: 'John',
+ lastName: 'Doe',
+ id: 1
+ },
+ {
+ firstName: 'Jane',
+ lastName: 'Doe',
+ id: 2
+ }];
+ $scope.newEmployees = [
+ {firstName : '', lastName: '', id : -1},
+ {firstName : '', lastName: '', id : -2},
+ {firstName : '', lastName: '', id : -3},
+ {firstName : '', lastName: '', id : -4},
+ {firstName : '', lastName: '', id : -5}
+ ];
+
+ $scope.submit = function() {
+ if (!new validationService().checkFormValidity($scope.inputForm)) {
+ var msg = '';
+ $scope.inputForm.$validationSummary.forEach(function (validationItem) {
+ msg += validationItem.message + '\n';
+ });
+ alert(msg);
+ return;
+ }
+ alert('Data saved successfully.');
+ };
+
+ function employeeHasData(employee)
+ {
+ if ((!employee.firstName || employee.firstName === '') && (!employee.lastName || employee.lastName === ''))
+ return false;
+ return true;
+ }
+ $scope.newEmployeeFirstNameValidation = function(employee) {
+ //alert('First name validation');
+ var isValid = true;
+ var msg = '';
+ if (employeeHasData(employee) && !employee.firstName)
+ {
+ isValid = false;
+ msg = 'First name required';
+ }
+
+ // The next 4 lines are only here to show that custom validation works if text is given
+ if (isValid && employee.firstName && employee.firstName.length > 10)
+ {
+ isValid = false;
+ msg = 'Max number of characters for first name: 10'
+ }
+
+ return { isValid: isValid, message: msg };
+ };
+
+ $scope.newEmployeeLastNameValidation = function(employee) {
+ var isValid = true;
+ var msg = '';
+ if (employeeHasData(employee) && !employee.lastName)
+ {
+ isValid = false;
+ msg = 'Last name required';
+ }
+
+ // The next 4 lines are only here to show that custom validation works if text is given
+ if (isValid && employee.lastName && employee.lastName.length > 8)
+ {
+ isValid = false;
+ msg = 'Max number of characters for last name: 8'
+ }
+ return { isValid: isValid, message: msg };
+ };
+});
\ No newline at end of file
diff --git a/more-examples/customValidationOnEmptyField/index.html b/more-examples/customValidationOnEmptyField/index.html
new file mode 100644
index 0000000..22543a3
--- /dev/null
+++ b/more-examples/customValidationOnEmptyField/index.html
@@ -0,0 +1,80 @@
+
+
+
+
+ Angular-Validation with Custom Javascript function
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/more-examples/validRequireHowMany/app.js b/more-examples/validRequireHowMany/app.js
new file mode 100644
index 0000000..7c1450a
--- /dev/null
+++ b/more-examples/validRequireHowMany/app.js
@@ -0,0 +1,56 @@
+'use strict';
+
+var myApp = angular.module('myApp', ['ghiscoding.validation', 'pascalprecht.translate', 'ui.bootstrap']);
+// --
+// configuration
+myApp.config(['$compileProvider', function ($compileProvider) {
+ $compileProvider.debugInfoEnabled(false);
+ }])
+ .config(['$translateProvider', function ($translateProvider) {
+ $translateProvider.useStaticFilesLoader({
+ prefix: '../../locales/validation/',
+ suffix: '.json'
+ });
+ // load English ('en') table on startup
+ $translateProvider.preferredLanguage('en').fallbackLanguage('en');
+ $translateProvider.useSanitizeValueStrategy('escapeParameters');
+ }]);
+
+// --
+// Directive
+myApp.controller('CtrlDirective', ['validationService', function (validationService) {
+ var vmd = this;
+ vmd.model = {};
+
+ // use the validationService only to declare the controllerAs syntax
+ var vs = new validationService({ controllerAs: vmd });
+
+ vmd.submitForm = function() {
+ if(vs.checkFormValidity(vmd.form1)) {
+ alert('All good, proceed with submit...');
+ }
+ }
+}]);
+
+// --
+// Service
+myApp.controller('CtrlService', ['$scope', 'validationService', function ($scope, validationService) {
+ var vms = this;
+ vms.model = {};
+
+ // use the validationService only to declare the controllerAs syntax
+ var vs = new validationService({ controllerAs: vms });
+
+ vs.addValidator({
+ elmName: 'input2',
+ validRequireHowMany: 2,
+ scope: $scope,
+ rules: 'ipv4|ipv6|required'
+ });
+
+ vms.submitForm = function() {
+ if(new validationService().checkFormValidity(vms.form2)) {
+ alert('All good, proceed with submit...');
+ }
+ }
+}]);
diff --git a/more-examples/validRequireHowMany/index.html b/more-examples/validRequireHowMany/index.html
new file mode 100644
index 0000000..5156b80
--- /dev/null
+++ b/more-examples/validRequireHowMany/index.html
@@ -0,0 +1,96 @@
+
+
+
+
+ Angular-Validation with ValidRequireHowMany
+
+
+
+
+
+
+
Angular-Validation with ValidRequireHowMany
+
+
+
Directive
+
+
+
ERRORS!
+
+
{{ item.field }}: {{item.message}}
+
+
+
+
+
+
+
+
+
+
Service
+
+
+
ERRORS!
+
+
{{ item.field }}: {{item.message}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
index 329c542..c3f34bc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "angular-validation-ghiscoding",
- "version": "1.4.17",
+ "version": "1.4.18",
"author": "Ghislain B.",
"description": "Angular-Validation Directive and Service (ghiscoding)",
"main": "app.js",
diff --git a/protractor/conf.js b/protractor/conf.js
index 5e1be7d..63a3860 100644
--- a/protractor/conf.js
+++ b/protractor/conf.js
@@ -32,6 +32,7 @@
'interpolate_spec.js',
'ngIfDestroy_spec.js',
'thirdParty_spec.js',
+ 'validRequireHowMany_spec.js',
'full_tests_spec.js'
],
jasmineNodeOpts: {
diff --git a/protractor/full_tests_spec.js b/protractor/full_tests_spec.js
index acd6155..762a185 100644
--- a/protractor/full_tests_spec.js
+++ b/protractor/full_tests_spec.js
@@ -156,7 +156,7 @@ function loadData() {
{
'validator': 'alpha',
'invalid_data': ['abc-def', 'abc def', '@', '#', '123', '{|\\}'],
- 'valid_data': ['abcdefghijklmnopqrstuvwxyz', 'ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝ', 'àáâãäåçèéêëìíîïðòóôõöùúûüýÿ'],
+ 'valid_data': ['abcdefghijklmnopqrstuvwxyz', 'ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝ', 'ążźćśłńęàáâãäåçèéêëìíîïðòóôõöùúûüýÿ'],
'error_message': {
'en': 'May only contain letters.',
'es': 'Unicamente puede contener letras.',
@@ -169,7 +169,7 @@ function loadData() {
'validator': 'alphaSpaces',
'aliases': ['alpha_spaces'],
'invalid_data': ['abc-def', 'abc(def)', '@', '#', '123', '{|\\}'],
- 'valid_data': ['abcdefghijklmnopqrstuvwxyz', 'ÀÁÂÃÄÅ ÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝ', 'àáâãäå çèéêëìíîïðòóôõöùúûüýÿ'],
+ 'valid_data': ['abcdefghijklmnopqrstuvwxyz', 'ÀÁÂÃÄÅ ÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝ', 'ążźćśłńęàáâãäå çèéêëìíîïðòóôõöùúûüýÿ'],
'error_message': {
'en': 'May only contain letters and spaces.',
'es': 'Unicamente puede contener letras y espacios.',
@@ -182,7 +182,7 @@ function loadData() {
'validator': 'alphaNum',
'aliases': ['alpha_num'],
'invalid_data': ['abc-def', 'abc(def)', '@', '#', '{|\\}'],
- 'valid_data': ['1234567890', 'abcdefghijklmnopqrstuvwxyz', 'ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝ', 'àáâãäåçèéêëìíîïðòóôõöùúûüýÿ'],
+ 'valid_data': ['1234567890', 'abcdefghijklmnopqrstuvwxyz', 'ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝ', 'ążźćśłńęàáâãäåçèéêëìíîïðòóôõöùúûüýÿ'],
'error_message': {
'en': 'May only contain letters and numbers.',
'es': 'Unicamente puede contener letras y números.',
@@ -195,7 +195,7 @@ function loadData() {
'validator': 'alphaNumSpaces',
'aliases': ['alpha_num_spaces'],
'invalid_data': ['abc-def', 'abc(def)', '@', '#'],
- 'valid_data': ['1234567890', 'abcdefghijkl mnopqrstuvwxyz', 'ÀÁÂÃÄÅ ÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝ', 'àáâãäå çèéêëìíîïðòóôõöùúûüýÿ'],
+ 'valid_data': ['1234567890', 'abcdefghijkl mnopqrstuvwxyz', 'ÀÁÂÃÄÅ ÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝ', 'ążźćśłńęàáâãäå çèéêëìíîïðòóôõöùúûüýÿ'],
'error_message': {
'en': 'May only contain letters, numbers and spaces.',
'es': 'Unicamente puede contener letras, números y espacios.',
@@ -208,7 +208,7 @@ function loadData() {
'validator': 'alphaDash',
'aliases': ['alpha_dash'],
'invalid_data': ['abc(def)', '@', '#', '{|\\}'],
- 'valid_data': ['1234567890', 'abcdefg-hijklmnopqrstuvwxyz', 'ÀÁÂÃÄÅ--ÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝ', 'àáâãäåçèéêëìíîïðòóôõöùúûüýÿ'],
+ 'valid_data': ['1234567890', 'abcdefg-hijklmnopqrstuvwxyz', 'ÀÁÂÃÄÅ--ÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝ', 'ążźćśłńęàáâãäåçèéêëìíîïðòóôõöùúûüýÿ'],
'error_message': {
'en': "May only contain letters, numbers and dashes.",
'es': "Unicamente puede contener letras, números y guiones.",
@@ -221,7 +221,7 @@ function loadData() {
'validator': 'alphaDashSpaces',
'aliases': ['alpha_dash_spaces'],
'invalid_data': ['abc(def)', '@', '#', '{|\\}'],
- 'valid_data': ['123456-7890', 'abcdefg-hijklmn opqrstuvwxyz', 'ÀÁÂÃÄÅ--ÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝ', 'àáâãäå çèéêëìíîïðòóôõöùúûüýÿ'],
+ 'valid_data': ['123456-7890', 'abcdefg-hijklmn opqrstuvwxyz', 'ÀÁÂÃÄÅ--ÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝ', 'ążźćśłńęàáâãäå çèéêëìíîïðòóôõöùúûüýÿ'],
'error_message': {
'en': "May only contain letters, numbers, dashes and spaces.",
'es': "Unicamente puede contener letras, números, guiones y espacios.",
@@ -589,7 +589,7 @@ function loadData() {
{
'validator': 'email',
'invalid_data': ['g$g.com', 'g@g,com', '.my@email.com.', 'some space@hotmail.com'],
- 'valid_data': ['nickname@domain', 'other.email-with-dash@some-company.com', 'кокер@спаниель.рф', 'hola.àáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿ@español.com'],
+ 'valid_data': ['nickname@domain', 'other.email-with-dash@some-company.com', 'кокер@спаниель.рф', 'hola.ążźćśłńęàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿ@español.com'],
'error_message': {
'en': "Must be a valid email address.",
'es': "Debe contener una dirección de correo electronico valida.",
@@ -705,7 +705,7 @@ function loadData() {
{
'validator': 'ipv6',
'invalid_data': ['127.0.0.1', '255.255.255.0', '1762:0:0:0:0:B03:1'],
- 'valid_data': ['1762:0:0:0:0:B03:1:AF18', '2001:0db8:0100:f101:0210:a4ff:fee3:9566'],
+ 'valid_data': ['2002:4559:1FE2::4559:1FE2', '2002:4559:1FE2:0:0:0:4559:1FE2', '2002:4559:1FE2:0000:0000:0000:4559:1FE2'],
'error_message': {
'en': "Must be a valid IP (IPV6).",
'es': "Debe contener una dirección IP valida (IPV6).",
diff --git a/protractor/interpolate_spec.js b/protractor/interpolate_spec.js
index 5cf2930..dd859ba 100644
--- a/protractor/interpolate_spec.js
+++ b/protractor/interpolate_spec.js
@@ -38,5 +38,40 @@
var itemRows = element.all(by.repeater('item in vm.test.$validationSummary'));
expect(itemRows.count()).toBe(0);
});
+
+ it('Should empty the field "if1" and show back the error on field & summary', function() {
+ var elmInput = $('[name=if1]');
+ clearInput(elmInput);
+
+ // validation summary should become empty
+ var firstError = element.all(by.repeater('item in vm.test.$validationSummary')).get(0);
+ expect(firstError.getText()).toEqual('if1: Field is required.');
+ });
+
+ it('Should click on toggle checkbox to inverse validation', function () {
+ var elmToggle = $('[name=toggle]');
+ elmToggle.click();
+ browser.waitForAngular();
+ });
+
+ it('Should empty the field "f1" and show back the error on field & summary', function() {
+ var elmInput = $('[name=f1]');
+ clearInput(elmInput);
+
+ // validation summary should become empty
+ var firstError = element.all(by.repeater('item in vm.test.$validationSummary')).get(0);
+ expect(firstError.getText()).toEqual('f1: Field is required.');
+ });
});
-});
\ No newline at end of file
+});
+
+/** From a given input name, clear the input
+ * @param string input name
+ */
+function clearInput(elem) {
+ elem.getAttribute('value').then(function (text) {
+ var len = text.length
+ var backspaceSeries = Array(len+1).join(protractor.Key.BACK_SPACE);
+ elem.sendKeys(backspaceSeries);
+ })
+}
\ No newline at end of file
diff --git a/protractor/validRequireHowMany_spec.js b/protractor/validRequireHowMany_spec.js
new file mode 100644
index 0000000..f272a75
--- /dev/null
+++ b/protractor/validRequireHowMany_spec.js
@@ -0,0 +1,126 @@
+describe('Angular-Validation ValidRequireHowMany Validation Tests:', function () {
+ // global variables
+ var formElementNames = ['input1', 'input2'];
+ var errorMessageWithRequired = 'Must be a valid IP (IPV4). Must be a valid IP (IPV6). Field is required.';
+ var errorMessageWithoutRequired = 'Must be a valid IP (IPV4). Must be a valid IP (IPV6).';
+ var invalidInputTexts = ['192.168.10.10.', '1762:0:0:0:0:B03:1'];
+ var validInputTexts = ['192.168.10.10', '2002:4559:1FE2::4559:1FE2'];
+ var title = 'Angular-Validation with ValidRequireHowMany';
+ var url = 'http://localhost/Github/angular-validation/more-examples/validRequireHowMany/';
+
+ describe('When choosing `more-examples` validRequireHowMany', function () {
+ it('Should navigate to home page', function () {
+ browser.get(url);
+
+ // Find the title element
+ var titleElement = element(by.css('h2'));
+ expect(titleElement.getText()).toEqual(title);
+ });
+
+ it('Should have multiple errors in Directive & Service validation summary', function () {
+ var itemRows = element.all(by.binding('message'));
+ var inputName;
+
+ for (var i = 0, j = 0, ln = itemRows.length; i < ln; i++) {
+ expect(itemRows.get(i).getText()).toEqual(errorMessageWithRequired);
+ }
+ });
+
+ it('Should check that both submit buttons are disabled', function() {
+ var elmSubmit1 = $('[name=btn_ngDisabled1]');
+ expect(elmSubmit1.isEnabled()).toBe(false);
+
+ var elmSubmit2 = $('[name=btn_ngDisabled2]');
+ expect(elmSubmit2.isEnabled()).toBe(false);
+ });
+
+ it('Should click, blur on each form elements and error message should display on each of them', function () {
+ for (var i = 0, ln = formElementNames.length; i < ln; i++) {
+ var elmInput = $('[name=' + formElementNames[i] + ']');
+ elmInput.click();
+ elmInput.sendKeys(protractor.Key.TAB);
+
+ var elmError = $('.validation-' + formElementNames[i]);
+ expect(elmError.getText()).toEqual(errorMessageWithRequired);
+ }
+ });
+
+ it('Should enter invalid IP and display error message without required', function() {
+ for (var i = 0, ln = formElementNames.length; i < ln; i++) {
+ var elmInput = $('[name=' + formElementNames[i] + ']');
+ elmInput.click();
+ clearInput(elmInput);
+ elmInput.sendKeys(invalidInputTexts[i]);
+ elmInput.sendKeys(protractor.Key.TAB);
+
+ var elmError = $('.validation-' + formElementNames[i]);
+ expect(elmError.getText()).toEqual(errorMessageWithoutRequired);
+ }
+ });
+
+ it('Should enter valid text and make error go away', function () {
+ for (var i = 0, ln = formElementNames.length; i < ln; i++) {
+ var elmInput = $('[name=' + formElementNames[i] + ']');
+ elmInput.click();
+ clearInput(elmInput);
+ elmInput.sendKeys(validInputTexts[i]);
+ elmInput.sendKeys(protractor.Key.TAB);
+
+ var elmError = $('.validation-' + formElementNames[i]);
+ expect(elmError.getText()).toEqual('');
+ }
+ });
+
+ it('Should have both validation summary empty', function() {
+ var itemRows = element.all(by.binding('message'));
+ expect(itemRows.count()).toBe(0);
+ });
+
+ it('Should check that both submit buttons are now enabled', function() {
+ var elmSubmit1 = $('[name=btn_ngDisabled1]');
+ expect(elmSubmit1.isEnabled()).toBe(true);
+
+ var elmSubmit2 = $('[name=btn_ngDisabled2]');
+ expect(elmSubmit2.isEnabled()).toBe(true);
+ });
+
+ it('Should navigate to home page', function () {
+ browser.get(url);
+
+ // Find the title element
+ var titleElement = element(by.css('h2'));
+ expect(titleElement.getText()).toEqual(title);
+ });
+
+ it('Should click on both ngSubmit buttons', function() {
+ var btnNgSubmit1 = $('[name=btn_ngSubmit1]');
+ btnNgSubmit1.click();
+
+ var btnNgSubmit2 = $('[name=btn_ngSubmit2]');
+ btnNgSubmit2.click();
+ });
+
+ it('Should show error message on each inputs', function () {
+ for (var i = 0, ln = formElementNames.length; i < ln; i++) {
+ var elmInput = $('[name=' + formElementNames[i] + ']');
+ elmInput.click();
+ elmInput.sendKeys(protractor.Key.TAB);
+
+ var elmError = $('.validation-' + formElementNames[i]);
+ expect(elmError.getText()).toEqual(errorMessageWithRequired);
+ }
+ });
+
+ });
+});
+
+/** From a given input name, clear the input
+ * @param string input name
+ */
+function clearInput(elem) {
+ elem.getAttribute('value').then(function (text) {
+ var len = text.length
+ var backspaceSeries = Array(len+1).join(protractor.Key.BACK_SPACE);
+ elem.sendKeys(backspaceSeries);
+ })
+}
\ No newline at end of file
diff --git a/readme.md b/readme.md
index 97d5860..0e8bed2 100644
--- a/readme.md
+++ b/readme.md
@@ -1,5 +1,5 @@
#Angular Validation (Directive / Service)
-`Version: 1.4.17`
+`Version: 1.4.18`
### Form validation after user stop typing (default 1sec).
Forms Validation with Angular made easy! Angular-Validation is an angular directive/service with locales (languages) with a very simple approach of defining your `validation=""` directly within your element to validate (input, textarea, etc) and...that's it!!! The directive/service will take care of the rest!
diff --git a/src/validation-common.js b/src/validation-common.js
index 24805ef..5ecf047 100644
--- a/src/validation-common.js
+++ b/src/validation-common.js
@@ -18,6 +18,7 @@ angular
};
var _remotePromises = []; // keep track of promises called and running when using the Remote validator
var _validationSummary = []; // Array Validation Error Summary
+ var _validateOnEmpty = false; // do we want to validate on empty field? False by default
// watch on route change, then reset some global variables, so that we don't carry over other controller/view validations
$rootScope.$on("$routeChangeStart", function (event, next, current) {
@@ -28,6 +29,8 @@ angular
preValidateFormElements: false, // reset the option of pre-validate all form elements, false by default
isolatedScope: null, // reset used scope on route change
scope: null, // reset used scope on route change
+ validateOnEmpty: false, // reset the flag of Validate Always
+ validRequireHowMany: "all", // how many Validators it needs to pass for the field to become valid, "all" by default
resetGlobalOptionsOnRouteChange: true
};
_formElements = []; // array containing all form elements, valid or invalid
@@ -44,6 +47,8 @@ angular
this.elm = elm;
this.ctrl = ctrl;
this.validatorAttrs = attrs;
+ this.validateOnEmpty = false; // do we want to always validate, even when field isn't required? False by default
+ this.validRequireHowMany = "all";
if(!!scope && !!scope.$validationOptions) {
_globalOptions = scope.$validationOptions; // save the global options
@@ -78,6 +83,7 @@ angular
validationCommon.prototype.isFieldRequired = isFieldRequired; // return boolean knowing if the current field is required
validationCommon.prototype.initialize = initialize; // initialize current object with passed arguments
validationCommon.prototype.mergeObjects = mergeObjects; // merge 2 javascript objects, Overwrites obj1's values with obj2's (basically Object2 as higher priority over Object1)
+ validationCommon.prototype.parseBool = parseBool; // parse a boolean value, string or bool
validationCommon.prototype.removeFromValidationSummary = removeFromValidationSummary; // remove an element from the $validationSummary
validationCommon.prototype.removeFromFormElementObjectList = removeFromFormElementObjectList; // remove named items from formElements list
validationCommon.prototype.runValidationCallbackOnPromise = runValidationCallbackOnPromise; // run a validation callback method when the promise resolve
@@ -170,15 +176,8 @@ angular
var customUserRegEx = {};
self.validators = []; // reset the global validators
- // debounce (alias of typingLimit) timeout after user stop typing and validation comes in play
- self.typingLimit = _INACTIVITY_LIMIT;
- if (self.validatorAttrs.hasOwnProperty('debounce')) {
- self.typingLimit = parseInt(self.validatorAttrs.debounce, 10);
- } else if (self.validatorAttrs.hasOwnProperty('typingLimit')) {
- self.typingLimit = parseInt(self.validatorAttrs.typingLimit, 10);
- } else if (!!_globalOptions && _globalOptions.hasOwnProperty('debounce')) {
- self.typingLimit = parseInt(_globalOptions.debounce, 10);
- }
+ // analyze the possible element attributes
+ self = analyzeElementAttributes(self);
// get the rules(or validation), inside directive it's named (validation), inside service(rules)
var rules = self.validatorAttrs.rules || self.validatorAttrs.validation;
@@ -497,6 +496,7 @@ angular
var self = this;
var isConditionValid = true;
var isFieldValid = true;
+ var nbValid = 0;
var validator;
var validatedObject = {};
@@ -558,7 +558,7 @@ angular
}
// not required and not filled is always valid & 'disabled', 'ng-disabled' elements should always be valid
- if ((!self.bFieldRequired && !strValue) || (!!self.elm.prop("disabled") || !!self.scope.$eval(elmAttrNgDisabled))) {
+ if ((!self.bFieldRequired && !strValue && !_validateOnEmpty) || (!!self.elm.prop("disabled") || !!self.scope.$eval(elmAttrNgDisabled))) {
isConditionValid = true;
}
@@ -602,6 +602,16 @@ angular
});
})(formElmObj, isConditionValid, validator);
} // if(!isConditionValid)
+
+ if(isConditionValid) {
+ nbValid++;
+ }
+
+ // when user want the field to become valid as soon as we have 1 validator passing
+ if(self.validRequireHowMany == nbValid && !!isConditionValid) {
+ isFieldValid = true;
+ break;
+ }
} // for() loop
// only log the invalid message in the $validationSummary
@@ -687,6 +697,34 @@ angular
}
}
+ /** Analyse the certain attributes that the element can have or could be passed by global options
+ * @param object self
+ * @return self
+ */
+ function analyzeElementAttributes(self) {
+ // debounce (alias of typingLimit) timeout after user stop typing and validation comes in play
+ self.typingLimit = _INACTIVITY_LIMIT;
+ if (self.validatorAttrs.hasOwnProperty('debounce')) {
+ self.typingLimit = parseInt(self.validatorAttrs.debounce, 10);
+ } else if (self.validatorAttrs.hasOwnProperty('typingLimit')) {
+ self.typingLimit = parseInt(self.validatorAttrs.typingLimit, 10);
+ } else if (!!_globalOptions && _globalOptions.hasOwnProperty('debounce')) {
+ self.typingLimit = parseInt(_globalOptions.debounce, 10);
+ }
+
+ // how many Validators it needs to pass for the field to become valid, "all" by default
+ self.validRequireHowMany = self.validatorAttrs.hasOwnProperty('validRequireHowMany')
+ ? self.validatorAttrs.validRequireHowMany
+ : _globalOptions.validRequireHowMany;
+
+ // do we want to validate on empty field? Useful on `custom` and `remote`
+ _validateOnEmpty = self.validatorAttrs.hasOwnProperty('validateOnEmpty')
+ ? parseBool(self.validatorAttrs.validateOnEmpty)
+ : _globalOptions.validateOnEmpty;
+
+ return self;
+ }
+
/** Quick function to find an object inside an array by it's given field name and value, return the object found or null
* @param Array sourceArray
* @param string searchId: search property id
@@ -819,6 +857,22 @@ angular
return sourceObject;
}
+ /** Parse a boolean value, we also want to parse on string values
+ * @param string/int value
+ * @return bool
+ */
+ function parseBool(value) {
+ if(typeof value === "boolean" || typeof value === "number") {
+ return (value === true || value === 1);
+ }
+ else if (typeof value === "string") {
+ value = value.replace(/^\s+|\s+$/g, "").toLowerCase();
+ if (value === "true" || value === "1" || value === "false" || value === "0")
+ return (value === "true" || value === "1");
+ }
+ return; // returns undefined
+ }
+
/** Parse a date from a String and return it as a Date Object to be valid for all browsers following ECMA Specs
* Date type ISO (default), US, UK, Europe, etc... Other format could be added in the switch case
* @param String dateStr: date String
@@ -1057,7 +1111,7 @@ angular
var missingErrorMsg = "Custom Javascript Validation requires an error message defined as 'alt=' in your validator or defined in your custom javascript function as { isValid: bool, message: 'your error' }"
var invalidResultErrorMsg = 'Custom Javascript Validation requires a declared function (in your Controller), please review your code.';
- if (!!strValue) {
+ if (!!strValue || !!_validateOnEmpty) {
var fct = null;
var fname = validator.params[0];
var result = runEvalScopeFunction(self, fname);
@@ -1183,7 +1237,7 @@ angular
var missingErrorMsg = "Remote Javascript Validation requires an error message defined as 'alt=' in your validator or defined in your custom remote function as { isValid: bool, message: 'your error' }"
var invalidResultErrorMsg = 'Remote Validation requires a declared function (in your Controller) which also needs to return a Promise, please review your code.';
- if (!!strValue && !!showError) {
+ if ((!!strValue && !!showError) || !!_validateOnEmpty) {
self.ctrl.$processing = true; // $processing can be use in the DOM to display a remote processing message to the user
var fct = null;
diff --git a/src/validation-directive.js b/src/validation-directive.js
index 6a66354..82d6049 100644
--- a/src/validation-directive.js
+++ b/src/validation-directive.js
@@ -23,10 +23,12 @@
var _promises = [];
var _timer;
var _watchers = [];
+ var _globalOptions = commonObj.getGlobalOptions();
// Possible element attributes
var _elmName = attrs.name;
var _validationCallback = (attrs.hasOwnProperty('validationCallback')) ? attrs.validationCallback : null;
+ var _validateOnEmpty = (attrs.hasOwnProperty('validateOnEmpty')) ? commonObj.parseBool(attrs.validateOnEmpty) : !!_globalOptions.validateOnEmpty;
//-- Possible validation-array attributes
// on a validation array, how many does it require to be valid?
@@ -40,26 +42,8 @@
cancelValidation : cancelValidation
}
- // watch the element for any value change, validate it once that happen
- var validationWatcher = scope.$watch(function() {
- if(isKeyTypedBadInput()) {
- return { badInput: true };
- }
- return ctrl.$modelValue;
- }, function(newValue, oldValue) {
- if(!!newValue && !!newValue.badInput) {
- unbindBlurHandler();
- return invalidateBadInputField();
- }
- // attempt to validate & run validation callback if user requested it
- var validationPromise = attemptToValidate(newValue);
- if(!!_validationCallback) {
- commonObj.runValidationCallbackOnPromise(validationPromise, _validationCallback);
- }
- }, true);
-
- // save the watcher inside an array in case we want to deregister it when removing a validator
- _watchers.push({ elmName: _elmName, watcherHandler: validationWatcher});
+ // create & save watcher inside an array in case we want to deregister it when removing a validator
+ _watchers.push({ elmName: _elmName, watcherHandler: createWatch() });
// watch the `disabled` attribute for changes
// if it become disabled then skip validation else it becomes enable then we need to revalidate it
@@ -92,6 +76,12 @@
// and finally revalidate & re-attach the onBlur event
commonObj.defineValidation();
revalidateAndAttachOnBlur();
+
+ // if watcher not already exist, then create & save watcher inside an array in case we want to deregister it later
+ var foundWatcher = commonObj.arrayFindObject(_watchers, 'elmName', ctrl.$name);
+ if(!foundWatcher) {
+ _watchers.push({ elmName: _elmName, watcherHandler: createWatch() });
+ }
}
});
@@ -154,7 +144,7 @@
commonObj.validate(value, false);
// if field is not required and his value is empty, cancel validation and exit out
- if(!commonObj.isFieldRequired() && (value === "" || value === null || typeof value === "undefined")) {
+ if(!commonObj.isFieldRequired() && !_validateOnEmpty && (value === "" || value === null || typeof value === "undefined")) {
cancelValidation();
deferred.resolve({ isFieldValid: true, formElmObj: formElmObj, value: value });
return deferred.promise;
@@ -163,7 +153,7 @@
}
// invalidate field before doing any validation
- if(!!value || commonObj.isFieldRequired()) {
+ if(!!value || commonObj.isFieldRequired() || _validateOnEmpty) {
ctrl.$setValidity('validation', false);
}
@@ -222,11 +212,10 @@
switch(_validArrayRequireHowMany) {
case "all" :
if(result.isFieldValid === false) {
- var globalOptions = commonObj.getGlobalOptions();
result.formElmObj.translatePromise.then(function(translation) {
// if user is requesting to see only the last error message, we will use '=' instead of usually concatenating with '+='
// then if validator rules has 'params' filled, then replace them inside the translation message (foo{0} {1}...), same syntax as String.format() in C#
- if (_arrayErrorMessage.length > 0 && globalOptions.displayOnlyLastErrorMsg) {
+ if (_arrayErrorMessage.length > 0 && _globalOptions.displayOnlyLastErrorMsg) {
_arrayErrorMessage = '[' + result.value + '] :: ' + ((!!result.formElmObj.validator && !!result.formElmObj.validator.params) ? String.format(translation, result.formElmObj.validator.params) : translation);
} else {
_arrayErrorMessage += ' [' + result.value + '] :: ' + ((!!result.formElmObj.validator && !!result.formElmObj.validator.params) ? String.format(translation, result.formElmObj.validator.params) : translation);
@@ -314,8 +303,9 @@
// deregister the $watch from the _watchers array we kept it
var foundWatcher = commonObj.arrayFindObject(_watchers, 'elmName', ctrl.$name);
- if(!!foundWatcher) {
- foundWatcher.watcherHandler(); // deregister the watch by calling his handler
+ if(!!foundWatcher && typeof foundWatcher.watcherHandler === "function") {
+ var deregister = foundWatcher.watcherHandler(); // deregister the watch by calling his handler
+ _watchers.shift();
}
}
@@ -334,6 +324,28 @@
unbindBlurHandler();
}
+ /** watch the element for any value change, validate it once that happen
+ * @return new watcher
+ */
+ function createWatch() {
+ return scope.$watch(function() {
+ if(isKeyTypedBadInput()) {
+ return { badInput: true };
+ }
+ return ctrl.$modelValue;
+ }, function(newValue, oldValue) {
+ if(!!newValue && !!newValue.badInput) {
+ unbindBlurHandler();
+ return invalidateBadInputField();
+ }
+ // attempt to validate & run validation callback if user requested it
+ var validationPromise = attemptToValidate(newValue);
+ if(!!_validationCallback) {
+ commonObj.runValidationCallbackOnPromise(validationPromise, _validationCallback);
+ }
+ }, true);
+ }
+
/** Invalidate the field that was tagged as bad input, cancel the timer validation,
* display an invalid key error and add it as well to the validation summary.
*/
diff --git a/src/validation-rules.js b/src/validation-rules.js
index 74279c0..b559747 100644
--- a/src/validation-rules.js
+++ b/src/validation-rules.js
@@ -452,7 +452,7 @@ angular
validator = {
// Email RFC 5322, pattern pulled from http://www.regular-expressions.info/email.html
// but removed necessity of a TLD (Top Level Domain) which makes this email valid: admin@mailserver1
- pattern: /^[-\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ0-9#~!$%^&*_=+\/`\|}{\'?]+(\.[-\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ0-9#~!$%^&*_=+\/`\|}{\'?]+)*@([\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ0-9_][-\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ0-9_]*(\.[-\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ0-9_]+)*([\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ]+)|(\.[\wа-яàáâãäåæçèéêëœìíïîðòóôõöøùúûñüýÿßÞďđ]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i,
+ pattern: /^[-\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9#~!$%^&*_=+\/`\|}{\'?]+(\.[-\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9#~!$%^&*_=+\/`\|}{\'?]+)*@([\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9_][-\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9_]*(\.[-\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ0-9_]+)*([\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ]+)|(\.[\wа-яàáâãäåąæçćèéêëęœìíïîłńðòóôõöøśùúûñüýÿżźßÞďđ]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i,
message: "INVALID_EMAIL",
type: "regex"
};
@@ -528,7 +528,7 @@ angular
break;
case "ipv6" :
validator = {
- pattern: /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/i,
+ pattern: /^(::|(([a-fA-F0-9]{1,4}):){7}(([a-fA-F0-9]{1,4}))|(:(:([a-fA-F0-9]{1,4})){1,6})|((([a-fA-F0-9]{1,4}):){1,6}:)|((([a-fA-F0-9]{1,4}):)(:([a-fA-F0-9]{1,4})){1,6})|((([a-fA-F0-9]{1,4}):){2}(:([a-fA-F0-9]{1,4})){1,5})|((([a-fA-F0-9]{1,4}):){3}(:([a-fA-F0-9]{1,4})){1,4})|((([a-fA-F0-9]{1,4}):){4}(:([a-fA-F0-9]{1,4})){1,3})|((([a-fA-F0-9]{1,4}):){5}(:([a-fA-F0-9]{1,4})){1,2}))$/i,
message: "INVALID_IPV6",
type: "regex"
};
diff --git a/src/validation-service.js b/src/validation-service.js
index cff88ba..22e5ba6 100644
--- a/src/validation-service.js
+++ b/src/validation-service.js
@@ -13,7 +13,9 @@ angular
// global variables of our object (start with _var)
var _blurHandler;
var _watchers = [];
+ var _validateOnEmpty;
var _validationCallback;
+ var _globalOptions;
// service constructor
var validationService = function (globalOptions) {
@@ -26,6 +28,8 @@ angular
if (!!globalOptions) {
this.setGlobalOptions(globalOptions);
}
+
+ _globalOptions = this.commonObj.getGlobalOptions();
}
// list of available published public functions of this object
@@ -92,7 +96,9 @@ angular
}
}
+ // Possible element attributes
_validationCallback = (self.validationAttrs.hasOwnProperty('validationCallback')) ? self.validationAttrs.validationCallback : null;
+ _validateOnEmpty = (self.validationAttrs.hasOwnProperty('validateOnEmpty')) ? commonObj.parseBool(self.validationAttrs.validateOnEmpty) : !!_globalOptions.validateOnEmpty;
// onBlur make validation without waiting
attrs.elm.bind('blur', _blurHandler = function(event) {
@@ -131,43 +137,8 @@ angular
}
});
- // watch the element for any value change, validate it once that happen
- var validationWatcher = scope.$watch(function() {
- attrs.ctrl = angular.element(attrs.elm).controller('ngModel');
-
- if(isKeyTypedBadInput(self, attrs.elmName)) {
- return { badInput: true };
- }
- return attrs.ctrl.$modelValue;
- }, function (newValue, oldValue) {
- if(!!newValue && !!newValue.badInput) {
- var formElmObj = self.commonObj.getFormElementByName(attrs.elmName);
- unbindBlurHandler(self, formElmObj);
- return invalidateBadInputField(self, attrs.name);
- }
- // when previous value was set and new value is not, this is most probably an invalid character entered in a type input="text"
- // we will still call the `.validate()` function so that it shows also the possible other error messages
- if(newValue === undefined && (oldValue !== undefined && !isNaN(oldValue))) {
- $timeout.cancel(self.timer);
- self.commonObj.ctrl.$setValidity('validation', self.commonObj.validate('', true));
- return;
- }
- // from the DOM element, find the Angular controller of this element & add value as well to list of attribtues
- attrs.ctrl = angular.element(attrs.elm).controller('ngModel');
- attrs.value = newValue;
-
- self.commonObj.initialize(scope, attrs.elm, attrs, attrs.ctrl);
-
- var waitingTimer = (typeof newValue === "undefined" || (typeof newValue === "number" && isNaN(newValue))) ? 0 : undefined;
- // attempt to validate & run validation callback if user requested it
- var validationPromise = attemptToValidate(self, newValue, waitingTimer);
- if(!!_validationCallback) {
- self.commonObj.runValidationCallbackOnPromise(validationPromise, _validationCallback);
- }
- }, true); // $watch()
-
// save the watcher inside an array in case we want to deregister it when removing a validator
- _watchers.push({ elmName: attrs.elmName, watcherHandler: validationWatcher});
+ _watchers.push({ elmName: attrs.elmName, watcherHandler: createWatch(scope, attrs, self) });
return self;
} // addValidator()
@@ -364,7 +335,7 @@ angular
self.commonObj.validate(value, false);
// if field is not required and his value is empty, cancel validation and exit out
- if(!self.commonObj.isFieldRequired() && (value === "" || value === null || typeof value === "undefined")) {
+ if(!self.commonObj.isFieldRequired() && !_validateOnEmpty && (value === "" || value === null || typeof value === "undefined")) {
cancelValidation(self, formElmObj);
deferred.resolve({ isFieldValid: true, formElmObj: formElmObj, value: value });
return deferred.promise;
@@ -373,7 +344,7 @@ angular
}
// invalidate field before doing any validation
- if(self.commonObj.isFieldRequired() || !!value) {
+ if(!!value || self.commonObj.isFieldRequired() || _validateOnEmpty) {
self.commonObj.ctrl.$setValidity('validation', false);
}
@@ -438,6 +409,45 @@ angular
unbindBlurHandler(obj, formElmObj);
}
+ /** watch the element for any value change, validate it once that happen
+ * @return new watcher
+ */
+ function createWatch(scope, attrs, self) {
+ return scope.$watch(function() {
+ attrs.ctrl = angular.element(attrs.elm).controller('ngModel');
+
+ if(isKeyTypedBadInput(self, attrs.elmName)) {
+ return { badInput: true };
+ }
+ return attrs.ctrl.$modelValue;
+ }, function (newValue, oldValue) {
+ if(!!newValue && !!newValue.badInput) {
+ var formElmObj = self.commonObj.getFormElementByName(attrs.elmName);
+ unbindBlurHandler(self, formElmObj);
+ return invalidateBadInputField(self, attrs.name);
+ }
+ // when previous value was set and new value is not, this is most probably an invalid character entered in a type input="text"
+ // we will still call the `.validate()` function so that it shows also the possible other error messages
+ if(newValue === undefined && (oldValue !== undefined && !isNaN(oldValue))) {
+ $timeout.cancel(self.timer);
+ self.commonObj.ctrl.$setValidity('validation', self.commonObj.validate('', true));
+ return;
+ }
+ // from the DOM element, find the Angular controller of this element & add value as well to list of attribtues
+ attrs.ctrl = angular.element(attrs.elm).controller('ngModel');
+ attrs.value = newValue;
+
+ self.commonObj.initialize(scope, attrs.elm, attrs, attrs.ctrl);
+
+ var waitingTimer = (typeof newValue === "undefined" || (typeof newValue === "number" && isNaN(newValue))) ? 0 : undefined;
+ // attempt to validate & run validation callback if user requested it
+ var validationPromise = attemptToValidate(self, newValue, waitingTimer);
+ if(!!_validationCallback) {
+ self.commonObj.runValidationCallbackOnPromise(validationPromise, _validationCallback);
+ }
+ }, true); // $watch()
+ }
+
/** Invalidate the field that was tagged as bad input, cancel the timer validation,
* display an invalid key error and add it as well to the validation summary.
* @param object self
@@ -480,6 +490,7 @@ angular
var foundWatcher = self.commonObj.arrayFindObject(_watchers, 'elmName', formElmObj.fieldName);
if(!!foundWatcher) {
foundWatcher.watcherHandler(); // deregister the watch by calling his handler
+ _watchers.shift();
}
// make the validation cancelled so it won't get called anymore in the blur eventHandler