mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-02-12 00:15:51 +01:00
Feature: Support manual redaction (#2433)
# Description ## Manual Redaction: - ### Text Selection-based redaction: - ![image](https://github.com/user-attachments/assets/e59c5e6c-ef52-4f54-a98e-fc26e3226c8e) - Users can now redact currently selected text by selecting the text then clicking `ctrl + s` shortcut or by pressing on **apply/save/disk icon** in the toolbar. - Users can delete/cancel the redacted area by clicking on the box containing the text, then clicking on `delete/trash` icon or by using the shortcut `delete`. - Users can customize the color of the redacted area/text (after the redaction was applied) by simply clicking on the box containing the text/area then clicking on the `color palette` icon and choosing the color they want. - Users can choose to select the color of redaction before redacting text or applying changes (this only affects newly created redaction areas, to change the color of an existing one; check the previous bullet point). - ### Draw/Area-based redaction: - ![image](https://github.com/user-attachments/assets/e2968ae3-ebaf-497e-b3bd-0c8c8f4ee157) - Users can now redact an area in the page by selecting the then clicking `ctrl + s` shortcut or by pressing on **apply/save/disk icon** in the toolbar. - Users can delete/cancel the redacted area by clicking on the drawn box, then clicking on `delete/trash` icon or by using the shortcut `delete` (requires temporarily turning off drawing mode). - Users can customize the color of the redacted area (after the redaction was applied) by simply clicking on the box containing the area then clicking on the `color palette` icon and choosing the color they want. - Users can choose to select the color of redaction before drawing the box or applying changes (this only affects newly created redaction areas, to change the color of an existing one; check the previous bullet point). - ### Page-based redaction: - ![image](https://github.com/user-attachments/assets/aba59432-23e7-4fe6-aa28-872c23a91242) - Users can now redact **ENTIRE** pages by specifying the page number(s), range(s) or functions. - Users can customize the color of page-based redaction (doesn't affect text-based nor draw-based redactions). ### Redaction modes: There are three modes of redaction/operation currently supported - Text Selection-based redaction (TEXT) - Draw/Area-based redaction (DRAWING) - None - by simply not choosing any of the above modes (NONE). ## How to use: - **Text Selection-based redaction:** click on this icon in the toolbar ![image](https://github.com/user-attachments/assets/52cc31ef-6946-482c-84a2-1ddb79646dd8) to enable `text-selection redaction mode` then select the text you want to redact then press `ctrl + s` or click on the disk/save icon ![image](https://github.com/user-attachments/assets/f2bdf2f2-ee07-4682-bb9a-95e13a1004cf). - **Draw/Area-based redaction:** click on this icon in the toolbar ![image](https://github.com/user-attachments/assets/fe00dca9-761e-47a0-a748-2041830dc73e) to enable `draw/area-based redaction` then `left mouse click (LMB)` on the starting point of the rectangle, then once you are satisfied with the rectangle's placement/dimensions then `left mouse click (LMB)` again to apply the redaction. - **Example:** `Left mouse click (LMB)` then move mouse to the right then bottom then `Left mouse click (LMB)`. - Note: Red box/rectangle borders indicate that you have not yet saved (you need to left click on the page to save) ![image](https://github.com/user-attachments/assets/5ce5f789-9d6f-4984-8555-e8fef2a3e3cc) once saved the borders will become green ![image](https://github.com/user-attachments/assets/85cabb9f-e7ee-4268-90cd-80493b625466) (they also become clickable/hover-able when drawing mode is off). - **Page-based redactions:**: Insert the page number(s), range(s) and/or functions (separated by `,`) then select your preferred color and click on `Redact` to submit. ![image](https://github.com/user-attachments/assets/ed8a0a98-32b2-4ae1-a3c7-c54bfe0fea66) - **Color Customizations:** - You can change the redaction color for new redactions by clicking on this icon in the toolbar ![image](https://github.com/user-attachments/assets/bad573ee-0545-4329-b131-2022f970f134). - You can change the redaction color for existing redactions by hovering over the redaction box then clicking on it (`Left mouse click LMB`) then clicking on color palette (highlighted in red in the picture) ![image](https://github.com/user-attachments/assets/22281a81-2cd9-4771-9a93-a75b6dd93433) then select your preferred color. - **Deletions:** - You can delete a redacted area by hovering over the redaction box then clicking on it (`Left mouse click LMB`) then clicking on the trash icon (highlighted in red in the picture) ![image](https://github.com/user-attachments/assets/f0347279-8211-4b1c-a91d-c1fcb929cc5d). ## Card in the home page: ![image](https://github.com/user-attachments/assets/b3fb16eb-5ff0-4548-9f22-b1b8fe162c8b) Closes #465 ## Checklist - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have performed a self-review of my own code - [x] I have attached images of the change if it is UI based - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] If my code has heavily changed functionality I have updated relevant docs on [Stirling-PDFs doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) - [ ] My changes generate no new warnings - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) --------- Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
This commit is contained in:
parent
79f6598508
commit
22af79a279
@ -135,6 +135,7 @@ public class EndpointConfiguration {
|
||||
addEndpointToGroup("Security", "remove-cert-sign");
|
||||
addEndpointToGroup("Security", "sanitize-pdf");
|
||||
addEndpointToGroup("Security", "auto-redact");
|
||||
addEndpointToGroup("Security", "redact");
|
||||
|
||||
// Adding endpoints to "Other" group
|
||||
addEndpointToGroup("Other", "ocr-pdf");
|
||||
@ -234,6 +235,7 @@ public class EndpointConfiguration {
|
||||
addEndpointToGroup("Java", "markdown-to-pdf");
|
||||
addEndpointToGroup("Java", "show-javascript");
|
||||
addEndpointToGroup("Java", "auto-redact");
|
||||
addEndpointToGroup("Java", "redact");
|
||||
addEndpointToGroup("Java", "pdf-to-csv");
|
||||
addEndpointToGroup("Java", "split-by-size-or-count");
|
||||
addEndpointToGroup("Java", "overlay-pdf");
|
||||
|
@ -3,13 +3,18 @@ package stirling.software.SPDF.controller.api.security;
|
||||
import java.awt.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.PDPageTree;
|
||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -21,12 +26,17 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import stirling.software.SPDF.model.PDFText;
|
||||
import stirling.software.SPDF.model.api.security.ManualRedactPdfRequest;
|
||||
import stirling.software.SPDF.model.api.security.RedactPdfRequest;
|
||||
import stirling.software.SPDF.model.api.security.RedactionArea;
|
||||
import stirling.software.SPDF.pdf.TextFinder;
|
||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
||||
import stirling.software.SPDF.utils.GeneralUtils;
|
||||
import stirling.software.SPDF.utils.PdfUtils;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
import stirling.software.SPDF.utils.propertyeditor.StringToArrayListPropertyEditor;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/security")
|
||||
@ -41,6 +51,107 @@ public class RedactController {
|
||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
public void initBinder(WebDataBinder binder) {
|
||||
binder.registerCustomEditor(List.class, "redactions", new StringToArrayListPropertyEditor());
|
||||
}
|
||||
|
||||
@PostMapping(value = "/redact", consumes = "multipart/form-data")
|
||||
@Operation(summary = "Redacts areas and pages in a PDF document", description = "This operation takes an input PDF file with a list of areas, page number(s)/range(s)/function(s) to redact. Input:PDF, Output:PDF, Type:SISO")
|
||||
public ResponseEntity<byte[]> redactPDF(@ModelAttribute ManualRedactPdfRequest request) throws IOException {
|
||||
MultipartFile file = request.getFileInput();
|
||||
List<RedactionArea> redactionAreas = request.getRedactions();
|
||||
|
||||
PDDocument document = pdfDocumentFactory.load(file);
|
||||
|
||||
PDPageTree allPages = document.getDocumentCatalog().getPages();
|
||||
|
||||
redactPages(request, document, allPages);
|
||||
redactAreas(redactionAreas, document, allPages);
|
||||
|
||||
if (request.isConvertPDFToImage()) {
|
||||
PDDocument convertedPdf = PdfUtils.convertPdfToPdfImage(document);
|
||||
document.close();
|
||||
document = convertedPdf;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
document.save(baos);
|
||||
document.close();
|
||||
|
||||
byte[] pdfContent = baos.toByteArray();
|
||||
return WebResponseUtils.bytesToWebResponse(
|
||||
pdfContent,
|
||||
Filenames.toSimpleFileName(file.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
|
||||
+ "_redacted.pdf");
|
||||
}
|
||||
|
||||
private void redactAreas(List<RedactionArea> redactionAreas, PDDocument document, PDPageTree allPages)
|
||||
throws IOException {
|
||||
Color redactColor = null;
|
||||
for (RedactionArea redactionArea : redactionAreas) {
|
||||
if (redactionArea.getPage() == null || redactionArea.getPage() <= 0
|
||||
|| redactionArea.getHeight() == null || redactionArea.getHeight() <= 0.0D
|
||||
|| redactionArea.getWidth() == null || redactionArea.getWidth() <= 0.0D)
|
||||
continue;
|
||||
PDPage page = allPages.get(redactionArea.getPage() - 1);
|
||||
|
||||
PDPageContentStream contentStream = new PDPageContentStream(
|
||||
document, page, PDPageContentStream.AppendMode.APPEND, true, true);
|
||||
redactColor = decodeOrDefault(redactionArea.getColor(), Color.BLACK);
|
||||
contentStream.setNonStrokingColor(redactColor);
|
||||
|
||||
float x = redactionArea.getX().floatValue();
|
||||
float y = redactionArea.getY().floatValue();
|
||||
float width = redactionArea.getWidth().floatValue();
|
||||
float height = redactionArea.getHeight().floatValue();
|
||||
|
||||
PDRectangle box = page.getBBox();
|
||||
|
||||
contentStream.addRect(x, box.getHeight() - y - height, width, height);
|
||||
contentStream.fill();
|
||||
contentStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void redactPages(ManualRedactPdfRequest request, PDDocument document, PDPageTree allPages)
|
||||
throws IOException {
|
||||
Color redactColor = decodeOrDefault(request.getPageRedactionColor(), Color.BLACK);
|
||||
List<Integer> pageNumbers = getPageNumbers(request, allPages.getCount());
|
||||
for (Integer pageNumber : pageNumbers) {
|
||||
PDPage page = allPages.get(pageNumber);
|
||||
|
||||
PDPageContentStream contentStream = new PDPageContentStream(
|
||||
document, page, PDPageContentStream.AppendMode.APPEND, true, true);
|
||||
contentStream.setNonStrokingColor(redactColor);
|
||||
|
||||
PDRectangle box = page.getBBox();
|
||||
|
||||
contentStream.addRect(0, 0, box.getWidth(), box.getHeight());
|
||||
contentStream.fill();
|
||||
contentStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
private Color decodeOrDefault(String hex, Color defaultColor) {
|
||||
Color color = null;
|
||||
try {
|
||||
color = Color.decode(hex);
|
||||
} catch (Exception e) {
|
||||
color = defaultColor;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
private List<Integer> getPageNumbers(ManualRedactPdfRequest request, int pagesCount) {
|
||||
String pageNumbersInput = request.getPageNumbers();
|
||||
String[] parsedPageNumbers = pageNumbersInput != null ? pageNumbersInput.split(",") : new String[0];
|
||||
List<Integer> pageNumbers = GeneralUtils.parsePageList(parsedPageNumbers, pagesCount, false);
|
||||
Collections.sort(pageNumbers);
|
||||
return pageNumbers;
|
||||
}
|
||||
|
||||
@PostMapping(value = "/auto-redact", consumes = "multipart/form-data")
|
||||
@Operation(
|
||||
summary = "Redacts listOfText in a PDF document",
|
||||
|
@ -18,6 +18,12 @@ public class SecurityWebController {
|
||||
return "security/auto-redact";
|
||||
}
|
||||
|
||||
@GetMapping("/redact")
|
||||
public String redactForm(Model model) {
|
||||
model.addAttribute("currentPage", "redact");
|
||||
return "security/redact";
|
||||
}
|
||||
|
||||
@GetMapping("/add-password")
|
||||
@Hidden
|
||||
public String addPasswordForm(Model model) {
|
||||
|
@ -0,0 +1,21 @@
|
||||
package stirling.software.SPDF.model.api.security;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ManualRedactPdfRequest extends PDFWithPageNums {
|
||||
@Schema(description = "A list of areas that should be redacted")
|
||||
private List<RedactionArea> redactions;
|
||||
|
||||
@Schema(description = "Convert the redacted PDF to an image", defaultValue = "false")
|
||||
private boolean convertPDFToImage;
|
||||
|
||||
@Schema(description = "The color used to fully redact certain pages")
|
||||
private String pageRedactionColor;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package stirling.software.SPDF.model.api.security;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RedactionArea {
|
||||
@Schema(description = "The left edge point of the area to be redacted.")
|
||||
private Double x;
|
||||
@Schema(description = "The top edge point of the area to be redacted.")
|
||||
private Double y;
|
||||
|
||||
@Schema(description = "The height of the area to be redacted.")
|
||||
private Double height;
|
||||
@Schema(description = "The width of the area to be redacted.")
|
||||
private Double width;
|
||||
|
||||
@Schema(description = "The page on which the area should be redacted.")
|
||||
private Integer page;
|
||||
|
||||
@Schema(description = "The color used to redact the specified area.")
|
||||
private String color;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package stirling.software.SPDF.utils.propertyeditor;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.model.api.security.RedactionArea;
|
||||
|
||||
@Slf4j
|
||||
public class StringToArrayListPropertyEditor extends PropertyEditorSupport {
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
if (text == null || text.trim().isEmpty()) {
|
||||
setValue(new ArrayList<>());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
|
||||
TypeReference<ArrayList<RedactionArea>> typeRef = new TypeReference<ArrayList<RedactionArea>>() {
|
||||
};
|
||||
List<RedactionArea> list = objectMapper.readValue(text, typeRef);
|
||||
setValue(list);
|
||||
} catch (Exception e) {
|
||||
log.error("Exception while converting {}", e);
|
||||
throw new IllegalArgumentException(
|
||||
"Failed to convert java.lang.String to java.util.List");
|
||||
}
|
||||
}
|
||||
}
|
@ -82,6 +82,7 @@ pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
apply=Apply
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
@ -474,6 +475,10 @@ home.autoRedact.title=Auto Redact
|
||||
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
|
||||
autoRedact.tags=Redact,Hide,black out,black,marker,hidden
|
||||
|
||||
home.redact.title=Manual Redaction
|
||||
home.redact.desc=Redacts a PDF based on selected text, drawn shapes and/or selected page(s)
|
||||
redact.tags=Redact,Hide,black out,black,marker,hidden,manual
|
||||
|
||||
home.tableExtraxt.title=PDF to CSV
|
||||
home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV
|
||||
tableExtraxt.tags=CSV,Table Extraction,extract,convert
|
||||
@ -579,6 +584,15 @@ autoRedact.customPaddingLabel=Custom Extra Padding
|
||||
autoRedact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
|
||||
autoRedact.submitButton=Submit
|
||||
|
||||
#redact
|
||||
redact.title=Manual Redaction
|
||||
redact.header=Manual Redaction
|
||||
redact.submit=Redact
|
||||
redact.pageBasedRedaction=Page-based Redaction
|
||||
redact.convertPDFToImageLabel=Convert PDF to PDF-Image (Used to remove text behind the box)
|
||||
redact.pageRedactionNumbers.title=Pages
|
||||
redact.pageRedactionNumbers.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
|
||||
redact.redactionColor.title=Redaction Color
|
||||
|
||||
#showJS
|
||||
showJS.title=Show Javascript
|
||||
|
322
src/main/resources/static/css/redact.css
Normal file
322
src/main/resources/static/css/redact.css
Normal file
@ -0,0 +1,322 @@
|
||||
:root {
|
||||
--page-redaction-color: #000000;
|
||||
}
|
||||
|
||||
.textLayer span::selection,
|
||||
.textLayer span::-moz-selection {
|
||||
background-color: rgba(0, 100, 0, 0.26);
|
||||
}
|
||||
|
||||
.selected-wrapper {
|
||||
position: absolute;
|
||||
outline: 2px solid darkgreen;
|
||||
outline-offset: -2px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.selected-wrapper:hover:not(:has(.redaction-overlay:hover)) {
|
||||
outline-color: var(--palette-color, #000000);
|
||||
background-color: var(--palette-color, #000000);
|
||||
z-index: 10;
|
||||
transition: background-color 0.065s linear;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.redaction-overlay {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
|
||||
left: 50%;
|
||||
top: 100%;
|
||||
|
||||
min-width: 25px;
|
||||
max-width: 90px;
|
||||
|
||||
min-height: 25px;
|
||||
|
||||
flex-wrap: nowrap;
|
||||
|
||||
column-gap: 5px;
|
||||
row-gap: 2px;
|
||||
|
||||
border-radius: 2px;
|
||||
padding: 2px;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
background-color: rgb(0 96 170);
|
||||
outline: 1px solid gray;
|
||||
translate: -50% -100%;
|
||||
}
|
||||
|
||||
.redaction-overlay svg {
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
|
||||
max-width: 35px;
|
||||
max-height: 35px;
|
||||
|
||||
fill: rgba(255, 255, 255, 0.904);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.redaction-overlay svg:hover {
|
||||
cursor: pointer;
|
||||
background-color: rgb(3, 63, 109);
|
||||
fill: rgba(226, 226, 226, 0.904);
|
||||
}
|
||||
|
||||
.textLayer div,
|
||||
.textLayer div > * {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.rectangle {
|
||||
border: 2px solid #ff0000;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
html {
|
||||
--textLayer-pointer-events: auto;
|
||||
--textLayer-user-select: auto;
|
||||
}
|
||||
|
||||
.textLayer * {
|
||||
pointer-events: var(--textLayer-pointer-events);
|
||||
user-select: var(--textLayer-user-select);
|
||||
}
|
||||
|
||||
#showMoreBtnIcon::before {
|
||||
left: 5px;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
#showMoreBtn {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#man-text-select-redact, #man-shape-redact, #downloadBtn, #uploadBtn, #pageBasedRedactionBtn, #pdfToImageBtn, #showMoreBtn {
|
||||
height: var(--toolButton-height);
|
||||
width: var(--toolButton-width);
|
||||
|
||||
border-radius: var(--toolButton-border-radius);
|
||||
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#text-selection, #shape-selection, #downloadBtnIcon, #uploadBtnIcon, #pageBasedRedactionBtnIcon, #pdfToImageBtnIcon, #showMoreBtnIcon {
|
||||
position: relative;
|
||||
font-size: var(--toolButton-icon-font-size);
|
||||
}
|
||||
|
||||
:is(#man-shape-redact, #man-text-select-redact, #sidebarToggle, #viewThumbnail, #viewOutline, #showMoreBtn).toggled {
|
||||
background-color: rgb(50, 159, 243);
|
||||
color: rgb(255 255 255);
|
||||
outline:rgb(50, 159, 243) !important;
|
||||
border-color: rgb(50, 159, 243) !important;
|
||||
}
|
||||
|
||||
:is(#man-shape-redact, #man-text-select-redact, #redactionsPaletteContainer, #downloadBtn, #uploadBtn, #pageBasedRedactionBtn, #pdfToImageBtn, #showMoreBtn):hover {
|
||||
background-color: rgba(6, 114, 197, 0.82);
|
||||
color: rgb(255 255 255);
|
||||
outline:rgba(6, 114, 197, 0.82) !important;
|
||||
border-color: rgba(6, 114, 197, 0.82) !important;
|
||||
}
|
||||
|
||||
#redactionsPaletteContainer {
|
||||
height: var(--toolButton-height);
|
||||
width: var(--toolButton-width);
|
||||
|
||||
border-radius: var(--toolButton-border-radius);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#redactionsPaletteContainer *, #showMoreBtn * {
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#redactions-palette {
|
||||
display: inline;
|
||||
position: relative;
|
||||
|
||||
border-bottom: 8px solid var(--palette-color);
|
||||
border-radius: inherit;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
font-size: var(--toolButton-icon-font-size);
|
||||
}
|
||||
|
||||
#redactions-palette::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
height: 6px;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
bottom: 0px;
|
||||
background-color: var(--palette-color);
|
||||
}
|
||||
|
||||
#redactions-palette > input[type=color] {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: var(--toolButton-height);
|
||||
height: 0;
|
||||
}
|
||||
|
||||
#apply-redaction {
|
||||
height: var(--toolButton-height);
|
||||
width: var(--toolButton-width);
|
||||
|
||||
border-radius: var(--toolButton-border-radius);
|
||||
}
|
||||
|
||||
#apply-redaction[disabled=true], #apply-redaction:disabled:not([disabled=false]) {
|
||||
color: rgb(147, 149, 153);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
#apply-redaction:is(:hover):not([disabled=true], :disabled:not([disabled=false])) {
|
||||
cursor: pointer;
|
||||
background-color: rgba(6, 114, 197, 0.82);
|
||||
color: rgb(255 255 255);
|
||||
outline:rgba(6, 114, 197, 0.82) !important;
|
||||
border-color: rgba(6, 114, 197, 0.82) !important;
|
||||
}
|
||||
|
||||
.toolbar-btn-hover:hover {
|
||||
cursor: pointer;
|
||||
background-color: rgba(6, 114, 197, 0.82) !important;
|
||||
color: rgb(255 255 255) !important;
|
||||
outline:rgba(6, 114, 197, 0.82) !important;
|
||||
border-color: rgba(6, 114, 197, 0.82) !important;
|
||||
}
|
||||
|
||||
#apply-redaction-icon {
|
||||
font-size: var(--toolButton-icon-font-size);
|
||||
}
|
||||
|
||||
#apply-redaction > span {
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#pageRedactColor, input[data-for=pageRedactColor] {
|
||||
flex: 1;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
#pageRedactColor:is(:hover, :focus-within), input[data-for=pageRedactColor]:is(:hover, :focus-within) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.palette-color {
|
||||
border-bottom: 3px solid var(--palette-color);
|
||||
}
|
||||
|
||||
.palette-color:is(:hover, :focus-within) {
|
||||
cursor: pointer;
|
||||
background-color: var(--button-hover-color);
|
||||
}
|
||||
|
||||
.splitToolbarButton > .btn-primary, .splitToolbarButton > .btn-secondary, .splitToolbarButton > .toolbarButton {
|
||||
margin-left: 3px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.spin-animation {
|
||||
-webkit-animation: spin 2s linear infinite; /* Safari */
|
||||
-moz-animation: spin 2s linear infinite;
|
||||
-o-animation: spin 2s linear infinite;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes spin {
|
||||
0% { -webkit-transform: rotate(0deg); }
|
||||
100% { -webkit-transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@-moz-keyframes spin {
|
||||
0% { -webkit-transform: rotate(0deg); }
|
||||
100% { -webkit-transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@-o-keyframes spin {
|
||||
0% { -webkit-transform: rotate(0deg); }
|
||||
100% { -webkit-transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.active-redaction {
|
||||
z-index: 30 !important;
|
||||
}
|
||||
|
||||
#pageBasedRedactionOverlay {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
background-color: var(--md-sys-color-surface);
|
||||
color: var(--md-sys-color-on-surface);
|
||||
border-radius: 3rem;
|
||||
z-index: 100;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.list-styling {
|
||||
display: list-item !important;
|
||||
margin-left: 15px;
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.redacted-page {
|
||||
--page-redaction-color: none;
|
||||
}
|
||||
|
||||
.redacted-page-preview {
|
||||
border: 2px solid blue;
|
||||
}
|
||||
|
||||
.redacted-page-preview:hover {
|
||||
background-color: var(--page-redaction-color) !important;
|
||||
}
|
||||
|
||||
.redacted-page-preview * {
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.overlay-colorpicker-window {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 24px;
|
||||
height: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.redacted-thumbnail-image-preview {
|
||||
border: 2px solid blue;
|
||||
}
|
||||
|
||||
.redacted-thumbnail-preview {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.redacted-thumbnail-preview:hover::after {
|
||||
content: '';
|
||||
background-color: var(--page-redaction-color);
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
||||
height: var(--thumbnail-height);
|
||||
width: var(--thumbnail-width);
|
||||
}
|
1206
src/main/resources/static/js/redact.js
Normal file
1206
src/main/resources/static/js/redact.js
Normal file
File diff suppressed because it is too large
Load Diff
5084
src/main/resources/static/pdfjs-legacy/css/viewer-redact.css
vendored
Normal file
5084
src/main/resources/static/pdfjs-legacy/css/viewer-redact.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
18
src/main/resources/static/pdfjs-legacy/pdf.mjs
vendored
18
src/main/resources/static/pdfjs-legacy/pdf.mjs
vendored
@ -4630,7 +4630,7 @@ if (DESCRIPTORS && !('size' in URLSearchParamsPrototype)) {
|
||||
/************************************************************************/
|
||||
/******/ // The module cache
|
||||
/******/ var __webpack_module_cache__ = {};
|
||||
/******/
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/ // Check if module is in cache
|
||||
@ -4644,14 +4644,14 @@ if (DESCRIPTORS && !('size' in URLSearchParamsPrototype)) {
|
||||
/******/ // no module.loaded needed
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/************************************************************************/
|
||||
/******/ /* webpack/runtime/define property getters */
|
||||
/******/ (() => {
|
||||
@ -4664,12 +4664,12 @@ if (DESCRIPTORS && !('size' in URLSearchParamsPrototype)) {
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/
|
||||
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/
|
||||
/************************************************************************/
|
||||
var __webpack_exports__ = globalThis.pdfjsLib = {};
|
||||
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
|
||||
@ -6385,8 +6385,8 @@ function setLayerDimensions(div, viewport, mustFlip = false, mustRotate = true)
|
||||
const useRound = util_FeatureTest.isCSSRoundSupported;
|
||||
const w = `var(--scale-factor) * ${pageWidth}px`,
|
||||
h = `var(--scale-factor) * ${pageHeight}px`;
|
||||
const widthStr = useRound ? `round(${w}, 1px)` : `calc(${w})`,
|
||||
heightStr = useRound ? `round(${h}, 1px)` : `calc(${h})`;
|
||||
const widthStr = useRound ? `round(up, ${w}, 1px)` : `calc(${w})`,
|
||||
heightStr = useRound ? `round(up, ${h}, 1px)` : `calc(${h})`;
|
||||
if (!mustFlip || viewport.rotation % 180 === 0) {
|
||||
style.width = widthStr;
|
||||
style.height = heightStr;
|
||||
@ -24317,4 +24317,4 @@ var __webpack_exports__updateTextLayer = __webpack_exports__.updateTextLayer;
|
||||
var __webpack_exports__version = __webpack_exports__.version;
|
||||
export { __webpack_exports__AbortException as AbortException, __webpack_exports__AnnotationEditorLayer as AnnotationEditorLayer, __webpack_exports__AnnotationEditorParamsType as AnnotationEditorParamsType, __webpack_exports__AnnotationEditorType as AnnotationEditorType, __webpack_exports__AnnotationEditorUIManager as AnnotationEditorUIManager, __webpack_exports__AnnotationLayer as AnnotationLayer, __webpack_exports__AnnotationMode as AnnotationMode, __webpack_exports__CMapCompressionType as CMapCompressionType, __webpack_exports__ColorPicker as ColorPicker, __webpack_exports__DOMSVGFactory as DOMSVGFactory, __webpack_exports__DrawLayer as DrawLayer, __webpack_exports__FeatureTest as FeatureTest, __webpack_exports__GlobalWorkerOptions as GlobalWorkerOptions, __webpack_exports__ImageKind as ImageKind, __webpack_exports__InvalidPDFException as InvalidPDFException, __webpack_exports__MissingPDFException as MissingPDFException, __webpack_exports__OPS as OPS, __webpack_exports__Outliner as Outliner, __webpack_exports__PDFDataRangeTransport as PDFDataRangeTransport, __webpack_exports__PDFDateString as PDFDateString, __webpack_exports__PDFWorker as PDFWorker, __webpack_exports__PasswordResponses as PasswordResponses, __webpack_exports__PermissionFlag as PermissionFlag, __webpack_exports__PixelsPerInch as PixelsPerInch, __webpack_exports__RenderingCancelledException as RenderingCancelledException, __webpack_exports__TextLayer as TextLayer, __webpack_exports__UnexpectedResponseException as UnexpectedResponseException, __webpack_exports__Util as Util, __webpack_exports__VerbosityLevel as VerbosityLevel, __webpack_exports__XfaLayer as XfaLayer, __webpack_exports__build as build, __webpack_exports__createValidAbsoluteUrl as createValidAbsoluteUrl, __webpack_exports__fetchData as fetchData, __webpack_exports__getDocument as getDocument, __webpack_exports__getFilenameFromUrl as getFilenameFromUrl, __webpack_exports__getPdfFilenameFromUrl as getPdfFilenameFromUrl, __webpack_exports__getXfaPageViewport as getXfaPageViewport, __webpack_exports__isDataScheme as isDataScheme, __webpack_exports__isPdfFile as isPdfFile, __webpack_exports__noContextMenu as noContextMenu, __webpack_exports__normalizeUnicode as normalizeUnicode, __webpack_exports__renderTextLayer as renderTextLayer, __webpack_exports__setLayerDimensions as setLayerDimensions, __webpack_exports__shadow as shadow, __webpack_exports__updateTextLayer as updateTextLayer, __webpack_exports__version as version };
|
||||
|
||||
//# sourceMappingURL=pdf.mjs.map
|
||||
//# sourceMappingURL=pdf.mjs.map
|
||||
|
@ -170,6 +170,9 @@
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('auto-redact', 'ink_eraser', 'home.autoRedact.title', 'home.autoRedact.desc', 'autoRedact.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('redact', 'ink_eraser', 'home.redact.title', 'home.redact.desc', 'redact.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('stamp', 'approval', 'home.AddStampRequest.title', 'home.AddStampRequest.desc', 'AddStampRequest.tags', 'security')}">
|
||||
</div>
|
||||
|
@ -227,6 +227,9 @@
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='auto-redact', cardTitle=#{home.autoRedact.title}, cardText=#{home.autoRedact.desc}, cardLink='auto-redact', toolIcon='ink_eraser', tags=#{autoRedact.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='redact', cardTitle=#{home.redact.title}, cardText=#{home.redact.desc}, cardLink='redact', toolIcon='ink_eraser', tags=#{redact.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='stamp', cardTitle=#{home.AddStampRequest.title}, cardText=#{home.AddStampRequest.desc}, cardLink='stamp', toolIcon='approval', tags=#{AddStampRequest.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
|
708
src/main/resources/templates/security/redact.html
Normal file
708
src/main/resources/templates/security/redact.html
Normal file
@ -0,0 +1,708 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr" th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
mozdisallowselectionprint xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{redact.title}, header=#{redact.header})}"></th:block>
|
||||
<script th:src="@{'/js/thirdParty/popper.min.js'}"></script>
|
||||
<script th:src="@{'/js/thirdParty/bootstrap.min.js'}"></script>
|
||||
|
||||
<script th:src="@{'/js/thirdParty/jquery.min.js'}"></script>
|
||||
<script th:src="@{'/js/thirdParty/jquery.validate.min.js'}"></script>
|
||||
|
||||
<link rel="stylesheet" th:href="@{'/css/theme/componentes.css'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/navbar.css'}">
|
||||
|
||||
<!-- This snippet is used in production (included from view-pdf.html) -->
|
||||
<link rel="resource" type="application/l10n" th:href="@{'/pdfjs-legacy/locale/locale.json'}">
|
||||
<script th:src="@{'/pdfjs-legacy/pdf.mjs'}" type="module"></script>
|
||||
|
||||
<link rel="stylesheet" th:href="@{'/pdfjs-legacy/css/viewer-redact.css'}">
|
||||
<script th:src="@{'/pdfjs-legacy/js/viewer.mjs'}" type="module"></script>
|
||||
<script src='./js/redact.js' type="module"></script>
|
||||
<link rel="stylesheet" th:href="@{'/css/redact.css'}">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div id="redactionFormContainer" class="container mb-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon security">ink_eraser</span>
|
||||
<span class="tool-header-text" th:text="#{redact.header}"></span>
|
||||
</div>
|
||||
<form th:action="@{'api/v1/security/redact'}" method="post" enctype="multipart/form-data">
|
||||
<div
|
||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, disableMultipleFiles=true, accept='application/pdf')}">
|
||||
</div>
|
||||
<div class="mb-3 form-check d-none">
|
||||
<input type="checkbox" id="convertPDFToImage" name="convertPDFToImage" checked>
|
||||
<label for="convertPDFToImage" th:text="#{redact.convertPDFToImageLabel}"></label>
|
||||
</div>
|
||||
<div class="mb-3 d-none">
|
||||
<label for="pageNumbers" th:text="#{redact.pageRedactionNumbers.title} + ':'" class="mb-2"></label>
|
||||
<input type="text" class="form-control" id="pageNumbers" name="pageNumbers"
|
||||
th:placeholder="#{redact.pageRedactionNumbers.placeholder}">
|
||||
</div>
|
||||
<div class="mb-3 d-none">
|
||||
<label for="pageRedactColor">Page Redaction Color:</label>
|
||||
<input id="pageRedactColor" name="pageRedactionColor" type="color" class="ms-3" value="#000000">
|
||||
</div>
|
||||
<input type="hidden" name="redactions" id="redactions-input">
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary d-none" th:text="#{redact.submit}"></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="pageBasedRedactionOverlay" class="d-none col-md-4 row justify-content-center align-content-center">
|
||||
<div class="bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon security">document_scanner</span>
|
||||
<span class="tool-header-text" th:text="#{redact.pageBasedRedaction}"></span>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="pageNumbers" th:text="#{redact.pageRedactionNumbers.title} + ':'" class="mb-2"></label>
|
||||
<input type="text" class="form-control" data-for="pageNumbers"
|
||||
th:placeholder="#{redact.pageRedactionNumbers.placeholder}">
|
||||
</div>
|
||||
<div class="mb-3 d-flex">
|
||||
<label for="pageRedactColor" th:inline="text" class="pe-none user-select-none">
|
||||
[[#{redact.redactionColor.title}]]
|
||||
<span class="material-symbols-rounded">palette</span>
|
||||
:
|
||||
</label>
|
||||
<input data-for="pageRedactColor" type="color" class="ms-3" value="#000000">
|
||||
</div>
|
||||
<button id="closePageRedactionBtn" class="btn btn-danger" th:text="#{close}"></button>
|
||||
<button id="applyPageRedactionBtn" class="btn btn-success ms-3" th:text="#{apply}"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="outerContainer" class="d-none">
|
||||
<div id="sidebarContainer">
|
||||
<div id="toolbarSidebar">
|
||||
<div id="toolbarSidebarLeft">
|
||||
<div id="sidebarViewButtons" class="splitToolbarButton toggled" role="radiogroup">
|
||||
<button id="viewThumbnail" class="toolbarButton toggled toolbar-btn-hover" title="Show Thumbnails" tabindex="2"
|
||||
data-l10n-id="pdfjs-thumbs-button" role="radio" aria-checked="true" aria-controls="thumbnailView">
|
||||
<span data-l10n-id="pdfjs-thumbs-button-label">Thumbnails</span>
|
||||
</button>
|
||||
<button id="viewOutline" class="toolbarButton toolbar-btn-hover"
|
||||
title="Show Document Outline (double-click to expand/collapse all items)" tabindex="3"
|
||||
data-l10n-id="pdfjs-document-outline-button" role="radio" aria-checked="false"
|
||||
aria-controls="outlineView">
|
||||
<span data-l10n-id="pdfjs-document-outline-button-label">Document Outline</span>
|
||||
</button>
|
||||
<button id="viewAttachments" class="d-none toolbarButton" title="Show Attachments" tabindex="4"
|
||||
data-l10n-id="pdfjs-attachments-button" role="radio" aria-checked="false" aria-controls="attachmentsView">
|
||||
<span data-l10n-id="pdfjs-attachments-button-label">Attachments</span>
|
||||
</button>
|
||||
<button id="viewLayers" class="d-none toolbarButton"
|
||||
title="Show Layers (double-click to reset all layers to the default state)" tabindex="5"
|
||||
data-l10n-id="pdfjs-layers-button" role="radio" aria-checked="false" aria-controls="layersView">
|
||||
<span data-l10n-id="pdfjs-layers-button-label">Layers</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="toolbarSidebarRight">
|
||||
<div id="outlineOptionsContainer">
|
||||
<div class="verticalToolbarSeparator"></div>
|
||||
|
||||
<button id="currentOutlineItem" class="toolbarButton" disabled="disabled" title="Find Current Outline Item"
|
||||
tabindex="6" data-l10n-id="pdfjs-current-outline-item-button">
|
||||
<span data-l10n-id="pdfjs-current-outline-item-button-label">Current Outline Item</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="sidebarContent">
|
||||
<div id="thumbnailView">
|
||||
</div>
|
||||
<div id="outlineView" class="hidden">
|
||||
</div>
|
||||
<div id="attachmentsView" class="hidden">
|
||||
</div>
|
||||
<div id="layersView" class="hidden">
|
||||
</div>
|
||||
</div>
|
||||
<div id="sidebarResizer"></div>
|
||||
</div> <!-- sidebarContainer -->
|
||||
|
||||
<div id="mainContainer">
|
||||
<div class="d-none findbar hidden doorHanger" id="findbar">
|
||||
<div id="findbarInputContainer">
|
||||
<span class="loadingInput end">
|
||||
<input id="findInput" class="toolbarField" title="Find" placeholder="Find in document…" tabindex="91"
|
||||
data-l10n-id="pdfjs-find-input" aria-invalid="false">
|
||||
</span>
|
||||
<div class="splitToolbarButton">
|
||||
<button id="findPrevious" class="toolbarButton" title="Find the previous occurrence of the phrase"
|
||||
tabindex="92" data-l10n-id="pdfjs-find-previous-button">
|
||||
<span data-l10n-id="pdfjs-find-previous-button-label">Previous</span>
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button id="findNext" class="toolbarButton" title="Find the next occurrence of the phrase" tabindex="93"
|
||||
data-l10n-id="pdfjs-find-next-button">
|
||||
<span data-l10n-id="pdfjs-find-next-button-label">Next</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="findbarOptionsOneContainer">
|
||||
<input type="checkbox" id="findHighlightAll" class="toolbarField" tabindex="94">
|
||||
<label for="findHighlightAll" class="toolbarLabel" data-l10n-id="pdfjs-find-highlight-checkbox">Highlight
|
||||
All</label>
|
||||
<input type="checkbox" id="findMatchCase" class="toolbarField" tabindex="95">
|
||||
<label for="findMatchCase" class="toolbarLabel" data-l10n-id="pdfjs-find-match-case-checkbox-label">Match
|
||||
Case</label>
|
||||
</div>
|
||||
<div id="findbarOptionsTwoContainer">
|
||||
<input type="checkbox" id="findMatchDiacritics" class="toolbarField" tabindex="96">
|
||||
<label for="findMatchDiacritics" class="toolbarLabel"
|
||||
data-l10n-id="pdfjs-find-match-diacritics-checkbox-label">Match Diacritics</label>
|
||||
<input type="checkbox" id="findEntireWord" class="toolbarField" tabindex="97">
|
||||
<label for="findEntireWord" class="toolbarLabel" data-l10n-id="pdfjs-find-entire-word-checkbox-label">Whole
|
||||
Words</label>
|
||||
</div>
|
||||
|
||||
<div id="findbarMessageContainer" aria-live="polite">
|
||||
<span id="findResultsCount" class="toolbarLabel"></span>
|
||||
<span id="findMsg" class="toolbarLabel"></span>
|
||||
</div>
|
||||
</div> <!-- findbar -->
|
||||
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorHighlightParamsToolbar">
|
||||
<div id="highlightParamsToolbarContainer" class="editorParamsToolbarContainer">
|
||||
<div id="editorHighlightColorPicker" class="colorPicker">
|
||||
<span id="highlightColorPickerLabel" class="editorParamsLabel"
|
||||
data-l10n-id="pdfjs-editor-highlight-colorpicker-label">Highlight color</span>
|
||||
</div>
|
||||
<div id="editorHighlightThickness">
|
||||
<label for="editorFreeHighlightThickness" class="editorParamsLabel"
|
||||
data-l10n-id="pdfjs-editor-free-highlight-thickness-input">Thickness</label>
|
||||
<div class="thicknessPicker">
|
||||
<input type="range" id="editorFreeHighlightThickness" class="editorParamsSlider"
|
||||
data-l10n-id="pdfjs-editor-free-highlight-thickness-title" value="12" min="8" max="24" step="1"
|
||||
tabindex="101">
|
||||
</div>
|
||||
</div>
|
||||
<div id="editorHighlightVisibility">
|
||||
<div class="divider"></div>
|
||||
<div class="toggler">
|
||||
<label for="editorHighlightShowAll" class="editorParamsLabel"
|
||||
data-l10n-id="pdfjs-editor-highlight-show-all-button-label">Show all</label>
|
||||
<button id="editorHighlightShowAll" class="toggle-button"
|
||||
data-l10n-id="pdfjs-editor-highlight-show-all-button" aria-pressed="true" tabindex="102"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorFreeTextParamsToolbar">
|
||||
<div class="editorParamsToolbarContainer">
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorFreeTextColor" class="editorParamsLabel"
|
||||
data-l10n-id="pdfjs-editor-free-text-color-input">Color</label>
|
||||
<input type="color" id="editorFreeTextColor" class="editorParamsColor" tabindex="103">
|
||||
</div>
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorFreeTextFontSize" class="editorParamsLabel"
|
||||
data-l10n-id="pdfjs-editor-free-text-size-input">Size</label>
|
||||
<input type="range" id="editorFreeTextFontSize" class="editorParamsSlider" value="10" min="5" max="100"
|
||||
step="1" tabindex="104">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorInkParamsToolbar">
|
||||
<div class="editorParamsToolbarContainer">
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorInkColor" class="editorParamsLabel"
|
||||
data-l10n-id="pdfjs-editor-ink-color-input">Color</label>
|
||||
<input type="color" id="editorInkColor" class="editorParamsColor" tabindex="105">
|
||||
</div>
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorInkThickness" class="editorParamsLabel"
|
||||
data-l10n-id="pdfjs-editor-ink-thickness-input">Thickness</label>
|
||||
<input type="range" id="editorInkThickness" class="editorParamsSlider" value="1" min="1" max="20" step="1"
|
||||
tabindex="106">
|
||||
</div>
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorInkOpacity" class="editorParamsLabel"
|
||||
data-l10n-id="pdfjs-editor-ink-opacity-input">Opacity</label>
|
||||
<input type="range" id="editorInkOpacity" class="editorParamsSlider" value="100" min="1" max="100" step="1"
|
||||
tabindex="107">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorStampParamsToolbar">
|
||||
<div class="editorParamsToolbarContainer">
|
||||
<button id="editorStampAddImage" class="secondaryToolbarButton" title="Add image" tabindex="108"
|
||||
data-l10n-id="pdfjs-editor-stamp-add-image-button">
|
||||
<span class="editorParamsLabel" data-l10n-id="pdfjs-editor-stamp-add-image-button-label">Add
|
||||
image</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="secondaryToolbar" class="secondaryToolbar hidden doorHangerRight">
|
||||
<div id="secondaryToolbarButtonContainer">
|
||||
<button id="secondaryOpenFile" class="secondaryToolbarButton visibleMediumView" title="Open File"
|
||||
tabindex="51" data-l10n-id="pdfjs-open-file-button">
|
||||
<span data-l10n-id="pdfjs-open-file-button-label">Open</span>
|
||||
</button>
|
||||
|
||||
<button id="secondaryPrint" class="secondaryToolbarButton visibleMediumView" title="Print" tabindex="52"
|
||||
data-l10n-id="pdfjs-print-button">
|
||||
<span data-l10n-id="pdfjs-print-button-label">Print</span>
|
||||
</button>
|
||||
|
||||
<button id="secondaryDownload" class="secondaryToolbarButton visibleMediumView" title="Save" tabindex="53"
|
||||
data-l10n-id="pdfjs-save-button">
|
||||
<span data-l10n-id="pdfjs-save-button-label">Save</span>
|
||||
</button>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="presentationMode" class="secondaryToolbarButton" title="Switch to Presentation Mode" tabindex="54"
|
||||
data-l10n-id="pdfjs-presentation-mode-button">
|
||||
<span data-l10n-id="pdfjs-presentation-mode-button-label">Presentation Mode</span>
|
||||
</button>
|
||||
|
||||
<a href="#" id="viewBookmark" class="secondaryToolbarButton" title="Current Page (View URL from Current Page)"
|
||||
tabindex="55" data-l10n-id="pdfjs-bookmark-button">
|
||||
<span data-l10n-id="pdfjs-bookmark-button-label">Current Page</span>
|
||||
</a>
|
||||
|
||||
<div id="viewBookmarkSeparator" class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="firstPage" class="secondaryToolbarButton" title="Go to First Page" tabindex="56"
|
||||
data-l10n-id="pdfjs-first-page-button">
|
||||
<span data-l10n-id="pdfjs-first-page-button-label">Go to First Page</span>
|
||||
</button>
|
||||
<button id="lastPage" class="secondaryToolbarButton" title="Go to Last Page" tabindex="57"
|
||||
data-l10n-id="pdfjs-last-page-button">
|
||||
<span data-l10n-id="pdfjs-last-page-button-label">Go to Last Page</span>
|
||||
</button>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="pageRotateCw" class="secondaryToolbarButton" title="Rotate Clockwise" tabindex="58"
|
||||
data-l10n-id="pdfjs-page-rotate-cw-button">
|
||||
<span data-l10n-id="pdfjs-page-rotate-cw-button-label">Rotate Clockwise</span>
|
||||
</button>
|
||||
<button id="pageRotateCcw" class="secondaryToolbarButton" title="Rotate Counterclockwise" tabindex="59"
|
||||
data-l10n-id="pdfjs-page-rotate-ccw-button">
|
||||
<span data-l10n-id="pdfjs-page-rotate-ccw-button-label">Rotate Counterclockwise</span>
|
||||
</button>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<div id="cursorToolButtons" role="radiogroup">
|
||||
<button id="cursorSelectTool" class="secondaryToolbarButton toggled" title="Enable Text Selection Tool"
|
||||
tabindex="60" data-l10n-id="pdfjs-cursor-text-select-tool-button" role="radio" aria-checked="true">
|
||||
<span data-l10n-id="pdfjs-cursor-text-select-tool-button-label">Text Selection Tool</span>
|
||||
</button>
|
||||
<button id="cursorHandTool" class="secondaryToolbarButton" title="Enable Hand Tool" tabindex="61"
|
||||
data-l10n-id="pdfjs-cursor-hand-tool-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-cursor-hand-tool-button-label">Hand Tool</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<div id="scrollModeButtons" role="radiogroup">
|
||||
<button id="scrollPage" class="secondaryToolbarButton" title="Use Page Scrolling" tabindex="62"
|
||||
data-l10n-id="pdfjs-scroll-page-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-scroll-page-button-label">Page Scrolling</span>
|
||||
</button>
|
||||
<button id="scrollVertical" class="secondaryToolbarButton toggled" title="Use Vertical Scrolling"
|
||||
tabindex="63" data-l10n-id="pdfjs-scroll-vertical-button" role="radio" aria-checked="true">
|
||||
<span data-l10n-id="pdfjs-scroll-vertical-button-label">Vertical Scrolling</span>
|
||||
</button>
|
||||
<button id="scrollHorizontal" class="secondaryToolbarButton" title="Use Horizontal Scrolling" tabindex="64"
|
||||
data-l10n-id="pdfjs-scroll-horizontal-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-scroll-horizontal-button-label">Horizontal Scrolling</span>
|
||||
</button>
|
||||
<button id="scrollWrapped" class="secondaryToolbarButton" title="Use Wrapped Scrolling" tabindex="65"
|
||||
data-l10n-id="pdfjs-scroll-wrapped-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-scroll-wrapped-button-label">Wrapped Scrolling</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<div id="spreadModeButtons" role="radiogroup">
|
||||
<button id="spreadNone" class="secondaryToolbarButton toggled" title="Do not join page spreads"
|
||||
tabindex="66" data-l10n-id="pdfjs-spread-none-button" role="radio" aria-checked="true">
|
||||
<span data-l10n-id="pdfjs-spread-none-button-label">No Spreads</span>
|
||||
</button>
|
||||
<button id="spreadOdd" class="secondaryToolbarButton"
|
||||
title="Join page spreads starting with odd-numbered pages" tabindex="67"
|
||||
data-l10n-id="pdfjs-spread-odd-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-spread-odd-button-label">Odd Spreads</span>
|
||||
</button>
|
||||
<button id="spreadEven" class="secondaryToolbarButton"
|
||||
title="Join page spreads starting with even-numbered pages" tabindex="68"
|
||||
data-l10n-id="pdfjs-spread-even-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-spread-even-button-label">Even Spreads</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="documentProperties" class="secondaryToolbarButton" title="Document Properties…" tabindex="69"
|
||||
data-l10n-id="pdfjs-document-properties-button" aria-controls="documentPropertiesDialog">
|
||||
<span data-l10n-id="pdfjs-document-properties-button-label">Document Properties…</span>
|
||||
</button>
|
||||
</div>
|
||||
</div> <!-- secondaryToolbar -->
|
||||
|
||||
<div class="toolbar">
|
||||
<div id="toolbarContainer">
|
||||
<div id="toolbarViewer">
|
||||
<div id="toolbarViewerLeft">
|
||||
<div id="showMoreBtnContainer" class="splitToolbarButton">
|
||||
<button id="showMoreBtn" class="btn-primary">
|
||||
<span id="showMoreBtnIcon" class="material-symbols-rounded">more_horiz</span>
|
||||
</button>
|
||||
</div>
|
||||
<button id="sidebarToggle" class="toolbarButton mt-2" title="Toggle Sidebar" tabindex="11"
|
||||
data-l10n-id="pdfjs-toggle-sidebar-button" aria-expanded="false" aria-controls="sidebarContainer">
|
||||
<span data-l10n-id="pdfjs-toggle-sidebar-button-label">Toggle Sidebar</span>
|
||||
</button>
|
||||
<div class="toolbarButtonSpacer d-none"></div>
|
||||
<button id="viewFind" class="d-none toolbarButton" title="Find in Document" tabindex="12"
|
||||
data-l10n-id="pdfjs-findbar-button" aria-expanded="false" aria-controls="findbar">
|
||||
<span data-l10n-id="pdfjs-findbar-button-label">Find</span>
|
||||
</button>
|
||||
<div class="splitToolbarButton hiddenSmallView">
|
||||
<button class="toolbarButton btn-secondary toolbar-btn-hover" title="Previous Page" id="previous" tabindex="13"
|
||||
data-l10n-id="pdfjs-previous-button">
|
||||
<span data-l10n-id="pdfjs-previous-button-label">Previous</span>
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator d-none"></div>
|
||||
<button class="toolbarButton btn-secondary toolbar-btn-hover" title="Next Page" id="next" tabindex="14"
|
||||
data-l10n-id="pdfjs-next-button">
|
||||
<span data-l10n-id="pdfjs-next-button-label">Next</span>
|
||||
</button>
|
||||
</div>
|
||||
<span class="loadingInput start">
|
||||
<input type="number" id="pageNumber" class="toolbarField" title="Page" value="1" min="1" tabindex="15"
|
||||
data-l10n-id="pdfjs-page-input" autocomplete="off">
|
||||
</span>
|
||||
<span id="numPages" class="toolbarLabel"></span>
|
||||
<img class="main-icon user-select-none" th:src="@{'/favicon.svg'}" alt="icon">
|
||||
</div>
|
||||
<div id="toolbarViewerMiddle">
|
||||
<div class="splitToolbarButton">
|
||||
<button id="zoomOut" class="toolbarButton btn-primary toolbar-btn-hover" title="Zoom Out" tabindex="21"
|
||||
data-l10n-id="pdfjs-zoom-out-button">
|
||||
<span data-l10n-id="pdfjs-zoom-out-button-label">Zoom Out</span>
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button id="zoomIn" class="toolbarButton btn-primary toolbar-btn-hover" title="Zoom In" tabindex="22"
|
||||
data-l10n-id="pdfjs-zoom-in-button">
|
||||
<span data-l10n-id="pdfjs-zoom-in-button-label">Zoom In</span>
|
||||
</button>
|
||||
</div>
|
||||
<span id="scaleSelectContainer" class="dropdownToolbarButton">
|
||||
<select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="pdfjs-zoom-select">
|
||||
<option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="pdfjs-page-scale-auto">
|
||||
Automatic Zoom</option>
|
||||
<option id="pageActualOption" title="" value="page-actual" data-l10n-id="pdfjs-page-scale-actual">
|
||||
Actual Size</option>
|
||||
<option id="pageFitOption" title="" value="page-fit" data-l10n-id="pdfjs-page-scale-fit">Page
|
||||
Fit
|
||||
</option>
|
||||
<option id="pageWidthOption" title="" value="page-width" data-l10n-id="pdfjs-page-scale-width">
|
||||
Page Width</option>
|
||||
<option id="customScaleOption" title="" value="custom" disabled="disabled" hidden="true"
|
||||
data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 0 }'>0%</option>
|
||||
<option title="" value="0.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 50 }'>
|
||||
50%</option>
|
||||
<option title="" value="0.75" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 75 }'>75%
|
||||
</option>
|
||||
<option title="" value="1" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 100 }'>
|
||||
100%</option>
|
||||
<option title="" value="1.25" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 125 }'>125%
|
||||
</option>
|
||||
<option title="" value="1.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 150 }'>150%
|
||||
</option>
|
||||
<option title="" value="2" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 200 }'>
|
||||
200%</option>
|
||||
<option title="" value="3" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 300 }'>
|
||||
300%</option>
|
||||
<option title="" value="4" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 400 }'>
|
||||
400%</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
<div id="redactionsToolbarViewer" class="splitToolbarButton d-flex">
|
||||
<button id="man-text-select-redact" class="btn-primary" title="Text-based selection redaction" tabindex="22">
|
||||
<span id="text-selection" class="material-symbols-rounded user-select-none pe-none">text_select_start
|
||||
</span>
|
||||
</button>
|
||||
<button id="man-shape-redact" class="btn-primary" title="Shape drawing redaction" tabindex="22">
|
||||
<span id="shape-selection" class="material-symbols-rounded user-select-none pe-none">pageless
|
||||
</span>
|
||||
</button>
|
||||
<button id="redactionsPaletteContainer" class="btn-primary">
|
||||
<label id="redactions-palette" class="material-symbols-rounded palette-color text-center"
|
||||
style="--palette-color: #000000;">
|
||||
palette
|
||||
<input type="color" name="color-picker">
|
||||
</label>
|
||||
</button>
|
||||
<button id="apply-redaction" title="Apply changes" class="btn-success d-none" disabled>
|
||||
<span id="apply-redaction-icon" class="material-symbols-rounded">
|
||||
check
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="toolbarViewerRight">
|
||||
<div class="splitToolbarButton">
|
||||
<button id="pdfToImageBtn" th:title="#{redact.convertPDFToImageLabel}" class="btn-success">
|
||||
<span id="pdfToImageBtnIcon" class="material-symbols-rounded">
|
||||
image
|
||||
</span>
|
||||
</button>
|
||||
<button id="pageBasedRedactionBtn" th:title="#{redact.pageBasedRedaction}" class="btn-primary">
|
||||
<span id="pageBasedRedactionBtnIcon" class="material-symbols-rounded">
|
||||
document_scanner
|
||||
</span>
|
||||
</button>
|
||||
<button id="uploadBtn" title="Upload" class="btn-primary">
|
||||
<span id="uploadBtnIcon" class="material-symbols-rounded">
|
||||
upload
|
||||
</span>
|
||||
</button>
|
||||
<button id="downloadBtn" title="Submit" class="btn-primary">
|
||||
<span id="downloadBtnIcon" class="material-symbols-rounded">
|
||||
download
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="editorModeButtons" class="splitToolbarButton toggled" role="radiogroup">
|
||||
<button id="editorHighlight" class="toolbarButton" hidden="true" disabled="disabled" title="Highlight"
|
||||
role="radio" aria-checked="false" aria-controls="editorHighlightParamsToolbar" tabindex="31"
|
||||
data-l10n-id="pdfjs-editor-highlight-button">
|
||||
<span data-l10n-id="pdfjs-editor-highlight-button-label">Highlight</span>
|
||||
</button>
|
||||
<button id="openFile" class="toolbarButton hiddenMediumView d-none" title="Open File" role="radio"
|
||||
aria-checked="false" tabindex="33" data-l10n-id="pdfjs-open-file-button">
|
||||
<span data-l10n-id="pdfjs-open-file-button-label">Open</span>
|
||||
</button>
|
||||
<button id="print" class="d-none toolbarButton hiddenMediumView d-none" title="Print" role="radio"
|
||||
aria-checked="false" tabindex="34" data-l10n-id="pdfjs-print-button">
|
||||
<span data-l10n-id="pdfjs-print-button-label">Print</span>
|
||||
</button>
|
||||
<button id="download" class="d-none toolbarButton hiddenMediumView d-none" title="Save" role="radio"
|
||||
aria-checked="false" tabindex="35" data-l10n-id="pdfjs-save-button">
|
||||
<span data-l10n-id="pdfjs-save-button-label">Save</span>
|
||||
</button>
|
||||
<button id="editorStamp" class="d-none toolbarButton hiddenMediumView d-none" title="Add or edit images"
|
||||
role="radio" aria-checked="false" aria-controls="editorStampParamsToolbar" tabindex="36"
|
||||
data-l10n-id="pdfjs-editor-stamp-button">
|
||||
<span data-l10n-id="pdfjs-editor-stamp-button-label">Add or edit images</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="editorModeSeparator" class="d-none verticalToolbarSeparator"></div>
|
||||
|
||||
<button id="editorFreeText" class="d-none toolbarButton hiddenMediumView" title="Text" tabindex="41"
|
||||
data-l10n-id="pdfjs-editor-free-text-button">
|
||||
<span data-l10n-id="pdfjs-editor-free-text-button-label">Text</span>
|
||||
</button>
|
||||
|
||||
<button id="editorInk" class="d-none toolbarButton hiddenMediumView" title="Draw" tabindex="42"
|
||||
data-l10n-id="pdfjs-editor-ink-button">
|
||||
<span data-l10n-id="pdfjs-editor-ink-button-label">Draw</span>
|
||||
</button>
|
||||
|
||||
<div class="verticalToolbarSeparator hiddenMediumView"></div>
|
||||
|
||||
<button id="secondaryToolbarToggle" class="toolbarButton d-none" title="Tools" tabindex="43"
|
||||
data-l10n-id="pdfjs-tools-button">
|
||||
<span data-l10n-id="pdfjs-tools-button-label">Tools</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loadingBar">
|
||||
<div class="progress">
|
||||
<div class="glimmer">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="viewerContainer" tabindex="0">
|
||||
<div id="viewer" class="pdfViewer"></div>
|
||||
</div>
|
||||
</div> <!-- mainContainer -->
|
||||
|
||||
<div id="dialogContainer">
|
||||
<dialog id="passwordDialog">
|
||||
<div class="row">
|
||||
<label for="password" id="passwordText" data-l10n-id="pdfjs-password-label">Enter the password to open
|
||||
this PDF file:</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<input type="password" id="password" class="toolbarField">
|
||||
</div>
|
||||
<div class="buttonRow">
|
||||
<button id="passwordCancel" class="dialogButton"><span
|
||||
data-l10n-id="pdfjs-password-cancel-button">Cancel</span></button>
|
||||
<button id="passwordSubmit" class="dialogButton"><span
|
||||
data-l10n-id="pdfjs-password-ok-button">OK</span></button>
|
||||
</div>
|
||||
</dialog>
|
||||
<dialog id="documentPropertiesDialog">
|
||||
<div class="row">
|
||||
<span id="fileNameLabel" data-l10n-id="pdfjs-document-properties-file-name">File name:</span>
|
||||
<p id="fileNameField" aria-labelledby="fileNameLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="fileSizeLabel" data-l10n-id="pdfjs-document-properties-file-size">File size:</span>
|
||||
<p id="fileSizeField" aria-labelledby="fileSizeLabel">-</p>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="row">
|
||||
<span id="titleLabel" data-l10n-id="pdfjs-document-properties-title">Title:</span>
|
||||
<p id="titleField" aria-labelledby="titleLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="authorLabel" data-l10n-id="pdfjs-document-properties-author">Author:</span>
|
||||
<p id="authorField" aria-labelledby="authorLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="subjectLabel" data-l10n-id="pdfjs-document-properties-subject">Subject:</span>
|
||||
<p id="subjectField" aria-labelledby="subjectLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="keywordsLabel" data-l10n-id="pdfjs-document-properties-keywords">Keywords:</span>
|
||||
<p id="keywordsField" aria-labelledby="keywordsLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="creationDateLabel" data-l10n-id="pdfjs-document-properties-creation-date">Creation
|
||||
Date:</span>
|
||||
<p id="creationDateField" aria-labelledby="creationDateLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="modificationDateLabel" data-l10n-id="pdfjs-document-properties-modification-date">Modification
|
||||
Date:</span>
|
||||
<p id="modificationDateField" aria-labelledby="modificationDateLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="creatorLabel" data-l10n-id="pdfjs-document-properties-creator">Creator:</span>
|
||||
<p id="creatorField" aria-labelledby="creatorLabel">-</p>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="row">
|
||||
<span id="producerLabel" data-l10n-id="pdfjs-document-properties-producer">PDF Producer:</span>
|
||||
<p id="producerField" aria-labelledby="producerLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="versionLabel" data-l10n-id="pdfjs-document-properties-version">PDF Version:</span>
|
||||
<p id="versionField" aria-labelledby="versionLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="pageCountLabel" data-l10n-id="pdfjs-document-properties-page-count">Page Count:</span>
|
||||
<p id="pageCountField" aria-labelledby="pageCountLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="pageSizeLabel" data-l10n-id="pdfjs-document-properties-page-size">Page Size:</span>
|
||||
<p id="pageSizeField" aria-labelledby="pageSizeLabel">-</p>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="row">
|
||||
<span id="linearizedLabel" data-l10n-id="pdfjs-document-properties-linearized">Fast Web View:</span>
|
||||
<p id="linearizedField" aria-labelledby="linearizedLabel">-</p>
|
||||
</div>
|
||||
<div class="buttonRow">
|
||||
<button id="documentPropertiesClose" class="dialogButton"><span
|
||||
data-l10n-id="pdfjs-document-properties-close-button">Close</span></button>
|
||||
</div>
|
||||
</dialog>
|
||||
<dialog class="dialog altText" id="altTextDialog" aria-labelledby="dialogLabel"
|
||||
aria-describedby="dialogDescription">
|
||||
<div id="altTextContainer" class="mainContainer">
|
||||
<div id="overallDescription">
|
||||
<span id="dialogLabel" data-l10n-id="pdfjs-editor-alt-text-dialog-label" class="title">Choose an
|
||||
option</span>
|
||||
<span id="dialogDescription" data-l10n-id="pdfjs-editor-alt-text-dialog-description">
|
||||
Alt text (alternative text) helps when people can’t see the image or when it doesn’t load.
|
||||
</span>
|
||||
</div>
|
||||
<div id="addDescription">
|
||||
<div class="radio">
|
||||
<div class="radioButton">
|
||||
<input type="radio" id="descriptionButton" name="altTextOption" tabindex="0"
|
||||
aria-describedby="descriptionAreaLabel" checked>
|
||||
<label for="descriptionButton" data-l10n-id="pdfjs-editor-alt-text-add-description-label">Add a
|
||||
description</label>
|
||||
</div>
|
||||
<div class="radioLabel">
|
||||
<span id="descriptionAreaLabel" data-l10n-id="pdfjs-editor-alt-text-add-description-description">
|
||||
Aim for 1-2 sentences that describe the subject, setting, or actions.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="descriptionArea">
|
||||
<textarea id="descriptionTextarea"
|
||||
placeholder="For example, “A young man sits down at a table to eat a meal”"
|
||||
aria-labelledby="descriptionAreaLabel" data-l10n-id="pdfjs-editor-alt-text-textarea"
|
||||
tabindex="0"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div id="markAsDecorative">
|
||||
<div class="radio">
|
||||
<div class="radioButton">
|
||||
<input type="radio" id="decorativeButton" name="altTextOption" aria-describedby="decorativeLabel">
|
||||
<label for="decorativeButton" data-l10n-id="pdfjs-editor-alt-text-mark-decorative-label">Mark as
|
||||
decorative</label>
|
||||
</div>
|
||||
<div class="radioLabel">
|
||||
<span id="decorativeLabel" data-l10n-id="pdfjs-editor-alt-text-mark-decorative-description">
|
||||
This is used for ornamental images, like borders or watermarks.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="buttons">
|
||||
<button id="altTextCancel" class="secondaryButton" tabindex="0"><span
|
||||
data-l10n-id="pdfjs-editor-alt-text-cancel-button">Cancel</span></button>
|
||||
<button id="altTextSave" class="primaryButton" tabindex="0"><span
|
||||
data-l10n-id="pdfjs-editor-alt-text-save-button">Save</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
<dialog id="printServiceDialog" style="min-width: 200px;">
|
||||
<div class="row">
|
||||
<span data-l10n-id="pdfjs-print-progress-message">Preparing document for printing…</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<progress value="0" max="100"></progress>
|
||||
<span data-l10n-id="pdfjs-print-progress-percent" data-l10n-args='{ "progress": 0 }'
|
||||
class="relative-progress">0%</span>
|
||||
</div>
|
||||
<div class="buttonRow">
|
||||
<button id="printCancel" class="dialogButton"><span
|
||||
data-l10n-id="pdfjs-print-progress-close-button">Cancel</span></button>
|
||||
</div>
|
||||
</dialog>
|
||||
</div> <!-- dialogContainer -->
|
||||
|
||||
</div> <!-- outerContainer -->
|
||||
<div id="printContainer" class="d-none"></div>
|
||||
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user