Merge pull request #3618 from NoelDeMartin/MOBILE-4284
MOBILE-4284: Implement custom question numbers in quizmain
commit
9e72d79eba
|
@ -18,11 +18,11 @@
|
||||||
(click)="loadPage(question.page, question.slot)" detail="false">
|
(click)="loadPage(question.page, question.slot)" detail="false">
|
||||||
|
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<span *ngIf="question.number">{{ 'core.question.questionno' | translate:{$a: question.number} }}</span>
|
<span *ngIf="question.questionnumber">{{ 'core.question.questionno' | translate:{$a: question.questionnumber} }}</span>
|
||||||
<span *ngIf="!question.number">{{ 'core.question.information' | translate }}</span>
|
<span *ngIf="!question.questionnumber">{{ 'core.question.information' | translate }}</span>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
|
|
||||||
<ion-icon *ngIf="!question.number" name="fas-circle-info" slot="end" aria-hidden="true"></ion-icon>
|
<ion-icon *ngIf="!question.questionnumber" name="fas-circle-info" slot="end" aria-hidden="true"></ion-icon>
|
||||||
<ion-icon *ngIf="question.stateClass == 'core-question-requiresgrading'" name="fas-circle-question"
|
<ion-icon *ngIf="question.stateClass == 'core-question-requiresgrading'" name="fas-circle-question"
|
||||||
[attr.aria-label]="question.status" slot="end">
|
[attr.aria-label]="question.status" slot="end">
|
||||||
</ion-icon>
|
</ion-icon>
|
||||||
|
|
|
@ -44,10 +44,10 @@
|
||||||
<!-- "Header" of the question. -->
|
<!-- "Header" of the question. -->
|
||||||
<ion-item-divider>
|
<ion-item-divider>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2 *ngIf="question.number" class="inline">
|
<h2 *ngIf="question.questionnumber" class="inline">
|
||||||
{{ 'core.question.questionno' | translate:{$a: question.number} }}
|
{{ 'core.question.questionno' | translate:{$a: question.questionnumber} }}
|
||||||
</h2>
|
</h2>
|
||||||
<h2 *ngIf="!question.number" class="inline">{{ 'core.question.information' | translate }}</h2>
|
<h2 *ngIf="!question.questionnumber" class="inline">{{ 'core.question.information' | translate }}</h2>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<div *ngIf="question.status || question.readableMark" slot="end"
|
<div *ngIf="question.status || question.readableMark" slot="end"
|
||||||
class="ion-text-wrap ion-margin-horizontal addon-mod_quiz-question-note">
|
class="ion-text-wrap ion-margin-horizontal addon-mod_quiz-question-note">
|
||||||
|
@ -108,12 +108,12 @@
|
||||||
|
|
||||||
<!-- List of questions of the summary table. -->
|
<!-- List of questions of the summary table. -->
|
||||||
<ng-container *ngFor="let question of summaryQuestions">
|
<ng-container *ngFor="let question of summaryQuestions">
|
||||||
<ion-item *ngIf="question.number" (click)="changePage(question.page, false, question.slot)"
|
<ion-item *ngIf="question.questionnumber" (click)="changePage(question.page, false, question.slot)"
|
||||||
[attr.aria-label]="'core.question.questionno' | translate:{$a: question.number}" [detail]="!isSequential && canReturn"
|
[attr.aria-label]="'core.question.questionno' | translate:{$a: question.questionnumber}"
|
||||||
[button]="!isSequential && canReturn">
|
[detail]="!isSequential && canReturn" [button]="!isSequential && canReturn">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<ion-row class="ion-align-items-center">
|
<ion-row class="ion-align-items-center">
|
||||||
<ion-col size="3" class="ion-text-center">{{ question.number }}</ion-col>
|
<ion-col size="3" class="ion-text-center">{{ question.questionnumber }}</ion-col>
|
||||||
<ion-col size="9" class="ion-text-center ion-text-wrap">{{ question.status }}</ion-col>
|
<ion-col size="9" class="ion-text-center ion-text-wrap">{{ question.status }}</ion-col>
|
||||||
</ion-row>
|
</ion-row>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
|
|
|
@ -86,8 +86,9 @@
|
||||||
<!-- "Header" of the question. -->
|
<!-- "Header" of the question. -->
|
||||||
<ion-item-divider>
|
<ion-item-divider>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2 *ngIf="question.number">{{ 'core.question.questionno' | translate:{$a: question.number} }}</h2>
|
<h2 *ngIf="question.questionnumber">{{ 'core.question.questionno' | translate:{$a: question.questionnumber} }}
|
||||||
<h2 *ngIf="!question.number">{{ 'core.question.information' | translate }}</h2>
|
</h2>
|
||||||
|
<h2 *ngIf="!question.questionnumber">{{ 'core.question.information' | translate }}</h2>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<div class="ion-text-wrap ion-margin-horizontal addon-mod_quiz-question-note" slot="end"
|
<div class="ion-text-wrap ion-margin-horizontal addon-mod_quiz-question-note" slot="end"
|
||||||
*ngIf="question.status || question.readableMark">
|
*ngIf="question.status || question.readableMark">
|
||||||
|
|
|
@ -12,16 +12,17 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { SQLiteDB } from '@classes/sqlitedb';
|
||||||
import { CoreSiteSchema } from '@services/sites';
|
import { CoreSiteSchema } from '@services/sites';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database variables for CoreQuestion service.
|
* Database variables for CoreQuestion service.
|
||||||
*/
|
*/
|
||||||
export const QUESTION_TABLE_NAME = 'questions';
|
export const QUESTION_TABLE_NAME = 'questions_2';
|
||||||
export const QUESTION_ANSWERS_TABLE_NAME = 'question_answers';
|
export const QUESTION_ANSWERS_TABLE_NAME = 'question_answers';
|
||||||
export const QUESTION_SITE_SCHEMA: CoreSiteSchema = {
|
export const QUESTION_SITE_SCHEMA: CoreSiteSchema = {
|
||||||
name: 'CoreQuestionProvider',
|
name: 'CoreQuestionProvider',
|
||||||
version: 1,
|
version: 2,
|
||||||
tables: [
|
tables: [
|
||||||
{
|
{
|
||||||
name: QUESTION_TABLE_NAME,
|
name: QUESTION_TABLE_NAME,
|
||||||
|
@ -45,14 +46,6 @@ export const QUESTION_SITE_SCHEMA: CoreSiteSchema = {
|
||||||
name: 'componentid',
|
name: 'componentid',
|
||||||
type: 'INTEGER',
|
type: 'INTEGER',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'userid',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'number',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'state',
|
name: 'state',
|
||||||
type: 'TEXT',
|
type: 'TEXT',
|
||||||
|
@ -102,6 +95,15 @@ export const QUESTION_SITE_SCHEMA: CoreSiteSchema = {
|
||||||
primaryKeys: ['component', 'attemptid', 'name'],
|
primaryKeys: ['component', 'attemptid', 'name'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
async migrate(db: SQLiteDB, oldVersion: number): Promise<void> {
|
||||||
|
if (oldVersion < 2) {
|
||||||
|
await db.migrateTable(
|
||||||
|
'questions',
|
||||||
|
QUESTION_TABLE_NAME,
|
||||||
|
({ component, componentid, attemptid, slot, state }) => ({ component, componentid, attemptid, slot, state }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,8 +114,6 @@ export type CoreQuestionDBRecord = {
|
||||||
attemptid: number;
|
attemptid: number;
|
||||||
slot: number;
|
slot: number;
|
||||||
componentid: number;
|
componentid: number;
|
||||||
userid: number;
|
|
||||||
number?: number; // eslint-disable-line id-blacklist
|
|
||||||
state: string;
|
state: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -637,7 +637,7 @@ export class CoreQuestionHelperProvider {
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!component) {
|
if (!component) {
|
||||||
component = CoreQuestionProvider.COMPONENT;
|
component = CoreQuestionProvider.COMPONENT;
|
||||||
componentId = question.number;
|
componentId = question.questionnumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
const files = CoreQuestionDelegate.getAdditionalDownloadableFiles(question, usageId) || [];
|
const files = CoreQuestionDelegate.getAdditionalDownloadableFiles(question, usageId) || [];
|
||||||
|
|
|
@ -314,7 +314,7 @@ export class CoreQuestionProvider {
|
||||||
* @returns Question component ID.
|
* @returns Question component ID.
|
||||||
*/
|
*/
|
||||||
getQuestionComponentId(question: CoreQuestionQuestionParsed, componentId: string | number): string {
|
getQuestionComponentId(question: CoreQuestionQuestionParsed, componentId: string | number): string {
|
||||||
return componentId + '_' + question.number;
|
return componentId + '_' + question.questionnumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -385,6 +385,10 @@ export class CoreQuestionProvider {
|
||||||
const parsedQuestions: CoreQuestionQuestionParsed[] = questions;
|
const parsedQuestions: CoreQuestionQuestionParsed[] = questions;
|
||||||
|
|
||||||
parsedQuestions.forEach((question) => {
|
parsedQuestions.forEach((question) => {
|
||||||
|
if (typeof question.questionnumber === 'undefined' && typeof question.number === 'number') {
|
||||||
|
question.questionnumber = String(question.number);
|
||||||
|
}
|
||||||
|
|
||||||
if (!question.settings) {
|
if (!question.settings) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -547,14 +551,11 @@ export class CoreQuestionProvider {
|
||||||
state: string,
|
state: string,
|
||||||
siteId?: string,
|
siteId?: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
|
||||||
const site = await CoreSites.getSite(siteId);
|
const site = await CoreSites.getSite(siteId);
|
||||||
const entry: CoreQuestionDBRecord = {
|
const entry: CoreQuestionDBRecord = {
|
||||||
component,
|
component,
|
||||||
componentid: componentId,
|
componentid: componentId,
|
||||||
attemptid: attemptId,
|
attemptid: attemptId,
|
||||||
userid: userId,
|
|
||||||
number: question.number, // eslint-disable-line id-blacklist
|
|
||||||
slot: question.slot,
|
slot: question.slot,
|
||||||
state: state,
|
state: state,
|
||||||
};
|
};
|
||||||
|
@ -594,14 +595,16 @@ export type CoreQuestionQuestionWSData = {
|
||||||
lastactiontime?: number; // The timestamp of the most recent step in this question attempt.
|
lastactiontime?: number; // The timestamp of the most recent step in this question attempt.
|
||||||
hasautosavedstep?: boolean; // Whether this question attempt has autosaved data.
|
hasautosavedstep?: boolean; // Whether this question attempt has autosaved data.
|
||||||
flagged: boolean; // Whether the question is flagged or not.
|
flagged: boolean; // Whether the question is flagged or not.
|
||||||
// eslint-disable-next-line id-blacklist
|
questionnumber?: string; // @since 4.2. Question ordering number in the quiz.
|
||||||
number?: number; // Question ordering number in the quiz.
|
|
||||||
state?: string; // The state where the question is in. It won't be returned if the user cannot see it.
|
state?: string; // The state where the question is in. It won't be returned if the user cannot see it.
|
||||||
status?: string; // Current formatted state of the question.
|
status?: string; // Current formatted state of the question.
|
||||||
blockedbyprevious?: boolean; // Whether the question is blocked by the previous question.
|
blockedbyprevious?: boolean; // Whether the question is blocked by the previous question.
|
||||||
mark?: string; // The mark awarded. It will be returned only if the user is allowed to see it.
|
mark?: string; // The mark awarded. It will be returned only if the user is allowed to see it.
|
||||||
maxmark?: number; // The maximum mark possible for this question attempt.
|
maxmark?: number; // The maximum mark possible for this question attempt.
|
||||||
settings?: string; // Question settings (JSON encoded).
|
settings?: string; // Question settings (JSON encoded).
|
||||||
|
|
||||||
|
/** @deprecated Since 4.2. Use questionnumber instead. */
|
||||||
|
number?: number; // eslint-disable-line id-blacklist
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Question data with parsed data.
|
* Question data with parsed data.
|
||||||
|
|
Loading…
Reference in New Issue