text: ﻿/*=======================h5f.js===========================*/
  /*
   * HTML5 Forms Chapter JavaScript Library
   * http://thecssninja.com/javascript/H5F
   *
   * Copyright (c) 2010-2011 Ryan Seddon - http://thecssninja.com/
   * Dual-licensed under the BSD and MIT licenses.
   * http://thecssninja.com/H5F/license.txt
   */
  
  var H5F = H5F || {};
  
  (function(d){
      
      var field = d.createElement("input"),
          emailPatt = /^[a-z0-9_.%+\-]+@[0-9a-z.\-]+\.[a-z.]{2,6}$/i, 
          urlPatt = /[a-z][\-\.+a-z]*:\/\//i,
          nodes = /^(input|select|textarea)$/i,
          isSubmit, usrPatt, curEvt, args, custMsg = "",
          // Methods
          setup, validation, validity, checkField, checkValidity, setCustomValidity, support, pattern, placeholder, range, required, valueMissing, listen, unlisten, preventActions, getTarget, addClass, removeClass, isHostMethod;
      
      setup = function(form,settings) {
          var isCollection = !form.nodeType || false;
          
          var opts = {
              validClass : "valid",
              invalidClass : "error",
              requiredClass : "required",
              placeholderClass : "placeholder"
          };
  
          if(typeof settings == "object") {
              for (var i in opts) {
                  if(typeof settings[i] == "undefined") { settings[i] = opts[i]; }
              }
          }
          
          args = settings || opts;
          
          if(isCollection) {
              for(var k=0,len=form.length;k<len;k++) {
                  validation(form[k]);
              }
          } else {
              validation(form);
          }
      };
      
      validation = function(form) {
          var f = form.elements,
              flen = f.length,
              isRequired, noValidate = !!(form.attributes["novalidate"]);
          
          listen(form,"invalid",checkField,true);
          listen(form,"blur",checkField,true);
          listen(form,"input",checkField,true);
          listen(form,"keyup",checkField,true);
          listen(form,"focus",checkField,true);
          
          listen(form,"submit",function(e){
              isSubmit = true;
              if(!noValidate && !form.checkValidity()) {
                  preventActions(e);
              }
          },false);
          
          if(!support()) { 
              form.checkValidity = function() { return checkValidity(form); };
              
              while(flen--) {
                  isRequired = !!(f[flen].attributes["required"]);
                  // Firefox includes fieldsets inside elements nodelist so we filter it out.
                  if(f[flen].nodeName !== "FIELDSET") {
                      validity(f[flen]); // Add validity object to field
                  }
              }
          }
      };
      validity = function(el) {
          var elem = el,
              missing = valueMissing(elem),
              attrs = { 
                  type: elem.getAttribute("type"), 
                  pattern: elem.getAttribute("pattern"), 
                  placeholder: elem.getAttribute("placeholder") 
              },
              isType = /^(email|url)$/i,
              evt = /^(input|keyup)$/i,
              fType = ((isType.test(attrs.type)) ? attrs.type : ((attrs.pattern) ? attrs.pattern : false)),
              patt = pattern(elem,fType),
              step = range(elem,"step"),
              min = range(elem,"min"),
              max = range(elem,"max"),
              customError = (custMsg !== "");
          
          elem.checkValidity = function() { return checkValidity.call(this,elem); };
          elem.setCustomValidity = function(msg) { setCustomValidity.call(elem,msg); };
          elem.validationMessage = custMsg;
          
          elem.validity = {
              valueMissing: missing,
              patternMismatch: patt,
              rangeUnderflow: min,
              rangeOverflow: max,
              stepMismatch: step,
              customError: customError,
              valid: (!missing && !patt && !step && !min && !max && !customError)
          };
          
          if(attrs.placeholder && !evt.test(curEvt)) { placeholder(elem); }
      };
      checkField = function (e) {
          var el = getTarget(e) || e, // checkValidity method passes element not event
              events = /^(input|keyup|focusin|focus)$/i,
              ignoredTypes = /^(submit|image|button|reset)$/i,
              checkForm = true;
          
          if(nodes.test(el.nodeName) && !(ignoredTypes.test(el.type) || ignoredTypes.test(el.nodeName))) {
              curEvt = e.type;
              if(!support()) { validity(el); }
              
              if(el.validity.valid) {
                  removeClass(el,[args.invalidClass,args.requiredClass]);
                  addClass(el,args.validClass);
              } else if(!events.test(curEvt)) {
                  if(el.validity.valueMissing) {
                      removeClass(el,[args.invalidClass,args.validClass]);
                      addClass(el,args.requiredClass);
                  } else {
                      removeClass(el,[args.validClass,args.requiredClass]);
                      addClass(el,args.invalidClass);
                  }
              } else if(el.validity.valueMissing) {
                  removeClass(el,[args.requiredClass,args.invalidClass,args.validClass]);
              }
              if(curEvt === "input" && checkForm) {
                  // If input is triggered remove the keyup event
                  unlisten(el.form,"keyup",checkField,true);
                  checkForm = false;
              }
          }
      };
      checkValidity = function (el) {
          var f, ff, isRequired, hasPattern, invalid = false;
          
          if(el.nodeName === "FORM") {
              f = el.elements;
              
              for(var i = 0,len = f.length;i < len;i++) {
                  ff = f[i];
                  
                  isRequired = !!(ff.attributes["required"]);
                  hasPattern = !!(ff.attributes["pattern"]);
                  
                  if(ff.nodeName !== "FIELDSET" && (isRequired || hasPattern && isRequired)) {
                      checkField(ff);
                      if(!ff.validity.valid && !invalid) {
                          if(isSubmit) { // If it's not a submit event the field shouldn't be focused
                              ff.focus();
                          }
                          invalid = true;
                      }
                  }
              }
              return !invalid;
          } else {
              checkField(el);
              return el.validity.valid;
          }
      };
      setCustomValidity = function (msg) {
          var el = this;
          custMsg = msg;
              
          el.validationMessage = custMsg;
      };
      
      support = function() {
          return (isHostMethod(field,"validity") && isHostMethod(field,"checkValidity"));
      };
  
      // Create helper methods to emulate attributes in older browsers
      pattern = function(el, type) {
          if(type === "email") {
              return !emailPatt.test(el.value);
          } else if(type === "url") {
              return !urlPatt.test(el.value);
          } else if(!type) {
              return false;
          } else {
              var placeholder = el.getAttribute("placeholder"),
                  val = el.value;
              
              usrPatt = new RegExp('^(?:' + type + ')$');
              
              if(val === placeholder) {    
                  return true;
              } else if(val === "") {
                  return false;
              } else {
                  return !usrPatt.test(el.value);
              }
          }
      };
      placeholder = function(el) {
          var attrs = { placeholder: el.getAttribute("placeholder") },
              focus = /^(focus|focusin|submit)$/i,
              node = /^(input|textarea)$/i,
              ignoredType = /^password$/i,
              isNative = !!("placeholder" in field);
          
          if(!isNative && node.test(el.nodeName) && !ignoredType.test(el.type)) {
              if(el.value === "" && !focus.test(curEvt)) {
                  el.value = attrs.placeholder;
                  listen(el.form,'submit', function () {
                    curEvt = 'submit';
                    placeholder(el);
                  }, true);
                  addClass(el,args.placeholderClass);
              } else if(el.value === attrs.placeholder && focus.test(curEvt)) {
                  el.value = "";
                  removeClass(el,args.placeholderClass);
              }
          }
      };
      range = function(el,type) {
          // Emulate min, max and step
          var min = parseInt(el.getAttribute("min"),10) || 0,
              max = parseInt(el.getAttribute("max"),10) || false,
              step = parseInt(el.getAttribute("step"),10) || 1,
              val = parseInt(el.value,10),
              mismatch = (val-min)%step;
          
          if(!valueMissing(el) && !isNaN(val)) {
              if(type === "step") {
                  return (el.getAttribute("step")) ? (mismatch !== 0) : false;
              } else if(type === "min") {
                  return (el.getAttribute("min")) ? (val < min) : false;
              } else if(type === "max") {
                  return (el.getAttribute("max")) ? (val > max) : false;
              } 
          } else if(el.getAttribute("type") === "number") { 
              return true;
          } else {
              return false;
          }
      };
      required = function(el) {
          var required = !!(el.attributes["required"]);
          
          return (required) ? valueMissing(el) : false;
      };
      valueMissing = function(el) {
          var placeholder = el.getAttribute("placeholder"),
              isRequired = !!(el.attributes["required"]);
          return !!(isRequired && (el.value === "" || el.value === placeholder));
      };
      
      /* Util methods */
      listen = function (node,type,fn,capture) {
          if(isHostMethod(window,"addEventListener")) {
              /* FF & Other Browsers */
              node.addEventListener( type, fn, capture );
          } else if(isHostMethod(window,"attachEvent") && typeof window.event !== "undefined") {
              /* Internet Explorer way */
              if(type === "blur") {
                  type = "focusout";
              } else if(type === "focus") {
                  type = "focusin";
              }
              node.attachEvent( "on" + type, fn );
          }
      };
      unlisten = function (node,type,fn,capture) {
          if(isHostMethod(window,"removeEventListener")) {
              /* FF & Other Browsers */
              node.removeEventListener( type, fn, capture );
          } else if(isHostMethod(window,"detachEvent") && typeof window.event !== "undefined") {
              /* Internet Explorer way */
              node.detachEvent( "on" + type, fn );
          }
      };
      preventActions = function (evt) {
          evt = evt || window.event;
          
          if(evt.stopPropagation && evt.preventDefault) {
              evt.stopPropagation();
              evt.preventDefault();
          } else {
              evt.cancelBubble = true;
              evt.returnValue = false;
          }
      };
      getTarget = function (evt) {
          evt = evt || window.event;
          return evt.target || evt.srcElement;
      };
      addClass = function (e,c) {
          var re;
          if (!e.className) {
              e.className = c;
          }
          else {
              re = new RegExp('(^|\\s)' + c + '(\\s|$)');
              if (!re.test(e.className)) { e.className += ' ' + c; }
          }
      };
      removeClass = function (e,c) {
          var re, m, arr = (typeof c === "object") ? c.length : 1, len = arr;
          if (e.className) {
              if (e.className == c) {
                  e.className = '';
              }
              else {        
                  while(arr--) {
                      re = new RegExp('(^|\\s)' + ((len > 1) ? c[arr] : c) + '(\\s|$)');
                      m = e.className.match(re);
                      if (m && m.length == 3) { e.className = e.className.replace(re, (m[1] && m[2])?' ':''); }
                  }
              }
          }
      };
      isHostMethod = function(o, m) {
          var t = typeof o[m], reFeaturedMethod = new RegExp('^function|object$', 'i');
          return !!((reFeaturedMethod.test(t) && o[m]) || t == 'unknown');
      };
      
      // Since all methods are only used internally no need to expose globally
      window["H5F"] = {
          setup: setup
      };
  
  })(document);
  