From 2403d5107d21010b336c2c7cc12266bd7b84529a Mon Sep 17 00:00:00 2001 From: Vanessa Date: Fri, 11 Oct 2024 01:07:32 +0800 Subject: [PATCH] :art: https://github.com/siyuan-note/siyuan/issues/11650 --- app/appearance/langs/de_DE.json | 1 - app/appearance/langs/en_US.json | 1 - app/appearance/langs/es_ES.json | 1 - app/appearance/langs/fr_FR.json | 1 - app/appearance/langs/he_IL.json | 3 +- app/appearance/langs/it_IT.json | 2 - app/appearance/langs/ja_JP.json | 1 - app/appearance/langs/pl_PL.json | 3 +- app/appearance/langs/ru_RU.json | 1 - app/appearance/langs/zh_CHT.json | 1 - app/appearance/langs/zh_CN.json | 1 - app/pnpm-lock.yaml | 18 +- app/src/asset/anno.ts | 28 +- app/src/asset/index.ts | 35 +- .../pdf/annotation_editor_layer_builder.js | 44 +- app/src/asset/pdf/annotation_editor_params.js | 84 +- app/src/asset/pdf/annotation_layer_builder.js | 89 +- app/src/asset/pdf/app.js | 6492 ++++++++--------- app/src/asset/pdf/app_options.js | 445 +- app/src/asset/pdf/base_tree_viewer.js | 25 +- app/src/asset/pdf/caret_browsing.js | 365 + app/src/asset/pdf/download_manager.js | 125 + app/src/asset/pdf/draw_layer_builder.js | 64 + app/src/asset/pdf/event_utils.js | 132 +- app/src/asset/pdf/external_services.js | 54 + app/src/asset/pdf/generic_scripting.js | 24 +- app/src/asset/pdf/genericcom.js | 147 +- app/src/asset/pdf/genericl10n.js | 56 + app/src/asset/pdf/grab_to_pan.js | 45 +- app/src/asset/pdf/l10n.js | 143 + app/src/asset/pdf/new_alt_text_manager.js | 696 ++ app/src/asset/pdf/overlay_manager.js | 35 +- app/src/asset/pdf/password_prompt.js | 20 +- app/src/asset/pdf/pdf_attachment_viewer.js | 43 +- app/src/asset/pdf/pdf_cursor_tools.js | 109 +- app/src/asset/pdf/pdf_document_properties.js | 126 +- app/src/asset/pdf/pdf_find_bar.js | 111 +- app/src/asset/pdf/pdf_find_controller.js | 317 +- app/src/asset/pdf/pdf_find_utils.js | 44 +- app/src/asset/pdf/pdf_history.js | 156 +- app/src/asset/pdf/pdf_layer_viewer.js | 63 +- app/src/asset/pdf/pdf_link_service.js | 539 +- app/src/asset/pdf/pdf_outline_viewer.js | 58 +- app/src/asset/pdf/pdf_page_view.js | 930 +-- app/src/asset/pdf/pdf_presentation_mode.js | 108 +- app/src/asset/pdf/pdf_print_service.js | 396 + app/src/asset/pdf/pdf_rendering_queue.js | 13 +- app/src/asset/pdf/pdf_scripting_manager.js | 446 +- app/src/asset/pdf/pdf_sidebar.js | 275 +- app/src/asset/pdf/pdf_thumbnail_view.js | 201 +- app/src/asset/pdf/pdf_thumbnail_viewer.js | 82 +- app/src/asset/pdf/pdf_viewer.js | 779 +- app/src/asset/pdf/pdfjs.js | 5 +- app/src/asset/pdf/preferences.js | 108 +- app/src/asset/pdf/print_utils.js | 43 + app/src/asset/pdf/secondary_toolbar.js | 225 +- .../asset/pdf/struct_tree_layer_builder.js | 127 +- app/src/asset/pdf/text_accessibility.js | 22 +- app/src/asset/pdf/text_highlighter.js | 42 +- app/src/asset/pdf/text_layer_builder.js | 341 +- app/src/asset/pdf/toolbar.js | 334 +- app/src/asset/pdf/ui_utils.js | 127 +- app/src/asset/pdf/view_history.js | 3 + app/src/asset/pdf/viewer.js | 146 +- app/src/asset/pdf/xfa_layer_builder.js | 11 +- app/src/assets/scss/pdf/_pdf.scss | 60 +- app/src/assets/template/app/index.tpl | 1 + app/src/assets/template/desktop/index.tpl | 1 + app/src/boot/globalEvent/click.ts | 4 +- app/stage/protyle/js/pdf/pdf.js | 22 - app/stage/protyle/js/pdf/pdf.min.mjs | 21 + app/stage/protyle/js/pdf/pdf.sandbox.min.mjs | 21 + app/stage/protyle/js/pdf/pdf.worker.js | 22 - app/stage/protyle/js/pdf/pdf.worker.min.mjs | 21 + .../js/pdf/standard_fonts/FoxitSans.pfb | Bin 15025 -> 0 bytes .../js/pdf/standard_fonts/FoxitSansBold.pfb | Bin 16344 -> 0 bytes .../standard_fonts/FoxitSansBoldItalic.pfb | Bin 16418 -> 0 bytes .../js/pdf/standard_fonts/FoxitSansItalic.pfb | Bin 16339 -> 0 bytes 78 files changed, 9107 insertions(+), 6578 deletions(-) create mode 100644 app/src/asset/pdf/caret_browsing.js create mode 100644 app/src/asset/pdf/download_manager.js create mode 100644 app/src/asset/pdf/draw_layer_builder.js create mode 100644 app/src/asset/pdf/external_services.js create mode 100644 app/src/asset/pdf/genericl10n.js create mode 100644 app/src/asset/pdf/l10n.js create mode 100644 app/src/asset/pdf/new_alt_text_manager.js create mode 100644 app/src/asset/pdf/pdf_print_service.js create mode 100644 app/src/asset/pdf/print_utils.js delete mode 100644 app/stage/protyle/js/pdf/pdf.js create mode 100644 app/stage/protyle/js/pdf/pdf.min.mjs create mode 100644 app/stage/protyle/js/pdf/pdf.sandbox.min.mjs delete mode 100644 app/stage/protyle/js/pdf/pdf.worker.js create mode 100644 app/stage/protyle/js/pdf/pdf.worker.min.mjs delete mode 100644 app/stage/protyle/js/pdf/standard_fonts/FoxitSans.pfb delete mode 100644 app/stage/protyle/js/pdf/standard_fonts/FoxitSansBold.pfb delete mode 100644 app/stage/protyle/js/pdf/standard_fonts/FoxitSansBoldItalic.pfb delete mode 100644 app/stage/protyle/js/pdf/standard_fonts/FoxitSansItalic.pfb diff --git a/app/appearance/langs/de_DE.json b/app/appearance/langs/de_DE.json index 800be438f..87dc3b6f6 100644 --- a/app/appearance/langs/de_DE.json +++ b/app/appearance/langs/de_DE.json @@ -702,7 +702,6 @@ "unitInches": "in", "unitMillimeters": "mm", "additionalLayers": "Zusätzliche Ebenen", - "thumbPage": "Miniaturansicht von Seite {{page}}", "thumbsTitle": "Miniaturansichten anzeigen", "document_properties_page_size_name_a3": "A3", "document_properties_page_size_name_a4": "A4", diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json index cf3ef308c..03f63d89a 100644 --- a/app/appearance/langs/en_US.json +++ b/app/appearance/langs/en_US.json @@ -702,7 +702,6 @@ "unitInches": "in", "unitMillimeters": "mm", "additionalLayers": "Additional Layers", - "thumbPage": "Thumbnail of Page {{page}}", "thumbsTitle": "Show Thumbnails", "document_properties_page_size_name_a3": "A3", "document_properties_page_size_name_a4": "A4", diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json index 64acb7f2f..fecf8bdb0 100644 --- a/app/appearance/langs/es_ES.json +++ b/app/appearance/langs/es_ES.json @@ -702,7 +702,6 @@ "unitInches": "pulgadas", "unitMillimeters": "milímetros", "additionalLayers": "Capas adicionales", - "thumbPage": "Miniatura de la página {{page}}", "thumbsTitle": "Mostrar miniaturas", "document_properties_page_size_name_a3": "A3", "document_properties_page_size_name_a4": "A4", diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json index 1c3785934..596f15b63 100644 --- a/app/appearance/langs/fr_FR.json +++ b/app/appearance/langs/fr_FR.json @@ -702,7 +702,6 @@ "unitInches": "in", "unitMillimeters": "mm", "additionalLayers": "Calques additionnels", - "thumbPage": "Vignette de la page {{page}}", "thumbsTitle": "Afficher les vignettes", "document_properties_page_size_name_a3": "A3", "document_properties_page_size_name_a4": "A4", diff --git a/app/appearance/langs/he_IL.json b/app/appearance/langs/he_IL.json index c54a60d28..af4db7e91 100644 --- a/app/appearance/langs/he_IL.json +++ b/app/appearance/langs/he_IL.json @@ -702,7 +702,6 @@ "unitInches": "אינצ'ים", "unitMillimeters": "מילימטרים", "additionalLayers": "שכבות נוספות", - "thumbPage": "תמונת עמוד {{page}}", "thumbsTitle": "הצג תמונות מקטנות", "document_properties_page_size_name_a3": "A3", "document_properties_page_size_name_a4": "A4", @@ -1549,7 +1548,7 @@ "241": "אין תמיכה בגרירה לתת הכותרת", "242": "מעט מקום נותר [%s], נדרש לפחות [%s] כדי לבצע פעולה זו", "243": "רק רשום את %d התגים הראשונים (כולל תתי תגים), אם יש צורך להתאים, אנא שנה את [הגדרות - עץ המסמכים - מספר מקסימלי לרשימה]", - "244": "אינדוקס הנתונים לא הושלם לאחר השימוש האחרון. אנא הפעל את [עץ מסמכים - שכתוב אינדקס]. אנא צא מהתוכנית לחלוטין לפני כיבוי המחשב.", + "244": "אינדוקס הנתונים לא הושלם לאחר השימוש האחרון. אנא הפעל את [עץ מסמכים - שכתוב אינדקס]. אנא צא מהתוכנית לחלוטין לפני כיבוי המחשב.", "245": "אינדוקס הנתונים לא הושלם לאחר השימוש האחרון. אנא זכור לבצע [עץ המסמכים - שחזור אינדקס]. אנא השתמש [צא מהאפליקציה] בפאנל הטורי הימני כדי לצאת על פי סדר", "246": "כותרת המסמך לא יכולה להכיל / והחלפה ב- _ ", "247": "הקובץ [%s] גדול יותר מהמגבלה המקסימלית [%s], והוזנח להעלות בענן", diff --git a/app/appearance/langs/it_IT.json b/app/appearance/langs/it_IT.json index 387345f50..4a7af9777 100644 --- a/app/appearance/langs/it_IT.json +++ b/app/appearance/langs/it_IT.json @@ -702,7 +702,6 @@ "unitInches": "in", "unitMillimeters": "mm", "additionalLayers": "Livelli aggiuntivi", - "thumbPage": "Miniatura di pagina {{page}}", "thumbsTitle": "Mostra miniature", "document_properties_page_size_name_a3": "A3", "document_properties_page_size_name_a4": "A4", @@ -1556,4 +1555,3 @@ "248": "L'intestazione di destinazione si trova nel blocco contenitore e non può essere utilizzata come punto di rilascio" } } - \ No newline at end of file diff --git a/app/appearance/langs/ja_JP.json b/app/appearance/langs/ja_JP.json index 82f0bea1b..93febb0b2 100644 --- a/app/appearance/langs/ja_JP.json +++ b/app/appearance/langs/ja_JP.json @@ -702,7 +702,6 @@ "unitInches": "インチ", "unitMillimeters": "ミリ", "additionalLayers": "追加のレイヤー", - "thumbPage": "ページ {{page}} のサムネイル", "thumbsTitle": "サムネイルを表示", "document_properties_page_size_name_a3": "A3", "document_properties_page_size_name_a4": "A4", diff --git a/app/appearance/langs/pl_PL.json b/app/appearance/langs/pl_PL.json index dc50a65ac..24acf35aa 100644 --- a/app/appearance/langs/pl_PL.json +++ b/app/appearance/langs/pl_PL.json @@ -702,7 +702,6 @@ "unitInches": "in", "unitMillimeters": "mm", "additionalLayers": "Dodatkowe warstwy", - "thumbPage": "Miniatura strony {{page}}", "thumbsTitle": "Pokaż miniatury", "document_properties_page_size_name_a3": "A3", "document_properties_page_size_name_a4": "A4", @@ -1555,4 +1554,4 @@ "247": "Plik [%s] jest większy niż maksymalne ograniczenie [%s], i został zignorowany przy przesyłaniu do chmury", "248": "Docelowy nagłówek znajduje się w bloku kontenera i nie może być użyty jako punkt upuszczenia" } -} \ No newline at end of file +} diff --git a/app/appearance/langs/ru_RU.json b/app/appearance/langs/ru_RU.json index c142d1125..d2dbcd26a 100644 --- a/app/appearance/langs/ru_RU.json +++ b/app/appearance/langs/ru_RU.json @@ -702,7 +702,6 @@ "unitInches": "дюйм", "unitMillimeters": "мм", "additionalLayers": "Дополнительные слои", - "thumbPage": "Миниатюра страницы {{page}}", "thumbsTitle": "Показать миниатюры", "document_properties_page_size_name_a3": "A3", "document_properties_page_size_name_a4": "A4", diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json index cb3e57dcb..7c92d271b 100644 --- a/app/appearance/langs/zh_CHT.json +++ b/app/appearance/langs/zh_CHT.json @@ -702,7 +702,6 @@ "unitInches": "英寸", "unitMillimeters": "毫米", "additionalLayers": "其他圖層", - "thumbPage": "頁面 {{page}} 的縮略圖", "thumbsTitle": "顯示縮略圖", "document_properties_page_size_name_a3": "A3", "document_properties_page_size_name_a4": "A4", diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json index 5a9a9afa5..4daa28c99 100644 --- a/app/appearance/langs/zh_CN.json +++ b/app/appearance/langs/zh_CN.json @@ -702,7 +702,6 @@ "unitInches": "英寸", "unitMillimeters": "毫米", "additionalLayers": "其他图层", - "thumbPage": "页面 {{page}} 的缩略图", "thumbsTitle": "显示缩略图", "document_properties_page_size_name_a3": "A3", "document_properties_page_size_name_a4": "A4", diff --git a/app/pnpm-lock.yaml b/app/pnpm-lock.yaml index 0b95830c1..fcae485f0 100644 --- a/app/pnpm-lock.yaml +++ b/app/pnpm-lock.yaml @@ -3300,7 +3300,7 @@ snapshots: app-builder-bin@5.0.0-alpha.7: {} - app-builder-lib@24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)): + app-builder-lib@24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)): dependencies: '@develar/schema-utils': 2.6.5 '@electron/notarize': 2.2.1 @@ -3314,7 +3314,7 @@ snapshots: builder-util-runtime: 9.2.4 chromium-pickle-js: 0.2.0 debug: 4.3.4 - dmg-builder: 24.13.3(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)) + dmg-builder: 24.13.3(electron-builder-squirrel-windows@25.0.5) ejs: 3.1.9 electron-builder-squirrel-windows: 25.0.5(dmg-builder@24.13.3) electron-publish: 24.13.1 @@ -3334,7 +3334,7 @@ snapshots: transitivePeerDependencies: - supports-color - app-builder-lib@25.0.5(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)): + app-builder-lib@25.0.5(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)): dependencies: '@develar/schema-utils': 2.6.5 '@electron/notarize': 2.3.2 @@ -3349,7 +3349,7 @@ snapshots: builder-util-runtime: 9.2.5 chromium-pickle-js: 0.2.0 debug: 4.3.4 - dmg-builder: 24.13.3(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)) + dmg-builder: 24.13.3(electron-builder-squirrel-windows@25.0.5) ejs: 3.1.9 electron-builder-squirrel-windows: 25.0.5(dmg-builder@24.13.3) electron-publish: 25.0.3 @@ -3814,9 +3814,9 @@ snapshots: dependencies: path-type: 4.0.0 - dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)): + dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5): dependencies: - app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)) + app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)) builder-util: 24.13.1 builder-util-runtime: 9.2.4 fs-extra: 10.1.0 @@ -3891,7 +3891,7 @@ snapshots: electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3): dependencies: - app-builder-lib: 25.0.5(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)) + app-builder-lib: 25.0.5(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)) archiver: 5.3.2 builder-util: 25.0.3 fs-extra: 10.1.0 @@ -3902,11 +3902,11 @@ snapshots: electron-builder@24.13.3(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)): dependencies: - app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)) + app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)) builder-util: 24.13.1 builder-util-runtime: 9.2.4 chalk: 4.1.2 - dmg-builder: 24.13.3(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)) + dmg-builder: 24.13.3(electron-builder-squirrel-windows@25.0.5) fs-extra: 10.1.0 is-ci: 3.0.1 lazy-val: 1.0.5 diff --git a/app/src/asset/anno.ts b/app/src/asset/anno.ts index 33c3c841b..1e9b2d689 100644 --- a/app/src/asset/anno.ts +++ b/app/src/asset/anno.ts @@ -8,8 +8,9 @@ import {Constants} from "../constants"; import {Dialog} from "../dialog"; import {showMessage} from "../dialog/message"; -export const initAnno = (element: HTMLElement, pdf: any, pdfConfig: any) => { +export const initAnno = (element: HTMLElement, pdf: any) => { getConfig(pdf); + const pdfConfig = pdf.appConfig; const rectAnnoElement = pdfConfig.toolbar.rectAnno; rectAnnoElement.addEventListener("click", () => { if (rectAnnoElement.classList.contains("toggled")) { @@ -644,16 +645,17 @@ export const getHighlight = (element: HTMLElement) => { const showHighlight = (selected: IPdfAnno, pdf: any, hl?: boolean) => { const pageIndex = selected.index; const page = pdf.pdfViewer.getPageView(pageIndex); - let textLayerElement = page.textLayer.div; + const textLayerElement = page.textLayer.div; if (!textLayerElement.lastElementChild) { return; } const viewport = page.viewport.clone({rotation: 0}); // rotation https://github.com/siyuan-note/siyuan/issues/9831 - if (textLayerElement.lastElementChild.classList.contains("endOfContent")) { - textLayerElement.insertAdjacentHTML("beforeend", "
"); + let rectsElement = textLayerElement.querySelector(".pdf__rects"); + if (!rectsElement) { + textLayerElement.insertAdjacentHTML("beforeend", "
"); + rectsElement = textLayerElement.querySelector(".pdf__rects"); } - textLayerElement = textLayerElement.lastElementChild; let html = `
`; selected.coords.forEach((rect) => { const bounds = viewport.convertToViewportRectangle(rect); @@ -666,17 +668,17 @@ const showHighlight = (selected: IPdfAnno, pdf: any, hl?: boolean) => { style = `border: 2px solid ${selected.color};`; } html += `
`; +left:${Math.min(bounds[0], bounds[2])}px; +top:${Math.min(bounds[1], bounds[3])}px; +width:${width}px; +height: ${Math.abs(bounds[1] - bounds[3])}px">
`; }); - textLayerElement.insertAdjacentHTML("beforeend", html + ""); - textLayerElement.lastElementChild.setAttribute("data-content", selected.content); + rectsElement.insertAdjacentHTML("beforeend", html + ""); + rectsElement.lastElementChild.setAttribute("data-content", selected.content); if (hl) { - hlPDFRect(textLayerElement, selected.id); + hlPDFRect(rectsElement, selected.id); } - return textLayerElement.lastElementChild; + return rectsElement.lastElementChild; }; export const hlPDFRect = (element: HTMLElement, id: string) => { diff --git a/app/src/asset/index.ts b/app/src/asset/index.ts index bd71cd786..506623ef3 100644 --- a/app/src/asset/index.ts +++ b/app/src/asset/index.ts @@ -9,7 +9,7 @@ import {setModelsHash} from "../window/setHeader"; // @ts-ignore import {webViewerLoad} from "./pdf/viewer"; // @ts-ignore -import {webViewerPageNumberChanged} from "./pdf/app"; +import {onPageNumberChanged} from "./pdf/app"; /// #endif import {fetchPost} from "../util/fetch"; import {setStorageVal, updateHotkeyTip} from "../protyle/util/compatibility"; @@ -73,12 +73,12 @@ export class Asset extends Model { /// #if !MOBILE if (typeof pdfId === "string") { this.getPdfId(() => { - webViewerPageNumberChanged({value: this.pdfPage, pdfInstance: this.pdfObject, id: this.pdfId}); + onPageNumberChanged({value: this.pdfPage, pdfInstance: this.pdfObject, id: this.pdfId}); }); return; } if (typeof pdfId === "number" && !isNaN(pdfId)) { - webViewerPageNumberChanged({value: this.pdfId, pdfInstance: this.pdfObject}); + onPageNumberChanged({value: this.pdfId, pdfInstance: this.pdfObject}); } /// #endif } @@ -135,10 +135,10 @@ export class Asset extends Model {
- -
@@ -453,11 +453,18 @@ export class Asset extends Model { - + + + + - + - + + + + +
`; diff --git a/app/src/asset/pdf/annotation_editor_layer_builder.js b/app/src/asset/pdf/annotation_editor_layer_builder.js index 28b0e26dd..c0c1954f8 100644 --- a/app/src/asset/pdf/annotation_editor_layer_builder.js +++ b/app/src/asset/pdf/annotation_editor_layer_builder.js @@ -21,34 +21,58 @@ // eslint-disable-next-line max-len /** @typedef {import("./text_accessibility.js").TextAccessibilityManager} TextAccessibilityManager */ /** @typedef {import("./interfaces").IL10n} IL10n */ +// eslint-disable-next-line max-len +/** @typedef {import("../src/display/annotation_layer.js").AnnotationLayer} AnnotationLayer */ +// eslint-disable-next-line max-len +/** @typedef {import("../src/display/struct_tree_layer_builder.js").StructTreeLayerBuilder} StructTreeLayerBuilder */ import { AnnotationEditorLayer } from "./pdfjs"; -import { NullL10n } from "./l10n_utils.js"; /** * @typedef {Object} AnnotationEditorLayerBuilderOptions * @property {AnnotationEditorUIManager} [uiManager] - * @property {HTMLDivElement} pageDiv * @property {PDFPageProxy} pdfPage * @property {IL10n} [l10n] + * @property {StructTreeLayerBuilder} [structTreeLayer] * @property {TextAccessibilityManager} [accessibilityManager] + * @property {AnnotationLayer} [annotationLayer] + * @property {TextLayer} [textLayer] + * @property {DrawLayer} [drawLayer] + * @property {function} [onAppend] */ class AnnotationEditorLayerBuilder { + #annotationLayer = null; + + #drawLayer = null; + + #onAppend = null; + + #structTreeLayer = null; + + #textLayer = null; + #uiManager; /** * @param {AnnotationEditorLayerBuilderOptions} options */ constructor(options) { - this.pageDiv = options.pageDiv; this.pdfPage = options.pdfPage; this.accessibilityManager = options.accessibilityManager; - this.l10n = options.l10n || NullL10n; + this.l10n = options.l10n; + if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { + this.l10n ||= new GenericL10n(); + } this.annotationEditorLayer = null; this.div = null; this._cancelled = false; this.#uiManager = options.uiManager; + this.#annotationLayer = options.annotationLayer || null; + this.#textLayer = options.textLayer || null; + this.#drawLayer = options.drawLayer || null; + this.#onAppend = options.onAppend || null; + this.#structTreeLayer = options.structTreeLayer || null; } /** @@ -74,17 +98,21 @@ class AnnotationEditorLayerBuilder { // Create an AnnotationEditor layer div const div = (this.div = document.createElement("div")); div.className = "annotationEditorLayer"; - div.tabIndex = 0; div.hidden = true; - this.pageDiv.append(div); + div.dir = this.#uiManager.direction; + this.#onAppend?.(div); this.annotationEditorLayer = new AnnotationEditorLayer({ uiManager: this.#uiManager, div, + structTreeLayer: this.#structTreeLayer, accessibilityManager: this.accessibilityManager, pageIndex: this.pdfPage.pageNumber - 1, l10n: this.l10n, viewport: clonedViewport, + annotationLayer: this.#annotationLayer, + textLayer: this.#textLayer, + drawLayer: this.#drawLayer, }); const parameters = { @@ -104,9 +132,7 @@ class AnnotationEditorLayerBuilder { if (!this.div) { return; } - this.pageDiv = null; this.annotationEditorLayer.destroy(); - this.div.remove(); } hide() { @@ -117,7 +143,7 @@ class AnnotationEditorLayerBuilder { } show() { - if (!this.div || this.annotationEditorLayer.isEmpty) { + if (!this.div || this.annotationEditorLayer.isInvisible) { return; } this.div.hidden = false; diff --git a/app/src/asset/pdf/annotation_editor_params.js b/app/src/asset/pdf/annotation_editor_params.js index 78e2777a7..ae864653c 100644 --- a/app/src/asset/pdf/annotation_editor_params.js +++ b/app/src/asset/pdf/annotation_editor_params.js @@ -13,8 +13,22 @@ * limitations under the License. */ +/** @typedef {import("./event_utils.js").EventBus} EventBus */ + import { AnnotationEditorParamsType } from "./pdfjs"; +/** + * @typedef {Object} AnnotationEditorParamsOptions + * @property {HTMLInputElement} editorFreeTextFontSize + * @property {HTMLInputElement} editorFreeTextColor + * @property {HTMLInputElement} editorInkColor + * @property {HTMLInputElement} editorInkThickness + * @property {HTMLInputElement} editorInkOpacity + * @property {HTMLButtonElement} editorStampAddImage + * @property {HTMLInputElement} editorFreeHighlightThickness + * @property {HTMLButtonElement} editorHighlightShowAll + */ + class AnnotationEditorParams { /** * @param {AnnotationEditorParamsOptions} options @@ -25,47 +39,58 @@ class AnnotationEditorParams { this.#bindListeners(options); } + /** + * @param {AnnotationEditorParamsOptions} options + */ #bindListeners({ editorFreeTextFontSize, editorFreeTextColor, editorInkColor, editorInkThickness, editorInkOpacity, + editorStampAddImage, + editorFreeHighlightThickness, + editorHighlightShowAll, }) { - editorFreeTextFontSize.addEventListener("input", evt => { + const dispatchEvent = (typeStr, value) => { this.eventBus.dispatch("switchannotationeditorparams", { source: this, - type: AnnotationEditorParamsType.FREETEXT_SIZE, - value: editorFreeTextFontSize.valueAsNumber, + type: AnnotationEditorParamsType[typeStr], + value, }); + }; + editorFreeTextFontSize.addEventListener("input", function () { + dispatchEvent("FREETEXT_SIZE", this.valueAsNumber); }); - editorFreeTextColor.addEventListener("input", evt => { - this.eventBus.dispatch("switchannotationeditorparams", { - source: this, - type: AnnotationEditorParamsType.FREETEXT_COLOR, - value: editorFreeTextColor.value, - }); + editorFreeTextColor.addEventListener("input", function () { + dispatchEvent("FREETEXT_COLOR", this.value); }); - editorInkColor.addEventListener("input", evt => { - this.eventBus.dispatch("switchannotationeditorparams", { - source: this, - type: AnnotationEditorParamsType.INK_COLOR, - value: editorInkColor.value, - }); + editorInkColor.addEventListener("input", function () { + dispatchEvent("INK_COLOR", this.value); }); - editorInkThickness.addEventListener("input", evt => { - this.eventBus.dispatch("switchannotationeditorparams", { - source: this, - type: AnnotationEditorParamsType.INK_THICKNESS, - value: editorInkThickness.valueAsNumber, - }); + editorInkThickness.addEventListener("input", function () { + dispatchEvent("INK_THICKNESS", this.valueAsNumber); }); - editorInkOpacity.addEventListener("input", evt => { - this.eventBus.dispatch("switchannotationeditorparams", { + editorInkOpacity.addEventListener("input", function () { + dispatchEvent("INK_OPACITY", this.valueAsNumber); + }); + editorStampAddImage.addEventListener("click", () => { + this.eventBus.dispatch("reporttelemetry", { source: this, - type: AnnotationEditorParamsType.INK_OPACITY, - value: editorInkOpacity.valueAsNumber, + details: { + type: "editing", + data: { action: "pdfjs.image.add_image_click" }, + }, }); + dispatchEvent("CREATE"); + }); + editorFreeHighlightThickness.addEventListener("input", function () { + dispatchEvent("HIGHLIGHT_THICKNESS", this.valueAsNumber); + }); + editorHighlightShowAll.addEventListener("click", function () { + const checked = this.getAttribute("aria-pressed") === "true"; + this.setAttribute("aria-pressed", !checked); + dispatchEvent("HIGHLIGHT_SHOW_ALL", !checked); }); this.eventBus._on("annotationeditorparamschanged", evt => { @@ -86,6 +111,15 @@ class AnnotationEditorParams { case AnnotationEditorParamsType.INK_OPACITY: editorInkOpacity.value = value; break; + case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS: + editorFreeHighlightThickness.value = value; + break; + case AnnotationEditorParamsType.HIGHLIGHT_FREE: + editorFreeHighlightThickness.disabled = !value; + break; + case AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL: + editorHighlightShowAll.setAttribute("aria-pressed", value); + break; } } }); diff --git a/app/src/asset/pdf/annotation_layer_builder.js b/app/src/asset/pdf/annotation_layer_builder.js index 2cd0845f5..64790bcd2 100644 --- a/app/src/asset/pdf/annotation_layer_builder.js +++ b/app/src/asset/pdf/annotation_layer_builder.js @@ -16,72 +16,75 @@ /** @typedef {import("../src/display/api").PDFPageProxy} PDFPageProxy */ // eslint-disable-next-line max-len /** @typedef {import("../src/display/display_utils").PageViewport} PageViewport */ +// eslint-disable-next-line max-len +/** @typedef {import("../src/display/annotation_storage").AnnotationStorage} AnnotationStorage */ /** @typedef {import("./interfaces").IDownloadManager} IDownloadManager */ -/** @typedef {import("./interfaces").IL10n} IL10n */ /** @typedef {import("./interfaces").IPDFLinkService} IPDFLinkService */ // eslint-disable-next-line max-len -/** @typedef {import("./textaccessibility.js").TextAccessibilityManager} TextAccessibilityManager */ +/** @typedef {import("./text_accessibility.js").TextAccessibilityManager} TextAccessibilityManager */ +// eslint-disable-next-line max-len +/** @typedef {import("../src/display/editor/tools.js").AnnotationEditorUIManager} AnnotationEditorUIManager */ import { AnnotationLayer } from "./pdfjs"; -import { NullL10n } from "./l10n_utils.js"; import { PresentationModeState } from "./ui_utils.js"; /** * @typedef {Object} AnnotationLayerBuilderOptions - * @property {HTMLDivElement} pageDiv * @property {PDFPageProxy} pdfPage * @property {AnnotationStorage} [annotationStorage] * @property {string} [imageResourcesPath] - Path for image resources, mainly * for annotation icons. Include trailing slash. * @property {boolean} renderForms * @property {IPDFLinkService} linkService - * @property {IDownloadManager} downloadManager - * @property {IL10n} l10n - Localization service. + * @property {IDownloadManager} [downloadManager] * @property {boolean} [enableScripting] * @property {Promise} [hasJSActionsPromise] * @property {Promise> | null>} * [fieldObjectsPromise] * @property {Map} [annotationCanvasMap] * @property {TextAccessibilityManager} [accessibilityManager] + * @property {AnnotationEditorUIManager} [annotationEditorUIManager] + * @property {function} [onAppend] */ class AnnotationLayerBuilder { - #numAnnotations = 0; + #onAppend = null; - #onPresentationModeChanged = null; + #eventAbortController = null; /** * @param {AnnotationLayerBuilderOptions} options */ constructor({ - pageDiv, pdfPage, linkService, downloadManager, annotationStorage = null, imageResourcesPath = "", renderForms = true, - l10n = NullL10n, enableScripting = false, hasJSActionsPromise = null, fieldObjectsPromise = null, annotationCanvasMap = null, accessibilityManager = null, + annotationEditorUIManager = null, + onAppend = null, }) { - this.pageDiv = pageDiv; this.pdfPage = pdfPage; this.linkService = linkService; this.downloadManager = downloadManager; this.imageResourcesPath = imageResourcesPath; this.renderForms = renderForms; - this.l10n = l10n; this.annotationStorage = annotationStorage; this.enableScripting = enableScripting; this._hasJSActionsPromise = hasJSActionsPromise || Promise.resolve(false); this._fieldObjectsPromise = fieldObjectsPromise || Promise.resolve(null); this._annotationCanvasMap = annotationCanvasMap; this._accessibilityManager = accessibilityManager; + this._annotationEditorUIManager = annotationEditorUIManager; + this.#onAppend = onAppend; + this.annotationLayer = null; this.div = null; this._cancelled = false; this._eventBus = linkService.eventBus; @@ -89,21 +92,20 @@ class AnnotationLayerBuilder { /** * @param {PageViewport} viewport + * @param {Object} options * @param {string} intent (default value is 'display') * @returns {Promise} A promise that is resolved when rendering of the * annotations is complete. */ - async render(viewport, intent = "display") { + async render(viewport, options, intent = "display") { if (this.div) { - if (this._cancelled || this.#numAnnotations === 0) { + if (this._cancelled || !this.annotationLayer) { return; } // If an annotationLayer already exists, refresh its children's // transformation matrices. - AnnotationLayer.update({ + this.annotationLayer.update({ viewport: viewport.clone({ dontFlip: true }), - div: this.div, - annotationCanvasMap: this._annotationCanvasMap, }); return; } @@ -116,23 +118,30 @@ class AnnotationLayerBuilder { if (this._cancelled) { return; } - this.#numAnnotations = annotations.length; // Create an annotation layer div and render the annotations // if there is at least one annotation. - this.div = document.createElement("div"); - this.div.className = "annotationLayer"; - this.pageDiv.append(this.div); + const div = (this.div = document.createElement("div")); + div.className = "annotationLayer"; + this.#onAppend?.(div); - if (this.#numAnnotations === 0) { + if (annotations.length === 0) { this.hide(); return; } - AnnotationLayer.render({ - viewport: viewport.clone({ dontFlip: true }), - div: this.div, - annotations, + + this.annotationLayer = new AnnotationLayer({ + div, + accessibilityManager: this._accessibilityManager, + annotationCanvasMap: this._annotationCanvasMap, + annotationEditorUIManager: this._annotationEditorUIManager, page: this.pdfPage, + viewport: viewport.clone({ dontFlip: true }), + structTreeLayer: options?.structTreeLayer || null, + }); + + await this.annotationLayer.render({ + annotations, imageResourcesPath: this.imageResourcesPath, renderForms: this.renderForms, linkService: this.linkService, @@ -141,23 +150,22 @@ class AnnotationLayerBuilder { enableScripting: this.enableScripting, hasJSActions, fieldObjects, - annotationCanvasMap: this._annotationCanvasMap, - accessibilityManager: this._accessibilityManager, }); - // NOTE this.l10n.translate(this.div); // Ensure that interactive form elements in the annotationLayer are // disabled while PresentationMode is active (see issue 12232). if (this.linkService.isInPresentationMode) { this.#updatePresentationModeState(PresentationModeState.FULLSCREEN); } - if (!this.#onPresentationModeChanged) { - this.#onPresentationModeChanged = evt => { - this.#updatePresentationModeState(evt.state); - }; + if (!this.#eventAbortController) { + this.#eventAbortController = new AbortController(); + this._eventBus?._on( "presentationmodechanged", - this.#onPresentationModeChanged + evt => { + this.#updatePresentationModeState(evt.state); + }, + { signal: this.#eventAbortController.signal } ); } } @@ -165,13 +173,8 @@ class AnnotationLayerBuilder { cancel() { this._cancelled = true; - if (this.#onPresentationModeChanged) { - this._eventBus?._off( - "presentationmodechanged", - this.#onPresentationModeChanged - ); - this.#onPresentationModeChanged = null; - } + this.#eventAbortController?.abort(); + this.#eventAbortController = null; } hide() { @@ -181,6 +184,10 @@ class AnnotationLayerBuilder { this.div.hidden = true; } + hasEditableAnnotations() { + return !!this.annotationLayer?.hasEditableAnnotations(); + } + #updatePresentationModeState(state) { if (!this.div) { return; diff --git a/app/src/asset/pdf/app.js b/app/src/asset/pdf/app.js index 0f29d0b53..29a9fa75c 100644 --- a/app/src/asset/pdf/app.js +++ b/app/src/asset/pdf/app.js @@ -13,3523 +13,3195 @@ * limitations under the License. */ +/** @typedef {import("./interfaces.js").IL10n} IL10n */ +// eslint-disable-next-line max-len +/** @typedef {import("../src/display/api.js").PDFDocumentProxy} PDFDocumentProxy */ +// eslint-disable-next-line max-len +/** @typedef {import("../src/display/api.js").PDFDocumentLoadingTask} PDFDocumentLoadingTask */ + import { - animationStarted, - apiPageLayoutToViewerModes, - apiPageModeToSidebarView, - AutoPrintRegExp, - CursorTool, - DEFAULT_SCALE_VALUE, - getActiveOrFocusedElement, - isValidRotation, - isValidScrollMode, - isValidSpreadMode, - normalizeWheelEventDirection, - parseQueryString, - ProgressBar, - RendererType, - RenderingStates, - ScrollMode, - SidebarView, - SpreadMode, - TextLayerMode, + animationStarted, + apiPageLayoutToViewerModes, + apiPageModeToSidebarView, + AutoPrintRegExp, + CursorTool, + DEFAULT_SCALE_VALUE, + getActiveOrFocusedElement, + isValidRotation, + isValidScrollMode, + isValidSpreadMode, + normalizeWheelEventDirection, + parseQueryString, + ProgressBar, + RenderingStates, + ScrollMode, + SidebarView, + SpreadMode, + TextLayerMode, } from "./ui_utils.js"; import { - AnnotationEditorType, - build, - createPromiseCapability, - FeatureTest, - getDocument, - getFilenameFromUrl, - getPdfFilenameFromUrl, - GlobalWorkerOptions, - InvalidPDFException, - isDataScheme, - isPdfFile, - loadScript, - MissingPDFException, - OPS, - PDFWorker, - shadow, - UnexpectedResponseException, - version, + AnnotationEditorType, + build, + FeatureTest, + getDocument, + getFilenameFromUrl, + getPdfFilenameFromUrl, + GlobalWorkerOptions, + InvalidPDFException, + isDataScheme, + isPdfFile, + MissingPDFException, + PDFWorker, + shadow, + UnexpectedResponseException, + version, } from "./pdfjs"; -import { AppOptions, OptionKind } from "./app_options.js"; -import { AutomationEventBus, EventBus } from "./event_utils.js"; -import { LinkTarget, PDFLinkService } from "./pdf_link_service.js"; -import { AnnotationEditorParams } from "./annotation_editor_params"; -import { OverlayManager } from "./overlay_manager.js"; -import { PasswordPrompt } from "./password_prompt.js"; -import { PDFAttachmentViewer } from "./pdf_attachment_viewer"; -import { PDFCursorTools } from "./pdf_cursor_tools"; -import { PDFDocumentProperties } from "./pdf_document_properties"; -import { PDFFindBar } from "./pdf_find_bar"; -import { PDFFindController } from "./pdf_find_controller.js"; -import { PDFHistory } from "./pdf_history.js"; -import { PDFLayerViewer } from "./pdf_layer_viewer"; -import { PDFOutlineViewer } from "./pdf_outline_viewer"; -import { PDFPresentationMode } from "./pdf_presentation_mode"; -import { PDFRenderingQueue } from "./pdf_rendering_queue.js"; -import { PDFScriptingManager } from "./pdf_scripting_manager.js"; -import { PDFSidebar } from "./pdf_sidebar"; -import { PDFSidebarResizer } from "./pdf_sidebar_resizer"; -import { PDFThumbnailViewer } from "./pdf_thumbnail_viewer"; -import { PDFViewer } from "./pdf_viewer.js"; -import { SecondaryToolbar } from "./secondary_toolbar.js"; -import { Toolbar } from "./toolbar.js"; -import { ViewHistory } from "./view_history.js"; -import { DefaultExternalServices } from './genericcom' -import { getPdfInstance, hlPDFRect } from '../anno' +import {AppOptions, OptionKind} from "./app_options.js"; +import {EventBus, FirefoxEventBus} from "./event_utils.js"; +import {ExternalServices, initCom, MLManager} from "./genericcom.js"; +import { + ImageAltTextSettings, + NewAltTextManager, +} from "./new_alt_text_manager"; +import {LinkTarget, PDFLinkService} from "./pdf_link_service.js"; +import {AnnotationEditorParams} from "./annotation_editor_params"; +import {CaretBrowsingMode} from "./caret_browsing.js"; +import {DownloadManager} from "./download_manager"; +import {OverlayManager} from "./overlay_manager.js"; +import {PasswordPrompt} from "./password_prompt.js"; +import {PDFAttachmentViewer} from "./pdf_attachment_viewer"; +import {PDFCursorTools} from "./pdf_cursor_tools"; +import {PDFDocumentProperties} from "./pdf_document_properties"; +import {PDFFindBar} from "./pdf_find_bar"; +import {PDFFindController} from "./pdf_find_controller.js"; +import {PDFHistory} from "./pdf_history.js"; +import {PDFLayerViewer} from "./pdf_layer_viewer"; +import {PDFOutlineViewer} from "./pdf_outline_viewer"; +import {PDFPresentationMode} from "./pdf_presentation_mode"; +import {PDFPrintServiceFactory} from "./pdf_print_service.js"; +import {PDFRenderingQueue} from "./pdf_rendering_queue.js"; +import {PDFScriptingManager} from "./pdf_scripting_manager.js"; +import {PDFSidebar} from "./pdf_sidebar"; +import {PDFThumbnailViewer} from "./pdf_thumbnail_viewer"; +import {PDFViewer} from "./pdf_viewer.js"; +import {Preferences} from "./genericcom.js"; +import {SecondaryToolbar} from "./secondary_toolbar"; +import {Toolbar} from "./toolbar"; +import {ViewHistory} from "./view_history.js"; import {hasClosestByClassName} from "../../protyle/util/hasClosest"; +import {Constants} from "../../constants"; +import {getPdfInstance} from "../anno"; const FORCE_PAGES_LOADED_TIMEOUT = 10000; // ms -const WHEEL_ZOOM_DISABLED_TIMEOUT = 1000; // ms const ViewOnLoad = { - UNKNOWN: -1, - PREVIOUS: 0, // Default value. - INITIAL: 1, -}; - -const ViewerCssTheme = { - AUTOMATIC: 0, // Default value. - LIGHT: 1, - DARK: 2, + UNKNOWN: -1, + PREVIOUS: 0, // Default value. + INITIAL: 1, }; // NOTE class PDFViewerApplication { - constructor (pdfId) { - this.pdfId = pdfId - this.initialBookmark = document.location.hash.substring(1) - this._initializedCapability = createPromiseCapability() - this.appConfig = null - this.pdfDocument = null - this.pdfLoadingTask = null - this.printService = null - /** @type {PDFViewer} */ - this.pdfViewer = null - /** @type {PDFThumbnailViewer} */ - this.pdfThumbnailViewer = null - /** @type {PDFRenderingQueue} */ - this.pdfRenderingQueue = null - /** @type {PDFPresentationMode} */ - this.pdfPresentationMode = null - /** @type {PDFDocumentProperties} */ - this.pdfDocumentProperties = null - /** @type {PDFLinkService} */ - this.pdfLinkService = null - /** @type {PDFHistory} */ - this.pdfHistory = null - /** @type {PDFSidebar} */ - this.pdfSidebar = null - /** @type {PDFSidebarResizer} */ - this.pdfSidebarResizer = null - /** @type {PDFOutlineViewer} */ - this.pdfOutlineViewer = null - /** @type {PDFAttachmentViewer} */ - this.pdfAttachmentViewer = null - /** @type {PDFLayerViewer} */ - this.pdfLayerViewer = null - /** @type {PDFCursorTools} */ - this.pdfCursorTools = null - /** @type {PDFScriptingManager} */ - this.pdfScriptingManager = null - /** @type {ViewHistory} */ - this.store = null - /** @type {DownloadManager} */ - this.downloadManager = null - /** @type {OverlayManager} */ - this.overlayManager = null - /** @type {Preferences} */ - this.preferences = null - /** @type {Toolbar} */ - this.toolbar = null - /** @type {SecondaryToolbar} */ - this.secondaryToolbar = null - /** @type {EventBus} */ - this.eventBus = null - /** @type {IL10n} */ - this.l10n = null - /** @type {AnnotationEditorParams} */ - this.annotationEditorParams = null - this.isInitialViewSet = false - this.downloadComplete = false - // NOTE 不使用 initialBookmark - this.isViewerEmbedded = true - this.url = "" - this.baseUrl = "" - this._downloadUrl = "" - this.externalServices = DefaultExternalServices - this._boundEvents = Object.create(null) - this.documentInfo = null - this.metadata = null - this._contentDispositionFilename = null - this._contentLength = null - this._saveInProgress = false - this._wheelUnusedTicks = 0 - this._wheelUnusedFactor = 1 - this._touchUnusedTicks = 0 - this._touchUnusedFactor = 1 - this._PDFBug = null - this._hasAnnotationEditors = false - this._title = document.title - this._printAnnotationStoragePromise = null - this._touchInfo = null - this._isCtrlKeyDown = false - } - // Called once when the document is loaded. - async initialize(appConfig) { - this.preferences = this.externalServices.createPreferences(); - this.appConfig = appConfig; - - await this._initializeOptions(); - this._forceCssTheme(); - // NOTE await this._initializeL10n(); - // https://github.com/siyuan-note/siyuan/issues/8997 - AppOptions.set("ignoreDestinationZoom", true); - - if ( - this.isViewerEmbedded && - AppOptions.get("externalLinkTarget") === LinkTarget.NONE - ) { - // Prevent external links from "replacing" the viewer, - // when it's embedded in e.g. an