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

Drop files anywhere to upload

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

Drop files anywhere to upload

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

Drop files anywhere to upload

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

Drop files anywhere to upload

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

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

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

-
-
-
+
+ +

+
+
+
- -

User Settings

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

User!

- - - -

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

Change Password?

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

Sync browser settings with Account

-
-

Settings Comparison:

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

User Settings

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

User!

+ + + + +

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

Change Password?

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

Sync browser settings with Account

+
+

Settings Comparison:

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

-
-
-
+
+ +

+
+
+
- -

Admin User Control Settings

+ +

Admin User Control Settings

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

Add New User

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

Add New User

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

-
-
-
-

- -

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

-
-
- - -
-

-

- -
-
+
+ +

+
+
+
+

+ +

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

+
+
+ +
+

+

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

-
-
-
- - -

User Settings

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

User!

- - - -

-

Change Username and password

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

+
+
+
+ +

User Settings

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

User!

+ +

+

Change Username and password

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

-
-
-
-

-
-
-
- -
-

-

-
-
+
+ +

+
+
+
+

+
+
+
+ +
+

+

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

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

-
-
-
-

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

-

-
+
+ +

+
+
+
+

+
+
+
+ +
+
+ +
+

+

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

-
-
-
-

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

- - - -
-
+
+ +

+
+
+
+

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

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

-
-
-
-

-
-
-
- - -
-

-

-
-
+
+ +

+
+
+
+

+
+
+
+ +
+

+

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

-
-
-
-

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

-

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

+
+
+
+

+
+
+
+ + +
+
+ +
+

+

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

+ +
+
+ +

-
-
-

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

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

-
-
-
-

-
-
-
- - -
-

-
-
+
+ +

+
+
+
+

+
+
+
+ +
+

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

-
-
-
-

-

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

+
+
+
+

+

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

-
-
-
-

-

Currently doesn't work for multiple inputs at once

-
-
-
- -
-

-
-
+
+ +

+
+
+
+

+

Currently doesn't work for multiple inputs at once

+
+
+
+ +
+

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

-
-
-
-

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

-
+
+ +

+
+
+
+

+
+
+
+ +
+
+ +
+

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

-
-
-
-

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

-
+
+ +

+
+
+
+

+
+
+
+ +
+
+ +
+

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

-
-
-
-

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

-
+
+ +

+
+
+
+

+
+
+
+ +
+
+ +
+

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

-
-
-
-

-
-
-
- - -
-

-
-
+
+ +

+
+
+
+

+
+
+
+ +
+

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

-
-
-
-

-
- -
- - -
-

-
-
+
+ +

+
+
+
+

+
+ +
+ +
+

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

-
-
-
-

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

+
+
+
+

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

Oops!

-

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

-

Something went wrong

- -
-

Need help / Found a issue?

-

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

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

Oops!

+

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

+

+ Something went wrong +

+
+

Need help / Found a issue?

+

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

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

-
-
-
-

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

+
+
+
+

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

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

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

-
-
-
-

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

    +
    +
    +
    +

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

      -
      -
      -
      -

      +
      + +

      +
      +
      +
      +

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

      +
      +
      +
      +

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

      -
      -
      -
      +
      +
      + +

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

      -
      -
      -
      -

      -
      -
      -
      - -
      -

      -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      + +
      +

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

      -
      -
      -
      -

      -
      -
      -
      - -
      -
      -
      +
      + +

      +
      +
      +
      +

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

      -
      -
      -
      -

      - -
      -
      -

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

      +
      +
      +
      +

      +
      +
      +

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

      -
      -
      -
      -

      - -
      -
      - - - -
      -
      -

      -
      -
      -
      -

      -
      -
      -
      - - -
      +
      + +

      +
      +
      +
      +

      +
      +
      + +
      +
      +

      +
      +
      +

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

      -
      -
      -
      -

      -
      -
      -
      -
      -

      - - -
      -
      - -
      -
      -

      - - -
      -
      - -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      +
      +

      + + +
      +
      +
      +

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      -

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

      +
      +
      +
      +

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

      +

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

      -
      -
      -
      -

      -
      -
      -
      -
      - -
      -
      +
      + +

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -
      -

      -
      -
      - -
      -
      -
      +
      + +

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -

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

      +
      +
      +

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

      -
      -
      -
      +
      + +

      +
      +
      +
      +

      +
      +
      +
      - -

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

      -
      -
      -
      -

      +
      + +

      +
      +
      +
      +

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

      -
      -
      -
      -

      -
      -
      - -
      -
      -
      +
      + +

      +
      +
      +
      +

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

      +
      +
      +

      +

      +
      +
      + + +
      -

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

      -

      -
      -
      - - +

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

      -
      +

      Current Limitations

      -
      -
      - -
      -
      -
      -
      -
      - +

      User Guide for Local Directory Scanning and File Processing

      -
      -
      -
      +

      Setting Up Watched Folders:

      +

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

      +

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

      +

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

      +

      Configuring Processing with JSON Files:

      +

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

      +

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

      -

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

      -

      Current Limitations

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

      Automatic Scanning and Processing:

      +

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

      +

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

      -

      How it Works Notes

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

      Processing Steps:

      +

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

      +

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

      -

      How to use pre-load configs in web UI

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

      Results and Output:

      +

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

      +

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

      -

      Todo

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

      Completion and Cleanup:

      +

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

      +

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

      +

      Error Handling:

      +

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

      -

      User Guide for Local Directory Scanning and File - Processing

      +

      User Interaction:

      +

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

      +

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

      -

      Setting Up Watched Folders:

      -

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

      -

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

      -

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

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

      +
      +
      +
      +

      - - - -
      -
      -
      -

      -
      -
      -
      -

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

      -
      -
      -
      -

      +
      + +

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -
      -

      -
      -
      - -
      + +
      +
      + +

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -
      -

      -

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

      +
      +
      +
      +

      +

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -
      -

      +
      + +

      +
      +
      +
      +

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

      -
      -
      -
      -

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

      +
      +
      +
      +

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

      -
      -
      -
      -

      -
      -
      +
      + +

      +
      +
      +
      +

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

      -
      -
      -
      -

      -

      -

      -

      -

      -

      -

      -

      -

      +
      + +

      +
      +
      +
      +

      +

      +

      +

      +

      +

      +

      +

      +

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