@media-quest/builder 0.0.39 → 0.0.41

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 (42) hide show
  1. package/dist/public-api.d.ts +82 -100
  2. package/dist/public-api.js +68 -128
  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 +77 -62
  8. package/src/Builder-question.spec.ts +1 -0
  9. package/src/Builder-question.ts +97 -98
  10. package/src/Builder-schema.spec.ts +348 -348
  11. package/src/Builder-schema.ts +308 -306
  12. package/src/builder-compiler.ts +14 -20
  13. package/src/code-book/codebook-variable.ts +27 -27
  14. package/src/code-book/codebook.ts +89 -89
  15. package/src/media-files.ts +28 -32
  16. package/src/page/Builder-page-collection.spec.ts +224 -219
  17. package/src/page/Builder-page-collection.ts +129 -129
  18. package/src/page/Builder-page.spec.ts +177 -177
  19. package/src/page/Builder-page.ts +250 -250
  20. package/src/primitives/ID.ts +135 -135
  21. package/src/public-api.ts +29 -30
  22. package/src/rulebuilder/RuleAction.ts +105 -105
  23. package/src/schema-config.ts +25 -26
  24. package/src/sum-score/sum-score-variable-collection.spec.ts +68 -68
  25. package/src/sum-score/sum-score-variable-collection.ts +101 -101
  26. package/src/sum-score/sum-score-variable.ts +0 -1
  27. package/src/sum-score/sum-score.ts +166 -167
  28. package/src/tag/BuilderTag.ts +45 -45
  29. package/src/tag/Tag-Collection.ts +53 -53
  30. package/src/theme/Default-theme.ts +173 -188
  31. package/src/theme/IDefault-theme.ts +124 -125
  32. package/src/theme/ThemeCompiler.ts +10 -11
  33. package/src/theme/default-theme-compiler.spec.ts +31 -31
  34. package/src/theme/default-theme-compiler.ts +660 -652
  35. package/src/theme/icon-urls.ts +29 -29
  36. package/src/theme/icons.ts +117 -117
  37. package/src/theme/theme-utils.spec.ts +52 -52
  38. package/src/theme/theme-utils.ts +56 -56
  39. package/src/theme/theme2.ts +399 -386
  40. package/tsconfig.json +19 -19
  41. package/src/Builder-schema-dto.spec.ts +0 -155
  42. package/src/Builder-schema-dto.ts +0 -86
@@ -1,652 +1,660 @@
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, DStyle,
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
+ const _btnStyles =
637
+ value === 9 ? t.buttonBar.responseButtons.dontKnow : t.buttonBar.responseButtons.normal;
638
+ let css: PStyle = DStyle.clone(_btnStyles.btn.css)
639
+ const cssEnabled = DStyle.clone(_btnStyles.btn.cssEnabled)
640
+
641
+ if (t.buttonBar.vibrateMs) {
642
+ // TODO DO NOT WORK.
643
+ // onclickAction.vibrateMs = t.buttonBar.vibrateMs;
644
+ }
645
+
646
+ if(cssOverride) {
647
+ console.log(cssOverride);
648
+ css = {...css, ...cssOverride}
649
+ }
650
+
651
+ const btn: DButtonDto = {
652
+ _tag: "button",
653
+ innerText: label,
654
+ style: { ...css, ...cssEnabled },
655
+ onClick: onclickAction,
656
+ };
657
+
658
+ return btn;
659
+ }
660
+ }