@pie-element/charting 13.0.8-next.20261024044430 → 13.0.8-next.20261024053312

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.
@@ -3202,7 +3202,7 @@ var Dr = class e extends CustomEvent {
3202
3202
  }
3203
3203
  }, mi = Object.freeze({
3204
3204
  name: "@pie-element/charting",
3205
- version: "13.0.8-next.20261024044430"
3205
+ version: "13.0.8-next.20261024053312"
3206
3206
  });
3207
3207
  //#endregion
3208
3208
  export { pi as default, mi as piePackage };
@@ -40,29 +40,68 @@ var a = /* @__PURE__ */ e(i(), 1), o = {
40
40
  function l(e, t, n) {
41
41
  return e?.partialScoring === !1 || t?.partialScoring === !1 ? !1 : typeof n != "boolean" || n;
42
42
  }
43
- //#endregion
44
- //#region src/controller/index.ts
45
- var u = (0, a.default)("@pie-element:graphing:controller"), d = (e) => (e || "").toLowerCase(), f = (e, t) => d(e) === d(t), p = (e, t) => e ? e.map((e) => ({
43
+ var u = /[\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069\u0640]/g, d = /[\uFB50-\uFDFF\uFE70-\uFEFC]+/g, f = /\p{Nd}/u, p = /(?![0-9])\p{Nd}/gu, m = /\u066B/g, h = /\u066C/g, g = /[\u0622\u0623\u0625\u0671]/g, _ = /[\u064B-\u065F\u0670]/g, v = /* @__PURE__ */ new Map(), y = (e) => {
44
+ let t = v.get(e);
45
+ if (t !== void 0) return t;
46
+ let n = 0;
47
+ for (; f.test(String.fromCodePoint(e - n - 1));) n++;
48
+ let r = n % 10;
49
+ return v.set(e, r), r;
50
+ }, b = (e) => e.replace(p, (e) => String(y(e.codePointAt(0)))), x = {
51
+ decimal: ".",
52
+ group: ","
53
+ }, S = /* @__PURE__ */ new Map(), C = (e) => {
54
+ if (!e) return x;
55
+ let t = S.get(e);
56
+ if (t) return t;
57
+ let n = x;
58
+ try {
59
+ if (Intl.NumberFormat.supportedLocalesOf(e).length > 0) {
60
+ let t = new Intl.NumberFormat(e, { numberingSystem: "latn" }).formatToParts(12345.6);
61
+ n = {
62
+ decimal: t.find((e) => e.type === "decimal")?.value ?? ".",
63
+ group: t.find((e) => e.type === "group")?.value ?? ","
64
+ };
65
+ }
66
+ } catch {}
67
+ return S.set(e, n), n;
68
+ }, w = (e, t) => {
69
+ let n = [e?.language, t?.locale];
70
+ for (let e of n) if (typeof e == "string" && e.trim()) return e.trim().replace(/_/g, "-");
71
+ }, T = /^(tr|az)(-|$)/i, E = (e, t) => {
72
+ if (!t || !T.test(t)) return e.toLowerCase();
73
+ try {
74
+ return e.toLocaleLowerCase(t);
75
+ } catch {
76
+ return e.toLowerCase();
77
+ }
78
+ }, D = (e, t = {}) => {
79
+ let n = C(t.language), r = (t.ignoreCase ? E(e, t.language) : e).replace(u, "").replace(d, (e) => e.normalize("NFKC")).normalize("NFC");
80
+ return r = b(r).replace(m, n.decimal).replace(h, n.group), t.foldLetterVariants && (r = r.replace(_, "").replace(g, "ا").replace(/\u0629/g, "ه").replace(/\u0649/g, "ي")), r;
81
+ }, O = (0, a.default)("@pie-element:graphing:controller"), k = (e, t) => D(e || "", {
82
+ language: t,
83
+ ignoreCase: !0
84
+ }), A = (e, t, n) => k(e, n) === k(t, n), j = (e, t) => e ? e.map((e) => ({
46
85
  ...e,
47
86
  correctness: {
48
87
  value: t ? "incorrect" : "correct",
49
88
  label: t ? "incorrect" : "correct"
50
89
  }
51
- })) : [], m = (e) => ({
90
+ })) : [], M = (e) => ({
52
91
  ...o,
53
92
  ...e
54
- }), h = (e, t, n = {}) => {
55
- let { correctAnswer: r, data: i = [], scoringType: a } = e, o = [], s = c.enabled({ partialScoring: a === void 0 ? a : a === "partial scoring" }, n), { data: l = [] } = r || {}, u = _(i), m = p(t && t.answer || u, s), h = 0;
56
- if (s) {
93
+ }), N = (e, t, n = {}) => {
94
+ let { correctAnswer: r, data: i = [], scoringType: a } = e, o = [], s = w(e, n), l = c.enabled({ partialScoring: a === void 0 ? a : a === "partial scoring" }, n), { data: u = [] } = r || {}, d = F(i), f = j(t && t.answer || d, l), p = 0;
95
+ if (l) {
57
96
  let e = 0, t = 0, n = (n, r) => {
58
- let { value: i, label: a, index: s } = n, c = i === r.value, l = f(a, r.label);
59
- e += 2, c && (t += 1, n.correctness.value = "correct"), l && (t += 1, n.correctness.label = "correct"), c && l && o.push({
97
+ let { value: i, label: a, index: c } = n, l = i === r.value, u = A(a, r.label, s);
98
+ e += 2, l && (t += 1, n.correctness.value = "correct"), u && (t += 1, n.correctness.label = "correct"), l && u && o.push({
60
99
  label: a,
61
- index: s
100
+ index: c
62
101
  });
63
102
  };
64
- l.forEach((r, i) => {
65
- let a = u[i], s = m[i];
103
+ u.forEach((r, i) => {
104
+ let a = d[i], s = f[i];
66
105
  s ? a ? !a.editable && s.interactive ? (e += 1, s.value === r.value && (t += 1, s.correctness.value = "correct", o.push({
67
106
  label: s.label,
68
107
  index: i
@@ -70,10 +109,10 @@ var u = (0, a.default)("@pie-element:graphing:controller"), d = (e) => (e || "")
70
109
  label: s.label,
71
110
  index: i
72
111
  })) : n(s, r) : e += 2;
73
- }), h = e ? t / e : 0;
74
- } else h = +(l.length === m.length), m = m.map((e, t) => {
75
- let n = l[t], r = n ? e.value === n.value : !1, i = n ? d(e.label) === d(n.label) : !1;
76
- return (!r || !i) && (h = 0), r && i && o.push({
112
+ }), p = e ? t / e : 0;
113
+ } else p = +(u.length === f.length), f = f.map((e, t) => {
114
+ let n = u[t], r = n ? e.value === n.value : !1, i = n ? A(e.label, n.label, s) : !1;
115
+ return (!r || !i) && (p = 0), r && i && o.push({
77
116
  label: e.label,
78
117
  index: t
79
118
  }), {
@@ -84,23 +123,23 @@ var u = (0, a.default)("@pie-element:graphing:controller"), d = (e) => (e || "")
84
123
  }
85
124
  };
86
125
  });
87
- let g = {
88
- score: parseFloat(h.toFixed(2)),
89
- answers: m
126
+ let m = {
127
+ score: parseFloat(p.toFixed(2)),
128
+ answers: f
90
129
  };
91
- return n.extraProps && n.extraProps.correctResponseEnabled && (g.correctResponses = o), g;
92
- }, g = (e, t, n) => {
93
- let r = [], { correctAnswer: i, data: a = [], scoringType: o } = e || {}, { data: s = [] } = i || {}, l = t && t.answer || [], u = c.enabled({ partialScoring: o === void 0 ? o : o === "partial scoring" }, n), d = _(a), p = l.length > 0 ? _(l) : d;
130
+ return n.extraProps && n.extraProps.correctResponseEnabled && (m.correctResponses = o), m;
131
+ }, P = (e, t, n) => {
132
+ let r = [], { correctAnswer: i, data: a = [], scoringType: o } = e || {}, { data: s = [] } = i || {}, l = t && t.answer || [], u = w(e, n), d = c.enabled({ partialScoring: o === void 0 ? o : o === "partial scoring" }, n), f = F(a), p = l.length > 0 ? F(l) : f;
94
133
  if (l.length || r.push("Student did not modify the chart. Initial chart is scored."), s.forEach((e, t) => {
95
- let n = d[t], i = p[t];
134
+ let n = f[t], i = p[t];
96
135
  if (!i) {
97
136
  r.push(`Category ${t + 1}: missing (expected value '${e.value}', label '${e.label}').`);
98
137
  return;
99
138
  }
100
- let a = i.value === e.value, o = f(i.label, e.label);
139
+ let a = i.value === e.value, o = A(i.label, e.label, u);
101
140
  if (!i.interactive) r.push(`Category ${t + 1}: non-interactive category treated as correct.`);
102
141
  else if (l.length > 0) {
103
- let e = !n || i.value !== n.value, s = !n || !f(i.label, n.label);
142
+ let e = !n || i.value !== n.value, s = !n || !A(i.label, n.label, u);
104
143
  if (!e && !s) {
105
144
  a && o ? r.push(`Category ${t + 1}: unchanged from initial value and correct.`) : r.push(`Category ${t + 1}: unchanged from initial value but incorrect.`);
106
145
  return;
@@ -112,22 +151,22 @@ var u = (0, a.default)("@pie-element:graphing:controller"), d = (e) => (e || "")
112
151
  let e = p.length - s.length;
113
152
  r.push(`${e} extra category(ies) provided beyond expected number.`);
114
153
  }
115
- u ? (r.push("Score calculated using partial scoring."), r.push("Student receives credit for each correct value and label independently.")) : (r.push("Score calculated using all-or-nothing scoring."), r.push("Student must match all category values and labels exactly for full credit."));
116
- let m = h(e, t, n);
154
+ d ? (r.push("Score calculated using partial scoring."), r.push("Student receives credit for each correct value and label independently.")) : (r.push("Score calculated using all-or-nothing scoring."), r.push("Student must match all category values and labels exactly for full credit."));
155
+ let m = N(e, t, n);
117
156
  return r.push(`Score: ${m.score}.`), r;
118
- }, _ = (e) => e ? e.map(({ deletable: e, ...t }) => t) : [];
119
- function v(e, t, n) {
157
+ }, F = (e) => e ? e.map(({ deletable: e, ...t }) => t) : [];
158
+ function I(e, t, n) {
120
159
  return new Promise((r) => {
121
- let i = m(e), { addCategoryEnabled: a, chartType: o, data: s, domain: c, graph: l, prompt: d, promptEnabled: f, range: p, rationale: g, title: v, rationaleEnabled: y, teacherInstructions: b, teacherInstructionsEnabled: x, correctAnswer: S, scoringType: C, studentNewCategoryDefaultLabel: w, language: T, extraCSSRules: E } = i, D = {
160
+ let i = M(e), { addCategoryEnabled: a, chartType: o, data: s, domain: c, graph: l, prompt: u, promptEnabled: d, range: f, rationale: p, title: m, rationaleEnabled: h, teacherInstructions: g, teacherInstructionsEnabled: _, correctAnswer: v, scoringType: y, studentNewCategoryDefaultLabel: b, language: x, extraCSSRules: S } = i, C = {
122
161
  addCategoryEnabled: a,
123
162
  chartType: o,
124
- data: _(s),
163
+ data: F(s),
125
164
  domain: c,
126
165
  graph: l,
127
- prompt: f ? d : null,
128
- range: p,
129
- rationale: g,
130
- title: v,
166
+ prompt: d ? u : null,
167
+ range: f,
168
+ rationale: p,
169
+ title: m,
131
170
  size: l,
132
171
  showToggle: !1,
133
172
  correctness: {
@@ -135,21 +174,21 @@ function v(e, t, n) {
135
174
  score: "0%"
136
175
  },
137
176
  disabled: n.mode !== "gather",
138
- scoringType: C,
139
- studentNewCategoryDefaultLabel: w,
140
- language: T,
177
+ scoringType: y,
178
+ studentNewCategoryDefaultLabel: b,
179
+ language: x,
141
180
  env: n,
142
- extraCSSRules: E
143
- }, O = h(i, t, n), k = _(O.answers);
144
- n.mode === "view" && (D.correctedAnswer = k.map(({ correctness: e, ...t }) => ({
181
+ extraCSSRules: S
182
+ }, w = N(i, t, n), T = F(w.answers);
183
+ n.mode === "view" && (C.correctedAnswer = T.map(({ correctness: e, ...t }) => ({
145
184
  ...t,
146
185
  interactive: !1
147
- })), D.addCategoryEnabled = !1), n.mode === "evaluate" && (D.correctedAnswer = k, D.correctAnswer = S, D.showToggle = !!S?.data?.length && O.score !== 1, D.addCategoryEnabled = !1, D.showKeyLegend = !0), n.role === "instructor" && (n.mode === "view" || n.mode === "evaluate") ? (D.rationale = y ? g : null, D.teacherInstructions = x ? b : null) : (D.rationale = null, D.teacherInstructions = null), u("base: ", D), r(D);
186
+ })), C.addCategoryEnabled = !1), n.mode === "evaluate" && (C.correctedAnswer = T, C.correctAnswer = v, C.showToggle = !!v?.data?.length && w.score !== 1, C.addCategoryEnabled = !1, C.showKeyLegend = !0), n.role === "instructor" && (n.mode === "view" || n.mode === "evaluate") ? (C.rationale = h ? p : null, C.teacherInstructions = _ ? g : null) : (C.rationale = null, C.teacherInstructions = null), O("base: ", C), r(C);
148
187
  });
149
188
  }
150
- function y(e, t, n) {
189
+ function L(e, t, n) {
151
190
  return new Promise((i) => {
152
- let a = g(e, t, n), o = h(e, t, n), s = {
191
+ let a = P(e, t, n), o = N(e, t, n), s = {
153
192
  score: o.score,
154
193
  empty: !t || r(t),
155
194
  traceLog: a
@@ -157,7 +196,7 @@ function y(e, t, n) {
157
196
  n.extraProps && n.extraProps.correctResponseEnabled && (s.extraProps = { correctResponse: o.correctResponses }), i(s);
158
197
  });
159
198
  }
160
- var b = (e, t) => new Promise((n) => {
199
+ var R = (e, t) => new Promise((n) => {
161
200
  if (t.mode !== "evaluate" && t.role === "instructor") {
162
201
  let { correctAnswer: r } = e, i = r && r.data;
163
202
  if (t.mode === "gather") {
@@ -172,23 +211,23 @@ var b = (e, t) => new Promise((n) => {
172
211
  id: "1"
173
212
  });
174
213
  } else return n(null);
175
- }), x = (e) => (e || "").replaceAll(/<[^>]*>/g, ""), S = (e) => (e || "").replace(/(<(?!img|iframe|source)([^>]+)>)/gi, ""), C = (e = {}, i = {}) => {
214
+ }), z = (e) => (e || "").replaceAll(/<[^>]*>/g, ""), B = (e) => (e || "").replace(/(<(?!img|iframe|source)([^>]+)>)/gi, ""), V = (e = {}, i = {}) => {
176
215
  let { correctAnswer: a, data: o } = e || {}, { data: s } = a || {}, c = s || [], l = {}, u = {}, d = {};
177
216
  return [
178
217
  "teacherInstructions",
179
218
  "prompt",
180
219
  "rationale"
181
220
  ].forEach((t) => {
182
- i[t]?.required && !S(e[t]) && (l[t] = "This field is required.");
221
+ i[t]?.required && !B(e[t]) && (l[t] = "This field is required.");
183
222
  }), c.forEach((e, t) => {
184
223
  let { label: n } = e;
185
- x(n) ? c.some((e, r) => e.label === n && t !== r) && (d[t] = "Category names should be unique. ") : d[t] = "Content should not be empty. ";
224
+ z(n) ? c.some((e, r) => e.label === n && t !== r) && (d[t] = "Category names should be unique. ") : d[t] = "Content should not be empty. ";
186
225
  }), c.length < 1 || c.length > 20 ? u.categoriesError = "The correct answer should include between 1 and 20 categories." : t(o.map((e) => n(e, "value", "label")), s.map((e) => n(e, "value", "label"))) && (u.identicalError = "Correct answer should not be identical to the chart’s initial state"), r(d) || (l.categoryErrors = d), r(u) || (l.correctAnswerErrors = u), l;
187
- }, w = Object.freeze({
226
+ }, H = Object.freeze({
188
227
  name: "@pie-element/charting",
189
- version: "13.0.8-next.20261024044430"
228
+ version: "13.0.8-next.20261024053312"
190
229
  });
191
230
  //#endregion
192
- export { f as checkLabelsEquality, b as createCorrectResponseSession, _ as filterCategories, g as getLogTrace, h as getScore, v as model, m as normalize, y as outcome, w as piePackage, p as setCorrectness, C as validate };
231
+ export { A as checkLabelsEquality, R as createCorrectResponseSession, F as filterCategories, P as getLogTrace, N as getScore, I as model, M as normalize, L as outcome, H as piePackage, j as setCorrectness, V as validate };
193
232
 
194
233
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["debug","defaults","partialScoring","isEmpty","isEqual","pick","__toESM","wn","Vn","Cn","require_browser","import_browser","defaults_default","e","s","r","i","t","n","c","log","lowerCase","string","checkLabelsEquality","givenAnswerLabel","correctAnswerLabel","setCorrectness","answers","answer","partialScoring","normalize","question","getScore","initialData","correctResponses","isPartialScoring","scoringType","env","correctAnswers","correctAnswer","defaultAnswers","filterCategories","session","result","maxScore","score","scoreForLabelAndValueEditable","valueIsCorrect","value","corrAnswer","labelIsCorrect","label","defaultAnswer","index","getLogTrace","traceLog","model","studentAnswers","initial","student","correct","valueCorrect","labelCorrect","valueChanged","labelChanged","parts","extra","scoreObject","categories","rest","normalizedQuestion","base","data","promptEnabled","prompt","graph","rationaleEnabled","rationale","teacherInstructionsEnabled","teacherInstructions","resolve","outcome","createCorrectResponseSession","getInnerText","html","getContent","validate","correctData","errors","correctAnswerErrors","categoryErrors","config","field","category","piePackage","\"name\"","\"version\""],"sources":["../../../src/controller/defaults.ts","../../../../../shared/controller-utils/dist/index.js","../../../src/controller/index.ts"],"sourcesContent":["import type { ChartingCategory, ChartingCorrectAnswer, ChartingDomain, ChartingModel } from '../types.js';\n\n/**\n * NOTE: There's no functionality described for graphTitle,\n * rationale, scoringType, studentInstructions, teacherInstructions\n * so there's no implementation (they are only added in model)\n */\n\nexport default {\n addCategoryEnabled: true,\n changeAddCategoryEnabled: false,\n changeEditableEnabled: false,\n changeInteractiveEnabled: false,\n chartType: 'lineCross',\n correctAnswer: {} as ChartingCorrectAnswer,\n data: [] as ChartingCategory[],\n domain: {} as ChartingDomain,\n graph: { width: 480, height: 480 },\n prompt: '',\n promptEnabled: true,\n range: { label: '', max: 1, min: 0, labelStep: 1 },\n rationale: '',\n rationaleEnabled: true,\n scoringType: 'all or nothing',\n studentInstructionsEnabled: true,\n studentNewCategoryDefaultLabel: 'New Category',\n teacherInstructions: '',\n teacherInstructionsEnabled: true,\n title: '',\n} satisfies Omit<ChartingModel, 'id' | 'element'>;\n","//#region \\0rolldown/runtime.js\nvar e = Object.defineProperty, t = (t, n) => {\n\tlet r = {};\n\tfor (var i in t) e(r, i, {\n\t\tget: t[i],\n\t\tenumerable: !0\n\t});\n\treturn n || e(r, Symbol.toStringTag, { value: \"Module\" }), r;\n};\n//#endregion\n//#region src/persistence.ts\nfunction n(e) {\n\treturn Array.isArray(e) ? e.filter((e) => e != null) : [];\n}\nfunction r(e) {\n\tlet t = [...e];\n\tfor (let e = t.length - 1; e > 0; e--) {\n\t\tlet n = Math.floor(Math.random() * (e + 1));\n\t\t[t[e], t[n]] = [t[n], t[e]];\n\t}\n\treturn t;\n}\nfunction i(e) {\n\treturn e == null ? !0 : Array.isArray(e) ? e.length === 0 : typeof e == \"object\" && Object.keys(e).length === 0;\n}\nasync function a(e, t, a, o = \"value\") {\n\tlet s = n(t?.data?.shuffledValues ?? t?.shuffledValues ?? []);\n\tif (!t) {\n\t\tconsole.warn(\"Unable to save shuffled choices because there's no session.\");\n\t\treturn;\n\t}\n\tif (!i(s)) return n(s.map((t) => e.find((e) => e[o] === t)));\n\tlet c = r(e);\n\tif (a && typeof a == \"function\") try {\n\t\tlet e = n(c.map((e) => e[o]));\n\t\ti(e) ? console.error(`shuffledValues is an empty array - refusing to call updateSession. shuffledChoices: ${JSON.stringify(c)}, key: ${o}`) : await a(t.id, t.element, { shuffledValues: e });\n\t} catch (e) {\n\t\tconsole.warn(\"Unable to save shuffled order for choices\"), console.error(e);\n\t}\n\telse console.warn(\"Unable to save shuffled choices, shuffle will happen every time.\");\n\treturn c;\n}\nfunction o(e, t, n) {\n\treturn !!(e.lockChoiceOrder || n?.[\"@pie-element\"]?.lockChoiceOrder);\n}\n//#endregion\n//#region src/partial-scoring.ts\nvar s = /* @__PURE__ */ t({ enabled: () => c });\nfunction c(e, t, n) {\n\treturn e?.partialScoring === !1 || t?.partialScoring === !1 ? !1 : typeof n != \"boolean\" || n;\n}\n//#endregion\nexport { a as getShuffledChoices, o as lockChoices, s as partialScoring };\n","import debug from 'debug';\nimport { isEmpty, isEqual, pick } from '@pie-element/shared-lodash';\nimport type { ExtraCSSRules, PieEnvironment } from '@pie-element/shared-types';\nimport defaults from './defaults.js';\n\nimport { partialScoring } from '@pie-element/shared-controller-utils';\nimport type {\n ChartingCategory,\n ChartingCategoryCorrectness,\n ChartingConfiguration,\n ChartingCorrectAnswer,\n ChartingModel,\n ChartingSession,\n} from '../types.js';\n\n/** The environment, plus the extra properties a host may ask the outcome for */\nexport type ChartingEnvironment = PieEnvironment & { extraProps?: { correctResponseEnabled?: boolean } };\n\n/** A category marked correct or incorrect */\nexport type ScoredCategory = ChartingCategory & { correctness: ChartingCategoryCorrectness };\n\n/** A category whose value and label both match the correct answer */\nexport type ChartingCorrectResponse = { label: string; index?: number };\n\nexport type ChartingScore = {\n score: number;\n answers: ScoredCategory[];\n correctResponses?: ChartingCorrectResponse[];\n};\n\nexport type ChartingValidationErrors = {\n teacherInstructions?: string;\n prompt?: string;\n rationale?: string;\n /** Category errors of the correct answer, keyed by category position */\n categoryErrors?: Record<number, string>;\n correctAnswerErrors?: {\n categoriesError?: string;\n identicalError?: string;\n };\n};\n\n/** What `model()` returns for the delivery view */\nexport type ChartingViewModel = {\n addCategoryEnabled?: boolean;\n chartType?: ChartingModel['chartType'];\n data: Omit<ChartingCategory, 'deletable'>[];\n domain?: ChartingModel['domain'];\n graph?: ChartingModel['graph'];\n prompt?: string | null;\n range?: ChartingModel['range'];\n rationale?: string | null;\n title?: string;\n size?: ChartingModel['graph'];\n showToggle: boolean;\n correctness: { correctness: string; score: string };\n disabled: boolean;\n scoringType?: ChartingModel['scoringType'];\n studentNewCategoryDefaultLabel?: string;\n language?: string;\n env: ChartingEnvironment;\n extraCSSRules?: ExtraCSSRules;\n correctedAnswer?: Omit<ChartingCategory, 'deletable'>[];\n correctAnswer?: ChartingCorrectAnswer;\n showKeyLegend?: boolean;\n teacherInstructions?: string | null;\n};\n\ntype ChartingOutcome = {\n score: number;\n empty: boolean;\n traceLog: string[];\n extraProps?: { correctResponse?: ChartingCorrectResponse[] };\n};\n\nconst log = debug('@pie-element:graphing:controller');\n\nconst lowerCase = (string?: string) => (string || '').toLowerCase();\n\nexport const checkLabelsEquality = (givenAnswerLabel?: string, correctAnswerLabel?: string) =>\n lowerCase(givenAnswerLabel) === lowerCase(correctAnswerLabel);\n\nexport const setCorrectness = (answers: ChartingCategory[] | undefined, partialScoring: boolean): ScoredCategory[] =>\n answers\n ? answers.map((answer) => ({\n ...answer,\n correctness: {\n value: partialScoring ? 'incorrect' : 'correct',\n label: partialScoring ? 'incorrect' : 'correct',\n },\n }))\n : [];\n\nexport const normalize = (question: ChartingModel) => ({ ...defaults, ...question });\n\nexport const getScore = (\n question: ChartingModel,\n session: ChartingSession | null | undefined,\n env: Partial<ChartingEnvironment> = {},\n): ChartingScore => {\n const { correctAnswer, data: initialData = [], scoringType } = question;\n const correctResponses: ChartingCorrectResponse[] = [];\n\n const isPartialScoring = partialScoring.enabled(\n { partialScoring: scoringType !== undefined ? scoringType === 'partial scoring' : scoringType },\n env,\n );\n\n const { data: correctAnswers = [] } = correctAnswer || {};\n const defaultAnswers = filterCategories(initialData);\n\n let answers = setCorrectness((session && session.answer) || defaultAnswers, isPartialScoring);\n\n let result = 0;\n\n if (isPartialScoring) {\n // if score type is \"partial scoring\"\n // maxScore is calculated based on the correct response\n // score is calculated based on the given response\n let maxScore = 0;\n let score = 0;\n\n const scoreForLabelAndValueEditable = (answer: ScoredCategory, corrAnswer: ChartingCategory) => {\n const { value, label, index } = answer;\n const valueIsCorrect = value === corrAnswer.value;\n const labelIsCorrect = checkLabelsEquality(label, corrAnswer.label);\n maxScore += 2;\n\n if (valueIsCorrect) {\n score += 1;\n answer.correctness.value = 'correct';\n }\n\n if (labelIsCorrect) {\n score += 1;\n answer.correctness.label = 'correct';\n }\n\n if (valueIsCorrect && labelIsCorrect) {\n correctResponses.push({ label: label, index: index });\n }\n };\n\n // if given answer has more categories than the correct answers, the \"extra\" will be ignored\n correctAnswers.forEach((corrAnswer, index) => {\n const defaultAnswer = defaultAnswers[index];\n const answer = answers[index];\n\n // if there is a corresponding category at the same position in the given answer\n if (answer) {\n // if there is a corresponding category at the same position in the default answer\n if (defaultAnswer) {\n // if category's label (in default answer) was not editable\n // it means that this category values only one point (only the value can be changed)\n if (!defaultAnswer.editable && answer.interactive) {\n maxScore += 1;\n\n if (answer.value === corrAnswer.value) {\n score += 1;\n answer.correctness.value = 'correct';\n correctResponses.push({ label: answer.label, index: index });\n }\n answer.correctness.label = 'correct';\n\n // if category's label (in default answer) was editable\n // it means that this category values 2 points (both label and value can be changed)\n } else if (defaultAnswer.editable && answer.interactive) {\n scoreForLabelAndValueEditable(answer, corrAnswer);\n } else if (!answer.interactive) {\n answer.correctness.value = 'correct';\n answer.correctness.label = 'correct';\n correctResponses.push({ label: answer.label, index: index });\n }\n } else {\n // if there is not a corresponding category at the same position in the default answer\n scoreForLabelAndValueEditable(answer, corrAnswer);\n }\n } else {\n // if there is not a corresponding category at the same position in the given answer\n // it means that the given answer has less categories than the correct answer\n maxScore += 2;\n }\n });\n\n result = maxScore ? score / maxScore : 0;\n } else {\n // all-or-nothing scoring: overall score is 1 only if lengths and all values/labels match\n result = correctAnswers.length === answers.length ? 1 : 0;\n\n // regardless of overall result, mark each answer individually for user feedback\n answers = answers.map((answer, index): ScoredCategory => {\n const correctAnswer = correctAnswers[index];\n const valueIsCorrect = correctAnswer ? answer.value === correctAnswer.value : false;\n const labelIsCorrect = correctAnswer ? lowerCase(answer.label) === lowerCase(correctAnswer.label) : false;\n\n if (!valueIsCorrect || !labelIsCorrect) {\n result = 0;\n }\n\n if (valueIsCorrect && labelIsCorrect) {\n correctResponses.push({ label: answer.label, index });\n }\n\n return {\n ...answer,\n correctness: {\n value: valueIsCorrect ? 'correct' : 'incorrect',\n label: labelIsCorrect ? 'correct' : 'incorrect',\n },\n };\n });\n }\n\n const score: ChartingScore = {\n score: parseFloat(result.toFixed(2)),\n answers,\n };\n\n if (env.extraProps && env.extraProps.correctResponseEnabled) {\n score.correctResponses = correctResponses;\n }\n\n return score;\n};\n\n/**\n * Generates detailed trace log for scoring evaluation\n * @param {Object} model - the question model\n * @param {Object} session - the student session\n * @param {Object} env - the environment\n * @returns {Array} traceLog - array of trace messages\n */\nexport const getLogTrace = (\n model: ChartingModel,\n session: ChartingSession | null | undefined,\n env: ChartingEnvironment,\n): string[] => {\n const traceLog: string[] = [];\n\n const { correctAnswer, data: initialData = [], scoringType } = model || {};\n const { data: correctAnswers = [] } = correctAnswer || {};\n const studentAnswers = (session && session.answer) || [];\n\n const isPartialScoring = partialScoring.enabled(\n { partialScoring: scoringType !== undefined ? scoringType === 'partial scoring' : scoringType },\n env\n );\n\n const defaultAnswers = filterCategories(initialData);\n const answers = studentAnswers.length > 0 ? filterCategories(studentAnswers) : defaultAnswers;\n\n if (!studentAnswers.length) {\n traceLog.push(`Student did not modify the chart. Initial chart is scored.`);\n }\n\n correctAnswers.forEach((correct, index) => {\n const initial = defaultAnswers[index];\n const student = answers[index];\n\n if (!student) {\n traceLog.push(`Category ${index + 1}: missing (expected value '${correct.value}', label '${correct.label}').`);\n return;\n }\n\n const valueCorrect = student.value === correct.value;\n const labelCorrect = checkLabelsEquality(student.label, correct.label);\n\n if (!student.interactive) {\n traceLog.push(`Category ${index + 1}: non-interactive category treated as correct.`);\n return;\n }\n\n if (studentAnswers.length > 0) {\n const valueChanged = initial ? student.value !== initial.value : true;\n const labelChanged = initial ? !checkLabelsEquality(student.label, initial.label) : true;\n\n if (!valueChanged && !labelChanged) {\n if (valueCorrect && labelCorrect) {\n traceLog.push(`Category ${index + 1}: unchanged from initial value and correct.`);\n } else {\n traceLog.push(`Category ${index + 1}: unchanged from initial value but incorrect.`);\n }\n return;\n }\n\n const parts: string[] = [];\n if (valueChanged) {\n parts.push(`value ${valueCorrect ? 'correct' : 'incorrect'}`);\n }\n if (labelChanged) {\n parts.push(`label ${labelCorrect ? 'correct' : 'incorrect'}`);\n }\n traceLog.push(`Category ${index + 1}: modified - ${parts.join(', ')}.`);\n } else {\n if (valueCorrect && labelCorrect) {\n traceLog.push(`Category ${index + 1}: initial values are correct.`);\n } else if (valueCorrect) {\n traceLog.push(`Category ${index + 1}: initial value correct, label incorrect.`);\n } else if (labelCorrect) {\n traceLog.push(`Category ${index + 1}: initial value incorrect, label correct.`);\n } else {\n traceLog.push(`Category ${index + 1}: initial value and label incorrect.`);\n }\n }\n });\n\n if (answers.length > correctAnswers.length) {\n const extra = answers.length - correctAnswers.length;\n traceLog.push(`${extra} extra category(ies) provided beyond expected number.`);\n }\n\n if (isPartialScoring) {\n traceLog.push('Score calculated using partial scoring.');\n traceLog.push('Student receives credit for each correct value and label independently.');\n } else {\n traceLog.push('Score calculated using all-or-nothing scoring.');\n traceLog.push('Student must match all category values and labels exactly for full credit.');\n }\n\n const scoreObject = getScore(model, session, env);\n traceLog.push(`Score: ${scoreObject.score}.`);\n\n return traceLog;\n};\n\n\n// eslint-disable-next-line no-unused-vars\nexport const filterCategories = <T extends ChartingCategory>(categories?: T[]): Omit<T, 'deletable'>[] =>\n categories ? categories.map(({ deletable, ...rest }) => rest) : [];\n\nexport function model(\n question: ChartingModel,\n session: ChartingSession | null | undefined,\n env: ChartingEnvironment,\n): Promise<ChartingViewModel> {\n return new Promise((resolve) => {\n const normalizedQuestion = normalize(question);\n const {\n addCategoryEnabled,\n chartType,\n data,\n domain,\n graph,\n prompt,\n promptEnabled,\n range,\n rationale,\n title,\n rationaleEnabled,\n teacherInstructions,\n teacherInstructionsEnabled,\n correctAnswer,\n scoringType,\n studentNewCategoryDefaultLabel,\n language,\n extraCSSRules,\n } = normalizedQuestion;\n\n const correctInfo = { correctness: 'incorrect', score: '0%' };\n\n const base: ChartingViewModel = {\n addCategoryEnabled,\n chartType,\n data: filterCategories(data),\n domain,\n graph,\n prompt: promptEnabled ? prompt : null,\n range,\n rationale,\n title,\n size: graph,\n showToggle: false,\n correctness: correctInfo,\n disabled: env.mode !== 'gather',\n scoringType,\n studentNewCategoryDefaultLabel,\n language,\n env,\n extraCSSRules,\n };\n\n const scoreObject = getScore(normalizedQuestion, session, env);\n const answers = filterCategories(scoreObject.answers);\n\n if (env.mode === 'view') {\n // eslint-disable-next-line no-unused-vars\n base.correctedAnswer = answers.map(({ correctness, ...rest }) => {\n return { ...rest, interactive: false };\n });\n\n base.addCategoryEnabled = false;\n }\n\n if (env.mode === 'evaluate') {\n base.correctedAnswer = answers;\n base.correctAnswer = correctAnswer;\n base.showToggle = !!correctAnswer?.data?.length && scoreObject.score !== 1;\n base.addCategoryEnabled = false;\n base.showKeyLegend = true;\n }\n\n if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {\n base.rationale = rationaleEnabled ? rationale : null;\n base.teacherInstructions = teacherInstructionsEnabled ? teacherInstructions : null;\n } else {\n base.rationale = null;\n base.teacherInstructions = null;\n }\n\n log('base: ', base);\n resolve(base);\n });\n}\n\nexport function outcome(\n model: ChartingModel,\n session: ChartingSession | null | undefined,\n env: ChartingEnvironment,\n): Promise<ChartingOutcome> {\n return new Promise((resolve) => {\n const traceLog = getLogTrace(model, session, env);\n const scoreObject = getScore(model, session, env);\n \n const result: ChartingOutcome = {\n score: scoreObject.score,\n empty: !session || isEmpty(session),\n traceLog\n };\n \n if (env.extraProps && env.extraProps.correctResponseEnabled) {\n result.extraProps = { correctResponse: scoreObject.correctResponses };\n }\n \n resolve(result);\n });\n}\n\nexport const createCorrectResponseSession = (\n question: ChartingModel,\n env: ChartingEnvironment,\n): Promise<ChartingSession | null> => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { correctAnswer } = question;\n\n let answers = correctAnswer && correctAnswer.data;\n\n // for IBX preview mode\n if (env.mode === 'gather') {\n const { data } = question;\n\n answers = ((correctAnswer && correctAnswer.data) || []).map((answer, index) => {\n // Throws when the model has no `data`, as it did untyped.\n return {\n ...(data as ChartingCategory[])[index],\n ...answer,\n };\n });\n }\n\n resolve({\n answer: answers,\n id: '1',\n });\n } else {\n return resolve(null);\n }\n });\n};\n\n// remove all html tags\nconst getInnerText = (html?: string) => (html || '').replaceAll(/<[^>]*>/g, '');\n\n// remove all html tags except img, iframe and source tag for audio\nconst getContent = (html?: string) => (html || '').replace(/(<(?!img|iframe|source)([^>]+)>)/gi, '');\n\nexport const validate = (\n model: Partial<ChartingModel> = {},\n config: ChartingConfiguration = {},\n): ChartingValidationErrors => {\n const { correctAnswer, data } = model || {};\n const { data: correctData } = correctAnswer || {};\n const categories = correctData || [];\n\n const errors: ChartingValidationErrors = {};\n const correctAnswerErrors: NonNullable<ChartingValidationErrors['correctAnswerErrors']> = {};\n const categoryErrors: Record<number, string> = {};\n\n (['teacherInstructions', 'prompt', 'rationale'] as const).forEach((field) => {\n if (config[field]?.required && !getContent(model[field])) {\n errors[field] = 'This field is required.';\n }\n });\n\n categories.forEach((category, index) => {\n const { label } = category;\n\n if (!getInnerText(label)) {\n categoryErrors[index] = 'Content should not be empty. ';\n } else {\n const identicalAnswer = categories.some((c, i) => c.label === label && index !== i);\n\n if (identicalAnswer) {\n categoryErrors[index] = 'Category names should be unique. ';\n }\n }\n });\n\n if (categories.length < 1 || categories.length > 20) {\n correctAnswerErrors.categoriesError = 'The correct answer should include between 1 and 20 categories.';\n } else if (\n isEqual(\n // `data.map` throws when the model has no `data`, as it did untyped.\n (data as ChartingCategory[]).map((category) => pick(category, 'value', 'label')),\n (correctData as ChartingCategory[]).map((category) => pick(category, 'value', 'label')),\n )\n ) {\n correctAnswerErrors.identicalError = 'Correct answer should not be identical to the chart’s initial state';\n }\n\n if (!isEmpty(categoryErrors)) {\n errors.categoryErrors = categoryErrors;\n }\n\n if (!isEmpty(correctAnswerErrors)) {\n errors.correctAnswerErrors = correctAnswerErrors;\n }\n\n return errors;\n};\n"],"mappings":";;A,mCAQAY,IAAe;CACb,oBAAoB;CACpB,0BAA0B;CAC1B,uBAAuB;CACvB,0BAA0B;CAC1B,WAAW;CACX,eAAe,CAAC;CAChB,MAAM,CAAC;CACP,QAAQ,CAAC;CACT,OAAO;EAAE,OAAO;EAAK,QAAQ;CAAI;CACjC,QAAQ;CACR,eAAe;CACf,OAAO;EAAE,OAAO;EAAI,KAAK;EAAG,KAAK;EAAG,WAAW;CAAE;CACjD,WAAW;CACX,kBAAkB;CAClB,aAAa;CACb,4BAA4B;CAC5B,gCAAgC;CAChC,qBAAqB;CACrB,4BAA4B;CAC5B,OAAO;AACT,GC5BIC,IAAI,OAAO,gBA8CXC,IAAoB,kBA9CY,GAAG,MAAM;CAC5C,IAAIC,IAAI,CAAC;CACT,KAAK,IAAIC,KAAKC,GAAG,EAAEF,GAAGC,GAAG;EACxB,KAAKC,EAAED;EACP,YAAY,CAAC;CACd,CAAC;CACD,OAAOE,KAAKL,EAAEE,GAAG,OAAO,aAAa,EAAE,OAAO,SAAS,CAAC,GAAGA;AAC5D,EAuCwB,CAAE,EAAE,eAAeI,EAAE,CAAC;AAC9C,SAASA,EAAE,GAAG,GAAG,GAAG;CACnB,OAAO,GAAG,mBAAmB,CAAC,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,OAAO,KAAK,aAAa;AAC7F;;;ACyBA,IAAMC,KAAA,GAAMpB,EAAAA,QAAAA,CAAM,kCAAkC,GAE9CqB,KAAa,OAAqBC,KAAU,GAAA,CAAI,YAAY,GAErDC,KAAuB,GAA2B,MAC7DF,EAAUG,CAAgB,MAAMH,EAAUI,CAAkB,GAEjDC,KAAkB,GAAyC,MACtEC,IACIA,EAAQ,KAAK,OAAY;CACvB,GAAGC;CACH,aAAa;EACX,OAAOC,IAAiB,cAAc;EACtC,OAAOA,IAAiB,cAAc;CACxC;AACF,EAAE,IACF,CAAC,GAEMC,KAAa,OAA6B;CAAE,GAAG7B;CAAU,GAAG8B;AAAS,IAErEC,KACX,GACA,GACA,IAAoC,CAAC,MACnB;CAClB,IAAM,EAAE,kBAAe,MAAMC,IAAc,CAAC,GAAG,mBAAgBF,GACzDG,IAA8C,CAAC,GAE/CC,IAAmBjC,EAAe,QACtC,EAAE,gBAAgBkC,MAAgB,KAAA,IAAgDA,IAApCA,MAAgB,kBAAgC,GAC9FC,CACF,GAEM,EAAE,MAAMC,IAAiB,CAAC,MAAMC,KAAiB,CAAC,GAClDC,IAAiBC,EAAiBR,CAAW,GAE/CN,IAAUD,EAAgBgB,KAAWA,EAAQ,UAAWF,GAAgBL,CAAgB,GAExFQ,IAAS;CAEb,IAAIR,GAAkB;EAIpB,IAAIS,IAAW,GACXC,IAAQ,GAENC,KAAiC,GAAwB,MAAiC;GAC9F,IAAM,EAAE,UAAO,UAAO,aAAUlB,GAC1BmB,IAAiBC,MAAUC,EAAW,OACtCC,IAAiB3B,EAAoB4B,GAAOF,EAAW,KAAK;GAalE,AAZA,KAAY,GAERF,MACF,KAAS,GACT,EAAO,YAAY,QAAQ,YAGzBG,MACF,KAAS,GACT,EAAO,YAAY,QAAQ,YAGzBH,KAAkBG,KACpBhB,EAAiB,KAAK;IAAS;IAAc;GAAM,CAAC;EAExD;EA2CA,AAxCAI,EAAe,SAAS,GAAY,MAAU;GAC5C,IAAMc,IAAgBZ,EAAea,IAC/BzB,IAASD,EAAQ0B;GAGvB,AAAIzB,IAEEwB,IAGE,CAACA,EAAc,YAAYxB,EAAO,eACpC,KAAY,GAERA,EAAO,UAAUqB,EAAW,UAC9B,KAAS,GACT,EAAO,YAAY,QAAQ,WAC3Bf,EAAiB,KAAK;IAAE,OAAON,EAAO;IAAc;GAAM,CAAC,IAE7D,EAAO,YAAY,QAAQ,aAIlBwB,EAAc,YAAYxB,EAAO,cAC1CkB,EAA8BlB,GAAQqB,CAAU,IACtCrB,EAAO,gBACjB,EAAO,YAAY,QAAQ,WAC3B,EAAO,YAAY,QAAQ,WAC3BM,EAAiB,KAAK;IAAE,OAAON,EAAO;IAAc;GAAM,CAAC,KAI7DkB,EAA8BlB,GAAQqB,CAAU,IAKlD,KAAY;EAEhB,CAAC,GAED,IAASL,IAAWC,IAAQD,IAAW;CACzC,OAKE,AAHA,IAAS,IAAe,WAAWjB,EAAQ,SAG3C,IAAUA,EAAQ,KAAK,GAAQ,MAA0B;EACvD,IAAMY,IAAgBD,EAAee,IAC/BN,IAAiBR,IAAgBX,EAAO,UAAUW,EAAc,QAAQ,IACxEW,IAAiBX,IAAgBlB,EAAUO,EAAO,KAAK,MAAMP,EAAUkB,EAAc,KAAK,IAAI;EAUpG,QARI,CAACQ,KAAkB,CAACG,OACtB,IAAS,IAGPH,KAAkBG,KACpBhB,EAAiB,KAAK;GAAE,OAAON,EAAO;GAAO;EAAM,CAAC,GAG/C;GACL,GAAGA;GACH,aAAa;IACX,OAAOmB,IAAiB,YAAY;IACpC,OAAOG,IAAiB,YAAY;GACtC;EACF;CACF,CAAC;CAGH,IAAML,IAAuB;EAC3B,OAAO,WAAWF,EAAO,QAAQ,CAAC,CAAC;EACnC;CACF;CAMA,OAJIN,EAAI,cAAcA,EAAI,WAAW,2BACnC,EAAM,mBAAmBH,IAGpBW;AACT,GASaS,KACX,GACA,GACA,MACa;CACb,IAAMC,IAAqB,CAAC,GAEtB,EAAE,kBAAe,MAAMtB,IAAc,CAAC,GAAG,mBAAgBuB,KAAS,CAAC,GACnE,EAAE,MAAMlB,IAAiB,CAAC,MAAMC,KAAiB,CAAC,GAClDkB,IAAkBf,KAAWA,EAAQ,UAAW,CAAC,GAEjDP,IAAmBjC,EAAe,QACtC,EAAE,gBAAgBkC,MAAgB,KAAA,IAAgDA,IAApCA,MAAgB,kBAAgC,GAC9FC,CACF,GAEMG,IAAiBC,EAAiBR,CAAW,GAC7CN,IAAU8B,EAAe,SAAS,IAAIhB,EAAiBgB,CAAc,IAAIjB;CAyD/E,IAvDKiB,EAAe,UAClBF,EAAS,KAAK,4DAA4D,GAG5EjB,EAAe,SAAS,GAAS,MAAU;EACzC,IAAMoB,IAAUlB,EAAea,IACzBM,IAAUhC,EAAQ0B;EAExB,IAAI,CAACM,GAAS;GACZ,EAAS,KAAK,YAAYN,IAAQ,EAAE,6BAA6BO,EAAQ,MAAM,YAAYA,EAAQ,MAAM,IAAI;GAC7G;EACF;EAEA,IAAMC,IAAeF,EAAQ,UAAUC,EAAQ,OACzCE,IAAevC,EAAoBoC,EAAQ,OAAOC,EAAQ,KAAK;EAErE,IAAI,CAACD,EAAQ,aACX,EAAS,KAAK,YAAYN,IAAQ,EAAE,+CAA+C;OAIrF,IAAII,EAAe,SAAS,GAAG;GAC7B,IAAMM,IAAe,MAAUJ,EAAQ,UAAUD,EAAQ,OACnDM,IAAe,MAAU,CAACzC,EAAoBoC,EAAQ,OAAOD,EAAQ,KAAK;GAEhF,IAAI,CAACK,KAAgB,CAACC,GAAc;IAClC,AAAIH,KAAgBC,IAClBP,EAAS,KAAK,YAAYF,IAAQ,EAAE,4CAA4C,IAEhFE,EAAS,KAAK,YAAYF,IAAQ,EAAE,8CAA8C;IAEpF;GACF;GAEA,IAAMY,IAAkB,CAAC;GAOzB,AANIF,KACFE,EAAM,KAAK,SAASJ,IAAe,YAAY,aAAa,GAE1DG,KACFC,EAAM,KAAK,SAASH,IAAe,YAAY,aAAa,GAE9DP,EAAS,KAAK,YAAYF,IAAQ,EAAE,eAAeY,EAAM,KAAK,IAAI,EAAE,EAAE;EACxE,OACE,AAAIJ,KAAgBC,IAClBP,EAAS,KAAK,YAAYF,IAAQ,EAAE,8BAA8B,IACzDQ,IACTN,EAAS,KAAK,YAAYF,IAAQ,EAAE,0CAA0C,IACrES,IACTP,EAAS,KAAK,YAAYF,IAAQ,EAAE,0CAA0C,IAE9EE,EAAS,KAAK,YAAYF,IAAQ,EAAE,qCAAqC;CAG/E,CAAC,GAEG1B,EAAQ,SAASW,EAAe,QAAQ;EAC1C,IAAM4B,IAAQvC,EAAQ,SAASW,EAAe;EAC9C,EAAS,KAAK,GAAG4B,EAAM,sDAAsD;CAC/E;CAEA,AAAI/B,KACFoB,EAAS,KAAK,yCAAyC,GACvDA,EAAS,KAAK,yEAAyE,MAEvFA,EAAS,KAAK,gDAAgD,GAC9DA,EAAS,KAAK,4EAA4E;CAG5F,IAAMY,IAAcnC,EAASwB,GAAOd,GAASL,CAAG;CAGhD,OAFAkB,EAAS,KAAK,UAAUY,EAAY,MAAM,EAAE,GAErCZ;AACT,GAIad,KAAgD,MAC3D2B,IAAaA,EAAW,KAAK,EAAE,cAAW,GAAGC,QAAWA,CAAI,IAAI,CAAC;AAEnE,SAAgBb,EACd,GACA,GACA,GAC4B;CAC5B,OAAO,IAAI,SAAS,MAAY;EAC9B,IAAMc,IAAqBxC,EAAUC,CAAQ,GACvC,EACJ,uBACA,cACA,SACA,WACA,UACA,WACA,kBACA,UACA,cACA,UACA,qBACA,wBACA,+BACA,kBACA,gBACA,mCACA,aACA,qBACEuC,GAIEC,IAA0B;GAC9B;GACA;GACA,MAAM9B,EAAiB+B,CAAI;GAC3B;GACA;GACA,QAAQC,IAAgBC,IAAS;GACjC;GACA;GACA;GACA,MAAMC;GACN,YAAY;GACZ,aAAa;IAdO,aAAa;IAAa,OAAO;GAcxC;GACb,UAAUtC,EAAI,SAAS;GACvB;GACA;GACA;GACA;GACA;EACF,GAEM8B,IAAcnC,EAASsC,GAAoB5B,GAASL,CAAG,GACvDV,IAAUc,EAAiB0B,EAAY,OAAO;EA4BpD,AA1BI9B,EAAI,SAAS,WAEf,EAAK,kBAAkBV,EAAQ,KAAK,EAAE,gBAAa,GAAG0C,SAC7C;GAAE,GAAGA;GAAM,aAAa;EAAM,EACtC,GAED,EAAK,qBAAqB,KAGxBhC,EAAI,SAAS,eACf,EAAK,kBAAkBV,GACvB,EAAK,gBAAgBY,GACrB,EAAK,aAAa,CAAC,CAACA,GAAe,MAAM,UAAU4B,EAAY,UAAU,GACzE,EAAK,qBAAqB,IAC1B,EAAK,gBAAgB,KAGnB9B,EAAI,SAAS,iBAAiBA,EAAI,SAAS,UAAUA,EAAI,SAAS,eACpE,EAAK,YAAYuC,IAAmBC,IAAY,MAChD,EAAK,sBAAsBC,IAA6BC,IAAsB,SAE9E,EAAK,YAAY,MACjB,EAAK,sBAAsB,OAG7B3D,EAAI,UAAUmD,CAAI,GAClBS,EAAQT,CAAI;CACd,CAAC;AACH;AAEA,SAAgBU,EACd,GACA,GACA,GAC0B;CAC1B,OAAO,IAAI,SAAS,MAAY;EAC9B,IAAM1B,IAAWD,EAAYE,GAAOd,GAASL,CAAG,GAC1C8B,IAAcnC,EAASwB,GAAOd,GAASL,CAAG,GAE1CM,IAA0B;GAC9B,OAAOwB,EAAY;GACnB,OAAO,CAACzB,KAAWvC,EAAQuC,CAAO;GAClC;EACF;EAMA,AAJIL,EAAI,cAAcA,EAAI,WAAW,2BACnC,EAAO,aAAa,EAAE,iBAAiB8B,EAAY,iBAAiB,IAGtEa,EAAQrC,CAAM;CAChB,CAAC;AACH;AAEA,IAAauC,KACX,GACA,MAEO,IAAI,SAAS,MAAY;CAC9B,IAAI7C,EAAI,SAAS,cAAcA,EAAI,SAAS,cAAc;EACxD,IAAM,EAAE,qBAAkBN,GAEtBJ,IAAUY,KAAiBA,EAAc;EAG7C,IAAIF,EAAI,SAAS,UAAU;GACzB,IAAM,EAAE,YAASN;GAEjB,KAAYQ,KAAiBA,EAAc,QAAS,CAAC,EAAA,CAAG,KAAK,GAAQ,OAE5D;IACL,GAAIiC,EAA4BnB;IAChC,GAAGzB;GACL,EACD;EACH;EAEA,EAAQ;GACN,QAAQD;GACR,IAAI;EACN,CAAC;CACH,OACE,OAAOqD,EAAQ,IAAI;AAEvB,CAAC,GAIGG,KAAgB,OAAmBC,KAAQ,GAAA,CAAI,WAAW,YAAY,EAAE,GAGxEC,KAAc,OAAmBD,KAAQ,GAAA,CAAI,QAAQ,sCAAsC,EAAE,GAEtFE,KACX,IAAgC,CAAC,GACjC,IAAgC,CAAC,MACJ;CAC7B,IAAM,EAAE,kBAAe,YAAS9B,KAAS,CAAC,GACpC,EAAE,MAAM+B,MAAgBhD,KAAiB,CAAC,GAC1C6B,IAAamB,KAAe,CAAC,GAE7BC,IAAmC,CAAC,GACpCC,IAAoF,CAAC,GACrFC,IAAyC,CAAC;CA0ChD,OAxCA;EAAE;EAAuB;EAAU;CAAW,CAAC,CAAW,SAAS,MAAU;EAC3E,AAAIC,EAAOC,EAAM,EAAE,YAAY,CAACP,EAAW7B,EAAMoC,EAAM,MACrD,EAAOA,KAAS;CAEpB,CAAC,GAEDxB,EAAW,SAAS,GAAU,MAAU;EACtC,IAAM,EAAE,aAAUyB;EAElB,AAAKV,EAAahC,CAAK,IAGGiB,EAAW,MAAM,GAAG,MAAMjD,EAAE,UAAUgC,KAASE,MAAUrC,CAE7E,MACF,EAAeqC,KAAS,uCAL1B,EAAeA,KAAS;CAQ5B,CAAC,GAEGe,EAAW,SAAS,KAAKA,EAAW,SAAS,KAC/C,EAAoB,kBAAkB,mEAEtChE,EAEGoE,EAA4B,KAAK,MAAanE,EAAKwF,GAAU,SAAS,OAAO,CAAC,GAC9EN,EAAmC,KAAK,MAAalF,EAAKwF,GAAU,SAAS,OAAO,CAAC,CACxF,MAEA,EAAoB,iBAAiB,wEAGlC1F,EAAQuF,CAAc,MACzB,EAAO,iBAAiBA,IAGrBvF,EAAQsF,CAAmB,MAC9B,EAAO,sBAAsBA,IAGxBD;AACT,G"}
1
+ {"version":3,"file":"index.js","names":["debug","normalizeResponse","defaults","contentLanguage","partialScoring","isEmpty","isEqual","pick","__toESM","wn","Vn","Cn","require_browser","import_browser","defaults_default","e","s","r","i","t","n","c","l","u","d","f","p","m","h","g","_","v","y","b","x","S","C","w","T","E","log","comparableLabel","label","checkLabelsEquality","givenAnswerLabel","language","correctAnswerLabel","setCorrectness","answers","answer","partialScoring","normalize","question","getScore","initialData","correctResponses","env","isPartialScoring","scoringType","correctAnswers","correctAnswer","defaultAnswers","filterCategories","session","result","maxScore","score","scoreForLabelAndValueEditable","valueIsCorrect","value","corrAnswer","labelIsCorrect","defaultAnswer","index","getLogTrace","traceLog","model","studentAnswers","initial","student","correct","valueCorrect","labelCorrect","valueChanged","labelChanged","parts","extra","scoreObject","categories","rest","normalizedQuestion","base","data","promptEnabled","prompt","graph","rationaleEnabled","rationale","teacherInstructionsEnabled","teacherInstructions","resolve","outcome","createCorrectResponseSession","getInnerText","html","getContent","validate","correctData","errors","correctAnswerErrors","categoryErrors","config","field","category","piePackage","\"name\"","\"version\""],"sources":["../../../src/controller/defaults.ts","../../../../../shared/controller-utils/dist/index.js","../../../src/controller/index.ts"],"sourcesContent":["import type { ChartingCategory, ChartingCorrectAnswer, ChartingDomain, ChartingModel } from '../types.js';\n\n/**\n * NOTE: There's no functionality described for graphTitle,\n * rationale, scoringType, studentInstructions, teacherInstructions\n * so there's no implementation (they are only added in model)\n */\n\nexport default {\n addCategoryEnabled: true,\n changeAddCategoryEnabled: false,\n changeEditableEnabled: false,\n changeInteractiveEnabled: false,\n chartType: 'lineCross',\n correctAnswer: {} as ChartingCorrectAnswer,\n data: [] as ChartingCategory[],\n domain: {} as ChartingDomain,\n graph: { width: 480, height: 480 },\n prompt: '',\n promptEnabled: true,\n range: { label: '', max: 1, min: 0, labelStep: 1 },\n rationale: '',\n rationaleEnabled: true,\n scoringType: 'all or nothing',\n studentInstructionsEnabled: true,\n studentNewCategoryDefaultLabel: 'New Category',\n teacherInstructions: '',\n teacherInstructionsEnabled: true,\n title: '',\n} satisfies Omit<ChartingModel, 'id' | 'element'>;\n","//#region \\0rolldown/runtime.js\nvar e = Object.defineProperty, t = (t, n) => {\n\tlet r = {};\n\tfor (var i in t) e(r, i, {\n\t\tget: t[i],\n\t\tenumerable: !0\n\t});\n\treturn n || e(r, Symbol.toStringTag, { value: \"Module\" }), r;\n};\n//#endregion\n//#region src/persistence.ts\nfunction n(e) {\n\treturn Array.isArray(e) ? e.filter((e) => e != null) : [];\n}\nfunction r(e) {\n\tlet t = [...e];\n\tfor (let e = t.length - 1; e > 0; e--) {\n\t\tlet n = Math.floor(Math.random() * (e + 1));\n\t\t[t[e], t[n]] = [t[n], t[e]];\n\t}\n\treturn t;\n}\nfunction i(e) {\n\treturn e == null ? !0 : Array.isArray(e) ? e.length === 0 : typeof e == \"object\" && Object.keys(e).length === 0;\n}\nasync function a(e, t, a, o = \"value\") {\n\tlet s = n(t?.data?.shuffledValues ?? t?.shuffledValues ?? []);\n\tif (!t) {\n\t\tconsole.warn(\"Unable to save shuffled choices because there's no session.\");\n\t\treturn;\n\t}\n\tif (!i(s)) return n(s.map((t) => e.find((e) => e[o] === t)));\n\tlet c = r(e);\n\tif (a && typeof a == \"function\") try {\n\t\tlet e = n(c.map((e) => e[o]));\n\t\ti(e) ? console.error(`shuffledValues is an empty array - refusing to call updateSession. shuffledChoices: ${JSON.stringify(c)}, key: ${o}`) : await a(t.id, t.element, { shuffledValues: e });\n\t} catch (e) {\n\t\tconsole.warn(\"Unable to save shuffled order for choices\"), console.error(e);\n\t}\n\telse console.warn(\"Unable to save shuffled choices, shuffle will happen every time.\");\n\treturn c;\n}\nfunction o(e, t, n) {\n\treturn !!(e.lockChoiceOrder || n?.[\"@pie-element\"]?.lockChoiceOrder);\n}\n//#endregion\n//#region src/partial-scoring.ts\nvar s = /* @__PURE__ */ t({ enabled: () => c });\nfunction c(e, t, n) {\n\treturn e?.partialScoring === !1 || t?.partialScoring === !1 ? !1 : typeof n != \"boolean\" || n;\n}\n//#endregion\n//#region src/response-normalizer.ts\nvar l = /[\\u061C\\u200E\\u200F\\u202A-\\u202E\\u2066-\\u2069\\u0640]/g, u = /[\\uFB50-\\uFDFF\\uFE70-\\uFEFC]+/g, d = /\\p{Nd}/u, f = /(?![0-9])\\p{Nd}/gu, p = /\\u066B/g, m = /\\u066C/g, h = /[\\u0622\\u0623\\u0625\\u0671]/g, g = /[\\u064B-\\u065F\\u0670]/g, _ = /* @__PURE__ */ new Map(), v = (e) => {\n\tlet t = _.get(e);\n\tif (t !== void 0) return t;\n\tlet n = 0;\n\tfor (; d.test(String.fromCodePoint(e - n - 1));) n++;\n\tlet r = n % 10;\n\treturn _.set(e, r), r;\n}, y = (e) => e.replace(f, (e) => String(v(e.codePointAt(0)))), b = {\n\tdecimal: \".\",\n\tgroup: \",\"\n}, x = /* @__PURE__ */ new Map(), S = (e) => {\n\tif (!e) return b;\n\tlet t = x.get(e);\n\tif (t) return t;\n\tlet n = b;\n\ttry {\n\t\tif (Intl.NumberFormat.supportedLocalesOf(e).length > 0) {\n\t\t\tlet t = new Intl.NumberFormat(e, { numberingSystem: \"latn\" }).formatToParts(12345.6);\n\t\t\tn = {\n\t\t\t\tdecimal: t.find((e) => e.type === \"decimal\")?.value ?? \".\",\n\t\t\t\tgroup: t.find((e) => e.type === \"group\")?.value ?? \",\"\n\t\t\t};\n\t\t}\n\t} catch {}\n\treturn x.set(e, n), n;\n}, C = (e, t) => {\n\tlet n = [e?.language, t?.locale];\n\tfor (let e of n) if (typeof e == \"string\" && e.trim()) return e.trim().replace(/_/g, \"-\");\n}, w = /^(tr|az)(-|$)/i, T = (e, t) => {\n\tif (!t || !w.test(t)) return e.toLowerCase();\n\ttry {\n\t\treturn e.toLocaleLowerCase(t);\n\t} catch {\n\t\treturn e.toLowerCase();\n\t}\n}, E = (e, t = {}) => {\n\tlet n = S(t.language), r = (t.ignoreCase ? T(e, t.language) : e).replace(l, \"\").replace(u, (e) => e.normalize(\"NFKC\")).normalize(\"NFC\");\n\treturn r = y(r).replace(p, n.decimal).replace(m, n.group), t.foldLetterVariants && (r = r.replace(g, \"\").replace(h, \"ا\").replace(/\\u0629/g, \"ه\").replace(/\\u0649/g, \"ي\")), r;\n};\n//#endregion\nexport { C as contentLanguage, T as foldCase, y as foldDigits, a as getShuffledChoices, o as lockChoices, E as normalizeResponse, s as partialScoring };\n","import debug from 'debug';\nimport { isEmpty, isEqual, pick } from '@pie-element/shared-lodash';\nimport type { ExtraCSSRules, PieEnvironment } from '@pie-element/shared-types';\nimport defaults from './defaults.js';\n\nimport { contentLanguage, normalizeResponse, partialScoring } from '@pie-element/shared-controller-utils';\nimport type {\n ChartingCategory,\n ChartingCategoryCorrectness,\n ChartingConfiguration,\n ChartingCorrectAnswer,\n ChartingModel,\n ChartingSession,\n} from '../types.js';\n\n/** The environment, plus the extra properties a host may ask the outcome for */\nexport type ChartingEnvironment = PieEnvironment & { extraProps?: { correctResponseEnabled?: boolean } };\n\n/** A category marked correct or incorrect */\nexport type ScoredCategory = ChartingCategory & { correctness: ChartingCategoryCorrectness };\n\n/** A category whose value and label both match the correct answer */\nexport type ChartingCorrectResponse = { label: string; index?: number };\n\nexport type ChartingScore = {\n score: number;\n answers: ScoredCategory[];\n correctResponses?: ChartingCorrectResponse[];\n};\n\nexport type ChartingValidationErrors = {\n teacherInstructions?: string;\n prompt?: string;\n rationale?: string;\n /** Category errors of the correct answer, keyed by category position */\n categoryErrors?: Record<number, string>;\n correctAnswerErrors?: {\n categoriesError?: string;\n identicalError?: string;\n };\n};\n\n/** What `model()` returns for the delivery view */\nexport type ChartingViewModel = {\n addCategoryEnabled?: boolean;\n chartType?: ChartingModel['chartType'];\n data: Omit<ChartingCategory, 'deletable'>[];\n domain?: ChartingModel['domain'];\n graph?: ChartingModel['graph'];\n prompt?: string | null;\n range?: ChartingModel['range'];\n rationale?: string | null;\n title?: string;\n size?: ChartingModel['graph'];\n showToggle: boolean;\n correctness: { correctness: string; score: string };\n disabled: boolean;\n scoringType?: ChartingModel['scoringType'];\n studentNewCategoryDefaultLabel?: string;\n language?: string;\n env: ChartingEnvironment;\n extraCSSRules?: ExtraCSSRules;\n correctedAnswer?: Omit<ChartingCategory, 'deletable'>[];\n correctAnswer?: ChartingCorrectAnswer;\n showKeyLegend?: boolean;\n teacherInstructions?: string | null;\n};\n\ntype ChartingOutcome = {\n score: number;\n empty: boolean;\n traceLog: string[];\n extraProps?: { correctResponse?: ChartingCorrectResponse[] };\n};\n\nconst log = debug('@pie-element:graphing:controller');\n\n/** A label's comparable form: normalized, and case folded in the content language. */\nconst comparableLabel = (label: string | undefined, language: string | undefined) =>\n normalizeResponse(label || '', { language, ignoreCase: true });\n\nexport const checkLabelsEquality = (givenAnswerLabel?: string, correctAnswerLabel?: string, language?: string) =>\n comparableLabel(givenAnswerLabel, language) === comparableLabel(correctAnswerLabel, language);\n\nexport const setCorrectness = (answers: ChartingCategory[] | undefined, partialScoring: boolean): ScoredCategory[] =>\n answers\n ? answers.map((answer) => ({\n ...answer,\n correctness: {\n value: partialScoring ? 'incorrect' : 'correct',\n label: partialScoring ? 'incorrect' : 'correct',\n },\n }))\n : [];\n\nexport const normalize = (question: ChartingModel) => ({ ...defaults, ...question });\n\nexport const getScore = (\n question: ChartingModel,\n session: ChartingSession | null | undefined,\n env: Partial<ChartingEnvironment> = {},\n): ChartingScore => {\n const { correctAnswer, data: initialData = [], scoringType } = question;\n const correctResponses: ChartingCorrectResponse[] = [];\n const language = contentLanguage(question, env);\n\n const isPartialScoring = partialScoring.enabled(\n { partialScoring: scoringType !== undefined ? scoringType === 'partial scoring' : scoringType },\n env,\n );\n\n const { data: correctAnswers = [] } = correctAnswer || {};\n const defaultAnswers = filterCategories(initialData);\n\n let answers = setCorrectness((session && session.answer) || defaultAnswers, isPartialScoring);\n\n let result = 0;\n\n if (isPartialScoring) {\n // if score type is \"partial scoring\"\n // maxScore is calculated based on the correct response\n // score is calculated based on the given response\n let maxScore = 0;\n let score = 0;\n\n const scoreForLabelAndValueEditable = (answer: ScoredCategory, corrAnswer: ChartingCategory) => {\n const { value, label, index } = answer;\n const valueIsCorrect = value === corrAnswer.value;\n const labelIsCorrect = checkLabelsEquality(label, corrAnswer.label, language);\n maxScore += 2;\n\n if (valueIsCorrect) {\n score += 1;\n answer.correctness.value = 'correct';\n }\n\n if (labelIsCorrect) {\n score += 1;\n answer.correctness.label = 'correct';\n }\n\n if (valueIsCorrect && labelIsCorrect) {\n correctResponses.push({ label: label, index: index });\n }\n };\n\n // if given answer has more categories than the correct answers, the \"extra\" will be ignored\n correctAnswers.forEach((corrAnswer, index) => {\n const defaultAnswer = defaultAnswers[index];\n const answer = answers[index];\n\n // if there is a corresponding category at the same position in the given answer\n if (answer) {\n // if there is a corresponding category at the same position in the default answer\n if (defaultAnswer) {\n // if category's label (in default answer) was not editable\n // it means that this category values only one point (only the value can be changed)\n if (!defaultAnswer.editable && answer.interactive) {\n maxScore += 1;\n\n if (answer.value === corrAnswer.value) {\n score += 1;\n answer.correctness.value = 'correct';\n correctResponses.push({ label: answer.label, index: index });\n }\n answer.correctness.label = 'correct';\n\n // if category's label (in default answer) was editable\n // it means that this category values 2 points (both label and value can be changed)\n } else if (defaultAnswer.editable && answer.interactive) {\n scoreForLabelAndValueEditable(answer, corrAnswer);\n } else if (!answer.interactive) {\n answer.correctness.value = 'correct';\n answer.correctness.label = 'correct';\n correctResponses.push({ label: answer.label, index: index });\n }\n } else {\n // if there is not a corresponding category at the same position in the default answer\n scoreForLabelAndValueEditable(answer, corrAnswer);\n }\n } else {\n // if there is not a corresponding category at the same position in the given answer\n // it means that the given answer has less categories than the correct answer\n maxScore += 2;\n }\n });\n\n result = maxScore ? score / maxScore : 0;\n } else {\n // all-or-nothing scoring: overall score is 1 only if lengths and all values/labels match\n result = correctAnswers.length === answers.length ? 1 : 0;\n\n // regardless of overall result, mark each answer individually for user feedback\n answers = answers.map((answer, index): ScoredCategory => {\n const correctAnswer = correctAnswers[index];\n const valueIsCorrect = correctAnswer ? answer.value === correctAnswer.value : false;\n const labelIsCorrect = correctAnswer ? checkLabelsEquality(answer.label, correctAnswer.label, language) : false;\n\n if (!valueIsCorrect || !labelIsCorrect) {\n result = 0;\n }\n\n if (valueIsCorrect && labelIsCorrect) {\n correctResponses.push({ label: answer.label, index });\n }\n\n return {\n ...answer,\n correctness: {\n value: valueIsCorrect ? 'correct' : 'incorrect',\n label: labelIsCorrect ? 'correct' : 'incorrect',\n },\n };\n });\n }\n\n const score: ChartingScore = {\n score: parseFloat(result.toFixed(2)),\n answers,\n };\n\n if (env.extraProps && env.extraProps.correctResponseEnabled) {\n score.correctResponses = correctResponses;\n }\n\n return score;\n};\n\n/**\n * Generates detailed trace log for scoring evaluation\n * @param {Object} model - the question model\n * @param {Object} session - the student session\n * @param {Object} env - the environment\n * @returns {Array} traceLog - array of trace messages\n */\nexport const getLogTrace = (\n model: ChartingModel,\n session: ChartingSession | null | undefined,\n env: ChartingEnvironment,\n): string[] => {\n const traceLog: string[] = [];\n\n const { correctAnswer, data: initialData = [], scoringType } = model || {};\n const { data: correctAnswers = [] } = correctAnswer || {};\n const studentAnswers = (session && session.answer) || [];\n const language = contentLanguage(model, env);\n\n const isPartialScoring = partialScoring.enabled(\n { partialScoring: scoringType !== undefined ? scoringType === 'partial scoring' : scoringType },\n env\n );\n\n const defaultAnswers = filterCategories(initialData);\n const answers = studentAnswers.length > 0 ? filterCategories(studentAnswers) : defaultAnswers;\n\n if (!studentAnswers.length) {\n traceLog.push(`Student did not modify the chart. Initial chart is scored.`);\n }\n\n correctAnswers.forEach((correct, index) => {\n const initial = defaultAnswers[index];\n const student = answers[index];\n\n if (!student) {\n traceLog.push(`Category ${index + 1}: missing (expected value '${correct.value}', label '${correct.label}').`);\n return;\n }\n\n const valueCorrect = student.value === correct.value;\n const labelCorrect = checkLabelsEquality(student.label, correct.label, language);\n\n if (!student.interactive) {\n traceLog.push(`Category ${index + 1}: non-interactive category treated as correct.`);\n return;\n }\n\n if (studentAnswers.length > 0) {\n const valueChanged = initial ? student.value !== initial.value : true;\n const labelChanged = initial ? !checkLabelsEquality(student.label, initial.label, language) : true;\n\n if (!valueChanged && !labelChanged) {\n if (valueCorrect && labelCorrect) {\n traceLog.push(`Category ${index + 1}: unchanged from initial value and correct.`);\n } else {\n traceLog.push(`Category ${index + 1}: unchanged from initial value but incorrect.`);\n }\n return;\n }\n\n const parts: string[] = [];\n if (valueChanged) {\n parts.push(`value ${valueCorrect ? 'correct' : 'incorrect'}`);\n }\n if (labelChanged) {\n parts.push(`label ${labelCorrect ? 'correct' : 'incorrect'}`);\n }\n traceLog.push(`Category ${index + 1}: modified - ${parts.join(', ')}.`);\n } else {\n if (valueCorrect && labelCorrect) {\n traceLog.push(`Category ${index + 1}: initial values are correct.`);\n } else if (valueCorrect) {\n traceLog.push(`Category ${index + 1}: initial value correct, label incorrect.`);\n } else if (labelCorrect) {\n traceLog.push(`Category ${index + 1}: initial value incorrect, label correct.`);\n } else {\n traceLog.push(`Category ${index + 1}: initial value and label incorrect.`);\n }\n }\n });\n\n if (answers.length > correctAnswers.length) {\n const extra = answers.length - correctAnswers.length;\n traceLog.push(`${extra} extra category(ies) provided beyond expected number.`);\n }\n\n if (isPartialScoring) {\n traceLog.push('Score calculated using partial scoring.');\n traceLog.push('Student receives credit for each correct value and label independently.');\n } else {\n traceLog.push('Score calculated using all-or-nothing scoring.');\n traceLog.push('Student must match all category values and labels exactly for full credit.');\n }\n\n const scoreObject = getScore(model, session, env);\n traceLog.push(`Score: ${scoreObject.score}.`);\n\n return traceLog;\n};\n\n\n// eslint-disable-next-line no-unused-vars\nexport const filterCategories = <T extends ChartingCategory>(categories?: T[]): Omit<T, 'deletable'>[] =>\n categories ? categories.map(({ deletable, ...rest }) => rest) : [];\n\nexport function model(\n question: ChartingModel,\n session: ChartingSession | null | undefined,\n env: ChartingEnvironment,\n): Promise<ChartingViewModel> {\n return new Promise((resolve) => {\n const normalizedQuestion = normalize(question);\n const {\n addCategoryEnabled,\n chartType,\n data,\n domain,\n graph,\n prompt,\n promptEnabled,\n range,\n rationale,\n title,\n rationaleEnabled,\n teacherInstructions,\n teacherInstructionsEnabled,\n correctAnswer,\n scoringType,\n studentNewCategoryDefaultLabel,\n language,\n extraCSSRules,\n } = normalizedQuestion;\n\n const correctInfo = { correctness: 'incorrect', score: '0%' };\n\n const base: ChartingViewModel = {\n addCategoryEnabled,\n chartType,\n data: filterCategories(data),\n domain,\n graph,\n prompt: promptEnabled ? prompt : null,\n range,\n rationale,\n title,\n size: graph,\n showToggle: false,\n correctness: correctInfo,\n disabled: env.mode !== 'gather',\n scoringType,\n studentNewCategoryDefaultLabel,\n language,\n env,\n extraCSSRules,\n };\n\n const scoreObject = getScore(normalizedQuestion, session, env);\n const answers = filterCategories(scoreObject.answers);\n\n if (env.mode === 'view') {\n // eslint-disable-next-line no-unused-vars\n base.correctedAnswer = answers.map(({ correctness, ...rest }) => {\n return { ...rest, interactive: false };\n });\n\n base.addCategoryEnabled = false;\n }\n\n if (env.mode === 'evaluate') {\n base.correctedAnswer = answers;\n base.correctAnswer = correctAnswer;\n base.showToggle = !!correctAnswer?.data?.length && scoreObject.score !== 1;\n base.addCategoryEnabled = false;\n base.showKeyLegend = true;\n }\n\n if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {\n base.rationale = rationaleEnabled ? rationale : null;\n base.teacherInstructions = teacherInstructionsEnabled ? teacherInstructions : null;\n } else {\n base.rationale = null;\n base.teacherInstructions = null;\n }\n\n log('base: ', base);\n resolve(base);\n });\n}\n\nexport function outcome(\n model: ChartingModel,\n session: ChartingSession | null | undefined,\n env: ChartingEnvironment,\n): Promise<ChartingOutcome> {\n return new Promise((resolve) => {\n const traceLog = getLogTrace(model, session, env);\n const scoreObject = getScore(model, session, env);\n \n const result: ChartingOutcome = {\n score: scoreObject.score,\n empty: !session || isEmpty(session),\n traceLog\n };\n \n if (env.extraProps && env.extraProps.correctResponseEnabled) {\n result.extraProps = { correctResponse: scoreObject.correctResponses };\n }\n \n resolve(result);\n });\n}\n\nexport const createCorrectResponseSession = (\n question: ChartingModel,\n env: ChartingEnvironment,\n): Promise<ChartingSession | null> => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { correctAnswer } = question;\n\n let answers = correctAnswer && correctAnswer.data;\n\n // for IBX preview mode\n if (env.mode === 'gather') {\n const { data } = question;\n\n answers = ((correctAnswer && correctAnswer.data) || []).map((answer, index) => {\n // Throws when the model has no `data`, as it did untyped.\n return {\n ...(data as ChartingCategory[])[index],\n ...answer,\n };\n });\n }\n\n resolve({\n answer: answers,\n id: '1',\n });\n } else {\n return resolve(null);\n }\n });\n};\n\n// remove all html tags\nconst getInnerText = (html?: string) => (html || '').replaceAll(/<[^>]*>/g, '');\n\n// remove all html tags except img, iframe and source tag for audio\nconst getContent = (html?: string) => (html || '').replace(/(<(?!img|iframe|source)([^>]+)>)/gi, '');\n\nexport const validate = (\n model: Partial<ChartingModel> = {},\n config: ChartingConfiguration = {},\n): ChartingValidationErrors => {\n const { correctAnswer, data } = model || {};\n const { data: correctData } = correctAnswer || {};\n const categories = correctData || [];\n\n const errors: ChartingValidationErrors = {};\n const correctAnswerErrors: NonNullable<ChartingValidationErrors['correctAnswerErrors']> = {};\n const categoryErrors: Record<number, string> = {};\n\n (['teacherInstructions', 'prompt', 'rationale'] as const).forEach((field) => {\n if (config[field]?.required && !getContent(model[field])) {\n errors[field] = 'This field is required.';\n }\n });\n\n categories.forEach((category, index) => {\n const { label } = category;\n\n if (!getInnerText(label)) {\n categoryErrors[index] = 'Content should not be empty. ';\n } else {\n const identicalAnswer = categories.some((c, i) => c.label === label && index !== i);\n\n if (identicalAnswer) {\n categoryErrors[index] = 'Category names should be unique. ';\n }\n }\n });\n\n if (categories.length < 1 || categories.length > 20) {\n correctAnswerErrors.categoriesError = 'The correct answer should include between 1 and 20 categories.';\n } else if (\n isEqual(\n // `data.map` throws when the model has no `data`, as it did untyped.\n (data as ChartingCategory[]).map((category) => pick(category, 'value', 'label')),\n (correctData as ChartingCategory[]).map((category) => pick(category, 'value', 'label')),\n )\n ) {\n correctAnswerErrors.identicalError = 'Correct answer should not be identical to the chart’s initial state';\n }\n\n if (!isEmpty(categoryErrors)) {\n errors.categoryErrors = categoryErrors;\n }\n\n if (!isEmpty(correctAnswerErrors)) {\n errors.correctAnswerErrors = correctAnswerErrors;\n }\n\n return errors;\n};\n"],"mappings":"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"}
@@ -610,7 +610,7 @@ var G = _, K = G.default, q = K && typeof K == "object" ? K : G, me = W(p, "UiLa
610
610
  }
611
611
  }, ye = Object.freeze({
612
612
  name: "@pie-element/charting",
613
- version: "13.0.8-next.20261024044430"
613
+ version: "13.0.8-next.20261024053312"
614
614
  });
615
615
  //#endregion
616
616
  export { Q as Component, ve as default, ye as piePackage };
@@ -3202,7 +3202,7 @@ var Dr = class e extends CustomEvent {
3202
3202
  }
3203
3203
  }, mi = Object.freeze({
3204
3204
  name: "@pie-element/charting",
3205
- version: "13.0.8-next.20261024044430"
3205
+ version: "13.0.8-next.20261024053312"
3206
3206
  });
3207
3207
  //#endregion
3208
3208
  export { pi as default, mi as piePackage };
@@ -40,29 +40,68 @@ var a = /* @__PURE__ */ e(i(), 1), o = {
40
40
  function l(e, t, n) {
41
41
  return e?.partialScoring === !1 || t?.partialScoring === !1 ? !1 : typeof n != "boolean" || n;
42
42
  }
43
- //#endregion
44
- //#region src/controller/index.ts
45
- var u = (0, a.default)("@pie-element:graphing:controller"), d = (e) => (e || "").toLowerCase(), f = (e, t) => d(e) === d(t), p = (e, t) => e ? e.map((e) => ({
43
+ var u = /[\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069\u0640]/g, d = /[\uFB50-\uFDFF\uFE70-\uFEFC]+/g, f = /\p{Nd}/u, p = /(?![0-9])\p{Nd}/gu, m = /\u066B/g, h = /\u066C/g, g = /[\u0622\u0623\u0625\u0671]/g, _ = /[\u064B-\u065F\u0670]/g, v = /* @__PURE__ */ new Map(), y = (e) => {
44
+ let t = v.get(e);
45
+ if (t !== void 0) return t;
46
+ let n = 0;
47
+ for (; f.test(String.fromCodePoint(e - n - 1));) n++;
48
+ let r = n % 10;
49
+ return v.set(e, r), r;
50
+ }, b = (e) => e.replace(p, (e) => String(y(e.codePointAt(0)))), x = {
51
+ decimal: ".",
52
+ group: ","
53
+ }, S = /* @__PURE__ */ new Map(), C = (e) => {
54
+ if (!e) return x;
55
+ let t = S.get(e);
56
+ if (t) return t;
57
+ let n = x;
58
+ try {
59
+ if (Intl.NumberFormat.supportedLocalesOf(e).length > 0) {
60
+ let t = new Intl.NumberFormat(e, { numberingSystem: "latn" }).formatToParts(12345.6);
61
+ n = {
62
+ decimal: t.find((e) => e.type === "decimal")?.value ?? ".",
63
+ group: t.find((e) => e.type === "group")?.value ?? ","
64
+ };
65
+ }
66
+ } catch {}
67
+ return S.set(e, n), n;
68
+ }, w = (e, t) => {
69
+ let n = [e?.language, t?.locale];
70
+ for (let e of n) if (typeof e == "string" && e.trim()) return e.trim().replace(/_/g, "-");
71
+ }, T = /^(tr|az)(-|$)/i, E = (e, t) => {
72
+ if (!t || !T.test(t)) return e.toLowerCase();
73
+ try {
74
+ return e.toLocaleLowerCase(t);
75
+ } catch {
76
+ return e.toLowerCase();
77
+ }
78
+ }, D = (e, t = {}) => {
79
+ let n = C(t.language), r = (t.ignoreCase ? E(e, t.language) : e).replace(u, "").replace(d, (e) => e.normalize("NFKC")).normalize("NFC");
80
+ return r = b(r).replace(m, n.decimal).replace(h, n.group), t.foldLetterVariants && (r = r.replace(_, "").replace(g, "ا").replace(/\u0629/g, "ه").replace(/\u0649/g, "ي")), r;
81
+ }, O = (0, a.default)("@pie-element:graphing:controller"), k = (e, t) => D(e || "", {
82
+ language: t,
83
+ ignoreCase: !0
84
+ }), A = (e, t, n) => k(e, n) === k(t, n), j = (e, t) => e ? e.map((e) => ({
46
85
  ...e,
47
86
  correctness: {
48
87
  value: t ? "incorrect" : "correct",
49
88
  label: t ? "incorrect" : "correct"
50
89
  }
51
- })) : [], m = (e) => ({
90
+ })) : [], M = (e) => ({
52
91
  ...o,
53
92
  ...e
54
- }), h = (e, t, n = {}) => {
55
- let { correctAnswer: r, data: i = [], scoringType: a } = e, o = [], s = c.enabled({ partialScoring: a === void 0 ? a : a === "partial scoring" }, n), { data: l = [] } = r || {}, u = _(i), m = p(t && t.answer || u, s), h = 0;
56
- if (s) {
93
+ }), N = (e, t, n = {}) => {
94
+ let { correctAnswer: r, data: i = [], scoringType: a } = e, o = [], s = w(e, n), l = c.enabled({ partialScoring: a === void 0 ? a : a === "partial scoring" }, n), { data: u = [] } = r || {}, d = F(i), f = j(t && t.answer || d, l), p = 0;
95
+ if (l) {
57
96
  let e = 0, t = 0, n = (n, r) => {
58
- let { value: i, label: a, index: s } = n, c = i === r.value, l = f(a, r.label);
59
- e += 2, c && (t += 1, n.correctness.value = "correct"), l && (t += 1, n.correctness.label = "correct"), c && l && o.push({
97
+ let { value: i, label: a, index: c } = n, l = i === r.value, u = A(a, r.label, s);
98
+ e += 2, l && (t += 1, n.correctness.value = "correct"), u && (t += 1, n.correctness.label = "correct"), l && u && o.push({
60
99
  label: a,
61
- index: s
100
+ index: c
62
101
  });
63
102
  };
64
- l.forEach((r, i) => {
65
- let a = u[i], s = m[i];
103
+ u.forEach((r, i) => {
104
+ let a = d[i], s = f[i];
66
105
  s ? a ? !a.editable && s.interactive ? (e += 1, s.value === r.value && (t += 1, s.correctness.value = "correct", o.push({
67
106
  label: s.label,
68
107
  index: i
@@ -70,10 +109,10 @@ var u = (0, a.default)("@pie-element:graphing:controller"), d = (e) => (e || "")
70
109
  label: s.label,
71
110
  index: i
72
111
  })) : n(s, r) : e += 2;
73
- }), h = e ? t / e : 0;
74
- } else h = +(l.length === m.length), m = m.map((e, t) => {
75
- let n = l[t], r = n ? e.value === n.value : !1, i = n ? d(e.label) === d(n.label) : !1;
76
- return (!r || !i) && (h = 0), r && i && o.push({
112
+ }), p = e ? t / e : 0;
113
+ } else p = +(u.length === f.length), f = f.map((e, t) => {
114
+ let n = u[t], r = n ? e.value === n.value : !1, i = n ? A(e.label, n.label, s) : !1;
115
+ return (!r || !i) && (p = 0), r && i && o.push({
77
116
  label: e.label,
78
117
  index: t
79
118
  }), {
@@ -84,23 +123,23 @@ var u = (0, a.default)("@pie-element:graphing:controller"), d = (e) => (e || "")
84
123
  }
85
124
  };
86
125
  });
87
- let g = {
88
- score: parseFloat(h.toFixed(2)),
89
- answers: m
126
+ let m = {
127
+ score: parseFloat(p.toFixed(2)),
128
+ answers: f
90
129
  };
91
- return n.extraProps && n.extraProps.correctResponseEnabled && (g.correctResponses = o), g;
92
- }, g = (e, t, n) => {
93
- let r = [], { correctAnswer: i, data: a = [], scoringType: o } = e || {}, { data: s = [] } = i || {}, l = t && t.answer || [], u = c.enabled({ partialScoring: o === void 0 ? o : o === "partial scoring" }, n), d = _(a), p = l.length > 0 ? _(l) : d;
130
+ return n.extraProps && n.extraProps.correctResponseEnabled && (m.correctResponses = o), m;
131
+ }, P = (e, t, n) => {
132
+ let r = [], { correctAnswer: i, data: a = [], scoringType: o } = e || {}, { data: s = [] } = i || {}, l = t && t.answer || [], u = w(e, n), d = c.enabled({ partialScoring: o === void 0 ? o : o === "partial scoring" }, n), f = F(a), p = l.length > 0 ? F(l) : f;
94
133
  if (l.length || r.push("Student did not modify the chart. Initial chart is scored."), s.forEach((e, t) => {
95
- let n = d[t], i = p[t];
134
+ let n = f[t], i = p[t];
96
135
  if (!i) {
97
136
  r.push(`Category ${t + 1}: missing (expected value '${e.value}', label '${e.label}').`);
98
137
  return;
99
138
  }
100
- let a = i.value === e.value, o = f(i.label, e.label);
139
+ let a = i.value === e.value, o = A(i.label, e.label, u);
101
140
  if (!i.interactive) r.push(`Category ${t + 1}: non-interactive category treated as correct.`);
102
141
  else if (l.length > 0) {
103
- let e = !n || i.value !== n.value, s = !n || !f(i.label, n.label);
142
+ let e = !n || i.value !== n.value, s = !n || !A(i.label, n.label, u);
104
143
  if (!e && !s) {
105
144
  a && o ? r.push(`Category ${t + 1}: unchanged from initial value and correct.`) : r.push(`Category ${t + 1}: unchanged from initial value but incorrect.`);
106
145
  return;
@@ -112,22 +151,22 @@ var u = (0, a.default)("@pie-element:graphing:controller"), d = (e) => (e || "")
112
151
  let e = p.length - s.length;
113
152
  r.push(`${e} extra category(ies) provided beyond expected number.`);
114
153
  }
115
- u ? (r.push("Score calculated using partial scoring."), r.push("Student receives credit for each correct value and label independently.")) : (r.push("Score calculated using all-or-nothing scoring."), r.push("Student must match all category values and labels exactly for full credit."));
116
- let m = h(e, t, n);
154
+ d ? (r.push("Score calculated using partial scoring."), r.push("Student receives credit for each correct value and label independently.")) : (r.push("Score calculated using all-or-nothing scoring."), r.push("Student must match all category values and labels exactly for full credit."));
155
+ let m = N(e, t, n);
117
156
  return r.push(`Score: ${m.score}.`), r;
118
- }, _ = (e) => e ? e.map(({ deletable: e, ...t }) => t) : [];
119
- function v(e, t, n) {
157
+ }, F = (e) => e ? e.map(({ deletable: e, ...t }) => t) : [];
158
+ function I(e, t, n) {
120
159
  return new Promise((r) => {
121
- let i = m(e), { addCategoryEnabled: a, chartType: o, data: s, domain: c, graph: l, prompt: d, promptEnabled: f, range: p, rationale: g, title: v, rationaleEnabled: y, teacherInstructions: b, teacherInstructionsEnabled: x, correctAnswer: S, scoringType: C, studentNewCategoryDefaultLabel: w, language: T, extraCSSRules: E } = i, D = {
160
+ let i = M(e), { addCategoryEnabled: a, chartType: o, data: s, domain: c, graph: l, prompt: u, promptEnabled: d, range: f, rationale: p, title: m, rationaleEnabled: h, teacherInstructions: g, teacherInstructionsEnabled: _, correctAnswer: v, scoringType: y, studentNewCategoryDefaultLabel: b, language: x, extraCSSRules: S } = i, C = {
122
161
  addCategoryEnabled: a,
123
162
  chartType: o,
124
- data: _(s),
163
+ data: F(s),
125
164
  domain: c,
126
165
  graph: l,
127
- prompt: f ? d : null,
128
- range: p,
129
- rationale: g,
130
- title: v,
166
+ prompt: d ? u : null,
167
+ range: f,
168
+ rationale: p,
169
+ title: m,
131
170
  size: l,
132
171
  showToggle: !1,
133
172
  correctness: {
@@ -135,21 +174,21 @@ function v(e, t, n) {
135
174
  score: "0%"
136
175
  },
137
176
  disabled: n.mode !== "gather",
138
- scoringType: C,
139
- studentNewCategoryDefaultLabel: w,
140
- language: T,
177
+ scoringType: y,
178
+ studentNewCategoryDefaultLabel: b,
179
+ language: x,
141
180
  env: n,
142
- extraCSSRules: E
143
- }, O = h(i, t, n), k = _(O.answers);
144
- n.mode === "view" && (D.correctedAnswer = k.map(({ correctness: e, ...t }) => ({
181
+ extraCSSRules: S
182
+ }, w = N(i, t, n), T = F(w.answers);
183
+ n.mode === "view" && (C.correctedAnswer = T.map(({ correctness: e, ...t }) => ({
145
184
  ...t,
146
185
  interactive: !1
147
- })), D.addCategoryEnabled = !1), n.mode === "evaluate" && (D.correctedAnswer = k, D.correctAnswer = S, D.showToggle = !!S?.data?.length && O.score !== 1, D.addCategoryEnabled = !1, D.showKeyLegend = !0), n.role === "instructor" && (n.mode === "view" || n.mode === "evaluate") ? (D.rationale = y ? g : null, D.teacherInstructions = x ? b : null) : (D.rationale = null, D.teacherInstructions = null), u("base: ", D), r(D);
186
+ })), C.addCategoryEnabled = !1), n.mode === "evaluate" && (C.correctedAnswer = T, C.correctAnswer = v, C.showToggle = !!v?.data?.length && w.score !== 1, C.addCategoryEnabled = !1, C.showKeyLegend = !0), n.role === "instructor" && (n.mode === "view" || n.mode === "evaluate") ? (C.rationale = h ? p : null, C.teacherInstructions = _ ? g : null) : (C.rationale = null, C.teacherInstructions = null), O("base: ", C), r(C);
148
187
  });
149
188
  }
150
- function y(e, t, n) {
189
+ function L(e, t, n) {
151
190
  return new Promise((i) => {
152
- let a = g(e, t, n), o = h(e, t, n), s = {
191
+ let a = P(e, t, n), o = N(e, t, n), s = {
153
192
  score: o.score,
154
193
  empty: !t || r(t),
155
194
  traceLog: a
@@ -157,7 +196,7 @@ function y(e, t, n) {
157
196
  n.extraProps && n.extraProps.correctResponseEnabled && (s.extraProps = { correctResponse: o.correctResponses }), i(s);
158
197
  });
159
198
  }
160
- var b = (e, t) => new Promise((n) => {
199
+ var R = (e, t) => new Promise((n) => {
161
200
  if (t.mode !== "evaluate" && t.role === "instructor") {
162
201
  let { correctAnswer: r } = e, i = r && r.data;
163
202
  if (t.mode === "gather") {
@@ -172,23 +211,23 @@ var b = (e, t) => new Promise((n) => {
172
211
  id: "1"
173
212
  });
174
213
  } else return n(null);
175
- }), x = (e) => (e || "").replaceAll(/<[^>]*>/g, ""), S = (e) => (e || "").replace(/(<(?!img|iframe|source)([^>]+)>)/gi, ""), C = (e = {}, i = {}) => {
214
+ }), z = (e) => (e || "").replaceAll(/<[^>]*>/g, ""), B = (e) => (e || "").replace(/(<(?!img|iframe|source)([^>]+)>)/gi, ""), V = (e = {}, i = {}) => {
176
215
  let { correctAnswer: a, data: o } = e || {}, { data: s } = a || {}, c = s || [], l = {}, u = {}, d = {};
177
216
  return [
178
217
  "teacherInstructions",
179
218
  "prompt",
180
219
  "rationale"
181
220
  ].forEach((t) => {
182
- i[t]?.required && !S(e[t]) && (l[t] = "This field is required.");
221
+ i[t]?.required && !B(e[t]) && (l[t] = "This field is required.");
183
222
  }), c.forEach((e, t) => {
184
223
  let { label: n } = e;
185
- x(n) ? c.some((e, r) => e.label === n && t !== r) && (d[t] = "Category names should be unique. ") : d[t] = "Content should not be empty. ";
224
+ z(n) ? c.some((e, r) => e.label === n && t !== r) && (d[t] = "Category names should be unique. ") : d[t] = "Content should not be empty. ";
186
225
  }), c.length < 1 || c.length > 20 ? u.categoriesError = "The correct answer should include between 1 and 20 categories." : t(o.map((e) => n(e, "value", "label")), s.map((e) => n(e, "value", "label"))) && (u.identicalError = "Correct answer should not be identical to the chart’s initial state"), r(d) || (l.categoryErrors = d), r(u) || (l.correctAnswerErrors = u), l;
187
- }, w = Object.freeze({
226
+ }, H = Object.freeze({
188
227
  name: "@pie-element/charting",
189
- version: "13.0.8-next.20261024044430"
228
+ version: "13.0.8-next.20261024053312"
190
229
  });
191
230
  //#endregion
192
- export { f as checkLabelsEquality, b as createCorrectResponseSession, _ as filterCategories, g as getLogTrace, h as getScore, v as model, m as normalize, y as outcome, w as piePackage, p as setCorrectness, C as validate };
231
+ export { A as checkLabelsEquality, R as createCorrectResponseSession, F as filterCategories, P as getLogTrace, N as getScore, I as model, M as normalize, L as outcome, H as piePackage, j as setCorrectness, V as validate };
193
232
 
194
233
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["debug","defaults","partialScoring","isEmpty","isEqual","pick","__toESM","wn","Vn","Cn","require_browser","import_browser","defaults_default","e","s","r","i","t","n","c","log","lowerCase","string","checkLabelsEquality","givenAnswerLabel","correctAnswerLabel","setCorrectness","answers","answer","partialScoring","normalize","question","getScore","initialData","correctResponses","isPartialScoring","scoringType","env","correctAnswers","correctAnswer","defaultAnswers","filterCategories","session","result","maxScore","score","scoreForLabelAndValueEditable","valueIsCorrect","value","corrAnswer","labelIsCorrect","label","defaultAnswer","index","getLogTrace","traceLog","model","studentAnswers","initial","student","correct","valueCorrect","labelCorrect","valueChanged","labelChanged","parts","extra","scoreObject","categories","rest","normalizedQuestion","base","data","promptEnabled","prompt","graph","rationaleEnabled","rationale","teacherInstructionsEnabled","teacherInstructions","resolve","outcome","createCorrectResponseSession","getInnerText","html","getContent","validate","correctData","errors","correctAnswerErrors","categoryErrors","config","field","category","piePackage","\"name\"","\"version\""],"sources":["../../../../src/controller/defaults.ts","../../../../../../shared/controller-utils/dist/index.js","../../../../src/controller/index.ts"],"sourcesContent":["import type { ChartingCategory, ChartingCorrectAnswer, ChartingDomain, ChartingModel } from '../types.js';\n\n/**\n * NOTE: There's no functionality described for graphTitle,\n * rationale, scoringType, studentInstructions, teacherInstructions\n * so there's no implementation (they are only added in model)\n */\n\nexport default {\n addCategoryEnabled: true,\n changeAddCategoryEnabled: false,\n changeEditableEnabled: false,\n changeInteractiveEnabled: false,\n chartType: 'lineCross',\n correctAnswer: {} as ChartingCorrectAnswer,\n data: [] as ChartingCategory[],\n domain: {} as ChartingDomain,\n graph: { width: 480, height: 480 },\n prompt: '',\n promptEnabled: true,\n range: { label: '', max: 1, min: 0, labelStep: 1 },\n rationale: '',\n rationaleEnabled: true,\n scoringType: 'all or nothing',\n studentInstructionsEnabled: true,\n studentNewCategoryDefaultLabel: 'New Category',\n teacherInstructions: '',\n teacherInstructionsEnabled: true,\n title: '',\n} satisfies Omit<ChartingModel, 'id' | 'element'>;\n","//#region \\0rolldown/runtime.js\nvar e = Object.defineProperty, t = (t, n) => {\n\tlet r = {};\n\tfor (var i in t) e(r, i, {\n\t\tget: t[i],\n\t\tenumerable: !0\n\t});\n\treturn n || e(r, Symbol.toStringTag, { value: \"Module\" }), r;\n};\n//#endregion\n//#region src/persistence.ts\nfunction n(e) {\n\treturn Array.isArray(e) ? e.filter((e) => e != null) : [];\n}\nfunction r(e) {\n\tlet t = [...e];\n\tfor (let e = t.length - 1; e > 0; e--) {\n\t\tlet n = Math.floor(Math.random() * (e + 1));\n\t\t[t[e], t[n]] = [t[n], t[e]];\n\t}\n\treturn t;\n}\nfunction i(e) {\n\treturn e == null ? !0 : Array.isArray(e) ? e.length === 0 : typeof e == \"object\" && Object.keys(e).length === 0;\n}\nasync function a(e, t, a, o = \"value\") {\n\tlet s = n(t?.data?.shuffledValues ?? t?.shuffledValues ?? []);\n\tif (!t) {\n\t\tconsole.warn(\"Unable to save shuffled choices because there's no session.\");\n\t\treturn;\n\t}\n\tif (!i(s)) return n(s.map((t) => e.find((e) => e[o] === t)));\n\tlet c = r(e);\n\tif (a && typeof a == \"function\") try {\n\t\tlet e = n(c.map((e) => e[o]));\n\t\ti(e) ? console.error(`shuffledValues is an empty array - refusing to call updateSession. shuffledChoices: ${JSON.stringify(c)}, key: ${o}`) : await a(t.id, t.element, { shuffledValues: e });\n\t} catch (e) {\n\t\tconsole.warn(\"Unable to save shuffled order for choices\"), console.error(e);\n\t}\n\telse console.warn(\"Unable to save shuffled choices, shuffle will happen every time.\");\n\treturn c;\n}\nfunction o(e, t, n) {\n\treturn !!(e.lockChoiceOrder || n?.[\"@pie-element\"]?.lockChoiceOrder);\n}\n//#endregion\n//#region src/partial-scoring.ts\nvar s = /* @__PURE__ */ t({ enabled: () => c });\nfunction c(e, t, n) {\n\treturn e?.partialScoring === !1 || t?.partialScoring === !1 ? !1 : typeof n != \"boolean\" || n;\n}\n//#endregion\nexport { a as getShuffledChoices, o as lockChoices, s as partialScoring };\n","import debug from 'debug';\nimport { isEmpty, isEqual, pick } from '@pie-element/shared-lodash';\nimport type { ExtraCSSRules, PieEnvironment } from '@pie-element/shared-types';\nimport defaults from './defaults.js';\n\nimport { partialScoring } from '@pie-element/shared-controller-utils';\nimport type {\n ChartingCategory,\n ChartingCategoryCorrectness,\n ChartingConfiguration,\n ChartingCorrectAnswer,\n ChartingModel,\n ChartingSession,\n} from '../types.js';\n\n/** The environment, plus the extra properties a host may ask the outcome for */\nexport type ChartingEnvironment = PieEnvironment & { extraProps?: { correctResponseEnabled?: boolean } };\n\n/** A category marked correct or incorrect */\nexport type ScoredCategory = ChartingCategory & { correctness: ChartingCategoryCorrectness };\n\n/** A category whose value and label both match the correct answer */\nexport type ChartingCorrectResponse = { label: string; index?: number };\n\nexport type ChartingScore = {\n score: number;\n answers: ScoredCategory[];\n correctResponses?: ChartingCorrectResponse[];\n};\n\nexport type ChartingValidationErrors = {\n teacherInstructions?: string;\n prompt?: string;\n rationale?: string;\n /** Category errors of the correct answer, keyed by category position */\n categoryErrors?: Record<number, string>;\n correctAnswerErrors?: {\n categoriesError?: string;\n identicalError?: string;\n };\n};\n\n/** What `model()` returns for the delivery view */\nexport type ChartingViewModel = {\n addCategoryEnabled?: boolean;\n chartType?: ChartingModel['chartType'];\n data: Omit<ChartingCategory, 'deletable'>[];\n domain?: ChartingModel['domain'];\n graph?: ChartingModel['graph'];\n prompt?: string | null;\n range?: ChartingModel['range'];\n rationale?: string | null;\n title?: string;\n size?: ChartingModel['graph'];\n showToggle: boolean;\n correctness: { correctness: string; score: string };\n disabled: boolean;\n scoringType?: ChartingModel['scoringType'];\n studentNewCategoryDefaultLabel?: string;\n language?: string;\n env: ChartingEnvironment;\n extraCSSRules?: ExtraCSSRules;\n correctedAnswer?: Omit<ChartingCategory, 'deletable'>[];\n correctAnswer?: ChartingCorrectAnswer;\n showKeyLegend?: boolean;\n teacherInstructions?: string | null;\n};\n\ntype ChartingOutcome = {\n score: number;\n empty: boolean;\n traceLog: string[];\n extraProps?: { correctResponse?: ChartingCorrectResponse[] };\n};\n\nconst log = debug('@pie-element:graphing:controller');\n\nconst lowerCase = (string?: string) => (string || '').toLowerCase();\n\nexport const checkLabelsEquality = (givenAnswerLabel?: string, correctAnswerLabel?: string) =>\n lowerCase(givenAnswerLabel) === lowerCase(correctAnswerLabel);\n\nexport const setCorrectness = (answers: ChartingCategory[] | undefined, partialScoring: boolean): ScoredCategory[] =>\n answers\n ? answers.map((answer) => ({\n ...answer,\n correctness: {\n value: partialScoring ? 'incorrect' : 'correct',\n label: partialScoring ? 'incorrect' : 'correct',\n },\n }))\n : [];\n\nexport const normalize = (question: ChartingModel) => ({ ...defaults, ...question });\n\nexport const getScore = (\n question: ChartingModel,\n session: ChartingSession | null | undefined,\n env: Partial<ChartingEnvironment> = {},\n): ChartingScore => {\n const { correctAnswer, data: initialData = [], scoringType } = question;\n const correctResponses: ChartingCorrectResponse[] = [];\n\n const isPartialScoring = partialScoring.enabled(\n { partialScoring: scoringType !== undefined ? scoringType === 'partial scoring' : scoringType },\n env,\n );\n\n const { data: correctAnswers = [] } = correctAnswer || {};\n const defaultAnswers = filterCategories(initialData);\n\n let answers = setCorrectness((session && session.answer) || defaultAnswers, isPartialScoring);\n\n let result = 0;\n\n if (isPartialScoring) {\n // if score type is \"partial scoring\"\n // maxScore is calculated based on the correct response\n // score is calculated based on the given response\n let maxScore = 0;\n let score = 0;\n\n const scoreForLabelAndValueEditable = (answer: ScoredCategory, corrAnswer: ChartingCategory) => {\n const { value, label, index } = answer;\n const valueIsCorrect = value === corrAnswer.value;\n const labelIsCorrect = checkLabelsEquality(label, corrAnswer.label);\n maxScore += 2;\n\n if (valueIsCorrect) {\n score += 1;\n answer.correctness.value = 'correct';\n }\n\n if (labelIsCorrect) {\n score += 1;\n answer.correctness.label = 'correct';\n }\n\n if (valueIsCorrect && labelIsCorrect) {\n correctResponses.push({ label: label, index: index });\n }\n };\n\n // if given answer has more categories than the correct answers, the \"extra\" will be ignored\n correctAnswers.forEach((corrAnswer, index) => {\n const defaultAnswer = defaultAnswers[index];\n const answer = answers[index];\n\n // if there is a corresponding category at the same position in the given answer\n if (answer) {\n // if there is a corresponding category at the same position in the default answer\n if (defaultAnswer) {\n // if category's label (in default answer) was not editable\n // it means that this category values only one point (only the value can be changed)\n if (!defaultAnswer.editable && answer.interactive) {\n maxScore += 1;\n\n if (answer.value === corrAnswer.value) {\n score += 1;\n answer.correctness.value = 'correct';\n correctResponses.push({ label: answer.label, index: index });\n }\n answer.correctness.label = 'correct';\n\n // if category's label (in default answer) was editable\n // it means that this category values 2 points (both label and value can be changed)\n } else if (defaultAnswer.editable && answer.interactive) {\n scoreForLabelAndValueEditable(answer, corrAnswer);\n } else if (!answer.interactive) {\n answer.correctness.value = 'correct';\n answer.correctness.label = 'correct';\n correctResponses.push({ label: answer.label, index: index });\n }\n } else {\n // if there is not a corresponding category at the same position in the default answer\n scoreForLabelAndValueEditable(answer, corrAnswer);\n }\n } else {\n // if there is not a corresponding category at the same position in the given answer\n // it means that the given answer has less categories than the correct answer\n maxScore += 2;\n }\n });\n\n result = maxScore ? score / maxScore : 0;\n } else {\n // all-or-nothing scoring: overall score is 1 only if lengths and all values/labels match\n result = correctAnswers.length === answers.length ? 1 : 0;\n\n // regardless of overall result, mark each answer individually for user feedback\n answers = answers.map((answer, index): ScoredCategory => {\n const correctAnswer = correctAnswers[index];\n const valueIsCorrect = correctAnswer ? answer.value === correctAnswer.value : false;\n const labelIsCorrect = correctAnswer ? lowerCase(answer.label) === lowerCase(correctAnswer.label) : false;\n\n if (!valueIsCorrect || !labelIsCorrect) {\n result = 0;\n }\n\n if (valueIsCorrect && labelIsCorrect) {\n correctResponses.push({ label: answer.label, index });\n }\n\n return {\n ...answer,\n correctness: {\n value: valueIsCorrect ? 'correct' : 'incorrect',\n label: labelIsCorrect ? 'correct' : 'incorrect',\n },\n };\n });\n }\n\n const score: ChartingScore = {\n score: parseFloat(result.toFixed(2)),\n answers,\n };\n\n if (env.extraProps && env.extraProps.correctResponseEnabled) {\n score.correctResponses = correctResponses;\n }\n\n return score;\n};\n\n/**\n * Generates detailed trace log for scoring evaluation\n * @param {Object} model - the question model\n * @param {Object} session - the student session\n * @param {Object} env - the environment\n * @returns {Array} traceLog - array of trace messages\n */\nexport const getLogTrace = (\n model: ChartingModel,\n session: ChartingSession | null | undefined,\n env: ChartingEnvironment,\n): string[] => {\n const traceLog: string[] = [];\n\n const { correctAnswer, data: initialData = [], scoringType } = model || {};\n const { data: correctAnswers = [] } = correctAnswer || {};\n const studentAnswers = (session && session.answer) || [];\n\n const isPartialScoring = partialScoring.enabled(\n { partialScoring: scoringType !== undefined ? scoringType === 'partial scoring' : scoringType },\n env\n );\n\n const defaultAnswers = filterCategories(initialData);\n const answers = studentAnswers.length > 0 ? filterCategories(studentAnswers) : defaultAnswers;\n\n if (!studentAnswers.length) {\n traceLog.push(`Student did not modify the chart. Initial chart is scored.`);\n }\n\n correctAnswers.forEach((correct, index) => {\n const initial = defaultAnswers[index];\n const student = answers[index];\n\n if (!student) {\n traceLog.push(`Category ${index + 1}: missing (expected value '${correct.value}', label '${correct.label}').`);\n return;\n }\n\n const valueCorrect = student.value === correct.value;\n const labelCorrect = checkLabelsEquality(student.label, correct.label);\n\n if (!student.interactive) {\n traceLog.push(`Category ${index + 1}: non-interactive category treated as correct.`);\n return;\n }\n\n if (studentAnswers.length > 0) {\n const valueChanged = initial ? student.value !== initial.value : true;\n const labelChanged = initial ? !checkLabelsEquality(student.label, initial.label) : true;\n\n if (!valueChanged && !labelChanged) {\n if (valueCorrect && labelCorrect) {\n traceLog.push(`Category ${index + 1}: unchanged from initial value and correct.`);\n } else {\n traceLog.push(`Category ${index + 1}: unchanged from initial value but incorrect.`);\n }\n return;\n }\n\n const parts: string[] = [];\n if (valueChanged) {\n parts.push(`value ${valueCorrect ? 'correct' : 'incorrect'}`);\n }\n if (labelChanged) {\n parts.push(`label ${labelCorrect ? 'correct' : 'incorrect'}`);\n }\n traceLog.push(`Category ${index + 1}: modified - ${parts.join(', ')}.`);\n } else {\n if (valueCorrect && labelCorrect) {\n traceLog.push(`Category ${index + 1}: initial values are correct.`);\n } else if (valueCorrect) {\n traceLog.push(`Category ${index + 1}: initial value correct, label incorrect.`);\n } else if (labelCorrect) {\n traceLog.push(`Category ${index + 1}: initial value incorrect, label correct.`);\n } else {\n traceLog.push(`Category ${index + 1}: initial value and label incorrect.`);\n }\n }\n });\n\n if (answers.length > correctAnswers.length) {\n const extra = answers.length - correctAnswers.length;\n traceLog.push(`${extra} extra category(ies) provided beyond expected number.`);\n }\n\n if (isPartialScoring) {\n traceLog.push('Score calculated using partial scoring.');\n traceLog.push('Student receives credit for each correct value and label independently.');\n } else {\n traceLog.push('Score calculated using all-or-nothing scoring.');\n traceLog.push('Student must match all category values and labels exactly for full credit.');\n }\n\n const scoreObject = getScore(model, session, env);\n traceLog.push(`Score: ${scoreObject.score}.`);\n\n return traceLog;\n};\n\n\n// eslint-disable-next-line no-unused-vars\nexport const filterCategories = <T extends ChartingCategory>(categories?: T[]): Omit<T, 'deletable'>[] =>\n categories ? categories.map(({ deletable, ...rest }) => rest) : [];\n\nexport function model(\n question: ChartingModel,\n session: ChartingSession | null | undefined,\n env: ChartingEnvironment,\n): Promise<ChartingViewModel> {\n return new Promise((resolve) => {\n const normalizedQuestion = normalize(question);\n const {\n addCategoryEnabled,\n chartType,\n data,\n domain,\n graph,\n prompt,\n promptEnabled,\n range,\n rationale,\n title,\n rationaleEnabled,\n teacherInstructions,\n teacherInstructionsEnabled,\n correctAnswer,\n scoringType,\n studentNewCategoryDefaultLabel,\n language,\n extraCSSRules,\n } = normalizedQuestion;\n\n const correctInfo = { correctness: 'incorrect', score: '0%' };\n\n const base: ChartingViewModel = {\n addCategoryEnabled,\n chartType,\n data: filterCategories(data),\n domain,\n graph,\n prompt: promptEnabled ? prompt : null,\n range,\n rationale,\n title,\n size: graph,\n showToggle: false,\n correctness: correctInfo,\n disabled: env.mode !== 'gather',\n scoringType,\n studentNewCategoryDefaultLabel,\n language,\n env,\n extraCSSRules,\n };\n\n const scoreObject = getScore(normalizedQuestion, session, env);\n const answers = filterCategories(scoreObject.answers);\n\n if (env.mode === 'view') {\n // eslint-disable-next-line no-unused-vars\n base.correctedAnswer = answers.map(({ correctness, ...rest }) => {\n return { ...rest, interactive: false };\n });\n\n base.addCategoryEnabled = false;\n }\n\n if (env.mode === 'evaluate') {\n base.correctedAnswer = answers;\n base.correctAnswer = correctAnswer;\n base.showToggle = !!correctAnswer?.data?.length && scoreObject.score !== 1;\n base.addCategoryEnabled = false;\n base.showKeyLegend = true;\n }\n\n if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {\n base.rationale = rationaleEnabled ? rationale : null;\n base.teacherInstructions = teacherInstructionsEnabled ? teacherInstructions : null;\n } else {\n base.rationale = null;\n base.teacherInstructions = null;\n }\n\n log('base: ', base);\n resolve(base);\n });\n}\n\nexport function outcome(\n model: ChartingModel,\n session: ChartingSession | null | undefined,\n env: ChartingEnvironment,\n): Promise<ChartingOutcome> {\n return new Promise((resolve) => {\n const traceLog = getLogTrace(model, session, env);\n const scoreObject = getScore(model, session, env);\n \n const result: ChartingOutcome = {\n score: scoreObject.score,\n empty: !session || isEmpty(session),\n traceLog\n };\n \n if (env.extraProps && env.extraProps.correctResponseEnabled) {\n result.extraProps = { correctResponse: scoreObject.correctResponses };\n }\n \n resolve(result);\n });\n}\n\nexport const createCorrectResponseSession = (\n question: ChartingModel,\n env: ChartingEnvironment,\n): Promise<ChartingSession | null> => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { correctAnswer } = question;\n\n let answers = correctAnswer && correctAnswer.data;\n\n // for IBX preview mode\n if (env.mode === 'gather') {\n const { data } = question;\n\n answers = ((correctAnswer && correctAnswer.data) || []).map((answer, index) => {\n // Throws when the model has no `data`, as it did untyped.\n return {\n ...(data as ChartingCategory[])[index],\n ...answer,\n };\n });\n }\n\n resolve({\n answer: answers,\n id: '1',\n });\n } else {\n return resolve(null);\n }\n });\n};\n\n// remove all html tags\nconst getInnerText = (html?: string) => (html || '').replaceAll(/<[^>]*>/g, '');\n\n// remove all html tags except img, iframe and source tag for audio\nconst getContent = (html?: string) => (html || '').replace(/(<(?!img|iframe|source)([^>]+)>)/gi, '');\n\nexport const validate = (\n model: Partial<ChartingModel> = {},\n config: ChartingConfiguration = {},\n): ChartingValidationErrors => {\n const { correctAnswer, data } = model || {};\n const { data: correctData } = correctAnswer || {};\n const categories = correctData || [];\n\n const errors: ChartingValidationErrors = {};\n const correctAnswerErrors: NonNullable<ChartingValidationErrors['correctAnswerErrors']> = {};\n const categoryErrors: Record<number, string> = {};\n\n (['teacherInstructions', 'prompt', 'rationale'] as const).forEach((field) => {\n if (config[field]?.required && !getContent(model[field])) {\n errors[field] = 'This field is required.';\n }\n });\n\n categories.forEach((category, index) => {\n const { label } = category;\n\n if (!getInnerText(label)) {\n categoryErrors[index] = 'Content should not be empty. ';\n } else {\n const identicalAnswer = categories.some((c, i) => c.label === label && index !== i);\n\n if (identicalAnswer) {\n categoryErrors[index] = 'Category names should be unique. ';\n }\n }\n });\n\n if (categories.length < 1 || categories.length > 20) {\n correctAnswerErrors.categoriesError = 'The correct answer should include between 1 and 20 categories.';\n } else if (\n isEqual(\n // `data.map` throws when the model has no `data`, as it did untyped.\n (data as ChartingCategory[]).map((category) => pick(category, 'value', 'label')),\n (correctData as ChartingCategory[]).map((category) => pick(category, 'value', 'label')),\n )\n ) {\n correctAnswerErrors.identicalError = 'Correct answer should not be identical to the chart’s initial state';\n }\n\n if (!isEmpty(categoryErrors)) {\n errors.categoryErrors = categoryErrors;\n }\n\n if (!isEmpty(correctAnswerErrors)) {\n errors.correctAnswerErrors = correctAnswerErrors;\n }\n\n return errors;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["debug","normalizeResponse","defaults","contentLanguage","partialScoring","isEmpty","isEqual","pick","__toESM","wn","Vn","Cn","require_browser","import_browser","defaults_default","e","s","r","i","t","n","c","l","u","d","f","p","m","h","g","_","v","y","b","x","S","C","w","T","E","log","comparableLabel","label","checkLabelsEquality","givenAnswerLabel","language","correctAnswerLabel","setCorrectness","answers","answer","partialScoring","normalize","question","getScore","initialData","correctResponses","env","isPartialScoring","scoringType","correctAnswers","correctAnswer","defaultAnswers","filterCategories","session","result","maxScore","score","scoreForLabelAndValueEditable","valueIsCorrect","value","corrAnswer","labelIsCorrect","defaultAnswer","index","getLogTrace","traceLog","model","studentAnswers","initial","student","correct","valueCorrect","labelCorrect","valueChanged","labelChanged","parts","extra","scoreObject","categories","rest","normalizedQuestion","base","data","promptEnabled","prompt","graph","rationaleEnabled","rationale","teacherInstructionsEnabled","teacherInstructions","resolve","outcome","createCorrectResponseSession","getInnerText","html","getContent","validate","correctData","errors","correctAnswerErrors","categoryErrors","config","field","category","piePackage","\"name\"","\"version\""],"sources":["../../../../src/controller/defaults.ts","../../../../../../shared/controller-utils/dist/index.js","../../../../src/controller/index.ts"],"sourcesContent":["import type { ChartingCategory, ChartingCorrectAnswer, ChartingDomain, ChartingModel } from '../types.js';\n\n/**\n * NOTE: There's no functionality described for graphTitle,\n * rationale, scoringType, studentInstructions, teacherInstructions\n * so there's no implementation (they are only added in model)\n */\n\nexport default {\n addCategoryEnabled: true,\n changeAddCategoryEnabled: false,\n changeEditableEnabled: false,\n changeInteractiveEnabled: false,\n chartType: 'lineCross',\n correctAnswer: {} as ChartingCorrectAnswer,\n data: [] as ChartingCategory[],\n domain: {} as ChartingDomain,\n graph: { width: 480, height: 480 },\n prompt: '',\n promptEnabled: true,\n range: { label: '', max: 1, min: 0, labelStep: 1 },\n rationale: '',\n rationaleEnabled: true,\n scoringType: 'all or nothing',\n studentInstructionsEnabled: true,\n studentNewCategoryDefaultLabel: 'New Category',\n teacherInstructions: '',\n teacherInstructionsEnabled: true,\n title: '',\n} satisfies Omit<ChartingModel, 'id' | 'element'>;\n","//#region \\0rolldown/runtime.js\nvar e = Object.defineProperty, t = (t, n) => {\n\tlet r = {};\n\tfor (var i in t) e(r, i, {\n\t\tget: t[i],\n\t\tenumerable: !0\n\t});\n\treturn n || e(r, Symbol.toStringTag, { value: \"Module\" }), r;\n};\n//#endregion\n//#region src/persistence.ts\nfunction n(e) {\n\treturn Array.isArray(e) ? e.filter((e) => e != null) : [];\n}\nfunction r(e) {\n\tlet t = [...e];\n\tfor (let e = t.length - 1; e > 0; e--) {\n\t\tlet n = Math.floor(Math.random() * (e + 1));\n\t\t[t[e], t[n]] = [t[n], t[e]];\n\t}\n\treturn t;\n}\nfunction i(e) {\n\treturn e == null ? !0 : Array.isArray(e) ? e.length === 0 : typeof e == \"object\" && Object.keys(e).length === 0;\n}\nasync function a(e, t, a, o = \"value\") {\n\tlet s = n(t?.data?.shuffledValues ?? t?.shuffledValues ?? []);\n\tif (!t) {\n\t\tconsole.warn(\"Unable to save shuffled choices because there's no session.\");\n\t\treturn;\n\t}\n\tif (!i(s)) return n(s.map((t) => e.find((e) => e[o] === t)));\n\tlet c = r(e);\n\tif (a && typeof a == \"function\") try {\n\t\tlet e = n(c.map((e) => e[o]));\n\t\ti(e) ? console.error(`shuffledValues is an empty array - refusing to call updateSession. shuffledChoices: ${JSON.stringify(c)}, key: ${o}`) : await a(t.id, t.element, { shuffledValues: e });\n\t} catch (e) {\n\t\tconsole.warn(\"Unable to save shuffled order for choices\"), console.error(e);\n\t}\n\telse console.warn(\"Unable to save shuffled choices, shuffle will happen every time.\");\n\treturn c;\n}\nfunction o(e, t, n) {\n\treturn !!(e.lockChoiceOrder || n?.[\"@pie-element\"]?.lockChoiceOrder);\n}\n//#endregion\n//#region src/partial-scoring.ts\nvar s = /* @__PURE__ */ t({ enabled: () => c });\nfunction c(e, t, n) {\n\treturn e?.partialScoring === !1 || t?.partialScoring === !1 ? !1 : typeof n != \"boolean\" || n;\n}\n//#endregion\n//#region src/response-normalizer.ts\nvar l = /[\\u061C\\u200E\\u200F\\u202A-\\u202E\\u2066-\\u2069\\u0640]/g, u = /[\\uFB50-\\uFDFF\\uFE70-\\uFEFC]+/g, d = /\\p{Nd}/u, f = /(?![0-9])\\p{Nd}/gu, p = /\\u066B/g, m = /\\u066C/g, h = /[\\u0622\\u0623\\u0625\\u0671]/g, g = /[\\u064B-\\u065F\\u0670]/g, _ = /* @__PURE__ */ new Map(), v = (e) => {\n\tlet t = _.get(e);\n\tif (t !== void 0) return t;\n\tlet n = 0;\n\tfor (; d.test(String.fromCodePoint(e - n - 1));) n++;\n\tlet r = n % 10;\n\treturn _.set(e, r), r;\n}, y = (e) => e.replace(f, (e) => String(v(e.codePointAt(0)))), b = {\n\tdecimal: \".\",\n\tgroup: \",\"\n}, x = /* @__PURE__ */ new Map(), S = (e) => {\n\tif (!e) return b;\n\tlet t = x.get(e);\n\tif (t) return t;\n\tlet n = b;\n\ttry {\n\t\tif (Intl.NumberFormat.supportedLocalesOf(e).length > 0) {\n\t\t\tlet t = new Intl.NumberFormat(e, { numberingSystem: \"latn\" }).formatToParts(12345.6);\n\t\t\tn = {\n\t\t\t\tdecimal: t.find((e) => e.type === \"decimal\")?.value ?? \".\",\n\t\t\t\tgroup: t.find((e) => e.type === \"group\")?.value ?? \",\"\n\t\t\t};\n\t\t}\n\t} catch {}\n\treturn x.set(e, n), n;\n}, C = (e, t) => {\n\tlet n = [e?.language, t?.locale];\n\tfor (let e of n) if (typeof e == \"string\" && e.trim()) return e.trim().replace(/_/g, \"-\");\n}, w = /^(tr|az)(-|$)/i, T = (e, t) => {\n\tif (!t || !w.test(t)) return e.toLowerCase();\n\ttry {\n\t\treturn e.toLocaleLowerCase(t);\n\t} catch {\n\t\treturn e.toLowerCase();\n\t}\n}, E = (e, t = {}) => {\n\tlet n = S(t.language), r = (t.ignoreCase ? T(e, t.language) : e).replace(l, \"\").replace(u, (e) => e.normalize(\"NFKC\")).normalize(\"NFC\");\n\treturn r = y(r).replace(p, n.decimal).replace(m, n.group), t.foldLetterVariants && (r = r.replace(g, \"\").replace(h, \"ا\").replace(/\\u0629/g, \"ه\").replace(/\\u0649/g, \"ي\")), r;\n};\n//#endregion\nexport { C as contentLanguage, T as foldCase, y as foldDigits, a as getShuffledChoices, o as lockChoices, E as normalizeResponse, s as partialScoring };\n","import debug from 'debug';\nimport { isEmpty, isEqual, pick } from '@pie-element/shared-lodash';\nimport type { ExtraCSSRules, PieEnvironment } from '@pie-element/shared-types';\nimport defaults from './defaults.js';\n\nimport { contentLanguage, normalizeResponse, partialScoring } from '@pie-element/shared-controller-utils';\nimport type {\n ChartingCategory,\n ChartingCategoryCorrectness,\n ChartingConfiguration,\n ChartingCorrectAnswer,\n ChartingModel,\n ChartingSession,\n} from '../types.js';\n\n/** The environment, plus the extra properties a host may ask the outcome for */\nexport type ChartingEnvironment = PieEnvironment & { extraProps?: { correctResponseEnabled?: boolean } };\n\n/** A category marked correct or incorrect */\nexport type ScoredCategory = ChartingCategory & { correctness: ChartingCategoryCorrectness };\n\n/** A category whose value and label both match the correct answer */\nexport type ChartingCorrectResponse = { label: string; index?: number };\n\nexport type ChartingScore = {\n score: number;\n answers: ScoredCategory[];\n correctResponses?: ChartingCorrectResponse[];\n};\n\nexport type ChartingValidationErrors = {\n teacherInstructions?: string;\n prompt?: string;\n rationale?: string;\n /** Category errors of the correct answer, keyed by category position */\n categoryErrors?: Record<number, string>;\n correctAnswerErrors?: {\n categoriesError?: string;\n identicalError?: string;\n };\n};\n\n/** What `model()` returns for the delivery view */\nexport type ChartingViewModel = {\n addCategoryEnabled?: boolean;\n chartType?: ChartingModel['chartType'];\n data: Omit<ChartingCategory, 'deletable'>[];\n domain?: ChartingModel['domain'];\n graph?: ChartingModel['graph'];\n prompt?: string | null;\n range?: ChartingModel['range'];\n rationale?: string | null;\n title?: string;\n size?: ChartingModel['graph'];\n showToggle: boolean;\n correctness: { correctness: string; score: string };\n disabled: boolean;\n scoringType?: ChartingModel['scoringType'];\n studentNewCategoryDefaultLabel?: string;\n language?: string;\n env: ChartingEnvironment;\n extraCSSRules?: ExtraCSSRules;\n correctedAnswer?: Omit<ChartingCategory, 'deletable'>[];\n correctAnswer?: ChartingCorrectAnswer;\n showKeyLegend?: boolean;\n teacherInstructions?: string | null;\n};\n\ntype ChartingOutcome = {\n score: number;\n empty: boolean;\n traceLog: string[];\n extraProps?: { correctResponse?: ChartingCorrectResponse[] };\n};\n\nconst log = debug('@pie-element:graphing:controller');\n\n/** A label's comparable form: normalized, and case folded in the content language. */\nconst comparableLabel = (label: string | undefined, language: string | undefined) =>\n normalizeResponse(label || '', { language, ignoreCase: true });\n\nexport const checkLabelsEquality = (givenAnswerLabel?: string, correctAnswerLabel?: string, language?: string) =>\n comparableLabel(givenAnswerLabel, language) === comparableLabel(correctAnswerLabel, language);\n\nexport const setCorrectness = (answers: ChartingCategory[] | undefined, partialScoring: boolean): ScoredCategory[] =>\n answers\n ? answers.map((answer) => ({\n ...answer,\n correctness: {\n value: partialScoring ? 'incorrect' : 'correct',\n label: partialScoring ? 'incorrect' : 'correct',\n },\n }))\n : [];\n\nexport const normalize = (question: ChartingModel) => ({ ...defaults, ...question });\n\nexport const getScore = (\n question: ChartingModel,\n session: ChartingSession | null | undefined,\n env: Partial<ChartingEnvironment> = {},\n): ChartingScore => {\n const { correctAnswer, data: initialData = [], scoringType } = question;\n const correctResponses: ChartingCorrectResponse[] = [];\n const language = contentLanguage(question, env);\n\n const isPartialScoring = partialScoring.enabled(\n { partialScoring: scoringType !== undefined ? scoringType === 'partial scoring' : scoringType },\n env,\n );\n\n const { data: correctAnswers = [] } = correctAnswer || {};\n const defaultAnswers = filterCategories(initialData);\n\n let answers = setCorrectness((session && session.answer) || defaultAnswers, isPartialScoring);\n\n let result = 0;\n\n if (isPartialScoring) {\n // if score type is \"partial scoring\"\n // maxScore is calculated based on the correct response\n // score is calculated based on the given response\n let maxScore = 0;\n let score = 0;\n\n const scoreForLabelAndValueEditable = (answer: ScoredCategory, corrAnswer: ChartingCategory) => {\n const { value, label, index } = answer;\n const valueIsCorrect = value === corrAnswer.value;\n const labelIsCorrect = checkLabelsEquality(label, corrAnswer.label, language);\n maxScore += 2;\n\n if (valueIsCorrect) {\n score += 1;\n answer.correctness.value = 'correct';\n }\n\n if (labelIsCorrect) {\n score += 1;\n answer.correctness.label = 'correct';\n }\n\n if (valueIsCorrect && labelIsCorrect) {\n correctResponses.push({ label: label, index: index });\n }\n };\n\n // if given answer has more categories than the correct answers, the \"extra\" will be ignored\n correctAnswers.forEach((corrAnswer, index) => {\n const defaultAnswer = defaultAnswers[index];\n const answer = answers[index];\n\n // if there is a corresponding category at the same position in the given answer\n if (answer) {\n // if there is a corresponding category at the same position in the default answer\n if (defaultAnswer) {\n // if category's label (in default answer) was not editable\n // it means that this category values only one point (only the value can be changed)\n if (!defaultAnswer.editable && answer.interactive) {\n maxScore += 1;\n\n if (answer.value === corrAnswer.value) {\n score += 1;\n answer.correctness.value = 'correct';\n correctResponses.push({ label: answer.label, index: index });\n }\n answer.correctness.label = 'correct';\n\n // if category's label (in default answer) was editable\n // it means that this category values 2 points (both label and value can be changed)\n } else if (defaultAnswer.editable && answer.interactive) {\n scoreForLabelAndValueEditable(answer, corrAnswer);\n } else if (!answer.interactive) {\n answer.correctness.value = 'correct';\n answer.correctness.label = 'correct';\n correctResponses.push({ label: answer.label, index: index });\n }\n } else {\n // if there is not a corresponding category at the same position in the default answer\n scoreForLabelAndValueEditable(answer, corrAnswer);\n }\n } else {\n // if there is not a corresponding category at the same position in the given answer\n // it means that the given answer has less categories than the correct answer\n maxScore += 2;\n }\n });\n\n result = maxScore ? score / maxScore : 0;\n } else {\n // all-or-nothing scoring: overall score is 1 only if lengths and all values/labels match\n result = correctAnswers.length === answers.length ? 1 : 0;\n\n // regardless of overall result, mark each answer individually for user feedback\n answers = answers.map((answer, index): ScoredCategory => {\n const correctAnswer = correctAnswers[index];\n const valueIsCorrect = correctAnswer ? answer.value === correctAnswer.value : false;\n const labelIsCorrect = correctAnswer ? checkLabelsEquality(answer.label, correctAnswer.label, language) : false;\n\n if (!valueIsCorrect || !labelIsCorrect) {\n result = 0;\n }\n\n if (valueIsCorrect && labelIsCorrect) {\n correctResponses.push({ label: answer.label, index });\n }\n\n return {\n ...answer,\n correctness: {\n value: valueIsCorrect ? 'correct' : 'incorrect',\n label: labelIsCorrect ? 'correct' : 'incorrect',\n },\n };\n });\n }\n\n const score: ChartingScore = {\n score: parseFloat(result.toFixed(2)),\n answers,\n };\n\n if (env.extraProps && env.extraProps.correctResponseEnabled) {\n score.correctResponses = correctResponses;\n }\n\n return score;\n};\n\n/**\n * Generates detailed trace log for scoring evaluation\n * @param {Object} model - the question model\n * @param {Object} session - the student session\n * @param {Object} env - the environment\n * @returns {Array} traceLog - array of trace messages\n */\nexport const getLogTrace = (\n model: ChartingModel,\n session: ChartingSession | null | undefined,\n env: ChartingEnvironment,\n): string[] => {\n const traceLog: string[] = [];\n\n const { correctAnswer, data: initialData = [], scoringType } = model || {};\n const { data: correctAnswers = [] } = correctAnswer || {};\n const studentAnswers = (session && session.answer) || [];\n const language = contentLanguage(model, env);\n\n const isPartialScoring = partialScoring.enabled(\n { partialScoring: scoringType !== undefined ? scoringType === 'partial scoring' : scoringType },\n env\n );\n\n const defaultAnswers = filterCategories(initialData);\n const answers = studentAnswers.length > 0 ? filterCategories(studentAnswers) : defaultAnswers;\n\n if (!studentAnswers.length) {\n traceLog.push(`Student did not modify the chart. Initial chart is scored.`);\n }\n\n correctAnswers.forEach((correct, index) => {\n const initial = defaultAnswers[index];\n const student = answers[index];\n\n if (!student) {\n traceLog.push(`Category ${index + 1}: missing (expected value '${correct.value}', label '${correct.label}').`);\n return;\n }\n\n const valueCorrect = student.value === correct.value;\n const labelCorrect = checkLabelsEquality(student.label, correct.label, language);\n\n if (!student.interactive) {\n traceLog.push(`Category ${index + 1}: non-interactive category treated as correct.`);\n return;\n }\n\n if (studentAnswers.length > 0) {\n const valueChanged = initial ? student.value !== initial.value : true;\n const labelChanged = initial ? !checkLabelsEquality(student.label, initial.label, language) : true;\n\n if (!valueChanged && !labelChanged) {\n if (valueCorrect && labelCorrect) {\n traceLog.push(`Category ${index + 1}: unchanged from initial value and correct.`);\n } else {\n traceLog.push(`Category ${index + 1}: unchanged from initial value but incorrect.`);\n }\n return;\n }\n\n const parts: string[] = [];\n if (valueChanged) {\n parts.push(`value ${valueCorrect ? 'correct' : 'incorrect'}`);\n }\n if (labelChanged) {\n parts.push(`label ${labelCorrect ? 'correct' : 'incorrect'}`);\n }\n traceLog.push(`Category ${index + 1}: modified - ${parts.join(', ')}.`);\n } else {\n if (valueCorrect && labelCorrect) {\n traceLog.push(`Category ${index + 1}: initial values are correct.`);\n } else if (valueCorrect) {\n traceLog.push(`Category ${index + 1}: initial value correct, label incorrect.`);\n } else if (labelCorrect) {\n traceLog.push(`Category ${index + 1}: initial value incorrect, label correct.`);\n } else {\n traceLog.push(`Category ${index + 1}: initial value and label incorrect.`);\n }\n }\n });\n\n if (answers.length > correctAnswers.length) {\n const extra = answers.length - correctAnswers.length;\n traceLog.push(`${extra} extra category(ies) provided beyond expected number.`);\n }\n\n if (isPartialScoring) {\n traceLog.push('Score calculated using partial scoring.');\n traceLog.push('Student receives credit for each correct value and label independently.');\n } else {\n traceLog.push('Score calculated using all-or-nothing scoring.');\n traceLog.push('Student must match all category values and labels exactly for full credit.');\n }\n\n const scoreObject = getScore(model, session, env);\n traceLog.push(`Score: ${scoreObject.score}.`);\n\n return traceLog;\n};\n\n\n// eslint-disable-next-line no-unused-vars\nexport const filterCategories = <T extends ChartingCategory>(categories?: T[]): Omit<T, 'deletable'>[] =>\n categories ? categories.map(({ deletable, ...rest }) => rest) : [];\n\nexport function model(\n question: ChartingModel,\n session: ChartingSession | null | undefined,\n env: ChartingEnvironment,\n): Promise<ChartingViewModel> {\n return new Promise((resolve) => {\n const normalizedQuestion = normalize(question);\n const {\n addCategoryEnabled,\n chartType,\n data,\n domain,\n graph,\n prompt,\n promptEnabled,\n range,\n rationale,\n title,\n rationaleEnabled,\n teacherInstructions,\n teacherInstructionsEnabled,\n correctAnswer,\n scoringType,\n studentNewCategoryDefaultLabel,\n language,\n extraCSSRules,\n } = normalizedQuestion;\n\n const correctInfo = { correctness: 'incorrect', score: '0%' };\n\n const base: ChartingViewModel = {\n addCategoryEnabled,\n chartType,\n data: filterCategories(data),\n domain,\n graph,\n prompt: promptEnabled ? prompt : null,\n range,\n rationale,\n title,\n size: graph,\n showToggle: false,\n correctness: correctInfo,\n disabled: env.mode !== 'gather',\n scoringType,\n studentNewCategoryDefaultLabel,\n language,\n env,\n extraCSSRules,\n };\n\n const scoreObject = getScore(normalizedQuestion, session, env);\n const answers = filterCategories(scoreObject.answers);\n\n if (env.mode === 'view') {\n // eslint-disable-next-line no-unused-vars\n base.correctedAnswer = answers.map(({ correctness, ...rest }) => {\n return { ...rest, interactive: false };\n });\n\n base.addCategoryEnabled = false;\n }\n\n if (env.mode === 'evaluate') {\n base.correctedAnswer = answers;\n base.correctAnswer = correctAnswer;\n base.showToggle = !!correctAnswer?.data?.length && scoreObject.score !== 1;\n base.addCategoryEnabled = false;\n base.showKeyLegend = true;\n }\n\n if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {\n base.rationale = rationaleEnabled ? rationale : null;\n base.teacherInstructions = teacherInstructionsEnabled ? teacherInstructions : null;\n } else {\n base.rationale = null;\n base.teacherInstructions = null;\n }\n\n log('base: ', base);\n resolve(base);\n });\n}\n\nexport function outcome(\n model: ChartingModel,\n session: ChartingSession | null | undefined,\n env: ChartingEnvironment,\n): Promise<ChartingOutcome> {\n return new Promise((resolve) => {\n const traceLog = getLogTrace(model, session, env);\n const scoreObject = getScore(model, session, env);\n \n const result: ChartingOutcome = {\n score: scoreObject.score,\n empty: !session || isEmpty(session),\n traceLog\n };\n \n if (env.extraProps && env.extraProps.correctResponseEnabled) {\n result.extraProps = { correctResponse: scoreObject.correctResponses };\n }\n \n resolve(result);\n });\n}\n\nexport const createCorrectResponseSession = (\n question: ChartingModel,\n env: ChartingEnvironment,\n): Promise<ChartingSession | null> => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { correctAnswer } = question;\n\n let answers = correctAnswer && correctAnswer.data;\n\n // for IBX preview mode\n if (env.mode === 'gather') {\n const { data } = question;\n\n answers = ((correctAnswer && correctAnswer.data) || []).map((answer, index) => {\n // Throws when the model has no `data`, as it did untyped.\n return {\n ...(data as ChartingCategory[])[index],\n ...answer,\n };\n });\n }\n\n resolve({\n answer: answers,\n id: '1',\n });\n } else {\n return resolve(null);\n }\n });\n};\n\n// remove all html tags\nconst getInnerText = (html?: string) => (html || '').replaceAll(/<[^>]*>/g, '');\n\n// remove all html tags except img, iframe and source tag for audio\nconst getContent = (html?: string) => (html || '').replace(/(<(?!img|iframe|source)([^>]+)>)/gi, '');\n\nexport const validate = (\n model: Partial<ChartingModel> = {},\n config: ChartingConfiguration = {},\n): ChartingValidationErrors => {\n const { correctAnswer, data } = model || {};\n const { data: correctData } = correctAnswer || {};\n const categories = correctData || [];\n\n const errors: ChartingValidationErrors = {};\n const correctAnswerErrors: NonNullable<ChartingValidationErrors['correctAnswerErrors']> = {};\n const categoryErrors: Record<number, string> = {};\n\n (['teacherInstructions', 'prompt', 'rationale'] as const).forEach((field) => {\n if (config[field]?.required && !getContent(model[field])) {\n errors[field] = 'This field is required.';\n }\n });\n\n categories.forEach((category, index) => {\n const { label } = category;\n\n if (!getInnerText(label)) {\n categoryErrors[index] = 'Content should not be empty. ';\n } else {\n const identicalAnswer = categories.some((c, i) => c.label === label && index !== i);\n\n if (identicalAnswer) {\n categoryErrors[index] = 'Category names should be unique. ';\n }\n }\n });\n\n if (categories.length < 1 || categories.length > 20) {\n correctAnswerErrors.categoriesError = 'The correct answer should include between 1 and 20 categories.';\n } else if (\n isEqual(\n // `data.map` throws when the model has no `data`, as it did untyped.\n (data as ChartingCategory[]).map((category) => pick(category, 'value', 'label')),\n (correctData as ChartingCategory[]).map((category) => pick(category, 'value', 'label')),\n )\n ) {\n correctAnswerErrors.identicalError = 'Correct answer should not be identical to the chart’s initial state';\n }\n\n if (!isEmpty(categoryErrors)) {\n errors.categoryErrors = categoryErrors;\n }\n\n if (!isEmpty(correctAnswerErrors)) {\n errors.correctAnswerErrors = correctAnswerErrors;\n }\n\n return errors;\n};\n"],"mappings":"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"}
@@ -610,7 +610,7 @@ var G = _, K = G.default, q = K && typeof K == "object" ? K : G, me = W(p, "UiLa
610
610
  }
611
611
  }, ye = Object.freeze({
612
612
  name: "@pie-element/charting",
613
- version: "13.0.8-next.20261024044430"
613
+ version: "13.0.8-next.20261024053312"
614
614
  });
615
615
  //#endregion
616
616
  export { Q as Component, ve as default, ye as piePackage };
@@ -67,7 +67,7 @@ type ChartingOutcome = {
67
67
  correctResponse?: ChartingCorrectResponse[];
68
68
  };
69
69
  };
70
- export declare const checkLabelsEquality: (givenAnswerLabel?: string, correctAnswerLabel?: string) => boolean;
70
+ export declare const checkLabelsEquality: (givenAnswerLabel?: string, correctAnswerLabel?: string, language?: string) => boolean;
71
71
  export declare const setCorrectness: (answers: ChartingCategory[] | undefined, partialScoring: boolean) => ScoredCategory[];
72
72
  export declare const normalize: (question: ChartingModel) => {
73
73
  addCategoryEnabled: boolean;
@@ -1,40 +1,43 @@
1
1
  import e from "./defaults.js";
2
2
  import { isEmpty as t, isEqual as n, pick as r } from "@pie-element/shared-lodash";
3
3
  import i from "debug";
4
- import { partialScoring as a } from "@pie-element/shared-controller-utils";
4
+ import { contentLanguage as a, normalizeResponse as o, partialScoring as s } from "@pie-element/shared-controller-utils";
5
5
  //#region src/controller/index.ts
6
- var o = i("@pie-element:graphing:controller"), s = (e) => (e || "").toLowerCase(), c = (e, t) => s(e) === s(t), l = (e, t) => e ? e.map((e) => ({
6
+ var c = i("@pie-element:graphing:controller"), l = (e, t) => o(e || "", {
7
+ language: t,
8
+ ignoreCase: !0
9
+ }), u = (e, t, n) => l(e, n) === l(t, n), d = (e, t) => e ? e.map((e) => ({
7
10
  ...e,
8
11
  correctness: {
9
12
  value: t ? "incorrect" : "correct",
10
13
  label: t ? "incorrect" : "correct"
11
14
  }
12
- })) : [], u = (t) => ({
15
+ })) : [], f = (t) => ({
13
16
  ...e,
14
17
  ...t
15
- }), d = (e, t, n = {}) => {
16
- let { correctAnswer: r, data: i = [], scoringType: o } = e, u = [], d = a.enabled({ partialScoring: o === void 0 ? o : o === "partial scoring" }, n), { data: f = [] } = r || {}, m = p(i), h = l(t && t.answer || m, d), g = 0;
17
- if (d) {
18
+ }), p = (e, t, n = {}) => {
19
+ let { correctAnswer: r, data: i = [], scoringType: o } = e, c = [], l = a(e, n), f = s.enabled({ partialScoring: o === void 0 ? o : o === "partial scoring" }, n), { data: p = [] } = r || {}, m = h(i), g = d(t && t.answer || m, f), _ = 0;
20
+ if (f) {
18
21
  let e = 0, t = 0, n = (n, r) => {
19
- let { value: i, label: a, index: o } = n, s = i === r.value, l = c(a, r.label);
20
- e += 2, s && (t += 1, n.correctness.value = "correct"), l && (t += 1, n.correctness.label = "correct"), s && l && u.push({
22
+ let { value: i, label: a, index: o } = n, s = i === r.value, d = u(a, r.label, l);
23
+ e += 2, s && (t += 1, n.correctness.value = "correct"), d && (t += 1, n.correctness.label = "correct"), s && d && c.push({
21
24
  label: a,
22
25
  index: o
23
26
  });
24
27
  };
25
- f.forEach((r, i) => {
26
- let a = m[i], o = h[i];
27
- o ? a ? !a.editable && o.interactive ? (e += 1, o.value === r.value && (t += 1, o.correctness.value = "correct", u.push({
28
+ p.forEach((r, i) => {
29
+ let a = m[i], o = g[i];
30
+ o ? a ? !a.editable && o.interactive ? (e += 1, o.value === r.value && (t += 1, o.correctness.value = "correct", c.push({
28
31
  label: o.label,
29
32
  index: i
30
- })), o.correctness.label = "correct") : a.editable && o.interactive ? n(o, r) : o.interactive || (o.correctness.value = "correct", o.correctness.label = "correct", u.push({
33
+ })), o.correctness.label = "correct") : a.editable && o.interactive ? n(o, r) : o.interactive || (o.correctness.value = "correct", o.correctness.label = "correct", c.push({
31
34
  label: o.label,
32
35
  index: i
33
36
  })) : n(o, r) : e += 2;
34
- }), g = e ? t / e : 0;
35
- } else g = +(f.length === h.length), h = h.map((e, t) => {
36
- let n = f[t], r = n ? e.value === n.value : !1, i = n ? s(e.label) === s(n.label) : !1;
37
- return (!r || !i) && (g = 0), r && i && u.push({
37
+ }), _ = e ? t / e : 0;
38
+ } else _ = +(p.length === g.length), g = g.map((e, t) => {
39
+ let n = p[t], r = n ? e.value === n.value : !1, i = n ? u(e.label, n.label, l) : !1;
40
+ return (!r || !i) && (_ = 0), r && i && c.push({
38
41
  label: e.label,
39
42
  index: t
40
43
  }), {
@@ -45,51 +48,51 @@ var o = i("@pie-element:graphing:controller"), s = (e) => (e || "").toLowerCase(
45
48
  }
46
49
  };
47
50
  });
48
- let _ = {
49
- score: parseFloat(g.toFixed(2)),
50
- answers: h
51
+ let v = {
52
+ score: parseFloat(_.toFixed(2)),
53
+ answers: g
51
54
  };
52
- return n.extraProps && n.extraProps.correctResponseEnabled && (_.correctResponses = u), _;
53
- }, f = (e, t, n) => {
54
- let r = [], { correctAnswer: i, data: o = [], scoringType: s } = e || {}, { data: l = [] } = i || {}, u = t && t.answer || [], f = a.enabled({ partialScoring: s === void 0 ? s : s === "partial scoring" }, n), m = p(o), h = u.length > 0 ? p(u) : m;
55
- if (u.length || r.push("Student did not modify the chart. Initial chart is scored."), l.forEach((e, t) => {
56
- let n = m[t], i = h[t];
55
+ return n.extraProps && n.extraProps.correctResponseEnabled && (v.correctResponses = c), v;
56
+ }, m = (e, t, n) => {
57
+ let r = [], { correctAnswer: i, data: o = [], scoringType: c } = e || {}, { data: l = [] } = i || {}, d = t && t.answer || [], f = a(e, n), m = s.enabled({ partialScoring: c === void 0 ? c : c === "partial scoring" }, n), g = h(o), _ = d.length > 0 ? h(d) : g;
58
+ if (d.length || r.push("Student did not modify the chart. Initial chart is scored."), l.forEach((e, t) => {
59
+ let n = g[t], i = _[t];
57
60
  if (!i) {
58
61
  r.push(`Category ${t + 1}: missing (expected value '${e.value}', label '${e.label}').`);
59
62
  return;
60
63
  }
61
- let a = i.value === e.value, o = c(i.label, e.label);
64
+ let a = i.value === e.value, o = u(i.label, e.label, f);
62
65
  if (!i.interactive) r.push(`Category ${t + 1}: non-interactive category treated as correct.`);
63
- else if (u.length > 0) {
64
- let e = !n || i.value !== n.value, s = !n || !c(i.label, n.label);
66
+ else if (d.length > 0) {
67
+ let e = !n || i.value !== n.value, s = !n || !u(i.label, n.label, f);
65
68
  if (!e && !s) {
66
69
  a && o ? r.push(`Category ${t + 1}: unchanged from initial value and correct.`) : r.push(`Category ${t + 1}: unchanged from initial value but incorrect.`);
67
70
  return;
68
71
  }
69
- let l = [];
70
- e && l.push(`value ${a ? "correct" : "incorrect"}`), s && l.push(`label ${o ? "correct" : "incorrect"}`), r.push(`Category ${t + 1}: modified - ${l.join(", ")}.`);
72
+ let c = [];
73
+ e && c.push(`value ${a ? "correct" : "incorrect"}`), s && c.push(`label ${o ? "correct" : "incorrect"}`), r.push(`Category ${t + 1}: modified - ${c.join(", ")}.`);
71
74
  } else a && o ? r.push(`Category ${t + 1}: initial values are correct.`) : a ? r.push(`Category ${t + 1}: initial value correct, label incorrect.`) : o ? r.push(`Category ${t + 1}: initial value incorrect, label correct.`) : r.push(`Category ${t + 1}: initial value and label incorrect.`);
72
- }), h.length > l.length) {
73
- let e = h.length - l.length;
75
+ }), _.length > l.length) {
76
+ let e = _.length - l.length;
74
77
  r.push(`${e} extra category(ies) provided beyond expected number.`);
75
78
  }
76
- f ? (r.push("Score calculated using partial scoring."), r.push("Student receives credit for each correct value and label independently.")) : (r.push("Score calculated using all-or-nothing scoring."), r.push("Student must match all category values and labels exactly for full credit."));
77
- let g = d(e, t, n);
78
- return r.push(`Score: ${g.score}.`), r;
79
- }, p = (e) => e ? e.map(({ deletable: e, ...t }) => t) : [];
80
- function m(e, t, n) {
79
+ m ? (r.push("Score calculated using partial scoring."), r.push("Student receives credit for each correct value and label independently.")) : (r.push("Score calculated using all-or-nothing scoring."), r.push("Student must match all category values and labels exactly for full credit."));
80
+ let v = p(e, t, n);
81
+ return r.push(`Score: ${v.score}.`), r;
82
+ }, h = (e) => e ? e.map(({ deletable: e, ...t }) => t) : [];
83
+ function g(e, t, n) {
81
84
  return new Promise((r) => {
82
- let i = u(e), { addCategoryEnabled: a, chartType: s, data: c, domain: l, graph: f, prompt: m, promptEnabled: h, range: g, rationale: _, title: v, rationaleEnabled: y, teacherInstructions: b, teacherInstructionsEnabled: x, correctAnswer: S, scoringType: C, studentNewCategoryDefaultLabel: w, language: T, extraCSSRules: E } = i, D = {
85
+ let i = f(e), { addCategoryEnabled: a, chartType: o, data: s, domain: l, graph: u, prompt: d, promptEnabled: m, range: g, rationale: _, title: v, rationaleEnabled: y, teacherInstructions: b, teacherInstructionsEnabled: x, correctAnswer: S, scoringType: C, studentNewCategoryDefaultLabel: w, language: T, extraCSSRules: E } = i, D = {
83
86
  addCategoryEnabled: a,
84
- chartType: s,
85
- data: p(c),
87
+ chartType: o,
88
+ data: h(s),
86
89
  domain: l,
87
- graph: f,
88
- prompt: h ? m : null,
90
+ graph: u,
91
+ prompt: m ? d : null,
89
92
  range: g,
90
93
  rationale: _,
91
94
  title: v,
92
- size: f,
95
+ size: u,
93
96
  showToggle: !1,
94
97
  correctness: {
95
98
  correctness: "incorrect",
@@ -101,16 +104,16 @@ function m(e, t, n) {
101
104
  language: T,
102
105
  env: n,
103
106
  extraCSSRules: E
104
- }, O = d(i, t, n), k = p(O.answers);
107
+ }, O = p(i, t, n), k = h(O.answers);
105
108
  n.mode === "view" && (D.correctedAnswer = k.map(({ correctness: e, ...t }) => ({
106
109
  ...t,
107
110
  interactive: !1
108
- })), D.addCategoryEnabled = !1), n.mode === "evaluate" && (D.correctedAnswer = k, D.correctAnswer = S, D.showToggle = !!S?.data?.length && O.score !== 1, D.addCategoryEnabled = !1, D.showKeyLegend = !0), n.role === "instructor" && (n.mode === "view" || n.mode === "evaluate") ? (D.rationale = y ? _ : null, D.teacherInstructions = x ? b : null) : (D.rationale = null, D.teacherInstructions = null), o("base: ", D), r(D);
111
+ })), D.addCategoryEnabled = !1), n.mode === "evaluate" && (D.correctedAnswer = k, D.correctAnswer = S, D.showToggle = !!S?.data?.length && O.score !== 1, D.addCategoryEnabled = !1, D.showKeyLegend = !0), n.role === "instructor" && (n.mode === "view" || n.mode === "evaluate") ? (D.rationale = y ? _ : null, D.teacherInstructions = x ? b : null) : (D.rationale = null, D.teacherInstructions = null), c("base: ", D), r(D);
109
112
  });
110
113
  }
111
- function h(e, n, r) {
114
+ function _(e, n, r) {
112
115
  return new Promise((i) => {
113
- let a = f(e, n, r), o = d(e, n, r), s = {
116
+ let a = m(e, n, r), o = p(e, n, r), s = {
114
117
  score: o.score,
115
118
  empty: !n || t(n),
116
119
  traceLog: a
@@ -118,7 +121,7 @@ function h(e, n, r) {
118
121
  r.extraProps && r.extraProps.correctResponseEnabled && (s.extraProps = { correctResponse: o.correctResponses }), i(s);
119
122
  });
120
123
  }
121
- var g = (e, t) => new Promise((n) => {
124
+ var v = (e, t) => new Promise((n) => {
122
125
  if (t.mode !== "evaluate" && t.role === "instructor") {
123
126
  let { correctAnswer: r } = e, i = r && r.data;
124
127
  if (t.mode === "gather") {
@@ -133,18 +136,18 @@ var g = (e, t) => new Promise((n) => {
133
136
  id: "1"
134
137
  });
135
138
  } else return n(null);
136
- }), _ = (e) => (e || "").replaceAll(/<[^>]*>/g, ""), v = (e) => (e || "").replace(/(<(?!img|iframe|source)([^>]+)>)/gi, ""), y = (e = {}, i = {}) => {
139
+ }), y = (e) => (e || "").replaceAll(/<[^>]*>/g, ""), b = (e) => (e || "").replace(/(<(?!img|iframe|source)([^>]+)>)/gi, ""), x = (e = {}, i = {}) => {
137
140
  let { correctAnswer: a, data: o } = e || {}, { data: s } = a || {}, c = s || [], l = {}, u = {}, d = {};
138
141
  return [
139
142
  "teacherInstructions",
140
143
  "prompt",
141
144
  "rationale"
142
145
  ].forEach((t) => {
143
- i[t]?.required && !v(e[t]) && (l[t] = "This field is required.");
146
+ i[t]?.required && !b(e[t]) && (l[t] = "This field is required.");
144
147
  }), c.forEach((e, t) => {
145
148
  let { label: n } = e;
146
- _(n) ? c.some((e, r) => e.label === n && t !== r) && (d[t] = "Category names should be unique. ") : d[t] = "Content should not be empty. ";
149
+ y(n) ? c.some((e, r) => e.label === n && t !== r) && (d[t] = "Category names should be unique. ") : d[t] = "Content should not be empty. ";
147
150
  }), c.length < 1 || c.length > 20 ? u.categoriesError = "The correct answer should include between 1 and 20 categories." : n(o.map((e) => r(e, "value", "label")), s.map((e) => r(e, "value", "label"))) && (u.identicalError = "Correct answer should not be identical to the chart’s initial state"), t(d) || (l.categoryErrors = d), t(u) || (l.correctAnswerErrors = u), l;
148
151
  };
149
152
  //#endregion
150
- export { c as checkLabelsEquality, g as createCorrectResponseSession, p as filterCategories, f as getLogTrace, d as getScore, m as model, u as normalize, h as outcome, l as setCorrectness, y as validate };
153
+ export { u as checkLabelsEquality, v as createCorrectResponseSession, h as filterCategories, m as getLogTrace, p as getScore, g as model, f as normalize, _ as outcome, d as setCorrectness, x as validate };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "https://cdn.jsdelivr.net/npm/@pie-element/charting@13.0.8-next.20261024044430/dist/schemas/configuration.schema.json",
3
+ "$id": "https://cdn.jsdelivr.net/npm/@pie-element/charting@13.0.8-next.20261024053312/dist/schemas/configuration.schema.json",
4
4
  "type": "object",
5
5
  "properties": {
6
6
  "baseInputConfiguration": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "https://cdn.jsdelivr.net/npm/@pie-element/charting@13.0.8-next.20261024044430/dist/schemas/model.schema.json",
3
+ "$id": "https://cdn.jsdelivr.net/npm/@pie-element/charting@13.0.8-next.20261024053312/dist/schemas/model.schema.json",
4
4
  "type": "object",
5
5
  "properties": {
6
6
  "id": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "https://cdn.jsdelivr.net/npm/@pie-element/charting@13.0.8-next.20261024044430/dist/schemas/session.schema.json",
3
+ "$id": "https://cdn.jsdelivr.net/npm/@pie-element/charting@13.0.8-next.20261024053312/dist/schemas/session.schema.json",
4
4
  "type": "object",
5
5
  "properties": {
6
6
  "id": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pie-element/charting",
3
- "version": "13.0.8-next.20261024044430",
3
+ "version": "13.0.8-next.20261024053312",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,22 +11,22 @@
11
11
  "@emotion/react": "^11.14.0",
12
12
  "@mui/icons-material": "^7.3.4",
13
13
  "@mui/material": "^7.3.4",
14
- "@pie-lib/charting": "8.0.8-next.20261024044430",
15
- "@pie-lib/correct-answer-toggle": "5.0.8-next.20261024044430",
16
- "@pie-lib/render-ui": "8.0.8-next.20261024044430",
14
+ "@pie-lib/charting": "8.0.8-next.20261024053312",
15
+ "@pie-lib/correct-answer-toggle": "5.0.8-next.20261024053312",
16
+ "@pie-lib/render-ui": "8.0.8-next.20261024053312",
17
17
  "@pie-lib/translator": "5.0.3-next.20261023101922",
18
18
  "debug": "^4.1.1",
19
19
  "prop-types": "^15.8.1",
20
- "@pie-lib/config-ui": "14.0.8-next.20261024044430",
21
- "@pie-lib/editable-html-tip-tap": "3.1.3-next.20261024044430",
20
+ "@pie-lib/config-ui": "14.0.8-next.20261024053312",
21
+ "@pie-lib/editable-html-tip-tap": "3.1.3-next.20261024053312",
22
22
  "@pie-element/shared-lodash": "0.1.4-next.20261023101922",
23
23
  "@pie-element/shared-configure-events": "0.1.3-next.20261023101922",
24
24
  "@pie-element/shared-math-rendering-mathjax": "0.1.9-next.20261023101922",
25
- "@pie-element/shared-controller-utils": "0.1.5-next.20261023101922",
25
+ "@pie-element/shared-controller-utils": "0.1.5-next.20261024053312",
26
26
  "@pie-element/shared-player-events": "0.2.2-next.20261023101922",
27
27
  "react": "^18.2.0",
28
28
  "react-dom": "^18.2.0",
29
- "@pie-element/shared-types": "0.2.4-next.20261023101922"
29
+ "@pie-element/shared-types": "0.2.4-next.20261024053312"
30
30
  },
31
31
  "exports": {
32
32
  ".": {