@pie-element/graphing-solution-set 4.0.1 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/configure/CHANGELOG.md +19 -0
- package/configure/package.json +5 -5
- package/controller/CHANGELOG.md +16 -0
- package/controller/package.json +1 -1
- package/package.json +8 -25
- package/esm/configure.js +0 -14451
- package/esm/configure.js.map +0 -1
- package/esm/controller.js +0 -690
- package/esm/controller.js.map +0 -1
- package/esm/element.js +0 -8504
- package/esm/element.js.map +0 -1
package/esm/controller.js
DELETED
|
@@ -1,690 +0,0 @@
|
|
|
1
|
-
import debug from 'debug';
|
|
2
|
-
import cloneDeep from 'lodash/cloneDeep';
|
|
3
|
-
import uniqWith from 'lodash/uniqWith';
|
|
4
|
-
import isEmpty from 'lodash/isEmpty';
|
|
5
|
-
import isEqual from 'lodash/isEqual';
|
|
6
|
-
import lodash from 'lodash';
|
|
7
|
-
import differenceWith from 'lodash/differenceWith';
|
|
8
|
-
|
|
9
|
-
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
10
|
-
if (source == null) return {};
|
|
11
|
-
var target = {};
|
|
12
|
-
var sourceKeys = Object.keys(source);
|
|
13
|
-
var key, i;
|
|
14
|
-
|
|
15
|
-
for (i = 0; i < sourceKeys.length; i++) {
|
|
16
|
-
key = sourceKeys[i];
|
|
17
|
-
if (excluded.indexOf(key) >= 0) continue;
|
|
18
|
-
target[key] = source[key];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return target;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function _objectWithoutProperties(source, excluded) {
|
|
25
|
-
if (source == null) return {};
|
|
26
|
-
var target = _objectWithoutPropertiesLoose(source, excluded);
|
|
27
|
-
var key, i;
|
|
28
|
-
|
|
29
|
-
if (Object.getOwnPropertySymbols) {
|
|
30
|
-
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
|
|
31
|
-
|
|
32
|
-
for (i = 0; i < sourceSymbolKeys.length; i++) {
|
|
33
|
-
key = sourceSymbolKeys[i];
|
|
34
|
-
if (excluded.indexOf(key) >= 0) continue;
|
|
35
|
-
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
|
|
36
|
-
target[key] = source[key];
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return target;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function _defineProperty(obj, key, value) {
|
|
44
|
-
if (key in obj) {
|
|
45
|
-
Object.defineProperty(obj, key, {
|
|
46
|
-
value: value,
|
|
47
|
-
enumerable: true,
|
|
48
|
-
configurable: true,
|
|
49
|
-
writable: true
|
|
50
|
-
});
|
|
51
|
-
} else {
|
|
52
|
-
obj[key] = value;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return obj;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/*
|
|
59
|
-
* This file contains the default configuration for the Graphing Solution Set Item Type.
|
|
60
|
-
* Model is similar to the one used in graphing item type except for the gssLineData object which handles
|
|
61
|
-
* the configuration for the lines and the solution set.
|
|
62
|
-
*
|
|
63
|
-
* Same model is used in configure/src default.js
|
|
64
|
-
* */
|
|
65
|
-
var defaults = {
|
|
66
|
-
answers: {
|
|
67
|
-
correctAnswer: {
|
|
68
|
-
name: 'Correct Answer',
|
|
69
|
-
marks: []
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
arrows: {
|
|
73
|
-
left: true,
|
|
74
|
-
right: true,
|
|
75
|
-
up: true,
|
|
76
|
-
down: true
|
|
77
|
-
},
|
|
78
|
-
marks: [],
|
|
79
|
-
defaultGridConfiguration: 0,
|
|
80
|
-
domain: {
|
|
81
|
-
min: -5,
|
|
82
|
-
max: 5,
|
|
83
|
-
step: 1,
|
|
84
|
-
labelStep: 1,
|
|
85
|
-
axisLabel: 'x'
|
|
86
|
-
},
|
|
87
|
-
graph: {
|
|
88
|
-
width: 500,
|
|
89
|
-
height: 500
|
|
90
|
-
},
|
|
91
|
-
gssLineData: {
|
|
92
|
-
numberOfLines: 1,
|
|
93
|
-
selectedTool: 'lineA',
|
|
94
|
-
sections: [],
|
|
95
|
-
lineA: {
|
|
96
|
-
lineType: 'Solid'
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
includeAxes: true,
|
|
100
|
-
labels: {},
|
|
101
|
-
labelsEnabled: true,
|
|
102
|
-
padding: true,
|
|
103
|
-
prompt: '',
|
|
104
|
-
range: {
|
|
105
|
-
min: -5,
|
|
106
|
-
max: 5,
|
|
107
|
-
step: 1,
|
|
108
|
-
labelStep: 1,
|
|
109
|
-
axisLabel: 'y'
|
|
110
|
-
},
|
|
111
|
-
rationale: '',
|
|
112
|
-
standardGrid: false,
|
|
113
|
-
title: '',
|
|
114
|
-
coordinatesOnHover: false,
|
|
115
|
-
promptEnabled: true,
|
|
116
|
-
rationaleEnabled: true,
|
|
117
|
-
teacherInstructionsEnabled: true,
|
|
118
|
-
studentInstructionsEnabled: true
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
var _excluded$1 = ["type"];
|
|
122
|
-
|
|
123
|
-
function ownKeys$1(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; }
|
|
124
|
-
|
|
125
|
-
function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys$1(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
126
|
-
/*
|
|
127
|
-
* Constant to check equal segments
|
|
128
|
-
* @param {Object} segment1 - segment 1
|
|
129
|
-
* @param {Object} segment2 - segment 2
|
|
130
|
-
* */
|
|
131
|
-
|
|
132
|
-
var equalSegment = (segment1, segment2) => {
|
|
133
|
-
// A.from = B.from, A.to = B.to OR A.from = B.to, A.to = B.from
|
|
134
|
-
// x1 = x3 & y1 = y3 & x2 = x4 & y2 = y4
|
|
135
|
-
return isEqual(segment1.from, segment2.from) && isEqual(segment1.to, segment2.to) || isEqual(segment1.to, segment2.from) && isEqual(segment1.from, segment2.to);
|
|
136
|
-
}; // this function is implemented in configure as well
|
|
137
|
-
|
|
138
|
-
/*
|
|
139
|
-
* Constant to get sorted answers
|
|
140
|
-
* @param {Object} answers - answers
|
|
141
|
-
* */
|
|
142
|
-
|
|
143
|
-
var sortedAnswers = answers => Object.keys(answers || {}).sort().reduce((result, key) => {
|
|
144
|
-
if (key !== 'correctAnswer') {
|
|
145
|
-
result[key] = answers[key];
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return result;
|
|
149
|
-
}, {});
|
|
150
|
-
/*
|
|
151
|
-
* Constant to return line equation coefficients
|
|
152
|
-
* @param {Object} line - line
|
|
153
|
-
* */
|
|
154
|
-
|
|
155
|
-
var returnLineEquationCoefficients = line => {
|
|
156
|
-
line = _objectSpread$1(_objectSpread$1({}, line), {}, {
|
|
157
|
-
to: _objectSpread$1({}, line.to),
|
|
158
|
-
from: _objectSpread$1({}, line.from)
|
|
159
|
-
});
|
|
160
|
-
var xA = line.from.x;
|
|
161
|
-
var yA = line.from.y;
|
|
162
|
-
var xB = line.to.x;
|
|
163
|
-
var yB = line.to.y;
|
|
164
|
-
return {
|
|
165
|
-
a: yB - yA,
|
|
166
|
-
b: xA - xB,
|
|
167
|
-
c: xB * yA - xA * yB
|
|
168
|
-
};
|
|
169
|
-
};
|
|
170
|
-
/*
|
|
171
|
-
* Constant to get significant decimals
|
|
172
|
-
* @param {Number} number - number
|
|
173
|
-
* */
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
var getSignificantDecimals = number => Math.round(number * 10000) / 10000;
|
|
177
|
-
/*
|
|
178
|
-
* Constant to check equal lines
|
|
179
|
-
* @param {Object} line1 - line 1
|
|
180
|
-
* @param {Object} line2 - line 2
|
|
181
|
-
* */
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
var equalLine = (line1, line2) => {
|
|
185
|
-
// line equation: ax + by + c = 0
|
|
186
|
-
// 2 lines are equal if a1/a2 = b1/b2 = c1/c2, where a, b, c are the coefficients in line equation
|
|
187
|
-
// line equation knowing 2 points: (y - yA) / (yB - yA) = (x - xA) / (xB - xA)
|
|
188
|
-
// extending this equation, we get: x * (yB - yA) + y * (xA - xB) + (xB * yA - xA * yB) = 0
|
|
189
|
-
// where a = yB - yA; b = xA - xB; c = xB * yA - xA * yB
|
|
190
|
-
var {
|
|
191
|
-
a: a1,
|
|
192
|
-
b: b1,
|
|
193
|
-
c: c1
|
|
194
|
-
} = returnLineEquationCoefficients(line1);
|
|
195
|
-
var {
|
|
196
|
-
a: a2,
|
|
197
|
-
b: b2,
|
|
198
|
-
c: c2
|
|
199
|
-
} = returnLineEquationCoefficients(line2);
|
|
200
|
-
var proportions = [];
|
|
201
|
-
|
|
202
|
-
if (a2 !== 0) {
|
|
203
|
-
proportions.push(getSignificantDecimals(a1 / a2));
|
|
204
|
-
} else if (a1 !== a2) {
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (b2 !== 0) {
|
|
209
|
-
proportions.push(getSignificantDecimals(b1 / b2));
|
|
210
|
-
} else if (b1 !== b2) {
|
|
211
|
-
return false;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (c2 !== 0) {
|
|
215
|
-
proportions.push(getSignificantDecimals(c1 / c2));
|
|
216
|
-
} else if (c1 !== c2) {
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return lodash.uniq(proportions).length === 1 && line1.fill === line2.fill; // (y2 - y1)/(x2 - x1) = (y4 - y3)/(x4 - x3);
|
|
221
|
-
// return ((Math.abs((line1.to.y - line1.from.y) / (line1.to.x - line1.from.x))) === (Math.abs((line2.to.y - line2.from.y) / (line2.to.x - line2.from.x))));
|
|
222
|
-
};
|
|
223
|
-
/*
|
|
224
|
-
* Constant to construct segments from points
|
|
225
|
-
* @param {Array} points - points
|
|
226
|
-
* */
|
|
227
|
-
|
|
228
|
-
var constructSegmentsFromPoints = points => {
|
|
229
|
-
// takes the list of points that represent a polygon and transforms it into a list of segments; eg.:
|
|
230
|
-
// points: A, B, C, D => segments: AB, BC, CD, DA
|
|
231
|
-
return (points || []).map((point, index) => ({
|
|
232
|
-
from: point,
|
|
233
|
-
to: points[(index + 1) % points.length]
|
|
234
|
-
}));
|
|
235
|
-
};
|
|
236
|
-
/*
|
|
237
|
-
* Constant to remove duplicate segments
|
|
238
|
-
* @param {Array} segments - segments
|
|
239
|
-
* */
|
|
240
|
-
|
|
241
|
-
var removeDuplicateSegments = segments => {
|
|
242
|
-
segments = segments || []; // removes segments that are duplicates; eg. These segments are the same, so one will be removed:
|
|
243
|
-
// segment1: from: { x: 1, y: 1 }, to: { x: 2, y: 1 }
|
|
244
|
-
// segment2: from: { x: 2, y: 1 }, to: { x: 1, y: 1 }
|
|
245
|
-
|
|
246
|
-
return uniqWith(segments, (s1, s2) => equalSegment(s1, s2));
|
|
247
|
-
};
|
|
248
|
-
/*
|
|
249
|
-
* Constant to remove invalid segments
|
|
250
|
-
* @param {Array} segments - segments
|
|
251
|
-
* */
|
|
252
|
-
|
|
253
|
-
var removeInvalidSegments = segments => {
|
|
254
|
-
segments = segments || []; // removes segments that start in a point and end in the same point (eg.: from: { x: 1, y: 1 }, to: { x: 1, y: 1 })
|
|
255
|
-
|
|
256
|
-
return segments.filter(segment => !isEqual(segment.from, segment.to));
|
|
257
|
-
};
|
|
258
|
-
/*
|
|
259
|
-
* Constant to check equal polygons
|
|
260
|
-
* @param {Object} poly1 - polygon 1 points
|
|
261
|
-
* @param {Object} poly2 - polygon 2 points
|
|
262
|
-
* */
|
|
263
|
-
|
|
264
|
-
var equalPolygon = (poly1, poly2) => {
|
|
265
|
-
var {
|
|
266
|
-
points: points1
|
|
267
|
-
} = poly1;
|
|
268
|
-
var {
|
|
269
|
-
points: points2
|
|
270
|
-
} = poly2; // generate segments
|
|
271
|
-
|
|
272
|
-
var segments1 = constructSegmentsFromPoints(points1);
|
|
273
|
-
var segments2 = constructSegmentsFromPoints(points2);
|
|
274
|
-
var segments1NoDuplicates = removeDuplicateSegments(removeInvalidSegments(segments1));
|
|
275
|
-
var segments2NoDuplicates = removeDuplicateSegments(removeInvalidSegments(segments2));
|
|
276
|
-
var differentSegments1 = differenceWith(segments1NoDuplicates, segments2NoDuplicates, equalSegment);
|
|
277
|
-
var differentSegments2 = differenceWith(segments2NoDuplicates, segments1NoDuplicates, equalSegment);
|
|
278
|
-
return (!differentSegments1 || !differentSegments1.length) && (!differentSegments2 || !differentSegments2.length);
|
|
279
|
-
};
|
|
280
|
-
/*
|
|
281
|
-
* Constant to compare equal marks
|
|
282
|
-
* */
|
|
283
|
-
|
|
284
|
-
var equalMarks = {
|
|
285
|
-
line: (sessAnswer, mark) => equalLine(sessAnswer, mark),
|
|
286
|
-
polygon: (sessAnswer, poly) => equalPolygon(sessAnswer, poly)
|
|
287
|
-
};
|
|
288
|
-
/*
|
|
289
|
-
* Check if a point is correct and complete
|
|
290
|
-
* @param {Object} point - point object
|
|
291
|
-
* */
|
|
292
|
-
|
|
293
|
-
var completePoint = point => point && Number.isFinite(point.x) && Number.isFinite(point.y);
|
|
294
|
-
/*
|
|
295
|
-
* Check if a line is complete
|
|
296
|
-
* @param {Object} item - mark object
|
|
297
|
-
* */
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
var completeFromTo = item => item && completeMark.point(item.from) && completeMark.point(item.to);
|
|
301
|
-
/*
|
|
302
|
-
* Check if a point is correct and complete
|
|
303
|
-
* @param {Object} item - mark object
|
|
304
|
-
* */
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
var completePoints = item => item && item.points && item.points.length && (item.points.filter(point => completePoint(point)) || []).length === item.points.length;
|
|
308
|
-
/*
|
|
309
|
-
* Complete mark object for line and point
|
|
310
|
-
* */
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
var completeMark = {
|
|
314
|
-
point: completePoint,
|
|
315
|
-
line: completeFromTo,
|
|
316
|
-
polygon: completePoints
|
|
317
|
-
};
|
|
318
|
-
/*
|
|
319
|
-
* Function to remove invalid answers
|
|
320
|
-
* @param {Array} answers - answers array
|
|
321
|
-
* */
|
|
322
|
-
|
|
323
|
-
var removeInvalidAnswers = answers => answers ? (answers || []).filter(_ref => {
|
|
324
|
-
var {
|
|
325
|
-
type
|
|
326
|
-
} = _ref,
|
|
327
|
-
answer = _objectWithoutProperties(_ref, _excluded$1);
|
|
328
|
-
|
|
329
|
-
return completeMark[type] ? completeMark[type](answer) : false;
|
|
330
|
-
}) : [];
|
|
331
|
-
|
|
332
|
-
var _excluded = ["defaultTool", "extraCSSRules", "prompt", "promptEnabled", "graph", "answers", "toolbarTools"];
|
|
333
|
-
|
|
334
|
-
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; }
|
|
335
|
-
|
|
336
|
-
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) { _defineProperty(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; }
|
|
337
|
-
var log = debug('@pie-element:graphing-solution-set:controller');
|
|
338
|
-
|
|
339
|
-
var initializeGraphMap = () => ({
|
|
340
|
-
line: []
|
|
341
|
-
});
|
|
342
|
-
/*
|
|
343
|
-
* Function to compare two marks
|
|
344
|
-
* @param {Object} mark1 - first mark
|
|
345
|
-
* @param {Object} mark2 - second mark
|
|
346
|
-
* */
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
var compareMarks = (mark1, mark2) => {
|
|
350
|
-
// marks can be compared with equalMarks[type] function only if they have the same type;
|
|
351
|
-
// if type is different, they are clearly not equal
|
|
352
|
-
return !!(mark1 && mark2 && mark1.type === mark2.type && equalMarks[mark1.type] && equalMarks[mark1.type](mark1, mark2));
|
|
353
|
-
};
|
|
354
|
-
/*
|
|
355
|
-
* Function to get the corrected answer
|
|
356
|
-
* @param {Object} sessionAnswers - array of marks from session
|
|
357
|
-
* @param {Object} marks - array of marks from correct answer
|
|
358
|
-
* */
|
|
359
|
-
|
|
360
|
-
var getAnswerCorrected = _ref => {
|
|
361
|
-
var {
|
|
362
|
-
sessionAnswers,
|
|
363
|
-
marks: correctAnswers
|
|
364
|
-
} = _ref;
|
|
365
|
-
sessionAnswers = sessionAnswers || [];
|
|
366
|
-
correctAnswers = correctAnswers || [];
|
|
367
|
-
var rez = cloneDeep(sessionAnswers).reduce((correctedAnswer, answer) => {
|
|
368
|
-
var answerIsCorrect = correctAnswers.find(mark => compareMarks(answer, mark));
|
|
369
|
-
answer.correctness = answerIsCorrect ? 'correct' : 'incorrect';
|
|
370
|
-
return [...correctedAnswer, answer];
|
|
371
|
-
}, []); // add missing objects from correct answer
|
|
372
|
-
|
|
373
|
-
var missingAnswers = cloneDeep(correctAnswers).reduce((correctedAnswer, answer) => {
|
|
374
|
-
var answerIndex = sessionAnswers.find(mark => compareMarks(answer, mark));
|
|
375
|
-
|
|
376
|
-
if (!answerIndex) {
|
|
377
|
-
// means that corrected answer is missing from session, so we mark it as missing object
|
|
378
|
-
return [...correctedAnswer, _objectSpread(_objectSpread({}, answer), {}, {
|
|
379
|
-
correctness: 'missing'
|
|
380
|
-
})];
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return correctedAnswer;
|
|
384
|
-
}, []);
|
|
385
|
-
return [...rez, ...missingAnswers];
|
|
386
|
-
};
|
|
387
|
-
/*
|
|
388
|
-
* Function to get the best answer
|
|
389
|
-
* @param {Object} question - question object
|
|
390
|
-
* @param {Object} session - session object
|
|
391
|
-
* @param {Object} env - env object
|
|
392
|
-
* */
|
|
393
|
-
|
|
394
|
-
var getBestAnswer = function getBestAnswer(question, session) {
|
|
395
|
-
// questionPossibleAnswers contains all possible answers (correct response and alternates);
|
|
396
|
-
var {
|
|
397
|
-
answers: questionPossibleAnswers = {},
|
|
398
|
-
scoringType
|
|
399
|
-
} = question || {};
|
|
400
|
-
var {
|
|
401
|
-
answer
|
|
402
|
-
} = session || {}; // filter the incomplete objects
|
|
403
|
-
|
|
404
|
-
Object.entries(questionPossibleAnswers || {}).forEach(_ref2 => {
|
|
405
|
-
var [key, value] = _ref2;
|
|
406
|
-
return questionPossibleAnswers[key] = _objectSpread(_objectSpread({}, value), {}, {
|
|
407
|
-
marks: value === null || value === void 0 ? void 0 : value.marks.filter(mark => !mark.building)
|
|
408
|
-
});
|
|
409
|
-
}); // initialize answer if no values
|
|
410
|
-
|
|
411
|
-
answer = answer || []; // initialize one possible answer if no values
|
|
412
|
-
|
|
413
|
-
if (isEmpty(questionPossibleAnswers)) {
|
|
414
|
-
questionPossibleAnswers = {
|
|
415
|
-
correctAnswer: initializeGraphMap()
|
|
416
|
-
};
|
|
417
|
-
} else {
|
|
418
|
-
questionPossibleAnswers = _objectSpread({
|
|
419
|
-
correctAnswer: questionPossibleAnswers.correctAnswer
|
|
420
|
-
}, sortedAnswers(questionPossibleAnswers));
|
|
421
|
-
} // student's answers without DUPLICATES
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
var sessionAnswers = uniqWith(answer, compareMarks); // array of possible answers entries
|
|
425
|
-
|
|
426
|
-
var possibleAnswers = Object.entries(questionPossibleAnswers);
|
|
427
|
-
return possibleAnswers.reduce((acc, entry) => {
|
|
428
|
-
// iterating each possible answer (main + alternates)
|
|
429
|
-
var possibleAnswerKey = entry[0];
|
|
430
|
-
var possibleAnswer = entry[1] || {};
|
|
431
|
-
var {
|
|
432
|
-
marks
|
|
433
|
-
} = possibleAnswer;
|
|
434
|
-
|
|
435
|
-
if (!marks || !marks.length) {
|
|
436
|
-
return acc;
|
|
437
|
-
} // returns array of marks, each having 'correctness' property
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
var correctedAnswer = getAnswerCorrected({
|
|
441
|
-
sessionAnswers,
|
|
442
|
-
marks
|
|
443
|
-
});
|
|
444
|
-
var correctMarks = correctedAnswer.filter(answer => answer.correctness === 'correct'); // filter out missing objects because they do not affect the calculation of the score
|
|
445
|
-
// only correct and incorrect are needed
|
|
446
|
-
|
|
447
|
-
var scoredCorrectedAnswer = correctedAnswer.filter(answer => answer.correctness !== 'missing');
|
|
448
|
-
var maxScore = marks.length;
|
|
449
|
-
var score = correctMarks.length; // if extra placements
|
|
450
|
-
|
|
451
|
-
if (scoredCorrectedAnswer.length > maxScore) {
|
|
452
|
-
score -= scoredCorrectedAnswer.length - maxScore;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
if (score < 0) {
|
|
456
|
-
score = 0;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
if (score / maxScore > acc.bestScore || !acc.foundOneSolution) {
|
|
460
|
-
acc.bestScore = Math.floor(score / maxScore);
|
|
461
|
-
acc.bestScoreAnswerKey = possibleAnswerKey;
|
|
462
|
-
acc.answersCorrected = correctedAnswer;
|
|
463
|
-
acc.foundOneSolution = true;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
return acc;
|
|
467
|
-
}, {
|
|
468
|
-
bestScore: 0,
|
|
469
|
-
bestScoreAnswerKey: null,
|
|
470
|
-
// initially we just suppose all the answers are incorrect
|
|
471
|
-
answersCorrected: cloneDeep(sessionAnswers).map(answer => _objectSpread(_objectSpread({}, answer), {}, {
|
|
472
|
-
correctness: 'incorrect'
|
|
473
|
-
})),
|
|
474
|
-
foundOneSolution: false
|
|
475
|
-
});
|
|
476
|
-
};
|
|
477
|
-
/*
|
|
478
|
-
* Constant normalize
|
|
479
|
-
* @param {Object} question - question object
|
|
480
|
-
* */
|
|
481
|
-
|
|
482
|
-
var normalize = question => _objectSpread(_objectSpread({}, defaults), question);
|
|
483
|
-
/*
|
|
484
|
-
* Function to set model
|
|
485
|
-
* @param {Object} question - question object
|
|
486
|
-
* @param {Object} session - session object
|
|
487
|
-
* @param {Object} env - env object
|
|
488
|
-
* */
|
|
489
|
-
|
|
490
|
-
function model(question, session, env) {
|
|
491
|
-
return new Promise(resolve => {
|
|
492
|
-
var normalizedQuestion = normalize(question); // ensure removing of invalid answers
|
|
493
|
-
// need this if undo redo was last operation
|
|
494
|
-
|
|
495
|
-
session.answer = removeInvalidAnswers(session.answer); // console.log('normalizedQuestion', normalizedQuestion);
|
|
496
|
-
|
|
497
|
-
var _ref3 = normalizedQuestion || {},
|
|
498
|
-
{
|
|
499
|
-
defaultTool,
|
|
500
|
-
extraCSSRules,
|
|
501
|
-
prompt,
|
|
502
|
-
promptEnabled,
|
|
503
|
-
graph,
|
|
504
|
-
answers,
|
|
505
|
-
toolbarTools
|
|
506
|
-
} = _ref3,
|
|
507
|
-
questionProps = _objectWithoutProperties(_ref3, _excluded);
|
|
508
|
-
|
|
509
|
-
var {
|
|
510
|
-
arrows
|
|
511
|
-
} = normalizedQuestion;
|
|
512
|
-
var {
|
|
513
|
-
mode,
|
|
514
|
-
role
|
|
515
|
-
} = env || {}; // This is used for offering support for old models which have the property arrows: boolean
|
|
516
|
-
// Same thing is set in authoring : packages/graphing/configure/src/configure.jsx - componentDidMount
|
|
517
|
-
|
|
518
|
-
if (typeof arrows === 'boolean') {
|
|
519
|
-
if (arrows) {
|
|
520
|
-
arrows = {
|
|
521
|
-
left: true,
|
|
522
|
-
right: true,
|
|
523
|
-
up: true,
|
|
524
|
-
down: true
|
|
525
|
-
};
|
|
526
|
-
} else {
|
|
527
|
-
arrows = {
|
|
528
|
-
left: false,
|
|
529
|
-
right: false,
|
|
530
|
-
up: false,
|
|
531
|
-
down: false
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
var base = _objectSpread(_objectSpread({}, questionProps), {}, {
|
|
537
|
-
answers,
|
|
538
|
-
arrows,
|
|
539
|
-
defaultTool: 'line',
|
|
540
|
-
disabled: env.mode !== 'gather',
|
|
541
|
-
prompt: promptEnabled ? prompt : null,
|
|
542
|
-
rationale: null,
|
|
543
|
-
size: graph,
|
|
544
|
-
showToggle: env.mode === 'evaluate' && !isEmpty(answers) && answers.correctAnswer && answers.correctAnswer.marks && !isEmpty(answers.correctAnswer.marks),
|
|
545
|
-
teacherInstructions: null,
|
|
546
|
-
toolbarTools,
|
|
547
|
-
extraCSSRules
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
if (role === 'instructor' && (mode === 'view' || mode === 'evaluate')) {
|
|
551
|
-
var {
|
|
552
|
-
rationale,
|
|
553
|
-
rationaleEnabled,
|
|
554
|
-
teacherInstructions,
|
|
555
|
-
teacherInstructionsEnabled
|
|
556
|
-
} = normalizedQuestion || {};
|
|
557
|
-
base.rationale = rationaleEnabled ? rationale : null;
|
|
558
|
-
base.teacherInstructions = teacherInstructionsEnabled ? teacherInstructions : null;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
if (mode === 'evaluate') {
|
|
562
|
-
if (!isEmpty(answers) && answers.correctAnswer && answers.correctAnswer.marks && !isEmpty(answers.correctAnswer.marks)) {
|
|
563
|
-
var {
|
|
564
|
-
answersCorrected,
|
|
565
|
-
bestScoreAnswerKey,
|
|
566
|
-
bestScore
|
|
567
|
-
} = getBestAnswer(normalizedQuestion, session); // array of marks from session with 'correctness' property set
|
|
568
|
-
|
|
569
|
-
base.answersCorrected = answersCorrected;
|
|
570
|
-
base.correctResponse = bestScoreAnswerKey ? (answers[bestScoreAnswerKey] || {}).marks : [];
|
|
571
|
-
base.showToggle = base.showToggle && bestScore !== 1;
|
|
572
|
-
} else {
|
|
573
|
-
base.answersCorrected = session && session.answer || [];
|
|
574
|
-
base.correctResponse = [];
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
log('base: ', base);
|
|
579
|
-
resolve(base);
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
/*
|
|
583
|
-
* Function to check the outcome
|
|
584
|
-
* @param {Object} question - question object
|
|
585
|
-
* @param {Object} session - session object
|
|
586
|
-
* @param {Object} env - env object
|
|
587
|
-
* */
|
|
588
|
-
|
|
589
|
-
function outcome(question, session) {
|
|
590
|
-
var env = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
591
|
-
return new Promise(resolve => {
|
|
592
|
-
if (!session || isEmpty(session)) {
|
|
593
|
-
resolve({
|
|
594
|
-
score: 0,
|
|
595
|
-
empty: true
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
if (env.mode !== 'evaluate' || isEmpty(question.answers) || question.answers && question.answers.correctAnswer && isEmpty(question.answers.correctAnswer.marks)) {
|
|
600
|
-
resolve({
|
|
601
|
-
score: 0
|
|
602
|
-
});
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
var {
|
|
606
|
-
bestScore
|
|
607
|
-
} = getBestAnswer(question, session);
|
|
608
|
-
resolve({
|
|
609
|
-
score: bestScore
|
|
610
|
-
});
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
/*
|
|
614
|
-
* Constant to create correct response session
|
|
615
|
-
* @param {Object} question - question object
|
|
616
|
-
* @param {Object} env - env object
|
|
617
|
-
* */
|
|
618
|
-
|
|
619
|
-
var createCorrectResponseSession = (question, env) => {
|
|
620
|
-
return new Promise(resolve => {
|
|
621
|
-
if (env.mode !== 'evaluate' && env.role === 'instructor') {
|
|
622
|
-
var {
|
|
623
|
-
answers
|
|
624
|
-
} = question || {};
|
|
625
|
-
var marks = [];
|
|
626
|
-
|
|
627
|
-
if (answers && Object.values(answers)) {
|
|
628
|
-
var correctAnswer = answers.correctAnswer || Object.values(answers)[0] || {};
|
|
629
|
-
marks = correctAnswer.marks || [];
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
resolve({
|
|
633
|
-
answer: marks,
|
|
634
|
-
id: '1'
|
|
635
|
-
});
|
|
636
|
-
} else {
|
|
637
|
-
resolve(null);
|
|
638
|
-
}
|
|
639
|
-
});
|
|
640
|
-
};
|
|
641
|
-
/*
|
|
642
|
-
* Constant to validate model before saving item
|
|
643
|
-
* @param {Object} model - model object
|
|
644
|
-
* */
|
|
645
|
-
|
|
646
|
-
var validate = function validate() {
|
|
647
|
-
var model = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
648
|
-
var {
|
|
649
|
-
answers,
|
|
650
|
-
gssLineData
|
|
651
|
-
} = model;
|
|
652
|
-
var errors = {};
|
|
653
|
-
var correctAnswerErrors = {};
|
|
654
|
-
var found = false;
|
|
655
|
-
|
|
656
|
-
if (gssLineData.numberOfLines === 1) {
|
|
657
|
-
if (answers.correctAnswer.marks.length < 1) {
|
|
658
|
-
found = true;
|
|
659
|
-
correctAnswerErrors.correctAnswer = 'At least 1 line object should be defined.';
|
|
660
|
-
} else if (answers.correctAnswer.marks.length === 1 && answers.correctAnswer.marks[0].building) {
|
|
661
|
-
found = true;
|
|
662
|
-
correctAnswerErrors.correctAnswer = '1 or more graph object should be correctly defined.';
|
|
663
|
-
}
|
|
664
|
-
} else {
|
|
665
|
-
if (answers.correctAnswer.marks.length < 2) {
|
|
666
|
-
found = true;
|
|
667
|
-
correctAnswerErrors.correctAnswer = 'At least 2 line object should be defined.';
|
|
668
|
-
} else if (answers.correctAnswer.marks.length === 2) {
|
|
669
|
-
if (answers.correctAnswer.marks[0].building || answers.correctAnswer.marks[1].building) {
|
|
670
|
-
found = true;
|
|
671
|
-
correctAnswerErrors.correctAnswer = '1 or more graph object should be correctly defined.';
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
var polygon = answers.correctAnswer.marks.find(mark => mark.type === 'polygon');
|
|
677
|
-
|
|
678
|
-
if (!found && (!gssLineData.selectedTool === 'solutionSet' || !polygon)) {
|
|
679
|
-
correctAnswerErrors.correctAnswer = 'Please select a solution set for the graphing solution set item.';
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
if (!isEmpty(correctAnswerErrors)) {
|
|
683
|
-
errors.correctAnswerErrors = correctAnswerErrors;
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
return errors;
|
|
687
|
-
};
|
|
688
|
-
|
|
689
|
-
export { compareMarks, createCorrectResponseSession, getAnswerCorrected, getBestAnswer, model, normalize, outcome, validate };
|
|
690
|
-
//# sourceMappingURL=controller.js.map
|