This commit is contained in:
Anthony Stirling 2023-02-09 22:05:51 +00:00
parent dcaddb53ee
commit 6cdccdd248
27 changed files with 873 additions and 903 deletions

View File

@ -13,23 +13,23 @@ import java.util.Locale;
@Configuration @Configuration
public class Beans implements WebMvcConfigurer { public class Beans implements WebMvcConfigurer {
@Bean @Bean
public LocaleResolver localeResolver() { public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver(); SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.US); slr.setDefaultLocale(Locale.US);
return slr; return slr;
} }
@Bean @Bean
public LocaleChangeInterceptor localeChangeInterceptor() { public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang"); lci.setParamName("lang");
return lci; return lci;
} }
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor()); registry.addInterceptor(localeChangeInterceptor());
} }
} }

View File

@ -31,13 +31,10 @@ public class PdfController {
return "redirect:/"; return "redirect:/";
} }
@GetMapping("/") @GetMapping("/")
public String home(Model model) { public String home(Model model) {
model.addAttribute("currentPage", "home"); model.addAttribute("currentPage", "home");
return "home"; return "home";
} }
} }

View File

@ -51,9 +51,9 @@ public class RearrangePagesPDFController {
List<Integer> pagesToRemove = pageOrderToString(pageOrderArr, document.getNumberOfPages()); List<Integer> pagesToRemove = pageOrderToString(pageOrderArr, document.getNumberOfPages());
for (int i = pagesToRemove.size() - 1; i >= 0; i--) { for (int i = pagesToRemove.size() - 1; i >= 0; i--) {
int pageIndex = pagesToRemove.get(i); int pageIndex = pagesToRemove.get(i);
document.removePage(pageIndex); document.removePage(pageIndex);
} }
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_removed_pages.pdf"); return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_removed_pages.pdf");

View File

@ -49,12 +49,14 @@ public class ConvertImgPDFController {
@PostMapping("/pdf-to-img") @PostMapping("/pdf-to-img")
public ResponseEntity<Resource> convertToImage(@RequestParam("fileInput") MultipartFile file, public ResponseEntity<Resource> convertToImage(@RequestParam("fileInput") MultipartFile file,
@RequestParam("imageFormat") String imageFormat, @RequestParam("imageFormat") String imageFormat, @RequestParam("singleOrMultiple") String singleOrMultiple,
@RequestParam("singleOrMultiple") String singleOrMultiple, @RequestParam("colorType") String colorType, @RequestParam("dpi") String dpi,
@RequestParam("colorType") String colorType) throws IOException { @RequestParam("contrast") String contrast, @RequestParam("brightness") String brightness)
throws IOException {
byte[] pdfBytes = file.getBytes(); byte[] pdfBytes = file.getBytes();
ImageType colorTypeResult = ImageType.RGB; ImageType colorTypeResult = ImageType.RGB;
if("greyscale".equals(colorType)) { if ("greyscale".equals(colorType)) {
colorTypeResult = ImageType.GRAY; colorTypeResult = ImageType.GRAY;
} else if ("blackwhite".equals(colorType)) { } else if ("blackwhite".equals(colorType)) {
colorTypeResult = ImageType.BINARY; colorTypeResult = ImageType.BINARY;
@ -63,7 +65,9 @@ public class ConvertImgPDFController {
boolean singleImage = singleOrMultiple.equals("single"); boolean singleImage = singleOrMultiple.equals("single");
byte[] result = null; byte[] result = null;
try { try {
result = PdfUtils.convertFromPdf(pdfBytes, imageFormat.toLowerCase(), colorTypeResult, singleImage); result = PdfUtils.convertFromPdf(pdfBytes, imageFormat.toLowerCase(), colorTypeResult, singleImage,
Integer.valueOf(dpi), Integer.valueOf(contrast), Integer.valueOf(brightness)); // DPI, contrast,
// brightness
} catch (IOException e) { } catch (IOException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
@ -71,17 +75,20 @@ public class ConvertImgPDFController {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
if(singleImage) { if (singleImage) {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(getMediaType(imageFormat))); headers.setContentType(MediaType.parseMediaType(getMediaType(imageFormat)));
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0"); headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
ResponseEntity<Resource> response = new ResponseEntity<>(new ByteArrayResource(result), headers, HttpStatus.OK); ResponseEntity<Resource> response = new ResponseEntity<>(new ByteArrayResource(result), headers,
HttpStatus.OK);
return response; return response;
} else { } else {
ByteArrayResource resource = new ByteArrayResource(result); ByteArrayResource resource = new ByteArrayResource(result);
// return the Resource in the response // return the Resource in the response
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=converted_documents.zip") return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM).contentLength(resource.contentLength()).body(resource); .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=converted_documents.zip")
.contentType(MediaType.APPLICATION_OCTET_STREAM).contentLength(resource.contentLength())
.body(resource);
} }
} }

View File

@ -38,20 +38,17 @@ public class MetadataController {
model.addAttribute("currentPage", "change-metadata"); model.addAttribute("currentPage", "change-metadata");
return "security/change-metadata"; return "security/change-metadata";
} }
@PostMapping("/update-metadata") @PostMapping("/update-metadata")
public ResponseEntity<byte[]> metadata( public ResponseEntity<byte[]> metadata(@RequestParam Map<String, String> allRequestParams) throws IOException {
@RequestParam Map<String,String> allRequestParams) throws IOException {
System.out.println("1 allRequestParams.size() = " + allRequestParams.size()); System.out.println("1 allRequestParams.size() = " + allRequestParams.size());
for(Entry entry : allRequestParams.entrySet()) { for (Entry entry : allRequestParams.entrySet()) {
System.out.println("1 key=" + entry.getKey() + ", value=" + entry.getValue()); System.out.println("1 key=" + entry.getKey() + ", value=" + entry.getValue());
} }
return null; return null;
} }
// @PostMapping("/update-metadata") // @PostMapping("/update-metadata")
// public ResponseEntity<byte[]> addWatermark(@RequestParam("fileInput") MultipartFile pdfFile, // public ResponseEntity<byte[]> addWatermark(@RequestParam("fileInput") MultipartFile pdfFile,
// @RequestParam Map<String,String> allRequestParams,HttpServletRequest request, ModelMap model) throws IOException { // @RequestParam Map<String,String> allRequestParams,HttpServletRequest request, ModelMap model) throws IOException {
@ -88,7 +85,6 @@ public class MetadataController {
// return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_metadata.pdf"); // return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_metadata.pdf");
// } // }
// // Loop over all pages and remove annotations // // Loop over all pages and remove annotations
// for (PDPage page : document.getPages()) { // for (PDPage page : document.getPages()) {
// page.getAnnotations().clear(); // page.getAnnotations().clear();

View File

@ -2,6 +2,7 @@ package stirling.software.SPDF.utils;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
@ -80,55 +81,61 @@ public class PdfUtils {
} }
} }
public static byte[] convertFromPdf(byte[] inputStream, String imageType, ImageType colorType, boolean singleImage) throws IOException, Exception { public static byte[] convertFromPdf(byte[] inputStream, String imageType, ImageType colorType, boolean singleImage,
try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) { int DPI, int contrast, int brightness) throws IOException, Exception {
PDFRenderer pdfRenderer = new PDFRenderer(document); try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) {
int pageCount = document.getNumberOfPages(); PDFRenderer pdfRenderer = new PDFRenderer(document);
List<BufferedImage> images = new ArrayList<>(); int pageCount = document.getNumberOfPages();
// Create images of all pages List<BufferedImage> images = new ArrayList<>();
for (int i = 0; i < pageCount; i++) {
images.add(pdfRenderer.renderImageWithDPI(i, 300, colorType));
}
if (singleImage) { // Create images of all pages
// Combine all images into a single big image for (int i = 0; i < pageCount; i++) {
BufferedImage combined = new BufferedImage(images.get(0).getWidth() , BufferedImage image = pdfRenderer.renderImageWithDPI(i, 300, colorType);
images.get(0).getHeight()* pageCount, BufferedImage.TYPE_INT_RGB); float scale = contrast + 1f;
Graphics g = combined.getGraphics(); float offset = brightness;
for (int i = 0; i < images.size(); i++) { RescaleOp rescaleOp = new RescaleOp(scale, offset, null);
g.drawImage(images.get(i), 0, i * images.get(0).getHeight(), null); BufferedImage dest = rescaleOp.filter(image, null);
} images.add(dest);
images = Arrays.asList(combined); }
}
if (singleImage) {
// Combine all images into a single big image
BufferedImage combined = new BufferedImage(images.get(0).getWidth(),
images.get(0).getHeight() * pageCount, BufferedImage.TYPE_INT_RGB);
Graphics g = combined.getGraphics();
for (int i = 0; i < images.size(); i++) {
g.drawImage(images.get(i), 0, i * images.get(0).getHeight(), null);
}
images = Arrays.asList(combined);
}
// Create a ByteArrayOutputStream to save the image(s) to // Create a ByteArrayOutputStream to save the image(s) to
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (singleImage) { if (singleImage) {
// Write the image to the output stream // Write the image to the output stream
ImageIO.write(images.get(0), "PNG", baos); ImageIO.write(images.get(0), "PNG", baos);
// Log that the image was successfully written to the byte array // Log that the image was successfully written to the byte array
logger.info("Image successfully written to byte array"); logger.info("Image successfully written to byte array");
} else { } else {
// Zip the images and return as byte array // Zip the images and return as byte array
try (ZipOutputStream zos = new ZipOutputStream(baos)) { try (ZipOutputStream zos = new ZipOutputStream(baos)) {
for (int i = 0; i < images.size(); i++) { for (int i = 0; i < images.size(); i++) {
BufferedImage image = images.get(i); BufferedImage image = images.get(i);
try (ByteArrayOutputStream baosImage = new ByteArrayOutputStream()) { try (ByteArrayOutputStream baosImage = new ByteArrayOutputStream()) {
ImageIO.write(image, "PNG", baosImage); ImageIO.write(image, "PNG", baosImage);
// Add the image to the zip file // Add the image to the zip file
zos.putNextEntry(new ZipEntry(String.format("page_%d.%s", i + 1, "png"))); zos.putNextEntry(new ZipEntry(String.format("page_%d.%s", i + 1, "png")));
zos.write(baosImage.toByteArray()); zos.write(baosImage.toByteArray());
} }
} }
// Log that the images were successfully written to the byte array // Log that the images were successfully written to the byte array
logger.info("Images successfully written to byte array as a zip"); logger.info("Images successfully written to byte array as a zip");
} }
} }
return baos.toByteArray(); return baos.toByteArray();
} catch (IOException e) { } catch (IOException e) {
// Log an error message if there is an issue converting the PDF to an image // Log an error message if there is an issue converting the PDF to an image
logger.error("Error converting PDF to image", e); logger.error("Error converting PDF to image", e);
throw e; throw e;

View File

@ -8,7 +8,7 @@ imgPrompt=Choose Image
genericSubmit=Submit genericSubmit=Submit
processTimeWarning=Warning: This process can take up to a minute depending on file-size processTimeWarning=Warning: This process can take up to a minute depending on file-size
pageOrderPrompt=Page Order (Enter a comma-separated list of page numbers) : pageOrderPrompt=Page Order (Enter a comma-separated list of page numbers) :
goToPage=go goToPage=Go
############# #############
# HOME-PAGE # # HOME-PAGE #
############# #############
@ -131,6 +131,8 @@ pdfToImage.colorType=Colour type
pdfToImage.color=Colour pdfToImage.color=Colour
pdfToImage.grey=Greyscale pdfToImage.grey=Greyscale
pdfToImage.blackwhite=Black and White (May lose data!) pdfToImage.blackwhite=Black and White (May lose data!)
pdfToImage.contrast=Contrast Value:
pdfToImage.brightness=Brightness Value:
pdfToImage.submit=Convert pdfToImage.submit=Convert
#addPassword #addPassword

View File

@ -11,7 +11,7 @@ imgPrompt=Choose Image
genericSubmit=Submit genericSubmit=Submit
processTimeWarning=Warning: This process can take up to a minute depending on file-size processTimeWarning=Warning: This process can take up to a minute depending on file-size
pageOrderPrompt=Page Order (Enter a comma-separated list of page numbers) : pageOrderPrompt=Page Order (Enter a comma-separated list of page numbers) :
goToPage=go goToPage=Go
############# #############
# HOME-PAGE # # HOME-PAGE #
############# #############

View File

@ -15,7 +15,7 @@ imgPrompt=Choisir une image
genericSubmit=Soumettre genericSubmit=Soumettre
processTimeWarning=Attention : ce processus peut prendre jusqu'à une minute en fonction de la taille du fichier processTimeWarning=Attention : ce processus peut prendre jusqu'à une minute en fonction de la taille du fichier
pageOrderPrompt=Ordre des pages (Entrez une liste de numéros de page séparés par des virgules) : pageOrderPrompt=Ordre des pages (Entrez une liste de numéros de page séparés par des virgules) :
goToPage=aller goToPage=Aller
############# #############
# HOME-PAGE # # HOME-PAGE #
############# #############

View File

@ -6,45 +6,35 @@
<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> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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="#{addImage.header}"></h2>
<h2 th:text="#{addImage.header}"></h2> <form method="post" th:action="@{add-image}" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<div class="custom-file">
<input type="file" class="custom-file-input" id="fileInput2" name="fileInput2" required>
<form method="post" th:action="@{add-image}" <label class="custom-file-label" for="fileInput2" th:text="#{imgPrompt}"></label>
enctype="multipart/form-data"> </div>
<div class="form-group">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> <label for="x">X</label> <input type="number" class="form-control" id="x" name="x" step="0.01" required>
<div class="custom-file"> </div>
<input type="file" class="custom-file-input" id="fileInput2" <div class="form-group">
name="fileInput2" required> <label <label for="y">Y</label> <input type="number" class="form-control" id="y" name="y" step="0.01" required>
class="custom-file-label" for="fileInput2" th:text="#{imgPrompt}"></label> </div>
</div> <button type="submit" class="btn btn-primary" th:text="#{addImage.submit}"></button>
<div class="form-group"> </form>
<label for="x">X</label> <input type="number" class="form-control" <th:block th:insert="~{fragments/common :: filelist}"></th:block>
id="x" name="x" step="0.01" required> </div>
</div> </div>
<div class="form-group"> </div>
<label for="y">Y</label> <input type="number" class="form-control" </div>
id="y" name="y" step="0.01" required> <div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
<button type="submit" class="btn btn-primary" th:text="#{addImage.submit}"></button>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div>
</div>
</div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div>
</body> </body>
</html> </html>

View File

@ -5,36 +5,32 @@
<th:block th:insert="~{fragments/common :: head(title=#{compress.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{compress.title})}"></th:block>
<body> <div id="page-container"> <body>
<div id="content-wrap"> <div id="page-container">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <div id="content-wrap">
<br> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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="#{compress.header}"></h2> <h2 th:text="#{compress.header}"></h2>
<form action="#" th:action="@{compress-pdf}" <form action="#" th:action="@{compress-pdf}" th:object="${rotateForm}" method="post" enctype="multipart/form-data">
th:object="${rotateForm}" method="post" <p th:text="#{processTimeWarning}"></p>
enctype="multipart/form-data"> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<p th:text="#{processTimeWarning}"></p> <div class="form-group">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> <label for="imageCompressionLevel" th:text="#{compress.compressLevel}"></label>
<div class="form-group"> <input type="number" class="form-control" id="imageCompressionLevel" name="imageCompressionLevel" step="1" value="1" min="1" max="100" required>
<label for="imageCompressionLevel" th:text="#{compress.compressLevel}"></label> <input type="number" class="form-control" </div>
id="imageCompressionLevel" name="imageCompressionLevel" step="1" <button type="submit" class="btn btn-primary" th:text="#{compress.submit}"></button>
value="1" min="1" max="100" required> </form>
</div> <th:block th:insert="~{fragments/common :: filelist}"></th:block>
<button type="submit" class="btn btn-primary" th:text="#{compress.submit}"></button> </div>
</form> </div>
<th:block th:insert="~{fragments/common :: filelist}"></th:block> </div>
</div>
</div> <div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
</div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div>
</body> </body>
</html> </html>

View File

@ -4,35 +4,32 @@
<th:block th:insert="~{fragments/common :: head(title=#{imageToPDF.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{imageToPDF.title})}"></th:block>
<body> <div id="page-container"> <body>
<div id="content-wrap"> <div id="page-container">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <div id="content-wrap">
<br> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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" <form method="post" enctype="multipart/form-data" th:action="@{img-to-pdf}">
th:action="@{img-to-pdf}"> <div class="custom-file">
<div class="custom-file"> <input type="file" class="custom-file-input" id="fileInput" name="fileInput" required>
<input type="file" class="custom-file-input" id="fileInput" <label class="custom-file-label" for="fileInput" th:text="#{imgPrompt}"></label>
name="fileInput" required> <label </div>
class="custom-file-label" for="fileInput" th:text="#{imgPrompt}"></label> <br> <br>
</div> <button type="submit" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button>
<br>
<br>
<button type="submit" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button>
</form> </form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block> <th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -4,51 +4,64 @@
<th:block th:insert="~{fragments/common :: head(title=#{pdfToImage.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{pdfToImage.title})}"></th:block>
<body> <div id="page-container"> <body>
<div id="content-wrap"> <div id="page-container">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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="#{pdfToImage.header}"></h2>
<h2 th:text="#{pdfToImage.header}"></h2> <p th:text="#{processTimeWarning}"></p>
<p th:text="#{processTimeWarning}"></p> <form method="post" enctype="multipart/form-data" th:action="@{pdf-to-img}">
<form method="post" enctype="multipart/form-data" <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
th:action="@{pdf-to-img}"> <div class="form-group">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> <label th:text="#{pdfToImage.selectText}"></label>
<div class="form-group"> <select class="form-control" name="imageFormat">
<label th:text="#{pdfToImage.selectText}"></label> <select class="form-control" <option value="png">PNG</option>
name="imageFormat"> </select>
<option value="png">PNG</option> </div>
</select> <div class="form-group">
</div> <label th:text="#{pdfToImage.singleOrMultiple}"></label>
<div class="form-group"> <select class="form-control" name="singleOrMultiple">
<label th:text="#{pdfToImage.singleOrMultiple}"></label> <option value="single" th:text="#{pdfToImage.single}"></option>
<select class="form-control" name="singleOrMultiple"> <option value="multiple" th:text="#{pdfToImage.multi}"></option>
<option value="single" th:text="#{pdfToImage.single}"></option> </select>
<option value="multiple" th:text="#{pdfToImage.multi}"></option> </div>
</select> <div class="form-group">
</div> <label th:text="#{pdfToImage.colorType}"></label>
<div class="form-group"> <select class="form-control" name="colorType">
<label th:text="#{pdfToImage.colorType}"></label> <option value="color" th:text="#{pdfToImage.color}"></option>
<select class="form-control" name="colorType"> <option value="greyscale" th:text="#{pdfToImage.grey}"></option>
<option value="color" th:text="#{pdfToImage.color}"></option> <option value="blackwhite" th:text="#{pdfToImage.blackwhite}"></option>
<option value="greyscale" th:text="#{pdfToImage.grey}"></option> </select>
<option value="blackwhite" th:text="#{pdfToImage.blackwhite}"></option> </div>
</select> <div class="form-group">
</div> <label for="dpi" th:text="#{pdfToImage.dpi}"></label>
<button type="submit" class="btn btn-primary" th:text="#{pdfToImage.submit}"></button> <input type="number" name="dpi" class="form-control" id="dpi" min="1" max="100" step="1" value="30" required>
</form> </div>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div> <div class="form-group">
</div> <label for="contrast" th:text="#{pdfToImage.contrast}"></label>
</div> <input type="number" name="contrast" class="form-control" id="contrast" min="-255" max="255" value="0" step="1" required>
</div>
</div> <div class="form-group">
<div th:insert="~{fragments/footer.html :: footer}"></div> <label for="brightness" th:text="#{pdfToImage.brightness}"></label>
</div> <input type="number" name="brightness" class="form-control" id="brightness" min="-255" max="255" step="1" value="1" required>
</div>
<button type="submit" class="btn btn-primary" th:text="#{pdfToImage.submit}"></button>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div>
</div>
</div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div>
</body> </body>
</html> </html>

View File

@ -1,5 +1,5 @@
<div th:fragment="card" class="feature-card"> <div th:fragment="card" class="feature-card">
<h5 class="card-title" th:text="${cardTitle}"></h5> <h5 class="card-title" th:text="${cardTitle}"></h5>
<p class="card-text" th:text="${cardText}"></p> <p class="card-text" th:text="${cardText}"></p>
<a class="btn btn-primary" th:href="${cardLink}" th:text="#{goToPage}"></a> <a class="btn btn-primary" th:href="${cardLink}" th:text="#{goToPage}"></a>
</div> </div>

View File

@ -1,29 +1,29 @@
<head th:fragment="head"> <head th:fragment="head">
<!-- Metadata --> <!-- Metadata -->
<meta charset="UTF-8"> <meta charset="UTF-8">
<title th:text="'S-PDF ' + ${title}"></title> <title th:text="'S-PDF ' + ${title}"></title>
<link rel="shortcut icon" href="favicon.svg"> <link rel="shortcut icon" href="favicon.svg">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- jQuery --> <!-- jQuery -->
<script src="js/jquery.min.js"></script> <script src="js/jquery.min.js"></script>
<!-- Bootstrap --> <!-- Bootstrap -->
<script src="js/popper.min.js"></script> <script src="js/popper.min.js"></script>
<script src="js/bootstrap.min.js"></script> <script src="js/bootstrap.min.js"></script>
<link rel="stylesheet" href="css/bootstrap.min.css"> <link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/bootstrap-icons.css"> <link rel="stylesheet" href="css/bootstrap-icons.css">
<!-- PDF.js --> <!-- PDF.js -->
<script src="pdfjs/pdf.min.js"></script> <script src="pdfjs/pdf.min.js"></script>
<link href="pdfjs/pdf_viewer.min.css" rel="stylesheet"> <link href="pdfjs/pdf_viewer.min.css" rel="stylesheet">
<!-- Custom --> <!-- Custom -->
<link rel="stylesheet" href="css/general.css"> <link rel="stylesheet" href="css/general.css">
<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">
<script> <script>
function toggleDarkMode() { function toggleDarkMode() {
var checkbox = document.getElementById("toggle-dark-mode"); var checkbox = document.getElementById("toggle-dark-mode");
var darkModeStyles = document.getElementById("dark-mode-styles"); var darkModeStyles = document.getElementById("dark-mode-styles");
@ -52,9 +52,9 @@
</head> </head>
<th:block th:fragment="filelist"> <th:block th:fragment="filelist">
<div id="fileList"></div> <div id="fileList"></div>
<div id="fileList2"></div> <div id="fileList2"></div>
<script> <script>
var input = document.getElementById("fileInput"); var input = document.getElementById("fileInput");
var output = document.getElementById("fileList"); var output = document.getElementById("fileList");
@ -69,7 +69,7 @@
output.innerHTML = fileNames; output.innerHTML = fileNames;
}); });
</script> </script>
<script> <script>
var input2 = document.getElementById("fileInput2"); var input2 = document.getElementById("fileInput2");
var output2 = document.getElementById("fileList2"); var output2 = document.getElementById("fileList2");
if (input2 != null && !input2) { if (input2 != null && !input2) {
@ -87,7 +87,7 @@
</script> </script>
<script> <script>
if (dropContainer) { if (dropContainer) {
dropContainer.ondragover = dropContainer.ondragenter = function(evt) { dropContainer.ondragover = dropContainer.ondragenter = function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -110,14 +110,14 @@
</th:block> </th:block>
<th:block th:fragment="fileSelector(name, multiple)"> <th:block th:fragment="fileSelector(name, multiple)">
<div class="custom-file-chooser"> <div class="custom-file-chooser">
<div class="custom-file"> <div class="custom-file">
<input type="file" class="custom-file-input" th:name="${name}" th:id="${name}+'-input'" th:multiple="${multiple}"> <input type="file" class="custom-file-input" th:name="${name}" th:id="${name}+'-input'" th:multiple="${multiple}">
<label class="custom-file-label" th:for="${name}+'-input'" th:text="#{pdfPrompt}"></label> <label class="custom-file-label" th:for="${name}+'-input'" th:text="#{pdfPrompt}"></label>
</div> </div>
</div> </div>
<script th:inline="javascript"> <script th:inline="javascript">
$([[${"#"+name+"-input"}]]).on("change", function() { $([[${"#"+name+"-input"}]]).on("change", function() {
const files = $(this).get(0).files; const files = $(this).get(0).files;
const fileNames = Array.from(files).map(f => f.name).join(", "); const fileNames = Array.from(files).map(f => f.name).join(", ");
@ -129,9 +129,9 @@
}); });
</script> </script>
<style> <style>
.custom-file-label { .custom-file-label {
padding-right: 90px; padding-right: 90px;
} }
</style> </style>
</th:block> </th:block>

View File

@ -67,9 +67,9 @@
</li> </li>
<input type="checkbox" id="toggle-dark-mode" checked="true" th:onclick="javascript:toggleDarkMode()"> <input type="checkbox" id="toggle-dark-mode" checked="true" th:onclick="javascript:toggleDarkMode()">
<a class="nav-link" href="#" for="toggle-dark-mode" th:text="#{navbar.darkmode}"></a> <a class="nav-link" href="#" for="toggle-dark-mode" th:text="#{navbar.darkmode}"></a>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="languageDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <a class="nav-link dropdown-toggle" href="#" id="languageDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="bi bi-globe2"></i> <i class="bi bi-globe2"></i>
@ -78,7 +78,7 @@
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="en_US">English (US)</a> <a class="dropdown-item lang_dropdown-item" href="" data-language-code="en_US">English (US)</a>
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="en_GB">English (UK)</a> <a class="dropdown-item lang_dropdown-item" href="" data-language-code="en_GB">English (UK)</a>
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="ar_AR">العربية</a> <a class="dropdown-item lang_dropdown-item" href="" data-language-code="ar_AR">العربية</a>
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="de_DE">German</a> <a class="dropdown-item lang_dropdown-item" href="" data-language-code="de_DE">Deutsch</a>
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="fr_FR">Français</a> <a class="dropdown-item lang_dropdown-item" href="" data-language-code="fr_FR">Français</a>
</div> </div>
</li> </li>

View File

@ -5,62 +5,63 @@
<th:block th:insert="~{fragments/common :: head(title='')}"></th:block> <th:block th:insert="~{fragments/common :: head(title='')}"></th:block>
<style> <style>
.features-container { .features-container {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr)); grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr));
gap: 25px 30px; gap: 25px 30px;
} }
.feature-card {
border: 1px solid rgba(0,0,0,.125);
border-radius: 0.25rem;
padding: 1.25rem;
display: flex; .feature-card {
flex-direction: column; border: 1px solid rgba(0, 0, 0, .125);
align-items: flex-start; border-radius: 0.25rem;
} padding: 1.25rem;
.feature-card .card-text { display: flex;
flex: 1; flex-direction: column;
} align-items: flex-start;
}
.feature-card .card-text {
flex: 1;
}
</style> </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> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<!-- Jumbotron --> <!-- Jumbotron -->
<div class="jumbotron jumbotron-fluid" id="jumbotron"> <div class="jumbotron jumbotron-fluid" id="jumbotron">
<div class="container"> <div class="container">
<h1 class="display-4">Stirling PDF</h1> <h1 class="display-4">Stirling PDF</h1>
<p class="lead" th:text="#{home.desc}"></p> <p class="lead" th:text="#{home.desc}"></p>
</div> </div>
</div> </div>
<!-- Features --> <!-- Features -->
<div class="features-container container"> <div class="features-container container">
<div th:replace="~{fragments/card :: card(cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.split.title}, cardText=#{home.split.desc}, cardLink='split-pdfs')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.split.title}, cardText=#{home.split.desc}, cardLink='split-pdfs')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.rotate.title}, cardText=#{home.rotate.desc}, cardLink='rotate-pdf')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.rotate.title}, cardText=#{home.rotate.desc}, cardLink='rotate-pdf')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.imageToPdf.title}, cardText=#{home.imageToPdf.desc}, cardLink='img-to-pdf')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.imageToPdf.title}, cardText=#{home.imageToPdf.desc}, cardLink='img-to-pdf')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.pdfToImage.title}, cardText=#{home.pdfToImage.desc}, cardLink='pdf-to-img')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.pdfToImage.title}, cardText=#{home.pdfToImage.desc}, cardLink='pdf-to-img')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.pdfOrganiser.title}, cardText=#{home.pdfOrganiser.desc}, cardLink='pdf-organizer')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.pdfOrganiser.title}, cardText=#{home.pdfOrganiser.desc}, cardLink='pdf-organizer')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.addImage.title}, cardText=#{home.addImage.desc}, cardLink='add-image')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.addImage.title}, cardText=#{home.addImage.desc}, cardLink='add-image')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.watermark.title}, cardText=#{home.watermark.desc}, cardLink='add-watermark')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.watermark.title}, cardText=#{home.watermark.desc}, cardLink='add-watermark')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.removePages.title}, cardText=#{home.removePages.desc}, cardLink='remove-pages')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.removePages.title}, cardText=#{home.removePages.desc}, cardLink='remove-pages')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.addPassword.title}, cardText=#{home.addPassword.desc}, cardLink='add-password')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.addPassword.title}, cardText=#{home.addPassword.desc}, cardLink='add-password')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata')}"></div> <div th:replace="~{fragments/card :: card(cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata')}"></div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -4,130 +4,124 @@
<th:block th:insert="~{fragments/common :: head(title=#{merge.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{merge.title})}"></th:block>
<body> <div id="page-container"> <body>
<div id="content-wrap"> <div id="page-container">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <div id="content-wrap">
<br> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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">
<h2 th:text="#{merge.header}"></h2> <h2 th:text="#{merge.header}"></h2>
<form action="merge-pdfs" method="post" <form action="merge-pdfs" method="post" enctype="multipart/form-data">
enctype="multipart/form-data"> <div class="form-group">
<div class="form-group"> <label th:text="#{multiPdfDropPrompt}"></label>
<label th:text="#{multiPdfDropPrompt}"></label> <div class="custom-file">
<div class="custom-file"> <input type="file" class="custom-file-input" id="fileInput" name="fileInput" multiple required>
<input type="file" class="custom-file-input" id="fileInput" <label class="custom-file-label" th:text="#{pdfPrompt}"></label>
name="fileInput" multiple required> <label </div>
class="custom-file-label" th:text="#{pdfPrompt}">s</label> </div>
</div> <div class="form-group">
</div> <ul id="selectedFiles" class="list-group"></ul>
<div class="form-group"> </div>
<ul id="selectedFiles" class="list-group"></ul> <div class="form-group text-center">
</div> <button type="submit" class="btn btn-primary" th:text="#{merge.submit}"></button>
<div class="form-group text-center"> </div>
<button type="submit" class="btn btn-primary" th:text="#{merge.submit}"></button> </form>
</div>
</form>
<script>
document
.getElementById(
"fileInput")
.addEventListener(
"change",
function() {
var files = this.files;
var list = document
.getElementById("selectedFiles");
list.innerHTML = "";
for (var i = 0; i < files.length; i++) {
var item = document
.createElement("li");
item.className = "list-group-item d-flex justify-content-between align-items-center";
item.textContent = files[i].name;
item.innerHTML += '<div><button class="btn btn-secondary move-up"><i class="fas fa-arrow-up"></i></button> <button class="btn btn-secondary move-down"><i class="fas fa-arrow-down"></i></button></div>';
list
.appendChild(item);
}
var moveUpButtons = document
.querySelectorAll(".move-up");
for (var i = 0; i < moveUpButtons.length; i++) {
moveUpButtons[i]
.addEventListener(
"click",
function(
event) {
event
.preventDefault();
var parent = this.parentNode.parentNode;
var grandParent = parent.parentNode;
if (parent.previousElementSibling) {
grandParent
.insertBefore(
parent,
parent.previousElementSibling);
updateFiles();
}
});
}
var moveDownButtons = document
.querySelectorAll(".move-down");
for (var i = 0; i < moveDownButtons.length; i++) {
moveDownButtons[i]
.addEventListener(
"click",
function(
event) {
event
.preventDefault();
var parent = this.parentNode.parentNode;
var grandParent = parent.parentNode;
if (parent.nextElementSibling) {
grandParent
.insertBefore(
parent.nextElementSibling,
parent);
updateFiles();
}
});
}
function updateFiles() {
var dataTransfer = new DataTransfer();
var liElements = document
.querySelectorAll("#selectedFiles li");
for (var i = 0; i < liElements.length; i++) {
var fileNameFromList = liElements[i].innerText
<script> .replace(
document "\nMove Up Move Down",
.getElementById("fileInput") "");
.addEventListener( var fileFromFiles
"change", for (var j = 0; j < files.length; j++) {
function() { var file = files[j];
var files = this.files; if (file.name === fileNameFromList) {
var list = document dataTransfer.items
.getElementById("selectedFiles"); .add(file);
list.innerHTML = ""; break;
for (var i = 0; i < files.length; i++) { }
var item = document
.createElement("li");
item.className = "list-group-item d-flex justify-content-between align-items-center";
item.textContent = files[i].name;
item.innerHTML += '<div><button class="btn btn-secondary move-up"><i class="fas fa-arrow-up"></i></button> <button class="btn btn-secondary move-down"><i class="fas fa-arrow-down"></i></button></div>';
list.appendChild(item);
}
var moveUpButtons = document
.querySelectorAll(".move-up");
for (var i = 0; i < moveUpButtons.length; i++) {
moveUpButtons[i]
.addEventListener(
"click",
function(event) {
event
.preventDefault();
var parent = this.parentNode.parentNode;
var grandParent = parent.parentNode;
if (parent.previousElementSibling) {
grandParent
.insertBefore(
parent,
parent.previousElementSibling);
updateFiles();
}
});
}
var moveDownButtons = document
.querySelectorAll(".move-down");
for (var i = 0; i < moveDownButtons.length; i++) {
moveDownButtons[i]
.addEventListener(
"click",
function(event) {
event
.preventDefault();
var parent = this.parentNode.parentNode;
var grandParent = parent.parentNode;
if (parent.nextElementSibling) {
grandParent
.insertBefore(
parent.nextElementSibling,
parent);
updateFiles();
}
});
}
function updateFiles() {
var dataTransfer = new DataTransfer();
var liElements = document
.querySelectorAll("#selectedFiles li");
for (var i = 0; i < liElements.length; i++) {
var fileNameFromList = liElements[i].innerText
.replace(
"\nMove Up Move Down",
"");
var fileFromFiles
for (var j = 0; j < files.length; j++) {
var file = files[j];
if (file.name === fileNameFromList) {
dataTransfer.items
.add(file);
break;
} }
} }
document
.getElementById("fileInput").files = dataTransfer.files;
} }
document });
.getElementById("fileInput").files = dataTransfer.files; </script>
} </div>
}); </div>
</script> </div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div>
</div>
</div>
</div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div>
</body> </body>
</html> </html>

View File

@ -4,33 +4,31 @@
<th:block th:insert="~{fragments/common :: head(title=#{pdfOrganiser.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{pdfOrganiser.title})}"></th:block>
<body> <div id="page-container"> <body>
<div id="content-wrap"> <div id="page-container">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <div id="content-wrap">
<br> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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="#{pdfOrganiser.header}"></h2> <h2 th:text="#{pdfOrganiser.header}"></h2>
<form th:action="@{rearrange-pages}" method="post" <form th:action="@{rearrange-pages}" method="post" enctype="multipart/form-data">
enctype="multipart/form-data"> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> <div class="form-group">
<div class="form-group"> <label for="pageOrder" th:text="#{pageOrderPrompt}"></label>
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label> <input type="text" class="form-control" <input type="text" class="form-control" id="fileInput" name="pageOrder" placeholder="(e.g. 1,3,2 or 4-8,2,10-12)" required>
id="fileInput" name="pageOrder" </div>
placeholder="(e.g. 1,3,2 or 4-8,2,10-12)" required> <button type="submit" class="btn btn-primary" th:text="#{pdfOrganiser.submit}"></button>
</div> </form>
<button type="submit" class="btn btn-primary" th:text="#{pdfOrganiser.submit}"></button> <th:block th:insert="~{fragments/common :: filelist}"></th:block>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -4,33 +4,31 @@
<th:block th:insert="~{fragments/common :: head(title=#{pageRemover.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{pageRemover.title})}"></th:block>
<body> <div id="page-container"> <body>
<div id="content-wrap"> <div id="page-container">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <div id="content-wrap">
<br> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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="#{pageRemover.header}"></h2> <h2 th:text="#{pageRemover.header}"></h2>
<form th:action="@{remove-pages}" method="post" <form th:action="@{remove-pages}" method="post" enctype="multipart/form-data">
enctype="multipart/form-data"> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> <div class="form-group">
<div class="form-group"> <label for="pagesToDelete" th:text="#{pageRemover.pagesToDelete}"></label>
<label for="pagesToDelete" th:text="#{pageRemover.pagesToDelete}"></label> <input type="text" class="form-control" <input type="text" class="form-control" id="fileInput" name="pagesToDelete" placeholder="(e.g. 1,2,6 or 1-10,15-30)" required>
id="fileInput" name="pagesToDelete" </div>
placeholder="(e.g. 1,2,6 or 1-10,15-30)" required> <button type="submit" class="btn btn-primary" th:text="#{pageRemover.submit}"></button>
</div> </form>
<button type="submit" class="btn btn-primary" th:text="#{pageRemover.submit}"></button> <th:block th:insert="~{fragments/common :: filelist}"></th:block>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -5,51 +5,51 @@
<th:block th:insert="~{fragments/common :: head(title=#{rotate.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{rotate.title})}"></th:block>
<body> <div id="page-container"> <body>
<div id="content-wrap"> <div id="page-container">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <div id="content-wrap">
<br> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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="#{rotate.header}"></h2> <h2 th:text="#{rotate.header}"></h2>
<form action="#" th:action="@{rotate-pdf}" th:object="${rotateForm}" method="post" enctype="multipart/form-data"> <form action="#" th:action="@{rotate-pdf}" th:object="${rotateForm}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<input type="hidden" id="angleInput" name="angle" value="0"> <input type="hidden" id="angleInput" name="angle" value="0">
<div id="editSection" style="display: none"> <div id="editSection" style="display: none">
<div class="previewContainer"> <div class="previewContainer">
<img id="pdf-preview"/> <img id="pdf-preview" />
</div> </div>
<div class="buttonContainer"> <div class="buttonContainer">
<button type="button" class="btn btn-secondary" onclick="rotate(-90)"> <button type="button" class="btn btn-secondary" onclick="rotate(-90)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16"> <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" />
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"/> <path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z" />
</svg> </svg>
</button> </button>
<button type="submit" class="btn btn-primary" th:text="#{rotate.submit}"></button> <button type="submit" class="btn btn-primary" th:text="#{rotate.submit}"></button>
<button type="button" class="btn btn-secondary" onclick="rotate(90)"> <button type="button" class="btn btn-secondary" onclick="rotate(90)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16"> <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" />
<path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/> <path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z" />
</svg> </svg>
</button> </button>
</div> </div>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
<script> <script>
const angleInput = document.getElementById("angleInput"); const angleInput = document.getElementById("angleInput");
const fileInput = document.getElementById("fileInput-input"); const fileInput = document.getElementById("fileInput-input");
const preview = document.getElementById("pdf-preview"); const preview = document.getElementById("pdf-preview");
@ -96,36 +96,37 @@
angleInput.value = newAngle; angleInput.value = newAngle;
} }
</script> </script>
<style> <style>
#pdf-preview { #pdf-preview {
margin: 0 auto; margin: 0 auto;
display: block; display: block;
max-width: calc(100% - 30px); max-width: calc(100% - 30px);
max-height: calc(100% - 30px); max-height: calc(100% - 30px);
box-shadow: 0 0 4px rgba(100,100,100,.25); box-shadow: 0 0 4px rgba(100, 100, 100, .25);
transition: rotate .3s; transition: rotate .3s;
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
translate: -50% -50%; translate: -50% -50%;
} }
.previewContainer {
aspect-ratio: 1;
width: 100%;
border: 1px solid rgba(0,0,0,.125);
border-radius: 0.25rem;
margin: 1rem 0;
padding: 15px;
display: block;
overflow: hidden;
position: relative;
}
.buttonContainer { .previewContainer {
display: flex; aspect-ratio: 1;
justify-content: space-around; width: 100%;
} border: 1px solid rgba(0, 0, 0, .125);
</style> border-radius: 0.25rem;
margin: 1rem 0;
padding: 15px;
display: block;
overflow: hidden;
position: relative;
}
.buttonContainer {
display: flex;
justify-content: space-around;
}
</style>
</body> </body>
</html> </html>

View File

@ -3,90 +3,78 @@
<th:block th:insert="~{fragments/common :: head(title=#{addPassword.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{addPassword.title})}"></th:block>
<body> <div id="page-container"> <body>
<div id="content-wrap"> <div id="page-container">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <div id="content-wrap">
<br> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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="#{addPassword.header}"></h2> <h2 th:text="#{addPassword.header}"></h2>
<form action="add-password" method="post" <form action="add-password" method="post" enctype="multipart/form-data">
enctype="multipart/form-data"> <div class="form-group">
<div class="form-group"> <label th:text="#{addPassword.selectText.1}"></label>
<label th:text="#{addPassword.selectText.1}"></label> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> </div>
</div> <div class="form-group">
<div class="form-group"> <label th:text="#{addPassword.selectText.2}"></label> <input type="password" class="form-control" id="password" name="password" required>
<label th:text="#{addPassword.selectText.2}"></label> <input type="password" </div>
class="form-control" id="password" name="password" required> <div class="form-group">
</div> <label th:text="#{addPassword.selectText.3}"></label> <select class="form-control" id="keyLength" name="keyLength">
<div class="form-group"> <option value="40">40</option>
<label th:text="#{addPassword.selectText.3}"></label> <select class="form-control" <option value="128">128</option>
id="keyLength" name="keyLength"> <option value="256">256</option>
<option value="40">40</option> </select> <small class="form-text text-muted" th:text="#{addPassword.selectText.4}"></small>
<option value="128">128</option> </div>
<option value="256">256</option> <div class="form-group">
</select> <small class="form-text text-muted" th:text="#{addPassword.selectText.4}"></small> <label th:text="#{addPassword.selectText.5}"></label>
</div> <div class="form-check">
<div class="form-group"> <input class="form-check-input" type="checkbox" id="canAssembleDocument" name="canAssembleDocument">
<label th:text="#{addPassword.selectText.5}"></label> <label class="form-check-label" for="canAssembleDocument" th:text="#{addPassword.selectText.6}"></label>
<div class="form-check"> </div>
<input class="form-check-input" type="checkbox" <div class="form-check">
id="canAssembleDocument" name="canAssembleDocument"> <label <input class="form-check-input" type="checkbox" id="canExtractContent" name="canExtractContent">
class="form-check-label" for="canAssembleDocument" th:text="#{addPassword.selectText.6}"></label> <label class="form-check-label" for="canExtractContent" th:text="#{addPassword.selectText.7}"></label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" <input class="form-check-input" type="checkbox" id="canExtractForAccessibility" name="canExtractForAccessibility">
id="canExtractContent" name="canExtractContent"> <label <label class="form-check-label" for="canExtractForAccessibility" th:text="#{addPassword.selectText.8}"></label>
class="form-check-label" for="canExtractContent" th:text="#{addPassword.selectText.7}"></label> </div>
</div> <div class="form-check">
<div class="form-check"> <input class="form-check-input" type="checkbox" id="canFillInForm" name="canFillInForm">
<input class="form-check-input" type="checkbox" <label class="form-check-label" for="canFillInForm" th:text="#{addPassword.selectText.9}"></label>
id="canExtractForAccessibility" </div>
name="canExtractForAccessibility"> <label <div class="form-check">
class="form-check-label" for="canExtractForAccessibility" th:text="#{addPassword.selectText.8}"></label> <input class="form-check-input" type="checkbox" id="canModify" name="canModify">
</div> <label class="form-check-label" for="canModify" th:text="#{addPassword.selectText.10}"></label>
<div class="form-check"> </div>
<input class="form-check-input" type="checkbox" <div class="form-check">
id="canFillInForm" name="canFillInForm"> <label <input class="form-check-input" type="checkbox" id="canModifyAnnotations" name="canModifyAnnotations">
class="form-check-label" for="canFillInForm" th:text="#{addPassword.selectText.9}"></label> <label class="form-check-label" for="canModifyAnnotations" th:text="#{addPassword.selectText.11}"></label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="canModify" <input class="form-check-input" type="checkbox" id="canPrint" name="canPrint">
name="canModify"> <label class="form-check-label" <label class="form-check-label" for="canPrint" th:text="#{addPassword.selectText.12}"></label>
for="canModify" th:text="#{addPassword.selectText.10}"></label> </div>
</div> <div class="form-check">
<div class="form-check"> <input class="form-check-input" type="checkbox" id="canPrintFaithful" name="canPrintFaithful">
<input class="form-check-input" type="checkbox" <label class="form-check-label" for="canPrintFaithful" th:text="#{addPassword.selectText.13}"></label>
id="canModifyAnnotations" name="canModifyAnnotations"> <label </div>
class="form-check-label" for="canModifyAnnotations" th:text="#{addPassword.selectText.11}"></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="canPrint"
name="canPrint"> <label class="form-check-label"
for="canPrint" th:text="#{addPassword.selectText.12}"></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox"
id="canPrintFaithful" name="canPrintFaithful"> <label
class="form-check-label" for="canPrintFaithful" th:text="#{addPassword.selectText.13}"></label>
</div>
</div> </div>
<br /> <br />
<div class="form-group text-center"> <div class="form-group text-center">
<button type="submit" class="btn btn-primary" th:text="#{addPassword.submit}"></button> <button type="submit" class="btn btn-primary" th:text="#{addPassword.submit}"></button>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -3,50 +3,50 @@
<th:block th:insert="~{fragments/common :: head(title=#{watermark.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{watermark.title})}"></th:block>
<body> <div id="page-container"> <body>
<div id="content-wrap"> <div id="page-container">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <div id="content-wrap">
<br> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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="#{watermark.header}"></h2> <h2 th:text="#{watermark.header}"></h2>
<form method="post" enctype="multipart/form-data" action="add-watermark"> <form method="post" enctype="multipart/form-data" action="add-watermark">
<div class="form-group"> <div class="form-group">
<label th:text="#{watermark.selectText.1}"></label> <label th:text="#{watermark.selectText.1}"></label>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="watermarkText" th:text="#{watermark.selectText.2}"></label> <label for="watermarkText" th:text="#{watermark.selectText.2}"></label>
<input type="text" id="watermarkText" name="watermarkText" class="form-control" placeholder="Stirling-PDF" required/> <input type="text" id="watermarkText" name="watermarkText" class="form-control" placeholder="Stirling-PDF" required />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="fontSize" th:text="#{watermark.selectText.3}"></label> <label for="fontSize" th:text="#{watermark.selectText.3}"></label>
<input type="text" id="fontSize" name="fontSize" class="form-control" value="30"/> <input type="text" id="fontSize" name="fontSize" class="form-control" value="30" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="rotation" th:text="#{watermark.selectText.4}"></label> <label for="rotation" th:text="#{watermark.selectText.4}"></label>
<input type="text" id="rotation" name="rotation" class="form-control" value="45"/> <input type="text" id="rotation" name="rotation" class="form-control" value="45" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="widthSpacer" th:text="#{watermark.selectText.5}"></label> <label for="widthSpacer" th:text="#{watermark.selectText.5}"></label>
<input type="text" id="widthSpacer" name="widthSpacer" class="form-control" value="50"/> <input type="text" id="widthSpacer" name="widthSpacer" class="form-control" value="50" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="heightSpacer" th:text="#{watermark.selectText.6}"></label> <label for="heightSpacer" th:text="#{watermark.selectText.6}"></label>
<input type="text" id="heightSpacer" name="heightSpacer" class="form-control" value="50"/> <input type="text" id="heightSpacer" name="heightSpacer" class="form-control" value="50" />
</div> </div>
<div class="form-group text-center"> <div class="form-group text-center">
<input type="submit" th:value="#{watermark.submit}" class="btn btn-primary"/> <input type="submit" th:value="#{watermark.submit}" class="btn btn-primary" />
</div> </div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -3,85 +3,84 @@
<th:block th:insert="~{fragments/common :: head(title=#{changeMetadata.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{changeMetadata.title})}"></th:block>
<body> <div id="page-container"> <body>
<div id="content-wrap"> <div id="page-container">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <div id="content-wrap">
<br> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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" enctype="multipart/form-data" th:action="@{/update-metadata}"> <form method="post" enctype="multipart/form-data" th:action="@{/update-metadata}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<p class="text-muted">Please select the variables you wish to change</p>
<div class="form-group form-check form-check-inline">
<input type="checkbox" class="form-check-input" id="deleteAll">
<label class="ml-3" for="deleteAll">Delete all metadata</label>
</div>
<p class="text-muted">Please select the variables you wish to change</p> <div class="form-group form-check form-check-inline">
<input type="checkbox" class="form-check-input" id="advancedModeCheckbox">
<label class="ml-3" for="advancedModeCheckbox">Show Advanced Metadata:</label>
</div>
<div class="form-group form-check form-check-inline"> <div class="form-group form-check">
<input type="checkbox" class="form-check-input" id="deleteAll"> <label class="form-check-label" for="author">Author:</label>
<label class="ml-3" for="deleteAll">Delete all metadata</label> <input type="text" class="form-control" id="author">
</div> </div>
<div class="form-group form-check form-check-inline"> <div class="form-group form-check">
<input type="checkbox" class="form-check-input" id="advancedModeCheckbox"> <label class="form-check-label" for="creationDate">Creation Date:</label>
<label class="ml-3" for="advancedModeCheckbox">Show Advanced Metadata:</label> <input type="text" class="form-control" id="creationDate">
</div> </div>
<div class="form-group form-check"> <div class="form-group form-check">
<label class="form-check-label" for="author">Author:</label> <label class="form-check-label" for="creator">Creator:</label>
<input type="text" class="form-control" id="author"> <input type="text" class="form-control" id="creator">
</div> </div>
<div class="form-group form-check"> <div class="form-group form-check">
<label class="form-check-label" for="creationDate">Creation Date:</label> <label class="form-check-label" for="keywords">Keywords:</label>
<input type="text" class="form-control" id="creationDate"> <input type="text" class="form-control" id="keywords">
</div> </div>
<div class="form-group form-check"> <div class="form-group form-check">
<label class="form-check-label" for="creator">Creator:</label> <label class="form-check-label" for="modificationDate">Modification Date:</label>
<input type="text" class="form-control" id="creator"> <input type="text" class="form-control" id="modificationDate">
</div> </div>
<div class="form-group form-check"> <div class="form-group form-check">
<label class="form-check-label" for="keywords">Keywords:</label> <label class="form-check-label" for="producer">Producer:</label>
<input type="text" class="form-control" id="keywords"> <input type="text" class="form-control" id="producer">
</div> </div>
<div class="form-group form-check"> <div class="form-group form-check">
<label class="form-check-label" for="modificationDate">Modification Date:</label> <label class="form-check-label" for="subject">Subject:</label>
<input type="text" class="form-control" id="modificationDate"> <input type="text" class="form-control" id="subject">
</div> </div>
<div class="form-group form-check"> <div class="form-group form-check">
<label class="form-check-label" for="producer">Producer:</label> <label class="form-check-label" for="title">Title:</label>
<input type="text" class="form-control" id="producer"> <input type="text" class="form-control" id="title">
</div> </div>
<div class="form-group form-check"> <div class="form-group form-check">
<label class="form-check-label" for="subject">Subject:</label> <label class="form-check-label" for="trapped">Trapped:</label>
<input type="text" class="form-control" id="subject"> <input type="text" class="form-control" id="trapped">
</div> </div>
<div id="advancedMetadata" style="display: none;">
<div class="form-group form-check"> <p>Other Metadata:</p>
<label class="form-check-label" for="title">Title:</label> <div class="form-group" id="otherMetadataEntries"></div>
<input type="text" class="form-control" id="title"> </div>
</div> <div id="customMetadataEntries"></div>
<button type="button" class="btn btn-secondary" id="addMetadataBtn">Add Custom Metadata Entry</button>
<div class="form-group form-check"> <br>
<label class="form-check-label" for="trapped">Trapped:</label> <br>
<input type="text" class="form-control" id="trapped"> <button class="btn btn-primary" type="submit">Save Changes and Download PDF</button>
</div> <script>
<div id="advancedMetadata" style="display:none;">
<p>Other Metadata:</p>
<div class="form-group" id="otherMetadataEntries"></div>
</div>
<div id="customMetadataEntries"></div>
<button type="button" class="btn btn-secondary" id="addMetadataBtn">Add Custom Metadata Entry</button>
<br><br>
<button class="btn btn-primary" type="submit">Save Changes and Download PDF</button>
<script>
const advancedModeCheckbox = document.getElementById('advancedModeCheckbox'); const advancedModeCheckbox = document.getElementById('advancedModeCheckbox');
@ -179,13 +178,13 @@
</script> </script>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -4,78 +4,68 @@
<th:block th:insert="~{fragments/common :: head(title=#{permissions.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{permissions.title})}"></th:block>
<body> <div id="page-container"> <body>
<div id="content-wrap"> <div id="page-container">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <div id="content-wrap">
<br> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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="#{permissions.header}"></h2> <h2 th:text="#{permissions.header}"></h2>
<p th:text="#{permissions.warning}"></p> <p th:text="#{permissions.warning}"></p>
<form action="add-password" method="post" <form action="add-password" method="post" enctype="multipart/form-data">
enctype="multipart/form-data"> <div class="form-group">
<div class="form-group"> <label th:text="#{permissions.selectText.1}"></label>
<label th:text="#{permissions.selectText.1}"></label> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> </div>
</div> <div class="form-group">
<div class="form-group"> <label th:text="#{permissions.selectText.2}"></label>
<label th:text="#{permissions.selectText.2}"></label> <div class="form-check">
<div class="form-check"> <input class="form-check-input" type="checkbox" id="canAssembleDocument" name="canAssembleDocument">
<input class="form-check-input" type="checkbox" <label class="form-check-label" for="canAssembleDocument" th:text="#{permissions.selectText.3}"></label>
id="canAssembleDocument" name="canAssembleDocument"> <label </div>
class="form-check-label" for="canAssembleDocument" th:text="#{permissions.selectText.3}"></label> <div class="form-check">
</div> <input class="form-check-input" type="checkbox" id="canExtractContent" name="canExtractContent">
<div class="form-check"> <label class="form-check-label" for="canExtractContent" th:text="#{permissions.selectText.4}"></label>
<input class="form-check-input" type="checkbox" </div>
id="canExtractContent" name="canExtractContent"> <label <div class="form-check">
class="form-check-label" for="canExtractContent" th:text="#{permissions.selectText.4}"></label> <input class="form-check-input" type="checkbox" id="canExtractForAccessibility" name="canExtractForAccessibility">
</div> <label class="form-check-label" for="canExtractForAccessibility" th:text="#{permissions.selectText.5}"></label>
<div class="form-check"> </div>
<input class="form-check-input" type="checkbox" <div class="form-check">
id="canExtractForAccessibility" <input class="form-check-input" type="checkbox" id="canFillInForm" name="canFillInForm">
name="canExtractForAccessibility"> <label <label class="form-check-label" for="canFillInForm" th:text="#{permissions.selectText.6}"></label>
class="form-check-label" for="canExtractForAccessibility" th:text="#{permissions.selectText.5}"></label> </div>
</div> <div class="form-check">
<div class="form-check"> <input class="form-check-input" type="checkbox" id="canModify" name="canModify">
<input class="form-check-input" type="checkbox" <label class="form-check-label" for="canModify" th:text="#{permissions.selectText.7}"></label>
id="canFillInForm" name="canFillInForm"> <label </div>
class="form-check-label" for="canFillInForm" th:text="#{permissions.selectText.6}"></label> <div class="form-check">
</div> <input class="form-check-input" type="checkbox" id="canModifyAnnotations" name="canModifyAnnotations">
<div class="form-check"> <label class="form-check-label" for="canModifyAnnotations" th:text="#{permissions.selectText.8}"></label>
<input class="form-check-input" type="checkbox" id="canModify" </div>
name="canModify"> <label class="form-check-label" <div class="form-check">
for="canModify" th:text="#{permissions.selectText.7}"></label> <input class="form-check-input" type="checkbox" id="canPrint" name="canPrint">
</div> <label class="form-check-label" for="canPrint" th:text="#{permissions.selectText.9}"></label>
<div class="form-check"> </div>
<input class="form-check-input" type="checkbox" <div class="form-check">
id="canModifyAnnotations" name="canModifyAnnotations"> <label <input class="form-check-input" type="checkbox" id="canPrintFaithful" name="canPrintFaithful">
class="form-check-label" for="canModifyAnnotations" th:text="#{permissions.selectText.8}"></label> <label class="form-check-label" for="canPrintFaithful" th:text="#{permissions.selectText.10}"></label>
</div> </div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="canPrint"
name="canPrint"> <label class="form-check-label"
for="canPrint" th:text="#{permissions.selectText.9}"></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox"
id="canPrintFaithful" name="canPrintFaithful"> <label
class="form-check-label" for="canPrintFaithful" th:text="#{permissions.selectText.10}"></label>
</div>
</div> </div>
<br /> <br />
<div class="form-group text-center"> <div class="form-group text-center">
<button type="submit" class="btn btn-primary" th:text="#{permissions.submit}"></button> <button type="submit" class="btn btn-primary" th:text="#{permissions.submit}"></button>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div th:insert="~{fragments/footer.html :: footer}"></div> <div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -3,36 +3,35 @@
<th:block th:insert="~{fragments/common :: head(title=#{removePassword.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{removePassword.title})}"></th:block>
<body> <div id="page-container"> <body>
<div id="content-wrap"> <div id="page-container">
<div th:insert="~{fragments/navbar.html :: navbar}"></div> <div id="content-wrap">
<br> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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="#{removePassword.header}"></h2> <h2 th:text="#{removePassword.header}"></h2>
<form action="add-password" method="post" <form action="add-password" method="post" enctype="multipart/form-data">
enctype="multipart/form-data"> <div class="form-group">
<div class="form-group"> <label th:text="#{removePassword.selectText.1}"></label>
<label th:text="#{removePassword.selectText.1}"></label> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> </div>
</div> <div class="form-group">
<div class="form-group"> <label th:text="#{removePassword.selectText.2}"></label>
<label th:text="#{removePassword.selectText.2}"></label> <input type="password" <input type="password" class="form-control" id="password" name="password" required>
class="form-control" id="password" name="password" required> </div>
</div> <br />
<br /> <div class="form-group text-center">
<div class="form-group text-center"> <button type="submit" class="btn btn-primary" th:text="#{removePassword.submit}"></button>
<button type="submit" class="btn btn-primary" th:text="#{removePassword.submit}"></button> </div>
</div> </form>
</form> </div>
</div> </div>
</div> </div>
</div> </div>
</div> <div th:insert="~{fragments/footer.html :: footer}"></div>
<div th:insert="~{fragments/footer.html :: footer}"></div> </div>
</div>
</body> </body>
</html> </html>

View File

@ -6,42 +6,39 @@
<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> <div th:insert="~{fragments/navbar.html :: navbar}"></div>
<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"> <h1 th:text="#{split.header}"></h1>
<h1 th:text="#{split.header}"></h1> <p th:text="#{split.desc.1}"></p>
<p th:text="#{split.desc.1}"></p> <p th:text="#{split.desc.2}"></p>
<p th:text="#{split.desc.2}"></p> <p th:text="#{split.desc.3}"></p>
<p th:text="#{split.desc.3}"></p> <p th:text="#{split.desc.4}"></p>
<p th:text="#{split.desc.4}"></p> <p th:text="#{split.desc.5}"></p>
<p th:text="#{split.desc.5}"></p> <p th:text="#{split.desc.6}"></p>
<p th:text="#{split.desc.6}"></p> <p th:text="#{split.desc.7}"></p>
<p th:text="#{split.desc.7}"></p> <p th:text="#{split.desc.8}"></p>
<p th:text="#{split.desc.8}"></p>
<form th:action="@{split-pages}" method="post" <form th:action="@{split-pages}" method="post" enctype="multipart/form-data">
enctype="multipart/form-data"> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<div class="form-group"> <div class="form-group">
<label for="pages" th:text="#{split.splitPages}"></label> <input <label for="pages" th:text="#{split.splitPages}"></label>
type="text" class="form-control" id="pages" name="pages" <input type="text" class="form-control" id="pages" name="pages" placeholder="1,3,5-10" required>
placeholder="1,3,5-10" required> </div>
</div> <br>
<br> <button type="submit" class="btn btn-primary" th:text="#{split.submit}"></button>
<button type="submit" class="btn btn-primary" th:text="#{split.submit}"></button> </form>
</form> <th:block th:insert="~{fragments/common :: filelist}"></th:block>
<th:block th:insert="~{fragments/common :: filelist}"></th:block> </div>
</div> </div>
</div> </div>
</div> </div>
</div> <div th:insert="~{fragments/footer.html :: footer}"></div>
<div th:insert="~{fragments/footer.html :: footer}"></div> </div>
</div>
</body> </body>
</html> </html>