style: Addition of the eslint rules
This commit is contained in:
parent
095f406fea
commit
acb6357433
60
.eslintrc.js
60
.eslintrc.js
@ -1,22 +1,42 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint',
|
||||
sourceType: 'module'
|
||||
},
|
||||
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
|
||||
extends: [
|
||||
'standard',
|
||||
'plugin:vue/recommended'
|
||||
],
|
||||
env: {
|
||||
browser: true,
|
||||
},
|
||||
// add your custom rules here
|
||||
'rules': {
|
||||
// allow paren-less arrow functions
|
||||
'arrow-parens': 0,
|
||||
// allow debugger during development
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
|
||||
}
|
||||
root: true,
|
||||
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint',
|
||||
sourceType: 'module',
|
||||
},
|
||||
|
||||
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
|
||||
extends: [
|
||||
'standard',
|
||||
'@vue/standard',
|
||||
'plugin:vue/recommended',
|
||||
],
|
||||
|
||||
env: {
|
||||
browser: true,
|
||||
},
|
||||
|
||||
rules: {
|
||||
// allow paren-less arrow functions
|
||||
'arrow-parens': 0,
|
||||
'comma-dangle': ['error', 'only-multiline'],
|
||||
'indent': ['error', 4],
|
||||
'max-depth': ['error', 3],
|
||||
'max-lines-per-function': ['error', 40],
|
||||
'no-console': ['warn', {allow: ['warn', 'error']}],
|
||||
// allow debugger during development
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
||||
'vue/html-closing-bracket-spacing': ['error', {
|
||||
startTag: 'never',
|
||||
endTag: 'never',
|
||||
selfClosingTag: 'always',
|
||||
}],
|
||||
'vue/html-indent': ['error', 4, {
|
||||
attribute: 1,
|
||||
closeBracket: 0,
|
||||
alignAttributesVertically: true,
|
||||
ignores: [],
|
||||
}],
|
||||
},
|
||||
}
|
||||
|
@ -5,30 +5,30 @@ import vue from 'rollup-plugin-vue' // Handle .vue SFC files
|
||||
import { terser } from 'rollup-plugin-terser'
|
||||
|
||||
export default {
|
||||
input: 'src/Formulario.js', // Path relative to package.json
|
||||
output: [
|
||||
{
|
||||
name: 'Formulario',
|
||||
exports: 'default',
|
||||
globals: {
|
||||
'is-plain-object': 'isPlainObject',
|
||||
'nanoid/non-secure': 'nanoid',
|
||||
'is-url': 'isUrl',
|
||||
},
|
||||
sourcemap: false
|
||||
}
|
||||
],
|
||||
external: ['nanoid/non-secure'],
|
||||
plugins: [
|
||||
commonjs(),
|
||||
autoExternal(),
|
||||
vue({
|
||||
css: true, // Dynamically inject css as a <style> tag
|
||||
compileTemplate: true // Explicitly convert template to render function
|
||||
}),
|
||||
buble({
|
||||
objectAssign: 'Object.assign'
|
||||
}), // Transpile to ES5,
|
||||
terser()
|
||||
]
|
||||
input: 'src/Formulario.js', // Path relative to package.json
|
||||
output: [
|
||||
{
|
||||
name: 'Formulario',
|
||||
exports: 'default',
|
||||
globals: {
|
||||
'is-plain-object': 'isPlainObject',
|
||||
'nanoid/non-secure': 'nanoid',
|
||||
'is-url': 'isUrl',
|
||||
},
|
||||
sourcemap: false
|
||||
}
|
||||
],
|
||||
external: ['nanoid/non-secure'],
|
||||
plugins: [
|
||||
commonjs(),
|
||||
autoExternal(),
|
||||
vue({
|
||||
css: true, // Dynamically inject css as a <style> tag
|
||||
compileTemplate: true // Explicitly convert template to render function
|
||||
}),
|
||||
buble({
|
||||
objectAssign: 'Object.assign'
|
||||
}), // Transpile to ES5,
|
||||
terser()
|
||||
]
|
||||
}
|
||||
|
@ -6,31 +6,31 @@ import internal from 'rollup-plugin-internal'
|
||||
import { terser } from 'rollup-plugin-terser'
|
||||
|
||||
export default {
|
||||
input: 'src/Formulario.js', // Path relative to package.json
|
||||
output: {
|
||||
name: 'VueFormulario',
|
||||
exports: 'default',
|
||||
format: 'iife',
|
||||
globals: {
|
||||
'is-plain-object': 'isPlainObject',
|
||||
'nanoid/non-secure': 'nanoid',
|
||||
'is-url': 'isUrl',
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
resolve({
|
||||
browser: true,
|
||||
preferBuiltins: false
|
||||
}),
|
||||
commonjs(),
|
||||
internal(['is-plain-object', 'nanoid/non-secure', 'is-url']),
|
||||
vue({
|
||||
css: true, // Dynamically inject css as a <style> tag
|
||||
compileTemplate: true // Explicitly convert template to render function
|
||||
}),
|
||||
buble({
|
||||
objectAssign: 'Object.assign'
|
||||
}), // Transpile to ES5,
|
||||
terser()
|
||||
]
|
||||
input: 'src/Formulario.js', // Path relative to package.json
|
||||
output: {
|
||||
name: 'VueFormulario',
|
||||
exports: 'default',
|
||||
format: 'iife',
|
||||
globals: {
|
||||
'is-plain-object': 'isPlainObject',
|
||||
'nanoid/non-secure': 'nanoid',
|
||||
'is-url': 'isUrl',
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
resolve({
|
||||
browser: true,
|
||||
preferBuiltins: false
|
||||
}),
|
||||
commonjs(),
|
||||
internal(['is-plain-object', 'nanoid/non-secure', 'is-url']),
|
||||
vue({
|
||||
css: true, // Dynamically inject css as a <style> tag
|
||||
compileTemplate: true // Explicitly convert template to render function
|
||||
}),
|
||||
buble({
|
||||
objectAssign: 'Object.assign'
|
||||
}), // Transpile to ES5,
|
||||
terser()
|
||||
]
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<div
|
||||
id="app"
|
||||
class="specimen-list"
|
||||
>
|
||||
<SpecimenButton />
|
||||
<SpecimenBox />
|
||||
<SpecimenFile />
|
||||
<SpecimenGroup />
|
||||
<SpecimenSelect />
|
||||
<SpecimenSlider />
|
||||
<SpecimenText />
|
||||
<SpecimenTextarea />
|
||||
</div>
|
||||
<div
|
||||
id="app"
|
||||
class="specimen-list"
|
||||
>
|
||||
<SpecimenButton />
|
||||
<SpecimenBox />
|
||||
<SpecimenFile />
|
||||
<SpecimenGroup />
|
||||
<SpecimenSelect />
|
||||
<SpecimenSlider />
|
||||
<SpecimenText />
|
||||
<SpecimenTextarea />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -25,82 +25,85 @@ import SpecimenSlider from './specimens/SpecimenSlider'
|
||||
import SpecimenSelect from './specimens/SpecimenSelect'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
SpecimenButton,
|
||||
SpecimenBox,
|
||||
SpecimenText,
|
||||
SpecimenTextarea,
|
||||
SpecimenGroup,
|
||||
SpecimenFile,
|
||||
SpecimenSlider,
|
||||
SpecimenSelect
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
name: 'App',
|
||||
|
||||
components: {
|
||||
SpecimenButton,
|
||||
SpecimenBox,
|
||||
SpecimenText,
|
||||
SpecimenTextarea,
|
||||
SpecimenGroup,
|
||||
SpecimenFile,
|
||||
SpecimenSlider,
|
||||
SpecimenSelect,
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: $formulate-font-stack;
|
||||
}
|
||||
h2 {
|
||||
display: block;
|
||||
width: 100%;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: white;
|
||||
padding: .5em 0;
|
||||
color: $formulate-green;
|
||||
border-bottom: 1px solid $formulate-gray;
|
||||
margin: 2em 0 0 0;
|
||||
z-index: 10;
|
||||
}
|
||||
.specimen-list {
|
||||
padding: 1em;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
@media (min-width: 756px) {
|
||||
padding: 2em;
|
||||
}
|
||||
$formulate-font-stack: Arial, sans-serif;
|
||||
$formulate-gray: gray;
|
||||
$formulate-green: green;
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: $formulate-font-stack;
|
||||
}
|
||||
|
||||
h2 {
|
||||
display: block;
|
||||
width: 100%;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: white;
|
||||
padding: .5em 0;
|
||||
color: $formulate-green;
|
||||
border-bottom: 1px solid $formulate-gray;
|
||||
margin: 2em 0 0 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.specimen-list {
|
||||
padding: 1em;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
@media (min-width: 756px) {
|
||||
padding: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.specimens {
|
||||
@media (min-width: 500px) {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
&:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
@media (min-width: 500px) {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
&:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.specimen {
|
||||
max-width: 400px;
|
||||
padding: 1em;
|
||||
box-sizing: border-box;
|
||||
max-width: 400px;
|
||||
padding: 1em;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media (min-width: 500px) {
|
||||
width: 50%;
|
||||
border-bottom: 1px solid $formulate-gray;
|
||||
&:nth-of-type(odd) {
|
||||
border-right: 1px solid $formulate-gray;
|
||||
@media (min-width: 500px) {
|
||||
width: 50%;
|
||||
border-bottom: 1px solid $formulate-gray;
|
||||
&:nth-of-type(odd) {
|
||||
border-right: 1px solid $formulate-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 900px) {
|
||||
width: 33.332%;
|
||||
border-right: 1px solid $formulate-gray;
|
||||
@media (min-width: 900px) {
|
||||
width: 33.332%;
|
||||
border-right: 1px solid $formulate-gray;
|
||||
|
||||
&:nth-of-type(3n) {
|
||||
border-right: 0;
|
||||
&:nth-of-type(3n) {
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,11 +1,10 @@
|
||||
import Vue from 'vue'
|
||||
import VueFormulate from '../src/Formulate'
|
||||
import VueFormulario from '../src/Formulario'
|
||||
import FormulateSpecimens from './FormulateSpecimens.vue'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
Vue.use(VueFormulate)
|
||||
Vue.use(VueFormulario)
|
||||
|
||||
new Vue({
|
||||
render: h => h(FormulateSpecimens)
|
||||
render: h => h(FormulateSpecimens)
|
||||
}).$mount('#app')
|
||||
|
@ -1,30 +1,30 @@
|
||||
<template>
|
||||
<div class="specimens specimens--text">
|
||||
<h2>Box classification</h2>
|
||||
<div class="specimen">
|
||||
<h3>Single Checkbox</h3>
|
||||
<FormulateInput
|
||||
type="checkbox"
|
||||
label="Are you attractive?"
|
||||
help="In your own opinion at least."
|
||||
/>
|
||||
<div class="specimens specimens--text">
|
||||
<h2>Box classification</h2>
|
||||
<div class="specimen">
|
||||
<h3>Single Checkbox</h3>
|
||||
<FormulateInput
|
||||
type="checkbox"
|
||||
label="Are you attractive?"
|
||||
help="In your own opinion at least."
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Multi checkbox</h3>
|
||||
<FormulateInput
|
||||
type="checkbox"
|
||||
label="Which recent U.S. president is your favorite?"
|
||||
:options="{trump: 'Trump', obama: 'Obama', bush: 'Bush', clinton: 'Clinton'}"
|
||||
help="Your selection will be transmitted directly to the NSA."
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Radio</h3>
|
||||
<FormulateInput
|
||||
type="radio"
|
||||
label="What heavily body would you like to visit?"
|
||||
:options="{moon: 'Moon', mars: 'Mars', venus: 'Venus', mercury: 'Mercury', sun: 'Sun'}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Multi checkbox</h3>
|
||||
<FormulateInput
|
||||
type="checkbox"
|
||||
label="Which recent U.S. president is your favorite?"
|
||||
:options="{trump: 'Trump', obama: 'Obama', bush: 'Bush', clinton: 'Clinton'}"
|
||||
help="Your selection will be transmitted directly to the NSA."
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Radio</h3>
|
||||
<FormulateInput
|
||||
type="radio"
|
||||
label="What heavily body would you like to visit?"
|
||||
:options="{moon: 'Moon', mars: 'Mars', venus: 'Venus', mercury: 'Mercury', sun: 'Sun'}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,19 +1,19 @@
|
||||
<template>
|
||||
<div class="specimens">
|
||||
<h2>Button classification</h2>
|
||||
<div class="specimen">
|
||||
<h3>Button</h3>
|
||||
<FormulateInput
|
||||
label="Click me"
|
||||
type="button"
|
||||
/>
|
||||
<div class="specimens">
|
||||
<h2>Button classification</h2>
|
||||
<div class="specimen">
|
||||
<h3>Button</h3>
|
||||
<FormulateInput
|
||||
label="Click me"
|
||||
type="button"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Submit</h3>
|
||||
<FormulateInput
|
||||
label="Submit me"
|
||||
type="submit"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Submit</h3>
|
||||
<FormulateInput
|
||||
label="Submit me"
|
||||
type="submit"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,21 +1,21 @@
|
||||
<template>
|
||||
<div class="specimens specimens--text">
|
||||
<h2>File classification</h2>
|
||||
<div class="specimen specimen">
|
||||
<h3>Text</h3>
|
||||
<FormulateInput
|
||||
label="Upload a file"
|
||||
type="file"
|
||||
help="Select any file to upload"
|
||||
/>
|
||||
<div class="specimens specimens--text">
|
||||
<h2>File classification</h2>
|
||||
<div class="specimen specimen">
|
||||
<h3>Text</h3>
|
||||
<FormulateInput
|
||||
label="Upload a file"
|
||||
type="file"
|
||||
help="Select any file to upload"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Image</h3>
|
||||
<FormulateInput
|
||||
label="What do you look like?"
|
||||
type="image"
|
||||
help="Select a picture to upload."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Image</h3>
|
||||
<FormulateInput
|
||||
label="What do you look like?"
|
||||
type="image"
|
||||
help="Select a picture to upload."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,55 +1,49 @@
|
||||
<template>
|
||||
<div class="specimens specimens--group">
|
||||
<h2>Group classification</h2>
|
||||
<div class="specimen">
|
||||
<h3>Non-repeatable group</h3>
|
||||
<FormulateInput
|
||||
type="group"
|
||||
>
|
||||
<FormulateInput
|
||||
label="City"
|
||||
type="text"
|
||||
name="city"
|
||||
/>
|
||||
<FormulateInput
|
||||
label="State"
|
||||
type="select"
|
||||
:options="{NE: 'Nebraska', MO: 'Missouri', VA: 'Virginia'}"
|
||||
placeholder="Select a state"
|
||||
/>
|
||||
</FormulateInput>
|
||||
<div class="specimens specimens--group">
|
||||
<h2>Group classification</h2>
|
||||
<div class="specimen">
|
||||
<h3>Non-repeatable group</h3>
|
||||
<FormulateInput
|
||||
type="group"
|
||||
>
|
||||
<FormulateInput
|
||||
label="City"
|
||||
type="text"
|
||||
name="city"
|
||||
/>
|
||||
<FormulateInput
|
||||
label="State"
|
||||
type="select"
|
||||
:options="{NE: 'Nebraska', MO: 'Missouri', VA: 'Virginia'}"
|
||||
placeholder="Select a state"
|
||||
/>
|
||||
</FormulateInput>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Repeatable group</h3>
|
||||
<FormulateInput
|
||||
name="users"
|
||||
label="Invite some new users"
|
||||
type="group"
|
||||
placeholder="users"
|
||||
help="Fields can be grouped"
|
||||
:repeatable="true"
|
||||
>
|
||||
<FormulateInput
|
||||
label="First and last name"
|
||||
name="name"
|
||||
type="text"
|
||||
placeholder="User’s name"
|
||||
validation="required"
|
||||
/>
|
||||
<FormulateInput
|
||||
name="email"
|
||||
label="Email address"
|
||||
type="email"
|
||||
placeholder="User’s email"
|
||||
validation="required|email"
|
||||
/>
|
||||
</FormulateInput>
|
||||
</div>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Repeatable group</h3>
|
||||
<FormulateInput
|
||||
name="users"
|
||||
label="Invite some new users"
|
||||
type="group"
|
||||
placeholder="users"
|
||||
help="Fields can be grouped"
|
||||
:repeatable="true"
|
||||
>
|
||||
<FormulateInput
|
||||
label="First and last name"
|
||||
name="name"
|
||||
type="text"
|
||||
placeholder="User’s name"
|
||||
validation="required"
|
||||
/>
|
||||
<FormulateInput
|
||||
name="email"
|
||||
label="Email address"
|
||||
type="email"
|
||||
placeholder="User’s email"
|
||||
validation="required|email"
|
||||
/>
|
||||
</FormulateInput>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div class="specimens specimens--text">
|
||||
<h2>Select classification</h2>
|
||||
<div class="specimen specimen--single">
|
||||
<h3>Select</h3>
|
||||
<FormulateInput
|
||||
label="What planet is the hottest?"
|
||||
type="select"
|
||||
:options="{mercury: 'Mercury', venus: 'Venus', earth: 'Earth', mars: 'Mars'}"
|
||||
help="Average temperature on the surface of the planet."
|
||||
/>
|
||||
<div class="specimens specimens--text">
|
||||
<h2>Select classification</h2>
|
||||
<div class="specimen specimen--single">
|
||||
<h3>Select</h3>
|
||||
<FormulateInput
|
||||
label="What planet is the hottest?"
|
||||
type="select"
|
||||
:options="{mercury: 'Mercury', venus: 'Venus', earth: 'Earth', mars: 'Mars'}"
|
||||
help="Average temperature on the surface of the planet."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<div class="specimens specimens--text">
|
||||
<h2>Slider classification</h2>
|
||||
<div class="specimen specimen--single">
|
||||
<h3>Range</h3>
|
||||
<FormulateInput
|
||||
label="How far should we crank it up?"
|
||||
type="range"
|
||||
min="0"
|
||||
max="11"
|
||||
:show-value="true"
|
||||
help="Whenever we’re allowed to have a party again..."
|
||||
/>
|
||||
<div class="specimens specimens--text">
|
||||
<h2>Slider classification</h2>
|
||||
<div class="specimen specimen--single">
|
||||
<h3>Range</h3>
|
||||
<FormulateInput
|
||||
label="How far should we crank it up?"
|
||||
type="range"
|
||||
min="0"
|
||||
max="11"
|
||||
:show-value="true"
|
||||
help="Whenever we’re allowed to have a party again..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,117 +1,117 @@
|
||||
<template>
|
||||
<div class="specimens specimens--text">
|
||||
<h2>Text classification</h2>
|
||||
<div class="specimen">
|
||||
<h3>Color</h3>
|
||||
<FormulateInput
|
||||
label="Pick a color?"
|
||||
type="color"
|
||||
help="Choose your favorite."
|
||||
/>
|
||||
<div class="specimens specimens--text">
|
||||
<h2>Text classification</h2>
|
||||
<div class="specimen">
|
||||
<h3>Color</h3>
|
||||
<FormulateInput
|
||||
label="Pick a color?"
|
||||
type="color"
|
||||
help="Choose your favorite."
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Date</h3>
|
||||
<FormulateInput
|
||||
label="Select a day."
|
||||
type="date"
|
||||
help="Choose your birthday."
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Datetime-local</h3>
|
||||
<FormulateInput
|
||||
label="Select a day and time."
|
||||
type="datetime-local"
|
||||
help="When is the meeting?"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Email</h3>
|
||||
<FormulateInput
|
||||
label="What is your email?"
|
||||
type="email"
|
||||
placeholder="placeholder@example.com"
|
||||
help="What is your email address?"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Month</h3>
|
||||
<FormulateInput
|
||||
label="Favorite month"
|
||||
type="month"
|
||||
help="When is Christmas?"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Number</h3>
|
||||
<FormulateInput
|
||||
label="How old are you?"
|
||||
type="number"
|
||||
placeholder="25"
|
||||
help="Select your age"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Password</h3>
|
||||
<FormulateInput
|
||||
label="Enter a password."
|
||||
type="password"
|
||||
help="Choose something long and tricky."
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Search</h3>
|
||||
<FormulateInput
|
||||
label="But I still haven't found."
|
||||
type="search"
|
||||
placeholder="What im looking for..."
|
||||
help="I have climbed the highest mountains."
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Tel</h3>
|
||||
<FormulateInput
|
||||
label="Oh you like Mike & Ikes?"
|
||||
type="tel"
|
||||
placeholder="Can I have you number..."
|
||||
help="Can I have it?"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Time</h3>
|
||||
<FormulateInput
|
||||
label="What time is dinner?"
|
||||
type="time"
|
||||
placeholder="Pick a time"
|
||||
help="When will you eat your food?"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Text</h3>
|
||||
<FormulateInput
|
||||
label="Username"
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
help="Select a username"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Url</h3>
|
||||
<FormulateInput
|
||||
label="Personal website"
|
||||
type="url"
|
||||
placeholder="https://"
|
||||
help="What is the url for your website?"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Week</h3>
|
||||
<FormulateInput
|
||||
label="I don’t know who would use this field."
|
||||
type="week"
|
||||
placeholder="Pick a week"
|
||||
help="What week is it?"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Date</h3>
|
||||
<FormulateInput
|
||||
label="Select a day."
|
||||
type="date"
|
||||
help="Choose your birthday."
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Datetime-local</h3>
|
||||
<FormulateInput
|
||||
label="Select a day and time."
|
||||
type="datetime-local"
|
||||
help="When is the meeting?"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Email</h3>
|
||||
<FormulateInput
|
||||
label="What is your email?"
|
||||
type="email"
|
||||
placeholder="placeholder@example.com"
|
||||
help="What is your email address?"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Month</h3>
|
||||
<FormulateInput
|
||||
label="Favorite month"
|
||||
type="month"
|
||||
help="When is Christmas?"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Number</h3>
|
||||
<FormulateInput
|
||||
label="How old are you?"
|
||||
type="number"
|
||||
placeholder="25"
|
||||
help="Select your age"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Password</h3>
|
||||
<FormulateInput
|
||||
label="Enter a password."
|
||||
type="password"
|
||||
help="Choose something long and tricky."
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Search</h3>
|
||||
<FormulateInput
|
||||
label="But I still haven't found."
|
||||
type="search"
|
||||
placeholder="What im looking for..."
|
||||
help="I have climbed the highest mountains."
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Tel</h3>
|
||||
<FormulateInput
|
||||
label="Oh you like Mike & Ikes?"
|
||||
type="tel"
|
||||
placeholder="Can I have you number..."
|
||||
help="Can I have it?"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Time</h3>
|
||||
<FormulateInput
|
||||
label="What time is dinner?"
|
||||
type="time"
|
||||
placeholder="Pick a time"
|
||||
help="When will you eat your food?"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Text</h3>
|
||||
<FormulateInput
|
||||
label="Username"
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
help="Select a username"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Url</h3>
|
||||
<FormulateInput
|
||||
label="Personal website"
|
||||
type="url"
|
||||
placeholder="https://"
|
||||
help="What is the url for your website?"
|
||||
/>
|
||||
</div>
|
||||
<div class="specimen">
|
||||
<h3>Week</h3>
|
||||
<FormulateInput
|
||||
label="I don’t know who would use this field."
|
||||
type="week"
|
||||
placeholder="Pick a week"
|
||||
help="What week is it?"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="specimens specimens--text">
|
||||
<h2>Textarea classification</h2>
|
||||
<div class="specimen specimen--single">
|
||||
<h3>Textarea</h3>
|
||||
<FormulateInput
|
||||
label="What is your life story?"
|
||||
type="textarea"
|
||||
help="I want to hear all about it!"
|
||||
/>
|
||||
<div class="specimens specimens--text">
|
||||
<h2>Textarea classification</h2>
|
||||
<div class="specimen specimen--single">
|
||||
<h3>Textarea</h3>
|
||||
<FormulateInput
|
||||
label="What is your life story?"
|
||||
type="textarea"
|
||||
help="I want to hear all about it!"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -51,6 +51,7 @@
|
||||
"@vue/cli-plugin-eslint": "^4.3.1",
|
||||
"@vue/cli-service": "^4.5.4",
|
||||
"@vue/component-compiler-utils": "^3.1.2",
|
||||
"@vue/eslint-config-standard": "^5.1.2",
|
||||
"@vue/test-utils": "^1.0.2",
|
||||
"autoprefixer": "^9.7.6",
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
|
@ -1,5 +1,6 @@
|
||||
import nanoid from 'nanoid/non-secure'
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
/**
|
||||
* The file upload class holds and represents a file’s upload state durring
|
||||
* the upload flow.
|
||||
@ -7,8 +8,9 @@ import nanoid from 'nanoid/non-secure'
|
||||
class FileUpload {
|
||||
/**
|
||||
* Create a file upload object.
|
||||
* @param {FileList} fileList
|
||||
* @param {FileList} input
|
||||
* @param {object} context
|
||||
* @param {object} options
|
||||
*/
|
||||
constructor (input, context, options = {}) {
|
||||
this.input = input
|
||||
@ -27,7 +29,6 @@ class FileUpload {
|
||||
/**
|
||||
* Given a pre-existing array of files, create a faux FileList.
|
||||
* @param {array} items expects an array of objects [{ url: '/uploads/file.pdf' }]
|
||||
* @param {string} pathKey the object-key to access the url (defaults to "url")
|
||||
*/
|
||||
rehydrateFileList (items) {
|
||||
const fauxFileList = items.reduce((fileList, item) => {
|
||||
@ -48,15 +49,12 @@ class FileUpload {
|
||||
|
||||
/**
|
||||
* Produce an array of files and alert the callback.
|
||||
* @param {FileList}
|
||||
* @param {FileList} fileList
|
||||
*/
|
||||
addFileList (fileList) {
|
||||
for (let i = 0; i < fileList.length; i++) {
|
||||
const file = fileList[i]
|
||||
const uuid = nanoid()
|
||||
const removeFile = function () {
|
||||
this.removeFile(uuid)
|
||||
}
|
||||
this.files.push({
|
||||
progress: false,
|
||||
error: false,
|
||||
@ -66,7 +64,7 @@ class FileUpload {
|
||||
file,
|
||||
uuid,
|
||||
path: false,
|
||||
removeFile: removeFile.bind(this),
|
||||
removeFile: () => this.removeFile(uuid),
|
||||
previewData: file.previewData || false
|
||||
})
|
||||
}
|
||||
@ -86,16 +84,11 @@ class FileUpload {
|
||||
* https://github.com/axios/axios/issues/737
|
||||
*/
|
||||
uploaderIsAxios () {
|
||||
if (
|
||||
this.hasUploader &&
|
||||
return this.hasUploader &&
|
||||
typeof this.context.uploader.request === 'function' &&
|
||||
typeof this.context.uploader.get === 'function' &&
|
||||
typeof this.context.uploader.delete === 'function' &&
|
||||
typeof this.context.uploader.post === 'function'
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,13 +3,15 @@ import rules from './libs/rules'
|
||||
import mimes from './libs/mimes'
|
||||
import FileUpload from './FileUpload'
|
||||
import RuleValidationMessages from './RuleValidationMessages'
|
||||
import { arrayify, parseLocale, has } from './libs/utils'
|
||||
import { arrayify } from './libs/utils'
|
||||
import isPlainObject from 'is-plain-object'
|
||||
import fauxUploader from './libs/faux-uploader'
|
||||
|
||||
import FormularioForm from './FormularioForm.vue'
|
||||
import FormularioInput from './FormularioInput.vue'
|
||||
import FormularioGrouping from './FormularioGrouping.vue'
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
/**
|
||||
* The base formulario library.
|
||||
*/
|
||||
@ -23,7 +25,7 @@ class Formulario {
|
||||
components: {
|
||||
FormularioForm,
|
||||
FormularioInput,
|
||||
FormularioGrouping,
|
||||
FormularioGrouping
|
||||
},
|
||||
library,
|
||||
rules,
|
||||
@ -34,7 +36,7 @@ class Formulario {
|
||||
fileUrlKey: 'url',
|
||||
uploadJustCompleteDuration: 1000,
|
||||
errorHandler: (err) => err,
|
||||
plugins: [ RuleValidationMessages ],
|
||||
plugins: [RuleValidationMessages],
|
||||
validationMessages: {},
|
||||
idPrefix: 'formulario-'
|
||||
}
|
||||
@ -48,14 +50,16 @@ class Formulario {
|
||||
install (Vue, options) {
|
||||
Vue.prototype.$formulario = this
|
||||
this.options = this.defaults
|
||||
var plugins = this.defaults.plugins
|
||||
let plugins = this.defaults.plugins
|
||||
if (options && Array.isArray(options.plugins) && options.plugins.length) {
|
||||
plugins = plugins.concat(options.plugins)
|
||||
plugins = plugins.concat(options.plugins)
|
||||
}
|
||||
plugins.forEach(plugin => (typeof plugin === 'function') ? plugin(this) : null)
|
||||
this.extend(options || {})
|
||||
for (var componentName in this.options.components) {
|
||||
Vue.component(componentName, this.options.components[componentName])
|
||||
for (const componentName in this.options.components) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.options.components, componentName)) {
|
||||
Vue.component(componentName, this.options.components[componentName])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,9 +99,10 @@ class Formulario {
|
||||
* @param {boolean} concatArrays
|
||||
*/
|
||||
merge (base, mergeWith, concatArrays = true) {
|
||||
var merged = {}
|
||||
for (var key in base) {
|
||||
if (mergeWith.hasOwnProperty(key)) {
|
||||
const merged = {}
|
||||
|
||||
for (const key in base) {
|
||||
if (Object.prototype.hasOwnProperty.call(mergeWith, key)) {
|
||||
if (isPlainObject(mergeWith[key]) && isPlainObject(base[key])) {
|
||||
merged[key] = this.merge(base[key], mergeWith[key], concatArrays)
|
||||
} else if (concatArrays && Array.isArray(base[key]) && Array.isArray(mergeWith[key])) {
|
||||
@ -109,11 +114,13 @@ class Formulario {
|
||||
merged[key] = base[key]
|
||||
}
|
||||
}
|
||||
for (var prop in mergeWith) {
|
||||
if (!merged.hasOwnProperty(prop)) {
|
||||
|
||||
for (const prop in mergeWith) {
|
||||
if (!Object.prototype.hasOwnProperty.call(merged, prop)) {
|
||||
merged[prop] = mergeWith[prop]
|
||||
}
|
||||
}
|
||||
|
||||
return merged
|
||||
}
|
||||
|
||||
@ -122,9 +129,10 @@ class Formulario {
|
||||
* @param {string} type
|
||||
*/
|
||||
classify (type) {
|
||||
if (this.options.library.hasOwnProperty(type)) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.options.library, type)) {
|
||||
return this.options.library[type].classification
|
||||
}
|
||||
|
||||
return 'unknown'
|
||||
}
|
||||
|
||||
@ -133,9 +141,10 @@ class Formulario {
|
||||
* @param {string} type
|
||||
*/
|
||||
component (type) {
|
||||
if (this.options.library.hasOwnProperty(type)) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.options.library, type)) {
|
||||
return this.options.library[type].component
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@ -151,16 +160,16 @@ class Formulario {
|
||||
* Get the validation message for a particular error.
|
||||
*/
|
||||
validationMessage (rule, validationContext, vm) {
|
||||
if (this.options.validationMessages.hasOwnProperty(rule)) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.options.validationMessages, rule)) {
|
||||
return this.options.validationMessages[rule](vm, validationContext)
|
||||
} else {
|
||||
return this.options.validationMessages['default'](vm, validationContext)
|
||||
return this.options.validationMessages.default(vm, validationContext)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an instance of a FormularioForm register it.
|
||||
* @param {vm} form
|
||||
* @param {Vue} form
|
||||
*/
|
||||
register (form) {
|
||||
if (form.$options.name === 'FormularioForm' && form.name) {
|
||||
@ -170,7 +179,7 @@ class Formulario {
|
||||
|
||||
/**
|
||||
* Given an instance of a form, remove it from the registry.
|
||||
* @param {vm} form
|
||||
* @param {Vue} form
|
||||
*/
|
||||
deregister (form) {
|
||||
if (
|
||||
@ -188,7 +197,7 @@ class Formulario {
|
||||
*
|
||||
* @param {error} err
|
||||
* @param {string} formName
|
||||
* @param {error}
|
||||
* @param {boolean} skip
|
||||
*/
|
||||
handle (err, formName, skip = false) {
|
||||
const e = skip ? err : this.options.errorHandler(err, formName)
|
||||
|
@ -16,13 +16,16 @@
|
||||
>
|
||||
<img
|
||||
:src="file.previewData"
|
||||
alt=""
|
||||
>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="formulario-file-name"
|
||||
:title="file.name"
|
||||
v-text="file.name"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-if="file.progress !== false"
|
||||
:data-just-finished="file.justFinished"
|
||||
@ -34,12 +37,14 @@
|
||||
:style="{width: file.progress + '%'}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="(file.complete && !file.justFinished) || file.progress === false"
|
||||
class="formulario-file-remove"
|
||||
@click="file.removeFile"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="file.error"
|
||||
class="formulario-file-upload-error"
|
||||
@ -54,21 +59,25 @@ import FileUpload from './FileUpload'
|
||||
|
||||
export default {
|
||||
name: 'FormularioFiles',
|
||||
|
||||
props: {
|
||||
files: {
|
||||
type: FileUpload,
|
||||
required: true
|
||||
},
|
||||
|
||||
imagePreview: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
fileUploads () {
|
||||
return this.files.files || []
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
files () {
|
||||
if (this.imagePreview) {
|
||||
@ -76,6 +85,7 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
if (this.imagePreview) {
|
||||
this.files.loadPreviews()
|
||||
|
@ -13,6 +13,8 @@ import useRegistry, { useRegistryComputed, useRegistryMethods, useRegistryProvid
|
||||
import FormSubmission from './FormSubmission'
|
||||
|
||||
export default {
|
||||
name: 'FormularioForm',
|
||||
|
||||
provide () {
|
||||
return {
|
||||
...useRegistryProviders(this),
|
||||
@ -22,33 +24,39 @@ export default {
|
||||
path: ''
|
||||
}
|
||||
},
|
||||
name: 'FormularioForm',
|
||||
|
||||
model: {
|
||||
prop: 'formularioValue',
|
||||
event: 'input'
|
||||
},
|
||||
|
||||
props: {
|
||||
name: {
|
||||
type: [String, Boolean],
|
||||
default: false
|
||||
},
|
||||
|
||||
formularioValue: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
|
||||
values: {
|
||||
type: [Object, Boolean],
|
||||
default: false
|
||||
},
|
||||
|
||||
errors: {
|
||||
type: [Object, Boolean],
|
||||
default: false
|
||||
},
|
||||
|
||||
formErrors: {
|
||||
type: Array,
|
||||
default: () => ([])
|
||||
}
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
...useRegistry(this),
|
||||
@ -58,51 +66,58 @@ export default {
|
||||
namedFieldErrors: {}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...useRegistryComputed(),
|
||||
|
||||
classes () {
|
||||
const classes = { 'formulario-form': true }
|
||||
if (this.name) {
|
||||
classes[`formulario-form--${this.name}`] = true
|
||||
return {
|
||||
'formulario-form': true,
|
||||
[`formulario-form--${this.name}`]: !!this.name
|
||||
}
|
||||
return classes
|
||||
},
|
||||
|
||||
mergedFormErrors () {
|
||||
return this.formErrors.concat(this.namedErrors)
|
||||
},
|
||||
|
||||
mergedFieldErrors () {
|
||||
const errors = {}
|
||||
|
||||
if (this.errors) {
|
||||
for (const fieldName in this.errors) {
|
||||
errors[fieldName] = arrayify(this.errors[fieldName])
|
||||
}
|
||||
}
|
||||
|
||||
for (const fieldName in this.namedFieldErrors) {
|
||||
errors[fieldName] = arrayify(this.namedFieldErrors[fieldName])
|
||||
}
|
||||
|
||||
return errors
|
||||
},
|
||||
|
||||
hasFormErrorObservers () {
|
||||
return !!this.errorObservers.filter(o => o.type === 'form').length
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
formularioValue: {
|
||||
handler (values) {
|
||||
if (this.isVmodeled &&
|
||||
values &&
|
||||
typeof values === 'object'
|
||||
) {
|
||||
if (this.isVmodeled && values && typeof values === 'object') {
|
||||
this.setValues(values)
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
|
||||
mergedFormErrors (errors) {
|
||||
this.errorObservers
|
||||
.filter(o => o.type === 'form')
|
||||
.forEach(o => o.callback(errors))
|
||||
},
|
||||
|
||||
mergedFieldErrors: {
|
||||
handler (errors) {
|
||||
this.errorObservers
|
||||
@ -112,20 +127,25 @@ export default {
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.$formulario.register(this)
|
||||
this.applyInitialValues()
|
||||
},
|
||||
|
||||
destroyed () {
|
||||
this.$formulario.deregister(this)
|
||||
},
|
||||
|
||||
methods: {
|
||||
...useRegistryMethods(),
|
||||
|
||||
applyErrors ({ formErrors, inputErrors }) {
|
||||
// given an object of errors, apply them to this form
|
||||
this.namedErrors = formErrors
|
||||
this.namedFieldErrors = inputErrors
|
||||
},
|
||||
|
||||
addErrorObserver (observer) {
|
||||
if (!this.errorObservers.find(obs => observer.callback === obs.callback)) {
|
||||
this.errorObservers.push(observer)
|
||||
@ -136,14 +156,17 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeErrorObserver (observer) {
|
||||
this.errorObservers = this.errorObservers.filter(obs => obs.callback !== observer)
|
||||
},
|
||||
|
||||
registerErrorComponent (component) {
|
||||
if (!this.errorComponents.includes(component)) {
|
||||
this.errorComponents.push(component)
|
||||
}
|
||||
},
|
||||
|
||||
formSubmitted () {
|
||||
// perform validation here
|
||||
this.showErrors()
|
||||
@ -159,6 +182,7 @@ export default {
|
||||
return undefined
|
||||
})
|
||||
},
|
||||
|
||||
formularioFieldValidation (errorObject) {
|
||||
this.$emit('validation', errorObject)
|
||||
}
|
||||
|
@ -10,33 +10,38 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'FormularioGrouping',
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
isArrayItem: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
|
||||
provide () {
|
||||
return {
|
||||
path: this.groupPath
|
||||
}
|
||||
},
|
||||
|
||||
inject: ['path'],
|
||||
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
isArrayItem: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
groupPath () {
|
||||
if (this.isArrayItem) {
|
||||
return this.path + '[' + this.name + ']';
|
||||
} else {
|
||||
if (this.path === '') {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
return this.path + '.' + this.name;
|
||||
return `${this.path}[${this.name}]`
|
||||
}
|
||||
|
||||
if (this.path === '') {
|
||||
return this.name
|
||||
}
|
||||
|
||||
return `${this.path}.${this.name}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,12 @@
|
||||
:data-is-showing-errors="hasVisibleErrors"
|
||||
:data-type="type"
|
||||
>
|
||||
<slot :id="id" :context="context" :errors="errors" :validationErrors="validationErrors" />
|
||||
<slot
|
||||
:id="id"
|
||||
:context="context"
|
||||
:errors="errors"
|
||||
:validationErrors="validationErrors"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -15,7 +20,9 @@ import { shallowEqualObjects, parseRules, snakeToCamel, has, arrayify, groupBail
|
||||
|
||||
export default {
|
||||
name: 'FormularioInput',
|
||||
|
||||
inheritAttrs: false,
|
||||
|
||||
provide () {
|
||||
return {
|
||||
// Allows sub-components of this input to register arbitrary rules.
|
||||
@ -23,6 +30,7 @@ export default {
|
||||
formularioRemoveRule: this.removeRule
|
||||
}
|
||||
},
|
||||
|
||||
inject: {
|
||||
formularioSetter: { default: undefined },
|
||||
formularioFieldValidation: { default: () => () => ({}) },
|
||||
@ -33,87 +41,107 @@ export default {
|
||||
removeErrorObserver: { default: undefined },
|
||||
path: { default: '' }
|
||||
},
|
||||
|
||||
model: {
|
||||
prop: 'formularioValue',
|
||||
event: 'input'
|
||||
},
|
||||
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'text'
|
||||
},
|
||||
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
/* eslint-disable */
|
||||
formularioValue: {
|
||||
default: ''
|
||||
},
|
||||
|
||||
value: {
|
||||
default: false
|
||||
},
|
||||
/* eslint-enable */
|
||||
|
||||
id: {
|
||||
type: [String, Boolean, Number],
|
||||
default: false
|
||||
},
|
||||
|
||||
errors: {
|
||||
type: [String, Array, Boolean],
|
||||
default: false
|
||||
},
|
||||
|
||||
validation: {
|
||||
type: [String, Boolean, Array],
|
||||
default: false
|
||||
},
|
||||
|
||||
validationName: {
|
||||
type: [String, Boolean],
|
||||
default: false
|
||||
},
|
||||
|
||||
errorBehavior: {
|
||||
type: String,
|
||||
default: 'blur',
|
||||
validator: function (value) {
|
||||
validator (value) {
|
||||
return ['blur', 'live', 'submit'].includes(value)
|
||||
}
|
||||
},
|
||||
|
||||
showErrors: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
imageBehavior: {
|
||||
type: String,
|
||||
default: 'preview'
|
||||
},
|
||||
|
||||
uploadUrl: {
|
||||
type: [String, Boolean],
|
||||
default: false
|
||||
},
|
||||
|
||||
uploader: {
|
||||
type: [Function, Object, Boolean],
|
||||
default: false
|
||||
},
|
||||
|
||||
uploadBehavior: {
|
||||
type: String,
|
||||
default: 'live'
|
||||
},
|
||||
|
||||
preventWindowDrops: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
|
||||
validationMessages: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
|
||||
validationRules: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
|
||||
disableErrors: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
defaultId: this.$formulario.nextId(this),
|
||||
@ -129,8 +157,10 @@ export default {
|
||||
messageRegistry: {}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...context,
|
||||
|
||||
parsedValidationRules () {
|
||||
const parsedValidationRules = {}
|
||||
Object.keys(this.validationRules).forEach(key => {
|
||||
@ -138,6 +168,7 @@ export default {
|
||||
})
|
||||
return parsedValidationRules
|
||||
},
|
||||
|
||||
messages () {
|
||||
const messages = {}
|
||||
Object.keys(this.validationMessages).forEach((key) => {
|
||||
@ -149,24 +180,28 @@ export default {
|
||||
return messages
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
'$attrs': {
|
||||
$attrs: {
|
||||
handler (value) {
|
||||
this.updateLocalAttributes(value)
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
|
||||
proxy (newValue, oldValue) {
|
||||
this.performValidation()
|
||||
if (!this.isVmodeled && !shallowEqualObjects(newValue, oldValue)) {
|
||||
this.context.model = newValue
|
||||
}
|
||||
},
|
||||
|
||||
formularioValue (newValue, oldValue) {
|
||||
if (this.isVmodeled && !shallowEqualObjects(newValue, oldValue)) {
|
||||
this.context.model = newValue
|
||||
}
|
||||
},
|
||||
|
||||
showValidationErrors: {
|
||||
handler (val) {
|
||||
this.$emit('error-visibility', val)
|
||||
@ -174,6 +209,7 @@ export default {
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.applyInitialValue()
|
||||
if (this.formularioRegister && typeof this.formularioRegister === 'function') {
|
||||
@ -187,6 +223,7 @@ export default {
|
||||
this.performValidation()
|
||||
}
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
if (!this.disableErrors && typeof this.removeErrorObserver === 'function') {
|
||||
this.removeErrorObserver(this.setErrors)
|
||||
@ -195,6 +232,7 @@ export default {
|
||||
this.formularioDeregister(this.nameOrFallback)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInitialValue () {
|
||||
if (has(this.$options.propsData, 'value')) {
|
||||
@ -204,6 +242,7 @@ export default {
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
applyInitialValue () {
|
||||
// This should only be run immediately on created and ensures that the
|
||||
// proxy and the model are both the same before any additional registration.
|
||||
@ -211,11 +250,13 @@ export default {
|
||||
this.context.model = this.proxy
|
||||
}
|
||||
},
|
||||
|
||||
updateLocalAttributes (value) {
|
||||
if (!shallowEqualObjects(value, this.localAttributes)) {
|
||||
this.localAttributes = value
|
||||
}
|
||||
},
|
||||
|
||||
performValidation () {
|
||||
let rules = parseRules(this.validation, this.$formulario.rules(this.parsedValidationRules))
|
||||
// Add in ruleRegistry rules. These are added directly via injection from
|
||||
@ -225,6 +266,7 @@ export default {
|
||||
.then(messages => this.didValidate(messages))
|
||||
return this.pendingValidation
|
||||
},
|
||||
|
||||
runRules (rules) {
|
||||
const run = ([rule, args, ruleName, modifier]) => {
|
||||
var res = rule({
|
||||
@ -257,6 +299,7 @@ export default {
|
||||
resolveGroups(groupBails(rules))
|
||||
})
|
||||
},
|
||||
|
||||
didValidate (messages) {
|
||||
const validationChanged = !shallowEqualObjects(messages, this.validationErrors)
|
||||
this.validationErrors = messages
|
||||
@ -268,15 +311,16 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getMessageObject (ruleName, args) {
|
||||
let context = {
|
||||
const context = {
|
||||
args,
|
||||
name: this.mergedValidationName,
|
||||
value: this.context.model,
|
||||
vm: this,
|
||||
formValues: this.getFormValues()
|
||||
};
|
||||
let message = this.getMessageFunc(ruleName)(context);
|
||||
}
|
||||
const message = this.getMessageFunc(ruleName)(context)
|
||||
|
||||
return {
|
||||
message: message,
|
||||
@ -284,19 +328,21 @@ export default {
|
||||
context: context
|
||||
}
|
||||
},
|
||||
|
||||
getMessageFunc (ruleName) {
|
||||
ruleName = snakeToCamel(ruleName)
|
||||
if (this.messages && typeof this.messages[ruleName] !== 'undefined') {
|
||||
switch (typeof this.messages[ruleName]) {
|
||||
case 'function':
|
||||
return this.messages[ruleName]
|
||||
case 'string':
|
||||
case 'boolean':
|
||||
return () => this.messages[ruleName]
|
||||
case 'function':
|
||||
return this.messages[ruleName]
|
||||
case 'string':
|
||||
case 'boolean':
|
||||
return () => this.messages[ruleName]
|
||||
}
|
||||
}
|
||||
return (context) => this.$formulario.validationMessage(ruleName, context, this)
|
||||
},
|
||||
|
||||
hasValidationErrors () {
|
||||
return new Promise(resolve => {
|
||||
this.$nextTick(() => {
|
||||
@ -304,11 +350,13 @@ export default {
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
getValidationErrors () {
|
||||
return new Promise(resolve => {
|
||||
this.$nextTick(() => this.pendingValidation.then(() => resolve(this.getErrorObject())))
|
||||
})
|
||||
},
|
||||
|
||||
getErrorObject () {
|
||||
return {
|
||||
name: this.context.nameOrFallback || this.context.name,
|
||||
@ -316,9 +364,11 @@ export default {
|
||||
hasErrors: !!this.validationErrors.length
|
||||
}
|
||||
},
|
||||
|
||||
setErrors (errors) {
|
||||
this.localErrors = arrayify(errors)
|
||||
},
|
||||
|
||||
registerRule (rule, args, ruleName, message = null) {
|
||||
if (!this.ruleRegistry.some(r => r[2] === ruleName)) {
|
||||
// These are the raw rule format since they will be used directly.
|
||||
@ -328,6 +378,7 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeRule (key) {
|
||||
const ruleIndex = this.ruleRegistry.findIndex(r => r[2] === key)
|
||||
if (ruleIndex >= 0) {
|
||||
|
@ -18,14 +18,14 @@ const validationMessages = {
|
||||
* The default render method for error messages.
|
||||
*/
|
||||
default: function (vm, context) {
|
||||
return vm.$t(`validation.default`, context)
|
||||
return vm.$t('validation.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* Valid accepted value.
|
||||
*/
|
||||
accepted: function (vm, context) {
|
||||
return vm.$t(`validation.accepted`, context)
|
||||
return vm.$t('validation.accepted', context)
|
||||
},
|
||||
|
||||
/**
|
||||
@ -33,25 +33,25 @@ const validationMessages = {
|
||||
*/
|
||||
after: function (vm, context) {
|
||||
if (Array.isArray(context.args) && context.args.length) {
|
||||
context['compare'] = context.args[0]
|
||||
return vm.$t(`validation.after.compare`, context)
|
||||
context.compare = context.args[0]
|
||||
return vm.$t('validation.after.compare', context)
|
||||
}
|
||||
|
||||
return vm.$t(`validation.after.default`, context)
|
||||
return vm.$t('validation.after.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* The value is not a letter.
|
||||
*/
|
||||
alpha: function (vm, context) {
|
||||
return vm.$t(`validation.alpha`, context)
|
||||
return vm.$t('validation.alpha', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* Rule: checks if the value is alpha numeric
|
||||
*/
|
||||
alphanumeric: function (vm, context) {
|
||||
return vm.$t(`validation.alphanumeric`, context)
|
||||
return vm.$t('validation.alphanumeric', context)
|
||||
},
|
||||
|
||||
/**
|
||||
@ -59,33 +59,33 @@ const validationMessages = {
|
||||
*/
|
||||
before: function (vm, context) {
|
||||
if (Array.isArray(context.args) && context.args.length) {
|
||||
context['compare'] = context.args[0]
|
||||
return vm.$t(`validation.before.compare`, context)
|
||||
context.compare = context.args[0]
|
||||
return vm.$t('validation.before.compare', context)
|
||||
}
|
||||
|
||||
return vm.$t(`validation.before.default`, context)
|
||||
return vm.$t('validation.before.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* The value is not between two numbers or lengths
|
||||
*/
|
||||
between: function (vm, context) {
|
||||
context['from'] = context.args[0]
|
||||
context['to'] = context.args[1]
|
||||
context.from = context.args[0]
|
||||
context.to = context.args[1]
|
||||
|
||||
const force = Array.isArray(context.args) && context.args[2] ? context.args[2] : false
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
return vm.$t(`validation.between.force`, context)
|
||||
return vm.$t('validation.between.force', context)
|
||||
}
|
||||
|
||||
return vm.$t(`validation.between.default`, context)
|
||||
return vm.$t('validation.between.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* The confirmation field does not match
|
||||
*/
|
||||
confirm: function (vm, context) {
|
||||
return vm.$t(`validation.confirm`, context)
|
||||
return vm.$t('validation.confirm', context)
|
||||
},
|
||||
|
||||
/**
|
||||
@ -93,25 +93,25 @@ const validationMessages = {
|
||||
*/
|
||||
date: function (vm, context) {
|
||||
if (Array.isArray(context.args) && context.args.length) {
|
||||
context['format'] = context.args[0]
|
||||
return vm.$t(`validation.date.format`, context)
|
||||
context.format = context.args[0]
|
||||
return vm.$t('validation.date.format', context)
|
||||
}
|
||||
|
||||
return vm.$t(`validation.date.default`, context)
|
||||
return vm.$t('validation.date.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* Is not a valid email address.
|
||||
*/
|
||||
email: function (vm, context) {
|
||||
return vm.$t(`validation.email.default`, context)
|
||||
return vm.$t('validation.email.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* Ends with specified value
|
||||
*/
|
||||
endsWith: function (vm, context) {
|
||||
return vm.$t(`validation.endsWith.default`, context)
|
||||
return vm.$t('validation.endsWith.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
@ -119,44 +119,44 @@ const validationMessages = {
|
||||
*/
|
||||
in: function (vm, context) {
|
||||
if (typeof context.value === 'string' && context.value) {
|
||||
return vm.$t(`validation.in.string`, context)
|
||||
return vm.$t('validation.in.string', context)
|
||||
}
|
||||
|
||||
return vm.$t(`validation.in.default`, context)
|
||||
return vm.$t('validation.in.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* Value is not a match.
|
||||
*/
|
||||
matches: function (vm, context) {
|
||||
return vm.$t(`validation.matches.default`, context)
|
||||
return vm.$t('validation.matches.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* The maximum value allowed.
|
||||
*/
|
||||
max: function (vm, context) {
|
||||
context['maximum'] = context.args[0]
|
||||
context.maximum = context.args[0]
|
||||
|
||||
if (Array.isArray(context.value)) {
|
||||
return vm.$tc(`validation.max.array`, context['maximum'], context)
|
||||
return vm.$tc('validation.max.array', context.maximum, context)
|
||||
}
|
||||
const force = Array.isArray(context.args) && context.args[1] ? context.args[1] : false
|
||||
if ((!isNaN(context.value) && force !== 'length') || force === 'value') {
|
||||
return vm.$tc(`validation.max.force`, context['maximum'], context)
|
||||
return vm.$tc('validation.max.force', context.maximum, context)
|
||||
}
|
||||
return vm.$tc(`validation.max.default`, context['maximum'], context)
|
||||
return vm.$tc('validation.max.default', context.maximum, context)
|
||||
},
|
||||
|
||||
/**
|
||||
* The (field-level) error message for mime errors.
|
||||
*/
|
||||
mime: function (vm, context) {
|
||||
context['types'] = context.args[0]
|
||||
if (context['types']) {
|
||||
return vm.$t(`validation.mime.default`, context)
|
||||
context.types = context.args[0]
|
||||
if (context.types) {
|
||||
return vm.$t('validation.mime.default', context)
|
||||
} else {
|
||||
return vm.$t(`validation.mime.no_formats_allowed`, context)
|
||||
return vm.$t('validation.mime.no_formats_allowed', context)
|
||||
}
|
||||
},
|
||||
|
||||
@ -164,51 +164,51 @@ const validationMessages = {
|
||||
* The maximum value allowed.
|
||||
*/
|
||||
min: function (vm, context) {
|
||||
context['minimum'] = context.args[0]
|
||||
context.minimum = context.args[0]
|
||||
|
||||
if (Array.isArray(context.value)) {
|
||||
return vm.$tc(`validation.min.array`, context['minimum'], context)
|
||||
return vm.$tc('validation.min.array', context.minimum, context)
|
||||
}
|
||||
const force = Array.isArray(context.args) && context.args[1] ? context.args[1] : false
|
||||
if ((!isNaN(context.value) && force !== 'length') || force === 'value') {
|
||||
return vm.$tc(`validation.min.force`, context['minimum'], context)
|
||||
return vm.$tc('validation.min.force', context.minimum, context)
|
||||
}
|
||||
return vm.$tc(`validation.min.default`, context['minimum'], context)
|
||||
return vm.$tc('validation.min.default', context.minimum, context)
|
||||
},
|
||||
|
||||
/**
|
||||
* The field is not an allowed value
|
||||
*/
|
||||
not: function (vm, context) {
|
||||
return vm.$t(`validation.not.default`, context)
|
||||
return vm.$t('validation.not.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* The field is not a number
|
||||
*/
|
||||
number: function (vm, context) {
|
||||
return vm.$t(`validation.number.default`, context)
|
||||
return vm.$t('validation.number.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* Required field.
|
||||
*/
|
||||
required: function (vm, context) {
|
||||
return vm.$t(`validation.required.default`, context)
|
||||
return vm.$t('validation.required.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts with specified value
|
||||
*/
|
||||
startsWith: function (vm, context) {
|
||||
return vm.$t(`validation.startsWith.default`, context)
|
||||
return vm.$t('validation.startsWith.default', context)
|
||||
},
|
||||
|
||||
/**
|
||||
* Value is not a url.
|
||||
*/
|
||||
url: function (vm, context) {
|
||||
return vm.$t(`validation.url.default`, context)
|
||||
return vm.$t('validation.url.default', context)
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,6 +218,6 @@ const validationMessages = {
|
||||
*/
|
||||
export default function (instance) {
|
||||
instance.extend({
|
||||
validationMessages: validationMessages
|
||||
validationMessages
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
const i = 'image/'
|
||||
export default {
|
||||
'csv': 'text/csv',
|
||||
'gif': i + 'gif',
|
||||
'jpg': i + 'jpeg',
|
||||
'jpeg': i + 'jpeg',
|
||||
'png': i + 'png',
|
||||
'pdf': 'application/pdf',
|
||||
'svg': i + 'svg+xml'
|
||||
csv: 'text/csv',
|
||||
gif: i + 'gif',
|
||||
jpg: i + 'jpeg',
|
||||
jpeg: i + 'jpeg',
|
||||
png: i + 'png',
|
||||
pdf: 'application/pdf',
|
||||
svg: i + 'svg+xml'
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ class Registry {
|
||||
|
||||
/**
|
||||
* Add an item to the registry.
|
||||
* @param {string|array} key
|
||||
* @param {string|array} name
|
||||
* @param {vue} component
|
||||
*/
|
||||
add (name, component) {
|
||||
@ -104,6 +104,7 @@ class Registry {
|
||||
/**
|
||||
* Reduce the registry.
|
||||
* @param {function} callback
|
||||
* @param accumulator
|
||||
*/
|
||||
reduce (callback, accumulator) {
|
||||
this.registry.forEach((component, field) => {
|
||||
@ -148,7 +149,7 @@ export function useRegistryComputed () {
|
||||
)
|
||||
},
|
||||
isVmodeled () {
|
||||
return !!(this.$options.propsData.hasOwnProperty('formularioValue') &&
|
||||
return !!(Object.prototype.hasOwnProperty.call(this.$options.propsData, 'formularioValue') &&
|
||||
this._events &&
|
||||
Array.isArray(this._events.input) &&
|
||||
this._events.input.length)
|
||||
@ -191,7 +192,7 @@ export function useRegistryMethods (without = []) {
|
||||
const { [field]: value, ...proxy } = this.proxy
|
||||
this.proxy = proxy
|
||||
} else {
|
||||
setNested(this.proxy, field, value);
|
||||
setNested(this.proxy, field, value)
|
||||
}
|
||||
this.$emit('input', Object.assign({}, this.proxy))
|
||||
},
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Vue from 'vue'
|
||||
import VueI18n from 'vue-i18n'
|
||||
import flushPromises from 'flush-promises'
|
||||
import { mount, createLocalVue } from '@vue/test-utils'
|
||||
|
||||
import Formulario from '@/Formulario.js'
|
||||
import FormularioForm from '@/FormularioForm.vue'
|
||||
import FormularioInput from '@/FormularioInput.vue'
|
||||
@ -19,7 +18,9 @@ function validationMessages (instance) {
|
||||
})
|
||||
}
|
||||
|
||||
Vue.use(Formulario, {
|
||||
const localVue = createLocalVue()
|
||||
|
||||
localVue.use(Formulario, {
|
||||
plugins: [validationMessages],
|
||||
rules: {
|
||||
globalRule
|
||||
@ -29,6 +30,7 @@ Vue.use(Formulario, {
|
||||
describe('FormularioInput', () => {
|
||||
it('allows custom field-rule level validation strings', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: {
|
||||
name: 'test',
|
||||
validation: 'required|in:abcdef',
|
||||
@ -38,7 +40,7 @@ describe('FormularioInput', () => {
|
||||
},
|
||||
scopedSlots: {
|
||||
default: `<div><span v-for="error in props.context.allErrors">{{ error.message }}</span></div>`
|
||||
}
|
||||
},
|
||||
})
|
||||
await flushPromises()
|
||||
expect(wrapper.find('span').text()).toBe('the value was different than expected')
|
||||
@ -62,6 +64,7 @@ describe('FormularioInput', () => {
|
||||
|
||||
it('allows custom field-rule level validation functions', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: {
|
||||
name: 'test',
|
||||
validation: 'required|in:abcdef',
|
||||
@ -79,6 +82,7 @@ describe('FormularioInput', () => {
|
||||
|
||||
it('uses custom async validation rules on defined on the field', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: {
|
||||
name: 'test',
|
||||
validation: 'required|foobar',
|
||||
@ -101,6 +105,7 @@ describe('FormularioInput', () => {
|
||||
|
||||
it('uses custom sync validation rules on defined on the field', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: {
|
||||
name: 'test',
|
||||
validation: 'required|foobar',
|
||||
@ -123,6 +128,7 @@ describe('FormularioInput', () => {
|
||||
|
||||
it('uses global custom validation rules', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: {
|
||||
name: 'test',
|
||||
validation: 'required|globalRule',
|
||||
@ -135,13 +141,15 @@ describe('FormularioInput', () => {
|
||||
})
|
||||
|
||||
it('emits correct validation event', async () => {
|
||||
const wrapper = mount(FormularioInput, { propsData: {
|
||||
name: 'test',
|
||||
validation: 'required',
|
||||
errorBehavior: 'live',
|
||||
value: '',
|
||||
name: 'testinput',
|
||||
} })
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: {
|
||||
validation: 'required',
|
||||
errorBehavior: 'live',
|
||||
value: '',
|
||||
name: 'testinput',
|
||||
}
|
||||
})
|
||||
await flushPromises()
|
||||
const errorObject = wrapper.emitted('validation')[0][0]
|
||||
expect(errorObject).toEqual({
|
||||
@ -159,8 +167,8 @@ describe('FormularioInput', () => {
|
||||
|
||||
it('emits a error-visibility event on blur', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: {
|
||||
name: 'test',
|
||||
validation: 'required',
|
||||
errorBehavior: 'blur',
|
||||
value: '',
|
||||
@ -178,21 +186,23 @@ describe('FormularioInput', () => {
|
||||
})
|
||||
|
||||
it('emits error-visibility event immediately when live', async () => {
|
||||
const wrapper = mount(FormularioInput, { propsData: {
|
||||
name: 'test',
|
||||
validation: 'required',
|
||||
errorBehavior: 'live',
|
||||
value: '',
|
||||
name: 'testinput',
|
||||
} })
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: {
|
||||
validation: 'required',
|
||||
errorBehavior: 'live',
|
||||
value: '',
|
||||
name: 'testinput',
|
||||
}
|
||||
})
|
||||
await flushPromises()
|
||||
expect(wrapper.emitted('error-visibility').length).toBe(1)
|
||||
})
|
||||
|
||||
it('Does not emit an error-visibility event if visibility did not change', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: {
|
||||
name: 'test',
|
||||
validation: 'in:xyz',
|
||||
errorBehavior: 'live',
|
||||
value: 'bar',
|
||||
@ -211,6 +221,7 @@ describe('FormularioInput', () => {
|
||||
|
||||
it('can bail on validation when encountering the bail rule', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: { name: 'test', validation: 'bail|required|in:xyz', errorBehavior: 'live' }
|
||||
})
|
||||
await flushPromises();
|
||||
@ -219,6 +230,7 @@ describe('FormularioInput', () => {
|
||||
|
||||
it('can show multiple validation errors if they occur before the bail rule', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: { name: 'test', validation: 'required|in:xyz|bail', errorBehavior: 'live' }
|
||||
})
|
||||
await flushPromises();
|
||||
@ -227,6 +239,7 @@ describe('FormularioInput', () => {
|
||||
|
||||
it('can avoid bail behavior by using modifier', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: { name: 'test', validation: '^required|in:xyz|min:10,length', errorBehavior: 'live', value: '123' }
|
||||
})
|
||||
await flushPromises();
|
||||
@ -235,6 +248,7 @@ describe('FormularioInput', () => {
|
||||
|
||||
it('prevents later error messages when modified rule fails', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: { name: 'test', validation: '^required|in:xyz|min:10,length', errorBehavior: 'live' }
|
||||
})
|
||||
await flushPromises();
|
||||
@ -243,6 +257,7 @@ describe('FormularioInput', () => {
|
||||
|
||||
it('can bail in the middle of the rule set with a modifier', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: { name: 'test', validation: 'required|^in:xyz|min:10,length', errorBehavior: 'live' }
|
||||
})
|
||||
await flushPromises();
|
||||
@ -251,6 +266,7 @@ describe('FormularioInput', () => {
|
||||
|
||||
it('does not show errors on blur when set error-behavior is submit', async () => {
|
||||
const wrapper = mount(FormularioInput, {
|
||||
localVue,
|
||||
propsData: {
|
||||
validation: 'required',
|
||||
errorBehavior: 'submit',
|
||||
@ -275,6 +291,7 @@ describe('FormularioInput', () => {
|
||||
|
||||
it('displays errors when error-behavior is submit and form is submitted', async () => {
|
||||
const wrapper = mount(FormularioForm, {
|
||||
localVue,
|
||||
propsData: {name: 'test'},
|
||||
slots: {
|
||||
default: `
|
||||
|
76
yarn.lock
76
yarn.lock
@ -1729,6 +1729,15 @@
|
||||
sass "^1.18.0"
|
||||
stylus "^0.54.5"
|
||||
|
||||
"@vue/eslint-config-standard@^5.1.2":
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@vue/eslint-config-standard/-/eslint-config-standard-5.1.2.tgz#c5d55af894a3ae23b65b1af4a425777ac0170b42"
|
||||
integrity sha512-FTz0k77dIrj9r3xskt9jsZyL/YprrLiPRf4m3k7G6dZ5PKuD6OPqYrHR9eduUmHDFpTlRgFpTVQrq+1el9k3QQ==
|
||||
dependencies:
|
||||
eslint-config-standard "^14.1.0"
|
||||
eslint-import-resolver-node "^0.3.3"
|
||||
eslint-import-resolver-webpack "^0.12.1"
|
||||
|
||||
"@vue/preload-webpack-plugin@^1.1.0":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.1.tgz#18723530d304f443021da2292d6ec9502826104a"
|
||||
@ -2158,6 +2167,11 @@ array-equal@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
|
||||
integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=
|
||||
|
||||
array-find@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8"
|
||||
integrity sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=
|
||||
|
||||
array-flatten@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
||||
@ -4186,6 +4200,15 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
enhanced-resolve@^0.9.1:
|
||||
version "0.9.1"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e"
|
||||
integrity sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
memory-fs "^0.2.0"
|
||||
tapable "^0.1.8"
|
||||
|
||||
enhanced-resolve@^4.1.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66"
|
||||
@ -4279,6 +4302,11 @@ eslint-config-standard@^12.0.0:
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz#638b4c65db0bd5a41319f96bba1f15ddad2107d9"
|
||||
integrity sha512-COUz8FnXhqFitYj4DTqHzidjIL/t4mumGZto5c7DrBpvWoie+Sn3P4sLEzUGeYhRElWuFEf8K1S1EfvD1vixCQ==
|
||||
|
||||
eslint-config-standard@^14.1.0:
|
||||
version "14.1.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea"
|
||||
integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg==
|
||||
|
||||
eslint-import-resolver-node@^0.3.2:
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404"
|
||||
@ -4287,6 +4315,30 @@ eslint-import-resolver-node@^0.3.2:
|
||||
debug "^2.6.9"
|
||||
resolve "^1.13.1"
|
||||
|
||||
eslint-import-resolver-node@^0.3.3:
|
||||
version "0.3.4"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
|
||||
integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==
|
||||
dependencies:
|
||||
debug "^2.6.9"
|
||||
resolve "^1.13.1"
|
||||
|
||||
eslint-import-resolver-webpack@^0.12.1:
|
||||
version "0.12.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.12.2.tgz#769e86cd0c752a1536c19855ebd90aa14ce384ee"
|
||||
integrity sha512-7Jnm4YAoNNkvqPaZkKdIHsKGmv8/uNnYC5QsXkiSodvX4XEEfH2AKOna98FK52fCDXm3q4HzuX+7pRMKkJ64EQ==
|
||||
dependencies:
|
||||
array-find "^1.0.0"
|
||||
debug "^2.6.9"
|
||||
enhanced-resolve "^0.9.1"
|
||||
find-root "^1.1.0"
|
||||
has "^1.0.3"
|
||||
interpret "^1.2.0"
|
||||
lodash "^4.17.15"
|
||||
node-libs-browser "^1.0.0 || ^2.0.0"
|
||||
resolve "^1.13.1"
|
||||
semver "^5.7.1"
|
||||
|
||||
eslint-loader@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.2.1.tgz#28b9c12da54057af0845e2a6112701a2f6bf8337"
|
||||
@ -4881,6 +4933,11 @@ find-cache-dir@^3.0.0, find-cache-dir@^3.3.1:
|
||||
make-dir "^3.0.2"
|
||||
pkg-dir "^4.1.0"
|
||||
|
||||
find-root@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
|
||||
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
|
||||
|
||||
find-up@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
|
||||
@ -5691,6 +5748,11 @@ internal-ip@^4.3.0:
|
||||
default-gateway "^4.2.0"
|
||||
ipaddr.js "^1.9.0"
|
||||
|
||||
interpret@^1.2.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
|
||||
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
|
||||
|
||||
invariant@^2.2.2, invariant@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
|
||||
@ -7006,6 +7068,11 @@ media-typer@0.3.0:
|
||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
|
||||
|
||||
memory-fs@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290"
|
||||
integrity sha1-8rslNovBIeORwlIN6Slpyu4KApA=
|
||||
|
||||
memory-fs@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
|
||||
@ -7357,7 +7424,7 @@ node-ipc@^9.1.1:
|
||||
js-message "1.0.5"
|
||||
js-queue "2.0.0"
|
||||
|
||||
node-libs-browser@^2.2.1:
|
||||
"node-libs-browser@^1.0.0 || ^2.0.0", node-libs-browser@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
|
||||
integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==
|
||||
@ -9361,7 +9428,7 @@ selfsigned@^1.10.7:
|
||||
dependencies:
|
||||
node-forge "0.9.0"
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.1:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
@ -10064,6 +10131,11 @@ table@^5.2.3:
|
||||
slice-ansi "^2.1.0"
|
||||
string-width "^3.0.0"
|
||||
|
||||
tapable@^0.1.8:
|
||||
version "0.1.10"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4"
|
||||
integrity sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=
|
||||
|
||||
tapable@^1.0.0, tapable@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
|
||||
|
Loading…
Reference in New Issue
Block a user