@media-quest/builder 0.0.1 → 0.0.2
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 +634 -0
- package/dist/public-api.d.ts +634 -0
- package/dist/public-api.js +2161 -0
- package/dist/public-api.mjs +2129 -0
- package/package.json +12 -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 +10 -6
- package/src/rulebuilder/Builder-condition-group.spec.ts +47 -0
- package/src/rulebuilder/Builder-condition-group.ts +109 -0
- package/src/rulebuilder/Builder-condition.spec.ts +169 -0
- package/src/rulebuilder/Builder-condition.ts +186 -0
- package/src/rulebuilder/Builder-operator.spec.ts +9 -0
- package/src/rulebuilder/Builder-operator.ts +31 -0
- package/src/rulebuilder/Builder-rule.spec.ts +207 -0
- package/src/rulebuilder/Builder-rule.ts +165 -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/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,395 @@
|
|
|
1
|
+
import { AbstractThemeCompiler } from "./AbstractThemeCompiler";
|
|
2
|
+
import type { BuilderSchemaDto } from "../Builder-schema";
|
|
3
|
+
import type { BuilderPageDto } from "../Builder-page";
|
|
4
|
+
import { DStateProps } from "./standard-props";
|
|
5
|
+
import { ThemeUtils } from "./theme-utils";
|
|
6
|
+
import { DefaultTheme, type IDefaultTheme } from "./IDefaultTheme";
|
|
7
|
+
import type { BuilderMainImageDto } from "../BuilderMainImageDto";
|
|
8
|
+
import type { BuilderMainVideoDto } from "../BuilderMainVideoDto";
|
|
9
|
+
import {
|
|
10
|
+
DAudioDto,
|
|
11
|
+
DAutoPlaySequence,
|
|
12
|
+
DCommand,
|
|
13
|
+
DDivDto,
|
|
14
|
+
DElementDto,
|
|
15
|
+
DImgDto,
|
|
16
|
+
DTextDto,
|
|
17
|
+
DUtil,
|
|
18
|
+
DVideoDto,
|
|
19
|
+
Fact,
|
|
20
|
+
PageDto,
|
|
21
|
+
SchemaDto,
|
|
22
|
+
} from "@media-quest/engine";
|
|
23
|
+
import { AudioFile } from "../media-files";
|
|
24
|
+
|
|
25
|
+
const U = DUtil;
|
|
26
|
+
const generateElementId = () => U.randomString(32);
|
|
27
|
+
export class DefaultThemeCompiler extends AbstractThemeCompiler<IDefaultTheme> {
|
|
28
|
+
readonly name = "Ispe default theme.";
|
|
29
|
+
constructor() {
|
|
30
|
+
super(DefaultTheme);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
compile(source: BuilderSchemaDto): SchemaDto {
|
|
34
|
+
const pages = source.pages.map((p) => this.compilePage(p, source.id));
|
|
35
|
+
const dto: SchemaDto = {
|
|
36
|
+
backgroundColor: source.backgroundColor,
|
|
37
|
+
baseHeight: source.baseHeight,
|
|
38
|
+
baseWidth: source.baseWidth,
|
|
39
|
+
id: source.id,
|
|
40
|
+
pageSequences: [],
|
|
41
|
+
pages,
|
|
42
|
+
predefinedFacts: [],
|
|
43
|
+
prefix: source.prefix,
|
|
44
|
+
rules: [],
|
|
45
|
+
stateFromEvent: [
|
|
46
|
+
{
|
|
47
|
+
onEvent: "VIDEO_ENDED_EVENT",
|
|
48
|
+
thenExecute: [
|
|
49
|
+
DStateProps.userPausedVideo.getSetFalseCommand(),
|
|
50
|
+
DStateProps.mediaBlockedByVideo.getSetFalseCommand(),
|
|
51
|
+
DStateProps.videoIsPlaying.getSetFalseCommand(),
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
onEvent: "VIDEO_PAUSED_EVENT",
|
|
56
|
+
thenExecute: [
|
|
57
|
+
DStateProps.videoIsPlaying.getSetFalseCommand(),
|
|
58
|
+
DStateProps.mediaBlockedByVideo.getSetFalseCommand(),
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
onEvent: "VIDEO_PLAY_EVENT",
|
|
63
|
+
thenExecute: [
|
|
64
|
+
DStateProps.videoIsPlaying.getSetTrueCommand(),
|
|
65
|
+
DStateProps.userPausedVideo.getSetFalseCommand(),
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
onEvent: "AUDIO_PLAY_EVENT",
|
|
70
|
+
thenExecute: [
|
|
71
|
+
DStateProps.audioIsPlaying.getSetTrueCommand(),
|
|
72
|
+
DStateProps.mediaBlockedByAudio.getSetTrueCommand(),
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
onEvent: "AUDIO_ENDED_EVENT",
|
|
77
|
+
thenExecute: [
|
|
78
|
+
DStateProps.audioIsPlaying.getSetFalseCommand(),
|
|
79
|
+
DStateProps.mediaBlockedByAudio.getSetFalseCommand(),
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
onEvent: "AUDIO_PAUSED_EVENT",
|
|
84
|
+
thenExecute: [
|
|
85
|
+
DStateProps.audioIsPlaying.getSetFalseCommand(),
|
|
86
|
+
DStateProps.mediaBlockedByAudio.getSetFalseCommand(),
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
stateProps: DStateProps.allDefaultProperties.map((def) => def.propDefinition),
|
|
91
|
+
stateQueries: DStateProps.allDefaultQueries,
|
|
92
|
+
};
|
|
93
|
+
return dto;
|
|
94
|
+
}
|
|
95
|
+
private compilePage(page: BuilderPageDto, _moduleId: string): PageDto {
|
|
96
|
+
// console.log(moduleId);
|
|
97
|
+
// const textElement
|
|
98
|
+
const { nextButton, mainText, id, mainMedia, _type } = page;
|
|
99
|
+
const elements: DElementDto[] = [];
|
|
100
|
+
const audioResourcesDto: DAudioDto[] = [];
|
|
101
|
+
const videoResources: DVideoDto[] = [];
|
|
102
|
+
let mainVideo: DVideoDto | false = false;
|
|
103
|
+
let mainTextAudio: DAudioDto | false = false;
|
|
104
|
+
|
|
105
|
+
if (page.mainText.audioFile) {
|
|
106
|
+
const res = this.compileMainTextAudio(page.mainText.audioFile);
|
|
107
|
+
elements.push(...res.elements);
|
|
108
|
+
audioResourcesDto.push(res.audioDto);
|
|
109
|
+
mainTextAudio = res.audioDto;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (_type === "question") {
|
|
113
|
+
const { buttons, question } = this.compileQuestion(id, page);
|
|
114
|
+
// console.log(question);
|
|
115
|
+
elements.push(...buttons, question);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (_type === "info-page") {
|
|
119
|
+
const infoText = mainText.text;
|
|
120
|
+
const nextBtnElement: DElementDto = this.compileButton(id, nextButton, {
|
|
121
|
+
kind: "next-button",
|
|
122
|
+
});
|
|
123
|
+
const element: DElementDto = {
|
|
124
|
+
text: infoText,
|
|
125
|
+
_tag: "p",
|
|
126
|
+
id: generateElementId(),
|
|
127
|
+
style: DefaultTheme.mainText.withMedia.text.css,
|
|
128
|
+
};
|
|
129
|
+
elements.push(element);
|
|
130
|
+
elements.push(nextBtnElement);
|
|
131
|
+
}
|
|
132
|
+
if (mainMedia && mainMedia.kind === "main-image") {
|
|
133
|
+
const mainImageElement = this.compileImage(mainMedia);
|
|
134
|
+
elements.push(mainImageElement);
|
|
135
|
+
}
|
|
136
|
+
if (mainMedia && mainMedia.kind === "main-video") {
|
|
137
|
+
const videoOutput = this.compileVideo(mainMedia);
|
|
138
|
+
mainVideo = videoOutput.videoDto;
|
|
139
|
+
elements.push(...videoOutput.elements);
|
|
140
|
+
videoResources.push(videoOutput.videoDto);
|
|
141
|
+
}
|
|
142
|
+
const mainVideoId = mainVideo ? mainVideo.id : undefined;
|
|
143
|
+
const autoPlaySequence: DAutoPlaySequence = {
|
|
144
|
+
blockUserInput: true,
|
|
145
|
+
id: "1",
|
|
146
|
+
items: [],
|
|
147
|
+
startCommands: [
|
|
148
|
+
DStateProps.mediaBlockedBySequence.getSetTrueCommand(),
|
|
149
|
+
DStateProps.inputBlockingBySequence.getSetTrueCommand(),
|
|
150
|
+
],
|
|
151
|
+
endCommands: [
|
|
152
|
+
DStateProps.mediaBlockedBySequence.getSetFalseCommand(),
|
|
153
|
+
DStateProps.inputBlockingBySequence.getSetFalseCommand(),
|
|
154
|
+
],
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
if (mainVideo && page.mainMedia && page.mainMedia.kind === "main-video" && page.mainMedia.mode === "autoplay") {
|
|
158
|
+
autoPlaySequence.items.push({
|
|
159
|
+
kind: "autoplay-video",
|
|
160
|
+
videoId: mainVideo.id,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (mainTextAudio && page.mainText.autoplay) {
|
|
165
|
+
autoPlaySequence.items.push({
|
|
166
|
+
kind: "autoplay-audio",
|
|
167
|
+
audioId: mainTextAudio.id,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const pageDto: PageDto = {
|
|
172
|
+
audio: audioResourcesDto,
|
|
173
|
+
autoPlaySequence: autoPlaySequence,
|
|
174
|
+
backgroundColor: "red",
|
|
175
|
+
elements,
|
|
176
|
+
id,
|
|
177
|
+
mainVideoId,
|
|
178
|
+
tags: [],
|
|
179
|
+
video: videoResources,
|
|
180
|
+
};
|
|
181
|
+
return pageDto;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private compileImage(image: BuilderMainImageDto) {
|
|
185
|
+
const img: DImgDto = {
|
|
186
|
+
_tag: "img",
|
|
187
|
+
id: image.file.id,
|
|
188
|
+
style: this.theme.image.style,
|
|
189
|
+
url: image.file.downloadUrl,
|
|
190
|
+
};
|
|
191
|
+
return img;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private compileMainTextAudio(audioFile: AudioFile): {
|
|
195
|
+
audioDto: DAudioDto;
|
|
196
|
+
elements: DElementDto[];
|
|
197
|
+
} {
|
|
198
|
+
const t = this.theme.mainText;
|
|
199
|
+
const audioId = audioFile.id;
|
|
200
|
+
const iconUrl =
|
|
201
|
+
"https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fvolume_up-24px.svg?alt=media&token=551bd0a6-a515-4f87-a245-da433f4833f9";
|
|
202
|
+
|
|
203
|
+
const buttonId = U.randomString(30);
|
|
204
|
+
const playMainTextAudio: DImgDto = {
|
|
205
|
+
_tag: "img",
|
|
206
|
+
id: buttonId,
|
|
207
|
+
url: iconUrl,
|
|
208
|
+
style: { ...t.withMedia.audio.css },
|
|
209
|
+
onClick: [
|
|
210
|
+
{
|
|
211
|
+
kind: "AUDIO_PLAY_COMMAND",
|
|
212
|
+
target: "AUDIO",
|
|
213
|
+
targetId: audioId,
|
|
214
|
+
payload: { volume: 1 },
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
onStateChange: [
|
|
218
|
+
{
|
|
219
|
+
queryName: DStateProps._Queries.disableAudioIconQuery.name,
|
|
220
|
+
whenTrue: [...ThemeUtils.disableClickCommands(buttonId, t.withMedia.audio.cssDisabled)],
|
|
221
|
+
whenFalse: [...ThemeUtils.enableClickCommands(buttonId, t.withMedia.audio.cssEnabled)],
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
};
|
|
225
|
+
const audioDto: DAudioDto = {
|
|
226
|
+
_tag: "audio",
|
|
227
|
+
// eventHandlers: [],
|
|
228
|
+
id: audioFile.id,
|
|
229
|
+
url: audioFile.downloadUrl,
|
|
230
|
+
};
|
|
231
|
+
return { audioDto, elements: [playMainTextAudio] };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private compileVideo(video: BuilderMainVideoDto) {
|
|
235
|
+
const t = this.theme.videoPlayer;
|
|
236
|
+
const videoId = video.file.id;
|
|
237
|
+
const playButtonId = "play-btn-for" + videoId;
|
|
238
|
+
const pauseButtonId = "pause-btn-for" + videoId;
|
|
239
|
+
const elements: DElementDto[] = [];
|
|
240
|
+
const videoDto: DVideoDto = {
|
|
241
|
+
_tag: "video",
|
|
242
|
+
id: video.file.id,
|
|
243
|
+
style: t.videoElement.css,
|
|
244
|
+
url: video.file.downloadUrl,
|
|
245
|
+
};
|
|
246
|
+
const playBtn: DImgDto = {
|
|
247
|
+
id: playButtonId,
|
|
248
|
+
_tag: "img",
|
|
249
|
+
url: t.playButton.iconUrl,
|
|
250
|
+
style: { ...t.playButton.css, ...t.playButton.cssEnabled },
|
|
251
|
+
onClick: [
|
|
252
|
+
{
|
|
253
|
+
kind: "VIDEO_PLAY_COMMAND",
|
|
254
|
+
target: "VIDEO",
|
|
255
|
+
targetId: videoId,
|
|
256
|
+
payload: {},
|
|
257
|
+
},
|
|
258
|
+
// TODO Check if this video shall block other media first?
|
|
259
|
+
DStateProps.mediaBlockedByVideo.getSetTrueCommand(),
|
|
260
|
+
DStateProps.userPausedVideo.getSetFalseCommand(),
|
|
261
|
+
],
|
|
262
|
+
onStateChange: [
|
|
263
|
+
{
|
|
264
|
+
queryName: DStateProps._Queries.disableVideoPlayQuery.name,
|
|
265
|
+
whenTrue: [...ThemeUtils.disableClickCommands(playButtonId, t.playButton.cssDisabled)],
|
|
266
|
+
whenFalse: [...ThemeUtils.enableClickCommands(playButtonId, t.playButton.cssEnabled)],
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
queryName: DStateProps._Queries.hideVideoPlayQuery.name,
|
|
270
|
+
whenTrue: [ThemeUtils.hideCommand(playButtonId)],
|
|
271
|
+
whenFalse: [ThemeUtils.showCommand(playButtonId)],
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
};
|
|
275
|
+
const pauseBtn: DImgDto = {
|
|
276
|
+
id: pauseButtonId,
|
|
277
|
+
_tag: "img",
|
|
278
|
+
style: {
|
|
279
|
+
...t.pauseButton.css,
|
|
280
|
+
visibility: "hidden",
|
|
281
|
+
...t.pauseButton.cssEnabled,
|
|
282
|
+
},
|
|
283
|
+
url: t.pauseButton.iconUrl,
|
|
284
|
+
onClick: [
|
|
285
|
+
{
|
|
286
|
+
kind: "VIDEO_PAUSE_COMMAND",
|
|
287
|
+
target: "VIDEO",
|
|
288
|
+
targetId: videoId,
|
|
289
|
+
payload: {},
|
|
290
|
+
},
|
|
291
|
+
DStateProps.mediaBlockedByVideo.getSetFalseCommand(),
|
|
292
|
+
DStateProps.userPausedVideo.getSetTrueCommand(),
|
|
293
|
+
],
|
|
294
|
+
onStateChange: [
|
|
295
|
+
{
|
|
296
|
+
queryName: DStateProps._Queries.hideVideoPauseQuery.name,
|
|
297
|
+
whenTrue: [ThemeUtils.hideCommand(pauseButtonId)],
|
|
298
|
+
whenFalse: [ThemeUtils.showCommand(pauseButtonId)],
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
};
|
|
302
|
+
elements.push(playBtn);
|
|
303
|
+
elements.push(pauseBtn);
|
|
304
|
+
return { videoDto, elements };
|
|
305
|
+
}
|
|
306
|
+
private compileQuestion(
|
|
307
|
+
pageId: string,
|
|
308
|
+
page: BuilderPageDto,
|
|
309
|
+
): {
|
|
310
|
+
question: DTextDto;
|
|
311
|
+
buttons: DDivDto[];
|
|
312
|
+
} {
|
|
313
|
+
// TODO REFACTORE DEFAULT QUESTION TO - (REMOVE USE TEXT1)
|
|
314
|
+
// console.log(page);
|
|
315
|
+
const q = page.defaultQuestion;
|
|
316
|
+
const text = page.mainText.text;
|
|
317
|
+
|
|
318
|
+
const question: DTextDto = {
|
|
319
|
+
_tag: "p",
|
|
320
|
+
text,
|
|
321
|
+
eventHandlers: [],
|
|
322
|
+
id: U.randomString(30),
|
|
323
|
+
onClick: [],
|
|
324
|
+
onStateChange: [],
|
|
325
|
+
style: DefaultTheme.mainText.withMedia.text.css,
|
|
326
|
+
};
|
|
327
|
+
const buttons = q.options.map((o) => {
|
|
328
|
+
const btns = this.compileButton(pageId, o, {
|
|
329
|
+
kind: "response-button",
|
|
330
|
+
questionId: "",
|
|
331
|
+
});
|
|
332
|
+
return btns;
|
|
333
|
+
});
|
|
334
|
+
ThemeUtils.spaceEvenlyX(buttons);
|
|
335
|
+
return { question, buttons };
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
private compileButton(
|
|
339
|
+
pageId: string,
|
|
340
|
+
buttonDto: BuilderPageDto["nextButton"],
|
|
341
|
+
options: { kind: "response-button"; questionId: string } | { kind: "next-button" },
|
|
342
|
+
) {
|
|
343
|
+
const factsCollected: Fact[] = [];
|
|
344
|
+
const { id, value, label } = buttonDto;
|
|
345
|
+
|
|
346
|
+
const { div, text1 } = DefaultTheme.responseButtons;
|
|
347
|
+
if (options.kind === "response-button") {
|
|
348
|
+
const fact: Fact = {
|
|
349
|
+
kind: "numeric-fact",
|
|
350
|
+
label: label,
|
|
351
|
+
value: value,
|
|
352
|
+
referenceId: options.questionId,
|
|
353
|
+
referenceLabel: "QuestionId: " + options.questionId,
|
|
354
|
+
};
|
|
355
|
+
factsCollected.push(fact);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const onClickHandler: DCommand = {
|
|
359
|
+
kind: "ENGINE_LEAVE_PAGE_COMMAND",
|
|
360
|
+
target: "ENGINE",
|
|
361
|
+
targetId: "ENGINE",
|
|
362
|
+
payload: {
|
|
363
|
+
pageId,
|
|
364
|
+
factsCollected,
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
const btn: DDivDto = {
|
|
368
|
+
id,
|
|
369
|
+
_tag: "div",
|
|
370
|
+
children: [
|
|
371
|
+
{
|
|
372
|
+
_tag: "p",
|
|
373
|
+
id: U.randomString(30),
|
|
374
|
+
text: label,
|
|
375
|
+
style: text1,
|
|
376
|
+
},
|
|
377
|
+
],
|
|
378
|
+
onStateChange: [
|
|
379
|
+
{
|
|
380
|
+
queryName: DStateProps._Queries.disableUserInputQuery.name,
|
|
381
|
+
whenFalse: [...ThemeUtils.enableClickCommands(id, div.cssEnabled)],
|
|
382
|
+
whenTrue: [...ThemeUtils.disableClickCommands(id, div.cssDisabled)],
|
|
383
|
+
},
|
|
384
|
+
],
|
|
385
|
+
style: { ...div.css, ...div.cssEnabled },
|
|
386
|
+
onClick: [onClickHandler],
|
|
387
|
+
};
|
|
388
|
+
if (options.kind === "next-button") {
|
|
389
|
+
btn.style.x = 50;
|
|
390
|
+
btn.style.y = 8;
|
|
391
|
+
btn.style.transform = "translate(-50%, 0%)";
|
|
392
|
+
}
|
|
393
|
+
return btn;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const IconUrls = {
|
|
2
|
+
ispeWhitePng:
|
|
3
|
+
'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fispe-hvit.png?alt=media&token=f6fe628b-2d99-472d-a2ea-e062873e2e22',
|
|
4
|
+
pauseSvg:
|
|
5
|
+
'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fpause-24px.svg?alt=media&token=47337491-bb0d-4c56-9c89-a073ce19fad4',
|
|
6
|
+
pauseCircleOutlineSvg:
|
|
7
|
+
'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fpause_circle_outline-24px.svg?alt=media&token=133aabc8-ab9a-4eaa-9914-4f0f82c22ee2',
|
|
8
|
+
|
|
9
|
+
pauseCircleFilledSvg:
|
|
10
|
+
'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fpause_circle_filled-24px.svg?alt=media&token=af3f12c3-3199-4096-8ed2-76347b9a0a0a',
|
|
11
|
+
playCircleRegular:
|
|
12
|
+
'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fplay-circle-regular.svg?alt=media&token=0867b690-d7fd-475c-8e91-b2d7aeca54d1',
|
|
13
|
+
playArrowSvg:
|
|
14
|
+
'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fplay_arrow-24px.svg?alt=media&token=2fa95e1f-61f7-4a18-afb3-210eabae8227',
|
|
15
|
+
playCircleOutline:
|
|
16
|
+
'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fplay_circle_outline-24px.svg?alt=media&token=3a9f62c5-dfa2-40ef-a50e-cf1bdd2d47f2',
|
|
17
|
+
|
|
18
|
+
stopCircleSvg:
|
|
19
|
+
'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fstop_circle-24px.svg?alt=media&token=8fbc8b89-29bb-49ad-ae11-b8882ba3ca77',
|
|
20
|
+
stopSvg:
|
|
21
|
+
'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fstop-24px.svg?alt=media&token=d2cd41f1-1331-4243-9b7a-dc0f0ccd255d',
|
|
22
|
+
replayCircleSvg:
|
|
23
|
+
'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Freplay-24px.svg?alt=media&token=3c35ccf4-b467-4e81-85d6-b36ac64738ad',
|
|
24
|
+
|
|
25
|
+
volumeOffSvg:
|
|
26
|
+
'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fvolume_off-24px.svg?alt=media&token=4e41cc10-9f4b-4967-b4df-ed0682e657a9',
|
|
27
|
+
volumeUpSvg:
|
|
28
|
+
'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fvolume_up-24px.svg?alt=media&token=551bd0a6-a515-4f87-a245-da433f4833f9'
|
|
29
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { DState, BooleanStateProperty } from "@media-quest/engine";
|
|
2
|
+
|
|
3
|
+
export namespace DStateProps {
|
|
4
|
+
export const mediaBlockedBySequence = new BooleanStateProperty(
|
|
5
|
+
"media-blocked-by-autoplay-sequence",
|
|
6
|
+
false,
|
|
7
|
+
"Should be true if the page is in a autoplay-sequence. The autoplay-sequence will always block other media.",
|
|
8
|
+
);
|
|
9
|
+
export const inputBlockingBySequence = new BooleanStateProperty("input-blocked-by-autoplay-sequence", false, "");
|
|
10
|
+
export const mediaBlockedByAudio = new BooleanStateProperty("media-blocked-by-audio", false, "");
|
|
11
|
+
export const inputBlockedByAudio = new BooleanStateProperty("input-blocked-by-audio", false, "");
|
|
12
|
+
export const mediaBlockedByVideo = new BooleanStateProperty("media-blocked-by-video", false, "");
|
|
13
|
+
export const inputBlockedByVideo = new BooleanStateProperty(
|
|
14
|
+
"input-blocked-by-video",
|
|
15
|
+
false,
|
|
16
|
+
"Should be true if a video is playing, and this video is suppose to block user-input.",
|
|
17
|
+
);
|
|
18
|
+
export const userPausedVideo = new BooleanStateProperty(
|
|
19
|
+
"user-paused-video",
|
|
20
|
+
false,
|
|
21
|
+
"Should be true if user paused the video by pressing the pause-button.",
|
|
22
|
+
);
|
|
23
|
+
export const videoIsPlaying = new BooleanStateProperty(
|
|
24
|
+
"video-is-playing",
|
|
25
|
+
false,
|
|
26
|
+
"Should be true if any video is playing on the page.",
|
|
27
|
+
);
|
|
28
|
+
export const audioIsPlaying = new BooleanStateProperty(
|
|
29
|
+
"audio-is-playing",
|
|
30
|
+
false,
|
|
31
|
+
"Should be tru if any audio is playing on page",
|
|
32
|
+
);
|
|
33
|
+
const _props = {
|
|
34
|
+
inputBlockedByAudio,
|
|
35
|
+
mediaBlockedByAudio,
|
|
36
|
+
inputBlockingBySequence,
|
|
37
|
+
mediaBlockedBySequence,
|
|
38
|
+
inputBlockedByVideo,
|
|
39
|
+
mediaBlockedByVideo,
|
|
40
|
+
userPausedVideo,
|
|
41
|
+
videoIsPlaying,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const disableAudioIconQuery: DState.StateQuery = {
|
|
45
|
+
name: "disable-Audio",
|
|
46
|
+
condition: {
|
|
47
|
+
kind: "complex-condition",
|
|
48
|
+
name: "audio-controls-are-blocked",
|
|
49
|
+
some: [
|
|
50
|
+
mediaBlockedBySequence.getIsTrueCondition(),
|
|
51
|
+
mediaBlockedByAudio.getIsTrueCondition(),
|
|
52
|
+
mediaBlockedByVideo.getIsTrueCondition(),
|
|
53
|
+
],
|
|
54
|
+
all: [],
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
const hideVideoPlayQuery: DState.StateQuery = {
|
|
58
|
+
name: "hide-video-play-button",
|
|
59
|
+
condition: {
|
|
60
|
+
kind: "complex-condition",
|
|
61
|
+
name: "video-is-playing-condition",
|
|
62
|
+
all: [videoIsPlaying.getIsTrueCondition()],
|
|
63
|
+
some: [],
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const hideVideoPauseQuery: DState.StateQuery = {
|
|
68
|
+
name: "hide-video-pause-button",
|
|
69
|
+
condition: {
|
|
70
|
+
kind: "complex-condition",
|
|
71
|
+
name: "video-is-not-playing-condition",
|
|
72
|
+
all: [videoIsPlaying.getIsFalseCondition()],
|
|
73
|
+
some: [],
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const disableVideoPlayQuery: DState.StateQuery = {
|
|
78
|
+
name: "disable-video",
|
|
79
|
+
condition: {
|
|
80
|
+
kind: "complex-condition",
|
|
81
|
+
name: "video-play shall be disabled",
|
|
82
|
+
all: [userPausedVideo.getIsFalseCondition()],
|
|
83
|
+
some: [
|
|
84
|
+
mediaBlockedBySequence.getIsTrueCondition(),
|
|
85
|
+
mediaBlockedByAudio.getIsTrueCondition(),
|
|
86
|
+
mediaBlockedByVideo.getIsTrueCondition(),
|
|
87
|
+
audioIsPlaying.getIsTrueCondition(),
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
const disableUserInputQuery: DState.StateQuery = {
|
|
92
|
+
name: "disable-user-input",
|
|
93
|
+
condition: {
|
|
94
|
+
kind: "complex-condition",
|
|
95
|
+
name: "User input shall be disabled (Response-buttons, FormControls...)",
|
|
96
|
+
all: [],
|
|
97
|
+
some: [
|
|
98
|
+
inputBlockedByAudio.getIsTrueCondition(),
|
|
99
|
+
inputBlockedByVideo.getIsTrueCondition(),
|
|
100
|
+
inputBlockingBySequence.getIsTrueCondition(),
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
export const _Queries = {
|
|
105
|
+
disableAudioIconQuery,
|
|
106
|
+
disableVideoPlayQuery,
|
|
107
|
+
disableUserInputQuery,
|
|
108
|
+
hideVideoPauseQuery,
|
|
109
|
+
hideVideoPlayQuery,
|
|
110
|
+
};
|
|
111
|
+
export const allDefaultProperties = Object.values(_props);
|
|
112
|
+
export const allDefaultQueries = Object.values(_Queries);
|
|
113
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { DCommand, ElementCommand } from "@media-quest/engine";
|
|
2
|
+
import { DStyle } from "@media-quest/engine";
|
|
3
|
+
import { DElementDto } from "@media-quest/engine";
|
|
4
|
+
|
|
5
|
+
export namespace ThemeUtils {
|
|
6
|
+
export const disableClickCommands = (elementId: string, styleChanges: Partial<DStyle>): ElementCommand[] => {
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
kind: "ELEMENT_DISABLE_CLICK_COMMAND",
|
|
10
|
+
target: "ELEMENT",
|
|
11
|
+
targetId: elementId,
|
|
12
|
+
payload: {},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
kind: "ELEMENT_STYLE_COMMAND",
|
|
16
|
+
target: "ELEMENT",
|
|
17
|
+
targetId: elementId,
|
|
18
|
+
payload: { changes: styleChanges },
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const enableClickCommands = (elementId: string, styleChanges: Partial<DStyle>): ElementCommand[] => {
|
|
24
|
+
return [
|
|
25
|
+
{
|
|
26
|
+
kind: "ELEMENT_ENABLE_CLICK_COMMAND",
|
|
27
|
+
target: "ELEMENT",
|
|
28
|
+
targetId: elementId,
|
|
29
|
+
payload: {},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
kind: "ELEMENT_STYLE_COMMAND",
|
|
33
|
+
target: "ELEMENT",
|
|
34
|
+
targetId: elementId,
|
|
35
|
+
payload: { changes: styleChanges },
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
};
|
|
39
|
+
export const hideCommand = (elementId: string): ElementCommand => {
|
|
40
|
+
const hideCommand: DCommand = {
|
|
41
|
+
kind: "ELEMENT_STYLE_COMMAND",
|
|
42
|
+
target: "ELEMENT",
|
|
43
|
+
targetId: elementId,
|
|
44
|
+
payload: { changes: { visibility: "hidden" } },
|
|
45
|
+
};
|
|
46
|
+
return hideCommand;
|
|
47
|
+
};
|
|
48
|
+
export const showCommand = (elementId: string): ElementCommand => {
|
|
49
|
+
const showCommand: DCommand = {
|
|
50
|
+
kind: "ELEMENT_STYLE_COMMAND",
|
|
51
|
+
target: "ELEMENT",
|
|
52
|
+
targetId: elementId,
|
|
53
|
+
payload: { changes: { visibility: "visible" } },
|
|
54
|
+
};
|
|
55
|
+
return showCommand;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const spaceEvenlyX = <T extends Pick<DElementDto, "style">>(
|
|
59
|
+
items: ReadonlyArray<T>,
|
|
60
|
+
options: { startAt: number; endAt: number; defaultItemWidth: number } = {
|
|
61
|
+
startAt: 0,
|
|
62
|
+
endAt: 100,
|
|
63
|
+
defaultItemWidth: 5,
|
|
64
|
+
},
|
|
65
|
+
): ReadonlyArray<T> => {
|
|
66
|
+
const startAt = options?.startAt ?? 0;
|
|
67
|
+
const endAt = options?.endAt ?? 100;
|
|
68
|
+
const range = Math.abs(endAt - startAt);
|
|
69
|
+
if (items.length === 0) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
const marginCount = items.length + 1;
|
|
73
|
+
const defaultWidth = options.defaultItemWidth ?? 150 / marginCount;
|
|
74
|
+
|
|
75
|
+
let totalWidthOfElements = items.reduce((prev, curr) => {
|
|
76
|
+
const w = curr.style.w ?? defaultWidth;
|
|
77
|
+
return prev + w;
|
|
78
|
+
}, 0);
|
|
79
|
+
|
|
80
|
+
let cursor = startAt;
|
|
81
|
+
const rest = Math.max(range - totalWidthOfElements, 0);
|
|
82
|
+
const margin = rest / marginCount;
|
|
83
|
+
|
|
84
|
+
items.forEach((item) => {
|
|
85
|
+
cursor = cursor + margin;
|
|
86
|
+
const w = item.style.w ?? defaultWidth;
|
|
87
|
+
const x = cursor;
|
|
88
|
+
cursor = cursor + w;
|
|
89
|
+
item.style.w = w;
|
|
90
|
+
item.style.x = x;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return items;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const centerY = (): Pick<DStyle, "y" | "transform"> => ({
|
|
97
|
+
y: 50,
|
|
98
|
+
transform: "translate(0%, 50%)",
|
|
99
|
+
});
|
|
100
|
+
export const centerX = (): Pick<DStyle, "x" | "transform"> => ({
|
|
101
|
+
x: 50,
|
|
102
|
+
transform: "translate(-50%, 0%)",
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
export const centerXY = (): Pick<DStyle, "x" | "y" | "transform"> => ({
|
|
106
|
+
x: 50,
|
|
107
|
+
y: 50,
|
|
108
|
+
transform: "translate(-50%, 50%)",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ThemeUtils } from "./theme-utils";
|
|
2
|
+
import { DStyle } from "@media-quest/engine";
|
|
3
|
+
|
|
4
|
+
describe("Theme1 works", () => {
|
|
5
|
+
test("Can space evenly when all is even", () => {
|
|
6
|
+
const btn1 = {};
|
|
7
|
+
const els = ThemeUtils.spaceEvenlyX<{ style: Partial<DStyle> }>([
|
|
8
|
+
{ style: { w: 20 } },
|
|
9
|
+
{ style: { w: 20 } },
|
|
10
|
+
{ style: { w: 20 } },
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
const first = els[0];
|
|
14
|
+
const second = els[1];
|
|
15
|
+
const third = els[2];
|
|
16
|
+
expect(first.style.x).toBe(10);
|
|
17
|
+
expect(second.style.x).toBe(40);
|
|
18
|
+
expect(third.style.x).toBe(70);
|
|
19
|
+
// responseButtons.forEach((el) => {
|
|
20
|
+
// expect(el._tag === "div").toBe(true);
|
|
21
|
+
// expect(el.children.length).toBe(1);
|
|
22
|
+
// });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("Can space evenly even if uneven lengths", () => {
|
|
26
|
+
const btn1 = {};
|
|
27
|
+
const els = ThemeUtils.spaceEvenlyX([
|
|
28
|
+
{ style: { w: 10, x: 0 } },
|
|
29
|
+
{ style: { w: 30, x: 10 } },
|
|
30
|
+
{ style: { w: 20, x: 30 } },
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
const first = els[0];
|
|
34
|
+
const second = els[1];
|
|
35
|
+
const third = els[2];
|
|
36
|
+
expect(first.style.x).toBe(10);
|
|
37
|
+
expect(second.style.x).toBe(30);
|
|
38
|
+
expect(third.style.x).toBe(70);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("Can space evenly on a shorter scale 10-90", () => {
|
|
42
|
+
const els = ThemeUtils.spaceEvenlyX([{ style: {} }, { style: {} }, { style: {} }], {
|
|
43
|
+
startAt: 10,
|
|
44
|
+
endAt: 90,
|
|
45
|
+
defaultItemWidth: 20,
|
|
46
|
+
}) as ReadonlyArray<{ style: { x: number; w: number } }>;
|
|
47
|
+
|
|
48
|
+
expect(els[0].style.x).toBe(15);
|
|
49
|
+
// expect(els[1].style.x).toBe(10);
|
|
50
|
+
// expect(els[2].style.x).toBe(10);
|
|
51
|
+
});
|
|
52
|
+
});
|