MOBILE-3651 qbehaviour: Implement all question behaviours
parent
14ba4869a3
commit
4917067f8d
|
@ -24,6 +24,7 @@ import { AddonNotificationsModule } from './notifications/notifications.module';
|
|||
import { AddonMessageOutputModule } from './messageoutput/messageoutput.module';
|
||||
import { AddonMessagesModule } from './messages/messages.module';
|
||||
import { AddonModModule } from './mod/mod.module';
|
||||
import { AddonQbehaviourModule } from './qbehaviour/qbehaviour.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
@ -37,6 +38,7 @@ import { AddonModModule } from './mod/mod.module';
|
|||
AddonNotificationsModule,
|
||||
AddonMessageOutputModule,
|
||||
AddonModModule,
|
||||
AddonQbehaviourModule,
|
||||
],
|
||||
})
|
||||
export class AddonsModule {}
|
||||
|
|
|
@ -30,7 +30,6 @@ export class AddonBlockRecentlyAccessedItemsHandlerService extends CoreBlockBase
|
|||
/**
|
||||
* Returns the data needed to render the block.
|
||||
*
|
||||
* @param injector Injector.
|
||||
* @param block The block to render.
|
||||
* @param contextLevel The context where the block will be used.
|
||||
* @param instanceId The instance ID associated with the context level.
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
|
||||
import { AddonQbehaviourAdaptiveHandler } from './services/handlers/adaptive';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreQuestionBehaviourDelegate.instance.registerHandler(AddonQbehaviourAdaptiveHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AddonQbehaviourAdaptiveModule {}
|
|
@ -0,0 +1,56 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 '@features/question/services/behaviour-delegate';
|
||||
import { CoreQuestionQuestionParsed } from '@features/question/services/question';
|
||||
import { CoreQuestionHelper } from '@features/question/services/question-helper';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
* Handler to support adaptive question behaviour.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonQbehaviourAdaptiveHandlerService implements CoreQuestionBehaviourHandler {
|
||||
|
||||
name = 'AddonQbehaviourAdaptive';
|
||||
type = 'adaptive';
|
||||
|
||||
/**
|
||||
* 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 question The question.
|
||||
* @return 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: CoreQuestionQuestionParsed): void {
|
||||
// Just extract the button, it doesn't need any specific component.
|
||||
CoreQuestionHelper.instance.extractQbehaviourButtons(question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AddonQbehaviourAdaptiveHandler extends makeSingleton(AddonQbehaviourAdaptiveHandlerService) {}
|
|
@ -0,0 +1,34 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
|
||||
import { AddonQbehaviourAdaptiveNoPenaltyHandler } from './services/handlers/adaptivenopenalty';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreQuestionBehaviourDelegate.instance.registerHandler(AddonQbehaviourAdaptiveNoPenaltyHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AddonQbehaviourAdaptiveNoPenaltyModule {}
|
|
@ -0,0 +1,56 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 '@features/question/services/behaviour-delegate';
|
||||
import { CoreQuestionQuestionParsed } from '@features/question/services/question';
|
||||
import { CoreQuestionHelper } from '@features/question/services/question-helper';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
* Handler to support adaptive no penalty question behaviour.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonQbehaviourAdaptiveNoPenaltyHandlerService implements CoreQuestionBehaviourHandler {
|
||||
|
||||
name = 'AddonQbehaviourAdaptiveNoPenalty';
|
||||
type = 'adaptivenopenalty';
|
||||
|
||||
/**
|
||||
* 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 question The question.
|
||||
* @return 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: CoreQuestionQuestionParsed): void {
|
||||
// Just extract the button, it doesn't need any specific component.
|
||||
CoreQuestionHelper.instance.extractQbehaviourButtons(question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AddonQbehaviourAdaptiveNoPenaltyHandler extends makeSingleton(AddonQbehaviourAdaptiveNoPenaltyHandlerService) {}
|
|
@ -0,0 +1,15 @@
|
|||
<div *ngIf="question && question.behaviourCertaintyOptions && question.behaviourCertaintyOptions.length">
|
||||
<ion-item class="ion-text-wrap addon-qbehaviour-deferredcbm-certainty-title" >
|
||||
<ion-label><p>{{ 'core.question.certainty' | translate }}</p></ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-radio-group [(ngModel)]="question.behaviourCertaintySelected" [name]="question.behaviourCertaintyOptions[0].name">
|
||||
<ion-item class="ion-text-wrap" *ngFor="let option of question.behaviourCertaintyOptions">
|
||||
<ion-label>{{ option.text }}</ion-label>
|
||||
<ion-radio slot="end" id="{{option.id}}" [value]="option.value" [disabled]="option.disabled"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
|
||||
<!-- ion-radio doesn't use an input. Create a hidden input to hold the selected value. -->
|
||||
<input type="hidden" [ngModel]="question.behaviourCertaintySelected" [attr.name]="question.behaviourCertaintyOptions[0].name">
|
||||
</div>
|
|
@ -0,0 +1,38 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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, EventEmitter } from '@angular/core';
|
||||
|
||||
import { CoreQuestionBehaviourButton, CoreQuestionQuestion } from '@features/question/services/question-helper';
|
||||
|
||||
/**
|
||||
* Component to render the deferred CBM in a question.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-qbehaviour-deferredcbm',
|
||||
templateUrl: 'addon-qbehaviour-deferredcbm.html',
|
||||
})
|
||||
export class AddonQbehaviourDeferredCBMComponent {
|
||||
|
||||
@Input() question?: CoreQuestionQuestion; // 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() contextLevel?: string; // The context level.
|
||||
@Input() contextInstanceId?: number; // The instance ID related to the context.
|
||||
@Output() buttonClicked = new EventEmitter<CoreQuestionBehaviourButton>(); // Will emit when a behaviour button is clicked.
|
||||
@Output() onAbort = new EventEmitter<void>(); // Should emit an event if the question should be aborted.
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
|
||||
import { AddonQbehaviourDeferredCBMComponent } from './component/deferredcbm';
|
||||
import { AddonQbehaviourDeferredCBMHandler } from './services/handlers/deferredcbm';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonQbehaviourDeferredCBMComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreQuestionBehaviourDelegate.instance.registerHandler(AddonQbehaviourDeferredCBMHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonQbehaviourDeferredCBMComponent,
|
||||
],
|
||||
})
|
||||
export class AddonQbehaviourDeferredCBMModule {}
|
|
@ -0,0 +1,152 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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, Type } from '@angular/core';
|
||||
|
||||
import { AddonQbehaviourDeferredFeedbackHandler } from '@addons/qbehaviour/deferredfeedback/services/handlers/deferredfeedback';
|
||||
import { CoreQuestionBehaviourHandler, CoreQuestionQuestionWithAnswers } from '@features/question/services/behaviour-delegate';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { CoreQuestionQuestionParsed, CoreQuestionsAnswers, CoreQuestionState } from '@features/question/services/question';
|
||||
import { CoreQuestionHelper } from '@features/question/services/question-helper';
|
||||
import { AddonQbehaviourDeferredCBMComponent } from '../../component/deferredcbm';
|
||||
import { CoreQuestionDelegate } from '@features/question/services/question-delegate';
|
||||
|
||||
/**
|
||||
* Handler to support deferred CBM question behaviour.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonQbehaviourDeferredCBMHandlerService implements CoreQuestionBehaviourHandler {
|
||||
|
||||
name = 'AddonQbehaviourDeferredCBM';
|
||||
type = 'deferredcbm';
|
||||
|
||||
/**
|
||||
* Determine a question new state based on its answer(s).
|
||||
*
|
||||
* @param component Component the question belongs to.
|
||||
* @param attemptId Attempt ID the question belongs to.
|
||||
* @param question The question.
|
||||
* @param componentId Component ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return New state (or promise resolved with state).
|
||||
*/
|
||||
determineNewState(
|
||||
component: string,
|
||||
attemptId: number,
|
||||
question: CoreQuestionQuestionWithAnswers,
|
||||
componentId: string | number,
|
||||
siteId?: string,
|
||||
): CoreQuestionState | Promise<CoreQuestionState> {
|
||||
// Depends on deferredfeedback.
|
||||
return AddonQbehaviourDeferredFeedbackHandler.instance.determineNewStateDeferred(
|
||||
component,
|
||||
attemptId,
|
||||
question,
|
||||
componentId,
|
||||
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 question The question.
|
||||
* @return 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: CoreQuestionQuestionParsed): void | Type<unknown>[] {
|
||||
if (CoreQuestionHelper.instance.extractQbehaviourCBM(question)) {
|
||||
return [AddonQbehaviourDeferredCBMComponent];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a response is complete.
|
||||
*
|
||||
* @param question The question.
|
||||
* @param answers Object with the question answers (without prefix).
|
||||
* @param component The component the question is related to.
|
||||
* @param componentId Component ID.
|
||||
* @return 1 if complete, 0 if not complete, -1 if cannot determine.
|
||||
*/
|
||||
protected isCompleteResponse(
|
||||
question: CoreQuestionQuestionParsed,
|
||||
answers: CoreQuestionsAnswers,
|
||||
component: string,
|
||||
componentId: string | number,
|
||||
): number {
|
||||
// First check if the question answer is complete.
|
||||
const complete = CoreQuestionDelegate.instance.isCompleteResponse(question, answers, component, componentId);
|
||||
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 True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two responses are the same.
|
||||
*
|
||||
* @param question Question.
|
||||
* @param prevAnswers Object with the previous question answers.
|
||||
* @param prevBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
|
||||
* @param newAnswers Object with the new question answers.
|
||||
* @param newBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
|
||||
* @param component The component the question is related to.
|
||||
* @param componentId Component ID.
|
||||
* @return Whether they're the same.
|
||||
*/
|
||||
protected isSameResponse(
|
||||
question: CoreQuestionQuestionParsed,
|
||||
prevAnswers: CoreQuestionsAnswers,
|
||||
prevBasicAnswers: CoreQuestionsAnswers,
|
||||
newAnswers: CoreQuestionsAnswers,
|
||||
newBasicAnswers: CoreQuestionsAnswers,
|
||||
component: string,
|
||||
componentId: string | number,
|
||||
): boolean {
|
||||
// First check if the question answer is the same.
|
||||
const sameResponse = CoreQuestionDelegate.instance.isSameResponse(
|
||||
question,
|
||||
prevBasicAnswers,
|
||||
newBasicAnswers,
|
||||
component,
|
||||
componentId,
|
||||
);
|
||||
|
||||
if (sameResponse) {
|
||||
// Same response, check the CBM is the same too.
|
||||
return prevAnswers['-certainty'] == newAnswers['-certainty'];
|
||||
}
|
||||
|
||||
return sameResponse;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AddonQbehaviourDeferredCBMHandler extends makeSingleton(AddonQbehaviourDeferredCBMHandlerService) {}
|
|
@ -0,0 +1,33 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
|
||||
import { AddonQbehaviourDeferredFeedbackHandler } from './services/handlers/deferredfeedback';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreQuestionBehaviourDelegate.instance.registerHandler(AddonQbehaviourDeferredFeedbackHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AddonQbehaviourDeferredFeedbackModule {}
|
|
@ -0,0 +1,216 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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, CoreQuestionQuestionWithAnswers } from '@features/question/services/behaviour-delegate';
|
||||
import { CoreQuestionDBRecord } from '@features/question/services/database/question';
|
||||
import {
|
||||
CoreQuestion,
|
||||
CoreQuestionQuestionParsed,
|
||||
CoreQuestionsAnswers,
|
||||
CoreQuestionState,
|
||||
} from '@features/question/services/question';
|
||||
import { CoreQuestionDelegate } from '@features/question/services/question-delegate';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
* Handler to support deferred feedback question behaviour.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonQbehaviourDeferredFeedbackHandlerService implements CoreQuestionBehaviourHandler {
|
||||
|
||||
name = 'AddonQbehaviourDeferredFeedback';
|
||||
type = 'deferredfeedback';
|
||||
|
||||
/**
|
||||
* Determine a question new state based on its answer(s).
|
||||
*
|
||||
* @param component Component the question belongs to.
|
||||
* @param attemptId Attempt ID the question belongs to.
|
||||
* @param question The question.
|
||||
* @param componentId Component ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return New state (or promise resolved with state).
|
||||
*/
|
||||
determineNewState(
|
||||
component: string,
|
||||
attemptId: number,
|
||||
question: CoreQuestionQuestionWithAnswers,
|
||||
componentId: string | number,
|
||||
siteId?: string,
|
||||
): CoreQuestionState | Promise<CoreQuestionState> {
|
||||
return this.determineNewStateDeferred(component, attemptId, question, componentId, siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine a question new state based on its answer(s) for deferred question behaviour.
|
||||
*
|
||||
* @param component Component the question belongs to.
|
||||
* @param attemptId Attempt ID the question belongs to.
|
||||
* @param question The question.
|
||||
* @param componentId Component ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param isCompleteFn Function to override the default isCompleteResponse check.
|
||||
* @param isSameFn Function to override the default isSameResponse check.
|
||||
* @return Promise resolved with state.
|
||||
*/
|
||||
async determineNewStateDeferred(
|
||||
component: string,
|
||||
attemptId: number,
|
||||
question: CoreQuestionQuestionWithAnswers,
|
||||
componentId: string | number,
|
||||
siteId?: string,
|
||||
isCompleteFn?: isCompleteResponseFunction,
|
||||
isSameFn?: isSameResponseFunction,
|
||||
): Promise<CoreQuestionState> {
|
||||
|
||||
// Check if we have local data for the question.
|
||||
let dbQuestion: CoreQuestionDBRecord | CoreQuestionQuestionWithAnswers = question;
|
||||
try {
|
||||
dbQuestion = await CoreQuestion.instance.getQuestion(component, attemptId, question.slot, siteId);
|
||||
} catch (error) {
|
||||
// No entry found, use the original data.
|
||||
}
|
||||
|
||||
const state = CoreQuestion.instance.getState(dbQuestion.state);
|
||||
|
||||
if (state.finished || !state.active) {
|
||||
// Question is finished, it cannot change.
|
||||
return state;
|
||||
}
|
||||
|
||||
const newBasicAnswers = CoreQuestion.instance.getBasicAnswers(question.answers || {});
|
||||
|
||||
if (dbQuestion.state) {
|
||||
// Question already has a state stored. Check if answer has changed.
|
||||
const prevAnswersList = await CoreQuestion.instance.getQuestionAnswers(
|
||||
component,
|
||||
attemptId,
|
||||
question.slot,
|
||||
false,
|
||||
siteId,
|
||||
);
|
||||
const prevAnswers = CoreQuestion.instance.convertAnswersArrayToObject(prevAnswersList, true);
|
||||
const prevBasicAnswers = CoreQuestion.instance.getBasicAnswers(prevAnswers);
|
||||
|
||||
// If answers haven't changed the state is the same.
|
||||
let sameResponse = false;
|
||||
|
||||
if (isSameFn) {
|
||||
sameResponse = isSameFn(
|
||||
question,
|
||||
prevAnswers,
|
||||
prevBasicAnswers,
|
||||
question.answers || {},
|
||||
newBasicAnswers,
|
||||
component,
|
||||
componentId,
|
||||
);
|
||||
} else {
|
||||
sameResponse = CoreQuestionDelegate.instance.isSameResponse(
|
||||
question,
|
||||
prevBasicAnswers,
|
||||
newBasicAnswers,
|
||||
component,
|
||||
componentId,
|
||||
);
|
||||
}
|
||||
|
||||
if (sameResponse) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
// Answers have changed. Now check if the response is complete and calculate the new state.
|
||||
let complete: number;
|
||||
let newState: string;
|
||||
|
||||
if (isCompleteFn) {
|
||||
// Pass all the answers since some behaviours might need the extra data.
|
||||
complete = isCompleteFn(question, question.answers || {}, component, componentId);
|
||||
} else {
|
||||
// Only pass the basic answers since questions should be independent of extra data.
|
||||
complete = CoreQuestionDelegate.instance.isCompleteResponse(question, newBasicAnswers, component, componentId);
|
||||
}
|
||||
|
||||
if (complete < 0) {
|
||||
newState = 'cannotdeterminestatus';
|
||||
} else if (complete > 0) {
|
||||
newState = 'complete';
|
||||
} else {
|
||||
const gradable = CoreQuestionDelegate.instance.isGradableResponse(question, newBasicAnswers, component, componentId);
|
||||
if (gradable < 0) {
|
||||
newState = 'cannotdeterminestatus';
|
||||
} else if (gradable > 0) {
|
||||
newState = 'invalid';
|
||||
} else {
|
||||
newState = 'todo';
|
||||
}
|
||||
}
|
||||
|
||||
return CoreQuestion.instance.getState(newState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AddonQbehaviourDeferredFeedbackHandler extends makeSingleton(AddonQbehaviourDeferredFeedbackHandlerService) {}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a response is complete.
|
||||
*
|
||||
* @param question The question.
|
||||
* @param answers Object with the question answers (without prefix).
|
||||
* @param component The component the question is related to.
|
||||
* @param componentId Component ID.
|
||||
* @return 1 if complete, 0 if not complete, -1 if cannot determine.
|
||||
*/
|
||||
export type isCompleteResponseFunction = (
|
||||
question: CoreQuestionQuestionParsed,
|
||||
answers: CoreQuestionsAnswers,
|
||||
component: string,
|
||||
componentId: string | number,
|
||||
) => number;
|
||||
|
||||
/**
|
||||
* Check if two responses are the same.
|
||||
*
|
||||
* @param question Question.
|
||||
* @param prevAnswers Object with the previous question answers.
|
||||
* @param prevBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
|
||||
* @param newAnswers Object with the new question answers.
|
||||
* @param newBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
|
||||
* @param component The component the question is related to.
|
||||
* @param componentId Component ID.
|
||||
* @return Whether they're the same.
|
||||
*/
|
||||
export type isSameResponseFunction = (
|
||||
question: CoreQuestionQuestionParsed,
|
||||
prevAnswers: CoreQuestionsAnswers,
|
||||
prevBasicAnswers: CoreQuestionsAnswers,
|
||||
newAnswers: CoreQuestionsAnswers,
|
||||
newBasicAnswers: CoreQuestionsAnswers,
|
||||
component: string,
|
||||
componentId: string | number,
|
||||
) => boolean;
|
|
@ -0,0 +1,34 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
|
||||
import { AddonQbehaviourImmediateCBMHandler } from './services/handlers/immediatecbm';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreQuestionBehaviourDelegate.instance.registerHandler(AddonQbehaviourImmediateCBMHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AddonQbehaviourImmediateCBMModule {}
|
|
@ -0,0 +1,61 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { AddonQbehaviourDeferredCBMComponent } from '@addons/qbehaviour/deferredcbm/component/deferredcbm';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
|
||||
import { CoreQuestionBehaviourHandler } from '@features/question/services/behaviour-delegate';
|
||||
import { CoreQuestionQuestionParsed } from '@features/question/services/question';
|
||||
import { CoreQuestionHelper } from '@features/question/services/question-helper';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
* Handler to support immediate CBM question behaviour.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonQbehaviourImmediateCBMHandlerService implements CoreQuestionBehaviourHandler {
|
||||
|
||||
name = 'AddonQbehaviourImmediateCBM';
|
||||
type = 'immediatecbm';
|
||||
|
||||
/**
|
||||
* 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 question The question.
|
||||
* @return 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: CoreQuestionQuestionParsed): void | Type<unknown>[] {
|
||||
CoreQuestionHelper.instance.extractQbehaviourButtons(question);
|
||||
|
||||
if (CoreQuestionHelper.instance.extractQbehaviourCBM(question)) {
|
||||
// Depends on deferredcbm.
|
||||
return [AddonQbehaviourDeferredCBMComponent];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AddonQbehaviourImmediateCBMHandler extends makeSingleton(AddonQbehaviourImmediateCBMHandlerService) {}
|
|
@ -0,0 +1,34 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
|
||||
import { AddonQbehaviourImmediateFeedbackHandler } from './services/handlers/immediatefeedback';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreQuestionBehaviourDelegate.instance.registerHandler(AddonQbehaviourImmediateFeedbackHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AddonQbehaviourImmediateFeedbackModule {}
|
|
@ -0,0 +1,58 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 '@features/question/services/behaviour-delegate';
|
||||
import { CoreQuestionQuestionParsed } from '@features/question/services/question';
|
||||
import { CoreQuestionHelper } from '@features/question/services/question-helper';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
* Handler to support immediate feedback question behaviour.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonQbehaviourImmediateFeedbackHandlerService implements CoreQuestionBehaviourHandler {
|
||||
|
||||
name = 'AddonQbehaviourImmediateFeedback';
|
||||
type = 'immediatefeedback';
|
||||
|
||||
/**
|
||||
* 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 question The question.
|
||||
* @return 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: CoreQuestionQuestionParsed): void {
|
||||
// Just extract the button, it doesn't need any specific component.
|
||||
CoreQuestionHelper.instance.extractQbehaviourButtons(question);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AddonQbehaviourImmediateFeedbackHandler extends makeSingleton(AddonQbehaviourImmediateFeedbackHandlerService) {}
|
|
@ -0,0 +1,2 @@
|
|||
<input *ngIf="question && question.behaviourSeenInput" type="hidden" [name]="question.behaviourSeenInput.name"
|
||||
[value]="question.behaviourSeenInput.value" >
|
|
@ -0,0 +1,38 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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, EventEmitter } from '@angular/core';
|
||||
|
||||
import { CoreQuestionBehaviourButton, CoreQuestionQuestion } from '@features/question/services/question-helper';
|
||||
|
||||
/**
|
||||
* Component to render a "seen" hidden input for informationitem question behaviour.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-qbehaviour-informationitem',
|
||||
templateUrl: 'addon-qbehaviour-informationitem.html',
|
||||
})
|
||||
export class AddonQbehaviourInformationItemComponent {
|
||||
|
||||
@Input() question?: CoreQuestionQuestion; // 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() contextLevel?: string; // The context level.
|
||||
@Input() contextInstanceId?: number; // The instance ID related to the context.
|
||||
@Output() buttonClicked = new EventEmitter<CoreQuestionBehaviourButton>(); // Will emit when a behaviour button is clicked.
|
||||
@Output() onAbort = new EventEmitter<void>(); // Should emit an event if the question should be aborted.
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { CoreSharedModule } from '@/core/shared.module';
|
||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
|
||||
import { AddonQbehaviourInformationItemComponent } from './component/informationitem';
|
||||
import { AddonQbehaviourInformationItemHandler } from './services/handlers/informationitem';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonQbehaviourInformationItemComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreQuestionBehaviourDelegate.instance.registerHandler(AddonQbehaviourInformationItemHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonQbehaviourInformationItemComponent,
|
||||
],
|
||||
})
|
||||
export class AddonQbehaviourInformationItemModule {}
|
|
@ -0,0 +1,80 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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, Type } from '@angular/core';
|
||||
|
||||
import { CoreQuestionBehaviourHandler, CoreQuestionQuestionWithAnswers } from '@features/question/services/behaviour-delegate';
|
||||
import { CoreQuestion, CoreQuestionQuestionParsed, CoreQuestionState } from '@features/question/services/question';
|
||||
import { CoreQuestionHelper } from '@features/question/services/question-helper';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonQbehaviourInformationItemComponent } from '../../component/informationitem';
|
||||
|
||||
/**
|
||||
* Handler to support information item question behaviour.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonQbehaviourInformationItemHandlerService implements CoreQuestionBehaviourHandler {
|
||||
|
||||
name = 'AddonQbehaviourInformationItem';
|
||||
type = 'informationitem';
|
||||
|
||||
/**
|
||||
* Determine a question new state based on its answer(s).
|
||||
*
|
||||
* @param component Component the question belongs to.
|
||||
* @param attemptId Attempt ID the question belongs to.
|
||||
* @param question The question.
|
||||
* @param componentId Component ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return New state (or promise resolved with state).
|
||||
*/
|
||||
determineNewState(
|
||||
component: string,
|
||||
attemptId: number,
|
||||
question: CoreQuestionQuestionWithAnswers,
|
||||
): CoreQuestionState | Promise<CoreQuestionState> {
|
||||
if (question.answers?.['-seen']) {
|
||||
return CoreQuestion.instance.getState('complete');
|
||||
}
|
||||
|
||||
return CoreQuestion.instance.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 question The question.
|
||||
* @return 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: CoreQuestionQuestionParsed): void | Type<unknown>[] {
|
||||
if (CoreQuestionHelper.instance.extractQbehaviourSeenInput(question)) {
|
||||
return [AddonQbehaviourInformationItemComponent];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AddonQbehaviourInformationItemHandler extends makeSingleton(AddonQbehaviourInformationItemHandlerService) {}
|
|
@ -0,0 +1,34 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
|
||||
import { AddonQbehaviourInteractiveHandler } from './services/handlers/interactive';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreQuestionBehaviourDelegate.instance.registerHandler(AddonQbehaviourInteractiveHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AddonQbehaviourInteractiveModule {}
|
|
@ -0,0 +1,56 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 '@features/question/services/behaviour-delegate';
|
||||
import { CoreQuestionQuestionParsed } from '@features/question/services/question';
|
||||
import { CoreQuestionHelper } from '@features/question/services/question-helper';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
* Handler to support interactive question behaviour.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonQbehaviourInteractiveHandlerService implements CoreQuestionBehaviourHandler {
|
||||
|
||||
name = 'AddonQbehaviourInteractive';
|
||||
type = 'interactive';
|
||||
|
||||
/**
|
||||
* 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 question The question.
|
||||
* @return 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: CoreQuestionQuestionParsed): void {
|
||||
// Just extract the button, it doesn't need any specific component.
|
||||
CoreQuestionHelper.instance.extractQbehaviourButtons(question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AddonQbehaviourInteractiveHandler extends makeSingleton(AddonQbehaviourInteractiveHandlerService) {}
|
|
@ -0,0 +1,34 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
|
||||
import { AddonQbehaviourInteractiveCountbackHandler } from './services/handlers/interactivecountback';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreQuestionBehaviourDelegate.instance.registerHandler(AddonQbehaviourInteractiveCountbackHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AddonQbehaviourInteractiveCountbackModule {}
|
|
@ -0,0 +1,56 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 '@features/question/services/behaviour-delegate';
|
||||
import { CoreQuestionQuestionParsed } from '@features/question/services/question';
|
||||
import { CoreQuestionHelper } from '@features/question/services/question-helper';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
* Handler to support interactive countback question behaviour.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonQbehaviourInteractiveCountbackHandlerService implements CoreQuestionBehaviourHandler {
|
||||
|
||||
name = 'AddonQbehaviourInteractiveCountback';
|
||||
type = 'interactivecountback';
|
||||
|
||||
/**
|
||||
* 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 question The question.
|
||||
* @return 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: CoreQuestionQuestionParsed): void {
|
||||
// Just extract the button, it doesn't need any specific component.
|
||||
CoreQuestionHelper.instance.extractQbehaviourButtons(question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AddonQbehaviourInteractiveCountbackHandler extends makeSingleton(AddonQbehaviourInteractiveCountbackHandlerService) {}
|
|
@ -0,0 +1,34 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
|
||||
import { AddonQbehaviourManualGradedHandler } from './services/handlers/manualgraded';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreQuestionBehaviourDelegate.instance.registerHandler(AddonQbehaviourManualGradedHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AddonQbehaviourManualGradedModule {}
|
|
@ -0,0 +1,69 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { AddonQbehaviourDeferredFeedbackHandler } from '@addons/qbehaviour/deferredfeedback/services/handlers/deferredfeedback';
|
||||
import { CoreQuestionBehaviourHandler, CoreQuestionQuestionWithAnswers } from '@features/question/services/behaviour-delegate';
|
||||
import { CoreQuestionState } from '@features/question/services/question';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
* Handler to support manual graded question behaviour.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonQbehaviourManualGradedHandlerService implements CoreQuestionBehaviourHandler {
|
||||
|
||||
name = 'AddonQbehaviourManualGraded';
|
||||
type = 'manualgraded';
|
||||
|
||||
/**
|
||||
* Determine a question new state based on its answer(s).
|
||||
*
|
||||
* @param component Component the question belongs to.
|
||||
* @param attemptId Attempt ID the question belongs to.
|
||||
* @param question The question.
|
||||
* @param componentId Component ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return New state (or promise resolved with state).
|
||||
*/
|
||||
determineNewState(
|
||||
component: string,
|
||||
attemptId: number,
|
||||
question: CoreQuestionQuestionWithAnswers,
|
||||
componentId: string | number,
|
||||
siteId?: string,
|
||||
): CoreQuestionState | Promise<CoreQuestionState> {
|
||||
// Same implementation as the deferred feedback. Use that function instead of replicating it.
|
||||
return AddonQbehaviourDeferredFeedbackHandler.instance.determineNewStateDeferred(
|
||||
component,
|
||||
attemptId,
|
||||
question,
|
||||
componentId,
|
||||
siteId,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AddonQbehaviourManualGradedHandler extends makeSingleton(AddonQbehaviourManualGradedHandlerService) {}
|
|
@ -0,0 +1,45 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { }
|
|
@ -69,7 +69,6 @@ export class AddonUserProfileFieldDatetimeHandlerService implements CoreUserProf
|
|||
* Return the Component to use to display the user profile field.
|
||||
* It's recommended to return the class of the component, but you can also return an instance of the component.
|
||||
*
|
||||
* @param injector Injector.
|
||||
* @return The component (or promise resolved with component) to use, undefined if not found.
|
||||
*/
|
||||
getComponent(): Type<unknown> | Promise<Type<unknown>> {
|
||||
|
|
|
@ -76,7 +76,6 @@ export class AddonUserProfileFieldTextareaHandlerService implements CoreUserProf
|
|||
* Return the Component to use to display the user profile field.
|
||||
* It's recommended to return the class of the component, but you can also return an instance of the component.
|
||||
*
|
||||
* @param injector Injector.
|
||||
* @return The component (or promise resolved with component) to use, undefined if not found.
|
||||
*/
|
||||
getComponent(): Type<unknown> | Promise<Type<unknown>> {
|
||||
|
|
|
@ -138,7 +138,6 @@ export class CoreBlockDelegateService extends CoreDelegate<CoreBlockHandler> {
|
|||
/**
|
||||
* Get the display data for a certain block.
|
||||
*
|
||||
* @param injector Injector.
|
||||
* @param block The block to render.
|
||||
* @param contextLevel The context where the block will be used.
|
||||
* @param instanceId The instance ID associated with the context level.
|
||||
|
@ -200,4 +199,3 @@ export class CoreBlockDelegateService extends CoreDelegate<CoreBlockHandler> {
|
|||
}
|
||||
|
||||
export class CoreBlockDelegate extends makeSingleton(CoreBlockDelegateService) {}
|
||||
|
||||
|
|
|
@ -127,7 +127,6 @@ export class CoreCourseFormatSingleActivityHandlerService implements CoreCourseF
|
|||
* If you want to customize the default format there are several methods to customize parts of it.
|
||||
* It's recommended to return the class of the component, but you can also return an instance of the component.
|
||||
*
|
||||
* @param injector Injector.
|
||||
* @param course The course to render.
|
||||
* @return The component (or promise resolved with component) to use, undefined if not found.
|
||||
*/
|
||||
|
|
|
@ -67,7 +67,6 @@ export class CoreCourseTagAreaHandlerService implements CoreTagAreaHandler {
|
|||
/**
|
||||
* Get the component to use to display items.
|
||||
*
|
||||
* @param injector Injector.
|
||||
* @return The component (or promise resolved with component) to use, undefined if not found.
|
||||
*/
|
||||
getComponent(): Type<unknown> | Promise<Type<unknown>> {
|
||||
|
|
|
@ -109,7 +109,7 @@ export class CoreCourseFormatDefaultHandler implements CoreCourseFormatHandler {
|
|||
* @return Whether the refresher should be displayed.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
displayRefresher?(course: CoreCourseAnyCourseData, sections: CoreCourseWSSection[]): boolean {
|
||||
displayRefresher(course: CoreCourseAnyCourseData, sections: CoreCourseWSSection[]): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ export class CoreCourseModulesTagAreaHandlerService implements CoreTagAreaHandle
|
|||
/**
|
||||
* Get the component to use to display items.
|
||||
*
|
||||
* @param injector Injector.
|
||||
* @return The component (or promise resolved with component) to use, undefined if not found.
|
||||
*/
|
||||
getComponent(): Type<unknown> | Promise<Type<unknown>> {
|
||||
|
|
|
@ -82,7 +82,6 @@ export class CoreUserTagAreaHandlerService implements CoreTagAreaHandler {
|
|||
/**
|
||||
* Get the component to use to display items.
|
||||
*
|
||||
* @param injector Injector.
|
||||
* @return The component (or promise resolved with component) to use, undefined if not found.
|
||||
*/
|
||||
getComponent(): Type<unknown> | Promise<Type<unknown>> {
|
||||
|
|
|
@ -96,7 +96,6 @@ export class CoreUserProfileFieldDelegateService extends CoreDelegate<CoreUserPr
|
|||
/**
|
||||
* Get the component to use to display an user field.
|
||||
*
|
||||
* @param injector Injector.
|
||||
* @param field User field to get the directive for.
|
||||
* @param signup True if user is in signup page.
|
||||
* @return Promise resolved with component to use, undefined if not found.
|
||||
|
|
Loading…
Reference in New Issue