UNPKG

vee-validate

Version:

Simple Vue.js input validation plugin

2,018 lines (1,671 loc) 70.4 kB
/** * vee-validate v2.0.0-rc.21 * (c) 2017 Abdelrahman Awad * @license MIT */ // /** * Gets the data attribute. the name must be kebab-case. */ var getDataAttribute = function (el, name) { return el.getAttribute(("data-vv-" + name)); }; /** * Checks if the value is either null or undefined. */ var isNullOrUndefined = function (value) { return value === null || value === undefined; }; /** * Sets the data attribute. */ var setDataAttribute = function (el, name, value) { return el.setAttribute(("data-vv-" + name), value); }; /** * Creates a proxy object if available in the environment. */ var createProxy = function (target, handler) { if (typeof Proxy === 'undefined') { return target; } return new Proxy(target, handler); }; /** * Creates the default flags object. */ var createFlags = function () { return ({ untouched: true, touched: false, dirty: false, pristine: true, valid: null, invalid: null, validated: false, pending: false, required: false }); }; /** * Shallow object comparison. */ var isEqual = function (lhs, rhs) { if (lhs instanceof RegExp && rhs instanceof RegExp) { return isEqual(lhs.source, rhs.source) && isEqual(lhs.flags, rhs.flags); } if (Array.isArray(lhs) && Array.isArray(rhs)) { if (lhs.length !== rhs.length) { return false; } for (var i = 0; i < lhs.length; i++) { if (!isEqual(lhs[i], rhs[i])) { return false; } } return true; } // if both are objects, compare each key recursively. if (isObject(lhs) && isObject(rhs)) { return Object.keys(lhs).every(function (key) { return isEqual(lhs[key], rhs[key]); }) && Object.keys(rhs).every(function (key) { return isEqual(lhs[key], rhs[key]); }); } return lhs === rhs; }; /** * Determines the input field scope. */ var getScope = function (el) { var scope = getDataAttribute(el, 'scope'); if (isNullOrUndefined(scope) && el.form) { scope = getDataAttribute(el.form, 'scope'); } return !isNullOrUndefined(scope) ? scope : null; }; /** * Gets the value in an object safely. */ var getPath = function (path, target, def) { if ( def === void 0 ) def = undefined; if (!path || !target) { return def; } var value = target; path.split('.').every(function (prop) { if (! Object.prototype.hasOwnProperty.call(value, prop) && value[prop] === undefined) { value = def; return false; } value = value[prop]; return true; }); return value; }; /** * Checks if path exists within an object. */ var hasPath = function (path, target) { var obj = target; return path.split('.').every(function (prop) { if (! Object.prototype.hasOwnProperty.call(obj, prop)) { return false; } obj = obj[prop]; return true; }); }; /** * Parses a rule string expression. */ var parseRule = function (rule) { var params = []; var name = rule.split(':')[0]; if (~rule.indexOf(':')) { params = rule.split(':').slice(1).join(':').split(','); } return { name: name, params: params }; }; /** * Debounces a function. */ var debounce = function (fn, wait, immediate) { if ( wait === void 0 ) wait = 0; if ( immediate === void 0 ) immediate = false; if (wait === 0) { return fn; } var timeout; return function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; var later = function () { timeout = null; if (!immediate) { fn.apply(void 0, args); } }; /* istanbul ignore next */ var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); /* istanbul ignore next */ if (callNow) { fn.apply(void 0, args); } }; }; /** * Normalizes the given rules expression. */ var normalizeRules = function (rules) { // if falsy value return an empty object. if (!rules) { return {}; } if (isObject(rules)) { // $FlowFixMe return Object.keys(rules).reduce(function (prev, curr) { var params = []; // $FlowFixMe if (rules[curr] === true) { params = []; } else if (Array.isArray(rules[curr])) { params = rules[curr]; } else { params = [rules[curr]]; } // $FlowFixMe if (rules[curr] !== false) { prev[curr] = params; } return prev; }, {}); } if (typeof rules !== 'string') { warn('rules must be either a string or an object.'); return {}; } return rules.split('|').reduce(function (prev, rule) { var parsedRule = parseRule(rule); if (!parsedRule.name) { return prev; } prev[parsedRule.name] = parsedRule.params; return prev; }, {}); }; /** * Emits a warning to the console. */ var warn = function (message) { console.warn(("[vee-validate] " + message)); // eslint-disable-line }; /** * Creates a branded error object. */ var createError = function (message) { return new Error(("[vee-validate] " + message)); }; /** * Checks if the value is an object. */ var isObject = function (obj) { return obj !== null && obj && typeof obj === 'object' && ! Array.isArray(obj); }; /** * Checks if a function is callable. */ var isCallable = function (func) { return typeof func === 'function'; }; /** * Check if element has the css class on it. */ var hasClass = function (el, className) { if (el.classList) { return el.classList.contains(className); } return !!el.className.match(new RegExp(("(\\s|^)" + className + "(\\s|$)"))); }; /** * Adds the provided css className to the element. */ var addClass = function (el, className) { if (el.classList) { el.classList.add(className); return; } if (!hasClass(el, className)) { el.className += " " + className; } }; /** * Remove the provided css className from the element. */ var removeClass = function (el, className) { if (el.classList) { el.classList.remove(className); return; } if (hasClass(el, className)) { var reg = new RegExp(("(\\s|^)" + className + "(\\s|$)")); el.className = el.className.replace(reg, ' '); } }; /** * Adds or removes a class name on the input depending on the status flag. */ var toggleClass = function (el, className, status) { if (!el || !className) { return; } if (status) { return addClass(el, className); } removeClass(el, className); }; /** * Converts an array-like object to array, provides a simple polyfill for Array.from */ var toArray = function (arrayLike) { if (isCallable(Array.from)) { return Array.from(arrayLike); } var array = []; var length = arrayLike.length; for (var i = 0; i < length; i++) { array.push(arrayLike[i]); } return array; }; /** * Assign polyfill from the mdn. */ var assign = function (target) { var others = [], len = arguments.length - 1; while ( len-- > 0 ) others[ len ] = arguments[ len + 1 ]; /* istanbul ignore else */ if (isCallable(Object.assign)) { return Object.assign.apply(Object, [ target ].concat( others )); } /* istanbul ignore next */ if (target == null) { throw new TypeError('Cannot convert undefined or null to object'); } /* istanbul ignore next */ var to = Object(target); /* istanbul ignore next */ others.forEach(function (arg) { // Skip over if undefined or null if (arg != null) { Object.keys(arg).forEach(function (key) { to[key] = arg[key]; }); } }); /* istanbul ignore next */ return to; }; /** * Generates a unique id. */ var uniqId = function () { return ("_" + (Math.random().toString(36).substr(2, 9))); }; /** * finds the first element that satisfies the predicate callback, polyfills array.find */ var find = function (arrayLike, predicate) { var array = toArray(arrayLike); if (isCallable(array.find)) { return array.find(predicate); } var result; array.some(function (item) { if (predicate(item)) { result = item; return true; } return false; }); return result; }; /** * Returns a suitable event name for the input element. */ var getInputEventName = function (el) { if (el && (el.tagName === 'SELECT' || ~['radio', 'checkbox', 'file'].indexOf(el.type))) { return 'change'; } return 'input'; }; var isBuiltInComponent = function (vnode) { if (!vnode) { return false; } var tag = vnode.componentOptions.tag; return /keep-alive|transition|transition-group/.test(tag); }; // var ErrorBag = function ErrorBag () { this.items = []; }; /** * Adds an error to the internal array. */ ErrorBag.prototype.add = function add (error) { // handle old signature. if (arguments.length > 1) { error = { field: arguments[0], msg: arguments[1], rule: arguments[2], scope: !isNullOrUndefined(arguments[3]) ? arguments[3] : null }; } error.scope = !isNullOrUndefined(error.scope) ? error.scope : null; this.items.push(error); }; /** * Updates a field error with the new field scope. */ ErrorBag.prototype.update = function update (id, error) { var item = find(this.items, function (i) { return i.id === id; }); if (!item) { return; } var idx = this.items.indexOf(item); this.items.splice(idx, 1); item.scope = error.scope; this.items.push(item); }; /** * Gets all error messages from the internal array. */ ErrorBag.prototype.all = function all (scope) { if (isNullOrUndefined(scope)) { return this.items.map(function (e) { return e.msg; }); } return this.items.filter(function (e) { return e.scope === scope; }).map(function (e) { return e.msg; }); }; /** * Checks if there are any errors in the internal array. */ ErrorBag.prototype.any = function any (scope) { if (isNullOrUndefined(scope)) { return !!this.items.length; } return !!this.items.filter(function (e) { return e.scope === scope; }).length; }; /** * Removes all items from the internal array. */ ErrorBag.prototype.clear = function clear (scope) { var this$1 = this; if (isNullOrUndefined(scope)) { scope = null; } for (var i = 0; i < this.items.length; ++i) { if (this$1.items[i].scope === scope) { this$1.items.splice(i, 1); --i; } } }; /** * Collects errors into groups or for a specific field. */ ErrorBag.prototype.collect = function collect (field, scope, map) { if ( map === void 0 ) map = true; if (!field) { var collection = {}; this.items.forEach(function (e) { if (! collection[e.field]) { collection[e.field] = []; } collection[e.field].push(map ? e.msg : e); }); return collection; } field = !isNullOrUndefined(field) ? String(field) : field; if (isNullOrUndefined(scope)) { return this.items.filter(function (e) { return e.field === field; }).map(function (e) { return (map ? e.msg : e); }); } return this.items.filter(function (e) { return e.field === field && e.scope === scope; }) .map(function (e) { return (map ? e.msg : e); }); }; /** * Gets the internal array length. */ ErrorBag.prototype.count = function count () { return this.items.length; }; /** * Finds and fetches the first error message for the specified field id. */ ErrorBag.prototype.firstById = function firstById (id) { var error = find(this.items, function (i) { return i.id === id; }); return error ? error.msg : null; }; /** * Gets the first error message for a specific field. */ ErrorBag.prototype.first = function first (field, scope) { var this$1 = this; if ( scope === void 0 ) scope = null; field = !isNullOrUndefined(field) ? String(field) : field; var selector = this._selector(field); var scoped = this._scope(field); if (scoped) { var result = this.first(scoped.name, scoped.scope); // if such result exist, return it. otherwise it could be a field. // with dot in its name. if (result) { return result; } } if (selector) { return this.firstByRule(selector.name, selector.rule, scope); } for (var i = 0; i < this.items.length; ++i) { if (this$1.items[i].field === field && (this$1.items[i].scope === scope)) { return this$1.items[i].msg; } } return null; }; /** * Returns the first error rule for the specified field */ ErrorBag.prototype.firstRule = function firstRule (field, scope) { var errors = this.collect(field, scope, false); return (errors.length && errors[0].rule) || null; }; /** * Checks if the internal array has at least one error for the specified field. */ ErrorBag.prototype.has = function has (field, scope) { if ( scope === void 0 ) scope = null; return !!this.first(field, scope); }; /** * Gets the first error message for a specific field and a rule. */ ErrorBag.prototype.firstByRule = function firstByRule (name, rule, scope) { if ( scope === void 0 ) scope = null; var error = this.collect(name, scope, false).filter(function (e) { return e.rule === rule; })[0]; return (error && error.msg) || null; }; /** * Gets the first error message for a specific field that not match the rule. */ ErrorBag.prototype.firstNot = function firstNot (name, rule, scope) { if ( rule === void 0 ) rule = 'required'; if ( scope === void 0 ) scope = null; var error = this.collect(name, scope, false).filter(function (e) { return e.rule !== rule; })[0]; return (error && error.msg) || null; }; /** * Removes errors by matching against the id. */ ErrorBag.prototype.removeById = function removeById (id) { var this$1 = this; for (var i = 0; i < this.items.length; ++i) { if (this$1.items[i].id === id) { this$1.items.splice(i, 1); --i; } } }; /** * Removes all error messages associated with a specific field. */ ErrorBag.prototype.remove = function remove (field, scope, id) { var this$1 = this; field = !isNullOrUndefined(field) ? String(field) : field; var removeCondition = function (e) { if (e.id && id) { return e.id === id; } if (!isNullOrUndefined(scope)) { return e.field === field && e.scope === scope; } return e.field === field && e.scope === null; }; for (var i = 0; i < this.items.length; ++i) { if (removeCondition(this$1.items[i])) { this$1.items.splice(i, 1); --i; } } }; /** * Get the field attributes if there's a rule selector. */ ErrorBag.prototype._selector = function _selector (field) { if (field.indexOf(':') > -1) { var ref = field.split(':'); var name = ref[0]; var rule = ref[1]; return { name: name, rule: rule }; } return null; }; /** * Get the field scope if specified using dot notation. */ ErrorBag.prototype._scope = function _scope (field) { if (field.indexOf('.') > -1) { var ref = field.split('.'); var scope = ref[0]; var name = ref.slice(1); return { name: name.join('.'), scope: scope }; } return null; }; // var Dictionary = function Dictionary (dictionary) { if ( dictionary === void 0 ) dictionary = {}; this.container = {}; this.merge(dictionary); }; Dictionary.prototype.hasLocale = function hasLocale (locale) { return !!this.container[locale]; }; Dictionary.prototype.setDateFormat = function setDateFormat (locale, format) { if (!this.container[locale]) { this.container[locale] = {}; } this.container[locale].dateFormat = format; }; Dictionary.prototype.getDateFormat = function getDateFormat (locale) { if (!this.container[locale]) { return undefined; } return this.container[locale].dateFormat; }; Dictionary.prototype.getMessage = function getMessage (locale, key, fallback) { if (!this.hasMessage(locale, key)) { return fallback || this._getDefaultMessage(locale); } return this.container[locale].messages[key]; }; /** * Gets a specific message for field. falls back to the rule message. */ Dictionary.prototype.getFieldMessage = function getFieldMessage (locale, field, key) { if (!this.hasLocale(locale)) { return this.getMessage(locale, key); } var dict = this.container[locale].custom && this.container[locale].custom[field]; if (!dict || !dict[key]) { return this.getMessage(locale, key); } return dict[key]; }; Dictionary.prototype._getDefaultMessage = function _getDefaultMessage (locale) { if (this.hasMessage(locale, '_default')) { return this.container[locale].messages._default; } return this.container.en.messages._default; }; Dictionary.prototype.getAttribute = function getAttribute (locale, key, fallback) { if ( fallback === void 0 ) fallback = ''; if (!this.hasAttribute(locale, key)) { return fallback; } return this.container[locale].attributes[key]; }; Dictionary.prototype.hasMessage = function hasMessage (locale, key) { return !! ( this.hasLocale(locale) && this.container[locale].messages && this.container[locale].messages[key] ); }; Dictionary.prototype.hasAttribute = function hasAttribute (locale, key) { return !! ( this.hasLocale(locale) && this.container[locale].attributes && this.container[locale].attributes[key] ); }; Dictionary.prototype.merge = function merge (dictionary) { this._merge(this.container, dictionary); }; Dictionary.prototype.setMessage = function setMessage (locale, key, message) { if (! this.hasLocale(locale)) { this.container[locale] = { messages: {}, attributes: {} }; } this.container[locale].messages[key] = message; }; Dictionary.prototype.setAttribute = function setAttribute (locale, key, attribute) { if (! this.hasLocale(locale)) { this.container[locale] = { messages: {}, attributes: {} }; } this.container[locale].attributes[key] = attribute; }; Dictionary.prototype._merge = function _merge (target, source) { var this$1 = this; if (! (isObject(target) && isObject(source))) { return target; } Object.keys(source).forEach(function (key) { if (isObject(source[key])) { if (! target[key]) { assign(target, ( obj = {}, obj[key] = {}, obj )); var obj; } this$1._merge(target[key], source[key]); return; } assign(target, ( obj$1 = {}, obj$1[key] = source[key], obj$1 )); var obj$1; }); return target; }; // var defaultConfig = { locale: 'en', delay: 0, errorBagName: 'errors', dictionary: null, strict: true, fieldsBagName: 'fields', classes: false, classNames: null, events: 'input|blur', inject: true, fastExit: true, aria: true, validity: false }; var currentConfig = assign({}, defaultConfig); var Config = function Config () {}; var staticAccessors$1 = { default: {},current: {} }; staticAccessors$1.default.get = function () { return defaultConfig; }; staticAccessors$1.current.get = function () { return currentConfig; }; /** * Merges the config with a new one. */ Config.merge = function merge (config) { currentConfig = assign({}, currentConfig, config); }; /** * Resolves the working config from a Vue instance. */ Config.resolve = function resolve (context) { var selfConfig = getPath('$options.$_veeValidate', context, {}); return assign({}, Config.current, selfConfig); }; Object.defineProperties( Config, staticAccessors$1 ); /** * Generates the options required to construct a field. */ var Generator = function Generator () {}; Generator.generate = function generate (el, binding, vnode) { var model = Generator.resolveModel(binding, vnode); var options = Config.resolve(vnode.context); return { name: Generator.resolveName(el, vnode), el: el, listen: !binding.modifiers.disable, scope: Generator.resolveScope(el, binding, vnode), vm: Generator.makeVM(vnode.context), expression: binding.value, component: vnode.child, classes: options.classes, classNames: options.classNames, getter: Generator.resolveGetter(el, vnode, model), events: Generator.resolveEvents(el, vnode) || options.events, model: model, delay: Generator.resolveDelay(el, vnode, options), rules: Generator.resolveRules(el, binding), initial: !!binding.modifiers.initial, alias: Generator.resolveAlias(el, vnode), validity: options.validity, aria: options.aria, initialValue: Generator.resolveInitialValue(vnode) }; }; Generator.getCtorConfig = function getCtorConfig (vnode) { if (!vnode.child) { return null; } var config = getPath('child.$options.$_veeValidate', vnode); return config; }; /** * * @param {*} el * @param {*} binding */ Generator.resolveRules = function resolveRules (el, binding) { if (!binding || !binding.expression) { return getDataAttribute(el, 'rules'); } if (typeof binding.value === 'string') { return binding.value; } if (~['string', 'object'].indexOf(typeof binding.value.rules)) { return binding.value.rules; } return binding.value; }; /** * @param {*} vnode */ Generator.resolveInitialValue = function resolveInitialValue (vnode) { var model = vnode.data.model || find(vnode.data.directives, function (d) { return d.name === 'model'; }); return model && model.value; }; /** * Creates a non-circular partial VM instance from a Vue instance. * @param {*} vm */ Generator.makeVM = function makeVM (vm) { return { get $el () { return vm.$el; }, get $refs () { return vm.$refs; }, $watch: vm.$watch ? vm.$watch.bind(vm) : function () {}, $validator: vm.$validator ? { errors: vm.$validator.errors, validate: vm.$validator.validate.bind(vm.$validator), update: vm.$validator.update.bind(vm.$validator) } : null }; }; /** * Resolves the delay value. * @param {*} el * @param {*} vnode * @param {Object} options */ Generator.resolveDelay = function resolveDelay (el, vnode, options) { if ( options === void 0 ) options = {}; return getDataAttribute(el, 'delay') || (vnode.child && vnode.child.$attrs && vnode.child.$attrs['data-vv-delay']) || options.delay; }; /** * Resolves the alias for the field. * @param {*} el * @param {*} vnode * @return {Function} alias getter */ Generator.resolveAlias = function resolveAlias (el, vnode) { return function () { return getDataAttribute(el, 'as') || (vnode.child && vnode.child.$attrs && vnode.child.$attrs['data-vv-as']) || el.title || null; }; }; /** * Resolves the events to validate in response to. * @param {*} el * @param {*} vnode */ Generator.resolveEvents = function resolveEvents (el, vnode) { var events = getDataAttribute(el, 'validate-on'); if (!events && vnode.child && vnode.child.$attrs) { events = vnode.child.$attrs['data-vv-validate-on']; } if (!events && vnode.child) { var config = Generator.getCtorConfig(vnode); events = config && config.events; } return events; }; /** * Resolves the scope for the field. * @param {*} el * @param {*} binding */ Generator.resolveScope = function resolveScope (el, binding, vnode) { if ( vnode === void 0 ) vnode = {}; var scope = null; if (isObject(binding.value)) { scope = binding.value.scope; } if (vnode.child && isNullOrUndefined(scope)) { scope = vnode.child.$attrs && vnode.child.$attrs['data-vv-scope']; } return !isNullOrUndefined(scope) ? scope : getScope(el); }; /** * Checks if the node directives contains a v-model or a specified arg. * Args take priority over models. * * @return {Object} */ Generator.resolveModel = function resolveModel (binding, vnode) { if (binding.arg) { return binding.arg; } if (isObject(binding.value) && binding.value.arg) { return binding.value.arg; } var model = vnode.data.model || find(vnode.data.directives, function (d) { return d.name === 'model'; }); if (!model) { return null; } var watchable = /^[a-z_]+[0-9]*(\w*\.[a-z_]\w*)*$/i.test(model.expression) && hasPath(model.expression, vnode.context); if (!watchable) { return null; } return model.expression; }; /** * Resolves the field name to trigger validations. * @return {String} The field name. */ Generator.resolveName = function resolveName (el, vnode) { var name = getDataAttribute(el, 'name'); if (!name && !vnode.child) { return el.name; } if (!name && vnode.child && vnode.child.$attrs) { name = vnode.child.$attrs['data-vv-name'] || vnode.child.$attrs['name']; } if (!name && vnode.child) { var config = Generator.getCtorConfig(vnode); if (config && isCallable(config.name)) { var boundGetter = config.name.bind(vnode.child); return boundGetter(); } return vnode.child.name; } return name; }; /** * Returns a value getter input type. */ Generator.resolveGetter = function resolveGetter (el, vnode, model) { if (model) { return function () { return getPath(model, vnode.context); }; } if (vnode.child) { var path = getDataAttribute(el, 'value-path') || (vnode.child.$attrs && vnode.child.$attrs['data-vv-value-path']); if (path) { return function () { return getPath(path, vnode.child); }; } var config = Generator.getCtorConfig(vnode); if (config && isCallable(config.value)) { var boundGetter = config.value.bind(vnode.child); return function () { return boundGetter(); }; } return function () { return vnode.child.value; }; } switch (el.type) { case 'checkbox': return function () { var els = document.querySelectorAll(("input[name=\"" + (el.name) + "\"]")); els = toArray(els).filter(function (el) { return el.checked; }); if (!els.length) { return undefined; } return els.map(function (checkbox) { return checkbox.value; }); }; case 'radio': return function () { var els = document.querySelectorAll(("input[name=\"" + (el.name) + "\"]")); var elm = find(els, function (el) { return el.checked; }); return elm && elm.value; }; case 'file': return function (context) { return toArray(el.files); }; case 'select-multiple': return function () { return toArray(el.options).filter(function (opt) { return opt.selected; }).map(function (opt) { return opt.value; }); }; default: return function () { return el && el.value; }; } }; // var DEFAULT_OPTIONS = { targetOf: null, initial: false, scope: null, listen: true, name: null, active: true, required: false, rules: {}, vm: null, classes: false, validity: true, aria: true, events: 'input|blur', delay: 0, classNames: { touched: 'touched', // the control has been blurred untouched: 'untouched', // the control hasn't been blurred valid: 'valid', // model is valid invalid: 'invalid', // model is invalid pristine: 'pristine', // control has not been interacted with dirty: 'dirty' // control has been interacted with } }; var Field = function Field (el, options) { if ( options === void 0 ) options = {}; this.id = uniqId(); this.el = el; this.updated = false; this.dependencies = []; this.watchers = []; this.events = []; this.rules = {}; if (!this.isHeadless && !options.targetOf) { setDataAttribute(this.el, 'id', this.id); // cache field id if it is independent and has a root element. } options = assign({}, DEFAULT_OPTIONS, options); this.validity = options.validity; this.aria = options.aria; this.flags = createFlags(); this.vm = options.vm; this.component = options.component; this.ctorConfig = this.component ? getPath('$options.$_veeValidate', this.component) : undefined; this.update(options); this.updated = false; }; var prototypeAccessors$1 = { isVue: {},validator: {},isRequired: {},isDisabled: {},isHeadless: {},displayName: {},value: {},rejectsFalse: {} }; prototypeAccessors$1.isVue.get = function () { return !!this.component; }; prototypeAccessors$1.validator.get = function () { if (!this.vm || !this.vm.$validator) { warn('No validator instance detected.'); return { validate: function () {} }; } return this.vm.$validator; }; prototypeAccessors$1.isRequired.get = function () { return !!this.rules.required; }; prototypeAccessors$1.isDisabled.get = function () { return !!(this.component && this.component.disabled) || !!(this.el && this.el.disabled); }; prototypeAccessors$1.isHeadless.get = function () { return !this.el; }; /** * Gets the display name (user-friendly name). */ prototypeAccessors$1.displayName.get = function () { return isCallable(this.alias) ? this.alias() : this.alias; }; /** * Gets the input value. */ prototypeAccessors$1.value.get = function () { if (!isCallable(this.getter)) { return undefined; } return this.getter(); }; /** * If the field rejects false as a valid value for the required rule. */ prototypeAccessors$1.rejectsFalse.get = function () { if (this.isVue && this.ctorConfig) { return !!this.ctorConfig.rejectsFalse; } if (this.isHeadless) { return false; } return this.el.type === 'checkbox'; }; /** * Determines if the instance matches the options provided. */ Field.prototype.matches = function matches (options) { if (options.id) { return this.id === options.id; } if (options.name === undefined && options.scope === undefined) { return true; } if (options.scope === undefined) { return this.name === options.name; } if (options.name === undefined) { return this.scope === options.scope; } return options.name === this.name && options.scope === this.scope; }; /** * Updates the field with changed data. */ Field.prototype.update = function update (options) { this.targetOf = options.targetOf || null; this.initial = options.initial || this.initial || false; // update errors scope if the field scope was changed. if (this.updated && !isNullOrUndefined(options.scope) && options.scope !== this.scope && isCallable(this.validator.update)) { this.validator.update(this.id, { scope: options.scope }); } this.scope = !isNullOrUndefined(options.scope) ? options.scope : !isNullOrUndefined(this.scope) ? this.scope : null; this.name = (!isNullOrUndefined(options.name) ? String(options.name) : options.name) || this.name || null; this.rules = options.rules !== undefined ? normalizeRules(options.rules) : this.rules; this.model = options.model || this.model; this.listen = options.listen !== undefined ? options.listen : this.listen; this.classes = options.classes || this.classes || false; this.classNames = options.classNames || this.classNames || DEFAULT_OPTIONS.classNames; this.alias = options.alias || this.alias; this.getter = isCallable(options.getter) ? options.getter : this.getter; this.delay = options.delay || this.delay || 0; this.events = typeof options.events === 'string' && options.events.length ? options.events.split('|') : this.events; this.updateDependencies(); this.addActionListeners(); // update required flag flags if (options.rules !== undefined) { this.flags.required = this.isRequired; } // validate if it was validated before and field was updated and there was a rules mutation. if (this.flags.validated && options.rules !== undefined && this.updated) { this.validator.validate(("#" + (this.id))); } this.updated = true; // no need to continue. if (this.isHeadless) { return; } this.updateClasses(); this.addValueListeners(); this.updateAriaAttrs(); }; /** * Resets field flags and errors. */ Field.prototype.reset = function reset () { var this$1 = this; var def = createFlags(); Object.keys(this.flags).forEach(function (flag) { this$1.flags[flag] = def[flag]; }); this.addActionListeners(); this.updateClasses(); this.updateAriaAttrs(); this.updateCustomValidity(); }; /** * Sets the flags and their negated counterparts, and updates the classes and re-adds action listeners. */ Field.prototype.setFlags = function setFlags (flags) { var this$1 = this; var negated = { pristine: 'dirty', dirty: 'pristine', valid: 'invalid', invalid: 'valid', touched: 'untouched', untouched: 'touched' }; Object.keys(flags).forEach(function (flag) { this$1.flags[flag] = flags[flag]; // if it has a negation and was not specified, set it as well. if (negated[flag] && flags[negated[flag]] === undefined) { this$1.flags[negated[flag]] = !flags[flag]; } }); if ( flags.untouched !== undefined || flags.touched !== undefined || flags.dirty !== undefined || flags.pristine !== undefined ) { this.addActionListeners(); } this.updateClasses(); this.updateAriaAttrs(); this.updateCustomValidity(); }; /** * Determines if the field requires references to target fields. */ Field.prototype.updateDependencies = function updateDependencies () { var this$1 = this; // reset dependencies. this.dependencies.forEach(function (d) { return d.field.destroy(); }); this.dependencies = []; // we get the selectors for each field. var fields = Object.keys(this.rules).reduce(function (prev, r) { if (r === 'confirmed') { prev.push({ selector: this$1.rules[r][0] || ((this$1.name) + "_confirmation"), name: r }); } else if (/after|before/.test(r)) { prev.push({ selector: this$1.rules[r][0], name: r }); } return prev; }, []); if (!fields.length || !this.vm || !this.vm.$el) { return; } // must be contained within the same component, so we use the vm root element constrain our dom search. fields.forEach(function (ref) { var selector = ref.selector; var name = ref.name; var el = null; // vue ref selector. if (selector[0] === '$') { el = this$1.vm.$refs[selector.slice(1)]; } else { try { // try query selector el = this$1.vm.$el.querySelector(selector); } catch (err) { el = null; } } if (!el) { try { el = this$1.vm.$el.querySelector(("input[name=\"" + selector + "\"]")); } catch (err) { el = null; } } if (!el) { return; } var options = { vm: this$1.vm, classes: this$1.classes, classNames: this$1.classNames, delay: this$1.delay, scope: this$1.scope, events: this$1.events.join('|'), initial: this$1.initial, targetOf: this$1.id }; // probably a component. if (isCallable(el.$watch)) { options.component = el; options.el = el.$el; options.alias = Generator.resolveAlias(el.$el, { child: el }); options.getter = Generator.resolveGetter(el.$el, { child: el }); } else { options.el = el; options.alias = Generator.resolveAlias(el, {}); options.getter = Generator.resolveGetter(el, {}); } this$1.dependencies.push({ name: name, field: new Field(options.el, options) }); }); }; /** * Removes listeners. */ Field.prototype.unwatch = function unwatch (tag) { if ( tag === void 0 ) tag = null; if (!tag) { this.watchers.forEach(function (w) { return w.unwatch(); }); this.watchers = []; return; } this.watchers.filter(function (w) { return tag.test(w.tag); }).forEach(function (w) { return w.unwatch(); }); this.watchers = this.watchers.filter(function (w) { return !tag.test(w.tag); }); }; /** * Updates the element classes depending on each field flag status. */ Field.prototype.updateClasses = function updateClasses () { if (!this.classes) { return; } toggleClass(this.el, this.classNames.dirty, this.flags.dirty); toggleClass(this.el, this.classNames.pristine, this.flags.pristine); toggleClass(this.el, this.classNames.valid, !!this.flags.valid); toggleClass(this.el, this.classNames.invalid, !!this.flags.invalid); toggleClass(this.el, this.classNames.touched, this.flags.touched); toggleClass(this.el, this.classNames.untouched, this.flags.untouched); }; /** * Adds the listeners required for automatic classes and some flags. */ Field.prototype.addActionListeners = function addActionListeners () { var this$1 = this; // remove previous listeners. this.unwatch(/class/); var onBlur = function () { this$1.flags.touched = true; this$1.flags.untouched = false; if (this$1.classes) { toggleClass(this$1.el, this$1.classNames.touched, true); toggleClass(this$1.el, this$1.classNames.untouched, false); } // only needed once. this$1.unwatch(/^class_blur$/); }; var inputEvent = getInputEventName(this.el); var onInput = function () { this$1.flags.dirty = true; this$1.flags.pristine = false; if (this$1.classes) { toggleClass(this$1.el, this$1.classNames.pristine, false); toggleClass(this$1.el, this$1.classNames.dirty, true); } // only needed once. this$1.unwatch(/^class_input$/); }; if (this.isVue && isCallable(this.component.$once)) { this.component.$once('input', onInput); this.component.$once('blur', onBlur); this.watchers.push({ tag: 'class_input', unwatch: function () { this$1.component.$off('input', onInput); } }); this.watchers.push({ tag: 'class_blur', unwatch: function () { this$1.component.$off('blur', onBlur); } }); return; } if (this.isHeadless) { return; } this.el.addEventListener(inputEvent, onInput); // Checkboxes and radio buttons on Mac don't emit blur naturally, so we listen on click instead. var blurEvent = ['radio', 'checkbox'].indexOf(this.el.type) === -1 ? 'blur' : 'click'; this.el.addEventListener(blurEvent, onBlur); this.watchers.push({ tag: 'class_input', unwatch: function () { this$1.el.removeEventListener(inputEvent, onInput); } }); this.watchers.push({ tag: 'class_blur', unwatch: function () { this$1.el.removeEventListener(blurEvent, onBlur); } }); }; /** * Adds the listeners required for validation. */ Field.prototype.addValueListeners = function addValueListeners () { var this$1 = this; this.unwatch(/^input_.+/); if (!this.listen) { return; } var fn = this.targetOf ? function () { this$1.validator.validate(("#" + (this$1.targetOf))); } : function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; // if its a DOM event, resolve the value, otherwise use the first parameter as the value. if (args.length === 0 || (isCallable(Event) && args[0] instanceof Event) || (args[0] && args[0].srcElement)) { args[0] = this$1.value; } this$1.validator.validate(("#" + (this$1.id)), args[0]); }; var validate = debounce(fn, this.delay); var inputEvent = getInputEventName(this.el); // replace input event with suitable one. var events = this.events.map(function (e) { return e === 'input' ? inputEvent : e; }); // if there is a watchable model and an on input validation is requested. if (this.model && events.indexOf(inputEvent) !== -1) { var unwatch = this.vm.$watch(this.model, validate); this.watchers.push({ tag: 'input_model', unwatch: unwatch }); // filter out input event as it is already handled by the watcher API. events = events.filter(function (e) { return e !== inputEvent; }); } // Add events. events.forEach(function (e) { if (this$1.isVue) { this$1.component.$on(e, validate); this$1.watchers.push({ tag: 'input_vue', unwatch: function () { this$1.component.$off(e, validate); } }); return; } if (~['radio', 'checkbox'].indexOf(this$1.el.type)) { var els = document.querySelectorAll(("input[name=\"" + (this$1.el.name) + "\"]")); toArray(els).forEach(function (el) { el.addEventListener(e, validate); this$1.watchers.push({ tag: 'input_native', unwatch: function () { el.removeEventListener(e, validate); } }); }); return; } this$1.el.addEventListener(e, validate); this$1.watchers.push({ tag: 'input_native', unwatch: function () { this$1.el.removeEventListener(e, validate); } }); }); }; /** * Updates aria attributes on the element. */ Field.prototype.updateAriaAttrs = function updateAriaAttrs () { if (!this.aria || this.isHeadless || !isCallable(this.el.setAttribute)) { return; } this.el.setAttribute('aria-required', this.isRequired ? 'true' : 'false'); this.el.setAttribute('aria-invalid', this.flags.invalid ? 'true' : 'false'); }; /** * Updates the custom validity for the field. */ Field.prototype.updateCustomValidity = function updateCustomValidity () { if (!this.validity || this.isHeadless || !isCallable(this.el.setCustomValidity)) { return; } this.el.setCustomValidity(this.flags.valid ? '' : (this.validator.errors.firstById(this.id) || '')); }; /** * Removes all listeners. */ Field.prototype.destroy = function destroy () { this.watchers.forEach(function (w) { return w.unwatch(); }); this.watchers = []; this.dependencies.forEach(function (d) { return d.field.destroy(); }); this.dependencies = []; }; Object.defineProperties( Field.prototype, prototypeAccessors$1 ); // var FieldBag = function FieldBag () { this.items = []; }; var prototypeAccessors$2 = { length: {} }; /** * Gets the current items length. */ prototypeAccessors$2.length.get = function () { return this.items.length; }; /** * Finds the first field that matches the provided matcher object. */ FieldBag.prototype.find = function find$1 (matcher) { return find(this.items, function (item) { return item.matches(matcher); }); }; /** * Filters the items down to the matched fields. */ FieldBag.prototype.filter = function filter (matcher) { // multiple matchers to be tried. if (Array.isArray(matcher)) { return this.items.filter(function (item) { return matcher.some(function (m) { return item.matches(m); }); }); } return this.items.filter(function (item) { return item.matches(matcher); }); }; /** * Maps the field items using the mapping function. */ FieldBag.prototype.map = function map (mapper) { return this.items.map(mapper); }; /** * Finds and removes the first field that matches the provided matcher object, returns the removed item. */ FieldBag.prototype.remove = function remove (matcher) { var item = null; if (matcher instanceof Field) { item = matcher; } else { item = this.find(matcher); } if (!item) { return null; } var index = this.items.indexOf(item); this.items.splice(index, 1); return item; }; /** * Adds a field item to the list. */ FieldBag.prototype.push = function push (item) { if (! (item instanceof Field)) { throw createError('FieldBag only accepts instances of Field that has an id defined.'); } if (!item.id) { throw createError('Field id must be defined.'); } if (this.find({ id: item.id })) { throw createError(("Field with id " + (item.id) + " is already added.")); } this.items.push(item); }; Object.defineProperties( FieldBag.prototype, prototypeAccessors$2 ); // var RULES = {}; var LOCALE = 'en'; var STRICT_MODE = true; var DICTIONARY = new Dictionary({ en: { messages: {}, attributes: {}, custom: {} } }); var Validator = function Validator (validations, options) { var this$1 = this; if ( options === void 0 ) options = { vm: null, fastExit: true }; this.strict = STRICT_MODE; this.errors = new ErrorBag(); this.fields = new FieldBag(); this.flags = {}; this._createFields(validations); this.paused = false; this.fastExit = options.fastExit || false; this.ownerId = options.vm && options.vm._uid; // create it statically since we don't need constant access to the vm. this.reset = options.vm && isCallable(options.vm.$nextTick) ? function () { return new Promise(function (resolve, reject) { options.vm.$nextTick(function () { this$1.fields.items.forEach(function (i) { return i.reset(); }); this$1.errors.clear(); resolve(); }); }); } : function () { return new Promise(function (resolve, reject) { this$1.fields.items.forEach(function (i) { return i.reset(); }); this$1.errors.clear(); resolve(); }); }; /* istanbul ignore next */ this.clean = function () { warn('validator.clean is marked for deprecation, please use validator.reset instead.'); this$1.reset(); }; }; var prototypeAccessors = { dictionary: {},locale: {},rules: {} }; var staticAccessors = { dictionary: {},locale: {},rules: {} }; /** * Getter for the dictionary. */ prototypeAccessors.dictionary.get = function () { return DICTIONARY; }; /** * Static Getter for the dictionary. */ staticAccessors.dictionary.get = function () { return DICTIONARY; }; /** * Getter for the current locale. */ prototypeAccessors.locale.get = function () { return LOCALE; }; /** * Setter for the validator locale. */ prototypeAccessors.locale.set = function (value) { Validator.locale = value; }; /** * Static getter for the validator locale. */ staticAccessors.locale.get = function () { return LOCALE; }; /** * Static setter for the validator locale. */ staticAccessors.locale.set = function (value) { /* istanbul ignore if */ if (!DICTIONARY.hasLocale(value)) { // eslint-disable-next-line warn('You are setting the validator locale to a locale that is not defined in the dictionary. English messages may still be generated.'); } LOCALE = value; }; /** * Getter for the rules object. */ prototypeAccessors.rules.get = function () { return RULES; }; /** * Static Getter for the rules object. */ staticAccessors.rules.get = function () { return RULES; }; /** * Static constructor. */ Validator.create = function create (validations, options) { return new Validator(validations, options); }; /** * Adds a custom validator to the list of validation rules. */ Validator.extend = function extend (name, validator) { Validator._guardExtend(name, validator); Validator._merge(name, validator); }; /** * Removes a rule from the list of validators. */ Validator.remove = function remove (name) { delete RULES[name]; }; /** * Sets the default locale for all validators. * @deprecated */ Validator.setLocale = function setLocale (language) { if ( language === void 0 ) language = 'en'; Validator.locale = language; }; /** * @deprecated */ Validator.installDateTimeValidators = function installDateTimeValidators () { /* istanbul ignore next */ warn('Date validations are now installed by default, you no longer need to install it.'); }; /** * @deprecated */ Validator.prototype.installDateTimeValidators = function installDateTimeValidators () { /* istanbul ignore next */ warn('Date validations are now installed by default, you no longer need to install it.'); }; /** * Sets the operating mode for all newly created validators. * strictMode = true: Values without a rule are invalid and cause failure. * strictMode = false: Values without a rule are valid and are skipped. */ Validator.setStrictMode = function setStrictMode (strictMode) { if ( strictMode === void 0 ) strictMode = true; STRICT_MODE = strictMode; }; /** * Updates the dictionary, overwriting existing values and adding new ones. * @deprecated */ Validator.updateDictionary = function updateDictionary (data) { DICTIONARY.merge(data); }; /** * Adds a locale object to the dictionary. * @deprecated */ Validator.addLocale = function addLocale (locale) { if (! locale.name) { warn('Your locale must have a name property'); return; } this.updateDictionary(( obj = {}, obj[locale.name] = locale, obj )); var obj; }; /** * Adds a locale object to the dictionary. * @deprecated * @param {Object} locale */ Validator.prototype.addLocale = function addLocale (locale) { Validator.addLocale(locale); }; /** * Adds and sets the current locale for the validator. */ Validator.prototype.localize = function localize (lang, dictionary) { Validator.localize(lang, dictionary); }; /** * Adds and sets the current locale for the validator. */ Validator.localize = function localize (lang, dictionary) { // merge the dictionary. if (dictionary) { dictionary = assign({}, dictionary, { name: lang }); Validator.addLocale(dictionary); } // set the locale. Validator.locale = lang; }; /** * Registers a field to be validated. */ Validator.prototype.attach = function attach (field) { // deprecate: handle old signature. if (arguments.length > 1) { field = assign({}, { name: arguments[0], rules: arguments[1] }, arguments[2] || { vm: { $validator: this } }); } // fixes initial value detection with v-model and select elements. var value = field.initialValue; if (!(field instanceof Field)) { field = new Field(field.el || null, field); } this.fields.push(field); // validate the field initially if (field.initial) { this.validate(("#" + (field.id)), value || field.value); } else { this._validate(field, value || field.value, true).then(function (valid) { field.flags.valid = valid; field.flags.invalid = !valid; }); } this._addFlag(field, field.scope); return field; }; /** * Sets the flags on a field. */ Validator.prototype.flag = function flag (name, flags) { var field = this._resolveField(name); if (! field || !flags) { return; } field.setFlags(flags); }; /** * Removes a field from the validator. */ Validator.prototype.detach = function detach (name, scope) { var field = name instanceof Field ? name : this._resolveField(name, scope); if (!field) { return; } field.destroy(); this.errors.remove(field.name, field.scope, field.id); this.fields.remove(field); var flags = this.flags; if (!isNullOrUndefined(field.scope) && flags[("$" + (field.scope))]) { delete flags[("$" + (field.scope))