@embedpdf-editor/chapter-snippet 1.0.0 → 1.0.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/README.md +61 -5
- package/dist/embedpdf-chapter.d.ts +55 -16
- package/dist/embedpdf-chapter.js +20421 -14454
- package/dist/embedpdf-chapter.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -43,7 +43,18 @@ import ChapterEmbedPDF from '@embedpdf-editor/chapter-snippet';
|
|
|
43
43
|
|
|
44
44
|
发包构建会对 `dist/embedpdf-chapter.js` 做语法降级(去掉 `??` 等 ES2020 语法),Webpack / Vue CLI 默认可 parse。默认 `wasmUrl` 指向 jsDelivr 上的 `pdfium.wasm`,无需复制到 `public/`。
|
|
45
45
|
|
|
46
|
-
离线或内网部署时,可传 `wasmUrl
|
|
46
|
+
离线或内网部署时,可传 `wasmUrl`(**init 顶层**,与 `options` 同级):
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
// 相对路径:自行把 dist/pdfium.wasm 放到静态目录
|
|
50
|
+
wasmUrl: '/pdfium.wasm',
|
|
51
|
+
|
|
52
|
+
// 自有 OSS / CDN(完整 HTTPS 地址,示例)
|
|
53
|
+
wasmUrl:
|
|
54
|
+
'https://hep-editor.oss-cn-beijing.aliyuncs.com/public/editor-public/js/pdfium.wasm',
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
详见 [docs/get-started/01-installation.md](../../docs/get-started/01-installation.md)。
|
|
47
58
|
|
|
48
59
|
`@embedpdf-editor/chapter-snippet/webpack` 为**可选**辅助(仅 monorepo Vue 2.6 解析、或自定义 devServer COOP/COEP),普通用户不必使用。
|
|
49
60
|
|
|
@@ -132,6 +143,25 @@ viewer?.addEventListener(CHAPTER_SNIPPET_EVENTS.ready, (event) => {
|
|
|
132
143
|
|
|
133
144
|
旧版本的 `editorInput` 仍可使用,但新代码应改为 `options`,并把 `features` 写在 `options.features` 或顶层 `features`。
|
|
134
145
|
|
|
146
|
+
### 章内多 PDF 分段(`source.urls[]`)
|
|
147
|
+
|
|
148
|
+
```js
|
|
149
|
+
source: {
|
|
150
|
+
urls: [part0Url, part1Url, part2Url],
|
|
151
|
+
segmentPageThreshold: 5, // 例:13 页 → 3 段
|
|
152
|
+
},
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
- 先加载第一段,滚动懒加载后续段;`localPageIndex` 仍为章内连续页。
|
|
156
|
+
- 引擎内部 `documentId` 为 `chapterId#s0`、`#s1`…;**业务 API / 数据库只存 `chapterId` + `localPageIndex`**。
|
|
157
|
+
- `chapterPdfLoader.loadPdf(chapter, segmentIndex)` 第二参数为段索引(0-based)。
|
|
158
|
+
|
|
159
|
+
[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
|
+
|
|
161
|
+
### 按章持久化
|
|
162
|
+
|
|
163
|
+
`options.notes` / `options.bookmarks` 回调里的 `chapterId`、`localPageIndex` 与单 URL 章相同。划线备份用 `exportChapterAnnotations`,JSON 键为 `chapters[chapterId]`(导出 markup 时会拉全部分段)。
|
|
164
|
+
|
|
135
165
|
### `ChapterViewerOptions`(与 React / Vue3 一致)
|
|
136
166
|
|
|
137
167
|
| 字段 | 说明 |
|
|
@@ -155,7 +185,7 @@ viewer?.addEventListener(CHAPTER_SNIPPET_EVENTS.ready, (event) => {
|
|
|
155
185
|
| `notes` | `marker.renderIcon`、`renderMenuActions`、`highlightColor` |
|
|
156
186
|
| `zoom` | `pageWidth`、`min` / `max` / `enabled`;实际上限不超过 `[data-chapter-scroll-viewport]` 宽度,resize 时自动 clamp |
|
|
157
187
|
| `scrollViewport` | `background`(默认 `#f1f5f9`),`[data-chapter-scroll-viewport]` 背景 |
|
|
158
|
-
| `selectionToolbar` | `hiddenBuiltinActions`、`extraActions`;扩展动作监听 `selectionExtraAction` 事件 |
|
|
188
|
+
| `selectionToolbar` | `hiddenBuiltinActions`(含 `copy`)、`renderCopyIcon`、`extraActions`;扩展动作监听 `selectionExtraAction` 事件 |
|
|
159
189
|
|
|
160
190
|
```js
|
|
161
191
|
features: {
|
|
@@ -182,12 +212,27 @@ features: {
|
|
|
182
212
|
},
|
|
183
213
|
},
|
|
184
214
|
selectionToolbar: {
|
|
215
|
+
// 复制默认开启,浮窗最左侧;隐藏:hiddenBuiltinActions: ['copy']
|
|
216
|
+
renderCopyIcon: () => {
|
|
217
|
+
const span = document.createElement('span');
|
|
218
|
+
span.textContent = '📋';
|
|
219
|
+
span.setAttribute('aria-hidden', 'true');
|
|
220
|
+
return span;
|
|
221
|
+
},
|
|
185
222
|
extraActions: [{ id: 'cite', label: '引用', order: 10 }],
|
|
186
223
|
},
|
|
187
224
|
},
|
|
188
225
|
```
|
|
189
226
|
|
|
190
|
-
|
|
227
|
+
划词后点**复制**会将选中文本写入剪贴板。程序化:
|
|
228
|
+
|
|
229
|
+
```js
|
|
230
|
+
import { copyTextToClipboard } from '@embedpdf-editor/chapter-snippet';
|
|
231
|
+
|
|
232
|
+
await copyTextToClipboard('文本');
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
`renderMenu` / `renderIcon` / `renderCopyIcon` 在 snippet(Preact)内执行,请返回 **DOM 或 Preact 节点**;Vue 2 宿主不要用 `h()` 直接塞进 Shadow DOM。
|
|
191
236
|
|
|
192
237
|
## 事件
|
|
193
238
|
|
|
@@ -247,11 +292,21 @@ import {
|
|
|
247
292
|
| 选项 | 说明 |
|
|
248
293
|
| --- | --- |
|
|
249
294
|
| `mode` | `replace` 清空后导入;`merge` 合并 |
|
|
250
|
-
| `ensureChapterLoaded` | 默认 true
|
|
295
|
+
| `ensureChapterLoaded` | 默认 true;含 markup 的分段章会加载 **全部段** 再合并页码 |
|
|
251
296
|
| `bookmarks` / `notes` / `markup` | 默认 true,可关闭某一类 |
|
|
252
297
|
| `persistNotes` / `persistBookmarks` | 导入后写回业务存储 |
|
|
253
298
|
|
|
254
|
-
示例见 `examples/chapter-viewer-demo-vue2/src/components/AnnotationsDemoBar.vue
|
|
299
|
+
示例见 `examples/chapter-viewer-demo-vue2/src/components/AnnotationsDemoBar.vue`。详见 [10-annotations-io.md](../../docs/get-started/10-annotations-io.md)。
|
|
300
|
+
|
|
301
|
+
## 教程索引
|
|
302
|
+
|
|
303
|
+
| 主题 | 文档 |
|
|
304
|
+
| --- | --- |
|
|
305
|
+
| 目录 | [docs/get-started/README.md](../../docs/get-started/README.md) |
|
|
306
|
+
| `wasmUrl`(含 OSS 示例) | [01-installation.md](../../docs/get-started/01-installation.md) |
|
|
307
|
+
| 划词复制 | [07-selection-toolbar.md](../../docs/get-started/07-selection-toolbar.md) |
|
|
308
|
+
| 事件常量 | [11-events-callbacks-and-component-api.md](../../docs/get-started/11-events-callbacks-and-component-api.md) |
|
|
309
|
+
| 分段 + 按章存储 | [12-segmented-pdf-and-per-chapter-storage.md](../../docs/get-started/12-segmented-pdf-and-per-chapter-storage.md) |
|
|
255
310
|
|
|
256
311
|
## 与 React / Vue3 渲染器的区别
|
|
257
312
|
|
|
@@ -277,3 +332,4 @@ import {
|
|
|
277
332
|
| 只显示空白 | 确认宿主元素有高度,且没有被父容器 `overflow`/flex 布局压到 0 |
|
|
278
333
|
| 划词后没有笔记弹窗 | 监听 `chapter-note-request-create`,保存后调用 `detail.complete(noteId)` |
|
|
279
334
|
| Vue/Vite 开发环境异常预构建 | 使用 `chapterSnippetViteResolve()`,确保 snippet 和 PDFium 引擎没有被 optimizeDeps 预构建 |
|
|
335
|
+
| 分段章存了 `#sN` | 业务层只用 `chapterId`;引擎段 ID 勿写入库 |
|
|
@@ -140,8 +140,16 @@ declare interface ChapterManagerCapability {
|
|
|
140
140
|
getVirtualPageMap(): VirtualPageMap;
|
|
141
141
|
/** ChapterScrollPlugin 在可见页位变化时调用,用以驱动按需加载 */
|
|
142
142
|
setVisibleGlobalPages(visiblePageIndices: number[]): void;
|
|
143
|
-
/**
|
|
143
|
+
/** 显式触发某章节加载(分段章节仅加载第 0 段) */
|
|
144
144
|
ensureChapterLoaded(chapterId: string): Promise<ChapterLoadStatus>;
|
|
145
|
+
/** 加载章内指定分段 PDF */
|
|
146
|
+
ensureSegmentLoaded(chapterId: string, segmentIndex: number): Promise<ChapterLoadStatus>;
|
|
147
|
+
/** 加载章内全部分段(导出划线等) */
|
|
148
|
+
ensureAllSegmentsLoaded(chapterId: string): Promise<ChapterLoadStatus>;
|
|
149
|
+
/** 将章内 localPageIndex 映射为 documentManager 的 documentId + 段内页码 */
|
|
150
|
+
resolvePageDocument(chapterId: string, localPageIndex: number): ChapterPageDocumentRef | null;
|
|
151
|
+
getSegmentPlan(chapterId: string): ChapterSegmentPlan | null;
|
|
152
|
+
isSegmentLoaded(chapterId: string, segmentIndex: number): boolean;
|
|
145
153
|
/** 状态查询 */
|
|
146
154
|
getChapterStatus(chapterId: string): ChapterLoadStatus;
|
|
147
155
|
getChapter(chapterId: string): ChapterDescriptor | null;
|
|
@@ -156,10 +164,8 @@ declare interface ChapterManagerCapability {
|
|
|
156
164
|
/**
|
|
157
165
|
* 章节生命周期管理:以章节为粒度懒加载/预取/卸载 PDF 文件,并屏蔽密码协议细节。
|
|
158
166
|
*
|
|
159
|
-
*
|
|
160
|
-
* -
|
|
161
|
-
* - 视觉上的「activeDocumentId」由本插件根据当前可见页位维护;上层无须感知。
|
|
162
|
-
* - 渲染层最终始终通过 `(chapterId, localPageIndex)` 索引到 owner 章节的 PDF 文档。
|
|
167
|
+
* - 单 URL:`documentId === chapterId`
|
|
168
|
+
* - 多段 URL:`documentId === chapterId#s{index}`,滚动时按段加载
|
|
163
169
|
*/
|
|
164
170
|
export declare class ChapterManagerPlugin extends BasePlugin<ChapterManagerPluginConfig, ChapterManagerCapability> {
|
|
165
171
|
static readonly id: "chapter-manager";
|
|
@@ -171,15 +177,11 @@ export declare class ChapterManagerPlugin extends BasePlugin<ChapterManagerPlugi
|
|
|
171
177
|
private manifest;
|
|
172
178
|
private overlapStrategy;
|
|
173
179
|
private virtualPageMap;
|
|
174
|
-
/** 每个章节当前状态(in-memory;不需要 redux 同步) */
|
|
175
180
|
private readonly chapterStatus;
|
|
176
|
-
/** 章节最近一次进入视口或被显式请求的时间戳,用于卸载判断 */
|
|
177
181
|
private readonly chapterLastUsed;
|
|
178
|
-
/** 章节密码累计尝试次数 */
|
|
179
182
|
private readonly passwordAttempts;
|
|
180
|
-
|
|
181
|
-
private readonly
|
|
182
|
-
/** unload tick 句柄 */
|
|
183
|
+
private readonly pendingChapterLoadPromises;
|
|
184
|
+
private readonly pendingSegmentLoadPromises;
|
|
183
185
|
private unloadTimer;
|
|
184
186
|
private documentManagerUnsubs;
|
|
185
187
|
constructor(id: string, registry: PluginRegistry);
|
|
@@ -187,16 +189,19 @@ export declare class ChapterManagerPlugin extends BasePlugin<ChapterManagerPlugi
|
|
|
187
189
|
protected buildCapability(): ChapterManagerCapability;
|
|
188
190
|
destroy(): void;
|
|
189
191
|
private setManifestInternal;
|
|
190
|
-
/** manifest 就绪后预取前 N 章(不依赖滚动视口是否已算出可见页) */
|
|
191
192
|
private eagerPrefetchFromManifest;
|
|
192
193
|
private findChapter;
|
|
193
|
-
private
|
|
194
|
+
private getSegmentPlanForChapter;
|
|
195
|
+
private isSegmentDocumentOpen;
|
|
196
|
+
private syncChapterStatusFromDocuments;
|
|
194
197
|
private handleVisibleChange;
|
|
195
198
|
private collectIdleChapters;
|
|
196
199
|
ensureChapterLoaded(chapterId: string): Promise<ChapterLoadStatus>;
|
|
200
|
+
ensureAllSegmentsLoaded(chapterId: string): Promise<ChapterLoadStatus>;
|
|
201
|
+
ensureSegmentLoaded(chapterId: string, segmentIndex: number): Promise<ChapterLoadStatus>;
|
|
202
|
+
private ensureSingleDocumentChapter;
|
|
197
203
|
private resolvePdfPayload;
|
|
198
|
-
private
|
|
199
|
-
/** 阻塞等待该章节状态进入 loaded / error / password-required / closed */
|
|
204
|
+
private startLoadSegment;
|
|
200
205
|
private waitForTerminalStatus;
|
|
201
206
|
private handleDocumentError;
|
|
202
207
|
private closeChapter;
|
|
@@ -238,6 +243,11 @@ export declare type ChapterNoteRequestEditDetail = {
|
|
|
238
243
|
anchor: NoteAnchor;
|
|
239
244
|
};
|
|
240
245
|
|
|
246
|
+
declare interface ChapterPageDocumentRef {
|
|
247
|
+
documentId: string;
|
|
248
|
+
pageIndex: number;
|
|
249
|
+
}
|
|
250
|
+
|
|
241
251
|
/**
|
|
242
252
|
* Backend-supplied chapter contract.
|
|
243
253
|
*
|
|
@@ -253,6 +263,21 @@ export declare type ChapterPdfPayload = {
|
|
|
253
263
|
buffer: ArrayBuffer;
|
|
254
264
|
};
|
|
255
265
|
|
|
266
|
+
declare interface ChapterSegmentInfo {
|
|
267
|
+
index: number;
|
|
268
|
+
url: string;
|
|
269
|
+
localPageStart: number;
|
|
270
|
+
localPageEnd: number;
|
|
271
|
+
documentId: string;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
declare interface ChapterSegmentPlan {
|
|
275
|
+
chapterId: string;
|
|
276
|
+
threshold: number;
|
|
277
|
+
pageCount: number;
|
|
278
|
+
segments: ChapterSegmentInfo[];
|
|
279
|
+
}
|
|
280
|
+
|
|
256
281
|
/** 划词工具栏扩展操作事件 */
|
|
257
282
|
export declare type ChapterSelectionActionDetail = {
|
|
258
283
|
actionId: string;
|
|
@@ -272,6 +297,14 @@ export declare type ChapterSource = {
|
|
|
272
297
|
/** 按章预处理:拉取、解密、转换后返回 url 或 buffer */
|
|
273
298
|
| {
|
|
274
299
|
load: () => Promise<ChapterPdfPayload>;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* 章内多 PDF 分段(后端已按段拆分)。
|
|
303
|
+
* `urls.length` 须为 ceil(章页数 / segmentPageThreshold)。
|
|
304
|
+
*/
|
|
305
|
+
| {
|
|
306
|
+
urls: string[];
|
|
307
|
+
segmentPageThreshold: number;
|
|
275
308
|
};
|
|
276
309
|
|
|
277
310
|
declare interface ChapterStatusEvent {
|
|
@@ -429,6 +462,9 @@ export declare type ContainerInitConfig = ChapterViewerContainerConfig & {
|
|
|
429
462
|
target: Element;
|
|
430
463
|
};
|
|
431
464
|
|
|
465
|
+
/** 将划选文本写入系统剪贴板(Clipboard API,失败时回退 execCommand) */
|
|
466
|
+
export declare function copyTextToClipboard(text: string): Promise<boolean>;
|
|
467
|
+
|
|
432
468
|
/** 生成插件列表 + 规范化后的 features(供 EmbedPDF / PdfChapterViewport 使用) */
|
|
433
469
|
export declare function createChapterViewerBundle(input: ChapterViewerOptions | CreateChapterViewerEditorOptionsInput): {
|
|
434
470
|
plugins: PluginBatchRegistration<any, any, any, any>[];
|
|
@@ -567,7 +603,10 @@ declare interface HoverBookmarkUiConfig_2 {
|
|
|
567
603
|
* 适合:所有章节走同一套 API、在内存中解密后再以 buffer 打开、动态签名 URL 等。
|
|
568
604
|
*/
|
|
569
605
|
export declare interface IChapterPdfLoader {
|
|
570
|
-
|
|
606
|
+
/**
|
|
607
|
+
* @param segmentIndex 章内分段索引;单 URL 章节为 0 或省略
|
|
608
|
+
*/
|
|
609
|
+
loadPdf(chapter: ChapterDescriptor, segmentIndex?: number): Promise<ChapterPdfPayload>;
|
|
571
610
|
}
|
|
572
611
|
|
|
573
612
|
/**
|