|
112 | 112 | <span class="f-nav-text" aria-hidden="true">{{ language.next }}</span> |
113 | 113 | </a> |
114 | 114 | </div> |
| 115 | + <div v-if="timer" class="f-timer"> |
| 116 | + <span>{{ formatTime(time) }}</span> |
| 117 | + </div> |
115 | 118 | </div> |
116 | 119 | </div> |
117 | 120 | </div> |
|
133 | 136 | components: { |
134 | 137 | FlowFormQuestion |
135 | 138 | }, |
| 139 | + |
136 | 140 | props: { |
137 | 141 | questions: Array, |
138 | 142 | language: { |
|
146 | 150 | standalone: { |
147 | 151 | type: Boolean, |
148 | 152 | default: true |
149 | | - } |
| 153 | + }, |
| 154 | + timer: { |
| 155 | + type: Boolean, |
| 156 | + default: false |
| 157 | + }, |
| 158 | + timerStartStep: [String, Number], |
| 159 | + timerStopStep: [String, Number] |
150 | 160 | }, |
| 161 | +
|
151 | 162 | mixins: [ |
152 | 163 | IsMobile, |
153 | 164 | ], |
| 165 | +
|
154 | 166 | data() { |
155 | 167 | return { |
156 | 168 | completed: false, |
157 | 169 | submitted: false, |
158 | 170 | activeQuestionIndex: 0, |
159 | 171 | questionList: [], |
160 | 172 | 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 |
167 | 177 | } |
168 | 178 | }, |
| 179 | +
|
169 | 180 | mounted() { |
170 | 181 | document.addEventListener('keydown', this.onKeyDownListener) |
171 | 182 | document.addEventListener('keyup', this.onKeyUpListener, true) |
172 | 183 | window.addEventListener('beforeunload', this.onBeforeUnload) |
173 | 184 |
|
174 | 185 | this.setQuestions() |
| 186 | + this.checkTimer() |
175 | 187 | }, |
| 188 | +
|
176 | 189 | beforeDestroy() { |
177 | 190 | document.removeEventListener('keydown', this.onKeyDownListener) |
178 | 191 | document.removeEventListener('keyup', this.onKeyUpListener, true) |
179 | 192 | window.removeEventListener('beforeunload', this.onBeforeUnload) |
| 193 | + |
| 194 | + this.stopTimer() |
180 | 195 | }, |
| 196 | +
|
181 | 197 | computed: { |
182 | 198 | numActiveQuestions() { |
183 | 199 | return this.questionListActivePath.length |
|
187 | 203 | return this.questionListActivePath[this.activeQuestionIndex] |
188 | 204 | }, |
189 | 205 |
|
| 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 | +
|
190 | 220 | numCompletedQuestions() { |
191 | 221 | let num = 0 |
192 | 222 |
|
|
209 | 239 |
|
210 | 240 | isOnLastStep() { |
211 | 241 | 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 |
212 | 266 | } |
213 | 267 | }, |
| 268 | +
|
214 | 269 | methods: { |
215 | 270 | /** |
216 | 271 | * Returns currently active question component (if any). |
|
251 | 306 | ++index |
252 | 307 | } else if (question.answered) { |
253 | 308 | nextId = question.getJumpId() |
254 | | -
|
255 | 309 | if (nextId) { |
256 | 310 | if (nextId === '_submit') { |
257 | 311 | index = this.questions.length |
|
320 | 374 | return |
321 | 375 | } |
322 | 376 |
|
323 | | -
|
324 | 377 | if (e.shiftKey) { |
325 | 378 | e.stopPropagation() |
326 | 379 | e.preventDefault() |
|
407 | 460 | } |
408 | 461 |
|
409 | 462 | const q = this.activeQuestion |
410 | | - |
411 | 463 | if (q && !q.required) { |
412 | 464 | return true |
413 | 465 | } |
|
423 | 475 | if (this.activeQuestionIndex < this.questionListActivePath.length) { |
424 | 476 | ++this.activeQuestionIndex |
425 | 477 | } |
426 | | -
|
| 478 | + |
427 | 479 | this.$nextTick(() => { |
428 | 480 | this.setQuestions() |
429 | | -
|
| 481 | + this.checkTimer() |
430 | 482 | // Nested $nextTick so we're 100% sure that setQuestions |
431 | 483 | // actually updated the question array |
432 | 484 | this.$nextTick(() => { |
|
454 | 506 | */ |
455 | 507 | goToPreviousQuestion() { |
456 | 508 | this.blurFocus() |
457 | | -
|
| 509 | + |
458 | 510 | if (this.activeQuestionIndex > 0 && !this.submitted) { |
| 511 | + if (this.isOnTimerStopStep) { |
| 512 | + this.startTimer() |
| 513 | + } |
| 514 | +
|
459 | 515 | --this.activeQuestionIndex |
460 | 516 |
|
461 | 517 | this.reverse = true |
| 518 | +
|
| 519 | + this.checkTimer() |
462 | 520 | } |
463 | 521 | }, |
464 | 522 |
|
|
467 | 525 | */ |
468 | 526 | goToNextQuestion() { |
469 | 527 | this.blurFocus() |
470 | | -
|
471 | 528 | if (this.isNextQuestionAvailable()) { |
472 | 529 | this.emitEnter() |
473 | 530 | } |
|
481 | 538 | blurFocus() { |
482 | 539 | document.activeElement && document.activeElement.blur && document.activeElement.blur() |
483 | 540 | }, |
| 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 | + } |
484 | 595 | } |
485 | 596 | } |
486 | 597 | </script> |
|
0 commit comments