vue-validator
Version:
Validator component for Vue.js
1,889 lines (1,657 loc) • 53.6 kB
JavaScript
/*!
* vue-validator v3.0.0-alpha.2
* (c) 2016 kazuya kawaguchi
* Released under the MIT License.
*/
'use strict';
/* */
function warn (msg, err) {
if (window.console) {
console.warn('[vue-validator] ' + msg);
if (err) {
console.warn(err.stack);
}
}
}
/* */
// validator configrations
var validator = {
classes: {}
};
var Config = function (Vue) {
// define Vue.config.validator configration
// $FlowFixMe: https://github.com/facebook/flow/issues/285
Object.defineProperty(Vue.config, 'validator', {
enumerable: true,
configurable: true,
get: function () { return validator },
set: function (val) { validator = val; }
});
};
/* */
/**
* build-in validators
*/
/**
* required
* This function validate whether the value has been filled out.
*/
function required (val, arg) {
var isRequired = arg === undefined ? true : arg;
if (Array.isArray(val)) {
if (val.length !== 0) {
var valid = true;
for (var i = 0, l = val.length; i < l; i++) {
valid = required(val[i], isRequired);
if ((isRequired && !valid) || (!isRequired && valid)) {
break
}
}
return valid
} else {
return !isRequired
}
} else if (typeof val === 'number' || typeof val === 'function') {
return isRequired
} else if (typeof val === 'boolean') {
return val === isRequired
} else if (typeof val === 'string') {
return isRequired ? (val.length > 0) : (val.length <= 0)
} else if (val !== null && typeof val === 'object') {
return isRequired ? (Object.keys(val).length > 0) : (Object.keys(val).length <= 0)
} else if (val === null || val === undefined) {
return !isRequired
} else {
return !isRequired
}
}
/**
* pattern
* This function validate whether the value matches the regex pattern
*/
function pattern (val, pat) {
if (typeof pat !== 'string') { return false }
var match = pat.match(new RegExp('^/(.*?)/([gimy]*)$'));
if (!match) { return false }
return new RegExp(match[1], match[2]).test(val)
}
/**
* minlength
* This function validate whether the minimum length.
*/
function minlength (val, min) {
if (typeof val === 'string') {
return isInteger(min, 10) && val.length >= parseInt(min, 10)
} else if (Array.isArray(val)) {
return val.length >= parseInt(min, 10)
} else {
return false
}
}
/**
* maxlength
* This function validate whether the maximum length.
*/
function maxlength (val, max) {
if (typeof val === 'string') {
return isInteger(max, 10) && val.length <= parseInt(max, 10)
} else if (Array.isArray(val)) {
return val.length <= parseInt(max, 10)
} else {
return false
}
}
/**
* min
* This function validate whether the minimum value of the numberable value.
*/
function min (val, arg) {
return !isNaN(+(val)) && !isNaN(+(arg)) && (+(val) >= +(arg))
}
/**
* max
* This function validate whether the maximum value of the numberable value.
*/
function max (val, arg) {
return !isNaN(+(val)) && !isNaN(+(arg)) && (+(val) <= +(arg))
}
/**
* isInteger
* This function check whether the value of the string is integer.
*/
function isInteger (val) {
return /^(-?[1-9]\d*|0)$/.test(val)
}
var validators = Object.freeze({
required: required,
pattern: pattern,
minlength: minlength,
maxlength: maxlength,
min: min,
max: max
});
/* */
var Asset = function (Vue) {
var ref = Vue.util;
var extend = ref.extend;
// set global validators asset
var assets = Object.create(null);
extend(assets, validators);
Vue.options.validators = assets;
// set option merge strategy
var strats = Vue.config.optionMergeStrategies;
if (strats) {
strats.validators = function (parent, child) {
if (!child) { return parent }
if (!parent) { return child }
var ret = Object.create(null);
extend(ret, parent);
var key;
for (key in child) {
ret[key] = child[key];
}
return ret
};
}
/**
* Register or retrieve a global validator definition.
*/
function validator (
id,
def
) {
if (def === undefined) {
return Vue.options['validators'][id]
} else {
Vue.options['validators'][id] = def;
if (def === null) {
delete Vue.options['validators']['id'];
}
}
}
Vue['validator'] = validator;
};
/* */
var Group = function (Vue) {
var ref = Vue.util;
var extend = ref.extend;
return {
data: function data () {
return {
valid: true,
dirty: false,
touched: false,
modified: false,
results: {}
}
},
computed: {
invalid: function invalid () { return !this.valid },
pristine: function pristine () { return !this.dirty },
untouched: function untouched () { return !this.touched },
result: function result () {
var ret = {
valid: this.valid,
invalid: this.invalid,
dirty: this.dirty,
pristine: this.pristine,
touched: this.touched,
untouched: this.untouched,
modified: this.modified
};
var results = this.results;
this._validityKeys.forEach(function (key) {
ret[key] = results[key];
if (ret[key].errors) {
var errors = ret.errors || [];
ret[key].errors.forEach(function (error) {
errors.push(error);
});
ret.errors = errors;
}
});
return ret
}
},
watch: {
results: function results (val, old) {
var keys = this._validityKeys;
var results = this.results;
this.valid = this.checkResults(keys, results, 'valid', true);
this.dirty = this.checkResults(keys, results, 'dirty', false);
this.touched = this.checkResults(keys, results, 'touched', false);
this.modified = this.checkResults(keys, results, 'modified', false);
}
},
created: function created () {
this._validities = Object.create(null);
this._validityWatchers = Object.create(null);
this._validityKeys = [];
this._committing = false;
},
destroyed: function destroyed () {
var this$1 = this;
this._validityKeys.forEach(function (key) {
this$1._validityWatchers[key]();
delete this$1._validityWatchers[key];
delete this$1._validities[key];
});
delete this._validityWatchers;
delete this._validities;
delete this._validityKeys;
},
methods: {
register: function register (name, validity) {
var this$1 = this;
this._validities[name] = validity;
this._validityKeys = Object.keys(this._validities);
this.setResults(name, {});
this.withCommit(function () {
this$1._validityWatchers[name] = validity.$watch('result', function (val, old) {
this$1.setResults(name, val);
}, { deep: true, immediate: true });
});
},
unregister: function unregister (name) {
var this$1 = this;
this._validityWatchers[name]();
delete this._validityWatchers[name];
delete this._validities[name];
this._validityKeys = Object.keys(this._validities);
this.withCommit(function () {
this$1.resetResults(name);
});
},
validityCount: function validityCount () {
return this._validityKeys.length
},
isRegistered: function isRegistered (name) {
return name in this._validities
},
getValidityKeys: function getValidityKeys () {
return this._validityKeys
},
checkResults: function checkResults (
keys,
results,
prop,
checking
) {
var ret = checking;
for (var i = 0; i < keys.length; i++) {
var result = results[keys[i]];
if (result[prop] !== checking) {
ret = !checking;
break
}
}
return ret
},
setResults: function setResults (name, val) {
var this$1 = this;
var newVal = {};
this._validityKeys.forEach(function (key) {
newVal[key] = extend({}, this$1.results[key]);
});
newVal[name] = extend({}, val);
this.results = newVal;
},
resetResults: function resetResults (ignore) {
var this$1 = this;
var newVal = {};
this._validityKeys.forEach(function (key) {
if (ignore && ignore !== key) {
newVal[key] = extend({}, this$1.results[key]);
}
});
this.results = newVal;
},
withCommit: function withCommit (fn) {
var committing = this._committing;
this._committing = true;
fn();
this._committing = committing;
}
}
}
};
/* */
var ValidationClass = function (Vue) {
var ValidityGroup = Group(Vue);
var Validation = function Validation (options) {
if ( options === void 0 ) options = {};
this._result = {};
this._host = options.host;
this._named = Object.create(null);
this._group = Object.create(null);
this._validities = Object.create(null);
this._beginDestroy = false;
Vue.util.defineReactive(this._host, '$validation', this._result);
};
Validation.prototype.register = function register (
field,
validity,
options
) {
if ( options === void 0 ) options = {};
// NOTE: lazy setup (in constructor, occured callstack recursive errors ...)
if (!this._validityManager) {
this._validityManager = new Vue(ValidityGroup);
this._watchValidityResult();
}
if (this._validities[field]) {
// TODO: should be output console.error
return
}
this._validities[field] = validity;
var named = options.named;
var group = options.group;
var groupValidity = group
? this._getValidityGroup('group', group) || this._registerValidityGroup('group', group)
: null;
var namedValidity = named
? this._getValidityGroup('named', named) || this._registerValidityGroup('named', named)
: null;
if (named && group && namedValidity && groupValidity) {
groupValidity.register(field, validity);
!namedValidity.isRegistered(group) && namedValidity.register(group, groupValidity);
!this._validityManager.isRegistered(named) && this._validityManager.register(named, namedValidity);
} else if (namedValidity) {
namedValidity.register(field, validity);
!this._validityManager.isRegistered(named) && this._validityManager.register(named, namedValidity);
} else if (groupValidity) {
groupValidity.register(field, validity);
!this._validityManager.isRegistered(group) && this._validityManager.register(group, groupValidity);
} else {
this._validityManager.register(field, validity);
}
};
Validation.prototype.unregister = function unregister (
field,
options
) {
if ( options === void 0 ) options = {};
if (!this._validityManager) {
// TODO: should be output error
return
}
if (!this._validities[field]) {
// TODO: should be output error
return
}
delete this._validities[field];
var named = options.named;
var group = options.group;
var groupValidity = group ? this._getValidityGroup('group', group) : null;
var namedValidity = named ? this._getValidityGroup('named', named) : null;
if (named && group && namedValidity && groupValidity) {
groupValidity.unregister(field);
if (groupValidity.validityCount() === 0) {
namedValidity.isRegistered(group) && namedValidity.unregister(group);
this._unregisterValidityGroup('group', group);
}
if (namedValidity.validityCount() === 0) {
this._validityManager.isRegistered(named) && this._validityManager.unregister(named);
this._unregisterValidityGroup('named', named);
}
} else if (named && namedValidity) {
namedValidity.unregister(field);
if (namedValidity.validityCount() === 0) {
this._validityManager.isRegistered(named) && this._validityManager.unregister(named);
this._unregisterValidityGroup('named', named);
}
} else if (group && groupValidity) {
groupValidity.unregister(field);
if (groupValidity.validityCount() === 0) {
this._validityManager.isRegistered(group) && this._validityManager.unregister(group);
this._unregisterValidityGroup('group', group);
}
} else {
this._validityManager.unregister(field);
}
};
Validation.prototype.destroy = function destroy () {
var this$1 = this;
var validityKeys = Object.keys(this._validities);
var namedKeys = Object.keys(this._named);
var groupKeys = Object.keys(this._group);
// unregister validity
validityKeys.forEach(function (validityKey) {
groupKeys.forEach(function (groupKey) {
var group = this$1._getValidityGroup('group', groupKey);
if (group && group.isRegistered(groupKey)) {
group.unregister(validityKey);
}
});
namedKeys.forEach(function (namedKey) {
var named = this$1._getValidityGroup('named', namedKey);
if (named && named.isRegistered(validityKey)) {
named.unregister(validityKey);
}
});
if (this$1._validityManager.isRegistered(validityKey)) {
this$1._validityManager.unregister(validityKey);
}
delete this$1._validities[validityKey];
});
// unregister grouped validity
groupKeys.forEach(function (groupKey) {
namedKeys.forEach(function (namedKey) {
var named = this$1._getValidityGroup('named', namedKey);
if (named && named.isRegistered(groupKey)) {
named.unregister(groupKey);
}
});
if (this$1._validityManager.isRegistered(groupKey)) {
this$1._validityManager.unregister(groupKey);
}
this$1._unregisterValidityGroup('group', groupKey);
});
// unregister named validity
namedKeys.forEach(function (namedKey) {
if (this$1._validityManager.isRegistered(namedKey)) {
this$1._validityManager.unregister(namedKey);
}
this$1._unregisterValidityGroup('named', namedKey);
});
this._beginDestroy = true;
};
Validation.prototype._getValidityGroup = function _getValidityGroup (type, name) {
return type === 'named' ? this._named[name] : this._group[name]
};
Validation.prototype._registerValidityGroup = function _registerValidityGroup (type, name) {
var groups = type === 'named' ? this._named : this._group;
groups[name] = new Vue(ValidityGroup);
return groups[name]
};
Validation.prototype._unregisterValidityGroup = function _unregisterValidityGroup (type, name) {
var groups = type === 'named' ? this._named : this._group;
if (!groups[name]) {
// TODO: should be warn
return
}
groups[name].$destroy();
delete groups[name];
};
Validation.prototype._watchValidityResult = function _watchValidityResult () {
var this$1 = this;
this._watcher = this._validityManager.$watch('results', function (val, old) {
Vue.set(this$1._host, '$validation', val);
if (this$1._beginDestroy) {
this$1._destroyValidityMananger();
}
}, { deep: true });
};
Validation.prototype._unwatchValidityResult = function _unwatchValidityResult () {
this._watcher();
delete this._watcher;
};
Validation.prototype._destroyValidityMananger = function _destroyValidityMananger () {
this._unwatchValidityResult();
this._validityManager.$destroy();
this._validityManager = null;
};
return Validation
};
/* */
var Mixin = function (Vue) {
var Validation = ValidationClass(Vue);
return {
beforeCreate: function beforeCreate () {
this._validation = new Validation({ host: this });
}
}
};
/* */
var baseProps = {
field: {
type: String,
required: true
},
validators: {
type: [String, Array, Object],
required: true
},
group: {
type: String
},
multiple: {
type: Boolean
},
autotouch: {
type: String,
default: function () {
return 'on'
}
},
classes: {
type: Object,
default: function () {
return {}
}
}
};
var DEFAULT_CLASSES = {
valid: 'valid',
invalid: 'invalid',
touched: 'touched',
untouched: 'untouched',
pristine: 'pristine',
dirty: 'dirty',
modified: 'modified'
};
/* */
var States = function (Vue) {
var ref = Vue.util;
var extend = ref.extend;
var isPlainObject = ref.isPlainObject;
function initialStates (states, validators, init) {
if ( init === void 0 ) init = undefined;
if (Array.isArray(validators)) {
validators.forEach(function (validator) {
states[validator] = init;
});
} else {
Object.keys(validators).forEach(function (validator) {
var props = (validators[validator] &&
validators[validator]['props'] &&
isPlainObject(validators[validator]['props']))
? validators[validator]['props']
: null;
if (props) {
Object.keys(props).forEach(function (prop) {
states[validator] = {};
states[validator][prop] = init;
});
} else {
states[validator] = init;
}
});
}
}
function getInitialResults (validators) {
var results = {};
initialStates(results, validators, undefined);
return results
}
function getInitialProgresses (validators) {
var progresses = {};
initialStates(progresses, validators, '');
return progresses
}
var props = extend({
child: {
type: Object,
required: true
},
value: {
type: Object
}
}, baseProps);
function data () {
var validators = nomalizeValidators(this.validators);
return {
results: getInitialResults(validators),
valid: true,
dirty: false,
touched: false,
modified: false,
progresses: getInitialProgresses(validators)
}
}
return {
props: props,
data: data
}
};
function nomalizeValidators (target) {
return typeof target === 'string' ? [target] : target
}
/* */
var Computed = function (Vue) {
var ref = Vue.util;
var isPlainObject = ref.isPlainObject;
function setError (
result,
field,
validator,
message,
prop
) {
var error = { field: field, validator: validator };
if (message) {
error.message = message;
}
if (prop) {
error.prop = prop;
}
result.errors = result.errors || [];
result.errors.push(error);
}
function walkProgresses (keys, target) {
var progress = '';
for (var i = 0; i < keys.length; i++) {
var result = target[keys[i]];
if (typeof result === 'string' && result) {
progress = result;
break
}
if (isPlainObject(result)) {
var nestedKeys = Object.keys(result);
progress = walkProgresses(nestedKeys, result);
if (!progress) {
break
}
}
}
return progress
}
function invalid () {
return !this.valid
}
function pristine () {
return !this.dirty
}
function untouched () {
return !this.touched
}
function result () {
var this$1 = this;
var ret = {
valid: this.valid,
invalid: this.invalid,
dirty: this.dirty,
pristine: this.pristine,
touched: this.touched,
untouched: this.untouched,
modified: this.modified
};
var keys = this._keysCached(this._uid.toString(), this.results);
keys.forEach(function (validator) {
var result = this$1.results[validator];
if (typeof result === 'boolean') {
if (result) {
ret[validator] = false;
} else {
setError(ret, this$1.field, validator);
ret[validator] = !result;
}
} else if (typeof result === 'string') {
setError(ret, this$1.field, validator, result);
ret[validator] = result;
} else if (isPlainObject(result)) { // object
var props = Object.keys(result);
props.forEach(function (prop) {
var propRet = result[prop];
ret[prop] = ret[prop] || {};
if (typeof propRet === 'boolean') {
if (propRet) {
ret[prop][validator] = false;
} else {
setError(ret, this$1.field, validator, undefined, prop);
ret[prop][validator] = !propRet;
}
} else if (typeof propRet === 'string') {
setError(ret, this$1.field, validator, propRet, prop);
ret[prop][validator] = propRet;
} else {
ret[prop][validator] = false;
}
});
} else {
ret[validator] = false;
}
});
return ret
}
function progress () {
var ret = '';
ret = walkProgresses(
this._keysCached(this._uid.toString(), this.results),
this.progresses
);
return ret
}
return {
invalid: invalid,
pristine: pristine,
untouched: untouched,
result: result,
progress: progress
}
};
/* */
var Render = function (Vue) {
return {
render: function render (h) {
return this.child
}
}
};
/* */
var SingleElementClass = function (Vue) {
var ref = Vue.util;
var looseEqual = ref.looseEqual;
var SingleElement = function SingleElement (vm) {
this._vm = vm;
this.initValue = this.getValue();
this.attachValidity();
};
SingleElement.prototype.attachValidity = function attachValidity () {
this._vm.$el.$validity = this._vm;
};
SingleElement.prototype.getValue = function getValue () {
var el = this._vm.$el;
if (el.tagName === 'SELECT') {
return getSelectValue(el)
} else {
if (el.type === 'checkbox') {
return el.checked
} else {
return el.value
}
}
};
SingleElement.prototype.checkModified = function checkModified () {
var el = this._vm.$el;
if (el.tagName === 'SELECT') {
return !looseEqual(this.initValue, getSelectValue(el))
} else {
if (el.type === 'checkbox') {
return !looseEqual(this.initValue, el.checked)
} else {
return !looseEqual(this.initValue, el.value)
}
}
};
SingleElement.prototype.listenToucheableEvent = function listenToucheableEvent () {
this._vm.$el.addEventListener('focusout', this._vm.willUpdateTouched);
};
SingleElement.prototype.unlistenToucheableEvent = function unlistenToucheableEvent () {
this._vm.$el.removeEventListener('focusout', this._vm.willUpdateTouched);
};
SingleElement.prototype.listenInputableEvent = function listenInputableEvent () {
var vm = this._vm;
var el = vm.$el;
if (el.tagName === 'SELECT') {
el.addEventListener('change', vm.handleInputable);
} else {
if (el.type === 'checkbox') {
el.addEventListener('change', vm.handleInputable);
} else {
el.addEventListener('input', vm.handleInputable);
}
}
};
SingleElement.prototype.unlistenInputableEvent = function unlistenInputableEvent () {
var vm = this._vm;
var el = vm.$el;
if (el.tagName === 'SELECT') {
el.removeEventListener('change', vm.handleInputable);
} else {
if (el.type === 'checkbox') {
el.removeEventListener('change', vm.handleInputable);
} else {
el.removeEventListener('input', vm.handleInputable);
}
}
};
return SingleElement
};
function getSelectValue (el) {
var value = [];
for (var i = 0, l = el.options.length; i < l; i++) {
var option = el.options[i];
if (!option.disabled && option.selected) {
value.push(option.value);
}
}
return value
}
/* */
var MultiElementClass = function (Vue) {
var ref = Vue.util;
var looseEqual = ref.looseEqual;
var MultiElement = function MultiElement (vm) {
// TODO: should be checked whether included radio or checkbox
this._vm = vm;
this.initValue = this.getValue();
this.attachValidity();
};
MultiElement.prototype.attachValidity = function attachValidity () {
var this$1 = this;
this._vm.$el.$validity = this._vm;
this._eachItems(function (item) {
item.$validity = this$1._vm;
});
};
MultiElement.prototype.getValue = function getValue () {
return this._getCheckedValue()
};
MultiElement.prototype.checkModified = function checkModified () {
return !looseEqual(this.initValue, this._getCheckedValue())
};
MultiElement.prototype.listenToucheableEvent = function listenToucheableEvent () {
var this$1 = this;
this._eachItems(function (item) {
item.addEventListener('focusout', this$1._vm.willUpdateTouched);
});
};
MultiElement.prototype.unlistenToucheableEvent = function unlistenToucheableEvent () {
var this$1 = this;
this._eachItems(function (item) {
item.removeEventListener('focusout', this$1._vm.willUpdateTouched);
});
};
MultiElement.prototype.listenInputableEvent = function listenInputableEvent () {
var this$1 = this;
this._eachItems(function (item) {
item.addEventListener('change', this$1._vm.handleInputable);
});
};
MultiElement.prototype.unlistenInputableEvent = function unlistenInputableEvent () {
var this$1 = this;
this._eachItems(function (item) {
item.removeEventListener('change', this$1._vm.handleInputable);
});
};
MultiElement.prototype._getCheckedValue = function _getCheckedValue () {
var value = [];
this._eachItems(function (item) {
if (!item.disabled && item.checked) {
value.push(item.value);
}
});
return value
};
MultiElement.prototype._getItems = function _getItems () {
return this._vm.$el.querySelectorAll('input[type="checkbox"], input[type="radio"]')
};
MultiElement.prototype._eachItems = function _eachItems (cb) {
var items = this._getItems();
for (var i = 0; i < items.length; i++) {
cb(items[i]);
}
};
return MultiElement
};
/* */
var inBrowser =
typeof window !== 'undefined' &&
Object.prototype.toString.call(window) !== '[object Object]';
var UA = inBrowser && window.navigator.userAgent.toLowerCase();
var isIE9 = UA && UA.indexOf('msie 9.0') > 0;
function getClass (el) {
var classname = el.className;
if (typeof classname === 'object') {
classname = classname.baseVal || '';
}
return classname
}
function setClass (el, cls) {
if (isIE9 && !/svg$/.test(el.namespaceURI)) {
el.className = cls;
} else {
el.setAttribute('class', cls);
}
}
function addClass (el, cls) {
if (el.classList) {
el.classList.add(cls);
} else {
var cur = ' ' + getClass(el) + ' ';
if (cur.indexOf(' ' + cls + ' ') < 0) {
setClass(el, (cur + cls).trim());
}
}
}
function removeClass (el, cls) {
if (el.classList) {
el.classList.remove(cls);
} else {
var cur = ' ' + getClass(el) + ' ';
var tar = ' ' + cls + ' ';
while (cur.indexOf(tar) >= 0) {
cur = cur.replace(tar, ' ');
}
setClass(el, cur.trim());
}
if (!el.className) {
el.removeAttribute('class');
}
}
function toggleClasses (el, key, fn) {
if (!el) { return }
key = key.trim();
if (key.indexOf(' ') === -1) {
fn(el, key);
return
}
var keys = key.split(/\s+/);
for (var i = 0, l = keys.length; i < l; i++) {
fn(el, keys[i]);
}
}
function memoize (fn) {
var cache = Object.create(null);
return function memoizeFn (id) {
var args = [], len = arguments.length - 1;
while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
var hit = cache[id];
return hit || (cache[id] = fn.apply(void 0, args))
}
}
/* */
var ComponentElementClass = function (Vue) {
var ref = Vue.util;
var looseEqual = ref.looseEqual;
var isPlainObject = ref.isPlainObject;
function getValidatorProps (validators) {
var normalized = typeof validators === 'string' ? [validators] : validators;
var targets = [];
if (isPlainObject(normalized)) {
Object.keys(normalized).forEach(function (validator) {
var props = (normalized[validator] &&
normalized[validator]['props'] &&
isPlainObject(normalized[validator]['props']))
? normalized[validator]['props']
: null;
if (props) {
Object.keys(props).forEach(function (prop) {
if (!~targets.indexOf(prop)) {
targets.push(prop);
}
});
}
});
}
return targets
}
var ComponentElement = function ComponentElement (vm, vnode, validatorProps) {
this._vm = vm;
this._vnode = vnode;
this._validatorProps = validatorProps || memoize(getValidatorProps);
this.initValue = this.getValue();
this._watchers = [];
this.attachValidity();
};
ComponentElement.prototype.attachValidity = function attachValidity () {
this._vm.$el.$validity = this._vm;
};
ComponentElement.prototype.getValidatorProps = function getValidatorProps$1 () {
var vm = this._vm;
return this._validatorProps(vm._uid.toString(), vm.validators)
};
ComponentElement.prototype.getValue = function getValue () {
var this$1 = this;
var value = {};
this.getValidatorProps().forEach(function (prop) {
value[prop] = this$1._vnode.child[prop];
});
return value
};
ComponentElement.prototype.checkModified = function checkModified () {
return !looseEqual(this.initValue, this.getValue())
};
ComponentElement.prototype.listenToucheableEvent = function listenToucheableEvent () {
this._vm.$el.addEventListener('focusout', this._vm.willUpdateTouched);
};
ComponentElement.prototype.unlistenToucheableEvent = function unlistenToucheableEvent () {
this._vm.$el.removeEventListener('focusout', this._vm.willUpdateTouched);
};
ComponentElement.prototype.listenInputableEvent = function listenInputableEvent () {
var this$1 = this;
this.getValidatorProps().forEach(function (prop) {
this$1._watchers.push(this$1._vnode.child.$watch(prop, this$1._vm.watchInputable));
});
};
ComponentElement.prototype.unlistenInputableEvent = function unlistenInputableEvent () {
this._watchers.forEach(function (watcher) { watcher(); });
this._watchers = [];
};
return ComponentElement
};
/* */
var Elements = function (Vue) {
var SingleElement = SingleElementClass(Vue);
var MultiElement = MultiElementClass(Vue);
var ComponentElement = ComponentElementClass(Vue);
return {
SingleElement: SingleElement,
MultiElement: MultiElement,
ComponentElement: ComponentElement
}
};
/* */
var Lifecycles = function (Vue) {
var ref = Elements(Vue);
var SingleElement = ref.SingleElement;
var MultiElement = ref.MultiElement;
var ComponentElement = ref.ComponentElement;
function createValidityElement (vm, vnode) {
return vm.multiple
? new MultiElement(vm)
: checkBuiltInElement(vnode)
? new SingleElement(vm)
: checkComponentElement(vnode)
? new ComponentElement(vm, vnode)
: null
}
function watchModelable (val) {
this.$emit('input', {
result: this.result,
progress: this.progress,
progresses: this.progresses
});
}
function created () {
this._elementable = null;
this._keysCached = memoize(function (results) {
return Object.keys(results)
});
// for event control flags
this._modified = false;
// watch validation raw results
this._watchValidationRawResults();
var validation = this.$options.propsData ? this.$options.propsData.validation : null;
if (validation) {
var instance = validation.instance;
var name = validation.name;
var group = this.group;
instance.register(this.field, this, { named: name, group: group });
}
}
function destroyed () {
var validation = this.$options.propsData ? this.$options.propsData.validation : null;
if (validation) {
var instance = validation.instance;
var name = validation.name;
var group = this.group;
instance.unregister(this.field, { named: name, group: group });
}
if (this._unwatchResultProp) {
this._unwatchResultProp();
this._unwatchResultProp = null;
}
if (this._unwatchProgressProp) {
this._unwatchProgressProp();
this._unwatchProgressProp = null;
}
this._unwatchValidationRawResults();
this._elementable.unlistenInputableEvent();
if (this.autotouch === 'on') {
this._elementable.unlistenToucheableEvent();
}
this._elementable = null;
}
function mounted () {
this._elementable = createValidityElement(this, this._vnode);
if (this._elementable) {
if (this.autotouch === 'on') {
this._elementable.listenToucheableEvent();
}
this._elementable.listenInputableEvent();
} else {
// TODO: should be warn
}
if (hasModelDirective(this.$vnode)) {
this._unwatchResultProp = this.$watch('result', watchModelable);
this._unwatchProgressProp = this.$watch('progress', watchModelable);
}
toggleClasses(this.$el, this.classes.untouched, addClass);
toggleClasses(this.$el, this.classes.pristine, addClass);
}
return {
created: created,
destroyed: destroyed,
mounted: mounted
}
};
function checkComponentElement (vnode) {
return vnode.child &&
vnode.componentOptions &&
vnode.tag &&
vnode.tag.match(/vue-component/)
}
function checkBuiltInElement (vnode) {
return !vnode.child &&
!vnode.componentOptions &&
vnode.tag
}
function hasModelDirective (vnode) {
return ((vnode && vnode.data && vnode.data.directives) || []).find(function (dir) { return dir.name === 'model'; })
}
/* */
var Event = function (Vue) {
function _fireEvent (type) {
var args = [], len = arguments.length - 1;
while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
(ref = this).$emit.apply(ref, [ type ].concat( args ));
var ref;
}
return {
_fireEvent: _fireEvent
}
};
/* */
var State = function (Vue) {
var ref = Vue.util;
var isPlainObject = ref.isPlainObject;
function getValue (options) {
return this._elementable.getValue()
}
function checkModified () {
return this._elementable.checkModified()
}
function willUpdateTouched (options) {
if (!this.touched) {
this.touched = true;
toggleClasses(this.$el, this.classes.touched, addClass);
toggleClasses(this.$el, this.classes.untouched, removeClass);
this._fireEvent('touched');
}
}
function willUpdateDirty () {
if (!this.dirty && this.checkModified()) {
this.dirty = true;
toggleClasses(this.$el, this.classes.dirty, addClass);
toggleClasses(this.$el, this.classes.pristine, removeClass);
this._fireEvent('dirty');
}
}
function willUpdateModified () {
var modified = this.modified = this.checkModified();
if (this._modified !== modified) {
this._modified = modified;
toggleClasses(this.$el, this.classes.modified, modified ? addClass : removeClass);
this._fireEvent('modified', modified);
}
}
function handleInputable (e) {
this.willUpdateDirty();
this.willUpdateModified();
}
function watchInputable (val) {
this.willUpdateDirty();
this.willUpdateModified();
}
function _initStates (keys, target, init) {
if ( init === void 0 ) init = undefined;
for (var i = 0; i < keys.length; i++) {
var result = target[keys[i]];
if (isPlainObject(result)) {
var nestedKeys = Object.keys(result);
_initStates(nestedKeys, result, init);
} else {
target[keys[i]] = init;
}
}
}
function reset () {
this._unwatchValidationRawResults();
var keys = this._keysCached(this._uid.toString(), this.results);
_initStates(keys, this.results, undefined);
_initStates(keys, this.progresses, '');
toggleClasses(this.$el, this.classes.valid, removeClass);
toggleClasses(this.$el, this.classes.invalid, removeClass);
toggleClasses(this.$el, this.classes.touched, removeClass);
toggleClasses(this.$el, this.classes.untouched, addClass);
toggleClasses(this.$el, this.classes.dirty, removeClass);
toggleClasses(this.$el, this.classes.pristine, addClass);
toggleClasses(this.$el, this.classes.modified, removeClass);
this.valid = true;
this.dirty = false;
this.touched = false;
this.modified = false;
this._modified = false;
this._watchValidationRawResults();
}
function _walkValid (keys, target) {
var valid = true;
for (var i = 0; i < keys.length; i++) {
var result = target[keys[i]];
if (typeof result === 'boolean' && !result) {
valid = false;
break
}
if (typeof result === 'string' && result) {
valid = false;
break
}
if (isPlainObject(result)) {
var nestedKeys = Object.keys(result);
valid = _walkValid(nestedKeys, result);
if (!valid) {
break
}
}
}
return valid
}
function _watchValidationRawResults () {
var this$1 = this;
this._unwatchResults = this.$watch('results', function (val) {
this$1.valid = _walkValid(
this$1._keysCached(this$1._uid.toString(), this$1.results),
this$1.results
);
if (this$1.valid) {
toggleClasses(this$1.$el, this$1.classes.valid, addClass);
toggleClasses(this$1.$el, this$1.classes.invalid, removeClass);
} else {
toggleClasses(this$1.$el, this$1.classes.valid, removeClass);
toggleClasses(this$1.$el, this$1.classes.invalid, addClass);
}
this$1._fireEvent(this$1.valid ? 'valid' : 'invalid');
}, { deep: true });
}
function _unwatchValidationRawResults () {
this._unwatchResults();
this._unwatchResults = undefined;
delete this._unwatchResults;
}
function touch () {
this.willUpdateTouched();
}
return {
getValue: getValue,
checkModified: checkModified,
willUpdateTouched: willUpdateTouched,
willUpdateDirty: willUpdateDirty,
willUpdateModified: willUpdateModified,
handleInputable: handleInputable,
watchInputable: watchInputable,
reset: reset,
_walkValid: _walkValid,
_watchValidationRawResults: _watchValidationRawResults,
_unwatchValidationRawResults: _unwatchValidationRawResults,
touch: touch
}
};
/* */
/**
* Forgiving check for a promise
*/
function isPromise (p) {
return p && typeof p.then === 'function'
}
var Validate = function (Vue) {
var ref = Vue.util;
var extend = ref.extend;
var isPlainObject = ref.isPlainObject;
var resolveAsset = ref.resolveAsset;
function _resolveValidator (name) {
var options = (this.child && this.child.context)
? this.child.context.$options
: this.$options;
return resolveAsset(options, 'validators', name)
}
function _getValidateRawDescriptor (
validator,
field,
value
) {
var asset = this._resolveValidator(validator);
if (!asset) {
// TODO: should be warned
return null
}
var fn = null;
var rule = null;
var msg = null;
if (isPlainObject(asset)) {
if (asset.check && typeof asset.check === 'function') {
fn = asset.check;
}
if (asset.message) {
msg = asset.message;
}
} else if (typeof asset === 'function') {
fn = asset;
} else {
// TODO: should be warned
return null
}
if (!fn) {
// TODO: should be warned
return null
}
var props = null;
var validators = this.validators;
if (isPlainObject(validators)) {
if (isPlainObject(validators[validator])) {
if (validators[validator].props && isPlainObject(validators[validator].props)) {
props = validators[validator].props;
} else {
if (validators[validator].rule) {
rule = validators[validator].rule;
}
if (validators[validator].message) {
msg = validators[validator].message;
}
}
} else {
rule = validators[validator];
}
}
var descriptor = { fn: fn, value: value, field: field };
if (rule) {
descriptor.rule = rule;
}
if (msg) {
descriptor.msg = msg;
}
if (props) {
descriptor.props = props;
}
return descriptor
}
function _resolveMessage (
field,
msg,
override
) {
if (override) { return override }
return msg
? typeof msg === 'function'
? msg(field)
: msg
: undefined
}
function _invokeValidator (
ref,
value,
cb
) {
var this$1 = this;
var fn = ref.fn;
var field = ref.field;
var rule = ref.rule;
var msg = ref.msg;
var future = fn.call(this.child.context, value, rule);
if (typeof future === 'function') { // function
future(function () { // resolve
cb(true);
}, function (err) { // reject
cb(false, this$1._resolveMessage(field, msg, err));
});
} else if (isPromise(future)) { // promise
future.then(function () { // resolve
cb(true);
}, function (err) { // reject
cb(false, this$1._resolveMessage(field, msg, err));
}).catch(function (err) {
cb(false, this$1._resolveMessage(field, msg, err.message));
});
} else { // sync
cb(future, future === false ? this._resolveMessage(field, msg) : undefined);
}
}
function _getValidateDescriptors (
validator,
field,
value
) {
var descriptors = [];
var rawDescriptor = this._getValidateRawDescriptor(validator, this.field, value);
if (!rawDescriptor) { return descriptors }
if (!rawDescriptor.props) {
var descriptor = { name: validator };
extend(descriptor, rawDescriptor);
descriptors.push(descriptor);
} else {
var propsKeys = Object.keys(!rawDescriptor.props);
propsKeys.forEach(function (prop) {
var descriptor = {
fn: rawDescriptor.fn,
name: validator,
value: rawDescriptor.value[prop],
field: rawDescriptor.field,
prop: prop
};
if (rawDescriptor.props[prop].rule) {
descriptor.rule = rawDescriptor.props[prop].rule;
}
if (rawDescriptor.props[prop].message) {
descriptor.msg = rawDescriptor.props[prop].message;
}
descriptors.push(descriptor);
});
}
return descriptors
}
function _syncValidates (field, cb) {
var this$1 = this;
var validators = this._keysCached(this._uid.toString(), this.results);
var value = this.getValue();
var descriptors = [];
validators.forEach(function (validator) {
this$1._getValidateDescriptors(validator, field, value).forEach(function (desc) {
descriptors.push(desc);
});
});
var count = 0;
var len = descriptors.length;
descriptors.forEach(function (desc) {
var validator = desc.name;
var prop = desc.prop;
if ((!prop && this$1.progresses[validator]) || (prop && this$1.progresses[validator][prop])) {
count++;
if (count === len) {
cb(this$1._walkValid(this$1._keysCached(this$1._uid.toString(), this$1.results), this$1.results));
}
return
}
if (!prop) {
this$1.progresses[validator] = 'running';
} else {
this$1.progresses[validator][prop] = 'running';
}
this$1.$nextTick(function () {
this$1._invokeValidator(desc, desc.value, function (ret, msg) {
if (!prop) {
this$1.progresses[validator] = '';
this$1.results[validator] = msg || ret;
} else {
this$1.progresses[validator][prop] = '';
this$1.results[validator][prop] = msg || ret;
}
count++;
if (count === len) {
cb(this$1._walkValid(this$1._keysCached(this$1._uid.toString(), this$1.results), this$1.results));
}
});
});
});
}
// TODO:should be refactor!!
function _validate (validator, value, cb) {
var this$1 = this;
var descriptor = this._getValidateRawDescriptor(validator, this.field, value);
if (descriptor && !descriptor.props) {
if (this.progresses[validator]) { return false }
this.progresses[validator] = 'running';
this.$nextTick(function () {
this$1._invokeValidator(descriptor, descriptor.value, function (ret, msg) {
this$1.progresses[validator] = '';
this$1.results[validator] = msg || ret;
if (cb) {
this$1.$nextTick(function () {
cb.call(this$1, null, ret, msg);
});
} else {
var e = { result: ret };
if (msg) {
e['msg'] = msg;
}
this$1._fireEvent('validate', validator, e);
}
});
});
} else if (descriptor && descriptor.props) {
var propsKeys = Object.keys(descriptor.props);
propsKeys.forEach(function (prop) {
if (this$1.progresses[validator][prop]) { return }
this$1.progresses[validator][prop] = 'running';
var values = descriptor.value;
var propDescriptor = {
fn: descriptor.fn,
value: values[prop],
field: descriptor.field
};
if (descriptor.props[prop].rule) {
propDescriptor.rule = descriptor.props[prop].rule;
}
if (descriptor.props[prop].message) {
propDescriptor.msg = descriptor.props[prop].message;
}
this$1.$nextTick(function () {
this$1._invokeValidator(propDescriptor, propDescriptor.value, function (result, msg) {
this$1.progresses[validator][prop] = '';
this$1.results[validator][prop] = msg || result;
var e = { prop: prop, result: result };
if (msg) {
e['msg'] = msg;
}
this$1._fireEvent('validate', validator, e);
});
});
});
} else {
// TODO:
var err = new Error();
cb ? cb.call(this, err) : this._fireEvent('validate', validator, err);
}
return true
}
// TODO: should be re-design of API
function validate () {
var this$1 = this;
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
var validators;
var value;
var cb;
var ret = true;
if (args.length === 3) {
validators = [args[0]];
value = args[1];
cb = args[2];
} else if (args.length === 2) {
if (isPlainObject(args[0])) {
validators = [args[0].validator];
value = args[0].value || this.getValue();
cb = args[1];
} else {
validators = this._keysCached(this._uid.toString(), this.results);
value = args[0];
cb = args[1];
}
} else if (args.length === 1) {
validators = this._keysCached(this._uid.toString(), this.results);
value = this.getValue();
cb = args[0];
} else {
validators = this._keysCached(this._uid.toString(), this.results);
value = this.getValue();
cb = null;
}
if (args.length === 3 || (args.length === 2 && isPlainObject(args[0]))) {
ret = this._validate(validators[0], value, cb);
} else {
validators.forEach(function (validator) {
ret = this$1._validate(validator, value, cb);
});
}
return ret
}
return {
_resolveValidator: _resolveValidator,
_getValidateRawDescriptor: _getValidateRawDescriptor,
_getValidateDescriptors: _getValidateDescriptors,
_resolveMessage: _resolveMessage,
_invokeValidator: _invokeValidator,
_validate: _validate,
_syncValidates: _syncValidates,
validate: validate
}
};
/* */
var Methods = function (Vue) {
var ref = Vue.util;
var extend = ref.extend;
var methods = {};
extend(methods, Event(Vue));
extend(methods, State(Vue));
extend(methods, Validate(Vue));
return methods
};
/* */
var ValidityControl = function (Vue) {
var ref = Vue.util;
var extend = ref.extend;
var ref$1 = States(Vue);
var props = ref$1.props;
var data = ref$1.data;
var computed = Computed(Vue);
var lifecycles = Lifecycles(Vue);
var ref$2 = Render(Vue);
var render = ref$2.render;
var methods = Methods(Vue);
var validity = {
props: props,
data: data,
render: render,
computed: computed,
methods: methods
};
extend(validity, lifecycles);
return validity
};
/* */
var Validity = function (Vue) {
var ref = Vue.util;
var extend = ref.extend;
return {
functional: true,
props: baseProps,
render: function render (
h,
ref
) {
var props = ref.props;
var data = ref.data;
var children = ref.children;
return children.map(function (child) {
if (!child.tag) { return child }
var newData = extend({}, data);
newData.props = extend({}, props);
// TODO: should be refactored
newData.props.classes = extend(extend(extend({}, DEFAULT_CLASSES), Vue.config.validator.classes), newData.props.classes);
newData.props.child = child;
return h('validity-control', newData)
})
}
}
};
/* */
var ValidityGroup = function (Vue) {
var ref = Vue.util;
var extend = ref.extend;
var props = extend({
tag: {
type: String,
default: 'fieldset'
}
}, baseProps);
return {
functional: true,
props: props,
render: function render (
h,
ref
) {
var props = ref.props;
var data = ref.data;
var children = ref.children;
var child = h(prop