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

Merge branch 'metadata' of github.com:24eme/signaturepdf into metadata

This commit is contained in:
Gabriel Poma 2023-04-19 10:48:47 +02:00
commit f9af7f969e
3 changed files with 276 additions and 0 deletions

View File

@ -353,6 +353,14 @@ $f3->route('POST /organize',
);
}
$f3->route('GET /metadata',
function($f3) {
$f3->set('maxSize', min(array(convertPHPSizeToBytes(ini_get('post_max_size')), convertPHPSizeToBytes(ini_get('upload_max_filesize')))));
echo View::instance()->render('metadata.html.php');
}
);
function convertPHPSizeToBytes($sSize)
{
$sSuffix = strtoupper(substr($sSize, -1));

166
public/js/metadata.js Normal file
View File

@ -0,0 +1,166 @@
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()) {
menu.classList.remove('show');
menuOffcanvas.hide();
} else {
menuOffcanvas.show();
}
menu.classList.remove('d-md-block');
menu.classList.remove('d-none');
};
var pdfjsLib = window['pdfjs-dist/build/pdf'];
pdfjsLib.GlobalWorkerOptions.workerSrc = '/vendor/pdf.worker.js?legacy';
var nbPDF = 0;
var pages = [];
var pdfRenderTasks = [];
var loadPDF = async function(pdfBlob, filename, pdfIndex) {
let url = await URL.createObjectURL(pdfBlob);
let loadingTask = pdfjsLib.getDocument(url);
document.querySelector('#text_document_name span').innerText = filename;
await loadingTask.promise.then(function(pdf) {
pdf.getMetadata().then(function(metadata) {
console.log(metadata);
for(metaKey in metadata.info) {
if(metaKey == "Custom" || metaKey == "PDFFormatVersion" || metaKey.match(/^Is/) || metaKey == "Trapped") {
continue;
}
addMetadata(metaKey, metadata.info[metaKey]);
}
for(metaKey in metadata.info.Custom) {
if(metaKey == "sha256") {
continue;
}
addMetadata(metaKey, metadata.info.Custom[metaKey]);
}
});
}, function (reason) {
console.error(reason);
});
return loadingTask;
}
var addMetadata = function(key, value) {
let div = document.createElement('div');
div.classList.add('form-floating');
div.classList.add('mt-3');
let input = document.createElement('input');
input.value = value;
input.classList.add('form-control');
let label = document.createElement('label');
label.innerText = key;
div.appendChild(input);
div.appendChild(label);
document.getElementById('form-metadata-container').appendChild(div);
input.focus();
}
var createEventsListener = function() {
document.getElementById('form_metadata_add').addEventListener('submit', function(e) {
let formData = new FormData(this);
addMetadata(formData.get('metadata_key'), "");
this.reset();
e.preventDefault();
})
}
async function getPDFBlobFromCache(cacheUrl) {
const cache = await caches.open('pdf');
let responsePdf = await cache.match(cacheUrl);
if(!responsePdf) {
return null;
}
let pdfBlob = await responsePdf.blob();
return pdfBlob;
}
async function uploadFromUrl(url) {
history.replaceState({}, '', '/metadata');
var response = await fetch(url);
if(response.status != 200) {
return;
}
var pdfBlob = await response.blob();
if(pdfBlob.type != 'application/pdf' && pdfBlob.type != 'application/octet-stream') {
return;
}
let dataTransfer = new DataTransfer();
let filename = url.replace(/^.*\//, '');
dataTransfer.items.add(new File([pdfBlob], filename, {
type: 'application/pdf'
}));
document.getElementById('input_pdf_upload').files = dataTransfer.files;
document.getElementById('input_pdf_upload').dispatchEvent(new Event("change"));
}
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-metadata').classList.add('d-none');
document.getElementById('input_pdf_upload').focus();
const cache = await caches.open('pdf');
document.getElementById('input_pdf_upload').addEventListener('change', async function(event) {
if(document.getElementById('input_pdf_upload').files[0].size > maxSize) {
alert("Le PDF ne doit pas dépasser " + Math.round(maxSize/1024/1024) + " Mo");
document.getElementById('input_pdf_upload').value = "";
return;
}
let filename = document.getElementById('input_pdf_upload').files[0].name;
let response = new Response(document.getElementById('input_pdf_upload').files[0], { "status" : 200, "statusText" : "OK" });
let urlPdf = '/pdf/'+filename;
await cache.put(urlPdf, response);
history.pushState({}, '', '/metadata#'+filename);
pageMetadata(urlPdf)
});
}
var pageMetadata = 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-metadata').classList.remove('d-none');
menu = document.getElementById('sidebarTools');
menuOffcanvas = new bootstrap.Offcanvas(menu);
responsiveDisplay();
let pdfBlob = await getPDFBlobFromCache(url);
if(!pdfBlob) {
document.location = '/metadata';
return;
}
createEventsListener();
loadPDF(pdfBlob, filename, nbPDF);
};
(function () {
if(window.location.hash && window.location.hash.match(/^\#http/)) {
let hashUrl = window.location.hash.replace(/^\#/, '');
pageUpload();
uploadFromUrl(hashUrl);
} else if(window.location.hash) {
pageMetadata('/pdf/'+window.location.hash.replace(/^\#/, ''));
} else {
pageUpload();
}
window.addEventListener('hashchange', function() {
window.location.reload();
})
})();

102
templates/metadata.html.php Normal file
View File

@ -0,0 +1,102 @@
<!doctype html>
<html lang="fr_FR">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/vendor/bootstrap.min.css?5.1.1" rel="stylesheet">
<link href="/vendor/bootstrap-icons.css?1.5.0" rel="stylesheet">
<link href="/css/app.css?202210080134" rel="stylesheet">
<link rel="icon" type="image/x-icon" href="/favicon-organization.ico">
<title>Métadonnées d'un PDF</title>
</head>
<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">
<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" href="/organization"><i class="bi bi-ui-checks-grid"></i> Organiser</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="/metadata"><i class="bi bi-ui-checks-grid"></i> Metadonnées</a>
</li>
</ul>
<div class="px-4 py-4 text-center">
<h1 class="display-5 fw-bold mb-0 mt-3"><i class="bi bi-ui-checks-grid"></i> Metadonnées d'un PDF</h1>
<p class="fw-light mb-3 subtitle text-dark text-nowrap" style="overflow: hidden; text-overflow: ellipsis;"></p>
<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-3" for="input_pdf_upload">Choisir un PDF <small class="opacity-75" style="cursor: help" title="Le PDF ne doit pas dépasser <?php echo round($maxSize / 1024 / 1024) ?> Mo"><i class="bi bi-info-circle"></i></small></label>
<input id="input_pdf_upload" placeholder="Choisir un PDF" class="form-control form-control-lg" type="file" accept=".pdf,application/pdf" />
<p class="mt-2 small fw-light text-dark">Le PDF sera traité par le serveur sans être conservé ni stocké</p>
<?php if($PDF_DEMO_LINK): ?>
<a class="btn btn-sm btn-link opacity-75" href="#<?php echo $PDF_DEMO_LINK ?>">Tester avec un PDF de démo</a>
<?php endif; ?>
</div>
</div>
</div>
<footer class="text-center text-muted mb-2 fixed-bottom opacity-75">
<small>Logiciel libre <span class="d-none d-md-inline">sous license AGPL-3.0 </span>: <a href="https://github.com/24eme/signaturepdf">voir le code source</a></small>
</footer>
</div>
<div id="page-metadata" style="padding-right: 350px;" class="d-none">
<div id="div-margin-top" style="height: 88px;" class="d-md-none"></div>
<div id="container-main">
<div id="form-metadata" class="w-50 mx-auto pt-3 pb-3">
<h3>Métadonnées</h3>
<div id="form-metadata-container">
</div>
<form id="form_metadata_add">
<div class="input-group mt-3">
<input name="metadata_key" type="text" class="form-control" placeholder="Ma nouvelle metadonnée" aria-label="Recipient's username">
<button class="btn btn-outline-secondary" type="submit">Ajouter</button>
</div>
</form>
</div>
</div>
<div id="div-margin-bottom" style="height: 55px;" class="d-md-none"></div>
<div class="offcanvas offcanvas-end show d-none d-md-block shadow-sm" data-bs-backdrop="false" data-bs-scroll="true" data-bs-keyboard="false" tabindex="-1" id="sidebarTools" aria-labelledby="sidebarToolsLabel">
<a class="btn btn-close btn-sm position-absolute opacity-25 d-none d-sm-none d-md-block" title="Fermer ce PDF et retourner à l'accueil" style="position: absolute; top: 2px; right: 2px; font-size: 10px;" href="/metadata"></a>
<div class="offcanvas-header mb-0 pb-0">
<h5 class="mb-1 d-block w-100" id="sidebarToolsLabel">Édition de métadonnées<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-0" style="padding-bottom: 60px;">
<p id="text_document_name" class="text-muted" style="text-overflow: ellipsis; white-space: nowrap; overflow: hidden;" title=""><i class="bi bi-files"></i> <span></span></p>
<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="btn_container" 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 id="bottom_bar" class="position-fixed bottom-0 start-0 bg-white w-100 p-2 shadow-sm d-md-none">
<div id="bottom_bar_action" 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>
<script src="/vendor/pdf.js?legacy"></script>
<script>
var maxSize = <?php echo $maxSize ?>;
</script>
<script src="/js/metadata.js?202212070154"></script>
</body>
</html>