@netless/forge-slide 0.1.1-alpha.1 → 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.
- package/build.mjs +21 -21
- package/dist/FooterView.d.ts +26 -0
- package/dist/FooterView.d.ts.map +1 -0
- package/dist/ForgeSlidePermession.d.ts +7 -46
- package/dist/ForgeSlidePermession.d.ts.map +1 -1
- package/dist/SiderBarView.d.ts +23 -6
- package/dist/SiderBarView.d.ts.map +1 -1
- package/dist/Slide.d.ts +30 -29
- package/dist/Slide.d.ts.map +1 -1
- package/dist/SlideApplication.d.ts +15 -5
- package/dist/SlideApplication.d.ts.map +1 -1
- package/dist/SlidePool.d.ts +22 -0
- package/dist/SlidePool.d.ts.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.esm.js +1840 -966
- package/dist/index.esm.js.map +4 -4
- package/dist/index.js +1832 -958
- package/dist/index.js.map +4 -4
- package/dist/utils.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/FooterView.ts +132 -0
- package/src/ForgeSlidePermession.ts +13 -120
- package/src/SiderBarView.ts +174 -73
- package/src/Slide.ts +29 -28
- package/src/SlideApplication.ts +531 -419
- package/src/SlidePool.ts +110 -0
- package/src/icons.ts +5 -5
- package/src/index.ts +4 -4
- package/src/utils.ts +43 -43
- package/src/FoorerView.ts +0 -109
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,26 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netless/forge-slide",
|
|
3
|
-
"version": "0.1.1-alpha.
|
|
3
|
+
"version": "0.1.1-alpha.11",
|
|
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.
|
|
10
|
-
"uuid": "^11.0.5",
|
|
11
|
-
"@netless/forge-room": "0.1.8",
|
|
12
|
-
"@netless/forge-whiteboard": "0.1.14"
|
|
9
|
+
"@netless/slide": "^1.4.21"
|
|
13
10
|
},
|
|
14
11
|
"peerDependencies": {
|
|
15
12
|
"eventemitter3": "^5.0.1",
|
|
16
13
|
"yjs": "^13.6.18",
|
|
17
|
-
"
|
|
14
|
+
"uuid": "^11.0.5",
|
|
15
|
+
"@netless/forge-room": "0.1.12-alpha.1",
|
|
16
|
+
"@netless/forge-whiteboard": "0.1.20-alpha.1"
|
|
18
17
|
},
|
|
19
18
|
"keywords": [],
|
|
20
19
|
"author": "",
|
|
21
20
|
"license": "ISC",
|
|
22
21
|
"scripts": {
|
|
23
22
|
"dev": "onChange 'src/**/*' -- npm run build",
|
|
24
|
-
"build": "tsc --emitDeclarationOnly && node build.mjs"
|
|
23
|
+
"build": "pnpm lint && tsc --emitDeclarationOnly && node build.mjs",
|
|
24
|
+
"lint": "eslint src"
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import EventEmitter from 'eventemitter3';
|
|
2
|
+
import { Icons } from './icons';
|
|
3
|
+
|
|
4
|
+
interface FooterViewEvents {
|
|
5
|
+
prevPage: () => void;
|
|
6
|
+
nextPage: () => void;
|
|
7
|
+
prevStep: () => void;
|
|
8
|
+
nextStep: () => void;
|
|
9
|
+
sideBarToggle: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const EM_COLOR = '#8C8C8C';
|
|
13
|
+
|
|
14
|
+
export class FooterView extends EventEmitter<FooterViewEvents> {
|
|
15
|
+
|
|
16
|
+
public readonly root: HTMLDivElement;
|
|
17
|
+
|
|
18
|
+
private prevStep: HTMLDivElement;
|
|
19
|
+
private nextStep: HTMLDivElement;
|
|
20
|
+
|
|
21
|
+
private prevPage: HTMLDivElement;
|
|
22
|
+
private nextPage: HTMLDivElement;
|
|
23
|
+
|
|
24
|
+
private sideBarToggle: HTMLDivElement;
|
|
25
|
+
|
|
26
|
+
private eventMap: Map<HTMLDivElement, (() => void)[]> = new Map();
|
|
27
|
+
|
|
28
|
+
public constructor() {
|
|
29
|
+
super();
|
|
30
|
+
this.root = document.createElement('div');
|
|
31
|
+
this.root.classList.add('forge-slide-footer');
|
|
32
|
+
this.root.style.height = '24px';
|
|
33
|
+
this.root.style.zIndex = '6';
|
|
34
|
+
this.root.style.display = 'flex';
|
|
35
|
+
this.root.style.alignItems = 'center';
|
|
36
|
+
this.root.style.justifyContent = 'center';
|
|
37
|
+
this.root.style.backgroundColor = '#fff';
|
|
38
|
+
|
|
39
|
+
this.prevStep = this.createIcon(Icons.prevStep(EM_COLOR), () => {
|
|
40
|
+
this.emit('prevStep');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
this.nextStep = this.createIcon(Icons.nextStep(EM_COLOR), () => {
|
|
44
|
+
this.emit('nextStep');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
this.prevPage = this.createIcon(Icons.prevPage(EM_COLOR), () => {
|
|
48
|
+
this.emit('prevPage');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
this.nextPage = this.createIcon(Icons.nextPage(EM_COLOR), () => {
|
|
52
|
+
this.emit('nextPage');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
this.sideBarToggle = this.createIcon(Icons.sideBar(EM_COLOR), () => {
|
|
56
|
+
this.emit('sideBarToggle');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
this.root.appendChild(this.sideBarToggle);
|
|
60
|
+
this.root.appendChild(this.createSpacer());
|
|
61
|
+
this.root.appendChild(this.prevPage);
|
|
62
|
+
this.root.appendChild(this.prevStep);
|
|
63
|
+
this.root.appendChild(this.nextStep);
|
|
64
|
+
this.root.appendChild(this.nextPage);
|
|
65
|
+
this.root.appendChild(this.createSpacer());
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public prevPageState(enable: boolean): void {
|
|
69
|
+
if (enable) {
|
|
70
|
+
this.prevPage.style.pointerEvents = 'all';
|
|
71
|
+
this.prevPage.style.opacity = '1';
|
|
72
|
+
} else {
|
|
73
|
+
this.prevPage.style.pointerEvents = 'none';
|
|
74
|
+
this.prevPage.style.opacity = '0.5';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
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
|
+
private createSpacer(): HTMLDivElement {
|
|
89
|
+
const div = document.createElement('div');
|
|
90
|
+
div.style.flex = '1 1 auto';
|
|
91
|
+
return div;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private createIcon(svgContent: string, action: () => void): HTMLDivElement {
|
|
95
|
+
const icon = document.createElement('div');
|
|
96
|
+
icon.style.width = '18px';
|
|
97
|
+
icon.style.height = '18px';
|
|
98
|
+
icon.style.borderRadius = '2px';
|
|
99
|
+
icon.style.margin = '6px';
|
|
100
|
+
icon.innerHTML = svgContent;
|
|
101
|
+
const onClickHandle = () => {
|
|
102
|
+
action();
|
|
103
|
+
};
|
|
104
|
+
const onMouseOverHandle = () => {
|
|
105
|
+
icon.style.backgroundColor = '#f0f0f0';
|
|
106
|
+
};
|
|
107
|
+
const onMouseOutHandle = () => {
|
|
108
|
+
icon.style.backgroundColor = 'transparent';
|
|
109
|
+
};
|
|
110
|
+
icon.addEventListener('click', onClickHandle);
|
|
111
|
+
icon.addEventListener('mouseover', onMouseOverHandle);
|
|
112
|
+
icon.addEventListener('mouseout', onMouseOutHandle);
|
|
113
|
+
this.eventMap.set(icon, [onClickHandle, onMouseOutHandle, onMouseOverHandle]);
|
|
114
|
+
return icon;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private clearHTMLEventListeners() {
|
|
118
|
+
this.eventMap.forEach((value, key) => {
|
|
119
|
+
if (key) {
|
|
120
|
+
const [clickEvent, mouseOutEvent, mouseOverEvent] = value;
|
|
121
|
+
key.removeEventListener('click', clickEvent);
|
|
122
|
+
key.removeEventListener('mouseover', mouseOverEvent);
|
|
123
|
+
key.removeEventListener('mouseout', mouseOutEvent);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
dispose() {
|
|
129
|
+
this.removeAllListeners();
|
|
130
|
+
this.clearHTMLEventListeners();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import EventEmitter from "eventemitter3";
|
|
3
|
-
import * as Y from "yjs";
|
|
1
|
+
import { AbstractApplicationPermissions, ApplicationPermissionEvents } from '@netless/forge-room';
|
|
4
2
|
|
|
5
3
|
export enum ForgeSlidePermissionFlag {
|
|
6
4
|
/**
|
|
@@ -27,7 +25,7 @@ export enum ForgeSlidePermissionFlag {
|
|
|
27
25
|
ForgeSlidePermissionFlag.clickAnim
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
export interface ForgeSlidePermissionEvents {
|
|
28
|
+
export interface ForgeSlidePermissionEvents extends ApplicationPermissionEvents {
|
|
31
29
|
/**
|
|
32
30
|
* 当用户权限变更时触发
|
|
33
31
|
* @param { string } userId 对应 userId
|
|
@@ -37,123 +35,18 @@ export interface ForgeSlidePermissionEvents {
|
|
|
37
35
|
change: (userId: string, flags: ForgeSlidePermissionFlag[], value: number) => void;
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
export class ForgeSlidePermissions extends
|
|
41
|
-
|
|
42
|
-
private requestUserMap: (userId: string) => Y.Map<any>;
|
|
43
|
-
private userManager: UserManager;
|
|
44
|
-
private observers: Map<string, any> = new Map();
|
|
45
|
-
|
|
46
|
-
public constructor(
|
|
47
|
-
userManager: UserManager,
|
|
48
|
-
requestUserMap: (userId: string) => Y.Map<any>,
|
|
49
|
-
) {
|
|
50
|
-
super();
|
|
51
|
-
this.userManager = userManager;
|
|
52
|
-
this.requestUserMap = requestUserMap;
|
|
53
|
-
this.createModel(this.userManager.selfId);
|
|
54
|
-
this.userManager.userIdList().forEach((userId) => {
|
|
55
|
-
this.addObserve(userId);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
this.userManager.on("join", this.handleUserJoin);
|
|
59
|
-
this.userManager.on("leave", this.handleUserLeave);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
private handleUserLeave = (user: RoomUser) => {
|
|
63
|
-
const cb = this.observers.get(user.id);
|
|
64
|
-
if (cb) {
|
|
65
|
-
this.requestUserMap(user.id).unobserve(cb);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
private handleUserJoin = (user: RoomUser) => {
|
|
70
|
-
this.addObserve(user.id);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
private addObserve(userId: string) {
|
|
74
|
-
const observer = (evt: Y.YMapEvent<any>) => {
|
|
75
|
-
this.handleUserPermissionChange(userId, evt);
|
|
76
|
-
};
|
|
77
|
-
this.observers.set(userId, observer);
|
|
78
|
-
this.requestUserMap(userId).observe(observer)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
private createModel(userId: string) {
|
|
82
|
-
const userMap = this.requestUserMap(userId);
|
|
83
|
-
if (!userMap.has("permission")) {
|
|
84
|
-
userMap.set("permission", 0);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
private handleUserPermissionChange(userId: string, evt: Y.YMapEvent<any>) {
|
|
89
|
-
for (const [key, value] of evt.changes.keys.entries()) {
|
|
90
|
-
if (key === "permission") {
|
|
91
|
-
if (value.action === "add" || value.action === "update") {
|
|
92
|
-
const newValue = this.requestUserMap(userId).get("permission");
|
|
93
|
-
this.emit("change", userId, this.resolveFlags(newValue), newValue);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
38
|
+
export class ForgeSlidePermissions extends AbstractApplicationPermissions<ForgeSlidePermissionFlag, ForgeSlidePermissionEvents> {
|
|
39
|
+
/**
|
|
100
40
|
* 解析权限列表组合
|
|
101
41
|
* @param {number} value - 权限数字值
|
|
102
42
|
* @return {WhiteboardPermissionFlag[]} - 权限列表
|
|
103
43
|
*/
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
* 获取权限列表组合对应的数值
|
|
114
|
-
* @param { string } userId 不传表示获取自己
|
|
115
|
-
*/
|
|
116
|
-
public getPermissionValue(userId?: string): number {
|
|
117
|
-
return this.requestUserMap(userId ?? this.userManager.selfId).get("permission") ?? 0;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* 获取权限列表
|
|
122
|
-
* @param {string=} userId 可选, 不传表示获取自己
|
|
123
|
-
*/
|
|
124
|
-
public getPermissionFlags(userId?: string): ForgeSlidePermissionFlag[] {
|
|
125
|
-
const value = this.requestUserMap(userId ?? this.userManager.selfId).get("permission") ?? 0;
|
|
126
|
-
return this.resolveFlags(value);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* 返回对应 userId 是否有相应权限
|
|
131
|
-
* @param {string=} userId 可选, 不传表示返回自己是否有相应权限
|
|
132
|
-
* @param {WhiteboardPermissionFlag} flag
|
|
133
|
-
*/
|
|
134
|
-
public hasPermission(flag: ForgeSlidePermissionFlag, userId?: string): boolean {
|
|
135
|
-
return ((this.requestUserMap(userId ?? this.userManager.selfId).get("permission") ?? 0) & flag) !== 0;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* 添加权限
|
|
140
|
-
* @param {WhiteboardPermissionFlag} flag 权限标记
|
|
141
|
-
* @param {string=} userId 可选, 为 userId 添加权限, 不传表示为自己添加权限
|
|
142
|
-
*/
|
|
143
|
-
public addPermission(flag: ForgeSlidePermissionFlag, userId?: string) {
|
|
144
|
-
const userMap = this.requestUserMap(userId ?? this.userManager.selfId);
|
|
145
|
-
const oldValue = userMap.get("permission") ?? 0;
|
|
146
|
-
this.requestUserMap(userId ?? this.userManager.selfId).set("permission", oldValue | flag);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* 移除权限
|
|
151
|
-
* @param {WhiteboardPermissionFlag} flag 权限标记
|
|
152
|
-
* @param {string=} userId 可选, 为 userId 移除权限, 不传表示为自己移除权限
|
|
153
|
-
*/
|
|
154
|
-
public removePermission(flag: ForgeSlidePermissionFlag, userId?: string) {
|
|
155
|
-
const userMap = this.requestUserMap(userId ?? this.userManager.selfId);
|
|
156
|
-
const oldValue = userMap.get("permission") ?? 0;
|
|
157
|
-
this.requestUserMap(userId ?? this.userManager.selfId).set("permission", oldValue & (~flag));
|
|
158
|
-
}
|
|
159
|
-
}
|
|
44
|
+
public resolveFlags(value: number): ForgeSlidePermissionFlag[] {
|
|
45
|
+
return [
|
|
46
|
+
ForgeSlidePermissionFlag.changePage,
|
|
47
|
+
ForgeSlidePermissionFlag.changeStep,
|
|
48
|
+
ForgeSlidePermissionFlag.clickAnim,
|
|
49
|
+
].filter(v => (v & value) !== 0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
}
|
package/src/SiderBarView.ts
CHANGED
|
@@ -1,91 +1,192 @@
|
|
|
1
|
-
import {SlideApplicationOption} from
|
|
2
|
-
import EventEmitter from
|
|
1
|
+
import { SlideApplicationOption } from './SlideApplication';
|
|
2
|
+
import EventEmitter from 'eventemitter3';
|
|
3
|
+
import { kvStore } from '@netless/forge-room';
|
|
3
4
|
|
|
4
5
|
interface SideBarViewEvents {
|
|
5
6
|
pageChange: (index: number) => void;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
export class SideBarView extends EventEmitter<SideBarViewEvents> {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
this.root.style.height = "100%";
|
|
18
|
-
this.root.style.position = "absolute";
|
|
19
|
-
this.root.style.left = "-240px";
|
|
20
|
-
this.root.style.top = "0";
|
|
21
|
-
this.root.style.zIndex = "5";
|
|
22
|
-
this.root.style.transition = "left 0.3s ease-in-out";
|
|
23
|
-
this.root.style.overflow = "auto";
|
|
24
|
-
this.root.style.border = "1px solid #ccc";
|
|
25
|
-
this.root.style.boxShadow = "0 0 10px rgba(0, 0, 0, 0.1)";
|
|
26
|
-
this.root.style.display = "flex";
|
|
27
|
-
this.root.style.flexDirection = "column";
|
|
28
|
-
this.root.style.justifyContent = "flex-start";
|
|
29
|
-
this.root.style.alignItems = "center";
|
|
10
|
+
public readonly root: HTMLDivElement = document.createElement('div');
|
|
11
|
+
private isShow: boolean = false;
|
|
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;
|
|
30
18
|
|
|
31
|
-
|
|
19
|
+
public constructor() {
|
|
20
|
+
super();
|
|
21
|
+
this.root.style.backgroundColor = '#eee';
|
|
22
|
+
this.root.className = 'forge-slide-sidebar';
|
|
23
|
+
this.root.style.width = '240px';
|
|
24
|
+
this.root.style.height = '100%';
|
|
25
|
+
this.root.style.position = 'absolute';
|
|
26
|
+
this.root.style.left = '-240px';
|
|
27
|
+
this.root.style.top = '0';
|
|
28
|
+
this.root.style.zIndex = '5';
|
|
29
|
+
this.root.style.transition = 'left 0.3s ease-in-out';
|
|
30
|
+
this.root.style.overflow = 'auto';
|
|
31
|
+
this.root.style.display = 'flex';
|
|
32
|
+
this.root.style.flexDirection = 'column';
|
|
33
|
+
this.root.style.justifyContent = 'flex-start';
|
|
34
|
+
this.root.style.alignItems = 'center';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get isShowSideBar(): boolean {
|
|
38
|
+
return this.isShow;
|
|
39
|
+
}
|
|
40
|
+
|
|
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
|
+
};
|
|
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';
|
|
32
73
|
|
|
33
|
-
|
|
34
|
-
|
|
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
|
+
};
|
|
83
|
+
|
|
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;
|
|
35
109
|
}
|
|
36
110
|
|
|
37
|
-
|
|
38
|
-
|
|
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;
|
|
39
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
|
+
}
|
|
40
142
|
|
|
41
|
-
|
|
42
|
-
|
|
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);
|
|
43
152
|
}
|
|
153
|
+
this.scheduleGetPreviewImage();
|
|
154
|
+
}
|
|
44
155
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
this.itemList.push(itemContainer);
|
|
49
|
-
itemContainer.style.width = "60%";
|
|
50
|
-
itemContainer.style.display = "flex";
|
|
51
|
-
itemContainer.style.justifyContent = "center";
|
|
52
|
-
itemContainer.style.alignItems = "flex-start";
|
|
53
|
-
itemContainer.style.border = "7px solid transparent";
|
|
54
|
-
itemContainer.style.position = "relative";
|
|
55
|
-
itemContainer.style.borderRadius = "4px"
|
|
56
|
-
itemContainer.style.transition = "border-color .3s";
|
|
57
|
-
itemContainer.style.marginBottom = "10px";
|
|
58
|
-
|
|
59
|
-
itemContainer.addEventListener("mouseover", () => this.onMouseOver(itemContainer))
|
|
60
|
-
itemContainer.addEventListener("mouseout", () => this.onMouseOut(itemContainer))
|
|
61
|
-
itemContainer.addEventListener("click", () => this.onClickHandle(i))
|
|
62
|
-
|
|
63
|
-
const pageIndex = document.createElement("span");
|
|
64
|
-
pageIndex.textContent = `${i}`;
|
|
65
|
-
pageIndex.style.position = "absolute";
|
|
66
|
-
pageIndex.style.top = "1px";
|
|
67
|
-
pageIndex.style.left = "-10px";
|
|
68
|
-
pageIndex.style.transform = "translate(-100%)";
|
|
69
|
-
pageIndex.style.fontSize = "12px";
|
|
70
|
-
pageIndex.style.color = "#5f5f5f";
|
|
71
|
-
|
|
72
|
-
const preview = document.createElement("img");
|
|
73
|
-
preview.style.width = "100%";
|
|
74
|
-
preview.style.display = "inline-block";
|
|
75
|
-
preview.src = `${option.prefix}/${option.taskId}/preview/${i}.png`;
|
|
76
|
-
|
|
77
|
-
itemContainer.appendChild(preview);
|
|
78
|
-
itemContainer.appendChild(pageIndex);
|
|
79
|
-
|
|
80
|
-
this.root.appendChild(itemContainer);
|
|
81
|
-
}
|
|
156
|
+
public hidden() {
|
|
157
|
+
if (!this.root || !this.isShow) {
|
|
158
|
+
return;
|
|
82
159
|
}
|
|
160
|
+
this.root.style.left = '-240px';
|
|
161
|
+
this.root.style.border = 'none';
|
|
162
|
+
this.root.style.boxShadow = 'none';
|
|
163
|
+
this.isShow = false;
|
|
164
|
+
}
|
|
83
165
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
item.removeEventListener("mouseout", () => this.onMouseOut(item))
|
|
88
|
-
})
|
|
166
|
+
public show() {
|
|
167
|
+
if (!this.root) {
|
|
168
|
+
return;
|
|
89
169
|
}
|
|
170
|
+
this.root.style.left = '0';
|
|
171
|
+
this.root.style.border = '1px solid #ccc';
|
|
172
|
+
this.root.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.1)';
|
|
173
|
+
this.isShow = true;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public dispose() {
|
|
177
|
+
this.removeAllListeners();
|
|
178
|
+
this.eventsMap.forEach((handlers, element) => {
|
|
179
|
+
const [clickEvent, mouseOverEvent, mouseOutEvent] = handlers;
|
|
180
|
+
element.removeEventListener('click', clickEvent);
|
|
181
|
+
element.removeEventListener('mouseover', mouseOverEvent);
|
|
182
|
+
element.removeEventListener('mouseout', mouseOutEvent);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
90
186
|
|
|
91
|
-
|
|
187
|
+
interface PreviewImage {
|
|
188
|
+
url: string;
|
|
189
|
+
src: string;
|
|
190
|
+
width: number;
|
|
191
|
+
height: number;
|
|
192
|
+
}
|
package/src/Slide.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import EventEmitter from
|
|
2
|
-
import { ApplicationInstanceType } from
|
|
3
|
-
import { ForgeSlidePermissionFlag, ForgeSlidePermissions } from
|
|
1
|
+
import EventEmitter from 'eventemitter3';
|
|
2
|
+
import { ApplicationInstanceType } from '@netless/forge-room';
|
|
3
|
+
import { ForgeSlidePermissionFlag, ForgeSlidePermissions } from './ForgeSlidePermession';
|
|
4
4
|
|
|
5
5
|
export interface SlideEvents {
|
|
6
6
|
/**
|
|
@@ -39,56 +39,57 @@ export interface SlideEvents {
|
|
|
39
39
|
|
|
40
40
|
export class SlideForge extends EventEmitter<SlideEvents> implements ApplicationInstanceType {
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
public readonly view!: HTMLDivElement;
|
|
43
|
+
public readonly permissions!: ForgeSlidePermissions;
|
|
44
|
+
public readonly footView!: HTMLDivElement;
|
|
45
|
+
public readonly sideBarView!: HTMLDivElement;
|
|
46
|
+
/**
|
|
46
47
|
* 当前页面索引, 从 0 开始
|
|
47
48
|
*/
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
public readonly pageIndex!: number;
|
|
50
|
+
/**
|
|
50
51
|
* 总页数
|
|
51
52
|
*/
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
public readonly pageCount!: number;
|
|
54
|
+
/**
|
|
54
55
|
* 切换到参数指定页面, index 从 0 开始
|
|
55
56
|
* @param {number} index 页面索引
|
|
56
57
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
public goto!: (index: number) => void;
|
|
59
|
+
/**
|
|
59
60
|
* 下一步, 如果已经是本页的最后一步, 则切换到下一页
|
|
60
61
|
*/
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
public nextStep!: () => void;
|
|
63
|
+
/**
|
|
63
64
|
* 上一步, 如果已经是本页的第一步, 则切换到上一页
|
|
64
65
|
*/
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
public prevStep!: () => void;
|
|
67
|
+
/**
|
|
67
68
|
* 下一页, 如果是最后一页, 则不执行任何操作
|
|
68
69
|
*/
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
public nextPage!: () => void;
|
|
71
|
+
/**
|
|
71
72
|
* 上一页, 如果是第一页, 则不执行任何操作
|
|
72
73
|
*/
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
public prevPage!: () => void;
|
|
75
|
+
/**
|
|
75
76
|
* 切换侧栏显示状态
|
|
76
77
|
*/
|
|
77
|
-
|
|
78
|
+
public sideBarToggle!: () => void;
|
|
78
79
|
|
|
79
|
-
|
|
80
|
+
/**
|
|
80
81
|
* 获取预览图图片内容, base64 编码
|
|
81
82
|
* @param {number} index 页面索引
|
|
82
83
|
*/
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
public imgContent!: (index: number) => Promise<string>;
|
|
85
|
+
/**
|
|
85
86
|
* 获取预览图图片链接
|
|
86
87
|
* @param {number} index 页面索引
|
|
87
88
|
*/
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
public imgUrl!: (index: number) => Promise<string>;
|
|
90
|
+
/**
|
|
90
91
|
* 获取预览图图片尺寸
|
|
91
92
|
* @param {number} index 页面索引
|
|
92
93
|
*/
|
|
93
|
-
|
|
94
|
+
public imgSize!: (index: number) => Promise<{width: number, height: number}>;
|
|
94
95
|
}
|