@gitlab/ui 132.2.1 → 133.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/base/dropdown/dropdown_item.js +1 -1
- package/dist/components/base/form/form_input/form_input.js +2 -60
- package/dist/components/base/form/form_textarea/form_textarea.js +421 -45
- package/dist/components/base/new_dropdowns/listbox/listbox_item.js +1 -1
- package/dist/vendor/bootstrap-vue/src/constants/components.js +1 -2
- package/package.json +1 -1
- package/src/components/base/dropdown/dropdown_item.vue +1 -1
- package/src/components/base/form/form_input/form_input.vue +2 -60
- package/src/components/base/form/form_textarea/form_textarea.vue +462 -49
- package/src/components/base/new_dropdowns/listbox/listbox_item.vue +1 -1
- package/src/vendor/bootstrap-vue/src/constants/components.js +0 -1
- package/dist/vendor/bootstrap-vue/src/components/form-textarea/form-textarea.js +0 -233
- package/dist/vendor/bootstrap-vue/src/components/form-textarea/index.js +0 -1
- package/dist/vendor/bootstrap-vue/src/mixins/form-selection.js +0 -62
- package/dist/vendor/bootstrap-vue/src/mixins/form-text.js +0 -279
- package/dist/vendor/bootstrap-vue/src/mixins/form-validity.js +0 -50
- package/src/vendor/bootstrap-vue/src/components/form-textarea/form-textarea.js +0 -241
- package/src/vendor/bootstrap-vue/src/components/form-textarea/index.js +0 -3
- package/src/vendor/bootstrap-vue/src/mixins/form-selection.js +0 -60
- package/src/vendor/bootstrap-vue/src/mixins/form-text.js +0 -280
- package/src/vendor/bootstrap-vue/src/mixins/form-validity.js +0 -48
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
import { extend } from '../../vue'
|
|
2
|
-
import { NAME_FORM_TEXTAREA } from '../../constants/components'
|
|
3
|
-
import { getCS, getStyle, isVisible, requestAF, setStyle } from '../../utils/dom'
|
|
4
|
-
import { isNull } from '../../utils/inspect'
|
|
5
|
-
import { mathCeil, mathMax, mathMin } from '../../utils/math'
|
|
6
|
-
import { toInteger, toFloat } from '../../utils/number'
|
|
7
|
-
import { sortKeys } from '../../utils/object'
|
|
8
|
-
import { formControlMixin, props as formControlProps } from '../../mixins/form-control'
|
|
9
|
-
import { formSelectionMixin } from '../../mixins/form-selection'
|
|
10
|
-
import { formSizeMixin, props as formSizeProps } from '../../mixins/form-size'
|
|
11
|
-
import { formStateMixin, props as formStateProps } from '../../mixins/form-state'
|
|
12
|
-
import { formTextMixin, props as formTextProps } from '../../mixins/form-text'
|
|
13
|
-
import { formValidityMixin } from '../../mixins/form-validity'
|
|
14
|
-
import { idMixin, props as idProps } from '../../mixins/id'
|
|
15
|
-
import { listenOnRootMixin } from '../../mixins/listen-on-root'
|
|
16
|
-
import { listenersMixin } from '../../mixins/listeners'
|
|
17
|
-
import { VBVisible } from '../../directives/visible/visible'
|
|
18
|
-
|
|
19
|
-
// --- Props ---
|
|
20
|
-
|
|
21
|
-
export const props = sortKeys({
|
|
22
|
-
...idProps,
|
|
23
|
-
...formControlProps,
|
|
24
|
-
...formSizeProps,
|
|
25
|
-
...formStateProps,
|
|
26
|
-
...formTextProps,
|
|
27
|
-
maxRows: {
|
|
28
|
-
type: [Number, String],
|
|
29
|
-
required: false,
|
|
30
|
-
default: undefined
|
|
31
|
-
},
|
|
32
|
-
// When in auto resize mode, disable shrinking to content height
|
|
33
|
-
noAutoShrink: {
|
|
34
|
-
type: Boolean,
|
|
35
|
-
required: false,
|
|
36
|
-
default: false
|
|
37
|
-
},
|
|
38
|
-
// Disable the resize handle of textarea
|
|
39
|
-
noResize: {
|
|
40
|
-
type: Boolean,
|
|
41
|
-
required: false,
|
|
42
|
-
default: false
|
|
43
|
-
},
|
|
44
|
-
rows: {
|
|
45
|
-
type: [Number, String],
|
|
46
|
-
required: false,
|
|
47
|
-
default: 2
|
|
48
|
-
},
|
|
49
|
-
// 'soft', 'hard' or 'off'
|
|
50
|
-
// Browser default is 'soft'
|
|
51
|
-
wrap: {
|
|
52
|
-
type: String,
|
|
53
|
-
required: false,
|
|
54
|
-
default: 'soft'
|
|
55
|
-
}
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
// --- Main component ---
|
|
59
|
-
|
|
60
|
-
// @vue/component
|
|
61
|
-
export const BFormTextarea = /*#__PURE__*/ extend({
|
|
62
|
-
name: NAME_FORM_TEXTAREA,
|
|
63
|
-
directives: {
|
|
64
|
-
'b-visible': VBVisible
|
|
65
|
-
},
|
|
66
|
-
// Mixin order is important!
|
|
67
|
-
mixins: [
|
|
68
|
-
listenersMixin,
|
|
69
|
-
idMixin,
|
|
70
|
-
listenOnRootMixin,
|
|
71
|
-
formControlMixin,
|
|
72
|
-
formSizeMixin,
|
|
73
|
-
formStateMixin,
|
|
74
|
-
formTextMixin,
|
|
75
|
-
formSelectionMixin,
|
|
76
|
-
formValidityMixin
|
|
77
|
-
],
|
|
78
|
-
props,
|
|
79
|
-
data() {
|
|
80
|
-
return {
|
|
81
|
-
heightInPx: null
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
computed: {
|
|
85
|
-
type() {
|
|
86
|
-
return null
|
|
87
|
-
},
|
|
88
|
-
computedStyle() {
|
|
89
|
-
const styles = {
|
|
90
|
-
// Setting `noResize` to true will disable the ability for the user to
|
|
91
|
-
// manually resize the textarea. We also disable when in auto height mode
|
|
92
|
-
resize: !this.computedRows || this.noResize ? 'none' : null
|
|
93
|
-
}
|
|
94
|
-
if (!this.computedRows) {
|
|
95
|
-
// Conditionally set the computed CSS height when auto rows/height is enabled
|
|
96
|
-
// We avoid setting the style to `null`, which can override user manual resize handle
|
|
97
|
-
styles.height = this.heightInPx
|
|
98
|
-
// We always add a vertical scrollbar to the textarea when auto-height is
|
|
99
|
-
// enabled so that the computed height calculation returns a stable value
|
|
100
|
-
styles.overflowY = 'scroll'
|
|
101
|
-
}
|
|
102
|
-
return styles
|
|
103
|
-
},
|
|
104
|
-
computedMinRows() {
|
|
105
|
-
// Ensure rows is at least 2 and positive (2 is the native textarea value)
|
|
106
|
-
// A value of 1 can cause issues in some browsers, and most browsers
|
|
107
|
-
// only support 2 as the smallest value
|
|
108
|
-
return mathMax(toInteger(this.rows, 2), 2)
|
|
109
|
-
},
|
|
110
|
-
computedMaxRows() {
|
|
111
|
-
return mathMax(this.computedMinRows, toInteger(this.maxRows, 0))
|
|
112
|
-
},
|
|
113
|
-
computedRows() {
|
|
114
|
-
// This is used to set the attribute 'rows' on the textarea
|
|
115
|
-
// If auto-height is enabled, then we return `null` as we use CSS to control height
|
|
116
|
-
return this.computedMinRows === this.computedMaxRows ? this.computedMinRows : null
|
|
117
|
-
},
|
|
118
|
-
computedAttrs() {
|
|
119
|
-
const { disabled, required } = this
|
|
120
|
-
|
|
121
|
-
return {
|
|
122
|
-
id: this.safeId(),
|
|
123
|
-
name: this.name || null,
|
|
124
|
-
form: this.form || null,
|
|
125
|
-
disabled,
|
|
126
|
-
placeholder: this.placeholder || null,
|
|
127
|
-
required,
|
|
128
|
-
autocomplete: this.autocomplete || null,
|
|
129
|
-
readonly: this.readonly || this.plaintext,
|
|
130
|
-
rows: this.computedRows,
|
|
131
|
-
wrap: this.wrap || null,
|
|
132
|
-
'aria-required': this.required ? 'true' : null,
|
|
133
|
-
'aria-invalid': this.computedAriaInvalid
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
computedListeners() {
|
|
137
|
-
return {
|
|
138
|
-
...this.bvListeners,
|
|
139
|
-
input: this.onInput,
|
|
140
|
-
change: this.onChange,
|
|
141
|
-
blur: this.onBlur
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
watch: {
|
|
146
|
-
localValue() {
|
|
147
|
-
this.setHeight()
|
|
148
|
-
}
|
|
149
|
-
},
|
|
150
|
-
mounted() {
|
|
151
|
-
this.setHeight()
|
|
152
|
-
},
|
|
153
|
-
methods: {
|
|
154
|
-
// Called by intersection observer directive
|
|
155
|
-
/* istanbul ignore next */
|
|
156
|
-
visibleCallback(visible) {
|
|
157
|
-
if (visible) {
|
|
158
|
-
// We use a `$nextTick()` here just to make sure any
|
|
159
|
-
// transitions or portalling have completed
|
|
160
|
-
this.$nextTick(this.setHeight)
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
setHeight() {
|
|
164
|
-
this.$nextTick(() => {
|
|
165
|
-
requestAF(() => {
|
|
166
|
-
this.heightInPx = this.computeHeight()
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
},
|
|
170
|
-
/* istanbul ignore next: can't test getComputedStyle in JSDOM */
|
|
171
|
-
computeHeight() {
|
|
172
|
-
if (this.$isServer || !isNull(this.computedRows)) {
|
|
173
|
-
return null
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const el = this.$el
|
|
177
|
-
|
|
178
|
-
// Element must be visible (not hidden) and in document
|
|
179
|
-
// Must be checked after above checks
|
|
180
|
-
if (!isVisible(el)) {
|
|
181
|
-
return null
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Get current computed styles
|
|
185
|
-
const computedStyle = getCS(el)
|
|
186
|
-
// Height of one line of text in px
|
|
187
|
-
const lineHeight = toFloat(computedStyle.lineHeight, 1)
|
|
188
|
-
// Calculate height of border and padding
|
|
189
|
-
const border =
|
|
190
|
-
toFloat(computedStyle.borderTopWidth, 0) + toFloat(computedStyle.borderBottomWidth, 0)
|
|
191
|
-
const padding = toFloat(computedStyle.paddingTop, 0) + toFloat(computedStyle.paddingBottom, 0)
|
|
192
|
-
// Calculate offset
|
|
193
|
-
const offset = border + padding
|
|
194
|
-
// Minimum height for min rows (which must be 2 rows or greater for cross-browser support)
|
|
195
|
-
const minHeight = lineHeight * this.computedMinRows + offset
|
|
196
|
-
|
|
197
|
-
// Get the current style height (with `px` units)
|
|
198
|
-
const oldHeight = getStyle(el, 'height') || computedStyle.height
|
|
199
|
-
// Probe scrollHeight by temporarily changing the height to `auto`
|
|
200
|
-
setStyle(el, 'height', 'auto')
|
|
201
|
-
const scrollHeight = el.scrollHeight
|
|
202
|
-
// Place the original old height back on the element, just in case `computedProp`
|
|
203
|
-
// returns the same value as before
|
|
204
|
-
setStyle(el, 'height', oldHeight)
|
|
205
|
-
|
|
206
|
-
// Calculate content height in 'rows' (scrollHeight includes padding but not border)
|
|
207
|
-
const contentRows = mathMax((scrollHeight - padding) / lineHeight, 2)
|
|
208
|
-
// Calculate number of rows to display (limited within min/max rows)
|
|
209
|
-
const rows = mathMin(mathMax(contentRows, this.computedMinRows), this.computedMaxRows)
|
|
210
|
-
// Calculate the required height of the textarea including border and padding (in pixels)
|
|
211
|
-
const height = mathMax(mathCeil(rows * lineHeight + offset), minHeight)
|
|
212
|
-
|
|
213
|
-
// Computed height remains the larger of `oldHeight` and new `height`,
|
|
214
|
-
// when height is in `sticky` mode (prop `no-auto-shrink` is true)
|
|
215
|
-
if (this.noAutoShrink && toFloat(oldHeight, 0) > height) {
|
|
216
|
-
return oldHeight
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Return the new computed CSS height in px units
|
|
220
|
-
return `${height}px`
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
render(h) {
|
|
224
|
-
return h('textarea', {
|
|
225
|
-
class: this.computedClass,
|
|
226
|
-
style: this.computedStyle,
|
|
227
|
-
directives: [
|
|
228
|
-
{
|
|
229
|
-
name: 'b-visible',
|
|
230
|
-
value: this.visibleCallback,
|
|
231
|
-
// If textarea is within 640px of viewport, consider it visible
|
|
232
|
-
modifiers: { '640': true }
|
|
233
|
-
}
|
|
234
|
-
],
|
|
235
|
-
attrs: this.computedAttrs,
|
|
236
|
-
domProps: { value: this.localValue },
|
|
237
|
-
on: this.computedListeners,
|
|
238
|
-
ref: 'input'
|
|
239
|
-
})
|
|
240
|
-
}
|
|
241
|
-
})
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { extend } from '../vue'
|
|
2
|
-
|
|
3
|
-
// @vue/component
|
|
4
|
-
export const formSelectionMixin = extend({
|
|
5
|
-
computed: {
|
|
6
|
-
selectionStart: {
|
|
7
|
-
// Expose selectionStart for formatters, etc
|
|
8
|
-
cache: false,
|
|
9
|
-
/* istanbul ignore next */
|
|
10
|
-
get() {
|
|
11
|
-
return this.$refs.input.selectionStart
|
|
12
|
-
},
|
|
13
|
-
/* istanbul ignore next */
|
|
14
|
-
set(val) {
|
|
15
|
-
this.$refs.input.selectionStart = val
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
selectionEnd: {
|
|
19
|
-
// Expose selectionEnd for formatters, etc
|
|
20
|
-
cache: false,
|
|
21
|
-
/* istanbul ignore next */
|
|
22
|
-
get() {
|
|
23
|
-
return this.$refs.input.selectionEnd
|
|
24
|
-
},
|
|
25
|
-
/* istanbul ignore next */
|
|
26
|
-
set(val) {
|
|
27
|
-
this.$refs.input.selectionEnd = val
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
selectionDirection: {
|
|
31
|
-
// Expose selectionDirection for formatters, etc
|
|
32
|
-
cache: false,
|
|
33
|
-
/* istanbul ignore next */
|
|
34
|
-
get() {
|
|
35
|
-
return this.$refs.input.selectionDirection
|
|
36
|
-
},
|
|
37
|
-
/* istanbul ignore next */
|
|
38
|
-
set(val) {
|
|
39
|
-
this.$refs.input.selectionDirection = val
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
methods: {
|
|
44
|
-
/* istanbul ignore next */
|
|
45
|
-
select() {
|
|
46
|
-
// For external handler that may want a select() method
|
|
47
|
-
this.$refs.input.select(...arguments)
|
|
48
|
-
},
|
|
49
|
-
/* istanbul ignore next */
|
|
50
|
-
setSelectionRange() {
|
|
51
|
-
// For external handler that may want a setSelectionRange(a,b,c) method
|
|
52
|
-
this.$refs.input.setSelectionRange(...arguments)
|
|
53
|
-
},
|
|
54
|
-
/* istanbul ignore next */
|
|
55
|
-
setRangeText() {
|
|
56
|
-
// For external handler that may want a setRangeText(a,b,c) method
|
|
57
|
-
this.$refs.input.setRangeText(...arguments)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
})
|
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
import { extend } from '../vue'
|
|
2
|
-
import {
|
|
3
|
-
EVENT_NAME_BLUR,
|
|
4
|
-
EVENT_NAME_CHANGE,
|
|
5
|
-
EVENT_NAME_INPUT,
|
|
6
|
-
EVENT_NAME_UPDATE
|
|
7
|
-
} from '../constants/events'
|
|
8
|
-
import { attemptBlur, attemptFocus } from '../utils/dom'
|
|
9
|
-
import { stopEvent } from '../utils/events'
|
|
10
|
-
import { mathMax } from '../utils/math'
|
|
11
|
-
import { toInteger, toFloat } from '../utils/number'
|
|
12
|
-
import { sortKeys } from '../utils/object'
|
|
13
|
-
import { isFunction } from '../utils/inspect'
|
|
14
|
-
import { toString } from '../utils/string'
|
|
15
|
-
|
|
16
|
-
// --- Constants ---
|
|
17
|
-
|
|
18
|
-
const MODEL_PROP_NAME = 'value'
|
|
19
|
-
const MODEL_EVENT_NAME = EVENT_NAME_UPDATE
|
|
20
|
-
|
|
21
|
-
// --- Props ---
|
|
22
|
-
|
|
23
|
-
export const props = sortKeys({
|
|
24
|
-
[MODEL_PROP_NAME]: {
|
|
25
|
-
type: [Number, String],
|
|
26
|
-
default: ''
|
|
27
|
-
},
|
|
28
|
-
ariaInvalid: {
|
|
29
|
-
type: [Boolean, String],
|
|
30
|
-
required: false,
|
|
31
|
-
default: false
|
|
32
|
-
},
|
|
33
|
-
autocomplete: {
|
|
34
|
-
type: String,
|
|
35
|
-
required: false,
|
|
36
|
-
default: undefined
|
|
37
|
-
},
|
|
38
|
-
// Debounce timeout (in ms). Not applicable with `lazy` prop
|
|
39
|
-
debounce: {
|
|
40
|
-
type: [Number, String],
|
|
41
|
-
required: false,
|
|
42
|
-
default: 0
|
|
43
|
-
},
|
|
44
|
-
formatter: {
|
|
45
|
-
type: Function,
|
|
46
|
-
required: false,
|
|
47
|
-
default: undefined
|
|
48
|
-
},
|
|
49
|
-
// Only update the `v-model` on blur/change events
|
|
50
|
-
lazy: {
|
|
51
|
-
type: Boolean,
|
|
52
|
-
required: false,
|
|
53
|
-
default: false
|
|
54
|
-
},
|
|
55
|
-
lazyFormatter: {
|
|
56
|
-
type: Boolean,
|
|
57
|
-
required: false,
|
|
58
|
-
default: false
|
|
59
|
-
},
|
|
60
|
-
number: {
|
|
61
|
-
type: Boolean,
|
|
62
|
-
required: false,
|
|
63
|
-
default: false
|
|
64
|
-
},
|
|
65
|
-
placeholder: {
|
|
66
|
-
type: String,
|
|
67
|
-
required: false,
|
|
68
|
-
default: undefined
|
|
69
|
-
},
|
|
70
|
-
plaintext: {
|
|
71
|
-
type: Boolean,
|
|
72
|
-
required: false,
|
|
73
|
-
default: false
|
|
74
|
-
},
|
|
75
|
-
readonly: {
|
|
76
|
-
type: Boolean,
|
|
77
|
-
required: false,
|
|
78
|
-
default: false
|
|
79
|
-
},
|
|
80
|
-
trim: {
|
|
81
|
-
type: Boolean,
|
|
82
|
-
required: false,
|
|
83
|
-
default: false
|
|
84
|
-
}
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
// --- Mixin ---
|
|
88
|
-
|
|
89
|
-
// @vue/component
|
|
90
|
-
export const formTextMixin = extend({
|
|
91
|
-
model: {
|
|
92
|
-
prop: MODEL_PROP_NAME,
|
|
93
|
-
event: MODEL_EVENT_NAME
|
|
94
|
-
},
|
|
95
|
-
props,
|
|
96
|
-
data() {
|
|
97
|
-
const value = this[MODEL_PROP_NAME]
|
|
98
|
-
return {
|
|
99
|
-
localValue: toString(value),
|
|
100
|
-
vModelValue: this.modifyValue(value)
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
computed: {
|
|
104
|
-
computedClass() {
|
|
105
|
-
const { plaintext, type } = this
|
|
106
|
-
const isRange = type === 'range'
|
|
107
|
-
const isColor = type === 'color'
|
|
108
|
-
|
|
109
|
-
return [
|
|
110
|
-
{
|
|
111
|
-
// Range input needs class `custom-range`
|
|
112
|
-
'custom-range': isRange,
|
|
113
|
-
// `plaintext` not supported by `type="range"` or `type="color"`
|
|
114
|
-
'form-control-plaintext': plaintext && !isRange && !isColor,
|
|
115
|
-
// `form-control` not used by `type="range"` or `plaintext`
|
|
116
|
-
// Always used by `type="color"`
|
|
117
|
-
'form-control': isColor || (!plaintext && !isRange)
|
|
118
|
-
},
|
|
119
|
-
this.sizeFormClass,
|
|
120
|
-
this.stateClass
|
|
121
|
-
]
|
|
122
|
-
},
|
|
123
|
-
computedDebounce() {
|
|
124
|
-
// Ensure we have a positive number equal to or greater than 0
|
|
125
|
-
return mathMax(toInteger(this.debounce, 0), 0)
|
|
126
|
-
},
|
|
127
|
-
hasFormatter() {
|
|
128
|
-
// `formatter` is an optional Function prop with no default
|
|
129
|
-
return isFunction(this.formatter)
|
|
130
|
-
}
|
|
131
|
-
},
|
|
132
|
-
watch: {
|
|
133
|
-
[MODEL_PROP_NAME](newValue) {
|
|
134
|
-
const stringifyValue = toString(newValue)
|
|
135
|
-
const modifiedValue = this.modifyValue(newValue)
|
|
136
|
-
if (stringifyValue !== this.localValue || modifiedValue !== this.vModelValue) {
|
|
137
|
-
// Clear any pending debounce timeout, as we are overwriting the user input
|
|
138
|
-
this.clearDebounce()
|
|
139
|
-
// Update the local values
|
|
140
|
-
this.localValue = stringifyValue
|
|
141
|
-
this.vModelValue = modifiedValue
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
created() {
|
|
146
|
-
// Create private non-reactive props
|
|
147
|
-
this.$_inputDebounceTimer = null
|
|
148
|
-
},
|
|
149
|
-
beforeDestroy() {
|
|
150
|
-
this.clearDebounce()
|
|
151
|
-
},
|
|
152
|
-
methods: {
|
|
153
|
-
clearDebounce() {
|
|
154
|
-
clearTimeout(this.$_inputDebounceTimer)
|
|
155
|
-
this.$_inputDebounceTimer = null
|
|
156
|
-
},
|
|
157
|
-
formatValue(value, event, force = false) {
|
|
158
|
-
value = toString(value)
|
|
159
|
-
if (this.hasFormatter && (!this.lazyFormatter || force)) {
|
|
160
|
-
value = this.formatter(value, event)
|
|
161
|
-
}
|
|
162
|
-
return value
|
|
163
|
-
},
|
|
164
|
-
modifyValue(value) {
|
|
165
|
-
value = toString(value)
|
|
166
|
-
// Emulate `.trim` modifier behaviour
|
|
167
|
-
if (this.trim) {
|
|
168
|
-
value = value.trim()
|
|
169
|
-
}
|
|
170
|
-
// Emulate `.number` modifier behaviour
|
|
171
|
-
if (this.number) {
|
|
172
|
-
value = toFloat(value, value)
|
|
173
|
-
}
|
|
174
|
-
return value
|
|
175
|
-
},
|
|
176
|
-
updateValue(value, force = false) {
|
|
177
|
-
const { lazy } = this
|
|
178
|
-
if (lazy && !force) {
|
|
179
|
-
return
|
|
180
|
-
}
|
|
181
|
-
// Make sure to always clear the debounce when `updateValue()`
|
|
182
|
-
// is called, even when the v-model hasn't changed
|
|
183
|
-
this.clearDebounce()
|
|
184
|
-
// Define the shared update logic in a method to be able to use
|
|
185
|
-
// it for immediate and debounced value changes
|
|
186
|
-
const doUpdate = () => {
|
|
187
|
-
value = this.modifyValue(value)
|
|
188
|
-
if (value !== this.vModelValue) {
|
|
189
|
-
this.vModelValue = value
|
|
190
|
-
this.$emit(MODEL_EVENT_NAME, value)
|
|
191
|
-
} else if (this.hasFormatter) {
|
|
192
|
-
// When the `vModelValue` hasn't changed but the actual input value
|
|
193
|
-
// is out of sync, make sure to change it to the given one
|
|
194
|
-
// Usually caused by browser autocomplete and how it triggers the
|
|
195
|
-
// change or input event, or depending on the formatter function
|
|
196
|
-
// https://github.com/bootstrap-vue/bootstrap-vue/issues/2657
|
|
197
|
-
// https://github.com/bootstrap-vue/bootstrap-vue/issues/3498
|
|
198
|
-
/* istanbul ignore next: hard to test */
|
|
199
|
-
const $input = this.$refs.input
|
|
200
|
-
/* istanbul ignore if: hard to test out of sync value */
|
|
201
|
-
if ($input && value !== $input.value) {
|
|
202
|
-
$input.value = value
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
// Only debounce the value update when a value greater than `0`
|
|
207
|
-
// is set and we are not in lazy mode or this is a forced update
|
|
208
|
-
const debounce = this.computedDebounce
|
|
209
|
-
if (debounce > 0 && !lazy && !force) {
|
|
210
|
-
this.$_inputDebounceTimer = setTimeout(doUpdate, debounce)
|
|
211
|
-
} else {
|
|
212
|
-
// Immediately update the v-model
|
|
213
|
-
doUpdate()
|
|
214
|
-
}
|
|
215
|
-
},
|
|
216
|
-
onInput(event) {
|
|
217
|
-
// `event.target.composing` is set by Vue
|
|
218
|
-
// https://github.com/vuejs/vue/blob/dev/src/platforms/web/runtime/directives/model.js
|
|
219
|
-
// TODO: Is this needed now with the latest Vue?
|
|
220
|
-
/* istanbul ignore if: hard to test composition events */
|
|
221
|
-
if (event.target.composing) {
|
|
222
|
-
return
|
|
223
|
-
}
|
|
224
|
-
const { value } = event.target
|
|
225
|
-
const formattedValue = this.formatValue(value, event)
|
|
226
|
-
// Exit when the `formatter` function strictly returned `false`
|
|
227
|
-
// or prevented the input event
|
|
228
|
-
/* istanbul ignore next */
|
|
229
|
-
if (formattedValue === false || event.defaultPrevented) {
|
|
230
|
-
stopEvent(event, { propagation: false })
|
|
231
|
-
return
|
|
232
|
-
}
|
|
233
|
-
this.localValue = formattedValue
|
|
234
|
-
this.updateValue(formattedValue)
|
|
235
|
-
this.$emit(EVENT_NAME_INPUT, formattedValue)
|
|
236
|
-
},
|
|
237
|
-
onChange(event) {
|
|
238
|
-
const { value } = event.target
|
|
239
|
-
const formattedValue = this.formatValue(value, event)
|
|
240
|
-
// Exit when the `formatter` function strictly returned `false`
|
|
241
|
-
// or prevented the input event
|
|
242
|
-
/* istanbul ignore next */
|
|
243
|
-
if (formattedValue === false || event.defaultPrevented) {
|
|
244
|
-
stopEvent(event, { propagation: false })
|
|
245
|
-
return
|
|
246
|
-
}
|
|
247
|
-
this.localValue = formattedValue
|
|
248
|
-
this.updateValue(formattedValue, true)
|
|
249
|
-
this.$emit(EVENT_NAME_CHANGE, formattedValue)
|
|
250
|
-
},
|
|
251
|
-
onBlur(event) {
|
|
252
|
-
// Apply the `localValue` on blur to prevent cursor jumps
|
|
253
|
-
// on mobile browsers (e.g. caused by autocomplete)
|
|
254
|
-
const { value } = event.target
|
|
255
|
-
const formattedValue = this.formatValue(value, event, true)
|
|
256
|
-
if (formattedValue !== false) {
|
|
257
|
-
// We need to use the modified value here to apply the
|
|
258
|
-
// `.trim` and `.number` modifiers properly
|
|
259
|
-
this.localValue = toString(this.modifyValue(formattedValue))
|
|
260
|
-
// We pass the formatted value here since the `updateValue` method
|
|
261
|
-
// handles the modifiers itself
|
|
262
|
-
this.updateValue(formattedValue, true)
|
|
263
|
-
}
|
|
264
|
-
// Emit native blur event
|
|
265
|
-
this.$emit(EVENT_NAME_BLUR, event)
|
|
266
|
-
},
|
|
267
|
-
focus() {
|
|
268
|
-
// For external handler that may want a focus method
|
|
269
|
-
if (!this.disabled) {
|
|
270
|
-
attemptFocus(this.$el)
|
|
271
|
-
}
|
|
272
|
-
},
|
|
273
|
-
blur() {
|
|
274
|
-
// For external handler that may want a blur method
|
|
275
|
-
if (!this.disabled) {
|
|
276
|
-
attemptBlur(this.$el)
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
})
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { extend } from '../vue'
|
|
2
|
-
|
|
3
|
-
// @vue/component
|
|
4
|
-
export const formValidityMixin = extend({
|
|
5
|
-
computed: {
|
|
6
|
-
validity: {
|
|
7
|
-
// Expose validity property
|
|
8
|
-
cache: false,
|
|
9
|
-
/* istanbul ignore next */
|
|
10
|
-
get() {
|
|
11
|
-
return this.$refs.input.validity
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
validationMessage: {
|
|
15
|
-
// Expose validationMessage property
|
|
16
|
-
cache: false,
|
|
17
|
-
/* istanbul ignore next */
|
|
18
|
-
get() {
|
|
19
|
-
return this.$refs.input.validationMessage
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
willValidate: {
|
|
23
|
-
// Expose willValidate property
|
|
24
|
-
cache: false,
|
|
25
|
-
/* istanbul ignore next */
|
|
26
|
-
get() {
|
|
27
|
-
return this.$refs.input.willValidate
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
methods: {
|
|
32
|
-
/* istanbul ignore next */
|
|
33
|
-
setCustomValidity() {
|
|
34
|
-
// For external handler that may want a setCustomValidity(...) method
|
|
35
|
-
return this.$refs.input.setCustomValidity(...arguments)
|
|
36
|
-
},
|
|
37
|
-
/* istanbul ignore next */
|
|
38
|
-
checkValidity() {
|
|
39
|
-
// For external handler that may want a checkValidity(...) method
|
|
40
|
-
return this.$refs.input.checkValidity(...arguments)
|
|
41
|
-
},
|
|
42
|
-
/* istanbul ignore next */
|
|
43
|
-
reportValidity() {
|
|
44
|
-
// For external handler that may want a reportValidity(...) method
|
|
45
|
-
return this.$refs.input.reportValidity(...arguments)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
})
|