Skip to content

Commit 822f321

Browse files
authored
Merge pull request #102 from ditdot-dev/return-focus
Tab and focus improvements
2 parents c2eef29 + 733e566 commit 822f321

File tree

9 files changed

+106
-37
lines changed

9 files changed

+106
-37
lines changed

examples/questionnaire/Example.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,6 @@
229229
// we need to implement the "keyup" listener manually.
230230
231231
if ($event.key === 'Enter' && this.completed && !this.submitted) {
232-
// Set `submitted` to true so the form knows not to allow back/forward
233-
// navigation anymore.
234-
this.$refs.flowform.submitted = true
235232
this.onSendData()
236233
}
237234
},
@@ -250,6 +247,10 @@
250247
},
251248
252249
onSendData() {
250+
// Set `submitted` to true so the form knows not to allow back/forward
251+
// navigation anymore.
252+
this.$refs.flowform.submitted = true
253+
253254
this.submitted = true
254255
255256
/* eslint-disable-next-line no-unused-vars */

examples/quiz/Example.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,11 @@
321321
},
322322
323323
onQuizSubmit() {
324-
this.submitted = true
324+
// Set `submitted` to true so the form knows not to allow back/forward
325+
// navigation anymore.
326+
this.$refs.flowform.submitted = true
327+
328+
this.submitted = true
325329
this.calculateScore()
326330
}
327331
}

src/assets/css/common.css

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,9 @@ span.faux-form {
275275
margin-top: 28px;
276276
}
277277

278-
span.f-sub + .f-answer.full-width, div.field-sectionbreaktype .f-answer {
279-
margin-top: 14px
278+
span.f-sub + .f-answer.full-width,
279+
div.field-sectionbreaktype .f-answer {
280+
margin-top: 16px
280281
}
281282

282283
span.f-empty {
@@ -349,7 +350,6 @@ h3,
349350
}
350351

351352
@media screen and (max-width:767px) {
352-
353353
h2,
354354
.fh2 {
355355
font-size: 2.2rem;
@@ -359,7 +359,6 @@ h3,
359359
}
360360

361361
@media screen and (max-width:479px), (max-height:400px) {
362-
363362
h2,
364363
.fh2 {
365364
font-size: 1.4rem;

src/components/FlowForm.vue

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -144,15 +144,15 @@
144144
}
145145
},
146146
mounted() {
147-
document.addEventListener('keyup', this.onKeyListener, true)
148-
document.addEventListener('keydown', this.onBackKeyListener)
147+
document.addEventListener('keydown', this.onKeyDownListener)
148+
document.addEventListener('keyup', this.onKeyUpListener, true)
149149
window.addEventListener('beforeunload', this.onBeforeUnload)
150150
151151
this.setQuestions()
152152
},
153153
beforeDestroy() {
154-
document.removeEventListener('keyup', this.onKeyListener, true)
155-
document.removeEventListener('keydown', this.onBackKeyListener)
154+
document.removeEventListener('keydown', this.onKeyDownListener)
155+
document.removeEventListener('keyup', this.onKeyUpListener, true)
156156
window.removeEventListener('beforeunload', this.onBeforeUnload)
157157
},
158158
computed: {
@@ -290,29 +290,54 @@
290290
},
291291
292292
/**
293-
* Global key listener, listens for Enter or Tab key events.
293+
* Global key listeners, listen for Enter or Tab key events.
294294
*/
295-
onKeyListener(e) {
296-
if (e.shiftKey) {
295+
onKeyDownListener(e) {
296+
if (e.key !== 'Tab' || this.submitted) {
297297
return
298298
}
299299
300-
if (e.key === 'Enter' || e.key === 'Tab') {
301-
e.stopPropagation()
302300
303-
this.emitEnter()
304-
this.reverse = false
305-
}
306-
},
307-
308-
onBackKeyListener(e) {
309-
if (e.shiftKey && e.key === 'Tab' ) {
301+
if (e.shiftKey) {
310302
e.stopPropagation()
311303
e.preventDefault()
304+
312305
this.goToPreviousQuestion()
306+
} else {
307+
e.preventDefault()
308+
309+
const q = this.activeQuestionComponent()
310+
311+
if (q.shouldFocus()) {
312+
q.focusField()
313+
} else {
314+
e.stopPropagation()
315+
316+
this.emitTab()
317+
this.reverse = false
318+
}
313319
}
314320
},
315321
322+
onKeyUpListener(e) {
323+
if (e.shiftKey || ['Tab', 'Enter'].indexOf(e.key) === -1 || this.submitted) {
324+
return
325+
}
326+
327+
const q = this.activeQuestionComponent()
328+
329+
if (e.key === 'Tab' && q.shouldFocus()) {
330+
q.focusField()
331+
} else {
332+
if (e.key === 'Enter') {
333+
this.emitEnter()
334+
}
335+
336+
e.stopPropagation()
337+
this.reverse = false
338+
}
339+
},
340+
316341
emitEnter() {
317342
const q = this.activeQuestionComponent()
318343
@@ -325,6 +350,17 @@
325350
}
326351
},
327352
353+
emitTab() {
354+
const q = this.activeQuestionComponent()
355+
356+
if (q) {
357+
// Send tab event to the current question component
358+
q.onTab()
359+
} else {
360+
this.emitEnter()
361+
}
362+
},
363+
328364
submit() {
329365
this.emitSubmit()
330366
this.submitted = true
@@ -343,6 +379,10 @@
343379
* can jump to it.
344380
*/
345381
isNextQuestionAvailable() {
382+
if (this.submitted) {
383+
return false
384+
}
385+
346386
const q = this.activeQuestion
347387
348388
if (q && !q.required) {

src/components/Question.vue

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,20 @@
153153
this.focusField()
154154
},
155155
156+
shouldFocus() {
157+
const q = this.$refs.questionComponent
158+
159+
return q && q.canReceiveFocus && !q.focused
160+
},
161+
162+
returnFocus() {
163+
const q = this.$refs.questionComponent
164+
165+
if (this.shouldFocus()) {
166+
this.focusField()
167+
}
168+
},
169+
156170
/**
157171
* Emits "answer" event and calls "onEnter" method on Enter press
158172
*/
@@ -163,10 +177,22 @@
163177
if (!q.focused) {
164178
this.$emit('answer', q)
165179
}
180+
166181
q.onEnter()
167182
}
168183
},
169184
185+
onTab($event) {
186+
const q = this.$refs.questionComponent
187+
188+
if (q) {
189+
this.returnFocus()
190+
this.$emit('answer', q)
191+
192+
q.onEnter()
193+
}
194+
},
195+
170196
/**
171197
* Check if the "OK" button should be shown.
172198
*/

src/components/QuestionTypes/BaseType.vue

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
enterPressed: false,
3131
allowedChars: null,
3232
alwaysAllowedKeys: ['ArrowLeft', 'ArrowRight', 'Delete', 'Backspace'],
33-
focused: false
33+
focused: false,
34+
canReceiveFocus: false,
3435
}
3536
},
3637
mounted() {
@@ -86,7 +87,7 @@
8687
clearTimeout(this.timeoutId)
8788
8889
if ($event) {
89-
if ($event.key === 'Enter') {
90+
if ($event.key === 'Enter' && !$event.shiftKey) {
9091
this.unsetFocus()
9192
}
9293
@@ -156,10 +157,6 @@
156157
}
157158
},
158159
computed: {
159-
editingFinished() {
160-
return true
161-
},
162-
163160
placeholder() {
164161
return this.question.placeholder || this.language.placeholder
165162
},

src/components/QuestionTypes/LongTextType.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
components: {
3636
TextareaAutosize
3737
},
38+
data () {
39+
return {
40+
canReceiveFocus: true
41+
}
42+
},
3843
mounted() {
3944
window.addEventListener('resize', this.onResizeListener)
4045
},
@@ -63,11 +68,6 @@
6368
this._onEnter()
6469
}
6570
}
66-
},
67-
computed: {
68-
editingFinished() {
69-
return !this.isMobile
70-
}
7171
}
7272
}
7373
</script>

src/components/QuestionTypes/PhoneType.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
name: QuestionType.Phone,
3636
data() {
3737
return {
38-
inputType: 'tel'
38+
inputType: 'tel',
39+
canReceiveFocus: true
3940
}
4041
}
4142
}

src/components/QuestionTypes/TextType.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
name: QuestionType.Text,
3131
data() {
3232
return {
33-
inputType: 'text'
33+
inputType: 'text',
34+
canReceiveFocus: true
3435
}
3536
}
3637
}

0 commit comments

Comments
 (0)