mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-11-16 01:21:16 +01:00
# Description of Changes <!-- Please provide a summary of the changes, including: - What was changed - Why the change was made - Any challenges encountered Closes #(issue_number) --> --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/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/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] 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/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details.
165 lines
5.2 KiB
TypeScript
165 lines
5.2 KiB
TypeScript
import { PDFDocument, PDFPage } from '../types/pageEditor';
|
|
|
|
/**
|
|
* Service for applying DOM changes to PDF document state
|
|
* Reads current DOM state and updates the document accordingly
|
|
*/
|
|
export class DocumentManipulationService {
|
|
/**
|
|
* Apply all DOM changes (rotations, splits, reordering) to document state
|
|
* Returns single document or multiple documents if splits are present
|
|
*/
|
|
applyDOMChangesToDocument(pdfDocument: PDFDocument, currentDisplayOrder?: PDFDocument, splitPositions?: Set<number>): PDFDocument | PDFDocument[] {
|
|
// Use current display order (from React state) if provided, otherwise use original order
|
|
const baseDocument = currentDisplayOrder || pdfDocument;
|
|
|
|
// Apply DOM changes to each page (rotation only now, splits are position-based)
|
|
let updatedPages = baseDocument.pages.map(page => this.applyPageChanges(page));
|
|
|
|
// Convert position-based splits to page-based splits for export
|
|
if (splitPositions && splitPositions.size > 0) {
|
|
updatedPages = updatedPages.map((page, index) => ({
|
|
...page,
|
|
splitAfter: splitPositions.has(index)
|
|
}));
|
|
}
|
|
|
|
// Create final document with reordered pages and applied changes
|
|
const finalDocument = {
|
|
...pdfDocument, // Use original document metadata but updated pages
|
|
pages: updatedPages // Use reordered pages with applied changes
|
|
};
|
|
|
|
// Check for splits and return multiple documents if needed
|
|
if (splitPositions && splitPositions.size > 0) {
|
|
return this.createSplitDocuments(finalDocument);
|
|
}
|
|
|
|
return finalDocument;
|
|
}
|
|
|
|
/**
|
|
* Check if document has split markers
|
|
*/
|
|
private hasSplitMarkers(document: PDFDocument): boolean {
|
|
return document.pages.some(page => page.splitAfter);
|
|
}
|
|
|
|
/**
|
|
* Create multiple documents from split markers
|
|
*/
|
|
private createSplitDocuments(document: PDFDocument): PDFDocument[] {
|
|
const documents: PDFDocument[] = [];
|
|
const splitPoints: number[] = [];
|
|
|
|
// Find split points
|
|
document.pages.forEach((page, index) => {
|
|
if (page.splitAfter) {
|
|
splitPoints.push(index + 1);
|
|
}
|
|
});
|
|
|
|
// Add end point if not already there
|
|
if (splitPoints.length === 0 || splitPoints[splitPoints.length - 1] !== document.pages.length) {
|
|
splitPoints.push(document.pages.length);
|
|
}
|
|
|
|
let startIndex = 0;
|
|
let partNumber = 1;
|
|
|
|
for (const endIndex of splitPoints) {
|
|
const segmentPages = document.pages.slice(startIndex, endIndex);
|
|
|
|
if (segmentPages.length > 0) {
|
|
documents.push({
|
|
...document,
|
|
id: `${document.id}_part_${partNumber}`,
|
|
name: `${document.name.replace(/\.pdf$/i, '')}_part_${partNumber}.pdf`,
|
|
pages: segmentPages,
|
|
totalPages: segmentPages.length
|
|
});
|
|
partNumber++;
|
|
}
|
|
|
|
startIndex = endIndex;
|
|
}
|
|
|
|
return documents;
|
|
}
|
|
|
|
/**
|
|
* Apply DOM changes for a single page
|
|
*/
|
|
private applyPageChanges(page: PDFPage): PDFPage {
|
|
// Find the DOM element for this page
|
|
const pageElement = document.querySelector(`[data-page-id="${page.id}"]`);
|
|
if (!pageElement) {
|
|
return page;
|
|
}
|
|
|
|
const updatedPage = { ...page };
|
|
|
|
// Apply rotation changes from DOM
|
|
updatedPage.rotation = this.getRotationFromDOM(pageElement, page);
|
|
|
|
return updatedPage;
|
|
}
|
|
|
|
/**
|
|
* Read rotation from DOM element
|
|
*/
|
|
private getRotationFromDOM(pageElement: Element, originalPage: PDFPage): number {
|
|
const img = pageElement.querySelector('img');
|
|
if (img) {
|
|
const originalRotation = parseInt(img.getAttribute('data-original-rotation') || '0');
|
|
|
|
const currentTransform = img.style.transform || '';
|
|
const rotationMatch = currentTransform.match(/rotate\((-?\d+)deg\)/);
|
|
const visualRotation = rotationMatch ? parseInt(rotationMatch[1]) : originalRotation;
|
|
|
|
const userChange = ((visualRotation - originalRotation) % 360 + 360) % 360;
|
|
|
|
let finalRotation = (originalPage.rotation + userChange) % 360;
|
|
if (finalRotation === 360) finalRotation = 0;
|
|
|
|
return finalRotation;
|
|
}
|
|
|
|
return originalPage.rotation;
|
|
}
|
|
|
|
/**
|
|
* Reset all DOM changes (useful for "discard changes" functionality)
|
|
*/
|
|
resetDOMToDocumentState(pdfDocument: PDFDocument): void {
|
|
console.log('DocumentManipulationService: Resetting DOM to match document state');
|
|
|
|
pdfDocument.pages.forEach(page => {
|
|
const pageElement = document.querySelector(`[data-page-id="${page.id}"]`);
|
|
if (pageElement) {
|
|
const img = pageElement.querySelector('img');
|
|
if (img) {
|
|
// Reset rotation to match document state
|
|
img.style.transform = `rotate(${page.rotation}deg)`;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Check if DOM state differs from document state
|
|
*/
|
|
hasUnsavedChanges(pdfDocument: PDFDocument): boolean {
|
|
return pdfDocument.pages.some(page => {
|
|
const pageElement = document.querySelector(`[data-page-id="${page.id}"]`);
|
|
if (pageElement) {
|
|
const domRotation = this.getRotationFromDOM(pageElement, page);
|
|
return domRotation !== page.rotation;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
}
|
|
|
|
// Export singleton instance
|
|
export const documentManipulationService = new DocumentManipulationService(); |