@pie-element/ebsr 0.1.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/dist/author/defaults.d.ts +67 -0
- package/dist/author/defaults.d.ts.map +1 -0
- package/dist/author/defaults.js +161 -0
- package/dist/author/index.d.ts +35 -0
- package/dist/author/index.d.ts.map +1 -0
- package/dist/author/index.js +78 -0
- package/dist/author/main.d.ts +23 -0
- package/dist/author/main.d.ts.map +1 -0
- package/dist/author/main.js +121 -0
- package/dist/controller/defaults.d.ts +16 -0
- package/dist/controller/defaults.d.ts.map +1 -0
- package/dist/controller/defaults.js +26 -0
- package/dist/controller/index.d.ts +43 -0
- package/dist/controller/index.d.ts.map +1 -0
- package/dist/controller/index.js +186 -0
- package/dist/controller/utils.d.ts +11 -0
- package/dist/controller/utils.d.ts.map +1 -0
- package/dist/controller/utils.js +8 -0
- package/dist/delivery/index.d.ts +25 -0
- package/dist/delivery/index.d.ts.map +1 -0
- package/dist/delivery/index.js +95 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.iife.d.ts +9 -0
- package/dist/index.iife.d.ts.map +1 -0
- package/dist/index.iife.js +165 -0
- package/dist/index.js +2 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_DataView.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_Hash.js +16 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_ListCache.js +16 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_Map.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_MapCache.js +16 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_Promise.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_Set.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_SetCache.js +11 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_Stack.js +13 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_Symbol.js +5 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_Uint8Array.js +5 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_WeakMap.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_apply.js +12 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_arrayEach.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_arrayFilter.js +10 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_arrayLikeKeys.js +15 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_arrayMap.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_arrayPush.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_arraySome.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_assignValue.js +10 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_assocIndexOf.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseAssign.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseAssignIn.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseAssignValue.js +12 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseClone.js +57 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseCreate.js +14 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseGet.js +10 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseGetAllKeys.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseGetTag.js +10 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseIsArguments.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseIsEqual.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseIsEqualDeep.js +30 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseIsMap.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseIsNative.js +11 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseIsSet.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseIsTypedArray.js +11 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseKeys.js +12 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseKeysIn.js +13 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseRest.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseSetToString.js +14 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseTimes.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseToString.js +15 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_baseUnary.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_cacheHas.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_castPath.js +10 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_cloneArrayBuffer.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_cloneBuffer.js +10 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_cloneDataView.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_cloneRegExp.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_cloneSymbol.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_cloneTypedArray.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_copyArray.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_copyObject.js +14 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_copySymbols.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_copySymbolsIn.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_coreJsData.js +5 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_defineProperty.js +10 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_equalArrays.js +35 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_equalByTag.js +35 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_equalObjects.js +32 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_freeGlobal.js +4 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_getAllKeys.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_getAllKeysIn.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_getMapData.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_getNative.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_getPrototype.js +5 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_getRawTag.js +14 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_getSymbols.js +10 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_getSymbolsIn.js +11 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_getTag.js +23 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_getValue.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_hashClear.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_hashDelete.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_hashGet.js +13 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_hashHas.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_hashSet.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_initCloneArray.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_initCloneByTag.js +33 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_initCloneObject.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_isIndex.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_isIterateeCall.js +12 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_isKey.js +11 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_isKeyable.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_isMasked.js +11 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_isPrototype.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_listCacheClear.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_listCacheDelete.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_listCacheGet.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_listCacheHas.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_listCacheSet.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_mapCacheClear.js +13 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_mapCacheDelete.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_mapCacheGet.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_mapCacheHas.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_mapCacheSet.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_mapToArray.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_memoizeCapped.js +11 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_nativeCreate.js +5 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_nativeKeys.js +5 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_nativeKeysIn.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_nodeUtil.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_objectToString.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_overArg.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_overRest.js +13 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_root.js +5 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_setCacheAdd.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_setCacheHas.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_setToArray.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_setToString.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_shortOut.js +14 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_stackClear.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_stackDelete.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_stackGet.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_stackHas.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_stackSet.js +16 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_stringToPath.js +10 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_toKey.js +10 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/_toSource.js +15 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/cloneDeep.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/constant.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/defaults.js +16 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/eq.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/get.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/identity.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isArguments.js +10 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isArray.js +4 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isArrayLike.js +8 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isBuffer.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isEmpty.js +21 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isEqual.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isFunction.js +11 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isLength.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isMap.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isObject.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isObjectLike.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isSet.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isSymbol.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/isTypedArray.js +7 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/keys.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/keysIn.js +9 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/memoize.js +16 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/stubArray.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/stubFalse.js +6 -0
- package/dist/node_modules/.bun/lodash-es@4.17.23/node_modules/lodash-es/toString.js +7 -0
- package/dist/print/index.d.ts +25 -0
- package/dist/print/index.d.ts.map +1 -0
- package/dist/print/index.js +104 -0
- package/package.json +70 -0
- package/src/author/defaults.ts +183 -0
- package/src/author/index.ts +184 -0
- package/src/author/main.tsx +245 -0
- package/src/controller/defaults.ts +35 -0
- package/src/controller/index.ts +452 -0
- package/src/controller/utils.ts +28 -0
- package/src/delivery/index.tsx +167 -0
- package/src/index.iife.ts +16 -0
- package/src/index.ts +1 -0
- package/src/print/index.tsx +213 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* @synced-from pie-elements/packages/ebsr/controller/src/defaults.js
|
|
4
|
+
* @auto-generated
|
|
5
|
+
*
|
|
6
|
+
* This file is automatically synced from pie-elements and converted to TypeScript.
|
|
7
|
+
* Manual edits will be overwritten on next sync.
|
|
8
|
+
* To make changes, edit the upstream JavaScript file and run sync again.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const partModel = (base) => ({
|
|
12
|
+
choiceMode: 'radio',
|
|
13
|
+
choicePrefix: 'letters',
|
|
14
|
+
choices: [],
|
|
15
|
+
choicesLayout: 'vertical',
|
|
16
|
+
feedbackEnabled: false,
|
|
17
|
+
gridColumns: 2,
|
|
18
|
+
prompt: '',
|
|
19
|
+
promptEnabled: true,
|
|
20
|
+
rationale: '',
|
|
21
|
+
rationaleEnabled: true,
|
|
22
|
+
spellCheckEnabled: true,
|
|
23
|
+
studentInstructionsEnabled: true,
|
|
24
|
+
teacherInstructions: '',
|
|
25
|
+
teacherInstructionsEnabled: true,
|
|
26
|
+
toolbarEditorPosition: 'bottom',
|
|
27
|
+
...base,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export default {
|
|
31
|
+
partLabels: true,
|
|
32
|
+
partLabelType: 'Letters',
|
|
33
|
+
partA: partModel(),
|
|
34
|
+
partB: partModel(),
|
|
35
|
+
};
|
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* @synced-from pie-elements/packages/ebsr/controller/src/index.js
|
|
4
|
+
* @auto-generated
|
|
5
|
+
*
|
|
6
|
+
* This file is automatically synced from pie-elements and converted to TypeScript.
|
|
7
|
+
* Manual edits will be overwritten on next sync.
|
|
8
|
+
* To make changes, edit the upstream JavaScript file and run sync again.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import defaults from './defaults.js';
|
|
12
|
+
import { lockChoices, getShuffledChoices, partialScoring } from '@pie-element/shared-controller-utils';
|
|
13
|
+
import { isResponseCorrect } from './utils.js';
|
|
14
|
+
import { get, isEmpty } from 'lodash-es';
|
|
15
|
+
import Translator from '@pie-lib/translator';
|
|
16
|
+
|
|
17
|
+
const { translator } = Translator;
|
|
18
|
+
|
|
19
|
+
const prepareChoice = (model, env, defaultFeedback) => (choice) => {
|
|
20
|
+
const out = {
|
|
21
|
+
label: choice.label,
|
|
22
|
+
value: choice.value,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {
|
|
26
|
+
out.rationale = model.rationaleEnabled ? choice.rationale : null;
|
|
27
|
+
} else {
|
|
28
|
+
out.rationale = null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (env.mode === 'evaluate') {
|
|
32
|
+
out.correct = !!choice.correct;
|
|
33
|
+
|
|
34
|
+
if (model.feedbackEnabled) {
|
|
35
|
+
const feedbackType = (choice.feedback && choice.feedback.type) || 'none';
|
|
36
|
+
|
|
37
|
+
if (feedbackType === 'default') {
|
|
38
|
+
out.feedback = defaultFeedback[choice.correct ? 'correct' : 'incorrect'];
|
|
39
|
+
} else if (feedbackType === 'custom') {
|
|
40
|
+
out.feedback = choice.feedback.value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return out;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const parsePart = (part, key, session, env) => {
|
|
49
|
+
const defaultFeedback = Object.assign({ correct: 'Correct', incorrect: 'Incorrect' }, part.defaultFeedback);
|
|
50
|
+
|
|
51
|
+
let choices = part.choices ? part.choices.map(prepareChoice(part, env, defaultFeedback)) : [];
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
...part,
|
|
55
|
+
choices,
|
|
56
|
+
disabled: env.mode !== 'gather',
|
|
57
|
+
complete: {
|
|
58
|
+
min: part.choices.filter((c) => c.correct).length,
|
|
59
|
+
},
|
|
60
|
+
responseCorrect: env.mode === 'evaluate' ? isResponseCorrect(part, key, session) : undefined,
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const normalizePart = (model, base) => ({
|
|
65
|
+
...base,
|
|
66
|
+
...model,
|
|
67
|
+
choicesLayout: model.choicesLayout || (model.verticalMode === false && 'horizontal') || 'vertical',
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export const normalize = ({ partA = {}, partB = {}, language, ...question }) => ({
|
|
71
|
+
...defaults,
|
|
72
|
+
...question,
|
|
73
|
+
partA: normalizePart(partA, { ...defaults.partA, language }),
|
|
74
|
+
partB: normalizePart(partB, { ...defaults.partB, language }),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
*
|
|
79
|
+
* @param {*} question
|
|
80
|
+
* @param {*} session
|
|
81
|
+
* @param {*} env
|
|
82
|
+
* @param {*} updateSession - optional - a function that will set the properties passed into it on the session.
|
|
83
|
+
*/
|
|
84
|
+
export async function model(question, session, env, updateSession) {
|
|
85
|
+
const normalizedQuestion = normalize(question);
|
|
86
|
+
const partA = parsePart(normalizedQuestion.partA, 'partA', session, env);
|
|
87
|
+
const partB = parsePart(normalizedQuestion.partB, 'partB', session, env);
|
|
88
|
+
|
|
89
|
+
const shuffledValues = {};
|
|
90
|
+
|
|
91
|
+
const us = (part) => (id, element, update) =>
|
|
92
|
+
new Promise((resolve) => {
|
|
93
|
+
shuffledValues[part] = update.shuffledValues;
|
|
94
|
+
resolve();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const partASession = get(session, 'value.partA');
|
|
98
|
+
const partALockChoiceOrder = lockChoices(normalizedQuestion.partA, partASession, env);
|
|
99
|
+
|
|
100
|
+
const { choices: partAChoices } = partA || {};
|
|
101
|
+
const { choices: partBChoices } = partB || {};
|
|
102
|
+
|
|
103
|
+
if (!partALockChoiceOrder && partAChoices && partAChoices.length) {
|
|
104
|
+
partA.choices = await getShuffledChoices(
|
|
105
|
+
partAChoices,
|
|
106
|
+
{ shuffledValues: (session.shuffledValues || {}).partA },
|
|
107
|
+
us('partA'),
|
|
108
|
+
'value',
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const partBSession = get(session, 'value.partB');
|
|
113
|
+
const partBLockChoiceOrder = lockChoices(normalizedQuestion.partB, partBSession, env);
|
|
114
|
+
|
|
115
|
+
if (!partBLockChoiceOrder && partBChoices && partBChoices.length) {
|
|
116
|
+
partB.choices = await getShuffledChoices(
|
|
117
|
+
partBChoices,
|
|
118
|
+
{ shuffledValues: (session.shuffledValues || {}).partB },
|
|
119
|
+
us('partB'),
|
|
120
|
+
'value',
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!isEmpty(shuffledValues)) {
|
|
125
|
+
if (updateSession && typeof updateSession === 'function') {
|
|
126
|
+
updateSession(session.id, session.element, {
|
|
127
|
+
shuffledValues,
|
|
128
|
+
}).catch((e) => {
|
|
129
|
+
// eslint-disable-next-line no-console
|
|
130
|
+
console.error('update session failed', e);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (normalizedQuestion.partLabels) {
|
|
136
|
+
const language = normalizedQuestion.language;
|
|
137
|
+
partA.partLabel = translator.t('ebsr.part', {
|
|
138
|
+
lng: language,
|
|
139
|
+
index: normalizedQuestion.partLabelType === 'Letters' ? 'A' : '1',
|
|
140
|
+
});
|
|
141
|
+
partB.partLabel = translator.t('ebsr.part', {
|
|
142
|
+
lng: language,
|
|
143
|
+
index: normalizedQuestion.partLabelType === 'Letters' ? 'B' : '2',
|
|
144
|
+
});
|
|
145
|
+
} else {
|
|
146
|
+
partA.partLabel = undefined;
|
|
147
|
+
partB.partLabel = undefined;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {
|
|
151
|
+
partA.teacherInstructions = normalizedQuestion.partA.teacherInstructionsEnabled
|
|
152
|
+
? normalizedQuestion.partA.teacherInstructions
|
|
153
|
+
: null;
|
|
154
|
+
partB.teacherInstructions = normalizedQuestion.partB.teacherInstructionsEnabled
|
|
155
|
+
? normalizedQuestion.partB.teacherInstructions
|
|
156
|
+
: null;
|
|
157
|
+
} else {
|
|
158
|
+
partA.teacherInstructions = null;
|
|
159
|
+
partB.teacherInstructions = null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
partA.prompt = normalizedQuestion.partA.promptEnabled ? normalizedQuestion.partA.prompt : null;
|
|
163
|
+
partB.prompt = normalizedQuestion.partB.promptEnabled ? normalizedQuestion.partB.prompt : null;
|
|
164
|
+
|
|
165
|
+
return new Promise((resolve) => {
|
|
166
|
+
resolve({
|
|
167
|
+
disabled: env.mode !== 'gather',
|
|
168
|
+
mode: env.mode,
|
|
169
|
+
extraCSSRules: normalizedQuestion.extraCSSRules,
|
|
170
|
+
partA,
|
|
171
|
+
partB,
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export const createDefaultModel = (model = {}) =>
|
|
177
|
+
new Promise((resolve) => {
|
|
178
|
+
resolve({
|
|
179
|
+
...defaults,
|
|
180
|
+
...model,
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const isCorrect = (c) => c.correct === true;
|
|
185
|
+
|
|
186
|
+
const getScore = (config, sessionPart, key, partialScoringEnabled) => {
|
|
187
|
+
const { choices = [] } = (config && config[key]) || {};
|
|
188
|
+
const maxScore = choices.length;
|
|
189
|
+
const { value: sessionPartValue } = sessionPart || {};
|
|
190
|
+
|
|
191
|
+
const chosen = (c) => !!(sessionPartValue || []).find((v) => v === c.value);
|
|
192
|
+
const correctAndNotChosen = (c) => isCorrect(c) && !chosen(c);
|
|
193
|
+
const incorrectAndChosen = (c) => !isCorrect(c) && chosen(c);
|
|
194
|
+
const correctChoices = choices.reduce((total, choice) => {
|
|
195
|
+
if (correctAndNotChosen(choice) || incorrectAndChosen(choice)) {
|
|
196
|
+
return total - 1;
|
|
197
|
+
} else {
|
|
198
|
+
return total;
|
|
199
|
+
}
|
|
200
|
+
}, choices.length);
|
|
201
|
+
|
|
202
|
+
// determine score for a part
|
|
203
|
+
if (!partialScoringEnabled && correctChoices < maxScore) {
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return parseFloat(maxScore ? (correctChoices / maxScore).toFixed(2) : 0);
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Generates detailed trace log for math-templated scoring evaluation
|
|
212
|
+
* @param {Object} question
|
|
213
|
+
* @param {Object} session
|
|
214
|
+
* @param {Object} env
|
|
215
|
+
* @returns {Array<string>} traceLog
|
|
216
|
+
*/
|
|
217
|
+
export const getLogTrace = (question, session, env) => {
|
|
218
|
+
const traceLog = [];
|
|
219
|
+
|
|
220
|
+
if (!session || !session.value) {
|
|
221
|
+
traceLog.push('Student did not answer the question.');
|
|
222
|
+
return traceLog;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const { value } = session;
|
|
226
|
+
const { partA, partB } = value;
|
|
227
|
+
|
|
228
|
+
const partialScoringEnabled = partialScoring.enabled(question, env);
|
|
229
|
+
|
|
230
|
+
traceLog.push(
|
|
231
|
+
`Scoring method: ${partialScoringEnabled ? 'partial scoring' : 'all-or-nothing scoring'}.`
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
const partAquestionType =
|
|
235
|
+
question.partA.choiceMode === 'radio'
|
|
236
|
+
? 'multiple-choice (radio)'
|
|
237
|
+
: 'multiple-select (checkbox)';
|
|
238
|
+
traceLog.push(`Part A question type: ${partAquestionType}.`);
|
|
239
|
+
|
|
240
|
+
const partASelections = partA?.value || [];
|
|
241
|
+
const partACorrectChoices = (question.partA.choices || []).filter((c) => c.correct);
|
|
242
|
+
const partACorrectValues = partACorrectChoices.map((c) => c.value);
|
|
243
|
+
const partACorrectSelected = partASelections.filter((v) => partACorrectValues.includes(v));
|
|
244
|
+
const partAIncorrectSelected = partASelections.filter((v) => !partACorrectValues.includes(v));
|
|
245
|
+
|
|
246
|
+
if (partASelections.length) {
|
|
247
|
+
traceLog.push(
|
|
248
|
+
`Part A: student selected ${partASelections.length} choice(s) (${partACorrectSelected.length} correct, ${partAIncorrectSelected.length} incorrect).`
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const scoreA = getScore(question, partA, 'partA', partialScoringEnabled);
|
|
253
|
+
traceLog.push(`Part A score: ${scoreA}.`);
|
|
254
|
+
|
|
255
|
+
const partBquestionType =
|
|
256
|
+
question.partB.choiceMode === 'radio'
|
|
257
|
+
? 'multiple-choice (radio)'
|
|
258
|
+
: 'multiple-select (checkbox)';
|
|
259
|
+
traceLog.push(`Part B question type: ${partBquestionType}.`);
|
|
260
|
+
|
|
261
|
+
const partBSelections = partB?.value || [];
|
|
262
|
+
const partBCorrectChoices = (question.partB.choices || []).filter((c) => c.correct);
|
|
263
|
+
const partBCorrectValues = partBCorrectChoices.map((c) => c.value);
|
|
264
|
+
const correctSelected = partBSelections.filter((v) => partBCorrectValues.includes(v));
|
|
265
|
+
const incorrectSelected = partBSelections.filter((v) => !partBCorrectValues.includes(v));
|
|
266
|
+
|
|
267
|
+
if (partBSelections.length) {
|
|
268
|
+
traceLog.push(
|
|
269
|
+
`Part B: student selected ${partBSelections.length} choice(s) (${correctSelected.length} correct, ${incorrectSelected.length} incorrect).`
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const scoreB = getScore(question, partB, 'partB', partialScoringEnabled);
|
|
274
|
+
traceLog.push(`Part B score: ${scoreB}.`);
|
|
275
|
+
|
|
276
|
+
if (!partialScoringEnabled) {
|
|
277
|
+
traceLog.push(
|
|
278
|
+
'Final score is awarded only if both Part A and Part B are completely correct.'
|
|
279
|
+
);
|
|
280
|
+
traceLog.push(`Final score: ${scoreA === 1 && scoreB === 1 ? 1 : 0}.`);
|
|
281
|
+
} else {
|
|
282
|
+
traceLog.push(
|
|
283
|
+
'With partial scoring enabled, Part A must be correct to earn any credit.'
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
let finalScore = 0;
|
|
287
|
+
if (scoreA === 1 && scoreB === 1) {
|
|
288
|
+
finalScore = 2;
|
|
289
|
+
} else if (scoreA === 1 && scoreB < 1) {
|
|
290
|
+
finalScore = 1;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
traceLog.push(`Final score: ${finalScore}.`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return traceLog;
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
export function outcome(config, session, env) {
|
|
300
|
+
return new Promise((resolve) => {
|
|
301
|
+
const { value } = session || {};
|
|
302
|
+
|
|
303
|
+
if (!session || !value) {
|
|
304
|
+
resolve({ score: 0, scoreA: 0, scoreB: 0, empty: true, logTrace: ['Student did not answer the question.'] });
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (value) {
|
|
308
|
+
const { partA, partB } = value || {};
|
|
309
|
+
|
|
310
|
+
const partialScoringEnabled = partialScoring.enabled(config, env);
|
|
311
|
+
|
|
312
|
+
const scoreA = getScore(config, partA, 'partA', partialScoringEnabled);
|
|
313
|
+
const scoreB = getScore(config, partB, 'partB', partialScoringEnabled);
|
|
314
|
+
const logTrace = getLogTrace(config, session, env);
|
|
315
|
+
|
|
316
|
+
if (!partialScoringEnabled) {
|
|
317
|
+
// The EBSR item is worth 1 point
|
|
318
|
+
// That point is awarded if and only if both parts are fully correct, otherwise no points are awarded
|
|
319
|
+
resolve({ score: scoreA === 1 && scoreB === 1 ? 1 : 0, scoreA, scoreB, max: 1, logTrace });
|
|
320
|
+
} else {
|
|
321
|
+
// The EBSR item is worth 2 points
|
|
322
|
+
if (scoreA === 1) {
|
|
323
|
+
if (scoreB === 1) {
|
|
324
|
+
// If Part A and Part B are both correct, 2 points are awarded
|
|
325
|
+
resolve({ score: 2, scoreA, scoreB, max: 2, logTrace });
|
|
326
|
+
} else {
|
|
327
|
+
// If Part A is correct and part B is incorrect, 1 point is awarded
|
|
328
|
+
resolve({ score: 1, scoreA, scoreB, max: 2, logTrace });
|
|
329
|
+
}
|
|
330
|
+
} else {
|
|
331
|
+
// For all other combinations, no points are awarded
|
|
332
|
+
resolve({ score: 0, scoreA, scoreB, max: 2, logTrace });
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const returnPartCorrect = (choices) => {
|
|
340
|
+
let answers = [];
|
|
341
|
+
|
|
342
|
+
choices.forEach((i) => {
|
|
343
|
+
const { correct, value } = i;
|
|
344
|
+
if (correct) {
|
|
345
|
+
answers.push(value);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
return answers;
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
export const createCorrectResponseSession = (question, env) => {
|
|
352
|
+
return new Promise((resolve) => {
|
|
353
|
+
if (env.mode !== 'evaluate' && env.role === 'instructor') {
|
|
354
|
+
const { partA, partB } = question;
|
|
355
|
+
|
|
356
|
+
const partACorrect = returnPartCorrect(partA.choices);
|
|
357
|
+
const partBCorrect = returnPartCorrect(partB.choices);
|
|
358
|
+
|
|
359
|
+
resolve({
|
|
360
|
+
value: {
|
|
361
|
+
partA: {
|
|
362
|
+
id: 'partA',
|
|
363
|
+
value: partACorrect,
|
|
364
|
+
},
|
|
365
|
+
partB: {
|
|
366
|
+
id: 'partB',
|
|
367
|
+
value: partBCorrect,
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
id: '1',
|
|
371
|
+
});
|
|
372
|
+
} else {
|
|
373
|
+
resolve(null);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
// remove all html tags
|
|
379
|
+
const getInnerText = (html) => (html || '').replaceAll(/<[^>]*>/g, '');
|
|
380
|
+
|
|
381
|
+
// remove all html tags except img, iframe and source tag for audio
|
|
382
|
+
const getContent = (html) => (html || '').replace(/(<(?!img|iframe|source)([^>]+)>)/gi, '');
|
|
383
|
+
|
|
384
|
+
const validatePart = (model = {}, config = {}) => {
|
|
385
|
+
const { choices } = model;
|
|
386
|
+
const { minAnswerChoices = 2, maxAnswerChoices } = config;
|
|
387
|
+
const reversedChoices = [...(choices || [])].reverse();
|
|
388
|
+
const errors = {};
|
|
389
|
+
const choicesErrors = {};
|
|
390
|
+
const rationaleErrors = {};
|
|
391
|
+
let hasCorrectResponse = false;
|
|
392
|
+
|
|
393
|
+
['teacherInstructions', 'prompt'].forEach((field) => {
|
|
394
|
+
if (config[field]?.required && !getContent(model[field])) {
|
|
395
|
+
errors[field] = 'This field is required.';
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
reversedChoices.forEach((choice, index) => {
|
|
400
|
+
const { correct, value, label, rationale } = choice;
|
|
401
|
+
|
|
402
|
+
if (correct) {
|
|
403
|
+
hasCorrectResponse = true;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (!getContent(label)) {
|
|
407
|
+
choicesErrors[value] = 'Content should not be empty.';
|
|
408
|
+
} else {
|
|
409
|
+
const identicalAnswer = reversedChoices.slice(index + 1).some((c) => c.label === label);
|
|
410
|
+
|
|
411
|
+
if (identicalAnswer) {
|
|
412
|
+
choicesErrors[value] = 'Content should be unique.';
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (config.rationale?.required && !getContent(rationale)) {
|
|
417
|
+
rationaleErrors[value] = 'This field is required.';
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
const nbOfChoices = (choices || []).length;
|
|
422
|
+
|
|
423
|
+
if (nbOfChoices < minAnswerChoices) {
|
|
424
|
+
errors.answerChoices = `There should be at least ${minAnswerChoices} choices defined.`;
|
|
425
|
+
} else if (nbOfChoices > maxAnswerChoices) {
|
|
426
|
+
errors.answerChoices = `No more than ${maxAnswerChoices} choices should be defined.`;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (!hasCorrectResponse) {
|
|
430
|
+
errors.correctResponse = 'No correct response defined.';
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (!isEmpty(choicesErrors)) {
|
|
434
|
+
errors.choices = choicesErrors;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (!isEmpty(rationaleErrors)) {
|
|
438
|
+
errors.rationale = rationaleErrors;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return errors;
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
export const validate = (model = {}, config = {}) => {
|
|
445
|
+
const { partA, partB } = model || {};
|
|
446
|
+
const { partA: partAConfig, partB: partBConfig } = config || {};
|
|
447
|
+
|
|
448
|
+
const partAErrors = validatePart(partA, partAConfig);
|
|
449
|
+
const partBErrors = validatePart(partB, partBConfig);
|
|
450
|
+
|
|
451
|
+
return { partA: partAErrors, partB: partBErrors };
|
|
452
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* @synced-from pie-elements/packages/ebsr/controller/src/utils.js
|
|
4
|
+
* @auto-generated
|
|
5
|
+
*
|
|
6
|
+
* This file is automatically synced from pie-elements and converted to TypeScript.
|
|
7
|
+
* Manual edits will be overwritten on next sync.
|
|
8
|
+
* To make changes, edit the upstream JavaScript file and run sync again.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { isEqual } from 'lodash-es';
|
|
12
|
+
|
|
13
|
+
export const getCorrectResponse = (choices) =>
|
|
14
|
+
choices &&
|
|
15
|
+
choices
|
|
16
|
+
.filter((c) => c.correct)
|
|
17
|
+
.map((c) => c.value)
|
|
18
|
+
.sort();
|
|
19
|
+
|
|
20
|
+
export const isResponseCorrect = (question, key, session) => {
|
|
21
|
+
let correctResponse = getCorrectResponse(question.choices);
|
|
22
|
+
|
|
23
|
+
if (session && session.value) {
|
|
24
|
+
return isEqual((session.value[key].value || []).sort(), correctResponse);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return false;
|
|
28
|
+
};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* @synced-from pie-elements/packages/ebsr/src/index.js
|
|
4
|
+
* @auto-generated
|
|
5
|
+
*
|
|
6
|
+
* This file is automatically synced from pie-elements and converted to TypeScript.
|
|
7
|
+
* Manual edits will be overwritten on next sync.
|
|
8
|
+
* To make changes, edit the upstream JavaScript file and run sync again.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { SessionChangedEvent } from '@pie-element/shared-player-events';
|
|
12
|
+
import MultipleChoice from '@pie-element/multiple-choice';
|
|
13
|
+
import { get } from 'lodash-es';
|
|
14
|
+
import debug from 'debug';
|
|
15
|
+
|
|
16
|
+
const SESSION_CHANGED = SessionChangedEvent.TYPE;
|
|
17
|
+
const MC_TAG_NAME = 'ebsr-multiple-choice';
|
|
18
|
+
const log = debug('pie-elements:ebsr');
|
|
19
|
+
|
|
20
|
+
class EbsrMC extends MultipleChoice {}
|
|
21
|
+
|
|
22
|
+
const defineMultipleChoice = () => {
|
|
23
|
+
if (!customElements.get(MC_TAG_NAME)) {
|
|
24
|
+
customElements.define(MC_TAG_NAME, EbsrMC);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
defineMultipleChoice();
|
|
29
|
+
|
|
30
|
+
const isNonEmptyArray = (a) => Array.isArray(a) && a.length > 0;
|
|
31
|
+
|
|
32
|
+
export const isSessionComplete = (session) => {
|
|
33
|
+
const a = get(session, 'value.partA.value');
|
|
34
|
+
const b = get(session, 'value.partB.value');
|
|
35
|
+
|
|
36
|
+
return isNonEmptyArray(a) && isNonEmptyArray(b);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default class Ebsr extends HTMLElement {
|
|
40
|
+
constructor() {
|
|
41
|
+
super();
|
|
42
|
+
this._model = {};
|
|
43
|
+
this._session = {};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
onSessionUpdated: any = (e) => {
|
|
47
|
+
if (e.target === this) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
e.stopImmediatePropagation();
|
|
53
|
+
|
|
54
|
+
const id = e.target.getAttribute('id');
|
|
55
|
+
|
|
56
|
+
if (id) {
|
|
57
|
+
const key = `part${id.toUpperCase()}`;
|
|
58
|
+
|
|
59
|
+
if (e.update) {
|
|
60
|
+
this._model[key] = e.update;
|
|
61
|
+
}
|
|
62
|
+
//TODO: accessing a private property here. The session event should contain the update in future to prevent this.
|
|
63
|
+
this.dispatchSessionChanged(e.srcElement._session, key);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
set model(m) {
|
|
68
|
+
this._model = m;
|
|
69
|
+
|
|
70
|
+
customElements.whenDefined(MC_TAG_NAME).then(() => {
|
|
71
|
+
this.setPartModel(this.partA, 'partA');
|
|
72
|
+
this.setPartModel(this.partB, 'partB');
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
set session(s) {
|
|
77
|
+
this._session = s;
|
|
78
|
+
|
|
79
|
+
customElements.whenDefined(MC_TAG_NAME).then(() => {
|
|
80
|
+
this.setPartSession(this.partA, 'partA');
|
|
81
|
+
this.setPartSession(this.partB, 'partB');
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get session() {
|
|
86
|
+
return this._session;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
setPartModel(part, key) {
|
|
90
|
+
if (this._model && this._model[key] && part) {
|
|
91
|
+
const { mode } = this._model;
|
|
92
|
+
|
|
93
|
+
part.model = {
|
|
94
|
+
...this._model[key],
|
|
95
|
+
mode,
|
|
96
|
+
keyMode: this._model[key].choicePrefix,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
setPartSession(part, key) {
|
|
102
|
+
if (this._session && this._model && part) {
|
|
103
|
+
const { value } = this._session;
|
|
104
|
+
part.session = value && value[key] ? value[key] : { id: key };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
dispatchSessionChanged(partSession, key) {
|
|
109
|
+
this._session.value = {
|
|
110
|
+
...this._session.value,
|
|
111
|
+
[key]: partSession,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
log('[onSessionChanged] session: ', this._session);
|
|
115
|
+
const complete = isSessionComplete(this._session);
|
|
116
|
+
this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), complete));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get partA() {
|
|
120
|
+
return this.querySelector(`${MC_TAG_NAME}#a`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
get partB() {
|
|
124
|
+
return this.querySelector(`${MC_TAG_NAME}#b`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
connectedCallback() {
|
|
128
|
+
this._render();
|
|
129
|
+
this.addEventListener(SESSION_CHANGED, this.onSessionUpdated);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
disconnectedCallback() {
|
|
133
|
+
this.removeEventListener(SESSION_CHANGED, this.onSessionUpdated);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
_render() {
|
|
137
|
+
this.ariaLabel = 'Two-Part Question';
|
|
138
|
+
this.role = 'region';
|
|
139
|
+
this.innerHTML = `
|
|
140
|
+
<style>
|
|
141
|
+
.srOnly {
|
|
142
|
+
position: absolute;
|
|
143
|
+
width: 1px;
|
|
144
|
+
height: 1px;
|
|
145
|
+
padding: 0;
|
|
146
|
+
margin: -1px;
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
left: -10000px;
|
|
149
|
+
top: auto;
|
|
150
|
+
}
|
|
151
|
+
${this._model?.extraCSSRules?.rules}
|
|
152
|
+
</style>
|
|
153
|
+
<h2 class="srOnly">Two-Part Question</h2>
|
|
154
|
+
<${MC_TAG_NAME} id="a"></${MC_TAG_NAME}>
|
|
155
|
+
<${MC_TAG_NAME} id="b"></${MC_TAG_NAME}>
|
|
156
|
+
`;
|
|
157
|
+
|
|
158
|
+
// when item is re-rendered (due to connectedCallback), if the custom element is already defined,
|
|
159
|
+
// we need to set the model and session, otherwise the setters are not reached again
|
|
160
|
+
if (customElements.get(MC_TAG_NAME)) {
|
|
161
|
+
this.setPartModel(this.partA, 'partA');
|
|
162
|
+
this.setPartModel(this.partB, 'partB');
|
|
163
|
+
this.setPartSession(this.partA, 'partA');
|
|
164
|
+
this.setPartSession(this.partB, 'partB');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IIFE entry point for ebsr element
|
|
3
|
+
* This file is only used for IIFE builds and includes auto-registration
|
|
4
|
+
*
|
|
5
|
+
* @sync-generated - Auto-generated during sync from pie-elements
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import Element from './index.js';
|
|
9
|
+
|
|
10
|
+
// Auto-register the custom element for IIFE mode
|
|
11
|
+
if (typeof window !== 'undefined' && !customElements.get('ebsr-element')) {
|
|
12
|
+
customElements.define('ebsr-element', Element);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Export for IIFE global
|
|
16
|
+
export default Element;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './delivery/index.js';
|