From 994bb4d1d23ce16a5c0e3a16c86b1219c4ab9c49 Mon Sep 17 00:00:00 2001 From: NeilJared Date: Wed, 14 Feb 2024 11:57:34 +0100 Subject: [PATCH 001/200] Update messages_es_ES.properties Minor bug fixes: es_ES translation --- src/main/resources/messages_es_ES.properties | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/resources/messages_es_ES.properties b/src/main/resources/messages_es_ES.properties index 43061780..3a303d9e 100644 --- a/src/main/resources/messages_es_ES.properties +++ b/src/main/resources/messages_es_ES.properties @@ -57,7 +57,7 @@ usernameExistsMessage=El nuevo nombre de usuario está en uso. ############### # Pipeline # ############### -pipeline.header=Menu Pipeline (Alfa) +pipeline.header=Menú de canalización (Alfa) pipeline.uploadButton=Cargar personalización pipeline.configureButton=Configurar pipeline.defaultOption=Personalizar @@ -66,13 +66,13 @@ pipeline.submitButton=Enviar ###################### # Pipeline Options # ###################### -pipelineOptions.header=Configuración Pipeline -pipelineOptions.pipelineNameLabel=Nombre del Pipeline -pipelineOptions.saveSettings=Guardar configuración de la oiperación -pipelineOptions.pipelineNamePrompt=Introduzca aquí el nombre del pipeline +pipelineOptions.header=Configuración de la canalización +pipelineOptions.pipelineNameLabel=Nombre de la canalización +pipelineOptions.saveSettings=Guardar configuración de la canalización +pipelineOptions.pipelineNamePrompt=Introduzca aquí el nombre de la canalización pipelineOptions.selectOperation=Seleccione la operación pipelineOptions.addOperationButton=Añadir operación -pipelineOptions.pipelineHeader=Pipeline: +pipelineOptions.pipelineHeader=Canalización: pipelineOptions.saveButton=Descargar pipelineOptions.validateButton=Validar @@ -563,7 +563,7 @@ autoSplitPDF.submit=Entregar #pipeline -pipeline.title=Pipeline +pipeline.title=Canalización #pageLayout From 639aed71203c89bdf391056815acd3d18319ad89 Mon Sep 17 00:00:00 2001 From: NeilJared Date: Wed, 14 Feb 2024 12:22:47 +0100 Subject: [PATCH 002/200] Update messages_es_ES.properties Updated es_ES translation --- src/main/resources/messages_es_ES.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/messages_es_ES.properties b/src/main/resources/messages_es_ES.properties index 3a303d9e..38c6d6a5 100644 --- a/src/main/resources/messages_es_ES.properties +++ b/src/main/resources/messages_es_ES.properties @@ -11,7 +11,7 @@ imgPrompt=Seleccionar Imagen(es) genericSubmit=Enviar processTimeWarning=Advertencia: este proceso puede tardar hasta un minuto dependiendo del tamaño del archivo pageOrderPrompt=Orden de páginas (Introduzca una lista de números de página separados por coma): -pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) : +pageSelectionPrompt=Selección de página personalizada (Intruduzca una lista de números de página separados por comas 1,5,6 o funciones como 2n+1) : goToPage=Ir a true=Verdadero false=Falso From e4a76e96af4fd2bedb1bced2b6cb05b7fe580887 Mon Sep 17 00:00:00 2001 From: Ludy Date: Fri, 16 Feb 2024 22:49:06 +0100 Subject: [PATCH 003/200] HTML, CSS, JS and JAVA corrections (#810) * CSS corrections * HTML corrections * JS corrections * JAVA corrections * remove tab * CSS corrections 2 * JS corrections 2 * back to the roots * max-linie 127 * add slash hr|br * return bootstrap-icons.css * return bootstrap-icons.min.css * return bootstrap.min.css * Update bootstrap-icons.css * Update bootstrap-icons.min.css * Update bootstrap-icons.min.css * Update bootstrap.min.css * CSS corrections * HTML corrections * JS corrections * JAVA corrections * remove tab * CSS corrections 2 * JS corrections 2 * back to the roots * max-linie 127 * add slash hr|br * return bootstrap-icons.css * Update bootstrap-icons.css * Bootstrap CSS * Update prism.css --- .../controller/web/AccountWebController.java | 3 + src/main/resources/static/css/account.css | 4 + src/main/resources/static/css/add-image.css | 28 + src/main/resources/static/css/dark-mode.css | 122 +- src/main/resources/static/css/dragdrop.css | 80 +- src/main/resources/static/css/error.css | 88 ++ src/main/resources/static/css/errorBanner.css | 109 +- src/main/resources/static/css/fileSelect.css | 12 +- src/main/resources/static/css/footer.css | 20 + src/main/resources/static/css/game.css | 67 +- src/main/resources/static/css/general.css | 80 +- src/main/resources/static/css/home.css | 98 +- .../resources/static/css/imageHighlighter.css | 57 +- src/main/resources/static/css/licenses.css | 9 + src/main/resources/static/css/light-mode.css | 11 +- src/main/resources/static/css/login.css | 111 ++ src/main/resources/static/css/merge.css | 3 +- src/main/resources/static/css/multi-tool.css | 119 ++ src/main/resources/static/css/navbar.css | 118 +- src/main/resources/static/css/pdfActions.css | 84 +- src/main/resources/static/css/pipeline.css | 21 + .../resources/static/css/rainbow-mode.css | 106 +- src/main/resources/static/css/rotate-pdf.css | 29 + src/main/resources/static/css/sign.css | 39 + .../static/css/split-pdf-by-sections.css | 10 + src/main/resources/static/css/stamp.css | 41 + .../resources/static/css/tab-container.css | 28 +- src/main/resources/static/js/darkmode.js | 86 +- src/main/resources/static/js/downloader.js | 383 +++--- .../resources/static/js/draggable-utils.js | 499 ++++---- src/main/resources/static/js/errorBanner.js | 72 +- src/main/resources/static/js/favourites.js | 74 +- src/main/resources/static/js/fileInput.js | 177 +-- src/main/resources/static/js/game.js | 513 ++++---- src/main/resources/static/js/githubVersion.js | 79 +- src/main/resources/static/js/homecard.js | 122 +- .../resources/static/js/languageSelection.js | 130 +- .../static/js/local-pdf-input-download.js | 78 +- src/main/resources/static/js/merge.js | 178 +-- .../static/js/multitool/DragDropManager.js | 204 ++-- .../static/js/multitool/ImageHighlighter.js | 74 +- .../static/js/multitool/PdfActionsManager.js | 290 ++--- .../static/js/multitool/PdfContainer.js | 515 ++++---- .../static/js/multitool/fileInput.js | 159 +-- .../static/js/multitool/horizontalScroll.js | 51 +- src/main/resources/static/js/pipeline.js | 1066 ++++++++--------- src/main/resources/static/js/search.js | 117 +- src/main/resources/static/js/settings.js | 57 +- src/main/resources/static/js/tab-container.js | 61 +- .../resources/static/pdfjs/css/viewer.css | 503 +++++--- src/main/resources/templates/about.html | 33 +- src/main/resources/templates/account.html | 594 +++++---- src/main/resources/templates/addUsers.html | 140 ++- .../resources/templates/auto-split-pdf.html | 69 +- .../resources/templates/change-creds.html | 153 ++- .../templates/convert/book-to-pdf.html | 44 +- .../templates/convert/file-to-pdf.html | 55 +- .../templates/convert/html-to-pdf.html | 53 +- .../templates/convert/img-to-pdf.html | 152 ++- .../templates/convert/markdown-to-pdf.html | 45 +- .../templates/convert/pdf-to-book.html | 96 +- .../templates/convert/pdf-to-csv.html | 284 +++-- .../templates/convert/pdf-to-html.html | 43 +- .../templates/convert/pdf-to-img.html | 101 +- .../templates/convert/pdf-to-pdfa.html | 47 +- .../convert/pdf-to-presentation.html | 58 +- .../templates/convert/pdf-to-text.html | 59 +- .../templates/convert/pdf-to-word.html | 58 +- .../templates/convert/pdf-to-xml.html | 43 +- .../templates/convert/url-to-pdf.html | 43 +- src/main/resources/templates/crop.html | 270 ++--- src/main/resources/templates/error.html | 148 +-- .../resources/templates/extract-page.html | 50 +- .../resources/templates/fragments/card.html | 24 +- .../resources/templates/fragments/common.html | 241 ++-- .../templates/fragments/errorBanner.html | 28 +- .../fragments/errorBannerPerPage.html | 101 +- .../resources/templates/fragments/footer.html | 69 +- .../templates/fragments/languages.html | 131 +- .../resources/templates/fragments/navbar.html | 502 ++++---- .../templates/fragments/navbarEntry.html | 12 +- src/main/resources/templates/home.html | 171 ++- src/main/resources/templates/licenses.html | 90 +- src/main/resources/templates/login.html | 448 +++---- src/main/resources/templates/merge-pdfs.html | 63 +- .../resources/templates/misc/add-image.html | 227 ++-- .../templates/misc/add-page-numbers.html | 269 ++--- .../templates/misc/adjust-contrast.html | 439 ++++--- .../resources/templates/misc/auto-crop.html | 45 +- .../resources/templates/misc/auto-rename.html | 43 +- .../templates/misc/change-metadata.html | 472 ++++---- .../resources/templates/misc/compare.html | 363 +++--- .../templates/misc/compress-pdf.html | 78 +- .../templates/misc/extract-image-scans.html | 91 +- .../templates/misc/extract-images.html | 49 +- .../resources/templates/misc/flatten.html | 94 +- .../resources/templates/misc/ocr-pdf.html | 477 ++++---- .../templates/misc/remove-annotations.html | 81 +- .../templates/misc/remove-blanks.html | 61 +- src/main/resources/templates/misc/repair.html | 42 +- .../templates/misc/show-javascript.html | 171 ++- src/main/resources/templates/misc/stamp.html | 361 +++--- .../templates/multi-page-layout.html | 68 +- src/main/resources/templates/multi-tool.html | 305 ++--- src/main/resources/templates/overlay-pdf.html | 178 ++- .../resources/templates/pdf-organizer.html | 95 +- .../templates/pdf-to-single-page.html | 41 +- src/main/resources/templates/pipeline.html | 369 +++--- .../resources/templates/remove-pages.html | 59 +- src/main/resources/templates/rotate-pdf.html | 184 ++- src/main/resources/templates/scale-pages.html | 76 +- .../templates/security/add-password.html | 155 ++- .../templates/security/add-watermark.html | 268 ++--- .../templates/security/auto-redact.html | 137 ++- .../templates/security/cert-sign.html | 199 ++- .../security/change-permissions.html | 124 +- .../templates/security/get-info-on-pdf.html | 283 +++-- .../templates/security/remove-password.html | 58 +- .../templates/security/remove-watermark.html | 56 +- .../templates/security/sanitize-pdf.html | 89 +- src/main/resources/templates/sign.html | 561 ++++----- .../templates/split-by-size-or-count.html | 65 +- .../templates/split-pdf-by-sections.html | 148 +-- src/main/resources/templates/split-pdfs.html | 65 +- 124 files changed, 9025 insertions(+), 9424 deletions(-) create mode 100644 src/main/resources/static/css/account.css create mode 100644 src/main/resources/static/css/add-image.css create mode 100644 src/main/resources/static/css/error.css create mode 100644 src/main/resources/static/css/footer.css create mode 100644 src/main/resources/static/css/licenses.css create mode 100644 src/main/resources/static/css/login.css create mode 100644 src/main/resources/static/css/multi-tool.css create mode 100644 src/main/resources/static/css/pipeline.css create mode 100644 src/main/resources/static/css/rotate-pdf.css create mode 100644 src/main/resources/static/css/sign.css create mode 100644 src/main/resources/static/css/split-pdf-by-sections.css create mode 100644 src/main/resources/static/css/stamp.css diff --git a/src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java b/src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java index 614dd8a0..a5b3d79e 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java @@ -33,6 +33,8 @@ public class AccountWebController { return "redirect:/"; } + model.addAttribute("currentPage", "login"); + if (request.getParameter("error") != null) { model.addAttribute("error", request.getParameter("error")); @@ -112,6 +114,7 @@ public class AccountWebController { model.addAttribute("role", user.get().getRolesAsString()); model.addAttribute("settings", settingsJson); model.addAttribute("changeCredsFlag", user.get().isFirstLogin()); + model.addAttribute("currentPage", "account"); } } else { return "redirect:/"; diff --git a/src/main/resources/static/css/account.css b/src/main/resources/static/css/account.css new file mode 100644 index 00000000..957fcd9f --- /dev/null +++ b/src/main/resources/static/css/account.css @@ -0,0 +1,4 @@ +.buttons-container { + margin-top: 20px; + text-align: center; +} diff --git a/src/main/resources/static/css/add-image.css b/src/main/resources/static/css/add-image.css new file mode 100644 index 00000000..5a735b42 --- /dev/null +++ b/src/main/resources/static/css/add-image.css @@ -0,0 +1,28 @@ +#box-drag-container { + position: relative; + margin: 20px 0; +} +#pdf-canvas { + box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384); + width: 100%; +} +.draggable-buttons-box { + position: absolute; + top: 0; + padding: 10px; + width: 100%; + display: flex; + gap: 5px; +} +.draggable-buttons-box > button { + z-index: 10; + background-color: rgba(13, 110, 253, 0.1); +} +.draggable-canvas { + border: 1px solid red; + position: absolute; + touch-action: none; + user-select: none; + top: 0px; + left: 0; +} diff --git a/src/main/resources/static/css/dark-mode.css b/src/main/resources/static/css/dark-mode.css index 6f914fc3..8ddbf052 100644 --- a/src/main/resources/static/css/dark-mode.css +++ b/src/main/resources/static/css/dark-mode.css @@ -1,9 +1,11 @@ /* Dark Mode Styles */ -body, select, textarea { - --body-background-color: 51, 51, 51; - --base-font-color: 255, 255, 255; - background-color: rgb(var(--body-background-color)) !important; - color: rgb(var(--base-font-color)) !important; +body, +select, +textarea { + --body-background-color: 51, 51, 51; + --base-font-color: 255, 255, 255; + background-color: rgb(var(--body-background-color)) !important; + color: rgb(var(--base-font-color)) !important; } .card { background-color: rgb(var(--body-background-color)) !important; @@ -11,11 +13,11 @@ body, select, textarea { color: rgb(var(--base-font-color)) !important; } - a { - color: #add8e6; - } - a:hover { - color: #87ceeb; /* Slightly brighter blue on hover for accessibility */ +a { + color: #add8e6; +} +a:hover { + color: #87ceeb; /* Slightly brighter blue on hover for accessibility */ } .dark-card { @@ -36,7 +38,7 @@ body, select, textarea { color: rgb(var(--base-font-color)) !important; } #support-section { - background-color: #444 !important; + background-color: #444 !important; } #pages-container-wrapper { @@ -47,89 +49,93 @@ body, select, textarea { } .favorite-icon img { - filter: brightness(0) invert(1) !important; + filter: brightness(0) invert(1) !important; } table thead { - background-color: #333 !important; - border: 1px solid #444; + background-color: #333 !important; + border: 1px solid #444; } -table th, table td { - border: 1px solid #444 !important; - color: white; +table th, +table td { + border: 1px solid #444 !important; + color: white; } .btn { - background-color: #444 !important; - border: none; - color: #fff !important; + background-color: #444 !important; + border: none; + color: #fff !important; } .btn-primary { - background-color: #007bff !important; - border: none; - color: #fff !important; + background-color: #007bff !important; + border: none; + color: #fff !important; } .btn-secondary { - background-color: #6c757d !important; - border: none; - color: #fff !important; + background-color: #6c757d !important; + border: none; + color: #fff !important; } .btn-info { - background-color: #17a2b8 !important; - border: none; - color: #fff !important; + background-color: #17a2b8 !important; + border: none; + color: #fff !important; } .btn-danger { - background-color: #dc3545 !important; - border: none; - color: #fff !important; + background-color: #dc3545 !important; + border: none; + color: #fff !important; } .btn-warning { - background-color: #ffc107 !important; - border: none; - color: #000 !important; + background-color: #ffc107 !important; + border: none; + color: #000 !important; } .btn-outline-secondary { - color: #fff !important; - border-color: #fff; + color: #fff !important; + border-color: #fff; } .btn-outline-secondary:hover { - background-color: #444 !important; - color: #007bff !important; - border-color: #007bff; + background-color: #444 !important; + color: #007bff !important; + border-color: #007bff; } .blackwhite-icon { - filter: brightness(0) invert(1); + filter: brightness(0) invert(1); } hr { - border-color: rgba(255, 255, 255, 0.6); /* semi-transparent white */ - background-color: rgba(255, 255, 255, 0.6); /* for some browsers that might use background instead of border for
*/ + border-color: rgba(255, 255, 255, 0.6); /* semi-transparent white */ + background-color: rgba(255, 255, 255, 0.6); /* for some browsers that might use background instead of border for
*/ } .modal-content { - color: #fff !important; - border-color: #fff; + color: #fff !important; + border-color: #fff; } #global-buttons-container input { - background-color: #323948; - caret-color: #ffffff; - color: #ffffff; + background-color: #323948; + caret-color: #ffffff; + color: #ffffff; } #global-buttons-container input::placeholder { - color: #ffffff; + color: #ffffff; } -#global-buttons-container input:disabled::-webkit-input-placeholder { /* WebKit browsers */ - color: #6E6865; +#global-buttons-container input:disabled::-webkit-input-placeholder { + /* WebKit browsers */ + color: #6e6865; } -#global-buttons-container input:disabled:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ - color: #6E6865; +#global-buttons-container input:disabled:-moz-placeholder { + /* Mozilla Firefox 4 to 18 */ + color: #6e6865; } -#global-buttons-container input:disabled::-moz-placeholder { /* Mozilla Firefox 19+ */ - color: #6E6865; +#global-buttons-container input:disabled::-moz-placeholder { + /* Mozilla Firefox 19+ */ + color: #6e6865; } -#global-buttons-container input:disabled:-ms-input-placeholder { /* Internet Explorer 10+ */ - color: #6E6865; +#global-buttons-container input:disabled:-ms-input-placeholder { + /* Internet Explorer 10+ */ + color: #6e6865; } - diff --git a/src/main/resources/static/css/dragdrop.css b/src/main/resources/static/css/dragdrop.css index e75a0d06..14c3befe 100644 --- a/src/main/resources/static/css/dragdrop.css +++ b/src/main/resources/static/css/dragdrop.css @@ -1,78 +1,78 @@ #drag-container { - position: fixed; - display:flex; - inset: 0; - pointer-events: none; - z-index: 10000; - visibility: hidden; + position: fixed; + display: flex; + inset: 0; + pointer-events: none; + z-index: 10000; + visibility: hidden; } #drag-container:not(:empty) { - visibility: visible; + visibility: visible; } #drag-container .dragged-img { - position: fixed; - max-width: 200px; - max-height: 200px; - box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.58); - transform-origin: top left; + position: fixed; + max-width: 200px; + max-height: 200px; + box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.58); + transform-origin: top left; } .drag-manager_dragging { - width: 0px; - visibility: hidden; + width: 0px; + visibility: hidden; } .drag-manager_draghover { - width: 375px !important; + width: 375px !important; } .drag-manager_draghover .insert-file-button-container { - display: none !important; + display: none !important; } .drag-manager_draghover .button-container { - visibility: hidden !important; + visibility: hidden !important; } -html[lang-direction=ltr] .drag-manager_draghover img { - left: calc(50% + 62.5px) !important; +html[lang-direction="ltr"] .drag-manager_draghover img { + left: calc(50% + 62.5px) !important; } -html[lang-direction=rtl] .drag-manager_draghover img { - left: 125px +html[lang-direction="rtl"] .drag-manager_draghover img { + left: 125px; } .drag-manager_dragging-container .hide-on-drag { - display: none !important; + display: none !important; } .drag-manager_endpoint { - width: 80px; - height: 100%; - background-color: #FFFFFF10; - transition: width 0.1s; - animation: end-drop-expand .3s ease; - display: flex; - align-items: center; - justify-content: center; + width: 80px; + height: 100%; + background-color: #ffffff10; + transition: width 0.1s; + animation: end-drop-expand 0.3s ease; + display: flex; + align-items: center; + justify-content: center; } .drag-manager_endpoint svg { - width: 50px; - height: 50px; + width: 50px; + height: 50px; } .drag-manager_endpoint.drag-manager_draghover { - width: 150px !important; + width: 150px !important; } @keyframes end-drop-expand { - from { - width: 0; - } - to { - width: 80px; - } -} \ No newline at end of file + from { + width: 0; + } + to { + width: 80px; + } +} diff --git a/src/main/resources/static/css/error.css b/src/main/resources/static/css/error.css new file mode 100644 index 00000000..0477d7e0 --- /dev/null +++ b/src/main/resources/static/css/error.css @@ -0,0 +1,88 @@ +h1 { + text-align: center; + margin-top: 10%; +} + +p { + text-align: center; + margin-top: 2em; +} + +.button:hover { + background-color: #005b7f; +} + +.features-container { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr)); + gap: 25px 30px; +} + +.feature-card { + border: 1px solid rgba(0, 0, 0, 0.125); + border-radius: 0.25rem; + padding: 1.25rem; + display: flex; + flex-direction: column; + align-items: flex-start; +} + +.feature-card .card-text { + flex: 1; +} + +#support-section { + background-color: #f9f9f9; + padding: 4rem; + margin-top: 1rem; + text-align: center; +} + +#support-section h1 { + margin-top: 0; +} + +#support-section p { + margin-top: 0; +} + +#button-group { + display: flex; + justify-content: center; + flex-wrap: wrap; +} + +#github-button, +#discord-button { + display: inline-block; + padding: 1rem 2rem; + margin: 1rem; + background-color: #008cba; + color: #fff; + font-size: 1.2rem; + text-align: center; + text-decoration: none; + border-radius: 3rem; + transition: all 0.3s ease-in-out; +} + +#github-button:hover, +#discord-button:hover, +#home-button:hover { + background-color: #005b7f; +} + +#home-button { + display: block; + width: 200px; + height: 50px; + margin: 2em auto; + background-color: #008cba; + color: white; + text-align: center; + line-height: 50px; + text-decoration: none; + font-weight: bold; + border-radius: 25px; + transition: all 0.3s ease-in-out; +} diff --git a/src/main/resources/static/css/errorBanner.css b/src/main/resources/static/css/errorBanner.css index 69a940b3..11b111ab 100644 --- a/src/main/resources/static/css/errorBanner.css +++ b/src/main/resources/static/css/errorBanner.css @@ -1,94 +1,97 @@ #errorContainer { - margin: 20px; /* adjust this value as needed */ + margin: 20px; /* adjust this value as needed */ } #helpModalDialog { - width: 90%; - max-width: 800px; + width: 90%; + max-width: 800px; } #helpModal h1 { - text-align: center; - margin-top: 10%; + text-align: center; + margin-top: 10%; } #helpModal p { - text-align: center; - margin-top: 2em; + text-align: center; + margin-top: 2em; } #helpModal .button:hover { - background-color: #005b7f; + background-color: #005b7f; } #helpModal .features-container { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr)); - gap: 25px 30px; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr)); + gap: 25px 30px; } #helpModal .feature-card { - border: 1px solid rgba(0, 0, 0, .125); - border-radius: 0.25rem; - padding: 1.25rem; - display: flex; - flex-direction: column; - align-items: flex-start; + border: 1px solid rgba(0, 0, 0, 0.125); + border-radius: 0.25rem; + padding: 1.25rem; + display: flex; + flex-direction: column; + align-items: flex-start; } #helpModal .feature-card .card-text { - flex: 1; + flex: 1; } #support-section { - background-color: #f9f9f9; - padding: 4rem; - margin-top: 1rem; - text-align: center; + background-color: #f9f9f9; + padding: 4rem; + margin-top: 1rem; + text-align: center; } #support-section h1 { - margin-top: 0; + margin-top: 0; } #support-section p { - margin-top: 0; + margin-top: 0; } #button-group { - display: flex; - justify-content: center; - flex-wrap: wrap; + display: flex; + justify-content: center; + flex-wrap: wrap; } -#github-button, #discord-button { - display: inline-block; - padding: 1rem 2rem; - margin: 1rem; - background-color: #008CBA; - color: #fff; - font-size: 1.2rem; - text-align: center; - text-decoration: none; - border-radius: 3rem; - transition: all 0.3s ease-in-out; +#github-button, +#discord-button { + display: inline-block; + padding: 1rem 2rem; + margin: 1rem; + background-color: #008cba; + color: #fff; + font-size: 1.2rem; + text-align: center; + text-decoration: none; + border-radius: 3rem; + transition: all 0.3s ease-in-out; } -#github-button:hover, #discord-button:hover, #home-button:hover { - background-color: #005b7f; +#github-button:hover, +#discord-button:hover, +#home-button:hover { + background-color: #005b7f; } #home-button { - display: block; - width: 200px; - height: 50px; - margin: 2em auto; - background-color: #008CBA; - color: white; - text-align: center; - line-height: 50px; - text-decoration: none; - font-weight: bold; - border-radius: 25px; - transition: all 0.3s ease-in-out; -} \ No newline at end of file + display: block; + width: 200px; + height: 50px; + margin: 2em auto; + background-color: #008cba; + color: white; + text-align: center; + line-height: 50px; + text-decoration: none; + font-weight: bold; + border-radius: 25px; + transition: all 0.3s ease-in-out; +} diff --git a/src/main/resources/static/css/fileSelect.css b/src/main/resources/static/css/fileSelect.css index 2cd2c682..e8f12979 100644 --- a/src/main/resources/static/css/fileSelect.css +++ b/src/main/resources/static/css/fileSelect.css @@ -1,10 +1,10 @@ .custom-file-label { - padding-right: 90px; + padding-right: 90px; } .selected-files { - margin-top: 10px; - max-height: 150px; - overflow-y: auto; - white-space: pre-wrap; -} \ No newline at end of file + margin-top: 10px; + max-height: 150px; + overflow-y: auto; + white-space: pre-wrap; +} diff --git a/src/main/resources/static/css/footer.css b/src/main/resources/static/css/footer.css new file mode 100644 index 00000000..f6cf093d --- /dev/null +++ b/src/main/resources/static/css/footer.css @@ -0,0 +1,20 @@ +#footer { + display: flex; + flex-direction: column; /* Stack children vertically */ + justify-content: center; + align-items: center; + width: 100%; +} + +.footer-center { + display: flex; + align-items: center; /* Center children horizontally */ + flex-grow: 1; +} + +.footer-powered-by { + margin-top: auto; /* Pushes the text to the bottom */ + color: grey; + text-align: center; /* Centers the text inside the div */ + width: 100%; /* Full width to center the text properly */ +} diff --git a/src/main/resources/static/css/game.css b/src/main/resources/static/css/game.css index 01b93e94..5b9f27d2 100644 --- a/src/main/resources/static/css/game.css +++ b/src/main/resources/static/css/game.css @@ -1,49 +1,54 @@ #game-container { - position: relative; - width: 100vh; - height: 0; - padding-bottom: 75%; /* 4:3 aspect ratio */ - background-color: transparent; - margin: auto; - overflow: hidden; - border: 2px solid black; /* Add border */ + position: relative; + width: 100vh; + height: 0; + padding-bottom: 75%; /* 4:3 aspect ratio */ + background-color: transparent; + margin: auto; + overflow: hidden; + border: 2px solid black; /* Add border */ } -.pdf, .player, .projectile { - position: absolute; +.pdf, +.player, +.projectile { + position: absolute; } .pdf { - width: 50px; - height: 50px; + width: 50px; + height: 50px; } .player { - width: 50px; - height: 50px; + width: 50px; + height: 50px; } .projectile { - background-color: black !important; - width: 5px; - height: 10px; + background-color: black !important; + width: 5px; + height: 10px; } -#score, #level, #lives, #high-score { - color: black; - font-family: sans-serif; - position: absolute; - font-size: calc(14px + 0.25vw); /* Reduced font size */ +#score, +#level, +#lives, +#high-score { + color: black; + font-family: sans-serif; + position: absolute; + font-size: calc(14px + 0.25vw); /* Reduced font size */ } #score { - top: 10px; - left: 10px; + top: 10px; + left: 10px; } #lives { - top: 10px; - left: calc(7vw); /* Adjusted position */ + top: 10px; + left: calc(7vw); /* Adjusted position */ } #high-score { - top: 10px; - left: calc(14vw); /* Adjusted position */ + top: 10px; + left: calc(14vw); /* Adjusted position */ } #level { - top: 10px; - right: 10px; -} \ No newline at end of file + top: 10px; + right: 10px; +} diff --git a/src/main/resources/static/css/general.css b/src/main/resources/static/css/general.css index 934074ca..8d631bfd 100644 --- a/src/main/resources/static/css/general.css +++ b/src/main/resources/static/css/general.css @@ -1,20 +1,20 @@ #page-container { - min-height: 100vh; - display: flex; - flex-direction: column; + min-height: 100vh; + display: flex; + flex-direction: column; } #content-wrap { - flex: 1; + flex: 1; } #footer { - bottom: 0; - width: 100%; + bottom: 0; + width: 100%; } .navbar { - height: auto; /* Adjusts height automatically based on content */ - white-space: nowrap; /* Prevents wrapping of navbar contents */ + height: auto; /* Adjusts height automatically based on content */ + white-space: nowrap; /* Prevents wrapping of navbar contents */ } /* TODO enable later .navbar .container { @@ -25,70 +25,70 @@ margin-right: auto; }*/ -html[lang-direction=ltr] * { - direction: ltr; +html[lang-direction="ltr"] * { + direction: ltr; } -html[lang-direction=rtl] * { - direction: rtl; - text-align: right; +html[lang-direction="rtl"] * { + direction: rtl; + text-align: right; } .ignore-rtl { - direction: ltr !important; - text-align: left !important; + direction: ltr !important; + text-align: left !important; } .align-top { - position: absolute; - top: 0; + position: absolute; + top: 0; } .align-center-right { - position: absolute; - right: 0; - top: 50%; + position: absolute; + right: 0; + top: 50%; } .align-center-left { - position: absolute; - left: 0; - top: 50%; + position: absolute; + left: 0; + top: 50%; } .align-bottom { - position: absolute; - bottom: 0; + position: absolute; + bottom: 0; } .btn-group > label:first-of-type { - border-top-left-radius: 0.25rem !important; - border-bottom-left-radius: 0.25rem !important; + border-top-left-radius: 0.25rem !important; + border-bottom-left-radius: 0.25rem !important; } html[lang-direction="rtl"] input.form-check-input { - position: relative; - margin-left: 0px; + position: relative; + margin-left: 0px; } html[lang-direction="rtl"] label.form-check-label { - display: inline; + display: inline; } .margin-auto-parent { - width: 100%; - display: flex; + width: 100%; + display: flex; } .margin-center { - margin: 0 auto; + margin: 0 auto; } #pdf-canvas { - box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384); - width: 100%; + box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384); + width: 100%; } .fixed-shadow-canvas { - box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384); - width: 100%; + box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384); + width: 100%; } .shadow-canvas { - box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384); + box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384); } .hidden { - display: none; -} \ No newline at end of file + display: none; +} diff --git a/src/main/resources/static/css/home.css b/src/main/resources/static/css/home.css index fe184637..d975dd79 100644 --- a/src/main/resources/static/css/home.css +++ b/src/main/resources/static/css/home.css @@ -1,64 +1,62 @@ #searchBar { - background-image: url('../images/search.svg'); - background-position: 16px 16px; - background-repeat: no-repeat; - width: 100%; - font-size: 16px; - margin-bottom: 12px; - padding: 12px 20px 12px 40px; - border: 1px solid #ddd; - - + background-image: url("../images/search.svg"); + background-position: 16px 16px; + background-repeat: no-repeat; + width: 100%; + font-size: 16px; + margin-bottom: 12px; + padding: 12px 20px 12px 40px; + border: 1px solid #ddd; } .dark-mode-search { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' hei… 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z'/%3E%3C/svg%3E") !important; - color: #f8f9fa !important; - background-color: #212529 !important; - border-color: #343a40 !important; - } - - + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' hei… 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z'/%3E%3C/svg%3E") !important; + color: #f8f9fa !important; + background-color: #212529 !important; + border-color: #343a40 !important; +} .features-container { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(15rem, 3fr)); - gap: 25px 30px; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(15rem, 3fr)); + gap: 25px 30px; } .feature-card { - border: 2px solid rgba(0, 0, 0, .25); - border-radius: 0.25rem; - padding: 1.25rem; - display: flex; - flex-direction: column; - align-items: flex-start; - background: rgba(13, 110, 253, 0.05); - transition: transform 0.3s, border 0.3s; - transform-origin: center center; - outline: 2px solid transparent; + border: 2px solid rgba(0, 0, 0, 0.25); + border-radius: 0.25rem; + padding: 1.25rem; + display: flex; + flex-direction: column; + align-items: flex-start; + background: rgba(13, 110, 253, 0.05); + transition: + transform 0.3s, + border 0.3s; + transform-origin: center center; + outline: 2px solid transparent; } .feature-card a { - text-decoration: none; - color: inherit; - display: flex; - flex-direction: column; - width: 100%; - height: 100%; + text-decoration: none; + color: inherit; + display: flex; + flex-direction: column; + width: 100%; + height: 100%; } .feature-card .card-text { - flex: 1; + flex: 1; } .feature-card:hover { - outline: 1px solid rgba(0, 0, 0, .5); - cursor: pointer; - transform: scale(1.1); + outline: 1px solid rgba(0, 0, 0, 0.5); + cursor: pointer; + transform: scale(1.1); } .feature-card:hover .card-title { - text-decoration: underline; + text-decoration: underline; } .card-title.text-primary { color: #000; /* Replace with your desired shade of blue */ @@ -67,27 +65,27 @@ .home-card-icon { width: 30px; height: 30px; - transform: translateY(-5px); + transform: translateY(-5px); } .home-card-icon-colour { -filter: invert(0.2) sepia(2) saturate(50) hue-rotate(190deg); + filter: invert(0.2) sepia(2) saturate(50) hue-rotate(190deg); } .favorite-icon { - display: none; - position: absolute; - top: 10px; - right: 10px; + display: none; + position: absolute; + top: 10px; + right: 10px; } /* Only show the favorite icons when the parent card is being hovered over */ .feature-card:hover .favorite-icon { - display: block; + display: block; } .favorite-icon img { - filter: brightness(0); + filter: brightness(0); } .jumbotron { - padding: 3rem 3rem; /* Reduce vertical padding */ + padding: 3rem 3rem; /* Reduce vertical padding */ } diff --git a/src/main/resources/static/css/imageHighlighter.css b/src/main/resources/static/css/imageHighlighter.css index 231895d6..397c0c54 100644 --- a/src/main/resources/static/css/imageHighlighter.css +++ b/src/main/resources/static/css/imageHighlighter.css @@ -1,40 +1,43 @@ - #image-highlighter { - position: fixed; - display:flex; - inset: 0; - z-index: 10000; - background-color: rgba(0, 0, 0, 0); - visibility: hidden; - align-items: center; - justify-content: center; - transition: visbility 0.1s linear, background-color 0.1s linear; + position: fixed; + display: flex; + inset: 0; + z-index: 10000; + background-color: rgba(0, 0, 0, 0); + visibility: hidden; + align-items: center; + justify-content: center; + transition: + visbility 0.1s linear, + background-color 0.1s linear; } #image-highlighter > * { - max-width: 80vw; - max-height: 80vh; - animation: image-highlight .1s linear; - transition: transform .1s linear, opacity .1s linear; + max-width: 80vw; + max-height: 80vh; + animation: image-highlight 0.1s linear; + transition: + transform 0.1s linear, + opacity 0.1s linear; } #image-highlighter > *.remove { - transform: scale(0.8) !important; - opacity: 0 !important; + transform: scale(0.8) !important; + opacity: 0 !important; } #image-highlighter:not(:empty) { - background-color: rgba(0, 0, 0, 0.37); - visibility: visible; + background-color: rgba(0, 0, 0, 0.37); + visibility: visible; } @keyframes image-highlight { - from { - transform: scale(0.8); - opacity: 0; - } - to { - transform: scale(1); - opacity: 1; - } -} \ No newline at end of file + from { + transform: scale(0.8); + opacity: 0; + } + to { + transform: scale(1); + opacity: 1; + } +} diff --git a/src/main/resources/static/css/licenses.css b/src/main/resources/static/css/licenses.css new file mode 100644 index 00000000..79abdc34 --- /dev/null +++ b/src/main/resources/static/css/licenses.css @@ -0,0 +1,9 @@ +td a { + text-decoration: none; +} + +td a:hover, +td a:focus { + text-decoration: underline; + /* Adds underline on hover/focus for clarity */ +} diff --git a/src/main/resources/static/css/light-mode.css b/src/main/resources/static/css/light-mode.css index 08efbf4c..af84b0d5 100644 --- a/src/main/resources/static/css/light-mode.css +++ b/src/main/resources/static/css/light-mode.css @@ -1,14 +1,13 @@ /* Dark Mode Styles */ body { - --body-background-color: 255, 255, 255; - --base-font-color: 33, 37, 41; + --body-background-color: 255, 255, 255; + --base-font-color: 33, 37, 41; } - #global-buttons-container input { - background-color: #ffffff; - /*caret-color: #ffffff;*/ - /*color: #ffffff;*/ + background-color: #ffffff; + /*caret-color: #ffffff;*/ + /*color: #ffffff;*/ } /*#global-buttons-container input:disabled::-webkit-input-placeholder { !* WebKit browsers *!*/ /* color: #98A0AB;*/ diff --git a/src/main/resources/static/css/login.css b/src/main/resources/static/css/login.css new file mode 100644 index 00000000..743ee606 --- /dev/null +++ b/src/main/resources/static/css/login.css @@ -0,0 +1,111 @@ +html, +body { + height: 100%; +} + +body { + display: flex; + align-items: center; + padding-top: 40px; + padding-bottom: 40px; + background-color: #f5f5f5; +} + +.form-signin { + width: 100%; + max-width: 330px; + padding: 15px; + margin: auto; +} + +.form-signin .checkbox { + font-weight: 400; +} + +.form-signin .form-floating:focus-within { + z-index: 2; +} + +.form-signin input[type="text"] { + margin-bottom: -1px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.form-signin input[type="password"] { + margin-bottom: 10px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.container-flex { + display: flex; + flex-direction: column; + min-height: 100vh; + width: 100%; /* Set width to 100% */ + align-items: center; /* Center its children horizontally */ +} +.footer-bottom { + margin-top: auto; +} +body.light-mode input:-webkit-autofill, +body.light-mode input:-webkit-autofill:hover, +body.light-mode input:-webkit-autofill:focus, +body.light-mode input:-webkit-autofill:active { + -webkit-text-fill-color: #212529; /* Dark font color */ + -webkit-box-shadow: 0 0 0 1000px #f8f9fa inset; /* Light background color */ +} + +/* Dark Mode */ +body.dark-mode input:-webkit-autofill, +body.dark-mode input:-webkit-autofill:hover, +body.dark-mode input:-webkit-autofill:focus, +body.dark-mode input:-webkit-autofill:active { + -webkit-text-fill-color: #f8f9fa; /* Light font color */ + -webkit-box-shadow: 0 0 0 1000px #212529 inset; /* Dark background color */ +} +/* Light Mode */ +body.light-mode .form-floating > input:focus + label { + color: #212529 !important; /* Dark text for light background */ +} + +/* Dark Mode */ +body.dark-mode .form-floating > input:focus + label { + color: #fff !important; /* Light text for dark background */ +} + +body.light-mode .form-floating > label { + color: #212529 !important; /* Dark text for light background */ +} + +body.dark-mode .form-floating > label { + color: #fff !important; /* Light text for dark background */ +} + +/* Removing default styles for ul and li */ +ul { + list-style: none; + padding: 0; + margin: 0; +} + +li { + list-style: none; +} + +/* Positioning the container of these elements to the top right */ +.your-container-class { + position: absolute; + top: 0; + right: 0; + display: flex; +} + +/* Styling for the dropdown */ +.dropdown-menu { + min-width: 200px; /* or whatever width you prefer */ +} + +.navbar-icon { + width: 40px; + height: 40px; +} diff --git a/src/main/resources/static/css/merge.css b/src/main/resources/static/css/merge.css index 866e2e8c..dc3c7657 100644 --- a/src/main/resources/static/css/merge.css +++ b/src/main/resources/static/css/merge.css @@ -1,4 +1,4 @@ - .list-group-item { +.list-group-item { display: flex; justify-content: space-between; align-items: center; @@ -25,5 +25,4 @@ .move-down span { font-weight: bold; font-size: 1.2em; - } diff --git a/src/main/resources/static/css/multi-tool.css b/src/main/resources/static/css/multi-tool.css new file mode 100644 index 00000000..9ed84f2b --- /dev/null +++ b/src/main/resources/static/css/multi-tool.css @@ -0,0 +1,119 @@ +.multi-tool-container { + max-width: 95vw; + margin: 0 auto; +} + +#global-buttons-container { + display: flex; + gap: 10px; + align-items: start; + + background-color: rgba(13, 110, 253, 0.1); + border: 1px solid rgba(0, 0, 0, 0.25); + backdrop-filter: blur(2px); + + top: 10px; + z-index: 10; + padding: 10px; + border-radius: 8px; +} +#global-buttons-container > * { + padding: 0.6rem 0.75rem; +} + +#global-buttons-container svg { + width: 20px; + height: 20px; +} +#export-button { + margin-left: auto; +} + +#pages-container-wrapper { + --background-color: rgba(0, 0, 0, 0.025); + --scroll-bar-color: #f1f1f1; + --scroll-bar-thumb: #888; + --scroll-bar-thumb-hover: #555; + background-color: var(--background-color); + width: 100%; + display: flex; + flex-direction: column; + padding: 10px 25px; + border-radius: 10px; + overflow-y: hidden; + overflow-x: auto; + min-height: 275px; + margin: 0 0 30px 0; +} + +#pages-container { + margin: auto; + gap: 0px; + display: flex; + align-items: center; + justify-content: center; +} + +/* width */ +#pages-container-wrapper::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +/* Track */ +#pages-container-wrapper::-webkit-scrollbar-track { + background: var(--scroll-bar-color); +} + +/* Handle */ +#pages-container-wrapper::-webkit-scrollbar-thumb { + border-radius: 10px; + background: var(--scroll-bar-thumb); +} + +/* Handle on hover */ +#pages-container-wrapper::-webkit-scrollbar-thumb:hover { + background: var(--scroll-bar-thumb-hover); +} + +.page-container { + height: 250px; + display: flex; + align-items: center; + flex-direction: column-reverse; + aspect-ratio: 1; + text-align: center; + position: relative; + user-select: none; + transition: width 1s linear; +} + +.page-container img { + /* max-width: calc(100% - 15px); */ + max-height: calc(100% - 15px); + max-width: 237px; + display: block; + position: absolute; + left: 50%; + top: 50%; + translate: -50% -50%; + box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384); + border-radius: 4px; + transition: rotate 0.3s; +} + +#add-pdf-button { + margin: 0 auto; +} + +.page-number { + position: absolute; + top: 5px; + right: 5px; + color: white; + background-color: #007bff; /* Primary blue color */ + padding: 3px 6px; + border-radius: 4px; + font-size: 12px; + z-index: 2; +} diff --git a/src/main/resources/static/css/navbar.css b/src/main/resources/static/css/navbar.css index 5bb99a5e..f46c44a6 100644 --- a/src/main/resources/static/css/navbar.css +++ b/src/main/resources/static/css/navbar.css @@ -1,80 +1,116 @@ - - #navbarSearch { - top: 100%; - right: 0; + top: 100%; + right: 0; + transition: all 0.3s; + max-height: 0; + overflow: hidden; +} + +#navbarSearch.show { + max-height: 300px; /* Adjust this to your desired max height */ } #searchForm { - width: 200px; /* Adjust this value as needed */ + width: 200px; /* Adjust this value as needed */ } /* Style the search results to match the navbar */ #searchResults { - max-height: 200px; /* Adjust this value as needed */ - overflow-y: auto; - width: 100%; + max-height: 200px; /* Adjust this value as needed */ + overflow-y: auto; + width: 100%; + max-width: 300px; /* Adjust to your preferred width */ + transition: height 0.3s ease; /* Smooth height transition */ } #searchResults .dropdown-item { - display: flex; - align-items: center; - white-space: nowrap; - height: 50px; /* Fixed height */ - overflow: hidden; /* Hide overflow */ + display: flex; + align-items: center; + white-space: nowrap; + height: 50px; /* Fixed height */ + overflow: hidden; /* Hide overflow */ } #searchResults .icon { - margin-right: 10px; + margin-right: 10px; } #searchResults .icon-text { - display: inline; - overflow: hidden; /* Hide overflow */ - text-overflow: ellipsis; /* Add ellipsis for long text */ + display: inline; + overflow: hidden; /* Hide overflow */ + text-overflow: ellipsis; /* Add ellipsis for long text */ } +#search-icon i { + font-size: 24px; /* Adjust this to your desired size */ + transition: color 0.3s; +} +#search-icon:hover i { + color: #666; /* Adjust this to your hover color */ +} + +.search-input { + transition: + border 0.3s, + box-shadow 0.3s; +} + +.search-input:focus { + border-color: #666; /* Adjust this to your focus color */ + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* Adjust this to your desired shadow */ +} + +/* Set a fixed height and styling for each search result item */ +.search-results a { + display: flex; + align-items: center; + gap: 10px; /* space between icon and text */ + height: 40px; /* Adjust based on your design */ + overflow: hidden; /* Prevent content from overflowing */ + white-space: nowrap; /* Prevent text from wrapping to next line */ + text-overflow: ellipsis; /* Truncate text if it's too long */ +} .main-icon { - width: 36px; - height: 36px; - vertical-align: middle; - transform: translateY(-2px); + width: 36px; + height: 36px; + vertical-align: middle; + transform: translateY(-2px); } .icon { - width: 16px; - height: 16px; - vertical-align: middle; - transform: translateY(-2px); + width: 16px; + height: 16px; + vertical-align: middle; + transform: translateY(-2px); } -.icon+.icon { - margin-left: -4px; +.icon + .icon { + margin-left: -4px; } .icon-text { - margin-left: 4px; + margin-left: 4px; } .nav-item-separator { - position: relative; - margin: 0 4px; /* Adjust the margin as needed */ + position: relative; + margin: 0 4px; /* Adjust the margin as needed */ } .nav-item-separator::before { - content: ''; - position: absolute; - left: 0; - top: 10%; /* Adjust the top and bottom margins as needed */ - bottom: 10%; - width: 1px; - background-color: #ccc; /* Adjust the color as needed */ + content: ""; + position: absolute; + left: 0; + top: 10%; /* Adjust the top and bottom margins as needed */ + bottom: 10%; + width: 1px; + background-color: #ccc; /* Adjust the color as needed */ } .navbar-icon { - width: 20px; - height: 20px; - transform: translateY(-2px); -} \ No newline at end of file + width: 20px; + height: 20px; + transform: translateY(-2px); +} diff --git a/src/main/resources/static/css/pdfActions.css b/src/main/resources/static/css/pdfActions.css index 98c29dbe..ff680036 100644 --- a/src/main/resources/static/css/pdfActions.css +++ b/src/main/resources/static/css/pdfActions.css @@ -1,87 +1,85 @@ - .pdf-actions_button-container { - z-index: 2; - display:flex; - opacity: 0; - transition: opacity 0.1s linear; + z-index: 2; + display: flex; + opacity: 0; + transition: opacity 0.1s linear; } .pdf-actions_container:hover .pdf-actions_button-container { - opacity: 1; + opacity: 1; } .pdf-actions_button-container > * { - padding: 0.25rem 0.5rem; - margin: 3px; - display: block; + padding: 0.25rem 0.5rem; + margin: 3px; + display: block; } .pdf-actions_container svg { - width: 16px; - height: 16px; + width: 16px; + height: 16px; } .pdf-actions_container:nth-child(1) .pdf-actions_move-left-button { - display: none; + display: none; } .pdf-actions_container:last-child .pdf-actions_move-right-button { - display: none; + display: none; } /* "insert pdf" buttons that appear on the right when hover */ .pdf-actions_insert-file-button-container { - translate: 0 -50%; - width: 80px; - height: 100%; + translate: 0 -50%; + width: 80px; + height: 100%; - z-index: 1; - opacity: 0; - transition: opacity 0.2s; + z-index: 1; + opacity: 0; + transition: opacity 0.2s; } .pdf-actions_insert-file-button-container.left { - left: -20px; + left: -20px; } .pdf-actions_insert-file-button-container.right { - right: -20px; + right: -20px; } -html[lang-direction=ltr] .pdf-actions_insert-file-button-container.right { - display:none; +html[lang-direction="ltr"] .pdf-actions_insert-file-button-container.right { + display: none; } -html[lang-direction=rtl] .pdf-actions_insert-file-button-container.left { - display:none; +html[lang-direction="rtl"] .pdf-actions_insert-file-button-container.left { + display: none; } .pdf-actions_insert-file-button-container.left .pdf-actions_insert-file-button { - left: 0; - translate: 0 -50%; + left: 0; + translate: 0 -50%; } .pdf-actions_insert-file-button-container.right .pdf-actions_insert-file-button { - right: 0; - translate: 0 -50%; + right: 0; + translate: 0 -50%; } -html[lang-direction=ltr] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.right { - display: block; +html[lang-direction="ltr"] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.right { + display: block; } - -html[lang-direction=rtl] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.left { - display: block; +html[lang-direction="rtl"] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.left { + display: block; } .pdf-actions_insert-file-button-container:hover { - opacity: 1; - transition: opacity 0.05s; + opacity: 1; + transition: opacity 0.05s; } .pdf-actions_insert-file-button { - position: absolute; - top: 50%; - right: 50%; - translate: 50% -50%; - aspect-ratio: 1; - border-radius: 100px; -} \ No newline at end of file + position: absolute; + top: 50%; + right: 50%; + translate: 50% -50%; + aspect-ratio: 1; + border-radius: 100px; +} diff --git a/src/main/resources/static/css/pipeline.css b/src/main/resources/static/css/pipeline.css new file mode 100644 index 00000000..9468333b --- /dev/null +++ b/src/main/resources/static/css/pipeline.css @@ -0,0 +1,21 @@ +.btn-margin { + margin-right: 2px; +} + +.bordered-box { + border: 1px solid #ddd; + padding: 20px; + margin: 20px; + width: 70%; +} + +.center-element { + width: 80%; + text-align: center; + margin: auto; +} + +.element-margin { + margin: 10px 0; + /* Adjust this value to increase/decrease the margin as needed */ +} diff --git a/src/main/resources/static/css/rainbow-mode.css b/src/main/resources/static/css/rainbow-mode.css index 2c58adf5..921423a5 100644 --- a/src/main/resources/static/css/rainbow-mode.css +++ b/src/main/resources/static/css/rainbow-mode.css @@ -1,37 +1,113 @@ /* Rainbow Mode Styles */ body { - background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%); - color: #fff !important; - --body-background-color: 255, 255, 255; - --base-font-color: 33, 37, 41; + background: linear-gradient( + 90deg, + rgba(255, 0, 0, 1) 0%, + rgba(255, 154, 0, 1) 10%, + rgba(208, 222, 33, 1) 20%, + rgba(79, 220, 74, 1) 30%, + rgba(63, 218, 216, 1) 40%, + rgba(47, 201, 226, 1) 50%, + rgba(28, 127, 238, 1) 60%, + rgba(95, 21, 242, 1) 70%, + rgba(186, 12, 248, 1) 80%, + rgba(251, 7, 217, 1) 90%, + rgba(255, 0, 0, 1) 100% + ); + color: #fff !important; + --body-background-color: 255, 255, 255; + --base-font-color: 33, 37, 41; } .dark-card { - background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important; - color: white !important; + background: linear-gradient( + 90deg, + rgba(255, 0, 0, 1) 0%, + rgba(255, 154, 0, 1) 10%, + rgba(208, 222, 33, 1) 20%, + rgba(79, 220, 74, 1) 30%, + rgba(63, 218, 216, 1) 40%, + rgba(47, 201, 226, 1) 50%, + rgba(28, 127, 238, 1) 60%, + rgba(95, 21, 242, 1) 70%, + rgba(186, 12, 248, 1) 80%, + rgba(251, 7, 217, 1) 90%, + rgba(255, 0, 0, 1) 100% + ) !important; + color: white !important; } .jumbotron { - background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%); - color: #fff !important; + background: linear-gradient( + 90deg, + rgba(255, 0, 0, 1) 0%, + rgba(255, 154, 0, 1) 10%, + rgba(208, 222, 33, 1) 20%, + rgba(79, 220, 74, 1) 30%, + rgba(63, 218, 216, 1) 40%, + rgba(47, 201, 226, 1) 50%, + rgba(28, 127, 238, 1) 60%, + rgba(95, 21, 242, 1) 70%, + rgba(186, 12, 248, 1) 80%, + rgba(251, 7, 217, 1) 90%, + rgba(255, 0, 0, 1) 100% + ); + color: #fff !important; } .list-group { - background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important; - color: fff !important; + background: linear-gradient( + 90deg, + rgba(255, 0, 0, 1) 0%, + rgba(255, 154, 0, 1) 10%, + rgba(208, 222, 33, 1) 20%, + rgba(79, 220, 74, 1) 30%, + rgba(63, 218, 216, 1) 40%, + rgba(47, 201, 226, 1) 50%, + rgba(28, 127, 238, 1) 60%, + rgba(95, 21, 242, 1) 70%, + rgba(186, 12, 248, 1) 80%, + rgba(251, 7, 217, 1) 90%, + rgba(255, 0, 0, 1) 100% + ) !important; + color: fff !important; } .list-group-item { - background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important; - color: fff !important; + background: linear-gradient( + 90deg, + rgba(255, 0, 0, 1) 0%, + rgba(255, 154, 0, 1) 10%, + rgba(208, 222, 33, 1) 20%, + rgba(79, 220, 74, 1) 30%, + rgba(63, 218, 216, 1) 40%, + rgba(47, 201, 226, 1) 50%, + rgba(28, 127, 238, 1) 60%, + rgba(95, 21, 242, 1) 70%, + rgba(186, 12, 248, 1) 80%, + rgba(251, 7, 217, 1) 90%, + rgba(255, 0, 0, 1) 100% + ) !important; + color: fff !important; } #support-section { - background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important; + background: linear-gradient( + 90deg, + rgba(255, 0, 0, 1) 0%, + rgba(255, 154, 0, 1) 10%, + rgba(208, 222, 33, 1) 20%, + rgba(79, 220, 74, 1) 30%, + rgba(63, 218, 216, 1) 40%, + rgba(47, 201, 226, 1) 50%, + rgba(28, 127, 238, 1) 60%, + rgba(95, 21, 242, 1) 70%, + rgba(186, 12, 248, 1) 80%, + rgba(251, 7, 217, 1) 90%, + rgba(255, 0, 0, 1) 100% + ) !important; } - #pages-container-wrapper { --background-color: rgba(255, 255, 255, 0.046) !important; --scroll-bar-color: #4c4c4c !important; --scroll-bar-thumb: #d3d3d3 !important; --scroll-bar-thumb-hover: #ffffff !important; } - diff --git a/src/main/resources/static/css/rotate-pdf.css b/src/main/resources/static/css/rotate-pdf.css new file mode 100644 index 00000000..7c5d388d --- /dev/null +++ b/src/main/resources/static/css/rotate-pdf.css @@ -0,0 +1,29 @@ +#pdf-preview { + margin: 0 auto; + display: block; + max-width: calc(100% - 30px); + max-height: calc(100% - 30px); + box-shadow: 0 0 4px rgba(100, 100, 100, 0.25); + transition: rotate 0.3s; + position: absolute; + top: 50%; + left: 50%; + translate: -50% -50%; +} + +.previewContainer { + aspect-ratio: 1; + width: 100%; + border: 1px solid rgba(0, 0, 0, 0.125); + border-radius: 0.25rem; + margin: 1rem 0; + padding: 15px; + display: block; + overflow: hidden; + position: relative; +} + +.buttonContainer { + display: flex; + justify-content: space-around; +} diff --git a/src/main/resources/static/css/sign.css b/src/main/resources/static/css/sign.css new file mode 100644 index 00000000..c6ae3374 --- /dev/null +++ b/src/main/resources/static/css/sign.css @@ -0,0 +1,39 @@ +select#font-select, +select#font-select option { + height: 60px; /* Adjust as needed */ + font-size: 30px; /* Adjust as needed */ +} + +.drawing-pad-container { + text-align: center; +} + +#drawing-pad-canvas { + background: rgba(125, 125, 125, 0.2); + width: 100%; + height: 300px; +} +#box-drag-container { + position: relative; + margin: 20px 0; +} +.draggable-buttons-box { + position: absolute; + top: 0; + padding: 10px; + width: 100%; + display: flex; + gap: 5px; +} +.draggable-buttons-box > button { + z-index: 10; + background-color: rgba(13, 110, 253, 0.1); +} +.draggable-canvas { + border: 1px solid red; + position: absolute; + touch-action: none; + user-select: none; + top: 0px; + left: 0; +} diff --git a/src/main/resources/static/css/split-pdf-by-sections.css b/src/main/resources/static/css/split-pdf-by-sections.css new file mode 100644 index 00000000..7520c10e --- /dev/null +++ b/src/main/resources/static/css/split-pdf-by-sections.css @@ -0,0 +1,10 @@ +.pdf-visual-aid { + width: 150px; /* Adjust as needed */ + height: 200px; /* Adjust as needed */ + border: 1px solid black; /* Represents the PDF page */ + position: relative; +} +.line { + position: absolute; + background-color: red; /* Line color */ +} diff --git a/src/main/resources/static/css/stamp.css b/src/main/resources/static/css/stamp.css new file mode 100644 index 00000000..9fed6178 --- /dev/null +++ b/src/main/resources/static/css/stamp.css @@ -0,0 +1,41 @@ +.a4container { + position: relative; + width: 50%; + aspect-ratio: 0.707; + border: 1px solid #ddd; + box-sizing: border-box; + background-color: white; +} + +.pageNumber { + position: absolute; + display: flex; + justify-content: center; + align-items: center; + font-size: 1em; + color: #333; + cursor: pointer; + background-color: #ccc; + width: 15%; + height: 15%; + transform: translate(-50%, -50%); +} + +.pageNumber:hover { + background-color: #eee; +} + +#myForm { + display: flex; + justify-content: center; + align-items: center; + margin-top: 20px; +} + +.selectedPosition { + background-color: #0a0; +} + +.selectedPosition.selectedHovered { + background-color: #006600; +} diff --git a/src/main/resources/static/css/tab-container.css b/src/main/resources/static/css/tab-container.css index f6609de4..cf048650 100644 --- a/src/main/resources/static/css/tab-container.css +++ b/src/main/resources/static/css/tab-container.css @@ -1,26 +1,24 @@ - .tab-group { - } .tab-container { - display: none; + display: none; } .tab-container.active { - display: block; - border: 1px solid rgba(var(--base-font-color), 0.25); - padding: 15px; + display: block; + border: 1px solid rgba(var(--base-font-color), 0.25); + padding: 15px; } .tab-buttons > button { - margin-bottom: -1px; - background: 0 0; - border: 1px solid transparent; - color: rgb(var(--base-font-color)); + margin-bottom: -1px; + background: 0 0; + border: 1px solid transparent; + color: rgb(var(--base-font-color)); - border-top-left-radius: 0.25rem; - border-top-right-radius: 0.25rem; + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; } .tab-buttons > button.active { - background-color: rgb(var(--body-background-color)); - border-color: rgba(var(--base-font-color), 0.25) rgba(var(--base-font-color), 0.25) rgb(var(--body-background-color)); -} \ No newline at end of file + background-color: rgb(var(--body-background-color)); + border-color: rgba(var(--base-font-color), 0.25) rgba(var(--base-font-color), 0.25) rgb(var(--body-background-color)); +} diff --git a/src/main/resources/static/js/darkmode.js b/src/main/resources/static/js/darkmode.js index d3c62266..cb119a8a 100644 --- a/src/main/resources/static/js/darkmode.js +++ b/src/main/resources/static/js/darkmode.js @@ -1,5 +1,5 @@ -var toggleCount = 0 -var lastToggleTime = Date.now() +var toggleCount = 0; +var lastToggleTime = Date.now(); var elements = { lightModeStyles: null, @@ -11,18 +11,18 @@ var elements = { navbar: null, navIcons: null, navDropdownMenus: null, -} +}; function getElements() { - elements.lightModeStyles = document.getElementById("light-mode-styles") - elements.darkModeStyles = document.getElementById("dark-mode-styles") - elements.rainbowModeStyles = document.getElementById("rainbow-mode-styles") - elements.darkModeIcon = document.getElementById("dark-mode-icon") - elements.searchBar = document.getElementById("searchBar") - elements.formControls = document.querySelectorAll(".form-control") - elements.navbar = document.querySelectorAll("nav.navbar") - elements.navIcons = document.querySelectorAll("nav .icon, .navbar-icon") - elements.navDropdownMenus = document.querySelectorAll("nav .dropdown-menu") + elements.lightModeStyles = document.getElementById("light-mode-styles"); + elements.darkModeStyles = document.getElementById("dark-mode-styles"); + elements.rainbowModeStyles = document.getElementById("rainbow-mode-styles"); + elements.darkModeIcon = document.getElementById("dark-mode-icon"); + elements.searchBar = document.getElementById("searchBar"); + elements.formControls = document.querySelectorAll(".form-control"); + elements.navbar = document.querySelectorAll("nav.navbar"); + elements.navIcons = document.querySelectorAll("nav .icon, .navbar-icon"); + elements.navDropdownMenus = document.querySelectorAll(".dropdown-menu"); } function setMode(mode) { var event = new CustomEvent("modeChanged", { detail: mode }); @@ -48,22 +48,22 @@ function setMode(mode) { elements.searchBar.classList.add("dark-mode-search"); } if (elements && elements.formControls) { - elements.formControls.forEach(input => input.classList.add("bg-dark", "text-white")); + elements.formControls.forEach((input) => input.classList.add("bg-dark", "text-white")); } if (elements && elements.navbar) { - elements.navbar.forEach(navElement => { + elements.navbar.forEach((navElement) => { navElement.classList.remove("navbar-light", "bg-light"); navElement.classList.add("navbar-dark", "bg-dark"); }); } if (elements && elements.navDropdownMenus) { - elements.navDropdownMenus.forEach(menu => menu.classList.add("dropdown-menu-dark")); + elements.navDropdownMenus.forEach((menu) => menu.classList.add("dropdown-menu-dark")); } if (elements && elements.navIcons) { - elements.navIcons.forEach(icon => (icon.style.filter = "invert(1)")); + elements.navIcons.forEach((icon) => (icon.style.filter = "invert(1)")); } var tables = document.querySelectorAll(".table"); - tables.forEach(table => { + tables.forEach((table) => { table.classList.add("table-dark"); }); if (jumbotron) { @@ -78,22 +78,22 @@ function setMode(mode) { elements.searchBar.classList.remove("dark-mode-search"); } if (elements && elements.formControls) { - elements.formControls.forEach(input => input.classList.remove("bg-dark", "text-white")); + elements.formControls.forEach((input) => input.classList.remove("bg-dark", "text-white")); } if (elements && elements.navbar) { - elements.navbar.forEach(navElement => { + elements.navbar.forEach((navElement) => { navElement.classList.remove("navbar-dark", "bg-dark"); navElement.classList.add("navbar-light", "bg-light"); }); } if (elements && elements.navDropdownMenus) { - elements.navDropdownMenus.forEach(menu => menu.classList.remove("dropdown-menu-dark")); + elements.navDropdownMenus.forEach((menu) => menu.classList.remove("dropdown-menu-dark")); } if (elements && elements.navIcons) { - elements.navIcons.forEach(icon => (icon.style.filter = "none")); + elements.navIcons.forEach((icon) => (icon.style.filter = "none")); } var tables = document.querySelectorAll(".table-dark"); - tables.forEach(table => { + tables.forEach((table) => { table.classList.remove("table-dark"); }); if (jumbotron) { @@ -108,43 +108,43 @@ function setMode(mode) { } function toggleDarkMode() { - var currentTime = Date.now() + var currentTime = Date.now(); if (currentTime - lastToggleTime < 1000) { - toggleCount++ + toggleCount++; } else { - toggleCount = 1 + toggleCount = 1; } - lastToggleTime = currentTime + lastToggleTime = currentTime; if (toggleCount >= 18) { - localStorage.setItem("dark-mode", "rainbow") - setMode("rainbow") + localStorage.setItem("dark-mode", "rainbow"); + setMode("rainbow"); } else if (localStorage.getItem("dark-mode") == "on") { - localStorage.setItem("dark-mode", "off") - setMode("off") + localStorage.setItem("dark-mode", "off"); + setMode("off"); } else { - localStorage.setItem("dark-mode", "on") - setMode("on") + localStorage.setItem("dark-mode", "on"); + setMode("on"); } } document.addEventListener("DOMContentLoaded", function () { - getElements() + getElements(); - var currentMode = localStorage.getItem("dark-mode") + var currentMode = localStorage.getItem("dark-mode"); if (currentMode === "on" || currentMode === "off" || currentMode === "rainbow") { - setMode(currentMode) + setMode(currentMode); } else if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) { - setMode("on") + setMode("on"); } else { - setMode("off") + setMode("off"); } var darkModeToggle = document.getElementById("dark-mode-toggle"); if (darkModeToggle !== null) { - darkModeToggle.addEventListener("click", function (event) { - event.preventDefault(); - toggleDarkMode(); - }); - } -}) + darkModeToggle.addEventListener("click", function (event) { + event.preventDefault(); + toggleDarkMode(); + }); + } +}); diff --git a/src/main/resources/static/js/downloader.js b/src/main/resources/static/js/downloader.js index 8971f98e..842e9df0 100644 --- a/src/main/resources/static/js/downloader.js +++ b/src/main/resources/static/js/downloader.js @@ -1,242 +1,235 @@ function showErrorBanner(message, stackTrace) { - const errorContainer = document.getElementById("errorContainer"); - errorContainer.style.display = "block"; // Display the banner - document.querySelector("#errorContainer .alert-heading").textContent = "Error"; - document.querySelector("#errorContainer p").textContent = message; - document.querySelector("#traceContent").textContent = stackTrace; + const errorContainer = document.getElementById("errorContainer"); + errorContainer.style.display = "block"; // Display the banner + document.querySelector("#errorContainer .alert-heading").textContent = "Error"; + document.querySelector("#errorContainer p").textContent = message; + document.querySelector("#traceContent").textContent = stackTrace; } let firstErrorOccurred = false; -$(document).ready(function() { - $('form').submit(async function(event) { - event.preventDefault(); - firstErrorOccurred = false; - const url = this.action; - const files = $('#fileInput-input')[0].files; - const formData = new FormData(this); +$(document).ready(function () { + $("form").submit(async function (event) { + event.preventDefault(); + firstErrorOccurred = false; + const url = this.action; + const files = $("#fileInput-input")[0].files; + const formData = new FormData(this); - // Remove empty file entries - for (let [key, value] of formData.entries()) { - if (value instanceof File && !value.name) { - formData.delete(key); - } + // Remove empty file entries + for (let [key, value] of formData.entries()) { + if (value instanceof File && !value.name) { + formData.delete(key); + } + } + const override = $("#override").val() || ""; + const originalButtonText = $("#submitBtn").text(); + $("#submitBtn").text("Processing..."); + console.log(override); + try { + if (remoteCall === true) { + if (override === "multi" || (!multiple && files.length > 1 && override !== "single")) { + await submitMultiPdfForm(url, files); + } else { + await handleSingleDownload(url, formData); } - const override = $('#override').val() || ''; - const originalButtonText = $('#submitBtn').text(); - $('#submitBtn').text('Processing...'); - console.log(override); - try { - if(remoteCall === true) { - if (override === 'multi' || (!multiple && files.length > 1) && override !== 'single' ) { - await submitMultiPdfForm(url, files); - } else { - await handleSingleDownload(url, formData); - } - } - $('#submitBtn').text(originalButtonText); - } catch (error) { - handleDownloadError(error); - $('#submitBtn').text(originalButtonText); - console.error(error); - } - }); + } + $("#submitBtn").text(originalButtonText); + } catch (error) { + handleDownloadError(error); + $("#submitBtn").text(originalButtonText); + console.error(error); + } + }); }); +async function handleSingleDownload(url, formData, isMulti = false, isZip = false) { + try { + const response = await fetch(url, { method: "POST", body: formData }); + const contentType = response.headers.get("content-type"); + if (!response.ok) { + if (contentType && contentType.includes("application/json")) { + return handleJsonResponse(response); + console.error("Throwing error banner, response was not okay"); + } + throw new Error(`HTTP error! status: ${response.status}`); + } -async function handleSingleDownload(url, formData, isMulti = false , isZip = false) { - try { - const response = await fetch(url, { method: 'POST', body: formData }); - const contentType = response.headers.get('content-type'); + const contentDisposition = response.headers.get("Content-Disposition"); + let filename = getFilenameFromContentDisposition(contentDisposition); - if (!response.ok) { - if (contentType && contentType.includes('application/json')) { - return handleJsonResponse(response); - console.error('Throwing error banner, response was not okay'); - } - throw new Error(`HTTP error! status: ${response.status}`); - } - - const contentDisposition = response.headers.get('Content-Disposition'); - let filename = getFilenameFromContentDisposition(contentDisposition); - - const blob = await response.blob(); - if (contentType.includes('application/pdf') || contentType.includes('image/')) { - return handleResponse(blob, filename, !isMulti, isZip); - } else { - return handleResponse(blob, filename, false, isZip); - } - } catch (error) { - console.error('Error in handleSingleDownload:', error); - throw error; // Re-throw the error if you want it to be handled higher up. - } + const blob = await response.blob(); + if (contentType.includes("application/pdf") || contentType.includes("image/")) { + return handleResponse(blob, filename, !isMulti, isZip); + } else { + return handleResponse(blob, filename, false, isZip); + } + } catch (error) { + console.error("Error in handleSingleDownload:", error); + throw error; // Re-throw the error if you want it to be handled higher up. + } } function getFilenameFromContentDisposition(contentDisposition) { - let filename; + let filename; - if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) { - filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, '')).trim(); - } else { - // If the Content-Disposition header is not present or does not contain the filename, use a default filename - filename = 'download'; - } + if (contentDisposition && contentDisposition.indexOf("attachment") !== -1) { + filename = decodeURIComponent(contentDisposition.split("filename=")[1].replace(/"/g, "")).trim(); + } else { + // If the Content-Disposition header is not present or does not contain the filename, use a default filename + filename = "download"; + } - return filename; + return filename; } - - async function handleJsonResponse(response) { - const json = await response.json(); - const errorMessage = JSON.stringify(json, null, 2); - if (errorMessage.toLowerCase().includes('the password is incorrect') || errorMessage.toLowerCase().includes('Password is not provided') || errorMessage.toLowerCase().includes('PDF contains an encryption dictionary')) { - if (!firstErrorOccurred) { - firstErrorOccurred = true; - alert(pdfPasswordPrompt); - } - } else { - showErrorBanner(json.error + ':' + json.message, json.trace); - } + const json = await response.json(); + const errorMessage = JSON.stringify(json, null, 2); + if ( + errorMessage.toLowerCase().includes("the password is incorrect") || + errorMessage.toLowerCase().includes("Password is not provided") || + errorMessage.toLowerCase().includes("PDF contains an encryption dictionary") + ) { + if (!firstErrorOccurred) { + firstErrorOccurred = true; + alert(pdfPasswordPrompt); + } + } else { + showErrorBanner(json.error + ":" + json.message, json.trace); + } } - async function handleResponse(blob, filename, considerViewOptions = false, isZip = false) { - if (!blob) return; - const downloadOption = localStorage.getItem('downloadOption'); - if (considerViewOptions) { - if (downloadOption === 'sameWindow') { - const url = URL.createObjectURL(blob); - window.location.href = url; - return; - } else if (downloadOption === 'newWindow') { - const url = URL.createObjectURL(blob); - window.open(url, '_blank'); - return; - } - } - if(!isZip){ - downloadFile(blob, filename); - } - return { filename, blob }; + if (!blob) return; + const downloadOption = localStorage.getItem("downloadOption"); + if (considerViewOptions) { + if (downloadOption === "sameWindow") { + const url = URL.createObjectURL(blob); + window.location.href = url; + return; + } else if (downloadOption === "newWindow") { + const url = URL.createObjectURL(blob); + window.open(url, "_blank"); + return; + } + } + if (!isZip) { + downloadFile(blob, filename); + } + return { filename, blob }; } function handleDownloadError(error) { - const errorMessage = error.message; - showErrorBanner(errorMessage); + const errorMessage = error.message; + showErrorBanner(errorMessage); } let urls = []; // An array to hold all the URLs function downloadFile(blob, filename) { - if (!(blob instanceof Blob)) { - console.error('Invalid blob passed to downloadFile function'); - return; - } - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = filename; - a.click(); - urls.push(url); // Store the URL so it doesn't get garbage collected too soon + if (!(blob instanceof Blob)) { + console.error("Invalid blob passed to downloadFile function"); + return; + } + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = filename; + a.click(); + urls.push(url); // Store the URL so it doesn't get garbage collected too soon - return { filename, blob }; + return { filename, blob }; } - - async function submitMultiPdfForm(url, files) { - const zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4; - const zipFiles = files.length > zipThreshold; - let jszip = null; - // Show the progress bar - $('#progressBarContainer').show(); - // Initialize the progress bar + const zipThreshold = parseInt(localStorage.getItem("zipThreshold"), 10) || 4; + const zipFiles = files.length > zipThreshold; + let jszip = null; + // Show the progress bar + $("#progressBarContainer").show(); + // Initialize the progress bar - let progressBar = $('#progressBar'); - progressBar.css('width', '0%'); - progressBar.attr('aria-valuenow', 0); - progressBar.attr('aria-valuemax', files.length); + let progressBar = $("#progressBar"); + progressBar.css("width", "0%"); + progressBar.attr("aria-valuenow", 0); + progressBar.attr("aria-valuemax", files.length); - if (zipFiles) { - jszip = new JSZip(); - } + if (zipFiles) { + jszip = new JSZip(); + } + // Get the form with the method attribute set to POST + let postForm = document.querySelector('form[method="POST"]'); - // Get the form with the method attribute set to POST - let postForm = document.querySelector('form[method="POST"]'); - - // Get existing form data - let formData; - if (postForm) { - formData = new FormData($(postForm)[0]); // Convert the form to a jQuery object and get the raw DOM element - } else { - console.log("No form with POST method found."); - } - //Remove file to reuse parameters for other runs - formData.delete('fileInput'); - // Remove empty file entries - for (let [key, value] of formData.entries()) { - if (value instanceof File && !value.name) { - formData.delete(key); - } + // Get existing form data + let formData; + if (postForm) { + formData = new FormData($(postForm)[0]); // Convert the form to a jQuery object and get the raw DOM element + } else { + console.log("No form with POST method found."); + } + //Remove file to reuse parameters for other runs + formData.delete("fileInput"); + // Remove empty file entries + for (let [key, value] of formData.entries()) { + if (value instanceof File && !value.name) { + formData.delete(key); } - const CONCURRENCY_LIMIT = 8; - const chunks = []; - for (let i = 0; i < Array.from(files).length; i += CONCURRENCY_LIMIT) { - chunks.push(Array.from(files).slice(i, i + CONCURRENCY_LIMIT)); - } + } + const CONCURRENCY_LIMIT = 8; + const chunks = []; + for (let i = 0; i < Array.from(files).length; i += CONCURRENCY_LIMIT) { + chunks.push(Array.from(files).slice(i, i + CONCURRENCY_LIMIT)); + } - for (const chunk of chunks) { - const promises = chunk.map(async file => { - let fileFormData = new FormData(); - fileFormData.append('fileInput', file); - console.log(fileFormData); - // Add other form data - for (let pair of formData.entries()) { - fileFormData.append(pair[0], pair[1]); - console.log(pair[0]+ ', ' + pair[1]); - } + for (const chunk of chunks) { + const promises = chunk.map(async (file) => { + let fileFormData = new FormData(); + fileFormData.append("fileInput", file); + console.log(fileFormData); + // Add other form data + for (let pair of formData.entries()) { + fileFormData.append(pair[0], pair[1]); + console.log(pair[0] + ", " + pair[1]); + } - try { - const downloadDetails = await handleSingleDownload(url, fileFormData, true, zipFiles); - console.log(downloadDetails); - if (zipFiles) { - jszip.file(downloadDetails.filename, downloadDetails.blob); - } else { - //downloadFile(downloadDetails.blob, downloadDetails.filename); - } - updateProgressBar(progressBar, Array.from(files).length); - } catch (error) { - handleDownloadError(error); - console.error(error); - } - }); - await Promise.all(promises); + try { + const downloadDetails = await handleSingleDownload(url, fileFormData, true, zipFiles); + console.log(downloadDetails); + if (zipFiles) { + jszip.file(downloadDetails.filename, downloadDetails.blob); + } else { + //downloadFile(downloadDetails.blob, downloadDetails.filename); + } + updateProgressBar(progressBar, Array.from(files).length); + } catch (error) { + handleDownloadError(error); + console.error(error); + } + }); + await Promise.all(promises); + } - } - - if (zipFiles) { - try { - const content = await jszip.generateAsync({ type: "blob" }); - downloadFile(content, "files.zip"); - } catch (error) { - console.error('Error generating ZIP file: ' + error); - } - } - progressBar.css('width', '100%'); - progressBar.attr('aria-valuenow', Array.from(files).length); + if (zipFiles) { + try { + const content = await jszip.generateAsync({ type: "blob" }); + downloadFile(content, "files.zip"); + } catch (error) { + console.error("Error generating ZIP file: " + error); + } + } + progressBar.css("width", "100%"); + progressBar.attr("aria-valuenow", Array.from(files).length); } - - function updateProgressBar(progressBar, files) { - let progress = ((progressBar.attr('aria-valuenow') / files.length) * 100) + (100 / files.length); - progressBar.css('width', progress + '%'); - progressBar.attr('aria-valuenow', parseInt(progressBar.attr('aria-valuenow')) + 1); + let progress = (progressBar.attr("aria-valuenow") / files.length) * 100 + 100 / files.length; + progressBar.css("width", progress + "%"); + progressBar.attr("aria-valuenow", parseInt(progressBar.attr("aria-valuenow")) + 1); } -window.addEventListener('unload', () => { - for (const url of urls) { - URL.revokeObjectURL(url); - } +window.addEventListener("unload", () => { + for (const url of urls) { + URL.revokeObjectURL(url); + } }); diff --git a/src/main/resources/static/js/draggable-utils.js b/src/main/resources/static/js/draggable-utils.js index 2263e540..bff4c3d4 100644 --- a/src/main/resources/static/js/draggable-utils.js +++ b/src/main/resources/static/js/draggable-utils.js @@ -1,282 +1,287 @@ const DraggableUtils = { + boxDragContainer: document.getElementById("box-drag-container"), + pdfCanvas: document.getElementById("pdf-canvas"), + nextId: 0, + pdfDoc: null, + pageIndex: 0, + documentsMap: new Map(), - boxDragContainer: document.getElementById('box-drag-container'), - pdfCanvas: document.getElementById('pdf-canvas'), - nextId: 0, - pdfDoc: null, - pageIndex: 0, - documentsMap: new Map(), + init() { + interact(".draggable-canvas") + .draggable({ + listeners: { + move: (event) => { + const target = event.target; + const x = (parseFloat(target.getAttribute("data-bs-x")) || 0) + event.dx; + const y = (parseFloat(target.getAttribute("data-bs-y")) || 0) + event.dy; - init() { - interact('.draggable-canvas') - .draggable({ - listeners: { - move: (event) => { - const target = event.target; - const x = (parseFloat(target.getAttribute('data-bs-x')) || 0) + event.dx; - const y = (parseFloat(target.getAttribute('data-bs-y')) || 0) + event.dy; + target.style.transform = `translate(${x}px, ${y}px)`; + target.setAttribute("data-bs-x", x); + target.setAttribute("data-bs-y", y); - target.style.transform = `translate(${x}px, ${y}px)`; - target.setAttribute('data-bs-x', x); - target.setAttribute('data-bs-y', y); - - this.onInteraction(target); - }, - }, - }) - .resizable({ - edges: { left: true, right: true, bottom: true, top: true }, - listeners: { - move: (event) => { - var target = event.target - var x = (parseFloat(target.getAttribute('data-bs-x')) || 0) - var y = (parseFloat(target.getAttribute('data-bs-y')) || 0) + this.onInteraction(target); + }, + }, + }) + .resizable({ + edges: { left: true, right: true, bottom: true, top: true }, + listeners: { + move: (event) => { + var target = event.target; + var x = parseFloat(target.getAttribute("data-bs-x")) || 0; + var y = parseFloat(target.getAttribute("data-bs-y")) || 0; // check if control key is pressed if (event.ctrlKey) { - const aspectRatio = target.offsetWidth / target.offsetHeight; - // preserve aspect ratio - let width = event.rect.width; - let height = event.rect.height; + const aspectRatio = target.offsetWidth / target.offsetHeight; + // preserve aspect ratio + let width = event.rect.width; + let height = event.rect.height; - if (Math.abs(event.deltaRect.width) >= Math.abs(event.deltaRect.height)) { - height = width / aspectRatio; - } else { - width = height * aspectRatio; - } + if (Math.abs(event.deltaRect.width) >= Math.abs(event.deltaRect.height)) { + height = width / aspectRatio; + } else { + width = height * aspectRatio; + } - event.rect.width = width; - event.rect.height = height; + event.rect.width = width; + event.rect.height = height; } - target.style.width = event.rect.width + 'px' - target.style.height = event.rect.height + 'px' + target.style.width = event.rect.width + "px"; + target.style.height = event.rect.height + "px"; // translate when resizing from top or left edges - x += event.deltaRect.left - y += event.deltaRect.top + x += event.deltaRect.left; + y += event.deltaRect.top; - target.style.transform = 'translate(' + x + 'px,' + y + 'px)' + target.style.transform = "translate(" + x + "px," + y + "px)"; - target.setAttribute('data-bs-x', x) - target.setAttribute('data-bs-y', y) - target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height) + target.setAttribute("data-bs-x", x); + target.setAttribute("data-bs-y", y); + target.textContent = Math.round(event.rect.width) + "\u00D7" + Math.round(event.rect.height); this.onInteraction(target); + }, }, - }, - modifiers: [ - interact.modifiers.restrictSize({ - min: { width: 5, height: 5 }, - }), - ], - inertia: true, - }); - }, - onInteraction(target) { - this.boxDragContainer.appendChild(target); - }, + modifiers: [ + interact.modifiers.restrictSize({ + min: { width: 5, height: 5 }, + }), + ], + inertia: true, + }); + }, + onInteraction(target) { + this.boxDragContainer.appendChild(target); + }, - createDraggableCanvas() { - const createdCanvas = document.createElement('canvas'); - createdCanvas.id = `draggable-canvas-${this.nextId++}`; - createdCanvas.classList.add("draggable-canvas"); + createDraggableCanvas() { + const createdCanvas = document.createElement("canvas"); + createdCanvas.id = `draggable-canvas-${this.nextId++}`; + createdCanvas.classList.add("draggable-canvas"); - const x = 0; - const y = 20; - createdCanvas.style.transform = `translate(${x}px, ${y}px)`; - createdCanvas.setAttribute('data-bs-x', x); - createdCanvas.setAttribute('data-bs-y', y); + const x = 0; + const y = 20; + createdCanvas.style.transform = `translate(${x}px, ${y}px)`; + createdCanvas.setAttribute("data-bs-x", x); + createdCanvas.setAttribute("data-bs-y", y); - createdCanvas.onclick = e => this.onInteraction(e.target); + createdCanvas.onclick = (e) => this.onInteraction(e.target); - this.boxDragContainer.appendChild(createdCanvas); - return createdCanvas; - }, - createDraggableCanvasFromUrl(dataUrl) { - return new Promise((resolve) => { - var myImage = new Image(); - myImage.src = dataUrl; - myImage.onload = () => { - var createdCanvas = this.createDraggableCanvas(); + this.boxDragContainer.appendChild(createdCanvas); + return createdCanvas; + }, + createDraggableCanvasFromUrl(dataUrl) { + return new Promise((resolve) => { + var myImage = new Image(); + myImage.src = dataUrl; + myImage.onload = () => { + var createdCanvas = this.createDraggableCanvas(); - createdCanvas.width = myImage.width; - createdCanvas.height = myImage.height; + createdCanvas.width = myImage.width; + createdCanvas.height = myImage.height; - const imgAspect = myImage.width / myImage.height; - const pdfAspect = this.boxDragContainer.offsetWidth / this.boxDragContainer.offsetHeight; + const imgAspect = myImage.width / myImage.height; + const pdfAspect = this.boxDragContainer.offsetWidth / this.boxDragContainer.offsetHeight; - var scaleMultiplier; - if (imgAspect > pdfAspect) { - scaleMultiplier = this.boxDragContainer.offsetWidth / myImage.width; - } else { - scaleMultiplier = this.boxDragContainer.offsetHeight / myImage.height; - } - - var newWidth = createdCanvas.width; - var newHeight = createdCanvas.height; - if (scaleMultiplier < 1) { - newWidth = newWidth * scaleMultiplier; - newHeight = newHeight * scaleMultiplier; - } - - createdCanvas.style.width = newWidth+"px"; - createdCanvas.style.height = newHeight+"px"; - - var myContext = createdCanvas.getContext("2d"); - myContext.drawImage(myImage,0,0); - resolve(createdCanvas); - } - }) - }, - deleteAllDraggableCanvases() { - this.boxDragContainer.querySelectorAll(".draggable-canvas").forEach(el => el.remove()); - }, - deleteDraggableCanvas(element) { - if (element) { - element.remove(); - } - }, - getLastInteracted() { - return this.boxDragContainer.querySelector(".draggable-canvas:last-of-type"); - }, - - storePageContents() { - var pagesMap = this.documentsMap.get(this.pdfDoc); - if (!pagesMap) { - pagesMap = {}; - } - - const elements = [...this.boxDragContainer.querySelectorAll(".draggable-canvas")]; - const draggablesData = elements.map(el => {return{element:el, offsetWidth:el.offsetWidth, offsetHeight:el.offsetHeight}}); - elements.forEach(el => this.boxDragContainer.removeChild(el)); - - pagesMap[this.pageIndex] = draggablesData; - pagesMap[this.pageIndex+"-offsetWidth"] = this.pdfCanvas.offsetWidth; - pagesMap[this.pageIndex+"-offsetHeight"] = this.pdfCanvas.offsetHeight; - - this.documentsMap.set(this.pdfDoc, pagesMap); - }, - loadPageContents() { - var pagesMap = this.documentsMap.get(this.pdfDoc); - this.deleteAllDraggableCanvases(); - if (!pagesMap) { - return; - } - - const draggablesData = pagesMap[this.pageIndex]; - if (draggablesData) { - draggablesData.forEach(draggableData => this.boxDragContainer.appendChild(draggableData.element)); - } - - this.documentsMap.set(this.pdfDoc, pagesMap); - }, - - async renderPage(pdfDocument, pageIdx) { - this.pdfDoc = pdfDocument ? pdfDocument : this.pdfDoc; - this.pageIndex = pageIdx; - - // persist - const page = await this.pdfDoc.getPage(this.pageIndex+1); - - // set the canvas size to the size of the page - if (page.rotate == 90 || page.rotate == 270) { - this.pdfCanvas.width = page.view[3]; - this.pdfCanvas.height = page.view[2]; + var scaleMultiplier; + if (imgAspect > pdfAspect) { + scaleMultiplier = this.boxDragContainer.offsetWidth / myImage.width; } else { - this.pdfCanvas.width = page.view[2]; - this.pdfCanvas.height = page.view[3]; + scaleMultiplier = this.boxDragContainer.offsetHeight / myImage.height; } - // render the page onto the canvas - var renderContext = { - canvasContext: this.pdfCanvas.getContext("2d"), - viewport: page.getViewport({ scale: 1 }) + var newWidth = createdCanvas.width; + var newHeight = createdCanvas.height; + if (scaleMultiplier < 1) { + newWidth = newWidth * scaleMultiplier; + newHeight = newHeight * scaleMultiplier; + } + + createdCanvas.style.width = newWidth + "px"; + createdCanvas.style.height = newHeight + "px"; + + var myContext = createdCanvas.getContext("2d"); + myContext.drawImage(myImage, 0, 0); + resolve(createdCanvas); + }; + }); + }, + deleteAllDraggableCanvases() { + this.boxDragContainer.querySelectorAll(".draggable-canvas").forEach((el) => el.remove()); + }, + deleteDraggableCanvas(element) { + if (element) { + element.remove(); + } + }, + getLastInteracted() { + return this.boxDragContainer.querySelector(".draggable-canvas:last-of-type"); + }, + + storePageContents() { + var pagesMap = this.documentsMap.get(this.pdfDoc); + if (!pagesMap) { + pagesMap = {}; + } + + const elements = [...this.boxDragContainer.querySelectorAll(".draggable-canvas")]; + const draggablesData = elements.map((el) => { + return { + element: el, + offsetWidth: el.offsetWidth, + offsetHeight: el.offsetHeight, + }; + }); + elements.forEach((el) => this.boxDragContainer.removeChild(el)); + + pagesMap[this.pageIndex] = draggablesData; + pagesMap[this.pageIndex + "-offsetWidth"] = this.pdfCanvas.offsetWidth; + pagesMap[this.pageIndex + "-offsetHeight"] = this.pdfCanvas.offsetHeight; + + this.documentsMap.set(this.pdfDoc, pagesMap); + }, + loadPageContents() { + var pagesMap = this.documentsMap.get(this.pdfDoc); + this.deleteAllDraggableCanvases(); + if (!pagesMap) { + return; + } + + const draggablesData = pagesMap[this.pageIndex]; + if (draggablesData) { + draggablesData.forEach((draggableData) => this.boxDragContainer.appendChild(draggableData.element)); + } + + this.documentsMap.set(this.pdfDoc, pagesMap); + }, + + async renderPage(pdfDocument, pageIdx) { + this.pdfDoc = pdfDocument ? pdfDocument : this.pdfDoc; + this.pageIndex = pageIdx; + + // persist + const page = await this.pdfDoc.getPage(this.pageIndex + 1); + + // set the canvas size to the size of the page + if (page.rotate == 90 || page.rotate == 270) { + this.pdfCanvas.width = page.view[3]; + this.pdfCanvas.height = page.view[2]; + } else { + this.pdfCanvas.width = page.view[2]; + this.pdfCanvas.height = page.view[3]; + } + + // render the page onto the canvas + var renderContext = { + canvasContext: this.pdfCanvas.getContext("2d"), + viewport: page.getViewport({ scale: 1 }), + }; + await page.render(renderContext).promise; + + //return pdfCanvas.toDataURL(); + }, + async incrementPage() { + if (this.pageIndex < this.pdfDoc.numPages - 1) { + this.storePageContents(); + await this.renderPage(this.pdfDoc, this.pageIndex + 1); + this.loadPageContents(); + } + }, + async decrementPage() { + if (this.pageIndex > 0) { + this.storePageContents(); + await this.renderPage(this.pdfDoc, this.pageIndex - 1); + this.loadPageContents(); + } + }, + + parseTransform(element) {}, + async getOverlayedPdfDocument() { + const pdfBytes = await this.pdfDoc.getData(); + const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, { + ignoreEncryption: true, + }); + this.storePageContents(); + + const pagesMap = this.documentsMap.get(this.pdfDoc); + for (let pageIdx in pagesMap) { + if (pageIdx.includes("offset")) { + continue; + } + console.log(typeof pageIdx); + + const page = pdfDocModified.getPage(parseInt(pageIdx)); + const draggablesData = pagesMap[pageIdx]; + const offsetWidth = pagesMap[pageIdx + "-offsetWidth"]; + const offsetHeight = pagesMap[pageIdx + "-offsetHeight"]; + + for (const draggableData of draggablesData) { + // embed the draggable canvas + const draggableElement = draggableData.element; + const response = await fetch(draggableElement.toDataURL()); + const draggableImgBytes = await response.arrayBuffer(); + const pdfImageObject = await pdfDocModified.embedPng(draggableImgBytes); + + // calculate the position in the pdf document + const tansform = draggableElement.style.transform.replace(/[^.,-\d]/g, ""); + const transformComponents = tansform.split(","); + const draggablePositionPixels = { + x: parseFloat(transformComponents[0]), + y: parseFloat(transformComponents[1]), + width: draggableData.offsetWidth, + height: draggableData.offsetHeight, + }; + const draggablePositionRelative = { + x: draggablePositionPixels.x / offsetWidth, + y: draggablePositionPixels.y / offsetHeight, + width: draggablePositionPixels.width / offsetWidth, + height: draggablePositionPixels.height / offsetHeight, + }; + const draggablePositionPdf = { + x: draggablePositionRelative.x * page.getWidth(), + y: draggablePositionRelative.y * page.getHeight(), + width: draggablePositionRelative.width * page.getWidth(), + height: draggablePositionRelative.height * page.getHeight(), }; - await page.render(renderContext).promise; - //return pdfCanvas.toDataURL(); - }, - async incrementPage() { - if (this.pageIndex < this.pdfDoc.numPages-1) { - this.storePageContents(); - await this.renderPage(this.pdfDoc, this.pageIndex+1); - this.loadPageContents(); - } - }, - async decrementPage() { - if (this.pageIndex > 0) { - this.storePageContents(); - await this.renderPage(this.pdfDoc, this.pageIndex-1); - this.loadPageContents(); - } - }, + // draw the image + page.drawImage(pdfImageObject, { + x: draggablePositionPdf.x, + y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height, + width: draggablePositionPdf.width, + height: draggablePositionPdf.height, + }); + } + } - parseTransform(element) { - - }, - async getOverlayedPdfDocument() { - const pdfBytes = await this.pdfDoc.getData(); - const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, { ignoreEncryption: true }); - this.storePageContents(); - - const pagesMap = this.documentsMap.get(this.pdfDoc); - for (let pageIdx in pagesMap) { - if (pageIdx.includes("offset")) { - continue; - } - console.log(typeof pageIdx); - - const page = pdfDocModified.getPage(parseInt(pageIdx)); - const draggablesData = pagesMap[pageIdx]; - const offsetWidth = pagesMap[pageIdx+"-offsetWidth"]; - const offsetHeight = pagesMap[pageIdx+"-offsetHeight"]; - - for (const draggableData of draggablesData) { - // embed the draggable canvas - const draggableElement = draggableData.element; - const response = await fetch(draggableElement.toDataURL()); - const draggableImgBytes = await response.arrayBuffer(); - const pdfImageObject = await pdfDocModified.embedPng(draggableImgBytes); - - // calculate the position in the pdf document - const tansform = draggableElement.style.transform.replace(/[^.,-\d]/g, ''); - const transformComponents = tansform.split(","); - const draggablePositionPixels = { - x: parseFloat(transformComponents[0]), - y: parseFloat(transformComponents[1]), - width: draggableData.offsetWidth, - height: draggableData.offsetHeight, - }; - const draggablePositionRelative = { - x: draggablePositionPixels.x / offsetWidth, - y: draggablePositionPixels.y / offsetHeight, - width: draggablePositionPixels.width / offsetWidth, - height: draggablePositionPixels.height / offsetHeight, - } - const draggablePositionPdf = { - x: draggablePositionRelative.x * page.getWidth(), - y: draggablePositionRelative.y * page.getHeight(), - width: draggablePositionRelative.width * page.getWidth(), - height: draggablePositionRelative.height * page.getHeight(), - } - - // draw the image - page.drawImage(pdfImageObject, { - x: draggablePositionPdf.x, - y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height, - width: draggablePositionPdf.width, - height: draggablePositionPdf.height, - }); - } - } - - this.loadPageContents(); - return pdfDocModified; - }, -} + this.loadPageContents(); + return pdfDocModified; + }, +}; document.addEventListener("DOMContentLoaded", () => { - DraggableUtils.init(); + DraggableUtils.init(); }); diff --git a/src/main/resources/static/js/errorBanner.js b/src/main/resources/static/js/errorBanner.js index 9d151407..727a854f 100644 --- a/src/main/resources/static/js/errorBanner.js +++ b/src/main/resources/static/js/errorBanner.js @@ -1,50 +1,50 @@ var traceVisible = false; function toggletrace() { - var traceDiv = document.getElementById("trace"); - if (!traceVisible) { - traceDiv.style.maxHeight = "500px"; - traceVisible = true; - } else { - traceDiv.style.maxHeight = "0px"; - traceVisible = false; - } - adjustContainerHeight(); + var traceDiv = document.getElementById("trace"); + if (!traceVisible) { + traceDiv.style.maxHeight = "500px"; + traceVisible = true; + } else { + traceDiv.style.maxHeight = "0px"; + traceVisible = false; + } + adjustContainerHeight(); } function copytrace() { - var flip = false - if (!traceVisible) { - toggletrace() - flip = true - } - var traceContent = document.getElementById("traceContent"); - var range = document.createRange(); - range.selectNode(traceContent); - window.getSelection().removeAllRanges(); - window.getSelection().addRange(range); - document.execCommand("copy"); - window.getSelection().removeAllRanges(); - if (flip) { - toggletrace() - } + var flip = false; + if (!traceVisible) { + toggletrace(); + flip = true; + } + var traceContent = document.getElementById("traceContent"); + var range = document.createRange(); + range.selectNode(traceContent); + window.getSelection().removeAllRanges(); + window.getSelection().addRange(range); + document.execCommand("copy"); + window.getSelection().removeAllRanges(); + if (flip) { + toggletrace(); + } } function dismissError() { - var errorContainer = document.getElementById("errorContainer"); - errorContainer.style.display = "none"; - errorContainer.style.height = "0"; + var errorContainer = document.getElementById("errorContainer"); + errorContainer.style.display = "none"; + errorContainer.style.height = "0"; } function adjustContainerHeight() { - var errorContainer = document.getElementById("errorContainer"); - var traceDiv = document.getElementById("trace"); - if (traceVisible) { - errorContainer.style.height = errorContainer.scrollHeight - traceDiv.scrollHeight + traceDiv.offsetHeight + "px"; - } else { - errorContainer.style.height = "auto"; - } + var errorContainer = document.getElementById("errorContainer"); + var traceDiv = document.getElementById("trace"); + if (traceVisible) { + errorContainer.style.height = errorContainer.scrollHeight - traceDiv.scrollHeight + traceDiv.offsetHeight + "px"; + } else { + errorContainer.style.height = "auto"; + } } function showHelp() { - $('#helpModal').modal('show'); -} \ No newline at end of file + $("#helpModal").modal("show"); +} diff --git a/src/main/resources/static/js/favourites.js b/src/main/resources/static/js/favourites.js index 08c6f183..dbecd013 100644 --- a/src/main/resources/static/js/favourites.js +++ b/src/main/resources/static/js/favourites.js @@ -1,45 +1,45 @@ function updateFavoritesDropdown() { - var dropdown = document.querySelector('#favoritesDropdown'); + var dropdown = document.querySelector("#favoritesDropdown"); - // Check if dropdown exists - if (!dropdown) { - console.error('Dropdown element with ID "favoritesDropdown" not found!'); - return; // Exit the function + // Check if dropdown exists + if (!dropdown) { + console.error('Dropdown element with ID "favoritesDropdown" not found!'); + return; // Exit the function + } + dropdown.innerHTML = ""; // Clear the current favorites + + var hasFavorites = false; + + for (var i = 0; i < localStorage.length; i++) { + var key = localStorage.key(i); + if (localStorage.getItem(key) === "favorite") { + // Find the corresponding navbar entry + var navbarEntry = document.querySelector(`a[href='${key}']`); + if (navbarEntry) { + // Create a new dropdown entry + var dropdownItem = document.createElement("a"); + dropdownItem.className = "dropdown-item"; + dropdownItem.href = navbarEntry.href; + dropdownItem.innerHTML = navbarEntry.innerHTML; + dropdown.appendChild(dropdownItem); + hasFavorites = true; + } else { + console.warn(`Navbar entry not found for key: ${key}`); + } } - dropdown.innerHTML = ''; // Clear the current favorites + } - var hasFavorites = false; - - for (var i = 0; i < localStorage.length; i++) { - var key = localStorage.key(i); - if (localStorage.getItem(key) === 'favorite') { - // Find the corresponding navbar entry - var navbarEntry = document.querySelector(`a[href='${key}']`); - if (navbarEntry) { - // Create a new dropdown entry - var dropdownItem = document.createElement('a'); - dropdownItem.className = 'dropdown-item'; - dropdownItem.href = navbarEntry.href; - dropdownItem.innerHTML = navbarEntry.innerHTML; - dropdown.appendChild(dropdownItem); - hasFavorites = true; - } else { - console.warn(`Navbar entry not found for key: ${key}`); - } - } - } - - // Show or hide the default item based on whether there are any favorites - if (!hasFavorites) { - var defaultItem = document.createElement('a'); - defaultItem.className = 'dropdown-item'; - defaultItem.textContent = noFavourites; - dropdown.appendChild(defaultItem); - } + // Show or hide the default item based on whether there are any favorites + if (!hasFavorites) { + var defaultItem = document.createElement("a"); + defaultItem.className = "dropdown-item"; + defaultItem.textContent = noFavourites; + dropdown.appendChild(defaultItem); + } } // Ensure that the DOM content has been fully loaded before calling the function -document.addEventListener('DOMContentLoaded', function() { - console.log('DOMContentLoaded event fired'); - updateFavoritesDropdown(); +document.addEventListener("DOMContentLoaded", function () { + console.log("DOMContentLoaded event fired"); + updateFavoritesDropdown(); }); diff --git a/src/main/resources/static/js/fileInput.js b/src/main/resources/static/js/fileInput.js index 610ae723..89ad1ad9 100644 --- a/src/main/resources/static/js/fileInput.js +++ b/src/main/resources/static/js/fileInput.js @@ -1,104 +1,107 @@ -document.addEventListener('DOMContentLoaded', function() { - document.querySelectorAll('.custom-file-chooser').forEach(setupFileInput); +document.addEventListener("DOMContentLoaded", function () { + document.querySelectorAll(".custom-file-chooser").forEach(setupFileInput); }); function setupFileInput(chooser) { - const elementId = chooser.getAttribute('data-bs-element-id'); - const filesSelected = chooser.getAttribute('data-bs-files-selected'); - const pdfPrompt = chooser.getAttribute('data-bs-pdf-prompt'); + const elementId = chooser.getAttribute("data-bs-element-id"); + const filesSelected = chooser.getAttribute("data-bs-files-selected"); + const pdfPrompt = chooser.getAttribute("data-bs-pdf-prompt"); - let allFiles = []; - let overlay; - let dragCounter = 0; + let allFiles = []; + let overlay; + let dragCounter = 0; - const dragenterListener = function() { - dragCounter++; - if (!overlay) { - overlay = document.createElement('div'); - overlay.style.position = 'fixed'; - overlay.style.top = 0; - overlay.style.left = 0; - overlay.style.width = '100%'; - overlay.style.height = '100%'; - overlay.style.background = 'rgba(0, 0, 0, 0.5)'; - overlay.style.color = '#fff'; - overlay.style.zIndex = '1000'; - overlay.style.display = 'flex'; - overlay.style.alignItems = 'center'; - overlay.style.justifyContent = 'center'; - overlay.style.pointerEvents = 'none'; - overlay.innerHTML = '

Drop files anywhere to upload

'; - document.getElementById('content-wrap').appendChild(overlay); - } - }; + const dragenterListener = function () { + dragCounter++; + if (!overlay) { + overlay = document.createElement("div"); + overlay.style.position = "fixed"; + overlay.style.top = 0; + overlay.style.left = 0; + overlay.style.width = "100%"; + overlay.style.height = "100%"; + overlay.style.background = "rgba(0, 0, 0, 0.5)"; + overlay.style.color = "#fff"; + overlay.style.zIndex = "1000"; + overlay.style.display = "flex"; + overlay.style.alignItems = "center"; + overlay.style.justifyContent = "center"; + overlay.style.pointerEvents = "none"; + overlay.innerHTML = "

Drop files anywhere to upload

"; + document.getElementById("content-wrap").appendChild(overlay); + } + }; - const dragleaveListener = function() { - dragCounter--; - if (dragCounter === 0) { - if (overlay) { - overlay.remove(); - overlay = null; - } - } - }; + const dragleaveListener = function () { + dragCounter--; + if (dragCounter === 0) { + if (overlay) { + overlay.remove(); + overlay = null; + } + } + }; - const dropListener = function(e) { - e.preventDefault(); - const dt = e.dataTransfer; - const files = dt.files; + const dropListener = function (e) { + e.preventDefault(); + const dt = e.dataTransfer; + const files = dt.files; - for (let i = 0; i < files.length; i++) { - allFiles.push(files[i]); - } + for (let i = 0; i < files.length; i++) { + allFiles.push(files[i]); + } - const dataTransfer = new DataTransfer(); - allFiles.forEach(file => dataTransfer.items.add(file)); + const dataTransfer = new DataTransfer(); + allFiles.forEach((file) => dataTransfer.items.add(file)); - const fileInput = document.getElementById(elementId); - fileInput.files = dataTransfer.files; + const fileInput = document.getElementById(elementId); + fileInput.files = dataTransfer.files; - if (overlay) { - overlay.remove(); - overlay = null; - } + if (overlay) { + overlay.remove(); + overlay = null; + } - dragCounter = 0; + dragCounter = 0; - fileInput.dispatchEvent(new Event('change', { bubbles: true })); - }; + fileInput.dispatchEvent(new Event("change", { bubbles: true })); + }; - ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { - document.body.addEventListener(eventName, preventDefaults, false); + ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => { + document.body.addEventListener(eventName, preventDefaults, false); + }); + + function preventDefaults(e) { + e.preventDefault(); + e.stopPropagation(); + } + + document.body.addEventListener("dragenter", dragenterListener); + document.body.addEventListener("dragleave", dragleaveListener); + document.body.addEventListener("drop", dropListener); + + $("#" + elementId).on("change", function (e) { + allFiles = Array.from(e.target.files); + handleFileInputChange(this); + }); + + function handleFileInputChange(inputElement) { + const files = allFiles; + const fileNames = files.map((f) => f.name); + const selectedFilesContainer = $(inputElement).siblings(".selected-files"); + selectedFilesContainer.empty(); + fileNames.forEach((fileName) => { + selectedFilesContainer.append("
" + fileName + "
"); }); - - function preventDefaults(e) { - e.preventDefault(); - e.stopPropagation(); - } - - document.body.addEventListener('dragenter', dragenterListener); - document.body.addEventListener('dragleave', dragleaveListener); - document.body.addEventListener('drop', dropListener); - - $("#" + elementId).on("change", function(e) { - allFiles = Array.from(e.target.files); - handleFileInputChange(this); - }); - - function handleFileInputChange(inputElement) { - const files = allFiles; - const fileNames = files.map(f => f.name); - const selectedFilesContainer = $(inputElement).siblings(".selected-files"); - selectedFilesContainer.empty(); - fileNames.forEach(fileName => { - selectedFilesContainer.append("
" + fileName + "
"); - }); - if (fileNames.length === 1) { - $(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]); - } else if (fileNames.length > 1) { - $(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames.length + " " + filesSelected); - } else { - $(inputElement).siblings(".custom-file-label").addClass("selected").html(pdfPrompt); - } + if (fileNames.length === 1) { + $(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]); + } else if (fileNames.length > 1) { + $(inputElement) + .siblings(".custom-file-label") + .addClass("selected") + .html(fileNames.length + " " + filesSelected); + } else { + $(inputElement).siblings(".custom-file-label").addClass("selected").html(pdfPrompt); } + } } diff --git a/src/main/resources/static/js/game.js b/src/main/resources/static/js/game.js index 1bfb9374..199bab0f 100644 --- a/src/main/resources/static/js/game.js +++ b/src/main/resources/static/js/game.js @@ -1,292 +1,265 @@ function initializeGame() { - const gameContainer = document.getElementById('game-container'); - const player = document.getElementById('player'); + const gameContainer = document.getElementById("game-container"); + const player = document.getElementById("player"); - let playerSize = gameContainer.clientWidth * 0.0625; // 5% of container width - player.style.width = playerSize + 'px'; - player.style.height = playerSize + 'px'; + let playerSize = gameContainer.clientWidth * 0.0625; // 5% of container width + player.style.width = playerSize + "px"; + player.style.height = playerSize + "px"; - let playerX = gameContainer.clientWidth / 2 - playerSize / 2; - let playerY = gameContainer.clientHeight * 0.1; - const scoreElement = document.getElementById('score'); - const levelElement = document.getElementById('level'); - const livesElement = document.getElementById('lives'); - const highScoreElement = document.getElementById('high-score'); + let playerX = gameContainer.clientWidth / 2 - playerSize / 2; + let playerY = gameContainer.clientHeight * 0.1; + const scoreElement = document.getElementById("score"); + const levelElement = document.getElementById("level"); + const livesElement = document.getElementById("lives"); + const highScoreElement = document.getElementById("high-score"); - let pdfSize = gameContainer.clientWidth * 0.0625; // 5% of container width - let projectileWidth = gameContainer.clientWidth * 0.00625;// 0.00625; // 0.5% of container width - let projectileHeight = gameContainer.clientHeight * 0.01667; // 1% of container height + let pdfSize = gameContainer.clientWidth * 0.0625; // 5% of container width + let projectileWidth = gameContainer.clientWidth * 0.00625; // 0.00625; // 0.5% of container width + let projectileHeight = gameContainer.clientHeight * 0.01667; // 1% of container height - let paused = false; + let paused = false; - const fireRate = 200; // Time between shots in milliseconds - let lastProjectileTime = 0; - let lives = 3; + const fireRate = 200; // Time between shots in milliseconds + let lastProjectileTime = 0; + let lives = 3; + let highScore = localStorage.getItem("highScore") ? parseInt(localStorage.getItem("highScore")) : 0; + updateHighScore(); - let highScore = localStorage.getItem('highScore') ? parseInt(localStorage.getItem('highScore')) : 0; - updateHighScore(); + const keysPressed = {}; + const pdfs = []; + const projectiles = []; + let score = 0; + let level = 1; + let pdfSpeed = 0.5; + let gameOver = false; - - - const keysPressed = {}; - const pdfs = []; - const projectiles = []; - let score = 0; - let level = 1; - let pdfSpeed = 0.5; - let gameOver = false; - - function handleKeys() { - if (keysPressed['ArrowLeft']) { - playerX -= 10; - } - if (keysPressed['ArrowRight']) { - playerX += 10; - } - if (keysPressed[' '] && !gameOver) { - const currentTime = new Date().getTime(); - if (currentTime - lastProjectileTime >= fireRate) { - shootProjectile(); - lastProjectileTime = currentTime; - } - } - updatePlayerPosition(); - } - - - - - document.addEventListener('keydown', (event) => { - if (event.key === ' ') { - event.preventDefault(); - } - keysPressed[event.key] = true; - handleKeys(); - }); - - document.addEventListener('keyup', (event) => { - keysPressed[event.key] = false; - }); - - - function updatePlayerPosition() { - player.style.left = playerX + 'px'; - player.style.bottom = playerY + 'px'; + function handleKeys() { + if (keysPressed["ArrowLeft"]) { + playerX -= 10; } - - function updateLives() { - livesElement.textContent = 'Lives: ' + lives; + if (keysPressed["ArrowRight"]) { + playerX += 10; } - - function updateHighScore() { - highScoreElement.textContent = 'High Score: ' + highScore; + if (keysPressed[" "] && !gameOver) { + const currentTime = new Date().getTime(); + if (currentTime - lastProjectileTime >= fireRate) { + shootProjectile(); + lastProjectileTime = currentTime; + } } - - - function shootProjectile() { - const projectile = document.createElement('div'); - projectile.classList.add('projectile'); - projectile.style.backgroundColor = 'black'; - projectile.style.width = projectileWidth + 'px'; - projectile.style.height = projectileHeight + 'px'; - projectile.style.left = (playerX + playerSize / 2 - projectileWidth / 2) + 'px'; - projectile.style.top = (gameContainer.clientHeight - playerY - playerSize) + 'px'; - gameContainer.appendChild(projectile); - projectiles.push(projectile); - } - - - - function spawnPdf() { - const pdf = document.createElement('img'); - pdf.src = 'images/file-earmark-pdf.svg'; - pdf.classList.add('pdf'); - pdf.style.width = pdfSize + 'px'; - pdf.style.height = pdfSize + 'px'; - pdf.style.left = Math.floor(Math.random() * (gameContainer.clientWidth - pdfSize)) + 'px'; - pdf.style.top = '0px'; - gameContainer.appendChild(pdf); - pdfs.push(pdf); - } - - - function resetEnemies() { - pdfs.forEach((pdf) => gameContainer.removeChild(pdf)); - pdfs.length = 0; - } - - - function updateGame() { - if (gameOver || paused) return; - - for (let pdfIndex = 0; pdfIndex < pdfs.length; pdfIndex++) { - const pdf = pdfs[pdfIndex]; - const pdfY = parseFloat(pdf.style.top) + pdfSpeed; - if (pdfY + 50 > gameContainer.clientHeight) { - gameContainer.removeChild(pdf); - pdfs.splice(pdfIndex, 1); - - // Deduct 2 points when a PDF gets past the player - score -= 0; - updateScore(); - - // Decrease lives and check if game over - lives--; - updateLives(); - if (lives <= 0) { - endGame(); - return; - } - - } else { - pdf.style.top = pdfY + 'px'; - - // Check for collision with player - if (collisionDetected(player, pdf)) { - lives--; - updateLives(); - resetEnemies(); - if (lives <= 0) { - endGame(); - return; - } - } - } - }; - - projectiles.forEach((projectile, projectileIndex) => { - const projectileY = parseInt(projectile.style.top) - 10; - if (projectileY < 0) { - gameContainer.removeChild(projectile); - projectiles.splice(projectileIndex, 1); - } else { - projectile.style.top = projectileY + 'px'; - } - - for (let pdfIndex = 0; pdfIndex < pdfs.length; pdfIndex++) { - const pdf = pdfs[pdfIndex]; - if (collisionDetected(projectile, pdf)) { - gameContainer.removeChild(pdf); - gameContainer.removeChild(projectile); - pdfs.splice(pdfIndex, 1); - projectiles.splice(projectileIndex, 1); - score = score + 10; - updateScore(); - break; - } - } - }); - - setTimeout(updateGame, 1000 / 60); - } - - function resetGame() { - playerX = gameContainer.clientWidth / 2; - playerY = 50; - updatePlayerPosition(); - - pdfs.forEach((pdf) => gameContainer.removeChild(pdf)); - projectiles.forEach((projectile) => gameContainer.removeChild(projectile)); - - pdfs.length = 0; - projectiles.length = 0; - - score = 0; - level = 1; - lives = 3; - - gameOver = false; - - updateScore(); - updateLives(); - levelElement.textContent = 'Level: ' + level; - pdfSpeed = 1; - clearTimeout(spawnPdfTimeout); // Clear the existing spawnPdfTimeout - setTimeout(updateGame, 1000 / 60); - spawnPdfInterval(); - } - - - - function updateScore() { - scoreElement.textContent = 'Score: ' + score; - checkLevelUp(); - } - - - - function checkLevelUp() { - const newLevel = Math.floor(score / 100) + 1; - if (newLevel > level) { - level = newLevel; - levelElement.textContent = 'Level: ' + level; - pdfSpeed += 0.2; - } - } - - function collisionDetected(a, b) { - const rectA = a.getBoundingClientRect(); - const rectB = b.getBoundingClientRect(); - return ( - rectA.left < rectB.right && - rectA.right > rectB.left && - rectA.top < rectB.bottom && - rectA.bottom > rectB.top - ); - } - - function endGame() { - gameOver = true; - if (score > highScore) { - highScore = score; - localStorage.setItem('highScore', highScore); - updateHighScore(); - } - alert('Game Over! Your final score is: ' + score); - document.getElementById('game-container-wrapper').close(); - } - - - - - let spawnPdfTimeout; - - const BASE_SPAWN_INTERVAL_MS = 1250; // milliseconds before a new enemy spawns - const LEVEL_INCREASE_FACTOR_MS = 0; // milliseconds to decrease the spawn interval per level - const MAX_SPAWN_RATE_REDUCTION_MS = 800; // Max milliseconds from the base spawn interval - - function spawnPdfInterval() { - console.log("spawnPdfInterval"); - if (gameOver || paused) { - console.log("spawnPdfInterval 2"); - clearTimeout(spawnPdfTimeout); - return; - } - console.log("spawnPdfInterval 3"); - spawnPdf(); - let spawnRateReduction = Math.min(level * LEVEL_INCREASE_FACTOR_MS, MAX_SPAWN_RATE_REDUCTION_MS); - let spawnRate = BASE_SPAWN_INTERVAL_MS - spawnRateReduction; - spawnPdfTimeout = setTimeout(spawnPdfInterval, spawnRate); - } - updatePlayerPosition(); - updateGame(); - spawnPdfInterval(); + } + document.addEventListener("keydown", (event) => { + if (event.key === " ") { + event.preventDefault(); + } + keysPressed[event.key] = true; + handleKeys(); + }); - document.addEventListener('visibilitychange', function() { - if (document.hidden) { - paused = true; - } else { - paused = false; - updateGame(); - spawnPdfInterval(); + document.addEventListener("keyup", (event) => { + keysPressed[event.key] = false; + }); + + function updatePlayerPosition() { + player.style.left = playerX + "px"; + player.style.bottom = playerY + "px"; + } + + function updateLives() { + livesElement.textContent = "Lives: " + lives; + } + + function updateHighScore() { + highScoreElement.textContent = "High Score: " + highScore; + } + + function shootProjectile() { + const projectile = document.createElement("div"); + projectile.classList.add("projectile"); + projectile.style.backgroundColor = "black"; + projectile.style.width = projectileWidth + "px"; + projectile.style.height = projectileHeight + "px"; + projectile.style.left = playerX + playerSize / 2 - projectileWidth / 2 + "px"; + projectile.style.top = gameContainer.clientHeight - playerY - playerSize + "px"; + gameContainer.appendChild(projectile); + projectiles.push(projectile); + } + + function spawnPdf() { + const pdf = document.createElement("img"); + pdf.src = "images/file-earmark-pdf.svg"; + pdf.classList.add("pdf"); + pdf.style.width = pdfSize + "px"; + pdf.style.height = pdfSize + "px"; + pdf.style.left = Math.floor(Math.random() * (gameContainer.clientWidth - pdfSize)) + "px"; + pdf.style.top = "0px"; + gameContainer.appendChild(pdf); + pdfs.push(pdf); + } + + function resetEnemies() { + pdfs.forEach((pdf) => gameContainer.removeChild(pdf)); + pdfs.length = 0; + } + + function updateGame() { + if (gameOver || paused) return; + + for (let pdfIndex = 0; pdfIndex < pdfs.length; pdfIndex++) { + const pdf = pdfs[pdfIndex]; + const pdfY = parseFloat(pdf.style.top) + pdfSpeed; + if (pdfY + 50 > gameContainer.clientHeight) { + gameContainer.removeChild(pdf); + pdfs.splice(pdfIndex, 1); + + // Deduct 2 points when a PDF gets past the player + score -= 0; + updateScore(); + + // Decrease lives and check if game over + lives--; + updateLives(); + if (lives <= 0) { + endGame(); + return; } + } else { + pdf.style.top = pdfY + "px"; + // Check for collision with player + if (collisionDetected(player, pdf)) { + lives--; + updateLives(); + resetEnemies(); + if (lives <= 0) { + endGame(); + return; + } + } + } + } + + projectiles.forEach((projectile, projectileIndex) => { + const projectileY = parseInt(projectile.style.top) - 10; + if (projectileY < 0) { + gameContainer.removeChild(projectile); + projectiles.splice(projectileIndex, 1); + } else { + projectile.style.top = projectileY + "px"; + } + + for (let pdfIndex = 0; pdfIndex < pdfs.length; pdfIndex++) { + const pdf = pdfs[pdfIndex]; + if (collisionDetected(projectile, pdf)) { + gameContainer.removeChild(pdf); + gameContainer.removeChild(projectile); + pdfs.splice(pdfIndex, 1); + projectiles.splice(projectileIndex, 1); + score = score + 10; + updateScore(); + break; + } + } }); - window.resetGame = resetGame; + setTimeout(updateGame, 1000 / 60); + } + + function resetGame() { + playerX = gameContainer.clientWidth / 2; + playerY = 50; + updatePlayerPosition(); + + pdfs.forEach((pdf) => gameContainer.removeChild(pdf)); + projectiles.forEach((projectile) => gameContainer.removeChild(projectile)); + + pdfs.length = 0; + projectiles.length = 0; + + score = 0; + level = 1; + lives = 3; + + gameOver = false; + + updateScore(); + updateLives(); + levelElement.textContent = "Level: " + level; + pdfSpeed = 1; + clearTimeout(spawnPdfTimeout); // Clear the existing spawnPdfTimeout + setTimeout(updateGame, 1000 / 60); + spawnPdfInterval(); + } + + function updateScore() { + scoreElement.textContent = "Score: " + score; + checkLevelUp(); + } + + function checkLevelUp() { + const newLevel = Math.floor(score / 100) + 1; + if (newLevel > level) { + level = newLevel; + levelElement.textContent = "Level: " + level; + pdfSpeed += 0.2; + } + } + + function collisionDetected(a, b) { + const rectA = a.getBoundingClientRect(); + const rectB = b.getBoundingClientRect(); + return rectA.left < rectB.right && rectA.right > rectB.left && rectA.top < rectB.bottom && rectA.bottom > rectB.top; + } + + function endGame() { + gameOver = true; + if (score > highScore) { + highScore = score; + localStorage.setItem("highScore", highScore); + updateHighScore(); + } + alert("Game Over! Your final score is: " + score); + document.getElementById("game-container-wrapper").close(); + } + + let spawnPdfTimeout; + + const BASE_SPAWN_INTERVAL_MS = 1250; // milliseconds before a new enemy spawns + const LEVEL_INCREASE_FACTOR_MS = 0; // milliseconds to decrease the spawn interval per level + const MAX_SPAWN_RATE_REDUCTION_MS = 800; // Max milliseconds from the base spawn interval + + function spawnPdfInterval() { + console.log("spawnPdfInterval"); + if (gameOver || paused) { + console.log("spawnPdfInterval 2"); + clearTimeout(spawnPdfTimeout); + return; + } + console.log("spawnPdfInterval 3"); + spawnPdf(); + let spawnRateReduction = Math.min(level * LEVEL_INCREASE_FACTOR_MS, MAX_SPAWN_RATE_REDUCTION_MS); + let spawnRate = BASE_SPAWN_INTERVAL_MS - spawnRateReduction; + spawnPdfTimeout = setTimeout(spawnPdfInterval, spawnRate); + } + + updatePlayerPosition(); + updateGame(); + spawnPdfInterval(); + + document.addEventListener("visibilitychange", function () { + if (document.hidden) { + paused = true; + } else { + paused = false; + updateGame(); + spawnPdfInterval(); + } + }); + + window.resetGame = resetGame; } window.initializeGame = initializeGame; diff --git a/src/main/resources/static/js/githubVersion.js b/src/main/resources/static/js/githubVersion.js index 6400d5cf..e17524d5 100644 --- a/src/main/resources/static/js/githubVersion.js +++ b/src/main/resources/static/js/githubVersion.js @@ -1,55 +1,52 @@ function compareVersions(version1, version2) { - const v1 = version1.split('.'); - const v2 = version2.split('.'); + const v1 = version1.split("."); + const v2 = version2.split("."); - for (let i = 0; i < v1.length || i < v2.length; i++) { - const n1 = parseInt(v1[i]) || 0; - const n2 = parseInt(v2[i]) || 0; + for (let i = 0; i < v1.length || i < v2.length; i++) { + const n1 = parseInt(v1[i]) || 0; + const n2 = parseInt(v2[i]) || 0; - if (n1 > n2) { - return 1; - } else if (n1 < n2) { - return -1; - } - } + if (n1 > n2) { + return 1; + } else if (n1 < n2) { + return -1; + } + } - return 0; + return 0; } - async function getLatestReleaseVersion() { - const url = "https://api.github.com/repos/Stirling-Tools/Stirling-PDF/releases/latest"; - try { - const response = await fetch(url); - const data = await response.json(); - return data.tag_name ? data.tag_name.substring(1) : ""; - } catch (error) { - console.error("Failed to fetch latest version:", error); - return ""; // Return an empty string if the fetch fails - } + const url = "https://api.github.com/repos/Stirling-Tools/Stirling-PDF/releases/latest"; + try { + const response = await fetch(url); + const data = await response.json(); + return data.tag_name ? data.tag_name.substring(1) : ""; + } catch (error) { + console.error("Failed to fetch latest version:", error); + return ""; // Return an empty string if the fetch fails + } } async function checkForUpdate() { - // Initialize the update button as hidden - var updateBtn = document.getElementById("update-btn"); - if (updateBtn !== null) { - updateBtn.style.display = "none"; - } + // Initialize the update button as hidden + var updateBtn = document.getElementById("update-btn"); + if (updateBtn !== null) { + updateBtn.style.display = "none"; + } - - const latestVersion = await getLatestReleaseVersion(); - console.log("latestVersion=" + latestVersion) - console.log("currentVersion=" + currentVersion) - console.log("compareVersions(latestVersion, currentVersion) > 0)=" + compareVersions(latestVersion, currentVersion)) - if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) { - document.getElementById("update-btn").style.display = "block"; - console.log("visible") - } else { - console.log("hidden") - } + const latestVersion = await getLatestReleaseVersion(); + console.log("latestVersion=" + latestVersion); + console.log("currentVersion=" + currentVersion); + console.log("compareVersions(latestVersion, currentVersion) > 0)=" + compareVersions(latestVersion, currentVersion)); + if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) { + document.getElementById("update-btn").style.display = "block"; + console.log("visible"); + } else { + console.log("hidden"); + } } - -document.addEventListener('DOMContentLoaded', (event) => { - checkForUpdate(); +document.addEventListener("DOMContentLoaded", (event) => { + checkForUpdate(); }); diff --git a/src/main/resources/static/js/homecard.js b/src/main/resources/static/js/homecard.js index 6fb43387..8ac2ef44 100644 --- a/src/main/resources/static/js/homecard.js +++ b/src/main/resources/static/js/homecard.js @@ -1,78 +1,76 @@ function filterCards() { - var input = document.getElementById('searchBar'); - var filter = input.value.toUpperCase(); - var cards = document.querySelectorAll('.feature-card'); + var input = document.getElementById("searchBar"); + var filter = input.value.toUpperCase(); + var cards = document.querySelectorAll(".feature-card"); - for (var i = 0; i < cards.length; i++) { - var card = cards[i]; - var title = card.querySelector('h5.card-title').innerText; - var text = card.querySelector('p.card-text').innerText; + for (var i = 0; i < cards.length; i++) { + var card = cards[i]; + var title = card.querySelector("h5.card-title").innerText; + var text = card.querySelector("p.card-text").innerText; - // Get the navbar tags associated with the card - var navbarItem = document.querySelector(`a.dropdown-item[href="${card.id}"]`); - var navbarTags = navbarItem ? navbarItem.getAttribute('data-bs-tags') : ''; + // Get the navbar tags associated with the card + var navbarItem = document.querySelector(`a.dropdown-item[href="${card.id}"]`); + var navbarTags = navbarItem ? navbarItem.getAttribute("data-bs-tags") : ""; - var content = title + ' ' + text + ' ' + navbarTags; + var content = title + " " + text + " " + navbarTags; - if (content.toUpperCase().indexOf(filter) > -1) { - card.style.display = ""; - } else { - card.style.display = "none"; - } + if (content.toUpperCase().indexOf(filter) > -1) { + card.style.display = ""; + } else { + card.style.display = "none"; } + } } - - function toggleFavorite(element) { - var img = element.querySelector('img'); - var card = element.closest('.feature-card'); - var cardId = card.id; - if (img.src.endsWith('star.svg')) { - img.src = 'images/star-fill.svg'; - card.classList.add('favorite'); - localStorage.setItem(cardId, 'favorite'); - } else { - img.src = 'images/star.svg'; - card.classList.remove('favorite'); - localStorage.removeItem(cardId); - } - reorderCards(); - updateFavoritesDropdown(); - filterCards(); + var img = element.querySelector("img"); + var card = element.closest(".feature-card"); + var cardId = card.id; + if (img.src.endsWith("star.svg")) { + img.src = "images/star-fill.svg"; + card.classList.add("favorite"); + localStorage.setItem(cardId, "favorite"); + } else { + img.src = "images/star.svg"; + card.classList.remove("favorite"); + localStorage.removeItem(cardId); + } + reorderCards(); + updateFavoritesDropdown(); + filterCards(); } function reorderCards() { - var container = document.querySelector('.features-container'); - var cards = Array.from(container.getElementsByClassName('feature-card')); - cards.sort(function(a, b) { - var aIsFavorite = localStorage.getItem(a.id) === 'favorite'; - var bIsFavorite = localStorage.getItem(b.id) === 'favorite'; - if (aIsFavorite && !bIsFavorite) { - return -1; - } - if (!aIsFavorite && bIsFavorite) { - return 1; - } - return 0; - }); - cards.forEach(function(card) { - container.appendChild(card); - }); + var container = document.querySelector(".features-container"); + var cards = Array.from(container.getElementsByClassName("feature-card")); + cards.sort(function (a, b) { + var aIsFavorite = localStorage.getItem(a.id) === "favorite"; + var bIsFavorite = localStorage.getItem(b.id) === "favorite"; + if (aIsFavorite && !bIsFavorite) { + return -1; + } + if (!aIsFavorite && bIsFavorite) { + return 1; + } + return 0; + }); + cards.forEach(function (card) { + container.appendChild(card); + }); } function initializeCards() { - var cards = document.querySelectorAll('.feature-card'); - cards.forEach(function(card) { - var cardId = card.id; - var img = card.querySelector('.favorite-icon img'); - if (localStorage.getItem(cardId) === 'favorite') { - img.src = 'images/star-fill.svg'; - card.classList.add('favorite'); - } - }); - reorderCards(); - updateFavoritesDropdown(); - filterCards(); + var cards = document.querySelectorAll(".feature-card"); + cards.forEach(function (card) { + var cardId = card.id; + var img = card.querySelector(".favorite-icon img"); + if (localStorage.getItem(cardId) === "favorite") { + img.src = "images/star-fill.svg"; + card.classList.add("favorite"); + } + }); + reorderCards(); + updateFavoritesDropdown(); + filterCards(); } -window.onload = initializeCards; \ No newline at end of file +window.onload = initializeCards; diff --git a/src/main/resources/static/js/languageSelection.js b/src/main/resources/static/js/languageSelection.js index 4cc18f12..af67da48 100644 --- a/src/main/resources/static/js/languageSelection.js +++ b/src/main/resources/static/js/languageSelection.js @@ -1,80 +1,88 @@ -document.addEventListener('DOMContentLoaded', function() { - setLanguageForDropdown('.lang_dropdown-item'); +document.addEventListener("DOMContentLoaded", function () { + setLanguageForDropdown(".lang_dropdown-item"); - // Detect the browser's preferred language - let browserLang = navigator.language || navigator.userLanguage; - // Convert to a format consistent with your language codes (e.g., en-GB, fr-FR) - browserLang = browserLang.replace('-', '_'); + // Detect the browser's preferred language + let browserLang = navigator.language || navigator.userLanguage; + // Convert to a format consistent with your language codes (e.g., en-GB, fr-FR) + browserLang = browserLang.replace("-", "_"); - // Check if the dropdown contains the browser's language - const dropdownLangExists = document.querySelector(`.lang_dropdown-item[data-language-code="${browserLang}"]`); + // Check if the dropdown contains the browser's language + const dropdownLangExists = document.querySelector(`.lang_dropdown-item[data-language-code="${browserLang}"]`); - // Set the default language to browser's language or 'en_GB' if not found in the dropdown - const defaultLocale = dropdownLangExists ? browserLang : 'en_GB'; - const storedLocale = localStorage.getItem('languageCode') || defaultLocale; + // Set the default language to browser's language or 'en_GB' if not found in the dropdown + const defaultLocale = dropdownLangExists ? browserLang : "en_GB"; + const storedLocale = localStorage.getItem("languageCode") || defaultLocale; + const dropdownItems = document.querySelectorAll(".lang_dropdown-item"); - - const dropdownItems = document.querySelectorAll('.lang_dropdown-item'); - - for (let i = 0; i < dropdownItems.length; i++) { - const item = dropdownItems[i]; - item.classList.remove('active'); - if (item.dataset.languageCode === storedLocale) { - item.classList.add('active'); - } - item.addEventListener('click', handleDropdownItemClick); - } + for (let i = 0; i < dropdownItems.length; i++) { + const item = dropdownItems[i]; + item.classList.remove("active"); + if (item.dataset.languageCode === storedLocale) { + item.classList.add("active"); + } + item.addEventListener("click", handleDropdownItemClick); + } }); function setLanguageForDropdown(dropdownClass) { - const defaultLocale = document.documentElement.lang || 'en_GB'; - const storedLocale = localStorage.getItem('languageCode') || defaultLocale; - const dropdownItems = document.querySelectorAll(dropdownClass); + const defaultLocale = document.documentElement.lang || "en_GB"; + const storedLocale = localStorage.getItem("languageCode") || defaultLocale; + const dropdownItems = document.querySelectorAll(dropdownClass); - for (let i = 0; i < dropdownItems.length; i++) { - const item = dropdownItems[i]; - item.classList.remove('active'); - if (item.dataset.languageCode === storedLocale) { - item.classList.add('active'); - } - item.addEventListener('click', handleDropdownItemClick); + for (let i = 0; i < dropdownItems.length; i++) { + const item = dropdownItems[i]; + item.classList.remove("active"); + if (item.dataset.languageCode === storedLocale) { + item.classList.add("active"); } + item.addEventListener("click", handleDropdownItemClick); + } } function handleDropdownItemClick(event) { - event.preventDefault(); - const languageCode = event.currentTarget.dataset.bsLanguageCode; // change this to event.currentTarget - if (languageCode) { - localStorage.setItem('languageCode', languageCode); + event.preventDefault(); + const languageCode = event.currentTarget.dataset.bsLanguageCode; // change this to event.currentTarget + if (languageCode) { + localStorage.setItem("languageCode", languageCode); - const currentUrl = window.location.href; - if (currentUrl.indexOf('?lang=') === -1) { - window.location.href = currentUrl + '?lang=' + languageCode; - } else { - window.location.href = currentUrl.replace(/\?lang=\w{2,}/, '?lang=' + languageCode); - } + const currentUrl = window.location.href; + if (currentUrl.indexOf("?lang=") === -1) { + window.location.href = currentUrl + "?lang=" + languageCode; } else { - console.error("Language code is not set for this item."); // for debugging + window.location.href = currentUrl.replace(/\?lang=\w{2,}/, "?lang=" + languageCode); } + } else { + console.error("Language code is not set for this item."); // for debugging + } } +document.addEventListener("DOMContentLoaded", function () { + document.querySelectorAll(".nav-item.dropdown").forEach((element) => { + const dropdownMenu = element.querySelector(".dropdown-menu"); + if ( + dropdownMenu.id !== "favoritesDropdown" && + dropdownMenu.children.length <= 2 && + dropdownMenu.querySelectorAll("hr.dropdown-divider").length === dropdownMenu.children.length + ) { + if ( + element.previousElementSibling && + element.previousElementSibling.classList.contains("nav-item") && + element.previousElementSibling.classList.contains("nav-item-separator") + ) { + element.previousElementSibling.remove(); + } + element.remove(); + } + }); -document.addEventListener('DOMContentLoaded', function() { - document.querySelectorAll('.nav-item.dropdown').forEach((element) => { - const dropdownMenu = element.querySelector(".dropdown-menu"); - if (dropdownMenu.id !== 'favoritesDropdown' && dropdownMenu.children.length <= 2 && dropdownMenu.querySelectorAll("hr.dropdown-divider").length === dropdownMenu.children.length) { - if (element.previousElementSibling && element.previousElementSibling.classList.contains('nav-item') && element.previousElementSibling.classList.contains('nav-item-separator')) { - element.previousElementSibling.remove(); - } - element.remove(); - } - }); - - //Sort languages by alphabet - const list = Array.from(document.querySelector('.dropdown-menu[aria-labelledby="languageDropdown"]').children).filter(child => child.matches('a')); - list.sort(function(a, b) { - return a.textContent.toUpperCase().localeCompare(b.textContent.toUpperCase()); - }).forEach(node => document.querySelector('.dropdown-menu[aria-labelledby="languageDropdown"]').appendChild(node)); - -}); \ No newline at end of file + //Sort languages by alphabet + const list = Array.from(document.querySelector('.dropdown-menu[aria-labelledby="languageDropdown"]').children).filter( + (child) => child.matches("a"), + ); + list + .sort(function (a, b) { + return a.textContent.toUpperCase().localeCompare(b.textContent.toUpperCase()); + }) + .forEach((node) => document.querySelector('.dropdown-menu[aria-labelledby="languageDropdown"]').appendChild(node)); +}); diff --git a/src/main/resources/static/js/local-pdf-input-download.js b/src/main/resources/static/js/local-pdf-input-download.js index 37090390..44793884 100644 --- a/src/main/resources/static/js/local-pdf-input-download.js +++ b/src/main/resources/static/js/local-pdf-input-download.js @@ -1,47 +1,47 @@ async function downloadFilesWithCallback(processFileCallback) { - const fileInput = document.querySelector('input[type="file"]'); - const files = fileInput.files; + const fileInput = document.querySelector('input[type="file"]'); + const files = fileInput.files; - const zipThreshold = 4; - const zipFiles = files.length > zipThreshold; + const zipThreshold = 4; + const zipFiles = files.length > zipThreshold; - let jszip = null; - if (zipFiles) { - jszip = new JSZip(); - } + let jszip = null; + if (zipFiles) { + jszip = new JSZip(); + } - const promises = Array.from(files).map(async file => { - const { processedData, fileName } = await processFileCallback(file); - - if (zipFiles) { - jszip.file(fileName, processedData); - } else { - const url = URL.createObjectURL(processedData); - const downloadOption = localStorage.getItem('downloadOption'); - - if (downloadOption === 'sameWindow') { - window.location.href = url; - } else if (downloadOption === 'newWindow') { - window.open(url, '_blank'); - } else { - const downloadLink = document.createElement('a'); - downloadLink.href = url; - downloadLink.download = fileName; - downloadLink.click(); - } - } - }); - - await Promise.all(promises); + const promises = Array.from(files).map(async (file) => { + const { processedData, fileName } = await processFileCallback(file); if (zipFiles) { - const content = await jszip.generateAsync({ type: "blob" }); - const url = URL.createObjectURL(content); - const a = document.createElement('a'); - a.href = url; - a.download = "files.zip"; - document.body.appendChild(a); - a.click(); - a.remove(); + jszip.file(fileName, processedData); + } else { + const url = URL.createObjectURL(processedData); + const downloadOption = localStorage.getItem("downloadOption"); + + if (downloadOption === "sameWindow") { + window.location.href = url; + } else if (downloadOption === "newWindow") { + window.open(url, "_blank"); + } else { + const downloadLink = document.createElement("a"); + downloadLink.href = url; + downloadLink.download = fileName; + downloadLink.click(); + } } + }); + + await Promise.all(promises); + + if (zipFiles) { + const content = await jszip.generateAsync({ type: "blob" }); + const url = URL.createObjectURL(content); + const a = document.createElement("a"); + a.href = url; + a.download = "files.zip"; + document.body.appendChild(a); + a.click(); + a.remove(); + } } diff --git a/src/main/resources/static/js/merge.js b/src/main/resources/static/js/merge.js index e8e60d4f..4936fa6b 100644 --- a/src/main/resources/static/js/merge.js +++ b/src/main/resources/static/js/merge.js @@ -1,27 +1,27 @@ let currentSort = { - field: null, - descending: false + field: null, + descending: false, }; -document.getElementById("fileInput-input").addEventListener("change", function() { - var files = this.files; - displayFiles(files); +document.getElementById("fileInput-input").addEventListener("change", function () { + var files = this.files; + displayFiles(files); }); /** * @param {FileList} files */ function displayFiles(files) { - const list = document.getElementById("selectedFiles"); + const list = document.getElementById("selectedFiles"); - while (list.firstChild) { - list.removeChild(list.firstChild); - } + while (list.firstChild) { + list.removeChild(list.firstChild); + } - for (let i = 0; i < files.length; i++) { - const item = document.createElement("li"); - item.className = "list-group-item"; - item.innerHTML = ` + for (let i = 0; i < files.length; i++) { + const item = document.createElement("li"); + item.className = "list-group-item"; + item.innerHTML = `
${files[i].name}
@@ -31,100 +31,100 @@ function displayFiles(files) {
`; - list.appendChild(item); - } + list.appendChild(item); + } - attachMoveButtons(); + attachMoveButtons(); } function attachMoveButtons() { - var moveUpButtons = document.querySelectorAll(".move-up"); - for (var i = 0; i < moveUpButtons.length; i++) { - moveUpButtons[i].addEventListener("click", function(event) { - event.preventDefault(); - var parent = this.closest(".list-group-item"); - var grandParent = parent.parentNode; - if (parent.previousElementSibling) { - grandParent.insertBefore(parent, parent.previousElementSibling); - updateFiles(); - } - }); - } + var moveUpButtons = document.querySelectorAll(".move-up"); + for (var i = 0; i < moveUpButtons.length; i++) { + moveUpButtons[i].addEventListener("click", function (event) { + event.preventDefault(); + var parent = this.closest(".list-group-item"); + var grandParent = parent.parentNode; + if (parent.previousElementSibling) { + grandParent.insertBefore(parent, parent.previousElementSibling); + updateFiles(); + } + }); + } - var moveDownButtons = document.querySelectorAll(".move-down"); - for (var i = 0; i < moveDownButtons.length; i++) { - moveDownButtons[i].addEventListener("click", function(event) { - event.preventDefault(); - var parent = this.closest(".list-group-item"); - var grandParent = parent.parentNode; - if (parent.nextElementSibling) { - grandParent.insertBefore(parent.nextElementSibling, parent); - updateFiles(); - } - }); - } + var moveDownButtons = document.querySelectorAll(".move-down"); + for (var i = 0; i < moveDownButtons.length; i++) { + moveDownButtons[i].addEventListener("click", function (event) { + event.preventDefault(); + var parent = this.closest(".list-group-item"); + var grandParent = parent.parentNode; + if (parent.nextElementSibling) { + grandParent.insertBefore(parent.nextElementSibling, parent); + updateFiles(); + } + }); + } - var removeButtons = document.querySelectorAll(".remove-file"); - for (var i = 0; i < removeButtons.length; i++) { - removeButtons[i].addEventListener("click", function (event) { - event.preventDefault(); - var parent = this.closest(".list-group-item"); - parent.remove(); - updateFiles(); - }); - } + var removeButtons = document.querySelectorAll(".remove-file"); + for (var i = 0; i < removeButtons.length; i++) { + removeButtons[i].addEventListener("click", function (event) { + event.preventDefault(); + var parent = this.closest(".list-group-item"); + parent.remove(); + updateFiles(); + }); + } } -document.getElementById("sortByNameBtn").addEventListener("click", function() { - if (currentSort.field === "name" && !currentSort.descending) { - currentSort.descending = true; - sortFiles((a, b) => b.name.localeCompare(a.name)); - } else { - currentSort.field = "name"; - currentSort.descending = false; - sortFiles((a, b) => a.name.localeCompare(b.name)); - } +document.getElementById("sortByNameBtn").addEventListener("click", function () { + if (currentSort.field === "name" && !currentSort.descending) { + currentSort.descending = true; + sortFiles((a, b) => b.name.localeCompare(a.name)); + } else { + currentSort.field = "name"; + currentSort.descending = false; + sortFiles((a, b) => a.name.localeCompare(b.name)); + } }); -document.getElementById("sortByDateBtn").addEventListener("click", function() { - if (currentSort.field === "lastModified" && !currentSort.descending) { - currentSort.descending = true; - sortFiles((a, b) => b.lastModified - a.lastModified); - } else { - currentSort.field = "lastModified"; - currentSort.descending = false; - sortFiles((a, b) => a.lastModified - b.lastModified); - } +document.getElementById("sortByDateBtn").addEventListener("click", function () { + if (currentSort.field === "lastModified" && !currentSort.descending) { + currentSort.descending = true; + sortFiles((a, b) => b.lastModified - a.lastModified); + } else { + currentSort.field = "lastModified"; + currentSort.descending = false; + sortFiles((a, b) => a.lastModified - b.lastModified); + } }); function sortFiles(comparator) { - // Convert FileList to array and sort - const sortedFilesArray = Array.from(document.getElementById("fileInput-input").files).sort(comparator); + // Convert FileList to array and sort + const sortedFilesArray = Array.from(document.getElementById("fileInput-input").files).sort(comparator); - // Refresh displayed list - displayFiles(sortedFilesArray); + // Refresh displayed list + displayFiles(sortedFilesArray); - // Update the files property - const dataTransfer = new DataTransfer(); - sortedFilesArray.forEach(file => dataTransfer.items.add(file)); - document.getElementById("fileInput-input").files = dataTransfer.files; + // Update the files property + const dataTransfer = new DataTransfer(); + sortedFilesArray.forEach((file) => dataTransfer.items.add(file)); + document.getElementById("fileInput-input").files = dataTransfer.files; } function updateFiles() { - var dataTransfer = new DataTransfer(); - var liElements = document.querySelectorAll("#selectedFiles li"); - const files = document.getElementById("fileInput-input").files; + var dataTransfer = new DataTransfer(); + var liElements = document.querySelectorAll("#selectedFiles li"); + const files = document.getElementById("fileInput-input").files; - for (var i = 0; i < liElements.length; i++) { - var fileNameFromList = liElements[i].querySelector(".filename").innerText; - var fileFromFiles; - for (var j = 0; j < files.length; j++) { - var file = files[j]; - if (file.name === fileNameFromList) { - dataTransfer.items.add(file); - break; - } - } + for (var i = 0; i < liElements.length; i++) { + var fileNameFromList = liElements[i].querySelector(".filename").innerText; + var fileFromFiles; + for (var j = 0; j < files.length; j++) { + var file = files[j]; + if (file.name === fileNameFromList) { + dataTransfer.items.add(file); + break; + } } - document.getElementById("fileInput-input").files = dataTransfer.files; + } + document.getElementById("fileInput-input").files = dataTransfer.files; } diff --git a/src/main/resources/static/js/multitool/DragDropManager.js b/src/main/resources/static/js/multitool/DragDropManager.js index 2481adf1..004412d4 100644 --- a/src/main/resources/static/js/multitool/DragDropManager.js +++ b/src/main/resources/static/js/multitool/DragDropManager.js @@ -1,125 +1,123 @@ class DragDropManager { - dragContainer; - wrapper; - pageDirection; - movePageTo; - pageDragging; - draggelEl; - draggedImageEl; - hoveredEl; - endInsertionElement; + dragContainer; + wrapper; + pageDirection; + movePageTo; + pageDragging; + draggelEl; + draggedImageEl; + hoveredEl; + endInsertionElement; - constructor(id, wrapperId) { - this.dragContainer = document.getElementById(id); - this.pageDirection = document.documentElement.getAttribute("lang-direction"); - this.wrapper = document.getElementById(wrapperId); - this.pageDragging = false; - this.hoveredEl = undefined; - this.draggelEl = undefined - this.draggedImageEl = undefined; + constructor(id, wrapperId) { + this.dragContainer = document.getElementById(id); + this.pageDirection = document.documentElement.getAttribute("lang-direction"); + this.wrapper = document.getElementById(wrapperId); + this.pageDragging = false; + this.hoveredEl = undefined; + this.draggelEl = undefined; + this.draggedImageEl = undefined; - var styleElement = document.createElement('link'); - styleElement.rel = 'stylesheet'; - styleElement.href = 'css/dragdrop.css' + var styleElement = document.createElement("link"); + styleElement.rel = "stylesheet"; + styleElement.href = "css/dragdrop.css"; - document.head.appendChild(styleElement); + document.head.appendChild(styleElement); - const div = document.createElement('div'); - div.classList.add('drag-manager_endpoint'); - div.innerHTML = ` + const div = document.createElement("div"); + div.classList.add("drag-manager_endpoint"); + div.innerHTML = ` - ` - this.endInsertionElement = div; + `; + this.endInsertionElement = div; - this.startDraggingPage = this.startDraggingPage.bind(this); - this.onDragEl = this.onDragEl.bind(this); - this.stopDraggingPage = this.stopDraggingPage.bind(this); + this.startDraggingPage = this.startDraggingPage.bind(this); + this.onDragEl = this.onDragEl.bind(this); + this.stopDraggingPage = this.stopDraggingPage.bind(this); - this.adapt(div); + this.adapt(div); + } + + startDraggingPage(div) { + this.pageDragging = true; + this.draggedEl = div; + const img = div.querySelector("img"); + div.classList.add("drag-manager_dragging"); + const imageSrc = img.src; + + const imgEl = document.createElement("img"); + imgEl.classList.add("dragged-img"); + imgEl.src = imageSrc; + this.draggedImageEl = imgEl; + imgEl.style.visibility = "hidden"; + imgEl.style.transform = `rotate(${img.style.rotate === "" ? "0deg" : img.style.rotate}) translate(-50%, -50%)`; + this.dragContainer.appendChild(imgEl); + + window.addEventListener("mouseup", this.stopDraggingPage); + window.addEventListener("mousemove", this.onDragEl); + this.wrapper.classList.add("drag-manager_dragging-container"); + this.wrapper.appendChild(this.endInsertionElement); + } + + onDragEl(mouseEvent) { + const { clientX, clientY } = mouseEvent; + if (this.draggedImageEl) { + this.draggedImageEl.style.visibility = "visible"; + this.draggedImageEl.style.left = `${clientX}px`; + this.draggedImageEl.style.top = `${clientY}px`; } + } - startDraggingPage(div,) { - this.pageDragging = true; - this.draggedEl = div; - const img = div.querySelector('img'); - div.classList.add('drag-manager_dragging'); - const imageSrc = img.src; - - const imgEl = document.createElement('img'); - imgEl.classList.add('dragged-img'); - imgEl.src = imageSrc; - this.draggedImageEl = imgEl; - imgEl.style.visibility = 'hidden'; - imgEl.style.transform = `rotate(${img.style.rotate === '' ? '0deg' : img.style.rotate}) translate(-50%, -50%)`; - this.dragContainer.appendChild(imgEl); - - window.addEventListener('mouseup', this.stopDraggingPage) - window.addEventListener('mousemove', this.onDragEl) - this.wrapper.classList.add('drag-manager_dragging-container'); - this.wrapper.appendChild(this.endInsertionElement); + stopDraggingPage() { + window.removeEventListener("mousemove", this.onDragEl); + this.wrapper.classList.remove("drag-manager_dragging-container"); + this.wrapper.removeChild(this.endInsertionElement); + window.removeEventListener("mouseup", this.stopDraggingPage); + this.draggedImageEl = undefined; + this.pageDragging = false; + this.draggedEl.classList.remove("drag-manager_dragging"); + this.hoveredEl?.classList.remove("drag-manager_draghover"); + this.dragContainer.childNodes.forEach((dragChild) => { + this.dragContainer.removeChild(dragChild); + }); + if (!this.hoveredEl) { + return; } - - onDragEl(mouseEvent) { - const { clientX, clientY } = mouseEvent; - if(this.draggedImageEl) { - this.draggedImageEl.style.visibility = 'visible'; - this.draggedImageEl.style.left = `${clientX}px`; - this.draggedImageEl.style.top = `${clientY}px`; - } + if (this.hoveredEl === this.endInsertionElement) { + this.movePageTo(this.draggedEl); + return; } + this.movePageTo(this.draggedEl, this.hoveredEl); + } + setActions({ movePageTo }) { + this.movePageTo = movePageTo; + } - stopDraggingPage() { - window.removeEventListener('mousemove', this.onDragEl); - this.wrapper.classList.remove('drag-manager_dragging-container'); - this.wrapper.removeChild(this.endInsertionElement); - window.removeEventListener('mouseup', this.stopDraggingPage) - this.draggedImageEl = undefined; - this.pageDragging = false; - this.draggedEl.classList.remove('drag-manager_dragging'); - this.hoveredEl?.classList.remove('drag-manager_draghover'); - this.dragContainer.childNodes.forEach((dragChild) => { - this.dragContainer.removeChild(dragChild); - }) - if(!this.hoveredEl) { - return; - } - if(this.hoveredEl === this.endInsertionElement) { - this.movePageTo(this.draggedEl); - return; - } - this.movePageTo(this.draggedEl, this.hoveredEl); - } + adapt(div) { + const onDragStart = () => { + this.startDraggingPage(div); + }; - setActions({ movePageTo }) { - this.movePageTo = movePageTo; - } + const onMouseEnter = () => { + if (this.pageDragging) { + this.hoveredEl = div; + div.classList.add("drag-manager_draghover"); + } + }; + const onMouseLeave = () => { + this.hoveredEl = undefined; + div.classList.remove("drag-manager_draghover"); + }; - adapt(div) { - const onDragStart = () => { - this.startDraggingPage(div); - } + div.addEventListener("dragstart", onDragStart); + div.addEventListener("mouseenter", onMouseEnter); + div.addEventListener("mouseleave", onMouseLeave); - const onMouseEnter = () => { - if (this.pageDragging) { - this.hoveredEl = div; - div.classList.add('drag-manager_draghover'); - } - } - - const onMouseLeave = () => { - this.hoveredEl = undefined - div.classList.remove('drag-manager_draghover'); - } - - div.addEventListener('dragstart', onDragStart); - div.addEventListener('mouseenter', onMouseEnter); - div.addEventListener('mouseleave', onMouseLeave); - - return div; - } + return div; + } } export default DragDropManager; diff --git a/src/main/resources/static/js/multitool/ImageHighlighter.js b/src/main/resources/static/js/multitool/ImageHighlighter.js index 6f7cd22e..b72df3bb 100644 --- a/src/main/resources/static/js/multitool/ImageHighlighter.js +++ b/src/main/resources/static/js/multitool/ImageHighlighter.js @@ -1,46 +1,46 @@ class ImageHiglighter { - imageHighlighter; - constructor(id) { - this.imageHighlighter = document.getElementById(id); - this.imageHighlightCallback = this.imageHighlightCallback.bind(this); + imageHighlighter; + constructor(id) { + this.imageHighlighter = document.getElementById(id); + this.imageHighlightCallback = this.imageHighlightCallback.bind(this); - var styleElement = document.createElement('link'); - styleElement.rel = 'stylesheet'; - styleElement.href = 'css/imageHighlighter.css' + var styleElement = document.createElement("link"); + styleElement.rel = "stylesheet"; + styleElement.href = "css/imageHighlighter.css"; - document.head.appendChild(styleElement); + document.head.appendChild(styleElement); - this.imageHighlighter.onclick = () => { - this.imageHighlighter.childNodes.forEach((child) => { - child.classList.add('remove'); - setTimeout(() => { - this.imageHighlighter.removeChild(child); - }, 100) - }) - } - } - - imageHighlightCallback(highlightEvent) { - var bigImg = document.createElement('img'); - bigImg.onclick = (imageClickEvent) => { - // This prevents the highlighter's onClick from closing the image when clicking - // on the image instead of next to it. - imageClickEvent.preventDefault(); - imageClickEvent.stopPropagation(); - }; - bigImg.src = highlightEvent.target.src; - this.imageHighlighter.appendChild(bigImg); + this.imageHighlighter.onclick = () => { + this.imageHighlighter.childNodes.forEach((child) => { + child.classList.add("remove"); + setTimeout(() => { + this.imageHighlighter.removeChild(child); + }, 100); + }); }; + } - setActions() { - // not needed in this case - } + imageHighlightCallback(highlightEvent) { + var bigImg = document.createElement("img"); + bigImg.onclick = (imageClickEvent) => { + // This prevents the highlighter's onClick from closing the image when clicking + // on the image instead of next to it. + imageClickEvent.preventDefault(); + imageClickEvent.stopPropagation(); + }; + bigImg.src = highlightEvent.target.src; + this.imageHighlighter.appendChild(bigImg); + } - adapt(div) { - const img = div.querySelector('.page-image'); - img.addEventListener('click', this.imageHighlightCallback) - return div; - } + setActions() { + // not needed in this case + } + + adapt(div) { + const img = div.querySelector(".page-image"); + img.addEventListener("click", this.imageHighlightCallback); + return div; + } } -export default ImageHiglighter; \ No newline at end of file +export default ImageHiglighter; diff --git a/src/main/resources/static/js/multitool/PdfActionsManager.js b/src/main/resources/static/js/multitool/PdfActionsManager.js index b77d2121..2fae22d3 100644 --- a/src/main/resources/static/js/multitool/PdfActionsManager.js +++ b/src/main/resources/static/js/multitool/PdfActionsManager.js @@ -1,198 +1,200 @@ class PdfActionsManager { - pageDirection; - pagesContainer; + pageDirection; + pagesContainer; - constructor(id) { - this.pagesContainer = document.getElementById(id); - this.pageDirection = document.documentElement.getAttribute("lang-direction"); + constructor(id) { + this.pagesContainer = document.getElementById(id); + this.pageDirection = document.documentElement.getAttribute("lang-direction"); - var styleElement = document.createElement('link'); - styleElement.rel = 'stylesheet'; - styleElement.href = 'css/pdfActions.css' + var styleElement = document.createElement("link"); + styleElement.rel = "stylesheet"; + styleElement.href = "css/pdfActions.css"; - document.head.appendChild(styleElement); + document.head.appendChild(styleElement); + } + + getPageContainer(element) { + var container = element; + while (!container.classList.contains("page-container")) { + container = container.parentNode; } + return container; + } - getPageContainer(element) { - var container = element - while (!container.classList.contains('page-container')) { - container = container.parentNode; - } - return container; + moveUpButtonCallback(e) { + var imgContainer = this.getPageContainer(e.target); + + const sibling = imgContainer.previousSibling; + if (sibling) { + this.movePageTo(imgContainer, sibling, true); } + } - moveUpButtonCallback(e) { - var imgContainer = this.getPageContainer(e.target); - - const sibling = imgContainer.previousSibling; - if (sibling) { - this.movePageTo(imgContainer, sibling, true); - } + moveDownButtonCallback(e) { + var imgContainer = this.getPageContainer(e.target); + const sibling = imgContainer.nextSibling; + if (sibling) { + this.movePageTo(imgContainer, sibling.nextSibling, true); } + } - moveDownButtonCallback(e) { - var imgContainer = this.getPageContainer(e.target); - const sibling = imgContainer.nextSibling; - if (sibling) { - this.movePageTo(imgContainer, sibling.nextSibling, true); - } - }; + rotateCCWButtonCallback(e) { + var imgContainer = this.getPageContainer(e.target); + const img = imgContainer.querySelector("img"); - rotateCCWButtonCallback(e) { - var imgContainer = this.getPageContainer(e.target); - const img = imgContainer.querySelector("img"); + this.rotateElement(img, -90); + } - this.rotateElement(img, -90) - }; + rotateCWButtonCallback(e) { + var imgContainer = this.getPageContainer(e.target); + const img = imgContainer.querySelector("img"); - rotateCWButtonCallback(e) { - var imgContainer = this.getPageContainer(e.target); - const img = imgContainer.querySelector("img"); + this.rotateElement(img, 90); + } - this.rotateElement(img, 90) - }; + deletePageButtonCallback(e) { + var imgContainer = this.getPageContainer(e.target); + this.pagesContainer.removeChild(imgContainer); + if (this.pagesContainer.childElementCount === 0) { + const filenameInput = document.getElementById("filename-input"); + const filenameParagraph = document.getElementById("filename"); + const downloadBtn = document.getElementById("export-button"); - deletePageButtonCallback(e) { - var imgContainer = this.getPageContainer(e.target); - this.pagesContainer.removeChild(imgContainer); - if (this.pagesContainer.childElementCount === 0) { - const filenameInput = document.getElementById('filename-input'); - const filenameParagraph = document.getElementById('filename'); - const downloadBtn = document.getElementById('export-button'); + filenameInput.disabled = true; + filenameInput.value = ""; + filenameParagraph.innerText = ""; - filenameInput.disabled = true; - filenameInput.value = ""; - filenameParagraph.innerText = ""; - - downloadBtn.disabled = true; - } - }; - - insertFileButtonCallback(e) { - var imgContainer = this.getPageContainer(e.target); - this.addPdfs(imgContainer) - }; - - setActions({ movePageTo, addPdfs, rotateElement }) { - this.movePageTo = movePageTo; - this.addPdfs = addPdfs; - this.rotateElement = rotateElement; - - this.moveUpButtonCallback = this.moveUpButtonCallback.bind(this); - this.moveDownButtonCallback = this.moveDownButtonCallback.bind(this); - this.rotateCCWButtonCallback = this.rotateCCWButtonCallback.bind(this); - this.rotateCWButtonCallback = this.rotateCWButtonCallback.bind(this); - this.deletePageButtonCallback = this.deletePageButtonCallback.bind(this); - this.insertFileButtonCallback = this.insertFileButtonCallback.bind(this); + downloadBtn.disabled = true; } + } - adapt(div) { - div.classList.add('pdf-actions_container'); - const leftDirection = this.pageDirection === 'rtl' ? 'right' : 'left' - const rightDirection = this.pageDirection === 'rtl' ? 'left' : 'right' - const buttonContainer = document.createElement('div'); + insertFileButtonCallback(e) { + var imgContainer = this.getPageContainer(e.target); + this.addPdfs(imgContainer); + } - buttonContainer.classList.add("pdf-actions_button-container", "hide-on-drag"); + setActions({ movePageTo, addPdfs, rotateElement }) { + this.movePageTo = movePageTo; + this.addPdfs = addPdfs; + this.rotateElement = rotateElement; - const moveUp = document.createElement('button'); - moveUp.classList.add("pdf-actions_move-left-button","btn", "btn-secondary"); - moveUp.innerHTML = ``; - moveUp.onclick = this.moveUpButtonCallback; - buttonContainer.appendChild(moveUp); + this.moveUpButtonCallback = this.moveUpButtonCallback.bind(this); + this.moveDownButtonCallback = this.moveDownButtonCallback.bind(this); + this.rotateCCWButtonCallback = this.rotateCCWButtonCallback.bind(this); + this.rotateCWButtonCallback = this.rotateCWButtonCallback.bind(this); + this.deletePageButtonCallback = this.deletePageButtonCallback.bind(this); + this.insertFileButtonCallback = this.insertFileButtonCallback.bind(this); + } - const moveDown = document.createElement('button'); - moveDown.classList.add("pdf-actions_move-right-button","btn", "btn-secondary"); - moveDown.innerHTML = ``; - moveDown.onclick = this.moveDownButtonCallback; - buttonContainer.appendChild(moveDown); + adapt(div) { + div.classList.add("pdf-actions_container"); + const leftDirection = this.pageDirection === "rtl" ? "right" : "left"; + const rightDirection = this.pageDirection === "rtl" ? "left" : "right"; + const buttonContainer = document.createElement("div"); - const rotateCCW = document.createElement('button'); - rotateCCW.classList.add("btn", "btn-secondary"); - rotateCCW.innerHTML = ` + buttonContainer.classList.add("pdf-actions_button-container", "hide-on-drag"); + + const moveUp = document.createElement("button"); + moveUp.classList.add("pdf-actions_move-left-button", "btn", "btn-secondary"); + moveUp.innerHTML = ``; + moveUp.onclick = this.moveUpButtonCallback; + buttonContainer.appendChild(moveUp); + + const moveDown = document.createElement("button"); + moveDown.classList.add("pdf-actions_move-right-button", "btn", "btn-secondary"); + moveDown.innerHTML = ``; + moveDown.onclick = this.moveDownButtonCallback; + buttonContainer.appendChild(moveDown); + + const rotateCCW = document.createElement("button"); + rotateCCW.classList.add("btn", "btn-secondary"); + rotateCCW.innerHTML = ` `; - rotateCCW.onclick = this.rotateCCWButtonCallback; - buttonContainer.appendChild(rotateCCW); + rotateCCW.onclick = this.rotateCCWButtonCallback; + buttonContainer.appendChild(rotateCCW); - const rotateCW = document.createElement('button'); - rotateCW.classList.add("btn", "btn-secondary"); - rotateCW.innerHTML = ` + const rotateCW = document.createElement("button"); + rotateCW.classList.add("btn", "btn-secondary"); + rotateCW.innerHTML = ` `; - rotateCW.onclick = this.rotateCWButtonCallback; - buttonContainer.appendChild(rotateCW); + rotateCW.onclick = this.rotateCWButtonCallback; + buttonContainer.appendChild(rotateCW); - const deletePage = document.createElement('button'); - deletePage.classList.add("btn", "btn-danger"); - deletePage.innerHTML = ` + const deletePage = document.createElement("button"); + deletePage.classList.add("btn", "btn-danger"); + deletePage.innerHTML = ` `; - deletePage.onclick = this.deletePageButtonCallback; - buttonContainer.appendChild(deletePage); + deletePage.onclick = this.deletePageButtonCallback; + buttonContainer.appendChild(deletePage); - div.appendChild(buttonContainer); + div.appendChild(buttonContainer); - const insertFileButtonContainer = document.createElement('div'); + const insertFileButtonContainer = document.createElement("div"); - insertFileButtonContainer.classList.add( - "pdf-actions_insert-file-button-container", - leftDirection, - `align-center-${leftDirection}`); + insertFileButtonContainer.classList.add( + "pdf-actions_insert-file-button-container", + leftDirection, + `align-center-${leftDirection}`, + ); - const insertFileButton = document.createElement('button'); - insertFileButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button"); - insertFileButton.innerHTML = ` + const insertFileButton = document.createElement("button"); + insertFileButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button"); + insertFileButton.innerHTML = ` `; - insertFileButton.onclick = this.insertFileButtonCallback; - insertFileButtonContainer.appendChild(insertFileButton); + insertFileButton.onclick = this.insertFileButtonCallback; + insertFileButtonContainer.appendChild(insertFileButton); - div.appendChild(insertFileButtonContainer); + div.appendChild(insertFileButtonContainer); - // add this button to every element, but only show it on the last one :D - const insertFileButtonRightContainer = document.createElement('div'); - insertFileButtonRightContainer.classList.add( - "pdf-actions_insert-file-button-container", - rightDirection, - `align-center-${rightDirection}`); + // add this button to every element, but only show it on the last one :D + const insertFileButtonRightContainer = document.createElement("div"); + insertFileButtonRightContainer.classList.add( + "pdf-actions_insert-file-button-container", + rightDirection, + `align-center-${rightDirection}`, + ); - const insertFileButtonRight = document.createElement('button'); - insertFileButtonRight.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button"); - insertFileButtonRight.innerHTML = ` + const insertFileButtonRight = document.createElement("button"); + insertFileButtonRight.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button"); + insertFileButtonRight.innerHTML = ` insertFileButtonRight`; - insertFileButtonRight.onclick = () => addPdfs(); - insertFileButtonRightContainer.appendChild(insertFileButtonRight); + insertFileButtonRight.onclick = () => addPdfs(); + insertFileButtonRightContainer.appendChild(insertFileButtonRight); - div.appendChild(insertFileButtonRightContainer); + div.appendChild(insertFileButtonRightContainer); - const adaptPageNumber = (pageNumber, div) => { - const pageNumberElement = document.createElement('span'); - pageNumberElement.classList.add('page-number'); - pageNumberElement.textContent = pageNumber; + const adaptPageNumber = (pageNumber, div) => { + const pageNumberElement = document.createElement("span"); + pageNumberElement.classList.add("page-number"); + pageNumberElement.textContent = pageNumber; - div.insertBefore(pageNumberElement, div.firstChild); - }; + div.insertBefore(pageNumberElement, div.firstChild); + }; - div.addEventListener('mouseenter', () => { - const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1; - adaptPageNumber(pageNumber, div); - }); + div.addEventListener("mouseenter", () => { + const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1; + adaptPageNumber(pageNumber, div); + }); - div.addEventListener('mouseleave', () => { - const pageNumberElement = div.querySelector('.page-number'); - if (pageNumberElement) { - div.removeChild(pageNumberElement); - } - }); + div.addEventListener("mouseleave", () => { + const pageNumberElement = div.querySelector(".page-number"); + if (pageNumberElement) { + div.removeChild(pageNumberElement); + } + }); - return div; - } + return div; + } } -export default PdfActionsManager; \ No newline at end of file +export default PdfActionsManager; diff --git a/src/main/resources/static/js/multitool/PdfContainer.js b/src/main/resources/static/js/multitool/PdfContainer.js index 1823cff4..76911a25 100644 --- a/src/main/resources/static/js/multitool/PdfContainer.js +++ b/src/main/resources/static/js/multitool/PdfContainer.js @@ -1,285 +1,282 @@ class PdfContainer { - fileName; - pagesContainer; - pagesContainerWrapper; - pdfAdapters; - downloadLink; + fileName; + pagesContainer; + pagesContainerWrapper; + pdfAdapters; + downloadLink; - constructor(id, wrapperId, pdfAdapters) { - this.pagesContainer = document.getElementById(id) - this.pagesContainerWrapper = document.getElementById(wrapperId); - this.downloadLink = null; - this.movePageTo = this.movePageTo.bind(this); - this.addPdfs = this.addPdfs.bind(this); - this.addPdfsFromFiles = this.addPdfsFromFiles.bind(this); - this.rotateElement = this.rotateElement.bind(this); - this.rotateAll = this.rotateAll.bind(this); - this.exportPdf = this.exportPdf.bind(this); - this.updateFilename = this.updateFilename.bind(this); - this.setDownloadAttribute = this.setDownloadAttribute.bind(this); - this.preventIllegalChars = this.preventIllegalChars.bind(this); + constructor(id, wrapperId, pdfAdapters) { + this.pagesContainer = document.getElementById(id); + this.pagesContainerWrapper = document.getElementById(wrapperId); + this.downloadLink = null; + this.movePageTo = this.movePageTo.bind(this); + this.addPdfs = this.addPdfs.bind(this); + this.addPdfsFromFiles = this.addPdfsFromFiles.bind(this); + this.rotateElement = this.rotateElement.bind(this); + this.rotateAll = this.rotateAll.bind(this); + this.exportPdf = this.exportPdf.bind(this); + this.updateFilename = this.updateFilename.bind(this); + this.setDownloadAttribute = this.setDownloadAttribute.bind(this); + this.preventIllegalChars = this.preventIllegalChars.bind(this); - this.pdfAdapters = pdfAdapters; + this.pdfAdapters = pdfAdapters; - this.pdfAdapters.forEach(adapter => { - adapter.setActions({ - movePageTo: this.movePageTo, - addPdfs: this.addPdfs, - rotateElement: this.rotateElement, - updateFilename: this.updateFilename - }) - }) + this.pdfAdapters.forEach((adapter) => { + adapter.setActions({ + movePageTo: this.movePageTo, + addPdfs: this.addPdfs, + rotateElement: this.rotateElement, + updateFilename: this.updateFilename, + }); + }); - window.addPdfs = this.addPdfs; - window.exportPdf = this.exportPdf; - window.rotateAll = this.rotateAll; + window.addPdfs = this.addPdfs; + window.exportPdf = this.exportPdf; + window.rotateAll = this.rotateAll; - const filenameInput = document.getElementById('filename-input'); - const downloadBtn = document.getElementById('export-button'); + const filenameInput = document.getElementById("filename-input"); + const downloadBtn = document.getElementById("export-button"); - filenameInput.onkeyup = this.updateFilename; - filenameInput.onkeydown = this.preventIllegalChars; - filenameInput.disabled = false; - filenameInput.innerText = ""; - downloadBtn.disabled = true; + filenameInput.onkeyup = this.updateFilename; + filenameInput.onkeydown = this.preventIllegalChars; + filenameInput.disabled = false; + filenameInput.innerText = ""; + downloadBtn.disabled = true; + } + + movePageTo(startElement, endElement, scrollTo = false) { + const childArray = Array.from(this.pagesContainer.childNodes); + const startIndex = childArray.indexOf(startElement); + const endIndex = childArray.indexOf(endElement); + this.pagesContainer.removeChild(startElement); + if (!endElement) { + this.pagesContainer.append(startElement); + } else { + this.pagesContainer.insertBefore(startElement, endElement); } - movePageTo(startElement, endElement, scrollTo = false) { - const childArray = Array.from(this.pagesContainer.childNodes); - const startIndex = childArray.indexOf(startElement); - const endIndex = childArray.indexOf(endElement); - this.pagesContainer.removeChild(startElement); - if(!endElement) { - this.pagesContainer.append(startElement); + if (scrollTo) { + const { width } = startElement.getBoundingClientRect(); + const vector = endIndex !== -1 && startIndex > endIndex ? 0 - width : width; + + this.pagesContainerWrapper.scroll({ + left: this.pagesContainerWrapper.scrollLeft + vector, + }); + } + } + + addPdfs(nextSiblingElement) { + var input = document.createElement("input"); + input.type = "file"; + input.multiple = true; + input.setAttribute("accept", "application/pdf"); + input.onchange = async (e) => { + const files = e.target.files; + + this.addPdfsFromFiles(files, nextSiblingElement); + this.updateFilename(files ? files[0].name : ""); + }; + + input.click(); + } + + async addPdfsFromFiles(files, nextSiblingElement) { + this.fileName = files[0].name; + for (var i = 0; i < files.length; i++) { + await this.addPdfFile(files[i], nextSiblingElement); + } + + document.querySelectorAll(".enable-on-file").forEach((element) => { + element.disabled = false; + }); + } + + rotateElement(element, deg) { + var lastTransform = element.style.rotate; + if (!lastTransform) { + lastTransform = "0"; + } + const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, "")); + const newAngle = lastAngle + deg; + + element.style.rotate = newAngle + "deg"; + } + + async addPdfFile(file, nextSiblingElement) { + const { renderer, pdfDocument } = await this.loadFile(file); + + for (var i = 0; i < renderer.pageCount; i++) { + const div = document.createElement("div"); + + div.classList.add("page-container"); + + var img = document.createElement("img"); + img.classList.add("page-image"); + const imageSrc = await renderer.renderPage(i); + img.src = imageSrc; + img.pageIdx = i; + img.rend = renderer; + img.doc = pdfDocument; + div.appendChild(img); + + this.pdfAdapters.forEach((adapter) => { + adapter.adapt?.(div); + }); + if (nextSiblingElement) { + this.pagesContainer.insertBefore(div, nextSiblingElement); + } else { + this.pagesContainer.appendChild(div); + } + } + } + + async loadFile(file) { + var objectUrl = URL.createObjectURL(file); + var pdfDocument = await this.toPdfLib(objectUrl); + var renderer = await this.toRenderer(objectUrl); + return { renderer, pdfDocument }; + } + + async toRenderer(objectUrl) { + pdfjsLib.GlobalWorkerOptions.workerSrc = "pdfjs/pdf.worker.js"; + const pdf = await pdfjsLib.getDocument(objectUrl).promise; + return { + document: pdf, + pageCount: pdf.numPages, + renderPage: async function (pageIdx) { + const page = await this.document.getPage(pageIdx + 1); + + const canvas = document.createElement("canvas"); + + // set the canvas size to the size of the page + if (page.rotate == 90 || page.rotate == 270) { + canvas.width = page.view[3]; + canvas.height = page.view[2]; } else { - this.pagesContainer.insertBefore(startElement, endElement); + canvas.width = page.view[2]; + canvas.height = page.view[3]; } - if(scrollTo) { - const { width } = startElement.getBoundingClientRect(); - const vector = (endIndex !== -1 && startIndex > endIndex) - ? 0-width - : width; - - this.pagesContainerWrapper.scroll({ - left: this.pagesContainerWrapper.scrollLeft + vector, - }) - } - } - - addPdfs(nextSiblingElement) { - var input = document.createElement('input'); - input.type = 'file'; - input.multiple = true; - input.setAttribute("accept", "application/pdf"); - input.onchange = async(e) => { - const files = e.target.files; - - this.addPdfsFromFiles(files, nextSiblingElement); - this.updateFilename(files ? files[0].name : ""); - } - - input.click(); - } - - async addPdfsFromFiles(files, nextSiblingElement) { - this.fileName = files[0].name; - for (var i=0; i < files.length; i++) { - await this.addPdfFile(files[i], nextSiblingElement); - } - - document.querySelectorAll(".enable-on-file").forEach(element => { - element.disabled = false; - }); - } - - rotateElement(element, deg) { - var lastTransform = element.style.rotate; - if (!lastTransform) { - lastTransform = "0"; - } - const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, '')); - const newAngle = lastAngle + deg; - - element.style.rotate = newAngle + "deg"; - } - - async addPdfFile(file, nextSiblingElement) { - const { renderer, pdfDocument } = await this.loadFile(file); - - for (var i=0; i < renderer.pageCount; i++) { - const div = document.createElement('div'); - - div.classList.add("page-container"); - - var img = document.createElement('img'); - img.classList.add('page-image') - const imageSrc = await renderer.renderPage(i) - img.src = imageSrc; - img.pageIdx = i; - img.rend = renderer; - img.doc = pdfDocument; - div.appendChild(img); - - this.pdfAdapters.forEach((adapter) => { - adapter.adapt?.(div) - }) - if (nextSiblingElement) { - this.pagesContainer.insertBefore(div, nextSiblingElement); - } else { - this.pagesContainer.appendChild(div); - } - } - } - - async loadFile(file) { - var objectUrl = URL.createObjectURL(file); - var pdfDocument = await this.toPdfLib(objectUrl); - var renderer = await this.toRenderer(objectUrl); - return { renderer, pdfDocument }; - } - - async toRenderer(objectUrl) { - pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js' - const pdf = await pdfjsLib.getDocument(objectUrl).promise; - return { - document: pdf, - pageCount: pdf.numPages, - renderPage: async function(pageIdx) { - const page = await this.document.getPage(pageIdx+1); - - const canvas = document.createElement("canvas"); - - // set the canvas size to the size of the page - if (page.rotate == 90 || page.rotate == 270) { - canvas.width = page.view[3]; - canvas.height = page.view[2]; - } else { - canvas.width = page.view[2]; - canvas.height = page.view[3]; - } - - // render the page onto the canvas - var renderContext = { - canvasContext: canvas.getContext("2d"), - viewport: page.getViewport({ scale: 1 }) - }; - - await page.render(renderContext).promise; - return canvas.toDataURL(); - } + // render the page onto the canvas + var renderContext = { + canvasContext: canvas.getContext("2d"), + viewport: page.getViewport({ scale: 1 }), }; + + await page.render(renderContext).promise; + return canvas.toDataURL(); + }, + }; + } + + async toPdfLib(objectUrl) { + const existingPdfBytes = await fetch(objectUrl).then((res) => res.arrayBuffer()); + const pdfDoc = await PDFLib.PDFDocument.load(existingPdfBytes, { + ignoreEncryption: true, + }); + return pdfDoc; + } + + rotateAll(deg) { + for (var i = 0; i < this.pagesContainer.childNodes.length; i++) { + const img = this.pagesContainer.childNodes[i].querySelector("img"); + if (!img) continue; + this.rotateElement(img, deg); + } + } + + async exportPdf() { + const pdfDoc = await PDFLib.PDFDocument.create(); + const pageContainers = this.pagesContainer.querySelectorAll(".page-container"); // Select all .page-container elements + for (var i = 0; i < pageContainers.length; i++) { + const img = pageContainers[i].querySelector("img"); // Find the img element within each .page-container + if (!img) continue; + const pages = await pdfDoc.copyPages(img.doc, [img.pageIdx]); + const page = pages[0]; + + const rotation = img.style.rotate; + if (rotation) { + const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, "")); + page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle)); + } + + pdfDoc.addPage(page); + } + const pdfBytes = await pdfDoc.save(); + const pdfBlob = new Blob([pdfBytes], { type: "application/pdf" }); + const url = URL.createObjectURL(pdfBlob); + const downloadOption = localStorage.getItem("downloadOption"); + + const filenameInput = document.getElementById("filename-input"); + + let inputArr = filenameInput.value.split("."); + + if (inputArr !== null && inputArr !== undefined && inputArr.length > 0) { + inputArr = inputArr.filter((n) => n); // remove all empty strings, nulls or undefined + + if (inputArr.length > 1) { + inputArr.pop(); // remove right part after last dot + } + + filenameInput.value = inputArr.join(""); + this.fileName = filenameInput.value; } - async toPdfLib(objectUrl) { - const existingPdfBytes = await fetch(objectUrl).then(res => res.arrayBuffer()); - const pdfDoc = await PDFLib.PDFDocument.load(existingPdfBytes, { ignoreEncryption: true }); - return pdfDoc; + if (!filenameInput.value.includes(".pdf")) { + filenameInput.value = filenameInput.value + ".pdf"; + this.fileName = filenameInput.value; } + if (downloadOption === "sameWindow") { + // Open the file in the same window + window.location.href = url; + } else if (downloadOption === "newWindow") { + // Open the file in a new window + window.open(url, "_blank"); + } else { + // Download the file + this.downloadLink = document.createElement("a"); + this.downloadLink.id = "download-link"; + this.downloadLink.href = url; + // downloadLink.download = this.fileName ? this.fileName : 'managed.pdf'; + // downloadLink.download = this.fileName; + this.downloadLink.setAttribute("download", this.fileName ? this.fileName : "managed.pdf"); + this.downloadLink.setAttribute("target", "_blank"); + this.downloadLink.onclick = this.setDownloadAttribute; + this.downloadLink.click(); + } + } + setDownloadAttribute() { + this.downloadLink.setAttribute("download", this.fileName ? this.fileName : "managed.pdf"); + } - rotateAll(deg) { - for (var i=0; i 0) { - - inputArr = inputArr.filter(n => n); // remove all empty strings, nulls or undefined - - if (inputArr.length > 1) { - inputArr.pop(); // remove right part after last dot - } - - filenameInput.value = inputArr.join(''); - this.fileName = filenameInput.value; - } - - if (!filenameInput.value.includes('.pdf')) { - filenameInput.value = filenameInput.value + '.pdf'; - this.fileName = filenameInput.value; - } - - if (downloadOption === 'sameWindow') { - // Open the file in the same window - window.location.href = url; - } else if (downloadOption === 'newWindow') { - // Open the file in a new window - window.open(url, '_blank'); - } else { - // Download the file - this.downloadLink = document.createElement('a'); - this.downloadLink.id = 'download-link'; - this.downloadLink.href = url; - // downloadLink.download = this.fileName ? this.fileName : 'managed.pdf'; - // downloadLink.download = this.fileName; - this.downloadLink.setAttribute('download', this.fileName ? this.fileName : 'managed.pdf'); - this.downloadLink.setAttribute('target', '_blank'); - this.downloadLink.onclick = this.setDownloadAttribute; - this.downloadLink.click(); - } + if (!filenameInput.value) { + filenameInput.value = this.fileName; } + } - setDownloadAttribute() { - this.downloadLink.setAttribute("download", this.fileName ? this.fileName : 'managed.pdf'); - } - - updateFilename(fileName = "") { - const filenameInput = document.getElementById('filename-input'); - const pagesContainer = document.getElementById('pages-container'); - const downloadBtn = document.getElementById('export-button'); - - downloadBtn.disabled = pagesContainer.childElementCount === 0 - - if (!this.fileName) { - this.fileName = fileName; - } - - if (!filenameInput.value) { - filenameInput.value = this.fileName; - } - } - - preventIllegalChars(e) { - // const filenameInput = document.getElementById('filename-input'); - // - // filenameInput.value = filenameInput.value.replace('.pdf', ''); - // - // // prevent . - // if (filenameInput.value.includes('.')) { - // filenameInput.value.replace('.',''); - // } - } + preventIllegalChars(e) { + // const filenameInput = document.getElementById('filename-input'); + // + // filenameInput.value = filenameInput.value.replace('.pdf', ''); + // + // // prevent . + // if (filenameInput.value.includes('.')) { + // filenameInput.value.replace('.',''); + // } + } } export default PdfContainer; diff --git a/src/main/resources/static/js/multitool/fileInput.js b/src/main/resources/static/js/multitool/fileInput.js index ecaf64ed..77455c06 100644 --- a/src/main/resources/static/js/multitool/fileInput.js +++ b/src/main/resources/static/js/multitool/fileInput.js @@ -1,94 +1,95 @@ class FileDragManager { - overlay; - dragCounter; - updateFilename; + overlay; + dragCounter; + updateFilename; - constructor(cb = null) { - this.dragCounter = 0; - this.setCallback(cb); + constructor(cb = null) { + this.dragCounter = 0; + this.setCallback(cb); - // Prevent default behavior for drag events - ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { - document.body.addEventListener(eventName, preventDefaults, false); - }); + // Prevent default behavior for drag events + ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => { + document.body.addEventListener(eventName, preventDefaults, false); + }); - function preventDefaults(e) { - e.preventDefault(); - e.stopPropagation(); - } - - this.dragenterListener = this.dragenterListener.bind(this); - this.dragleaveListener = this.dragleaveListener.bind(this); - this.dropListener = this.dropListener.bind(this); - - document.body.addEventListener('dragenter', this.dragenterListener); - document.body.addEventListener('dragleave', this.dragleaveListener); - // Add drop event listener - document.body.addEventListener('drop', this.dropListener); + function preventDefaults(e) { + e.preventDefault(); + e.stopPropagation(); } - setActions({ updateFilename }) { - this.updateFilename = updateFilename; + this.dragenterListener = this.dragenterListener.bind(this); + this.dragleaveListener = this.dragleaveListener.bind(this); + this.dropListener = this.dropListener.bind(this); + + document.body.addEventListener("dragenter", this.dragenterListener); + document.body.addEventListener("dragleave", this.dragleaveListener); + // Add drop event listener + document.body.addEventListener("drop", this.dropListener); + } + + setActions({ updateFilename }) { + this.updateFilename = updateFilename; + } + + setCallback(cb) { + if (cb) { + this.callback = cb; + } else { + this.callback = (files) => console.warn("FileDragManager not set"); } + } - setCallback(cb) { - if (cb) { - this.callback = cb; - } else { - this.callback = (files) => console.warn("FileDragManager not set"); - } + dragenterListener() { + this.dragCounter++; + if (!this.overlay) { + // Create and show the overlay + this.overlay = document.createElement("div"); + this.overlay.style.position = "fixed"; + this.overlay.style.top = 0; + this.overlay.style.left = 0; + this.overlay.style.width = "100%"; + this.overlay.style.height = "100%"; + this.overlay.style.background = "rgba(0, 0, 0, 0.5)"; + this.overlay.style.color = "#fff"; + this.overlay.style.zIndex = "1000"; + this.overlay.style.display = "flex"; + this.overlay.style.alignItems = "center"; + this.overlay.style.justifyContent = "center"; + this.overlay.style.pointerEvents = "none"; + this.overlay.innerHTML = "

Drop files anywhere to upload

"; + document.getElementById("content-wrap").appendChild(this.overlay); } + } - dragenterListener() { - this.dragCounter++; - if (!this.overlay) { - // Create and show the overlay - this.overlay = document.createElement('div'); - this.overlay.style.position = 'fixed'; - this.overlay.style.top = 0; - this.overlay.style.left = 0; - this.overlay.style.width = '100%'; - this.overlay.style.height = '100%'; - this.overlay.style.background = 'rgba(0, 0, 0, 0.5)'; - this.overlay.style.color = '#fff'; - this.overlay.style.zIndex = '1000'; - this.overlay.style.display = 'flex'; - this.overlay.style.alignItems = 'center'; - this.overlay.style.justifyContent = 'center'; - this.overlay.style.pointerEvents = 'none'; - this.overlay.innerHTML = '

Drop files anywhere to upload

'; - document.getElementById('content-wrap').appendChild(this.overlay); + dragleaveListener() { + this.dragCounter--; + if (this.dragCounter === 0) { + // Hide and remove the overlay + if (this.overlay) { + this.overlay.remove(); + this.overlay = null; + } + } + } + + dropListener(e) { + const dt = e.dataTransfer; + const files = dt.files; + this.callback(files) + .catch((err) => { + console.error(err); + //maybe + }) + .finally(() => { + // Hide and remove the overlay + if (this.overlay) { + this.overlay.remove(); + this.overlay = null; } - }; - dragleaveListener() { - this.dragCounter--; - if (this.dragCounter === 0) { - // Hide and remove the overlay - if (this.overlay) { - this.overlay.remove(); - this.overlay = null; - } - } - }; - - dropListener(e) { - - const dt = e.dataTransfer; - const files = dt.files; - this.callback(files).catch((err) => { - console.error(err); - //maybe - }).finally(() => { - // Hide and remove the overlay - if (this.overlay) { - this.overlay.remove(); - this.overlay = null; - } - - this.updateFilename(files ? files[0].name : ""); - }); - }; + this.updateFilename(files ? files[0].name : ""); + }); + } } export default FileDragManager; diff --git a/src/main/resources/static/js/multitool/horizontalScroll.js b/src/main/resources/static/js/multitool/horizontalScroll.js index 1bbcfed0..2d20fd7b 100644 --- a/src/main/resources/static/js/multitool/horizontalScroll.js +++ b/src/main/resources/static/js/multitool/horizontalScroll.js @@ -1,35 +1,34 @@ const scrollDivHorizontally = (id) => { - var scrollDelta = 0; // variable to store the accumulated scroll delta - var isScrolling = false; // variable to track if scroll is already in progress - const divToScrollHorizontally = document.getElementById(id) - function scrollLoop() { - // Scroll the div horizontally by a fraction of the accumulated scroll delta - divToScrollHorizontally.scrollLeft += scrollDelta * 0.1; + var scrollDelta = 0; // variable to store the accumulated scroll delta + var isScrolling = false; // variable to track if scroll is already in progress + const divToScrollHorizontally = document.getElementById(id); + function scrollLoop() { + // Scroll the div horizontally by a fraction of the accumulated scroll delta + divToScrollHorizontally.scrollLeft += scrollDelta * 0.1; - // Reduce the accumulated scroll delta by a fraction - scrollDelta *= 0.9; + // Reduce the accumulated scroll delta by a fraction + scrollDelta *= 0.9; - // If scroll delta is still significant, continue the scroll loop - if (Math.abs(scrollDelta) > 0.1) { - requestAnimationFrame(scrollLoop); - } else { - isScrolling = false; // Reset scroll in progress flag - } + // If scroll delta is still significant, continue the scroll loop + if (Math.abs(scrollDelta) > 0.1) { + requestAnimationFrame(scrollLoop); + } else { + isScrolling = false; // Reset scroll in progress flag } + } + divToScrollHorizontally.addEventListener("wheel", function (e) { + e.preventDefault(); // prevent default mousewheel behavior - divToScrollHorizontally.addEventListener("wheel", function(e) { - e.preventDefault(); // prevent default mousewheel behavior + // Accumulate the horizontal scroll delta + scrollDelta -= e.deltaX || e.wheelDeltaX || -e.deltaY || -e.wheelDeltaY; - // Accumulate the horizontal scroll delta - scrollDelta -= e.deltaX || e.wheelDeltaX || -e.deltaY || -e.wheelDeltaY; - - // If scroll is not already in progress, start the scroll loop - if (!isScrolling) { - isScrolling = true; - requestAnimationFrame(scrollLoop); - } - }); -} + // If scroll is not already in progress, start the scroll loop + if (!isScrolling) { + isScrolling = true; + requestAnimationFrame(scrollLoop); + } + }); +}; export default scrollDivHorizontally; diff --git a/src/main/resources/static/js/pipeline.js b/src/main/resources/static/js/pipeline.js index e77c4d01..fcfd3df5 100644 --- a/src/main/resources/static/js/pipeline.js +++ b/src/main/resources/static/js/pipeline.js @@ -1,277 +1,261 @@ -document.getElementById('validateButton').addEventListener('click', function(event) { - event.preventDefault(); - validatePipeline(); +document.getElementById("validateButton").addEventListener("click", function (event) { + event.preventDefault(); + validatePipeline(); }); function validatePipeline() { - let pipelineListItems = document.getElementById('pipelineList').children; - let isValid = true; - let containsAddPassword = false; - for (let i = 0; i < pipelineListItems.length - 1; i++) { - let currentOperation = pipelineListItems[i].querySelector('.operationName').textContent; - let nextOperation = pipelineListItems[i + 1].querySelector('.operationName').textContent; - if (currentOperation === '/add-password') { - containsAddPassword = true; - } + let pipelineListItems = document.getElementById("pipelineList").children; + let isValid = true; + let containsAddPassword = false; + for (let i = 0; i < pipelineListItems.length - 1; i++) { + let currentOperation = pipelineListItems[i].querySelector(".operationName").textContent; + let nextOperation = pipelineListItems[i + 1].querySelector(".operationName").textContent; + if (currentOperation === "/add-password") { + containsAddPassword = true; + } - let currentOperationDescription = apiDocs[currentOperation]?.post?.description || ""; - let nextOperationDescription = apiDocs[nextOperation]?.post?.description || ""; + let currentOperationDescription = apiDocs[currentOperation]?.post?.description || ""; + let nextOperationDescription = apiDocs[nextOperation]?.post?.description || ""; - // Strip off 'ZIP-' prefix - currentOperationDescription = currentOperationDescription.replace("ZIP-", ''); - nextOperationDescription = nextOperationDescription.replace("ZIP-", ''); + // Strip off 'ZIP-' prefix + currentOperationDescription = currentOperationDescription.replace("ZIP-", ""); + nextOperationDescription = nextOperationDescription.replace("ZIP-", ""); - let currentOperationOutput = currentOperationDescription.match(/Output:([A-Z\/]*)/)?.[1] || ""; - let nextOperationInput = nextOperationDescription.match(/Input:([A-Z\/]*)/)?.[1] || ""; + let currentOperationOutput = currentOperationDescription.match(/Output:([A-Z\/]*)/)?.[1] || ""; + let nextOperationInput = nextOperationDescription.match(/Input:([A-Z\/]*)/)?.[1] || ""; - // Splitting in case of multiple possible output/input - let currentOperationOutputArr = currentOperationOutput.split('/'); - let nextOperationInputArr = nextOperationInput.split('/'); + // Splitting in case of multiple possible output/input + let currentOperationOutputArr = currentOperationOutput.split("/"); + let nextOperationInputArr = nextOperationInput.split("/"); - if (currentOperationOutput !== 'ANY' && nextOperationInput !== 'ANY') { - let intersection = currentOperationOutputArr.filter(value => nextOperationInputArr.includes(value)); - console.log(`Intersection: ${intersection}`); + if (currentOperationOutput !== "ANY" && nextOperationInput !== "ANY") { + let intersection = currentOperationOutputArr.filter((value) => nextOperationInputArr.includes(value)); + console.log(`Intersection: ${intersection}`); - if (intersection.length === 0) { - updateValidateButton(false); - isValid = false; - console.log(`Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`); - alert(`Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`); - break; - } - } - } - if (containsAddPassword && pipelineListItems[pipelineListItems.length - 1].querySelector('.operationName').textContent !== '/add-password') { - updateValidateButton(false); - alert('The "add-password" operation should be at the end of the operations sequence. Please adjust the operations order.'); - return false; - } - if (isValid) { - console.log('Pipeline is valid'); - // Continue with the pipeline operation - } else { - console.error('Pipeline is not valid'); - // Stop operation, maybe display an error to the user - } - updateValidateButton(isValid); - return isValid; + if (intersection.length === 0) { + updateValidateButton(false); + isValid = false; + console.log( + `Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`, + ); + alert( + `Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`, + ); + break; + } + } + } + if ( + containsAddPassword && + pipelineListItems[pipelineListItems.length - 1].querySelector(".operationName").textContent !== "/add-password" + ) { + updateValidateButton(false); + alert('The "add-password" operation should be at the end of the operations sequence. Please adjust the operations order.'); + return false; + } + if (isValid) { + console.log("Pipeline is valid"); + // Continue with the pipeline operation + } else { + console.error("Pipeline is not valid"); + // Stop operation, maybe display an error to the user + } + updateValidateButton(isValid); + return isValid; } function updateValidateButton(isValid) { - var validateButton = document.getElementById('validateButton'); - if (isValid) { - validateButton.classList.remove('btn-danger'); - validateButton.classList.add('btn-success'); - } else { - validateButton.classList.remove('btn-success'); - validateButton.classList.add('btn-danger'); - } + var validateButton = document.getElementById("validateButton"); + if (isValid) { + validateButton.classList.remove("btn-danger"); + validateButton.classList.add("btn-success"); + } else { + validateButton.classList.remove("btn-success"); + validateButton.classList.add("btn-danger"); + } } +document.getElementById("submitConfigBtn").addEventListener("click", function () { + if (validatePipeline() === false) { + return; + } + let selectedOperation = document.getElementById("operationsDropdown").value; + var pipelineName = document.getElementById("pipelineName").value; + let pipelineList = document.getElementById("pipelineList").children; + let pipelineConfig = { + name: pipelineName, + pipeline: [], + _examples: { + outputDir: "{outputFolder}/{folderName}", + outputFileName: "{filename}-{pipelineName}-{date}-{time}", + }, + outputDir: "httpWebRequest", + outputFileName: "{filename}", + }; + for (let i = 0; i < pipelineList.length; i++) { + let operationName = pipelineList[i].querySelector(".operationName").textContent; + let parameters = operationSettings[operationName] || {}; -document.getElementById('submitConfigBtn').addEventListener('click', function() { + pipelineConfig.pipeline.push({ + operation: operationName, + parameters: parameters, + }); + } - if (validatePipeline() === false) { - return; - } - let selectedOperation = document.getElementById('operationsDropdown').value; + let pipelineConfigJson = JSON.stringify(pipelineConfig, null, 2); + let formData = new FormData(); + let fileInput = document.getElementById("fileInput-input"); + let files = fileInput.files; - var pipelineName = document.getElementById('pipelineName').value; - let pipelineList = document.getElementById('pipelineList').children; - let pipelineConfig = { - "name": pipelineName, - "pipeline": [], - "_examples": { - "outputDir": "{outputFolder}/{folderName}", - "outputFileName": "{filename}-{pipelineName}-{date}-{time}" - }, - "outputDir": "httpWebRequest", - "outputFileName": "{filename}" - }; + for (let i = 0; i < files.length; i++) { + console.log("files[i]", files[i].name); + formData.append("fileInput", files[i], files[i].name); + } - for (let i = 0; i < pipelineList.length; i++) { - let operationName = pipelineList[i].querySelector('.operationName').textContent; - let parameters = operationSettings[operationName] || {}; + console.log("pipelineConfigJson", pipelineConfigJson); + formData.append("json", pipelineConfigJson); + console.log("formData", formData); - pipelineConfig.pipeline.push({ - "operation": operationName, - "parameters": parameters - }); - } + fetch("api/v1/pipeline/handleData", { + method: "POST", + body: formData, + }) + .then((response) => { + // Save the response to use it later + const responseToUseLater = response; + return response.blob().then((blob) => { + let url = window.URL.createObjectURL(blob); + let a = document.createElement("a"); + a.href = url; + // Use responseToUseLater instead of response + const contentDisposition = responseToUseLater.headers.get("Content-Disposition"); + let filename = "download"; + if (contentDisposition && contentDisposition.indexOf("attachment") !== -1) { + filename = decodeURIComponent(contentDisposition.split("filename=")[1].replace(/"/g, "")).trim(); + } + a.download = filename; - - - - - - - - - - - let pipelineConfigJson = JSON.stringify(pipelineConfig, null, 2); - - let formData = new FormData(); - - let fileInput = document.getElementById('fileInput-input'); - let files = fileInput.files; - - for (let i = 0; i < files.length; i++) { - console.log("files[i]", files[i].name); - formData.append('fileInput', files[i], files[i].name); - } - - console.log("pipelineConfigJson", pipelineConfigJson); - formData.append('json', pipelineConfigJson); - console.log("formData", formData); - - fetch('api/v1/pipeline/handleData', { - method: 'POST', - body: formData - }) - .then(response => { - // Save the response to use it later - const responseToUseLater = response; - - return response.blob().then(blob => { - let url = window.URL.createObjectURL(blob); - let a = document.createElement('a'); - a.href = url; - - // Use responseToUseLater instead of response - const contentDisposition = responseToUseLater.headers.get('Content-Disposition'); - let filename = 'download'; - if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) { - filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, '')).trim(); - } - a.download = filename; - - document.body.appendChild(a); - a.click(); - a.remove(); - }); - }) - .catch((error) => { - console.error('Error:', error); - }); - + document.body.appendChild(a); + a.click(); + a.remove(); + }); + }) + .catch((error) => { + console.error("Error:", error); + }); }); let apiDocs = {}; let apiSchemas = {}; let operationSettings = {}; -fetch('v1/api-docs') - .then(response => response.json()) - .then(data => { +fetch("v1/api-docs") + .then((response) => response.json()) + .then((data) => { + apiDocs = data.paths; + apiSchemas = data.components.schemas; + let operationsDropdown = document.getElementById("operationsDropdown"); + const ignoreOperations = ["/api/v1/pipeline/handleData", "/api/v1/pipeline/operationToIgnore"]; // Add the operations you want to ignore here - apiDocs = data.paths; - apiSchemas = data.components.schemas; - let operationsDropdown = document.getElementById('operationsDropdown'); - const ignoreOperations = ["/api/v1/pipeline/handleData", "/api/v1/pipeline/operationToIgnore"]; // Add the operations you want to ignore here + operationsDropdown.innerHTML = ""; - operationsDropdown.innerHTML = ''; + let operationsByTag = {}; - let operationsByTag = {}; + // Group operations by tags + Object.keys(data.paths).forEach((operationPath) => { + let operation = data.paths[operationPath].post; + if (!operation || !operation.description) { + console.log(operationPath); + } + //!operation.description.includes("Type:MISO") + if (operation && !ignoreOperations.includes(operationPath)) { + let operationTag = operation.tags[0]; // This assumes each operation has exactly one tag + if (!operationsByTag[operationTag]) { + operationsByTag[operationTag] = []; + } + operationsByTag[operationTag].push(operationPath); + } + }); - // Group operations by tags - Object.keys(data.paths).forEach(operationPath => { - let operation = data.paths[operationPath].post; - if (!operation || !operation.description) { - console.log(operationPath); - } - //!operation.description.includes("Type:MISO") - if (operation && !ignoreOperations.includes(operationPath)) { - let operationTag = operation.tags[0]; // This assumes each operation has exactly one tag - if (!operationsByTag[operationTag]) { - operationsByTag[operationTag] = []; - } - operationsByTag[operationTag].push(operationPath); - } - }); + // Sort operations within each tag alphabetically + Object.keys(operationsByTag).forEach((tag) => { + operationsByTag[tag].sort(); + }); - // Sort operations within each tag alphabetically - Object.keys(operationsByTag).forEach(tag => { - operationsByTag[tag].sort(); - }); + // Specify the order of tags + let tagOrder = ["General", "Security", "Convert", "Misc", "Filter"]; - // Specify the order of tags - let tagOrder = ["General", "Security", "Convert", "Misc", "Filter"]; + // Create dropdown options + tagOrder.forEach((tag) => { + if (operationsByTag[tag]) { + let group = document.createElement("optgroup"); + group.label = tag; - // Create dropdown options - tagOrder.forEach(tag => { - if (operationsByTag[tag]) { - let group = document.createElement('optgroup'); - group.label = tag; + operationsByTag[tag].forEach((operationPath) => { + let option = document.createElement("option"); - operationsByTag[tag].forEach(operationPath => { - let option = document.createElement('option'); + let operationPathDisplay = operationPath; + operationPathDisplay = operationPath.replace(new RegExp("api/v1/" + tag.toLowerCase() + "/", "i"), ""); - let operationPathDisplay = operationPath - operationPathDisplay = operationPath.replace(new RegExp("api/v1/" + tag.toLowerCase() + "/", 'i'), ""); + if (operationPath.includes("/convert")) { + operationPathDisplay = operationPathDisplay.replace(/^\//, "").replaceAll("/", " to "); + } else { + operationPathDisplay = operationPathDisplay.replace(/\//g, ""); // Remove slashes + } + operationPathDisplay = operationPathDisplay.replaceAll(" ", "-"); + option.textContent = operationPathDisplay; + option.value = operationPath; // Keep the value with slashes for querying + group.appendChild(option); + }); + operationsDropdown.appendChild(group); + } + }); + }); - if (operationPath.includes("/convert")) { - operationPathDisplay = operationPathDisplay.replace(/^\//, '').replaceAll("/", " to "); - } else { - operationPathDisplay = operationPathDisplay.replace(/\//g, ''); // Remove slashes - } - operationPathDisplay = operationPathDisplay.replaceAll(" ", "-"); - option.textContent = operationPathDisplay; - option.value = operationPath; // Keep the value with slashes for querying - group.appendChild(option); - }); +document.getElementById("addOperationBtn").addEventListener("click", function () { + let selectedOperation = document.getElementById("operationsDropdown").value; + let pipelineList = document.getElementById("pipelineList"); - operationsDropdown.appendChild(group); - } - }); - }); + let listItem = document.createElement("li"); + listItem.className = "list-group-item"; + let hasSettings = false; + if (apiDocs[selectedOperation] && apiDocs[selectedOperation].post) { + const postMethod = apiDocs[selectedOperation].post; + // Check if parameters exist + if (postMethod.parameters && postMethod.parameters.length > 0) { + hasSettings = true; + } else if (postMethod.requestBody && postMethod.requestBody.content["multipart/form-data"]) { + // Extract the reference key + const refKey = postMethod.requestBody.content["multipart/form-data"].schema["$ref"].split("/").pop(); + // Check if the referenced schema exists and has properties more than just its input file + if (apiSchemas[refKey]) { + const properties = apiSchemas[refKey].properties; + const propertyKeys = Object.keys(properties); -document.getElementById('addOperationBtn').addEventListener('click', function() { - let selectedOperation = document.getElementById('operationsDropdown').value; - let pipelineList = document.getElementById('pipelineList'); + // Check if there's more than one property or if there's exactly one property and its format is not 'binary' + if (propertyKeys.length > 1 || (propertyKeys.length === 1 && properties[propertyKeys[0]].format !== "binary")) { + hasSettings = true; + } + } + } + } - let listItem = document.createElement('li'); - listItem.className = "list-group-item"; - let hasSettings = false; - if (apiDocs[selectedOperation] && apiDocs[selectedOperation].post) { - const postMethod = apiDocs[selectedOperation].post; - - // Check if parameters exist - if (postMethod.parameters && postMethod.parameters.length > 0) { - hasSettings = true; - } else if (postMethod.requestBody && postMethod.requestBody.content['multipart/form-data']) { - // Extract the reference key - const refKey = postMethod.requestBody.content['multipart/form-data'].schema['$ref'].split('/').pop(); - // Check if the referenced schema exists and has properties more than just its input file - if (apiSchemas[refKey]) { - const properties = apiSchemas[refKey].properties; - const propertyKeys = Object.keys(properties); - - // Check if there's more than one property or if there's exactly one property and its format is not 'binary' - if (propertyKeys.length > 1 || (propertyKeys.length === 1 && properties[propertyKeys[0]].format !== 'binary')) { - hasSettings = true; - } - } - } - } - - - - - listItem.innerHTML = ` + listItem.innerHTML = `
${selectedOperation}
- @@ -279,393 +263,379 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
`; + pipelineList.appendChild(listItem); - pipelineList.appendChild(listItem); + listItem.querySelector(".move-up").addEventListener("click", function (event) { + event.preventDefault(); + if (listItem.previousElementSibling) { + pipelineList.insertBefore(listItem, listItem.previousElementSibling); + updateConfigInDropdown(); + } + }); - listItem.querySelector('.move-up').addEventListener('click', function(event) { - event.preventDefault(); - if (listItem.previousElementSibling) { - pipelineList.insertBefore(listItem, listItem.previousElementSibling); - updateConfigInDropdown(); - } - }); + listItem.querySelector(".move-down").addEventListener("click", function (event) { + event.preventDefault(); + if (listItem.nextElementSibling) { + pipelineList.insertBefore(listItem.nextElementSibling, listItem); + updateConfigInDropdown(); + } + }); - listItem.querySelector('.move-down').addEventListener('click', function(event) { - event.preventDefault(); - if (listItem.nextElementSibling) { - pipelineList.insertBefore(listItem.nextElementSibling, listItem); - updateConfigInDropdown(); - } + listItem.querySelector(".remove").addEventListener("click", function (event) { + event.preventDefault(); + pipelineList.removeChild(listItem); + hideOrShowPipelineHeader(); + updateConfigInDropdown(); + }); - }); + listItem.querySelector(".pipelineSettings").addEventListener("click", function (event) { + event.preventDefault(); + showpipelineSettingsModal(selectedOperation); + hideOrShowPipelineHeader(); + }); - listItem.querySelector('.remove').addEventListener('click', function(event) { - event.preventDefault(); - pipelineList.removeChild(listItem); - hideOrShowPipelineHeader(); - updateConfigInDropdown(); - }); + function showpipelineSettingsModal(operation) { + let pipelineSettingsModal = document.getElementById("pipelineSettingsModal"); + let pipelineSettingsContent = document.getElementById("pipelineSettingsContent"); + let operationData = apiDocs[operation].post.parameters || []; - listItem.querySelector('.pipelineSettings').addEventListener('click', function(event) { - event.preventDefault(); - showpipelineSettingsModal(selectedOperation); - hideOrShowPipelineHeader(); - }); + // Resolve the $ref reference to get actual schema properties + let refKey = apiDocs[operation].post.requestBody.content["multipart/form-data"].schema["$ref"].split("/").pop(); + let requestBodyData = apiSchemas[refKey].properties || {}; - function showpipelineSettingsModal(operation) { - let pipelineSettingsModal = document.getElementById('pipelineSettingsModal'); - let pipelineSettingsContent = document.getElementById('pipelineSettingsContent'); - let operationData = apiDocs[operation].post.parameters || []; + // Combine operationData and requestBodyData into a single array + operationData = operationData.concat( + Object.keys(requestBodyData).map((key) => ({ + name: key, + schema: requestBodyData[key], + })), + ); - // Resolve the $ref reference to get actual schema properties - let refKey = apiDocs[operation].post.requestBody.content['multipart/form-data'].schema['$ref'].split('/').pop(); - let requestBodyData = apiSchemas[refKey].properties || {}; + pipelineSettingsContent.innerHTML = ""; - // Combine operationData and requestBodyData into a single array - operationData = operationData.concat(Object.keys(requestBodyData).map(key => ({ - name: key, - schema: requestBodyData[key] - }))); + operationData.forEach((parameter) => { + // If the parameter name is 'fileInput', return early to skip the rest of this iteration + if (parameter.name === "fileInput") return; - pipelineSettingsContent.innerHTML = ''; + let parameterDiv = document.createElement("div"); + parameterDiv.className = "mb-3"; - operationData.forEach(parameter => { - // If the parameter name is 'fileInput', return early to skip the rest of this iteration - if (parameter.name === 'fileInput') return; + let parameterLabel = document.createElement("label"); + parameterLabel.textContent = `${parameter.name} (${parameter.schema.type}): `; + parameterLabel.title = parameter.schema.description; + parameterLabel.setAttribute("for", parameter.name); + parameterDiv.appendChild(parameterLabel); - let parameterDiv = document.createElement('div'); - parameterDiv.className = "mb-3"; + let defaultValue = parameter.schema.example; + if (defaultValue === undefined) defaultValue = parameter.schema.default; - let parameterLabel = document.createElement('label'); - parameterLabel.textContent = `${parameter.name} (${parameter.schema.type}): `; - parameterLabel.title = parameter.schema.description; - parameterLabel.setAttribute('for', parameter.name); - parameterDiv.appendChild(parameterLabel); + let parameterInput; - let defaultValue = parameter.schema.example; - if (defaultValue === undefined) defaultValue = parameter.schema.default; + // check if enum exists in schema + if (parameter.schema.enum) { + // if enum exists, create a select element + parameterInput = document.createElement("select"); + parameterInput.className = "form-control"; - let parameterInput; + // iterate over each enum value and create an option for it + parameter.schema.enum.forEach((value) => { + let option = document.createElement("option"); + option.value = value; + option.text = value; + parameterInput.appendChild(option); + }); + } else { + // switch-case statement for handling non-enum types + switch (parameter.schema.type) { + case "string": + if (parameter.schema.format === "binary") { + // This is a file input - // check if enum exists in schema - if (parameter.schema.enum) { - // if enum exists, create a select element - parameterInput = document.createElement('select'); - parameterInput.className = "form-control"; - - // iterate over each enum value and create an option for it - parameter.schema.enum.forEach(value => { - let option = document.createElement('option'); - option.value = value; - option.text = value; - parameterInput.appendChild(option); - }); - } else { - // switch-case statement for handling non-enum types - switch (parameter.schema.type) { - case 'string': - if (parameter.schema.format === 'binary') { - // This is a file input - - //parameterInput = document.createElement('input'); - //parameterInput.type = 'file'; - //parameterInput.className = "form-control"; - - parameterInput = document.createElement('input'); - parameterInput.type = 'text'; - parameterInput.className = "form-control"; - parameterInput.value = "FileInputPathToBeInputtedManuallyForOffline"; - } else { - parameterInput = document.createElement('input'); - parameterInput.type = 'text'; - parameterInput.className = "form-control"; - if (defaultValue !== undefined) parameterInput.value = defaultValue; - } - break; - case 'number': - case 'integer': - parameterInput = document.createElement('input'); - parameterInput.type = 'number'; - parameterInput.className = "form-control"; - if (defaultValue !== undefined) parameterInput.value = defaultValue; - break; - case 'boolean': - parameterInput = document.createElement('input'); - parameterInput.type = 'checkbox'; - if (defaultValue === true) parameterInput.checked = true; - break; - case 'array': - case 'object': - //TODO compare to doc and check if fileInput array? parameter.schema.format === 'binary' - parameterInput = document.createElement('textarea'); - parameterInput.placeholder = `Enter a JSON formatted ${parameter.schema.type}, If this is a fileInput, it is not currently supported`; - parameterInput.className = "form-control"; - break; - default: - parameterInput = document.createElement('input'); - parameterInput.type = 'text'; - parameterInput.className = "form-control"; - if (defaultValue !== undefined) parameterInput.value = defaultValue; - } - } - parameterInput.id = parameter.name; - - console.log("defaultValue", defaultValue); - console.log("parameterInput", parameterInput); - if (operationSettings[operation] && operationSettings[operation][parameter.name] !== undefined) { - let savedValue = operationSettings[operation][parameter.name]; - - switch (parameter.schema.type) { - case 'number': - case 'integer': - parameterInput.value = savedValue.toString(); - break; - case 'boolean': - parameterInput.checked = savedValue; - break; - case 'array': - case 'object': - parameterInput.value = JSON.stringify(savedValue); - break; - default: - parameterInput.value = savedValue; - } - } - console.log("parameterInput2", parameterInput); - parameterDiv.appendChild(parameterInput); - - pipelineSettingsContent.appendChild(parameterDiv); - }); - - if(hasSettings) { - let saveButton = document.createElement('button'); - saveButton.textContent = saveSettings; - saveButton.className = "btn btn-primary"; - saveButton.addEventListener('click', function(event) { - event.preventDefault(); - let settings = {}; - operationData.forEach(parameter => { - if (parameter.name !== "fileInput") { - let value = document.getElementById(parameter.name).value; - switch (parameter.schema.type) { - case 'number': - case 'integer': - settings[parameter.name] = Number(value); - break; - case 'boolean': - settings[parameter.name] = document.getElementById(parameter.name).checked; - break; - case 'array': - case 'object': - if (value === null || value === '') { - settings[parameter.name] = ''; - } else { - try { - settings[parameter.name] = JSON.parse(value); - } catch (err) { - console.error(`Invalid JSON format for ${parameter.name}`); - } - } - break; - default: - settings[parameter.name] = value; - } - } - }); - operationSettings[operation] = settings; - //pipelineSettingsModal.style.display = "none"; - }); - pipelineSettingsContent.appendChild(saveButton); - saveButton.click(); - } - //pipelineSettingsModal.style.display = "block"; - - //pipelineSettingsModal.getElementsByClassName("close")[0].onclick = function() { - // pipelineSettingsModal.style.display = "none"; - //} - - //window.onclick = function(event) { - // if (event.target == pipelineSettingsModal) { - // pipelineSettingsModal.style.display = "none"; - // } - //} - } - showpipelineSettingsModal(selectedOperation); - updateConfigInDropdown(); - hideOrShowPipelineHeader(); + //parameterInput = document.createElement('input'); + //parameterInput.type = 'file'; + //parameterInput.className = "form-control"; + parameterInput = document.createElement("input"); + parameterInput.type = "text"; + parameterInput.className = "form-control"; + parameterInput.value = "FileInputPathToBeInputtedManuallyForOffline"; + } else { + parameterInput = document.createElement("input"); + parameterInput.type = "text"; + parameterInput.className = "form-control"; + if (defaultValue !== undefined) parameterInput.value = defaultValue; + } + break; + case "number": + case "integer": + parameterInput = document.createElement("input"); + parameterInput.type = "number"; + parameterInput.className = "form-control"; + if (defaultValue !== undefined) parameterInput.value = defaultValue; + break; + case "boolean": + parameterInput = document.createElement("input"); + parameterInput.type = "checkbox"; + if (defaultValue === true) parameterInput.checked = true; + break; + case "array": + case "object": + //TODO compare to doc and check if fileInput array? parameter.schema.format === 'binary' + parameterInput = document.createElement("textarea"); + parameterInput.placeholder = `Enter a JSON formatted ${parameter.schema.type}, If this is a fileInput, it is not currently supported`; + parameterInput.className = "form-control"; + break; + default: + parameterInput = document.createElement("input"); + parameterInput.type = "text"; + parameterInput.className = "form-control"; + if (defaultValue !== undefined) parameterInput.value = defaultValue; + } + } + parameterInput.id = parameter.name; + console.log("defaultValue", defaultValue); + console.log("parameterInput", parameterInput); + if (operationSettings[operation] && operationSettings[operation][parameter.name] !== undefined) { + let savedValue = operationSettings[operation][parameter.name]; + switch (parameter.schema.type) { + case "number": + case "integer": + parameterInput.value = savedValue.toString(); + break; + case "boolean": + parameterInput.checked = savedValue; + break; + case "array": + case "object": + parameterInput.value = JSON.stringify(savedValue); + break; + default: + parameterInput.value = savedValue; + } + } + console.log("parameterInput2", parameterInput); + parameterDiv.appendChild(parameterInput); + pipelineSettingsContent.appendChild(parameterDiv); + }); + if (hasSettings) { + let saveButton = document.createElement("button"); + saveButton.textContent = saveSettings; + saveButton.className = "btn btn-primary"; + saveButton.addEventListener("click", function (event) { + event.preventDefault(); + let settings = {}; + operationData.forEach((parameter) => { + if (parameter.name !== "fileInput") { + let value = document.getElementById(parameter.name).value; + switch (parameter.schema.type) { + case "number": + case "integer": + settings[parameter.name] = Number(value); + break; + case "boolean": + settings[parameter.name] = document.getElementById(parameter.name).checked; + break; + case "array": + case "object": + if (value === null || value === "") { + settings[parameter.name] = ""; + } else { + try { + settings[parameter.name] = JSON.parse(value); + } catch (err) { + console.error(`Invalid JSON format for ${parameter.name}`); + } + } + break; + default: + settings[parameter.name] = value; + } + } + }); + operationSettings[operation] = settings; + //pipelineSettingsModal.style.display = "none"; + }); + pipelineSettingsContent.appendChild(saveButton); + saveButton.click(); + } + //pipelineSettingsModal.style.display = "block"; + //pipelineSettingsModal.getElementsByClassName("close")[0].onclick = function() { + // pipelineSettingsModal.style.display = "none"; + //} + //window.onclick = function(event) { + // if (event.target == pipelineSettingsModal) { + // pipelineSettingsModal.style.display = "none"; + // } + //} + } + showpipelineSettingsModal(selectedOperation); + updateConfigInDropdown(); + hideOrShowPipelineHeader(); }); function updateConfigInDropdown() { - let pipelineSelect = document.getElementById('pipelineSelect'); - let selectedOption = pipelineSelect.options[pipelineSelect.selectedIndex]; + let pipelineSelect = document.getElementById("pipelineSelect"); + let selectedOption = pipelineSelect.options[pipelineSelect.selectedIndex]; - // Get the current configuration as JSON - let pipelineConfigJson = configToJson(); - console.log("pipelineConfigJson", pipelineConfigJson); - if (!pipelineConfigJson) { - console.error("Failed to update configuration: Invalid configuration"); - return; - } - - // Update the value of the selected option with the new configuration - selectedOption.value = pipelineConfigJson; + // Get the current configuration as JSON + let pipelineConfigJson = configToJson(); + console.log("pipelineConfigJson", pipelineConfigJson); + if (!pipelineConfigJson) { + console.error("Failed to update configuration: Invalid configuration"); + return; + } + // Update the value of the selected option with the new configuration + selectedOption.value = pipelineConfigJson; } -var saveBtn = document.getElementById('savePipelineBtn'); +var saveBtn = document.getElementById("savePipelineBtn"); // Remove any existing event listeners -saveBtn.removeEventListener('click', savePipeline); +saveBtn.removeEventListener("click", savePipeline); // Add the event listener -saveBtn.addEventListener('click', savePipeline); -console.log("saveBtn", saveBtn) +saveBtn.addEventListener("click", savePipeline); +console.log("saveBtn", saveBtn); function configToJson() { - if (!validatePipeline()) { - return null; // Return null if validation fails - } + if (!validatePipeline()) { + return null; // Return null if validation fails + } - var pipelineName = document.getElementById('pipelineName').value; - let pipelineList = document.getElementById('pipelineList').children; - let pipelineConfig = { - "name": pipelineName, - "pipeline": [], - "_examples": { - "outputDir": "{outputFolder}/{folderName}", - "outputFileName": "{filename}-{pipelineName}-{date}-{time}" - }, - "outputDir": "{outputFolder}", - "outputFileName": "{filename}" - }; + var pipelineName = document.getElementById("pipelineName").value; + let pipelineList = document.getElementById("pipelineList").children; + let pipelineConfig = { + name: pipelineName, + pipeline: [], + _examples: { + outputDir: "{outputFolder}/{folderName}", + outputFileName: "{filename}-{pipelineName}-{date}-{time}", + }, + outputDir: "{outputFolder}", + outputFileName: "{filename}", + }; - for (let i = 0; i < pipelineList.length; i++) { - let operationName = pipelineList[i].querySelector('.operationName').textContent; - let parameters = operationSettings[operationName] || {}; + for (let i = 0; i < pipelineList.length; i++) { + let operationName = pipelineList[i].querySelector(".operationName").textContent; + let parameters = operationSettings[operationName] || {}; - parameters['fileInput'] = 'automated'; + parameters["fileInput"] = "automated"; - pipelineConfig.pipeline.push({ - "operation": operationName, - "parameters": parameters - }); - } + pipelineConfig.pipeline.push({ + operation: operationName, + parameters: parameters, + }); + } - return JSON.stringify(pipelineConfig, null, 2); + return JSON.stringify(pipelineConfig, null, 2); } - - function savePipeline() { - let pipelineConfigJson = configToJson(); - if (!pipelineConfigJson) { - console.error("Failed to save pipeline: Invalid configuration"); - return; - } + let pipelineConfigJson = configToJson(); + if (!pipelineConfigJson) { + console.error("Failed to save pipeline: Invalid configuration"); + return; + } - let pipelineName = document.getElementById('pipelineName').value; - console.log("Downloading..."); - let a = document.createElement('a'); - a.href = URL.createObjectURL(new Blob([pipelineConfigJson], { type: 'application/json' })); - a.download = pipelineName + '.json'; - a.style.display = 'none'; + let pipelineName = document.getElementById("pipelineName").value; + console.log("Downloading..."); + let a = document.createElement("a"); + a.href = URL.createObjectURL(new Blob([pipelineConfigJson], { type: "application/json" })); + a.download = pipelineName + ".json"; + a.style.display = "none"; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); } - async function processPipelineConfig(configString) { - console.log("configString", configString); - let pipelineConfig = JSON.parse(configString); - let pipelineList = document.getElementById('pipelineList'); + console.log("configString", configString); + let pipelineConfig = JSON.parse(configString); + let pipelineList = document.getElementById("pipelineList"); - while (pipelineList.firstChild) { - pipelineList.removeChild(pipelineList.firstChild); - } - document.getElementById('pipelineName').value = pipelineConfig.name - for (const operationConfig of pipelineConfig.pipeline) { - let operationsDropdown = document.getElementById('operationsDropdown'); - operationsDropdown.value = operationConfig.operation; - operationSettings[operationConfig.operation] = operationConfig.parameters; + while (pipelineList.firstChild) { + pipelineList.removeChild(pipelineList.firstChild); + } + document.getElementById("pipelineName").value = pipelineConfig.name; + for (const operationConfig of pipelineConfig.pipeline) { + let operationsDropdown = document.getElementById("operationsDropdown"); + operationsDropdown.value = operationConfig.operation; + operationSettings[operationConfig.operation] = operationConfig.parameters; - // assuming addOperation is async - await new Promise((resolve) => { - document.getElementById('addOperationBtn').addEventListener('click', resolve, { once: true }); - document.getElementById('addOperationBtn').click(); - }); + // assuming addOperation is async + await new Promise((resolve) => { + document.getElementById("addOperationBtn").addEventListener("click", resolve, { once: true }); + document.getElementById("addOperationBtn").click(); + }); - let lastOperation = pipelineList.lastChild; + let lastOperation = pipelineList.lastChild; - Object.keys(operationConfig.parameters).forEach(parameterName => { - let input = document.getElementById(parameterName); - if (input) { - switch (input.type) { - case 'checkbox': - input.checked = operationConfig.parameters[parameterName]; - break; - case 'number': - input.value = operationConfig.parameters[parameterName].toString(); - break; - case 'file': - if (parameterName !== 'fileInput') { - // Create a new file input element - let newInput = document.createElement('input'); - newInput.type = 'file'; - newInput.id = parameterName; + Object.keys(operationConfig.parameters).forEach((parameterName) => { + let input = document.getElementById(parameterName); + if (input) { + switch (input.type) { + case "checkbox": + input.checked = operationConfig.parameters[parameterName]; + break; + case "number": + input.value = operationConfig.parameters[parameterName].toString(); + break; + case "file": + if (parameterName !== "fileInput") { + // Create a new file input element + let newInput = document.createElement("input"); + newInput.type = "file"; + newInput.id = parameterName; - // Add the new file input to the main page (change the selector according to your needs) - document.querySelector('#main').appendChild(newInput); - } - break; - case 'text': - case 'textarea': - default: - input.value = JSON.stringify(operationConfig.parameters[parameterName]); - } - } - }); - - } + // Add the new file input to the main page (change the selector according to your needs) + document.querySelector("#main").appendChild(newInput); + } + break; + case "text": + case "textarea": + default: + input.value = JSON.stringify(operationConfig.parameters[parameterName]); + } + } + }); + } } - -document.getElementById('uploadPipelineBtn').addEventListener('click', function() { - document.getElementById('uploadPipelineInput').click(); +document.getElementById("uploadPipelineBtn").addEventListener("click", function () { + document.getElementById("uploadPipelineInput").click(); }); -document.getElementById('uploadPipelineInput').addEventListener('change', function(e) { - let reader = new FileReader(); - reader.onload = function(event) { - processPipelineConfig(event.target.result); - }; - reader.readAsText(e.target.files[0]); - hideOrShowPipelineHeader(); +document.getElementById("uploadPipelineInput").addEventListener("change", function (e) { + let reader = new FileReader(); + reader.onload = function (event) { + processPipelineConfig(event.target.result); + }; + reader.readAsText(e.target.files[0]); + hideOrShowPipelineHeader(); }); -document.getElementById('pipelineSelect').addEventListener('change', function(e) { - let selectedPipelineJson = e.target.value; // assuming the selected value is the JSON string of the pipeline config - processPipelineConfig(selectedPipelineJson); +document.getElementById("pipelineSelect").addEventListener("change", function (e) { + let selectedPipelineJson = e.target.value; // assuming the selected value is the JSON string of the pipeline config + processPipelineConfig(selectedPipelineJson); }); - function hideOrShowPipelineHeader() { - var pipelineHeader = document.getElementById('pipelineHeader'); - var pipelineList = document.getElementById('pipelineList'); + var pipelineHeader = document.getElementById("pipelineHeader"); + var pipelineList = document.getElementById("pipelineList"); - if (pipelineList.children.length === 0) { - // Hide the pipeline header if there are no items in the pipeline list - pipelineHeader.style.display = 'none'; - } else { - // Show the pipeline header if there are items in the pipeline list - pipelineHeader.style.display = 'block'; - } + if (pipelineList.children.length === 0) { + // Hide the pipeline header if there are no items in the pipeline list + pipelineHeader.style.display = "none"; + } else { + // Show the pipeline header if there are items in the pipeline list + pipelineHeader.style.display = "block"; + } } diff --git a/src/main/resources/static/js/search.js b/src/main/resources/static/js/search.js index 674b54b7..2329f998 100644 --- a/src/main/resources/static/js/search.js +++ b/src/main/resources/static/js/search.js @@ -1,75 +1,76 @@ // Toggle search bar when the search icon is clicked -document.querySelector('#search-icon').addEventListener('click', function(e) { - e.preventDefault(); - var searchBar = document.querySelector('#navbarSearch'); - searchBar.classList.toggle('show'); +document.querySelector("#search-icon").addEventListener("click", function (e) { + e.preventDefault(); + var searchBar = document.querySelector("#navbarSearch"); + searchBar.classList.toggle("show"); }); -window.onload = function() { - var items = document.querySelectorAll('.dropdown-item, .nav-link'); - var dummyContainer = document.createElement('div'); - dummyContainer.style.position = 'absolute'; - dummyContainer.style.visibility = 'hidden'; - dummyContainer.style.whiteSpace = 'nowrap'; // Ensure we measure full width - document.body.appendChild(dummyContainer); +window.onload = function () { + var items = document.querySelectorAll(".dropdown-item, .nav-link"); + var dummyContainer = document.createElement("div"); + dummyContainer.style.position = "absolute"; + dummyContainer.style.visibility = "hidden"; + dummyContainer.style.whiteSpace = "nowrap"; // Ensure we measure full width + document.body.appendChild(dummyContainer); - var maxWidth = 0; + var maxWidth = 0; - items.forEach(function(item) { - var clone = item.cloneNode(true); - dummyContainer.appendChild(clone); - var width = clone.offsetWidth; - if (width > maxWidth) { - maxWidth = width; - } - dummyContainer.removeChild(clone); - }); + items.forEach(function (item) { + var clone = item.cloneNode(true); + dummyContainer.appendChild(clone); + var width = clone.offsetWidth; + if (width > maxWidth) { + maxWidth = width; + } + dummyContainer.removeChild(clone); + }); - document.body.removeChild(dummyContainer); + document.body.removeChild(dummyContainer); - // Store max width for later use - window.navItemMaxWidth = maxWidth; + // Store max width for later use + window.navItemMaxWidth = maxWidth; }; // Show search results as user types in search box -document.querySelector('#navbarSearchInput').addEventListener('input', function(e) { - var searchText = e.target.value.toLowerCase(); - var items = document.querySelectorAll('.dropdown-item, .nav-link'); - var resultsBox = document.querySelector('#searchResults'); +document.querySelector("#navbarSearchInput").addEventListener("input", function (e) { + var searchText = e.target.value.toLowerCase(); + var items = document.querySelectorAll(".dropdown-item, .nav-link"); + var resultsBox = document.querySelector("#searchResults"); - // Clear any previous results - resultsBox.innerHTML = ''; + // Clear any previous results + resultsBox.innerHTML = ""; - items.forEach(function(item) { - var titleElement = item.querySelector('.icon-text'); - var iconElement = item.querySelector('.icon'); - var itemHref = item.getAttribute('href'); - var tags = item.getAttribute('data-bs-tags') || ""; // If no tags, default to empty string + items.forEach(function (item) { + var titleElement = item.querySelector(".icon-text"); + var iconElement = item.querySelector(".icon"); + var itemHref = item.getAttribute("href"); + var tags = item.getAttribute("data-bs-tags") || ""; // If no tags, default to empty string - if (titleElement && iconElement && itemHref !== '#') { - var title = titleElement.innerText; - if ((title.toLowerCase().indexOf(searchText) !== -1 || tags.toLowerCase().indexOf(searchText) !== -1) && !resultsBox.querySelector(`a[href="${item.getAttribute('href')}"]`)) { - var result = document.createElement('a'); - result.href = itemHref; - result.classList.add('dropdown-item'); + if (titleElement && iconElement && itemHref !== "#") { + var title = titleElement.innerText; + if ( + (title.toLowerCase().indexOf(searchText) !== -1 || tags.toLowerCase().indexOf(searchText) !== -1) && + !resultsBox.querySelector(`a[href="${item.getAttribute("href")}"]`) + ) { + var result = document.createElement("a"); + result.href = itemHref; + result.classList.add("dropdown-item"); - var resultIcon = document.createElement('img'); - resultIcon.src = iconElement.src; - resultIcon.alt = 'icon'; - resultIcon.classList.add('icon'); - result.appendChild(resultIcon); + var resultIcon = document.createElement("img"); + resultIcon.src = iconElement.src; + resultIcon.alt = "icon"; + resultIcon.classList.add("icon"); + result.appendChild(resultIcon); - var resultText = document.createElement('span'); - resultText.textContent = title; - resultText.classList.add('icon-text'); - result.appendChild(resultText); + var resultText = document.createElement("span"); + resultText.textContent = title; + resultText.classList.add("icon-text"); + result.appendChild(resultText); - resultsBox.appendChild(result); - } - } - }); + resultsBox.appendChild(result); + } + } + }); - // Set the width of the search results box to the maximum width - resultsBox.style.width = window.navItemMaxWidth + 'px'; + // Set the width of the search results box to the maximum width + resultsBox.style.width = window.navItemMaxWidth + "px"; }); - - diff --git a/src/main/resources/static/js/settings.js b/src/main/resources/static/js/settings.js index 272b555b..77a55a3f 100644 --- a/src/main/resources/static/js/settings.js +++ b/src/main/resources/static/js/settings.js @@ -1,42 +1,33 @@ // Get the download option from local storage, or set it to 'sameWindow' if it doesn't exist -var downloadOption = localStorage.getItem('downloadOption') - || 'sameWindow'; +var downloadOption = localStorage.getItem("downloadOption") || "sameWindow"; // Set the selected option in the dropdown -document.getElementById('downloadOption').value = downloadOption; - +document.getElementById("downloadOption").value = downloadOption; // Save the selected option to local storage when the dropdown value changes -document.getElementById('downloadOption').addEventListener( - 'change', - function() { - downloadOption = this.value; - localStorage.setItem('downloadOption', - downloadOption); - }); - - -// Get the zipThreshold value from local storage, or set it to 0 if it doesn't exist -var zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4; - -// Set the value of the slider and the display span -document.getElementById('zipThreshold').value = zipThreshold; -document.getElementById('zipThresholdValue').textContent = zipThreshold; - - - -// Save the selected value to local storage when the slider value changes -document.getElementById('zipThreshold').addEventListener('input', function() { - zipThreshold = this.value; - document.getElementById('zipThresholdValue').textContent = zipThreshold; - localStorage.setItem('zipThreshold', zipThreshold); +document.getElementById("downloadOption").addEventListener("change", function () { + downloadOption = this.value; + localStorage.setItem("downloadOption", downloadOption); }); +// Get the zipThreshold value from local storage, or set it to 0 if it doesn't exist +var zipThreshold = parseInt(localStorage.getItem("zipThreshold"), 10) || 4; -var boredWaiting = localStorage.getItem('boredWaiting') || 'disabled'; -document.getElementById('boredWaiting').checked = boredWaiting === 'enabled'; +// Set the value of the slider and the display span +document.getElementById("zipThreshold").value = zipThreshold; +document.getElementById("zipThresholdValue").textContent = zipThreshold; -document.getElementById('boredWaiting').addEventListener('change', function() { - boredWaiting = this.checked ? 'enabled' : 'disabled'; - localStorage.setItem('boredWaiting', boredWaiting); -}); \ No newline at end of file +// Save the selected value to local storage when the slider value changes +document.getElementById("zipThreshold").addEventListener("input", function () { + zipThreshold = this.value; + document.getElementById("zipThresholdValue").textContent = zipThreshold; + localStorage.setItem("zipThreshold", zipThreshold); +}); + +var boredWaiting = localStorage.getItem("boredWaiting") || "disabled"; +document.getElementById("boredWaiting").checked = boredWaiting === "enabled"; + +document.getElementById("boredWaiting").addEventListener("change", function () { + boredWaiting = this.checked ? "enabled" : "disabled"; + localStorage.setItem("boredWaiting", boredWaiting); +}); diff --git a/src/main/resources/static/js/tab-container.js b/src/main/resources/static/js/tab-container.js index bd97d2b6..2aa85b32 100644 --- a/src/main/resources/static/js/tab-container.js +++ b/src/main/resources/static/js/tab-container.js @@ -1,39 +1,38 @@ - TabContainer = { - initTabGroups() { - const groups = document.querySelectorAll(".tab-group"); - const unloadedGroups = [...groups].filter(g => !g.initialised); - unloadedGroups.forEach(group => { - const containers = group.querySelectorAll(".tab-container"); - const tabTitles = [...containers].map(c => c.getAttribute("title")); + initTabGroups() { + const groups = document.querySelectorAll(".tab-group"); + const unloadedGroups = [...groups].filter((g) => !g.initialised); + unloadedGroups.forEach((group) => { + const containers = group.querySelectorAll(".tab-container"); + const tabTitles = [...containers].map((c) => c.getAttribute("title")); - const tabList = document.createElement("div"); - tabList.classList.add("tab-buttons"); - tabTitles.forEach(title => { - const tabButton = document.createElement("button"); - tabButton.innerHTML = title; - tabButton.onclick = e => { - this.setActiveTab(e.target); - } - tabList.appendChild(tabButton); - }); - group.prepend(tabList); + const tabList = document.createElement("div"); + tabList.classList.add("tab-buttons"); + tabTitles.forEach((title) => { + const tabButton = document.createElement("button"); + tabButton.innerHTML = title; + tabButton.onclick = (e) => { + this.setActiveTab(e.target); + }; + tabList.appendChild(tabButton); + }); + group.prepend(tabList); - this.setActiveTab(tabList.firstChild); + this.setActiveTab(tabList.firstChild); - group.initialised = true; - }); - }, - setActiveTab(tabButton) { - const group = tabButton.closest(".tab-group") + group.initialised = true; + }); + }, + setActiveTab(tabButton) { + const group = tabButton.closest(".tab-group"); - group.querySelectorAll(".active").forEach(el => el.classList.remove("active")); + group.querySelectorAll(".active").forEach((el) => el.classList.remove("active")); - tabButton.classList.add("active"); - group.querySelector(`[title="${tabButton.innerHTML}"]`).classList.add("active"); - }, -} + tabButton.classList.add("active"); + group.querySelector(`[title="${tabButton.innerHTML}"]`).classList.add("active"); + }, +}; document.addEventListener("DOMContentLoaded", () => { - TabContainer.initTabGroups(); -}) \ No newline at end of file + TabContainer.initTabGroups(); +}); diff --git a/src/main/resources/static/pdfjs/css/viewer.css b/src/main/resources/static/pdfjs/css/viewer.css index 14a8aff0..ab0ad406 100644 --- a/src/main/resources/static/pdfjs/css/viewer.css +++ b/src/main/resources/static/pdfjs/css/viewer.css @@ -116,7 +116,6 @@ top: 0; } - :root { --annotation-unfocused-field-background: url("data:image/svg+xml;charset=UTF-8,"); --input-focus-border-color: Highlight; @@ -139,9 +138,7 @@ .annotationLayer .textWidgetAnnotation :is(input, textarea):required, .annotationLayer .choiceWidgetAnnotation select:required, - .annotationLayer - .buttonWidgetAnnotation:is(.checkBox, .radioButton) - input:required { + .annotationLayer .buttonWidgetAnnotation:is(.checkBox, .radioButton) input:required { outline: 1.5px solid selectedItem; } @@ -228,9 +225,7 @@ height: 100%; } -.annotationLayer -:is(.linkAnnotation, .buttonWidgetAnnotation.pushButton):not(.hasBorder) -> a:hover { +.annotationLayer :is(.linkAnnotation, .buttonWidgetAnnotation.pushButton):not(.hasBorder) > a:hover { opacity: 0.2; background-color: rgba(255, 255, 0, 1); box-shadow: 0 2px 10px rgba(255, 255, 0, 1); @@ -268,9 +263,7 @@ .annotationLayer .textWidgetAnnotation :is(input, textarea):required, .annotationLayer .choiceWidgetAnnotation select:required, -.annotationLayer -.buttonWidgetAnnotation:is(.checkBox, .radioButton) -input:required { +.annotationLayer .buttonWidgetAnnotation:is(.checkBox, .radioButton) input:required { outline: 1.5px solid red; } @@ -288,9 +281,7 @@ input:required { .annotationLayer .textWidgetAnnotation :is(input, textarea)[disabled], .annotationLayer .choiceWidgetAnnotation select[disabled], -.annotationLayer -.buttonWidgetAnnotation:is(.checkBox, .radioButton) -input[disabled] { +.annotationLayer .buttonWidgetAnnotation:is(.checkBox, .radioButton) input[disabled] { background: none; border: 2px solid var(--input-disabled-border-color); cursor: not-allowed; @@ -298,9 +289,7 @@ input[disabled] { .annotationLayer .textWidgetAnnotation :is(input, textarea):hover, .annotationLayer .choiceWidgetAnnotation select:hover, -.annotationLayer -.buttonWidgetAnnotation:is(.checkBox, .radioButton) -input:hover { +.annotationLayer .buttonWidgetAnnotation:is(.checkBox, .radioButton) input:hover { border: 2px solid var(--input-hover-border-color); } @@ -489,7 +478,6 @@ input:hover { z-index: -1; } - :root { --xfa-unfocused-field-background: url("data:image/svg+xml;charset=UTF-8,"); --xfa-focus-outline: auto; @@ -827,10 +815,7 @@ input:hover { --freetext-padding: 2px; --resizer-bg-color: var(--outline-color); --resizer-size: 6px; - --resizer-shift: calc( - 0px - (var(--outline-width) + var(--resizer-size)) / 2 - - var(--outline-around-width) - ); + --resizer-shift: calc(0px - (var(--outline-width) + var(--resizer-size)) / 2 - var(--outline-around-width)); --editorFreeText-editing-cursor: text; --editorInk-editing-cursor: url(../images/cursor-editorInk.svg) 0 16, pointer; @@ -853,8 +838,7 @@ input:hover { @media (-webkit-min-device-pixel-ratio: 1.1), (min-resolution: 1.1dppx) { :root { - --editorFreeText-editing-cursor: url(../images/cursor-editorFreeText.svg) 0 16, - text; + --editorFreeText-editing-cursor: url(../images/cursor-editorFreeText.svg) 0 16, text; } } @@ -1109,216 +1093,354 @@ input:hover { } .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.topLeft, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.topLeft, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.topLeft, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.topLeft, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.topLeft, + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.topLeft, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.topLeft, + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.topLeft, .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.bottomRight, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.bottomRight, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.bottomRight, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.bottomRight, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.bottomRight, + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.bottomRight, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.bottomRight { + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.bottomRight { cursor: nwse-resize; } .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.topMiddle, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.topMiddle, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.topMiddle, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.topMiddle, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.topMiddle, + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.topMiddle, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.topMiddle, + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.topMiddle, .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.bottomMiddle, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.bottomMiddle, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.bottomMiddle, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.bottomMiddle, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.bottomMiddle, + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.bottomMiddle, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.bottomMiddle { + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.bottomMiddle { cursor: ns-resize; } .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.topRight, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.topRight, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.topRight, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.topRight, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.topRight, + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.topRight, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.topRight, + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.topRight, .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.bottomLeft, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.bottomLeft, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.bottomLeft, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.bottomLeft, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.bottomLeft, + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.bottomLeft, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.bottomLeft { + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.bottomLeft { cursor: nesw-resize; } .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.middleRight, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.middleRight, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.middleRight, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.middleRight, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.middleRight, + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.middleRight, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.middleRight, + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.middleRight, .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.middleLeft, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.middleLeft, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.middleLeft, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.middleLeft, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.middleLeft, + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.middleLeft, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.middleLeft { + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.middleLeft { cursor: ew-resize; } .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.topLeft, + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.topLeft, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.topLeft, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.topLeft, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.topLeft, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.topLeft, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.topLeft, + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.topLeft, .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.bottomRight, + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.bottomRight, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.bottomRight, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.bottomRight, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.bottomRight, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.bottomRight, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.bottomRight { + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.bottomRight { cursor: nesw-resize; } .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.topMiddle, + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.topMiddle, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.topMiddle, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.topMiddle, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.topMiddle, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.topMiddle, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.topMiddle, + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.topMiddle, .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.bottomMiddle, + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.bottomMiddle, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.bottomMiddle, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.bottomMiddle, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.bottomMiddle, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.bottomMiddle, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.bottomMiddle { + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.bottomMiddle { cursor: ew-resize; } .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.topRight, + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.topRight, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.topRight, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.topRight, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.topRight, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.topRight, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.topRight, + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.topRight, .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.bottomLeft, + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.bottomLeft, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.bottomLeft, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.bottomLeft, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.bottomLeft, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.bottomLeft, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.bottomLeft { + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.bottomLeft { cursor: nwse-resize; } .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.middleRight, + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.middleRight, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.middleRight, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.middleRight, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.middleRight, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.middleRight, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.middleRight, + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.middleRight, .annotationEditorLayer[data-main-rotation="0"] -:is([data-editor-rotation="90"], [data-editor-rotation="270"]) > .resizers > .resizer.middleLeft, + :is([data-editor-rotation="90"], [data-editor-rotation="270"]) + > .resizers + > .resizer.middleLeft, .annotationEditorLayer[data-main-rotation="90"] -:is([data-editor-rotation="0"], [data-editor-rotation="180"]) > .resizers > .resizer.middleLeft, + :is([data-editor-rotation="0"], [data-editor-rotation="180"]) + > .resizers + > .resizer.middleLeft, .annotationEditorLayer[data-main-rotation="180"] -:is([data-editor-rotation="270"], [data-editor-rotation="90"]) > .resizers > .resizer.middleLeft, + :is([data-editor-rotation="270"], [data-editor-rotation="90"]) + > .resizers + > .resizer.middleLeft, .annotationEditorLayer[data-main-rotation="270"] -:is([data-editor-rotation="180"], [data-editor-rotation="0"]) > .resizers > .resizer.middleLeft { + :is([data-editor-rotation="180"], [data-editor-rotation="0"]) + > .resizers + > .resizer.middleLeft { cursor: ns-resize; } .annotationEditorLayer -:is( - [data-main-rotation="0"] [data-editor-rotation="90"], - [data-main-rotation="90"] [data-editor-rotation="0"], - [data-main-rotation="180"] [data-editor-rotation="270"], - [data-main-rotation="270"] [data-editor-rotation="180"] - ) .altText { + :is( + [data-main-rotation="0"] [data-editor-rotation="90"], + [data-main-rotation="90"] [data-editor-rotation="0"], + [data-main-rotation="180"] [data-editor-rotation="270"], + [data-main-rotation="270"] [data-editor-rotation="180"] + ) + .altText { rotate: 270deg; } -[dir="ltr"] .annotationEditorLayer -:is( - [data-main-rotation="0"] [data-editor-rotation="90"], - [data-main-rotation="90"] [data-editor-rotation="0"], - [data-main-rotation="180"] [data-editor-rotation="270"], - [data-main-rotation="270"] [data-editor-rotation="180"] - ) .altText { +[dir="ltr"] + .annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="90"], + [data-main-rotation="90"] [data-editor-rotation="0"], + [data-main-rotation="180"] [data-editor-rotation="270"], + [data-main-rotation="270"] [data-editor-rotation="180"] + ) + .altText { inset-inline-start: calc(100% - 8px); } -[dir="ltr"] .annotationEditorLayer -:is( - [data-main-rotation="0"] [data-editor-rotation="90"], - [data-main-rotation="90"] [data-editor-rotation="0"], - [data-main-rotation="180"] [data-editor-rotation="270"], - [data-main-rotation="270"] [data-editor-rotation="180"] - ) .altText.small { +[dir="ltr"] + .annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="90"], + [data-main-rotation="90"] [data-editor-rotation="0"], + [data-main-rotation="180"] [data-editor-rotation="270"], + [data-main-rotation="270"] [data-editor-rotation="180"] + ) + .altText.small { inset-inline-start: calc(100% + 8px); inset-block-start: 100%; } -[dir="rtl"] .annotationEditorLayer -:is( - [data-main-rotation="0"] [data-editor-rotation="90"], - [data-main-rotation="90"] [data-editor-rotation="0"], - [data-main-rotation="180"] [data-editor-rotation="270"], - [data-main-rotation="270"] [data-editor-rotation="180"] - ) .altText { +[dir="rtl"] + .annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="90"], + [data-main-rotation="90"] [data-editor-rotation="0"], + [data-main-rotation="180"] [data-editor-rotation="270"], + [data-main-rotation="270"] [data-editor-rotation="180"] + ) + .altText { inset-block-end: calc(100% - 8px); } -[dir="rtl"] .annotationEditorLayer -:is( - [data-main-rotation="0"] [data-editor-rotation="90"], - [data-main-rotation="90"] [data-editor-rotation="0"], - [data-main-rotation="180"] [data-editor-rotation="270"], - [data-main-rotation="270"] [data-editor-rotation="180"] - ) .altText.small { +[dir="rtl"] + .annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="90"], + [data-main-rotation="90"] [data-editor-rotation="0"], + [data-main-rotation="180"] [data-editor-rotation="270"], + [data-main-rotation="270"] [data-editor-rotation="180"] + ) + .altText.small { inset-inline-start: -8px; inset-block-start: 0; } .annotationEditorLayer -:is( - [data-main-rotation="0"] [data-editor-rotation="180"], - [data-main-rotation="90"] [data-editor-rotation="90"], - [data-main-rotation="180"] [data-editor-rotation="0"], - [data-main-rotation="270"] [data-editor-rotation="270"] - ) .altText { + :is( + [data-main-rotation="0"] [data-editor-rotation="180"], + [data-main-rotation="90"] [data-editor-rotation="90"], + [data-main-rotation="180"] [data-editor-rotation="0"], + [data-main-rotation="270"] [data-editor-rotation="270"] + ) + .altText { rotate: 180deg; inset-block-end: calc(100% - 8px); @@ -1326,64 +1448,74 @@ input:hover { } .annotationEditorLayer -:is( - [data-main-rotation="0"] [data-editor-rotation="180"], - [data-main-rotation="90"] [data-editor-rotation="90"], - [data-main-rotation="180"] [data-editor-rotation="0"], - [data-main-rotation="270"] [data-editor-rotation="270"] - ) .altText.small { + :is( + [data-main-rotation="0"] [data-editor-rotation="180"], + [data-main-rotation="90"] [data-editor-rotation="90"], + [data-main-rotation="180"] [data-editor-rotation="0"], + [data-main-rotation="270"] [data-editor-rotation="270"] + ) + .altText.small { inset-inline-start: 100%; inset-block-start: -8px; } .annotationEditorLayer -:is( - [data-main-rotation="0"] [data-editor-rotation="270"], - [data-main-rotation="90"] [data-editor-rotation="180"], - [data-main-rotation="180"] [data-editor-rotation="90"], - [data-main-rotation="270"] [data-editor-rotation="0"] - ) .altText { + :is( + [data-main-rotation="0"] [data-editor-rotation="270"], + [data-main-rotation="90"] [data-editor-rotation="180"], + [data-main-rotation="180"] [data-editor-rotation="90"], + [data-main-rotation="270"] [data-editor-rotation="0"] + ) + .altText { rotate: 90deg; } -[dir="ltr"] .annotationEditorLayer -:is( - [data-main-rotation="0"] [data-editor-rotation="270"], - [data-main-rotation="90"] [data-editor-rotation="180"], - [data-main-rotation="180"] [data-editor-rotation="90"], - [data-main-rotation="270"] [data-editor-rotation="0"] - ) .altText { +[dir="ltr"] + .annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="270"], + [data-main-rotation="90"] [data-editor-rotation="180"], + [data-main-rotation="180"] [data-editor-rotation="90"], + [data-main-rotation="270"] [data-editor-rotation="0"] + ) + .altText { inset-block-end: calc(100% - 8px); } -[dir="ltr"] .annotationEditorLayer -:is( - [data-main-rotation="0"] [data-editor-rotation="270"], - [data-main-rotation="90"] [data-editor-rotation="180"], - [data-main-rotation="180"] [data-editor-rotation="90"], - [data-main-rotation="270"] [data-editor-rotation="0"] - ) .altText.small { +[dir="ltr"] + .annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="270"], + [data-main-rotation="90"] [data-editor-rotation="180"], + [data-main-rotation="180"] [data-editor-rotation="90"], + [data-main-rotation="270"] [data-editor-rotation="0"] + ) + .altText.small { inset-inline-start: -8px; inset-block-start: 0; } -[dir="rtl"] .annotationEditorLayer -:is( - [data-main-rotation="0"] [data-editor-rotation="270"], - [data-main-rotation="90"] [data-editor-rotation="180"], - [data-main-rotation="180"] [data-editor-rotation="90"], - [data-main-rotation="270"] [data-editor-rotation="0"] - ) .altText { +[dir="rtl"] + .annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="270"], + [data-main-rotation="90"] [data-editor-rotation="180"], + [data-main-rotation="180"] [data-editor-rotation="90"], + [data-main-rotation="270"] [data-editor-rotation="0"] + ) + .altText { inset-inline-start: calc(100% - 8px); } -[dir="rtl"] .annotationEditorLayer -:is( - [data-main-rotation="0"] [data-editor-rotation="270"], - [data-main-rotation="90"] [data-editor-rotation="180"], - [data-main-rotation="180"] [data-editor-rotation="90"], - [data-main-rotation="270"] [data-editor-rotation="0"] - ) .altText.small { +[dir="rtl"] + .annotationEditorLayer + :is( + [data-main-rotation="0"] [data-editor-rotation="270"], + [data-main-rotation="90"] [data-editor-rotation="180"], + [data-main-rotation="180"] [data-editor-rotation="90"], + [data-main-rotation="270"] [data-editor-rotation="0"] + ) + .altText.small { inset-inline-start: calc(100% + 8px); inset-block-start: 100%; } @@ -1421,7 +1553,6 @@ input:hover { } .altText.small { - inset-block-end: unset; inset-inline-start: 0; inset-block-start: calc(100% + 8px); @@ -1515,7 +1646,6 @@ input:hover { } @media (prefers-color-scheme: dark) { - .altText .tooltip.show { --alt-text-tooltip-bg: #1c1b22; --alt-text-tooltip-fg: #fbfbfe; @@ -1524,7 +1654,6 @@ input:hover { } @media screen and (forced-colors: active) { - .altText .tooltip.show { --alt-text-tooltip-bg: Canvas; --alt-text-tooltip-fg: CanvasText; @@ -1581,7 +1710,6 @@ input:hover { } @media (prefers-color-scheme: dark) { - #altTextDialog { --dialog-bg-color: #1c1b22; --dialog-border-color: #1c1b22; @@ -1604,7 +1732,6 @@ input:hover { } @media screen and (forced-colors: active) { - #altTextDialog { --dialog-bg-color: Canvas; --dialog-border-color: CanvasText; @@ -2022,8 +2149,8 @@ input:hover { --toolbar-border-color: rgba(184, 184, 184, 1); --toolbar-box-shadow: 0 1px 0 var(--toolbar-border-color); --toolbar-border-bottom: none; - --toolbarSidebar-box-shadow: inset calc(-1px * var(--dir-factor)) 0 0 rgba(0, 0, 0, 0.25), - 0 1px 0 rgba(0, 0, 0, 0.15), 0 0 1px rgba(0, 0, 0, 0.1); + --toolbarSidebar-box-shadow: inset calc(-1px * var(--dir-factor)) 0 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(0, 0, 0, 0.15), + 0 0 1px rgba(0, 0, 0, 0.1); --toolbarSidebar-border-bottom: none; --button-hover-color: rgba(221, 222, 223, 1); --toggled-btn-color: rgba(0, 0, 0, 1); @@ -2319,8 +2446,7 @@ body { font: message-box; } -:is(.toolbar, .editorParamsToolbar, .findbar, #sidebarContainer) -:is(input, button, select), +:is(.toolbar, .editorParamsToolbar, .findbar, #sidebarContainer) :is(input, button, select), .secondaryToolbar :is(input, button, a, select) { outline: none; font: message-box; @@ -2417,19 +2543,18 @@ body { height: 100%; width: calc(100% + 150px); background: repeating-linear-gradient( - 135deg, - var(--progressBar-blend-color) 0, - var(--progressBar-bg-color) 5px, - var(--progressBar-bg-color) 45px, - var(--progressBar-color) 55px, - var(--progressBar-color) 95px, - var(--progressBar-blend-color) 100px + 135deg, + var(--progressBar-blend-color) 0, + var(--progressBar-bg-color) 5px, + var(--progressBar-bg-color) 45px, + var(--progressBar-color) 55px, + var(--progressBar-color) 95px, + var(--progressBar-blend-color) 100px ); animation: progressIndeterminate 1s linear infinite; } -#outerContainer.sidebarResizing -:is(#sidebarContainer, #viewerContainer, #loadingBar) { +#outerContainer.sidebarResizing :is(#sidebarContainer, #viewerContainer, #loadingBar) { /* Improve responsiveness and avoid visual glitches when the sidebar is resized. */ transition-duration: 0s; } @@ -2600,8 +2725,9 @@ body { .doorHanger, .doorHangerRight { border-radius: 2px; - box-shadow: 0 1px 5px var(--doorhanger-border-color), - 0 0 0 1px var(--doorhanger-border-color); + box-shadow: + 0 1px 5px var(--doorhanger-border-color), + 0 0 0 1px var(--doorhanger-border-color); border: var(--doorhanger-border-color-whcm); } @@ -3455,8 +3581,7 @@ dialog :link { cursor: grab !important; } -.grab-to-pan-grab -*:not(input):not(textarea):not(button):not(select):not(:link) { +.grab-to-pan-grab *:not(input):not(textarea):not(button):not(select):not(:link) { cursor: inherit !important; } diff --git a/src/main/resources/templates/about.html b/src/main/resources/templates/about.html index 1ce5726f..17e79d57 100644 --- a/src/main/resources/templates/about.html +++ b/src/main/resources/templates/about.html @@ -1,22 +1,21 @@ - - - - - -
-
-
-

-
-
-
+ + + + + +
+
+ +

+
+
+
+
+
-
-
- - - + + \ No newline at end of file diff --git a/src/main/resources/templates/account.html b/src/main/resources/templates/account.html index b39da2f1..9b7f4df9 100644 --- a/src/main/resources/templates/account.html +++ b/src/main/resources/templates/account.html @@ -1,326 +1,286 @@ - - + + + + + - - - +
-
-
-

-
-
-
+
+ +

+
+
+
- -

User Settings

-
-
- Default message if not found -
-
- Default message if not found -
-
- Default message if not found -
-
- Default message if not found -
- - - - - - - -

User!

- - - -

-
-
- - -
-
- - -
-
- -
-
- -
- - -

Change Password?

-
-
- - -
-
- - -
-
- - -
-
- -
-
- -
- -
-
- -
-
-
- -
- - - - - -
-
-
-
- - - - -
- -

Sync browser settings with Account

-
-

Settings Comparison:

- - - - - - - - - - - -
PropertyAccount SettingWeb Browser Setting
- -
- - -
-
- - - - - - - - - - - - - - - - - -
+ +

User Settings

+
+ +
+ Default message if not found +
+
+ Default message if not found +
+
+ Default message if not found +
+
+ Default message if not found +
+
+ +

User!

+ + + + +

+
+
+ +
-
+
+ + +
+
+ +
+ +
+ + +

Change Password?

+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +
+ +
+
+
+
+ +
+ + + +
+
+
+
+ + + +
+ +

Sync browser settings with Account

+
+

Settings Comparison:

+ + + + + + + + + + + +
PropertyAccount SettingWeb Browser Setting
+ +
+ + +
+
+ + + +
+
-
+
+
- + diff --git a/src/main/resources/templates/addUsers.html b/src/main/resources/templates/addUsers.html index ff3eb559..0cf3306d 100644 --- a/src/main/resources/templates/addUsers.html +++ b/src/main/resources/templates/addUsers.html @@ -1,84 +1,78 @@ - + + + + - - - +
-
-
-

-
-
-
+
+ +

+
+
+
- -

Admin User Control Settings

+ +

Admin User Control Settings

+ + + + + + + + + + + + + + + +
UsernameRolesActions
+
+ +
+
- - - - - - - - - - - - - - - - - - -
UsernameRolesActions
-
- -
-
- - - -

Add New User

-
- Default message if not found -
-
-
- - -
-
- - -
-
- - -
-
- - -
- - - -
-
+

Add New User

+
+ Default message if not found +
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
-
+ + + +
+
-
+
+
- + diff --git a/src/main/resources/templates/auto-split-pdf.html b/src/main/resources/templates/auto-split-pdf.html index 304216b9..e4d213d8 100644 --- a/src/main/resources/templates/auto-split-pdf.html +++ b/src/main/resources/templates/auto-split-pdf.html @@ -1,44 +1,43 @@ - + + + + - - - - +
-
-
-

-
-
-
-

- -

-
    -
  • -
  • -
  • -
  • -
-
-

-
-
- - -
-

-

- -
-
+
+ +

+
+
+
+

+ +

+
    +
  • +
  • +
  • +
  • +
+
+

+
+
+ +
+

+

+ +
- +
-
+
+
- + \ No newline at end of file diff --git a/src/main/resources/templates/change-creds.html b/src/main/resources/templates/change-creds.html index f5b86b67..4709e40b 100644 --- a/src/main/resources/templates/change-creds.html +++ b/src/main/resources/templates/change-creds.html @@ -1,90 +1,83 @@ - - + + + + + - - - +
-
-
-

-
-
-
- - -

User Settings

-
- -
- Default message if not found -
-
- Default message if not found -
-
- Default message if not found -
-
- Default message if not found -
- - -

User!

- - - -

-

Change Username and password

-
-
- - -
-
- - -
-
- - -
-
- - -
-
- -
-
- - -
- - - +
+ +

+
+
+
+ +

User Settings

+
+ +
+ Default message if not found +
+
+ Default message if not found +
+
+ Default message if not found +
+
+ Default message if not found +
+
+ +

User!

+ +

+

Change Username and password

+
+
+ +
-
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+
-
+
+
- + diff --git a/src/main/resources/templates/convert/book-to-pdf.html b/src/main/resources/templates/convert/book-to-pdf.html index 67facbb3..94229ccf 100644 --- a/src/main/resources/templates/convert/book-to-pdf.html +++ b/src/main/resources/templates/convert/book-to-pdf.html @@ -1,29 +1,31 @@ - + + + + - - +
-
-
-

-
-
-
-

-
-
-
- -
-

-

-
-
+
+ +

+
+
+
+

+
+
+
+ +
+

+

+
-
+
+
- + diff --git a/src/main/resources/templates/convert/file-to-pdf.html b/src/main/resources/templates/convert/file-to-pdf.html index 774c2dc8..3949688f 100644 --- a/src/main/resources/templates/convert/file-to-pdf.html +++ b/src/main/resources/templates/convert/file-to-pdf.html @@ -1,37 +1,34 @@ - + + + + - - - - +
-
-
-

- - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/html-to-pdf.html b/src/main/resources/templates/convert/html-to-pdf.html index f0d17e6e..11184606 100644 --- a/src/main/resources/templates/convert/html-to-pdf.html +++ b/src/main/resources/templates/convert/html-to-pdf.html @@ -1,36 +1,35 @@ - + + + + - - +
-
-
-

-
-
-
-

-
-
- -
- - -
- -
- - -
-

-

-
+
+ +

+
+
+
+

+
+
+
+ +
+
+ +
+

+

+
-
+
+
- + diff --git a/src/main/resources/templates/convert/img-to-pdf.html b/src/main/resources/templates/convert/img-to-pdf.html index 60478409..4de9e0f6 100644 --- a/src/main/resources/templates/convert/img-to-pdf.html +++ b/src/main/resources/templates/convert/img-to-pdf.html @@ -1,88 +1,82 @@ - + + + + - - - +
-
-
-

-
-
-
-

- -
- -
- -
- - -
- -
- - -
-
- - -
-
- -
- - -
- -

- - - -
-
+
+ +

+
+
+
+

+
+
+
+ +
-
+
+ + +
+
+ + +
+
+ +
+ + +
+

+ + + +
+
-
+
+
- + diff --git a/src/main/resources/templates/convert/markdown-to-pdf.html b/src/main/resources/templates/convert/markdown-to-pdf.html index 4606d2b5..d0266aac 100644 --- a/src/main/resources/templates/convert/markdown-to-pdf.html +++ b/src/main/resources/templates/convert/markdown-to-pdf.html @@ -1,30 +1,31 @@ - + + + + - - +
-
-
-

-
-
-
-

-
-
-
- - -
-

-

-
-
+
+ +

+
+
+
+

+
+
+
+ +
+

+

+
-
+
+
- + diff --git a/src/main/resources/templates/convert/pdf-to-book.html b/src/main/resources/templates/convert/pdf-to-book.html index a136c5cf..e8ef9402 100644 --- a/src/main/resources/templates/convert/pdf-to-book.html +++ b/src/main/resources/templates/convert/pdf-to-book.html @@ -1,55 +1,47 @@ - + + + + - - - - -
-
-
-

-
-
-
-

-
-
- -
- - -
-
- - -
-

-

-
-
-
-
-
-
- + + +
+
+ +

+
+
+
+

+
+
+
+ + +
+
+ +
+

+

+
+
+
+
+ +
+ diff --git a/src/main/resources/templates/convert/pdf-to-csv.html b/src/main/resources/templates/convert/pdf-to-csv.html index 463e1a9c..d21156f0 100644 --- a/src/main/resources/templates/convert/pdf-to-csv.html +++ b/src/main/resources/templates/convert/pdf-to-csv.html @@ -1,159 +1,143 @@ - + + + + - - - - -
-
-
-

+ +
+
+ +

-
-
-

-
- -
- -
- - -
-
- - - - -
- -
- - +
+
+

+
+ +
+ +
+ +
+
+ +
+ +
+
+
+
+
-
-
- + diff --git a/src/main/resources/templates/convert/pdf-to-html.html b/src/main/resources/templates/convert/pdf-to-html.html index 7360e631..b2347f02 100644 --- a/src/main/resources/templates/convert/pdf-to-html.html +++ b/src/main/resources/templates/convert/pdf-to-html.html @@ -1,29 +1,30 @@ - + + + + - - +
-
-
-

-
-
-
-

-
-
-
- - -
-

-
-
+
+ +

+
+
+
+

+
+
+
+ +
+

+
-
+
+
- + diff --git a/src/main/resources/templates/convert/pdf-to-img.html b/src/main/resources/templates/convert/pdf-to-img.html index 52bf2e66..61034578 100644 --- a/src/main/resources/templates/convert/pdf-to-img.html +++ b/src/main/resources/templates/convert/pdf-to-img.html @@ -1,61 +1,58 @@ - + + + + - - - - +
-
-
- -

-
-
-
-

-

-
-
-
- - -
-
- - -
-
- - -
-
- - -
- -
- -
+
+ +

+
+
+
+

+

+
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+ +
- +
-
+
+
- + diff --git a/src/main/resources/templates/convert/pdf-to-pdfa.html b/src/main/resources/templates/convert/pdf-to-pdfa.html index 5b0d5cf1..1b75a078 100644 --- a/src/main/resources/templates/convert/pdf-to-pdfa.html +++ b/src/main/resources/templates/convert/pdf-to-pdfa.html @@ -1,32 +1,31 @@ - + + + + - - - - +
-
-
-

-
-
-
-

-

Currently doesn't work for multiple inputs at once

-
-
-
- -
-

-
-
+
+ +

+
+
+
+

+

Currently doesn't work for multiple inputs at once

+
+
+
+ +
+

- +
-
+
+
- + \ No newline at end of file diff --git a/src/main/resources/templates/convert/pdf-to-presentation.html b/src/main/resources/templates/convert/pdf-to-presentation.html index a08c202b..f0a4a44a 100644 --- a/src/main/resources/templates/convert/pdf-to-presentation.html +++ b/src/main/resources/templates/convert/pdf-to-presentation.html @@ -1,38 +1,38 @@ - + + + + - - +
-
-
-

-
-
-
-

-
-
- -
- - -
-
- - -
-

-
+
+ +

+
+
+
+

+
+
+
+ +
+
+ +
+

+
-
+
+
- + diff --git a/src/main/resources/templates/convert/pdf-to-text.html b/src/main/resources/templates/convert/pdf-to-text.html index 8ad6e94a..cc6b7dcb 100644 --- a/src/main/resources/templates/convert/pdf-to-text.html +++ b/src/main/resources/templates/convert/pdf-to-text.html @@ -1,35 +1,38 @@ - + + + + - - +
-
-
-

-
-
-
-

-
-
- -
- - -
-
- - -
-

-
+
+ +

+
+
+
+

+
+
+
+ +
+
+ +
+

+
+
+
+
-
-
+ + + diff --git a/src/main/resources/templates/convert/pdf-to-word.html b/src/main/resources/templates/convert/pdf-to-word.html index 8ed0d9a8..74e6f314 100644 --- a/src/main/resources/templates/convert/pdf-to-word.html +++ b/src/main/resources/templates/convert/pdf-to-word.html @@ -1,40 +1,40 @@ - + + + + - - +
-
-
-

-
-
-
-

-
-
- -
- - -
-
- - -
-

-
+
+ +

+
+
+
+

+
+
+
+ +
+
+ +
+

+
-
+
+
- + diff --git a/src/main/resources/templates/convert/pdf-to-xml.html b/src/main/resources/templates/convert/pdf-to-xml.html index b26a97fe..701220c1 100644 --- a/src/main/resources/templates/convert/pdf-to-xml.html +++ b/src/main/resources/templates/convert/pdf-to-xml.html @@ -1,29 +1,30 @@ - + + + + - - +
-
-
-

-
-
-
-

-
-
-
- - -
-

-
-
+
+ +

+
+
+
+

+
+
+
+ +
+

+
-
+
+
- + diff --git a/src/main/resources/templates/convert/url-to-pdf.html b/src/main/resources/templates/convert/url-to-pdf.html index c74bd5d5..68044385 100644 --- a/src/main/resources/templates/convert/url-to-pdf.html +++ b/src/main/resources/templates/convert/url-to-pdf.html @@ -1,29 +1,30 @@ - + + + + - - +
-
-
-

-
-
-
-

-
- -
- - -
-

-
-
+
+ +

+
+
+
+

+
+ +
+ +
+

+
-
+
+
- + diff --git a/src/main/resources/templates/crop.html b/src/main/resources/templates/crop.html index f0d2186f..825cfbec 100644 --- a/src/main/resources/templates/crop.html +++ b/src/main/resources/templates/crop.html @@ -1,147 +1,135 @@ - + + + + - - - - -
-
-
-

-
-
-
-

-
-
- - - - - -
-
- - -
- - - -
+ +
+
+ +

+
+
+
+

+
+
+ + + + + +
+
+ +
+
+
-
-
- + diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html index 90e654f7..d3cbecb6 100644 --- a/src/main/resources/templates/error.html +++ b/src/main/resources/templates/error.html @@ -1,131 +1,39 @@ - - + - Error! :( - - + -
-
- -
-
-
- -
-

Oops!

-

We can't seem to find the page you're looking for.

-

Something went wrong

- -
-

Need help / Found a issue?

-

If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

-
- Submit a ticket on GitHub - Join our Discord server +
+
+ +
+
+
+

Oops!

+

+ We can't seem to find the page you're looking for. +

+

+ Something went wrong +

+
+

Need help / Found a issue?

+

+ If you're still having trouble, don't hesitate to reach out to us + for help. You can submit a ticket on our GitHub page or contact us + through Discord: +

+ + Go back to homepage
- Go back to homepage
+
-
-
- - - diff --git a/src/main/resources/templates/extract-page.html b/src/main/resources/templates/extract-page.html index 77cc7496..a14e13d2 100644 --- a/src/main/resources/templates/extract-page.html +++ b/src/main/resources/templates/extract-page.html @@ -1,33 +1,33 @@ - + + + + - - - - +
-
-
-

-
-
-
-

-
-
- -
- - -
- - -
-
+
+ +

+
+
+
+

+
+
+ +
+ +
+ + +
+
-
+
+
- + \ No newline at end of file diff --git a/src/main/resources/templates/fragments/card.html b/src/main/resources/templates/fragments/card.html index 1d8193cd..6fa05163 100644 --- a/src/main/resources/templates/fragments/card.html +++ b/src/main/resources/templates/fragments/card.html @@ -1,12 +1,12 @@ -
- -
- Icon -
-
-

-
-
- Favorite -
-
+
+ +
+ Icon +
+
+

+
+
+ Favorite +
+
diff --git a/src/main/resources/templates/fragments/common.html b/src/main/resources/templates/fragments/common.html index 633810ef..78f229c6 100644 --- a/src/main/resources/templates/fragments/common.html +++ b/src/main/resources/templates/fragments/common.html @@ -1,137 +1,144 @@ - + + + - - + + + + + + - - - - - - + + + + + + + + + + + - - - - - - - - - - - + + + - - - + + + + - - - - + + - - + + - - + + - - + + + + + + + - - - - - - - + + + + + + + + + - + + + + + + - -
-
Lives: 3
-
Score: 0
-
High Score: 0
-
Level: 1
- -
- + +
+
Lives: 3
+
Score: 0
+
High Score: 0
+
Level: 1
+ +
+
- - - + + + -
-
- -
-
-
+
+
+ +
+
+
- - - - - - - + + +
\ No newline at end of file diff --git a/src/main/resources/templates/fragments/errorBanner.html b/src/main/resources/templates/fragments/errorBanner.html index 1bc79031..d9865b63 100644 --- a/src/main/resources/templates/fragments/errorBanner.html +++ b/src/main/resources/templates/fragments/errorBanner.html @@ -1,23 +1,5 @@ -
+ diff --git a/src/main/resources/templates/merge-pdfs.html b/src/main/resources/templates/merge-pdfs.html index d97d88d9..3638391e 100644 --- a/src/main/resources/templates/merge-pdfs.html +++ b/src/main/resources/templates/merge-pdfs.html @@ -1,40 +1,39 @@ - + + + + + - - - - +
-
-
-

-
-
-
-

-
-
- -
- -
-
-
    -
    -
    - - - -
    -
    - - -
    +
    + +

    +
    +
    +
    +

    +
    +
    + +
    +
    +
      +
      +
      + + + +
      +
      +
      +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/misc/add-image.html b/src/main/resources/templates/misc/add-image.html index ae531a8f..1a0f96ee 100644 --- a/src/main/resources/templates/misc/add-image.html +++ b/src/main/resources/templates/misc/add-image.html @@ -1,141 +1,112 @@ - - - + + + + - - +
      -
      -
      -

      -
      -
      -
      -

      +
      + +

      +
      +
      +
      +

      - -
      - + document.querySelectorAll(".show-on-file-selected").forEach(el => { + el.style.cssText = ''; + }); + } + }); + document.addEventListener("DOMContentLoaded", () => { + document.querySelectorAll(".show-on-file-selected").forEach(el => { + el.style.cssText = "display:none !important"; + }) + }); + -
      -
      -
      - -
      -
      - - -
      - - -
      - - - -
      - -
      - - -
      - -
      - -
      +
      +
      +
      +
      +
      + + +
      + + +
      + + + +
      +
      + + +
      + +
      + +
      +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/misc/add-page-numbers.html b/src/main/resources/templates/misc/add-page-numbers.html index e484a72d..bd7104c2 100644 --- a/src/main/resources/templates/misc/add-page-numbers.html +++ b/src/main/resources/templates/misc/add-page-numbers.html @@ -1,154 +1,137 @@ - + + + + + -#myForm { - display: flex; - justify-content: center; - align-items: center; - margin-top: 20px; -} + + +
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      +
      + + +
      +
      + +
      +
      1
      +
      2
      +
      3
      +
      4
      +
      5
      +
      6
      +
      7
      +
      8
      +
      9
      +
      +
      + +
      + + +
      +
      + + +
      +
      + + +
      + +
      +
      +
      +
      + - -
      -
      -
      - + cell.addEventListener('mouseleave', function(e) { + if(e.target.classList.contains('selectedPosition')) { + e.target.classList.remove('selectedHovered'); + } + }); + }); + +
      + +
      + diff --git a/src/main/resources/templates/misc/adjust-contrast.html b/src/main/resources/templates/misc/adjust-contrast.html index 23effdd0..2b28a734 100644 --- a/src/main/resources/templates/misc/adjust-contrast.html +++ b/src/main/resources/templates/misc/adjust-contrast.html @@ -1,20 +1,17 @@ - - - - + + + + -
      -
      -
      -

      -
      -
      -
      +
      +
      + +

      +
      +
      +
      - - + -
      -
      -
      -
      -
      -
      + document.getElementById('download-button').addEventListener('click', function() { + downloadPDF(); + }); + +
      +
      +
      +
      + +
      diff --git a/src/main/resources/templates/misc/auto-crop.html b/src/main/resources/templates/misc/auto-crop.html index da6e6c22..d3f79ade 100644 --- a/src/main/resources/templates/misc/auto-crop.html +++ b/src/main/resources/templates/misc/auto-crop.html @@ -1,31 +1,30 @@ - + + + + - - - - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      -
      - -
      -

      -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      + +
      +

      - +
      -
      +
      +
      - + \ No newline at end of file diff --git a/src/main/resources/templates/misc/auto-rename.html b/src/main/resources/templates/misc/auto-rename.html index 0295acac..62712dce 100644 --- a/src/main/resources/templates/misc/auto-rename.html +++ b/src/main/resources/templates/misc/auto-rename.html @@ -1,30 +1,29 @@ - + + + + - - - - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      -
      - -
      -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      + +
      - +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/misc/change-metadata.html b/src/main/resources/templates/misc/change-metadata.html index 6affa6bf..e2c8de1c 100644 --- a/src/main/resources/templates/misc/change-metadata.html +++ b/src/main/resources/templates/misc/change-metadata.html @@ -1,261 +1,227 @@ - + + + + - - - +
      -
      -
      -

      -
      -
      -
      -

      - -
      -
      -

      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - -
      -
      - - -
      - -
      +
      + +

      +
      +
      +
      +

      +
      +
      +

      +
      + +
      +
      + + +
      +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      +
      + + +
      +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/misc/compare.html b/src/main/resources/templates/misc/compare.html index ffe08a31..c9194005 100644 --- a/src/main/resources/templates/misc/compare.html +++ b/src/main/resources/templates/misc/compare.html @@ -1,190 +1,187 @@ - + + + + + - - - - - +
      -
      -
      -

      -
      -
      -
      -

      - -
      -
      - - - -
      -
      -

      -
      -
      -
      -

      -
      -
      -
      - - -
      +
      + +

      +
      +
      +
      +

      +
      +
      + +
      +
      +

      +
      +
      +

      +
      +
      +
      +
      +
      -
      +
      +
      + + diff --git a/src/main/resources/templates/misc/compress-pdf.html b/src/main/resources/templates/misc/compress-pdf.html index c991a6c8..ef495577 100644 --- a/src/main/resources/templates/misc/compress-pdf.html +++ b/src/main/resources/templates/misc/compress-pdf.html @@ -1,50 +1,48 @@ - + + + + - - - - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      -
      -
      -

      - - -
      -
      - -
      -
      -

      - - -
      -
      - -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      +
      +

      + + +
      +
      +
      +

      + + +
      +
      + +
      +
      -
      +
      +
      - - + \ No newline at end of file diff --git a/src/main/resources/templates/misc/extract-image-scans.html b/src/main/resources/templates/misc/extract-image-scans.html index 82f7313c..016cc973 100644 --- a/src/main/resources/templates/misc/extract-image-scans.html +++ b/src/main/resources/templates/misc/extract-image-scans.html @@ -1,54 +1,53 @@ - + + + + - - - - -
      -
      -
      -

      -
      -
      -
      -

      - -
      -
      -
      - - - -
      -
      - - - -
      -
      - - - -
      -
      - - - -
      -
      - - - -
      - -
      + +
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      + + + +
      +
      + + + +
      +
      + + + +
      +
      + + + +
      +
      + + + +
      + +
      +
      +
      -
      -
      - + \ No newline at end of file diff --git a/src/main/resources/templates/misc/extract-images.html b/src/main/resources/templates/misc/extract-images.html index e813e680..caf4b549 100644 --- a/src/main/resources/templates/misc/extract-images.html +++ b/src/main/resources/templates/misc/extract-images.html @@ -1,36 +1,35 @@ - + + + + - - - - -
      -
      -
      -

      -
      -
      -
      -

      - -
      -
      -
      - - - + +
      + +
      - -
      +
      -
      -
      - + \ No newline at end of file diff --git a/src/main/resources/templates/misc/flatten.html b/src/main/resources/templates/misc/flatten.html index 430e343b..94c616cc 100644 --- a/src/main/resources/templates/misc/flatten.html +++ b/src/main/resources/templates/misc/flatten.html @@ -1,57 +1,55 @@ - + + + + - - - - - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      -
      -
      - - - - -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      + + + +
      +
      -
      +
      +
      - + \ No newline at end of file diff --git a/src/main/resources/templates/misc/ocr-pdf.html b/src/main/resources/templates/misc/ocr-pdf.html index 9aabdec4..4d9b0046 100644 --- a/src/main/resources/templates/misc/ocr-pdf.html +++ b/src/main/resources/templates/misc/ocr-pdf.html @@ -1,254 +1,249 @@ - - - - - + + + - + - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      -
      - -
      -
      -
      - - -
      -
      -
      -
      -
      - - -
      -
      - -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      - - -
      - - -
      -
      - -
      - -

      -

      - https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToUseOCR.md +
      + +

      +
      +
      +
      +

      +
      +
      +
      + +
      +
      +
      + +
      +
      +
      +
      + + +
      +
      + +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + +
      + +

      +

      + https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToUseOCR.md
      +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/misc/remove-annotations.html b/src/main/resources/templates/misc/remove-annotations.html index cbd46be4..40623fac 100644 --- a/src/main/resources/templates/misc/remove-annotations.html +++ b/src/main/resources/templates/misc/remove-annotations.html @@ -1,64 +1,65 @@ - - + + + + - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      -
      -
      - -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      + +
      +
      -
      +
      +
      - - - + + \ No newline at end of file diff --git a/src/main/resources/templates/misc/remove-blanks.html b/src/main/resources/templates/misc/remove-blanks.html index b2c8e358..99ce01db 100644 --- a/src/main/resources/templates/misc/remove-blanks.html +++ b/src/main/resources/templates/misc/remove-blanks.html @@ -1,39 +1,38 @@ - + + + + - - - - -
      -
      -
      -

      -
      -
      -
      -

      - -
      -
      -
      - - - -
      -
      - - - -
      - -
      + +
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      + + + +
      +
      + + + +
      + +
      +
      +
      -
      -
      - + diff --git a/src/main/resources/templates/misc/repair.html b/src/main/resources/templates/misc/repair.html index 10d5d148..2b7e4d5a 100644 --- a/src/main/resources/templates/misc/repair.html +++ b/src/main/resources/templates/misc/repair.html @@ -1,29 +1,27 @@ - + + + + - - - - - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      - -
      -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      + +
      +
      -
      +
      +
      - - + \ No newline at end of file diff --git a/src/main/resources/templates/misc/show-javascript.html b/src/main/resources/templates/misc/show-javascript.html index 0614a2c2..0311fe0e 100644 --- a/src/main/resources/templates/misc/show-javascript.html +++ b/src/main/resources/templates/misc/show-javascript.html @@ -1,100 +1,93 @@ - - - - - -
      -
      -
      -

      -
      -
      -
      -

      -
      -
      -
      - + + + + + + + -
      -
      - -
      - -
      + +
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      + +
      +
      + +
      + +
      - - -
      - - -
      -
      -
      - -
      -
      -
      - + // Set the URL as the href of the download button and provide a download name + let downloadButton = document.querySelector('#downloadJS'); + downloadButton.href = url; + downloadButton.download = 'extracted.js'; + downloadButton.style.display = 'block'; + }) + .catch(error => { + console.error('Error:', error); + }); + }); + +
      +
      +
      +
      + +
      + \ No newline at end of file diff --git a/src/main/resources/templates/misc/stamp.html b/src/main/resources/templates/misc/stamp.html index 1578de36..5fa2125a 100644 --- a/src/main/resources/templates/misc/stamp.html +++ b/src/main/resources/templates/misc/stamp.html @@ -1,222 +1,167 @@ - + + + + - + + +
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      +
      + + +
      + +
      + + +
      + +
      + +
      +
      1
      +
      2
      +
      3
      +
      4
      +
      5
      +
      6
      +
      7
      +
      8
      +
      9
      +
      +
      + + + +
      + + +
      + +
      + + +
      + + + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      - - -
      -
      -
      -

      -
      -
      -
      -

      - -
      -
      +
      + + +
      -
      - - -
      +
      + + +
      -
      - - -
      - - - -
      - -
      -
      1
      -
      2
      -
      3
      -
      4
      -
      5
      -
      6
      -
      7
      -
      8
      -
      9
      -
      -
      - - - - - -
      - - + + +
      +
      + -
      -
      -
      - + if (stampType === 'text') { + stampTextGroup.style.display = 'block'; + stampImageGroup.style.display = 'none'; + alphabetGroup.style.display = 'block'; + } else if (stampType === 'image') { + stampTextGroup.style.display = 'none'; + stampImageGroup.style.display = 'block'; + alphabetGroup.style.display = 'none'; + } + } + +
      + +
      + diff --git a/src/main/resources/templates/multi-page-layout.html b/src/main/resources/templates/multi-page-layout.html index 646f7dc0..5f77806b 100644 --- a/src/main/resources/templates/multi-page-layout.html +++ b/src/main/resources/templates/multi-page-layout.html @@ -1,43 +1,41 @@ - + + + + - - - - - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      -
      - - -
      -
      - - -
      - -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      + +
      +
      + + +
      + +
      +
      -
      +
      +
      - - + \ No newline at end of file diff --git a/src/main/resources/templates/multi-tool.html b/src/main/resources/templates/multi-tool.html index d49b7f83..ef618e0c 100644 --- a/src/main/resources/templates/multi-tool.html +++ b/src/main/resources/templates/multi-tool.html @@ -1,233 +1,104 @@ - + + + + - - - +
      -
      -
      -

      -
      -
      -

      -
      -
      -
      -
      - -
      - PDF Page -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - - -
      -
      -
      - - - - - - - - - - -
      -
      +
      + +

      +
      +
      +

      +
      +
      +
      +
      + +
      + PDF Page
      +
      +
      -
      +
      +
      +
      +
      +
      + + +
      +
      +
      + + + + +
      +
      +
      +
      +
      +
      - - - - + diff --git a/src/main/resources/templates/overlay-pdf.html b/src/main/resources/templates/overlay-pdf.html index cab73486..7e17c913 100644 --- a/src/main/resources/templates/overlay-pdf.html +++ b/src/main/resources/templates/overlay-pdf.html @@ -1,102 +1,96 @@ - + + + + - - - - +
      -
      -
      -

      -
      -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      - -

      - -
      -
      - - - -
      - - -
      - - - -
      - - - - - -
      + + +
      + + +
      + -
      + + + +
      +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/pdf-organizer.html b/src/main/resources/templates/pdf-organizer.html index 4c033e35..5f2ff037 100644 --- a/src/main/resources/templates/pdf-organizer.html +++ b/src/main/resources/templates/pdf-organizer.html @@ -1,57 +1,56 @@ - + + + + - - - - +
      -
      -
      -

      -
      -
      -
      -

      +
      + +

      +
      +
      +
      +

      -
      -
      -
      - - -
      -
      - - -
      - - -
      - -
      +
      +
      +
      + +
      +
      + + +
      + +
      +
      +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/pdf-to-single-page.html b/src/main/resources/templates/pdf-to-single-page.html index 6c26ace5..c3c56e4c 100644 --- a/src/main/resources/templates/pdf-to-single-page.html +++ b/src/main/resources/templates/pdf-to-single-page.html @@ -1,28 +1,27 @@ - + + + + - - - - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      - -
      -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      + +
      - +
      -
      +
      +
      - + \ No newline at end of file diff --git a/src/main/resources/templates/pipeline.html b/src/main/resources/templates/pipeline.html index d70c52ff..0489f1a4 100644 --- a/src/main/resources/templates/pipeline.html +++ b/src/main/resources/templates/pipeline.html @@ -1,254 +1,163 @@ - - - - - - + - -
      -
      -
      + +
      +
      + +

      +
      +
      +

      +

      +
      +
      + + +
      -

      -
      -
      +
      +
      + +
      +
      +
      +
      +
      + +
      +
      +
      -

      -

      -
      -
      - - +

      Below info is Alpha only, will be removed and hence not translated

      -
      +

      Current Limitations

      -
      -
      - -
      -
      -
      -
      -
      - +

      User Guide for Local Directory Scanning and File Processing

      -
      -
      -
      +

      Setting Up Watched Folders:

      +

      Create a folder where you want your files to be monitored. This is your 'watched folder'.

      +

      The default directory for this is ./pipeline/watchedFolders/

      +

      Place any directories you want to be scanned into this folder, this folder should contain multiple folders each for their own tasks and pipelines.

      +

      Configuring Processing with JSON Files:

      +

      In each directory you want processed (e.g. ./pipeline/watchedFolders/officePrinter), include a JSON configuration file.

      +

      This JSON file should specify how you want the files in the directory to be handled (e.g., what operations to perform on them) which can be made, configured and downloaded from Stirling-PDF Pipeline interface.

      -

      Below info is Alpha only, will be removed and hence not translated

      -

      Current Limitations

      -
        -
      • Cannot have more than one of the same operation
      • -
      • Cannot input additional files via UI
      • -
      • All files and operations run in serial mode
      • -
      +

      Automatic Scanning and Processing:

      +

      The system automatically checks the watched folder every minute for new directories and files to process.

      +

      When a directory with a valid JSON configuration file is found, it begins processing the files inside as per the configuration.

      -

      How it Works Notes

      -
        -
      • Configure the pipeline config file and input files to run - files against it
      • -
      • For reuse, download the config file and re-upload it when - needed, or place it in /pipeline/defaultWebUIConfigs/ to - auto-load in the web UI for all users
      • -
      +

      Processing Steps:

      +

      Files in each directory are processed according to the instructions in the JSON file.

      +

      This might involve file conversions, data filtering, renaming files, etc. If the output of a step is a zip, this zip will be automatically unzipped as it passes to next process.

      -

      How to use pre-load configs in web UI

      -
        -
      • Download config files
      • -
      • For reuse, download the config file and re-upload it when - needed, or place it in /pipeline/defaultWebUIConfigs/ to - auto-load in the web UI for all users
      • -
      +

      Results and Output:

      +

      After processing, the results are saved in a specified output location. This could be a different folder or location as defined in the JSON file or the default location ./pipeline/finishedFolders/.

      +

      Each processed file is named and organized according to the rules set in the JSON configuration.

      -

      Todo

      -
        -
      • Save to browser/Account
      • -
      • offline folder scan mode checks and testing for unique usecases
      • -
      • Improve operation config settings UI
      • -
      +

      Completion and Cleanup:

      +

      Once processing is complete, the original files in the watched folder's directory are removed.

      +

      You can find the processed files in the designated output location.

      +

      Error Handling:

      +

      If there's an error during processing, the system will not delete the original files, allowing you to check and retry if necessary.

      -

      User Guide for Local Directory Scanning and File - Processing

      +

      User Interaction:

      +

      As a user, your main tasks are to set up the watched folders, place directories with files for processing, and create the corresponding JSON configuration files.

      +

      The system handles the rest, including scanning, processing, and outputting results.

      -

      Setting Up Watched Folders:

      -

      Create a folder where you want your files to be monitored. - This is your 'watched folder'.

      -

      - The default directory for this is - ./pipeline/watchedFolders/ -

      -

      Place any directories you want to be scanned into this - folder, this folder should contain multiple folders each for their - own tasks and pipelines.

      + + - - +
      + +
      +
      +
      +
      +
      + +
      +
      +
      + +
      + diff --git a/src/main/resources/templates/remove-pages.html b/src/main/resources/templates/remove-pages.html index 1449fc2e..e540e7dc 100644 --- a/src/main/resources/templates/remove-pages.html +++ b/src/main/resources/templates/remove-pages.html @@ -1,38 +1,37 @@ - + + + + - + +
      +
      + +

      +
      +
      +
      +

      - - - -
      -
      -
      -

      -
      -
      -
      -

      - -
      -
      -
      - - -
      - -
      +
      +
      +
      + + +
      + +
      +
      +
      -
      -
      - - + + \ No newline at end of file diff --git a/src/main/resources/templates/rotate-pdf.html b/src/main/resources/templates/rotate-pdf.html index 72cb280d..920ed4ab 100644 --- a/src/main/resources/templates/rotate-pdf.html +++ b/src/main/resources/templates/rotate-pdf.html @@ -1,132 +1,98 @@ - + + + + - - - - - +
      -
      -
      -

      -
      -
      -
      -

      +
      + +

      +
      +
      +
      +

      -
      -
      - + +
      + - -
      + +
      +
      -
      +
      +
      - - + preview.style.rotate = newAngle + "deg"; + angleInput.value = newAngle; + } + diff --git a/src/main/resources/templates/scale-pages.html b/src/main/resources/templates/scale-pages.html index 1165f862..22b52ba6 100644 --- a/src/main/resources/templates/scale-pages.html +++ b/src/main/resources/templates/scale-pages.html @@ -1,47 +1,45 @@ - + + + + - - - - - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      -
      - - -
      -
      - - -
      - -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      + +
      +
      + + +
      + +
      +
      -
      +
      +
      - - + \ No newline at end of file diff --git a/src/main/resources/templates/security/add-password.html b/src/main/resources/templates/security/add-password.html index 5c09720f..b495bcb2 100644 --- a/src/main/resources/templates/security/add-password.html +++ b/src/main/resources/templates/security/add-password.html @@ -1,86 +1,85 @@ - + + + + - - - +
      -
      -
      -

      -
      -
      -
      -

      - -
      -
      - -
      -
      -
      - - -
      -
      - - -
      - -
      - -
      -
      - -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      - -
      -
      -
      - -
      - -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      + +
      +
      + + +
      +
      + + +
      + +
      + + +
      +
      + +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      +
      +
      + +
      +
      +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/security/add-watermark.html b/src/main/resources/templates/security/add-watermark.html index f61dcabf..297c9ba1 100644 --- a/src/main/resources/templates/security/add-watermark.html +++ b/src/main/resources/templates/security/add-watermark.html @@ -1,144 +1,142 @@ - + + + + - - - +
      -
      -
      -

      -
      -
      -
      -

      - -
      -
      - -
      - -
      -
      - -
      - - -
      -
      - - -
      -
      - - -
      - - - -
      - - -
      -
      - - - -
      - - - - -
      - - -
      -
      - - -
      -
      - - -
      -
      - -
      -
      - - +
      + +

      +
      +
      +
      +

      +
      +
      + +
      + +
      -
      + +
      + + +
      +
      + + +
      +
      + + +
      + + + +
      + + +
      +
      + + + +
      + + +
      + + +
      +
      + + +
      +
      + + +
      +
      + +
      + + +
      +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/security/auto-redact.html b/src/main/resources/templates/security/auto-redact.html index 791b5da0..bec2e316 100644 --- a/src/main/resources/templates/security/auto-redact.html +++ b/src/main/resources/templates/security/auto-redact.html @@ -1,84 +1,83 @@ - + + + + - - -
      -
      -
      -

      -
      -
      -
      -

      -
      -
      - -
      + +
      +
      + +

      +
      +
      +
      +

      + +
      + +
      -
      - - -
      +
      + + +
      -
      - - -
      +
      + + +
      - - + + - + +
      + + +
      +
      + + +
      +
      + + +
      -
      - - -
      +
      + + +
      -
      - - -
      - -
      - - -
      - -
      - - -
      - - - + + +
      +
      -
      -
      - + diff --git a/src/main/resources/templates/security/cert-sign.html b/src/main/resources/templates/security/cert-sign.html index 20148355..bfadb5a7 100644 --- a/src/main/resources/templates/security/cert-sign.html +++ b/src/main/resources/templates/security/cert-sign.html @@ -1,113 +1,106 @@ - - + + + + - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      - -
      -
      - -
      - -
      -
      - -
      - - - -
      - -
      -
      - -
      - -
      - -
      -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      + +
      + +
      + +
      +
      + +
      + + + +
      + +
      +
      + +
      + +
      + +
      +
      +
      -
      +
      +
      - - - + + \ No newline at end of file diff --git a/src/main/resources/templates/security/change-permissions.html b/src/main/resources/templates/security/change-permissions.html index cf0cd3b0..9c76bafa 100644 --- a/src/main/resources/templates/security/change-permissions.html +++ b/src/main/resources/templates/security/change-permissions.html @@ -1,71 +1,69 @@ - + + + + - - - - +
      -
      -
      -

      -
      -
      -
      -

      -

      -
      -
      - -
      -
      -
      - -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      - -
      -
      -
      - -
      - -
      -
      +
      + +

      +
      +
      +
      +

      +

      +
      +
      + +
      +
      + +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      +
      +
      + +
      +
      +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/security/get-info-on-pdf.html b/src/main/resources/templates/security/get-info-on-pdf.html index 317c4e5e..00b425d4 100644 --- a/src/main/resources/templates/security/get-info-on-pdf.html +++ b/src/main/resources/templates/security/get-info-on-pdf.html @@ -1,165 +1,152 @@ - - - -
      -
      -
      -

      -
      -
      -
      -

      -
      -
      -
      - + + + + -
      -
      - -
      - -
      + +
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      + +
      +
      + +
      + +
      - - -
      - -
      -
      -
      - -
      -
      -
      - + card.appendChild(content); + return card; + } + function createButtonElement(key, safeKey, depth) { + const buttonElem = document.createElement('button'); + buttonElem.className = 'btn btn-link'; + buttonElem.type = 'button'; + buttonElem.dataset.bsToggle = "collapse"; + buttonElem.dataset.bsTarget = `#${safeKey}-content-${depth}`; + buttonElem.setAttribute('aria-expanded', 'true'); + buttonElem.setAttribute('aria-controls', `${safeKey}-content-${depth}`); + buttonElem.textContent = key; + return buttonElem; + } + const collapsibleElems = document.querySelectorAll('[data-bs-toggle="collapse"]'); + collapsibleElems.forEach(elem => { + new bootstrap.Collapse(elem); + }); + +
      +
      +
      +
      + +
      + \ No newline at end of file diff --git a/src/main/resources/templates/security/remove-password.html b/src/main/resources/templates/security/remove-password.html index fe0c4a3c..950d6b1f 100644 --- a/src/main/resources/templates/security/remove-password.html +++ b/src/main/resources/templates/security/remove-password.html @@ -1,37 +1,37 @@ - + + + + - - - +
      -
      -
      -

      -
      -
      -
      -

      - -
      -
      - -
      -
      -
      - - -
      -
      -
      - -
      -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      + +
      +
      + + +
      +
      +
      + +
      +
      +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/security/remove-watermark.html b/src/main/resources/templates/security/remove-watermark.html index a87a1bd7..64b2fa7e 100644 --- a/src/main/resources/templates/security/remove-watermark.html +++ b/src/main/resources/templates/security/remove-watermark.html @@ -1,36 +1,36 @@ - + + + + - - - +
      -
      -
      -

      -
      -
      -
      -

      - -
      -
      - -
      -
      -
      - - -
      -
      - -
      -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      + +
      +
      + + +
      +
      + +
      +
      +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/security/sanitize-pdf.html b/src/main/resources/templates/security/sanitize-pdf.html index 8d393cba..3d0f4deb 100644 --- a/src/main/resources/templates/security/sanitize-pdf.html +++ b/src/main/resources/templates/security/sanitize-pdf.html @@ -1,53 +1,52 @@ - + + + + - - - +
      -
      -
      -

      -
      -
      -
      -

      - -
      -
      -
      -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      -
      - -
      - -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      +
      + +
      +
      +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/sign.html b/src/main/resources/templates/sign.html index 48d39e41..57a2d31d 100644 --- a/src/main/resources/templates/sign.html +++ b/src/main/resources/templates/sign.html @@ -1,333 +1,276 @@ + + + + + + + - - - - - - - - - +
      -
      -
      -

      -
      -
      -
      -

      +
      + +

      +
      +
      +
      +

      - -
      - + document.querySelectorAll(".show-on-file-selected").forEach(el => { + el.style.cssText = ''; + }) + } + }); + document.addEventListener("DOMContentLoaded", () => { + document.querySelectorAll(".show-on-file-selected").forEach(el => { + el.style.cssText = "display:none !important"; + }) + }); + +
      +
      +
      + +
      +
      + +
      + + + -
      -
      - -
      - - - - -
      -
      - - - - -
      - -
      - - - - - - - - - -
      -
      - - -
      - - -
      - - - -
      - -
      - - -
      - -
      - - + // This library does not listen for canvas changes, so after the canvas is automatically + // cleared by the browser, SignaturePad#isEmpty might still return false, even though the + // canvas looks empty, because the internal data of this library wasn't cleared. To make sure + // that the state of this library is consistent with visual state of the canvas, you + // have to clear it manually. + signaturePad.clear(); + } + new IntersectionObserver((entries, observer) => { + if (entries.some(entry => entry.intersectionRatio > 0)) { + resizeCanvas(); + } + }).observe(signaturePadCanvas); + new ResizeObserver(resizeCanvas).observe(signaturePadCanvas); + +
      +
      + + + + +
      +
      + +
      +
      + + +
      + + +
      + + + +
      +
      + + +
      + +
      + +
      +
      -
      +
      +
      - + \ No newline at end of file diff --git a/src/main/resources/templates/split-by-size-or-count.html b/src/main/resources/templates/split-by-size-or-count.html index 0b6f9b52..f5b58ef9 100644 --- a/src/main/resources/templates/split-by-size-or-count.html +++ b/src/main/resources/templates/split-by-size-or-count.html @@ -1,43 +1,38 @@ - + + + + - - - - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      - - - -
      - - - -
      - - -
      - -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      + + +
      + + +
      + +
      - +
      -
      +
      +
      - + diff --git a/src/main/resources/templates/split-pdf-by-sections.html b/src/main/resources/templates/split-pdf-by-sections.html index 94900977..dc8b5476 100644 --- a/src/main/resources/templates/split-pdf-by-sections.html +++ b/src/main/resources/templates/split-pdf-by-sections.html @@ -1,95 +1,79 @@ - + + + + + - - - +
      -
      -
      -

      -
      -
      -
      -

      -
      -
      +
      + +

      +
      +
      +
      +

      + +
      + + +
      + + +
      +
      + -
      - - - -
      -
      + // Initial draw + updateVisualAid(); + +
      + + +
      - +
      -
      +
      +
      - + \ No newline at end of file diff --git a/src/main/resources/templates/split-pdfs.html b/src/main/resources/templates/split-pdfs.html index 872dc323..c6beffac 100644 --- a/src/main/resources/templates/split-pdfs.html +++ b/src/main/resources/templates/split-pdfs.html @@ -1,43 +1,42 @@ - - - - - - + + + + +
      -
      -
      -

      -
      -
      -
      -

      -

      -

      -

      -

      -

      -

      -

      -

      +
      + +

      +
      +
      +
      +

      +

      +

      +

      +

      +

      +

      +

      +

      -
      -
      + +
      -
      - - -
      -
      - -
      -
      +
      + +
      +
      + +
      +
      -
      +
      +
      - + From 094fde98019123766ee380a2ba5f92bd79e312d3 Mon Sep 17 00:00:00 2001 From: Sherif Metwally Date: Sat, 17 Feb 2024 00:23:11 +0200 Subject: [PATCH 004/200] Update-helm-chart (#815) * upgrade app in helm chart to 0.20.2 * update and correct UI env variable names in chart values.yaml --- chart/stirling-pdf/Chart.yaml | 2 +- chart/stirling-pdf/values.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/chart/stirling-pdf/Chart.yaml b/chart/stirling-pdf/Chart.yaml index 686d2422..94bc50fc 100644 --- a/chart/stirling-pdf/Chart.yaml +++ b/chart/stirling-pdf/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -appVersion: 0.14.2 +appVersion: 0.20.2 description: locally hosted web application that allows you to perform various operations on PDF files home: https://github.com/Stirling-Tools/Stirling-PDF keywords: diff --git a/chart/stirling-pdf/values.yaml b/chart/stirling-pdf/values.yaml index 3c4ca888..e9e00c3e 100644 --- a/chart/stirling-pdf/values.yaml +++ b/chart/stirling-pdf/values.yaml @@ -16,11 +16,11 @@ commonLabels: {} # team_name: dev envs: [] -# - name: PP_HOME_NAME +# - name: UI_APP_NAME # value: "Stirling PDF" -# - name: APP_HOME_DESCRIPTION +# - name: UI_HOME_DESCRIPTION # value: "Your locally hosted one-stop-shop for all your PDF needs." -# - name: APP_NAVBAR_NAME +# - name: UI_APP_NAVBAR_NAME # value: "Stirling PDF" # - name: ALLOW_GOOGLE_VISIBILITY # value: "true" From 6fc9c7be90a7ab3736dc85bf73cea7403e48b697 Mon Sep 17 00:00:00 2001 From: Aliarev Date: Fri, 16 Feb 2024 23:24:26 +0100 Subject: [PATCH 005/200] Update french translation (#814) --- src/main/resources/messages_fr_FR.properties | 168 +++++++++---------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/src/main/resources/messages_fr_FR.properties b/src/main/resources/messages_fr_FR.properties index 7bda2156..e40d9291 100644 --- a/src/main/resources/messages_fr_FR.properties +++ b/src/main/resources/messages_fr_FR.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -11,7 +11,7 @@ imgPrompt=Choisir une image genericSubmit=Envoyer processTimeWarning=Attention, ce processus peut prendre jusqu\u2019à une minute en fonction de la taille du fichier. pageOrderPrompt=Ordre des pages (entrez une liste de numéros de page séparés par des virgules ou des fonctions telles que 2n+1)\u00a0: -pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) : +pageSelectionPrompt=Sélection des pages (entrez une liste de numéros de page séparés par des virgules ou des fonctions telles que 2n+1)\u00a0: goToPage=Aller true=Vrai false=Faux @@ -43,10 +43,10 @@ red=Rouge green=Vert blue=Bleu custom=Personnalisé\u2026 -WorkInProgess=Work in progress, May not work or be buggy, Please report any problems! -poweredBy=Powered by -yes=Yes -no=No +WorkInProgess=En cours de développement, merci de nous remonter les problèmes que vous pourriez constater! +poweredBy=Propulsé par +yes=Oui +no=Non changedCredsMessage=Les identifiants ont été mis à jour\u00a0! notAuthenticatedMessage=Utilisateur non authentifié. userNotFoundMessage=Utilisateur non trouvé. @@ -57,24 +57,24 @@ usernameExistsMessage=Le nouveau nom d\u2019utilisateur existe déjà. ############### # Pipeline # ############### -pipeline.header=Pipeline Menu (Alpha) -pipeline.uploadButton=Upload Custom -pipeline.configureButton=Configure -pipeline.defaultOption=Custom -pipeline.submitButton=Submit +pipeline.header=Menu Pipeline (Alpha) +pipeline.uploadButton=Télécharger une personnalisation +pipeline.configureButton=Configurer +pipeline.defaultOption=Personnaliser +pipeline.submitButton=Soumettre ###################### # Pipeline Options # ###################### -pipelineOptions.header=Pipeline Configuration -pipelineOptions.pipelineNameLabel=Pipeline Name -pipelineOptions.saveSettings=Save Operation Settings -pipelineOptions.pipelineNamePrompt=Enter pipeline name here -pipelineOptions.selectOperation=Select Operation -pipelineOptions.addOperationButton=Add operation +pipelineOptions.header=Configuration du pipeline +pipelineOptions.pipelineNameLabel=Nom du pipeline +pipelineOptions.saveSettings=Sauvegarder la configuration +pipelineOptions.pipelineNamePrompt=Entrez ici le nom du pipeline +pipelineOptions.selectOperation=Sélectionner une opération +pipelineOptions.addOperationButton=Ajouter une opération pipelineOptions.pipelineHeader=Pipeline: -pipelineOptions.saveButton=Download -pipelineOptions.validateButton=Validate +pipelineOptions.saveButton=Télécharger +pipelineOptions.validateButton=Valider @@ -147,7 +147,7 @@ adminUserSettings.role=Rôle adminUserSettings.actions=Actions adminUserSettings.apiUser=Utilisateur API limité adminUserSettings.webOnlyUser=Utilisateur Web uniquement -adminUserSettings.demoUser=Demo User (No custom settings) +adminUserSettings.demoUser=Demo User (Paramètres par défaut) adminUserSettings.forceChange=Forcer l\u2019utilisateur à changer son nom d\u2019utilisateur/mot de passe lors de la connexion adminUserSettings.submit=Ajouter @@ -159,7 +159,7 @@ home.searchBar=Rechercher des fonctionnalités... home.viewPdf.title=Visionner le PDF -home.viewPdf.desc=Visionner, annoter, ajouter du texte ou des images +home.viewPdf.desc=Visionner, annoter, ajouter du texte ou des images. viewPdf.tags=visualiser,lire,annoter,texte,image home.multiTool.title=Outil multifonction PDF @@ -168,7 +168,7 @@ multiTool.tags=outil multifonction,opération multifonction,interface utilisateu home.merge.title=Fusionner home.merge.desc=Fusionnez facilement plusieurs PDF en un seul. -merge.tags=fusionner,opérations sur les pages,backeend,server side,merge +merge.tags=fusionner,opérations sur les pages,backend,server side,merge home.split.title=Diviser home.split.desc=Divisez un PDF en plusieurs documents. @@ -284,9 +284,9 @@ home.removeBlanks.title=Supprimer les pages vierges home.removeBlanks.desc=Détectez et supprimez les pages vierges d\u2019un PDF. removeBlanks.tags=pages vierges,supprimer,nettoyer,cleanup,streamline,non-content,organize -home.removeAnnotations.title=Remove Annotations -home.removeAnnotations.desc=Removes all comments/annotations from a PDF -removeAnnotations.tags=comments,highlight,notes,markup,remove +home.removeAnnotations.title=Supprimer les annotations +home.removeAnnotations.desc=Supprimer tous les commentaires/annotations d\u2019un PDF. +removeAnnotations.tags=commentaires,supprimer,annotations,highlight,notes,markup,remove home.compare.title=Comparer home.compare.desc=Comparez et visualisez les différences entre deux PDF. @@ -370,7 +370,7 @@ home.autoRedact.desc=Caviardez automatiquement les informations sensibles d\u201 autoRedact.tags=caviarder,redact,auto home.tableExtraxt.title=PDF en CSV -home.tableExtraxt.desc=Extrait les tableaux d\u2019un PDF et les transforme en CSV +home.tableExtraxt.desc=Extrait les tableaux d\u2019un PDF et les transforme en CSV. tableExtraxt.tags=CSV,Table Extraction,extract,convert @@ -380,16 +380,16 @@ autoSizeSplitPDF.tags=pdf,split,document,organization home.overlay-pdfs.title=Incrustation de PDF -home.overlay-pdfs.desc=Incrustation d\u2019un PDF sur un autre PDF -overlay-pdfs.tags=Overlay +home.overlay-pdfs.desc=Incrustation d\u2019un PDF sur un autre PDF. +overlay-pdfs.tags=Overlay,incrustation -home.split-by-sections.title=Split PDF by Sections -home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections -split-by-sections.tags=Section Split, Divide, Customize +home.split-by-sections.title=Séparer un PDF en sections +home.split-by-sections.desc=Diviser chaque page d\u2019un PDF en sections horizontales/verticales plus petites. +split-by-sections.tags=Sections,Diviser,Section Split, Divide, Customize -home.AddStampRequest.title=Add Stamp to PDF -home.AddStampRequest.desc=Add text or add image stamps at set locations -AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize +home.AddStampRequest.title=Ajouter un tampon sur un PDF +home.AddStampRequest.desc=Ajouter un texte ou l\u2019image d\u2019un tampon à un emplacement défini. +AddStampRequest.tags=Tampon,Ajouter,Stamp,Add image,center image,Watermark,PDF,Embed,Customize ########################### @@ -467,37 +467,37 @@ HTMLToPDF.header=HTML en PDF HTMLToPDF.help=Accepte les fichiers HTML et les ZIP contenant du HTML, du CSS, des images, etc. (requis). HTMLToPDF.submit=Convertir HTMLToPDF.credit=Utilise WeasyPrint. -HTMLToPDF.zoom=Zoom level for displaying the website. -HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default) -HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default) -HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default) -HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default) -HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default) -HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default) -HTMLToPDF.printBackground=Render the background of websites. -HTMLToPDF.defaultHeader=Enable Default Header (Name and page number) -HTMLToPDF.cssMediaType=Change the CSS media type of the page. -HTMLToPDF.none=None -HTMLToPDF.print=Print -HTMLToPDF.screen=Screen +HTMLToPDF.zoom=Niveau de zoom pour l\u2019affichage du site web. +HTMLToPDF.pageWidth=Largeur de la page en centimètres. (Vide par défaut) +HTMLToPDF.pageHeight=Hauteur de la page en centimètres. (Vide par défaut) +HTMLToPDF.marginTop=Marge supérieure de la page en millimètres. (Vide par défaut) +HTMLToPDF.marginBottom=Marge inférieure de la page en millimètres. (Vide par défaut) +HTMLToPDF.marginLeft=Marge gauche de la page en millimètres. (Vide par défaut) +HTMLToPDF.marginRight=Marge droite de la page en millimètres. (Vide par défaut) +HTMLToPDF.printBackground=Restituer l\u2019image de fond des sites web. +HTMLToPDF.defaultHeader=Activer l\u2019entête par défaut (Nom et numéro de page) +HTMLToPDF.cssMediaType=Modifier le type de média CSS de la page. +HTMLToPDF.none=Aucun +HTMLToPDF.print=Imprimer +HTMLToPDF.screen=Écran #AddStampRequest -AddStampRequest.header=Stamp PDF -AddStampRequest.title=Stamp PDF -AddStampRequest.stampType=Stamp Type -AddStampRequest.stampText=Stamp Text -AddStampRequest.stampImage=Stamp Image +AddStampRequest.header=Tampon PDF +AddStampRequest.title=Tampon PDF +AddStampRequest.stampType=Type de tampon +AddStampRequest.stampText=Tampon texte +AddStampRequest.stampImage=Tampon image AddStampRequest.alphabet=Alphabet -AddStampRequest.fontSize=Font/Image Size +AddStampRequest.fontSize=Taille de fonte/image AddStampRequest.rotation=Rotation -AddStampRequest.opacity=Opacity +AddStampRequest.opacity=Opacité AddStampRequest.position=Position -AddStampRequest.overrideX=Override X Coordinate -AddStampRequest.overrideY=Override Y Coordinate -AddStampRequest.customMargin=Custom Margin -AddStampRequest.customColor=Custom Text Color -AddStampRequest.submit=Submit +AddStampRequest.overrideX=Définir coordonnées X +AddStampRequest.overrideY=Définir coordonnées Y +AddStampRequest.customMargin=Marge personnalisée +AddStampRequest.customColor=Couleur de texte personnalisée +AddStampRequest.submit=Soumettre #sanitizePDF @@ -586,11 +586,11 @@ scalePages.submit=Ajuster certSign.title=Signer avec un certificat certSign.header=Signer avec un certificat (Travail en cours) certSign.selectPDF=PDF à signer -certSign.jksNote=Note: If your certificate type is not listed below, please convert it to a Java Keystore (.jks) file using the keytool command line tool. Then, choose the .jks file option below. +certSign.jksNote=Note: Si votre type de certificat n\u2019est pas listé ci\u002Ddessous, merci de le convertir en fichier Java Keystore (.jks) en utilisant l\u2019outil en ligne de commande keytool. Puis choisissez l\u2019option Fichier .jks ci\u002Ddessous. certSign.selectKey=Fichier de clé privée (format PKCS#8, peut être .pem ou .der) certSign.selectCert=Fichier de certificat (format X.509, peut être .pem ou .der) certSign.selectP12=Fichier keystore de clés PKCS#12 (.p12 ou .pfx) (facultatif, s\u2019il n\u2019est fourni, il doit contenir votre clé privée et votre certificat) -certSign.selectJKS=Select Your Java Keystore File (.jks or .keystore): +certSign.selectJKS=Sélectionner votre fichier Java Keystore File (.jks or .keystore): certSign.certType=Type de certificat certSign.password=Mot de passe keystore ou clé privée le cas échéant certSign.showSig=Afficher la signature @@ -611,9 +611,9 @@ removeBlanks.submit=Supprimer les pages vierges #removeAnnotations -removeAnnotations.title=Remove Annotations -removeAnnotations.header=Remove Annotations -removeAnnotations.submit=Remove +removeAnnotations.title=Supprimer les annotations +removeAnnotations.header=Supprimer les annotations +removeAnnotations.submit=Supprimer #compare @@ -695,14 +695,14 @@ fileToPDF.submit=Convertir #compress -compress.title=Compresser -compress.header=Compresser +compress.title=Compresser un PDF +compress.header=Compresser un PDF (lorsque c\u2019est possible!) compress.credit=Ce service utilise Ghostscript pour la compression et l\u2019optimisation des PDF. compress.selectText.1=Mode manuel \u2013 de 1 à 4 compress.selectText.2=Niveau d\u2019optimisation compress.selectText.3=4 (terrible pour les images textuelles) compress.selectText.4=Mode automatique \u2013 ajuste automatiquement la qualité pour obtenir le PDF à la taille exacte -compress.selectText.5=Taille PDF attendue (par exemple, 25\u202fMo, 10,8\u202fMo, 25\u202fKo) +compress.selectText.5=Taille PDF attendue (par exemple, 25\u202fMB, 10,8\u202fMB, 25\u202fKB) compress.submit=Compresser @@ -733,8 +733,8 @@ multiTool.title=Outil multifonction PDF multiTool.header=Outil multifonction PDF #view pdf -viewPdf.title=View PDF -viewPdf.header=View PDF +viewPdf.title=Visualiser un PDF +viewPdf.header=Visualiser un PDF #pageRemover pageRemover.title=Supprimer des pages @@ -789,7 +789,7 @@ pdfToImage.multi=Plusieurs images pdfToImage.colorType=Type d\u2019impression pdfToImage.color=Couleur pdfToImage.grey=Niveaux de gris -pdfToImage.blackwhite=Noir et blanc (peut engendre une perde de données\u00a0!) +pdfToImage.blackwhite=Noir et blanc (peut engendrer une perte de données\u00a0!) pdfToImage.submit=Convertir @@ -868,7 +868,7 @@ changeMetadata.keywords=Mots clés changeMetadata.modDate=Date de modification (yyyy/MM/dd HH:mm:ss) changeMetadata.producer=Producteur changeMetadata.subject=Sujet -changeMetadata.trapped=Défoncé (technique d’impression) +changeMetadata.trapped=Recouvrement (technique d’impression) changeMetadata.selectText.4=Autres métadonnées changeMetadata.selectText.5=Ajouter une entrée de métadonnées personnalisée changeMetadata.submit=Modifier @@ -925,6 +925,7 @@ PDFToCSV.prompt=Choisir la page pour en extraire le tableau PDFToCSV.submit=Extrait #split-by-size-or-count +split-by-size-or-count.title=Séparer le PDF par taille ou par nombre split-by-size-or-count.header=Séparer le PDF par taille ou par nombre split-by-size-or-count.type.label=Sélectionner le type de division split-by-size-or-count.type.size=Par taille @@ -936,19 +937,20 @@ split-by-size-or-count.submit=Séparer #overlay-pdfs -overlay-pdfs.header=Overlay PDF Files +overlay-pdfs.title=Incrustation de PDF +overlay-pdfs.header=Incrustation de PDF overlay-pdfs.baseFile.label=Sélectionner le fichier PDF de base overlay-pdfs.overlayFiles.label=Sélectionner les fichiers PDF à superposer -overlay-pdfs.mode.label=Select Overlay Mode -overlay-pdfs.mode.sequential=Sequential Overlay -overlay-pdfs.mode.interleaved=Interleaved Overlay +overlay-pdfs.mode.label=Sélectionner le mode d\u2019incrustation +overlay-pdfs.mode.sequential=Superposition séquentielle +overlay-pdfs.mode.interleaved=Superposition entrelacée overlay-pdfs.mode.fixedRepeat=Superposition à répétition fixe overlay-pdfs.counts.label=Nombre de superpositions (pour le mode de répétition fixe) -overlay-pdfs.counts.placeholder=Enter comma-separated counts (e.g., 2,3,1) -overlay-pdfs.position.label=Select Overlay Position +overlay-pdfs.counts.placeholder=Compteurs (séparés par des virgules, exemple : 2,3,1) +overlay-pdfs.position.label=Définir la position de l\u2019incrustation overlay-pdfs.position.foreground=Premier plan overlay-pdfs.position.background=Arrière-plan -overlay-pdfs.submit=Submit +overlay-pdfs.submit=Soumettre #split-by-sections @@ -962,11 +964,9 @@ split-by-sections.submit=Diviser le PDF #licenses -licenses.nav=Licenses -licenses.title=3rd Party Licenses -licenses.header=3rd Party Licenses +licenses.nav=Licences +licenses.title=Licences tierces +licenses.header=Licences tierces licenses.module=Module licenses.version=Version -licenses.license=License - - +licenses.license=Licence From 010426d488adae315bc6f118b9367e1d5f5570c1 Mon Sep 17 00:00:00 2001 From: Ludy Date: Fri, 16 Feb 2024 23:42:56 +0100 Subject: [PATCH 006/200] Document (#803) * Update HowToAddNewLanguage.md * Update HowToUseOCR.md * Update LocalRunGuide.md * Update README.md * Update LocalRunGuide.md * Update README.md --------- Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> --- HowToAddNewLanguage.md | 4 ++-- HowToUseOCR.md | 2 +- LocalRunGuide.md | 4 ++-- README.md | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/HowToAddNewLanguage.md b/HowToAddNewLanguage.md index 9f8e3f39..385ccbbc 100644 --- a/HowToAddNewLanguage.md +++ b/HowToAddNewLanguage.md @@ -12,7 +12,7 @@ https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/temp and add a flag svg file to https://github.com/Stirling-Tools/Stirling-PDF/tree/main/src/main/resources/static/images/flags Any SVG flags are fine, i got most of mine from [here](https://flagicons.lipis.dev/) -If your language isnt represented by a flag just find whichever closely matches it, such as for Arabic i chose Saudi Arabia +If your language isn't represented by a flag just find whichever closely matches it, such as for Arabic i chose Saudi Arabia For example to add Polish you would add @@ -32,7 +32,7 @@ Copy and rename it to messages_{your data-language-code here}.properties, in the Then simply translate all property entries within that file and make a PR into main for others to use! -If you do not have a java IDE i am happy to verify the changes worked once you raise PR (but wont be able to verify the translations themselves) +If you do not have a java IDE i am happy to verify the changes worked once you raise PR (but won't be able to verify the translations themselves) diff --git a/HowToUseOCR.md b/HowToUseOCR.md index 388ab438..d3e5744c 100644 --- a/HowToUseOCR.md +++ b/HowToUseOCR.md @@ -2,7 +2,7 @@ This document provides instructions on how to add additional language packs for the OCR tab in Stirling-PDF, both inside and outside of Docker. -## My OCR used to work and now doesnt! +## My OCR used to work and now doesn't! Please update your tesseract docker volume path version from 4.00 to 5 ## How does the OCR Work diff --git a/LocalRunGuide.md b/LocalRunGuide.md index 3c9b2716..9858f300 100644 --- a/LocalRunGuide.md +++ b/LocalRunGuide.md @@ -65,7 +65,7 @@ sudo make install ``` ### Step 3: Install Additional Software -Next we need to install LibreOffice for conversions, ocrmypdf for OCR, and opencv for patern recognition functionality. +Next we need to install LibreOffice for conversions, ocrmypdf for OCR, and opencv for pattern recognition functionality. Install the following software: @@ -264,7 +264,7 @@ sudo systemctl restart stirlingpdf.service Remember to set the necessary environment variables before running the project if you want to customize the application the list can be seen in the main readme. -You can do this in the terminal by using the `export` command or -D arguements to java -jar command: +You can do this in the terminal by using the `export` command or -D argument to java -jar command: ```bash export APP_HOME_NAME="Stirling PDF" diff --git a/README.md b/README.md index 5876a7e2..b04da526 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Docker Image Version (tag latest semver)](https://img.shields.io/docker/v/frooodle/s-pdf/latest)](https://github.com/Stirling-Tools/Stirling-PDF/) [![GitHub Repo stars](https://img.shields.io/github/stars/stirling-tools/stirling-pdf?style=social)](https://github.com/Stirling-Tools/stirling-pdf) [![Paypal Donate](https://img.shields.io/badge/Paypal%20Donate-yellow?style=flat&logo=paypal)](https://www.paypal.com/paypalme/froodleplex) -[![Github Sponser](https://img.shields.io/badge/Github%20Sponsor-yellow?style=flat&logo=github)](https://github.com/sponsors/Frooodle) +[![Github Sponsor](https://img.shields.io/badge/Github%20Sponsor-yellow?style=flat&logo=github)](https://github.com/sponsors/Frooodle) [![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Stirling-Tools/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af) @@ -262,7 +262,7 @@ For API usage you must provide a header with 'X-API-Key' and the associated API - Redact text (Via UI not just automated way) - Add Forms - Multi page layout (Stich PDF pages together) support x rows y columns and custom page sizing -- Fill forms mannual and automatic +- Fill forms manually or automatically ### Q2: Why is my application downloading .htm files? This is an issue caused commonly by your NGINX configuration. The default file upload size for NGINX is 1MB, you need to add the following in your Nginx sites-available file. ``client_max_body_size SIZE;`` Where "SIZE" is 50M for example for 50MB files. From a5f07778926da2e883b202c637906b44577e6a4d Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sat, 17 Feb 2024 13:10:00 +0000 Subject: [PATCH 007/200] Update ConfigInitializer.java for auto settings removal --- .../SPDF/config/ConfigInitializer.java | 79 ++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/main/java/stirling/software/SPDF/config/ConfigInitializer.java b/src/main/java/stirling/software/SPDF/config/ConfigInitializer.java index a5d05999..7bceaf8f 100644 --- a/src/main/java/stirling/software/SPDF/config/ConfigInitializer.java +++ b/src/main/java/stirling/software/SPDF/config/ConfigInitializer.java @@ -79,6 +79,16 @@ public class ConfigInitializer return parts.length > 0 ? parts[0].trim().replace("#", "").trim() : ""; }; + Function getIndentationLevel = + line -> { + int count = 0; + for (char ch : line.toCharArray()) { + if (ch == ' ') count++; + else break; + } + return count; + }; + Set userKeys = userLines.stream().map(extractKey).collect(Collectors.toSet()); for (String line : templateLines) { @@ -134,10 +144,77 @@ public class ConfigInitializer .map(extractKey) .anyMatch(templateKey -> templateKey.equalsIgnoreCase(userKey)); if (!isPresentInTemplate && !isCommented.apply(userLine)) { - mergedLines.add(userLine); + if (!childOfTemplateEntry( + isCommented, + extractKey, + getIndentationLevel, + userLines, + userLine, + templateLines)) { + // check if userLine is a child of a entry within templateLines or not, if child + // of parent in templateLines then dont add to mergedLines, if anything else + // then add + mergedLines.add(userLine); + } } } Files.write(outputPath, mergedLines, StandardCharsets.UTF_8); } + + // New method to check if a userLine is a child of an entry in templateLines + boolean childOfTemplateEntry( + Function isCommented, + Function extractKey, + Function getIndentationLevel, + List userLines, + String userLine, + List templateLines) { + String userKey = extractKey.apply(userLine).trim(); + int userIndentation = getIndentationLevel.apply(userLine); + + // Start by assuming the line is not a child of an entry in templateLines + boolean isChild = false; + + // Iterate backwards through userLines from the current line to find any parent + for (int i = userLines.indexOf(userLine) - 1; i >= 0; i--) { + String potentialParentLine = userLines.get(i); + int parentIndentation = getIndentationLevel.apply(potentialParentLine); + + // Check if we've reached a potential parent based on indentation + if (parentIndentation < userIndentation) { + String parentKey = extractKey.apply(potentialParentLine).trim(); + + // Now, check if this potential parent or any of its parents exist in templateLines + boolean parentExistsInTemplate = + templateLines.stream() + .filter(line -> !isCommented.apply(line)) // Skip commented lines + .anyMatch( + templateLine -> { + String templateKey = + extractKey.apply(templateLine).trim(); + return parentKey.equalsIgnoreCase(templateKey); + }); + + if (!parentExistsInTemplate) { + // If the parent does not exist in template, check the next level parent + userIndentation = + parentIndentation; // Update userIndentation to the parent's indentation + // for next iteration + if (parentIndentation == 0) { + // If we've reached the top-level parent and it's not in template, the + // original line is considered not a child + isChild = false; + break; + } + } else { + // If any parent exists in template, the original line is considered a child + isChild = true; + break; + } + } + } + + return isChild; // Return true if the line is not a child of any entry in templateLines + } } From 148dcdaee7680d45ce46cb4f835e50721117d510 Mon Sep 17 00:00:00 2001 From: albanobattistella <34811668+albanobattistella@users.noreply.github.com> Date: Sat, 17 Feb 2024 14:22:15 +0100 Subject: [PATCH 008/200] Update messages_it_IT.properties (#816) --- src/main/resources/messages_it_IT.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/messages_it_IT.properties b/src/main/resources/messages_it_IT.properties index 70793c70..4557da8d 100644 --- a/src/main/resources/messages_it_IT.properties +++ b/src/main/resources/messages_it_IT.properties @@ -11,7 +11,7 @@ imgPrompt=Scegli immagine/i genericSubmit=Invia processTimeWarning=Nota: Questo processo potrebbe richiedere fino a un minuto in base alla dimensione dei file pageOrderPrompt=Ordine delle pagine (inserisci una lista di numeri separati da virgola): -pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) : +pageSelectionPrompt=Selezione pagina personalizzata (inserisci un elenco separato da virgole di numeri di pagina 1,5,6 o funzioni come 2n+1) : goToPage=Vai true=Vero false=Falso From 918f5954b7f33890dd25bc634ced9a192926b197 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 17 Feb 2024 13:23:10 +0000 Subject: [PATCH 009/200] Bump io.micrometer:micrometer-core from 1.12.2 to 1.12.3 (#806) Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.12.2 to 1.12.3. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.12.2...v1.12.3) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 727b2b53..52c8970c 100644 --- a/build.gradle +++ b/build.gradle @@ -150,7 +150,7 @@ dependencies { implementation 'org.bouncycastle:bcprov-jdk18on:1.77' implementation 'org.bouncycastle:bcpkix-jdk18on:1.77' implementation 'org.springframework.boot:spring-boot-starter-actuator:3.2.2' - implementation 'io.micrometer:micrometer-core:1.12.2' + implementation 'io.micrometer:micrometer-core:1.12.3' implementation group: 'com.google.zxing', name: 'core', version: '3.5.2' // https://mvnrepository.com/artifact/org.commonmark/commonmark implementation 'org.commonmark:commonmark:0.21.0' From a0acafcefce317d981a4af7372767f21a02fe00d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 17 Feb 2024 13:24:38 +0000 Subject: [PATCH 010/200] Bump org.springframework:spring-webmvc from 6.1.2 to 6.1.3 (#713) Bumps [org.springframework:spring-webmvc](https://github.com/spring-projects/spring-framework) from 6.1.2 to 6.1.3. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.2...v6.1.3) --- updated-dependencies: - dependency-name: org.springframework:spring-webmvc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 52c8970c..413383e4 100644 --- a/build.gradle +++ b/build.gradle @@ -89,7 +89,7 @@ dependencies { //security updates implementation 'ch.qos.logback:logback-classic:1.4.14' implementation 'ch.qos.logback:logback-core:1.4.14' - implementation 'org.springframework:spring-webmvc:6.1.2' + implementation 'org.springframework:spring-webmvc:6.1.3' implementation("io.github.pixee:java-security-toolkit:1.1.2") From 56e3ec121981fc06ab97d2d4c2bf7832de8fbd7e Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sat, 17 Feb 2024 19:28:32 +0000 Subject: [PATCH 011/200] Update HowToUseOCR.md --- HowToUseOCR.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HowToUseOCR.md b/HowToUseOCR.md index d3e5744c..d68283f7 100644 --- a/HowToUseOCR.md +++ b/HowToUseOCR.md @@ -3,7 +3,7 @@ This document provides instructions on how to add additional language packs for the OCR tab in Stirling-PDF, both inside and outside of Docker. ## My OCR used to work and now doesn't! -Please update your tesseract docker volume path version from 4.00 to 5 +The paths have changed for the tessadata locations on new docker images, please use ``/usr/share/tessdata`` (Others should still work for backwards compatability but might not) ## How does the OCR Work Stirling-PDF uses [OCRmyPDF](https://github.com/ocrmypdf/OCRmyPDF) which in turn uses tesseract for its text recognition. From 8d9f0361d0a7db2c4eae62d8f58530eb55eadf8b Mon Sep 17 00:00:00 2001 From: Ludy Date: Sat, 17 Feb 2024 20:56:56 +0100 Subject: [PATCH 012/200] Fix Serbia Language (#822) * Fix Serbia Language * Rename messages_sr_Latn_RS.properties to messages_sr_LATN_RS.properties * Update languages.html * Update README.md --- README.md | 2 +- ...sr-Latn-RS.properties => messages_sr_LATN_RS.properties} | 0 src/main/resources/static/js/languageSelection.js | 2 +- src/main/resources/templates/about.html | 2 +- src/main/resources/templates/account.html | 2 +- src/main/resources/templates/addUsers.html | 2 +- src/main/resources/templates/auto-split-pdf.html | 2 +- src/main/resources/templates/change-creds.html | 2 +- src/main/resources/templates/convert/book-to-pdf.html | 2 +- src/main/resources/templates/convert/file-to-pdf.html | 2 +- src/main/resources/templates/convert/html-to-pdf.html | 2 +- src/main/resources/templates/convert/img-to-pdf.html | 2 +- src/main/resources/templates/convert/markdown-to-pdf.html | 2 +- src/main/resources/templates/convert/pdf-to-book.html | 2 +- src/main/resources/templates/convert/pdf-to-csv.html | 2 +- src/main/resources/templates/convert/pdf-to-html.html | 2 +- src/main/resources/templates/convert/pdf-to-img.html | 2 +- src/main/resources/templates/convert/pdf-to-pdfa.html | 2 +- .../resources/templates/convert/pdf-to-presentation.html | 2 +- src/main/resources/templates/convert/pdf-to-text.html | 2 +- src/main/resources/templates/convert/pdf-to-word.html | 2 +- src/main/resources/templates/convert/pdf-to-xml.html | 2 +- src/main/resources/templates/convert/url-to-pdf.html | 2 +- src/main/resources/templates/crop.html | 2 +- src/main/resources/templates/error.html | 2 +- src/main/resources/templates/extract-page.html | 2 +- src/main/resources/templates/fragments/languages.html | 2 +- src/main/resources/templates/fragments/navbar.html | 1 - src/main/resources/templates/home.html | 2 +- src/main/resources/templates/licenses.html | 2 +- src/main/resources/templates/login.html | 6 +++--- src/main/resources/templates/merge-pdfs.html | 2 +- src/main/resources/templates/misc/add-image.html | 2 +- src/main/resources/templates/misc/add-page-numbers.html | 2 +- src/main/resources/templates/misc/adjust-contrast.html | 2 +- src/main/resources/templates/misc/auto-crop.html | 2 +- src/main/resources/templates/misc/auto-rename.html | 2 +- src/main/resources/templates/misc/change-metadata.html | 2 +- src/main/resources/templates/misc/compare.html | 2 +- src/main/resources/templates/misc/compress-pdf.html | 3 +-- src/main/resources/templates/misc/extract-image-scans.html | 2 +- src/main/resources/templates/misc/extract-images.html | 2 +- src/main/resources/templates/misc/flatten.html | 2 +- src/main/resources/templates/misc/ocr-pdf.html | 2 +- src/main/resources/templates/misc/remove-annotations.html | 2 +- src/main/resources/templates/misc/remove-blanks.html | 2 +- src/main/resources/templates/misc/repair.html | 2 +- src/main/resources/templates/misc/show-javascript.html | 2 +- src/main/resources/templates/misc/stamp.html | 2 +- src/main/resources/templates/multi-page-layout.html | 2 +- src/main/resources/templates/multi-tool.html | 2 +- src/main/resources/templates/overlay-pdf.html | 2 +- src/main/resources/templates/pdf-organizer.html | 2 +- src/main/resources/templates/pdf-to-single-page.html | 2 +- src/main/resources/templates/pipeline.html | 2 +- src/main/resources/templates/remove-pages.html | 2 +- src/main/resources/templates/rotate-pdf.html | 2 +- src/main/resources/templates/scale-pages.html | 2 +- src/main/resources/templates/security/add-password.html | 2 +- src/main/resources/templates/security/add-watermark.html | 2 +- src/main/resources/templates/security/auto-redact.html | 2 +- src/main/resources/templates/security/cert-sign.html | 2 +- .../resources/templates/security/change-permissions.html | 2 +- src/main/resources/templates/security/get-info-on-pdf.html | 2 +- src/main/resources/templates/security/remove-password.html | 2 +- src/main/resources/templates/security/remove-watermark.html | 2 +- src/main/resources/templates/security/sanitize-pdf.html | 2 +- src/main/resources/templates/sign.html | 2 +- src/main/resources/templates/split-by-size-or-count.html | 2 +- src/main/resources/templates/split-pdf-by-sections.html | 2 +- src/main/resources/templates/split-pdfs.html | 2 +- 71 files changed, 71 insertions(+), 73 deletions(-) rename src/main/resources/{messages_sr-Latn-RS.properties => messages_sr_LATN_RS.properties} (100%) diff --git a/README.md b/README.md index b04da526..690adacd 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ Stirling PDF currently supports 26! - Hindi (हिंदी) (hi_IN) - Hungarian (Magyar) (hu_HU) - Bulgarian (Български) (bg_BG) -- Sebian Latin alphabet (Srpski) (sr-Latn-RS) +- Sebian Latin alphabet (Srpski) (sr_LATN_RS) ## Contributing (creating issues, translations, fixing bugs, etc.) diff --git a/src/main/resources/messages_sr-Latn-RS.properties b/src/main/resources/messages_sr_LATN_RS.properties similarity index 100% rename from src/main/resources/messages_sr-Latn-RS.properties rename to src/main/resources/messages_sr_LATN_RS.properties diff --git a/src/main/resources/static/js/languageSelection.js b/src/main/resources/static/js/languageSelection.js index af67da48..413bebe0 100644 --- a/src/main/resources/static/js/languageSelection.js +++ b/src/main/resources/static/js/languageSelection.js @@ -26,7 +26,7 @@ document.addEventListener("DOMContentLoaded", function () { }); function setLanguageForDropdown(dropdownClass) { - const defaultLocale = document.documentElement.lang || "en_GB"; + const defaultLocale = document.documentElement.language || "en_GB"; const storedLocale = localStorage.getItem("languageCode") || defaultLocale; const dropdownItems = document.querySelectorAll(dropdownClass); diff --git a/src/main/resources/templates/about.html b/src/main/resources/templates/about.html index 17e79d57..957bf45f 100644 --- a/src/main/resources/templates/about.html +++ b/src/main/resources/templates/about.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/account.html b/src/main/resources/templates/account.html index 9b7f4df9..4398891d 100644 --- a/src/main/resources/templates/account.html +++ b/src/main/resources/templates/account.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/addUsers.html b/src/main/resources/templates/addUsers.html index 0cf3306d..f5e5e87d 100644 --- a/src/main/resources/templates/addUsers.html +++ b/src/main/resources/templates/addUsers.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/auto-split-pdf.html b/src/main/resources/templates/auto-split-pdf.html index e4d213d8..26106b46 100644 --- a/src/main/resources/templates/auto-split-pdf.html +++ b/src/main/resources/templates/auto-split-pdf.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/change-creds.html b/src/main/resources/templates/change-creds.html index 4709e40b..b22a9bd2 100644 --- a/src/main/resources/templates/change-creds.html +++ b/src/main/resources/templates/change-creds.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/book-to-pdf.html b/src/main/resources/templates/convert/book-to-pdf.html index 94229ccf..7d9d436c 100644 --- a/src/main/resources/templates/convert/book-to-pdf.html +++ b/src/main/resources/templates/convert/book-to-pdf.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/file-to-pdf.html b/src/main/resources/templates/convert/file-to-pdf.html index 3949688f..26217b56 100644 --- a/src/main/resources/templates/convert/file-to-pdf.html +++ b/src/main/resources/templates/convert/file-to-pdf.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/html-to-pdf.html b/src/main/resources/templates/convert/html-to-pdf.html index 11184606..c9a26a6b 100644 --- a/src/main/resources/templates/convert/html-to-pdf.html +++ b/src/main/resources/templates/convert/html-to-pdf.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/img-to-pdf.html b/src/main/resources/templates/convert/img-to-pdf.html index 4de9e0f6..6d68fdec 100644 --- a/src/main/resources/templates/convert/img-to-pdf.html +++ b/src/main/resources/templates/convert/img-to-pdf.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/markdown-to-pdf.html b/src/main/resources/templates/convert/markdown-to-pdf.html index d0266aac..8df3ad17 100644 --- a/src/main/resources/templates/convert/markdown-to-pdf.html +++ b/src/main/resources/templates/convert/markdown-to-pdf.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/pdf-to-book.html b/src/main/resources/templates/convert/pdf-to-book.html index e8ef9402..2056c7f5 100644 --- a/src/main/resources/templates/convert/pdf-to-book.html +++ b/src/main/resources/templates/convert/pdf-to-book.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/pdf-to-csv.html b/src/main/resources/templates/convert/pdf-to-csv.html index d21156f0..16da051e 100644 --- a/src/main/resources/templates/convert/pdf-to-csv.html +++ b/src/main/resources/templates/convert/pdf-to-csv.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/pdf-to-html.html b/src/main/resources/templates/convert/pdf-to-html.html index b2347f02..f2e914f9 100644 --- a/src/main/resources/templates/convert/pdf-to-html.html +++ b/src/main/resources/templates/convert/pdf-to-html.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/pdf-to-img.html b/src/main/resources/templates/convert/pdf-to-img.html index 61034578..bcf3e8b3 100644 --- a/src/main/resources/templates/convert/pdf-to-img.html +++ b/src/main/resources/templates/convert/pdf-to-img.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/pdf-to-pdfa.html b/src/main/resources/templates/convert/pdf-to-pdfa.html index 1b75a078..866449f1 100644 --- a/src/main/resources/templates/convert/pdf-to-pdfa.html +++ b/src/main/resources/templates/convert/pdf-to-pdfa.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/pdf-to-presentation.html b/src/main/resources/templates/convert/pdf-to-presentation.html index f0a4a44a..408ff151 100644 --- a/src/main/resources/templates/convert/pdf-to-presentation.html +++ b/src/main/resources/templates/convert/pdf-to-presentation.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/pdf-to-text.html b/src/main/resources/templates/convert/pdf-to-text.html index cc6b7dcb..d1616589 100644 --- a/src/main/resources/templates/convert/pdf-to-text.html +++ b/src/main/resources/templates/convert/pdf-to-text.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/pdf-to-word.html b/src/main/resources/templates/convert/pdf-to-word.html index 74e6f314..6fd76f4e 100644 --- a/src/main/resources/templates/convert/pdf-to-word.html +++ b/src/main/resources/templates/convert/pdf-to-word.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/pdf-to-xml.html b/src/main/resources/templates/convert/pdf-to-xml.html index 701220c1..a7d020b0 100644 --- a/src/main/resources/templates/convert/pdf-to-xml.html +++ b/src/main/resources/templates/convert/pdf-to-xml.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/convert/url-to-pdf.html b/src/main/resources/templates/convert/url-to-pdf.html index 68044385..94f0bfa5 100644 --- a/src/main/resources/templates/convert/url-to-pdf.html +++ b/src/main/resources/templates/convert/url-to-pdf.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/crop.html b/src/main/resources/templates/crop.html index 825cfbec..05de3516 100644 --- a/src/main/resources/templates/crop.html +++ b/src/main/resources/templates/crop.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html index d3cbecb6..954bcd7d 100644 --- a/src/main/resources/templates/error.html +++ b/src/main/resources/templates/error.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/extract-page.html b/src/main/resources/templates/extract-page.html index a14e13d2..4bbd8b22 100644 --- a/src/main/resources/templates/extract-page.html +++ b/src/main/resources/templates/extract-page.html @@ -1,5 +1,5 @@ - + diff --git a/src/main/resources/templates/fragments/languages.html b/src/main/resources/templates/fragments/languages.html index f44caef3..07f16cc3 100644 --- a/src/main/resources/templates/fragments/languages.html +++ b/src/main/resources/templates/fragments/languages.html @@ -24,5 +24,5 @@ icon Ελληνικά icon Hungarian icon हिन्दी - icon Srpski + icon Srpski diff --git a/src/main/resources/templates/fragments/navbar.html b/src/main/resources/templates/fragments/navbar.html index c8ad96b6..4eaa22eb 100644 --- a/src/main/resources/templates/fragments/navbar.html +++ b/src/main/resources/templates/fragments/navbar.html @@ -139,7 +139,6 @@
      -
      +
      +
      +

      +
      +
      +
      +
      + + +
      +
      + + - +
      +
      - -
      - + diff --git a/src/main/resources/templates/misc/compare.html b/src/main/resources/templates/misc/compare.html index c225f6b2..3b564855 100644 --- a/src/main/resources/templates/misc/compare.html +++ b/src/main/resources/templates/misc/compare.html @@ -4,11 +4,11 @@ diff --git a/src/main/resources/templates/misc/extract-images.html b/src/main/resources/templates/misc/extract-images.html index b14c9b20..bf79fa54 100644 --- a/src/main/resources/templates/misc/extract-images.html +++ b/src/main/resources/templates/misc/extract-images.html @@ -5,7 +5,7 @@ - +
      diff --git a/src/main/resources/templates/misc/flatten.html b/src/main/resources/templates/misc/flatten.html index 1d4563bc..6107fcc4 100644 --- a/src/main/resources/templates/misc/flatten.html +++ b/src/main/resources/templates/misc/flatten.html @@ -21,26 +21,26 @@ diff --git a/src/main/resources/templates/view-pdf.html b/src/main/resources/templates/view-pdf.html index 8aca4542..afe4e957 100644 --- a/src/main/resources/templates/view-pdf.html +++ b/src/main/resources/templates/view-pdf.html @@ -32,11 +32,11 @@ See https://github.com/adobe-type-tools/cmap-resources - - + + - - + + From 3a62d199794d7a2193630973cd3dad256ea4e29a Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com.> Date: Sun, 18 Feb 2024 09:21:30 +0000 Subject: [PATCH 015/200] game const --- src/main/resources/static/js/game.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/resources/static/js/game.js b/src/main/resources/static/js/game.js index 199bab0f..c98c3a86 100644 --- a/src/main/resources/static/js/game.js +++ b/src/main/resources/static/js/game.js @@ -26,14 +26,22 @@ function initializeGame() { let highScore = localStorage.getItem("highScore") ? parseInt(localStorage.getItem("highScore")) : 0; updateHighScore(); + const BASE_PDF_SPEED = 1; + const LEVEL_INCREASE_PDF_SPEED = 0.2; + const BASE_SPAWN_INTERVAL_MS = 1250; // milliseconds before a new enemy spawns + const LEVEL_INCREASE_FACTOR_MS = 25; // milliseconds to decrease the spawn interval per level + const MAX_SPAWN_RATE_REDUCTION_MS = 800; // Max milliseconds from the base spawn interval + + const keysPressed = {}; const pdfs = []; const projectiles = []; let score = 0; let level = 1; - let pdfSpeed = 0.5; + let pdfSpeed = BASE_PDF_SPEED; let gameOver = false; + function handleKeys() { if (keysPressed["ArrowLeft"]) { playerX -= 10; @@ -188,7 +196,7 @@ function initializeGame() { updateScore(); updateLives(); levelElement.textContent = "Level: " + level; - pdfSpeed = 1; + pdfSpeed = BASE_PDF_SPEED; clearTimeout(spawnPdfTimeout); // Clear the existing spawnPdfTimeout setTimeout(updateGame, 1000 / 60); spawnPdfInterval(); @@ -204,7 +212,7 @@ function initializeGame() { if (newLevel > level) { level = newLevel; levelElement.textContent = "Level: " + level; - pdfSpeed += 0.2; + pdfSpeed += LEVEL_INCREASE_PDF_SPEED; } } @@ -227,9 +235,7 @@ function initializeGame() { let spawnPdfTimeout; - const BASE_SPAWN_INTERVAL_MS = 1250; // milliseconds before a new enemy spawns - const LEVEL_INCREASE_FACTOR_MS = 0; // milliseconds to decrease the spawn interval per level - const MAX_SPAWN_RATE_REDUCTION_MS = 800; // Max milliseconds from the base spawn interval + function spawnPdfInterval() { console.log("spawnPdfInterval"); From 20cb460a7eb13452ff14d5cf0d98a54119773ab1 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com.> Date: Sun, 18 Feb 2024 09:45:50 +0000 Subject: [PATCH 016/200] controls and sizing bounds --- src/main/resources/static/js/game.js | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/main/resources/static/js/game.js b/src/main/resources/static/js/game.js index c98c3a86..6ddc392e 100644 --- a/src/main/resources/static/js/game.js +++ b/src/main/resources/static/js/game.js @@ -26,6 +26,7 @@ function initializeGame() { let highScore = localStorage.getItem("highScore") ? parseInt(localStorage.getItem("highScore")) : 0; updateHighScore(); + const PLAYER_MOVE_SPEED = 5; const BASE_PDF_SPEED = 1; const LEVEL_INCREASE_PDF_SPEED = 0.2; const BASE_SPAWN_INTERVAL_MS = 1250; // milliseconds before a new enemy spawns @@ -33,7 +34,7 @@ function initializeGame() { const MAX_SPAWN_RATE_REDUCTION_MS = 800; // Max milliseconds from the base spawn interval - const keysPressed = {}; + let keysPressed = {}; const pdfs = []; const projectiles = []; let score = 0; @@ -44,10 +45,12 @@ function initializeGame() { function handleKeys() { if (keysPressed["ArrowLeft"]) { - playerX -= 10; + playerX -= PLAYER_MOVE_SPEED; + playerX = Math.max(0, playerX) } if (keysPressed["ArrowRight"]) { - playerX += 10; + playerX += PLAYER_MOVE_SPEED; + playerX = Math.min(gameContainer.clientWidth - playerSize, playerX); } if (keysPressed[" "] && !gameOver) { const currentTime = new Date().getTime(); @@ -59,17 +62,21 @@ function initializeGame() { updatePlayerPosition(); } - document.addEventListener("keydown", (event) => { + function onKeydown(event) { if (event.key === " ") { event.preventDefault(); } keysPressed[event.key] = true; handleKeys(); - }); - - document.addEventListener("keyup", (event) => { - keysPressed[event.key] = false; - }); + } + function onKeyUp(event) { + keysPressed[event.key] = false; + } + + document.removeEventListener("keydown", onKeydown); + document.removeEventListener("keyup", onKeyUp); + document.addEventListener("keydown", onKeydown); + document.addEventListener("keyup", onKeyUp); function updatePlayerPosition() { player.style.left = playerX + "px"; @@ -102,7 +109,7 @@ function initializeGame() { pdf.classList.add("pdf"); pdf.style.width = pdfSize + "px"; pdf.style.height = pdfSize + "px"; - pdf.style.left = Math.floor(Math.random() * (gameContainer.clientWidth - pdfSize)) + "px"; + pdf.style.left = Math.floor(Math.random() * (gameContainer.clientWidth - (2*pdfSize))) + pdfSize + "px"; pdf.style.top = "0px"; gameContainer.appendChild(pdf); pdfs.push(pdf); @@ -116,6 +123,7 @@ function initializeGame() { function updateGame() { if (gameOver || paused) return; + handleKeys(); for (let pdfIndex = 0; pdfIndex < pdfs.length; pdfIndex++) { const pdf = pdfs[pdfIndex]; const pdfY = parseFloat(pdf.style.top) + pdfSpeed; From c96ebccae46a8c367f42754c13541ba96eb6011f Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com.> Date: Sun, 18 Feb 2024 13:30:56 +0000 Subject: [PATCH 017/200] Download message for game --- src/main/resources/messages_ar_AR.properties | 3 ++- src/main/resources/messages_bg_BG.properties | 3 ++- src/main/resources/messages_ca_CA.properties | 3 ++- src/main/resources/messages_de_DE.properties | 3 ++- src/main/resources/messages_el_GR.properties | 3 ++- src/main/resources/messages_en_GB.properties | 3 ++- src/main/resources/messages_en_US.properties | 3 ++- src/main/resources/messages_es_ES.properties | 3 ++- src/main/resources/messages_eu_ES.properties | 3 ++- src/main/resources/messages_fr_FR.properties | 5 +++-- src/main/resources/messages_hi_IN.properties | 3 ++- src/main/resources/messages_hu_HU.properties | 3 ++- src/main/resources/messages_id_ID.properties | 3 ++- src/main/resources/messages_it_IT.properties | 3 ++- src/main/resources/messages_ja_JP.properties | 4 +++- src/main/resources/messages_ko_KR.properties | 3 ++- src/main/resources/messages_nl_NL.properties | 3 ++- src/main/resources/messages_pl_PL.properties | 3 ++- src/main/resources/messages_pt_BR.properties | 3 ++- src/main/resources/messages_ro_RO.properties | 3 ++- src/main/resources/messages_ru_RU.properties | 3 ++- .../resources/messages_sr_LATN_RS.properties | 3 ++- src/main/resources/messages_sv_SE.properties | 3 ++- src/main/resources/messages_tr_TR.properties | 3 ++- src/main/resources/messages_zh_CN.properties | 3 ++- src/main/resources/messages_zh_TW.properties | 3 ++- src/main/resources/static/js/downloader.js | 18 ++++++++++++++++++ src/main/resources/static/js/game.js | 3 --- .../resources/templates/fragments/common.html | 7 +++++-- 29 files changed, 77 insertions(+), 32 deletions(-) diff --git a/src/main/resources/messages_ar_AR.properties b/src/main/resources/messages_ar_AR.properties index bdd14ecd..f2a2a75d 100644 --- a/src/main/resources/messages_ar_AR.properties +++ b/src/main/resources/messages_ar_AR.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=\u062D\u0641\u0638 close=\u0625\u063A\u0644\u0627\u0642 filesSelected=الملفات المحددة noFavourites=لم تتم إضافة أي مفضلات +downloadComplete=Download Complete bored=الانتظار بالملل؟ alphabet=\u0627\u0644\u0623\u0628\u062C\u062F\u064A\u0629 downloadPdf=تنزيل PDF diff --git a/src/main/resources/messages_bg_BG.properties b/src/main/resources/messages_bg_BG.properties index 9bef411d..9fbee0f4 100644 --- a/src/main/resources/messages_bg_BG.properties +++ b/src/main/resources/messages_bg_BG.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Съхранете close=Затворете filesSelected=избрани файлове noFavourites=Няма добавени любими +downloadComplete=Download Complete bored=Отекчени сте да чакате? alphabet=Азбука downloadPdf=Изтеглете PDF diff --git a/src/main/resources/messages_ca_CA.properties b/src/main/resources/messages_ca_CA.properties index e47451b6..0cac1ef3 100644 --- a/src/main/resources/messages_ca_CA.properties +++ b/src/main/resources/messages_ca_CA.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Desa close=Tanca filesSelected=fitxers seleccionats noFavourites=No s'ha afegit cap favorit +downloadComplete=Download Complete bored=Avorrit esperant? alphabet=Alfabet downloadPdf=Descarregueu PDF diff --git a/src/main/resources/messages_de_DE.properties b/src/main/resources/messages_de_DE.properties index 2f043a7c..badb132f 100644 --- a/src/main/resources/messages_de_DE.properties +++ b/src/main/resources/messages_de_DE.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Speichern close=Schließen filesSelected=Dateien ausgewählt noFavourites=Keine Favoriten hinzugefügt +downloadComplete=Download Complete bored=Langeweile beim Warten? alphabet=Alphabet downloadPdf=PDF herunterladen diff --git a/src/main/resources/messages_el_GR.properties b/src/main/resources/messages_el_GR.properties index fa3c4b65..ae4993a9 100644 --- a/src/main/resources/messages_el_GR.properties +++ b/src/main/resources/messages_el_GR.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=\u0391\u03C0\u03BF\u03B8\u03AE\u03BA\u03B5\u03C5\u03C3\u03B7 close=\u039A\u03BB\u03B5\u03AF\u03C3\u03B9\u03BC\u03BF filesSelected=\u03B1\u03C1\u03C7\u03B5\u03AF\u03B1 \u03C0\u03BF\u03C5 \u03B5\u03C0\u03B9\u03BB\u03AD\u03C7\u03B8\u03B7\u03BA\u03B1\u03BD noFavourites=\u039A\u03B1\u03BD\u03AD\u03BD\u03B1 \u03B1\u03B3\u03B1\u03C0\u03AE\u03BC\u03B5\u03BD\u03BF \u03B4\u03B5\u03BD \u03AD\u03C7\u03B5\u03B9 \u03C0\u03C1\u03BF\u03C3\u03C4\u03B5\u03B8\u03B5\u03AF +downloadComplete=Download Complete bored=\u0392\u03B1\u03C1\u03B9\u03AD\u03C3\u03C4\u03B5 \u03BD\u03B1 \u03C0\u03B5\u03C1\u03B9\u03BC\u03AD\u03BD\u03B5\u03C4\u03B5; alphabet=\u0391\u03BB\u03C6\u03AC\u03B2\u03B7\u03C4\u03BF downloadPdf=\u039A\u03B1\u03C4\u03AD\u03B2\u03B1\u03C3\u03BC\u03B1 \u03C4\u03BF\u03C5 PDF diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index 1dd5262d..5d8a4dbc 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr = left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Save close=Close filesSelected=files selected noFavourites=No favourites added +downloadComplete=Download Complete bored=Bored Waiting? alphabet=Alphabet downloadPdf=Download PDF diff --git a/src/main/resources/messages_en_US.properties b/src/main/resources/messages_en_US.properties index 120ace75..2948fa20 100644 --- a/src/main/resources/messages_en_US.properties +++ b/src/main/resources/messages_en_US.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Save close=Close filesSelected=files selected noFavourites=No favorites added +downloadComplete=Download Complete bored=Bored Waiting? alphabet=Alphabet downloadPdf=Download PDF diff --git a/src/main/resources/messages_es_ES.properties b/src/main/resources/messages_es_ES.properties index 38c6d6a5..8e28ef35 100644 --- a/src/main/resources/messages_es_ES.properties +++ b/src/main/resources/messages_es_ES.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Guardar close=Cerrar filesSelected=archivos seleccionados noFavourites=No se agregaron favoritos +downloadComplete=Download Complete bored=¿Cansado de esperar? alphabet=Alfabeto downloadPdf=Descargar PDF diff --git a/src/main/resources/messages_eu_ES.properties b/src/main/resources/messages_eu_ES.properties index 21767b94..9267379f 100644 --- a/src/main/resources/messages_eu_ES.properties +++ b/src/main/resources/messages_eu_ES.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Gorde close=Itxi filesSelected=Hautatutako fitxategiak noFavourites=Ez dira gogokoak gehitu +downloadComplete=Download Complete bored=Itxaroten aspertuta? alphabet=Alfabetoa downloadPdf=PDFa deskargatu diff --git a/src/main/resources/messages_fr_FR.properties b/src/main/resources/messages_fr_FR.properties index e40d9291..58ee579d 100644 --- a/src/main/resources/messages_fr_FR.properties +++ b/src/main/resources/messages_fr_FR.properties @@ -20,6 +20,7 @@ save=Enregistrer close=Fermer filesSelected=fichiers sélectionnés noFavourites=Aucun favori ajouté +downloadComplete=Téléchargement terminé bored=Ennuyé d\u2019attendre\u00a0? alphabet=Alphabet downloadPdf=Télécharger le PDF @@ -925,7 +926,6 @@ PDFToCSV.prompt=Choisir la page pour en extraire le tableau PDFToCSV.submit=Extrait #split-by-size-or-count -split-by-size-or-count.title=Séparer le PDF par taille ou par nombre split-by-size-or-count.header=Séparer le PDF par taille ou par nombre split-by-size-or-count.type.label=Sélectionner le type de division split-by-size-or-count.type.size=Par taille @@ -937,7 +937,6 @@ split-by-size-or-count.submit=Séparer #overlay-pdfs -overlay-pdfs.title=Incrustation de PDF overlay-pdfs.header=Incrustation de PDF overlay-pdfs.baseFile.label=Sélectionner le fichier PDF de base overlay-pdfs.overlayFiles.label=Sélectionner les fichiers PDF à superposer @@ -970,3 +969,5 @@ licenses.header=Licences tierces licenses.module=Module licenses.version=Version licenses.license=Licence + + diff --git a/src/main/resources/messages_hi_IN.properties b/src/main/resources/messages_hi_IN.properties index b17af690..1033b65a 100644 --- a/src/main/resources/messages_hi_IN.properties +++ b/src/main/resources/messages_hi_IN.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=सहेजें close=बंद करें filesSelected=फ़ाइलें चयनित हैं noFavourites=कोई पसंदीदा जोड़ा नहीं गया है +downloadComplete=Download Complete bored=बोर हो रहे हैं? alphabet=वर्णमाला downloadPdf=पीडीएफ़ डाउनलोड करें diff --git a/src/main/resources/messages_hu_HU.properties b/src/main/resources/messages_hu_HU.properties index 0fab7e30..b82e1d64 100644 --- a/src/main/resources/messages_hu_HU.properties +++ b/src/main/resources/messages_hu_HU.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Mentés close=Bezárás filesSelected=kiválasztott fájlok noFavourites=Nincs hozzáadva kedvenc +downloadComplete=Download Complete bored=Unatkozol? alphabet=Ábécé downloadPdf=PDF letöltése diff --git a/src/main/resources/messages_id_ID.properties b/src/main/resources/messages_id_ID.properties index 4bbe247b..e3c1cec7 100644 --- a/src/main/resources/messages_id_ID.properties +++ b/src/main/resources/messages_id_ID.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl=right to left) @@ -20,6 +20,7 @@ save=Simpan close=Tutup filesSelected=berkas dipilih noFavourites=Tidak ada favorit yang ditambahkan +downloadComplete=Download Complete bored=Bosan Menunggu? alphabet=Abjad downloadPdf=Unduh PDF diff --git a/src/main/resources/messages_it_IT.properties b/src/main/resources/messages_it_IT.properties index 4557da8d..871b28a7 100644 --- a/src/main/resources/messages_it_IT.properties +++ b/src/main/resources/messages_it_IT.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Salva close=Chiudi filesSelected=file selezionati noFavourites=Nessun preferito +downloadComplete=Download Complete bored=Stanco di aspettare? alphabet=Alfabeto downloadPdf=Scarica PDF diff --git a/src/main/resources/messages_ja_JP.properties b/src/main/resources/messages_ja_JP.properties index fb794c81..46740e68 100644 --- a/src/main/resources/messages_ja_JP.properties +++ b/src/main/resources/messages_ja_JP.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=保存 close=閉じる filesSelected=選択されたファイル noFavourites=お気に入りはありません +downloadComplete=Download Complete bored=待ち時間が退屈 alphabet=\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8 downloadPdf=PDFをダウンロード @@ -969,3 +970,4 @@ licenses.module=モジュール licenses.version=バージョン licenses.license=ライセンス + diff --git a/src/main/resources/messages_ko_KR.properties b/src/main/resources/messages_ko_KR.properties index a016e6b3..e710eccf 100644 --- a/src/main/resources/messages_ko_KR.properties +++ b/src/main/resources/messages_ko_KR.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=저장 close=닫기 filesSelected=개 파일 선택됨 noFavourites=즐겨찾기 없음 +downloadComplete=Download Complete bored=기다리는 게 지루하신가요? alphabet=\uC54C\uD30C\uBCB3 downloadPdf=PDF 다운로드 diff --git a/src/main/resources/messages_nl_NL.properties b/src/main/resources/messages_nl_NL.properties index fed34234..d261f5a1 100644 --- a/src/main/resources/messages_nl_NL.properties +++ b/src/main/resources/messages_nl_NL.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Opslaan close=Sluiten filesSelected=Bestanden geselecteerd noFavourites=Geen favorieten toegevoegd +downloadComplete=Download Complete bored=Verveeld met wachten? alphabet=Alfabet downloadPdf=Download PDF diff --git a/src/main/resources/messages_pl_PL.properties b/src/main/resources/messages_pl_PL.properties index c385a13f..14a4f979 100644 --- a/src/main/resources/messages_pl_PL.properties +++ b/src/main/resources/messages_pl_PL.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Zapisz close=Zamknij filesSelected=wybrane pliki noFavourites=Nie dodano ulubionych +downloadComplete=Download Complete bored=Znudzony czekaniem? alphabet=Alfabet downloadPdf=Pobierz PDF diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties index 778f1df5..d7115da7 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Salvar close=Fechar filesSelected=arquivos selecionados noFavourites=Nenhum favorito adicionado +downloadComplete=Download Complete bored=Entediado esperando? alphabet=Alfabeto downloadPdf=baixar PDF diff --git a/src/main/resources/messages_ro_RO.properties b/src/main/resources/messages_ro_RO.properties index 4e34c6e3..4c3712e9 100644 --- a/src/main/resources/messages_ro_RO.properties +++ b/src/main/resources/messages_ro_RO.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Salvează close=Închide filesSelected=fișiere selectate noFavourites=Niciun favorit adăugat +downloadComplete=Download Complete bored=Plictisit așteptând? alphabet=Alfabet downloadPdf=Descarcă PDF diff --git a/src/main/resources/messages_ru_RU.properties b/src/main/resources/messages_ru_RU.properties index d386167b..14971b97 100644 --- a/src/main/resources/messages_ru_RU.properties +++ b/src/main/resources/messages_ru_RU.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Сохранить close=Закрыть filesSelected=файлов выбрано noFavourites=Нет избранного +downloadComplete=Download Complete bored=Скучно ждать? alphabet=Алфавит downloadPdf=Скачать PDF diff --git a/src/main/resources/messages_sr_LATN_RS.properties b/src/main/resources/messages_sr_LATN_RS.properties index 1cd0eec3..7c4446f7 100644 --- a/src/main/resources/messages_sr_LATN_RS.properties +++ b/src/main/resources/messages_sr_LATN_RS.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Sačuvaj close=Zatvori filesSelected=odabrani fajlovi noFavourites=Nema dodatih favorita +downloadComplete=Download Complete bored=Da li ti je dosadno dok čekaš? alphabet=Alfabet downloadPdf=Skini PDF diff --git a/src/main/resources/messages_sv_SE.properties b/src/main/resources/messages_sv_SE.properties index 5908b41c..e2199e00 100644 --- a/src/main/resources/messages_sv_SE.properties +++ b/src/main/resources/messages_sv_SE.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Spara close=Stäng filesSelected=filer valda noFavourites=Inga favoriter har lagts till +downloadComplete=Download Complete bored=Utråkad att vänta? alphabet=Alfabet downloadPdf=Ladda ner PDF diff --git a/src/main/resources/messages_tr_TR.properties b/src/main/resources/messages_tr_TR.properties index 618e967e..0dd60789 100644 --- a/src/main/resources/messages_tr_TR.properties +++ b/src/main/resources/messages_tr_TR.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=Kaydet close=Kapat filesSelected=dosya seçildi noFavourites=Favori eklenmedi +downloadComplete=Download Complete bored=Sıkıldınız mı? alphabet=Alfabe downloadPdf=PDF İndir diff --git a/src/main/resources/messages_zh_CN.properties b/src/main/resources/messages_zh_CN.properties index ea994fbb..c79eb73c 100644 --- a/src/main/resources/messages_zh_CN.properties +++ b/src/main/resources/messages_zh_CN.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=保存 close=关闭 filesSelected=选中的文件 noFavourites=没有添加收藏夹 +downloadComplete=Download Complete bored=无聊等待吗? alphabet=字母表 downloadPdf=下载PDF diff --git a/src/main/resources/messages_zh_TW.properties b/src/main/resources/messages_zh_TW.properties index 2122d9f0..fa0e2d35 100644 --- a/src/main/resources/messages_zh_TW.properties +++ b/src/main/resources/messages_zh_TW.properties @@ -1,4 +1,4 @@ -########### +########### # Generic # ########### # the direction that the language is written (ltr=left to right, rtl = right to left) @@ -20,6 +20,7 @@ save=儲存 close=關閉 filesSelected=已選擇的檔案 noFavourites=未新增收藏 +downloadComplete=Download Complete bored=等待時覺得無聊? alphabet=字母表 downloadPdf=下載 PDF diff --git a/src/main/resources/static/js/downloader.js b/src/main/resources/static/js/downloader.js index 9871b69d..4d7fa783 100644 --- a/src/main/resources/static/js/downloader.js +++ b/src/main/resources/static/js/downloader.js @@ -45,6 +45,24 @@ $(document).ready(function () { } clearTimeout(timeoutId); $("#submitBtn").text(originalButtonText); + + // After process finishes, check for boredWaiting and gameDialog open status + const boredWaiting = localStorage.getItem("boredWaiting") || "disabled"; + const gameDialog = document.getElementById('game-container-wrapper'); + if (boredWaiting === "enabled" && gameDialog && gameDialog.open) { + // Display a green banner at the bottom of the screen saying "Download complete" + let downloadCompleteText = "Download Complete"; + if(window.downloadCompleteText){ + downloadCompleteText = window.downloadCompleteText; + } + $("body").append('
      '+ downloadCompleteText + '
      '); + setTimeout(function() { + $("#download-complete-banner").fadeOut("slow", function() { + $(this).remove(); // Remove the banner after fading out + }); + }, 5000); // Banner will fade out after 5 seconds + } + } catch (error) { clearTimeout(timeoutId); handleDownloadError(error); diff --git a/src/main/resources/static/js/game.js b/src/main/resources/static/js/game.js index 6ddc392e..c5162127 100644 --- a/src/main/resources/static/js/game.js +++ b/src/main/resources/static/js/game.js @@ -246,13 +246,10 @@ function initializeGame() { function spawnPdfInterval() { - console.log("spawnPdfInterval"); if (gameOver || paused) { - console.log("spawnPdfInterval 2"); clearTimeout(spawnPdfTimeout); return; } - console.log("spawnPdfInterval 3"); spawnPdf(); let spawnRateReduction = Math.min(level * LEVEL_INCREASE_FACTOR_MS, MAX_SPAWN_RATE_REDUCTION_MS); let spawnRate = BASE_SPAWN_INTERVAL_MS - spawnRateReduction; diff --git a/src/main/resources/templates/fragments/common.html b/src/main/resources/templates/fragments/common.html index 517a902b..2bd60360 100644 --- a/src/main/resources/templates/fragments/common.html +++ b/src/main/resources/templates/fragments/common.html @@ -67,7 +67,7 @@ - -
      +

      Sync browser settings with Account

      @@ -286,4 +280,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/addUsers.html b/src/main/resources/templates/addUsers.html index 397b054a..850beb9e 100644 --- a/src/main/resources/templates/addUsers.html +++ b/src/main/resources/templates/addUsers.html @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@
      -

      +

      @@ -25,7 +25,7 @@ Username Roles - Actions + Actions @@ -76,4 +76,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/auto-split-pdf.html b/src/main/resources/templates/auto-split-pdf.html index 26106b46..914b9d60 100644 --- a/src/main/resources/templates/auto-split-pdf.html +++ b/src/main/resources/templates/auto-split-pdf.html @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@
      -

      +

      @@ -29,8 +29,8 @@
      -

      -

      +

      +

      diff --git a/src/main/resources/templates/change-creds.html b/src/main/resources/templates/change-creds.html index aab874e2..08a3ade7 100644 --- a/src/main/resources/templates/change-creds.html +++ b/src/main/resources/templates/change-creds.html @@ -1,5 +1,5 @@ - + @@ -9,14 +9,14 @@
      -

      +

      User Settings

      -
      +
      Default message if not found @@ -35,7 +35,6 @@

      User!

      -

      Change password

      @@ -76,4 +75,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/book-to-pdf.html b/src/main/resources/templates/convert/book-to-pdf.html index d614af0d..acd40b21 100644 --- a/src/main/resources/templates/convert/book-to-pdf.html +++ b/src/main/resources/templates/convert/book-to-pdf.html @@ -1,5 +1,5 @@ - + @@ -9,14 +9,14 @@
      -

      +

      -
      - +
      +

      @@ -26,4 +26,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/file-to-pdf.html b/src/main/resources/templates/convert/file-to-pdf.html index c0553c26..d8c8b969 100644 --- a/src/main/resources/templates/convert/file-to-pdf.html +++ b/src/main/resources/templates/convert/file-to-pdf.html @@ -1,5 +1,5 @@ - + @@ -9,31 +9,30 @@
      -

      +

      -

      -

      -
      -
      -
      - -
      -

      -

      -

      Microsoft Word: (DOC, DOCX, DOT, DOTX)

      -

      Microsoft Excel: (CSV, XLS, XLSX, XLT, XLTX, SLK, DIF)

      -

      Microsoft PowerPoint: (PPT, PPTX)

      -

      OpenDocument Formats: (ODT, OTT, ODS, OTS, ODP, OTP, ODG, OTG)

      -

      Plain Text: (TXT, TEXT, XML)

      -

      Rich Text Format: (RTF)

      -

      Images: (BMP, GIF, JPEG, PNG, TIF, PBM, PGM, PPM, RAS, XBM, XPM, SVG, SVM, WMF)

      -

      HTML: (HTML)

      -

      Lotus Word Pro: (LWP)

      -

      StarOffice: (SDA, SDC, SDD, SDW, STC, STD, STI, STW, SXD, SXG, SXI, SXW)

      -

      Other: (DBF, FODS, VSD, VOR, VOR3, VOR4, UOP, PCT, PS, PDF)

      - https://help.libreoffice.org/latest/en-US/text/shared/guide/supported_formats.html +

      +

      +
      +
      + +
      +

      +

      +

      Microsoft Word: (DOC, DOCX, DOT, DOTX)

      +

      Microsoft Excel: (CSV, XLS, XLSX, XLT, XLTX, SLK, DIF)

      +

      Microsoft PowerPoint: (PPT, PPTX)

      +

      OpenDocument Formats: (ODT, OTT, ODS, OTS, ODP, OTP, ODG, OTG)

      +

      Plain Text: (TXT, TEXT, XML)

      +

      Rich Text Format: (RTF)

      +

      Images: (BMP, GIF, JPEG, PNG, TIF, PBM, PGM, PPM, RAS, XBM, XPM, SVG, SVM, WMF)

      +

      HTML: (HTML)

      +

      Lotus Word Pro: (LWP)

      +

      StarOffice: (SDA, SDC, SDD, SDW, STC, STD, STI, STW, SXD, SXG, SXI, SXW)

      +

      Other: (DBF, FODS, VSD, VOR, VOR3, VOR4, UOP, PCT, PS, PDF)

      + https://help.libreoffice.org/latest/en-US/text/shared/guide/supported_formats.html
      diff --git a/src/main/resources/templates/convert/html-to-pdf.html b/src/main/resources/templates/convert/html-to-pdf.html index c9a26a6b..3c426917 100644 --- a/src/main/resources/templates/convert/html-to-pdf.html +++ b/src/main/resources/templates/convert/html-to-pdf.html @@ -1,5 +1,5 @@ - + @@ -9,16 +9,16 @@
      -

      +

      -
      +
      - +

      @@ -32,4 +32,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/img-to-pdf.html b/src/main/resources/templates/convert/img-to-pdf.html index 6d68fdec..a8633ad1 100644 --- a/src/main/resources/templates/convert/img-to-pdf.html +++ b/src/main/resources/templates/convert/img-to-pdf.html @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@
      -

      +

      @@ -46,7 +46,7 @@
      -

      +

      @@ -79,4 +79,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/markdown-to-pdf.html b/src/main/resources/templates/convert/markdown-to-pdf.html index 8df3ad17..7a51a29c 100644 --- a/src/main/resources/templates/convert/markdown-to-pdf.html +++ b/src/main/resources/templates/convert/markdown-to-pdf.html @@ -1,5 +1,5 @@ - + @@ -9,14 +9,13 @@
      -

      +

      -

      @@ -28,4 +27,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/pdf-to-book.html b/src/main/resources/templates/convert/pdf-to-book.html index db9b4692..33fbd2e1 100644 --- a/src/main/resources/templates/convert/pdf-to-book.html +++ b/src/main/resources/templates/convert/pdf-to-book.html @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@
      -

      +

      @@ -42,4 +42,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/pdf-to-csv.html b/src/main/resources/templates/convert/pdf-to-csv.html index 16da051e..9fba9430 100644 --- a/src/main/resources/templates/convert/pdf-to-csv.html +++ b/src/main/resources/templates/convert/pdf-to-csv.html @@ -1,5 +1,5 @@ - + @@ -8,13 +8,13 @@
      -

      +

      - +
      @@ -23,8 +23,8 @@
      @@ -106,9 +106,9 @@ let typedArray = new Uint8Array(reader.result); pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'; pdfjsLib.getDocument(typedArray).promise.then(function(pdf) { - pdfDoc = pdf; - totalPages = pdf.numPages; - renderPage(currentPage); + pdfDoc = pdf; + totalPages = pdf.numPages; + renderPage(currentPage); }); pageId.value = currentPage; }; @@ -140,4 +140,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/pdf-to-html.html b/src/main/resources/templates/convert/pdf-to-html.html index f2e914f9..c9256805 100644 --- a/src/main/resources/templates/convert/pdf-to-html.html +++ b/src/main/resources/templates/convert/pdf-to-html.html @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@
      -

      +

      @@ -27,4 +27,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/pdf-to-img.html b/src/main/resources/templates/convert/pdf-to-img.html index bcf3e8b3..039c52e0 100644 --- a/src/main/resources/templates/convert/pdf-to-img.html +++ b/src/main/resources/templates/convert/pdf-to-img.html @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@
      -

      +

      @@ -55,4 +55,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/pdf-to-pdfa.html b/src/main/resources/templates/convert/pdf-to-pdfa.html index 866449f1..e9b8ac88 100644 --- a/src/main/resources/templates/convert/pdf-to-pdfa.html +++ b/src/main/resources/templates/convert/pdf-to-pdfa.html @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@
      -

      +

      diff --git a/src/main/resources/templates/convert/pdf-to-presentation.html b/src/main/resources/templates/convert/pdf-to-presentation.html index 408ff151..48d27d24 100644 --- a/src/main/resources/templates/convert/pdf-to-presentation.html +++ b/src/main/resources/templates/convert/pdf-to-presentation.html @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@
      -

      +

      @@ -35,4 +35,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/pdf-to-text.html b/src/main/resources/templates/convert/pdf-to-text.html index d1616589..9877be8f 100644 --- a/src/main/resources/templates/convert/pdf-to-text.html +++ b/src/main/resources/templates/convert/pdf-to-text.html @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@
      -

      +

      @@ -34,5 +34,4 @@
      - - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/pdf-to-word.html b/src/main/resources/templates/convert/pdf-to-word.html index 6fd76f4e..fbbbf45d 100644 --- a/src/main/resources/templates/convert/pdf-to-word.html +++ b/src/main/resources/templates/convert/pdf-to-word.html @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@
      -

      +

      @@ -35,7 +35,4 @@
      - - - - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/pdf-to-xml.html b/src/main/resources/templates/convert/pdf-to-xml.html index a7d020b0..cad43da2 100644 --- a/src/main/resources/templates/convert/pdf-to-xml.html +++ b/src/main/resources/templates/convert/pdf-to-xml.html @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@
      -

      +

      @@ -27,4 +27,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/convert/url-to-pdf.html b/src/main/resources/templates/convert/url-to-pdf.html index 94f0bfa5..714bd1c4 100644 --- a/src/main/resources/templates/convert/url-to-pdf.html +++ b/src/main/resources/templates/convert/url-to-pdf.html @@ -1,5 +1,5 @@ - + @@ -9,13 +9,13 @@
      -

      +

      - +
      @@ -27,4 +27,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/crop.html b/src/main/resources/templates/crop.html index 05de3516..f2049572 100644 --- a/src/main/resources/templates/crop.html +++ b/src/main/resources/templates/crop.html @@ -1,5 +1,5 @@ - + @@ -8,7 +8,7 @@
      -

      +

      @@ -22,114 +22,117 @@
      - - -
      - + + overlayCanvas.addEventListener('mousedown', function(e) { + // Clear previously drawn rectangle on the main canvas + context.clearRect(0, 0, pdfCanvas.width, pdfCanvas.height); + renderPage(currentPage); // Re-render the PDF + + // Clear the overlay canvas to ensure old drawings are removed + overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); + + startX = e.offsetX; + startY = e.offsetY; + isDrawing = true; + }); + + overlayCanvas.addEventListener('mousemove', function(e) { + if (!isDrawing) return; + overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); // Clear previous rectangle + + rectWidth = e.offsetX - startX; + rectHeight = e.offsetY - startY; + overlayContext.strokeStyle = 'red'; + overlayContext.strokeRect(startX, startY, rectWidth, rectHeight); + }); + + overlayCanvas.addEventListener('mouseup', function(e) { + isDrawing = false; + + rectWidth = e.offsetX - startX; + rectHeight = e.offsetY - startY; + + let flippedY = pdfCanvas.height - e.offsetY; + + xInput.value = startX; + yInput.value = flippedY; + widthInput.value = rectWidth; + heightInput.value = rectHeight; + + // Draw the final rectangle on the main canvas + context.strokeStyle = 'red'; + context.strokeRect(startX, startY, rectWidth, rectHeight); + + overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); // Clear the overlay + }); + + function renderPage(pageNumber) { + pdfDoc.getPage(pageNumber).then(function(page) { + let viewport = page.getViewport({ scale: 1.0 }); + pdfCanvas.width = viewport.width; + pdfCanvas.height = viewport.height; + + overlayCanvas.width = viewport.width; // Match overlay canvas size with PDF canvas + overlayCanvas.height = viewport.height; + + let renderContext = { canvasContext: context, viewport: viewport }; + page.render(renderContext); + pdfCanvas.classList.add("shadow-canvas"); + }); + } + +
      - + \ No newline at end of file diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html index 954bcd7d..57f2f4ad 100644 --- a/src/main/resources/templates/error.html +++ b/src/main/resources/templates/error.html @@ -1,5 +1,5 @@ - + @@ -29,11 +29,11 @@ Submit a ticket on GitHub Join our Discord server
      - Go back to homepage + Go back to homepage
      - + \ No newline at end of file diff --git a/src/main/resources/templates/extract-page.html b/src/main/resources/templates/extract-page.html index 4bbd8b22..c10485b8 100644 --- a/src/main/resources/templates/extract-page.html +++ b/src/main/resources/templates/extract-page.html @@ -1,5 +1,5 @@ - + @@ -8,7 +8,7 @@
      -

      +

      diff --git a/src/main/resources/templates/fragments/card.html b/src/main/resources/templates/fragments/card.html index 6fa05163..3f5517d6 100644 --- a/src/main/resources/templates/fragments/card.html +++ b/src/main/resources/templates/fragments/card.html @@ -1,7 +1,7 @@ - - - + + -
      diff --git a/src/main/resources/templates/fragments/footer.html b/src/main/resources/templates/fragments/footer.html index e382553b..3d32604d 100644 --- a/src/main/resources/templates/fragments/footer.html +++ b/src/main/resources/templates/fragments/footer.html @@ -1,19 +1,19 @@ diff --git a/src/main/resources/templates/fragments/navbar.html b/src/main/resources/templates/fragments/navbar.html index f7d01c0e..926f494d 100644 --- a/src/main/resources/templates/fragments/navbar.html +++ b/src/main/resources/templates/fragments/navbar.html @@ -31,11 +31,11 @@
      +
      \ No newline at end of file diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index 8ddb7dea..ed1c6a18 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -1,5 +1,5 @@ - + @@ -21,7 +21,7 @@

      - +
      @@ -75,7 +75,6 @@
      -
      @@ -102,4 +101,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/licenses.html b/src/main/resources/templates/licenses.html index 9d7cd250..f9d6c641 100644 --- a/src/main/resources/templates/licenses.html +++ b/src/main/resources/templates/licenses.html @@ -1,5 +1,5 @@ - + @@ -8,7 +8,7 @@
      -

      +

      @@ -23,15 +23,12 @@ - + - + -
      @@ -39,4 +36,4 @@
      - + \ No newline at end of file diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html index 19a4b728..02c9cfed 100644 --- a/src/main/resources/templates/login.html +++ b/src/main/resources/templates/login.html @@ -1,5 +1,5 @@ - + @@ -52,7 +52,7 @@ document.addEventListener('DOMContentLoaded', function() { - const defaultLocale = document.documentElement.language || 'en_GB'; + const defaultLocale = document.documentElement.getAttribute('language') || 'en_GB'; const storedLocale = localStorage.getItem('languageCode') || defaultLocale; const currentURL = new URL(window.location.href); @@ -61,10 +61,10 @@ if (defaultLocale !== storedLocale && currentLangParam !== storedLocale) { - urlParams.set('lang', storedLocale); - currentURL.search = urlParams.toString(); - window.location.href = currentURL.toString(); - return; + urlParams.set('lang', storedLocale); + currentURL.search = urlParams.toString(); + window.location.href = currentURL.toString(); + return; } const dropdown = document.getElementById('languageDropdown'); @@ -72,17 +72,17 @@ let activeItem; for (let i = 0; i < dropdownItems.length; i++) { - const item = dropdownItems[i]; - item.classList.remove('active'); - if (item.dataset.bsLanguageCode === storedLocale) { - item.classList.add('active'); - activeItem = item; - } - item.addEventListener('click', handleDropdownItemClick); + const item = dropdownItems[i]; + item.classList.remove('active'); + if (item.dataset.bsLanguageCode === storedLocale) { + item.classList.add('active'); + activeItem = item; + } + item.addEventListener('click', handleDropdownItemClick); } if (activeItem) { - dropdown.innerHTML = activeItem.innerHTML; // This will set the dropdown button's content to the active language's flag and name + dropdown.innerHTML = activeItem.innerHTML; // This will set the dropdown button's content to the active language's flag and name } // Additional functionality that was in your provided code: @@ -91,7 +91,7 @@ const dropdownMenu = element.querySelector(".dropdown-menu"); if (dropdownMenu.id !== 'favoritesDropdown' && dropdownMenu.children.length <= 2 && dropdownMenu.querySelectorAll("hr.dropdown-divider").length === dropdownMenu.children.length) { if (element.previousElementSibling && element.previousElementSibling.classList.contains('nav-item') && element.previousElementSibling.classList.contains('nav-item-separator')) { - element.previousElementSibling.remove(); + element.previousElementSibling.remove(); } element.remove(); } @@ -142,23 +142,25 @@

      Please sign in

      - + +
      - + +
      - + +