feat:Setup Prettier for code formatting
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import { showLoader, hideLoader, showAlert } from '../ui.js';
|
||||
import { readFileAsArrayBuffer } from '../utils/helpers.js';
|
||||
import { icons, createIcons } from "lucide";
|
||||
import { icons, createIcons } from 'lucide';
|
||||
|
||||
const state = {
|
||||
pdfDoc1: null,
|
||||
pdfDoc2: null,
|
||||
currentPage: 1,
|
||||
viewMode: 'overlay',
|
||||
isSyncScroll: true,
|
||||
pdfDoc1: null,
|
||||
pdfDoc2: null,
|
||||
currentPage: 1,
|
||||
viewMode: 'overlay',
|
||||
isSyncScroll: true,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -17,110 +17,137 @@ const state = {
|
||||
* @param {HTMLCanvasElement} canvas - The canvas element to draw on.
|
||||
* @param {HTMLElement} container - The container to fit the canvas into.
|
||||
*/
|
||||
async function renderPage(pdfDoc: any, pageNum: any, canvas: any, container: any) {
|
||||
const page = await pdfDoc.getPage(pageNum);
|
||||
async function renderPage(
|
||||
pdfDoc: any,
|
||||
pageNum: any,
|
||||
canvas: any,
|
||||
container: any
|
||||
) {
|
||||
const page = await pdfDoc.getPage(pageNum);
|
||||
|
||||
// Calculate scale to fit the container width.
|
||||
const containerWidth = container.clientWidth - 2; // Subtract border width
|
||||
const viewport = page.getViewport({ scale: 1.0 });
|
||||
const scale = containerWidth / viewport.width;
|
||||
const scaledViewport = page.getViewport({ scale: scale });
|
||||
// Calculate scale to fit the container width.
|
||||
const containerWidth = container.clientWidth - 2; // Subtract border width
|
||||
const viewport = page.getViewport({ scale: 1.0 });
|
||||
const scale = containerWidth / viewport.width;
|
||||
const scaledViewport = page.getViewport({ scale: scale });
|
||||
|
||||
canvas.width = scaledViewport.width;
|
||||
canvas.height = scaledViewport.height;
|
||||
canvas.width = scaledViewport.width;
|
||||
canvas.height = scaledViewport.height;
|
||||
|
||||
await page.render({
|
||||
canvasContext: canvas.getContext('2d'),
|
||||
viewport: scaledViewport,
|
||||
}).promise;
|
||||
await page.render({
|
||||
canvasContext: canvas.getContext('2d'),
|
||||
viewport: scaledViewport,
|
||||
}).promise;
|
||||
}
|
||||
|
||||
|
||||
async function renderBothPages() {
|
||||
if (!state.pdfDoc1 || !state.pdfDoc2) return;
|
||||
if (!state.pdfDoc1 || !state.pdfDoc2) return;
|
||||
|
||||
showLoader(`Loading page ${state.currentPage}...`);
|
||||
showLoader(`Loading page ${state.currentPage}...`);
|
||||
|
||||
const canvas1 = document.getElementById('canvas-compare-1');
|
||||
const canvas2 = document.getElementById('canvas-compare-2');
|
||||
const panel1 = document.getElementById('panel-1');
|
||||
const panel2 = document.getElementById('panel-2');
|
||||
const wrapper = document.getElementById('compare-viewer-wrapper');
|
||||
const canvas1 = document.getElementById('canvas-compare-1');
|
||||
const canvas2 = document.getElementById('canvas-compare-2');
|
||||
const panel1 = document.getElementById('panel-1');
|
||||
const panel2 = document.getElementById('panel-2');
|
||||
const wrapper = document.getElementById('compare-viewer-wrapper');
|
||||
|
||||
// Determine the correct container based on the view mode
|
||||
const container1 = state.viewMode === 'overlay' ? wrapper : panel1;
|
||||
const container2 = state.viewMode === 'overlay' ? wrapper : panel2;
|
||||
// Determine the correct container based on the view mode
|
||||
const container1 = state.viewMode === 'overlay' ? wrapper : panel1;
|
||||
const container2 = state.viewMode === 'overlay' ? wrapper : panel2;
|
||||
|
||||
await Promise.all([
|
||||
renderPage(state.pdfDoc1, Math.min(state.currentPage, state.pdfDoc1.numPages), canvas1, container1),
|
||||
renderPage(state.pdfDoc2, Math.min(state.currentPage, state.pdfDoc2.numPages), canvas2, container2)
|
||||
]);
|
||||
await Promise.all([
|
||||
renderPage(
|
||||
state.pdfDoc1,
|
||||
Math.min(state.currentPage, state.pdfDoc1.numPages),
|
||||
canvas1,
|
||||
container1
|
||||
),
|
||||
renderPage(
|
||||
state.pdfDoc2,
|
||||
Math.min(state.currentPage, state.pdfDoc2.numPages),
|
||||
canvas2,
|
||||
container2
|
||||
),
|
||||
]);
|
||||
|
||||
updateNavControls();
|
||||
hideLoader();
|
||||
updateNavControls();
|
||||
hideLoader();
|
||||
}
|
||||
|
||||
function updateNavControls() {
|
||||
const maxPages = Math.max(state.pdfDoc1?.numPages || 0, state.pdfDoc2?.numPages || 0);
|
||||
// @ts-expect-error TS(2322) FIXME: Type 'number' is not assignable to type 'string'.
|
||||
document.getElementById('current-page-display-compare').textContent = state.currentPage;
|
||||
// @ts-expect-error TS(2322) FIXME: Type 'number' is not assignable to type 'string'.
|
||||
document.getElementById('total-pages-display-compare').textContent = maxPages;
|
||||
// @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message
|
||||
document.getElementById('prev-page-compare').disabled = state.currentPage <= 1;
|
||||
// @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message
|
||||
document.getElementById('next-page-compare').disabled = state.currentPage >= maxPages;
|
||||
const maxPages = Math.max(
|
||||
state.pdfDoc1?.numPages || 0,
|
||||
state.pdfDoc2?.numPages || 0
|
||||
);
|
||||
// @ts-expect-error TS(2322) FIXME: Type 'number' is not assignable to type 'string'.
|
||||
document.getElementById('current-page-display-compare').textContent =
|
||||
state.currentPage;
|
||||
// @ts-expect-error TS(2322) FIXME: Type 'number' is not assignable to type 'string'.
|
||||
document.getElementById('total-pages-display-compare').textContent = maxPages;
|
||||
// @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message
|
||||
document.getElementById('prev-page-compare').disabled =
|
||||
state.currentPage <= 1;
|
||||
// @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message
|
||||
document.getElementById('next-page-compare').disabled =
|
||||
state.currentPage >= maxPages;
|
||||
}
|
||||
|
||||
async function setupFileInput(inputId: any, docKey: any, displayId: any) {
|
||||
const fileInput = document.getElementById(inputId);
|
||||
const dropZone = document.getElementById(`drop-zone-${inputId.slice(-1)}`);
|
||||
const fileInput = document.getElementById(inputId);
|
||||
const dropZone = document.getElementById(`drop-zone-${inputId.slice(-1)}`);
|
||||
|
||||
const handleFile = async (file: any) => {
|
||||
if (!file || file.type !== 'application/pdf') return showAlert('Invalid File', 'Please select a valid PDF file.');
|
||||
const handleFile = async (file: any) => {
|
||||
if (!file || file.type !== 'application/pdf')
|
||||
return showAlert('Invalid File', 'Please select a valid PDF file.');
|
||||
|
||||
const displayDiv = document.getElementById(displayId);
|
||||
displayDiv.textContent = '';
|
||||
const displayDiv = document.getElementById(displayId);
|
||||
displayDiv.textContent = '';
|
||||
|
||||
// 2. Create the icon element
|
||||
const icon = document.createElement('i');
|
||||
icon.setAttribute('data-lucide', 'check-circle');
|
||||
icon.className = 'w-10 h-10 mb-3 text-green-500';
|
||||
// 2. Create the icon element
|
||||
const icon = document.createElement('i');
|
||||
icon.setAttribute('data-lucide', 'check-circle');
|
||||
icon.className = 'w-10 h-10 mb-3 text-green-500';
|
||||
|
||||
// 3. Create the paragraph element for the file name
|
||||
const p = document.createElement('p');
|
||||
p.className = 'text-sm text-gray-300 truncate';
|
||||
// 3. Create the paragraph element for the file name
|
||||
const p = document.createElement('p');
|
||||
p.className = 'text-sm text-gray-300 truncate';
|
||||
|
||||
// 4. Set the file name safely using textContent
|
||||
p.textContent = file.name;
|
||||
// 4. Set the file name safely using textContent
|
||||
p.textContent = file.name;
|
||||
|
||||
// 5. Append the safe elements to the container
|
||||
displayDiv.append(icon, p);
|
||||
createIcons({ icons });
|
||||
// 5. Append the safe elements to the container
|
||||
displayDiv.append(icon, p);
|
||||
createIcons({ icons });
|
||||
|
||||
try {
|
||||
showLoader(`Loading ${file.name}...`);
|
||||
const pdfBytes = await readFileAsArrayBuffer(file);
|
||||
// @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'.
|
||||
state[docKey] = await pdfjsLib.getDocument(pdfBytes).promise;
|
||||
try {
|
||||
showLoader(`Loading ${file.name}...`);
|
||||
const pdfBytes = await readFileAsArrayBuffer(file);
|
||||
// @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'.
|
||||
state[docKey] = await pdfjsLib.getDocument(pdfBytes).promise;
|
||||
|
||||
if (state.pdfDoc1 && state.pdfDoc2) {
|
||||
document.getElementById('compare-viewer').classList.remove('hidden');
|
||||
state.currentPage = 1;
|
||||
await renderBothPages();
|
||||
}
|
||||
} catch (e) {
|
||||
showAlert('Error', 'Could not load PDF. It may be corrupt or password-protected.');
|
||||
console.error(e);
|
||||
} finally {
|
||||
hideLoader();
|
||||
}
|
||||
};
|
||||
if (state.pdfDoc1 && state.pdfDoc2) {
|
||||
document.getElementById('compare-viewer').classList.remove('hidden');
|
||||
state.currentPage = 1;
|
||||
await renderBothPages();
|
||||
}
|
||||
} catch (e) {
|
||||
showAlert(
|
||||
'Error',
|
||||
'Could not load PDF. It may be corrupt or password-protected.'
|
||||
);
|
||||
console.error(e);
|
||||
} finally {
|
||||
hideLoader();
|
||||
}
|
||||
};
|
||||
|
||||
// @ts-expect-error TS(2339) FIXME: Property 'files' does not exist on type 'EventTarg... Remove this comment to see the full error message
|
||||
fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));
|
||||
dropZone.addEventListener('dragover', (e) => e.preventDefault());
|
||||
dropZone.addEventListener('drop', (e) => { e.preventDefault(); handleFile(e.dataTransfer.files[0]); });
|
||||
// @ts-expect-error TS(2339) FIXME: Property 'files' does not exist on type 'EventTarg... Remove this comment to see the full error message
|
||||
fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));
|
||||
dropZone.addEventListener('dragover', (e) => e.preventDefault());
|
||||
dropZone.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
handleFile(e.dataTransfer.files[0]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,81 +155,92 @@ async function setupFileInput(inputId: any, docKey: any, displayId: any) {
|
||||
* @param {'overlay' | 'side-by-side'} mode
|
||||
*/
|
||||
function setViewMode(mode: any) {
|
||||
state.viewMode = mode;
|
||||
const wrapper = document.getElementById('compare-viewer-wrapper');
|
||||
const overlayControls = document.getElementById('overlay-controls');
|
||||
const sideControls = document.getElementById('side-by-side-controls');
|
||||
const btnOverlay = document.getElementById('view-mode-overlay');
|
||||
const btnSide = document.getElementById('view-mode-side');
|
||||
const canvas2 = document.getElementById('canvas-compare-2');
|
||||
const opacitySlider = document.getElementById('opacity-slider');
|
||||
state.viewMode = mode;
|
||||
const wrapper = document.getElementById('compare-viewer-wrapper');
|
||||
const overlayControls = document.getElementById('overlay-controls');
|
||||
const sideControls = document.getElementById('side-by-side-controls');
|
||||
const btnOverlay = document.getElementById('view-mode-overlay');
|
||||
const btnSide = document.getElementById('view-mode-side');
|
||||
const canvas2 = document.getElementById('canvas-compare-2');
|
||||
const opacitySlider = document.getElementById('opacity-slider');
|
||||
|
||||
|
||||
if (mode === 'overlay') {
|
||||
wrapper.className = 'compare-viewer-wrapper overlay-mode';
|
||||
overlayControls.classList.remove('hidden');
|
||||
sideControls.classList.add('hidden');
|
||||
btnOverlay.classList.add('bg-indigo-600');
|
||||
btnSide.classList.remove('bg-indigo-600');
|
||||
// @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message
|
||||
canvas2.style.opacity = opacitySlider.value;
|
||||
} else {
|
||||
wrapper.className = 'compare-viewer-wrapper side-by-side-mode';
|
||||
overlayControls.classList.add('hidden');
|
||||
sideControls.classList.remove('hidden');
|
||||
btnOverlay.classList.remove('bg-indigo-600');
|
||||
btnSide.classList.add('bg-indigo-600');
|
||||
// CHANGE: When switching to side-by-side, reset the canvas opacity to 1.
|
||||
canvas2.style.opacity = '1';
|
||||
}
|
||||
renderBothPages();
|
||||
if (mode === 'overlay') {
|
||||
wrapper.className = 'compare-viewer-wrapper overlay-mode';
|
||||
overlayControls.classList.remove('hidden');
|
||||
sideControls.classList.add('hidden');
|
||||
btnOverlay.classList.add('bg-indigo-600');
|
||||
btnSide.classList.remove('bg-indigo-600');
|
||||
// @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message
|
||||
canvas2.style.opacity = opacitySlider.value;
|
||||
} else {
|
||||
wrapper.className = 'compare-viewer-wrapper side-by-side-mode';
|
||||
overlayControls.classList.add('hidden');
|
||||
sideControls.classList.remove('hidden');
|
||||
btnOverlay.classList.remove('bg-indigo-600');
|
||||
btnSide.classList.add('bg-indigo-600');
|
||||
// CHANGE: When switching to side-by-side, reset the canvas opacity to 1.
|
||||
canvas2.style.opacity = '1';
|
||||
}
|
||||
renderBothPages();
|
||||
}
|
||||
|
||||
export function setupCompareTool() {
|
||||
setupFileInput('file-input-1', 'pdfDoc1', 'file-display-1');
|
||||
setupFileInput('file-input-2', 'pdfDoc2', 'file-display-2');
|
||||
setupFileInput('file-input-1', 'pdfDoc1', 'file-display-1');
|
||||
setupFileInput('file-input-2', 'pdfDoc2', 'file-display-2');
|
||||
|
||||
document.getElementById('prev-page-compare').addEventListener('click', () => {
|
||||
if (state.currentPage > 1) { state.currentPage--; renderBothPages(); }
|
||||
});
|
||||
document.getElementById('next-page-compare').addEventListener('click', () => {
|
||||
const maxPages = Math.max(state.pdfDoc1.numPages, state.pdfDoc2.numPages);
|
||||
if (state.currentPage < maxPages) { state.currentPage++; renderBothPages(); }
|
||||
});
|
||||
document.getElementById('prev-page-compare').addEventListener('click', () => {
|
||||
if (state.currentPage > 1) {
|
||||
state.currentPage--;
|
||||
renderBothPages();
|
||||
}
|
||||
});
|
||||
document.getElementById('next-page-compare').addEventListener('click', () => {
|
||||
const maxPages = Math.max(state.pdfDoc1.numPages, state.pdfDoc2.numPages);
|
||||
if (state.currentPage < maxPages) {
|
||||
state.currentPage++;
|
||||
renderBothPages();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('view-mode-overlay').addEventListener('click', () => setViewMode('overlay'));
|
||||
document.getElementById('view-mode-side').addEventListener('click', () => setViewMode('side-by-side'));
|
||||
document
|
||||
.getElementById('view-mode-overlay')
|
||||
.addEventListener('click', () => setViewMode('overlay'));
|
||||
document
|
||||
.getElementById('view-mode-side')
|
||||
.addEventListener('click', () => setViewMode('side-by-side'));
|
||||
|
||||
const canvas2 = document.getElementById('canvas-compare-2');
|
||||
document.getElementById('flicker-btn').addEventListener('click', () => {
|
||||
canvas2.style.transition = 'opacity 150ms ease-in-out';
|
||||
canvas2.style.opacity = (canvas2.style.opacity === '0') ? '1' : '0';
|
||||
});
|
||||
document.getElementById('opacity-slider').addEventListener('input', (e) => {
|
||||
canvas2.style.transition = '';
|
||||
// @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'EventTarg... Remove this comment to see the full error message
|
||||
canvas2.style.opacity = e.target.value;
|
||||
});
|
||||
const canvas2 = document.getElementById('canvas-compare-2');
|
||||
document.getElementById('flicker-btn').addEventListener('click', () => {
|
||||
canvas2.style.transition = 'opacity 150ms ease-in-out';
|
||||
canvas2.style.opacity = canvas2.style.opacity === '0' ? '1' : '0';
|
||||
});
|
||||
document.getElementById('opacity-slider').addEventListener('input', (e) => {
|
||||
canvas2.style.transition = '';
|
||||
// @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'EventTarg... Remove this comment to see the full error message
|
||||
canvas2.style.opacity = e.target.value;
|
||||
});
|
||||
|
||||
const panel1 = document.getElementById('panel-1');
|
||||
const panel2 = document.getElementById('panel-2');
|
||||
const syncToggle = document.getElementById('sync-scroll-toggle');
|
||||
// @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message
|
||||
syncToggle.addEventListener('change', () => { state.isSyncScroll = syncToggle.checked; });
|
||||
const panel1 = document.getElementById('panel-1');
|
||||
const panel2 = document.getElementById('panel-2');
|
||||
const syncToggle = document.getElementById('sync-scroll-toggle');
|
||||
// @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message
|
||||
syncToggle.addEventListener('change', () => {
|
||||
state.isSyncScroll = syncToggle.checked;
|
||||
});
|
||||
|
||||
let scrollingPanel: any = null;
|
||||
panel1.addEventListener('scroll', () => {
|
||||
if (state.isSyncScroll && scrollingPanel !== panel2) {
|
||||
scrollingPanel = panel1;
|
||||
panel2.scrollTop = panel1.scrollTop;
|
||||
setTimeout(() => scrollingPanel = null, 100);
|
||||
}
|
||||
});
|
||||
panel2.addEventListener('scroll', () => {
|
||||
if (state.isSyncScroll && scrollingPanel !== panel1) {
|
||||
scrollingPanel = panel2;
|
||||
panel1.scrollTop = panel2.scrollTop;
|
||||
setTimeout(() => scrollingPanel = null, 100);
|
||||
}
|
||||
});
|
||||
}
|
||||
let scrollingPanel: any = null;
|
||||
panel1.addEventListener('scroll', () => {
|
||||
if (state.isSyncScroll && scrollingPanel !== panel2) {
|
||||
scrollingPanel = panel1;
|
||||
panel2.scrollTop = panel1.scrollTop;
|
||||
setTimeout(() => (scrollingPanel = null), 100);
|
||||
}
|
||||
});
|
||||
panel2.addEventListener('scroll', () => {
|
||||
if (state.isSyncScroll && scrollingPanel !== panel1) {
|
||||
scrollingPanel = panel2;
|
||||
panel1.scrollTop = panel2.scrollTop;
|
||||
setTimeout(() => (scrollingPanel = null), 100);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user