1
0
mirror of https://github.com/24eme/signaturepdf.git synced 2023-08-25 09:33:08 +02:00

Merge branch 'organization'

This commit is contained in:
Vincent LAURENT 2022-09-24 09:43:11 +02:00
commit c300673ab1
4 changed files with 425 additions and 91 deletions

View File

@ -34,22 +34,32 @@
max-height: 200px;
}
.canvas-container .btn-drag, .canvas-container .btn-rotate, .canvas-container .btn-delete, .canvas-container .btn-select, .canvas-container .btn-download {
.canvas-container .btn-drag, .canvas-container .btn-rotate, .canvas-container .btn-delete, .canvas-container .btn-select, .canvas-container .btn-download, .canvas-container .btn-restore, .canvas-container .btn-drag-here, .canvas-container .btn-cancel {
font-size: 30px;
cursor: move;
background: rgb(255,255,255,0.6);
opacity: 0;
}
.canvas-container .btn-rotate, .canvas-container .btn-delete, .canvas-container .btn-select, .canvas-container .btn-download {
.canvas-container .btn-drag-here, .canvas-container .btn-cancel {
cursor: pointer;
z-index: 9999;
}
.canvas-container .btn-rotate, .canvas-container .btn-delete, .canvas-container .btn-select, .canvas-container .btn-download, .canvas-container .btn-restore {
cursor: pointer;
font-size: 25px;
}
.canvas-container:hover .btn-drag, .canvas-container:hover .btn-rotate, .canvas-container:hover .btn-delete, .canvas-container:hover .btn-select, .canvas-container:hover .btn-download {
opacity: 1;
.canvas-container .btn-cancel {
font-size: 20px;
}
.border-transparent {
border-color: transparent !important;
}
#backdrop_drag_mode {
top: 0;
left: 0;
z-index: 1000;
}

View File

@ -1,10 +1,37 @@
var windowWidth = window.innerWidth;
var menu = null;
var menuOffcanvas = null;
var is_mobile = function() {
return !(window.getComputedStyle(document.getElementById('is_mobile')).display === "none");
};
var responsiveDisplay = function() {
if(is_mobile()) {
document.getElementById('page-organization').style.paddingRight = "inherit";
menu.classList.remove('show');
menuOffcanvas.hide();
document.getElementById('container-pages').classList.remove('vh-100');
document.getElementById('container-btn-zoom').style.top = '62px';
document.getElementById('container-btn-zoom').style.right = '6px';
} else {
menuOffcanvas.show();
document.getElementById('page-organization').style.paddingRight = "350px";
document.getElementById('container-pages').classList.add('vh-100');
document.getElementById('container-btn-zoom').style.top = '6px';
document.getElementById('container-btn-zoom').style.right = '368px';
}
menu.classList.remove('d-md-block');
menu.classList.remove('d-none');
};
var isSelectionMode = function() {
return document.querySelectorAll('.canvas-container .input-select:checked').length > 0;
}
var isDraggedMode = function() {
return document.querySelectorAll('.canvas-container .input-drag:checked').length > 0;
}
var nbPagePerLine = 5;
if(is_mobile()) {
nbPagePerLine = 2;
nbPagePerLine = 1;
}
var pdfjsLib = window['pdfjs-dist/build/pdf'];
pdfjsLib.GlobalWorkerOptions.workerSrc = '/vendor/pdf.worker.js?legacy';
@ -29,29 +56,52 @@ var loadPDF = async function(pdfBlob, filename, pdfIndex) {
let pdfLetter = String.fromCharCode(96 + i+1).toUpperCase();
let loadingTask = pdfjsLib.getDocument(url);
loadingTask.promise.then(function(pdf) {
await loadingTask.promise.then(function(pdf) {
for(var pageNumber = 1; pageNumber <= pdf.numPages; pageNumber++ ) {
pdf.getPage(pageNumber).then(function(page) {
let pageIndex = pdfLetter + "_" + (page.pageNumber - 1);
pages[pageIndex] = page;
let pageHTML = '<div class="position-relative mt-0 ms-1 me-0 mb-1 canvas-container shadow-sm d-flex align-items-center justify-content-center bg-white bg-opacity-50 border border-2 border-transparent" id="canvas-container-' + pageIndex +'" draggable="true">';
pageHTML += '<canvas class="canvas-pdf"></canvas>';
pageHTML += '<div class="position-absolute top-0 start-50 translate-middle-x p-2 ps-3 pe-3 rounded-circle btn-select"><i class="bi bi-check-square"></i></div>';
pageHTML += '<div class="position-absolute top-50 start-0 translate-middle-y p-2 ps-3 pe-3 rounded-circle btn-delete"><i class="bi bi-trash"></i></div>';
pageHTML += '<div class="position-absolute top-50 start-50 translate-middle p-2 ps-3 pe-3 rounded-circle container-resize btn-drag"><i class="bi bi-arrows-move"></i></div>';
pageHTML += '<div class="position-absolute top-50 end-0 translate-middle-y p-2 ps-3 pe-3 rounded-circle container-rotate btn-rotate"><i class="bi bi-arrow-clockwise"></i></div>';
pageHTML += '<div class="position-absolute bottom-0 start-50 translate-middle-x p-2 ps-3 pe-3 rounded-circle btn-download"><i class="bi bi-download"></i></div>';
pageHTML += '<div class="position-absolute text-center w-100 pt-1 container-checkbox pb-4 d-none" style="background: rgb(255,255,255,0.8); bottom: 0; cursor: pointer;"><div class="form-switch d-none"><input form="form_pdf" class="form-check-input checkbox-page" role="switch" type="checkbox" checked="checked" style="cursor: pointer;" value="'+pdfLetter+page.pageNumber+'" /></div></div>';
pageHTML += '<div class="position-absolute text-center w-100 pt-1 container-checkbox pb-4 d-none" style="background: rgb(255,255,255,0.8); bottom: 0; cursor: pointer;"><div class="form-switch d-none"><input form="form_pdf" class="form-check-input checkbox-page" role="switch" type="checkbox" checked="checked" style="cursor: pointer;" value="'+pdfLetter+page.pageNumber+'" /></div></div>';
pageHTML += '<p class="position-absolute text-center w-100 ps-2 pe-2 pb-0 mb-1 opacity-75" style="bottom: 0; font-size: 10px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden;">Page '+page.pageNumber+' - '+filename+'</p>';
let pageHTML = '<div class="position-relative mt-0 ms-1 me-0 mb-1 canvas-container d-flex align-items-center justify-content-center bg-transparent bg-opacity-25 border border-2 border-transparent" id="canvas-container-' + pageIndex +'" draggable="true">';
pageHTML += '<canvas class="canvas-pdf shadow-sm"></canvas>';
pageHTML += '<div title="Séléctionner cette page" class="position-absolute top-0 start-50 translate-middle-x p-2 ps-3 pe-3 mt-2 rounded-circle btn-select d-none"><i class="bi bi-check-square"></i></div>';
pageHTML += '<div title="Supprimer cette page" class="position-absolute top-50 start-0 translate-middle-y p-2 ps-3 pe-3 ms-2 rounded-circle btn-delete d-none"><i class="bi bi-trash"></i></div>';
pageHTML += '<div title="Restaurer cette page" class="position-absolute top-50 start-50 translate-middle p-2 ps-3 pe-3 rounded-circle container-resize btn-restore d-none"><i class="bi bi-recycle"></i></div>';
pageHTML += '<div title="Déplacer cette page" class="position-absolute top-50 start-50 translate-middle p-2 ps-3 pe-3 rounded-circle container-resize btn-drag d-none"><i class="bi bi-arrows-move"></i></div>';
pageHTML += '<div title="Déplacer ici" class="position-absolute top-50 start-50 translate-middle p-2 ps-3 pe-3 rounded-circle container-resize btn-drag-here bg-white shadow d-none"><i class="bi bi-hand-index"></i></div>';
pageHTML += '<div title="Annuler" class="position-absolute top-50 start-50 translate-middle p-2 ps-3 pe-3 rounded-circle container-resize btn-cancel d-none"><i class="bi bi-x-lg"></i></div>';
pageHTML += '<div title="Tourner cette page" class="position-absolute top-50 end-0 translate-middle-y p-2 ps-3 pe-3 me-2 rounded-circle container-rotate btn-rotate d-none"><i class="bi bi-arrow-clockwise"></i></div>';
pageHTML += '<div title="Télécharger cette page" class="position-absolute bottom-0 start-50 translate-middle-x p-2 ps-3 pe-3 mb-3 rounded-circle btn-download d-none"><i class="bi bi-download"></i></div>';
pageHTML += '<p class="page-title position-absolute text-center w-100 ps-2 pe-2 pb-0 pt-0 mb-1 bg-white opacity-75 d-none" style="bottom: -4px; font-size: 10px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden;">Page '+page.pageNumber+' - '+filename+'</p>';
pageHTML += '<input form="form_pdf" class="checkbox-page d-none" role="switch" type="checkbox" checked="checked" value="'+pdfLetter+page.pageNumber+'" />';
pageHTML += '<input type="hidden" class="input-rotate" value="0" id="input_rotate_'+pageIndex+'" />';
pageHTML += '<input type="checkbox" class="input-select d-none" value="'+pdfLetter+page.pageNumber+'" id="input_select_'+pageIndex+'" />';
pageHTML += '<input type="checkbox" class="input-hover d-none" value="'+pdfLetter+page.pageNumber+'" id="input_select_'+pageIndex+'" />';
pageHTML += '<input type="checkbox" class="input-drag d-none" value="'+pdfLetter+page.pageNumber+'" id="input_drag_'+pageIndex+'" />';
pageHTML += '</div>';
document.getElementById('container-pages').insertAdjacentHTML('beforeend', pageHTML);
let canvasContainer = document.getElementById('canvas-container-' + pageIndex);
canvasContainer.addEventListener('click', function(e) {
if(!is_mobile()) {
return;
}
let checkbox = this.querySelector('input[type=checkbox].input-hover');
checkbox.checked = !checkbox.checked;
updatePageState(this);
});
canvasContainer.addEventListener('mouseenter', function(e) {
if(is_mobile()) {
return false;
}
this.querySelector('input[type=checkbox].input-hover').checked = true;
updatePageState(this);
});
canvasContainer.addEventListener('mouseleave', function(e) {
this.querySelector('input[type=checkbox].input-hover').checked = false;
updatePageState(this);
});
canvasContainer.addEventListener('dragstart', function(e) {
this.querySelector('.container-resize').classList.add('d-none');
this.querySelector('.canvas-pdf').classList.add('shadow-lg');
@ -62,9 +112,9 @@ var loadPDF = async function(pdfBlob, filename, pdfIndex) {
canvasContainer.addEventListener('dragend', function(e) {
this.querySelector('.container-resize').classList.remove('d-none');
this.querySelector('.canvas-pdf').classList.remove('shadow-lg');
this.querySelector('.canvas-pdf').style.border = '2px solid transparent';
this.querySelector('.canvas-pdf').style.removeProperty('border');
this.style.opacity = 1;
stateCheckbox(this.querySelector('input[type=checkbox]'));
updatePageState(this);
});
canvasContainer.addEventListener('dragover', function(e) {
if (e.preventDefault) {
@ -79,28 +129,45 @@ var loadPDF = async function(pdfBlob, filename, pdfIndex) {
return false;
});
canvasContainer.querySelector('.btn-delete').addEventListener('click', function(e) {
let checkbox = this.parentNode.querySelector('input[type=checkbox]');
checkbox.checked = !checkbox.checked;
stateCheckbox(checkbox);
toggleDeletePage(this.parentNode);
});
canvasContainer.querySelector('.btn-restore').addEventListener('click', function(e) {
toggleDeletePage(this.parentNode);
});
canvasContainer.querySelector('.btn-select').addEventListener('click', function(e) {
let checkbox = this.parentNode.querySelector('input[type=checkbox].input-select');
checkbox.checked = !checkbox.checked;
let container = this.parentNode;
if(checkbox.checked) {
container.classList.add('border-primary', 'shadow', 'bg-primary');
container.classList.remove('border-transparent', 'shadow-sm', 'bg-white');
} else {
container.classList.remove('border-primary', 'shadow', 'bg-primary');
container.classList.add('border-transparent', 'shadow-sm', 'bg-white');
}
if(document.querySelectorAll('.canvas-container .input-select:checked').length > 0) {
document.querySelector('#container-btn-save-select').classList.remove('d-none');
document.querySelector('#container-btn-save').classList.add('d-none');
} else {
document.querySelector('#container-btn-save-select').classList.add('d-none');
document.querySelector('#container-btn-save').classList.remove('d-none');
}
toggleSelectPage(this.parentNode);
});
canvasContainer.querySelector('.btn-drag').addEventListener('click', function(e) {
toggleDragPage(this.parentNode);
});
canvasContainer.querySelector('.btn-drag-here').addEventListener('click', function(e) {
let pageHere = this.parentNode;
let after = false;
let pageHereFound = false;
document.querySelectorAll('.canvas-container').forEach(function(page) {
if(page.id == pageHere.id) {
pageHereFound = true;
}
if(!after && isPageDragged(page) && !pageHereFound) {
after = true;
}
});
document.querySelectorAll('.canvas-container .input-drag:checked').forEach(function(item) {
let page = item.parentNode;
if(after) {
pageHere.insertAdjacentElement('afterend', page);
} else {
pageHere.insertAdjacentElement('beforebegin', page);
}
page.querySelector('input[type=checkbox].input-drag').checked = false;
});
updateGlobalState();
document.querySelectorAll('.canvas-container').forEach(function(page) {
updatePageState(page);
});
});
canvasContainer.querySelector('.btn-cancel').addEventListener('click', function(e) {
toggleDragPage(this.parentNode);
});
canvasContainer.querySelector('.btn-download').addEventListener('click', function(e) {
let container = this.parentNode;
@ -113,7 +180,7 @@ var loadPDF = async function(pdfBlob, filename, pdfIndex) {
document.querySelector('#form_pdf').submit();
});
canvasContainer.querySelector('.btn-rotate').addEventListener('click', function(e) {
let inputRotate = document.querySelector('#input_rotate_'+pageIndex);
let inputRotate = this.parentNode.querySelector('.input-rotate');
inputRotate.value = (parseInt(inputRotate.value) + 90) % 360;
pageRender(pageIndex);
})
@ -124,6 +191,8 @@ var loadPDF = async function(pdfBlob, filename, pdfIndex) {
}, function (reason) {
console.error(reason);
});
return loadingTask;
};
var pageRenderAll = function() {
@ -133,24 +202,29 @@ var pageRenderAll = function() {
}
var pageRender = async function(pageIndex) {
let scrollWidth = 12;
if(is_mobile()) {
scrollWidth = -4;
}
let page = pages[pageIndex];
let rotation = parseInt(document.querySelector('#input_rotate_'+pageIndex).value);
let viewport = page.getViewport({scale: 1, rotation: rotation});
let size = Math.floor((document.getElementById('container-pages').offsetWidth - (8*(nbPagePerLine+1)) - 12) / nbPagePerLine);
let scaleWidth = size / viewport.width;
let scaleHeight = size / viewport.height;
let sizeWidth = Math.floor((document.getElementById('container-pages').offsetWidth - (8*(nbPagePerLine+1)) - scrollWidth) / nbPagePerLine);
let sizeHeight = sizeWidth * 1.25;
let scaleWidth = sizeWidth / viewport.width;
let scaleHeight = sizeHeight / viewport.height;
let viewportWidth = page.getViewport({scale: scaleWidth, rotation: rotation});
let viewportHeight = page.getViewport({scale: scaleHeight, rotation: rotation});
if(viewportWidth.height > size) {
if(viewportWidth.height > sizeWidth) {
viewport = viewportHeight;
} else {
viewport = viewportWidth;
}
let canvasContainer = document.getElementById('canvas-container-' + pageIndex);
canvasContainer.style.height = (size + 4) + "px";
canvasContainer.style.width = (size + 4) + "px";
canvasContainer.style.height = (sizeHeight + 4) + "px";
canvasContainer.style.width = (sizeWidth + 4) + "px";
let canvasPDF = canvasContainer.querySelector('.canvas-pdf');
let context = canvasPDF.getContext('2d');
canvasPDF.height = viewport.height;
@ -165,21 +239,221 @@ var pageRender = async function(pageIndex) {
});
}
var stateCheckbox = function(checkbox) {
let checkboxContainer = checkbox.parentNode.parentNode.parentNode;
var getFileIndex = function(page) {
if(checkbox.checked) {
checkboxContainer.style.opacity = '1'
} else {
checkboxContainer.style.opacity = '0.2';
}
};
return page.id.replace('canvas-container-', '').replace(/_.*$/, '');
}
var getFilesStats = function() {
let files = [];
document.querySelectorAll('.canvas-container').forEach(function(page) {
let fileIndex = getFileIndex(page);
if(!files[fileIndex]) {
files[fileIndex] = { nbPage: 0, nbPageSelected: 0, nbPageDeleted: 0};
}
if(isPageDeleted(page)) {
files[fileIndex].nbPageDeleted++;
} else {
files[fileIndex].nbPage++;
}
if(isPageSelected(page)) {
files[fileIndex].nbPageSelected++;
}
});
console.log(files);
return files;
}
var updateListePDF = function() {
document.querySelector('#list_pdf').innerHTML = "";
for (var i = 0; i < document.querySelector('#input_pdf').files.length; i++) {
let pdfLetter = String.fromCharCode(96 + i+1).toUpperCase();
const pdfFile = document.querySelector('#input_pdf').files.item(i);
document.querySelector('#list_pdf').insertAdjacentHTML('beforeend', '<li class="list-group-item small" style="text-overflow: ellipsis; white-space: nowrap; overflow: hidden;"><i class="bi bi-files"></i> '+decodeURI(pdfFile.name)+'</li>');
document.querySelector('#list_pdf').insertAdjacentHTML('beforeend', '<li id="file_' + pdfLetter + '" class="list-group-item small ps-2 pe-5" title="'+decodeURI(pdfFile.name)+'" style="text-overflow: ellipsis; white-space: nowrap; overflow: hidden;"><i class="bi bi-files"></i><span class="ms-2">'+decodeURI(pdfFile.name)+'</span> <input class="form-check-input float-end position-absolute" style="right: 10px;" type="checkbox" /> </li>');
let fileItem = document.querySelector('#file_' + pdfLetter);
fileItem.querySelector('input[type=checkbox]').addEventListener('change', function(e) {
document.querySelectorAll('.canvas-container').forEach(function(page) {
if(getFileIndex(page) == pdfLetter && !isPageDeleted(page)) {
selectPage(page, e.target.checked);
}
});
updateGlobalState();
});
}
updateGlobalState();
}
var getPagesSelected = function() {
let pages = [];
document.querySelectorAll('.canvas-container .input-select:checked').forEach(function(item) {
pages[item.parentNode.id.replace('canvas-container-', '')] = item.parentNode;
});
return pages;
}
var selectPage = function(page, state) {
page.querySelector('input[type=checkbox].input-select').checked = state;
updatePageState(page);
}
var toggleSelectPage = function(page) {
selectPage(page, !isPageSelected(page));
updateGlobalState();
}
var isPageSelected = function(page) {
return page.querySelector('input[type=checkbox].input-select').checked;
}
var dragPage = function(page, state) {
page.querySelector('input[type=checkbox].input-drag').checked = state;
updatePageState(page);
}
var toggleDragPage = function(page) {
dragPage(page, !isPageDragged(page));
updateGlobalState();
document.querySelectorAll('.canvas-container').forEach(function(page) {
updatePageState(page);
});
}
var isPageDragged = function(page) {
return page.querySelector('input[type=checkbox].input-drag').checked;
}
var toggleDeletePage = function(page) {
deletePage(page, isPageDeleted(page))
updateGlobalState();
}
var deletePage = function(page, state) {
page.querySelector('input[type=checkbox].checkbox-page').checked = state;
page.querySelector('input[type=checkbox].input-select').checked = false;
updatePageState(page);
}
var isPageDeleted = function(page) {
return !page.querySelector('input[type=checkbox].checkbox-page').checked;
}
var isPageHover = function(page) {
return page.querySelector('input[type=checkbox].input-hover').checked;
}
var updatePageState = function(page) {
page.classList.remove('border-primary', 'shadow-sm', 'bg-primary', 'border-secondary', 'bg-secondary');
page.classList.add('border-transparent', 'bg-transparent');
page.querySelector('.canvas-pdf').style.opacity = '1';
page.querySelector('.canvas-pdf').style.zIndex = 'inherit';
page.querySelector('.canvas-pdf').classList.add('shadow-sm');
page.querySelector('.canvas-pdf').classList.remove('shadow');
page.querySelector('.btn-rotate').classList.add('d-none');
page.querySelector('.btn-download').classList.add('d-none');
page.querySelector('.btn-delete').classList.add('d-none');
page.querySelector('.btn-select').classList.add('d-none');
page.querySelector('.btn-select').classList.remove('text-primary');
page.querySelector('.btn-drag').classList.add('d-none');
page.querySelector('.btn-cancel').classList.add('d-none');
page.querySelector('.btn-drag-here').classList.add('d-none');
page.querySelector('.btn-restore').classList.add('d-none');
page.querySelector('.page-title').classList.add('d-none');
if(isPageDeleted(page)) {
page.querySelector('.canvas-pdf').style.opacity = '0.15';
}
if(isPageHover(page) && !isPageDeleted(page) && !isPageDragged(page) && !isDraggedMode()) {
page.querySelector('.page-title').classList.remove('d-none');
page.classList.add('border-secondary', 'bg-secondary');
page.classList.remove('border-transparent', 'bg-transparent');
page.querySelector('.btn-rotate').classList.remove('d-none');
page.querySelector('.btn-download').classList.remove('d-none');
page.querySelector('.btn-delete').classList.remove('d-none');
page.querySelector('.btn-select').classList.remove('d-none')
page.querySelector('.btn-drag').classList.remove('d-none');
}
if(isPageHover(page) && isPageDeleted(page)) {
page.querySelector('.btn-restore').classList.remove('d-none');
}
if(isPageSelected(page)) {
page.classList.add('border-primary', 'shadow-sm', 'bg-primary');
page.classList.remove('border-transparent', 'bg-transparent', 'border-secondary', 'bg-secondary');
page.querySelector('.btn-select').classList.add('text-primary');
page.querySelector('.btn-select').classList.remove('d-none')
}
if(isPageDragged(page)) {
page.querySelector('.btn-cancel').classList.remove('d-none');
page.querySelector('.canvas-pdf').classList.remove('shadow-sm');
page.querySelector('.canvas-pdf').classList.add('shadow');
page.querySelector('.canvas-pdf').style.zIndex = 9999;
}
if(!isPageDragged(page) && isDraggedMode()) {
page.querySelector('.btn-drag-here').classList.remove('d-none');
}
}
var updateFilesState = function() {
let filesStats = getFilesStats();
for(fileIndex in filesStats) {
let checkbox = document.querySelector('#file_'+fileIndex+' input[type=checkbox]');
let fileStat = filesStats[fileIndex];
checkbox.checked = (fileStat.nbPageSelected > 0 && fileStat.nbPageSelected == fileStat.nbPage);
checkbox.indeterminate = (fileStat.nbPageSelected > 0 && fileStat.nbPageSelected < fileStat.nbPage);
document.querySelector('#file_'+fileIndex+' span').classList.remove('text-primary');
if(fileStat.nbPageSelected > 0) {
document.querySelector('#file_'+fileIndex+' span').classList.add('text-primary');
}
}
}
var updateGlobalState = function() {
updateFilesState();
document.querySelector('#container_btn_select').classList.add('opacity-50');
document.querySelector('#container_btn_select').classList.remove('border-primary');
document.querySelector('#container_btn_select .card-header').classList.remove('bg-primary', 'text-white');
document.querySelector('#container_btn_select .card-header').classList.add('text-muted');
document.querySelectorAll('#container_btn_select .card-body button').forEach(function(button) {
button.classList.add('btn-outline-secondary');
button.classList.remove('btn-outline-primary');
button.setAttribute('disabled', 'disabled');
});
document.querySelector('#container_btn_select .card-header span').innerText = "Aucune";
document.querySelector('#backdrop_drag_mode').classList.add('d-none');
if(isSelectionMode()) {
document.querySelector('#container_btn_select .card-header span').innerText = document.querySelectorAll('.canvas-container .input-select:checked').length;
document.querySelector('#container_btn_select').classList.remove('opacity-50');
document.querySelector('#container_btn_select').classList.add('border-primary');
document.querySelector('#container_btn_select .card-header').classList.remove('text-muted');
document.querySelector('#container_btn_select .card-header').classList.add('bg-primary', 'text-white');
document.querySelectorAll('#container_btn_select .card-body button').forEach(function(button) {
button.classList.add('btn-outline-primary');
button.classList.remove('btn-outline-secondary');
button.removeAttribute('disabled');
});
document.querySelectorAll('.canvas-container .btn-add').forEach(function(button) {
button.classList.remove('d-none');
});
}
if(isDraggedMode()) {
document.querySelector('#backdrop_drag_mode').style.width = document.querySelector('#container-pages').scrollWidth+'px';
console.log(document.querySelector('#container-pages'));
document.querySelector('#backdrop_drag_mode').style.height = document.querySelector('#container-pages').scrollHeight+'px';
document.querySelector('#backdrop_drag_mode').classList.remove('d-none');
}
}
@ -198,10 +472,7 @@ var createEventsListener = function() {
document.getElementById('save').addEventListener('click', function(event) {
let order = [];
let selectionMode = false;
if(document.querySelectorAll('.canvas-container .input-select:checked').length > 0) {
selectionMode = true;
}
let selectionMode = isSelectionMode();
document.querySelectorAll('.canvas-container').forEach(function(canvasContainer) {
let checkbox = canvasContainer.querySelector('.checkbox-page');
@ -223,21 +494,26 @@ var createEventsListener = function() {
});
document.querySelector('#input_pages').value = order.join(',');
});
document.getElementById('save_mobile').addEventListener('click', function(event) {
document.getElementById('save').click();
});
document.getElementById('input_pdf_upload_2').addEventListener('change', async function(event) {
if(this.files[0].size > maxSize) {
console.log(this.files.length);
for (let i = 0; i < this.files.length; i++) {
if(this.files[i].size > maxSize) {
alert("Le PDF ne doit pas dépasser " + Math.round(maxSize/1024/1024) + " Mo");
this.value = "";
return;
alert("Le PDF ne doit pas dépasser " + Math.round(maxSize/1024/1024) + " Mo");
break;
}
const cache = await caches.open('pdf');
let filename = this.files[i].name;
let response = new Response(this.files[i], { "status" : 200, "statusText" : "OK" });
let urlPdf = '/pdf/'+filename;
await cache.put(urlPdf, response);
let pdfBlob = await getPDFBlobFromCache(urlPdf);
nbPDF++;
await loadPDF(pdfBlob, filename, nbPDF);
}
const cache = await caches.open('pdf');
let filename = this.files[0].name;
let response = new Response(this.files[0], { "status" : 200, "statusText" : "OK" });
let urlPdf = '/pdf/'+filename;
await cache.put(urlPdf, response);
let pdfBlob = await getPDFBlobFromCache(urlPdf);
nbPDF++;
loadPDF(pdfBlob, filename, nbPDF);
this.value = '';
});
document.getElementById('btn-zoom-decrease').addEventListener('click', function(event) {
@ -253,7 +529,21 @@ var createEventsListener = function() {
input.parentNode.querySelector('.btn-select').click();
});
});
document.getElementById('btn_delete_select').addEventListener('click', function(event) {
let pages = getPagesSelected();
for(index in pages) {
deletePage(pages[index]);
}
updateGlobalState();
});
document.getElementById('btn_rotate_select').addEventListener('click', function(event) {
let pages = getPagesSelected();
for(index in pages) {
let inputRotate = pages[index].querySelector('.input-rotate');
inputRotate.value = (parseInt(inputRotate.value) + 90) % 360;
pageRender(index);
}
});
}
async function getPDFBlobFromCache(cacheUrl) {
@ -290,6 +580,7 @@ async function uploadFromUrl(url) {
}
var pageUpload = async function() {
document.querySelector('body').classList.remove('bg-light');
document.getElementById('input_pdf_upload').value = '';
document.getElementById('page-upload').classList.remove('d-none');
document.getElementById('page-organization').classList.add('d-none');
@ -314,14 +605,19 @@ var pageUpload = async function() {
var pageOrganization = async function(url) {
let filename = url.replace('/pdf/', '');
document.title = filename + ' - ' + document.title;
document.querySelector('body').classList.add('bg-light');
document.getElementById('page-upload').classList.add('d-none');
document.getElementById('page-organization').classList.remove('d-none');
menu = document.getElementById('sidebarTools');
menuOffcanvas = new bootstrap.Offcanvas(menu);
responsiveDisplay();
let pdfBlob = await getPDFBlobFromCache(url);
if(!pdfBlob) {
document.location = '/organization';
return;
}
createEventsListener();
loadPDF(pdfBlob, filename, nbPDF);
};

View File

@ -12,15 +12,23 @@
<title>Organiser un PDF</title>
</head>
<body class="bg-light">
<body>
<noscript>
<div class="alert alert-danger text-center" role="alert">
<i class="bi bi-exclamation-triangle"></i> Site non fonctionnel sans JavaScript activé
</div>
</noscript>
<div id="page-upload">
<div class="px-4 py-5 my-5 text-center">
<h1 class="display-5 fw-bold"><i class="bi bi-ui-checks-grid"></i> Organiser un PDF</h1>
<ul class="nav justify-content-center nav-tabs mt-2">
<li class="nav-item">
<a class="nav-link" href="/signature"><i class="bi bi-vector-pen"></i> Signer</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="/organization"><i class="bi bi-ui-checks-grid"></i> Organiser</a>
</li>
</ul>
<div class="px-4 py-5 text-center">
<h1 class="display-5 fw-bold"><i class="bi bi-ui-checks-grid"></i> Organiser des PDF</h1>
<div class="col-md-6 col-lg-5 col-xl-4 col-xxl-3 mx-auto">
<div class="col-12">
<label class="form-label mt-2" for="input_pdf_upload">Choisir un PDF <small class="opacity-75" title="Le PDF ne doit pas dépasser <?php echo round($maxSize / 1024 / 1024) ?> Mo"><i class="bi bi-info-circle"></i></small></label>
@ -33,16 +41,13 @@
<footer class="text-center text-muted mb-2 fixed-bottom">
<small>Logiciel libre sous license AGPL-3.0 : <a href="https://github.com/24eme/signaturepdf">voir le code source</a></small>
</footer>
</div>
<footer class="text-center text-muted mb-2 fixed-bottom">
<small>Logiciel libre sous license AGPL-3.0 : <a href="https://github.com/24eme/signaturepdf">voir le code source</a></small>
</footer>
</div>
<div id="page-organization" style="padding-right: 350px;" class="d-none">
<div style="height: 65px;" class="d-md-none"></div>
<div id="container-pages" class="col-12 pt-1 vh-100 d-flex align-content-start flex-wrap" style="padding-bottom: 60px; overflow-y: scroll;">
<div id="container-pages" class="col-12 pt-1 vh-100 d-flex align-content-start flex-wrap position-relative" style="overflow-y: scroll;">
<div id="backdrop_drag_mode" class="position-absolute bg-dark opacity-25 d-none"></div>
</div>
<div class="btn-group-vertical position-absolute" style="top: 6px; right: 368px;">
<div id="container-btn-zoom" class="btn-group-vertical position-fixed" style="top: 6px; right: 368px;">
<button id="btn-zoom-increase" class="btn btn-outline-dark bg-white text-dark"><i class="bi bi-zoom-in"></i></button>
<button id="btn-zoom-decrease" class="btn btn-outline-dark bg-white text-dark"><i class="bi bi-zoom-out"></i></button>
</div>
@ -53,29 +58,44 @@
<h5 class="mb-1 d-block w-100" id="sidebarToolsLabel">Organisation de PDF <span class="float-end me-2" title="Ce PDF est stocké sur votre ordinateur pour être signé par vous uniquement"><i class="bi-ui-checks-grid"></i></span></h5>
<button type="button" class="btn-close text-reset d-md-none" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body pt-3">
<div class="offcanvas-body pt-3" style="padding-bottom: 60px;">
<ul id="list_pdf" class="list-group">
</ul>
<div class="d-grid gap-2 mt-2">
<button type="button" class="btn btn-sm btn-outline-dark" onclick="document.getElementById('input_pdf_upload_2').click();"><i class="bi bi-plus-circle"></i> Ajouter un PDF</button>
<input id="input_pdf_upload_2" class="form-control d-none" type="file" accept=".pdf,application/pdf">
<input id="input_pdf_upload_2" class="form-control d-none" type="file" accept=".pdf,application/pdf" multiple="true">
</div>
<hr />
<div id="container_btn_select" class="opacity-50 card">
<div class="card-header small text-center p-1"><span>Aucune</span> page(s) séléctionnée(s) <button id="btn_cancel_select" type="button" class="btn-close btn-close-white float-end" aria-label="Close"></button></div>
<div class="card-body d-grid gap-2 p-2">
<button id="btn_rotate_select" disabled="disabled" type="button" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-clockwise"></i> Tourner de 90°</button>
<button id="btn_delete_select" disabled="disabled" type="button" class="btn btn-sm btn-outline-secondary"><i class="bi bi-trash"></i> Supprimer</button>
<button id="save-select" class="btn btn-sm btn-outline-secondary" disabled="disabled" form="form_pdf" type="submit"><i class="bi bi-download"></i> Télécharger</button>
</div>
</div>
<div class="position-absolute bottom-0 pb-2 ps-0 pe-4 w-100">
<form id="form_pdf" action="/organize" method="post" enctype="multipart/form-data">
<input id="input_pdf" name="pdf[]" type="file" class="d-none" />
<input id="input_pages" type="hidden" value="" name="pages" />
<div id="container-btn-save-select" class="d-grid gap-2 mt-2 d-none">
<button id="btn_cancel_select" type="button" class="btn btn-link">Annuler la sélection</button>
<button class="btn btn-outline-primary" type="submit" id="save-select"><i class="bi bi-download"></i> Télécharger les pages séléctionnées</button>
</div>
<div id="container-btn-save" class="d-grid gap-2 mt-2">
<div class="d-grid gap-2 mt-2">
<button class="btn btn-primary" type="submit" id="save"><i class="bi bi-download"></i> Télécharger le PDF</button>
</div>
</form>
</div>
</div>
</div>
<div class="position-fixed top-0 start-0 bg-white w-100 p-2 shadow-sm d-md-none">
<button type=button class="btn btn-light float-end" data-bs-toggle="offcanvas" data-bs-target="#sidebarTools" aria-controls="sidebarTools"><i class="bi bi-list"></i></button>
</div>
<div class="position-fixed bottom-0 start-0 bg-white w-100 p-2 shadow-sm d-md-none">
<div class="d-grid gap-2">
<button class="btn btn-primary" type="submit" id="save_mobile"><i class="bi bi-download"></i> Télécharger le PDF</button>
</div>
</div>
</div>
<span id="is_mobile" class="d-md-none"></span>
<script src="/vendor/bootstrap.min.js?5.1.3"></script>
@ -83,6 +103,6 @@
<script>
var maxSize = <?php echo $maxSize ?>;
</script>
<script src="/js/organization.js?202205070208"></script>
<script src="/js/organization.js?202205310125"></script>
</body>
</html>

View File

@ -17,7 +17,15 @@
</div>
</noscript>
<div id="page-upload">
<div class="px-4 py-5 my-5 text-center">
<ul class="nav justify-content-center nav-tabs mt-2">
<li class="nav-item">
<a class="nav-link active" href="/signature"><i class="bi bi-vector-pen"></i> Signer</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/organization"><i class="bi bi-ui-checks-grid"></i> Organiser</a>
</li>
</ul>
<div class="px-4 py-5 text-center">
<h1 class="display-5 fw-bold"><i class="bi bi-vector-pen"></i> Signer un PDF</h1>
<div class="col-md-6 col-lg-5 col-xl-4 col-xxl-3 mx-auto">
<div class="col-12">
@ -135,7 +143,7 @@
<nav class="nav nav-tabs" id="nav-tab" role="tablist">
<button class="nav-link active ps-2 ps-md-3 pe-2 pe-md-3" id="nav-draw-tab" data-bs-toggle="tab" data-bs-target="#nav-draw" type="button" role="tab" aria-controls="nav-draw" aria-selected="true"><i class="bi bi-vector-pen"></i> Dessiner<br /><small>à main levée</small></button>
<button class="nav-link ps-2 ps-md-3 pe-2 pe-md-3" id="nav-type-tab" data-bs-toggle="tab" data-bs-target="#nav-type" type="button" role="tab" aria-controls="nav-type" aria-selected="false"><i class="bi bi-fonts"></i> Saisir<br /><small>du texte</small></button>
<button class="nav-link ps-2 ps-md-3 pe-2 pe-md-3" id="nav-import-tab" data-bs-toggle="tab" data-bs-target="#nav-import" type="button" role="tab" aria-controls="nav-import" aria-selected="false"><i class="bi bi-image"></i> Importer<br /><small class="opacity-75">une image</small></button>
<button class="nav-link ps-2 ps-md-3 pe-2 pe-md-3" id="nav-import-tab" data-bs-toggle="tab" data-bs-target="#nav-import" type="button" role="tab" aria-controls="nav-import" aria-selected="false"><i class="bi bi-image"></i> Importer<br /><small>une image</small></button>
</nav>
<div class="tab-content mt-3" id="nav-svg-add">
<div class="tab-pane fade show active" id="nav-draw" role="tabpanel" aria-labelledby="nav-draw-tab">