From e4a76e96af4fd2bedb1bced2b6cb05b7fe580887 Mon Sep 17 00:00:00 2001 From: Ludy Date: Fri, 16 Feb 2024 22:49:06 +0100 Subject: [PATCH] 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 614dd8a0f..a5b3d79e7 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 000000000..957fcd9f5 --- /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 000000000..5a735b425 --- /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 6f914fc3d..8ddbf0525 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 e75a0d06d..14c3befe4 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 000000000..0477d7e0c --- /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 69a940b37..11b111ab1 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 2cd2c682a..e8f129795 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 000000000..f6cf093d7 --- /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 01b93e947..5b9f27d27 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 934074ca7..8d631bfd1 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 fe1846373..d975dd79f 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 231895d65..397c0c548 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 000000000..79abdc34b --- /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 08efbf4c0..af84b0d57 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 000000000..743ee6063 --- /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 866e2e8cd..dc3c76571 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 000000000..9ed84f2b7 --- /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 5bb99a5ea..f46c44a6b 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 98c29dbe6..ff6800365 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 000000000..9468333b1 --- /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 2c58adf51..921423a5c 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 000000000..7c5d388db --- /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 000000000..c6ae3374b --- /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 000000000..7520c10e5 --- /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 000000000..9fed61782 --- /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 f6609de4e..cf0486508 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 d3c622662..cb119a8ad 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 8971f98e6..842e9df0e 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 2263e5406..bff4c3d49 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 9d151407f..727a854f7 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 08c6f1832..dbecd013f 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 610ae7235..89ad1ad90 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 1bfb9374b..199bab0f8 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 6400d5cfe..e17524d54 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 6fb433875..8ac2ef443 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 4cc18f12a..af67da487 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 370903904..447938847 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 e8e60d4f1..4936fa6bc 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 2481adf17..004412d49 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 6f7cd22e9..b72df3bbe 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 b77d21213..2fae22d31 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 1823cff48..76911a25a 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 ecaf64edf..77455c06b 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 1bbcfed0a..2d20fd7b2 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 e77c4d01b..fcfd3df51 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 674b54b77..2329f9983 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 272b555b9..77a55a3f1 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 bd97d2b63..2aa85b32b 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 14a8aff0e..ab0ad4061 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 1ce5726f7..17e79d57d 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 b39da2f1c..9b7f4df97 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 ff3eb5597..0cf3306d6 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 304216b91..e4d213d81 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 f5b86b679..4709e40bd 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 67facbb35..94229ccfc 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 774c2dc81..3949688f0 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 f0d17e6e8..111846063 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 60478409e..4de9e0f60 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 4606d2b51..d0266aac4 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 a136c5cf7..e8ef94029 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 463e1a9c6..d21156f08 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 7360e6318..b2347f024 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 52bf2e663..610345785 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 5b0d5cf14..1b75a0785 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 a08c202bd..f0a4a44a9 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 8ad6e94a6..cc6b7dcbf 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 8ed0d9a83..74e6f314b 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 b26a97fe9..701220c17 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 c74bd5d5e..680443859 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 f0d2186f8..825cfbec5 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 90e654f7a..d3cbecb6b 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 77cc74963..a14e13d25 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 1d8193cd4..6fa05163f 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 633810ef5..78f229c67 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 1bc790318..d9865b639 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 d97d88d96..3638391e9 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 ae531a8f8..1a0f96ee9 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 e484a72d1..bd7104c26 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 23effdd0d..2b28a7340 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 da6e6c22f..d3f79ade3 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 0295acacb..62712dce6 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 6affa6bf6..e2c8de1cb 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 ffe08a310..c91940052 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 c991a6c86..ef4955777 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 82f7313c2..016cc9731 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 e813e6806..caf4b5495 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 430e343bf..94c616cc4 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 9aabdec44..4d9b00461 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 cbd46be4e..40623fac7 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 b2c8e3584..99ce01db6 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 10d5d148f..2b7e4d5ac 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 0614a2c23..0311fe0ed 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 1578de36b..5fa2125a4 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 646f7dc00..5f77806ba 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 d49b7f837..ef618e0c5 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 cab73486f..7e17c9137 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 4c033e356..5f2ff037d 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 6c26ace5f..c3c56e4c9 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 d70c52ff9..0489f1a4b 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 1449fc2e9..e540e7dc3 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 72cb280d2..920ed4ab3 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 1165f8627..22b52ba69 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 5c09720f2..b495bcb2b 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 f61dcabf1..297c9ba17 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 791b5da0e..bec2e3163 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 20148355d..bfadb5a75 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 cf0cd3b0b..9c76bafa9 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 317c4e5ed..00b425d4f 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 fe0c4a3c4..950d6b1fa 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 a87a1bd7a..64b2fa7e4 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 8d393cba9..3d0f4deb8 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 48d39e417..57a2d31d9 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 0b6f9b52c..f5b58ef9c 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 949009778..dc8b54761 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 872dc323c..c6beffaca 100644 --- a/src/main/resources/templates/split-pdfs.html +++ b/src/main/resources/templates/split-pdfs.html @@ -1,43 +1,42 @@ - - - - - - + + + + +
      -
      -
      -

      -
      -
      -
      -

      -

      -

      -

      -

      -

      -

      -

      -

      +
      + +

      +
      +
      +
      +

      +

      +

      +

      +

      +

      +

      +

      +

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