1
0
mirror of synced 2025-02-16 20:53:13 +03:00

Adds default validation messages for all rule types

This commit is contained in:
Justin Schroeder 2019-11-13 16:10:17 -05:00
parent e952e46aad
commit ba24fc21e8
15 changed files with 1755 additions and 617 deletions

574
dist/formulate.esm.js vendored
View File

@ -161,6 +161,17 @@ function arrayify (item) {
return []
}
/**
* How to add an item.
* @param {string} item
*/
function sentence (item) {
if (typeof item === 'string') {
return item[0].toUpperCase() + item.substr(1)
}
return item
}
/**
* Given an array or string return an array of callables.
* @param {array|string} validation
@ -187,6 +198,7 @@ function parseRule (rule, rules) {
return [rule, []]
}
if (Array.isArray(rule) && rule.length) {
rule = rule.map(function (r) { return r; }); // light clone
if (typeof rule[0] === 'string' && rules.hasOwnProperty(rule[0])) {
return [rules[rule.shift()], rule]
}
@ -217,88 +229,6 @@ var rules = {
return Promise.resolve(['yes', 'on', '1', 1, true, 'true'].includes(value))
},
/**
* Rule: must be a value
*/
required: function (value, isRequired) {
if ( isRequired === void 0 ) isRequired = true;
return Promise.resolve((function () {
if (!isRequired || ['no', 'false'].includes(isRequired)) {
return true
}
if (Array.isArray(value)) {
return !!value.length
}
if (typeof value === 'string') {
return !!value
}
if (typeof value === 'object') {
return (!value) ? false : !!Object.keys(value).length
}
return true
})())
},
/**
* Rule: Value is in an array (stack).
*/
in: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(stack.find(function (item) {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) !== undefined)
},
/**
* Rule: Value is not in stack.
*/
not: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(stack.find(function (item) {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) === undefined)
},
/**
* Rule: Match the value against a (stack) of patterns or strings
*/
matches: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(!!stack.find(function (pattern) {
if (pattern instanceof RegExp) {
return pattern.test(value)
}
return pattern === value
}))
},
/**
* Rule: checks if a string is a valid url
*/
url: function (value) {
return Promise.resolve(isUrl(value))
},
/**
* Rule: ensures the value is a date according to Date.parse()
*/
date: function (value) {
return Promise.resolve(!isNaN(Date.parse(value)))
},
/**
* Rule: checks if a value is after a given date. Defaults to current time
*/
@ -310,6 +240,34 @@ var rules = {
return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue > timestamp))
},
/**
* Rule: checks if the value is only alpha
*/
alpha: function (value, set) {
if ( set === void 0 ) set = 'default';
var sets = {
default: /^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/,
latin: /^[a-zA-Z]+$/
};
var selectedSet = sets.hasOwnProperty(set) ? set : 'default';
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if the value is alpha numeric
*/
alphanumeric: function (value, set) {
if ( set === void 0 ) set = 'default';
var sets = {
default: /^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/,
latin: /^[a-zA-Z0-9]+$/
};
var selectedSet = sets.hasOwnProperty(set) ? set : 'default';
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if a value is after a given date. Defaults to current time
*/
@ -321,45 +279,13 @@ var rules = {
return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue < timestamp))
},
/**
* Rule: checks if the value is only alpha numeric
*/
alpha: function (value, set) {
if ( set === void 0 ) set = 'default';
var sets = {
default: /^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/,
latin: /^[a-z][A-Z]$/
};
var selectedSet = sets.hasOwnProperty(set) ? set : 'default';
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if the value is only alpha numeric
*/
number: function (value) {
return Promise.resolve(!isNaN(value))
},
/**
* Rule: checks if the value is alpha numeric
*/
alphanumeric: function (value, set) {
if ( set === void 0 ) set = 'default';
var sets = {
default: /^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/,
latin: /^[a-zA-Z0-9]$/
};
var selectedSet = sets.hasOwnProperty(set) ? set : 'default';
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if the value is between two other values
*/
between: function (value, from, to) {
if ( from === void 0 ) from = 0;
if ( to === void 0 ) to = 10;
return Promise.resolve((function () {
if (from === null || to === null || isNaN(from) || isNaN(to)) {
return false
@ -377,6 +303,13 @@ var rules = {
})())
},
/**
* Rule: ensures the value is a date according to Date.parse()
*/
date: function (value) {
return Promise.resolve(!isNaN(Date.parse(value)))
},
/**
* Rule: tests
*/
@ -386,6 +319,58 @@ var rules = {
return Promise.resolve(isEmail.test(value))
},
/**
* Rule: Value is in an array (stack).
*/
in: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(stack.find(function (item) {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) !== undefined)
},
/**
* Rule: Match the value against a (stack) of patterns or strings
*/
matches: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(!!stack.find(function (pattern) {
if (pattern instanceof RegExp) {
return pattern.test(value)
}
return pattern === value
}))
},
/**
* Check the maximum value of a particular.
*/
max: function (value, minimum) {
if ( minimum === void 0 ) minimum = 10;
return Promise.resolve((function () {
minimum = Number(minimum);
if (!isNaN(value)) {
value = Number(value);
return value <= minimum
}
if (typeof value === 'string') {
return value.length <= minimum
}
if (Array.isArray(value)) {
return value.length <= minimum
}
return false
})())
},
/**
* Check the file type is correct.
*/
@ -409,6 +394,8 @@ var rules = {
* Check the minimum value of a particular.
*/
min: function (value, minimum) {
if ( minimum === void 0 ) minimum = 1;
return Promise.resolve((function () {
minimum = Number(minimum);
if (!isNaN(value)) {
@ -426,23 +413,243 @@ var rules = {
},
/**
* Check the minimum value of a particular.
* Rule: Value is not in stack.
*/
max: function (value, minimum) {
return Promise.resolve((function () {
minimum = Number(minimum);
if (!isNaN(value)) {
value = Number(value);
return value <= minimum
not: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(stack.find(function (item) {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
if (typeof value === 'string') {
return value.length <= minimum
return item === value
}) === undefined)
},
/**
* Rule: checks if the value is only alpha numeric
*/
number: function (value) {
return Promise.resolve(!isNaN(value))
},
/**
* Rule: must be a value
*/
required: function (value, isRequired) {
if ( isRequired === void 0 ) isRequired = true;
return Promise.resolve((function () {
if (!isRequired || ['no', 'false'].includes(isRequired)) {
return true
}
if (Array.isArray(value)) {
return value.length <= minimum
return !!value.length
}
return false
if (typeof value === 'string') {
return !!value
}
if (typeof value === 'object') {
return (!value) ? false : !!Object.keys(value).length
}
return true
})())
},
/**
* Rule: checks if a string is a valid url
*/
url: function (value) {
return Promise.resolve(isUrl(value))
}
};
/**
* Validation error message generators.
*/
var en = {
/**
* Valid accepted value.
*/
accepted: function (ref) {
var name = ref.name;
return ("Please accept the " + name + ".")
},
/**
* The date is not after.
*/
after: function (ref) {
var name = ref.name;
var args = ref.args;
if (Array.isArray(args) && args.length) {
return ((sentence(name)) + " must be after " + (args[0]) + ".")
}
return ((sentence(name)) + " must be a later date.")
},
/**
* The value is not a letter.
*/
alpha: function (ref) {
var name = ref.name;
return ((sentence(name)) + " can only contain alphabetical characters.")
},
/**
* Rule: checks if the value is alpha numeric
*/
alphanumeric: function (ref) {
var name = ref.name;
return ((sentence(name)) + " can only contain letters and numbers.")
},
/**
* The date is not before.
*/
before: function (ref) {
var name = ref.name;
var args = ref.args;
if (Array.isArray(args) && args.length) {
return ((sentence(name)) + " must be before " + (args[0]) + ".")
}
return ((sentence(name)) + " must be an earlier date.")
},
/**
* The value is not between two numbers or lengths
*/
between: function (ref) {
var name = ref.name;
var value = ref.value;
var args = ref.args;
if (!isNaN(value)) {
return ((sentence(name)) + " must be between " + (args[0]) + " and " + (args[1]) + ".")
}
return ((sentence(name)) + " must be between " + (args[0]) + " and " + (args[1]) + " characters long.")
},
/**
* Is not a valid date.
*/
date: function (ref) {
var name = ref.name;
return ((sentence(name)) + " is not a valid date.")
},
/**
* The default render method for error messages.
*/
default: function (ref) {
var name = ref.name;
return "This field isnt valid."
},
/**
* Is not a valid email address.
*/
email: function (ref) {
var name = ref.name;
var value = ref.value;
return (value + " is not a valid email address.")
},
/**
* Value is an allowed value.
*/
in: function (ref) {
var name = ref.name;
var value = ref.value;
if (typeof value === 'string') {
return ("“" + (sentence(value)) + "” is not an allowed " + name + ".")
}
return ((sentence(name)) + " is not an allowed value.")
},
/**
* Value is not a match.
*/
matches: function (ref) {
var name = ref.name;
return ((sentence(name)) + " is not an allowed value.")
},
/**
* The maximum value allowed.
*/
max: function (ref) {
var name = ref.name;
var value = ref.value;
var args = ref.args;
if (!isNaN(value)) {
return (name + " must be less than " + (args[0]) + ".")
}
return (name + " must be less than " + (args[0]) + " characters long.")
},
/**
* The maximum value allowed.
*/
min: function (ref) {
var name = ref.name;
var value = ref.value;
var args = ref.args;
if (!isNaN(value)) {
return (name + " must be more than " + (args[0]) + ".")
}
return (name + " must be more than " + (args[0]) + " characters long.")
},
/**
* The field is not an allowed value
*/
not: function (ref) {
var name = ref.name;
var value = ref.value;
return ("“" + value + "” is not an allowed " + name + ".")
},
/**
* The field is not a number
*/
number: function (ref) {
var name = ref.name;
return ((sentence(name)) + " must be a number.")
},
/**
* Required field.
*/
required: function (ref) {
var name = ref.name;
return ((sentence(name)) + " is required.")
},
/**
* Value is not a url.
*/
url: function (ref) {
var name = ref.name;
return "Please include a valid url."
}
};
@ -453,9 +660,6 @@ var rules = {
*/
var context = {
context: function context () {
if (this.debug) {
console.log(((this.type) + " re-context"));
}
return defineModel.call(this, Object.assign({}, {type: this.type,
value: this.value,
name: this.nameOrFallback,
@ -464,7 +668,8 @@ var context = {
id: this.id || this.defaultId,
label: this.label,
labelPosition: this.logicalLabelPosition,
attributes: this.elementAttributes},
attributes: this.elementAttributes,
blurHandler: blurHandler.bind(this)},
this.typeContext))
},
nameOrFallback: nameOrFallback,
@ -473,7 +678,9 @@ var context = {
logicalLabelPosition: logicalLabelPosition,
isVmodeled: isVmodeled,
mergedErrors: mergedErrors,
hasErrors: hasErrors
hasErrors: hasErrors,
showFieldErrors: showFieldErrors,
mergedValidationName: mergedValidationName
};
/**
@ -533,6 +740,33 @@ function logicalLabelPosition () {
}
}
/**
* The validation label to use.
*/
function mergedValidationName () {
if (this.validationName) {
return this.validationName
}
if (typeof this.name === 'string') {
return this.name
}
if (this.label) {
return this.label
}
return this.type
}
/**
* Determines if the field should show it's error (if it has one)
* @return {boolean}
*/
function showFieldErrors () {
if (this.showErrors) {
return this.showErrors
}
return this.behavioralErrorVisibility
}
/**
* Return the elements name, or select a fallback.
*/
@ -593,6 +827,15 @@ function hasErrors () {
return !!this.mergedErrors.length
}
/**
* Bound into the context object.
*/
function blurHandler () {
if (this.errorBehavior === 'blur') {
this.behavioralErrorVisibility = true;
}
}
/**
* Defines the model used throughout the existing context.
* @param {object} context
@ -636,7 +879,8 @@ var script = {
inheritAttrs: false,
inject: {
formulateFormSetter: { default: undefined },
formulateFormRegister: { default: undefined }
formulateFormRegister: { default: undefined },
getFormValues: { default: function () { return function () { return ({}); }; } }
},
model: {
prop: 'formulateValue',
@ -695,15 +939,23 @@ var script = {
type: [String, Boolean, Array],
default: false
},
validationBehavior: {
validationName: {
type: [String, Boolean],
default: false
},
error: {
type: [String, Boolean],
default: false
},
errorBehavior: {
type: String,
default: 'blur',
validator: function (value) {
return ['blur', 'live'].includes(value)
}
},
error: {
type: [String, Boolean],
showErrors: {
type: Boolean,
default: false
}
},
@ -712,6 +964,7 @@ var script = {
defaultId: nanoid(9),
localAttributes: {},
internalModelProxy: this.formulateValue,
behavioralErrorVisibility: (this.errorBehavior === 'live'),
validationErrors: []
}
},
@ -765,7 +1018,13 @@ var script = {
var args = ref[1];
return rule.apply(void 0, [ this$1.context.model ].concat( args ))
.then(function (res) { return res ? false : 'Validation error!'; })
.then(function (res) { return res ? false : this$1.$formulate.validationMessage(rule.name, {
args: args,
name: this$1.mergedValidationName,
value: this$1.context.model,
vm: this$1,
formValues: this$1.getFormValues()
}); })
})
)
.then(function (result) { return result.filter(function (result) { return result; }); })
@ -864,6 +1123,7 @@ var __vue_render__ = function() {
attrs: {
"data-classification": _vm.classification,
"data-has-errors": _vm.hasErrors,
"data-is-showing-errors": _vm.hasErrors && _vm.showFieldErrors,
"data-type": _vm.type
}
},
@ -926,7 +1186,9 @@ var __vue_render__ = function() {
})
: _vm._e(),
_vm._v(" "),
_c("FormulateInputErrors", { attrs: { errors: _vm.mergedErrors } })
_vm.showFieldErrors
? _c("FormulateInputErrors", { attrs: { errors: _vm.mergedErrors } })
: _vm._e()
],
1
)
@ -969,7 +1231,8 @@ var script$1 = {
provide: function provide () {
return {
formulateFormSetter: this.setFieldValue,
formulateFormRegister: this.register
formulateFormRegister: this.register,
getFormValues: this.getFormValues
}
},
name: 'FormulateForm',
@ -1051,6 +1314,9 @@ var script$1 = {
formSubmitted: function formSubmitted () {
// perform validation here
this.$emit('submit', this.formModel);
},
getFormValues: function getFormValues () {
return this.internalFormModelProxy
}
}
};
@ -1379,6 +1645,7 @@ var __vue_render__$4 = function() {
: _vm.context.model
},
on: {
blur: _vm.context.blurHandler,
change: function($event) {
var $$a = _vm.context.model,
$$el = $event.target,
@ -1427,6 +1694,7 @@ var __vue_render__$4 = function() {
checked: _vm._q(_vm.context.model, _vm.context.value)
},
on: {
blur: _vm.context.blurHandler,
change: function($event) {
return _vm.$set(_vm.context, "model", _vm.context.value)
}
@ -1455,6 +1723,7 @@ var __vue_render__$4 = function() {
value: _vm.context.model
},
on: {
blur: _vm.context.blurHandler,
input: function($event) {
if ($event.target.composing) {
return
@ -1549,6 +1818,7 @@ var __vue_render__$5 = function() {
: _vm.context.model
},
on: {
blur: _vm.context.blurHandler,
change: function($event) {
var $$a = _vm.context.model,
$$el = $event.target,
@ -1594,6 +1864,7 @@ var __vue_render__$5 = function() {
attrs: { type: "radio" },
domProps: { checked: _vm._q(_vm.context.model, null) },
on: {
blur: _vm.context.blurHandler,
change: function($event) {
return _vm.$set(_vm.context, "model", null)
}
@ -1619,6 +1890,7 @@ var __vue_render__$5 = function() {
attrs: { type: _vm.type },
domProps: { value: _vm.context.model },
on: {
blur: _vm.context.blurHandler,
input: function($event) {
if ($event.target.composing) {
return
@ -1711,6 +1983,7 @@ var __vue_render__$6 = function() {
],
attrs: { "data-placeholder-selected": _vm.placeholderSelected },
on: {
blur: _vm.context.blurHandler,
change: function($event) {
var $$selectedVal = Array.prototype.filter
.call($event.target.options, function(o) {
@ -1863,6 +2136,7 @@ var __vue_render__$7 = function() {
],
domProps: { value: _vm.context.model },
on: {
blur: _vm.context.blurHandler,
input: function($event) {
if ($event.target.composing) {
return
@ -1927,7 +2201,11 @@ var Formulate = function Formulate () {
FormulateInputTextArea: FormulateInputTextArea
},
library: library,
rules: rules
rules: rules,
locale: 'en',
locales: {
en: en
}
};
};
@ -1997,6 +2275,20 @@ Formulate.prototype.rules = function rules () {
return this.options.rules
};
/**
* Get the validation message for a particular error.
*/
Formulate.prototype.validationMessage = function validationMessage (rule, validationContext) {
var generators = this.options.locales[this.options.locale];
if (generators.hasOwnProperty(rule)) {
return generators[rule](validationContext)
}
if (generators.hasOwnProperty('default')) {
return generators.default(validationContext)
}
return 'This field does not have a valid value'
};
var Formulate$1 = new Formulate();
export default Formulate$1;

574
dist/formulate.min.js vendored
View File

@ -164,6 +164,17 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
return []
}
/**
* How to add an item.
* @param {string} item
*/
function sentence (item) {
if (typeof item === 'string') {
return item[0].toUpperCase() + item.substr(1)
}
return item
}
/**
* Given an array or string return an array of callables.
* @param {array|string} validation
@ -190,6 +201,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
return [rule, []]
}
if (Array.isArray(rule) && rule.length) {
rule = rule.map(function (r) { return r; }); // light clone
if (typeof rule[0] === 'string' && rules.hasOwnProperty(rule[0])) {
return [rules[rule.shift()], rule]
}
@ -220,88 +232,6 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
return Promise.resolve(['yes', 'on', '1', 1, true, 'true'].includes(value))
},
/**
* Rule: must be a value
*/
required: function (value, isRequired) {
if ( isRequired === void 0 ) isRequired = true;
return Promise.resolve((function () {
if (!isRequired || ['no', 'false'].includes(isRequired)) {
return true
}
if (Array.isArray(value)) {
return !!value.length
}
if (typeof value === 'string') {
return !!value
}
if (typeof value === 'object') {
return (!value) ? false : !!Object.keys(value).length
}
return true
})())
},
/**
* Rule: Value is in an array (stack).
*/
in: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(stack.find(function (item) {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) !== undefined)
},
/**
* Rule: Value is not in stack.
*/
not: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(stack.find(function (item) {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) === undefined)
},
/**
* Rule: Match the value against a (stack) of patterns or strings
*/
matches: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(!!stack.find(function (pattern) {
if (pattern instanceof RegExp) {
return pattern.test(value)
}
return pattern === value
}))
},
/**
* Rule: checks if a string is a valid url
*/
url: function (value) {
return Promise.resolve(isUrl(value))
},
/**
* Rule: ensures the value is a date according to Date.parse()
*/
date: function (value) {
return Promise.resolve(!isNaN(Date.parse(value)))
},
/**
* Rule: checks if a value is after a given date. Defaults to current time
*/
@ -313,6 +243,34 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue > timestamp))
},
/**
* Rule: checks if the value is only alpha
*/
alpha: function (value, set) {
if ( set === void 0 ) set = 'default';
var sets = {
default: /^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/,
latin: /^[a-zA-Z]+$/
};
var selectedSet = sets.hasOwnProperty(set) ? set : 'default';
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if the value is alpha numeric
*/
alphanumeric: function (value, set) {
if ( set === void 0 ) set = 'default';
var sets = {
default: /^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/,
latin: /^[a-zA-Z0-9]+$/
};
var selectedSet = sets.hasOwnProperty(set) ? set : 'default';
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if a value is after a given date. Defaults to current time
*/
@ -324,45 +282,13 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue < timestamp))
},
/**
* Rule: checks if the value is only alpha numeric
*/
alpha: function (value, set) {
if ( set === void 0 ) set = 'default';
var sets = {
default: /^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/,
latin: /^[a-z][A-Z]$/
};
var selectedSet = sets.hasOwnProperty(set) ? set : 'default';
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if the value is only alpha numeric
*/
number: function (value) {
return Promise.resolve(!isNaN(value))
},
/**
* Rule: checks if the value is alpha numeric
*/
alphanumeric: function (value, set) {
if ( set === void 0 ) set = 'default';
var sets = {
default: /^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/,
latin: /^[a-zA-Z0-9]$/
};
var selectedSet = sets.hasOwnProperty(set) ? set : 'default';
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if the value is between two other values
*/
between: function (value, from, to) {
if ( from === void 0 ) from = 0;
if ( to === void 0 ) to = 10;
return Promise.resolve((function () {
if (from === null || to === null || isNaN(from) || isNaN(to)) {
return false
@ -380,6 +306,13 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
})())
},
/**
* Rule: ensures the value is a date according to Date.parse()
*/
date: function (value) {
return Promise.resolve(!isNaN(Date.parse(value)))
},
/**
* Rule: tests
*/
@ -389,6 +322,58 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
return Promise.resolve(isEmail.test(value))
},
/**
* Rule: Value is in an array (stack).
*/
in: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(stack.find(function (item) {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) !== undefined)
},
/**
* Rule: Match the value against a (stack) of patterns or strings
*/
matches: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(!!stack.find(function (pattern) {
if (pattern instanceof RegExp) {
return pattern.test(value)
}
return pattern === value
}))
},
/**
* Check the maximum value of a particular.
*/
max: function (value, minimum) {
if ( minimum === void 0 ) minimum = 10;
return Promise.resolve((function () {
minimum = Number(minimum);
if (!isNaN(value)) {
value = Number(value);
return value <= minimum
}
if (typeof value === 'string') {
return value.length <= minimum
}
if (Array.isArray(value)) {
return value.length <= minimum
}
return false
})())
},
/**
* Check the file type is correct.
*/
@ -412,6 +397,8 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
* Check the minimum value of a particular.
*/
min: function (value, minimum) {
if ( minimum === void 0 ) minimum = 1;
return Promise.resolve((function () {
minimum = Number(minimum);
if (!isNaN(value)) {
@ -429,23 +416,243 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
},
/**
* Check the minimum value of a particular.
* Rule: Value is not in stack.
*/
max: function (value, minimum) {
return Promise.resolve((function () {
minimum = Number(minimum);
if (!isNaN(value)) {
value = Number(value);
return value <= minimum
not: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(stack.find(function (item) {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
if (typeof value === 'string') {
return value.length <= minimum
return item === value
}) === undefined)
},
/**
* Rule: checks if the value is only alpha numeric
*/
number: function (value) {
return Promise.resolve(!isNaN(value))
},
/**
* Rule: must be a value
*/
required: function (value, isRequired) {
if ( isRequired === void 0 ) isRequired = true;
return Promise.resolve((function () {
if (!isRequired || ['no', 'false'].includes(isRequired)) {
return true
}
if (Array.isArray(value)) {
return value.length <= minimum
return !!value.length
}
return false
if (typeof value === 'string') {
return !!value
}
if (typeof value === 'object') {
return (!value) ? false : !!Object.keys(value).length
}
return true
})())
},
/**
* Rule: checks if a string is a valid url
*/
url: function (value) {
return Promise.resolve(isUrl(value))
}
};
/**
* Validation error message generators.
*/
var en = {
/**
* Valid accepted value.
*/
accepted: function (ref) {
var name = ref.name;
return ("Please accept the " + name + ".")
},
/**
* The date is not after.
*/
after: function (ref) {
var name = ref.name;
var args = ref.args;
if (Array.isArray(args) && args.length) {
return ((sentence(name)) + " must be after " + (args[0]) + ".")
}
return ((sentence(name)) + " must be a later date.")
},
/**
* The value is not a letter.
*/
alpha: function (ref) {
var name = ref.name;
return ((sentence(name)) + " can only contain alphabetical characters.")
},
/**
* Rule: checks if the value is alpha numeric
*/
alphanumeric: function (ref) {
var name = ref.name;
return ((sentence(name)) + " can only contain letters and numbers.")
},
/**
* The date is not before.
*/
before: function (ref) {
var name = ref.name;
var args = ref.args;
if (Array.isArray(args) && args.length) {
return ((sentence(name)) + " must be before " + (args[0]) + ".")
}
return ((sentence(name)) + " must be an earlier date.")
},
/**
* The value is not between two numbers or lengths
*/
between: function (ref) {
var name = ref.name;
var value = ref.value;
var args = ref.args;
if (!isNaN(value)) {
return ((sentence(name)) + " must be between " + (args[0]) + " and " + (args[1]) + ".")
}
return ((sentence(name)) + " must be between " + (args[0]) + " and " + (args[1]) + " characters long.")
},
/**
* Is not a valid date.
*/
date: function (ref) {
var name = ref.name;
return ((sentence(name)) + " is not a valid date.")
},
/**
* The default render method for error messages.
*/
default: function (ref) {
var name = ref.name;
return "This field isnt valid."
},
/**
* Is not a valid email address.
*/
email: function (ref) {
var name = ref.name;
var value = ref.value;
return (value + " is not a valid email address.")
},
/**
* Value is an allowed value.
*/
in: function (ref) {
var name = ref.name;
var value = ref.value;
if (typeof value === 'string') {
return ("“" + (sentence(value)) + "” is not an allowed " + name + ".")
}
return ((sentence(name)) + " is not an allowed value.")
},
/**
* Value is not a match.
*/
matches: function (ref) {
var name = ref.name;
return ((sentence(name)) + " is not an allowed value.")
},
/**
* The maximum value allowed.
*/
max: function (ref) {
var name = ref.name;
var value = ref.value;
var args = ref.args;
if (!isNaN(value)) {
return (name + " must be less than " + (args[0]) + ".")
}
return (name + " must be less than " + (args[0]) + " characters long.")
},
/**
* The maximum value allowed.
*/
min: function (ref) {
var name = ref.name;
var value = ref.value;
var args = ref.args;
if (!isNaN(value)) {
return (name + " must be more than " + (args[0]) + ".")
}
return (name + " must be more than " + (args[0]) + " characters long.")
},
/**
* The field is not an allowed value
*/
not: function (ref) {
var name = ref.name;
var value = ref.value;
return ("“" + value + "” is not an allowed " + name + ".")
},
/**
* The field is not a number
*/
number: function (ref) {
var name = ref.name;
return ((sentence(name)) + " must be a number.")
},
/**
* Required field.
*/
required: function (ref) {
var name = ref.name;
return ((sentence(name)) + " is required.")
},
/**
* Value is not a url.
*/
url: function (ref) {
var name = ref.name;
return "Please include a valid url."
}
};
@ -456,9 +663,6 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
*/
var context = {
context: function context () {
if (this.debug) {
console.log(((this.type) + " re-context"));
}
return defineModel.call(this, Object.assign({}, {type: this.type,
value: this.value,
name: this.nameOrFallback,
@ -467,7 +671,8 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
id: this.id || this.defaultId,
label: this.label,
labelPosition: this.logicalLabelPosition,
attributes: this.elementAttributes},
attributes: this.elementAttributes,
blurHandler: blurHandler.bind(this)},
this.typeContext))
},
nameOrFallback: nameOrFallback,
@ -476,7 +681,9 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
logicalLabelPosition: logicalLabelPosition,
isVmodeled: isVmodeled,
mergedErrors: mergedErrors,
hasErrors: hasErrors
hasErrors: hasErrors,
showFieldErrors: showFieldErrors,
mergedValidationName: mergedValidationName
};
/**
@ -536,6 +743,33 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
}
}
/**
* The validation label to use.
*/
function mergedValidationName () {
if (this.validationName) {
return this.validationName
}
if (typeof this.name === 'string') {
return this.name
}
if (this.label) {
return this.label
}
return this.type
}
/**
* Determines if the field should show it's error (if it has one)
* @return {boolean}
*/
function showFieldErrors () {
if (this.showErrors) {
return this.showErrors
}
return this.behavioralErrorVisibility
}
/**
* Return the elements name, or select a fallback.
*/
@ -596,6 +830,15 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
return !!this.mergedErrors.length
}
/**
* Bound into the context object.
*/
function blurHandler () {
if (this.errorBehavior === 'blur') {
this.behavioralErrorVisibility = true;
}
}
/**
* Defines the model used throughout the existing context.
* @param {object} context
@ -639,7 +882,8 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
inheritAttrs: false,
inject: {
formulateFormSetter: { default: undefined },
formulateFormRegister: { default: undefined }
formulateFormRegister: { default: undefined },
getFormValues: { default: function () { return function () { return ({}); }; } }
},
model: {
prop: 'formulateValue',
@ -698,15 +942,23 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
type: [String, Boolean, Array],
default: false
},
validationBehavior: {
validationName: {
type: [String, Boolean],
default: false
},
error: {
type: [String, Boolean],
default: false
},
errorBehavior: {
type: String,
default: 'blur',
validator: function (value) {
return ['blur', 'live'].includes(value)
}
},
error: {
type: [String, Boolean],
showErrors: {
type: Boolean,
default: false
}
},
@ -715,6 +967,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
defaultId: nanoid(9),
localAttributes: {},
internalModelProxy: this.formulateValue,
behavioralErrorVisibility: (this.errorBehavior === 'live'),
validationErrors: []
}
},
@ -768,7 +1021,13 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
var args = ref[1];
return rule.apply(void 0, [ this$1.context.model ].concat( args ))
.then(function (res) { return res ? false : 'Validation error!'; })
.then(function (res) { return res ? false : this$1.$formulate.validationMessage(rule.name, {
args: args,
name: this$1.mergedValidationName,
value: this$1.context.model,
vm: this$1,
formValues: this$1.getFormValues()
}); })
})
)
.then(function (result) { return result.filter(function (result) { return result; }); })
@ -867,6 +1126,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
attrs: {
"data-classification": _vm.classification,
"data-has-errors": _vm.hasErrors,
"data-is-showing-errors": _vm.hasErrors && _vm.showFieldErrors,
"data-type": _vm.type
}
},
@ -929,7 +1189,9 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
})
: _vm._e(),
_vm._v(" "),
_c("FormulateInputErrors", { attrs: { errors: _vm.mergedErrors } })
_vm.showFieldErrors
? _c("FormulateInputErrors", { attrs: { errors: _vm.mergedErrors } })
: _vm._e()
],
1
)
@ -972,7 +1234,8 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
provide: function provide () {
return {
formulateFormSetter: this.setFieldValue,
formulateFormRegister: this.register
formulateFormRegister: this.register,
getFormValues: this.getFormValues
}
},
name: 'FormulateForm',
@ -1054,6 +1317,9 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
formSubmitted: function formSubmitted () {
// perform validation here
this.$emit('submit', this.formModel);
},
getFormValues: function getFormValues () {
return this.internalFormModelProxy
}
}
};
@ -1382,6 +1648,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
: _vm.context.model
},
on: {
blur: _vm.context.blurHandler,
change: function($event) {
var $$a = _vm.context.model,
$$el = $event.target,
@ -1430,6 +1697,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
checked: _vm._q(_vm.context.model, _vm.context.value)
},
on: {
blur: _vm.context.blurHandler,
change: function($event) {
return _vm.$set(_vm.context, "model", _vm.context.value)
}
@ -1458,6 +1726,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
value: _vm.context.model
},
on: {
blur: _vm.context.blurHandler,
input: function($event) {
if ($event.target.composing) {
return
@ -1552,6 +1821,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
: _vm.context.model
},
on: {
blur: _vm.context.blurHandler,
change: function($event) {
var $$a = _vm.context.model,
$$el = $event.target,
@ -1597,6 +1867,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
attrs: { type: "radio" },
domProps: { checked: _vm._q(_vm.context.model, null) },
on: {
blur: _vm.context.blurHandler,
change: function($event) {
return _vm.$set(_vm.context, "model", null)
}
@ -1622,6 +1893,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
attrs: { type: _vm.type },
domProps: { value: _vm.context.model },
on: {
blur: _vm.context.blurHandler,
input: function($event) {
if ($event.target.composing) {
return
@ -1714,6 +1986,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
],
attrs: { "data-placeholder-selected": _vm.placeholderSelected },
on: {
blur: _vm.context.blurHandler,
change: function($event) {
var $$selectedVal = Array.prototype.filter
.call($event.target.options, function(o) {
@ -1866,6 +2139,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
],
domProps: { value: _vm.context.model },
on: {
blur: _vm.context.blurHandler,
input: function($event) {
if ($event.target.composing) {
return
@ -1930,7 +2204,11 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
FormulateInputTextArea: FormulateInputTextArea
},
library: library,
rules: rules
rules: rules,
locale: 'en',
locales: {
en: en
}
};
};
@ -2000,6 +2278,20 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
return this.options.rules
};
/**
* Get the validation message for a particular error.
*/
Formulate.prototype.validationMessage = function validationMessage (rule, validationContext) {
var generators = this.options.locales[this.options.locale];
if (generators.hasOwnProperty(rule)) {
return generators[rule](validationContext)
}
if (generators.hasOwnProperty('default')) {
return generators.default(validationContext)
}
return 'This field does not have a valid value'
};
var Formulate$1 = new Formulate();
exports.default = Formulate$1;

574
dist/formulate.umd.js vendored
View File

@ -167,6 +167,17 @@
return []
}
/**
* How to add an item.
* @param {string} item
*/
function sentence (item) {
if (typeof item === 'string') {
return item[0].toUpperCase() + item.substr(1)
}
return item
}
/**
* Given an array or string return an array of callables.
* @param {array|string} validation
@ -193,6 +204,7 @@
return [rule, []]
}
if (Array.isArray(rule) && rule.length) {
rule = rule.map(function (r) { return r; }); // light clone
if (typeof rule[0] === 'string' && rules.hasOwnProperty(rule[0])) {
return [rules[rule.shift()], rule]
}
@ -223,88 +235,6 @@
return Promise.resolve(['yes', 'on', '1', 1, true, 'true'].includes(value))
},
/**
* Rule: must be a value
*/
required: function (value, isRequired) {
if ( isRequired === void 0 ) isRequired = true;
return Promise.resolve((function () {
if (!isRequired || ['no', 'false'].includes(isRequired)) {
return true
}
if (Array.isArray(value)) {
return !!value.length
}
if (typeof value === 'string') {
return !!value
}
if (typeof value === 'object') {
return (!value) ? false : !!Object.keys(value).length
}
return true
})())
},
/**
* Rule: Value is in an array (stack).
*/
in: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(stack.find(function (item) {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) !== undefined)
},
/**
* Rule: Value is not in stack.
*/
not: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(stack.find(function (item) {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) === undefined)
},
/**
* Rule: Match the value against a (stack) of patterns or strings
*/
matches: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(!!stack.find(function (pattern) {
if (pattern instanceof RegExp) {
return pattern.test(value)
}
return pattern === value
}))
},
/**
* Rule: checks if a string is a valid url
*/
url: function (value) {
return Promise.resolve(isUrl(value))
},
/**
* Rule: ensures the value is a date according to Date.parse()
*/
date: function (value) {
return Promise.resolve(!isNaN(Date.parse(value)))
},
/**
* Rule: checks if a value is after a given date. Defaults to current time
*/
@ -316,6 +246,34 @@
return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue > timestamp))
},
/**
* Rule: checks if the value is only alpha
*/
alpha: function (value, set) {
if ( set === void 0 ) set = 'default';
var sets = {
default: /^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/,
latin: /^[a-zA-Z]+$/
};
var selectedSet = sets.hasOwnProperty(set) ? set : 'default';
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if the value is alpha numeric
*/
alphanumeric: function (value, set) {
if ( set === void 0 ) set = 'default';
var sets = {
default: /^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/,
latin: /^[a-zA-Z0-9]+$/
};
var selectedSet = sets.hasOwnProperty(set) ? set : 'default';
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if a value is after a given date. Defaults to current time
*/
@ -327,45 +285,13 @@
return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue < timestamp))
},
/**
* Rule: checks if the value is only alpha numeric
*/
alpha: function (value, set) {
if ( set === void 0 ) set = 'default';
var sets = {
default: /^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/,
latin: /^[a-z][A-Z]$/
};
var selectedSet = sets.hasOwnProperty(set) ? set : 'default';
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if the value is only alpha numeric
*/
number: function (value) {
return Promise.resolve(!isNaN(value))
},
/**
* Rule: checks if the value is alpha numeric
*/
alphanumeric: function (value, set) {
if ( set === void 0 ) set = 'default';
var sets = {
default: /^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/,
latin: /^[a-zA-Z0-9]$/
};
var selectedSet = sets.hasOwnProperty(set) ? set : 'default';
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if the value is between two other values
*/
between: function (value, from, to) {
if ( from === void 0 ) from = 0;
if ( to === void 0 ) to = 10;
return Promise.resolve((function () {
if (from === null || to === null || isNaN(from) || isNaN(to)) {
return false
@ -383,6 +309,13 @@
})())
},
/**
* Rule: ensures the value is a date according to Date.parse()
*/
date: function (value) {
return Promise.resolve(!isNaN(Date.parse(value)))
},
/**
* Rule: tests
*/
@ -392,6 +325,58 @@
return Promise.resolve(isEmail.test(value))
},
/**
* Rule: Value is in an array (stack).
*/
in: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(stack.find(function (item) {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) !== undefined)
},
/**
* Rule: Match the value against a (stack) of patterns or strings
*/
matches: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(!!stack.find(function (pattern) {
if (pattern instanceof RegExp) {
return pattern.test(value)
}
return pattern === value
}))
},
/**
* Check the maximum value of a particular.
*/
max: function (value, minimum) {
if ( minimum === void 0 ) minimum = 10;
return Promise.resolve((function () {
minimum = Number(minimum);
if (!isNaN(value)) {
value = Number(value);
return value <= minimum
}
if (typeof value === 'string') {
return value.length <= minimum
}
if (Array.isArray(value)) {
return value.length <= minimum
}
return false
})())
},
/**
* Check the file type is correct.
*/
@ -415,6 +400,8 @@
* Check the minimum value of a particular.
*/
min: function (value, minimum) {
if ( minimum === void 0 ) minimum = 1;
return Promise.resolve((function () {
minimum = Number(minimum);
if (!isNaN(value)) {
@ -432,23 +419,243 @@
},
/**
* Check the minimum value of a particular.
* Rule: Value is not in stack.
*/
max: function (value, minimum) {
return Promise.resolve((function () {
minimum = Number(minimum);
if (!isNaN(value)) {
value = Number(value);
return value <= minimum
not: function (value) {
var stack = [], len = arguments.length - 1;
while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ];
return Promise.resolve(stack.find(function (item) {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
if (typeof value === 'string') {
return value.length <= minimum
return item === value
}) === undefined)
},
/**
* Rule: checks if the value is only alpha numeric
*/
number: function (value) {
return Promise.resolve(!isNaN(value))
},
/**
* Rule: must be a value
*/
required: function (value, isRequired) {
if ( isRequired === void 0 ) isRequired = true;
return Promise.resolve((function () {
if (!isRequired || ['no', 'false'].includes(isRequired)) {
return true
}
if (Array.isArray(value)) {
return value.length <= minimum
return !!value.length
}
return false
if (typeof value === 'string') {
return !!value
}
if (typeof value === 'object') {
return (!value) ? false : !!Object.keys(value).length
}
return true
})())
},
/**
* Rule: checks if a string is a valid url
*/
url: function (value) {
return Promise.resolve(isUrl(value))
}
};
/**
* Validation error message generators.
*/
var en = {
/**
* Valid accepted value.
*/
accepted: function (ref) {
var name = ref.name;
return ("Please accept the " + name + ".")
},
/**
* The date is not after.
*/
after: function (ref) {
var name = ref.name;
var args = ref.args;
if (Array.isArray(args) && args.length) {
return ((sentence(name)) + " must be after " + (args[0]) + ".")
}
return ((sentence(name)) + " must be a later date.")
},
/**
* The value is not a letter.
*/
alpha: function (ref) {
var name = ref.name;
return ((sentence(name)) + " can only contain alphabetical characters.")
},
/**
* Rule: checks if the value is alpha numeric
*/
alphanumeric: function (ref) {
var name = ref.name;
return ((sentence(name)) + " can only contain letters and numbers.")
},
/**
* The date is not before.
*/
before: function (ref) {
var name = ref.name;
var args = ref.args;
if (Array.isArray(args) && args.length) {
return ((sentence(name)) + " must be before " + (args[0]) + ".")
}
return ((sentence(name)) + " must be an earlier date.")
},
/**
* The value is not between two numbers or lengths
*/
between: function (ref) {
var name = ref.name;
var value = ref.value;
var args = ref.args;
if (!isNaN(value)) {
return ((sentence(name)) + " must be between " + (args[0]) + " and " + (args[1]) + ".")
}
return ((sentence(name)) + " must be between " + (args[0]) + " and " + (args[1]) + " characters long.")
},
/**
* Is not a valid date.
*/
date: function (ref) {
var name = ref.name;
return ((sentence(name)) + " is not a valid date.")
},
/**
* The default render method for error messages.
*/
default: function (ref) {
var name = ref.name;
return "This field isnt valid."
},
/**
* Is not a valid email address.
*/
email: function (ref) {
var name = ref.name;
var value = ref.value;
return (value + " is not a valid email address.")
},
/**
* Value is an allowed value.
*/
in: function (ref) {
var name = ref.name;
var value = ref.value;
if (typeof value === 'string') {
return ("“" + (sentence(value)) + "” is not an allowed " + name + ".")
}
return ((sentence(name)) + " is not an allowed value.")
},
/**
* Value is not a match.
*/
matches: function (ref) {
var name = ref.name;
return ((sentence(name)) + " is not an allowed value.")
},
/**
* The maximum value allowed.
*/
max: function (ref) {
var name = ref.name;
var value = ref.value;
var args = ref.args;
if (!isNaN(value)) {
return (name + " must be less than " + (args[0]) + ".")
}
return (name + " must be less than " + (args[0]) + " characters long.")
},
/**
* The maximum value allowed.
*/
min: function (ref) {
var name = ref.name;
var value = ref.value;
var args = ref.args;
if (!isNaN(value)) {
return (name + " must be more than " + (args[0]) + ".")
}
return (name + " must be more than " + (args[0]) + " characters long.")
},
/**
* The field is not an allowed value
*/
not: function (ref) {
var name = ref.name;
var value = ref.value;
return ("“" + value + "” is not an allowed " + name + ".")
},
/**
* The field is not a number
*/
number: function (ref) {
var name = ref.name;
return ((sentence(name)) + " must be a number.")
},
/**
* Required field.
*/
required: function (ref) {
var name = ref.name;
return ((sentence(name)) + " is required.")
},
/**
* Value is not a url.
*/
url: function (ref) {
var name = ref.name;
return "Please include a valid url."
}
};
@ -459,9 +666,6 @@
*/
var context = {
context: function context () {
if (this.debug) {
console.log(((this.type) + " re-context"));
}
return defineModel.call(this, Object.assign({}, {type: this.type,
value: this.value,
name: this.nameOrFallback,
@ -470,7 +674,8 @@
id: this.id || this.defaultId,
label: this.label,
labelPosition: this.logicalLabelPosition,
attributes: this.elementAttributes},
attributes: this.elementAttributes,
blurHandler: blurHandler.bind(this)},
this.typeContext))
},
nameOrFallback: nameOrFallback,
@ -479,7 +684,9 @@
logicalLabelPosition: logicalLabelPosition,
isVmodeled: isVmodeled,
mergedErrors: mergedErrors,
hasErrors: hasErrors
hasErrors: hasErrors,
showFieldErrors: showFieldErrors,
mergedValidationName: mergedValidationName
};
/**
@ -539,6 +746,33 @@
}
}
/**
* The validation label to use.
*/
function mergedValidationName () {
if (this.validationName) {
return this.validationName
}
if (typeof this.name === 'string') {
return this.name
}
if (this.label) {
return this.label
}
return this.type
}
/**
* Determines if the field should show it's error (if it has one)
* @return {boolean}
*/
function showFieldErrors () {
if (this.showErrors) {
return this.showErrors
}
return this.behavioralErrorVisibility
}
/**
* Return the elements name, or select a fallback.
*/
@ -599,6 +833,15 @@
return !!this.mergedErrors.length
}
/**
* Bound into the context object.
*/
function blurHandler () {
if (this.errorBehavior === 'blur') {
this.behavioralErrorVisibility = true;
}
}
/**
* Defines the model used throughout the existing context.
* @param {object} context
@ -642,7 +885,8 @@
inheritAttrs: false,
inject: {
formulateFormSetter: { default: undefined },
formulateFormRegister: { default: undefined }
formulateFormRegister: { default: undefined },
getFormValues: { default: function () { return function () { return ({}); }; } }
},
model: {
prop: 'formulateValue',
@ -701,15 +945,23 @@
type: [String, Boolean, Array],
default: false
},
validationBehavior: {
validationName: {
type: [String, Boolean],
default: false
},
error: {
type: [String, Boolean],
default: false
},
errorBehavior: {
type: String,
default: 'blur',
validator: function (value) {
return ['blur', 'live'].includes(value)
}
},
error: {
type: [String, Boolean],
showErrors: {
type: Boolean,
default: false
}
},
@ -718,6 +970,7 @@
defaultId: nanoid(9),
localAttributes: {},
internalModelProxy: this.formulateValue,
behavioralErrorVisibility: (this.errorBehavior === 'live'),
validationErrors: []
}
},
@ -771,7 +1024,13 @@
var args = ref[1];
return rule.apply(void 0, [ this$1.context.model ].concat( args ))
.then(function (res) { return res ? false : 'Validation error!'; })
.then(function (res) { return res ? false : this$1.$formulate.validationMessage(rule.name, {
args: args,
name: this$1.mergedValidationName,
value: this$1.context.model,
vm: this$1,
formValues: this$1.getFormValues()
}); })
})
)
.then(function (result) { return result.filter(function (result) { return result; }); })
@ -870,6 +1129,7 @@
attrs: {
"data-classification": _vm.classification,
"data-has-errors": _vm.hasErrors,
"data-is-showing-errors": _vm.hasErrors && _vm.showFieldErrors,
"data-type": _vm.type
}
},
@ -932,7 +1192,9 @@
})
: _vm._e(),
_vm._v(" "),
_c("FormulateInputErrors", { attrs: { errors: _vm.mergedErrors } })
_vm.showFieldErrors
? _c("FormulateInputErrors", { attrs: { errors: _vm.mergedErrors } })
: _vm._e()
],
1
)
@ -975,7 +1237,8 @@
provide: function provide () {
return {
formulateFormSetter: this.setFieldValue,
formulateFormRegister: this.register
formulateFormRegister: this.register,
getFormValues: this.getFormValues
}
},
name: 'FormulateForm',
@ -1057,6 +1320,9 @@
formSubmitted: function formSubmitted () {
// perform validation here
this.$emit('submit', this.formModel);
},
getFormValues: function getFormValues () {
return this.internalFormModelProxy
}
}
};
@ -1385,6 +1651,7 @@
: _vm.context.model
},
on: {
blur: _vm.context.blurHandler,
change: function($event) {
var $$a = _vm.context.model,
$$el = $event.target,
@ -1433,6 +1700,7 @@
checked: _vm._q(_vm.context.model, _vm.context.value)
},
on: {
blur: _vm.context.blurHandler,
change: function($event) {
return _vm.$set(_vm.context, "model", _vm.context.value)
}
@ -1461,6 +1729,7 @@
value: _vm.context.model
},
on: {
blur: _vm.context.blurHandler,
input: function($event) {
if ($event.target.composing) {
return
@ -1555,6 +1824,7 @@
: _vm.context.model
},
on: {
blur: _vm.context.blurHandler,
change: function($event) {
var $$a = _vm.context.model,
$$el = $event.target,
@ -1600,6 +1870,7 @@
attrs: { type: "radio" },
domProps: { checked: _vm._q(_vm.context.model, null) },
on: {
blur: _vm.context.blurHandler,
change: function($event) {
return _vm.$set(_vm.context, "model", null)
}
@ -1625,6 +1896,7 @@
attrs: { type: _vm.type },
domProps: { value: _vm.context.model },
on: {
blur: _vm.context.blurHandler,
input: function($event) {
if ($event.target.composing) {
return
@ -1717,6 +1989,7 @@
],
attrs: { "data-placeholder-selected": _vm.placeholderSelected },
on: {
blur: _vm.context.blurHandler,
change: function($event) {
var $$selectedVal = Array.prototype.filter
.call($event.target.options, function(o) {
@ -1869,6 +2142,7 @@
],
domProps: { value: _vm.context.model },
on: {
blur: _vm.context.blurHandler,
input: function($event) {
if ($event.target.composing) {
return
@ -1933,7 +2207,11 @@
FormulateInputTextArea: FormulateInputTextArea
},
library: library,
rules: rules
rules: rules,
locale: 'en',
locales: {
en: en
}
};
};
@ -2003,6 +2281,20 @@
return this.options.rules
};
/**
* Get the validation message for a particular error.
*/
Formulate.prototype.validationMessage = function validationMessage (rule, validationContext) {
var generators = this.options.locales[this.options.locale];
if (generators.hasOwnProperty(rule)) {
return generators[rule](validationContext)
}
if (generators.hasOwnProperty('default')) {
return generators.default(validationContext)
}
return 'This field does not have a valid value'
};
var Formulate$1 = new Formulate();
exports.default = Formulate$1;

View File

@ -1,5 +1,6 @@
import library from './libs/library'
import rules from './libs/rules'
import en from './locales/en'
import isPlainObject from 'is-plain-object'
import FormulateInput from './FormulateInput.vue'
import FormulateForm from './FormulateForm.vue'
@ -30,7 +31,11 @@ class Formulate {
FormulateInputTextArea
},
library,
rules
rules,
locale: 'en',
locales: {
en
}
}
}
@ -99,6 +104,20 @@ class Formulate {
rules () {
return this.options.rules
}
/**
* Get the validation message for a particular error.
*/
validationMessage (rule, validationContext) {
const generators = this.options.locales[this.options.locale]
if (generators.hasOwnProperty(rule)) {
return generators[rule](validationContext)
}
if (generators.hasOwnProperty('default')) {
return generators.default(validationContext)
}
return 'This field does not have a valid value'
}
}
export default new Formulate()

View File

@ -13,7 +13,8 @@ export default {
provide () {
return {
formulateFormSetter: this.setFieldValue,
formulateFormRegister: this.register
formulateFormRegister: this.register,
getFormValues: this.getFormValues
}
},
name: 'FormulateForm',
@ -93,6 +94,9 @@ export default {
formSubmitted () {
// perform validation here
this.$emit('submit', this.formModel)
},
getFormValues () {
return this.internalFormModelProxy
}
}
}

View File

@ -3,6 +3,7 @@
class="formulate-input"
:data-classification="classification"
:data-has-errors="hasErrors"
:data-is-showing-errors="hasErrors && showFieldErrors"
:data-type="type"
>
<div class="formulate-input-wrapper">
@ -41,6 +42,7 @@
v-text="help"
/>
<FormulateInputErrors
v-if="showFieldErrors"
:errors="mergedErrors"
/>
</div>
@ -56,7 +58,8 @@ export default {
inheritAttrs: false,
inject: {
formulateFormSetter: { default: undefined },
formulateFormRegister: { default: undefined }
formulateFormRegister: { default: undefined },
getFormValues: { default: () => () => ({}) }
},
model: {
prop: 'formulateValue',
@ -115,15 +118,23 @@ export default {
type: [String, Boolean, Array],
default: false
},
validationBehavior: {
validationName: {
type: [String, Boolean],
default: false
},
error: {
type: [String, Boolean],
default: false
},
errorBehavior: {
type: String,
default: 'blur',
validator: function (value) {
return ['blur', 'live'].includes(value)
}
},
error: {
type: [String, Boolean],
showErrors: {
type: Boolean,
default: false
}
},
@ -132,6 +143,7 @@ export default {
defaultId: nanoid(9),
localAttributes: {},
internalModelProxy: this.formulateValue,
behavioralErrorVisibility: (this.errorBehavior === 'live'),
validationErrors: []
}
},
@ -182,7 +194,13 @@ export default {
Promise.all(
rules.map(([rule, args]) => {
return rule(this.context.model, ...args)
.then(res => res ? false : 'Validation error!')
.then(res => res ? false : this.$formulate.validationMessage(rule.name, {
args,
name: this.mergedValidationName,
value: this.context.model,
vm: this,
formValues: this.getFormValues()
}))
})
)
.then(result => result.filter(result => result))

View File

@ -8,6 +8,7 @@
:type="type"
:value="context.value"
v-bind="attributes"
@blur="context.blurHandler"
>
<label
class="formulate-input-element-decorator"

View File

@ -6,6 +6,7 @@
v-model="context.model"
v-bind="attributes"
:data-placeholder-selected="placeholderSelected"
@blur="context.blurHandler"
>
<option
v-if="context.placeholder"

View File

@ -6,6 +6,7 @@
v-model="context.model"
:type="type"
v-bind="attributes"
@blur="context.blurHandler"
>
</div>
</template>

View File

@ -5,6 +5,7 @@
<textarea
v-model="context.model"
v-bind="attributes"
@blur="context.blurHandler"
/>
</div>
</template>

View File

@ -8,9 +8,6 @@ import { map, arrayify } from './utils'
*/
export default {
context () {
if (this.debug) {
console.log(`${this.type} re-context`)
}
return defineModel.call(this, {
type: this.type,
value: this.value,
@ -21,6 +18,7 @@ export default {
label: this.label,
labelPosition: this.logicalLabelPosition,
attributes: this.elementAttributes,
blurHandler: blurHandler.bind(this),
...this.typeContext
})
},
@ -30,7 +28,9 @@ export default {
logicalLabelPosition,
isVmodeled,
mergedErrors,
hasErrors
hasErrors,
showFieldErrors,
mergedValidationName
}
/**
@ -88,6 +88,33 @@ function logicalLabelPosition () {
}
}
/**
* The validation label to use.
*/
function mergedValidationName () {
if (this.validationName) {
return this.validationName
}
if (typeof this.name === 'string') {
return this.name
}
if (this.label) {
return this.label
}
return this.type
}
/**
* Determines if the field should show it's error (if it has one)
* @return {boolean}
*/
function showFieldErrors () {
if (this.showErrors) {
return this.showErrors
}
return this.behavioralErrorVisibility
}
/**
* Return the elements name, or select a fallback.
*/
@ -148,6 +175,15 @@ function hasErrors () {
return !!this.mergedErrors.length
}
/**
* Bound into the context object.
*/
function blurHandler () {
if (this.errorBehavior === 'blur') {
this.behavioralErrorVisibility = true
}
}
/**
* Defines the model used throughout the existing context.
* @param {object} context

View File

@ -12,6 +12,184 @@ export default {
return Promise.resolve(['yes', 'on', '1', 1, true, 'true'].includes(value))
},
/**
* Rule: checks if a value is after a given date. Defaults to current time
*/
after: function (value, compare = false) {
const timestamp = Date.parse(compare || new Date())
const fieldValue = Date.parse(value)
return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue > timestamp))
},
/**
* Rule: checks if the value is only alpha
*/
alpha: function (value, set = 'default') {
const sets = {
default: /^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/,
latin: /^[a-zA-Z]+$/
}
const selectedSet = sets.hasOwnProperty(set) ? set : 'default'
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if the value is alpha numeric
*/
alphanumeric: function (value, set = 'default') {
const sets = {
default: /^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/,
latin: /^[a-zA-Z0-9]+$/
}
const selectedSet = sets.hasOwnProperty(set) ? set : 'default'
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if a value is after a given date. Defaults to current time
*/
before: function (value, compare = false) {
const timestamp = Date.parse(compare || new Date())
const fieldValue = Date.parse(value)
return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue < timestamp))
},
/**
* Rule: checks if the value is between two other values
*/
between: function (value, from = 0, to = 10) {
return Promise.resolve((() => {
if (from === null || to === null || isNaN(from) || isNaN(to)) {
return false
}
from = Number(from)
to = Number(to)
if (!isNaN(value)) {
value = Number(value)
return (value > from && value < to)
}
if (typeof value === 'string') {
return value.length > from && value.length < to
}
return false
})())
},
/**
* Rule: ensures the value is a date according to Date.parse()
*/
date: function (value) {
return Promise.resolve(!isNaN(Date.parse(value)))
},
/**
* Rule: tests
*/
email: function (value) {
// eslint-disable-next-line
const isEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i
return Promise.resolve(isEmail.test(value))
},
/**
* Rule: Value is in an array (stack).
*/
in: function (value, ...stack) {
return Promise.resolve(stack.find(item => {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) !== undefined)
},
/**
* Rule: Match the value against a (stack) of patterns or strings
*/
matches: function (value, ...stack) {
return Promise.resolve(!!stack.find(pattern => {
if (pattern instanceof RegExp) {
return pattern.test(value)
}
return pattern === value
}))
},
/**
* Check the maximum value of a particular.
*/
max: function (value, minimum = 10) {
return Promise.resolve((() => {
minimum = Number(minimum)
if (!isNaN(value)) {
value = Number(value)
return value <= minimum
}
if (typeof value === 'string') {
return value.length <= minimum
}
if (Array.isArray(value)) {
return value.length <= minimum
}
return false
})())
},
/**
* Check the file type is correct.
*/
mime: function (files, ...types) {
return Promise.resolve((() => {
if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') {
for (const i in files) {
if (!types.includes(files[i].type)) {
return false
}
}
}
return true
})())
},
/**
* Check the minimum value of a particular.
*/
min: function (value, minimum = 1) {
return Promise.resolve((() => {
minimum = Number(minimum)
if (!isNaN(value)) {
value = Number(value)
return value >= minimum
}
if (typeof value === 'string') {
return value.length >= minimum
}
if (Array.isArray(value)) {
return value.length >= minimum
}
return false
})())
},
/**
* Rule: Value is not in stack.
*/
not: function (value, ...stack) {
return Promise.resolve(stack.find(item => {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) === undefined)
},
/**
* Rule: checks if the value is only alpha numeric
*/
number: function (value) {
return Promise.resolve(!isNaN(value))
},
/**
* Rule: must be a value
*/
@ -33,188 +211,10 @@ export default {
})())
},
/**
* Rule: Value is in an array (stack).
*/
in: function (value, ...stack) {
return Promise.resolve(stack.find(item => {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) !== undefined)
},
/**
* Rule: Value is not in stack.
*/
not: function (value, ...stack) {
return Promise.resolve(stack.find(item => {
if (typeof item === 'object') {
return shallowEqualObjects(item, value)
}
return item === value
}) === undefined)
},
/**
* Rule: Match the value against a (stack) of patterns or strings
*/
matches: function (value, ...stack) {
return Promise.resolve(!!stack.find(pattern => {
if (pattern instanceof RegExp) {
return pattern.test(value)
}
return pattern === value
}))
},
/**
* Rule: checks if a string is a valid url
*/
url: function (value) {
return Promise.resolve(isUrl(value))
},
/**
* Rule: ensures the value is a date according to Date.parse()
*/
date: function (value) {
return Promise.resolve(!isNaN(Date.parse(value)))
},
/**
* Rule: checks if a value is after a given date. Defaults to current time
*/
after: function (value, compare = false) {
const timestamp = Date.parse(compare || new Date())
const fieldValue = Date.parse(value)
return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue > timestamp))
},
/**
* Rule: checks if a value is after a given date. Defaults to current time
*/
before: function (value, compare = false) {
const timestamp = Date.parse(compare || new Date())
const fieldValue = Date.parse(value)
return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue < timestamp))
},
/**
* Rule: checks if the value is only alpha numeric
*/
alpha: function (value, set = 'default') {
const sets = {
default: /^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/,
latin: /^[a-z][A-Z]$/
}
const selectedSet = sets.hasOwnProperty(set) ? set : 'default'
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if the value is only alpha numeric
*/
number: function (value) {
return Promise.resolve(!isNaN(value))
},
/**
* Rule: checks if the value is alpha numeric
*/
alphanumeric: function (value, set = 'default') {
const sets = {
default: /^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/,
latin: /^[a-zA-Z0-9]$/
}
const selectedSet = sets.hasOwnProperty(set) ? set : 'default'
return Promise.resolve(sets[selectedSet].test(value))
},
/**
* Rule: checks if the value is between two other values
*/
between: function (value, from, to) {
return Promise.resolve((() => {
if (from === null || to === null || isNaN(from) || isNaN(to)) {
return false
}
from = Number(from)
to = Number(to)
if (!isNaN(value)) {
value = Number(value)
return (value > from && value < to)
}
if (typeof value === 'string') {
return value.length > from && value.length < to
}
return false
})())
},
/**
* Rule: tests
*/
email: function (value) {
// eslint-disable-next-line
const isEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i
return Promise.resolve(isEmail.test(value))
},
/**
* Check the file type is correct.
*/
mime: function (files, ...types) {
return Promise.resolve((() => {
if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') {
for (const i in files) {
if (!types.includes(files[i].type)) {
return false
}
}
}
return true
})())
},
/**
* Check the minimum value of a particular.
*/
min: function (value, minimum) {
return Promise.resolve((() => {
minimum = Number(minimum)
if (!isNaN(value)) {
value = Number(value)
return value >= minimum
}
if (typeof value === 'string') {
return value.length >= minimum
}
if (Array.isArray(value)) {
return value.length >= minimum
}
return false
})())
},
/**
* Check the minimum value of a particular.
*/
max: function (value, minimum) {
return Promise.resolve((() => {
minimum = Number(minimum)
if (!isNaN(value)) {
value = Number(value)
return value <= minimum
}
if (typeof value === 'string') {
return value.length <= minimum
}
if (Array.isArray(value)) {
return value.length <= minimum
}
return false
})())
}
}

View File

@ -1,4 +1,3 @@
/**
* Function to map over an object.
* @param {Object} obj An object to map over
@ -90,6 +89,17 @@ export function arrayify (item) {
return []
}
/**
* How to add an item.
* @param {string} item
*/
export function sentence (item) {
if (typeof item === 'string') {
return item[0].toUpperCase() + item.substr(1)
}
return item
}
/**
* Given an array or string return an array of callables.
* @param {array|string} validation
@ -116,6 +126,7 @@ function parseRule (rule, rules) {
return [rule, []]
}
if (Array.isArray(rule) && rule.length) {
rule = rule.map(r => r) // light clone
if (typeof rule[0] === 'string' && rules.hasOwnProperty(rule[0])) {
return [rules[rule.shift()], rule]
}

143
src/locales/en.js Normal file
View File

@ -0,0 +1,143 @@
import { sentence as s } from '../libs/utils'
/**
* Validation error message generators.
*/
export default {
/**
* Valid accepted value.
*/
accepted: function ({ name }) {
return `Please accept the ${name}.`
},
/**
* The date is not after.
*/
after: function ({ name, args }) {
if (Array.isArray(args) && args.length) {
return `${s(name)} must be after ${args[0]}.`
}
return `${s(name)} must be a later date.`
},
/**
* The value is not a letter.
*/
alpha: function ({ name }) {
return `${s(name)} can only contain alphabetical characters.`
},
/**
* Rule: checks if the value is alpha numeric
*/
alphanumeric: function ({ name }) {
return `${s(name)} can only contain letters and numbers.`
},
/**
* The date is not before.
*/
before: function ({ name, args }) {
if (Array.isArray(args) && args.length) {
return `${s(name)} must be before ${args[0]}.`
}
return `${s(name)} must be an earlier date.`
},
/**
* The value is not between two numbers or lengths
*/
between: function ({ name, value, args }) {
if (!isNaN(value)) {
return `${s(name)} must be between ${args[0]} and ${args[1]}.`
}
return `${s(name)} must be between ${args[0]} and ${args[1]} characters long.`
},
/**
* Is not a valid date.
*/
date: function ({ name }) {
return `${s(name)} is not a valid date.`
},
/**
* The default render method for error messages.
*/
default: function ({ name }) {
return `This field isnt valid.`
},
/**
* Is not a valid email address.
*/
email: function ({ name, value }) {
return `${value} is not a valid email address.`
},
/**
* Value is an allowed value.
*/
in: function ({ name, value }) {
if (typeof value === 'string') {
return `${s(value)}” is not an allowed ${name}.`
}
return `${s(name)} is not an allowed value.`
},
/**
* Value is not a match.
*/
matches: function ({ name }) {
return `${s(name)} is not an allowed value.`
},
/**
* The maximum value allowed.
*/
max: function ({ name, value, args }) {
if (!isNaN(value)) {
return `${name} must be less than ${args[0]}.`
}
return `${name} must be less than ${args[0]} characters long.`
},
/**
* The maximum value allowed.
*/
min: function ({ name, value, args }) {
if (!isNaN(value)) {
return `${name} must be more than ${args[0]}.`
}
return `${name} must be more than ${args[0]} characters long.`
},
/**
* The field is not an allowed value
*/
not: function ({ name, value }) {
return `${value}” is not an allowed ${name}.`
},
/**
* The field is not a number
*/
number: function ({ name }) {
return `${s(name)} must be a number.`
},
/**
* Required field.
*/
required: function ({ name }) {
return `${s(name)} is required.`
},
/**
* Value is not a url.
*/
url: function ({ name }) {
return `Please include a valid url.`
}
}

View File

@ -165,22 +165,49 @@ describe('FormulateInputText', () => {
})
it('accepts a single string as an error prop', () => {
const wrapper = mount(FormulateInput, { propsData: { type: 'text', error: 'This is an error' } })
const wrapper = mount(FormulateInput, { propsData: { type: 'text', errorBehavior: 'live', error: 'This is an error' } })
expect(wrapper.find('.formulate-input-errors').exists()).toBe(true)
})
it('accepts an array as errors prop', () => {
const wrapper = mount(FormulateInput, { propsData: { type: 'text', errors: ['This is an error', 'this is another'] } })
const wrapper = mount(FormulateInput, { propsData: { type: 'text', errorBehavior: 'live', errors: ['This is an error', 'this is another'] } })
expect(wrapper.findAll('.formulate-input-error').length).toBe(2)
})
it('removes any duplicate errors', () => {
const wrapper = mount(FormulateInput, { propsData: { type: 'text', errors: ['This is an error', 'This is an error'] } })
const wrapper = mount(FormulateInput, { propsData: { type: 'text', errorBehavior: 'live', errors: ['This is an error', 'This is an error'] } })
expect(wrapper.findAll('.formulate-input-error').length).toBe(1)
})
it('adds data-has-errors when there are errors', () => {
const wrapper = mount(FormulateInput, { propsData: { type: 'text', errors: ['This is an error', 'This is an error'] } })
const wrapper = mount(FormulateInput, { propsData: { type: 'text', errorBehavior: 'live', errors: ['This is an error', 'This is an error'] } })
expect(wrapper.find('[data-has-errors]').exists()).toBe(true)
})
it('does not initially show error-behavior blur errors', () => {
const wrapper = mount(FormulateInput, { propsData: { type: 'text', errorBehavior: 'blur', errors: ['Bad input'] } })
expect(wrapper.find('[data-has-errors]').exists()).toBe(true)
expect(wrapper.find('[data-is-showing-errors]').exists()).toBe(false)
expect(wrapper.findAll('.formulate-input-errors').exists()).toBe(false)
})
it('allows error-behavior blur to be overridden with show-errors', () => {
const wrapper = mount(FormulateInput, { propsData: { type: 'text', errorBehavior: 'blur', showErrors: true, errors: ['Bad input'] } })
expect(wrapper.find('[data-has-errors]').exists()).toBe(true)
expect(wrapper.find('[data-is-showing-errors]').exists()).toBe(true)
expect(wrapper.findAll('.formulate-input-errors').exists()).toBe(true)
expect(wrapper.findAll('.formulate-input-error').length).toBe(1)
})
it('shows errors on blur with error-behavior blur', () => {
const wrapper = mount(FormulateInput, { propsData: { type: 'text', errorBehavior: 'blur', errors: ['Bad input'] } })
expect(wrapper.find('[data-has-errors]').exists()).toBe(true)
expect(wrapper.find('[data-is-showing-errors]').exists()).toBe(false)
expect(wrapper.findAll('.formulate-input-errors').exists()).toBe(false)
wrapper.find('input').trigger('blur')
expect(wrapper.find('[data-is-showing-errors]').exists()).toBe(true)
expect(wrapper.findAll('.formulate-input-errors').exists()).toBe(true)
expect(wrapper.findAll('.formulate-input-error').length).toBe(1)
})
})