UNPKG

@precision-nutrition/vee-validate

Version:

Simple Vue.js input validation plugin

1,917 lines (1,541 loc) 125 kB
/** * vee-validate v2.1.8 * (c) 2018 Abdelrahman Awad * @license MIT */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.VeeValidate = factory()); }(this, (function () { 'use strict'; // var isTextInput = function (el) { return includes(['text', 'password', 'search', 'email', 'tel', 'url', 'textarea', 'number'], el.type); }; var isCheckboxOrRadioInput = function (el) { return includes(['radio', 'checkbox'], el.type); }; var isDateInput = function (el) { return includes(['date', 'week', 'month', 'datetime-local', 'time'], el.type); }; /** * Gets the data attribute. the name must be kebab-case. */ var getDataAttribute = function (el, name) { return el.getAttribute(("data-vv-" + name)); }; /** * Checks if the values are either null or undefined. */ var isNullOrUndefined = function () { var values = [], len = arguments.length; while ( len-- ) values[ len ] = arguments[ len ]; return values.every(function (value) { return value === null || value === undefined; }); }; /** * 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, changed: 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)) { var form = getForm(el); if (form) { scope = getDataAttribute(form, 'scope'); } } return !isNullOrUndefined(scope) ? scope : null; }; /** * Get the closest form element. */ var getForm = function (el) { if (isNullOrUndefined(el)) { return null; } if (el.tagName === 'FORM') { return el; } if (!isNullOrUndefined(el.form)) { return el.form; } return !isNullOrUndefined(el.parentNode) ? getForm(el.parentNode) : 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 (prop in value) { value = value[prop]; return true; } value = def; return false; }); return value; }; /** * Checks if path exists within an object. */ var hasPath = function (path, target) { var obj = target; return path.split('.').every(function (prop) { if (prop in obj) { obj = obj[prop]; return true; } return false; }); }; /** * Parses a rule string expression. */ var parseRule = function (rule) { var params = []; var name = rule.split(':')[0]; if (includes(rule, ':')) { params = rule.split(':').slice(1).join(':').split(','); } return { name: name, params: params }; }; /** * Debounces a function. */ var debounce = function (fn, wait, token) { if ( wait === void 0 ) wait = 0; if ( token === void 0 ) token = { cancelled: 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; // check if the fn call was cancelled. if (!token.cancelled) { fn.apply(void 0, args); } }; clearTimeout(timeout); timeout = setTimeout(later, wait); if (!timeout) { fn.apply(void 0, args); } }; }; /** * Appends a rule definition to a list of rules. */ var appendRule = function (rule, rules) { if (!rules) { return normalizeRules(rule); } if (!rule) { return normalizeRules(rules); } if (typeof rules === 'string') { rules = normalizeRules(rules); } return assign({}, rules, normalizeRules(rule)); }; /** * 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 if (isObject(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 (Array.isArray(className)) { className.forEach(function (item) { return toggleClass(el, item, status); }); 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; /* istanbul ignore next */ for (var i = 0; i < length; i++) { array.push(arrayLike[i]); } /* istanbul ignore next */ 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; }; var id = 0; var idTemplate = '{id}'; /** * Generates a unique id. */ var uniqId = function () { // handle too many uses of uniqId, although unlikely. if (id >= 9999) { id = 0; // shift the template. idTemplate = idTemplate.replace('{id}', '_{id}'); } id++; var newId = idTemplate.replace('{id}', String(id)); return newId; }; /** * finds the first element that satisfies the predicate callback, polyfills array.find */ var find = function (arrayLike, predicate) { var array = Array.isArray(arrayLike) ? arrayLike : toArray(arrayLike); for (var i = 0; i < array.length; i++) { if (predicate(array[i])) { return array[i]; } } return undefined; }; var isBuiltInComponent = function (vnode) { if (!vnode) { return false; } var tag = vnode.componentOptions.tag; return /^(keep-alive|transition|transition-group)$/.test(tag); }; var makeDelayObject = function (events, delay, delayConfig) { if (typeof delay === 'number') { return events.reduce(function (prev, e) { prev[e] = delay; return prev; }, {}); } return events.reduce(function (prev, e) { if (typeof delay === 'object' && e in delay) { prev[e] = delay[e]; return prev; } if (typeof delayConfig === 'number') { prev[e] = delayConfig; return prev; } prev[e] = (delayConfig && delayConfig[e]) || 0; return prev; }, {}); }; var deepParseInt = function (input) { if (typeof input === 'number') { return input; } if (typeof input === 'string') { return parseInt(input); } var map = {}; for (var element in input) { map[element] = parseInt(input[element]); } return map; }; var merge = function (target, source) { if (! (isObject(target) && isObject(source))) { return target; } Object.keys(source).forEach(function (key) { var obj, obj$1; if (isObject(source[key])) { if (! target[key]) { assign(target, ( obj = {}, obj[key] = {}, obj )); } merge(target[key], source[key]); return; } assign(target, ( obj$1 = {}, obj$1[key] = source[key], obj$1 )); }); return target; }; var fillRulesFromElement = function (el, rules) { if (el.required) { rules = appendRule('required', rules); } if (isTextInput(el)) { if (el.type === 'email') { rules = appendRule(("email" + (el.multiple ? ':multiple' : '')), rules); } if (el.pattern) { rules = appendRule({ regex: el.pattern }, rules); } // 524288 is the max on some browsers and test environments. if (el.maxLength >= 0 && el.maxLength < 524288) { rules = appendRule(("max:" + (el.maxLength)), rules); } if (el.minLength > 0) { rules = appendRule(("min:" + (el.minLength)), rules); } if (el.type === 'number') { rules = appendRule('decimal', rules); if (el.min !== '') { rules = appendRule(("min_value:" + (el.min)), rules); } if (el.max !== '') { rules = appendRule(("max_value:" + (el.max)), rules); } } return rules; } if (isDateInput(el)) { var timeFormat = el.step && Number(el.step) < 60 ? 'HH:mm:ss' : 'HH:mm'; if (el.type === 'date') { return appendRule('date_format:YYYY-MM-DD', rules); } if (el.type === 'datetime-local') { return appendRule(("date_format:YYYY-MM-DDT" + timeFormat), rules); } if (el.type === 'month') { return appendRule('date_format:YYYY-MM', rules); } if (el.type === 'week') { return appendRule('date_format:YYYY-[W]WW', rules); } if (el.type === 'time') { return appendRule(("date_format:" + timeFormat), rules); } } return rules; }; var values = function (obj) { if (isCallable(Object.values)) { return Object.values(obj); } // fallback to keys() /* istanbul ignore next */ return Object.keys(obj).map(function (k) { return obj[k]; }); }; var parseSelector = function (selector) { var rule = null; if (includes(selector, ':')) { rule = selector.split(':').pop(); selector = selector.replace((":" + rule), ''); } if (selector[0] === '#') { return { id: selector.slice(1), rule: rule, name: null, scope: null }; } var scope = null; var name = selector; if (includes(selector, '.')) { var parts = selector.split('.'); scope = parts[0]; name = parts.slice(1).join('.'); } return { id: null, scope: scope, name: name, rule: rule }; }; var includes = function (collection, item) { return collection.indexOf(item) !== -1; }; var isEmptyArray = function (arr) { return Array.isArray(arr) && arr.length === 0; }; // var LOCALE = 'en'; var Dictionary = function Dictionary (dictionary) { if ( dictionary === void 0 ) dictionary = {}; this.container = {}; this.merge(dictionary); }; var prototypeAccessors = { locale: { configurable: true } }; prototypeAccessors.locale.get = function () { return LOCALE; }; prototypeAccessors.locale.set = function (value) { LOCALE = value || 'en'; }; 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] || !this.container[locale].dateFormat) { return null; } return this.container[locale].dateFormat; }; Dictionary.prototype.getMessage = function getMessage (locale, key, data) { var message = null; if (!this.hasMessage(locale, key)) { message = this._getDefaultMessage(locale); } else { message = this.container[locale].messages[key]; } return isCallable(message) ? message.apply(void 0, data) : message; }; /** * Gets a specific message for field. falls back to the rule message. */ Dictionary.prototype.getFieldMessage = function getFieldMessage (locale, field, key, data) { if (!this.hasLocale(locale)) { return this.getMessage(locale, key, data); } var dict = this.container[locale].custom && this.container[locale].custom[field]; if (!dict || !dict[key]) { return this.getMessage(locale, key, data); } var message = dict[key]; return isCallable(message) ? message.apply(void 0, data) : message; }; 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$1 (dictionary) { 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; }; Object.defineProperties( Dictionary.prototype, prototypeAccessors ); var drivers = { default: new Dictionary({ en: { messages: {}, attributes: {}, custom: {} } }) }; var currentDriver = 'default'; var DictionaryResolver = function DictionaryResolver () {}; DictionaryResolver._checkDriverName = function _checkDriverName (driver) { if (!driver) { throw createError('you must provide a name to the dictionary driver'); } }; DictionaryResolver.setDriver = function setDriver (driver, implementation) { if ( implementation === void 0 ) implementation = null; this._checkDriverName(driver); if (implementation) { drivers[driver] = implementation; } currentDriver = driver; }; DictionaryResolver.getDriver = function getDriver () { return drivers[currentDriver]; }; // var ErrorBag = function ErrorBag (errorBag, id) { if ( errorBag === void 0 ) errorBag = null; if ( id === void 0 ) id = null; this.vmId = id || null; // make this bag a mirror of the provided one, sharing the same items reference. if (errorBag && errorBag instanceof ErrorBag) { this.items = errorBag.items; } else { this.items = []; } }; ErrorBag.prototype[typeof Symbol === 'function' ? Symbol.iterator : '@@iterator'] = function () { var this$1 = this; var index = 0; return { next: function () { return { value: this$1.items[index++], done: index > this$1.items.length }; } }; }; /** * Adds an error to the internal array. */ ErrorBag.prototype.add = function add (error) { var ref; (ref = this.items).push.apply( ref, this._normalizeError(error) ); }; /** * Normalizes passed errors to an error array. */ ErrorBag.prototype._normalizeError = function _normalizeError (error) { var this$1 = this; if (Array.isArray(error)) { return error.map(function (e) { e.scope = !isNullOrUndefined(e.scope) ? e.scope : null; e.vmId = !isNullOrUndefined(e.vmId) ? e.vmId : (this$1.vmId || null); return e; }); } error.scope = !isNullOrUndefined(error.scope) ? error.scope : null; error.vmId = !isNullOrUndefined(error.vmId) ? error.vmId : (this.vmId || null); return [error]; }; /** * Regenrates error messages if they have a generator function. */ ErrorBag.prototype.regenerate = function regenerate () { this.items.forEach(function (i) { i.msg = isCallable(i.regenerate) ? i.regenerate() : i.msg; }); }; /** * 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) { var this$1 = this; var filterFn = function (item) { var matchesScope = true; var matchesVM = true; if (!isNullOrUndefined(scope)) { matchesScope = item.scope === scope; } if (!isNullOrUndefined(this$1.vmId)) { matchesVM = item.vmId === this$1.vmId; } return matchesVM && matchesScope; }; return this.items.filter(filterFn).map(function (e) { return e.msg; }); }; /** * Checks if there are any errors in the internal array. */ ErrorBag.prototype.any = function any (scope) { var this$1 = this; var filterFn = function (item) { var matchesScope = true; var matchesVM = true; if (!isNullOrUndefined(scope)) { matchesScope = item.scope === scope; } if (!isNullOrUndefined(this$1.vmId)) { matchesVM = item.vmId === this$1.vmId; } return matchesVM && matchesScope; }; return !!this.items.filter(filterFn).length; }; /** * Removes all items from the internal array. */ ErrorBag.prototype.clear = function clear (scope) { var this$1 = this; var matchesVM = isNullOrUndefined(this.vmId) ? function () { return true; } : function (i) { return i.vmId === this$1.vmId; }; if (isNullOrUndefined(scope)) { scope = null; } for (var i = 0; i < this.items.length; ++i) { if (matchesVM(this.items[i]) && this.items[i].scope === scope) { this.items.splice(i, 1); --i; } } }; /** * Collects errors into groups or for a specific field. */ ErrorBag.prototype.collect = function collect (field, scope, map) { var this$1 = this; if ( map === void 0 ) map = true; var isSingleField = !isNullOrUndefined(field) && !field.includes('*'); var groupErrors = function (items) { var errors = items.reduce(function (collection, error) { if (!isNullOrUndefined(this$1.vmId) && error.vmId !== this$1.vmId) { return collection; } if (!collection[error.field]) { collection[error.field] = []; } collection[error.field].push(map ? error.msg : error); return collection; }, {}); // reduce the collection to be a single array. if (isSingleField) { return values(errors)[0] || []; } return errors; }; if (isNullOrUndefined(field)) { return groupErrors(this.items); } var selector = isNullOrUndefined(scope) ? String(field) : (scope + "." + field); var ref = this._makeCandidateFilters(selector); var isPrimary = ref.isPrimary; var isAlt = ref.isAlt; var collected = this.items.reduce(function (prev, curr) { if (isPrimary(curr)) { prev.primary.push(curr); } if (isAlt(curr)) { prev.alt.push(curr); } return prev; }, { primary: [], alt: [] }); collected = collected.primary.length ? collected.primary : collected.alt; return groupErrors(collected); }; /** * Gets the internal array length. */ ErrorBag.prototype.count = function count () { var this$1 = this; if (this.vmId) { return this.items.filter(function (e) { return e.vmId === this$1.vmId; }).length; } 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 : undefined; }; /** * Gets the first error message for a specific field. */ ErrorBag.prototype.first = function first (field, scope) { if ( scope === void 0 ) scope = null; var selector = isNullOrUndefined(scope) ? field : (scope + "." + field); var match = this._match(selector); return match && match.msg; }; /** * 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) || undefined; }; /** * 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) || undefined; }; /** * 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) || undefined; }; /** * Removes errors by matching against the id or ids. */ ErrorBag.prototype.removeById = function removeById (id) { var condition = function (item) { return item.id === id; }; if (Array.isArray(id)) { condition = function (item) { return id.indexOf(item.id) !== -1; }; } for (var i = 0; i < this.items.length; ++i) { if (condition(this.items[i])) { this.items.splice(i, 1); --i; } } }; /** * Removes all error messages associated with a specific field. */ ErrorBag.prototype.remove = function remove (field, scope, vmId) { if (isNullOrUndefined(field)) { return; } var selector = isNullOrUndefined(scope) ? String(field) : (scope + "." + field); var ref = this._makeCandidateFilters(selector); var isPrimary = ref.isPrimary; var shouldRemove = function (item) { if (isNullOrUndefined(vmId)) { return isPrimary(item); } return isPrimary(item) && item.vmId === vmId; }; for (var i = 0; i < this.items.length; ++i) { if (shouldRemove(this.items[i])) { this.items.splice(i, 1); --i; } } }; ErrorBag.prototype._makeCandidateFilters = function _makeCandidateFilters (selector) { var this$1 = this; var matchesRule = function () { return true; }; var matchesScope = function () { return true; }; var matchesName = function () { return true; }; var matchesVM = function () { return true; }; var ref = parseSelector(selector); var id = ref.id; var rule = ref.rule; var scope = ref.scope; var name = ref.name; if (rule) { matchesRule = function (item) { return item.rule === rule; }; } // match by id, can be combined with rule selection. if (id) { return { isPrimary: function (item) { return matchesRule(item) && (function (item) { return id === item.id; }); }, isAlt: function () { return false; } }; } if (isNullOrUndefined(scope)) { // if no scope specified, make sure the found error has no scope. matchesScope = function (item) { return isNullOrUndefined(item.scope); }; } else { matchesScope = function (item) { return item.scope === scope; }; } if (!isNullOrUndefined(name) && name !== '*') { matchesName = function (item) { return item.field === name; }; } if (!isNullOrUndefined(this.vmId)) { matchesVM = function (item) { return item.vmId === this$1.vmId; }; } // matches the first candidate. var isPrimary = function (item) { return matchesVM(item) && matchesName(item) && matchesRule(item) && matchesScope(item); }; // matches a second candidate, which is a field with a name containing the '.' character. var isAlt = function (item) { return matchesVM(item) && matchesRule(item) && item.field === (scope + "." + name); }; return { isPrimary: isPrimary, isAlt: isAlt }; }; ErrorBag.prototype._match = function _match (selector) { if (isNullOrUndefined(selector)) { return undefined; } var ref = this._makeCandidateFilters(selector); var isPrimary = ref.isPrimary; var isAlt = ref.isAlt; return this.items.reduce(function (prev, item, idx, arr) { var isLast = idx === arr.length - 1; if (prev.primary) { return isLast ? prev.primary : prev; } if (isPrimary(item)) { prev.primary = item; } if (isAlt(item)) { prev.alt = item; } // keep going. if (!isLast) { return prev; } return prev.primary || prev.alt; }, {}); }; // VNode Utils // Gets the model object on the vnode. function findModel (vnode) { if (!vnode.data) { return null; } // Component Model if (vnode.data.model) { return vnode.data.model; } return !!(vnode.data.directives) && find(vnode.data.directives, function (d) { return d.name === 'model'; }); } function extractVNodes (vnode) { if (findModel(vnode)) { return [vnode]; } var children = Array.isArray(vnode) ? vnode : vnode.children; if (!Array.isArray(children)) { return []; } return children.reduce(function (nodes, node) { var candidates = extractVNodes(node); if (candidates.length) { nodes.push.apply(nodes, candidates); } return nodes; }, []); } // Resolves v-model config if exists. function findModelConfig (vnode) { if (!vnode.componentOptions) { return null; } return vnode.componentOptions.Ctor.options.model; } // Adds a listener to vnode listener object. function mergeVNodeListeners (obj, eventName, handler) { // Has a single listener. if (isCallable(obj[eventName])) { var prevHandler = obj[eventName]; obj[eventName] = [prevHandler]; } // has other listeners. if (Array.isArray(obj[eventName])) { obj[eventName].push(handler); return; } // no listener at all. if (isNullOrUndefined(obj[eventName])) { obj[eventName] = [handler]; } } // Adds a listener to a native HTML vnode. function addNativeNodeListener (node, eventName, handler) { if (isNullOrUndefined(node.data.on)) { node.data.on = {}; } mergeVNodeListeners(node.data.on, eventName, handler); } // Adds a listener to a Vue component vnode. function addComponentNodeListener (node, eventName, handler) { /* istanbul ignore next */ if (!node.componentOptions.listeners) { node.componentOptions.listeners = {}; } mergeVNodeListeners(node.componentOptions.listeners, eventName, handler); } function addVNodeListener (vnode, eventName, handler) { if (vnode.componentOptions) { addComponentNodeListener(vnode, eventName, handler); } addNativeNodeListener(vnode, eventName, handler); } // Determines if `change` should be used over `input` for listeners. function getInputEventName (vnode, model) { // Is a component. if (vnode.componentOptions) { var ref = findModelConfig(vnode) || { event: 'input' }; var event = ref.event; return event; } // Lazy Models typically use change event if (model && model.modifiers && model.modifiers.lazy) { return 'change'; } // is a textual-type input. if (vnode.data.attrs && isTextInput({ type: vnode.data.attrs.type || 'text' })) { return 'input'; } return 'change'; } function normalizeSlots (slots, ctx) { return Object.keys(slots).reduce(function (arr, key) { slots[key].forEach(function (vnode) { if (!vnode.context) { slots[key].context = ctx; if (!vnode.data) { vnode.data = {}; } vnode.data.slot = key; } }); return arr.concat(slots[key]); }, []); } function createRenderless (h, vnode) { // a single-root slot yay! if (!Array.isArray(vnode)) { return vnode; } if (vnode.length === 1) { return vnode[0]; } { warn('Your slot should have one root element. Rendering a span as the root.'); } // Renders a multi-root node, should throw a Vue error. return vnode; } /** * Generates the options required to construct a field. */ var Resolver = function Resolver () {}; Resolver.generate = function generate (el, binding, vnode) { var model = Resolver.resolveModel(binding, vnode); var options = pluginInstance.resolveConfig(vnode.context); return { name: Resolver.resolveName(el, vnode), el: el, listen: !binding.modifiers.disable, bails: binding.modifiers.bails ? true : (binding.modifiers.continues === true ? false : undefined), scope: Resolver.resolveScope(el, binding, vnode), vm: Resolver.makeVM(vnode.context), expression: binding.value, component: vnode.componentInstance, classes: options.classes, classNames: options.classNames, getter: Resolver.resolveGetter(el, vnode, model), events: Resolver.resolveEvents(el, vnode) || options.events, model: model, delay: Resolver.resolveDelay(el, vnode, options), rules: Resolver.resolveRules(el, binding, vnode), immediate: !!binding.modifiers.initial || !!binding.modifiers.immediate, validity: options.validity, aria: options.aria, initialValue: Resolver.resolveInitialValue(vnode) }; }; Resolver.getCtorConfig = function getCtorConfig (vnode) { if (!vnode.componentInstance) { return null; } var config = getPath('componentInstance.$options.$_veeValidate', vnode); return config; }; /** * Resolves the rules defined on an element. */ Resolver.resolveRules = function resolveRules (el, binding, vnode) { var rules = ''; if (!binding.value && (!binding || !binding.expression)) { rules = getDataAttribute(el, 'rules'); } if (binding.value && includes(['string', 'object'], typeof binding.value.rules)) { rules = binding.value.rules; } else if (binding.value) { rules = binding.value; } if (vnode.componentInstance) { return rules; } // If validity is disabled, ignore field rules. var normalized = normalizeRules(rules); if (!pluginInstance.config.validity) { return normalized; } return assign({}, fillRulesFromElement(el, {}), normalized); }; /** * @param {*} vnode */ Resolver.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 */ Resolver.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 */ Resolver.resolveDelay = function resolveDelay (el, vnode, options) { var delay = getDataAttribute(el, 'delay'); var globalDelay = (options && 'delay' in options) ? options.delay : 0; if (!delay && vnode.componentInstance && vnode.componentInstance.$attrs) { delay = vnode.componentInstance.$attrs['data-vv-delay']; } if (!isObject(globalDelay)) { return deepParseInt(delay || globalDelay); } if (!isNullOrUndefined(delay)) { globalDelay.input = delay; } return deepParseInt(globalDelay); }; /** * Resolves the events to validate in response to. * @param {*} el * @param {*} vnode */ Resolver.resolveEvents = function resolveEvents (el, vnode) { // resolve it from the root element. var events = getDataAttribute(el, 'validate-on'); // resolve from data-vv-validate-on if its a vue component. if (!events && vnode.componentInstance && vnode.componentInstance.$attrs) { events = vnode.componentInstance.$attrs['data-vv-validate-on']; } // resolve it from $_veeValidate options. if (!events && vnode.componentInstance) { var config = Resolver.getCtorConfig(vnode); events = config && config.events; } if (!events && pluginInstance.config.events) { events = pluginInstance.config.events; } // resolve the model event if its configured for custom components. if (events && vnode.componentInstance && includes(events, 'input')) { var ref = vnode.componentInstance.$options.model || { event: 'input' }; var event = ref.event; // if the prop was configured but not the model. if (!event) { return events; } events = events.replace('input', event); } return events; }; /** * Resolves the scope for the field. * @param {*} el * @param {*} binding */ Resolver.resolveScope = function resolveScope (el, binding, vnode) { if ( vnode === void 0 ) vnode = {}; var scope = null; if (vnode.componentInstance && isNullOrUndefined(scope)) { scope = vnode.componentInstance.$attrs && vnode.componentInstance.$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} */ Resolver.resolveModel = function resolveModel (binding, vnode) { if (binding.arg) { return { expression: binding.arg }; } var model = findModel(vnode); if (!model) { return null; } // https://github.com/vuejs/vue/blob/dev/src/core/util/lang.js#L26 var watchable = !/[^\w.$]/.test(model.expression) && hasPath(model.expression, vnode.context); var lazy = !!(model.modifiers && model.modifiers.lazy); if (!watchable) { return { expression: null, lazy: lazy }; } return { expression: model.expression, lazy: lazy }; }; /** * Resolves the field name to trigger validations. * @return {String} The field name. */ Resolver.resolveName = function resolveName (el, vnode) { var name = getDataAttribute(el, 'name'); if (!name && !vnode.componentInstance) { return el.name; } if (!name && vnode.componentInstance && vnode.componentInstance.$attrs) { name = vnode.componentInstance.$attrs['data-vv-name'] || vnode.componentInstance.$attrs['name']; } if (!name && vnode.componentInstance) { var config = Resolver.getCtorConfig(vnode); if (config && isCallable(config.name)) { var boundGetter = config.name.bind(vnode.componentInstance); return boundGetter(); } return vnode.componentInstance.name; } return name; }; /** * Returns a value getter input type. */ Resolver.resolveGetter = function resolveGetter (el, vnode, model) { if (model && model.expression) { return function () { return getPath(model.expression, vnode.context); }; } if (vnode.componentInstance) { var path = getDataAttribute(el, 'value-path') || (vnode.componentInstance.$attrs && vnode.componentInstance.$attrs['data-vv-value-path']); if (path) { return function () { return getPath(path, vnode.componentInstance); }; } var config = Resolver.getCtorConfig(vnode); if (config && isCallable(config.value)) { var boundGetter = config.value.bind(vnode.componentInstance); return function () { return boundGetter(); }; } var ref = vnode.componentInstance.$options.model || { prop: 'value' }; var prop = ref.prop; return function () { return vnode.componentInstance[prop]; }; } 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 RULES = {}; var RuleContainer = function RuleContainer () {}; var staticAccessors = { rules: { configurable: true } }; RuleContainer.add = function add (name, ref) { var validate = ref.validate; var options = ref.options; var paramNames = ref.paramNames; RULES[name] = { validate: validate, options: options, paramNames: paramNames }; }; staticAccessors.rules.get = function () { return RULES; }; RuleContainer.has = function has (name) { return !!RULES[name]; }; RuleContainer.isImmediate = function isImmediate (name) { return !!(RULES[name] && RULES[name].options.immediate); }; RuleContainer.isTargetRule = function isTargetRule (name) { return !!(RULES[name] && RULES[name].options.hasTarget); }; RuleContainer.remove = function remove (ruleName) { delete RULES[ruleName]; }; RuleContainer.getParamNames = function getParamNames (ruleName) { return RULES[ruleName] && RULES[ruleName].paramNames; }; RuleContainer.getOptions = function getOptions (ruleName) { return RULES[ruleName] && RULES[ruleName].options; }; RuleContainer.getValidatorMethod = function getValidatorMethod (ruleName) { return RULES[ruleName] ? RULES[ruleName].validate : null; }; Object.defineProperties( RuleContainer, staticAccessors ); // var isEvent = function (evt) { return (typeof Event !== 'undefined' && isCallable(Event) && evt instanceof Event) || (evt && evt.srcElement); }; var normalizeEvents = function (evts) { if (!evts) { return []; } return (typeof evts === 'string' ? evts.split('|') : evts); }; var supportsPassive = true; var detectPassiveSupport = function () { try { var opts = Object.defineProperty({}, 'passive', { get: function get () { supportsPassive = true; } }); window.addEventListener('testPassive', null, opts); window.removeEventListener('testPassive', null, opts); } catch (e) { supportsPassive = false; } return supportsPassive; }; var addEventListener = function (el, eventName, cb) { el.addEventListener(eventName, cb, supportsPassive ? { passive: true } : false); }; // var DEFAULT_OPTIONS = { targetOf: null, immediate: false, scope: null, listen: true, name: null, 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 (options) { if ( options === void 0 ) options = {}; this.id = uniqId(); this.el = options.el; this.updated = false; this.dependencies = []; this.vmId = options.vmId; this.watchers = []; this.events = []; this.delay = 0; this.rules = {}; this._cacheId(options); this.classNames = assign({}, DEFAULT_OPTIONS.classNames); options = assign({}, DEFAULT_OPTIONS, options); this._delay = !isNullOrUndefined(options.delay) ? options.delay : 0; // cache initial delay this.validity = options.validity; this.aria = options.aria; this.flags = createFlags(); this.vm = options.vm; this.componentInstance = options.component; this.ctorConfig = this.componentInstance ? getPath('$options.$_veeValidate', this.componentInstance) : undefined; this.update(options); // set initial value. this.initialValue = this.value; this.updated = false; }; var prototypeAccessors$1 = { validator: { configurable: true },isRequired: { configurable: true },isDisabled: { configurable: true },alias: { configurable: true },value: { configurable: true },bails: { configurable: true },rejectsFalse: { configurable: true } }; prototypeAccessors$1.validator.get = function () { if (!this.vm || !this.vm.$validator) { return { validate: function () {} }; } return this.vm.$validator; }; prototypeAccessors$1.isRequired.get = function () { return !!this.rules.required; }; prototypeAccessors$1.isDisabled.get = function () { return !!(this.componentInstance && this.componentInstance.disabled) || !!(this.el && this.el.disabled); }; /** * Gets the display name (user-friendly name). */ prototypeAccessors$1.alias.get = function () { if (this._alias) { return this._alias; } var alias = null; if (this.ctorConfig && this.ctorConfig.alias) { alias = isCallable(this.ctorConfig.alias) ? this.ctorConfig.alias.call(this.componentInstance) : this.ctorConfig.alias; } if (!alias && this.el) { alias = getDataAttribute(this.el, 'as'); } if (!alias && this.componentInstance) { return this.componentInstance.$attrs && this.componentInstance.$attrs['data-vv-as']; } return alias; }; /** * Gets the input value. */ prototypeAccessors$1.value.get = function () { if (!isCallable(this.getter)) { return undefined; } return this.getter(); }; prototypeAccessors$1.bails.get = function () { return this._bails; }; /** * If the field rejects false as a valid value for the required rule. */ prototypeAccessors$1.rejectsFalse.get = function () { if (this.componentInstance && this.ctorConfig) { return !!this.ctorConfig.rejectsFalse; } if (!this.el) { return false; } return this.el.type === 'checkbox'; }; /** * Determines if the instance matches the options provided. */ Field.prototype.matches = function matches (options) { var this$1 = this; if (!options) { return true; } if (options.id) { return this.id === options.id; } var matchesComponentId = isNullOrUndefined(options.vmId) ? function () { return true; } : function (id) { return id === this$1.vmId; }; if (!matchesComponentId(options.vmId)) { return false; } 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; }; /** * Caches the field id. */ Field.prototype._cacheId = function _cacheId (options) { if (this.el && !options.targetOf) { this.el._veeValidateId = this.id; } }; /** * Keeps a reference of the most current validation run. */ Field.prototype.waitFor = function waitFor (pendingPromise) { this._waitingFor = pendingPromise; }; Field.prototype.isWaitingFor = function isWaitingFor (promise) { return this._waitingFor === promise; }; /** * Updates the field with changed data. */ Field.prototype.update = function update (options) { this.targetOf = options.targetOf || null; this.immediate = options.immediate || this.immediate || false; // update errors scope if the field scope was changed. if (!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