@pie-element/image-cloze-association 4.9.1-next.2 → 4.9.1-next.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -129,7 +129,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
129
129
 
130
130
  ### Features
131
131
 
132
- * add a different property in the config, forceEnabled, to force a value ([300c664](https://github.com/pie-framework/pie-elements/commit/300c664618f46177137deef3bced2d096cdb8126))
132
+ * add a different property in the config, to force a value ([300c664](https://github.com/pie-framework/pie-elements/commit/300c664618f46177137deef3bced2d096cdb8126))
133
133
 
134
134
 
135
135
 
@@ -24,6 +24,8 @@ var _controllerUtils = require("@pie-lib/controller-utils");
24
24
 
25
25
  var _utils = require("./utils");
26
26
 
27
+ var _lodash = require("lodash");
28
+
27
29
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
28
30
 
29
31
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
@@ -79,7 +81,7 @@ var isResponseCorrect = function isResponseCorrect(responses, session) {
79
81
 
80
82
  if (session.answers && totalValidResponses === session.answers.length) {
81
83
  session.answers.forEach(function (answer) {
82
- if (!(responses[answer.containerIndex].images || []).includes(answer.value)) {
84
+ if (!(responses[answer.containerIndex] && responses[answer.containerIndex].images || []).includes(answer.value)) {
83
85
  isCorrect = false;
84
86
  }
85
87
  });
@@ -88,15 +90,23 @@ var isResponseCorrect = function isResponseCorrect(responses, session) {
88
90
  }
89
91
 
90
92
  return isCorrect;
91
- }; // This applies for items that don't support partial scoring.
93
+ }; // This applies for correct responses that have empty values
92
94
 
93
95
 
94
96
  exports.isResponseCorrect = isResponseCorrect;
95
97
 
98
+ var keepNonEmptyResponses = function keepNonEmptyResponses(responses) {
99
+ var filtered = responses.filter(function (response) {
100
+ return response.images && response.images.length;
101
+ });
102
+ return (0, _lodash.cloneDeep)(filtered);
103
+ }; // This applies for items that don't support partial scoring.
104
+
105
+
96
106
  var isDefaultOrAltResponseCorrect = function isDefaultOrAltResponseCorrect(question, session) {
97
- var _question$validation = question.validation,
98
- value = _question$validation.validResponse.value,
99
- altResponses = _question$validation.altResponses;
107
+ var altResponses = question.validation.altResponses;
108
+ var value = question.validation.validResponse.value;
109
+ value = keepNonEmptyResponses(value);
100
110
  var isCorrect = isResponseCorrect(value, session); // Look for correct answers in alternate responses.
101
111
 
102
112
  if (!isCorrect && altResponses && altResponses.length) {
@@ -130,8 +140,7 @@ var getDeductionPerContainer = function getDeductionPerContainer(containerIndex,
130
140
 
131
141
  var getPartialScore = function getPartialScore(question, session) {
132
142
  var validResponse = question.validation.validResponse,
133
- maxResponsePerZone = question.maxResponsePerZone,
134
- responseContainers = question.responseContainers;
143
+ maxResponsePerZone = question.maxResponsePerZone;
135
144
  var correctAnswers = 0;
136
145
  var possibleResponses = 0;
137
146
 
@@ -139,6 +148,7 @@ var getPartialScore = function getPartialScore(question, session) {
139
148
  return 0;
140
149
  }
141
150
 
151
+ validResponse.value = keepNonEmptyResponses(validResponse.value);
142
152
  validResponse.value.forEach(function (value) {
143
153
  return possibleResponses += (value.images || []).length;
144
154
  });
@@ -167,8 +177,9 @@ var getPartialScore = function getPartialScore(question, session) {
167
177
  } // negative values will implicitly make the score equal to zero
168
178
 
169
179
 
170
- correctAnswers = correctAnswers < 0 ? 0 : correctAnswers;
171
- var denominator = maxResponsePerZone > 1 ? possibleResponses : responseContainers.length;
180
+ correctAnswers = correctAnswers < 0 ? 0 : correctAnswers; // use length of validResponse since some containers can be left empty
181
+
182
+ var denominator = maxResponsePerZone > 1 ? possibleResponses : (validResponse.value || []).length;
172
183
  var str = (correctAnswers / denominator).toFixed(2);
173
184
  return parseFloat(str);
174
185
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.js"],"names":["log","normalize","question","rationaleEnabled","teacherInstructionsEnabled","studentInstructionsEnabled","model","session","env","questionNormalized","questionCamelized","Promise","resolve","out","disabled","mode","responseCorrect","getScore","undefined","shuffle","possibleResponses","possible_responses","role","teacherInstructions","isResponseCorrect","responses","isCorrect","totalValidResponses","forEach","value","images","length","answers","answer","containerIndex","includes","isDefaultOrAltResponseCorrect","validation","validResponse","altResponses","altResponse","getDeductionPerContainer","valid","totalStack","filter","item","incorrectStack","maxValid","ignored","slice","getPartialScore","maxResponsePerZone","responseContainers","correctAnswers","all","deductionList","id","denominator","str","toFixed","parseFloat","config","isPartialScoring","partialScoring","enabled","correct","outcome","score","empty","configCamelized","createCorrectResponseSession","valid_response","container","i","v","push"],"mappings":"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","sourcesContent":["import debug from 'debug';\nimport isEmpty from 'lodash/isEmpty';\nimport shuffle from 'lodash/shuffle';\nimport { camelizeKeys } from 'humps';\nimport { partialScoring } from '@pie-lib/controller-utils';\n\nimport { getAllUniqueCorrectness } from './utils';\n\nconst log = debug('pie-elements:image-cloze-association:controller');\n\nexport const normalize = (question) => ({\n rationaleEnabled: true,\n teacherInstructionsEnabled: true,\n studentInstructionsEnabled: true,\n ...question,\n});\n\nexport function model(question, session, env) {\n const questionNormalized = normalize(question);\n const questionCamelized = camelizeKeys(questionNormalized);\n\n return new Promise((resolve) => {\n const out = {\n disabled: env.mode !== 'gather',\n mode: env.mode,\n ...questionCamelized,\n responseCorrect: env.mode === 'evaluate' ? getScore(questionCamelized, session) === 1 : undefined,\n };\n\n if (questionNormalized.shuffle) {\n out.possibleResponses = shuffle(questionNormalized.possible_responses);\n }\n\n if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {\n out.teacherInstructions = questionCamelized.teacherInstructionsEnabled\n ? questionCamelized.teacherInstructions\n : null;\n } else {\n out.teacherInstructions = null;\n }\n\n resolve(out);\n });\n}\n\nexport const isResponseCorrect = (responses, session) => {\n let isCorrect = true;\n let totalValidResponses = 0;\n\n if (!session || isEmpty(session)) {\n return false;\n }\n\n responses.forEach((value) => (totalValidResponses += (value.images || []).length));\n\n if (session.answers && totalValidResponses === session.answers.length) {\n session.answers.forEach((answer) => {\n if (!(responses[answer.containerIndex].images || []).includes(answer.value)) {\n isCorrect = false;\n }\n });\n } else {\n isCorrect = false;\n }\n return isCorrect;\n};\n\n// This applies for items that don't support partial scoring.\nconst isDefaultOrAltResponseCorrect = (question, session) => {\n const {\n validation: {\n validResponse: { value },\n altResponses,\n },\n } = question;\n\n let isCorrect = isResponseCorrect(value, session);\n\n // Look for correct answers in alternate responses.\n if (!isCorrect && altResponses && altResponses.length) {\n altResponses.forEach((altResponse) => {\n if (isResponseCorrect(altResponse.value, session)) {\n isCorrect = true;\n }\n });\n }\n return isCorrect;\n};\n\n// Deduct only the items that exceeded the maximum valid response per container.\nconst getDeductionPerContainer = (containerIndex, answers, valid) => {\n const totalStack = answers.filter((item) => item.containerIndex === containerIndex);\n const incorrectStack = totalStack.filter((item) => !item.isCorrect);\n const maxValid = (valid.value[containerIndex].images || []).length;\n\n if (totalStack.length > maxValid) {\n const ignored = totalStack.length - maxValid;\n return incorrectStack.slice(-ignored);\n }\n return [];\n};\n\nexport const getPartialScore = (question, session) => {\n const {\n validation: { validResponse },\n maxResponsePerZone,\n responseContainers,\n } = question;\n let correctAnswers = 0;\n let possibleResponses = 0;\n\n if (!session || isEmpty(session)) {\n return 0;\n }\n\n validResponse.value.forEach((value) => (possibleResponses += (value.images || []).length));\n\n if (session.answers && session.answers.length) {\n const all = getAllUniqueCorrectness(session.answers, validResponse.value);\n correctAnswers = all.filter((item) => item.isCorrect).length;\n\n // deduction rules: https://docs.google.com/document/d/1Oprm8Qs5fg_Dwoj2pNpsfu4D63QgCZgvcqTgeaVel7I/edit\n session.answers.forEach((answer) => {\n if (maxResponsePerZone > 1) {\n const deductionList = getDeductionPerContainer(answer.containerIndex, all, validResponse);\n\n if (deductionList.length) {\n deductionList.forEach((item) => {\n if (item.id === answer.id) {\n correctAnswers -= 1;\n }\n });\n }\n }\n });\n } else {\n correctAnswers = 0;\n }\n // negative values will implicitly make the score equal to zero\n correctAnswers = correctAnswers < 0 ? 0 : correctAnswers;\n\n const denominator = maxResponsePerZone > 1 ? possibleResponses : responseContainers.length;\n const str = (correctAnswers / denominator).toFixed(2);\n\n return parseFloat(str);\n};\n\nconst getScore = (config, session, env = {}) => {\n const isPartialScoring = partialScoring.enabled(config, env);\n const correct = isDefaultOrAltResponseCorrect(config, session);\n\n return isPartialScoring ? getPartialScore(config, session) : correct ? 1 : 0;\n};\n\nexport function outcome(config, session, env = {}) {\n return new Promise((resolve) => {\n log('outcome...');\n if (!session || isEmpty(session)) {\n resolve({ score: 0, empty: true });\n }\n\n const configCamelized = camelizeKeys(config);\n\n if (session.answers || []) {\n const score = getScore(configCamelized, session, env);\n resolve({ score });\n }\n });\n}\n\nexport const createCorrectResponseSession = (question, env) => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const {\n validation: {\n valid_response: { value },\n },\n } = question;\n const answers = [];\n\n if (value) {\n value.forEach((container, i) => {\n (container.images || []).forEach((v) => {\n answers.push({\n value: v,\n containerIndex: i,\n });\n });\n });\n }\n\n resolve({\n answers,\n id: '1',\n });\n } else {\n resolve(null);\n }\n });\n};\n"],"file":"index.js"}
1
+ {"version":3,"sources":["../src/index.js"],"names":["log","normalize","question","rationaleEnabled","teacherInstructionsEnabled","studentInstructionsEnabled","model","session","env","questionNormalized","questionCamelized","Promise","resolve","out","disabled","mode","responseCorrect","getScore","undefined","shuffle","possibleResponses","possible_responses","role","teacherInstructions","isResponseCorrect","responses","isCorrect","totalValidResponses","forEach","value","images","length","answers","answer","containerIndex","includes","keepNonEmptyResponses","filtered","filter","response","isDefaultOrAltResponseCorrect","altResponses","validation","validResponse","altResponse","getDeductionPerContainer","valid","totalStack","item","incorrectStack","maxValid","ignored","slice","getPartialScore","maxResponsePerZone","correctAnswers","all","deductionList","id","denominator","str","toFixed","parseFloat","config","isPartialScoring","partialScoring","enabled","correct","outcome","score","empty","configCamelized","createCorrectResponseSession","valid_response","container","i","v","push"],"mappings":"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","sourcesContent":["import debug from 'debug';\nimport isEmpty from 'lodash/isEmpty';\nimport shuffle from 'lodash/shuffle';\nimport { camelizeKeys } from 'humps';\nimport { partialScoring } from '@pie-lib/controller-utils';\n\nimport { getAllUniqueCorrectness } from './utils';\nimport { cloneDeep } from 'lodash';\n\nconst log = debug('pie-elements:image-cloze-association:controller');\n\nexport const normalize = (question) => ({\n rationaleEnabled: true,\n teacherInstructionsEnabled: true,\n studentInstructionsEnabled: true,\n ...question,\n});\n\nexport function model(question, session, env) {\n const questionNormalized = normalize(question);\n const questionCamelized = camelizeKeys(questionNormalized);\n\n return new Promise((resolve) => {\n const out = {\n disabled: env.mode !== 'gather',\n mode: env.mode,\n ...questionCamelized,\n responseCorrect: env.mode === 'evaluate' ? getScore(questionCamelized, session) === 1 : undefined,\n };\n\n if (questionNormalized.shuffle) {\n out.possibleResponses = shuffle(questionNormalized.possible_responses);\n }\n\n if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {\n out.teacherInstructions = questionCamelized.teacherInstructionsEnabled\n ? questionCamelized.teacherInstructions\n : null;\n } else {\n out.teacherInstructions = null;\n }\n\n resolve(out);\n });\n}\n\nexport const isResponseCorrect = (responses, session) => {\n let isCorrect = true;\n let totalValidResponses = 0;\n\n if (!session || isEmpty(session)) {\n return false;\n }\n\n responses.forEach((value) => (totalValidResponses += (value.images || []).length));\n\n if (session.answers && totalValidResponses === session.answers.length) {\n session.answers.forEach((answer) => {\n if (!(responses[answer.containerIndex] && responses[answer.containerIndex].images || []).includes(answer.value)) {\n isCorrect = false;\n }\n });\n } else {\n isCorrect = false;\n }\n return isCorrect;\n};\n\n// This applies for correct responses that have empty values\nconst keepNonEmptyResponses = (responses) => {\n const filtered = responses.filter(response => response.images && response.images.length);\n return cloneDeep(filtered);\n};\n\n// This applies for items that don't support partial scoring.\nconst isDefaultOrAltResponseCorrect = (question, session) => {\n const {\n validation: { altResponses }\n } = question;\n let {\n validation: {\n validResponse: { value },\n }\n } = question;\n\n value = keepNonEmptyResponses(value);\n\n let isCorrect = isResponseCorrect(value, session);\n\n // Look for correct answers in alternate responses.\n if (!isCorrect && altResponses && altResponses.length) {\n altResponses.forEach((altResponse) => {\n if (isResponseCorrect(altResponse.value, session)) {\n isCorrect = true;\n }\n });\n }\n return isCorrect;\n};\n\n// Deduct only the items that exceeded the maximum valid response per container.\nconst getDeductionPerContainer = (containerIndex, answers, valid) => {\n const totalStack = answers.filter((item) => item.containerIndex === containerIndex);\n const incorrectStack = totalStack.filter((item) => !item.isCorrect);\n const maxValid = (valid.value[containerIndex].images || []).length;\n\n if (totalStack.length > maxValid) {\n const ignored = totalStack.length - maxValid;\n return incorrectStack.slice(-ignored);\n }\n return [];\n};\n\nexport const getPartialScore = (question, session) => {\n const {\n validation: { validResponse },\n maxResponsePerZone,\n } = question;\n let correctAnswers = 0;\n let possibleResponses = 0;\n\n if (!session || isEmpty(session)) {\n return 0;\n }\n validResponse.value = keepNonEmptyResponses(validResponse.value);\n\n validResponse.value.forEach((value) => (possibleResponses += (value.images || []).length));\n\n if (session.answers && session.answers.length) {\n const all = getAllUniqueCorrectness(session.answers, validResponse.value);\n correctAnswers = all.filter((item) => item.isCorrect).length;\n\n // deduction rules: https://docs.google.com/document/d/1Oprm8Qs5fg_Dwoj2pNpsfu4D63QgCZgvcqTgeaVel7I/edit\n session.answers.forEach((answer) => {\n if (maxResponsePerZone > 1) {\n const deductionList = getDeductionPerContainer(answer.containerIndex, all, validResponse);\n\n if (deductionList.length) {\n deductionList.forEach((item) => {\n if (item.id === answer.id) {\n correctAnswers -= 1;\n }\n });\n }\n }\n });\n } else {\n correctAnswers = 0;\n }\n // negative values will implicitly make the score equal to zero\n correctAnswers = correctAnswers < 0 ? 0 : correctAnswers;\n\n // use length of validResponse since some containers can be left empty\n const denominator = maxResponsePerZone > 1 ? possibleResponses : (validResponse.value || []).length;\n const str = (correctAnswers / denominator).toFixed(2);\n\n return parseFloat(str);\n};\n\nconst getScore = (config, session, env = {}) => {\n const isPartialScoring = partialScoring.enabled(config, env);\n const correct = isDefaultOrAltResponseCorrect(config, session);\n\n return isPartialScoring ? getPartialScore(config, session) : correct ? 1 : 0;\n};\n\nexport function outcome(config, session, env = {}) {\n return new Promise((resolve) => {\n log('outcome...');\n if (!session || isEmpty(session)) {\n resolve({ score: 0, empty: true });\n }\n\n const configCamelized = camelizeKeys(config);\n\n if (session.answers || []) {\n const score = getScore(configCamelized, session, env);\n resolve({ score });\n }\n });\n}\n\nexport const createCorrectResponseSession = (question, env) => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const {\n validation: {\n valid_response: { value },\n },\n } = question;\n const answers = [];\n\n if (value) {\n value.forEach((container, i) => {\n (container.images || []).forEach((v) => {\n answers.push({\n value: v,\n containerIndex: i,\n });\n });\n });\n }\n\n resolve({\n answers,\n id: '1',\n });\n } else {\n resolve(null);\n }\n });\n};\n"],"file":"index.js"}
@@ -16,13 +16,13 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
16
16
  var getAllCorrectness = function getAllCorrectness(answers, responses) {
17
17
  return answers.map(function (answer) {
18
18
  return _objectSpread(_objectSpread({}, answer), {}, {
19
- isCorrect: (responses[answer.containerIndex].images || []).includes(answer.value)
19
+ isCorrect: (responses[answer.containerIndex] && responses[answer.containerIndex].images || []).includes(answer.value)
20
20
  });
21
21
  });
22
22
  };
23
23
 
24
24
  var getValidAnswer = function getValidAnswer(answer, response) {
25
- return (response[answer.containerIndex].images || []).filter(function (res) {
25
+ return (response[answer.containerIndex] && response[answer.containerIndex].images || []).filter(function (res) {
26
26
  return res === answer.value;
27
27
  });
28
28
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils.js"],"names":["getAllCorrectness","answers","responses","map","answer","isCorrect","containerIndex","images","includes","value","getValidAnswer","response","filter","res","getAllUniqueCorrectness","validResponses","allCorrectness","forEach","answer1","valuesToParse","answer2","length","shift","index","finalAnswer","id","valid"],"mappings":";;;;;;;;;;;;;;;AAAA,IAAMA,iBAAiB,GAAG,SAApBA,iBAAoB,CAACC,OAAD,EAAUC,SAAV;AAAA,SACxBD,OAAO,CAACE,GAAR,CAAY,UAACC,MAAD;AAAA,2CACPA,MADO;AAEVC,MAAAA,SAAS,EAAE,CAACH,SAAS,CAACE,MAAM,CAACE,cAAR,CAAT,CAAiCC,MAAjC,IAA2C,EAA5C,EAAgDC,QAAhD,CAAyDJ,MAAM,CAACK,KAAhE;AAFD;AAAA,GAAZ,CADwB;AAAA,CAA1B;;AAMA,IAAMC,cAAc,GAAG,SAAjBA,cAAiB,CAACN,MAAD,EAASO,QAAT;AAAA,SACrB,CAACA,QAAQ,CAACP,MAAM,CAACE,cAAR,CAAR,CAAgCC,MAAhC,IAA0C,EAA3C,EAA+CK,MAA/C,CAAsD,UAACC,GAAD;AAAA,WAASA,GAAG,KAAKT,MAAM,CAACK,KAAxB;AAAA,GAAtD,CADqB;AAAA,CAAvB;;AAGO,IAAMK,uBAAuB,GAAG,SAA1BA,uBAA0B,CAACb,OAAD,EAAUc,cAAV,EAA6B;AAClE,MAAIC,cAAc,GAAGhB,iBAAiB,CAACC,OAAD,EAAUc,cAAV,CAAtC;AAEAd,EAAAA,OAAO,CAACgB,OAAR,CAAgB,UAACC,OAAD,EAAa;AAC3B,QAAMC,aAAa,GAAGlB,OAAO,CAACW,MAAR,CACpB,UAACQ,OAAD;AAAA,aAAaA,OAAO,CAACX,KAAR,KAAkBS,OAAO,CAACT,KAA1B,IAAmCW,OAAO,CAACd,cAAR,KAA2BY,OAAO,CAACZ,cAAnF;AAAA,KADoB,CAAtB;;AAIA,QAAIa,aAAa,CAACE,MAAd,GAAuB,CAA3B,EAA8B;AAC5B;AACAF,MAAAA,aAAa,CAACG,KAAd,GAF4B,CAG5B;;AACAH,MAAAA,aAAa,CAACF,OAAd,CAAsB,UAACR,KAAD,EAAQc,KAAR,EAAkB;AACtCP,QAAAA,cAAc,GAAGA,cAAc,CAACb,GAAf,CAAmB,UAACqB,WAAD,EAAiB;AACnD,cAAIA,WAAW,CAACC,EAAZ,KAAmBhB,KAAK,CAACgB,EAA7B,EAAiC;AAC/B,gBAAIC,KAAK,GAAGhB,cAAc,CAACc,WAAD,EAAcT,cAAd,CAA1B;AACA,mDACKS,WADL;AAEEnB,cAAAA,SAAS,EAAEqB,KAAK,CAACL,MAAN,GAAeE,KAAK,GAAG;AAFpC;AAID;;AACD,iBAAOC,WAAP;AACD,SATgB,CAAjB;AAUD,OAXD;AAYD;AACF,GAtBD;AAuBA,SAAOR,cAAP;AACD,CA3BM","sourcesContent":["const getAllCorrectness = (answers, responses) =>\n answers.map((answer) => ({\n ...answer,\n isCorrect: (responses[answer.containerIndex].images || []).includes(answer.value),\n }));\n\nconst getValidAnswer = (answer, response) =>\n (response[answer.containerIndex].images || []).filter((res) => res === answer.value);\n\nexport const getAllUniqueCorrectness = (answers, validResponses) => {\n let allCorrectness = getAllCorrectness(answers, validResponses);\n\n answers.forEach((answer1) => {\n const valuesToParse = answers.filter(\n (answer2) => answer2.value === answer1.value && answer2.containerIndex === answer1.containerIndex,\n );\n\n if (valuesToParse.length > 1) {\n // point only to duplicates but first\n valuesToParse.shift();\n // mark duplicates as incorrect\n valuesToParse.forEach((value, index) => {\n allCorrectness = allCorrectness.map((finalAnswer) => {\n if (finalAnswer.id === value.id) {\n let valid = getValidAnswer(finalAnswer, validResponses);\n return {\n ...finalAnswer,\n isCorrect: valid.length > index + 1,\n };\n }\n return finalAnswer;\n });\n });\n }\n });\n return allCorrectness;\n};\n"],"file":"utils.js"}
1
+ {"version":3,"sources":["../src/utils.js"],"names":["getAllCorrectness","answers","responses","map","answer","isCorrect","containerIndex","images","includes","value","getValidAnswer","response","filter","res","getAllUniqueCorrectness","validResponses","allCorrectness","forEach","answer1","valuesToParse","answer2","length","shift","index","finalAnswer","id","valid"],"mappings":";;;;;;;;;;;;;;;AAAA,IAAMA,iBAAiB,GAAG,SAApBA,iBAAoB,CAACC,OAAD,EAAUC,SAAV;AAAA,SACxBD,OAAO,CAACE,GAAR,CAAY,UAACC,MAAD;AAAA,2CACPA,MADO;AAEVC,MAAAA,SAAS,EAAE,CAACH,SAAS,CAACE,MAAM,CAACE,cAAR,CAAT,IAAoCJ,SAAS,CAACE,MAAM,CAACE,cAAR,CAAT,CAAiCC,MAArE,IAA+E,EAAhF,EAAoFC,QAApF,CAA6FJ,MAAM,CAACK,KAApG;AAFD;AAAA,GAAZ,CADwB;AAAA,CAA1B;;AAMA,IAAMC,cAAc,GAAG,SAAjBA,cAAiB,CAACN,MAAD,EAASO,QAAT;AAAA,SACrB,CAACA,QAAQ,CAACP,MAAM,CAACE,cAAR,CAAR,IAAmCK,QAAQ,CAACP,MAAM,CAACE,cAAR,CAAR,CAAgCC,MAAnE,IAA6E,EAA9E,EAAkFK,MAAlF,CAAyF,UAACC,GAAD;AAAA,WAASA,GAAG,KAAKT,MAAM,CAACK,KAAxB;AAAA,GAAzF,CADqB;AAAA,CAAvB;;AAGO,IAAMK,uBAAuB,GAAG,SAA1BA,uBAA0B,CAACb,OAAD,EAAUc,cAAV,EAA6B;AAClE,MAAIC,cAAc,GAAGhB,iBAAiB,CAACC,OAAD,EAAUc,cAAV,CAAtC;AAEAd,EAAAA,OAAO,CAACgB,OAAR,CAAgB,UAACC,OAAD,EAAa;AAC3B,QAAMC,aAAa,GAAGlB,OAAO,CAACW,MAAR,CACpB,UAACQ,OAAD;AAAA,aAAaA,OAAO,CAACX,KAAR,KAAkBS,OAAO,CAACT,KAA1B,IAAmCW,OAAO,CAACd,cAAR,KAA2BY,OAAO,CAACZ,cAAnF;AAAA,KADoB,CAAtB;;AAIA,QAAIa,aAAa,CAACE,MAAd,GAAuB,CAA3B,EAA8B;AAC5B;AACAF,MAAAA,aAAa,CAACG,KAAd,GAF4B,CAG5B;;AACAH,MAAAA,aAAa,CAACF,OAAd,CAAsB,UAACR,KAAD,EAAQc,KAAR,EAAkB;AACtCP,QAAAA,cAAc,GAAGA,cAAc,CAACb,GAAf,CAAmB,UAACqB,WAAD,EAAiB;AACnD,cAAIA,WAAW,CAACC,EAAZ,KAAmBhB,KAAK,CAACgB,EAA7B,EAAiC;AAC/B,gBAAIC,KAAK,GAAGhB,cAAc,CAACc,WAAD,EAAcT,cAAd,CAA1B;AACA,mDACKS,WADL;AAEEnB,cAAAA,SAAS,EAAEqB,KAAK,CAACL,MAAN,GAAeE,KAAK,GAAG;AAFpC;AAID;;AACD,iBAAOC,WAAP;AACD,SATgB,CAAjB;AAUD,OAXD;AAYD;AACF,GAtBD;AAuBA,SAAOR,cAAP;AACD,CA3BM","sourcesContent":["const getAllCorrectness = (answers, responses) =>\n answers.map((answer) => ({\n ...answer,\n isCorrect: (responses[answer.containerIndex] && responses[answer.containerIndex].images || []).includes(answer.value),\n }));\n\nconst getValidAnswer = (answer, response) =>\n (response[answer.containerIndex] && response[answer.containerIndex].images || []).filter((res) => res === answer.value);\n\nexport const getAllUniqueCorrectness = (answers, validResponses) => {\n let allCorrectness = getAllCorrectness(answers, validResponses);\n\n answers.forEach((answer1) => {\n const valuesToParse = answers.filter(\n (answer2) => answer2.value === answer1.value && answer2.containerIndex === answer1.containerIndex,\n );\n\n if (valuesToParse.length > 1) {\n // point only to duplicates but first\n valuesToParse.shift();\n // mark duplicates as incorrect\n valuesToParse.forEach((value, index) => {\n allCorrectness = allCorrectness.map((finalAnswer) => {\n if (finalAnswer.id === value.id) {\n let valid = getValidAnswer(finalAnswer, validResponses);\n return {\n ...finalAnswer,\n isCorrect: valid.length > index + 1,\n };\n }\n return finalAnswer;\n });\n });\n }\n });\n return allCorrectness;\n};\n"],"file":"utils.js"}
@@ -163,6 +163,58 @@ describe('controller', () => {
163
163
  expect(result.score).toEqual(1);
164
164
  });
165
165
 
166
+ it('returns correct score for valid response with empty response containers and partialScoring: false', async () => {
167
+ const result = await outcome({
168
+ ...question,
169
+ validation: {
170
+ valid_response: {
171
+ score: 1,
172
+ value: [
173
+ {
174
+ images: [rhomb, square],
175
+ },
176
+ {
177
+ images: [],
178
+ },
179
+ ],
180
+ },
181
+ }
182
+ }, {
183
+ answers: [
184
+ { value: rhomb, containerIndex: 0 },
185
+ { value: square, containerIndex: 0 },
186
+ ],
187
+ });
188
+
189
+ expect(result.score).toEqual(1);
190
+ });
191
+
192
+ it('returns correct score for valid response with empty response containers and partialScoring: true', async () => {
193
+ const result = await outcome({
194
+ ...question,
195
+ partialScoring: true,
196
+ validation: {
197
+ valid_response: {
198
+ score: 1,
199
+ value: [
200
+ {
201
+ images: [rhomb, square],
202
+ },
203
+ {
204
+ images: [],
205
+ },
206
+ ],
207
+ },
208
+ }
209
+ }, {
210
+ answers: [
211
+ { value: rhomb, containerIndex: 0 },
212
+ ],
213
+ });
214
+
215
+ expect(result.score).toEqual(0.5);
216
+ });
217
+
166
218
  describe('returns score 0 for wrong validation format', () => {
167
219
  it('returns 0 for old value format', async () => {
168
220
  const result = await outcome(
@@ -5,6 +5,7 @@ import { camelizeKeys } from 'humps';
5
5
  import { partialScoring } from '@pie-lib/controller-utils';
6
6
 
7
7
  import { getAllUniqueCorrectness } from './utils';
8
+ import { cloneDeep } from 'lodash';
8
9
 
9
10
  const log = debug('pie-elements:image-cloze-association:controller');
10
11
 
@@ -55,7 +56,7 @@ export const isResponseCorrect = (responses, session) => {
55
56
 
56
57
  if (session.answers && totalValidResponses === session.answers.length) {
57
58
  session.answers.forEach((answer) => {
58
- if (!(responses[answer.containerIndex].images || []).includes(answer.value)) {
59
+ if (!(responses[answer.containerIndex] && responses[answer.containerIndex].images || []).includes(answer.value)) {
59
60
  isCorrect = false;
60
61
  }
61
62
  });
@@ -65,15 +66,25 @@ export const isResponseCorrect = (responses, session) => {
65
66
  return isCorrect;
66
67
  };
67
68
 
69
+ // This applies for correct responses that have empty values
70
+ const keepNonEmptyResponses = (responses) => {
71
+ const filtered = responses.filter(response => response.images && response.images.length);
72
+ return cloneDeep(filtered);
73
+ };
74
+
68
75
  // This applies for items that don't support partial scoring.
69
76
  const isDefaultOrAltResponseCorrect = (question, session) => {
70
77
  const {
78
+ validation: { altResponses }
79
+ } = question;
80
+ let {
71
81
  validation: {
72
82
  validResponse: { value },
73
- altResponses,
74
- },
83
+ }
75
84
  } = question;
76
85
 
86
+ value = keepNonEmptyResponses(value);
87
+
77
88
  let isCorrect = isResponseCorrect(value, session);
78
89
 
79
90
  // Look for correct answers in alternate responses.
@@ -104,7 +115,6 @@ export const getPartialScore = (question, session) => {
104
115
  const {
105
116
  validation: { validResponse },
106
117
  maxResponsePerZone,
107
- responseContainers,
108
118
  } = question;
109
119
  let correctAnswers = 0;
110
120
  let possibleResponses = 0;
@@ -112,6 +122,7 @@ export const getPartialScore = (question, session) => {
112
122
  if (!session || isEmpty(session)) {
113
123
  return 0;
114
124
  }
125
+ validResponse.value = keepNonEmptyResponses(validResponse.value);
115
126
 
116
127
  validResponse.value.forEach((value) => (possibleResponses += (value.images || []).length));
117
128
 
@@ -139,7 +150,8 @@ export const getPartialScore = (question, session) => {
139
150
  // negative values will implicitly make the score equal to zero
140
151
  correctAnswers = correctAnswers < 0 ? 0 : correctAnswers;
141
152
 
142
- const denominator = maxResponsePerZone > 1 ? possibleResponses : responseContainers.length;
153
+ // use length of validResponse since some containers can be left empty
154
+ const denominator = maxResponsePerZone > 1 ? possibleResponses : (validResponse.value || []).length;
143
155
  const str = (correctAnswers / denominator).toFixed(2);
144
156
 
145
157
  return parseFloat(str);
@@ -1,11 +1,11 @@
1
1
  const getAllCorrectness = (answers, responses) =>
2
2
  answers.map((answer) => ({
3
3
  ...answer,
4
- isCorrect: (responses[answer.containerIndex].images || []).includes(answer.value),
4
+ isCorrect: (responses[answer.containerIndex] && responses[answer.containerIndex].images || []).includes(answer.value),
5
5
  }));
6
6
 
7
7
  const getValidAnswer = (answer, response) =>
8
- (response[answer.containerIndex].images || []).filter((res) => res === answer.value);
8
+ (response[answer.containerIndex] && response[answer.containerIndex].images || []).filter((res) => res === answer.value);
9
9
 
10
10
  export const getAllUniqueCorrectness = (answers, validResponses) => {
11
11
  let allCorrectness = getAllCorrectness(answers, validResponses);
@@ -18,7 +18,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
18
18
  var getAllCorrectAnswers = function getAllCorrectAnswers(answers, responses) {
19
19
  return answers.map(function (answer) {
20
20
  return _objectSpread(_objectSpread({}, answer), {}, {
21
- isCorrect: (responses[answer.containerIndex].images || []).includes(answer.value)
21
+ isCorrect: (responses[answer.containerIndex] && responses[answer.containerIndex].images || []).includes(answer.value)
22
22
  });
23
23
  });
24
24
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils-correctness.js"],"names":["getAllCorrectAnswers","answers","responses","map","answer","isCorrect","containerIndex","images","includes","value","getValidAnswer","response","filter","res","getUniqueCorrectAnswers","validResponses","finalAnswers","forEach","answer1","valuesToParse","answer2","length","shift","index","finalAnswer","id","valid","getUnansweredAnswers","validation","validResponse","unansweredAnswers","reduce","unanswered","isAnswered","find","hidden","getAnswersCorrectness","altResponses","allCorrect","uniqueAnswers","noOfCorrect","altUniqueStack","altResponse","altValue","altAllCorrect","sort","a","b","c"],"mappings":"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","sourcesContent":["const getAllCorrectAnswers = (answers, responses) =>\n answers.map((answer) => ({\n ...answer,\n isCorrect: (responses[answer.containerIndex].images || []).includes(answer.value),\n }));\n\nconst getValidAnswer = (answer, response) =>\n (response[answer.containerIndex].images || []).filter((res) => res === answer.value);\n\nconst getUniqueCorrectAnswers = (answers, validResponses) => {\n let finalAnswers = answers;\n\n answers.forEach((answer1) => {\n const valuesToParse = answers.filter(\n (answer2) => answer2.value === answer1.value && answer2.containerIndex === answer1.containerIndex,\n );\n\n if (valuesToParse.length > 1) {\n // point only to duplicates but first\n valuesToParse.shift();\n // mark duplicates as incorrect\n valuesToParse.forEach((value, index) => {\n finalAnswers = finalAnswers.map((finalAnswer) => {\n if (finalAnswer.id === value.id) {\n let valid = getValidAnswer(finalAnswer, validResponses);\n\n return {\n ...finalAnswer,\n isCorrect: valid.length > index + 1,\n };\n }\n return finalAnswer;\n });\n });\n }\n });\n return finalAnswers;\n};\n\nexport const getUnansweredAnswers = (answers, validation) => {\n const { validResponse: { value } = {} } = validation;\n\n const unansweredAnswers = (value || []).reduce((unanswered, response, index) => {\n const isAnswered = !!answers.find((answer) => answer.containerIndex === index);\n\n if (!isAnswered) {\n return [\n ...unanswered,\n {\n id: `unanswered-${index}`,\n value: response.images[0] || '',\n containerIndex: index,\n isCorrect: false,\n hidden: true,\n },\n ];\n }\n\n return unanswered;\n }, []);\n\n return unansweredAnswers;\n};\n\nexport const getAnswersCorrectness = (answers, validation) => {\n const {\n validResponse: { value },\n altResponses,\n } = validation;\n\n const allCorrect = getAllCorrectAnswers(answers, value);\n const uniqueAnswers = getUniqueCorrectAnswers(allCorrect, value);\n const noOfCorrect = uniqueAnswers.filter((answer) => answer.isCorrect).length;\n\n // Look for alternate correct responses if there are incorrect responses.\n if (noOfCorrect < uniqueAnswers.length && altResponses && altResponses.length) {\n const altUniqueStack = altResponses.map((altResponse) => {\n const altValue = altResponse.value;\n\n const altAllCorrect = getAllCorrectAnswers(answers, altValue);\n return getUniqueCorrectAnswers(altAllCorrect, altValue);\n });\n // Return the one with most correct answers.\n return altUniqueStack.sort((a, b) => b.filter((c) => c.isCorrect).length - a.filter((c) => c.isCorrect).length)[0];\n }\n return uniqueAnswers;\n};\n"],"file":"utils-correctness.js"}
1
+ {"version":3,"sources":["../src/utils-correctness.js"],"names":["getAllCorrectAnswers","answers","responses","map","answer","isCorrect","containerIndex","images","includes","value","getValidAnswer","response","filter","res","getUniqueCorrectAnswers","validResponses","finalAnswers","forEach","answer1","valuesToParse","answer2","length","shift","index","finalAnswer","id","valid","getUnansweredAnswers","validation","validResponse","unansweredAnswers","reduce","unanswered","isAnswered","find","hidden","getAnswersCorrectness","altResponses","allCorrect","uniqueAnswers","noOfCorrect","altUniqueStack","altResponse","altValue","altAllCorrect","sort","a","b","c"],"mappings":"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","sourcesContent":["const getAllCorrectAnswers = (answers, responses) =>\n answers.map((answer) => ({\n ...answer,\n isCorrect: (responses[answer.containerIndex] && responses[answer.containerIndex].images || []).includes(answer.value),\n }));\n\nconst getValidAnswer = (answer, response) =>\n (response[answer.containerIndex].images || []).filter((res) => res === answer.value);\n\nconst getUniqueCorrectAnswers = (answers, validResponses) => {\n let finalAnswers = answers;\n\n answers.forEach((answer1) => {\n const valuesToParse = answers.filter(\n (answer2) => answer2.value === answer1.value && answer2.containerIndex === answer1.containerIndex,\n );\n\n if (valuesToParse.length > 1) {\n // point only to duplicates but first\n valuesToParse.shift();\n // mark duplicates as incorrect\n valuesToParse.forEach((value, index) => {\n finalAnswers = finalAnswers.map((finalAnswer) => {\n if (finalAnswer.id === value.id) {\n let valid = getValidAnswer(finalAnswer, validResponses);\n\n return {\n ...finalAnswer,\n isCorrect: valid.length > index + 1,\n };\n }\n return finalAnswer;\n });\n });\n }\n });\n return finalAnswers;\n};\n\nexport const getUnansweredAnswers = (answers, validation) => {\n const { validResponse: { value } = {} } = validation;\n\n const unansweredAnswers = (value || []).reduce((unanswered, response, index) => {\n const isAnswered = !!answers.find((answer) => answer.containerIndex === index);\n\n if (!isAnswered) {\n return [\n ...unanswered,\n {\n id: `unanswered-${index}`,\n value: response.images[0] || '',\n containerIndex: index,\n isCorrect: false,\n hidden: true,\n },\n ];\n }\n\n return unanswered;\n }, []);\n\n return unansweredAnswers;\n};\n\nexport const getAnswersCorrectness = (answers, validation) => {\n const {\n validResponse: { value },\n altResponses,\n } = validation;\n\n const allCorrect = getAllCorrectAnswers(answers, value);\n const uniqueAnswers = getUniqueCorrectAnswers(allCorrect, value);\n const noOfCorrect = uniqueAnswers.filter((answer) => answer.isCorrect).length;\n\n // Look for alternate correct responses if there are incorrect responses.\n if (noOfCorrect < uniqueAnswers.length && altResponses && altResponses.length) {\n const altUniqueStack = altResponses.map((altResponse) => {\n const altValue = altResponse.value;\n\n const altAllCorrect = getAllCorrectAnswers(answers, altValue);\n return getUniqueCorrectAnswers(altAllCorrect, altValue);\n });\n // Return the one with most correct answers.\n return altUniqueStack.sort((a, b) => b.filter((c) => c.isCorrect).length - a.filter((c) => c.isCorrect).length)[0];\n }\n return uniqueAnswers;\n};\n"],"file":"utils-correctness.js"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pie-element/image-cloze-association",
3
- "version": "4.9.1-next.2+755b939e9",
3
+ "version": "4.9.1-next.24+9353f7376",
4
4
  "description": "",
5
5
  "repository": "pie-framework/pie-elements",
6
6
  "publishConfig": {
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "author": "pie framework developers",
23
23
  "license": "ISC",
24
- "gitHead": "755b939e9891a6523a5d20360e52dce285fbc83a",
24
+ "gitHead": "9353f73768c78233621ab11119b1961af018a7e4",
25
25
  "scripts": {
26
26
  "postpublish": "../../scripts/postpublish"
27
27
  },
@@ -1,7 +1,7 @@
1
1
  const getAllCorrectAnswers = (answers, responses) =>
2
2
  answers.map((answer) => ({
3
3
  ...answer,
4
- isCorrect: (responses[answer.containerIndex].images || []).includes(answer.value),
4
+ isCorrect: (responses[answer.containerIndex] && responses[answer.containerIndex].images || []).includes(answer.value),
5
5
  }));
6
6
 
7
7
  const getValidAnswer = (answer, response) =>