--- /dev/null
+!function(Foundation, $) {
+ 'use strict';
+
+ /**
+ * Creates a new instance of Abide.
+ * @class
+ * @fires Abide#init
+ * @param {Object} element - jQuery object to add the trigger to.
+ * @param {Object} options - Overrides to the default plugin settings.
+ */
+ function Abide(element, options) {
+ this.$element = element;
+ this.options = $.extend({}, Abide.defaults, this.$element.data(), options);
+
+ this._init();
+
+ Foundation.registerPlugin(this);
+ }
+
+ /**
+ * Default settings for plugin
+ */
+ Abide.defaults = {
+ validateOn: 'fieldChange', // options: fieldChange, manual, submit
+ labelErrorClass: 'is-invalid-label',
+ inputErrorClass: 'is-invalid-input',
+ formErrorSelector: '.form-error',
+ formErrorClass: 'is-visible',
+ liveValidate: false,
+
+ patterns: {
+ alpha : /^[a-zA-Z]+$/,
+ alpha_numeric : /^[a-zA-Z0-9]+$/,
+ integer : /^[-+]?\d+$/,
+ number : /^[-+]?\d*(?:[\.\,]\d+)?$/,
+
+ // amex, visa, diners
+ card : /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/,
+ cvv : /^([0-9]){3,4}$/,
+
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#valid-e-mail-address
+ email : /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[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])?)+$/,
+
+ url : /^(https?|ftp|file|ssh):\/\/(((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
+ // abc.de
+ domain : /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,8}$/,
+
+ datetime : /^([0-2][0-9]{3})\-([0-1][0-9])\-([0-3][0-9])T([0-5][0-9])\:([0-5][0-9])\:([0-5][0-9])(Z|([\-\+]([0-1][0-9])\:00))$/,
+ // YYYY-MM-DD
+ date : /(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))$/,
+ // HH:MM:SS
+ time : /^(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2}$/,
+ dateISO : /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
+ // MM/DD/YYYY
+ month_day_year : /^(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.]\d{4}$/,
+ // DD/MM/YYYY
+ day_month_year : /^(0[1-9]|[12][0-9]|3[01])[- \/.](0[1-9]|1[012])[- \/.]\d{4}$/,
+
+ // #FFF or #FFFFFF
+ color : /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/
+ },
+
+ validators: {
+ equalTo: function (el, required, parent) {
+ return $('#' + el.attr('data-equalto')).val() === el.val();
+ }
+ }
+ };
+
+
+ /**
+ * Initializes the Abide plugin and calls functions to get Abide functioning on load.
+ * @private
+ */
+ Abide.prototype._init = function(){
+ this.$inputs = this.$element.find('input, textarea, select');
+ this._events();
+ };
+
+ /**
+ * Initializes events for Abide.
+ * @private
+ */
+ Abide.prototype._events = function() {
+ var _this = this;
+
+ this.$element.off('.abide')
+ .on('reset.zf.abide reset.fndtn.abide', function(e){
+ _this.resetForm($(this));
+ })
+ .on('submit.zf.abide submit.fndtn.abide', function(e){
+ _this.validateForm();
+ });
+
+ this.$inputs.off('.abide')
+ .on('change.zf.abide', function(e){
+ if(_this.options.validateOn === 'fieldChange') _this.validateInput($(this));
+ });
+
+ if(this.options.liveValidate){
+ this.$inputs.on('input.zf.abide', function(e){
+ _this.validateInput($(this));
+ });
+ }
+ },
+ /**
+ * Calls necessary functions to update Abide upon DOM change
+ * @private
+ */
+ Abide.prototype._reflow = function() {
+ var self = this;
+ };
+ /**
+ * Checks whether or not a form element has the required attribute and if it's checked or not
+ * @param {Object} element - jQuery object to check for required attribute
+ * @returns {Boolean} Boolean value depends on whether or not attribute is checked or empty
+ */
+ var counter = 0;
+ Abide.prototype.requiredCheck = function($el) {
+ if(!$el.attr('required')) return true;
+ var isGood = true;
+ switch ($el[0].type) {
+
+ case 'checkbox':
+ case 'radio':
+ isGood = $el[0].checked;
+ break;
+
+ case 'select':
+ case 'select-one':
+ var opt = $el.find('option:selected');
+ if(!opt.length || !opt.val()) isGood = false;
+ break;
+
+ default:
+ if(!$el.val() || !$el.val().length) isGood = false;
+ }
+ return isGood;
+ };
+ /**
+ * Based on $el, get the first element with selector in this order:
+ * 1. The element next to it.
+ * 2. The element inside (is a child of) it.
+ * 3. As its sibling.
+ *
+ * @param {Object} element - jQuery object to use as reference to find the form error selector.
+ * @param {String} selector - jQuery selector to show error message when field doesn't pass validation.
+ * @returns {Object} jQuery object with the selector.
+ */
+ Abide.prototype.findFormError = function($el, selector) {
+ };
+ /**
+ * Get the first element in this order:
+ * 1. The closest parent ".input-group" class.
+ * 2. The <label> next to the element.
+ * 3. The closest parent <label>
+ *
+ * @param {Object} element - jQuery object to check for required attribute
+ * @returns {Boolean} Boolean value depends on whether or not attribute is checked or empty
+ */
+ Abide.prototype.findLabel = function($el) {
+ };
+ /**
+ * Adds the CSS error class as specified by the Abide settings to the label, input, and the form
+ * @param {Object} element - jQuery object to add the class to
+ */
+ Abide.prototype.addErrorClasses = function($el){
+
+ };
+ /**
+ * Removes CSS error class as specified by the Abide settings from the label, input, and the form
+ * @param {Object} element - jQuery object to remove the class from
+ */
+ Abide.prototype.removeErrorClasses = function($el) {
+ };
+ /**
+ * Goes through a form to find inputs and proceeds to validate them in ways specific to their type
+ * @fires Abide#invalid
+ * @fires Abide#valid
+ * @param {Object} element - jQuery object to validate, should be an HTML input
+ * @param {Object} form - jQuery object of the entire form to find the various input elements
+ */
+ Abide.prototype.validateInput = function($el, $form){
+ var clearRequire = this.requiredCheck($el),
+ validated = true;
+
+ switch ($el[0].type) {
+
+ case 'radio':
+ validated = this.validateRadio($el.attr('name'));
+ break;
+
+ case 'checkbox':
+ validated = clearRequire;
+ break;
+
+ case 'select':
+ case 'select-one':
+ console.log('validating selects');
+ validated = clearRequire;
+ break;
+
+ default:
+ validated = this.validateText($el);
+ }
+ var goodToGo = (clearRequire === validated === true),
+ message = (goodToGo ? 'valid' : 'invalid') + '.zf.abide';
+ console.log(goodToGo);
+ this[goodToGo ? 'removeErrorClasses' : 'addErrorClasses']($el);
+ $el.trigger(message, $el[0]);
+ return goodToGo;
+ };
+ /**
+ * Goes through a form and if there are any invalid inputs, it will display the form error element
+ * @param {Object} element - jQuery object to validate, should be a form HTML element
+ */
+ Abide.prototype.validateForm = function(){
+ var acc = [],
+ _this = this;
+
+ this.$inputs.each(function(){
+ acc.push(_this.validateInput($(this)));
+ });
+
+ hasError = acc.indexOf(false) > -1;
+
+ this.$element.find('[data-abide-error]').css('display', (hasError ? 'block' : 'none'));
+
+ return !hasError;
+ };
+ /**
+ * Determines whether or a not a text input is valid based on the patterns specified in the attribute
+ * @param {Object} element - jQuery object to validate, should be a text input HTML element
+ * @returns {Boolean} Boolean value depends on whether or not the input value matches the pattern specified
+ */
+ Abide.prototype.validateText = function($el, pattern){
+ console.log('validating text', $el);
+ pattern = pattern ? pattern : $el.attr('pattern');
+ var inputText = $el.val();
+
+ return inputText.length ?
+ this.options.patterns.hasOwnProperty(pattern) ? this.options.patterns[pattern].test(inputText) :
+ true : true;
+ };
+ /**
+ * Determines whether or a not a radio input is valid based on whether or not it is required and selected
+ * @param {String} group - A string that specifies the name of a radio button group
+ * @returns {Boolean} Boolean value depends on whether or not at least one radio input has been selected (if it's required)
+ */
+ Abide.prototype.validateRadio = function(groupName){
+ var $group = this.$element.find(':radio[name="' + groupName + '"]'),
+ counter = [],
+ _this = this;
+
+ $group.each(function(){
+ counter.push(_this.requiredCheck($(this)));
+ });
+ return counter.indexOf(false) === -1;
+ };
+ Abide.prototype.matchValidation = function(val, validation){
+
+ };
+ /**
+ * Resets form inputs and styles
+ * @param {Object} $form - A jQuery object that should be an HTML form element
+ */
+ Abide.prototype.resetForm = function($form) {
+ var self = this;
+ var invalidAttr = 'data-invalid';
+ // remove data attributes
+ $('[' + self.invalidAttr + ']', $form).removeAttr(invalidAttr);
+ // remove styles
+ $('.' + self.options.labelErrorClass, $form).not('small').removeClass(self.options.labelErrorClass);
+ $('.' + self.options.inputErrorClass, $form).not('small').removeClass(self.options.inputErrorClass);
+ $('.form-error.is-visible').removeClass('is-visible');
+ $form.find('[data-abide-error]').css('display', 'none');
+ $(':input', $form).not(':button, :submit, :reset, :hidden, [data-abide-ignore]').val('').removeAttr(invalidAttr);
+ };
+ Abide.prototype.destroy = function(){
+ //TODO this...
+ };
+
+ Foundation.plugin(Abide, 'Abide');
+
+ // Exports for AMD/Browserify
+ if (typeof module !== 'undefined' && typeof module.exports !== 'undefined')
+ module.exports = Abide;
+ if (typeof define === 'function')
+ define(['foundation'], function() {
+ return Abide;
+ });
+
+}(Foundation, jQuery);