Browse Source

Merge branch 'v0.4.0'

phuoc 12 years ago
parent
commit
1b5ee03cc1

+ 22 - 0
bootstrapvalidator.jquery.json

@@ -0,0 +1,22 @@
+{
+    "name": "bootstrapValidator",
+    "version": "0.4.0-dev",
+    "title": "BootstrapValidator",
+    "author": {
+        "name": "Nguyen Huu Phuoc",
+        "email": "phuoc@huuphuoc.me",
+        "url": "https://twitter.com/nghuuphuoc"
+    },
+    "license": "MIT",
+    "dependencies": {
+        "jquery": ">= 1.9.0",
+        "bootstrap": ">= 3.0.0"
+    },
+    "description": "A jQuery plugin to validate form fields. Designed to use with Bootstrap 3",
+    "keywords": ["jQuery", "plugin", "validate", "validator", "form", "Bootstrap"],
+    "homepage": "http://bootstrapvalidator.com",
+    "bugs": "https://github.com/nghuuphuoc/bootstrapvalidator/issues",
+    "maintainers": [
+        { "name": "Nguyen Huu Phuoc", "email": "phuoc@huuphuoc.me", "url": "https://twitter.com/nghuuphuoc" }
+    ]
+}

+ 3 - 3
bower.json

@@ -1,17 +1,17 @@
 {
     "name": "bootstrapValidator",
     "description": "A jQuery plugin to validate form fields. Use with Bootstrap 3",
-    "version": "0.3.0",
+    "version": "0.4.0-dev",
     "main": [
         "dist/css/bootstrapValidator.css",
         "dist/js/bootstrapValidator.js"
     ],
     "license": "MIT",
-    "keywords": ["jQuery", "plugin", "validator", "Bootstrap"],
+    "keywords": ["jQuery", "plugin", "validate", "validator", "form", "Bootstrap"],
     "authors": [
         { "name": "Nguyen Huu Phuoc", "email": "phuoc@huuphuoc.me"," homepage": "https://twitter.com/nghuuphuoc" }
     ],
-    "homepage": "https://github.com/nghuuphuoc/bootstrapvalidator",
+    "homepage": "http://bootstrapvalidator.com",
     "repository": {
         "type": "git",
         "url": "https://github.com/nghuuphuoc/bootstrapvalidator.git"

+ 202 - 0
demo/attribute.html

@@ -0,0 +1,202 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>BootstrapValidator demo</title>
+
+    <link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
+    <link rel="stylesheet" href="../dist/css/bootstrapValidator.css"/>
+
+    <script type="text/javascript" src="../vendor/jquery/jquery-1.10.2.min.js"></script>
+    <script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
+    <script type="text/javascript" src="../dist/js/bootstrapValidator.js"></script>
+</head>
+<body>
+<div class="container">
+    <div class="row">
+        <!-- form: -->
+        <section>
+            <div class="col-lg-8 col-lg-offset-2">
+                <div class="page-header">
+                    <h2>Sign up</h2>
+                </div>
+
+                <form id="defaultForm" method="post" class="form-horizontal" action="target.php"
+                      data-bv-message="This value is not valid"
+                      data-bv-feedbackicons-valid="glyphicon glyphicon-ok"
+                      data-bv-feedbackicons-invalid="glyphicon glyphicon-remove"
+                      data-bv-feedbackicons-validating="glyphicon glyphicon-refresh">
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Full name</label>
+                        <div class="col-lg-4">
+                            <input type="text" class="form-control" name="firstName" placeholder="First name" required data-bv-notempty-message="The first name is required and cannot be empty" />
+                        </div>
+                        <div class="col-lg-4">
+                            <input type="text" class="form-control" name="lastName" placeholder="Last name" required data-bv-notempty-message="The last name is required and cannot be empty" />
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Username</label>
+                        <div class="col-lg-5">
+                            <input type="text" class="form-control" name="username"
+                                   data-bv-message="The username is not valid"
+                                   required data-bv-notempty-message="The username is required and cannot be empty"
+                                   pattern="[a-zA-Z0-9_\.]+" data-bv-regexp-message="The username can only consist of alphabetical, number, dot and underscore"
+                                   data-bv-stringlength="true" data-bv-stringlength-min="6" data-bv-stringlength-max="30" data-bv-stringlength-message="The username must be more than 6 and less than 30 characters long"
+                                   data-bv-different="true" data-bv-different-field="password" data-bv-different-message="The username and password cannot be the same as each other"
+                                   data-bv-remote="true" data-bv-remote-url="remote.php" data-bv-remote-message="The username is not available"
+                                    />
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Email address</label>
+                        <div class="col-lg-5">
+                            <input class="form-control" name="email" type="email" data-bv-emailaddress-message="The input is not a valid email address" />
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Password</label>
+                        <div class="col-lg-5">
+                            <input type="password" class="form-control" name="password"
+                                   required data-bv-notempty-message="The password is required and cannot be empty"
+                                   data-bv-identical="true" data-bv-identical-field="confirmPassword" data-bv-identical-message="The password and its confirm are not the same"
+                                   data-bv-different="true" data-bv-different-field="username" data-bv-different-message="The password cannot be the same as username"/>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Retype password</label>
+                        <div class="col-lg-5">
+                            <input type="password" class="form-control" name="confirmPassword"
+                                   required data-bv-notempty-message="The confirm password is required and cannot be empty"
+                                   data-bv-identical="true" data-bv-identical-field="password" data-bv-identical-message="The password and its confirm are not the same"
+                                   data-bv-different="true" data-bv-different-field="username" data-bv-different-message="The password cannot be the same as username"/>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Gender</label>
+                        <div class="col-lg-5">
+                            <div class="radio">
+                                <label>
+                                    <input type="radio" name="gender" value="male" required data-bv-notempty-message="The gender is required" /> Male
+                                </label>
+                            </div>
+                            <div class="radio">
+                                <label>
+                                    <input type="radio" name="gender" value="female" /> Female
+                                </label>
+                            </div>
+                            <div class="radio">
+                                <label>
+                                    <input type="radio" name="gender" value="other" /> Other
+                                </label>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Birthday</label>
+                        <div class="col-lg-5">
+                            <input type="text" class="form-control" name="birthday" data-bv-date="false" data-bv-date-format="YYYY/MM/DD" data-bv-date-message="The birthday is not valid" /> (YYYY/MM/DD)
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Languages</label>
+                        <div class="col-lg-5">
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="languages[]" value="english" data-bv-message="Please specify at least one language you can speak" /> English
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="languages[]" value="french" /> French
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="languages[]" value="german" required /> German
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="languages[]" value="russian" /> Russian
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="languages[]" value="other" /> Other
+                                </label>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Programming Languages</label>
+                        <div class="col-lg-5">
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="programs[]" value="net" data-bv-choice="true" data-bv-choice-min="2" data-bv-choice-max="4" data-bv-choice-message="Please choose 2 - 4 programming languages you are good at" /> .Net
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="programs[]" value="java" /> Java
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="programs[]" value="c" /> C/C++
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="programs[]" value="php" /> PHP
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="programs[]" value="perl" /> Perl
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="programs[]" value="ruby" /> Ruby
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="programs[]" value="python" /> Python
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="programs[]" value="javascript" /> Javascript
+                                </label>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <div class="col-lg-9 col-lg-offset-3">
+                            <button type="submit" class="btn btn-primary">Sign up</button>
+                        </div>
+                    </div>
+                </form>
+            </div>
+        </section>
+        <!-- :form -->
+    </div>
+</div>
+
+<script type="text/javascript">
+    $(document).ready(function() {
+        $('#defaultForm').bootstrapValidator();
+    });
+</script>
+</body>
+</html>

+ 107 - 0
demo/html5.html

@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>BootstrapValidator demo</title>
+
+    <link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
+    <link rel="stylesheet" href="../dist/css/bootstrapValidator.css"/>
+
+    <script type="text/javascript" src="../vendor/jquery/jquery-1.10.2.min.js"></script>
+    <script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
+    <script type="text/javascript" src="../dist/js/bootstrapValidator.js"></script>
+</head>
+<body>
+<div class="container">
+    <div class="row">
+        <!-- form: -->
+        <section>
+            <div class="col-lg-8 col-lg-offset-2">
+                <div class="page-header">
+                    <h2>Sign up</h2>
+                </div>
+
+                <form id="defaultForm" method="post" class="form-horizontal" action="target.php"
+                      data-bv-message="This value is not valid"
+                      data-bv-feedbackicons-valid="glyphicon glyphicon-ok"
+                      data-bv-feedbackicons-invalid="glyphicon glyphicon-remove"
+                      data-bv-feedbackicons-validating="glyphicon glyphicon-refresh">
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Full name</label>
+                        <div class="col-lg-4">
+                            <input type="text" class="form-control" name="firstName" placeholder="First name" data-bv-trigger="keyup" required data-bv-notempty-message="The first name is required and cannot be empty" />
+                        </div>
+                        <div class="col-lg-4">
+                            <input type="text" class="form-control" name="lastName" placeholder="Last name" required data-bv-trigger="blur" data-bv-notempty-message="The last name is required and cannot be empty" />
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Username</label>
+                        <div class="col-lg-5">
+                            <input type="text" class="form-control" name="username"
+                                   data-bv-trigger="blur"
+                                   data-bv-message="The username is not valid"
+                                   required data-bv-notempty-message="The username is required and cannot be empty"
+                                   pattern="[a-zA-Z0-9_\.]+" data-bv-regexp-message="The username can only consist of alphabetical, number, dot and underscore"
+                                    />
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Email address</label>
+                        <div class="col-lg-5">
+                            <input class="form-control" name="email" type="email" required data-bv-emailaddress-message="The input is not a valid email address" />
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Website</label>
+                        <div class="col-lg-5">
+                            <input class="form-control" name="website" type="url" required data-bv-uri-message="The input is not a valid website address" />
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Fav color</label>
+                        <div class="col-lg-3">
+                            <input class="form-control" name="color" type="color" required data-bv-hexcolor-message="The input is not a valid color code" />
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Age</label>
+                        <div class="col-lg-2">
+                            <input type="text" class="form-control" name="age"
+                                   required
+                                   min="10" data-bv-greaterthan-inclusive="false" data-bv-greaterthan-message="The input must be greater than or equal to 10"
+                                   max="100" data-bv-lessthan-inclusive="true" data-bv-lessthan-message="The input must be less than 100"
+                                    />
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Bio</label>
+                        <div class="col-lg-5">
+                            <textarea class="form-control" name="bio" rows="10" data-bv-stringlength data-bv-stringlength-max="100" data-bv-stringlength-message="The bio must be less than 100 characters long"></textarea>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <div class="col-lg-9 col-lg-offset-3">
+                            <button type="submit" class="btn btn-primary">Sign up</button>
+                        </div>
+                    </div>
+                </form>
+            </div>
+        </section>
+        <!-- :form -->
+    </div>
+</div>
+
+<script type="text/javascript">
+    $(document).ready(function() {
+        $('#defaultForm').bootstrapValidator();
+    });
+</script>
+</body>
+</html>

+ 4 - 4
demo/index.html

@@ -234,10 +234,10 @@ $(document).ready(function() {
                         regexp: /^[a-zA-Z0-9_\.]+$/,
                         message: 'The username can only consist of alphabetical, number, dot and underscore'
                     },
-//                    remote: {
-//                        url: 'remote.php',
-//                        message: 'The username is not available'
-//                    },
+                    remote: {
+                        url: 'remote.php',
+                        message: 'The username is not available'
+                    },
                     different: {
                         field: 'password',
                         message: 'The username and password cannot be the same as each other'

+ 163 - 0
demo/live.html

@@ -0,0 +1,163 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>BootstrapValidator demo</title>
+
+    <link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
+    <link rel="stylesheet" href="../dist/css/bootstrapValidator.css"/>
+
+    <script type="text/javascript" src="../vendor/jquery/jquery-1.10.2.min.js"></script>
+    <script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
+    <script type="text/javascript" src="../dist/js/bootstrapValidator.js"></script>
+</head>
+<body>
+<div class="container">
+    <div class="row">
+        <!-- form: -->
+        <section>
+            <div class="col-lg-8 col-lg-offset-2">
+                <div class="page-header">
+                    <h2>Multiple elements with the same name</h2>
+                </div>
+
+                <form id="defaultForm" method="post" class="form-horizontal" action="target.php">
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Gender</label>
+                        <div class="col-lg-5">
+                            <div class="radio">
+                                <label>
+                                    <input type="radio" name="gender" value="male" /> Male
+                                </label>
+                            </div>
+                            <div class="radio">
+                                <label>
+                                    <input type="radio" name="gender" value="female" /> Female
+                                </label>
+                            </div>
+                            <div class="radio">
+                                <label>
+                                    <input type="radio" name="gender" value="other" /> Other
+                                </label>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Browser</label>
+                        <div class="col-lg-5">
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="browsers[]" value="chrome" /> Google Chrome
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="browsers[]" value="firefox" /> Firefox
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="browsers[]" value="ie" /> IE
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="browsers[]" value="safari" /> Safari
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="browsers[]" value="opera" /> Opera
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="browsers[]" value="other" /> Other
+                                </label>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Editors</label>
+                        <div class="col-lg-5">
+                            <input class="form-control" type="text" name="editors[]" />
+                        </div>
+                    </div>
+                    <div class="form-group">
+                        <div class="col-lg-offset-3 col-lg-5">
+                            <input class="form-control" type="text" name="editors[]" />
+                        </div>
+                    </div>
+                    <div class="form-group">
+                        <div class="col-lg-offset-3 col-lg-5">
+                            <input class="form-control" type="text" name="editors[]" />
+                        </div>
+                    </div>
+                    <div class="form-group">
+                        <div class="col-lg-offset-3 col-lg-5">
+                            <input class="form-control" type="text" name="editors[]" />
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <div class="col-lg-offset-3 col-lg-9">
+                            <button type="button" class="btn btn-info" data-mode="enabled">Set live="enabled"</button>
+                            <button type="button" class="btn btn-info" data-mode="disabled">Set live="disabled"</button>
+                            <button type="button" class="btn btn-info" data-mode="submitted">Set live="submitted"</button>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <div class="col-lg-offset-3 col-lg-3">
+                            <button type="submit" class="btn btn-primary">Submit</button>
+                        </div>
+                    </div>
+                </form>
+            </div>
+        </section>
+        <!-- :form -->
+    </div>
+</div>
+
+<script type="text/javascript">
+    $(document).ready(function() {
+        $('#defaultForm').bootstrapValidator({
+            message: 'This value is not valid',
+            feedbackIcons: {
+                valid: 'glyphicon glyphicon-ok',
+                invalid: 'glyphicon glyphicon-remove',
+                validating: 'glyphicon glyphicon-refresh'
+            },
+            fields: {
+                gender: {
+                    validators: {
+                        notEmpty: {
+                            message: 'The gender is required'
+                        }
+                    }
+                },
+                'browsers[]': {
+                    validators: {
+                        notEmpty: {
+                            message: 'Please specify at least one browser you use daily for development'
+                        }
+                    }
+                },
+                'editors[]': {
+                    validators: {
+                        notEmpty: {
+                            message: 'The editor names are required'
+                        }
+                    }
+                }
+            }
+        });
+
+        $('button[data-mode]').click(function() {
+            $('#defaultForm').data('bootstrapValidator').setLiveMode($(this).attr('data-mode'));
+        });
+    });
+</script>
+</body>
+</html>

+ 151 - 0
demo/multiple.html

@@ -0,0 +1,151 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>BootstrapValidator demo</title>
+
+    <link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
+    <link rel="stylesheet" href="../dist/css/bootstrapValidator.css"/>
+
+    <script type="text/javascript" src="../vendor/jquery/jquery-1.10.2.min.js"></script>
+    <script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
+    <script type="text/javascript" src="../dist/js/bootstrapValidator.js"></script>
+</head>
+<body>
+<div class="container">
+    <div class="row">
+        <!-- form: -->
+        <section>
+            <div class="col-lg-8 col-lg-offset-2">
+                <div class="page-header">
+                    <h2>Multiple elements with the same name</h2>
+                </div>
+
+                <form id="defaultForm" method="post" class="form-horizontal" action="target.php">
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Gender</label>
+                        <div class="col-lg-5">
+                            <div class="radio">
+                                <label>
+                                    <input type="radio" name="gender" value="male" /> Male
+                                </label>
+                            </div>
+                            <div class="radio">
+                                <label>
+                                    <input type="radio" name="gender" value="female" /> Female
+                                </label>
+                            </div>
+                            <div class="radio">
+                                <label>
+                                    <input type="radio" name="gender" value="other" /> Other
+                                </label>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Browser</label>
+                        <div class="col-lg-5">
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="browsers[]" value="chrome" /> Google Chrome
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="browsers[]" value="firefox" /> Firefox
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="browsers[]" value="ie" /> IE
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="browsers[]" value="safari" /> Safari
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="browsers[]" value="opera" /> Opera
+                                </label>
+                            </div>
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="browsers[]" value="other" /> Other
+                                </label>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <label class="col-lg-3 control-label">Editors</label>
+                        <div class="col-lg-5">
+                            <input class="form-control" type="text" name="editors[]" />
+                        </div>
+                    </div>
+                    <div class="form-group">
+                        <div class="col-lg-offset-3 col-lg-5">
+                            <input class="form-control" type="text" name="editors[]" />
+                        </div>
+                    </div>
+                    <div class="form-group">
+                        <div class="col-lg-offset-3 col-lg-5">
+                            <input class="form-control" type="text" name="editors[]" />
+                        </div>
+                    </div>
+                    <div class="form-group">
+                        <div class="col-lg-offset-3 col-lg-5">
+                            <input class="form-control" type="text" name="editors[]" />
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <div class="col-lg-offset-3 col-lg-3">
+                            <button type="submit" class="btn btn-primary">Submit</button>
+                        </div>
+                    </div>
+                </form>
+            </div>
+        </section>
+        <!-- :form -->
+    </div>
+</div>
+
+<script type="text/javascript">
+    $(document).ready(function() {
+        $('#defaultForm').bootstrapValidator({
+            message: 'This value is not valid',
+            feedbackIcons: {
+                valid: 'glyphicon glyphicon-ok',
+                invalid: 'glyphicon glyphicon-remove',
+                validating: 'glyphicon glyphicon-refresh'
+            },
+            fields: {
+                gender: {
+                    validators: {
+                        notEmpty: {
+                            message: 'The gender is required'
+                        }
+                    }
+                },
+                'browsers[]': {
+                    validators: {
+                        notEmpty: {
+                            message: 'Please specify at least one browser you use daily for development'
+                        }
+                    }
+                },
+                'editors[]': {
+                    validators: {
+                        notEmpty: {
+                            message: 'The editor names are required'
+                        }
+                    }
+                }
+            }
+        });
+    });
+</script>
+</body>
+</html>

+ 1 - 1
demo/validators.html

@@ -20,7 +20,7 @@
                 </div>
 
                 <div class="col-lg-8 col-lg-offset-2">
-                    <form id="defaultForm" method="post" action="validators.html" class="form-horizontal">
+                    <form id="defaultForm" method="post" action="target.php" class="form-horizontal">
                         <fieldset>
                             <legend>Not Empty validator</legend>
 

+ 2 - 2
dist/css/bootstrapValidator.min.css

@@ -1,9 +1,9 @@
 /**
- * BootstrapValidator (https://github.com/nghuuphuoc/bootstrapvalidator)
+ * BootstrapValidator (http://bootstrapvalidator.com)
  *
  * A jQuery plugin to validate form fields. Use with Bootstrap 3
  *
- * @version     v0.3.3
+ * @version     v0.4.0-dev
  * @author      https://twitter.com/nghuuphuoc
  * @copyright   (c) 2013 - 2014 Nguyen Huu Phuoc
  * @license     MIT

File diff suppressed because it is too large
+ 496 - 179
dist/js/bootstrapValidator.js


File diff suppressed because it is too large
+ 3 - 3
dist/js/bootstrapValidator.min.js


+ 3 - 3
package.json

@@ -1,14 +1,14 @@
 {
     "name": "bootstrapValidator",
-    "version": "0.3.3",
+    "version": "0.4.0-dev",
     "description": "A jQuery plugin to validate form fields. Use with Bootstrap 3",
-    "keywords": ["jQuery", "plugin", "validator", "Bootstrap"],
+    "keywords": ["jQuery", "plugin", "validate", "validator", "form", "Bootstrap"],
     "author": {
         "name": "Nguyen Huu Phuoc",
         "email": "phuoc@huuphuoc.me",
         "url": "https://twitter.com/nghuuphuoc"
     },
-    "homepage": "https://github.com/nghuuphuoc/bootstrapvalidator",
+    "homepage": "http://bootstrapvalidator.com",
     "bugs": {
         "url": "https://github.com/nghuuphuoc/bootstrapvalidator/issues",
         "email": "phuoc@huuphuoc.me"

+ 313 - 168
src/js/bootstrapValidator.js

@@ -13,18 +13,16 @@
         this.$form   = $(form);
         this.options = $.extend({}, BootstrapValidator.DEFAULT_OPTIONS, options);
 
-        this.dfds    = {};      // Array of deferred
-        this.results = {};      // Validating results
-
-        this.invalidField  = null;  // First invalid field
+        this.$invalidField = null;  // First invalid field
         this.$submitButton = null;  // The submit button which is clicked to submit form
 
-        this._init();
-
+        // Validating status
         this.STATUS_NOT_VALIDATED = 'NOT_VALIDATED';
         this.STATUS_VALIDATING    = 'VALIDATING';
         this.STATUS_INVALID       = 'INVALID';
         this.STATUS_VALID         = 'VALID';
+
+        this._init();
     };
 
     // The default options
@@ -54,8 +52,8 @@
         //      validating: 'fa fa-refresh'
         //  }
         feedbackIcons: {
-            valid: null,
-            invalid: null,
+            valid:      null,
+            invalid:    null,
             validating: null
         },
 
@@ -90,30 +88,88 @@
          * Init form
          */
         _init: function() {
-            if (this.options.fields == null) {
-                return;
-            }
+            var that    = this,
+                options = {
+                    trigger:        this.$form.attr('data-bv-trigger'),
+                    message:        this.$form.attr('data-bv-message'),
+                    submitButtons:  this.$form.attr('data-bv-submitbuttons'),
+                    live:           this.$form.attr('data-bv-live'),
+                    fields:         {},
+                    feedbackIcons: {
+                        valid:      this.$form.attr('data-bv-feedbackicons-valid'),
+                        invalid:    this.$form.attr('data-bv-feedbackicons-invalid'),
+                        validating: this.$form.attr('data-bv-feedbackicons-validating')
+                    }
+                },
+                validator,
+                v,          // Validator name
+                enabled,
+                optionName,
+                optionValue,
+                html5AttrName,
+                html5Attrs;
 
-            var that = this;
             this.$form
                 // Disable client side validation in HTML 5
                 .attr('novalidate', 'novalidate')
                 .addClass(this.options.elementClass)
                 // Disable the default submission first
-                .on('submit.bootstrapValidator', function(e) {
+                .on('submit.bv', function(e) {
                     e.preventDefault();
                     that.validate();
                 })
-                .find(this.options.submitButtons)
-                    .on('click', function() {
-                        that.$submitButton = $(this);
-                    });
+                .on('click', this.options.submitButtons, function() {
+                    that.$submitButton = $(this);
+                })
+                // Find all fields which have either "name" or "data-bv-field" attribute
+                .find('[name], [data-bv-field]').each(function() {
+                    var $field = $(this),
+                        field  = $field.attr('name') || $field.attr('data-bv-field');
+                    $field.attr('data-bv-field', field);
+
+                    options.fields[field] = $.extend({}, {
+                        trigger:    $field.attr('data-bv-trigger'),
+                        message:    $field.attr('data-bv-message'),
+                        container:  $field.attr('data-bv-container'),
+                        selector:   $field.attr('data-bv-selector'),
+                        validators: {}
+                    }, options.fields[field]);
+
+                    for (v in $.fn.bootstrapValidator.validators) {
+                        validator  = $.fn.bootstrapValidator.validators[v];
+                        enabled    = $field.attr('data-bv-' + v.toLowerCase()) + '';
+                        html5Attrs = ('function' == typeof validator.enableByHtml5) ? validator.enableByHtml5($(this)) : null;
+
+                        if ((html5Attrs && enabled != 'false')
+                            || (html5Attrs !== true && ('' == enabled || 'true' == enabled)))
+                        {
+                            // Try to parse the options via attributes
+                            validator.html5Attributes = validator.html5Attributes || { message: 'message' };
+                            options.fields[field]['validators'][v] = $.extend({}, html5Attrs == true ? {} : html5Attrs, options.fields[field]['validators'][v]);
+
+                            for (html5AttrName in validator.html5Attributes) {
+                                optionName  = validator.html5Attributes[html5AttrName];
+                                optionValue = $field.attr('data-bv-' + v.toLowerCase() + '-' + html5AttrName);
+                                if (optionValue) {
+                                    if ('true' == optionValue) {
+                                        optionValue = true;
+                                    } else if ('false' == optionValue) {
+                                        optionValue = false;
+                                    }
+                                    options.fields[field]['validators'][v][optionName] = optionValue;
+                                }
+                            }
+                        }
+                    }
+                });
+
+            this.options = $.extend(true, this.options, options);
 
             for (var field in this.options.fields) {
                 this._initField(field);
             }
 
-            this._setLiveValidating();
+            this.setLiveMode(this.options.live);
         },
 
         /**
@@ -126,9 +182,6 @@
                 return;
             }
 
-            this.dfds[field]    = {};
-            this.results[field] = {};
-
             var fields = this.getFieldElements(field);
 
             // We don't need to validate invisible or hidden fields
@@ -141,59 +194,71 @@
             // We don't need to validate non-existing fields
             if (fields == null) {
                 delete this.options.fields[field];
-                delete this.dfds[field];
                 return;
             }
-
-            fields.attr('data-bv-field', field);
-
-            // Create help block elements for showing the error messages
-            var $field   = $(fields[0]),
-                $parent  = $field.parents('.form-group'),
-                // Allow user to indicate where the error messages are shown
-                $message = this.options.fields[field].container ? $parent.find(this.options.fields[field].container) : this._getMessageContainer($field);
-
-            $field.data('bootstrapValidator.messageContainer', $message);
             for (var validatorName in this.options.fields[field].validators) {
                 if (!$.fn.bootstrapValidator.validators[validatorName]) {
                     delete this.options.fields[field].validators[validatorName];
-                    continue;
                 }
-
-                this.results[field][validatorName] = this.STATUS_NOT_VALIDATED;
-                $('<small/>')
-                    .css('display', 'none')
-                    .attr('data-bv-validator', validatorName)
-                    .html(this.options.fields[field].validators[validatorName].message || this.options.message)
-                    .addClass('help-block')
-                    .appendTo($message);
             }
 
-            // Prepare the feedback icons
-            // Available from Bootstrap 3.1 (http://getbootstrap.com/css/#forms-control-validation)
-            if (this.options.feedbackIcons
-                && this.options.feedbackIcons.validating && this.options.feedbackIcons.invalid && this.options.feedbackIcons.valid)
-            {
-                $parent.addClass('has-feedback');
-                var $icon = $('<i/>').css('display', 'none').addClass('form-control-feedback').attr('data-bv-field', field).insertAfter($(fields[fields.length - 1]));
-                // The feedback icon does not render correctly if there is no label
-                // https://github.com/twbs/bootstrap/issues/12873
-                if ($parent.find('label').length == 0) {
-                    $icon.css('top', 0);
+            var that      = this,
+                type      = fields.attr('type'),
+                event     = ('radio' == type || 'checkbox' == type || 'file' == type || 'SELECT' == fields[0].tagName) ? 'change' : 'keyup',
+                total     = fields.length,
+                updateAll = (total == 1) || ('radio' == type) || ('checkbox' == type);
+
+            for (var i = 0; i < total; i++) {
+                var $field   = $(fields[i]),
+                    $parent  = $field.parents('.form-group'),
+                    // Allow user to indicate where the error messages are shown
+                    $message = this.options.fields[field].container ? $parent.find(this.options.fields[field].container) : this._getMessageContainer($field);
+
+                // Set the attribute to indicate the fields which are defined by selector
+                if (!$field.attr('data-bv-field')) {
+                    $field.attr('data-bv-field', field);
+                }
+
+                // Whenever the user change the field value, mark it as not validated yet
+                $field.on(event + '.update.bv', function() {
+                    updateAll ? that.updateStatus(field, that.STATUS_NOT_VALIDATED, null)
+                              : that.updateElementStatus($(this), that.STATUS_NOT_VALIDATED, null);
+                });
+
+                // Create help block elements for showing the error messages
+                $field.data('bv.messages', $message);
+                for (validatorName in this.options.fields[field].validators) {
+                    $field.data('bv.result.' + validatorName, this.STATUS_NOT_VALIDATED);
+
+                    if (!updateAll || i == total - 1) {
+                        $('<small/>')
+                            .css('display', 'none')
+                            .attr('data-bv-validator', validatorName)
+                            .html(this.options.fields[field].validators[validatorName].message || this.options.fields[field].message || this.options.message)
+                            .addClass('help-block')
+                            .appendTo($message);
+                    }
+                }
+
+                // Prepare the feedback icons
+                // Available from Bootstrap 3.1 (http://getbootstrap.com/css/#forms-control-validation)
+                if (this.options.feedbackIcons
+                    && this.options.feedbackIcons.validating && this.options.feedbackIcons.invalid && this.options.feedbackIcons.valid
+                    && (!updateAll || i == total - 1))
+                {
+                    $parent.addClass('has-feedback');
+                    var $icon = $('<i/>').css('display', 'none').addClass('form-control-feedback').attr('data-bv-field', field).insertAfter($field);
+                    // The feedback icon does not render correctly if there is no label
+                    // https://github.com/twbs/bootstrap/issues/12873
+                    if ($parent.find('label').length == 0) {
+                        $icon.css('top', 0);
+                    }
                 }
             }
 
             if (this.options.fields[field]['enabled'] == null) {
                 this.options.fields[field]['enabled'] = true;
             }
-
-            // Whenever the user change the field value, mark it as not validated yet
-            var that  = this,
-                type  = fields.attr('type'),
-                event = ('radio' == type || 'checkbox' == type || 'file' == type || 'SELECT' == fields[0].tagName) ? 'change' : 'keyup';
-            fields.on(event + '.bootstrapValidator', function() {
-                that.updateStatus($field, that.STATUS_NOT_VALIDATED, null);
-            });
         },
 
         /**
@@ -225,68 +290,31 @@
         },
 
         /**
-         * Enable live validating
-         */
-        _setLiveValidating: function() {
-            if ('enabled' == this.options.live) {
-                var that = this;
-                for (var field in this.options.fields) {
-                    (function(f) {
-                        var fields = that.getFieldElements(f);
-                        if (fields) {
-                            var type  = fields.attr('type'),
-                                event = ('radio' == type || 'checkbox' == type || 'file' == type || 'SELECT' == fields[0].tagName) ? 'change' : 'keyup';
-
-                            fields.on(event + '.bootstrapValidator', function() {
-                                that.validateField(f);
-                            });
-                        }
-                    })(field);
-                }
-            }
-        },
-
-        /**
-         * Disable/Enable submit buttons
-         *
-         * @param {Boolean} disabled
-         */
-        _disableSubmitButtons: function(disabled) {
-            if (!disabled) {
-                this.$form.find(this.options.submitButtons).removeAttr('disabled');
-            } else if (this.options.live != 'disabled') {
-                // Don't disable if the live validating mode is disabled
-                this.$form.find(this.options.submitButtons).attr('disabled', 'disabled');
-            }
-        },
-
-        /**
          * Called when all validations are completed
          */
         _submit: function() {
             if (!this.isValid()) {
                 if ('submitted' == this.options.live) {
-                    this.options.live = 'enabled';
-                    this._setLiveValidating();
+                    this.setLiveMode('enabled');
                 }
 
                 // Focus to the first invalid field
-                if (this.invalidField) {
-                    this.getFieldElements(this.invalidField).focus();
+                if (this.$invalidField) {
+                    this.$invalidField.focus();
                 }
                 return;
             }
 
-            this._disableSubmitButtons(true);
-
             // Call the custom submission if enabled
             if (this.options.submitHandler && 'function' == typeof this.options.submitHandler) {
                 // Turn off the submit handler, so user can call form.submit() inside their submitHandler method
-                this.$form.off('submit.bootstrapValidator');
+                this.$form.off('submit.bv');
                 this.options.submitHandler.call(this, this, this.$form, this.$submitButton);
             } else {
+                this.disableSubmitButtons(true);
+
                 // Submit form
-                this.$form.off('submit.bootstrapValidator').submit();
+                this.$form.off('submit.bv').submit();
             }
         },
 
@@ -304,6 +332,63 @@
         },
 
         /**
+         * Set live validating mode
+         *
+         * @param {String} mode Live validating mode. Can be 'enabled', 'disabled', 'submitted'
+         * @returns {BootstrapValidator}
+         */
+        setLiveMode: function(mode) {
+            this.options.live = mode;
+            if ('submitted' == mode) {
+                return this;
+            }
+
+            var that = this;
+            for (var field in this.options.fields) {
+                (function(f) {
+                    var fields = that.getFieldElements(f);
+                    if (fields) {
+                        var type      = fields.attr('type'),
+                            total     = fields.length,
+                            updateAll = (total == 1) || ('radio' == type) || ('checkbox' == type),
+                            trigger   = that.options.fields[field].trigger
+                                || that.options.trigger
+                                || (('radio' == type || 'checkbox' == type || 'file' == type || 'SELECT' == fields[0].tagName) ? 'change' : 'keyup'),
+                            events    = trigger.split(' ').map(function(item) {
+                                return item + '.live.bv';
+                            }).join(' ');
+
+                        for (var i = 0; i < total; i++) {
+                            ('enabled' == mode)
+                                ? $(fields[i]).on(events, function() {
+                                    updateAll ? that.validateField(f) : that.validateFieldElement($(this), false);
+                                })
+                                : $(fields[i]).off(events);
+                        }
+                    }
+                })(field);
+            }
+
+            return this;
+        },
+
+        /**
+         * Disable/enable submit buttons
+         *
+         * @param {Boolean} disabled Can be true or false
+         * @returns {BootstrapValidator}
+         */
+        disableSubmitButtons: function(disabled) {
+            if (!disabled) {
+                this.$form.find(this.options.submitButtons).removeAttr('disabled');
+            } else if (this.options.live != 'disabled') {
+                // Don't disable if the live validating mode is disabled
+                this.$form.find(this.options.submitButtons).attr('disabled', 'disabled');
+            }
+            return this;
+        },
+
+        /**
          * Validate the form
          *
          * @return {BootstrapValidator}
@@ -312,7 +397,7 @@
             if (!this.options.fields) {
                 return this;
             }
-            this._disableSubmitButtons(true);
+            this.disableSubmitButtons(true);
 
             for (var field in this.options.fields) {
                 this.validateField(field);
@@ -325,25 +410,38 @@
         /**
          * Validate given field
          *
-         * @param {String} field The field name
+         * @param {String} field The field element
+         * @returns {BootstrapValidator}
          */
         validateField: function(field) {
-            if (!this.options.fields[field]['enabled']) {
-                return;
+            var fields = this.getFieldElements(field),
+                type   = fields.attr('type'),
+                n      = (('radio' == type) || ('checkbox' == type)) ? 1 : fields.length;
+
+            for (var i = 0; i < n; i++) {
+                this.validateFieldElement($(fields[i]), (n == 1));
             }
 
+            return this;
+        },
+
+        /**
+         * Validate field element
+         *
+         * @param {jQuery} $field The field element
+         * @param {Boolean} updateAll If true, update status of all elements which have the same name
+         * @returns {BootstrapValidator}
+         */
+        validateFieldElement: function($field, updateAll) {
             var that       = this,
-                fields     = this.getFieldElements(field),
-                $field     = $(fields[0]),
+                field      = $field.attr('data-bv-field'),
                 validators = this.options.fields[field].validators,
                 validatorName,
                 validateResult;
 
             // We don't need to validate disabled field
-            if (fields.length == 1 && fields.is(':disabled')) {
-                delete this.options.fields[field];
-                delete this.dfds[field];
-                return;
+            if ($field.is(':disabled')) {
+                return this;
             }
 
             // We don't need to validate hide field
@@ -354,95 +452,94 @@
             }
 
             for (validatorName in validators) {
-                if (this.dfds[field][validatorName]) {
-                    this.dfds[field][validatorName].reject();
+                if ($field.data('bv.dfs.' + validatorName)) {
+                    $field.data('bv.dfs.' + validatorName).reject();
                 }
 
                 // Don't validate field if it is already done
-                if (this.results[field][validatorName] == this.STATUS_VALID || this.results[field][validatorName] == this.STATUS_INVALID) {
+                var result = $field.data('bv.result.' + validatorName);
+                if (result == this.STATUS_VALID || result == this.STATUS_INVALID) {
                     continue;
                 }
 
-                this.results[field][validatorName] = this.STATUS_VALIDATING;
+                $field.data('bv.result.' + validatorName, this.STATUS_VALIDATING);
                 validateResult = $.fn.bootstrapValidator.validators[validatorName].validate(this, $field, validators[validatorName]);
 
                 if ('object' == typeof validateResult) {
-                    this.updateStatus($field, this.STATUS_VALIDATING, validatorName);
-                    this.dfds[field][validatorName] = validateResult;
+                    updateAll ? this.updateStatus(field, this.STATUS_VALIDATING, validatorName)
+                              : this.updateElementStatus($field, this.STATUS_VALIDATING, validatorName);
+                    $field.data('bv.dfs.' + validatorName, validateResult);
 
-                    validateResult.done(function(isValid, v) {
+                    validateResult.done(function($f, v, isValid) {
                         // v is validator name
-                        delete that.dfds[field][v];
-                        that.updateStatus($field, isValid ? that.STATUS_VALID : that.STATUS_INVALID, v);
+                        $f.removeData('bv.dfs.' + v);
+                        updateAll ? that.updateStatus($f.attr('data-bv-field'), isValid ? that.STATUS_VALID : that.STATUS_INVALID, v)
+                                  : that.updateElementStatus($f, isValid ? that.STATUS_VALID : that.STATUS_INVALID, v);
 
                         if (isValid && 'disabled' == that.options.live) {
                             that._submit();
                         }
                     });
                 } else if ('boolean' == typeof validateResult) {
-                    this.updateStatus($field, validateResult ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
+                    updateAll ? this.updateStatus(field, validateResult ? this.STATUS_VALID : this.STATUS_INVALID, validatorName)
+                              : this.updateElementStatus($field, validateResult ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
                 }
             }
+
+            return this;
         },
 
         /**
-         * Check the form validity
+         * Update all validating results of elements which have the same field name
          *
-         * @returns {Boolean}
+         * @param {String} field The field name
+         * @param {String} status The status
+         * Can be 'NOT_VALIDATED', 'VALIDATING', 'INVALID' or 'VALID'
+         * @param {String|null} validatorName The validator name. If null, the method updates validity result for all validators
+         * @return {BootstrapValidator}
          */
-        isValid: function() {
-            var field, validatorName;
-            for (field in this.results) {
-                if (this.options.fields[field] == null || !this.options.fields[field]['enabled']) {
-                    continue;
-                }
-
-                for (validatorName in this.results[field]) {
-                    if (this.results[field][validatorName] == this.STATUS_NOT_VALIDATED || this.results[field][validatorName] == this.STATUS_VALIDATING) {
-                        return false;
-                    }
+        updateStatus: function(field, status, validatorName) {
+            var fields = this.getFieldElements(field),
+                type   = fields.attr('type'),
+                n      = (('radio' == type) || ('checkbox' == type)) ? 1 : fields.length;
 
-                    if (this.results[field][validatorName] == this.STATUS_INVALID) {
-                        this.invalidField = field;
-                        return false;
-                    }
-                }
+            for (var i = 0; i < n; i++) {
+                this.updateElementStatus($(fields[i]), status, validatorName);
             }
 
-            return true;
+            return this;
         },
 
         /**
-         * Update field status
+         * Update validating result of given element
          *
-         * @param {String|jQuery} field The field name or field element
+         * @param {String} field The field name
          * @param {String} status The status
          * Can be 'NOT_VALIDATED', 'VALIDATING', 'INVALID' or 'VALID'
          * @param {String|null} validatorName The validator name. If null, the method updates validity result for all validators
          * @return {BootstrapValidator}
          */
-        updateStatus: function(field, status, validatorName) {
-            var $field   = ('string' == typeof field) ? this.getFieldElements(field) : field,
-                that     = this,
+        updateElementStatus: function($field, status, validatorName) {
+            var that     = this,
                 field    = $field.attr('data-bv-field'),
                 $parent  = $field.parents('.form-group'),
-                $message = $field.data('bootstrapValidator.messageContainer'),
+                $message = $field.data('bv.messages'),
                 $errors  = $message.find('.help-block[data-bv-validator]'),
                 $icon    = $parent.find('.form-control-feedback[data-bv-field="' + field + '"]');
 
             // Update status
             if (validatorName) {
-                this.results[field][validatorName] = status;
+                $field.data('bv.result.' + validatorName, status);
             } else {
                 for (var v in this.options.fields[field].validators) {
-                    this.results[field][v] = status;
+                    $field.data('bv.result.' + v, status);
                 }
             }
 
             // Show/hide error elements and feedback icons
             switch (status) {
                 case this.STATUS_VALIDATING:
-                    this._disableSubmitButtons(true);
+                    this.disableSubmitButtons(true);
                     $parent.removeClass('has-success').removeClass('has-error');
                     // TODO: Show validating message
                     validatorName ? $errors.filter('.help-block[data-bv-validator="' + validatorName + '"]').hide() : $errors.hide();
@@ -452,7 +549,7 @@
                     break;
 
                 case this.STATUS_INVALID:
-                    this._disableSubmitButtons(true);
+                    this.disableSubmitButtons(true);
                     $parent.removeClass('has-success').addClass('has-error');
                     validatorName ? $errors.filter('[data-bv-validator="' + validatorName + '"]').show() : $errors.show();
                     if ($icon) {
@@ -463,23 +560,29 @@
                 case this.STATUS_VALID:
                     validatorName ? $errors.filter('[data-bv-validator="' + validatorName + '"]').hide() : $errors.hide();
 
-                    // If the field is valid
+                    // If the field is valid (passes all validators)
                     if ($errors.filter(function() {
                             var display = $(this).css('display'), v = $(this).attr('data-bv-validator');
-                            return ('block' == display) || (that.results[field][v] != that.STATUS_VALID);
-                        }).length == 0
-                    ) {
-                        this._disableSubmitButtons(false);
+                            return ('block' == display) || ($field.data('bv.result.' + v) != that.STATUS_VALID);
+                        }).length == 0)
+                    {
+                        this.disableSubmitButtons(false);
                         $parent.removeClass('has-error').addClass('has-success');
                         if ($icon) {
                             $icon.removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).addClass(this.options.feedbackIcons.valid).show();
                         }
+                    } else {
+                        this.disableSubmitButtons(true);
+                        $parent.removeClass('has-success').addClass('has-error');
+                        if ($icon) {
+                            $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.validating).addClass(this.options.feedbackIcons.invalid).show();
+                        }
                     }
                     break;
 
                 case this.STATUS_NOT_VALIDATED:
                 default:
-                    this._disableSubmitButtons(false);
+                    this.disableSubmitButtons(false);
                     $parent.removeClass('has-success').removeClass('has-error');
                     validatorName ? $errors.filter('.help-block[data-bv-validator="' + validatorName + '"]').hide() : $errors.hide();
                     if ($icon) {
@@ -491,6 +594,43 @@
             return this;
         },
 
+        /**
+         * Check the form validity
+         *
+         * @returns {Boolean}
+         */
+        isValid: function() {
+            var fields, field, $field,
+                type, status, validatorName,
+                n, i;
+            for (field in this.options.fields) {
+                if (this.options.fields[field] == null || !this.options.fields[field]['enabled']) {
+                    continue;
+                }
+
+                fields = this.getFieldElements(field);
+                type   = fields.attr('type');
+                n      = (('radio' == type) || ('checkbox' == type)) ? 1 : fields.length;
+
+                for (i = 0; i < n; i++) {
+                    $field = $(fields[i]);
+                    for (validatorName in this.options.fields[field].validators) {
+                        status = $field.data('bv.result.' + validatorName);
+                        if (status == this.STATUS_NOT_VALIDATED || status == this.STATUS_VALIDATING) {
+                            return false;
+                        }
+
+                        if (status == this.STATUS_INVALID) {
+                            this.$invalidField = $field;
+                            return false;
+                        }
+                    }
+                }
+            }
+
+            return true;
+        },
+
         // Useful APIs which aren't used internally
 
         /**
@@ -500,26 +640,31 @@
          * @return {BootstrapValidator}
          */
         resetForm: function(resetFormData) {
-            var field, $field, type;
+            var field, fields, total, type, validator;
             for (field in this.options.fields) {
-                this.dfds[field]    = {};
-                this.results[field] = {};
+                fields = this.getFieldElements(field);
+                total  = fields.length;
+
+                for (var i = 0; i < total; i++) {
+                    for (validator in this.options.fields[field].validators) {
+                        $(fields[i]).removeData('bv.dfs.' + validator);
+                    }
+                }
 
-                $field = this.getFieldElements(field);
                 // Mark field as not validated yet
-                this.updateStatus($field, this.STATUS_NOT_VALIDATED, null);
+                this.updateStatus(field, this.STATUS_NOT_VALIDATED, null);
 
                 if (resetFormData) {
-                    type = $field.attr('type');
-                    ('radio' == type || 'checkbox' == type) ? $field.removeAttr('checked').removeAttr('selected') : $field.val('');
+                    type = fields.attr('type');
+                    ('radio' == type || 'checkbox' == type) ? fields.removeAttr('checked').removeAttr('selected') : fields.val('');
                 }
             }
 
-            this.invalidField  = null;
+            this.$invalidField = null;
             this.$submitButton = null;
 
             // Enable submit buttons
-            this._disableSubmitButtons(false);
+            this.disableSubmitButtons(false);
 
             return this;
         },

+ 7 - 0
src/js/validator/between.js

@@ -1,5 +1,12 @@
 (function($) {
     $.fn.bootstrapValidator.validators.between = {
+        html5Attributes: {
+            message: 'message',
+            min: 'min',
+            max: 'max',
+            inclusive: 'inclusive'
+        },
+
         /**
          * Return true if the input value is between (strictly or not) two given numbers
          *

+ 1 - 1
src/js/validator/callback.js

@@ -18,7 +18,7 @@
             var value = $field.val();
             if (options.callback && 'function' == typeof options.callback) {
                 var dfd = new $.Deferred();
-                dfd.resolve(options.callback.call(this, value, validator), 'callback');
+                dfd.resolve($field, 'callback', options.callback.call(this, value, validator));
                 return dfd;
             }
             return true;

+ 7 - 0
src/js/validator/choice.js

@@ -1,5 +1,11 @@
 (function($) {
     $.fn.bootstrapValidator.validators.choice = {
+        html5Attributes: {
+            message: 'message',
+            min: 'min',
+            max: 'max'
+        },
+
         /**
          * Check if the number of checked boxes are less or more than a given number
          *
@@ -9,6 +15,7 @@
          * - min
          * - max
          * At least one of two keys is required
+         * - message: The invalid message
          * @returns {Boolean}
          */
         validate: function(validator, $field, options) {

+ 5 - 0
src/js/validator/cvv.js

@@ -1,5 +1,10 @@
 (function($) {
     $.fn.bootstrapValidator.validators.cvv = {
+        html5Attributes: {
+            message: 'message',
+            ccfield: 'creditCardField'
+        },
+
         /**
          * Return true if the input value is a valid CVV number.
          *

+ 5 - 0
src/js/validator/date.js

@@ -1,5 +1,10 @@
 (function($) {
     $.fn.bootstrapValidator.validators.date = {
+        html5Attributes: {
+            message: 'message',
+            format: 'format'
+        },
+
         /**
          * Return true if the input value is valid date
          *

+ 7 - 1
src/js/validator/different.js

@@ -1,5 +1,10 @@
 (function($) {
     $.fn.bootstrapValidator.validators.different = {
+        html5Attributes: {
+            message: 'message',
+            field: 'field'
+        },
+
         /**
          * Return true if the input value is different with given field's value
          *
@@ -7,6 +12,7 @@
          * @param {jQuery} $field Field element
          * @param {Object} options Consists of the following key:
          * - field: The name of field that will be used to compare with current one
+         * - message: The invalid message
          * @returns {Boolean}
          */
         validate: function(validator, $field, options) {
@@ -21,7 +27,7 @@
             }
 
             if (value != compareWith.val()) {
-                validator.updateStatus(compareWith, validator.STATUS_VALID, 'different');
+                validator.updateStatus(options.field, validator.STATUS_VALID, 'different');
                 return true;
             } else {
                 return false;

+ 4 - 0
src/js/validator/emailAddress.js

@@ -1,5 +1,9 @@
 (function($) {
     $.fn.bootstrapValidator.validators.emailAddress = {
+        enableByHtml5: function($field) {
+            return ('email' == $field.attr('type'));
+        },
+
         /**
          * Return true if and only if the input value is a valid email address
          *

+ 17 - 0
src/js/validator/greaterThan.js

@@ -1,5 +1,22 @@
 (function($) {
     $.fn.bootstrapValidator.validators.greaterThan = {
+        html5Attributes: {
+            message: 'message',
+            value: 'value',
+            inclusive: 'inclusive'
+        },
+
+        enableByHtml5: function($field) {
+            var min = $field.attr('min');
+            if (min) {
+                return {
+                    value: min
+                };
+            }
+
+            return false;
+        },
+
         /**
          * Return true if the input value is greater than or equals to given number
          *

+ 4 - 0
src/js/validator/hexColor.js

@@ -1,5 +1,9 @@
 (function($) {
     $.fn.bootstrapValidator.validators.hexColor = {
+        enableByHtml5: function($field) {
+            return ('color' == $field.attr('type'));
+        },
+
         /**
          * Return true if the input value is a valid hex color
          *

+ 6 - 1
src/js/validator/identical.js

@@ -1,5 +1,10 @@
 (function($) {
     $.fn.bootstrapValidator.validators.identical = {
+        html5Attributes: {
+            message: 'message',
+            field: 'field'
+        },
+
         /**
          * Check if input value equals to value of particular one
          *
@@ -21,7 +26,7 @@
             }
 
             if (value == compareWith.val()) {
-                validator.updateStatus(compareWith, validator.STATUS_VALID, 'identical');
+                validator.updateStatus(options.field, validator.STATUS_VALID, 'identical');
                 return true;
             } else {
                 return false;

+ 24 - 0
src/js/validator/integer.js

@@ -0,0 +1,24 @@
+(function($) {
+    $.fn.bootstrapValidator.validators.integer = {
+        enableByHtml5: function($field) {
+            return ('number' == $field.attr('type'));
+        },
+
+        /**
+         * Return true if the input value is an integer
+         *
+         * @param {BootstrapValidator} validator The validator plugin instance
+         * @param {jQuery} $field Field element
+         * @param {Object} options Can consist of the following key:
+         * - message: The invalid message
+         * @returns {Boolean}
+         */
+        validate: function(validator, $field, options) {
+            var value = $field.val();
+            if (value == '') {
+                return true;
+            }
+            return /^(?:-?(?:0|[1-9][0-9]*))$/.test(value);
+        }
+    };
+}(window.jQuery));

+ 6 - 0
src/js/validator/ip.js

@@ -1,5 +1,11 @@
 (function($) {
     $.fn.bootstrapValidator.validators.ip = {
+        html5Attributes: {
+            message: 'message',
+            ipv4: 'ipv4',
+            ipv6: 'ipv6'
+        },
+
         /**
          * Return true if the input value is a IP address.
          *

+ 18 - 1
src/js/validator/lessThan.js

@@ -1,5 +1,22 @@
 (function($) {
     $.fn.bootstrapValidator.validators.lessThan = {
+        html5Attributes: {
+            message: 'message',
+            value: 'value',
+            inclusive: 'inclusive'
+        },
+
+        enableByHtml5: function($field) {
+            var max = $field.attr('max');
+            if (max) {
+                return {
+                    value: max
+                };
+            }
+
+            return false;
+        },
+
         /**
          * Return true if the input value is less than or equal to given number
          *
@@ -17,7 +34,7 @@
                 return true;
             }
             value = parseFloat(value);
-            return (options.inclusive === true) ? (value < options.value) : (value <= options.value);
+            return (options.inclusive === false) ? (value <= options.value) : (value < options.value);
         }
     };
 }(window.jQuery));

+ 5 - 0
src/js/validator/notEmpty.js

@@ -1,5 +1,10 @@
 (function($) {
     $.fn.bootstrapValidator.validators.notEmpty = {
+        enableByHtml5: function($field) {
+            var required = $field.attr('required') + '';
+            return ('required' == required || 'true' == required);
+        },
+
         /**
          * Check if input value is empty or not
          *

+ 6 - 1
src/js/validator/phone.js

@@ -1,13 +1,18 @@
 (function($) {
     $.fn.bootstrapValidator.validators.phone = {
+        html5Attributes: {
+            message: 'message',
+            country: 'country'
+        },
+
         /**
          * Return true if the input value contains a valid US phone number only
          *
          * @param {BootstrapValidator} validator Validate plugin instance
          * @param {jQuery} $field Field element
          * @param {Object} options Consist of key:
+         * - message: The invalid message
          * - country: The ISO 3166 country code
-         *
          * Currently it only supports United State (US) country
          * @returns {Boolean}
          */

+ 18 - 1
src/js/validator/regexp.js

@@ -1,5 +1,21 @@
 (function($) {
     $.fn.bootstrapValidator.validators.regexp = {
+        html5Attributes: {
+            message: 'message',
+            regexp: 'regexp'
+        },
+
+        enableByHtml5: function($field) {
+            var pattern = $field.attr('pattern');
+            if (pattern) {
+                return {
+                    regexp: pattern
+                };
+            }
+
+            return false;
+        },
+
         /**
          * Check if the element value matches given regular expression
          *
@@ -15,7 +31,8 @@
                 return true;
             }
 
-            return options.regexp.test(value);
+            var regexp = ('string' == typeof options.regexp) ? new RegExp(options.regexp) : options.regexp;
+            return regexp.test(value);
         }
     };
 }(window.jQuery));

+ 6 - 1
src/js/validator/remote.js

@@ -1,5 +1,10 @@
 (function($) {
     $.fn.bootstrapValidator.validators.remote = {
+        html5Attributes: {
+            message: 'message',
+            url: 'url'
+        },
+
         /**
          * Request a remote server to check the input value
          *
@@ -38,7 +43,7 @@
                 data: data
             });
             xhr.then(function(response) {
-                dfd.resolve(response.valid === true || response.valid === 'true', 'remote');
+                dfd.resolve($field, 'remote', response.valid === true || response.valid === 'true');
             });
 
             dfd.fail(function() {

+ 6 - 0
src/js/validator/step.js

@@ -1,5 +1,11 @@
 (function($) {
     $.fn.bootstrapValidator.validators.step = {
+        html5Attributes: {
+            message: 'message',
+            base: 'baseValue',
+            step: 'step'
+        },
+
         /**
          * Return true if the input value is valid step one
          *

+ 18 - 0
src/js/validator/stringLength.js

@@ -1,5 +1,22 @@
 (function($) {
     $.fn.bootstrapValidator.validators.stringLength = {
+        html5Attributes: {
+            message: 'message',
+            min: 'min',
+            max: 'max'
+        },
+
+        enableByHtml5: function($field) {
+            var maxLength = $field.attr('maxlength');
+            if (maxLength) {
+                return {
+                    max: parseInt(maxLength, 10)
+                };
+            }
+
+            return false;
+        },
+
         /**
          * Check if the length of element value is less or more than given number
          *
@@ -9,6 +26,7 @@
          * - min
          * - max
          * At least one of two keys is required
+         * - message: The invalid message
          * @returns {Boolean}
          */
         validate: function(validator, $field, options) {

+ 4 - 0
src/js/validator/uri.js

@@ -1,5 +1,9 @@
 (function($) {
     $.fn.bootstrapValidator.validators.uri = {
+        enableByHtml5: function($field) {
+            return ('url' == $field.attr('type'));
+        },
+
         /**
          * Return true if the input value is a valid URL
          *

+ 6 - 1
src/js/validator/zipCode.js

@@ -1,18 +1,23 @@
 (function($) {
     $.fn.bootstrapValidator.validators.zipCode = {
+        html5Attributes: {
+            message: 'message',
+            country: 'country'
+        },
+
         /**
          * Return true if and only if the input value is a valid country zip code
          *
          * @param {BootstrapValidator} validator The validator plugin instance
          * @param {jQuery} $field Field element
          * @param {Object} options Consist of key:
+         * - message: The invalid message
          * - country: The ISO 3166 country code
          *
          * Currently it supports the following countries:
          * - US (United State)
          * - DK (Denmark)
          * - SE (Sweden)
-         *
          * @returns {Boolean}
          */
         validate: function(validator, $field, options) {