UNPKG

4.6 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 $updateCustomValidity (field, result) {
110 if (result) {
111 if (result && typeof result === 'string') {
112 this[field].$el.setCustomValidity(result)
113 this[field].customErrorMessage = result
114 } else {
115 if (result.valid) {
116 this[field].$el.setCustomValidity('')
117 } else {
118 this[field].$el.setCustomValidity('Multiple errors')
119 }
120 Object.assign(this[field], result)
121 }
122 } else {
123 this[field].$el.setCustomValidity('')
124 this[field].customErrorMessage = null
125 }
126 Object.assign(this[field], extractValidity(this[field].$el))
127 this.$updateFormValidity(field)
128 }
129
130 $updateFormValidity (field) {
131 const index = this.$invalidFields.indexOf(field)
132 if (this[field].valid && index !== -1) {
133 this.$invalidFields.splice(index, 1)
134 if (this.$invalidFields.length === 0) {
135 this.$isValid = true
136 this.$isInvalid = false
137 }
138 } else if (!this[field].valid && index === -1) {
139 this.$isValid = false
140 this.$isInvalid = true
141 this.$invalidFields.push(field)
142 }
143 }
144}