@netless/slide 1.4.60 → 1.4.61

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/README.md CHANGED
@@ -4,28 +4,18 @@
4
4
 
5
5
  ## changelog
6
6
 
7
- ### 1.4.60 (2026-09-21)
8
- * 新增 `onPptMediaPermissionRequest(callback)` 与 `playPptMedia()`,支持在浏览器阻止自动播放时通知业务方并由真实用户点击恢复当前媒体
9
- * 增加 HTML5 音频和视频播放确认,覆盖浏览器静默暂停或未触发 `playerror` 的情况
10
- * 修复部分移动浏览器播放前 `duration`、`seekable` 为 0 导致 Howler 提前结束且不触发权限回调的问题
11
- * 修复视频启动时浏览器底层暂停独立音轨,以及用户点击恢复遇到 Howler pending play 无法重新播放的问题
7
+ ### 1.4.61 (2026-09-23)
8
+ * 修复部分 PPT 中点击元素无法触发动画的问题
9
+ * 修复重复触发条件导致动画重复推进的问题
10
+ * 修复 PPT 冻结、恢复和销毁并发执行时的时序问题
11
+ * `frozen()`、`release()`、`destroy()` 支持返回 Promise,便于等待操作完成
12
12
 
13
- ### 1.4.60-alpha.0 (2026-09-20)
14
- * 修复部分移动浏览器中 HTML5 音频播放请求卡住后,用户点击恢复仍无法重新发起播放的问题
15
- * 避免将媒体加载或缓冲过程误判为自动播放权限错误,并忽略旧播放请求的迟到事件
13
+ ### 1.4.60 (2026-09-21)
14
+ * 新增 PPT 媒体权限回调和点击恢复接口:`onPptMediaPermissionRequest(callback)`、`playPptMedia()`
15
+ * 修复部分移动浏览器中 PPT 音视频无法自动播放或恢复的问题
16
16
 
17
17
  ### 1.4.59 (2026-09-18)
18
- * 优化移动端切页时的 Player 与 WebGL context 生命周期,减少重复创建和资源残留
19
- * 完善 Player 原地重置、候选 Player 交换和失败回退,避免快速切页后出现白屏或旧画面
20
- * 加强纹理缓存隔离、取消任务清理和 context 释放超时保护,降低页面切换对 RTC 与其他 WebGL 内容的影响
21
-
22
- ### 1.4.59-alpha.4 (2026-09-17)
23
- * 增强 PPT 媒体自动播放恢复:为 Howler/HTML5 音频与视频增加播放确认 watchdog,覆盖浏览器静默失败未触发 `playerror` 的场景
24
- * 修正 Howler `playerror` 在内部状态已变为 playing 但 DOM 仍 paused 时被误过滤的问题
25
-
26
- ### 1.4.59-alpha.0 (2026-09-11)
27
- * 新增 `onPptMediaPermissionRequest(callback)` 接口,用于通知当前 PPT 音视频需要用户交互后才能播放
28
- * 新增 `playPptMedia()` 接口,用于在用户点击事件中恢复当前仍处于播放状态、且本地被浏览器拦截的 PPT 音视频
18
+ * 优化移动端切页时的播放器和 WebGL 资源管理,减少白屏和资源残留
29
19
 
30
20
  ### 1.4.58 (2026-09-07)
31
21
  * 修复低版本 WebView 中纯色图形显示为黑块的问题
@@ -2,13 +2,15 @@ export interface FrozenTask {
2
2
  type: "frozen" | "release";
3
3
  status: "running" | "wait";
4
4
  fn: () => Promise<void>;
5
+ promise: Promise<void>;
6
+ resolve: () => void;
7
+ reject: (error: unknown) => void;
5
8
  }
6
9
  export declare class FrozenTaskManager {
7
10
  private tasks;
8
11
  private isDestroy;
9
- private isScheduling;
12
+ private runningTask?;
10
13
  private schedule;
11
- private getRunningTask;
12
- addTask(type: "frozen" | "release", fn: () => Promise<void>): void;
13
- destroy(): void;
14
+ addTask(type: "frozen" | "release", fn: () => Promise<void>): Promise<void>;
15
+ destroy(): Promise<void>;
14
16
  }
@@ -3,56 +3,65 @@ var FrozenTaskManager = /** @class */ (function () {
3
3
  var _this = this;
4
4
  this.tasks = [];
5
5
  this.isDestroy = false;
6
- this.isScheduling = false;
7
6
  this.schedule = function () {
8
- _this.isScheduling = true;
7
+ if (_this.runningTask || _this.isDestroy) {
8
+ return;
9
+ }
9
10
  var task = _this.tasks.shift();
10
- if (task && !_this.isDestroy) {
11
- task.status = "running";
12
- task.fn.apply(null).then(function () {
13
- if (_this.tasks.length > 0) {
14
- setTimeout(_this.schedule);
15
- }
16
- else {
17
- _this.isScheduling = false;
18
- }
19
- }).catch(function () {
20
- if (_this.tasks.length > 0) {
21
- setTimeout(_this.schedule);
22
- }
23
- else {
24
- _this.isScheduling = false;
25
- }
26
- });
11
+ if (!task) {
12
+ return;
27
13
  }
14
+ task.status = "running";
15
+ _this.runningTask = task;
16
+ void task.fn.apply(null).then(task.resolve, task.reject).finally(function () {
17
+ if (_this.runningTask === task) {
18
+ _this.runningTask = undefined;
19
+ }
20
+ if (!_this.isDestroy && _this.tasks.length > 0) {
21
+ setTimeout(_this.schedule);
22
+ }
23
+ });
28
24
  };
29
25
  }
30
- FrozenTaskManager.prototype.getRunningTask = function () {
31
- if (this.tasks[0] && this.tasks[0].status === "running") {
32
- return this.tasks[0];
33
- }
34
- return null;
35
- };
36
26
  FrozenTaskManager.prototype.addTask = function (type, fn) {
27
+ var _a;
28
+ if (this.isDestroy) {
29
+ return Promise.resolve();
30
+ }
31
+ // Only consecutive requests may share a task. An opposite queued
32
+ // request separates a new intent from the running task of the same type.
33
+ var lastTask = (_a = this.tasks[this.tasks.length - 1]) !== null && _a !== void 0 ? _a : this.runningTask;
34
+ if ((lastTask === null || lastTask === void 0 ? void 0 : lastTask.type) === type) {
35
+ return lastTask.promise;
36
+ }
37
+ var resolveTask;
38
+ var rejectTask;
39
+ var promise = new Promise(function (resolve, reject) {
40
+ resolveTask = resolve;
41
+ rejectTask = reject;
42
+ });
43
+ // Existing callers are allowed to ignore frozen()/release(). Keep the
44
+ // original promise observable to awaiters without creating an
45
+ // unhandled rejection for legacy fire-and-forget calls.
46
+ promise.catch(function () { return undefined; });
37
47
  var task = {
38
48
  type: type,
39
49
  status: "wait",
40
50
  fn: fn,
51
+ promise: promise,
52
+ resolve: resolveTask,
53
+ reject: rejectTask,
41
54
  };
42
- var runningTask = this.getRunningTask();
43
- if (runningTask && type === runningTask.type) {
44
- return;
45
- }
46
- else {
47
- this.tasks = this.tasks.filter(function (v) { return v.type !== type; });
48
- this.tasks.push(task);
49
- if (!this.isScheduling) {
50
- this.schedule();
51
- }
52
- }
55
+ this.tasks.push(task);
56
+ this.schedule();
57
+ return promise;
53
58
  };
54
59
  FrozenTaskManager.prototype.destroy = function () {
60
+ var _a, _b;
55
61
  this.isDestroy = true;
62
+ var pending = this.tasks.splice(0, this.tasks.length);
63
+ pending.forEach(function (task) { return task.resolve(); });
64
+ return (_b = (_a = this.runningTask) === null || _a === void 0 ? void 0 : _a.promise.catch(function () { return undefined; })) !== null && _b !== void 0 ? _b : Promise.resolve();
56
65
  };
57
66
  return FrozenTaskManager;
58
67
  }());
package/lib/Slide.d.ts CHANGED
@@ -460,6 +460,7 @@ export declare class Slide extends Slide_base {
460
460
  private lifecycle;
461
461
  private lifecycleGeneration;
462
462
  private renderVisibilityTimers;
463
+ private destroyPromise?;
463
464
  private isLoading;
464
465
  private isReleasing;
465
466
  private interactive;
@@ -718,12 +719,12 @@ export declare class Slide extends Slide_base {
718
719
  /**
719
720
  * Enter freeze state, cache the ppt screen as an image, and release the WebGL context.
720
721
  */
721
- frozen(callback?: () => void): void;
722
+ frozen(callback?: () => void): Promise<void>;
722
723
  private _doRelease;
723
724
  /**
724
725
  * Recover from frozen state.
725
726
  */
726
- release(callback?: () => void): void;
727
+ release(callback?: () => void): Promise<void>;
727
728
  private _doDestroy;
728
729
  private waitLoadEnd;
729
730
  /**
@@ -735,7 +736,7 @@ export declare class Slide extends Slide_base {
735
736
  /**
736
737
  * Destruction method.
737
738
  */
738
- destroy(): void;
739
+ destroy(): Promise<void>;
739
740
  /**
740
741
  * Destroy the local cache of the current Slide instance, need to be called before destroy.
741
742
  */