@media-quest/builder 0.0.39 → 0.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/public-api.d.ts +82 -99
  2. package/dist/public-api.js +36 -101
  3. package/dist/public-api.js.map +1 -1
  4. package/package.json +29 -29
  5. package/src/{theme → ARKIV}/button-bar/button-text-utils.ts +233 -233
  6. package/src/{theme → ARKIV}/button-bar/text-utils.spec.ts +105 -105
  7. package/src/Builder-option.ts +78 -62
  8. package/src/Builder-question.ts +98 -98
  9. package/src/Builder-schema.spec.ts +348 -348
  10. package/src/Builder-schema.ts +308 -306
  11. package/src/builder-compiler.ts +14 -20
  12. package/src/code-book/codebook-variable.ts +27 -27
  13. package/src/code-book/codebook.ts +89 -89
  14. package/src/media-files.ts +28 -32
  15. package/src/page/Builder-page-collection.spec.ts +219 -219
  16. package/src/page/Builder-page-collection.ts +129 -129
  17. package/src/page/Builder-page.spec.ts +177 -177
  18. package/src/page/Builder-page.ts +250 -250
  19. package/src/primitives/ID.ts +135 -135
  20. package/src/public-api.ts +29 -30
  21. package/src/rulebuilder/RuleAction.ts +105 -105
  22. package/src/schema-config.ts +25 -26
  23. package/src/sum-score/sum-score-variable-collection.spec.ts +68 -68
  24. package/src/sum-score/sum-score-variable-collection.ts +101 -101
  25. package/src/sum-score/sum-score-variable.ts +0 -1
  26. package/src/sum-score/sum-score.ts +166 -167
  27. package/src/tag/BuilderTag.ts +45 -45
  28. package/src/tag/Tag-Collection.ts +53 -53
  29. package/src/theme/Default-theme.ts +173 -188
  30. package/src/theme/IDefault-theme.ts +125 -125
  31. package/src/theme/ThemeCompiler.ts +10 -11
  32. package/src/theme/default-theme-compiler.spec.ts +31 -31
  33. package/src/theme/default-theme-compiler.ts +655 -652
  34. package/src/theme/icon-urls.ts +29 -29
  35. package/src/theme/icons.ts +117 -117
  36. package/src/theme/theme-utils.spec.ts +52 -52
  37. package/src/theme/theme-utils.ts +56 -56
  38. package/src/theme/theme2.ts +388 -386
  39. package/tsconfig.json +19 -19
  40. package/src/Builder-schema-dto.spec.ts +0 -155
  41. package/src/Builder-schema-dto.ts +0 -86
@@ -1,652 +1,655 @@
1
- import { ThemeCompiler } from "./ThemeCompiler";
2
- import { BuilderSchema } from "../Builder-schema";
3
- import type { BuilderPageDto } from "../page/Builder-page";
4
- import { DefaultTheme } from "./Default-theme";
5
- import type { BuilderMainImageDto } from "../BuilderMainImageDto";
6
- import type { BuilderMainVideoDto } from "../BuilderMainVideoDto";
7
- import {
8
- ButtonClickAction,
9
- DButtonDto,
10
- DDivDto,
11
- DelayTask,
12
- DElementDto,
13
- DImgDto,
14
- DTextDto,
15
- PageDto,
16
- PlayAudioTask,
17
- PlayVideoTask,
18
- PStyle,
19
- Rule,
20
- RuleActionPageQue,
21
- SchemaDto,
22
- } from "@media-quest/engine";
23
-
24
- import { AudioFile } from "../media-files";
25
- import { BuilderRule } from "../rulebuilder";
26
- import { IDefaultTheme } from "./IDefault-theme";
27
- import { Theme2 } from "./theme2";
28
- import { BuilderSchemaDto } from "../Builder-schema-dto";
29
-
30
- export class DefaultThemeCompiler implements ThemeCompiler<IDefaultTheme> {
31
- readonly name = "Ispe default theme.";
32
- readonly defaultTheme = DefaultTheme;
33
- readonly theme2 = Theme2;
34
- currentTheme = DefaultTheme;
35
- allThemes = [DefaultTheme, Theme2];
36
- private readonly TAG = "[ DEFAULT_THEME_COMPILER ]: ";
37
-
38
- setTheme(theme: IDefaultTheme) {
39
- this.currentTheme = theme;
40
- }
41
-
42
- constructor() {}
43
-
44
- private compileRules(source: BuilderSchemaDto): Rule<RuleActionPageQue, never>[] {
45
- const builderSchema = BuilderSchema.fromJson(source);
46
- const ruleInput = builderSchema.getRuleInput();
47
- const pageQueRules: Rule<RuleActionPageQue, never>[] = [];
48
- source.rules.forEach((rule) => {
49
- const engineRule = BuilderRule.fromDto(rule, ruleInput).toEngineRule();
50
- if (!Rule.isEmpty(engineRule)) {
51
- pageQueRules.push(engineRule);
52
- } else {
53
- console.log(this.TAG, "Throws away empty rule. " + rule.type + " " + rule.name);
54
- }
55
- });
56
- return pageQueRules;
57
- }
58
-
59
- compile(source: BuilderSchemaDto): SchemaDto {
60
- const t = this.currentTheme;
61
- const themeName = t.name;
62
- const schema = source.name;
63
- const tag = schema + "-" + themeName + " compile";
64
- const TAG = tag.toUpperCase();
65
- // console.group(TAG);
66
- const numberOfPages = source.pages.length;
67
- const pages = source.pages.map((p, index) => {
68
- return this.compilePage(p, index, numberOfPages, source.prefix);
69
- });
70
-
71
- let baseHeight = source.baseHeight;
72
- let baseWidth = source.baseWidth;
73
- let backgroundColor = source.backgroundColor;
74
- if (t.dimensions.baseHeight) {
75
- baseHeight = t.dimensions.baseHeight;
76
- }
77
- if (t.dimensions.baseWidth) {
78
- baseWidth = t.dimensions.baseWidth;
79
- }
80
- if (t.dimensions.baseWidth) {
81
- baseWidth = t.dimensions.baseWidth;
82
- }
83
- if (t.schemaBackgroundColor) {
84
- backgroundColor = t.schemaBackgroundColor;
85
- }
86
-
87
- const rules = this.compileRules(source);
88
-
89
- const dto: SchemaDto = {
90
- id: source.id,
91
- backgroundColor,
92
- baseHeight,
93
- baseWidth,
94
- pageSequences: [],
95
- pages,
96
- predefinedFacts: [],
97
- rules,
98
- };
99
- // console.groupEnd();
100
- return dto;
101
- }
102
-
103
- private compilePage(
104
- page: BuilderPageDto,
105
- pageIndex: number,
106
- totalNumberOfPages: number,
107
- modulePrefix: string,
108
- ): PageDto {
109
- const pageNumber = pageIndex + 1;
110
- const tags = page.tags ?? [];
111
- const { nextButton, mainText, id, mainMedia, _type, prefix } = page;
112
- const t = this.currentTheme;
113
- const hasMainMedia = !!mainMedia;
114
- const hasMainTextAudio = !!mainText.audioFile;
115
-
116
- const elements: DElementDto[] = [];
117
- let initialAudioTasks: Array<PlayAudioTask | DelayTask> = [];
118
- let initialVideoTaskList: Array<PlayVideoTask | DelayTask> = [];
119
- const newPage: PageDto = {
120
- background: "white",
121
- pageNumber,
122
- elements,
123
- id,
124
- prefix,
125
- initialTasks: [],
126
- tags: [...tags],
127
- };
128
- const bg = t.pageBackGround;
129
- if (bg) {
130
- const pageBackGround: DDivDto = {
131
- style: bg.style,
132
- _tag: "div",
133
- children: [],
134
- };
135
- elements.push(pageBackGround);
136
- }
137
-
138
- const bgArea1 = t.backGroundArea1;
139
-
140
- if (bgArea1) {
141
- const backgroundArea1: DDivDto = {
142
- style: bgArea1.style,
143
- _tag: "div",
144
- children: [],
145
- };
146
- elements.push(backgroundArea1);
147
- }
148
-
149
- if (t.progressBar) {
150
- // console.log("ADDED PROGRESS.");
151
- const progressInPercent = pageNumber / totalNumberOfPages;
152
- // const a =
153
- const baseStyles: PStyle = {
154
- bottom: t.progressBar.bottom,
155
- left: t.progressBar.left,
156
- height: t.progressBar.height,
157
- width: t.progressBar.width,
158
- };
159
- const progressBackGround: DDivDto = {
160
- style: {
161
- ...baseStyles,
162
- ...t.progressBar.backgroundStyles,
163
- },
164
- _tag: "div",
165
- children: [],
166
- };
167
-
168
- const currentProgress = t.progressBar.width * progressInPercent;
169
- const progressIndicator: DDivDto = {
170
- style: { ...baseStyles, ...t.progressBar.progressStyles, w: currentProgress },
171
- _tag: "div",
172
- children: [],
173
- };
174
- const pText = t.progressBar.text;
175
-
176
- elements.push(progressBackGround);
177
- elements.push(progressIndicator);
178
- if (pText) {
179
- const progressText: DTextDto = {
180
- _tag: "p",
181
- innerText: "side " + pageNumber + " av " + totalNumberOfPages,
182
- style: pText.style,
183
- };
184
- elements.push(progressText);
185
- }
186
- }
187
-
188
- if (page.mainText.audioFile) {
189
- const autoPlay = page.mainText.autoplay;
190
- const autoPlayDelay = page.mainText.autoplayDelay;
191
- const res = this.compileMainTextAudio(
192
- page.mainText.audioFile,
193
- autoPlay,
194
- autoPlayDelay,
195
- hasMainMedia,
196
- );
197
- // console.log(page.mainText.text);
198
- initialAudioTasks = [...res.initialTasks];
199
- newPage.elements.push(...res.components);
200
- }
201
-
202
- if (_type === "question") {
203
- const variableId = modulePrefix + "_" + page.prefix;
204
- const qRes = this.compileQuestion(id, page, variableId, hasMainMedia);
205
- newPage.elements.push(qRes.buttonBar, qRes.question);
206
-
207
- // newPage.elements.push(question);
208
- // console.log(question);
209
- // elements.push(...buttons, question);
210
- }
211
-
212
- if (_type === "info-page") {
213
- const infoText = mainText.text;
214
- const nextButtonBar = this.compileButtonBar([
215
- this.compileButton(nextButton, { kind: "next-button" }),
216
- ]);
217
- const infoTextElement = this.compileMainText(infoText, hasMainTextAudio, hasMainMedia);
218
-
219
- // const textBase =
220
- newPage.elements.push(infoTextElement, nextButtonBar);
221
- // newPage.components.push(nextButtonComponent);
222
- }
223
- if (mainMedia && mainMedia.kind === "main-image") {
224
- const mainImageElement = this.compileImage(mainMedia);
225
- newPage.elements.push(mainImageElement);
226
- }
227
-
228
- if (mainMedia && mainMedia.kind === "main-video") {
229
- const videoOutput = this.compileVideo(mainMedia);
230
- // newPage.videoPlayer?.playUrl
231
- newPage.videoPlayer = videoOutput.videoPlayer;
232
- newPage.elements.push(...videoOutput.components);
233
- initialVideoTaskList = [...videoOutput.autoPlayTasks];
234
- }
235
-
236
- // ADDING INITIAL TASKS IN CORRECT ORDER
237
- newPage.initialTasks.push(...initialVideoTaskList);
238
- newPage.initialTasks.push(...initialAudioTasks);
239
- const clone = JSON.parse(JSON.stringify(newPage)) as PageDto;
240
- return clone;
241
- }
242
-
243
- private compileImage(image: BuilderMainImageDto) {
244
- const img: DImgDto = {
245
- _tag: "img",
246
- style: this.currentTheme.image.style,
247
- url: image.file.downloadUrl,
248
- };
249
- return img;
250
- }
251
-
252
- private compileMainText(text: string, hasAudio: boolean, hasMainMedia: boolean): DTextDto {
253
- const t = this.currentTheme;
254
- const { base, hasMediaNotAudio, notMediaHasAudio, notMediaNotAudio, hasMediaHasAudio } =
255
- t.mainText;
256
- let style = base.text;
257
- if (hasMainMedia && hasAudio) style = { ...style, ...hasMediaHasAudio.text };
258
- if (!hasMainMedia && hasAudio) style = { ...style, ...notMediaHasAudio.text };
259
- if (hasMainMedia && !hasAudio) style = { ...style, ...hasMediaNotAudio.text };
260
- if (!hasMainMedia && !hasAudio) style = { ...style, ...notMediaNotAudio.text };
261
- // console.log(style.textColor);
262
- return {
263
- _tag: "p",
264
- innerText: text,
265
- style,
266
- };
267
- }
268
-
269
- private compileMainTextAudio(
270
- audioFile: AudioFile,
271
- autoPlay: boolean,
272
- autoPlayDelay: number,
273
- hasMainMedia: boolean,
274
- ): {
275
- components: DElementDto[];
276
- initialTasks: Array<PlayAudioTask | DelayTask>;
277
- } {
278
- const t = this.currentTheme.mainText;
279
- const audioId = audioFile.id;
280
- const iconUrl = this.currentTheme.mainText.base.audio.iconUrl;
281
- const baseIconStyles = t.base.audio;
282
- const addedStyles = hasMainMedia ? t.hasMediaHasAudio.audio : t.notMediaHasAudio.audio;
283
-
284
- const audioIconStyle = { ...baseIconStyles.css, ...addedStyles };
285
- const task: PlayAudioTask = {
286
- audioId,
287
- blockAudio: false,
288
- blockFormInput: false,
289
- blockResponseButton: false,
290
- blockVideo: false,
291
- kind: "play-audio-task",
292
- priority: "replace-all",
293
- url: audioFile.downloadUrl,
294
- };
295
-
296
- const playMainTextAudio: DImgDto = {
297
- _tag: "img",
298
- url: iconUrl,
299
- style: { ...audioIconStyle },
300
- onClick: { kind: "play-audio", task },
301
- };
302
-
303
- let initialAudioTasks: Array<PlayAudioTask | DelayTask> = [];
304
- if (autoPlay) {
305
- const playAudioTask: PlayAudioTask = { ...task, priority: "follow-queue" };
306
- initialAudioTasks = [playAudioTask];
307
- if (autoPlayDelay > 0) {
308
- const delayTask: DelayTask = {
309
- kind: "delay-task",
310
- priority: "follow-queue",
311
- duration: autoPlayDelay,
312
- blockVideo: false,
313
- blockAudio: false,
314
- blockResponseButton: false,
315
- blockFormInput: false,
316
- };
317
- initialAudioTasks = [delayTask, playAudioTask];
318
- }
319
- }
320
- // const autoplayTask =
321
-
322
- return { components: [playMainTextAudio], initialTasks: [...initialAudioTasks] };
323
- }
324
-
325
- private compileVideo(video: BuilderMainVideoDto): {
326
- videoPlayer: PageDto["videoPlayer"];
327
- components: DElementDto[];
328
- autoPlayTasks: Array<PlayVideoTask | DelayTask>;
329
- } {
330
- const t = this.currentTheme.videoPlayer;
331
- const hasReplayButton = !!t.replayButton;
332
-
333
- const mode = video.mode;
334
- // const components: DElementDto[] = [];
335
-
336
- let autoPlayTasks: Array<PlayVideoTask | DelayTask> = [];
337
-
338
- let autoplayVideoTask: PlayVideoTask | false = false;
339
- let autoplayDelayTask: DelayTask | false = false;
340
-
341
- let buttonBar: DDivDto | false = false;
342
- let playButton: DImgDto | false = false;
343
- let playButtonText: DTextDto | false = false;
344
- let replayButton: DImgDto | false = false;
345
- let replayButtonText: DTextDto | false = false;
346
- let pauseButton: DImgDto | false = false;
347
- let pauseButtonText: DTextDto | false = false;
348
- let unmuteButton: DImgDto | false = false;
349
- let unmuteButtonText: DTextDto | false = false;
350
- let muteButton: DImgDto | false = false;
351
- let muteButtonText: DTextDto | false = false;
352
-
353
- const showWhenEnded: Partial<DElementDto> = {
354
- whenVideoEnded: { visibility: "visible" },
355
- whenVideoEndedAndMuted: { visibility: "visible" },
356
- whenVideoPlaying: { visibility: "hidden" },
357
- whenVideoPlayingAndMuted: { visibility: "hidden" },
358
- whenVideoPaused: { visibility: "hidden" },
359
- whenVideoPausedAndMuted: { visibility: "hidden" },
360
- };
361
-
362
- const showWhenPlayingOrPaused: Partial<DElementDto> = {
363
- whenVideoEnded: { visibility: "visible" },
364
- whenVideoEndedAndMuted: { visibility: "visible" },
365
- whenVideoPlaying: { visibility: "visible" },
366
- whenVideoPlayingAndMuted: { visibility: "visible" },
367
- whenVideoPaused: { visibility: "hidden" },
368
- whenVideoPausedAndMuted: { visibility: "hidden" },
369
- };
370
-
371
- const showWhenPlaying: Partial<DElementDto> = {
372
- whenVideoEnded: { visibility: "hidden" },
373
- whenVideoEndedAndMuted: { visibility: "hidden" },
374
- whenVideoPlaying: { visibility: "visible" },
375
- whenVideoPlayingAndMuted: { visibility: "visible" },
376
- whenVideoPaused: { visibility: "hidden" },
377
- whenVideoPausedAndMuted: { visibility: "hidden" },
378
- };
379
-
380
- const showWhenPaused: Partial<DElementDto> = {
381
- whenVideoEnded: { visibility: "hidden" },
382
- whenVideoEndedAndMuted: { visibility: "hidden" },
383
- whenVideoPlaying: { visibility: "hidden" },
384
- whenVideoPlayingAndMuted: { visibility: "hidden" },
385
- whenVideoPaused: { visibility: "visible" },
386
- whenVideoPausedAndMuted: { visibility: "visible" },
387
- };
388
-
389
- const playButtonTask: PlayVideoTask = {
390
- kind: "play-video-task",
391
- url: video.file.downloadUrl,
392
- videoId: video.file.id,
393
- blockAudio: false,
394
- blockFormInput: false,
395
- blockResponseButton: false,
396
- loop: mode === "gif-mode",
397
- blockVideo: false,
398
- priority: "replace-all",
399
- };
400
-
401
- if (video.mode === "autoplay" || video.mode === "gif-mode") {
402
- autoplayVideoTask = { ...playButtonTask, priority: "follow-queue" };
403
- autoPlayTasks = [autoplayVideoTask];
404
- if (video.preDelay > 0) {
405
- autoplayDelayTask = {
406
- kind: "delay-task",
407
- priority: "follow-queue",
408
- duration: video.preDelay,
409
- blockVideo: false,
410
- blockAudio: false,
411
- blockResponseButton: false,
412
- blockFormInput: false,
413
- };
414
- autoPlayTasks = [autoplayDelayTask, autoplayVideoTask];
415
- }
416
- }
417
-
418
- const videoPlayer: PageDto["videoPlayer"] = {
419
- playUrl: video.file.downloadUrl,
420
- style: t.videoElement.css,
421
- // style: { h: 45, w: 100, x: 0, y: 55 },
422
- };
423
-
424
- if (t.buttonBar) {
425
- buttonBar = {
426
- _tag: "div",
427
- style: { ...t.buttonBar },
428
- children: [],
429
- };
430
- }
431
-
432
- playButton = {
433
- ...showWhenPaused,
434
- _tag: "img",
435
- url: t.playButton.iconUrl,
436
- style: { ...t.playButton.css, ...t.playButton.cssEnabled },
437
- // },
438
- onClick: { kind: "play-video", task: playButtonTask },
439
- };
440
- if (t.playButton.text) {
441
- playButtonText = {
442
- ...showWhenPaused,
443
- _tag: "p",
444
- style: t.playButton.text.css,
445
- innerText: t.playButton.text.text,
446
- };
447
- // components.push({
448
- //
449
- // });
450
- }
451
-
452
- pauseButton = {
453
- ...showWhenPlaying,
454
- _tag: "img",
455
- style: {
456
- ...t.pauseButton.css,
457
- visibility: "hidden",
458
- ...t.pauseButton.cssEnabled,
459
- },
460
- url: t.pauseButton.iconUrl,
461
- onClick: { kind: "pause-video" },
462
- };
463
-
464
- if (t.pauseButton.text) {
465
- pauseButtonText = {
466
- ...showWhenPlaying,
467
- _tag: "p",
468
- style: t.pauseButton.text.css,
469
- innerText: t.pauseButton.text.text,
470
- };
471
- }
472
- if (t.unMuteButton) {
473
- unmuteButton = {
474
- _tag: "img",
475
- style: { ...t.unMuteButton.css },
476
- url: t.unMuteButton.iconUrl,
477
- onClick: { kind: "un-mute-video" },
478
- whenVideoPausedAndMuted: { visibility: "visible" },
479
- whenVideoPaused: { visibility: "hidden" },
480
- whenVideoPlayingAndMuted: { visibility: "visible" },
481
- whenVideoPlaying: { visibility: "hidden" },
482
- whenVideoEnded: { visibility: "hidden" },
483
- whenVideoEndedAndMuted: { visibility: "hidden" },
484
- };
485
- if (t.unMuteButton.text) {
486
- unmuteButtonText = {
487
- _tag: "p",
488
- style: t.unMuteButton.text.css,
489
- innerText: t.unMuteButton.text.text,
490
- whenVideoPausedAndMuted: { visibility: "visible" },
491
- whenVideoPaused: { visibility: "hidden" },
492
- whenVideoPlayingAndMuted: { visibility: "visible" },
493
- whenVideoPlaying: { visibility: "hidden" },
494
- whenVideoEnded: { visibility: "hidden" },
495
- whenVideoEndedAndMuted: { visibility: "hidden" },
496
- };
497
- }
498
- }
499
- if (t.muteButton) {
500
- muteButton = {
501
- _tag: "img",
502
- style: { ...t.muteButton.css },
503
- url: t.muteButton.iconUrl,
504
- onClick: { kind: "mute-video" },
505
- whenVideoPausedAndMuted: { visibility: "hidden" },
506
- whenVideoPaused: { visibility: "visible" },
507
- whenVideoPlayingAndMuted: { visibility: "hidden" },
508
- whenVideoPlaying: { visibility: "visible" },
509
- whenVideoEnded: { visibility: "hidden" },
510
- whenVideoEndedAndMuted: { visibility: "hidden" },
511
- };
512
-
513
- if (t.muteButton.text) {
514
- muteButtonText = {
515
- _tag: "p",
516
- style: t.muteButton.text.css,
517
- innerText: t.muteButton.text.text,
518
- whenVideoPausedAndMuted: { visibility: "hidden" },
519
- whenVideoPaused: { visibility: "visible" },
520
- whenVideoPlayingAndMuted: { visibility: "hidden" },
521
- whenVideoPlaying: { visibility: "visible" },
522
- whenVideoEnded: { visibility: "hidden" },
523
- whenVideoEndedAndMuted: { visibility: "hidden" },
524
- };
525
- }
526
- }
527
-
528
- if (t.replayButton) {
529
- replayButton = {
530
- ...showWhenEnded,
531
- _tag: "img",
532
- style: { ...t.replayButton.css },
533
- url: t.replayButton.iconUrl,
534
- onClick: { kind: "play-video", task: playButtonTask },
535
- };
536
- if (t.replayButton.text) {
537
- replayButtonText = {
538
- ...showWhenEnded,
539
- _tag: "p",
540
- style: t.replayButton.text.css,
541
- innerText: t.replayButton.text.text,
542
- };
543
- }
544
- }
545
-
546
- const componentsSet = new Set<DElementDto>();
547
- const addComponent = (maybeComponent: DElementDto | false) => {
548
- if (maybeComponent) {
549
- componentsSet.add(maybeComponent);
550
- }
551
- };
552
-
553
- if (mode !== "gif-mode") {
554
- addComponent(buttonBar);
555
- addComponent(unmuteButton);
556
- addComponent(unmuteButtonText);
557
- addComponent(muteButton);
558
- addComponent(muteButtonText);
559
- addComponent(playButton);
560
- addComponent(playButtonText);
561
- addComponent(pauseButton);
562
- addComponent(pauseButtonText);
563
- addComponent(replayButton);
564
- addComponent(replayButtonText);
565
- }
566
- // components = []
567
- return { videoPlayer, components: [...componentsSet], autoPlayTasks: [...autoPlayTasks] };
568
- }
569
- private compileQuestion(
570
- pageId: string,
571
- page: BuilderPageDto,
572
- variableId: string,
573
- hasMainMedia: boolean,
574
- ): {
575
- question: DTextDto;
576
- buttonBar: DDivDto;
577
- } {
578
- // TODO REFACTORE DEFAULT QUESTION TO - (REMOVE USE TEXT1)
579
- // console.log(page);
580
- const t = this.currentTheme;
581
- const q = page.defaultQuestion;
582
- const text = page.mainText.text;
583
-
584
- const questionElement = this.compileMainText(text, !!page.mainText.audioFile, hasMainMedia);
585
- // initialTasks: Array<PlayAudioTask | DelayTask>;
586
- const buttons: DButtonDto[] = q.options.map((o) => {
587
- const btns = this.compileButton(o, {
588
- kind: "response-button",
589
- questionId: variableId,
590
- questionText: text,
591
- });
592
- return btns;
593
- });
594
- const buttonBar = this.compileButtonBar(buttons);
595
- return {
596
- question: questionElement,
597
- buttonBar,
598
- };
599
- }
600
-
601
- private compileButtonBar(buttons: Array<DButtonDto>): DDivDto {
602
- const t = this.currentTheme;
603
- const isSingle = buttons.length < 2;
604
- const style: PStyle = isSingle
605
- ? { ...t.buttonBar.container.base, ...t.buttonBar.container.whenSingle }
606
- : { ...t.buttonBar.container.base, ...t.buttonBar.container.whenMany };
607
- // console.log(t);
608
- const buttonBar: DDivDto = {
609
- _tag: "div",
610
- children: [...buttons],
611
- style,
612
- };
613
- return buttonBar;
614
- }
615
- private compileButton(
616
- buttonDto: BuilderPageDto["nextButton"],
617
- options:
618
- | { kind: "response-button"; questionId: string; questionText: string }
619
- | { kind: "next-button" },
620
- ): DButtonDto {
621
- const { id, value, label } = buttonDto;
622
- const t = this.currentTheme;
623
- const onclickAction: ButtonClickAction =
624
- options.kind === "response-button"
625
- ? {
626
- kind: "submit-fact",
627
- fact: {
628
- kind: "numeric-fact",
629
- label: label,
630
- value: value,
631
- referenceId: options.questionId,
632
- referenceLabel: options.questionText,
633
- },
634
- }
635
- : { kind: "next-page" };
636
-
637
- const btnStyles =
638
- value === 9 ? t.buttonBar.responseButtons.dontKnow : t.buttonBar.responseButtons.normal;
639
- if (t.buttonBar.vibrateMs) {
640
- onclickAction.vibrateMs = t.buttonBar.vibrateMs;
641
- }
642
-
643
- const btn: DButtonDto = {
644
- _tag: "button",
645
- innerText: label,
646
- style: { ...btnStyles.btn.css, ...btnStyles.btn.cssEnabled },
647
- onClick: onclickAction,
648
- };
649
-
650
- return btn;
651
- }
652
- }
1
+ import { ThemeCompiler } from "./ThemeCompiler";
2
+ import type { BuilderSchemaDto } from "../Builder-schema";
3
+ import { BuilderSchema } from "../Builder-schema";
4
+ import type { BuilderPageDto } from "../page/Builder-page";
5
+ import { DefaultTheme } from "./Default-theme";
6
+ import type { BuilderMainImageDto } from "../BuilderMainImageDto";
7
+ import type { BuilderMainVideoDto } from "../BuilderMainVideoDto";
8
+ import {
9
+ ButtonClickAction,
10
+ DButtonDto,
11
+ DDivDto,
12
+ DelayTask,
13
+ DElementDto,
14
+ DImgDto,
15
+ DTextDto,
16
+ PageDto,
17
+ PlayAudioTask,
18
+ PlayVideoTask,
19
+ PStyle,
20
+ Rule,
21
+ RuleActionPageQue,
22
+ SchemaDto,
23
+ } from "@media-quest/engine";
24
+
25
+ import { AudioFile } from "../media-files";
26
+ import { BuilderRule } from "../rulebuilder";
27
+ import { IDefaultTheme } from "./IDefault-theme";
28
+ import { Theme2 } from "./theme2";
29
+
30
+ export class DefaultThemeCompiler implements ThemeCompiler<IDefaultTheme> {
31
+ readonly name = "Ispe default theme.";
32
+ readonly defaultTheme = DefaultTheme;
33
+ readonly theme2 = Theme2;
34
+ currentTheme = Theme2;
35
+ allThemes = [DefaultTheme, Theme2];
36
+ private readonly TAG = "[ DEFAULT_THEME_COMPILER ]: ";
37
+
38
+ setTheme(theme: IDefaultTheme) {
39
+ this.currentTheme = theme;
40
+ }
41
+
42
+ constructor() {}
43
+
44
+ private compileRules(source: BuilderSchemaDto): Rule<RuleActionPageQue, never>[] {
45
+ const builderSchema = BuilderSchema.fromJson(source);
46
+ const ruleInput = builderSchema.getRuleInput();
47
+ const pageQueRules: Rule<RuleActionPageQue, never>[] = [];
48
+ source.rules.forEach((rule) => {
49
+ const engineRule = BuilderRule.fromDto(rule, ruleInput).toEngineRule();
50
+ if (!Rule.isEmpty(engineRule)) {
51
+ pageQueRules.push(engineRule);
52
+ } else {
53
+ console.log(this.TAG, "Throws away empty rule. " + rule.type + " " + rule.name);
54
+ }
55
+ });
56
+ return pageQueRules;
57
+ }
58
+
59
+ compile(source: BuilderSchemaDto): SchemaDto {
60
+ const t = this.currentTheme;
61
+ const themeName = t.name;
62
+ const schema = source.name;
63
+ const tag = schema + "-" + themeName + " compile";
64
+ const TAG = tag.toUpperCase();
65
+ // console.group(TAG);
66
+ const numberOfPages = source.pages.length;
67
+ const pages = source.pages.map((p, index) => {
68
+ return this.compilePage(p, index, numberOfPages, source.prefix);
69
+ });
70
+
71
+ let baseHeight = source.baseHeight;
72
+ let baseWidth = source.baseWidth;
73
+ let backgroundColor = source.backgroundColor;
74
+ if (t.dimensions.baseHeight) {
75
+ baseHeight = t.dimensions.baseHeight;
76
+ }
77
+ if (t.dimensions.baseWidth) {
78
+ baseWidth = t.dimensions.baseWidth;
79
+ }
80
+ if (t.dimensions.baseWidth) {
81
+ baseWidth = t.dimensions.baseWidth;
82
+ }
83
+ if (t.schemaBackgroundColor) {
84
+ backgroundColor = t.schemaBackgroundColor;
85
+ }
86
+
87
+ const rules = this.compileRules(source);
88
+
89
+ const dto: SchemaDto = {
90
+ id: source.id,
91
+ backgroundColor,
92
+ baseHeight,
93
+ baseWidth,
94
+ pageSequences: [],
95
+ pages,
96
+ predefinedFacts: [],
97
+ rules,
98
+ };
99
+ // console.groupEnd();
100
+ return dto;
101
+ }
102
+
103
+ private compilePage(
104
+ page: BuilderPageDto,
105
+ pageIndex: number,
106
+ totalNumberOfPages: number,
107
+ modulePrefix: string,
108
+ ): PageDto {
109
+ const pageNumber = pageIndex + 1;
110
+ const tags = page.tags ?? [];
111
+ const { nextButton, mainText, id, mainMedia, _type, prefix } = page;
112
+ const t = this.currentTheme;
113
+ const hasMainMedia = !!mainMedia;
114
+ const hasMainTextAudio = !!mainText.audioFile;
115
+
116
+ const elements: DElementDto[] = [];
117
+ let initialAudioTasks: Array<PlayAudioTask | DelayTask> = [];
118
+ let initialVideoTaskList: Array<PlayVideoTask | DelayTask> = [];
119
+ const newPage: PageDto = {
120
+ background: "white",
121
+ elements,
122
+ id,
123
+ prefix,
124
+ initialTasks: [],
125
+ tags: [...tags],
126
+ };
127
+ const bg = t.pageBackGround;
128
+ if (bg) {
129
+ const pageBackGround: DDivDto = {
130
+ style: bg.style,
131
+ _tag: "div",
132
+ children: [],
133
+ };
134
+ elements.push(pageBackGround);
135
+ }
136
+
137
+ const bgArea1 = t.backGroundArea1;
138
+
139
+ if (bgArea1) {
140
+ const backgroundArea1: DDivDto = {
141
+ style: bgArea1.style,
142
+ _tag: "div",
143
+ children: [],
144
+ };
145
+ elements.push(backgroundArea1);
146
+ }
147
+
148
+ if (t.progressBar) {
149
+ // console.log("ADDED PROGRESS.");
150
+ const progressInPercent = pageNumber / totalNumberOfPages;
151
+ // const a =
152
+ const baseStyles: PStyle = {
153
+ bottom: t.progressBar.bottom,
154
+ left: t.progressBar.left,
155
+ height: t.progressBar.height,
156
+ width: t.progressBar.width,
157
+ };
158
+ const progressBackGround: DDivDto = {
159
+ style: {
160
+ ...baseStyles,
161
+ ...t.progressBar.backgroundStyles,
162
+ },
163
+ _tag: "div",
164
+ children: [],
165
+ };
166
+
167
+ const currentProgress = t.progressBar.width * progressInPercent;
168
+ const progressIndicator: DDivDto = {
169
+ style: { ...baseStyles, ...t.progressBar.progressStyles, w: currentProgress },
170
+ _tag: "div",
171
+ children: [],
172
+ };
173
+ const pText = t.progressBar.text;
174
+
175
+ elements.push(progressBackGround);
176
+ elements.push(progressIndicator);
177
+ if (pText) {
178
+ const progressText: DTextDto = {
179
+ _tag: "p",
180
+ innerText: "side " + pageNumber + " av " + totalNumberOfPages,
181
+ style: pText.style,
182
+ };
183
+ elements.push(progressText);
184
+ }
185
+ }
186
+
187
+ if (page.mainText.audioFile) {
188
+ const autoPlay = page.mainText.autoplay;
189
+ const autoPlayDelay = page.mainText.autoplayDelay;
190
+ const res = this.compileMainTextAudio(
191
+ page.mainText.audioFile,
192
+ autoPlay,
193
+ autoPlayDelay,
194
+ hasMainMedia,
195
+ );
196
+ // console.log(page.mainText.text);
197
+ initialAudioTasks = [...res.initialTasks];
198
+ newPage.elements.push(...res.components);
199
+ }
200
+
201
+ if (_type === "question") {
202
+ const variableId = modulePrefix + "_" + page.prefix;
203
+ const qRes = this.compileQuestion(id, page, variableId, hasMainMedia);
204
+ newPage.elements.push(qRes.buttonBar, qRes.question);
205
+
206
+ // newPage.elements.push(question);
207
+ // console.log(question);
208
+ // elements.push(...buttons, question);
209
+ }
210
+
211
+ if (_type === "info-page") {
212
+ const infoText = mainText.text;
213
+ const nextButtonBar = this.compileButtonBar([
214
+ this.compileButton(nextButton, { kind: "next-button" }),
215
+ ]);
216
+ const infoTextElement = this.compileMainText(infoText, hasMainTextAudio, hasMainMedia);
217
+
218
+ // const textBase =
219
+ newPage.elements.push(infoTextElement, nextButtonBar);
220
+ // newPage.components.push(nextButtonComponent);
221
+ }
222
+ if (mainMedia && mainMedia.kind === "main-image") {
223
+ const mainImageElement = this.compileImage(mainMedia);
224
+ newPage.elements.push(mainImageElement);
225
+ }
226
+
227
+ if (mainMedia && mainMedia.kind === "main-video") {
228
+ const videoOutput = this.compileVideo(mainMedia);
229
+ // newPage.videoPlayer?.playUrl
230
+ newPage.videoPlayer = videoOutput.videoPlayer;
231
+ newPage.elements.push(...videoOutput.components);
232
+ initialVideoTaskList = [...videoOutput.autoPlayTasks];
233
+ }
234
+
235
+ // ADDING INITIAL TASKS IN CORRECT ORDER
236
+ newPage.initialTasks.push(...initialVideoTaskList);
237
+ newPage.initialTasks.push(...initialAudioTasks);
238
+ const clone = JSON.parse(JSON.stringify(newPage)) as PageDto;
239
+ return clone;
240
+ }
241
+
242
+ private compileImage(image: BuilderMainImageDto) {
243
+ const img: DImgDto = {
244
+ _tag: "img",
245
+ style: this.currentTheme.image.style,
246
+ url: image.file.downloadUrl,
247
+ };
248
+ return img;
249
+ }
250
+
251
+ private compileMainText(text: string, hasAudio: boolean, hasMainMedia: boolean): DTextDto {
252
+ const t = this.currentTheme;
253
+ const { base, hasMediaNotAudio, notMediaHasAudio, notMediaNotAudio, hasMediaHasAudio } =
254
+ t.mainText;
255
+ let style = base.text;
256
+ if (hasMainMedia && hasAudio) style = { ...style, ...hasMediaHasAudio.text };
257
+ if (!hasMainMedia && hasAudio) style = { ...style, ...notMediaHasAudio.text };
258
+ if (hasMainMedia && !hasAudio) style = { ...style, ...hasMediaNotAudio.text };
259
+ if (!hasMainMedia && !hasAudio) style = { ...style, ...notMediaNotAudio.text };
260
+ // console.log(style.textColor);
261
+ return {
262
+ _tag: "p",
263
+ innerText: text,
264
+ style,
265
+ };
266
+ }
267
+
268
+ private compileMainTextAudio(
269
+ audioFile: AudioFile,
270
+ autoPlay: boolean,
271
+ autoPlayDelay: number,
272
+ hasMainMedia: boolean,
273
+ ): {
274
+ components: DElementDto[];
275
+ initialTasks: Array<PlayAudioTask | DelayTask>;
276
+ } {
277
+ const t = this.currentTheme.mainText;
278
+ const audioId = audioFile.id;
279
+ const iconUrl = this.currentTheme.mainText.base.audio.iconUrl;
280
+ const baseIconStyles = t.base.audio;
281
+ const addedStyles = hasMainMedia ? t.hasMediaHasAudio.audio : t.notMediaHasAudio.audio;
282
+
283
+ const audioIconStyle = { ...baseIconStyles.css, ...addedStyles };
284
+ const task: PlayAudioTask = {
285
+ audioId,
286
+ blockAudio: false,
287
+ blockFormInput: false,
288
+ blockResponseButton: false,
289
+ blockVideo: false,
290
+ kind: "play-audio-task",
291
+ priority: "replace-all",
292
+ url: audioFile.downloadUrl,
293
+ };
294
+
295
+ const playMainTextAudio: DImgDto = {
296
+ _tag: "img",
297
+ url: iconUrl,
298
+ style: { ...audioIconStyle },
299
+ onClick: { kind: "play-audio", task },
300
+ };
301
+
302
+ let initialAudioTasks: Array<PlayAudioTask | DelayTask> = [];
303
+ if (autoPlay) {
304
+ const playAudioTask: PlayAudioTask = { ...task, priority: "follow-queue" };
305
+ initialAudioTasks = [playAudioTask];
306
+ if (autoPlayDelay > 0) {
307
+ const delayTask: DelayTask = {
308
+ kind: "delay-task",
309
+ priority: "follow-queue",
310
+ duration: autoPlayDelay,
311
+ blockVideo: false,
312
+ blockAudio: false,
313
+ blockResponseButton: false,
314
+ blockFormInput: false,
315
+ };
316
+ initialAudioTasks = [delayTask, playAudioTask];
317
+ }
318
+ }
319
+ // const autoplayTask =
320
+
321
+ return { components: [playMainTextAudio], initialTasks: [...initialAudioTasks] };
322
+ }
323
+
324
+ private compileVideo(video: BuilderMainVideoDto): {
325
+ videoPlayer: PageDto["videoPlayer"];
326
+ components: DElementDto[];
327
+ autoPlayTasks: Array<PlayVideoTask | DelayTask>;
328
+ } {
329
+ const t = this.currentTheme.videoPlayer;
330
+ const hasReplayButton = !!t.replayButton;
331
+
332
+ const mode = video.mode;
333
+ // const components: DElementDto[] = [];
334
+
335
+ let autoPlayTasks: Array<PlayVideoTask | DelayTask> = [];
336
+
337
+ let autoplayVideoTask: PlayVideoTask | false = false;
338
+ let autoplayDelayTask: DelayTask | false = false;
339
+
340
+ let buttonBar: DDivDto | false = false;
341
+ let playButton: DImgDto | false = false;
342
+ let playButtonText: DTextDto | false = false;
343
+ let replayButton: DImgDto | false = false;
344
+ let replayButtonText: DTextDto | false = false;
345
+ let pauseButton: DImgDto | false = false;
346
+ let pauseButtonText: DTextDto | false = false;
347
+ let unmuteButton: DImgDto | false = false;
348
+ let unmuteButtonText: DTextDto | false = false;
349
+ let muteButton: DImgDto | false = false;
350
+ let muteButtonText: DTextDto | false = false;
351
+
352
+ const showWhenEnded: Partial<DElementDto> = {
353
+ whenVideoEnded: { visibility: "visible" },
354
+ whenVideoEndedAndMuted: { visibility: "visible" },
355
+ whenVideoPlaying: { visibility: "hidden" },
356
+ whenVideoPlayingAndMuted: { visibility: "hidden" },
357
+ whenVideoPaused: { visibility: "hidden" },
358
+ whenVideoPausedAndMuted: { visibility: "hidden" },
359
+ };
360
+
361
+ const showWhenPlayingOrPaused: Partial<DElementDto> = {
362
+ whenVideoEnded: { visibility: "visible" },
363
+ whenVideoEndedAndMuted: { visibility: "visible" },
364
+ whenVideoPlaying: { visibility: "visible" },
365
+ whenVideoPlayingAndMuted: { visibility: "visible" },
366
+ whenVideoPaused: { visibility: "hidden" },
367
+ whenVideoPausedAndMuted: { visibility: "hidden" },
368
+ };
369
+
370
+ const showWhenPlaying: Partial<DElementDto> = {
371
+ whenVideoEnded: { visibility: "hidden" },
372
+ whenVideoEndedAndMuted: { visibility: "hidden" },
373
+ whenVideoPlaying: { visibility: "visible" },
374
+ whenVideoPlayingAndMuted: { visibility: "visible" },
375
+ whenVideoPaused: { visibility: "hidden" },
376
+ whenVideoPausedAndMuted: { visibility: "hidden" },
377
+ };
378
+
379
+ const showWhenPaused: Partial<DElementDto> = {
380
+ whenVideoEnded: { visibility: "hidden" },
381
+ whenVideoEndedAndMuted: { visibility: "hidden" },
382
+ whenVideoPlaying: { visibility: "hidden" },
383
+ whenVideoPlayingAndMuted: { visibility: "hidden" },
384
+ whenVideoPaused: { visibility: "visible" },
385
+ whenVideoPausedAndMuted: { visibility: "visible" },
386
+ };
387
+
388
+ const playButtonTask: PlayVideoTask = {
389
+ kind: "play-video-task",
390
+ url: video.file.downloadUrl,
391
+ videoId: video.file.id,
392
+ blockAudio: false,
393
+ blockFormInput: false,
394
+ blockResponseButton: false,
395
+ loop: mode === "gif-mode",
396
+ blockVideo: false,
397
+ priority: "replace-all",
398
+ };
399
+
400
+ if (video.mode === "autoplay" || video.mode === "gif-mode") {
401
+ autoplayVideoTask = { ...playButtonTask, priority: "follow-queue" };
402
+ autoPlayTasks = [autoplayVideoTask];
403
+ if (video.preDelay > 0) {
404
+ autoplayDelayTask = {
405
+ kind: "delay-task",
406
+ priority: "follow-queue",
407
+ duration: video.preDelay,
408
+ blockVideo: false,
409
+ blockAudio: false,
410
+ blockResponseButton: false,
411
+ blockFormInput: false,
412
+ };
413
+ autoPlayTasks = [autoplayDelayTask, autoplayVideoTask];
414
+ }
415
+ }
416
+
417
+ const videoPlayer: PageDto["videoPlayer"] = {
418
+ playUrl: video.file.downloadUrl,
419
+ style: t.videoElement.css,
420
+ // style: { h: 45, w: 100, x: 0, y: 55 },
421
+ };
422
+
423
+ if (t.buttonBar) {
424
+ buttonBar = {
425
+ _tag: "div",
426
+ style: { ...t.buttonBar },
427
+ children: [],
428
+ };
429
+ }
430
+
431
+ playButton = {
432
+ ...showWhenPaused,
433
+ _tag: "img",
434
+ url: t.playButton.iconUrl,
435
+ style: { ...t.playButton.css, ...t.playButton.cssEnabled },
436
+ // },
437
+ onClick: { kind: "play-video", task: playButtonTask },
438
+ };
439
+ if (t.playButton.text) {
440
+ playButtonText = {
441
+ ...showWhenPaused,
442
+ _tag: "p",
443
+ style: t.playButton.text.css,
444
+ innerText: t.playButton.text.text,
445
+ };
446
+ // components.push({
447
+ //
448
+ // });
449
+ }
450
+
451
+ pauseButton = {
452
+ ...showWhenPlaying,
453
+ _tag: "img",
454
+ style: {
455
+ ...t.pauseButton.css,
456
+ visibility: "hidden",
457
+ ...t.pauseButton.cssEnabled,
458
+ },
459
+ url: t.pauseButton.iconUrl,
460
+ onClick: { kind: "pause-video" },
461
+ };
462
+
463
+ if (t.pauseButton.text) {
464
+ pauseButtonText = {
465
+ ...showWhenPlaying,
466
+ _tag: "p",
467
+ style: t.pauseButton.text.css,
468
+ innerText: t.pauseButton.text.text,
469
+ };
470
+ }
471
+ if (t.unMuteButton) {
472
+ unmuteButton = {
473
+ _tag: "img",
474
+ style: { ...t.unMuteButton.css },
475
+ url: t.unMuteButton.iconUrl,
476
+ onClick: { kind: "un-mute-video" },
477
+ whenVideoPausedAndMuted: { visibility: "visible" },
478
+ whenVideoPaused: { visibility: "hidden" },
479
+ whenVideoPlayingAndMuted: { visibility: "visible" },
480
+ whenVideoPlaying: { visibility: "hidden" },
481
+ whenVideoEnded: { visibility: "hidden" },
482
+ whenVideoEndedAndMuted: { visibility: "hidden" },
483
+ };
484
+ if (t.unMuteButton.text) {
485
+ unmuteButtonText = {
486
+ _tag: "p",
487
+ style: t.unMuteButton.text.css,
488
+ innerText: t.unMuteButton.text.text,
489
+ whenVideoPausedAndMuted: { visibility: "visible" },
490
+ whenVideoPaused: { visibility: "hidden" },
491
+ whenVideoPlayingAndMuted: { visibility: "visible" },
492
+ whenVideoPlaying: { visibility: "hidden" },
493
+ whenVideoEnded: { visibility: "hidden" },
494
+ whenVideoEndedAndMuted: { visibility: "hidden" },
495
+ };
496
+ }
497
+ }
498
+ if (t.muteButton) {
499
+ muteButton = {
500
+ _tag: "img",
501
+ style: { ...t.muteButton.css },
502
+ url: t.muteButton.iconUrl,
503
+ onClick: { kind: "mute-video" },
504
+ whenVideoPausedAndMuted: { visibility: "hidden" },
505
+ whenVideoPaused: { visibility: "visible" },
506
+ whenVideoPlayingAndMuted: { visibility: "hidden" },
507
+ whenVideoPlaying: { visibility: "visible" },
508
+ whenVideoEnded: { visibility: "hidden" },
509
+ whenVideoEndedAndMuted: { visibility: "hidden" },
510
+ };
511
+
512
+ if (t.muteButton.text) {
513
+ muteButtonText = {
514
+ _tag: "p",
515
+ style: t.muteButton.text.css,
516
+ innerText: t.muteButton.text.text,
517
+ whenVideoPausedAndMuted: { visibility: "hidden" },
518
+ whenVideoPaused: { visibility: "visible" },
519
+ whenVideoPlayingAndMuted: { visibility: "hidden" },
520
+ whenVideoPlaying: { visibility: "visible" },
521
+ whenVideoEnded: { visibility: "hidden" },
522
+ whenVideoEndedAndMuted: { visibility: "hidden" },
523
+ };
524
+ }
525
+ }
526
+
527
+ if (t.replayButton) {
528
+ replayButton = {
529
+ ...showWhenEnded,
530
+ _tag: "img",
531
+ style: { ...t.replayButton.css },
532
+ url: t.replayButton.iconUrl,
533
+ onClick: { kind: "play-video", task: playButtonTask },
534
+ };
535
+ if (t.replayButton.text) {
536
+ replayButtonText = {
537
+ ...showWhenEnded,
538
+ _tag: "p",
539
+ style: t.replayButton.text.css,
540
+ innerText: t.replayButton.text.text,
541
+ };
542
+ }
543
+ }
544
+
545
+ const componentsSet = new Set<DElementDto>();
546
+ const addComponent = (maybeComponent: DElementDto | false) => {
547
+ if (maybeComponent) {
548
+ componentsSet.add(maybeComponent);
549
+ }
550
+ };
551
+
552
+ if (mode !== "gif-mode") {
553
+ addComponent(buttonBar);
554
+ addComponent(unmuteButton);
555
+ addComponent(unmuteButtonText);
556
+ addComponent(muteButton);
557
+ addComponent(muteButtonText);
558
+ addComponent(playButton);
559
+ addComponent(playButtonText);
560
+ addComponent(pauseButton);
561
+ addComponent(pauseButtonText);
562
+ addComponent(replayButton);
563
+ addComponent(replayButtonText);
564
+ }
565
+ // components = []
566
+ return { videoPlayer, components: [...componentsSet], autoPlayTasks: [...autoPlayTasks] };
567
+ }
568
+ private compileQuestion(
569
+ pageId: string,
570
+ page: BuilderPageDto,
571
+ variableId: string,
572
+ hasMainMedia: boolean,
573
+ ): {
574
+ question: DTextDto;
575
+ buttonBar: DDivDto;
576
+ } {
577
+ // TODO REFACTORE DEFAULT QUESTION TO - (REMOVE USE TEXT1)
578
+ // console.log(page);
579
+ const t = this.currentTheme;
580
+ const q = page.defaultQuestion;
581
+ const text = page.mainText.text;
582
+
583
+ const questionElement = this.compileMainText(text, !!page.mainText.audioFile, hasMainMedia);
584
+ // initialTasks: Array<PlayAudioTask | DelayTask>;
585
+ const buttons: DButtonDto[] = q.options.map((o) => {
586
+ const btns = this.compileButton(o, {
587
+ kind: "response-button",
588
+ questionId: variableId,
589
+ questionText: text,
590
+ });
591
+ return btns;
592
+ });
593
+ const buttonBar = this.compileButtonBar(buttons);
594
+ return {
595
+ question: questionElement,
596
+ buttonBar,
597
+ };
598
+ }
599
+
600
+ private compileButtonBar(buttons: Array<DButtonDto>): DDivDto {
601
+ const t = this.currentTheme;
602
+ const isSingle = buttons.length < 2;
603
+ const style: PStyle = isSingle
604
+ ? { ...t.buttonBar.container.base, ...t.buttonBar.container.whenSingle }
605
+ : { ...t.buttonBar.container.base, ...t.buttonBar.container.whenMany };
606
+ // console.log(t);
607
+ const buttonBar: DDivDto = {
608
+ _tag: "div",
609
+ children: [...buttons],
610
+ style,
611
+ };
612
+ return buttonBar;
613
+ }
614
+ private compileButton(
615
+ buttonDto: BuilderPageDto["nextButton"],
616
+ options:
617
+ | { kind: "response-button"; questionId: string; questionText: string }
618
+ | { kind: "next-button" },
619
+ ): DButtonDto {
620
+ const { id, value, label, cssOverride } = buttonDto;
621
+ const t = this.currentTheme;
622
+ const onclickAction: ButtonClickAction =
623
+ options.kind === "response-button"
624
+ ? {
625
+ kind: "submit-fact",
626
+ fact: {
627
+ kind: "numeric-fact",
628
+ label: label,
629
+ value: value,
630
+ referenceId: options.questionId,
631
+ referenceLabel: options.questionText,
632
+ },
633
+ }
634
+ : { kind: "next-page" };
635
+
636
+ let btnStyles =
637
+ value === 9 ? t.buttonBar.responseButtons.dontKnow : t.buttonBar.responseButtons.normal;
638
+ if (t.buttonBar.vibrateMs) {
639
+ onclickAction.vibrateMs = t.buttonBar.vibrateMs;
640
+ }
641
+
642
+ if(cssOverride) {
643
+ btnStyles.btn.css = {...btnStyles.btn.css, ...cssOverride}
644
+ }
645
+
646
+ const btn: DButtonDto = {
647
+ _tag: "button",
648
+ innerText: label,
649
+ style: { ...btnStyles.btn.css, ...btnStyles.btn.cssEnabled },
650
+ onClick: onclickAction,
651
+ };
652
+
653
+ return btn;
654
+ }
655
+ }