@@ -23,9 +23,11 @@ import { CoreQuestionProvider, CoreQuestionState } from '@core/question/provider
2323 *
2424 * @param question The question.
2525 * @param answers Object with the question answers (without prefix).
26+ * @param component The component the question is related to.
27+ * @param componentId Component ID.
2628 * @return 1 if complete, 0 if not complete, -1 if cannot determine.
2729 */
28- export type isCompleteResponseFunction = ( question : any , answers : any ) => number ;
30+ export type isCompleteResponseFunction = ( question : any , answers : any , component : string , componentId : string | number ) => number ;
2931
3032/**
3133 * Check if two responses are the same.
@@ -35,10 +37,12 @@ export type isCompleteResponseFunction = (question: any, answers: any) => number
3537 * @param prevBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
3638 * @param newAnswers Object with the new question answers.
3739 * @param newBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
40+ * @param component The component the question is related to.
41+ * @param componentId Component ID.
3842 * @return Whether they're the same.
3943 */
4044export type isSameResponseFunction = ( question : any , prevAnswers : any , prevBasicAnswers : any , newAnswers : any ,
41- newBasicAnswers : any ) => boolean ;
45+ newBasicAnswers : any , component : string , componentId : string | number ) => boolean ;
4246
4347/**
4448 * Handler to support deferred feedback question behaviour.
@@ -58,12 +62,13 @@ export class AddonQbehaviourDeferredFeedbackHandler implements CoreQuestionBehav
5862 * @param component Component the question belongs to.
5963 * @param attemptId Attempt ID the question belongs to.
6064 * @param question The question.
65+ * @param componentId Component ID.
6166 * @param siteId Site ID. If not defined, current site.
6267 * @return New state (or promise resolved with state).
6368 */
64- determineNewState ( component : string , attemptId : number , question : any , siteId ?: string )
69+ determineNewState ( component : string , attemptId : number , question : any , componentId : string | number , siteId ?: string )
6570 : CoreQuestionState | Promise < CoreQuestionState > {
66- return this . determineNewStateDeferred ( component , attemptId , question , siteId ) ;
71+ return this . determineNewStateDeferred ( component , attemptId , question , componentId , siteId ) ;
6772 }
6873
6974 /**
@@ -72,75 +77,82 @@ export class AddonQbehaviourDeferredFeedbackHandler implements CoreQuestionBehav
7277 * @param component Component the question belongs to.
7378 * @param attemptId Attempt ID the question belongs to.
7479 * @param question The question.
80+ * @param componentId Component ID.
7581 * @param siteId Site ID. If not defined, current site.
7682 * @param isCompleteFn Function to override the default isCompleteResponse check.
7783 * @param isSameFn Function to override the default isSameResponse check.
7884 * @return Promise resolved with state.
7985 */
80- determineNewStateDeferred ( component : string , attemptId : number , question : any , siteId ?: string ,
81- isCompleteFn ?: isCompleteResponseFunction , isSameFn ?: isSameResponseFunction ) : Promise < CoreQuestionState > {
86+ async determineNewStateDeferred ( component : string , attemptId : number , question : any , componentId : string | number ,
87+ siteId ?: string , isCompleteFn ?: isCompleteResponseFunction , isSameFn ?: isSameResponseFunction )
88+ : Promise < CoreQuestionState > {
8289
8390 // Check if we have local data for the question.
84- return this . questionProvider . getQuestion ( component , attemptId , question . slot , siteId ) . catch ( ( ) => {
91+ let dbQuestion ;
92+ try {
93+ dbQuestion = await this . questionProvider . getQuestion ( component , attemptId , question . slot , siteId ) ;
94+ } catch ( error ) {
8595 // No entry found, use the original data.
86- return question ;
87- } ) . then ( ( dbQuestion ) => {
88- const state = this . questionProvider . getState ( dbQuestion . state ) ;
96+ dbQuestion = question ;
97+ }
8998
90- if ( state . finished || ! state . active ) {
91- // Question is finished, it cannot change.
92- return state ;
93- }
99+ const state = this . questionProvider . getState ( dbQuestion . state ) ;
94100
95- // We need to check if the answers have changed. Retrieve current stored answers.
96- return this . questionProvider . getQuestionAnswers ( component , attemptId , question . slot , false , siteId )
97- . then ( ( prevAnswers ) => {
101+ if ( state . finished || ! state . active ) {
102+ // Question is finished, it cannot change.
103+ return state ;
104+ }
98105
99- const newBasicAnswers = this . questionProvider . getBasicAnswers ( question . answers ) ;
106+ const newBasicAnswers = this . questionProvider . getBasicAnswers ( question . answers ) ;
100107
101- prevAnswers = this . questionProvider . convertAnswersArrayToObject ( prevAnswers , true ) ;
102- const prevBasicAnswers = this . questionProvider . getBasicAnswers ( prevAnswers ) ;
108+ if ( dbQuestion . state ) {
109+ // Question already has a state stored. Check if answer has changed.
110+ let prevAnswers = await this . questionProvider . getQuestionAnswers ( component , attemptId , question . slot , false , siteId ) ;
103111
104- // If answers haven't changed the state is the same.
105- if ( isSameFn ) {
106- if ( isSameFn ( question , prevAnswers , prevBasicAnswers , question . answers , newBasicAnswers ) ) {
107- return state ;
108- }
109- } else {
110- if ( this . questionDelegate . isSameResponse ( question , prevBasicAnswers , newBasicAnswers ) ) {
111- return state ;
112- }
113- }
112+ prevAnswers = this . questionProvider . convertAnswersArrayToObject ( prevAnswers , true ) ;
113+ const prevBasicAnswers = this . questionProvider . getBasicAnswers ( prevAnswers ) ;
114114
115- // Answers have changed. Now check if the response is complete and calculate the new state.
116- let complete : number ,
117- newState : string ;
118- if ( isCompleteFn ) {
119- // Pass all the answers since some behaviours might need the extra data.
120- complete = isCompleteFn ( question , question . answers ) ;
121- } else {
122- // Only pass the basic answers since questions should be independent of extra data.
123- complete = this . questionDelegate . isCompleteResponse ( question , newBasicAnswers ) ;
115+ // If answers haven't changed the state is the same.
116+ if ( isSameFn ) {
117+ if ( isSameFn ( question , prevAnswers , prevBasicAnswers , question . answers , newBasicAnswers ,
118+ component , componentId ) ) {
119+ return state ;
124120 }
125-
126- if ( complete < 0 ) {
127- newState = 'cannotdeterminestatus' ;
128- } else if ( complete > 0 ) {
129- newState = 'complete' ;
130- } else {
131- const gradable = this . questionDelegate . isGradableResponse ( question , newBasicAnswers ) ;
132- if ( gradable < 0 ) {
133- newState = 'cannotdeterminestatus' ;
134- } else if ( gradable > 0 ) {
135- newState = 'invalid' ;
136- } else {
137- newState = 'todo' ;
138- }
121+ } else {
122+ if ( this . questionDelegate . isSameResponse ( question , prevBasicAnswers , newBasicAnswers , component , componentId ) ) {
123+ return state ;
139124 }
125+ }
126+ }
127+
128+ // Answers have changed. Now check if the response is complete and calculate the new state.
129+ let complete : number ;
130+ let newState : string ;
131+
132+ if ( isCompleteFn ) {
133+ // Pass all the answers since some behaviours might need the extra data.
134+ complete = isCompleteFn ( question , question . answers , component , componentId ) ;
135+ } else {
136+ // Only pass the basic answers since questions should be independent of extra data.
137+ complete = this . questionDelegate . isCompleteResponse ( question , newBasicAnswers , component , componentId ) ;
138+ }
139+
140+ if ( complete < 0 ) {
141+ newState = 'cannotdeterminestatus' ;
142+ } else if ( complete > 0 ) {
143+ newState = 'complete' ;
144+ } else {
145+ const gradable = this . questionDelegate . isGradableResponse ( question , newBasicAnswers , component , componentId ) ;
146+ if ( gradable < 0 ) {
147+ newState = 'cannotdeterminestatus' ;
148+ } else if ( gradable > 0 ) {
149+ newState = 'invalid' ;
150+ } else {
151+ newState = 'todo' ;
152+ }
153+ }
140154
141- return this . questionProvider . getState ( newState ) ;
142- } ) ;
143- } ) ;
155+ return this . questionProvider . getState ( newState ) ;
144156 }
145157
146158 /**
0 commit comments