@pie-element/hotspot 4.7.18-next.85 → 4.8.1-beta.587
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 +485 -0
- package/configure/CHANGELOG.md +425 -0
- package/configure/lib/button.js.map +1 -1
- package/configure/lib/defaults.js +24 -2
- package/configure/lib/defaults.js.map +1 -1
- package/configure/lib/hotspot-container.js +44 -23
- package/configure/lib/hotspot-container.js.map +1 -1
- package/configure/lib/hotspot-drawable.js +11 -5
- package/configure/lib/hotspot-drawable.js.map +1 -1
- package/configure/lib/hotspot-palette.js +1 -1
- package/configure/lib/hotspot-palette.js.map +1 -1
- package/configure/lib/hotspot-polygon.js +1 -1
- package/configure/lib/hotspot-polygon.js.map +1 -1
- package/configure/lib/hotspot-rectangle.js +1 -1
- package/configure/lib/hotspot-rectangle.js.map +1 -1
- package/configure/lib/index.js +17 -3
- package/configure/lib/index.js.map +1 -1
- package/configure/lib/root.js +133 -27
- package/configure/lib/root.js.map +1 -1
- package/configure/lib/upload-control.js.map +1 -1
- package/configure/lib/utils.js +18 -4
- package/configure/lib/utils.js.map +1 -1
- package/configure/package.json +4 -4
- package/configure/src/__tests__/__snapshots__/hotspot-container.test.js.snap +2 -1
- package/configure/src/__tests__/__snapshots__/root.test.js.snap +56 -4
- package/configure/src/__tests__/hotspot-container.test.js +98 -71
- package/configure/src/__tests__/hotspot-drawable.test.js +48 -49
- package/configure/src/__tests__/index.test.js +28 -51
- package/configure/src/__tests__/root.test.js +162 -82
- package/configure/src/__tests__/utils.test.js +112 -98
- package/configure/src/button.jsx +4 -4
- package/configure/src/defaults.js +36 -18
- package/configure/src/hotspot-container.jsx +107 -97
- package/configure/src/hotspot-drawable.jsx +59 -53
- package/configure/src/hotspot-palette.jsx +12 -25
- package/configure/src/hotspot-polygon.jsx +20 -22
- package/configure/src/hotspot-rectangle.jsx +5 -15
- package/configure/src/index.js +32 -18
- package/configure/src/root.jsx +120 -51
- package/configure/src/upload-control.jsx +9 -20
- package/configure/src/utils.js +51 -22
- package/controller/CHANGELOG.md +72 -0
- package/controller/lib/defaults.js +2 -2
- package/controller/lib/defaults.js.map +1 -1
- package/controller/lib/index.js +57 -9
- package/controller/lib/index.js.map +1 -1
- package/controller/lib/utils.js.map +1 -1
- package/controller/package.json +2 -2
- package/controller/src/__tests__/index.test.js +99 -55
- package/controller/src/defaults.js +5 -9
- package/controller/src/index.js +58 -34
- package/controller/src/utils.js +9 -6
- package/docs/config-schema.json +217 -0
- package/docs/config-schema.json.md +169 -0
- package/docs/demo/config.js +2 -2
- package/docs/demo/generate.js +54 -35
- package/docs/demo/session.js +2 -2
- package/docs/pie-schema.json +59 -0
- package/docs/pie-schema.json.md +47 -0
- package/lib/hotspot/container.js +44 -7
- package/lib/hotspot/container.js.map +1 -1
- package/lib/hotspot/icons.js.map +1 -1
- package/lib/hotspot/image.js +35 -8
- package/lib/hotspot/image.js.map +1 -1
- package/lib/hotspot/index.js +72 -18
- package/lib/hotspot/index.js.map +1 -1
- package/lib/hotspot/polygon.js +51 -32
- package/lib/hotspot/polygon.js.map +1 -1
- package/lib/hotspot/rectangle.js +51 -32
- package/lib/hotspot/rectangle.js.map +1 -1
- package/lib/index.js +4 -1
- package/lib/index.js.map +1 -1
- package/lib/session-updater.js.map +1 -1
- package/package.json +7 -4
- package/src/__tests__/__snapshots__/{container-test.jsx.snap → container.test.jsx.snap} +8 -0
- package/src/__tests__/__snapshots__/image.test.jsx.snap +43 -0
- package/src/__tests__/__snapshots__/{polygon-test.jsx.snap → polygon.test.jsx.snap} +11 -0
- package/src/__tests__/__snapshots__/{rectangle-test.jsx.snap → rectangle.test.jsx.snap} +11 -0
- package/src/__tests__/container.test.jsx +214 -0
- package/src/__tests__/{image-test.jsx → image.test.jsx} +10 -2
- package/src/__tests__/polygon.test.jsx +235 -0
- package/src/__tests__/rectangle.test.jsx +237 -0
- package/src/__tests__/{session-updater-test.jsx → session-updater.test.jsx} +22 -31
- package/src/hotspot/container.jsx +60 -23
- package/src/hotspot/icons.js +4 -2
- package/src/hotspot/image.jsx +26 -13
- package/src/hotspot/index.jsx +73 -33
- package/src/hotspot/polygon.jsx +51 -40
- package/src/hotspot/rectangle.jsx +51 -40
- package/src/index.js +10 -18
- package/src/session-updater.js +1 -1
- package/src/__tests__/__snapshots__/image-test.jsx.snap +0 -21
- package/src/__tests__/container-test.jsx +0 -143
- package/src/__tests__/polygon-test.jsx +0 -76
- package/src/__tests__/rectangle-test.jsx +0 -77
|
@@ -41,20 +41,17 @@ describe('controller', () => {
|
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
describe('outcome partialScoring test', () => {
|
|
44
|
-
|
|
45
|
-
describe('hanging controller', ()=> {
|
|
46
|
-
|
|
44
|
+
describe('hanging controller', () => {
|
|
47
45
|
it('doesnt hang if answers is missing', async () => {
|
|
48
|
-
const response = await outcome({}, {id:
|
|
49
|
-
expect(response).toEqual({score: 0, empty: true});
|
|
46
|
+
const response = await outcome({}, { id: '1' }, {});
|
|
47
|
+
expect(response).toEqual({ score: 0, empty: true });
|
|
50
48
|
});
|
|
51
49
|
|
|
52
50
|
it('doesnt hang if the rest is missing', async () => {
|
|
53
|
-
const response = await outcome({}, {id:
|
|
54
|
-
expect(response).toEqual({score: 0 });
|
|
51
|
+
const response = await outcome({}, { id: '1', answers: {} }, {});
|
|
52
|
+
expect(response).toEqual({ score: 0 });
|
|
55
53
|
});
|
|
56
|
-
|
|
57
|
-
})
|
|
54
|
+
});
|
|
58
55
|
|
|
59
56
|
beforeEach(() => {
|
|
60
57
|
const rectangles = question.shapes.rectangles.concat({
|
|
@@ -72,11 +69,7 @@ describe('controller', () => {
|
|
|
72
69
|
|
|
73
70
|
const assertOutcome = (message, extra, sessionValue, env, expected) => {
|
|
74
71
|
it(message, async () => {
|
|
75
|
-
const result = await outcome(
|
|
76
|
-
{ ...question, ...extra },
|
|
77
|
-
sessionValue,
|
|
78
|
-
env
|
|
79
|
-
);
|
|
72
|
+
const result = await outcome({ ...question, ...extra }, sessionValue, env);
|
|
80
73
|
expect(result).toEqual(expect.objectContaining(expected));
|
|
81
74
|
});
|
|
82
75
|
};
|
|
@@ -86,7 +79,7 @@ describe('controller', () => {
|
|
|
86
79
|
{ partialScoring: true },
|
|
87
80
|
{ answers: [{ id: '2' }] },
|
|
88
81
|
{ mode: 'evaluate' },
|
|
89
|
-
{ score: 0
|
|
82
|
+
{ score: 0 },
|
|
90
83
|
);
|
|
91
84
|
|
|
92
85
|
assertOutcome(
|
|
@@ -94,7 +87,7 @@ describe('controller', () => {
|
|
|
94
87
|
{ partialScoring: false },
|
|
95
88
|
{ answers: [{ id: '2' }] },
|
|
96
89
|
{ mode: 'evaluate' },
|
|
97
|
-
{ score: 0 }
|
|
90
|
+
{ score: 0 },
|
|
98
91
|
);
|
|
99
92
|
|
|
100
93
|
assertOutcome(
|
|
@@ -102,7 +95,7 @@ describe('controller', () => {
|
|
|
102
95
|
{ partialScoring: false },
|
|
103
96
|
{ answers: [{ id: '2' }] },
|
|
104
97
|
{ mode: 'evaluate', partialScoring: true },
|
|
105
|
-
{ score: 0 }
|
|
98
|
+
{ score: 0 },
|
|
106
99
|
);
|
|
107
100
|
|
|
108
101
|
assertOutcome(
|
|
@@ -110,7 +103,7 @@ describe('controller', () => {
|
|
|
110
103
|
{ partialScoring: true },
|
|
111
104
|
{ answers: [{ id: '2' }] },
|
|
112
105
|
{ mode: 'evaluate', partialScoring: false },
|
|
113
|
-
{ score: 0 }
|
|
106
|
+
{ score: 0 },
|
|
114
107
|
);
|
|
115
108
|
});
|
|
116
109
|
|
|
@@ -136,10 +129,16 @@ describe('controller', () => {
|
|
|
136
129
|
|
|
137
130
|
describe('partial scoring', () => {
|
|
138
131
|
beforeEach(() => {
|
|
139
|
-
const rectangles = question.shapes.rectangles.concat(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
132
|
+
const rectangles = question.shapes.rectangles.concat(
|
|
133
|
+
{
|
|
134
|
+
id: '5',
|
|
135
|
+
correct: true,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: '6',
|
|
139
|
+
correct: true,
|
|
140
|
+
},
|
|
141
|
+
);
|
|
143
142
|
question = {
|
|
144
143
|
...question,
|
|
145
144
|
partialScoring: true,
|
|
@@ -149,42 +148,101 @@ describe('controller', () => {
|
|
|
149
148
|
},
|
|
150
149
|
};
|
|
151
150
|
});
|
|
152
|
-
it('returns a score of 0
|
|
151
|
+
it('returns a score of 0', async () => {
|
|
153
152
|
const result = await outcome(question, { answers: [{ id: '2' }] });
|
|
154
|
-
expect(result.score).toEqual(0
|
|
153
|
+
expect(result.score).toEqual(0);
|
|
155
154
|
});
|
|
156
155
|
|
|
157
|
-
it('returns a score of 0.4', async () => {
|
|
156
|
+
it('returns a score of 0.25 for 1/4 correct answers and 0 incorrect answers', async () => {
|
|
158
157
|
const result = await outcome(question, {
|
|
159
158
|
answers: [{ id: '2' }, { id: '5' }],
|
|
160
159
|
});
|
|
161
|
-
expect(result.score).toEqual(0.
|
|
160
|
+
expect(result.score).toEqual(0.25);
|
|
162
161
|
});
|
|
163
162
|
|
|
164
|
-
it('returns a score of 0.
|
|
163
|
+
it('returns a score of 0.25, even if answers are not in order', async () => {
|
|
165
164
|
const result = await outcome(question, {
|
|
166
165
|
answers: [{ id: '5' }, { id: '2' }],
|
|
167
166
|
});
|
|
168
|
-
expect(result.score).toEqual(0.
|
|
167
|
+
expect(result.score).toEqual(0.25);
|
|
169
168
|
});
|
|
170
169
|
|
|
171
|
-
it('returns a score of 0.
|
|
172
|
-
const result = await outcome(question, { answers: [{ id: '5' }] });
|
|
173
|
-
expect(result.score).toEqual(0.
|
|
170
|
+
it('returns a score of 0.5 for 2/4 correct answers and 0 incorrect answers', async () => {
|
|
171
|
+
const result = await outcome(question, { answers: [{ id: '5' }, { id: '4' }] });
|
|
172
|
+
expect(result.score).toEqual(0.5);
|
|
174
173
|
});
|
|
175
174
|
|
|
176
|
-
it('returns a score of
|
|
175
|
+
it('returns a score of 0.75 for 3/4 correct answers and 0 incorrect answers', async () => {
|
|
176
|
+
const result = await outcome(question, { answers: [{ id: '1' }, { id: '5' }, { id: '4' }] });
|
|
177
|
+
expect(result.score).toEqual(0.75);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('returns a score of 1 for 4/4 correct answers and 0 incorrect answers', async () => {
|
|
177
181
|
const result = await outcome(question, {
|
|
178
|
-
answers: [{ id: '1' }, { id: '4' }, { id: '5' }],
|
|
182
|
+
answers: [{ id: '1' }, { id: '4' }, { id: '5' }, { id: '6' }],
|
|
179
183
|
});
|
|
180
184
|
expect(result.score).toEqual(1);
|
|
181
185
|
});
|
|
186
|
+
|
|
187
|
+
it('returns a score of 0.25 for 1/4 correct answers and 2 incorrect answers', async () => {
|
|
188
|
+
const result = await outcome(question, {
|
|
189
|
+
answers: [{ id: '1' }, { id: '2' }, { id: '3' }],
|
|
190
|
+
});
|
|
191
|
+
expect(result.score).toEqual(0.25);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('returns a score of 0.5 for 2/4 correct answers and 2 incorrect answers', async () => {
|
|
195
|
+
const result = await outcome(question, {
|
|
196
|
+
answers: [{ id: '1' }, { id: '4' }, { id: '2' }, { id: '3' }],
|
|
197
|
+
});
|
|
198
|
+
expect(result.score).toEqual(0.5);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('returns a score of 0.5 for 2/4 correct answers and 2 incorrect answers', async () => {
|
|
202
|
+
const result = await outcome(question, {
|
|
203
|
+
answers: [{ id: '1' }, { id: '4' }, { id: '2' }, { id: '3' }],
|
|
204
|
+
});
|
|
205
|
+
expect(result.score).toEqual(0.5);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('returns a score of 0.75 for 3/4 correct answers and 1 incorrect answer', async () => {
|
|
209
|
+
const result = await outcome(question, {
|
|
210
|
+
answers: [{ id: '6' }, { id: '4' }, { id: '1' }, { id: '3' }],
|
|
211
|
+
});
|
|
212
|
+
expect(result.score).toEqual(0.75);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('returns a score of 0.75 for 3/4 correct answers and 1 incorrect answer', async () => {
|
|
216
|
+
const result = await outcome(question, {
|
|
217
|
+
answers: [{ id: '6' }, { id: '4' }, { id: '1' }, { id: '3' }],
|
|
218
|
+
});
|
|
219
|
+
expect(result.score).toEqual(0.75);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('returns a score of 0.5 for 3/4 correct answers and 2 incorrect answer', async () => {
|
|
223
|
+
const result = await outcome(question, {
|
|
224
|
+
answers: [{ id: '6' }, { id: '4' }, { id: '2' }, { id: '3' }, { id: '1' }],
|
|
225
|
+
});
|
|
226
|
+
expect(result.score).toEqual(0.5);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('returns a score of 0.75 for 4/4 correct answers and 1 incorrect answer', async () => {
|
|
230
|
+
const result = await outcome(question, {
|
|
231
|
+
answers: [{ id: '6' }, { id: '4' }, { id: '2' }, { id: '5' }, { id: '1' }],
|
|
232
|
+
});
|
|
233
|
+
expect(result.score).toEqual(0.75);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('returns a score of 0.5 for 4/4 correct answers and 2 incorrect answers', async () => {
|
|
237
|
+
const result = await outcome(question, {
|
|
238
|
+
answers: [{ id: '6' }, { id: '4' }, { id: '2' }, { id: '5' }, { id: '1' }, { id: '3' }],
|
|
239
|
+
});
|
|
240
|
+
expect(result.score).toEqual(0.5);
|
|
241
|
+
});
|
|
182
242
|
});
|
|
183
243
|
|
|
184
244
|
const returnOutcome = (session) => {
|
|
185
|
-
it(`returns empty: true when session is ${JSON.stringify(
|
|
186
|
-
session
|
|
187
|
-
)}`, async () => {
|
|
245
|
+
it(`returns empty: true when session is ${JSON.stringify(session)}`, async () => {
|
|
188
246
|
const result = await outcome(question, session);
|
|
189
247
|
expect(result).toEqual({ score: 0, empty: true });
|
|
190
248
|
});
|
|
@@ -233,15 +291,9 @@ describe('controller', () => {
|
|
|
233
291
|
|
|
234
292
|
it('returns shapes', () => {
|
|
235
293
|
expect(result.shapes.rectangles).toEqual(
|
|
236
|
-
expect.arrayContaining([
|
|
237
|
-
{ id: '1', correct: true },
|
|
238
|
-
{ id: '2' },
|
|
239
|
-
{ id: '3' },
|
|
240
|
-
])
|
|
241
|
-
);
|
|
242
|
-
expect(result.shapes.polygons).toEqual(
|
|
243
|
-
expect.arrayContaining([{ id: '4', correct: true }])
|
|
294
|
+
expect.arrayContaining([{ id: '1', correct: true }, { id: '2' }, { id: '3' }]),
|
|
244
295
|
);
|
|
296
|
+
expect(result.shapes.polygons).toEqual(expect.arrayContaining([{ id: '4', correct: true }]));
|
|
245
297
|
});
|
|
246
298
|
|
|
247
299
|
it('does not return responseCorrect', () => {
|
|
@@ -271,15 +323,9 @@ describe('controller', () => {
|
|
|
271
323
|
|
|
272
324
|
it('returns choices w/ correct', () => {
|
|
273
325
|
expect(result.shapes.rectangles).toEqual(
|
|
274
|
-
expect.arrayContaining([
|
|
275
|
-
{ id: '1', correct: true },
|
|
276
|
-
{ id: '2' },
|
|
277
|
-
{ id: '3' },
|
|
278
|
-
])
|
|
279
|
-
);
|
|
280
|
-
expect(result.shapes.polygons).toEqual(
|
|
281
|
-
expect.arrayContaining([{ id: '4', correct: true }])
|
|
326
|
+
expect.arrayContaining([{ id: '1', correct: true }, { id: '2' }, { id: '3' }]),
|
|
282
327
|
);
|
|
328
|
+
expect(result.shapes.polygons).toEqual(expect.arrayContaining([{ id: '4', correct: true }]));
|
|
283
329
|
});
|
|
284
330
|
|
|
285
331
|
it('returns is response correct', () => {
|
|
@@ -290,9 +336,7 @@ describe('controller', () => {
|
|
|
290
336
|
|
|
291
337
|
describe('isResponseCorrect', () => {
|
|
292
338
|
const returnIsResponseCorect = (session) => {
|
|
293
|
-
it(`response is not correct if session is ${JSON.stringify(
|
|
294
|
-
session
|
|
295
|
-
)}`, () => {
|
|
339
|
+
it(`response is not correct if session is ${JSON.stringify(session)}`, () => {
|
|
296
340
|
expect(isResponseCorrect(question, session)).toEqual(false);
|
|
297
341
|
});
|
|
298
342
|
};
|
|
@@ -3,20 +3,16 @@ export default {
|
|
|
3
3
|
imageUrl: '',
|
|
4
4
|
shapes: {
|
|
5
5
|
rectangles: [],
|
|
6
|
-
polygons: []
|
|
6
|
+
polygons: [],
|
|
7
7
|
},
|
|
8
8
|
multipleCorrect: true,
|
|
9
9
|
partialScoring: false,
|
|
10
10
|
dimensions: {
|
|
11
11
|
height: 0,
|
|
12
|
-
width: 0
|
|
12
|
+
width: 0,
|
|
13
13
|
},
|
|
14
|
-
hotspotColor: 'rgba(137, 183, 244, 0.
|
|
15
|
-
hotspotList: [
|
|
16
|
-
'rgba(137, 183, 244, 0.65)'
|
|
17
|
-
],
|
|
14
|
+
hotspotColor: 'rgba(137, 183, 244, 0.25)',
|
|
15
|
+
hotspotList: ['rgba(137, 183, 244, 0.25)'],
|
|
18
16
|
outlineColor: 'blue',
|
|
19
|
-
outlineList: [
|
|
20
|
-
'blue'
|
|
21
|
-
]
|
|
17
|
+
outlineList: ['blue'],
|
|
22
18
|
};
|
package/controller/src/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import defaults from './defaults';
|
|
|
8
8
|
|
|
9
9
|
const log = debug('pie-elements:hotspot:controller');
|
|
10
10
|
|
|
11
|
-
export const normalize = question => ({
|
|
11
|
+
export const normalize = (question) => ({
|
|
12
12
|
promptEnabled: true,
|
|
13
13
|
rationaleEnabled: true,
|
|
14
14
|
teacherInstructionsEnabled: true,
|
|
@@ -19,19 +19,11 @@ export const normalize = question => ({
|
|
|
19
19
|
|
|
20
20
|
export function model(question, session, env) {
|
|
21
21
|
const normalizedQuestion = normalize(question);
|
|
22
|
-
const {
|
|
23
|
-
|
|
24
|
-
dimensions,
|
|
25
|
-
hotspotColor,
|
|
26
|
-
multipleCorrect,
|
|
27
|
-
outlineColor,
|
|
28
|
-
partialScoring,
|
|
29
|
-
prompt,
|
|
30
|
-
shapes
|
|
31
|
-
} = normalizedQuestion;
|
|
22
|
+
const { imageUrl, dimensions, hotspotColor, multipleCorrect, outlineColor, partialScoring, prompt, shapes } =
|
|
23
|
+
normalizedQuestion;
|
|
32
24
|
const { rectangles, polygons } = shapes || {};
|
|
33
25
|
|
|
34
|
-
return new Promise(resolve => {
|
|
26
|
+
return new Promise((resolve) => {
|
|
35
27
|
const out = {
|
|
36
28
|
disabled: env.mode !== 'gather',
|
|
37
29
|
mode: env.mode,
|
|
@@ -46,17 +38,16 @@ export function model(question, session, env) {
|
|
|
46
38
|
// eslint-disable-next-line no-unused-vars
|
|
47
39
|
rectangles: (rectangles || []).map(({ index, ...rectProps }) => ({ ...rectProps })),
|
|
48
40
|
// eslint-disable-next-line no-unused-vars
|
|
49
|
-
polygons: (polygons || []).map(({ index, ...polyProps }) => ({ ...polyProps }))
|
|
41
|
+
polygons: (polygons || []).map(({ index, ...polyProps }) => ({ ...polyProps })),
|
|
50
42
|
},
|
|
51
|
-
responseCorrect:
|
|
52
|
-
env.mode === 'evaluate'
|
|
53
|
-
? isResponseCorrect(normalizedQuestion, session)
|
|
54
|
-
: undefined
|
|
43
|
+
responseCorrect: env.mode === 'evaluate' ? isResponseCorrect(normalizedQuestion, session) : undefined,
|
|
55
44
|
};
|
|
56
45
|
|
|
57
46
|
if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {
|
|
58
47
|
out.rationale = normalizedQuestion.rationaleEnabled ? normalizedQuestion.rationale : null;
|
|
59
|
-
out.teacherInstructions = normalizedQuestion.teacherInstructionsEnabled
|
|
48
|
+
out.teacherInstructions = normalizedQuestion.teacherInstructionsEnabled
|
|
49
|
+
? normalizedQuestion.teacherInstructions
|
|
50
|
+
: null;
|
|
60
51
|
} else {
|
|
61
52
|
out.rationale = null;
|
|
62
53
|
out.teacherInstructions = null;
|
|
@@ -71,7 +62,7 @@ export function model(question, session, env) {
|
|
|
71
62
|
}
|
|
72
63
|
|
|
73
64
|
export const createDefaultModel = (model = {}) =>
|
|
74
|
-
new Promise(resolve => {
|
|
65
|
+
new Promise((resolve) => {
|
|
75
66
|
resolve({
|
|
76
67
|
...defaults,
|
|
77
68
|
...model,
|
|
@@ -93,25 +84,35 @@ const getScore = (config, session, env = {}) => {
|
|
|
93
84
|
}
|
|
94
85
|
|
|
95
86
|
let correctAnswers = 0;
|
|
87
|
+
let selectedChoices = 0;
|
|
96
88
|
|
|
97
89
|
const choices = [...rectangles, ...polygons];
|
|
98
90
|
|
|
99
|
-
choices.
|
|
100
|
-
|
|
91
|
+
const correctChoices = choices.filter((choice) => choice.correct);
|
|
92
|
+
|
|
93
|
+
choices.forEach((shape) => {
|
|
94
|
+
const selected = answers && answers.filter((answer) => answer.id === shape.id)[0];
|
|
101
95
|
const correctlySelected = shape.correct && selected;
|
|
102
|
-
const correctlyUnselected = !shape.correct && !selected;
|
|
103
96
|
|
|
104
|
-
if (
|
|
97
|
+
if (selected) {
|
|
98
|
+
selectedChoices += 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (correctlySelected) {
|
|
105
102
|
correctAnswers += 1;
|
|
106
103
|
}
|
|
107
104
|
});
|
|
108
105
|
|
|
109
|
-
const
|
|
110
|
-
|
|
106
|
+
const extraAnswers = selectedChoices > correctChoices.length ? selectedChoices - correctChoices.length : 0;
|
|
107
|
+
|
|
108
|
+
const total = correctChoices.length === 0 ? 1 : correctChoices.length;
|
|
109
|
+
const str = ((correctAnswers - extraAnswers) / total).toFixed(2);
|
|
110
|
+
|
|
111
|
+
return str < 0 ? 0 : parseFloat(str);
|
|
111
112
|
};
|
|
112
113
|
|
|
113
114
|
export function outcome(config, session, env = {}) {
|
|
114
|
-
return new Promise(resolve => {
|
|
115
|
+
return new Promise((resolve) => {
|
|
115
116
|
log('outcome...');
|
|
116
117
|
|
|
117
118
|
if (!session || isEmpty(session)) {
|
|
@@ -122,7 +123,7 @@ export function outcome(config, session, env = {}) {
|
|
|
122
123
|
const score = getScore(config, session, env);
|
|
123
124
|
resolve({ score });
|
|
124
125
|
} else {
|
|
125
|
-
resolve({score: 0, empty: true})
|
|
126
|
+
resolve({ score: 0, empty: true });
|
|
126
127
|
}
|
|
127
128
|
});
|
|
128
129
|
}
|
|
@@ -130,7 +131,7 @@ export function outcome(config, session, env = {}) {
|
|
|
130
131
|
const returnShapesCorrect = (shapes) => {
|
|
131
132
|
let answers = [];
|
|
132
133
|
|
|
133
|
-
shapes.forEach(i => {
|
|
134
|
+
shapes.forEach((i) => {
|
|
134
135
|
const { correct, id } = i;
|
|
135
136
|
if (correct) {
|
|
136
137
|
answers.push({ id });
|
|
@@ -140,7 +141,7 @@ const returnShapesCorrect = (shapes) => {
|
|
|
140
141
|
};
|
|
141
142
|
|
|
142
143
|
export const createCorrectResponseSession = (question, env) => {
|
|
143
|
-
return new Promise(resolve => {
|
|
144
|
+
return new Promise((resolve) => {
|
|
144
145
|
if (env.mode !== 'evaluate' && env.role === 'instructor') {
|
|
145
146
|
const { shapes: { rectangles = [], polygons = {} } = {} } = question;
|
|
146
147
|
|
|
@@ -148,14 +149,37 @@ export const createCorrectResponseSession = (question, env) => {
|
|
|
148
149
|
const polygonsCorrect = returnShapesCorrect(polygons);
|
|
149
150
|
|
|
150
151
|
resolve({
|
|
151
|
-
answers: [
|
|
152
|
-
|
|
153
|
-
...polygonsCorrect
|
|
154
|
-
],
|
|
155
|
-
id: '1'
|
|
152
|
+
answers: [...rectangleCorrect, ...polygonsCorrect],
|
|
153
|
+
id: '1',
|
|
156
154
|
});
|
|
157
155
|
} else {
|
|
158
156
|
resolve(null);
|
|
159
157
|
}
|
|
160
158
|
});
|
|
161
159
|
};
|
|
160
|
+
|
|
161
|
+
export const validate = (model = {}, config = {}) => {
|
|
162
|
+
const { shapes } = model;
|
|
163
|
+
const { minShapes = 2, maxShapes, maxSelections } = config;
|
|
164
|
+
const errors = {};
|
|
165
|
+
|
|
166
|
+
const allShapes = Object.values(shapes || {}).reduce((acc, shape) => [...acc, ...shape], []);
|
|
167
|
+
|
|
168
|
+
const nbOfSelections = (allShapes || []).reduce((acc, shape) => (shape.correct ? acc + 1 : acc), 0);
|
|
169
|
+
|
|
170
|
+
const nbOfShapes = (allShapes || []).length;
|
|
171
|
+
|
|
172
|
+
if (nbOfShapes < minShapes) {
|
|
173
|
+
errors.shapesError = `There should be at least ${minShapes} shapes defined.`;
|
|
174
|
+
} else if (nbOfShapes > maxShapes) {
|
|
175
|
+
errors.shapesError = `No more than ${maxShapes} shapes should be defined.`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (nbOfSelections < 1) {
|
|
179
|
+
errors.selectionsError = 'There should be at least 1 shape selected.';
|
|
180
|
+
} else if (nbOfSelections > maxSelections) {
|
|
181
|
+
errors.selectionsError = `No more than ${maxSelections} shapes should be selected.`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return errors;
|
|
185
|
+
};
|
package/controller/src/utils.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import isEqual from 'lodash/isEqual';
|
|
2
2
|
import isEmpty from 'lodash/isEmpty';
|
|
3
3
|
|
|
4
|
-
export const getCorrectResponse = (choices) =>
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
export const getCorrectResponse = (choices) =>
|
|
5
|
+
choices
|
|
6
|
+
.filter((c) => c.correct)
|
|
7
|
+
.map((c) => c.id)
|
|
8
|
+
.sort();
|
|
8
9
|
|
|
9
10
|
export const isResponseCorrect = (question, session) => {
|
|
10
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
shapes: { rectangles, polygons },
|
|
13
|
+
} = question;
|
|
11
14
|
const choices = [...rectangles, ...polygons];
|
|
12
15
|
let correctResponseIds = getCorrectResponse(choices);
|
|
13
16
|
|
|
@@ -16,7 +19,7 @@ export const isResponseCorrect = (question, session) => {
|
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
if (session.answers && session.answers.length) {
|
|
19
|
-
let answerIds = (session.answers || []).map(a => a.id);
|
|
22
|
+
let answerIds = (session.answers || []).map((a) => a.id);
|
|
20
23
|
|
|
21
24
|
return isEqual(answerIds.sort(), correctResponseIds);
|
|
22
25
|
} else if (!(correctResponseIds && correctResponseIds.length)) {
|