MOBILE-2812 quiz: Update styles to match web version

main
Pau Ferrer Ocaña 2019-01-28 17:42:50 +01:00
parent d2fc0ed420
commit 9d320b5914
30 changed files with 225 additions and 128 deletions

View File

@ -22,11 +22,11 @@
<p>{{ rule }}</p>
</ion-item>
<ion-item text-wrap *ngIf="quiz && quiz.gradeMethodReadable">
<p class="item-heading">{{ 'addon.mod_quiz.grademethod' | translate }}</p>
<h2>{{ 'addon.mod_quiz.grademethod' | translate }}</h2>
<p>{{ quiz.gradeMethodReadable }}</p>
</ion-item>
<ion-item text-wrap *ngIf="syncTime">
<p class="item-heading">{{ 'core.lastsync' | translate }}</p>
<h2>{{ 'core.lastsync' | translate }}</h2>
<p>{{ syncTime }}</p>
</ion-item>
</ion-list>

View File

@ -1,4 +1,5 @@
{
"answercolon": "Answer:",
"attemptfirst": "First attempt",
"attemptlast": "Last attempt",
"attemptnumber": "Attempt",

View File

@ -9,25 +9,25 @@
</ion-refresher>
<core-loading [hideUntil]="loaded">
<ion-list *ngIf="attempt">
<ion-item text-wrap>
<p class="item-heading">{{ 'addon.mod_quiz.attemptnumber' | translate }}</p>
<ion-item text-wrap no-lines>
<h2>{{ 'addon.mod_quiz.attemptnumber' | translate }}</h2>
<p *ngIf="attempt.preview">{{ 'addon.mod_quiz.preview' | translate }}</p>
<p *ngIf="!attempt.preview">{{ attempt.attempt }}</p>
</ion-item>
<ion-item text-wrap>
<p class="item-heading">{{ 'addon.mod_quiz.attemptstate' | translate }}</p>
<ion-item text-wrap no-lines>
<h2>{{ 'addon.mod_quiz.attemptstate' | translate }}</h2>
<p *ngFor="let sentence of attempt.readableState">{{ sentence }}</p>
</ion-item>
<ion-item text-wrap *ngIf="quiz.showMarkColumn && attempt.readableMark !== ''">
<p class="item-heading">{{ 'addon.mod_quiz.marks' | translate }} / {{ quiz.sumGradesFormatted }}</p>
<ion-item text-wrap no-lines *ngIf="quiz.showMarkColumn && attempt.readableMark !== ''">
<h2>{{ 'addon.mod_quiz.marks' | translate }} / {{ quiz.sumGradesFormatted }}</h2>
<p>{{ attempt.readableMark }}</p>
</ion-item>
<ion-item text-wrap *ngIf="quiz.showGradeColumn && attempt.readableGrade !== ''">
<p class="item-heading">{{ 'addon.mod_quiz.grade' | translate }} / {{ quiz.gradeFormatted }}</p>
<ion-item text-wrap no-lines *ngIf="quiz.showGradeColumn && attempt.readableGrade !== ''">
<h2>{{ 'addon.mod_quiz.grade' | translate }} / {{ quiz.gradeFormatted }}</h2>
<p>{{ attempt.readableGrade }}</p>
</ion-item>
<ion-item text-wrap *ngIf="quiz.showFeedbackColumn && attempt.feedback">
<p class="item-heading">{{ 'addon.mod_quiz.feedback' | translate }}</p>
<ion-item text-wrap no-lines *ngIf="quiz.showFeedbackColumn && attempt.feedback">
<h2>{{ 'addon.mod_quiz.feedback' | translate }}</h2>
<p><core-format-text [component]="component" [componentId]="componentId" [text]="attempt.feedback"></core-format-text></p>
</ion-item>
<ion-item *ngIf="quiz.showReviewColumn && attempt.finished">

View File

@ -24,6 +24,10 @@
<a ion-item text-wrap *ngFor="let question of pageInstance.navigation" class="{{question.stateClass}}" [ngClass]='{"addon-mod_quiz-selected": !pageInstance.showSummary && pageInstance.attempt.currentpage == question.page}' (click)="loadPage(question.page, question.slot)">
<span *ngIf="question.number">{{ 'core.question.questionno' | translate:{$a: question.number} }}</span>
<span *ngIf="!question.number">{{ 'core.question.information' | translate }}</span>
<core-icon item-content *ngIf="!question.number" name="information-circle" color="info"></core-icon>
<core-icon item-content *ngIf="question.stateClass == 'core-question-correct'" name="fa-check" color="success"></core-icon>
<core-icon item-content *ngIf="question.stateClass == 'core-question-partiallycorrect'" name="fa-check-square" color="warning"></core-icon>
<core-icon item-content *ngIf="question.stateClass == 'core-question-incorrect' || question.stateClass == 'core-question-notanswered'" name="fa-remove" color="danger"></core-icon>
</a>
<!-- In player, show button to finish attempt. -->

View File

@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { AddonModQuizNavigationModalPage } from './navigation-modal';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
@ -24,6 +25,7 @@ import { CoreDirectivesModule } from '@directives/directives.module';
],
imports: [
CoreDirectivesModule,
CoreComponentsModule,
IonicPageModule.forChild(AddonModQuizNavigationModalPage),
TranslateModule.forChild()
]

View File

@ -14,15 +14,49 @@ ion-app.app-root page-addon-mod-quiz-navigation-modal {
}
}
.item.core-question-correct .item-inner {
@include push-arrow-color($core-question-correct-color);
.item.core-question-correct {
&.addon-mod_quiz-selected {
@include border-start(5px, solid, $core-question-correct-color);
}
.item-inner {
@include push-arrow-color($core-question-correct-color);
border-bottom-color: $core-question-correct-color;
}
}
.item.core-question-incorrect .item-inner {
@include push-arrow-color($core-question-incorrect-color);
.item.core-question-incorrect,
.item.core-question-notanswered {
&.addon-mod_quiz-selected {
@include border-start(5px, solid, $core-question-incorrect-color);
}
.item-inner {
@include push-arrow-color($core-question-incorrect-color);
border-bottom-color: $core-question-incorrect-color;
}
}
.item.core-question-answersaved .item-inner {
@include push-arrow-color($text-color);
.item.core-question-partiallycorrect {
&.addon-mod_quiz-selected {
@include border-start(5px, solid, $core-question-state-partial-text);
}
.item-inner {
@include push-arrow-color($core-question-state-partial-text);
border-bottom-color: $core-question-state-partial-text;
}
}
.item.core-question-requiresgrading,
.item.core-question-answersaved {
&.addon-mod_quiz-selected {
@include border-start(5px, solid, $text-color);
}
.item-inner {
@include push-arrow-color($text-color);
border-bottom-color: $text-color;
}
}
}

View File

@ -11,4 +11,9 @@ ion-app.app-root page-addon-mod-quiz-player {
.toolbar-ios .bar-buttons-ios .bar-button {
@include padding-horizontal($content-padding);
}
.core-question-container {
display: block;
padding-bottom: $content-padding;
}
}

View File

@ -22,36 +22,36 @@
<h2 *ngIf="!attempt.preview">{{ 'addon.mod_quiz.reviewofattempt' | translate:{$a: attempt.attempt} }}</h2>
</ion-card-header>
<ion-list>
<ion-item text-wrap>
<p class="item-heading">{{ 'addon.mod_quiz.startedon' | translate }}</p>
<ion-item text-wrap no-lines>
<h2>{{ 'addon.mod_quiz.startedon' | translate }}</h2>
<p>{{ attempt.timestart * 1000 | coreFormatDate }}</p>
</ion-item>
<ion-item text-wrap>
<p class="item-heading">{{ 'addon.mod_quiz.attemptstate' | translate }}</p>
<ion-item text-wrap no-lines>
<h2>{{ 'addon.mod_quiz.attemptstate' | translate }}</h2>
<p>{{ attempt.readableState }}</p>
</ion-item>
<ion-item text-wrap *ngIf="showCompleted">
<p class="item-heading">{{ 'addon.mod_quiz.completedon' | translate }}</p>
<ion-item text-wrap no-lines *ngIf="showCompleted">
<h2>{{ 'addon.mod_quiz.completedon' | translate }}</h2>
<p>{{ attempt.timefinish * 1000 | coreFormatDate }}</p>
</ion-item>
<ion-item text-wrap *ngIf="attempt.timeTaken">
<p class="item-heading">{{ 'addon.mod_quiz.timetaken' | translate }}</p>
<ion-item text-wrap no-lines *ngIf="attempt.timeTaken">
<h2>{{ 'addon.mod_quiz.timetaken' | translate }}</h2>
<p>{{ attempt.timeTaken }}</p>
</ion-item>
<ion-item text-wrap *ngIf="attempt.overTime">
<p class="item-heading">{{ 'addon.mod_quiz.overdue' | translate }}</p>
<ion-item text-wrap no-lines *ngIf="attempt.overTime">
<h2>{{ 'addon.mod_quiz.overdue' | translate }}</h2>
<p>{{ attempt.overTime }}</p>
</ion-item>
<ion-item text-wrap *ngIf="attempt.readableMark">
<p class="item-heading">{{ 'addon.mod_quiz.marks' | translate }}</p>
<ion-item text-wrap no-lines *ngIf="attempt.readableMark">
<h2>{{ 'addon.mod_quiz.marks' | translate }}</h2>
<p><core-format-text [text]="attempt.readableMark"></core-format-text></p>
</ion-item>
<ion-item text-wrap *ngIf="attempt.readableGrade">
<p class="item-heading">{{ 'addon.mod_quiz.grade' | translate }}</p>
<ion-item text-wrap no-lines *ngIf="attempt.readableGrade">
<h2>{{ 'addon.mod_quiz.grade' | translate }}</h2>
<p>{{ attempt.readableGrade }}</p>
</ion-item>
<ion-item text-wrap *ngFor="let data of additionalData">
<p class="item-heading">{{ data.title }}</p>
<ion-item text-wrap no-lines *ngFor="let data of additionalData">
<h2>{{ data.title }}</h2>
<core-format-text [component]="component" [componentId]="componentId" [text]="data.content"></core-format-text>
</ion-item>
</ion-list>
@ -70,7 +70,7 @@
<h2 *ngIf="question.number" class="inline">{{ 'core.question.questionno' | translate:{$a: question.number} }}</h2>
<h2 *ngIf="!question.number" class="inline">{{ 'core.question.information' | translate }}</h2>
<ion-note text-wrap item-end *ngIf="question.status || question.readableMark">
<p *ngIf="question.status" class="block">{{question.status}}</p>
<p *ngIf="question.status">{{question.status}}</p>
<p *ngIf="question.readableMark"><core-format-text [text]="question.readableMark"></core-format-text></p>
</ion-note>
</ion-item-divider>

View File

@ -1,11 +1,12 @@
ion-app.app-root page-addon-mod-quiz-review {
.item-radio-disabled,
.item-checkbox-disabled,
.text-input[disabled] {
opacity: 1;
.item-select-disabled,
.item-input-disabled {
opacity: 0.8;
.label, .radio, .checkbox {
opacity: 1;
}
.label, .radio, .checkbox, .select-disabled, .core-correct-icon {
opacity: 1;
}
}
}

View File

@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonQtypeCalculatedHandler } from './providers/handler';
import { AddonQtypeCalculatedComponent } from './component/calculated';
@ -27,6 +28,7 @@ import { AddonQtypeCalculatedComponent } from './component/calculated';
imports: [
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
],
providers: [

View File

@ -8,8 +8,9 @@
<ng-container *ngTemplateOutlet="radioUnits"></ng-container>
</ng-container>
<ion-item text-wrap ion-grid>
<ion-grid item-content>
<ion-item text-wrap ion-grid ngClass="core-{{question.input.correctIconColor}}-item">
<ion-label stacked>{{ 'addon.mod_quiz.answercolon' | translate }}</ion-label>
<ion-grid item-content no-padding>
<ion-row>
<!-- Display unit select before the answer input. -->
<ng-container *ngIf="question.select && question.selectFirst">
@ -18,7 +19,7 @@
<!-- Input to enter the answer. -->
<ion-col>
<ion-input padding-left type="text" placeholder="{{ 'core.question.answer' | translate }}" [attr.name]="question.input.name" [value]="question.input.value" [disabled]="question.input.readOnly" [ngClass]="[question.input.correctClass]" autocorrect="off">
<ion-input padding-left type="text" [placeholder]="question.input.readOnly ? '' : 'core.question.answer' | translate" [attr.name]="question.input.name" [value]="question.input.value" [disabled]="question.input.readOnly" autocorrect="off">
</ion-input>
</ion-col>
@ -27,6 +28,7 @@
<ng-container *ngTemplateOutlet="selectUnits"></ng-container>
</ng-container>
</ion-row>
<core-icon *ngIf="question.input.correctIcon" class="core-correct-icon" item-content item-end [name]="question.input.correctIcon" [color]="[question.input.correctIconColor]"></core-icon>
</ion-grid>
</ion-item>
@ -54,9 +56,9 @@
<div radio-group [(ngModel)]="question.unit" [name]="question.optionsName">
<ion-item text-wrap *ngFor="let option of question.options">
<ion-label>
<p>{{option.text}}</p>
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text"></core-format-text>
</ion-label>
<ion-radio [value]="option.value" [disabled]="option.disabled || question.input.readOnly"></ion-radio>
<ion-radio [value]="option.value" [disabled]="option.disabled || question.input.readOnly" [color]="question.input.correctIconColor"></ion-radio>
</ion-item>
<!-- ion-radio doesn't use an input. Create a hidden input to hold the selected value. -->

View File

@ -0,0 +1,5 @@
ion-app.app-root addon-qtype-calculated {
ion-col .select-disabled {
@include margin(0, 20px, 0, 0);
}
}

View File

@ -29,30 +29,12 @@ addon-qtype-ddimageortext {
zoom: 1;
}
.group1 {
background-color: $white;
}
.group2 {
background-color: $blue-light;
}
.group3 {
background-color: #DCDCDC;
}
.group4 {
background-color: #D8BFD8;
}
.group5 {
background-color: #87CEFA;
}
.group6 {
background-color: #DAA520;
}
.group7 {
background-color: #FFD700;
}
.group8 {
background-color: #F0E68C;
@for $i from 0 to length($core-dd-question-colors) {
.group#{$i + 1} {
background: nth($core-dd-question-colors, $i + 1);
}
}
.drag {
border: 1px solid $gray-darker;
cursor: pointer;
@ -96,6 +78,6 @@ addon-qtype-ddimageortext {
}
.drag.beingdragged {
z-index: 3;
box-shadow: 3px 3px 4px $gray-darker;
box-shadow: $core-dd-question-selected-shadow;
}
}

View File

@ -290,18 +290,13 @@ export class AddonQtypeDdMarkerQuestion {
* @param {string} shape Name of the shape of the drop zone (circle, rectangle, polygon).
* @param {string} coords Coordinates of the shape.
* @param {string} colour Colour of the shape.
* @param {boolean} link Whether the marker should have a link in it.
*/
drawDropZone(dropZoneNo: number, markerText: string, shape: string, coords: string, colour: string, link: boolean): void {
drawDropZone(dropZoneNo: number, markerText: string, shape: string, coords: string, colour: string): void {
let existingMarkerText: HTMLElement;
const markerTexts = this.doc.markerTexts();
// Check if there is already a marker text for this drop zone.
if (link) {
existingMarkerText = <HTMLElement> markerTexts.querySelector('span.markertext' + dropZoneNo + ' a');
} else {
existingMarkerText = <HTMLElement> markerTexts.querySelector('span.markertext' + dropZoneNo);
}
existingMarkerText = <HTMLElement> markerTexts.querySelector('span.markertext' + dropZoneNo);
if (existingMarkerText) {
// Marker text already exists. Update it or remove it if empty.
@ -316,12 +311,7 @@ export class AddonQtypeDdMarkerQuestion {
span = document.createElement('span');
span.className = classNames;
if (link) {
span.innerHTML = '<a href="#">' + markerText + '</a>';
} else {
span.innerHTML = markerText;
}
span.innerHTML = markerText;
markerTexts.appendChild(span);
}
@ -802,7 +792,7 @@ export class AddonQtypeDdMarkerQuestion {
dropZone = this.dropZones[dropZoneNo],
dzNo = Number(dropZoneNo);
this.drawDropZone(dzNo, dropZone.markertext, dropZone.shape, dropZone.coords, colourForDropZone, true);
this.drawDropZone(dzNo, dropZone.markertext, dropZone.shape, dropZone.coords, colourForDropZone);
}
}
}

View File

@ -33,7 +33,7 @@ addon-qtype-ddmarker {
.dragitem.beingdragged .markertext {
z-index: 5;
box-shadow: 3px 3px 4px $gray-darker;
box-shadow: $core-dd-question-selected-shadow;
}
.dragitems .draghome {
margin: 10px;

View File

@ -40,10 +40,11 @@ addon-qtype-ddwtos {
.drag {
z-index: 2;
border-radius: 5px;
line-height: 25px;
}
.drag.selected {
z-index: 3;
box-shadow: 3px 3px 4px $gray-darker;
box-shadow: $core-dd-question-selected-shadow;
}
.drop.selected {
@ -73,29 +74,10 @@ addon-qtype-ddwtos {
background-color: $green-light;
}
.group1 {
background-color: $white;
}
.group2 {
background-color: #DCDCDC;
}
.group3 {
background-color: $blue-light;
}
.group4 {
background-color: #D8BFD8;
}
.group5 {
background-color: #87CEFA;
}
.group6 {
background-color: #DAA520;
}
.group7 {
background-color: #FFD700;
}
.group8 {
background-color: #F0E68C;
@for $i from 0 to length($core-dd-question-colors) {
.group#{$i + 1} {
background: nth($core-dd-question-colors, $i + 1);
}
}
sub, sup {

View File

@ -1,5 +1,5 @@
// Style gapselect content a bit. All these styles are copied from Moodle.
addon-qtype-gapselect {
ion-app.app-root addon-qtype-gapselect {
p {
margin: 0 0 .5em;
}
@ -15,5 +15,11 @@ addon-qtype-gapselect {
border-radius: 4px;
margin-bottom: 10px;
background: $gray-lighter;
&.core-question-answer-correct,
&.core-question-answer-incorrect {
background-color: $gray-lighter;
color: $text-color;
}
}
}

View File

@ -1,19 +1,22 @@
<section ion-list class="addon-qtype-match-container" *ngIf="question.loaded">
<ion-item text-wrap>
<p><core-format-text [component]="component" [componentId]="componentId" [text]="question.text"></core-format-text></p>
<core-format-text [component]="component" [componentId]="componentId" [text]="question.text"></core-format-text>
</ion-item>
<ion-item text-wrap *ngFor="let row of question.rows">
<ion-grid item-content>
<ion-row>
<ion-grid item-content no-margin no-padding>
<ion-row no-margin>
<ion-col>
<p><core-format-text id="addon-qtype-match-question-{{row.id}}" [component]="component" [componentId]="componentId" [text]="row.text"></core-format-text></p>
</ion-col>
<ion-col [ngClass]='{"core-question-answer-correct": row.isCorrect === 1, "core-question-answer-incorrect": row.isCorrect === 0}'>
<ion-col>
<label class="accesshide" for="{{row.id}}" *ngIf="row.accessibilityLabel">{{ row.accessibilityLabel }}</label>
<ion-select id="{{row.id}}" [name]="row.name" [attr.aria-labelledby]="'addon-qtype-match-question-' + row.id" [(ngModel)]="row.selected" interface="action-sheet" [disabled]="row.disabled">
<ion-select id="{{row.id}}" [name]="row.name" [attr.aria-labelledby]="'addon-qtype-match-question-' + row.id" [(ngModel)]="row.selected" interface="action-sheet" [disabled]="row.disabled" [color]='(row.isCorrect === 1 ? "success": "") + (row.isCorrect === 0 ? "danger": "")'>
<ion-option *ngFor="let option of row.options" [value]="option.value">{{option.label}}</ion-option>
</ion-select>
<core-icon *ngIf="row.isCorrect === 1" class="core-correct-icon" name="fa-check" color="success"></core-icon>
<core-icon *ngIf="row.isCorrect === 0" class="core-correct-icon" name="fa-remove" color="danger"></core-icon>
<!-- ion-select doesn't use a select. Create a hidden input to hold the selected value. -->
<input type="hidden" [ngModel]="row.selected" [attr.name]="row.name">
</ion-col>

View File

@ -0,0 +1,10 @@
ion-app.app-root addon-qtype-match {
ion-col .select-disabled {
@include margin(0, 20px, 0, 0);
}
.core-correct-icon {
bottom: 50%;
margin-bottom: -7px;
}
}

View File

@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonQtypeMatchHandler } from './providers/handler';
import { AddonQtypeMatchComponent } from './component/match';
@ -27,6 +28,7 @@ import { AddonQtypeMatchComponent } from './component/match';
imports: [
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
],
providers: [

View File

@ -1,5 +1,5 @@
<section ion-list class="addon-qtype-multianswer-container" *ngIf="question.text || question.text === ''">
<ion-item text-wrap>
<p><core-format-text [component]="component" [componentId]="componentId" [text]="question.text" (afterRender)="questionRendered()"></core-format-text></p>
<core-format-text [component]="component" [componentId]="componentId" [text]="question.text" (afterRender)="questionRendered()"></core-format-text>
</ion-item>
</section>

View File

@ -1,18 +1,20 @@
<section ion-list *ngIf="question.text || question.text === ''">
<!-- Question text first. -->
<ion-item text-wrap>
<p><core-format-text [component]="component" [componentId]="componentId" [text]="question.text"></core-format-text></p>
<p *ngIf="question.prompt"><core-format-text [component]="component" [componentId]="componentId" [text]="question.prompt"></core-format-text></p>
<core-format-text [component]="component" [componentId]="componentId" [text]="question.text"></core-format-text>
<core-format-text [component]="component" [componentId]="componentId" [text]="question.prompt" *ngIf="question.prompt"></core-format-text>
</ion-item>
<!-- Checkbox for multiple choice. -->
<ng-container *ngIf="question.multi">
<ion-item text-wrap *ngFor="let option of question.options" [ngClass]="{'core-question-answer-correct': option.isCorrect === 1, 'core-question-answer-incorrect': option.isCorrect === 0}">
<ion-label>
<ion-item text-wrap *ngFor="let option of question.options">
<ion-label [color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")'>
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text"></core-format-text>
<p *ngIf="option.feedback" class="core-question-feedback-container"><core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback"></core-format-text></p>
<div *ngIf="option.feedback" class="specificfeedback"><core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback"></core-format-text></div>
</ion-label>
<ion-checkbox [attr.name]="option.name" [(ngModel)]="option.checked" [disabled]="option.disabled" item-end></ion-checkbox>
<ion-checkbox [attr.name]="option.name" [(ngModel)]="option.checked" [disabled]="option.disabled" item-end [color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")'></ion-checkbox>
<core-icon item-content *ngIf="option.isCorrect === 1" class="core-correct-icon" name="fa-check" color="success"></core-icon>
<core-icon item-content *ngIf="option.isCorrect === 0" class="core-correct-icon" name="fa-remove" color="danger"></core-icon>
<!-- ion-checkbox doesn't use an input. Create a hidden input to hold the value. -->
<input item-content type="hidden" [ngModel]="option.checked" [attr.name]="option.name">
@ -21,12 +23,14 @@
<!-- Radio buttons for single choice. -->
<div *ngIf="!question.multi" radio-group [(ngModel)]="question.singleChoiceModel" [name]="question.optionsName">
<ion-item text-wrap *ngFor="let option of question.options" [ngClass]='{"core-question-answer-correct": option.isCorrect === 1, "core-question-answer-incorrect": option.isCorrect === 0}'>
<ion-item text-wrap *ngFor="let option of question.options">
<ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text"></core-format-text>
<p *ngIf="option.feedback" class="core-question-feedback-container"><core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback"></core-format-text></p>
<div *ngIf="option.feedback" class="specificfeedback"><core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback"></core-format-text></div>
</ion-label>
<ion-radio [value]="option.value" [disabled]="option.disabled"></ion-radio>
<ion-radio [value]="option.value" [disabled]="option.disabled" [color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")'></ion-radio>
<core-icon item-content *ngIf="option.isCorrect === 1" class="core-correct-icon" name="fa-check" color="success"></core-icon>
<core-icon item-content *ngIf="option.isCorrect === 0" class="core-correct-icon" name="fa-remove" color="danger"></core-icon>
</ion-item>
<!-- ion-radio doesn't use an input. Create a hidden input to hold the selected value. -->

View File

@ -0,0 +1,13 @@
ion-app.app-root addon-qtype-multichoice {
.core-correct-icon {
bottom: 50%;
margin-bottom: -7px;
}
.specificfeedback {
background-color: $core-question-feedback-color-bg;
color: $core-question-feedback-color;
display: inline;
padding: 0 .7em;
}
}

View File

@ -17,6 +17,7 @@ import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreComponentsModule } from '@components/components.module';
import { AddonQtypeMultichoiceHandler } from './providers/handler';
import { AddonQtypeMultichoiceComponent } from './component/multichoice';
@ -27,6 +28,7 @@ import { AddonQtypeMultichoiceComponent } from './component/multichoice';
imports: [
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
],
providers: [

View File

@ -2,6 +2,10 @@
<ion-item text-wrap>
<p><core-format-text [component]="component" [componentId]="componentId" [text]="question.text"></core-format-text></p>
</ion-item>
<ion-input padding-left type="text" placeholder="{{ 'core.question.answer' | translate }}" [attr.name]="question.input.name" [value]="question.input.value" autocorrect="off" [disabled]="question.input.readOnly" [ngClass]="[question.input.correctClass]">
</ion-input>
<ion-item text-wrap ngClass="core-{{question.input.correctIconColor}}-item">
<ion-label stacked>{{ 'addon.mod_quiz.answercolon' | translate }}</ion-label>
<ion-input padding-left type="text" [placeholder]="question.input.readOnly ? '' : 'core.question.answer' | translate" [attr.name]="question.input.name" [value]="question.input.value" autocorrect="off" [disabled]="question.input.readOnly">
</ion-input>
<core-icon *ngIf="question.input.correctIcon" class="core-correct-icon" item-content item-end [name]="question.input.correctIcon" [color]="[question.input.correctIconColor]"></core-icon>
</ion-item>
</section>

View File

@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonQtypeShortAnswerHandler } from './providers/handler';
import { AddonQtypeShortAnswerComponent } from './component/shortanswer';
@ -27,6 +28,7 @@ import { AddonQtypeShortAnswerComponent } from './component/shortanswer';
imports: [
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
],
providers: [

View File

@ -378,6 +378,21 @@ ion-app.app-root {
.select-icon .select-icon-inner {
color: $core-select-placeholder-color;
}
&.select-disabled, .select-icon .select-icon-inner {
color: $text-color;
}
@each $color-name, $color-base, $color-contrast in get-colors($colors) {
&.select-md-#{$color-name},
&.select-ios-#{$color-name},
&.select-wp-#{$color-name} {
color: $color-base;
.select-icon .select-icon-inner {
color: $color-base;
}
}
}
}
ion-select.core-button-select,
@ -454,8 +469,16 @@ ion-app.app-root {
// Question.
// -------------------------
.core-correct-icon {
padding: 0 ($content-padding / 2);
position: absolute;
@include position(null, 0, $content-padding / 2, null);
margin-top: 0;
margin-bottom: 0;
}
.core-question-answer-correct,
.core-question-correct,
.core-question-comment {
color: $core-question-correct-color;
background-color: $core-question-correct-color-bg;
@ -533,7 +556,8 @@ ion-app.app-root {
.core-question-incorrect {
background-color: $core-question-state-incorrect-color;
}
.core-question-answersaved {
.core-question-answersaved,
.core-question-requiresgrading {
color: $text-color;
background-color: $core-question-saved-color-bg;
}

View File

@ -602,6 +602,7 @@
"addon.mod_lti.modulenameplural": "External tools",
"addon.mod_page.errorwhileloadingthepage": "Error while loading the page content.",
"addon.mod_page.modulenameplural": "Pages",
"addon.mod_quiz.answercolon": "Answer:",
"addon.mod_quiz.attemptfirst": "First attempt",
"addon.mod_quiz.attemptlast": "Last attempt",
"addon.mod_quiz.attemptnumber": "Attempt",

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Input, Output, EventEmitter, Injector } from '@angular/core';
import { Input, Output, EventEmitter, Injector, ElementRef } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
@ -34,6 +34,7 @@ export class CoreQuestionBaseComponent {
protected questionHelper: CoreQuestionHelperProvider;
protected domUtils: CoreDomUtilsProvider;
protected textUtils: CoreTextUtilsProvider;
protected realElement: HTMLElement;
constructor(logger: CoreLoggerProvider, logName: string, protected injector: Injector) {
this.logger = logger.getInstance(logName);
@ -42,6 +43,7 @@ export class CoreQuestionBaseComponent {
this.questionHelper = injector.get(CoreQuestionHelperProvider);
this.domUtils = injector.get(CoreDomUtilsProvider);
this.textUtils = injector.get(CoreTextUtilsProvider);
this.realElement = injector.get(ElementRef).nativeElement;
}
/**
@ -172,6 +174,8 @@ export class CoreQuestionBaseComponent {
return this.questionHelper.showComponentError(this.onAbort);
}
this.realElement.classList.add('core-question-container');
const element = this.domUtils.convertToElement(this.question.html);
// Extract question text.
@ -291,12 +295,20 @@ export class CoreQuestionBaseComponent {
// Check if question is marked as correct.
if (input.classList.contains('incorrect')) {
this.question.input.correctClass = 'core-question-incorrect';
this.question.input.correctIcon = 'fa-remove';
this.question.input.correctIconColor = 'danger';
} else if (input.classList.contains('correct')) {
this.question.input.correctClass = 'core-question-correct';
this.question.input.correctIcon = 'fa-check';
this.question.input.correctIconColor = 'success';
} else if (input.classList.contains('partiallycorrect')) {
this.question.input.correctClass = 'core-question-partiallycorrect';
this.question.input.correctIcon = 'fa-check-square';
this.question.input.correctIconColor = 'warning';
} else {
this.question.input.correctClass = '';
this.question.input.correctIcon = '';
this.question.input.correctIconColor = '';
}
}

View File

@ -279,8 +279,12 @@ $core-question-saved-color-bg: $gray-light !default;
$core-question-state-correct-color: $green-light !default;
$core-question-state-partial-color: $yellow-light !default;
$core-question-state-partial-text: $yellow !default;
$core-question-state-incorrect-color: $red-light !default;
$core-dd-question-selected-shadow: 2px 2px 4px $gray-dark !default;
$core-dd-question-colors: $white, $blue-light, #DCDCDC, #D8BFD8, #87CEFA, #DAA520, #FFD700, #F0E68C !default;
// Mixins
// -------------------------
@mixin core-transition($where: all, $time: 500ms) {