@netless/app-slide 0.2.51 → 0.2.52

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/app-slide",
3
- "version": "0.2.51",
3
+ "version": "0.2.52",
4
4
  "main": "dist/main.cjs.js",
5
5
  "module": "dist/main.es.js",
6
6
  "types": "dist/index.d.ts",
@@ -17,14 +17,20 @@ export interface DocsViewerPage {
17
17
 
18
18
  export interface DocsViewerConfig {
19
19
  readonly: boolean;
20
- onNewPageIndex: (index: number) => void;
20
+ onNewPageIndex: (index: number, origin?: string) => void;
21
21
  onPlay?: () => void;
22
22
  urlInterrupter?: (url: string) => Promise<string>;
23
23
  onPagesReady?: (pages: DocsViewerPage[]) => void;
24
24
  }
25
25
 
26
26
  export class DocsViewer {
27
- public constructor({ readonly, onNewPageIndex, onPlay, onPagesReady, urlInterrupter }: DocsViewerConfig) {
27
+ public constructor({
28
+ readonly,
29
+ onNewPageIndex,
30
+ onPlay,
31
+ onPagesReady,
32
+ urlInterrupter,
33
+ }: DocsViewerConfig) {
28
34
  this.readonly = readonly;
29
35
  this.onNewPageIndex = onNewPageIndex;
30
36
  this.onPlay = onPlay;
@@ -35,9 +41,9 @@ export class DocsViewer {
35
41
  }
36
42
 
37
43
  protected readonly: boolean;
38
- protected onNewPageIndex: (index: number) => void;
44
+ protected onNewPageIndex: (index: number, origin?: string) => void;
39
45
  protected onPlay?: () => void;
40
- protected onPagesReady?: (pages: DocsViewerPage[]) => void
46
+ protected onPagesReady?: (pages: DocsViewerPage[]) => void;
41
47
  protected urlInterrupter: (url: string) => Promise<string> | string;
42
48
 
43
49
  private _pages: DocsViewerPage[] = [];
@@ -147,7 +153,7 @@ export class DocsViewer {
147
153
  ev.preventDefault();
148
154
  ev.stopPropagation();
149
155
  ev.stopImmediatePropagation();
150
- this.onNewPageIndex(Number(pageIndex));
156
+ this.onNewPageIndex(Number(pageIndex), "preview");
151
157
  this.togglePreview(false);
152
158
  }
153
159
  });
@@ -174,7 +180,7 @@ export class DocsViewer {
174
180
  }
175
181
  // Promise.all(), but no closure
176
182
  for (let i = 0, len = this.pages.length; i < len; i++) {
177
- previewSRCs[i] = await previewSRCs[i]
183
+ previewSRCs[i] = await previewSRCs[i];
178
184
  }
179
185
 
180
186
  this.pages.forEach((page, i) => {
@@ -270,7 +276,7 @@ export class DocsViewer {
270
276
  if (this.readonly) {
271
277
  return;
272
278
  }
273
- this.onNewPageIndex(this.pageIndex - 1);
279
+ this.onNewPageIndex(this.pageIndex - 1, "navigation");
274
280
  });
275
281
  $pageJumps.appendChild($btnPageBack);
276
282
 
@@ -299,7 +305,7 @@ export class DocsViewer {
299
305
  if (this.readonly) {
300
306
  return;
301
307
  }
302
- this.onNewPageIndex(this.pageIndex + 1);
308
+ this.onNewPageIndex(this.pageIndex + 1, "navigation");
303
309
  });
304
310
  $pageJumps.appendChild($btnPageNext);
305
311
 
@@ -321,7 +327,7 @@ export class DocsViewer {
321
327
  return;
322
328
  }
323
329
  if ($pageNumberInput.value) {
324
- this.onNewPageIndex(Number($pageNumberInput.value) - 1);
330
+ this.onNewPageIndex(Number($pageNumberInput.value) - 1, "input");
325
331
  }
326
332
  });
327
333
 
@@ -39,9 +39,14 @@ export interface SlideControllerOptions {
39
39
  onTransitionEnd: () => void;
40
40
  onError: (args: { error: Error; index: number }) => void;
41
41
  onRenderError?: (error: Error, pageIndex: number) => void;
42
+ onNavigate?: (index: number, origin?: string) => void;
42
43
  showRenderError?: boolean;
43
44
  }
44
45
 
46
+ const noop = function noop() {
47
+ // do nothing
48
+ };
49
+
45
50
  type MagixEventListener = Parameters<
46
51
  AppContext<Attributes, MagixEvents>["addMagixEventListener"]
47
52
  >[1];
@@ -51,6 +56,7 @@ export class SlideController {
51
56
  public readonly slide: Slide;
52
57
  public readonly showRenderError: boolean;
53
58
  public readonly onRenderError?: (error: Error, pageIndex: number) => void;
59
+ public readonly onNavigate: (index: number, origin?: string) => void;
54
60
 
55
61
  private readonly room?: Room;
56
62
  private readonly player?: Player;
@@ -74,14 +80,16 @@ export class SlideController {
74
80
  onPageChanged,
75
81
  onTransitionStart,
76
82
  onTransitionEnd,
83
+ onNavigate,
77
84
  onError,
78
85
  onRenderError,
79
86
  showRenderError,
80
87
  }: SlideControllerOptions) {
81
- this.onRenderStart = onRenderStart
88
+ this.onRenderStart = onRenderStart;
82
89
  this.onPageChanged = onPageChanged;
83
90
  this.onTransitionStart = onTransitionStart;
84
91
  this.onTransitionEnd = onTransitionEnd;
92
+ this.onNavigate = onNavigate || noop;
85
93
  this.onError = onError;
86
94
  this.onRenderError = onRenderError;
87
95
  this.showRenderError = showRenderError ?? true;
@@ -116,9 +124,16 @@ export class SlideController {
116
124
  };
117
125
  });
118
126
 
119
- public jumpToPage(page: number) {
127
+ // origin = why it happens
128
+ // - undefined: via fastboard dispatchDocsEvent()
129
+ // - input: via bottom-right page number input box
130
+ // - preview: via the left preview menu's item
131
+ // - navigation: via the footer's back/next button
132
+ // - keydown: via global arrow left/right keydown
133
+ public jumpToPage(page: number, origin?: string) {
120
134
  if (this.ready) {
121
135
  page = clamp(page, 1, this.pageCount);
136
+ this.onNavigate(page, origin);
122
137
  this.slide.renderSlide(page);
123
138
  }
124
139
  }
@@ -244,8 +259,7 @@ export class SlideController {
244
259
  setTimeout(this.pollReadyState, 500);
245
260
  } else {
246
261
  this.pollCount = 0;
247
- log("[Slide] renderSlide 1 (retry after timeout)");
248
- this.slide.renderSlide(1);
262
+ log("[Slide] init timeout");
249
263
  }
250
264
  };
251
265
 
@@ -3,12 +3,16 @@ import type { SlideController, SlideControllerOptions } from "../SlideController
3
3
 
4
4
  import { SideEffectManager } from "side-effect-manager";
5
5
  import { createDocsViewerPages } from "../SlideController";
6
- import { DocsViewer, DocsViewerPage } from "../DocsViewer";
6
+ import { DocsViewer, type DocsViewerPage } from "../DocsViewer";
7
7
  import { logger } from "../utils/logger";
8
8
  import { isEditable } from "../utils/helpers";
9
9
 
10
10
  export const ClickThroughAppliances = new Set(["clicker"]);
11
11
 
12
+ const noop = function noop() {
13
+ // do nothing
14
+ };
15
+
12
16
  export type MountSlideOptions = Omit<SlideControllerOptions, "context" | "onPageChanged"> & {
13
17
  onReady: () => void;
14
18
  };
@@ -22,6 +26,7 @@ export interface SlideDocsViewerConfig {
22
26
  appId: string;
23
27
  urlInterrupter?: (url: string) => Promise<string>;
24
28
  onPagesReady?: (pages: DocsViewerPage[]) => void;
29
+ onNavigate?: (index: number, origin?: string) => void;
25
30
  }
26
31
 
27
32
  export interface SavePdfConfig {
@@ -37,6 +42,7 @@ export class SlideDocsViewer {
37
42
  protected readonly whiteboardView: SlideDocsViewerConfig["view"];
38
43
  protected readonly mountSlideController: SlideDocsViewerConfig["mountSlideController"];
39
44
  protected readonly mountWhiteboard: SlideDocsViewerConfig["mountWhiteboard"];
45
+ protected readonly onNavigate: (index: number, origin?: string) => void;
40
46
  private readonly baseScenePath: string;
41
47
  private readonly appId: string;
42
48
  private isViewMounted = false;
@@ -50,11 +56,13 @@ export class SlideDocsViewer {
50
56
  appId,
51
57
  urlInterrupter,
52
58
  onPagesReady,
59
+ onNavigate,
53
60
  }: SlideDocsViewerConfig) {
54
61
  this.box = box;
55
62
  this.whiteboardView = view;
56
63
  this.mountSlideController = mountSlideController;
57
64
  this.mountWhiteboard = mountWhiteboard;
65
+ this.onNavigate = onNavigate || noop;
58
66
  this.baseScenePath = baseScenePath;
59
67
  this.appId = appId;
60
68
  this.viewer = new DocsViewer({
@@ -101,11 +109,13 @@ export class SlideDocsViewer {
101
109
  case "ArrowUp":
102
110
  case "ArrowLeft": {
103
111
  this.slideController.slide.prevStep();
112
+ this.onNavigate(this.slideController.page, "keydown");
104
113
  break;
105
114
  }
106
115
  case "ArrowRight":
107
116
  case "ArrowDown": {
108
117
  this.slideController.slide.nextStep();
118
+ this.onNavigate(this.slideController.page, "keydown");
109
119
  break;
110
120
  }
111
121
  default: {
@@ -154,6 +164,7 @@ export class SlideDocsViewer {
154
164
  onTransitionStart: this.viewer.setPlaying,
155
165
  onTransitionEnd: this.viewer.setPaused,
156
166
  onReady: this.refreshPages,
167
+ onNavigate: this.onNavigate,
157
168
  onError: this.onError,
158
169
  });
159
170
 
@@ -271,9 +282,9 @@ export class SlideDocsViewer {
271
282
  }
272
283
  };
273
284
 
274
- protected onNewPageIndex = (index: number) => {
285
+ protected onNewPageIndex = (index: number, origin?: string) => {
275
286
  if (this.slideController) {
276
- this.slideController.jumpToPage(index + 1);
287
+ this.slideController.jumpToPage(index + 1, origin);
277
288
  }
278
289
  };
279
290
 
package/src/index.ts CHANGED
@@ -147,6 +147,7 @@ const SlideApp: NetlessApp<Attributes, MagixEvents, AppOptions, AppResult> = {
147
147
  context,
148
148
  ...options,
149
149
  onPageChanged,
150
+ onNavigate: options.onNavigate,
150
151
  onRenderError: appOptions.onRenderError,
151
152
  showRenderError: appOptions.showRenderError,
152
153
  });
@@ -181,7 +182,10 @@ const SlideApp: NetlessApp<Attributes, MagixEvents, AppOptions, AppResult> = {
181
182
  onPagesReady: ({ length }) => {
182
183
  const index = docsViewer?.viewer.pageIndex || 0;
183
184
  context.dispatchAppEvent("pageStateChange", { index, length });
184
- }
185
+ },
186
+ onNavigate: (page, origin) => {
187
+ log("[Slide] user navigate to", page, origin ? `(${origin})` : "");
188
+ },
185
189
  });
186
190
 
187
191
  if (import.meta.env.DEV) {
@@ -1,6 +1,6 @@
1
- import type { Displayer } from "white-web-sdk"
2
- import type { ISlideConfig } from "@netless/slide"
1
+ import type { Displayer } from "white-web-sdk";
2
+ import type { ISlideConfig } from "@netless/slide";
3
3
 
4
4
  export const getRoomTracker = (displayer: Displayer): ISlideConfig["whiteTracker"] => {
5
- return (displayer as any).tracker;
6
- }
5
+ return (displayer as unknown as { tracker: ISlideConfig["whiteTracker"] }).tracker;
6
+ };