mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-09-13 12:15:29 +02:00
Resolve conflicts using files from Stirling-2.0
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import {Command} from './command.js';
|
||||
|
||||
export class AddFilesCommand extends Command {
|
||||
constructor(element, selectedPages, addFilesAction, pagesContainer) {
|
||||
super();
|
||||
this.element = element;
|
||||
this.selectedPages = selectedPages;
|
||||
this.addFilesAction = addFilesAction;
|
||||
this.pagesContainer = pagesContainer;
|
||||
this.addedElements = [];
|
||||
}
|
||||
|
||||
async execute() {
|
||||
const undoBtn = document.getElementById('undo-btn');
|
||||
undoBtn.disabled = true;
|
||||
if (this.element) {
|
||||
const newElement = await this.addFilesAction(this.element);
|
||||
if (newElement) {
|
||||
this.addedElements = newElement;
|
||||
}
|
||||
} else {
|
||||
const newElement = await this.addFilesAction(false);
|
||||
if (newElement) {
|
||||
this.addedElements = newElement;
|
||||
}
|
||||
}
|
||||
undoBtn.disabled = false;
|
||||
}
|
||||
|
||||
undo() {
|
||||
this.addedElements.forEach((element) => {
|
||||
const nextSibling = element.nextSibling;
|
||||
this.pagesContainer.removeChild(element);
|
||||
|
||||
if (this.pagesContainer.childElementCount === 0) {
|
||||
const filenameInput = document.getElementById('filename-input');
|
||||
const downloadBtn = document.getElementById('export-button');
|
||||
|
||||
filenameInput.disabled = true;
|
||||
filenameInput.value = '';
|
||||
downloadBtn.disabled = true;
|
||||
}
|
||||
|
||||
element._nextSibling = nextSibling;
|
||||
});
|
||||
this.addedElements = [];
|
||||
}
|
||||
redo() {
|
||||
this.execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export class Command {
|
||||
execute() {}
|
||||
undo() {}
|
||||
redo() {}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Command} from './command.js';
|
||||
|
||||
export class CommandSequence extends Command {
|
||||
constructor(commands) {
|
||||
super();
|
||||
this.commands = commands;
|
||||
|
||||
}
|
||||
execute() {
|
||||
this.commands.forEach((command) => command.execute())
|
||||
}
|
||||
|
||||
undo() {
|
||||
this.commands.slice().reverse().forEach((command) => command.undo())
|
||||
}
|
||||
|
||||
redo() {
|
||||
this.execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { Command } from "./command.js";
|
||||
|
||||
export class DeletePageCommand extends Command {
|
||||
constructor(element, pagesContainer) {
|
||||
super();
|
||||
|
||||
this.element = element;
|
||||
this.pagesContainer = pagesContainer;
|
||||
|
||||
this.filenameInputValue = document.getElementById("filename-input").value;
|
||||
|
||||
const filenameParagraph = document.getElementById("filename");
|
||||
this.filenameParagraphText = filenameParagraph
|
||||
? filenameParagraph.innerText
|
||||
: "";
|
||||
}
|
||||
|
||||
execute() {
|
||||
this.nextSibling = this.element.nextSibling;
|
||||
|
||||
this.pagesContainer.removeChild(this.element);
|
||||
if (this.pagesContainer.childElementCount === 0) {
|
||||
const filenameInput = document.getElementById("filename-input");
|
||||
const downloadBtn = document.getElementById("export-button");
|
||||
|
||||
filenameInput.disabled = true;
|
||||
filenameInput.value = "";
|
||||
|
||||
downloadBtn.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
undo() {
|
||||
let node = this.nextSibling;
|
||||
if (node) this.pagesContainer.insertBefore(this.element, node);
|
||||
else this.pagesContainer.appendChild(this.element);
|
||||
|
||||
const pageNumberElement = this.element.querySelector(".page-number");
|
||||
if (pageNumberElement) {
|
||||
this.element.removeChild(pageNumberElement);
|
||||
}
|
||||
|
||||
const filenameInput = document.getElementById("filename-input");
|
||||
const downloadBtn = document.getElementById("export-button");
|
||||
|
||||
filenameInput.disabled = false;
|
||||
filenameInput.value = this.filenameInputValue;
|
||||
|
||||
downloadBtn.disabled = false;
|
||||
}
|
||||
|
||||
redo() {
|
||||
const pageNumberElement = this.element.querySelector(".page-number");
|
||||
if (pageNumberElement) {
|
||||
this.element.removeChild(pageNumberElement);
|
||||
}
|
||||
|
||||
this.pagesContainer.removeChild(this.element);
|
||||
if (this.pagesContainer.childElementCount === 0) {
|
||||
const filenameInput = document.getElementById("filename-input");
|
||||
const downloadBtn = document.getElementById("export-button");
|
||||
|
||||
filenameInput.disabled = true;
|
||||
filenameInput.value = "";
|
||||
|
||||
downloadBtn.disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import {Command} from './command.js';
|
||||
|
||||
export class MovePageCommand extends Command {
|
||||
constructor(startElement, endElement, pagesContainer, pagesContainerWrapper, scrollTo = false) {
|
||||
super();
|
||||
|
||||
this.pagesContainer = pagesContainer;
|
||||
const childArray = Array.from(this.pagesContainer.childNodes);
|
||||
|
||||
this.startIndex = childArray.indexOf(startElement);
|
||||
this.endIndex = childArray.indexOf(endElement);
|
||||
|
||||
this.startElement = startElement;
|
||||
this.endElement = endElement;
|
||||
|
||||
this.scrollTo = scrollTo;
|
||||
this.pagesContainerWrapper = pagesContainerWrapper;
|
||||
}
|
||||
execute() {
|
||||
// Check & remove page number elements here too if they exist because Firefox doesn't fire the relevant event on page move.
|
||||
const pageNumberElement = this.startElement.querySelector('.page-number');
|
||||
if (pageNumberElement) {
|
||||
this.startElement.removeChild(pageNumberElement);
|
||||
}
|
||||
|
||||
this.pagesContainer.removeChild(this.startElement);
|
||||
if (!this.endElement) {
|
||||
this.pagesContainer.append(this.startElement);
|
||||
} else {
|
||||
this.pagesContainer.insertBefore(this.startElement, this.endElement);
|
||||
}
|
||||
|
||||
if (this.scrollTo) {
|
||||
const {width} = this.startElement.getBoundingClientRect();
|
||||
const vector = this.endIndex !== -1 && this.startIndex > this.endIndex ? 0 - width : width;
|
||||
|
||||
this.pagesContainerWrapper.scroll({
|
||||
left: this.pagesContainerWrapper.scrollLeft + vector,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
undo() {
|
||||
if (this.startElement) {
|
||||
this.pagesContainer.removeChild(this.startElement);
|
||||
let previousNeighbour = Array.from(this.pagesContainer.childNodes)[this.startIndex];
|
||||
previousNeighbour?.insertAdjacentElement('beforebegin', this.startElement)
|
||||
?? this.pagesContainer.append(this.startElement);
|
||||
}
|
||||
|
||||
if (this.scrollTo) {
|
||||
const {width} = this.startElement.getBoundingClientRect();
|
||||
const vector = this.endIndex === -1 || this.startIndex <= this.endIndex ? 0 - width : width;
|
||||
|
||||
this.pagesContainerWrapper.scroll({
|
||||
left: this.pagesContainerWrapper.scrollLeft - vector,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
redo() {
|
||||
this.execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import {Command} from './command.js';
|
||||
|
||||
export class PageBreakCommand extends Command {
|
||||
constructor(elements, isSelectedInWindow, selectedPages, pageBreakCallback, pagesContainer) {
|
||||
super();
|
||||
this.elements = elements;
|
||||
this.isSelectedInWindow = isSelectedInWindow;
|
||||
this.selectedPages = selectedPages;
|
||||
this.pageBreakCallback = pageBreakCallback;
|
||||
this.pagesContainer = pagesContainer;
|
||||
this.addedElements = [];
|
||||
this.originalStates = Array.from(elements, (element) => ({
|
||||
element,
|
||||
hasContent: element.innerHTML.trim() !== '',
|
||||
}));
|
||||
}
|
||||
|
||||
async execute() {
|
||||
const undoBtn = document.getElementById('undo-btn');
|
||||
undoBtn.disabled = true;
|
||||
for (const [index, element] of this.elements.entries()) {
|
||||
if (!this.isSelectedInWindow || this.selectedPages.includes(index)) {
|
||||
if (index !== 0) {
|
||||
const newElement = await this.pageBreakCallback(element, this.addedElements);
|
||||
|
||||
if (newElement) {
|
||||
this.addedElements = newElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
undoBtn.disabled = false;
|
||||
}
|
||||
|
||||
undo() {
|
||||
this.addedElements.forEach((element) => {
|
||||
const nextSibling = element.nextSibling;
|
||||
|
||||
this.pagesContainer.removeChild(element);
|
||||
|
||||
if (this.pagesContainer.childElementCount === 0) {
|
||||
const filenameInput = document.getElementById('filename-input');
|
||||
const filenameParagraph = document.getElementById('filename');
|
||||
const downloadBtn = document.getElementById('export-button');
|
||||
|
||||
filenameInput.disabled = true;
|
||||
filenameInput.value = '';
|
||||
filenameParagraph.innerText = '';
|
||||
downloadBtn.disabled = true;
|
||||
}
|
||||
|
||||
element._nextSibling = nextSibling;
|
||||
});
|
||||
}
|
||||
|
||||
redo() {
|
||||
this.execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import { Command } from "./command.js";
|
||||
|
||||
export class RemoveSelectedCommand extends Command {
|
||||
constructor(pagesContainer, selectedPages, updatePageNumbersAndCheckboxes) {
|
||||
super();
|
||||
this.pagesContainer = pagesContainer;
|
||||
this.selectedPages = selectedPages;
|
||||
|
||||
this.deletedChildren = [];
|
||||
|
||||
if (updatePageNumbersAndCheckboxes) {
|
||||
this.updatePageNumbersAndCheckboxes = updatePageNumbersAndCheckboxes;
|
||||
} else {
|
||||
const pageDivs = document.querySelectorAll(".pdf-actions_container");
|
||||
|
||||
pageDivs.forEach((div, index) => {
|
||||
const pageNumber = index + 1;
|
||||
const checkbox = div.querySelector(".pdf-actions_checkbox");
|
||||
checkbox.id = `selectPageCheckbox-${pageNumber}`;
|
||||
checkbox.setAttribute("data-page-number", pageNumber);
|
||||
checkbox.checked = window.selectedPages.includes(pageNumber);
|
||||
});
|
||||
}
|
||||
|
||||
const filenameInput = document.getElementById("filename-input");
|
||||
const filenameParagraph = document.getElementById("filename");
|
||||
|
||||
this.originalFilenameInputValue = filenameInput ? filenameInput.value : "";
|
||||
if (filenameParagraph)
|
||||
this.originalFilenameParagraphText = filenameParagraph.innerText;
|
||||
}
|
||||
|
||||
execute() {
|
||||
let deletions = 0;
|
||||
|
||||
this.selectedPages.forEach((pageIndex) => {
|
||||
const adjustedIndex = pageIndex - 1 - deletions;
|
||||
const child = this.pagesContainer.children[adjustedIndex];
|
||||
if (child) {
|
||||
this.pagesContainer.removeChild(child);
|
||||
deletions++;
|
||||
|
||||
this.deletedChildren.push({
|
||||
idx: adjustedIndex,
|
||||
childNode: child,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (this.pagesContainer.childElementCount === 0) {
|
||||
const filenameInput = document.getElementById("filename-input");
|
||||
const filenameParagraph = document.getElementById("filename");
|
||||
const downloadBtn = document.getElementById("export-button");
|
||||
|
||||
if (filenameInput) filenameInput.disabled = true;
|
||||
filenameInput.value = "";
|
||||
if (filenameParagraph) filenameParagraph.innerText = "";
|
||||
|
||||
downloadBtn.disabled = true;
|
||||
}
|
||||
|
||||
window.selectedPages = [];
|
||||
this.updatePageNumbersAndCheckboxes();
|
||||
document.dispatchEvent(new Event("selectedPagesUpdated"));
|
||||
}
|
||||
|
||||
undo() {
|
||||
while (this.deletedChildren.length > 0) {
|
||||
let deletedChild = this.deletedChildren.pop();
|
||||
if (this.pagesContainer.children.length <= deletedChild.idx)
|
||||
this.pagesContainer.appendChild(deletedChild.childNode);
|
||||
else {
|
||||
this.pagesContainer.insertBefore(
|
||||
deletedChild.childNode,
|
||||
this.pagesContainer.children[deletedChild.idx]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.pagesContainer.childElementCount > 0) {
|
||||
const filenameInput = document.getElementById("filename-input");
|
||||
const filenameParagraph = document.getElementById("filename");
|
||||
const downloadBtn = document.getElementById("export-button");
|
||||
|
||||
if (filenameInput) filenameInput.disabled = false;
|
||||
filenameInput.value = this.originalFilenameInputValue;
|
||||
if (filenameParagraph)
|
||||
filenameParagraph.innerText = this.originalFilenameParagraphText;
|
||||
|
||||
downloadBtn.disabled = false;
|
||||
}
|
||||
|
||||
window.selectedPages = this.selectedPages;
|
||||
this.updatePageNumbersAndCheckboxes();
|
||||
document.dispatchEvent(new Event("selectedPagesUpdated"));
|
||||
}
|
||||
|
||||
redo() {
|
||||
this.execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { Command } from "./command.js";
|
||||
|
||||
export class RotateElementCommand extends Command {
|
||||
constructor(element, degree) {
|
||||
super();
|
||||
this.element = element;
|
||||
this.degree = degree;
|
||||
}
|
||||
|
||||
execute() {
|
||||
let lastTransform = this.element.style.rotate;
|
||||
if (!lastTransform) {
|
||||
lastTransform = "0";
|
||||
}
|
||||
const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, ""));
|
||||
const newAngle = lastAngle + parseInt(this.degree);
|
||||
|
||||
this.element.style.rotate = newAngle + "deg";
|
||||
}
|
||||
|
||||
undo() {
|
||||
let lastTransform = this.element.style.rotate;
|
||||
if (!lastTransform) {
|
||||
lastTransform = "0";
|
||||
}
|
||||
|
||||
const currentAngle = parseInt(lastTransform.replace(/[^\d-]/g, ""));
|
||||
const undoAngle = currentAngle + -parseInt(this.degree);
|
||||
|
||||
this.element.style.rotate = undoAngle + "deg";
|
||||
}
|
||||
|
||||
redo() {
|
||||
this.execute();
|
||||
}
|
||||
}
|
||||
|
||||
export class RotateAllCommand extends Command {
|
||||
constructor(elements, degree) {
|
||||
super();
|
||||
this.elements = elements;
|
||||
this.degree = degree;
|
||||
}
|
||||
|
||||
execute() {
|
||||
for (let element of this.elements) {
|
||||
let lastTransform = element.style.rotate;
|
||||
if (!lastTransform) {
|
||||
lastTransform = "0";
|
||||
}
|
||||
const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, ""));
|
||||
const newAngle = lastAngle + this.degree;
|
||||
|
||||
element.style.rotate = newAngle + "deg";
|
||||
}
|
||||
}
|
||||
|
||||
undo() {
|
||||
for (let element of this.elements) {
|
||||
let lastTransform = element.style.rotate;
|
||||
if (!lastTransform) {
|
||||
lastTransform = "0";
|
||||
}
|
||||
const currentAngle = parseInt(lastTransform.replace(/[^\d-]/g, ""));
|
||||
const undoAngle = currentAngle + -this.degree;
|
||||
|
||||
element.style.rotate = undoAngle + "deg";
|
||||
}
|
||||
}
|
||||
|
||||
redo() {
|
||||
this.execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Command } from "./command.js";
|
||||
|
||||
export class SelectPageCommand extends Command {
|
||||
constructor(pageNumber, checkbox) {
|
||||
super();
|
||||
this.pageNumber = pageNumber;
|
||||
this.selectCheckbox = checkbox;
|
||||
}
|
||||
|
||||
execute() {
|
||||
if (this.selectCheckbox.checked) {
|
||||
//adds to array of selected pages
|
||||
window.selectedPages.push(this.pageNumber);
|
||||
} else {
|
||||
//remove page from selected pages array
|
||||
const index = window.selectedPages.indexOf(this.pageNumber);
|
||||
if (index !== -1) {
|
||||
window.selectedPages.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (window.selectedPages.length > 0 && !window.selectPage) {
|
||||
window.toggleSelectPageVisibility();
|
||||
}
|
||||
if (window.selectedPages.length == 0 && window.selectPage) {
|
||||
window.toggleSelectPageVisibility();
|
||||
}
|
||||
|
||||
window.updateSelectedPagesDisplay();
|
||||
}
|
||||
|
||||
undo() {
|
||||
this.selectCheckbox.checked = !this.selectCheckbox.checked;
|
||||
if (this.selectCheckbox.checked) {
|
||||
//adds to array of selected pages
|
||||
window.selectedPages.push(this.pageNumber);
|
||||
} else {
|
||||
//remove page from selected pages array
|
||||
const index = window.selectedPages.indexOf(this.pageNumber);
|
||||
if (index !== -1) {
|
||||
window.selectedPages.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (window.selectedPages.length > 0 && !window.selectPage) {
|
||||
window.toggleSelectPageVisibility();
|
||||
}
|
||||
if (window.selectedPages.length == 0 && window.selectPage) {
|
||||
window.toggleSelectPageVisibility();
|
||||
}
|
||||
|
||||
window.updateSelectedPagesDisplay();
|
||||
}
|
||||
|
||||
redo() {
|
||||
this.selectCheckbox.checked = !this.selectCheckbox.checked;
|
||||
this.execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import { Command } from "./command.js";
|
||||
|
||||
export class SplitFileCommand extends Command {
|
||||
constructor(element, splitClass) {
|
||||
super();
|
||||
this.element = element;
|
||||
this.splitClass = splitClass;
|
||||
}
|
||||
|
||||
execute() {
|
||||
this.element.classList.toggle(this.splitClass);
|
||||
}
|
||||
|
||||
undo() {
|
||||
this.element.classList.toggle(this.splitClass);
|
||||
}
|
||||
|
||||
redo() {
|
||||
this.execute();
|
||||
}
|
||||
}
|
||||
|
||||
export class SplitAllCommand extends Command {
|
||||
constructor(elements, isSelectedInWindow, selectedPages, splitClass) {
|
||||
super();
|
||||
this.elements = elements;
|
||||
this.isSelectedInWindow = isSelectedInWindow;
|
||||
this.selectedPages = selectedPages;
|
||||
this.splitClass = splitClass;
|
||||
}
|
||||
|
||||
execute() {
|
||||
if (!this.isSelectedInWindow) {
|
||||
const hasSplit = this._hasSplit(this.elements, this.splitClass);
|
||||
if (hasSplit) {
|
||||
this.elements.forEach((page) => {
|
||||
page.classList.remove(this.splitClass);
|
||||
});
|
||||
} else {
|
||||
this.elements.forEach((page) => {
|
||||
page.classList.add(this.splitClass);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.elements.forEach((page, index) => {
|
||||
const pageIndex = index;
|
||||
if (this.isSelectedInWindow && !this.selectedPages.includes(pageIndex))
|
||||
return;
|
||||
|
||||
if (page.classList.contains(this.splitClass)) {
|
||||
page.classList.remove(this.splitClass);
|
||||
} else {
|
||||
page.classList.add(this.splitClass);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_hasSplit() {
|
||||
if (!this.elements || this.elements.length == 0) return false;
|
||||
|
||||
for (const node of this.elements) {
|
||||
if (node.classList.contains(this.splitClass)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
undo() {
|
||||
if (!this.isSelectedInWindow) {
|
||||
const hasSplit = this._hasSplit(this.elements, this.splitClass);
|
||||
if (hasSplit) {
|
||||
this.elements.forEach((page) => {
|
||||
page.classList.remove(this.splitClass);
|
||||
});
|
||||
} else {
|
||||
this.elements.forEach((page) => {
|
||||
page.classList.add(this.splitClass);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.elements.forEach((page, index) => {
|
||||
const pageIndex = index;
|
||||
if (this.isSelectedInWindow && !this.selectedPages.includes(pageIndex))
|
||||
return;
|
||||
|
||||
if (page.classList.contains(this.splitClass)) {
|
||||
page.classList.remove(this.splitClass);
|
||||
} else {
|
||||
page.classList.add(this.splitClass);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
redo() {
|
||||
this.execute();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user