123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /*! H5F
- * https://github.com/ryanseddon/H5F/
- * Copyright (c) Ryan Seddon | Licensed MIT */
- (function (root, factory) {
- if (typeof define === 'function' && define.amd) {
- // AMD. Register as an anonymous module.
- define(factory);
- } else if (typeof module === 'object' && module.exports) {
- // CommonJS
- module.exports = factory();
- } else {
- // Browser globals
- root.H5F = factory();
- }
- }(this, function () {
- var d = document,
- field = d.createElement("input"),
- emailPatt = /^[a-zA-Z0-9.!#$%&'*+-\/=?\^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
- urlPatt = /[a-z][\-\.+a-z]*:\/\//i,
- nodes = /^(input|select|textarea)$/i,
- isSubmit, bypassSubmit, usrPatt, curEvt, args,
- // Methods
- setup, validation, validity, checkField, bypassChecks, checkValidity, setCustomValidity, support, pattern, placeholder, range, required, valueMissing, listen, unlisten, preventActions, getTarget, addClass, removeClass, isHostMethod, isSiblingChecked;
- setup = function(form, settings) {
- var isCollection = !form.nodeType || false;
- var opts = {
- validClass : "valid",
- invalidClass : "error",
- requiredClass : "required",
- placeholderClass : "placeholder",
- onSubmit : Function.prototype,
- onInvalid : Function.prototype
- };
- 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,"change",checkField,true);
- listen(form,"click",bypassChecks,true);
- listen(form,"submit",function(e){
- isSubmit = true;
- if(!bypassSubmit && !noValidate && !form.checkValidity()) {
- preventActions(e);
- return;
- }
- args.onSubmit.call(form, 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.toLowerCase() !== "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 = !( elem.validationMessage === "" || elem.validationMessage === undefined );
- elem.checkValidity = function() { return checkValidity.call(this,elem); };
- elem.setCustomValidity = function(msg) { setCustomValidity.call(elem,msg); };
- 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|change)$/i,
- ignoredTypes = /^(submit|image|button|reset)$/i,
- specialTypes = /^(checkbox|radio)$/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 && (el.value !== "" || specialTypes.test(el.type)) || (el.value !== el.getAttribute("placeholder") && 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 if(!el.validity.valid) {
- 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, isDisabled, isRequired, hasPattern, invalid = false;
- if(el.nodeName.toLowerCase() === "form") {
- f = el.elements;
- for(var i = 0,len = f.length;i < len;i++) {
- ff = f[i];
- isDisabled = !!(ff.attributes["disabled"]);
- isRequired = !!(ff.attributes["required"]);
- hasPattern = !!(ff.attributes["pattern"]);
- if(ff.nodeName.toLowerCase() !== "fieldset" && !isDisabled && (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;
- args.onInvalid.call(el, ff);
- }
- }
- }
- return !invalid;
- } else {
- checkField(el);
- return el.validity.valid;
- }
- };
- setCustomValidity = function(msg) {
- var el = this;
- el.validationMessage = msg;
- };
- bypassChecks = function(e) {
- // handle formnovalidate attribute
- var el = getTarget(e);
- if(el.attributes["formnovalidate"] && el.type === "submit") {
- bypassSubmit = true;
- }
- };
- 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 false;
- } 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"),
- specialTypes = /^(checkbox|radio)$/i,
- isRequired = !!(el.attributes["required"]);
- return !!(isRequired && (el.value === "" || el.value === placeholder || (specialTypes.test(el.type) && !isSiblingChecked(el))));
- };
- /* 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');
- };
- /* Checking if one of the radio siblings is checked */
- isSiblingChecked = function(el) {
- var siblings = document.getElementsByName(el.name);
- for(var i=0; i<siblings.length; i++){
- if(siblings[i].checked){
- return true;
- }
- }
- return false;
- };
- // Since all methods are only used internally no need to expose globally
- return {
- setup: setup
- };
- }));
|