Merge pull request #1285 from dpalou/MOBILE-2388
MOBILE-2388 qbehaviour: Implement all behaviour addonsmain
commit
f3ea09c7ea
|
@ -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 { AddonQbehaviourAdaptiveHandler } from './providers/handler';
|
||||||
|
import { CoreQuestionBehaviourDelegate } from '@core/question/providers/behaviour-delegate';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AddonQbehaviourAdaptiveHandler
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourAdaptiveModule {
|
||||||
|
constructor(behaviourDelegate: CoreQuestionBehaviourDelegate, handler: AddonQbehaviourAdaptiveHandler) {
|
||||||
|
behaviourDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
// (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 } from '@angular/core';
|
||||||
|
import { CoreQuestionBehaviourHandler } from '@core/question/providers/behaviour-delegate';
|
||||||
|
import { CoreQuestionHelperProvider } from '@core/question/providers/helper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support adaptive question behaviour.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonQbehaviourAdaptiveHandler implements CoreQuestionBehaviourHandler {
|
||||||
|
name = 'AddonQbehaviourAdaptive';
|
||||||
|
type = 'adaptive';
|
||||||
|
|
||||||
|
constructor(private questionHelper: CoreQuestionHelperProvider) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a question behaviour.
|
||||||
|
* If the behaviour requires a submit button, it should add it to question.behaviourButtons.
|
||||||
|
* If the behaviour requires to show some extra data, it should return the components to render it.
|
||||||
|
*
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @return {any[]|Promise<any[]>} Components (or promise resolved with components) to render some extra data in the question
|
||||||
|
* (e.g. certainty options). Don't return anything if no extra data is required.
|
||||||
|
*/
|
||||||
|
handleQuestion(question: any): any[] | Promise<any[]> {
|
||||||
|
// Just extract the button, it doesn't need any specific component.
|
||||||
|
this.questionHelper.extractQbehaviourButtons(question);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 { AddonQbehaviourAdaptiveNoPenaltyHandler } from './providers/handler';
|
||||||
|
import { CoreQuestionBehaviourDelegate } from '@core/question/providers/behaviour-delegate';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AddonQbehaviourAdaptiveNoPenaltyHandler
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourAdaptiveNoPenaltyModule {
|
||||||
|
constructor(behaviourDelegate: CoreQuestionBehaviourDelegate, handler: AddonQbehaviourAdaptiveNoPenaltyHandler) {
|
||||||
|
behaviourDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
// (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 } from '@angular/core';
|
||||||
|
import { CoreQuestionBehaviourHandler } from '@core/question/providers/behaviour-delegate';
|
||||||
|
import { CoreQuestionHelperProvider } from '@core/question/providers/helper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support adaptive no penalty question behaviour.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonQbehaviourAdaptiveNoPenaltyHandler implements CoreQuestionBehaviourHandler {
|
||||||
|
name = 'AddonQbehaviourAdaptiveNoPenalty';
|
||||||
|
type = 'adaptivenopenalty';
|
||||||
|
|
||||||
|
constructor(private questionHelper: CoreQuestionHelperProvider) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a question behaviour.
|
||||||
|
* If the behaviour requires a submit button, it should add it to question.behaviourButtons.
|
||||||
|
* If the behaviour requires to show some extra data, it should return the components to render it.
|
||||||
|
*
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @return {any[]|Promise<any[]>} Components (or promise resolved with components) to render some extra data in the question
|
||||||
|
* (e.g. certainty options). Don't return anything if no extra data is required.
|
||||||
|
*/
|
||||||
|
handleQuestion(question: any): any[] | Promise<any[]> {
|
||||||
|
// Just extract the button, it doesn't need any specific component.
|
||||||
|
this.questionHelper.extractQbehaviourButtons(question);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<ion-item text-wrap class="addon-qbehaviour-deferredcbm-certainty-title" *ngIf="question.behaviourCertaintyOptions && question.behaviourCertaintyOptions.length">
|
||||||
|
<p>{{ 'core.question.certainty' | translate }}</p>
|
||||||
|
</ion-item>
|
||||||
|
<ion-radio *ngFor="let option of question.behaviourCertaintyOptions" id="{{option.id}}" name="{{option.name}}" [ngModel]="question.behaviourCertaintySelected" [value]="option.value" [disabled]="option.disabled">
|
||||||
|
<p><core-format-text [component]="component" [componentId]="componentId" [text]="option.text"></core-format-text></p>
|
||||||
|
</ion-radio>
|
|
@ -0,0 +1,36 @@
|
||||||
|
// (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, EventEmitter } from '@angular/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component to render the deferred CBM in a question.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'addon-qbehaviour-deferredcbm',
|
||||||
|
templateUrl: 'deferredcbm.html'
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourDeferredCBMComponent {
|
||||||
|
@Input() question: any; // The question.
|
||||||
|
@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.
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 { CoreQuestionBehaviourDelegate } from '@core/question/providers/behaviour-delegate';
|
||||||
|
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||||
|
import { AddonQbehaviourDeferredCBMHandler } from './providers/handler';
|
||||||
|
import { AddonQbehaviourDeferredCBMComponent } from './component/deferredcbm';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AddonQbehaviourDeferredCBMComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
IonicModule,
|
||||||
|
TranslateModule.forChild(),
|
||||||
|
CoreDirectivesModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AddonQbehaviourDeferredCBMHandler
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
AddonQbehaviourDeferredCBMComponent
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
AddonQbehaviourDeferredCBMComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourDeferredCBMModule {
|
||||||
|
constructor(behaviourDelegate: CoreQuestionBehaviourDelegate, handler: AddonQbehaviourDeferredCBMHandler) {
|
||||||
|
behaviourDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
|
||||||
|
// (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 } from '@angular/core';
|
||||||
|
import { CoreQuestionBehaviourHandler } from '@core/question/providers/behaviour-delegate';
|
||||||
|
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
|
||||||
|
import { CoreQuestionState } from '@core/question/providers/question';
|
||||||
|
import { CoreQuestionHelperProvider } from '@core/question/providers/helper';
|
||||||
|
import { AddonQbehaviourDeferredFeedbackHandler } from '@addon/qbehaviour/deferredfeedback/providers/handler';
|
||||||
|
import { AddonQbehaviourDeferredCBMComponent } from '../component/deferredcbm';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support deferred CBM question behaviour.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonQbehaviourDeferredCBMHandler implements CoreQuestionBehaviourHandler {
|
||||||
|
name = 'AddonQbehaviourDeferredCBM';
|
||||||
|
type = 'deferredcbm';
|
||||||
|
|
||||||
|
constructor(private questionDelegate: CoreQuestionDelegate, private questionHelper: CoreQuestionHelperProvider,
|
||||||
|
private deferredFeedbackHandler: AddonQbehaviourDeferredFeedbackHandler) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine a question new state based on its answer(s).
|
||||||
|
*
|
||||||
|
* @param {string} component Component the question belongs to.
|
||||||
|
* @param {number} attemptId Attempt ID the question belongs to.
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {CoreQuestionState|Promise<CoreQuestionState>} New state (or promise resolved with state).
|
||||||
|
*/
|
||||||
|
determineNewState(component: string, attemptId: number, question: any, siteId?: string)
|
||||||
|
: CoreQuestionState | Promise<CoreQuestionState> {
|
||||||
|
// Depends on deferredfeedback.
|
||||||
|
return this.deferredFeedbackHandler.determineNewStateDeferred(component, attemptId, question, siteId,
|
||||||
|
this.isCompleteResponse.bind(this), this.isSameResponse.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a question behaviour.
|
||||||
|
* If the behaviour requires a submit button, it should add it to question.behaviourButtons.
|
||||||
|
* If the behaviour requires to show some extra data, it should return the components to render it.
|
||||||
|
*
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @return {any[]|Promise<any[]>} Components (or promise resolved with components) to render some extra data in the question
|
||||||
|
* (e.g. certainty options). Don't return anything if no extra data is required.
|
||||||
|
*/
|
||||||
|
handleQuestion(question: any): any[] | Promise<any[]> {
|
||||||
|
if (this.questionHelper.extractQbehaviourCBM(question)) {
|
||||||
|
return [AddonQbehaviourDeferredCBMComponent];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
protected isCompleteResponse(question: any, answers: any): number {
|
||||||
|
// First check if the question answer is complete.
|
||||||
|
const complete = this.questionDelegate.isCompleteResponse(question, answers);
|
||||||
|
if (complete > 0) {
|
||||||
|
// Answer is complete, check the user answered CBM too.
|
||||||
|
return answers['-certainty'] ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 two responses are the same.
|
||||||
|
*
|
||||||
|
* @param {any} question Question.
|
||||||
|
* @param {any} prevAnswers Object with the previous question answers.
|
||||||
|
* @param {any} prevBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
|
||||||
|
* @param {any} newAnswers Object with the new question answers.
|
||||||
|
* @param {any} newBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
|
||||||
|
* @return {boolean} Whether they're the same.
|
||||||
|
*/
|
||||||
|
protected isSameResponse(question: any, prevAnswers: any, prevBasicAnswers: any, newAnswers: any, newBasicAnswers: any)
|
||||||
|
: boolean {
|
||||||
|
// First check if the question answer is the same.
|
||||||
|
const same = this.questionDelegate.isSameResponse(question, prevBasicAnswers, newBasicAnswers);
|
||||||
|
if (same) {
|
||||||
|
// Same response, check the CBM is the same too.
|
||||||
|
return prevAnswers['-certainty'] == newAnswers['-certainty'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return same;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 { AddonQbehaviourDeferredFeedbackHandler } from './providers/handler';
|
||||||
|
import { CoreQuestionBehaviourDelegate } from '@core/question/providers/behaviour-delegate';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AddonQbehaviourDeferredFeedbackHandler
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourDeferredFeedbackModule {
|
||||||
|
constructor(behaviourDelegate: CoreQuestionBehaviourDelegate, handler: AddonQbehaviourDeferredFeedbackHandler) {
|
||||||
|
behaviourDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
|
||||||
|
// (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 } from '@angular/core';
|
||||||
|
import { CoreQuestionBehaviourHandler } from '@core/question/providers/behaviour-delegate';
|
||||||
|
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
|
||||||
|
import { CoreQuestionProvider, CoreQuestionState } from '@core/question/providers/question';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
export type isCompleteResponseFunction = (question: any, answers: any) => number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if two responses are the same.
|
||||||
|
*
|
||||||
|
* @param {any} question Question.
|
||||||
|
* @param {any} prevAnswers Object with the previous question answers.
|
||||||
|
* @param {any} prevBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
|
||||||
|
* @param {any} newAnswers Object with the new question answers.
|
||||||
|
* @param {any} newBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
|
||||||
|
* @return {boolean} Whether they're the same.
|
||||||
|
*/
|
||||||
|
export type isSameResponseFunction = (question: any, prevAnswers: any, prevBasicAnswers: any, newAnswers: any,
|
||||||
|
newBasicAnswers: any) => boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support deferred feedback question behaviour.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonQbehaviourDeferredFeedbackHandler implements CoreQuestionBehaviourHandler {
|
||||||
|
name = 'AddonQbehaviourDeferredFeedback';
|
||||||
|
type = 'deferredfeedback';
|
||||||
|
|
||||||
|
constructor(private questionDelegate: CoreQuestionDelegate, private questionProvider: CoreQuestionProvider) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine a question new state based on its answer(s).
|
||||||
|
*
|
||||||
|
* @param {string} component Component the question belongs to.
|
||||||
|
* @param {number} attemptId Attempt ID the question belongs to.
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {CoreQuestionState|Promise<CoreQuestionState>} New state (or promise resolved with state).
|
||||||
|
*/
|
||||||
|
determineNewState(component: string, attemptId: number, question: any, siteId?: string)
|
||||||
|
: CoreQuestionState | Promise<CoreQuestionState> {
|
||||||
|
return this.determineNewStateDeferred(component, attemptId, question, siteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine a question new state based on its answer(s) for deferred question behaviour.
|
||||||
|
*
|
||||||
|
* @param {string} component Component the question belongs to.
|
||||||
|
* @param {number} attemptId Attempt ID the question belongs to.
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @param {isCompleteResponseFunction} [isCompleteFn] Function to override the default isCompleteResponse check.
|
||||||
|
* @param {isSameResponseFunction} [isSameFn] Function to override the default isSameResponse check.
|
||||||
|
* @return {Promise<CoreQuestionState>} Promise resolved with state.
|
||||||
|
*/
|
||||||
|
determineNewStateDeferred(component: string, attemptId: number, question: any, siteId?: string,
|
||||||
|
isCompleteFn?: isCompleteResponseFunction, isSameFn?: isSameResponseFunction): Promise<CoreQuestionState> {
|
||||||
|
|
||||||
|
// Check if we have local data for the question.
|
||||||
|
return this.questionProvider.getQuestion(component, attemptId, question.slot, siteId).catch(() => {
|
||||||
|
// No entry found, use the original data.
|
||||||
|
return question;
|
||||||
|
}).then((dbQuestion) => {
|
||||||
|
const state = this.questionProvider.getState(dbQuestion.state);
|
||||||
|
|
||||||
|
if (state.finished || !state.active) {
|
||||||
|
// Question is finished, it cannot change.
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to check if the answers have changed. Retrieve current stored answers.
|
||||||
|
return this.questionProvider.getQuestionAnswers(component, attemptId, question.slot, false, siteId)
|
||||||
|
.then((prevAnswers) => {
|
||||||
|
|
||||||
|
const newBasicAnswers = this.questionProvider.getBasicAnswers(question.answers);
|
||||||
|
|
||||||
|
prevAnswers = this.questionProvider.convertAnswersArrayToObject(prevAnswers, true);
|
||||||
|
const prevBasicAnswers = this.questionProvider.getBasicAnswers(prevAnswers);
|
||||||
|
|
||||||
|
// If answers haven't changed the state is the same.
|
||||||
|
if (isSameFn) {
|
||||||
|
if (isSameFn(question, prevAnswers, prevBasicAnswers, question.answers, newBasicAnswers)) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.questionDelegate.isSameResponse(question, prevBasicAnswers, newBasicAnswers)) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Answers have changed. Now check if the response is complete and calculate the new state.
|
||||||
|
let complete: number,
|
||||||
|
newState: string;
|
||||||
|
if (isCompleteFn) {
|
||||||
|
// Pass all the answers since some behaviours might need the extra data.
|
||||||
|
complete = isCompleteFn(question, question.answers);
|
||||||
|
} else {
|
||||||
|
// Only pass the basic answers since questions should be independent of extra data.
|
||||||
|
complete = this.questionDelegate.isCompleteResponse(question, newBasicAnswers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (complete < 0) {
|
||||||
|
newState = 'unknown';
|
||||||
|
} else if (complete > 0) {
|
||||||
|
newState = 'complete';
|
||||||
|
} else {
|
||||||
|
const gradable = this.questionDelegate.isGradableResponse(question, newBasicAnswers);
|
||||||
|
if (gradable < 0) {
|
||||||
|
newState = 'unknown';
|
||||||
|
} else if (gradable > 0) {
|
||||||
|
newState = 'invalid';
|
||||||
|
} else {
|
||||||
|
newState = 'todo';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.questionProvider.getState(newState);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 { AddonQbehaviourImmediateCBMHandler } from './providers/handler';
|
||||||
|
import { CoreQuestionBehaviourDelegate } from '@core/question/providers/behaviour-delegate';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AddonQbehaviourImmediateCBMHandler
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourImmediateCBMModule {
|
||||||
|
constructor(behaviourDelegate: CoreQuestionBehaviourDelegate, handler: AddonQbehaviourImmediateCBMHandler) {
|
||||||
|
behaviourDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
|
||||||
|
// (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 } from '@angular/core';
|
||||||
|
import { CoreQuestionBehaviourHandler } from '@core/question/providers/behaviour-delegate';
|
||||||
|
import { CoreQuestionHelperProvider } from '@core/question/providers/helper';
|
||||||
|
import { AddonQbehaviourDeferredCBMComponent } from '@addon/qbehaviour/deferredcbm/component/deferredcbm';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support immediate CBM question behaviour.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonQbehaviourImmediateCBMHandler implements CoreQuestionBehaviourHandler {
|
||||||
|
name = 'AddonQbehaviourImmediateCBM';
|
||||||
|
type = 'immediatecbm';
|
||||||
|
|
||||||
|
constructor(private questionHelper: CoreQuestionHelperProvider) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a question behaviour.
|
||||||
|
* If the behaviour requires a submit button, it should add it to question.behaviourButtons.
|
||||||
|
* If the behaviour requires to show some extra data, it should return the components to render it.
|
||||||
|
*
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @return {any[]|Promise<any[]>} Components (or promise resolved with components) to render some extra data in the question
|
||||||
|
* (e.g. certainty options). Don't return anything if no extra data is required.
|
||||||
|
*/
|
||||||
|
handleQuestion(question: any): any[] | Promise<any[]> {
|
||||||
|
// Just extract the button, it doesn't need any specific component.
|
||||||
|
this.questionHelper.extractQbehaviourButtons(question);
|
||||||
|
if (this.questionHelper.extractQbehaviourCBM(question)) {
|
||||||
|
// Depends on deferredcbm.
|
||||||
|
return [AddonQbehaviourDeferredCBMComponent];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 { AddonQbehaviourImmediateFeedbackHandler } from './providers/handler';
|
||||||
|
import { CoreQuestionBehaviourDelegate } from '@core/question/providers/behaviour-delegate';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AddonQbehaviourImmediateFeedbackHandler
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourImmediateFeedbackModule {
|
||||||
|
constructor(behaviourDelegate: CoreQuestionBehaviourDelegate, handler: AddonQbehaviourImmediateFeedbackHandler) {
|
||||||
|
behaviourDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
// (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 } from '@angular/core';
|
||||||
|
import { CoreQuestionBehaviourHandler } from '@core/question/providers/behaviour-delegate';
|
||||||
|
import { CoreQuestionHelperProvider } from '@core/question/providers/helper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support immediate feedback question behaviour.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonQbehaviourImmediateFeedbackHandler implements CoreQuestionBehaviourHandler {
|
||||||
|
name = 'AddonQbehaviourImmediateFeedback';
|
||||||
|
type = 'immediatefeedback';
|
||||||
|
|
||||||
|
constructor(private questionHelper: CoreQuestionHelperProvider) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a question behaviour.
|
||||||
|
* If the behaviour requires a submit button, it should add it to question.behaviourButtons.
|
||||||
|
* If the behaviour requires to show some extra data, it should return the components to render it.
|
||||||
|
*
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @return {any[]|Promise<any[]>} Components (or promise resolved with components) to render some extra data in the question
|
||||||
|
* (e.g. certainty options). Don't return anything if no extra data is required.
|
||||||
|
*/
|
||||||
|
handleQuestion(question: any): any[] | Promise<any[]> {
|
||||||
|
// Just extract the button, it doesn't need any specific component.
|
||||||
|
this.questionHelper.extractQbehaviourButtons(question);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
<input *ngIf="question.behaviourSeenInput" type="hidden" name="{{question.behaviourSeenInput.name}}" value="{{question.behaviourSeenInput.value}}" >
|
|
@ -0,0 +1,36 @@
|
||||||
|
// (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, EventEmitter } from '@angular/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component to render a "seen" hidden input for informationitem question behaviour.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'addon-qbehaviour-informationitem',
|
||||||
|
templateUrl: 'informationitem.html'
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourInformationItemComponent {
|
||||||
|
@Input() question: any; // The question.
|
||||||
|
@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.
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
// (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 { CoreQuestionBehaviourDelegate } from '@core/question/providers/behaviour-delegate';
|
||||||
|
import { AddonQbehaviourInformationItemHandler } from './providers/handler';
|
||||||
|
import { AddonQbehaviourInformationItemComponent } from './component/informationitem';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AddonQbehaviourInformationItemComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
IonicModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AddonQbehaviourInformationItemHandler
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
AddonQbehaviourInformationItemComponent
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
AddonQbehaviourInformationItemComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourInformationItemModule {
|
||||||
|
constructor(behaviourDelegate: CoreQuestionBehaviourDelegate, handler: AddonQbehaviourInformationItemHandler) {
|
||||||
|
behaviourDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
|
||||||
|
// (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 } from '@angular/core';
|
||||||
|
import { CoreQuestionBehaviourHandler } from '@core/question/providers/behaviour-delegate';
|
||||||
|
import { CoreQuestionProvider, CoreQuestionState } from '@core/question/providers/question';
|
||||||
|
import { CoreQuestionHelperProvider } from '@core/question/providers/helper';
|
||||||
|
import { AddonQbehaviourInformationItemComponent } from '../component/informationitem';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support information item question behaviour.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonQbehaviourInformationItemHandler implements CoreQuestionBehaviourHandler {
|
||||||
|
name = 'AddonQbehaviourInformationItem';
|
||||||
|
type = 'informationitem';
|
||||||
|
|
||||||
|
constructor(private questionHelper: CoreQuestionHelperProvider, private questionProvider: CoreQuestionProvider) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine a question new state based on its answer(s).
|
||||||
|
*
|
||||||
|
* @param {string} component Component the question belongs to.
|
||||||
|
* @param {number} attemptId Attempt ID the question belongs to.
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {CoreQuestionState|Promise<CoreQuestionState>} New state (or promise resolved with state).
|
||||||
|
*/
|
||||||
|
determineNewState(component: string, attemptId: number, question: any, siteId?: string)
|
||||||
|
: CoreQuestionState | Promise<CoreQuestionState> {
|
||||||
|
if (question.answers['-seen']) {
|
||||||
|
return this.questionProvider.getState('complete');
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.questionProvider.getState(question.state || 'todo');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a question behaviour.
|
||||||
|
* If the behaviour requires a submit button, it should add it to question.behaviourButtons.
|
||||||
|
* If the behaviour requires to show some extra data, it should return the components to render it.
|
||||||
|
*
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @return {any[]|Promise<any[]>} Components (or promise resolved with components) to render some extra data in the question
|
||||||
|
* (e.g. certainty options). Don't return anything if no extra data is required.
|
||||||
|
*/
|
||||||
|
handleQuestion(question: any): any[] | Promise<any[]> {
|
||||||
|
if (this.questionHelper.extractQbehaviourSeenInput(question)) {
|
||||||
|
return [AddonQbehaviourInformationItemComponent];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 { AddonQbehaviourInteractiveHandler } from './providers/handler';
|
||||||
|
import { CoreQuestionBehaviourDelegate } from '@core/question/providers/behaviour-delegate';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AddonQbehaviourInteractiveHandler
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourInteractiveModule {
|
||||||
|
constructor(behaviourDelegate: CoreQuestionBehaviourDelegate, handler: AddonQbehaviourInteractiveHandler) {
|
||||||
|
behaviourDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
// (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 } from '@angular/core';
|
||||||
|
import { CoreQuestionBehaviourHandler } from '@core/question/providers/behaviour-delegate';
|
||||||
|
import { CoreQuestionHelperProvider } from '@core/question/providers/helper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support interactive question behaviour.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonQbehaviourInteractiveHandler implements CoreQuestionBehaviourHandler {
|
||||||
|
name = 'AddonQbehaviourInteractive';
|
||||||
|
type = 'interactive';
|
||||||
|
|
||||||
|
constructor(private questionHelper: CoreQuestionHelperProvider) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a question behaviour.
|
||||||
|
* If the behaviour requires a submit button, it should add it to question.behaviourButtons.
|
||||||
|
* If the behaviour requires to show some extra data, it should return the components to render it.
|
||||||
|
*
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @return {any[]|Promise<any[]>} Components (or promise resolved with components) to render some extra data in the question
|
||||||
|
* (e.g. certainty options). Don't return anything if no extra data is required.
|
||||||
|
*/
|
||||||
|
handleQuestion(question: any): any[] | Promise<any[]> {
|
||||||
|
// Just extract the button, it doesn't need any specific component.
|
||||||
|
this.questionHelper.extractQbehaviourButtons(question);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 { AddonQbehaviourInteractiveCountbackHandler } from './providers/handler';
|
||||||
|
import { CoreQuestionBehaviourDelegate } from '@core/question/providers/behaviour-delegate';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AddonQbehaviourInteractiveCountbackHandler
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourInteractiveCountbackModule {
|
||||||
|
constructor(behaviourDelegate: CoreQuestionBehaviourDelegate, handler: AddonQbehaviourInteractiveCountbackHandler) {
|
||||||
|
behaviourDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
// (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 } from '@angular/core';
|
||||||
|
import { CoreQuestionBehaviourHandler } from '@core/question/providers/behaviour-delegate';
|
||||||
|
import { CoreQuestionHelperProvider } from '@core/question/providers/helper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support interactive countback question behaviour.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonQbehaviourInteractiveCountbackHandler implements CoreQuestionBehaviourHandler {
|
||||||
|
name = 'AddonQbehaviourInteractiveCountback';
|
||||||
|
type = 'interactivecountback';
|
||||||
|
|
||||||
|
constructor(private questionHelper: CoreQuestionHelperProvider) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a question behaviour.
|
||||||
|
* If the behaviour requires a submit button, it should add it to question.behaviourButtons.
|
||||||
|
* If the behaviour requires to show some extra data, it should return the components to render it.
|
||||||
|
*
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @return {any[]|Promise<any[]>} Components (or promise resolved with components) to render some extra data in the question
|
||||||
|
* (e.g. certainty options). Don't return anything if no extra data is required.
|
||||||
|
*/
|
||||||
|
handleQuestion(question: any): any[] | Promise<any[]> {
|
||||||
|
// Just extract the button, it doesn't need any specific component.
|
||||||
|
this.questionHelper.extractQbehaviourButtons(question);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 { AddonQbehaviourManualGradedHandler } from './providers/handler';
|
||||||
|
import { CoreQuestionBehaviourDelegate } from '@core/question/providers/behaviour-delegate';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AddonQbehaviourManualGradedHandler
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourManualGradedModule {
|
||||||
|
constructor(behaviourDelegate: CoreQuestionBehaviourDelegate, handler: AddonQbehaviourManualGradedHandler) {
|
||||||
|
behaviourDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
|
||||||
|
// (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 } from '@angular/core';
|
||||||
|
import { CoreQuestionBehaviourHandler } from '@core/question/providers/behaviour-delegate';
|
||||||
|
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
|
||||||
|
import { CoreQuestionProvider, CoreQuestionState } from '@core/question/providers/question';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
export type isCompleteResponseFunction = (question: any, answers: any) => number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if two responses are the same.
|
||||||
|
*
|
||||||
|
* @param {any} question Question.
|
||||||
|
* @param {any} prevAnswers Object with the previous question answers.
|
||||||
|
* @param {any} prevBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
|
||||||
|
* @param {any} newAnswers Object with the new question answers.
|
||||||
|
* @param {any} newBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
|
||||||
|
* @return {boolean} Whether they're the same.
|
||||||
|
*/
|
||||||
|
export type isSameResponseFunction = (question: any, prevAnswers: any, prevBasicAnswers: any, newAnswers: any,
|
||||||
|
newBasicAnswers: any) => boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support manual graded question behaviour.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonQbehaviourManualGradedHandler implements CoreQuestionBehaviourHandler {
|
||||||
|
name = 'AddonQbehaviourManualGraded';
|
||||||
|
type = 'manualgraded';
|
||||||
|
|
||||||
|
constructor(private questionDelegate: CoreQuestionDelegate, private questionProvider: CoreQuestionProvider) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine a question new state based on its answer(s).
|
||||||
|
*
|
||||||
|
* @param {string} component Component the question belongs to.
|
||||||
|
* @param {number} attemptId Attempt ID the question belongs to.
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {CoreQuestionState|Promise<CoreQuestionState>} New state (or promise resolved with state).
|
||||||
|
*/
|
||||||
|
determineNewState(component: string, attemptId: number, question: any, siteId?: string)
|
||||||
|
: CoreQuestionState | Promise<CoreQuestionState> {
|
||||||
|
return this.determineNewStateManualGraded(component, attemptId, question, siteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine a question new state based on its answer(s) for manual graded question behaviour.
|
||||||
|
*
|
||||||
|
* @param {string} component Component the question belongs to.
|
||||||
|
* @param {number} attemptId Attempt ID the question belongs to.
|
||||||
|
* @param {any} question The question.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @param {isCompleteResponseFunction} [isCompleteFn] Function to override the default isCompleteResponse check.
|
||||||
|
* @param {isSameResponseFunction} [isSameFn] Function to override the default isSameResponse check.
|
||||||
|
* @return {Promise<CoreQuestionState>} Promise resolved with state.
|
||||||
|
*/
|
||||||
|
determineNewStateManualGraded(component: string, attemptId: number, question: any, siteId?: string,
|
||||||
|
isCompleteFn?: isCompleteResponseFunction, isSameFn?: isSameResponseFunction): Promise<CoreQuestionState> {
|
||||||
|
|
||||||
|
// Check if we have local data for the question.
|
||||||
|
return this.questionProvider.getQuestion(component, attemptId, question.slot, siteId).catch(() => {
|
||||||
|
// No entry found, use the original data.
|
||||||
|
return question;
|
||||||
|
}).then((dbQuestion) => {
|
||||||
|
const state = this.questionProvider.getState(dbQuestion.state);
|
||||||
|
|
||||||
|
if (state.finished || !state.active) {
|
||||||
|
// Question is finished, it cannot change.
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to check if the answers have changed. Retrieve current stored answers.
|
||||||
|
return this.questionProvider.getQuestionAnswers(component, attemptId, question.slot, false, siteId)
|
||||||
|
.then((prevAnswers) => {
|
||||||
|
|
||||||
|
const newBasicAnswers = this.questionProvider.getBasicAnswers(question.answers);
|
||||||
|
|
||||||
|
prevAnswers = this.questionProvider.convertAnswersArrayToObject(prevAnswers, true);
|
||||||
|
const prevBasicAnswers = this.questionProvider.getBasicAnswers(prevAnswers);
|
||||||
|
|
||||||
|
// If answers haven't changed the state is the same.
|
||||||
|
if (isSameFn) {
|
||||||
|
if (isSameFn(question, prevAnswers, prevBasicAnswers, question.answers, newBasicAnswers)) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.questionDelegate.isSameResponse(question, prevBasicAnswers, newBasicAnswers)) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Answers have changed. Now check if the response is complete and calculate the new state.
|
||||||
|
let complete: number,
|
||||||
|
newState: string;
|
||||||
|
if (isCompleteFn) {
|
||||||
|
// Pass all the answers since some behaviours might need the extra data.
|
||||||
|
complete = isCompleteFn(question, question.answers);
|
||||||
|
} else {
|
||||||
|
// Only pass the basic answers since questions should be independent of extra data.
|
||||||
|
complete = this.questionDelegate.isCompleteResponse(question, newBasicAnswers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (complete < 0) {
|
||||||
|
newState = 'unknown';
|
||||||
|
} else if (complete > 0) {
|
||||||
|
newState = 'complete';
|
||||||
|
} else {
|
||||||
|
newState = 'todo';
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.questionProvider.getState(newState);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
// (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 { AddonQbehaviourAdaptiveModule } from './adaptive/adaptive.module';
|
||||||
|
import { AddonQbehaviourAdaptiveNoPenaltyModule } from './adaptivenopenalty/adaptivenopenalty.module';
|
||||||
|
import { AddonQbehaviourDeferredCBMModule } from './deferredcbm/deferredcbm.module';
|
||||||
|
import { AddonQbehaviourDeferredFeedbackModule } from './deferredfeedback/deferredfeedback.module';
|
||||||
|
import { AddonQbehaviourImmediateCBMModule } from './immediatecbm/immediatecbm.module';
|
||||||
|
import { AddonQbehaviourImmediateFeedbackModule } from './immediatefeedback/immediatefeedback.module';
|
||||||
|
import { AddonQbehaviourInformationItemModule } from './informationitem/informationitem.module';
|
||||||
|
import { AddonQbehaviourInteractiveModule } from './interactive/interactive.module';
|
||||||
|
import { AddonQbehaviourInteractiveCountbackModule } from './interactivecountback/interactivecountback.module';
|
||||||
|
import { AddonQbehaviourManualGradedModule } from './manualgraded/manualgraded.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [
|
||||||
|
AddonQbehaviourAdaptiveModule,
|
||||||
|
AddonQbehaviourAdaptiveNoPenaltyModule,
|
||||||
|
AddonQbehaviourDeferredCBMModule,
|
||||||
|
AddonQbehaviourDeferredFeedbackModule,
|
||||||
|
AddonQbehaviourImmediateCBMModule,
|
||||||
|
AddonQbehaviourImmediateFeedbackModule,
|
||||||
|
AddonQbehaviourInformationItemModule,
|
||||||
|
AddonQbehaviourInteractiveModule,
|
||||||
|
AddonQbehaviourInteractiveCountbackModule,
|
||||||
|
AddonQbehaviourManualGradedModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
],
|
||||||
|
exports: []
|
||||||
|
})
|
||||||
|
export class AddonQbehaviourModule { }
|
|
@ -86,6 +86,7 @@ import { AddonMessagesModule } from '@addon/messages/messages.module';
|
||||||
import { AddonNotesModule } from '../addon/notes/notes.module';
|
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';
|
||||||
|
|
||||||
// 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 {
|
||||||
|
@ -172,7 +173,8 @@ export const CORE_PROVIDERS: any[] = [
|
||||||
AddonMessagesModule,
|
AddonMessagesModule,
|
||||||
AddonNotesModule,
|
AddonNotesModule,
|
||||||
AddonPushNotificationsModule,
|
AddonPushNotificationsModule,
|
||||||
AddonRemoteThemesModule
|
AddonRemoteThemesModule,
|
||||||
|
AddonQbehaviourModule
|
||||||
],
|
],
|
||||||
bootstrap: [IonicApp],
|
bootstrap: [IonicApp],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
|
|
|
@ -52,6 +52,68 @@ export class CoreQuestionHelperProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract question behaviour submit buttons from the question's HTML and add them to "behaviourButtons" property.
|
||||||
|
* The buttons aren't deleted from the content because all the im-controls block will be removed afterwards.
|
||||||
|
*
|
||||||
|
* @param {any} question Question to treat.
|
||||||
|
* @param {string} [selector] Selector to search the buttons. By default, '.im-controls input[type="submit"]'.
|
||||||
|
*/
|
||||||
|
extractQbehaviourButtons(question: any, selector?: string): void {
|
||||||
|
selector = selector || '.im-controls input[type="submit"]';
|
||||||
|
|
||||||
|
this.div.innerHTML = question.html;
|
||||||
|
|
||||||
|
// Search the buttons.
|
||||||
|
const buttons = <HTMLInputElement[]> Array.from(this.div.querySelectorAll(selector));
|
||||||
|
buttons.forEach((button) => {
|
||||||
|
this.addBehaviourButton(question, button);
|
||||||
|
});
|
||||||
|
|
||||||
|
question.html = this.div.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the question has CBM and, if so, extract the certainty options and add them to a new
|
||||||
|
* "behaviourCertaintyOptions" property.
|
||||||
|
* The value of the selected option is stored in question.behaviourCertaintySelected.
|
||||||
|
* We don't remove them from HTML because the whole im-controls block will be removed afterwards.
|
||||||
|
*
|
||||||
|
* @param {any} question Question to treat.
|
||||||
|
* @return {boolean} Wether the certainty is found.
|
||||||
|
*/
|
||||||
|
extractQbehaviourCBM(question: any): boolean {
|
||||||
|
this.div.innerHTML = question.html;
|
||||||
|
|
||||||
|
const labels = Array.from(this.div.querySelectorAll('.im-controls .certaintychoices label[for*="certainty"]'));
|
||||||
|
question.behaviourCertaintyOptions = [];
|
||||||
|
|
||||||
|
labels.forEach((label) => {
|
||||||
|
// Search the radio button inside this certainty and add its data to the options array.
|
||||||
|
const input = <HTMLInputElement> label.querySelector('input[type="radio"]');
|
||||||
|
if (input) {
|
||||||
|
question.behaviourCertaintyOptions.push({
|
||||||
|
id: input.id,
|
||||||
|
name: input.name,
|
||||||
|
value: input.value,
|
||||||
|
text: this.textUtils.cleanTags(label.innerHTML),
|
||||||
|
disabled: input.disabled
|
||||||
|
});
|
||||||
|
|
||||||
|
if (input.checked) {
|
||||||
|
question.behaviourCertaintySelected = input.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// If we have a certainty value stored in local we'll use that one.
|
||||||
|
if (question.localAnswers && typeof question.localAnswers['-certainty'] != 'undefined') {
|
||||||
|
question.behaviourCertaintySelected = question.localAnswers['-certainty'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the question has a redo button and, if so, add it to "behaviourButtons" property
|
* Check if the question has a redo button and, if so, add it to "behaviourButtons" property
|
||||||
* and remove it from the HTML.
|
* and remove it from the HTML.
|
||||||
|
@ -80,6 +142,33 @@ export class CoreQuestionHelperProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the question contains a "seen" input.
|
||||||
|
* If so, add the name and value to a "behaviourSeenInput" property and remove the input.
|
||||||
|
*
|
||||||
|
* @param {any} question Question to treat.
|
||||||
|
* @return {boolean} Whether the seen input is found.
|
||||||
|
*/
|
||||||
|
extractQbehaviourSeenInput(question: any): boolean {
|
||||||
|
this.div.innerHTML = question.html;
|
||||||
|
|
||||||
|
// Search the "seen" input.
|
||||||
|
const seenInput = <HTMLInputElement> this.div.querySelector('input[type="hidden"][name*=seen]');
|
||||||
|
if (seenInput) {
|
||||||
|
// Get the data and remove the input.
|
||||||
|
question.behaviourSeenInput = {
|
||||||
|
name: seenInput.name,
|
||||||
|
value: seenInput.value
|
||||||
|
};
|
||||||
|
seenInput.parentElement.removeChild(seenInput);
|
||||||
|
question.html = this.div.innerHTML;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the comment from the question HTML code and adds it in a new "commentHtml" property.
|
* Removes the comment from the question HTML code and adds it in a new "commentHtml" property.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue