vendor/assets/javascripts/vue-validator.js in vuejs-1.0.31 vs vendor/assets/javascripts/vue-validator.js in vuejs-1.0.33
- old
+ new
@@ -1,28 +1,1828 @@
/*!
- * vue-validator v2.1.3
+ * vue-validator v3.0.0-alpha.1
* (c) 2016 kazuya kawaguchi
* Released under the MIT License.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.VueValidator = factory());
-}(this, function () { 'use strict';
+}(this, (function () { 'use strict';
- function plugin(Vue) {
- var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
+/* */
- Vue.prototype.$add = function (a, b) {
- return a + b;
+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;
+
+var MODEL_NOTIFY_EVENT = '__VUE_VALIDATOR_MODEL_NOTIFY_EVENT__';
+
+function warn (msg, err) {
+ if (window.console) {
+ console.warn('[vue-validator] ' + msg);
+ if (err) {
+ console.warn(err.stack);
+ }
+ }
+}
+
+function looseEqual (a, b) {
+ return a === b || (
+ isObject(a) && isObject(b)
+ ? JSON.stringify(a) === JSON.stringify(b)
+ : false
+ )
+}
+
+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 triggerEvent (el, event, fn) {
+ var e = document.createEvent('HTMLEvents');
+ e.initEvent(event, true, true);
+ fn && fn(e);
+ el.dispatchEvent(e);
+}
+
+// TODO: should be defined strict type
+function mapValidation (results) {
+ var res = {};
+
+ normalizeMap(results).forEach(function (ref) {
+ var key = ref.key;
+ var val = ref.val;
+
+ res[key] = function mappedValidation () {
+ var validation = this.$validation;
+ if (!this._isMounted) {
+ return null
+ }
+ var paths = val.split('.');
+ var first = paths.shift();
+ if (first !== '$validation') {
+ warn(("unknown validation result path: " + val));
+ return null
+ }
+ var path;
+ var value = validation;
+ do {
+ path = paths.shift();
+ value = value[path];
+ } while (paths.length > 0)
+ return value
};
+ });
+
+ return res
+}
+
+function isObject (obj) {
+ return obj !== null && typeof obj === 'object'
+}
+
+// TODO: should be defined strict type
+function normalizeMap (map) {
+ return Array.isArray(map)
+ ? map.map(function (key) { return ({ key: key, val: key }); })
+ : Object.keys(map).map(function (key) { return ({ key: key, val: map[key] }); })
+}
+
+/* */
+
+// 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) {
+ 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]);
+ if (!valid) {
+ break
+ }
+ }
+ return valid
+ } else {
+ return false
+ }
+ } else if (typeof val === 'number' || typeof val === 'function') {
+ return true
+ } else if (typeof val === 'boolean') {
+ return val
+ } else if (typeof val === 'string') {
+ return val.length > 0
+ } else if (val !== null && typeof val === 'object') {
+ return Object.keys(val).length > 0
+ } else if (val === null || val === undefined) {
+ return false
+ } else {
+ return false
}
+}
- plugin.version = '2.1.3';
+/**
+ * pattern
+ * This function validate whether the value matches the regex pattern
+ */
+function pattern (val, pat) {
+ if (typeof pat !== 'string') { return false }
- if (typeof window !== 'undefined' && window.Vue) {
- window.Vue.use(plugin);
+ 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
}
+}
- return plugin;
+/**
+ * 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
+ }
+}
-}));
\ No newline at end of file
+/**
+ * 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];
+ });
+ 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);
+ });
+ },
+ 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);
+ namedValidity.isRegistered(group) && namedValidity.unregister(group);
+ this._validityManager.isRegistered(named) && this._validityManager.unregister(named);
+ } else if (namedValidity) {
+ namedValidity.unregister(field);
+ this._validityManager.isRegistered(named) && this._validityManager.unregister(named);
+ } else if (groupValidity) {
+ groupValidity.unregister(field);
+ this._validityManager.isRegistered(group) && this._validityManager.unregister(group);
+ } else {
+ this._validityManager.unregister(field);
+ }
+
+ group && this._unregisterValidityGroup('group', group);
+ named && this._unregisterValidityGroup('named', named);
+ };
+
+ 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
+ },
+ classes: {
+ type: Object,
+ default: function () {
+ return {
+ 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 props = extend({
+ child: {
+ type: Object,
+ required: true
+ }
+ }, 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) {
+ var validators;
+ if (typeof target === 'string') {
+ validators = [target];
+ } else if (Array.isArray(target)) {
+ validators = target;
+ } else {
+ validators = Object.keys(target);
+ }
+ return validators
+}
+
+function getInitialResults (validators) {
+ var results = {};
+ validators.forEach(function (validator) {
+ results[validator] = undefined;
+ });
+ return results
+}
+
+function getInitialProgresses (validators) {
+ var progresses = {};
+ validators.forEach(function (validator) {
+ progresses[validator] = '';
+ });
+ return progresses
+}
+
+/* */
+
+var Computed = function (Vue) {
+ 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 = getValidatorResult(validator, this$1.results[validator]);
+ if (result === false) { // success
+ ret[validator] = false;
+ } else { // failed
+ var error = { field: this$1.field, validator: validator };
+ if (typeof result === 'string') {
+ error.message = result;
+ }
+ if (!ret.errors) {
+ ret.errors = [];
+ }
+ if (Array.isArray(ret.errors)) {
+ ret.errors.push(error);
+ }
+ ret[validator] = result;
+ }
+ });
+
+ return ret
+ }
+
+ return {
+ invalid: invalid,
+ pristine: pristine,
+ untouched: untouched,
+ result: result
+ }
+};
+
+function getValidatorResult (
+ validator,
+ result
+) {
+ if (typeof result === 'boolean' && !result) {
+ return true
+ }
+
+ if (typeof result === 'string' && result) {
+ return result
+ }
+
+ return false
+}
+
+/* */
+
+var Render = function (Vue) {
+ return {
+ render: function render (h) {
+ this._interceptEvents(this.child, this.multiple);
+ return this.child
+ }
+ }
+};
+
+/* */
+function addEventInfo (e) {
+ e[MODEL_NOTIFY_EVENT] = 'DOM';
+}
+
+function modelValueEqual (vnode) {
+ var directives = (vnode.data && vnode.data.directives) || [];
+ var directive = directives.find(function (dir) {
+ return dir.name === 'model'
+ });
+ return !directive
+ ? null
+ : looseEqual(directive.value, directive.oldValue)
+}
+
+/* */
+var SingleElement = function SingleElement (vm, vnode) {
+ this._vm = vm;
+ this._vnode = vnode;
+ this.initValue = this.getValue();
+ this.attachValidity();
+};
+
+var prototypeAccessors = { _isBuiltIn: {},_isComponent: {} };
+
+prototypeAccessors._isBuiltIn.get = function () {
+ var vnode = this._vnode;
+ return !vnode.child &&
+ !vnode.componentOptions &&
+ vnode.tag
+};
+
+prototypeAccessors._isComponent.get = function () {
+ var vnode = this._vnode;
+ return vnode.child &&
+ vnode.componentOptions &&
+ vnode.tag.match(/vue-component/)
+};
+
+SingleElement.prototype.attachValidity = function attachValidity () {
+ this._vm.$el.$validity = this._vm;
+};
+
+SingleElement.prototype.getValue = function getValue () {
+ if (this._isBuiltIn) {
+ var el = this._vm.$el;
+ if (el.tagName === 'SELECT') {
+ return getSelectValue(el)
+ } else {
+ if (el.type === 'checkbox') {
+ return el.checked
+ } else {
+ return el.value
+ }
+ }
+ } else if (this._isComponent) {
+ return this._vnode.child.value
+ } else {
+ // TODO: should be warn !!
+ return ''
+ }
+};
+
+SingleElement.prototype.checkModified = function checkModified () {
+ if (this._isBuiltIn) {
+ 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)
+ }
+ }
+ } else if (this._isComponent) {
+ return !looseEqual(this.initValue, this._vnode.child.value)
+ } else {
+ // TODO: should be warn !!
+ return false
+ }
+};
+
+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;
+ if (this._isBuiltIn) {
+ 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);
+ }
+ }
+ } else if (this._isComponent) {
+ this._unwatchInputable = this._vnode.child.$watch('value', vm.watchInputable);
+ } else {
+ // TODO: should be warn !!
+ }
+};
+
+SingleElement.prototype.unlistenInputableEvent = function unlistenInputableEvent () {
+ var vm = this._vm;
+ if (this._isBuiltIn) {
+ 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);
+ }
+ }
+ } else if (this._isComponent) {
+ if (this._unwatchInputable) {
+ this._unwatchInputable();
+ this._unwatchInputable = undefined;
+ delete this._unwatchInputable;
+ }
+ } else {
+ // TODO: should be warn !!
+ }
+};
+
+SingleElement.prototype.fireInputableEvent = function fireInputableEvent () {
+ if (this._isBuiltIn) {
+ var el = this._vm.$el;
+ if (el.tagName === 'SELECT') {
+ triggerEvent(el, 'change', addEventInfo);
+ } else {
+ if (el.type === 'checkbox') {
+ triggerEvent(el, 'change', addEventInfo);
+ } else {
+ triggerEvent(el, 'input', addEventInfo);
+ }
+ }
+ } else if (this._isComponent) {
+ var args = { value: this.getValue() };
+ args[MODEL_NOTIFY_EVENT] = 'COMPONENT';
+ this._vnode.child.$emit('input', args);
+ } else {
+ // TODO: should be warn !!
+ }
+};
+
+SingleElement.prototype.modelValueEqual = function modelValueEqual$1 () {
+ return modelValueEqual(this._vnode)
+};
+
+Object.defineProperties( SingleElement.prototype, prototypeAccessors );
+
+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 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.fireInputableEvent = function fireInputableEvent () {
+ this._eachItems(function (item) {
+ triggerEvent(item, 'change', addEventInfo);
+ });
+};
+
+MultiElement.prototype.modelValueEqual = function modelValueEqual$1 () {
+ var ret = null;
+ var children = (this._vm.child && this._vm.child.children) || [];
+ for (var i = 0; i < children.length; i++) {
+ if (!modelValueEqual(children[i])) {
+ ret = false;
+ break
+ }
+ }
+ return ret
+};
+
+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]);
+ }
+};
+
+/* */
+
+/* */
+var Lifecycles = function (Vue) {
+ 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, this, { named: name, group: group });
+ }
+
+ this._unwatchValidationRawResults();
+
+ this._elementable.unlistenInputableEvent();
+ this._elementable.unlistenToucheableEvent();
+ this._elementable = null;
+ }
+
+ function mounted () {
+ this._elementable = createValidityElement(this);
+ this._elementable.listenToucheableEvent();
+ this._elementable.listenInputableEvent();
+
+ toggleClasses(this.$el, this.classes.untouched, addClass);
+ toggleClasses(this.$el, this.classes.pristine, addClass);
+ }
+
+ function updated () {
+ var maybeChangeModel = this._elementable.modelValueEqual();
+ if (!this._applyWithUserHandler && maybeChangeModel !== null && !maybeChangeModel) {
+ this._elementable.fireInputableEvent();
+ }
+ delete this._applyWithUserHandler;
+ }
+
+ return {
+ created: created,
+ destroyed: destroyed,
+ mounted: mounted,
+ updated: updated
+ }
+};
+
+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))
+ }
+}
+
+function createValidityElement (vm) {
+ var vnode = vm.child;
+ return !vm.multiple
+ ? new SingleElement(vm, vnode)
+ : new MultiElement(vm)
+}
+
+/* */
+var Event = function (Vue) {
+ var ref = Vue.util;
+ var toArray = ref.toArray;
+
+ 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;
+ }
+
+ function _interceptEvents (child, multiple) {
+ var this$1 = this;
+
+ (multiple ? (child.children || []) : [child]).forEach(function (child) { this$1._wrapEvent(child); });
+ }
+
+ function _wrapEvent (child) {
+ var this$1 = this;
+
+ var ret = {};
+ if (!child.tag || !child.data) { return ret }
+
+ var dir = getModelDirective(child);
+ if (!dir) { return ret }
+
+ var ref = getEventSources(child);
+ var type = ref.type;
+ var orgListeners = ref.orgListeners;
+ var listeners = ref.listeners;
+ if (!Array.isArray(orgListeners)) { return ret }
+
+ var modelHandler = orgListeners[0];
+ var userHandler = orgListeners[1];
+ var modelApplyer = function (args) {
+ return function () {
+ this$1._applyWithUserHandler = true;
+ modelHandler.apply(child.context, args);
+ }
+ };
+ var modifier = (dir.modifiers || {}).validity;
+ listeners[type] = function () {
+ var args = toArray(arguments, 0);
+ var event = args[0];
+ if (event[MODEL_NOTIFY_EVENT] === 'DOM') {
+ delete event[MODEL_NOTIFY_EVENT];
+ userHandler.apply(child.context, args);
+ return
+ } else if (event[MODEL_NOTIFY_EVENT] === 'COMPONENT') {
+ var value = event.value;
+ args[0] = value;
+ userHandler.apply(child.context, args);
+ return
+ }
+
+ if (modifier) {
+ args.push(modelApplyer(args));
+ userHandler.apply(child.context, args);
+ } else {
+ userHandler.apply(child.context, args);
+ modelHandler.apply(child.context, args);
+ }
+ };
+
+ ret.dir = dir;
+ return ret
+ }
+
+ return {
+ _fireEvent: _fireEvent,
+ _interceptEvents: _interceptEvents,
+ _wrapEvent: _wrapEvent
+ }
+};
+
+function getModelDirective (child) {
+ return ((child.data && child.data.directives) || []).find(function (dir) { return dir.name === 'model' })
+}
+
+function getEventSources (child) {
+ var sources = {};
+ var listeners = sources.listeners = child.componentOptions
+ ? child.componentOptions.listeners
+ : (child.data && child.data.on);
+ sources.type =
+ (child.tag === 'input' && (child.data && child.data.attrs && child.data.attrs.type) === 'text') ||
+ (child.tag && child.tag.match(/vue-component/))
+ ? 'input'
+ : 'change';
+ if (listeners) {
+ sources.orgListeners = listeners[sources.type];
+ }
+ return sources
+}
+
+/* */
+var State = function (Vue) {
+ 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 reset () {
+ var this$1 = this;
+
+ this._unwatchValidationRawResults();
+ var keys = this._keysCached(this._uid.toString(), this.results);
+ for (var i = 0; i < keys.length; i++) {
+ this$1.results[keys[i]] = undefined;
+ this$1.progresses[keys[i]] = '';
+ }
+ 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 _watchValidationRawResults () {
+ var this$1 = this;
+
+ this._unwatch = this.$watch('results', function (val) {
+ var valid = true;
+ var keys = this$1._keysCached(this$1._uid.toString(), this$1.results);
+ for (var i = 0; i < keys.length; i++) {
+ var result = this$1.results[keys[i]];
+ if (typeof result === 'boolean' && !result) {
+ valid = false;
+ break
+ }
+ if (typeof result === 'string' && result) {
+ valid = false;
+ break
+ }
+ }
+ this$1.valid = valid;
+
+ if (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(valid ? 'valid' : 'invalid');
+ }, { deep: true });
+ }
+
+ function _unwatchValidationRawResults () {
+ this._unwatch();
+ this._unwatch = undefined;
+ delete this._unwatch;
+ }
+
+ return {
+ getValue: getValue,
+ checkModified: checkModified,
+ willUpdateTouched: willUpdateTouched,
+ willUpdateDirty: willUpdateDirty,
+ willUpdateModified: willUpdateModified,
+ handleInputable: handleInputable,
+ watchInputable: watchInputable,
+ reset: reset,
+ _watchValidationRawResults: _watchValidationRawResults,
+ _unwatchValidationRawResults: _unwatchValidationRawResults
+ }
+};
+
+/* */
+
+/**
+ * Forgiving check for a promise
+ */
+function isPromise (p) {
+ return p && typeof p.then === 'function'
+}
+
+var Validate = function (Vue) {
+ function _resolveValidator (name) {
+ var ref = Vue.util;
+ var resolveAsset = ref.resolveAsset;
+ var options = (this.child && this.child.context)
+ ? this.child.context.$options
+ : this.$options;
+ return resolveAsset(options, 'validators', name)
+ }
+
+ function _getValidateDescriptor (
+ validator,
+ field,
+ value
+ ) {
+ var ref = Vue.util;
+ var isPlainObject = ref.isPlainObject;
+
+ 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
+ }
+
+ if (isPlainObject(this.validators)) {
+ if (isPlainObject(this.validators[validator])) {
+ if (this.validators[validator].rule) {
+ rule = this.validators[validator].rule;
+ }
+ if (this.validators[validator].message) {
+ msg = this.validators[validator].message;
+ }
+ } else {
+ rule = this.validators[validator];
+ }
+ }
+
+ var descriptor = { fn: fn, value: value, field: field };
+ if (rule) {
+ descriptor.rule = rule;
+ }
+ if (msg) {
+ descriptor.msg = msg;
+ }
+
+ return descriptor
+ }
+
+ function _resolveMessage (
+ field,
+ msg,
+ override
+ ) {
+ if (override) { return override }
+ return msg
+ ? typeof msg === 'function'
+ ? msg(field)
+ : msg
+ : undefined
+ }
+
+ function _invokeValidator (
+ ref,
+ cb
+ ) {
+ var this$1 = this;
+ var fn = ref.fn;
+ var value = ref.value;
+ var field = ref.field;
+ var rule = ref.rule;
+ var msg = ref.msg;
+
+ var future = fn.call(this, 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 _validate (validator, value, cb) {
+ var this$1 = this;
+
+ var descriptor = this._getValidateDescriptor(validator, this.field, value);
+ if (descriptor) {
+ if (this.progresses[validator]) { return false }
+ this.progresses[validator] = 'running';
+ this.$nextTick(function () {
+ this$1._invokeValidator(descriptor, 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 {
+ // TODO:
+ var err = new Error();
+ cb ? cb.call(this, err) : this._fireEvent('validate', validator, err);
+ }
+ return true
+ }
+
+ 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) {
+ 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) {
+ ret = this._validate(validators[0], value, cb);
+ } else {
+ validators.forEach(function (validator) {
+ ret = this$1._validate(validator, value, cb);
+ });
+ }
+
+ return ret
+ }
+
+ return {
+ _resolveValidator: _resolveValidator,
+ _getValidateDescriptor: _getValidateDescriptor,
+ _resolveMessage: _resolveMessage,
+ _invokeValidator: _invokeValidator,
+ _validate: _validate,
+ 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);
+ extend(newData.props.classes, Vue.config.validator.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(props.tag, children);
+ var newData = extend({}, data);
+ newData.props = extend({}, props);
+ extend(newData.props.classes, Vue.config.validator.classes);
+ newData.props.child = child;
+ newData.props.multiple = true;
+ return h('validity-control', newData)
+ }
+ }
+};
+
+/* */
+
+var Validation = function (Vue) {
+ return {
+ functional: true,
+ props: {
+ name: {
+ type: String
+ },
+ tag: {
+ type: String,
+ default: 'form'
+ }
+ },
+ render: function render (
+ h,
+ ref
+ ) {
+ var props = ref.props;
+ var data = ref.data;
+ var parent = ref.parent;
+ var children = ref.children;
+ var slots = ref.slots;
+
+ if (!parent._validation) {
+ // TODO: should be warned
+ return children
+ }
+ var tag = props.tag || 'form';
+ walkChildren(parent._validation, props.name, children);
+ return h(tag, tag === 'form' ? { attrs: { novalidate: true }} : {}, children)
+ }
+ }
+};
+
+function walkChildren (validation, name, children) {
+ children.forEach(function (child) {
+ if (child &&
+ child.componentOptions &&
+ child.componentOptions.propsData && child.componentOptions.tag === 'validity-control') {
+ child.componentOptions.propsData.validation = {
+ instance: validation,
+ name: name
+ };
+ }
+ child.children && walkChildren(validation, name, child.children);
+ });
+}
+
+/* */
+var Component = function (Vue) {
+ return {
+ 'validity-control': ValidityControl(Vue),
+ 'validity': Validity(Vue),
+ 'validity-group': ValidityGroup(Vue),
+ 'validation': Validation(Vue)
+ }
+};
+
+/* */
+var installed = false;
+
+function plugin (Vue, options) {
+ if ( options === void 0 ) options = {};
+
+ if (installed) {
+ warn('already installed.');
+ return
+ }
+
+ Config(Vue);
+ Asset(Vue);
+ installMixin(Vue);
+ installComponent(Vue);
+ installed = true;
+}
+
+function installMixin (Vue) {
+ Vue.mixin(Mixin(Vue));
+}
+
+function installComponent (Vue) {
+ var components = Component(Vue);
+ Object.keys(components).forEach(function (id) {
+ Vue.component(id, components[id]);
+ });
+}
+
+plugin.mapValidation = mapValidation; // for standalone
+plugin.version = '3.0.0-alpha.1';
+
+if (typeof window !== 'undefined' && window.Vue) {
+ window.Vue.use(plugin);
+}
+
+var index = {
+ install: plugin,
+ mapValidation: mapValidation
+};
+
+return index;
+
+})));