2023-04-18 05:08:38 +03:00
|
|
|
<!DOCTYPE html>
|
2024-05-05 15:19:53 +04:00
|
|
|
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
2024-05-22 21:48:23 +01:00
|
|
|
xmlns:th="https://www.thymeleaf.org">
|
2024-05-05 15:19:53 +04:00
|
|
|
|
|
|
|
<head>
|
2024-02-16 22:49:06 +01:00
|
|
|
<th:block th:insert="~{fragments/common :: head(title=#{multiTool.title}, header=#{multiTool.header})}"></th:block>
|
2024-05-05 15:19:53 +04:00
|
|
|
</head>
|
2023-04-18 05:08:38 +03:00
|
|
|
|
2024-05-05 15:19:53 +04:00
|
|
|
<body>
|
|
|
|
<div id="image-highlighter"></div>
|
|
|
|
<div id="page-container">
|
|
|
|
<div id="content-wrap">
|
|
|
|
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
|
|
|
<br><br>
|
|
|
|
<div class="container">
|
|
|
|
<div class="row justify-content-center">
|
2025-03-20 00:06:47 +00:00
|
|
|
|
2024-05-05 15:19:53 +04:00
|
|
|
<div class="col-md-12">
|
2024-05-19 12:44:54 +02:00
|
|
|
<div class="bg-card">
|
2024-05-05 15:19:53 +04:00
|
|
|
<div class="tool-header">
|
|
|
|
<span class="material-symbols-rounded tool-header-icon advance">construction</span>
|
|
|
|
<span class="tool-header-text" th:text="#{multiTool.header}"></span>
|
2024-02-16 22:49:06 +01:00
|
|
|
</div>
|
2025-03-20 00:06:47 +00:00
|
|
|
<div class="mt-action-bar d-flex flex-wrap">
|
|
|
|
<div class="mt-filename">
|
|
|
|
<input type="text" class="form-control" id="filename-input"
|
|
|
|
th:placeholder="#{multiTool.uploadPrompts}">
|
|
|
|
</div>
|
|
|
|
<div class="mt-file-uploader">
|
|
|
|
<div
|
|
|
|
th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multipleInputsForSingleRequest=false, accept='image/*, application/pdf', showUploads=false)}">
|
2024-05-05 15:19:53 +04:00
|
|
|
</div>
|
2025-03-20 00:06:47 +00:00
|
|
|
</div>
|
2024-11-28 16:25:13 +02:00
|
|
|
|
2025-03-20 00:06:47 +00:00
|
|
|
<div id="selected-pages-display" class="selected-pages-container hidden">
|
|
|
|
<div style="display:flex; height:3rem; margin-right:1rem">
|
|
|
|
<h5 th:text="#{multiTool.selectedPages}" style="white-space: nowrap; margin-right: 1rem;">Selected
|
|
|
|
Pages</h5>
|
|
|
|
<input type="text" id="csv-input" class="form-control" style="height:2.5rem" placeholder="1,3,5-10"
|
|
|
|
value="">
|
2024-11-14 20:00:36 +00:00
|
|
|
</div>
|
2025-03-20 00:06:47 +00:00
|
|
|
<ul id="selected-pages-list" class="pages-list"></ul>
|
2024-02-16 22:49:06 +01:00
|
|
|
</div>
|
2025-03-20 00:06:47 +00:00
|
|
|
</div>
|
|
|
|
|
2024-05-05 15:19:53 +04:00
|
|
|
<div class="multi-tool-container">
|
|
|
|
<div class="d-flex flex-wrap" id="pages-container-wrapper">
|
|
|
|
<div id="pages-container">
|
|
|
|
</div>
|
|
|
|
</div>
|
2024-02-16 22:49:06 +01:00
|
|
|
</div>
|
2025-03-20 00:06:47 +00:00
|
|
|
|
|
|
|
<div class="mt-action-btn">
|
|
|
|
<button id="undo-btn" th:title="#{multiTool.undo}" class="btn btn-secondary" onclick="undo()"
|
|
|
|
disabled>
|
|
|
|
<span class="material-symbols-rounded">
|
|
|
|
undo
|
|
|
|
</span>
|
|
|
|
</button>
|
|
|
|
<button id="redo-btn" class="btn btn-secondary" th:title="#{multiTool.redo}" onclick="redo()"
|
|
|
|
disabled>
|
|
|
|
<span class="material-symbols-rounded">
|
|
|
|
redo
|
|
|
|
</span>
|
|
|
|
</button>
|
|
|
|
<button class="btn btn-secondary enable-on-file" th:title="#{multiTool.rotateLeft}"
|
|
|
|
onclick="rotateAll(-90)" disabled>
|
|
|
|
<span class="material-symbols-rounded">
|
|
|
|
rotate_left
|
|
|
|
</span>
|
|
|
|
</button>
|
|
|
|
<button class="btn btn-secondary enable-on-file" th:title="#{multiTool.rotateRight}"
|
|
|
|
onclick="rotateAll(90)" disabled>
|
|
|
|
<span class="material-symbols-rounded">
|
|
|
|
rotate_right
|
|
|
|
</span>
|
|
|
|
</button>
|
|
|
|
<button class="btn btn-secondary enable-on-file" th:title="#{multiTool.split}" onclick="splitAll()"
|
|
|
|
disabled>
|
|
|
|
<span class="material-symbols-rounded">
|
|
|
|
cut
|
|
|
|
</span>
|
|
|
|
</button>
|
|
|
|
<button class="btn btn-secondary enable-on-file" th:title="#{multiTool.insertPageBreak}"
|
|
|
|
onclick="addFilesBlankAll()" disabled>
|
|
|
|
<span class="material-symbols-rounded">
|
|
|
|
insert_page_break
|
|
|
|
</span>
|
|
|
|
</button>
|
|
|
|
<button id="select-pages-container" th:title="#{multiTool.selectPages}"
|
|
|
|
class="btn btn-secondary enable-on-file" onclick="toggleSelectPageVisibility()" disabled>
|
|
|
|
<span id="select-pages-button" class="material-symbols-rounded">
|
|
|
|
event_list
|
|
|
|
</span>
|
|
|
|
</button>
|
|
|
|
<button id="deselect-All-Container" th:title="#{multiTool.deselectAll}"
|
Multi tool select buttons bug (#3404)
# Description of Changes
Changes:
- In the multitool page, the behavior of the "Select/Deselect All"
buttons was changed so that if no pages are selected, then the "Deselect
All" button is disabled, and if all pages are selected, then the "Select
All" button is disabled.
- These buttons will also appear if the "Page Select" is turned on,
either by pressing the "Page Select" button or manually selecting one
page.
- Furthermore, a bug that caused the pages to remain selected when "Page
Select" is off was also fixed
Why the changes were made:
- The multitool did not allow the "Select All" or "Deselect All" button
to appear simultaneously. The multitool was relying on a toggle mechanic
for the Page Selection and this could prevent the user from selecting or
deselecting all pages as intended, if they manually select/deselect one
or more pages.
Other challenges:
- No particular challenges encountered
Relevant Screenshots:

*Fig. 1 - Only "Select All" button appears when Page Select is turned
on, since no pages are selected*

*Fig. 2 - Both "Select All" and "Deselect All" buttons appear when one
or more, but not all pages are selected*

*Fig. 3 - Only "Deselect All" button appears when all pages are
selected*

*Fig. 4 - When Page Select is turned off, both "Select All" and
"Deselect All" buttons disappear and all pages are deselected*
Closes #3206
---
## Checklist
### General
- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] 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)
### UI Changes (if applicable)
- [x] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.
2025-04-28 22:44:51 +01:00
|
|
|
class="btn btn-secondary enable-on-file hidden" onclick="deselectAll()" disabled>
|
2025-03-20 00:06:47 +00:00
|
|
|
<span class="material-symbols-rounded" id="deselect-icon">deselect</span>
|
|
|
|
</button>
|
|
|
|
<button id="select-All-Container" th:title="#{multiTool.selectAll}"
|
Multi tool select buttons bug (#3404)
# Description of Changes
Changes:
- In the multitool page, the behavior of the "Select/Deselect All"
buttons was changed so that if no pages are selected, then the "Deselect
All" button is disabled, and if all pages are selected, then the "Select
All" button is disabled.
- These buttons will also appear if the "Page Select" is turned on,
either by pressing the "Page Select" button or manually selecting one
page.
- Furthermore, a bug that caused the pages to remain selected when "Page
Select" is off was also fixed
Why the changes were made:
- The multitool did not allow the "Select All" or "Deselect All" button
to appear simultaneously. The multitool was relying on a toggle mechanic
for the Page Selection and this could prevent the user from selecting or
deselecting all pages as intended, if they manually select/deselect one
or more pages.
Other challenges:
- No particular challenges encountered
Relevant Screenshots:

*Fig. 1 - Only "Select All" button appears when Page Select is turned
on, since no pages are selected*

*Fig. 2 - Both "Select All" and "Deselect All" buttons appear when one
or more, but not all pages are selected*

*Fig. 3 - Only "Deselect All" button appears when all pages are
selected*

*Fig. 4 - When Page Select is turned off, both "Select All" and
"Deselect All" buttons disappear and all pages are deselected*
Closes #3206
---
## Checklist
### General
- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] 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)
### UI Changes (if applicable)
- [x] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.
2025-04-28 22:44:51 +01:00
|
|
|
class="btn btn-secondary enable-on-file hidden" onclick="selectAll()" disabled>
|
2025-03-20 00:06:47 +00:00
|
|
|
<span class="material-symbols-rounded" id="select-icon">select_all</span>
|
|
|
|
</button>
|
|
|
|
<button id="delete-button" th:title="#{multiTool.deleteSelected}"
|
|
|
|
class="btn btn-danger delete hidden" onclick="deleteSelected()">
|
|
|
|
<span class="material-symbols-rounded">delete</span>
|
|
|
|
</button>
|
|
|
|
<button id="export-selected-button" th:title="#{multiTool.downloadSelected}"
|
|
|
|
style="border-color: green; color:#b2e3a8; background: rgba(24, 122, 5, 1)"
|
|
|
|
class="btn btn-primary enable-on-file hidden" onclick="exportPdf(true)" disabled>
|
|
|
|
<span class="material-symbols-rounded">
|
|
|
|
file_save
|
|
|
|
</span>
|
|
|
|
</button>
|
|
|
|
|
|
|
|
<button style="border-color: green; color:#b2e3a8; background: rgba(24, 122, 5, 1)"
|
|
|
|
th:title="#{multiTool.downloadAll}" id="export-button" class="btn btn-primary enable-on-file"
|
|
|
|
onclick="exportPdf(false)" disabled>
|
|
|
|
<span class="material-symbols-rounded">
|
|
|
|
download
|
|
|
|
</span>
|
|
|
|
</button>
|
|
|
|
</div>
|
2023-04-18 05:08:38 +03:00
|
|
|
</div>
|
2024-02-16 22:49:06 +01:00
|
|
|
</div>
|
2023-04-18 05:08:38 +03:00
|
|
|
</div>
|
2024-02-16 22:49:06 +01:00
|
|
|
</div>
|
2023-04-18 05:08:38 +03:00
|
|
|
</div>
|
2024-05-05 15:19:53 +04:00
|
|
|
<div id="drag-container"></div>
|
|
|
|
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
|
|
|
</div>
|
2024-09-15 00:24:04 -07:00
|
|
|
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
2024-11-14 20:00:36 +00:00
|
|
|
<script>
|
|
|
|
window.selectedPages = [];
|
|
|
|
window.selectPage = false;
|
|
|
|
window.selectAll = false;
|
2024-11-21 19:33:19 +00:00
|
|
|
|
|
|
|
window.translations = {
|
2025-01-03 11:23:26 +00:00
|
|
|
rotateLeft: '[[#{multiTool.rotateLeft}]]',
|
|
|
|
rotateRight: '[[#{multiTool.rotateRight}]]',
|
|
|
|
moveLeft: '[[#{multiTool.moveLeft}]]',
|
|
|
|
moveRight: '[[#{multiTool.moveRight}]]',
|
|
|
|
delete: '[[#{multiTool.delete}]]',
|
|
|
|
split: '[[#{multiTool.split}]]',
|
|
|
|
addFile: '[[#{multiTool.addFile}]]',
|
|
|
|
insertPageBreak: '[[#{multiTool.insertPageBreak}]]',
|
|
|
|
dragDropMessage: '[[#{multiTool.dragDropMessage}]]',
|
|
|
|
undo: '[[#{multiTool.undo}]]',
|
|
|
|
redo: '[[#{multiTool.redo}]]',
|
2024-11-21 19:33:19 +00:00
|
|
|
};
|
|
|
|
|
2024-12-10 16:39:06 +00:00
|
|
|
window.decrypt = {
|
2025-01-03 11:23:26 +00:00
|
|
|
passwordPrompt: '[[#{decrypt.passwordPrompt}]]',
|
|
|
|
cancelled: '[[#{decrypt.cancelled}]]',
|
|
|
|
noPassword: '[[#{decrypt.noPassword}]]',
|
|
|
|
invalidPassword: '[[#{decrypt.invalidPassword}]]',
|
|
|
|
invalidPasswordHeader: '[[#{decrypt.invalidPasswordHeader}]]',
|
|
|
|
unexpectedError: '[[#{decrypt.unexpectedError}]]',
|
|
|
|
serverError: '[[#{decrypt.serverError}]]',
|
|
|
|
success: '[[#{decrypt.success}]]',
|
|
|
|
}
|
2024-11-21 19:33:19 +00:00
|
|
|
|
2024-11-14 20:00:36 +00:00
|
|
|
const csvInput = document.getElementById("csv-input");
|
|
|
|
csvInput.addEventListener("keydown", function (event) {
|
|
|
|
if (event.key === "Enter") {
|
|
|
|
updatePagesFromCSV();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
csvInput.addEventListener("blur", function () {
|
|
|
|
updatePagesFromCSV();
|
|
|
|
});
|
|
|
|
</script>
|
2024-05-05 15:19:53 +04:00
|
|
|
<script type="module">
|
2024-11-28 16:25:13 +02:00
|
|
|
import { UndoManager } from './js/multitool/UndoManager.js';
|
2024-05-05 15:19:53 +04:00
|
|
|
import PdfContainer from './js/multitool/PdfContainer.js';
|
|
|
|
import DragDropManager from "./js/multitool/DragDropManager.js";
|
|
|
|
import ImageHighlighter from "./js/multitool/ImageHighlighter.js";
|
|
|
|
import PdfActionsManager from './js/multitool/PdfActionsManager.js';
|
|
|
|
// enables drag and drop
|
2025-03-20 00:06:47 +00:00
|
|
|
|
|
|
|
const pdfUpload = document.querySelector("input[name=pdf-upload]");
|
|
|
|
pdfUpload.addEventListener("change", async (e) => {
|
|
|
|
if (!e.target.files) return;
|
|
|
|
await pdfContainer.handleDroppedFiles( e.target.files);
|
|
|
|
e.target.dispatchEvent(new CustomEvent('reset', {}));
|
|
|
|
});
|
2024-11-28 16:25:13 +02:00
|
|
|
|
|
|
|
var undoManager = new UndoManager();
|
2024-05-05 15:19:53 +04:00
|
|
|
const dragDropManager = new DragDropManager('drag-container', 'pages-container');
|
|
|
|
// enables image highlight on click
|
|
|
|
const imageHighlighter = new ImageHighlighter('image-highlighter');
|
2024-08-29 11:07:31 +02:00
|
|
|
// enables the default action buttons on each file
|
2024-11-28 16:25:13 +02:00
|
|
|
const pdfActionsManager = new PdfActionsManager('pages-container', undoManager);
|
2024-05-05 15:19:53 +04:00
|
|
|
// Scroll the wrapper horizontally
|
2024-02-16 22:49:06 +01:00
|
|
|
|
2024-08-29 11:07:31 +02:00
|
|
|
// Automatically exposes rotateAll, addFiles and exportPdf to the window for the global buttons.
|
2024-05-05 15:19:53 +04:00
|
|
|
const pdfContainer = new PdfContainer(
|
|
|
|
'pages-container',
|
|
|
|
'pages-container-wrapper',
|
|
|
|
[
|
|
|
|
dragDropManager,
|
|
|
|
imageHighlighter,
|
2025-03-20 00:06:47 +00:00
|
|
|
pdfActionsManager
|
2024-11-28 16:25:13 +02:00
|
|
|
],
|
|
|
|
undoManager
|
2024-05-05 15:19:53 +04:00
|
|
|
)
|
2024-02-16 22:49:06 +01:00
|
|
|
|
2025-01-03 11:23:26 +00:00
|
|
|
document.addEventListener('keydown', function (event) {
|
|
|
|
let targetElementId = event.target.id;
|
2024-11-28 16:25:13 +02:00
|
|
|
|
2025-01-03 11:23:26 +00:00
|
|
|
// To avoid undoing/redoing the page when the user is simply undoing/redoing text
|
|
|
|
const isFilenameInputField = (targetElementId === 'filename-input') && (event.target === document.activeElement);
|
2024-11-28 16:25:13 +02:00
|
|
|
|
2025-01-03 11:23:26 +00:00
|
|
|
const isUndo = (event.ctrlKey && event.key === 'z');
|
|
|
|
const isRedo = (event.ctrlKey && event.key == 'y');
|
|
|
|
if (isUndo && !isFilenameInputField)
|
|
|
|
undoManager.undo();
|
|
|
|
else if (isRedo && !isFilenameInputField) undoManager.redo();
|
|
|
|
});
|
2024-05-05 15:19:53 +04:00
|
|
|
</script>
|
|
|
|
</body>
|
2024-02-16 22:49:06 +01:00
|
|
|
|
2024-11-21 19:33:19 +00:00
|
|
|
</html>
|