@pie-element/ebsr 6.6.3-next.133 → 6.6.3-next.1353
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 +246 -0
- package/configure/CHANGELOG.md +246 -0
- package/configure/lib/defaults.js +28 -6
- package/configure/lib/defaults.js.map +1 -1
- package/configure/lib/index.js +29 -17
- package/configure/lib/index.js.map +1 -1
- package/configure/lib/main.js +48 -18
- package/configure/lib/main.js.map +1 -1
- package/configure/package.json +4 -4
- package/configure/src/__tests__/__snapshots__/index.test.js.snap +12 -4
- package/configure/src/__tests__/index.test.js +4 -2
- package/configure/src/defaults.js +26 -4
- package/configure/src/index.js +14 -30
- package/configure/src/main.jsx +43 -14
- package/controller/CHANGELOG.md +33 -0
- package/controller/lib/index.js +113 -23
- package/controller/lib/index.js.map +1 -1
- package/controller/package.json +1 -1
- package/controller/src/index.js +62 -5
- package/docs/config-schema.json +311 -3
- package/docs/config-schema.json.md +243 -7
- package/docs/pie-schema.json +139 -1
- package/docs/pie-schema.json.md +106 -2
- package/lib/index.js +12 -9
- package/lib/index.js.map +1 -1
- package/lib/print.js +243 -0
- package/lib/print.js.map +1 -0
- package/package.json +8 -4
- package/src/index.js +6 -2
- package/src/print.js +181 -0
package/configure/src/main.jsx
CHANGED
|
@@ -2,7 +2,6 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { settings, layout } from '@pie-lib/config-ui';
|
|
4
4
|
import { withStyles } from '@material-ui/core/styles';
|
|
5
|
-
import cloneDeep from 'lodash/cloneDeep';
|
|
6
5
|
|
|
7
6
|
const { Panel, toggle, radio, dropdown } = settings;
|
|
8
7
|
|
|
@@ -68,7 +67,7 @@ export class Main extends React.Component {
|
|
|
68
67
|
configuration,
|
|
69
68
|
onConfigurationChanged
|
|
70
69
|
} = this.props;
|
|
71
|
-
const { partLabelType } = model;
|
|
70
|
+
const { partLabelType, partA: modelPartA, partB: modelPartB } = model;
|
|
72
71
|
const { partA, partB, partialScoring, scoringType, ...generalConfiguration } = configuration;
|
|
73
72
|
const {
|
|
74
73
|
feedback: feedbackA = {},
|
|
@@ -78,8 +77,10 @@ export class Main extends React.Component {
|
|
|
78
77
|
prompt: promptA = {},
|
|
79
78
|
teacherInstructions: teacherInstructionsA = {},
|
|
80
79
|
studentInstructions: studentInstructionsA = {},
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
choicesLayout: choicesLayoutA = {},
|
|
81
|
+
gridColumns: gridColumnsA = {},
|
|
82
|
+
rationale: rationaleA = {},
|
|
83
|
+
spellCheck: spellCheckA = {}
|
|
83
84
|
} = partA || {};
|
|
84
85
|
const {
|
|
85
86
|
feedback: feedbackB = {},
|
|
@@ -89,13 +90,21 @@ export class Main extends React.Component {
|
|
|
89
90
|
prompt: promptB = {},
|
|
90
91
|
teacherInstructions: teacherInstructionsB = {},
|
|
91
92
|
studentInstructions: studentInstructionsB = {},
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
choicesLayout: choicesLayoutB = {},
|
|
94
|
+
gridColumns: gridColumnsB = {},
|
|
95
|
+
rationale: rationaleB = {},
|
|
96
|
+
spellCheck: spellCheckB = {}
|
|
94
97
|
} = partB || {};
|
|
95
98
|
const type = partLabelType || 'Numbers';
|
|
96
99
|
const typeIsNumber = type === 'Numbers';
|
|
97
100
|
const firstPart = `Part ${typeIsNumber ? '1' : 'A'}`;
|
|
98
101
|
const secondPart = `Part ${typeIsNumber ? '2' : 'B'}`;
|
|
102
|
+
const nrOfColumnsAvailable = {
|
|
103
|
+
partA: modelPartA.choices && modelPartA.choices.length ?
|
|
104
|
+
Array.from({length: modelPartA.choices.length}, (_, i) => (`${i + 1}`)) : [],
|
|
105
|
+
partB: modelPartB.choices && modelPartB.choices.length ?
|
|
106
|
+
Array.from({length: modelPartB.choices.length}, (_, i) => (`${i + 1}`)) : [],
|
|
107
|
+
};
|
|
99
108
|
|
|
100
109
|
return (
|
|
101
110
|
<div className={classes.design}>
|
|
@@ -127,8 +136,13 @@ export class Main extends React.Component {
|
|
|
127
136
|
radio(choicePrefixA.label, ['numbers', 'letters']),
|
|
128
137
|
'partA.lockChoiceOrder':
|
|
129
138
|
lockChoiceOrderA.settings && toggle(lockChoiceOrderA.label),
|
|
130
|
-
'partA.
|
|
131
|
-
|
|
139
|
+
'partA.choicesLayout':
|
|
140
|
+
choicesLayoutA.settings &&
|
|
141
|
+
dropdown(choicesLayoutA.label, ['vertical', 'grid', 'horizontal']),
|
|
142
|
+
'partA.gridColumns':
|
|
143
|
+
choicesLayoutA.settings && modelPartA.choicesLayout === 'grid' &&
|
|
144
|
+
nrOfColumnsAvailable.partA.length > 0 &&
|
|
145
|
+
dropdown(gridColumnsA.label, nrOfColumnsAvailable.partA)
|
|
132
146
|
},
|
|
133
147
|
[`Properties ${firstPart}`]: {
|
|
134
148
|
'partA.feedbackEnabled': feedbackA.settings &&
|
|
@@ -142,7 +156,9 @@ export class Main extends React.Component {
|
|
|
142
156
|
studentInstructionsA.settings &&
|
|
143
157
|
toggle(studentInstructionsA.label),
|
|
144
158
|
'partA.rationaleEnabled':
|
|
145
|
-
rationaleA.settings && toggle(rationaleA.label)
|
|
159
|
+
rationaleA.settings && toggle(rationaleA.label),
|
|
160
|
+
'partA.spellCheckEnabled':
|
|
161
|
+
spellCheckA.settings && toggle(spellCheckA.label),
|
|
146
162
|
},
|
|
147
163
|
[`Settings ${secondPart}`]: {
|
|
148
164
|
'partB.choiceMode':
|
|
@@ -153,8 +169,13 @@ export class Main extends React.Component {
|
|
|
153
169
|
radio(choicePrefixB.label, ['numbers', 'letters']),
|
|
154
170
|
'partB.lockChoiceOrder':
|
|
155
171
|
lockChoiceOrderB.settings && toggle(lockChoiceOrderB.label),
|
|
156
|
-
'partB.
|
|
157
|
-
|
|
172
|
+
'partB.choicesLayout':
|
|
173
|
+
choicesLayoutB.settings &&
|
|
174
|
+
dropdown(choicesLayoutB.label, ['vertical', 'grid', 'horizontal']),
|
|
175
|
+
'partB.gridColumns':
|
|
176
|
+
choicesLayoutB.settings && modelPartB.choicesLayout === 'grid' &&
|
|
177
|
+
nrOfColumnsAvailable.partB.length > 0 &&
|
|
178
|
+
dropdown(gridColumnsB.label, nrOfColumnsAvailable.partB)
|
|
158
179
|
},
|
|
159
180
|
[`Properties ${secondPart}`]: {
|
|
160
181
|
'partB.feedbackEnabled':
|
|
@@ -168,7 +189,9 @@ export class Main extends React.Component {
|
|
|
168
189
|
studentInstructionsB.settings &&
|
|
169
190
|
toggle(studentInstructionsB.label),
|
|
170
191
|
'partB.rationaleEnabled':
|
|
171
|
-
rationaleB.settings && toggle(rationaleB.label)
|
|
192
|
+
rationaleB.settings && toggle(rationaleB.label),
|
|
193
|
+
'partB.spellCheckEnabled':
|
|
194
|
+
spellCheckB.settings && toggle(spellCheckB.label),
|
|
172
195
|
}
|
|
173
196
|
}}
|
|
174
197
|
/>
|
|
@@ -184,7 +207,10 @@ export class Main extends React.Component {
|
|
|
184
207
|
if (ref) {
|
|
185
208
|
// do not use destructuring to get model from props
|
|
186
209
|
this.partA = ref;
|
|
187
|
-
this.partA._model =
|
|
210
|
+
this.partA._model = {
|
|
211
|
+
...this.props.model.partA,
|
|
212
|
+
errors: this.props.model.errors && this.props.model.errors.partA || {}
|
|
213
|
+
};
|
|
188
214
|
this.partA.configuration = {
|
|
189
215
|
...partA,
|
|
190
216
|
...generalConfiguration
|
|
@@ -203,7 +229,10 @@ export class Main extends React.Component {
|
|
|
203
229
|
if (ref) {
|
|
204
230
|
// do not use destructuring to get model from props
|
|
205
231
|
this.partB = ref;
|
|
206
|
-
this.partB._model =
|
|
232
|
+
this.partB._model ={
|
|
233
|
+
...this.props.model.partB,
|
|
234
|
+
errors: this.props.model.errors && this.props.model.errors.partB || {}
|
|
235
|
+
};
|
|
207
236
|
this.partB.configuration = {
|
|
208
237
|
...partB,
|
|
209
238
|
...generalConfiguration
|
package/controller/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,39 @@
|
|
|
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.0.5](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-controller@6.0.4...@pie-element/ebsr-controller@6.0.5) (2022-05-30)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @pie-element/ebsr-controller
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [6.0.1](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-controller@6.0.0...@pie-element/ebsr-controller@6.0.1) (2021-09-01)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @pie-element/ebsr-controller
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# [6.0.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-controller@5.2.2...@pie-element/ebsr-controller@6.0.0) (2021-08-09)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* **ebsr:** Added choicesLayout support ([33fb7e7](https://github.com/pie-framework/pie-elements/commit/33fb7e765146a7343a58663f3667f4a5de472960))
|
|
28
|
+
* **ebsr:** Added choicesLayout support \n BREAKING CHANGE: removed vertical mode ([348fc00](https://github.com/pie-framework/pie-elements/commit/348fc0031536d458071a1105e742c3d19399a15e))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### BREAKING CHANGES
|
|
32
|
+
|
|
33
|
+
* **ebsr:** removed vertical mode.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
6
39
|
## [5.2.2](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-controller@5.2.0...@pie-element/ebsr-controller@5.2.2) (2021-08-05)
|
|
7
40
|
|
|
8
41
|
|
package/controller/lib/index.js
CHANGED
|
@@ -5,14 +5,20 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", {
|
|
6
6
|
value: true
|
|
7
7
|
});
|
|
8
|
+
exports.createDefaultModel = exports.createCorrectResponseSession = void 0;
|
|
8
9
|
exports.model = model;
|
|
10
|
+
exports.normalize = void 0;
|
|
9
11
|
exports.outcome = outcome;
|
|
10
|
-
exports.
|
|
12
|
+
exports.validate = void 0;
|
|
11
13
|
|
|
12
14
|
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
13
15
|
|
|
16
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
17
|
+
|
|
14
18
|
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
15
19
|
|
|
20
|
+
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
|
|
21
|
+
|
|
16
22
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
17
23
|
|
|
18
24
|
var _defaults = _interopRequireDefault(require("./defaults"));
|
|
@@ -25,9 +31,11 @@ var _get = _interopRequireDefault(require("lodash/get"));
|
|
|
25
31
|
|
|
26
32
|
var _isEmpty = _interopRequireDefault(require("lodash/isEmpty"));
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
var _excluded = ["partA", "partB"];
|
|
29
35
|
|
|
30
|
-
function
|
|
36
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
37
|
+
|
|
38
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
31
39
|
|
|
32
40
|
var prepareChoice = function prepareChoice(model, env, defaultFeedback) {
|
|
33
41
|
return function (choice) {
|
|
@@ -78,27 +86,36 @@ var parsePart = function parsePart(part, key, session, env) {
|
|
|
78
86
|
});
|
|
79
87
|
};
|
|
80
88
|
|
|
81
|
-
var normalize = function normalize(
|
|
89
|
+
var normalize = function normalize(_ref) {
|
|
90
|
+
var _ref$partA = _ref.partA,
|
|
91
|
+
partA = _ref$partA === void 0 ? {} : _ref$partA,
|
|
92
|
+
_ref$partB = _ref.partB,
|
|
93
|
+
partB = _ref$partB === void 0 ? {} : _ref$partB,
|
|
94
|
+
question = (0, _objectWithoutProperties2["default"])(_ref, _excluded);
|
|
82
95
|
return _objectSpread(_objectSpread({
|
|
83
96
|
partLabels: true,
|
|
84
97
|
partLabelType: 'Letters'
|
|
85
98
|
}, question), {}, {
|
|
86
|
-
partA: _objectSpread(_objectSpread({}, _defaults["default"].partA), {}, {
|
|
99
|
+
partA: _objectSpread(_objectSpread(_objectSpread({}, _defaults["default"].partA), {}, {
|
|
87
100
|
rationaleEnabled: true,
|
|
88
101
|
feedbackEnabled: true,
|
|
89
102
|
promptEnabled: true,
|
|
90
103
|
teacherInstructionsEnabled: true,
|
|
91
104
|
studentInstructionsEnabled: true,
|
|
92
|
-
|
|
93
|
-
},
|
|
94
|
-
|
|
105
|
+
gridColumns: '2'
|
|
106
|
+
}, partA), {}, {
|
|
107
|
+
choicesLayout: partA.choicesLayout || partA.verticalMode === false && 'horizontal' || 'vertical'
|
|
108
|
+
}),
|
|
109
|
+
partB: _objectSpread(_objectSpread(_objectSpread({}, _defaults["default"].partB), {}, {
|
|
95
110
|
rationaleEnabled: true,
|
|
96
111
|
promptEnabled: true,
|
|
97
112
|
feedbackEnabled: true,
|
|
98
113
|
teacherInstructionsEnabled: true,
|
|
99
114
|
studentInstructionsEnabled: true,
|
|
100
|
-
|
|
101
|
-
},
|
|
115
|
+
gridColumns: '2'
|
|
116
|
+
}, partB), {}, {
|
|
117
|
+
choicesLayout: partB.choicesLayout || partB.verticalMode === false && 'horizontal' || 'vertical'
|
|
118
|
+
})
|
|
102
119
|
});
|
|
103
120
|
};
|
|
104
121
|
/**
|
|
@@ -118,7 +135,7 @@ function model(_x, _x2, _x3, _x4) {
|
|
|
118
135
|
|
|
119
136
|
function _model() {
|
|
120
137
|
_model = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(question, session, env, updateSession) {
|
|
121
|
-
var normalizedQuestion, partA, partB, shuffledValues, us, partASession, partALockChoiceOrder,
|
|
138
|
+
var normalizedQuestion, partA, partB, shuffledValues, us, partASession, partALockChoiceOrder, _ref8, partAChoices, _ref9, partBChoices, partBSession, partBLockChoiceOrder;
|
|
122
139
|
|
|
123
140
|
return _regenerator["default"].wrap(function _callee$(_context) {
|
|
124
141
|
while (1) {
|
|
@@ -140,8 +157,8 @@ function _model() {
|
|
|
140
157
|
|
|
141
158
|
partASession = (0, _get["default"])(session, 'value.partA');
|
|
142
159
|
partALockChoiceOrder = (0, _controllerUtils.lockChoices)(normalizedQuestion.partA, partASession, env);
|
|
143
|
-
|
|
144
|
-
|
|
160
|
+
_ref8 = partA || {}, partAChoices = _ref8.choices;
|
|
161
|
+
_ref9 = partB || {}, partBChoices = _ref9.choices;
|
|
145
162
|
|
|
146
163
|
if (!(!partALockChoiceOrder && partAChoices && partAChoices.length)) {
|
|
147
164
|
_context.next = 13;
|
|
@@ -235,14 +252,14 @@ var isCorrect = function isCorrect(c) {
|
|
|
235
252
|
};
|
|
236
253
|
|
|
237
254
|
var getScore = function getScore(config, sessionPart, key) {
|
|
238
|
-
var
|
|
239
|
-
|
|
240
|
-
choices =
|
|
255
|
+
var _ref2 = config && config[key] || {},
|
|
256
|
+
_ref2$choices = _ref2.choices,
|
|
257
|
+
choices = _ref2$choices === void 0 ? [] : _ref2$choices;
|
|
241
258
|
|
|
242
259
|
var maxScore = choices.length;
|
|
243
260
|
|
|
244
|
-
var
|
|
245
|
-
sessionPartValue =
|
|
261
|
+
var _ref3 = sessionPart || {},
|
|
262
|
+
sessionPartValue = _ref3.value;
|
|
246
263
|
|
|
247
264
|
var chosen = function chosen(c) {
|
|
248
265
|
return !!(sessionPartValue || []).find(function (v) {
|
|
@@ -275,8 +292,8 @@ var getScore = function getScore(config, sessionPart, key) {
|
|
|
275
292
|
|
|
276
293
|
function outcome(config, session) {
|
|
277
294
|
return new Promise(function (resolve) {
|
|
278
|
-
var
|
|
279
|
-
value =
|
|
295
|
+
var _ref4 = session || {},
|
|
296
|
+
value = _ref4.value;
|
|
280
297
|
|
|
281
298
|
if (!session || !value) {
|
|
282
299
|
resolve({
|
|
@@ -288,9 +305,9 @@ function outcome(config, session) {
|
|
|
288
305
|
}
|
|
289
306
|
|
|
290
307
|
if (value) {
|
|
291
|
-
var
|
|
292
|
-
partA =
|
|
293
|
-
partB =
|
|
308
|
+
var _ref5 = value || {},
|
|
309
|
+
partA = _ref5.partA,
|
|
310
|
+
partB = _ref5.partB;
|
|
294
311
|
|
|
295
312
|
var scoreA = getScore(config, partA, 'partA');
|
|
296
313
|
var scoreB = getScore(config, partB, 'partB');
|
|
@@ -378,4 +395,77 @@ var createCorrectResponseSession = function createCorrectResponseSession(questio
|
|
|
378
395
|
};
|
|
379
396
|
|
|
380
397
|
exports.createCorrectResponseSession = createCorrectResponseSession;
|
|
398
|
+
|
|
399
|
+
var validatePart = function validatePart() {
|
|
400
|
+
var model = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
401
|
+
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
402
|
+
var choices = model.choices;
|
|
403
|
+
var _config$minAnswerChoi = config.minAnswerChoices,
|
|
404
|
+
minAnswerChoices = _config$minAnswerChoi === void 0 ? 2 : _config$minAnswerChoi,
|
|
405
|
+
maxAnswerChoices = config.maxAnswerChoices;
|
|
406
|
+
var reversedChoices = (0, _toConsumableArray2["default"])(choices || []).reverse();
|
|
407
|
+
var choicesErrors = {};
|
|
408
|
+
var hasCorrectResponse = false;
|
|
409
|
+
reversedChoices.forEach(function (choice, index) {
|
|
410
|
+
var correct = choice.correct,
|
|
411
|
+
value = choice.value,
|
|
412
|
+
label = choice.label;
|
|
413
|
+
|
|
414
|
+
if (correct) {
|
|
415
|
+
hasCorrectResponse = true;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (label === '' || label === '<div></div>') {
|
|
419
|
+
choicesErrors[value] = 'Content should not be empty.';
|
|
420
|
+
} else {
|
|
421
|
+
var identicalAnswer = reversedChoices.slice(index + 1).some(function (c) {
|
|
422
|
+
return c.label === label;
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
if (identicalAnswer) {
|
|
426
|
+
choicesErrors[value] = 'Content should be unique.';
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
var errors = {};
|
|
431
|
+
var nbOfChoices = (choices || []).length;
|
|
432
|
+
|
|
433
|
+
if (nbOfChoices < minAnswerChoices) {
|
|
434
|
+
errors.answerChoicesError = "There should be at least ".concat(minAnswerChoices, " choices defined.");
|
|
435
|
+
} else if (nbOfChoices > maxAnswerChoices) {
|
|
436
|
+
errors.answerChoicesError = "No more than ".concat(maxAnswerChoices, " choices should be defined.");
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (!hasCorrectResponse) {
|
|
440
|
+
errors.correctResponseError = 'No correct response defined.';
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (!(0, _isEmpty["default"])(choicesErrors)) {
|
|
444
|
+
errors.choicesErrors = choicesErrors;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return errors;
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
var validate = function validate() {
|
|
451
|
+
var model = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
452
|
+
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
453
|
+
|
|
454
|
+
var _ref6 = model || {},
|
|
455
|
+
partA = _ref6.partA,
|
|
456
|
+
partB = _ref6.partB;
|
|
457
|
+
|
|
458
|
+
var _ref7 = config || {},
|
|
459
|
+
partAConfig = _ref7.partA,
|
|
460
|
+
partBConfig = _ref7.partB;
|
|
461
|
+
|
|
462
|
+
var partAErrors = validatePart(partA, partAConfig);
|
|
463
|
+
var partBErrors = validatePart(partB, partBConfig);
|
|
464
|
+
return {
|
|
465
|
+
partA: partAErrors,
|
|
466
|
+
partB: partBErrors
|
|
467
|
+
};
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
exports.validate = validate;
|
|
381
471
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.js"],"names":["prepareChoice","model","env","defaultFeedback","choice","out","label","value","role","mode","rationale","rationaleEnabled","correct","feedbackEnabled","feedbackType","feedback","type","parsePart","part","key","session","Object","assign","incorrect","choices","map","disabled","complete","min","filter","c","length","responseCorrect","undefined","normalize","question","partLabels","partLabelType","partA","defaults","promptEnabled","teacherInstructionsEnabled","studentInstructionsEnabled","verticalMode","partB","updateSession","normalizedQuestion","shuffledValues","us","id","element","update","Promise","resolve","partASession","partALockChoiceOrder","partAChoices","partBChoices","partBSession","partBLockChoiceOrder","e","console","error","partLabel","teacherInstructions","prompt","createDefaultModel","isCorrect","getScore","config","sessionPart","maxScore","sessionPartValue","chosen","find","v","correctAndNotChosen","incorrectAndChosen","correctChoices","reduce","total","partialScoring","parseFloat","toFixed","outcome","score","scoreA","scoreB","empty","max","returnPartCorrect","answers","forEach","i","push","createCorrectResponseSession","partACorrect","partBCorrect"],"mappings":"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","sourcesContent":["import defaults from './defaults';\nimport { lockChoices, getShuffledChoices } from '@pie-lib/controller-utils';\nimport { isResponseCorrect } from './utils';\nimport get from 'lodash/get';\nimport isEmpty from 'lodash/isEmpty';\n\nconst prepareChoice = (model, env, defaultFeedback) => choice => {\n const out = {\n label: choice.label,\n value: choice.value\n };\n\n if (\n env.role === 'instructor' &&\n (env.mode === 'view' || env.mode === 'evaluate')\n ) {\n out.rationale = model.rationaleEnabled ? choice.rationale : null;\n } else {\n out.rationale = null;\n }\n\n if (env.mode === 'evaluate') {\n out.correct = !!choice.correct;\n\n if (model.feedbackEnabled) {\n const feedbackType = (choice.feedback && choice.feedback.type) || 'none';\n\n if (feedbackType === 'default') {\n out.feedback = defaultFeedback[choice.correct ? 'correct' : 'incorrect'];\n } else if (feedbackType === 'custom') {\n out.feedback = choice.feedback.value;\n }\n }\n }\n\n return out;\n};\n\nconst parsePart = (part, key, session, env) => {\n const defaultFeedback = Object.assign(\n { correct: 'Correct', incorrect: 'Incorrect' },\n part.defaultFeedback\n );\n\n let choices = part.choices\n ? part.choices.map(prepareChoice(part, env, defaultFeedback))\n : [];\n\n return {\n ...part,\n choices,\n disabled: env.mode !== 'gather',\n complete: {\n min: part.choices.filter(c => c.correct).length\n },\n responseCorrect:\n env.mode === 'evaluate'\n ? isResponseCorrect(part, key, session)\n : undefined\n };\n};\n\nexport const normalize = question => ({\n partLabels: true,\n partLabelType: 'Letters',\n ...question,\n partA: {\n ...defaults.partA,\n rationaleEnabled: true,\n feedbackEnabled: true,\n promptEnabled: true,\n teacherInstructionsEnabled: true,\n studentInstructionsEnabled: true,\n verticalMode: true,\n ...question.partA\n },\n partB: {\n ...defaults.partB,\n rationaleEnabled: true,\n promptEnabled: true,\n feedbackEnabled: true,\n teacherInstructionsEnabled: true,\n studentInstructionsEnabled: true,\n verticalMode: true,\n ...question.partB\n }\n});\n\n/**\n *\n * @param {*} question\n * @param {*} session\n * @param {*} env\n * @param {*} updateSession - optional - a function that will set the properties passed into it on the session.\n */\nexport async function model(question, session, env, updateSession) {\n const normalizedQuestion = normalize(question);\n const partA = parsePart(normalizedQuestion.partA, 'partA', session, env);\n const partB = parsePart(normalizedQuestion.partB, 'partB', session, env);\n\n const shuffledValues = {};\n\n const us = part => (id, element, update) =>\n new Promise(resolve => {\n shuffledValues[part] = update.shuffledValues;\n resolve();\n });\n\n const partASession = get(session, 'value.partA');\n const partALockChoiceOrder = lockChoices(normalizedQuestion.partA, partASession, env);\n\n const { choices: partAChoices } = partA || {};\n const { choices: partBChoices } = partB || {};\n\n if (!partALockChoiceOrder && partAChoices && partAChoices.length) {\n partA.choices = await getShuffledChoices(\n partAChoices,\n { shuffledValues: (session.shuffledValues || {}).partA },\n us('partA'),\n 'value'\n );\n }\n\n const partBSession = get(session, 'value.partB');\n const partBLockChoiceOrder = lockChoices(normalizedQuestion.partB, partBSession, env);\n\n if (!partBLockChoiceOrder && partBChoices && partBChoices.length) {\n partB.choices = await getShuffledChoices(\n partBChoices,\n { shuffledValues: (session.shuffledValues || {}).partB },\n us('partB'),\n 'value'\n );\n }\n\n if (!isEmpty(shuffledValues)) {\n if (updateSession && typeof updateSession === 'function') {\n updateSession(session.id, session.element, {\n shuffledValues\n }).catch(e => {\n console.error('update session failed', e);\n });\n }\n }\n\n if (normalizedQuestion.partLabels) {\n partA.partLabel =\n normalizedQuestion.partLabelType === 'Letters' ? 'Part A' : 'Part 1';\n partB.partLabel =\n normalizedQuestion.partLabelType === 'Letters' ? 'Part B' : 'Part 2';\n } else {\n partA.partLabel = undefined;\n partB.partLabel = undefined;\n }\n\n if (\n env.role === 'instructor' &&\n (env.mode === 'view' || env.mode === 'evaluate')\n ) {\n partA.teacherInstructions = normalizedQuestion.partA\n .teacherInstructionsEnabled\n ? normalizedQuestion.partA.teacherInstructions\n : null;\n partB.teacherInstructions = normalizedQuestion.partB\n .teacherInstructionsEnabled\n ? normalizedQuestion.partB.teacherInstructions\n : null;\n } else {\n partA.teacherInstructions = null;\n partB.teacherInstructions = null;\n }\n\n partA.prompt = normalizedQuestion.partA.promptEnabled\n ? normalizedQuestion.partA.prompt\n : null;\n partB.prompt = normalizedQuestion.partB.promptEnabled\n ? normalizedQuestion.partB.prompt\n : null;\n\n return new Promise(resolve => {\n resolve({\n disabled: env.mode !== 'gather',\n mode: env.mode,\n partA,\n partB\n });\n });\n}\n\nexport const createDefaultModel = (model = {}) =>\n new Promise(resolve => {\n resolve({\n ...defaults,\n ...model\n });\n });\n\nconst isCorrect = c => c.correct === true;\n\nconst getScore = (config, sessionPart, key) => {\n const { choices = [] } = (config && config[key]) || {};\n const maxScore = choices.length;\n const { value: sessionPartValue } = sessionPart || {};\n\n const chosen = c => !!(sessionPartValue || []).find(v => v === c.value);\n const correctAndNotChosen = c => isCorrect(c) && !chosen(c);\n const incorrectAndChosen = c => !isCorrect(c) && chosen(c);\n const correctChoices = choices.reduce((total, choice) => {\n if (correctAndNotChosen(choice) || incorrectAndChosen(choice)) {\n return total - 1;\n } else {\n return total;\n }\n }, choices.length);\n\n // determine score for a part\n if (!config.partialScoring && correctChoices < maxScore) {\n return 0;\n }\n\n return parseFloat(maxScore ? (correctChoices / maxScore).toFixed(2) : 0);\n};\n\nexport function outcome(config, session) {\n return new Promise(resolve => {\n const { value } = session || {};\n\n if (!session || !value) {\n resolve({ score: 0, scoreA: 0, scoreB: 0, empty: true });\n }\n\n if (value) {\n const { partA, partB } = value || {};\n\n const scoreA = getScore(config, partA, 'partA');\n const scoreB = getScore(config, partB, 'partB');\n\n if (!config.partialScoring) {\n // The EBSR item is worth 1 point\n // That point is awarded if and only if both parts are fully correct, otherwise no points are awarded\n resolve({ score: (scoreA === 1 && scoreB === 1) ? 1 : 0, scoreA, scoreB, max: 1 });\n } else {\n // The EBSR item is worth 2 points\n if (scoreA === 1) {\n if (scoreB === 1) {\n // If Part A and Part B are both correct, 2 points are awarded\n resolve({ score: 2, scoreA, scoreB, max: 2 });\n } else {\n // If Part A is correct and part B is incorrect, 1 point is awarded\n resolve({ score: 1, scoreA, scoreB, max: 2 });\n }\n } else {\n // For all other combinations, no points are awarded\n resolve({ score: 0, scoreA, scoreB, max: 2 });\n }\n }\n }\n });\n}\n\nconst returnPartCorrect = choices => {\n let answers = [];\n\n choices.forEach(i => {\n const { correct, value } = i;\n if (correct) {\n answers.push(value);\n }\n });\n return answers;\n};\n\nexport const createCorrectResponseSession = (question, env) => {\n return new Promise(resolve => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { partA, partB } = question;\n\n const partACorrect = returnPartCorrect(partA.choices);\n const partBCorrect = returnPartCorrect(partB.choices);\n\n resolve({\n value: {\n partA: {\n id: 'partA',\n value: partACorrect\n },\n partB: {\n id: 'partB',\n value: partBCorrect\n }\n },\n id: '1'\n });\n } else {\n resolve(null);\n }\n });\n};\n"],"file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../src/index.js"],"names":["prepareChoice","model","env","defaultFeedback","choice","out","label","value","role","mode","rationale","rationaleEnabled","correct","feedbackEnabled","feedbackType","feedback","type","parsePart","part","key","session","Object","assign","incorrect","choices","map","disabled","complete","min","filter","c","length","responseCorrect","undefined","normalize","partA","partB","question","partLabels","partLabelType","defaults","promptEnabled","teacherInstructionsEnabled","studentInstructionsEnabled","gridColumns","choicesLayout","verticalMode","updateSession","normalizedQuestion","shuffledValues","us","id","element","update","Promise","resolve","partASession","partALockChoiceOrder","partAChoices","partBChoices","partBSession","partBLockChoiceOrder","e","console","error","partLabel","teacherInstructions","prompt","createDefaultModel","isCorrect","getScore","config","sessionPart","maxScore","sessionPartValue","chosen","find","v","correctAndNotChosen","incorrectAndChosen","correctChoices","reduce","total","partialScoring","parseFloat","toFixed","outcome","score","scoreA","scoreB","empty","max","returnPartCorrect","answers","forEach","i","push","createCorrectResponseSession","partACorrect","partBCorrect","validatePart","minAnswerChoices","maxAnswerChoices","reversedChoices","reverse","choicesErrors","hasCorrectResponse","index","identicalAnswer","slice","some","errors","nbOfChoices","answerChoicesError","correctResponseError","validate","partAConfig","partBConfig","partAErrors","partBErrors"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;;AACA;;AACA;;AACA;;AACA;;;;;;;;AAEA,IAAMA,aAAa,GAAG,SAAhBA,aAAgB,CAACC,KAAD,EAAQC,GAAR,EAAaC,eAAb;AAAA,SAAiC,UAAAC,MAAM,EAAI;AAC/D,QAAMC,GAAG,GAAG;AACVC,MAAAA,KAAK,EAAEF,MAAM,CAACE,KADJ;AAEVC,MAAAA,KAAK,EAAEH,MAAM,CAACG;AAFJ,KAAZ;;AAKA,QACEL,GAAG,CAACM,IAAJ,KAAa,YAAb,KACCN,GAAG,CAACO,IAAJ,KAAa,MAAb,IAAuBP,GAAG,CAACO,IAAJ,KAAa,UADrC,CADF,EAGE;AACAJ,MAAAA,GAAG,CAACK,SAAJ,GAAgBT,KAAK,CAACU,gBAAN,GAAyBP,MAAM,CAACM,SAAhC,GAA4C,IAA5D;AACD,KALD,MAKO;AACLL,MAAAA,GAAG,CAACK,SAAJ,GAAgB,IAAhB;AACD;;AAED,QAAIR,GAAG,CAACO,IAAJ,KAAa,UAAjB,EAA6B;AAC3BJ,MAAAA,GAAG,CAACO,OAAJ,GAAc,CAAC,CAACR,MAAM,CAACQ,OAAvB;;AAEA,UAAIX,KAAK,CAACY,eAAV,EAA2B;AACzB,YAAMC,YAAY,GAAIV,MAAM,CAACW,QAAP,IAAmBX,MAAM,CAACW,QAAP,CAAgBC,IAApC,IAA6C,MAAlE;;AAEA,YAAIF,YAAY,KAAK,SAArB,EAAgC;AAC9BT,UAAAA,GAAG,CAACU,QAAJ,GAAeZ,eAAe,CAACC,MAAM,CAACQ,OAAP,GAAiB,SAAjB,GAA6B,WAA9B,CAA9B;AACD,SAFD,MAEO,IAAIE,YAAY,KAAK,QAArB,EAA+B;AACpCT,UAAAA,GAAG,CAACU,QAAJ,GAAeX,MAAM,CAACW,QAAP,CAAgBR,KAA/B;AACD;AACF;AACF;;AAED,WAAOF,GAAP;AACD,GA9BqB;AAAA,CAAtB;;AAgCA,IAAMY,SAAS,GAAG,SAAZA,SAAY,CAACC,IAAD,EAAOC,GAAP,EAAYC,OAAZ,EAAqBlB,GAArB,EAA6B;AAC7C,MAAMC,eAAe,GAAGkB,MAAM,CAACC,MAAP,CACtB;AAAEV,IAAAA,OAAO,EAAE,SAAX;AAAsBW,IAAAA,SAAS,EAAE;AAAjC,GADsB,EAEtBL,IAAI,CAACf,eAFiB,CAAxB;AAKA,MAAIqB,OAAO,GAAGN,IAAI,CAACM,OAAL,GACVN,IAAI,CAACM,OAAL,CAAaC,GAAb,CAAiBzB,aAAa,CAACkB,IAAD,EAAOhB,GAAP,EAAYC,eAAZ,CAA9B,CADU,GAEV,EAFJ;AAIA,yCACKe,IADL;AAEEM,IAAAA,OAAO,EAAPA,OAFF;AAGEE,IAAAA,QAAQ,EAAExB,GAAG,CAACO,IAAJ,KAAa,QAHzB;AAIEkB,IAAAA,QAAQ,EAAE;AACRC,MAAAA,GAAG,EAAEV,IAAI,CAACM,OAAL,CAAaK,MAAb,CAAoB,UAAAC,CAAC;AAAA,eAAIA,CAAC,CAAClB,OAAN;AAAA,OAArB,EAAoCmB;AADjC,KAJZ;AAOEC,IAAAA,eAAe,EACb9B,GAAG,CAACO,IAAJ,KAAa,UAAb,GACI,8BAAkBS,IAAlB,EAAwBC,GAAxB,EAA6BC,OAA7B,CADJ,GAEIa;AAVR;AAYD,CAtBD;;AAwBO,IAAMC,SAAS,GAAG,SAAZA,SAAY;AAAA,wBAAGC,KAAH;AAAA,MAAGA,KAAH,2BAAW,EAAX;AAAA,wBAAeC,KAAf;AAAA,MAAeA,KAAf,2BAAuB,EAAvB;AAAA,MAA8BC,QAA9B;AAAA;AACvBC,IAAAA,UAAU,EAAE,IADW;AAEvBC,IAAAA,aAAa,EAAE;AAFQ,KAGpBF,QAHoB;AAIvBF,IAAAA,KAAK,gDACAK,qBAASL,KADT;AAEHxB,MAAAA,gBAAgB,EAAE,IAFf;AAGHE,MAAAA,eAAe,EAAE,IAHd;AAIH4B,MAAAA,aAAa,EAAE,IAJZ;AAKHC,MAAAA,0BAA0B,EAAE,IALzB;AAMHC,MAAAA,0BAA0B,EAAE,IANzB;AAOHC,MAAAA,WAAW,EAAE;AAPV,OAQAT,KARA;AASHU,MAAAA,aAAa,EAAEV,KAAK,CAACU,aAAN,IAAwBV,KAAK,CAACW,YAAN,KAAuB,KAAvB,IAAgC,YAAxD,IAAyE;AATrF,MAJkB;AAevBV,IAAAA,KAAK,gDACAI,qBAASJ,KADT;AAEHzB,MAAAA,gBAAgB,EAAE,IAFf;AAGH8B,MAAAA,aAAa,EAAE,IAHZ;AAIH5B,MAAAA,eAAe,EAAE,IAJd;AAKH6B,MAAAA,0BAA0B,EAAE,IALzB;AAMHC,MAAAA,0BAA0B,EAAE,IANzB;AAOHC,MAAAA,WAAW,EAAE;AAPV,OAQAR,KARA;AASHS,MAAAA,aAAa,EAAET,KAAK,CAACS,aAAN,IAAwBT,KAAK,CAACU,YAAN,KAAuB,KAAvB,IAAgC,YAAxD,IAAyE;AATrF;AAfkB;AAAA,CAAlB;AA4BP;AACA;AACA;AACA;AACA;AACA;AACA;;;;;SACsB7C,K;;;;;yFAAf,iBAAqBoC,QAArB,EAA+BjB,OAA/B,EAAwClB,GAAxC,EAA6C6C,aAA7C;AAAA;;AAAA;AAAA;AAAA;AAAA;AACCC,YAAAA,kBADD,GACsBd,SAAS,CAACG,QAAD,CAD/B;AAECF,YAAAA,KAFD,GAESlB,SAAS,CAAC+B,kBAAkB,CAACb,KAApB,EAA2B,OAA3B,EAAoCf,OAApC,EAA6ClB,GAA7C,CAFlB;AAGCkC,YAAAA,KAHD,GAGSnB,SAAS,CAAC+B,kBAAkB,CAACZ,KAApB,EAA2B,OAA3B,EAAoChB,OAApC,EAA6ClB,GAA7C,CAHlB;AAKC+C,YAAAA,cALD,GAKkB,EALlB;;AAOCC,YAAAA,EAPD,GAOM,SAALA,EAAK,CAAAhC,IAAI;AAAA,qBAAI,UAACiC,EAAD,EAAKC,OAAL,EAAcC,MAAd;AAAA,uBACjB,IAAIC,OAAJ,CAAY,UAAAC,OAAO,EAAI;AACrBN,kBAAAA,cAAc,CAAC/B,IAAD,CAAd,GAAuBmC,MAAM,CAACJ,cAA9B;AACAM,kBAAAA,OAAO;AACR,iBAHD,CADiB;AAAA,eAAJ;AAAA,aAPV;;AAaCC,YAAAA,YAbD,GAagB,qBAAIpC,OAAJ,EAAa,aAAb,CAbhB;AAcCqC,YAAAA,oBAdD,GAcwB,kCAAYT,kBAAkB,CAACb,KAA/B,EAAsCqB,YAAtC,EAAoDtD,GAApD,CAdxB;AAAA,oBAgB6BiC,KAAK,IAAI,EAhBtC,EAgBYuB,YAhBZ,SAgBGlC,OAhBH;AAAA,oBAiB6BY,KAAK,IAAI,EAjBtC,EAiBYuB,YAjBZ,SAiBGnC,OAjBH;;AAAA,kBAmBD,CAACiC,oBAAD,IAAyBC,YAAzB,IAAyCA,YAAY,CAAC3B,MAnBrD;AAAA;AAAA;AAAA;;AAAA;AAAA,mBAoBmB,yCACpB2B,YADoB,EAEpB;AAAET,cAAAA,cAAc,EAAE,CAAC7B,OAAO,CAAC6B,cAAR,IAA0B,EAA3B,EAA+Bd;AAAjD,aAFoB,EAGpBe,EAAE,CAAC,OAAD,CAHkB,EAIpB,OAJoB,CApBnB;;AAAA;AAoBHf,YAAAA,KAAK,CAACX,OApBH;;AAAA;AA4BCoC,YAAAA,YA5BD,GA4BgB,qBAAIxC,OAAJ,EAAa,aAAb,CA5BhB;AA6BCyC,YAAAA,oBA7BD,GA6BwB,kCAAYb,kBAAkB,CAACZ,KAA/B,EAAsCwB,YAAtC,EAAoD1D,GAApD,CA7BxB;;AAAA,kBA+BD,CAAC2D,oBAAD,IAAyBF,YAAzB,IAAyCA,YAAY,CAAC5B,MA/BrD;AAAA;AAAA;AAAA;;AAAA;AAAA,mBAgCmB,yCACpB4B,YADoB,EAEpB;AAAEV,cAAAA,cAAc,EAAE,CAAC7B,OAAO,CAAC6B,cAAR,IAA0B,EAA3B,EAA+Bb;AAAjD,aAFoB,EAGpBc,EAAE,CAAC,OAAD,CAHkB,EAIpB,OAJoB,CAhCnB;;AAAA;AAgCHd,YAAAA,KAAK,CAACZ,OAhCH;;AAAA;AAwCL,gBAAI,CAAC,yBAAQyB,cAAR,CAAL,EAA8B;AAC5B,kBAAIF,aAAa,IAAI,OAAOA,aAAP,KAAyB,UAA9C,EAA0D;AACxDA,gBAAAA,aAAa,CAAC3B,OAAO,CAAC+B,EAAT,EAAa/B,OAAO,CAACgC,OAArB,EAA8B;AACzCH,kBAAAA,cAAc,EAAdA;AADyC,iBAA9B,CAAb,UAES,UAAAa,CAAC,EAAI;AACZC,kBAAAA,OAAO,CAACC,KAAR,CAAc,uBAAd,EAAuCF,CAAvC;AACD,iBAJD;AAKD;AACF;;AAED,gBAAId,kBAAkB,CAACV,UAAvB,EAAmC;AACjCH,cAAAA,KAAK,CAAC8B,SAAN,GACEjB,kBAAkB,CAACT,aAAnB,KAAqC,SAArC,GAAiD,QAAjD,GAA4D,QAD9D;AAEAH,cAAAA,KAAK,CAAC6B,SAAN,GACEjB,kBAAkB,CAACT,aAAnB,KAAqC,SAArC,GAAiD,QAAjD,GAA4D,QAD9D;AAED,aALD,MAKO;AACLJ,cAAAA,KAAK,CAAC8B,SAAN,GAAkBhC,SAAlB;AACAG,cAAAA,KAAK,CAAC6B,SAAN,GAAkBhC,SAAlB;AACD;;AAED,gBACE/B,GAAG,CAACM,IAAJ,KAAa,YAAb,KACCN,GAAG,CAACO,IAAJ,KAAa,MAAb,IAAuBP,GAAG,CAACO,IAAJ,KAAa,UADrC,CADF,EAGE;AACA0B,cAAAA,KAAK,CAAC+B,mBAAN,GAA4BlB,kBAAkB,CAACb,KAAnB,CACzBO,0BADyB,GAExBM,kBAAkB,CAACb,KAAnB,CAAyB+B,mBAFD,GAGxB,IAHJ;AAIA9B,cAAAA,KAAK,CAAC8B,mBAAN,GAA4BlB,kBAAkB,CAACZ,KAAnB,CACzBM,0BADyB,GAExBM,kBAAkB,CAACZ,KAAnB,CAAyB8B,mBAFD,GAGxB,IAHJ;AAID,aAZD,MAYO;AACL/B,cAAAA,KAAK,CAAC+B,mBAAN,GAA4B,IAA5B;AACA9B,cAAAA,KAAK,CAAC8B,mBAAN,GAA4B,IAA5B;AACD;;AAED/B,YAAAA,KAAK,CAACgC,MAAN,GAAenB,kBAAkB,CAACb,KAAnB,CAAyBM,aAAzB,GACXO,kBAAkB,CAACb,KAAnB,CAAyBgC,MADd,GAEX,IAFJ;AAGA/B,YAAAA,KAAK,CAAC+B,MAAN,GAAenB,kBAAkB,CAACZ,KAAnB,CAAyBK,aAAzB,GACXO,kBAAkB,CAACZ,KAAnB,CAAyB+B,MADd,GAEX,IAFJ;AAhFK,6CAoFE,IAAIb,OAAJ,CAAY,UAAAC,OAAO,EAAI;AAC5BA,cAAAA,OAAO,CAAC;AACN7B,gBAAAA,QAAQ,EAAExB,GAAG,CAACO,IAAJ,KAAa,QADjB;AAENA,gBAAAA,IAAI,EAAEP,GAAG,CAACO,IAFJ;AAGN0B,gBAAAA,KAAK,EAALA,KAHM;AAINC,gBAAAA,KAAK,EAALA;AAJM,eAAD,CAAP;AAMD,aAPM,CApFF;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,G;;;;AA8FA,IAAMgC,kBAAkB,GAAG,SAArBA,kBAAqB;AAAA,MAACnE,KAAD,uEAAS,EAAT;AAAA,SAChC,IAAIqD,OAAJ,CAAY,UAAAC,OAAO,EAAI;AACrBA,IAAAA,OAAO,iCACFf,oBADE,GAEFvC,KAFE,EAAP;AAID,GALD,CADgC;AAAA,CAA3B;;;;AAQP,IAAMoE,SAAS,GAAG,SAAZA,SAAY,CAAAvC,CAAC;AAAA,SAAIA,CAAC,CAAClB,OAAF,KAAc,IAAlB;AAAA,CAAnB;;AAEA,IAAM0D,QAAQ,GAAG,SAAXA,QAAW,CAACC,MAAD,EAASC,WAAT,EAAsBrD,GAAtB,EAA8B;AAC7C,cAA0BoD,MAAM,IAAIA,MAAM,CAACpD,GAAD,CAAjB,IAA2B,EAApD;AAAA,4BAAQK,OAAR;AAAA,MAAQA,OAAR,8BAAkB,EAAlB;;AACA,MAAMiD,QAAQ,GAAGjD,OAAO,CAACO,MAAzB;;AACA,cAAoCyC,WAAW,IAAI,EAAnD;AAAA,MAAeE,gBAAf,SAAQnE,KAAR;;AAEA,MAAMoE,MAAM,GAAG,SAATA,MAAS,CAAA7C,CAAC;AAAA,WAAI,CAAC,CAAC,CAAC4C,gBAAgB,IAAI,EAArB,EAAyBE,IAAzB,CAA8B,UAAAC,CAAC;AAAA,aAAIA,CAAC,KAAK/C,CAAC,CAACvB,KAAZ;AAAA,KAA/B,CAAN;AAAA,GAAhB;;AACA,MAAMuE,mBAAmB,GAAG,SAAtBA,mBAAsB,CAAAhD,CAAC;AAAA,WAAIuC,SAAS,CAACvC,CAAD,CAAT,IAAgB,CAAC6C,MAAM,CAAC7C,CAAD,CAA3B;AAAA,GAA7B;;AACA,MAAMiD,kBAAkB,GAAG,SAArBA,kBAAqB,CAAAjD,CAAC;AAAA,WAAI,CAACuC,SAAS,CAACvC,CAAD,CAAV,IAAiB6C,MAAM,CAAC7C,CAAD,CAA3B;AAAA,GAA5B;;AACA,MAAMkD,cAAc,GAAGxD,OAAO,CAACyD,MAAR,CAAe,UAACC,KAAD,EAAQ9E,MAAR,EAAmB;AACvD,QAAI0E,mBAAmB,CAAC1E,MAAD,CAAnB,IAA+B2E,kBAAkB,CAAC3E,MAAD,CAArD,EAA+D;AAC7D,aAAO8E,KAAK,GAAG,CAAf;AACD,KAFD,MAEO;AACL,aAAOA,KAAP;AACD;AACF,GANsB,EAMpB1D,OAAO,CAACO,MANY,CAAvB,CAR6C,CAgB7C;;AACA,MAAI,CAACwC,MAAM,CAACY,cAAR,IAA0BH,cAAc,GAAGP,QAA/C,EAAyD;AACvD,WAAO,CAAP;AACD;;AAED,SAAOW,UAAU,CAACX,QAAQ,GAAG,CAACO,cAAc,GAAGP,QAAlB,EAA4BY,OAA5B,CAAoC,CAApC,CAAH,GAA4C,CAArD,CAAjB;AACD,CAtBD;;AAwBO,SAASC,OAAT,CAAiBf,MAAjB,EAAyBnD,OAAzB,EAAkC;AACvC,SAAO,IAAIkC,OAAJ,CAAY,UAAAC,OAAO,EAAI;AAC5B,gBAAkBnC,OAAO,IAAI,EAA7B;AAAA,QAAQb,KAAR,SAAQA,KAAR;;AAEA,QAAI,CAACa,OAAD,IAAY,CAACb,KAAjB,EAAwB;AACtBgD,MAAAA,OAAO,CAAC;AAAEgC,QAAAA,KAAK,EAAE,CAAT;AAAYC,QAAAA,MAAM,EAAE,CAApB;AAAuBC,QAAAA,MAAM,EAAE,CAA/B;AAAkCC,QAAAA,KAAK,EAAE;AAAzC,OAAD,CAAP;AACD;;AAED,QAAInF,KAAJ,EAAW;AACT,kBAAyBA,KAAK,IAAI,EAAlC;AAAA,UAAQ4B,KAAR,SAAQA,KAAR;AAAA,UAAeC,KAAf,SAAeA,KAAf;;AAEA,UAAMoD,MAAM,GAAGlB,QAAQ,CAACC,MAAD,EAASpC,KAAT,EAAgB,OAAhB,CAAvB;AACA,UAAMsD,MAAM,GAAGnB,QAAQ,CAACC,MAAD,EAASnC,KAAT,EAAgB,OAAhB,CAAvB;;AAEA,UAAI,CAACmC,MAAM,CAACY,cAAZ,EAA4B;AAC1B;AACA;AACA5B,QAAAA,OAAO,CAAC;AAAEgC,UAAAA,KAAK,EAAGC,MAAM,KAAK,CAAX,IAAgBC,MAAM,KAAK,CAA5B,GAAiC,CAAjC,GAAqC,CAA9C;AAAiDD,UAAAA,MAAM,EAANA,MAAjD;AAAyDC,UAAAA,MAAM,EAANA,MAAzD;AAAiEE,UAAAA,GAAG,EAAE;AAAtE,SAAD,CAAP;AACD,OAJD,MAIO;AACL;AACA,YAAIH,MAAM,KAAK,CAAf,EAAkB;AAChB,cAAIC,MAAM,KAAK,CAAf,EAAkB;AAChB;AACAlC,YAAAA,OAAO,CAAC;AAAEgC,cAAAA,KAAK,EAAE,CAAT;AAAYC,cAAAA,MAAM,EAANA,MAAZ;AAAoBC,cAAAA,MAAM,EAANA,MAApB;AAA4BE,cAAAA,GAAG,EAAE;AAAjC,aAAD,CAAP;AACD,WAHD,MAGO;AACL;AACApC,YAAAA,OAAO,CAAC;AAAEgC,cAAAA,KAAK,EAAE,CAAT;AAAYC,cAAAA,MAAM,EAANA,MAAZ;AAAoBC,cAAAA,MAAM,EAANA,MAApB;AAA4BE,cAAAA,GAAG,EAAE;AAAjC,aAAD,CAAP;AACD;AACF,SARD,MAQO;AACL;AACApC,UAAAA,OAAO,CAAC;AAAEgC,YAAAA,KAAK,EAAE,CAAT;AAAYC,YAAAA,MAAM,EAANA,MAAZ;AAAoBC,YAAAA,MAAM,EAANA,MAApB;AAA4BE,YAAAA,GAAG,EAAE;AAAjC,WAAD,CAAP;AACD;AACF;AACF;AACF,GAjCM,CAAP;AAkCD;;AAED,IAAMC,iBAAiB,GAAG,SAApBA,iBAAoB,CAAApE,OAAO,EAAI;AACnC,MAAIqE,OAAO,GAAG,EAAd;AAEArE,EAAAA,OAAO,CAACsE,OAAR,CAAgB,UAAAC,CAAC,EAAI;AACnB,QAAQnF,OAAR,GAA2BmF,CAA3B,CAAQnF,OAAR;AAAA,QAAiBL,KAAjB,GAA2BwF,CAA3B,CAAiBxF,KAAjB;;AACA,QAAIK,OAAJ,EAAa;AACXiF,MAAAA,OAAO,CAACG,IAAR,CAAazF,KAAb;AACD;AACF,GALD;AAMA,SAAOsF,OAAP;AACD,CAVD;;AAYO,IAAMI,4BAA4B,GAAG,SAA/BA,4BAA+B,CAAC5D,QAAD,EAAWnC,GAAX,EAAmB;AAC7D,SAAO,IAAIoD,OAAJ,CAAY,UAAAC,OAAO,EAAI;AAC5B,QAAIrD,GAAG,CAACO,IAAJ,KAAa,UAAb,IAA2BP,GAAG,CAACM,IAAJ,KAAa,YAA5C,EAA0D;AACxD,UAAQ2B,KAAR,GAAyBE,QAAzB,CAAQF,KAAR;AAAA,UAAeC,KAAf,GAAyBC,QAAzB,CAAeD,KAAf;AAEA,UAAM8D,YAAY,GAAGN,iBAAiB,CAACzD,KAAK,CAACX,OAAP,CAAtC;AACA,UAAM2E,YAAY,GAAGP,iBAAiB,CAACxD,KAAK,CAACZ,OAAP,CAAtC;AAEA+B,MAAAA,OAAO,CAAC;AACNhD,QAAAA,KAAK,EAAE;AACL4B,UAAAA,KAAK,EAAE;AACLgB,YAAAA,EAAE,EAAE,OADC;AAEL5C,YAAAA,KAAK,EAAE2F;AAFF,WADF;AAKL9D,UAAAA,KAAK,EAAE;AACLe,YAAAA,EAAE,EAAE,OADC;AAEL5C,YAAAA,KAAK,EAAE4F;AAFF;AALF,SADD;AAWNhD,QAAAA,EAAE,EAAE;AAXE,OAAD,CAAP;AAaD,KAnBD,MAmBO;AACLI,MAAAA,OAAO,CAAC,IAAD,CAAP;AACD;AACF,GAvBM,CAAP;AAwBD,CAzBM;;;;AA2BP,IAAM6C,YAAY,GAAG,SAAfA,YAAe,GAA6B;AAAA,MAA5BnG,KAA4B,uEAApB,EAAoB;AAAA,MAAhBsE,MAAgB,uEAAP,EAAO;AAChD,MAAQ/C,OAAR,GAAoBvB,KAApB,CAAQuB,OAAR;AACA,8BAAmD+C,MAAnD,CAAQ8B,gBAAR;AAAA,MAAQA,gBAAR,sCAA2B,CAA3B;AAAA,MAA8BC,gBAA9B,GAAmD/B,MAAnD,CAA8B+B,gBAA9B;AACA,MAAMC,eAAe,GAAG,oCAAI/E,OAAO,IAAI,EAAf,EAAmBgF,OAAnB,EAAxB;AACA,MAAMC,aAAa,GAAG,EAAtB;AACA,MAAIC,kBAAkB,GAAG,KAAzB;AAEAH,EAAAA,eAAe,CAACT,OAAhB,CAAwB,UAAC1F,MAAD,EAASuG,KAAT,EAAmB;AACzC,QAAQ/F,OAAR,GAAkCR,MAAlC,CAAQQ,OAAR;AAAA,QAAiBL,KAAjB,GAAkCH,MAAlC,CAAiBG,KAAjB;AAAA,QAAwBD,KAAxB,GAAkCF,MAAlC,CAAwBE,KAAxB;;AAEA,QAAIM,OAAJ,EAAa;AACX8F,MAAAA,kBAAkB,GAAG,IAArB;AACD;;AAED,QAAIpG,KAAK,KAAK,EAAV,IAAgBA,KAAK,KAAK,aAA9B,EAA6C;AAC3CmG,MAAAA,aAAa,CAAClG,KAAD,CAAb,GAAuB,8BAAvB;AACD,KAFD,MAEO;AACL,UAAMqG,eAAe,GAAGL,eAAe,CAACM,KAAhB,CAAsBF,KAAK,GAAG,CAA9B,EAAiCG,IAAjC,CAAsC,UAAAhF,CAAC;AAAA,eAAIA,CAAC,CAACxB,KAAF,KAAYA,KAAhB;AAAA,OAAvC,CAAxB;;AAEA,UAAIsG,eAAJ,EAAqB;AACnBH,QAAAA,aAAa,CAAClG,KAAD,CAAb,GAAuB,2BAAvB;AACD;AACF;AACF,GAhBD;AAkBA,MAAMwG,MAAM,GAAG,EAAf;AACA,MAAMC,WAAW,GAAG,CAACxF,OAAO,IAAI,EAAZ,EAAgBO,MAApC;;AAEA,MAAIiF,WAAW,GAAGX,gBAAlB,EAAoC;AAClCU,IAAAA,MAAM,CAACE,kBAAP,sCAAwDZ,gBAAxD;AACD,GAFD,MAEO,IAAIW,WAAW,GAAGV,gBAAlB,EAAoC;AACzCS,IAAAA,MAAM,CAACE,kBAAP,0BAA4CX,gBAA5C;AACD;;AAED,MAAI,CAACI,kBAAL,EAAyB;AACvBK,IAAAA,MAAM,CAACG,oBAAP,GAA8B,8BAA9B;AACD;;AAED,MAAI,CAAC,yBAAQT,aAAR,CAAL,EAA6B;AAC3BM,IAAAA,MAAM,CAACN,aAAP,GAAuBA,aAAvB;AACD;;AAED,SAAOM,MAAP;AACD,CA3CD;;AA6CO,IAAMI,QAAQ,GAAG,SAAXA,QAAW,GAA6B;AAAA,MAA5BlH,KAA4B,uEAApB,EAAoB;AAAA,MAAhBsE,MAAgB,uEAAP,EAAO;;AACnD,cAAyBtE,KAAK,IAAI,EAAlC;AAAA,MAAQkC,KAAR,SAAQA,KAAR;AAAA,MAAeC,KAAf,SAAeA,KAAf;;AACA,cAAmDmC,MAAM,IAAI,EAA7D;AAAA,MAAe6C,WAAf,SAAQjF,KAAR;AAAA,MAAmCkF,WAAnC,SAA4BjF,KAA5B;;AAEA,MAAMkF,WAAW,GAAGlB,YAAY,CAACjE,KAAD,EAAQiF,WAAR,CAAhC;AACA,MAAMG,WAAW,GAAGnB,YAAY,CAAChE,KAAD,EAAQiF,WAAR,CAAhC;AAEA,SAAO;AAAElF,IAAAA,KAAK,EAAEmF,WAAT;AAAsBlF,IAAAA,KAAK,EAAEmF;AAA7B,GAAP;AACD,CARM","sourcesContent":["import defaults from './defaults';\nimport { lockChoices, getShuffledChoices } from '@pie-lib/controller-utils';\nimport { isResponseCorrect } from './utils';\nimport get from 'lodash/get';\nimport isEmpty from 'lodash/isEmpty';\n\nconst prepareChoice = (model, env, defaultFeedback) => choice => {\n const out = {\n label: choice.label,\n value: choice.value\n };\n\n if (\n env.role === 'instructor' &&\n (env.mode === 'view' || env.mode === 'evaluate')\n ) {\n out.rationale = model.rationaleEnabled ? choice.rationale : null;\n } else {\n out.rationale = null;\n }\n\n if (env.mode === 'evaluate') {\n out.correct = !!choice.correct;\n\n if (model.feedbackEnabled) {\n const feedbackType = (choice.feedback && choice.feedback.type) || 'none';\n\n if (feedbackType === 'default') {\n out.feedback = defaultFeedback[choice.correct ? 'correct' : 'incorrect'];\n } else if (feedbackType === 'custom') {\n out.feedback = choice.feedback.value;\n }\n }\n }\n\n return out;\n};\n\nconst parsePart = (part, key, session, env) => {\n const defaultFeedback = Object.assign(\n { correct: 'Correct', incorrect: 'Incorrect' },\n part.defaultFeedback\n );\n\n let choices = part.choices\n ? part.choices.map(prepareChoice(part, env, defaultFeedback))\n : [];\n\n return {\n ...part,\n choices,\n disabled: env.mode !== 'gather',\n complete: {\n min: part.choices.filter(c => c.correct).length\n },\n responseCorrect:\n env.mode === 'evaluate'\n ? isResponseCorrect(part, key, session)\n : undefined\n };\n};\n\nexport const normalize = ({ partA = {}, partB = {}, ...question }) => ({\n partLabels: true,\n partLabelType: 'Letters',\n ...question,\n partA: {\n ...defaults.partA,\n rationaleEnabled: true,\n feedbackEnabled: true,\n promptEnabled: true,\n teacherInstructionsEnabled: true,\n studentInstructionsEnabled: true,\n gridColumns: '2',\n ...partA,\n choicesLayout: partA.choicesLayout || (partA.verticalMode === false && 'horizontal') || 'vertical'\n },\n partB: {\n ...defaults.partB,\n rationaleEnabled: true,\n promptEnabled: true,\n feedbackEnabled: true,\n teacherInstructionsEnabled: true,\n studentInstructionsEnabled: true,\n gridColumns: '2',\n ...partB,\n choicesLayout: partB.choicesLayout || (partB.verticalMode === false && 'horizontal') || 'vertical'\n }\n});\n\n/**\n *\n * @param {*} question\n * @param {*} session\n * @param {*} env\n * @param {*} updateSession - optional - a function that will set the properties passed into it on the session.\n */\nexport async function model(question, session, env, updateSession) {\n const normalizedQuestion = normalize(question);\n const partA = parsePart(normalizedQuestion.partA, 'partA', session, env);\n const partB = parsePart(normalizedQuestion.partB, 'partB', session, env);\n\n const shuffledValues = {};\n\n const us = part => (id, element, update) =>\n new Promise(resolve => {\n shuffledValues[part] = update.shuffledValues;\n resolve();\n });\n\n const partASession = get(session, 'value.partA');\n const partALockChoiceOrder = lockChoices(normalizedQuestion.partA, partASession, env);\n\n const { choices: partAChoices } = partA || {};\n const { choices: partBChoices } = partB || {};\n\n if (!partALockChoiceOrder && partAChoices && partAChoices.length) {\n partA.choices = await getShuffledChoices(\n partAChoices,\n { shuffledValues: (session.shuffledValues || {}).partA },\n us('partA'),\n 'value'\n );\n }\n\n const partBSession = get(session, 'value.partB');\n const partBLockChoiceOrder = lockChoices(normalizedQuestion.partB, partBSession, env);\n\n if (!partBLockChoiceOrder && partBChoices && partBChoices.length) {\n partB.choices = await getShuffledChoices(\n partBChoices,\n { shuffledValues: (session.shuffledValues || {}).partB },\n us('partB'),\n 'value'\n );\n }\n\n if (!isEmpty(shuffledValues)) {\n if (updateSession && typeof updateSession === 'function') {\n updateSession(session.id, session.element, {\n shuffledValues\n }).catch(e => {\n console.error('update session failed', e);\n });\n }\n }\n\n if (normalizedQuestion.partLabels) {\n partA.partLabel =\n normalizedQuestion.partLabelType === 'Letters' ? 'Part A' : 'Part 1';\n partB.partLabel =\n normalizedQuestion.partLabelType === 'Letters' ? 'Part B' : 'Part 2';\n } else {\n partA.partLabel = undefined;\n partB.partLabel = undefined;\n }\n\n if (\n env.role === 'instructor' &&\n (env.mode === 'view' || env.mode === 'evaluate')\n ) {\n partA.teacherInstructions = normalizedQuestion.partA\n .teacherInstructionsEnabled\n ? normalizedQuestion.partA.teacherInstructions\n : null;\n partB.teacherInstructions = normalizedQuestion.partB\n .teacherInstructionsEnabled\n ? normalizedQuestion.partB.teacherInstructions\n : null;\n } else {\n partA.teacherInstructions = null;\n partB.teacherInstructions = null;\n }\n\n partA.prompt = normalizedQuestion.partA.promptEnabled\n ? normalizedQuestion.partA.prompt\n : null;\n partB.prompt = normalizedQuestion.partB.promptEnabled\n ? normalizedQuestion.partB.prompt\n : null;\n\n return new Promise(resolve => {\n resolve({\n disabled: env.mode !== 'gather',\n mode: env.mode,\n partA,\n partB\n });\n });\n}\n\nexport const createDefaultModel = (model = {}) =>\n new Promise(resolve => {\n resolve({\n ...defaults,\n ...model\n });\n });\n\nconst isCorrect = c => c.correct === true;\n\nconst getScore = (config, sessionPart, key) => {\n const { choices = [] } = (config && config[key]) || {};\n const maxScore = choices.length;\n const { value: sessionPartValue } = sessionPart || {};\n\n const chosen = c => !!(sessionPartValue || []).find(v => v === c.value);\n const correctAndNotChosen = c => isCorrect(c) && !chosen(c);\n const incorrectAndChosen = c => !isCorrect(c) && chosen(c);\n const correctChoices = choices.reduce((total, choice) => {\n if (correctAndNotChosen(choice) || incorrectAndChosen(choice)) {\n return total - 1;\n } else {\n return total;\n }\n }, choices.length);\n\n // determine score for a part\n if (!config.partialScoring && correctChoices < maxScore) {\n return 0;\n }\n\n return parseFloat(maxScore ? (correctChoices / maxScore).toFixed(2) : 0);\n};\n\nexport function outcome(config, session) {\n return new Promise(resolve => {\n const { value } = session || {};\n\n if (!session || !value) {\n resolve({ score: 0, scoreA: 0, scoreB: 0, empty: true });\n }\n\n if (value) {\n const { partA, partB } = value || {};\n\n const scoreA = getScore(config, partA, 'partA');\n const scoreB = getScore(config, partB, 'partB');\n\n if (!config.partialScoring) {\n // The EBSR item is worth 1 point\n // That point is awarded if and only if both parts are fully correct, otherwise no points are awarded\n resolve({ score: (scoreA === 1 && scoreB === 1) ? 1 : 0, scoreA, scoreB, max: 1 });\n } else {\n // The EBSR item is worth 2 points\n if (scoreA === 1) {\n if (scoreB === 1) {\n // If Part A and Part B are both correct, 2 points are awarded\n resolve({ score: 2, scoreA, scoreB, max: 2 });\n } else {\n // If Part A is correct and part B is incorrect, 1 point is awarded\n resolve({ score: 1, scoreA, scoreB, max: 2 });\n }\n } else {\n // For all other combinations, no points are awarded\n resolve({ score: 0, scoreA, scoreB, max: 2 });\n }\n }\n }\n });\n}\n\nconst returnPartCorrect = choices => {\n let answers = [];\n\n choices.forEach(i => {\n const { correct, value } = i;\n if (correct) {\n answers.push(value);\n }\n });\n return answers;\n};\n\nexport const createCorrectResponseSession = (question, env) => {\n return new Promise(resolve => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { partA, partB } = question;\n\n const partACorrect = returnPartCorrect(partA.choices);\n const partBCorrect = returnPartCorrect(partB.choices);\n\n resolve({\n value: {\n partA: {\n id: 'partA',\n value: partACorrect\n },\n partB: {\n id: 'partB',\n value: partBCorrect\n }\n },\n id: '1'\n });\n } else {\n resolve(null);\n }\n });\n};\n\nconst validatePart = (model = {}, config = {}) => {\n const { choices } = model;\n const { minAnswerChoices = 2, maxAnswerChoices } = config;\n const reversedChoices = [...choices || []].reverse();\n const choicesErrors = {};\n let hasCorrectResponse = false;\n\n reversedChoices.forEach((choice, index) => {\n const { correct, value, label } = choice;\n\n if (correct) {\n hasCorrectResponse = true;\n }\n\n if (label === '' || label === '<div></div>') {\n choicesErrors[value] = 'Content should not be empty.';\n } else {\n const identicalAnswer = reversedChoices.slice(index + 1).some(c => c.label === label);\n\n if (identicalAnswer) {\n choicesErrors[value] = 'Content should be unique.';\n }\n }\n });\n\n const errors = {};\n const nbOfChoices = (choices || []).length;\n\n if (nbOfChoices < minAnswerChoices) {\n errors.answerChoicesError = `There should be at least ${minAnswerChoices} choices defined.`;\n } else if (nbOfChoices > maxAnswerChoices) {\n errors.answerChoicesError = `No more than ${maxAnswerChoices} choices should be defined.`;\n }\n\n if (!hasCorrectResponse) {\n errors.correctResponseError = 'No correct response defined.';\n }\n\n if (!isEmpty(choicesErrors)) {\n errors.choicesErrors = choicesErrors;\n }\n\n return errors;\n};\n\nexport const validate = (model = {}, config = {}) => {\n const { partA, partB } = model || {};\n const { partA: partAConfig, partB: partBConfig } = config || {};\n\n const partAErrors = validatePart(partA, partAConfig);\n const partBErrors = validatePart(partB, partBConfig);\n\n return { partA: partAErrors, partB: partBErrors };\n};\n"],"file":"index.js"}
|
package/controller/package.json
CHANGED
package/controller/src/index.js
CHANGED
|
@@ -60,7 +60,7 @@ const parsePart = (part, key, session, env) => {
|
|
|
60
60
|
};
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
export const normalize = question => ({
|
|
63
|
+
export const normalize = ({ partA = {}, partB = {}, ...question }) => ({
|
|
64
64
|
partLabels: true,
|
|
65
65
|
partLabelType: 'Letters',
|
|
66
66
|
...question,
|
|
@@ -71,8 +71,9 @@ export const normalize = question => ({
|
|
|
71
71
|
promptEnabled: true,
|
|
72
72
|
teacherInstructionsEnabled: true,
|
|
73
73
|
studentInstructionsEnabled: true,
|
|
74
|
-
|
|
75
|
-
...
|
|
74
|
+
gridColumns: '2',
|
|
75
|
+
...partA,
|
|
76
|
+
choicesLayout: partA.choicesLayout || (partA.verticalMode === false && 'horizontal') || 'vertical'
|
|
76
77
|
},
|
|
77
78
|
partB: {
|
|
78
79
|
...defaults.partB,
|
|
@@ -81,8 +82,9 @@ export const normalize = question => ({
|
|
|
81
82
|
feedbackEnabled: true,
|
|
82
83
|
teacherInstructionsEnabled: true,
|
|
83
84
|
studentInstructionsEnabled: true,
|
|
84
|
-
|
|
85
|
-
...
|
|
85
|
+
gridColumns: '2',
|
|
86
|
+
...partB,
|
|
87
|
+
choicesLayout: partB.choicesLayout || (partB.verticalMode === false && 'horizontal') || 'vertical'
|
|
86
88
|
}
|
|
87
89
|
});
|
|
88
90
|
|
|
@@ -296,3 +298,58 @@ export const createCorrectResponseSession = (question, env) => {
|
|
|
296
298
|
}
|
|
297
299
|
});
|
|
298
300
|
};
|
|
301
|
+
|
|
302
|
+
const validatePart = (model = {}, config = {}) => {
|
|
303
|
+
const { choices } = model;
|
|
304
|
+
const { minAnswerChoices = 2, maxAnswerChoices } = config;
|
|
305
|
+
const reversedChoices = [...choices || []].reverse();
|
|
306
|
+
const choicesErrors = {};
|
|
307
|
+
let hasCorrectResponse = false;
|
|
308
|
+
|
|
309
|
+
reversedChoices.forEach((choice, index) => {
|
|
310
|
+
const { correct, value, label } = choice;
|
|
311
|
+
|
|
312
|
+
if (correct) {
|
|
313
|
+
hasCorrectResponse = true;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (label === '' || label === '<div></div>') {
|
|
317
|
+
choicesErrors[value] = 'Content should not be empty.';
|
|
318
|
+
} else {
|
|
319
|
+
const identicalAnswer = reversedChoices.slice(index + 1).some(c => c.label === label);
|
|
320
|
+
|
|
321
|
+
if (identicalAnswer) {
|
|
322
|
+
choicesErrors[value] = 'Content should be unique.';
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
const errors = {};
|
|
328
|
+
const nbOfChoices = (choices || []).length;
|
|
329
|
+
|
|
330
|
+
if (nbOfChoices < minAnswerChoices) {
|
|
331
|
+
errors.answerChoicesError = `There should be at least ${minAnswerChoices} choices defined.`;
|
|
332
|
+
} else if (nbOfChoices > maxAnswerChoices) {
|
|
333
|
+
errors.answerChoicesError = `No more than ${maxAnswerChoices} choices should be defined.`;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (!hasCorrectResponse) {
|
|
337
|
+
errors.correctResponseError = 'No correct response defined.';
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (!isEmpty(choicesErrors)) {
|
|
341
|
+
errors.choicesErrors = choicesErrors;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return errors;
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
export const validate = (model = {}, config = {}) => {
|
|
348
|
+
const { partA, partB } = model || {};
|
|
349
|
+
const { partA: partAConfig, partB: partBConfig } = config || {};
|
|
350
|
+
|
|
351
|
+
const partAErrors = validatePart(partA, partAConfig);
|
|
352
|
+
const partBErrors = validatePart(partB, partBConfig);
|
|
353
|
+
|
|
354
|
+
return { partA: partAErrors, partB: partBErrors };
|
|
355
|
+
};
|