@media-quest/builder 0.0.25 → 0.0.26
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/package.json +15 -15
- package/src/Builder-option.ts +64 -64
- package/src/Builder-page.spec.ts +2 -160
- package/src/Builder-page.ts +6 -83
- package/src/Builder-question.spec.ts +68 -68
- package/src/Builder-question.ts +102 -102
- package/src/Builder-schema.spec.ts +86 -114
- package/src/Builder-schema.ts +13 -9
- package/src/Builder-text.spec.ts +24 -24
- package/src/Builder-text.ts +57 -57
- package/src/BuilderObject.ts +30 -29
- package/src/BuilderTag.ts +96 -96
- package/src/builder-compiler.ts +1 -1
- package/src/code-book/codebook-variable.ts +29 -0
- package/src/{codebook.ts → code-book/codebook.ts} +72 -72
- package/src/primitives/ID.spec.ts +39 -39
- package/src/primitives/ID.ts +138 -119
- package/src/primitives/page-prefix.ts +59 -59
- package/src/primitives/varID.ts +12 -12
- package/src/public-api.ts +28 -26
- package/src/rulebuilder/Builder-rule.spec.ts +323 -323
- package/src/rulebuilder/Builder-rule.ts +191 -191
- package/src/rulebuilder/RuleBuilder-test-utils.ts +320 -320
- package/src/rulebuilder/RuleInput.ts +30 -30
- package/src/rulebuilder/RuleVariable.ts +34 -48
- package/src/rulebuilder/SingleSelectItem.ts +9 -8
- package/src/rulebuilder/condition/Builder-condition-group.ts +14 -6
- package/src/rulebuilder/condition/Builder-condition.spec.ts +12 -12
- package/src/rulebuilder/condition/Builder-condition.ts +17 -13
- package/src/rulebuilder/index.ts +16 -3
- package/src/rulebuilder/page-action-manager.ts +33 -33
- package/src/rulebuilder/rule2/Rule2.ts +211 -215
- package/src/schema-config.ts +25 -25
- package/src/sum-score/sum-score-answer.ts +6 -0
- package/src/sum-score/sum-score-manager.spec.ts +189 -0
- package/src/sum-score/sum-score-manager.ts +154 -0
- package/src/sum-score/sum-score-membership.ts +45 -0
- package/src/sum-score/sum-score-variable.spec.ts +151 -0
- package/src/sum-score/sum-score-variable.ts +36 -0
- package/src/{variable → sum-score}/sum-score.ts +122 -130
- package/tsconfig.tsbuildinfo +1 -1
- package/src/variable/b-variable.ts +0 -68
- package/src/variable/mq-variable.spec.ts +0 -147
- package/src/variable/sum-score-variable.ts +0 -50
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@media-quest/builder",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Builder library for Media-quest schemas",
|
|
5
|
-
"main": "src/public-api.ts",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"tsc:check:builder": "tsc --watch --noEmit",
|
|
9
|
-
"clean": "rimraf dist",
|
|
10
|
-
"buildXXX": "npm run clean && tsup src/public-api.ts --sourcemap inline --format cjs,esm --dts"
|
|
11
|
-
},
|
|
12
|
-
"dependencies": {
|
|
13
|
-
"@media-quest/engine": "0.0.
|
|
14
|
-
}
|
|
15
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@media-quest/builder",
|
|
3
|
+
"version": "0.0.26",
|
|
4
|
+
"description": "Builder library for Media-quest schemas",
|
|
5
|
+
"main": "src/public-api.ts",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"tsc:check:builder": "tsc --watch --noEmit",
|
|
9
|
+
"clean": "rimraf dist",
|
|
10
|
+
"buildXXX": "npm run clean && tsup src/public-api.ts --sourcemap inline --format cjs,esm --dts"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@media-quest/engine": "0.0.26"
|
|
14
|
+
}
|
|
15
|
+
}
|
package/src/Builder-option.ts
CHANGED
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
import { BuilderObject } from "./BuilderObject";
|
|
2
|
-
import type { BuilderOptionTheme } from "./theme/IDefaultTheme";
|
|
3
|
-
import { DefaultTheme } from "./theme/IDefaultTheme";
|
|
4
|
-
import { AudioFile } from "./media-files";
|
|
5
|
-
import { OptionID } from "./primitives/ID";
|
|
6
|
-
|
|
7
|
-
export interface BuilderOptionDto {
|
|
8
|
-
readonly id: OptionID;
|
|
9
|
-
readonly value: number;
|
|
10
|
-
readonly label: string;
|
|
11
|
-
readonly labelAudio?: AudioFile;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export class BuilderOption extends BuilderObject<"builder-question-option", BuilderOptionDto> {
|
|
15
|
-
readonly objectType = "builder-question-option";
|
|
16
|
-
id: OptionID;
|
|
17
|
-
value: number;
|
|
18
|
-
label = "";
|
|
19
|
-
private _labelAudioFile: AudioFile | false = false;
|
|
20
|
-
get labelAudioFile() {
|
|
21
|
-
return this._labelAudioFile;
|
|
22
|
-
}
|
|
23
|
-
set labelAudioFile(audioFile: AudioFile | false) {
|
|
24
|
-
this._labelAudioFile = audioFile;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
private constructor(dto: BuilderOptionDto) {
|
|
28
|
-
super(dto);
|
|
29
|
-
this.id = dto.id;
|
|
30
|
-
this.value = dto.value;
|
|
31
|
-
this.label = dto.label;
|
|
32
|
-
// this.theme = dto.theme;
|
|
33
|
-
}
|
|
34
|
-
public static create(value: number, label: string) {
|
|
35
|
-
const id = OptionID.create();
|
|
36
|
-
const dto: BuilderOptionDto = {
|
|
37
|
-
id,
|
|
38
|
-
value,
|
|
39
|
-
label,
|
|
40
|
-
};
|
|
41
|
-
const instance = new BuilderOption(dto);
|
|
42
|
-
return instance;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
public static fromJson(dto: BuilderOptionDto) {
|
|
46
|
-
const instance = new BuilderOption(dto);
|
|
47
|
-
return instance;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
toJson(): BuilderOptionDto {
|
|
51
|
-
const dto: BuilderOptionDto = {
|
|
52
|
-
id: this.id,
|
|
53
|
-
value: this.value,
|
|
54
|
-
label: this.label,
|
|
55
|
-
};
|
|
56
|
-
return dto;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
clone(): BuilderOptionDto {
|
|
60
|
-
const dto = this.toJson();
|
|
61
|
-
const cloneDto: BuilderOptionDto = { ...dto, id: OptionID.create() };
|
|
62
|
-
return cloneDto;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
1
|
+
import { BuilderObject } from "./BuilderObject";
|
|
2
|
+
import type { BuilderOptionTheme } from "./theme/IDefaultTheme";
|
|
3
|
+
import { DefaultTheme } from "./theme/IDefaultTheme";
|
|
4
|
+
import { AudioFile } from "./media-files";
|
|
5
|
+
import { OptionID } from "./primitives/ID";
|
|
6
|
+
|
|
7
|
+
export interface BuilderOptionDto {
|
|
8
|
+
readonly id: OptionID;
|
|
9
|
+
readonly value: number;
|
|
10
|
+
readonly label: string;
|
|
11
|
+
readonly labelAudio?: AudioFile;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class BuilderOption extends BuilderObject<"builder-question-option", BuilderOptionDto> {
|
|
15
|
+
readonly objectType = "builder-question-option";
|
|
16
|
+
id: OptionID;
|
|
17
|
+
value: number;
|
|
18
|
+
label = "";
|
|
19
|
+
private _labelAudioFile: AudioFile | false = false;
|
|
20
|
+
get labelAudioFile() {
|
|
21
|
+
return this._labelAudioFile;
|
|
22
|
+
}
|
|
23
|
+
set labelAudioFile(audioFile: AudioFile | false) {
|
|
24
|
+
this._labelAudioFile = audioFile;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private constructor(dto: BuilderOptionDto) {
|
|
28
|
+
super(dto);
|
|
29
|
+
this.id = dto.id;
|
|
30
|
+
this.value = dto.value;
|
|
31
|
+
this.label = dto.label;
|
|
32
|
+
// this.theme = dto.theme;
|
|
33
|
+
}
|
|
34
|
+
public static create(value: number, label: string) {
|
|
35
|
+
const id = OptionID.create();
|
|
36
|
+
const dto: BuilderOptionDto = {
|
|
37
|
+
id,
|
|
38
|
+
value,
|
|
39
|
+
label,
|
|
40
|
+
};
|
|
41
|
+
const instance = new BuilderOption(dto);
|
|
42
|
+
return instance;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public static fromJson(dto: BuilderOptionDto) {
|
|
46
|
+
const instance = new BuilderOption(dto);
|
|
47
|
+
return instance;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
toJson(): BuilderOptionDto {
|
|
51
|
+
const dto: BuilderOptionDto = {
|
|
52
|
+
id: this.id,
|
|
53
|
+
value: this.value,
|
|
54
|
+
label: this.label,
|
|
55
|
+
};
|
|
56
|
+
return dto;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
clone(): BuilderOptionDto {
|
|
60
|
+
const dto = this.toJson();
|
|
61
|
+
const cloneDto: BuilderOptionDto = { ...dto, id: OptionID.create() };
|
|
62
|
+
return cloneDto;
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/Builder-page.spec.ts
CHANGED
|
@@ -16,7 +16,6 @@ const deleteIdsFromPage = (page: BuilderPageDto) => {
|
|
|
16
16
|
});
|
|
17
17
|
};
|
|
18
18
|
U.deleteProp(page, "id");
|
|
19
|
-
page.questions.forEach(deleteIdsFromQuestion);
|
|
20
19
|
deleteIdsFromQuestion(page.defaultQuestion);
|
|
21
20
|
return page;
|
|
22
21
|
};
|
|
@@ -64,7 +63,6 @@ const questionPageDto: BuilderPageDto = {
|
|
|
64
63
|
// id: "p1" as BuilderObjectId.PageID,
|
|
65
64
|
id: PageID.create(),
|
|
66
65
|
prefix: PagePrefix.fromStringOrThrow("pxx"),
|
|
67
|
-
questions: [],
|
|
68
66
|
};
|
|
69
67
|
|
|
70
68
|
const multiQuestionPageDto: BuilderPageDto = {
|
|
@@ -92,56 +90,6 @@ const multiQuestionPageDto: BuilderPageDto = {
|
|
|
92
90
|
|
|
93
91
|
id: PageID.create(),
|
|
94
92
|
prefix: PagePrefix.fromStringOrThrow("pxx"),
|
|
95
|
-
questions: [
|
|
96
|
-
{
|
|
97
|
-
id: QuestionID.dummy.a,
|
|
98
|
-
prefix: "a",
|
|
99
|
-
text: "har du..",
|
|
100
|
-
_type: "select-one",
|
|
101
|
-
// options: []
|
|
102
|
-
options: [
|
|
103
|
-
{
|
|
104
|
-
id: "q3-opt1" as OptionID,
|
|
105
|
-
value: 0,
|
|
106
|
-
label: "Nei",
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
id: "q3-opt2" as OptionID,
|
|
110
|
-
value: 1,
|
|
111
|
-
label: "Ja",
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
id: "q3-opt3" as OptionID,
|
|
115
|
-
value: 9,
|
|
116
|
-
label: "Vet ikke",
|
|
117
|
-
},
|
|
118
|
-
],
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
id: QuestionID.create(),
|
|
122
|
-
prefix: "a",
|
|
123
|
-
text: "har du..",
|
|
124
|
-
_type: "select-one",
|
|
125
|
-
// options: []
|
|
126
|
-
options: [
|
|
127
|
-
{
|
|
128
|
-
id: OptionID.dummy.a,
|
|
129
|
-
value: 0,
|
|
130
|
-
label: "Nei",
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
id: OptionID.dummy.b,
|
|
134
|
-
value: 1,
|
|
135
|
-
label: "Ja",
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
id: OptionID.dummy.c,
|
|
139
|
-
value: 9,
|
|
140
|
-
label: "Vet ikke",
|
|
141
|
-
},
|
|
142
|
-
],
|
|
143
|
-
},
|
|
144
|
-
],
|
|
145
93
|
};
|
|
146
94
|
|
|
147
95
|
let page = BuilderPage.create("info-page", PagePrefix.fromStringOrThrow("a"));
|
|
@@ -160,39 +108,6 @@ describe("Builder Page", () => {
|
|
|
160
108
|
expect(multiQuestionPageDto).toStrictEqual(asJson2);
|
|
161
109
|
// expect(page1.prefix).toBe(pageDto.prefix);
|
|
162
110
|
});
|
|
163
|
-
test("Can change question type", () => {
|
|
164
|
-
expect(page.questions.length).toBe(0);
|
|
165
|
-
page.addQuestion("select-one");
|
|
166
|
-
page.addQuestion("select-one");
|
|
167
|
-
expect(page.questions.length).toBe(2);
|
|
168
|
-
page.pageType = "question";
|
|
169
|
-
expect(page.questions.length).toBe(0);
|
|
170
|
-
});
|
|
171
|
-
test("Can add and delete questions", () => {
|
|
172
|
-
page.pageType = "multi-select";
|
|
173
|
-
expect(page.questions.length).toBe(1);
|
|
174
|
-
const q1 = page.addQuestion("select-one");
|
|
175
|
-
const q2 = page.addQuestion("select-one");
|
|
176
|
-
expect(page.questions.length).toBe(3);
|
|
177
|
-
page.deleteQuestion(q1);
|
|
178
|
-
expect(page.questions.length).toBe(2);
|
|
179
|
-
page.deleteQuestion(q2);
|
|
180
|
-
expect(page.questions.length).toBe(1);
|
|
181
|
-
// page.pageType = 'question';
|
|
182
|
-
// expect(page.questions.length).toBe(0);
|
|
183
|
-
});
|
|
184
|
-
test("Can add question at concrete index. ", () => {
|
|
185
|
-
page.pageType = "multi-select";
|
|
186
|
-
expect(page.questions.length).toBe(1);
|
|
187
|
-
const q1 = page.addQuestion("select-one", 0);
|
|
188
|
-
expect(page.questions[0].id).toBe(q1.id);
|
|
189
|
-
const q2 = page.addQuestion("select-one", 1);
|
|
190
|
-
expect(page.questions[1].id).toBe(q2.id);
|
|
191
|
-
expect(page.questions.length).toBe(3);
|
|
192
|
-
const q3 = page.addQuestion("email", 2);
|
|
193
|
-
expect(page.questions[2]).toBe(q3);
|
|
194
|
-
expect(q3.type).toBe("email");
|
|
195
|
-
});
|
|
196
111
|
test("Can clone a page and everything except id is equal ", () => {
|
|
197
112
|
const page1 = BuilderPage.create("info-page", PagePrefix.fromStringOrThrow("as"));
|
|
198
113
|
const clone1 = BuilderPage.fromJson(page1.clone());
|
|
@@ -220,85 +135,12 @@ describe("Builder Page", () => {
|
|
|
220
135
|
const testDtoIds = (dto: BuilderPageDto) => {
|
|
221
136
|
const instance = BuilderPage.fromJson(dto);
|
|
222
137
|
const clone = BuilderPage.fromJson(instance.clone());
|
|
223
|
-
const p2QuestionIds = instance.questions.map((q) => q.id);
|
|
224
|
-
const cloneQuestionIds = clone.questions.map((q) => q.id);
|
|
225
138
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
expect(p2QuestionIds.length).toBe(cloneQuestionIds.length);
|
|
229
|
-
p2QuestionIds.forEach((id, index) => {
|
|
230
|
-
expect(id).not.toBe(cloneQuestionIds[index]);
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
instance.questions.forEach((q, qIndex) => {
|
|
234
|
-
const cloneQ = clone.questions[qIndex];
|
|
235
|
-
expect(cloneQ).toBeDefined();
|
|
236
|
-
expect(q.id).not.toBe(cloneQ.id);
|
|
237
|
-
q.options.forEach((op, opIndex) => {
|
|
238
|
-
const cloneOp = cloneQ.options[opIndex];
|
|
239
|
-
expect(cloneOp).toBeDefined();
|
|
240
|
-
expect(op.id).not.toBe(cloneOp.id);
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
// expect(p)
|
|
139
|
+
testDtoIds(questionPageDto);
|
|
140
|
+
testDtoIds(multiQuestionPageDto);
|
|
245
141
|
};
|
|
246
|
-
testDtoIds(questionPageDto);
|
|
247
|
-
testDtoIds(multiQuestionPageDto);
|
|
248
|
-
});
|
|
249
|
-
test("Can insert a new Question at index", () => {
|
|
250
|
-
const page1 = BuilderPage.create("form", pxx);
|
|
251
|
-
const q1 = page1.addQuestion("select-one");
|
|
252
|
-
const q2 = page1.addQuestion("select-many");
|
|
253
|
-
expect(page1.questions.length).toBe(3);
|
|
254
|
-
expect(page1.questions[1]).toBe(q1);
|
|
255
|
-
const q1Clone = BuilderQuestion.fromJson(q1.clone());
|
|
256
|
-
const result10 = page1.insertQuestion(q1Clone, 10);
|
|
257
|
-
expect(result10).toBeFalsy();
|
|
258
|
-
const result1 = page1.insertQuestion(q1Clone, 1);
|
|
259
|
-
expect(result1).toBeTruthy();
|
|
260
|
-
expect(page1.questions[1]).toBe(q1Clone);
|
|
261
|
-
});
|
|
262
|
-
test("Can not insert a duplicate question", () => {
|
|
263
|
-
const page1 = BuilderPage.create("form", pxx);
|
|
264
|
-
const q1 = page1.addQuestion("select-one");
|
|
265
|
-
expect(page1.questions.length).toBe(2);
|
|
266
|
-
expect(page1.questions[1]).toBe(q1);
|
|
267
|
-
const result1 = page1.insertQuestion(q1, 0);
|
|
268
|
-
expect(page1.questions.length).toBe(2);
|
|
269
|
-
expect(result1).toBeFalsy();
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
test("Can move a question", () => {
|
|
273
|
-
const page1 = BuilderPage.create("form", pxx);
|
|
274
|
-
const q1 = page1.addQuestion("select-many");
|
|
275
|
-
const q2 = page1.addQuestion("select-one");
|
|
276
|
-
const q3 = page1.addQuestion("select-one");
|
|
277
|
-
const q4 = page1.addQuestion("select-one");
|
|
278
|
-
expect(page1.questions.length).toBe(5);
|
|
279
|
-
const m1 = page1.moveQuestion(q1, 0);
|
|
280
|
-
expect(page1.questions.length).toBe(5);
|
|
281
|
-
expect(page1.questions[0]).toBe(q1);
|
|
282
|
-
expect(m1).toBeTruthy();
|
|
283
|
-
const illegalMove = page1.moveQuestion(q2, -1);
|
|
284
|
-
expect(illegalMove).toBeFalsy();
|
|
285
|
-
expect(page1.questions.length).toBe(5);
|
|
286
|
-
const m3 = page1.moveQuestion(q4, 1);
|
|
287
|
-
expect(m3).toBe(true);
|
|
288
|
-
expect(page1.questions[1]).toBe(q4);
|
|
289
142
|
});
|
|
290
143
|
|
|
291
|
-
test("Can not move a question that is not in questions-array", () => {
|
|
292
|
-
const prefix = PagePrefix.fromStringOrThrow("as1");
|
|
293
|
-
const page1 = BuilderPage.create("form", prefix);
|
|
294
|
-
const q1 = page1.addQuestion("select-many");
|
|
295
|
-
const q2 = page1.addQuestion("select-one");
|
|
296
|
-
expect(page1.questions.length).toBe(3);
|
|
297
|
-
const newQuestion = BuilderQuestion.create("select-one");
|
|
298
|
-
const m1 = page1.moveQuestion(newQuestion, 0);
|
|
299
|
-
expect(page1.questions.length).toBe(3);
|
|
300
|
-
expect(m1).toBe(false);
|
|
301
|
-
});
|
|
302
144
|
test("Can get all rule-variables.", () => {
|
|
303
145
|
const prefix = PagePrefix.fromStringOrThrow("as1");
|
|
304
146
|
const page = BuilderPage.create("question", prefix);
|
package/src/Builder-page.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { BuilderMainVideoDto } from "./BuilderMainVideoDto";
|
|
|
7
7
|
import type { BuilderMainImageDto } from "./BuilderMainImageDto";
|
|
8
8
|
import type { BuilderMainTextDto } from "./BuilderMainText";
|
|
9
9
|
import { BuilderMainText } from "./BuilderMainText";
|
|
10
|
-
import {
|
|
10
|
+
import { RuleVariableOption, RuleQuestionVariable } from "./rulebuilder";
|
|
11
11
|
import { DUtil } from "@media-quest/engine";
|
|
12
12
|
import { PagePrefix, PagePrefixValue } from "./primitives/page-prefix";
|
|
13
13
|
import { VarID } from "./primitives/varID";
|
|
@@ -24,11 +24,9 @@ export interface BuilderPageDto {
|
|
|
24
24
|
mainText: BuilderMainTextDto;
|
|
25
25
|
nextButton: BuilderOptionDto;
|
|
26
26
|
defaultQuestion: BuilderQuestionDto;
|
|
27
|
-
questions: Array<BuilderQuestionDto>;
|
|
28
27
|
mainMedia?: BuilderMainImageDto | BuilderMainVideoDto;
|
|
29
28
|
autoplaySequence: Array<string>;
|
|
30
29
|
tags: ReadonlyArray<string>;
|
|
31
|
-
// sumScoreVariables: Array<BuilderObjectId.SumScoreVariableId>
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
|
|
@@ -36,7 +34,6 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
|
|
|
36
34
|
readonly id: PageID;
|
|
37
35
|
private _pageType: BuilderPageType;
|
|
38
36
|
private _prefix: PagePrefix;
|
|
39
|
-
private _questions: Array<BuilderQuestion> = [];
|
|
40
37
|
private readonly _tags: Set<string>;
|
|
41
38
|
private _backgroundColor = "#FFFFFF";
|
|
42
39
|
mainMedia: BuilderMainVideoDto | BuilderMainImageDto | false = false;
|
|
@@ -63,7 +60,7 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
|
|
|
63
60
|
nextButton: nextButtonDto,
|
|
64
61
|
mainText: mainTextDto,
|
|
65
62
|
prefix: _prefix,
|
|
66
|
-
questions: [],
|
|
63
|
+
// questions: [],
|
|
67
64
|
tags: [],
|
|
68
65
|
};
|
|
69
66
|
|
|
@@ -84,74 +81,11 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
|
|
|
84
81
|
this.mainText = BuilderMainText.fromJson(dto.mainText);
|
|
85
82
|
this.nextButton = BuilderOption.fromJson(dto.nextButton);
|
|
86
83
|
this.defaultQuestion = BuilderQuestion.fromJson(dto.defaultQuestion);
|
|
87
|
-
this._questions = dto.questions.map((q) => BuilderQuestion.fromJson(q));
|
|
88
84
|
const tagList: string[] = Array.isArray(dto.tags) ? dto.tags : [];
|
|
89
85
|
this._tags = new Set(tagList);
|
|
90
86
|
if (dto.mainMedia) {
|
|
91
87
|
this.mainMedia = dto.mainMedia;
|
|
92
88
|
}
|
|
93
|
-
this.updateRows();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
insertQuestion(question: BuilderQuestion, atIndex: number): boolean {
|
|
97
|
-
const validIndexFn = U.isInRange(0, this._questions.length);
|
|
98
|
-
if (!validIndexFn(atIndex)) {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
const hasQuestion = !!this._questions.find((q) => q.id === question.id);
|
|
102
|
-
if (hasQuestion) {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
this._questions.splice(atIndex, 0, question);
|
|
106
|
-
return true;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
addQuestion(type: BuilderQuestionType, atIndex = -1): BuilderQuestion {
|
|
110
|
-
const question = BuilderQuestion.create(type);
|
|
111
|
-
if (atIndex < this._questions.length && atIndex >= 0) {
|
|
112
|
-
this._questions.splice(atIndex, 0, question);
|
|
113
|
-
} else {
|
|
114
|
-
this._questions.push(question);
|
|
115
|
-
}
|
|
116
|
-
return question;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Move a question in questions-array
|
|
121
|
-
* @param question (reference)
|
|
122
|
-
* @param toIndex
|
|
123
|
-
*/
|
|
124
|
-
moveQuestion(question: BuilderQuestion, toIndex: number): boolean {
|
|
125
|
-
const validToIndexFn = U.isInRange(0, this._questions.length);
|
|
126
|
-
if (!validToIndexFn(toIndex)) {
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
const currentIndex = this._questions.indexOf(question);
|
|
130
|
-
if (currentIndex < 0) {
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
this._questions.splice(currentIndex, 1);
|
|
134
|
-
this._questions.splice(toIndex, 0, question);
|
|
135
|
-
return true;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
deleteQuestion(question: BuilderQuestion) {
|
|
139
|
-
this._questions = this._questions.filter((q) => q !== question);
|
|
140
|
-
// TODO EMIT DELETED QUESTION.
|
|
141
|
-
this.updateRows();
|
|
142
|
-
}
|
|
143
|
-
private updateRows() {
|
|
144
|
-
if (this._pageType === "question" || this._pageType === "info-page") {
|
|
145
|
-
this._questions = [];
|
|
146
|
-
}
|
|
147
|
-
if (this._pageType === "form" && this._questions.length === 0) {
|
|
148
|
-
this._questions = [];
|
|
149
|
-
this.addQuestion("text");
|
|
150
|
-
}
|
|
151
|
-
if (this._pageType === "multi-select" && this._questions.length === 0) {
|
|
152
|
-
this._questions = [];
|
|
153
|
-
this.addQuestion("text");
|
|
154
|
-
}
|
|
155
89
|
}
|
|
156
90
|
|
|
157
91
|
public addTag(tag: string) {
|
|
@@ -163,15 +97,13 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
|
|
|
163
97
|
|
|
164
98
|
set pageType(value: BuilderPageType) {
|
|
165
99
|
this._pageType = value;
|
|
166
|
-
// TODO Emit All questions that are deleted? Listen for removed variables??
|
|
167
|
-
this.updateRows();
|
|
168
100
|
}
|
|
169
101
|
|
|
170
102
|
getQuestionVariables(
|
|
171
103
|
modulePrefix: SchemaPrefix,
|
|
172
104
|
pageNumber: number,
|
|
173
|
-
): ReadonlyArray<
|
|
174
|
-
const variables:
|
|
105
|
+
): ReadonlyArray<RuleQuestionVariable> {
|
|
106
|
+
const variables: RuleQuestionVariable[] = [];
|
|
175
107
|
|
|
176
108
|
if (this._pageType === "question") {
|
|
177
109
|
const pagePrefix = this.prefix;
|
|
@@ -180,9 +112,9 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
|
|
|
180
112
|
const op = this.defaultQuestion.options.map((o) => {
|
|
181
113
|
const label = o.label;
|
|
182
114
|
const value = o.value;
|
|
183
|
-
return new
|
|
115
|
+
return new RuleVariableOption(label, value);
|
|
184
116
|
});
|
|
185
|
-
const singleVar = new
|
|
117
|
+
const singleVar = new RuleQuestionVariable(varId, label, op, pageNumber);
|
|
186
118
|
variables.push(singleVar);
|
|
187
119
|
}
|
|
188
120
|
return variables;
|
|
@@ -204,7 +136,6 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
|
|
|
204
136
|
}
|
|
205
137
|
|
|
206
138
|
toJson(): BuilderPageDto {
|
|
207
|
-
const questions = this._questions.map((q) => q.toJson());
|
|
208
139
|
const mainText = this.mainText.toJson();
|
|
209
140
|
const nextButton = this.nextButton.toJson();
|
|
210
141
|
const mainMedia = this.mainMedia;
|
|
@@ -217,7 +148,6 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
|
|
|
217
148
|
tags: [...this.tags],
|
|
218
149
|
prefix: this._prefix.value,
|
|
219
150
|
defaultQuestion: this.defaultQuestion.toJson(),
|
|
220
|
-
questions,
|
|
221
151
|
};
|
|
222
152
|
if (mainMedia) {
|
|
223
153
|
dto.mainMedia = mainMedia;
|
|
@@ -229,15 +159,12 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
|
|
|
229
159
|
const dto = this.toJson();
|
|
230
160
|
const defaultQuestionClone = this.defaultQuestion.clone();
|
|
231
161
|
const mainTextClone = JSON.parse(JSON.stringify(this.mainText));
|
|
232
|
-
// const pagesClone = this
|
|
233
|
-
const questionsClone = this.questions.map((q) => q.clone());
|
|
234
162
|
const newId = PageID.create();
|
|
235
163
|
const clone: BuilderPageDto = {
|
|
236
164
|
...dto,
|
|
237
165
|
id: newId,
|
|
238
166
|
defaultQuestion: defaultQuestionClone,
|
|
239
167
|
mainText: mainTextClone,
|
|
240
|
-
questions: questionsClone,
|
|
241
168
|
};
|
|
242
169
|
// const cloneDto
|
|
243
170
|
return clone;
|
|
@@ -252,8 +179,4 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
|
|
|
252
179
|
this._backgroundColor = color;
|
|
253
180
|
}
|
|
254
181
|
}
|
|
255
|
-
|
|
256
|
-
get questions(): ReadonlyArray<BuilderQuestion> {
|
|
257
|
-
return this._questions;
|
|
258
|
-
}
|
|
259
182
|
}
|
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
import type { BuilderQuestionDto } from "./Builder-question";
|
|
2
|
-
import { BuilderQuestion } from "./Builder-question";
|
|
3
|
-
import { OptionID, QuestionID } from "./primitives/ID";
|
|
4
|
-
|
|
5
|
-
const question1: BuilderQuestionDto = {
|
|
6
|
-
id: QuestionID.validateOrThrow("id-for-question-1"),
|
|
7
|
-
prefix: "q1",
|
|
8
|
-
text: "sadf",
|
|
9
|
-
options: [],
|
|
10
|
-
_type: "select-one",
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const question2: BuilderQuestionDto = {
|
|
14
|
-
id: QuestionID.validateOrThrow("id-for-question-2"),
|
|
15
|
-
prefix: "a",
|
|
16
|
-
text: "har du..",
|
|
17
|
-
_type: "select-one",
|
|
18
|
-
// options: []
|
|
19
|
-
options: [
|
|
20
|
-
{
|
|
21
|
-
id: "q3-opt1" as OptionID,
|
|
22
|
-
value: 0,
|
|
23
|
-
label: "Nei",
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
id: "q3-opt2" as OptionID,
|
|
27
|
-
value: 1,
|
|
28
|
-
label: "Ja",
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
id: "q3-opt3" as OptionID,
|
|
32
|
-
value: 9,
|
|
33
|
-
label: "Vet ikke",
|
|
34
|
-
},
|
|
35
|
-
],
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
describe("Builder Question", () => {
|
|
39
|
-
test("Can create question from json", () => {
|
|
40
|
-
const q1 = BuilderQuestion.fromJson(question1);
|
|
41
|
-
const q1AsJson = q1.toJson();
|
|
42
|
-
expect(question1).toStrictEqual(q1AsJson);
|
|
43
|
-
const q2Instance = BuilderQuestion.fromJson(question2);
|
|
44
|
-
const q2AsJson = q2Instance.toJson();
|
|
45
|
-
expect(question2).toStrictEqual(q2AsJson);
|
|
46
|
-
});
|
|
47
|
-
test("Can add options", () => {
|
|
48
|
-
const q1 = BuilderQuestion.fromJson(question1);
|
|
49
|
-
expect(q1.options.length).toBe(0);
|
|
50
|
-
q1.addOption("Ja", 1);
|
|
51
|
-
expect(q1.options.length).toBe(1);
|
|
52
|
-
const nei = q1.addOption("Nei", 0, 0);
|
|
53
|
-
expect(q1.options.length).toBe(2);
|
|
54
|
-
expect(q1.options[0]).toBe(nei);
|
|
55
|
-
const vetIkke = q1.addOption("Vet-ikke", 9);
|
|
56
|
-
expect(q1.options.length).toBe(3);
|
|
57
|
-
expect(q1.options[2]).toBe(vetIkke);
|
|
58
|
-
});
|
|
59
|
-
test("Can delete options", () => {
|
|
60
|
-
const q = BuilderQuestion.fromJson(question2);
|
|
61
|
-
expect(q.options.length).toBe(3);
|
|
62
|
-
const o1 = q.options[0];
|
|
63
|
-
const o2 = q.options[1];
|
|
64
|
-
const o3 = q.options[2];
|
|
65
|
-
const didDelete = q.deleteOption(o1);
|
|
66
|
-
expect(q.options.length).toBe(2);
|
|
67
|
-
});
|
|
68
|
-
});
|
|
1
|
+
import type { BuilderQuestionDto } from "./Builder-question";
|
|
2
|
+
import { BuilderQuestion } from "./Builder-question";
|
|
3
|
+
import { OptionID, QuestionID } from "./primitives/ID";
|
|
4
|
+
|
|
5
|
+
const question1: BuilderQuestionDto = {
|
|
6
|
+
id: QuestionID.validateOrThrow("id-for-question-1"),
|
|
7
|
+
prefix: "q1",
|
|
8
|
+
text: "sadf",
|
|
9
|
+
options: [],
|
|
10
|
+
_type: "select-one",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const question2: BuilderQuestionDto = {
|
|
14
|
+
id: QuestionID.validateOrThrow("id-for-question-2"),
|
|
15
|
+
prefix: "a",
|
|
16
|
+
text: "har du..",
|
|
17
|
+
_type: "select-one",
|
|
18
|
+
// options: []
|
|
19
|
+
options: [
|
|
20
|
+
{
|
|
21
|
+
id: "q3-opt1" as OptionID,
|
|
22
|
+
value: 0,
|
|
23
|
+
label: "Nei",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: "q3-opt2" as OptionID,
|
|
27
|
+
value: 1,
|
|
28
|
+
label: "Ja",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "q3-opt3" as OptionID,
|
|
32
|
+
value: 9,
|
|
33
|
+
label: "Vet ikke",
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
describe("Builder Question", () => {
|
|
39
|
+
test("Can create question from json", () => {
|
|
40
|
+
const q1 = BuilderQuestion.fromJson(question1);
|
|
41
|
+
const q1AsJson = q1.toJson();
|
|
42
|
+
expect(question1).toStrictEqual(q1AsJson);
|
|
43
|
+
const q2Instance = BuilderQuestion.fromJson(question2);
|
|
44
|
+
const q2AsJson = q2Instance.toJson();
|
|
45
|
+
expect(question2).toStrictEqual(q2AsJson);
|
|
46
|
+
});
|
|
47
|
+
test("Can add options", () => {
|
|
48
|
+
const q1 = BuilderQuestion.fromJson(question1);
|
|
49
|
+
expect(q1.options.length).toBe(0);
|
|
50
|
+
q1.addOption("Ja", 1);
|
|
51
|
+
expect(q1.options.length).toBe(1);
|
|
52
|
+
const nei = q1.addOption("Nei", 0, 0);
|
|
53
|
+
expect(q1.options.length).toBe(2);
|
|
54
|
+
expect(q1.options[0]).toBe(nei);
|
|
55
|
+
const vetIkke = q1.addOption("Vet-ikke", 9);
|
|
56
|
+
expect(q1.options.length).toBe(3);
|
|
57
|
+
expect(q1.options[2]).toBe(vetIkke);
|
|
58
|
+
});
|
|
59
|
+
test("Can delete options", () => {
|
|
60
|
+
const q = BuilderQuestion.fromJson(question2);
|
|
61
|
+
expect(q.options.length).toBe(3);
|
|
62
|
+
const o1 = q.options[0];
|
|
63
|
+
const o2 = q.options[1];
|
|
64
|
+
const o3 = q.options[2];
|
|
65
|
+
const didDelete = q.deleteOption(o1);
|
|
66
|
+
expect(q.options.length).toBe(2);
|
|
67
|
+
});
|
|
68
|
+
});
|