├── test ├── helper.js ├── valid.json ├── invalid.json ├── spec │ ├── validator │ │ ├── cusip.js │ │ ├── imo.js │ │ ├── ean.js │ │ ├── issn.js │ │ ├── bic.js │ │ ├── isin.js │ │ ├── ismn.js │ │ ├── identical.js │ │ ├── ein.js │ │ ├── isbn.js │ │ ├── callback.js │ │ ├── creditCard.js │ │ └── meid.js │ ├── dynamic.js │ ├── api.js │ ├── autoFocus.js │ ├── enable.js │ ├── transformer.js │ └── message.js └── index.html ├── .gitignore ├── screenshots ├── pure.gif ├── uikit.gif ├── bootstrap.gif ├── semantic.gif └── foundation.gif ├── vendor ├── jasmine │ ├── jasmine_favicon.png │ └── jasmine.css └── bootstrap │ ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff │ └── js │ └── npm.js ├── demo ├── ajaxSubmit.php ├── target.php ├── remote.php ├── remote2.php ├── event2.html ├── tooltip.html ├── ignored.html ├── event3.html ├── container.html ├── selector2.html └── mailgun.html ├── dist ├── js │ └── framework │ │ ├── pure.min.js │ │ ├── semantic.min.js │ │ ├── uikit.min.js │ │ ├── foundation.min.js │ │ ├── pure.js │ │ └── bootstrap.min.js └── css │ └── formValidation.min.css ├── src └── js │ ├── validator │ ├── digits.js │ ├── siren.js │ ├── hex.js │ ├── mac.js │ ├── base64.js │ ├── siret.js │ ├── bic.js │ ├── blank.js │ ├── integer.js │ ├── rtn.js │ ├── regexp.js │ ├── notEmpty.js │ ├── sedol.js │ ├── ean.js │ ├── grid.js │ ├── stringCase.js │ ├── numeric.js │ ├── callback.js │ ├── issn.js │ ├── imo.js │ ├── imei.js │ ├── vin.js │ ├── cusip.js │ ├── uuid.js │ ├── ismn.js │ ├── ein.js │ ├── step.js │ ├── identical.js │ ├── lessThan.js │ ├── greaterThan.js │ ├── isin.js │ ├── between.js │ ├── choice.js │ ├── ip.js │ ├── different.js │ ├── isbn.js │ ├── meid.js │ ├── emailAddress.js │ └── file.js │ └── framework │ └── pure.js ├── package.json ├── README.md └── LICENSE.txt /test/helper.js: -------------------------------------------------------------------------------- 1 | var TestSuite = {}; -------------------------------------------------------------------------------- /test/valid.json: -------------------------------------------------------------------------------- 1 | { 2 | "valid": true 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | _gh_pages 3 | node_modules -------------------------------------------------------------------------------- /test/invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "valid": "false" 3 | } -------------------------------------------------------------------------------- /screenshots/pure.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icai/formvalidation/master/screenshots/pure.gif -------------------------------------------------------------------------------- /screenshots/uikit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icai/formvalidation/master/screenshots/uikit.gif -------------------------------------------------------------------------------- /screenshots/bootstrap.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icai/formvalidation/master/screenshots/bootstrap.gif -------------------------------------------------------------------------------- /screenshots/semantic.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icai/formvalidation/master/screenshots/semantic.gif -------------------------------------------------------------------------------- /screenshots/foundation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icai/formvalidation/master/screenshots/foundation.gif -------------------------------------------------------------------------------- /vendor/jasmine/jasmine_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icai/formvalidation/master/vendor/jasmine/jasmine_favicon.png -------------------------------------------------------------------------------- /demo/ajaxSubmit.php: -------------------------------------------------------------------------------- 1 | sprintf('Welcome %s', $userName), 6 | )); 7 | -------------------------------------------------------------------------------- /vendor/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icai/formvalidation/master/vendor/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /vendor/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icai/formvalidation/master/vendor/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /vendor/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icai/formvalidation/master/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /demo/target.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FormValidation demo 5 | 6 | 7 | 8 |
9 |
10 |

Form data

11 |
12 |

This is a simple page showing the data you have just submitted

13 |
14 |
15 |
16 | 17 | -------------------------------------------------------------------------------- /vendor/bootstrap/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /demo/remote.php: -------------------------------------------------------------------------------- 1 | 'admin@domain.com', 15 | 'administrator' => 'administrator@domain.com', 16 | 'root' => 'root@domain.com', 17 | ); 18 | 19 | if (isset($_POST['username']) && array_key_exists($_POST['username'], $users)) { 20 | $valid = false; 21 | } else if (isset($_POST['email'])) { 22 | $email = $_POST['email'][0]; 23 | foreach ($users as $k => $v) { 24 | if ($email == $v) { 25 | $valid = false; 26 | break; 27 | } 28 | } 29 | } 30 | 31 | echo json_encode(array( 32 | 'valid' => $valid, 33 | )); 34 | -------------------------------------------------------------------------------- /demo/remote2.php: -------------------------------------------------------------------------------- 1 | 'admin@domain.com', 14 | 'administrator' => 'administrator@domain.com', 15 | 'root' => 'root@domain.com', 16 | ); 17 | 18 | if (isset($_POST['username']) && array_key_exists($_POST['username'], $users)) { 19 | $valid = false; 20 | $message = 'The username is not available'; 21 | } else if (isset($_POST['email'])) { 22 | $email = $_POST['email']; 23 | foreach ($users as $k => $v) { 24 | if ($email == $v) { 25 | $valid = false; 26 | $message = 'The email is not available'; 27 | break; 28 | } 29 | } 30 | } 31 | 32 | echo json_encode( 33 | $valid ? array('valid' => $valid) : array('valid' => $valid, 'message' => $message) 34 | ); 35 | -------------------------------------------------------------------------------- /dist/js/framework/pure.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * FormValidation (http://formvalidation.io) 3 | * The best jQuery plugin to validate form fields. Support Bootstrap, Foundation, Pure, SemanticUI, UIKit and custom frameworks 4 | * 5 | * @version v0.6.2-dev, built on 2015-03-13 8:15:46 AM 6 | * @author https://twitter.com/nghuuphuoc 7 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 8 | * @license http://formvalidation.io/license/ 9 | */ 10 | !function(a){FormValidation.Framework.Pure=function(b,c){c=a.extend(!0,{button:{selector:'[type="submit"]',disabled:"pure-button-disabled"},err:{clazz:"fv-help-block",parent:"^.*pure-control-group.*$"},icon:{valid:null,invalid:null,validating:null,feedback:"fv-control-feedback"},row:{selector:".pure-control-group",valid:"fv-has-success",invalid:"fv-has-error",feedback:"fv-has-feedback"}},c),FormValidation.Base.apply(this,[b,c])},FormValidation.Framework.Pure.prototype=a.extend({},FormValidation.Base.prototype,{_fixIcon:function(a,b){var c=this._namespace,d=(a.attr("type"),a.attr("data-"+c+"-field")),e=this.options.fields[d].row||this.options.row.selector,f=a.closest(e);0===f.find("label").length&&b.addClass("fv-icon-no-label")}})}(jQuery); -------------------------------------------------------------------------------- /src/js/validator/digits.js: -------------------------------------------------------------------------------- 1 | /** 2 | * digits validator 3 | * 4 | * @link http://formvalidation.io/validators/digits/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | digits: { 13 | 'default': 'Please enter only digits' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.digits = { 19 | /** 20 | * Return true if the input value contains digits only 21 | * 22 | * @param {FormValidation.Base} validator Validate plugin instance 23 | * @param {jQuery} $field Field element 24 | * @param {Object} [options] 25 | * @returns {Boolean} 26 | */ 27 | validate: function(validator, $field, options) { 28 | var value = validator.getFieldValue($field, 'digits'); 29 | if (value === '') { 30 | return true; 31 | } 32 | 33 | return /^\d+$/.test(value); 34 | } 35 | }; 36 | }(jQuery)); 37 | -------------------------------------------------------------------------------- /src/js/validator/siren.js: -------------------------------------------------------------------------------- 1 | /** 2 | * siren validator 3 | * 4 | * @link http://formvalidation.io/validators/siren/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | siren: { 13 | 'default': 'Please enter a valid SIREN number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.siren = { 19 | /** 20 | * Check if a string is a siren number 21 | * 22 | * @param {FormValidation.Base} validator The validator plugin instance 23 | * @param {jQuery} $field Field element 24 | * @param {Object} options Consist of key: 25 | * - message: The invalid message 26 | * @returns {Boolean} 27 | */ 28 | validate: function(validator, $field, options) { 29 | var value = validator.getFieldValue($field, 'siren'); 30 | if (value === '') { 31 | return true; 32 | } 33 | 34 | if (!/^\d{9}$/.test(value)) { 35 | return false; 36 | } 37 | return FormValidation.Helper.luhn(value); 38 | } 39 | }; 40 | }(jQuery)); 41 | -------------------------------------------------------------------------------- /src/js/validator/hex.js: -------------------------------------------------------------------------------- 1 | /** 2 | * hex validator 3 | * 4 | * @link http://formvalidation.io/validators/hex/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | hex: { 13 | 'default': 'Please enter a valid hexadecimal number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.hex = { 19 | /** 20 | * Return true if and only if the input value is a valid hexadecimal number 21 | * 22 | * @param {FormValidation.Base} validator The validator plugin instance 23 | * @param {jQuery} $field Field element 24 | * @param {Object} options Consist of key: 25 | * - message: The invalid message 26 | * @returns {Boolean} 27 | */ 28 | validate: function(validator, $field, options) { 29 | var value = validator.getFieldValue($field, 'hex'); 30 | if (value === '') { 31 | return true; 32 | } 33 | 34 | return /^[0-9a-fA-F]+$/.test(value); 35 | } 36 | }; 37 | }(jQuery)); 38 | -------------------------------------------------------------------------------- /src/js/validator/mac.js: -------------------------------------------------------------------------------- 1 | /** 2 | * mac validator 3 | * 4 | * @link http://formvalidation.io/validators/mac/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | mac: { 13 | 'default': 'Please enter a valid MAC address' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.mac = { 19 | /** 20 | * Return true if the input value is a MAC address. 21 | * 22 | * @param {FormValidation.Base} validator The validator plugin instance 23 | * @param {jQuery} $field Field element 24 | * @param {Object} options Can consist of the following keys: 25 | * - message: The invalid message 26 | * @returns {Boolean} 27 | */ 28 | validate: function(validator, $field, options) { 29 | var value = validator.getFieldValue($field, 'mac'); 30 | if (value === '') { 31 | return true; 32 | } 33 | 34 | return /^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/.test(value); 35 | } 36 | }; 37 | }(jQuery)); 38 | -------------------------------------------------------------------------------- /src/js/validator/base64.js: -------------------------------------------------------------------------------- 1 | /** 2 | * base64 validator 3 | * 4 | * @link http://formvalidation.io/validators/base64/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | base64: { 13 | 'default': 'Please enter a valid base 64 encoded' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.base64 = { 19 | /** 20 | * Return true if the input value is a base 64 encoded string. 21 | * 22 | * @param {FormValidation.Base} validator The validator plugin instance 23 | * @param {jQuery} $field Field element 24 | * @param {Object} options Can consist of the following keys: 25 | * - message: The invalid message 26 | * @returns {Boolean} 27 | */ 28 | validate: function(validator, $field, options) { 29 | var value = validator.getFieldValue($field, 'base64'); 30 | if (value === '') { 31 | return true; 32 | } 33 | 34 | return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/.test(value); 35 | } 36 | }; 37 | }(jQuery)); 38 | -------------------------------------------------------------------------------- /test/spec/validator/cusip.js: -------------------------------------------------------------------------------- 1 | describe('cusip', function() { 2 | beforeEach(function() { 3 | $([ 4 | '
', 5 | '
', 6 | '', 7 | '
', 8 | '
' 9 | ].join('\n')).appendTo('body'); 10 | $('#cusipForm').formValidation(); 11 | 12 | this.fv = $('#cusipForm').data('formValidation'); 13 | this.$cusip = this.fv.getFieldElements('cusip'); 14 | }); 15 | 16 | afterEach(function() { 17 | $('#cusipForm').formValidation('destroy').remove(); 18 | }); 19 | 20 | it('valid', function() { 21 | var samples = ['037833100', '931142103', '14149YAR8', '126650BG6']; 22 | 23 | for (var i in samples) { 24 | this.fv.resetForm(); 25 | this.$cusip.val(samples[i]); 26 | this.fv.validate(); 27 | expect(this.fv.isValidField('cusip')).toBeTruthy(); 28 | } 29 | }); 30 | 31 | it('invalid', function() { 32 | var samples = ['31430F200', '022615AC2']; 33 | 34 | for (var i in samples) { 35 | this.fv.resetForm(); 36 | this.$cusip.val(samples[i]); 37 | this.fv.validate(); 38 | expect(this.fv.isValidField('cusip')).toEqual(false); 39 | } 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "formvalidation", 3 | "version": "0.6.2-dev", 4 | "description": "The best jQuery plugin to validate form fields. Support Bootstrap, Foundation, Pure, SemanticUI, UIKit and custom frameworks", 5 | "keywords": [ 6 | "jQuery", 7 | "plugin", 8 | "validate", 9 | "validator", 10 | "form", 11 | "Bootstrap", 12 | "Foundation", 13 | "Pure", 14 | "SemanticUI", 15 | "UIKit" 16 | ], 17 | "author": { 18 | "name": "Nguyen Huu Phuoc", 19 | "email": "phuoc@huuphuoc.me", 20 | "url": "https://twitter.com/nghuuphuoc" 21 | }, 22 | "homepage": "http://formvalidation.io", 23 | "bugs": { 24 | "url": "https://github.com/formvalidation/formvalidation/issues", 25 | "email": "phuoc@huuphuoc.me" 26 | }, 27 | "license": "http://formvalidation.io/license/", 28 | "main": "./dist/js/formValidation.js", 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/formvalidation/formvalidation.git" 32 | }, 33 | "devDependencies": { 34 | "grunt": "latest", 35 | "grunt-contrib-concat": "latest", 36 | "grunt-contrib-copy": "latest", 37 | "grunt-contrib-cssmin": "latest", 38 | "grunt-contrib-jasmine": "latest", 39 | "grunt-contrib-jshint": "latest", 40 | "grunt-contrib-uglify": "latest", 41 | "grunt-contrib-watch": "latest" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/js/validator/siret.js: -------------------------------------------------------------------------------- 1 | /** 2 | * siret validator 3 | * 4 | * @link http://formvalidation.io/validators/siret/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | siret: { 13 | 'default': 'Please enter a valid SIRET number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.siret = { 19 | /** 20 | * Check if a string is a siret number 21 | * 22 | * @param {FormValidation.Base} validator The validator plugin instance 23 | * @param {jQuery} $field Field element 24 | * @param {Object} options Consist of key: 25 | * - message: The invalid message 26 | * @returns {Boolean} 27 | */ 28 | validate: function(validator, $field, options) { 29 | var value = validator.getFieldValue($field, 'siret'); 30 | if (value === '') { 31 | return true; 32 | } 33 | 34 | var sum = 0, 35 | length = value.length, 36 | tmp; 37 | for (var i = 0; i < length; i++) { 38 | tmp = parseInt(value.charAt(i), 10); 39 | if ((i % 2) === 0) { 40 | tmp = tmp * 2; 41 | if (tmp > 9) { 42 | tmp -= 9; 43 | } 44 | } 45 | sum += tmp; 46 | } 47 | return (sum % 10 === 0); 48 | } 49 | }; 50 | }(jQuery)); 51 | -------------------------------------------------------------------------------- /src/js/validator/bic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * bic validator 3 | * 4 | * @link http://formvalidation.io/validators/bic/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | bic: { 13 | 'default': 'Please enter a valid BIC number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.bic = { 19 | /** 20 | * Validate an Business Identifier Code (BIC), also known as ISO 9362, SWIFT-BIC, SWIFT ID or SWIFT code 21 | * 22 | * For more information see http://en.wikipedia.org/wiki/ISO_9362 23 | * 24 | * @todo The 5 and 6 characters are an ISO 3166-1 country code, this could also be validated 25 | * @param {FormValidation.Base} validator The validator plugin instance 26 | * @param {jQuery} $field Field element 27 | * @param {Object} options Can consist of the following keys: 28 | * - message: The invalid message 29 | * @returns {Object} 30 | */ 31 | validate: function(validator, $field, options) { 32 | var value = validator.getFieldValue($field, 'bic'); 33 | if (value === '') { 34 | return true; 35 | } 36 | return /^[a-zA-Z]{6}[a-zA-Z0-9]{2}([a-zA-Z0-9]{3})?$/.test(value); 37 | } 38 | }; 39 | }(jQuery)); 40 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FormValidation test suites 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/js/validator/blank.js: -------------------------------------------------------------------------------- 1 | /** 2 | * blank validator 3 | * 4 | * @author https://twitter.com/nghuuphuoc 5 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 6 | * @license http://formvalidation.io/license/ 7 | */ 8 | (function($) { 9 | FormValidation.Validator.blank = { 10 | /** 11 | * Placeholder validator that can be used to display a custom validation message 12 | * returned from the server 13 | * Example: 14 | * 15 | * (1) a "blank" validator is applied to an input field. 16 | * (2) data is entered via the UI that is unable to be validated client-side. 17 | * (3) server returns a 400 with JSON data that contains the field that failed 18 | * validation and an associated message. 19 | * (4) ajax 400 call handler does the following: 20 | * 21 | * bv.updateMessage(field, 'blank', errorMessage); 22 | * bv.updateStatus(field, 'INVALID'); 23 | * 24 | * @see https://github.com/formvalidation/formvalidation/issues/542 25 | * @see https://github.com/formvalidation/formvalidation/pull/666 26 | * @param {FormValidation.Base} validator The validator plugin instance 27 | * @param {jQuery} $field Field element 28 | * @param {Object} options Can consist of the following keys: 29 | * - message: The invalid message 30 | * @returns {Boolean} 31 | */ 32 | validate: function(validator, $field, options) { 33 | return true; 34 | } 35 | }; 36 | }(jQuery)); 37 | -------------------------------------------------------------------------------- /test/spec/validator/imo.js: -------------------------------------------------------------------------------- 1 | describe('imo', function() { 2 | beforeEach(function() { 3 | $([ 4 | '
', 5 | '
', 6 | '', 7 | '
', 8 | '
' 9 | ].join('\n')).appendTo('body'); 10 | 11 | $('#imoForm').formValidation(); 12 | 13 | this.fv = $('#imoForm').data('formValidation'); 14 | this.$imo = this.fv.getFieldElements('imo'); 15 | }); 16 | 17 | afterEach(function() { 18 | $('#imoForm').formValidation('destroy').remove(); 19 | }); 20 | 21 | it('Valid IMO (upper)', function() { 22 | this.fv.resetForm(); 23 | this.$imo.val('IMO 9074729'); 24 | this.fv.validate(); 25 | expect(this.fv.isValid()).toBeTruthy(); 26 | }); 27 | 28 | it('Valid IMO (lower)', function() { 29 | this.fv.resetForm(); 30 | this.$imo.val('imo 9074729'); 31 | this.fv.validate(); 32 | expect(this.fv.isValid()).toBeTruthy(); 33 | }); 34 | 35 | it('Invalid IMO (bad format)', function() { 36 | this.fv.resetForm(); 37 | this.$imo.val('9074729'); 38 | this.fv.validate(); 39 | expect(this.fv.isValid()).toBeFalsy(); 40 | }); 41 | 42 | it('Invalid IMO (bad check digit)', function() { 43 | this.fv.resetForm(); 44 | this.$imo.val('IMO 9074728'); 45 | this.fv.validate(); 46 | expect(this.fv.isValid()).toBeFalsy(); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/js/validator/integer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * integer validator 3 | * 4 | * @link http://formvalidation.io/validators/integer/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | integer: { 13 | 'default': 'Please enter a valid number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.integer = { 19 | enableByHtml5: function($field) { 20 | return ('number' === $field.attr('type')) && ($field.attr('step') === undefined || $field.attr('step') % 1 === 0); 21 | }, 22 | 23 | /** 24 | * Return true if the input value is an integer 25 | * 26 | * @param {FormValidation.Base} validator The validator plugin instance 27 | * @param {jQuery} $field Field element 28 | * @param {Object} options Can consist of the following key: 29 | * - message: The invalid message 30 | * @returns {Boolean} 31 | */ 32 | validate: function(validator, $field, options) { 33 | if (this.enableByHtml5($field) && $field.get(0).validity && $field.get(0).validity.badInput === true) { 34 | return false; 35 | } 36 | 37 | var value = validator.getFieldValue($field, 'integer'); 38 | if (value === '') { 39 | return true; 40 | } 41 | return /^(?:-?(?:0|[1-9][0-9]*))$/.test(value); 42 | } 43 | }; 44 | }(jQuery)); 45 | -------------------------------------------------------------------------------- /dist/js/framework/semantic.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * FormValidation (http://formvalidation.io) 3 | * The best jQuery plugin to validate form fields. Support Bootstrap, Foundation, Pure, SemanticUI, UIKit and custom frameworks 4 | * 5 | * @version v0.6.2-dev, built on 2015-03-13 8:15:46 AM 6 | * @author https://twitter.com/nghuuphuoc 7 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 8 | * @license http://formvalidation.io/license/ 9 | */ 10 | !function(a){FormValidation.Framework.Semantic=function(b,c){c=a.extend(!0,{button:{selector:'[type="submit"]',disabled:"disabled"},control:{valid:"",invalid:""},err:{clazz:"ui red pointing label transition",parent:"^.*(field|column).*$"},icon:{valid:null,invalid:null,validating:null,feedback:"fv-control-feedback"},row:{selector:".field",valid:"fv-has-success",invalid:"error",feedback:"fv-has-feedback"}},c),FormValidation.Base.apply(this,[b,c])},FormValidation.Framework.Semantic.prototype=a.extend({},FormValidation.Base.prototype,{_fixIcon:function(a,b){var c=a.attr("type");if("checkbox"===c||"radio"===c){var d=a.parent();d.hasClass(c)&&b.insertAfter(d)}},_createTooltip:function(a,b,c){var d=a.data("fv.icon");if(d)switch(d.popup("exists")&&d.popup("remove popup").popup("destroy"),c){case"popover":d.css({cursor:"pointer"}).popup({content:b,position:"top center"});break;case"tooltip":default:d.css({cursor:"pointer"}).popup({content:b,position:"top center",variation:"inverted"})}},_destroyTooltip:function(a){var b=a.data("fv.icon");b&&b.popup("exists")&&b.css({cursor:""}).popup("remove popup").popup("destroy")},_hideTooltip:function(a){var b=a.data("fv.icon");b&&b.popup("hide")},_showTooltip:function(a){var b=a.data("fv.icon");b&&b.popup("show")}})}(jQuery); -------------------------------------------------------------------------------- /test/spec/validator/ean.js: -------------------------------------------------------------------------------- 1 | describe('ean', function() { 2 | beforeEach(function() { 3 | var html = [ 4 | '
', 5 | '
', 6 | '
', 7 | '', 8 | '
', 9 | '
', 10 | '
' 11 | ].join('\n'); 12 | 13 | $(html).appendTo('body'); 14 | $('#eanForm').formValidation(); 15 | 16 | this.fv = $('#eanForm').data('formValidation'); 17 | this.$ean = this.fv.getFieldElements('ean'); 18 | }); 19 | 20 | afterEach(function() { 21 | $('#eanForm').formValidation('destroy').parent().remove(); 22 | }); 23 | 24 | it('valid', function() { 25 | var samples = ['73513537', '9780471117094', '4006381333931']; 26 | 27 | for (var i in samples) { 28 | this.$ean.val(samples[i]); 29 | this.fv.validate(); 30 | expect(this.fv.isValidField('ean')).toBeTruthy(); 31 | } 32 | }); 33 | 34 | it('contains only digits', function() { 35 | this.$ean.val('123abcDEF!@#'); 36 | this.fv.validate(); 37 | expect(this.fv.isValidField('ean')).toEqual(false); 38 | }); 39 | 40 | it('invalid length', function() { 41 | this.$ean.val('1234567'); 42 | this.fv.validate(); 43 | expect(this.fv.isValidField('ean')).toEqual(false); 44 | }); 45 | 46 | it('invalid check digit', function() { 47 | this.$ean.val('73513536'); 48 | this.fv.validate(); 49 | expect(this.fv.isValidField('ean')).toEqual(false); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /test/spec/validator/issn.js: -------------------------------------------------------------------------------- 1 | describe('issn', function() { 2 | beforeEach(function() { 3 | var html = [ 4 | '
', 5 | '
', 6 | '
', 7 | '', 8 | '
', 9 | '
', 10 | '
' 11 | ].join('\n'); 12 | 13 | $(html).appendTo('body'); 14 | $('#issnForm').formValidation(); 15 | 16 | this.fv = $('#issnForm').data('formValidation'); 17 | this.$issn = this.fv.getFieldElements('issn'); 18 | }); 19 | 20 | afterEach(function() { 21 | $('#issnForm').formValidation('destroy').parent().remove(); 22 | }); 23 | 24 | it('valid', function() { 25 | var samples = ['0378-5955', '0024-9319', '0032-1478']; 26 | 27 | for (var i in samples) { 28 | this.$issn.val(samples[i]); 29 | this.fv.validate(); 30 | expect(this.fv.isValidField('issn')).toBeTruthy(); 31 | } 32 | }); 33 | 34 | it('not contains hyphen', function() { 35 | this.$issn.val('03785955'); 36 | this.fv.validate(); 37 | expect(this.fv.isValidField('issn')).toEqual(false); 38 | }); 39 | 40 | it('contains only digits, X', function() { 41 | this.$issn.val('1234-566A'); 42 | this.fv.validate(); 43 | expect(this.fv.isValidField('issn')).toEqual(false); 44 | }); 45 | 46 | it('invalid check sum', function() { 47 | this.$issn.val('0032-147X'); 48 | this.fv.validate(); 49 | expect(this.fv.isValidField('issn')).toEqual(false); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /test/spec/validator/bic.js: -------------------------------------------------------------------------------- 1 | describe('bic', function() { 2 | beforeEach(function() { 3 | $([ 4 | '
', 5 | '
', 6 | '', 7 | '
', 8 | '
' 9 | ].join('\n')).appendTo('body'); 10 | 11 | $('#bicForm').formValidation(); 12 | 13 | this.fv = $('#bicForm').data('formValidation'); 14 | this.$bic = this.fv.getFieldElements('bic'); 15 | }); 16 | 17 | afterEach(function() { 18 | $('#bicForm').formValidation('destroy').remove(); 19 | }); 20 | 21 | it('invalid bic', function() { 22 | // Test some invalid BICs 23 | var invalidSamples = [ 24 | 'ASPKAT2LXX', 'ASPKAT2LX', 'ASPKAT2LXXX1', 'DABADKK', 'RZ00AT2L303', 25 | // Invalid fist 6 characters 26 | '1SBACNBXSHA', 'D2BACNBXSHA', 'DS3ACNBXSHA', 'DSB4CNBXSHA', 'DSBA5NBXSHA', 'DSBAC6BXSHA', '1S3AC6BXSHA' 27 | ]; 28 | for (i in invalidSamples) { 29 | this.fv.resetForm(); 30 | this.$bic.val(invalidSamples[i]); 31 | this.fv.validate(); 32 | expect(this.fv.isValid()).toEqual(false); 33 | } 34 | }); 35 | 36 | it('valid bic', function() { 37 | // Examples see http://en.wikipedia.org/wiki/ISO_9362 38 | var validSamples = ['ASPKAT2LXXX', 'ASPKAT2L', 'DSBACNBXSHA', 'UNCRIT2B912', 'DABADKKK', 'RZOOAT2L303']; 39 | for (i in validSamples) { 40 | this.fv.resetForm(); 41 | this.$bic.val(validSamples[i]); 42 | this.fv.validate(); 43 | expect(this.fv.isValid()).toBeTruthy(); 44 | } 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /src/js/validator/rtn.js: -------------------------------------------------------------------------------- 1 | /** 2 | * rtn validator 3 | * 4 | * @link http://formvalidation.io/validators/rtn/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | rtn: { 13 | 'default': 'Please enter a valid RTN number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.rtn = { 19 | /** 20 | * Validate a RTN (Routing transit number) 21 | * Examples: 22 | * - Valid: 021200025, 789456124 23 | * 24 | * @see http://en.wikipedia.org/wiki/Routing_transit_number 25 | * @param {FormValidation.Base} validator The validator plugin instance 26 | * @param {jQuery} $field Field element 27 | * @param {Object} options Can consist of the following keys: 28 | * - message: The invalid message 29 | * @returns {Boolean} 30 | */ 31 | validate: function(validator, $field, options) { 32 | var value = validator.getFieldValue($field, 'rtn'); 33 | if (value === '') { 34 | return true; 35 | } 36 | 37 | if (!/^\d{9}$/.test(value)) { 38 | return false; 39 | } 40 | 41 | var sum = 0; 42 | for (var i = 0; i < value.length; i += 3) { 43 | sum += parseInt(value.charAt(i), 10) * 3 44 | + parseInt(value.charAt(i + 1), 10) * 7 45 | + parseInt(value.charAt(i + 2), 10); 46 | } 47 | return (sum !== 0 && sum % 10 === 0); 48 | } 49 | }; 50 | }(jQuery)); 51 | -------------------------------------------------------------------------------- /src/js/validator/regexp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * regexp validator 3 | * 4 | * @link http://formvalidation.io/validators/regexp/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | regexp: { 13 | 'default': 'Please enter a value matching the pattern' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.regexp = { 19 | html5Attributes: { 20 | message: 'message', 21 | regexp: 'regexp' 22 | }, 23 | 24 | enableByHtml5: function($field) { 25 | var pattern = $field.attr('pattern'); 26 | if (pattern) { 27 | return { 28 | regexp: pattern 29 | }; 30 | } 31 | 32 | return false; 33 | }, 34 | 35 | /** 36 | * Check if the element value matches given regular expression 37 | * 38 | * @param {FormValidation.Base} validator The validator plugin instance 39 | * @param {jQuery} $field Field element 40 | * @param {Object} options Consists of the following key: 41 | * - regexp: The regular expression you need to check 42 | * @returns {Boolean} 43 | */ 44 | validate: function(validator, $field, options) { 45 | var value = validator.getFieldValue($field, 'regexp'); 46 | if (value === '') { 47 | return true; 48 | } 49 | 50 | var regexp = ('string' === typeof options.regexp) ? new RegExp(options.regexp) : options.regexp; 51 | return regexp.test(value); 52 | } 53 | }; 54 | }(jQuery)); 55 | -------------------------------------------------------------------------------- /dist/css/formValidation.min.css: -------------------------------------------------------------------------------- 1 | .fv-has-feedback{position:relative}.fv-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center}.fv-help-block{display:block}.fv-form-bootstrap .help-block{margin-bottom:0}.fv-form-bootstrap .tooltip-inner{text-align:left}.fv-form-bootstrap .fv-icon-no-label{top:0}.fv-form-bootstrap .fv-bootstrap-icon-input-group{z-index:100}.form-inline.fv-form-bootstrap .form-group{vertical-align:top}.fv-form-foundation .fv-control-feedback{top:21px;right:15px;width:37px;height:37px;line-height:37px}.fv-form-foundation .collapse .fv-control-feedback{top:0;right:0}.fv-form-foundation .fv-icon-no-label,.fv-form-horizontal.fv-form-foundation .fv-control-feedback{top:0}.fv-form-foundation .error .fv-control-feedback{color:#f04124}.error.fv-has-tooltip select,.error.fv-has-tooltip textarea,.fv-form-foundation .error.fv-has-tooltip input{margin-bottom:1rem}.fv-form-pure .fv-control-feedback{top:22px;width:36px;height:36px;line-height:36px}.pure-form-stacked.fv-form-pure .fv-control-feedback{top:4px}.pure-form-aligned .pure-control-group .fv-help-block{margin-top:5px;margin-left:180px}.fv-form-pure .fv-icon-no-label,.pure-form-aligned.fv-form-pure .fv-control-feedback{top:0}.fv-form-pure .fv-has-error .fv-control-feedback,.fv-form-pure .fv-has-error .fv-help-block,.fv-form-pure .fv-has-error label{color:#CA3C3C}.fv-form-semantic .fv-control-feedback.icon{right:7px}.fv-form-semantic .error .icon{color:#d95c5c}.fv-form-horizontal.fv-form-semantic .row{padding-bottom:0}.fv-form-uikit .fv-control-feedback{top:25px;width:30px;height:30px;line-height:30px}.fv-form-uikit .uk-text-danger{display:block}.uk-form-horizontal.fv-form-uikit .fv-control-feedback{top:0}.fv-form-uikit .fv-has-error .fv-control-feedback,.fv-form-uikit .fv-has-error .uk-form-label,.fv-form-uikit .fv-has-error label{color:#D85030}.fv-form-uikit .fv-icon-no-label{top:0} -------------------------------------------------------------------------------- /src/js/validator/notEmpty.js: -------------------------------------------------------------------------------- 1 | /** 2 | * notEmpty validator 3 | * 4 | * @link http://formvalidation.io/validators/notEmpty/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | notEmpty: { 13 | 'default': 'Please enter a value' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.notEmpty = { 19 | enableByHtml5: function($field) { 20 | var required = $field.attr('required') + ''; 21 | return ('required' === required || 'true' === required); 22 | }, 23 | 24 | /** 25 | * Check if input value is empty or not 26 | * 27 | * @param {FormValidation.Base} validator The validator plugin instance 28 | * @param {jQuery} $field Field element 29 | * @param {Object} options 30 | * @returns {Boolean} 31 | */ 32 | validate: function(validator, $field, options) { 33 | var type = $field.attr('type'); 34 | if ('radio' === type || 'checkbox' === type) { 35 | var ns = validator.getNamespace(); 36 | return validator 37 | .getFieldElements($field.attr('data-' + ns + '-field')) 38 | .filter(':checked') 39 | .length > 0; 40 | } 41 | 42 | if ('number' === type && $field.get(0).validity && $field.get(0).validity.badInput === true) { 43 | return true; 44 | } 45 | 46 | var value = validator.getFieldValue($field, 'notEmpty'); 47 | return $.trim(value) !== ''; 48 | } 49 | }; 50 | }(jQuery)); 51 | -------------------------------------------------------------------------------- /dist/js/framework/uikit.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * FormValidation (http://formvalidation.io) 3 | * The best jQuery plugin to validate form fields. Support Bootstrap, Foundation, Pure, SemanticUI, UIKit and custom frameworks 4 | * 5 | * @version v0.6.2-dev, built on 2015-03-13 8:15:46 AM 6 | * @author https://twitter.com/nghuuphuoc 7 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 8 | * @license http://formvalidation.io/license/ 9 | */ 10 | !function(a){FormValidation.Framework.Uikit=function(b,c){c=a.extend(!0,{button:{selector:'[type="submit"]',disabled:"disabled"},control:{valid:"uk-form-success",invalid:"uk-form-danger"},err:{clazz:"uk-text-danger",parent:"^.*(uk-form-controls|uk-width-[\\d+]-[\\d+]).*$"},icon:{valid:null,invalid:null,validating:null,feedback:"fv-control-feedback"},row:{selector:".uk-form-row",valid:"fv-has-success",invalid:"fv-has-error",feedback:"fv-has-feedback"}},c),FormValidation.Base.apply(this,[b,c])},FormValidation.Framework.Uikit.prototype=a.extend({},FormValidation.Base.prototype,{_fixIcon:function(a,b){var c=this._namespace,d=a.attr("type"),e=a.attr("data-"+c+"-field"),f=this.options.fields[e].row||this.options.row.selector,g=a.closest(f);if("checkbox"===d||"radio"===d){var h=a.parent();h.is("label")&&b.insertAfter(h)}0===g.find("label").length&&b.addClass("fv-icon-no-label")},_createTooltip:function(b,c){var d=b.data("fv.icon");d&&(d.data("tooltip")&&(d.data("tooltip").off(),d.removeData("tooltip")),d.attr("title",c).css({cursor:"pointer"}),new a.UIkit.tooltip(d))},_destroyTooltip:function(a){var b=a.data("fv.icon");if(b){var c=b.data("tooltip");c&&(c.hide(),c.off(),b.off("focus mouseenter").removeData("tooltip")),b.css({cursor:""})}},_hideTooltip:function(a){var b=a.data("fv.icon");if(b){var c=b.data("tooltip");c&&c.hide(),b.css({cursor:""})}},_showTooltip:function(a){var b=a.data("fv.icon");if(b){b.css({cursor:"pointer"});var c=b.data("tooltip");c&&c.show()}}})}(jQuery); -------------------------------------------------------------------------------- /src/js/validator/sedol.js: -------------------------------------------------------------------------------- 1 | /** 2 | * sedol validator 3 | * 4 | * @link http://formvalidation.io/validators/sedol/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | sedol: { 13 | 'default': 'Please enter a valid SEDOL number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.sedol = { 19 | /** 20 | * Validate a SEDOL (Stock Exchange Daily Official List) 21 | * Examples: 22 | * - Valid: 0263494, B0WNLY7 23 | * 24 | * @see http://en.wikipedia.org/wiki/SEDOL 25 | * @param {FormValidation.Base} validator The validator plugin instance 26 | * @param {jQuery} $field Field element 27 | * @param {Object} options Can consist of the following keys: 28 | * - message: The invalid message 29 | * @returns {Boolean} 30 | */ 31 | validate: function(validator, $field, options) { 32 | var value = validator.getFieldValue($field, 'sedol'); 33 | if (value === '') { 34 | return true; 35 | } 36 | 37 | value = value.toUpperCase(); 38 | if (!/^[0-9A-Z]{7}$/.test(value)) { 39 | return false; 40 | } 41 | 42 | var sum = 0, 43 | weight = [1, 3, 1, 7, 3, 9, 1], 44 | length = value.length; 45 | for (var i = 0; i < length - 1; i++) { 46 | sum += weight[i] * parseInt(value.charAt(i), 36); 47 | } 48 | sum = (10 - sum % 10) % 10; 49 | return sum + '' === value.charAt(length - 1); 50 | } 51 | }; 52 | }(jQuery)); 53 | -------------------------------------------------------------------------------- /src/js/validator/ean.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ean validator 3 | * 4 | * @link http://formvalidation.io/validators/ean/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | ean: { 13 | 'default': 'Please enter a valid EAN number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.ean = { 19 | /** 20 | * Validate EAN (International Article Number) 21 | * Examples: 22 | * - Valid: 73513537, 9780471117094, 4006381333931 23 | * - Invalid: 73513536 24 | * 25 | * @see http://en.wikipedia.org/wiki/European_Article_Number 26 | * @param {FormValidation.Base} validator The validator plugin instance 27 | * @param {jQuery} $field Field element 28 | * @param {Object} options Can consist of the following keys: 29 | * - message: The invalid message 30 | * @returns {Boolean} 31 | */ 32 | validate: function(validator, $field, options) { 33 | var value = validator.getFieldValue($field, 'ean'); 34 | if (value === '') { 35 | return true; 36 | } 37 | 38 | if (!/^(\d{8}|\d{12}|\d{13})$/.test(value)) { 39 | return false; 40 | } 41 | 42 | var length = value.length, 43 | sum = 0, 44 | weight = (length === 8) ? [3, 1] : [1, 3]; 45 | for (var i = 0; i < length - 1; i++) { 46 | sum += parseInt(value.charAt(i), 10) * weight[i % 2]; 47 | } 48 | sum = (10 - sum % 10) % 10; 49 | return (sum + '' === value.charAt(length - 1)); 50 | } 51 | }; 52 | }(jQuery)); 53 | -------------------------------------------------------------------------------- /src/js/validator/grid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * grid validator 3 | * 4 | * @link http://formvalidation.io/validators/grid/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | grid: { 13 | 'default': 'Please enter a valid GRId number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.grid = { 19 | /** 20 | * Validate GRId (Global Release Identifier) 21 | * Examples: 22 | * - Valid: A12425GABC1234002M, A1-2425G-ABC1234002-M, A1 2425G ABC1234002 M, Grid:A1-2425G-ABC1234002-M 23 | * - Invalid: A1-2425G-ABC1234002-Q 24 | * 25 | * @see http://en.wikipedia.org/wiki/Global_Release_Identifier 26 | * @param {FormValidation.Base} validator The validator plugin instance 27 | * @param {jQuery} $field Field element 28 | * @param {Object} options Can consist of the following keys: 29 | * - message: The invalid message 30 | * @returns {Boolean} 31 | */ 32 | validate: function(validator, $field, options) { 33 | var value = validator.getFieldValue($field, 'grid'); 34 | if (value === '') { 35 | return true; 36 | } 37 | 38 | value = value.toUpperCase(); 39 | if (!/^[GRID:]*([0-9A-Z]{2})[-\s]*([0-9A-Z]{5})[-\s]*([0-9A-Z]{10})[-\s]*([0-9A-Z]{1})$/g.test(value)) { 40 | return false; 41 | } 42 | value = value.replace(/\s/g, '').replace(/-/g, ''); 43 | if ('GRID:' === value.substr(0, 5)) { 44 | value = value.substr(5); 45 | } 46 | return FormValidation.Helper.mod37And36(value); 47 | } 48 | }; 49 | }(jQuery)); 50 | -------------------------------------------------------------------------------- /src/js/validator/stringCase.js: -------------------------------------------------------------------------------- 1 | /** 2 | * stringCase validator 3 | * 4 | * @link http://formvalidation.io/validators/stringCase/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | stringCase: { 13 | 'default': 'Please enter only lowercase characters', 14 | upper: 'Please enter only uppercase characters' 15 | } 16 | } 17 | }); 18 | 19 | FormValidation.Validator.stringCase = { 20 | html5Attributes: { 21 | message: 'message', 22 | 'case': 'case' 23 | }, 24 | 25 | /** 26 | * Check if a string is a lower or upper case one 27 | * 28 | * @param {FormValidation.Base} validator The validator plugin instance 29 | * @param {jQuery} $field Field element 30 | * @param {Object} options Consist of key: 31 | * - message: The invalid message 32 | * - case: Can be 'lower' (default) or 'upper' 33 | * @returns {Object} 34 | */ 35 | validate: function(validator, $field, options) { 36 | var value = validator.getFieldValue($field, 'stringCase'); 37 | if (value === '') { 38 | return true; 39 | } 40 | 41 | var locale = validator.getLocale(), 42 | stringCase = (options['case'] || 'lower').toLowerCase(); 43 | return { 44 | valid: ('upper' === stringCase) ? value === value.toUpperCase() : value === value.toLowerCase(), 45 | message: options.message || (('upper' === stringCase) ? FormValidation.I18n[locale].stringCase.upper : FormValidation.I18n[locale].stringCase['default']) 46 | }; 47 | } 48 | }; 49 | }(jQuery)); 50 | -------------------------------------------------------------------------------- /test/spec/validator/isin.js: -------------------------------------------------------------------------------- 1 | describe('isin', function() { 2 | beforeEach(function() { 3 | var html = [ 4 | '
', 5 | '
', 6 | '
', 7 | '', 8 | '
', 9 | '
', 10 | '
' 11 | ].join('\n'); 12 | 13 | $(html).appendTo('body'); 14 | $('#isinForm').formValidation(); 15 | 16 | this.fv = $('#isinForm').data('formValidation'); 17 | this.$isin = this.fv.getFieldElements('isin'); 18 | }); 19 | 20 | afterEach(function() { 21 | $('#isinForm').formValidation('destroy').parent().remove(); 22 | }); 23 | 24 | it('valid', function() { 25 | var samples = ['US0378331005', 'AU0000XVGZA3', 'GB0002634946']; 26 | 27 | for (var i in samples) { 28 | this.$isin.val(samples[i]); 29 | this.fv.validate(); 30 | expect(this.fv.isValidField('isin')).toBeTruthy(); 31 | } 32 | }); 33 | 34 | it('invalid country code', function() { 35 | this.$isin.val('AA0000XVGZA3'); 36 | this.fv.validate(); 37 | expect(this.fv.isValidField('isin')).toEqual(false); 38 | }); 39 | 40 | it('contains only digits and alphabet', function() { 41 | this.$isin.val('US12345ABC@#$'); 42 | this.fv.validate(); 43 | expect(this.fv.isValidField('isin')).toEqual(false); 44 | }); 45 | 46 | it('invalid length', function() { 47 | this.$isin.val('US1234567'); 48 | this.fv.validate(); 49 | expect(this.fv.isValidField('isin')).toEqual(false); 50 | }); 51 | 52 | it('invalid check digit', function() { 53 | this.$isin.val('US0378331004'); 54 | this.fv.validate(); 55 | expect(this.fv.isValidField('isin')).toEqual(false); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/js/validator/numeric.js: -------------------------------------------------------------------------------- 1 | /** 2 | * numeric validator 3 | * 4 | * @link http://formvalidation.io/validators/numeric/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | numeric: { 13 | 'default': 'Please enter a valid float number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.numeric = { 19 | html5Attributes: { 20 | message: 'message', 21 | separator: 'separator' 22 | }, 23 | 24 | enableByHtml5: function($field) { 25 | return ('number' === $field.attr('type')) && ($field.attr('step') !== undefined) && ($field.attr('step') % 1 !== 0); 26 | }, 27 | 28 | /** 29 | * Validate decimal number 30 | * 31 | * @param {FormValidation.Base} validator The validator plugin instance 32 | * @param {jQuery} $field Field element 33 | * @param {Object} options Consist of key: 34 | * - message: The invalid message 35 | * - separator: The decimal separator. Can be "." (default), "," 36 | * @returns {Boolean} 37 | */ 38 | validate: function(validator, $field, options) { 39 | if (this.enableByHtml5($field) && $field.get(0).validity && $field.get(0).validity.badInput === true) { 40 | return false; 41 | } 42 | 43 | var value = validator.getFieldValue($field, 'numeric'); 44 | if (value === '') { 45 | return true; 46 | } 47 | var separator = options.separator || '.'; 48 | if (separator !== '.') { 49 | value = value.replace(separator, '.'); 50 | } 51 | 52 | return !isNaN(parseFloat(value)) && isFinite(value); 53 | } 54 | }; 55 | }(jQuery)); 56 | -------------------------------------------------------------------------------- /test/spec/validator/ismn.js: -------------------------------------------------------------------------------- 1 | describe('ismn', function() { 2 | beforeEach(function() { 3 | var html = [ 4 | '
', 5 | '
', 6 | '
', 7 | '', 8 | '
', 9 | '
', 10 | '
' 11 | ].join('\n'); 12 | 13 | $(html).appendTo('body'); 14 | $('#ismnForm').formValidation(); 15 | 16 | this.fv = $('#ismnForm').data('formValidation'); 17 | this.$ismn = this.fv.getFieldElements('ismn'); 18 | }); 19 | 20 | afterEach(function() { 21 | $('#ismnForm').formValidation('destroy').parent().remove(); 22 | }); 23 | 24 | it('valid start with M', function() { 25 | this.$ismn.val('M230671187'); 26 | this.fv.validate(); 27 | expect(this.fv.isValidField('ismn')).toBeTruthy(); 28 | }); 29 | 30 | it('valid start with 979', function() { 31 | this.$ismn.val('9790060115615'); 32 | this.fv.validate(); 33 | expect(this.fv.isValidField('ismn')).toBeTruthy(); 34 | }); 35 | 36 | it('valid contains spaces', function() { 37 | this.$ismn.val('979 0 3452 4680 5'); 38 | this.fv.validate(); 39 | expect(this.fv.isValidField('ismn')).toBeTruthy(); 40 | }); 41 | 42 | it('valid contains dashes', function() { 43 | this.$ismn.val('979-0-0601-1561-5'); 44 | this.fv.validate(); 45 | expect(this.fv.isValidField('ismn')).toBeTruthy(); 46 | }); 47 | 48 | it('invalid format', function() { 49 | this.$ismn.val('N123456789'); 50 | this.fv.validate(); 51 | expect(this.fv.isValidField('ismn')).toEqual(false); 52 | }); 53 | 54 | it('invalid check digit', function() { 55 | this.$ismn.val('9790060115614'); 56 | this.fv.validate(); 57 | expect(this.fv.isValidField('ismn')).toEqual(false); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /test/spec/validator/identical.js: -------------------------------------------------------------------------------- 1 | describe('identical', function() { 2 | beforeEach(function() { 3 | $([ 4 | '
', 5 | '
', 6 | '', 7 | '
', 8 | '
', 9 | '', 10 | '
', 11 | '
', 12 | '', 13 | '
', 14 | '
' 15 | ].join('\n')).appendTo('body'); 16 | 17 | $('#identicalForm').formValidation(); 18 | 19 | this.fv = $('#identicalForm').data('formValidation'); 20 | this.$a = this.fv.getFieldElements('a'); 21 | this.$b = this.fv.getFieldElements('b'); 22 | }); 23 | 24 | afterEach(function () { 25 | $('#identicalForm').formValidation('destroy').remove(); 26 | }); 27 | 28 | // #1267 29 | it('compare to field which does not use any validators', function() { 30 | this.$a.val('123'); 31 | this.$b.val('123abc'); 32 | this.fv.validate(); 33 | expect(this.fv.isValid()).toEqual(false); 34 | 35 | this.fv.resetForm(); 36 | this.$a.val('123456'); 37 | this.$b.val('123456'); 38 | this.fv.validate(); 39 | expect(this.fv.isValid()).toEqual(true); 40 | }); 41 | 42 | it('compare to hidden field', function() { 43 | this.$b.attr('data-fv-identical-field', 'hiddenField'); 44 | 45 | this.fv = $('#identicalForm').formValidation('destroy').formValidation().data('formValidation'); 46 | this.$b.val('123abc'); 47 | this.fv.validate(); 48 | expect(this.fv.isValid()).toEqual(false); 49 | 50 | this.fv.resetForm(); 51 | this.$b.val('abcdef'); 52 | this.fv.validate(); 53 | expect(this.fv.isValid()).toEqual(true); 54 | }); 55 | }); -------------------------------------------------------------------------------- /src/js/validator/callback.js: -------------------------------------------------------------------------------- 1 | /** 2 | * callback validator 3 | * 4 | * @link http://formvalidation.io/validators/callback/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | callback: { 13 | 'default': 'Please enter a valid value' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.callback = { 19 | html5Attributes: { 20 | message: 'message', 21 | callback: 'callback' 22 | }, 23 | 24 | /** 25 | * Return result from the callback method 26 | * 27 | * @param {FormValidation.Base} validator The validator plugin instance 28 | * @param {jQuery} $field Field element 29 | * @param {Object} options Can consist of the following keys: 30 | * - callback: The callback method that passes 2 parameters: 31 | * callback: function(fieldValue, validator, $field) { 32 | * // fieldValue is the value of field 33 | * // validator is instance of BootstrapValidator 34 | * // $field is the field element 35 | * } 36 | * - message: The invalid message 37 | * @returns {Deferred} 38 | */ 39 | validate: function(validator, $field, options) { 40 | var value = validator.getFieldValue($field, 'callback'), 41 | dfd = new $.Deferred(), 42 | result = { valid: true }; 43 | 44 | if (options.callback) { 45 | var response = FormValidation.Helper.call(options.callback, [value, validator, $field]); 46 | result = ('boolean' === typeof response || null === response) ? { valid: response } : response; 47 | } 48 | 49 | dfd.resolve($field, 'callback', result); 50 | return dfd; 51 | } 52 | }; 53 | }(jQuery)); 54 | -------------------------------------------------------------------------------- /src/js/validator/issn.js: -------------------------------------------------------------------------------- 1 | /** 2 | * issn validator 3 | * 4 | * @link http://formvalidation.io/validators/issn/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | issn: { 13 | 'default': 'Please enter a valid ISSN number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.issn = { 19 | /** 20 | * Validate ISSN (International Standard Serial Number) 21 | * Examples: 22 | * - Valid: 0378-5955, 0024-9319, 0032-1478 23 | * - Invalid: 0032-147X 24 | * 25 | * @see http://en.wikipedia.org/wiki/International_Standard_Serial_Number 26 | * @param {FormValidation.Base} validator The validator plugin instance 27 | * @param {jQuery} $field Field element 28 | * @param {Object} options Can consist of the following keys: 29 | * - message: The invalid message 30 | * @returns {Boolean} 31 | */ 32 | validate: function(validator, $field, options) { 33 | var value = validator.getFieldValue($field, 'issn'); 34 | if (value === '') { 35 | return true; 36 | } 37 | 38 | // Groups are separated by a hyphen or a space 39 | if (!/^\d{4}\-\d{3}[\dX]$/.test(value)) { 40 | return false; 41 | } 42 | 43 | // Replace all special characters except digits and X 44 | value = value.replace(/[^0-9X]/gi, ''); 45 | var chars = value.split(''), 46 | length = chars.length, 47 | sum = 0; 48 | 49 | if (chars[7] === 'X') { 50 | chars[7] = 10; 51 | } 52 | for (var i = 0; i < length; i++) { 53 | sum += parseInt(chars[i], 10) * (8 - i); 54 | } 55 | return (sum % 11 === 0); 56 | } 57 | }; 58 | }(jQuery)); 59 | -------------------------------------------------------------------------------- /src/js/validator/imo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * imo validator 3 | * 4 | * @link http://formvalidation.io/validators/imo/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | imo: { 13 | 'default': 'Please enter a valid IMO number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.imo = { 19 | /** 20 | * Validate IMO (International Maritime Organization) 21 | * Examples: 22 | * - Valid: IMO 8814275, IMO 9176187 23 | * - Invalid: IMO 8814274 24 | * 25 | * @see http://en.wikipedia.org/wiki/IMO_Number 26 | * @param {FormValidation.Base} validator The validator plugin instance 27 | * @param {jQuery} $field Field element 28 | * @param {Object} options Can consist of the following keys: 29 | * - message: The invalid message 30 | * @returns {Boolean} 31 | */ 32 | validate: function(validator, $field, options) { 33 | var value = validator.getFieldValue($field, 'imo'); 34 | if (value === '') { 35 | return true; 36 | } 37 | 38 | if (!/^IMO \d{7}$/i.test(value)) { 39 | return false; 40 | } 41 | 42 | // Grab just the digits 43 | var sum = 0, 44 | digits = value.replace(/^.*(\d{7})$/, '$1'); 45 | 46 | // Go over each char, multiplying by the inverse of it's position 47 | // IMO 9176187 48 | // (9 * 7) + (1 * 6) + (7 * 5) + (6 * 4) + (1 * 3) + (8 * 2) = 147 49 | // Take the last digit of that, that's the check digit (7) 50 | for (var i = 6; i >= 1; i--) { 51 | sum += (digits.slice((6 - i), -i) * (i + 1)); 52 | } 53 | 54 | return sum % 10 === parseInt(digits.charAt(6), 10); 55 | } 56 | }; 57 | }(jQuery)); 58 | -------------------------------------------------------------------------------- /dist/js/framework/foundation.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * FormValidation (http://formvalidation.io) 3 | * The best jQuery plugin to validate form fields. Support Bootstrap, Foundation, Pure, SemanticUI, UIKit and custom frameworks 4 | * 5 | * @version v0.6.2-dev, built on 2015-03-13 8:15:46 AM 6 | * @author https://twitter.com/nghuuphuoc 7 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 8 | * @license http://formvalidation.io/license/ 9 | */ 10 | !function(a){FormValidation.Framework.Foundation=function(b,c){c=a.extend(!0,{button:{selector:'[type="submit"]',disabled:"disabled"},err:{clazz:"error",parent:"^.*((small|medium|large)-[0-9]+)\\s.*(columns).*$"},icon:{valid:null,invalid:null,validating:null,feedback:"fv-control-feedback"},row:{selector:".row",valid:"fv-has-success",invalid:"error",feedback:"fv-has-feedback"}},c),FormValidation.Base.apply(this,[b,c])},FormValidation.Framework.Foundation.prototype=a.extend({},FormValidation.Base.prototype,{_fixIcon:function(a,b){var c=this._namespace,d=a.attr("type"),e=a.attr("data-"+c+"-field"),f=this.options.fields[e].row||this.options.row.selector,g=a.closest(f);if("checkbox"===d||"radio"===d){var h=b.next();h.is("label")&&b.insertAfter(h)}0===g.find("label").length&&b.addClass("fv-icon-no-label")},_createTooltip:function(a,b,c){var d=this,e=a.data("fv.icon");e&&(e.attr("title",b).css({cursor:"pointer"}).off("mouseenter.container.fv focusin.container.fv").on("mouseenter.container.fv",function(){d._showTooltip(a,c)}).off("mouseleave.container.fv focusout.container.fv").on("mouseleave.container.fv focusout.container.fv",function(){d._hideTooltip(a,c)}),Foundation.libs.tooltip.create(e),e.data("fv.foundation.tooltip",e))},_destroyTooltip:function(a){var b=a.data("fv.icon");if(b){b.css({cursor:""});var c=b.data("fv.foundation.tooltip");c&&(c.off(".fndtn.tooltip"),Foundation.libs.tooltip.hide(c),b.removeData("fv.foundation.tooltip"))}},_hideTooltip:function(a){var b=a.data("fv.icon");if(b){b.css({cursor:""});var c=b.data("fv.foundation.tooltip");c&&Foundation.libs.tooltip.hide(c)}},_showTooltip:function(a){var b=a.data("fv.icon");if(b){var c=b.data("fv.foundation.tooltip");c&&(b.css({cursor:"pointer"}),Foundation.libs.tooltip.show(c))}}})}(jQuery); -------------------------------------------------------------------------------- /src/js/validator/imei.js: -------------------------------------------------------------------------------- 1 | /** 2 | * imei validator 3 | * 4 | * @link http://formvalidation.io/validators/imei/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | imei: { 13 | 'default': 'Please enter a valid IMEI number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.imei = { 19 | /** 20 | * Validate IMEI (International Mobile Station Equipment Identity) 21 | * Examples: 22 | * - Valid: 35-209900-176148-1, 35-209900-176148-23, 3568680000414120, 490154203237518 23 | * - Invalid: 490154203237517 24 | * 25 | * @see http://en.wikipedia.org/wiki/International_Mobile_Station_Equipment_Identity 26 | * @param {FormValidation.Base} validator The validator plugin instance 27 | * @param {jQuery} $field Field element 28 | * @param {Object} options Can consist of the following keys: 29 | * - message: The invalid message 30 | * @returns {Boolean} 31 | */ 32 | validate: function(validator, $field, options) { 33 | var value = validator.getFieldValue($field, 'imei'); 34 | if (value === '') { 35 | return true; 36 | } 37 | 38 | switch (true) { 39 | case /^\d{15}$/.test(value): 40 | case /^\d{2}-\d{6}-\d{6}-\d{1}$/.test(value): 41 | case /^\d{2}\s\d{6}\s\d{6}\s\d{1}$/.test(value): 42 | value = value.replace(/[^0-9]/g, ''); 43 | return FormValidation.Helper.luhn(value); 44 | 45 | case /^\d{14}$/.test(value): 46 | case /^\d{16}$/.test(value): 47 | case /^\d{2}-\d{6}-\d{6}(|-\d{2})$/.test(value): 48 | case /^\d{2}\s\d{6}\s\d{6}(|\s\d{2})$/.test(value): 49 | return true; 50 | 51 | default: 52 | return false; 53 | } 54 | } 55 | }; 56 | }(jQuery)); 57 | -------------------------------------------------------------------------------- /test/spec/validator/ein.js: -------------------------------------------------------------------------------- 1 | describe('ein', function() { 2 | beforeEach(function() { 3 | $([ 4 | '
', 5 | '
', 6 | '', 7 | '
', 8 | '
' 9 | ].join('\n')).appendTo('body'); 10 | $('#einForm').formValidation(); 11 | 12 | this.fv = $('#einForm').data('formValidation'); 13 | this.$ein = this.fv.getFieldElements('ein'); 14 | }); 15 | 16 | afterEach(function() { 17 | $('#einForm').formValidation('destroy').remove(); 18 | }); 19 | 20 | it('valid', function() { 21 | var samples = ['01-1234567', '91-1144442', '011234567']; 22 | 23 | for (var i in samples) { 24 | this.fv.resetForm(); 25 | this.$ein.val(samples[i]); 26 | this.fv.validate(); 27 | expect(this.fv.isValid()).toBeTruthy(); 28 | } 29 | }); 30 | 31 | it('invalid format', function() { 32 | var samples = ['123-45-6789']; 33 | 34 | for (var i in samples) { 35 | this.fv.resetForm(); 36 | this.$ein.val(samples[i]); 37 | this.fv.validate(); 38 | expect(this.fv.isValid()).toEqual(false); 39 | } 40 | }); 41 | 42 | it('invalid campus', function() { 43 | var samples = ['00-1234567', '07-1144442', '49-1234567']; 44 | 45 | for (var i in samples) { 46 | this.fv.resetForm(); 47 | this.$ein.val(samples[i]); 48 | this.fv.validate(); 49 | expect(this.fv.isValid()).toEqual(false); 50 | } 51 | }); 52 | 53 | it('campus', function() { 54 | $('#einForm').on('success.field.fv', function(e, data) { 55 | expect(data.result.campus).toEqual(data.element.attr('data-campus')); 56 | }); 57 | 58 | var samples = { 59 | AUSTIN: '50-1234567', 60 | BROOKHAVEN: '04-2103594', 61 | SMALL_BUSINESS_ADMINISTRATION: '31-1234567' 62 | }; 63 | 64 | for (var i in samples) { 65 | this.fv.resetForm(); 66 | this.$ein.val(samples[i]).attr('data-campus', i); 67 | this.fv.validate(); 68 | } 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /src/js/validator/vin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * vin validator 3 | * 4 | * @link http://formvalidation.io/validators/vin/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | vin: { 13 | 'default': 'Please enter a valid VIN number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.vin = { 19 | /** 20 | * Validate an US VIN (Vehicle Identification Number) 21 | * 22 | * @param {FormValidation.Base} validator The validator plugin instance 23 | * @param {jQuery} $field Field element 24 | * @param {Object} options Consist of key: 25 | * - message: The invalid message 26 | * @returns {Boolean} 27 | */ 28 | validate: function(validator, $field, options) { 29 | var value = validator.getFieldValue($field, 'vin'); 30 | if (value === '') { 31 | return true; 32 | } 33 | 34 | // Don't accept I, O, Q characters 35 | if (!/^[a-hj-npr-z0-9]{8}[0-9xX][a-hj-npr-z0-9]{8}$/i.test(value)) { 36 | return false; 37 | } 38 | 39 | value = value.toUpperCase(); 40 | var chars = { 41 | A: 1, B: 2, C: 3, D: 4, E: 5, F: 6, G: 7, H: 8, 42 | J: 1, K: 2, L: 3, M: 4, N: 5, P: 7, R: 9, 43 | S: 2, T: 3, U: 4, V: 5, W: 6, X: 7, Y: 8, Z: 9, 44 | '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '0': 0 45 | }, 46 | weights = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2], 47 | sum = 0, 48 | length = value.length; 49 | for (var i = 0; i < length; i++) { 50 | sum += chars[value.charAt(i) + ''] * weights[i]; 51 | } 52 | 53 | var reminder = sum % 11; 54 | if (reminder === 10) { 55 | reminder = 'X'; 56 | } 57 | 58 | return (reminder + '') === value.charAt(8); 59 | } 60 | }; 61 | }(jQuery)); 62 | -------------------------------------------------------------------------------- /test/spec/validator/isbn.js: -------------------------------------------------------------------------------- 1 | describe('isbn', function() { 2 | beforeEach(function() { 3 | var html = [ 4 | '
', 5 | '
', 6 | '
', 7 | '', 8 | '
', 9 | '
', 10 | '
' 11 | ].join('\n'); 12 | 13 | $(html).appendTo('body'); 14 | $('#isbnForm').formValidation(); 15 | 16 | this.fv = $('#isbnForm').data('formValidation'); 17 | this.$isbn = this.fv.getFieldElements('isbn'); 18 | }); 19 | 20 | afterEach(function() { 21 | $('#isbnForm').formValidation('destroy').parent().remove(); 22 | }); 23 | 24 | it('isbn10 hyphen', function() { 25 | var samples = ['99921-58-10-7', '9971-5-0210-0', '960-425-059-0', '80-902734-1-6']; 26 | 27 | for (var i in samples) { 28 | this.$isbn.val(samples[i]); 29 | this.fv.validate(); 30 | expect(this.fv.isValidField('isbn')).toBeTruthy(); 31 | } 32 | }); 33 | 34 | it('isbn10 space', function() { 35 | var samples = ['85 359 0277 5', '1 84356 028 3', '0 684 84328 5', '0 85131 041 9', '0 943396 04 2']; 36 | 37 | for (var i in samples) { 38 | this.$isbn.val(samples[i]); 39 | this.fv.validate(); 40 | expect(this.fv.isValidField('isbn')).toBeTruthy(); 41 | } 42 | }); 43 | 44 | it('isbn10 hyphen with X', function() { 45 | var samples = ['0-8044-2957-X', '0-9752298-0-X']; 46 | for (var i in samples) { 47 | this.$isbn.val(samples[i]); 48 | this.fv.validate(); 49 | expect(this.fv.isValidField('isbn')).toBeTruthy(); 50 | } 51 | }); 52 | 53 | it('isbn10 invalid check digit', function() { 54 | this.$isbn.val('99921-58-10-6'); 55 | this.fv.validate(); 56 | expect(this.fv.isValidField('isbn')).toEqual(false); 57 | }); 58 | 59 | it('isbn13', function() { 60 | this.$isbn.val('978-0-306-40615-7'); 61 | this.fv.validate(); 62 | expect(this.fv.isValidField('isbn')).toBeTruthy(); 63 | }); 64 | 65 | it('isbn13 invalid check digit', function() { 66 | this.$isbn.val('978-0-306-40615-6'); 67 | this.fv.validate(); 68 | expect(this.fv.isValidField('isbn')).toEqual(false); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /src/js/framework/pure.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FormValidation (http://formvalidation.io) 3 | * The best jQuery plugin to validate form fields. Support Bootstrap, Foundation, Pure, SemanticUI, UIKit and custom frameworks 4 | * 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | 10 | /** 11 | * This class supports validating Pure framework (http://purecss.io/) 12 | */ 13 | (function($) { 14 | FormValidation.Framework.Pure = function(element, options) { 15 | options = $.extend(true, { 16 | button: { 17 | selector: '[type="submit"]', 18 | // The class of disabled button 19 | // http://purecss.io/buttons/#disabled-buttons 20 | disabled: 'pure-button-disabled' 21 | }, 22 | err: { 23 | clazz: 'fv-help-block', 24 | parent: '^.*pure-control-group.*$' 25 | }, 26 | // Pure doesn't support feedback icon 27 | icon: { 28 | valid: null, 29 | invalid: null, 30 | validating: null, 31 | feedback: 'fv-control-feedback' 32 | }, 33 | row: { 34 | // http://purecss.io/forms/#aligned-form 35 | selector: '.pure-control-group', 36 | valid: 'fv-has-success', 37 | invalid: 'fv-has-error', 38 | feedback: 'fv-has-feedback' 39 | } 40 | }, options); 41 | 42 | FormValidation.Base.apply(this, [element, options]); 43 | }; 44 | 45 | FormValidation.Framework.Pure.prototype = $.extend({}, FormValidation.Base.prototype, { 46 | /** 47 | * Specific framework might need to adjust the icon position 48 | * 49 | * @param {jQuery} $field The field element 50 | * @param {jQuery} $icon The icon element 51 | */ 52 | _fixIcon: function($field, $icon) { 53 | var ns = this._namespace, 54 | type = $field.attr('type'), 55 | field = $field.attr('data-' + ns + '-field'), 56 | row = this.options.fields[field].row || this.options.row.selector, 57 | $parent = $field.closest(row); 58 | 59 | if ($parent.find('label').length === 0) { 60 | $icon.addClass('fv-icon-no-label'); 61 | } 62 | } 63 | }); 64 | }(jQuery)); 65 | -------------------------------------------------------------------------------- /dist/js/framework/pure.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * FormValidation (http://formvalidation.io) 3 | * The best jQuery plugin to validate form fields. Support Bootstrap, Foundation, Pure, SemanticUI, UIKit and custom frameworks 4 | * 5 | * @version v0.6.2-dev, built on 2015-03-13 8:15:45 AM 6 | * @author https://twitter.com/nghuuphuoc 7 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 8 | * @license http://formvalidation.io/license/ 9 | */ 10 | /** 11 | * This class supports validating Pure framework (http://purecss.io/) 12 | */ 13 | (function($) { 14 | FormValidation.Framework.Pure = function(element, options) { 15 | options = $.extend(true, { 16 | button: { 17 | selector: '[type="submit"]', 18 | // The class of disabled button 19 | // http://purecss.io/buttons/#disabled-buttons 20 | disabled: 'pure-button-disabled' 21 | }, 22 | err: { 23 | clazz: 'fv-help-block', 24 | parent: '^.*pure-control-group.*$' 25 | }, 26 | // Pure doesn't support feedback icon 27 | icon: { 28 | valid: null, 29 | invalid: null, 30 | validating: null, 31 | feedback: 'fv-control-feedback' 32 | }, 33 | row: { 34 | // http://purecss.io/forms/#aligned-form 35 | selector: '.pure-control-group', 36 | valid: 'fv-has-success', 37 | invalid: 'fv-has-error', 38 | feedback: 'fv-has-feedback' 39 | } 40 | }, options); 41 | 42 | FormValidation.Base.apply(this, [element, options]); 43 | }; 44 | 45 | FormValidation.Framework.Pure.prototype = $.extend({}, FormValidation.Base.prototype, { 46 | /** 47 | * Specific framework might need to adjust the icon position 48 | * 49 | * @param {jQuery} $field The field element 50 | * @param {jQuery} $icon The icon element 51 | */ 52 | _fixIcon: function($field, $icon) { 53 | var ns = this._namespace, 54 | type = $field.attr('type'), 55 | field = $field.attr('data-' + ns + '-field'), 56 | row = this.options.fields[field].row || this.options.row.selector, 57 | $parent = $field.closest(row); 58 | 59 | if ($parent.find('label').length === 0) { 60 | $icon.addClass('fv-icon-no-label'); 61 | } 62 | } 63 | }); 64 | }(jQuery)); 65 | -------------------------------------------------------------------------------- /src/js/validator/cusip.js: -------------------------------------------------------------------------------- 1 | /** 2 | * cusip validator 3 | * 4 | * @link http://formvalidation.io/validators/cusip/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | cusip: { 13 | 'default': 'Please enter a valid CUSIP number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.cusip = { 19 | /** 20 | * Validate a CUSIP number 21 | * Examples: 22 | * - Valid: 037833100, 931142103, 14149YAR8, 126650BG6 23 | * - Invalid: 31430F200, 022615AC2 24 | * 25 | * @see http://en.wikipedia.org/wiki/CUSIP 26 | * @param {FormValidation.Base} validator The validator plugin instance 27 | * @param {jQuery} $field Field element 28 | * @param {Object} [options] Can consist of the following keys: 29 | * - message: The invalid message 30 | * @returns {Boolean} 31 | */ 32 | validate: function(validator, $field, options) { 33 | var value = validator.getFieldValue($field, 'cusip'); 34 | if (value === '') { 35 | return true; 36 | } 37 | 38 | value = value.toUpperCase(); 39 | if (!/^[0-9A-Z]{9}$/.test(value)) { 40 | return false; 41 | } 42 | 43 | var converted = $.map(value.split(''), function(item) { 44 | var code = item.charCodeAt(0); 45 | return (code >= 'A'.charCodeAt(0) && code <= 'Z'.charCodeAt(0)) 46 | // Replace A, B, C, ..., Z with 10, 11, ..., 35 47 | ? (code - 'A'.charCodeAt(0) + 10) 48 | : item; 49 | }), 50 | length = converted.length, 51 | sum = 0; 52 | for (var i = 0; i < length - 1; i++) { 53 | var num = parseInt(converted[i], 10); 54 | if (i % 2 !== 0) { 55 | num *= 2; 56 | } 57 | if (num > 9) { 58 | num -= 9; 59 | } 60 | sum += num; 61 | } 62 | 63 | sum = (10 - (sum % 10)) % 10; 64 | return sum === parseInt(converted[length - 1], 10); 65 | } 66 | }; 67 | }(jQuery)); 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FormValidation - [v0.6.1](http://formvalidation.io/download/) 2 | 3 | [http://formvalidation.io](http://formvalidation.io) - The best [jQuery](http://jquery.com/) plugin to validate form fields, designed to use with: 4 | 5 | - [x] [Bootstrap](http://getbootstrap.com/) 6 | - [x] [Foundation](http://foundation.zurb.com/) 7 | - [x] [Pure](http://purecss.io/) 8 | - [x] [Semantic UI](http://semantic-ui.com/) 9 | - [x] [UIKit](http://getuikit.com/) 10 | 11 | It's developed from scratch by [@nghuuphuoc](http://twitter.com/nghuuphuoc). 12 | 13 | __Required__: [jQuery 1.9.1+](http://jquery.com/) 14 | 15 | Screenshots first because we love it! 16 | 17 | __Validating Bootstrap form__ 18 | 19 | ![Screenshot](screenshots/bootstrap.gif) 20 | 21 | __Validating Foundation form__ 22 | 23 | ![Screenshot](screenshots/foundation.gif) 24 | 25 | __Validating Pure form__ 26 | 27 | ![Screenshot](screenshots/pure.gif) 28 | 29 | __Validating Semantic UI form__ 30 | 31 | ![Screenshot](screenshots/semantic.gif) 32 | 33 | __Validating UI Kit form__ 34 | 35 | ![Screenshot](screenshots/uikit.gif) 36 | 37 | ## Live demo 38 | 39 | http://formvalidation.io/examples/ 40 | 41 | There are also many examples located in the [demo](demo) directory. 42 | 43 | You also can run the ```demo``` locally by: 44 | 45 | * Clone the repo: 46 | 47 | ``` 48 | git clone https://github.com/formvalidation/formvalidation.git 49 | ``` 50 | 51 | * Go to the cloned directory and run the command: 52 | 53 | ``` 54 | python -m SimpleHTTPServer 8000 55 | ``` 56 | 57 | * Access the demo at 58 | 59 | ``` 60 | http://localhost:8000/demo/the_demo_file_here.html 61 | ``` 62 | 63 | ## Features 64 | 65 | See the [official website](http://formvalidation.io) for the full list of features 66 | 67 | ## Download 68 | 69 | * Latest version: [v0.6.1](http://formvalidation.io/download/), released on 2015-02-24 70 | * For older versions, look at the [Releases](https://github.com/formvalidation/formvalidation/releases) page 71 | * Release History: Look at the [Change Log](CHANGELOG.md) 72 | 73 | ## Documentation 74 | 75 | * [Official website](http://formvalidation.io) 76 | 77 | ## Author 78 | 79 | The __FormValidation__ plugin is written by Nguyen Huu Phuoc, aka @nghuuphuoc 80 | 81 | * [http://twitter.com/nghuuphuoc](http://twitter.com/nghuuphuoc) 82 | * [http://github.com/nghuuphuoc](http://github.com/nghuuphuoc) 83 | 84 | ## Contribution 85 | 86 | Contributions are welcome! 87 | 88 | Please notice that **your code** may be used as part of a **commercial product** if the pull request is **merged**. 89 | 90 | ## License 91 | 92 | For more information about the license, see http://formvalidation.io/license/ -------------------------------------------------------------------------------- /src/js/validator/uuid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * uuid validator 3 | * 4 | * @link http://formvalidation.io/validators/uuid/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | uuid: { 13 | 'default': 'Please enter a valid UUID number', 14 | version: 'Please enter a valid UUID version %s number' 15 | } 16 | } 17 | }); 18 | 19 | FormValidation.Validator.uuid = { 20 | html5Attributes: { 21 | message: 'message', 22 | version: 'version' 23 | }, 24 | 25 | /** 26 | * Return true if and only if the input value is a valid UUID string 27 | * 28 | * @see http://en.wikipedia.org/wiki/Universally_unique_identifier 29 | * @param {FormValidation.Base} validator The validator plugin instance 30 | * @param {jQuery} $field Field element 31 | * @param {Object} options Consist of key: 32 | * - message: The invalid message 33 | * - version: Can be 3, 4, 5, null 34 | * @returns {Boolean|Object} 35 | */ 36 | validate: function(validator, $field, options) { 37 | var value = validator.getFieldValue($field, 'uuid'); 38 | if (value === '') { 39 | return true; 40 | } 41 | 42 | // See the format at http://en.wikipedia.org/wiki/Universally_unique_identifier#Variants_and_versions 43 | var locale = validator.getLocale(), 44 | patterns = { 45 | '3': /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i, 46 | '4': /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, 47 | '5': /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, 48 | all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i 49 | }, 50 | version = options.version ? (options.version + '') : 'all'; 51 | return { 52 | valid: (null === patterns[version]) ? true : patterns[version].test(value), 53 | message: options.version 54 | ? FormValidation.Helper.format(options.message || FormValidation.I18n[locale].uuid.version, options.version) 55 | : (options.message || FormValidation.I18n[locale].uuid['default']) 56 | }; 57 | } 58 | }; 59 | }(jQuery)); 60 | -------------------------------------------------------------------------------- /src/js/validator/ismn.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ismn validator 3 | * 4 | * @link http://formvalidation.io/validators/ismn/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | ismn: { 13 | 'default': 'Please enter a valid ISMN number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.ismn = { 19 | /** 20 | * Validate ISMN (International Standard Music Number) 21 | * Examples: 22 | * - Valid: M230671187, 979-0-0601-1561-5, 979 0 3452 4680 5, 9790060115615 23 | * - Invalid: 9790060115614 24 | * 25 | * @see http://en.wikipedia.org/wiki/International_Standard_Music_Number 26 | * @param {FormValidation.Base} validator The validator plugin instance 27 | * @param {jQuery} $field Field element 28 | * @param {Object} options Can consist of the following keys: 29 | * - message: The invalid message 30 | * @returns {Boolean} 31 | */ 32 | validate: function(validator, $field, options) { 33 | var value = validator.getFieldValue($field, 'ismn'); 34 | if (value === '') { 35 | return true; 36 | } 37 | 38 | // Groups are separated by a hyphen or a space 39 | var type; 40 | switch (true) { 41 | case /^M\d{9}$/.test(value): 42 | case /^M-\d{4}-\d{4}-\d{1}$/.test(value): 43 | case /^M\s\d{4}\s\d{4}\s\d{1}$/.test(value): 44 | type = 'ISMN10'; 45 | break; 46 | case /^9790\d{9}$/.test(value): 47 | case /^979-0-\d{4}-\d{4}-\d{1}$/.test(value): 48 | case /^979\s0\s\d{4}\s\d{4}\s\d{1}$/.test(value): 49 | type = 'ISMN13'; 50 | break; 51 | default: 52 | return false; 53 | } 54 | 55 | if ('ISMN10' === type) { 56 | value = '9790' + value.substr(1); 57 | } 58 | 59 | // Replace all special characters except digits 60 | value = value.replace(/[^0-9]/gi, ''); 61 | var length = value.length, 62 | sum = 0, 63 | weight = [1, 3]; 64 | for (var i = 0; i < length - 1; i++) { 65 | sum += parseInt(value.charAt(i), 10) * weight[i % 2]; 66 | } 67 | sum = 10 - sum % 10; 68 | return (sum + '' === value.charAt(length - 1)); 69 | } 70 | }; 71 | }(jQuery)); 72 | -------------------------------------------------------------------------------- /test/spec/validator/callback.js: -------------------------------------------------------------------------------- 1 | function validateCaptcha(value, validator, $field) { 2 | var items = $('#captchaOperation').html().split(' '), sum = parseInt(items[0]) + parseInt(items[2]); 3 | return value === sum + ''; 4 | }; 5 | 6 | describe('callback', function() { 7 | beforeEach(function() { 8 | $([ 9 | '
', 10 | '
', 11 | '', 12 | '
', 13 | '', 14 | '
', 15 | '
', 16 | '
', 17 | '
', 18 | '', 19 | '
', 20 | '
', 21 | '
' 22 | ].join('\n')).appendTo('body'); 23 | 24 | $('#callbackForm').formValidation({ 25 | fields: { 26 | captcha: { 27 | validators: { 28 | callback: { 29 | message: 'Wrong answer', 30 | callback: function(value, validator, $field) { 31 | return validateCaptcha(value, validator, $field); 32 | } 33 | } 34 | } 35 | } 36 | } 37 | }); 38 | 39 | this.fv = $('#callbackForm').data('formValidation'); 40 | this.$captcha = this.fv.getFieldElements('captcha'); 41 | this.$declarativeCaptcha = this.fv.getFieldElements('declarativeCaptcha'); 42 | }); 43 | 44 | afterEach(function() { 45 | $('#callbackForm').formValidation('destroy').remove(); 46 | }); 47 | 48 | it('execute the callback', function() { 49 | $('#captchaOperation').html('1 + 2'); 50 | 51 | this.$captcha.val('3'); 52 | this.fv.validate(); 53 | expect(this.fv.isValidField('captcha')).toBeTruthy(); 54 | 55 | this.fv.resetForm(); 56 | this.$captcha.val('5'); 57 | this.fv.validate(); 58 | expect(this.fv.isValidField('captcha')).toEqual(false); 59 | }); 60 | 61 | it('callback declarative', function() { 62 | $('#captchaOperation').html('10 + 20'); 63 | 64 | this.$declarativeCaptcha.val('40'); 65 | this.fv.validate(); 66 | expect(this.fv.isValidField('declarativeCaptcha')).toEqual(false); 67 | 68 | this.fv.resetForm(); 69 | this.$declarativeCaptcha.val('30'); 70 | this.fv.validate(); 71 | expect(this.fv.isValidField('declarativeCaptcha')).toBeTruthy(); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /src/js/validator/ein.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ein validator 3 | * 4 | * @link http://formvalidation.io/validators/ein/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | ein: { 13 | 'default': 'Please enter a valid EIN number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.ein = { 19 | // The first two digits are called campus 20 | // See http://en.wikipedia.org/wiki/Employer_Identification_Number 21 | // http://www.irs.gov/Businesses/Small-Businesses-&-Self-Employed/How-EINs-are-Assigned-and-Valid-EIN-Prefixes 22 | CAMPUS: { 23 | ANDOVER: ['10', '12'], 24 | ATLANTA: ['60', '67'], 25 | AUSTIN: ['50', '53'], 26 | BROOKHAVEN: ['01', '02', '03', '04', '05', '06', '11', '13', '14', '16', '21', '22', '23', '25', '34', '51', '52', '54', '55', '56', '57', '58', '59', '65'], 27 | CINCINNATI: ['30', '32', '35', '36', '37', '38', '61'], 28 | FRESNO: ['15', '24'], 29 | KANSAS_CITY: ['40', '44'], 30 | MEMPHIS: ['94', '95'], 31 | OGDEN: ['80', '90'], 32 | PHILADELPHIA: ['33', '39', '41', '42', '43', '46', '48', '62', '63', '64', '66', '68', '71', '72', '73', '74', '75', '76', '77', '81', '82', '83', '84', '85', '86', '87', '88', '91', '92', '93', '98', '99'], 33 | INTERNET: ['20', '26', '27', '45', '46'], 34 | SMALL_BUSINESS_ADMINISTRATION: ['31'] 35 | }, 36 | 37 | /** 38 | * Validate EIN (Employer Identification Number) which is also known as 39 | * Federal Employer Identification Number (FEIN) or Federal Tax Identification Number 40 | * 41 | * @param {FormValidation.Base} validator The validator plugin instance 42 | * @param {jQuery} $field Field element 43 | * @param {Object} options Can consist of the following keys: 44 | * - message: The invalid message 45 | * @returns {Object|Boolean} 46 | */ 47 | validate: function(validator, $field, options) { 48 | var value = validator.getFieldValue($field, 'ein'); 49 | if (value === '') { 50 | return true; 51 | } 52 | 53 | if (!/^[0-9]{2}-?[0-9]{7}$/.test(value)) { 54 | return false; 55 | } 56 | // Check the first two digits 57 | var campus = value.substr(0, 2) + ''; 58 | for (var key in this.CAMPUS) { 59 | if ($.inArray(campus, this.CAMPUS[key]) !== -1) { 60 | return { 61 | valid: true, 62 | campus: key 63 | }; 64 | } 65 | } 66 | 67 | return false; 68 | } 69 | }; 70 | }(jQuery)); 71 | -------------------------------------------------------------------------------- /src/js/validator/step.js: -------------------------------------------------------------------------------- 1 | /** 2 | * step validator 3 | * 4 | * @link http://formvalidation.io/validators/step/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | step: { 13 | 'default': 'Please enter a valid step of %s' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.step = { 19 | html5Attributes: { 20 | message: 'message', 21 | base: 'baseValue', 22 | step: 'step' 23 | }, 24 | 25 | /** 26 | * Return true if the input value is valid step one 27 | * 28 | * @param {FormValidation.Base} validator The validator plugin instance 29 | * @param {jQuery} $field Field element 30 | * @param {Object} options Can consist of the following keys: 31 | * - baseValue: The base value 32 | * - step: The step 33 | * - message: The invalid message 34 | * @returns {Boolean|Object} 35 | */ 36 | validate: function(validator, $field, options) { 37 | var value = validator.getFieldValue($field, 'step'); 38 | if (value === '') { 39 | return true; 40 | } 41 | 42 | options = $.extend({}, { baseValue: 0, step: 1 }, options); 43 | value = parseFloat(value); 44 | if (!$.isNumeric(value)) { 45 | return false; 46 | } 47 | 48 | var round = function(x, precision) { 49 | var m = Math.pow(10, precision); 50 | x = x * m; 51 | var sign = (x > 0) | -(x < 0), 52 | isHalf = (x % 1 === 0.5 * sign); 53 | if (isHalf) { 54 | return (Math.floor(x) + (sign > 0)) / m; 55 | } else { 56 | return Math.round(x) / m; 57 | } 58 | }, 59 | floatMod = function(x, y) { 60 | if (y === 0.0) { 61 | return 1.0; 62 | } 63 | var dotX = (x + '').split('.'), 64 | dotY = (y + '').split('.'), 65 | precision = ((dotX.length === 1) ? 0 : dotX[1].length) + ((dotY.length === 1) ? 0 : dotY[1].length); 66 | return round(x - y * Math.floor(x / y), precision); 67 | }; 68 | 69 | var locale = validator.getLocale(), 70 | mod = floatMod(value - options.baseValue, options.step); 71 | return { 72 | valid: mod === 0.0 || mod === options.step, 73 | message: FormValidation.Helper.format(options.message || FormValidation.I18n[locale].step['default'], [options.step]) 74 | }; 75 | } 76 | }; 77 | }(jQuery)); 78 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | FormValidation License 2 | --- 3 | 4 | For more information about the license, see http://formvalidation.io/license/ 5 | 6 | ## FormValidation commercial license agreement 7 | 8 | This Commercial License Agreement is a binding legal agreement between you and Nguyen Huu Phuoc. 9 | By installing, copying, or using FormValidation (the Software), you agree to be bound 10 | by these terms of this Agreement. 11 | 12 | ### Grant of license 13 | 14 | Subject to the payment of the fee required and the conditions herein, you are hereby granted 15 | a non-exclusive, non-transferable right to use FormValidation (the Software) to design 16 | and develop commercial applications (Applications). 17 | 18 | ### Developer grant 19 | 20 | The FormValidation Commercial Developer License grants one license for you as one designated 21 | user (Developer) to use the Software for developing Applications. A Developer is an individual 22 | who implements the Software into Applications, most often writing the necessary code to do so. 23 | You must purchase another separate license to the Software for each and any additional Developer, 24 | or purchase a FormValidation Commercial Organization License to cover your entire organization. 25 | 26 | ### Organization grant 27 | 28 | The FormValidation Commercial Organization License grants one license for your Organization 29 | as one designated, collective user (Organization) to use the Software for developing Applications. 30 | There is no limit or restriction of the number of Developers within your Organization who 31 | may develop Applications using the Software. 32 | 33 | ### Usage 34 | 35 | You are granted the right to use and to modify the source code of the Software for use in 36 | Applications. There is no limit or restriction of the number of Applications which use the 37 | Software. You own any original work authored by you. Nguyen Huu Phuoc continues to retain 38 | all copyright and other intellectual property rights in the Software. You are not permitted 39 | to move, remove, edit, or obscure any copyright, trademark, attribution, warning or disclaimer 40 | notices in the Software. 41 | 42 | You may use the Software only to create Applications that are significantly different than 43 | and do not compete with the Software. You are granted the license to distribute the Software 44 | as part of your Applications on a royalty-free basis. Users of your Applications are permitted 45 | to use the Software or your modifications of the Software as part of your Applications. 46 | Users do not need to purchase their own commercial license for the Software, so long as they 47 | are not acting as Developers, developing their own commercial Applications with the Software. 48 | 49 | ### Warranties and remedies 50 | 51 | The Software is provided "as is", without warranty of any kind, express or implied, including 52 | but not limited to the warranties of merchantability, fitness for a particular purpose and 53 | non-infringement. Nguyen Huu Phuoc's entire liability and your exclusive remedy under this 54 | agreement shall be return of the price paid for the Software. -------------------------------------------------------------------------------- /dist/js/framework/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * FormValidation (http://formvalidation.io) 3 | * The best jQuery plugin to validate form fields. Support Bootstrap, Foundation, Pure, SemanticUI, UIKit and custom frameworks 4 | * 5 | * @version v0.6.2-dev, built on 2015-03-13 8:15:46 AM 6 | * @author https://twitter.com/nghuuphuoc 7 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 8 | * @license http://formvalidation.io/license/ 9 | */ 10 | !function(a){FormValidation.Framework.Bootstrap=function(b,c,d){c=a.extend(!0,{button:{selector:'[type="submit"]',disabled:"disabled"},err:{clazz:"help-block",parent:"^(.*)col-(xs|sm|md|lg)-(offset-){0,1}[0-9]+(.*)$"},icon:{valid:null,invalid:null,validating:null,feedback:"form-control-feedback"},row:{selector:".form-group",valid:"has-success",invalid:"has-error",feedback:"has-feedback"}},c),FormValidation.Base.apply(this,[b,c,d])},FormValidation.Framework.Bootstrap.prototype=a.extend({},FormValidation.Base.prototype,{_fixIcon:function(a,b){var c=this._namespace,d=a.attr("type"),e=a.attr("data-"+c+"-field"),f=this.options.fields[e].row||this.options.row.selector,g=a.closest(f);if("checkbox"===d||"radio"===d){var h=a.parent();h.hasClass(d)?b.insertAfter(h):h.parent().hasClass(d)&&b.insertAfter(h.parent())}0===g.find("label").length&&b.addClass("fv-icon-no-label"),0!==g.find(".input-group").length&&b.addClass("fv-bootstrap-icon-input-group").insertAfter(g.find(".input-group").eq(0))},_createTooltip:function(a,b,c){var d=this._namespace,e=a.data(d+".icon");if(e)switch(c){case"popover":e.css({cursor:"pointer","pointer-events":"auto"}).popover("destroy").popover({container:"body",content:b,html:!0,placement:"auto top",trigger:"hover click"});break;case"tooltip":default:e.css({cursor:"pointer","pointer-events":"auto"}).tooltip("destroy").tooltip({container:"body",html:!0,placement:"auto top",title:b})}},_destroyTooltip:function(a,b){var c=this._namespace,d=a.data(c+".icon");if(d)switch(b){case"popover":d.css({cursor:"","pointer-events":"none"}).popover("destroy");break;case"tooltip":default:d.css({cursor:"","pointer-events":"none"}).tooltip("destroy")}},_hideTooltip:function(a,b){var c=this._namespace,d=a.data(c+".icon");if(d)switch(b){case"popover":d.popover("hide");break;case"tooltip":default:d.tooltip("hide")}},_showTooltip:function(a,b){var c=this._namespace,d=a.data(c+".icon");if(d)switch(b){case"popover":d.popover("show");break;case"tooltip":default:d.tooltip("show")}}}),a.fn.bootstrapValidator=function(b){var c=arguments;return this.each(function(){var d=a(this),e=d.data("formValidation")||d.data("bootstrapValidator"),f="object"==typeof b&&b;e||(e=new FormValidation.Framework.Bootstrap(this,a.extend({},{events:{formInit:"init.form.bv",formError:"error.form.bv",formSuccess:"success.form.bv",fieldAdded:"added.field.bv",fieldRemoved:"removed.field.bv",fieldInit:"init.field.bv",fieldError:"error.field.bv",fieldSuccess:"success.field.bv",fieldStatus:"status.field.bv",localeChanged:"changed.locale.bv",validatorError:"error.validator.bv",validatorSuccess:"success.validator.bv"}},f),"bv"),d.addClass("fv-form-bootstrap").data("formValidation",e).data("bootstrapValidator",e)),"string"==typeof b&&e[b].apply(e,Array.prototype.slice.call(c,1))})},a.fn.bootstrapValidator.Constructor=FormValidation.Framework.Bootstrap}(jQuery); -------------------------------------------------------------------------------- /src/js/validator/identical.js: -------------------------------------------------------------------------------- 1 | /** 2 | * identical validator 3 | * 4 | * @link http://formvalidation.io/validators/identical/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | identical: { 13 | 'default': 'Please enter the same value' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.identical = { 19 | html5Attributes: { 20 | message: 'message', 21 | field: 'field' 22 | }, 23 | 24 | /** 25 | * Bind the validator on the live change of the field to compare with current one 26 | * 27 | * @param {FormValidation.Base} validator The validator plugin instance 28 | * @param {jQuery} $field Field element 29 | * @param {Object} options Consists of the following key: 30 | * - field: The name of field that will be used to compare with current one 31 | */ 32 | init: function(validator, $field, options) { 33 | var compareWith = validator.getFieldElements(options.field); 34 | validator.onLiveChange(compareWith, 'live_identical', function() { 35 | var status = validator.getStatus($field, 'identical'); 36 | if (status !== validator.STATUS_NOT_VALIDATED) { 37 | validator.revalidateField($field); 38 | } 39 | }); 40 | }, 41 | 42 | /** 43 | * Unbind the validator on the live change of the field to compare with current one 44 | * 45 | * @param {FormValidation.Base} validator The validator plugin instance 46 | * @param {jQuery} $field Field element 47 | * @param {Object} options Consists of the following key: 48 | * - field: The name of field that will be used to compare with current one 49 | */ 50 | destroy: function(validator, $field, options) { 51 | var compareWith = validator.getFieldElements(options.field); 52 | validator.offLiveChange(compareWith, 'live_identical'); 53 | }, 54 | 55 | /** 56 | * Check if input value equals to value of particular one 57 | * 58 | * @param {FormValidation.Base} validator The validator plugin instance 59 | * @param {jQuery} $field Field element 60 | * @param {Object} options Consists of the following key: 61 | * - field: The name of field that will be used to compare with current one 62 | * @returns {Boolean} 63 | */ 64 | validate: function(validator, $field, options) { 65 | var value = validator.getFieldValue($field, 'identical'), 66 | compareWith = validator.getFieldElements(options.field); 67 | if (compareWith === null || compareWith.length === 0) { 68 | return true; 69 | } 70 | 71 | var compareValue = validator.getFieldValue(compareWith, 'identical'); 72 | if (value === compareValue) { 73 | validator.updateStatus(compareWith, validator.STATUS_VALID, 'identical'); 74 | return true; 75 | } 76 | 77 | return false; 78 | } 79 | }; 80 | }(jQuery)); 81 | -------------------------------------------------------------------------------- /src/js/validator/lessThan.js: -------------------------------------------------------------------------------- 1 | /** 2 | * lessThan validator 3 | * 4 | * @link http://formvalidation.io/validators/lessThan/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | lessThan: { 13 | 'default': 'Please enter a value less than or equal to %s', 14 | notInclusive: 'Please enter a value less than %s' 15 | } 16 | } 17 | }); 18 | 19 | FormValidation.Validator.lessThan = { 20 | html5Attributes: { 21 | message: 'message', 22 | value: 'value', 23 | inclusive: 'inclusive' 24 | }, 25 | 26 | enableByHtml5: function($field) { 27 | var type = $field.attr('type'), 28 | max = $field.attr('max'); 29 | if (max && type !== 'date') { 30 | return { 31 | value: max 32 | }; 33 | } 34 | 35 | return false; 36 | }, 37 | 38 | /** 39 | * Return true if the input value is less than or equal to given number 40 | * 41 | * @param {FormValidation.Base} validator The validator plugin instance 42 | * @param {jQuery} $field Field element 43 | * @param {Object} options Can consist of the following keys: 44 | * - value: The number used to compare to. It can be 45 | * - A number 46 | * - Name of field which its value defines the number 47 | * - Name of callback function that returns the number 48 | * - A callback function that returns the number 49 | * 50 | * - inclusive [optional]: Can be true or false. Default is true 51 | * - message: The invalid message 52 | * @returns {Boolean|Object} 53 | */ 54 | validate: function(validator, $field, options) { 55 | var value = validator.getFieldValue($field, 'lessThan'); 56 | if (value === '') { 57 | return true; 58 | } 59 | 60 | value = this._format(value); 61 | if (!$.isNumeric(value)) { 62 | return false; 63 | } 64 | 65 | var locale = validator.getLocale(), 66 | compareTo = $.isNumeric(options.value) ? options.value : validator.getDynamicOption($field, options.value), 67 | compareToValue = this._format(compareTo); 68 | 69 | value = parseFloat(value); 70 | return (options.inclusive === true || options.inclusive === undefined) 71 | ? { 72 | valid: value <= compareToValue, 73 | message: FormValidation.Helper.format(options.message || FormValidation.I18n[locale].lessThan['default'], compareTo) 74 | } 75 | : { 76 | valid: value < compareToValue, 77 | message: FormValidation.Helper.format(options.message || FormValidation.I18n[locale].lessThan.notInclusive, compareTo) 78 | }; 79 | }, 80 | 81 | _format: function(value) { 82 | return (value + '').replace(',', '.'); 83 | } 84 | }; 85 | }(jQuery)); 86 | -------------------------------------------------------------------------------- /src/js/validator/greaterThan.js: -------------------------------------------------------------------------------- 1 | /** 2 | * greaterThan validator 3 | * 4 | * @link http://formvalidation.io/validators/greaterThan/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | greaterThan: { 13 | 'default': 'Please enter a value greater than or equal to %s', 14 | notInclusive: 'Please enter a value greater than %s' 15 | } 16 | } 17 | }); 18 | 19 | FormValidation.Validator.greaterThan = { 20 | html5Attributes: { 21 | message: 'message', 22 | value: 'value', 23 | inclusive: 'inclusive' 24 | }, 25 | 26 | enableByHtml5: function($field) { 27 | var type = $field.attr('type'), 28 | min = $field.attr('min'); 29 | if (min && type !== 'date') { 30 | return { 31 | value: min 32 | }; 33 | } 34 | 35 | return false; 36 | }, 37 | 38 | /** 39 | * Return true if the input value is greater than or equals to given number 40 | * 41 | * @param {FormValidation.Base} validator Validate plugin instance 42 | * @param {jQuery} $field Field element 43 | * @param {Object} options Can consist of the following keys: 44 | * - value: Define the number to compare with. It can be 45 | * - A number 46 | * - Name of field which its value defines the number 47 | * - Name of callback function that returns the number 48 | * - A callback function that returns the number 49 | * 50 | * - inclusive [optional]: Can be true or false. Default is true 51 | * - message: The invalid message 52 | * @returns {Boolean|Object} 53 | */ 54 | validate: function(validator, $field, options) { 55 | var value = validator.getFieldValue($field, 'greaterThan'); 56 | if (value === '') { 57 | return true; 58 | } 59 | 60 | value = this._format(value); 61 | if (!$.isNumeric(value)) { 62 | return false; 63 | } 64 | 65 | var locale = validator.getLocale(), 66 | compareTo = $.isNumeric(options.value) ? options.value : validator.getDynamicOption($field, options.value), 67 | compareToValue = this._format(compareTo); 68 | 69 | value = parseFloat(value); 70 | return (options.inclusive === true || options.inclusive === undefined) 71 | ? { 72 | valid: value >= compareToValue, 73 | message: FormValidation.Helper.format(options.message || FormValidation.I18n[locale].greaterThan['default'], compareTo) 74 | } 75 | : { 76 | valid: value > compareToValue, 77 | message: FormValidation.Helper.format(options.message || FormValidation.I18n[locale].greaterThan.notInclusive, compareTo) 78 | }; 79 | }, 80 | 81 | _format: function(value) { 82 | return (value + '').replace(',', '.'); 83 | } 84 | }; 85 | }(jQuery)); 86 | -------------------------------------------------------------------------------- /src/js/validator/isin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * isin validator 3 | * 4 | * @link http://formvalidation.io/validators/isin/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | isin: { 13 | 'default': 'Please enter a valid ISIN number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.isin = { 19 | // Available country codes 20 | // See http://isin.net/country-codes/ 21 | COUNTRY_CODES: 'AF|AX|AL|DZ|AS|AD|AO|AI|AQ|AG|AR|AM|AW|AU|AT|AZ|BS|BH|BD|BB|BY|BE|BZ|BJ|BM|BT|BO|BQ|BA|BW|BV|BR|IO|BN|BG|BF|BI|KH|CM|CA|CV|KY|CF|TD|CL|CN|CX|CC|CO|KM|CG|CD|CK|CR|CI|HR|CU|CW|CY|CZ|DK|DJ|DM|DO|EC|EG|SV|GQ|ER|EE|ET|FK|FO|FJ|FI|FR|GF|PF|TF|GA|GM|GE|DE|GH|GI|GR|GL|GD|GP|GU|GT|GG|GN|GW|GY|HT|HM|VA|HN|HK|HU|IS|IN|ID|IR|IQ|IE|IM|IL|IT|JM|JP|JE|JO|KZ|KE|KI|KP|KR|KW|KG|LA|LV|LB|LS|LR|LY|LI|LT|LU|MO|MK|MG|MW|MY|MV|ML|MT|MH|MQ|MR|MU|YT|MX|FM|MD|MC|MN|ME|MS|MA|MZ|MM|NA|NR|NP|NL|NC|NZ|NI|NE|NG|NU|NF|MP|NO|OM|PK|PW|PS|PA|PG|PY|PE|PH|PN|PL|PT|PR|QA|RE|RO|RU|RW|BL|SH|KN|LC|MF|PM|VC|WS|SM|ST|SA|SN|RS|SC|SL|SG|SX|SK|SI|SB|SO|ZA|GS|SS|ES|LK|SD|SR|SJ|SZ|SE|CH|SY|TW|TJ|TZ|TH|TL|TG|TK|TO|TT|TN|TR|TM|TC|TV|UG|UA|AE|GB|US|UM|UY|UZ|VU|VE|VN|VG|VI|WF|EH|YE|ZM|ZW', 22 | 23 | /** 24 | * Validate an ISIN (International Securities Identification Number) 25 | * Examples: 26 | * - Valid: US0378331005, AU0000XVGZA3, GB0002634946 27 | * - Invalid: US0378331004, AA0000XVGZA3 28 | * 29 | * @see http://en.wikipedia.org/wiki/International_Securities_Identifying_Number 30 | * @param {FormValidation.Base} validator The validator plugin instance 31 | * @param {jQuery} $field Field element 32 | * @param {Object} options Can consist of the following keys: 33 | * - message: The invalid message 34 | * @returns {Boolean} 35 | */ 36 | validate: function(validator, $field, options) { 37 | var value = validator.getFieldValue($field, 'isin'); 38 | if (value === '') { 39 | return true; 40 | } 41 | 42 | value = value.toUpperCase(); 43 | var regex = new RegExp('^(' + this.COUNTRY_CODES + ')[0-9A-Z]{10}$'); 44 | if (!regex.test(value)) { 45 | return false; 46 | } 47 | 48 | var converted = '', 49 | length = value.length; 50 | // Convert letters to number 51 | for (var i = 0; i < length - 1; i++) { 52 | var c = value.charCodeAt(i); 53 | converted += ((c > 57) ? (c - 55).toString() : value.charAt(i)); 54 | } 55 | 56 | var digits = '', 57 | n = converted.length, 58 | group = (n % 2 !== 0) ? 0 : 1; 59 | for (i = 0; i < n; i++) { 60 | digits += (parseInt(converted[i], 10) * ((i % 2) === group ? 2 : 1) + ''); 61 | } 62 | 63 | var sum = 0; 64 | for (i = 0; i < digits.length; i++) { 65 | sum += parseInt(digits.charAt(i), 10); 66 | } 67 | sum = (10 - (sum % 10)) % 10; 68 | return sum + '' === value.charAt(length - 1); 69 | } 70 | }; 71 | }(jQuery)); 72 | -------------------------------------------------------------------------------- /test/spec/dynamic.js: -------------------------------------------------------------------------------- 1 | describe('dynamic fields', function() { 2 | beforeEach(function() { 3 | $([ 4 | '
', 5 | '
', 6 | '', 7 | '
', 8 | '
', 9 | '', 10 | '
', 11 | '
' 12 | ].join('\n')).appendTo('body'); 13 | 14 | $('#dynamicForm').formValidation({ 15 | fields: { 16 | userName: { 17 | validators: { 18 | notEmpty: { 19 | message: 'The user name is required and cannot be empty' 20 | }, 21 | regexp: { 22 | regexp: /^[a-zA-Z]+$/, 23 | message: 'The user name can only consist of alphabetical, number' 24 | } 25 | } 26 | }, 27 | // #725: Note that the email field isn't available in the form yet 28 | email: { 29 | validators: { 30 | emailAddress: { 31 | message: 'The email address is not valid' 32 | } 33 | } 34 | } 35 | } 36 | }); 37 | 38 | this.fv = $('#dynamicForm').data('formValidation'); 39 | this.$userName = this.fv.getFieldElements('userName'); 40 | }); 41 | 42 | afterEach(function() { 43 | $('#dynamicForm').formValidation('destroy').remove(); 44 | }); 45 | 46 | // https://github.com/formvalidation/formvalidation/pull/725 47 | it('adding field [does not exist but is already set in "fields" option]', function() { 48 | var $div = $('
').addClass('form-group').appendTo($('#dynamicForm')); 49 | $email = $('') 50 | .attr('type', 'text') 51 | .addClass('form-control') 52 | .attr('name', 'email') 53 | .appendTo($div); 54 | 55 | this.fv.addField('email'); 56 | 57 | this.$userName.val('FormValidation'); 58 | 59 | $email.val('not valid@email'); 60 | this.fv.validate(); 61 | expect(this.fv.isValidField('email')).toBeFalsy(); 62 | expect(this.fv.isValid()).toBeFalsy(); 63 | 64 | this.fv.resetForm(); 65 | $email.val('valid@email.com'); 66 | this.fv.validate(); 67 | expect(this.fv.isValidField('email')).toBeTruthy(); 68 | expect(this.fv.isValid()).toBeTruthy(); 69 | }); 70 | 71 | // support#48 72 | it('Override the options when adding field', function() { 73 | var options = { 74 | validators: { 75 | stringLength: { 76 | min: 6, 77 | max: 20 78 | } 79 | } 80 | }; 81 | 82 | $('#dynamicForm') 83 | .formValidation('destroy') 84 | .formValidation() 85 | .formValidation('addField', 'userName', options); 86 | 87 | // The options shouldn't contain the notEmpty validator (userName field have required attribute) 88 | expect(options.validators.notEmpty).toBeUndefined(); 89 | }) 90 | }); 91 | -------------------------------------------------------------------------------- /test/spec/api.js: -------------------------------------------------------------------------------- 1 | describe('api', function() { 2 | beforeEach(function() { 3 | $([ 4 | '
', 5 | '
', 6 | '', 7 | '
', 8 | '
', 9 | '', 10 | '
', 11 | '
', 12 | '', 13 | '
', 14 | '
' 15 | ].join('\n')).appendTo('body'); 16 | 17 | $('#apiForm').formValidation({ 18 | icon: { 19 | valid: 'glyphicon glyphicon-ok', 20 | invalid: 'glyphicon glyphicon-remove', 21 | validating: 'glyphicon glyphicon-refresh' 22 | } 23 | }); 24 | 25 | this.fv = $('#apiForm').data('formValidation'); 26 | this.$email = this.fv.getFieldElements('email'); 27 | this.$note = $('#apiForm').find('input[name="note"]'); 28 | }); 29 | 30 | afterEach(function() { 31 | $('#apiForm').formValidation('destroy').remove(); 32 | }); 33 | 34 | it('revalidateField()', function() { 35 | this.$email.val('email@domain.com'); 36 | this.fv.validate(); 37 | expect(this.fv.isValidField('email')).toBeTruthy(); 38 | 39 | this.$email.val('invalid#email.address'); 40 | this.fv.revalidateField('email'); 41 | expect(this.fv.isValidField(this.$email)).toEqual(false); 42 | }); 43 | 44 | it('destroy()', function() { 45 | this.fv.destroy(); 46 | expect($('#apiForm').data('formValidation')).toBeUndefined(); 47 | expect($('#apiForm').find('i[data-fv-icon-for]').length).toEqual(0); 48 | expect($('#apiForm').find('.help-block[data-fv-for]').length).toEqual(0); 49 | expect($('#apiForm').find('.has-feedback').length).toEqual(0); 50 | expect($('#apiForm').find('.has-success').length).toEqual(0); 51 | expect($('#apiForm').find('.has-error').length).toEqual(0); 52 | expect($('#apiForm').find('[data-fv-field]').length).toEqual(0); 53 | }); 54 | 55 | it('getOptions()', function() { 56 | // Form options 57 | expect(this.fv.getOptions().icon.valid).toEqual('glyphicon glyphicon-ok'); 58 | 59 | // Field options 60 | expect(this.fv.getOptions('username', 'stringlength')).toBeNull(); 61 | expect(this.fv.getOptions('username', 'stringlength', 'min')).toBeNull(); 62 | 63 | expect(this.fv.getOptions('username', 'stringLength')).toBeDefined(); 64 | expect(this.fv.getOptions('username', 'stringLength', 'min')).toEqual('8'); 65 | expect(this.fv.getOptions('username', 'stringlength', 'max')).toBeNull(); 66 | }); 67 | 68 | // #1014 69 | it('isValidField()', function() { 70 | this.$email.val('email@domain.com'); 71 | this.fv.validate(); 72 | expect(this.fv.isValidField(this.$note)).toBeTruthy(); 73 | expect(this.fv.isValidField(this.$email)).toBeTruthy(); 74 | }); 75 | 76 | // #1014 77 | it('validateField()', function() { 78 | this.$email.val('email@domain.com'); 79 | this.fv.validateField(this.$email); 80 | this.fv.validateField(this.$note); 81 | expect(this.fv.isValidField(this.$email)).toBeTruthy(); 82 | expect(this.fv.isValidField(this.$note)).toBeTruthy(); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /src/js/validator/between.js: -------------------------------------------------------------------------------- 1 | /** 2 | * between validator 3 | * 4 | * @link http://formvalidation.io/validators/between/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | between: { 13 | 'default': 'Please enter a value between %s and %s', 14 | notInclusive: 'Please enter a value between %s and %s strictly' 15 | } 16 | } 17 | }); 18 | 19 | FormValidation.Validator.between = { 20 | html5Attributes: { 21 | message: 'message', 22 | min: 'min', 23 | max: 'max', 24 | inclusive: 'inclusive' 25 | }, 26 | 27 | enableByHtml5: function($field) { 28 | if ('range' === $field.attr('type')) { 29 | return { 30 | min: $field.attr('min'), 31 | max: $field.attr('max') 32 | }; 33 | } 34 | 35 | return false; 36 | }, 37 | 38 | /** 39 | * Return true if the input value is between (strictly or not) two given numbers 40 | * 41 | * @param {FormValidation.Base} validator The validator plugin instance 42 | * @param {jQuery} $field Field element 43 | * @param {Object} options Can consist of the following keys: 44 | * - min 45 | * - max 46 | * 47 | * The min, max keys define the number which the field value compares to. min, max can be 48 | * - A number 49 | * - Name of field which its value defines the number 50 | * - Name of callback function that returns the number 51 | * - A callback function that returns the number 52 | * 53 | * - inclusive [optional]: Can be true or false. Default is true 54 | * - message: The invalid message 55 | * @returns {Boolean|Object} 56 | */ 57 | validate: function(validator, $field, options) { 58 | var value = validator.getFieldValue($field, 'between'); 59 | if (value === '') { 60 | return true; 61 | } 62 | 63 | value = this._format(value); 64 | if (!$.isNumeric(value)) { 65 | return false; 66 | } 67 | 68 | var locale = validator.getLocale(), 69 | min = $.isNumeric(options.min) ? options.min : validator.getDynamicOption($field, options.min), 70 | max = $.isNumeric(options.max) ? options.max : validator.getDynamicOption($field, options.max), 71 | minValue = this._format(min), 72 | maxValue = this._format(max); 73 | 74 | value = parseFloat(value); 75 | return (options.inclusive === true || options.inclusive === undefined) 76 | ? { 77 | valid: value >= minValue && value <= maxValue, 78 | message: FormValidation.Helper.format(options.message || FormValidation.I18n[locale].between['default'], [min, max]) 79 | } 80 | : { 81 | valid: value > minValue && value < maxValue, 82 | message: FormValidation.Helper.format(options.message || FormValidation.I18n[locale].between.notInclusive, [min, max]) 83 | }; 84 | }, 85 | 86 | _format: function(value) { 87 | return (value + '').replace(',', '.'); 88 | } 89 | }; 90 | }(jQuery)); 91 | -------------------------------------------------------------------------------- /src/js/validator/choice.js: -------------------------------------------------------------------------------- 1 | /** 2 | * choice validator 3 | * 4 | * @link http://formvalidation.io/validators/choice/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | choice: { 13 | 'default': 'Please enter a valid value', 14 | less: 'Please choose %s options at minimum', 15 | more: 'Please choose %s options at maximum', 16 | between: 'Please choose %s - %s options' 17 | } 18 | } 19 | }); 20 | 21 | FormValidation.Validator.choice = { 22 | html5Attributes: { 23 | message: 'message', 24 | min: 'min', 25 | max: 'max' 26 | }, 27 | 28 | /** 29 | * Check if the number of checked boxes are less or more than a given number 30 | * 31 | * @param {FormValidation.Base} validator The validator plugin instance 32 | * @param {jQuery} $field Field element 33 | * @param {Object} options Consists of following keys: 34 | * - min 35 | * - max 36 | * 37 | * At least one of two keys is required 38 | * The min, max keys define the number which the field value compares to. min, max can be 39 | * - A number 40 | * - Name of field which its value defines the number 41 | * - Name of callback function that returns the number 42 | * - A callback function that returns the number 43 | * 44 | * - message: The invalid message 45 | * @returns {Object} 46 | */ 47 | validate: function(validator, $field, options) { 48 | var locale = validator.getLocale(), 49 | ns = validator.getNamespace(), 50 | numChoices = $field.is('select') 51 | ? validator.getFieldElements($field.attr('data-' + ns + '-field')).find('option').filter(':selected').length 52 | : validator.getFieldElements($field.attr('data-' + ns + '-field')).filter(':checked').length, 53 | min = options.min ? ($.isNumeric(options.min) ? options.min : validator.getDynamicOption($field, options.min)) : null, 54 | max = options.max ? ($.isNumeric(options.max) ? options.max : validator.getDynamicOption($field, options.max)) : null, 55 | isValid = true, 56 | message = options.message || FormValidation.I18n[locale].choice['default']; 57 | 58 | if ((min && numChoices < parseInt(min, 10)) || (max && numChoices > parseInt(max, 10))) { 59 | isValid = false; 60 | } 61 | 62 | switch (true) { 63 | case (!!min && !!max): 64 | message = FormValidation.Helper.format(options.message || FormValidation.I18n[locale].choice.between, [parseInt(min, 10), parseInt(max, 10)]); 65 | break; 66 | 67 | case (!!min): 68 | message = FormValidation.Helper.format(options.message || FormValidation.I18n[locale].choice.less, parseInt(min, 10)); 69 | break; 70 | 71 | case (!!max): 72 | message = FormValidation.Helper.format(options.message || FormValidation.I18n[locale].choice.more, parseInt(max, 10)); 73 | break; 74 | 75 | default: 76 | break; 77 | } 78 | 79 | return { valid: isValid, message: message }; 80 | } 81 | }; 82 | }(jQuery)); 83 | -------------------------------------------------------------------------------- /test/spec/autoFocus.js: -------------------------------------------------------------------------------- 1 | describe('autoFocus', function() { 2 | // Use $element.is(document.activeElement) instead of $element.is(':focus') 3 | // to support running the test cases with PhantomJS 4 | // See https://github.com/ariya/phantomjs/issues/10427 5 | 6 | beforeEach(function() { 7 | $([ 8 | '
', 9 | '
', 10 | '', 11 | '
', 12 | '
', 13 | '', 14 | '
', 15 | '
', 16 | '', 17 | '
', 18 | '
' 19 | ].join('')).appendTo('body'); 20 | 21 | this.fv = $('#autoFocusForm') 22 | .formValidation() 23 | .submit(function(e) { 24 | e.preventDefault(); 25 | }) 26 | .data('formValidation'); 27 | this.$username = this.fv.getFieldElements('username'); 28 | this.$email = this.fv.getFieldElements('email'); 29 | }); 30 | 31 | afterEach(function() { 32 | $('#autoFocusForm').formValidation('destroy').remove(); 33 | }); 34 | 35 | it('default option (autoFocus=true)', function() { 36 | $('#submitButton').click(); 37 | expect(this.$username.is(document.activeElement)).toBeTruthy(); 38 | expect($(document.activeElement).attr('name')).toEqual('username'); 39 | 40 | this.fv.resetForm(); 41 | this.$username.val('user_name'); 42 | this.$email.val(''); 43 | $('#submitButton').click(); 44 | expect(this.$email.is(document.activeElement)).toBeTruthy(); 45 | expect($(document.activeElement).attr('name')).toEqual('email'); 46 | }); 47 | 48 | it('set autoFocus=false for form', function() { 49 | $('#autoFocusForm') 50 | .formValidation('destroy') 51 | .formValidation({ 52 | autoFocus: false 53 | }); 54 | this.$username.val(''); 55 | this.$email.val('invalid#email'); 56 | $('#submitButton').click(); 57 | 58 | expect(this.$username.is(document.activeElement)).toBeFalsy(); 59 | expect(this.$email.is(document.activeElement)).toBeFalsy(); 60 | }); 61 | 62 | it('set autoFocus=false for all fields', function() { 63 | this.fv 64 | .addField('username', { 65 | autoFocus: false 66 | }) 67 | .addField('email', { 68 | autoFocus: false 69 | }); 70 | this.$username.val('user_name'); 71 | this.$email.val('invalid#email'); 72 | $('#submitButton').click(); 73 | 74 | expect(this.$username.is(document.activeElement)).toBeFalsy(); 75 | expect(this.$email.is(document.activeElement)).toBeFalsy(); 76 | }); 77 | 78 | it('set different autoFocus value for fields', function() { 79 | this.fv 80 | .addField('username', { 81 | autoFocus: false 82 | }) 83 | .addField('email', { 84 | autoFocus: true 85 | }); 86 | this.$username.val(''); 87 | this.$email.val('invalid_email'); 88 | $('#submitButton').click(); 89 | 90 | expect(this.$username.is(document.activeElement)).toBeFalsy(); 91 | expect(this.$email.is(document.activeElement)).toBeTruthy(); 92 | expect($(document.activeElement).attr('name')).toEqual('email'); 93 | }); 94 | }); 95 | -------------------------------------------------------------------------------- /demo/event2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FormValidation demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 21 | 22 |
23 |
24 | 25 |
26 |
27 | Singapore 28 | 29 |
30 |
31 |
32 | 33 |
34 |
35 | 36 |
37 |
38 | 39 |
40 |
41 |
42 |
43 |
44 |
45 | 46 | 88 | 89 | -------------------------------------------------------------------------------- /src/js/validator/ip.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ip validator 3 | * 4 | * @link http://formvalidation.io/validators/ip/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | ip: { 13 | 'default': 'Please enter a valid IP address', 14 | ipv4: 'Please enter a valid IPv4 address', 15 | ipv6: 'Please enter a valid IPv6 address' 16 | } 17 | } 18 | }); 19 | 20 | FormValidation.Validator.ip = { 21 | html5Attributes: { 22 | message: 'message', 23 | ipv4: 'ipv4', 24 | ipv6: 'ipv6' 25 | }, 26 | 27 | /** 28 | * Return true if the input value is a IP address. 29 | * 30 | * @param {FormValidation.Base} validator The validator plugin instance 31 | * @param {jQuery} $field Field element 32 | * @param {Object} options Can consist of the following keys: 33 | * - ipv4: Enable IPv4 validator, default to true 34 | * - ipv6: Enable IPv6 validator, default to true 35 | * - message: The invalid message 36 | * @returns {Boolean|Object} 37 | */ 38 | validate: function(validator, $field, options) { 39 | var value = validator.getFieldValue($field, 'ip'); 40 | if (value === '') { 41 | return true; 42 | } 43 | options = $.extend({}, { ipv4: true, ipv6: true }, options); 44 | 45 | var locale = validator.getLocale(), 46 | ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/, 47 | ipv6Regex = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/, 48 | valid = false, 49 | message; 50 | 51 | switch (true) { 52 | case (options.ipv4 && !options.ipv6): 53 | valid = ipv4Regex.test(value); 54 | message = options.message || FormValidation.I18n[locale].ip.ipv4; 55 | break; 56 | 57 | case (!options.ipv4 && options.ipv6): 58 | valid = ipv6Regex.test(value); 59 | message = options.message || FormValidation.I18n[locale].ip.ipv6; 60 | break; 61 | 62 | case (options.ipv4 && options.ipv6): 63 | /* falls through */ 64 | default: 65 | valid = ipv4Regex.test(value) || ipv6Regex.test(value); 66 | message = options.message || FormValidation.I18n[locale].ip['default']; 67 | break; 68 | } 69 | 70 | return { 71 | valid: valid, 72 | message: message 73 | }; 74 | } 75 | }; 76 | }(jQuery)); 77 | -------------------------------------------------------------------------------- /demo/tooltip.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FormValidation demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 |
19 | 22 | 23 |
24 |
25 | 26 |
27 | 28 |
29 |
30 | 31 |
32 | 33 |
34 | 35 |
36 |
37 | 38 |
39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | 49 | 98 | 99 | -------------------------------------------------------------------------------- /src/js/validator/different.js: -------------------------------------------------------------------------------- 1 | /** 2 | * different validator 3 | * 4 | * @link http://formvalidation.io/validators/different/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | different: { 13 | 'default': 'Please enter a different value' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.different = { 19 | html5Attributes: { 20 | message: 'message', 21 | field: 'field' 22 | }, 23 | 24 | /** 25 | * Bind the validator on the live change of the field to compare with current one 26 | * 27 | * @param {FormValidation.Base} validator The validator plugin instance 28 | * @param {jQuery} $field Field element 29 | * @param {Object} options Consists of the following key: 30 | * - field: The name of field that will be used to compare with current one 31 | */ 32 | init: function(validator, $field, options) { 33 | var fields = options.field.split(','); 34 | for (var i = 0; i < fields.length; i++) { 35 | var compareWith = validator.getFieldElements(fields[i]); 36 | validator.onLiveChange(compareWith, 'live_different', function() { 37 | var status = validator.getStatus($field, 'different'); 38 | if (status !== validator.STATUS_NOT_VALIDATED) { 39 | validator.revalidateField($field); 40 | } 41 | }); 42 | } 43 | }, 44 | 45 | /** 46 | * Unbind the validator on the live change of the field to compare with current one 47 | * 48 | * @param {FormValidation.Base} validator The validator plugin instance 49 | * @param {jQuery} $field Field element 50 | * @param {Object} options Consists of the following key: 51 | * - field: The name of field that will be used to compare with current one 52 | */ 53 | destroy: function(validator, $field, options) { 54 | var fields = options.field.split(','); 55 | for (var i = 0; i < fields.length; i++) { 56 | var compareWith = validator.getFieldElements(fields[i]); 57 | validator.offLiveChange(compareWith, 'live_different'); 58 | } 59 | }, 60 | 61 | /** 62 | * Return true if the input value is different with given field's value 63 | * 64 | * @param {FormValidation.Base} validator The validator plugin instance 65 | * @param {jQuery} $field Field element 66 | * @param {Object} options Consists of the following key: 67 | * - field: The name of field that will be used to compare with current one 68 | * - message: The invalid message 69 | * @returns {Boolean} 70 | */ 71 | validate: function(validator, $field, options) { 72 | var value = validator.getFieldValue($field, 'different'); 73 | if (value === '') { 74 | return true; 75 | } 76 | 77 | var fields = options.field.split(','), 78 | isValid = true; 79 | 80 | for (var i = 0; i < fields.length; i++) { 81 | var compareWith = validator.getFieldElements(fields[i]); 82 | if (compareWith == null || compareWith.length === 0) { 83 | continue; 84 | } 85 | 86 | var compareValue = validator.getFieldValue(compareWith, 'different'); 87 | if (value === compareValue) { 88 | isValid = false; 89 | } else if (compareValue !== '') { 90 | validator.updateStatus(compareWith, validator.STATUS_VALID, 'different'); 91 | } 92 | } 93 | 94 | return isValid; 95 | } 96 | }; 97 | }(jQuery)); 98 | -------------------------------------------------------------------------------- /src/js/validator/isbn.js: -------------------------------------------------------------------------------- 1 | /** 2 | * isbn validator 3 | * 4 | * @link http://formvalidation.io/validators/isbn/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | isbn: { 13 | 'default': 'Please enter a valid ISBN number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.isbn = { 19 | /** 20 | * Return true if the input value is a valid ISBN 10 or ISBN 13 number 21 | * Examples: 22 | * - Valid: 23 | * ISBN 10: 99921-58-10-7, 9971-5-0210-0, 960-425-059-0, 80-902734-1-6, 85-359-0277-5, 1-84356-028-3, 0-684-84328-5, 0-8044-2957-X, 0-85131-041-9, 0-943396-04-2, 0-9752298-0-X 24 | * ISBN 13: 978-0-306-40615-7 25 | * - Invalid: 26 | * ISBN 10: 99921-58-10-6 27 | * ISBN 13: 978-0-306-40615-6 28 | * 29 | * @see http://en.wikipedia.org/wiki/International_Standard_Book_Number 30 | * @param {FormValidation.Base} validator The validator plugin instance 31 | * @param {jQuery} $field Field element 32 | * @param {Object} [options] Can consist of the following keys: 33 | * - message: The invalid message 34 | * @returns {Boolean} 35 | */ 36 | validate: function(validator, $field, options) { 37 | var value = validator.getFieldValue($field, 'isbn'); 38 | if (value === '') { 39 | return true; 40 | } 41 | 42 | // http://en.wikipedia.org/wiki/International_Standard_Book_Number#Overview 43 | // Groups are separated by a hyphen or a space 44 | var type; 45 | switch (true) { 46 | case /^\d{9}[\dX]$/.test(value): 47 | case (value.length === 13 && /^(\d+)-(\d+)-(\d+)-([\dX])$/.test(value)): 48 | case (value.length === 13 && /^(\d+)\s(\d+)\s(\d+)\s([\dX])$/.test(value)): 49 | type = 'ISBN10'; 50 | break; 51 | case /^(978|979)\d{9}[\dX]$/.test(value): 52 | case (value.length === 17 && /^(978|979)-(\d+)-(\d+)-(\d+)-([\dX])$/.test(value)): 53 | case (value.length === 17 && /^(978|979)\s(\d+)\s(\d+)\s(\d+)\s([\dX])$/.test(value)): 54 | type = 'ISBN13'; 55 | break; 56 | default: 57 | return false; 58 | } 59 | 60 | // Replace all special characters except digits and X 61 | value = value.replace(/[^0-9X]/gi, ''); 62 | var chars = value.split(''), 63 | length = chars.length, 64 | sum = 0, 65 | i, 66 | checksum; 67 | 68 | switch (type) { 69 | case 'ISBN10': 70 | sum = 0; 71 | for (i = 0; i < length - 1; i++) { 72 | sum += parseInt(chars[i], 10) * (10 - i); 73 | } 74 | checksum = 11 - (sum % 11); 75 | if (checksum === 11) { 76 | checksum = 0; 77 | } else if (checksum === 10) { 78 | checksum = 'X'; 79 | } 80 | return (checksum + '' === chars[length - 1]); 81 | 82 | case 'ISBN13': 83 | sum = 0; 84 | for (i = 0; i < length - 1; i++) { 85 | sum += ((i % 2 === 0) ? parseInt(chars[i], 10) : (parseInt(chars[i], 10) * 3)); 86 | } 87 | checksum = 10 - (sum % 10); 88 | if (checksum === 10) { 89 | checksum = '0'; 90 | } 91 | return (checksum + '' === chars[length - 1]); 92 | 93 | default: 94 | return false; 95 | } 96 | } 97 | }; 98 | }(jQuery)); 99 | -------------------------------------------------------------------------------- /demo/ignored.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FormValidation demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 21 | 22 |
23 |
24 | 25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 | 33 |
34 |
35 | 36 |
37 |
38 | 39 |
40 |
41 | 42 |
43 | 44 | 45 |
46 | 47 |
48 | 49 |
50 |
51 |
52 |
53 |
54 | 55 | 93 | 94 | -------------------------------------------------------------------------------- /demo/event3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FormValidation demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 22 | 23 |
24 |
25 | 26 |
27 | 28 |
29 |
30 | 31 |
32 | 33 |
34 | 35 |
36 |
37 | 38 |
39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 |
47 | 48 | 100 | 101 | -------------------------------------------------------------------------------- /demo/container.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FormValidation demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 |
19 |
20 | 23 | 24 |
25 |
26 | 27 |
28 | 29 | 30 |
31 |
32 | 33 | 34 |
35 |
36 | 37 |
38 | 39 |
40 | 41 |
42 |
43 | 44 |
45 |
46 | 47 |
48 |
49 |
50 |
51 |
52 | 53 |
54 |
55 | 56 | 99 | 100 | -------------------------------------------------------------------------------- /test/spec/validator/creditCard.js: -------------------------------------------------------------------------------- 1 | describe('creditCard', function() { 2 | // Get the fake credit card number at http://www.getcreditcardnumbers.com/ 3 | 4 | beforeEach(function() { 5 | var html = [ 6 | '
', 7 | '
', 8 | '
', 9 | '', 10 | '
', 11 | '
', 12 | '
' 13 | ].join('\n'); 14 | 15 | $(html).appendTo('body'); 16 | $('#ccForm').formValidation(); 17 | 18 | this.fv = $('#ccForm').data('formValidation'); 19 | this.$creditCard = this.fv.getFieldElements('cc'); 20 | }); 21 | 22 | afterEach(function() { 23 | $('#ccForm').formValidation('destroy').parent().remove(); 24 | }); 25 | 26 | it('accept spaces', function() { 27 | this.$creditCard.val('5267 9789 9451 9654'); 28 | this.fv.validate(); 29 | expect(this.fv.isValidField('cc')).toBeTruthy(); 30 | }); 31 | 32 | it('accept dashes', function() { 33 | this.$creditCard.val('6011-2649-6840-4521'); 34 | this.fv.validate(); 35 | expect(this.fv.isValidField('cc')).toBeTruthy(); 36 | }); 37 | 38 | it('invalid format', function() { 39 | this.$creditCard.val('4539.1870.2954.3862'); 40 | this.fv.validate(); 41 | expect(this.fv.isValidField('cc')).toEqual(false); 42 | }); 43 | 44 | it('American Express', function() { 45 | this.$creditCard.val('340653705597107'); 46 | this.fv.validate(); 47 | expect(this.fv.isValidField('cc')).toBeTruthy(); 48 | }); 49 | 50 | it('American Express invalid length', function() { 51 | this.$creditCard.val('3744148309166730'); 52 | this.fv.validate(); 53 | expect(this.fv.isValidField('cc')).toEqual(false); 54 | }); 55 | 56 | it('American Express invalid prefix', function() { 57 | this.$creditCard.val('356120148436654'); 58 | this.fv.validate(); 59 | expect(this.fv.isValidField('cc')).toEqual(false); 60 | }); 61 | 62 | it('Diners Club', function() { 63 | this.$creditCard.val('30130708434187'); 64 | this.fv.validate(); 65 | expect(this.fv.isValidField('cc')).toBeTruthy(); 66 | }); 67 | 68 | it('Diners Club (US)', function() { 69 | this.$creditCard.val('5517479515603901'); 70 | this.fv.validate(); 71 | expect(this.fv.isValidField('cc')).toBeTruthy(); 72 | }); 73 | 74 | it('Discover', function() { 75 | this.$creditCard.val('6011734674929094'); 76 | this.fv.validate(); 77 | expect(this.fv.isValidField('cc')).toBeTruthy(); 78 | }); 79 | 80 | it('JCB', function() { 81 | this.$creditCard.val('3566002020360505'); 82 | this.fv.validate(); 83 | expect(this.fv.isValidField('cc')).toBeTruthy(); 84 | }); 85 | 86 | it('Laser', function() { 87 | this.$creditCard.val('6304 9000 1774 0292 441'); 88 | this.fv.validate(); 89 | expect(this.fv.isValidField('cc')).toBeTruthy(); 90 | }); 91 | 92 | it('Maestro', function() { 93 | this.$creditCard.val('6762835098779303'); 94 | this.fv.validate(); 95 | expect(this.fv.isValidField('cc')).toBeTruthy(); 96 | }); 97 | 98 | it('Mastercard', function() { 99 | this.$creditCard.val('5303765013600904'); 100 | this.fv.validate(); 101 | expect(this.fv.isValidField('cc')).toBeTruthy(); 102 | }); 103 | 104 | it('Solo', function() { 105 | this.$creditCard.val('6334580500000000'); 106 | this.fv.validate(); 107 | expect(this.fv.isValidField('cc')).toBeTruthy(); 108 | }); 109 | 110 | it('Visa', function() { 111 | this.$creditCard.val('4929248980295542'); 112 | this.fv.validate(); 113 | expect(this.fv.isValidField('cc')).toBeTruthy(); 114 | }); 115 | 116 | it('Visa invalid check digit', function() { 117 | this.$creditCard.val('4532599916257826'); 118 | this.fv.validate(); 119 | expect(this.fv.isValidField('cc')).toEqual(false); 120 | }); 121 | }); 122 | -------------------------------------------------------------------------------- /src/js/validator/meid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * meid validator 3 | * 4 | * @link http://formvalidation.io/validators/meid/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | meid: { 13 | 'default': 'Please enter a valid MEID number' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.meid = { 19 | /** 20 | * Validate MEID (Mobile Equipment Identifier) 21 | * Examples: 22 | * - Valid: 293608736500703710, 29360-87365-0070-3710, AF0123450ABCDE, AF-012345-0ABCDE 23 | * - Invalid: 2936087365007037101 24 | * 25 | * @see http://en.wikipedia.org/wiki/Mobile_equipment_identifier 26 | * @param {FormValidation.Base} validator The validator plugin instance 27 | * @param {jQuery} $field Field element 28 | * @param {Object} options Can consist of the following keys: 29 | * - message: The invalid message 30 | * @returns {Boolean} 31 | */ 32 | validate: function(validator, $field, options) { 33 | var value = validator.getFieldValue($field, 'meid'); 34 | if (value === '') { 35 | return true; 36 | } 37 | 38 | switch (true) { 39 | // 14 digit hex representation (no check digit) 40 | case /^[0-9A-F]{15}$/i.test(value): 41 | // 14 digit hex representation + dashes or spaces (no check digit) 42 | case /^[0-9A-F]{2}[- ][0-9A-F]{6}[- ][0-9A-F]{6}[- ][0-9A-F]$/i.test(value): 43 | // 18 digit decimal representation (no check digit) 44 | case /^\d{19}$/.test(value): 45 | // 18 digit decimal representation + dashes or spaces (no check digit) 46 | case /^\d{5}[- ]\d{5}[- ]\d{4}[- ]\d{4}[- ]\d$/.test(value): 47 | // Grab the check digit 48 | var cd = value.charAt(value.length - 1); 49 | 50 | // Strip any non-hex chars 51 | value = value.replace(/[- ]/g, ''); 52 | 53 | // If it's all digits, luhn base 10 is used 54 | if (value.match(/^\d*$/i)) { 55 | return FormValidation.Helper.luhn(value); 56 | } 57 | 58 | // Strip the check digit 59 | value = value.slice(0, -1); 60 | 61 | // Get every other char, and double it 62 | var cdCalc = ''; 63 | for (var i = 1; i <= 13; i += 2) { 64 | cdCalc += (parseInt(value.charAt(i), 16) * 2).toString(16); 65 | } 66 | 67 | // Get the sum of each char in the string 68 | var sum = 0; 69 | for (i = 0; i < cdCalc.length; i++) { 70 | sum += parseInt(cdCalc.charAt(i), 16); 71 | } 72 | 73 | // If the last digit of the calc is 0, the check digit is 0 74 | return (sum % 10 === 0) 75 | ? (cd === '0') 76 | // Subtract it from the next highest 10s number (64 goes to 70) and subtract the sum 77 | // Double it and turn it into a hex char 78 | : (cd === ((Math.floor((sum + 10) / 10) * 10 - sum) * 2).toString(16)); 79 | 80 | // 14 digit hex representation (no check digit) 81 | case /^[0-9A-F]{14}$/i.test(value): 82 | // 14 digit hex representation + dashes or spaces (no check digit) 83 | case /^[0-9A-F]{2}[- ][0-9A-F]{6}[- ][0-9A-F]{6}$/i.test(value): 84 | // 18 digit decimal representation (no check digit) 85 | case /^\d{18}$/.test(value): 86 | // 18 digit decimal representation + dashes or spaces (no check digit) 87 | case /^\d{5}[- ]\d{5}[- ]\d{4}[- ]\d{4}$/.test(value): 88 | return true; 89 | 90 | default: 91 | return false; 92 | } 93 | } 94 | }; 95 | }(jQuery)); 96 | -------------------------------------------------------------------------------- /vendor/jasmine/jasmine.css: -------------------------------------------------------------------------------- 1 | body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; } 2 | 3 | .html-reporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } 4 | .html-reporter a { text-decoration: none; } 5 | .html-reporter a:hover { text-decoration: underline; } 6 | .html-reporter p, .html-reporter h1, .html-reporter h2, .html-reporter h3, .html-reporter h4, .html-reporter h5, .html-reporter h6 { margin: 0; line-height: 14px; } 7 | .html-reporter .banner, .html-reporter .symbol-summary, .html-reporter .summary, .html-reporter .result-message, .html-reporter .spec .description, .html-reporter .spec-detail .description, .html-reporter .alert .bar, .html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; } 8 | .html-reporter .banner .version { margin-left: 14px; } 9 | .html-reporter #jasmine_content { position: fixed; right: 100%; } 10 | .html-reporter .version { color: #aaaaaa; } 11 | .html-reporter .banner { margin-top: 14px; } 12 | .html-reporter .duration { color: #aaaaaa; float: right; } 13 | .html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; } 14 | .html-reporter .symbol-summary li { display: inline-block; height: 8px; width: 14px; font-size: 16px; } 15 | .html-reporter .symbol-summary li.passed { font-size: 14px; } 16 | .html-reporter .symbol-summary li.passed:before { color: #5e7d00; content: "\02022"; } 17 | .html-reporter .symbol-summary li.failed { line-height: 9px; } 18 | .html-reporter .symbol-summary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; } 19 | .html-reporter .symbol-summary li.disabled { font-size: 14px; } 20 | .html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; } 21 | .html-reporter .symbol-summary li.pending { line-height: 17px; } 22 | .html-reporter .symbol-summary li.pending:before { color: #ba9d37; content: "*"; } 23 | .html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; } 24 | .html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } 25 | .html-reporter .bar.failed { background-color: #b03911; } 26 | .html-reporter .bar.passed { background-color: #a6b779; } 27 | .html-reporter .bar.skipped { background-color: #bababa; } 28 | .html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; } 29 | .html-reporter .bar.menu a { color: #333333; } 30 | .html-reporter .bar a { color: white; } 31 | .html-reporter.spec-list .bar.menu.failure-list, .html-reporter.spec-list .results .failures { display: none; } 32 | .html-reporter.failure-list .bar.menu.spec-list, .html-reporter.failure-list .summary { display: none; } 33 | .html-reporter .running-alert { background-color: #666666; } 34 | .html-reporter .results { margin-top: 14px; } 35 | .html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } 36 | .html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } 37 | .html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } 38 | .html-reporter.showDetails .summary { display: none; } 39 | .html-reporter.showDetails #details { display: block; } 40 | .html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } 41 | .html-reporter .summary { margin-top: 14px; } 42 | .html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; } 43 | .html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; } 44 | .html-reporter .summary li.passed a { color: #5e7d00; } 45 | .html-reporter .summary li.failed a { color: #b03911; } 46 | .html-reporter .summary li.pending a { color: #ba9d37; } 47 | .html-reporter .description + .suite { margin-top: 0; } 48 | .html-reporter .suite { margin-top: 14px; } 49 | .html-reporter .suite a { color: #333333; } 50 | .html-reporter .failures .spec-detail { margin-bottom: 28px; } 51 | .html-reporter .failures .spec-detail .description { background-color: #b03911; } 52 | .html-reporter .failures .spec-detail .description a { color: white; } 53 | .html-reporter .result-message { padding-top: 14px; color: #333333; white-space: pre; } 54 | .html-reporter .result-message span.result { display: block; } 55 | .html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } 56 | -------------------------------------------------------------------------------- /test/spec/enable.js: -------------------------------------------------------------------------------- 1 | describe('enable validators', function() { 2 | beforeEach(function() { 3 | $([ 4 | '
', 5 | '
', 6 | '', 7 | '
', 8 | '
' 9 | ].join('\n')).appendTo('body'); 10 | 11 | $('#enableForm').formValidation({ 12 | fields: { 13 | fullName: { 14 | validators: { 15 | notEmpty: { 16 | message: 'The full name is required and cannot be empty' 17 | }, 18 | stringLength: { 19 | min: 8, 20 | max: 40, 21 | message: 'The full name must be more than %s and less than %s characters long' 22 | }, 23 | regexp: { 24 | enabled: false, 25 | regexp: /^[a-zA-Z\s]+$/, 26 | message: 'The full name can only consist of alphabetical, number, and space' 27 | } 28 | } 29 | } 30 | } 31 | }); 32 | 33 | this.fv = $('#enableForm').data('formValidation'); 34 | this.$fullName = this.fv.getFieldElements('fullName'); 35 | }); 36 | 37 | afterEach(function() { 38 | $('#enableForm').formValidation('destroy').remove(); 39 | }); 40 | 41 | it('enable all validators', function() { 42 | this.$fullName.val('@ $full N@m3'); 43 | this.fv.validate(); 44 | expect(this.fv.isValid()).toBeTruthy(); 45 | 46 | this.fv.resetForm(); 47 | this.$fullName.val('Contain#$@'); 48 | this.fv.enableFieldValidators('fullName', true); 49 | this.fv.validate(); 50 | expect(this.fv.isValidField('fullName')).toEqual(false); 51 | expect(this.fv.isValid()).toEqual(false); 52 | }); 53 | 54 | it('disable all validators', function() { 55 | this.fv.resetForm(); 56 | this.fv.enableFieldValidators('fullName', false); 57 | this.fv.validate(); 58 | expect(this.fv.isValid()).toBeTruthy(); 59 | }); 60 | 61 | it('enabled option particular validator', function() { 62 | this.$fullName.val('Contain@#$'); 63 | this.fv.validate(); 64 | expect(this.fv.isValid()).toBeTruthy(); 65 | 66 | var messages = this.fv.getMessages('fullName'); 67 | expect(messages.length).toEqual(0); 68 | }); 69 | 70 | it('enable particular validators', function() { 71 | // Enable stringLength validator 72 | this.fv.resetForm(); 73 | this.fv.enableFieldValidators('fullName', true, 'stringLength'); 74 | this.fv.enableFieldValidators('fullName', true, 'regexp'); 75 | this.$fullName.val('Full@'); 76 | this.fv.validate(); 77 | expect(this.fv.isValid()).toEqual(false); 78 | 79 | var messages = this.fv.getMessages('fullName'); 80 | expect($.inArray('The full name must be more than 8 and less than 40 characters long', messages)).toBeGreaterThan(-1); 81 | expect($.inArray('The full name can only consist of alphabetical, number, and space', messages)).toBeGreaterThan(-1); 82 | }); 83 | 84 | it('disable particular validators', function() { 85 | // Disable stringLength validator 86 | this.fv.enableFieldValidators('fullName', false, 'stringLength'); 87 | this.$fullName.val('Full'); 88 | this.fv.validate(); 89 | expect(this.fv.isValid()).toBeTruthy(); 90 | 91 | var messages = this.fv.getMessages('fullName'); 92 | expect($.inArray('The full name must be more than 8 and less than 40 characters long', messages)).toEqual(-1); 93 | 94 | // Disable regexp validator 95 | this.fv.enableFieldValidators('fullName', false, 'regexp'); 96 | this.$fullName.val('Special@#$'); 97 | this.fv.validate(); 98 | expect(this.fv.isValid()).toBeTruthy(); 99 | 100 | var messages = this.fv.getMessages('fullName'); 101 | expect($.inArray('The full name can only consist of alphabetical, number, and space', messages)).toEqual(-1); 102 | }); 103 | }); 104 | -------------------------------------------------------------------------------- /test/spec/transformer.js: -------------------------------------------------------------------------------- 1 | TestSuite = $.extend({}, TestSuite, { 2 | Transformer: { 3 | uri: function($field, validator) { 4 | var value = $field.val(); 5 | if (value && value.substr(0, 7) !== 'http://' && value.substr(0, 8) !== 'https://') { 6 | value = 'http://' + value; 7 | } 8 | return value; 9 | } 10 | } 11 | }); 12 | 13 | describe('transformer', function() { 14 | beforeEach(function() { 15 | $([ 16 | '
', 17 | '
', 18 | '', 19 | '
', 20 | '
' 21 | ].join('\n')).appendTo('body'); 22 | 23 | $('#transformerForm').formValidation(); 24 | 25 | this.fv = $('#transformerForm').data('formValidation'); 26 | this.$website = this.fv.getFieldElements('website'); 27 | }); 28 | 29 | afterEach(function() { 30 | $('#transformerForm').formValidation('destroy').remove(); 31 | }); 32 | 33 | it('transformer not set', function() { 34 | this.$website.val('foo.com'); 35 | this.fv.validate(); 36 | expect(this.fv.isValid()).toBeFalsy(); 37 | }); 38 | 39 | it('programmatically usage', function() { 40 | this.fv = $('#transformerForm') 41 | .formValidation('destroy') 42 | .formValidation({ 43 | fields: { 44 | website: { 45 | validators: { 46 | uri: { 47 | transformer: function($field, validator) { 48 | var value = $field.val(); 49 | if (value && value.substr(0, 7) !== 'http://' && value.substr(0, 8) !== 'https://') { 50 | value = 'http://' + value; 51 | } 52 | return value; 53 | } 54 | } 55 | } 56 | } 57 | } 58 | }) 59 | .data('formValidation'); 60 | this.$website.val('foo.com'); 61 | this.fv.validate(); 62 | expect(this.fv.isValid()).toBeTruthy(); 63 | 64 | this.fv.resetForm(); 65 | this.$website.val('http://foo.com'); 66 | this.fv.validate(); 67 | expect(this.fv.isValid()).toBeTruthy(); 68 | 69 | this.fv.resetForm(); 70 | this.$website.val('https://foo.com'); 71 | this.fv.validate(); 72 | expect(this.fv.isValid()).toBeTruthy(); 73 | }); 74 | 75 | it('declarative usage', function() { 76 | this.$website.attr('data-fv-uri-transformer', 'TestSuite.Transformer.uri'); 77 | 78 | this.fv = $('#transformerForm') 79 | .formValidation('destroy') 80 | .formValidation() 81 | .data('formValidation'); 82 | 83 | this.$website.val('foo.com'); 84 | this.fv.validate(); 85 | expect(this.fv.isValid()).toBeTruthy(); 86 | 87 | this.fv.resetForm(); 88 | this.$website.val('http://foo.com'); 89 | this.fv.validate(); 90 | expect(this.fv.isValid()).toBeTruthy(); 91 | 92 | this.fv.resetForm(); 93 | this.$website.val('https://foo.com'); 94 | this.fv.validate(); 95 | expect(this.fv.isValid()).toBeTruthy(); 96 | }); 97 | 98 | it('update via updateOption()', function() { 99 | this.fv.updateOption('website', 'uri', 'transformer', 'TestSuite.Transformer.uri'); 100 | 101 | this.$website.val('foo.com'); 102 | this.fv.validate(); 103 | expect(this.fv.isValid()).toBeTruthy(); 104 | 105 | this.fv.resetForm(); 106 | this.$website.val('http://foo.com'); 107 | this.fv.validate(); 108 | expect(this.fv.isValid()).toBeTruthy(); 109 | 110 | this.fv.resetForm(); 111 | this.$website.val('https://foo.com'); 112 | this.fv.validate(); 113 | expect(this.fv.isValid()).toBeTruthy(); 114 | }); 115 | }); -------------------------------------------------------------------------------- /src/js/validator/emailAddress.js: -------------------------------------------------------------------------------- 1 | /** 2 | * emailAddress validator 3 | * 4 | * @link http://formvalidation.io/validators/emailAddress/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | emailAddress: { 13 | 'default': 'Please enter a valid email address' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.emailAddress = { 19 | html5Attributes: { 20 | message: 'message', 21 | multiple: 'multiple', 22 | separator: 'separator' 23 | }, 24 | 25 | enableByHtml5: function($field) { 26 | return ('email' === $field.attr('type')); 27 | }, 28 | 29 | /** 30 | * Return true if and only if the input value is a valid email address 31 | * 32 | * @param {FormValidation.Base} validator Validate plugin instance 33 | * @param {jQuery} $field Field element 34 | * @param {Object} [options] 35 | * - multiple: Allow multiple email addresses, separated by a comma or semicolon; default is false. 36 | * - separator: Regex for character or characters expected as separator between addresses; default is comma /[,;]/, i.e. comma or semicolon. 37 | * @returns {Boolean} 38 | */ 39 | validate: function(validator, $field, options) { 40 | var value = validator.getFieldValue($field, 'emailAddress'); 41 | if (value === '') { 42 | return true; 43 | } 44 | 45 | // Email address regular expression 46 | // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript 47 | var emailRegExp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/, 48 | allowMultiple = options.multiple === true || options.multiple === 'true'; 49 | 50 | if (allowMultiple) { 51 | var separator = options.separator || /[,;]/, 52 | addresses = this._splitEmailAddresses(value, separator); 53 | 54 | for (var i = 0; i < addresses.length; i++) { 55 | if (!emailRegExp.test(addresses[i])) { 56 | return false; 57 | } 58 | } 59 | 60 | return true; 61 | } else { 62 | return emailRegExp.test(value); 63 | } 64 | }, 65 | 66 | _splitEmailAddresses: function(emailAddresses, separator) { 67 | var quotedFragments = emailAddresses.split(/"/), 68 | quotedFragmentCount = quotedFragments.length, 69 | emailAddressArray = [], 70 | nextEmailAddress = ''; 71 | 72 | for (var i = 0; i < quotedFragmentCount; i++) { 73 | if (i % 2 === 0) { 74 | var splitEmailAddressFragments = quotedFragments[i].split(separator), 75 | splitEmailAddressFragmentCount = splitEmailAddressFragments.length; 76 | 77 | if (splitEmailAddressFragmentCount === 1) { 78 | nextEmailAddress += splitEmailAddressFragments[0]; 79 | } else { 80 | emailAddressArray.push(nextEmailAddress + splitEmailAddressFragments[0]); 81 | 82 | for (var j = 1; j < splitEmailAddressFragmentCount - 1; j++) { 83 | emailAddressArray.push(splitEmailAddressFragments[j]); 84 | } 85 | nextEmailAddress = splitEmailAddressFragments[splitEmailAddressFragmentCount - 1]; 86 | } 87 | } else { 88 | nextEmailAddress += '"' + quotedFragments[i]; 89 | if (i < quotedFragmentCount - 1) { 90 | nextEmailAddress += '"'; 91 | } 92 | } 93 | } 94 | 95 | emailAddressArray.push(nextEmailAddress); 96 | return emailAddressArray; 97 | } 98 | }; 99 | }(jQuery)); 100 | -------------------------------------------------------------------------------- /test/spec/message.js: -------------------------------------------------------------------------------- 1 | describe('message', function() { 2 | beforeEach(function() { 3 | var html = [ 4 | '
', 5 | '
', 6 | '
', 7 | '', 8 | '
', 9 | '
', 10 | '
' 11 | ].join('\n'); 12 | 13 | $(html).appendTo('body'); 14 | $('#messageForm').formValidation({ 15 | fields: { 16 | password: { 17 | validators: { 18 | notEmpty: { 19 | message: 'The password is required' 20 | }, 21 | callback: { 22 | callback: function(value, validator) { 23 | // Check the password strength 24 | if (value.length < 6) { 25 | return { 26 | valid: false, 27 | message: 'The password must be more than 6 characters' 28 | } 29 | } 30 | 31 | if (value === value.toLowerCase()) { 32 | return { 33 | valid: false, 34 | message: 'The password must contain at least one upper case character' 35 | } 36 | } 37 | if (value === value.toUpperCase()) { 38 | return { 39 | valid: false, 40 | message: 'The password must contain at least one lower case character' 41 | } 42 | } 43 | if (value.search(/[0-9]/) < 0) { 44 | return { 45 | valid: false, 46 | message: 'The password must contain at least one digit' 47 | } 48 | } 49 | 50 | return true; 51 | } 52 | } 53 | } 54 | } 55 | } 56 | }); 57 | 58 | this.fv = $('#messageForm').data('formValidation'); 59 | this.$password = this.fv.getFieldElements('password'); 60 | }); 61 | 62 | afterEach(function() { 63 | $('#messageForm').formValidation('destroy').parent().remove(); 64 | }); 65 | 66 | it('update message from callback', function() { 67 | this.fv.resetForm(); 68 | this.$password.val('123'); 69 | this.fv.validate(); 70 | expect(this.fv.getMessages('password', 'callback')[0]).toEqual('The password must be more than 6 characters'); 71 | 72 | this.fv.resetForm(); 73 | this.$password.val('no_upper_case!@#'); 74 | this.fv.validate(); 75 | expect(this.fv.getMessages('password', 'callback')[0]).toEqual('The password must contain at least one upper case character'); 76 | 77 | this.fv.resetForm(); 78 | this.$password.val('NO_LOWER_CASE123'); 79 | this.fv.validate(); 80 | expect(this.fv.getMessages('password', 'callback')[0]).toEqual('The password must contain at least one lower case character'); 81 | 82 | this.fv.resetForm(); 83 | this.$password.val('NoDigits!@#'); 84 | this.fv.validate(); 85 | expect(this.fv.getMessages('password', 'callback')[0]).toEqual('The password must contain at least one digit'); 86 | }); 87 | 88 | it('call updateMessage()', function() { 89 | this.fv.updateStatus('password', this.fv.STATUS_INVALID, 'callback'); 90 | 91 | this.fv.updateMessage('password', 'callback', 'The password is weak'); 92 | expect(this.fv.getMessages('password', 'callback')[0]).toEqual('The password is weak'); 93 | 94 | this.fv.updateMessage(this.$password, 'callback', 'The password is not strong'); 95 | expect(this.fv.getMessages(this.$password, 'callback')[0]).toEqual('The password is not strong'); 96 | }); 97 | }); 98 | -------------------------------------------------------------------------------- /demo/selector2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FormValidation demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 | 23 | 24 |
25 |
26 | 27 |
28 | 29 |
30 |
31 |
32 |
33 | 34 |
35 |
36 |
37 |
38 | 39 |
40 |
41 |
42 |
43 | 44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | 52 | 100 | 101 | -------------------------------------------------------------------------------- /src/js/validator/file.js: -------------------------------------------------------------------------------- 1 | /** 2 | * file validator 3 | * 4 | * @link http://formvalidation.io/validators/file/ 5 | * @author https://twitter.com/nghuuphuoc 6 | * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc 7 | * @license http://formvalidation.io/license/ 8 | */ 9 | (function($) { 10 | FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 11 | 'en_US': { 12 | file: { 13 | 'default': 'Please choose a valid file' 14 | } 15 | } 16 | }); 17 | 18 | FormValidation.Validator.file = { 19 | html5Attributes: { 20 | extension: 'extension', 21 | maxfiles: 'maxFiles', 22 | minfiles: 'minFiles', 23 | maxsize: 'maxSize', 24 | minsize: 'minSize', 25 | maxtotalsize: 'maxTotalSize', 26 | mintotalsize: 'minTotalSize', 27 | message: 'message', 28 | type: 'type' 29 | }, 30 | 31 | /** 32 | * Validate upload file. Use HTML 5 API if the browser supports 33 | * 34 | * @param {FormValidation.Base} validator The validator plugin instance 35 | * @param {jQuery} $field Field element 36 | * @param {Object} options Can consist of the following keys: 37 | * - extension: The allowed extensions, separated by a comma 38 | * - maxFiles: The maximum number of files 39 | * - minFiles: The minimum number of files 40 | * - maxSize: The maximum size in bytes 41 | * - minSize: The minimum size in bytes 42 | * - maxTotalSize: The maximum size in bytes for all files 43 | * - minTotalSize: The minimum size in bytes for all files 44 | * - message: The invalid message 45 | * - type: The allowed MIME type, separated by a comma 46 | * @returns {Boolean} 47 | */ 48 | validate: function(validator, $field, options) { 49 | var value = validator.getFieldValue($field, 'file'); 50 | if (value === '') { 51 | return true; 52 | } 53 | 54 | var ext, 55 | extensions = options.extension ? options.extension.toLowerCase().split(',') : null, 56 | types = options.type ? options.type.toLowerCase().split(',') : null, 57 | html5 = (window.File && window.FileList && window.FileReader); 58 | 59 | if (html5) { 60 | // Get FileList instance 61 | var files = $field.get(0).files, 62 | total = files.length, 63 | totalSize = 0; 64 | 65 | if ((options.maxFiles && total > parseInt(options.maxFiles, 10)) // Check the maxFiles 66 | || (options.minFiles && total < parseInt(options.minFiles, 10))) // Check the minFiles 67 | { 68 | return false; 69 | } 70 | 71 | for (var i = 0; i < total; i++) { 72 | totalSize += files[i].size; 73 | ext = files[i].name.substr(files[i].name.lastIndexOf('.') + 1); 74 | 75 | if ((options.minSize && files[i].size < parseInt(options.minSize, 10)) // Check the minSize 76 | || (options.maxSize && files[i].size > parseInt(options.maxSize, 10)) // Check the maxSize 77 | || (extensions && $.inArray(ext.toLowerCase(), extensions) === -1) // Check file extension 78 | || (files[i].type && types && $.inArray(files[i].type.toLowerCase(), types) === -1)) // Check file type 79 | { 80 | return false; 81 | } 82 | } 83 | 84 | if ((options.maxTotalSize && totalSize > parseInt(options.maxTotalSize, 10)) // Check the maxTotalSize 85 | || (options.minTotalSize && totalSize < parseInt(options.minTotalSize, 10))) // Check the minTotalSize 86 | { 87 | return false; 88 | } 89 | } else { 90 | // Check file extension 91 | ext = value.substr(value.lastIndexOf('.') + 1); 92 | if (extensions && $.inArray(ext.toLowerCase(), extensions) === -1) { 93 | return false; 94 | } 95 | } 96 | 97 | return true; 98 | } 99 | }; 100 | }(jQuery)); 101 | -------------------------------------------------------------------------------- /test/spec/validator/meid.js: -------------------------------------------------------------------------------- 1 | describe('meid', function() { 2 | beforeEach(function() { 3 | $([ 4 | '
', 5 | '
', 6 | '', 7 | '
', 8 | '
' 9 | ].join('\n')).appendTo('body'); 10 | 11 | $('#meidForm').formValidation(); 12 | 13 | this.fv = $('#meidForm').data('formValidation'); 14 | this.$meid = this.fv.getFieldElements('meid'); 15 | }); 16 | 17 | afterEach(function() { 18 | $('#meidForm').formValidation('destroy').remove(); 19 | }); 20 | 21 | it('Valid MEID (14 hex, check digit)', function() { 22 | this.fv.resetForm(); 23 | this.$meid.val('A00000049259B16'); 24 | this.fv.validate(); 25 | expect(this.fv.isValid()).toBeTruthy(); 26 | }); 27 | 28 | it('Valid MEID (14 hex, dashes, check digit)', function() { 29 | this.fv.resetForm(); 30 | this.$meid.val('A0-000004-9259B1-6'); 31 | this.fv.validate(); 32 | expect(this.fv.isValid()).toBeTruthy(); 33 | }); 34 | 35 | it('Valid MEID (14 hex, spaces, check digit)', function() { 36 | this.fv.resetForm(); 37 | this.$meid.val('A0 000004 9259B1 6'); 38 | this.fv.validate(); 39 | expect(this.fv.isValid()).toBeTruthy(); 40 | }); 41 | 42 | it('Valid MEID (18 dec, check digit)', function() { 43 | this.fv.resetForm(); 44 | this.$meid.val('2936087365007037100'); 45 | this.fv.validate(); 46 | expect(this.fv.isValid()).toBeTruthy(); 47 | }); 48 | 49 | it('Valid MEID (18 dec, dashes, check digit)', function() { 50 | this.fv.resetForm(); 51 | this.$meid.val('29360-87365-0070-3710-0'); 52 | this.fv.validate(); 53 | expect(this.fv.isValid()).toBeTruthy(); 54 | }); 55 | 56 | it('Valid MEID (18 dec, spaces, check digit)', function() { 57 | this.fv.resetForm(); 58 | this.$meid.val('29360 87365 0070 3710 0'); 59 | this.fv.validate(); 60 | expect(this.fv.isValid()).toBeTruthy(); 61 | }); 62 | 63 | it('Valid MEID (14 hex)', function() { 64 | this.fv.resetForm(); 65 | this.$meid.val('AF0123450ABCDE'); 66 | this.fv.validate(); 67 | expect(this.fv.isValid()).toBeTruthy(); 68 | }); 69 | 70 | it('Valid MEID (14 hex, dashes)', function() { 71 | this.fv.resetForm(); 72 | this.$meid.val('AF-012345-0ABCDE'); 73 | this.fv.validate(); 74 | expect(this.fv.isValid()).toBeTruthy(); 75 | }); 76 | 77 | it('Valid MEID (14 hex, spaces)', function() { 78 | this.fv.resetForm(); 79 | this.$meid.val('AF 012345 0ABCDE'); 80 | this.fv.validate(); 81 | expect(this.fv.isValid()).toBeTruthy(); 82 | }); 83 | 84 | it('Valid MEID (18 dec)', function() { 85 | this.fv.resetForm(); 86 | this.$meid.val('293608736500703710'); 87 | this.fv.validate(); 88 | expect(this.fv.isValid()).toBeTruthy(); 89 | }); 90 | 91 | it('Valid MEID (18 dec, dashes)', function() { 92 | this.fv.resetForm(); 93 | this.$meid.val('29360-87365-0070-3710'); 94 | this.fv.validate(); 95 | expect(this.fv.isValid()).toBeTruthy(); 96 | }); 97 | 98 | it('Valid MEID (18 dec, spaces)', function() { 99 | this.fv.resetForm(); 100 | this.$meid.val('29360 87365 0070 3710'); 101 | this.fv.validate(); 102 | expect(this.fv.isValid()).toBeTruthy(); 103 | }); 104 | 105 | it('Invalid MEID (14 hex, bad check digit)', function() { 106 | this.fv.resetForm(); 107 | this.$meid.val('A00000049259B15'); 108 | this.fv.validate(); 109 | expect(this.fv.isValid()).toBeFalsy(); 110 | }); 111 | 112 | it('Invalid MEID (13 hex)', function() { 113 | this.fv.resetForm(); 114 | this.$meid.val('A00000049259B'); 115 | this.fv.validate(); 116 | expect(this.fv.isValid()).toBeFalsy(); 117 | }); 118 | 119 | it('Invalid MEID (18 dec, bad check digit)', function() { 120 | this.fv.resetForm(); 121 | this.$meid.val('2936087365007037101'); 122 | this.fv.validate(); 123 | expect(this.fv.isValid()).toBeFalsy(); 124 | }); 125 | 126 | it('Invalid MEID (17 dec)', function() { 127 | this.fv.resetForm(); 128 | this.$meid.val('29360873650070371'); 129 | this.fv.validate(); 130 | expect(this.fv.isValid()).toBeFalsy(); 131 | }); 132 | }); 133 | -------------------------------------------------------------------------------- /demo/mailgun.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FormValidation demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 21 | 22 |
23 |
24 | 25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 | 33 |
34 |
35 |
36 |
37 |
38 |
39 | 40 | 104 | 105 | --------------------------------------------------------------------------------