@case-framework/survey-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/editor.d.mts +245 -0
- package/build/editor.d.mts.map +1 -0
- package/build/editor.mjs +603 -0
- package/build/editor.mjs.map +1 -0
- package/build/index.d.mts +597 -0
- package/build/index.d.mts.map +1 -0
- package/build/index.mjs +1586 -0
- package/build/index.mjs.map +1 -0
- package/build/package.json/package.json +49 -0
- package/build/survey-C3ZHI-5z.mjs +931 -0
- package/build/survey-C3ZHI-5z.mjs.map +1 -0
- package/build/survey-TUPUXiXl.d.mts +614 -0
- package/build/survey-TUPUXiXl.d.mts.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,931 @@
|
|
|
1
|
+
//#region src/utils.ts
|
|
2
|
+
/**
|
|
3
|
+
* Shuffles an array of indices using the Fisher-Yates shuffle algorithm
|
|
4
|
+
* @param length - The length of the array to create indices for
|
|
5
|
+
* @returns A shuffled array of indices from 0 to length-1
|
|
6
|
+
*/
|
|
7
|
+
function shuffleIndices(length) {
|
|
8
|
+
const shuffledIndices = Array.from({ length }, (_, i) => i);
|
|
9
|
+
for (let i = shuffledIndices.length - 1; i > 0; i--) {
|
|
10
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
11
|
+
[shuffledIndices[i], shuffledIndices[j]] = [shuffledIndices[j], shuffledIndices[i]];
|
|
12
|
+
}
|
|
13
|
+
return shuffledIndices;
|
|
14
|
+
}
|
|
15
|
+
function structuredCloneMethod(obj) {
|
|
16
|
+
if (typeof structuredClone !== "undefined") return structuredClone(obj);
|
|
17
|
+
return JSON.parse(JSON.stringify(obj));
|
|
18
|
+
}
|
|
19
|
+
const ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
20
|
+
function generateId() {
|
|
21
|
+
const length = 10;
|
|
22
|
+
const timestamp = Date.now();
|
|
23
|
+
let encodedTimestamp = "";
|
|
24
|
+
let t = timestamp;
|
|
25
|
+
const base = 62;
|
|
26
|
+
while (t > 0) {
|
|
27
|
+
encodedTimestamp = ALPHABET.charAt(t % base) + encodedTimestamp;
|
|
28
|
+
t = Math.floor(t / base);
|
|
29
|
+
}
|
|
30
|
+
let randomPart = "";
|
|
31
|
+
for (let i = 0; i < length; i++) randomPart += ALPHABET.charAt(Math.floor(Math.random() * base));
|
|
32
|
+
return randomPart + encodedTimestamp;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/survey/utils/value-reference.ts
|
|
37
|
+
const SEPARATOR = "...";
|
|
38
|
+
let ValueReferenceMethod = /* @__PURE__ */ function(ValueReferenceMethod) {
|
|
39
|
+
ValueReferenceMethod["get"] = "get";
|
|
40
|
+
ValueReferenceMethod["isDefined"] = "isDefined";
|
|
41
|
+
return ValueReferenceMethod;
|
|
42
|
+
}({});
|
|
43
|
+
var ValueReference = class ValueReference {
|
|
44
|
+
_itemId;
|
|
45
|
+
_name;
|
|
46
|
+
_slotId;
|
|
47
|
+
constructor(str) {
|
|
48
|
+
const parts = str.split(SEPARATOR);
|
|
49
|
+
if (parts.length !== 3) throw new Error("Invalid value reference: " + str);
|
|
50
|
+
this._itemId = parts[0];
|
|
51
|
+
this._name = parts[1];
|
|
52
|
+
this._slotId = parts[2];
|
|
53
|
+
}
|
|
54
|
+
get itemId() {
|
|
55
|
+
return this._itemId;
|
|
56
|
+
}
|
|
57
|
+
get name() {
|
|
58
|
+
return this._name;
|
|
59
|
+
}
|
|
60
|
+
get slotId() {
|
|
61
|
+
return this._slotId;
|
|
62
|
+
}
|
|
63
|
+
set itemId(itemId) {
|
|
64
|
+
this._itemId = itemId;
|
|
65
|
+
}
|
|
66
|
+
toString() {
|
|
67
|
+
return `${this._itemId}${SEPARATOR}${this._name}${this._slotId ? SEPARATOR + this._slotId : ""}`;
|
|
68
|
+
}
|
|
69
|
+
static fromParts(itemId, name, slotId) {
|
|
70
|
+
return new ValueReference(`${itemId}${SEPARATOR}${name}${SEPARATOR}${slotId}`);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
let ReferenceUsageType = /* @__PURE__ */ function(ReferenceUsageType) {
|
|
74
|
+
ReferenceUsageType["displayConditions"] = "displayConditions";
|
|
75
|
+
ReferenceUsageType["templateValues"] = "templateValues";
|
|
76
|
+
ReferenceUsageType["validations"] = "validations";
|
|
77
|
+
ReferenceUsageType["disabledConditions"] = "disabledConditions";
|
|
78
|
+
return ReferenceUsageType;
|
|
79
|
+
}({});
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/expressions/expression.ts
|
|
83
|
+
const ExpressionType = {
|
|
84
|
+
Const: "const",
|
|
85
|
+
ResponseVariable: "responseVariable",
|
|
86
|
+
ContextVariable: "contextVariable",
|
|
87
|
+
Function: "function"
|
|
88
|
+
};
|
|
89
|
+
const ContextVariableType = {
|
|
90
|
+
Locale: "locale",
|
|
91
|
+
ParticipantFlag: "participantFlag",
|
|
92
|
+
CustomValue: "customValue",
|
|
93
|
+
CustomExpression: "customExpression"
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Base class for all expressions.
|
|
97
|
+
*/
|
|
98
|
+
var Expression = class Expression {
|
|
99
|
+
type;
|
|
100
|
+
editorConfig;
|
|
101
|
+
constructor(type, editorConfig) {
|
|
102
|
+
this.type = type;
|
|
103
|
+
this.editorConfig = editorConfig;
|
|
104
|
+
}
|
|
105
|
+
static deserialize(json) {
|
|
106
|
+
if (!json) return;
|
|
107
|
+
switch (json.type) {
|
|
108
|
+
case ExpressionType.Const: return ConstExpression.deserialize(json);
|
|
109
|
+
case ExpressionType.ResponseVariable: return ResponseVariableExpression.deserialize(json);
|
|
110
|
+
case ExpressionType.ContextVariable: return ContextVariableExpression.deserialize(json);
|
|
111
|
+
case ExpressionType.Function: return FunctionExpression.deserialize(json);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
clone() {
|
|
115
|
+
return Expression.deserialize(this.serialize()) ?? (() => {
|
|
116
|
+
throw new Error("Failed to clone expression");
|
|
117
|
+
})();
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
var ConstExpression = class ConstExpression extends Expression {
|
|
121
|
+
value;
|
|
122
|
+
constructor(value, editorConfig) {
|
|
123
|
+
super(ExpressionType.Const, editorConfig);
|
|
124
|
+
this.value = value;
|
|
125
|
+
this.type = ExpressionType.Const;
|
|
126
|
+
}
|
|
127
|
+
static deserialize(json) {
|
|
128
|
+
if (json.type !== ExpressionType.Const) throw new Error("Invalid expression type: " + json.type);
|
|
129
|
+
return new ConstExpression(json.value, json.editorConfig);
|
|
130
|
+
}
|
|
131
|
+
get responseVariableRefs() {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
serialize() {
|
|
135
|
+
return {
|
|
136
|
+
type: this.type,
|
|
137
|
+
value: this.value,
|
|
138
|
+
editorConfig: this.editorConfig
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
updateItemKeyReferences(_oldItemKey, _newItemKey) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
var ResponseVariableExpression = class ResponseVariableExpression extends Expression {
|
|
146
|
+
variableRef;
|
|
147
|
+
constructor(variableRef, editorConfig) {
|
|
148
|
+
super(ExpressionType.ResponseVariable, editorConfig);
|
|
149
|
+
this.variableRef = variableRef;
|
|
150
|
+
this.type = ExpressionType.ResponseVariable;
|
|
151
|
+
}
|
|
152
|
+
static deserialize(json) {
|
|
153
|
+
if (json.type !== ExpressionType.ResponseVariable) throw new Error("Invalid expression type: " + json.type);
|
|
154
|
+
return new ResponseVariableExpression(json.variableRef, json.editorConfig);
|
|
155
|
+
}
|
|
156
|
+
get responseVariableRefs() {
|
|
157
|
+
return [new ValueReference(this.variableRef)];
|
|
158
|
+
}
|
|
159
|
+
get responseVariableRef() {
|
|
160
|
+
return new ValueReference(this.variableRef);
|
|
161
|
+
}
|
|
162
|
+
serialize() {
|
|
163
|
+
return {
|
|
164
|
+
type: this.type,
|
|
165
|
+
variableRef: this.variableRef,
|
|
166
|
+
editorConfig: this.editorConfig
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
var ContextVariableExpression = class ContextVariableExpression extends Expression {
|
|
171
|
+
contextType;
|
|
172
|
+
key;
|
|
173
|
+
arguments;
|
|
174
|
+
asType;
|
|
175
|
+
constructor(contextType, key, args, asType, editorConfig) {
|
|
176
|
+
super(ExpressionType.ContextVariable, editorConfig);
|
|
177
|
+
this.type = ExpressionType.ContextVariable;
|
|
178
|
+
this.contextType = contextType;
|
|
179
|
+
this.key = key;
|
|
180
|
+
this.arguments = args;
|
|
181
|
+
this.asType = asType;
|
|
182
|
+
}
|
|
183
|
+
static deserialize(json) {
|
|
184
|
+
if (json.type !== ExpressionType.ContextVariable) throw new Error("Invalid expression type: " + json.type);
|
|
185
|
+
return new ContextVariableExpression(json.contextType, Expression.deserialize(json.key), json.arguments?.map((arg) => Expression.deserialize(arg)), json.asType, json.editorConfig);
|
|
186
|
+
}
|
|
187
|
+
get responseVariableRefs() {
|
|
188
|
+
return this.arguments?.flatMap((arg) => arg?.responseVariableRefs).filter((ref) => ref !== void 0) ?? [];
|
|
189
|
+
}
|
|
190
|
+
serialize() {
|
|
191
|
+
return {
|
|
192
|
+
type: this.type,
|
|
193
|
+
contextType: this.contextType,
|
|
194
|
+
key: this.key?.serialize(),
|
|
195
|
+
arguments: this.arguments?.map((arg) => arg?.serialize()),
|
|
196
|
+
asType: this.asType,
|
|
197
|
+
editorConfig: this.editorConfig
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
let FunctionExpressionNames = /* @__PURE__ */ function(FunctionExpressionNames) {
|
|
202
|
+
FunctionExpressionNames["and"] = "and";
|
|
203
|
+
FunctionExpressionNames["or"] = "or";
|
|
204
|
+
FunctionExpressionNames["not"] = "not";
|
|
205
|
+
FunctionExpressionNames["list_contains"] = "list_contains";
|
|
206
|
+
FunctionExpressionNames["eq"] = "eq";
|
|
207
|
+
FunctionExpressionNames["gt"] = "gt";
|
|
208
|
+
FunctionExpressionNames["gte"] = "gte";
|
|
209
|
+
FunctionExpressionNames["lt"] = "lt";
|
|
210
|
+
FunctionExpressionNames["lte"] = "lte";
|
|
211
|
+
FunctionExpressionNames["in_range"] = "in_range";
|
|
212
|
+
FunctionExpressionNames["sum"] = "sum";
|
|
213
|
+
FunctionExpressionNames["min"] = "min";
|
|
214
|
+
FunctionExpressionNames["max"] = "max";
|
|
215
|
+
FunctionExpressionNames["str_eq"] = "str_eq";
|
|
216
|
+
FunctionExpressionNames["date_eq"] = "date_eq";
|
|
217
|
+
return FunctionExpressionNames;
|
|
218
|
+
}({});
|
|
219
|
+
var FunctionExpression = class FunctionExpression extends Expression {
|
|
220
|
+
functionName;
|
|
221
|
+
arguments;
|
|
222
|
+
constructor(functionName, args, editorConfig) {
|
|
223
|
+
super(ExpressionType.Function);
|
|
224
|
+
this.type = ExpressionType.Function;
|
|
225
|
+
this.functionName = functionName;
|
|
226
|
+
this.arguments = args;
|
|
227
|
+
this.editorConfig = editorConfig;
|
|
228
|
+
}
|
|
229
|
+
static deserialize(json) {
|
|
230
|
+
if (json.type !== ExpressionType.Function) throw new Error("Invalid expression type: " + json.type);
|
|
231
|
+
const functionName = json.functionName;
|
|
232
|
+
if (!Object.values(FunctionExpressionNames).includes(functionName)) throw new Error("Invalid function name: " + functionName);
|
|
233
|
+
const expr = new FunctionExpression(functionName, json.arguments.map((arg) => Expression.deserialize(arg)));
|
|
234
|
+
expr.editorConfig = json.editorConfig;
|
|
235
|
+
return expr;
|
|
236
|
+
}
|
|
237
|
+
get responseVariableRefs() {
|
|
238
|
+
const refStrings = this.arguments.flatMap((arg) => arg?.responseVariableRefs).filter((ref) => ref !== void 0).map((ref) => ref.toString());
|
|
239
|
+
return [...new Set(refStrings)].map((ref) => new ValueReference(ref));
|
|
240
|
+
}
|
|
241
|
+
serialize() {
|
|
242
|
+
return {
|
|
243
|
+
type: this.type,
|
|
244
|
+
functionName: this.functionName,
|
|
245
|
+
arguments: this.arguments.map((arg) => arg?.serialize()),
|
|
246
|
+
editorConfig: this.editorConfig
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
//#endregion
|
|
252
|
+
//#region src/expressions/template-value.ts
|
|
253
|
+
let TemplateDefTypes = /* @__PURE__ */ function(TemplateDefTypes) {
|
|
254
|
+
TemplateDefTypes["Default"] = "default";
|
|
255
|
+
TemplateDefTypes["Date2String"] = "date2string";
|
|
256
|
+
return TemplateDefTypes;
|
|
257
|
+
}({});
|
|
258
|
+
const serializeTemplateValue = (templateValue) => {
|
|
259
|
+
const json = {
|
|
260
|
+
type: templateValue.type,
|
|
261
|
+
returnType: templateValue.returnType,
|
|
262
|
+
expression: templateValue.expression?.serialize()
|
|
263
|
+
};
|
|
264
|
+
if (templateValue.type === TemplateDefTypes.Date2String) json.dateFormat = templateValue.dateFormat;
|
|
265
|
+
return json;
|
|
266
|
+
};
|
|
267
|
+
const serializeTemplateValues = (templateValues) => {
|
|
268
|
+
const json = {};
|
|
269
|
+
for (const [key, value] of templateValues.entries()) json[key] = serializeTemplateValue(value);
|
|
270
|
+
return json;
|
|
271
|
+
};
|
|
272
|
+
const deserializeTemplateValue = (json) => {
|
|
273
|
+
return {
|
|
274
|
+
type: json.type,
|
|
275
|
+
expression: json.expression ? Expression.deserialize(json.expression) : void 0,
|
|
276
|
+
returnType: json.returnType,
|
|
277
|
+
dateFormat: json.dateFormat
|
|
278
|
+
};
|
|
279
|
+
};
|
|
280
|
+
const deserializeTemplateValues = (json) => {
|
|
281
|
+
return new Map(Object.entries(json).map(([key, value]) => [key, deserializeTemplateValue(value)]));
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
//#endregion
|
|
285
|
+
//#region src/survey/items/utils.ts
|
|
286
|
+
const displayConditionsFromJson = (json) => {
|
|
287
|
+
return {
|
|
288
|
+
root: json.root ? Expression.deserialize(json.root) : void 0,
|
|
289
|
+
components: json.components ? Object.fromEntries(Object.entries(json.components).map(([key, value]) => [key, Expression.deserialize(value)])) : void 0
|
|
290
|
+
};
|
|
291
|
+
};
|
|
292
|
+
const disabledConditionsFromJson = (json) => {
|
|
293
|
+
return { components: json.components ? Object.fromEntries(Object.entries(json.components).map(([key, value]) => [key, Expression.deserialize(value)])) : void 0 };
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region src/survey/items/survey-item.ts
|
|
298
|
+
/**
|
|
299
|
+
* Base class for survey item handlers.
|
|
300
|
+
* Each handler holds type, id, key, and config (properly typed) and implements core methods.
|
|
301
|
+
* Subclass for each item type; the core works with SurveyItemHandler only—no casting needed.
|
|
302
|
+
*/
|
|
303
|
+
var SurveyItemCore = class {
|
|
304
|
+
id;
|
|
305
|
+
key;
|
|
306
|
+
config;
|
|
307
|
+
_rawItem;
|
|
308
|
+
displayConditions;
|
|
309
|
+
disabledConditions;
|
|
310
|
+
validations;
|
|
311
|
+
prefillRules;
|
|
312
|
+
constructor(rawItem) {
|
|
313
|
+
this._rawItem = rawItem;
|
|
314
|
+
this.updateExpressions();
|
|
315
|
+
this.id = this._rawItem.id;
|
|
316
|
+
this.key = this._rawItem.key;
|
|
317
|
+
this.config = this.parseConfig(this._rawItem.config);
|
|
318
|
+
}
|
|
319
|
+
get rawItem() {
|
|
320
|
+
return this._rawItem;
|
|
321
|
+
}
|
|
322
|
+
updateRawItem(rawItem) {
|
|
323
|
+
if (rawItem.id !== this.id) throw new Error("Cannot update raw item with a different id");
|
|
324
|
+
this._rawItem = rawItem;
|
|
325
|
+
this.updateExpressions();
|
|
326
|
+
this.key = rawItem.key;
|
|
327
|
+
this.config = this.parseConfig(rawItem.config);
|
|
328
|
+
}
|
|
329
|
+
updateExpressions() {
|
|
330
|
+
this.displayConditions = this._rawItem.displayConditions ? displayConditionsFromJson(this._rawItem.displayConditions) : void 0;
|
|
331
|
+
this.disabledConditions = this._rawItem.disabledConditions ? disabledConditionsFromJson(this._rawItem.disabledConditions) : void 0;
|
|
332
|
+
this.validations = this._rawItem.validations ? Object.fromEntries(Object.entries(this._rawItem.validations).map(([key, value]) => [key, Expression.deserialize(value)])) : void 0;
|
|
333
|
+
this.prefillRules = this._rawItem.prefillRules ? this._rawItem.prefillRules.map((rule) => rule ? Expression.deserialize(rule) : void 0) : void 0;
|
|
334
|
+
}
|
|
335
|
+
getReferenceUsages() {
|
|
336
|
+
const usages = [];
|
|
337
|
+
if (this.displayConditions) {
|
|
338
|
+
for (const ref of this.displayConditions.root?.responseVariableRefs || []) usages.push({
|
|
339
|
+
itemId: this.id,
|
|
340
|
+
usageType: ReferenceUsageType.displayConditions,
|
|
341
|
+
valueReference: ref
|
|
342
|
+
});
|
|
343
|
+
for (const [componentKey, expression] of Object.entries(this.displayConditions.components || {})) for (const ref of expression?.responseVariableRefs || []) usages.push({
|
|
344
|
+
itemId: this.id,
|
|
345
|
+
fullComponentKey: componentKey,
|
|
346
|
+
usageType: ReferenceUsageType.displayConditions,
|
|
347
|
+
valueReference: ref
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
if (this.disabledConditions) for (const [componentKey, expression] of Object.entries(this.disabledConditions.components || {})) for (const ref of expression?.responseVariableRefs || []) usages.push({
|
|
351
|
+
itemId: this.id,
|
|
352
|
+
fullComponentKey: componentKey,
|
|
353
|
+
usageType: ReferenceUsageType.disabledConditions,
|
|
354
|
+
valueReference: ref
|
|
355
|
+
});
|
|
356
|
+
if (this.validations) for (const [validationKey, expression] of Object.entries(this.validations)) for (const ref of expression?.responseVariableRefs || []) usages.push({
|
|
357
|
+
itemId: this.id,
|
|
358
|
+
fullComponentKey: validationKey,
|
|
359
|
+
usageType: ReferenceUsageType.validations,
|
|
360
|
+
valueReference: ref
|
|
361
|
+
});
|
|
362
|
+
return usages;
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
//#endregion
|
|
367
|
+
//#region src/survey/items/types.ts
|
|
368
|
+
let ReservedSurveyItemTypes = /* @__PURE__ */ function(ReservedSurveyItemTypes) {
|
|
369
|
+
ReservedSurveyItemTypes["Group"] = "group";
|
|
370
|
+
ReservedSurveyItemTypes["PageBreak"] = "page-break";
|
|
371
|
+
return ReservedSurveyItemTypes;
|
|
372
|
+
}({});
|
|
373
|
+
|
|
374
|
+
//#endregion
|
|
375
|
+
//#region src/survey/item-key.ts
|
|
376
|
+
/**
|
|
377
|
+
* SurveyItemKey stores the key of the item and the path to the item.
|
|
378
|
+
*/
|
|
379
|
+
var SurveyItemKey = class {
|
|
380
|
+
_itemKey;
|
|
381
|
+
_path;
|
|
382
|
+
_keySeparator;
|
|
383
|
+
constructor(itemKey, path, keySeparator = ".") {
|
|
384
|
+
this._itemKey = itemKey;
|
|
385
|
+
this._path = path ?? [];
|
|
386
|
+
this._keySeparator = keySeparator;
|
|
387
|
+
}
|
|
388
|
+
get itemKey() {
|
|
389
|
+
return this._itemKey;
|
|
390
|
+
}
|
|
391
|
+
get path() {
|
|
392
|
+
return this._path;
|
|
393
|
+
}
|
|
394
|
+
get parentFullKey() {
|
|
395
|
+
return this._path.join(this._keySeparator);
|
|
396
|
+
}
|
|
397
|
+
get fullKey() {
|
|
398
|
+
return [...this._path, this._itemKey].join(this._keySeparator);
|
|
399
|
+
}
|
|
400
|
+
get isRoot() {
|
|
401
|
+
return this._path.length === 0;
|
|
402
|
+
}
|
|
403
|
+
get keySeparator() {
|
|
404
|
+
return this._keySeparator;
|
|
405
|
+
}
|
|
406
|
+
set keySeparator(keySeparator) {
|
|
407
|
+
this._keySeparator = keySeparator;
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
//#endregion
|
|
412
|
+
//#region src/survey/survey-file-schema.ts
|
|
413
|
+
const CURRENT_SURVEY_SCHEMA = "https://github.com/case-framework/case-survey-toolkit/packages/survey-core/schemas/survey-schema.json";
|
|
414
|
+
|
|
415
|
+
//#endregion
|
|
416
|
+
//#region src/survey/utils/translations.ts
|
|
417
|
+
const validateLocale = (locale) => {
|
|
418
|
+
if (locale.trim() === "") throw new Error("Locale cannot be empty");
|
|
419
|
+
};
|
|
420
|
+
var SurveyItemTranslations = class {
|
|
421
|
+
_translations;
|
|
422
|
+
constructor() {
|
|
423
|
+
this._translations = {};
|
|
424
|
+
}
|
|
425
|
+
setContent(locale, contentKey, content) {
|
|
426
|
+
validateLocale(locale);
|
|
427
|
+
if (!this._translations?.[locale]) {
|
|
428
|
+
if (!content) return;
|
|
429
|
+
this._translations[locale] = {};
|
|
430
|
+
}
|
|
431
|
+
if (!content) delete this._translations[locale][contentKey];
|
|
432
|
+
else this._translations[locale][contentKey] = content;
|
|
433
|
+
}
|
|
434
|
+
setAllForLocale(locale, content) {
|
|
435
|
+
validateLocale(locale);
|
|
436
|
+
if (!this._translations?.[locale]) {
|
|
437
|
+
if (!content) return;
|
|
438
|
+
this._translations[locale] = {};
|
|
439
|
+
}
|
|
440
|
+
this._translations[locale] = content || {};
|
|
441
|
+
}
|
|
442
|
+
get locales() {
|
|
443
|
+
return Object.keys(this._translations || {});
|
|
444
|
+
}
|
|
445
|
+
getAllForLocale(locale) {
|
|
446
|
+
return this._translations?.[locale];
|
|
447
|
+
}
|
|
448
|
+
getContent(locale, contentKey, fallbackLocale) {
|
|
449
|
+
const content = this._translations?.[locale]?.[contentKey];
|
|
450
|
+
if (content) return content;
|
|
451
|
+
if (fallbackLocale) return this._translations?.[fallbackLocale]?.[contentKey];
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
var SurveyTranslations = class {
|
|
455
|
+
_translations;
|
|
456
|
+
constructor(translations) {
|
|
457
|
+
this._translations = translations || {};
|
|
458
|
+
}
|
|
459
|
+
serialize() {
|
|
460
|
+
if (this.locales.length === 0) return;
|
|
461
|
+
return this._translations;
|
|
462
|
+
}
|
|
463
|
+
get locales() {
|
|
464
|
+
return Object.keys(this._translations);
|
|
465
|
+
}
|
|
466
|
+
removeLocale(locale) {
|
|
467
|
+
validateLocale(locale);
|
|
468
|
+
delete this._translations[locale];
|
|
469
|
+
}
|
|
470
|
+
renameLocale(oldLocale, newLocale) {
|
|
471
|
+
validateLocale(oldLocale);
|
|
472
|
+
validateLocale(newLocale);
|
|
473
|
+
if (this._translations[oldLocale]) {
|
|
474
|
+
this._translations[newLocale] = this._translations[oldLocale];
|
|
475
|
+
delete this._translations[oldLocale];
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
cloneLocaleAs(locale, newLocale) {
|
|
479
|
+
validateLocale(locale);
|
|
480
|
+
validateLocale(newLocale);
|
|
481
|
+
if (this._translations[locale]) this._translations[newLocale] = structuredCloneMethod(this._translations[locale]);
|
|
482
|
+
}
|
|
483
|
+
get surveyCardContent() {
|
|
484
|
+
const translations = {};
|
|
485
|
+
for (const locale of this.locales) {
|
|
486
|
+
const contentForLocale = this._translations?.[locale]?.surveyCardContent;
|
|
487
|
+
if (contentForLocale) translations[locale] = contentForLocale;
|
|
488
|
+
}
|
|
489
|
+
return translations;
|
|
490
|
+
}
|
|
491
|
+
get navigationContent() {
|
|
492
|
+
const translations = {};
|
|
493
|
+
for (const locale of this.locales) {
|
|
494
|
+
const contentForLocale = this._translations?.[locale]?.navigationContent;
|
|
495
|
+
if (contentForLocale) translations[locale] = contentForLocale;
|
|
496
|
+
}
|
|
497
|
+
return translations;
|
|
498
|
+
}
|
|
499
|
+
get validationMessages() {
|
|
500
|
+
const translations = {};
|
|
501
|
+
for (const locale of this.locales) {
|
|
502
|
+
const contentForLocale = this._translations?.[locale]?.validationMessages;
|
|
503
|
+
if (contentForLocale) translations[locale] = contentForLocale;
|
|
504
|
+
}
|
|
505
|
+
return translations;
|
|
506
|
+
}
|
|
507
|
+
setSurveyCardContent(locale, content) {
|
|
508
|
+
validateLocale(locale);
|
|
509
|
+
if (!this._translations[locale]) {
|
|
510
|
+
if (!content) return;
|
|
511
|
+
this._translations[locale] = {};
|
|
512
|
+
}
|
|
513
|
+
this._translations[locale].surveyCardContent = content;
|
|
514
|
+
}
|
|
515
|
+
setNavigationContent(locale, content) {
|
|
516
|
+
validateLocale(locale);
|
|
517
|
+
if (!this._translations[locale]) {
|
|
518
|
+
if (!content) return;
|
|
519
|
+
this._translations[locale] = {};
|
|
520
|
+
}
|
|
521
|
+
this._translations[locale].navigationContent = content;
|
|
522
|
+
}
|
|
523
|
+
setValidationMessages(locale, content) {
|
|
524
|
+
validateLocale(locale);
|
|
525
|
+
if (!this._translations[locale]) {
|
|
526
|
+
if (!content) return;
|
|
527
|
+
this._translations[locale] = {};
|
|
528
|
+
}
|
|
529
|
+
this._translations[locale].validationMessages = content;
|
|
530
|
+
}
|
|
531
|
+
getItemTranslations(itemId) {
|
|
532
|
+
const itemTranslations = new SurveyItemTranslations();
|
|
533
|
+
for (const locale of this.locales) {
|
|
534
|
+
const contentForLocale = this._translations?.[locale].itemTranslations?.[itemId];
|
|
535
|
+
itemTranslations.setAllForLocale(locale, contentForLocale);
|
|
536
|
+
}
|
|
537
|
+
return itemTranslations;
|
|
538
|
+
}
|
|
539
|
+
setItemTranslations(itemId, itemContent) {
|
|
540
|
+
itemContent?.locales.forEach((locale) => validateLocale(locale));
|
|
541
|
+
if (!itemContent) {
|
|
542
|
+
for (const locale of this.locales) if (this._translations[locale].itemTranslations?.[itemId]) delete this._translations[locale].itemTranslations?.[itemId];
|
|
543
|
+
} else {
|
|
544
|
+
const localesInUpdate = itemContent.locales;
|
|
545
|
+
for (const locale of localesInUpdate) if (!this.locales.includes(locale)) this._translations[locale] = {};
|
|
546
|
+
for (const locale of this.locales) if (localesInUpdate.includes(locale)) {
|
|
547
|
+
if (!this._translations[locale]) this._translations[locale] = {};
|
|
548
|
+
if (!this._translations[locale].itemTranslations) this._translations[locale].itemTranslations = {};
|
|
549
|
+
this._translations[locale].itemTranslations[itemId] = itemContent.getAllForLocale(locale) ?? {};
|
|
550
|
+
} else delete this._translations[locale].itemTranslations[itemId];
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Rename a component key (within an item) - update key in all translations and remove old key
|
|
555
|
+
* @param itemKey - The key of the item
|
|
556
|
+
* @param oldKey - The old key of the component
|
|
557
|
+
* @param newKey - The new key of the component
|
|
558
|
+
*/
|
|
559
|
+
onComponentKeyChanged(itemKey, oldKey, newKey) {
|
|
560
|
+
for (const locale of this.locales) {
|
|
561
|
+
const itemTranslations = this._translations?.[locale].itemTranslations?.[itemKey];
|
|
562
|
+
if (itemTranslations) {
|
|
563
|
+
for (const key of Object.keys(itemTranslations)) if (key.startsWith(oldKey + ".") || key === oldKey) {
|
|
564
|
+
itemTranslations[key.replace(oldKey, newKey)] = { ...itemTranslations[key] };
|
|
565
|
+
delete itemTranslations[key];
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Remove all translations for a component
|
|
572
|
+
* @param itemId - The id of the item
|
|
573
|
+
* @param componentKey - The key of the component
|
|
574
|
+
*/
|
|
575
|
+
onComponentDeleted(itemId, componentKey) {
|
|
576
|
+
for (const locale of this.locales) {
|
|
577
|
+
const itemTranslations = this._translations?.[locale].itemTranslations?.[itemId];
|
|
578
|
+
if (itemTranslations) {
|
|
579
|
+
for (const key of Object.keys(itemTranslations)) if (key.startsWith(componentKey + ".") || key === componentKey) delete itemTranslations[key];
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Remove all translations for an item
|
|
585
|
+
* @param id - The id of the item
|
|
586
|
+
*/
|
|
587
|
+
onItemDeleted(id) {
|
|
588
|
+
for (const locale of this.locales) delete this._translations[locale].itemTranslations?.[id];
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
//#endregion
|
|
593
|
+
//#region src/survey/utils/group-utils.ts
|
|
594
|
+
/**
|
|
595
|
+
* Shared utilities for array operations.
|
|
596
|
+
*/
|
|
597
|
+
/**
|
|
598
|
+
* Swap two elements in an array by index.
|
|
599
|
+
* @returns A new array with the elements swapped
|
|
600
|
+
*/
|
|
601
|
+
function swapArrayElements(arr, fromIndex, toIndex) {
|
|
602
|
+
const result = [...arr];
|
|
603
|
+
[result[fromIndex], result[toIndex]] = [result[toIndex], result[fromIndex]];
|
|
604
|
+
return result;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Move an element from one index to another.
|
|
608
|
+
* @returns A new array with the element moved
|
|
609
|
+
*/
|
|
610
|
+
function moveArrayElement(arr, fromIndex, toIndex) {
|
|
611
|
+
const result = [...arr];
|
|
612
|
+
const [moved] = result.splice(fromIndex, 1);
|
|
613
|
+
result.splice(toIndex, 0, moved);
|
|
614
|
+
return result;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
//#endregion
|
|
618
|
+
//#region src/survey/registry/built-in-items.ts
|
|
619
|
+
var GroupItemCore = class extends SurveyItemCore {
|
|
620
|
+
type = ReservedSurveyItemTypes.Group;
|
|
621
|
+
parseConfig(rawConfig) {
|
|
622
|
+
const cfg = rawConfig ?? {};
|
|
623
|
+
return {
|
|
624
|
+
items: cfg.items,
|
|
625
|
+
shuffleItems: cfg.shuffleItems,
|
|
626
|
+
isRoot: cfg.isRoot
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
serializeConfig() {
|
|
630
|
+
return this.config;
|
|
631
|
+
}
|
|
632
|
+
isInteractive() {
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
getAvailableResponseValueSlots() {
|
|
636
|
+
return {};
|
|
637
|
+
}
|
|
638
|
+
isRoot() {
|
|
639
|
+
return this.config.isRoot ?? false;
|
|
640
|
+
}
|
|
641
|
+
get items() {
|
|
642
|
+
return this.config.items ?? [];
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Add a child item id to this group at the given index.
|
|
646
|
+
* @param itemId The id of the item to add to this group.
|
|
647
|
+
* @param index The index at which to add the item. If not provided, the item is added to the end of the group.
|
|
648
|
+
*/
|
|
649
|
+
addChild(itemId, index) {
|
|
650
|
+
const items = this.config.items ??= [];
|
|
651
|
+
const insertIndex = index !== void 0 ? Math.min(index, items.length) : items.length;
|
|
652
|
+
items.splice(insertIndex, 0, itemId);
|
|
653
|
+
this.updateRawItem({
|
|
654
|
+
...this.rawItem,
|
|
655
|
+
config: { ...this.config }
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Remove a child item id from this group.
|
|
660
|
+
* @param itemId The id of the item to remove from this group.
|
|
661
|
+
*/
|
|
662
|
+
removeChild(itemId) {
|
|
663
|
+
const items = this.config.items ??= [];
|
|
664
|
+
const index = items.indexOf(itemId);
|
|
665
|
+
if (index !== -1) {
|
|
666
|
+
items.splice(index, 1);
|
|
667
|
+
this.updateRawItem({
|
|
668
|
+
...this.rawItem,
|
|
669
|
+
config: { ...this.config }
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Check if an item is a direct child of this group.
|
|
675
|
+
*/
|
|
676
|
+
hasChild(itemId) {
|
|
677
|
+
return this.items.includes(itemId);
|
|
678
|
+
}
|
|
679
|
+
/** Whether items in this group should be shuffled. */
|
|
680
|
+
get shuffleItems() {
|
|
681
|
+
return this.config.shuffleItems ?? false;
|
|
682
|
+
}
|
|
683
|
+
set shuffleItems(value) {
|
|
684
|
+
this.config.shuffleItems = value;
|
|
685
|
+
this.updateRawItem({
|
|
686
|
+
...this.rawItem,
|
|
687
|
+
config: { ...this.config }
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Get the ordered list of child item ids.
|
|
692
|
+
*/
|
|
693
|
+
getChildrenIds() {
|
|
694
|
+
return [...this.items];
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Swap two items by their positions in the group.
|
|
698
|
+
* @throws Error if indices are out of bounds
|
|
699
|
+
*/
|
|
700
|
+
swapItemsByIndex(from, to) {
|
|
701
|
+
const items = this.items;
|
|
702
|
+
if (from < 0 || from >= items.length || to < 0 || to >= items.length) throw new Error(`Index out of bounds. Valid range is 0-${items.length - 1}`);
|
|
703
|
+
if (from === to) return;
|
|
704
|
+
this.config.items = swapArrayElements(items, from, to);
|
|
705
|
+
this.updateRawItem({
|
|
706
|
+
...this.rawItem,
|
|
707
|
+
config: { ...this.config }
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Swap two items by their ids.
|
|
712
|
+
* @throws Error if either id is not found in this group
|
|
713
|
+
*/
|
|
714
|
+
swapItemsById(id, withId) {
|
|
715
|
+
const items = this.items;
|
|
716
|
+
const index1 = items.indexOf(id);
|
|
717
|
+
const index2 = items.indexOf(withId);
|
|
718
|
+
if (index1 === -1) throw new Error(`Item '${id}' not found in group '${this.key}'`);
|
|
719
|
+
if (index2 === -1) throw new Error(`Item '${withId}' not found in group '${this.key}'`);
|
|
720
|
+
this.swapItemsByIndex(index1, index2);
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Move an item by id to a specific index.
|
|
724
|
+
* @throws Error if the item is not found or index is out of bounds
|
|
725
|
+
*/
|
|
726
|
+
moveItemToIndex(id, index) {
|
|
727
|
+
const items = this.items;
|
|
728
|
+
const fromIndex = items.indexOf(id);
|
|
729
|
+
if (fromIndex === -1) throw new Error(`Item '${id}' not found in group '${this.key}'`);
|
|
730
|
+
if (index < 0 || index >= items.length) throw new Error(`Index out of bounds. Valid range is 0-${items.length - 1}`);
|
|
731
|
+
if (fromIndex === index) return;
|
|
732
|
+
this.config.items = moveArrayElement(items, fromIndex, index);
|
|
733
|
+
this.updateRawItem({
|
|
734
|
+
...this.rawItem,
|
|
735
|
+
config: { ...this.config }
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
var PageBreakItemCore = class extends SurveyItemCore {
|
|
740
|
+
type = ReservedSurveyItemTypes.PageBreak;
|
|
741
|
+
parseConfig(_rawConfig) {
|
|
742
|
+
return {};
|
|
743
|
+
}
|
|
744
|
+
serializeConfig() {}
|
|
745
|
+
isInteractive() {
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
getAvailableResponseValueSlots() {
|
|
749
|
+
return {};
|
|
750
|
+
}
|
|
751
|
+
};
|
|
752
|
+
const builtInItemCoreRegistry = {
|
|
753
|
+
[ReservedSurveyItemTypes.Group]: GroupItemCore,
|
|
754
|
+
[ReservedSurveyItemTypes.PageBreak]: PageBreakItemCore
|
|
755
|
+
};
|
|
756
|
+
const isBuiltInItemType = (itemType) => itemType in builtInItemCoreRegistry;
|
|
757
|
+
|
|
758
|
+
//#endregion
|
|
759
|
+
//#region src/survey/registry/item-registry.ts
|
|
760
|
+
/**
|
|
761
|
+
* Creates a handler instance for a raw survey item.
|
|
762
|
+
* Uses built-in registry for group/page-break, otherwise the provided plugin registry.
|
|
763
|
+
*/
|
|
764
|
+
function createItemCore(rawItem, pluginRegistry) {
|
|
765
|
+
if (isBuiltInItemType(rawItem.itemType)) {
|
|
766
|
+
const HandlerClass = builtInItemCoreRegistry[rawItem.itemType];
|
|
767
|
+
return new HandlerClass(rawItem);
|
|
768
|
+
}
|
|
769
|
+
if (pluginRegistry && rawItem.itemType in pluginRegistry) {
|
|
770
|
+
const HandlerClass = pluginRegistry[rawItem.itemType];
|
|
771
|
+
return new HandlerClass(rawItem);
|
|
772
|
+
}
|
|
773
|
+
throw new Error(`Unknown item type: ${rawItem.itemType}`);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
//#endregion
|
|
777
|
+
//#region src/survey/survey.ts
|
|
778
|
+
var Survey = class Survey {
|
|
779
|
+
maxItemsPerPage;
|
|
780
|
+
metadata;
|
|
781
|
+
surveyItems = /* @__PURE__ */ new Map();
|
|
782
|
+
_templateValues = /* @__PURE__ */ new Map();
|
|
783
|
+
_translations;
|
|
784
|
+
constructor(pluginRegistry) {
|
|
785
|
+
this.pluginRegistry = pluginRegistry;
|
|
786
|
+
this._translations = new SurveyTranslations();
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Create a survey item from raw JSON data.
|
|
790
|
+
* Uses the survey's plugin registry when available.
|
|
791
|
+
*/
|
|
792
|
+
createItemFromRaw(rawItem) {
|
|
793
|
+
return createItemCore(rawItem, this.pluginRegistry);
|
|
794
|
+
}
|
|
795
|
+
static fromJson(json, pluginRegistry) {
|
|
796
|
+
const survey = new Survey(pluginRegistry);
|
|
797
|
+
const rawSurvey = json;
|
|
798
|
+
if (rawSurvey.$schema !== CURRENT_SURVEY_SCHEMA) throw new Error(`Unsupported survey schema: ${rawSurvey.$schema}`);
|
|
799
|
+
survey.surveyItems = /* @__PURE__ */ new Map();
|
|
800
|
+
if (!rawSurvey.surveyItems || rawSurvey.surveyItems.length === 0) throw new Error("surveyItems is required");
|
|
801
|
+
rawSurvey.surveyItems.forEach((item) => {
|
|
802
|
+
const surveyItem = createItemCore(item, pluginRegistry);
|
|
803
|
+
survey.surveyItems.set(surveyItem.id, surveyItem);
|
|
804
|
+
});
|
|
805
|
+
if (rawSurvey.templateValues) survey._templateValues = deserializeTemplateValues(rawSurvey.templateValues);
|
|
806
|
+
survey._translations = new SurveyTranslations(rawSurvey.translations);
|
|
807
|
+
if (rawSurvey.maxItemsPerPage) survey.maxItemsPerPage = rawSurvey.maxItemsPerPage;
|
|
808
|
+
if (rawSurvey.metadata) survey.metadata = rawSurvey.metadata;
|
|
809
|
+
return survey;
|
|
810
|
+
}
|
|
811
|
+
serialize() {
|
|
812
|
+
const json = {
|
|
813
|
+
$schema: CURRENT_SURVEY_SCHEMA,
|
|
814
|
+
surveyItems: Array.from(this.surveyItems.values()).map((item) => item.rawItem)
|
|
815
|
+
};
|
|
816
|
+
json.translations = this._translations?.serialize();
|
|
817
|
+
if (this._templateValues) json.templateValues = serializeTemplateValues(this._templateValues);
|
|
818
|
+
if (this.maxItemsPerPage) json.maxItemsPerPage = this.maxItemsPerPage;
|
|
819
|
+
if (this.metadata) json.metadata = this.metadata;
|
|
820
|
+
return json;
|
|
821
|
+
}
|
|
822
|
+
get surveyKey() {
|
|
823
|
+
if (!this.rootItem) return;
|
|
824
|
+
return this.rootItem.key;
|
|
825
|
+
}
|
|
826
|
+
get locales() {
|
|
827
|
+
return this._translations?.locales || [];
|
|
828
|
+
}
|
|
829
|
+
get rootItem() {
|
|
830
|
+
return Array.from(this.surveyItems.values()).find((item) => item instanceof GroupItemCore && item.isRoot);
|
|
831
|
+
}
|
|
832
|
+
get keyIndex() {
|
|
833
|
+
const index = [];
|
|
834
|
+
for (const item of this.surveyItems.values()) {
|
|
835
|
+
const path = this.getItemPath(item.id);
|
|
836
|
+
index.push({
|
|
837
|
+
itemId: item.id,
|
|
838
|
+
key: item.key,
|
|
839
|
+
keyPath: path.map((id) => this.surveyItems.get(id)?.key ?? ""),
|
|
840
|
+
path
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
return index;
|
|
844
|
+
}
|
|
845
|
+
getItemPath(itemId) {
|
|
846
|
+
const item = this.surveyItems.get(itemId);
|
|
847
|
+
if (!item) throw new Error(`Item ${itemId} not found`);
|
|
848
|
+
if (item instanceof GroupItemCore && item.isRoot()) return [];
|
|
849
|
+
const parentItem = this.getParentItem(itemId);
|
|
850
|
+
if (!parentItem) throw new Error(`Parent item for ${itemId} not found`);
|
|
851
|
+
return [...this.getItemPath(parentItem.id), parentItem.id];
|
|
852
|
+
}
|
|
853
|
+
getItemKey(itemId) {
|
|
854
|
+
const item = this.surveyItems.get(itemId);
|
|
855
|
+
if (!item) return;
|
|
856
|
+
const keyPath = this.getItemPath(itemId).map((id) => this.surveyItems.get(id)?.key ?? "");
|
|
857
|
+
return new SurveyItemKey(item.key, keyPath);
|
|
858
|
+
}
|
|
859
|
+
getParentItem(itemId) {
|
|
860
|
+
const item = this.surveyItems.get(itemId);
|
|
861
|
+
if (!item) throw new Error(`Item ${itemId} not found`);
|
|
862
|
+
if (item instanceof GroupItemCore && item.isRoot()) return;
|
|
863
|
+
const parentItem = Array.from(this.surveyItems.values()).find((item) => item instanceof GroupItemCore && item.config.items?.includes(itemId));
|
|
864
|
+
if (!parentItem) return;
|
|
865
|
+
return parentItem;
|
|
866
|
+
}
|
|
867
|
+
getChildrenItems(parentId) {
|
|
868
|
+
const parentItem = this.surveyItems.get(parentId);
|
|
869
|
+
if (!parentItem || !(parentItem instanceof GroupItemCore)) return [];
|
|
870
|
+
return parentItem.config.items?.map((id) => this.surveyItems.get(id))?.filter((item) => item !== void 0) || [];
|
|
871
|
+
}
|
|
872
|
+
getSiblings(itemId) {
|
|
873
|
+
if (!this.surveyItems.get(itemId)) return [];
|
|
874
|
+
return this.getParentItem(itemId)?.items?.map((id) => this.surveyItems.get(id))?.filter((item) => item !== void 0) || [];
|
|
875
|
+
}
|
|
876
|
+
get translations() {
|
|
877
|
+
if (!this._translations) this._translations = new SurveyTranslations();
|
|
878
|
+
return this._translations;
|
|
879
|
+
}
|
|
880
|
+
getItemTranslations(id) {
|
|
881
|
+
if (!this.surveyItems.get(id)) throw new Error(`Item ${id} not found`);
|
|
882
|
+
return this._translations?.getItemTranslations(id);
|
|
883
|
+
}
|
|
884
|
+
getTemplateValue(templateValueKey) {
|
|
885
|
+
return this._templateValues?.get(templateValueKey);
|
|
886
|
+
}
|
|
887
|
+
setTemplateValue(templateValueKey, templateValue) {
|
|
888
|
+
if (!this._templateValues) this._templateValues = /* @__PURE__ */ new Map();
|
|
889
|
+
this._templateValues?.set(templateValueKey, templateValue);
|
|
890
|
+
}
|
|
891
|
+
deleteTemplateValue(templateValueKey) {
|
|
892
|
+
this._templateValues?.delete(templateValueKey);
|
|
893
|
+
}
|
|
894
|
+
getTemplateValueKeys() {
|
|
895
|
+
return Array.from(this._templateValues?.keys() || []);
|
|
896
|
+
}
|
|
897
|
+
getAvailableResponseValueSlots(byType) {
|
|
898
|
+
let valueRefs = {};
|
|
899
|
+
for (const item of this.surveyItems.values()) valueRefs = {
|
|
900
|
+
...valueRefs,
|
|
901
|
+
...item.getAvailableResponseValueSlots(byType)
|
|
902
|
+
};
|
|
903
|
+
return valueRefs;
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Get all reference usages for the survey
|
|
907
|
+
* @param forItemId - optional item id to filter usages for a specific item and its children (if not provided, all usages are returned)
|
|
908
|
+
* @returns all reference usages for the survey (or for a specific item and its children)
|
|
909
|
+
*/
|
|
910
|
+
getReferenceUsages(forItemId) {
|
|
911
|
+
const usages = [];
|
|
912
|
+
for (const item of this.surveyItems.values()) {
|
|
913
|
+
if (forItemId && item.id !== forItemId && !this.isDescendantOf(item.id, forItemId)) continue;
|
|
914
|
+
usages.push(...item.getReferenceUsages());
|
|
915
|
+
}
|
|
916
|
+
if (this._templateValues) for (const [templateValueKey, templateValue] of this._templateValues.entries()) for (const ref of templateValue.expression?.responseVariableRefs || []) usages.push({
|
|
917
|
+
itemId: templateValueKey,
|
|
918
|
+
usageType: ReferenceUsageType.templateValues,
|
|
919
|
+
valueReference: ref
|
|
920
|
+
});
|
|
921
|
+
return usages;
|
|
922
|
+
}
|
|
923
|
+
isDescendantOf(targetId, ancestorId) {
|
|
924
|
+
if (targetId === ancestorId) return true;
|
|
925
|
+
return this.getItemPath(targetId).includes(ancestorId);
|
|
926
|
+
}
|
|
927
|
+
};
|
|
928
|
+
|
|
929
|
+
//#endregion
|
|
930
|
+
export { ValueReference as C, structuredCloneMethod as D, shuffleIndices as E, ReferenceUsageType as S, generateId as T, Expression as _, validateLocale as a, FunctionExpressionNames as b, SurveyItemCore as c, deserializeTemplateValues as d, serializeTemplateValue as f, ContextVariableType as g, ContextVariableExpression as h, SurveyTranslations as i, TemplateDefTypes as l, ConstExpression as m, GroupItemCore as n, SurveyItemKey as o, serializeTemplateValues as p, SurveyItemTranslations as r, ReservedSurveyItemTypes as s, Survey as t, deserializeTemplateValue as u, ExpressionType as v, ValueReferenceMethod as w, ResponseVariableExpression as x, FunctionExpression as y };
|
|
931
|
+
//# sourceMappingURL=survey-C3ZHI-5z.mjs.map
|