@netless/app-presentation 0.1.13-beta.0 → 0.1.13-beta.2
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/index.d.ts +84 -1
- package/dist/index.global.js +282 -14
- package/dist/index.js +282 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +282 -15
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/app-presentation.ts +322 -4
- package/src/preload.ts +14 -0
- package/src/presentation.ts +18 -1
- package/src/runtime-lifecycle.ts +24 -0
- package/src/style.scss +7 -1
package/dist/index.d.ts
CHANGED
|
@@ -143,6 +143,40 @@ interface DisposableStore extends DisposableDisposer {
|
|
|
143
143
|
*/
|
|
144
144
|
size(): number;
|
|
145
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Create a {@link DisposableStore} that manages {@link Disposer}s and {@link IDisposable}s.
|
|
148
|
+
*
|
|
149
|
+
* A {@link DisposableStore} is also a {@link Disposer}, which means it can be the `dispose` method of an {@link IDisposable}.
|
|
150
|
+
*
|
|
151
|
+
* A {@link DisposableStore} is also an {@link IDisposable}, which means it can be managed by another {@link DisposableStore}.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```ts
|
|
155
|
+
* import { type IDisposable, disposableStore } from "@wopjs/disposable";
|
|
156
|
+
*
|
|
157
|
+
* class A implements IDisposable {
|
|
158
|
+
* dispose = disposableStore()
|
|
159
|
+
* constructor() {
|
|
160
|
+
* this.dispose.add(...);
|
|
161
|
+
* }
|
|
162
|
+
* }
|
|
163
|
+
*
|
|
164
|
+
* class B implements IDisposable {
|
|
165
|
+
* dispose = disposableStore()
|
|
166
|
+
* a = this.dispose.add(new A())
|
|
167
|
+
* constructor() {
|
|
168
|
+
* this.dispose.add(...);
|
|
169
|
+
* }
|
|
170
|
+
* }
|
|
171
|
+
*
|
|
172
|
+
* const b = new B();
|
|
173
|
+
* b.dispose(); // dispose both `b` and `b.a`.
|
|
174
|
+
* ```
|
|
175
|
+
*
|
|
176
|
+
* @param disposables Optional array of {@link DisposableType}s added to the store.
|
|
177
|
+
* @returns A disposable store.
|
|
178
|
+
*/
|
|
179
|
+
declare function disposableStore(disposables?: DisposableType[]): DisposableStore;
|
|
146
180
|
|
|
147
181
|
interface ILazyLoadInstance {
|
|
148
182
|
/**
|
|
@@ -218,7 +252,10 @@ declare class Preload implements IDisposable {
|
|
|
218
252
|
readonly preloadMap: Map<number, IPreloadMapValue>;
|
|
219
253
|
touchIndex: number;
|
|
220
254
|
preloadSize: number;
|
|
255
|
+
paused: boolean;
|
|
221
256
|
constructor(pages: PresentationPage[]);
|
|
257
|
+
pause(): void;
|
|
258
|
+
resume(index?: number): void;
|
|
222
259
|
touch(index: number, force?: boolean): void;
|
|
223
260
|
private createLink;
|
|
224
261
|
private destroySomeLink;
|
|
@@ -299,15 +336,27 @@ declare class Presentation implements IDisposable<void> {
|
|
|
299
336
|
setReadonly(readonly: boolean): void;
|
|
300
337
|
setPageIndex(pageIndex: number): void;
|
|
301
338
|
togglePreview(showPreview?: boolean): void;
|
|
339
|
+
/** Release preview images while this presentation stays in the runtime cache. */
|
|
340
|
+
suspendPreviewResources(): void;
|
|
302
341
|
onNewPageIndex(index: number, _origin: "navigation" | "keydown" | "input" | "preview"): void;
|
|
303
342
|
page(): PresentationPage | undefined;
|
|
304
343
|
updateImage(): void;
|
|
305
344
|
/** Returns a modified URL that points to the thumbnail image. */
|
|
306
345
|
thumbnail(src: string): string;
|
|
346
|
+
private destroyPreviewLazyload;
|
|
307
347
|
private c;
|
|
308
348
|
private isEditable;
|
|
309
349
|
}
|
|
310
350
|
|
|
351
|
+
type Subscriber<T> = (value: T) => void;
|
|
352
|
+
type Unsubscriber = () => void;
|
|
353
|
+
interface Readable<T> {
|
|
354
|
+
readonly value: T;
|
|
355
|
+
subscribe(this: void, run: Subscriber<T>): Unsubscriber;
|
|
356
|
+
reaction(this: void, run: Subscriber<T>): Unsubscriber;
|
|
357
|
+
dispose(value?: T): void;
|
|
358
|
+
}
|
|
359
|
+
|
|
311
360
|
interface ScrollbarOption {
|
|
312
361
|
appId: string;
|
|
313
362
|
readonly?: boolean;
|
|
@@ -420,6 +469,17 @@ interface PresentationAppOptions {
|
|
|
420
469
|
goToPageByClick?: boolean;
|
|
421
470
|
/** useClipView is used to set the presentation use clip view, it will be used in the presentation, and the presentation will be use clip view when the app is initialized */
|
|
422
471
|
useClipView?: boolean;
|
|
472
|
+
/**
|
|
473
|
+
* Max time (ms) `setup()` waits for the first visible page image to load
|
|
474
|
+
* before resolving anyway. Default: 5_000.
|
|
475
|
+
*/
|
|
476
|
+
setupReadyTimeout?: number;
|
|
477
|
+
/**
|
|
478
|
+
* Blur thumbnail degradation keeps cached (focused-lost) presentations on
|
|
479
|
+
* the low-res `previewURL` thumbnail to save memory. Enabled by default in
|
|
480
|
+
* maximized/minimized states; set `true` to disable it.
|
|
481
|
+
*/
|
|
482
|
+
disableBlurThumbnailDegradation?: boolean;
|
|
423
483
|
}
|
|
424
484
|
interface PresentationController {
|
|
425
485
|
readonly app: Presentation;
|
|
@@ -469,6 +529,29 @@ interface PresentationController {
|
|
|
469
529
|
/** screenshot the current page */
|
|
470
530
|
screenshotCurrentPageAsync: (context: CanvasRenderingContext2D, width?: number, height?: number) => Promise<void>;
|
|
471
531
|
}
|
|
532
|
+
/**
|
|
533
|
+
* Blur thumbnail degradation (see lazy-setup design doc §15): when the app
|
|
534
|
+
* loses focus but stays cached (multi-runtime cache mode), swap the scene
|
|
535
|
+
* background `<img>` src to the low-res `PptDescription.previewURL`
|
|
536
|
+
* (`page.thumbnail`) via a pure DOM change and pause full-image preloading;
|
|
537
|
+
* restore the full image when focus comes back. A page without a real
|
|
538
|
+
* thumbnail keeps its measurable view container, but its background layer is
|
|
539
|
+
* hidden and replaced with a static pixel after TeleBox commits the blur.
|
|
540
|
+
*
|
|
541
|
+
* While degraded, every load of a background `<img>` is re-degraded
|
|
542
|
+
* immediately via a capture-phase `load` listener on the view container
|
|
543
|
+
* (`load` does not bubble but capture works). This covers remote page turns,
|
|
544
|
+
* SDK React re-renders and the SDK's own background-image onError retries —
|
|
545
|
+
* any path that (re)renders the full-size image while the app stays blurred.
|
|
546
|
+
*/
|
|
547
|
+
declare const setupBlurThumbnailDegradation: (config: {
|
|
548
|
+
context: AppContext;
|
|
549
|
+
view: View;
|
|
550
|
+
pages: PresentationPage[];
|
|
551
|
+
pageIndex$: Readable<number>;
|
|
552
|
+
app: Presentation;
|
|
553
|
+
dispose: ReturnType<typeof disposableStore>;
|
|
554
|
+
}) => void;
|
|
472
555
|
declare const NetlessAppPresentation: NetlessApp<PresentationAttributes, {}, PresentationAppOptions, PresentationController> & {
|
|
473
556
|
teardown(context: AppContext): void;
|
|
474
557
|
};
|
|
@@ -496,5 +579,5 @@ declare const install: (register: RegisterFn, options?: InstallOptions) => Promi
|
|
|
496
579
|
|
|
497
580
|
declare const version: string;
|
|
498
581
|
|
|
499
|
-
export { NetlessAppPresentation, Presentation, Scrollbar, NetlessAppPresentation as default, install, version };
|
|
582
|
+
export { NetlessAppPresentation, Presentation, Scrollbar, NetlessAppPresentation as default, install, setupBlurThumbnailDegradation, version };
|
|
500
583
|
export type { InstallOptions, Logger, PresentationAppOptions, PresentationAttributes, PresentationConfig, PresentationController, PresentationPage, RegisterFn, ScrollbarEventCallback, ScrollbarOption };
|
package/dist/index.global.js
CHANGED
|
@@ -1150,6 +1150,9 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
1150
1150
|
// 当前触摸的索引
|
|
1151
1151
|
this.touchIndex = 0;
|
|
1152
1152
|
this.preloadSize = 0;
|
|
1153
|
+
// 暂停后不再创建预加载链接(app 失焦降级时调用);已插入的 link 会被移除,
|
|
1154
|
+
// 挂起的 idle 回调重新进入 touch() 时也会被跳过
|
|
1155
|
+
this.paused = false;
|
|
1153
1156
|
this.preloadMap = new Map(pages.map((e, index) => [index, {
|
|
1154
1157
|
src: e.src,
|
|
1155
1158
|
state: 0 /* unloaded */
|
|
@@ -1157,7 +1160,21 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
1157
1160
|
this.preloadSize = this.preloadMap.size;
|
|
1158
1161
|
this.touch(0, true);
|
|
1159
1162
|
}
|
|
1163
|
+
pause() {
|
|
1164
|
+
if (this.paused)
|
|
1165
|
+
return;
|
|
1166
|
+
this.paused = true;
|
|
1167
|
+
this.destroySomeLink();
|
|
1168
|
+
}
|
|
1169
|
+
resume(index) {
|
|
1170
|
+
if (!this.paused)
|
|
1171
|
+
return;
|
|
1172
|
+
this.paused = false;
|
|
1173
|
+
this.touch(index != null ? index : this.touchIndex, true);
|
|
1174
|
+
}
|
|
1160
1175
|
touch(index, force = false) {
|
|
1176
|
+
if (this.paused)
|
|
1177
|
+
return;
|
|
1161
1178
|
if (index >= this.preloadSize) {
|
|
1162
1179
|
this.touchIndex = 0;
|
|
1163
1180
|
} else {
|
|
@@ -1299,10 +1316,7 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
1299
1316
|
if (this.initialized)
|
|
1300
1317
|
return;
|
|
1301
1318
|
this.initialized = true;
|
|
1302
|
-
this.dispose.add(() =>
|
|
1303
|
-
var _a2;
|
|
1304
|
-
return (_a2 = this.previewLazyload) == null ? void 0 : _a2.destroy();
|
|
1305
|
-
});
|
|
1319
|
+
this.dispose.add(() => this.destroyPreviewLazyload());
|
|
1306
1320
|
this.contentDOM.classList.toggle(this.c("readonly"), this.readonly);
|
|
1307
1321
|
this.dom.appendChild(this.contentDOM);
|
|
1308
1322
|
const previewMask = this.contentDOM.appendChild(document.createElement("div"));
|
|
@@ -1455,6 +1469,17 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
1455
1469
|
}
|
|
1456
1470
|
}
|
|
1457
1471
|
}
|
|
1472
|
+
/** Release preview images while this presentation stays in the runtime cache. */
|
|
1473
|
+
suspendPreviewResources() {
|
|
1474
|
+
this.togglePreview(false);
|
|
1475
|
+
this.destroyPreviewLazyload();
|
|
1476
|
+
this.previewDOM.querySelectorAll("img").forEach((img) => {
|
|
1477
|
+
img.removeAttribute("src");
|
|
1478
|
+
img.removeAttribute("srcset");
|
|
1479
|
+
img.removeAttribute("sizes");
|
|
1480
|
+
LazyLoad.resetStatus(img);
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1458
1483
|
// [origin] means the cause:
|
|
1459
1484
|
// - navigation: user clicked on the left / right button on footer
|
|
1460
1485
|
// - input: user filled the bottom-right page number input box
|
|
@@ -1489,6 +1514,11 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
1489
1514
|
return src;
|
|
1490
1515
|
}
|
|
1491
1516
|
}
|
|
1517
|
+
destroyPreviewLazyload() {
|
|
1518
|
+
var _a;
|
|
1519
|
+
(_a = this.previewLazyload) == null ? void 0 : _a.destroy();
|
|
1520
|
+
this.previewLazyload = null;
|
|
1521
|
+
}
|
|
1492
1522
|
c(className) {
|
|
1493
1523
|
return `${this.namespace}-${className}`;
|
|
1494
1524
|
}
|
|
@@ -1501,7 +1531,7 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
1501
1531
|
};
|
|
1502
1532
|
|
|
1503
1533
|
// src/style.scss?inline
|
|
1504
|
-
var style_default = ".netless-app-presentation{height:100%;display:flex;flex-flow:column nowrap}.netless-app-presentation-content{position:relative;height:100%;overflow:hidden}.netless-app-presentation-preview-mask{display:none;position:absolute;z-index:200;top:0;left:0;width:100%;height:100%}.netless-app-presentation-preview{display:flex;flex-direction:column;align-items:center;position:absolute;z-index:300;top:0;left:0;width:33%;max-width:200px;height:100%;padding-top:10px;transform:translate(-100%);background:#ededf0e6;box-shadow:inset -1px 0 #0000001c;transition:transform .4s;overflow:auto;overflow-y:scroll}.netless-app-presentation-preview-active .netless-app-presentation-preview-mask{display:block}.netless-app-presentation-preview-active .netless-app-presentation-preview{transform:translate(0)}.netless-app-presentation-preview-page{position:relative;display:block;width:55%;margin-bottom:10px;font-size:0;color:#0000;outline:none;border:7px solid rgba(0,0,0,0);border-radius:4px;transition:border-color .3s;user-select:none}.netless-app-presentation-preview-page:hover,.netless-app-presentation-preview-page.netless-app-presentation-preview-page-active{border-color:#444e601a}.netless-app-presentation-preview-page>img{width:100%;height:auto;box-sizing:border-box;border:1px solid rgba(0,0,0,.5);border-radius:1px;background-color:#fff;box-shadow:0 2px 8px #0000004d}.netless-app-presentation-preview-page-name{position:absolute;top:1px;left:-10px;transform:translate(-100%);text-align:right;font-size:12px;color:#5f5f5f;user-select:none}.netless-app-presentation-footer{box-sizing:border-box;height:26px;display:flex;align-items:center;padding:0 16px;border-top:1px solid #eeeef7;color:#191919}.netless-app-presentation-float-footer{width:100%;min-height:26px;position:absolute;left:0;bottom:0;z-index:2000;background:#f9f9fce6;transition:opacity .4s}.netless-app-presentation-footer-btn{box-sizing:border-box;width:26px;height:26px;font-size:0;margin:0;padding:3px;border:none;border-radius:1px;outline:none;color:currentColor;background:#0000;transition:background .4s;cursor:pointer;user-select:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}.netless-app-presentation-footer-btn:hover{background:#ededf0e6}@media (hover: none){.netless-app-presentation-footer-btn:hover{background:#0000!important}}.netless-app-presentation-footer-btn>svg{width:100%;height:100%}.netless-app-presentation-footer-btn>svg:nth-of-type(2){display:none}.netless-app-presentation-footer-btn.netless-app-presentation-footer-btn-playing>svg:nth-of-type(1){display:none}.netless-app-presentation-footer-btn.netless-app-presentation-footer-btn-playing>svg:nth-of-type(2){display:initial}.netless-app-presentation-footer-btn~.netless-app-presentation-footer-btn{margin-left:15px}.netless-app-presentation-page-jumps{flex:1;display:flex;justify-content:center;align-items:center}.netless-app-presentation-page-number{margin-left:auto;font-size:13px;user-select:none;white-space:nowrap;word-break:keep-all}.netless-app-presentation-page-number-input{border:none;outline:none;width:3em;margin:0;padding:0 2px;text-align:right;font-size:13px;line-height:1;font-weight:400;font-family:inherit;border-radius:2px;color:currentColor;background:#0000;transition:background .4s;user-select:text;-webkit-tap-highlight-color:rgba(0,0,0,0)}.netless-app-presentation-page-number-input:hover,.netless-app-presentation-page-number-input:focus,.netless-app-presentation-page-number-input:active{background:#fff;box-shadow:#63636333 0 2px 8px}.netless-app-presentation-readonly.netless-app-presentation-footer{display:none}.netless-app-presentation-wb-view{position:absolute;top:0;left:0;width:100%;height:100%;z-index:100;overflow:hidden;transition:opacity .2s}.netless-app-presentation-image{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.netless-app-presentation-image>img{max-width:100%;max-height:100%;object-fit:contain}.telebox-color-scheme-dark .netless-app-presentation-page-number-input{color:#a6a6a8}.telebox-color-scheme-dark .netless-app-presentation-page-number-input:active,.telebox-color-scheme-dark .netless-app-presentation-page-number-input:focus,.telebox-color-scheme-dark .netless-app-presentation-page-number-input:hover{color:#222}.telebox-color-scheme-dark .netless-app-presentation-footer{color:#a6a6a8;background:#2d2d33;border-top:none}.telebox-color-scheme-dark .netless-app-presentation-footer-btn:hover{background:#212126}.telebox-color-scheme-dark .netless-app-presentation-preview{background:#323232e6}.netless-app-presentation-scrollbar-container{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;z-index:101}.netless-app-presentation-scrollbar-container-x,.netless-app-presentation-scrollbar-container-y{position:absolute;pointer-events:none;display:flex;justify-content:center;box-sizing:border-box;padding:0}.netless-app-presentation-scrollbar-container-x{bottom:0;left:0;height:6px;width:100%;padding-right:6px}.netless-app-presentation-scrollbar-container-y{top:0;right:0;width:6px;height:100%;flex-direction:column;padding-bottom:6px}.netless-app-presentation-scrollbar-x,.netless-app-presentation-scrollbar-y{border-radius:2px;background-color:#1b1f4d4d;pointer-events:auto;cursor:default}.netless-app-presentation-scrollbar-x{height:6px}.netless-app-presentation-scrollbar-y{width:6px}";
|
|
1534
|
+
var style_default = ".netless-app-presentation{height:100%;display:flex;flex-flow:column nowrap}.netless-app-presentation-content{position:relative;height:100%;overflow:hidden}.netless-app-presentation-background-suspended .background{display:none!important}.netless-app-presentation-preview-mask{display:none;position:absolute;z-index:200;top:0;left:0;width:100%;height:100%}.netless-app-presentation-preview{display:flex;flex-direction:column;align-items:center;position:absolute;z-index:300;top:0;left:0;width:33%;max-width:200px;height:100%;padding-top:10px;transform:translate(-100%);background:#ededf0e6;box-shadow:inset -1px 0 #0000001c;transition:transform .4s;overflow:auto;overflow-y:scroll}.netless-app-presentation-preview-active .netless-app-presentation-preview-mask{display:block}.netless-app-presentation-preview-active .netless-app-presentation-preview{transform:translate(0)}.netless-app-presentation-preview-page{position:relative;display:block;width:55%;margin-bottom:10px;font-size:0;color:#0000;outline:none;border:7px solid rgba(0,0,0,0);border-radius:4px;transition:border-color .3s;user-select:none}.netless-app-presentation-preview-page:hover,.netless-app-presentation-preview-page.netless-app-presentation-preview-page-active{border-color:#444e601a}.netless-app-presentation-preview-page>img{width:100%;height:auto;box-sizing:border-box;border:1px solid rgba(0,0,0,.5);border-radius:1px;background-color:#fff;box-shadow:0 2px 8px #0000004d}.netless-app-presentation-preview-page-name{position:absolute;top:1px;left:-10px;transform:translate(-100%);text-align:right;font-size:12px;color:#5f5f5f;user-select:none}.netless-app-presentation-footer{box-sizing:border-box;height:26px;display:flex;align-items:center;padding:0 16px;border-top:1px solid #eeeef7;color:#191919}.netless-app-presentation-float-footer{width:100%;min-height:26px;position:absolute;left:0;bottom:0;z-index:2000;background:#f9f9fce6;transition:opacity .4s}.netless-app-presentation-footer-btn{box-sizing:border-box;width:26px;height:26px;font-size:0;margin:0;padding:3px;border:none;border-radius:1px;outline:none;color:currentColor;background:#0000;transition:background .4s;cursor:pointer;user-select:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}.netless-app-presentation-footer-btn:hover{background:#ededf0e6}@media (hover: none){.netless-app-presentation-footer-btn:hover{background:#0000!important}}.netless-app-presentation-footer-btn>svg{width:100%;height:100%}.netless-app-presentation-footer-btn>svg:nth-of-type(2){display:none}.netless-app-presentation-footer-btn.netless-app-presentation-footer-btn-playing>svg:nth-of-type(1){display:none}.netless-app-presentation-footer-btn.netless-app-presentation-footer-btn-playing>svg:nth-of-type(2){display:initial}.netless-app-presentation-footer-btn~.netless-app-presentation-footer-btn{margin-left:15px}.netless-app-presentation-page-jumps{flex:1;display:flex;justify-content:center;align-items:center}.netless-app-presentation-page-number{margin-left:auto;font-size:13px;user-select:none;white-space:nowrap;word-break:keep-all}.netless-app-presentation-page-number-input{border:none;outline:none;width:3em;margin:0;padding:0 2px;text-align:right;font-size:13px;line-height:1;font-weight:400;font-family:inherit;border-radius:2px;color:currentColor;background:#0000;transition:background .4s;user-select:text;-webkit-tap-highlight-color:rgba(0,0,0,0)}.netless-app-presentation-page-number-input:hover,.netless-app-presentation-page-number-input:focus,.netless-app-presentation-page-number-input:active{background:#fff;box-shadow:#63636333 0 2px 8px}.netless-app-presentation-readonly.netless-app-presentation-footer{display:none}.netless-app-presentation-wb-view{position:absolute;top:0;left:0;width:100%;height:100%;z-index:100;overflow:hidden;transition:opacity .2s}.netless-app-presentation-image{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.netless-app-presentation-image>img{max-width:100%;max-height:100%;object-fit:contain}.telebox-color-scheme-dark .netless-app-presentation-page-number-input{color:#a6a6a8}.telebox-color-scheme-dark .netless-app-presentation-page-number-input:active,.telebox-color-scheme-dark .netless-app-presentation-page-number-input:focus,.telebox-color-scheme-dark .netless-app-presentation-page-number-input:hover{color:#222}.telebox-color-scheme-dark .netless-app-presentation-footer{color:#a6a6a8;background:#2d2d33;border-top:none}.telebox-color-scheme-dark .netless-app-presentation-footer-btn:hover{background:#212126}.telebox-color-scheme-dark .netless-app-presentation-preview{background:#323232e6}.netless-app-presentation-scrollbar-container{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;z-index:101}.netless-app-presentation-scrollbar-container-x,.netless-app-presentation-scrollbar-container-y{position:absolute;pointer-events:none;display:flex;justify-content:center;box-sizing:border-box;padding:0}.netless-app-presentation-scrollbar-container-x{bottom:0;left:0;height:6px;width:100%;padding-right:6px}.netless-app-presentation-scrollbar-container-y{top:0;right:0;width:6px;height:100%;flex-direction:column;padding-bottom:6px}.netless-app-presentation-scrollbar-x,.netless-app-presentation-scrollbar-y{border-radius:2px;background-color:#1b1f4d4d;pointer-events:auto;cursor:default}.netless-app-presentation-scrollbar-x{height:6px}.netless-app-presentation-scrollbar-y{width:6px}";
|
|
1505
1535
|
|
|
1506
1536
|
// src/store.ts
|
|
1507
1537
|
function noop() {
|
|
@@ -1947,6 +1977,23 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
1947
1977
|
};
|
|
1948
1978
|
}
|
|
1949
1979
|
|
|
1980
|
+
// src/runtime-lifecycle.ts
|
|
1981
|
+
var createPresentationRuntimeTeardown = (box, dispose2) => {
|
|
1982
|
+
let tornDown = false;
|
|
1983
|
+
return () => {
|
|
1984
|
+
if (tornDown)
|
|
1985
|
+
return;
|
|
1986
|
+
tornDown = true;
|
|
1987
|
+
try {
|
|
1988
|
+
dispose2();
|
|
1989
|
+
} finally {
|
|
1990
|
+
box.unmountContent();
|
|
1991
|
+
box.unmountFooter();
|
|
1992
|
+
box.unmountStyles();
|
|
1993
|
+
}
|
|
1994
|
+
};
|
|
1995
|
+
};
|
|
1996
|
+
|
|
1950
1997
|
// src/app-presentation.ts
|
|
1951
1998
|
var import_debounce2 = __toESM(require_debounce());
|
|
1952
1999
|
var emptySceneName = "$$empty$$";
|
|
@@ -1956,6 +2003,211 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
1956
2003
|
const size = fitPageSizeToOrigin(ppt, originSize);
|
|
1957
2004
|
return __spreadProps(__spreadValues({}, size), { src: ppt.src, thumbnail: ppt.previewURL, name });
|
|
1958
2005
|
};
|
|
2006
|
+
var findBackgroundImage = (view) => {
|
|
2007
|
+
const container = view.divElement;
|
|
2008
|
+
if (!container || typeof container.querySelector !== "function")
|
|
2009
|
+
return null;
|
|
2010
|
+
return container.querySelector('img[alt="background"]');
|
|
2011
|
+
};
|
|
2012
|
+
var isBlurDegradationAllowed = (context) => {
|
|
2013
|
+
var _a;
|
|
2014
|
+
if (((_a = context.getWindowManager()) == null ? void 0 : _a.lazySetupInMaximizedMode) !== true) {
|
|
2015
|
+
return false;
|
|
2016
|
+
}
|
|
2017
|
+
const boxStatus = context.getBoxStatus();
|
|
2018
|
+
if (boxStatus) {
|
|
2019
|
+
return boxStatus !== "normal";
|
|
2020
|
+
}
|
|
2021
|
+
const boxState = context.getWindowManager().boxState;
|
|
2022
|
+
return boxState !== void 0 && boxState !== "normal";
|
|
2023
|
+
};
|
|
2024
|
+
var DEFAULT_SETUP_READY_TIMEOUT = 5e3;
|
|
2025
|
+
var waitForCurrentPageImage = (view, timeoutMs, isDisposed) => {
|
|
2026
|
+
return new Promise((resolve) => {
|
|
2027
|
+
let settled = false;
|
|
2028
|
+
let pollTimer;
|
|
2029
|
+
const settle = (loaded) => {
|
|
2030
|
+
if (settled)
|
|
2031
|
+
return;
|
|
2032
|
+
settled = true;
|
|
2033
|
+
window.clearTimeout(timeoutTimer);
|
|
2034
|
+
if (pollTimer !== void 0)
|
|
2035
|
+
window.clearInterval(pollTimer);
|
|
2036
|
+
resolve(loaded);
|
|
2037
|
+
};
|
|
2038
|
+
const timeoutTimer = window.setTimeout(() => settle(false), timeoutMs);
|
|
2039
|
+
const check = () => {
|
|
2040
|
+
if (isDisposed()) {
|
|
2041
|
+
settle(false);
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2044
|
+
const img = findBackgroundImage(view);
|
|
2045
|
+
if (img && img.complete && img.naturalWidth > 0) {
|
|
2046
|
+
settle(true);
|
|
2047
|
+
}
|
|
2048
|
+
};
|
|
2049
|
+
check();
|
|
2050
|
+
if (!settled) {
|
|
2051
|
+
pollTimer = window.setInterval(check, 100);
|
|
2052
|
+
}
|
|
2053
|
+
});
|
|
2054
|
+
};
|
|
2055
|
+
var resolveImageUrl = (url) => {
|
|
2056
|
+
try {
|
|
2057
|
+
return new URL(url, window.location.href).href;
|
|
2058
|
+
} catch (e) {
|
|
2059
|
+
return url;
|
|
2060
|
+
}
|
|
2061
|
+
};
|
|
2062
|
+
var TRANSPARENT_BACKGROUND = "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";
|
|
2063
|
+
var BACKGROUND_SUSPENDED_CLASS = "netless-app-presentation-background-suspended";
|
|
2064
|
+
var hasUsableThumbnail = (page) => {
|
|
2065
|
+
const thumbnailURL = page.thumbnail;
|
|
2066
|
+
if (!thumbnailURL)
|
|
2067
|
+
return false;
|
|
2068
|
+
try {
|
|
2069
|
+
const source = new URL(page.src, window.location.href);
|
|
2070
|
+
const thumbnail = new URL(thumbnailURL, window.location.href);
|
|
2071
|
+
const sameResourcePath = source.origin === thumbnail.origin && source.pathname === thumbnail.pathname;
|
|
2072
|
+
if (/\.gif$/i.test(source.pathname) && sameResourcePath)
|
|
2073
|
+
return false;
|
|
2074
|
+
} catch (e) {
|
|
2075
|
+
if (/\.gif(?:$|[?#])/i.test(page.src))
|
|
2076
|
+
return false;
|
|
2077
|
+
}
|
|
2078
|
+
return resolveImageUrl(thumbnailURL) !== resolveImageUrl(page.src);
|
|
2079
|
+
};
|
|
2080
|
+
var setupBlurThumbnailDegradation = (config) => {
|
|
2081
|
+
const { context, view, pages, pageIndex$, app, dispose: dispose2 } = config;
|
|
2082
|
+
const box = context.getBox();
|
|
2083
|
+
const boxBlurClass = box.wrapClassName("blur");
|
|
2084
|
+
let blurEpisode = false;
|
|
2085
|
+
let reDegradeEnabled = false;
|
|
2086
|
+
let boxBlurred = box.$box.classList.contains(boxBlurClass);
|
|
2087
|
+
const setBackgroundSuspended = (suspended) => {
|
|
2088
|
+
app.whiteboardDOM.classList.toggle(
|
|
2089
|
+
BACKGROUND_SUSPENDED_CLASS,
|
|
2090
|
+
suspended
|
|
2091
|
+
);
|
|
2092
|
+
};
|
|
2093
|
+
const degrade = () => {
|
|
2094
|
+
const page = pages[pageIndex$.value];
|
|
2095
|
+
if (!page)
|
|
2096
|
+
return;
|
|
2097
|
+
const thumbnailURL = page.thumbnail;
|
|
2098
|
+
const img = findBackgroundImage(view);
|
|
2099
|
+
if (!thumbnailURL || !hasUsableThumbnail(page)) {
|
|
2100
|
+
if (boxBlurred) {
|
|
2101
|
+
setBackgroundSuspended(true);
|
|
2102
|
+
if (img && resolveImageUrl(img.src) !== resolveImageUrl(TRANSPARENT_BACKGROUND)) {
|
|
2103
|
+
img.src = TRANSPARENT_BACKGROUND;
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
return;
|
|
2107
|
+
}
|
|
2108
|
+
setBackgroundSuspended(false);
|
|
2109
|
+
if (img && resolveImageUrl(img.src) !== resolveImageUrl(thumbnailURL)) {
|
|
2110
|
+
img.src = thumbnailURL;
|
|
2111
|
+
}
|
|
2112
|
+
};
|
|
2113
|
+
const restore2 = () => {
|
|
2114
|
+
const page = pages[pageIndex$.value];
|
|
2115
|
+
const img = findBackgroundImage(view);
|
|
2116
|
+
if (page && img && resolveImageUrl(img.src) !== resolveImageUrl(page.src)) {
|
|
2117
|
+
img.src = page.src;
|
|
2118
|
+
}
|
|
2119
|
+
setBackgroundSuspended(false);
|
|
2120
|
+
};
|
|
2121
|
+
const suspendCachedResources = () => {
|
|
2122
|
+
if (!blurEpisode || !boxBlurred)
|
|
2123
|
+
return;
|
|
2124
|
+
app.suspendPreviewResources();
|
|
2125
|
+
const page = pages[pageIndex$.value];
|
|
2126
|
+
if (!page || !hasUsableThumbnail(page) || reDegradeEnabled) {
|
|
2127
|
+
degrade();
|
|
2128
|
+
}
|
|
2129
|
+
};
|
|
2130
|
+
const restoreFocusedResources = () => {
|
|
2131
|
+
if (!blurEpisode)
|
|
2132
|
+
return;
|
|
2133
|
+
blurEpisode = false;
|
|
2134
|
+
reDegradeEnabled = false;
|
|
2135
|
+
restore2();
|
|
2136
|
+
app.preload.resume(pageIndex$.value);
|
|
2137
|
+
};
|
|
2138
|
+
const isBackgroundImg = (target) => {
|
|
2139
|
+
var _a;
|
|
2140
|
+
const el = target;
|
|
2141
|
+
return Boolean(
|
|
2142
|
+
el && el.tagName === "IMG" && ((_a = el.matches) == null ? void 0 : _a.call(el, 'img[alt="background"]'))
|
|
2143
|
+
);
|
|
2144
|
+
};
|
|
2145
|
+
const ownsTarget = (target) => {
|
|
2146
|
+
if (!isBackgroundImg(target))
|
|
2147
|
+
return false;
|
|
2148
|
+
const el = view.divElement;
|
|
2149
|
+
return !!(el && el.contains(target));
|
|
2150
|
+
};
|
|
2151
|
+
const onImgLoad = (ev) => {
|
|
2152
|
+
if (!blurEpisode || !reDegradeEnabled)
|
|
2153
|
+
return;
|
|
2154
|
+
if (!ownsTarget(ev.target))
|
|
2155
|
+
return;
|
|
2156
|
+
degrade();
|
|
2157
|
+
};
|
|
2158
|
+
const onImgError = (ev) => {
|
|
2159
|
+
if (!blurEpisode || !reDegradeEnabled)
|
|
2160
|
+
return;
|
|
2161
|
+
if (!ownsTarget(ev.target))
|
|
2162
|
+
return;
|
|
2163
|
+
reDegradeEnabled = false;
|
|
2164
|
+
};
|
|
2165
|
+
const offFocus = context.emitter.on("focus", (isFocused) => {
|
|
2166
|
+
if (isFocused) {
|
|
2167
|
+
restoreFocusedResources();
|
|
2168
|
+
} else {
|
|
2169
|
+
if (!isBlurDegradationAllowed(context))
|
|
2170
|
+
return;
|
|
2171
|
+
blurEpisode = true;
|
|
2172
|
+
reDegradeEnabled = true;
|
|
2173
|
+
degrade();
|
|
2174
|
+
app.preload.pause();
|
|
2175
|
+
suspendCachedResources();
|
|
2176
|
+
}
|
|
2177
|
+
});
|
|
2178
|
+
dispose2.add(offFocus);
|
|
2179
|
+
const updateBoxBlurred = (blurred) => {
|
|
2180
|
+
if (boxBlurred === blurred)
|
|
2181
|
+
return;
|
|
2182
|
+
boxBlurred = blurred;
|
|
2183
|
+
if (blurred)
|
|
2184
|
+
suspendCachedResources();
|
|
2185
|
+
else
|
|
2186
|
+
restoreFocusedResources();
|
|
2187
|
+
};
|
|
2188
|
+
const onBoxBlur = () => updateBoxBlurred(true);
|
|
2189
|
+
const onBoxFocus = () => updateBoxBlurred(false);
|
|
2190
|
+
box.events.on("blur", onBoxBlur);
|
|
2191
|
+
box.events.on("focus", onBoxFocus);
|
|
2192
|
+
dispose2.add(() => {
|
|
2193
|
+
box.events.off("blur", onBoxBlur);
|
|
2194
|
+
box.events.off("focus", onBoxFocus);
|
|
2195
|
+
});
|
|
2196
|
+
const boxClassObserver = new MutationObserver(() => {
|
|
2197
|
+
updateBoxBlurred(box.$box.classList.contains(boxBlurClass));
|
|
2198
|
+
});
|
|
2199
|
+
boxClassObserver.observe(box.$box, {
|
|
2200
|
+
attributes: true,
|
|
2201
|
+
attributeFilter: ["class"]
|
|
2202
|
+
});
|
|
2203
|
+
dispose2.add(() => boxClassObserver.disconnect());
|
|
2204
|
+
document.addEventListener("load", onImgLoad, true);
|
|
2205
|
+
document.addEventListener("error", onImgError, true);
|
|
2206
|
+
dispose2.add(() => {
|
|
2207
|
+
document.removeEventListener("load", onImgLoad, true);
|
|
2208
|
+
document.removeEventListener("error", onImgError, true);
|
|
2209
|
+
});
|
|
2210
|
+
};
|
|
1959
2211
|
var createLogger = (room) => {
|
|
1960
2212
|
if (room && room.logger) {
|
|
1961
2213
|
return (...args) => room.logger.info(...args);
|
|
@@ -2031,7 +2283,7 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
2031
2283
|
var NetlessAppPresentation = {
|
|
2032
2284
|
kind: "Presentation",
|
|
2033
2285
|
setup(context) {
|
|
2034
|
-
var _a, _b, _c;
|
|
2286
|
+
var _a, _b, _c, _d;
|
|
2035
2287
|
const diagnosticLogger = createDiagnosticLogger(context);
|
|
2036
2288
|
const view = context.getView();
|
|
2037
2289
|
if (!view)
|
|
@@ -2377,10 +2629,13 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
2377
2629
|
options.useClipView
|
|
2378
2630
|
)
|
|
2379
2631
|
);
|
|
2380
|
-
app.contentDOM.dataset.appPresentationVersion = "0.1.13-beta.
|
|
2632
|
+
app.contentDOM.dataset.appPresentationVersion = "0.1.13-beta.2";
|
|
2381
2633
|
app.scaleDocsToFit = scaleDocsToFit;
|
|
2382
2634
|
app.log = log;
|
|
2383
2635
|
app.warn = warn;
|
|
2636
|
+
if (pageIndex$.value !== 0) {
|
|
2637
|
+
app.preload.touch(pageIndex$.value, true);
|
|
2638
|
+
}
|
|
2384
2639
|
const getCameraDiagnosticState = (reason, requestedCamera) => {
|
|
2385
2640
|
const page = app.page();
|
|
2386
2641
|
const pageSize = page && isValidSize(page) ? { width: page.width, height: page.height } : void 0;
|
|
@@ -2437,8 +2692,8 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
2437
2692
|
app.setDocsViewReadonly(true);
|
|
2438
2693
|
}
|
|
2439
2694
|
const goToPageByClick = () => {
|
|
2440
|
-
var _a2, _b2, _c2,
|
|
2441
|
-
const currentApplianceName = (
|
|
2695
|
+
var _a2, _b2, _c2, _d2;
|
|
2696
|
+
const currentApplianceName = (_d2 = (_c2 = (_b2 = (_a2 = context.getRoom()) == null ? void 0 : _a2.state) == null ? void 0 : _b2.memberState) == null ? void 0 : _c2.currentApplianceName) != null ? _d2 : "";
|
|
2442
2697
|
if (!app.readonly && currentApplianceName === "clicker") {
|
|
2443
2698
|
nextPage();
|
|
2444
2699
|
}
|
|
@@ -2485,6 +2740,9 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
2485
2740
|
app.setReadonly(!isWritable);
|
|
2486
2741
|
})
|
|
2487
2742
|
);
|
|
2743
|
+
if (!options.disableBlurThumbnailDegradation) {
|
|
2744
|
+
setupBlurThumbnailDegradation({ context, view, pages, pageIndex$, app, dispose: dispose2 });
|
|
2745
|
+
}
|
|
2488
2746
|
const getOriginScale = () => {
|
|
2489
2747
|
const page = app.page();
|
|
2490
2748
|
if (!page || !isValidSize(page))
|
|
@@ -2613,6 +2871,10 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
2613
2871
|
};
|
|
2614
2872
|
let disposed = false;
|
|
2615
2873
|
let offDestroy;
|
|
2874
|
+
const teardownRuntime = createPresentationRuntimeTeardown(
|
|
2875
|
+
box,
|
|
2876
|
+
dispose2
|
|
2877
|
+
);
|
|
2616
2878
|
const teardown = () => {
|
|
2617
2879
|
if (disposed)
|
|
2618
2880
|
return;
|
|
@@ -2620,7 +2882,7 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
2620
2882
|
const removeDestroy = offDestroy;
|
|
2621
2883
|
offDestroy = void 0;
|
|
2622
2884
|
removeDestroy == null ? void 0 : removeDestroy();
|
|
2623
|
-
|
|
2885
|
+
teardownRuntime();
|
|
2624
2886
|
};
|
|
2625
2887
|
offDestroy = context.emitter.on("destroy", teardown);
|
|
2626
2888
|
teardownByContext.set(context, teardown);
|
|
@@ -2834,9 +3096,14 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
2834
3096
|
}
|
|
2835
3097
|
)
|
|
2836
3098
|
);
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
3099
|
+
const setupReadyTimeout = (_d = options.setupReadyTimeout) != null ? _d : DEFAULT_SETUP_READY_TIMEOUT;
|
|
3100
|
+
return prepareScenesPromise.then(async () => {
|
|
3101
|
+
const loaded = await waitForCurrentPageImage(view, setupReadyTimeout, () => disposed);
|
|
3102
|
+
if (!loaded && !disposed) {
|
|
3103
|
+
warn(`[Presentation] setup ready wait timed out after ${setupReadyTimeout}ms`);
|
|
3104
|
+
}
|
|
3105
|
+
return controller;
|
|
3106
|
+
});
|
|
2840
3107
|
},
|
|
2841
3108
|
teardown(context) {
|
|
2842
3109
|
var _a;
|
|
@@ -2922,13 +3189,14 @@ var NetlessAppPresentation = (function (exports) {
|
|
|
2922
3189
|
};
|
|
2923
3190
|
|
|
2924
3191
|
// src/index.ts
|
|
2925
|
-
var version = "0.1.13-beta.
|
|
3192
|
+
var version = "0.1.13-beta.2";
|
|
2926
3193
|
|
|
2927
3194
|
exports.NetlessAppPresentation = NetlessAppPresentation;
|
|
2928
3195
|
exports.Presentation = Presentation;
|
|
2929
3196
|
exports.Scrollbar = Scrollbar;
|
|
2930
3197
|
exports.default = NetlessAppPresentation;
|
|
2931
3198
|
exports.install = install;
|
|
3199
|
+
exports.setupBlurThumbnailDegradation = setupBlurThumbnailDegradation;
|
|
2932
3200
|
exports.version = version;
|
|
2933
3201
|
|
|
2934
3202
|
Object.defineProperty(exports, '__esModule', { value: true });
|