@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/dist/Slide.d.ts +57 -1
- package/dist/Slide.d.ts.map +1 -1
- package/dist/SlideApplication.d.ts +7 -1
- package/dist/SlideApplication.d.ts.map +1 -1
- package/dist/index.esm.js +192 -11
- package/dist/index.esm.js.map +2 -2
- package/dist/index.js +192 -11
- package/dist/index.js.map +3 -3
- package/package.json +6 -5
- package/src/Slide.ts +57 -2
- package/src/SlideApplication.ts +167 -18
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
|
-
"
|
|
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) =>
|
|
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
|
}
|
package/src/SlideApplication.ts
CHANGED
|
@@ -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.
|
|
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, "
|
|
160
|
+
Object.defineProperty(this.emitter, "pageCount", {
|
|
138
161
|
get(): any {
|
|
139
|
-
return
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
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
|
-
|
|
263
|
-
|
|
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";
|