Skip to content

Commit

Permalink
Bug fixes on v-text-field (#2099)
Browse files Browse the repository at this point in the history
* Bug fixes on v-text-field
1. Resolves #2057
2. Resolves #2096
3. Resolves #2097

* Make way for props.clearable=true

* Removes unneeded sanity check.

* null check on externally set value

* Add conditional setSelectionRange() & anticipate valid null value.

* Allow null value & v-model.number config + handle input of type number

- Dev should be allowed to set input to null and expect v-model to
  retain the null value. Requesting a reconsideration against returning
a string as in commit 95b7f83

- Handle v-model.number modifier correctly. Whether the input is string,
  number or null, the resulting emit() should return the same type or
null. Requesting this as an alternative to resolve #2137.

- Handle input of type number. Likewise, the resulting emit() should
  return the same type. Requesting this as an alternative to resolve #2136.

* Clean up codes involving conditional mask

Fix #2158

* Removes redundant check on oldValue (input.value)

* Removes useless getLazyValue()

* Post-review updates & fixes
- Revert to last commit to undo unnecessary changes
- Fix computed.inputValue to account for type of emitted value
- Enhance watch.value to check for external/internal change
- Prevent resetSelections() from causing runtime error when
  type="number'
- Fix multiple emits bug
- Minor change to local variable names to be consistent between
  functions
  • Loading branch information
azaars authored and johnleider committed Oct 18, 2017
1 parent 28fbca9 commit 54e2b78
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 27 deletions.
45 changes: 37 additions & 8 deletions src/components/VTextField/VTextField.js
Expand Up @@ -17,6 +17,7 @@ export default {
return {
initialValue: null,
inputHeight: null,
internalChange: false,
badInput: false,
lazySelection: 0
}
Expand Down Expand Up @@ -84,12 +85,18 @@ export default {
},
inputValue: {
get () {
return this.value
return this.lazyValue
},
set (val) {
this.lazyValue = val
this.mask && this.setSelectionRange()
this.$emit('input', val)
if (this.mask) {
const value = this.unmaskText(this.maskText(this.unmaskText(val)))
this.lazyValue = typeof val === 'number' ? +value : value
this.setSelectionRange()
} else {
const type = typeof this.lazyValue
this.lazyValue = type === 'number' ? +val : val
this.$emit('input', this.lazyValue)
}
}
},
isDirty () {
Expand All @@ -112,8 +119,25 @@ export default {
}
},
value (val) {
if (this.internalChange) { // Through keystroke
this.internalChange = false
return
}

// Value was changed externally, update lazy
this.lazyValue = val
if (this.mask) {
const masked = this.maskText(this.unmaskText(val))
const value = this.unmaskText(masked)
this.lazyValue = typeof val === 'number' ? +value : value

// Emit when the externally set value was modified internally
val !== this.lazyValue && this.$nextTick(() => {
this.$refs.input.value = masked
this.$emit('input', this.lazyValue)
})
} else {
this.lazyValue = val
}

!this.validateOnBlur && this.validate()
this.shouldAutoGrow && this.calculateInputHeight()
Expand Down Expand Up @@ -141,8 +165,8 @@ export default {
})
},
onInput (e) {
this.resetSelections(e.target)
this.inputValue = this.unmaskText(e.target.value)
this.mask && this.resetSelections(e.target)
this.inputValue = e.target.value
this.badInput = e.target.validity && e.target.validity.badInput
this.shouldAutoGrow && this.calculateInputHeight()
},
Expand All @@ -163,6 +187,9 @@ export default {
}
this.$emit('focus', e)
},
keyDown (e) {
this.internalChange = true
},
genCounter () {
return this.$createElement('div', {
'class': {
Expand Down Expand Up @@ -193,7 +220,8 @@ export default {
on: Object.assign(listeners, {
blur: this.blur,
input: this.onInput,
focus: this.focus
focus: this.focus,
keydown: this.keyDown
}),
ref: 'input'
}
Expand Down Expand Up @@ -231,6 +259,7 @@ export default {
this.$nextTick(() => this.$refs.input.focus())
},
resetSelections (input) {
if (!input.selectionEnd) return
this.selection = input.selectionEnd
this.lazySelection = 0

Expand Down
41 changes: 23 additions & 18 deletions src/mixins/maskable.js
Expand Up @@ -55,23 +55,28 @@ export default {
mask () {
if (!this.$refs.input) return

const oldText = this.$refs.input.value
const newText = this.maskText(this.lazyValue)
const oldValue = this.$refs.input.value
const newValue = this.maskText(this.lazyValue)
let position = 0
let selection = this.selection

for (const char of oldText.substr(0, selection)) {
for (const char of oldValue.substr(0, selection)) {
isMaskDelimiter(char) || position++
}

selection = 0
for (const char of newText) {
isMaskDelimiter(char) || position--
selection++
if (position <= 0) break
if (newValue) {
for (const char of newValue) {
isMaskDelimiter(char) || position--
selection++
if (position <= 0) break
}
}

this.setCaretPosition(selection)
this.$nextTick(() => {
this.$refs.input.value = newValue
this.setCaretPosition(selection)
})
}
},

Expand All @@ -89,23 +94,23 @@ export default {
let selection = 0

this.$refs.input.value = newValue
for (const char of newValue) {
if (this.lazySelection <= 0) break
isMaskDelimiter(char) || this.lazySelection--
selection++
if (newValue) {
for (const char of newValue) {
if (this.lazySelection <= 0) break
isMaskDelimiter(char) || this.lazySelection--
selection++
}
}

this.setCaretPosition(selection)
// this.$emit() must occur only when all internal values are correct
this.$emit('input', this.returnMaskedValue ? this.$refs.input.value : this.lazyValue)
},
maskText (text) {
if (!this.mask) return text

return maskText(text, this.masked, this.dontFillMaskBlanks)
return this.mask ? maskText(text, this.masked, this.dontFillMaskBlanks) : text
},
unmaskText (text) {
if (this.returnMaskedValue || !this.mask) return text

return unmaskText(text)
return this.mask ? unmaskText(text) : text
},
// When the input changes and is
// re-created, ensure that the
Expand Down
3 changes: 2 additions & 1 deletion src/util/mask.js
Expand Up @@ -98,6 +98,7 @@ export const maskText = (text, masked, dontFillMaskBlanks) => {
let textIndex = 0
let maskIndex = 0
let newText = ''

while (maskIndex < masked.length) {
const mask = masked[maskIndex]

Expand Down Expand Up @@ -134,5 +135,5 @@ export const maskText = (text, masked, dontFillMaskBlanks) => {
* @return {String}
*/
export const unmaskText = (text) => {
return text.replace(new RegExp(defaultDelimiters, 'g'), '')
return text ? String(text).replace(new RegExp(defaultDelimiters, 'g'), '') : text
}

0 comments on commit 54e2b78

Please sign in to comment.