@examplary/qti 1.1.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +31 -2
  2. package/dist/ims/ims-manifest.d.ts +3 -0
  3. package/dist/ims/ims-manifest.js +55 -0
  4. package/dist/ims/ims-package.d.ts +2 -0
  5. package/dist/ims/ims-package.js +25 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +2 -0
  8. package/dist/qti/interactions/associate-interaction.d.ts +8 -0
  9. package/dist/qti/interactions/associate-interaction.js +54 -8
  10. package/dist/qti/interactions/choice-interaction.d.ts +11 -0
  11. package/dist/qti/interactions/choice-interaction.js +60 -11
  12. package/dist/qti/interactions/drawing-interaction.d.ts +5 -0
  13. package/dist/qti/interactions/drawing-interaction.js +34 -8
  14. package/dist/qti/interactions/end-attempt-interaction.d.ts +6 -0
  15. package/dist/qti/interactions/end-attempt-interaction.js +24 -5
  16. package/dist/qti/interactions/extended-text-interaction.d.ts +13 -0
  17. package/dist/qti/interactions/extended-text-interaction.js +60 -12
  18. package/dist/qti/interactions/gap-match-interaction.d.ts +9 -0
  19. package/dist/qti/interactions/gap-match-interaction.js +60 -10
  20. package/dist/qti/interactions/graphic-associate-interaction.d.ts +8 -0
  21. package/dist/qti/interactions/graphic-associate-interaction.js +68 -12
  22. package/dist/qti/interactions/graphic-gap-match-interaction.d.ts +9 -0
  23. package/dist/qti/interactions/graphic-gap-match-interaction.js +97 -14
  24. package/dist/qti/interactions/graphic-order-interaction.d.ts +8 -0
  25. package/dist/qti/interactions/graphic-order-interaction.js +63 -12
  26. package/dist/qti/interactions/hotspot-interaction.d.ts +8 -0
  27. package/dist/qti/interactions/hotspot-interaction.js +63 -12
  28. package/dist/qti/interactions/hottext-interaction.d.ts +7 -0
  29. package/dist/qti/interactions/hottext-interaction.js +34 -7
  30. package/dist/qti/interactions/index.d.ts +3 -0
  31. package/dist/qti/interactions/index.js +3 -0
  32. package/dist/qti/interactions/inline-choice-interaction.d.ts +7 -0
  33. package/dist/qti/interactions/inline-choice-interaction.js +39 -7
  34. package/dist/qti/interactions/interaction.d.ts +7 -3
  35. package/dist/qti/interactions/interaction.js +15 -9
  36. package/dist/qti/interactions/match-interaction.d.ts +9 -0
  37. package/dist/qti/interactions/match-interaction.js +66 -10
  38. package/dist/qti/interactions/media-interaction.d.ts +9 -0
  39. package/dist/qti/interactions/media-interaction.js +54 -12
  40. package/dist/qti/interactions/order-interaction.d.ts +9 -0
  41. package/dist/qti/interactions/order-interaction.js +52 -9
  42. package/dist/qti/interactions/portable-custom-interaction.d.ts +50 -0
  43. package/dist/qti/interactions/portable-custom-interaction.js +123 -0
  44. package/dist/qti/interactions/position-object-interaction.d.ts +9 -0
  45. package/dist/qti/interactions/position-object-interaction.js +74 -17
  46. package/dist/qti/interactions/select-point-interaction.d.ts +7 -0
  47. package/dist/qti/interactions/select-point-interaction.js +46 -10
  48. package/dist/qti/interactions/slider-interaction.d.ts +10 -0
  49. package/dist/qti/interactions/slider-interaction.js +40 -9
  50. package/dist/qti/interactions/text-entry-interaction.d.ts +10 -0
  51. package/dist/qti/interactions/text-entry-interaction.js +42 -9
  52. package/dist/qti/interactions/upload-interaction.d.ts +7 -2
  53. package/dist/qti/interactions/upload-interaction.js +21 -5
  54. package/dist/qti/qti-assessment-section.d.ts +26 -0
  55. package/dist/qti/qti-assessment-section.js +29 -0
  56. package/dist/qti/qti-element.d.ts +10 -2
  57. package/dist/qti/qti-element.js +18 -6
  58. package/dist/qti/qti-item.d.ts +15 -9
  59. package/dist/qti/qti-item.js +175 -77
  60. package/dist/qti/qti-test-part.d.ts +19 -0
  61. package/dist/qti/qti-test-part.js +25 -0
  62. package/dist/qti/qti-test.d.ts +12 -7
  63. package/dist/qti/qti-test.js +180 -43
  64. package/package.json +3 -2
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  This module provides utilities for creating and managing QTI 3.0 assessment packages, including generating IMS manifests and QTI test/item XML structures.
4
4
 
5
+ ## Building QTI assessments
6
+
5
7
  Example usage:
6
8
 
7
9
  ```ts
@@ -20,8 +22,10 @@ const item = new QtiItem({
20
22
  title: "Sample Question",
21
23
  });
22
24
 
23
- item.addResponseDeclaration({ identifier: "RESPONSE" });
24
- item.addCorrectResponse("RESPONSE", ["4"]);
25
+ item.addResponseDeclaration({
26
+ identifier: "RESPONSE",
27
+ correctResponse: ["4"],
28
+ });
25
29
 
26
30
  item.addItemBodyFromHtml("<p>What is 2 + 2?</p>");
27
31
  item.addInteraction(
@@ -47,3 +51,28 @@ test.addToPackage(pkg);
47
51
 
48
52
  const zip = await pkg.generateZip();
49
53
  ```
54
+
55
+ ## Parsing QTI assessments
56
+
57
+ The library also supports parsing existing QTI packages:
58
+
59
+ ```ts
60
+ import { QtiItem, ImsPackage, ImsManifestResourceType } from "@examplary/qti";
61
+ import { readFile } from "fs/promises";
62
+
63
+ const contents = await readFile("./example-qti-package.zip");
64
+ const pkg = await ImsPackage.fromZip(contents);
65
+
66
+ const itemResources = pkg.manifest.getResourcesOfType(
67
+ ImsManifestResourceType.imsqti_item_xmlv3p0,
68
+ );
69
+
70
+ for (const resource of itemResources) {
71
+ const item = await QtiItem.fromImsPackageResource(pkg, resource);
72
+ const xml = await pkg.getResourceContentsString(item.identifier);
73
+ const item = QtiItem.fromXmlString(xml!);
74
+
75
+ console.log("Question title:", item.title);
76
+ console.log("Interactions:", item.getInteractions());
77
+ }
78
+ ```
@@ -51,5 +51,8 @@ export declare class ImsManifest {
51
51
  constructor(options?: ImsManifestOptions);
52
52
  addResource(resource: ImsManifestResource): void;
53
53
  getResources(): ImsManifestResource[];
54
+ getResourcesOfType(type: ImsManifestResourceType): ImsManifestResource[];
55
+ getResourceByIdentifier(identifier: string): ImsManifestResource | undefined;
56
+ static fromXmlString(xml: string): ImsManifest;
54
57
  buildXml(): string;
55
58
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ImsManifest = exports.ImsManifestResourceType = void 0;
4
+ const cheerio_1 = require("cheerio");
4
5
  const xmlbuilder2_1 = require("xmlbuilder2");
5
6
  var ImsManifestResourceType;
6
7
  (function (ImsManifestResourceType) {
@@ -73,6 +74,60 @@ class ImsManifest {
73
74
  getResources() {
74
75
  return Array.from(this.resources.values());
75
76
  }
77
+ getResourcesOfType(type) {
78
+ return Array.from(this.resources.values()).filter((res) => res.type === type);
79
+ }
80
+ getResourceByIdentifier(identifier) {
81
+ return this.resources.get(identifier);
82
+ }
83
+ static fromXmlString(xml) {
84
+ const $ = (0, cheerio_1.load)(xml, { xmlMode: true });
85
+ const root = $("manifest");
86
+ if (!root.length)
87
+ throw new Error("Missing manifest element");
88
+ const resources = root.find("resources");
89
+ if (!resources?.length) {
90
+ throw new Error("Invalid IMS Manifest XML: Missing resources element");
91
+ }
92
+ const manifest = new ImsManifest({
93
+ identifier: root.attr("identifier"),
94
+ // TODO: parse other metadata if needed
95
+ });
96
+ resources.find("resource").each((_, res) => {
97
+ const $res = $(res);
98
+ const identifier = $res.attr("identifier");
99
+ const type = $res.attr("type");
100
+ if (!identifier || !type) {
101
+ throw new Error("Invalid IMS Manifest XML: Resource missing identifier or type");
102
+ }
103
+ const href = $res.attr("href");
104
+ const files = [];
105
+ $res.find("file").each((_, file) => {
106
+ const $file = $(file);
107
+ const fileHref = $file.attr("href");
108
+ if (fileHref) {
109
+ files.push({ href: fileHref });
110
+ }
111
+ });
112
+ const dependencies = [];
113
+ $res.find("dependency").each((_, dep) => {
114
+ const $dep = $(dep);
115
+ const identifierref = $dep.attr("identifierref");
116
+ if (identifierref) {
117
+ dependencies.push({ identifierref });
118
+ }
119
+ });
120
+ manifest.addResource({
121
+ identifier,
122
+ type: type,
123
+ href: href || undefined,
124
+ metadata: $res.find("metadata").first(), // TODO: inconsistent type casting here
125
+ files,
126
+ dependencies: dependencies.length > 0 ? dependencies : undefined,
127
+ });
128
+ });
129
+ return manifest;
130
+ }
76
131
  buildXml() {
77
132
  const manifest = (0, xmlbuilder2_1.create)({ version: "1.0", encoding: "UTF-8" }).ele("manifest", {
78
133
  xmlns: "http://www.imsglobal.org/xsd/qti/qtiv3p0/imscp_v1p1",
@@ -18,10 +18,12 @@ export declare class ImsPackage {
18
18
  * Create a new IMS Package.
19
19
  */
20
20
  constructor(manifestOptions?: ImsManifestOptions);
21
+ static fromZip(zipContents: ArrayBuffer | Buffer): Promise<ImsPackage>;
21
22
  /**
22
23
  * Add a resource to the IMS Package, along with its associated files.
23
24
  */
24
25
  addResource(resource: ImsManifestResourceWithoutFiles, files: ImsPackageFile[]): Promise<void>;
26
+ getResourceContentsString(resourceIdentifier: string): Promise<string | undefined>;
25
27
  /**
26
28
  * Add a file directly to the final ZIP, without adding it to the manifest.
27
29
  * Can fetch from URL or add from data.
@@ -16,6 +16,19 @@ class ImsPackage {
16
16
  this.manifest = new ims_manifest_1.ImsManifest(manifestOptions);
17
17
  this.zip = new jszip_1.default();
18
18
  }
19
+ static async fromZip(zipContents) {
20
+ const zip = await jszip_1.default.loadAsync(zipContents);
21
+ const manifestFile = zip.file("imsmanifest.xml");
22
+ if (!manifestFile) {
23
+ throw new Error("Invalid IMS Package: Missing imsmanifest.xml");
24
+ }
25
+ const manifestXml = await manifestFile.async("string");
26
+ const manifest = ims_manifest_1.ImsManifest.fromXmlString(manifestXml);
27
+ const imsPackage = new ImsPackage(manifest);
28
+ imsPackage.manifest = manifest;
29
+ imsPackage.zip = zip;
30
+ return imsPackage;
31
+ }
19
32
  /**
20
33
  * Add a resource to the IMS Package, along with its associated files.
21
34
  */
@@ -28,6 +41,18 @@ class ImsPackage {
28
41
  files: files.map((file) => ({ href: file.filename })),
29
42
  });
30
43
  }
44
+ async getResourceContentsString(resourceIdentifier) {
45
+ const resource = this.manifest.getResourceByIdentifier(resourceIdentifier);
46
+ if (!resource || !resource.href) {
47
+ throw new Error(`Resource with identifier ${resourceIdentifier} not found or has no href`);
48
+ }
49
+ const href = resource.href || resource.files[0]?.href;
50
+ const file = this.zip.file(href);
51
+ if (!file) {
52
+ throw new Error(`File for resource with identifier ${resourceIdentifier} not found in ZIP in path ${href}`);
53
+ }
54
+ return file.async("string");
55
+ }
31
56
  /**
32
57
  * Add a file directly to the final ZIP, without adding it to the manifest.
33
58
  * Can fetch from URL or add from data.
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ export * from "./ims/ims-manifest";
2
2
  export * from "./ims/ims-package";
3
3
  export * from "./qti/qti-element";
4
4
  export * from "./qti/qti-test";
5
+ export * from "./qti/qti-test-part";
6
+ export * from "./qti/qti-assessment-section";
5
7
  export * from "./qti/qti-item";
6
8
  export * from "./qti/interactions";
7
9
  export * from "./qti/types";
package/dist/index.js CHANGED
@@ -18,6 +18,8 @@ __exportStar(require("./ims/ims-manifest"), exports);
18
18
  __exportStar(require("./ims/ims-package"), exports);
19
19
  __exportStar(require("./qti/qti-element"), exports);
20
20
  __exportStar(require("./qti/qti-test"), exports);
21
+ __exportStar(require("./qti/qti-test-part"), exports);
22
+ __exportStar(require("./qti/qti-assessment-section"), exports);
21
23
  __exportStar(require("./qti/qti-item"), exports);
22
24
  __exportStar(require("./qti/interactions"), exports);
23
25
  __exportStar(require("./qti/types"), exports);
@@ -1,3 +1,4 @@
1
+ import { XMLBuilder } from "xmlbuilder2/lib/interfaces";
1
2
  import { QtiPromptInteraction, QtiPromptInteractionOptions } from "./interaction";
2
3
  export type SimpleAssociableChoiceOptions = {
3
4
  identifier: string;
@@ -32,5 +33,12 @@ export type AssociateInteractionOptions = QtiPromptInteractionOptions & {
32
33
  * });
33
34
  */
34
35
  export declare class AssociateInteraction extends QtiPromptInteraction {
36
+ static tagName: string;
37
+ shuffle?: boolean;
38
+ minAssociations?: number;
39
+ maxAssociations?: number;
40
+ choices?: SimpleAssociableChoiceOptions[];
35
41
  constructor(options: AssociateInteractionOptions);
42
+ static fromXmlString(xml: string): AssociateInteraction;
43
+ protected buildXmlPayload(): XMLBuilder;
36
44
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AssociateInteraction = void 0;
4
+ const cheerio_1 = require("cheerio");
4
5
  const xmlbuilder2_1 = require("xmlbuilder2");
5
6
  const interaction_1 = require("./interaction");
6
7
  const html_1 = require("../../utils/html");
@@ -22,17 +23,61 @@ const html_1 = require("../../utils/html");
22
23
  * });
23
24
  */
24
25
  class AssociateInteraction extends interaction_1.QtiPromptInteraction {
26
+ static tagName = "qti-associate-interaction";
27
+ shuffle;
28
+ minAssociations;
29
+ maxAssociations;
30
+ choices;
25
31
  constructor(options) {
26
32
  super(options);
27
- this.item = (0, xmlbuilder2_1.fragment)().ele("qti-associate-interaction", {
28
- "response-identifier": options.responseIdentifier,
29
- label: options.label,
30
- shuffle: options.shuffle ? "true" : "false",
31
- "min-associations": options.minAssociations?.toString(),
32
- "max-associations": options.maxAssociations?.toString(),
33
+ this.shuffle = options.shuffle;
34
+ this.minAssociations = options.minAssociations;
35
+ this.maxAssociations = options.maxAssociations;
36
+ this.choices = options.choices;
37
+ }
38
+ static fromXmlString(xml) {
39
+ const choices = [];
40
+ const $ = (0, cheerio_1.load)(xml, { xmlMode: true });
41
+ const $root = $("qti-associate-interaction");
42
+ $("qti-simple-associable-choice").each((_, node) => {
43
+ const choice = $(node);
44
+ choices.push({
45
+ identifier: choice.attr("identifier"),
46
+ matchMax: choice.attr("match-max")
47
+ ? Number(choice.attr("match-max"))
48
+ : undefined,
49
+ matchMin: choice.attr("match-min")
50
+ ? Number(choice.attr("match-min"))
51
+ : undefined,
52
+ matchGroup: choice.attr("match-group"),
53
+ fixed: choice.attr("fixed") === "true",
54
+ templateIdentifier: choice.attr("template-identifier"),
55
+ content: (choice.html() || "").trim(),
56
+ });
57
+ });
58
+ return new AssociateInteraction({
59
+ responseIdentifier: $root.attr("response-identifier"),
60
+ label: $root.attr("label"),
61
+ shuffle: $root.attr("shuffle") === "true",
62
+ minAssociations: $root.attr("min-associations")
63
+ ? Number($root.attr("min-associations"))
64
+ : undefined,
65
+ maxAssociations: $root.attr("max-associations")
66
+ ? Number($root.attr("max-associations"))
67
+ : undefined,
68
+ choices,
69
+ });
70
+ }
71
+ buildXmlPayload() {
72
+ const item = (0, xmlbuilder2_1.fragment)().ele("qti-associate-interaction", {
73
+ "response-identifier": this.responseIdentifier,
74
+ label: this.label,
75
+ shuffle: this.shuffle ? "true" : "false",
76
+ "min-associations": this.minAssociations?.toString(),
77
+ "max-associations": this.maxAssociations?.toString(),
33
78
  });
34
- for (const choice of options.choices || []) {
35
- const choiceEl = this.item.ele("qti-simple-associable-choice", {
79
+ for (const choice of this.choices || []) {
80
+ const choiceEl = item.ele("qti-simple-associable-choice", {
36
81
  identifier: choice.identifier,
37
82
  "match-max": choice.matchMax?.toString(),
38
83
  "match-min": choice.matchMin?.toString(),
@@ -44,6 +89,7 @@ class AssociateInteraction extends interaction_1.QtiPromptInteraction {
44
89
  (0, html_1.appendHtmlFragment)(choice.content, choiceEl);
45
90
  }
46
91
  }
92
+ return item;
47
93
  }
48
94
  }
49
95
  exports.AssociateInteraction = AssociateInteraction;
@@ -1,3 +1,4 @@
1
+ import { XMLBuilder } from "xmlbuilder2/lib/interfaces";
1
2
  import { QtiPromptInteraction, QtiPromptInteractionOptions } from "./interaction";
2
3
  export type SimpleChoiceOptions = {
3
4
  identifier: string;
@@ -32,5 +33,15 @@ export type ChoiceInteractionOptions = QtiPromptInteractionOptions & {
32
33
  * });
33
34
  */
34
35
  export declare class ChoiceInteraction extends QtiPromptInteraction {
36
+ static tagName: string;
37
+ choices?: SimpleChoiceOptions[];
38
+ shuffle?: boolean;
39
+ maxChoices?: number;
40
+ minChoices?: number;
41
+ orientation?: "horizontal" | "vertical";
42
+ minSelectionsMessage?: string;
43
+ maxSelectionsMessage?: string;
35
44
  constructor(options: ChoiceInteractionOptions);
45
+ static fromXmlString(xml: string): ChoiceInteraction;
46
+ protected buildXmlPayload(): XMLBuilder;
36
47
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ChoiceInteraction = void 0;
4
+ const cheerio_1 = require("cheerio");
4
5
  const xmlbuilder2_1 = require("xmlbuilder2");
5
6
  const interaction_1 = require("./interaction");
6
7
  const html_1 = require("../../utils/html");
@@ -21,26 +22,74 @@ const html_1 = require("../../utils/html");
21
22
  * });
22
23
  */
23
24
  class ChoiceInteraction extends interaction_1.QtiPromptInteraction {
25
+ static tagName = "qti-choice-interaction";
26
+ choices;
27
+ shuffle;
28
+ maxChoices;
29
+ minChoices;
30
+ orientation;
31
+ minSelectionsMessage;
32
+ maxSelectionsMessage;
24
33
  constructor(options) {
25
34
  super(options);
26
- this.item = (0, xmlbuilder2_1.fragment)().ele("qti-choice-interaction", {
27
- "response-identifier": options.responseIdentifier,
28
- label: options.label,
29
- shuffle: options.shuffle ? "true" : "false",
30
- "max-choices": options.maxChoices?.toString(),
31
- "min-choices": options.minChoices?.toString(),
32
- orientation: options.orientation,
33
- "data-min-selections-message": options.minSelectionsMessage,
34
- "data-max-selections-message": options.maxSelectionsMessage,
35
+ this.shuffle = options.shuffle;
36
+ this.maxChoices = options.maxChoices;
37
+ this.minChoices = options.minChoices;
38
+ this.orientation = options.orientation;
39
+ this.minSelectionsMessage = options.minSelectionsMessage;
40
+ this.maxSelectionsMessage = options.maxSelectionsMessage;
41
+ this.choices = options.choices;
42
+ }
43
+ static fromXmlString(xml) {
44
+ const choices = [];
45
+ const $ = (0, cheerio_1.load)(xml, { xmlMode: true });
46
+ const $root = $("qti-choice-interaction");
47
+ $("qti-simple-choice").each((_, node) => {
48
+ const choice = $(node);
49
+ choices.push({
50
+ identifier: choice.attr("identifier"),
51
+ fixed: choice.attr("fixed") === "true",
52
+ templateIdentifier: choice.attr("template-identifier"),
53
+ label: choice.attr("label"),
54
+ content: (choice.html() || "").trim(),
55
+ });
56
+ });
57
+ return new ChoiceInteraction({
58
+ responseIdentifier: $root.attr("response-identifier"),
59
+ label: $root.attr("label"),
60
+ shuffle: $root.attr("shuffle") === "true",
61
+ minChoices: $root.attr("min-choices")
62
+ ? Number($root.attr("min-choices"))
63
+ : undefined,
64
+ maxChoices: $root.attr("max-choices")
65
+ ? Number($root.attr("max-choices"))
66
+ : undefined,
67
+ orientation: $root.attr("orientation"),
68
+ minSelectionsMessage: $root.attr("data-min-selections-message"),
69
+ maxSelectionsMessage: $root.attr("data-max-selections-message"),
70
+ choices,
71
+ });
72
+ }
73
+ buildXmlPayload() {
74
+ const item = (0, xmlbuilder2_1.fragment)().ele("qti-choice-interaction", {
75
+ "response-identifier": this.responseIdentifier,
76
+ label: this.label,
77
+ shuffle: this.shuffle ? "true" : "false",
78
+ "max-choices": this.maxChoices?.toString(),
79
+ "min-choices": this.minChoices?.toString(),
80
+ orientation: this.orientation,
81
+ "data-min-selections-message": this.minSelectionsMessage,
82
+ "data-max-selections-message": this.maxSelectionsMessage,
35
83
  });
36
- for (const choice of options.choices || []) {
37
- (0, html_1.appendHtmlFragment)(choice.content || "", this.item.ele("qti-simple-choice", {
84
+ for (const choice of this.choices || []) {
85
+ (0, html_1.appendHtmlFragment)(choice.content || "", item.ele("qti-simple-choice", {
38
86
  identifier: choice.identifier,
39
87
  fixed: choice.fixed ? "true" : "false",
40
88
  "template-identifier": choice.templateIdentifier,
41
89
  label: choice.label,
42
90
  }));
43
91
  }
92
+ return item;
44
93
  }
45
94
  }
46
95
  exports.ChoiceInteraction = ChoiceInteraction;
@@ -1,3 +1,4 @@
1
+ import { XMLBuilder } from "xmlbuilder2/lib/interfaces";
1
2
  import { QtiPromptInteraction, QtiPromptInteractionOptions } from "./interaction";
2
3
  export type DrawingObjectOptions = {
3
4
  data: string;
@@ -21,5 +22,9 @@ export type DrawingInteractionOptions = QtiPromptInteractionOptions & {
21
22
  * });
22
23
  */
23
24
  export declare class DrawingInteraction extends QtiPromptInteraction {
25
+ static tagName: string;
26
+ object: DrawingObjectOptions;
24
27
  constructor(options: DrawingInteractionOptions);
28
+ static fromXmlString(xml: string): DrawingInteraction;
29
+ protected buildXmlPayload(): XMLBuilder;
25
30
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DrawingInteraction = void 0;
4
+ const cheerio_1 = require("cheerio");
4
5
  const xmlbuilder2_1 = require("xmlbuilder2");
5
6
  const interaction_1 = require("./interaction");
6
7
  /**
@@ -16,18 +17,43 @@ const interaction_1 = require("./interaction");
16
17
  * });
17
18
  */
18
19
  class DrawingInteraction extends interaction_1.QtiPromptInteraction {
20
+ static tagName = "qti-drawing-interaction";
21
+ object;
19
22
  constructor(options) {
20
23
  super(options);
21
- this.item = (0, xmlbuilder2_1.fragment)().ele("qti-drawing-interaction", {
22
- "response-identifier": options.responseIdentifier,
23
- label: options.label,
24
+ this.object = options.object;
25
+ }
26
+ static fromXmlString(xml) {
27
+ const $ = (0, cheerio_1.load)(xml, { xmlMode: true });
28
+ const $root = $("qti-drawing-interaction");
29
+ const $object = $root.find("object");
30
+ return new DrawingInteraction({
31
+ responseIdentifier: $root.attr("response-identifier"),
32
+ label: $root.attr("label"),
33
+ object: {
34
+ data: $object.attr("data"),
35
+ type: $object.attr("type"),
36
+ width: $object.attr("width")
37
+ ? Number($object.attr("width"))
38
+ : undefined,
39
+ height: $object.attr("height")
40
+ ? Number($object.attr("height"))
41
+ : undefined,
42
+ },
43
+ });
44
+ }
45
+ buildXmlPayload() {
46
+ const item = (0, xmlbuilder2_1.fragment)().ele("qti-drawing-interaction", {
47
+ "response-identifier": this.responseIdentifier,
48
+ label: this.label,
24
49
  });
25
- this.item.ele("object", {
26
- data: options.object.data,
27
- type: options.object.type,
28
- width: options.object.width?.toString(),
29
- height: options.object.height?.toString(),
50
+ item.ele("object", {
51
+ data: this.object.data,
52
+ type: this.object.type,
53
+ width: this.object.width?.toString(),
54
+ height: this.object.height?.toString(),
30
55
  });
56
+ return item;
31
57
  }
32
58
  }
33
59
  exports.DrawingInteraction = DrawingInteraction;
@@ -1,3 +1,4 @@
1
+ import { XMLBuilder } from "xmlbuilder2/lib/interfaces";
1
2
  import { QtiInteraction, QtiInteractionOptions } from "./interaction";
2
3
  export type EndAttemptInteractionOptions = QtiInteractionOptions & {
3
4
  title: string;
@@ -17,5 +18,10 @@ export type EndAttemptInteractionOptions = QtiInteractionOptions & {
17
18
  * });
18
19
  */
19
20
  export declare class EndAttemptInteraction extends QtiInteraction {
21
+ static tagName: string;
22
+ title: string;
23
+ countAttempt?: boolean;
20
24
  constructor(options: EndAttemptInteractionOptions);
25
+ static fromXmlString(xml: string): EndAttemptInteraction;
26
+ protected buildXmlPayload(): XMLBuilder;
21
27
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EndAttemptInteraction = void 0;
4
+ const cheerio_1 = require("cheerio");
4
5
  const xmlbuilder2_1 = require("xmlbuilder2");
5
6
  const interaction_1 = require("./interaction");
6
7
  /**
@@ -17,14 +18,32 @@ const interaction_1 = require("./interaction");
17
18
  * });
18
19
  */
19
20
  class EndAttemptInteraction extends interaction_1.QtiInteraction {
21
+ static tagName = "qti-end-attempt-interaction";
22
+ title;
23
+ countAttempt;
20
24
  constructor(options) {
21
25
  super(options);
22
- this.item = (0, xmlbuilder2_1.fragment)().ele("qti-end-attempt-interaction", {
23
- "response-identifier": options.responseIdentifier,
24
- label: options.label,
25
- title: options.title,
26
- "count-attempt": options.countAttempt ? "true" : undefined,
26
+ this.title = options.title;
27
+ this.countAttempt = options.countAttempt;
28
+ }
29
+ static fromXmlString(xml) {
30
+ const $ = (0, cheerio_1.load)(xml, { xmlMode: true });
31
+ const $root = $("qti-end-attempt-interaction");
32
+ return new EndAttemptInteraction({
33
+ responseIdentifier: $root.attr("response-identifier"),
34
+ label: $root.attr("label"),
35
+ title: $root.attr("title"),
36
+ countAttempt: $root.attr("count-attempt") === "true",
37
+ });
38
+ }
39
+ buildXmlPayload() {
40
+ const item = (0, xmlbuilder2_1.fragment)().ele("qti-end-attempt-interaction", {
41
+ "response-identifier": this.responseIdentifier,
42
+ label: this.label,
43
+ title: this.title,
44
+ "count-attempt": this.countAttempt ? "true" : undefined,
27
45
  });
46
+ return item;
28
47
  }
29
48
  }
30
49
  exports.EndAttemptInteraction = EndAttemptInteraction;
@@ -1,3 +1,4 @@
1
+ import { XMLBuilder } from "xmlbuilder2/lib/interfaces";
1
2
  import { QtiPromptInteraction, QtiPromptInteractionOptions } from "./interaction";
2
3
  export type ExtendedTextInteractionOptions = QtiPromptInteractionOptions & {
3
4
  base?: number;
@@ -24,5 +25,17 @@ export type ExtendedTextInteractionOptions = QtiPromptInteractionOptions & {
24
25
  * });
25
26
  */
26
27
  export declare class ExtendedTextInteraction extends QtiPromptInteraction {
28
+ static tagName: string;
29
+ base?: number;
30
+ stringIdentifier?: string;
31
+ expectedLength?: number;
32
+ patternMask?: string;
33
+ placeholderText?: string;
34
+ maxStrings?: number;
35
+ minStrings?: number;
36
+ expectedLines?: number;
37
+ format?: "plain" | "pre-formatted" | "xhtml";
27
38
  constructor(options: ExtendedTextInteractionOptions);
39
+ static fromXmlString(xml: string): ExtendedTextInteraction;
40
+ protected buildXmlPayload(): XMLBuilder;
28
41
  }