Skip to content

Commit 0ad6100

Browse files
authored
Allow pasting in 6 digit auth code input (baserow#4475)
1 parent d926fb3 commit 0ad6100

File tree

2 files changed

+60
-3
lines changed

2 files changed

+60
-3
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "feature",
3+
"message": "Allow pasting in 6 digit auth code input.",
4+
"issue_origin": "github",
5+
"issue_number": null,
6+
"domain": "core",
7+
"bullet_points": [],
8+
"created_at": "2025-12-17"
9+
}

web-frontend/modules/core/components/settings/twoFactorAuth/AuthCodeInput.vue

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
:class="{ 'auth-code-input__input--filled': allFilled }"
1414
@keyup="handleKeyUp"
1515
@keydown="handleKeyDown"
16+
@paste="pasteAt(1, $event)"
1617
/>
1718
<input
19+
ref="input2"
1820
v-model="number2"
1921
type="text"
2022
maxlength="1"
@@ -23,8 +25,10 @@
2325
:class="{ 'auth-code-input__input--filled': allFilled }"
2426
@keyup="handleKeyUp"
2527
@keydown="handleKeyDown"
28+
@paste="pasteAt(2, $event)"
2629
/>
2730
<input
31+
ref="input3"
2832
v-model="number3"
2933
type="text"
3034
maxlength="1"
@@ -33,8 +37,10 @@
3337
:class="{ 'auth-code-input__input--filled': allFilled }"
3438
@keyup="handleKeyUp"
3539
@keydown="handleKeyDown"
40+
@paste="pasteAt(3, $event)"
3641
/>
3742
<input
43+
ref="input4"
3844
v-model="number4"
3945
type="text"
4046
maxlength="1"
@@ -43,8 +49,10 @@
4349
:class="{ 'auth-code-input__input--filled': allFilled }"
4450
@keyup="handleKeyUp"
4551
@keydown="handleKeyDown"
52+
@paste="pasteAt(4, $event)"
4653
/>
4754
<input
55+
ref="input5"
4856
v-model="number5"
4957
type="text"
5058
maxlength="1"
@@ -53,8 +61,10 @@
5361
:class="{ 'auth-code-input__input--filled': allFilled }"
5462
@keyup="handleKeyUp"
5563
@keydown="handleKeyDown"
64+
@paste="pasteAt(5, $event)"
5665
/>
5766
<input
67+
ref="input6"
5868
v-model="number6"
5969
type="text"
6070
maxlength="1"
@@ -63,6 +73,7 @@
6373
:class="{ 'auth-code-input__input--filled': allFilled }"
6474
@keyup="handleKeyUp"
6575
@keydown="handleKeyDown"
76+
@paste="pasteAt(6, $event)"
6677
/>
6778
</div>
6879
</template>
@@ -87,6 +98,7 @@ export default {
8798
number5: '',
8899
number6: '',
89100
},
101+
hasEmitted: false,
90102
}
91103
},
92104
computed: {
@@ -152,10 +164,25 @@ export default {
152164
return this.code.length === 6
153165
},
154166
},
167+
watch: {
168+
allFilled(isFilled) {
169+
if (isFilled && !this.hasEmitted) {
170+
this.hasEmitted = true
171+
this.$emit('all-filled', this.code)
172+
}
173+
if (!isFilled) {
174+
this.hasEmitted = false
175+
}
176+
},
177+
},
155178
mounted() {
156179
this.reset()
157180
},
158181
methods: {
182+
focusIndex(i) {
183+
const el = this.$refs[`input${i}`]
184+
if (el && typeof el.focus === 'function') el.focus()
185+
},
159186
reset() {
160187
this.values.number1 = ''
161188
this.values.number2 = ''
@@ -164,6 +191,7 @@ export default {
164191
this.values.number5 = ''
165192
this.values.number6 = ''
166193
this.$refs.input1.focus()
194+
this.hasEmitted = false
167195
},
168196
sanitizeInput(value) {
169197
const sanitized = value.replace(/\D/g, '').slice(0, 1)
@@ -192,11 +220,31 @@ export default {
192220
if (nextInput && nextInput.tagName === 'INPUT') {
193221
nextInput.focus()
194222
}
223+
}
224+
},
225+
pasteAt(startIndex, event) {
226+
event.preventDefault()
195227
196-
if (this.allFilled) {
197-
this.$emit('all-filled', this.code)
198-
}
228+
const raw =
229+
(event.clipboardData && event.clipboardData.getData('text')) ||
230+
(window.clipboardData && window.clipboardData.getData('Text')) ||
231+
''
232+
233+
const digits = raw.replace(/\D/g, '')
234+
const maxLen = 7 - startIndex
235+
const chunk = digits.slice(0, maxLen)
236+
237+
for (let i = startIndex; i <= 6; i++) {
238+
this.values[`number${i}`] = ''
199239
}
240+
241+
for (let offset = 0; offset < chunk.length; offset++) {
242+
const i = startIndex + offset
243+
this.values[`number${i}`] = chunk[offset]
244+
}
245+
246+
const nextIndex = Math.min(startIndex + chunk.length, 6)
247+
this.$nextTick(() => this.focusIndex(nextIndex))
200248
},
201249
},
202250
}

0 commit comments

Comments
 (0)