@pie-element/image-cloze-association 8.0.1 → 8.2.0
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 +20 -0
- package/configure/CHANGELOG.md +19 -0
- package/configure/package.json +3 -3
- package/controller/CHANGELOG.md +20 -0
- package/controller/lib/index.js +7 -1
- package/controller/lib/index.js.map +1 -1
- package/controller/lib/utils.js +41 -2
- package/controller/lib/utils.js.map +1 -1
- package/controller/package.json +2 -2
- package/controller/src/index.js +7 -1
- package/controller/src/utils.js +24 -0
- package/lib/index.js +44 -3
- package/lib/index.js.map +1 -1
- package/package.json +8 -25
- package/src/__tests__/index.test.js +17 -2
- package/src/index.js +40 -3
- package/esm/configure.js +0 -7714
- package/esm/configure.js.map +0 -1
- package/esm/controller.js +0 -444
- package/esm/controller.js.map +0 -1
- package/esm/element.js +0 -11333
- package/esm/element.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [8.2.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/image-cloze-association@8.0.0...@pie-element/image-cloze-association@8.2.0) (2025-10-10)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* update completion rule for categorize, ditb, and image-cloze PD-5179 ([cd03a6e](https://github.com/pie-framework/pie-elements/commit/cd03a6e56e51cc3778749b3679b87f9122405936))
|
|
12
|
+
* update libs PD-5208, PD-5211, PD-5199, PD-5218, PD-5217 ([da327fa](https://github.com/pie-framework/pie-elements/commit/da327fa501f6e9eff1c0b30b5ef092426a91f78b))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# [8.1.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/image-cloze-association@7.0.0...@pie-element/image-cloze-association@8.1.0) (2025-10-07)
|
|
19
|
+
|
|
20
|
+
**Note:** Version bump only for package @pie-element/image-cloze-association
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
6
26
|
# [8.0.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/image-cloze-association@6.14.0...@pie-element/image-cloze-association@8.0.0) (2025-10-02)
|
|
7
27
|
|
|
8
28
|
|
package/configure/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [7.2.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/image-cloze-association-configure@7.0.1...@pie-element/image-cloze-association-configure@7.2.0) (2025-10-10)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* update libs PD-5208, PD-5211, PD-5199, PD-5218, PD-5217 ([da327fa](https://github.com/pie-framework/pie-elements/commit/da327fa501f6e9eff1c0b30b5ef092426a91f78b))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [7.1.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/image-cloze-association-configure@7.0.0...@pie-element/image-cloze-association-configure@7.1.0) (2025-10-07)
|
|
18
|
+
|
|
19
|
+
**Note:** Version bump only for package @pie-element/image-cloze-association-configure
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
6
25
|
## [7.0.1](https://github.com/pie-framework/pie-elements/compare/@pie-element/image-cloze-association-configure@6.6.0...@pie-element/image-cloze-association-configure@7.0.1) (2025-10-02)
|
|
7
26
|
|
|
8
27
|
**Note:** Version bump only for package @pie-element/image-cloze-association-configure
|
package/configure/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pie-element/image-cloze-association-configure",
|
|
3
3
|
"private": true,
|
|
4
|
-
"version": "7.0
|
|
4
|
+
"version": "7.2.0",
|
|
5
5
|
"description": "",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"module": "src/index.js",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@material-ui/core": "^3.9.2",
|
|
11
11
|
"@pie-framework/pie-configure-events": "^1.3.0",
|
|
12
|
-
"@pie-lib/config-ui": "^11.
|
|
13
|
-
"@pie-lib/editable-html": "^11.
|
|
12
|
+
"@pie-lib/config-ui": "^11.25.1",
|
|
13
|
+
"@pie-lib/editable-html": "^11.17.1",
|
|
14
14
|
"debug": "^3.1.0",
|
|
15
15
|
"prop-types": "^15.7.2",
|
|
16
16
|
"react": "^16.8.6",
|
package/controller/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [6.2.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/image-cloze-association-controller@6.0.1...@pie-element/image-cloze-association-controller@6.2.0) (2025-10-10)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* update completion rule for categorize, ditb, and image-cloze PD-5179 ([cd03a6e](https://github.com/pie-framework/pie-elements/commit/cd03a6e56e51cc3778749b3679b87f9122405936))
|
|
12
|
+
* update libs PD-5208, PD-5211, PD-5199, PD-5218, PD-5217 ([da327fa](https://github.com/pie-framework/pie-elements/commit/da327fa501f6e9eff1c0b30b5ef092426a91f78b))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# [6.1.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/image-cloze-association-controller@6.0.0...@pie-element/image-cloze-association-controller@6.1.0) (2025-10-07)
|
|
19
|
+
|
|
20
|
+
**Note:** Version bump only for package @pie-element/image-cloze-association-controller
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
6
26
|
## [6.0.1](https://github.com/pie-framework/pie-elements/compare/@pie-element/image-cloze-association-controller@5.3.0...@pie-element/image-cloze-association-controller@6.0.1) (2025-10-02)
|
|
7
27
|
|
|
8
28
|
**Note:** Version bump only for package @pie-element/image-cloze-association-controller
|
package/controller/lib/index.js
CHANGED
|
@@ -39,12 +39,18 @@ var model = function model(question, session, env) {
|
|
|
39
39
|
return new Promise(function (resolve) {
|
|
40
40
|
var shouldIncludeCorrectResponse = env.mode === 'evaluate';
|
|
41
41
|
|
|
42
|
+
var _getCompleteResponseD = (0, _utils.getCompleteResponseDetails)(questionCamelized.validation),
|
|
43
|
+
responseAreasToBeFilled = _getCompleteResponseD.responseAreasToBeFilled,
|
|
44
|
+
completeResponses = _getCompleteResponseD.possibleResponses;
|
|
45
|
+
|
|
42
46
|
var out = _objectSpread(_objectSpread({
|
|
43
47
|
disabled: env.mode !== 'gather',
|
|
44
48
|
mode: env.mode
|
|
45
49
|
}, questionCamelized), {}, {
|
|
46
50
|
responseCorrect: shouldIncludeCorrectResponse ? getScore(questionCamelized, session) === 1 : undefined,
|
|
47
|
-
validation: shouldIncludeCorrectResponse ? questionCamelized.validation : undefined
|
|
51
|
+
validation: shouldIncludeCorrectResponse ? questionCamelized.validation : undefined,
|
|
52
|
+
responseAreasToBeFilled: responseAreasToBeFilled,
|
|
53
|
+
completeResponses: completeResponses
|
|
48
54
|
});
|
|
49
55
|
|
|
50
56
|
if (questionNormalized.shuffle) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.js"],"names":["log","normalize","question","defaults","model","session","env","questionNormalized","questionCamelized","Promise","resolve","shouldIncludeCorrectResponse","mode","out","disabled","responseCorrect","getScore","undefined","validation","shuffle","possibleResponses","possible_responses","role","teacherInstructions","teacherInstructionsEnabled","rationale","isResponseCorrect","correctResponses","responses","isCorrect","totalValidResponses","forEach","value","images","length","answers","answer","index","containerIndex","indexOf","splice","keepNonEmptyResponses","filtered","filter","response","isDefaultOrAltResponseCorrect","altResponses","validResponse","altResponse","getDeductionPerContainer","valid","totalStack","item","incorrectStack","maxValid","ignored","slice","getPartialScore","maxResponsePerZone","correctAnswers","incorrectAnswers","all","deductionList","id","nonEmptyResponses","denominator","str","toFixed","parseFloat","config","isPartialScoring","partialScoring","enabled","correct","outcome","score","empty","configCamelized","createCorrectResponseSession","valid_response","container","i","v","push","getInnerText","html","replaceAll","getContent","replace","validate","errors","field","required"],"mappings":"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","sourcesContent":["import debug from 'debug';\nimport { camelizeKeys } from 'humps';\nimport { partialScoring } from '@pie-lib/controller-utils';\nimport { cloneDeep, isEmpty, shuffle } from 'lodash';\n\nimport defaults from './defaults';\nimport { getAllUniqueCorrectness } from './utils';\n\nconst log = debug('pie-elements:image-cloze-association:controller');\n\nexport const normalize = (question) => ({ ...defaults, ...question });\n\nexport const model = (question, session, env) => {\n const questionNormalized = normalize(question);\n const questionCamelized = camelizeKeys(questionNormalized);\n\n return new Promise((resolve) => {\n const shouldIncludeCorrectResponse = env.mode === 'evaluate';\n\n const out = {\n disabled: env.mode !== 'gather',\n mode: env.mode,\n ...questionCamelized,\n responseCorrect: shouldIncludeCorrectResponse ? getScore(questionCamelized, session) === 1 : undefined,\n validation: shouldIncludeCorrectResponse ? questionCamelized.validation : 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 out.rationale = questionCamelized.rationale ? questionCamelized.rationale : null;\n } else {\n out.teacherInstructions = null;\n out.rationale = null;\n }\n\n resolve(out);\n });\n};\n\nexport const isResponseCorrect = (correctResponses, session) => {\n const responses = cloneDeep(correctResponses);\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 const index = (responses[answer.containerIndex]?.images || []).indexOf(answer.value);\n\n if (index >= 0) {\n // remove response from correct responses array to ensure that duplicates are evaluated correctly\n responses[answer.containerIndex].images.splice(index, 1);\n } else {\n isCorrect = false;\n }\n });\n } else {\n isCorrect = false;\n }\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 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 incorrectAnswers = 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 incorrectAnswers = 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\n if (!maxResponsePerZone || maxResponsePerZone <= 1) {\n correctAnswers -= incorrectAnswers;\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 nonEmptyResponses = keepNonEmptyResponses(validResponse.value);\n const denominator = maxResponsePerZone > 1 ? possibleResponses : (nonEmptyResponses || []).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 const 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\n// remove all html tags\nconst getInnerText = (html) => (html || '').replaceAll(/<[^>]*>/g, '');\n\n// remove all html tags except img, iframe and source tag for audio\nconst getContent = (html) => (html || '').replace(/(<(?!img|iframe|source)([^>]+)>)/gi, '');\n\nexport const validate = (model = {}, config = {}) => {\n const errors = {};\n\n ['teacherInstructions'].forEach((field) => {\n if (config[field]?.required && !getContent(model[field])) {\n errors[field] = 'This field is required.';\n }\n });\n\n return errors;\n};\n"],"file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../src/index.js"],"names":["log","normalize","question","defaults","model","session","env","questionNormalized","questionCamelized","Promise","resolve","shouldIncludeCorrectResponse","mode","validation","responseAreasToBeFilled","completeResponses","possibleResponses","out","disabled","responseCorrect","getScore","undefined","shuffle","possible_responses","role","teacherInstructions","teacherInstructionsEnabled","rationale","isResponseCorrect","correctResponses","responses","isCorrect","totalValidResponses","forEach","value","images","length","answers","answer","index","containerIndex","indexOf","splice","keepNonEmptyResponses","filtered","filter","response","isDefaultOrAltResponseCorrect","altResponses","validResponse","altResponse","getDeductionPerContainer","valid","totalStack","item","incorrectStack","maxValid","ignored","slice","getPartialScore","maxResponsePerZone","correctAnswers","incorrectAnswers","all","deductionList","id","nonEmptyResponses","denominator","str","toFixed","parseFloat","config","isPartialScoring","partialScoring","enabled","correct","outcome","score","empty","configCamelized","createCorrectResponseSession","valid_response","container","i","v","push","getInnerText","html","replaceAll","getContent","replace","validate","errors","field","required"],"mappings":"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","sourcesContent":["import debug from 'debug';\nimport { camelizeKeys } from 'humps';\nimport { partialScoring } from '@pie-lib/controller-utils';\nimport { cloneDeep, isEmpty, shuffle } from 'lodash';\n\nimport defaults from './defaults';\nimport { getAllUniqueCorrectness, getCompleteResponseDetails } from './utils';\n\nconst log = debug('pie-elements:image-cloze-association:controller');\n\nexport const normalize = (question) => ({ ...defaults, ...question });\n\nexport const model = (question, session, env) => {\n const questionNormalized = normalize(question);\n const questionCamelized = camelizeKeys(questionNormalized);\n\n return new Promise((resolve) => {\n const shouldIncludeCorrectResponse = env.mode === 'evaluate';\n\n const { responseAreasToBeFilled, possibleResponses: completeResponses } = getCompleteResponseDetails(\n questionCamelized.validation,\n );\n\n const out = {\n disabled: env.mode !== 'gather',\n mode: env.mode,\n ...questionCamelized,\n responseCorrect: shouldIncludeCorrectResponse ? getScore(questionCamelized, session) === 1 : undefined,\n validation: shouldIncludeCorrectResponse ? questionCamelized.validation : undefined,\n responseAreasToBeFilled,\n completeResponses,\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 out.rationale = questionCamelized.rationale ? questionCamelized.rationale : null;\n } else {\n out.teacherInstructions = null;\n out.rationale = null;\n }\n\n resolve(out);\n });\n};\n\nexport const isResponseCorrect = (correctResponses, session) => {\n const responses = cloneDeep(correctResponses);\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 const index = (responses[answer.containerIndex]?.images || []).indexOf(answer.value);\n\n if (index >= 0) {\n // remove response from correct responses array to ensure that duplicates are evaluated correctly\n responses[answer.containerIndex].images.splice(index, 1);\n } else {\n isCorrect = false;\n }\n });\n } else {\n isCorrect = false;\n }\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 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 incorrectAnswers = 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 incorrectAnswers = 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\n if (!maxResponsePerZone || maxResponsePerZone <= 1) {\n correctAnswers -= incorrectAnswers;\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 nonEmptyResponses = keepNonEmptyResponses(validResponse.value);\n const denominator = maxResponsePerZone > 1 ? possibleResponses : (nonEmptyResponses || []).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 const 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\n// remove all html tags\nconst getInnerText = (html) => (html || '').replaceAll(/<[^>]*>/g, '');\n\n// remove all html tags except img, iframe and source tag for audio\nconst getContent = (html) => (html || '').replace(/(<(?!img|iframe|source)([^>]+)>)/gi, '');\n\nexport const validate = (model = {}, config = {}) => {\n const errors = {};\n\n ['teacherInstructions'].forEach((field) => {\n if (config[field]?.required && !getContent(model[field])) {\n errors[field] = 'This field is required.';\n }\n });\n\n return errors;\n};\n"],"file":"index.js"}
|
package/controller/lib/utils.js
CHANGED
|
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", {
|
|
6
6
|
value: true
|
|
7
7
|
});
|
|
8
|
-
exports.getAllUniqueCorrectness = void 0;
|
|
8
|
+
exports.getCompleteResponseDetails = exports.getAllUniqueCorrectness = void 0;
|
|
9
9
|
|
|
10
10
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
11
|
|
|
@@ -54,7 +54,46 @@ var getAllUniqueCorrectness = function getAllUniqueCorrectness(answers, validRes
|
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
return allCorrectness;
|
|
57
|
-
};
|
|
57
|
+
}; // calculate the minimum number of populated response areas (categories) in the correct answer or alternates
|
|
58
|
+
// and create an array with the possible responses ids
|
|
59
|
+
|
|
58
60
|
|
|
59
61
|
exports.getAllUniqueCorrectness = getAllUniqueCorrectness;
|
|
62
|
+
|
|
63
|
+
var getCompleteResponseDetails = function getCompleteResponseDetails(validation) {
|
|
64
|
+
var extractImages = function extractImages(response) {
|
|
65
|
+
return ((response === null || response === void 0 ? void 0 : response.value) || []).map(function (container) {
|
|
66
|
+
return container.images;
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
var countFilledResponseAreas = function countFilledResponseAreas(container) {
|
|
71
|
+
return (container || []).filter(function (images) {
|
|
72
|
+
return images.length;
|
|
73
|
+
}).length;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
var _ref = validation || {},
|
|
77
|
+
validResponse = _ref.validResponse,
|
|
78
|
+
altResponses = _ref.altResponses;
|
|
79
|
+
|
|
80
|
+
var imagesPerContainer = extractImages(validResponse);
|
|
81
|
+
var possibleResponses = [imagesPerContainer.flat()];
|
|
82
|
+
var responseAreasToBeFilled = countFilledResponseAreas(imagesPerContainer);
|
|
83
|
+
(altResponses || []).forEach(function (altResponse) {
|
|
84
|
+
var altImagesPerContainer = extractImages(altResponse);
|
|
85
|
+
var filledResponseAreas = countFilledResponseAreas(altImagesPerContainer);
|
|
86
|
+
possibleResponses.push(altImagesPerContainer.flat());
|
|
87
|
+
|
|
88
|
+
if (filledResponseAreas < responseAreasToBeFilled) {
|
|
89
|
+
responseAreasToBeFilled = filledResponseAreas;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
responseAreasToBeFilled: responseAreasToBeFilled,
|
|
94
|
+
possibleResponses: possibleResponses
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
exports.getCompleteResponseDetails = getCompleteResponseDetails;
|
|
60
99
|
//# sourceMappingURL=utils.js.map
|
|
@@ -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;AAEA,IAAMA,iBAAiB,GAAG,SAApBA,iBAAoB,CAACC,OAAD,EAAUC,SAAV;AAAA,SACxB,CAACD,OAAO,IAAI,EAAZ,EAAgBE,GAAhB,CAAoB,UAACC,MAAD;AAAA,2CACfA,MADe;AAElBC,MAAAA,SAAS,EAAE,CAAEH,SAAS,CAACE,MAAM,CAACE,cAAR,CAAT,IAAoCJ,SAAS,CAACE,MAAM,CAACE,cAAR,CAAT,CAAiCC,MAAtE,IAAiF,EAAlF,EAAsFC,QAAtF,CACTJ,MAAM,CAACK,KADE;AAFO;AAAA,GAApB,CADwB;AAAA,CAA1B;;AAQA,IAAMC,cAAc,GAAG,SAAjBA,cAAiB,CAACN,MAAD,EAASO,QAAT;AAAA,SACrB,CAAEA,QAAQ,CAACP,MAAM,CAACE,cAAR,CAAR,IAAmCK,QAAQ,CAACP,MAAM,CAACE,cAAR,CAAR,CAAgCC,MAApE,IAA+E,EAAhF,EAAoFK,MAApF,CACE,UAACC,GAAD;AAAA,WAASA,GAAG,KAAKT,MAAM,CAACK,KAAxB;AAAA,GADF,CADqB;AAAA,CAAvB;;AAKO,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,GAAG,CAACA,cAAc,IAAI,EAAnB,EAAuBb,GAAvB,CAA2B,UAACqB,WAAD,EAAiB;AAC3D,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":["// functions also used in src/utils-correctness.js\n\nconst getAllCorrectness = (answers, responses) =>\n (answers || []).map((answer) => ({\n ...answer,\n isCorrect: ((responses[answer.containerIndex] && responses[answer.containerIndex].images) || []).includes(\n answer.value,\n ),\n }));\n\nconst getValidAnswer = (answer, response) =>\n ((response[answer.containerIndex] && response[answer.containerIndex].images) || []).filter(\n (res) => res === answer.value,\n );\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","getCompleteResponseDetails","validation","extractImages","container","countFilledResponseAreas","validResponse","altResponses","imagesPerContainer","possibleResponses","flat","responseAreasToBeFilled","altResponse","altImagesPerContainer","filledResponseAreas","push"],"mappings":"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","sourcesContent":["// functions also used in src/utils-correctness.js\n\nconst getAllCorrectness = (answers, responses) =>\n (answers || []).map((answer) => ({\n ...answer,\n isCorrect: ((responses[answer.containerIndex] && responses[answer.containerIndex].images) || []).includes(\n answer.value,\n ),\n }));\n\nconst getValidAnswer = (answer, response) =>\n ((response[answer.containerIndex] && response[answer.containerIndex].images) || []).filter(\n (res) => res === answer.value,\n );\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\n// calculate the minimum number of populated response areas (categories) in the correct answer or alternates\n// and create an array with the possible responses ids\nexport const getCompleteResponseDetails = (validation) => {\n const extractImages = (response) => (response?.value || []).map((container) => container.images);\n const countFilledResponseAreas = (container) => (container || []).filter((images) => images.length).length;\n\n const { validResponse, altResponses } = validation || {};\n const imagesPerContainer = extractImages(validResponse);\n const possibleResponses = [imagesPerContainer.flat()];\n let responseAreasToBeFilled = countFilledResponseAreas(imagesPerContainer);\n\n (altResponses || []).forEach((altResponse) => {\n const altImagesPerContainer = extractImages(altResponse);\n const filledResponseAreas = countFilledResponseAreas(altImagesPerContainer);\n possibleResponses.push(altImagesPerContainer.flat());\n\n if (filledResponseAreas < responseAreasToBeFilled) {\n responseAreasToBeFilled = filledResponseAreas;\n }\n });\n\n return { responseAreasToBeFilled, possibleResponses };\n};\n"],"file":"utils.js"}
|
package/controller/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pie-element/image-cloze-association-controller",
|
|
3
3
|
"private": true,
|
|
4
|
-
"version": "6.0
|
|
4
|
+
"version": "6.2.0",
|
|
5
5
|
"description": "",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"main": "lib/index.js",
|
|
12
12
|
"module": "src/index.js",
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@pie-lib/controller-utils": "^0.19.
|
|
14
|
+
"@pie-lib/controller-utils": "^0.19.4",
|
|
15
15
|
"debug": "^4.1.1",
|
|
16
16
|
"humps": "^2.0.1",
|
|
17
17
|
"lodash": "^4.17.15"
|
package/controller/src/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { partialScoring } from '@pie-lib/controller-utils';
|
|
|
4
4
|
import { cloneDeep, isEmpty, shuffle } from 'lodash';
|
|
5
5
|
|
|
6
6
|
import defaults from './defaults';
|
|
7
|
-
import { getAllUniqueCorrectness } from './utils';
|
|
7
|
+
import { getAllUniqueCorrectness, getCompleteResponseDetails } from './utils';
|
|
8
8
|
|
|
9
9
|
const log = debug('pie-elements:image-cloze-association:controller');
|
|
10
10
|
|
|
@@ -17,12 +17,18 @@ export const model = (question, session, env) => {
|
|
|
17
17
|
return new Promise((resolve) => {
|
|
18
18
|
const shouldIncludeCorrectResponse = env.mode === 'evaluate';
|
|
19
19
|
|
|
20
|
+
const { responseAreasToBeFilled, possibleResponses: completeResponses } = getCompleteResponseDetails(
|
|
21
|
+
questionCamelized.validation,
|
|
22
|
+
);
|
|
23
|
+
|
|
20
24
|
const out = {
|
|
21
25
|
disabled: env.mode !== 'gather',
|
|
22
26
|
mode: env.mode,
|
|
23
27
|
...questionCamelized,
|
|
24
28
|
responseCorrect: shouldIncludeCorrectResponse ? getScore(questionCamelized, session) === 1 : undefined,
|
|
25
29
|
validation: shouldIncludeCorrectResponse ? questionCamelized.validation : undefined,
|
|
30
|
+
responseAreasToBeFilled,
|
|
31
|
+
completeResponses,
|
|
26
32
|
};
|
|
27
33
|
|
|
28
34
|
if (questionNormalized.shuffle) {
|
package/controller/src/utils.js
CHANGED
|
@@ -41,3 +41,27 @@ export const getAllUniqueCorrectness = (answers, validResponses) => {
|
|
|
41
41
|
});
|
|
42
42
|
return allCorrectness;
|
|
43
43
|
};
|
|
44
|
+
|
|
45
|
+
// calculate the minimum number of populated response areas (categories) in the correct answer or alternates
|
|
46
|
+
// and create an array with the possible responses ids
|
|
47
|
+
export const getCompleteResponseDetails = (validation) => {
|
|
48
|
+
const extractImages = (response) => (response?.value || []).map((container) => container.images);
|
|
49
|
+
const countFilledResponseAreas = (container) => (container || []).filter((images) => images.length).length;
|
|
50
|
+
|
|
51
|
+
const { validResponse, altResponses } = validation || {};
|
|
52
|
+
const imagesPerContainer = extractImages(validResponse);
|
|
53
|
+
const possibleResponses = [imagesPerContainer.flat()];
|
|
54
|
+
let responseAreasToBeFilled = countFilledResponseAreas(imagesPerContainer);
|
|
55
|
+
|
|
56
|
+
(altResponses || []).forEach((altResponse) => {
|
|
57
|
+
const altImagesPerContainer = extractImages(altResponse);
|
|
58
|
+
const filledResponseAreas = countFilledResponseAreas(altImagesPerContainer);
|
|
59
|
+
possibleResponses.push(altImagesPerContainer.flat());
|
|
60
|
+
|
|
61
|
+
if (filledResponseAreas < responseAreasToBeFilled) {
|
|
62
|
+
responseAreasToBeFilled = filledResponseAreas;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return { responseAreasToBeFilled, possibleResponses };
|
|
67
|
+
};
|
package/lib/index.js
CHANGED
|
@@ -7,6 +7,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
});
|
|
8
8
|
exports["default"] = void 0;
|
|
9
9
|
|
|
10
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
11
|
+
|
|
10
12
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
11
13
|
|
|
12
14
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
@@ -58,7 +60,11 @@ var ImageClozeAssociation = /*#__PURE__*/function (_HTMLElement) {
|
|
|
58
60
|
value: function isComplete() {
|
|
59
61
|
var _ref = this._model || {},
|
|
60
62
|
autoplayAudioEnabled = _ref.autoplayAudioEnabled,
|
|
61
|
-
completeAudioEnabled = _ref.completeAudioEnabled
|
|
63
|
+
completeAudioEnabled = _ref.completeAudioEnabled,
|
|
64
|
+
completeResponses = _ref.completeResponses,
|
|
65
|
+
duplicateResponses = _ref.duplicateResponses,
|
|
66
|
+
maxResponsePerZone = _ref.maxResponsePerZone,
|
|
67
|
+
responseAreasToBeFilled = _ref.responseAreasToBeFilled;
|
|
62
68
|
|
|
63
69
|
var elementContext = this; // check audio completion if audio settings are enabled and audio actually exists
|
|
64
70
|
|
|
@@ -77,11 +83,46 @@ var ImageClozeAssociation = /*#__PURE__*/function (_HTMLElement) {
|
|
|
77
83
|
return false;
|
|
78
84
|
}
|
|
79
85
|
|
|
80
|
-
|
|
86
|
+
var answers = this._session.answers;
|
|
87
|
+
|
|
88
|
+
if (!Array.isArray(answers)) {
|
|
81
89
|
return false;
|
|
90
|
+
} // filter answers by containerIndex and count the ones with content
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
var filledResponseAreas = (0, _toConsumableArray2["default"])(new Map(answers.map(function (item) {
|
|
94
|
+
return [item.containerIndex, item];
|
|
95
|
+
})).values()).length; // check if an answer choice was added to at least as many response areas
|
|
96
|
+
// as the number of populated response areas in the correct answer
|
|
97
|
+
|
|
98
|
+
var areResponseAreasFilled = filledResponseAreas >= responseAreasToBeFilled;
|
|
99
|
+
|
|
100
|
+
if (maxResponsePerZone > 1) {
|
|
101
|
+
if (duplicateResponses) {
|
|
102
|
+
// an answer choice can be used multiple times
|
|
103
|
+
return areResponseAreasFilled;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
var allAnswersValue = answers.map(function (answer) {
|
|
107
|
+
return answer.value;
|
|
108
|
+
}); // check if any correct answer have any unplaced answer choices
|
|
109
|
+
|
|
110
|
+
var requiredAnswersPlaced = completeResponses.some(function (response) {
|
|
111
|
+
return response.every(function (val) {
|
|
112
|
+
return allAnswersValue.includes(val);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
if (!requiredAnswersPlaced) {
|
|
117
|
+
// correct answer have unplaced answer choices
|
|
118
|
+
return areResponseAreasFilled;
|
|
119
|
+
} // all choices (required for a correct response) were placed into a response area
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
return requiredAnswersPlaced;
|
|
82
123
|
}
|
|
83
124
|
|
|
84
|
-
return
|
|
125
|
+
return areResponseAreasFilled;
|
|
85
126
|
}
|
|
86
127
|
}, {
|
|
87
128
|
key: "session",
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.js"],"names":["ImageClozeAssociation","m","_model","dispatchEvent","ModelSetEvent","tagName","toLowerCase","isComplete","_render","autoplayAudioEnabled","completeAudioEnabled","elementContext","audioComplete","audio","querySelector","isInsidePrompt","closest","_session","answers","Array","isArray","length","s","data","selector","SessionChangedEvent","info","document","createElement","id","Object","assign","style","position","top","width","height","display","justifyContent","alignItems","background","zIndex","cursor","img","src","EnableAudioAutoplayImage","alt","appendChild","observer","MutationObserver","mutationsList","forEach","mutation","type","_createAudioInfoToast","container","enableAudio","play","removeChild","removeEventListener","setTimeout","paused","addEventListener","handlePlaying","handleEnded","_audio","_handlePlaying","_handleEnded","_enableAudio","disconnect","observe","childList","subtree","el","React","ImageClozeAssociationComponent","model","session","updateAnswer","bind","ReactDOM","render","HTMLElement"],"mappings":"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","sourcesContent":["import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { renderMath } from '@pie-lib/math-rendering';\nimport { EnableAudioAutoplayImage } from '@pie-lib/render-ui';\nimport { ModelSetEvent, SessionChangedEvent } from '@pie-framework/pie-player-events';\n\nimport ImageClozeAssociationComponent from './root';\n\nexport default class ImageClozeAssociation extends HTMLElement {\n set model(m) {\n this._model = m;\n\n this.dispatchEvent(new ModelSetEvent(this.tagName.toLowerCase(), this.isComplete(), !!this._model));\n this._render();\n }\n\n isComplete() {\n const { autoplayAudioEnabled, completeAudioEnabled } = this._model || {};\n const elementContext = this;\n\n // check audio completion if audio settings are enabled and audio actually exists\n if (autoplayAudioEnabled && completeAudioEnabled && !this.audioComplete) {\n if (elementContext) {\n const audio = elementContext.querySelector('audio');\n const isInsidePrompt = audio && audio.closest('#preview-prompt');\n\n // only require audio completion if audio exists and is inside the prompt\n if (audio && isInsidePrompt) {\n return false;\n }\n }\n }\n\n if (!this._session || !this._session.answers) {\n return false;\n }\n\n if (!Array.isArray(this._session.answers)) {\n return false;\n }\n\n return Array.isArray(this._session.answers) && this._session.answers.length > 0;\n }\n\n set session(s) {\n if (s && !s.answers) {\n s.answers = [];\n }\n\n this._session = s;\n this._render();\n }\n\n get session() {\n return this._session;\n }\n\n updateAnswer(data) {\n this._session.answers = data;\n this._session.selector = 'Mouse';\n\n this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), this.isComplete()));\n\n this._render();\n }\n\n _createAudioInfoToast() {\n const info = document.createElement('div');\n info.id = 'play-audio-info';\n\n Object.assign(info.style, {\n position: 'absolute',\n top: 0,\n width: '100%',\n height: '100%',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n background: 'white',\n zIndex: '1000',\n cursor: 'pointer',\n });\n\n const img = document.createElement('img');\n img.src = EnableAudioAutoplayImage;\n img.alt = 'Click anywhere to enable audio autoplay';\n img.width = 500;\n img.height = 300;\n\n info.appendChild(img);\n return info;\n }\n\n connectedCallback() {\n this._render();\n\n // Observation: audio in Chrome will have the autoplay attribute,\n // while other browsers will not have the autoplay attribute and will need a user interaction to play the audio\n // This workaround fixes the issue of audio being cached and played on any user interaction in Safari and Firefox\n const observer = new MutationObserver((mutationsList, observer) => {\n mutationsList.forEach((mutation) => {\n if (mutation.type === 'childList') {\n const audio = this.querySelector('audio');\n const isInsidePrompt = audio && audio.closest('#preview-prompt');\n\n if (!this._model) return;\n if (!this._model.autoplayAudioEnabled) return;\n if (audio && !isInsidePrompt) return;\n if (!audio) return;\n\n const info = this._createAudioInfoToast();\n const container = this.querySelector('#main-container');\n const enableAudio = () => {\n if (this.querySelector('#play-audio-info')) {\n audio.play();\n container.removeChild(info);\n }\n\n document.removeEventListener('click', enableAudio);\n };\n\n // if the audio is paused, it means the user has not interacted with the page yet and the audio will not play\n // FIX FOR SAFARI: play with a slight delay to check if autoplay was blocked\n setTimeout(() => {\n if (audio.paused && !this.querySelector('#play-audio-info')) {\n // add info message as a toast to enable audio playback\n container.appendChild(info);\n document.addEventListener('click', enableAudio);\n } else {\n document.removeEventListener('click', enableAudio);\n }\n }, 500);\n\n // we need to listen for the playing event to remove the toast in case the audio plays because of re-rendering\n const handlePlaying = () => {\n const info = this.querySelector('#play-audio-info');\n\n if (info) {\n container.removeChild(info);\n }\n\n audio.removeEventListener('playing', handlePlaying);\n };\n\n audio.addEventListener('playing', handlePlaying);\n\n // we need to listen for the ended event to update the isComplete state\n const handleEnded = () => {\n this.audioComplete = true;\n this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), this.isComplete()));\n\n audio.removeEventListener('ended', handleEnded);\n };\n\n audio.addEventListener('ended', handleEnded);\n\n // store references to remove later\n this._audio = audio;\n this._handlePlaying = handlePlaying;\n this._handleEnded = handleEnded;\n this._enableAudio = enableAudio;\n\n observer.disconnect();\n }\n });\n });\n\n observer.observe(this, { childList: true, subtree: true });\n }\n\n disconnectedCallback() {\n document.removeEventListener('click', this._enableAudio);\n\n if (this._audio) {\n this._audio.removeEventListener('playing', this._handlePlaying);\n this._audio.removeEventListener('ended', this._handleEnded);\n this._audio = null;\n }\n }\n\n _render() {\n if (this._model && this._session) {\n const el = React.createElement(ImageClozeAssociationComponent, {\n model: this._model,\n session: this._session,\n updateAnswer: this.updateAnswer.bind(this),\n });\n\n ReactDOM.render(el, this, () => {\n renderMath(this);\n });\n }\n }\n}\n"],"file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../src/index.js"],"names":["ImageClozeAssociation","m","_model","dispatchEvent","ModelSetEvent","tagName","toLowerCase","isComplete","_render","autoplayAudioEnabled","completeAudioEnabled","completeResponses","duplicateResponses","maxResponsePerZone","responseAreasToBeFilled","elementContext","audioComplete","audio","querySelector","isInsidePrompt","closest","_session","answers","Array","isArray","filledResponseAreas","Map","map","item","containerIndex","values","length","areResponseAreasFilled","allAnswersValue","answer","value","requiredAnswersPlaced","some","response","every","val","includes","s","data","selector","SessionChangedEvent","info","document","createElement","id","Object","assign","style","position","top","width","height","display","justifyContent","alignItems","background","zIndex","cursor","img","src","EnableAudioAutoplayImage","alt","appendChild","observer","MutationObserver","mutationsList","forEach","mutation","type","_createAudioInfoToast","container","enableAudio","play","removeChild","removeEventListener","setTimeout","paused","addEventListener","handlePlaying","handleEnded","_audio","_handlePlaying","_handleEnded","_enableAudio","disconnect","observe","childList","subtree","el","React","ImageClozeAssociationComponent","model","session","updateAnswer","bind","ReactDOM","render","HTMLElement"],"mappings":"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","sourcesContent":["import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { renderMath } from '@pie-lib/math-rendering';\nimport { EnableAudioAutoplayImage } from '@pie-lib/render-ui';\nimport { ModelSetEvent, SessionChangedEvent } from '@pie-framework/pie-player-events';\n\nimport ImageClozeAssociationComponent from './root';\n\nexport default class ImageClozeAssociation extends HTMLElement {\n set model(m) {\n this._model = m;\n\n this.dispatchEvent(new ModelSetEvent(this.tagName.toLowerCase(), this.isComplete(), !!this._model));\n this._render();\n }\n\n isComplete() {\n const {\n autoplayAudioEnabled,\n completeAudioEnabled,\n completeResponses,\n duplicateResponses,\n maxResponsePerZone,\n responseAreasToBeFilled,\n } = this._model || {};\n const elementContext = this;\n\n // check audio completion if audio settings are enabled and audio actually exists\n if (autoplayAudioEnabled && completeAudioEnabled && !this.audioComplete) {\n if (elementContext) {\n const audio = elementContext.querySelector('audio');\n const isInsidePrompt = audio && audio.closest('#preview-prompt');\n\n // only require audio completion if audio exists and is inside the prompt\n if (audio && isInsidePrompt) {\n return false;\n }\n }\n }\n\n if (!this._session || !this._session.answers) {\n return false;\n }\n\n const { answers } = this._session;\n\n if (!Array.isArray(answers)) {\n return false;\n }\n\n // filter answers by containerIndex and count the ones with content\n const filledResponseAreas = [...new Map(answers.map((item) => [item.containerIndex, item])).values()].length;\n // check if an answer choice was added to at least as many response areas\n // as the number of populated response areas in the correct answer\n const areResponseAreasFilled = filledResponseAreas >= responseAreasToBeFilled;\n\n if (maxResponsePerZone > 1) {\n if (duplicateResponses) {\n // an answer choice can be used multiple times\n return areResponseAreasFilled;\n }\n\n const allAnswersValue = answers.map((answer) => answer.value);\n\n // check if any correct answer have any unplaced answer choices\n const requiredAnswersPlaced = completeResponses.some((response) =>\n response.every((val) => allAnswersValue.includes(val)),\n );\n\n if (!requiredAnswersPlaced) {\n // correct answer have unplaced answer choices\n return areResponseAreasFilled;\n }\n\n // all choices (required for a correct response) were placed into a response area\n return requiredAnswersPlaced;\n }\n\n return areResponseAreasFilled;\n }\n\n set session(s) {\n if (s && !s.answers) {\n s.answers = [];\n }\n\n this._session = s;\n this._render();\n }\n\n get session() {\n return this._session;\n }\n\n updateAnswer(data) {\n this._session.answers = data;\n this._session.selector = 'Mouse';\n\n this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), this.isComplete()));\n\n this._render();\n }\n\n _createAudioInfoToast() {\n const info = document.createElement('div');\n info.id = 'play-audio-info';\n\n Object.assign(info.style, {\n position: 'absolute',\n top: 0,\n width: '100%',\n height: '100%',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n background: 'white',\n zIndex: '1000',\n cursor: 'pointer',\n });\n\n const img = document.createElement('img');\n img.src = EnableAudioAutoplayImage;\n img.alt = 'Click anywhere to enable audio autoplay';\n img.width = 500;\n img.height = 300;\n\n info.appendChild(img);\n return info;\n }\n\n connectedCallback() {\n this._render();\n\n // Observation: audio in Chrome will have the autoplay attribute,\n // while other browsers will not have the autoplay attribute and will need a user interaction to play the audio\n // This workaround fixes the issue of audio being cached and played on any user interaction in Safari and Firefox\n const observer = new MutationObserver((mutationsList, observer) => {\n mutationsList.forEach((mutation) => {\n if (mutation.type === 'childList') {\n const audio = this.querySelector('audio');\n const isInsidePrompt = audio && audio.closest('#preview-prompt');\n\n if (!this._model) return;\n if (!this._model.autoplayAudioEnabled) return;\n if (audio && !isInsidePrompt) return;\n if (!audio) return;\n\n const info = this._createAudioInfoToast();\n const container = this.querySelector('#main-container');\n const enableAudio = () => {\n if (this.querySelector('#play-audio-info')) {\n audio.play();\n container.removeChild(info);\n }\n\n document.removeEventListener('click', enableAudio);\n };\n\n // if the audio is paused, it means the user has not interacted with the page yet and the audio will not play\n // FIX FOR SAFARI: play with a slight delay to check if autoplay was blocked\n setTimeout(() => {\n if (audio.paused && !this.querySelector('#play-audio-info')) {\n // add info message as a toast to enable audio playback\n container.appendChild(info);\n document.addEventListener('click', enableAudio);\n } else {\n document.removeEventListener('click', enableAudio);\n }\n }, 500);\n\n // we need to listen for the playing event to remove the toast in case the audio plays because of re-rendering\n const handlePlaying = () => {\n const info = this.querySelector('#play-audio-info');\n\n if (info) {\n container.removeChild(info);\n }\n\n audio.removeEventListener('playing', handlePlaying);\n };\n\n audio.addEventListener('playing', handlePlaying);\n\n // we need to listen for the ended event to update the isComplete state\n const handleEnded = () => {\n this.audioComplete = true;\n this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), this.isComplete()));\n\n audio.removeEventListener('ended', handleEnded);\n };\n\n audio.addEventListener('ended', handleEnded);\n\n // store references to remove later\n this._audio = audio;\n this._handlePlaying = handlePlaying;\n this._handleEnded = handleEnded;\n this._enableAudio = enableAudio;\n\n observer.disconnect();\n }\n });\n });\n\n observer.observe(this, { childList: true, subtree: true });\n }\n\n disconnectedCallback() {\n document.removeEventListener('click', this._enableAudio);\n\n if (this._audio) {\n this._audio.removeEventListener('playing', this._handlePlaying);\n this._audio.removeEventListener('ended', this._handleEnded);\n this._audio = null;\n }\n }\n\n _render() {\n if (this._model && this._session) {\n const el = React.createElement(ImageClozeAssociationComponent, {\n model: this._model,\n session: this._session,\n updateAnswer: this.updateAnswer.bind(this),\n });\n\n ReactDOM.render(el, this, () => {\n renderMath(this);\n });\n }\n }\n}\n"],"file":"index.js"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pie-element/image-cloze-association",
|
|
3
|
-
"version": "8.0
|
|
3
|
+
"version": "8.2.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": "pie-framework/pie-elements",
|
|
6
6
|
"publishConfig": {
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
"@material-ui/core": "^3.9.3",
|
|
11
11
|
"@material-ui/icons": "^3.0.1",
|
|
12
12
|
"@pie-framework/pie-player-events": "^0.1.0",
|
|
13
|
-
"@pie-lib/correct-answer-toggle": "^2.
|
|
14
|
-
"@pie-lib/drag": "^2.
|
|
15
|
-
"@pie-lib/math-rendering": "^3.19.
|
|
16
|
-
"@pie-lib/render-ui": "^4.
|
|
17
|
-
"@pie-lib/translator": "^2.20.
|
|
13
|
+
"@pie-lib/correct-answer-toggle": "^2.21.1",
|
|
14
|
+
"@pie-lib/drag": "^2.18.1",
|
|
15
|
+
"@pie-lib/math-rendering": "^3.19.4",
|
|
16
|
+
"@pie-lib/render-ui": "^4.31.1",
|
|
17
|
+
"@pie-lib/translator": "^2.20.4",
|
|
18
18
|
"classnames": "^2.2.6",
|
|
19
19
|
"humps": "^2.0.1",
|
|
20
20
|
"prop-types": "^15.6.1",
|
|
@@ -23,27 +23,10 @@
|
|
|
23
23
|
},
|
|
24
24
|
"author": "pie framework developers",
|
|
25
25
|
"license": "ISC",
|
|
26
|
-
"gitHead": "
|
|
26
|
+
"gitHead": "edd2d8fc80a70863b9a71dab5fc2caed85175533",
|
|
27
27
|
"scripts": {
|
|
28
28
|
"postpublish": "../../scripts/postpublish"
|
|
29
29
|
},
|
|
30
30
|
"main": "lib/index.js",
|
|
31
|
-
"module": "src/index.js"
|
|
32
|
-
"exports": {
|
|
33
|
-
".": {
|
|
34
|
-
"import": "./esm/element.js",
|
|
35
|
-
"require": "./lib/index.js",
|
|
36
|
-
"default": "./esm/element.js"
|
|
37
|
-
},
|
|
38
|
-
"./configure": {
|
|
39
|
-
"import": "./esm/configure.js",
|
|
40
|
-
"require": "./configure/lib/index.js",
|
|
41
|
-
"default": "./esm/configure.js"
|
|
42
|
-
},
|
|
43
|
-
"./controller": {
|
|
44
|
-
"import": "./esm/controller.js",
|
|
45
|
-
"require": "./controller/lib/index.js",
|
|
46
|
-
"default": "./esm/controller.js"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
31
|
+
"module": "src/index.js"
|
|
49
32
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
2
3
|
import { shallow } from 'enzyme';
|
|
3
4
|
import { ModelSetEvent, SessionChangedEvent } from '@pie-framework/pie-player-events';
|
|
4
5
|
import ImageClozeAssociation from '../index';
|
|
5
6
|
import { ImageClozeAssociationComponent } from '../root';
|
|
6
7
|
|
|
7
8
|
jest.mock('@pie-lib/math-rendering', () => ({ renderMath: jest.fn() }));
|
|
9
|
+
jest.spyOn(ReactDOM, 'render').mockImplementation(() => {});
|
|
8
10
|
|
|
9
11
|
describe('image-cloze-association', () => {
|
|
10
12
|
describe('renders', () => {
|
|
@@ -48,6 +50,9 @@ describe('image-cloze-association', () => {
|
|
|
48
50
|
it('dispatches session changed event - add answer', () => {
|
|
49
51
|
const el = new ImageClozeAssociation();
|
|
50
52
|
el.tagName = 'ica-el';
|
|
53
|
+
el.model = {
|
|
54
|
+
responseAreasToBeFilled: 1,
|
|
55
|
+
};
|
|
51
56
|
el.session = { answers: [] };
|
|
52
57
|
el.updateAnswer([{ id: '1', containerIndex: 0, value: '' }]);
|
|
53
58
|
expect(el.dispatchEvent).toBeCalledWith(new SessionChangedEvent('ica-el', true));
|
|
@@ -56,6 +61,9 @@ describe('image-cloze-association', () => {
|
|
|
56
61
|
it('dispatches session changed event - remove answer', () => {
|
|
57
62
|
const el = new ImageClozeAssociation();
|
|
58
63
|
el.tagName = 'ica-el';
|
|
64
|
+
el.model = {
|
|
65
|
+
responseAreasToBeFilled: 1,
|
|
66
|
+
};
|
|
59
67
|
el.session = { answers: [{ id: '1', containerIndex: 0, value: '' }] };
|
|
60
68
|
el.updateAnswer([]);
|
|
61
69
|
expect(el.dispatchEvent).toBeCalledWith(new SessionChangedEvent('ica-el', false));
|
|
@@ -64,7 +72,14 @@ describe('image-cloze-association', () => {
|
|
|
64
72
|
it('dispatches session changed event - add/remove answer', () => {
|
|
65
73
|
const el = new ImageClozeAssociation();
|
|
66
74
|
el.tagName = 'ica-el';
|
|
67
|
-
el.
|
|
75
|
+
el.model = {
|
|
76
|
+
responseAreasToBeFilled: 2,
|
|
77
|
+
};
|
|
78
|
+
el.session = { answers: [] };
|
|
79
|
+
el.updateAnswer([{ id: '1', containerIndex: 0, value: '' }]);
|
|
80
|
+
expect(el.dispatchEvent).toBeCalledWith(new SessionChangedEvent('ica-el', false));
|
|
81
|
+
|
|
82
|
+
|
|
68
83
|
el.updateAnswer([
|
|
69
84
|
{ id: '1', containerIndex: 0, value: '' },
|
|
70
85
|
{ id: '2', containerIndex: 1, value: '' },
|
|
@@ -72,7 +87,7 @@ describe('image-cloze-association', () => {
|
|
|
72
87
|
expect(el.dispatchEvent).toBeCalledWith(new SessionChangedEvent('ica-el', true));
|
|
73
88
|
|
|
74
89
|
el.updateAnswer([{ id: '2', containerIndex: 1, value: '' }]);
|
|
75
|
-
expect(el.dispatchEvent).toBeCalledWith(new SessionChangedEvent('ica-el',
|
|
90
|
+
expect(el.dispatchEvent).toBeCalledWith(new SessionChangedEvent('ica-el', false));
|
|
76
91
|
|
|
77
92
|
el.updateAnswer([]);
|
|
78
93
|
expect(el.dispatchEvent).toBeCalledWith(new SessionChangedEvent('ica-el', false));
|