forked from EVOgeek/Vmeda.Online
150 lines
6.8 KiB
TypeScript
150 lines
6.8 KiB
TypeScript
// (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, OnInit, Injector, EventEmitter } from '@angular/core';
|
|
import { TranslateService } from '@ngx-translate/core';
|
|
import { CoreLoggerProvider } from '@providers/logger';
|
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
|
import { CoreQuestionProvider } from '../../providers/question';
|
|
import { CoreQuestionDelegate } from '../../providers/delegate';
|
|
import { CoreQuestionBehaviourDelegate } from '../../providers/behaviour-delegate';
|
|
import { CoreQuestionHelperProvider } from '../../providers/helper';
|
|
|
|
/**
|
|
* Component to render a question.
|
|
*/
|
|
@Component({
|
|
selector: 'core-question',
|
|
templateUrl: 'question.html'
|
|
})
|
|
export class CoreQuestionComponent implements OnInit {
|
|
@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.
|
|
@Output() buttonClicked: EventEmitter<any>; // Will emit an event when a behaviour button is clicked.
|
|
@Output() onAbort: EventEmitter<void>; // Will emit an event if the question should be aborted.
|
|
|
|
componentClass: any; // The class of the component to render.
|
|
data: any = {}; // Data to pass to the component.
|
|
seqCheck: {name: string, value: string}; // Sequenche check name and value (if any).
|
|
behaviourComponents: any[] = []; // Components to render the question behaviour.
|
|
loaded = false;
|
|
|
|
protected logger;
|
|
|
|
constructor(logger: CoreLoggerProvider, protected injector: Injector, protected questionDelegate: CoreQuestionDelegate,
|
|
protected utils: CoreUtilsProvider, protected behaviourDelegate: CoreQuestionBehaviourDelegate,
|
|
protected questionHelper: CoreQuestionHelperProvider, protected translate: TranslateService,
|
|
protected questionProvider: CoreQuestionProvider, protected domUtils: CoreDomUtilsProvider) {
|
|
logger = logger.getInstance('CoreQuestionComponent');
|
|
|
|
this.buttonClicked = new EventEmitter();
|
|
this.onAbort = new EventEmitter();
|
|
}
|
|
|
|
/**
|
|
* Component being initialized.
|
|
*/
|
|
ngOnInit(): void {
|
|
this.offlineEnabled = this.utils.isTrueOrOne(this.offlineEnabled);
|
|
|
|
if (!this.question) {
|
|
this.loaded = true;
|
|
|
|
return;
|
|
}
|
|
|
|
// Get the component to render the question.
|
|
this.questionDelegate.getComponentForQuestion(this.injector, this.question).then((componentClass) => {
|
|
this.componentClass = componentClass;
|
|
|
|
if (componentClass) {
|
|
// Set up the data needed by the question and behaviour components.
|
|
this.data = {
|
|
question: this.question,
|
|
component: this.component,
|
|
componentId: this.componentId,
|
|
attemptId: this.attemptId,
|
|
offlineEnabled: this.offlineEnabled,
|
|
buttonClicked: this.buttonClicked,
|
|
onAbort: this.onAbort
|
|
};
|
|
|
|
// Treat the question.
|
|
this.questionHelper.extractQuestionScripts(this.question);
|
|
|
|
// Handle question behaviour.
|
|
const behaviour = this.questionDelegate.getBehaviourForQuestion(this.question, this.question.preferredBehaviour);
|
|
if (!this.behaviourDelegate.isBehaviourSupported(behaviour)) {
|
|
// Behaviour not supported, abort.
|
|
this.logger.warn('Aborting question because the behaviour is not supported.', this.question.name);
|
|
this.questionHelper.showComponentError(this.onAbort,
|
|
this.translate.instant('addon.mod_quiz.errorbehaviournotsupported') + ' ' + behaviour);
|
|
|
|
return;
|
|
}
|
|
|
|
// Get the sequence check (hidden input). This is required.
|
|
this.seqCheck = this.questionHelper.getQuestionSequenceCheckFromHtml(this.question.html);
|
|
if (!this.seqCheck) {
|
|
this.logger.warn('Aborting question because couldn\'t retrieve sequence check.', this.question.name);
|
|
this.questionHelper.showComponentError(this.onAbort);
|
|
|
|
return;
|
|
}
|
|
|
|
// Load local answers if offline is enabled.
|
|
let promise;
|
|
if (this.offlineEnabled) {
|
|
promise = this.questionProvider.getQuestionAnswers(this.component, this.attemptId, this.question.slot)
|
|
.then((answers) => {
|
|
this.question.localAnswers = this.questionProvider.convertAnswersArrayToObject(answers, true);
|
|
}).catch(() => {
|
|
this.question.localAnswers = {};
|
|
});
|
|
} else {
|
|
this.question.localAnswers = {};
|
|
promise = Promise.resolve();
|
|
}
|
|
|
|
promise.then(() => {
|
|
// Handle behaviour.
|
|
this.behaviourDelegate.handleQuestion(this.question, this.question.preferredBehaviour).then((comps) => {
|
|
this.behaviourComponents = comps;
|
|
});
|
|
this.questionHelper.extractQbehaviourRedoButton(this.question);
|
|
this.question.html = this.domUtils.removeElementFromHtml(this.question.html, '.im-controls');
|
|
|
|
// Extract the validation error of the question.
|
|
this.question.validationError = this.questionHelper.getValidationErrorFromHtml(this.question.html);
|
|
|
|
// Load the local answers in the HTML.
|
|
this.questionHelper.loadLocalAnswersInHtml(this.question);
|
|
|
|
// Try to extract the feedback and comment for the question.
|
|
this.questionHelper.extractQuestionFeedback(this.question);
|
|
this.questionHelper.extractQuestionComment(this.question);
|
|
|
|
this.loaded = true;
|
|
});
|
|
}
|
|
}).catch(() => {
|
|
// Ignore errors.
|
|
});
|
|
}
|
|
}
|