@media-quest/builder 0.0.1 → 0.0.3
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/dist/public-api.d.mts +652 -0
- package/dist/public-api.d.ts +652 -0
- package/dist/public-api.js +2187 -0
- package/dist/public-api.mjs +2136 -0
- package/package.json +11 -3
- package/src/Builder-option.ts +67 -0
- package/src/Builder-page.spec.ts +313 -0
- package/src/Builder-page.ts +249 -0
- package/src/Builder-question.spec.ts +68 -0
- package/src/Builder-question.ts +101 -0
- package/src/Builder-schema.spec.ts +302 -0
- package/src/Builder-schema.ts +250 -0
- package/src/Builder-text.spec.ts +24 -0
- package/src/Builder-text.ts +57 -0
- package/src/BuilderMainImageDto.ts +7 -0
- package/src/BuilderMainText.ts +81 -0
- package/src/BuilderMainVideoDto.ts +10 -0
- package/src/BuilderObject.ts +69 -0
- package/src/BuilderTag.ts +97 -0
- package/src/media-files.ts +28 -0
- package/src/public-api.ts +13 -6
- package/src/rulebuilder/Builder-rule.spec.ts +207 -0
- package/src/rulebuilder/Builder-rule.ts +134 -0
- package/src/rulebuilder/RuleAction.ts +20 -0
- package/src/rulebuilder/RuleBuilder-test-utils.ts +254 -0
- package/src/rulebuilder/RuleInput.ts +44 -0
- package/src/rulebuilder/RuleVariable.ts +39 -0
- package/src/rulebuilder/SingleSelectItem.ts +135 -0
- package/src/rulebuilder/condition/Builder-condition-group.spec.ts +47 -0
- package/src/rulebuilder/condition/Builder-condition-group.ts +91 -0
- package/src/rulebuilder/condition/Builder-condition.spec.ts +169 -0
- package/src/rulebuilder/condition/Builder-condition.ts +186 -0
- package/src/rulebuilder/condition/Builder-operator.spec.ts +9 -0
- package/src/rulebuilder/condition/Builder-operator.ts +31 -0
- package/src/rulebuilder/index.ts +22 -0
- package/src/rulebuilder/jump-to-action-manager.ts +33 -0
- package/src/rulebuilder/multi-select-item.ts +70 -0
- package/src/rulebuilder/page-action-manager.ts +20 -0
- package/src/rulebuilder/tag-action-manager.spec.ts +44 -0
- package/src/rulebuilder/tag-action-manager.ts +18 -0
- package/src/theme/AbstractThemeCompiler.ts +7 -0
- package/src/theme/IDefaultTheme.ts +178 -0
- package/src/theme/css-theme.ts +7 -0
- package/src/theme/default-theme-compiler.ts +395 -0
- package/src/theme/icon-urls.ts +29 -0
- package/src/theme/standard-props.ts +113 -0
- package/src/theme/theme-utils.ts +110 -0
- package/src/theme/theme1.spec.ts +52 -0
- package/tsconfig.json +0 -2
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import type { BuilderPageDto, BuilderPageType } from "./Builder-page";
|
|
2
|
+
import { BuilderPage } from "./Builder-page";
|
|
3
|
+
import { RuleInput } from "./rulebuilder/RuleInput";
|
|
4
|
+
import type { QuestionVariable } from "./rulebuilder/RuleVariable";
|
|
5
|
+
import type { CustomVariable } from "./rulebuilder";
|
|
6
|
+
import type { ExcludeByPageAction, ExcludeByTagAction, JumpToPageAction } from "./rulebuilder";
|
|
7
|
+
import type { BuilderTagDto } from "./BuilderTag";
|
|
8
|
+
import { BuilderTag, TagCollection } from "./BuilderTag";
|
|
9
|
+
import type { BuilderRuleDto } from "./rulebuilder";
|
|
10
|
+
import { BuilderRule } from "./rulebuilder";
|
|
11
|
+
import { DefaultThemeCompiler } from "./theme/default-theme-compiler";
|
|
12
|
+
import { ImageFile } from "./media-files";
|
|
13
|
+
import { SchemaDto, DUtil } from "@media-quest/engine";
|
|
14
|
+
const U = DUtil;
|
|
15
|
+
// type SchemaHash = string & { __MD5__HASH: true };
|
|
16
|
+
export interface BuilderSchemaDto {
|
|
17
|
+
readonly id: string;
|
|
18
|
+
readonly prefix: string;
|
|
19
|
+
readonly mainImage: ImageFile | false;
|
|
20
|
+
readonly backgroundColor: string;
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly pages: BuilderPageDto[];
|
|
23
|
+
readonly baseHeight: number;
|
|
24
|
+
readonly baseWidth: number;
|
|
25
|
+
readonly rules: ReadonlyArray<BuilderRuleDto>;
|
|
26
|
+
readonly tags: ReadonlyArray<BuilderTagDto>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface SchemaBuildOutput {
|
|
30
|
+
schema: SchemaDto;
|
|
31
|
+
codebook: Record<string, string>;
|
|
32
|
+
schemaConfig: Record<string, string>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class BuilderSchema {
|
|
36
|
+
baseHeight = 1300;
|
|
37
|
+
baseWidth = 1024;
|
|
38
|
+
backgroundColor = "#000000";
|
|
39
|
+
pages: BuilderPage[] = [];
|
|
40
|
+
mainImage: ImageFile | false = false;
|
|
41
|
+
private _rules: BuilderRule[] = [];
|
|
42
|
+
get rules(): ReadonlyArray<BuilderRule> {
|
|
43
|
+
return [...this._rules];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private readonly _tagCollection: TagCollection = TagCollection.create();
|
|
47
|
+
get tags(): ReadonlyArray<BuilderTag> {
|
|
48
|
+
return [...this._tagCollection];
|
|
49
|
+
}
|
|
50
|
+
public static create(id: string, name: string, prefix: string) {
|
|
51
|
+
return new BuilderSchema(id, name, prefix);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public static fromJson(dto: BuilderSchemaDto): BuilderSchema {
|
|
55
|
+
const schema = new BuilderSchema(dto.id, dto.name, dto.prefix);
|
|
56
|
+
const pages = dto.pages.map(BuilderPage.fromJson);
|
|
57
|
+
schema._tagCollection.init(dto.tags);
|
|
58
|
+
schema.backgroundColor = dto.backgroundColor;
|
|
59
|
+
schema.baseHeight = dto.baseHeight;
|
|
60
|
+
schema.baseWidth = dto.baseWidth;
|
|
61
|
+
schema.pages = pages;
|
|
62
|
+
schema.backgroundColor = dto.backgroundColor;
|
|
63
|
+
schema.mainImage = dto.mainImage ?? false;
|
|
64
|
+
const rulesDto = dto.rules ?? [];
|
|
65
|
+
const ruleInput = schema.getRuleInput();
|
|
66
|
+
schema._rules = rulesDto.map((r) => BuilderRule.fromDto(r, ruleInput));
|
|
67
|
+
return schema;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
toJson(): BuilderSchemaDto {
|
|
71
|
+
const pages = this.pages.map((p) => p.toJson());
|
|
72
|
+
const tags = this._tagCollection.toJson();
|
|
73
|
+
const rules = this._rules.map((rule) => rule.toJson());
|
|
74
|
+
|
|
75
|
+
const dto: BuilderSchemaDto = {
|
|
76
|
+
backgroundColor: this.backgroundColor,
|
|
77
|
+
baseHeight: this.baseHeight,
|
|
78
|
+
baseWidth: this.baseWidth,
|
|
79
|
+
id: this.id,
|
|
80
|
+
name: this.name,
|
|
81
|
+
pages,
|
|
82
|
+
rules,
|
|
83
|
+
tags,
|
|
84
|
+
mainImage: this.mainImage,
|
|
85
|
+
prefix: this.prefix,
|
|
86
|
+
};
|
|
87
|
+
return dto;
|
|
88
|
+
}
|
|
89
|
+
private constructor(
|
|
90
|
+
public readonly id: string,
|
|
91
|
+
public name: string,
|
|
92
|
+
public prefix: string,
|
|
93
|
+
) {}
|
|
94
|
+
|
|
95
|
+
addPage(type: BuilderPageType, atIndex = -1): BuilderPage {
|
|
96
|
+
const newPage = BuilderPage.create(type, "");
|
|
97
|
+
if (atIndex >= 0 && atIndex < this.pages.length) {
|
|
98
|
+
this.pages.splice(atIndex, 0, newPage);
|
|
99
|
+
} else {
|
|
100
|
+
this.pages.push(newPage);
|
|
101
|
+
}
|
|
102
|
+
return newPage;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
insertPage(page: BuilderPage, atIndex: number): boolean {
|
|
106
|
+
return this.insertPageAtIndex(page, atIndex);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private insertPageAtIndex(page: BuilderPage, atIndex: number) {
|
|
110
|
+
const isValidIndex = U.isInRange(0, this.pages.length - 1);
|
|
111
|
+
if (!isValidIndex(atIndex)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
const exists = !!this.pages.find((p) => p.id === page.id);
|
|
115
|
+
if (exists) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
this.pages.splice(atIndex, 0, page);
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
addRule() {
|
|
123
|
+
const input = this.getRuleInput();
|
|
124
|
+
const count = this._rules.length + 1;
|
|
125
|
+
const name = "Rule-number: " + count;
|
|
126
|
+
const rule = BuilderRule.fromDto(
|
|
127
|
+
{
|
|
128
|
+
conditions: [],
|
|
129
|
+
type: "all",
|
|
130
|
+
name,
|
|
131
|
+
excludeTags: [],
|
|
132
|
+
jumpToPage: false,
|
|
133
|
+
excludePages: [],
|
|
134
|
+
},
|
|
135
|
+
input,
|
|
136
|
+
);
|
|
137
|
+
this._rules.push(rule);
|
|
138
|
+
}
|
|
139
|
+
deleteRule(rule: BuilderRule) {
|
|
140
|
+
this._rules = this._rules.filter((r) => r !== rule);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
movePage(page: BuilderPage, toIndex: number): boolean {
|
|
144
|
+
const index = this.pages.indexOf(page);
|
|
145
|
+
if (index < 0) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
const isValidIndex = U.isInRange(0, this.pages.length - 1);
|
|
149
|
+
if (!isValidIndex(toIndex)) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
// console.log('Moving from :' + index + ' to: ' + toIndex);
|
|
153
|
+
this.pages.splice(index, 1);
|
|
154
|
+
this.pages.splice(toIndex, 0, page);
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
deletePage(page: BuilderPage): boolean {
|
|
159
|
+
const filtered = this.pages.filter((p) => p !== page);
|
|
160
|
+
const didDelete = filtered.length === this.pages.length - 1;
|
|
161
|
+
this.pages = filtered;
|
|
162
|
+
return didDelete;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
reevaluateRules() {
|
|
166
|
+
console.log("Reevaluationg rulesInput");
|
|
167
|
+
const input = this.getRuleInput();
|
|
168
|
+
const rulesDto = this._rules.map((r) => r.toJson());
|
|
169
|
+
this._rules = rulesDto.map((dto) => BuilderRule.fromDto(dto, input));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
getRuleInput(): RuleInput {
|
|
173
|
+
const qVars: QuestionVariable[] = [];
|
|
174
|
+
const cVars: CustomVariable[] = [];
|
|
175
|
+
const pageIdActions: ExcludeByPageAction[] = [];
|
|
176
|
+
const tagActions: ExcludeByTagAction[] = this.tags.map((t) => {
|
|
177
|
+
const tag = t.tagText;
|
|
178
|
+
const pageCount = this.pages.reduce((count, curr) => {
|
|
179
|
+
return curr.tags.includes(tag) ? count + 1 : count;
|
|
180
|
+
}, 0);
|
|
181
|
+
const excludeByTagDto: ExcludeByTagAction = {
|
|
182
|
+
kind: "exclude-by-tag",
|
|
183
|
+
pageCount,
|
|
184
|
+
tag,
|
|
185
|
+
description: t.tagDescription,
|
|
186
|
+
};
|
|
187
|
+
return excludeByTagDto;
|
|
188
|
+
});
|
|
189
|
+
const jumpActions: JumpToPageAction[] = [];
|
|
190
|
+
const prefix = "";
|
|
191
|
+
this.pages.forEach((page, index) => {
|
|
192
|
+
const pageVariables = page.getQuestionVariables(prefix, index);
|
|
193
|
+
qVars.push(...pageVariables);
|
|
194
|
+
const pageId = page.prefix;
|
|
195
|
+
const mainText = page.mainText.text;
|
|
196
|
+
const jumpAction: JumpToPageAction = {
|
|
197
|
+
kind: "jump-to-page",
|
|
198
|
+
pageId: pageId,
|
|
199
|
+
pageNumber: index,
|
|
200
|
+
mainText: page.mainText.text,
|
|
201
|
+
};
|
|
202
|
+
const excludePageAction: ExcludeByPageAction = {
|
|
203
|
+
kind: "exclude-by-pageId",
|
|
204
|
+
pageId,
|
|
205
|
+
pageNumber: index,
|
|
206
|
+
mainText,
|
|
207
|
+
};
|
|
208
|
+
jumpActions.push(jumpAction);
|
|
209
|
+
pageIdActions.push(excludePageAction);
|
|
210
|
+
});
|
|
211
|
+
const ruleInput = new RuleInput(qVars, cVars, pageIdActions, tagActions, jumpActions);
|
|
212
|
+
|
|
213
|
+
return ruleInput;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
deleteTags(tags: ReadonlyArray<BuilderTag>) {
|
|
217
|
+
this._tagCollection.deleteAll(tags);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
addTag(builderTag: BuilderTag) {
|
|
221
|
+
this._tagCollection.add(builderTag);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// getHash(): SchemaHash {
|
|
225
|
+
// const md5 = MD5(this.toJson());
|
|
226
|
+
// return
|
|
227
|
+
// }
|
|
228
|
+
|
|
229
|
+
// hasChanged(hash: SchemaHash): boolean {
|
|
230
|
+
// return hash !== this.getHash();
|
|
231
|
+
// }
|
|
232
|
+
|
|
233
|
+
private getQuestionVariables(withModulePrefix = false): ReadonlyArray<QuestionVariable> {
|
|
234
|
+
const prefix = withModulePrefix ? this.prefix : "";
|
|
235
|
+
const all = this.pages
|
|
236
|
+
.map((page, index) => {
|
|
237
|
+
return page.getQuestionVariables(prefix, index);
|
|
238
|
+
})
|
|
239
|
+
.flat(1);
|
|
240
|
+
return all;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
compile(): SchemaBuildOutput {
|
|
244
|
+
const moduleDto = this.toJson();
|
|
245
|
+
const imp = new DefaultThemeCompiler();
|
|
246
|
+
const schema = imp.compile(moduleDto);
|
|
247
|
+
|
|
248
|
+
return { codebook: {}, schema, schemaConfig: {} };
|
|
249
|
+
}
|
|
250
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { BuilderTextDto } from "./Builder-text";
|
|
2
|
+
import { BuilderText } from "./Builder-text";
|
|
3
|
+
import type { BuilderObjectId } from "./BuilderObject";
|
|
4
|
+
|
|
5
|
+
const textDto: BuilderTextDto = {
|
|
6
|
+
id: "dto1" as BuilderObjectId.TextID,
|
|
7
|
+
name: "dto1-name",
|
|
8
|
+
text: "text one",
|
|
9
|
+
translationRequired: true,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
let text1 = BuilderText.create("text one created");
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
text1 = BuilderText.create("text one created");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("Builder Text", () => {
|
|
19
|
+
test("Can serialize", () => {
|
|
20
|
+
const instance1 = BuilderText.fromJson(textDto);
|
|
21
|
+
const json = instance1.toJson();
|
|
22
|
+
expect(textDto).toStrictEqual(json);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { BuilderObjectId, BuilderObject } from './BuilderObject';
|
|
2
|
+
|
|
3
|
+
export interface BuilderTextDto {
|
|
4
|
+
readonly id: BuilderObjectId.TextID;
|
|
5
|
+
text: string;
|
|
6
|
+
name: string;
|
|
7
|
+
translationRequired: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class BuilderText extends BuilderObject<'builder-text', BuilderTextDto> {
|
|
11
|
+
readonly objectType = 'builder-text';
|
|
12
|
+
id: BuilderObjectId.TextID;
|
|
13
|
+
text = '';
|
|
14
|
+
name = '';
|
|
15
|
+
translateRequired = false;
|
|
16
|
+
// audio: {id: B}
|
|
17
|
+
private constructor(dto: BuilderTextDto) {
|
|
18
|
+
super(dto);
|
|
19
|
+
this.id = dto.id;
|
|
20
|
+
this.translateRequired = dto.translationRequired;
|
|
21
|
+
this.name = dto.name;
|
|
22
|
+
this.text = dto.text;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public static create(name: string) {
|
|
26
|
+
const id = BuilderObjectId.textId();
|
|
27
|
+
const dto: BuilderTextDto = {
|
|
28
|
+
id,
|
|
29
|
+
name,
|
|
30
|
+
text: '',
|
|
31
|
+
translationRequired: false
|
|
32
|
+
};
|
|
33
|
+
const instance = new BuilderText(dto);
|
|
34
|
+
return instance;
|
|
35
|
+
}
|
|
36
|
+
public static fromJson(dto: BuilderTextDto) {
|
|
37
|
+
const instance = new BuilderText(dto);
|
|
38
|
+
return instance;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
clone(): BuilderTextDto {
|
|
42
|
+
const newId = BuilderObjectId.textId();
|
|
43
|
+
const dto = this.toJson();
|
|
44
|
+
const withNewId: BuilderTextDto = { ...dto, id: newId };
|
|
45
|
+
return withNewId;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
toJson(): BuilderTextDto {
|
|
49
|
+
const dto: BuilderTextDto = {
|
|
50
|
+
id: this.id,
|
|
51
|
+
name: this.name,
|
|
52
|
+
text: this.text,
|
|
53
|
+
translationRequired: this.translateRequired
|
|
54
|
+
};
|
|
55
|
+
return dto;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { BuilderObject } from "./BuilderObject";
|
|
2
|
+
import { AudioFile } from "./media-files";
|
|
3
|
+
|
|
4
|
+
export interface BuilderMainTextDto {
|
|
5
|
+
text: string;
|
|
6
|
+
audioFile: AudioFile | false;
|
|
7
|
+
autoplay: boolean;
|
|
8
|
+
autoplayDelay: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class BuilderMainText extends BuilderObject<"builder-main-text", BuilderMainTextDto> {
|
|
12
|
+
readonly objectType: "builder-main-text" = "builder-main-text";
|
|
13
|
+
autoplay = false;
|
|
14
|
+
private _audioFile: AudioFile | false = false;
|
|
15
|
+
autoplayDelay = 0;
|
|
16
|
+
|
|
17
|
+
text = "";
|
|
18
|
+
|
|
19
|
+
private constructor(dto: BuilderMainTextDto) {
|
|
20
|
+
super(dto);
|
|
21
|
+
this._audioFile = dto.audioFile ?? false;
|
|
22
|
+
this.autoplay = dto.autoplay ?? false;
|
|
23
|
+
this.autoplayDelay = dto.autoplayDelay ?? 0;
|
|
24
|
+
this.text = dto.text ?? "";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get autoplayDelayInSeconds() {
|
|
28
|
+
const delay = this.autoplayDelay;
|
|
29
|
+
const s = delay / 1000;
|
|
30
|
+
const formatted = s.toFixed(1);
|
|
31
|
+
return formatted;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get durationTag() {
|
|
35
|
+
if (!this.audioFile) return "";
|
|
36
|
+
// console.log(this.audioFile.duration);
|
|
37
|
+
const dur = this.audioFile.duration.toFixed(1);
|
|
38
|
+
return "dur " + dur + " s";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static fromJson(dto: BuilderMainTextDto): BuilderMainText {
|
|
42
|
+
const mainText = new BuilderMainText(dto);
|
|
43
|
+
return mainText;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static create = () => {
|
|
47
|
+
const dto: BuilderMainTextDto = {
|
|
48
|
+
autoplay: false,
|
|
49
|
+
autoplayDelay: 0,
|
|
50
|
+
audioFile: false,
|
|
51
|
+
text: "",
|
|
52
|
+
};
|
|
53
|
+
return new BuilderMainText(dto);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
clone(): BuilderMainTextDto {
|
|
57
|
+
const dto = this.toJson();
|
|
58
|
+
const clone = JSON.parse(JSON.stringify(dto));
|
|
59
|
+
return clone;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
toJson(): BuilderMainTextDto {
|
|
63
|
+
const dto: BuilderMainTextDto = {
|
|
64
|
+
text: this.text,
|
|
65
|
+
audioFile: this.audioFile,
|
|
66
|
+
autoplay: this.autoplay,
|
|
67
|
+
autoplayDelay: this.autoplayDelay,
|
|
68
|
+
};
|
|
69
|
+
return dto;
|
|
70
|
+
}
|
|
71
|
+
get audioFile(): AudioFile | false {
|
|
72
|
+
return this._audioFile;
|
|
73
|
+
}
|
|
74
|
+
set audioFile(audioFile: AudioFile | false) {
|
|
75
|
+
if (audioFile === false) {
|
|
76
|
+
this.autoplayDelay = 0;
|
|
77
|
+
this.autoplay = false;
|
|
78
|
+
}
|
|
79
|
+
this._audioFile = audioFile;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { DUtil } from "@media-quest/engine";
|
|
2
|
+
|
|
3
|
+
const U = DUtil;
|
|
4
|
+
/**
|
|
5
|
+
* Builder objects are complex objects that are embedded inside
|
|
6
|
+
* a Builder-schema, and needs to be serialized to json. Often these objects
|
|
7
|
+
* are used in collections, and that is why most of them need an id.
|
|
8
|
+
*/
|
|
9
|
+
type BuilderObjectType =
|
|
10
|
+
| "builder-page"
|
|
11
|
+
| "builder-question-option"
|
|
12
|
+
| "builder-question"
|
|
13
|
+
| "builder-main-text"
|
|
14
|
+
| "builder-text"
|
|
15
|
+
| "builder-rule"
|
|
16
|
+
| "builder-tag"
|
|
17
|
+
| "builder-condition"
|
|
18
|
+
| "builder-variable"
|
|
19
|
+
| "builder-condition-group";
|
|
20
|
+
|
|
21
|
+
export namespace BuilderObjectId {
|
|
22
|
+
export type QuestionOptionID = string & { __OPTION__ID__: true };
|
|
23
|
+
export type QuestionID = string & { __QUESTION__ID__: true };
|
|
24
|
+
export type VideoFileID = string & { __VIDEO__ID__: true };
|
|
25
|
+
export type AudioFileID = string & { __AUDIO__ID__: true };
|
|
26
|
+
export type ImageID = string & { __IMAGE__ID__: true };
|
|
27
|
+
export type TextID = string & { __TEXT__ID__: true };
|
|
28
|
+
export type MainTextID = string & { __MAIN__TEXT__ID__: true };
|
|
29
|
+
export type PageID = string & { __PAGE__ID__: true };
|
|
30
|
+
export type TagId = string & { __TAG__ID__: true };
|
|
31
|
+
|
|
32
|
+
export const createTagId = (): TagId => {
|
|
33
|
+
return createId("builder-tag") as TagId;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const mainTextId = (): MainTextID => {
|
|
37
|
+
return createId("builder-main-text") as MainTextID;
|
|
38
|
+
};
|
|
39
|
+
export const textId = (): TextID => {
|
|
40
|
+
return createId("builder-text") as TextID;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const questionOptionId = (): QuestionOptionID => {
|
|
44
|
+
return createId("builder-question-option") as QuestionOptionID;
|
|
45
|
+
};
|
|
46
|
+
export const questionId = (): QuestionID => {
|
|
47
|
+
return createId("builder-question") as QuestionID;
|
|
48
|
+
};
|
|
49
|
+
export const pageId = (): PageID => {
|
|
50
|
+
return createId("builder-page") as PageID;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const createId = (type: BuilderObjectType): string => {
|
|
54
|
+
const id = U.randomString(24);
|
|
55
|
+
return type + "-" + id;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export abstract class BuilderObject<T extends BuilderObjectType, Dto extends {}> {
|
|
60
|
+
// abstract readonly id: string;
|
|
61
|
+
abstract readonly objectType: T;
|
|
62
|
+
abstract toJson(): Dto;
|
|
63
|
+
abstract clone(): Dto;
|
|
64
|
+
protected readonly originalDto: Dto;
|
|
65
|
+
protected constructor(dto: Dto) {
|
|
66
|
+
this.originalDto = dto;
|
|
67
|
+
// this.objectId = dto.objectId;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { BuilderObjectId, BuilderObject } from './BuilderObject';
|
|
2
|
+
|
|
3
|
+
export interface BuilderTagDto {
|
|
4
|
+
readonly id: BuilderObjectId.TagId;
|
|
5
|
+
readonly tag: string;
|
|
6
|
+
readonly description: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class BuilderTag extends BuilderObject<'builder-tag', BuilderTagDto> {
|
|
10
|
+
readonly objectType: 'builder-tag' = 'builder-tag';
|
|
11
|
+
readonly id: BuilderObjectId.TagId;
|
|
12
|
+
tagText = '';
|
|
13
|
+
tagDescription = '';
|
|
14
|
+
public static readonly MAX_LENGTH = 20;
|
|
15
|
+
public static readonly MIN_LENGTH = 1;
|
|
16
|
+
|
|
17
|
+
public static readonly create = (tag: string, description: string = '') => {
|
|
18
|
+
const id = BuilderObjectId.createTagId();
|
|
19
|
+
const dto: BuilderTagDto = {
|
|
20
|
+
id,
|
|
21
|
+
tag,
|
|
22
|
+
description
|
|
23
|
+
};
|
|
24
|
+
return new BuilderTag(dto);
|
|
25
|
+
};
|
|
26
|
+
public static readonly fromDto = (dto: BuilderTagDto) => {
|
|
27
|
+
return new BuilderTag(dto);
|
|
28
|
+
};
|
|
29
|
+
protected constructor(dto: BuilderTagDto) {
|
|
30
|
+
const id = dto.id ?? BuilderObjectId.createTagId();
|
|
31
|
+
const withId = { ...dto, id };
|
|
32
|
+
super(withId);
|
|
33
|
+
this.id = id;
|
|
34
|
+
this.tagText = dto.tag ?? '';
|
|
35
|
+
this.tagDescription = dto.description ?? '';
|
|
36
|
+
}
|
|
37
|
+
clone(): BuilderTagDto {
|
|
38
|
+
return this.toJson();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
toJson(): BuilderTagDto {
|
|
42
|
+
return { tag: this.tagText, description: this.tagDescription, id: this.id };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class TagCollection implements Iterable<BuilderTag> {
|
|
47
|
+
private readonly _tags = new Set<BuilderTag>();
|
|
48
|
+
public static readonly create = () => {
|
|
49
|
+
return new TagCollection([]);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
[Symbol.iterator]() {
|
|
53
|
+
const list = [...this._tags];
|
|
54
|
+
return list[Symbol.iterator]();
|
|
55
|
+
}
|
|
56
|
+
private constructor(initialTags: ReadonlyArray<BuilderTag>) {
|
|
57
|
+
initialTags.forEach(tag => {
|
|
58
|
+
this._tags.add(tag);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
init(tags: ReadonlyArray<BuilderTagDto>) {
|
|
63
|
+
const dtoList: ReadonlyArray<BuilderTagDto> = Array.isArray(tags)
|
|
64
|
+
? tags
|
|
65
|
+
: [];
|
|
66
|
+
const all = dtoList.map(BuilderTag.fromDto);
|
|
67
|
+
all.forEach(tag => {
|
|
68
|
+
this._tags.add(tag);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
add(tag: BuilderTag) {
|
|
73
|
+
this._tags.add(tag);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Delete this tag from collection;
|
|
78
|
+
* @param tag
|
|
79
|
+
*/
|
|
80
|
+
delete(tag: BuilderTag) {
|
|
81
|
+
this._tags.delete(tag);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
toJson(): ReadonlyArray<BuilderTagDto> {
|
|
85
|
+
const list = [...this._tags];
|
|
86
|
+
const dtoList = list.map(t => t.toJson());
|
|
87
|
+
return dtoList;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
deleteAll(tags: Iterable<BuilderTag>) {
|
|
91
|
+
const l = tags[Symbol.iterator]();
|
|
92
|
+
const asList = [...tags];
|
|
93
|
+
asList.forEach(t => {
|
|
94
|
+
this.delete(t);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface AudioFile {
|
|
2
|
+
readonly kind: "audio-file";
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly downloadUrl: string;
|
|
5
|
+
readonly duration: number;
|
|
6
|
+
readonly originalFileName: string;
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly size: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface VideoFile {
|
|
12
|
+
readonly kind: "video-file";
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly downloadUrl: string;
|
|
15
|
+
readonly duration: number;
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly size: number;
|
|
18
|
+
readonly type: string;
|
|
19
|
+
readonly originalFileName: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ImageFile {
|
|
22
|
+
readonly kind: "image-file";
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly downloadUrl: string;
|
|
25
|
+
readonly name: string;
|
|
26
|
+
readonly size: number;
|
|
27
|
+
readonly type: string;
|
|
28
|
+
}
|
package/src/public-api.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
1
|
+
export { type BuilderOptionDto, BuilderOption } from "./Builder-option";
|
|
2
|
+
export { type BuilderPageDto, type BuilderPageType, BuilderPage } from "./Builder-page";
|
|
3
|
+
export { type BuilderQuestionDto, BuilderQuestion, type BuilderQuestionType } from "./Builder-question";
|
|
4
|
+
export { BuilderSchema, type BuilderSchemaDto } from "./Builder-schema";
|
|
5
|
+
export { BuilderText, type BuilderTextDto } from "./Builder-text";
|
|
6
|
+
export { type BuilderMainImageDto } from "./BuilderMainImageDto";
|
|
7
|
+
export { BuilderMainText, type BuilderMainTextDto } from "./BuilderMainText";
|
|
8
|
+
export { type BuilderMainVideoDto } from "./BuilderMainVideoDto";
|
|
9
|
+
export { type BuilderTagDto, BuilderTag, TagCollection } from "./BuilderTag";
|
|
10
|
+
export { type AudioFile, type ImageFile, type VideoFile } from "./media-files";
|
|
11
|
+
|
|
12
|
+
// Public Api of rule-builder
|
|
13
|
+
export * from "./rulebuilder";
|