New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

pristinejs

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pristinejs - npm Package Compare versions

Comparing version

to
0.1.2

src/utils.js

190

dist/pristine.js

@@ -16,5 +16,23 @@ (function (global, factory) {

min: "Minimum value for this field is ${1}",
max: "Maximum value for this field is ${1}"
max: "Maximum value for this field is ${1}",
pattern: "Input must match the pattern ${1}"
};
function findAncestor(el, cls) {
while ((el = el.parentElement) && !el.classList.contains(cls)) {}
return el;
}
function tmpl(o) {
var _arguments = arguments;
return this.replace(/\${([^{}]*)}/g, function (a, b) {
return _arguments[b];
});
}
function groupedElemCount(input) {
return input.pristine.self.form.querySelectorAll('input[name="' + input.getAttribute('name') + '"]:checked').length;
}
var defaultConfig = {

@@ -31,3 +49,3 @@ classTo: 'form-group',

var SELECTOR = "input:not([type^=hidden]):not([type^=submit]), select, textarea";
var ALLOWED_ATTRIBUTES = ["required", "min", "max", 'minlength', 'maxlength'];
var ALLOWED_ATTRIBUTES = ["required", "min", "max", 'minlength', 'maxlength', 'pattern'];

@@ -47,47 +65,39 @@ var validators = {};

_('required', { fn: function fn(val) {
return val !== '';
return this.type === 'radio' || this.type === 'checkbox' ? groupedElemCount(this) : val !== undefined && val !== '';
}, priority: 99, halt: true });
_('email', { fn: function fn(val) {
return (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val)
);
}, priority: 1 });
return !val || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val);
} });
_('number', { fn: function fn(val) {
return parseFloat(val);
}, priority: 1 });
return !val || !isNaN(parseFloat(val));
}, priority: 2 });
_('integer', { fn: function fn(val) {
return val && /^\d+$/.test(val);
} });
_('minlength', { fn: function fn(val, length) {
return console.log(val, length) || val && val.length >= parseInt(length);
}, priority: 1 });
return !val || val.length >= parseInt(length);
} });
_('maxlength', { fn: function fn(val, length) {
return val && val.length <= parseInt(length);
}, priority: 1 });
return !val || val.length <= parseInt(length);
} });
_('min', { fn: function fn(val, limit) {
return parseFloat(val) >= parseFloat(limit);
}, priority: 1 });
return !val || (this.type === 'checkbox' ? groupedElemCount(this) >= parseInt(limit) : parseFloat(val) >= parseFloat(limit));
} });
_('max', { fn: function fn(val, limit) {
return parseFloat(val) <= parseFloat(limit);
}, priority: 1 });
return !val || (this.type === 'checkbox' ? groupedElemCount(this) <= parseInt(limit) : parseFloat(val) <= parseFloat(limit));
} });
_('pattern', { fn: function fn(val, pattern) {
var m = pattern.match(new RegExp('^/(.*?)/([gimy]*)$'));return !val || new RegExp(m[1], m[2]).test(val);
} });
function findAncestor(el, cls) {
while ((el = el.parentElement) && !el.classList.contains(cls)) {}
return el;
}
function Pristine(form, config, live) {
function tmpl(o) {
var _arguments = arguments;
return this.replace(/\${([^{}]*)}/g, function (a, b) {
return _arguments[b];
});
}
function Pristine(form, config, online) {
var self = this;
init(form, config, online);
init(form, config, live);
function init(form, config, online) {
function init(form, config, live) {
self.form = form;
self.config = config || defaultConfig;
self.online = !(online === false);
self.live = !(live === false);
self.fields = Array.from(form.querySelectorAll(SELECTOR)).map(function (input) {

@@ -97,20 +107,20 @@

var params = {};
var messages = {};
ALLOWED_ATTRIBUTES.forEach(function (item) {
var val = input.getAttribute(item);
if (val !== null) {
_addValidatorToField(fns, params, item, val);
}
});
[].forEach.call(input.attributes, function (attr) {
if (/^data-pristine-/.test(attr.name)) {
var name = attr.name.substr(14);
if (name.endsWith('-message')) {
messages[name.slice(0, name.length - 8)] = attr.value;
return;
}
if (name === 'type') name = attr.value;
_addValidatorToField(fns, params, name, attr.value);
} else if (~ALLOWED_ATTRIBUTES.indexOf(attr.name)) {
_addValidatorToField(fns, params, attr.name, attr.value);
} else if (attr.name === 'type') {
_addValidatorToField(fns, params, attr.value);
}
});
_addValidatorToField(fns, params, input.getAttribute('type'));
fns.sort(function (a, b) {

@@ -120,8 +130,7 @@ return b.priority - a.priority;

self.online && input.addEventListener(!~['radio', 'checkbox'].indexOf(input.getAttribute('type')) ? 'input' : 'change', function (e) {
self.live && input.addEventListener(!~['radio', 'checkbox'].indexOf(input.getAttribute('type')) ? 'input' : 'change', function (e) {
self.validate(e.target);
}.bind(self));
input.pristine = { input: input, validators: fns, params: params };
return input.pristine;
return input.pristine = { input: input, validators: fns, params: params, messages: messages, self: self };
}.bind(self));

@@ -151,3 +160,3 @@ }

valid = false;
!silent && _showError(field, field.messages);
!silent && _showError(field);
}

@@ -158,8 +167,8 @@ }

self.getErrorMessages = function (input) {
return input.length ? input[0].pristine.messages : input.pristine.messages;
self.getErrors = function (input) {
return input.length ? input[0].pristine.errors : input.pristine.errors;
};
function _validateField(field) {
var messages = [];
var errors = [];
var valid = true;

@@ -172,3 +181,4 @@ for (var i in field.validators) {

valid = false;
messages.push(tmpl.apply(validator.msg, params));
var error = field.messages[validator.name] || validator.msg;
errors.push(tmpl.apply(error, params));
if (validator.halt === true) {

@@ -179,3 +189,3 @@ break;

}
field.messages = messages;
field.errors = errors;
return valid;

@@ -188,3 +198,2 @@ }

} else if (elemOrName instanceof HTMLElement) {
//TODO check if pristine field
elemOrName.pristine.validators.push({ fn: fn, msg: msg, priority: priority, halt: halt });

@@ -197,24 +206,61 @@ elemOrName.pristine.validators.sort(function (a, b) {

function _showError(field, messages) {
var ret = _removeError(field);
var errorClassElement = ret[0],
errorTextParent = ret[1];
errorClassElement && errorClassElement.classList.add(self.config.errorClass);
function _getErrorElements(field) {
if (field.errorElements) {
return field.errorElements;
}
var errorClassElement = findAncestor(field.input, self.config.classTo);
var errorTextParent = null,
errorTextElement = null;
if (self.config.classTo === self.config.errorTextParent) {
errorTextParent = errorClassElement;
} else {
errorTextParent = errorClassElement.querySelector(self.errorTextParent);
}
if (errorTextParent) {
errorTextElement = errorTextParent.querySelector('.' + PRISTINE_ERROR);
if (!errorTextElement) {
errorTextElement = document.createElement(self.config.errorTextTag);
errorTextElement.className = PRISTINE_ERROR + ' ' + self.config.errorTextClass;
errorTextParent.appendChild(errorTextElement);
errorTextElement.pristineDisplay = errorTextElement.style.display;
}
}
return field.errorElements = [errorClassElement, errorTextElement];
}
var elem = document.createElement(self.config.errorTextTag);
elem.className = PRISTINE_ERROR + ' ' + self.config.errorTextClass;
elem.innerHTML = messages.join('<br/>');
errorTextParent && errorTextParent.appendChild(elem);
function _showError(field) {
var errorElements = _getErrorElements(field);
var errorClassElement = errorElements[0],
errorTextElement = errorElements[1];
if (errorClassElement) {
errorClassElement.classList.remove(self.config.successClass);
errorClassElement.classList.add(self.config.errorClass);
}
if (errorTextElement) {
errorTextElement.innerHTML = field.errors.join('<br/>');
errorTextElement.style.display = errorTextElement.pristineDisplay || '';
}
}
self.addError = function (input, error) {
input = input.length ? input[0] : input;
input.pristine.errors.push(error);
_showError(input.pristine);
};
function _removeError(field) {
var errorClassElement = findAncestor(field.input, self.config.classTo);
errorClassElement && errorClassElement.classList.remove(self.config.errorClass, self.config.successClass);
var errorTextParent = findAncestor(field.input, self.config.errorTextParent);
var existing = errorTextParent ? errorTextParent.querySelector('.' + PRISTINE_ERROR) : null;
if (existing) {
existing.parentNode.removeChild(existing);
var errorElements = _getErrorElements(field);
var errorClassElement = errorElements[0],
errorTextElement = errorElements[1];
if (errorClassElement) {
// IE > 9 doesn't support multiple class removal
errorClassElement.classList.remove(self.config.errorClass);
errorClassElement.classList.remove(self.config.successClass);
}
return [errorClassElement, errorTextParent];
if (errorTextElement) {
errorTextElement.innerHTML = '';
errorTextElement.style.display = 'none';
}
return errorElements;
}

@@ -228,2 +274,5 @@

self.reset = function () {
for (var i in self.fields) {
self.fields[i].errorElements = null;
}
Array.from(self.form.querySelectorAll('.' + PRISTINE_ERROR)).map(function (elem) {

@@ -233,3 +282,4 @@ elem.parentNode.removeChild(elem);

Array.from(self.form.querySelectorAll('.' + self.config.classTo)).map(function (elem) {
elem.classList.remove(self.config.successClass, self.config.errorClass);
elem.classList.remove(self.config.successClass);
elem.classList.remove(self.config.errorClass);
});

@@ -236,0 +286,0 @@ };

@@ -1,1 +0,1 @@

!function(r,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):r.Pristine=e()}(this,function(){"use strict";function r(r,e){for(;(r=r.parentElement)&&!r.classList.contains(e););return r}function e(r){var e=arguments;return this.replace(/\${([^{}]*)}/g,function(r,t){return e[t]})}function t(t,n,f){function c(e){var t=r(e.input,m.config.classTo);t&&t.classList.remove(m.config.errorClass,m.config.successClass);var n=r(e.input,m.config.errorTextParent),i=n?n.querySelector("."+s):null;return i&&i.parentNode.removeChild(i),[t,n]}function p(r,e,t,n){var i=u[t];if(i&&(r.push(i),n)){var s=n.split(",");s.unshift(null),e[t]=s}}var m=this;return function(r,e,t){m.form=r,m.config=e||i,m.online=!(!1===t),m.fields=Array.from(r.querySelectorAll(a)).map(function(r){var e=[],t={};return o.forEach(function(n){var i=r.getAttribute(n);null!==i&&p(e,t,n,i)}),[].forEach.call(r.attributes,function(r){if(/^data-pristine-/.test(r.name)){var n=r.name.substr(14);"type"===n&&(n=r.value),p(e,t,n,r.value)}}),p(e,t,r.getAttribute("type")),e.sort(function(r,e){return e.priority-r.priority}),m.online&&r.addEventListener(~["radio","checkbox"].indexOf(r.getAttribute("type"))?"change":"input",function(r){m.validate(r.target)}.bind(m)),r.pristine={input:r,validators:e,params:t},r.pristine}.bind(m))}(t,n,f),m.validate=function(r,t){t=r&&!0===t||!0===r;var n=m.fields;!0!==r&&!1!==r&&(r instanceof HTMLElement?n=[r.pristine]:(r instanceof NodeList||r instanceof(window.$||Array)||r instanceof Array)&&(n=Array.from(r).map(function(r){return r.pristine})));var i=!0;for(var a in n){var o=n[a];!function(r){var t=[],n=!0;for(var i in r.validators){var s=r.validators[i],a=r.params[s.name]?r.params[s.name]:[];if(a[0]=r.input.value,!s.fn.apply(r.input,a)&&(n=!1,t.push(e.apply(s.msg,a)),!0===s.halt))break}return r.messages=t,n}(o)?(i=!1,!t&&function(r,e){var t=c(r),n=t[0],i=t[1];n&&n.classList.add(m.config.errorClass);var a=document.createElement(m.config.errorTextTag);a.className=s+" "+m.config.errorTextClass,a.innerHTML=e.join("<br/>"),i&&i.appendChild(a)}(o,o.messages)):!t&&function(r){var e=c(r)[0];e&&e.classList.add(m.config.successClass)}(o)}return i},m.getErrorMessages=function(r){return r.length?r[0].pristine.messages:r.pristine.messages},m.addValidator=function(r,e,t,n,i){"string"==typeof r?l(r,{fn:e,msg:t,priority:n,halt:i}):r instanceof HTMLElement&&(r.pristine.validators.push({fn:e,msg:t,priority:n,halt:i}),r.pristine.validators.sort(function(r,e){return e.priority-r.priority}))},m.reset=function(){Array.from(m.form.querySelectorAll("."+s)).map(function(r){r.parentNode.removeChild(r)}),Array.from(m.form.querySelectorAll("."+m.config.classTo)).map(function(r){r.classList.remove(m.config.successClass,m.config.errorClass)})},m.destroy=function(){m.reset(),m.fields.forEach(function(r){delete r.input.pristine}),m.fields=[]},m.setGlobalConfig=function(r){i=r},m}var n={required:"This field is required",email:"This field requires a valid e-mail address",number:"This field requires a number",url:"This field requires a valid website URL",tel:"This field requires a valid telephone number",maxlength:"This fields length must be < ${1}",minlength:"This fields length must be > ${1}",min:"Minimum value for this field is ${1}",max:"Maximum value for this field is ${1}"},i={classTo:"form-group",errorClass:"has-danger",successClass:"has-success",errorTextParent:"form-group",errorTextTag:"div",errorTextClass:"text-help"},s="pristine-error",a="input:not([type^=hidden]):not([type^=submit]), select, textarea",o=["required","min","max","minlength","maxlength"],u={},l=function(r,e){e.name=r,e.msg||(e.msg=n[r]),void 0===e.priority&&(e.priority=1),u[r]=e};return l("text",{fn:function(r){return!0},priority:0}),l("required",{fn:function(r){return""!==r},priority:99,halt:!0}),l("email",{fn:function(r){return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(r)},priority:1}),l("number",{fn:function(r){return parseFloat(r)},priority:1}),l("minlength",{fn:function(r,e){return console.log(r,e)||r&&r.length>=parseInt(e)},priority:1}),l("maxlength",{fn:function(r,e){return r&&r.length<=parseInt(e)},priority:1}),l("min",{fn:function(r,e){return parseFloat(r)>=parseFloat(e)},priority:1}),l("max",{fn:function(r,e){return parseFloat(r)<=parseFloat(e)},priority:1}),t});
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):e.Pristine=r()}(this,function(){"use strict";function e(e){var r=arguments;return this.replace(/\${([^{}]*)}/g,function(e,t){return r[t]})}function r(e){return e.pristine.self.form.querySelectorAll('input[name="'+e.getAttribute("name")+'"]:checked').length}function t(r,t,n){function f(e){if(e.errorElements)return e.errorElements;var r=function(e,r){for(;(e=e.parentElement)&&!e.classList.contains(r););return e}(e.input,d.config.classTo),t=null,n=null;return(t=d.config.classTo===d.config.errorTextParent?r:r.querySelector(d.errorTextParent))&&((n=t.querySelector("."+s))||((n=document.createElement(d.config.errorTextTag)).className=s+" "+d.config.errorTextClass,t.appendChild(n),n.pristineDisplay=n.style.display)),e.errorElements=[r,n]}function c(e){var r=f(e),t=r[0],n=r[1];t&&(t.classList.remove(d.config.successClass),t.classList.add(d.config.errorClass)),n&&(n.innerHTML=e.errors.join("<br/>"),n.style.display=n.pristineDisplay||"")}function p(e){var r=function(e){var r=f(e),t=r[0],n=r[1];return t&&(t.classList.remove(d.config.errorClass),t.classList.remove(d.config.successClass)),n&&(n.innerHTML="",n.style.display="none"),r}(e)[0];r&&r.classList.add(d.config.successClass)}function m(e,r,t,n){var i=l[t];if(i&&(e.push(i),n)){var s=n.split(",");s.unshift(null),r[t]=s}}var d=this;return function(e,r,t){d.form=e,d.config=r||i,d.live=!(!1===t),d.fields=Array.from(e.querySelectorAll(a)).map(function(e){var r=[],t={},n={};return[].forEach.call(e.attributes,function(e){if(/^data-pristine-/.test(e.name)){var i=e.name.substr(14);if(i.endsWith("-message"))return void(n[i.slice(0,i.length-8)]=e.value);"type"===i&&(i=e.value),m(r,t,i,e.value)}else~o.indexOf(e.name)?m(r,t,e.name,e.value):"type"===e.name&&m(r,t,e.value)}),r.sort(function(e,r){return r.priority-e.priority}),d.live&&e.addEventListener(~["radio","checkbox"].indexOf(e.getAttribute("type"))?"change":"input",function(e){d.validate(e.target)}.bind(d)),e.pristine={input:e,validators:r,params:t,messages:n,self:d}}.bind(d))}(r,t,n),d.validate=function(r,t){t=r&&!0===t||!0===r;var n=d.fields;!0!==r&&!1!==r&&(r instanceof HTMLElement?n=[r.pristine]:(r instanceof NodeList||r instanceof(window.$||Array)||r instanceof Array)&&(n=Array.from(r).map(function(e){return e.pristine})));var i=!0;for(var s in n){var a=n[s];!function(r){var t=[],n=!0;for(var i in r.validators){var s=r.validators[i],a=r.params[s.name]?r.params[s.name]:[];if(a[0]=r.input.value,!s.fn.apply(r.input,a)){n=!1;var o=r.messages[s.name]||s.msg;if(t.push(e.apply(o,a)),!0===s.halt)break}}return r.errors=t,n}(a)?(i=!1,!t&&c(a)):!t&&p(a)}return i},d.getErrors=function(e){return e.length?e[0].pristine.errors:e.pristine.errors},d.addValidator=function(e,r,t,n,i){"string"==typeof e?u(e,{fn:r,msg:t,priority:n,halt:i}):e instanceof HTMLElement&&(e.pristine.validators.push({fn:r,msg:t,priority:n,halt:i}),e.pristine.validators.sort(function(e,r){return r.priority-e.priority}))},d.addError=function(e,r){(e=e.length?e[0]:e).pristine.errors.push(r),c(e.pristine)},d.reset=function(){for(var e in d.fields)d.fields[e].errorElements=null;Array.from(d.form.querySelectorAll("."+s)).map(function(e){e.parentNode.removeChild(e)}),Array.from(d.form.querySelectorAll("."+d.config.classTo)).map(function(e){e.classList.remove(d.config.successClass),e.classList.remove(d.config.errorClass)})},d.destroy=function(){d.reset(),d.fields.forEach(function(e){delete e.input.pristine}),d.fields=[]},d.setGlobalConfig=function(e){i=e},d}var n={required:"This field is required",email:"This field requires a valid e-mail address",number:"This field requires a number",url:"This field requires a valid website URL",tel:"This field requires a valid telephone number",maxlength:"This fields length must be < ${1}",minlength:"This fields length must be > ${1}",min:"Minimum value for this field is ${1}",max:"Maximum value for this field is ${1}",pattern:"Input must match the pattern ${1}"},i={classTo:"form-group",errorClass:"has-danger",successClass:"has-success",errorTextParent:"form-group",errorTextTag:"div",errorTextClass:"text-help"},s="pristine-error",a="input:not([type^=hidden]):not([type^=submit]), select, textarea",o=["required","min","max","minlength","maxlength","pattern"],l={},u=function(e,r){r.name=e,r.msg||(r.msg=n[e]),void 0===r.priority&&(r.priority=1),l[e]=r};return u("text",{fn:function(e){return!0},priority:0}),u("required",{fn:function(e){return"radio"===this.type||"checkbox"===this.type?r(this):void 0!==e&&""!==e},priority:99,halt:!0}),u("email",{fn:function(e){return!e||/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)}}),u("number",{fn:function(e){return!e||!isNaN(parseFloat(e))},priority:2}),u("integer",{fn:function(e){return e&&/^\d+$/.test(e)}}),u("minlength",{fn:function(e,r){return!e||e.length>=parseInt(r)}}),u("maxlength",{fn:function(e,r){return!e||e.length<=parseInt(r)}}),u("min",{fn:function(e,t){return!e||("checkbox"===this.type?r(this)>=parseInt(t):parseFloat(e)>=parseFloat(t))}}),u("max",{fn:function(e,t){return!e||("checkbox"===this.type?r(this)<=parseInt(t):parseFloat(e)<=parseFloat(t))}}),u("pattern",{fn:function(e,r){var t=r.match(new RegExp("^/(.*?)/([gimy]*)$"));return!e||new RegExp(t[1],t[2]).test(e)}}),t});
{
"name": "pristinejs",
"version": "0.1.1",
"version": "0.1.2",
"description": "A tiny vanilla javascript form validation library",

@@ -5,0 +5,0 @@ "main": "dist/pristine.js",

@@ -5,7 +5,4 @@ # Pristine - Vanilla javascript form validation library

## Install
**~4kb minified, ~2kb gzipped, no dependencies**
```sh
$ npm install pristinejs --save
```

@@ -43,4 +40,13 @@ ## Usage

It automatically validates `required, min, max, minlength, maxlength` and type attributes like `email, number` amd more
It automatically validates `required, min, max, minlength, maxlength` attributes and the value of type attributes
like `email, number` and more..
## Install
```sh
$ npm install pristinejs --save
```
`Pristine` takes `3` parameters

@@ -50,3 +56,3 @@

- **config** A object containing the configuration. Default is bootstrap's configuration which is
- **config** An object containing the configuration. Default is bootstrap's configuration which is

@@ -68,3 +74,3 @@ ```javascript

- **online** boolean value indicating whether pristine should validate as you type, default is `true`
- **live** A boolean value indicating whether pristine should validate as you type, default is `true`

@@ -101,3 +107,3 @@

}, "The value must be between {$0} and {$1}", 5, false);
}, "The value (${0}) must be between ${1} and ${2}", 5, false);
```

@@ -109,2 +115,5 @@

<input type="text" class="form-control" data-pristine-my-range="10,30" />
```
```
> The goal of this library is not to provide every possible type of validation and thus becoming a bloat.
> The goal is to provide most common types of validations and a neat way to add custom validators.

@@ -11,2 +11,3 @@ export const lang = {

max: "Maximum value for this field is ${1}",
pattern: "Input must match the pattern ${1}",
};
import { lang } from './lang';
import { tmpl, findAncestor, groupedElemCount } from './utils';

@@ -14,3 +15,3 @@ let defaultConfig = {

const SELECTOR = "input:not([type^=hidden]):not([type^=submit]), select, textarea";
const ALLOWED_ATTRIBUTES = ["required", "min", "max", 'minlength', 'maxlength'];
const ALLOWED_ATTRIBUTES = ["required", "min", "max", 'minlength', 'maxlength', 'pattern'];

@@ -28,31 +29,24 @@ const validators = {};

_('text', {fn: (val) => true, priority: 0});
_('required', {fn: (val) => val !== '', priority: 99, halt: true});
_('email', {fn: (val) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val), priority: 1});
_('number', {fn: (val) => parseFloat(val), priority: 1});
_('minlength', {fn: (val, length) => console.log(val, length) || val && val.length >= parseInt(length), priority: 1});
_('maxlength', {fn: (val, length) => val && val.length <= parseInt(length), priority: 1});
_('min', {fn: (val, limit) => parseFloat(val) >= parseFloat(limit), priority: 1});
_('max', {fn: (val, limit) => parseFloat(val) <= parseFloat(limit), priority: 1});
_('text', { fn: (val) => true, priority: 0});
_('required', { fn: function(val){ return (this.type === 'radio' || this.type === 'checkbox') ? groupedElemCount(this) : val !== undefined && val !== ''}, priority: 99, halt: true});
_('email', { fn: (val) => !val || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val)});
_('number', { fn: (val) => !val || !isNaN(parseFloat(val)), priority: 2 });
_('integer', { fn: (val) => val && /^\d+$/.test(val) });
_('minlength', { fn: (val, length) => !val || val.length >= parseInt(length) });
_('maxlength', { fn: (val, length) => !val || val.length <= parseInt(length) });
_('min', { fn: function(val, limit){ return !val || (this.type === 'checkbox' ? groupedElemCount(this) >= parseInt(limit) : parseFloat(val) >= parseFloat(limit)); } });
_('max', { fn: function(val, limit){ return !val || (this.type === 'checkbox' ? groupedElemCount(this) <= parseInt(limit) : parseFloat(val) <= parseFloat(limit)); } });
_('pattern', { fn: (val, pattern) => { let m = pattern.match(new RegExp('^/(.*?)/([gimy]*)$')); return !val || (new RegExp(m[1], m[2])).test(val);} });
function findAncestor (el, cls) {
while ((el = el.parentElement) && !el.classList.contains(cls));
return el;
}
function tmpl(o) {
return this.replace(/\${([^{}]*)}/g, (a, b) => arguments[b]);
}
export default function Pristine(form, config, online){
export default function Pristine(form, config, live){
let self = this;
init(form, config, online);
init(form, config, live);
function init(form, config, online){
function init(form, config, live){
self.form = form;
self.config = config || defaultConfig;
self.online = !(online === false);
self.live = !(live === false);
self.fields = Array.from(form.querySelectorAll(SELECTOR)).map(function (input) {

@@ -62,30 +56,27 @@

let params = {};
let messages = {};
ALLOWED_ATTRIBUTES.forEach(function (item) {
let val = input.getAttribute(item);
if (val !== null){
_addValidatorToField(fns, params, item, val);
}
});
[].forEach.call(input.attributes, function (attr) {
if (/^data-pristine-/.test(attr.name)) {
let name = attr.name.substr(14);
if (name.endsWith('-message')){
messages[name.slice(0, name.length-8)] = attr.value;
return;
}
if (name === 'type') name = attr.value;
_addValidatorToField(fns, params, name, attr.value);
} else if (~ALLOWED_ATTRIBUTES.indexOf(attr.name)){
_addValidatorToField(fns, params, attr.name, attr.value);
} else if (attr.name === 'type'){
_addValidatorToField(fns, params, attr.value);
}
});
_addValidatorToField(fns, params, input.getAttribute('type'));
fns.sort( (a, b) => b.priority - a.priority);
fns.sort(function (a, b) {
return b.priority - a.priority;
});
self.online && input.addEventListener((!~['radio', 'checkbox'].indexOf(input.getAttribute('type')) ? 'input':'change'), function(e) {
self.live && input.addEventListener((!~['radio', 'checkbox'].indexOf(input.getAttribute('type')) ? 'input':'change'), function(e) {
self.validate(e.target);
}.bind(self));
input.pristine = {input, validators: fns, params};
return input.pristine;
return input.pristine = {input, validators: fns, params, messages, self};

@@ -114,3 +105,3 @@ }.bind(self));

valid = false;
!silent && _showError(field, field.messages);
!silent && _showError(field);
}

@@ -121,8 +112,8 @@ }

self.getErrorMessages = function(input) {
return input.length ? input[0].pristine.messages : input.pristine.messages;
self.getErrors = function(input) {
return input.length ? input[0].pristine.errors : input.pristine.errors;
};
function _validateField(field){
let messages = [];
let errors = [];
let valid = true;

@@ -135,3 +126,4 @@ for(let i in field.validators){

valid = false;
messages.push(tmpl.apply(validator.msg, params));
let error = field.messages[validator.name] || validator.msg;
errors.push(tmpl.apply(error, params));
if (validator.halt === true){

@@ -142,3 +134,3 @@ break;

}
field.messages = messages;
field.errors = errors;
return valid;

@@ -151,32 +143,63 @@ }

} else if (elemOrName instanceof HTMLElement){
//TODO check if pristine field
elemOrName.pristine.validators.push({fn, msg, priority, halt});
elemOrName.pristine.validators.sort(function (a, b) {
return b.priority - a.priority;
});
elemOrName.pristine.validators.sort( (a, b) => b.priority - a.priority);
}
};
function _showError(field, messages){
let ret = _removeError(field);
let errorClassElement = ret[0], errorTextParent = ret[1];
errorClassElement && errorClassElement.classList.add(self.config.errorClass);
function _getErrorElements(field) {
if (field.errorElements){
return field.errorElements;
}
let errorClassElement = findAncestor(field.input, self.config.classTo);
let errorTextParent = null, errorTextElement = null;
if (self.config.classTo === self.config.errorTextParent){
errorTextParent = errorClassElement;
} else {
errorTextParent = errorClassElement.querySelector(self.errorTextParent);
}
if (errorTextParent){
errorTextElement = errorTextParent.querySelector('.' + PRISTINE_ERROR);
if (!errorTextElement){
errorTextElement = document.createElement(self.config.errorTextTag);
errorTextElement.className = PRISTINE_ERROR + ' ' + self.config.errorTextClass;
errorTextParent.appendChild(errorTextElement);
errorTextElement.pristineDisplay = errorTextElement.style.display;
}
}
return field.errorElements = [errorClassElement, errorTextElement]
}
let elem = document.createElement(self.config.errorTextTag);
elem.className = PRISTINE_ERROR + ' ' + self.config.errorTextClass;
elem.innerHTML = messages.join('<br/>');
errorTextParent && errorTextParent.appendChild(elem);
function _showError(field){
let errorElements = _getErrorElements(field);
let errorClassElement = errorElements[0], errorTextElement = errorElements[1];
if(errorClassElement){
errorClassElement.classList.remove(self.config.successClass);
errorClassElement.classList.add(self.config.errorClass);
}
if (errorTextElement){
errorTextElement.innerHTML = field.errors.join('<br/>');
errorTextElement.style.display = errorTextElement.pristineDisplay || '';
}
}
self.addError = function(input, error) {
input = input.length ? input[0] : input;
input.pristine.errors.push(error);
_showError(input.pristine);
};
function _removeError(field){
let errorClassElement = findAncestor(field.input, self.config.classTo);
errorClassElement && errorClassElement.classList.remove(self.config.errorClass, self.config.successClass);
let errorTextParent = findAncestor(field.input, self.config.errorTextParent);
var existing = errorTextParent ? errorTextParent.querySelector('.' + PRISTINE_ERROR) : null;
if (existing){
existing.parentNode.removeChild(existing);
let errorElements = _getErrorElements(field);
let errorClassElement = errorElements[0], errorTextElement = errorElements[1];
if (errorClassElement){
// IE > 9 doesn't support multiple class removal
errorClassElement.classList.remove(self.config.errorClass);
errorClassElement.classList.remove(self.config.successClass);
}
return [errorClassElement, errorTextParent]
if (errorTextElement){
errorTextElement.innerHTML = '';
errorTextElement.style.display = 'none';
}
return errorElements;
}

@@ -190,2 +213,5 @@

self.reset = function () {
for(var i in self.fields){
self.fields[i].errorElements = null;
}
Array.from(self.form.querySelectorAll('.' + PRISTINE_ERROR)).map(function (elem) {

@@ -195,3 +221,4 @@ elem.parentNode.removeChild(elem);

Array.from(self.form.querySelectorAll('.' + self.config.classTo)).map(function (elem) {
elem.classList.remove(self.config.successClass, self.config.errorClass);
elem.classList.remove(self.config.successClass);
elem.classList.remove(self.config.errorClass);
});

@@ -198,0 +225,0 @@