@netless/forge-slide 0.1.1-alpha.9 → 1.0.0-alpha.1

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 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,WAAW,GAAE,MAAM,EAAa,WAkDzE;AAWD,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAA8D"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,WAAW,GAAE,MAAM,EAAmB,WAkD/E;AAWD,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAA8D"}
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@netless/forge-slide",
3
- "version": "0.1.1-alpha.9",
3
+ "version": "1.0.0-alpha.1",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "dependencies": {
9
- "@netless/slide": "^1.4.15"
9
+ "@netless/slide": "^1.4.21"
10
10
  },
11
11
  "peerDependencies": {
12
12
  "eventemitter3": "^5.0.1",
13
13
  "yjs": "^13.6.18",
14
14
  "uuid": "^11.0.5",
15
- "@netless/forge-room": "0.1.11",
16
- "@netless/forge-whiteboard": "0.1.15"
15
+ "@netless/forge-room": "1.0.0-alpha.1",
16
+ "@netless/forge-whiteboard": "0.1.20-alpha.1"
17
17
  },
18
18
  "keywords": [],
19
19
  "author": "",
package/src/FooterView.ts CHANGED
@@ -15,20 +15,25 @@ export class FooterView extends EventEmitter<FooterViewEvents> {
15
15
 
16
16
  public readonly root: HTMLDivElement;
17
17
 
18
- private prevStep: HTMLDivElement;
19
18
  private nextStep: HTMLDivElement;
19
+ private pauseIcon: HTMLDivElement;
20
20
 
21
21
  private prevPage: HTMLDivElement;
22
22
  private nextPage: HTMLDivElement;
23
23
 
24
24
  private sideBarToggle: HTMLDivElement;
25
-
25
+
26
+ private currentPageIndex: number = 0;
27
+ private totalPageIndex: number = 0;
28
+ private pageIndexContainer: HTMLDivElement;
29
+
26
30
  private eventMap: Map<HTMLDivElement, (() => void)[]> = new Map();
27
31
 
28
32
  public constructor() {
29
33
  super();
30
34
  this.root = document.createElement('div');
31
35
  this.root.classList.add('forge-slide-footer');
36
+ this.root.style.padding = '0 16px 0 0';
32
37
  this.root.style.height = '24px';
33
38
  this.root.style.zIndex = '6';
34
39
  this.root.style.display = 'flex';
@@ -36,17 +41,19 @@ export class FooterView extends EventEmitter<FooterViewEvents> {
36
41
  this.root.style.justifyContent = 'center';
37
42
  this.root.style.backgroundColor = '#fff';
38
43
 
39
- this.prevStep = this.createIcon(Icons.prevStep(EM_COLOR), () => {
40
- this.emit('prevStep');
44
+
45
+ this.prevPage = this.createIcon(Icons.prevPage(EM_COLOR), () => {
46
+ this.emit('prevPage');
41
47
  });
42
48
 
43
49
  this.nextStep = this.createIcon(Icons.nextStep(EM_COLOR), () => {
44
50
  this.emit('nextStep');
45
51
  });
46
52
 
47
- this.prevPage = this.createIcon(Icons.prevPage(EM_COLOR), () => {
48
- this.emit('prevPage');
53
+ this.pauseIcon = this.createIcon(Icons.pause(EM_COLOR), () => {
54
+
49
55
  });
56
+ this.pauseIcon.style.display = 'none';
50
57
 
51
58
  this.nextPage = this.createIcon(Icons.nextPage(EM_COLOR), () => {
52
59
  this.emit('nextPage');
@@ -56,13 +63,36 @@ export class FooterView extends EventEmitter<FooterViewEvents> {
56
63
  this.emit('sideBarToggle');
57
64
  });
58
65
 
66
+
67
+ this.pageIndexContainer = this.createPageNumber();
68
+
59
69
  this.root.appendChild(this.sideBarToggle);
60
70
  this.root.appendChild(this.createSpacer());
61
71
  this.root.appendChild(this.prevPage);
62
- this.root.appendChild(this.prevStep);
63
72
  this.root.appendChild(this.nextStep);
73
+ this.root.appendChild(this.pauseIcon);
64
74
  this.root.appendChild(this.nextPage);
65
75
  this.root.appendChild(this.createSpacer());
76
+ this.root.appendChild(this.pageIndexContainer);
77
+ }
78
+
79
+ public changeIconToPause(): void {
80
+ this.nextStep.style.display = 'none';
81
+ this.pauseIcon.style.display = 'block';
82
+ }
83
+
84
+ public changeIconToNextStep(): void {
85
+ this.nextStep.style.display = 'block';
86
+ this.pauseIcon.style.display = 'none';
87
+ }
88
+
89
+ public setCurrentPageIndex(index: number): void {
90
+ this.currentPageIndex = index;
91
+ this.pageIndexContainer.textContent = `${this.currentPageIndex} / ${this.totalPageIndex}`;
92
+ }
93
+
94
+ public setTotalPageIndex(count: number): void {
95
+ this.totalPageIndex = count;
66
96
  }
67
97
 
68
98
  public prevPageState(enable: boolean): void {
@@ -75,22 +105,24 @@ export class FooterView extends EventEmitter<FooterViewEvents> {
75
105
  }
76
106
  }
77
107
 
78
- public nextPageState(enable: boolean): void {
79
- if (enable) {
80
- this.nextPage.style.pointerEvents = 'all';
81
- this.nextPage.style.opacity = '1';
82
- } else {
83
- this.nextPage.style.pointerEvents = 'none';
84
- this.nextPage.style.opacity = '0.5';
85
- }
86
- }
87
-
88
108
  private createSpacer(): HTMLDivElement {
89
109
  const div = document.createElement('div');
90
110
  div.style.flex = '1 1 auto';
91
111
  return div;
92
112
  }
93
113
 
114
+ private createPageNumber(): HTMLDivElement {
115
+ const div = document.createElement('div');
116
+ div.style.fontSize = '13px';
117
+ div.style.margin = '6px';
118
+ div.style.color = '#191919';
119
+ div.style.fontFamily = 'system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji"';
120
+ div.style.fontWeight = '400';
121
+ div.style.lineHeight = '18px';
122
+ div.style.userSelect = 'none';
123
+ return div;
124
+ }
125
+
94
126
  private createIcon(svgContent: string, action: () => void): HTMLDivElement {
95
127
  const icon = document.createElement('div');
96
128
  icon.style.width = '18px';
@@ -129,4 +161,4 @@ export class FooterView extends EventEmitter<FooterViewEvents> {
129
161
  this.removeAllListeners();
130
162
  this.clearHTMLEventListeners();
131
163
  }
132
- }
164
+ }
@@ -1,5 +1,6 @@
1
1
  import { SlideApplicationOption } from './SlideApplication';
2
2
  import EventEmitter from 'eventemitter3';
3
+ import { kvStore } from '@netless/forge-room';
3
4
 
4
5
  interface SideBarViewEvents {
5
6
  pageChange: (index: number) => void;
@@ -9,6 +10,11 @@ export class SideBarView extends EventEmitter<SideBarViewEvents> {
9
10
  public readonly root: HTMLDivElement = document.createElement('div');
10
11
  private isShow: boolean = false;
11
12
  private eventsMap: Map<HTMLDivElement, (() => void)[]> = new Map();
13
+ private taskId: string = '';
14
+ private prefix: string = '';
15
+ private addImagesPool: number[] = [];
16
+ private scheduleId: number = 0;
17
+ private isSchedule = false;
12
18
 
13
19
  public constructor() {
14
20
  super();
@@ -26,62 +32,130 @@ export class SideBarView extends EventEmitter<SideBarViewEvents> {
26
32
  this.root.style.flexDirection = 'column';
27
33
  this.root.style.justifyContent = 'flex-start';
28
34
  this.root.style.alignItems = 'center';
35
+ this.root.style.userSelect = 'none';
29
36
  }
30
37
 
31
38
  get isShowSideBar(): boolean {
32
39
  return this.isShow;
33
40
  }
34
41
 
35
- public initialize(slideCount: number, option: SlideApplicationOption): void {
36
- for (let i = 1; i <= slideCount; i++) {
37
- const itemContainer = document.createElement('div');
38
- itemContainer.style.width = '60%';
39
- itemContainer.style.display = 'flex';
40
- itemContainer.style.justifyContent = 'center';
41
- itemContainer.style.alignItems = 'flex-start';
42
- itemContainer.style.position = 'relative';
43
- itemContainer.style.borderRadius = '4px';
44
- itemContainer.style.transition = 'border-color .3s';
45
- itemContainer.style.marginBottom = '10px';
46
-
47
- const onMouseOverHandle = () => {
48
- itemContainer.style.borderColor = '#ccc';
49
- };
50
- const onMouseOutHandle = () => {
51
- itemContainer.style.borderColor = 'transparent';
52
- };
53
- const onClickHandle = () => {
54
- this.emit('pageChange', i);
42
+ public async getPreviewImage(imageUrl: string) {
43
+ const image = await fetch(imageUrl);
44
+ const blob = await image.blob();
45
+ return new Promise<PreviewImage>(resolve => {
46
+ const reader = new FileReader();
47
+ reader.onloadend = () => {
48
+ const base64Data = reader.result as string;
49
+ const img = document.createElement('img');
50
+ img.src = base64Data;
51
+ img.onload = () => {
52
+ resolve({
53
+ url: imageUrl,
54
+ src: base64Data,
55
+ width: img.width,
56
+ height: img.height,
57
+ });
58
+ };
55
59
  };
60
+ reader.readAsDataURL(blob);
61
+ });
62
+ }
63
+
64
+ private async appendPreviewImage(pageIndex: number) {
65
+ const itemContainer = document.createElement('div');
66
+ itemContainer.style.width = '60%';
67
+ itemContainer.style.display = 'flex';
68
+ itemContainer.style.justifyContent = 'center';
69
+ itemContainer.style.alignItems = 'flex-start';
70
+ itemContainer.style.position = 'relative';
71
+ itemContainer.style.borderRadius = '4px';
72
+ itemContainer.style.transition = 'border-color .3s';
73
+ itemContainer.style.marginBottom = '10px';
74
+
75
+ const onMouseOverHandle = () => {
76
+ itemContainer.style.borderColor = '#ccc';
77
+ };
78
+ const onMouseOutHandle = () => {
79
+ itemContainer.style.borderColor = 'transparent';
80
+ };
81
+ const onClickHandle = () => {
82
+ this.emit('pageChange', pageIndex);
83
+ };
56
84
 
57
- itemContainer.addEventListener('click', onClickHandle);
58
- itemContainer.addEventListener('mouseover', onMouseOverHandle);
59
- itemContainer.addEventListener('mouseout', onMouseOutHandle);
60
- this.eventsMap.set(itemContainer, [onClickHandle, onMouseOverHandle, onMouseOutHandle]);
61
-
62
- const pageIndex = document.createElement('span');
63
- pageIndex.textContent = `${i}`;
64
- pageIndex.style.position = 'absolute';
65
- pageIndex.style.top = '1px';
66
- pageIndex.style.left = '-10px';
67
- pageIndex.style.transform = 'translate(-100%)';
68
- pageIndex.style.fontSize = '12px';
69
- pageIndex.style.color = '#5f5f5f';
70
-
71
- const preview = document.createElement('img');
72
- preview.style.width = '100%';
73
- preview.style.display = 'inline-block';
74
- preview.src = `${option.prefix}/${option.taskId}/preview/${i}.png`;
75
-
76
- itemContainer.appendChild(preview);
77
- itemContainer.appendChild(pageIndex);
78
-
79
- this.root.appendChild(itemContainer);
85
+ itemContainer.addEventListener('click', onClickHandle);
86
+ itemContainer.addEventListener('mouseover', onMouseOverHandle);
87
+ itemContainer.addEventListener('mouseout', onMouseOutHandle);
88
+ this.eventsMap.set(itemContainer, [onClickHandle, onMouseOverHandle, onMouseOutHandle]);
89
+
90
+ const pageIndexContainer = document.createElement('span');
91
+ pageIndexContainer.textContent = `${pageIndex}`;
92
+ pageIndexContainer.style.position = 'absolute';
93
+ pageIndexContainer.style.top = '1px';
94
+ pageIndexContainer.style.left = '-10px';
95
+ pageIndexContainer.style.transform = 'translate(-100%)';
96
+ pageIndexContainer.style.fontSize = '12px';
97
+ pageIndexContainer.style.color = '#5f5f5f';
98
+
99
+ const previewUrl = `${this.prefix}/${this.taskId}/preview/${pageIndex}.png`;
100
+ const preview = document.createElement('img');
101
+ const cachePreview = await kvStore.getItem(previewUrl);
102
+ if (cachePreview) {
103
+ const { src } = JSON.parse(cachePreview);
104
+ preview.src = src;
105
+ } else {
106
+ const previewInfo = await this.getPreviewImage(previewUrl);
107
+ await kvStore.setItem(previewUrl, JSON.stringify(previewInfo));
108
+ const { src } = previewInfo;
109
+ preview.src = src;
80
110
  }
111
+
112
+ preview.style.width = '100%';
113
+ preview.style.display = 'inline-block';
114
+
115
+ itemContainer.appendChild(preview);
116
+ itemContainer.appendChild(pageIndexContainer);
117
+
118
+ this.root.appendChild(itemContainer);
119
+ }
120
+
121
+ private async scheduleGetPreviewImage() {
122
+ if (!this.isSchedule) {
123
+ this.scheduleId = setTimeout(async () => {
124
+ await this.scheduleGetPreviewImage();
125
+ }, 32) as unknown as number;
126
+ return;
127
+ }
128
+ const pageIndex = this.addImagesPool.shift();
129
+ if (!pageIndex) {
130
+ clearTimeout(this.scheduleId);
131
+ this.scheduleId = 0;
132
+ return;
133
+ }
134
+ await this.appendPreviewImage(pageIndex);
135
+ this.scheduleId = setTimeout(async () => {
136
+ await this.scheduleGetPreviewImage();
137
+ }, 32) as unknown as number;
138
+ }
139
+
140
+ public async startGetPreviewImageSchedule() {
141
+ this.isSchedule = true;
142
+ }
143
+
144
+ public pauseGetPreviewImageSchedule() {
145
+ this.isSchedule = false;
146
+ }
147
+
148
+ public initialize(slideCount: number, option: SlideApplicationOption): void {
149
+ this.taskId = option.taskId;
150
+ this.prefix = option.prefix;
151
+ for (let i = 1; i <= slideCount; i++) {
152
+ this.addImagesPool.push(i);
153
+ }
154
+ this.scheduleGetPreviewImage();
81
155
  }
82
156
 
83
157
  public hidden() {
84
- if (!this.root) {
158
+ if (!this.root || !this.isShow) {
85
159
  return;
86
160
  }
87
161
  this.root.style.left = '-240px';
@@ -109,5 +183,11 @@ export class SideBarView extends EventEmitter<SideBarViewEvents> {
109
183
  element.removeEventListener('mouseout', mouseOutEvent);
110
184
  });
111
185
  }
186
+ }
112
187
 
113
- }
188
+ interface PreviewImage {
189
+ url: string;
190
+ src: string;
191
+ width: number;
192
+ height: number;
193
+ }
@@ -6,8 +6,7 @@ import { ForgeSlidePermissionFlag, ForgeSlidePermissions } from './ForgeSlidePer
6
6
  import { FooterView } from './FooterView';
7
7
  import * as Y from 'yjs';
8
8
  import { SideBarView } from './SiderBarView';
9
- import { deepEqual, delay } from './utils';
10
- // import { slidePool } from './SlidePool';
9
+ import { deepEqual } from './utils';
11
10
 
12
11
  export interface SlideApplicationOption {
13
12
  prefix: string;
@@ -49,12 +48,15 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
49
48
  private taskId: string = '';
50
49
  private prefix: string = '';
51
50
  private slideCount: number = 0;
51
+ private lastDispatchUuid: string = '';
52
+ private syncMessageQueue: { state: any, dispatch: any }[] = [];
53
+ private isSyncing: boolean = false;
52
54
 
53
55
  constructor() {
54
56
  super();
55
57
  (window as any).emitter = this.emitter;
56
58
  this.rootView.setAttribute('data-forge-app', Slide_APP_NAME);
57
- this.rootView.style.background = '#f0f0f0f0';
59
+ this.rootView.style.background = '#f9f9fc';
58
60
  this.rootView.style.overflow = 'hidden';
59
61
 
60
62
  this.contentContainer.style.width = '100%';
@@ -114,7 +116,6 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
114
116
  this.slide.renderSlide(this.currentSlideIndex + 1);
115
117
  }
116
118
  });
117
-
118
119
  this.footer.on('sideBarToggle', () => {
119
120
  if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
120
121
  return;
@@ -213,7 +214,6 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
213
214
  return this.getImageContent(pageIndex);
214
215
  },
215
216
  });
216
-
217
217
  Object.defineProperty(this.emitter, 'imgUrl', {
218
218
  writable: false,
219
219
  enumerable: false,
@@ -221,7 +221,6 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
221
221
  return this.getImageUrl(pageIndex);
222
222
  },
223
223
  });
224
-
225
224
  Object.defineProperty(this.emitter, 'imgSize', {
226
225
  writable: false,
227
226
  enumerable: false,
@@ -229,6 +228,7 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
229
228
  return this.getImageSize(pageIndex);
230
229
  },
231
230
  });
231
+ this.applySlideState();
232
232
  }
233
233
 
234
234
  private getPreviewImageUrl (pageIndex: number) {
@@ -238,29 +238,6 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
238
238
  return `${this.prefix}/${this.taskId}/preview/${pageIndex}.png`;
239
239
  }
240
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
241
  private async getImageUrl(pageIndex: number) {
265
242
  return this.getPreviewImageUrl(pageIndex);
266
243
  }
@@ -277,7 +254,7 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
277
254
  if (preview) {
278
255
  return { width: preview.width, height: preview.height };
279
256
  }
280
- preview = await this.getPreviewImage(imageUrl);
257
+ preview = await this.sideBar.getPreviewImage(imageUrl);
281
258
  await kvStore.setItem(imageUrl, JSON.stringify(preview));
282
259
  return { width: preview.width, height: preview.height };
283
260
  }
@@ -294,23 +271,50 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
294
271
  if (preview) {
295
272
  return preview.src;
296
273
  }
297
- preview = await this.getPreviewImage(imageUrl);
274
+ preview = await this.sideBar.getPreviewImage(imageUrl);
298
275
  await kvStore.setItem(imageUrl, JSON.stringify(preview));
299
276
  return preview.src;
300
277
  }
301
278
 
302
- private applySlideState = async (slideState: any, lastDispatch: any) => {
303
- if (this.slide.slideState.currentSlideIndex < 0) {
304
- this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
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) {
305
290
  return;
306
291
  }
307
- if (this.slide.slideState.currentSlideIndex > 0 && deepEqual(this.slide.slideState, slideState)) {
308
- this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
292
+
293
+ const lastSyncMessage = this.syncMessageQueue.pop();
294
+ if (!lastSyncMessage) {
295
+ return this.nextTick();
296
+ }
297
+
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];
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);
309
313
  } else {
310
- await this.slide.setSlideState(slideState);
311
- await delay(200);
312
- this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
314
+ this.slide.emit(SLIDE_EVENTS.syncReceive, dispatch);
313
315
  }
316
+ return this.nextTick();
317
+
314
318
  };
315
319
 
316
320
  private onSlideEventHandler = async (event: Y.YMapEvent<any>) => {
@@ -318,7 +322,15 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
318
322
  if (key === 'syncSlide') {
319
323
  if (value.action === 'add' || value.action === 'update') {
320
324
  const { slideState: slideStateFromServer, dispatch: dispatchFromServer } = this.getMap(this.name).get('syncSlide');
321
- this.applySlideState(slideStateFromServer, dispatchFromServer);
325
+ if (this.lastDispatchUuid === dispatchFromServer.uuid) {
326
+ return;
327
+ }
328
+ this.lastDispatchUuid = dispatchFromServer.uuid;
329
+ this.syncMessageQueue.push({
330
+ state: slideStateFromServer,
331
+ dispatch: dispatchFromServer,
332
+ });
333
+ this.applySlideState();
322
334
  }
323
335
  }
324
336
  }
@@ -359,24 +371,27 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
359
371
  this.taskId = option.taskId;
360
372
  const whiteboardApp = new WhiteboardApplication();
361
373
  // @ts-ignore
362
- whiteboardApp.roomDoc = this.roomDoc;
374
+ whiteboardApp.appDoc = this.appDoc;
363
375
  // @ts-ignore
364
- whiteboardApp.appId = `${option.taskId}_${this.appId}_wb`;
376
+ whiteboardApp.appId = `${this.appId}_wb`;
365
377
  // @ts-ignore
366
378
  whiteboardApp.userId = this.userId;
367
379
  // @ts-ignore
368
380
  whiteboardApp.userManager = this.userManager;
369
381
  // @ts-ignore
370
- whiteboardApp.applicationManager = this.applicationManager;
382
+ whiteboardApp.deleteSubDoc = this.deleteSubDoc;
371
383
 
372
384
  const json = await fetch(`${option.prefix}/${option.taskId}/jsonOutput/slide-1.json`).then(res => res.json());
373
385
  this.slideCount = json.slideCount;
386
+ this.footer.setTotalPageIndex(this.slideCount);
374
387
  await whiteboardApp.initialize({
375
388
  width: json.width,
376
389
  height: json.height,
390
+ maxScaleRatio: 1,
377
391
  });
378
392
  this.whiteboardApp = whiteboardApp;
379
393
  this.whiteboard = whiteboardApp.emitter;
394
+ this.whiteboard.enableCameraBoundaryHighlight = false;
380
395
  this.whiteboard.enableCameraByMouse = false;
381
396
  this.whiteboard.enableCameraByTouch = false;
382
397
  this.whiteboard.view.style.width = '100%';
@@ -414,6 +429,12 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
414
429
  interactive: true,
415
430
  anchor: this.slideContainer,
416
431
  mode: 'interactive',
432
+ clientId: Math.random().toString(36).substring(2, 15),
433
+ timestamp: () => {
434
+ console.log('timestamp');
435
+ console.log(Date.now, this.calibrationTimestamp, Date.now() - this.calibrationTimestamp);
436
+ return this.calibrationTimestamp;
437
+ },
417
438
  // logger: {
418
439
  // info: console.log,
419
440
  // warn: console.warn,
@@ -432,16 +453,14 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
432
453
 
433
454
  this.slide.on(SLIDE_EVENTS.mainSeqStepStart, (animateIndex: number) => {
434
455
  this.emitter.emit('mainSeqStepStart', animateIndex);
456
+ this.footer.changeIconToPause();
435
457
  });
436
458
 
437
459
  this.slide.on(SLIDE_EVENTS.mainSeqStepEnd, (animateIndex: number) => {
438
460
  this.emitter.emit('mainSeqStepEnd', animateIndex);
461
+ this.footer.changeIconToNextStep();
439
462
  });
440
463
 
441
- this.slide.on(SLIDE_EVENTS.animateStart, () => {
442
- this.sideBar.hidden();
443
- });
444
-
445
464
  this.slide.on(SLIDE_EVENTS.renderError, ({ error, index }) => {
446
465
  if (error.errorType === 'CANVAS_CRASH') {
447
466
  this.slide.renderSlide(index);
@@ -449,21 +468,28 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
449
468
  });
450
469
 
451
470
  this.slide.on(SLIDE_EVENTS.renderStart, (slideIndex) => {
452
- this.whiteboardApp.emitter.view.style.opacity = '0';
453
- this.whiteboardApp.emitter.addPage(`${slideIndex}`);
454
- this.whiteboardApp.emitter.gotoPage(`${slideIndex}`);
455
- this.sideBar.hidden();
456
- const { slideState: slideStateFromServer, dispatch: dispatchFromServer } = this.getMap(this.name).get('syncSlide');
457
- this.applySlideState(slideStateFromServer, dispatchFromServer);
458
- this.emitter.emit('renderStart', slideIndex);
471
+ if (slideIndex >= 0) {
472
+ this.sideBar.pauseGetPreviewImageSchedule();
473
+ this.whiteboardApp.emitter.view.style.opacity = '0';
474
+ this.whiteboardApp.emitter.addPage(`${slideIndex}`);
475
+ this.whiteboardApp.emitter.gotoPage(`${slideIndex}`);
476
+ this.sideBar.hidden();
477
+ this.footer.changeIconToPause();
478
+ this.emitter.emit('renderStart', slideIndex);
479
+ }
459
480
  });
460
481
 
461
482
  this.slide.on(SLIDE_EVENTS.renderEnd, (slideIndex) => {
462
- this.currentSlideIndex = slideIndex;
463
- this.whiteboardApp.emitter.view.style.opacity = '1';
464
- // slidePool.active(this.appId, this.slide);
465
- // slidePool.onRenderEnd(this.appId, this.window?.focused ?? false);
466
- this.emitter.emit('renderEnd', slideIndex);
483
+ if (slideIndex >= 0) {
484
+ this.sideBar.startGetPreviewImageSchedule();
485
+ this.currentSlideIndex = slideIndex;
486
+ this.whiteboardApp.emitter.view.style.opacity = '1';
487
+ this.footer.setCurrentPageIndex(slideIndex);
488
+ // slidePool.active(this.appId, this.slide);
489
+ // slidePool.onRenderEnd(this.appId, this.window?.focused ?? false);
490
+ this.footer.changeIconToNextStep();
491
+ this.emitter.emit('renderEnd', slideIndex);
492
+ }
467
493
  });
468
494
 
469
495
  this.slide.on(SLIDE_EVENTS.stateChange, (state) => {
@@ -476,6 +502,10 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
476
502
  (window as any).slideWhiteboard = this.whiteboardApp;
477
503
  (window as any).forgeSlide = this;
478
504
 
505
+ this.whiteboardContainer.addEventListener('click', () => {
506
+ this.sideBar.hidden();
507
+ }, false);
508
+
479
509
  const syncSlide = this.getMap(this.name).get('slideState');
480
510
  if (syncSlide && syncSlide.taskId === option.taskId) {
481
511
  this.slide.setSlideState(syncSlide);
@@ -519,6 +549,7 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
519
549
  this.onRefocusInstance();
520
550
  }
521
551
  });
552
+ this.bindKeyBoardEvent();
522
553
  }
523
554
  // @ts-ignore
524
555
  window.__forge_slide = this;
@@ -531,8 +562,11 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
531
562
  return this.getMap(`user/${userId}`);
532
563
  }
533
564
 
534
- public async dispose(): Promise<void> {
535
- await this.whiteboardApp.dispose();
565
+ public async dispose(removeSubDoc: boolean): Promise<void> {
566
+ if (removeSubDoc) {
567
+ this.deleteSubDoc(this.appId);
568
+ }
569
+ await this.whiteboardApp.dispose(removeSubDoc);
536
570
  this.rootView.parentElement?.removeChild(this.rootView);
537
571
  this.slide.destroy();
538
572
  this.sideBar.dispose();
@@ -542,4 +576,4 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
542
576
  // slidePool.remove(this.appId);
543
577
  }
544
578
 
545
- }
579
+ }