Skip to content

Commit 9b3d4c0

Browse files
authored
Merge branch 'master' into feature/footer-nav
2 parents e186fce + 58d2bde commit 9b3d4c0

File tree

8 files changed

+182
-17
lines changed

8 files changed

+182
-17
lines changed

examples/questionnaire/Example.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
multiple: false,
127127
allowOther: true,
128128
required: true,
129+
nextStepOnAnswer: true,
129130
options: [
130131
new ChoiceOption({
131132
label: 'Answer 1'

examples/quiz/Example.vue

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919
ref="flowform"
2020
v-on:complete="onComplete"
2121
v-on:submit="onQuizSubmit"
22+
v-on:timer="onTimer"
2223
v-bind:questions="questions"
2324
v-bind:language="language"
2425
v-bind:standalone="true"
26+
v-bind:timer="true"
27+
timer-start-step="html_1"
2528
>
2629
<!-- Custom content for the Complete/Submit screen slots in the FlowForm component -->
2730
<!-- We've overriden the default "complete" slot content -->
@@ -53,6 +56,7 @@
5356
v-html="language.formatString(language.pressEnter)">
5457
</a>
5558
</div>
59+
<p class="text-success" v-if="submitted && time">Your time: {{ formattedTime }}</p>
5660
<p class="text-success" v-if="submitted && score < 4">"You scored {{ score }} out of {{ total }}. There's a lot of room for improvement."</p>
5761
<p class="text-success" v-else-if="submitted && score < 7">"You scored {{ score }} out of {{ total }}. Not bad at all!"</p>
5862
<p class="text-success" v-else-if="submitted && score <= total">"You scored {{ score }} out of {{ total }}. Wow, that's impressive!"</p>
@@ -85,6 +89,8 @@
8589
completed: false,
8690
score: 0,
8791
total: 8,
92+
time: 0,
93+
formattedTime: '',
8894
answers: {
8995
html_1: ['2', '3'],
9096
html_2: 'false',
@@ -139,6 +145,7 @@
139145
type: QuestionType.MultipleChoice,
140146
required: true,
141147
multiple: false,
148+
nextStepOnAnswer: true,
142149
options: [
143150
new ChoiceOption({
144151
label: 'True',
@@ -157,6 +164,7 @@
157164
type: QuestionType.MultipleChoice,
158165
required: true,
159166
multiple: false,
167+
nextStepOnAnswer: true,
160168
options: [
161169
new ChoiceOption({
162170
label: '<form>',
@@ -240,6 +248,7 @@
240248
type: QuestionType.MultipleChoice,
241249
multiple: false,
242250
required: true,
251+
nextStepOnAnswer: true,
243252
options: [
244253
new ChoiceOption({
245254
label: 'True',
@@ -258,6 +267,7 @@
258267
multiple: false,
259268
helpText: 'Select one correct answer.',
260269
required: true,
270+
nextStepOnAnswer: true,
261271
options: [
262272
new ChoiceOption({
263273
label: 'Add progress bar to the form',
@@ -284,6 +294,7 @@
284294
type: QuestionType.MultipleChoice,
285295
multiple: false,
286296
required: true,
297+
nextStepOnAnswer: true,
287298
options: [
288299
new ChoiceOption({
289300
label: 'True',
@@ -335,6 +346,11 @@
335346
336347
this.submitted = true
337348
this.calculateScore()
349+
},
350+
351+
onTimer(time, formattedTime) {
352+
this.time = formattedTime
353+
this.formattedTime = formattedTime
338354
}
339355
},
340356
}

src/assets/css/common.css

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,10 @@ header.vff-header svg.f-logo {
372372
font-weight: 900;
373373
}
374374

375+
.vff .f-other.f-selected .f-label {
376+
font-weight: 900;
377+
}
378+
375379
.vff textarea {
376380
overflow: auto;
377381
display: block;
@@ -584,7 +588,7 @@ header.vff-header svg.f-logo {
584588
}
585589

586590
.vff ul.f-radios li {
587-
padding: .58em .68em;
591+
padding: .6em .68em;
588592
margin: .5em 0 .6em;
589593
font-weight: 300;
590594
line-height: 1.24;
@@ -645,10 +649,15 @@ header.vff-header svg.f-logo {
645649
}
646650

647651
.vff-footer .f-progress,
648-
.vff-footer .f-nav {
652+
.vff-footer .f-nav,
653+
.vff-footer .f-timer {
649654
display: inline-block;
650655
}
651656

657+
.vff-footer .f-timer {
658+
font-family: monospace;
659+
}
660+
652661
.vff-footer .f-prev,
653662
.vff-footer .f-next,
654663
.vff-footer .f-progress {

src/components/FlowForm.vue

Lines changed: 129 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@
112112
<span class="f-nav-text" aria-hidden="true">{{ language.next }}</span>
113113
</a>
114114
</div>
115+
<div v-if="timer" class="f-timer">
116+
<span>{{ formatTime(time) }}</span>
117+
</div>
115118
</div>
116119
</div>
117120
</div>
@@ -133,6 +136,7 @@
133136
components: {
134137
FlowFormQuestion
135138
},
139+
136140
props: {
137141
questions: Array,
138142
language: {
@@ -150,38 +154,50 @@
150154
navigation: {
151155
type: Boolean,
152156
default: true
153-
}
157+
},
158+
timer: {
159+
type: Boolean,
160+
default: false
161+
},
162+
timerStartStep: [String, Number],
163+
timerStopStep: [String, Number]
154164
},
165+
155166
mixins: [
156167
IsMobile,
157168
],
169+
158170
data() {
159171
return {
160172
completed: false,
161173
submitted: false,
162174
activeQuestionIndex: 0,
163175
questionList: [],
164176
questionListActivePath: [],
165-
reverse: false
166-
}
167-
},
168-
watch: {
169-
completed() {
170-
this.emitComplete()
177+
reverse: false,
178+
timerOn: false,
179+
timerInterval: null,
180+
time: 0
171181
}
172182
},
183+
173184
mounted() {
174185
document.addEventListener('keydown', this.onKeyDownListener)
175186
document.addEventListener('keyup', this.onKeyUpListener, true)
176187
window.addEventListener('beforeunload', this.onBeforeUnload)
177188
178189
this.setQuestions()
190+
this.checkTimer()
179191
},
192+
180193
beforeDestroy() {
181194
document.removeEventListener('keydown', this.onKeyDownListener)
182195
document.removeEventListener('keyup', this.onKeyUpListener, true)
183196
window.removeEventListener('beforeunload', this.onBeforeUnload)
197+
198+
this.stopTimer()
184199
},
200+
185201
computed: {
186202
numActiveQuestions() {
187203
return this.questionListActivePath.length
@@ -191,6 +207,20 @@
191207
return this.questionListActivePath[this.activeQuestionIndex]
192208
},
193209
210+
activeQuestionId() {
211+
const question = this.questions[this.activeQuestionIndex]
212+
213+
if (this.isOnLastStep) {
214+
return '_submit'
215+
}
216+
217+
if (question && question.id) {
218+
return question.id
219+
}
220+
221+
return null
222+
},
223+
194224
numCompletedQuestions() {
195225
let num = 0
196226
@@ -213,8 +243,33 @@
213243
214244
isOnLastStep() {
215245
return this.activeQuestionIndex === this.questionListActivePath.length
246+
},
247+
248+
isOnTimerStartStep() {
249+
if (this.activeQuestionId === this.timerStartStep) {
250+
return true
251+
}
252+
253+
if (!this.timerOn && !this.timerStartStep && this.activeQuestionIndex === 0) {
254+
return true
255+
}
256+
257+
return false
258+
},
259+
260+
isOnTimerStopStep() {
261+
if (this.submitted) {
262+
return true
263+
}
264+
265+
if (this.activeQuestionId === this.timerStopStep) {
266+
return true
267+
}
268+
269+
return false
216270
}
217271
},
272+
218273
methods: {
219274
/**
220275
* Returns currently active question component (if any).
@@ -255,7 +310,6 @@
255310
++index
256311
} else if (question.answered) {
257312
nextId = question.getJumpId()
258-
259313
if (nextId) {
260314
if (nextId === '_submit') {
261315
index = this.questions.length
@@ -412,7 +466,6 @@
412466
}
413467
414468
const q = this.activeQuestion
415-
416469
if (q && !q.required) {
417470
return true
418471
}
@@ -425,13 +478,15 @@
425478
*/
426479
onQuestionAnswered(question) {
427480
if (question.isValid()) {
481+
this.$emit('answer', question)
482+
428483
if (this.activeQuestionIndex < this.questionListActivePath.length) {
429484
++this.activeQuestionIndex
430485
}
431-
486+
432487
this.$nextTick(() => {
433488
this.setQuestions()
434-
489+
this.checkTimer()
435490
// Nested $nextTick so we're 100% sure that setQuestions
436491
// actually updated the question array
437492
this.$nextTick(() => {
@@ -447,6 +502,8 @@
447502
448503
this.$refs.button && this.$refs.button.focus()
449504
}
505+
506+
this.$emit('step', this.activeQuestionId, this.activeQuestion)
450507
})
451508
})
452509
} else if (this.completed) {
@@ -459,11 +516,17 @@
459516
*/
460517
goToPreviousQuestion() {
461518
this.blurFocus()
462-
519+
463520
if (this.activeQuestionIndex > 0 && !this.submitted) {
521+
if (this.isOnTimerStopStep) {
522+
this.startTimer()
523+
}
524+
464525
--this.activeQuestionIndex
465526
466527
this.reverse = true
528+
529+
this.checkTimer()
467530
}
468531
},
469532
@@ -472,7 +535,6 @@
472535
*/
473536
goToNextQuestion() {
474537
this.blurFocus()
475-
476538
if (this.isNextQuestionAvailable()) {
477539
this.emitEnter()
478540
}
@@ -486,6 +548,60 @@
486548
blurFocus() {
487549
document.activeElement && document.activeElement.blur && document.activeElement.blur()
488550
},
551+
552+
checkTimer() {
553+
if (this.timer) {
554+
if (this.isOnTimerStartStep) {
555+
this.startTimer()
556+
} else if (this.isOnTimerStopStep) {
557+
this.stopTimer()
558+
}
559+
}
560+
},
561+
562+
startTimer() {
563+
if (this.timer && !this.timerOn) {
564+
this.timerInterval = setInterval(this.incrementTime, 1000)
565+
this.timerOn = true
566+
}
567+
},
568+
569+
stopTimer() {
570+
if (this.timerOn) {
571+
clearInterval(this.timerInterval)
572+
}
573+
574+
this.timerOn = false
575+
},
576+
577+
incrementTime() {
578+
++this.time
579+
580+
this.$emit('timer', this.time, this.formatTime(this.time))
581+
},
582+
583+
formatTime(seconds) {
584+
let
585+
startIndex = 14,
586+
length = 5
587+
588+
if (seconds >= 60 * 60) {
589+
startIndex = 11
590+
length = 8
591+
}
592+
593+
return new Date(1000 * seconds).toISOString().substr(startIndex, length)
594+
}
595+
},
596+
597+
watch: {
598+
completed() {
599+
this.emitComplete()
600+
},
601+
602+
submitted() {
603+
this.stopTimer()
604+
}
489605
}
490606
}
491607
</script>

0 commit comments

Comments
 (0)