@netless/forge-slide 0.1.1-alpha.10 → 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 +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,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/forge-slide",
3
- "version": "0.1.1-alpha.10",
3
+ "version": "0.1.1-alpha.11",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
@@ -12,8 +12,8 @@
12
12
  "eventemitter3": "^5.0.1",
13
13
  "yjs": "^13.6.18",
14
14
  "uuid": "^11.0.5",
15
- "@netless/forge-room": "0.1.12-alpha.0",
16
- "@netless/forge-whiteboard": "0.1.15"
15
+ "@netless/forge-room": "0.1.12-alpha.1",
16
+ "@netless/forge-whiteboard": "0.1.20-alpha.1"
17
17
  },
18
18
  "keywords": [],
19
19
  "author": "",
@@ -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();
@@ -32,56 +38,123 @@ export class SideBarView extends EventEmitter<SideBarViewEvents> {
32
38
  return this.isShow;
33
39
  }
34
40
 
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);
41
+ public async getPreviewImage(imageUrl: string) {
42
+ const image = await fetch(imageUrl);
43
+ const blob = await image.blob();
44
+ return new Promise<PreviewImage>(resolve => {
45
+ const reader = new FileReader();
46
+ reader.onloadend = () => {
47
+ const base64Data = reader.result as string;
48
+ const img = document.createElement('img');
49
+ img.src = base64Data;
50
+ img.onload = () => {
51
+ resolve({
52
+ url: imageUrl,
53
+ src: base64Data,
54
+ width: img.width,
55
+ height: img.height,
56
+ });
57
+ };
55
58
  };
59
+ reader.readAsDataURL(blob);
60
+ });
61
+ }
62
+
63
+ private async appendPreviewImage(pageIndex: number) {
64
+ const itemContainer = document.createElement('div');
65
+ itemContainer.style.width = '60%';
66
+ itemContainer.style.display = 'flex';
67
+ itemContainer.style.justifyContent = 'center';
68
+ itemContainer.style.alignItems = 'flex-start';
69
+ itemContainer.style.position = 'relative';
70
+ itemContainer.style.borderRadius = '4px';
71
+ itemContainer.style.transition = 'border-color .3s';
72
+ itemContainer.style.marginBottom = '10px';
73
+
74
+ const onMouseOverHandle = () => {
75
+ itemContainer.style.borderColor = '#ccc';
76
+ };
77
+ const onMouseOutHandle = () => {
78
+ itemContainer.style.borderColor = 'transparent';
79
+ };
80
+ const onClickHandle = () => {
81
+ this.emit('pageChange', pageIndex);
82
+ };
56
83
 
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);
84
+ itemContainer.addEventListener('click', onClickHandle);
85
+ itemContainer.addEventListener('mouseover', onMouseOverHandle);
86
+ itemContainer.addEventListener('mouseout', onMouseOutHandle);
87
+ this.eventsMap.set(itemContainer, [onClickHandle, onMouseOverHandle, onMouseOutHandle]);
88
+
89
+ const pageIndexContainer = document.createElement('span');
90
+ pageIndexContainer.textContent = `${pageIndex}`;
91
+ pageIndexContainer.style.position = 'absolute';
92
+ pageIndexContainer.style.top = '1px';
93
+ pageIndexContainer.style.left = '-10px';
94
+ pageIndexContainer.style.transform = 'translate(-100%)';
95
+ pageIndexContainer.style.fontSize = '12px';
96
+ pageIndexContainer.style.color = '#5f5f5f';
97
+
98
+ const previewUrl = `${this.prefix}/${this.taskId}/preview/${pageIndex}.png`;
99
+ const preview = document.createElement('img');
100
+ const cachePreview = await kvStore.getItem(previewUrl);
101
+ if (cachePreview) {
102
+ const { src } = JSON.parse(cachePreview);
103
+ preview.src = src;
104
+ } else {
105
+ const previewInfo = await this.getPreviewImage(previewUrl);
106
+ await kvStore.setItem(previewUrl, JSON.stringify(previewInfo));
107
+ const { src } = previewInfo;
108
+ preview.src = src;
80
109
  }
110
+
111
+ preview.style.width = '100%';
112
+ preview.style.display = 'inline-block';
113
+
114
+ itemContainer.appendChild(preview);
115
+ itemContainer.appendChild(pageIndexContainer);
116
+
117
+ this.root.appendChild(itemContainer);
118
+ }
119
+
120
+ private async scheduleGetPreviewImage() {
121
+ if (!this.isSchedule) {
122
+ this.scheduleId = setTimeout(async () => {
123
+ await this.scheduleGetPreviewImage();
124
+ }, 32) as unknown as number;
125
+ return;
126
+ }
127
+ const pageIndex = this.addImagesPool.shift();
128
+ if (!pageIndex) {
129
+ clearTimeout(this.scheduleId);
130
+ this.scheduleId = 0;
131
+ return;
132
+ }
133
+ await this.appendPreviewImage(pageIndex);
134
+ this.scheduleId = setTimeout(async () => {
135
+ await this.scheduleGetPreviewImage();
136
+ }, 32) as unknown as number;
137
+ }
138
+
139
+ public async startGetPreviewImageSchedule() {
140
+ this.isSchedule = true;
141
+ }
142
+
143
+ public pauseGetPreviewImageSchedule() {
144
+ this.isSchedule = false;
145
+ }
146
+
147
+ public initialize(slideCount: number, option: SlideApplicationOption): void {
148
+ this.taskId = option.taskId;
149
+ this.prefix = option.prefix;
150
+ for (let i = 1; i <= slideCount; i++) {
151
+ this.addImagesPool.push(i);
152
+ }
153
+ this.scheduleGetPreviewImage();
81
154
  }
82
155
 
83
156
  public hidden() {
84
- if (!this.root) {
157
+ if (!this.root || !this.isShow) {
85
158
  return;
86
159
  }
87
160
  this.root.style.left = '-240px';
@@ -109,5 +182,11 @@ export class SideBarView extends EventEmitter<SideBarViewEvents> {
109
182
  element.removeEventListener('mouseout', mouseOutEvent);
110
183
  });
111
184
  }
185
+ }
112
186
 
113
- }
187
+ interface PreviewImage {
188
+ url: string;
189
+ src: string;
190
+ width: number;
191
+ height: number;
192
+ }
@@ -56,7 +56,7 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
56
56
  super();
57
57
  (window as any).emitter = this.emitter;
58
58
  this.rootView.setAttribute('data-forge-app', Slide_APP_NAME);
59
- this.rootView.style.background = '#f0f0f0f0';
59
+ this.rootView.style.background = '#f9f9fc';
60
60
  this.rootView.style.overflow = 'hidden';
61
61
 
62
62
  this.contentContainer.style.width = '100%';
@@ -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,7 +271,7 @@ 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
  }
@@ -321,11 +298,15 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
321
298
  this.syncMessageQueue = [];
322
299
  this.isSyncing = true;
323
300
  const { state, dispatch } = lastSyncMessage;
324
- if (this.slide.slideState.currentSlideIndex < 0) {
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) {
325
306
  // @ts-ignore
326
307
  await this.slide.receiveSyncHandler(dispatch);
327
308
  return this.nextTick();
328
- } else if (!deepEqual(this.slide.slideState, state)) {
309
+ } else if (!deepEqual(this.slide.slideState, state, ignoreKeys)) {
329
310
  await this.slide.setSlideState(state);
330
311
  // @ts-ignore
331
312
  await this.slide.receiveSyncHandler(dispatch);
@@ -390,15 +371,15 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
390
371
  this.taskId = option.taskId;
391
372
  const whiteboardApp = new WhiteboardApplication();
392
373
  // @ts-ignore
393
- whiteboardApp.roomDoc = this.roomDoc;
374
+ whiteboardApp.appDoc = this.appDoc;
394
375
  // @ts-ignore
395
- whiteboardApp.appId = `${option.taskId}_${this.appId}_wb`;
376
+ whiteboardApp.appId = `${this.appId}_wb`;
396
377
  // @ts-ignore
397
378
  whiteboardApp.userId = this.userId;
398
379
  // @ts-ignore
399
380
  whiteboardApp.userManager = this.userManager;
400
381
  // @ts-ignore
401
- whiteboardApp.applicationManager = this.applicationManager;
382
+ whiteboardApp.deleteSubDoc = this.deleteSubDoc;
402
383
 
403
384
  const json = await fetch(`${option.prefix}/${option.taskId}/jsonOutput/slide-1.json`).then(res => res.json());
404
385
  this.slideCount = json.slideCount;
@@ -445,6 +426,12 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
445
426
  interactive: true,
446
427
  anchor: this.slideContainer,
447
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
+ },
448
435
  // logger: {
449
436
  // info: console.log,
450
437
  // warn: console.warn,
@@ -469,10 +456,6 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
469
456
  this.emitter.emit('mainSeqStepEnd', animateIndex);
470
457
  });
471
458
 
472
- this.slide.on(SLIDE_EVENTS.animateStart, () => {
473
- this.sideBar.hidden();
474
- });
475
-
476
459
  this.slide.on(SLIDE_EVENTS.renderError, ({ error, index }) => {
477
460
  if (error.errorType === 'CANVAS_CRASH') {
478
461
  this.slide.renderSlide(index);
@@ -480,19 +463,25 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
480
463
  });
481
464
 
482
465
  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);
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
+ }
488
474
  });
489
475
 
490
476
  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);
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
+ }
496
485
  });
497
486
 
498
487
  this.slide.on(SLIDE_EVENTS.stateChange, (state) => {
@@ -505,6 +494,10 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
505
494
  (window as any).slideWhiteboard = this.whiteboardApp;
506
495
  (window as any).forgeSlide = this;
507
496
 
497
+ this.whiteboardContainer.addEventListener('click', () => {
498
+ this.sideBar.hidden();
499
+ }, false);
500
+
508
501
  const syncSlide = this.getMap(this.name).get('slideState');
509
502
  if (syncSlide && syncSlide.taskId === option.taskId) {
510
503
  this.slide.setSlideState(syncSlide);
@@ -548,6 +541,7 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
548
541
  this.onRefocusInstance();
549
542
  }
550
543
  });
544
+ this.bindKeyBoardEvent();
551
545
  }
552
546
  // @ts-ignore
553
547
  window.__forge_slide = this;
@@ -560,8 +554,11 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
560
554
  return this.getMap(`user/${userId}`);
561
555
  }
562
556
 
563
- public async dispose(): Promise<void> {
564
- await this.whiteboardApp.dispose();
557
+ public async dispose(removeSubDoc: boolean): Promise<void> {
558
+ if (removeSubDoc) {
559
+ this.deleteSubDoc(this.appId);
560
+ }
561
+ await this.whiteboardApp.dispose(removeSubDoc);
565
562
  this.rootView.parentElement?.removeChild(this.rootView);
566
563
  this.slide.destroy();
567
564
  this.sideBar.dispose();
@@ -571,4 +568,4 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
571
568
  // slidePool.remove(this.appId);
572
569
  }
573
570
 
574
- }
571
+ }
package/src/utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- export function deepEqual(a: any, b: any, excludeKeys: string[] = ['time']) {
1
+ export function deepEqual(a: any, b: any, excludeKeys: string[] = ['mediaState']) {
2
2
  // 严格相等检查
3
3
  if (a === b) return true;
4
4
 
@@ -59,4 +59,4 @@ function arrayEqual(arr1: any[], arr2: any[]) {
59
59
  return true;
60
60
  }
61
61
 
62
- export async function delay(time: number): Promise<void> { return new Promise(resolve => setTimeout(resolve, time)); }
62
+ export async function delay(time: number): Promise<void> { return new Promise(resolve => setTimeout(resolve, time)); }