2025-03-05 08:40:03 +00:00
|
|
|
import { MovePageCommand } from './commands/move-page.js';
|
2025-01-30 18:55:33 +00:00
|
|
|
import { RemoveSelectedCommand } from './commands/remove.js';
|
|
|
|
import { RotateAllCommand, RotateElementCommand } from './commands/rotate.js';
|
|
|
|
import { SplitAllCommand } from './commands/split.js';
|
|
|
|
import { UndoManager } from './UndoManager.js';
|
|
|
|
import { PageBreakCommand } from './commands/page-break.js';
|
|
|
|
import { AddFilesCommand } from './commands/add-page.js';
|
|
|
|
import { DecryptFile } from '../DecryptFiles.js';
|
2025-03-05 08:40:03 +00:00
|
|
|
import { CommandSequence } from './commands/commands-sequence.js';
|
2024-11-28 16:25:13 +02:00
|
|
|
|
2023-07-22 13:17:24 +01:00
|
|
|
class PdfContainer {
|
2024-02-16 22:49:06 +01:00
|
|
|
fileName;
|
|
|
|
pagesContainer;
|
|
|
|
pagesContainerWrapper;
|
|
|
|
pdfAdapters;
|
|
|
|
downloadLink;
|
2024-11-28 16:25:13 +02:00
|
|
|
undoManager;
|
2024-02-16 22:49:06 +01:00
|
|
|
|
2024-11-28 16:25:13 +02:00
|
|
|
constructor(id, wrapperId, pdfAdapters, undoManager) {
|
2024-02-16 22:49:06 +01:00
|
|
|
this.pagesContainer = document.getElementById(id);
|
|
|
|
this.pagesContainerWrapper = document.getElementById(wrapperId);
|
|
|
|
this.downloadLink = null;
|
|
|
|
this.movePageTo = this.movePageTo.bind(this);
|
2024-08-29 11:07:31 +02:00
|
|
|
this.addFiles = this.addFiles.bind(this);
|
|
|
|
this.addFilesFromFiles = this.addFilesFromFiles.bind(this);
|
2024-02-16 22:49:06 +01:00
|
|
|
this.rotateElement = this.rotateElement.bind(this);
|
|
|
|
this.rotateAll = this.rotateAll.bind(this);
|
|
|
|
this.exportPdf = this.exportPdf.bind(this);
|
|
|
|
this.updateFilename = this.updateFilename.bind(this);
|
|
|
|
this.setDownloadAttribute = this.setDownloadAttribute.bind(this);
|
|
|
|
this.preventIllegalChars = this.preventIllegalChars.bind(this);
|
2024-08-29 11:07:31 +02:00
|
|
|
this.addImageFile = this.addImageFile.bind(this);
|
2024-09-07 13:25:39 +03:00
|
|
|
this.nameAndArchiveFiles = this.nameAndArchiveFiles.bind(this);
|
|
|
|
this.splitPDF = this.splitPDF.bind(this);
|
|
|
|
this.splitAll = this.splitAll.bind(this);
|
2024-11-14 20:00:36 +00:00
|
|
|
this.deleteSelected = this.deleteSelected.bind(this);
|
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
|
|
|
this.selectAll = this.selectAll.bind(this);
|
|
|
|
this.deselectAll = this.deselectAll.bind(this);
|
2024-11-14 20:00:36 +00:00
|
|
|
this.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay.bind(this);
|
|
|
|
this.toggleSelectPageVisibility = this.toggleSelectPageVisibility.bind(this);
|
|
|
|
this.updatePagesFromCSV = this.updatePagesFromCSV.bind(this);
|
2024-12-05 10:43:31 +00:00
|
|
|
this.addFilesBlankAll = this.addFilesBlankAll.bind(this);
|
2024-11-15 13:21:23 -07:00
|
|
|
this.removeAllElements = this.removeAllElements.bind(this);
|
2024-11-22 11:39:22 +00:00
|
|
|
this.resetPages = this.resetPages.bind(this);
|
2024-02-16 22:49:06 +01:00
|
|
|
|
2024-12-06 19:08:18 +00:00
|
|
|
this.decryptFile = new DecryptFile();
|
|
|
|
|
2024-11-28 16:25:13 +02:00
|
|
|
this.undoManager = undoManager || new UndoManager();
|
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
this.pdfAdapters = pdfAdapters;
|
|
|
|
|
|
|
|
this.pdfAdapters.forEach((adapter) => {
|
|
|
|
adapter.setActions({
|
|
|
|
movePageTo: this.movePageTo,
|
2024-08-29 11:07:31 +02:00
|
|
|
addFiles: this.addFiles,
|
2024-02-16 22:49:06 +01:00
|
|
|
rotateElement: this.rotateElement,
|
|
|
|
updateFilename: this.updateFilename,
|
2024-11-14 20:00:36 +00:00
|
|
|
deleteSelected: this.deleteSelected,
|
2024-02-16 22:49:06 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2024-08-29 11:07:31 +02:00
|
|
|
window.addFiles = this.addFiles;
|
2024-02-16 22:49:06 +01:00
|
|
|
window.exportPdf = this.exportPdf;
|
|
|
|
window.rotateAll = this.rotateAll;
|
2024-09-07 13:25:39 +03:00
|
|
|
window.splitAll = this.splitAll;
|
2024-11-14 20:00:36 +00:00
|
|
|
window.deleteSelected = this.deleteSelected;
|
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
|
|
|
window.selectAll = this.selectAll;
|
|
|
|
window.deselectAll = this.deselectAll;
|
2024-11-14 20:00:36 +00:00
|
|
|
window.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay;
|
|
|
|
window.toggleSelectPageVisibility = this.toggleSelectPageVisibility;
|
|
|
|
window.updatePagesFromCSV = this.updatePagesFromCSV;
|
|
|
|
window.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay;
|
|
|
|
window.updatePageNumbersAndCheckboxes = this.updatePageNumbersAndCheckboxes;
|
2024-12-05 10:43:31 +00:00
|
|
|
window.addFilesBlankAll = this.addFilesBlankAll;
|
2024-11-15 13:21:23 -07:00
|
|
|
window.removeAllElements = this.removeAllElements;
|
2024-11-22 11:39:22 +00:00
|
|
|
window.resetPages = this.resetPages;
|
2024-02-16 22:49:06 +01:00
|
|
|
|
2024-11-28 16:25:13 +02:00
|
|
|
let undoBtn = document.getElementById('undo-btn');
|
|
|
|
let redoBtn = document.getElementById('redo-btn');
|
|
|
|
|
|
|
|
document.addEventListener('undo-manager-update', (e) => {
|
|
|
|
let canUndo = e.detail.canUndo;
|
|
|
|
let canRedo = e.detail.canRedo;
|
|
|
|
|
|
|
|
undoBtn.disabled = !canUndo;
|
|
|
|
redoBtn.disabled = !canRedo;
|
2024-12-05 10:43:31 +00:00
|
|
|
});
|
2024-11-28 16:25:13 +02:00
|
|
|
|
|
|
|
window.undo = () => {
|
|
|
|
if (undoManager.canUndo()) undoManager.undo();
|
|
|
|
else {
|
|
|
|
undoBtn.disabled = !undoManager.canUndo();
|
|
|
|
redoBtn.disabled = !undoManager.canRedo();
|
|
|
|
}
|
2024-12-05 10:43:31 +00:00
|
|
|
};
|
2024-11-28 16:25:13 +02:00
|
|
|
|
|
|
|
window.redo = () => {
|
|
|
|
if (undoManager.canRedo()) undoManager.redo();
|
|
|
|
else {
|
|
|
|
undoBtn.disabled = !undoManager.canUndo();
|
|
|
|
redoBtn.disabled = !undoManager.canRedo();
|
|
|
|
}
|
2024-12-05 10:43:31 +00:00
|
|
|
};
|
2024-11-28 16:25:13 +02:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
const filenameInput = document.getElementById('filename-input');
|
|
|
|
const downloadBtn = document.getElementById('export-button');
|
2024-02-16 22:49:06 +01:00
|
|
|
|
|
|
|
filenameInput.onkeyup = this.updateFilename;
|
|
|
|
filenameInput.onkeydown = this.preventIllegalChars;
|
|
|
|
filenameInput.disabled = false;
|
2024-12-05 10:43:31 +00:00
|
|
|
filenameInput.innerText = '';
|
2024-02-16 22:49:06 +01:00
|
|
|
downloadBtn.disabled = true;
|
|
|
|
}
|
|
|
|
|
2025-03-05 08:40:03 +00:00
|
|
|
movePagesTo(startElements, endElement, scrollTo = false) {
|
|
|
|
let commands = [];
|
|
|
|
startElements.forEach((page) => {
|
|
|
|
let command = new MovePageCommand(
|
|
|
|
page,
|
2024-11-28 16:25:13 +02:00
|
|
|
endElement,
|
|
|
|
this.pagesContainer,
|
|
|
|
this.pagesContainerWrapper,
|
|
|
|
scrollTo
|
2025-03-05 08:40:03 +00:00
|
|
|
)
|
|
|
|
command.execute();
|
|
|
|
commands.push(command);
|
|
|
|
})
|
|
|
|
|
|
|
|
let commandSequence = new CommandSequence(commands);
|
|
|
|
this.undoManager.pushUndoClearRedo(commandSequence);
|
|
|
|
return commandSequence;
|
|
|
|
}
|
|
|
|
|
2025-03-20 00:06:47 +00:00
|
|
|
showButton(button, show) {
|
|
|
|
button.classList.toggle('hidden', !show);
|
|
|
|
}
|
|
|
|
|
2025-03-05 08:40:03 +00:00
|
|
|
movePageTo(startElements, endElement, scrollTo = false) {
|
|
|
|
|
|
|
|
if (Array.isArray(startElements)){
|
|
|
|
return this.movePagesTo(startElements, endElement, scrollTo = false);
|
2023-07-22 13:17:24 +01:00
|
|
|
}
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2025-03-05 08:40:03 +00:00
|
|
|
let movePageCommand = new MovePageCommand(
|
|
|
|
startElements,
|
|
|
|
endElement,
|
|
|
|
this.pagesContainer,
|
|
|
|
this.pagesContainerWrapper,
|
|
|
|
scrollTo
|
|
|
|
);
|
|
|
|
|
2024-11-28 16:25:13 +02:00
|
|
|
movePageCommand.execute();
|
2025-03-05 08:40:03 +00:00
|
|
|
this.undoManager.pushUndoClearRedo(movePageCommand);
|
2024-11-28 16:25:13 +02:00
|
|
|
return movePageCommand;
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
async addFiles(element) {
|
|
|
|
let addFilesCommand = new AddFilesCommand(
|
|
|
|
element,
|
|
|
|
window.selectedPages,
|
|
|
|
this.addFilesAction.bind(this),
|
|
|
|
this.pagesContainer
|
|
|
|
);
|
|
|
|
|
|
|
|
await addFilesCommand.execute();
|
2024-02-16 22:49:06 +01:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
this.undoManager.pushUndoClearRedo(addFilesCommand);
|
2025-01-30 18:55:33 +00:00
|
|
|
window.tooltipSetup();
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
}
|
2024-02-16 22:49:06 +01:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
async addFilesAction(nextSiblingElement) {
|
|
|
|
let pages = [];
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
var input = document.createElement('input');
|
|
|
|
input.type = 'file';
|
2024-11-08 19:51:03 -03:00
|
|
|
input.multiple = true;
|
2024-12-05 10:43:31 +00:00
|
|
|
input.setAttribute('accept', 'application/pdf,image/*');
|
|
|
|
|
2024-11-08 19:51:03 -03:00
|
|
|
input.onchange = async (e) => {
|
|
|
|
const files = e.target.files;
|
2024-12-05 10:43:31 +00:00
|
|
|
if (files.length > 0) {
|
|
|
|
pages = await this.addFilesFromFiles(files, nextSiblingElement, pages);
|
|
|
|
this.updateFilename(files[0].name);
|
2025-03-20 00:06:47 +00:00
|
|
|
|
|
|
|
if(window.selectPage){
|
|
|
|
this.showButton(document.getElementById('select-pages-container'), true);
|
|
|
|
}
|
2024-12-05 10:43:31 +00:00
|
|
|
}
|
|
|
|
resolve(pages);
|
2024-11-08 19:51:03 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
input.click();
|
2024-12-05 10:43:31 +00:00
|
|
|
});
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
2024-12-31 10:44:49 +00:00
|
|
|
|
|
|
|
async handleDroppedFiles(files, nextSiblingElement = null) {
|
|
|
|
if (files.length > 0) {
|
|
|
|
const pages = await this.addFilesFromFiles(files, nextSiblingElement, []);
|
|
|
|
this.updateFilename(files[0]?.name || 'untitled');
|
|
|
|
|
2025-03-20 00:06:47 +00:00
|
|
|
if(window.selectPage) {
|
|
|
|
this.showButton(document.getElementById('select-pages-container'), true);
|
2024-12-31 10:44:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return pages;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
async addFilesFromFiles(files, nextSiblingElement, pages) {
|
2024-02-16 22:49:06 +01:00
|
|
|
this.fileName = files[0].name;
|
|
|
|
for (var i = 0; i < files.length; i++) {
|
2024-11-22 17:38:44 +00:00
|
|
|
const startTime = Date.now();
|
2024-12-05 10:43:31 +00:00
|
|
|
let processingTime,
|
|
|
|
errorMessage = null,
|
|
|
|
pageCount = 0;
|
2024-12-06 19:08:18 +00:00
|
|
|
|
2024-11-22 17:38:44 +00:00
|
|
|
try {
|
2024-12-06 19:08:18 +00:00
|
|
|
let decryptedFile = files[i];
|
2024-12-09 13:20:08 +00:00
|
|
|
let isEncrypted = false;
|
|
|
|
let requiresPassword = false;
|
|
|
|
await this.decryptFile
|
|
|
|
.checkFileEncrypted(decryptedFile)
|
|
|
|
.then((result) => {
|
|
|
|
isEncrypted = result.isEncrypted;
|
|
|
|
requiresPassword = result.requiresPassword;
|
|
|
|
})
|
|
|
|
.catch((error) => {
|
|
|
|
console.error(error);
|
|
|
|
});
|
|
|
|
if (decryptedFile.type === 'application/pdf' && isEncrypted) {
|
|
|
|
decryptedFile = await this.decryptFile.decryptFile(decryptedFile, requiresPassword);
|
2024-12-06 19:08:18 +00:00
|
|
|
if (!decryptedFile) {
|
|
|
|
throw new Error('File decryption failed.');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (decryptedFile.type === 'application/pdf') {
|
2025-01-30 18:55:33 +00:00
|
|
|
const { renderer, pdfDocument } = await this.loadFile(decryptedFile);
|
2024-12-05 10:43:31 +00:00
|
|
|
pageCount = renderer.pageCount || 0;
|
|
|
|
pages = await this.addPdfFile(renderer, pdfDocument, nextSiblingElement, pages);
|
2024-12-06 19:08:18 +00:00
|
|
|
} else if (decryptedFile.type.startsWith('image/')) {
|
|
|
|
pages = await this.addImageFile(decryptedFile, nextSiblingElement, pages);
|
2024-12-05 10:43:31 +00:00
|
|
|
}
|
2024-12-06 19:08:18 +00:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
processingTime = Date.now() - startTime;
|
2024-12-06 19:08:18 +00:00
|
|
|
this.captureFileProcessingEvent(true, decryptedFile, processingTime, null, pageCount);
|
2024-12-05 10:43:31 +00:00
|
|
|
} catch (error) {
|
|
|
|
processingTime = Date.now() - startTime;
|
|
|
|
errorMessage = error.message || 'Unknown error';
|
|
|
|
this.captureFileProcessingEvent(false, files[i], processingTime, errorMessage, pageCount);
|
2024-08-29 11:07:31 +02:00
|
|
|
}
|
2024-01-18 12:07:02 +11:00
|
|
|
}
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
document.querySelectorAll('.enable-on-file').forEach((element) => {
|
2024-02-16 22:49:06 +01:00
|
|
|
element.disabled = false;
|
|
|
|
});
|
2024-12-06 19:08:18 +00:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
return pages;
|
|
|
|
}
|
|
|
|
|
|
|
|
captureFileProcessingEvent(success, file, processingTime, errorMessage, pageCount) {
|
|
|
|
try {
|
|
|
|
if (analyticsEnabled) {
|
|
|
|
posthog.capture('file_processing', {
|
|
|
|
success,
|
|
|
|
file_type: file?.type || 'unknown',
|
|
|
|
file_size: file?.size || 0,
|
|
|
|
processing_time: processingTime,
|
|
|
|
error_message: errorMessage,
|
|
|
|
pdf_pages: pageCount,
|
|
|
|
});
|
|
|
|
}
|
2025-01-30 18:55:33 +00:00
|
|
|
} catch { }
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
async addFilesBlank(nextSiblingElement, pages) {
|
2024-11-28 12:21:14 +02:00
|
|
|
let doc = await PDFLib.PDFDocument.create();
|
|
|
|
let docBytes = await doc.save();
|
|
|
|
|
2025-01-30 18:55:33 +00:00
|
|
|
const url = URL.createObjectURL(new Blob([docBytes], { type: 'application/pdf' }));
|
2024-11-28 12:21:14 +02:00
|
|
|
|
|
|
|
const renderer = await this.toRenderer(url);
|
2024-12-05 10:43:31 +00:00
|
|
|
pages = await this.addPdfFile(renderer, doc, nextSiblingElement, pages);
|
|
|
|
return pages;
|
2024-11-08 19:51:03 -03:00
|
|
|
}
|
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
rotateElement(element, deg) {
|
2024-11-28 16:25:13 +02:00
|
|
|
let rotateCommand = new RotateElementCommand(element, deg);
|
|
|
|
rotateCommand.execute();
|
2024-10-14 22:34:41 +01:00
|
|
|
|
2024-11-28 16:25:13 +02:00
|
|
|
return rotateCommand;
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
async addPdfFile(renderer, pdfDocument, nextSiblingElement, pages) {
|
2024-02-16 22:49:06 +01:00
|
|
|
for (var i = 0; i < renderer.pageCount; i++) {
|
2024-12-05 10:43:31 +00:00
|
|
|
const div = document.createElement('div');
|
2024-02-16 22:49:06 +01:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
div.classList.add('page-container');
|
|
|
|
div.id = 'page-container-' + (i + 1);
|
|
|
|
var img = document.createElement('img');
|
|
|
|
img.classList.add('page-image');
|
2024-02-16 22:49:06 +01:00
|
|
|
const imageSrc = await renderer.renderPage(i);
|
|
|
|
img.src = imageSrc;
|
|
|
|
img.pageIdx = i;
|
|
|
|
img.rend = renderer;
|
|
|
|
img.doc = pdfDocument;
|
|
|
|
div.appendChild(img);
|
2024-12-05 10:43:31 +00:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
this.pdfAdapters.forEach((adapter) => {
|
|
|
|
adapter.adapt?.(div);
|
|
|
|
});
|
2024-12-05 10:43:31 +00:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
if (nextSiblingElement) {
|
|
|
|
this.pagesContainer.insertBefore(div, nextSiblingElement);
|
|
|
|
} else {
|
|
|
|
this.pagesContainer.appendChild(div);
|
|
|
|
}
|
2024-12-05 10:43:31 +00:00
|
|
|
|
|
|
|
pages.push(div);
|
2023-07-22 13:17:24 +01:00
|
|
|
}
|
2024-12-05 10:43:31 +00:00
|
|
|
|
|
|
|
return pages;
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
async addImageFile(file, nextSiblingElement, pages) {
|
|
|
|
const div = document.createElement('div');
|
|
|
|
div.classList.add('page-container');
|
2024-08-29 11:07:31 +02:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
var img = document.createElement('img');
|
|
|
|
img.classList.add('page-image');
|
2024-08-29 11:07:31 +02:00
|
|
|
img.src = URL.createObjectURL(file);
|
|
|
|
div.appendChild(img);
|
|
|
|
|
|
|
|
this.pdfAdapters.forEach((adapter) => {
|
|
|
|
adapter.adapt?.(div);
|
|
|
|
});
|
|
|
|
if (nextSiblingElement) {
|
|
|
|
this.pagesContainer.insertBefore(div, nextSiblingElement);
|
|
|
|
} else {
|
|
|
|
this.pagesContainer.appendChild(div);
|
|
|
|
}
|
2024-12-05 10:43:31 +00:00
|
|
|
pages.push(div);
|
|
|
|
return pages;
|
2024-08-29 11:07:31 +02:00
|
|
|
}
|
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
async loadFile(file) {
|
|
|
|
var objectUrl = URL.createObjectURL(file);
|
|
|
|
var pdfDocument = await this.toPdfLib(objectUrl);
|
|
|
|
var renderer = await this.toRenderer(objectUrl);
|
2025-01-30 18:55:33 +00:00
|
|
|
return { renderer, pdfDocument };
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
async toRenderer(objectUrl) {
|
2024-12-05 10:43:31 +00:00
|
|
|
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
|
2024-02-16 22:49:06 +01:00
|
|
|
const pdf = await pdfjsLib.getDocument(objectUrl).promise;
|
|
|
|
return {
|
|
|
|
document: pdf,
|
|
|
|
pageCount: pdf.numPages,
|
|
|
|
renderPage: async function (pageIdx) {
|
|
|
|
const page = await this.document.getPage(pageIdx + 1);
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
const canvas = document.createElement('canvas');
|
2024-02-16 22:49:06 +01:00
|
|
|
|
|
|
|
// set the canvas size to the size of the page
|
|
|
|
if (page.rotate == 90 || page.rotate == 270) {
|
|
|
|
canvas.width = page.view[3];
|
|
|
|
canvas.height = page.view[2];
|
|
|
|
} else {
|
|
|
|
canvas.width = page.view[2];
|
|
|
|
canvas.height = page.view[3];
|
2023-07-22 13:17:24 +01:00
|
|
|
}
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
// render the page onto the canvas
|
|
|
|
var renderContext = {
|
2024-12-05 10:43:31 +00:00
|
|
|
canvasContext: canvas.getContext('2d'),
|
2025-01-30 18:55:33 +00:00
|
|
|
viewport: page.getViewport({ scale: 1 }),
|
2023-07-22 13:17:24 +01:00
|
|
|
};
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
await page.render(renderContext).promise;
|
|
|
|
return canvas.toDataURL();
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
async toPdfLib(objectUrl) {
|
|
|
|
const existingPdfBytes = await fetch(objectUrl).then((res) => res.arrayBuffer());
|
|
|
|
const pdfDoc = await PDFLib.PDFDocument.load(existingPdfBytes, {
|
|
|
|
ignoreEncryption: true,
|
|
|
|
});
|
|
|
|
return pdfDoc;
|
|
|
|
}
|
|
|
|
|
|
|
|
rotateAll(deg) {
|
2024-11-28 16:25:13 +02:00
|
|
|
let elementsToRotate = [];
|
2024-11-14 20:00:36 +00:00
|
|
|
for (let i = 0; i < this.pagesContainer.childNodes.length; i++) {
|
2024-03-09 13:18:00 +01:00
|
|
|
const child = this.pagesContainer.children[i];
|
|
|
|
if (!child) continue;
|
2024-11-14 20:00:36 +00:00
|
|
|
|
|
|
|
const pageIndex = i + 1;
|
|
|
|
//if in page select mode is active rotate only selected pages
|
|
|
|
if (window.selectPage && !window.selectedPages.includes(pageIndex)) continue;
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
const img = child.querySelector('img');
|
2024-02-16 22:49:06 +01:00
|
|
|
if (!img) continue;
|
2024-11-14 20:00:36 +00:00
|
|
|
|
2024-11-28 16:25:13 +02:00
|
|
|
elementsToRotate.push(img);
|
2023-07-22 13:17:24 +01:00
|
|
|
}
|
2024-11-28 16:25:13 +02:00
|
|
|
|
|
|
|
let rotateAllCommand = new RotateAllCommand(elementsToRotate, deg);
|
|
|
|
rotateAllCommand.execute();
|
|
|
|
|
|
|
|
this.undoManager.pushUndoClearRedo(rotateAllCommand);
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
removeAllElements() {
|
|
|
|
let pageContainerNodeList = document.querySelectorAll('.page-container');
|
2024-11-15 13:21:23 -07:00
|
|
|
for (var i = 0; i < pageContainerNodeList.length; i++) {
|
|
|
|
pageContainerNodeList[i].remove();
|
|
|
|
}
|
2024-12-05 10:43:31 +00:00
|
|
|
document.querySelectorAll('.enable-on-file').forEach((element) => {
|
2024-11-15 13:21:23 -07:00
|
|
|
element.disabled = true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-11-14 20:00:36 +00:00
|
|
|
deleteSelected() {
|
|
|
|
window.selectedPages.sort((a, b) => a - b);
|
2024-11-28 16:25:13 +02:00
|
|
|
let removeSelectedCommand = new RemoveSelectedCommand(
|
|
|
|
this.pagesContainer,
|
|
|
|
window.selectedPages,
|
|
|
|
this.updatePageNumbersAndCheckboxes
|
|
|
|
);
|
2024-12-05 10:43:31 +00:00
|
|
|
removeSelectedCommand.execute();
|
2024-11-28 16:25:13 +02:00
|
|
|
this.undoManager.pushUndoClearRedo(removeSelectedCommand);
|
2024-11-14 20:00:36 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
selectAll() {
|
2024-12-05 10:43:31 +00:00
|
|
|
const checkboxes = document.querySelectorAll('.pdf-actions_checkbox');
|
|
|
|
const selectIcon = document.getElementById('select-All-Container');
|
|
|
|
const deselectIcon = document.getElementById('deselect-All-Container');
|
2024-11-14 20:00:36 +00:00
|
|
|
|
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
|
|
|
this.showButton(selectIcon, false);
|
|
|
|
this.showButton(deselectIcon, true);
|
|
|
|
|
2024-11-14 20:00:36 +00:00
|
|
|
checkboxes.forEach((checkbox) => {
|
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
|
|
|
checkbox.checked = true;
|
2024-11-14 20:00:36 +00:00
|
|
|
|
|
|
|
const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1;
|
|
|
|
|
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
|
|
|
if (!window.selectedPages.includes(pageNumber)) {
|
|
|
|
window.selectedPages.push(pageNumber);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
this.updateSelectedPagesDisplay();
|
|
|
|
}
|
|
|
|
|
|
|
|
deselectAll() {
|
|
|
|
const checkboxes = document.querySelectorAll('.pdf-actions_checkbox');
|
|
|
|
const selectIcon = document.getElementById('select-All-Container');
|
|
|
|
const deselectIcon = document.getElementById('deselect-All-Container');
|
|
|
|
|
|
|
|
this.showButton(selectIcon, true);
|
|
|
|
this.showButton(deselectIcon, false);
|
2025-05-05 23:23:08 +01:00
|
|
|
|
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
|
|
|
checkboxes.forEach((checkbox) => {
|
|
|
|
checkbox.checked = false;
|
|
|
|
|
|
|
|
const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1;
|
|
|
|
|
|
|
|
const index = window.selectedPages.indexOf(pageNumber);
|
|
|
|
if (index !== -1) {
|
|
|
|
window.selectedPages.splice(index, 1);
|
2024-11-14 20:00:36 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
this.updateSelectedPagesDisplay();
|
|
|
|
}
|
|
|
|
|
|
|
|
parseCSVInput(csvInput, maxPageIndex) {
|
|
|
|
const pages = new Set();
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
csvInput.split(',').forEach((item) => {
|
|
|
|
const range = item.split('-').map((p) => parseInt(p.trim()));
|
2024-11-14 20:00:36 +00:00
|
|
|
if (range.length === 2) {
|
|
|
|
const [start, end] = range;
|
|
|
|
for (let i = start; i <= end && i <= maxPageIndex; i++) {
|
2024-12-05 10:43:31 +00:00
|
|
|
if (i > 0) {
|
|
|
|
// Ensure the page number is greater than 0
|
2024-11-14 20:00:36 +00:00
|
|
|
pages.add(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (range.length === 1 && Number.isInteger(range[0])) {
|
|
|
|
const page = range[0];
|
2024-12-05 10:43:31 +00:00
|
|
|
if (page > 0 && page <= maxPageIndex) {
|
|
|
|
// Ensure page is within valid range
|
2024-11-14 20:00:36 +00:00
|
|
|
pages.add(page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return Array.from(pages).sort((a, b) => a - b);
|
|
|
|
}
|
|
|
|
|
|
|
|
updatePagesFromCSV() {
|
2024-12-05 10:43:31 +00:00
|
|
|
const csvInput = document.getElementById('csv-input').value;
|
2024-11-14 20:00:36 +00:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
const allPages = this.pagesContainer.querySelectorAll('.page-container');
|
2024-11-14 20:00:36 +00:00
|
|
|
const maxPageIndex = allPages.length;
|
|
|
|
|
|
|
|
window.selectedPages = this.parseCSVInput(csvInput, maxPageIndex);
|
|
|
|
|
|
|
|
this.updateSelectedPagesDisplay();
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
const allCheckboxes = document.querySelectorAll('.pdf-actions_checkbox');
|
2024-11-14 20:00:36 +00:00
|
|
|
allCheckboxes.forEach((checkbox) => {
|
2024-12-05 10:43:31 +00:00
|
|
|
const page = parseInt(checkbox.getAttribute('data-page-number'));
|
2024-11-14 20:00:36 +00:00
|
|
|
checkbox.checked = window.selectedPages.includes(page);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
formatSelectedPages(pages) {
|
2024-12-05 10:43:31 +00:00
|
|
|
if (pages.length === 0) return '';
|
2024-11-14 20:00:36 +00:00
|
|
|
|
|
|
|
pages.sort((a, b) => a - b); // Sort the page numbers in ascending order
|
|
|
|
const ranges = [];
|
|
|
|
let start = pages[0];
|
|
|
|
let end = start;
|
|
|
|
|
|
|
|
for (let i = 1; i < pages.length; i++) {
|
|
|
|
if (pages[i] === end + 1) {
|
|
|
|
// Consecutive page, update end
|
|
|
|
end = pages[i];
|
|
|
|
} else {
|
|
|
|
// Non-consecutive page, finalize current range
|
|
|
|
ranges.push(start === end ? `${start}` : `${start}-${end}`);
|
|
|
|
start = pages[i];
|
|
|
|
end = start;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Add the last range
|
|
|
|
ranges.push(start === end ? `${start}` : `${start}-${end}`);
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
return ranges.join(', ');
|
2024-11-14 20:00:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
updateSelectedPagesDisplay() {
|
2024-12-05 10:43:31 +00:00
|
|
|
const selectedPagesList = document.getElementById('selected-pages-list');
|
|
|
|
const selectedPagesInput = document.getElementById('csv-input');
|
|
|
|
selectedPagesList.innerHTML = ''; // Clear the list
|
2024-11-21 17:34:50 +00:00
|
|
|
window.selectedPages.sort((a, b) => a - b);
|
2024-11-14 20:00:36 +00:00
|
|
|
window.selectedPages.forEach((page) => {
|
2024-12-05 10:43:31 +00:00
|
|
|
const pageItem = document.createElement('div');
|
|
|
|
pageItem.className = 'page-item';
|
2024-11-14 20:00:36 +00:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
const pageNumber = document.createElement('span');
|
2024-11-14 20:00:36 +00:00
|
|
|
const pagelabel = /*[[#{multiTool.page}]]*/ 'Page';
|
2024-12-05 10:43:31 +00:00
|
|
|
pageNumber.className = 'selected-page-number';
|
2024-11-14 20:00:36 +00:00
|
|
|
pageNumber.innerText = `${pagelabel} ${page}`;
|
|
|
|
pageItem.appendChild(pageNumber);
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
const removeBtn = document.createElement('span');
|
|
|
|
removeBtn.className = 'remove-btn';
|
|
|
|
removeBtn.innerHTML = '✕';
|
2024-11-14 20:00:36 +00:00
|
|
|
|
|
|
|
// Remove page from selected pages list and update display and checkbox
|
|
|
|
removeBtn.onclick = () => {
|
|
|
|
window.selectedPages = window.selectedPages.filter((p) => p !== page);
|
|
|
|
this.updateSelectedPagesDisplay();
|
|
|
|
|
|
|
|
const checkbox = document.getElementById(`selectPageCheckbox-${page}`);
|
|
|
|
if (checkbox) {
|
|
|
|
checkbox.checked = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
pageItem.appendChild(removeBtn);
|
|
|
|
selectedPagesList.appendChild(pageItem);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Update the input field with the formatted page list
|
|
|
|
selectedPagesInput.value = this.formatSelectedPages(window.selectedPages);
|
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
|
|
|
|
|
|
|
const selectIcon = document.getElementById('select-All-Container');
|
|
|
|
const deselectIcon = document.getElementById('deselect-All-Container');
|
2025-05-05 23:23:08 +01:00
|
|
|
|
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
|
|
|
if (window.selectPage) { // Check if selectPage mode is active
|
|
|
|
console.log("Page Select on. Showing buttons");
|
|
|
|
//Check if no pages are selected
|
|
|
|
if (window.selectedPages.length === 0) {
|
|
|
|
this.showButton(selectIcon, true);
|
|
|
|
this.showButton(deselectIcon, false);
|
|
|
|
} else {
|
|
|
|
this.showButton(deselectIcon, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//Check if all pages are selected
|
|
|
|
const allCheckboxes = document.querySelectorAll('.pdf-actions_checkbox');
|
|
|
|
const allSelected = Array.from(allCheckboxes).every((checkbox) => checkbox.checked);
|
|
|
|
if (allSelected) {
|
|
|
|
this.showButton(selectIcon, false);
|
|
|
|
this.showButton(deselectIcon, true);
|
|
|
|
} else {
|
|
|
|
this.showButton(selectIcon, true);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
console.log("Page Select off. Hidding buttons");
|
|
|
|
this.showButton(selectIcon, false);
|
|
|
|
this.showButton(deselectIcon, false);
|
|
|
|
}
|
2024-11-14 20:00:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
parsePageRanges(ranges) {
|
|
|
|
const pages = new Set();
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
ranges.split(',').forEach((range) => {
|
2024-11-14 20:00:36 +00:00
|
|
|
const [start, end] = range.split('-').map(Number);
|
|
|
|
if (end) {
|
|
|
|
for (let i = start; i <= end; i++) {
|
|
|
|
pages.add(i);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pages.add(start);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return Array.from(pages).sort((a, b) => a - b);
|
|
|
|
}
|
2024-11-08 19:51:03 -03:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
async addFilesBlankAll() {
|
|
|
|
const allPages = this.pagesContainer.querySelectorAll('.page-container');
|
2024-11-08 19:51:03 -03:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
let pageBreakCommand = new PageBreakCommand(
|
2024-11-28 16:25:13 +02:00
|
|
|
allPages,
|
|
|
|
window.selectPage,
|
|
|
|
window.selectedPages,
|
2024-12-05 10:43:31 +00:00
|
|
|
this.addFilesBlank.bind(this),
|
|
|
|
this.pagesContainer
|
2024-11-28 16:25:13 +02:00
|
|
|
);
|
2024-12-05 10:43:31 +00:00
|
|
|
|
|
|
|
await pageBreakCommand.execute();
|
|
|
|
|
|
|
|
this.undoManager.pushUndoClearRedo(pageBreakCommand);
|
|
|
|
}
|
|
|
|
|
|
|
|
splitAll() {
|
|
|
|
const allPages = this.pagesContainer.querySelectorAll('.page-container');
|
|
|
|
let splitAllCommand = new SplitAllCommand(allPages, window.selectPage, window.selectedPages, 'split-before');
|
2024-11-28 16:25:13 +02:00
|
|
|
splitAllCommand.execute();
|
|
|
|
|
|
|
|
this.undoManager.pushUndoClearRedo(splitAllCommand);
|
2024-09-07 13:25:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
async splitPDF(baseDocBytes, splitters) {
|
|
|
|
const baseDocument = await PDFLib.PDFDocument.load(baseDocBytes);
|
|
|
|
const pageNum = baseDocument.getPages().length;
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
splitters.sort((a, b) => a - b); // We'll sort the separator indexes just in case querySelectorAll does something funny.
|
2024-09-07 13:25:39 +03:00
|
|
|
splitters.push(pageNum); // We'll also add a faux separator at the end in order to get the pages after the last separator.
|
|
|
|
|
|
|
|
const splitDocuments = [];
|
|
|
|
for (const splitterPosition of splitters) {
|
|
|
|
const subDocument = await PDFLib.PDFDocument.create();
|
|
|
|
|
|
|
|
const splitterIndex = splitters.indexOf(splitterPosition);
|
|
|
|
|
|
|
|
let firstPage = splitterIndex === 0 ? 0 : splitters[splitterIndex - 1];
|
|
|
|
|
2025-01-30 18:55:33 +00:00
|
|
|
const pageIndices = Array.from({ length: splitterPosition - firstPage }, (value, key) => firstPage + key);
|
2024-09-07 13:25:39 +03:00
|
|
|
|
|
|
|
const copiedPages = await subDocument.copyPages(baseDocument, pageIndices);
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
copiedPages.forEach((copiedPage) => {
|
2024-09-07 13:25:39 +03:00
|
|
|
subDocument.addPage(copiedPage);
|
|
|
|
});
|
|
|
|
|
|
|
|
const subDocumentBytes = await subDocument.save();
|
|
|
|
|
|
|
|
splitDocuments.push(subDocumentBytes);
|
2024-12-05 10:43:31 +00:00
|
|
|
}
|
2024-09-07 13:25:39 +03:00
|
|
|
|
|
|
|
return splitDocuments;
|
|
|
|
}
|
|
|
|
|
|
|
|
async nameAndArchiveFiles(pdfBytesArray, baseNameString) {
|
|
|
|
const zip = new JSZip();
|
|
|
|
|
|
|
|
for (let i = 0; i < pdfBytesArray.length; i++) {
|
2024-12-05 10:43:31 +00:00
|
|
|
const documentBlob = new Blob([pdfBytesArray[i]], {
|
|
|
|
type: 'application/pdf',
|
|
|
|
});
|
|
|
|
zip.file(baseNameString + '-' + (i + 1) + '.pdf', documentBlob);
|
2024-09-07 13:25:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return zip;
|
|
|
|
}
|
|
|
|
|
2024-11-14 20:00:36 +00:00
|
|
|
async exportPdf(selected) {
|
2024-02-16 22:49:06 +01:00
|
|
|
const pdfDoc = await PDFLib.PDFDocument.create();
|
2024-12-05 10:43:31 +00:00
|
|
|
const pageContainers = this.pagesContainer.querySelectorAll('.page-container'); // Select all .page-container elements
|
2024-02-16 22:49:06 +01:00
|
|
|
for (var i = 0; i < pageContainers.length; i++) {
|
2024-11-14 20:00:36 +00:00
|
|
|
if (!selected || window.selectedPages.includes(i + 1)) {
|
2024-12-05 10:43:31 +00:00
|
|
|
const img = pageContainers[i].querySelector('img'); // Find the img element within each .page-container
|
2024-11-14 20:00:36 +00:00
|
|
|
if (!img) continue;
|
|
|
|
let page;
|
|
|
|
if (img.doc) {
|
|
|
|
const pages = await pdfDoc.copyPages(img.doc, [img.pageIdx]);
|
|
|
|
page = pages[0];
|
|
|
|
pdfDoc.addPage(page);
|
|
|
|
} else {
|
|
|
|
page = pdfDoc.addPage([img.naturalWidth, img.naturalHeight]);
|
|
|
|
const imageBytes = await fetch(img.src).then((res) => res.arrayBuffer());
|
|
|
|
const uint8Array = new Uint8Array(imageBytes);
|
|
|
|
const imageType = detectImageType(uint8Array);
|
|
|
|
|
|
|
|
let image;
|
|
|
|
switch (imageType) {
|
|
|
|
case 'PNG':
|
|
|
|
image = await pdfDoc.embedPng(imageBytes);
|
|
|
|
break;
|
|
|
|
case 'JPEG':
|
|
|
|
image = await pdfDoc.embedJpg(imageBytes);
|
|
|
|
break;
|
|
|
|
case 'TIFF':
|
|
|
|
image = await pdfDoc.embedTiff(imageBytes);
|
|
|
|
break;
|
|
|
|
case 'GIF':
|
|
|
|
console.warn(`Unsupported image type: ${imageType}`);
|
|
|
|
continue; // Skip this image
|
|
|
|
default:
|
|
|
|
console.warn(`Unsupported image type: ${imageType}`);
|
|
|
|
continue; // Skip this image
|
|
|
|
}
|
|
|
|
page.drawImage(image, {
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
width: img.naturalWidth,
|
|
|
|
height: img.naturalHeight,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
const rotation = img.style.rotate;
|
|
|
|
if (rotation) {
|
2024-12-05 10:43:31 +00:00
|
|
|
const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, ''));
|
2024-11-14 20:00:36 +00:00
|
|
|
page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle));
|
2024-08-29 11:07:31 +02:00
|
|
|
}
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
2023-07-22 13:17:24 +01:00
|
|
|
}
|
2024-10-14 22:34:41 +01:00
|
|
|
pdfDoc.setCreator(stirlingPDFLabel);
|
|
|
|
pdfDoc.setProducer(stirlingPDFLabel);
|
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
const pdfBytes = await pdfDoc.save();
|
2025-01-30 18:55:33 +00:00
|
|
|
const pdfBlob = new Blob([pdfBytes], { type: 'application/pdf' });
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
const filenameInput = document.getElementById('filename-input');
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
let inputArr = filenameInput.value.split('.');
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
if (inputArr !== null && inputArr !== undefined && inputArr.length > 0) {
|
|
|
|
inputArr = inputArr.filter((n) => n); // remove all empty strings, nulls or undefined
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
if (inputArr.length > 1) {
|
|
|
|
inputArr.pop(); // remove right part after last dot
|
|
|
|
}
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
filenameInput.value = inputArr.join('');
|
2024-02-16 22:49:06 +01:00
|
|
|
this.fileName = filenameInput.value;
|
|
|
|
}
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
const separators = this.pagesContainer.querySelectorAll('.split-before');
|
|
|
|
if (separators.length !== 0) {
|
|
|
|
// Split the pdf if there are separators.
|
|
|
|
const baseName = this.fileName ? this.fileName : 'managed';
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-09-07 13:25:39 +03:00
|
|
|
const pagesArray = Array.from(this.pagesContainer.children);
|
|
|
|
const splitters = [];
|
2024-12-05 10:43:31 +00:00
|
|
|
separators.forEach((page) => {
|
2024-09-07 13:25:39 +03:00
|
|
|
const pageIndex = pagesArray.indexOf(page);
|
|
|
|
if (pageIndex !== 0) {
|
|
|
|
splitters.push(pageIndex);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
const splitDocuments = await this.splitPDF(pdfBytes, splitters);
|
|
|
|
const archivedDocuments = await this.nameAndArchiveFiles(splitDocuments, baseName);
|
|
|
|
|
|
|
|
const self = this;
|
2025-01-30 18:55:33 +00:00
|
|
|
archivedDocuments.generateAsync({ type: 'base64' }).then(function (base64) {
|
2024-12-05 10:43:31 +00:00
|
|
|
const url = 'data:application/zip;base64,' + base64;
|
|
|
|
self.downloadLink = document.createElement('a');
|
2024-09-07 13:25:39 +03:00
|
|
|
self.downloadLink.href = url;
|
2024-12-05 10:43:31 +00:00
|
|
|
self.downloadLink.setAttribute('download', baseName + '.zip');
|
|
|
|
self.downloadLink.setAttribute('target', '_blank');
|
2024-09-07 13:25:39 +03:00
|
|
|
self.downloadLink.click();
|
|
|
|
});
|
2024-12-05 10:43:31 +00:00
|
|
|
} else {
|
|
|
|
// Continue normally if there are no separators
|
2024-09-07 13:25:39 +03:00
|
|
|
|
|
|
|
const url = URL.createObjectURL(pdfBlob);
|
2024-12-05 10:43:31 +00:00
|
|
|
const downloadOption = localStorage.getItem('downloadOption');
|
2024-09-07 13:25:39 +03:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
if (!filenameInput.value.includes('.pdf')) {
|
|
|
|
filenameInput.value = filenameInput.value + '.pdf';
|
2024-09-07 13:25:39 +03:00
|
|
|
this.fileName = filenameInput.value;
|
|
|
|
}
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
if (downloadOption === 'sameWindow') {
|
2024-09-07 13:25:39 +03:00
|
|
|
// Open the file in the same window
|
|
|
|
window.location.href = url;
|
2024-12-05 10:43:31 +00:00
|
|
|
} else if (downloadOption === 'newWindow') {
|
2024-09-07 13:25:39 +03:00
|
|
|
// Open the file in a new window
|
2024-12-05 10:43:31 +00:00
|
|
|
window.open(url, '_blank');
|
2024-09-07 13:25:39 +03:00
|
|
|
} else {
|
|
|
|
// Download the file
|
2024-12-05 10:43:31 +00:00
|
|
|
this.downloadLink = document.createElement('a');
|
|
|
|
this.downloadLink.id = 'download-link';
|
2024-09-07 13:25:39 +03:00
|
|
|
this.downloadLink.href = url;
|
|
|
|
// downloadLink.download = this.fileName ? this.fileName : 'managed.pdf';
|
|
|
|
// downloadLink.download = this.fileName;
|
2024-12-05 10:43:31 +00:00
|
|
|
this.downloadLink.setAttribute('download', this.fileName ? this.fileName : 'managed.pdf');
|
|
|
|
this.downloadLink.setAttribute('target', '_blank');
|
2024-09-07 13:25:39 +03:00
|
|
|
this.downloadLink.onclick = this.setDownloadAttribute;
|
|
|
|
this.downloadLink.click();
|
|
|
|
}
|
2023-10-08 19:57:19 +03:00
|
|
|
}
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
resetPages() {
|
|
|
|
const pageContainers = this.pagesContainer.querySelectorAll('.page-container');
|
2024-11-22 11:39:22 +00:00
|
|
|
|
|
|
|
pageContainers.forEach((container, index) => {
|
2024-12-05 10:43:31 +00:00
|
|
|
container.id = 'page-container-' + (index + 1);
|
2024-11-22 11:39:22 +00:00
|
|
|
});
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
const checkboxes = document.querySelectorAll('.pdf-actions_checkbox');
|
|
|
|
const selectIcon = document.getElementById('select-All-Container');
|
|
|
|
const deselectIcon = document.getElementById('deselect-All-Container');
|
2024-11-22 11:39:22 +00:00
|
|
|
|
|
|
|
checkboxes.forEach((checkbox) => {
|
|
|
|
const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1;
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
const index = window.selectedPages.indexOf(pageNumber);
|
|
|
|
if (index !== -1) {
|
|
|
|
window.selectedPages.splice(index, 1);
|
|
|
|
}
|
2024-11-22 11:39:22 +00:00
|
|
|
});
|
|
|
|
window.toggleSelectPageVisibility();
|
|
|
|
}
|
2024-08-29 11:07:31 +02:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
setDownloadAttribute() {
|
2024-12-05 10:43:31 +00:00
|
|
|
this.downloadLink.setAttribute('download', this.fileName ? this.fileName : 'managed.pdf');
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
updateFilename(fileName = '') {
|
|
|
|
const filenameInput = document.getElementById('filename-input');
|
|
|
|
const pagesContainer = document.getElementById('pages-container');
|
|
|
|
const downloadBtn = document.getElementById('export-button');
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
downloadBtn.disabled = pagesContainer.childElementCount === 0;
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
if (!this.fileName) {
|
|
|
|
this.fileName = fileName;
|
2023-10-15 19:03:10 +03:00
|
|
|
}
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
if (!filenameInput.value) {
|
|
|
|
filenameInput.value = this.fileName;
|
2023-10-08 18:59:43 +03:00
|
|
|
}
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
preventIllegalChars(e) {
|
|
|
|
// const filenameInput = document.getElementById('filename-input');
|
|
|
|
//
|
|
|
|
// filenameInput.value = filenameInput.value.replace('.pdf', '');
|
|
|
|
//
|
|
|
|
// // prevent .
|
|
|
|
// if (filenameInput.value.includes('.')) {
|
|
|
|
// filenameInput.value.replace('.','');
|
|
|
|
// }
|
|
|
|
}
|
2024-11-14 20:00:36 +00:00
|
|
|
|
|
|
|
toggleSelectPageVisibility() {
|
|
|
|
window.selectPage = !window.selectPage;
|
2024-12-05 10:43:31 +00:00
|
|
|
const checkboxes = document.querySelectorAll('.pdf-actions_checkbox');
|
|
|
|
checkboxes.forEach((checkbox) => {
|
|
|
|
checkbox.classList.toggle('hidden', !window.selectPage);
|
2024-11-14 20:00:36 +00:00
|
|
|
});
|
2024-12-05 10:43:31 +00:00
|
|
|
const deleteButton = document.getElementById('delete-button');
|
|
|
|
deleteButton.classList.toggle('hidden', !window.selectPage);
|
|
|
|
const selectedPages = document.getElementById('selected-pages-display');
|
|
|
|
selectedPages.classList.toggle('hidden', !window.selectPage);
|
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
|
|
|
|
2025-03-20 00:06:47 +00:00
|
|
|
if(!window.selectPage)
|
|
|
|
{
|
|
|
|
this.showButton(document.getElementById('deselect-All-Container'), false);
|
|
|
|
this.showButton(document.getElementById('select-All-Container'), false);
|
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
|
|
|
|
|
|
|
// Uncheck all checkboxes and clear selected pages
|
|
|
|
const allCheckboxes = document.querySelectorAll('.pdf-actions_checkbox');
|
|
|
|
allCheckboxes.forEach((checkbox) => {
|
|
|
|
checkbox.checked = false;
|
|
|
|
});
|
|
|
|
window.selectedPages = [];
|
|
|
|
this.updateSelectedPagesDisplay();
|
2025-03-20 00:06:47 +00:00
|
|
|
}
|
|
|
|
else{
|
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
|
|
|
const allCheckboxes = document.querySelectorAll('.pdf-actions_checkbox');
|
|
|
|
const allSelected = Array.from(allCheckboxes).every((checkbox) => checkbox.checked);
|
|
|
|
if (!allSelected) {
|
|
|
|
this.showButton(document.getElementById('select-All-Container'), true);
|
|
|
|
}
|
2025-05-05 23:23:08 +01:00
|
|
|
|
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
|
|
|
if (window.selectedPages.length > 0) {
|
|
|
|
this.showButton(document.getElementById('deselect-All-Container'), true);
|
|
|
|
}
|
2025-03-20 00:06:47 +00:00
|
|
|
}
|
|
|
|
|
2024-12-05 10:43:31 +00:00
|
|
|
const exportSelected = document.getElementById('export-selected-button');
|
|
|
|
exportSelected.classList.toggle('hidden', !window.selectPage);
|
|
|
|
const selectPagesButton = document.getElementById('select-pages-button');
|
|
|
|
selectPagesButton.style.opacity = window.selectPage ? '1' : '0.5';
|
2024-11-14 20:00:36 +00:00
|
|
|
|
|
|
|
if (window.selectPage) {
|
|
|
|
this.updatePageNumbersAndCheckboxes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updatePageNumbersAndCheckboxes() {
|
2024-12-05 10:43:31 +00:00
|
|
|
const pageDivs = document.querySelectorAll('.pdf-actions_container');
|
2024-11-14 20:00:36 +00:00
|
|
|
|
|
|
|
pageDivs.forEach((div, index) => {
|
|
|
|
const pageNumber = index + 1;
|
2024-12-05 10:43:31 +00:00
|
|
|
const checkbox = div.querySelector('.pdf-actions_checkbox');
|
2024-11-14 20:00:36 +00:00
|
|
|
checkbox.id = `selectPageCheckbox-${pageNumber}`;
|
2024-12-05 10:43:31 +00:00
|
|
|
checkbox.setAttribute('data-page-number', pageNumber);
|
2024-11-14 20:00:36 +00:00
|
|
|
checkbox.checked = window.selectedPages.includes(pageNumber);
|
|
|
|
});
|
|
|
|
}
|
2023-07-22 13:17:24 +01:00
|
|
|
}
|
2024-11-14 20:00:36 +00:00
|
|
|
|
2024-08-29 11:07:31 +02:00
|
|
|
function detectImageType(uint8Array) {
|
|
|
|
// Check for PNG signature
|
|
|
|
if (uint8Array[0] === 137 && uint8Array[1] === 80 && uint8Array[2] === 78 && uint8Array[3] === 71) {
|
|
|
|
return 'PNG';
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for JPEG signature
|
|
|
|
if (uint8Array[0] === 255 && uint8Array[1] === 216 && uint8Array[2] === 255) {
|
|
|
|
return 'JPEG';
|
|
|
|
}
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-08-29 11:07:31 +02:00
|
|
|
// Check for TIFF signature (little-endian and big-endian)
|
2024-12-05 10:43:31 +00:00
|
|
|
if (
|
|
|
|
(uint8Array[0] === 73 && uint8Array[1] === 73 && uint8Array[2] === 42 && uint8Array[3] === 0) ||
|
|
|
|
(uint8Array[0] === 77 && uint8Array[1] === 77 && uint8Array[2] === 0 && uint8Array[3] === 42)
|
|
|
|
) {
|
2024-08-29 11:07:31 +02:00
|
|
|
return 'TIFF';
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for GIF signature
|
|
|
|
if (uint8Array[0] === 71 && uint8Array[1] === 73 && uint8Array[2] === 70) {
|
|
|
|
return 'GIF';
|
|
|
|
}
|
|
|
|
|
|
|
|
return 'UNKNOWN';
|
|
|
|
}
|
2024-11-14 20:00:36 +00:00
|
|
|
|
2023-07-22 13:17:24 +01:00
|
|
|
export default PdfContainer;
|