@netless/window-manager 1.0.14 → 1.0.15
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/app-docs-viewer.js +4 -0
- package/dist/app-docs-viewer.js.map +1 -0
- package/dist/app-docs-viewer.mjs +2892 -0
- package/dist/app-docs-viewer.mjs.map +1 -0
- package/dist/app-media-player.js +31 -0
- package/dist/app-media-player.js.map +1 -0
- package/dist/app-media-player.mjs +7056 -0
- package/dist/app-media-player.mjs.map +1 -0
- package/dist/app-presentation.js +21 -0
- package/dist/app-presentation.js.map +1 -0
- package/dist/app-presentation.mjs +7538 -0
- package/dist/app-presentation.mjs.map +1 -0
- package/dist/index.d.ts +18 -1
- package/dist/index.js +5 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1204 -10940
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/App/AppProxy.ts +8 -3
- package/src/AppManager.ts +16 -11
- package/src/BuiltinApps.ts +25 -6
- package/src/ContainerResizeObserver.ts +14 -5
- package/src/Utils/RoomHacker.ts +3 -1
- package/src/Utils/attributesLogStringify.ts +13 -8
- package/src/Utils/log.ts +13 -9
- package/src/View/MainView.ts +50 -24
- package/src/css.d.ts +1 -0
- package/src/index.ts +255 -18
package/src/index.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { ArgusLog, log } from "./Utils/log";
|
|
|
16
16
|
import { PageStateImpl } from "./PageState";
|
|
17
17
|
import { ReconnectRefresher } from "./ReconnectRefresher";
|
|
18
18
|
import { replaceRoomFunction } from "./Utils/RoomHacker";
|
|
19
|
-
import { setupBuiltin } from "./BuiltinApps";
|
|
19
|
+
import { BuiltinApps, setupBuiltin } from "./BuiltinApps";
|
|
20
20
|
import "video.js/dist/video-js.css";
|
|
21
21
|
import "./style.css";
|
|
22
22
|
import "@netless/telebox-insider/dist/style.css";
|
|
@@ -62,7 +62,6 @@ import type Emittery from "emittery";
|
|
|
62
62
|
import type { PageController, AddPageParams, PageState } from "./Page";
|
|
63
63
|
import { boxEmitter } from "./BoxEmitter";
|
|
64
64
|
import { IframeBridge } from "./View/IframeBridge";
|
|
65
|
-
import { setOptions } from "@netless/app-media-player";
|
|
66
65
|
import type { ExtendPluginInstance } from "./ExtendPluginManager";
|
|
67
66
|
import { ExtendPluginManager } from "./ExtendPluginManager";
|
|
68
67
|
import { getExtendClass } from "./Utils/extendClass";
|
|
@@ -90,6 +89,54 @@ export type AddAppOptions = {
|
|
|
90
89
|
|
|
91
90
|
export type setAppOptions = AddAppOptions & { appOptions?: any };
|
|
92
91
|
|
|
92
|
+
export type DocsEvent =
|
|
93
|
+
| "prevPage"
|
|
94
|
+
| "nextPage"
|
|
95
|
+
| "prevStep"
|
|
96
|
+
| "nextStep"
|
|
97
|
+
| "jumpToPage"
|
|
98
|
+
| "scalePage";
|
|
99
|
+
|
|
100
|
+
export type DocsEventOptions = {
|
|
101
|
+
/** If provided, will dispatch to the specific app. Default to the focused app. */
|
|
102
|
+
appId?: string;
|
|
103
|
+
/** Used by `jumpToPage` event, range from 1 to total pages count. */
|
|
104
|
+
page?: number;
|
|
105
|
+
/** Used by `scalePage` event. Range from 1 to 4, decimals allowed. `1` means default fitted size. */
|
|
106
|
+
scale?: number;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
type SlideDocsAppResult = {
|
|
110
|
+
prevPage: () => boolean;
|
|
111
|
+
nextPage: () => boolean;
|
|
112
|
+
prevStep: () => boolean;
|
|
113
|
+
nextStep: () => boolean;
|
|
114
|
+
jumpToPage: (page: number) => boolean;
|
|
115
|
+
scaleView: (scale: number) => void;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
type PresentationDocsAppResult = {
|
|
119
|
+
prevPage: () => boolean;
|
|
120
|
+
nextPage: () => boolean;
|
|
121
|
+
jumpPage: (index: number) => boolean;
|
|
122
|
+
moveCamera: (camera: { centerX: number; centerY: number; scale: number }) => void;
|
|
123
|
+
getOriginScale: () => number;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const SlideAppKind = "Slide";
|
|
127
|
+
const PresentationAppKind = BuiltinApps.Presentation;
|
|
128
|
+
const MinDocsPageScale = 1;
|
|
129
|
+
const MaxDocsPageScale = 4;
|
|
130
|
+
|
|
131
|
+
function isValidDocsPageScale(scale: unknown): scale is number {
|
|
132
|
+
return (
|
|
133
|
+
typeof scale === "number" &&
|
|
134
|
+
Number.isFinite(scale) &&
|
|
135
|
+
scale >= MinDocsPageScale &&
|
|
136
|
+
scale <= MaxDocsPageScale
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
93
140
|
export type AddAppParams<TAttributes = any> = {
|
|
94
141
|
kind: string;
|
|
95
142
|
// app 地址(本地 app 不需要传)
|
|
@@ -255,7 +302,7 @@ export class WindowManager
|
|
|
255
302
|
super(context);
|
|
256
303
|
WindowManager.displayer = context.displayer;
|
|
257
304
|
(window as any).NETLESS_DEPS = __APP_DEPENDENCIES__;
|
|
258
|
-
this.emitter.on(
|
|
305
|
+
this.emitter.on("mainViewScenePathChange", this.onMainViewScenePathChangeHandler);
|
|
259
306
|
}
|
|
260
307
|
|
|
261
308
|
public static onCreate(manager: WindowManager) {
|
|
@@ -289,7 +336,11 @@ export class WindowManager
|
|
|
289
336
|
manager = await this.initManager(room);
|
|
290
337
|
if (manager) {
|
|
291
338
|
manager._roomLogger = (room as unknown as { logger: Logger }).logger;
|
|
292
|
-
manager.attributesDeboundceLog = new ArgusLog(
|
|
339
|
+
manager.attributesDeboundceLog = new ArgusLog(
|
|
340
|
+
manager._roomLogger,
|
|
341
|
+
"attributes",
|
|
342
|
+
300
|
|
343
|
+
);
|
|
293
344
|
if (WindowManager.registered.size > 0) {
|
|
294
345
|
manager._roomLogger.info(
|
|
295
346
|
`[WindowManager] registered apps: ${JSON.stringify(
|
|
@@ -304,9 +355,6 @@ export class WindowManager
|
|
|
304
355
|
}
|
|
305
356
|
|
|
306
357
|
this.debug = Boolean(debug);
|
|
307
|
-
if (this.debug) {
|
|
308
|
-
setOptions({ verbose: true });
|
|
309
|
-
}
|
|
310
358
|
if (manager?._roomLogger) {
|
|
311
359
|
manager._roomLogger.info(
|
|
312
360
|
`[WindowManager] Already insert room version: ${manager.version}`
|
|
@@ -390,27 +438,43 @@ export class WindowManager
|
|
|
390
438
|
console.warn("[WindowManager]: indexedDB open failed");
|
|
391
439
|
console.log(error);
|
|
392
440
|
}
|
|
393
|
-
manager.emitter.on(
|
|
441
|
+
manager.emitter.on("mainViewScenePathChange", manager.onMainViewScenePathChangeHandler);
|
|
394
442
|
return manager;
|
|
395
443
|
}
|
|
396
444
|
|
|
397
445
|
public onMainViewScenePathChangeHandler = (scenePath: string) => {
|
|
398
446
|
const mainViewElement = this.mainView.divElement;
|
|
399
447
|
if (mainViewElement) {
|
|
400
|
-
const backgroundImage = mainViewElement.querySelector(
|
|
448
|
+
const backgroundImage = mainViewElement.querySelector(".background img");
|
|
401
449
|
if (backgroundImage) {
|
|
402
450
|
const backgroundImageRect = backgroundImage?.getBoundingClientRect();
|
|
403
451
|
const backgroundImageCSS = window.getComputedStyle(backgroundImage);
|
|
404
|
-
const backgroundImageVisible =
|
|
452
|
+
const backgroundImageVisible =
|
|
453
|
+
backgroundImageRect?.width > 0 &&
|
|
454
|
+
backgroundImageRect?.height > 0 &&
|
|
455
|
+
backgroundImageCSS.display !== "none";
|
|
405
456
|
const camera = this.mainView.camera;
|
|
406
|
-
console.log(
|
|
457
|
+
console.log(
|
|
458
|
+
"[window-manager] backgroundImageVisible:" +
|
|
459
|
+
backgroundImageVisible +
|
|
460
|
+
" camera:" +
|
|
461
|
+
JSON.stringify(camera)
|
|
462
|
+
);
|
|
407
463
|
return;
|
|
408
464
|
}
|
|
409
|
-
console.log(
|
|
465
|
+
console.log(
|
|
466
|
+
"[window-manager] onMainViewScenePathChange scenePath:" +
|
|
467
|
+
scenePath +
|
|
468
|
+
" backgroundImageVisible is not found"
|
|
469
|
+
);
|
|
410
470
|
return;
|
|
411
471
|
}
|
|
412
|
-
console.log(
|
|
413
|
-
|
|
472
|
+
console.log(
|
|
473
|
+
"[window-manager] onMainViewScenePathChange scenePath:" +
|
|
474
|
+
scenePath +
|
|
475
|
+
" mainViewElement is not found"
|
|
476
|
+
);
|
|
477
|
+
};
|
|
414
478
|
|
|
415
479
|
private static initManager(room: Room): Promise<WindowManager | undefined> {
|
|
416
480
|
return createInvisiblePlugin(room);
|
|
@@ -1007,6 +1071,172 @@ export class WindowManager
|
|
|
1007
1071
|
return this.appManager?.appProxies.get(appId);
|
|
1008
1072
|
}
|
|
1009
1073
|
|
|
1074
|
+
/**
|
|
1075
|
+
* Send specific command to DocsViewer / Presentation / Slide app.
|
|
1076
|
+
*
|
|
1077
|
+
* Static docs and Presentation do not have animation steps, so `prevStep` / `nextStep`
|
|
1078
|
+
* are treated as `prevPage` / `nextPage`.
|
|
1079
|
+
*/
|
|
1080
|
+
public dispatchDocsEvent(event: DocsEvent, options: DocsEventOptions = {}): boolean {
|
|
1081
|
+
const appId = options.appId || this.focused;
|
|
1082
|
+
if (!appId) {
|
|
1083
|
+
console.warn("not found " + (options.appId || "focused app"));
|
|
1084
|
+
return false;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
const app = this.queryOne(appId);
|
|
1088
|
+
if (!app) {
|
|
1089
|
+
console.warn("not found app with id " + appId);
|
|
1090
|
+
return false;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
const isDocsViewerApp =
|
|
1094
|
+
appId.startsWith(`${BuiltinApps.DocsViewer}-`) || app.kind === BuiltinApps.DocsViewer;
|
|
1095
|
+
const isPresentationApp =
|
|
1096
|
+
appId.startsWith(`${PresentationAppKind}-`) || app.kind === PresentationAppKind;
|
|
1097
|
+
const isSlideApp = appId.startsWith(`${SlideAppKind}-`) || app.kind === SlideAppKind;
|
|
1098
|
+
let appKind = app.kind;
|
|
1099
|
+
if (isDocsViewerApp) {
|
|
1100
|
+
appKind = BuiltinApps.DocsViewer;
|
|
1101
|
+
} else if (isPresentationApp) {
|
|
1102
|
+
appKind = PresentationAppKind;
|
|
1103
|
+
} else if (isSlideApp) {
|
|
1104
|
+
appKind = SlideAppKind;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
if (!WindowManager.registered.has(appKind)) {
|
|
1108
|
+
console.warn("not registered app kind " + appKind);
|
|
1109
|
+
return false;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
let page: number | undefined, input: HTMLInputElement | null, scale: number | undefined;
|
|
1113
|
+
|
|
1114
|
+
if (isDocsViewerApp) {
|
|
1115
|
+
const dom = app.box?.$footer;
|
|
1116
|
+
if (!dom) {
|
|
1117
|
+
console.warn("not found app with id " + appId);
|
|
1118
|
+
return false;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
const click = (el: Element | null) => {
|
|
1122
|
+
el && el.dispatchEvent(new MouseEvent("click"));
|
|
1123
|
+
};
|
|
1124
|
+
|
|
1125
|
+
switch (event) {
|
|
1126
|
+
case "prevPage":
|
|
1127
|
+
case "prevStep":
|
|
1128
|
+
click(dom.querySelector('button[class$="btn-page-back"]'));
|
|
1129
|
+
break;
|
|
1130
|
+
case "nextPage":
|
|
1131
|
+
case "nextStep":
|
|
1132
|
+
click(dom.querySelector('button[class$="btn-page-next"]'));
|
|
1133
|
+
break;
|
|
1134
|
+
case "jumpToPage":
|
|
1135
|
+
page = options.page;
|
|
1136
|
+
input = dom.querySelector('input[class$="page-number-input"]');
|
|
1137
|
+
if (!input || typeof page !== "number") {
|
|
1138
|
+
console.warn("failed to jump" + (page ? " to page " + page : ""));
|
|
1139
|
+
return false;
|
|
1140
|
+
}
|
|
1141
|
+
input.value = "" + page;
|
|
1142
|
+
input.dispatchEvent(new InputEvent("change"));
|
|
1143
|
+
break;
|
|
1144
|
+
case "scalePage":
|
|
1145
|
+
console.warn("not supported event " + event + " for app kind " + appKind);
|
|
1146
|
+
return false;
|
|
1147
|
+
default:
|
|
1148
|
+
console.warn("unknown event " + event);
|
|
1149
|
+
return false;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
return true;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
if (isPresentationApp) {
|
|
1156
|
+
const controller = app.appResult as PresentationDocsAppResult | undefined;
|
|
1157
|
+
if (!controller) {
|
|
1158
|
+
console.warn("not found app with id " + appId);
|
|
1159
|
+
return false;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
switch (event) {
|
|
1163
|
+
case "prevPage":
|
|
1164
|
+
case "prevStep":
|
|
1165
|
+
return controller.prevPage();
|
|
1166
|
+
case "nextPage":
|
|
1167
|
+
case "nextStep":
|
|
1168
|
+
return controller.nextPage();
|
|
1169
|
+
case "jumpToPage":
|
|
1170
|
+
page = options.page;
|
|
1171
|
+
if (typeof page !== "number") {
|
|
1172
|
+
console.warn("failed to jump" + (page ? " to page " + page : ""));
|
|
1173
|
+
return false;
|
|
1174
|
+
}
|
|
1175
|
+
return controller.jumpPage(page - 1);
|
|
1176
|
+
case "scalePage":
|
|
1177
|
+
scale = options.scale;
|
|
1178
|
+
if (!isValidDocsPageScale(scale)) {
|
|
1179
|
+
console.warn("failed to scale, scale should be a number from 1 to 4");
|
|
1180
|
+
return false;
|
|
1181
|
+
}
|
|
1182
|
+
try {
|
|
1183
|
+
controller.moveCamera({
|
|
1184
|
+
centerX: 0,
|
|
1185
|
+
centerY: 0,
|
|
1186
|
+
scale: controller.getOriginScale() * scale,
|
|
1187
|
+
});
|
|
1188
|
+
return true;
|
|
1189
|
+
} catch (error) {
|
|
1190
|
+
console.warn(error);
|
|
1191
|
+
return false;
|
|
1192
|
+
}
|
|
1193
|
+
default:
|
|
1194
|
+
console.warn("unknown event " + event);
|
|
1195
|
+
return false;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
if (isSlideApp) {
|
|
1200
|
+
const controller = app.appResult as SlideDocsAppResult | undefined;
|
|
1201
|
+
if (!controller) {
|
|
1202
|
+
console.warn("not found app with id " + appId);
|
|
1203
|
+
return false;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
switch (event) {
|
|
1207
|
+
case "prevPage":
|
|
1208
|
+
return controller.prevPage();
|
|
1209
|
+
case "nextPage":
|
|
1210
|
+
return controller.nextPage();
|
|
1211
|
+
case "prevStep":
|
|
1212
|
+
return controller.prevStep();
|
|
1213
|
+
case "nextStep":
|
|
1214
|
+
return controller.nextStep();
|
|
1215
|
+
case "jumpToPage":
|
|
1216
|
+
page = options.page;
|
|
1217
|
+
if (typeof page !== "number") {
|
|
1218
|
+
console.warn("failed to jump" + (page ? " to page " + page : ""));
|
|
1219
|
+
return false;
|
|
1220
|
+
}
|
|
1221
|
+
return controller.jumpToPage(page);
|
|
1222
|
+
case "scalePage":
|
|
1223
|
+
scale = options.scale;
|
|
1224
|
+
if (!isValidDocsPageScale(scale)) {
|
|
1225
|
+
console.warn("failed to scale, scale should be a number from 1 to 4");
|
|
1226
|
+
return false;
|
|
1227
|
+
}
|
|
1228
|
+
controller.scaleView(scale);
|
|
1229
|
+
return true;
|
|
1230
|
+
default:
|
|
1231
|
+
console.warn("unknown event " + event);
|
|
1232
|
+
return false;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
console.warn("not supported app kind " + app.kind);
|
|
1237
|
+
return false;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1010
1240
|
/**
|
|
1011
1241
|
* 关闭 APP
|
|
1012
1242
|
*/
|
|
@@ -1081,7 +1311,7 @@ export class WindowManager
|
|
|
1081
1311
|
WindowManager.playground.parentNode?.removeChild(WindowManager.playground);
|
|
1082
1312
|
}
|
|
1083
1313
|
WindowManager.params = undefined;
|
|
1084
|
-
this.emitter.off(
|
|
1314
|
+
this.emitter.off("mainViewScenePathChange", this.onMainViewScenePathChangeHandler);
|
|
1085
1315
|
this._iframeBridge?.destroy();
|
|
1086
1316
|
this._iframeBridge = undefined;
|
|
1087
1317
|
log("Destroyed");
|
|
@@ -1113,7 +1343,10 @@ export class WindowManager
|
|
|
1113
1343
|
if (this.canOperate) {
|
|
1114
1344
|
this.setAttributes(attributes);
|
|
1115
1345
|
if (this.attributesDeboundceLog) {
|
|
1116
|
-
this.attributesDeboundceLog.logDebouncedShallowMerge(
|
|
1346
|
+
this.attributesDeboundceLog.logDebouncedShallowMerge(
|
|
1347
|
+
"safeSetAttributes",
|
|
1348
|
+
attributes
|
|
1349
|
+
);
|
|
1117
1350
|
}
|
|
1118
1351
|
}
|
|
1119
1352
|
}
|
|
@@ -1134,7 +1367,10 @@ export class WindowManager
|
|
|
1134
1367
|
public cleanCurrentScene(): void {
|
|
1135
1368
|
log("clean current scene");
|
|
1136
1369
|
this.focusedView?.cleanCurrentScene();
|
|
1137
|
-
this.Logger &&
|
|
1370
|
+
this.Logger &&
|
|
1371
|
+
this.Logger.info(
|
|
1372
|
+
`[WindowManager]: cleanCurrentScene ${this.focusedView?.focusScenePath}`
|
|
1373
|
+
);
|
|
1138
1374
|
}
|
|
1139
1375
|
|
|
1140
1376
|
public redo(): number {
|
|
@@ -1147,7 +1383,8 @@ export class WindowManager
|
|
|
1147
1383
|
|
|
1148
1384
|
public delete(): void {
|
|
1149
1385
|
this.focusedView?.delete();
|
|
1150
|
-
this.Logger &&
|
|
1386
|
+
this.Logger &&
|
|
1387
|
+
this.Logger.info(`[WindowManager]: delete ${this.focusedView?.focusScenePath}`);
|
|
1151
1388
|
}
|
|
1152
1389
|
|
|
1153
1390
|
public copy(): void {
|