diff --git a/src/addon/mod/quiz/pages/player/player.html b/src/addon/mod/quiz/pages/player/player.html index 581493ff5..941f5840a 100644 --- a/src/addon/mod/quiz/pages/player/player.html +++ b/src/addon/mod/quiz/pages/player/player.html @@ -11,7 +11,7 @@ - +
@@ -19,8 +19,8 @@ - - + + @@ -101,7 +101,8 @@ {{ attempt.dueDateWarning }} - + +

{{ 'addon.mod_quiz.cannotsubmitquizdueto' | translate }}

diff --git a/src/components/components.module.ts b/src/components/components.module.ts index ff4ae9592..2ede4477b 100644 --- a/src/components/components.module.ts +++ b/src/components/components.module.ts @@ -40,6 +40,7 @@ import { CoreRichTextEditorComponent } from './rich-text-editor/rich-text-editor import { CoreNavBarButtonsComponent } from './navbar-buttons/navbar-buttons'; import { CoreDynamicComponent } from './dynamic-component/dynamic-component'; import { CoreSendMessageFormComponent } from './send-message-form/send-message-form'; +import { CoreTimerComponent } from './timer/timer'; @NgModule({ declarations: [ @@ -65,7 +66,8 @@ import { CoreSendMessageFormComponent } from './send-message-form/send-message-f CoreRichTextEditorComponent, CoreNavBarButtonsComponent, CoreDynamicComponent, - CoreSendMessageFormComponent + CoreSendMessageFormComponent, + CoreTimerComponent ], entryComponents: [ CoreContextMenuPopoverComponent, @@ -98,7 +100,8 @@ import { CoreSendMessageFormComponent } from './send-message-form/send-message-f CoreRichTextEditorComponent, CoreNavBarButtonsComponent, CoreDynamicComponent, - CoreSendMessageFormComponent + CoreSendMessageFormComponent, + CoreTimerComponent ] }) export class CoreComponentsModule {} diff --git a/src/components/timer/timer.html b/src/components/timer/timer.html new file mode 100644 index 000000000..31262562e --- /dev/null +++ b/src/components/timer/timer.html @@ -0,0 +1,6 @@ + + + + {{ timeLeft | coreSecondsToHMS }} + {{ 'core.timesup' | translate }} + diff --git a/src/components/timer/timer.scss b/src/components/timer/timer.scss new file mode 100644 index 000000000..1f499b693 --- /dev/null +++ b/src/components/timer/timer.scss @@ -0,0 +1,21 @@ +core-timer { + .core-timer { + background-color: $core-timer-color; + + span { + font-weight: bold; + } + + // Create the timer warning colors. Go from $core-timer-color to $core-timer-warn-color. + @for $i from 0 through $core-timer-iterations { + &.core-timer-timeleft-#{$i} { + background-color: mix($core-timer-color, $core-timer-warn-color, ($i / $core-timer-iterations) * 100); + @if $i <= $core-timer-iterations / 2 { + label, span, ion-icon { + color: $white; + } + } + } + } + } +} diff --git a/src/components/timer/timer.ts b/src/components/timer/timer.ts new file mode 100644 index 000000000..3fb267a34 --- /dev/null +++ b/src/components/timer/timer.ts @@ -0,0 +1,86 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, ElementRef, ViewChild } from '@angular/core'; +import { CoreTimeUtilsProvider } from '@providers/utils/time'; + +/** + * This directive shows a timer in format HH:MM:SS. When the countdown reaches 0, a function is called. + * + * Usage: + * + */ +@Component({ + selector: 'core-timer', + templateUrl: 'timer.html' +}) +export class CoreTimerComponent implements OnInit, OnDestroy { + @Input() endTime: string | number; // Timestamp (in seconds) when the timer should end. + @Input() timerText: string; // Text to show next to the timer. If not defined, no text shown. + @Input() timeLeftClass: string; // Name of the class to apply with each second. By default, 'core-timer-timeleft-'. + @Input() align: string; // Where to align the time and text. Defaults to 'left'. Other values: 'center', 'right'. + @Output() finished: EventEmitter; // Will emit an event when the timer reaches 0. + + @ViewChild('container', { read: ElementRef }) containerRef: ElementRef; + + timeLeft: number; // Seconds left to end. + + protected timeInterval; + protected container: HTMLElement; + + constructor(protected timeUtils: CoreTimeUtilsProvider) { + this.finished = new EventEmitter(); + } + + /** + * Component being initialized. + */ + ngOnInit(): void { + const timeLeftClass = this.timeLeftClass || 'core-timer-timeleft-', + endTime = Math.round(Number(this.endTime)), + container: HTMLElement = this.containerRef && this.containerRef.nativeElement; + + if (!endTime) { + return; + } + + // Check time left every 200ms. + this.timeInterval = setInterval(() => { + this.timeLeft = endTime - this.timeUtils.timestamp(); + + if (this.timeLeft < 0) { + // Time is up! Stop the timer and call the finish function. + clearInterval(this.timeInterval); + this.finished.emit(); + + return; + } + + // If the time has nearly expired, change the color. + if (this.timeLeft < 100 && !container.classList.contains(timeLeftClass + this.timeLeft)) { + // Time left has changed. Remove previous classes and add the new one. + container.classList.remove(timeLeftClass + (this.timeLeft + 1)); + container.classList.remove(timeLeftClass + (this.timeLeft + 2)); + container.classList.add(timeLeftClass + this.timeLeft); + } + }, 200); + } + + /** + * Component destroyed. + */ + ngOnDestroy(): void { + clearInterval(this.timeInterval); + } +} diff --git a/src/theme/variables.scss b/src/theme/variables.scss index 9f6fc3d6b..d80964743 100644 --- a/src/theme/variables.scss +++ b/src/theme/variables.scss @@ -208,6 +208,11 @@ $core-rte-min-height: 80px; $core-toolbar-button-image-width: 32px; +// Timer variables. +$core-timer-warn-color: $red !default; +$core-timer-color: $white !default; +$core-timer-iterations: 15 !default; + // Mixins // ------------------------- @mixin core-transition($where: all, $time: 500ms) {