2024-11-28 16:25:13 +02:00
|
|
|
import { DeletePageCommand } from "./commands/delete-page.js";
|
|
|
|
import { SelectPageCommand } from "./commands/select.js";
|
|
|
|
import { SplitFileCommand } from "./commands/split.js";
|
|
|
|
import { UndoManager } from "./UndoManager.js";
|
|
|
|
|
2023-04-28 21:20:56 +02:00
|
|
|
class PdfActionsManager {
|
2024-02-16 22:49:06 +01:00
|
|
|
pageDirection;
|
|
|
|
pagesContainer;
|
2024-11-14 20:00:36 +00:00
|
|
|
static selectedPages = []; // Static property shared across all instances
|
2024-11-28 16:25:13 +02:00
|
|
|
undoManager;
|
2023-04-29 12:43:12 +02:00
|
|
|
|
2024-11-28 16:25:13 +02:00
|
|
|
constructor(id, undoManager) {
|
2024-02-16 22:49:06 +01:00
|
|
|
this.pagesContainer = document.getElementById(id);
|
2024-03-21 21:58:01 +01:00
|
|
|
this.pageDirection = document.documentElement.getAttribute("dir");
|
2023-04-30 13:38:30 +02:00
|
|
|
|
2024-11-28 16:25:13 +02:00
|
|
|
this.undoManager = undoManager || new UndoManager();
|
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
var styleElement = document.createElement("link");
|
|
|
|
styleElement.rel = "stylesheet";
|
|
|
|
styleElement.href = "css/pdfActions.css";
|
2023-04-30 13:38:30 +02:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
document.head.appendChild(styleElement);
|
|
|
|
}
|
2023-04-29 12:43:12 +02:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
getPageContainer(element) {
|
|
|
|
var container = element;
|
|
|
|
while (!container.classList.contains("page-container")) {
|
|
|
|
container = container.parentNode;
|
2023-04-29 12:43:12 +02:00
|
|
|
}
|
2024-02-16 22:49:06 +01:00
|
|
|
return container;
|
|
|
|
}
|
2023-04-29 12:43:12 +02:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
moveUpButtonCallback(e) {
|
|
|
|
var imgContainer = this.getPageContainer(e.target);
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
const sibling = imgContainer.previousSibling;
|
|
|
|
if (sibling) {
|
2024-11-28 16:25:13 +02:00
|
|
|
let movePageCommand = this.movePageTo(imgContainer, sibling, true, true);
|
|
|
|
this._pushUndoClearRedo(movePageCommand);
|
2023-04-28 21:20:56 +02:00
|
|
|
}
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
2023-04-28 21:20:56 +02:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
moveDownButtonCallback(e) {
|
|
|
|
var imgContainer = this.getPageContainer(e.target);
|
|
|
|
const sibling = imgContainer.nextSibling;
|
|
|
|
if (sibling) {
|
2024-11-28 16:25:13 +02:00
|
|
|
let movePageCommand = this.movePageTo(
|
|
|
|
imgContainer,
|
|
|
|
sibling.nextSibling,
|
|
|
|
true
|
|
|
|
);
|
|
|
|
this._pushUndoClearRedo(movePageCommand);
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
|
|
|
}
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
rotateCCWButtonCallback(e) {
|
|
|
|
var imgContainer = this.getPageContainer(e.target);
|
|
|
|
const img = imgContainer.querySelector("img");
|
2023-04-29 12:43:12 +02:00
|
|
|
|
2024-11-28 16:25:13 +02:00
|
|
|
let rotateCommand = this.rotateElement(img, -90);
|
|
|
|
this._pushUndoClearRedo(rotateCommand);
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
rotateCWButtonCallback(e) {
|
|
|
|
var imgContainer = this.getPageContainer(e.target);
|
|
|
|
const img = imgContainer.querySelector("img");
|
2023-04-29 12:43:12 +02:00
|
|
|
|
2024-11-28 16:25:13 +02:00
|
|
|
let rotateCommand = this.rotateElement(img, 90);
|
|
|
|
this._pushUndoClearRedo(rotateCommand);
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
2023-10-14 00:03:08 +03:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
deletePageButtonCallback(e) {
|
2024-11-28 16:25:13 +02:00
|
|
|
let imgContainer = this.getPageContainer(e.target);
|
|
|
|
let deletePageCommand = new DeletePageCommand(
|
|
|
|
imgContainer,
|
|
|
|
this.pagesContainer
|
|
|
|
);
|
|
|
|
deletePageCommand.execute();
|
2023-04-29 12:43:12 +02:00
|
|
|
|
2024-11-28 16:25:13 +02:00
|
|
|
this._pushUndoClearRedo(deletePageCommand);
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
insertFileButtonCallback(e) {
|
|
|
|
var imgContainer = this.getPageContainer(e.target);
|
2024-09-05 17:14:22 +03:00
|
|
|
this.addFiles(imgContainer);
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
|
|
|
|
2024-11-08 19:51:03 -03:00
|
|
|
insertFileBlankButtonCallback(e) {
|
|
|
|
var imgContainer = this.getPageContainer(e.target);
|
|
|
|
this.addFiles(imgContainer, true);
|
|
|
|
}
|
|
|
|
|
2024-09-07 13:25:39 +03:00
|
|
|
splitFileButtonCallback(e) {
|
|
|
|
var imgContainer = this.getPageContainer(e.target);
|
2024-11-28 16:25:13 +02:00
|
|
|
|
|
|
|
let splitFileCommand = new SplitFileCommand(imgContainer, "split-before");
|
|
|
|
splitFileCommand.execute();
|
|
|
|
|
|
|
|
this._pushUndoClearRedo(splitFileCommand);
|
|
|
|
}
|
|
|
|
|
|
|
|
_pushUndoClearRedo(command) {
|
|
|
|
this.undoManager.pushUndoClearRedo(command);
|
2024-09-07 13:25:39 +03:00
|
|
|
}
|
|
|
|
|
2024-09-07 23:40:19 +03:00
|
|
|
setActions({ movePageTo, addFiles, rotateElement }) {
|
2024-02-16 22:49:06 +01:00
|
|
|
this.movePageTo = movePageTo;
|
2024-09-05 17:14:22 +03:00
|
|
|
this.addFiles = addFiles;
|
2024-02-16 22:49:06 +01:00
|
|
|
this.rotateElement = rotateElement;
|
|
|
|
|
|
|
|
this.moveUpButtonCallback = this.moveUpButtonCallback.bind(this);
|
|
|
|
this.moveDownButtonCallback = this.moveDownButtonCallback.bind(this);
|
|
|
|
this.rotateCCWButtonCallback = this.rotateCCWButtonCallback.bind(this);
|
|
|
|
this.rotateCWButtonCallback = this.rotateCWButtonCallback.bind(this);
|
|
|
|
this.deletePageButtonCallback = this.deletePageButtonCallback.bind(this);
|
|
|
|
this.insertFileButtonCallback = this.insertFileButtonCallback.bind(this);
|
2024-11-08 19:51:03 -03:00
|
|
|
this.insertFileBlankButtonCallback = this.insertFileBlankButtonCallback.bind(this);
|
2024-09-07 13:25:39 +03:00
|
|
|
this.splitFileButtonCallback = this.splitFileButtonCallback.bind(this);
|
2024-02-16 22:49:06 +01:00
|
|
|
}
|
|
|
|
|
2024-11-14 20:00:36 +00:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
adapt(div) {
|
|
|
|
div.classList.add("pdf-actions_container");
|
|
|
|
const leftDirection = this.pageDirection === "rtl" ? "right" : "left";
|
|
|
|
const rightDirection = this.pageDirection === "rtl" ? "left" : "right";
|
|
|
|
const buttonContainer = document.createElement("div");
|
|
|
|
|
2024-05-05 15:12:30 +04:00
|
|
|
buttonContainer.classList.add("btn-group", "pdf-actions_button-container", "hide-on-drag");
|
2024-02-16 22:49:06 +01:00
|
|
|
|
|
|
|
const moveUp = document.createElement("button");
|
|
|
|
moveUp.classList.add("pdf-actions_move-left-button", "btn", "btn-secondary");
|
2025-01-30 18:55:33 +00:00
|
|
|
moveUp.setAttribute('title', window.translations.moveLeft);
|
|
|
|
moveUp.innerHTML = `<span class="material-symbols-rounded">arrow_${leftDirection}_alt</span>`;
|
2024-02-16 22:49:06 +01:00
|
|
|
moveUp.onclick = this.moveUpButtonCallback;
|
|
|
|
buttonContainer.appendChild(moveUp);
|
|
|
|
|
|
|
|
const moveDown = document.createElement("button");
|
|
|
|
moveDown.classList.add("pdf-actions_move-right-button", "btn", "btn-secondary");
|
2025-01-30 18:55:33 +00:00
|
|
|
moveDown.setAttribute('title', window.translations.moveRight);
|
|
|
|
moveDown.innerHTML = `<span class="material-symbols-rounded">arrow_${rightDirection}_alt</span>`;
|
2024-02-16 22:49:06 +01:00
|
|
|
moveDown.onclick = this.moveDownButtonCallback;
|
|
|
|
buttonContainer.appendChild(moveDown);
|
|
|
|
|
2024-11-21 19:33:19 +00:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
const rotateCCW = document.createElement("button");
|
|
|
|
rotateCCW.classList.add("btn", "btn-secondary");
|
2025-01-30 18:55:33 +00:00
|
|
|
rotateCCW.setAttribute('title', window.translations.rotateLeft);
|
|
|
|
rotateCCW.innerHTML = `<span class="material-symbols-rounded">rotate_left</span>`;
|
2024-02-16 22:49:06 +01:00
|
|
|
rotateCCW.onclick = this.rotateCCWButtonCallback;
|
|
|
|
buttonContainer.appendChild(rotateCCW);
|
2023-04-28 21:20:56 +02:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
const rotateCW = document.createElement("button");
|
|
|
|
rotateCW.classList.add("btn", "btn-secondary");
|
2025-01-30 18:55:33 +00:00
|
|
|
rotateCW.setAttribute('title', window.translations.rotateRight);
|
|
|
|
rotateCW.innerHTML = `<span class="material-symbols-rounded">rotate_right</span>`;
|
2024-02-16 22:49:06 +01:00
|
|
|
rotateCW.onclick = this.rotateCWButtonCallback;
|
|
|
|
buttonContainer.appendChild(rotateCW);
|
2023-04-28 21:20:56 +02:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
const deletePage = document.createElement("button");
|
|
|
|
deletePage.classList.add("btn", "btn-danger");
|
2025-01-30 18:55:33 +00:00
|
|
|
deletePage.setAttribute('title', window.translations.delete);
|
|
|
|
deletePage.innerHTML = `<span class="material-symbols-rounded">delete</span>`;
|
2024-02-16 22:49:06 +01:00
|
|
|
deletePage.onclick = this.deletePageButtonCallback;
|
|
|
|
buttonContainer.appendChild(deletePage);
|
2023-04-28 21:20:56 +02:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
div.appendChild(buttonContainer);
|
2023-04-28 21:20:56 +02:00
|
|
|
|
2024-11-14 20:00:36 +00:00
|
|
|
//enerate checkbox to select individual pages
|
|
|
|
const selectCheckbox = document.createElement("input");
|
|
|
|
selectCheckbox.type = "checkbox";
|
|
|
|
selectCheckbox.classList.add("pdf-actions_checkbox", "form-check-input");
|
|
|
|
selectCheckbox.id = `selectPageCheckbox`;
|
|
|
|
selectCheckbox.checked = window.selectAll;
|
|
|
|
|
|
|
|
div.appendChild(selectCheckbox);
|
|
|
|
|
|
|
|
//only show whenpage select mode is active
|
|
|
|
if (!window.selectPage) {
|
|
|
|
selectCheckbox.classList.add("hidden");
|
|
|
|
} else {
|
|
|
|
selectCheckbox.classList.remove("hidden");
|
|
|
|
}
|
|
|
|
|
|
|
|
selectCheckbox.onchange = () => {
|
|
|
|
const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1;
|
2024-11-28 16:25:13 +02:00
|
|
|
let selectPageCommand = new SelectPageCommand(pageNumber, selectCheckbox);
|
|
|
|
selectPageCommand.execute();
|
|
|
|
|
|
|
|
this._pushUndoClearRedo(selectPageCommand);
|
2024-11-14 20:00:36 +00:00
|
|
|
};
|
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
const insertFileButtonContainer = document.createElement("div");
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
insertFileButtonContainer.classList.add(
|
|
|
|
"pdf-actions_insert-file-button-container",
|
|
|
|
leftDirection,
|
|
|
|
`align-center-${leftDirection}`,
|
|
|
|
);
|
2024-02-11 11:47:00 -05:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
const insertFileButton = document.createElement("button");
|
|
|
|
insertFileButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button");
|
2025-01-30 18:55:33 +00:00
|
|
|
moveUp.setAttribute('title', window.translations.addFile);
|
|
|
|
insertFileButton.innerHTML = `<span class="material-symbols-rounded">add</span>`;
|
2024-02-16 22:49:06 +01:00
|
|
|
insertFileButton.onclick = this.insertFileButtonCallback;
|
|
|
|
insertFileButtonContainer.appendChild(insertFileButton);
|
|
|
|
|
2024-09-07 13:25:39 +03:00
|
|
|
const splitFileButton = document.createElement("button");
|
|
|
|
splitFileButton.classList.add("btn", "btn-primary", "pdf-actions_split-file-button");
|
2025-01-30 18:55:33 +00:00
|
|
|
splitFileButton.setAttribute('title', window.translations.split);
|
|
|
|
splitFileButton.innerHTML = `<span class="material-symbols-rounded">cut</span>`;
|
2024-09-07 13:25:39 +03:00
|
|
|
splitFileButton.onclick = this.splitFileButtonCallback;
|
|
|
|
insertFileButtonContainer.appendChild(splitFileButton);
|
|
|
|
|
2024-11-08 19:51:03 -03:00
|
|
|
const insertFileBlankButton = document.createElement("button");
|
|
|
|
insertFileBlankButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-blank-button");
|
2025-01-30 18:55:33 +00:00
|
|
|
insertFileBlankButton.setAttribute('title', window.translations.insertPageBreak);
|
|
|
|
insertFileBlankButton.innerHTML = `<span class="material-symbols-rounded">insert_page_break</span>`;
|
2024-11-08 19:51:03 -03:00
|
|
|
insertFileBlankButton.onclick = this.insertFileBlankButtonCallback;
|
|
|
|
insertFileButtonContainer.appendChild(insertFileBlankButton);
|
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
div.appendChild(insertFileButtonContainer);
|
|
|
|
|
|
|
|
// add this button to every element, but only show it on the last one :D
|
|
|
|
const insertFileButtonRightContainer = document.createElement("div");
|
|
|
|
insertFileButtonRightContainer.classList.add(
|
|
|
|
"pdf-actions_insert-file-button-container",
|
|
|
|
rightDirection,
|
|
|
|
`align-center-${rightDirection}`,
|
|
|
|
);
|
|
|
|
|
|
|
|
const insertFileButtonRight = document.createElement("button");
|
|
|
|
insertFileButtonRight.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button");
|
2024-05-05 15:12:30 +04:00
|
|
|
insertFileButtonRight.innerHTML = `<span class="material-symbols-rounded">add</span>`;
|
2024-09-05 17:14:22 +03:00
|
|
|
insertFileButtonRight.onclick = () => addFiles();
|
2024-02-16 22:49:06 +01:00
|
|
|
insertFileButtonRightContainer.appendChild(insertFileButtonRight);
|
2023-04-28 21:20:56 +02:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
div.appendChild(insertFileButtonRightContainer);
|
2023-04-29 12:43:12 +02:00
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
const adaptPageNumber = (pageNumber, div) => {
|
|
|
|
const pageNumberElement = document.createElement("span");
|
|
|
|
pageNumberElement.classList.add("page-number");
|
|
|
|
pageNumberElement.textContent = pageNumber;
|
2024-01-02 16:44:57 +05:30
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
div.insertBefore(pageNumberElement, div.firstChild);
|
|
|
|
};
|
2024-01-02 16:44:57 +05:30
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
div.addEventListener("mouseenter", () => {
|
2024-11-14 20:00:36 +00:00
|
|
|
window.updatePageNumbersAndCheckboxes();
|
2024-02-16 22:49:06 +01:00
|
|
|
const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1;
|
|
|
|
adaptPageNumber(pageNumber, div);
|
2024-11-14 20:00:36 +00:00
|
|
|
const checkbox = document.getElementById(`selectPageCheckbox-${pageNumber}`);
|
|
|
|
if (checkbox && !window.selectPage) {
|
|
|
|
checkbox.classList.remove("hidden");
|
|
|
|
}
|
2024-02-16 22:49:06 +01:00
|
|
|
});
|
2024-01-02 16:44:57 +05:30
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
div.addEventListener("mouseleave", () => {
|
2024-11-14 20:00:36 +00:00
|
|
|
const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1;
|
2024-02-16 22:49:06 +01:00
|
|
|
const pageNumberElement = div.querySelector(".page-number");
|
|
|
|
if (pageNumberElement) {
|
|
|
|
div.removeChild(pageNumberElement);
|
|
|
|
}
|
2024-11-14 20:00:36 +00:00
|
|
|
const checkbox = document.getElementById(`selectPageCheckbox-${pageNumber}`);
|
|
|
|
if (checkbox && !window.selectPage) {
|
|
|
|
checkbox.classList.add("hidden");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
document.addEventListener("selectedPagesUpdated", () => {
|
|
|
|
window.updateSelectedPagesDisplay();
|
2024-02-16 22:49:06 +01:00
|
|
|
});
|
|
|
|
return div;
|
|
|
|
}
|
2023-04-28 21:20:56 +02:00
|
|
|
}
|
|
|
|
|
2024-02-16 22:49:06 +01:00
|
|
|
export default PdfActionsManager;
|