@media-quest/engine 0.0.30 → 0.0.31

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.
@@ -1,35 +1,42 @@
1
- import { PlayAudioTask, PlayVideoTask } from "../page/task";
2
- import { Fact } from "../rules/fact";
3
-
4
- export type ButtonClickAction =
5
- | { kind: "play-audio"; task: PlayAudioTask }
6
- | { kind: "pause-audio" }
7
- | { kind: "play-video"; task: PlayVideoTask }
8
- | { kind: "pause-video" }
9
- | { kind: "submit-fact"; fact: Fact }
10
- | { kind: "next-page" }
11
- | { kind: "submit-form" };
12
-
13
- export const ButtonClickAction = {
14
- describe: (a: ButtonClickAction): string => {
15
- switch (a.kind) {
16
- case "next-page":
17
- return "go to next page";
18
- case "play-video":
19
- return "VideoId = " + a.task.videoId;
20
- case "play-audio":
21
- return "AudioId = " + a.task.audioId;
22
- case "pause-video":
23
- return "";
24
- case "pause-audio":
25
- return "";
26
- case "submit-fact":
27
- return a.fact.label + " = " + a.fact.value;
28
- case "submit-form":
29
- return "";
30
- default:
31
- const _exhaustiveCheck: never = a;
32
- return "";
33
- }
34
- },
35
- };
1
+ import { PlayAudioTask, PlayVideoTask } from "../page/task";
2
+ import { Fact } from "../rules/fact";
3
+
4
+ export type ButtonClickAction =
5
+ | { kind: "play-audio"; task: PlayAudioTask; vibrateMs?: number }
6
+ | { kind: "pause-audio"; vibrateMs?: number }
7
+ | { kind: "play-video"; task: PlayVideoTask; vibrateMs?: number }
8
+ | { kind: "mute-video"; vibrateMs?: number }
9
+ | { kind: "un-mute-video"; vibrateMs?: number }
10
+ | { kind: "pause-video"; vibrateMs?: number }
11
+ | { kind: "submit-fact"; fact: Fact; vibrateMs?: number }
12
+ | { kind: "next-page"; vibrateMs?: number }
13
+ | { kind: "submit-form"; vibrateMs?: number };
14
+
15
+ // export type ButtonClickAction = _ButtonClickAction & ;
16
+ export const ButtonClickAction = {
17
+ describe: (a: ButtonClickAction): string => {
18
+ switch (a.kind) {
19
+ case "next-page":
20
+ return "go to next page";
21
+ case "play-video":
22
+ return "VideoId = " + a.task.videoId;
23
+ case "play-audio":
24
+ return "AudioId = " + a.task.audioId;
25
+ case "pause-video":
26
+ return "";
27
+ case "pause-audio":
28
+ return "";
29
+ case "submit-fact":
30
+ return a.fact.label + " = " + a.fact.value;
31
+ case "submit-form":
32
+ return "";
33
+ case "mute-video":
34
+ return "mute-video";
35
+ case "un-mute-video":
36
+ return "un-mute-video";
37
+ default:
38
+ const _exhaustiveCheck: never = a;
39
+ return "";
40
+ }
41
+ },
42
+ };
@@ -1,36 +1,40 @@
1
- import { DCss } from "./css";
2
- import LengthUnit = DCss.LengthUnit;
3
- import { DStyle } from "./DStyle";
4
- describe("Css utils testing", () => {
5
- test("Clamp and round of px-units", () => {
6
- const px1300: DCss.Px = { _unit: "px", value: 1300 };
7
- const px555: DCss.Px = { _unit: "px", value: 555 };
8
- const px123: DCss.Px = { _unit: "px", value: 123 };
9
- const px10: DCss.Px = { _unit: "px", value: 10 };
10
- const px3: DCss.Px = { _unit: "px", value: 3 };
11
- const px0: DCss.Px = { _unit: "px", value: 0 };
12
- const px1: DCss.Px = { _unit: "px", value: 1 };
13
- const scale026 = DCss.toString;
14
- // const scale001 = DCss.toStringCreator(0.01);
15
-
16
- expect(DCss.toString(px1300, 0.26)).toBe("338px");
17
- expect(DCss.toString(px10, 0.26)).toBe("3px");
18
- expect(DCss.toString(px1, 0.26)).toBe("1px");
19
- expect(DCss.toString(px3, 0.26)).toBe("1px");
20
- expect(DCss.toString(px0, 0.26)).toBe("0px");
21
- expect(DCss.toString(px0, 0.26)).toBe("0px");
22
- expect(DCss.toString(px555, 0.26)).toBe("144px");
23
- expect(DCss.toString(px123, 0.01)).toBe("4px");
24
- expect(DCss.toString(px1300, 0.01)).toBe("39px");
25
- expect(DCss.isLengthUnit()).toBe(false);
26
- expect(DCss.isLengthUnit({} as LengthUnit)).toBe(false);
27
- expect(DCss.isLengthUnit(px123)).toBe(true);
28
- });
29
-
30
- test("Normalize div: ", () => {
31
- const div = document.createElement("div");
32
- const normalized = DStyle.normalize(div);
33
- expect(normalized.style.padding).toBe("0px");
34
- expect(normalized.style.boxSizing).toBe("border-box");
35
- });
36
- });
1
+ import { DCss } from "./css";
2
+ import LengthUnit = DCss.LengthUnit;
3
+ import { DStyle } from "./DStyle";
4
+ describe("Css utils testing", () => {
5
+ test("Clamp and round of px-units", () => {
6
+ const px1300: DCss.Px = { _unit: "px", value: 1300 };
7
+ const px555: DCss.Px = { _unit: "px", value: 555 };
8
+ const px123: DCss.Px = { _unit: "px", value: 123 };
9
+ const px10: DCss.Px = { _unit: "px", value: 10 };
10
+ const px3: DCss.Px = { _unit: "px", value: 3 };
11
+ const px0: DCss.Px = { _unit: "px", value: 0 };
12
+ const px1: DCss.Px = { _unit: "px", value: 1 };
13
+ const scale026 = DCss.toString;
14
+ // const scale001 = DCss.toStringCreator(0.01);
15
+
16
+ expect(DCss.toString(px1300, 0.26)).toBe("338px");
17
+ expect(DCss.toString(px10, 0.26)).toBe("3px");
18
+ expect(DCss.toString(px1, 0.26)).toBe("1px");
19
+ expect(DCss.toString(px3, 0.26)).toBe("1px");
20
+ expect(DCss.toString(px0, 0.26)).toBe("0px");
21
+ expect(DCss.toString(px0, 0.26)).toBe("0px");
22
+ expect(DCss.toString(px555, 0.26)).toBe("144px");
23
+ expect(DCss.toString(px123, 0.01)).toBe("4px");
24
+ expect(DCss.toString(px1300, 0.01)).toBe("39px");
25
+ expect(DCss.isLengthUnit()).toBe(false);
26
+ expect(DCss.isLengthUnit({} as LengthUnit)).toBe(false);
27
+ expect(DCss.isLengthUnit(px123)).toBe(true);
28
+ });
29
+
30
+ test("Normalize div: ", () => {
31
+ const div = document.createElement("div");
32
+ const normalized = DStyle.normalize(div);
33
+ expect(normalized.style.padding).toBe("0px");
34
+ expect(normalized.style.boxSizing).toBe("border-box");
35
+ });
36
+
37
+ test("Can validate Length-units ", () => {
38
+ expect(DCss.isLengthUnit(0)).toBe(true);
39
+ });
40
+ });
@@ -1,46 +1,56 @@
1
- import { DUtil } from "../utils/DUtil";
2
-
3
- export namespace DCss {
4
- export interface Px {
5
- readonly _unit: "px";
6
- readonly value: number;
7
- }
8
-
9
- export type LengthString = `${number}px` | `${number}%`;
10
- export interface Percent {
11
- readonly _unit: "percent";
12
- readonly value: number;
13
- }
14
-
15
- export type LengthUnit = Px | Percent;
16
-
17
- /**
18
- * Will scale to 3% of baseScale
19
- * @param unit
20
- * @param scale
21
- */
22
- export const toString = (unit: Readonly<LengthUnit>, scale: number): LengthString => {
23
- const clampedScale = Math.max(scale, 0.03);
24
- if (unit._unit === "px") {
25
- if (unit.value < 0.1) {
26
- return "0px";
27
- }
28
-
29
- const rounded = Math.round(unit.value * clampedScale);
30
- const clamped = Math.max(rounded, 1);
31
- return (clamped + "px") as LengthString;
32
- }
33
- return (unit.value + "%") as LengthString;
34
- };
35
-
36
- export const isLengthUnit = (unit?: LengthUnit): unit is LengthUnit => {
37
- if (!unit) {
38
- return false;
39
- }
40
- const unitKey: keyof LengthUnit = "_unit";
41
- const valueKey: keyof LengthUnit = "value";
42
- const hasUnitKey = DUtil.hasKey(unit, unitKey);
43
- const hasValueKey = DUtil.hasKey(unit, valueKey);
44
- return hasUnitKey && hasValueKey;
45
- };
46
- }
1
+ import { DUtil } from "../utils/DUtil";
2
+
3
+ export namespace DCss {
4
+ export interface Px {
5
+ readonly _unit: "px";
6
+ readonly value: number;
7
+ }
8
+
9
+ export type LengthString = `${number}px` | `${number}%`;
10
+ export interface Percent {
11
+ readonly _unit: "percent";
12
+ readonly value: number;
13
+ }
14
+
15
+ export type LengthUnit = Px | Percent | number;
16
+
17
+ /**
18
+ * Will scale to 3% of baseScale
19
+ * @param unit
20
+ * @param scale
21
+ */
22
+ export const toString = (unit: Readonly<LengthUnit>, scale: number): LengthString => {
23
+ const _mapped: Percent | Px =
24
+ typeof unit === "number" ? { _unit: "percent", value: unit } : unit;
25
+ return _toString(_mapped, scale);
26
+ };
27
+ const _toString = (unit: Readonly<Percent | Px>, scale: number): LengthString => {
28
+ const clampedScale = Math.max(scale, 0.03);
29
+ if (unit._unit === "px") {
30
+ if (unit.value < 0.1) {
31
+ return "0px";
32
+ }
33
+
34
+ const rounded = Math.round(unit.value * clampedScale);
35
+ const clamped = Math.max(rounded, 1);
36
+ return (clamped + "px") as LengthString;
37
+ }
38
+ return (unit.value + "%") as LengthString;
39
+ };
40
+
41
+ export const isLengthUnit = (unit?: LengthUnit): unit is LengthUnit => {
42
+ if (typeof unit === "number") {
43
+ return true;
44
+ }
45
+
46
+ if (!unit) {
47
+ return false;
48
+ }
49
+
50
+ const unitKey: keyof DCss.Px = "_unit";
51
+ const valueKey: keyof DCss.Px = "value";
52
+ const hasUnitKey = DUtil.hasKey(unit, unitKey);
53
+ const hasValueKey = DUtil.hasKey(unit, valueKey);
54
+ return hasUnitKey && hasValueKey;
55
+ };
56
+ }
@@ -1,40 +1,49 @@
1
- import { DElement } from "./DElement";
2
- import { DDiv, DDivDto } from "./Ddiv";
3
- import { DImg } from "./DImg";
4
- import { DText } from "./DText";
5
- import { ScaleService } from "../engine/scale";
6
- import { DElementDto } from "./DElement.dto";
7
-
8
- export const createDElement = (dto: DElementDto, scale: ScaleService): DElement<any> => {
9
- switch (dto._tag) {
10
- case "div":
11
- const childEls = createChildrenForDiv(dto, scale);
12
- const newDiv = new DDiv(dto, scale, childEls);
13
- return newDiv;
14
- case "img":
15
- return new DImg(dto, scale);
16
- case "p":
17
- return new DText(dto, scale);
18
- default:
19
- const check: never = dto;
20
- throw new Error("Unknown dto given to the createDElement function.");
21
- // TODO LOGGING or create any HTML-ELEMENT??
22
- }
23
- };
24
-
25
- const createChildrenForDiv = (dto: DDivDto, scale: ScaleService): DDiv["children"] => {
26
- const childDto = dto.children;
27
- const childEls: Array<DImg | DText> = [];
28
- // console.log(childElements);
29
- childDto.forEach((dto) => {
30
- if (dto._tag === "p") {
31
- const newText = new DText(dto, scale);
32
- childEls.push(newText);
33
- }
34
- if (dto._tag === "img") {
35
- const newImage = new DImg(dto, scale);
36
- childEls.push(newImage);
37
- }
38
- });
39
- return childEls;
40
- };
1
+ import { DElement } from "./DElement";
2
+ import { DDiv, DDivDto } from "./Ddiv";
3
+ import { DImg } from "./DImg";
4
+ import { DText } from "./DText";
5
+ import { ScaleService } from "../engine/scale";
6
+ import { DElementDto } from "./DElement.dto";
7
+ import { DButton } from "./DButton";
8
+
9
+ export const createDElement = (dto: DElementDto, scale: ScaleService): DElement<any> => {
10
+ switch (dto._tag) {
11
+ case "div":
12
+ const childEls = createChildrenForDiv(dto, scale);
13
+ return new DDiv(dto, scale, childEls);
14
+ case "img":
15
+ return new DImg(dto, scale);
16
+ case "p":
17
+ return new DText(dto, scale);
18
+ case "button":
19
+ return new DButton(dto, scale);
20
+ default:
21
+ const check: never = dto;
22
+ throw new Error("Unknown dto given to the createDElement function.");
23
+ // TODO LOGGING or create any HTML-ELEMENT??
24
+ }
25
+ };
26
+
27
+ const createChildrenForDiv = (dto: DDivDto, scale: ScaleService): DDiv["children"] => {
28
+ const childDto = dto.children;
29
+ const childEls: Array<DImg | DText | DButton> = [];
30
+ childDto.forEach((dto) => {
31
+ switch (dto._tag) {
32
+ case "p":
33
+ const newText = new DText(dto, scale);
34
+ childEls.push(newText);
35
+ break;
36
+ case "img":
37
+ const newImage = new DImg(dto, scale);
38
+ childEls.push(newImage);
39
+ break;
40
+ case "button":
41
+ const newButton = new DButton(dto, scale);
42
+ childEls.push(newButton);
43
+ break;
44
+ default:
45
+ const check: never = dto;
46
+ }
47
+ });
48
+ return childEls;
49
+ };
@@ -1,150 +1,155 @@
1
- import { SchemaDto } from "./SchemaDto";
2
- import { DPlayer } from "./dplayer";
3
- import { ScaleService } from "./scale";
4
- import { Page } from "../page/Page";
5
- import { TaskManager } from "../page/task-manager";
6
- import { PageResult } from "../page/page-result";
7
- import { SchemaResult } from "./SchemaResult";
8
- export interface EngineLogger {
9
- info(message: string): void;
10
- error(message: string): void;
11
- warn(message: string): void;
12
- }
13
-
14
- const voidLogger: EngineLogger = {
15
- info: (message: string) => {},
16
- error: (message: string) => {},
17
- warn: (message: string) => {},
18
- };
19
-
20
- export interface ISchemaEngine {
21
- onProgress(handler: (result: SchemaResult) => void): void;
22
- onFatalError(handler: (error: { message: string }) => void): void;
23
- setLogger(logger: EngineLogger): void;
24
- }
25
-
26
- export class SchemaEngine implements ISchemaEngine {
27
- private readonly TAG = "[ SCHEMA_ENGINE ] :";
28
- private readonly scale: ScaleService;
29
- private readonly hostElement: HTMLDivElement;
30
- private readonly taskManager: TaskManager;
31
- private logger: EngineLogger = voidLogger;
32
- private readonly uiLayer: HTMLDivElement = document.createElement("div");
33
- private readonly mediaLayer: HTMLDivElement = document.createElement("div");
34
- private player: DPlayer;
35
- private currentPage: Page | false = false;
36
- private readonly tickerRef: number | false = false;
37
- constructor(
38
- hostEl: HTMLDivElement,
39
- private readonly height: number,
40
- private readonly width: number,
41
- private readonly schema: SchemaDto,
42
- ) {
43
- this.tickerRef = window.setInterval(() => {
44
- if (this.currentPage) {
45
- this.currentPage.tick();
46
- }
47
- }, 100);
48
- this.hostElement = hostEl;
49
- this.hostElement.appendChild(this.mediaLayer);
50
- this.hostElement.appendChild(this.uiLayer);
51
- this.scale = new ScaleService({
52
- baseHeight: schema.baseHeight,
53
- baseWidth: schema.baseWidth,
54
- containerWidth: width,
55
- containerHeight: height,
56
- });
57
- this.logger.info(this.TAG + "Scale: " + JSON.stringify(this.scale));
58
- this.player = new DPlayer(this.schema);
59
- this.taskManager = new TaskManager(this.mediaLayer, this.scale, (error) => {
60
- console.log(error);
61
- });
62
-
63
- this.styleSelf();
64
- this.handlePageCompleted = this.handlePageCompleted.bind(this);
65
- this.nextPage();
66
- }
67
-
68
- private handlePageCompleted(result: PageResult) {
69
- // 1 Save data from last page
70
- this.player.saveHistory(result);
71
-
72
- // 2 Emit progress
73
- const currentResults = this.player.getResults();
74
- const a: SchemaResult = {
75
- schemaId: this.schema.id,
76
- pagesLeft: currentResults.pagesLeft,
77
- predefinedFacts: currentResults.predefinedFacts,
78
- eventLog: currentResults.eventLog,
79
- answers: currentResults.answerFacts,
80
- };
81
- if (this._onProgress) {
82
- this._onProgress(a);
83
- }
84
-
85
- // 3. Next page
86
- this.nextPage();
87
- }
88
-
89
- private styleSelf() {
90
- this.hostElement.style.height = this.scale.pageHeight + "px";
91
- this.hostElement.style.width = this.scale.pageWidth + "px";
92
- this.hostElement.style.backgroundColor = this.schema.backgroundColor ?? "white";
93
- this.hostElement.style.position = "relative";
94
- // this.hostElement.style.overflow = "hidden";
95
- const makeStatic = (div: HTMLDivElement) => {
96
- div.style.height = "0px";
97
- div.style.width = "0px";
98
- div.style.position = "static";
99
- };
100
-
101
- makeStatic(this.uiLayer);
102
- this.uiLayer.style.zIndex = "10";
103
- this.mediaLayer.style.zIndex = "8";
104
- makeStatic(this.mediaLayer);
105
- }
106
-
107
- private nextPage() {
108
- const nextPage = this.player.getNextPage();
109
- if (this.currentPage) {
110
- this.currentPage.destroy();
111
- this.uiLayer.innerHTML = "";
112
- }
113
-
114
- if (!nextPage) {
115
- // TODO FIGURE OUT WHAQT TO DO AT END OF TEST!! Start over??
116
- this.player = new DPlayer(this.schema);
117
- if (this.player.pagesLeft > 0) {
118
- this.nextPage();
119
- }
120
- return false;
121
- }
122
-
123
- const newPage = new Page(nextPage, this.taskManager, this.scale, (result) => {
124
- this.handlePageCompleted(result);
125
- });
126
- this.currentPage = newPage;
127
- newPage.appendYourself(this.uiLayer);
128
- return true;
129
- }
130
-
131
- destroy() {
132
- if (this.currentPage) {
133
- this.currentPage.destroy();
134
- this.uiLayer.innerHTML = "";
135
- }
136
- }
137
-
138
- private _onProgress: ((result: SchemaResult) => void) | false = false;
139
- onProgress(handler: (result: SchemaResult) => void) {
140
- this._onProgress = handler;
141
- }
142
-
143
- private _onFatalError: ((error: { message: string }) => void) | false = false;
144
- onFatalError(handler: (error: { message: string }) => void): void {
145
- this._onFatalError = handler;
146
- }
147
- setLogger(logger: EngineLogger) {
148
- this.logger = logger;
149
- }
150
- }
1
+ import { SchemaDto } from "./SchemaDto";
2
+ import { DPlayer } from "./dplayer";
3
+ import { ScaleService } from "./scale";
4
+ import { Page } from "../page/Page";
5
+ import { TaskManager } from "../page/task-manager";
6
+ import { PageResult } from "../page/page-result";
7
+ import { SchemaResult } from "./SchemaResult";
8
+ export interface EngineLogger {
9
+ info(message: string): void;
10
+ error(message: string): void;
11
+ warn(message: string): void;
12
+ }
13
+
14
+ const voidLogger: EngineLogger = {
15
+ info: (message: string) => {},
16
+ error: (message: string) => {},
17
+ warn: (message: string) => {},
18
+ };
19
+
20
+ export interface ISchemaEngine {
21
+ onProgress(handler: (result: SchemaResult) => void): void;
22
+ onFatalError(handler: (error: { message: string }) => void): void;
23
+ setLogger(logger: EngineLogger): void;
24
+ }
25
+
26
+ export class SchemaEngine implements ISchemaEngine {
27
+ private readonly TAG = "[ SCHEMA_ENGINE ] :";
28
+ private readonly scale: ScaleService;
29
+ private readonly hostElement: HTMLDivElement;
30
+ private readonly taskManager: TaskManager;
31
+ private logger: EngineLogger = voidLogger;
32
+ private readonly uiLayer: HTMLDivElement = document.createElement("div");
33
+ private readonly mediaLayer: HTMLDivElement = document.createElement("div");
34
+ private player: DPlayer;
35
+ private currentPage: Page | false = false;
36
+ private readonly tickerRef: number | false = false;
37
+ constructor(
38
+ hostEl: HTMLDivElement,
39
+ private readonly height: number,
40
+ private readonly width: number,
41
+ private readonly schema: SchemaDto,
42
+ ) {
43
+ this.tickerRef = window.setInterval(() => {
44
+ if (this.currentPage) {
45
+ this.currentPage.tick();
46
+ }
47
+ }, 100);
48
+ this.hostElement = hostEl;
49
+ this.hostElement.appendChild(this.mediaLayer);
50
+ this.hostElement.appendChild(this.uiLayer);
51
+ this.scale = new ScaleService({
52
+ baseHeight: schema.baseHeight,
53
+ baseWidth: schema.baseWidth,
54
+ containerWidth: this.width,
55
+ containerHeight: this.height,
56
+ });
57
+ this.logger.info(this.TAG + "Scale: " + JSON.stringify(this.scale));
58
+ this.player = new DPlayer(this.schema);
59
+ this.taskManager = new TaskManager(this.mediaLayer, this.scale, (error) => {
60
+ console.log(error);
61
+ });
62
+
63
+ this.styleSelf();
64
+ this.handlePageCompleted = this.handlePageCompleted.bind(this);
65
+ this.nextPage();
66
+ }
67
+
68
+ private handlePageCompleted(result: PageResult) {
69
+ // 1 Save data from last page
70
+ this.player.saveHistory(result);
71
+
72
+ // 2 Emit progress
73
+ const currentResults = this.player.getResults();
74
+ const a: SchemaResult = {
75
+ schemaId: this.schema.id,
76
+ pagesLeft: currentResults.pagesLeft,
77
+ predefinedFacts: currentResults.predefinedFacts,
78
+ eventLog: currentResults.eventLog,
79
+ answers: currentResults.answerFacts,
80
+ };
81
+ if (this._onProgress) {
82
+ this._onProgress(a);
83
+ }
84
+
85
+ // 3. Next page
86
+ this.nextPage();
87
+ }
88
+
89
+ private styleSelf() {
90
+ this.hostElement.style.height = this.scale.pageHeight + "px";
91
+ this.hostElement.style.width = this.scale.pageWidth + "px";
92
+ this.hostElement.style.backgroundColor = this.schema.backgroundColor ?? "white";
93
+ this.hostElement.style.position = "relative";
94
+ // this.hostElement.style.overflow = "hidden";
95
+ const makeStatic = (div: HTMLDivElement) => {
96
+ div.style.height = "0px";
97
+ div.style.width = "0px";
98
+ div.style.position = "static";
99
+ };
100
+
101
+ makeStatic(this.uiLayer);
102
+ this.uiLayer.style.zIndex = "10";
103
+ this.mediaLayer.style.zIndex = "8";
104
+ makeStatic(this.mediaLayer);
105
+ }
106
+
107
+ private nextPage() {
108
+ const nextPage = this.player.getNextPage();
109
+ if (this.currentPage) {
110
+ this.currentPage.destroy();
111
+ this.uiLayer.innerHTML = "";
112
+ }
113
+
114
+ // console.log(nextPage);
115
+ if (nextPage && nextPage.videoPlayer && nextPage.videoPlayer.style) {
116
+ this.taskManager.setVideoStyles(nextPage.videoPlayer.style);
117
+ }
118
+
119
+ if (!nextPage) {
120
+ // TODO FIGURE OUT WHAQT TO DO AT END OF TEST!! Start over??
121
+ this.player = new DPlayer(this.schema);
122
+ if (this.player.pagesLeft > 0) {
123
+ this.nextPage();
124
+ }
125
+ return false;
126
+ }
127
+
128
+ const newPage = new Page(nextPage, this.taskManager, this.scale, (result) => {
129
+ this.handlePageCompleted(result);
130
+ });
131
+ this.currentPage = newPage;
132
+ newPage.appendYourself(this.uiLayer);
133
+ return true;
134
+ }
135
+
136
+ destroy() {
137
+ if (this.currentPage) {
138
+ this.currentPage.destroy();
139
+ this.uiLayer.innerHTML = "";
140
+ }
141
+ }
142
+
143
+ private _onProgress: ((result: SchemaResult) => void) | false = false;
144
+ onProgress(handler: (result: SchemaResult) => void) {
145
+ this._onProgress = handler;
146
+ }
147
+
148
+ private _onFatalError: ((error: { message: string }) => void) | false = false;
149
+ onFatalError(handler: (error: { message: string }) => void): void {
150
+ this._onFatalError = handler;
151
+ }
152
+ setLogger(logger: EngineLogger) {
153
+ this.logger = logger;
154
+ }
155
+ }