@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.
- package/dist/FoorerView.d.ts +23 -0
- package/dist/FoorerView.d.ts.map +1 -0
- package/dist/FooterView.d.ts +9 -2
- package/dist/FooterView.d.ts.map +1 -1
- package/dist/SiderBarView.d.ts +16 -0
- package/dist/SiderBarView.d.ts.map +1 -1
- package/dist/SlideApplication.d.ts +5 -2
- package/dist/SlideApplication.d.ts.map +1 -1
- package/dist/icons.d.ts +1 -1
- package/dist/icons.d.ts.map +1 -1
- package/dist/index.esm.js +3571 -2361
- package/dist/index.esm.js.map +4 -4
- package/dist/index.js +3568 -2358
- package/dist/index.js.map +4 -4
- package/dist/utils.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/FooterView.ts +50 -18
- package/src/SiderBarView.ts +125 -45
- package/src/SlideApplication.ts +96 -62
- package/src/icons.ts +38 -19
- package/src/utils.ts +2 -2
package/dist/utils.d.ts.map
CHANGED
|
@@ -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,
|
|
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.
|
|
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.
|
|
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
|
|
16
|
-
"@netless/forge-whiteboard": "0.1.
|
|
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
|
-
|
|
40
|
-
|
|
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.
|
|
48
|
-
|
|
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
|
+
}
|
package/src/SiderBarView.ts
CHANGED
|
@@ -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
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
+
}
|
package/src/SlideApplication.ts
CHANGED
|
@@ -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
|
|
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 = '#
|
|
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
|
|
303
|
-
|
|
304
|
-
|
|
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
|
-
|
|
308
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
374
|
+
whiteboardApp.appDoc = this.appDoc;
|
|
363
375
|
// @ts-ignore
|
|
364
|
-
whiteboardApp.appId = `${
|
|
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.
|
|
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
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|
-
|
|
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
|
+
}
|