@pie-element/categorize 11.0.1 → 11.0.2-esm.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/esm/controller.js CHANGED
@@ -5,83 +5,50 @@ import { getFeedbackForCorrectness } from '@pie-lib/feedback';
5
5
  import { partialScoring, lockChoices, getShuffledChoices } from '@pie-lib/controller-utils';
6
6
  import Translator from '@pie-lib/translator';
7
7
 
8
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
9
- try {
10
- var info = gen[key](arg);
11
- var value = info.value;
12
- } catch (error) {
13
- reject(error);
14
- return;
15
- }
16
-
17
- if (info.done) {
18
- resolve(value);
19
- } else {
20
- Promise.resolve(value).then(_next, _throw);
21
- }
22
- }
23
-
24
- function _asyncToGenerator(fn) {
25
- return function () {
26
- var self = this,
27
- args = arguments;
28
- return new Promise(function (resolve, reject) {
29
- var gen = fn.apply(self, args);
30
-
31
- function _next(value) {
32
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
33
- }
34
-
35
- function _throw(err) {
36
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
8
+ function _extends() {
9
+ _extends = Object.assign || function (target) {
10
+ for (var i = 1; i < arguments.length; i++) {
11
+ var source = arguments[i];
12
+
13
+ for (var key in source) {
14
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
15
+ target[key] = source[key];
16
+ }
37
17
  }
18
+ }
38
19
 
39
- _next(undefined);
40
- });
20
+ return target;
41
21
  };
42
- }
43
-
44
- function _defineProperty(obj, key, value) {
45
- if (key in obj) {
46
- Object.defineProperty(obj, key, {
47
- value: value,
48
- enumerable: true,
49
- configurable: true,
50
- writable: true
51
- });
52
- } else {
53
- obj[key] = value;
54
- }
55
22
 
56
- return obj;
23
+ return _extends.apply(this, arguments);
57
24
  }
58
25
 
59
26
  // used in configure too, for consistency modify it there too
60
- var multiplePlacements = {
27
+ const multiplePlacements = {
61
28
  enabled: 'Yes',
62
29
  disabled: 'No',
63
30
  perChoice: 'Set Per Choice'
64
31
  }; // used to validate the config
65
32
 
66
- var isCorrectResponseDuplicated = (choices, alternate) => {
33
+ const isCorrectResponseDuplicated = (choices, alternate) => {
67
34
  if (choices.length < 1 || alternate.length < 1) {
68
35
  return -1;
69
36
  }
70
37
 
71
- var stringChoices = JSON.stringify(choices.sort());
72
- var stringAlternate = alternate.reduce((total, current) => current.length > 0 ? [...total, JSON.stringify(current.sort())] : total, []);
73
- var foundIndexDuplicate = stringAlternate.findIndex(alternate => alternate.length && alternate === stringChoices);
38
+ const stringChoices = JSON.stringify(choices.sort());
39
+ const stringAlternate = alternate.reduce((total, current) => current.length > 0 ? [...total, JSON.stringify(current.sort())] : total, []);
40
+ const foundIndexDuplicate = stringAlternate.findIndex(alternate => alternate.length && alternate === stringChoices);
74
41
  return foundIndexDuplicate;
75
42
  };
76
- var isAlternateDuplicated = alternate => {
43
+ const isAlternateDuplicated = alternate => {
77
44
  if (alternate.length <= 1) {
78
45
  return -1;
79
46
  }
80
47
 
81
- var elementSet = new Set();
82
- var stringAlternate = alternate.reduce((total, current) => current.length > 0 ? [...total, JSON.stringify(current.sort())] : total, []);
48
+ const elementSet = new Set();
49
+ const stringAlternate = alternate.reduce((total, current) => current.length > 0 ? [...total, JSON.stringify(current.sort())] : total, []);
83
50
 
84
- for (var i = 0; i < stringAlternate.length; i++) {
51
+ for (let i = 0; i < stringAlternate.length; i++) {
85
52
  if (elementSet.has(stringAlternate[i]) && stringAlternate[i]) {
86
53
  return i;
87
54
  }
@@ -118,52 +85,43 @@ var defaults = {
118
85
  minRowHeight: '80px'
119
86
  };
120
87
 
121
- 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; }
122
-
123
- 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; }
124
- var {
88
+ const {
125
89
  translator
126
90
  } = Translator;
127
- var getPartialScore = (correctResponse, builtCategories) => {
91
+ const getPartialScore = (correctResponse, builtCategories) => {
128
92
  // in the resulted best scenario we make a sum with all the correct responses
129
93
  // and all the placements
130
- var {
94
+ const {
131
95
  placements,
132
96
  score
133
- } = builtCategories.reduce((acc, _ref) => {
134
- var {
135
- choices = []
136
- } = _ref;
137
- return {
138
- placements: acc.placements + choices.length,
139
- score: acc.score + choices.filter(ch => ch.correct).length
140
- };
141
- }, {
97
+ } = builtCategories.reduce((acc, {
98
+ choices: _choices = []
99
+ }) => ({
100
+ placements: acc.placements + _choices.length,
101
+ score: acc.score + _choices.filter(ch => ch.correct).length
102
+ }), {
142
103
  placements: 0,
143
104
  score: 0
144
105
  }); // in the correct response, we make a sum of the max possible score
145
106
 
146
- var {
107
+ const {
147
108
  maxScore
148
- } = correctResponse.reduce((acc, _ref2) => {
149
- var {
150
- choices
151
- } = _ref2;
152
- return {
153
- maxScore: acc.maxScore + choices.length
154
- };
155
- }, {
109
+ } = correctResponse.reduce((acc, {
110
+ choices
111
+ }) => ({
112
+ maxScore: acc.maxScore + choices.length
113
+ }), {
156
114
  maxScore: 0
157
115
  }); // if there are any extra placements, we subtract from the obtained score
158
116
 
159
- var extraPlacements = placements > maxScore ? placements - maxScore : 0;
160
- var totalScore = (score - extraPlacements) / maxScore;
117
+ const extraPlacements = placements > maxScore ? placements - maxScore : 0;
118
+ const totalScore = (score - extraPlacements) / maxScore;
161
119
  return totalScore < 0 ? 0 : parseFloat(totalScore.toFixed(2));
162
120
  };
163
121
 
164
- var getAlternates = correctResponse => correctResponse.map(c => c.alternateResponses).filter(alternate => alternate);
122
+ const getAlternates = correctResponse => correctResponse.map(c => c.alternateResponses).filter(alternate => alternate);
165
123
 
166
- var getTotalScore = (question, session, env) => {
124
+ const getTotalScore = (question, session, env) => {
167
125
  if (!session) {
168
126
  return 0;
169
127
  }
@@ -172,26 +130,26 @@ var getTotalScore = (question, session, env) => {
172
130
  return 0;
173
131
  }
174
132
 
175
- var {
133
+ const {
176
134
  categories,
177
135
  choices
178
136
  } = question || {};
179
- var {
137
+ let {
180
138
  correctResponse
181
139
  } = question || {};
182
- var {
140
+ let {
183
141
  answers
184
142
  } = session || {};
185
143
  answers = answers || [];
186
144
  correctResponse = correctResponse || []; // this function is used in pie-ui/categorize as well, in order to get the best scenario
187
145
  // so we get the best scenario and calculate the score
188
146
 
189
- var {
147
+ const {
190
148
  categories: builtCategories,
191
149
  correct
192
150
  } = buildState(categories, choices, answers, correctResponse);
193
- var alternates = getAlternates(correctResponse);
194
- var enabled = partialScoring.enabled(question, env); // if there are any alternates, there will be no partial scoring!
151
+ const alternates = getAlternates(correctResponse);
152
+ const enabled = partialScoring.enabled(question, env); // if there are any alternates, there will be no partial scoring!
195
153
 
196
154
  if (enabled && !alternates.length) {
197
155
  // we apply partial scoring
@@ -201,14 +159,14 @@ var getTotalScore = (question, session, env) => {
201
159
 
202
160
  return correct ? 1 : 0;
203
161
  };
204
- var getCorrectness = (question, session, env) => {
162
+ const getCorrectness = (question, session, env) => {
205
163
  return new Promise(resolve => {
206
164
  if (env.mode === 'evaluate') {
207
- var _score = getTotalScore(question, session, env);
165
+ const score = getTotalScore(question, session, env);
208
166
 
209
- if (_score === 1) {
167
+ if (score === 1) {
210
168
  resolve('correct');
211
- } else if (_score === 0) {
169
+ } else if (score === 0) {
212
170
  resolve('incorrect');
213
171
  } else {
214
172
  resolve('partially-correct');
@@ -218,13 +176,10 @@ var getCorrectness = (question, session, env) => {
218
176
  }
219
177
  });
220
178
  };
221
- var createDefaultModel = function createDefaultModel() {
222
- var model = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
223
- return new Promise(resolve => {
224
- resolve(_objectSpread(_objectSpread({}, defaults), model));
225
- });
226
- };
227
- var normalize = question => _objectSpread(_objectSpread({}, defaults), question);
179
+ const createDefaultModel = (model = {}) => new Promise(resolve => {
180
+ resolve(_extends({}, defaults, model));
181
+ });
182
+ const normalize = question => _extends({}, defaults, question);
228
183
  /**
229
184
  *
230
185
  * @param {*} question
@@ -233,108 +188,102 @@ var normalize = question => _objectSpread(_objectSpread({}, defaults), question)
233
188
  * @param {*} updateSession - optional - a function that will set the properties passed into it on the session.
234
189
  */
235
190
 
236
- var model = (question, session, env, updateSession) => new Promise( /*#__PURE__*/function () {
237
- var _ref3 = _asyncToGenerator(function* (resolve) {
238
- var normalizedQuestion = normalize(question);
239
- var answerCorrectness = yield getCorrectness(normalizedQuestion, session, env);
240
- var {
241
- mode,
242
- role
243
- } = env || {};
244
- var {
245
- categories,
246
- categoriesPerRow,
247
- choicesLabel,
248
- choicesPosition,
249
- correctResponse,
250
- feedback,
251
- feedbackEnabled,
252
- promptEnabled,
253
- prompt,
254
- rowLabels,
255
- rationaleEnabled,
256
- rationale,
257
- teacherInstructionsEnabled,
258
- teacherInstructions,
259
- language,
260
- maxChoicesPerCategory,
261
- extraCSSRules,
262
- minRowHeight,
263
- fontSizeFactor,
264
- autoplayAudioEnabled,
265
- completeAudioEnabled,
266
- customAudioButton
267
- } = normalizedQuestion;
268
- var {
269
- choices,
270
- note
271
- } = normalizedQuestion;
272
- var fb;
273
- var lockChoiceOrder = lockChoices(normalizedQuestion, session, env);
274
- var filteredCorrectResponse = correctResponse.map(response => {
275
- var filteredChoices = (response.choices || []).filter(choice => choice !== 'null');
276
- return _objectSpread(_objectSpread({}, response), {}, {
277
- choices: filteredChoices
278
- });
191
+ const model = (question, session, env, updateSession) => new Promise(async resolve => {
192
+ const normalizedQuestion = normalize(question);
193
+ const answerCorrectness = await getCorrectness(normalizedQuestion, session, env);
194
+ const {
195
+ mode,
196
+ role
197
+ } = env || {};
198
+ const {
199
+ categories,
200
+ categoriesPerRow,
201
+ choicesLabel,
202
+ choicesPosition,
203
+ correctResponse,
204
+ feedback,
205
+ feedbackEnabled,
206
+ promptEnabled,
207
+ prompt,
208
+ rowLabels,
209
+ rationaleEnabled,
210
+ rationale,
211
+ teacherInstructionsEnabled,
212
+ teacherInstructions,
213
+ language,
214
+ maxChoicesPerCategory,
215
+ extraCSSRules,
216
+ minRowHeight,
217
+ fontSizeFactor,
218
+ autoplayAudioEnabled,
219
+ completeAudioEnabled,
220
+ customAudioButton
221
+ } = normalizedQuestion;
222
+ let {
223
+ choices,
224
+ note
225
+ } = normalizedQuestion;
226
+ let fb;
227
+ const lockChoiceOrder = lockChoices(normalizedQuestion, session, env);
228
+ const filteredCorrectResponse = correctResponse.map(response => {
229
+ const filteredChoices = (response.choices || []).filter(choice => choice !== 'null');
230
+ return _extends({}, response, {
231
+ choices: filteredChoices
279
232
  });
233
+ });
280
234
 
281
- if (mode === 'evaluate' && feedbackEnabled) {
282
- fb = yield getFeedbackForCorrectness(answerCorrectness, feedback);
283
- }
235
+ if (mode === 'evaluate' && feedbackEnabled) {
236
+ fb = await getFeedbackForCorrectness(answerCorrectness, feedback);
237
+ }
284
238
 
285
- if (!lockChoiceOrder) {
286
- choices = yield getShuffledChoices(choices, session, updateSession, 'id');
287
- }
239
+ if (!lockChoiceOrder) {
240
+ choices = await getShuffledChoices(choices, session, updateSession, 'id');
241
+ }
288
242
 
289
- if (!note) {
290
- note = translator.t('common:commonCorrectAnswerWithAlternates', {
291
- lng: language
292
- });
293
- }
243
+ if (!note) {
244
+ note = translator.t('common:commonCorrectAnswerWithAlternates', {
245
+ lng: language
246
+ });
247
+ }
294
248
 
295
- var alternates = getAlternates(filteredCorrectResponse);
296
- var out = {
297
- categories: categories || [],
298
- categoriesPerRow: categoriesPerRow || 2,
299
- maxChoicesPerCategory,
300
- correctness: answerCorrectness,
301
- choices: choices || [],
302
- choicesLabel: choicesLabel || '',
303
- choicesPosition,
304
- disabled: mode !== 'gather',
305
- feedback: fb,
306
- lockChoiceOrder,
307
- prompt: promptEnabled ? prompt : null,
308
- rowLabels,
309
- note,
310
- env,
311
- showNote: alternates && alternates.length > 0,
312
- correctResponse: mode === 'evaluate' ? filteredCorrectResponse : undefined,
313
- language,
314
- extraCSSRules,
315
- fontSizeFactor,
316
- minRowHeight: minRowHeight,
317
- autoplayAudioEnabled,
318
- completeAudioEnabled,
319
- customAudioButton
320
- };
321
-
322
- if (role === 'instructor' && (mode === 'view' || mode === 'evaluate')) {
323
- out.rationale = rationaleEnabled ? rationale : null;
324
- out.teacherInstructions = teacherInstructionsEnabled ? teacherInstructions : null;
325
- } else {
326
- out.rationale = null;
327
- out.teacherInstructions = null;
328
- }
249
+ const alternates = getAlternates(filteredCorrectResponse);
250
+ const out = {
251
+ categories: categories || [],
252
+ categoriesPerRow: categoriesPerRow || 2,
253
+ maxChoicesPerCategory,
254
+ correctness: answerCorrectness,
255
+ choices: choices || [],
256
+ choicesLabel: choicesLabel || '',
257
+ choicesPosition,
258
+ disabled: mode !== 'gather',
259
+ feedback: fb,
260
+ lockChoiceOrder,
261
+ prompt: promptEnabled ? prompt : null,
262
+ rowLabels,
263
+ note,
264
+ env,
265
+ showNote: alternates && alternates.length > 0,
266
+ correctResponse: mode === 'evaluate' ? filteredCorrectResponse : undefined,
267
+ language,
268
+ extraCSSRules,
269
+ fontSizeFactor,
270
+ minRowHeight: minRowHeight,
271
+ autoplayAudioEnabled,
272
+ completeAudioEnabled,
273
+ customAudioButton
274
+ };
329
275
 
330
- resolve(out);
331
- });
276
+ if (role === 'instructor' && (mode === 'view' || mode === 'evaluate')) {
277
+ out.rationale = rationaleEnabled ? rationale : null;
278
+ out.teacherInstructions = teacherInstructionsEnabled ? teacherInstructions : null;
279
+ } else {
280
+ out.rationale = null;
281
+ out.teacherInstructions = null;
282
+ }
332
283
 
333
- return function (_x) {
334
- return _ref3.apply(this, arguments);
335
- };
336
- }());
337
- var outcome = (question, session, env) => {
284
+ resolve(out);
285
+ });
286
+ const outcome = (question, session, env) => {
338
287
  if (env.mode !== 'evaluate') {
339
288
  return Promise.reject(new Error('Can not call outcome when mode is not evaluate'));
340
289
  } else {
@@ -346,15 +295,15 @@ var outcome = (question, session, env) => {
346
295
  });
347
296
  }
348
297
  };
349
- var createCorrectResponseSession = (question, env) => {
298
+ const createCorrectResponseSession = (question, env) => {
350
299
  return new Promise(resolve => {
351
- var {
300
+ const {
352
301
  mode,
353
302
  role
354
303
  } = env || {};
355
304
 
356
305
  if (mode !== 'evaluate' && role === 'instructor') {
357
- var {
306
+ const {
358
307
  correctResponse
359
308
  } = question;
360
309
  resolve({
@@ -367,87 +316,85 @@ var createCorrectResponseSession = (question, env) => {
367
316
  });
368
317
  }; // remove all html tags
369
318
 
370
- var getInnerText = html => (html || '').replaceAll(/<[^>]*>/g, ''); // remove all html tags except img, iframe and source tag for audio
319
+ const getInnerText = html => (html || '').replaceAll(/<[^>]*>/g, ''); // remove all html tags except img, iframe and source tag for audio
371
320
 
372
321
 
373
- var getContent = html => (html || '').replace(/(<(?!img|iframe|source)([^>]+)>)/gi, '');
322
+ const getContent = html => (html || '').replace(/(<(?!img|iframe|source)([^>]+)>)/gi, '');
374
323
 
375
- var validate = function validate() {
376
- var model = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
377
- var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
378
- var {
324
+ const validate = (model = {}, config = {}) => {
325
+ const {
379
326
  categories,
380
327
  choices,
381
328
  correctResponse,
382
329
  maxAnswerChoices
383
330
  } = model;
384
- var {
331
+ const {
385
332
  minChoices = 1,
386
333
  minCategories = 1,
387
334
  maxCategories = 12,
388
335
  maxLengthPerChoice = 300,
389
336
  maxLengthPerCategory = 150
390
337
  } = config;
391
- var reversedChoices = [...(choices || [])].reverse();
392
- var errors = {};
393
- var choicesErrors = {};
394
- var categoriesErrors = {};
338
+ const reversedChoices = [...(choices || [])].reverse();
339
+ const errors = {};
340
+ const choicesErrors = {};
341
+ const categoriesErrors = {};
395
342
  ['teacherInstructions', 'prompt', 'rationale'].forEach(field => {
396
343
  var _config$field;
397
344
 
398
- if ((_config$field = config[field]) !== null && _config$field !== void 0 && _config$field.required && !getContent(model[field])) {
345
+ if ((_config$field = config[field]) != null && _config$field.required && !getContent(model[field])) {
399
346
  errors[field] = 'This field is required.';
400
347
  }
401
348
  });
402
349
  (categories || []).forEach(category => {
403
- var {
350
+ const {
404
351
  id,
405
352
  label
406
353
  } = category;
407
354
 
408
355
  if (getInnerText(label).length > maxLengthPerCategory) {
409
- categoriesErrors[id] = "Category labels should be no more than ".concat(maxLengthPerCategory, " characters long.");
356
+ categoriesErrors[id] = `Category labels should be no more than ${maxLengthPerCategory} characters long.`;
410
357
  }
411
358
  });
412
359
  (reversedChoices || []).forEach((choice, index) => {
413
- var {
360
+ const {
414
361
  id,
415
362
  content
416
363
  } = choice;
417
364
 
418
365
  if (getInnerText(content).length > maxLengthPerChoice) {
419
- choicesErrors[id] = "Tokens should be no more than ".concat(maxLengthPerChoice, " characters long.");
366
+ choicesErrors[id] = `Tokens should be no more than ${maxLengthPerChoice} characters long.`;
420
367
  }
421
368
 
422
369
  if (!getContent(content)) {
423
370
  choicesErrors[id] = 'Tokens should not be empty.';
424
371
  } else {
425
- var identicalAnswer = reversedChoices.slice(index + 1).some(c => c.content === content);
372
+ const identicalAnswer = reversedChoices.slice(index + 1).some(c => c.content === content);
426
373
 
427
374
  if (identicalAnswer) {
428
375
  choicesErrors[id] = 'Tokens content should be unique.';
429
376
  }
430
377
  }
431
378
  });
432
- var nbOfCategories = (categories || []).length;
433
- var nbOfChoices = (choices || []).length;
379
+ const nbOfCategories = (categories || []).length;
380
+ const nbOfChoices = (choices || []).length;
434
381
 
435
382
  if (nbOfCategories > maxCategories) {
436
- errors.categoriesError = "No more than ".concat(maxCategories, " categories should be defined.");
383
+ errors.categoriesError = `No more than ${maxCategories} categories should be defined.`;
437
384
  } else if (nbOfCategories < minCategories) {
438
- errors.categoriesError = "There should be at least ".concat(minCategories, " category defined.");
385
+ errors.categoriesError = `There should be at least ${minCategories} category defined.`;
439
386
  }
440
387
 
441
388
  if (nbOfChoices < minChoices) {
442
- errors.choicesError = "There should be at least ".concat(minChoices, " choices defined.");
389
+ errors.choicesError = `There should be at least ${minChoices} choices defined.`;
443
390
  } else if (nbOfChoices > maxAnswerChoices) {
444
- errors.choicesError = "No more than ".concat(maxAnswerChoices, " choices should be defined.");
391
+ errors.choicesError = `No more than ${maxAnswerChoices} choices should be defined.`;
445
392
  }
446
393
 
447
394
  if (nbOfChoices && nbOfCategories) {
448
- var hasAssociations = false;
395
+ let hasAssociations = false;
449
396
  (correctResponse || []).forEach(response => {
450
- var {
397
+ const {
451
398
  choices = [],
452
399
  alternateResponses = []
453
400
  } = response;
@@ -462,10 +409,10 @@ var validate = function validate() {
462
409
  });
463
410
  }
464
411
  });
465
- var duplicateAlternateIndex = -1;
466
- var duplicateCategory = '';
412
+ let duplicateAlternateIndex = -1;
413
+ let duplicateCategory = '';
467
414
  (correctResponse || []).forEach(response => {
468
- var {
415
+ const {
469
416
  choices = [],
470
417
  alternateResponses = [],
471
418
  category