@thanh01.pmt/interactive-quiz-kit 1.0.23 → 1.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -11,26 +11,6 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
11
 
12
12
  var JSZip__default = /*#__PURE__*/_interopDefault(JSZip);
13
13
 
14
- var __defProp = Object.defineProperty;
15
- var __defProps = Object.defineProperties;
16
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
17
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
18
- var __hasOwnProp = Object.prototype.hasOwnProperty;
19
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
20
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
21
- var __spreadValues = (a, b) => {
22
- for (var prop in b || (b = {}))
23
- if (__hasOwnProp.call(b, prop))
24
- __defNormalProp(a, prop, b[prop]);
25
- if (__getOwnPropSymbols)
26
- for (var prop of __getOwnPropSymbols(b)) {
27
- if (__propIsEnum.call(b, prop))
28
- __defNormalProp(a, prop, b[prop]);
29
- }
30
- return a;
31
- };
32
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
33
-
34
14
  // src/services/SCORMService.ts
35
15
  var SCORM_TRUE = "true";
36
16
  var SCORM_NO_ERROR = "0";
@@ -50,11 +30,12 @@ var SCORMService = class {
50
30
  this.isInitialized = false;
51
31
  this.isTerminated = false;
52
32
  this.studentName = null;
53
- this.settings = __spreadValues({
33
+ this.settings = {
54
34
  setCompletionOnFinish: true,
55
35
  setSuccessOnPass: true,
56
- autoCommit: true
57
- }, settings);
36
+ autoCommit: true,
37
+ ...settings
38
+ };
58
39
  if (typeof window !== "undefined") {
59
40
  this._findAPI();
60
41
  }
@@ -160,14 +141,13 @@ var SCORMService = class {
160
141
  }
161
142
  }
162
143
  getValue(element) {
163
- var _a;
164
144
  if (!this.hasAPI() || !this.isInitialized) return null;
165
145
  const value = this.scormVersionFound === "2004" ? this.scormAPI.GetValue(element) : this.scormAPI.LMSGetValue(element);
166
146
  const error = this.getLastError();
167
147
  if (error.code !== SCORM_NO_ERROR && error.code !== "403" && error.code !== "0") {
168
148
  console.warn(`SCORMService: GetValue for ${element} produced an error ${error.code}: ${error.message}. Returning raw value:`, value);
169
149
  }
170
- return (_a = value == null ? void 0 : value.toString()) != null ? _a : null;
150
+ return value?.toString() ?? null;
171
151
  }
172
152
  commit() {
173
153
  if (!this.hasAPI() || !this.isInitialized) {
@@ -239,7 +219,6 @@ var SCORMService = class {
239
219
  }
240
220
  }
241
221
  getLastError() {
242
- var _a, _b;
243
222
  if (!this.hasAPI()) return { code: "-1", message: "SCORM API not found." };
244
223
  const errorCode = this.scormVersionFound === "2004" ? this.scormAPI.GetLastError() : this.scormAPI.LMSGetLastError();
245
224
  if (errorCode === SCORM_NO_ERROR || errorCode === 0 || errorCode === "0") {
@@ -249,8 +228,8 @@ var SCORMService = class {
249
228
  const diagnostic = this.scormVersionFound === "2004" ? this.scormAPI.GetDiagnostic(errorCode.toString()) : this.scormAPI.LMSGetDiagnostic(errorCode.toString());
250
229
  return {
251
230
  code: errorCode.toString(),
252
- message: (_a = errorMessage == null ? void 0 : errorMessage.toString()) != null ? _a : "Unknown error.",
253
- diagnostic: (_b = diagnostic == null ? void 0 : diagnostic.toString()) != null ? _b : void 0
231
+ message: errorMessage?.toString() ?? "Unknown error.",
232
+ diagnostic: diagnostic?.toString() ?? void 0
254
233
  };
255
234
  }
256
235
  formatCMITime(totalSeconds) {
@@ -281,14 +260,13 @@ var SCORMService = class {
281
260
  // src/services/evaluators/multiple-choice-evaluator.ts
282
261
  var MultipleChoiceEvaluator = class {
283
262
  async evaluate(question, answer) {
284
- var _a;
285
- const points = (_a = question.points) != null ? _a : 0;
263
+ const points = question.points ?? 0;
286
264
  const correctAnswerId = question.correctAnswerId;
287
265
  const isCorrect = answer === correctAnswerId;
288
266
  const correctOption = question.options.find((opt) => opt.id === correctAnswerId);
289
267
  const correctAnswerDetail = {
290
268
  id: correctAnswerId,
291
- value: (correctOption == null ? void 0 : correctOption.text) || ""
269
+ value: correctOption?.text || ""
292
270
  };
293
271
  return Promise.resolve({
294
272
  isCorrect,
@@ -301,8 +279,7 @@ var MultipleChoiceEvaluator = class {
301
279
  // src/services/evaluators/multiple-response-evaluator.ts
302
280
  var MultipleResponseEvaluator = class {
303
281
  async evaluate(question, answer) {
304
- var _a;
305
- const points = (_a = question.points) != null ? _a : 0;
282
+ const points = question.points ?? 0;
306
283
  const correctAnswerIds = question.correctAnswerIds;
307
284
  let isCorrect = false;
308
285
  if (Array.isArray(answer)) {
@@ -311,10 +288,7 @@ var MultipleResponseEvaluator = class {
311
288
  isCorrect = userAnswerSet.size === correctAnswerSet.size && [...userAnswerSet].every((id) => correctAnswerSet.has(id));
312
289
  }
313
290
  const correctValues = correctAnswerIds.map(
314
- (id) => {
315
- var _a2;
316
- return ((_a2 = question.options.find((opt) => opt.id === id)) == null ? void 0 : _a2.text) || "";
317
- }
291
+ (id) => question.options.find((opt) => opt.id === id)?.text || ""
318
292
  );
319
293
  const correctAnswerDetail = {
320
294
  id: correctAnswerIds,
@@ -331,8 +305,7 @@ var MultipleResponseEvaluator = class {
331
305
  // src/services/evaluators/true-false-evaluator.ts
332
306
  var TrueFalseEvaluator = class {
333
307
  async evaluate(question, answer) {
334
- var _a;
335
- const points = (_a = question.points) != null ? _a : 0;
308
+ const points = question.points ?? 0;
336
309
  const correctAnswer = question.correctAnswer;
337
310
  let userAnswer = answer;
338
311
  if (typeof answer === "string") {
@@ -354,12 +327,11 @@ var TrueFalseEvaluator = class {
354
327
  // src/services/evaluators/short-answer-evaluator.ts
355
328
  var ShortAnswerEvaluator = class {
356
329
  async evaluate(question, answer) {
357
- var _a, _b;
358
- const points = (_a = question.points) != null ? _a : 0;
330
+ const points = question.points ?? 0;
359
331
  let isCorrect = false;
360
332
  if (typeof answer === "string") {
361
333
  const userAnswerTrimmed = answer.trim();
362
- const caseSensitive = (_b = question.isCaseSensitive) != null ? _b : false;
334
+ const caseSensitive = question.isCaseSensitive ?? false;
363
335
  isCorrect = question.acceptedAnswers.some(
364
336
  (accAns) => caseSensitive ? accAns.trim() === userAnswerTrimmed : accAns.trim().toLowerCase() === userAnswerTrimmed.toLowerCase()
365
337
  );
@@ -379,8 +351,7 @@ var ShortAnswerEvaluator = class {
379
351
  // src/services/evaluators/numeric-evaluator.ts
380
352
  var NumericEvaluator = class {
381
353
  async evaluate(question, answer) {
382
- var _a;
383
- const points = (_a = question.points) != null ? _a : 0;
354
+ const points = question.points ?? 0;
384
355
  let isCorrect = false;
385
356
  if (typeof answer === "string" || typeof answer === "number") {
386
357
  const userAnswerNum = parseFloat(String(answer));
@@ -403,17 +374,13 @@ var NumericEvaluator = class {
403
374
  // src/services/evaluators/sequence-evaluator.ts
404
375
  var SequenceEvaluator = class {
405
376
  async evaluate(question, answer) {
406
- var _a;
407
- const points = (_a = question.points) != null ? _a : 0;
377
+ const points = question.points ?? 0;
408
378
  let isCorrect = false;
409
379
  if (Array.isArray(answer) && answer.length === question.correctOrder.length) {
410
380
  isCorrect = answer.every((itemId, index) => itemId === question.correctOrder[index]);
411
381
  }
412
382
  const correctValues = question.correctOrder.map(
413
- (id) => {
414
- var _a2;
415
- return ((_a2 = question.items.find((item) => item.id === id)) == null ? void 0 : _a2.content) || "";
416
- }
383
+ (id) => question.items.find((item) => item.id === id)?.content || ""
417
384
  );
418
385
  const correctAnswerDetail = {
419
386
  id: question.correctOrder,
@@ -430,17 +397,15 @@ var SequenceEvaluator = class {
430
397
  // src/services/evaluators/matching-evaluator.ts
431
398
  var MatchingEvaluator = class {
432
399
  async evaluate(question, answer) {
433
- var _a;
434
- const points = (_a = question.points) != null ? _a : 0;
400
+ const points = question.points ?? 0;
435
401
  let isCorrect = false;
436
402
  if (typeof answer === "object" && answer !== null && !Array.isArray(answer)) {
437
403
  const userAnswerMap = answer;
438
404
  isCorrect = question.correctAnswerMap.length === Object.keys(userAnswerMap).length && question.correctAnswerMap.every((map) => userAnswerMap[map.promptId] === map.optionId);
439
405
  }
440
406
  const correctMap = question.correctAnswerMap.reduce((acc, curr) => {
441
- var _a2, _b;
442
- const promptText = ((_a2 = question.prompts.find((p) => p.id === curr.promptId)) == null ? void 0 : _a2.content) || "";
443
- const optionText = ((_b = question.options.find((o) => o.id === curr.optionId)) == null ? void 0 : _b.content) || "";
407
+ const promptText = question.prompts.find((p) => p.id === curr.promptId)?.content || "";
408
+ const optionText = question.options.find((o) => o.id === curr.optionId)?.content || "";
444
409
  acc[promptText] = optionText;
445
410
  return acc;
446
411
  }, {});
@@ -459,16 +424,14 @@ var MatchingEvaluator = class {
459
424
  // src/services/evaluators/fill-in-the-blanks-evaluator.ts
460
425
  var FillInTheBlanksEvaluator = class {
461
426
  async evaluate(question, answer) {
462
- var _a;
463
- const points = (_a = question.points) != null ? _a : 0;
427
+ const points = question.points ?? 0;
464
428
  let isCorrect = false;
465
429
  if (typeof answer === "object" && answer !== null && !Array.isArray(answer)) {
466
430
  const userAnswerMap = answer;
467
431
  isCorrect = question.answers.length > 0 && question.answers.every((correctAnsDef) => {
468
- var _a2, _b;
469
- const userValForBlank = (_a2 = userAnswerMap[correctAnsDef.blankId]) == null ? void 0 : _a2.trim();
432
+ const userValForBlank = userAnswerMap[correctAnsDef.blankId]?.trim();
470
433
  if (userValForBlank === void 0) return false;
471
- const caseSensitive = (_b = question.isCaseSensitive) != null ? _b : false;
434
+ const caseSensitive = question.isCaseSensitive ?? false;
472
435
  return correctAnsDef.acceptedValues.some(
473
436
  (accVal) => caseSensitive ? accVal.trim() === userValForBlank : accVal.trim().toLowerCase() === userValForBlank.toLowerCase()
474
437
  );
@@ -493,17 +456,15 @@ var FillInTheBlanksEvaluator = class {
493
456
  // src/services/evaluators/drag-and-drop-evaluator.ts
494
457
  var DragAndDropEvaluator = class {
495
458
  async evaluate(question, answer) {
496
- var _a;
497
- const points = (_a = question.points) != null ? _a : 0;
459
+ const points = question.points ?? 0;
498
460
  let isCorrect = false;
499
461
  if (typeof answer === "object" && answer !== null && !Array.isArray(answer)) {
500
462
  const userAnswerMap = answer;
501
463
  isCorrect = question.answerMap.length === Object.keys(userAnswerMap).length && question.answerMap.every((map) => userAnswerMap[map.draggableId] === map.dropZoneId);
502
464
  }
503
465
  const correctMap = question.answerMap.reduce((acc, curr) => {
504
- var _a2, _b;
505
- const draggableText = ((_a2 = question.draggableItems.find((d) => d.id === curr.draggableId)) == null ? void 0 : _a2.content) || "";
506
- const dropZoneText = ((_b = question.dropZones.find((z4) => z4.id === curr.dropZoneId)) == null ? void 0 : _b.label) || "";
466
+ const draggableText = question.draggableItems.find((d) => d.id === curr.draggableId)?.content || "";
467
+ const dropZoneText = question.dropZones.find((z4) => z4.id === curr.dropZoneId)?.label || "";
507
468
  acc[draggableText] = dropZoneText;
508
469
  return acc;
509
470
  }, {});
@@ -522,8 +483,7 @@ var DragAndDropEvaluator = class {
522
483
  // src/services/evaluators/hotspot-evaluator.ts
523
484
  var HotspotEvaluator = class {
524
485
  async evaluate(question, answer) {
525
- var _a;
526
- const points = (_a = question.points) != null ? _a : 0;
486
+ const points = question.points ?? 0;
527
487
  let isCorrect = false;
528
488
  if (Array.isArray(answer)) {
529
489
  const userAnswerSet = new Set(answer);
@@ -531,10 +491,7 @@ var HotspotEvaluator = class {
531
491
  isCorrect = userAnswerSet.size === correctAnswerSet.size && [...userAnswerSet].every((id) => correctAnswerSet.has(id));
532
492
  }
533
493
  const correctValues = question.correctHotspotIds.map(
534
- (id) => {
535
- var _a2;
536
- return ((_a2 = question.hotspots.find((h) => h.id === id)) == null ? void 0 : _a2.description) || id;
537
- }
494
+ (id) => question.hotspots.find((h) => h.id === id)?.description || id
538
495
  );
539
496
  const correctAnswerDetail = {
540
497
  id: question.correctHotspotIds,
@@ -551,11 +508,10 @@ var HotspotEvaluator = class {
551
508
  // src/services/evaluators/programming-evaluator.ts
552
509
  var ProgrammingEvaluator = class {
553
510
  async evaluate(question, answer) {
554
- var _a, _b;
555
- const points = (_a = question.points) != null ? _a : 0;
511
+ const points = question.points ?? 0;
556
512
  let isCorrect = false;
557
513
  if (typeof answer === "string" && typeof question.solutionGeneratedCode === "string") {
558
- if (typeof window !== "undefined" && ((_b = window.Blockly) == null ? void 0 : _b.JavaScript)) {
514
+ if (typeof window !== "undefined" && window.Blockly?.JavaScript) {
559
515
  const LocalBlockly = window.Blockly;
560
516
  let generatedUserCode = "";
561
517
  try {
@@ -629,10 +585,10 @@ var JsonRepairEngine = class {
629
585
  if (breakIndex !== -1) {
630
586
  const stringContent = afterUnterminated.substring(0, breakIndex);
631
587
  const remainder = afterUnterminated.substring(breakIndex);
632
- const escapedContent = stringContent.replace(new RegExp('(?<!\\\\)"', "g"), '\\"');
588
+ const escapedContent = stringContent.replace(/(?<!\\)"/g, '\\"');
633
589
  repaired = beforeUnterminated + escapedContent + '"' + remainder;
634
590
  } else {
635
- const escapedContent = afterUnterminated.replace(new RegExp('(?<!\\\\)"', "g"), '\\"');
591
+ const escapedContent = afterUnterminated.replace(/(?<!\\)"/g, '\\"');
636
592
  repaired = beforeUnterminated + escapedContent + '"';
637
593
  }
638
594
  }
@@ -708,7 +664,6 @@ var JsonRepairEngine = class {
708
664
  * Main repair function that attempts multiple strategies.
709
665
  */
710
666
  static repairJson(jsonStr) {
711
- var _a;
712
667
  let current = jsonStr.trim();
713
668
  const maxAttempts = 5;
714
669
  let lastError = "";
@@ -738,7 +693,7 @@ var JsonRepairEngine = class {
738
693
  }
739
694
  lastError = validation.error || "";
740
695
  lastPosition = validation.position;
741
- if ((_a = validation.error) == null ? void 0 : _a.includes("Unterminated string")) {
696
+ if (validation.error?.includes("Unterminated string")) {
742
697
  current = this.repairUnterminatedStrings(current);
743
698
  } else {
744
699
  current = this.applyCommonFixes(current);
@@ -1033,9 +988,10 @@ var CodeEvaluationService = class {
1033
988
  userCode,
1034
989
  testCase
1035
990
  }, this.apiKey);
1036
- return __spreadValues({
1037
- testCaseId: testCase.id
1038
- }, aiResult);
991
+ return {
992
+ testCaseId: testCase.id,
993
+ ...aiResult
994
+ };
1039
995
  }
1040
996
  /**
1041
997
  * Evaluates user's code against all test cases for a given question.
@@ -1072,8 +1028,7 @@ var CodeEvaluationService = class {
1072
1028
  // src/services/evaluators/coding-evaluator.ts
1073
1029
  var CodingEvaluator = class {
1074
1030
  async evaluate(question, answer) {
1075
- var _a;
1076
- const points = (_a = question.points) != null ? _a : 0;
1031
+ const points = question.points ?? 0;
1077
1032
  if (typeof answer !== "string" || !answer.trim()) {
1078
1033
  return {
1079
1034
  isCorrect: false,
@@ -1130,17 +1085,16 @@ var QuizEngine = class {
1130
1085
  this.quizResultState = { scormStatus: "idle" };
1131
1086
  this.questionStartTime = null;
1132
1087
  this.questionTimings = /* @__PURE__ */ new Map();
1133
- var _a, _b, _c, _d, _e;
1134
1088
  this.config = options.config;
1135
1089
  this.callbacks = options.callbacks || {};
1136
- this.questions = ((_a = this.config.settings) == null ? void 0 : _a.shuffleQuestions) ? [...this.config.questions].sort(() => Math.random() - 0.5) : this.config.questions;
1090
+ this.questions = this.config.settings?.shuffleQuestions ? [...this.config.questions].sort(() => Math.random() - 0.5) : this.config.questions;
1137
1091
  this.overallStartTime = Date.now();
1138
1092
  this.evaluators = /* @__PURE__ */ new Map();
1139
1093
  this.registerEvaluators();
1140
- if (((_b = this.config.settings) == null ? void 0 : _b.timeLimitMinutes) && this.config.settings.timeLimitMinutes > 0) {
1094
+ if (this.config.settings?.timeLimitMinutes && this.config.settings.timeLimitMinutes > 0) {
1141
1095
  this.timeLeftInSeconds = this.config.settings.timeLimitMinutes * 60;
1142
1096
  }
1143
- if ((_c = this.config.settings) == null ? void 0 : _c.scorm) {
1097
+ if (this.config.settings?.scorm) {
1144
1098
  this.quizResultState.scormStatus = "initializing";
1145
1099
  this.scormService = new SCORMService(this.config.settings.scorm);
1146
1100
  if (this.scormService.hasAPI()) {
@@ -1173,7 +1127,7 @@ var QuizEngine = class {
1173
1127
  if (this.timeLeftInSeconds !== null) {
1174
1128
  this.startTimer();
1175
1129
  }
1176
- (_e = (_d = this.callbacks).onQuestionChange) == null ? void 0 : _e.call(_d, initialQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1130
+ this.callbacks.onQuestionChange?.(initialQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1177
1131
  }
1178
1132
  registerEvaluators() {
1179
1133
  this.evaluators.set("multiple_choice", new MultipleChoiceEvaluator());
@@ -1211,15 +1165,14 @@ var QuizEngine = class {
1211
1165
  }
1212
1166
  }
1213
1167
  handleTick() {
1214
- var _a, _b, _c, _d;
1215
1168
  if (this.timeLeftInSeconds === null) return;
1216
1169
  if (this.timeLeftInSeconds > 0) {
1217
1170
  this.timeLeftInSeconds--;
1218
- (_b = (_a = this.callbacks).onTimeTick) == null ? void 0 : _b.call(_a, this.timeLeftInSeconds);
1171
+ this.callbacks.onTimeTick?.(this.timeLeftInSeconds);
1219
1172
  }
1220
1173
  if (this.timeLeftInSeconds <= 0) {
1221
1174
  this.stopTimer();
1222
- (_d = (_c = this.callbacks).onQuizTimeUp) == null ? void 0 : _d.call(_c);
1175
+ this.callbacks.onQuizTimeUp?.();
1223
1176
  this.calculateResults();
1224
1177
  }
1225
1178
  }
@@ -1242,43 +1195,39 @@ var QuizEngine = class {
1242
1195
  return this.quizResultState.score !== void 0;
1243
1196
  }
1244
1197
  submitAnswer(questionId, answer) {
1245
- var _a, _b;
1246
1198
  this.userAnswers.set(questionId, answer);
1247
1199
  const question = this.questions.find((q) => q.id === questionId);
1248
- if (question) (_b = (_a = this.callbacks).onAnswerSubmit) == null ? void 0 : _b.call(_a, question, answer);
1200
+ if (question) this.callbacks.onAnswerSubmit?.(question, answer);
1249
1201
  }
1250
1202
  nextQuestion() {
1251
- var _a, _b;
1252
1203
  this._recordCurrentQuestionTime();
1253
1204
  if (this.currentQuestionIndex < this.questions.length - 1) {
1254
1205
  this.currentQuestionIndex++;
1255
1206
  const currentQ = this.getCurrentQuestion();
1256
1207
  this.questionStartTime = Date.now();
1257
- (_b = (_a = this.callbacks).onQuestionChange) == null ? void 0 : _b.call(_a, currentQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1208
+ this.callbacks.onQuestionChange?.(currentQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1258
1209
  return currentQ;
1259
1210
  }
1260
1211
  return null;
1261
1212
  }
1262
1213
  previousQuestion() {
1263
- var _a, _b;
1264
1214
  this._recordCurrentQuestionTime();
1265
1215
  if (this.currentQuestionIndex > 0) {
1266
1216
  this.currentQuestionIndex--;
1267
1217
  const currentQ = this.getCurrentQuestion();
1268
1218
  this.questionStartTime = Date.now();
1269
- (_b = (_a = this.callbacks).onQuestionChange) == null ? void 0 : _b.call(_a, currentQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1219
+ this.callbacks.onQuestionChange?.(currentQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1270
1220
  return currentQ;
1271
1221
  }
1272
1222
  return null;
1273
1223
  }
1274
1224
  goToQuestion(index) {
1275
- var _a, _b;
1276
1225
  if (index >= 0 && index < this.questions.length && index !== this.currentQuestionIndex) {
1277
1226
  this._recordCurrentQuestionTime();
1278
1227
  this.currentQuestionIndex = index;
1279
1228
  const currentQ = this.getCurrentQuestion();
1280
1229
  this.questionStartTime = Date.now();
1281
- (_b = (_a = this.callbacks).onQuestionChange) == null ? void 0 : _b.call(_a, currentQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1230
+ this.callbacks.onQuestionChange?.(currentQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1282
1231
  return currentQ;
1283
1232
  }
1284
1233
  return this.getCurrentQuestion();
@@ -1304,7 +1253,6 @@ var QuizEngine = class {
1304
1253
  }
1305
1254
  // (Tiếp theo từ Phần 1)
1306
1255
  async calculateResults() {
1307
- var _a, _b, _c, _d, _e;
1308
1256
  this.stopTimer();
1309
1257
  this._recordCurrentQuestionTime();
1310
1258
  let totalScore = 0;
@@ -1313,7 +1261,7 @@ var QuizEngine = class {
1313
1261
  let accumulatedTotalTimeSpent = 0;
1314
1262
  for (const question of this.questions) {
1315
1263
  const userAnswerRaw = this.userAnswers.get(question.id) || null;
1316
- maxScore += (_a = question.points) != null ? _a : 0;
1264
+ maxScore += question.points ?? 0;
1317
1265
  const evaluator = this.evaluators.get(question.questionType);
1318
1266
  if (!evaluator) {
1319
1267
  console.warn(`No evaluator found for question type: ${question.questionType}`);
@@ -1353,13 +1301,13 @@ var QuizEngine = class {
1353
1301
  }
1354
1302
  const percentage = maxScore > 0 ? parseFloat((totalScore / maxScore * 100).toFixed(2)) : 0;
1355
1303
  let passed = void 0;
1356
- if (((_b = this.config.settings) == null ? void 0 : _b.passingScorePercent) != null) {
1304
+ if (this.config.settings?.passingScorePercent != null) {
1357
1305
  passed = percentage >= this.config.settings.passingScorePercent;
1358
1306
  }
1359
1307
  const totalQuizTimeSpentSeconds = parseFloat(accumulatedTotalTimeSpent.toFixed(2));
1360
1308
  const averageTimePerQuestionSeconds = this.questions.length > 0 ? parseFloat((totalQuizTimeSpentSeconds / this.questions.length).toFixed(2)) : 0;
1361
1309
  const metadataPerformance = await this._calculateMetadataPerformance();
1362
- const finalResults = __spreadValues({
1310
+ const finalResults = {
1363
1311
  score: totalScore,
1364
1312
  maxScore,
1365
1313
  percentage,
@@ -1371,39 +1319,33 @@ var QuizEngine = class {
1371
1319
  scormError: this.quizResultState.scormError,
1372
1320
  studentName: this.quizResultState.studentName,
1373
1321
  totalTimeSpentSeconds: totalQuizTimeSpentSeconds,
1374
- averageTimePerQuestionSeconds
1375
- }, metadataPerformance);
1376
- this.quizResultState = __spreadValues(__spreadValues({}, this.quizResultState), finalResults);
1377
- if ((_c = this.config.settings) == null ? void 0 : _c.scorm) this._sendResultsToSCORM(finalResults);
1322
+ averageTimePerQuestionSeconds,
1323
+ ...metadataPerformance
1324
+ };
1325
+ this.quizResultState = { ...this.quizResultState, ...finalResults };
1326
+ if (this.config.settings?.scorm) this._sendResultsToSCORM(finalResults);
1378
1327
  await this._sendResultsToWebhook(finalResults);
1379
- (_e = (_d = this.callbacks).onQuizFinish) == null ? void 0 : _e.call(_d, finalResults);
1328
+ this.callbacks.onQuizFinish?.(finalResults);
1380
1329
  return finalResults;
1381
1330
  }
1382
1331
  formatUserAnswerDetail(question, userAnswerRaw) {
1383
- var _a, _b, _c, _d, _e;
1384
1332
  if (userAnswerRaw === null) return null;
1385
1333
  switch (question.questionType) {
1386
1334
  case "multiple_choice": {
1387
1335
  const q = question;
1388
1336
  const id = userAnswerRaw;
1389
- return { id, value: ((_a = q.options.find((opt) => opt.id === id)) == null ? void 0 : _a.text) || "" };
1337
+ return { id, value: q.options.find((opt) => opt.id === id)?.text || "" };
1390
1338
  }
1391
1339
  case "multiple_response": {
1392
1340
  const q = question;
1393
1341
  const ids = userAnswerRaw;
1394
- const values = ids.map((id) => {
1395
- var _a2;
1396
- return ((_a2 = q.options.find((opt) => opt.id === id)) == null ? void 0 : _a2.text) || "";
1397
- });
1342
+ const values = ids.map((id) => q.options.find((opt) => opt.id === id)?.text || "");
1398
1343
  return { id: ids, value: values };
1399
1344
  }
1400
1345
  case "sequence": {
1401
1346
  const q = question;
1402
1347
  const ids = userAnswerRaw;
1403
- const values = ids.map((id) => {
1404
- var _a2;
1405
- return ((_a2 = q.items.find((item) => item.id === id)) == null ? void 0 : _a2.content) || "";
1406
- });
1348
+ const values = ids.map((id) => q.items.find((item) => item.id === id)?.content || "");
1407
1349
  return { id: ids, value: values };
1408
1350
  }
1409
1351
  case "matching": {
@@ -1412,8 +1354,8 @@ var QuizEngine = class {
1412
1354
  const valueMap = {};
1413
1355
  for (const promptId in userAnswerMap) {
1414
1356
  const optionId = userAnswerMap[promptId];
1415
- const promptText = ((_b = q.prompts.find((p) => p.id === promptId)) == null ? void 0 : _b.content) || "";
1416
- const optionText = ((_c = q.options.find((o) => o.id === optionId)) == null ? void 0 : _c.content) || "";
1357
+ const promptText = q.prompts.find((p) => p.id === promptId)?.content || "";
1358
+ const optionText = q.options.find((o) => o.id === optionId)?.content || "";
1417
1359
  valueMap[promptText] = optionText;
1418
1360
  }
1419
1361
  return { id: null, value: valueMap };
@@ -1425,8 +1367,8 @@ var QuizEngine = class {
1425
1367
  const enrichedUserAnswerMap = {};
1426
1368
  for (const draggableId in userAnswerMapByIds) {
1427
1369
  const dropZoneId = userAnswerMapByIds[draggableId];
1428
- const draggableText = ((_d = q.draggableItems.find((d) => d.id === draggableId)) == null ? void 0 : _d.content) || `(ID: ${draggableId})`;
1429
- const dropZoneText = ((_e = q.dropZones.find((z4) => z4.id === dropZoneId)) == null ? void 0 : _e.label) || `(ID: ${dropZoneId})`;
1370
+ const draggableText = q.draggableItems.find((d) => d.id === draggableId)?.content || `(ID: ${draggableId})`;
1371
+ const dropZoneText = q.dropZones.find((z4) => z4.id === dropZoneId)?.label || `(ID: ${dropZoneId})`;
1430
1372
  enrichedUserAnswerMap[draggableText] = dropZoneText;
1431
1373
  }
1432
1374
  return { id: null, value: enrichedUserAnswerMap };
@@ -1438,7 +1380,6 @@ var QuizEngine = class {
1438
1380
  }
1439
1381
  }
1440
1382
  async _calculateMetadataPerformance() {
1441
- var _a;
1442
1383
  const loPerformanceMap = /* @__PURE__ */ new Map();
1443
1384
  const categoryPerformanceMap = /* @__PURE__ */ new Map();
1444
1385
  const topicPerformanceMap = /* @__PURE__ */ new Map();
@@ -1460,7 +1401,7 @@ var QuizEngine = class {
1460
1401
  const evaluator = this.evaluators.get(q.questionType);
1461
1402
  if (evaluator) {
1462
1403
  const { isCorrect } = await evaluator.evaluate(q, userAnswer);
1463
- const pointsForThisQuestion = (_a = q.points) != null ? _a : 0;
1404
+ const pointsForThisQuestion = q.points ?? 0;
1464
1405
  updateMap(loPerformanceMap, q.learningObjective, pointsForThisQuestion, isCorrect);
1465
1406
  updateMap(categoryPerformanceMap, q.category, pointsForThisQuestion, isCorrect);
1466
1407
  updateMap(topicPerformanceMap, q.topic, pointsForThisQuestion, isCorrect);
@@ -1487,8 +1428,7 @@ var QuizEngine = class {
1487
1428
  };
1488
1429
  }
1489
1430
  async _sendResultsToWebhook(results) {
1490
- var _a;
1491
- if (!((_a = this.config.settings) == null ? void 0 : _a.webhookUrl)) {
1431
+ if (!this.config.settings?.webhookUrl) {
1492
1432
  results.webhookStatus = "idle";
1493
1433
  return;
1494
1434
  }
@@ -1516,12 +1456,11 @@ var QuizEngine = class {
1516
1456
  }
1517
1457
  }
1518
1458
  _sendResultsToSCORM(results) {
1519
- var _a, _b, _c, _d, _e, _f, _g;
1520
1459
  if (!this.scormService || !this.scormService.hasAPI() || this.quizResultState.scormStatus === "no_api") {
1521
1460
  results.scormStatus = this.quizResultState.scormStatus || "idle";
1522
1461
  return;
1523
1462
  }
1524
- if (this.quizResultState.scormStatus === "error" && ((_a = this.quizResultState.scormError) == null ? void 0 : _a.includes("initialization failed"))) {
1463
+ if (this.quizResultState.scormStatus === "error" && this.quizResultState.scormError?.includes("initialization failed")) {
1525
1464
  results.scormStatus = "error";
1526
1465
  results.scormError = this.quizResultState.scormError;
1527
1466
  return;
@@ -1530,15 +1469,15 @@ var QuizEngine = class {
1530
1469
  try {
1531
1470
  this.scormService.setScore(results.score, results.maxScore, 0);
1532
1471
  let lessonStatusSetting = "completed";
1533
- if (((_b = this.config.settings) == null ? void 0 : _b.passingScorePercent) !== void 0 && ((_c = this.config.settings) == null ? void 0 : _c.passingScorePercent) !== null) {
1472
+ if (this.config.settings?.passingScorePercent !== void 0 && this.config.settings?.passingScorePercent !== null) {
1534
1473
  lessonStatusSetting = results.passed ? "passed" : "failed";
1535
- } else if ((_e = (_d = this.config.settings) == null ? void 0 : _d.scorm) == null ? void 0 : _e.setCompletionOnFinish) {
1474
+ } else if (this.config.settings?.scorm?.setCompletionOnFinish) {
1536
1475
  lessonStatusSetting = "completed";
1537
1476
  }
1538
1477
  this.scormService.setLessonStatus(lessonStatusSetting, results.passed);
1539
1478
  if (results.totalTimeSpentSeconds !== void 0 && this.scormService.formatCMITime) {
1540
1479
  const cmiTime = this.scormService.formatCMITime(results.totalTimeSpentSeconds);
1541
- const sessionTimeVar = ((_g = (_f = this.config.settings) == null ? void 0 : _f.scorm) == null ? void 0 : _g.sessionTimeVar) || (this.scormService.getSCORMVersion() === "2004" ? "cmi.session_time" : "cmi.core.session_time");
1480
+ const sessionTimeVar = this.config.settings?.scorm?.sessionTimeVar || (this.scormService.getSCORMVersion() === "2004" ? "cmi.session_time" : "cmi.core.session_time");
1542
1481
  if (sessionTimeVar) this.scormService.setValue(sessionTimeVar, cmiTime);
1543
1482
  }
1544
1483
  const commitResult = this.scormService.commit();
@@ -1578,18 +1517,19 @@ var QuizEditorService = class {
1578
1517
  };
1579
1518
  switch (type) {
1580
1519
  case "true_false":
1581
- return __spreadProps(__spreadValues({}, baseNewQuestion), { questionType: "true_false", correctAnswer: true });
1520
+ return { ...baseNewQuestion, questionType: "true_false", correctAnswer: true };
1582
1521
  case "multiple_choice":
1583
- return __spreadProps(__spreadValues({}, baseNewQuestion), { questionType: "multiple_choice", options: [], correctAnswerId: "" });
1522
+ return { ...baseNewQuestion, questionType: "multiple_choice", options: [], correctAnswerId: "" };
1584
1523
  case "multiple_response":
1585
- return __spreadProps(__spreadValues({}, baseNewQuestion), { questionType: "multiple_response", options: [], correctAnswerIds: [] });
1524
+ return { ...baseNewQuestion, questionType: "multiple_response", options: [], correctAnswerIds: [] };
1586
1525
  case "short_answer":
1587
- return __spreadProps(__spreadValues({}, baseNewQuestion), { questionType: "short_answer", acceptedAnswers: [""], isCaseSensitive: false });
1526
+ return { ...baseNewQuestion, questionType: "short_answer", acceptedAnswers: [""], isCaseSensitive: false };
1588
1527
  case "numeric":
1589
- return __spreadProps(__spreadValues({}, baseNewQuestion), { questionType: "numeric", answer: 0 });
1528
+ return { ...baseNewQuestion, questionType: "numeric", answer: 0 };
1590
1529
  case "fill_in_the_blanks": {
1591
1530
  const blankId = generateUniqueId("blank_");
1592
- return __spreadProps(__spreadValues({}, baseNewQuestion), {
1531
+ return {
1532
+ ...baseNewQuestion,
1593
1533
  questionType: "fill_in_the_blanks",
1594
1534
  segments: [
1595
1535
  { type: "text", content: "Your text before " },
@@ -1598,49 +1538,52 @@ var QuizEditorService = class {
1598
1538
  ],
1599
1539
  answers: [{ blankId, acceptedValues: [""] }],
1600
1540
  isCaseSensitive: false
1601
- });
1541
+ };
1602
1542
  }
1603
1543
  case "sequence":
1604
- return __spreadProps(__spreadValues({}, baseNewQuestion), { questionType: "sequence", items: [], correctOrder: [] });
1544
+ return { ...baseNewQuestion, questionType: "sequence", items: [], correctOrder: [] };
1605
1545
  case "matching":
1606
- return __spreadProps(__spreadValues({}, baseNewQuestion), { questionType: "matching", prompts: [], options: [], correctAnswerMap: [], shuffleOptions: true });
1546
+ return { ...baseNewQuestion, questionType: "matching", prompts: [], options: [], correctAnswerMap: [], shuffleOptions: true };
1607
1547
  case "drag_and_drop":
1608
- return __spreadProps(__spreadValues({}, baseNewQuestion), { questionType: "drag_and_drop", draggableItems: [], dropZones: [], answerMap: [] });
1548
+ return { ...baseNewQuestion, questionType: "drag_and_drop", draggableItems: [], dropZones: [], answerMap: [] };
1609
1549
  case "hotspot":
1610
- return __spreadProps(__spreadValues({}, baseNewQuestion), { questionType: "hotspot", imageUrl: "", hotspots: [], correctHotspotIds: [] });
1550
+ return { ...baseNewQuestion, questionType: "hotspot", imageUrl: "", hotspots: [], correctHotspotIds: [] };
1611
1551
  case "blockly_programming":
1612
- return __spreadProps(__spreadValues({}, baseNewQuestion), {
1552
+ return {
1553
+ ...baseNewQuestion,
1613
1554
  questionType: "blockly_programming",
1614
1555
  toolboxDefinition: '<xml xmlns="https://developers.google.com/blockly/xml"></xml>',
1615
1556
  initialWorkspace: "",
1616
1557
  solutionWorkspaceXML: "",
1617
1558
  solutionGeneratedCode: ""
1618
- });
1559
+ };
1619
1560
  case "scratch_programming":
1620
- return __spreadProps(__spreadValues({}, baseNewQuestion), {
1561
+ return {
1562
+ ...baseNewQuestion,
1621
1563
  questionType: "scratch_programming",
1622
1564
  toolboxDefinition: '<xml xmlns="https://developers.google.com/blockly/xml"></xml>',
1623
1565
  initialWorkspace: "",
1624
1566
  solutionWorkspaceXML: "",
1625
1567
  solutionGeneratedCode: ""
1626
- });
1568
+ };
1627
1569
  case "coding":
1628
- return __spreadProps(__spreadValues({}, baseNewQuestion), {
1570
+ return {
1571
+ ...baseNewQuestion,
1629
1572
  questionType: "coding",
1630
- language: "javascript",
1573
+ codingLanguage: "javascript",
1631
1574
  solutionCode: "",
1632
1575
  testCases: [],
1633
1576
  functionSignature: "",
1634
1577
  points: 25
1635
1578
  // Coding questions are worth more by default
1636
- });
1579
+ };
1637
1580
  default:
1638
1581
  const _exhaustiveCheck = type;
1639
1582
  throw new Error(`Question type "${_exhaustiveCheck}" is not supported for creation.`);
1640
1583
  }
1641
1584
  }
1642
1585
  addQuestion(question) {
1643
- const newQuestion = __spreadValues({}, question);
1586
+ const newQuestion = { ...question };
1644
1587
  if (newQuestion.id.startsWith("new_")) {
1645
1588
  newQuestion.id = generateUniqueId(`${newQuestion.questionType}_`);
1646
1589
  }
@@ -1754,8 +1697,7 @@ var QuestionImportService = class {
1754
1697
  const values = line.split(" ");
1755
1698
  const rowObject = {};
1756
1699
  header.forEach((h, i) => {
1757
- var _a;
1758
- rowObject[h] = ((_a = values[i]) == null ? void 0 : _a.trim()) || "";
1700
+ rowObject[h] = values[i]?.trim() || "";
1759
1701
  });
1760
1702
  try {
1761
1703
  const transformedObject = this.transformTsvRowToRawObject(rowObject);
@@ -1797,17 +1739,17 @@ var QuestionImportService = class {
1797
1739
  };
1798
1740
  switch (questionType) {
1799
1741
  case "multiple_choice":
1800
- return __spreadProps(__spreadValues({}, base), { options: options.split("|"), correctAnswer });
1742
+ return { ...base, options: options.split("|"), correctAnswer };
1801
1743
  case "multiple_response":
1802
- return __spreadProps(__spreadValues({}, base), { options: options.split("|"), correctAnswers: correctAnswer.split("|") });
1744
+ return { ...base, options: options.split("|"), correctAnswers: correctAnswer.split("|") };
1803
1745
  case "true_false":
1804
- return __spreadProps(__spreadValues({}, base), { correctAnswer: correctAnswer.toLowerCase() === "true" });
1746
+ return { ...base, correctAnswer: correctAnswer.toLowerCase() === "true" };
1805
1747
  case "short_answer":
1806
- return __spreadProps(__spreadValues({}, base), { acceptedAnswers: correctAnswer.split("|") });
1748
+ return { ...base, acceptedAnswers: correctAnswer.split("|") };
1807
1749
  case "numeric":
1808
- return __spreadProps(__spreadValues({}, base), { answer: parseFloat(correctAnswer), tolerance: tolerance ? parseFloat(tolerance) : void 0 });
1750
+ return { ...base, answer: parseFloat(correctAnswer), tolerance: tolerance ? parseFloat(tolerance) : void 0 };
1809
1751
  case "sequence":
1810
- return __spreadProps(__spreadValues({}, base), { items: options.split("|"), correctOrder: correctAnswer.split("|") });
1752
+ return { ...base, items: options.split("|"), correctOrder: correctAnswer.split("|") };
1811
1753
  case "matching": {
1812
1754
  const [promptsStr, optionsStr] = options.split("#");
1813
1755
  const prompts = promptsStr.replace("prompts:", "").split("|");
@@ -1817,7 +1759,7 @@ var QuestionImportService = class {
1817
1759
  acc[key] = valParts.join(":");
1818
1760
  return acc;
1819
1761
  }, {});
1820
- return __spreadProps(__spreadValues({}, base), { prompts, options: opts, correctAnswerMap });
1762
+ return { ...base, prompts, options: opts, correctAnswerMap };
1821
1763
  }
1822
1764
  case "fill_in_the_blanks": {
1823
1765
  const blanks = correctAnswer.split("#").reduce((acc, part) => {
@@ -1825,7 +1767,7 @@ var QuestionImportService = class {
1825
1767
  acc[key] = valuesStr.split("|");
1826
1768
  return acc;
1827
1769
  }, {});
1828
- return __spreadProps(__spreadValues({}, base), { sentenceWithPlaceholders: options, blanks });
1770
+ return { ...base, sentenceWithPlaceholders: options, blanks };
1829
1771
  }
1830
1772
  default:
1831
1773
  throw new Error(`Unsupported questionType "${questionType}" in TSV.`);
@@ -1846,20 +1788,20 @@ var QuestionImportService = class {
1846
1788
  const options = validatedRawQ.options.map((text) => ({ id: generateUniqueId("opt_"), text }));
1847
1789
  const correctOption = options.find((opt) => opt.text === validatedRawQ.correctAnswer);
1848
1790
  if (!correctOption) throw new Error(`Correct answer "${validatedRawQ.correctAnswer}" not found in options.`);
1849
- return __spreadProps(__spreadValues({}, baseQuestionData), { questionType: "multiple_choice", options, correctAnswerId: correctOption.id });
1791
+ return { ...baseQuestionData, questionType: "multiple_choice", options, correctAnswerId: correctOption.id };
1850
1792
  }
1851
1793
  case "multiple_response": {
1852
1794
  const options = validatedRawQ.options.map((text) => ({ id: generateUniqueId("opt_mr_"), text }));
1853
1795
  const correctIds = options.filter((opt) => validatedRawQ.correctAnswers.includes(opt.text)).map((opt) => opt.id);
1854
1796
  if (correctIds.length !== validatedRawQ.correctAnswers.length) throw new Error("Some correct answers were not found in options.");
1855
- return __spreadProps(__spreadValues({}, baseQuestionData), { questionType: "multiple_response", options, correctAnswerIds: correctIds });
1797
+ return { ...baseQuestionData, questionType: "multiple_response", options, correctAnswerIds: correctIds };
1856
1798
  }
1857
1799
  case "true_false":
1858
- return __spreadProps(__spreadValues({}, baseQuestionData), { questionType: "true_false", correctAnswer: validatedRawQ.correctAnswer });
1800
+ return { ...baseQuestionData, questionType: "true_false", correctAnswer: validatedRawQ.correctAnswer };
1859
1801
  case "short_answer":
1860
- return __spreadProps(__spreadValues({}, baseQuestionData), { questionType: "short_answer", acceptedAnswers: validatedRawQ.acceptedAnswers, isCaseSensitive: false });
1802
+ return { ...baseQuestionData, questionType: "short_answer", acceptedAnswers: validatedRawQ.acceptedAnswers, isCaseSensitive: false };
1861
1803
  case "numeric":
1862
- return __spreadProps(__spreadValues({}, baseQuestionData), { questionType: "numeric", answer: validatedRawQ.answer, tolerance: validatedRawQ.tolerance });
1804
+ return { ...baseQuestionData, questionType: "numeric", answer: validatedRawQ.answer, tolerance: validatedRawQ.tolerance };
1863
1805
  case "sequence": {
1864
1806
  if (validatedRawQ.items.length !== validatedRawQ.correctOrder.length) {
1865
1807
  throw new Error("The number of items must match the number of items in the correct order for a sequence question.");
@@ -1870,7 +1812,7 @@ var QuestionImportService = class {
1870
1812
  if (!foundItem) throw new Error(`Sequence item "${orderText}" in correctOrder not found in items list.`);
1871
1813
  return foundItem.id;
1872
1814
  });
1873
- return __spreadProps(__spreadValues({}, baseQuestionData), { questionType: "sequence", items, correctOrder });
1815
+ return { ...baseQuestionData, questionType: "sequence", items, correctOrder };
1874
1816
  }
1875
1817
  case "matching": {
1876
1818
  if (validatedRawQ.prompts.length !== Object.keys(validatedRawQ.correctAnswerMap).length) {
@@ -1884,7 +1826,7 @@ var QuestionImportService = class {
1884
1826
  if (!prompt || !option) throw new Error(`Matching pair "${promptText}":"${optionText}" not found in prompts/options.`);
1885
1827
  return { promptId: prompt.id, optionId: option.id };
1886
1828
  });
1887
- return __spreadProps(__spreadValues({}, baseQuestionData), { questionType: "matching", prompts, options, correctAnswerMap, shuffleOptions: true });
1829
+ return { ...baseQuestionData, questionType: "matching", prompts, options, correctAnswerMap, shuffleOptions: true };
1888
1830
  }
1889
1831
  case "fill_in_the_blanks": {
1890
1832
  const { sentenceWithPlaceholders, blanks } = validatedRawQ;
@@ -1912,7 +1854,7 @@ var QuestionImportService = class {
1912
1854
  if (lastIndex < sentenceWithPlaceholders.length) {
1913
1855
  segments.push({ type: "text", content: sentenceWithPlaceholders.substring(lastIndex) });
1914
1856
  }
1915
- return __spreadProps(__spreadValues({}, baseQuestionData), { questionType: "fill_in_the_blanks", segments, answers, isCaseSensitive: false });
1857
+ return { ...baseQuestionData, questionType: "fill_in_the_blanks", segments, answers, isCaseSensitive: false };
1916
1858
  }
1917
1859
  }
1918
1860
  throw new Error(`Unhandled question type in createQuestionFromRawObject: ${validatedRawQ.questionType}`);
@@ -1973,8 +1915,7 @@ var UserConfigService = class {
1973
1915
  this.setConfig("weeklyGoal", goal);
1974
1916
  }
1975
1917
  static getLanguage() {
1976
- var _a;
1977
- return (_a = this.getConfig("language", "en")) != null ? _a : "en";
1918
+ return this.getConfig("language", "en") ?? "en";
1978
1919
  }
1979
1920
  static setLanguage(language) {
1980
1921
  this.setConfig("language", language);
@@ -1992,10 +1933,11 @@ var UserConfigService = class {
1992
1933
  */
1993
1934
  static addGoal(newGoal) {
1994
1935
  const goals = this.getGoals();
1995
- const goalToAdd = __spreadProps(__spreadValues({}, newGoal), {
1936
+ const goalToAdd = {
1937
+ ...newGoal,
1996
1938
  id: generateUniqueId("goal_"),
1997
1939
  isAchieved: false
1998
- });
1940
+ };
1999
1941
  this.saveGoals([...goals, goalToAdd]);
2000
1942
  }
2001
1943
  static updateGoal(updatedGoal) {
@@ -2628,6 +2570,263 @@ var KnowledgeCardService = class {
2628
2570
  }
2629
2571
  };
2630
2572
 
2573
+ // src/services/metadataService.ts
2574
+ var LocalStorageManager = class {
2575
+ constructor(key) {
2576
+ this.key = `iqk_metadata_${key}`;
2577
+ }
2578
+ getAll() {
2579
+ if (typeof window === "undefined") return [];
2580
+ try {
2581
+ const stored = localStorage.getItem(this.key);
2582
+ return stored ? JSON.parse(stored) : [];
2583
+ } catch (e) {
2584
+ console.error(`Error reading from localStorage key ${this.key}:`, e);
2585
+ return [];
2586
+ }
2587
+ }
2588
+ saveAll(items) {
2589
+ if (typeof window === "undefined") return;
2590
+ try {
2591
+ localStorage.setItem(this.key, JSON.stringify(items));
2592
+ } catch (e) {
2593
+ console.error(`Error writing to localStorage key ${this.key}:`, e);
2594
+ }
2595
+ }
2596
+ add(item) {
2597
+ const items = this.getAll();
2598
+ if (items.some((i) => i.code === item.code)) {
2599
+ throw new Error(`An item with code "${item.code}" already exists for ${this.key}.`);
2600
+ }
2601
+ const newItem = { ...item, id: generateUniqueId(`${this.key}_`) };
2602
+ this.saveAll([...items, newItem]);
2603
+ return newItem;
2604
+ }
2605
+ // ===== FIX IS HERE =====
2606
+ // Changed the type of 'updates' to allow 'code' to be part of the update object.
2607
+ update(id, updates) {
2608
+ const items = this.getAll();
2609
+ const index = items.findIndex((i) => i.id === id);
2610
+ if (index === -1) {
2611
+ console.warn(`Item with id "${id}" not found in ${this.key} for update.`);
2612
+ return null;
2613
+ }
2614
+ const updatedItem = { ...items[index], ...updates };
2615
+ items[index] = updatedItem;
2616
+ this.saveAll(items);
2617
+ return updatedItem;
2618
+ }
2619
+ // =======================
2620
+ delete(code) {
2621
+ const items = this.getAll();
2622
+ const newItems = items.filter((i) => i.code !== code);
2623
+ if (items.length === newItems.length) {
2624
+ return false;
2625
+ }
2626
+ this.saveAll(newItems);
2627
+ return true;
2628
+ }
2629
+ };
2630
+ var subjectManager = new LocalStorageManager("subjects");
2631
+ var gradeLevelManager = new LocalStorageManager("grade_levels");
2632
+ var topicManager = new LocalStorageManager("topics");
2633
+ var categoryManager = new LocalStorageManager("categories");
2634
+ var bloomLevelManager = new LocalStorageManager("bloom_levels");
2635
+ var questionTypeManager = new LocalStorageManager("question_types");
2636
+ var learningObjectiveManager = new LocalStorageManager("learning_objectives");
2637
+ var contextManager = new LocalStorageManager("contexts");
2638
+ var approachManager = new LocalStorageManager("approaches");
2639
+ function mapRawDifficultyToStandard(rawDifficulty) {
2640
+ switch (rawDifficulty) {
2641
+ case "E":
2642
+ case "E~M":
2643
+ return "easy";
2644
+ case "M":
2645
+ case "M~H":
2646
+ return "medium";
2647
+ case "H":
2648
+ return "hard";
2649
+ default:
2650
+ return "medium";
2651
+ }
2652
+ }
2653
+ var _MetadataService = class _MetadataService {
2654
+ };
2655
+ // --- Subject Services ---
2656
+ _MetadataService.getSubjects = () => subjectManager.getAll().sort((a, b) => a.name.localeCompare(b.name));
2657
+ _MetadataService.addSubject = (name, code) => {
2658
+ return subjectManager.add({ code, name, createdAt: (/* @__PURE__ */ new Date()).toISOString(), updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
2659
+ };
2660
+ _MetadataService.updateSubject = (id, name, code) => {
2661
+ return subjectManager.update(id, { name, code, updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
2662
+ };
2663
+ _MetadataService.deleteSubject = (code) => {
2664
+ const topics = _MetadataService.getTopics(code);
2665
+ if (topics.length > 0) {
2666
+ throw new Error("Cannot delete subject: It is referenced by topics.");
2667
+ }
2668
+ return subjectManager.delete(code);
2669
+ };
2670
+ // --- GradeLevel Services ---
2671
+ _MetadataService.getGradeLevels = () => gradeLevelManager.getAll().sort((a, b) => a.name.localeCompare(b.name));
2672
+ _MetadataService.addGradeLevel = (name, code) => gradeLevelManager.add({ name, code });
2673
+ _MetadataService.updateGradeLevel = (id, name, code) => gradeLevelManager.update(id, { name, code });
2674
+ _MetadataService.deleteGradeLevel = (code) => gradeLevelManager.delete(code);
2675
+ // --- Topic Services ---
2676
+ _MetadataService.getTopics = (subjectCode) => {
2677
+ const allTopics = topicManager.getAll();
2678
+ const filtered = subjectCode ? allTopics.filter((t) => t.subjectCode === subjectCode) : allTopics;
2679
+ return filtered.sort((a, b) => a.name.localeCompare(b.name));
2680
+ };
2681
+ _MetadataService.addTopic = (name, code, subjectCode) => topicManager.add({ name, code, subjectCode });
2682
+ _MetadataService.updateTopic = (id, name, code, subjectCode) => topicManager.update(id, { name, code, subjectCode });
2683
+ _MetadataService.deleteTopic = (code) => topicManager.delete(code);
2684
+ // --- BloomLevel Services ---
2685
+ _MetadataService.getBloomLevels = () => bloomLevelManager.getAll().sort((a, b) => a.name.localeCompare(b.name));
2686
+ _MetadataService.addBloomLevel = (name, code, description) => bloomLevelManager.add({ name, code, description });
2687
+ _MetadataService.updateBloomLevel = (id, name, code, description) => bloomLevelManager.update(id, { name, code, description });
2688
+ _MetadataService.deleteBloomLevel = (code) => bloomLevelManager.delete(code);
2689
+ // --- QuestionType Services ---
2690
+ _MetadataService.getQuestionTypes = () => questionTypeManager.getAll().sort((a, b) => a.name.localeCompare(b.name));
2691
+ _MetadataService.addQuestionType = (name, code, description) => questionTypeManager.add({ name, code, description });
2692
+ _MetadataService.updateQuestionType = (id, name, code, description) => questionTypeManager.update(id, { name, code, description });
2693
+ _MetadataService.deleteQuestionType = (code) => questionTypeManager.delete(code);
2694
+ // --- Category Services ---
2695
+ _MetadataService.getCategories = () => categoryManager.getAll().sort((a, b) => a.name.localeCompare(b.name));
2696
+ _MetadataService.addCategory = (name, code, description) => categoryManager.add({ name, code, description });
2697
+ _MetadataService.updateCategory = (id, name, code, description) => categoryManager.update(id, { name, code, description });
2698
+ _MetadataService.deleteCategory = (code) => categoryManager.delete(code);
2699
+ // --- Context Services ---
2700
+ _MetadataService.getContexts = () => contextManager.getAll().sort((a, b) => a.name.localeCompare(b.name));
2701
+ _MetadataService.addContext = (name, code, description) => contextManager.add({ name, code, description });
2702
+ _MetadataService.updateContext = (id, name, code, description) => contextManager.update(id, { name, code, description });
2703
+ _MetadataService.deleteContext = (code) => contextManager.delete(code);
2704
+ // --- Approach Services ---
2705
+ _MetadataService.getApproaches = () => approachManager.getAll().sort((a, b) => a.code.localeCompare(b.code));
2706
+ _MetadataService.addApproach = (approachData) => {
2707
+ const difficulty = mapRawDifficultyToStandard(approachData.rawDifficulty);
2708
+ return approachManager.add({ ...approachData, difficulty });
2709
+ };
2710
+ _MetadataService.updateApproach = (id, approachData) => {
2711
+ const updates = { ...approachData };
2712
+ if (approachData.rawDifficulty) {
2713
+ updates.difficulty = mapRawDifficultyToStandard(approachData.rawDifficulty);
2714
+ }
2715
+ return approachManager.update(id, updates);
2716
+ };
2717
+ _MetadataService.deleteApproach = (code) => approachManager.delete(code);
2718
+ // --- LearningObjective Services ---
2719
+ _MetadataService.getLearningObjectives = (subjectCode) => {
2720
+ const allLOs = learningObjectiveManager.getAll();
2721
+ const filtered = subjectCode ? allLOs.filter((lo) => lo.subjectCode === subjectCode) : allLOs;
2722
+ return filtered.sort((a, b) => a.name.localeCompare(b.name));
2723
+ };
2724
+ _MetadataService.addLearningObjective = (name, code, subjectCode, description) => learningObjectiveManager.add({ name, code, subjectCode, description });
2725
+ _MetadataService.updateLearningObjective = (id, name, code, subjectCode, description) => learningObjectiveManager.update(id, { name, code, subjectCode, description });
2726
+ _MetadataService.deleteLearningObjective = (code) => learningObjectiveManager.delete(code);
2727
+ var MetadataService = _MetadataService;
2728
+
2729
+ // src/services/questionBankService.ts
2730
+ var LocalStorageManager2 = class {
2731
+ constructor(key) {
2732
+ this.key = key;
2733
+ }
2734
+ getAll() {
2735
+ if (typeof window === "undefined") return [];
2736
+ try {
2737
+ const stored = localStorage.getItem(this.key);
2738
+ return stored ? JSON.parse(stored) : [];
2739
+ } catch (e) {
2740
+ console.error(`Error reading from localStorage key ${this.key}:`, e);
2741
+ return [];
2742
+ }
2743
+ }
2744
+ saveAll(items) {
2745
+ if (typeof window === "undefined") return;
2746
+ try {
2747
+ localStorage.setItem(this.key, JSON.stringify(items));
2748
+ } catch (e) {
2749
+ console.error(`Error writing to localStorage key ${this.key}:`, e);
2750
+ }
2751
+ }
2752
+ };
2753
+ var questionBankManager = new LocalStorageManager2("iqk_question_bank");
2754
+ var QuestionBankService = class {
2755
+ static getQuestions(filters) {
2756
+ let questions = questionBankManager.getAll();
2757
+ if (filters) {
2758
+ if (filters.subjectCode) {
2759
+ questions = questions.filter((q) => q.subjectCode === filters.subjectCode);
2760
+ }
2761
+ if (filters.topicCode) {
2762
+ questions = questions.filter((q) => q.topicCode === filters.topicCode);
2763
+ }
2764
+ if (filters.gradeLevelCode) {
2765
+ questions = questions.filter((q) => q.gradeLevelCode === filters.gradeLevelCode);
2766
+ }
2767
+ if (filters.bloomLevelCode) {
2768
+ questions = questions.filter((q) => q.bloomLevelCode === filters.bloomLevelCode);
2769
+ }
2770
+ if (filters.questionTypeCode) {
2771
+ questions = questions.filter((q) => q.questionTypeCode === filters.questionTypeCode);
2772
+ }
2773
+ if (filters.difficulty) {
2774
+ questions = questions.filter((q) => q.difficulty === filters.difficulty);
2775
+ }
2776
+ if (filters.searchTerm) {
2777
+ const lowercasedTerm = filters.searchTerm.toLowerCase();
2778
+ questions = questions.filter(
2779
+ (q) => q.text.toLowerCase().includes(lowercasedTerm) || q.code.toLowerCase().includes(lowercasedTerm)
2780
+ );
2781
+ }
2782
+ }
2783
+ return questions.sort((a, b) => new Date(b.lastModified).getTime() - new Date(a.lastModified).getTime());
2784
+ }
2785
+ static getQuestionByCode(code) {
2786
+ return questionBankManager.getAll().find((q) => q.code === code);
2787
+ }
2788
+ // CHANGE 2: Simplified function signature. It now takes the full object to be added.
2789
+ static addQuestion(questionData) {
2790
+ const allQuestions = questionBankManager.getAll();
2791
+ if (allQuestions.some((q) => q.code === questionData.code)) {
2792
+ throw new Error(`A question with code "${questionData.code}" already exists.`);
2793
+ }
2794
+ const newQuestion = {
2795
+ ...questionData,
2796
+ id: generateUniqueId("qb_"),
2797
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
2798
+ };
2799
+ questionBankManager.saveAll([...allQuestions, newQuestion]);
2800
+ return newQuestion;
2801
+ }
2802
+ // CHANGE 2: Simplified function signature.
2803
+ static updateQuestion(id, updates) {
2804
+ const allQuestions = questionBankManager.getAll();
2805
+ const index = allQuestions.findIndex((q) => q.id === id);
2806
+ if (index === -1) {
2807
+ console.warn(`Question with id "${id}" not found for update.`);
2808
+ return null;
2809
+ }
2810
+ const updatedQuestion = {
2811
+ ...allQuestions[index],
2812
+ ...updates,
2813
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
2814
+ };
2815
+ allQuestions[index] = updatedQuestion;
2816
+ questionBankManager.saveAll(allQuestions);
2817
+ return updatedQuestion;
2818
+ }
2819
+ static deleteQuestionByCode(code) {
2820
+ const allQuestions = questionBankManager.getAll();
2821
+ const newQuestions = allQuestions.filter((q) => q.code !== code);
2822
+ if (allQuestions.length === newQuestions.length) {
2823
+ return false;
2824
+ }
2825
+ questionBankManager.saveAll(newQuestions);
2826
+ return true;
2827
+ }
2828
+ };
2829
+
2631
2830
  // src/services/HTMLLauncherGenerator.ts
2632
2831
  var escapeAttribute = (unsafe) => {
2633
2832
  if (typeof unsafe !== "string") return "";
@@ -2760,13 +2959,12 @@ var escapeXML = (unsafe) => {
2760
2959
  });
2761
2960
  };
2762
2961
  var generateSCORMManifest = (quizConfig, scormVersion, launcherFile = "index.html", libraryJSPath = "scorm-bundle/player.js", quizDataPath = "quiz_data.json", blocklyCSSPath = "blockly-styles.css", mainCSSPath = "styles.css") => {
2763
- var _a;
2764
2962
  const uniqueId = `iqk_${quizConfig.id.replace(/[^a-zA-Z0-9_]/g, "_")}`;
2765
2963
  const organizationId = `ORG-${uniqueId}`;
2766
2964
  const itemId = `ITEM-${uniqueId}`;
2767
2965
  const resourceId = `RES-${uniqueId}`;
2768
2966
  const quizTitle = escapeXML(quizConfig.title);
2769
- const passingScore = (_a = quizConfig.settings) == null ? void 0 : _a.passingScorePercent;
2967
+ const passingScore = quizConfig.settings?.passingScorePercent;
2770
2968
  const effectiveScormVersion = scormVersion;
2771
2969
  const schemaVersion = effectiveScormVersion === "2004" ? "2004 4th Edition" : "1.2";
2772
2970
  const adlcpNamespace = effectiveScormVersion === "2004" ? "http://www.adlnet.org/xsd/adlcp_v1p3" : "http://www.adlnet.org/xsd/adlcp_rootv1p2";
@@ -3253,7 +3451,9 @@ exports.APIKeyService = APIKeyService;
3253
3451
  exports.AchievementService = AchievementService;
3254
3452
  exports.GEMINI_API_KEY_SERVICE_NAME = GEMINI_API_KEY_SERVICE_NAME;
3255
3453
  exports.KnowledgeCardService = KnowledgeCardService;
3454
+ exports.MetadataService = MetadataService;
3256
3455
  exports.PracticeHistoryService = PracticeHistoryService;
3456
+ exports.QuestionBankService = QuestionBankService;
3257
3457
  exports.QuestionImportService = QuestionImportService;
3258
3458
  exports.QuizEditorService = QuizEditorService;
3259
3459
  exports.QuizEngine = QuizEngine;