Skip to content

Commit 49111d5

Browse files
authored
Merge pull request #140 from ditdot-dev/feature/timer
Feature/timer
2 parents 9708b6b + b4350c7 commit 49111d5

File tree

4 files changed

+142
-16
lines changed

4 files changed

+142
-16
lines changed

examples/quiz/Example.vue

Lines changed: 11 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',
@@ -335,6 +341,11 @@
335341
336342
this.submitted = true
337343
this.calculateScore()
344+
},
345+
346+
onTimer(time, formattedTime) {
347+
this.time = formattedTime
348+
this.formattedTime = formattedTime
338349
}
339350
},
340351
}

src/assets/css/common.css

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,10 +645,15 @@ header.vff-header svg.f-logo {
645645
}
646646

647647
.vff-footer .f-progress,
648-
.vff-footer .f-nav {
648+
.vff-footer .f-nav,
649+
.vff-footer .f-timer {
649650
display: inline-block;
650651
}
651652

653+
.vff-footer .f-timer {
654+
font-family: monospace;
655+
}
656+
652657
.vff-footer .f-prev,
653658
.vff-footer .f-next,
654659
.vff-footer .f-progress {

src/components/FlowForm.vue

Lines changed: 125 additions & 14 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: {
@@ -146,38 +150,50 @@
146150
standalone: {
147151
type: Boolean,
148152
default: true
149-
}
153+
},
154+
timer: {
155+
type: Boolean,
156+
default: false
157+
},
158+
timerStartStep: [String, Number],
159+
timerStopStep: [String, Number]
150160
},
161+
151162
mixins: [
152163
IsMobile,
153164
],
165+
154166
data() {
155167
return {
156168
completed: false,
157169
submitted: false,
158170
activeQuestionIndex: 0,
159171
questionList: [],
160172
questionListActivePath: [],
161-
reverse: false
162-
}
163-
},
164-
watch: {
165-
completed() {
166-
this.emitComplete()
173+
reverse: false,
174+
timerOn: false,
175+
timerInterval: null,
176+
time: 0
167177
}
168178
},
179+
169180
mounted() {
170181
document.addEventListener('keydown', this.onKeyDownListener)
171182
document.addEventListener('keyup', this.onKeyUpListener, true)
172183
window.addEventListener('beforeunload', this.onBeforeUnload)
173184
174185
this.setQuestions()
186+
this.checkTimer()
175187
},
188+
176189
beforeDestroy() {
177190
document.removeEventListener('keydown', this.onKeyDownListener)
178191
document.removeEventListener('keyup', this.onKeyUpListener, true)
179192
window.removeEventListener('beforeunload', this.onBeforeUnload)
193+
194+
this.stopTimer()
180195
},
196+
181197
computed: {
182198
numActiveQuestions() {
183199
return this.questionListActivePath.length
@@ -187,6 +203,20 @@
187203
return this.questionListActivePath[this.activeQuestionIndex]
188204
},
189205
206+
activeQuestionId() {
207+
const question = this.questions[this.activeQuestionIndex]
208+
209+
if (this.isOnLastStep) {
210+
return '_submit'
211+
}
212+
213+
if (question && question.id) {
214+
return question.id
215+
}
216+
217+
return null
218+
},
219+
190220
numCompletedQuestions() {
191221
let num = 0
192222
@@ -209,8 +239,33 @@
209239
210240
isOnLastStep() {
211241
return this.activeQuestionIndex === this.questionListActivePath.length
242+
},
243+
244+
isOnTimerStartStep() {
245+
if (this.activeQuestionId === this.timerStartStep) {
246+
return true
247+
}
248+
249+
if (!this.timerOn && !this.timerStartStep && this.activeQuestionIndex === 0) {
250+
return true
251+
}
252+
253+
return false
254+
},
255+
256+
isOnTimerStopStep() {
257+
if (this.submitted) {
258+
return true
259+
}
260+
261+
if (this.activeQuestionId === this.timerStopStep) {
262+
return true
263+
}
264+
265+
return false
212266
}
213267
},
268+
214269
methods: {
215270
/**
216271
* Returns currently active question component (if any).
@@ -251,7 +306,6 @@
251306
++index
252307
} else if (question.answered) {
253308
nextId = question.getJumpId()
254-
255309
if (nextId) {
256310
if (nextId === '_submit') {
257311
index = this.questions.length
@@ -320,7 +374,6 @@
320374
return
321375
}
322376
323-
324377
if (e.shiftKey) {
325378
e.stopPropagation()
326379
e.preventDefault()
@@ -407,7 +460,6 @@
407460
}
408461
409462
const q = this.activeQuestion
410-
411463
if (q && !q.required) {
412464
return true
413465
}
@@ -423,10 +475,10 @@
423475
if (this.activeQuestionIndex < this.questionListActivePath.length) {
424476
++this.activeQuestionIndex
425477
}
426-
478+
427479
this.$nextTick(() => {
428480
this.setQuestions()
429-
481+
this.checkTimer()
430482
// Nested $nextTick so we're 100% sure that setQuestions
431483
// actually updated the question array
432484
this.$nextTick(() => {
@@ -454,11 +506,17 @@
454506
*/
455507
goToPreviousQuestion() {
456508
this.blurFocus()
457-
509+
458510
if (this.activeQuestionIndex > 0 && !this.submitted) {
511+
if (this.isOnTimerStopStep) {
512+
this.startTimer()
513+
}
514+
459515
--this.activeQuestionIndex
460516
461517
this.reverse = true
518+
519+
this.checkTimer()
462520
}
463521
},
464522
@@ -467,7 +525,6 @@
467525
*/
468526
goToNextQuestion() {
469527
this.blurFocus()
470-
471528
if (this.isNextQuestionAvailable()) {
472529
this.emitEnter()
473530
}
@@ -481,6 +538,60 @@
481538
blurFocus() {
482539
document.activeElement && document.activeElement.blur && document.activeElement.blur()
483540
},
541+
542+
checkTimer() {
543+
if (this.timer) {
544+
if (this.isOnTimerStartStep) {
545+
this.startTimer()
546+
} else if (this.isOnTimerStopStep) {
547+
this.stopTimer()
548+
}
549+
}
550+
},
551+
552+
startTimer() {
553+
if (this.timer && !this.timerOn) {
554+
this.timerInterval = setInterval(this.incrementTime, 1000)
555+
this.timerOn = true
556+
}
557+
},
558+
559+
stopTimer() {
560+
if (this.timerOn) {
561+
clearInterval(this.timerInterval)
562+
}
563+
564+
this.timerOn = false
565+
},
566+
567+
incrementTime() {
568+
++this.time
569+
570+
this.$emit('timer', this.time, this.formatTime(this.time))
571+
},
572+
573+
formatTime(seconds) {
574+
let
575+
startIndex = 14,
576+
length = 5
577+
578+
if (seconds >= 60 * 60) {
579+
startIndex = 11
580+
length = 8
581+
}
582+
583+
return new Date(1000 * seconds).toISOString().substr(startIndex, length)
584+
}
585+
},
586+
587+
watch: {
588+
completed() {
589+
this.emitComplete()
590+
},
591+
592+
submitted() {
593+
this.stopTimer()
594+
}
484595
}
485596
}
486597
</script>

src/components/QuestionTypes/TextType.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
v-bind:min="question.min"
1919
v-bind:max="question.max"
2020
v-on:change="onChange"
21-
v-bind:tokens="tokens"
2221
/>
2322
<input
2423
v-else

0 commit comments

Comments
 (0)