]> git.ipfire.org Git - thirdparty/foundation/foundation-sites.git/commitdiff
Support custom validators with abide 4669/head
authorSteve Hull <p.witty@gmail.com>
Thu, 13 Mar 2014 17:54:50 +0000 (10:54 -0700)
committerSteve Hull <p.witty@gmail.com>
Thu, 13 Mar 2014 17:54:50 +0000 (10:54 -0700)
doc/includes/abide/examples_abide_javascript_options.html
doc/pages/components/abide.html
js/foundation/foundation.abide.js
spec/abide/abide.js
spec/abide/advanced.html [new file with mode: 0644]

index ebae95bb273e066ce2efbc76fedcf8adada3a2a2..66e4c2eaca68667705bcb83bb4e9578b6f93dac9 100644 (file)
@@ -36,8 +36,14 @@ $(document).foundation({
 
       // #FFF or #FFFFFF
       color: /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/
+    },
+    validators: {
+      diceRoll: function(el, required, parent) {
+        var possibilities = [true, false];
+        return possibilities[Math.round(Math.random())];
+      }
     }
   }
 });
 ```
-{{/markdown}}
\ No newline at end of file
+{{/markdown}}
index 4855f156c1ee0af78790ff00467e9b8f11504a4e..9fb8ec018560c342a5dd2272103e7b57ac78f6ff 100644 (file)
@@ -95,6 +95,35 @@ To handle the `submit` event yourself, use `data-abide="ajax"` instead of `data-
 
 ***
 
+## Custom Validators
+
+`equalTo` is actually an example of a built-in validator. To get an idea of how validators work, check out the implementation of `equalTo`:
+
+{{#markdown}}
+```javascript
+equalTo: function(el, required, parent) {
+  var from  = document.getElementById(el.getAttribute(this.add_namespace('data-equalto'))).value,
+      to    = el.value,
+      valid = (from === to);
+
+  return valid;
+}
+```
+{{/markdown}}
+
+Your function will be passed three arguments: `el`, `required`, and `parent`. These are the elements being validated, whether or not it was marked as required, and the parent of the element being validated, respectively.
+Your function should return `true` if the element is valid, or `false` if it is invalid. You can define your custom validators and pass them into abide options when initializing foundation. See the Configuration section for more details on defining custom validators.
+
+Suppose you've defined a custom validator `diceRoll` which randomly marks your element as valid or invalid. You would use it like so:
+
+{{#markdown}}
+```html
+<input type="text" data-abide-validator="diceRoll">
+```
+{{/markdown}}
+
+***
+
 ## Using the Javascript
 
 <div class="panel">
index 8cb4b7872d9eef86398d53a08e8dad0396e08724..021268a8a6e9ef00225bbf41e6e5dc7cb3d33e35 100644 (file)
 
         // #FFF or #FFFFFF
         color: /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/
+      },
+      validators : {
+        equalTo: function(el, required, parent) {
+          var from  = document.getElementById(el.getAttribute(this.add_namespace('data-equalto'))).value,
+              to    = el.value,
+              valid = (from === to);
+
+          return valid;
+        }
       }
     },
 
       } else if (pattern.length > 0) {
         return [el, new RegExp(pattern), required];
       }
-      
+
       if (this.settings.patterns.hasOwnProperty(type)) {
         return [el, this.settings.patterns[type], required];
       }
             required = el_patterns[i][2],
             value = el.value,
             direct_parent = this.S(el).parent(),
-            is_equal = el.getAttribute(this.add_namespace('data-equalto')),
+            validator = el.getAttribute(this.add_namespace('data-abide-validator')),
             is_radio = el.type === "radio",
             is_checkbox = el.type === "checkbox",
             label = this.S('label[for="' + el.getAttribute('id') + '"]'),
             valid_length = (required) ? (el.value.length > 0) : true;
 
-        var parent;
+        var parent, valid;
+
+        // support old way to do equalTo validations
+        if(el.getAttribute(this.add_namespace('data-equalto'))) { validator = "equalTo" }
 
         if (!direct_parent.is('label')) {
           parent = direct_parent;
           validations.push(this.valid_radio(el, required));
         } else if (is_checkbox && required) {
           validations.push(this.valid_checkbox(el, required));
-        } else if (is_equal && required) {
-          validations.push(this.valid_equal(el, required, parent));
+        } else if (validator) {
+          valid = this.settings.validators[validator].apply(this, [el, required, parent])
+          validations.push(valid);
+
+          if (valid) {
+            this.S(el).removeAttr(this.invalid_attr);
+            parent.removeClass('error');
+          } else {
+            this.S(el).attr(this.invalid_attr, '');
+            parent.addClass('error');
+          }
         } else {
 
           if (el_patterns[i][1].test(value) && valid_length ||
         }
       }
 
-      return valid;
-    },
-
-    valid_equal: function(el, required, parent) {
-      var from  = document.getElementById(el.getAttribute(this.add_namespace('data-equalto'))).value,
-          to    = el.value,
-          valid = (from === to);
-
-      if (valid) {
-        this.S(el).removeAttr(this.invalid_attr);
-        parent.removeClass('error');
-      } else {
-        this.S(el).attr(this.invalid_attr, '');
-        parent.addClass('error');
-      }
-
       return valid;
     }
   };
index 23a219e39f61daeb37c0777435162582f1be0baf..5d8f14d7430e29043b5f73633ebbff4200425e64 100644 (file)
@@ -90,4 +90,84 @@ describe('abide:', function() {
       expect('invalid').not.toHaveBeenTriggeredOn('input[name="user_email"]');
     });
   });
+
+  describe('advanced validation', function() {
+    beforeEach(function() {
+      document.body.innerHTML = __html__['spec/abide/advanced.html'];
+    });
+
+    it('should support builtin equalTo validator', function() {
+      $(document).foundation({
+        abide: {
+          validators: {
+            range: function(){ return true; }
+          }
+        }
+      });
+
+
+      expect($('input[name="user_password"]')).not.toHaveAttr('data-invalid');
+      expect($('input[name="user_password_confirmation"]')).not.toHaveAttr('data-invalid');
+
+      $('input[name="user_password"]').val("foobarbaz");
+      // now they're not equal
+      $('form').submit();
+
+      var invalid_fields = $('form').find('[data-invalid]');
+      expect(invalid_fields.length).toBe(1);
+      expect($('input[name="user_password_confirmation"]')).toHaveAttr('data-invalid');
+
+      $('input[name="user_password_confirmation"]').val("foobarbaz");
+      // now they're equal
+      spyOnEvent('form', 'invalid');
+      spyOnEvent('form', 'valid');
+
+      $('form').submit();
+
+      expect('valid').toHaveBeenTriggeredOn('form');
+      expect($('input[name="user_password"]')).not.toHaveAttr('data-invalid');
+      expect($('input[name="user_password_confirmation"]')).not.toHaveAttr('data-invalid');
+    });
+
+    it('should support custom validators', function() {
+      $(document).foundation({
+        abide: {
+          validators: {
+            range: function(el, required, parent) {
+              var start = parseInt(this.S("[name='user_start_num']").val()),
+                  end = parseInt(el.value);
+
+              return start < end;
+            }
+          }
+        }
+      });
+
+      expect($('input[name="user_start_num"]')).not.toHaveData('invalid');
+      expect($('input[name="user_end_num"]')).not.toHaveData('invalid');
+
+      // invalid
+      $('input[name="user_start_num"]').val("10");
+      $('input[name="user_end_num"]').val("2");
+
+      $('form').submit();
+
+      var invalid_fields = $('form').find('[data-invalid]');
+      expect(invalid_fields.length).toBe(1);
+
+      expect($('input[name="user_start_num"]')).not.toHaveAttr('data-invalid');
+      expect($('input[name="user_end_num"]')).toHaveAttr('data-invalid');
+
+      // valid now
+      $('input[name="user_end_num"]').val("12");
+      spyOnEvent('form', 'invalid');
+      spyOnEvent('form', 'valid');
+
+      $('form').submit();
+
+      expect('valid').toHaveBeenTriggeredOn('form');
+      expect($('input[name="user_start_num"]')).not.toHaveAttr('data-invalid');
+      expect($('input[name="user_end_num"]')).not.toHaveAttr('data-invalid');
+    });
+  });
 });
diff --git a/spec/abide/advanced.html b/spec/abide/advanced.html
new file mode 100644 (file)
index 0000000..718f6e3
--- /dev/null
@@ -0,0 +1,22 @@
+<form data-abide="ajax">
+  <div class="range-start-field">
+    <label>Starting number <small>required</small></label>
+    <input name="user_start_num" type="text">
+    <small class="error">Starting number must be before the end date</small>
+  </div>
+  <div class="range-end-field">
+    <label>Ending number <small>required</small></label>
+    <input name="user_end_num" type="text" data-abide-validator="range">
+    <small class="error">Ending number must be before the end date</small>
+  </div>
+  <div class="password-field">
+    <label>Password <small>required</small></label>
+    <input id="user_password" name="user_password" type="password">
+  </div>
+  <div class="password-confirmation-field">
+    <label>Password confirmation<small>required</small></label>
+    <input name="user_password_confirmation" type="password" data-abide-validator="equalTo" data-equalto="user_password">
+    <small class="error">Password and password confirmation must match.</small>
+  </div>
+  <button type="submit">Submit</button>
+</form>