@netless/forge-slide 0.1.1-alpha.1 → 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,434 +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.emitter.on("renderStart", pageIndex => {
132
- this.footer.prevPageState(pageIndex !== 0);
133
- });
134
-
135
- const that = this;
136
- Object.defineProperty(this.emitter, "view", {
137
- get(): any {
138
- return that.rootView;
139
- }
140
- });
141
- Object.defineProperty(this.emitter, "permissions", {
142
- get(): any {
143
- return that.permissions;
144
- }
145
- });
146
- Object.defineProperty(this.emitter, "footView", {
147
- get(): any {
148
- return that.footer.root;
149
- }
150
- })
151
- Object.defineProperty(this.emitter, "pageIndex", {
152
- get(): any {
153
- return that.currentSlideIndex;
154
- }
155
- });
156
- Object.defineProperty(this.emitter, "pageCount", {
157
- get(): any {
158
- return that.slide.slideCount;
159
- }
160
- });
161
- Object.defineProperty(this.emitter, "goto", {
162
- writable: false,
163
- enumerable: false,
164
- value: (pageIndex: number) => {
165
- this.sideBar.emit("pageChange", pageIndex);
166
- }
167
- });
168
- Object.defineProperty(this.emitter, "nextStep", {
169
- writable: false,
170
- enumerable: false,
171
- value: () => {
172
- this.footer.emit("nextStep");
173
- }
174
- })
175
- Object.defineProperty(this.emitter, "prevStep", {
176
- writable: false,
177
- enumerable: false,
178
- value: () => {
179
- this.footer.emit("prevStep");
180
- }
181
- })
182
- Object.defineProperty(this.emitter, "nextPage", {
183
- writable: false,
184
- enumerable: false,
185
- value: () => {
186
- this.footer.emit("nextPage");
187
- }
188
- })
189
- Object.defineProperty(this.emitter, "prevPage", {
190
- writable: false,
191
- enumerable: false,
192
- value: () => {
193
- this.footer.emit("prevPage");
194
- }
195
- })
196
- Object.defineProperty(this.emitter, "sideBarToggle", {
197
- writable: false,
198
- enumerable: false,
199
- value: () => {
200
- this.footer.emit("sideBarToggle");
201
- }
202
- })
203
- Object.defineProperty(this.emitter, "imgContent", {
204
- writable: false,
205
- enumerable: false,
206
- value: (pageIndex: number) => {
207
- return this.getImageContent(pageIndex);
208
- }
209
- })
210
-
211
- Object.defineProperty(this.emitter, "imgUrl", {
212
- writable: false,
213
- enumerable: false,
214
- value: (pageIndex: number) => {
215
- return this.getImageUrl(pageIndex);
216
- }
217
- })
218
-
219
- Object.defineProperty(this.emitter, "imgSize", {
220
- writable: false,
221
- enumerable: false,
222
- value: (pageIndex: number) => {
223
- return this.getImageSize(pageIndex);
224
- }
225
- })
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');
226
237
  }
227
-
228
- private async getPreviewImage(imageUrl: string) {
229
- const image = fetch(imageUrl);
230
- return await image.then(res => res.blob()).then(blob => {
231
- return new Promise<PreviewImage>(resolve => {
232
- const reader = new FileReader();
233
- reader.onloadend = () => {
234
- const base64Data = reader.result as string;
235
- const img = document.createElement("img");
236
- img.src = base64Data;
237
- img.onload = () => {
238
- resolve({
239
- url: imageUrl,
240
- src: base64Data,
241
- width: img.width,
242
- height: img.height,
243
- });
244
- }
245
- }
246
- reader.readAsDataURL(blob);
247
- })
248
- });
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);
249
276
  }
250
-
251
- private async getImageUrl(pageIndex: number) {
252
- 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;
253
314
  }
254
315
 
255
- private async getImageSize(pageIndex: number) {
256
- const imageUrl = `${this.prefix}/${this.taskId}/preview/${pageIndex + 1}.png`;
257
- let preview: PreviewImage | null = null;
258
- try {
259
- const result = await kvStore.getItem(imageUrl);
260
- preview = result ? JSON.parse(result) : null;
261
- } catch (e) {
262
- console.warn("kvStore getItem error", e);
263
- }
264
- if (preview) {
265
- return { width: preview.width, height: preview.height };
266
- }
267
- preview = await this.getPreviewImage(imageUrl);
268
- await kvStore.setItem(imageUrl, JSON.stringify(preview));
269
- return { width: preview.width, height: preview.height };
316
+ const lastSyncMessage = this.syncMessageQueue.pop();
317
+ if (!lastSyncMessage) {
318
+ return this.nextTick();
270
319
  }
271
320
 
272
- private async getImageContent(pageIndex: number) {
273
- const imageUrl = `${this.prefix}/${this.taskId}/preview/${pageIndex + 1}.png`;
274
- let preview: PreviewImage | null = null;
275
- try {
276
- const result = await kvStore.getItem(imageUrl);
277
- preview = result ? JSON.parse(result) : null;
278
- } catch (e) {
279
- console.warn("kvStore getItem error", e);
280
- }
281
- if (preview) {
282
- return preview.src;
283
- }
284
- preview = await this.getPreviewImage(imageUrl);
285
- await kvStore.setItem(imageUrl, JSON.stringify(preview));
286
- 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);
287
334
  }
335
+ return this.nextTick();
288
336
 
289
- private applySlideState = async (slideState: any, lastDispatch: any) => {
290
- if (this.slide.slideState.currentSlideIndex < 0) {
291
- 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) {
292
345
  return;
346
+ }
347
+ this.lastDispatchUuid = dispatchFromServer.uuid;
348
+ this.syncMessageQueue.push({
349
+ state: slideStateFromServer,
350
+ dispatch: dispatchFromServer,
351
+ });
352
+ this.applySlideState();
293
353
  }
294
- if (this.slide.slideState.currentSlideIndex > 0 && deepEqual(this.slide.slideState, slideState)) {
295
- this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
296
- } else {
297
- await this.slide.setSlideState(slideState);
298
- await delay(200);
299
- this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
300
- }
354
+ }
301
355
  }
302
-
303
- private onSlideEventHandler = async (event: Y.YMapEvent<any>) => {
304
- for (const [key, value] of event.changes.keys.entries()) {
305
- if (key === "syncSlide") {
306
- if (value.action === "add" || value.action === "update") {
307
- const { slideState: slideStateFromServer, dispatch: dispatchFromServer } = this.getMap(this.name).get("syncSlide");
308
- this.applySlideState(slideStateFromServer, dispatchFromServer);
309
- }
310
- }
311
- }
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);
312
435
  }
313
436
 
314
- public async initialize(option: SlideApplicationOption): Promise<void> {
315
- this.prefix = option.prefix;
316
- this.taskId = option.taskId;
317
- const whiteboardApp = new WhiteboardApplication();
318
- // @ts-ignore
319
- whiteboardApp.roomDoc = this.roomDoc;
320
- // @ts-ignore
321
- whiteboardApp.appId = `${option.taskId}_wb`;
322
- // @ts-ignore
323
- whiteboardApp.userId = this.userId;
324
- // @ts-ignore
325
- whiteboardApp.userManager = this.userManager;
326
- // @ts-ignore
327
- whiteboardApp.applicationManager = this.applicationManager;
328
-
329
- const json = await fetch(`${option.prefix}/${option.taskId}/jsonOutput/slide-1.json`).then(res => res.json())
330
-
331
- await whiteboardApp.initialize({
332
- width: json.width,
333
- height: json.height,
334
- });
335
- this.whiteboardApp = whiteboardApp;
336
- this.whiteboard = whiteboardApp.emitter;
337
- this.whiteboard.enableCameraByMouse = false;
338
- this.whiteboard.enableCameraByTouch = false;
339
- this.whiteboard.view.style.width = "100%";
340
- this.whiteboard.view.style.height = "100%";
341
- this.whiteboard.view.style.position = "absolute";
342
- this.whiteboard.view.style.top = "0";
343
- this.whiteboard.view.style.left = "0";
344
- this.whiteboard.view.style.zIndex = "4";
345
- this.whiteboard.permissions.addPermission(WhiteboardPermissionFlag.all);
346
- this.whiteboard.setCanvasBackgroundColor("#f0f0f000");
347
- this.whiteboardContainer.style.position = "relative";
348
- this.whiteboardContainer.style.flex = "0 0 auto";
349
- this.whiteboardContainer.style.height = "calc(100% - 24px)";
350
- this.whiteboardContainer.appendChild(this.whiteboard.view);
351
- this.whiteboardContainer.appendChild(this.slideContainer);
352
-
353
- this.contentContainer.appendChild(this.whiteboardContainer);
354
- this.contentContainer.appendChild(this.footer.root);
355
- this.contentContainer.appendChild(this.sideBar.root);
356
-
357
- if (option.inheritWhiteboardId) {
358
- 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';
359
524
  }
360
-
361
- this.whiteboard.setViewModeToMain();
362
-
363
-
364
- this.slideContainer.setAttribute("builder", "slide-builder")
365
- this.slide = new Slide({
366
- ...option.options,
367
- interactive: true,
368
- anchor: this.slideContainer,
369
- mode: "interactive",
370
- // logger: {
371
- // info: console.log,
372
- // warn: console.warn,
373
- // error: console.error,
374
- // },
375
- })
376
- this.slide.setResource(option.taskId, option.prefix);
377
- this.sideBar.initialize(json.slideCount, option);
378
-
379
- this.slide.on("syncDispatch", event => {
380
- this.getMap(this.name).set("syncSlide", {
381
- slideState: this.slide.slideState,
382
- dispatch: event,
383
- })
384
- })
385
-
386
- this.slide.on("mainSeqStepStart", (animateIndex: number) => {
387
- this.emitter.emit("mainSeqStepStart", animateIndex);
388
- })
389
-
390
- this.slide.on("mainSeqStepEnd", (animateIndex: number) => {
391
- this.emitter.emit("mainSeqStepEnd", animateIndex);
392
- })
393
-
394
- this.slide.on("renderStart", (slideIndex) => {
395
- this.whiteboardApp.emitter.view.style.opacity = "0";
396
- this.whiteboardApp.emitter.addPage(`${slideIndex}`);
397
- this.whiteboardApp.emitter.gotoPage(`${slideIndex}`);
398
- this.emitter.emit("renderStart", slideIndex);
399
- })
400
-
401
- this.slide.on("renderEnd", (slideIndex) => {
402
- this.currentSlideIndex = slideIndex;
403
- this.whiteboardApp.emitter.view.style.opacity = "1";
404
- this.emitter.emit("renderEnd", slideIndex);
405
- });
406
-
407
- this.slide.on("stateChange", (state) => {
408
- this.getMap(this.name).set("slideState", state)
409
- })
410
-
411
- this.getMap(this.name).observe(this.onSlideEventHandler);
412
-
413
- (window as any).slide = this.slide;
414
- (window as any).slideWhiteboard = this.whiteboardApp;
415
- (window as any).forgeSlide = this;
416
-
417
- const syncSlide = this.getMap(this.name).get("slideState");
418
- if (syncSlide && syncSlide.taskId === option.taskId) {
419
- 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();
420
547
  } else {
421
- this.slide.renderSlide(1);
548
+ this.onRefocusInstance();
422
549
  }
423
-
424
- this.permissions = new ForgeSlidePermissions(this.userManager, (userId: string) => {
425
- return this.userMap(userId);
426
- });
427
- this.permissions.on("change", (userId, flags, value) => {
428
- this.emitter.emit("permissionChange", userId, flags, value);
429
- if (this.userId === userId) {
430
- if (flags.includes(ForgeSlidePermissionFlag.clickAnim)) {
431
- this.slideContainer.style.pointerEvents = "auto";
432
- } else {
433
- this.slideContainer.style.pointerEvents = "none";
434
- }
435
- }
436
- });
437
- this.permissions.addPermission(ForgeSlidePermissionFlag.all);
438
- this.whiteboardApp.disableViewModel();
439
- // @ts-ignore
440
- window.__forge_slide = this;
441
- // @ts-ignore
442
- window.slidePermissions = this.permissions;
443
- return Promise.resolve(undefined);
444
- }
445
-
446
- private userMap(userId: string): Y.Map<any> {
447
- return this.getMap(`user/${userId}`);
448
- }
449
-
450
- public async dispose(): Promise<void> {
451
- await this.whiteboardApp.dispose();
452
- this.rootView.parentElement?.removeChild(this.rootView);
453
- this.slide.destroy();
454
- this.sideBar.dispose();
455
- this.getMap(this.name).unobserve(this.onSlideEventHandler)
456
- return Promise.resolve(undefined);
550
+ });
457
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
+ }
458
573
 
459
574
  }