@netless/forge-slide 0.1.1-alpha.1 → 0.1.1-alpha.11

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,547 @@ 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 = '#f9f9fc';
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 getImageUrl(pageIndex: number) {
242
+ return this.getPreviewImageUrl(pageIndex);
243
+ }
244
+
245
+ private async getImageSize(pageIndex: number) {
246
+ const imageUrl = this.getPreviewImageUrl(pageIndex);
247
+ let preview: PreviewImage | null = null;
248
+ try {
249
+ const result = await kvStore.getItem(imageUrl);
250
+ preview = result ? JSON.parse(result) : null;
251
+ } catch (e) {
252
+ console.warn('kvStore getItem error', e);
249
253
  }
250
-
251
- private async getImageUrl(pageIndex: number) {
252
- return `${this.prefix}/${this.taskId}/preview/${pageIndex + 1}.png`;
254
+ if (preview) {
255
+ return { width: preview.width, height: preview.height };
256
+ }
257
+ preview = await this.sideBar.getPreviewImage(imageUrl);
258
+ await kvStore.setItem(imageUrl, JSON.stringify(preview));
259
+ return { width: preview.width, height: preview.height };
260
+ }
261
+
262
+ private async getImageContent(pageIndex: number) {
263
+ const imageUrl = this.getPreviewImageUrl(pageIndex);
264
+ let preview: PreviewImage | null = null;
265
+ try {
266
+ const result = await kvStore.getItem(imageUrl);
267
+ preview = result ? JSON.parse(result) : null;
268
+ } catch (e) {
269
+ console.warn('kvStore getItem error', e);
270
+ }
271
+ if (preview) {
272
+ return preview.src;
273
+ }
274
+ preview = await this.sideBar.getPreviewImage(imageUrl);
275
+ await kvStore.setItem(imageUrl, JSON.stringify(preview));
276
+ return preview.src;
277
+ }
278
+
279
+ private nextTick = () => {
280
+ this.isSyncing = false;
281
+ requestAnimationFrame(() => {
282
+ this.applySlideState().catch((error) => {
283
+ console.error('Error in applySlideState:', error);
284
+ });
285
+ });
286
+ };
287
+
288
+ private applySlideState = async () => {
289
+ if (this.isSyncing) {
290
+ return;
253
291
  }
254
292
 
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 };
293
+ const lastSyncMessage = this.syncMessageQueue.pop();
294
+ if (!lastSyncMessage) {
295
+ return this.nextTick();
270
296
  }
271
297
 
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;
298
+ this.syncMessageQueue = [];
299
+ this.isSyncing = true;
300
+ const { state, dispatch } = lastSyncMessage;
301
+ let ignoreKeys: string[] | undefined = undefined;
302
+ if ( dispatch.type === 'mediaPlay' || dispatch.type === 'mediaPause' || dispatch.type === 'mediaFullscreen') {
303
+ ignoreKeys = [dispatch.id];
287
304
  }
305
+ if (this.slide.slideState.currentSlideIndex < 0 || state.currentSlideIndex < 0) {
306
+ // @ts-ignore
307
+ await this.slide.receiveSyncHandler(dispatch);
308
+ return this.nextTick();
309
+ } else if (!deepEqual(this.slide.slideState, state, ignoreKeys)) {
310
+ await this.slide.setSlideState(state);
311
+ // @ts-ignore
312
+ await this.slide.receiveSyncHandler(dispatch);
313
+ } else {
314
+ this.slide.emit(SLIDE_EVENTS.syncReceive, dispatch);
315
+ }
316
+ return this.nextTick();
317
+
318
+ };
288
319
 
289
- private applySlideState = async (slideState: any, lastDispatch: any) => {
290
- if (this.slide.slideState.currentSlideIndex < 0) {
291
- this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
320
+ private onSlideEventHandler = async (event: Y.YMapEvent<any>) => {
321
+ for (const [key, value] of event.changes.keys.entries()) {
322
+ if (key === 'syncSlide') {
323
+ if (value.action === 'add' || value.action === 'update') {
324
+ const { slideState: slideStateFromServer, dispatch: dispatchFromServer } = this.getMap(this.name).get('syncSlide');
325
+ if (this.lastDispatchUuid === dispatchFromServer.uuid) {
292
326
  return;
327
+ }
328
+ this.lastDispatchUuid = dispatchFromServer.uuid;
329
+ this.syncMessageQueue.push({
330
+ state: slideStateFromServer,
331
+ dispatch: dispatchFromServer,
332
+ });
333
+ this.applySlideState();
293
334
  }
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
- }
335
+ }
301
336
  }
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
- }
337
+ };
338
+
339
+ private keyBoardEvents = (event: KeyboardEvent) => {
340
+ if (event.key === 'ArrowLeft') {
341
+ this.footer.emit('prevStep');
342
+ } else if (event.key === 'ArrowRight') {
343
+ this.footer.emit('nextStep');
344
+ } else if (event.key === 'ArrowUp') {
345
+ this.footer.emit('prevPage');
346
+ } else if (event.key === 'ArrowDown') {
347
+ this.footer.emit('nextPage');
348
+ }
349
+ };
350
+
351
+ private bindKeyBoardEvent() {
352
+ document.addEventListener('keydown', this.keyBoardEvents);
353
+ }
354
+
355
+ private unbindKeyBoardEvent() {
356
+ document.removeEventListener('keydown', this.keyBoardEvents);
357
+ }
358
+
359
+ private async onFocusInstance() {
360
+ this.bindKeyBoardEvent();
361
+ // await slidePool.active(this.appId, this.slide);
362
+ }
363
+
364
+ private onRefocusInstance() {
365
+ this.unbindKeyBoardEvent();
366
+ }
367
+
368
+
369
+ public async initialize(option: SlideApplicationOption): Promise<void> {
370
+ this.prefix = option.prefix;
371
+ this.taskId = option.taskId;
372
+ const whiteboardApp = new WhiteboardApplication();
373
+ // @ts-ignore
374
+ whiteboardApp.appDoc = this.appDoc;
375
+ // @ts-ignore
376
+ whiteboardApp.appId = `${this.appId}_wb`;
377
+ // @ts-ignore
378
+ whiteboardApp.userId = this.userId;
379
+ // @ts-ignore
380
+ whiteboardApp.userManager = this.userManager;
381
+ // @ts-ignore
382
+ whiteboardApp.deleteSubDoc = this.deleteSubDoc;
383
+
384
+ const json = await fetch(`${option.prefix}/${option.taskId}/jsonOutput/slide-1.json`).then(res => res.json());
385
+ this.slideCount = json.slideCount;
386
+ await whiteboardApp.initialize({
387
+ width: json.width,
388
+ height: json.height,
389
+ });
390
+ this.whiteboardApp = whiteboardApp;
391
+ this.whiteboard = whiteboardApp.emitter;
392
+ this.whiteboard.enableCameraByMouse = false;
393
+ this.whiteboard.enableCameraByTouch = false;
394
+ this.whiteboard.view.style.width = '100%';
395
+ this.whiteboard.view.style.height = '100%';
396
+ this.whiteboard.view.style.position = 'absolute';
397
+ this.whiteboard.view.style.top = '0';
398
+ this.whiteboard.view.style.left = '0';
399
+ this.whiteboard.view.style.zIndex = '4';
400
+ this.whiteboard.view.classList.add('slide-whiteboard');
401
+ this.whiteboard.permissions.addPermission(WhiteboardPermissionFlag.all);
402
+ this.whiteboard.setCanvasBackgroundColor('#f0f0f000');
403
+ this.whiteboardContainer.style.position = 'relative';
404
+ this.whiteboardContainer.style.flex = '0 0 auto';
405
+ this.whiteboardContainer.style.height = 'calc(100% - 24px)';
406
+ this.whiteboardContainer.classList.add('forge-slide-whiteboard-container');
407
+ this.whiteboardContainer.appendChild(this.whiteboard.view);
408
+ this.whiteboardContainer.appendChild(this.slideContainer);
409
+
410
+ this.contentContainer.appendChild(this.whiteboardContainer);
411
+ this.contentContainer.appendChild(this.footer.root);
412
+ this.contentContainer.appendChild(this.sideBar.root);
413
+
414
+ if (option.inheritWhiteboardId) {
415
+ whiteboardApp.linkToWhiteboard(option.inheritWhiteboardId);
312
416
  }
313
417
 
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);
418
+ this.whiteboard.setViewModeToMain();
419
+
420
+
421
+ this.slideContainer.setAttribute('builder', 'slide-builder');
422
+
423
+ // await slidePool.waitUntilReady(this.appId);
424
+ this.slide = new Slide({
425
+ ...option.options,
426
+ interactive: true,
427
+ anchor: this.slideContainer,
428
+ mode: 'interactive',
429
+ clientId: Math.random().toString(36).substring(2, 15),
430
+ timestamp: () => {
431
+ console.log('timestamp');
432
+ console.log(Date.now, this.calibrationTimestamp, Date.now() - this.calibrationTimestamp);
433
+ return this.calibrationTimestamp;
434
+ },
435
+ // logger: {
436
+ // info: console.log,
437
+ // warn: console.warn,
438
+ // error: console.error,
439
+ // },
440
+ });
441
+ this.slide.setResource(option.taskId, option.prefix);
442
+ this.sideBar.initialize(json.slideCount, option);
443
+
444
+ this.slide.on(SLIDE_EVENTS.syncDispatch, event => {
445
+ this.getMap(this.name).set('syncSlide', {
446
+ slideState: this.slide.slideState,
447
+ dispatch: event,
448
+ });
449
+ });
450
+
451
+ this.slide.on(SLIDE_EVENTS.mainSeqStepStart, (animateIndex: number) => {
452
+ this.emitter.emit('mainSeqStepStart', animateIndex);
453
+ });
454
+
455
+ this.slide.on(SLIDE_EVENTS.mainSeqStepEnd, (animateIndex: number) => {
456
+ this.emitter.emit('mainSeqStepEnd', animateIndex);
457
+ });
458
+
459
+ this.slide.on(SLIDE_EVENTS.renderError, ({ error, index }) => {
460
+ if (error.errorType === 'CANVAS_CRASH') {
461
+ this.slide.renderSlide(index);
462
+ }
463
+ });
464
+
465
+ this.slide.on(SLIDE_EVENTS.renderStart, (slideIndex) => {
466
+ if (slideIndex >= 0) {
467
+ this.sideBar.pauseGetPreviewImageSchedule();
468
+ this.whiteboardApp.emitter.view.style.opacity = '0';
469
+ this.whiteboardApp.emitter.addPage(`${slideIndex}`);
470
+ this.whiteboardApp.emitter.gotoPage(`${slideIndex}`);
471
+ this.sideBar.hidden();
472
+ this.emitter.emit('renderStart', slideIndex);
473
+ }
474
+ });
475
+
476
+ this.slide.on(SLIDE_EVENTS.renderEnd, (slideIndex) => {
477
+ if (slideIndex >= 0) {
478
+ this.sideBar.startGetPreviewImageSchedule();
479
+ this.currentSlideIndex = slideIndex;
480
+ this.whiteboardApp.emitter.view.style.opacity = '1';
481
+ // slidePool.active(this.appId, this.slide);
482
+ // slidePool.onRenderEnd(this.appId, this.window?.focused ?? false);
483
+ this.emitter.emit('renderEnd', slideIndex);
484
+ }
485
+ });
486
+
487
+ this.slide.on(SLIDE_EVENTS.stateChange, (state) => {
488
+ this.getMap(this.name).set('slideState', state);
489
+ });
490
+
491
+ this.getMap(this.name).observe(this.onSlideEventHandler);
492
+
493
+ (window as any).slide = this.slide;
494
+ (window as any).slideWhiteboard = this.whiteboardApp;
495
+ (window as any).forgeSlide = this;
496
+
497
+ this.whiteboardContainer.addEventListener('click', () => {
498
+ this.sideBar.hidden();
499
+ }, false);
500
+
501
+ const syncSlide = this.getMap(this.name).get('slideState');
502
+ if (syncSlide && syncSlide.taskId === option.taskId) {
503
+ this.slide.setSlideState(syncSlide);
504
+ } else {
505
+ this.slide.renderSlide(1);
506
+ }
507
+ this.permissions = new ForgeSlidePermissions(this.userManager, (userId: string) => {
508
+ return this.userMap(userId);
509
+ });
510
+ this.permissions.on('change', (userId, flags, value) => {
511
+ this.emitter.emit('permissionChange', userId, flags, value);
512
+ if (this.userId === userId) {
513
+ if (flags.includes(ForgeSlidePermissionFlag.clickAnim)) {
514
+ this.slideContainer.style.pointerEvents = 'auto';
515
+ } else {
516
+ this.slideContainer.style.pointerEvents = 'none';
359
517
  }
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)
518
+ }
519
+ });
520
+ this.permissions.setPermission(ForgeSlidePermissionFlag.all);
521
+ this.whiteboardApp.disableViewModel();
522
+ if (this.window) {
523
+ let prevStatus = 'normal';
524
+ this.window.on('statusChange', (status) => {
525
+ if (prevStatus === 'minimized') {
526
+ this.onFocusInstance();
527
+ prevStatus = status;
528
+ return;
529
+ }
530
+ prevStatus = status;
531
+ if (status === 'normal') {
532
+ this.onFocusInstance();
533
+ } else if (status === 'minimized') {
534
+ this.onRefocusInstance();
535
+ }
536
+ });
537
+ this.window.on('focusedChange', (status) => {
538
+ if (status) {
539
+ this.onFocusInstance();
420
540
  } else {
421
- this.slide.renderSlide(1);
541
+ this.onRefocusInstance();
422
542
  }
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);
543
+ });
544
+ this.bindKeyBoardEvent();
444
545
  }
445
-
446
- private userMap(userId: string): Y.Map<any> {
447
- return this.getMap(`user/${userId}`);
546
+ // @ts-ignore
547
+ window.__forge_slide = this;
548
+ // @ts-ignore
549
+ window.slidePermissions = this.permissions;
550
+ return Promise.resolve(undefined);
551
+ }
552
+
553
+ private userMap(userId: string): Y.Map<any> {
554
+ return this.getMap(`user/${userId}`);
555
+ }
556
+
557
+ public async dispose(removeSubDoc: boolean): Promise<void> {
558
+ if (removeSubDoc) {
559
+ this.deleteSubDoc(this.appId);
448
560
  }
561
+ await this.whiteboardApp.dispose(removeSubDoc);
562
+ this.rootView.parentElement?.removeChild(this.rootView);
563
+ this.slide.destroy();
564
+ this.sideBar.dispose();
565
+ this.getMap(this.name).unobserve(this.onSlideEventHandler);
566
+ this.permissions.dispose();
567
+ this.footer.dispose();
568
+ // slidePool.remove(this.appId);
569
+ }
449
570
 
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);
457
- }
458
-
459
- }
571
+ }