@netless/forge-slide 0.1.1-alpha.0 → 0.1.1-alpha.10

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,13 +1,12 @@
1
- import {Whiteboard, WhiteboardApplication, WhiteboardPermissionFlag} from "@netless/forge-whiteboard";
2
- import {ISlideConfig, Slide, SLIDE_EVENTS} from "@netless/slide";
3
- import {AbstractApplication} from "@netless/forge-room";
4
- import {SlideForge} from "./Slide";
5
- import {ForgeSlidePermissionFlag, ForgeSlidePermissions} from "./ForgeSlidePermession";
6
- import {FooterView} from "./FoorerView";
7
- import * as Y from "yjs";
8
- import {SideBarView} from "./SiderBarView";
9
- import {deepEqual, delay} from "./utils";
10
- import { kvStore } from "@netless/forge-room";
1
+ import { Whiteboard, WhiteboardApplication, WhiteboardPermissionFlag } from '@netless/forge-whiteboard';
2
+ import { ISlideConfig, Slide, SLIDE_EVENTS } from '@netless/slide';
3
+ import { AbstractApplication, kvStore } from '@netless/forge-room';
4
+ import { SlideForge } from './Slide';
5
+ import { ForgeSlidePermissionFlag, ForgeSlidePermissions } from './ForgeSlidePermession';
6
+ import { FooterView } from './FooterView';
7
+ import * as Y from 'yjs';
8
+ import { SideBarView } from './SiderBarView';
9
+ import { deepEqual } from './utils';
11
10
 
12
11
  export interface SlideApplicationOption {
13
12
  prefix: string;
@@ -26,437 +25,550 @@ interface PreviewImage {
26
25
  height: number;
27
26
  }
28
27
 
29
- export const Slide_APP_NAME = "forge_slide";
28
+ export const Slide_APP_NAME = 'forge_slide';
30
29
 
31
30
  export class SlideApplication extends AbstractApplication<SlideApplicationOption, SlideForge> {
32
31
 
33
- static applicationName = Slide_APP_NAME;
34
-
35
- public readonly name: string = Slide_APP_NAME;
36
- public readonly emitter: SlideForge = new SlideForge();
37
-
38
- private whiteboardApp!: WhiteboardApplication;
39
- private whiteboard!: Whiteboard;
40
- private rootView: HTMLDivElement = document.createElement("div");
41
- private contentContainer: HTMLDivElement = document.createElement("div");
42
- private whiteboardContainer: HTMLDivElement = document.createElement("div");
43
- private slideContainer: HTMLDivElement = document.createElement("div");
44
- private permissions!: ForgeSlidePermissions;
45
- private footer: FooterView;
46
- private sideBar: SideBarView;
47
- private slide!: Slide;
48
- private currentSlideIndex: number = 0;
49
- private taskId: string = "";
50
- private prefix: string = "";
51
-
52
- constructor() {
53
- super();
54
- (window as any).emitter = this.emitter;
55
- this.rootView.setAttribute("data-forge-app", Slide_APP_NAME);
56
- this.rootView.style.background = "#f0f0f0f0";
57
- this.rootView.style.overflow = "hidden";
58
-
59
- this.contentContainer.style.width = "100%";
60
- this.contentContainer.style.height = "100%";
61
- this.contentContainer.style.display = "flex";
62
- this.contentContainer.style.flexDirection = "column";
63
-
64
- this.slideContainer.style.width = "100%";
65
- this.slideContainer.style.height = "100%";
66
- // this.slideContainer.style.height = "calc(100% - 24px)";
67
-
68
- this.footer = new FooterView();
69
- this.sideBar = new SideBarView();
70
- this.sideBar.on("pageChange", index => {
71
- if (index > 0 && index <= this.slide.slideCount) {
72
- this.slide.renderSlide(index);
73
- }
74
- });
75
- this.footer.on("prevStep", () => {
76
- if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changeStep)) {
77
- return;
78
- }
79
- if (this.slide.mainSeqStep > 0 || this.slide.mainSeqState !== "idle") {
80
- this.slide.prevStep();
81
- } else if (this.currentSlideIndex > 1){
82
- if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
83
- return;
84
- }
85
- this.slide.renderSlide(this.currentSlideIndex - 1)
86
- }
87
- });
88
- this.footer.on("nextStep", () => {
89
- if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changeStep)) {
90
- return;
91
- }
92
- if (this.slide.mainSeqStep < this.slide.mainSeqLength) {
93
- this.slide.nextStep()
94
- } else {
95
- if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
96
- return;
97
- }
98
- this.slide.renderSlide(this.currentSlideIndex + 1)
99
- }
100
- });
101
- this.footer.on("prevPage", () => {
102
- if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
103
- return;
104
- }
105
- if (this.currentSlideIndex > 1) {
106
- this.slide.renderSlide(this.currentSlideIndex - 1);
107
- }
108
- });
109
- this.footer.on("nextPage", () => {
110
- if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
111
- return;
112
- }
113
- if (this.currentSlideIndex < this.slide.slideCount) {
114
- this.slide.renderSlide(this.currentSlideIndex + 1);
115
- }
116
- });
117
-
118
- this.footer.on("sideBarToggle", () => {
119
- if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
120
- return;
121
- }
122
- if (this.sideBar.root.style.left === "0px") {
123
- this.sideBar.root.style.left = "-240px";
124
- } else {
125
- this.sideBar.root.style.left = "0px";
126
- }
127
- })
128
-
129
- this.rootView.appendChild(this.contentContainer);
130
-
131
- this.permissions.on("change", (userId, flags, value) => {
132
- this.emitter.emit("permissionChange", userId, flags, value);
133
- })
134
-
135
- this.emitter.on("renderStart", pageIndex => {
136
- this.footer.prevPageState(pageIndex !== 0);
137
- });
138
-
139
- const that = this;
140
- Object.defineProperty(this.emitter, "view", {
141
- get(): any {
142
- return that.rootView;
143
- }
144
- });
145
- Object.defineProperty(this.emitter, "permissions", {
146
- get(): any {
147
- return that.permissions;
148
- }
149
- });
150
- Object.defineProperty(this.emitter, "footView", {
151
- get(): any {
152
- return that.footer.root;
153
- }
154
- })
155
- Object.defineProperty(this.emitter, "pageIndex", {
156
- get(): any {
157
- return that.currentSlideIndex;
158
- }
159
- });
160
- Object.defineProperty(this.emitter, "pageCount", {
161
- get(): any {
162
- return that.slide.slideCount;
163
- }
164
- });
165
- Object.defineProperty(this.emitter, "goto", {
166
- writable: false,
167
- enumerable: false,
168
- value: (pageIndex: number) => {
169
- this.sideBar.emit("pageChange", pageIndex);
170
- }
171
- });
172
- Object.defineProperty(this.emitter, "nextStep", {
173
- writable: false,
174
- enumerable: false,
175
- value: () => {
176
- this.footer.emit("nextStep");
177
- }
178
- })
179
- Object.defineProperty(this.emitter, "prevStep", {
180
- writable: false,
181
- enumerable: false,
182
- value: () => {
183
- this.footer.emit("prevStep");
184
- }
185
- })
186
- Object.defineProperty(this.emitter, "nextPage", {
187
- writable: false,
188
- enumerable: false,
189
- value: () => {
190
- this.footer.emit("nextPage");
191
- }
192
- })
193
- Object.defineProperty(this.emitter, "prevPage", {
194
- writable: false,
195
- enumerable: false,
196
- value: () => {
197
- this.footer.emit("prevPage");
198
- }
199
- })
200
- Object.defineProperty(this.emitter, "sideBarToggle", {
201
- writable: false,
202
- enumerable: false,
203
- value: () => {
204
- this.footer.emit("sideBarToggle");
205
- }
206
- })
207
- Object.defineProperty(this.emitter, "imgContent", {
208
- writable: false,
209
- enumerable: false,
210
- value: (pageIndex: number) => {
211
- return this.getImageContent(pageIndex);
212
- }
213
- })
214
-
215
- Object.defineProperty(this.emitter, "imgUrl", {
216
- writable: false,
217
- enumerable: false,
218
- value: (pageIndex: number) => {
219
- return this.getImageUrl(pageIndex);
220
- }
221
- })
222
-
223
- Object.defineProperty(this.emitter, "imgSize", {
224
- writable: false,
225
- enumerable: false,
226
- value: (pageIndex: number) => {
227
- return this.getImageSize(pageIndex);
228
- }
229
- })
32
+ static applicationName = Slide_APP_NAME;
33
+
34
+ public readonly name: string = Slide_APP_NAME;
35
+ public readonly emitter: SlideForge = new SlideForge();
36
+
37
+ private whiteboardApp!: WhiteboardApplication;
38
+ private whiteboard!: Whiteboard;
39
+ private rootView: HTMLDivElement = document.createElement('div');
40
+ private contentContainer: HTMLDivElement = document.createElement('div');
41
+ private whiteboardContainer: HTMLDivElement = document.createElement('div');
42
+ private slideContainer: HTMLDivElement = document.createElement('div');
43
+ private permissions!: ForgeSlidePermissions;
44
+ private footer: FooterView;
45
+ private sideBar: SideBarView;
46
+ private slide!: Slide;
47
+ private currentSlideIndex: number = 0;
48
+ private taskId: string = '';
49
+ private prefix: string = '';
50
+ private slideCount: number = 0;
51
+ private lastDispatchUuid: string = '';
52
+ private syncMessageQueue: { state: any, dispatch: any }[] = [];
53
+ private isSyncing: boolean = false;
54
+
55
+ constructor() {
56
+ super();
57
+ (window as any).emitter = this.emitter;
58
+ this.rootView.setAttribute('data-forge-app', Slide_APP_NAME);
59
+ this.rootView.style.background = '#f0f0f0f0';
60
+ this.rootView.style.overflow = 'hidden';
61
+
62
+ this.contentContainer.style.width = '100%';
63
+ this.contentContainer.style.height = '100%';
64
+ this.contentContainer.style.display = 'flex';
65
+ this.contentContainer.style.flexDirection = 'column';
66
+
67
+ this.slideContainer.style.width = '100%';
68
+ this.slideContainer.style.height = '100%';
69
+
70
+ this.footer = new FooterView();
71
+ this.sideBar = new SideBarView();
72
+ this.sideBar.on('pageChange', index => {
73
+ if (index > 0 && index <= this.slideCount) {
74
+ this.slide.renderSlide(index);
75
+ }
76
+ });
77
+ this.footer.on('prevStep', () => {
78
+ if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changeStep)) {
79
+ return;
80
+ }
81
+ if (this.slide.mainSeqStep > 0 || this.slide.mainSeqState !== 'idle') {
82
+ this.slide.prevStep();
83
+ } else if (this.currentSlideIndex > 1){
84
+ if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
85
+ return;
86
+ }
87
+ this.slide.renderSlide(this.currentSlideIndex - 1);
88
+ }
89
+ });
90
+ this.footer.on('nextStep', () => {
91
+ if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changeStep)) {
92
+ return;
93
+ }
94
+ if (this.slide.mainSeqStep < this.slide.mainSeqLength) {
95
+ this.slide.nextStep();
96
+ } else {
97
+ if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
98
+ return;
99
+ }
100
+ this.slide.renderSlide(this.currentSlideIndex + 1);
101
+ }
102
+ });
103
+ this.footer.on('prevPage', () => {
104
+ if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
105
+ return;
106
+ }
107
+ if (this.currentSlideIndex > 1) {
108
+ this.slide.renderSlide(this.currentSlideIndex - 1);
109
+ }
110
+ });
111
+ this.footer.on('nextPage', () => {
112
+ if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
113
+ return;
114
+ }
115
+ if (this.currentSlideIndex < this.slideCount) {
116
+ this.slide.renderSlide(this.currentSlideIndex + 1);
117
+ }
118
+ });
119
+ this.footer.on('sideBarToggle', () => {
120
+ if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
121
+ return;
122
+ }
123
+ if (this.sideBar.isShowSideBar) {
124
+ this.sideBar.hidden();
125
+ } else {
126
+ this.sideBar.show();
127
+ }
128
+ });
129
+
130
+ this.rootView.appendChild(this.contentContainer);
131
+
132
+ this.emitter.on('renderStart', pageIndex => {
133
+ this.footer.prevPageState(pageIndex !== 0);
134
+ });
135
+
136
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
137
+ const that = this;
138
+ Object.defineProperty(this.emitter, 'view', {
139
+ get(): any {
140
+ return that.rootView;
141
+ },
142
+ });
143
+ Object.defineProperty(this.emitter, 'permissions', {
144
+ get(): any {
145
+ return that.permissions;
146
+ },
147
+ });
148
+ Object.defineProperty(this.emitter, 'footView', {
149
+ get(): any {
150
+ return that.footer.root;
151
+ },
152
+ });
153
+ Object.defineProperty(this.emitter, 'sidebarView', {
154
+ get(): any {
155
+ return that.sideBar.root;
156
+ },
157
+ });
158
+ Object.defineProperty(this.emitter, 'pageIndex', {
159
+ get(): any {
160
+ return that.currentSlideIndex;
161
+ },
162
+ });
163
+ Object.defineProperty(this.emitter, 'pageCount', {
164
+ get(): any {
165
+ return that.slideCount;
166
+ },
167
+ });
168
+ Object.defineProperty(this.emitter, 'goto', {
169
+ writable: false,
170
+ enumerable: false,
171
+ value: (pageIndex: number) => {
172
+ this.sideBar.emit('pageChange', pageIndex);
173
+ },
174
+ });
175
+ Object.defineProperty(this.emitter, 'nextStep', {
176
+ writable: false,
177
+ enumerable: false,
178
+ value: () => {
179
+ this.footer.emit('nextStep');
180
+ },
181
+ });
182
+ Object.defineProperty(this.emitter, 'prevStep', {
183
+ writable: false,
184
+ enumerable: false,
185
+ value: () => {
186
+ this.footer.emit('prevStep');
187
+ },
188
+ });
189
+ Object.defineProperty(this.emitter, 'nextPage', {
190
+ writable: false,
191
+ enumerable: false,
192
+ value: () => {
193
+ this.footer.emit('nextPage');
194
+ },
195
+ });
196
+ Object.defineProperty(this.emitter, 'prevPage', {
197
+ writable: false,
198
+ enumerable: false,
199
+ value: () => {
200
+ this.footer.emit('prevPage');
201
+ },
202
+ });
203
+ Object.defineProperty(this.emitter, 'sideBarToggle', {
204
+ writable: false,
205
+ enumerable: false,
206
+ value: () => {
207
+ this.footer.emit('sideBarToggle');
208
+ },
209
+ });
210
+ Object.defineProperty(this.emitter, 'imgContent', {
211
+ writable: false,
212
+ enumerable: false,
213
+ value: (pageIndex: number) => {
214
+ return this.getImageContent(pageIndex);
215
+ },
216
+ });
217
+ Object.defineProperty(this.emitter, 'imgUrl', {
218
+ writable: false,
219
+ enumerable: false,
220
+ value: (pageIndex: number) => {
221
+ return this.getImageUrl(pageIndex);
222
+ },
223
+ });
224
+ Object.defineProperty(this.emitter, 'imgSize', {
225
+ writable: false,
226
+ enumerable: false,
227
+ value: (pageIndex: number) => {
228
+ return this.getImageSize(pageIndex);
229
+ },
230
+ });
231
+ this.applySlideState();
232
+ }
233
+
234
+ private getPreviewImageUrl (pageIndex: number) {
235
+ if (pageIndex < 1 || pageIndex > this.slideCount) {
236
+ throw new Error('pageIndex out of range');
230
237
  }
231
-
232
- private async getPreviewImage(imageUrl: string) {
233
- const image = fetch(imageUrl);
234
- return await image.then(res => res.blob()).then(blob => {
235
- return new Promise<PreviewImage>(resolve => {
236
- const reader = new FileReader();
237
- reader.onloadend = () => {
238
- const base64Data = reader.result as string;
239
- const img = document.createElement("img");
240
- img.src = base64Data;
241
- img.onload = () => {
242
- resolve({
243
- url: imageUrl,
244
- src: base64Data,
245
- width: img.width,
246
- height: img.height,
247
- });
248
- }
249
- }
250
- reader.readAsDataURL(blob);
251
- })
252
- });
238
+ return `${this.prefix}/${this.taskId}/preview/${pageIndex}.png`;
239
+ }
240
+
241
+ private async getPreviewImage(imageUrl: string) {
242
+ const image = fetch(imageUrl);
243
+ return await image.then(res => res.blob()).then(blob => {
244
+ return new Promise<PreviewImage>(resolve => {
245
+ const reader = new FileReader();
246
+ reader.onloadend = () => {
247
+ const base64Data = reader.result as string;
248
+ const img = document.createElement('img');
249
+ img.src = base64Data;
250
+ img.onload = () => {
251
+ resolve({
252
+ url: imageUrl,
253
+ src: base64Data,
254
+ width: img.width,
255
+ height: img.height,
256
+ });
257
+ };
258
+ };
259
+ reader.readAsDataURL(blob);
260
+ });
261
+ });
262
+ }
263
+
264
+ private async getImageUrl(pageIndex: number) {
265
+ return this.getPreviewImageUrl(pageIndex);
266
+ }
267
+
268
+ private async getImageSize(pageIndex: number) {
269
+ const imageUrl = this.getPreviewImageUrl(pageIndex);
270
+ let preview: PreviewImage | null = null;
271
+ try {
272
+ const result = await kvStore.getItem(imageUrl);
273
+ preview = result ? JSON.parse(result) : null;
274
+ } catch (e) {
275
+ console.warn('kvStore getItem error', e);
253
276
  }
254
-
255
- private async getImageUrl(pageIndex: number) {
256
- return `${this.prefix}/${this.taskId}/preview/${pageIndex + 1}.png`;
277
+ if (preview) {
278
+ return { width: preview.width, height: preview.height };
279
+ }
280
+ preview = await this.getPreviewImage(imageUrl);
281
+ await kvStore.setItem(imageUrl, JSON.stringify(preview));
282
+ return { width: preview.width, height: preview.height };
283
+ }
284
+
285
+ private async getImageContent(pageIndex: number) {
286
+ const imageUrl = this.getPreviewImageUrl(pageIndex);
287
+ let preview: PreviewImage | null = null;
288
+ try {
289
+ const result = await kvStore.getItem(imageUrl);
290
+ preview = result ? JSON.parse(result) : null;
291
+ } catch (e) {
292
+ console.warn('kvStore getItem error', e);
293
+ }
294
+ if (preview) {
295
+ return preview.src;
296
+ }
297
+ preview = await this.getPreviewImage(imageUrl);
298
+ await kvStore.setItem(imageUrl, JSON.stringify(preview));
299
+ return preview.src;
300
+ }
301
+
302
+ private nextTick = () => {
303
+ this.isSyncing = false;
304
+ requestAnimationFrame(() => {
305
+ this.applySlideState().catch((error) => {
306
+ console.error('Error in applySlideState:', error);
307
+ });
308
+ });
309
+ };
310
+
311
+ private applySlideState = async () => {
312
+ if (this.isSyncing) {
313
+ return;
257
314
  }
258
315
 
259
- private async getImageSize(pageIndex: number) {
260
- const imageUrl = `${this.prefix}/${this.taskId}/preview/${pageIndex + 1}.png`;
261
- let preview: PreviewImage | null = null;
262
- try {
263
- const result = await kvStore.getItem(imageUrl);
264
- preview = result ? JSON.parse(result) : null;
265
- } catch (e) {
266
- console.warn("kvStore getItem error", e);
267
- }
268
- if (preview) {
269
- return { width: preview.width, height: preview.height };
270
- }
271
- preview = await this.getPreviewImage(imageUrl);
272
- await kvStore.setItem(imageUrl, JSON.stringify(preview));
273
- return { width: preview.width, height: preview.height };
316
+ const lastSyncMessage = this.syncMessageQueue.pop();
317
+ if (!lastSyncMessage) {
318
+ return this.nextTick();
274
319
  }
275
320
 
276
- private async getImageContent(pageIndex: number) {
277
- const imageUrl = `${this.prefix}/${this.taskId}/preview/${pageIndex + 1}.png`;
278
- let preview: PreviewImage | null = null;
279
- try {
280
- const result = await kvStore.getItem(imageUrl);
281
- preview = result ? JSON.parse(result) : null;
282
- } catch (e) {
283
- console.warn("kvStore getItem error", e);
284
- }
285
- if (preview) {
286
- return preview.src;
287
- }
288
- preview = await this.getPreviewImage(imageUrl);
289
- await kvStore.setItem(imageUrl, JSON.stringify(preview));
290
- return preview.src;
321
+ this.syncMessageQueue = [];
322
+ this.isSyncing = true;
323
+ const { state, dispatch } = lastSyncMessage;
324
+ if (this.slide.slideState.currentSlideIndex < 0) {
325
+ // @ts-ignore
326
+ await this.slide.receiveSyncHandler(dispatch);
327
+ return this.nextTick();
328
+ } else if (!deepEqual(this.slide.slideState, state)) {
329
+ await this.slide.setSlideState(state);
330
+ // @ts-ignore
331
+ await this.slide.receiveSyncHandler(dispatch);
332
+ } else {
333
+ this.slide.emit(SLIDE_EVENTS.syncReceive, dispatch);
291
334
  }
335
+ return this.nextTick();
292
336
 
293
- private applySlideState = async (slideState: any, lastDispatch: any) => {
294
- if (this.slide.slideState.currentSlideIndex < 0) {
295
- this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
337
+ };
338
+
339
+ private onSlideEventHandler = async (event: Y.YMapEvent<any>) => {
340
+ for (const [key, value] of event.changes.keys.entries()) {
341
+ if (key === 'syncSlide') {
342
+ if (value.action === 'add' || value.action === 'update') {
343
+ const { slideState: slideStateFromServer, dispatch: dispatchFromServer } = this.getMap(this.name).get('syncSlide');
344
+ if (this.lastDispatchUuid === dispatchFromServer.uuid) {
296
345
  return;
346
+ }
347
+ this.lastDispatchUuid = dispatchFromServer.uuid;
348
+ this.syncMessageQueue.push({
349
+ state: slideStateFromServer,
350
+ dispatch: dispatchFromServer,
351
+ });
352
+ this.applySlideState();
297
353
  }
298
- if (this.slide.slideState.currentSlideIndex > 0 && deepEqual(this.slide.slideState, slideState)) {
299
- this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
300
- } else {
301
- await this.slide.setSlideState(slideState);
302
- await delay(200);
303
- this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
304
- }
354
+ }
305
355
  }
306
-
307
- private onSlideEventHandler = async (event: Y.YMapEvent<any>) => {
308
- for (const [key, value] of event.changes.keys.entries()) {
309
- if (key === "syncSlide") {
310
- if (value.action === "add" || value.action === "update") {
311
- const { slideState: slideStateFromServer, dispatch: dispatchFromServer } = this.getMap(this.name).get("syncSlide");
312
- this.applySlideState(slideStateFromServer, dispatchFromServer);
313
- }
314
- }
315
- }
356
+ };
357
+
358
+ private keyBoardEvents = (event: KeyboardEvent) => {
359
+ if (event.key === 'ArrowLeft') {
360
+ this.footer.emit('prevStep');
361
+ } else if (event.key === 'ArrowRight') {
362
+ this.footer.emit('nextStep');
363
+ } else if (event.key === 'ArrowUp') {
364
+ this.footer.emit('prevPage');
365
+ } else if (event.key === 'ArrowDown') {
366
+ this.footer.emit('nextPage');
367
+ }
368
+ };
369
+
370
+ private bindKeyBoardEvent() {
371
+ document.addEventListener('keydown', this.keyBoardEvents);
372
+ }
373
+
374
+ private unbindKeyBoardEvent() {
375
+ document.removeEventListener('keydown', this.keyBoardEvents);
376
+ }
377
+
378
+ private async onFocusInstance() {
379
+ this.bindKeyBoardEvent();
380
+ // await slidePool.active(this.appId, this.slide);
381
+ }
382
+
383
+ private onRefocusInstance() {
384
+ this.unbindKeyBoardEvent();
385
+ }
386
+
387
+
388
+ public async initialize(option: SlideApplicationOption): Promise<void> {
389
+ this.prefix = option.prefix;
390
+ this.taskId = option.taskId;
391
+ const whiteboardApp = new WhiteboardApplication();
392
+ // @ts-ignore
393
+ whiteboardApp.roomDoc = this.roomDoc;
394
+ // @ts-ignore
395
+ whiteboardApp.appId = `${option.taskId}_${this.appId}_wb`;
396
+ // @ts-ignore
397
+ whiteboardApp.userId = this.userId;
398
+ // @ts-ignore
399
+ whiteboardApp.userManager = this.userManager;
400
+ // @ts-ignore
401
+ whiteboardApp.applicationManager = this.applicationManager;
402
+
403
+ const json = await fetch(`${option.prefix}/${option.taskId}/jsonOutput/slide-1.json`).then(res => res.json());
404
+ this.slideCount = json.slideCount;
405
+ await whiteboardApp.initialize({
406
+ width: json.width,
407
+ height: json.height,
408
+ });
409
+ this.whiteboardApp = whiteboardApp;
410
+ this.whiteboard = whiteboardApp.emitter;
411
+ this.whiteboard.enableCameraByMouse = false;
412
+ this.whiteboard.enableCameraByTouch = false;
413
+ this.whiteboard.view.style.width = '100%';
414
+ this.whiteboard.view.style.height = '100%';
415
+ this.whiteboard.view.style.position = 'absolute';
416
+ this.whiteboard.view.style.top = '0';
417
+ this.whiteboard.view.style.left = '0';
418
+ this.whiteboard.view.style.zIndex = '4';
419
+ this.whiteboard.view.classList.add('slide-whiteboard');
420
+ this.whiteboard.permissions.addPermission(WhiteboardPermissionFlag.all);
421
+ this.whiteboard.setCanvasBackgroundColor('#f0f0f000');
422
+ this.whiteboardContainer.style.position = 'relative';
423
+ this.whiteboardContainer.style.flex = '0 0 auto';
424
+ this.whiteboardContainer.style.height = 'calc(100% - 24px)';
425
+ this.whiteboardContainer.classList.add('forge-slide-whiteboard-container');
426
+ this.whiteboardContainer.appendChild(this.whiteboard.view);
427
+ this.whiteboardContainer.appendChild(this.slideContainer);
428
+
429
+ this.contentContainer.appendChild(this.whiteboardContainer);
430
+ this.contentContainer.appendChild(this.footer.root);
431
+ this.contentContainer.appendChild(this.sideBar.root);
432
+
433
+ if (option.inheritWhiteboardId) {
434
+ whiteboardApp.linkToWhiteboard(option.inheritWhiteboardId);
316
435
  }
317
436
 
318
- public async initialize(option: SlideApplicationOption): Promise<void> {
319
- this.prefix = option.prefix;
320
- this.taskId = option.taskId;
321
- const whiteboardApp = new WhiteboardApplication();
322
- // @ts-ignore
323
- whiteboardApp.roomDoc = this.roomDoc;
324
- // @ts-ignore
325
- whiteboardApp.appId = `${option.taskId}_wb`;
326
- // @ts-ignore
327
- whiteboardApp.userId = this.userId;
328
- // @ts-ignore
329
- whiteboardApp.userManager = this.userManager;
330
- // @ts-ignore
331
- whiteboardApp.applicationManager = this.applicationManager;
332
-
333
- const json = await fetch(`${option.prefix}/${option.taskId}/jsonOutput/slide-1.json`).then(res => res.json())
334
-
335
- await whiteboardApp.initialize({
336
- width: json.width,
337
- height: json.height,
338
- });
339
- this.whiteboardApp = whiteboardApp;
340
- this.whiteboard = whiteboardApp.emitter;
341
- this.whiteboard.enableCameraByMouse = false;
342
- this.whiteboard.enableCameraByTouch = false;
343
- this.whiteboard.view.style.width = "100%";
344
- this.whiteboard.view.style.height = "100%";
345
- this.whiteboard.view.style.position = "absolute";
346
- this.whiteboard.view.style.top = "0";
347
- this.whiteboard.view.style.left = "0";
348
- this.whiteboard.view.style.zIndex = "4";
349
- this.whiteboard.permissions.addPermission(WhiteboardPermissionFlag.all);
350
- this.whiteboard.setCanvasBackgroundColor("#f0f0f000");
351
- this.whiteboardContainer.style.position = "relative";
352
- this.whiteboardContainer.style.flex = "0 0 auto";
353
- this.whiteboardContainer.style.height = "calc(100% - 24px)";
354
- this.whiteboardContainer.appendChild(this.whiteboard.view);
355
- this.whiteboardContainer.appendChild(this.slideContainer);
356
-
357
- this.contentContainer.appendChild(this.whiteboardContainer);
358
- this.contentContainer.appendChild(this.footer.root);
359
- this.contentContainer.appendChild(this.sideBar.root);
360
-
361
- if (option.inheritWhiteboardId) {
362
- whiteboardApp.linkToWhiteboard(option.inheritWhiteboardId);
437
+ this.whiteboard.setViewModeToMain();
438
+
439
+
440
+ this.slideContainer.setAttribute('builder', 'slide-builder');
441
+
442
+ // await slidePool.waitUntilReady(this.appId);
443
+ this.slide = new Slide({
444
+ ...option.options,
445
+ interactive: true,
446
+ anchor: this.slideContainer,
447
+ mode: 'interactive',
448
+ // logger: {
449
+ // info: console.log,
450
+ // warn: console.warn,
451
+ // error: console.error,
452
+ // },
453
+ });
454
+ this.slide.setResource(option.taskId, option.prefix);
455
+ this.sideBar.initialize(json.slideCount, option);
456
+
457
+ this.slide.on(SLIDE_EVENTS.syncDispatch, event => {
458
+ this.getMap(this.name).set('syncSlide', {
459
+ slideState: this.slide.slideState,
460
+ dispatch: event,
461
+ });
462
+ });
463
+
464
+ this.slide.on(SLIDE_EVENTS.mainSeqStepStart, (animateIndex: number) => {
465
+ this.emitter.emit('mainSeqStepStart', animateIndex);
466
+ });
467
+
468
+ this.slide.on(SLIDE_EVENTS.mainSeqStepEnd, (animateIndex: number) => {
469
+ this.emitter.emit('mainSeqStepEnd', animateIndex);
470
+ });
471
+
472
+ this.slide.on(SLIDE_EVENTS.animateStart, () => {
473
+ this.sideBar.hidden();
474
+ });
475
+
476
+ this.slide.on(SLIDE_EVENTS.renderError, ({ error, index }) => {
477
+ if (error.errorType === 'CANVAS_CRASH') {
478
+ this.slide.renderSlide(index);
479
+ }
480
+ });
481
+
482
+ this.slide.on(SLIDE_EVENTS.renderStart, (slideIndex) => {
483
+ this.whiteboardApp.emitter.view.style.opacity = '0';
484
+ this.whiteboardApp.emitter.addPage(`${slideIndex}`);
485
+ this.whiteboardApp.emitter.gotoPage(`${slideIndex}`);
486
+ this.sideBar.hidden();
487
+ this.emitter.emit('renderStart', slideIndex);
488
+ });
489
+
490
+ this.slide.on(SLIDE_EVENTS.renderEnd, (slideIndex) => {
491
+ this.currentSlideIndex = slideIndex;
492
+ this.whiteboardApp.emitter.view.style.opacity = '1';
493
+ // slidePool.active(this.appId, this.slide);
494
+ // slidePool.onRenderEnd(this.appId, this.window?.focused ?? false);
495
+ this.emitter.emit('renderEnd', slideIndex);
496
+ });
497
+
498
+ this.slide.on(SLIDE_EVENTS.stateChange, (state) => {
499
+ this.getMap(this.name).set('slideState', state);
500
+ });
501
+
502
+ this.getMap(this.name).observe(this.onSlideEventHandler);
503
+
504
+ (window as any).slide = this.slide;
505
+ (window as any).slideWhiteboard = this.whiteboardApp;
506
+ (window as any).forgeSlide = this;
507
+
508
+ const syncSlide = this.getMap(this.name).get('slideState');
509
+ if (syncSlide && syncSlide.taskId === option.taskId) {
510
+ this.slide.setSlideState(syncSlide);
511
+ } else {
512
+ this.slide.renderSlide(1);
513
+ }
514
+ this.permissions = new ForgeSlidePermissions(this.userManager, (userId: string) => {
515
+ return this.userMap(userId);
516
+ });
517
+ this.permissions.on('change', (userId, flags, value) => {
518
+ this.emitter.emit('permissionChange', userId, flags, value);
519
+ if (this.userId === userId) {
520
+ if (flags.includes(ForgeSlidePermissionFlag.clickAnim)) {
521
+ this.slideContainer.style.pointerEvents = 'auto';
522
+ } else {
523
+ this.slideContainer.style.pointerEvents = 'none';
363
524
  }
364
-
365
- this.whiteboard.setViewModeToMain();
366
-
367
-
368
- this.slideContainer.setAttribute("builder", "slide-builder")
369
- this.slide = new Slide({
370
- ...option.options,
371
- interactive: true,
372
- anchor: this.slideContainer,
373
- mode: "interactive",
374
- // logger: {
375
- // info: console.log,
376
- // warn: console.warn,
377
- // error: console.error,
378
- // },
379
- })
380
- this.slide.setResource(option.taskId, option.prefix);
381
- this.sideBar.initialize(json.slideCount, option);
382
-
383
- this.slide.on("syncDispatch", event => {
384
- this.getMap(this.name).set("syncSlide", {
385
- slideState: this.slide.slideState,
386
- dispatch: event,
387
- })
388
- })
389
-
390
- this.slide.on("mainSeqStepStart", (animateIndex: number) => {
391
- this.emitter.emit("mainSeqStepStart", animateIndex);
392
- })
393
-
394
- this.slide.on("mainSeqStepEnd", (animateIndex: number) => {
395
- this.emitter.emit("mainSeqStepEnd", animateIndex);
396
- })
397
-
398
- this.slide.on("renderStart", (slideIndex) => {
399
- this.whiteboardApp.emitter.view.style.opacity = "0";
400
- this.whiteboardApp.emitter.addPage(`${slideIndex}`);
401
- this.whiteboardApp.emitter.gotoPage(`${slideIndex}`);
402
- this.emitter.emit("renderStart", slideIndex);
403
- })
404
-
405
- this.slide.on("renderEnd", (slideIndex) => {
406
- this.currentSlideIndex = slideIndex;
407
- this.whiteboardApp.emitter.view.style.opacity = "1";
408
- this.emitter.emit("renderEnd", slideIndex);
409
- });
410
-
411
- this.slide.on("stateChange", (state) => {
412
- this.getMap(this.name).set("slideState", state)
413
- })
414
-
415
- this.getMap(this.name).observe(this.onSlideEventHandler);
416
-
417
- (window as any).slide = this.slide;
418
- (window as any).slideWhiteboard = this.whiteboardApp;
419
- (window as any).forgeSlide = this;
420
-
421
- const syncSlide = this.getMap(this.name).get("slideState");
422
- if (syncSlide && syncSlide.taskId === option.taskId) {
423
- await this.slide.setSlideState(syncSlide)
525
+ }
526
+ });
527
+ this.permissions.setPermission(ForgeSlidePermissionFlag.all);
528
+ this.whiteboardApp.disableViewModel();
529
+ if (this.window) {
530
+ let prevStatus = 'normal';
531
+ this.window.on('statusChange', (status) => {
532
+ if (prevStatus === 'minimized') {
533
+ this.onFocusInstance();
534
+ prevStatus = status;
535
+ return;
536
+ }
537
+ prevStatus = status;
538
+ if (status === 'normal') {
539
+ this.onFocusInstance();
540
+ } else if (status === 'minimized') {
541
+ this.onRefocusInstance();
542
+ }
543
+ });
544
+ this.window.on('focusedChange', (status) => {
545
+ if (status) {
546
+ this.onFocusInstance();
424
547
  } else {
425
- this.slide.renderSlide(1);
548
+ this.onRefocusInstance();
426
549
  }
427
-
428
- this.permissions = new ForgeSlidePermissions(this.userManager, (userId: string) => {
429
- return this.userMap(userId);
430
- });
431
- this.permissions.on("change", (userId, flags, value) => {
432
- if (this.userId === userId) {
433
- if (flags.includes(ForgeSlidePermissionFlag.clickAnim)) {
434
- this.slideContainer.style.pointerEvents = "auto";
435
- } else {
436
- this.slideContainer.style.pointerEvents = "none";
437
- }
438
- }
439
- });
440
- this.permissions.addPermission(ForgeSlidePermissionFlag.all);
441
- this.whiteboardApp.disableViewModel();
442
- // @ts-ignore
443
- window.__forge_slide = this;
444
- // @ts-ignore
445
- window.slidePermissions = this.permissions;
446
- return Promise.resolve(undefined);
447
- }
448
-
449
- private userMap(userId: string): Y.Map<any> {
450
- return this.getMap(`user/${userId}`);
451
- }
452
-
453
- public async dispose(): Promise<void> {
454
- await this.whiteboardApp.dispose();
455
- this.rootView.parentElement?.removeChild(this.rootView);
456
- this.slide.destroy();
457
- this.sideBar.dispose();
458
- this.getMap(this.name).unobserve(this.onSlideEventHandler)
459
- return Promise.resolve(undefined);
550
+ });
460
551
  }
552
+ // @ts-ignore
553
+ window.__forge_slide = this;
554
+ // @ts-ignore
555
+ window.slidePermissions = this.permissions;
556
+ return Promise.resolve(undefined);
557
+ }
558
+
559
+ private userMap(userId: string): Y.Map<any> {
560
+ return this.getMap(`user/${userId}`);
561
+ }
562
+
563
+ public async dispose(): Promise<void> {
564
+ await this.whiteboardApp.dispose();
565
+ this.rootView.parentElement?.removeChild(this.rootView);
566
+ this.slide.destroy();
567
+ this.sideBar.dispose();
568
+ this.getMap(this.name).unobserve(this.onSlideEventHandler);
569
+ this.permissions.dispose();
570
+ this.footer.dispose();
571
+ // slidePool.remove(this.appId);
572
+ }
461
573
 
462
574
  }