@open-file-viewer/core 0.1.22 → 0.1.23

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.cts CHANGED
@@ -96,6 +96,7 @@ interface PreviewOptions {
96
96
  onUnsupported?: (file: PreviewFile) => void;
97
97
  }
98
98
  interface PreviewMessages {
99
+ [key: string]: string | undefined;
99
100
  loading: string;
100
101
  unsupportedTitle: string;
101
102
  downloadTitle: string;
@@ -143,6 +144,35 @@ interface PreviewMessages {
143
144
  officeUnsupportedSupportedFormats: string;
144
145
  officeErrorWithMessage: string;
145
146
  officeErrorWithoutMessage: string;
147
+ officeConvertedTitle: string;
148
+ officeConvertedPdfFailed: string;
149
+ pdfEncryptedTitle: string;
150
+ pdfEncryptedMessage: string;
151
+ pdfPreviewFailedTitle: string;
152
+ pdfCorruptedMessage: string;
153
+ pdfCannotLoadMessage: string;
154
+ pdfDownload: string;
155
+ pdfPageLoading: string;
156
+ pdfPageEmpty: string;
157
+ pdfPageRenderFailed: string;
158
+ pdfPreviousPage: string;
159
+ pdfNextPage: string;
160
+ pdfPageInput: string;
161
+ pdfPagePosition: string;
162
+ pdfPageLabel: string;
163
+ pdfSummaryPages: string;
164
+ pdfSummaryPageSizes: string;
165
+ pdfSummaryFit: string;
166
+ pdfSummaryActualSize: string;
167
+ pdfSummaryFitWidth: string;
168
+ pdfSummaryZoom: string;
169
+ imagePreviewFailedTitle: string;
170
+ imagePreviewFailedMessage: string;
171
+ imageDownload: string;
172
+ imageZoomOut: string;
173
+ imageZoomIn: string;
174
+ imageRotate: string;
175
+ imageReset: string;
146
176
  }
147
177
  interface PreviewContext {
148
178
  host: HTMLElement;
@@ -192,6 +222,7 @@ type PdfJsModule = typeof pdfjs_dist;
192
222
  interface PdfPluginOptions {
193
223
  pdfjs?: PdfJsModule;
194
224
  workerSrc?: string;
225
+ compatibilityMode?: "auto" | "modern" | "legacy";
195
226
  cMapUrl?: string;
196
227
  cMapPacked?: boolean;
197
228
  standardFontDataUrl?: string;
package/dist/index.d.ts CHANGED
@@ -96,6 +96,7 @@ interface PreviewOptions {
96
96
  onUnsupported?: (file: PreviewFile) => void;
97
97
  }
98
98
  interface PreviewMessages {
99
+ [key: string]: string | undefined;
99
100
  loading: string;
100
101
  unsupportedTitle: string;
101
102
  downloadTitle: string;
@@ -143,6 +144,35 @@ interface PreviewMessages {
143
144
  officeUnsupportedSupportedFormats: string;
144
145
  officeErrorWithMessage: string;
145
146
  officeErrorWithoutMessage: string;
147
+ officeConvertedTitle: string;
148
+ officeConvertedPdfFailed: string;
149
+ pdfEncryptedTitle: string;
150
+ pdfEncryptedMessage: string;
151
+ pdfPreviewFailedTitle: string;
152
+ pdfCorruptedMessage: string;
153
+ pdfCannotLoadMessage: string;
154
+ pdfDownload: string;
155
+ pdfPageLoading: string;
156
+ pdfPageEmpty: string;
157
+ pdfPageRenderFailed: string;
158
+ pdfPreviousPage: string;
159
+ pdfNextPage: string;
160
+ pdfPageInput: string;
161
+ pdfPagePosition: string;
162
+ pdfPageLabel: string;
163
+ pdfSummaryPages: string;
164
+ pdfSummaryPageSizes: string;
165
+ pdfSummaryFit: string;
166
+ pdfSummaryActualSize: string;
167
+ pdfSummaryFitWidth: string;
168
+ pdfSummaryZoom: string;
169
+ imagePreviewFailedTitle: string;
170
+ imagePreviewFailedMessage: string;
171
+ imageDownload: string;
172
+ imageZoomOut: string;
173
+ imageZoomIn: string;
174
+ imageRotate: string;
175
+ imageReset: string;
146
176
  }
147
177
  interface PreviewContext {
148
178
  host: HTMLElement;
@@ -192,6 +222,7 @@ type PdfJsModule = typeof pdfjs_dist;
192
222
  interface PdfPluginOptions {
193
223
  pdfjs?: PdfJsModule;
194
224
  workerSrc?: string;
225
+ compatibilityMode?: "auto" | "modern" | "legacy";
195
226
  cMapUrl?: string;
196
227
  cMapPacked?: boolean;
197
228
  standardFontDataUrl?: string;
package/dist/index.js CHANGED
@@ -602,7 +602,36 @@ var defaultMessages = {
602
602
  officeUnsupportedIntro: "\u5DF2\u8FDB\u5165 Office \u63D2\u4EF6\u3002{message}",
603
603
  officeUnsupportedSupportedFormats: "\u5F53\u524D\u7248\u672C\u4F18\u5148\u652F\u6301 docx\u3001rtf\u3001odt/fodt\u3001xlsx/xls/csv/ods\u3001pptx/ppsx\u3001odp/fodp \u7684\u57FA\u7840\u5185\u5BB9\u9884\u89C8\u3002",
604
604
  officeErrorWithMessage: "\u89E3\u6790\u5668\u8FD4\u56DE\uFF1A{message}",
605
- officeErrorWithoutMessage: "\u89E3\u6790\u5668\u672A\u8FD4\u56DE\u5177\u4F53\u9519\u8BEF\u4FE1\u606F\u3002"
605
+ officeErrorWithoutMessage: "\u89E3\u6790\u5668\u672A\u8FD4\u56DE\u5177\u4F53\u9519\u8BEF\u4FE1\u606F\u3002",
606
+ officeConvertedTitle: "Office \u9AD8\u4FDD\u771F\u8F6C\u6362\u9884\u89C8",
607
+ officeConvertedPdfFailed: "Office \u8F6C\u6362\u540E\u7684 PDF \u65E0\u6CD5\u9884\u89C8",
608
+ pdfEncryptedTitle: "PDF \u5DF2\u52A0\u5BC6\uFF0C\u65E0\u6CD5\u5728\u7EBF\u9884\u89C8",
609
+ pdfEncryptedMessage: "\u8BF7\u4E0B\u8F7D\u540E\u4F7F\u7528\u5BC6\u7801\u6253\u5F00\uFF0C\u6216\u4E0A\u4F20\u89E3\u5BC6\u540E\u7684 PDF \u6587\u4EF6\u3002",
610
+ pdfPreviewFailedTitle: "PDF \u9884\u89C8\u5931\u8D25",
611
+ pdfCorruptedMessage: "\u8BE5 PDF \u6587\u4EF6\u53EF\u80FD\u5DF2\u635F\u574F\u6216\u683C\u5F0F\u65E0\u6548\u3002",
612
+ pdfCannotLoadMessage: "\u5F53\u524D\u6D4F\u89C8\u5668\u65E0\u6CD5\u52A0\u8F7D\u8BE5 PDF\u3002",
613
+ pdfDownload: "\u4E0B\u8F7D PDF",
614
+ pdfPageLoading: "\u9875\u9762 {page} \u52A0\u8F7D\u4E2D...",
615
+ pdfPageEmpty: "\u8BE5\u9875\u6CA1\u6709\u68C0\u6D4B\u5230\u53EF\u663E\u793A\u7684 PDF \u517C\u5BB9\u5185\u5BB9\u3002\u82E5\u8FD9\u662F Illustrator/AI \u6587\u4EF6\uFF0C\u53EF\u80FD\u53EA\u5305\u542B\u79C1\u6709\u7F16\u8F91\u6570\u636E\uFF0C\u5EFA\u8BAE\u5BFC\u51FA\u4E3A PDF/SVG/PNG \u540E\u9884\u89C8\u3002",
616
+ pdfPageRenderFailed: "\u65E0\u6CD5\u6E32\u67D3\u8BE5\u9875\u9762\u3002\u8BE5\u9875\u53EF\u80FD\u5305\u542B\u6D4F\u89C8\u5668 PDF \u5F15\u64CE\u6682\u4E0D\u652F\u6301\u7684\u56FE\u5F62\u3001\u5B57\u4F53\u6216\u538B\u7F29\u7279\u6027\u3002",
617
+ pdfPreviousPage: "\u4E0A\u4E00\u9875",
618
+ pdfNextPage: "\u4E0B\u4E00\u9875",
619
+ pdfPageInput: "\u5F53\u524D\u9875\u7801",
620
+ pdfPagePosition: "/ {total}",
621
+ pdfPageLabel: "\u7B2C {page} \u9875",
622
+ pdfSummaryPages: "\u9875\u6570",
623
+ pdfSummaryPageSizes: "\u9875\u9762\u5C3A\u5BF8",
624
+ pdfSummaryFit: "\u9002\u914D",
625
+ pdfSummaryActualSize: "\u539F\u59CB\u5927\u5C0F",
626
+ pdfSummaryFitWidth: "\u9002\u5408\u5BBD\u5EA6",
627
+ pdfSummaryZoom: "\u7F29\u653E",
628
+ imagePreviewFailedTitle: "\u56FE\u7247\u9884\u89C8\u5931\u8D25",
629
+ imagePreviewFailedMessage: "\u5F53\u524D\u6D4F\u89C8\u5668\u65E0\u6CD5\u76F4\u63A5\u663E\u793A\u8BE5\u56FE\u7247\uFF0C\u6587\u4EF6\u53EF\u80FD\u5DF2\u635F\u574F\u6216\u7F16\u7801\u6682\u4E0D\u53D7\u652F\u6301\u3002",
630
+ imageDownload: "\u4E0B\u8F7D\u56FE\u7247",
631
+ imageZoomOut: "\u7F29\u5C0F",
632
+ imageZoomIn: "\u653E\u5927",
633
+ imageRotate: "\u65CB\u8F6C\u56FE\u7247",
634
+ imageReset: "\u91CD\u7F6E\u56FE\u7247\u89C6\u56FE"
606
635
  },
607
636
  "en-US": {
608
637
  loading: "Loading preview...",
@@ -651,7 +680,36 @@ var defaultMessages = {
651
680
  officeUnsupportedIntro: "is handled by the Office plugin. {message}",
652
681
  officeUnsupportedSupportedFormats: "This version prioritizes basic previews for docx, rtf, odt/fodt, xlsx/xls/csv/ods, pptx/ppsx, and odp/fodp files.",
653
682
  officeErrorWithMessage: "Parser returned: {message}",
654
- officeErrorWithoutMessage: "Parser did not return a specific error."
683
+ officeErrorWithoutMessage: "Parser did not return a specific error.",
684
+ officeConvertedTitle: "High-fidelity Office conversion preview",
685
+ officeConvertedPdfFailed: "The converted Office PDF could not be previewed",
686
+ pdfEncryptedTitle: "This PDF is encrypted and cannot be previewed online",
687
+ pdfEncryptedMessage: "Download and open it with the password, or upload a decrypted PDF file.",
688
+ pdfPreviewFailedTitle: "PDF preview failed",
689
+ pdfCorruptedMessage: "The PDF may be corrupted or use an invalid format.",
690
+ pdfCannotLoadMessage: "This browser could not load the PDF.",
691
+ pdfDownload: "Download PDF",
692
+ pdfPageLoading: "Loading page {page}...",
693
+ pdfPageEmpty: "No displayable PDF-compatible content was detected on this page. If this is an Illustrator/AI file, export it as PDF, SVG, or PNG before previewing.",
694
+ pdfPageRenderFailed: "This page could not be rendered. It may contain graphics, fonts, or compression features that the browser PDF engine does not support.",
695
+ pdfPreviousPage: "Previous page",
696
+ pdfNextPage: "Next page",
697
+ pdfPageInput: "Current page",
698
+ pdfPagePosition: "/ {total}",
699
+ pdfPageLabel: "Page {page}",
700
+ pdfSummaryPages: "Pages",
701
+ pdfSummaryPageSizes: "Page sizes",
702
+ pdfSummaryFit: "Fit",
703
+ pdfSummaryActualSize: "Actual size",
704
+ pdfSummaryFitWidth: "Fit width",
705
+ pdfSummaryZoom: "Zoom",
706
+ imagePreviewFailedTitle: "Image preview failed",
707
+ imagePreviewFailedMessage: "This browser cannot display the image. The file may be corrupted or use an unsupported encoding.",
708
+ imageDownload: "Download image",
709
+ imageZoomOut: "Zoom out",
710
+ imageZoomIn: "Zoom in",
711
+ imageRotate: "Rotate image",
712
+ imageReset: "Reset image view"
655
713
  }
656
714
  };
657
715
  function resolveMessages(options) {
@@ -2162,7 +2220,7 @@ function imagePlugin() {
2162
2220
  infoBar.hidden = false;
2163
2221
  infoBar.removeAttribute("aria-hidden");
2164
2222
  infoBar.style.removeProperty("display");
2165
- stage.replaceChildren(createImageFallback(ctx.file.name, url));
2223
+ stage.replaceChildren(createImageFallback(ctx.file.name, url, ctx.options.messages));
2166
2224
  ctx.toolbar?.refreshCommandSupport();
2167
2225
  };
2168
2226
  const setScale = (nextScale) => {
@@ -2187,13 +2245,13 @@ function imagePlugin() {
2187
2245
  return () => button.removeEventListener("click", action);
2188
2246
  };
2189
2247
  const disposers = showInlineControls ? [
2190
- addButton("-", "Zoom out", () => setScale(scale - 0.25)),
2191
- addButton("+", "Zoom in", () => setScale(scale + 0.25)),
2192
- addButton("Rotate", "Rotate image", () => {
2248
+ addButton("-", ctx.options.messages.imageZoomOut, () => setScale(scale - 0.25)),
2249
+ addButton("+", ctx.options.messages.imageZoomIn, () => setScale(scale + 0.25)),
2250
+ addButton(ctx.options.messages.imageRotate, ctx.options.messages.imageRotate, () => {
2193
2251
  rotation += 90;
2194
2252
  updateTransform();
2195
2253
  }),
2196
- addButton("Reset", "Reset image view", reset)
2254
+ addButton(ctx.options.messages.imageReset, ctx.options.messages.imageReset, reset)
2197
2255
  ] : [];
2198
2256
  if (showInlineControls) {
2199
2257
  controls.append(zoomLabel);
@@ -2408,17 +2466,17 @@ function getTiffDimensions(ifd) {
2408
2466
  height: Number(ifd.height || ifd.t257 || 0)
2409
2467
  };
2410
2468
  }
2411
- function createImageFallback(fileName, url) {
2469
+ function createImageFallback(fileName, url, messages) {
2412
2470
  const fallback = document.createElement("div");
2413
2471
  fallback.className = "ofv-fallback";
2414
2472
  const title = document.createElement("strong");
2415
- title.textContent = "\u56FE\u7247\u9884\u89C8\u5931\u8D25";
2473
+ title.textContent = messages.imagePreviewFailedTitle;
2416
2474
  const meta = document.createElement("span");
2417
- meta.textContent = "\u5F53\u524D\u6D4F\u89C8\u5668\u65E0\u6CD5\u76F4\u63A5\u663E\u793A\u8BE5\u56FE\u7247\uFF0C\u6587\u4EF6\u53EF\u80FD\u5DF2\u635F\u574F\u6216\u7F16\u7801\u6682\u4E0D\u53D7\u652F\u6301\u3002";
2475
+ meta.textContent = messages.imagePreviewFailedMessage;
2418
2476
  const download = document.createElement("a");
2419
2477
  download.href = url;
2420
2478
  download.download = fileName;
2421
- download.textContent = "\u4E0B\u8F7D\u56FE\u7247";
2479
+ download.textContent = messages.imageDownload;
2422
2480
  fallback.append(title, meta, download);
2423
2481
  return fallback;
2424
2482
  }
@@ -4779,17 +4837,20 @@ function pdfPlugin(options = {}) {
4779
4837
  fit: ctx.options.fit,
4780
4838
  zoom: ctx.options.zoom,
4781
4839
  toolbar: ctx.toolbar,
4782
- encryptedTitle: "PDF \u5DF2\u52A0\u5BC6\uFF0C\u65E0\u6CD5\u5728\u7EBF\u9884\u89C8",
4783
- encryptedMessage: "\u8BF7\u4E0B\u8F7D\u540E\u4F7F\u7528\u5BC6\u7801\u6253\u5F00\uFF0C\u6216\u4E0A\u4F20\u89E3\u5BC6\u540E\u7684 PDF \u6587\u4EF6\u3002",
4784
- encryptedAction: "\u4E0B\u8F7D PDF",
4840
+ messages: ctx.options.messages,
4785
4841
  revokeUrlOnDestroy: true
4786
4842
  });
4787
4843
  }
4788
4844
  };
4789
4845
  }
4790
4846
  async function renderPdfDocumentPreview(options) {
4847
+ const useLegacyCompatibility = shouldUseLegacyPdfCompatibility(options.compatibilityMode);
4848
+ if (useLegacyCompatibility) {
4849
+ installPromiseWithResolversPolyfill();
4850
+ }
4791
4851
  const pdf = options.pdfjs || await import("pdfjs-dist");
4792
- configurePdfWorker(pdf, options.workerSrc);
4852
+ const messages = { ...defaultMessages["en-US"], ...options.messages };
4853
+ configurePdfWorker(pdf, options.workerSrc, useLegacyCompatibility);
4793
4854
  const viewer = document.createElement("div");
4794
4855
  viewer.className = "ofv-pdf-viewer";
4795
4856
  if (options.title) {
@@ -4818,10 +4879,10 @@ async function renderPdfDocumentPreview(options) {
4818
4879
  url: options.fileUrl
4819
4880
  };
4820
4881
  const fallback = isEncryptedError(error) ? createEncryptedFallback(fileLike, options.fileUrl, {
4821
- title: options.encryptedTitle || "PDF \u5DF2\u52A0\u5BC6\uFF0C\u65E0\u6CD5\u5728\u7EBF\u9884\u89C8",
4822
- message: options.encryptedMessage || "\u8BF7\u4E0B\u8F7D\u540E\u4F7F\u7528\u5BC6\u7801\u6253\u5F00\uFF0C\u6216\u4E0A\u4F20\u89E3\u5BC6\u540E\u7684 PDF \u6587\u4EF6\u3002",
4823
- action: options.encryptedAction || "\u4E0B\u8F7D PDF"
4824
- }) : createPdfFallback(options.fileName, options.fileUrl, normalizePdfError(error), options.fallbackTitle);
4882
+ title: options.encryptedTitle || messages.pdfEncryptedTitle,
4883
+ message: options.encryptedMessage || messages.pdfEncryptedMessage,
4884
+ action: options.encryptedAction || messages.pdfDownload
4885
+ }) : createPdfFallback(options.fileName, options.fileUrl, normalizePdfError(error, messages), messages, options.fallbackTitle);
4825
4886
  if (!fallback.classList.contains("ofv-pdf-web-fallback")) {
4826
4887
  options.viewport.classList.add("ofv-center");
4827
4888
  }
@@ -4888,8 +4949,43 @@ async function renderPdfDocumentPreview(options) {
4888
4949
  let currentSize = options.size;
4889
4950
  let zoomFactor = getInitialZoom({ options: { zoom: options.zoom ?? 1 } }, 0.25, 4);
4890
4951
  let rotation = 0;
4952
+ let currentPage = 1;
4953
+ const goToPage = (page, scroll = true) => {
4954
+ currentPage = Math.min(pdfDocument.numPages, Math.max(1, Math.round(page) || 1));
4955
+ pageNavigator.setCurrent(currentPage);
4956
+ const wrapper = pageStates[currentPage - 1]?.wrapper;
4957
+ if (!scroll || !wrapper) {
4958
+ return;
4959
+ }
4960
+ const top = Math.max(0, wrapper.offsetTop - 16);
4961
+ if (typeof scroller.scrollTo === "function") {
4962
+ scroller.scrollTo({ top, behavior: "smooth" });
4963
+ } else {
4964
+ scroller.scrollTop = top;
4965
+ }
4966
+ };
4967
+ const pageNavigator = createPdfPageNavigator(pdfDocument.numPages, messages, (page) => goToPage(page));
4968
+ viewer.insertBefore(pageNavigator.element, summary);
4969
+ const handleScrollerScroll = () => {
4970
+ const scrollerRect = scroller.getBoundingClientRect();
4971
+ const targetY = scrollerRect.top + Math.min(Math.max(scroller.clientHeight * 0.25, 40), 180);
4972
+ let nearestPage = currentPage;
4973
+ let nearestDistance = Number.POSITIVE_INFINITY;
4974
+ pageStates.forEach((state, index) => {
4975
+ const distance = Math.abs(state.wrapper.getBoundingClientRect().top - targetY);
4976
+ if (distance < nearestDistance) {
4977
+ nearestDistance = distance;
4978
+ nearestPage = index + 1;
4979
+ }
4980
+ });
4981
+ if (nearestPage !== currentPage) {
4982
+ currentPage = nearestPage;
4983
+ pageNavigator.setCurrent(currentPage);
4984
+ }
4985
+ };
4986
+ scroller.addEventListener("scroll", handleScrollerScroll, { passive: true });
4891
4987
  const updateSummary = () => {
4892
- renderPdfSummary(summary, pdfDocument.numPages, pagesMeta, options.fit, zoomFactor);
4988
+ renderPdfSummary(summary, pdfDocument.numPages, pagesMeta, options.fit, zoomFactor, messages);
4893
4989
  options.toolbar?.setZoom(zoomFactor);
4894
4990
  };
4895
4991
  const clearPage = (pageIdx) => {
@@ -4905,7 +5001,9 @@ async function renderPdfDocumentPreview(options) {
4905
5001
  state.canvas = null;
4906
5002
  state.rendered = false;
4907
5003
  state.wrapper.replaceChildren();
4908
- state.wrapper.append(createPageStatus("ofv-pdf-skeleton", `\u9875\u9762 ${pageIdx + 1} \u52A0\u8F7D\u4E2D...`));
5004
+ state.wrapper.append(
5005
+ createPageStatus("ofv-pdf-skeleton", formatPreviewMessage(messages.pdfPageLoading, { page: pageIdx + 1 }))
5006
+ );
4909
5007
  };
4910
5008
  const renderPage = async (pageIdx, size) => {
4911
5009
  const state = pageStates[pageIdx];
@@ -4973,7 +5071,7 @@ async function renderPdfDocumentPreview(options) {
4973
5071
  state.wrapper.appendChild(
4974
5072
  createPageStatus(
4975
5073
  "ofv-pdf-empty",
4976
- "\u8BE5\u9875\u6CA1\u6709\u68C0\u6D4B\u5230\u53EF\u663E\u793A\u7684 PDF \u517C\u5BB9\u5185\u5BB9\u3002\u82E5\u8FD9\u662F Illustrator/AI \u6587\u4EF6\uFF0C\u53EF\u80FD\u53EA\u5305\u542B\u79C1\u6709\u7F16\u8F91\u6570\u636E\uFF0C\u5EFA\u8BAE\u5BFC\u51FA\u4E3A PDF/SVG/PNG \u540E\u9884\u89C8\u3002"
5074
+ messages.pdfPageEmpty
4977
5075
  )
4978
5076
  );
4979
5077
  }
@@ -4981,7 +5079,7 @@ async function renderPdfDocumentPreview(options) {
4981
5079
  console.error(`Failed to render PDF page ${pageIdx + 1}:`, err);
4982
5080
  state.rendered = false;
4983
5081
  state.wrapper.replaceChildren(
4984
- createPageStatus("ofv-pdf-error", "\u65E0\u6CD5\u6E32\u67D3\u8BE5\u9875\u9762\u3002\u8BE5\u9875\u53EF\u80FD\u5305\u542B\u6D4F\u89C8\u5668 PDF \u5F15\u64CE\u6682\u4E0D\u652F\u6301\u7684\u56FE\u5F62\u3001\u5B57\u4F53\u6216\u538B\u7F29\u7279\u6027\u3002")
5082
+ createPageStatus("ofv-pdf-error", messages.pdfPageRenderFailed)
4985
5083
  );
4986
5084
  }
4987
5085
  };
@@ -5022,9 +5120,10 @@ async function renderPdfDocumentPreview(options) {
5022
5120
  const wrapper = document.createElement("div");
5023
5121
  wrapper.className = "ofv-pdf-page-wrapper";
5024
5122
  wrapper.setAttribute("data-page-index", String(i));
5123
+ wrapper.setAttribute("aria-label", formatPreviewMessage(messages.pdfPageLabel, { page: i + 1 }));
5025
5124
  wrapper.style.width = `${w}px`;
5026
5125
  wrapper.style.height = `${h}px`;
5027
- wrapper.append(createPageStatus("ofv-pdf-skeleton", `\u9875\u9762 ${i + 1} \u52A0\u8F7D\u4E2D...`));
5126
+ wrapper.append(createPageStatus("ofv-pdf-skeleton", formatPreviewMessage(messages.pdfPageLoading, { page: i + 1 })));
5028
5127
  scroller.appendChild(wrapper);
5029
5128
  pageStates.push({
5030
5129
  wrapper,
@@ -5046,6 +5145,7 @@ async function renderPdfDocumentPreview(options) {
5046
5145
  }
5047
5146
  }, 0);
5048
5147
  }
5148
+ goToPage(currentPage, false);
5049
5149
  };
5050
5150
  renderLayout(options.size);
5051
5151
  let resizeTimer;
@@ -5086,6 +5186,8 @@ async function renderPdfDocumentPreview(options) {
5086
5186
  },
5087
5187
  destroy() {
5088
5188
  options.toolbar?.setZoom(void 0);
5189
+ pageNavigator.destroy();
5190
+ scroller.removeEventListener("scroll", handleScrollerScroll);
5089
5191
  window.clearTimeout(resizeTimer);
5090
5192
  observer?.disconnect();
5091
5193
  pageStates.forEach((state) => {
@@ -5131,15 +5233,15 @@ function getPdfAvailableWidth(width) {
5131
5233
  const gutter = width < 160 ? 16 : 32;
5132
5234
  return Math.max(1, width - gutter);
5133
5235
  }
5134
- function renderPdfSummary(summary, pages, pagesMeta, fit, zoomFactor) {
5236
+ function renderPdfSummary(summary, pages, pagesMeta, fit, zoomFactor, messages) {
5135
5237
  summary.replaceChildren();
5136
- appendPdfSummary(summary, "\u9875\u6570", String(pages));
5238
+ appendPdfSummary(summary, messages.pdfSummaryPages, String(pages));
5137
5239
  const pageSizes = formatPdfPageSizes(pagesMeta);
5138
5240
  if (pageSizes) {
5139
- appendPdfSummary(summary, "\u9875\u9762\u5C3A\u5BF8", pageSizes);
5241
+ appendPdfSummary(summary, messages.pdfSummaryPageSizes, pageSizes);
5140
5242
  }
5141
- appendPdfSummary(summary, "\u9002\u914D", fit === "actual" ? "\u539F\u59CB\u5927\u5C0F" : "\u9002\u5408\u5BBD\u5EA6");
5142
- appendPdfSummary(summary, "\u7F29\u653E", `${Math.round(zoomFactor * 100)}%`);
5243
+ appendPdfSummary(summary, messages.pdfSummaryFit, fit === "actual" ? messages.pdfSummaryActualSize : messages.pdfSummaryFitWidth);
5244
+ appendPdfSummary(summary, messages.pdfSummaryZoom, `${Math.round(zoomFactor * 100)}%`);
5143
5245
  }
5144
5246
  function appendPdfSummary(parent, label, value) {
5145
5247
  const item = document.createElement("span");
@@ -5229,7 +5331,7 @@ function createPageStatus(className, text) {
5229
5331
  status.textContent = text;
5230
5332
  return status;
5231
5333
  }
5232
- function createPdfFallback(fileName, url, message, titleText = "PDF \u9884\u89C8\u5931\u8D25") {
5334
+ function createPdfFallback(fileName, url, message, messages, titleText = messages.pdfPreviewFailedTitle) {
5233
5335
  if (isEmbeddableRemoteUrl(url)) {
5234
5336
  return createPdfWebFallback(fileName, url);
5235
5337
  }
@@ -5242,7 +5344,7 @@ function createPdfFallback(fileName, url, message, titleText = "PDF \u9884\u89C8
5242
5344
  const download = document.createElement("a");
5243
5345
  download.href = url;
5244
5346
  download.download = fileName;
5245
- download.textContent = "\u4E0B\u8F7D PDF";
5347
+ download.textContent = messages.pdfDownload;
5246
5348
  fallback.append(title, meta, download);
5247
5349
  return fallback;
5248
5350
  }
@@ -5261,23 +5363,109 @@ function createPdfWebFallback(fileName, url) {
5261
5363
  function isEmbeddableRemoteUrl(url) {
5262
5364
  return /^https?:\/\//i.test(url);
5263
5365
  }
5264
- function normalizePdfError(error) {
5366
+ function normalizePdfError(error, messages) {
5265
5367
  const message = error instanceof Error ? error.message : String(error || "");
5266
5368
  const name = typeof error === "object" && error !== null && "name" in error ? String(error.name) : "";
5267
5369
  const lower = `${name} ${message}`.toLowerCase();
5268
5370
  if (lower.includes("invalid") || lower.includes("missing") || lower.includes("corrupt")) {
5269
- return "\u8BE5 PDF \u6587\u4EF6\u53EF\u80FD\u5DF2\u635F\u574F\u6216\u683C\u5F0F\u65E0\u6548\u3002";
5371
+ return messages.pdfCorruptedMessage;
5270
5372
  }
5271
- return "\u5F53\u524D\u6D4F\u89C8\u5668\u65E0\u6CD5\u52A0\u8F7D\u8BE5 PDF\u3002";
5373
+ return messages.pdfCannotLoadMessage;
5374
+ }
5375
+ function createPdfPageNavigator(total, messages, onChange) {
5376
+ const element = document.createElement("div");
5377
+ element.className = "ofv-pdf-page-navigator";
5378
+ const previous = document.createElement("button");
5379
+ previous.type = "button";
5380
+ previous.textContent = "\u2039";
5381
+ previous.title = messages.pdfPreviousPage;
5382
+ previous.setAttribute("aria-label", messages.pdfPreviousPage);
5383
+ const input = document.createElement("input");
5384
+ input.type = "number";
5385
+ input.min = "1";
5386
+ input.max = String(total);
5387
+ input.value = "1";
5388
+ input.inputMode = "numeric";
5389
+ input.setAttribute("aria-label", messages.pdfPageInput);
5390
+ const position = document.createElement("span");
5391
+ position.textContent = formatPreviewMessage(messages.pdfPagePosition, { total });
5392
+ const next = document.createElement("button");
5393
+ next.type = "button";
5394
+ next.textContent = "\u203A";
5395
+ next.title = messages.pdfNextPage;
5396
+ next.setAttribute("aria-label", messages.pdfNextPage);
5397
+ const commit = () => onChange(Number(input.value));
5398
+ const handleKeydown = (event) => {
5399
+ if (event.key === "Enter") {
5400
+ commit();
5401
+ }
5402
+ };
5403
+ const handlePrevious = () => onChange(Number(input.value) - 1);
5404
+ const handleNext = () => onChange(Number(input.value) + 1);
5405
+ input.addEventListener("change", commit);
5406
+ input.addEventListener("keydown", handleKeydown);
5407
+ previous.addEventListener("click", handlePrevious);
5408
+ next.addEventListener("click", handleNext);
5409
+ element.append(previous, input, position, next);
5410
+ return {
5411
+ element,
5412
+ setCurrent(page) {
5413
+ input.value = String(page);
5414
+ previous.disabled = page <= 1;
5415
+ next.disabled = page >= total;
5416
+ },
5417
+ destroy() {
5418
+ input.removeEventListener("change", commit);
5419
+ input.removeEventListener("keydown", handleKeydown);
5420
+ previous.removeEventListener("click", handlePrevious);
5421
+ next.removeEventListener("click", handleNext);
5422
+ }
5423
+ };
5272
5424
  }
5273
- function configurePdfWorker(pdf, workerSrc) {
5425
+ function configurePdfWorker(pdf, workerSrc, legacy = false) {
5274
5426
  if (workerSrc) {
5275
5427
  pdf.GlobalWorkerOptions.workerSrc = workerSrc;
5276
5428
  return;
5277
5429
  }
5278
5430
  if (!pdf.GlobalWorkerOptions.workerSrc && typeof window !== "undefined") {
5279
- pdf.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdf.version}/build/pdf.worker.mjs`;
5431
+ const build = legacy ? "legacy/build" : "build";
5432
+ pdf.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdf.version}/${build}/pdf.worker.mjs`;
5433
+ }
5434
+ }
5435
+ function shouldUseLegacyPdfCompatibility(mode = "auto") {
5436
+ if (mode === "legacy") {
5437
+ return true;
5438
+ }
5439
+ if (mode === "modern") {
5440
+ return false;
5441
+ }
5442
+ const promise = Promise;
5443
+ if (typeof promise.withResolvers !== "function") {
5444
+ return true;
5445
+ }
5446
+ if (typeof navigator === "undefined") {
5447
+ return false;
5280
5448
  }
5449
+ return /(?:QIHU|360SE|360EE)/i.test(navigator.userAgent);
5450
+ }
5451
+ function installPromiseWithResolversPolyfill() {
5452
+ const promise = Promise;
5453
+ if (typeof promise.withResolvers === "function") {
5454
+ return;
5455
+ }
5456
+ Object.defineProperty(promise, "withResolvers", {
5457
+ configurable: true,
5458
+ writable: true,
5459
+ value: () => {
5460
+ let resolve;
5461
+ let reject;
5462
+ const pending = new Promise((resolvePromise, rejectPromise) => {
5463
+ resolve = resolvePromise;
5464
+ reject = rejectPromise;
5465
+ });
5466
+ return { promise: pending, resolve, reject };
5467
+ }
5468
+ });
5281
5469
  }
5282
5470
 
5283
5471
  // src/plugins/epub.ts
@@ -7672,8 +7860,9 @@ async function renderConvertedOfficePreview(panel, ctx, options, conversionConte
7672
7860
  fit: ctx.options.fit,
7673
7861
  zoom: ctx.options.zoom,
7674
7862
  toolbar: ctx.toolbar,
7675
- title: "Office \u9AD8\u4FDD\u771F\u8F6C\u6362\u9884\u89C8",
7676
- fallbackTitle: "Office \u8F6C\u6362\u540E\u7684 PDF \u65E0\u6CD5\u9884\u89C8",
7863
+ messages: ctx.options.messages,
7864
+ title: ctx.options.messages.officeConvertedTitle,
7865
+ fallbackTitle: ctx.options.messages.officeConvertedPdfFailed,
7677
7866
  revokeUrlOnDestroy: converted.revokeUrlOnDestroy
7678
7867
  });
7679
7868
  }