MOBILE-2389 qtype: Implement shortanswer and numerical question types
This commit is contained in:
parent
7792efff55
commit
2f172f77dd
30
src/addon/qtype/numerical/numerical.module.ts
Normal file
30
src/addon/qtype/numerical/numerical.module.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// (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 { NgModule } from '@angular/core';
|
||||||
|
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
|
||||||
|
import { AddonQtypeNumericalHandler } from './providers/handler';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AddonQtypeNumericalHandler
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonQtypeNumericalModule {
|
||||||
|
constructor(questionDelegate: CoreQuestionDelegate, handler: AddonQtypeNumericalHandler) {
|
||||||
|
questionDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
125
src/addon/qtype/numerical/providers/handler.ts
Normal file
125
src/addon/qtype/numerical/providers/handler.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
|
||||||
|
// (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 { Injectable, Injector } from '@angular/core';
|
||||||
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
|
import { CoreQuestionHandler } from '@core/question/providers/delegate';
|
||||||
|
import { AddonQtypeShortAnswerComponent } from '@addon/qtype/shortanswer/component/shortanswer';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support numerical question type.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonQtypeNumericalHandler implements CoreQuestionHandler {
|
||||||
|
name = 'AddonQtypeNumerical';
|
||||||
|
type = 'qtype_numerical';
|
||||||
|
|
||||||
|
constructor(private utils: CoreUtilsProvider) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Component to use to display the question.
|
||||||
|
* It's recommended to return the class of the component, but you can also return an instance of the component.
|
||||||
|
*
|
||||||
|
* @param {Injector} injector Injector.
|
||||||
|
* @param {any} question The question to render.
|
||||||
|
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
|
||||||
|
*/
|
||||||
|
getComponent(injector: Injector, question: any): any | Promise<any> {
|
||||||
|
// Numerical behaves like a short answer, use the same component.
|
||||||
|
return AddonQtypeShortAnswerComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a response is complete.
|
||||||
|
*
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @param {any} answers Object with the question answers (without prefix).
|
||||||
|
* @return {number} 1 if complete, 0 if not complete, -1 if cannot determine.
|
||||||
|
*/
|
||||||
|
isCompleteResponse(question: any, answers: any): number {
|
||||||
|
if (this.isGradableResponse(question, answers) === 0 || !this.validateUnits(answers['answer'])) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the handler is enabled on a site level.
|
||||||
|
*
|
||||||
|
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
|
||||||
|
*/
|
||||||
|
isEnabled(): boolean | Promise<boolean> {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a student has provided enough of an answer for the question to be graded automatically,
|
||||||
|
* or whether it must be considered aborted.
|
||||||
|
*
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @param {any} answers Object with the question answers (without prefix).
|
||||||
|
* @return {number} 1 if gradable, 0 if not gradable, -1 if cannot determine.
|
||||||
|
*/
|
||||||
|
isGradableResponse(question: any, answers: any): number {
|
||||||
|
return (answers['answer'] || answers['answer'] === '0' || answers['answer'] === 0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if two responses are the same.
|
||||||
|
*
|
||||||
|
* @param {any} question Question.
|
||||||
|
* @param {any} prevAnswers Object with the previous question answers.
|
||||||
|
* @param {any} newAnswers Object with the new question answers.
|
||||||
|
* @return {boolean} Whether they're the same.
|
||||||
|
*/
|
||||||
|
isSameResponse(question: any, prevAnswers: any, newAnswers: any): boolean {
|
||||||
|
return this.utils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a number with units. We don't have the list of valid units and conversions, so we can't perform
|
||||||
|
* a full validation. If this function returns true it means we can't be sure it's valid.
|
||||||
|
*
|
||||||
|
* @param {string} answer Answer.
|
||||||
|
* @return {boolean} False if answer isn't valid, true if we aren't sure if it's valid.
|
||||||
|
*/
|
||||||
|
validateUnits(answer: string): boolean {
|
||||||
|
if (!answer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const regexString = '[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[-+]?\\d+)?';
|
||||||
|
|
||||||
|
// Strip spaces (which may be thousands separators) and change other forms of writing e to e.
|
||||||
|
answer = answer.replace(' ', '');
|
||||||
|
answer = answer.replace(/(?:e|E|(?:x|\*|×)10(?:\^|\*\*))([+-]?\d+)/, 'e$1');
|
||||||
|
|
||||||
|
// If a '.' is present or there are multiple ',' (i.e. 2,456,789) assume ',' is a thousands separator and stip it.
|
||||||
|
// Else assume it is a decimal separator, and change it to '.'.
|
||||||
|
if (answer.indexOf('.') != -1 || answer.split(',').length - 1 > 1) {
|
||||||
|
answer = answer.replace(',', '');
|
||||||
|
} else {
|
||||||
|
answer = answer.replace(',', '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't know if units should be before or after so we check both.
|
||||||
|
if (answer.match(new RegExp('^' + regexString)) === null || answer.match(new RegExp(regexString + '$')) === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
29
src/addon/qtype/qtype.module.ts
Normal file
29
src/addon/qtype/qtype.module.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// (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 { NgModule } from '@angular/core';
|
||||||
|
import { AddonQtypeNumericalModule } from './numerical/numerical.module';
|
||||||
|
import { AddonQtypeShortAnswerModule } from './shortanswer/shortanswer.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [
|
||||||
|
AddonQtypeNumericalModule,
|
||||||
|
AddonQtypeShortAnswerModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
],
|
||||||
|
exports: []
|
||||||
|
})
|
||||||
|
export class AddonQtypeModule { }
|
7
src/addon/qtype/shortanswer/component/shortanswer.html
Normal file
7
src/addon/qtype/shortanswer/component/shortanswer.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<section ion-list *ngIf="question.text || question.text === ''">
|
||||||
|
<ion-item text-wrap>
|
||||||
|
<p><core-format-text [component]="component" [componentId]="componentId" [text]="question.text"></core-format-text></p>
|
||||||
|
</ion-item>
|
||||||
|
<ion-input type="text" placeholder="{{ 'core.question.answer' | translate }}" [attr.name]="question.input.name" [value]="question.input.value" autocorrect="off" [disabled]="question.input.readOnly" [ngClass]='{"core-question-answer-correct": question.input.isCorrect === 1, "core-question-answer-incorrect": question.input.isCorrect === 0}'>
|
||||||
|
</ion-input>
|
||||||
|
</section>
|
40
src/addon/qtype/shortanswer/component/shortanswer.ts
Normal file
40
src/addon/qtype/shortanswer/component/shortanswer.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// (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, OnInit } from '@angular/core';
|
||||||
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
|
import { CoreQuestionHelperProvider } from '@core/question/providers/helper';
|
||||||
|
import { CoreQuestionBaseComponent } from '@core/question/classes/base-question-component';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component to render a short answer question.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'addon-qtype-shortanswer',
|
||||||
|
templateUrl: 'shortanswer.html'
|
||||||
|
})
|
||||||
|
export class AddonQtypeShortAnswerComponent extends CoreQuestionBaseComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(logger: CoreLoggerProvider, questionHelper: CoreQuestionHelperProvider, domUtils: CoreDomUtilsProvider) {
|
||||||
|
super(logger, 'AddonQtypeShortAnswerComponent', questionHelper, domUtils);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component being initialized.
|
||||||
|
*/
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.initInputTextComponent();
|
||||||
|
}
|
||||||
|
}
|
86
src/addon/qtype/shortanswer/providers/handler.ts
Normal file
86
src/addon/qtype/shortanswer/providers/handler.ts
Normal file
@ -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 { Injectable, Injector } from '@angular/core';
|
||||||
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
|
import { CoreQuestionHandler } from '@core/question/providers/delegate';
|
||||||
|
import { AddonQtypeShortAnswerComponent } from '../component/shortanswer';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support short answer question type.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonQtypeShortAnswerHandler implements CoreQuestionHandler {
|
||||||
|
name = 'AddonQtypeShortAnswer';
|
||||||
|
type = 'qtype_shortanswer';
|
||||||
|
|
||||||
|
constructor(private utils: CoreUtilsProvider) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Component to use to display the question.
|
||||||
|
* It's recommended to return the class of the component, but you can also return an instance of the component.
|
||||||
|
*
|
||||||
|
* @param {Injector} injector Injector.
|
||||||
|
* @param {any} question The question to render.
|
||||||
|
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
|
||||||
|
*/
|
||||||
|
getComponent(injector: Injector, question: any): any | Promise<any> {
|
||||||
|
return AddonQtypeShortAnswerComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a response is complete.
|
||||||
|
*
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @param {any} answers Object with the question answers (without prefix).
|
||||||
|
* @return {number} 1 if complete, 0 if not complete, -1 if cannot determine.
|
||||||
|
*/
|
||||||
|
isCompleteResponse(question: any, answers: any): number {
|
||||||
|
return (answers['answer'] || answers['answer'] === 0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the handler is enabled on a site level.
|
||||||
|
*
|
||||||
|
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
|
||||||
|
*/
|
||||||
|
isEnabled(): boolean | Promise<boolean> {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a student has provided enough of an answer for the question to be graded automatically,
|
||||||
|
* or whether it must be considered aborted.
|
||||||
|
*
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @param {any} answers Object with the question answers (without prefix).
|
||||||
|
* @return {number} 1 if gradable, 0 if not gradable, -1 if cannot determine.
|
||||||
|
*/
|
||||||
|
isGradableResponse(question: any, answers: any): number {
|
||||||
|
return this.isCompleteResponse(question, answers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if two responses are the same.
|
||||||
|
*
|
||||||
|
* @param {any} question Question.
|
||||||
|
* @param {any} prevAnswers Object with the previous question answers.
|
||||||
|
* @param {any} newAnswers Object with the new question answers.
|
||||||
|
* @return {boolean} Whether they're the same.
|
||||||
|
*/
|
||||||
|
isSameResponse(question: any, prevAnswers: any, newAnswers: any): boolean {
|
||||||
|
return this.utils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
|
||||||
|
}
|
||||||
|
}
|
46
src/addon/qtype/shortanswer/shortanswer.module.ts
Normal file
46
src/addon/qtype/shortanswer/shortanswer.module.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// (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 { NgModule } from '@angular/core';
|
||||||
|
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 { AddonQtypeShortAnswerHandler } from './providers/handler';
|
||||||
|
import { AddonQtypeShortAnswerComponent } from './component/shortanswer';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AddonQtypeShortAnswerComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
IonicModule,
|
||||||
|
TranslateModule.forChild(),
|
||||||
|
CoreDirectivesModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AddonQtypeShortAnswerHandler
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
AddonQtypeShortAnswerComponent
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
AddonQtypeShortAnswerComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonQtypeShortAnswerModule {
|
||||||
|
constructor(questionDelegate: CoreQuestionDelegate, handler: AddonQtypeShortAnswerHandler) {
|
||||||
|
questionDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
@ -87,6 +87,7 @@ import { AddonNotesModule } from '../addon/notes/notes.module';
|
|||||||
import { AddonPushNotificationsModule } from '@addon/pushnotifications/pushnotifications.module';
|
import { AddonPushNotificationsModule } from '@addon/pushnotifications/pushnotifications.module';
|
||||||
import { AddonRemoteThemesModule } from '@addon/remotethemes/remotethemes.module';
|
import { AddonRemoteThemesModule } from '@addon/remotethemes/remotethemes.module';
|
||||||
import { AddonQbehaviourModule } from '@addon/qbehaviour/qbehaviour.module';
|
import { AddonQbehaviourModule } from '@addon/qbehaviour/qbehaviour.module';
|
||||||
|
import { AddonQtypeModule } from '@addon/qtype/qtype.module';
|
||||||
|
|
||||||
// For translate loader. AoT requires an exported function for factories.
|
// For translate loader. AoT requires an exported function for factories.
|
||||||
export function createTranslateLoader(http: HttpClient): TranslateHttpLoader {
|
export function createTranslateLoader(http: HttpClient): TranslateHttpLoader {
|
||||||
@ -174,7 +175,8 @@ export const CORE_PROVIDERS: any[] = [
|
|||||||
AddonNotesModule,
|
AddonNotesModule,
|
||||||
AddonPushNotificationsModule,
|
AddonPushNotificationsModule,
|
||||||
AddonRemoteThemesModule,
|
AddonRemoteThemesModule,
|
||||||
AddonQbehaviourModule
|
AddonQbehaviourModule,
|
||||||
|
AddonQtypeModule
|
||||||
],
|
],
|
||||||
bootstrap: [IonicApp],
|
bootstrap: [IonicApp],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
|
98
src/core/question/classes/base-question-component.ts
Normal file
98
src/core/question/classes/base-question-component.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// (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 { Input, EventEmitter } from '@angular/core';
|
||||||
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
|
import { CoreQuestionHelperProvider } from '@core/question/providers/helper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for components to render a question.
|
||||||
|
*/
|
||||||
|
export class CoreQuestionBaseComponent {
|
||||||
|
@Input() question: any; // The question to render.
|
||||||
|
@Input() component: string; // The component the question belongs to.
|
||||||
|
@Input() componentId: number; // ID of the component the question belongs to.
|
||||||
|
@Input() attemptId: number; // Attempt ID.
|
||||||
|
@Input() offlineEnabled?: boolean | string; // Whether the question can be answered in offline.
|
||||||
|
@Input() buttonClicked: EventEmitter<any>; // Should emit an event when a behaviour button is clicked.
|
||||||
|
@Input() onAbort: EventEmitter<void>; // Should emit an event if the question should be aborted.
|
||||||
|
|
||||||
|
protected logger;
|
||||||
|
|
||||||
|
constructor(logger: CoreLoggerProvider, logName: string, protected questionHelper: CoreQuestionHelperProvider,
|
||||||
|
protected domUtils: CoreDomUtilsProvider) {
|
||||||
|
this.logger = logger.getInstance(logName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the component and the question text.
|
||||||
|
*
|
||||||
|
* @return {void|HTMLElement} Element containing the question HTML, void if the data is not valid.
|
||||||
|
*/
|
||||||
|
initComponent(): void | HTMLElement {
|
||||||
|
if (!this.question) {
|
||||||
|
this.logger.warn('Aborting because of no question received.');
|
||||||
|
|
||||||
|
return this.questionHelper.showComponentError(this.onAbort);
|
||||||
|
}
|
||||||
|
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.innerHTML = this.question.html;
|
||||||
|
|
||||||
|
// Extract question text.
|
||||||
|
this.question.text = this.domUtils.getContentsOfElement(div, '.qtext');
|
||||||
|
if (typeof this.question.text == 'undefined') {
|
||||||
|
this.logger.warn('Aborting because of an error parsing question.', this.question.name);
|
||||||
|
|
||||||
|
return this.questionHelper.showComponentError(this.onAbort);
|
||||||
|
}
|
||||||
|
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a question component that has an input of type "text".
|
||||||
|
*
|
||||||
|
* @return {void|HTMLElement} Element containing the question HTML, void if the data is not valid.
|
||||||
|
*/
|
||||||
|
initInputTextComponent(): void | HTMLElement {
|
||||||
|
const questionDiv = this.initComponent();
|
||||||
|
if (questionDiv) {
|
||||||
|
// Get the input element.
|
||||||
|
const input = <HTMLInputElement> questionDiv.querySelector('input[type="text"][name*=answer]');
|
||||||
|
if (!input) {
|
||||||
|
this.logger.warn('Aborting because couldn\'t find input.', this.question.name);
|
||||||
|
|
||||||
|
return this.questionHelper.showComponentError(this.onAbort);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.question.input = {
|
||||||
|
id: input.id,
|
||||||
|
name: input.name,
|
||||||
|
value: input.value,
|
||||||
|
readOnly: input.readOnly
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if question is marked as correct.
|
||||||
|
if (input.className.indexOf('incorrect') >= 0) {
|
||||||
|
this.question.input.isCorrect = 0;
|
||||||
|
} else if (input.className.indexOf('correct') >= 0) {
|
||||||
|
this.question.input.isCorrect = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return questionDiv;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user