@embedpdf-editor/chapter-snippet 1.0.2 → 1.0.3

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
@@ -143,18 +143,41 @@ viewer?.addEventListener(CHAPTER_SNIPPET_EVENTS.ready, (event) => {
143
143
 
144
144
  旧版本的 `editorInput` 仍可使用,但新代码应改为 `options`,并把 `features` 写在 `options.features` 或顶层 `features`。
145
145
 
146
- ### 章内多 PDF 分段(`source.urls[]`)
146
+ ### PDF 三步加载(Vue 2 推荐)
147
+
148
+ | 步骤 | 说明 |
149
+ | --- | --- |
150
+ | 1 | `manifest.chapters`:仅页码;`segmentPageThreshold` 写在章节上 |
151
+ | 2 | `chapterPdfLoader.loadChapterUrls`:按章 `getOneChap`,**每章只调一次** |
152
+ | 3 | `chapterPdfLoader.openPdf`(可选):解密等;省略则直接打开 `ctx.url` |
147
153
 
148
154
  ```js
149
- source: {
150
- urls: [part0Url, part1Url, part2Url],
151
- segmentPageThreshold: 5, // 例:13 页 → 3 段
155
+ options: {
156
+ manifest: {
157
+ chapters: [
158
+ {
159
+ chapterId: item._id,
160
+ title: item.title,
161
+ globalPageRange: [item.startPage, item.endPage],
162
+ localPageRange: [0, item.endPage - item.startPage],
163
+ segmentPageThreshold: item.page,
164
+ },
165
+ ],
166
+ },
167
+ chapterPdfLoader: {
168
+ async loadChapterUrls(chapter) {
169
+ const res = await getOneChap(chapter.chapterId);
170
+ if (!res.success) throw new Error(res.message);
171
+ const raw = res.data.resourceUrl;
172
+ return Array.isArray(raw) ? raw : raw ? [raw] : [];
173
+ },
174
+ },
175
+ notes: { /* ... */ },
176
+ bookmarks: { /* ... */ },
152
177
  },
153
178
  ```
154
179
 
155
- - 先加载第一段,滚动懒加载后续段;`localPageIndex` 仍为章内连续页。
156
- - 引擎内部 `documentId` 为 `chapterId#s0`、`#s1`…;**业务 API / 数据库只存 `chapterId` + `localPageIndex`**。
157
- - `chapterPdfLoader.loadPdf(chapter, segmentIndex)` 第二参数为段索引(0-based)。
180
+ 勿在 loader 外再请求章节详情;勿把 `segmentPageThreshold` 放进 `source`。
158
181
 
159
182
  [03-manifest.md](../../docs/get-started/03-manifest.md) · [12-segmented-pdf-and-per-chapter-storage.md](../../docs/get-started/12-segmented-pdf-and-per-chapter-storage.md)
160
183
 
@@ -110,6 +110,11 @@ export declare interface ChapterDescriptor {
110
110
  * PDF 来源。可省略:须在 ChapterManager 配置 `chapterPdfLoader` 中统一加载。
111
111
  */
112
112
  source?: ChapterSource;
113
+ /**
114
+ * 章内多 PDF 分段时,每段最多页数(如 5 表示 13 页 → 3 段)。
115
+ * URL 由 `chapterPdfLoader.loadChapterUrls` 按章拉取,**不要**写在 `source` 里。
116
+ */
117
+ segmentPageThreshold?: number;
113
118
  encrypted?: boolean;
114
119
  /**
115
120
  * 仅当 OverlapOwnerStrategy = 'explicit' 时使用:
@@ -182,6 +187,9 @@ export declare class ChapterManagerPlugin extends BasePlugin<ChapterManagerPlugi
182
187
  private readonly passwordAttempts;
183
188
  private readonly pendingChapterLoadPromises;
184
189
  private readonly pendingSegmentLoadPromises;
190
+ /** 步骤 2:`loadChapterUrls` 按章缓存 */
191
+ private readonly chapterUrlsCache;
192
+ private readonly pendingChapterUrlsPromises;
185
193
  private unloadTimer;
186
194
  private documentManagerUnsubs;
187
195
  constructor(id: string, registry: PluginRegistry);
@@ -200,6 +208,8 @@ export declare class ChapterManagerPlugin extends BasePlugin<ChapterManagerPlugi
200
208
  ensureAllSegmentsLoaded(chapterId: string): Promise<ChapterLoadStatus>;
201
209
  ensureSegmentLoaded(chapterId: string, segmentIndex: number): Promise<ChapterLoadStatus>;
202
210
  private ensureSingleDocumentChapter;
211
+ private resolveChapterUrls;
212
+ private openPayloadFromUrl;
203
213
  private resolvePdfPayload;
204
214
  private startLoadSegment;
205
215
  private waitForTerminalStatus;
@@ -248,6 +258,21 @@ declare interface ChapterPageDocumentRef {
248
258
  pageIndex: number;
249
259
  }
250
260
 
261
+ /**
262
+ * 打开某一段 PDF 时的上下文(步骤 2 已拿到 urls,步骤 3 可选处理)。
263
+ */
264
+ declare interface ChapterPdfLoadContext {
265
+ chapter: ChapterDescriptor;
266
+ /** 当前要打开的段,0-based */
267
+ segmentIndex: number;
268
+ /** 该章总段数 */
269
+ segmentCount: number;
270
+ /** 步骤 2:`loadChapterUrls` 返回的完整列表 */
271
+ urls: string[];
272
+ /** 当前段对应 URL:`urls[segmentIndex]` */
273
+ url: string;
274
+ }
275
+
251
276
  /**
252
277
  * Backend-supplied chapter contract.
253
278
  *
@@ -265,6 +290,7 @@ export declare type ChapterPdfPayload = {
265
290
 
266
291
  declare interface ChapterSegmentInfo {
267
292
  index: number;
293
+ /** 静态 manifest 有值;动态 loader 时为空,打开段时再解析 URL */
268
294
  url: string;
269
295
  localPageStart: number;
270
296
  localPageEnd: number;
@@ -299,8 +325,8 @@ export declare type ChapterSource = {
299
325
  load: () => Promise<ChapterPdfPayload>;
300
326
  }
301
327
  /**
302
- * 章内多 PDF 分段(后端已按段拆分)。
303
- * `urls.length` 须为 ceil(章页数 / segmentPageThreshold)。
328
+ * @deprecated 请用章节级 `segmentPageThreshold` + `chapterPdfLoader.loadChapterUrls`。
329
+ * 静态多 URL 时:`urls.length` 须为 ceil(章页数 / segmentPageThreshold)。
304
330
  */
305
331
  | {
306
332
  urls: string[];
@@ -327,6 +353,8 @@ export declare type ChapterTreeInput = {
327
353
  startPage: number;
328
354
  endPage: number;
329
355
  source?: ChapterSource;
356
+ /** 章内分段阈值;URL 由 `chapterPdfLoader.loadChapterUrls` 拉取 */
357
+ segmentPageThreshold?: number;
330
358
  encrypted?: boolean;
331
359
  children?: ChapterTreeInput[];
332
360
  };
@@ -593,20 +621,32 @@ declare interface HoverBookmarkUiConfig_2 {
593
621
  }
594
622
 
595
623
  /**
596
- * 全局章节 PDF 加载器:在打开章节前由引擎调用,用于预处理/拉取 PDF。
624
+ * 章节 PDF 加载(推荐三步;`loadPdf` 仍兼容旧版单步写法)。
597
625
  *
598
- * 优先级(`ChapterManagerPlugin.resolvePdfPayload`):
599
- * 1. `chapter.source.url` / `source.buffer` 直接使用
600
- * 2. `chapter.source.load()` 按章异步,返回 `{ url }` `{ buffer }`
601
- * 3. `chapterPdfLoader.loadPdf(chapter)` 全局统一逻辑(鉴权、解密、转 blob URL 等)
626
+ * | 步骤 | 方法 | 说明 |
627
+ * | --- | --- | --- |
628
+ * | 1 | manifest 章节树 | `chapterId`、页码、`segmentPageThreshold` 等,**无 URL** |
629
+ * | 2 | `loadChapterUrls(chapter)` | 按章请求详情,返回 URL 列表(分段时多项) |
630
+ * | 3 | `openPdf(ctx)`(可选) | 对 `ctx.url` 解密/下载;省略则直接用 `ctx.url` 打开 |
602
631
  *
603
- * 适合:所有章节走同一套 API、在内存中解密后再以 buffer 打开、动态签名 URL 等。
632
+ * 仍可使用 `loadPdf(chapter, segmentIndex)` 单步实现(等价于 2+3 合并)。
604
633
  */
605
634
  export declare interface IChapterPdfLoader {
606
635
  /**
636
+ * 步骤 2:按章拉取 PDF 地址列表。
637
+ * 单 PDF 章节返回长度为 1 的数组;分段章节返回与 `ceil(页数/threshold)` 一致的多项。
638
+ */
639
+ loadChapterUrls?(chapter: ChapterDescriptor): Promise<string[]>;
640
+ /**
641
+ * 步骤 3(可选):将步骤 2 的 URL 转为可打开的 payload。
642
+ * 未实现时引擎使用 `{ url: ctx.url }`。
643
+ */
644
+ openPdf?(ctx: ChapterPdfLoadContext): Promise<ChapterPdfPayload>;
645
+ /**
646
+ * @deprecated 单步加载;新代码请用 `loadChapterUrls` + 可选 `openPdf`。
607
647
  * @param segmentIndex 章内分段索引;单 URL 章节为 0 或省略
608
648
  */
609
- loadPdf(chapter: ChapterDescriptor, segmentIndex?: number): Promise<ChapterPdfPayload>;
649
+ loadPdf?(chapter: ChapterDescriptor, segmentIndex?: number): Promise<ChapterPdfPayload>;
610
650
  }
611
651
 
612
652
  /**