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

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.
package/package.json CHANGED
@@ -1,19 +1,20 @@
1
1
  {
2
2
  "name": "@netless/forge-slide",
3
- "version": "0.1.0",
3
+ "version": "0.1.1-alpha.0",
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.15",
10
+ "uuid": "^11.0.5",
11
+ "@netless/forge-room": "0.1.8",
12
+ "@netless/forge-whiteboard": "0.1.14"
10
13
  },
11
14
  "peerDependencies": {
12
15
  "eventemitter3": "^5.0.1",
13
16
  "yjs": "^13.6.18",
14
- "uuid": "^11.0.5",
15
- "@netless/forge-room": "0.1.8",
16
- "@netless/forge-whiteboard": "0.1.14"
17
+ "@netless/forge-room": "0.1.8"
17
18
  },
18
19
  "keywords": [],
19
20
  "author": "",
package/src/Slide.ts CHANGED
@@ -22,6 +22,18 @@ export interface SlideEvents {
22
22
  * @param {number} pageIndex 页面索引
23
23
  */
24
24
  renderEnd: (pageIndex: number) => void;
25
+
26
+ /**
27
+ * 主序列动画完成时触发
28
+ * @param {number} animateIndex 主动画索引
29
+ */
30
+ mainSeqStepEnd: (animateIndex: number) => void;
31
+
32
+ /**
33
+ * 主序列动画开始时触发
34
+ * @param {number} animateIndex 主动画索引
35
+ */
36
+ mainSeqStepStart: (animateIndex: number) => void;
25
37
  }
26
38
 
27
39
 
@@ -29,11 +41,54 @@ export class SlideForge extends EventEmitter<SlideEvents> implements Application
29
41
 
30
42
  public readonly view!: HTMLDivElement;
31
43
  public readonly permissions!: ForgeSlidePermissions;
44
+ public readonly footView!: HTMLDivElement;
45
+ /**
46
+ * 当前页面索引, 从 0 开始
47
+ */
32
48
  public readonly pageIndex!: number;
33
-
49
+ /**
50
+ * 总页数
51
+ */
52
+ public readonly pageCount!: number;
34
53
  /**
35
54
  * 切换到参数指定页面, index 从 0 开始
36
55
  * @param {number} index 页面索引
37
56
  */
38
- public goto!: (index: number) => Promise<void>
57
+ public goto!: (index: number) => void
58
+ /**
59
+ * 下一步, 如果已经是本页的最后一步, 则切换到下一页
60
+ */
61
+ public nextStep!: () => void
62
+ /**
63
+ * 上一步, 如果已经是本页的第一步, 则切换到上一页
64
+ */
65
+ public prevStep!: () => void
66
+ /**
67
+ * 下一页, 如果是最后一页, 则不执行任何操作
68
+ */
69
+ public nextPage!: () => void
70
+ /**
71
+ * 上一页, 如果是第一页, 则不执行任何操作
72
+ */
73
+ public prevPage!: () => void
74
+ /**
75
+ * 切换侧栏显示状态
76
+ */
77
+ public sideBarToggle!: () => void
78
+
79
+ /**
80
+ * 获取预览图图片内容, base64 编码
81
+ * @param {number} index 页面索引
82
+ */
83
+ public imgContent!: (index: number) => Promise<string>;
84
+ /**
85
+ * 获取预览图图片链接
86
+ * @param {number} index 页面索引
87
+ */
88
+ public imgUrl!: (index: number) => Promise<string>;
89
+ /**
90
+ * 获取预览图图片尺寸
91
+ * @param {number} index 页面索引
92
+ */
93
+ public imgSize!: (index: number) => Promise<{width: number, height: number}>;
39
94
  }
@@ -7,6 +7,7 @@ import {FooterView} from "./FoorerView";
7
7
  import * as Y from "yjs";
8
8
  import {SideBarView} from "./SiderBarView";
9
9
  import {deepEqual, delay} from "./utils";
10
+ import { kvStore } from "@netless/forge-room";
10
11
 
11
12
  export interface SlideApplicationOption {
12
13
  prefix: string;
@@ -18,6 +19,13 @@ export interface SlideApplicationOption {
18
19
  inheritWhiteboardId?: string;
19
20
  }
20
21
 
22
+ interface PreviewImage {
23
+ url: string;
24
+ src: string;
25
+ width: number;
26
+ height: number;
27
+ }
28
+
21
29
  export const Slide_APP_NAME = "forge_slide";
22
30
 
23
31
  export class SlideApplication extends AbstractApplication<SlideApplicationOption, SlideForge> {
@@ -25,6 +33,7 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
25
33
  static applicationName = Slide_APP_NAME;
26
34
 
27
35
  public readonly name: string = Slide_APP_NAME;
36
+ public readonly emitter: SlideForge = new SlideForge();
28
37
 
29
38
  private whiteboardApp!: WhiteboardApplication;
30
39
  private whiteboard!: Whiteboard;
@@ -37,9 +46,12 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
37
46
  private sideBar: SideBarView;
38
47
  private slide!: Slide;
39
48
  private currentSlideIndex: number = 0;
49
+ private taskId: string = "";
50
+ private prefix: string = "";
40
51
 
41
52
  constructor() {
42
53
  super();
54
+ (window as any).emitter = this.emitter;
43
55
  this.rootView.setAttribute("data-forge-app", Slide_APP_NAME);
44
56
  this.rootView.style.background = "#f0f0f0f0";
45
57
  this.rootView.style.overflow = "hidden";
@@ -56,7 +68,9 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
56
68
  this.footer = new FooterView();
57
69
  this.sideBar = new SideBarView();
58
70
  this.sideBar.on("pageChange", index => {
59
- this.slide.renderSlide(index);
71
+ if (index > 0 && index <= this.slide.slideCount) {
72
+ this.slide.renderSlide(index);
73
+ }
60
74
  });
61
75
  this.footer.on("prevStep", () => {
62
76
  if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changeStep)) {
@@ -114,6 +128,10 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
114
128
 
115
129
  this.rootView.appendChild(this.contentContainer);
116
130
 
131
+ this.permissions.on("change", (userId, flags, value) => {
132
+ this.emitter.emit("permissionChange", userId, flags, value);
133
+ })
134
+
117
135
  this.emitter.on("renderStart", pageIndex => {
118
136
  this.footer.prevPageState(pageIndex !== 0);
119
137
  });
@@ -129,34 +147,154 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
129
147
  return that.permissions;
130
148
  }
131
149
  });
150
+ Object.defineProperty(this.emitter, "footView", {
151
+ get(): any {
152
+ return that.footer.root;
153
+ }
154
+ })
132
155
  Object.defineProperty(this.emitter, "pageIndex", {
133
156
  get(): any {
134
157
  return that.currentSlideIndex;
135
158
  }
136
159
  });
137
- Object.defineProperty(this.emitter, "goto", {
160
+ Object.defineProperty(this.emitter, "pageCount", {
138
161
  get(): any {
139
- return (index: number) => {
140
- if (index > 0 && index < this.slide.slideCount) {
141
- this.slide.renderSlide(index);
142
- }
143
- };
162
+ return that.slide.slideCount;
163
+ }
164
+ });
165
+ Object.defineProperty(this.emitter, "goto", {
166
+ writable: false,
167
+ enumerable: false,
168
+ value: (pageIndex: number) => {
169
+ this.sideBar.emit("pageChange", pageIndex);
170
+ }
171
+ });
172
+ Object.defineProperty(this.emitter, "nextStep", {
173
+ writable: false,
174
+ enumerable: false,
175
+ value: () => {
176
+ this.footer.emit("nextStep");
177
+ }
178
+ })
179
+ Object.defineProperty(this.emitter, "prevStep", {
180
+ writable: false,
181
+ enumerable: false,
182
+ value: () => {
183
+ this.footer.emit("prevStep");
184
+ }
185
+ })
186
+ Object.defineProperty(this.emitter, "nextPage", {
187
+ writable: false,
188
+ enumerable: false,
189
+ value: () => {
190
+ this.footer.emit("nextPage");
191
+ }
192
+ })
193
+ Object.defineProperty(this.emitter, "prevPage", {
194
+ writable: false,
195
+ enumerable: false,
196
+ value: () => {
197
+ this.footer.emit("prevPage");
198
+ }
199
+ })
200
+ Object.defineProperty(this.emitter, "sideBarToggle", {
201
+ writable: false,
202
+ enumerable: false,
203
+ value: () => {
204
+ this.footer.emit("sideBarToggle");
205
+ }
206
+ })
207
+ Object.defineProperty(this.emitter, "imgContent", {
208
+ writable: false,
209
+ enumerable: false,
210
+ value: (pageIndex: number) => {
211
+ return this.getImageContent(pageIndex);
144
212
  }
213
+ })
214
+
215
+ Object.defineProperty(this.emitter, "imgUrl", {
216
+ writable: false,
217
+ enumerable: false,
218
+ value: (pageIndex: number) => {
219
+ return this.getImageUrl(pageIndex);
220
+ }
221
+ })
222
+
223
+ Object.defineProperty(this.emitter, "imgSize", {
224
+ writable: false,
225
+ enumerable: false,
226
+ value: (pageIndex: number) => {
227
+ return this.getImageSize(pageIndex);
228
+ }
229
+ })
230
+ }
231
+
232
+ private async getPreviewImage(imageUrl: string) {
233
+ const image = fetch(imageUrl);
234
+ return await image.then(res => res.blob()).then(blob => {
235
+ return new Promise<PreviewImage>(resolve => {
236
+ const reader = new FileReader();
237
+ reader.onloadend = () => {
238
+ const base64Data = reader.result as string;
239
+ const img = document.createElement("img");
240
+ img.src = base64Data;
241
+ img.onload = () => {
242
+ resolve({
243
+ url: imageUrl,
244
+ src: base64Data,
245
+ width: img.width,
246
+ height: img.height,
247
+ });
248
+ }
249
+ }
250
+ reader.readAsDataURL(blob);
251
+ })
145
252
  });
146
253
  }
147
254
 
148
- emitter: SlideForge = new SlideForge();
255
+ private async getImageUrl(pageIndex: number) {
256
+ return `${this.prefix}/${this.taskId}/preview/${pageIndex + 1}.png`;
257
+ }
258
+
259
+ private async getImageSize(pageIndex: number) {
260
+ const imageUrl = `${this.prefix}/${this.taskId}/preview/${pageIndex + 1}.png`;
261
+ let preview: PreviewImage | null = null;
262
+ try {
263
+ const result = await kvStore.getItem(imageUrl);
264
+ preview = result ? JSON.parse(result) : null;
265
+ } catch (e) {
266
+ console.warn("kvStore getItem error", e);
267
+ }
268
+ if (preview) {
269
+ return { width: preview.width, height: preview.height };
270
+ }
271
+ preview = await this.getPreviewImage(imageUrl);
272
+ await kvStore.setItem(imageUrl, JSON.stringify(preview));
273
+ return { width: preview.width, height: preview.height };
274
+ }
275
+
276
+ private async getImageContent(pageIndex: number) {
277
+ const imageUrl = `${this.prefix}/${this.taskId}/preview/${pageIndex + 1}.png`;
278
+ let preview: PreviewImage | null = null;
279
+ try {
280
+ const result = await kvStore.getItem(imageUrl);
281
+ preview = result ? JSON.parse(result) : null;
282
+ } catch (e) {
283
+ console.warn("kvStore getItem error", e);
284
+ }
285
+ if (preview) {
286
+ return preview.src;
287
+ }
288
+ preview = await this.getPreviewImage(imageUrl);
289
+ await kvStore.setItem(imageUrl, JSON.stringify(preview));
290
+ return preview.src;
291
+ }
149
292
 
150
293
  private applySlideState = async (slideState: any, lastDispatch: any) => {
151
- // console.log('%cstate', 'color: blue; font-size: 20px;');
152
- // console.log(slideStateFromServer);
153
- // console.log('%cevent', 'color: blue; font-size: 20px;');
154
- // console.log(dispatchFromServer);
155
294
  if (this.slide.slideState.currentSlideIndex < 0) {
156
295
  this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
157
296
  return;
158
297
  }
159
- console.log('%cisEqual', 'color: blue; font-size: 20px;', deepEqual(this.slide.slideState, slideState));
160
298
  if (this.slide.slideState.currentSlideIndex > 0 && deepEqual(this.slide.slideState, slideState)) {
161
299
  this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
162
300
  } else {
@@ -178,6 +316,8 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
178
316
  }
179
317
 
180
318
  public async initialize(option: SlideApplicationOption): Promise<void> {
319
+ this.prefix = option.prefix;
320
+ this.taskId = option.taskId;
181
321
  const whiteboardApp = new WhiteboardApplication();
182
322
  // @ts-ignore
183
323
  whiteboardApp.roomDoc = this.roomDoc;
@@ -220,7 +360,6 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
220
360
 
221
361
  if (option.inheritWhiteboardId) {
222
362
  whiteboardApp.linkToWhiteboard(option.inheritWhiteboardId);
223
- console.log("inheritWhiteboardId", option.inheritWhiteboardId);
224
363
  }
225
364
 
226
365
  this.whiteboard.setViewModeToMain();
@@ -248,25 +387,36 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
248
387
  })
249
388
  })
250
389
 
390
+ this.slide.on("mainSeqStepStart", (animateIndex: number) => {
391
+ this.emitter.emit("mainSeqStepStart", animateIndex);
392
+ })
393
+
394
+ this.slide.on("mainSeqStepEnd", (animateIndex: number) => {
395
+ this.emitter.emit("mainSeqStepEnd", animateIndex);
396
+ })
397
+
251
398
  this.slide.on("renderStart", (slideIndex) => {
252
399
  this.whiteboardApp.emitter.view.style.opacity = "0";
253
400
  this.whiteboardApp.emitter.addPage(`${slideIndex}`);
254
401
  this.whiteboardApp.emitter.gotoPage(`${slideIndex}`);
402
+ this.emitter.emit("renderStart", slideIndex);
255
403
  })
256
404
 
257
405
  this.slide.on("renderEnd", (slideIndex) => {
258
406
  this.currentSlideIndex = slideIndex;
259
407
  this.whiteboardApp.emitter.view.style.opacity = "1";
408
+ this.emitter.emit("renderEnd", slideIndex);
260
409
  });
261
410
 
262
- this.slide.on("stateChange", (state) => {
263
- this.getMap(this.name).set("slideState", state)
264
- })
411
+ this.slide.on("stateChange", (state) => {
412
+ this.getMap(this.name).set("slideState", state)
413
+ })
265
414
 
266
415
  this.getMap(this.name).observe(this.onSlideEventHandler);
267
416
 
268
417
  (window as any).slide = this.slide;
269
418
  (window as any).slideWhiteboard = this.whiteboardApp;
419
+ (window as any).forgeSlide = this;
270
420
 
271
421
  const syncSlide = this.getMap(this.name).get("slideState");
272
422
  if (syncSlide && syncSlide.taskId === option.taskId) {
@@ -279,7 +429,6 @@ export class SlideApplication extends AbstractApplication<SlideApplicationOption
279
429
  return this.userMap(userId);
280
430
  });
281
431
  this.permissions.on("change", (userId, flags, value) => {
282
- console.log(userId, flags, value);
283
432
  if (this.userId === userId) {
284
433
  if (flags.includes(ForgeSlidePermissionFlag.clickAnim)) {
285
434
  this.slideContainer.style.pointerEvents = "auto";