1
0
mirror of https://github.com/Stirling-Tools/Stirling-PDF.git synced 2024-11-16 12:20:12 +01:00

HTML, CSS, JS and JAVA corrections (#810)

* CSS corrections

* HTML corrections

* JS corrections

* JAVA corrections

* remove tab

* CSS corrections 2

* JS corrections 2

* back to the roots

* max-linie 127

* add slash hr|br

* return bootstrap-icons.css

* return bootstrap-icons.min.css

* return bootstrap.min.css

* Update bootstrap-icons.css

* Update bootstrap-icons.min.css

* Update bootstrap-icons.min.css

* Update bootstrap.min.css

* CSS corrections

* HTML corrections

* JS corrections

* JAVA corrections

* remove tab

* CSS corrections 2

* JS corrections 2

* back to the roots

* max-linie 127

* add slash hr|br

* return bootstrap-icons.css

* Update bootstrap-icons.css

* Bootstrap CSS

* Update prism.css
This commit is contained in:
Ludy 2024-02-16 22:49:06 +01:00 committed by GitHub
parent 68f582bcb9
commit e4a76e96af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
124 changed files with 9025 additions and 9424 deletions

View File

@ -33,6 +33,8 @@ public class AccountWebController {
return "redirect:/"; return "redirect:/";
} }
model.addAttribute("currentPage", "login");
if (request.getParameter("error") != null) { if (request.getParameter("error") != null) {
model.addAttribute("error", request.getParameter("error")); model.addAttribute("error", request.getParameter("error"));
@ -112,6 +114,7 @@ public class AccountWebController {
model.addAttribute("role", user.get().getRolesAsString()); model.addAttribute("role", user.get().getRolesAsString());
model.addAttribute("settings", settingsJson); model.addAttribute("settings", settingsJson);
model.addAttribute("changeCredsFlag", user.get().isFirstLogin()); model.addAttribute("changeCredsFlag", user.get().isFirstLogin());
model.addAttribute("currentPage", "account");
} }
} else { } else {
return "redirect:/"; return "redirect:/";

View File

@ -0,0 +1,4 @@
.buttons-container {
margin-top: 20px;
text-align: center;
}

View File

@ -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;
}

View File

@ -1,5 +1,7 @@
/* Dark Mode Styles */ /* Dark Mode Styles */
body, select, textarea { body,
select,
textarea {
--body-background-color: 51, 51, 51; --body-background-color: 51, 51, 51;
--base-font-color: 255, 255, 255; --base-font-color: 255, 255, 255;
background-color: rgb(var(--body-background-color)) !important; background-color: rgb(var(--body-background-color)) !important;
@ -53,7 +55,8 @@ table thead {
background-color: #333 !important; background-color: #333 !important;
border: 1px solid #444; border: 1px solid #444;
} }
table th, table td { table th,
table td {
border: 1px solid #444 !important; border: 1px solid #444 !important;
color: white; color: white;
} }
@ -120,16 +123,19 @@ hr {
color: #ffffff; color: #ffffff;
} }
#global-buttons-container input:disabled::-webkit-input-placeholder { /* WebKit browsers */ #global-buttons-container input:disabled::-webkit-input-placeholder {
color: #6E6865; /* WebKit browsers */
color: #6e6865;
} }
#global-buttons-container input:disabled:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ #global-buttons-container input:disabled:-moz-placeholder {
color: #6E6865; /* Mozilla Firefox 4 to 18 */
color: #6e6865;
} }
#global-buttons-container input:disabled::-moz-placeholder { /* Mozilla Firefox 19+ */ #global-buttons-container input:disabled::-moz-placeholder {
color: #6E6865; /* Mozilla Firefox 19+ */
color: #6e6865;
} }
#global-buttons-container input:disabled:-ms-input-placeholder { /* Internet Explorer 10+ */ #global-buttons-container input:disabled:-ms-input-placeholder {
color: #6E6865; /* Internet Explorer 10+ */
color: #6e6865;
} }

View File

@ -36,12 +36,12 @@
visibility: hidden !important; visibility: hidden !important;
} }
html[lang-direction=ltr] .drag-manager_draghover img { html[lang-direction="ltr"] .drag-manager_draghover img {
left: calc(50% + 62.5px) !important; left: calc(50% + 62.5px) !important;
} }
html[lang-direction=rtl] .drag-manager_draghover img { html[lang-direction="rtl"] .drag-manager_draghover img {
left: 125px left: 125px;
} }
.drag-manager_dragging-container .hide-on-drag { .drag-manager_dragging-container .hide-on-drag {
@ -51,9 +51,9 @@ html[lang-direction=rtl] .drag-manager_draghover img {
.drag-manager_endpoint { .drag-manager_endpoint {
width: 80px; width: 80px;
height: 100%; height: 100%;
background-color: #FFFFFF10; background-color: #ffffff10;
transition: width 0.1s; transition: width 0.1s;
animation: end-drop-expand .3s ease; animation: end-drop-expand 0.3s ease;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;

View File

@ -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;
}

View File

@ -28,7 +28,7 @@
} }
#helpModal .feature-card { #helpModal .feature-card {
border: 1px solid rgba(0, 0, 0, .125); border: 1px solid rgba(0, 0, 0, 0.125);
border-radius: 0.25rem; border-radius: 0.25rem;
padding: 1.25rem; padding: 1.25rem;
display: flex; display: flex;
@ -61,11 +61,12 @@
flex-wrap: wrap; flex-wrap: wrap;
} }
#github-button, #discord-button { #github-button,
#discord-button {
display: inline-block; display: inline-block;
padding: 1rem 2rem; padding: 1rem 2rem;
margin: 1rem; margin: 1rem;
background-color: #008CBA; background-color: #008cba;
color: #fff; color: #fff;
font-size: 1.2rem; font-size: 1.2rem;
text-align: center; text-align: center;
@ -74,7 +75,9 @@
transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out;
} }
#github-button:hover, #discord-button:hover, #home-button:hover { #github-button:hover,
#discord-button:hover,
#home-button:hover {
background-color: #005b7f; background-color: #005b7f;
} }
@ -83,7 +86,7 @@
width: 200px; width: 200px;
height: 50px; height: 50px;
margin: 2em auto; margin: 2em auto;
background-color: #008CBA; background-color: #008cba;
color: white; color: white;
text-align: center; text-align: center;
line-height: 50px; line-height: 50px;

View File

@ -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 */
}

View File

@ -9,7 +9,9 @@
border: 2px solid black; /* Add border */ border: 2px solid black; /* Add border */
} }
.pdf, .player, .projectile { .pdf,
.player,
.projectile {
position: absolute; position: absolute;
} }
.pdf { .pdf {
@ -25,7 +27,10 @@
width: 5px; width: 5px;
height: 10px; height: 10px;
} }
#score, #level, #lives, #high-score { #score,
#level,
#lives,
#high-score {
color: black; color: black;
font-family: sans-serif; font-family: sans-serif;
position: absolute; position: absolute;

View File

@ -25,10 +25,10 @@
margin-right: auto; margin-right: auto;
}*/ }*/
html[lang-direction=ltr] * { html[lang-direction="ltr"] * {
direction: ltr; direction: ltr;
} }
html[lang-direction=rtl] * { html[lang-direction="rtl"] * {
direction: rtl; direction: rtl;
text-align: right; text-align: right;
} }

View File

@ -1,5 +1,5 @@
#searchBar { #searchBar {
background-image: url('../images/search.svg'); background-image: url("../images/search.svg");
background-position: 16px 16px; background-position: 16px 16px;
background-repeat: no-repeat; background-repeat: no-repeat;
width: 100%; width: 100%;
@ -7,8 +7,6 @@
margin-bottom: 12px; margin-bottom: 12px;
padding: 12px 20px 12px 40px; padding: 12px 20px 12px 40px;
border: 1px solid #ddd; border: 1px solid #ddd;
} }
.dark-mode-search { .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; 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;
@ -17,8 +15,6 @@
border-color: #343a40 !important; border-color: #343a40 !important;
} }
.features-container { .features-container {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(15rem, 3fr)); grid-template-columns: repeat(auto-fill, minmax(15rem, 3fr));
@ -26,14 +22,16 @@
} }
.feature-card { .feature-card {
border: 2px solid rgba(0, 0, 0, .25); border: 2px solid rgba(0, 0, 0, 0.25);
border-radius: 0.25rem; border-radius: 0.25rem;
padding: 1.25rem; padding: 1.25rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
background: rgba(13, 110, 253, 0.05); background: rgba(13, 110, 253, 0.05);
transition: transform 0.3s, border 0.3s; transition:
transform 0.3s,
border 0.3s;
transform-origin: center center; transform-origin: center center;
outline: 2px solid transparent; outline: 2px solid transparent;
} }
@ -52,7 +50,7 @@
} }
.feature-card:hover { .feature-card:hover {
outline: 1px solid rgba(0, 0, 0, .5); outline: 1px solid rgba(0, 0, 0, 0.5);
cursor: pointer; cursor: pointer;
transform: scale(1.1); transform: scale(1.1);
} }

View File

@ -1,4 +1,3 @@
#image-highlighter { #image-highlighter {
position: fixed; position: fixed;
display: flex; display: flex;
@ -8,14 +7,18 @@
visibility: hidden; visibility: hidden;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
transition: visbility 0.1s linear, background-color 0.1s linear; transition:
visbility 0.1s linear,
background-color 0.1s linear;
} }
#image-highlighter > * { #image-highlighter > * {
max-width: 80vw; max-width: 80vw;
max-height: 80vh; max-height: 80vh;
animation: image-highlight .1s linear; animation: image-highlight 0.1s linear;
transition: transform .1s linear, opacity .1s linear; transition:
transform 0.1s linear,
opacity 0.1s linear;
} }
#image-highlighter > *.remove { #image-highlighter > *.remove {

View File

@ -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 */
}

View File

@ -4,7 +4,6 @@ body {
--base-font-color: 33, 37, 41; --base-font-color: 33, 37, 41;
} }
#global-buttons-container input { #global-buttons-container input {
background-color: #ffffff; background-color: #ffffff;
/*caret-color: #ffffff;*/ /*caret-color: #ffffff;*/

View File

@ -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;
}

View File

@ -25,5 +25,4 @@
.move-down span { .move-down span {
font-weight: bold; font-weight: bold;
font-size: 1.2em; font-size: 1.2em;
} }

View File

@ -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;
}

View File

@ -1,8 +1,13 @@
#navbarSearch { #navbarSearch {
top: 100%; top: 100%;
right: 0; right: 0;
transition: all 0.3s;
max-height: 0;
overflow: hidden;
}
#navbarSearch.show {
max-height: 300px; /* Adjust this to your desired max height */
} }
#searchForm { #searchForm {
@ -14,6 +19,8 @@
max-height: 200px; /* Adjust this value as needed */ max-height: 200px; /* Adjust this value as needed */
overflow-y: auto; overflow-y: auto;
width: 100%; width: 100%;
max-width: 300px; /* Adjust to your preferred width */
transition: height 0.3s ease; /* Smooth height transition */
} }
#searchResults .dropdown-item { #searchResults .dropdown-item {
@ -34,7 +41,36 @@
text-overflow: ellipsis; /* Add ellipsis for long text */ 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 { .main-icon {
width: 36px; width: 36px;
@ -64,7 +100,7 @@
} }
.nav-item-separator::before { .nav-item-separator::before {
content: ''; content: "";
position: absolute; position: absolute;
left: 0; left: 0;
top: 10%; /* Adjust the top and bottom margins as needed */ top: 10%; /* Adjust the top and bottom margins as needed */

View File

@ -1,4 +1,3 @@
.pdf-actions_button-container { .pdf-actions_button-container {
z-index: 2; z-index: 2;
display: flex; display: flex;
@ -46,11 +45,11 @@
right: -20px; right: -20px;
} }
html[lang-direction=ltr] .pdf-actions_insert-file-button-container.right { html[lang-direction="ltr"] .pdf-actions_insert-file-button-container.right {
display: none; display: none;
} }
html[lang-direction=rtl] .pdf-actions_insert-file-button-container.left { html[lang-direction="rtl"] .pdf-actions_insert-file-button-container.left {
display: none; display: none;
} }
@ -64,12 +63,11 @@ html[lang-direction=rtl] .pdf-actions_insert-file-button-container.left {
translate: 0 -50%; translate: 0 -50%;
} }
html[lang-direction=ltr] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.right { html[lang-direction="ltr"] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.right {
display: block; display: block;
} }
html[lang-direction="rtl"] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.left {
html[lang-direction=rtl] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.left {
display: block; display: block;
} }

View File

@ -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 */
}

View File

@ -1,37 +1,113 @@
/* Rainbow Mode Styles */ /* Rainbow Mode Styles */
body { 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%); 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; color: #fff !important;
--body-background-color: 255, 255, 255; --body-background-color: 255, 255, 255;
--base-font-color: 33, 37, 41; --base-font-color: 33, 37, 41;
} }
.dark-card { .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; 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; color: white !important;
} }
.jumbotron { .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%); 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; color: #fff !important;
} }
.list-group { .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; 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; color: fff !important;
} }
.list-group-item { .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; 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; color: fff !important;
} }
#support-section { #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 { #pages-container-wrapper {
--background-color: rgba(255, 255, 255, 0.046) !important; --background-color: rgba(255, 255, 255, 0.046) !important;
--scroll-bar-color: #4c4c4c !important; --scroll-bar-color: #4c4c4c !important;
--scroll-bar-thumb: #d3d3d3 !important; --scroll-bar-thumb: #d3d3d3 !important;
--scroll-bar-thumb-hover: #ffffff !important; --scroll-bar-thumb-hover: #ffffff !important;
} }

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */
}

View File

@ -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;
}

View File

@ -1,6 +1,4 @@
.tab-group { .tab-group {
} }
.tab-container { .tab-container {

View File

@ -1,5 +1,5 @@
var toggleCount = 0 var toggleCount = 0;
var lastToggleTime = Date.now() var lastToggleTime = Date.now();
var elements = { var elements = {
lightModeStyles: null, lightModeStyles: null,
@ -11,18 +11,18 @@ var elements = {
navbar: null, navbar: null,
navIcons: null, navIcons: null,
navDropdownMenus: null, navDropdownMenus: null,
} };
function getElements() { function getElements() {
elements.lightModeStyles = document.getElementById("light-mode-styles") elements.lightModeStyles = document.getElementById("light-mode-styles");
elements.darkModeStyles = document.getElementById("dark-mode-styles") elements.darkModeStyles = document.getElementById("dark-mode-styles");
elements.rainbowModeStyles = document.getElementById("rainbow-mode-styles") elements.rainbowModeStyles = document.getElementById("rainbow-mode-styles");
elements.darkModeIcon = document.getElementById("dark-mode-icon") elements.darkModeIcon = document.getElementById("dark-mode-icon");
elements.searchBar = document.getElementById("searchBar") elements.searchBar = document.getElementById("searchBar");
elements.formControls = document.querySelectorAll(".form-control") elements.formControls = document.querySelectorAll(".form-control");
elements.navbar = document.querySelectorAll("nav.navbar") elements.navbar = document.querySelectorAll("nav.navbar");
elements.navIcons = document.querySelectorAll("nav .icon, .navbar-icon") elements.navIcons = document.querySelectorAll("nav .icon, .navbar-icon");
elements.navDropdownMenus = document.querySelectorAll("nav .dropdown-menu") elements.navDropdownMenus = document.querySelectorAll(".dropdown-menu");
} }
function setMode(mode) { function setMode(mode) {
var event = new CustomEvent("modeChanged", { detail: mode }); var event = new CustomEvent("modeChanged", { detail: mode });
@ -48,22 +48,22 @@ function setMode(mode) {
elements.searchBar.classList.add("dark-mode-search"); elements.searchBar.classList.add("dark-mode-search");
} }
if (elements && elements.formControls) { 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) { if (elements && elements.navbar) {
elements.navbar.forEach(navElement => { elements.navbar.forEach((navElement) => {
navElement.classList.remove("navbar-light", "bg-light"); navElement.classList.remove("navbar-light", "bg-light");
navElement.classList.add("navbar-dark", "bg-dark"); navElement.classList.add("navbar-dark", "bg-dark");
}); });
} }
if (elements && elements.navDropdownMenus) { 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) { 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"); var tables = document.querySelectorAll(".table");
tables.forEach(table => { tables.forEach((table) => {
table.classList.add("table-dark"); table.classList.add("table-dark");
}); });
if (jumbotron) { if (jumbotron) {
@ -78,22 +78,22 @@ function setMode(mode) {
elements.searchBar.classList.remove("dark-mode-search"); elements.searchBar.classList.remove("dark-mode-search");
} }
if (elements && elements.formControls) { 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) { if (elements && elements.navbar) {
elements.navbar.forEach(navElement => { elements.navbar.forEach((navElement) => {
navElement.classList.remove("navbar-dark", "bg-dark"); navElement.classList.remove("navbar-dark", "bg-dark");
navElement.classList.add("navbar-light", "bg-light"); navElement.classList.add("navbar-light", "bg-light");
}); });
} }
if (elements && elements.navDropdownMenus) { 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) { 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"); var tables = document.querySelectorAll(".table-dark");
tables.forEach(table => { tables.forEach((table) => {
table.classList.remove("table-dark"); table.classList.remove("table-dark");
}); });
if (jumbotron) { if (jumbotron) {
@ -108,36 +108,36 @@ function setMode(mode) {
} }
function toggleDarkMode() { function toggleDarkMode() {
var currentTime = Date.now() var currentTime = Date.now();
if (currentTime - lastToggleTime < 1000) { if (currentTime - lastToggleTime < 1000) {
toggleCount++ toggleCount++;
} else { } else {
toggleCount = 1 toggleCount = 1;
} }
lastToggleTime = currentTime lastToggleTime = currentTime;
if (toggleCount >= 18) { if (toggleCount >= 18) {
localStorage.setItem("dark-mode", "rainbow") localStorage.setItem("dark-mode", "rainbow");
setMode("rainbow") setMode("rainbow");
} else if (localStorage.getItem("dark-mode") == "on") { } else if (localStorage.getItem("dark-mode") == "on") {
localStorage.setItem("dark-mode", "off") localStorage.setItem("dark-mode", "off");
setMode("off") setMode("off");
} else { } else {
localStorage.setItem("dark-mode", "on") localStorage.setItem("dark-mode", "on");
setMode("on") setMode("on");
} }
} }
document.addEventListener("DOMContentLoaded", function () { 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") { if (currentMode === "on" || currentMode === "off" || currentMode === "rainbow") {
setMode(currentMode) setMode(currentMode);
} else if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) { } else if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
setMode("on") setMode("on");
} else { } else {
setMode("off") setMode("off");
} }
var darkModeToggle = document.getElementById("dark-mode-toggle"); var darkModeToggle = document.getElementById("dark-mode-toggle");
@ -147,4 +147,4 @@ document.addEventListener("DOMContentLoaded", function () {
toggleDarkMode(); toggleDarkMode();
}); });
} }
}) });

View File

@ -8,11 +8,11 @@ function showErrorBanner(message, stackTrace) {
let firstErrorOccurred = false; let firstErrorOccurred = false;
$(document).ready(function () { $(document).ready(function () {
$('form').submit(async function(event) { $("form").submit(async function (event) {
event.preventDefault(); event.preventDefault();
firstErrorOccurred = false; firstErrorOccurred = false;
const url = this.action; const url = this.action;
const files = $('#fileInput-input')[0].files; const files = $("#fileInput-input")[0].files;
const formData = new FormData(this); const formData = new FormData(this);
// Remove empty file entries // Remove empty file entries
@ -21,53 +21,51 @@ $(document).ready(function() {
formData.delete(key); formData.delete(key);
} }
} }
const override = $('#override').val() || ''; const override = $("#override").val() || "";
const originalButtonText = $('#submitBtn').text(); const originalButtonText = $("#submitBtn").text();
$('#submitBtn').text('Processing...'); $("#submitBtn").text("Processing...");
console.log(override); console.log(override);
try { try {
if (remoteCall === true) { if (remoteCall === true) {
if (override === 'multi' || (!multiple && files.length > 1) && override !== 'single' ) { if (override === "multi" || (!multiple && files.length > 1 && override !== "single")) {
await submitMultiPdfForm(url, files); await submitMultiPdfForm(url, files);
} else { } else {
await handleSingleDownload(url, formData); await handleSingleDownload(url, formData);
} }
} }
$('#submitBtn').text(originalButtonText); $("#submitBtn").text(originalButtonText);
} catch (error) { } catch (error) {
handleDownloadError(error); handleDownloadError(error);
$('#submitBtn').text(originalButtonText); $("#submitBtn").text(originalButtonText);
console.error(error); console.error(error);
} }
}); });
}); });
async function handleSingleDownload(url, formData, isMulti = false, isZip = false) { async function handleSingleDownload(url, formData, isMulti = false, isZip = false) {
try { try {
const response = await fetch(url, { method: 'POST', body: formData }); const response = await fetch(url, { method: "POST", body: formData });
const contentType = response.headers.get('content-type'); const contentType = response.headers.get("content-type");
if (!response.ok) { if (!response.ok) {
if (contentType && contentType.includes('application/json')) { if (contentType && contentType.includes("application/json")) {
return handleJsonResponse(response); return handleJsonResponse(response);
console.error('Throwing error banner, response was not okay'); console.error("Throwing error banner, response was not okay");
} }
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);
} }
const contentDisposition = response.headers.get('Content-Disposition'); const contentDisposition = response.headers.get("Content-Disposition");
let filename = getFilenameFromContentDisposition(contentDisposition); let filename = getFilenameFromContentDisposition(contentDisposition);
const blob = await response.blob(); const blob = await response.blob();
if (contentType.includes('application/pdf') || contentType.includes('image/')) { if (contentType.includes("application/pdf") || contentType.includes("image/")) {
return handleResponse(blob, filename, !isMulti, isZip); return handleResponse(blob, filename, !isMulti, isZip);
} else { } else {
return handleResponse(blob, filename, false, isZip); return handleResponse(blob, filename, false, isZip);
} }
} catch (error) { } catch (error) {
console.error('Error in handleSingleDownload:', error); console.error("Error in handleSingleDownload:", error);
throw error; // Re-throw the error if you want it to be handled higher up. throw error; // Re-throw the error if you want it to be handled higher up.
} }
} }
@ -75,43 +73,44 @@ async function handleSingleDownload(url, formData, isMulti = false , isZip = fal
function getFilenameFromContentDisposition(contentDisposition) { function getFilenameFromContentDisposition(contentDisposition) {
let filename; let filename;
if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) { if (contentDisposition && contentDisposition.indexOf("attachment") !== -1) {
filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, '')).trim(); filename = decodeURIComponent(contentDisposition.split("filename=")[1].replace(/"/g, "")).trim();
} else { } else {
// If the Content-Disposition header is not present or does not contain the filename, use a default filename // If the Content-Disposition header is not present or does not contain the filename, use a default filename
filename = 'download'; filename = "download";
} }
return filename; return filename;
} }
async function handleJsonResponse(response) { async function handleJsonResponse(response) {
const json = await response.json(); const json = await response.json();
const errorMessage = JSON.stringify(json, null, 2); 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 (
errorMessage.toLowerCase().includes("the password is incorrect") ||
errorMessage.toLowerCase().includes("Password is not provided") ||
errorMessage.toLowerCase().includes("PDF contains an encryption dictionary")
) {
if (!firstErrorOccurred) { if (!firstErrorOccurred) {
firstErrorOccurred = true; firstErrorOccurred = true;
alert(pdfPasswordPrompt); alert(pdfPasswordPrompt);
} }
} else { } else {
showErrorBanner(json.error + ':' + json.message, json.trace); showErrorBanner(json.error + ":" + json.message, json.trace);
} }
} }
async function handleResponse(blob, filename, considerViewOptions = false, isZip = false) { async function handleResponse(blob, filename, considerViewOptions = false, isZip = false) {
if (!blob) return; if (!blob) return;
const downloadOption = localStorage.getItem('downloadOption'); const downloadOption = localStorage.getItem("downloadOption");
if (considerViewOptions) { if (considerViewOptions) {
if (downloadOption === 'sameWindow') { if (downloadOption === "sameWindow") {
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
window.location.href = url; window.location.href = url;
return; return;
} else if (downloadOption === 'newWindow') { } else if (downloadOption === "newWindow") {
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
window.open(url, '_blank'); window.open(url, "_blank");
return; return;
} }
} }
@ -130,11 +129,11 @@ let urls = []; // An array to hold all the URLs
function downloadFile(blob, filename) { function downloadFile(blob, filename) {
if (!(blob instanceof Blob)) { if (!(blob instanceof Blob)) {
console.error('Invalid blob passed to downloadFile function'); console.error("Invalid blob passed to downloadFile function");
return; return;
} }
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
const a = document.createElement('a'); const a = document.createElement("a");
a.href = url; a.href = url;
a.download = filename; a.download = filename;
a.click(); a.click();
@ -143,26 +142,23 @@ function downloadFile(blob, filename) {
return { filename, blob }; return { filename, blob };
} }
async function submitMultiPdfForm(url, files) { async function submitMultiPdfForm(url, files) {
const zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4; const zipThreshold = parseInt(localStorage.getItem("zipThreshold"), 10) || 4;
const zipFiles = files.length > zipThreshold; const zipFiles = files.length > zipThreshold;
let jszip = null; let jszip = null;
// Show the progress bar // Show the progress bar
$('#progressBarContainer').show(); $("#progressBarContainer").show();
// Initialize the progress bar // Initialize the progress bar
let progressBar = $('#progressBar'); let progressBar = $("#progressBar");
progressBar.css('width', '0%'); progressBar.css("width", "0%");
progressBar.attr('aria-valuenow', 0); progressBar.attr("aria-valuenow", 0);
progressBar.attr('aria-valuemax', files.length); progressBar.attr("aria-valuemax", files.length);
if (zipFiles) { if (zipFiles) {
jszip = new JSZip(); jszip = new JSZip();
} }
// Get the form with the method attribute set to POST // Get the form with the method attribute set to POST
let postForm = document.querySelector('form[method="POST"]'); let postForm = document.querySelector('form[method="POST"]');
@ -174,7 +170,7 @@ async function submitMultiPdfForm(url, files) {
console.log("No form with POST method found."); console.log("No form with POST method found.");
} }
//Remove file to reuse parameters for other runs //Remove file to reuse parameters for other runs
formData.delete('fileInput'); formData.delete("fileInput");
// Remove empty file entries // Remove empty file entries
for (let [key, value] of formData.entries()) { for (let [key, value] of formData.entries()) {
if (value instanceof File && !value.name) { if (value instanceof File && !value.name) {
@ -188,14 +184,14 @@ async function submitMultiPdfForm(url, files) {
} }
for (const chunk of chunks) { for (const chunk of chunks) {
const promises = chunk.map(async file => { const promises = chunk.map(async (file) => {
let fileFormData = new FormData(); let fileFormData = new FormData();
fileFormData.append('fileInput', file); fileFormData.append("fileInput", file);
console.log(fileFormData); console.log(fileFormData);
// Add other form data // Add other form data
for (let pair of formData.entries()) { for (let pair of formData.entries()) {
fileFormData.append(pair[0], pair[1]); fileFormData.append(pair[0], pair[1]);
console.log(pair[0]+ ', ' + pair[1]); console.log(pair[0] + ", " + pair[1]);
} }
try { try {
@ -213,7 +209,6 @@ async function submitMultiPdfForm(url, files) {
} }
}); });
await Promise.all(promises); await Promise.all(promises);
} }
if (zipFiles) { if (zipFiles) {
@ -221,21 +216,19 @@ async function submitMultiPdfForm(url, files) {
const content = await jszip.generateAsync({ type: "blob" }); const content = await jszip.generateAsync({ type: "blob" });
downloadFile(content, "files.zip"); downloadFile(content, "files.zip");
} catch (error) { } catch (error) {
console.error('Error generating ZIP file: ' + error); console.error("Error generating ZIP file: " + error);
} }
} }
progressBar.css('width', '100%'); progressBar.css("width", "100%");
progressBar.attr('aria-valuenow', Array.from(files).length); progressBar.attr("aria-valuenow", Array.from(files).length);
} }
function updateProgressBar(progressBar, files) { function updateProgressBar(progressBar, files) {
let progress = ((progressBar.attr('aria-valuenow') / files.length) * 100) + (100 / files.length); let progress = (progressBar.attr("aria-valuenow") / files.length) * 100 + 100 / files.length;
progressBar.css('width', progress + '%'); progressBar.css("width", progress + "%");
progressBar.attr('aria-valuenow', parseInt(progressBar.attr('aria-valuenow')) + 1); progressBar.attr("aria-valuenow", parseInt(progressBar.attr("aria-valuenow")) + 1);
} }
window.addEventListener('unload', () => { window.addEventListener("unload", () => {
for (const url of urls) { for (const url of urls) {
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
} }

View File

@ -1,24 +1,23 @@
const DraggableUtils = { const DraggableUtils = {
boxDragContainer: document.getElementById("box-drag-container"),
boxDragContainer: document.getElementById('box-drag-container'), pdfCanvas: document.getElementById("pdf-canvas"),
pdfCanvas: document.getElementById('pdf-canvas'),
nextId: 0, nextId: 0,
pdfDoc: null, pdfDoc: null,
pageIndex: 0, pageIndex: 0,
documentsMap: new Map(), documentsMap: new Map(),
init() { init() {
interact('.draggable-canvas') interact(".draggable-canvas")
.draggable({ .draggable({
listeners: { listeners: {
move: (event) => { move: (event) => {
const target = event.target; const target = event.target;
const x = (parseFloat(target.getAttribute('data-bs-x')) || 0) + event.dx; const x = (parseFloat(target.getAttribute("data-bs-x")) || 0) + event.dx;
const y = (parseFloat(target.getAttribute('data-bs-y')) || 0) + event.dy; const y = (parseFloat(target.getAttribute("data-bs-y")) || 0) + event.dy;
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-x", x);
target.setAttribute('data-bs-y', y); target.setAttribute("data-bs-y", y);
this.onInteraction(target); this.onInteraction(target);
}, },
@ -28,9 +27,9 @@ const DraggableUtils = {
edges: { left: true, right: true, bottom: true, top: true }, edges: { left: true, right: true, bottom: true, top: true },
listeners: { listeners: {
move: (event) => { move: (event) => {
var target = event.target var target = event.target;
var x = (parseFloat(target.getAttribute('data-bs-x')) || 0) var x = parseFloat(target.getAttribute("data-bs-x")) || 0;
var y = (parseFloat(target.getAttribute('data-bs-y')) || 0) var y = parseFloat(target.getAttribute("data-bs-y")) || 0;
// check if control key is pressed // check if control key is pressed
if (event.ctrlKey) { if (event.ctrlKey) {
@ -49,18 +48,18 @@ const DraggableUtils = {
event.rect.height = height; event.rect.height = height;
} }
target.style.width = event.rect.width + 'px' target.style.width = event.rect.width + "px";
target.style.height = event.rect.height + 'px' target.style.height = event.rect.height + "px";
// translate when resizing from top or left edges // translate when resizing from top or left edges
x += event.deltaRect.left x += event.deltaRect.left;
y += event.deltaRect.top 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-x", x);
target.setAttribute('data-bs-y', y) target.setAttribute("data-bs-y", y);
target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height) target.textContent = Math.round(event.rect.width) + "\u00D7" + Math.round(event.rect.height);
this.onInteraction(target); this.onInteraction(target);
}, },
@ -79,17 +78,17 @@ const DraggableUtils = {
}, },
createDraggableCanvas() { createDraggableCanvas() {
const createdCanvas = document.createElement('canvas'); const createdCanvas = document.createElement("canvas");
createdCanvas.id = `draggable-canvas-${this.nextId++}`; createdCanvas.id = `draggable-canvas-${this.nextId++}`;
createdCanvas.classList.add("draggable-canvas"); createdCanvas.classList.add("draggable-canvas");
const x = 0; const x = 0;
const y = 20; const y = 20;
createdCanvas.style.transform = `translate(${x}px, ${y}px)`; createdCanvas.style.transform = `translate(${x}px, ${y}px)`;
createdCanvas.setAttribute('data-bs-x', x); createdCanvas.setAttribute("data-bs-x", x);
createdCanvas.setAttribute('data-bs-y', y); createdCanvas.setAttribute("data-bs-y", y);
createdCanvas.onclick = e => this.onInteraction(e.target); createdCanvas.onclick = (e) => this.onInteraction(e.target);
this.boxDragContainer.appendChild(createdCanvas); this.boxDragContainer.appendChild(createdCanvas);
return createdCanvas; return createdCanvas;
@ -127,11 +126,11 @@ const DraggableUtils = {
var myContext = createdCanvas.getContext("2d"); var myContext = createdCanvas.getContext("2d");
myContext.drawImage(myImage, 0, 0); myContext.drawImage(myImage, 0, 0);
resolve(createdCanvas); resolve(createdCanvas);
} };
}) });
}, },
deleteAllDraggableCanvases() { deleteAllDraggableCanvases() {
this.boxDragContainer.querySelectorAll(".draggable-canvas").forEach(el => el.remove()); this.boxDragContainer.querySelectorAll(".draggable-canvas").forEach((el) => el.remove());
}, },
deleteDraggableCanvas(element) { deleteDraggableCanvas(element) {
if (element) { if (element) {
@ -149,8 +148,14 @@ const DraggableUtils = {
} }
const elements = [...this.boxDragContainer.querySelectorAll(".draggable-canvas")]; const elements = [...this.boxDragContainer.querySelectorAll(".draggable-canvas")];
const draggablesData = elements.map(el => {return{element:el, offsetWidth:el.offsetWidth, offsetHeight:el.offsetHeight}}); const draggablesData = elements.map((el) => {
elements.forEach(el => this.boxDragContainer.removeChild(el)); return {
element: el,
offsetWidth: el.offsetWidth,
offsetHeight: el.offsetHeight,
};
});
elements.forEach((el) => this.boxDragContainer.removeChild(el));
pagesMap[this.pageIndex] = draggablesData; pagesMap[this.pageIndex] = draggablesData;
pagesMap[this.pageIndex + "-offsetWidth"] = this.pdfCanvas.offsetWidth; pagesMap[this.pageIndex + "-offsetWidth"] = this.pdfCanvas.offsetWidth;
@ -167,7 +172,7 @@ const DraggableUtils = {
const draggablesData = pagesMap[this.pageIndex]; const draggablesData = pagesMap[this.pageIndex];
if (draggablesData) { if (draggablesData) {
draggablesData.forEach(draggableData => this.boxDragContainer.appendChild(draggableData.element)); draggablesData.forEach((draggableData) => this.boxDragContainer.appendChild(draggableData.element));
} }
this.documentsMap.set(this.pdfDoc, pagesMap); this.documentsMap.set(this.pdfDoc, pagesMap);
@ -192,7 +197,7 @@ const DraggableUtils = {
// render the page onto the canvas // render the page onto the canvas
var renderContext = { var renderContext = {
canvasContext: this.pdfCanvas.getContext("2d"), canvasContext: this.pdfCanvas.getContext("2d"),
viewport: page.getViewport({ scale: 1 }) viewport: page.getViewport({ scale: 1 }),
}; };
await page.render(renderContext).promise; await page.render(renderContext).promise;
@ -213,12 +218,12 @@ const DraggableUtils = {
} }
}, },
parseTransform(element) { parseTransform(element) {},
},
async getOverlayedPdfDocument() { async getOverlayedPdfDocument() {
const pdfBytes = await this.pdfDoc.getData(); const pdfBytes = await this.pdfDoc.getData();
const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, { ignoreEncryption: true }); const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, {
ignoreEncryption: true,
});
this.storePageContents(); this.storePageContents();
const pagesMap = this.documentsMap.get(this.pdfDoc); const pagesMap = this.documentsMap.get(this.pdfDoc);
@ -241,7 +246,7 @@ const DraggableUtils = {
const pdfImageObject = await pdfDocModified.embedPng(draggableImgBytes); const pdfImageObject = await pdfDocModified.embedPng(draggableImgBytes);
// calculate the position in the pdf document // calculate the position in the pdf document
const tansform = draggableElement.style.transform.replace(/[^.,-\d]/g, ''); const tansform = draggableElement.style.transform.replace(/[^.,-\d]/g, "");
const transformComponents = tansform.split(","); const transformComponents = tansform.split(",");
const draggablePositionPixels = { const draggablePositionPixels = {
x: parseFloat(transformComponents[0]), x: parseFloat(transformComponents[0]),
@ -254,13 +259,13 @@ const DraggableUtils = {
y: draggablePositionPixels.y / offsetHeight, y: draggablePositionPixels.y / offsetHeight,
width: draggablePositionPixels.width / offsetWidth, width: draggablePositionPixels.width / offsetWidth,
height: draggablePositionPixels.height / offsetHeight, height: draggablePositionPixels.height / offsetHeight,
} };
const draggablePositionPdf = { const draggablePositionPdf = {
x: draggablePositionRelative.x * page.getWidth(), x: draggablePositionRelative.x * page.getWidth(),
y: draggablePositionRelative.y * page.getHeight(), y: draggablePositionRelative.y * page.getHeight(),
width: draggablePositionRelative.width * page.getWidth(), width: draggablePositionRelative.width * page.getWidth(),
height: draggablePositionRelative.height * page.getHeight(), height: draggablePositionRelative.height * page.getHeight(),
} };
// draw the image // draw the image
page.drawImage(pdfImageObject, { page.drawImage(pdfImageObject, {
@ -275,7 +280,7 @@ const DraggableUtils = {
this.loadPageContents(); this.loadPageContents();
return pdfDocModified; return pdfDocModified;
}, },
} };
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
DraggableUtils.init(); DraggableUtils.init();

View File

@ -13,10 +13,10 @@ function toggletrace() {
} }
function copytrace() { function copytrace() {
var flip = false var flip = false;
if (!traceVisible) { if (!traceVisible) {
toggletrace() toggletrace();
flip = true flip = true;
} }
var traceContent = document.getElementById("traceContent"); var traceContent = document.getElementById("traceContent");
var range = document.createRange(); var range = document.createRange();
@ -26,7 +26,7 @@ function copytrace() {
document.execCommand("copy"); document.execCommand("copy");
window.getSelection().removeAllRanges(); window.getSelection().removeAllRanges();
if (flip) { if (flip) {
toggletrace() toggletrace();
} }
} }
@ -46,5 +46,5 @@ function adjustContainerHeight() {
} }
} }
function showHelp() { function showHelp() {
$('#helpModal').modal('show'); $("#helpModal").modal("show");
} }

View File

@ -1,24 +1,24 @@
function updateFavoritesDropdown() { function updateFavoritesDropdown() {
var dropdown = document.querySelector('#favoritesDropdown'); var dropdown = document.querySelector("#favoritesDropdown");
// Check if dropdown exists // Check if dropdown exists
if (!dropdown) { if (!dropdown) {
console.error('Dropdown element with ID "favoritesDropdown" not found!'); console.error('Dropdown element with ID "favoritesDropdown" not found!');
return; // Exit the function return; // Exit the function
} }
dropdown.innerHTML = ''; // Clear the current favorites dropdown.innerHTML = ""; // Clear the current favorites
var hasFavorites = false; var hasFavorites = false;
for (var i = 0; i < localStorage.length; i++) { for (var i = 0; i < localStorage.length; i++) {
var key = localStorage.key(i); var key = localStorage.key(i);
if (localStorage.getItem(key) === 'favorite') { if (localStorage.getItem(key) === "favorite") {
// Find the corresponding navbar entry // Find the corresponding navbar entry
var navbarEntry = document.querySelector(`a[href='${key}']`); var navbarEntry = document.querySelector(`a[href='${key}']`);
if (navbarEntry) { if (navbarEntry) {
// Create a new dropdown entry // Create a new dropdown entry
var dropdownItem = document.createElement('a'); var dropdownItem = document.createElement("a");
dropdownItem.className = 'dropdown-item'; dropdownItem.className = "dropdown-item";
dropdownItem.href = navbarEntry.href; dropdownItem.href = navbarEntry.href;
dropdownItem.innerHTML = navbarEntry.innerHTML; dropdownItem.innerHTML = navbarEntry.innerHTML;
dropdown.appendChild(dropdownItem); dropdown.appendChild(dropdownItem);
@ -31,15 +31,15 @@ function updateFavoritesDropdown() {
// Show or hide the default item based on whether there are any favorites // Show or hide the default item based on whether there are any favorites
if (!hasFavorites) { if (!hasFavorites) {
var defaultItem = document.createElement('a'); var defaultItem = document.createElement("a");
defaultItem.className = 'dropdown-item'; defaultItem.className = "dropdown-item";
defaultItem.textContent = noFavourites; defaultItem.textContent = noFavourites;
dropdown.appendChild(defaultItem); dropdown.appendChild(defaultItem);
} }
} }
// Ensure that the DOM content has been fully loaded before calling the function // Ensure that the DOM content has been fully loaded before calling the function
document.addEventListener('DOMContentLoaded', function() { document.addEventListener("DOMContentLoaded", function () {
console.log('DOMContentLoaded event fired'); console.log("DOMContentLoaded event fired");
updateFavoritesDropdown(); updateFavoritesDropdown();
}); });

View File

@ -1,11 +1,11 @@
document.addEventListener('DOMContentLoaded', function() { document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll('.custom-file-chooser').forEach(setupFileInput); document.querySelectorAll(".custom-file-chooser").forEach(setupFileInput);
}); });
function setupFileInput(chooser) { function setupFileInput(chooser) {
const elementId = chooser.getAttribute('data-bs-element-id'); const elementId = chooser.getAttribute("data-bs-element-id");
const filesSelected = chooser.getAttribute('data-bs-files-selected'); const filesSelected = chooser.getAttribute("data-bs-files-selected");
const pdfPrompt = chooser.getAttribute('data-bs-pdf-prompt'); const pdfPrompt = chooser.getAttribute("data-bs-pdf-prompt");
let allFiles = []; let allFiles = [];
let overlay; let overlay;
@ -14,21 +14,21 @@ function setupFileInput(chooser) {
const dragenterListener = function () { const dragenterListener = function () {
dragCounter++; dragCounter++;
if (!overlay) { if (!overlay) {
overlay = document.createElement('div'); overlay = document.createElement("div");
overlay.style.position = 'fixed'; overlay.style.position = "fixed";
overlay.style.top = 0; overlay.style.top = 0;
overlay.style.left = 0; overlay.style.left = 0;
overlay.style.width = '100%'; overlay.style.width = "100%";
overlay.style.height = '100%'; overlay.style.height = "100%";
overlay.style.background = 'rgba(0, 0, 0, 0.5)'; overlay.style.background = "rgba(0, 0, 0, 0.5)";
overlay.style.color = '#fff'; overlay.style.color = "#fff";
overlay.style.zIndex = '1000'; overlay.style.zIndex = "1000";
overlay.style.display = 'flex'; overlay.style.display = "flex";
overlay.style.alignItems = 'center'; overlay.style.alignItems = "center";
overlay.style.justifyContent = 'center'; overlay.style.justifyContent = "center";
overlay.style.pointerEvents = 'none'; overlay.style.pointerEvents = "none";
overlay.innerHTML = '<p>Drop files anywhere to upload</p>'; overlay.innerHTML = "<p>Drop files anywhere to upload</p>";
document.getElementById('content-wrap').appendChild(overlay); document.getElementById("content-wrap").appendChild(overlay);
} }
}; };
@ -52,7 +52,7 @@ function setupFileInput(chooser) {
} }
const dataTransfer = new DataTransfer(); const dataTransfer = new DataTransfer();
allFiles.forEach(file => dataTransfer.items.add(file)); allFiles.forEach((file) => dataTransfer.items.add(file));
const fileInput = document.getElementById(elementId); const fileInput = document.getElementById(elementId);
fileInput.files = dataTransfer.files; fileInput.files = dataTransfer.files;
@ -64,10 +64,10 @@ function setupFileInput(chooser) {
dragCounter = 0; dragCounter = 0;
fileInput.dispatchEvent(new Event('change', { bubbles: true })); fileInput.dispatchEvent(new Event("change", { bubbles: true }));
}; };
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => {
document.body.addEventListener(eventName, preventDefaults, false); document.body.addEventListener(eventName, preventDefaults, false);
}); });
@ -76,9 +76,9 @@ function setupFileInput(chooser) {
e.stopPropagation(); e.stopPropagation();
} }
document.body.addEventListener('dragenter', dragenterListener); document.body.addEventListener("dragenter", dragenterListener);
document.body.addEventListener('dragleave', dragleaveListener); document.body.addEventListener("dragleave", dragleaveListener);
document.body.addEventListener('drop', dropListener); document.body.addEventListener("drop", dropListener);
$("#" + elementId).on("change", function (e) { $("#" + elementId).on("change", function (e) {
allFiles = Array.from(e.target.files); allFiles = Array.from(e.target.files);
@ -87,16 +87,19 @@ function setupFileInput(chooser) {
function handleFileInputChange(inputElement) { function handleFileInputChange(inputElement) {
const files = allFiles; const files = allFiles;
const fileNames = files.map(f => f.name); const fileNames = files.map((f) => f.name);
const selectedFilesContainer = $(inputElement).siblings(".selected-files"); const selectedFilesContainer = $(inputElement).siblings(".selected-files");
selectedFilesContainer.empty(); selectedFilesContainer.empty();
fileNames.forEach(fileName => { fileNames.forEach((fileName) => {
selectedFilesContainer.append("<div>" + fileName + "</div>"); selectedFilesContainer.append("<div>" + fileName + "</div>");
}); });
if (fileNames.length === 1) { if (fileNames.length === 1) {
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]); $(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]);
} else if (fileNames.length > 1) { } else if (fileNames.length > 1) {
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames.length + " " + filesSelected); $(inputElement)
.siblings(".custom-file-label")
.addClass("selected")
.html(fileNames.length + " " + filesSelected);
} else { } else {
$(inputElement).siblings(".custom-file-label").addClass("selected").html(pdfPrompt); $(inputElement).siblings(".custom-file-label").addClass("selected").html(pdfPrompt);
} }

View File

@ -1,17 +1,17 @@
function initializeGame() { function initializeGame() {
const gameContainer = document.getElementById('game-container'); const gameContainer = document.getElementById("game-container");
const player = document.getElementById('player'); const player = document.getElementById("player");
let playerSize = gameContainer.clientWidth * 0.0625; // 5% of container width let playerSize = gameContainer.clientWidth * 0.0625; // 5% of container width
player.style.width = playerSize + 'px'; player.style.width = playerSize + "px";
player.style.height = playerSize + 'px'; player.style.height = playerSize + "px";
let playerX = gameContainer.clientWidth / 2 - playerSize / 2; let playerX = gameContainer.clientWidth / 2 - playerSize / 2;
let playerY = gameContainer.clientHeight * 0.1; let playerY = gameContainer.clientHeight * 0.1;
const scoreElement = document.getElementById('score'); const scoreElement = document.getElementById("score");
const levelElement = document.getElementById('level'); const levelElement = document.getElementById("level");
const livesElement = document.getElementById('lives'); const livesElement = document.getElementById("lives");
const highScoreElement = document.getElementById('high-score'); const highScoreElement = document.getElementById("high-score");
let pdfSize = gameContainer.clientWidth * 0.0625; // 5% of container width let pdfSize = gameContainer.clientWidth * 0.0625; // 5% of container width
let projectileWidth = gameContainer.clientWidth * 0.00625; // 0.00625; // 0.5% of container width let projectileWidth = gameContainer.clientWidth * 0.00625; // 0.00625; // 0.5% of container width
@ -23,12 +23,9 @@ function initializeGame() {
let lastProjectileTime = 0; let lastProjectileTime = 0;
let lives = 3; let lives = 3;
let highScore = localStorage.getItem("highScore") ? parseInt(localStorage.getItem("highScore")) : 0;
let highScore = localStorage.getItem('highScore') ? parseInt(localStorage.getItem('highScore')) : 0;
updateHighScore(); updateHighScore();
const keysPressed = {}; const keysPressed = {};
const pdfs = []; const pdfs = [];
const projectiles = []; const projectiles = [];
@ -38,13 +35,13 @@ function initializeGame() {
let gameOver = false; let gameOver = false;
function handleKeys() { function handleKeys() {
if (keysPressed['ArrowLeft']) { if (keysPressed["ArrowLeft"]) {
playerX -= 10; playerX -= 10;
} }
if (keysPressed['ArrowRight']) { if (keysPressed["ArrowRight"]) {
playerX += 10; playerX += 10;
} }
if (keysPressed[' '] && !gameOver) { if (keysPressed[" "] && !gameOver) {
const currentTime = new Date().getTime(); const currentTime = new Date().getTime();
if (currentTime - lastProjectileTime >= fireRate) { if (currentTime - lastProjectileTime >= fireRate) {
shootProjectile(); shootProjectile();
@ -54,69 +51,60 @@ function initializeGame() {
updatePlayerPosition(); updatePlayerPosition();
} }
document.addEventListener("keydown", (event) => {
if (event.key === " ") {
document.addEventListener('keydown', (event) => {
if (event.key === ' ') {
event.preventDefault(); event.preventDefault();
} }
keysPressed[event.key] = true; keysPressed[event.key] = true;
handleKeys(); handleKeys();
}); });
document.addEventListener('keyup', (event) => { document.addEventListener("keyup", (event) => {
keysPressed[event.key] = false; keysPressed[event.key] = false;
}); });
function updatePlayerPosition() { function updatePlayerPosition() {
player.style.left = playerX + 'px'; player.style.left = playerX + "px";
player.style.bottom = playerY + 'px'; player.style.bottom = playerY + "px";
} }
function updateLives() { function updateLives() {
livesElement.textContent = 'Lives: ' + lives; livesElement.textContent = "Lives: " + lives;
} }
function updateHighScore() { function updateHighScore() {
highScoreElement.textContent = 'High Score: ' + highScore; highScoreElement.textContent = "High Score: " + highScore;
} }
function shootProjectile() { function shootProjectile() {
const projectile = document.createElement('div'); const projectile = document.createElement("div");
projectile.classList.add('projectile'); projectile.classList.add("projectile");
projectile.style.backgroundColor = 'black'; projectile.style.backgroundColor = "black";
projectile.style.width = projectileWidth + 'px'; projectile.style.width = projectileWidth + "px";
projectile.style.height = projectileHeight + 'px'; projectile.style.height = projectileHeight + "px";
projectile.style.left = (playerX + playerSize / 2 - projectileWidth / 2) + 'px'; projectile.style.left = playerX + playerSize / 2 - projectileWidth / 2 + "px";
projectile.style.top = (gameContainer.clientHeight - playerY - playerSize) + 'px'; projectile.style.top = gameContainer.clientHeight - playerY - playerSize + "px";
gameContainer.appendChild(projectile); gameContainer.appendChild(projectile);
projectiles.push(projectile); projectiles.push(projectile);
} }
function spawnPdf() { function spawnPdf() {
const pdf = document.createElement('img'); const pdf = document.createElement("img");
pdf.src = 'images/file-earmark-pdf.svg'; pdf.src = "images/file-earmark-pdf.svg";
pdf.classList.add('pdf'); pdf.classList.add("pdf");
pdf.style.width = pdfSize + 'px'; pdf.style.width = pdfSize + "px";
pdf.style.height = pdfSize + 'px'; pdf.style.height = pdfSize + "px";
pdf.style.left = Math.floor(Math.random() * (gameContainer.clientWidth - pdfSize)) + 'px'; pdf.style.left = Math.floor(Math.random() * (gameContainer.clientWidth - pdfSize)) + "px";
pdf.style.top = '0px'; pdf.style.top = "0px";
gameContainer.appendChild(pdf); gameContainer.appendChild(pdf);
pdfs.push(pdf); pdfs.push(pdf);
} }
function resetEnemies() { function resetEnemies() {
pdfs.forEach((pdf) => gameContainer.removeChild(pdf)); pdfs.forEach((pdf) => gameContainer.removeChild(pdf));
pdfs.length = 0; pdfs.length = 0;
} }
function updateGame() { function updateGame() {
if (gameOver || paused) return; if (gameOver || paused) return;
@ -138,9 +126,8 @@ function initializeGame() {
endGame(); endGame();
return; return;
} }
} else { } else {
pdf.style.top = pdfY + 'px'; pdf.style.top = pdfY + "px";
// Check for collision with player // Check for collision with player
if (collisionDetected(player, pdf)) { if (collisionDetected(player, pdf)) {
@ -153,7 +140,7 @@ function initializeGame() {
} }
} }
} }
}; }
projectiles.forEach((projectile, projectileIndex) => { projectiles.forEach((projectile, projectileIndex) => {
const projectileY = parseInt(projectile.style.top) - 10; const projectileY = parseInt(projectile.style.top) - 10;
@ -161,7 +148,7 @@ function initializeGame() {
gameContainer.removeChild(projectile); gameContainer.removeChild(projectile);
projectiles.splice(projectileIndex, 1); projectiles.splice(projectileIndex, 1);
} else { } else {
projectile.style.top = projectileY + 'px'; projectile.style.top = projectileY + "px";
} }
for (let pdfIndex = 0; pdfIndex < pdfs.length; pdfIndex++) { for (let pdfIndex = 0; pdfIndex < pdfs.length; pdfIndex++) {
@ -200,27 +187,23 @@ function initializeGame() {
updateScore(); updateScore();
updateLives(); updateLives();
levelElement.textContent = 'Level: ' + level; levelElement.textContent = "Level: " + level;
pdfSpeed = 1; pdfSpeed = 1;
clearTimeout(spawnPdfTimeout); // Clear the existing spawnPdfTimeout clearTimeout(spawnPdfTimeout); // Clear the existing spawnPdfTimeout
setTimeout(updateGame, 1000 / 60); setTimeout(updateGame, 1000 / 60);
spawnPdfInterval(); spawnPdfInterval();
} }
function updateScore() { function updateScore() {
scoreElement.textContent = 'Score: ' + score; scoreElement.textContent = "Score: " + score;
checkLevelUp(); checkLevelUp();
} }
function checkLevelUp() { function checkLevelUp() {
const newLevel = Math.floor(score / 100) + 1; const newLevel = Math.floor(score / 100) + 1;
if (newLevel > level) { if (newLevel > level) {
level = newLevel; level = newLevel;
levelElement.textContent = 'Level: ' + level; levelElement.textContent = "Level: " + level;
pdfSpeed += 0.2; pdfSpeed += 0.2;
} }
} }
@ -228,28 +211,20 @@ function initializeGame() {
function collisionDetected(a, b) { function collisionDetected(a, b) {
const rectA = a.getBoundingClientRect(); const rectA = a.getBoundingClientRect();
const rectB = b.getBoundingClientRect(); const rectB = b.getBoundingClientRect();
return ( return rectA.left < rectB.right && rectA.right > rectB.left && rectA.top < rectB.bottom && rectA.bottom > rectB.top;
rectA.left < rectB.right &&
rectA.right > rectB.left &&
rectA.top < rectB.bottom &&
rectA.bottom > rectB.top
);
} }
function endGame() { function endGame() {
gameOver = true; gameOver = true;
if (score > highScore) { if (score > highScore) {
highScore = score; highScore = score;
localStorage.setItem('highScore', highScore); localStorage.setItem("highScore", highScore);
updateHighScore(); updateHighScore();
} }
alert('Game Over! Your final score is: ' + score); alert("Game Over! Your final score is: " + score);
document.getElementById('game-container-wrapper').close(); document.getElementById("game-container-wrapper").close();
} }
let spawnPdfTimeout; let spawnPdfTimeout;
const BASE_SPAWN_INTERVAL_MS = 1250; // milliseconds before a new enemy spawns const BASE_SPAWN_INTERVAL_MS = 1250; // milliseconds before a new enemy spawns
@ -274,8 +249,7 @@ function initializeGame() {
updateGame(); updateGame();
spawnPdfInterval(); spawnPdfInterval();
document.addEventListener("visibilitychange", function () {
document.addEventListener('visibilitychange', function() {
if (document.hidden) { if (document.hidden) {
paused = true; paused = true;
} else { } else {
@ -283,7 +257,6 @@ function initializeGame() {
updateGame(); updateGame();
spawnPdfInterval(); spawnPdfInterval();
} }
}); });
window.resetGame = resetGame; window.resetGame = resetGame;

View File

@ -1,6 +1,6 @@
function compareVersions(version1, version2) { function compareVersions(version1, version2) {
const v1 = version1.split('.'); const v1 = version1.split(".");
const v2 = version2.split('.'); const v2 = version2.split(".");
for (let i = 0; i < v1.length || i < v2.length; i++) { for (let i = 0; i < v1.length || i < v2.length; i++) {
const n1 = parseInt(v1[i]) || 0; const n1 = parseInt(v1[i]) || 0;
@ -16,7 +16,6 @@ function compareVersions(version1, version2) {
return 0; return 0;
} }
async function getLatestReleaseVersion() { async function getLatestReleaseVersion() {
const url = "https://api.github.com/repos/Stirling-Tools/Stirling-PDF/releases/latest"; const url = "https://api.github.com/repos/Stirling-Tools/Stirling-PDF/releases/latest";
try { try {
@ -36,20 +35,18 @@ async function checkForUpdate() {
updateBtn.style.display = "none"; updateBtn.style.display = "none";
} }
const latestVersion = await getLatestReleaseVersion(); const latestVersion = await getLatestReleaseVersion();
console.log("latestVersion=" + latestVersion) console.log("latestVersion=" + latestVersion);
console.log("currentVersion=" + currentVersion) console.log("currentVersion=" + currentVersion);
console.log("compareVersions(latestVersion, currentVersion) > 0)=" + compareVersions(latestVersion, currentVersion)) console.log("compareVersions(latestVersion, currentVersion) > 0)=" + compareVersions(latestVersion, currentVersion));
if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) { if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {
document.getElementById("update-btn").style.display = "block"; document.getElementById("update-btn").style.display = "block";
console.log("visible") console.log("visible");
} else { } else {
console.log("hidden") console.log("hidden");
} }
} }
document.addEventListener("DOMContentLoaded", (event) => {
document.addEventListener('DOMContentLoaded', (event) => {
checkForUpdate(); checkForUpdate();
}); });

View File

@ -1,18 +1,18 @@
function filterCards() { function filterCards() {
var input = document.getElementById('searchBar'); var input = document.getElementById("searchBar");
var filter = input.value.toUpperCase(); var filter = input.value.toUpperCase();
var cards = document.querySelectorAll('.feature-card'); var cards = document.querySelectorAll(".feature-card");
for (var i = 0; i < cards.length; i++) { for (var i = 0; i < cards.length; i++) {
var card = cards[i]; var card = cards[i];
var title = card.querySelector('h5.card-title').innerText; var title = card.querySelector("h5.card-title").innerText;
var text = card.querySelector('p.card-text').innerText; var text = card.querySelector("p.card-text").innerText;
// Get the navbar tags associated with the card // Get the navbar tags associated with the card
var navbarItem = document.querySelector(`a.dropdown-item[href="${card.id}"]`); var navbarItem = document.querySelector(`a.dropdown-item[href="${card.id}"]`);
var navbarTags = navbarItem ? navbarItem.getAttribute('data-bs-tags') : ''; var navbarTags = navbarItem ? navbarItem.getAttribute("data-bs-tags") : "";
var content = title + ' ' + text + ' ' + navbarTags; var content = title + " " + text + " " + navbarTags;
if (content.toUpperCase().indexOf(filter) > -1) { if (content.toUpperCase().indexOf(filter) > -1) {
card.style.display = ""; card.style.display = "";
@ -22,19 +22,17 @@ function filterCards() {
} }
} }
function toggleFavorite(element) { function toggleFavorite(element) {
var img = element.querySelector('img'); var img = element.querySelector("img");
var card = element.closest('.feature-card'); var card = element.closest(".feature-card");
var cardId = card.id; var cardId = card.id;
if (img.src.endsWith('star.svg')) { if (img.src.endsWith("star.svg")) {
img.src = 'images/star-fill.svg'; img.src = "images/star-fill.svg";
card.classList.add('favorite'); card.classList.add("favorite");
localStorage.setItem(cardId, 'favorite'); localStorage.setItem(cardId, "favorite");
} else { } else {
img.src = 'images/star.svg'; img.src = "images/star.svg";
card.classList.remove('favorite'); card.classList.remove("favorite");
localStorage.removeItem(cardId); localStorage.removeItem(cardId);
} }
reorderCards(); reorderCards();
@ -43,11 +41,11 @@ function toggleFavorite(element) {
} }
function reorderCards() { function reorderCards() {
var container = document.querySelector('.features-container'); var container = document.querySelector(".features-container");
var cards = Array.from(container.getElementsByClassName('feature-card')); var cards = Array.from(container.getElementsByClassName("feature-card"));
cards.sort(function (a, b) { cards.sort(function (a, b) {
var aIsFavorite = localStorage.getItem(a.id) === 'favorite'; var aIsFavorite = localStorage.getItem(a.id) === "favorite";
var bIsFavorite = localStorage.getItem(b.id) === 'favorite'; var bIsFavorite = localStorage.getItem(b.id) === "favorite";
if (aIsFavorite && !bIsFavorite) { if (aIsFavorite && !bIsFavorite) {
return -1; return -1;
} }
@ -61,13 +59,13 @@ function reorderCards() {
}); });
} }
function initializeCards() { function initializeCards() {
var cards = document.querySelectorAll('.feature-card'); var cards = document.querySelectorAll(".feature-card");
cards.forEach(function (card) { cards.forEach(function (card) {
var cardId = card.id; var cardId = card.id;
var img = card.querySelector('.favorite-icon img'); var img = card.querySelector(".favorite-icon img");
if (localStorage.getItem(cardId) === 'favorite') { if (localStorage.getItem(cardId) === "favorite") {
img.src = 'images/star-fill.svg'; img.src = "images/star-fill.svg";
card.classList.add('favorite'); card.classList.add("favorite");
} }
}); });
reorderCards(); reorderCards();

View File

@ -1,44 +1,42 @@
document.addEventListener('DOMContentLoaded', function() { document.addEventListener("DOMContentLoaded", function () {
setLanguageForDropdown('.lang_dropdown-item'); setLanguageForDropdown(".lang_dropdown-item");
// Detect the browser's preferred language // Detect the browser's preferred language
let browserLang = navigator.language || navigator.userLanguage; let browserLang = navigator.language || navigator.userLanguage;
// Convert to a format consistent with your language codes (e.g., en-GB, fr-FR) // Convert to a format consistent with your language codes (e.g., en-GB, fr-FR)
browserLang = browserLang.replace('-', '_'); browserLang = browserLang.replace("-", "_");
// Check if the dropdown contains the browser's language // Check if the dropdown contains the browser's language
const dropdownLangExists = document.querySelector(`.lang_dropdown-item[data-language-code="${browserLang}"]`); 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 // Set the default language to browser's language or 'en_GB' if not found in the dropdown
const defaultLocale = dropdownLangExists ? browserLang : 'en_GB'; const defaultLocale = dropdownLangExists ? browserLang : "en_GB";
const storedLocale = localStorage.getItem('languageCode') || defaultLocale; 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++) { for (let i = 0; i < dropdownItems.length; i++) {
const item = dropdownItems[i]; const item = dropdownItems[i];
item.classList.remove('active'); item.classList.remove("active");
if (item.dataset.languageCode === storedLocale) { if (item.dataset.languageCode === storedLocale) {
item.classList.add('active'); item.classList.add("active");
} }
item.addEventListener('click', handleDropdownItemClick); item.addEventListener("click", handleDropdownItemClick);
} }
}); });
function setLanguageForDropdown(dropdownClass) { function setLanguageForDropdown(dropdownClass) {
const defaultLocale = document.documentElement.lang || 'en_GB'; const defaultLocale = document.documentElement.lang || "en_GB";
const storedLocale = localStorage.getItem('languageCode') || defaultLocale; const storedLocale = localStorage.getItem("languageCode") || defaultLocale;
const dropdownItems = document.querySelectorAll(dropdownClass); const dropdownItems = document.querySelectorAll(dropdownClass);
for (let i = 0; i < dropdownItems.length; i++) { for (let i = 0; i < dropdownItems.length; i++) {
const item = dropdownItems[i]; const item = dropdownItems[i];
item.classList.remove('active'); item.classList.remove("active");
if (item.dataset.languageCode === storedLocale) { if (item.dataset.languageCode === storedLocale) {
item.classList.add('active'); item.classList.add("active");
} }
item.addEventListener('click', handleDropdownItemClick); item.addEventListener("click", handleDropdownItemClick);
} }
} }
@ -46,25 +44,32 @@ function handleDropdownItemClick(event) {
event.preventDefault(); event.preventDefault();
const languageCode = event.currentTarget.dataset.bsLanguageCode; // change this to event.currentTarget const languageCode = event.currentTarget.dataset.bsLanguageCode; // change this to event.currentTarget
if (languageCode) { if (languageCode) {
localStorage.setItem('languageCode', languageCode); localStorage.setItem("languageCode", languageCode);
const currentUrl = window.location.href; const currentUrl = window.location.href;
if (currentUrl.indexOf('?lang=') === -1) { if (currentUrl.indexOf("?lang=") === -1) {
window.location.href = currentUrl + '?lang=' + languageCode; window.location.href = currentUrl + "?lang=" + languageCode;
} else { } else {
window.location.href = currentUrl.replace(/\?lang=\w{2,}/, '?lang=' + languageCode); window.location.href = currentUrl.replace(/\?lang=\w{2,}/, "?lang=" + languageCode);
} }
} else { } else {
console.error("Language code is not set for this item."); // for debugging console.error("Language code is not set for this item."); // for debugging
} }
} }
document.addEventListener("DOMContentLoaded", function () {
document.addEventListener('DOMContentLoaded', function() { document.querySelectorAll(".nav-item.dropdown").forEach((element) => {
document.querySelectorAll('.nav-item.dropdown').forEach((element) => {
const dropdownMenu = element.querySelector(".dropdown-menu"); const dropdownMenu = element.querySelector(".dropdown-menu");
if (dropdownMenu.id !== 'favoritesDropdown' && dropdownMenu.children.length <= 2 && dropdownMenu.querySelectorAll("hr.dropdown-divider").length === dropdownMenu.children.length) { if (
if (element.previousElementSibling && element.previousElementSibling.classList.contains('nav-item') && element.previousElementSibling.classList.contains('nav-item-separator')) { dropdownMenu.id !== "favoritesDropdown" &&
dropdownMenu.children.length <= 2 &&
dropdownMenu.querySelectorAll("hr.dropdown-divider").length === dropdownMenu.children.length
) {
if (
element.previousElementSibling &&
element.previousElementSibling.classList.contains("nav-item") &&
element.previousElementSibling.classList.contains("nav-item-separator")
) {
element.previousElementSibling.remove(); element.previousElementSibling.remove();
} }
element.remove(); element.remove();
@ -72,9 +77,12 @@ document.addEventListener('DOMContentLoaded', function() {
}); });
//Sort languages by alphabet //Sort languages by alphabet
const list = Array.from(document.querySelector('.dropdown-menu[aria-labelledby="languageDropdown"]').children).filter(child => child.matches('a')); const list = Array.from(document.querySelector('.dropdown-menu[aria-labelledby="languageDropdown"]').children).filter(
list.sort(function(a, b) { (child) => child.matches("a"),
);
list
.sort(function (a, b) {
return a.textContent.toUpperCase().localeCompare(b.textContent.toUpperCase()); return a.textContent.toUpperCase().localeCompare(b.textContent.toUpperCase());
}).forEach(node => document.querySelector('.dropdown-menu[aria-labelledby="languageDropdown"]').appendChild(node)); })
.forEach((node) => document.querySelector('.dropdown-menu[aria-labelledby="languageDropdown"]').appendChild(node));
}); });

View File

@ -10,21 +10,21 @@ async function downloadFilesWithCallback(processFileCallback) {
jszip = new JSZip(); jszip = new JSZip();
} }
const promises = Array.from(files).map(async file => { const promises = Array.from(files).map(async (file) => {
const { processedData, fileName } = await processFileCallback(file); const { processedData, fileName } = await processFileCallback(file);
if (zipFiles) { if (zipFiles) {
jszip.file(fileName, processedData); jszip.file(fileName, processedData);
} else { } else {
const url = URL.createObjectURL(processedData); const url = URL.createObjectURL(processedData);
const downloadOption = localStorage.getItem('downloadOption'); const downloadOption = localStorage.getItem("downloadOption");
if (downloadOption === 'sameWindow') { if (downloadOption === "sameWindow") {
window.location.href = url; window.location.href = url;
} else if (downloadOption === 'newWindow') { } else if (downloadOption === "newWindow") {
window.open(url, '_blank'); window.open(url, "_blank");
} else { } else {
const downloadLink = document.createElement('a'); const downloadLink = document.createElement("a");
downloadLink.href = url; downloadLink.href = url;
downloadLink.download = fileName; downloadLink.download = fileName;
downloadLink.click(); downloadLink.click();
@ -37,7 +37,7 @@ async function downloadFilesWithCallback(processFileCallback) {
if (zipFiles) { if (zipFiles) {
const content = await jszip.generateAsync({ type: "blob" }); const content = await jszip.generateAsync({ type: "blob" });
const url = URL.createObjectURL(content); const url = URL.createObjectURL(content);
const a = document.createElement('a'); const a = document.createElement("a");
a.href = url; a.href = url;
a.download = "files.zip"; a.download = "files.zip";
document.body.appendChild(a); document.body.appendChild(a);

View File

@ -1,6 +1,6 @@
let currentSort = { let currentSort = {
field: null, field: null,
descending: false descending: false,
}; };
document.getElementById("fileInput-input").addEventListener("change", function () { document.getElementById("fileInput-input").addEventListener("change", function () {
@ -106,7 +106,7 @@ function sortFiles(comparator) {
// Update the files property // Update the files property
const dataTransfer = new DataTransfer(); const dataTransfer = new DataTransfer();
sortedFilesArray.forEach(file => dataTransfer.items.add(file)); sortedFilesArray.forEach((file) => dataTransfer.items.add(file));
document.getElementById("fileInput-input").files = dataTransfer.files; document.getElementById("fileInput-input").files = dataTransfer.files;
} }

View File

@ -15,21 +15,21 @@ class DragDropManager {
this.wrapper = document.getElementById(wrapperId); this.wrapper = document.getElementById(wrapperId);
this.pageDragging = false; this.pageDragging = false;
this.hoveredEl = undefined; this.hoveredEl = undefined;
this.draggelEl = undefined this.draggelEl = undefined;
this.draggedImageEl = undefined; this.draggedImageEl = undefined;
var styleElement = document.createElement('link'); var styleElement = document.createElement("link");
styleElement.rel = 'stylesheet'; styleElement.rel = "stylesheet";
styleElement.href = 'css/dragdrop.css' styleElement.href = "css/dragdrop.css";
document.head.appendChild(styleElement); document.head.appendChild(styleElement);
const div = document.createElement('div'); const div = document.createElement("div");
div.classList.add('drag-manager_endpoint'); div.classList.add("drag-manager_endpoint");
div.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-earmark-arrow-down" viewBox="0 0 16 16"> div.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-earmark-arrow-down" viewBox="0 0 16 16">
<path d="M8.5 6.5a.5.5 0 0 0-1 0v3.793L6.354 9.146a.5.5 0 1 0-.708.708l2 2a.5.5 0 0 0 .708 0l2-2a.5.5 0 0 0-.708-.708L8.5 10.293V6.5z"/> <path d="M8.5 6.5a.5.5 0 0 0-1 0v3.793L6.354 9.146a.5.5 0 1 0-.708.708l2 2a.5.5 0 0 0 .708 0l2-2a.5.5 0 0 0-.708-.708L8.5 10.293V6.5z"/>
<path d="M14 14V4.5L9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2zM9.5 3A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h5.5v2z"/> <path d="M14 14V4.5L9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2zM9.5 3A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h5.5v2z"/>
</svg>` </svg>`;
this.endInsertionElement = div; this.endInsertionElement = div;
this.startDraggingPage = this.startDraggingPage.bind(this); this.startDraggingPage = this.startDraggingPage.bind(this);
@ -39,49 +39,48 @@ class DragDropManager {
this.adapt(div); this.adapt(div);
} }
startDraggingPage(div,) { startDraggingPage(div) {
this.pageDragging = true; this.pageDragging = true;
this.draggedEl = div; this.draggedEl = div;
const img = div.querySelector('img'); const img = div.querySelector("img");
div.classList.add('drag-manager_dragging'); div.classList.add("drag-manager_dragging");
const imageSrc = img.src; const imageSrc = img.src;
const imgEl = document.createElement('img'); const imgEl = document.createElement("img");
imgEl.classList.add('dragged-img'); imgEl.classList.add("dragged-img");
imgEl.src = imageSrc; imgEl.src = imageSrc;
this.draggedImageEl = imgEl; this.draggedImageEl = imgEl;
imgEl.style.visibility = 'hidden'; imgEl.style.visibility = "hidden";
imgEl.style.transform = `rotate(${img.style.rotate === '' ? '0deg' : img.style.rotate}) translate(-50%, -50%)`; imgEl.style.transform = `rotate(${img.style.rotate === "" ? "0deg" : img.style.rotate}) translate(-50%, -50%)`;
this.dragContainer.appendChild(imgEl); this.dragContainer.appendChild(imgEl);
window.addEventListener('mouseup', this.stopDraggingPage) window.addEventListener("mouseup", this.stopDraggingPage);
window.addEventListener('mousemove', this.onDragEl) window.addEventListener("mousemove", this.onDragEl);
this.wrapper.classList.add('drag-manager_dragging-container'); this.wrapper.classList.add("drag-manager_dragging-container");
this.wrapper.appendChild(this.endInsertionElement); this.wrapper.appendChild(this.endInsertionElement);
} }
onDragEl(mouseEvent) { onDragEl(mouseEvent) {
const { clientX, clientY } = mouseEvent; const { clientX, clientY } = mouseEvent;
if (this.draggedImageEl) { if (this.draggedImageEl) {
this.draggedImageEl.style.visibility = 'visible'; this.draggedImageEl.style.visibility = "visible";
this.draggedImageEl.style.left = `${clientX}px`; this.draggedImageEl.style.left = `${clientX}px`;
this.draggedImageEl.style.top = `${clientY}px`; this.draggedImageEl.style.top = `${clientY}px`;
} }
} }
stopDraggingPage() { stopDraggingPage() {
window.removeEventListener('mousemove', this.onDragEl); window.removeEventListener("mousemove", this.onDragEl);
this.wrapper.classList.remove('drag-manager_dragging-container'); this.wrapper.classList.remove("drag-manager_dragging-container");
this.wrapper.removeChild(this.endInsertionElement); this.wrapper.removeChild(this.endInsertionElement);
window.removeEventListener('mouseup', this.stopDraggingPage) window.removeEventListener("mouseup", this.stopDraggingPage);
this.draggedImageEl = undefined; this.draggedImageEl = undefined;
this.pageDragging = false; this.pageDragging = false;
this.draggedEl.classList.remove('drag-manager_dragging'); this.draggedEl.classList.remove("drag-manager_dragging");
this.hoveredEl?.classList.remove('drag-manager_draghover'); this.hoveredEl?.classList.remove("drag-manager_draghover");
this.dragContainer.childNodes.forEach((dragChild) => { this.dragContainer.childNodes.forEach((dragChild) => {
this.dragContainer.removeChild(dragChild); this.dragContainer.removeChild(dragChild);
}) });
if (!this.hoveredEl) { if (!this.hoveredEl) {
return; return;
} }
@ -96,27 +95,26 @@ class DragDropManager {
this.movePageTo = movePageTo; this.movePageTo = movePageTo;
} }
adapt(div) { adapt(div) {
const onDragStart = () => { const onDragStart = () => {
this.startDraggingPage(div); this.startDraggingPage(div);
} };
const onMouseEnter = () => { const onMouseEnter = () => {
if (this.pageDragging) { if (this.pageDragging) {
this.hoveredEl = div; this.hoveredEl = div;
div.classList.add('drag-manager_draghover'); div.classList.add("drag-manager_draghover");
}
} }
};
const onMouseLeave = () => { const onMouseLeave = () => {
this.hoveredEl = undefined this.hoveredEl = undefined;
div.classList.remove('drag-manager_draghover'); div.classList.remove("drag-manager_draghover");
} };
div.addEventListener('dragstart', onDragStart); div.addEventListener("dragstart", onDragStart);
div.addEventListener('mouseenter', onMouseEnter); div.addEventListener("mouseenter", onMouseEnter);
div.addEventListener('mouseleave', onMouseLeave); div.addEventListener("mouseleave", onMouseLeave);
return div; return div;
} }

View File

@ -4,24 +4,24 @@ class ImageHiglighter {
this.imageHighlighter = document.getElementById(id); this.imageHighlighter = document.getElementById(id);
this.imageHighlightCallback = this.imageHighlightCallback.bind(this); this.imageHighlightCallback = this.imageHighlightCallback.bind(this);
var styleElement = document.createElement('link'); var styleElement = document.createElement("link");
styleElement.rel = 'stylesheet'; styleElement.rel = "stylesheet";
styleElement.href = 'css/imageHighlighter.css' styleElement.href = "css/imageHighlighter.css";
document.head.appendChild(styleElement); document.head.appendChild(styleElement);
this.imageHighlighter.onclick = () => { this.imageHighlighter.onclick = () => {
this.imageHighlighter.childNodes.forEach((child) => { this.imageHighlighter.childNodes.forEach((child) => {
child.classList.add('remove'); child.classList.add("remove");
setTimeout(() => { setTimeout(() => {
this.imageHighlighter.removeChild(child); this.imageHighlighter.removeChild(child);
}, 100) }, 100);
}) });
} };
} }
imageHighlightCallback(highlightEvent) { imageHighlightCallback(highlightEvent) {
var bigImg = document.createElement('img'); var bigImg = document.createElement("img");
bigImg.onclick = (imageClickEvent) => { bigImg.onclick = (imageClickEvent) => {
// This prevents the highlighter's onClick from closing the image when clicking // This prevents the highlighter's onClick from closing the image when clicking
// on the image instead of next to it. // on the image instead of next to it.
@ -30,15 +30,15 @@ class ImageHiglighter {
}; };
bigImg.src = highlightEvent.target.src; bigImg.src = highlightEvent.target.src;
this.imageHighlighter.appendChild(bigImg); this.imageHighlighter.appendChild(bigImg);
}; }
setActions() { setActions() {
// not needed in this case // not needed in this case
} }
adapt(div) { adapt(div) {
const img = div.querySelector('.page-image'); const img = div.querySelector(".page-image");
img.addEventListener('click', this.imageHighlightCallback) img.addEventListener("click", this.imageHighlightCallback);
return div; return div;
} }
} }

View File

@ -6,16 +6,16 @@ class PdfActionsManager {
this.pagesContainer = document.getElementById(id); this.pagesContainer = document.getElementById(id);
this.pageDirection = document.documentElement.getAttribute("lang-direction"); this.pageDirection = document.documentElement.getAttribute("lang-direction");
var styleElement = document.createElement('link'); var styleElement = document.createElement("link");
styleElement.rel = 'stylesheet'; styleElement.rel = "stylesheet";
styleElement.href = 'css/pdfActions.css' styleElement.href = "css/pdfActions.css";
document.head.appendChild(styleElement); document.head.appendChild(styleElement);
} }
getPageContainer(element) { getPageContainer(element) {
var container = element var container = element;
while (!container.classList.contains('page-container')) { while (!container.classList.contains("page-container")) {
container = container.parentNode; container = container.parentNode;
} }
return container; return container;
@ -36,29 +36,29 @@ class PdfActionsManager {
if (sibling) { if (sibling) {
this.movePageTo(imgContainer, sibling.nextSibling, true); this.movePageTo(imgContainer, sibling.nextSibling, true);
} }
}; }
rotateCCWButtonCallback(e) { rotateCCWButtonCallback(e) {
var imgContainer = this.getPageContainer(e.target); var imgContainer = this.getPageContainer(e.target);
const img = imgContainer.querySelector("img"); const img = imgContainer.querySelector("img");
this.rotateElement(img, -90) this.rotateElement(img, -90);
}; }
rotateCWButtonCallback(e) { rotateCWButtonCallback(e) {
var imgContainer = this.getPageContainer(e.target); var imgContainer = this.getPageContainer(e.target);
const img = imgContainer.querySelector("img"); const img = imgContainer.querySelector("img");
this.rotateElement(img, 90) this.rotateElement(img, 90);
}; }
deletePageButtonCallback(e) { deletePageButtonCallback(e) {
var imgContainer = this.getPageContainer(e.target); var imgContainer = this.getPageContainer(e.target);
this.pagesContainer.removeChild(imgContainer); this.pagesContainer.removeChild(imgContainer);
if (this.pagesContainer.childElementCount === 0) { if (this.pagesContainer.childElementCount === 0) {
const filenameInput = document.getElementById('filename-input'); const filenameInput = document.getElementById("filename-input");
const filenameParagraph = document.getElementById('filename'); const filenameParagraph = document.getElementById("filename");
const downloadBtn = document.getElementById('export-button'); const downloadBtn = document.getElementById("export-button");
filenameInput.disabled = true; filenameInput.disabled = true;
filenameInput.value = ""; filenameInput.value = "";
@ -66,12 +66,12 @@ class PdfActionsManager {
downloadBtn.disabled = true; downloadBtn.disabled = true;
} }
}; }
insertFileButtonCallback(e) { insertFileButtonCallback(e) {
var imgContainer = this.getPageContainer(e.target); var imgContainer = this.getPageContainer(e.target);
this.addPdfs(imgContainer) this.addPdfs(imgContainer);
}; }
setActions({ movePageTo, addPdfs, rotateElement }) { setActions({ movePageTo, addPdfs, rotateElement }) {
this.movePageTo = movePageTo; this.movePageTo = movePageTo;
@ -87,26 +87,26 @@ class PdfActionsManager {
} }
adapt(div) { adapt(div) {
div.classList.add('pdf-actions_container'); div.classList.add("pdf-actions_container");
const leftDirection = this.pageDirection === 'rtl' ? 'right' : 'left' const leftDirection = this.pageDirection === "rtl" ? "right" : "left";
const rightDirection = this.pageDirection === 'rtl' ? 'left' : 'right' const rightDirection = this.pageDirection === "rtl" ? "left" : "right";
const buttonContainer = document.createElement('div'); const buttonContainer = document.createElement("div");
buttonContainer.classList.add("pdf-actions_button-container", "hide-on-drag"); buttonContainer.classList.add("pdf-actions_button-container", "hide-on-drag");
const moveUp = document.createElement('button'); const moveUp = document.createElement("button");
moveUp.classList.add("pdf-actions_move-left-button", "btn", "btn-secondary"); moveUp.classList.add("pdf-actions_move-left-button", "btn", "btn-secondary");
moveUp.innerHTML = `<i class="bi bi-arrow-${leftDirection}-short"></i>`; moveUp.innerHTML = `<i class="bi bi-arrow-${leftDirection}-short"></i>`;
moveUp.onclick = this.moveUpButtonCallback; moveUp.onclick = this.moveUpButtonCallback;
buttonContainer.appendChild(moveUp); buttonContainer.appendChild(moveUp);
const moveDown = document.createElement('button'); const moveDown = document.createElement("button");
moveDown.classList.add("pdf-actions_move-right-button", "btn", "btn-secondary"); moveDown.classList.add("pdf-actions_move-right-button", "btn", "btn-secondary");
moveDown.innerHTML = `<i class="bi bi-arrow-${rightDirection}-short"></i>`; moveDown.innerHTML = `<i class="bi bi-arrow-${rightDirection}-short"></i>`;
moveDown.onclick = this.moveDownButtonCallback; moveDown.onclick = this.moveDownButtonCallback;
buttonContainer.appendChild(moveDown); buttonContainer.appendChild(moveDown);
const rotateCCW = document.createElement('button'); const rotateCCW = document.createElement("button");
rotateCCW.classList.add("btn", "btn-secondary"); rotateCCW.classList.add("btn", "btn-secondary");
rotateCCW.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16"> rotateCCW.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z" /> <path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z" />
@ -115,7 +115,7 @@ class PdfActionsManager {
rotateCCW.onclick = this.rotateCCWButtonCallback; rotateCCW.onclick = this.rotateCCWButtonCallback;
buttonContainer.appendChild(rotateCCW); buttonContainer.appendChild(rotateCCW);
const rotateCW = document.createElement('button'); const rotateCW = document.createElement("button");
rotateCW.classList.add("btn", "btn-secondary"); rotateCW.classList.add("btn", "btn-secondary");
rotateCW.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16"> rotateCW.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" /> <path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" />
@ -124,7 +124,7 @@ class PdfActionsManager {
rotateCW.onclick = this.rotateCWButtonCallback; rotateCW.onclick = this.rotateCWButtonCallback;
buttonContainer.appendChild(rotateCW); buttonContainer.appendChild(rotateCW);
const deletePage = document.createElement('button'); const deletePage = document.createElement("button");
deletePage.classList.add("btn", "btn-danger"); deletePage.classList.add("btn", "btn-danger");
deletePage.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16"> deletePage.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6Z"/> <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6Z"/>
@ -135,14 +135,15 @@ class PdfActionsManager {
div.appendChild(buttonContainer); div.appendChild(buttonContainer);
const insertFileButtonContainer = document.createElement('div'); const insertFileButtonContainer = document.createElement("div");
insertFileButtonContainer.classList.add( insertFileButtonContainer.classList.add(
"pdf-actions_insert-file-button-container", "pdf-actions_insert-file-button-container",
leftDirection, leftDirection,
`align-center-${leftDirection}`); `align-center-${leftDirection}`,
);
const insertFileButton = document.createElement('button'); const insertFileButton = document.createElement("button");
insertFileButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button"); insertFileButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button");
insertFileButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-earmark-plus" viewBox="0 0 16 16"> insertFileButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-earmark-plus" viewBox="0 0 16 16">
<path d="M8 6.5a.5.5 0 0 1 .5.5v1.5H10a.5.5 0 0 1 0 1H8.5V11a.5.5 0 0 1-1 0V9.5H6a.5.5 0 0 1 0-1h1.5V7a.5.5 0 0 1 .5-.5z"/> <path d="M8 6.5a.5.5 0 0 1 .5.5v1.5H10a.5.5 0 0 1 0 1H8.5V11a.5.5 0 0 1-1 0V9.5H6a.5.5 0 0 1 0-1h1.5V7a.5.5 0 0 1 .5-.5z"/>
@ -154,13 +155,14 @@ class PdfActionsManager {
div.appendChild(insertFileButtonContainer); div.appendChild(insertFileButtonContainer);
// add this button to every element, but only show it on the last one :D // add this button to every element, but only show it on the last one :D
const insertFileButtonRightContainer = document.createElement('div'); const insertFileButtonRightContainer = document.createElement("div");
insertFileButtonRightContainer.classList.add( insertFileButtonRightContainer.classList.add(
"pdf-actions_insert-file-button-container", "pdf-actions_insert-file-button-container",
rightDirection, rightDirection,
`align-center-${rightDirection}`); `align-center-${rightDirection}`,
);
const insertFileButtonRight = document.createElement('button'); const insertFileButtonRight = document.createElement("button");
insertFileButtonRight.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button"); insertFileButtonRight.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button");
insertFileButtonRight.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-earmark-plus" viewBox="0 0 16 16"> insertFileButtonRight.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-earmark-plus" viewBox="0 0 16 16">
<path d="M8 6.5a.5.5 0 0 1 .5.5v1.5H10a.5.5 0 0 1 0 1H8.5V11a.5.5 0 0 1-1 0V9.5H6a.5.5 0 0 1 0-1h1.5V7a.5.5 0 0 1 .5-.5z"/> <path d="M8 6.5a.5.5 0 0 1 .5.5v1.5H10a.5.5 0 0 1 0 1H8.5V11a.5.5 0 0 1-1 0V9.5H6a.5.5 0 0 1 0-1h1.5V7a.5.5 0 0 1 .5-.5z"/>
@ -172,20 +174,20 @@ class PdfActionsManager {
div.appendChild(insertFileButtonRightContainer); div.appendChild(insertFileButtonRightContainer);
const adaptPageNumber = (pageNumber, div) => { const adaptPageNumber = (pageNumber, div) => {
const pageNumberElement = document.createElement('span'); const pageNumberElement = document.createElement("span");
pageNumberElement.classList.add('page-number'); pageNumberElement.classList.add("page-number");
pageNumberElement.textContent = pageNumber; pageNumberElement.textContent = pageNumber;
div.insertBefore(pageNumberElement, div.firstChild); div.insertBefore(pageNumberElement, div.firstChild);
}; };
div.addEventListener('mouseenter', () => { div.addEventListener("mouseenter", () => {
const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1; const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1;
adaptPageNumber(pageNumber, div); adaptPageNumber(pageNumber, div);
}); });
div.addEventListener('mouseleave', () => { div.addEventListener("mouseleave", () => {
const pageNumberElement = div.querySelector('.page-number'); const pageNumberElement = div.querySelector(".page-number");
if (pageNumberElement) { if (pageNumberElement) {
div.removeChild(pageNumberElement); div.removeChild(pageNumberElement);
} }

View File

@ -6,7 +6,7 @@ class PdfContainer {
downloadLink; downloadLink;
constructor(id, wrapperId, pdfAdapters) { constructor(id, wrapperId, pdfAdapters) {
this.pagesContainer = document.getElementById(id) this.pagesContainer = document.getElementById(id);
this.pagesContainerWrapper = document.getElementById(wrapperId); this.pagesContainerWrapper = document.getElementById(wrapperId);
this.downloadLink = null; this.downloadLink = null;
this.movePageTo = this.movePageTo.bind(this); this.movePageTo = this.movePageTo.bind(this);
@ -21,21 +21,21 @@ class PdfContainer {
this.pdfAdapters = pdfAdapters; this.pdfAdapters = pdfAdapters;
this.pdfAdapters.forEach(adapter => { this.pdfAdapters.forEach((adapter) => {
adapter.setActions({ adapter.setActions({
movePageTo: this.movePageTo, movePageTo: this.movePageTo,
addPdfs: this.addPdfs, addPdfs: this.addPdfs,
rotateElement: this.rotateElement, rotateElement: this.rotateElement,
updateFilename: this.updateFilename updateFilename: this.updateFilename,
}) });
}) });
window.addPdfs = this.addPdfs; window.addPdfs = this.addPdfs;
window.exportPdf = this.exportPdf; window.exportPdf = this.exportPdf;
window.rotateAll = this.rotateAll; window.rotateAll = this.rotateAll;
const filenameInput = document.getElementById('filename-input'); const filenameInput = document.getElementById("filename-input");
const downloadBtn = document.getElementById('export-button'); const downloadBtn = document.getElementById("export-button");
filenameInput.onkeyup = this.updateFilename; filenameInput.onkeyup = this.updateFilename;
filenameInput.onkeydown = this.preventIllegalChars; filenameInput.onkeydown = this.preventIllegalChars;
@ -57,19 +57,17 @@ class PdfContainer {
if (scrollTo) { if (scrollTo) {
const { width } = startElement.getBoundingClientRect(); const { width } = startElement.getBoundingClientRect();
const vector = (endIndex !== -1 && startIndex > endIndex) const vector = endIndex !== -1 && startIndex > endIndex ? 0 - width : width;
? 0-width
: width;
this.pagesContainerWrapper.scroll({ this.pagesContainerWrapper.scroll({
left: this.pagesContainerWrapper.scrollLeft + vector, left: this.pagesContainerWrapper.scrollLeft + vector,
}) });
} }
} }
addPdfs(nextSiblingElement) { addPdfs(nextSiblingElement) {
var input = document.createElement('input'); var input = document.createElement("input");
input.type = 'file'; input.type = "file";
input.multiple = true; input.multiple = true;
input.setAttribute("accept", "application/pdf"); input.setAttribute("accept", "application/pdf");
input.onchange = async (e) => { input.onchange = async (e) => {
@ -77,7 +75,7 @@ class PdfContainer {
this.addPdfsFromFiles(files, nextSiblingElement); this.addPdfsFromFiles(files, nextSiblingElement);
this.updateFilename(files ? files[0].name : ""); this.updateFilename(files ? files[0].name : "");
} };
input.click(); input.click();
} }
@ -88,7 +86,7 @@ class PdfContainer {
await this.addPdfFile(files[i], nextSiblingElement); await this.addPdfFile(files[i], nextSiblingElement);
} }
document.querySelectorAll(".enable-on-file").forEach(element => { document.querySelectorAll(".enable-on-file").forEach((element) => {
element.disabled = false; element.disabled = false;
}); });
} }
@ -98,7 +96,7 @@ class PdfContainer {
if (!lastTransform) { if (!lastTransform) {
lastTransform = "0"; lastTransform = "0";
} }
const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, '')); const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, ""));
const newAngle = lastAngle + deg; const newAngle = lastAngle + deg;
element.style.rotate = newAngle + "deg"; element.style.rotate = newAngle + "deg";
@ -108,13 +106,13 @@ class PdfContainer {
const { renderer, pdfDocument } = await this.loadFile(file); const { renderer, pdfDocument } = await this.loadFile(file);
for (var i = 0; i < renderer.pageCount; i++) { for (var i = 0; i < renderer.pageCount; i++) {
const div = document.createElement('div'); const div = document.createElement("div");
div.classList.add("page-container"); div.classList.add("page-container");
var img = document.createElement('img'); var img = document.createElement("img");
img.classList.add('page-image') img.classList.add("page-image");
const imageSrc = await renderer.renderPage(i) const imageSrc = await renderer.renderPage(i);
img.src = imageSrc; img.src = imageSrc;
img.pageIdx = i; img.pageIdx = i;
img.rend = renderer; img.rend = renderer;
@ -122,8 +120,8 @@ class PdfContainer {
div.appendChild(img); div.appendChild(img);
this.pdfAdapters.forEach((adapter) => { this.pdfAdapters.forEach((adapter) => {
adapter.adapt?.(div) adapter.adapt?.(div);
}) });
if (nextSiblingElement) { if (nextSiblingElement) {
this.pagesContainer.insertBefore(div, nextSiblingElement); this.pagesContainer.insertBefore(div, nextSiblingElement);
} else { } else {
@ -140,7 +138,7 @@ class PdfContainer {
} }
async toRenderer(objectUrl) { async toRenderer(objectUrl) {
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js' pdfjsLib.GlobalWorkerOptions.workerSrc = "pdfjs/pdf.worker.js";
const pdf = await pdfjsLib.getDocument(objectUrl).promise; const pdf = await pdfjsLib.getDocument(objectUrl).promise;
return { return {
document: pdf, document: pdf,
@ -162,104 +160,103 @@ class PdfContainer {
// render the page onto the canvas // render the page onto the canvas
var renderContext = { var renderContext = {
canvasContext: canvas.getContext("2d"), canvasContext: canvas.getContext("2d"),
viewport: page.getViewport({ scale: 1 }) viewport: page.getViewport({ scale: 1 }),
}; };
await page.render(renderContext).promise; await page.render(renderContext).promise;
return canvas.toDataURL(); return canvas.toDataURL();
} },
}; };
} }
async toPdfLib(objectUrl) { async toPdfLib(objectUrl) {
const existingPdfBytes = await fetch(objectUrl).then(res => res.arrayBuffer()); const existingPdfBytes = await fetch(objectUrl).then((res) => res.arrayBuffer());
const pdfDoc = await PDFLib.PDFDocument.load(existingPdfBytes, { ignoreEncryption: true }); const pdfDoc = await PDFLib.PDFDocument.load(existingPdfBytes, {
ignoreEncryption: true,
});
return pdfDoc; return pdfDoc;
} }
rotateAll(deg) { rotateAll(deg) {
for (var i = 0; i < this.pagesContainer.childNodes.length; i++) { for (var i = 0; i < this.pagesContainer.childNodes.length; i++) {
const img = this.pagesContainer.childNodes[i].querySelector("img"); const img = this.pagesContainer.childNodes[i].querySelector("img");
if (!img) continue; if (!img) continue;
this.rotateElement(img, deg) this.rotateElement(img, deg);
} }
} }
async exportPdf() { async exportPdf() {
const pdfDoc = await PDFLib.PDFDocument.create(); const pdfDoc = await PDFLib.PDFDocument.create();
const pageContainers = this.pagesContainer.querySelectorAll('.page-container'); // Select all .page-container elements const pageContainers = this.pagesContainer.querySelectorAll(".page-container"); // Select all .page-container elements
for (var i = 0; i < pageContainers.length; i++) { for (var i = 0; i < pageContainers.length; i++) {
const img = pageContainers[i].querySelector("img"); // Find the img element within each .page-container const img = pageContainers[i].querySelector("img"); // Find the img element within each .page-container
if (!img) continue; if (!img) continue;
const pages = await pdfDoc.copyPages(img.doc, [img.pageIdx]) const pages = await pdfDoc.copyPages(img.doc, [img.pageIdx]);
const page = pages[0]; const page = pages[0];
const rotation = img.style.rotate; const rotation = img.style.rotate;
if (rotation) { if (rotation) {
const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, '')); const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, ""));
page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle)) page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle));
} }
pdfDoc.addPage(page); pdfDoc.addPage(page);
} }
const pdfBytes = await pdfDoc.save(); const pdfBytes = await pdfDoc.save();
const pdfBlob = new Blob([pdfBytes], { type: 'application/pdf' }); const pdfBlob = new Blob([pdfBytes], { type: "application/pdf" });
const url = URL.createObjectURL(pdfBlob); const url = URL.createObjectURL(pdfBlob);
const downloadOption = localStorage.getItem('downloadOption'); const downloadOption = localStorage.getItem("downloadOption");
const filenameInput = document.getElementById('filename-input'); const filenameInput = document.getElementById("filename-input");
let inputArr = filenameInput.value.split('.'); let inputArr = filenameInput.value.split(".");
if (inputArr !== null && inputArr !== undefined && inputArr.length > 0) { if (inputArr !== null && inputArr !== undefined && inputArr.length > 0) {
inputArr = inputArr.filter((n) => n); // remove all empty strings, nulls or undefined
inputArr = inputArr.filter(n => n); // remove all empty strings, nulls or undefined
if (inputArr.length > 1) { if (inputArr.length > 1) {
inputArr.pop(); // remove right part after last dot inputArr.pop(); // remove right part after last dot
} }
filenameInput.value = inputArr.join(''); filenameInput.value = inputArr.join("");
this.fileName = filenameInput.value; this.fileName = filenameInput.value;
} }
if (!filenameInput.value.includes('.pdf')) { if (!filenameInput.value.includes(".pdf")) {
filenameInput.value = filenameInput.value + '.pdf'; filenameInput.value = filenameInput.value + ".pdf";
this.fileName = filenameInput.value; this.fileName = filenameInput.value;
} }
if (downloadOption === 'sameWindow') { if (downloadOption === "sameWindow") {
// Open the file in the same window // Open the file in the same window
window.location.href = url; window.location.href = url;
} else if (downloadOption === 'newWindow') { } else if (downloadOption === "newWindow") {
// Open the file in a new window // Open the file in a new window
window.open(url, '_blank'); window.open(url, "_blank");
} else { } else {
// Download the file // Download the file
this.downloadLink = document.createElement('a'); this.downloadLink = document.createElement("a");
this.downloadLink.id = 'download-link'; this.downloadLink.id = "download-link";
this.downloadLink.href = url; this.downloadLink.href = url;
// downloadLink.download = this.fileName ? this.fileName : 'managed.pdf'; // downloadLink.download = this.fileName ? this.fileName : 'managed.pdf';
// downloadLink.download = this.fileName; // downloadLink.download = this.fileName;
this.downloadLink.setAttribute('download', this.fileName ? this.fileName : 'managed.pdf'); this.downloadLink.setAttribute("download", this.fileName ? this.fileName : "managed.pdf");
this.downloadLink.setAttribute('target', '_blank'); this.downloadLink.setAttribute("target", "_blank");
this.downloadLink.onclick = this.setDownloadAttribute; this.downloadLink.onclick = this.setDownloadAttribute;
this.downloadLink.click(); this.downloadLink.click();
} }
} }
setDownloadAttribute() { setDownloadAttribute() {
this.downloadLink.setAttribute("download", this.fileName ? this.fileName : 'managed.pdf'); this.downloadLink.setAttribute("download", this.fileName ? this.fileName : "managed.pdf");
} }
updateFilename(fileName = "") { updateFilename(fileName = "") {
const filenameInput = document.getElementById('filename-input'); const filenameInput = document.getElementById("filename-input");
const pagesContainer = document.getElementById('pages-container'); const pagesContainer = document.getElementById("pages-container");
const downloadBtn = document.getElementById('export-button'); const downloadBtn = document.getElementById("export-button");
downloadBtn.disabled = pagesContainer.childElementCount === 0 downloadBtn.disabled = pagesContainer.childElementCount === 0;
if (!this.fileName) { if (!this.fileName) {
this.fileName = fileName; this.fileName = fileName;

View File

@ -8,7 +8,7 @@ class FileDragManager {
this.setCallback(cb); this.setCallback(cb);
// Prevent default behavior for drag events // Prevent default behavior for drag events
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => {
document.body.addEventListener(eventName, preventDefaults, false); document.body.addEventListener(eventName, preventDefaults, false);
}); });
@ -21,10 +21,10 @@ class FileDragManager {
this.dragleaveListener = this.dragleaveListener.bind(this); this.dragleaveListener = this.dragleaveListener.bind(this);
this.dropListener = this.dropListener.bind(this); this.dropListener = this.dropListener.bind(this);
document.body.addEventListener('dragenter', this.dragenterListener); document.body.addEventListener("dragenter", this.dragenterListener);
document.body.addEventListener('dragleave', this.dragleaveListener); document.body.addEventListener("dragleave", this.dragleaveListener);
// Add drop event listener // Add drop event listener
document.body.addEventListener('drop', this.dropListener); document.body.addEventListener("drop", this.dropListener);
} }
setActions({ updateFilename }) { setActions({ updateFilename }) {
@ -43,23 +43,23 @@ class FileDragManager {
this.dragCounter++; this.dragCounter++;
if (!this.overlay) { if (!this.overlay) {
// Create and show the overlay // Create and show the overlay
this.overlay = document.createElement('div'); this.overlay = document.createElement("div");
this.overlay.style.position = 'fixed'; this.overlay.style.position = "fixed";
this.overlay.style.top = 0; this.overlay.style.top = 0;
this.overlay.style.left = 0; this.overlay.style.left = 0;
this.overlay.style.width = '100%'; this.overlay.style.width = "100%";
this.overlay.style.height = '100%'; this.overlay.style.height = "100%";
this.overlay.style.background = 'rgba(0, 0, 0, 0.5)'; this.overlay.style.background = "rgba(0, 0, 0, 0.5)";
this.overlay.style.color = '#fff'; this.overlay.style.color = "#fff";
this.overlay.style.zIndex = '1000'; this.overlay.style.zIndex = "1000";
this.overlay.style.display = 'flex'; this.overlay.style.display = "flex";
this.overlay.style.alignItems = 'center'; this.overlay.style.alignItems = "center";
this.overlay.style.justifyContent = 'center'; this.overlay.style.justifyContent = "center";
this.overlay.style.pointerEvents = 'none'; this.overlay.style.pointerEvents = "none";
this.overlay.innerHTML = '<p>Drop files anywhere to upload</p>'; this.overlay.innerHTML = "<p>Drop files anywhere to upload</p>";
document.getElementById('content-wrap').appendChild(this.overlay); document.getElementById("content-wrap").appendChild(this.overlay);
}
} }
};
dragleaveListener() { dragleaveListener() {
this.dragCounter--; this.dragCounter--;
@ -70,16 +70,17 @@ class FileDragManager {
this.overlay = null; this.overlay = null;
} }
} }
}; }
dropListener(e) { dropListener(e) {
const dt = e.dataTransfer; const dt = e.dataTransfer;
const files = dt.files; const files = dt.files;
this.callback(files).catch((err) => { this.callback(files)
.catch((err) => {
console.error(err); console.error(err);
//maybe //maybe
}).finally(() => { })
.finally(() => {
// Hide and remove the overlay // Hide and remove the overlay
if (this.overlay) { if (this.overlay) {
this.overlay.remove(); this.overlay.remove();
@ -88,7 +89,7 @@ class FileDragManager {
this.updateFilename(files ? files[0].name : ""); this.updateFilename(files ? files[0].name : "");
}); });
}; }
} }
export default FileDragManager; export default FileDragManager;

View File

@ -1,7 +1,7 @@
const scrollDivHorizontally = (id) => { const scrollDivHorizontally = (id) => {
var scrollDelta = 0; // variable to store the accumulated scroll delta var scrollDelta = 0; // variable to store the accumulated scroll delta
var isScrolling = false; // variable to track if scroll is already in progress var isScrolling = false; // variable to track if scroll is already in progress
const divToScrollHorizontally = document.getElementById(id) const divToScrollHorizontally = document.getElementById(id);
function scrollLoop() { function scrollLoop() {
// Scroll the div horizontally by a fraction of the accumulated scroll delta // Scroll the div horizontally by a fraction of the accumulated scroll delta
divToScrollHorizontally.scrollLeft += scrollDelta * 0.1; divToScrollHorizontally.scrollLeft += scrollDelta * 0.1;
@ -17,7 +17,6 @@ const scrollDivHorizontally = (id) => {
} }
} }
divToScrollHorizontally.addEventListener("wheel", function (e) { divToScrollHorizontally.addEventListener("wheel", function (e) {
e.preventDefault(); // prevent default mousewheel behavior e.preventDefault(); // prevent default mousewheel behavior
@ -30,6 +29,6 @@ const scrollDivHorizontally = (id) => {
requestAnimationFrame(scrollLoop); requestAnimationFrame(scrollLoop);
} }
}); });
} };
export default scrollDivHorizontally; export default scrollDivHorizontally;

View File

@ -1,15 +1,15 @@
document.getElementById('validateButton').addEventListener('click', function(event) { document.getElementById("validateButton").addEventListener("click", function (event) {
event.preventDefault(); event.preventDefault();
validatePipeline(); validatePipeline();
}); });
function validatePipeline() { function validatePipeline() {
let pipelineListItems = document.getElementById('pipelineList').children; let pipelineListItems = document.getElementById("pipelineList").children;
let isValid = true; let isValid = true;
let containsAddPassword = false; let containsAddPassword = false;
for (let i = 0; i < pipelineListItems.length - 1; i++) { for (let i = 0; i < pipelineListItems.length - 1; i++) {
let currentOperation = pipelineListItems[i].querySelector('.operationName').textContent; let currentOperation = pipelineListItems[i].querySelector(".operationName").textContent;
let nextOperation = pipelineListItems[i + 1].querySelector('.operationName').textContent; let nextOperation = pipelineListItems[i + 1].querySelector(".operationName").textContent;
if (currentOperation === '/add-password') { if (currentOperation === "/add-password") {
containsAddPassword = true; containsAddPassword = true;
} }
@ -17,39 +17,46 @@ function validatePipeline() {
let nextOperationDescription = apiDocs[nextOperation]?.post?.description || ""; let nextOperationDescription = apiDocs[nextOperation]?.post?.description || "";
// Strip off 'ZIP-' prefix // Strip off 'ZIP-' prefix
currentOperationDescription = currentOperationDescription.replace("ZIP-", ''); currentOperationDescription = currentOperationDescription.replace("ZIP-", "");
nextOperationDescription = nextOperationDescription.replace("ZIP-", ''); nextOperationDescription = nextOperationDescription.replace("ZIP-", "");
let currentOperationOutput = currentOperationDescription.match(/Output:([A-Z\/]*)/)?.[1] || ""; let currentOperationOutput = currentOperationDescription.match(/Output:([A-Z\/]*)/)?.[1] || "";
let nextOperationInput = nextOperationDescription.match(/Input:([A-Z\/]*)/)?.[1] || ""; let nextOperationInput = nextOperationDescription.match(/Input:([A-Z\/]*)/)?.[1] || "";
// Splitting in case of multiple possible output/input // Splitting in case of multiple possible output/input
let currentOperationOutputArr = currentOperationOutput.split('/'); let currentOperationOutputArr = currentOperationOutput.split("/");
let nextOperationInputArr = nextOperationInput.split('/'); let nextOperationInputArr = nextOperationInput.split("/");
if (currentOperationOutput !== 'ANY' && nextOperationInput !== 'ANY') { if (currentOperationOutput !== "ANY" && nextOperationInput !== "ANY") {
let intersection = currentOperationOutputArr.filter(value => nextOperationInputArr.includes(value)); let intersection = currentOperationOutputArr.filter((value) => nextOperationInputArr.includes(value));
console.log(`Intersection: ${intersection}`); console.log(`Intersection: ${intersection}`);
if (intersection.length === 0) { if (intersection.length === 0) {
updateValidateButton(false); updateValidateButton(false);
isValid = 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}).`); console.log(
alert(`Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`); `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; break;
} }
} }
} }
if (containsAddPassword && pipelineListItems[pipelineListItems.length - 1].querySelector('.operationName').textContent !== '/add-password') { if (
containsAddPassword &&
pipelineListItems[pipelineListItems.length - 1].querySelector(".operationName").textContent !== "/add-password"
) {
updateValidateButton(false); updateValidateButton(false);
alert('The "add-password" operation should be at the end of the operations sequence. Please adjust the operations order.'); alert('The "add-password" operation should be at the end of the operations sequence. Please adjust the operations order.');
return false; return false;
} }
if (isValid) { if (isValid) {
console.log('Pipeline is valid'); console.log("Pipeline is valid");
// Continue with the pipeline operation // Continue with the pipeline operation
} else { } else {
console.error('Pipeline is not valid'); console.error("Pipeline is not valid");
// Stop operation, maybe display an error to the user // Stop operation, maybe display an error to the user
} }
updateValidateButton(isValid); updateValidateButton(isValid);
@ -57,97 +64,79 @@ function validatePipeline() {
} }
function updateValidateButton(isValid) { function updateValidateButton(isValid) {
var validateButton = document.getElementById('validateButton'); var validateButton = document.getElementById("validateButton");
if (isValid) { if (isValid) {
validateButton.classList.remove('btn-danger'); validateButton.classList.remove("btn-danger");
validateButton.classList.add('btn-success'); validateButton.classList.add("btn-success");
} else { } else {
validateButton.classList.remove('btn-success'); validateButton.classList.remove("btn-success");
validateButton.classList.add('btn-danger'); validateButton.classList.add("btn-danger");
} }
} }
document.getElementById("submitConfigBtn").addEventListener("click", function () {
document.getElementById('submitConfigBtn').addEventListener('click', function() {
if (validatePipeline() === false) { if (validatePipeline() === false) {
return; return;
} }
let selectedOperation = document.getElementById('operationsDropdown').value; let selectedOperation = document.getElementById("operationsDropdown").value;
var pipelineName = document.getElementById("pipelineName").value;
let pipelineList = document.getElementById("pipelineList").children;
var pipelineName = document.getElementById('pipelineName').value;
let pipelineList = document.getElementById('pipelineList').children;
let pipelineConfig = { let pipelineConfig = {
"name": pipelineName, name: pipelineName,
"pipeline": [], pipeline: [],
"_examples": { _examples: {
"outputDir": "{outputFolder}/{folderName}", outputDir: "{outputFolder}/{folderName}",
"outputFileName": "{filename}-{pipelineName}-{date}-{time}" outputFileName: "{filename}-{pipelineName}-{date}-{time}",
}, },
"outputDir": "httpWebRequest", outputDir: "httpWebRequest",
"outputFileName": "{filename}" outputFileName: "{filename}",
}; };
for (let i = 0; i < pipelineList.length; i++) { for (let i = 0; i < pipelineList.length; i++) {
let operationName = pipelineList[i].querySelector('.operationName').textContent; let operationName = pipelineList[i].querySelector(".operationName").textContent;
let parameters = operationSettings[operationName] || {}; let parameters = operationSettings[operationName] || {};
pipelineConfig.pipeline.push({ pipelineConfig.pipeline.push({
"operation": operationName, operation: operationName,
"parameters": parameters parameters: parameters,
}); });
} }
let pipelineConfigJson = JSON.stringify(pipelineConfig, null, 2); let pipelineConfigJson = JSON.stringify(pipelineConfig, null, 2);
let formData = new FormData(); let formData = new FormData();
let fileInput = document.getElementById('fileInput-input'); let fileInput = document.getElementById("fileInput-input");
let files = fileInput.files; let files = fileInput.files;
for (let i = 0; i < files.length; i++) { for (let i = 0; i < files.length; i++) {
console.log("files[i]", files[i].name); console.log("files[i]", files[i].name);
formData.append('fileInput', files[i], files[i].name); formData.append("fileInput", files[i], files[i].name);
} }
console.log("pipelineConfigJson", pipelineConfigJson); console.log("pipelineConfigJson", pipelineConfigJson);
formData.append('json', pipelineConfigJson); formData.append("json", pipelineConfigJson);
console.log("formData", formData); console.log("formData", formData);
fetch('api/v1/pipeline/handleData', { fetch("api/v1/pipeline/handleData", {
method: 'POST', method: "POST",
body: formData body: formData,
}) })
.then(response => { .then((response) => {
// Save the response to use it later // Save the response to use it later
const responseToUseLater = response; const responseToUseLater = response;
return response.blob().then(blob => { return response.blob().then((blob) => {
let url = window.URL.createObjectURL(blob); let url = window.URL.createObjectURL(blob);
let a = document.createElement('a'); let a = document.createElement("a");
a.href = url; a.href = url;
// Use responseToUseLater instead of response // Use responseToUseLater instead of response
const contentDisposition = responseToUseLater.headers.get('Content-Disposition'); const contentDisposition = responseToUseLater.headers.get("Content-Disposition");
let filename = 'download'; let filename = "download";
if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) { if (contentDisposition && contentDisposition.indexOf("attachment") !== -1) {
filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, '')).trim(); filename = decodeURIComponent(contentDisposition.split("filename=")[1].replace(/"/g, "")).trim();
} }
a.download = filename; a.download = filename;
@ -157,30 +146,28 @@ document.getElementById('submitConfigBtn').addEventListener('click', function()
}); });
}) })
.catch((error) => { .catch((error) => {
console.error('Error:', error); console.error("Error:", error);
}); });
}); });
let apiDocs = {}; let apiDocs = {};
let apiSchemas = {}; let apiSchemas = {};
let operationSettings = {}; let operationSettings = {};
fetch('v1/api-docs') fetch("v1/api-docs")
.then(response => response.json()) .then((response) => response.json())
.then(data => { .then((data) => {
apiDocs = data.paths; apiDocs = data.paths;
apiSchemas = data.components.schemas; apiSchemas = data.components.schemas;
let operationsDropdown = document.getElementById('operationsDropdown'); let operationsDropdown = document.getElementById("operationsDropdown");
const ignoreOperations = ["/api/v1/pipeline/handleData", "/api/v1/pipeline/operationToIgnore"]; // Add the operations you want to ignore here 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 // Group operations by tags
Object.keys(data.paths).forEach(operationPath => { Object.keys(data.paths).forEach((operationPath) => {
let operation = data.paths[operationPath].post; let operation = data.paths[operationPath].post;
if (!operation || !operation.description) { if (!operation || !operation.description) {
console.log(operationPath); console.log(operationPath);
@ -196,7 +183,7 @@ fetch('v1/api-docs')
}); });
// Sort operations within each tag alphabetically // Sort operations within each tag alphabetically
Object.keys(operationsByTag).forEach(tag => { Object.keys(operationsByTag).forEach((tag) => {
operationsByTag[tag].sort(); operationsByTag[tag].sort();
}); });
@ -204,22 +191,21 @@ fetch('v1/api-docs')
let tagOrder = ["General", "Security", "Convert", "Misc", "Filter"]; let tagOrder = ["General", "Security", "Convert", "Misc", "Filter"];
// Create dropdown options // Create dropdown options
tagOrder.forEach(tag => { tagOrder.forEach((tag) => {
if (operationsByTag[tag]) { if (operationsByTag[tag]) {
let group = document.createElement('optgroup'); let group = document.createElement("optgroup");
group.label = tag; group.label = tag;
operationsByTag[tag].forEach(operationPath => { operationsByTag[tag].forEach((operationPath) => {
let option = document.createElement('option'); 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")) { if (operationPath.includes("/convert")) {
operationPathDisplay = operationPathDisplay.replace(/^\//, '').replaceAll("/", " to "); operationPathDisplay = operationPathDisplay.replace(/^\//, "").replaceAll("/", " to ");
} else { } else {
operationPathDisplay = operationPathDisplay.replace(/\//g, ''); // Remove slashes operationPathDisplay = operationPathDisplay.replace(/\//g, ""); // Remove slashes
} }
operationPathDisplay = operationPathDisplay.replaceAll(" ", "-"); operationPathDisplay = operationPathDisplay.replaceAll(" ", "-");
option.textContent = operationPathDisplay; option.textContent = operationPathDisplay;
@ -232,12 +218,11 @@ fetch('v1/api-docs')
}); });
}); });
document.getElementById("addOperationBtn").addEventListener("click", function () {
let selectedOperation = document.getElementById("operationsDropdown").value;
let pipelineList = document.getElementById("pipelineList");
document.getElementById('addOperationBtn').addEventListener('click', function() { let listItem = document.createElement("li");
let selectedOperation = document.getElementById('operationsDropdown').value;
let pipelineList = document.getElementById('pipelineList');
let listItem = document.createElement('li');
listItem.className = "list-group-item"; listItem.className = "list-group-item";
let hasSettings = false; let hasSettings = false;
if (apiDocs[selectedOperation] && apiDocs[selectedOperation].post) { if (apiDocs[selectedOperation] && apiDocs[selectedOperation].post) {
@ -246,32 +231,31 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
// Check if parameters exist // Check if parameters exist
if (postMethod.parameters && postMethod.parameters.length > 0) { if (postMethod.parameters && postMethod.parameters.length > 0) {
hasSettings = true; hasSettings = true;
} else if (postMethod.requestBody && postMethod.requestBody.content['multipart/form-data']) { } else if (postMethod.requestBody && postMethod.requestBody.content["multipart/form-data"]) {
// Extract the reference key // Extract the reference key
const refKey = postMethod.requestBody.content['multipart/form-data'].schema['$ref'].split('/').pop(); 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 // Check if the referenced schema exists and has properties more than just its input file
if (apiSchemas[refKey]) { if (apiSchemas[refKey]) {
const properties = apiSchemas[refKey].properties; const properties = apiSchemas[refKey].properties;
const propertyKeys = Object.keys(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' // 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')) { if (propertyKeys.length > 1 || (propertyKeys.length === 1 && properties[propertyKeys[0]].format !== "binary")) {
hasSettings = true; hasSettings = true;
} }
} }
} }
} }
listItem.innerHTML = ` listItem.innerHTML = `
<div class="d-flex justify-content-between align-items-center w-100"> <div class="d-flex justify-content-between align-items-center w-100">
<div class="operationName">${selectedOperation}</div> <div class="operationName">${selectedOperation}</div>
<div class="arrows d-flex"> <div class="arrows d-flex">
<button class="btn btn-secondary move-up ms-1"><span>&uarr;</span></button> <button class="btn btn-secondary move-up ms-1"><span>&uarr;</span></button>
<button class="btn btn-secondary move-down ms-1"><span>&darr;</span></button> <button class="btn btn-secondary move-down ms-1"><span>&darr;</span></button>
<button class="btn ${hasSettings ? 'btn-warning' : 'btn-secondary'} pipelineSettings ms-1" ${hasSettings ? "" : "disabled"}> <button class="btn ${hasSettings ? "btn-warning" : "btn-secondary"} pipelineSettings ms-1" ${
hasSettings ? "" : "disabled"
}>
<span style="color: ${hasSettings ? "white" : "grey"};"></span> <span style="color: ${hasSettings ? "white" : "grey"};"></span>
</button> </button>
<button class="btn btn-danger remove ms-1"><span>X</span></button> <button class="btn btn-danger remove ms-1"><span>X</span></button>
@ -279,10 +263,9 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
</div> </div>
`; `;
pipelineList.appendChild(listItem); pipelineList.appendChild(listItem);
listItem.querySelector('.move-up').addEventListener('click', function(event) { listItem.querySelector(".move-up").addEventListener("click", function (event) {
event.preventDefault(); event.preventDefault();
if (listItem.previousElementSibling) { if (listItem.previousElementSibling) {
pipelineList.insertBefore(listItem, listItem.previousElementSibling); pipelineList.insertBefore(listItem, listItem.previousElementSibling);
@ -290,56 +273,57 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
} }
}); });
listItem.querySelector('.move-down').addEventListener('click', function(event) { listItem.querySelector(".move-down").addEventListener("click", function (event) {
event.preventDefault(); event.preventDefault();
if (listItem.nextElementSibling) { if (listItem.nextElementSibling) {
pipelineList.insertBefore(listItem.nextElementSibling, listItem); pipelineList.insertBefore(listItem.nextElementSibling, listItem);
updateConfigInDropdown(); updateConfigInDropdown();
} }
}); });
listItem.querySelector('.remove').addEventListener('click', function(event) { listItem.querySelector(".remove").addEventListener("click", function (event) {
event.preventDefault(); event.preventDefault();
pipelineList.removeChild(listItem); pipelineList.removeChild(listItem);
hideOrShowPipelineHeader(); hideOrShowPipelineHeader();
updateConfigInDropdown(); updateConfigInDropdown();
}); });
listItem.querySelector('.pipelineSettings').addEventListener('click', function(event) { listItem.querySelector(".pipelineSettings").addEventListener("click", function (event) {
event.preventDefault(); event.preventDefault();
showpipelineSettingsModal(selectedOperation); showpipelineSettingsModal(selectedOperation);
hideOrShowPipelineHeader(); hideOrShowPipelineHeader();
}); });
function showpipelineSettingsModal(operation) { function showpipelineSettingsModal(operation) {
let pipelineSettingsModal = document.getElementById('pipelineSettingsModal'); let pipelineSettingsModal = document.getElementById("pipelineSettingsModal");
let pipelineSettingsContent = document.getElementById('pipelineSettingsContent'); let pipelineSettingsContent = document.getElementById("pipelineSettingsContent");
let operationData = apiDocs[operation].post.parameters || []; let operationData = apiDocs[operation].post.parameters || [];
// Resolve the $ref reference to get actual schema properties // Resolve the $ref reference to get actual schema properties
let refKey = apiDocs[operation].post.requestBody.content['multipart/form-data'].schema['$ref'].split('/').pop(); let refKey = apiDocs[operation].post.requestBody.content["multipart/form-data"].schema["$ref"].split("/").pop();
let requestBodyData = apiSchemas[refKey].properties || {}; let requestBodyData = apiSchemas[refKey].properties || {};
// Combine operationData and requestBodyData into a single array // Combine operationData and requestBodyData into a single array
operationData = operationData.concat(Object.keys(requestBodyData).map(key => ({ operationData = operationData.concat(
Object.keys(requestBodyData).map((key) => ({
name: key, name: key,
schema: requestBodyData[key] schema: requestBodyData[key],
}))); })),
);
pipelineSettingsContent.innerHTML = ''; pipelineSettingsContent.innerHTML = "";
operationData.forEach(parameter => { operationData.forEach((parameter) => {
// If the parameter name is 'fileInput', return early to skip the rest of this iteration // If the parameter name is 'fileInput', return early to skip the rest of this iteration
if (parameter.name === 'fileInput') return; if (parameter.name === "fileInput") return;
let parameterDiv = document.createElement('div'); let parameterDiv = document.createElement("div");
parameterDiv.className = "mb-3"; parameterDiv.className = "mb-3";
let parameterLabel = document.createElement('label'); let parameterLabel = document.createElement("label");
parameterLabel.textContent = `${parameter.name} (${parameter.schema.type}): `; parameterLabel.textContent = `${parameter.name} (${parameter.schema.type}): `;
parameterLabel.title = parameter.schema.description; parameterLabel.title = parameter.schema.description;
parameterLabel.setAttribute('for', parameter.name); parameterLabel.setAttribute("for", parameter.name);
parameterDiv.appendChild(parameterLabel); parameterDiv.appendChild(parameterLabel);
let defaultValue = parameter.schema.example; let defaultValue = parameter.schema.example;
@ -350,12 +334,12 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
// check if enum exists in schema // check if enum exists in schema
if (parameter.schema.enum) { if (parameter.schema.enum) {
// if enum exists, create a select element // if enum exists, create a select element
parameterInput = document.createElement('select'); parameterInput = document.createElement("select");
parameterInput.className = "form-control"; parameterInput.className = "form-control";
// iterate over each enum value and create an option for it // iterate over each enum value and create an option for it
parameter.schema.enum.forEach(value => { parameter.schema.enum.forEach((value) => {
let option = document.createElement('option'); let option = document.createElement("option");
option.value = value; option.value = value;
option.text = value; option.text = value;
parameterInput.appendChild(option); parameterInput.appendChild(option);
@ -363,47 +347,47 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
} else { } else {
// switch-case statement for handling non-enum types // switch-case statement for handling non-enum types
switch (parameter.schema.type) { switch (parameter.schema.type) {
case 'string': case "string":
if (parameter.schema.format === 'binary') { if (parameter.schema.format === "binary") {
// This is a file input // This is a file input
//parameterInput = document.createElement('input'); //parameterInput = document.createElement('input');
//parameterInput.type = 'file'; //parameterInput.type = 'file';
//parameterInput.className = "form-control"; //parameterInput.className = "form-control";
parameterInput = document.createElement('input'); parameterInput = document.createElement("input");
parameterInput.type = 'text'; parameterInput.type = "text";
parameterInput.className = "form-control"; parameterInput.className = "form-control";
parameterInput.value = "FileInputPathToBeInputtedManuallyForOffline"; parameterInput.value = "FileInputPathToBeInputtedManuallyForOffline";
} else { } else {
parameterInput = document.createElement('input'); parameterInput = document.createElement("input");
parameterInput.type = 'text'; parameterInput.type = "text";
parameterInput.className = "form-control"; parameterInput.className = "form-control";
if (defaultValue !== undefined) parameterInput.value = defaultValue; if (defaultValue !== undefined) parameterInput.value = defaultValue;
} }
break; break;
case 'number': case "number":
case 'integer': case "integer":
parameterInput = document.createElement('input'); parameterInput = document.createElement("input");
parameterInput.type = 'number'; parameterInput.type = "number";
parameterInput.className = "form-control"; parameterInput.className = "form-control";
if (defaultValue !== undefined) parameterInput.value = defaultValue; if (defaultValue !== undefined) parameterInput.value = defaultValue;
break; break;
case 'boolean': case "boolean":
parameterInput = document.createElement('input'); parameterInput = document.createElement("input");
parameterInput.type = 'checkbox'; parameterInput.type = "checkbox";
if (defaultValue === true) parameterInput.checked = true; if (defaultValue === true) parameterInput.checked = true;
break; break;
case 'array': case "array":
case 'object': case "object":
//TODO compare to doc and check if fileInput array? parameter.schema.format === 'binary' //TODO compare to doc and check if fileInput array? parameter.schema.format === 'binary'
parameterInput = document.createElement('textarea'); parameterInput = document.createElement("textarea");
parameterInput.placeholder = `Enter a JSON formatted ${parameter.schema.type}, If this is a fileInput, it is not currently supported`; parameterInput.placeholder = `Enter a JSON formatted ${parameter.schema.type}, If this is a fileInput, it is not currently supported`;
parameterInput.className = "form-control"; parameterInput.className = "form-control";
break; break;
default: default:
parameterInput = document.createElement('input'); parameterInput = document.createElement("input");
parameterInput.type = 'text'; parameterInput.type = "text";
parameterInput.className = "form-control"; parameterInput.className = "form-control";
if (defaultValue !== undefined) parameterInput.value = defaultValue; if (defaultValue !== undefined) parameterInput.value = defaultValue;
} }
@ -416,15 +400,15 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
let savedValue = operationSettings[operation][parameter.name]; let savedValue = operationSettings[operation][parameter.name];
switch (parameter.schema.type) { switch (parameter.schema.type) {
case 'number': case "number":
case 'integer': case "integer":
parameterInput.value = savedValue.toString(); parameterInput.value = savedValue.toString();
break; break;
case 'boolean': case "boolean":
parameterInput.checked = savedValue; parameterInput.checked = savedValue;
break; break;
case 'array': case "array":
case 'object': case "object":
parameterInput.value = JSON.stringify(savedValue); parameterInput.value = JSON.stringify(savedValue);
break; break;
default: default:
@ -438,27 +422,27 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
}); });
if (hasSettings) { if (hasSettings) {
let saveButton = document.createElement('button'); let saveButton = document.createElement("button");
saveButton.textContent = saveSettings; saveButton.textContent = saveSettings;
saveButton.className = "btn btn-primary"; saveButton.className = "btn btn-primary";
saveButton.addEventListener('click', function(event) { saveButton.addEventListener("click", function (event) {
event.preventDefault(); event.preventDefault();
let settings = {}; let settings = {};
operationData.forEach(parameter => { operationData.forEach((parameter) => {
if (parameter.name !== "fileInput") { if (parameter.name !== "fileInput") {
let value = document.getElementById(parameter.name).value; let value = document.getElementById(parameter.name).value;
switch (parameter.schema.type) { switch (parameter.schema.type) {
case 'number': case "number":
case 'integer': case "integer":
settings[parameter.name] = Number(value); settings[parameter.name] = Number(value);
break; break;
case 'boolean': case "boolean":
settings[parameter.name] = document.getElementById(parameter.name).checked; settings[parameter.name] = document.getElementById(parameter.name).checked;
break; break;
case 'array': case "array":
case 'object': case "object":
if (value === null || value === '') { if (value === null || value === "") {
settings[parameter.name] = ''; settings[parameter.name] = "";
} else { } else {
try { try {
settings[parameter.name] = JSON.parse(value); settings[parameter.name] = JSON.parse(value);
@ -493,17 +477,10 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
showpipelineSettingsModal(selectedOperation); showpipelineSettingsModal(selectedOperation);
updateConfigInDropdown(); updateConfigInDropdown();
hideOrShowPipelineHeader(); hideOrShowPipelineHeader();
}); });
function updateConfigInDropdown() { function updateConfigInDropdown() {
let pipelineSelect = document.getElementById('pipelineSelect'); let pipelineSelect = document.getElementById("pipelineSelect");
let selectedOption = pipelineSelect.options[pipelineSelect.selectedIndex]; let selectedOption = pipelineSelect.options[pipelineSelect.selectedIndex];
// Get the current configuration as JSON // Get the current configuration as JSON
@ -516,53 +493,50 @@ function updateConfigInDropdown() {
// Update the value of the selected option with the new configuration // Update the value of the selected option with the new configuration
selectedOption.value = pipelineConfigJson; selectedOption.value = pipelineConfigJson;
} }
var saveBtn = document.getElementById('savePipelineBtn'); var saveBtn = document.getElementById("savePipelineBtn");
// Remove any existing event listeners // Remove any existing event listeners
saveBtn.removeEventListener('click', savePipeline); saveBtn.removeEventListener("click", savePipeline);
// Add the event listener // Add the event listener
saveBtn.addEventListener('click', savePipeline); saveBtn.addEventListener("click", savePipeline);
console.log("saveBtn", saveBtn) console.log("saveBtn", saveBtn);
function configToJson() { function configToJson() {
if (!validatePipeline()) { if (!validatePipeline()) {
return null; // Return null if validation fails return null; // Return null if validation fails
} }
var pipelineName = document.getElementById('pipelineName').value; var pipelineName = document.getElementById("pipelineName").value;
let pipelineList = document.getElementById('pipelineList').children; let pipelineList = document.getElementById("pipelineList").children;
let pipelineConfig = { let pipelineConfig = {
"name": pipelineName, name: pipelineName,
"pipeline": [], pipeline: [],
"_examples": { _examples: {
"outputDir": "{outputFolder}/{folderName}", outputDir: "{outputFolder}/{folderName}",
"outputFileName": "{filename}-{pipelineName}-{date}-{time}" outputFileName: "{filename}-{pipelineName}-{date}-{time}",
}, },
"outputDir": "{outputFolder}", outputDir: "{outputFolder}",
"outputFileName": "{filename}" outputFileName: "{filename}",
}; };
for (let i = 0; i < pipelineList.length; i++) { for (let i = 0; i < pipelineList.length; i++) {
let operationName = pipelineList[i].querySelector('.operationName').textContent; let operationName = pipelineList[i].querySelector(".operationName").textContent;
let parameters = operationSettings[operationName] || {}; let parameters = operationSettings[operationName] || {};
parameters['fileInput'] = 'automated'; parameters["fileInput"] = "automated";
pipelineConfig.pipeline.push({ pipelineConfig.pipeline.push({
"operation": operationName, operation: operationName,
"parameters": parameters parameters: parameters,
}); });
} }
return JSON.stringify(pipelineConfig, null, 2); return JSON.stringify(pipelineConfig, null, 2);
} }
function savePipeline() { function savePipeline() {
let pipelineConfigJson = configToJson(); let pipelineConfigJson = configToJson();
if (!pipelineConfigJson) { if (!pipelineConfigJson) {
@ -570,79 +544,76 @@ function savePipeline() {
return; return;
} }
let pipelineName = document.getElementById('pipelineName').value; let pipelineName = document.getElementById("pipelineName").value;
console.log("Downloading..."); console.log("Downloading...");
let a = document.createElement('a'); let a = document.createElement("a");
a.href = URL.createObjectURL(new Blob([pipelineConfigJson], { type: 'application/json' })); a.href = URL.createObjectURL(new Blob([pipelineConfigJson], { type: "application/json" }));
a.download = pipelineName + '.json'; a.download = pipelineName + ".json";
a.style.display = 'none'; a.style.display = "none";
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
document.body.removeChild(a); document.body.removeChild(a);
} }
async function processPipelineConfig(configString) { async function processPipelineConfig(configString) {
console.log("configString", configString); console.log("configString", configString);
let pipelineConfig = JSON.parse(configString); let pipelineConfig = JSON.parse(configString);
let pipelineList = document.getElementById('pipelineList'); let pipelineList = document.getElementById("pipelineList");
while (pipelineList.firstChild) { while (pipelineList.firstChild) {
pipelineList.removeChild(pipelineList.firstChild); pipelineList.removeChild(pipelineList.firstChild);
} }
document.getElementById('pipelineName').value = pipelineConfig.name document.getElementById("pipelineName").value = pipelineConfig.name;
for (const operationConfig of pipelineConfig.pipeline) { for (const operationConfig of pipelineConfig.pipeline) {
let operationsDropdown = document.getElementById('operationsDropdown'); let operationsDropdown = document.getElementById("operationsDropdown");
operationsDropdown.value = operationConfig.operation; operationsDropdown.value = operationConfig.operation;
operationSettings[operationConfig.operation] = operationConfig.parameters; operationSettings[operationConfig.operation] = operationConfig.parameters;
// assuming addOperation is async // assuming addOperation is async
await new Promise((resolve) => { await new Promise((resolve) => {
document.getElementById('addOperationBtn').addEventListener('click', resolve, { once: true }); document.getElementById("addOperationBtn").addEventListener("click", resolve, { once: true });
document.getElementById('addOperationBtn').click(); document.getElementById("addOperationBtn").click();
}); });
let lastOperation = pipelineList.lastChild; let lastOperation = pipelineList.lastChild;
Object.keys(operationConfig.parameters).forEach(parameterName => { Object.keys(operationConfig.parameters).forEach((parameterName) => {
let input = document.getElementById(parameterName); let input = document.getElementById(parameterName);
if (input) { if (input) {
switch (input.type) { switch (input.type) {
case 'checkbox': case "checkbox":
input.checked = operationConfig.parameters[parameterName]; input.checked = operationConfig.parameters[parameterName];
break; break;
case 'number': case "number":
input.value = operationConfig.parameters[parameterName].toString(); input.value = operationConfig.parameters[parameterName].toString();
break; break;
case 'file': case "file":
if (parameterName !== 'fileInput') { if (parameterName !== "fileInput") {
// Create a new file input element // Create a new file input element
let newInput = document.createElement('input'); let newInput = document.createElement("input");
newInput.type = 'file'; newInput.type = "file";
newInput.id = parameterName; newInput.id = parameterName;
// Add the new file input to the main page (change the selector according to your needs) // Add the new file input to the main page (change the selector according to your needs)
document.querySelector('#main').appendChild(newInput); document.querySelector("#main").appendChild(newInput);
} }
break; break;
case 'text': case "text":
case 'textarea': case "textarea":
default: default:
input.value = JSON.stringify(operationConfig.parameters[parameterName]); input.value = JSON.stringify(operationConfig.parameters[parameterName]);
} }
} }
}); });
} }
} }
document.getElementById("uploadPipelineBtn").addEventListener("click", function () {
document.getElementById('uploadPipelineBtn').addEventListener('click', function() { document.getElementById("uploadPipelineInput").click();
document.getElementById('uploadPipelineInput').click();
}); });
document.getElementById('uploadPipelineInput').addEventListener('change', function(e) { document.getElementById("uploadPipelineInput").addEventListener("change", function (e) {
let reader = new FileReader(); let reader = new FileReader();
reader.onload = function (event) { reader.onload = function (event) {
processPipelineConfig(event.target.result); processPipelineConfig(event.target.result);
@ -651,21 +622,20 @@ document.getElementById('uploadPipelineInput').addEventListener('change', functi
hideOrShowPipelineHeader(); hideOrShowPipelineHeader();
}); });
document.getElementById('pipelineSelect').addEventListener('change', function(e) { document.getElementById("pipelineSelect").addEventListener("change", function (e) {
let selectedPipelineJson = e.target.value; // assuming the selected value is the JSON string of the pipeline config let selectedPipelineJson = e.target.value; // assuming the selected value is the JSON string of the pipeline config
processPipelineConfig(selectedPipelineJson); processPipelineConfig(selectedPipelineJson);
}); });
function hideOrShowPipelineHeader() { function hideOrShowPipelineHeader() {
var pipelineHeader = document.getElementById('pipelineHeader'); var pipelineHeader = document.getElementById("pipelineHeader");
var pipelineList = document.getElementById('pipelineList'); var pipelineList = document.getElementById("pipelineList");
if (pipelineList.children.length === 0) { if (pipelineList.children.length === 0) {
// Hide the pipeline header if there are no items in the pipeline list // Hide the pipeline header if there are no items in the pipeline list
pipelineHeader.style.display = 'none'; pipelineHeader.style.display = "none";
} else { } else {
// Show the pipeline header if there are items in the pipeline list // Show the pipeline header if there are items in the pipeline list
pipelineHeader.style.display = 'block'; pipelineHeader.style.display = "block";
} }
} }

View File

@ -1,15 +1,15 @@
// Toggle search bar when the search icon is clicked // Toggle search bar when the search icon is clicked
document.querySelector('#search-icon').addEventListener('click', function(e) { document.querySelector("#search-icon").addEventListener("click", function (e) {
e.preventDefault(); e.preventDefault();
var searchBar = document.querySelector('#navbarSearch'); var searchBar = document.querySelector("#navbarSearch");
searchBar.classList.toggle('show'); searchBar.classList.toggle("show");
}); });
window.onload = function () { window.onload = function () {
var items = document.querySelectorAll('.dropdown-item, .nav-link'); var items = document.querySelectorAll(".dropdown-item, .nav-link");
var dummyContainer = document.createElement('div'); var dummyContainer = document.createElement("div");
dummyContainer.style.position = 'absolute'; dummyContainer.style.position = "absolute";
dummyContainer.style.visibility = 'hidden'; dummyContainer.style.visibility = "hidden";
dummyContainer.style.whiteSpace = 'nowrap'; // Ensure we measure full width dummyContainer.style.whiteSpace = "nowrap"; // Ensure we measure full width
document.body.appendChild(dummyContainer); document.body.appendChild(dummyContainer);
var maxWidth = 0; var maxWidth = 0;
@ -31,36 +31,39 @@ window.onload = function() {
}; };
// Show search results as user types in search box // Show search results as user types in search box
document.querySelector('#navbarSearchInput').addEventListener('input', function(e) { document.querySelector("#navbarSearchInput").addEventListener("input", function (e) {
var searchText = e.target.value.toLowerCase(); var searchText = e.target.value.toLowerCase();
var items = document.querySelectorAll('.dropdown-item, .nav-link'); var items = document.querySelectorAll(".dropdown-item, .nav-link");
var resultsBox = document.querySelector('#searchResults'); var resultsBox = document.querySelector("#searchResults");
// Clear any previous results // Clear any previous results
resultsBox.innerHTML = ''; resultsBox.innerHTML = "";
items.forEach(function (item) { items.forEach(function (item) {
var titleElement = item.querySelector('.icon-text'); var titleElement = item.querySelector(".icon-text");
var iconElement = item.querySelector('.icon'); var iconElement = item.querySelector(".icon");
var itemHref = item.getAttribute('href'); var itemHref = item.getAttribute("href");
var tags = item.getAttribute('data-bs-tags') || ""; // If no tags, default to empty string var tags = item.getAttribute("data-bs-tags") || ""; // If no tags, default to empty string
if (titleElement && iconElement && itemHref !== '#') { if (titleElement && iconElement && itemHref !== "#") {
var title = titleElement.innerText; var title = titleElement.innerText;
if ((title.toLowerCase().indexOf(searchText) !== -1 || tags.toLowerCase().indexOf(searchText) !== -1) && !resultsBox.querySelector(`a[href="${item.getAttribute('href')}"]`)) { if (
var result = document.createElement('a'); (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.href = itemHref;
result.classList.add('dropdown-item'); result.classList.add("dropdown-item");
var resultIcon = document.createElement('img'); var resultIcon = document.createElement("img");
resultIcon.src = iconElement.src; resultIcon.src = iconElement.src;
resultIcon.alt = 'icon'; resultIcon.alt = "icon";
resultIcon.classList.add('icon'); resultIcon.classList.add("icon");
result.appendChild(resultIcon); result.appendChild(resultIcon);
var resultText = document.createElement('span'); var resultText = document.createElement("span");
resultText.textContent = title; resultText.textContent = title;
resultText.classList.add('icon-text'); resultText.classList.add("icon-text");
result.appendChild(resultText); result.appendChild(resultText);
resultsBox.appendChild(result); resultsBox.appendChild(result);
@ -69,7 +72,5 @@ document.querySelector('#navbarSearchInput').addEventListener('input', function(
}); });
// Set the width of the search results box to the maximum width // Set the width of the search results box to the maximum width
resultsBox.style.width = window.navItemMaxWidth + 'px'; resultsBox.style.width = window.navItemMaxWidth + "px";
}); });

View File

@ -1,42 +1,33 @@
// Get the download option from local storage, or set it to 'sameWindow' if it doesn't exist // Get the download option from local storage, or set it to 'sameWindow' if it doesn't exist
var downloadOption = localStorage.getItem('downloadOption') var downloadOption = localStorage.getItem("downloadOption") || "sameWindow";
|| 'sameWindow';
// Set the selected option in the dropdown // 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 // Save the selected option to local storage when the dropdown value changes
document.getElementById('downloadOption').addEventListener( document.getElementById("downloadOption").addEventListener("change", function () {
'change',
function() {
downloadOption = this.value; downloadOption = this.value;
localStorage.setItem('downloadOption', localStorage.setItem("downloadOption", downloadOption);
downloadOption);
}); });
// Get the zipThreshold value from local storage, or set it to 0 if it doesn't exist // 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 zipThreshold = parseInt(localStorage.getItem("zipThreshold"), 10) || 4;
// Set the value of the slider and the display span // Set the value of the slider and the display span
document.getElementById('zipThreshold').value = zipThreshold; document.getElementById("zipThreshold").value = zipThreshold;
document.getElementById('zipThresholdValue').textContent = zipThreshold; document.getElementById("zipThresholdValue").textContent = zipThreshold;
// Save the selected value to local storage when the slider value changes // Save the selected value to local storage when the slider value changes
document.getElementById('zipThreshold').addEventListener('input', function() { document.getElementById("zipThreshold").addEventListener("input", function () {
zipThreshold = this.value; zipThreshold = this.value;
document.getElementById('zipThresholdValue').textContent = zipThreshold; document.getElementById("zipThresholdValue").textContent = zipThreshold;
localStorage.setItem('zipThreshold', zipThreshold); localStorage.setItem("zipThreshold", zipThreshold);
}); });
var boredWaiting = localStorage.getItem("boredWaiting") || "disabled";
document.getElementById("boredWaiting").checked = boredWaiting === "enabled";
var boredWaiting = localStorage.getItem('boredWaiting') || 'disabled'; document.getElementById("boredWaiting").addEventListener("change", function () {
document.getElementById('boredWaiting').checked = boredWaiting === 'enabled'; boredWaiting = this.checked ? "enabled" : "disabled";
localStorage.setItem("boredWaiting", boredWaiting);
document.getElementById('boredWaiting').addEventListener('change', function() {
boredWaiting = this.checked ? 'enabled' : 'disabled';
localStorage.setItem('boredWaiting', boredWaiting);
}); });

View File

@ -1,20 +1,19 @@
TabContainer = { TabContainer = {
initTabGroups() { initTabGroups() {
const groups = document.querySelectorAll(".tab-group"); const groups = document.querySelectorAll(".tab-group");
const unloadedGroups = [...groups].filter(g => !g.initialised); const unloadedGroups = [...groups].filter((g) => !g.initialised);
unloadedGroups.forEach(group => { unloadedGroups.forEach((group) => {
const containers = group.querySelectorAll(".tab-container"); const containers = group.querySelectorAll(".tab-container");
const tabTitles = [...containers].map(c => c.getAttribute("title")); const tabTitles = [...containers].map((c) => c.getAttribute("title"));
const tabList = document.createElement("div"); const tabList = document.createElement("div");
tabList.classList.add("tab-buttons"); tabList.classList.add("tab-buttons");
tabTitles.forEach(title => { tabTitles.forEach((title) => {
const tabButton = document.createElement("button"); const tabButton = document.createElement("button");
tabButton.innerHTML = title; tabButton.innerHTML = title;
tabButton.onclick = e => { tabButton.onclick = (e) => {
this.setActiveTab(e.target); this.setActiveTab(e.target);
} };
tabList.appendChild(tabButton); tabList.appendChild(tabButton);
}); });
group.prepend(tabList); group.prepend(tabList);
@ -25,15 +24,15 @@ TabContainer = {
}); });
}, },
setActiveTab(tabButton) { setActiveTab(tabButton) {
const group = tabButton.closest(".tab-group") 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"); tabButton.classList.add("active");
group.querySelector(`[title="${tabButton.innerHTML}"]`).classList.add("active"); group.querySelector(`[title="${tabButton.innerHTML}"]`).classList.add("active");
}, },
} };
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
TabContainer.initTabGroups(); TabContainer.initTabGroups();
}) });

View File

@ -116,7 +116,6 @@
top: 0; top: 0;
} }
:root { :root {
--annotation-unfocused-field-background: url("data:image/svg+xml;charset=UTF-8,<svg width='1px' height='1px' xmlns='http://www.w3.org/2000/svg'><rect width='100%' height='100%' style='fill:rgba(0, 54, 255, 0.13);'/></svg>"); --annotation-unfocused-field-background: url("data:image/svg+xml;charset=UTF-8,<svg width='1px' height='1px' xmlns='http://www.w3.org/2000/svg'><rect width='100%' height='100%' style='fill:rgba(0, 54, 255, 0.13);'/></svg>");
--input-focus-border-color: Highlight; --input-focus-border-color: Highlight;
@ -139,9 +138,7 @@
.annotationLayer .textWidgetAnnotation :is(input, textarea):required, .annotationLayer .textWidgetAnnotation :is(input, textarea):required,
.annotationLayer .choiceWidgetAnnotation select:required, .annotationLayer .choiceWidgetAnnotation select:required,
.annotationLayer .annotationLayer .buttonWidgetAnnotation:is(.checkBox, .radioButton) input:required {
.buttonWidgetAnnotation:is(.checkBox, .radioButton)
input:required {
outline: 1.5px solid selectedItem; outline: 1.5px solid selectedItem;
} }
@ -228,9 +225,7 @@
height: 100%; height: 100%;
} }
.annotationLayer .annotationLayer :is(.linkAnnotation, .buttonWidgetAnnotation.pushButton):not(.hasBorder) > a:hover {
:is(.linkAnnotation, .buttonWidgetAnnotation.pushButton):not(.hasBorder)
> a:hover {
opacity: 0.2; opacity: 0.2;
background-color: rgba(255, 255, 0, 1); background-color: rgba(255, 255, 0, 1);
box-shadow: 0 2px 10px 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 .textWidgetAnnotation :is(input, textarea):required,
.annotationLayer .choiceWidgetAnnotation select:required, .annotationLayer .choiceWidgetAnnotation select:required,
.annotationLayer .annotationLayer .buttonWidgetAnnotation:is(.checkBox, .radioButton) input:required {
.buttonWidgetAnnotation:is(.checkBox, .radioButton)
input:required {
outline: 1.5px solid red; outline: 1.5px solid red;
} }
@ -288,9 +281,7 @@ input:required {
.annotationLayer .textWidgetAnnotation :is(input, textarea)[disabled], .annotationLayer .textWidgetAnnotation :is(input, textarea)[disabled],
.annotationLayer .choiceWidgetAnnotation select[disabled], .annotationLayer .choiceWidgetAnnotation select[disabled],
.annotationLayer .annotationLayer .buttonWidgetAnnotation:is(.checkBox, .radioButton) input[disabled] {
.buttonWidgetAnnotation:is(.checkBox, .radioButton)
input[disabled] {
background: none; background: none;
border: 2px solid var(--input-disabled-border-color); border: 2px solid var(--input-disabled-border-color);
cursor: not-allowed; cursor: not-allowed;
@ -298,9 +289,7 @@ input[disabled] {
.annotationLayer .textWidgetAnnotation :is(input, textarea):hover, .annotationLayer .textWidgetAnnotation :is(input, textarea):hover,
.annotationLayer .choiceWidgetAnnotation select:hover, .annotationLayer .choiceWidgetAnnotation select:hover,
.annotationLayer .annotationLayer .buttonWidgetAnnotation:is(.checkBox, .radioButton) input:hover {
.buttonWidgetAnnotation:is(.checkBox, .radioButton)
input:hover {
border: 2px solid var(--input-hover-border-color); border: 2px solid var(--input-hover-border-color);
} }
@ -489,7 +478,6 @@ input:hover {
z-index: -1; z-index: -1;
} }
:root { :root {
--xfa-unfocused-field-background: url("data:image/svg+xml;charset=UTF-8,<svg width='1px' height='1px' xmlns='http://www.w3.org/2000/svg'><rect width='100%' height='100%' style='fill:rgba(0, 54, 255, 0.13);'/></svg>"); --xfa-unfocused-field-background: url("data:image/svg+xml;charset=UTF-8,<svg width='1px' height='1px' xmlns='http://www.w3.org/2000/svg'><rect width='100%' height='100%' style='fill:rgba(0, 54, 255, 0.13);'/></svg>");
--xfa-focus-outline: auto; --xfa-focus-outline: auto;
@ -827,10 +815,7 @@ input:hover {
--freetext-padding: 2px; --freetext-padding: 2px;
--resizer-bg-color: var(--outline-color); --resizer-bg-color: var(--outline-color);
--resizer-size: 6px; --resizer-size: 6px;
--resizer-shift: calc( --resizer-shift: calc(0px - (var(--outline-width) + var(--resizer-size)) / 2 - var(--outline-around-width));
0px - (var(--outline-width) + var(--resizer-size)) / 2 -
var(--outline-around-width)
);
--editorFreeText-editing-cursor: text; --editorFreeText-editing-cursor: text;
--editorInk-editing-cursor: url(../images/cursor-editorInk.svg) 0 16, pointer; --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) { @media (-webkit-min-device-pixel-ratio: 1.1), (min-resolution: 1.1dppx) {
:root { :root {
--editorFreeText-editing-cursor: url(../images/cursor-editorFreeText.svg) 0 16, --editorFreeText-editing-cursor: url(../images/cursor-editorFreeText.svg) 0 16, text;
text;
} }
} }
@ -1109,154 +1093,282 @@ input:hover {
} }
.annotationEditorLayer[data-main-rotation="0"] .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"] .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"] .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"] .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"] .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"] .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"] .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"] .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; cursor: nwse-resize;
} }
.annotationEditorLayer[data-main-rotation="0"] .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"] .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"] .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"] .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"] .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"] .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"] .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"] .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; cursor: ns-resize;
} }
.annotationEditorLayer[data-main-rotation="0"] .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"] .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"] .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"] .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"] .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"] .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"] .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"] .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; cursor: nesw-resize;
} }
.annotationEditorLayer[data-main-rotation="0"] .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"] .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"] .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"] .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"] .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"] .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"] .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"] .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; cursor: ew-resize;
} }
.annotationEditorLayer[data-main-rotation="0"] .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"] .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"] .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"] .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"] .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"] .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"] .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"] .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; cursor: nesw-resize;
} }
.annotationEditorLayer[data-main-rotation="0"] .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"] .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"] .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"] .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"] .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"] .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"] .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"] .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; cursor: ew-resize;
} }
.annotationEditorLayer[data-main-rotation="0"] .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"] .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"] .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"] .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"] .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"] .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"] .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"] .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; cursor: nwse-resize;
} }
.annotationEditorLayer[data-main-rotation="0"] .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"] .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"] .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"] .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"] .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"] .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"] .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"] .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; cursor: ns-resize;
} }
@ -1266,48 +1378,57 @@ input:hover {
[data-main-rotation="90"] [data-editor-rotation="0"], [data-main-rotation="90"] [data-editor-rotation="0"],
[data-main-rotation="180"] [data-editor-rotation="270"], [data-main-rotation="180"] [data-editor-rotation="270"],
[data-main-rotation="270"] [data-editor-rotation="180"] [data-main-rotation="270"] [data-editor-rotation="180"]
) .altText { )
.altText {
rotate: 270deg; rotate: 270deg;
} }
[dir="ltr"] .annotationEditorLayer [dir="ltr"]
.annotationEditorLayer
:is( :is(
[data-main-rotation="0"] [data-editor-rotation="90"], [data-main-rotation="0"] [data-editor-rotation="90"],
[data-main-rotation="90"] [data-editor-rotation="0"], [data-main-rotation="90"] [data-editor-rotation="0"],
[data-main-rotation="180"] [data-editor-rotation="270"], [data-main-rotation="180"] [data-editor-rotation="270"],
[data-main-rotation="270"] [data-editor-rotation="180"] [data-main-rotation="270"] [data-editor-rotation="180"]
) .altText { )
.altText {
inset-inline-start: calc(100% - 8px); inset-inline-start: calc(100% - 8px);
} }
[dir="ltr"] .annotationEditorLayer [dir="ltr"]
.annotationEditorLayer
:is( :is(
[data-main-rotation="0"] [data-editor-rotation="90"], [data-main-rotation="0"] [data-editor-rotation="90"],
[data-main-rotation="90"] [data-editor-rotation="0"], [data-main-rotation="90"] [data-editor-rotation="0"],
[data-main-rotation="180"] [data-editor-rotation="270"], [data-main-rotation="180"] [data-editor-rotation="270"],
[data-main-rotation="270"] [data-editor-rotation="180"] [data-main-rotation="270"] [data-editor-rotation="180"]
) .altText.small { )
.altText.small {
inset-inline-start: calc(100% + 8px); inset-inline-start: calc(100% + 8px);
inset-block-start: 100%; inset-block-start: 100%;
} }
[dir="rtl"] .annotationEditorLayer [dir="rtl"]
.annotationEditorLayer
:is( :is(
[data-main-rotation="0"] [data-editor-rotation="90"], [data-main-rotation="0"] [data-editor-rotation="90"],
[data-main-rotation="90"] [data-editor-rotation="0"], [data-main-rotation="90"] [data-editor-rotation="0"],
[data-main-rotation="180"] [data-editor-rotation="270"], [data-main-rotation="180"] [data-editor-rotation="270"],
[data-main-rotation="270"] [data-editor-rotation="180"] [data-main-rotation="270"] [data-editor-rotation="180"]
) .altText { )
.altText {
inset-block-end: calc(100% - 8px); inset-block-end: calc(100% - 8px);
} }
[dir="rtl"] .annotationEditorLayer [dir="rtl"]
.annotationEditorLayer
:is( :is(
[data-main-rotation="0"] [data-editor-rotation="90"], [data-main-rotation="0"] [data-editor-rotation="90"],
[data-main-rotation="90"] [data-editor-rotation="0"], [data-main-rotation="90"] [data-editor-rotation="0"],
[data-main-rotation="180"] [data-editor-rotation="270"], [data-main-rotation="180"] [data-editor-rotation="270"],
[data-main-rotation="270"] [data-editor-rotation="180"] [data-main-rotation="270"] [data-editor-rotation="180"]
) .altText.small { )
.altText.small {
inset-inline-start: -8px; inset-inline-start: -8px;
inset-block-start: 0; inset-block-start: 0;
} }
@ -1318,7 +1439,8 @@ input:hover {
[data-main-rotation="90"] [data-editor-rotation="90"], [data-main-rotation="90"] [data-editor-rotation="90"],
[data-main-rotation="180"] [data-editor-rotation="0"], [data-main-rotation="180"] [data-editor-rotation="0"],
[data-main-rotation="270"] [data-editor-rotation="270"] [data-main-rotation="270"] [data-editor-rotation="270"]
) .altText { )
.altText {
rotate: 180deg; rotate: 180deg;
inset-block-end: calc(100% - 8px); inset-block-end: calc(100% - 8px);
@ -1331,7 +1453,8 @@ input:hover {
[data-main-rotation="90"] [data-editor-rotation="90"], [data-main-rotation="90"] [data-editor-rotation="90"],
[data-main-rotation="180"] [data-editor-rotation="0"], [data-main-rotation="180"] [data-editor-rotation="0"],
[data-main-rotation="270"] [data-editor-rotation="270"] [data-main-rotation="270"] [data-editor-rotation="270"]
) .altText.small { )
.altText.small {
inset-inline-start: 100%; inset-inline-start: 100%;
inset-block-start: -8px; inset-block-start: -8px;
} }
@ -1342,48 +1465,57 @@ input:hover {
[data-main-rotation="90"] [data-editor-rotation="180"], [data-main-rotation="90"] [data-editor-rotation="180"],
[data-main-rotation="180"] [data-editor-rotation="90"], [data-main-rotation="180"] [data-editor-rotation="90"],
[data-main-rotation="270"] [data-editor-rotation="0"] [data-main-rotation="270"] [data-editor-rotation="0"]
) .altText { )
.altText {
rotate: 90deg; rotate: 90deg;
} }
[dir="ltr"] .annotationEditorLayer [dir="ltr"]
.annotationEditorLayer
:is( :is(
[data-main-rotation="0"] [data-editor-rotation="270"], [data-main-rotation="0"] [data-editor-rotation="270"],
[data-main-rotation="90"] [data-editor-rotation="180"], [data-main-rotation="90"] [data-editor-rotation="180"],
[data-main-rotation="180"] [data-editor-rotation="90"], [data-main-rotation="180"] [data-editor-rotation="90"],
[data-main-rotation="270"] [data-editor-rotation="0"] [data-main-rotation="270"] [data-editor-rotation="0"]
) .altText { )
.altText {
inset-block-end: calc(100% - 8px); inset-block-end: calc(100% - 8px);
} }
[dir="ltr"] .annotationEditorLayer [dir="ltr"]
.annotationEditorLayer
:is( :is(
[data-main-rotation="0"] [data-editor-rotation="270"], [data-main-rotation="0"] [data-editor-rotation="270"],
[data-main-rotation="90"] [data-editor-rotation="180"], [data-main-rotation="90"] [data-editor-rotation="180"],
[data-main-rotation="180"] [data-editor-rotation="90"], [data-main-rotation="180"] [data-editor-rotation="90"],
[data-main-rotation="270"] [data-editor-rotation="0"] [data-main-rotation="270"] [data-editor-rotation="0"]
) .altText.small { )
.altText.small {
inset-inline-start: -8px; inset-inline-start: -8px;
inset-block-start: 0; inset-block-start: 0;
} }
[dir="rtl"] .annotationEditorLayer [dir="rtl"]
.annotationEditorLayer
:is( :is(
[data-main-rotation="0"] [data-editor-rotation="270"], [data-main-rotation="0"] [data-editor-rotation="270"],
[data-main-rotation="90"] [data-editor-rotation="180"], [data-main-rotation="90"] [data-editor-rotation="180"],
[data-main-rotation="180"] [data-editor-rotation="90"], [data-main-rotation="180"] [data-editor-rotation="90"],
[data-main-rotation="270"] [data-editor-rotation="0"] [data-main-rotation="270"] [data-editor-rotation="0"]
) .altText { )
.altText {
inset-inline-start: calc(100% - 8px); inset-inline-start: calc(100% - 8px);
} }
[dir="rtl"] .annotationEditorLayer [dir="rtl"]
.annotationEditorLayer
:is( :is(
[data-main-rotation="0"] [data-editor-rotation="270"], [data-main-rotation="0"] [data-editor-rotation="270"],
[data-main-rotation="90"] [data-editor-rotation="180"], [data-main-rotation="90"] [data-editor-rotation="180"],
[data-main-rotation="180"] [data-editor-rotation="90"], [data-main-rotation="180"] [data-editor-rotation="90"],
[data-main-rotation="270"] [data-editor-rotation="0"] [data-main-rotation="270"] [data-editor-rotation="0"]
) .altText.small { )
.altText.small {
inset-inline-start: calc(100% + 8px); inset-inline-start: calc(100% + 8px);
inset-block-start: 100%; inset-block-start: 100%;
} }
@ -1421,7 +1553,6 @@ input:hover {
} }
.altText.small { .altText.small {
inset-block-end: unset; inset-block-end: unset;
inset-inline-start: 0; inset-inline-start: 0;
inset-block-start: calc(100% + 8px); inset-block-start: calc(100% + 8px);
@ -1515,7 +1646,6 @@ input:hover {
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
.altText .tooltip.show { .altText .tooltip.show {
--alt-text-tooltip-bg: #1c1b22; --alt-text-tooltip-bg: #1c1b22;
--alt-text-tooltip-fg: #fbfbfe; --alt-text-tooltip-fg: #fbfbfe;
@ -1524,7 +1654,6 @@ input:hover {
} }
@media screen and (forced-colors: active) { @media screen and (forced-colors: active) {
.altText .tooltip.show { .altText .tooltip.show {
--alt-text-tooltip-bg: Canvas; --alt-text-tooltip-bg: Canvas;
--alt-text-tooltip-fg: CanvasText; --alt-text-tooltip-fg: CanvasText;
@ -1581,7 +1710,6 @@ input:hover {
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
#altTextDialog { #altTextDialog {
--dialog-bg-color: #1c1b22; --dialog-bg-color: #1c1b22;
--dialog-border-color: #1c1b22; --dialog-border-color: #1c1b22;
@ -1604,7 +1732,6 @@ input:hover {
} }
@media screen and (forced-colors: active) { @media screen and (forced-colors: active) {
#altTextDialog { #altTextDialog {
--dialog-bg-color: Canvas; --dialog-bg-color: Canvas;
--dialog-border-color: CanvasText; --dialog-border-color: CanvasText;
@ -2022,8 +2149,8 @@ input:hover {
--toolbar-border-color: rgba(184, 184, 184, 1); --toolbar-border-color: rgba(184, 184, 184, 1);
--toolbar-box-shadow: 0 1px 0 var(--toolbar-border-color); --toolbar-box-shadow: 0 1px 0 var(--toolbar-border-color);
--toolbar-border-bottom: none; --toolbar-border-bottom: none;
--toolbarSidebar-box-shadow: inset calc(-1px * var(--dir-factor)) 0 0 rgba(0, 0, 0, 0.25), --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 1px 0 rgba(0, 0, 0, 0.15), 0 0 1px rgba(0, 0, 0, 0.1); 0 0 1px rgba(0, 0, 0, 0.1);
--toolbarSidebar-border-bottom: none; --toolbarSidebar-border-bottom: none;
--button-hover-color: rgba(221, 222, 223, 1); --button-hover-color: rgba(221, 222, 223, 1);
--toggled-btn-color: rgba(0, 0, 0, 1); --toggled-btn-color: rgba(0, 0, 0, 1);
@ -2319,8 +2446,7 @@ body {
font: message-box; font: message-box;
} }
:is(.toolbar, .editorParamsToolbar, .findbar, #sidebarContainer) :is(.toolbar, .editorParamsToolbar, .findbar, #sidebarContainer) :is(input, button, select),
:is(input, button, select),
.secondaryToolbar :is(input, button, a, select) { .secondaryToolbar :is(input, button, a, select) {
outline: none; outline: none;
font: message-box; font: message-box;
@ -2428,8 +2554,7 @@ body {
animation: progressIndeterminate 1s linear infinite; animation: progressIndeterminate 1s linear infinite;
} }
#outerContainer.sidebarResizing #outerContainer.sidebarResizing :is(#sidebarContainer, #viewerContainer, #loadingBar) {
:is(#sidebarContainer, #viewerContainer, #loadingBar) {
/* Improve responsiveness and avoid visual glitches when the sidebar is resized. */ /* Improve responsiveness and avoid visual glitches when the sidebar is resized. */
transition-duration: 0s; transition-duration: 0s;
} }
@ -2600,7 +2725,8 @@ body {
.doorHanger, .doorHanger,
.doorHangerRight { .doorHangerRight {
border-radius: 2px; border-radius: 2px;
box-shadow: 0 1px 5px var(--doorhanger-border-color), box-shadow:
0 1px 5px var(--doorhanger-border-color),
0 0 0 1px var(--doorhanger-border-color); 0 0 0 1px var(--doorhanger-border-color);
border: var(--doorhanger-border-color-whcm); border: var(--doorhanger-border-color-whcm);
} }
@ -3455,8 +3581,7 @@ dialog :link {
cursor: grab !important; cursor: grab !important;
} }
.grab-to-pan-grab .grab-to-pan-grab *:not(input):not(textarea):not(button):not(select):not(:link) {
*:not(input):not(textarea):not(button):not(select):not(:link) {
cursor: inherit !important; cursor: inherit !important;
} }

View File

@ -1,22 +1,21 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title='<3')}"></th:block> <th:block th:insert="~{fragments/common :: head(title='<3')}"></th:block>
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6"></div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,45 +1,43 @@
<!doctype html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{account.title}, header=#{account.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{account.title})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-9"> <div class="col-md-9">
<!-- User Settings Title --> <!-- User Settings Title -->
<h2 class="text-center" th:text="#{account.accountSettings}">User Settings</h2> <h2 class="text-center" th:text="#{account.accountSettings}">User Settings</h2>
<hr> <hr />
<div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'notAuthenticated'}" class="alert alert-danger"> <th:block th:if="${param.messageType != null and param.messageType.size() > 0}">
<div th:if="${param.messageType[0] == 'notAuthenticated'}" class="alert alert-danger">
<span th:text="#{notAuthenticatedMessage}">Default message if not found</span> <span th:text="#{notAuthenticatedMessage}">Default message if not found</span>
</div> </div>
<div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'userNotFound'}" class="alert alert-danger"> <div th:if="${param.messageType[0] == 'userNotFound'}" class="alert alert-danger">
<span th:text="#{userNotFoundMessage}">Default message if not found</span> <span th:text="#{userNotFoundMessage}">Default message if not found</span>
</div> </div>
<div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'incorrectPassword'}" class="alert alert-danger"> <div th:if="${param.messageType[0] == 'incorrectPassword'}" class="alert alert-danger">
<span th:text="#{incorrectPasswordMessage}">Default message if not found</span> <span th:text="#{incorrectPasswordMessage}">Default message if not found</span>
</div> </div>
<div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'usernameExists'}" class="alert alert-danger"> <div th:if="${param.messageType[0] == 'usernameExists'}" class="alert alert-danger">
<span th:text="#{usernameExistsMessage}">Default message if not found</span> <span th:text="#{usernameExistsMessage}">Default message if not found</span>
</div> </div>
</th:block>
<!-- At the top of the user settings --> <!-- At the top of the user settings -->
<h3 class="text-center"><span th:text="#{welcome} + ' ' + ${username}">User</span>!</h3> <h3 class="text-center"><span th:text="#{welcome} + ' ' + ${username}">User</span>!</h3>
<th:block th:if="${error}">
<div th:if="${error}" class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
<span th:text="${error}">Error Message</span> <span th:text="${error}">Error Message</span>
</div> </div>
</th:block>
<!-- Change Username Form --> <!-- Change Username Form -->
<h4></h4> <h4></h4>
<form action="api/v1/user/change-username" method="post"> <form action="api/v1/user/change-username" method="post">
@ -56,7 +54,7 @@
</div> </div>
</form> </form>
<hr> <!-- Separator Line --> <hr /> <!-- Separator Line -->
<!-- Change Password Form --> <!-- Change Password Form -->
<h4 th:text="#{account.changePassword}">Change Password?</h4> <h4 th:text="#{account.changePassword}">Change Password?</h4>
@ -78,12 +76,10 @@
</div> </div>
</form> </form>
<hr> <hr />
<div class="card"> <div class="card">
<div class="card-header" th:text="#{account.yourApiKey}"> <div class="card-header" th:text="#{account.yourApiKey}"></div>
</div>
<div class="card-body"> <div class="card-body">
<div class="input-group mb-3"> <div class="input-group mb-3">
<input type="password" class="form-control" id="apiKey" th:placeholder="#{account.yourApiKey}" readonly> <input type="password" class="form-control" id="apiKey" th:placeholder="#{account.yourApiKey}" readonly>
@ -97,8 +93,6 @@
<button class="btn btn-outline-secondary" id="refreshBtn" type="button" onclick="refreshApiKey()"> <button class="btn btn-outline-secondary" id="refreshBtn" type="button" onclick="refreshApiKey()">
<img class="blackwhite-icon" id="eyeIcon" src="images/arrow-clockwise.svg" alt="Refresh API-Key" style="height:20px;"> <img class="blackwhite-icon" id="eyeIcon" src="images/arrow-clockwise.svg" alt="Refresh API-Key" style="height:20px;">
</button> </button>
</div> </div>
</div> </div>
</div> </div>
@ -111,7 +105,6 @@
document.execCommand("copy"); document.execCommand("copy");
} }
function showApiKey() { function showApiKey() {
const apiKeyElement = document.getElementById("apiKey"); const apiKeyElement = document.getElementById("apiKey");
const copyBtn = document.getElementById("copyBtn"); const copyBtn = document.getElementById("copyBtn");
@ -189,8 +182,7 @@
}); });
</script> </script>
<hr /> <!-- Separator Line -->
<hr> <!-- Separator Line -->
<h4 th:text="#{account.syncTitle}">Sync browser settings with Account</h4> <h4 th:text="#{account.syncTitle}">Sync browser settings with Account</h4>
<div class="container mt-4"> <div class="container mt-4">
@ -214,23 +206,6 @@
</div> </div>
</div> </div>
<style>
.container {
width: 100%;
max-width: 800px;
margin: 0 auto;
}
.buttons-container {
margin-top: 20px;
text-align: center;
}
</style>
<script th:inline="javascript"> <script th:inline="javascript">
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function() {
const settingsTableBody = document.querySelector("#settingsTable tbody"); const settingsTableBody = document.querySelector("#settingsTable tbody");
@ -271,7 +246,6 @@
location.reload(); // Refresh the page after sync location.reload(); // Refresh the page after sync
}); });
document.getElementById('syncToAccount').addEventListener('click', function() { document.getElementById('syncToAccount').addEventListener('click', function() {
let form = document.createElement("form"); let form = document.createElement("form");
form.method = "POST"; form.method = "POST";
@ -293,18 +267,7 @@
}); });
}); });
</script> </script>
<div class="mb-3 mt-4"> <div class="mb-3 mt-4">
<a href="logout"> <a href="logout">
<button type="button" class="btn btn-danger" th:text="#{account.signOut}">Sign Out</button> <button type="button" class="btn btn-danger" th:text="#{account.signOut}">Sign Out</button>
@ -312,15 +275,12 @@
<a th:if="${role == 'ROLE_ADMIN'}" href="addUsers" target="_blank"> <a th:if="${role == 'ROLE_ADMIN'}" href="addUsers" target="_blank">
<button type="button" class="btn btn-info" th:text="#{account.adminSettings}">Admin Settings</button> <button type="button" class="btn btn-info" th:text="#{account.adminSettings}">Admin Settings</button>
</a> </a>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> </div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,24 +1,21 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{adminUserSettings.title}, header=#{adminUserSettings.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{adminUserSettings.title}, header=#{adminUserSettings.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-8"> <div class="col-md-8">
<!-- User Settings Title --> <!-- User Settings Title -->
<h2 class="text-center" th:text="#{adminUserSettings.header}">Admin User Control Settings</h2> <h2 class="text-center" th:text="#{adminUserSettings.header}">Admin User Control Settings</h2>
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
@ -40,8 +37,6 @@
</tbody> </tbody>
</table> </table>
<h2 th:text="#{adminUserSettings.addUser}">Add New User</h2> <h2 th:text="#{adminUserSettings.addUser}">Add New User</h2>
<div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'usernameExists'}" class="alert alert-danger"> <div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'usernameExists'}" class="alert alert-danger">
<span th:text="#{usernameExistsMessage}">Default message if not found</span> <span th:text="#{usernameExistsMessage}">Default message if not found</span>
@ -76,9 +71,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,15 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{autoSplitPDF.title}, header=#{autoSplitPDF.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{autoSplitPDF.title}, header=#{autoSplitPDF.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -36,9 +36,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,39 +1,39 @@
<!doctype html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{changeCreds.title}, header=#{changeCreds.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{changeCreds.title}, header=#{changeCreds.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-9"> <div class="col-md-9">
<!-- User Settings Title --> <!-- User Settings Title -->
<h2 class="text-center" th:text="#{changeCreds.header}">User Settings</h2> <h2 class="text-center" th:text="#{changeCreds.header}">User Settings</h2>
<hr> <hr />
<th:block th:if="${param.messageType != null and param.messageType.size() > 0}">
<div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'notAuthenticated'}" class="alert alert-danger"> <div th:if="${param.messageType[0] == 'notAuthenticated'}" class="alert alert-danger">
<span th:text="#{notAuthenticatedMessage}">Default message if not found</span> <span th:text="#{notAuthenticatedMessage}">Default message if not found</span>
</div> </div>
<div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'userNotFound'}" class="alert alert-danger"> <div th:if="${param.messageType[0] == 'userNotFound'}" class="alert alert-danger">
<span th:text="#{userNotFoundMessage}">Default message if not found</span> <span th:text="#{userNotFoundMessage}">Default message if not found</span>
</div> </div>
<div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'incorrectPassword'}" class="alert alert-danger"> <div th:if="${param.messageType[0] == 'incorrectPassword'}" class="alert alert-danger">
<span th:text="#{incorrectPasswordMessage}">Default message if not found</span> <span th:text="#{incorrectPasswordMessage}">Default message if not found</span>
</div> </div>
<div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'usernameExists'}" class="alert alert-danger"> <div th:if="${param.messageType[0] == 'usernameExists'}" class="alert alert-danger">
<span th:text="#{usernameExistsMessage}">Default message if not found</span> <span th:text="#{usernameExistsMessage}">Default message if not found</span>
</div> </div>
</th:block>
<!-- At the top of the user settings --> <!-- At the top of the user settings -->
<h3 class="text-center"><span th:text="#{welcome} + ' ' + ${username}">User</span>!</h3> <h3 class="text-center"><span th:text="#{welcome} + ' ' + ${username}">User</span>!</h3>
<!-- Change Username Form --> <!-- Change Username Form -->
<h4></h4> <h4></h4>
<h4 th:text="#{changeCreds.changeUserAndPassword}">Change Username and password</h4> <h4 th:text="#{changeCreds.changeUserAndPassword}">Change Username and password</h4>
@ -58,7 +58,6 @@
<button type="submit" class="btn btn-primary" th:text="#{changeCreds.submit}">Change credentials!</button> <button type="submit" class="btn btn-primary" th:text="#{changeCreds.submit}">Change credentials!</button>
</div> </div>
</form> </form>
<script> <script>
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function() {
const form = document.querySelector('form[action="api/v1/user/change-username-and-password"]'); const form = document.querySelector('form[action="api/v1/user/change-username-and-password"]');
@ -75,16 +74,10 @@
}); });
</script> </script>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,13 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{BookToPDF.title}, header=#{BookToPDF.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{BookToPDF.title}, header=#{BookToPDF.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -23,7 +25,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,37 +1,34 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{fileToPDF.title}, header=#{fileToPDF.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{fileToPDF.title}, header=#{fileToPDF.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<h2 th:text="#{fileToPDF.header}"></h2> <h2 th:text="#{fileToPDF.header}"></h2>
<p th:text="#{processTimeWarning}"> <p th:text="#{processTimeWarning}"></p>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/file/pdf}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/file/pdf}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{fileToPDF.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{fileToPDF.submit}"></button>
</form> </form>
<p class="mt-3" th:text="#{fileToPDF.credit}"></p> <p class="mt-3" th:text="#{fileToPDF.credit}"></p>
<p class="mt-3" th:text="#{fileToPDF.supportedFileTypes}"></p> <p class="mt-3" th:text="#{fileToPDF.supportedFileTypes}"></p>
<p th:utext="#{fileToPDF.fileTypesList}"></p> <p th:utext="#{fileToPDF.fileTypesList}"></p>
<a href="https://help.libreoffice.org/latest/en-US/text/shared/guide/supported_formats.html">https://help.libreoffice.org/latest/en-US/text/shared/guide/supported_formats.html</a> <a href="https://help.libreoffice.org/latest/en-US/text/shared/guide/supported_formats.html">https://help.libreoffice.org/latest/en-US/text/shared/guide/supported_formats.html</a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,28 +1,27 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{HTMLToPDF.title}, header=#{HTMLToPDF.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{HTMLToPDF.title}, header=#{HTMLToPDF.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="mb-3"> <div class="mb-3">
<h2 th:text="#{HTMLToPDF.header}"></h2> <h2 th:text="#{HTMLToPDF.header}"></h2>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/html/pdf}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/html/pdf}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/html,application/zip' )}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/html,application/zip' )}"></div>
<div class="mb-3"> <div class="mb-3">
<label for="zoom" th:text="#{HTMLToPDF.zoom}" class="form-label"></label> <label for="zoom" th:text="#{HTMLToPDF.zoom}" class="form-label"></label>
<input type="number" step="0.1" class="form-control" id="zoom" name="zoom" value="1" /> <input type="number" step="0.1" class="form-control" id="zoom" name="zoom" value="1" />
</div> </div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{HTMLToPDF.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{HTMLToPDF.submit}"></button>
</form> </form>
<p class="mt-3" th:text="#{HTMLToPDF.help}"></p> <p class="mt-3" th:text="#{HTMLToPDF.help}"></p>
<p class="mt-3" th:text="#{HTMLToPDF.credit}"></p> <p class="mt-3" th:text="#{HTMLToPDF.credit}"></p>
@ -30,7 +29,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,23 +1,21 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{imageToPDF.title}, header=#{imageToPDF.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{imageToPDF.title}, header=#{imageToPDF.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<h2 th:text="#{imageToPDF.header}"></h2> <h2 th:text="#{imageToPDF.header}"></h2>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/img/pdf}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/img/pdf}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*', inputText=#{imgPrompt})}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*', inputText=#{imgPrompt})}"></div>
<div class="mb-3"> <div class="mb-3">
<label for="fitOption" th:text="#{imageToPDF.selectLabel}">Fit Options</label> <label for="fitOption" th:text="#{imageToPDF.selectLabel}">Fit Options</label>
<select class="form-control" id="fitOption" name="fitOption"> <select class="form-control" id="fitOption" name="fitOption">
@ -48,8 +46,7 @@
<option value="convert" th:text=#{imageToPDF.selectText.5} selected></option> <option value="convert" th:text=#{imageToPDF.selectText.5} selected></option>
</select> </select>
</div> </div>
<br /><br />
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button>
<script> <script>
$('#fileInput-input').on('change', function() { $('#fileInput-input').on('change', function() {
@ -73,16 +70,13 @@
override.value = "multi"; override.value = "multi";
} }
}); });
</script> </script>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,13 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{MarkdownToPDF.title}, header=#{MarkdownToPDF.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{MarkdownToPDF.title}, header=#{MarkdownToPDF.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -16,7 +18,6 @@
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/markdown')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/markdown')}"></div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{MarkdownToPDF.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{MarkdownToPDF.submit}"></button>
</form> </form>
<p class="mt-3" th:text="#{MarkdownToPDF.help}"></p> <p class="mt-3" th:text="#{MarkdownToPDF.help}"></p>
<p class="mt-3" th:text="#{MarkdownToPDF.credit}"></p> <p class="mt-3" th:text="#{MarkdownToPDF.credit}"></p>
@ -24,7 +25,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,29 +1,24 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
th:lang-direction="#{language.direction}" <head>
xmlns:th="http://www.thymeleaf.org"> <th:block th:insert="~{fragments/common :: head(title=#{PDFToBook.title}, header=#{PDFToBook.header})}"></th:block>
</head>
<th:block
th:insert="~{fragments/common :: head(title=#{PDFToBook.title}, header=#{PDFToBook.header})}"></th:block>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<h2 th:text="#{PDFToBook.header}"></h2> <h2 th:text="#{PDFToBook.header}"></h2>
<form method="post" enctype="multipart/form-data" <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/book}">
th:action="@{api/v1/convert/pdf/book}"> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div
th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{PDFToBook.selectText.1}"></label> <select <label th:text="#{PDFToBook.selectText.1}"></label>
class="form-control" name="outputFormat"> <select class="form-control" name="outputFormat">
<option value="epub">EPUB</option> <option value="epub">EPUB</option>
<option value="mobi">MOBI</option> <option value="mobi">MOBI</option>
<option value="azw3">AZW3</option> <option value="azw3">AZW3</option>
@ -36,12 +31,9 @@
<option value="pdb">PDB</option> <option value="pdb">PDB</option>
<option value="lrf">LRF</option> <option value="lrf">LRF</option>
</select> </select>
</div> </div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToBook.submit}"></button>
th:text="#{PDFToBook.submit}"></button>
</form> </form>
<p class="mt-3" th:text="#{PDFToBook.help}"></p> <p class="mt-3" th:text="#{PDFToBook.help}"></p>
<p class="mt-3" th:text="#{PDFToBook.credit}"></p> <p class="mt-3" th:text="#{PDFToBook.credit}"></p>
@ -49,7 +41,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,14 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{PDFToCSV.title}, header=#{PDFToCSV.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{PDFToCSV.title}, header=#{PDFToCSV.header})}"></th:block>
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
</br></br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -22,19 +22,15 @@
<div style="position: relative; display: inline-block;"> <div style="position: relative; display: inline-block;">
<div> <div>
<div style="display:none ;margin: 3px;position: absolute;top: 0;width: 120px;justify-content:space-between;z-index: 10" id="pagination-button-container"> <div style="display:none ;margin: 3px;position: absolute;top: 0;width: 120px;justify-content:space-between;z-index: 10" id="pagination-button-container">
<button id='previous-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> < </button> <button id='previous-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> < </button>
<button id='next-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> > </button> <button id='next-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> > </button>
</div> </div>
<canvas id="crop-pdf-canvas" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas> <canvas id="crop-pdf-canvas" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas>
</div> </div>
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas> <canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas>
</div> </div>
<script> <script>
let pdfCanvas = document.getElementById('crop-pdf-canvas'); let pdfCanvas = document.getElementById('crop-pdf-canvas');
let overlayCanvas = document.getElementById('overlayCanvas'); let overlayCanvas = document.getElementById('overlayCanvas');
// let paginationBtnContainer = ; // let paginationBtnContainer = ;
@ -61,7 +57,6 @@
let rectHeight = 0; let rectHeight = 0;
btn1Object.addEventListener('click',function (e){ btn1Object.addEventListener('click',function (e){
if (currentPage !== 1) { if (currentPage !== 1) {
currentPage = currentPage - 1; currentPage = currentPage - 1;
pageId.value = currentPage; pageId.value = currentPage;
@ -83,9 +78,7 @@
}); });
btn2Object.addEventListener('click',function (e){ btn2Object.addEventListener('click',function (e){
if (currentPage !== totalPages){ if (currentPage !== totalPages){
currentPage=currentPage+1; currentPage=currentPage+1;
pageId.value = currentPage; pageId.value = currentPage;
@ -106,20 +99,18 @@
}); });
fileInput.addEventListener('change', function(e) { fileInput.addEventListener('change', function(e) {
file = e.target.files[0]; file = e.target.files[0];
if (file.type === 'application/pdf') { if (file.type === 'application/pdf') {
let reader = new FileReader(); let reader = new FileReader();
reader.onload = function(ev) { reader.onload = function(ev) {
let typedArray = new Uint8Array(reader.result); let typedArray = new Uint8Array(reader.result);
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js' pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js';
pdfjsLib.getDocument(typedArray).promise.then(function(pdf) { pdfjsLib.getDocument(typedArray).promise.then(function(pdf) {
pdfDoc = pdf; pdfDoc = pdf;
totalPages = pdf.numPages; totalPages = pdf.numPages;
renderPage(currentPage); renderPage(currentPage);
}); });
pageId.value = currentPage; pageId.value = currentPage;
}; };
reader.readAsArrayBuffer(file); reader.readAsArrayBuffer(file);
document.getElementById("pagination-button-container").style.display="flex"; document.getElementById("pagination-button-container").style.display="flex";
@ -127,7 +118,6 @@
} }
}); });
function renderPage(pageNumber) { function renderPage(pageNumber) {
pdfDoc.getPage(pageNumber).then(function(page) { pdfDoc.getPage(pageNumber).then(function(page) {
let viewport = page.getViewport({ scale: 1.0 }); let viewport = page.getViewport({ scale: 1.0 });
@ -142,18 +132,12 @@
pdfCanvas.classList.add("shadow-canvas"); pdfCanvas.classList.add("shadow-canvas");
}); });
} }
</script> </script>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,13 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{PDFToHTML.title}, header=#{PDFToHTML.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{PDFToHTML.title}, header=#{PDFToHTML.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -16,14 +18,13 @@
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToHTML.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToHTML.submit}"></button>
</form> </form>
<p class="mt-3" th:text="#{PDFToHTML.credit}"></p> <p class="mt-3" th:text="#{PDFToHTML.credit}"></p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,16 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{pdfToImage.title}, header=#{pdfToImage.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{pdfToImage.title}, header=#{pdfToImage.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br /><br />
<br> <br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -49,13 +48,11 @@
</div> </div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToImage.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToImage.submit}"></button>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,15 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{pdfToPDFA.title}, header=#{pdfToPDFA.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{pdfToPDFA.title}, header=#{pdfToPDFA.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -24,9 +24,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,20 +1,21 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{PDFToPresentation.title}, header=#{PDFToPresentation.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{PDFToPresentation.title}, header=#{PDFToPresentation.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<h2 th:text="#{PDFToPresentation.header}"></h2> <h2 th:text="#{PDFToPresentation.header}"></h2>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/presentation}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/presentation}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{PDFToPresentation.selectText.1}"></label> <label th:text="#{PDFToPresentation.selectText.1}"></label>
<select class="form-control" name="outputFormat"> <select class="form-control" name="outputFormat">
@ -25,14 +26,13 @@
</div> </div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToPresentation.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToPresentation.submit}"></button>
</form> </form>
<p class="mt-3" th:text="#{PDFToPresentation.credit}"></p> <p class="mt-3" th:text="#{PDFToPresentation.credit}"></p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,20 +1,21 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{PDFToText.title}, header=#{PDFToText.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{PDFToText.title}, header=#{PDFToText.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<h2 th:text="#{PDFToText.header}"></h2> <h2 th:text="#{PDFToText.header}"></h2>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/text}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/text}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{PDFToText.selectText.1}"></label> <label th:text="#{PDFToText.selectText.1}"></label>
<select class="form-control" name="outputFormat"> <select class="form-control" name="outputFormat">
@ -24,12 +25,14 @@
</div> </div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToText.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToText.submit}"></button>
</form> </form>
<p class="mt-3" th:text="#{PDFToText.credit}"></p> <p class="mt-3" th:text="#{PDFToText.credit}"></p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body>
</html>

View File

@ -1,20 +1,21 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{PDFToWord.title}, header=#{PDFToWord.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{PDFToWord.title}, header=#{PDFToWord.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<h2 th:text="#{PDFToWord.header}"></h2> <h2 th:text="#{PDFToWord.header}"></h2>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/word}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/word}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{PDFToWord.selectText.1}"></label> <label th:text="#{PDFToWord.selectText.1}"></label>
<select class="form-control" name="outputFormat"> <select class="form-control" name="outputFormat">
@ -25,14 +26,13 @@
</div> </div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToWord.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToWord.submit}"></button>
</form> </form>
<p class="mt-3" th:text="#{PDFToWord.credit}"></p> <p class="mt-3" th:text="#{PDFToWord.credit}"></p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,13 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{PDFToXML.title}, header=#{PDFToXML.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{PDFToXML.title}, header=#{PDFToXML.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -16,14 +18,13 @@
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToXML.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToXML.submit}"></button>
</form> </form>
<p class="mt-3" th:text="#{PDFToXML.credit}"></p> <p class="mt-3" th:text="#{PDFToXML.credit}"></p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,13 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{URLToPDF.title}, header=#{URLToPDF.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{URLToPDF.title}, header=#{URLToPDF.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -16,14 +18,13 @@
<input type="text" class="form-control" id="urlInput" name="urlInput"> <input type="text" class="form-control" id="urlInput" name="urlInput">
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{URLToPDF.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{URLToPDF.submit}"></button>
</form> </form>
<p class="mt-3" th:text="#{URLToPDF.credit}"></p> <p class="mt-3" th:text="#{URLToPDF.credit}"></p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,14 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{crop.title}, header=#{crop.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{crop.title}, header=#{crop.header})}"></th:block>
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -25,9 +25,7 @@
<canvas id="crop-pdf-canvas" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas> <canvas id="crop-pdf-canvas" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas>
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas> <canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas>
</div> </div>
<script> <script>
let pdfCanvas = document.getElementById('crop-pdf-canvas'); let pdfCanvas = document.getElementById('crop-pdf-canvas');
let overlayCanvas = document.getElementById('overlayCanvas'); let overlayCanvas = document.getElementById('overlayCanvas');
@ -115,7 +113,6 @@
overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); // Clear the overlay overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); // Clear the overlay
}); });
function renderPage(pageNumber) { function renderPage(pageNumber) {
pdfDoc.getPage(pageNumber).then(function(page) { pdfDoc.getPage(pageNumber).then(function(page) {
let viewport = page.getViewport({ scale: 1.0 }); let viewport = page.getViewport({ scale: 1.0 });
@ -130,18 +127,9 @@
pdfCanvas.classList.add("shadow-canvas"); pdfCanvas.classList.add("shadow-canvas");
}); });
} }
</script> </script>
</div> </div>
</div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,119 +1,30 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head> <head>
<title>Error! :(</title> <th:block th:insert="~{fragments/common :: head(title='404 - Page Not Found | Oops, we tripped in the code!')}"></th:block>
<th:block th:insert="~{fragments/common :: head(title='')}"></th:block>
<style>
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, .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;
}
</style>
</head> </head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<div th:insert="~{fragments/navbar.html :: navbar}"></div>
<div th:insert="~{fragments/errorBanner.html :: errorBanner}"></div> <div th:insert="~{fragments/errorBanner.html :: errorBanner}"></div>
<div class="container"> <div class="container">
<div id="support-section"> <div id="support-section">
<h1 class="display-2">Oops!</h1> <h1 class="display-2">Oops!</h1>
<p class="lead" th:if="${param.status == '404'}">We can't seem to find the page you're looking for.</p> <p class="lead" th:if="${param.status == '404'}">
<p class="lead" th:unless="${param.status == '404'}">Something went wrong</p> We can't seem to find the page you're looking for.
</p>
<p class="lead" th:unless="${param.status == '404'}">
Something went wrong
</p>
<br> <br>
<h2>Need help / Found a issue?</h2> <h2>Need help / Found a issue?</h2>
<p>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:</p> <p>
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:
</p>
<div id="button-group"> <div id="button-group">
<a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" target="_blank">Submit a ticket on GitHub</a> <a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" target="_blank">Submit a ticket on GitHub</a>
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" target="_blank">Join our Discord server</a> <a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" target="_blank">Join our Discord server</a>
@ -122,10 +33,7 @@ margin-top: 0;
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,14 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{pageExtracter.title}, header=#{pageExtracter.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{pageExtracter.title}, header=#{pageExtracter.header})}"></th:block>
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -27,7 +27,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,4 +1,4 @@
<div th:fragment="card" class="feature-card" th:id="${id}" th:if="${@endpointConfiguration.isEndpointEnabled(cardLink)}" data-bs-tags="${tags}"> <div th:fragment="card" class="feature-card" th:id="${id}" th:if="${@endpointConfiguration.isEndpointEnabled(cardLink)}" th:data-bs-tags="${tags}">
<a th:href="${cardLink}"> <a th:href="${cardLink}">
<div class="d-flex align-items-center"> <!-- Add a flex container to align the SVG and title --> <div class="d-flex align-items-center"> <!-- Add a flex container to align the SVG and title -->
<img th:if="${svgPath}" id="card-icon" class="home-card-icon home-card-icon-colour" th:src="${svgPath}" alt="Icon" width="30" height="30"> <img th:if="${svgPath}" id="card-icon" class="home-card-icon home-card-icon-colour" th:src="${svgPath}" alt="Icon" width="30" height="30">

View File

@ -1,5 +1,4 @@
<head th:fragment="head"> <th:block th:fragment="head">
<!-- Title --> <!-- Title -->
<title th:text="${@appName} + (${title} != null and ${title} != '' ? ' - ' + ${title} : '')"></title> <title th:text="${@appName} + (${title} != null and ${title} != '' ? ' - ' + ${title} : '')"></title>
@ -46,15 +45,30 @@
<link rel="stylesheet" th:href="@{css/dark-mode.css}" id="dark-mode-styles"> <link rel="stylesheet" th:href="@{css/dark-mode.css}" id="dark-mode-styles">
<link rel="stylesheet" th:href="@{css/rainbow-mode.css}" id="rainbow-mode-styles" disabled="true"> <link rel="stylesheet" th:href="@{css/rainbow-mode.css}" id="rainbow-mode-styles" disabled="true">
<link rel="stylesheet" href="css/tab-container.css"> <link rel="stylesheet" href="css/tab-container.css">
<link rel="stylesheet" href="css/navbar.css">
<link rel="stylesheet" th:href="@{/css/error.css}" th:if="${error}">
<link rel="stylesheet" href="css/home.css" th:if="${currentPage == 'home'}">
<link rel="stylesheet" href="css/account.css" th:if="${currentPage == 'account'}">
<link rel="stylesheet" href="css/licenses.css" th:if="${currentPage == 'licenses'}">
<link rel="stylesheet" href="css/multi-tool.css" th:if="${currentPage == 'multi-tool'}">
<link rel="stylesheet" href="css/rotate-pdf.css" th:if="${currentPage == 'rotate-pdf'}">
<link rel="stylesheet" href="css/stamp.css" th:if="${currentPage == 'stamp'}">
<link rel="stylesheet" href="css/fileSelect.css">
<link rel="stylesheet" href="css/footer.css">
<!-- Help Modal -->
<link rel="stylesheet" href="css/errorBanner.css">
<script src="js/tab-container.js"></script> <script src="js/tab-container.js"></script>
<script src="js/darkmode.js"></script>
</th:block>
</head>
<th:block th:fragment="game"> <th:block th:fragment="game">
<dialog id="game-container-wrapper" class="game-container-wrapper" data-bs-modal> <dialog id="game-container-wrapper" class="game-container-wrapper" data-bs-modal>
<script> <script>
console.log("loaded game") console.log("loaded game");
$(document).ready(function() { $(document).ready(function() {
function loadGameScript(callback) { function loadGameScript(callback) {
console.log('loadGameScript called'); console.log('loadGameScript called');
@ -64,7 +78,7 @@
document.body.appendChild(script); document.body.appendChild(script);
} }
let gameScriptLoaded = false; let gameScriptLoaded = false;
const gameDialog = document.getElementById('game-container-wrapper') const gameDialog = document.getElementById('game-container-wrapper');
$('#show-game-btn').on('click', function() { $('#show-game-btn').on('click', function() {
console.log('Show game button clicked'); console.log('Show game button clicked');
if (!gameScriptLoaded) { if (!gameScriptLoaded) {
@ -87,7 +101,7 @@
e.clientY < dialogDimensions.top || e.clientY < dialogDimensions.top ||
e.clientY > dialogDimensions.bottom e.clientY > dialogDimensions.bottom
) { ) {
gameDialog.close() gameDialog.close();
} }
}) })
}) })
@ -111,10 +125,7 @@
</script> </script>
<script src="js/downloader.js"></script> <script src="js/downloader.js"></script>
<div class="custom-file-chooser" th:attr="data-bs-unique-id=${name}, <div class="custom-file-chooser" th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}">
data-bs-element-id=${name+'-input'},
data-bs-files-selected=#{filesSelected},
data-bs-pdf-prompt=#{pdfPrompt}">
<div class="mb-3"> <div class="mb-3">
<input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" multiple th:required="${notRequired} ? null : 'required'"> <input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" multiple th:required="${notRequired} ? null : 'required'">
</div> </div>
@ -129,9 +140,5 @@
</div> </div>
</div> </div>
<button type="button" class="btn btn-primary" id="show-game-btn" style="display:none;">Bored waiting?</button> <button type="button" class="btn btn-primary" id="show-game-btn" style="display:none;">Bored waiting?</button>
<script src="js/fileInput.js"></script> <script src="js/fileInput.js"></script>
<link rel="stylesheet" href="css/fileSelect.css">
</th:block> </th:block>

View File

@ -1,23 +1,5 @@
<th:block th:fragment="errorBanner"> <th:block th:fragment="errorBanner">
<style>
#github-button,
#discord-button {
display: inline-block;
padding: 1rem 2rem;
background-color: #008CBA;
color: #fff;
text-align: center;
text-decoration: none;
border-radius: 3rem;
transition: all 0.3s ease-in-out;
}
#github-button:hover,
#discord-button:hover {
background-color: #005b7f;
}
</style>
<br th:if="${message}"> <br th:if="${message}">
<div id="errorContainer" th:if="${message}" class="alert alert-danger alert-dismissible fade show" role="alert"> <div id="errorContainer" th:if="${message}" class="alert alert-danger alert-dismissible fade show" role="alert">
<h4 class="alert-heading" th:text="'Error: ' + ${status} + ' ' + ${error}"></h4> <h4 class="alert-heading" th:text="'Error: ' + ${status} + ' ' + ${error}"></h4>

View File

@ -1,6 +1,4 @@
<th:block th:fragment="errorBannerPerPage"> <th:block th:fragment="errorBannerPerPage">
<div id="errorContainer" class="alert alert-danger alert-dismissible fade show" role="alert" style="display: none;"> <div id="errorContainer" class="alert alert-danger alert-dismissible fade show" role="alert" style="display: none;">
<h4 class="alert-heading">Error</h4> <h4 class="alert-heading">Error</h4>
<p></p> <p></p>
@ -16,14 +14,8 @@
<pre id="traceContent"></pre> <pre id="traceContent"></pre>
</div> </div>
</div> </div>
</div> </div>
<!-- Help Modal -->
<link rel="stylesheet" href="css/errorBanner.css">
<div class="modal fade" id="helpModal" tabindex="-1" role="dialog" aria-labelledby="helpModalLabel" aria-hidden="true"> <div class="modal fade" id="helpModal" tabindex="-1" role="dialog" aria-labelledby="helpModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document" id="helpModalDialog"> <div class="modal-dialog modal-dialog-centered" role="document" id="helpModalDialog">
<div class="modal-content"> <div class="modal-content">
@ -34,7 +26,6 @@
</button> </button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="container"> <div class="container">
<div id="support-section"> <div id="support-section">
<h1 class="display-2">Oops!</h1> <h1 class="display-2">Oops!</h1>

View File

@ -1,58 +1,19 @@
<div th:fragment="footer"> <footer th:fragment="footer" id="footer" class="text-center py-3">
<footer id="footer" class="text-center py-3">
<div class="footer-center"> <div class="footer-center">
<a href="https://github.com/Stirling-Tools/Stirling-PDF" target="_blank" class="mx-1" title="Visit Github Repository">
<a href="https://github.com/Stirling-Tools/Stirling-PDF" <img src="images/github.svg">
target="_blank" class="mx-1" title="Visit Github Repository"><img </a>
src="images/github.svg"></img></a> <a <a href="https://hub.docker.com/r/frooodle/s-pdf" target="_blank" class="mx-1" title="See Docker Hub">
href="https://hub.docker.com/r/frooodle/s-pdf" target="_blank" <img src="images/docker.svg">
class="mx-1" title="See Docker Hub"><img src="images/docker.svg"></img></a> </a>
<a href="https://discord.gg/Cn8pWhQRxZ" target="_blank" class="mx-1" <a href="https://discord.gg/Cn8pWhQRxZ" target="_blank" class="mx-1" title="Join Discord Channel">
title="Join Discord Channel"><img src="images/discord.svg"></img></a> <img src="images/discord.svg">
<a href="https://github.com/sponsors/Frooodle" target="_blank" </a>
class="mx-1" title="Donate"><img <a href="https://github.com/sponsors/Frooodle" target="_blank" class="mx-1" title="Donate">
src="images/suit-heart-fill.svg"></img></a> <img src="images/suit-heart-fill.svg">
</a>
<div style="color: grey;" th:if="${@appName} != 'Stirling PDF'" class="footer-powered-by" th:text="#{poweredBy} + ' Stirling PDF'"></div> <div style="color: grey;" th:if="${@appName} != 'Stirling PDF'" class="footer-powered-by" th:text="#{poweredBy} + ' Stirling PDF'"></div>
</div> </div>
<a href="licenses" id="licenses" target="_blank" class="mx-1" title="" th:text="#{licenses.nav}">Licenses</a> <a href="licenses" id="licenses" target="_blank" class="mx-1" title="" th:text="#{licenses.nav}">Licenses</a>
</footer> </footer>
</div>
<style>
#footer {
display: flex;
flex-direction: column; /* Stack children vertically */
justify-content: center;
align-items: center;
width: 100%;
}
.footer-center {
display: flex;
flex-direction: column; /* Stack items vertically */
justify-content: center; /* Center children vertically */
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 */
}
.right-link-container {
align-self: flex-end; /* Align to the end of the flex container */
padding-right: 20px;
}
</style>

View File

@ -1,107 +1,28 @@
<th:block th:fragment="langs"> <th:block th:fragment="langs">
<a class="dropdown-item lang_dropdown-item" href="" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="bg_BG"> <img src="images/flags/bg.svg" alt="icon" width="20" height="15"> Български</a>
data-bs-language-code="bg_BG"> <img src="images/flags/bg.svg" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ar_AR"> <img src="images/flags/sa.svg" alt="icon" width="20" height="15"> العربية</a>
alt="icon" width="20" height="15"> Български <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ca_CA"> <img src="images/flags/es-ct.svg" alt="icon" width="20" height="15"> Català</a>
</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="zh_CN"> <img src="images/flags/cn.svg" alt="icon" width="20" height="15"> 简体中文</a>
<a class="dropdown-item lang_dropdown-item" href="" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="zh_TW"> <img src="images/flags/tw.svg" alt="icon" width="20" height="15"> 正體中文</a>
data-bs-language-code="ar_AR"> <img src="images/flags/sa.svg" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="de_DE"> <img src="images/flags/de.svg" alt="icon" width="20" height="15"> Deutsch</a>
alt="icon" width="20" height="15"> العربية <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="en_GB"> <img src="images/flags/gb.svg" alt="icon" width="20" height="15"> English (GB)</a>
</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="en_US"> <img src="images/flags/us.svg" alt="icon" width="20" height="15"> English (US)</a>
<a class="dropdown-item lang_dropdown-item" href="" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="eu_ES"> <img src="images/flags/eu.svg" alt="icon" width="20" height="15"> Euskara</a>
data-bs-language-code="ca_CA"> <img src="images/flags/es-ct.svg" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="es_ES"> <img src="images/flags/es.svg" alt="icon" width="20" height="15"> Español</a>
alt="icon" width="20" height="15"> Català <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="fr_FR"> <img src="images/flags/fr.svg" alt="icon" width="20" height="15"> Français</a>
</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="id_ID"> <img src="images/flags/id.svg" alt="icon" width="20" height="15"> Indonesia</a>
<a class="dropdown-item lang_dropdown-item" href="" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="it_IT"> <img src="images/flags/it.svg" alt="icon" width="20" height="15"> Italiano</a>
data-bs-language-code="zh_CN"> <img src="images/flags/cn.svg" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="nl_NL"> <img src="images/flags/nl.svg" alt="icon" width="20" height="15"> Nederlands</a>
alt="icon" width="20" height="15"> 简体中文 <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pl_PL"> <img src="images/flags/pl.svg" alt="icon" width="20" height="15"> Polski</a>
</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pt_BR"> <img src="images/flags/pt_br.svg" alt="icon" width="20" height="15"> Português (BR)</a>
<a class="dropdown-item lang_dropdown-item" href="" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ro_RO"> <img src="images/flags/ro.svg" alt="icon" width="20" height="15"> Romanian</a>
data-bs-language-code="zh_TW"> <img src="images/flags/tw.svg" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="sv_SE"> <img src="images/flags/se.svg" alt="icon" width="20" height="15"> Svenska</a>
alt="icon" width="20" height="15"> 正體中文 <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="tr_TR"> <img src="images/flags/tr.svg" alt="icon" width="20" height="15"> Türkçe</a>
</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ru_RU"> <img src="images/flags/ru.svg" alt="icon" width="20" height="15"> Русский</a>
<a class="dropdown-item lang_dropdown-item" href="" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ko_KR"> <img src="images/flags/kr.svg" alt="icon" width="20" height="15"> 한국어</a>
data-bs-language-code="de_DE"> <img src="images/flags/de.svg" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ja_JP"> <img src="images/flags/jp.svg" alt="icon" width="20" height="15"> 日本語</a>
alt="icon" width="20" height="15"> Deutsch <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="el_GR"> <img src="images/flags/gr.svg" alt="icon" width="20" height="15"> Ελληνικά</a>
</a> <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="hu_HU"> <img src="images/flags/hu.svg" alt="icon" width="20" height="15"> Hungarian</a>
<a class="dropdown-item lang_dropdown-item" href="" <a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="hi_IN"> <img src="images/flags/in.svg" alt="icon" width="20" height="15"> हिन्दी</a>
data-bs-language-code="en_GB"> <img src="images/flags/gb.svg" <a class="dropdown-item lang_dropdown-item" href="" data-language-code="sr-Latn-RS"> <img src="images/flags/rs.svg" alt="icon" width="20" height="15"> Srpski</a>
alt="icon" width="20" height="15"> English (GB)
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="en_US"> <img src="images/flags/us.svg"
alt="icon" width="20" height="15"> English (US)
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="eu_ES"> <img src="images/flags/eu.svg"
alt="icon" width="20" height="15"> Euskara
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="es_ES"> <img src="images/flags/es.svg"
alt="icon" width="20" height="15"> Español
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="fr_FR"> <img src="images/flags/fr.svg"
alt="icon" width="20" height="15"> Français
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="id_ID"> <img src="images/flags/id.svg"
alt="icon" width="20" height="15"> Indonesia
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="it_IT"> <img src="images/flags/it.svg"
alt="icon" width="20" height="15"> Italiano
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="nl_NL"> <img src="images/flags/nl.svg"
alt="icon" width="20" height="15"> Nederlands
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="pl_PL"> <img src="images/flags/pl.svg"
alt="icon" width="20" height="15"> Polski
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="pt_BR"> <img src="images/flags/pt_br.svg"
alt="icon" width="20" height="15"> Português (BR)
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="ro_RO"> <img src="images/flags/ro.svg"
alt="icon" width="20" height="15"> Romanian
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="sv_SE"> <img src="images/flags/se.svg"
alt="icon" width="20" height="15"> Svenska
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="tr_TR"> <img src="images/flags/tr.svg"
alt="icon" width="20" height="15"> Türkçe
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="ru_RU"> <img src="images/flags/ru.svg"
alt="icon" width="20" height="15"> Русский
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="ko_KR"> <img src="images/flags/kr.svg"
alt="icon" width="20" height="15"> 한국어
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="ja_JP"> <img src="images/flags/jp.svg"
alt="icon" width="20" height="15"> 日本語
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="el_GR"> <img src="images/flags/gr.svg"
alt="icon" width="20" height="15"> Ελληνικά
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="hu_HU"> <img src="images/flags/hu.svg"
alt="icon" width="20" height="15"> Hungarian
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-bs-language-code="hi_IN"> <img src="images/flags/in.svg"
alt="icon" width="20" height="15"> हिन्दी
</a>
<a class="dropdown-item lang_dropdown-item" href=""
data-language-code="sr-Latn-RS"> <img src="images/flags/rs.svg"
alt="icon" width="20" height="15"> Srpski
</a>
</th:block> </th:block>

View File

@ -1,31 +1,21 @@
<div th:fragment="navbar" class="mx-auto"> <div th:fragment="navbar" class="mx-auto">
<script src="js/languageSelection.js"></script> <script src="js/languageSelection.js"></script>
<script th:inline="javascript"> <script th:inline="javascript">
const currentVersion = /*[[${@appVersion}]]*/ ''; const currentVersion = /*[[${@appVersion}]]*/ '';
const noFavourites = /*[[#{noFavourites}]]*/ ''; const noFavourites = /*[[#{noFavourites}]]*/ '';
</script> </script>
<script th:src="@{js/githubVersion.js}"></script> <script th:src="@{js/githubVersion.js}"></script>
<link rel="stylesheet" href="css/navbar.css">
<nav class="navbar navbar-expand-lg navbar-light bg-light"> <nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container "> <div class="container ">
<a class="navbar-brand" href="#" th:href="@{/}" style="display: flex;">
<a class="navbar-brand" href="#" th:href="@{/}" >
<img class="main-icon" src="favicon.svg?v=2" alt="icon"> <img class="main-icon" src="favicon.svg?v=2" alt="icon">
<span class="icon-text" th:text="${@navBarText}"></span> <span class="icon-text" th:text="${@navBarText}"></span>
</a> </a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse" id="navbarNav"> <div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto flex-nowrap"> <ul class="navbar-nav me-auto flex-nowrap">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="#" th:href="@{multi-tool}" th:classappend="${currentPage}=='multi-tool' ? 'active' : ''" th:title="#{home.multiTool.desc}"> <a class="nav-link" href="#" th:href="@{multi-tool}" th:classappend="${currentPage}=='multi-tool' ? 'active' : ''" th:title="#{home.multiTool.desc}">
<img class="icon" src="images/tools.svg" alt="icon"> <img class="icon" src="images/tools.svg" alt="icon">
@ -39,7 +29,6 @@
<span class="icon-text" th:text="#{home.pipeline.title}"></span> <span class="icon-text" th:text="#{home.pipeline.title}"></span>
</a> </a>
</li> </li>
<li class="nav-item nav-item-separator"></li> <li class="nav-item nav-item-separator"></li>
<li class="nav-item dropdown" th:classappend="${currentPage}=='remove-pages' OR ${currentPage}=='merge-pdfs' OR ${currentPage}=='split-pdfs' OR ${currentPage}=='crop' OR ${currentPage}=='adjust-contrast' OR ${currentPage}=='pdf-organizer' OR ${currentPage}=='rotate-pdf' OR ${currentPage}=='multi-page-layout' OR ${currentPage}=='scale-pages' OR ${currentPage}=='auto-split-pdf' OR ${currentPage}=='extract-page' OR ${currentPage}=='pdf-to-single-page' ? 'active' : ''"> <li class="nav-item dropdown" th:classappend="${currentPage}=='remove-pages' OR ${currentPage}=='merge-pdfs' OR ${currentPage}=='split-pdfs' OR ${currentPage}=='crop' OR ${currentPage}=='adjust-contrast' OR ${currentPage}=='pdf-organizer' OR ${currentPage}=='rotate-pdf' OR ${currentPage}=='multi-page-layout' OR ${currentPage}=='scale-pages' OR ${currentPage}=='auto-split-pdf' OR ${currentPage}=='extract-page' OR ${currentPage}=='pdf-to-single-page' ? 'active' : ''">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@ -65,9 +54,11 @@
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdf-by-sections', 'images/layout-split.svg', 'home.split-by-sections.title', 'home.split-by-sections.desc', 'split-by-sections.tags')}"></div> <div th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdf-by-sections', 'images/layout-split.svg', 'home.split-by-sections.title', 'home.split-by-sections.desc', 'split-by-sections.tags')}"></div>
</div> </div>
</li> </li>
<li class="nav-item nav-item-separator"></li> <li class="nav-item nav-item-separator"></li>
<li class="nav-item dropdown" th:classappend="${currentPage}=='pdf-to-img' OR ${currentPage}=='img-to-pdf' OR ${currentPage}=='pdf-to-pdfa' OR ${currentPage}=='file-to-pdf' OR ${currentPage}=='xlsx-to-pdf' OR ${currentPage}=='pdf-to-word' OR ${currentPage}=='pdf-to-presentation' OR ${currentPage}=='pdf-to-text' OR ${currentPage}=='pdf-to-html' OR ${currentPage}=='pdf-to-xml' ? 'active' : ''"><a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown"
aria-haspopup="true" aria-expanded="false"> <li class="nav-item dropdown" th:classappend="${currentPage}=='pdf-to-img' OR ${currentPage}=='img-to-pdf' OR ${currentPage}=='pdf-to-pdfa' OR ${currentPage}=='file-to-pdf' OR ${currentPage}=='xlsx-to-pdf' OR ${currentPage}=='pdf-to-word' OR ${currentPage}=='pdf-to-presentation' OR ${currentPage}=='pdf-to-text' OR ${currentPage}=='pdf-to-html' OR ${currentPage}=='pdf-to-xml' ? 'active' : ''">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img class="icon" src="images/arrow-left-right.svg" alt="icon" style="width: 16px; height: 16px; vertical-align: middle;"> <img class="icon" src="images/arrow-left-right.svg" alt="icon" style="width: 16px; height: 16px; vertical-align: middle;">
<span class="icon-text" th:text="#{navbar.convert}"></span> <span class="icon-text" th:text="#{navbar.convert}"></span>
</a> </a>
@ -110,14 +101,15 @@
</li> </li>
<li class="nav-item nav-item-separator"></li> <li class="nav-item nav-item-separator"></li>
<li class="nav-item dropdown" th:classappend="${currentPage}=='sign' OR ${currentPage}=='repair' OR ${currentPage}=='compare' OR ${currentPage}=='show-javascript' OR ${currentPage}=='flatten' OR ${currentPage}=='remove-blanks' OR ${currentPage}=='remove-annotations' OR ${currentPage}=='extract-image-scans' OR ${currentPage}=='change-metadata' OR ${currentPage}=='add-image' OR ${currentPage}=='ocr-pdf' OR ${currentPage}=='change-permissions' OR ${currentPage}=='extract-images' OR ${currentPage}=='compress-pdf' OR ${currentPage}=='add-page-numbers' OR ${currentPage}=='auto-rename' OR ${currentPage}=='get-info-on-pdf' ? 'active' : ''"> <li class="nav-item dropdown" th:classappend="${currentPage}=='sign' OR ${currentPage}=='repair' OR ${currentPage}=='compare' OR ${currentPage}=='show-javascript' OR ${currentPage}=='flatten' OR ${currentPage}=='remove-blanks' OR ${currentPage}=='remove-annotations' OR ${currentPage}=='extract-image-scans' OR ${currentPage}=='change-metadata' OR ${currentPage}=='add-image' OR ${currentPage}=='ocr-pdf' OR ${currentPage}=='change-permissions' OR ${currentPage}=='extract-images' OR ${currentPage}=='compress-pdf' OR ${currentPage}=='add-page-numbers' OR ${currentPage}=='auto-rename' OR ${currentPage}=='get-info-on-pdf' ? 'active' : ''">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img class="icon" src="images/card-list.svg" alt="icon" style="width: 16px; height: 16px; vertical-align: middle;"> <img class="icon" src="images/card-list.svg" alt="icon" style="width: 16px; height: 16px; vertical-align: middle;">
<span class="icon-text" th:text="#{navbar.other}"></span> <span class="icon-text" th:text="#{navbar.other}"></span>
</a> </a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown"> <div class="dropdown-menu" aria-labelledby="navbarDropdown">
<!--<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pipeline', 'images/pipeline.svg', 'home.pipeline.title', 'home.pipeline.desc', 'pipeline.tags')}"></div> --> <!--<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pipeline', 'images/pipeline.svg', 'home.pipeline.title', 'home.pipeline.desc', 'pipeline.tags')}"></div> -->
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('view-pdf', 'images/book-opened.svg', 'home.viewPdf.title', 'home.viewPdf.desc', 'viewPdf.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('ocr-pdf', 'images/search.svg', 'home.ocr.title', 'home.ocr.desc', 'ocr.tags')}"></div> <div th:replace="~{fragments/navbarEntry :: navbarEntry ('ocr-pdf', 'images/search.svg', 'home.ocr.title', 'home.ocr.desc', 'ocr.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('add-image', 'images/file-earmark-richtext.svg', 'home.addImage.title', 'home.addImage.desc', 'addImage.tags')}"></div> <div th:replace="~{fragments/navbarEntry :: navbarEntry ('add-image', 'images/file-earmark-richtext.svg', 'home.addImage.title', 'home.addImage.desc', 'addImage.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('compress-pdf', 'images/file-zip.svg', 'home.compressPdfs.title', 'home.compressPdfs.desc', 'compressPdfs.tags')}"></div> <div th:replace="~{fragments/navbarEntry :: navbarEntry ('compress-pdf', 'images/file-zip.svg', 'home.compressPdfs.title', 'home.compressPdfs.desc', 'compressPdfs.tags')}"></div>
@ -137,8 +129,6 @@
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('stamp', 'images/stamp.svg', 'home.AddStampRequest.title', 'home.AddStampRequest.desc', 'AddStampRequest.tags')}"></div> <div th:replace="~{fragments/navbarEntry :: navbarEntry ('stamp', 'images/stamp.svg', 'home.AddStampRequest.title', 'home.AddStampRequest.desc', 'AddStampRequest.tags')}"></div>
</div> </div>
</li> </li>
</ul> </ul>
<ul class="navbar-nav flex-nowrap"> <ul class="navbar-nav flex-nowrap">
<li class="nav-item dropdown"> <li class="nav-item dropdown">
@ -149,18 +139,12 @@
<!-- Dropdown items will be added here by JavaScript --> <!-- Dropdown items will be added here by JavaScript -->
</div> </div>
</li> </li>
<script src="js/languageSelection.js"></script> <script src="js/languageSelection.js"></script>
<script src="js/darkmode.js"></script>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" id="dark-mode-toggle" href="#"> <a class="nav-link" id="dark-mode-toggle" href="#">
<img class="navbar-icon" id="dark-mode-icon" src="moon.svg" alt="icon" /> <img class="navbar-icon" id="dark-mode-icon" src="moon.svg" alt="icon" />
</a> </a>
</li> </li>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <a class="nav-link dropdown-toggle" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-globe2 globe-icon" viewBox="0 0 20 20"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-globe2 globe-icon" viewBox="0 0 20 20">
@ -171,16 +155,12 @@
<th:block th:insert="~{fragments/languages :: langs}"></th:block> <th:block th:insert="~{fragments/languages :: langs}"></th:block>
</div> </div>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<!-- Settings Button --> <!-- Settings Button -->
<a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#settingsModal"> <a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#settingsModal">
<img class="navbar-icon" src="images/gear.svg" alt="icon" width="24" height="24"> <img class="navbar-icon" src="images/gear.svg" alt="icon" width="24" height="24">
</a> </a>
</li> </li>
<!-- Search Button and Search Bar --> <!-- Search Button and Search Bar -->
<li class="nav-item position-relative"> <li class="nav-item position-relative">
<a href="#" class="nav-link" id="search-icon"> <a href="#" class="nav-link" id="search-icon">
@ -195,66 +175,14 @@
<div id="searchResults" class="border p-2 bg-white search-results"></div> <div id="searchResults" class="border p-2 bg-white search-results"></div>
</div> </div>
</li> </li>
<style>
#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 */
}
#navbarSearch {
transition: all 0.3s;
max-height: 0;
overflow: hidden;
}
#navbarSearch.show {
max-height: 300px; /* Adjust this to your desired max height */
}
.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 */
}
#searchResults {
max-width: 300px; /* Adjust to your preferred width */
transition: height 0.3s ease; /* Smooth height transition */
}
/* 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 */
}
</style>
</ul> </ul>
</div> </div>
</div> </div>
<script src="js/favourites.js"></script> <script src="js/favourites.js"></script>
<script src="js/search.js"></script> <script src="js/search.js"></script>
</nav> </nav>
<div th:insert="~{fragments/errorBannerPerPage.html :: errorBannerPerPage}"></div> <th:block th:insert="~{fragments/errorBannerPerPage.html :: errorBannerPerPage}"></th:block>
<div class="modal fade" id="settingsModal" tabindex="-1" role="dialog" aria-labelledby="settingsModalLabel" aria-hidden="true"> <div class="modal fade" id="settingsModal" tabindex="-1" role="dialog" aria-labelledby="settingsModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document"> <div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content dark-card"> <div class="modal-content dark-card">
@ -305,11 +233,5 @@
</div> </div>
</div> </div>
</div> </div>
<script src="js/settings.js"></script> <script src="js/settings.js"></script>
</div> </div>

View File

@ -1,6 +1,6 @@
<div th:fragment="navbarEntry (endpoint, imgSrc, titleKey, descKey, tagKey)" th:if="${@endpointConfiguration.isEndpointEnabled(endpoint)}"> <th:block th:fragment="navbarEntry(endpoint, imgSrc, titleKey, descKey, tagKey)" th:if="${@endpointConfiguration.isEndpointEnabled(endpoint)}">
<a class="dropdown-item" href="#" th:href="@{${endpoint}}" th:classappend="${endpoint.equals(currentPage)} ? 'active' : ''" th:title="#{${descKey}}" th:data-bs-tags="#{${tagKey}}"> <a class="dropdown-item" href="#" th:href="@{${endpoint}}" th:classappend="${endpoint.equals(currentPage)} ? 'active' : ''" th:title="#{${descKey}}" th:data-bs-tags="#{${tagKey}}">
<img class="icon" th:src="@{${imgSrc}}" alt="icon"> <img class="icon" th:src="@{${imgSrc}}" alt="icon">
<span class="icon-text" th:text="#{${titleKey}}"></span> <span class="icon-text" th:text="#{${titleKey}}"></span>
</a> </a>
</div> </th:block>

View File

@ -1,16 +1,13 @@
<!doctype html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title='')}"></th:block> <th:block th:insert="~{fragments/common :: head(title='')}"></th:block>
</head>
<link rel="stylesheet" href="css/home.css">
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<!-- Jumbotron --> <!-- Jumbotron -->
<div class="bg-light p-5 rounded d-none d-md-block" id="jumbotron"> <div class="bg-light p-5 rounded d-none d-md-block" id="jumbotron">
<div class="container"> <div class="container">
@ -26,90 +23,84 @@
<br> <br>
<input type="text" id="searchBar" onkeyup="filterCards()" th:placeholder="#{home.searchBar}"> <input type="text" id="searchBar" onkeyup="filterCards()" th:placeholder="#{home.searchBar}">
<div class="features-container"> <div class="features-container">
<th:block th:if="${@enableAlphaFunctionality}"> <th:block th:if="${@enableAlphaFunctionality}">
<div th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', svgPath='images/pipeline.svg')}"></div> <div th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', svgPath='images/pipeline.svg', tags=#{pipeline.tags})}"></div>
</th:block> </th:block>
<div th:replace="~{fragments/card :: card(id='view-pdf', cardTitle=#{home.viewPdf.title}, cardText=#{home.viewPdf.desc}, cardLink='view-pdf', svgPath='images/book-opened.svg', tags=#{viewPdf.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', svgPath='images/tools.svg', tags=#{multiTool.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='merge-pdfs', cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs', svgPath='images/union.svg', tags=#{merge.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='split-pdfs', cardTitle=#{home.split.title}, cardText=#{home.split.desc}, cardLink='split-pdfs', svgPath='images/layout-split.svg', tags=#{split.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='view-pdf', cardTitle=#{home.viewPdf.title}, cardText=#{home.viewPdf.desc}, cardLink='view-pdf', svgPath='images/book-opened.svg')}"></div> <div th:replace="~{fragments/card :: card(id='rotate-pdf', cardTitle=#{home.rotate.title}, cardText=#{home.rotate.desc}, cardLink='rotate-pdf', svgPath='images/arrow-clockwise.svg', tags=#{rotate.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', svgPath='images/tools.svg')}"></div> <div th:replace="~{fragments/card :: card(id='crop', cardTitle=#{home.crop.title}, cardText=#{home.crop.desc}, cardLink='crop', svgPath='images/crop.svg', tags=#{crop.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='merge-pdfs', cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs', svgPath='images/union.svg')}"></div> <div th:replace="~{fragments/card :: card(id='add-page-numbers', cardTitle=#{home.add-page-numbers.title}, cardText=#{home.add-page-numbers.desc}, cardLink='add-page-numbers', svgPath='images/add-page-numbers.svg', tags=#{add-page-numbers.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='split-pdfs', cardTitle=#{home.split.title}, cardText=#{home.split.desc}, cardLink='split-pdfs', svgPath='images/layout-split.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='rotate-pdf', cardTitle=#{home.rotate.title}, cardText=#{home.rotate.desc}, cardLink='rotate-pdf', svgPath='images/arrow-clockwise.svg')}"></div> <div th:replace="~{fragments/card :: card(id='adjust-contrast', cardTitle=#{home.adjust-contrast.title}, cardText=#{home.adjust-contrast.desc}, cardLink='adjust-contrast', svgPath='images/adjust-contrast.svg', tags=#{adjust-contrast.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='crop', cardTitle=#{home.crop.title}, cardText=#{home.crop.desc}, cardLink='crop', svgPath='images/crop.svg')}"></div> <div th:replace="~{fragments/card :: card(id='img-to-pdf', cardTitle=#{home.imageToPdf.title}, cardText=#{home.imageToPdf.desc}, cardLink='img-to-pdf', svgPath='images/image.svg', tags=#{imageToPdf.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='add-page-numbers', cardTitle=#{home.add-page-numbers.title}, cardText=#{home.add-page-numbers.desc}, cardLink='add-page-numbers', svgPath='images/add-page-numbers.svg')}"></div> <div th:replace="~{fragments/card :: card(id='pdf-to-img', cardTitle=#{home.pdfToImage.title}, cardText=#{home.pdfToImage.desc}, cardLink='pdf-to-img', svgPath='images/image.svg', tags=#{pdfToImage.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='adjust-contrast', cardTitle=#{home.adjust-contrast.title}, cardText=#{home.adjust-contrast.desc}, cardLink='adjust-contrast', svgPath='images/adjust-contrast.svg')}"></div> <div th:replace="~{fragments/card :: card(id='pdf-organizer', cardTitle=#{home.pdfOrganiser.title}, cardText=#{home.pdfOrganiser.desc}, cardLink='pdf-organizer', svgPath='images/sort-numeric-down.svg', tags=#{pdfOrganiser.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='img-to-pdf', cardTitle=#{home.imageToPdf.title}, cardText=#{home.imageToPdf.desc}, cardLink='img-to-pdf', svgPath='images/image.svg')}"></div> <div th:replace="~{fragments/card :: card(id='add-image', cardTitle=#{home.addImage.title}, cardText=#{home.addImage.desc}, cardLink='add-image', svgPath='images/file-earmark-richtext.svg', tags=#{addImage.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-img', cardTitle=#{home.pdfToImage.title}, cardText=#{home.pdfToImage.desc}, cardLink='pdf-to-img', svgPath='images/image.svg')}"></div> <div th:replace="~{fragments/card :: card(id='add-watermark', cardTitle=#{home.watermark.title}, cardText=#{home.watermark.desc}, cardLink='add-watermark', svgPath='images/droplet.svg', tags=#{watermark.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-organizer', cardTitle=#{home.pdfOrganiser.title}, cardText=#{home.pdfOrganiser.desc}, cardLink='pdf-organizer', svgPath='images/sort-numeric-down.svg')}"></div> <div th:replace="~{fragments/card :: card(id='file-to-pdf', cardTitle=#{home.fileToPDF.title}, cardText=#{home.fileToPDF.desc}, cardLink='file-to-pdf', svgPath='images/file.svg', tags=#{fileToPDF.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='add-image', cardTitle=#{home.addImage.title}, cardText=#{home.addImage.desc}, cardLink='add-image', svgPath='images/file-earmark-richtext.svg')}"></div> <div th:replace="~{fragments/card :: card(id='remove-pages', cardTitle=#{home.removePages.title}, cardText=#{home.removePages.desc}, cardLink='remove-pages', svgPath='images/file-earmark-x.svg', tags=#{removePages.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='add-watermark', cardTitle=#{home.watermark.title}, cardText=#{home.watermark.desc}, cardLink='add-watermark', svgPath='images/droplet.svg')}"></div> <div th:replace="~{fragments/card :: card(id='add-password', cardTitle=#{home.addPassword.title}, cardText=#{home.addPassword.desc}, cardLink='add-password', svgPath='images/lock.svg', tags=#{addPassword.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='file-to-pdf', cardTitle=#{home.fileToPDF.title}, cardText=#{home.fileToPDF.desc}, cardLink='file-to-pdf', svgPath='images/file.svg')}"></div> <div th:replace="~{fragments/card :: card(id='remove-password', cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password', svgPath='images/unlock.svg', tags=#{removePassword.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='remove-pages', cardTitle=#{home.removePages.title}, cardText=#{home.removePages.desc}, cardLink='remove-pages', svgPath='images/file-earmark-x.svg')}"></div> <div th:replace="~{fragments/card :: card(id='compress-pdf', cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf', svgPath='images/file-zip.svg', tags=#{compressPdfs.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='add-password', cardTitle=#{home.addPassword.title}, cardText=#{home.addPassword.desc}, cardLink='add-password', svgPath='images/lock.svg')}"></div> <div th:replace="~{fragments/card :: card(id='change-metadata', cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata', svgPath='images/clipboard-data.svg', tags=#{changeMetadata.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='remove-password', cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password', svgPath='images/unlock.svg')}"></div> <div th:replace="~{fragments/card :: card(id='change-permissions', cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions', svgPath='images/shield-lock.svg', tags=#{permissions.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='compress-pdf', cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf', svgPath='images/file-zip.svg')}"></div> <div th:replace="~{fragments/card :: card(id='ocr-pdf', cardTitle=#{home.ocr.title}, cardText=#{home.ocr.desc}, cardLink='ocr-pdf', svgPath='images/search.svg', tags=#{ocr.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='change-metadata', cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata', svgPath='images/clipboard-data.svg')}"></div> <div th:replace="~{fragments/card :: card(id='extract-images', cardTitle=#{home.extractImages.title}, cardText=#{home.extractImages.desc}, cardLink='extract-images', svgPath='images/images.svg', tags=#{extractImages.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='change-permissions', cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions', svgPath='images/shield-lock.svg')}"></div> <div th:replace="~{fragments/card :: card(id='pdf-to-pdfa', cardTitle=#{home.pdfToPDFA.title}, cardText=#{home.pdfToPDFA.desc}, cardLink='pdf-to-pdfa', svgPath='images/file-earmark-pdf.svg', tags=#{pdfToPDFA.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='ocr-pdf', cardTitle=#{home.ocr.title}, cardText=#{home.ocr.desc}, cardLink='ocr-pdf', svgPath='images/search.svg')}"></div> <div th:replace="~{fragments/card :: card(id='pdf-to-word', cardTitle=#{home.PDFToWord.title}, cardText=#{home.PDFToWord.desc}, cardLink='pdf-to-word', svgPath='images/file-earmark-word.svg', tags=#{PDFToWord.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='extract-images', cardTitle=#{home.extractImages.title}, cardText=#{home.extractImages.desc}, cardLink='extract-images', svgPath='images/images.svg')}"></div> <div th:replace="~{fragments/card :: card(id='pdf-to-presentation', cardTitle=#{home.PDFToPresentation.title}, cardText=#{home.PDFToPresentation.desc}, cardLink='pdf-to-presentation', svgPath='images/file-earmark-ppt.svg', tags=#{PDFToPresentation.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-pdfa', cardTitle=#{home.pdfToPDFA.title}, cardText=#{home.pdfToPDFA.desc}, cardLink='pdf-to-pdfa', svgPath='images/file-earmark-pdf.svg')}"></div> <div th:replace="~{fragments/card :: card(id='pdf-to-text', cardTitle=#{home.PDFToText.title}, cardText=#{home.PDFToText.desc}, cardLink='pdf-to-text', svgPath='images/filetype-txt.svg', tags=#{PDFToText.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-word', cardTitle=#{home.PDFToWord.title}, cardText=#{home.PDFToWord.desc}, cardLink='pdf-to-word', svgPath='images/file-earmark-word.svg')}"></div> <div th:replace="~{fragments/card :: card(id='pdf-to-html', cardTitle=#{home.PDFToHTML.title}, cardText=#{home.PDFToHTML.desc}, cardLink='pdf-to-html', svgPath='images/filetype-html.svg', tags=#{PDFToHTML.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-presentation', cardTitle=#{home.PDFToPresentation.title}, cardText=#{home.PDFToPresentation.desc}, cardLink='pdf-to-presentation', svgPath='images/file-earmark-ppt.svg')}"></div> <div th:replace="~{fragments/card :: card(id='pdf-to-xml', cardTitle=#{home.PDFToXML.title}, cardText=#{home.PDFToXML.desc}, cardLink='pdf-to-xml', svgPath='images/filetype-xml.svg', tags=#{PDFToXML.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-text', cardTitle=#{home.PDFToText.title}, cardText=#{home.PDFToText.desc}, cardLink='pdf-to-text', svgPath='images/filetype-txt.svg')}"></div> <div th:replace="~{fragments/card :: card(id='extract-image-scans', cardTitle=#{home.ScannerImageSplit.title}, cardText=#{home.ScannerImageSplit.desc}, cardLink='extract-image-scans', svgPath='images/scanner.svg', tags=#{ScannerImageSplit.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-html', cardTitle=#{home.PDFToHTML.title}, cardText=#{home.PDFToHTML.desc}, cardLink='pdf-to-html', svgPath='images/filetype-html.svg')}"></div> <div th:replace="~{fragments/card :: card(id='sign', cardTitle=#{home.sign.title}, cardText=#{home.sign.desc}, cardLink='sign', svgPath='images/sign.svg', tags=#{sign.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-xml', cardTitle=#{home.PDFToXML.title}, cardText=#{home.PDFToXML.desc}, cardLink='pdf-to-xml', svgPath='images/filetype-xml.svg')}"></div> <div th:replace="~{fragments/card :: card(id='flatten', cardTitle=#{home.flatten.title}, cardText=#{home.flatten.desc}, cardLink='flatten', svgPath='images/flatten.svg', tags=#{flatten.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='extract-image-scans', cardTitle=#{home.ScannerImageSplit.title}, cardText=#{home.ScannerImageSplit.desc}, cardLink='extract-image-scans', svgPath='images/scanner.svg')}"></div> <div th:replace="~{fragments/card :: card(id='repair', cardTitle=#{home.repair.title}, cardText=#{home.repair.desc}, cardLink='repair', svgPath='images/wrench.svg', tags=#{repair.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='sign', cardTitle=#{home.sign.title}, cardText=#{home.sign.desc}, cardLink='sign', svgPath='images/sign.svg')}"></div> <div th:replace="~{fragments/card :: card(id='remove-blanks', cardTitle=#{home.removeBlanks.title}, cardText=#{home.removeBlanks.desc}, cardLink='remove-blanks', svgPath='images/blank-file.svg', tags=#{removeBlanks.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='flatten', cardTitle=#{home.flatten.title}, cardText=#{home.flatten.desc}, cardLink='flatten', svgPath='images/flatten.svg')}"></div> <div th:replace="~{fragments/card :: card(id='remove-annotations', cardTitle=#{home.removeAnnotations.title}, cardText=#{home.removeAnnotations.desc}, cardLink='remove-annotations', svgPath='images/no-chat.svg', tags=#{removeAnnotations.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='compare', cardTitle=#{home.compare.title}, cardText=#{home.compare.desc}, cardLink='compare', svgPath='images/scales.svg', tags=#{compare.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='repair', cardTitle=#{home.repair.title}, cardText=#{home.repair.desc}, cardLink='repair', svgPath='images/wrench.svg')}"></div> <div th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', svgPath='images/award.svg', tags=#{certSign.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='remove-blanks', cardTitle=#{home.removeBlanks.title}, cardText=#{home.removeBlanks.desc}, cardLink='remove-blanks', svgPath='images/blank-file.svg')}"></div> <div th:replace="~{fragments/card :: card(id='multi-page-layout', cardTitle=#{home.pageLayout.title}, cardText=#{home.pageLayout.desc}, cardLink='multi-page-layout', svgPath='images/page-layout.svg', tags=#{pageLayout.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='remove-annotations', cardTitle=#{home.removeAnnotations.title}, cardText=#{home.removeAnnotations.desc}, cardLink='remove-annotations', svgPath='images/no-chat.svg')}"></div> <div th:replace="~{fragments/card :: card(id='scale-pages', cardTitle=#{home.scalePages.title}, cardText=#{home.scalePages.desc}, cardLink='scale-pages', svgPath='images/scale-pages.svg', tags=#{scalePages.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='compare', cardTitle=#{home.compare.title}, cardText=#{home.compare.desc}, cardLink='compare', svgPath='images/scales.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', svgPath='images/award.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='multi-page-layout', cardTitle=#{home.pageLayout.title}, cardText=#{home.pageLayout.desc}, cardLink='multi-page-layout', svgPath='images/page-layout.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='scale-pages', cardTitle=#{home.scalePages.title}, cardText=#{home.scalePages.desc}, cardLink='scale-pages', svgPath='images/scale-pages.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='auto-rename', cardTitle=#{home.auto-rename.title}, cardText=#{home.auto-rename.desc}, cardLink='auto-rename', svgPath='images/fonts.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='auto-split-pdf', cardTitle=#{home.autoSplitPDF.title}, cardText=#{home.autoSplitPDF.desc}, cardLink='auto-split-pdf', svgPath='images/layout-split.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='sanitize-pdf', cardTitle=#{home.sanitizePdf.title}, cardText=#{home.sanitizePdf.desc}, cardLink='sanitize-pdf', svgPath='images/sanitize.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='url-to-pdf', cardTitle=#{home.URLToPDF.title}, cardText=#{home.URLToPDF.desc}, cardLink='url-to-pdf', svgPath='images/url.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='html-to-pdf', cardTitle=#{home.HTMLToPDF.title}, cardText=#{home.HTMLToPDF.desc}, cardLink='html-to-pdf', svgPath='images/html.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='markdown-to-pdf', cardTitle=#{home.MarkdownToPDF.title}, cardText=#{home.MarkdownToPDF.desc}, cardLink='markdown-to-pdf', svgPath='images/markdown.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='get-info-on-pdf', cardTitle=#{home.getPdfInfo.title}, cardText=#{home.getPdfInfo.desc}, cardLink='get-info-on-pdf', svgPath='images/info.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='extract-page', cardTitle=#{home.extractPage.title}, cardText=#{home.extractPage.desc}, cardLink='extract-page', svgPath='images/extract.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-single-page', cardTitle=#{home.PdfToSinglePage.title}, cardText=#{home.PdfToSinglePage.desc}, cardLink='pdf-to-single-page', svgPath='images/single-page.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='show-javascript', cardTitle=#{home.showJS.title}, cardText=#{home.showJS.desc}, cardLink='show-javascript', svgPath='images/js.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='auto-redact', cardTitle=#{home.autoRedact.title}, cardText=#{home.autoRedact.desc}, cardLink='auto-redact', svgPath='images/eraser-fill.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-csv', cardTitle=#{home.tableExtraxt.title}, cardText=#{home.tableExtraxt.desc}, cardLink='pdf-to-csv', svgPath='images/pdf-csv.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='split-by-size-or-count', cardTitle=#{home.autoSizeSplitPDF.title}, cardText=#{home.autoSizeSplitPDF.desc}, cardLink='split-by-size-or-count', svgPath='images/layout-split.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='overlay-pdf', cardTitle=#{home.overlay-pdfs.title}, cardText=#{home.overlay-pdfs.desc}, cardLink='overlay-pdf', svgPath='images/overlay.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='split-pdf-by-sections', cardTitle=#{home.split-by-sections.title}, cardText=#{home.split-by-sections.desc}, cardLink='split-pdf-by-sections', svgPath='images/layout-split.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='book-to-pdf', cardTitle=#{home.BookToPDF.title}, cardText=#{home.BookToPDF.desc}, cardLink='book-to-pdf', svgPath='images/book.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-book', cardTitle=#{home.PDFToBook.title}, cardText=#{home.PDFToBook.desc}, cardLink='pdf-to-book', svgPath='images/book.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='stamp', cardTitle=#{home.AddStampRequest.title}, cardText=#{home.AddStampRequest.desc}, cardLink='stamp', svgPath='images/stamp.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='auto-rename', cardTitle=#{home.auto-rename.title}, cardText=#{home.auto-rename.desc}, cardLink='auto-rename', svgPath='images/fonts.svg', tags=#{auto-rename.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='auto-split-pdf', cardTitle=#{home.autoSplitPDF.title}, cardText=#{home.autoSplitPDF.desc}, cardLink='auto-split-pdf', svgPath='images/layout-split.svg', tags=#{autoSplitPDF.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='sanitize-pdf', cardTitle=#{home.sanitizePdf.title}, cardText=#{home.sanitizePdf.desc}, cardLink='sanitize-pdf', svgPath='images/sanitize.svg', tags=#{sanitizePdf.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='url-to-pdf', cardTitle=#{home.URLToPDF.title}, cardText=#{home.URLToPDF.desc}, cardLink='url-to-pdf', svgPath='images/url.svg', tags=#{URLToPDF.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='html-to-pdf', cardTitle=#{home.HTMLToPDF.title}, cardText=#{home.HTMLToPDF.desc}, cardLink='html-to-pdf', svgPath='images/html.svg', tags=#{HTMLToPDF.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='markdown-to-pdf', cardTitle=#{home.MarkdownToPDF.title}, cardText=#{home.MarkdownToPDF.desc}, cardLink='markdown-to-pdf', svgPath='images/markdown.svg', tags=#{MarkdownToPDF.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='get-info-on-pdf', cardTitle=#{home.getPdfInfo.title}, cardText=#{home.getPdfInfo.desc}, cardLink='get-info-on-pdf', svgPath='images/info.svg', tags=#{getPdfInfo.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='extract-page', cardTitle=#{home.extractPage.title}, cardText=#{home.extractPage.desc}, cardLink='extract-page', svgPath='images/extract.svg', tags=#{extractPage.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-single-page', cardTitle=#{home.PdfToSinglePage.title}, cardText=#{home.PdfToSinglePage.desc}, cardLink='pdf-to-single-page', svgPath='images/single-page.svg', tags=#{PdfToSinglePage.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='show-javascript', cardTitle=#{home.showJS.title}, cardText=#{home.showJS.desc}, cardLink='show-javascript', svgPath='images/js.svg', tags=#{showJS.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='auto-redact', cardTitle=#{home.autoRedact.title}, cardText=#{home.autoRedact.desc}, cardLink='auto-redact', svgPath='images/eraser-fill.svg', tags=#{autoRedact.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-csv', cardTitle=#{home.tableExtraxt.title}, cardText=#{home.tableExtraxt.desc}, cardLink='pdf-to-csv', svgPath='images/pdf-csv.svg', tags=#{tableExtraxt.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='split-by-size-or-count', cardTitle=#{home.autoSizeSplitPDF.title}, cardText=#{home.autoSizeSplitPDF.desc}, cardLink='split-by-size-or-count', svgPath='images/layout-split.svg', tags=#{autoSizeSplitPDF.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='overlay-pdf', cardTitle=#{home.overlay-pdfs.title}, cardText=#{home.overlay-pdfs.desc}, cardLink='overlay-pdf', svgPath='images/overlay.svg', tags=#{overlay-pdfs.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='split-pdf-by-sections', cardTitle=#{home.split-by-sections.title}, cardText=#{home.split-by-sections.desc}, cardLink='split-pdf-by-sections', svgPath='images/layout-split.svg', tags=#{split-by-sections.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='book-to-pdf', cardTitle=#{home.BookToPDF.title}, cardText=#{home.BookToPDF.desc}, cardLink='book-to-pdf', svgPath='images/book.svg', tags=#{BookToPDF.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-book', cardTitle=#{home.PDFToBook.title}, cardText=#{home.PDFToBook.desc}, cardLink='pdf-to-book', svgPath='images/book.svg', tags=#{PDFToBook.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='stamp', cardTitle=#{home.AddStampRequest.title}, cardText=#{home.AddStampRequest.desc}, cardLink='stamp', svgPath='images/stamp.svg', tags=#{AddStampRequest.tags})}"></div>
</div> </div>
</div> </div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> </div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,28 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
th:lang-direction="#{language.direction}" <head>
xmlns:th="http://www.thymeleaf.org"> <th:block th:insert="~{fragments/common :: head(title=#{licenses.title}, header=#{licenses.title})}"></th:block>
</head>
<th:block
th:insert="~{fragments/common :: head(title=#{licenses.title}, header=#{licenses.title})}"></th:block>
<style>
td a {
text-decoration: none;
}
td a:hover, td a:focus {
text-decoration: underline;
/* Adds underline on hover/focus for clarity */
}
</style>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -50,7 +36,7 @@ td a:hover, td a:focus {
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,130 +1,14 @@
<!doctype html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{login.title}, header=#{login.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{login.title}, header=#{login.header})}"></th:block>
<script src="js/darkmode.js"></script> <link rel="stylesheet" href="css/login.css">
<style> </head>
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;
}
</style>
<body> <body>
<div class="your-container-class"> <div class="your-container-class"></div>
</div>
<div class="container-flex"> <div class="container-flex">
<main class="form-signin text-center"> <main class="form-signin text-center">
<script> <script>
function setInputMode(elementId, mode) { function setInputMode(elementId, mode) {
var inputElement = document.getElementById(elementId); var inputElement = document.getElementById(elementId);
@ -142,13 +26,10 @@ function setInputMode(elementId, mode) {
break; break;
case "rainbow": case "rainbow":
// Assuming you have defined some classes for rainbow mode // Assuming you have defined some classes for rainbow mode
break; break;
} }
} }
document.addEventListener('modeChanged', function(e) { document.addEventListener('modeChanged', function(e) {
var mode = e.detail; var mode = e.detail;
@ -167,7 +48,6 @@ document.addEventListener('modeChanged', function(e) {
document.body.classList.add("rainbow-mode"); document.body.classList.add("rainbow-mode");
break; break;
} }
}); });
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
@ -249,13 +129,8 @@ function handleDropdownItemClick(event) {
console.error("Language code is not set for this item."); console.error("Language code is not set for this item.");
} }
} }
</script> </script>
<div th:if="${logoutMessage}" class="alert alert-success" <div th:if="${logoutMessage}" class="alert alert-success" th:text="${logoutMessage}"></div>
th:text="${logoutMessage}"></div>
<div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'credsUpdated'}" class="alert alert-success"> <div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'credsUpdated'}" class="alert alert-success">
<span th:text="#{changedCredsMessage}">Default message if not found</span> <span th:text="#{changedCredsMessage}">Default message if not found</span>
</div> </div>
@ -265,12 +140,10 @@ function handleDropdownItemClick(event) {
<h2 class="h5 mb-3 fw-normal" th:text="#{login.signinTitle}">Please sign in</h2> <h2 class="h5 mb-3 fw-normal" th:text="#{login.signinTitle}">Please sign in</h2>
<div class="form-floating"> <div class="form-floating">
<input type="text" class="form-control bg-dark text-light" id="username" name="username" <input type="text" class="form-control bg-dark text-light" id="username" name="username" placeholder="admin"> <label for="username" th:text="#{username}">Username</label>
placeholder="admin"> <label for="username" th:text="#{username}">Username</label>
</div> </div>
<div class="form-floating"> <div class="form-floating">
<input type="password" class="form-control bg-dark text-light" id="password" name="password" <input type="password" class="form-control bg-dark text-light" id="password" name="password" placeholder="Password"> <label for="password" th:text="#{password}">Password</label>
placeholder="Password"> <label for="password" th:text="#{password}">Password</label>
</div> </div>
<div class="checkbox mb-3"> <div class="checkbox mb-3">
@ -278,8 +151,7 @@ function handleDropdownItemClick(event) {
<span th:text="#{login.rememberme}"></span> <span th:text="#{login.rememberme}"></span>
</label> </label>
</div> </div>
<button class="w-100 btn btn-lg btn-primary" type="submit" th:text="#{login.signin}">Sign <button class="w-100 btn btn-lg btn-primary" type="submit" th:text="#{login.signin}">Sign in</button>
in</button>
</form> </form>
<div class="mt-3"> <!-- Added a margin-top for spacing --> <div class="mt-3"> <!-- Added a margin-top for spacing -->
<div class="dropdown"> <div class="dropdown">
@ -292,22 +164,12 @@ function handleDropdownItemClick(event) {
</div> </div>
</div> </div>
</div> </div>
<div class="text-danger text-center"> <div class="text-danger text-center">
<div th:if="${error == 'badcredentials'}" th:text="#{login.invalid}">Invalid username or <div th:if="${error == 'badcredentials'}" th:text="#{login.invalid}">Invalid username or password.</div>
password.</div> <div th:if="${error == 'locked'}" th:text="#{login.locked}">Your account has been locked. </div>
<div th:if="${error == 'locked'}" th:text="#{login.locked}">Your account has been locked.
</div> </div>
</div>
</main> </main>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,14 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{merge.title}, header=#{merge.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{merge.title}, header=#{merge.header})}"></th:block>
<link rel="stylesheet" href="css/merge.css">
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container" id="dropContainer"> <div class="container" id="dropContainer">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -17,7 +18,6 @@
<div class="mb-3"> <div class="mb-3">
<label th:text="#{multiPdfDropPrompt}"></label> <label th:text="#{multiPdfDropPrompt}"></label>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=true, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=true, accept='application/pdf')}"></div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<ul id="selectedFiles" class="list-group"></ul> <ul id="selectedFiles" class="list-group"></ul>
@ -28,13 +28,12 @@
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{merge.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{merge.submit}"></button>
</div> </div>
</form> </form>
<link rel="stylesheet" href="css/merge.css">
<script src="js/merge.js"></script> <script src="js/merge.js"></script>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,16 +1,16 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head> <head>
<th:block th:insert="~{fragments/common :: head(title=#{addImage.title}, header=#{addImage.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{addImage.title}, header=#{addImage.header})}"></th:block>
<script src="js/thirdParty/interact.min.js"></script> <script src="js/thirdParty/interact.min.js"></script>
<link rel="stylesheet" href="css/add-image.css">
</head> </head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -31,7 +31,7 @@
document.querySelectorAll(".show-on-file-selected").forEach(el => { document.querySelectorAll(".show-on-file-selected").forEach(el => {
el.style.cssText = ''; el.style.cssText = '';
}) });
} }
}); });
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
@ -84,36 +84,6 @@
</svg> </svg>
</button> </button>
</div> </div>
<style>
#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;
}
</style>
</div> </div>
<!-- download button --> <!-- download button -->
@ -135,7 +105,8 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> </div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,37 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
th:lang-direction="#{language.direction}" <head>
xmlns:th="http://www.thymeleaf.org"> <th:block th:insert="~{fragments/common :: head(title=#{addPageNumbers.title}, header=#{addPageNumbers.header})}"></th:block>
<th:block
th:insert="~{fragments/common :: head(title=#{addPageNumbers.title}, header=#{addPageNumbers.header})}"></th:block>
<body>
<th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container">
<div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div>
<br> <br>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6">
<h2 th:text="#{addPageNumbers.header}"></h2>
<form method="post" enctype="multipart/form-data"
th:action="@{api/v1/misc/add-page-numbers}">
<div
th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<br>
<div class="mb-3">
<label for="customMargin" th:text="#{addPageNumbers.selectText.2}"></label> <select
class="form-control" id="customMargin" name="customMargin"
required>
<option value="small" th:text="#{sizes.small}"></option>
<option value="medium" selected th:text="#{sizes.medium}"></option>
<option value="large" th:text="#{sizes.large}"></option>
<option value="x-large" th:text="#{sizes.x-large}"></option>
</select>
</div>
<style> <style>
.a4container { .a4container {
position: relative; position: relative;
@ -75,8 +45,30 @@
background-color: #006600; background-color: #006600;
} }
</style> </style>
</head>
<body>
<th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container">
<div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br /><br />
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6">
<h2 th:text="#{addPageNumbers.header}"></h2>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/add-page-numbers}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<br>
<div class="mb-3">
<label for="customMargin" th:text="#{addPageNumbers.selectText.2}"></label>
<select class="form-control" id="customMargin" name="customMargin" required>
<option value="small" th:text="#{sizes.small}"></option>
<option value="medium" selected th:text="#{sizes.medium}"></option>
<option value="large" th:text="#{sizes.large}"></option>
<option value="x-large" th:text="#{sizes.x-large}"></option>
</select>
</div>
<div class="mb-3"> <div class="mb-3">
<label for="position" th:text="#{addPageNumbers.selectText.3}"></label> <label for="position" th:text="#{addPageNumbers.selectText.3}"></label>
<div class="a4container"> <div class="a4container">
@ -91,29 +83,21 @@
<div class="pageNumber" id="9" style="top: 90%; left: 90%;">9</div> <div class="pageNumber" id="9" style="top: 90%; left: 90%;">9</div>
</div> </div>
</div> </div>
<input type="hidden" id="numberInput" name="position" min="1" max="9" value="8" required />
<input type="hidden" id="numberInput" name="position" min="1"
max="9" value="8" required />
<div class="mb-3"> <div class="mb-3">
<label for="startingNumber" th:text="#{addPageNumbers.selectText.4}"></label> <input <label for="startingNumber" th:text="#{addPageNumbers.selectText.4}"></label>
type="number" class="form-control" id="startingNumber" <input type="number" class="form-control" id="startingNumber" name="startingNumber" min="1" required value="1" />
name="startingNumber" min="1" required value="1" />
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="pagesToNumber" th:text="#{addPageNumbers.selectText.5}"></label> <input <label for="pagesToNumber" th:text="#{addPageNumbers.selectText.5}"></label>
type="text" class="form-control" id="pagesToNumber" <input type="text" class="form-control" id="pagesToNumber" name="pagesToNumber" th:placeholder="#{addPageNumbers.numberPagesDesc}" />
name="pagesToNumber"
th:placeholder="#{addPageNumbers.numberPagesDesc}" />
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="customText" th:text="#{addPageNumbers.selectText.6}"></label> <input type="text" <label for="customText" th:text="#{addPageNumbers.selectText.6}"></label>
class="form-control" id="customText" name="customText" <input type="text" class="form-control" id="customText" name="customText" th:placeholder="#{addPageNumbers.customNumberDesc}" />
th:placeholder="#{addPageNumbers.customNumberDesc}" />
</div> </div>
<button type="submit" id="submitBtn" class="btn btn-primary" <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{addPageNumbers.submit}"></button>
th:text="#{addPageNumbers.submit}"></button>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
@ -146,9 +130,8 @@
}); });
}); });
</script> </script>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,17 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
th:lang-direction="#{language.direction}" <head>
xmlns:th="http://www.thymeleaf.org"> <th:block th:insert="~{fragments/common :: head(title=#{adjustContrast.title}, header=#{adjustContrast.header})}"></th:block>
</head>
<th:block
th:insert="~{fragments/common :: head(title=#{adjustContrast.title}, header=#{adjustContrast.header})}"></th:block>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-12"> <div class="col-md-12">
@ -304,7 +301,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,15 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{autoCrop.title}, header=#{autoCrop.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{autoCrop.title}, header=#{autoCrop.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -23,9 +23,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,15 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{auto-rename.title}, header=#{auto-rename.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{auto-rename.title}, header=#{auto-rename.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -22,9 +22,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,32 +1,29 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{changeMetadata.title}, header=#{changeMetadata.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{changeMetadata.title}, header=#{changeMetadata.header})}"></th:block>
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<h2 th:text="#{changeMetadata.header}"></h2> <h2 th:text="#{changeMetadata.header}"></h2>
<form method="post" id="form1" enctype="multipart/form-data" th:action="@{api/v1/misc/update-metadata}"> <form method="post" id="form1" enctype="multipart/form-data" th:action="@{api/v1/misc/update-metadata}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<p class="text-muted" th:text="#{changeMetadata.selectText.1}"></p> <p class="text-muted" th:text="#{changeMetadata.selectText.1}"></p>
<div class="mb-3-inline form-check"> <div class="mb-3-inline form-check">
<input type="checkbox" class="form-check-input" id="deleteAll" name="deleteAll"> <input type="checkbox" class="form-check-input" id="deleteAll" name="deleteAll">
<label class="ms-3" for="deleteAll" th:text="#{changeMetadata.selectText.2}" ></label> <label class="ms-3" for="deleteAll" th:text="#{changeMetadata.selectText.2}" ></label>
</div> </div>
<div class="mb-3-inline form-check"> <div class="mb-3-inline form-check">
<input type="checkbox" class="form-check-input" id="customModeCheckbox"> <input type="checkbox" class="form-check-input" id="customModeCheckbox">
<label class="ms-3" for="customModeCheckbox" th:text="#{changeMetadata.selectText.3}"></label> <label class="ms-3" for="customModeCheckbox" th:text="#{changeMetadata.selectText.3}"></label>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-check-label" for="author" th:text="#{changeMetadata.author}"></label> <label class="form-check-label" for="author" th:text="#{changeMetadata.author}"></label>
<input type="text" class="form-control" id="author" name="author"> <input type="text" class="form-control" id="author" name="author">
@ -85,7 +82,6 @@
<br> <br>
<button class="btn btn-primary" type="submit" id="submitBtn" th:text="#{changeMetadata.submit}"></button> <button class="btn btn-primary" type="submit" id="submitBtn" th:text="#{changeMetadata.submit}"></button>
<script> <script>
const deleteAllCheckbox = document.querySelector("#deleteAll"); const deleteAllCheckbox = document.querySelector("#deleteAll");
let inputs = document.querySelectorAll("input"); let inputs = document.querySelectorAll("input");
const customMetadataDiv = document.getElementById('customMetadata'); const customMetadataDiv = document.getElementById('customMetadata');
@ -102,20 +98,10 @@
}); });
}); });
const customModeCheckbox = document.getElementById('customModeCheckbox'); const customModeCheckbox = document.getElementById('customModeCheckbox');
const addMetadataBtn = document.getElementById("addMetadataBtn"); const addMetadataBtn = document.getElementById("addMetadataBtn");
const customMetadataFormContainer = document.getElementById("customMetadataEntries"); const customMetadataFormContainer = document.getElementById("customMetadataEntries");
var count = 1; var count = 1;
const fileInput = document.querySelector("#fileInput-input"); const fileInput = document.querySelector("#fileInput-input");
const authorInput = document.querySelector("#author"); const authorInput = document.querySelector("#author");
const creationDateInput = document.querySelector("#creationDate"); const creationDateInput = document.querySelector("#creationDate");
@ -126,21 +112,14 @@
const subjectInput = document.querySelector("#subject"); const subjectInput = document.querySelector("#subject");
const titleInput = document.querySelector("#title"); const titleInput = document.querySelector("#title");
const trappedInput = document.querySelector("#trapped"); const trappedInput = document.querySelector("#trapped");
var lastPDFFileMeta = null; var lastPDFFileMeta = null;
fileInput.addEventListener("change", async function() { fileInput.addEventListener("change", async function() {
while (otherMetadataEntriesDiv.firstChild) { while (otherMetadataEntriesDiv.firstChild) {
otherMetadataEntriesDiv.removeChild(otherMetadataEntriesDiv.firstChild); otherMetadataEntriesDiv.removeChild(otherMetadataEntriesDiv.firstChild);
} }
while (customMetadataFormContainer.firstChild) { while (customMetadataFormContainer.firstChild) {
customMetadataFormContainer.removeChild(customMetadataFormContainer.firstChild); customMetadataFormContainer.removeChild(customMetadataFormContainer.firstChild);
} }
const file = this.files[0]; const file = this.files[0];
var url = URL.createObjectURL(file) var url = URL.createObjectURL(file)
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js' pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
@ -177,7 +156,6 @@
}); });
addMetadataBtn.addEventListener("click", () => { addMetadataBtn.addEventListener("click", () => {
const keyInput = document.createElement("input"); const keyInput = document.createElement("input");
keyInput.type = "text"; keyInput.type = "text";
keyInput.placeholder = 'Key'; keyInput.placeholder = 'Key';
@ -196,7 +174,6 @@
formGroup.appendChild(keyInput); formGroup.appendChild(keyInput);
formGroup.appendChild(valueInput); formGroup.appendChild(valueInput);
customMetadataFormContainer.appendChild(formGroup); customMetadataFormContainer.appendChild(formGroup);
}); });
function convertDateFormat(dateTimeString) { function convertDateFormat(dateTimeString) {
@ -216,8 +193,6 @@
function addExtra() { function addExtra() {
const event = document.getElementById("customModeCheckbox"); const event = document.getElementById("customModeCheckbox");
if (event.checked && lastPDFFile.Custom != null) { if (event.checked && lastPDFFile.Custom != null) {
customMetadataDiv.style.display = 'block'; customMetadataDiv.style.display = 'block';
for (const [key, value] of Object.entries(lastPDFFile.Custom)) { for (const [key, value] of Object.entries(lastPDFFile.Custom)) {
@ -226,9 +201,6 @@
} }
const entryDiv = document.createElement('div'); const entryDiv = document.createElement('div');
entryDiv.className = 'mb-3'; entryDiv.className = 'mb-3';
entryDiv.innerHTML = `<div class="mb-3"><label class="form-check-label" for="${key}">${key}:</label><input name="${key}" value="${value}" type="text" class="form-control" id="${key}"></div>`; entryDiv.innerHTML = `<div class="mb-3"><label class="form-check-label" for="${key}">${key}:</label><input name="${key}" value="${value}" type="text" class="form-control" id="${key}"></div>`;
otherMetadataEntriesDiv.appendChild(entryDiv); otherMetadataEntriesDiv.appendChild(entryDiv);
} }
@ -238,24 +210,18 @@
otherMetadataEntriesDiv.removeChild(otherMetadataEntriesDiv.firstChild); otherMetadataEntriesDiv.removeChild(otherMetadataEntriesDiv.firstChild);
} }
} }
} }
customModeCheckbox.addEventListener('change', (event) => { customModeCheckbox.addEventListener('change', (event) => {
addExtra(); addExtra();
}); });
</script> </script>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,25 +1,30 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{compare.title}, header=#{compare.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{compare.title}, header=#{compare.header})}"></th:block>
<style>
.result-column {
border: 1px solid #ccc;
padding: 15px;
overflow-y: auto;
height: calc(100vh - 400px);
white-space: pre-wrap;
}
</style>
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-9"> <div class="col-md-9">
<h2 th:text="#{compare.header}"></h2> <h2 th:text="#{compare.header}"></h2>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput2', multiple=false, accept='application/pdf', remoteCall='false')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput2', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
<button class="btn btn-primary" onclick="comparePDFs()" th:text="#{compare.submit}"></button> <button class="btn btn-primary" onclick="comparePDFs()" th:text="#{compare.submit}"></button>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h3 th:text="#{compare.document.1}"></h3> <h3 th:text="#{compare.document.1}"></h3>
@ -30,15 +35,6 @@
<div id="result2" class="result-column"></div> <div id="result2" class="result-column"></div>
</div> </div>
</div> </div>
<style>
.result-column {
border: 1px solid #ccc;
padding: 15px;
overflow-y: auto;
height: calc(100vh - 400px);
white-space: pre-wrap;
}
</style>
<script> <script>
// get the elements // get the elements
var result1 = document.getElementById('result1'); var result1 = document.getElementById('result1');
@ -127,7 +123,6 @@
return differences; return differences;
}; };
const differences = diff(text1, text2); const differences = diff(text1, text2);
const displayDifferences = (differences) => { const displayDifferences = (differences) => {
@ -186,5 +181,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body>
</html>

View File

@ -1,16 +1,16 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{compress.title}, header=#{compress.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{compress.title}, header=#{compress.header})}"></th:block>
</head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -29,7 +29,6 @@
</select> </select>
</div> </div>
</div> </div>
<div class="card mb-3"> <div class="card mb-3">
<div class="card-body"> <div class="card-body">
<h4 th:text="#{compress.selectText.4}"></h4> <h4 th:text="#{compress.selectText.4}"></h4>
@ -43,8 +42,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,14 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{home.ScannerImageSplit.title}, header=#{home.ScannerImageSplit.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{home.ScannerImageSplit.title}, header=#{home.ScannerImageSplit.header})}"></th:block>
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -43,12 +43,11 @@
</div> </div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{genericSubmit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{genericSubmit}"></button>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,19 +1,18 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{extractImages.title}, header=#{extractImages.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{extractImages.title}, header=#{extractImages.header})}"></th:block>
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<h2 th:text="#{extractImages.header}"></h2> <h2 th:text="#{extractImages.header}"></h2>
<form id="multiPdfForm" th:action="@{api/v1/misc/extract-images}" method="post" enctype="multipart/form-data"> <form id="multiPdfForm" th:action="@{api/v1/misc/extract-images}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
@ -30,7 +29,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,15 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{flatten.title}, header=#{flatten.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{flatten.title}, header=#{flatten.header})}"></th:block>
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -44,13 +43,12 @@
await downloadFilesWithCallback(processFile); await downloadFilesWithCallback(processFile);
}); });
</script> </script>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>

View File

@ -1,9 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<th:block th:insert="~{fragments/common :: head(title=#{ocr.title}, header=#{ocr.header})}"></th:block>
<head> <head>
<th:block th:insert="~{fragments/common :: head(title=#{ocr.title}, header=#{ocr.header})}"></th:block>
<script> <script>
function handleLangSelection() { function handleLangSelection() {
let checkboxes = document.getElementsByName("languages"); let checkboxes = document.getElementsByName("languages");
@ -32,8 +30,8 @@
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -42,14 +40,14 @@
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label for="languages" class="form-label" th:text="#{ocr.selectText.1}"></label> <label for="languages" class="form-label" th:text="#{ocr.selectText.1}"></label>
<hr> <hr />
<div id="languages"> <div id="languages">
<div th:each="language, iterStat : ${languages}"> <div th:each="language, iterStat : ${languages}">
<input type="checkbox" th:name="languages" th:value="${language}" required th:id="${'language-' + language}" onchange="handleLangSelection()" /> <input type="checkbox" th:name="languages" th:value="${language}" required th:id="${'language-' + language}" onchange="handleLangSelection()" />
<label class="form-check-label" th:for="${'language-' + language}" th:text="${language}"></label> <label class="form-check-label" th:for="${'language-' + language}" th:text="${language}"></label>
</div> </div>
</div> </div>
<hr> <hr />
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{ocr.selectText.10}"></label> <label th:text="#{ocr.selectText.10}"></label>
@ -81,8 +79,6 @@
<input type="checkbox" class="form-check-input" name="removeImagesAfter" id="removeImagesAfter" /> <input type="checkbox" class="form-check-input" name="removeImagesAfter" id="removeImagesAfter" />
<label class="form-check-label" for="removeImagesAfter" th:text="#{ocr.selectText.11}"></label> <label class="form-check-label" for="removeImagesAfter" th:text="#{ocr.selectText.11}"></label>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{ocr.selectText.12}"></label> <label th:text="#{ocr.selectText.12}"></label>
<select class="form-control" name="ocrRenderType"> <select class="form-control" name="ocrRenderType">
@ -239,7 +235,6 @@
label.textContent = getFullLanguageName(languageCode); label.textContent = getFullLanguageName(languageCode);
}); });
}); });
</script> </script>
<p th:text="#{ocr.credit}"></p> <p th:text="#{ocr.credit}"></p>
<p th:text="#{ocr.help}"></p> <p th:text="#{ocr.help}"></p>
@ -248,7 +243,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,12 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{removeAnnotations.title}, header=#{removeAnnotations.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{removeAnnotations.title}, header=#{removeAnnotations.header})}"></th:block>
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -21,7 +23,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
<script src="js/local-pdf-input-download.js"></script> <script src="js/local-pdf-input-download.js"></script>
<script> <script>
@ -60,5 +62,4 @@
}); });
</script> </script>
</body> </body>
</html> </html>

View File

@ -1,19 +1,18 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{removeBlanks.title}, header=#{removeBlanks.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{removeBlanks.title}, header=#{removeBlanks.header})}"></th:block>
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<h2 th:text="#{removeBlanks.header}"></h2> <h2 th:text="#{removeBlanks.header}"></h2>
<form id="multiPdfForm" th:action="@{api/v1/misc/remove-blanks}" method="post" enctype="multipart/form-data"> <form id="multiPdfForm" th:action="@{api/v1/misc/remove-blanks}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
@ -32,7 +31,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,15 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{repair.title}, header=#{repair.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{repair.title}, header=#{repair.header})}"></th:block>
</head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
@ -22,8 +21,7 @@
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,28 +1,31 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.toString()}" <html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
th:lang-direction="#{language.direction}" <head>
xmlns:th="http://www.thymeleaf.org"> <th:block th:insert="~{fragments/common :: head(title=#{showJS.title}, header=#{showJS.header})}"></th:block>
<th:block
th:insert="~{fragments/common :: head(title=#{showJS.title}, header=#{showJS.header})}"></th:block>
<body>
<link href="css/prism.css" rel="stylesheet" /> <link href="css/prism.css" rel="stylesheet" />
<script src="js/thirdParty/prism.js"></script> <script src="js/thirdParty/prism.js"></script>
<style>
/* Add a max-height and make it scrollable */
#script-content {
max-height: 1000px; /* Adjust this to your preferred maximum height */
overflow-y: auto;
}
</style>
</head>
<body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br> <br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-12"> <div class="col-md-12">
<h2 th:text="#{showJS.header}"></h2> <h2 th:text="#{showJS.header}"></h2>
<form id="pdfInfoForm" method="post" enctype="multipart/form-data" <form id="pdfInfoForm" method="post" enctype="multipart/form-data" th:action="@{show-javascript}">
th:action="@{show-javascript}"> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, remoteCall='false', accept='application/pdf')}"></div>
<div
th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, remoteCall='false', accept='application/pdf')}"></div>
<br> <br>
<button type="submit" id="submitBtn" class="btn btn-primary" <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{showJS.submit}"></button>
th:text="#{showJS.submit}"></button>
</form> </form>
<div class="container mt-5"> <div class="container mt-5">
<!-- Iterate over each main section in the JSON --> <!-- Iterate over each main section in the JSON -->
@ -31,17 +34,8 @@
</div> </div>
<!-- Button to download the JSON --> <!-- Button to download the JSON -->
<a href="#" id="downloadJS" class="btn btn-primary mt-3" <a href="#" id="downloadJS" class="btn btn-primary mt-3" style="display: none;" th:text="#{showJS.downloadJS}">Download JSON</a>
style="display: none;" th:text="#{showJS.downloadJS}">Download
JSON</a>
</div> </div>
<style>
/* Add a max-height and make it scrollable */
#script-content {
max-height: 1000px; /* Adjust this to your preferred maximum height */
overflow-y: auto;
}
</style>
<script> <script>
document.querySelector('#pdfInfoForm').addEventListener('submit', function(event){ document.querySelector('#pdfInfoForm').addEventListener('submit', function(event){
event.preventDefault(); event.preventDefault();
@ -92,9 +86,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

Some files were not shown because too many files have changed in this diff Show More