UNPKG

4.63 kBJavaScriptView Raw
1// This is the only way I've been able to copy the ValidityState object.
2function extractValidity(el) {
3 const validity = el.validity
4
5 // VaidityState.tooShort/minlength polyfill for older browsers.
6 let tooShort = validity.tooShort
7 let valid = validity.valid
8 const minlength = el.getAttribute('minlength')
9 if (minlength && typeof tooShort === 'undefined') {
10 tooShort = el.value.length < minlength
11 if (tooShort) {
12 valid = false
13 el.setCustomValidity(`
14 Please lengthen this text to ${minlength} characters or more (you are
15 currently using ${el.value.length} characters).
16 `.trim())
17 } else {
18 el.setCustomValidity('')
19 }
20 }
21
22 return {
23 badInput: validity.badInput,
24 customError: validity.customError,
25 patternMismatch: validity.patternMismatch,
26 rangeOverflow: validity.rangeOverflow,
27 rangeUnderflow: validity.rangeUnderflow,
28 stepMismatch: validity.stepMismatch,
29 tooLong: validity.tooLong,
30 tooShort,
31 typeMismatch: validity.typeMismatch,
32 valid,
33 valueMissing: validity.valueMissing,
34 }
35}
36
37export default class VueForm {
38 constructor (options = {
39 wasFocusedClass: 'wasFocused',
40 wasSubmittedClass: 'wasSubmitted',
41 noValidate: true
42 }) {
43 this.$noValidate = options.noValidate
44 this.$wasFocusedClass = options.wasFocusedClass
45 this.$wasSubmittedClass = options.wasSubmittedClass
46 this.$wasSubmitted = false
47 this.$isInvalid = false
48 this.$isValid = true
49 this.$invalidFields = []
50 }
51
52 static install (Vue) {
53 // v-form directive.
54 Vue.directive('form', {
55 bind (el, { value }) {
56 value.$el = el
57 value.$el.noValidate = value.$noValidate
58
59 //
60 value.$el.addEventListener('submit', () => {
61 value.$wasSubmitted = true
62 value.$el.classList.add(value.$wasSubmittedClass)
63 })
64
65 value.$el.addEventListener('reset', () => {
66 // Reset $wasSubmitted property.
67 value.$wasSubmitted = false
68 value.$el.classList.remove(value.$wasSubmittedClass)
69
70 // Reset $wasFocused property and remove the corresponding class
71 // from each child node.
72 for (const id of Object.keys(value)) {
73 if (id.indexOf('$') === -1) {
74 value[id].$wasFocused = false
75 value[id].$el.classList.remove(value.$wasFocusedClass)
76 Object.assign(value[id], extractValidity(value[id].$el))
77 value.$updateFormValidity(id)
78 }
79 }
80 })
81
82 for (const $el of el.querySelectorAll('input, textarea, select')) {
83 //
84 if ($el.form === el && $el.willValidate && $el.hasAttribute('id')) {
85 //
86 const field = Object.assign({ $el }, extractValidity($el))
87 const id = $el.getAttribute('id')
88 Vue.set(value, id, field)
89 value.$updateFormValidity(id)
90
91 // Add wasFocused class to element when focus event is triggered.
92 $el.addEventListener('focus', ({ target }) => {
93 const id = $el.getAttribute('id')
94 value[id].$wasFocused = true
95 target.classList.add(value.$wasFocusedClass)
96 })
97
98 $el.addEventListener('input', ({ target }) => {
99 const id = target.getAttribute('id')
100 Object.assign(value[id], extractValidity(target))
101 value.$updateFormValidity(id)
102 })
103 }
104 }
105 }
106 })
107 }
108
109 $setCustomValidity (field, invalid) {
110 if (this[field]) {
111 const isBoolean = typeof invalid === 'boolean'
112 const isNonEmptyString = typeof invalid === 'string' && invalid.length > 0
113 if (invalid && (isBoolean || isNonEmptyString)) {
114 if (isNonEmptyString) {
115 this[field].customMessage = invalid
116 this[field].$el.setCustomValidity(invalid)
117 } else {
118 this[field].$el.setCustomValidity('Error')
119 }
120 } else {
121 delete this[field].customMessage
122 this[field].$el.setCustomValidity('')
123 }
124 Object.assign(this[field], extractValidity(this[field].$el))
125 this.$updateFormValidity(field)
126 }
127 }
128
129 $updateFormValidity (field) {
130 const index = this.$invalidFields.indexOf(field)
131 if (this[field].valid && index !== -1) {
132 this.$invalidFields.splice(index, 1)
133 if (this.$invalidFields.length === 0) {
134 this.$isValid = true
135 this.$isInvalid = false
136 }
137 } else if (!this[field].valid && index === -1) {
138 this.$isValid = false
139 this.$isInvalid = true
140 this.$invalidFields.push(field)
141 }
142 }
143}