@examind/block-sdk 0.1.27 → 0.1.29

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.
Files changed (3) hide show
  1. package/dist/index.js +165 -123
  2. package/dist/index.mjs +160 -118
  3. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -317,9 +317,9 @@ var NodeHandlerChainBuilder = class {
317
317
  }
318
318
  };
319
319
 
320
- // src/typeGuards/isSerializedEssayQuestionNode.ts
321
- function isSerializedEssayQuestionNode(node) {
322
- return node?.type === "essay-question" && "id" in node && typeof node.id === "string" && "points" in node && typeof node.points === "number" && "maxWords" in node && typeof node.maxWords === "number" && "hideChat" in node && typeof node.hideChat === "boolean";
320
+ // src/typeGuards/isSerializedCustomQuestionNode.ts
321
+ function isSerializedCustomQuestionNode(node) {
322
+ return node?.type === "custom-question" && "id" in node && typeof node.id === "string" && "points" in node && typeof node.points === "number" && "name" in node && typeof node.name === "string" && "data" in node && typeof node.data === "string";
323
323
  }
324
324
 
325
325
  // src/exportToHtml/types.ts
@@ -342,6 +342,19 @@ var NodeHandler = class {
342
342
  }
343
343
  };
344
344
 
345
+ // src/exportToHtml/CustomQuestionNodeHandler.ts
346
+ var CustomQuestionNodeHandler = class extends NodeHandler {
347
+ processNode(node) {
348
+ if (!isSerializedCustomQuestionNode(node)) return null;
349
+ return `<x-custom id="${node.id}" data-x-prompt data-x-points="${node.points}" data-x-name="${node.name}"></x-custom>`;
350
+ }
351
+ };
352
+
353
+ // src/typeGuards/isSerializedEssayQuestionNode.ts
354
+ function isSerializedEssayQuestionNode(node) {
355
+ return node?.type === "essay-question" && "id" in node && typeof node.id === "string" && "points" in node && typeof node.points === "number" && "maxWords" in node && typeof node.maxWords === "number" && "hideChat" in node && typeof node.hideChat === "boolean";
356
+ }
357
+
345
358
  // src/exportToHtml/EssayQuestionNodeHandler.ts
346
359
  var EssayQuestionNodeHandler = class extends NodeHandler {
347
360
  processNode(node) {
@@ -405,6 +418,11 @@ function isSerializedFillInTheBlankSpaceNode(node) {
405
418
  return node?.type === "space" && "id" in node && typeof node.id === "string" && "spaceName" in node && typeof node.spaceName === "string" && "matches" in node && typeof node.matches === "string" && "spaceType" in node;
406
419
  }
407
420
 
421
+ // src/exportToHtml/serializeErrorToleranceAttribute.ts
422
+ function serializeErrorToleranceAttribute(errorTolerance) {
423
+ return (errorTolerance ?? 0) / 100;
424
+ }
425
+
408
426
  // src/exportToHtml/FillInTheBlankSpaceNodeHandler.ts
409
427
  var FillInTheBlankSpaceNodeHandler = class extends NodeHandler {
410
428
  processNode(node) {
@@ -422,7 +440,7 @@ var FillInTheBlankSpaceNodeHandler = class extends NodeHandler {
422
440
  `data-x-case-sensitive="${!!node.caseSensitive}"`,
423
441
  `data-x-errors-allowed="${node.errorsAllowed ?? 0}"`,
424
442
  `data-x-min-decimals="${node.minDecimals ?? ""}"`,
425
- `data-x-error-tolerance="${(node.errorTolerance ?? 0) / 100}"`,
443
+ `data-x-error-tolerance="${serializeErrorToleranceAttribute(node.errorTolerance)}"`,
426
444
  // Divide by 100 to convert percentage to rate
427
445
  `data-x-distractors="${node.distractors ?? ""}"`
428
446
  ];
@@ -631,7 +649,7 @@ var JournalEntryQuestionNodeHandler = class extends NodeHandler {
631
649
  ];
632
650
  if (journalNode.errorTolerance !== void 0) {
633
651
  attributes.push(
634
- `data-x-error-tolerance="${journalNode.errorTolerance}"`
652
+ `data-x-error-tolerance="${serializeErrorToleranceAttribute(journalNode.errorTolerance)}"`
635
653
  );
636
654
  }
637
655
  attributes.push(
@@ -1179,7 +1197,7 @@ var VariableNodeHandler = class extends NodeHandler {
1179
1197
 
1180
1198
  // src/exportToHtml/traverse.ts
1181
1199
  var builder = new NodeHandlerChainBuilder();
1182
- var nodeHandlerChain = builder.addHandler(EssayQuestionNodeHandler).addHandler(FillInTheBlankQuestionNodeHandler).addHandler(FillInTheBlankSpaceNodeHandler).addHandler(FinancialStatementQuestionNodeHandler).addHandler(HorizontalRuleNodeHandler).addHandler(ImageNodeHandler).addHandler(JournalEntryQuestionNodeHandler).addHandler(LineBreakNodeHandler).addHandler(LinkNodeHandler).addHandler(ListNodeHandler).addHandler(ListItemNodeHandler).addHandler(MatchingQuestionNodeHandler).addHandler(MultipleOptionQuestionNodeHandler).addHandler(ParagraphNodeHandler).addHandler(ShortAnswerQuestionNodeHandler).addHandler(SimulationQuestionNodeHandler).addHandler(TableCellNodeHandler).addHandler(TableNodeHandler).addHandler(TableRowNodeHandler).addHandler(TextNodeHandler).addHandler(VariableNodeHandler).build();
1200
+ var nodeHandlerChain = builder.addHandler(CustomQuestionNodeHandler).addHandler(EssayQuestionNodeHandler).addHandler(FillInTheBlankQuestionNodeHandler).addHandler(FillInTheBlankSpaceNodeHandler).addHandler(FinancialStatementQuestionNodeHandler).addHandler(HorizontalRuleNodeHandler).addHandler(ImageNodeHandler).addHandler(JournalEntryQuestionNodeHandler).addHandler(LineBreakNodeHandler).addHandler(LinkNodeHandler).addHandler(ListNodeHandler).addHandler(ListItemNodeHandler).addHandler(MatchingQuestionNodeHandler).addHandler(MultipleOptionQuestionNodeHandler).addHandler(ParagraphNodeHandler).addHandler(ShortAnswerQuestionNodeHandler).addHandler(SimulationQuestionNodeHandler).addHandler(TableCellNodeHandler).addHandler(TableNodeHandler).addHandler(TableRowNodeHandler).addHandler(TextNodeHandler).addHandler(VariableNodeHandler).build();
1183
1201
  var traverse = (node, metadata) => {
1184
1202
  return nodeHandlerChain.handle(node, metadata);
1185
1203
  };
@@ -1214,11 +1232,59 @@ function createEmptyParagraphNode(format = "") {
1214
1232
  };
1215
1233
  }
1216
1234
 
1235
+ // src/importFromHtml/CustomQuestionNodeHandler.ts
1236
+ import { HTMLElement } from "node-html-parser";
1237
+
1238
+ // src/importFromHtml/types.ts
1239
+ var NodeHandler2 = class {
1240
+ constructor() {
1241
+ this.nextHandler = null;
1242
+ }
1243
+ getChildNodesTextContent(childNodes) {
1244
+ return childNodes.reduce((acc, item) => {
1245
+ const text = item.textContent || "";
1246
+ return acc + text.trim() + " ";
1247
+ }, "").trimEnd();
1248
+ }
1249
+ setNext(handler) {
1250
+ this.nextHandler = handler;
1251
+ return handler;
1252
+ }
1253
+ handle(node) {
1254
+ const result = this.processNode(node);
1255
+ if (result) {
1256
+ return result;
1257
+ } else if (this.nextHandler) {
1258
+ return this.nextHandler.handle(node);
1259
+ }
1260
+ return null;
1261
+ }
1262
+ };
1263
+
1264
+ // src/importFromHtml/CustomQuestionNodeHandler.ts
1265
+ var TAG_X_CUSTOM = "x-custom";
1266
+ var CustomQuestionNodeHandler2 = class extends NodeHandler2 {
1267
+ processNode(node) {
1268
+ if (!(node instanceof HTMLElement) || node.tagName !== TAG_X_CUSTOM.toUpperCase()) {
1269
+ return null;
1270
+ }
1271
+ const jsonNode = {
1272
+ id: node.getAttribute("id") || "",
1273
+ points: Number(node.getAttribute("data-x-points") || 1),
1274
+ name: node.getAttribute("data-x-name") || "",
1275
+ data: "",
1276
+ type: "custom-question",
1277
+ version: 1
1278
+ };
1279
+ return jsonNode;
1280
+ }
1281
+ };
1282
+
1217
1283
  // src/importFromHtml/DivNodeHandler.ts
1218
- import { HTMLElement as HTMLElement2 } from "node-html-parser";
1284
+ import { HTMLElement as HTMLElement3 } from "node-html-parser";
1219
1285
 
1220
1286
  // src/importFromHtml/createNestedNodesFromHtml.ts
1221
- import { HTMLElement } from "node-html-parser";
1287
+ import { HTMLElement as HTMLElement2 } from "node-html-parser";
1222
1288
  var wrapInlinesInParagraph = (inlineNodes, format = "") => {
1223
1289
  const paragraph = createEmptyParagraphNode(format);
1224
1290
  paragraph.children = inlineNodes;
@@ -1244,9 +1310,9 @@ var extractFormatFromStyle = (styleAttribute) => {
1244
1310
  return "";
1245
1311
  };
1246
1312
  var createNestedNodesFromHtml = (node) => {
1247
- const parentStyleAttribute = node instanceof HTMLElement ? node.getAttribute("style") : null;
1313
+ const parentStyleAttribute = node instanceof HTMLElement2 ? node.getAttribute("style") : null;
1248
1314
  const format = extractFormatFromStyle(parentStyleAttribute);
1249
- if (node.childNodes.length === 1 && node.childNodes[0] instanceof HTMLElement && node.childNodes[0].tagName === "BR") {
1315
+ if (node.childNodes.length === 1 && node.childNodes[0] instanceof HTMLElement2 && node.childNodes[0].tagName === "BR") {
1250
1316
  return [createEmptyParagraphNode(format)];
1251
1317
  }
1252
1318
  const results = [];
@@ -1382,36 +1448,10 @@ function processImageNodeContainer(node) {
1382
1448
  ];
1383
1449
  }
1384
1450
 
1385
- // src/importFromHtml/types.ts
1386
- var NodeHandler2 = class {
1387
- constructor() {
1388
- this.nextHandler = null;
1389
- }
1390
- getChildNodesTextContent(childNodes) {
1391
- return childNodes.reduce((acc, item) => {
1392
- const text = item.textContent || "";
1393
- return acc + text.trim() + " ";
1394
- }, "").trimEnd();
1395
- }
1396
- setNext(handler) {
1397
- this.nextHandler = handler;
1398
- return handler;
1399
- }
1400
- handle(node) {
1401
- const result = this.processNode(node);
1402
- if (result) {
1403
- return result;
1404
- } else if (this.nextHandler) {
1405
- return this.nextHandler.handle(node);
1406
- }
1407
- return null;
1408
- }
1409
- };
1410
-
1411
1451
  // src/importFromHtml/DivNodeHandler.ts
1412
1452
  var DivNodeHandler = class extends NodeHandler2 {
1413
1453
  isHtmlDivElement(node) {
1414
- return node instanceof HTMLElement2 && node.tagName === "DIV";
1454
+ return node instanceof HTMLElement3 && node.tagName === "DIV";
1415
1455
  }
1416
1456
  processNode(node) {
1417
1457
  if (!this.isHtmlDivElement(node)) {
@@ -1426,12 +1466,12 @@ var DivNodeHandler = class extends NodeHandler2 {
1426
1466
 
1427
1467
  // src/importFromHtml/EssayQuestionNodeHandler.ts
1428
1468
  import { nanoid } from "nanoid";
1429
- import { HTMLElement as HTMLElement3 } from "node-html-parser";
1469
+ import { HTMLElement as HTMLElement4 } from "node-html-parser";
1430
1470
  var TAG_X_ESSAY = "x-essay";
1431
1471
  var TAG_X_SYSTEM_MESSAGE = "x-ai-system-message";
1432
1472
  var EssayQuestionNodeHandler2 = class extends NodeHandler2 {
1433
1473
  processNode(node) {
1434
- if (!(node instanceof HTMLElement3) || node.tagName !== TAG_X_ESSAY.toUpperCase()) {
1474
+ if (!(node instanceof HTMLElement4) || node.tagName !== TAG_X_ESSAY.toUpperCase()) {
1435
1475
  return null;
1436
1476
  }
1437
1477
  const jsonNode = {
@@ -1457,7 +1497,7 @@ var EssayQuestionNodeHandler2 = class extends NodeHandler2 {
1457
1497
 
1458
1498
  // src/importFromHtml/FillInTheBlankQuestionNodeHandler.ts
1459
1499
  import { nanoid as nanoid2 } from "nanoid";
1460
- import { HTMLElement as HTMLElement4 } from "node-html-parser";
1500
+ import { HTMLElement as HTMLElement5 } from "node-html-parser";
1461
1501
 
1462
1502
  // src/importFromHtml/createNestedEditorFromHtml.ts
1463
1503
  function createNestedEditorFromHtml(node) {
@@ -1478,7 +1518,7 @@ function createNestedEditorFromHtml(node) {
1478
1518
  // src/importFromHtml/FillInTheBlankQuestionNodeHandler.ts
1479
1519
  var FillInTheBlankQuestionNodeHandler2 = class extends NodeHandler2 {
1480
1520
  processNode(node) {
1481
- if (!(node instanceof HTMLElement4) || node.tagName !== "x-fill-in-the-blank".toUpperCase())
1521
+ if (!(node instanceof HTMLElement5) || node.tagName !== "x-fill-in-the-blank".toUpperCase())
1482
1522
  return null;
1483
1523
  const jsonNode = {
1484
1524
  id: node.getAttribute("id") ?? nanoid2(),
@@ -1495,10 +1535,19 @@ var FillInTheBlankQuestionNodeHandler2 = class extends NodeHandler2 {
1495
1535
 
1496
1536
  // src/importFromHtml/FillInTheBlankSpaceNodeHandler.ts
1497
1537
  import { nanoid as nanoid3 } from "nanoid";
1498
- import { HTMLElement as HTMLElement5 } from "node-html-parser";
1538
+ import { HTMLElement as HTMLElement6 } from "node-html-parser";
1539
+
1540
+ // src/importFromHtml/parseErrorToleranceAttribute.ts
1541
+ function parseErrorToleranceAttribute(attr) {
1542
+ const value = Number(attr);
1543
+ if (isNaN(value)) return 0;
1544
+ else return value * 100;
1545
+ }
1546
+
1547
+ // src/importFromHtml/FillInTheBlankSpaceNodeHandler.ts
1499
1548
  var FillInTheBlankSpaceNodeHandler2 = class extends NodeHandler2 {
1500
1549
  processNode(node) {
1501
- if (!(node instanceof HTMLElement5) || node.tagName !== "x-space".toUpperCase())
1550
+ if (!(node instanceof HTMLElement6) || node.tagName !== "x-space".toUpperCase())
1502
1551
  return null;
1503
1552
  const spaceTypeAttr = node.getAttribute("data-x-type");
1504
1553
  const spaceType = spaceTypeAttr === "Text" || spaceTypeAttr === "Number" || spaceTypeAttr === "Dropdown" ? spaceTypeAttr : "Text";
@@ -1529,16 +1578,11 @@ var FillInTheBlankSpaceNodeHandler2 = class extends NodeHandler2 {
1529
1578
  errorsAllowed: node.getAttribute("data-x-errors-allowed") ? Number(node.getAttribute("data-x-errors-allowed")) : void 0
1530
1579
  };
1531
1580
  }
1532
- parseErrorToleranceAttr(attr) {
1533
- const value = Number(attr);
1534
- if (isNaN(value)) return 0;
1535
- else return value * 100;
1536
- }
1537
1581
  processNumberSpace(node, baseNode) {
1538
1582
  return {
1539
1583
  ...baseNode,
1540
1584
  minDecimals: node.getAttribute("data-x-min-decimals") ? Number(node.getAttribute("data-x-min-decimals")) : void 0,
1541
- errorTolerance: this.parseErrorToleranceAttr(
1585
+ errorTolerance: parseErrorToleranceAttribute(
1542
1586
  node.getAttribute("data-x-error-tolerance")
1543
1587
  )
1544
1588
  };
@@ -1553,7 +1597,7 @@ var FillInTheBlankSpaceNodeHandler2 = class extends NodeHandler2 {
1553
1597
 
1554
1598
  // src/importFromHtml/FinancialStatementQuestionNodeHandler.ts
1555
1599
  import { nanoid as nanoid4 } from "nanoid";
1556
- import { HTMLElement as HTMLElement6 } from "node-html-parser";
1600
+ import { HTMLElement as HTMLElement7 } from "node-html-parser";
1557
1601
  var TAG_X_FINANCIAL_STATEMENT = "x-financial-statement";
1558
1602
  var TAG_X_HEADER = "x-header";
1559
1603
  var TAG_X_ROWS = "x-rows";
@@ -1565,7 +1609,7 @@ var TAG_X_ENTRY = "x-entry";
1565
1609
  var TAG_X_AMOUNT = "x-amount";
1566
1610
  var FinancialStatementQuestionNodeHandler2 = class extends NodeHandler2 {
1567
1611
  processNode(node) {
1568
- if (!(node instanceof HTMLElement6) || node.tagName !== TAG_X_FINANCIAL_STATEMENT.toUpperCase()) {
1612
+ if (!(node instanceof HTMLElement7) || node.tagName !== TAG_X_FINANCIAL_STATEMENT.toUpperCase()) {
1569
1613
  return null;
1570
1614
  }
1571
1615
  const headerElement = node.querySelector(TAG_X_HEADER);
@@ -1580,7 +1624,7 @@ var FinancialStatementQuestionNodeHandler2 = class extends NodeHandler2 {
1580
1624
  version: 1
1581
1625
  };
1582
1626
  node.childNodes.forEach((child) => {
1583
- if (!(child instanceof HTMLElement6)) return;
1627
+ if (!(child instanceof HTMLElement7)) return;
1584
1628
  if (child.tagName === TAG_X_DISTRACTORS.toUpperCase()) {
1585
1629
  this.processDistractorsNode(child, jsonNode);
1586
1630
  } else if (child.tagName === TAG_X_ROWS.toUpperCase()) {
@@ -1591,7 +1635,7 @@ var FinancialStatementQuestionNodeHandler2 = class extends NodeHandler2 {
1591
1635
  }
1592
1636
  processDistractorsNode(distractorsNode, jsonNode) {
1593
1637
  for (const distractorsChild of distractorsNode.childNodes) {
1594
- if (!(distractorsChild instanceof HTMLElement6)) continue;
1638
+ if (!(distractorsChild instanceof HTMLElement7)) continue;
1595
1639
  if (distractorsChild.tagName !== TAG_X_DISTRACTOR.toUpperCase())
1596
1640
  continue;
1597
1641
  jsonNode.distractors.push({
@@ -1612,7 +1656,7 @@ var FinancialStatementQuestionNodeHandler2 = class extends NodeHandler2 {
1612
1656
  const contentDiv = headerElement.querySelector(
1613
1657
  'div > div:not([style*="display:flex"])'
1614
1658
  );
1615
- if (contentDiv && contentDiv instanceof HTMLElement6) {
1659
+ if (contentDiv && contentDiv instanceof HTMLElement7) {
1616
1660
  const contentDivClone = contentDiv.clone();
1617
1661
  contentDivClone.setAttribute("style", "text-align: left;");
1618
1662
  return createNestedEditorFromHtml(contentDivClone);
@@ -1632,7 +1676,7 @@ var FinancialStatementQuestionNodeHandler2 = class extends NodeHandler2 {
1632
1676
  }
1633
1677
  processRowsNode(rowsNode, jsonNode) {
1634
1678
  for (const rowsChild of rowsNode.childNodes) {
1635
- if (!(rowsChild instanceof HTMLElement6)) continue;
1679
+ if (!(rowsChild instanceof HTMLElement7)) continue;
1636
1680
  if (rowsChild.tagName === TAG_X_HEADING.toUpperCase()) {
1637
1681
  this.processHeadingRow(rowsChild, jsonNode);
1638
1682
  } else if (rowsChild.tagName === TAG_X_LINE.toUpperCase()) {
@@ -1666,7 +1710,7 @@ var FinancialStatementQuestionNodeHandler2 = class extends NodeHandler2 {
1666
1710
  };
1667
1711
 
1668
1712
  // src/importFromHtml/FormattedNodeHandler.ts
1669
- import { HTMLElement as HTMLElement7 } from "node-html-parser";
1713
+ import { HTMLElement as HTMLElement8 } from "node-html-parser";
1670
1714
  var IS_BOLD2 = 1;
1671
1715
  var IS_ITALIC2 = 1 << 1;
1672
1716
  var IS_STRIKETHROUGH2 = 1 << 2;
@@ -1706,7 +1750,7 @@ function formatToProps(format) {
1706
1750
  }
1707
1751
  var FormattedNodeHandler = class extends NodeHandler2 {
1708
1752
  processNode(node) {
1709
- if (!(node instanceof HTMLElement7)) return null;
1753
+ if (!(node instanceof HTMLElement8)) return null;
1710
1754
  const tagName = node.tagName;
1711
1755
  if (!tagName || !(tagName in TAG_TO_FORMAT)) return null;
1712
1756
  const formatFlag = TAG_TO_FORMAT[tagName];
@@ -1741,11 +1785,11 @@ var FormattedNodeHandler = class extends NodeHandler2 {
1741
1785
  };
1742
1786
 
1743
1787
  // src/importFromHtml/HorizontalRuleNodeHandler.ts
1744
- import { HTMLElement as HTMLElement8 } from "node-html-parser";
1788
+ import { HTMLElement as HTMLElement9 } from "node-html-parser";
1745
1789
  var TAG_HR = "hr";
1746
1790
  var HorizontalRuleNodeHandler2 = class extends NodeHandler2 {
1747
1791
  processNode(node) {
1748
- if (!(node instanceof HTMLElement8) || node.tagName !== TAG_HR.toUpperCase()) {
1792
+ if (!(node instanceof HTMLElement9) || node.tagName !== TAG_HR.toUpperCase()) {
1749
1793
  return null;
1750
1794
  }
1751
1795
  const horizontalRuleNode = {
@@ -1757,11 +1801,11 @@ var HorizontalRuleNodeHandler2 = class extends NodeHandler2 {
1757
1801
  };
1758
1802
 
1759
1803
  // src/importFromHtml/ImageNodeHandler.ts
1760
- import { HTMLElement as HTMLElement9 } from "node-html-parser";
1804
+ import { HTMLElement as HTMLElement10 } from "node-html-parser";
1761
1805
  var TAG_IMG = "img";
1762
1806
  var ImageNodeHandler2 = class extends NodeHandler2 {
1763
1807
  processNode(node) {
1764
- if (!(node instanceof HTMLElement9) || node.tagName !== TAG_IMG.toUpperCase()) {
1808
+ if (!(node instanceof HTMLElement10) || node.tagName !== TAG_IMG.toUpperCase()) {
1765
1809
  return null;
1766
1810
  }
1767
1811
  return createImageNode(
@@ -1777,11 +1821,11 @@ var ImageNodeHandler2 = class extends NodeHandler2 {
1777
1821
 
1778
1822
  // src/importFromHtml/JournalEntryQuestionNodeHandler.ts
1779
1823
  import { nanoid as nanoid6 } from "nanoid";
1780
- import { HTMLElement as HTMLElement11 } from "node-html-parser";
1824
+ import { HTMLElement as HTMLElement12 } from "node-html-parser";
1781
1825
 
1782
1826
  // src/importFromHtml/createOnePerLineDistractorNode.ts
1783
1827
  import { nanoid as nanoid5 } from "nanoid";
1784
- import { HTMLElement as HTMLElement10 } from "node-html-parser";
1828
+ import { HTMLElement as HTMLElement11 } from "node-html-parser";
1785
1829
  function extractDistractorId(id) {
1786
1830
  if (!id) return null;
1787
1831
  const parts = id.split("|");
@@ -1794,7 +1838,7 @@ var createOnePerLineDistractorNode = (node) => {
1794
1838
  distractorEditor.editorState.root.children = [];
1795
1839
  let distractorId = null;
1796
1840
  distractors.forEach((distractor) => {
1797
- if (!(distractor instanceof HTMLElement10)) return;
1841
+ if (!(distractor instanceof HTMLElement11)) return;
1798
1842
  distractorId = distractorId ?? extractDistractorId(distractor.getAttribute("id"));
1799
1843
  distractorEditor.editorState.root.children.push(
1800
1844
  ...createNestedNodesFromHtml(distractor)
@@ -1812,20 +1856,22 @@ var createOnePerLineDistractorNode = (node) => {
1812
1856
  // src/importFromHtml/JournalEntryQuestionNodeHandler.ts
1813
1857
  var JournalEntryQuestionNodeHandler2 = class extends NodeHandler2 {
1814
1858
  processNode(node) {
1815
- if (!(node instanceof HTMLElement11) || node.tagName !== "x-journal-entry".toUpperCase())
1859
+ if (!(node instanceof HTMLElement12) || node.tagName !== "x-journal-entry".toUpperCase())
1816
1860
  return null;
1817
1861
  const jsonNode = {
1818
1862
  id: node.getAttribute("id") ?? nanoid6(),
1819
1863
  points: Number(node.getAttribute("data-x-points") ?? 1),
1820
1864
  noEntryRequired: node.getAttribute("data-x-no-entry-required-correct") === "true",
1821
- errorTolerance: node.getAttribute("data-x-error-tolerance") ? Number(node.getAttribute("data-x-error-tolerance")) : void 0,
1865
+ errorTolerance: parseErrorToleranceAttribute(
1866
+ node.getAttribute("data-x-error-tolerance")
1867
+ ),
1822
1868
  lineItems: [],
1823
1869
  type: "journal-entry-question",
1824
1870
  version: 1
1825
1871
  };
1826
1872
  const lineItems = node.querySelectorAll("x-line-item");
1827
1873
  lineItems.forEach((lineItem) => {
1828
- if (!(lineItem instanceof HTMLElement11)) return;
1874
+ if (!(lineItem instanceof HTMLElement12)) return;
1829
1875
  const accountElement = lineItem.querySelector("x-account");
1830
1876
  const debitElement = lineItem.querySelector("x-debit");
1831
1877
  const creditElement = lineItem.querySelector("x-credit");
@@ -1854,10 +1900,10 @@ var JournalEntryQuestionNodeHandler2 = class extends NodeHandler2 {
1854
1900
  };
1855
1901
 
1856
1902
  // src/importFromHtml/LineBreakNodeHandler.ts
1857
- import { HTMLElement as HTMLElement12 } from "node-html-parser";
1903
+ import { HTMLElement as HTMLElement13 } from "node-html-parser";
1858
1904
  var LineBreakNodeHandler2 = class extends NodeHandler2 {
1859
1905
  processNode(node) {
1860
- if (!(node instanceof HTMLElement12)) return null;
1906
+ if (!(node instanceof HTMLElement13)) return null;
1861
1907
  if (node.tagName !== "BR") return null;
1862
1908
  return {
1863
1909
  type: "linebreak",
@@ -1867,11 +1913,11 @@ var LineBreakNodeHandler2 = class extends NodeHandler2 {
1867
1913
  };
1868
1914
 
1869
1915
  // src/importFromHtml/LinkNodeHandler.ts
1870
- import { HTMLElement as HTMLElement13 } from "node-html-parser";
1916
+ import { HTMLElement as HTMLElement14 } from "node-html-parser";
1871
1917
  var TAG_A = "a";
1872
1918
  var LinkNodeHandler2 = class extends NodeHandler2 {
1873
1919
  processNode(node) {
1874
- if (!(node instanceof HTMLElement13) || node.tagName !== TAG_A.toUpperCase()) {
1920
+ if (!(node instanceof HTMLElement14) || node.tagName !== TAG_A.toUpperCase()) {
1875
1921
  return null;
1876
1922
  }
1877
1923
  const url = node.getAttribute("href") || "";
@@ -1900,10 +1946,10 @@ var LinkNodeHandler2 = class extends NodeHandler2 {
1900
1946
  };
1901
1947
 
1902
1948
  // src/importFromHtml/ListItemNodeHandler.ts
1903
- import { HTMLElement as HTMLElement14 } from "node-html-parser";
1949
+ import { HTMLElement as HTMLElement15 } from "node-html-parser";
1904
1950
  var ListItemNodeHandler2 = class extends NodeHandler2 {
1905
1951
  processNode(node) {
1906
- if (!(node instanceof HTMLElement14)) return null;
1952
+ if (!(node instanceof HTMLElement15)) return null;
1907
1953
  if (node.tagName !== "LI") return null;
1908
1954
  const jsonNode = {
1909
1955
  type: "listitem",
@@ -1924,10 +1970,10 @@ var ListItemNodeHandler2 = class extends NodeHandler2 {
1924
1970
  };
1925
1971
 
1926
1972
  // src/importFromHtml/ListNodeHandler.ts
1927
- import { HTMLElement as HTMLElement15 } from "node-html-parser";
1973
+ import { HTMLElement as HTMLElement16 } from "node-html-parser";
1928
1974
  var ListNodeHandler2 = class extends NodeHandler2 {
1929
1975
  processNode(node) {
1930
- if (!(node instanceof HTMLElement15)) return null;
1976
+ if (!(node instanceof HTMLElement16)) return null;
1931
1977
  if (node.tagName !== "UL" && node.tagName !== "OL") return null;
1932
1978
  const tag = node.tagName.toLowerCase();
1933
1979
  const listType = tag === "ol" ? "number" : "bullet";
@@ -1945,7 +1991,7 @@ var ListNodeHandler2 = class extends NodeHandler2 {
1945
1991
  };
1946
1992
  let itemIndex = 1;
1947
1993
  node.childNodes.forEach((child) => {
1948
- if (child instanceof HTMLElement15 && child.tagName === "LI") {
1994
+ if (child instanceof HTMLElement16 && child.tagName === "LI") {
1949
1995
  const listItemNode = {
1950
1996
  type: "listitem",
1951
1997
  version: 1,
@@ -1970,10 +2016,10 @@ var ListNodeHandler2 = class extends NodeHandler2 {
1970
2016
 
1971
2017
  // src/importFromHtml/MatchingQuestionNodeHandler.ts
1972
2018
  import { nanoid as nanoid7 } from "nanoid";
1973
- import { HTMLElement as HTMLElement16 } from "node-html-parser";
2019
+ import { HTMLElement as HTMLElement17 } from "node-html-parser";
1974
2020
  var MatchingQuestionNodeHandler2 = class extends NodeHandler2 {
1975
2021
  processNode(node) {
1976
- if (!(node instanceof HTMLElement16) || node.tagName !== "x-matching".toUpperCase())
2022
+ if (!(node instanceof HTMLElement17) || node.tagName !== "x-matching".toUpperCase())
1977
2023
  return null;
1978
2024
  const jsonNode = {
1979
2025
  id: node.getAttribute("id") ?? nanoid7(),
@@ -1986,7 +2032,7 @@ var MatchingQuestionNodeHandler2 = class extends NodeHandler2 {
1986
2032
  };
1987
2033
  const matches = node.querySelectorAll("x-match");
1988
2034
  matches.forEach((match) => {
1989
- if (!(match instanceof HTMLElement16)) return;
2035
+ if (!(match instanceof HTMLElement17)) return;
1990
2036
  const premise = match.querySelector("x-premise");
1991
2037
  const option = match.querySelector("x-option");
1992
2038
  if (!premise || !option) return;
@@ -2009,10 +2055,10 @@ var MatchingQuestionNodeHandler2 = class extends NodeHandler2 {
2009
2055
 
2010
2056
  // src/importFromHtml/MultipleOptionQuestionNodeHandler.ts
2011
2057
  import { nanoid as nanoid8 } from "nanoid";
2012
- import { HTMLElement as HTMLElement17 } from "node-html-parser";
2058
+ import { HTMLElement as HTMLElement18 } from "node-html-parser";
2013
2059
  var MultipleOptionQuestionNodeHandler2 = class extends NodeHandler2 {
2014
2060
  processNode(node) {
2015
- if (!(node instanceof HTMLElement17)) return null;
2061
+ if (!(node instanceof HTMLElement18)) return null;
2016
2062
  if (node.tagName === "x-multiple-choice".toUpperCase())
2017
2063
  return this.processMultipleChoiceNode(node);
2018
2064
  else if (node.tagName === "x-multiple-answers".toUpperCase())
@@ -2052,7 +2098,7 @@ var MultipleOptionQuestionNodeHandler2 = class extends NodeHandler2 {
2052
2098
  processOptions(node, jsonNode) {
2053
2099
  const childNodes = node.childNodes;
2054
2100
  childNodes.forEach((child) => {
2055
- if (!(child instanceof HTMLElement17)) return;
2101
+ if (!(child instanceof HTMLElement18)) return;
2056
2102
  if (child.tagName !== "x-option".toUpperCase()) return;
2057
2103
  jsonNode.options.push({
2058
2104
  id: child.getAttribute("id") ?? nanoid8(),
@@ -2064,7 +2110,7 @@ var MultipleOptionQuestionNodeHandler2 = class extends NodeHandler2 {
2064
2110
  };
2065
2111
 
2066
2112
  // src/importFromHtml/ParagraphNodeHandler.ts
2067
- import { HTMLElement as HTMLElement18 } from "node-html-parser";
2113
+ import { HTMLElement as HTMLElement19 } from "node-html-parser";
2068
2114
  var TEXT_ALIGN_TO_FORMAT = {
2069
2115
  center: "center",
2070
2116
  end: "end",
@@ -2087,25 +2133,25 @@ var ParagraphNodeHandler2 = class extends NodeHandler2 {
2087
2133
  return "";
2088
2134
  }
2089
2135
  processImageNode(node) {
2090
- if (node.childNodes.length === 1 && node.childNodes[0] instanceof HTMLElement18 && node.childNodes[0].tagName === "IMG") {
2136
+ if (node.childNodes.length === 1 && node.childNodes[0] instanceof HTMLElement19 && node.childNodes[0].tagName === "IMG") {
2091
2137
  return traverse2(node.childNodes[0]);
2092
2138
  }
2093
2139
  return null;
2094
2140
  }
2095
2141
  processSpanImageNode(node) {
2096
- if (node.childNodes.length === 1 && node.childNodes[0] instanceof HTMLElement18 && node.childNodes[0].tagName === "SPAN" && node.childNodes[0].childNodes.length === 1 && node.childNodes[0].childNodes[0] instanceof HTMLElement18 && node.childNodes[0].childNodes[0].tagName === "IMG") {
2142
+ if (node.childNodes.length === 1 && node.childNodes[0] instanceof HTMLElement19 && node.childNodes[0].tagName === "SPAN" && node.childNodes[0].childNodes.length === 1 && node.childNodes[0].childNodes[0] instanceof HTMLElement19 && node.childNodes[0].childNodes[0].tagName === "IMG") {
2097
2143
  return traverse2(node.childNodes[0].childNodes[0]);
2098
2144
  }
2099
2145
  return null;
2100
2146
  }
2101
2147
  processNode(node) {
2102
- if (!(node instanceof HTMLElement18)) return null;
2148
+ if (!(node instanceof HTMLElement19)) return null;
2103
2149
  if (node.tagName !== "P") return null;
2104
2150
  const imageNode = this.processImageNode(node) ?? this.processSpanImageNode(node);
2105
2151
  if (imageNode) return imageNode;
2106
2152
  const jsonNode = createEmptyParagraphNode();
2107
2153
  jsonNode.format = this.extractTextAlignment(node);
2108
- if (node.childNodes.length === 1 && node.childNodes[0] instanceof HTMLElement18 && node.childNodes[0].tagName === "BR")
2154
+ if (node.childNodes.length === 1 && node.childNodes[0] instanceof HTMLElement19 && node.childNodes[0].tagName === "BR")
2109
2155
  return jsonNode;
2110
2156
  node.childNodes.forEach((child) => {
2111
2157
  const processedChildren = traverse2(child);
@@ -2117,10 +2163,10 @@ var ParagraphNodeHandler2 = class extends NodeHandler2 {
2117
2163
 
2118
2164
  // src/importFromHtml/ShortAnswerQuestionNodeHandler.ts
2119
2165
  import { nanoid as nanoid9 } from "nanoid";
2120
- import { HTMLElement as HTMLElement19 } from "node-html-parser";
2166
+ import { HTMLElement as HTMLElement20 } from "node-html-parser";
2121
2167
  var ShortAnswerQuestionNodeHandler2 = class extends NodeHandler2 {
2122
2168
  processNode(node) {
2123
- if (!(node instanceof HTMLElement19) || node.tagName !== "x-short-answer".toUpperCase())
2169
+ if (!(node instanceof HTMLElement20) || node.tagName !== "x-short-answer".toUpperCase())
2124
2170
  return null;
2125
2171
  return {
2126
2172
  id: node.getAttribute("id") ?? nanoid9(),
@@ -2136,13 +2182,13 @@ var ShortAnswerQuestionNodeHandler2 = class extends NodeHandler2 {
2136
2182
  };
2137
2183
 
2138
2184
  // src/importFromHtml/SimulationQuestionNodeHandler.ts
2139
- import { HTMLElement as HTMLElement20 } from "node-html-parser";
2185
+ import { HTMLElement as HTMLElement21 } from "node-html-parser";
2140
2186
  var TAG_X_SIMULATION = "x-simulation";
2141
2187
  var TAG_X_SYSTEM_MESSAGE2 = "x-ai-system-message";
2142
2188
  var TAG_X_STEP2_INSTRUCTIONS = "x-step2-instructions";
2143
2189
  var SimulationQuestionNodeHandler2 = class extends NodeHandler2 {
2144
2190
  processNode(node) {
2145
- if (!(node instanceof HTMLElement20) || node.tagName !== TAG_X_SIMULATION.toUpperCase()) {
2191
+ if (!(node instanceof HTMLElement21) || node.tagName !== TAG_X_SIMULATION.toUpperCase()) {
2146
2192
  return null;
2147
2193
  }
2148
2194
  const jsonNode = {
@@ -2169,11 +2215,11 @@ var SimulationQuestionNodeHandler2 = class extends NodeHandler2 {
2169
2215
  };
2170
2216
 
2171
2217
  // src/importFromHtml/SpanNodeHandler.ts
2172
- import { HTMLElement as HTMLElement21, parse } from "node-html-parser";
2218
+ import { HTMLElement as HTMLElement22, parse } from "node-html-parser";
2173
2219
  var TextNode = parse.TextNode;
2174
2220
  var SpanNodeHandler = class extends NodeHandler2 {
2175
2221
  processNode(node) {
2176
- if (!(node instanceof HTMLElement21) || node.tagName !== "SPAN")
2222
+ if (!(node instanceof HTMLElement22) || node.tagName !== "SPAN")
2177
2223
  return null;
2178
2224
  const styleAttr = node.getAttribute("style") || "";
2179
2225
  if (node.childNodes.length === 1 && node.childNodes[0] instanceof TextNode) {
@@ -2235,7 +2281,7 @@ var SpanNodeHandler = class extends NodeHandler2 {
2235
2281
  };
2236
2282
 
2237
2283
  // src/importFromHtml/TableCellNodeHandler.ts
2238
- import { HTMLElement as HTMLElement22 } from "node-html-parser";
2284
+ import { HTMLElement as HTMLElement23 } from "node-html-parser";
2239
2285
 
2240
2286
  // src/utils/styleUtils.ts
2241
2287
  var extractStyleValue = (styleAttr, property, isNumeric = false, unit = "") => {
@@ -2284,7 +2330,7 @@ function createEmptyTableCellNode(isHeader = false) {
2284
2330
 
2285
2331
  // src/importFromHtml/TableCellNodeHandler.ts
2286
2332
  var isHtmlTableCellElement = (node) => {
2287
- return node instanceof HTMLElement22 && (node.tagName === "TD" || node.tagName === "TH");
2333
+ return node instanceof HTMLElement23 && (node.tagName === "TD" || node.tagName === "TH");
2288
2334
  };
2289
2335
  var TableCellNodeHandler2 = class extends NodeHandler2 {
2290
2336
  processNode(node) {
@@ -2326,10 +2372,10 @@ var TableCellNodeHandler2 = class extends NodeHandler2 {
2326
2372
  };
2327
2373
 
2328
2374
  // src/importFromHtml/TableNodeHandler.ts
2329
- import { HTMLElement as HTMLElement23 } from "node-html-parser";
2375
+ import { HTMLElement as HTMLElement24 } from "node-html-parser";
2330
2376
  var REFERENCE_TABLE_WIDTH = 720;
2331
2377
  var MINIMUM_REFERENCE_TABLE_WIDTH = 500;
2332
- var isHtmlTableElement = (node) => node instanceof HTMLElement23 && node.tagName === "TABLE";
2378
+ var isHtmlTableElement = (node) => node instanceof HTMLElement24 && node.tagName === "TABLE";
2333
2379
  var TableNodeHandler2 = class extends NodeHandler2 {
2334
2380
  processNode(node) {
2335
2381
  if (!isHtmlTableElement(node)) return null;
@@ -2484,9 +2530,9 @@ var TableNodeHandler2 = class extends NodeHandler2 {
2484
2530
  };
2485
2531
 
2486
2532
  // src/importFromHtml/TableRowNodeHandler.ts
2487
- import { HTMLElement as HTMLElement24 } from "node-html-parser";
2533
+ import { HTMLElement as HTMLElement25 } from "node-html-parser";
2488
2534
  var isHtmlTableRowElement = (node) => {
2489
- return node instanceof HTMLElement24 && node.tagName === "TR";
2535
+ return node instanceof HTMLElement25 && node.tagName === "TR";
2490
2536
  };
2491
2537
  var TableRowNodeHandler2 = class extends NodeHandler2 {
2492
2538
  processNode(node) {
@@ -2513,30 +2559,26 @@ import { parse as parse2 } from "node-html-parser";
2513
2559
  var TextNode2 = parse2.TextNode;
2514
2560
  var TextNodeHandler2 = class extends NodeHandler2 {
2515
2561
  processNode(node) {
2516
- if (node instanceof TextNode2 && !!node.parentNode.tagName) {
2517
- if (node.isWhitespace) {
2518
- return null;
2519
- }
2520
- const jsonNode = {
2521
- detail: 0,
2522
- format: 0,
2523
- mode: "normal",
2524
- style: "",
2525
- text: node.text,
2526
- type: "text",
2527
- version: 1
2528
- };
2529
- return jsonNode;
2530
- }
2531
- return null;
2562
+ if (!(node instanceof TextNode2)) return null;
2563
+ if (!node.parentNode.tagName) return null;
2564
+ const jsonNode = {
2565
+ detail: 0,
2566
+ format: 0,
2567
+ mode: "normal",
2568
+ style: "",
2569
+ text: node.text,
2570
+ type: "text",
2571
+ version: 1
2572
+ };
2573
+ return jsonNode;
2532
2574
  }
2533
2575
  };
2534
2576
 
2535
2577
  // src/importFromHtml/VariableNodeHandler.ts
2536
- import { HTMLElement as HTMLElement25 } from "node-html-parser";
2578
+ import { HTMLElement as HTMLElement26 } from "node-html-parser";
2537
2579
  var VariableNodeHandler2 = class extends NodeHandler2 {
2538
2580
  processNode(node) {
2539
- if (!(node instanceof HTMLElement25) || !node.tagName) return null;
2581
+ if (!(node instanceof HTMLElement26) || !node.tagName) return null;
2540
2582
  if (node.tagName !== "x-param".toUpperCase()) return null;
2541
2583
  return {
2542
2584
  variableName: node.getAttribute("data-x-name") || "undefined",
@@ -2549,7 +2591,7 @@ var VariableNodeHandler2 = class extends NodeHandler2 {
2549
2591
 
2550
2592
  // src/importFromHtml/traverse.ts
2551
2593
  var builder2 = new NodeHandlerChainBuilder();
2552
- var nodeHandlerChain2 = builder2.addHandler(DivNodeHandler).addHandler(EssayQuestionNodeHandler2).addHandler(FillInTheBlankQuestionNodeHandler2).addHandler(FillInTheBlankSpaceNodeHandler2).addHandler(FinancialStatementQuestionNodeHandler2).addHandler(FormattedNodeHandler).addHandler(ImageNodeHandler2).addHandler(HorizontalRuleNodeHandler2).addHandler(JournalEntryQuestionNodeHandler2).addHandler(LineBreakNodeHandler2).addHandler(LinkNodeHandler2).addHandler(ListNodeHandler2).addHandler(ListItemNodeHandler2).addHandler(MatchingQuestionNodeHandler2).addHandler(MultipleOptionQuestionNodeHandler2).addHandler(ParagraphNodeHandler2).addHandler(ShortAnswerQuestionNodeHandler2).addHandler(SimulationQuestionNodeHandler2).addHandler(SpanNodeHandler).addHandler(TableCellNodeHandler2).addHandler(TableNodeHandler2).addHandler(TableRowNodeHandler2).addHandler(TextNodeHandler2).addHandler(VariableNodeHandler2).build();
2594
+ var nodeHandlerChain2 = builder2.addHandler(CustomQuestionNodeHandler2).addHandler(DivNodeHandler).addHandler(EssayQuestionNodeHandler2).addHandler(FillInTheBlankQuestionNodeHandler2).addHandler(FillInTheBlankSpaceNodeHandler2).addHandler(FinancialStatementQuestionNodeHandler2).addHandler(FormattedNodeHandler).addHandler(ImageNodeHandler2).addHandler(HorizontalRuleNodeHandler2).addHandler(JournalEntryQuestionNodeHandler2).addHandler(LineBreakNodeHandler2).addHandler(LinkNodeHandler2).addHandler(ListNodeHandler2).addHandler(ListItemNodeHandler2).addHandler(MatchingQuestionNodeHandler2).addHandler(MultipleOptionQuestionNodeHandler2).addHandler(ParagraphNodeHandler2).addHandler(ShortAnswerQuestionNodeHandler2).addHandler(SimulationQuestionNodeHandler2).addHandler(SpanNodeHandler).addHandler(TableCellNodeHandler2).addHandler(TableNodeHandler2).addHandler(TableRowNodeHandler2).addHandler(TextNodeHandler2).addHandler(VariableNodeHandler2).build();
2553
2595
  function traverse2(node) {
2554
2596
  const result = nodeHandlerChain2.handle(node);
2555
2597
  if (result === null) return [];