@netless/window-manager 0.4.0-canary.14 → 0.4.0-canary.18
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/.vscode/settings.json +1 -0
- package/CHANGELOG.md +29 -1
- package/README.md +1 -0
- package/dist/AppListener.d.ts +1 -0
- package/dist/AppManager.d.ts +10 -7
- package/dist/AppProxy.d.ts +3 -2
- package/dist/AttributesDelegate.d.ts +2 -2
- package/dist/BoxManager.d.ts +5 -3
- package/dist/BuiltinApps.d.ts +0 -1
- package/dist/Cursor/Cursor.d.ts +8 -11
- package/dist/Cursor/index.d.ts +5 -15
- package/dist/Register/storage.d.ts +5 -1
- package/dist/Utils/Common.d.ts +4 -1
- package/dist/Utils/RoomHacker.d.ts +1 -1
- package/dist/View/MainView.d.ts +3 -2
- package/dist/constants.d.ts +3 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.es.js +41 -1
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +41 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/docs/api.md +36 -6
- package/docs/concept.md +9 -0
- package/package.json +5 -5
- package/src/AppContext.ts +1 -4
- package/src/AppListener.ts +14 -6
- package/src/AppManager.ts +96 -50
- package/src/AppProxy.ts +13 -8
- package/src/AttributesDelegate.ts +2 -2
- package/src/BoxManager.ts +33 -19
- package/src/BuiltinApps.ts +0 -1
- package/src/Cursor/Cursor.ts +22 -36
- package/src/Cursor/index.ts +33 -135
- package/src/Register/index.ts +25 -16
- package/src/Register/loader.ts +1 -1
- package/src/Register/storage.ts +6 -1
- package/src/Utils/Common.ts +32 -1
- package/src/Utils/RoomHacker.ts +28 -15
- package/src/View/MainView.ts +10 -11
- package/src/constants.ts +3 -2
- package/src/index.ts +61 -2
- package/src/shim.d.ts +2 -1
- package/src/style.css +1 -1
- package/vite.config.js +5 -2
- package/dist/Base/Context.d.ts +0 -12
- package/dist/Base/index.d.ts +0 -7
- package/src/Base/Context.ts +0 -45
- package/src/Base/index.ts +0 -10
package/src/BoxManager.ts
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
import { AppAttributes, Events, MIN_HEIGHT, MIN_WIDTH } from "./constants";
|
2
|
-
import { debounce
|
2
|
+
import { debounce } from "lodash";
|
3
|
+
import { emitter, WindowManager } from "./index";
|
3
4
|
import {
|
4
|
-
TELE_BOX_MANAGER_EVENT,
|
5
5
|
TELE_BOX_STATE,
|
6
6
|
TeleBoxCollector,
|
7
7
|
TeleBoxManager,
|
8
8
|
} from "@netless/telebox-insider";
|
9
|
-
import { emitter, WindowManager } from "./index";
|
10
9
|
import type { AddAppOptions, AppInitState, EmitterType, CallbacksType } from "./index";
|
11
10
|
import type {
|
12
11
|
TeleBoxManagerUpdateConfig,
|
@@ -15,6 +14,7 @@ import type {
|
|
15
14
|
TeleBoxManagerConfig,
|
16
15
|
TeleBoxColorScheme,
|
17
16
|
TeleBoxRect,
|
17
|
+
TeleBoxConfig,
|
18
18
|
} from "@netless/telebox-insider";
|
19
19
|
import type Emittery from "emittery";
|
20
20
|
import type { NetlessApp } from "./typings";
|
@@ -57,6 +57,7 @@ export type BoxManagerContext = {
|
|
57
57
|
canOperate: () => boolean;
|
58
58
|
notifyContainerRectUpdate: (rect: TeleBoxRect) => void;
|
59
59
|
cleanFocus: () => void;
|
60
|
+
setAppFocus: (appId: string) => void;
|
60
61
|
};
|
61
62
|
|
62
63
|
export const createBoxManager = (
|
@@ -74,6 +75,7 @@ export const createBoxManager = (
|
|
74
75
|
notifyContainerRectUpdate: (rect: TeleBoxRect) =>
|
75
76
|
manager.appManager?.notifyContainerRectUpdate(rect),
|
76
77
|
cleanFocus: () => manager.appManager?.store.cleanFocus(),
|
78
|
+
setAppFocus: (appId: string) => manager.appManager?.store.setAppFocus(appId, true),
|
77
79
|
callbacks,
|
78
80
|
emitter,
|
79
81
|
},
|
@@ -90,17 +92,32 @@ export class BoxManager {
|
|
90
92
|
) {
|
91
93
|
const { emitter, callbacks } = context;
|
92
94
|
this.teleBoxManager = this.setupBoxManager(createTeleBoxManagerConfig);
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
95
|
+
|
96
|
+
// 使用 _xxx$.reaction 订阅修改的值, 不管有没有 skipUpdate, 修改值都会触发回调
|
97
|
+
this.teleBoxManager._state$.reaction(state => {
|
98
|
+
callbacks.emit("boxStateChange", state);
|
99
|
+
emitter.emit("boxStateChange", state);
|
100
|
+
});
|
101
|
+
|
102
|
+
this.teleBoxManager._darkMode$.reaction(darkMode => {
|
103
|
+
callbacks.emit("darkModeChange", darkMode);
|
98
104
|
});
|
105
|
+
this.teleBoxManager._prefersColorScheme$.reaction(colorScheme => {
|
106
|
+
callbacks.emit("prefersColorSchemeChange", colorScheme);
|
107
|
+
});
|
108
|
+
|
109
|
+
// events.on 的值则会根据 skipUpdate 来决定是否触发回调
|
99
110
|
this.teleBoxManager.events.on("minimized", minimized => {
|
100
111
|
this.context.safeSetAttributes({ minimized });
|
101
112
|
if (minimized) {
|
102
113
|
this.context.cleanFocus();
|
103
114
|
this.blurAllBox();
|
115
|
+
} else {
|
116
|
+
const topBox = this.getTopBox();
|
117
|
+
if (topBox) {
|
118
|
+
this.context.setAppFocus(topBox.id);
|
119
|
+
this.focusBox({ appId: topBox.id }, false);
|
120
|
+
}
|
104
121
|
}
|
105
122
|
});
|
106
123
|
this.teleBoxManager.events.on("maximized", maximized => {
|
@@ -136,12 +153,6 @@ export class BoxManager {
|
|
136
153
|
}
|
137
154
|
}
|
138
155
|
});
|
139
|
-
this.teleBoxManager.events.on("dark_mode", darkMode => {
|
140
|
-
callbacks.emit("darkModeChange", darkMode);
|
141
|
-
});
|
142
|
-
this.teleBoxManager.events.on("prefers_color_scheme", colorScheme => {
|
143
|
-
callbacks.emit("prefersColorSchemeChange", colorScheme);
|
144
|
-
});
|
145
156
|
this.teleBoxManager.events.on("z_index", box => {
|
146
157
|
this.context.updateAppState(box.id, AppAttributes.ZIndex, box.zIndex);
|
147
158
|
});
|
@@ -150,7 +161,7 @@ export class BoxManager {
|
|
150
161
|
|
151
162
|
private playgroundSizeChangeListener = () => {
|
152
163
|
this.updateManagerRect();
|
153
|
-
}
|
164
|
+
};
|
154
165
|
|
155
166
|
private get mainView() {
|
156
167
|
return this.context.getMainView();
|
@@ -281,8 +292,7 @@ export class BoxManager {
|
|
281
292
|
}
|
282
293
|
|
283
294
|
public getTopBox(): ReadonlyTeleBox | undefined {
|
284
|
-
|
285
|
-
return maxBy(boxes, "zIndex");
|
295
|
+
return this.teleBoxManager.topBox;
|
286
296
|
}
|
287
297
|
|
288
298
|
public updateBoxState(state?: AppInitState): void {
|
@@ -359,9 +369,9 @@ export class BoxManager {
|
|
359
369
|
this.teleBoxManager.updateAll(config);
|
360
370
|
}
|
361
371
|
|
362
|
-
public setMaximized(maximized: boolean) {
|
372
|
+
public setMaximized(maximized: boolean, skipUpdate = true): void {
|
363
373
|
if (maximized !== this.maximized) {
|
364
|
-
this.teleBoxManager.setMaximized(maximized,
|
374
|
+
this.teleBoxManager.setMaximized(maximized, skipUpdate);
|
365
375
|
}
|
366
376
|
}
|
367
377
|
|
@@ -379,6 +389,10 @@ export class BoxManager {
|
|
379
389
|
}
|
380
390
|
}
|
381
391
|
|
392
|
+
public updateBox(id: string, payload: TeleBoxConfig, skipUpdate = true): void {
|
393
|
+
this.teleBoxManager.update(id, payload, skipUpdate);
|
394
|
+
}
|
395
|
+
|
382
396
|
public setReadonly(readonly: boolean) {
|
383
397
|
this.teleBoxManager.setReadonly(readonly);
|
384
398
|
}
|
package/src/BuiltinApps.ts
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
import AppDocsViewer from "@netless/app-docs-viewer";
|
2
2
|
import AppMediaPlayer, { setOptions } from "@netless/app-media-player";
|
3
3
|
import { WindowManager } from "./index";
|
4
|
-
import "@netless/app-docs-viewer/dist/style.css";
|
5
4
|
|
6
5
|
export const setupBuiltin = () => {
|
7
6
|
if (WindowManager.debug) {
|
package/src/Cursor/Cursor.ts
CHANGED
@@ -1,42 +1,34 @@
|
|
1
|
-
import App from
|
2
|
-
import { ApplianceMap } from
|
3
|
-
import { ApplianceNames } from
|
4
|
-
import {
|
5
|
-
import {
|
6
|
-
import { get, omit } from 'lodash';
|
7
|
-
import type { Position } from '../AttributesDelegate';
|
1
|
+
import App from "./Cursor.svelte";
|
2
|
+
import { ApplianceMap } from "./icons";
|
3
|
+
import { ApplianceNames } from "white-web-sdk";
|
4
|
+
import { omit } from "lodash";
|
5
|
+
import type { Position } from "../AttributesDelegate";
|
8
6
|
import type { RoomMember } from "white-web-sdk";
|
9
7
|
import type { CursorManager } from "./index";
|
10
8
|
import type { SvelteComponent } from "svelte";
|
11
|
-
import {
|
12
|
-
import type { AppManager } from '../AppManager';
|
9
|
+
import type { AppManager } from "../AppManager";
|
13
10
|
|
14
11
|
export type Payload = {
|
15
|
-
[key: string]: any
|
16
|
-
}
|
17
|
-
|
12
|
+
[key: string]: any;
|
13
|
+
};
|
18
14
|
|
19
|
-
export class Cursor
|
15
|
+
export class Cursor {
|
20
16
|
private member?: RoomMember;
|
21
17
|
private timer?: number;
|
22
18
|
private component?: SvelteComponent;
|
23
19
|
|
24
20
|
constructor(
|
25
|
-
manager: AppManager,
|
26
|
-
addCursorChangeListener: (uid: string, callback: (position: Position, state: CursorState) => void) => void,
|
27
|
-
private cursors: any,
|
21
|
+
private manager: AppManager,
|
28
22
|
private memberId: string,
|
29
23
|
private cursorManager: CursorManager,
|
30
|
-
private wrapper?: HTMLElement
|
24
|
+
private wrapper?: HTMLElement
|
31
25
|
) {
|
32
|
-
super(manager);
|
33
26
|
this.setMember();
|
34
27
|
this.createCursor();
|
35
|
-
addCursorChangeListener(this.memberId, this.onCursorChange);
|
36
28
|
this.autoHidden();
|
37
29
|
}
|
38
30
|
|
39
|
-
|
31
|
+
public move = (position: Position) => {
|
40
32
|
if (position.type === "main") {
|
41
33
|
const rect = this.cursorManager.wrapperRect;
|
42
34
|
if (this.component && rect) {
|
@@ -45,7 +37,6 @@ export class Cursor extends Base {
|
|
45
37
|
}
|
46
38
|
} else {
|
47
39
|
const focusView = this.cursorManager.focusView;
|
48
|
-
// TODO 可以存一个当前 focusView 的 Rect 这样只有 focus 切换的时候才调用 getBoundingClientRect
|
49
40
|
const viewRect = focusView?.divElement?.getBoundingClientRect();
|
50
41
|
const viewCamera = focusView?.camera;
|
51
42
|
if (focusView && viewRect && viewCamera && this.component) {
|
@@ -53,10 +44,11 @@ export class Cursor extends Base {
|
|
53
44
|
this.moveCursor(position, viewRect, focusView);
|
54
45
|
}
|
55
46
|
}
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
47
|
+
};
|
48
|
+
|
49
|
+
public leave = () => {
|
50
|
+
this.hide();
|
51
|
+
};
|
60
52
|
|
61
53
|
private moveCursor(cursor: Position, rect: DOMRect, view: any) {
|
62
54
|
const { x, y, type } = cursor;
|
@@ -124,21 +116,12 @@ export class Cursor extends Base {
|
|
124
116
|
}
|
125
117
|
}
|
126
118
|
|
127
|
-
public get cursorState(): CursorState | undefined {
|
128
|
-
return get(this.cursors, [this.memberId, Fields.CursorState]);
|
129
|
-
}
|
130
|
-
|
131
|
-
public get cursorPosition(): Position | undefined {
|
132
|
-
return get(this.cursors, [this.memberId, Fields.Position]);
|
133
|
-
}
|
134
|
-
|
135
119
|
private autoHidden() {
|
136
120
|
if (this.timer) {
|
137
121
|
clearTimeout(this.timer);
|
138
122
|
}
|
139
123
|
this.timer = window.setTimeout(() => {
|
140
124
|
this.hide();
|
141
|
-
this.store.updateCursorState(this.memberId, CursorState.Leave);
|
142
125
|
}, 1000 * 10); // 10 秒钟自动隐藏
|
143
126
|
}
|
144
127
|
|
@@ -176,7 +159,7 @@ export class Cursor extends Base {
|
|
176
159
|
}
|
177
160
|
|
178
161
|
public setMember() {
|
179
|
-
this.member = this.
|
162
|
+
this.member = this.manager.findMemberByUid(this.memberId);
|
180
163
|
this.updateComponent();
|
181
164
|
}
|
182
165
|
|
@@ -188,13 +171,16 @@ export class Cursor extends Base {
|
|
188
171
|
if (this.component) {
|
189
172
|
this.component.$destroy();
|
190
173
|
}
|
191
|
-
this.manager.refresher?.remove(this.memberId);
|
192
174
|
this.cursorManager.cursorInstances.delete(this.memberId);
|
175
|
+
if (this.timer) {
|
176
|
+
clearTimeout(this.timer);
|
177
|
+
}
|
193
178
|
}
|
194
179
|
|
195
180
|
public hide() {
|
196
181
|
if (this.component) {
|
197
182
|
this.component.$set({ visible: false });
|
183
|
+
this.destroy();
|
198
184
|
}
|
199
185
|
}
|
200
186
|
}
|
package/src/Cursor/index.ts
CHANGED
@@ -1,13 +1,10 @@
|
|
1
|
-
import {
|
2
|
-
import { Base } from "../Base";
|
3
|
-
import { compact, debounce, get, uniq } from "lodash";
|
1
|
+
import { compact, throttle, uniq } from "lodash";
|
4
2
|
import { Cursor } from "./Cursor";
|
5
|
-
import { CursorState } from "../constants";
|
3
|
+
import { CursorState, Events } from "../constants";
|
6
4
|
import { emitter, WindowManager } from "../index";
|
7
|
-
import { Fields } from "../AttributesDelegate";
|
8
|
-
import { onObjectInserted } from "../Utils/Reactive";
|
9
5
|
import { SideEffectManager } from "side-effect-manager";
|
10
|
-
import type {
|
6
|
+
import type { CursorMovePayload } from "../index";
|
7
|
+
import type { PositionType } from "../AttributesDelegate";
|
11
8
|
import type { Point, RoomMember, View } from "white-web-sdk";
|
12
9
|
import type { AppManager } from "../AppManager";
|
13
10
|
|
@@ -21,30 +18,36 @@ export type MoveCursorParams = {
|
|
21
18
|
x: number;
|
22
19
|
y: number;
|
23
20
|
};
|
24
|
-
export class CursorManager
|
21
|
+
export class CursorManager {
|
25
22
|
public containerRect?: DOMRect;
|
26
23
|
public wrapperRect?: DOMRect;
|
27
24
|
public cursorInstances: Map<string, Cursor> = new Map();
|
28
25
|
public roomMembers?: readonly RoomMember[];
|
29
26
|
private mainViewElement?: HTMLDivElement;
|
30
27
|
private sideEffectManager = new SideEffectManager();
|
28
|
+
private store = this.manager.store;
|
31
29
|
|
32
|
-
constructor(private
|
33
|
-
|
34
|
-
this.roomMembers = this.appManager.room?.state.roomMembers;
|
30
|
+
constructor(private manager: AppManager) {
|
31
|
+
this.roomMembers = this.manager.room?.state.roomMembers;
|
35
32
|
const wrapper = WindowManager.wrapper;
|
36
33
|
if (wrapper) {
|
37
34
|
this.setupWrapper(wrapper);
|
38
35
|
}
|
39
|
-
emitter.on("
|
40
|
-
this.
|
36
|
+
emitter.on("cursorMove", payload => {
|
37
|
+
let cursorInstance = this.cursorInstances.get(payload.uid);
|
38
|
+
if (!cursorInstance) {
|
39
|
+
cursorInstance = new Cursor(this.manager, payload.uid, this, WindowManager.wrapper);
|
40
|
+
this.cursorInstances.set(payload.uid, cursorInstance);
|
41
|
+
}
|
42
|
+
if (payload.state === CursorState.Leave) {
|
43
|
+
cursorInstance.leave();
|
44
|
+
} else {
|
45
|
+
cursorInstance.move(payload.position);
|
46
|
+
}
|
41
47
|
});
|
42
48
|
}
|
43
49
|
|
44
50
|
public setupWrapper(wrapper: HTMLElement) {
|
45
|
-
if (this.manager.refresher?.hasReactor("cursors")) {
|
46
|
-
this.destroy();
|
47
|
-
}
|
48
51
|
this.sideEffectManager.add(() => {
|
49
52
|
wrapper.addEventListener("pointerenter", this.mouseMoveListener);
|
50
53
|
wrapper.addEventListener("pointermove", this.mouseMoveListener);
|
@@ -56,77 +59,42 @@ export class CursorManager extends Base {
|
|
56
59
|
};
|
57
60
|
});
|
58
61
|
|
59
|
-
this.initCursorAttributes();
|
60
62
|
this.wrapperRect = wrapper.getBoundingClientRect();
|
61
|
-
this.startReaction(wrapper);
|
62
63
|
}
|
63
64
|
|
64
65
|
public setMainViewDivElement(div: HTMLDivElement) {
|
65
66
|
this.mainViewElement = div;
|
66
67
|
}
|
67
68
|
|
68
|
-
private startReaction(wrapper: HTMLElement) {
|
69
|
-
this.manager.refresher?.add("cursors", () => {
|
70
|
-
return onObjectInserted(this.cursors, () => {
|
71
|
-
this.handleRoomMembersChange(wrapper);
|
72
|
-
});
|
73
|
-
});
|
74
|
-
}
|
75
|
-
|
76
69
|
private getUids = (members: readonly RoomMember[] | undefined) => {
|
77
70
|
return compact(uniq(members?.map(member => member.payload?.uid)));
|
78
71
|
};
|
79
72
|
|
80
|
-
private handleRoomMembersChange = debounce((wrapper: HTMLElement) => {
|
81
|
-
const uids = this.getUids(this.roomMembers);
|
82
|
-
const cursors = Object.keys(this.cursors);
|
83
|
-
if (uids?.length) {
|
84
|
-
cursors.map(uid => {
|
85
|
-
if (uids.includes(uid) && !this.cursorInstances.has(uid)) {
|
86
|
-
if (uid === this.context.uid) {
|
87
|
-
return;
|
88
|
-
}
|
89
|
-
const component = new Cursor(
|
90
|
-
this.appManager,
|
91
|
-
this.addCursorChangeListener,
|
92
|
-
this.cursors,
|
93
|
-
uid,
|
94
|
-
this,
|
95
|
-
wrapper
|
96
|
-
);
|
97
|
-
this.cursorInstances.set(uid, component);
|
98
|
-
}
|
99
|
-
});
|
100
|
-
}
|
101
|
-
}, 100);
|
102
|
-
|
103
|
-
public get cursors() {
|
104
|
-
return this.manager.attributes?.[Fields.Cursors];
|
105
|
-
}
|
106
|
-
|
107
73
|
public get boxState() {
|
108
74
|
return this.store.getBoxState();
|
109
75
|
}
|
110
76
|
|
111
77
|
public get focusView() {
|
112
|
-
return this.
|
78
|
+
return this.manager.focusApp?.view;
|
113
79
|
}
|
114
80
|
|
115
|
-
private mouseMoveListener =
|
81
|
+
private mouseMoveListener = throttle((event: MouseEvent) => {
|
116
82
|
this.updateCursor(this.getType(event), event.clientX, event.clientY);
|
117
|
-
},
|
83
|
+
}, 16);
|
118
84
|
|
119
85
|
private updateCursor(event: EventType, clientX: number, clientY: number) {
|
120
86
|
if (this.wrapperRect && this.manager.canOperate) {
|
121
|
-
const view = event.type === "main" ? this.
|
87
|
+
const view = event.type === "main" ? this.manager.mainView : this.focusView;
|
122
88
|
const point = this.getPoint(view, clientX, clientY);
|
123
89
|
if (point) {
|
124
|
-
this.
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
90
|
+
this.manager.dispatchInternalEvent(Events.CursorMove, {
|
91
|
+
uid: this.manager.uid,
|
92
|
+
position: {
|
93
|
+
x: point.x,
|
94
|
+
y: point.y,
|
95
|
+
type: event.type,
|
96
|
+
},
|
97
|
+
} as CursorMovePayload);
|
130
98
|
}
|
131
99
|
}
|
132
100
|
}
|
@@ -151,7 +119,7 @@ export class CursorManager extends Base {
|
|
151
119
|
*/
|
152
120
|
private getType = (event: MouseEvent | Touch): EventType => {
|
153
121
|
const target = event.target as HTMLElement;
|
154
|
-
const focusApp = this.
|
122
|
+
const focusApp = this.manager.focusApp;
|
155
123
|
switch (target.parentElement) {
|
156
124
|
case this.mainViewElement: {
|
157
125
|
return { type: "main" };
|
@@ -165,25 +133,8 @@ export class CursorManager extends Base {
|
|
165
133
|
}
|
166
134
|
};
|
167
135
|
|
168
|
-
private initCursorAttributes() {
|
169
|
-
this.store.updateCursor(this.context.uid, {
|
170
|
-
x: 0,
|
171
|
-
y: 0,
|
172
|
-
type: "main",
|
173
|
-
});
|
174
|
-
this.store.updateCursorState(this.context.uid, CursorState.Leave);
|
175
|
-
}
|
176
|
-
|
177
|
-
private setNormalCursorState() {
|
178
|
-
const cursorState = this.store.getCursorState(this.context.uid);
|
179
|
-
if (cursorState !== CursorState.Normal) {
|
180
|
-
this.store.updateCursorState(this.context.uid, CursorState.Normal);
|
181
|
-
}
|
182
|
-
}
|
183
|
-
|
184
136
|
private mouseLeaveListener = () => {
|
185
|
-
this.hideCursor(this.
|
186
|
-
this.store.updateCursorState(this.context.uid, CursorState.Leave);
|
137
|
+
this.hideCursor(this.manager.uid);
|
187
138
|
};
|
188
139
|
|
189
140
|
public updateContainerRect() {
|
@@ -191,16 +142,6 @@ export class CursorManager extends Base {
|
|
191
142
|
this.wrapperRect = WindowManager.wrapper?.getBoundingClientRect();
|
192
143
|
}
|
193
144
|
|
194
|
-
public setRoomMembers(members: readonly RoomMember[]) {
|
195
|
-
this.roomMembers = members;
|
196
|
-
this.cursorInstances.forEach(cursor => {
|
197
|
-
cursor.setMember();
|
198
|
-
});
|
199
|
-
if (WindowManager.wrapper) {
|
200
|
-
this.handleRoomMembersChange(WindowManager.wrapper);
|
201
|
-
}
|
202
|
-
}
|
203
|
-
|
204
145
|
public deleteCursor(uid: string) {
|
205
146
|
this.store.cleanCursor(uid);
|
206
147
|
const cursor = this.cursorInstances.get(uid);
|
@@ -216,48 +157,6 @@ export class CursorManager extends Base {
|
|
216
157
|
}
|
217
158
|
}
|
218
159
|
|
219
|
-
public cleanMemberAttributes(members: readonly RoomMember[]) {
|
220
|
-
const uids = this.getUids(members);
|
221
|
-
const needDeleteIds: string[] = [];
|
222
|
-
const cursors = Object.keys(this.cursors);
|
223
|
-
cursors.map(cursorId => {
|
224
|
-
const index = uids.findIndex(id => id === cursorId);
|
225
|
-
if (index === -1) {
|
226
|
-
needDeleteIds.push(cursorId);
|
227
|
-
}
|
228
|
-
});
|
229
|
-
needDeleteIds.forEach(uid => {
|
230
|
-
this.deleteCursor(uid);
|
231
|
-
});
|
232
|
-
}
|
233
|
-
|
234
|
-
public onReconnect() {
|
235
|
-
if (this.cursorInstances.size) {
|
236
|
-
this.cursorInstances.forEach(cursor => cursor.destroy());
|
237
|
-
this.cursorInstances.clear();
|
238
|
-
}
|
239
|
-
this.roomMembers = this.appManager.room?.state.roomMembers;
|
240
|
-
if (WindowManager.wrapper) {
|
241
|
-
this.handleRoomMembersChange(WindowManager.wrapper);
|
242
|
-
}
|
243
|
-
}
|
244
|
-
|
245
|
-
public addCursorChangeListener = (
|
246
|
-
uid: string,
|
247
|
-
callback: (position: Position, state: CursorState) => void
|
248
|
-
) => {
|
249
|
-
this.manager.refresher?.add(uid, () => {
|
250
|
-
const disposer = autorun(() => {
|
251
|
-
const position = get(this.cursors, [uid, Fields.Position]);
|
252
|
-
const state = get(this.cursors, [uid, Fields.CursorState]);
|
253
|
-
if (position) {
|
254
|
-
callback(position, state);
|
255
|
-
}
|
256
|
-
});
|
257
|
-
return disposer;
|
258
|
-
});
|
259
|
-
};
|
260
|
-
|
261
160
|
public destroy() {
|
262
161
|
this.sideEffectManager.flushAll();
|
263
162
|
if (this.cursorInstances.size) {
|
@@ -266,6 +165,5 @@ export class CursorManager extends Base {
|
|
266
165
|
});
|
267
166
|
this.cursorInstances.clear();
|
268
167
|
}
|
269
|
-
this.manager.refresher?.remove("cursors");
|
270
168
|
}
|
271
169
|
}
|
package/src/Register/index.ts
CHANGED
@@ -10,34 +10,39 @@ class AppRegister {
|
|
10
10
|
|
11
11
|
public async register(params: RegisterParams): Promise<void> {
|
12
12
|
this.registered.set(params.kind, params);
|
13
|
-
|
14
|
-
const srcOrAppOrFunction = params.src
|
15
|
-
let downloadApp: () => Promise<NetlessApp
|
16
|
-
|
13
|
+
|
14
|
+
const srcOrAppOrFunction = params.src;
|
15
|
+
let downloadApp: () => Promise<NetlessApp>;
|
16
|
+
|
17
17
|
if (typeof srcOrAppOrFunction === "string") {
|
18
18
|
downloadApp = async () => {
|
19
|
-
|
19
|
+
let appClass = (await loadApp(srcOrAppOrFunction, params.kind)) as any;
|
20
20
|
if (appClass) {
|
21
|
-
|
21
|
+
if (appClass.__esModule) {
|
22
|
+
appClass = appClass.default;
|
23
|
+
}
|
24
|
+
return appClass;
|
22
25
|
} else {
|
23
|
-
throw new Error(
|
26
|
+
throw new Error(
|
27
|
+
`[WindowManager]: load remote script failed, ${srcOrAppOrFunction}`
|
28
|
+
);
|
24
29
|
}
|
25
|
-
}
|
30
|
+
};
|
26
31
|
} else if (typeof srcOrAppOrFunction === "function") {
|
27
|
-
downloadApp = srcOrAppOrFunction
|
32
|
+
downloadApp = srcOrAppOrFunction;
|
28
33
|
} else {
|
29
|
-
downloadApp = async () => srcOrAppOrFunction
|
34
|
+
downloadApp = async () => srcOrAppOrFunction;
|
30
35
|
}
|
31
36
|
|
32
37
|
this.appClasses.set(params.kind, async () => {
|
33
|
-
let app = this.appClassesCache.get(params.kind)
|
38
|
+
let app = this.appClassesCache.get(params.kind);
|
34
39
|
if (!app) {
|
35
|
-
app = downloadApp()
|
36
|
-
this.appClassesCache.set(params.kind, app)
|
40
|
+
app = downloadApp();
|
41
|
+
this.appClassesCache.set(params.kind, app);
|
37
42
|
}
|
38
|
-
return app
|
43
|
+
return app;
|
39
44
|
});
|
40
|
-
|
45
|
+
|
41
46
|
if (params.addHooks) {
|
42
47
|
const emitter = this.createKindEmitter(params.kind);
|
43
48
|
if (emitter) {
|
@@ -46,7 +51,11 @@ class AppRegister {
|
|
46
51
|
}
|
47
52
|
}
|
48
53
|
|
49
|
-
public async notifyApp<T extends keyof RegisterEvents>(
|
54
|
+
public async notifyApp<T extends keyof RegisterEvents>(
|
55
|
+
kind: string,
|
56
|
+
event: T,
|
57
|
+
payload: RegisterEvents[T]
|
58
|
+
) {
|
50
59
|
const emitter = this.kindEmitters.get(kind);
|
51
60
|
await emitter?.emit(event, payload);
|
52
61
|
}
|
package/src/Register/loader.ts
CHANGED
@@ -8,7 +8,7 @@ const TIMEOUT = 10000; // 10 秒超时
|
|
8
8
|
export const getScript = async (url: string): Promise<string> => {
|
9
9
|
const item = await getItem(url);
|
10
10
|
if (item) {
|
11
|
-
return item;
|
11
|
+
return item.sourceCode;
|
12
12
|
} else {
|
13
13
|
const result = await fetchWithTimeout(url, { timeout: TIMEOUT });
|
14
14
|
const text = await result.text();
|
package/src/Register/storage.ts
CHANGED
@@ -3,6 +3,11 @@ const DatabaseName = "__WindowManagerAppCache";
|
|
3
3
|
let db: IDBDatabase;
|
4
4
|
let store: IDBObjectStore;
|
5
5
|
|
6
|
+
export type Item = {
|
7
|
+
kind: string;
|
8
|
+
sourceCode: string;
|
9
|
+
}
|
10
|
+
|
6
11
|
export const initDb = async () => {
|
7
12
|
db = await createDb();
|
8
13
|
}
|
@@ -12,7 +17,7 @@ export const setItem = (key: string, val: any) => {
|
|
12
17
|
return addRecord(db, { kind: key, sourceCode: val })
|
13
18
|
};
|
14
19
|
|
15
|
-
export const getItem = async (key: string): Promise<
|
20
|
+
export const getItem = async (key: string): Promise<Item | null> => {
|
16
21
|
if (!db) return null;
|
17
22
|
return await query(db, key);
|
18
23
|
};
|