commit
655254abd2
|
@ -22,6 +22,7 @@ import { AddonModQuizNavigationModalComponent } from './navigation-modal/navigat
|
|||
import { AddonModQuizPreflightModalComponent } from './preflight-modal/preflight-modal';
|
||||
import { AddonModQuizAttemptInfoComponent } from './attempt-info/attempt-info';
|
||||
import { AddonModQuizAttemptStateComponent } from './attempt-state/attempt-state';
|
||||
import { AddonModQuizQuestionCardComponent } from './question-card/question-card';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -31,13 +32,12 @@ import { AddonModQuizAttemptStateComponent } from './attempt-state/attempt-state
|
|||
AddonModQuizConnectionErrorComponent,
|
||||
AddonModQuizNavigationModalComponent,
|
||||
AddonModQuizPreflightModalComponent,
|
||||
AddonModQuizQuestionCardComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
CoreCourseComponentsModule,
|
||||
],
|
||||
providers: [
|
||||
],
|
||||
exports: [
|
||||
AddonModQuizAttemptInfoComponent,
|
||||
AddonModQuizAttemptStateComponent,
|
||||
|
@ -45,6 +45,8 @@ import { AddonModQuizAttemptStateComponent } from './attempt-state/attempt-state
|
|||
AddonModQuizConnectionErrorComponent,
|
||||
AddonModQuizNavigationModalComponent,
|
||||
AddonModQuizPreflightModalComponent,
|
||||
AddonModQuizQuestionCardComponent,
|
||||
|
||||
],
|
||||
})
|
||||
export class AddonModQuizComponentsModule {}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<ion-card id="addon-mod_quiz-question-{{question.slot}}">
|
||||
<ion-item-divider>
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h2 *ngIf="question.type !== 'description' && question.questionnumber" class="inline">
|
||||
{{ 'core.question.questionno' | translate:{$a: question.questionnumber} }}
|
||||
</h2>
|
||||
<h2 *ngIf="question.type === 'description' || !question.questionnumber" class="inline">
|
||||
{{ 'core.question.information' | translate }}
|
||||
</h2>
|
||||
</ion-label>
|
||||
<div class="ion-text-wrap ion-margin-start addon-mod_quiz-question-note" slot="end"
|
||||
*ngIf="question.status || question.readableMark">
|
||||
<p *ngIf="question.status">{{question.status}}</p>
|
||||
<p *ngIf="question.readableMark" [innerHTML]="question.readableMark"></p>
|
||||
</div>
|
||||
</ion-item-divider>
|
||||
|
||||
<ng-content />
|
||||
</ion-card>
|
|
@ -0,0 +1,7 @@
|
|||
.addon-mod_quiz-question-note p {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
text-align: end;
|
||||
font-weight: normal;
|
||||
font-size: var(--mdl-typography-fontSize-md);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 } from '@angular/core';
|
||||
import { CoreQuestionQuestionForView } from '@features/question/services/question';
|
||||
|
||||
/**
|
||||
* Component that displays a question card.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-quiz-question-card',
|
||||
templateUrl: 'question-card.html',
|
||||
styleUrl: 'question-card.scss',
|
||||
})
|
||||
export class AddonModQuizQuestionCardComponent {
|
||||
|
||||
@Input() question!: CoreQuestionQuestionForView;
|
||||
|
||||
}
|
|
@ -34,32 +34,14 @@
|
|||
|
||||
<!-- Questions -->
|
||||
<form name="addon-mod_quiz-player-form" *ngIf="questions.length && !quizAborted && !showSummary" #quizForm>
|
||||
<div *ngFor="let question of questions">
|
||||
<ion-card id="addon-mod_quiz-question-{{question.slot}}">
|
||||
<!-- "Header" of the question. -->
|
||||
<ion-item-divider>
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h2 *ngIf="question.type !== 'description' && question.questionnumber" class="inline">
|
||||
{{ 'core.question.questionno' | translate:{$a: question.questionnumber} }}
|
||||
</h2>
|
||||
<h2 *ngIf="question.type === 'description' || !question.questionnumber" class="inline">
|
||||
{{ 'core.question.information' | translate }}
|
||||
</h2>
|
||||
</ion-label>
|
||||
<div *ngIf="question.status || question.readableMark" slot="end"
|
||||
class="ion-text-wrap ion-margin-start addon-mod_quiz-question-note">
|
||||
<p *ngIf="question.status" class="block">{{question.status}}</p>
|
||||
<p *ngIf="question.readableMark" [innerHTML]="question.readableMark"></p>
|
||||
</div>
|
||||
</ion-item-divider>
|
||||
|
||||
<!-- Body of the question. -->
|
||||
<ng-container *ngFor="let question of questions">
|
||||
<addon-mod-quiz-question-card [question]="question">
|
||||
<core-question class="ion-text-wrap" [question]="question" [component]="component" [componentId]="cmId"
|
||||
[attemptId]="attempt!.id" [usageId]="attempt!.uniqueid" [offlineEnabled]="offline" contextLevel="module"
|
||||
[contextInstanceId]="cmId" [courseId]="courseId" [preferredBehaviour]="quiz!.preferredbehaviour" [review]="false"
|
||||
(onAbort)="abortQuiz()" (buttonClicked)="behaviourButtonClicked($event)" />
|
||||
</ion-card>
|
||||
</div>
|
||||
</addon-mod-quiz-question-card>
|
||||
</ng-container>
|
||||
</form>
|
||||
|
||||
<!-- Go to next or previous page. -->
|
||||
|
|
|
@ -5,14 +5,6 @@ $quiz-timer-warn-color: $red !default;
|
|||
$quiz-timer-iterations: 15 !default;
|
||||
|
||||
:host {
|
||||
.addon-mod_quiz-question-note p {
|
||||
font-weight: normal;
|
||||
font-size: var(--mdl-typography-fontSize-md);
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
core-timer {
|
||||
// Make the timer go red when it's reaching 0.
|
||||
@for $i from 0 through $quiz-timer-iterations {
|
||||
|
|
|
@ -18,7 +18,11 @@ import { Subscription } from 'rxjs';
|
|||
|
||||
import { CoreIonLoadingElement } from '@classes/ion-loading';
|
||||
import { CoreQuestionComponent } from '@features/question/components/question/question';
|
||||
import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
|
||||
import {
|
||||
CoreQuestionQuestionForView,
|
||||
CoreQuestionQuestionParsed,
|
||||
CoreQuestionsAnswers,
|
||||
} from '@features/question/services/question';
|
||||
import { CoreQuestionBehaviourButton, CoreQuestionHelper } from '@features/question/services/question-helper';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
|
||||
|
@ -73,7 +77,7 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy, CanLeave {
|
|||
quizAborted = false; // Whether the quiz was aborted due to an error.
|
||||
offline = false; // Whether the quiz is being attempted in offline mode.
|
||||
navigation: AddonModQuizNavigationQuestion[] = []; // List of questions to navigate them.
|
||||
questions: QuizQuestion[] = []; // Questions of the current page.
|
||||
questions: CoreQuestionQuestionForView[] = []; // Questions of the current page.
|
||||
nextPage = -2; // Next page.
|
||||
previousPage = -1; // Previous page.
|
||||
showSummary = false; // Whether the attempt summary should be displayed.
|
||||
|
@ -936,13 +940,6 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy, CanLeave {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Question with some calculated data for the view.
|
||||
*/
|
||||
type QuizQuestion = CoreQuestionQuestionParsed & {
|
||||
readableMark?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt with some calculated data for the view.
|
||||
*/
|
||||
|
|
|
@ -29,35 +29,17 @@
|
|||
</ion-card>
|
||||
|
||||
<!-- Questions -->
|
||||
<div *ngIf="attempt && questions.length">
|
||||
<ng-container *ngIf="attempt && questions.length">
|
||||
|
||||
<!-- Questions. -->
|
||||
<div *ngFor="let question of questions">
|
||||
<ion-card id="addon-mod_quiz-question-{{question.slot}}">
|
||||
<!-- "Header" of the question. -->
|
||||
<ion-item-divider>
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h2 *ngIf="question.type !== 'description' && question.questionnumber">
|
||||
{{ 'core.question.questionno' | translate:{$a: question.questionnumber} }}
|
||||
</h2>
|
||||
<h2 *ngIf="question.type === 'description' || !question.questionnumber">
|
||||
{{ 'core.question.information' | translate }}
|
||||
</h2>
|
||||
</ion-label>
|
||||
<div class="ion-text-wrap ion-margin-horizontal addon-mod_quiz-question-note" slot="end"
|
||||
*ngIf="question.status || question.readableMark">
|
||||
<p *ngIf="question.status">{{question.status}}</p>
|
||||
<p *ngIf="question.readableMark" [innerHTML]="question.readableMark"></p>
|
||||
</div>
|
||||
</ion-item-divider>
|
||||
|
||||
<!-- Body of the question. -->
|
||||
<ng-container *ngFor="let question of questions">
|
||||
<addon-mod-quiz-question-card [question]="question">
|
||||
<core-question class="ion-text-wrap" [question]="question" [component]="component" [componentId]="cmId"
|
||||
[attemptId]="attempt.id" [usageId]="attempt.uniqueid" [offlineEnabled]="false" contextLevel="module"
|
||||
[contextInstanceId]="cmId" [courseId]="courseId" [review]="true" [preferredBehaviour]="quiz?.preferredbehaviour" />
|
||||
</ion-card>
|
||||
</div>
|
||||
</div>
|
||||
</addon-mod-quiz-question-card>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<div collapsible-footer appearOnBottom *ngIf="loaded && numPages > 1" slot="fixed">
|
||||
<ion-row class="ion-justify-content-between ion-align-items-center ion-no-padding ion-wrap">
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
:host {
|
||||
.addon-mod_quiz-question-note p {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { CoreQuestionQuestionParsed } from '@features/question/services/question';
|
||||
import { CoreQuestionQuestionForView } from '@features/question/services/question';
|
||||
import { CoreQuestionHelper } from '@features/question/services/question-helper';
|
||||
import { IonContent } from '@ionic/angular';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
|
@ -43,7 +43,6 @@ import { ADDON_MOD_QUIZ_COMPONENT } from '../../constants';
|
|||
@Component({
|
||||
selector: 'page-addon-mod-quiz-review',
|
||||
templateUrl: 'review.html',
|
||||
styleUrls: ['review.scss'],
|
||||
})
|
||||
export class AddonModQuizReviewPage implements OnInit {
|
||||
|
||||
|
@ -57,11 +56,10 @@ export class AddonModQuizReviewPage implements OnInit {
|
|||
additionalData?: AddonModQuizWSAdditionalData[]; // Additional data to display for the attempt.
|
||||
loaded = false; // Whether data has been loaded.
|
||||
navigation: AddonModQuizNavigationQuestion[] = []; // List of questions to navigate them.
|
||||
questions: QuizQuestion[] = []; // Questions of the current page.
|
||||
questions: CoreQuestionQuestionForView[] = []; // Questions of the current page.
|
||||
nextPage = -2; // Next page.
|
||||
previousPage = -2; // Previous page.
|
||||
readableGrade?: string;
|
||||
readableMark?: string;
|
||||
timeTaken?: string;
|
||||
gradeItemMarks: { name: string; grade: string }[] = [];
|
||||
overTime?: string;
|
||||
|
@ -320,13 +318,6 @@ export class AddonModQuizReviewPage implements OnInit {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Question with some calculated data for the view.
|
||||
*/
|
||||
type QuizQuestion = CoreQuestionQuestionParsed & {
|
||||
readableMark?: string;
|
||||
};
|
||||
|
||||
type LogViewOptions = {
|
||||
page?: number; // Page being viewed (if viewing pages);
|
||||
showAllDisabled?: boolean; // Whether the showAll option has just been disabled.
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
@ -69,7 +69,7 @@
|
|||
</ion-badge>
|
||||
<!-- Download progress. -->
|
||||
<p *ngIf="downloadEnabled && section.isDownloading">
|
||||
<core-progress-bar [progress]="section.total === 0 ? -1 : section.count / section.total" />
|
||||
<core-progress-bar [progress]="section.total === 0 ? -1 : (section.count / section.total) * 100" />
|
||||
</p>
|
||||
</ion-label>
|
||||
<div class="storage-buttons" slot="end"
|
||||
|
@ -112,7 +112,8 @@
|
|||
<ion-icon name="fam-cloud-done" *ngIf="module.downloadStatus === statusDownloaded"
|
||||
[attr.aria-label]="'core.downloaded' | translate" />{{ module.totalSize | coreBytesToSize }}
|
||||
</ion-badge>
|
||||
<ion-badge color="light" *ngIf="module.calculatingSize">
|
||||
<ion-badge color="light" *ngIf="module.calculatingSize ||
|
||||
(section.isDownloading && module.downloadStatus === statusDownloaded)">
|
||||
{{ 'core.calculating' | translate }}
|
||||
</ion-badge>
|
||||
</ion-label>
|
||||
|
|
|
@ -10,12 +10,16 @@
|
|||
ion-card.section {
|
||||
ion-card-header {
|
||||
padding: 0;
|
||||
|
||||
.item-heading {
|
||||
font: var(--mdl-typography-heading4-font);
|
||||
}
|
||||
}
|
||||
ion-card-content {
|
||||
padding: 0;
|
||||
|
||||
.core-course-storage-activity ion-label {
|
||||
h3 {
|
||||
p.item-heading {
|
||||
position: relative;
|
||||
max-height: var(--course-storage-max-activity-height);
|
||||
overflow: hidden;
|
||||
|
@ -35,15 +39,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.item-heading {
|
||||
font-weight: bold;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ion-badge {
|
||||
margin-top: 8px;
|
||||
ion-icon {
|
||||
@include margin-horizontal(null, 8px);
|
||||
}
|
||||
|
|
|
@ -653,6 +653,13 @@ export type CoreQuestionQuestionParsed = CoreQuestionQuestionWSData & {
|
|||
parsedSettings?: Record<string, unknown> | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Question with some calculated data for the view.
|
||||
*/
|
||||
export type CoreQuestionQuestionForView = CoreQuestionQuestionParsed & {
|
||||
readableMark?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* List of answers to a set of questions.
|
||||
*/
|
||||
|
|
|
@ -16,7 +16,8 @@ input[type=checkbox] {
|
|||
}
|
||||
|
||||
ion-checkbox {
|
||||
&.checkbox-disabled::part(label) {
|
||||
&.md.checkbox-disabled::part(label),
|
||||
&.ios.checkbox-disabled {
|
||||
opacity: var(--mdl-input-disabled-opacity);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,8 @@ input[type=radio],
|
|||
}
|
||||
|
||||
ion-radio {
|
||||
&.radio-disabled::part(label) {
|
||||
&.md.radio-disabled::part(label),
|
||||
&.ios.radio-disabled {
|
||||
opacity: var(--mdl-input-disabled-opacity);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue