2023-04-18 23:44:38 +02:00
|
|
|
|
var windowWidth = window.innerWidth;
|
|
|
|
|
var menu = null;
|
|
|
|
|
var menuOffcanvas = null;
|
|
|
|
|
var is_mobile = function() {
|
|
|
|
|
return !(window.getComputedStyle(document.getElementById('is_mobile')).display === "none");
|
|
|
|
|
};
|
|
|
|
|
|
2023-04-19 02:29:24 +02:00
|
|
|
|
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 = [];
|
2023-04-20 15:55:35 +02:00
|
|
|
|
let filename = null
|
2023-04-20 13:21:44 +02:00
|
|
|
|
let pdffile = null
|
2023-04-20 15:52:27 +02:00
|
|
|
|
let deletedMetadata = [];
|
2023-04-19 02:29:24 +02:00
|
|
|
|
|
|
|
|
|
var loadPDF = async function(pdfBlob, filename, pdfIndex) {
|
|
|
|
|
let url = await URL.createObjectURL(pdfBlob);
|
2023-04-20 13:21:44 +02:00
|
|
|
|
|
|
|
|
|
pdffile = pdfBlob
|
|
|
|
|
|
2023-04-19 02:29:24 +02:00
|
|
|
|
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);
|
2023-04-20 15:37:01 +02:00
|
|
|
|
for(fieldKey in defaultFields) {
|
2023-04-20 15:43:20 +02:00
|
|
|
|
addMetadata(fieldKey, null, defaultFields[fieldKey]['type'], false);
|
2023-04-20 15:37:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 02:29:24 +02:00
|
|
|
|
for(metaKey in metadata.info) {
|
|
|
|
|
if(metaKey == "Custom" || metaKey == "PDFFormatVersion" || metaKey.match(/^Is/) || metaKey == "Trapped") {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-04-20 15:43:20 +02:00
|
|
|
|
addMetadata(metaKey, metadata.info[metaKey], "text", false);
|
2023-04-19 02:29:24 +02:00
|
|
|
|
}
|
2023-04-20 15:37:01 +02:00
|
|
|
|
|
2023-04-19 02:29:24 +02:00
|
|
|
|
for(metaKey in metadata.info.Custom) {
|
|
|
|
|
if(metaKey == "sha256") {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:43:20 +02:00
|
|
|
|
addMetadata(metaKey, metadata.info.Custom[metaKey], "text", false);
|
2023-04-19 02:29:24 +02:00
|
|
|
|
}
|
2023-04-19 17:26:55 +02:00
|
|
|
|
|
|
|
|
|
for(let pageNumber = 1; pageNumber <= pdf.numPages; pageNumber++ ) {
|
|
|
|
|
pdf.getPage(pageNumber).then(function(page) {
|
|
|
|
|
let pageIndex = (page.pageNumber - 1);
|
|
|
|
|
pages[pageIndex] = page;
|
|
|
|
|
pageRender(pageIndex);
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-04-20 15:43:20 +02:00
|
|
|
|
if(document.querySelector('.input-metadata input')) {
|
|
|
|
|
document.querySelector('.input-metadata input').focus();
|
2023-04-20 15:44:59 +02:00
|
|
|
|
} else {
|
|
|
|
|
document.getElementById('input_metadata_key').focus();
|
2023-04-20 15:43:20 +02:00
|
|
|
|
}
|
2023-04-19 02:29:24 +02:00
|
|
|
|
});
|
|
|
|
|
}, function (reason) {
|
|
|
|
|
console.error(reason);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return loadingTask;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 17:26:55 +02:00
|
|
|
|
var pageRender = async function(pageIndex) {
|
|
|
|
|
|
|
|
|
|
let page = pages[pageIndex];
|
|
|
|
|
|
|
|
|
|
let viewport = page.getViewport({scale: 1});
|
|
|
|
|
let sizeWidth = document.getElementById('container-pages').offsetWidth;
|
|
|
|
|
let scaleWidth = sizeWidth / viewport.width;
|
|
|
|
|
let viewportWidth = page.getViewport({scale: scaleWidth });
|
|
|
|
|
|
|
|
|
|
viewport = viewportWidth;
|
|
|
|
|
|
|
|
|
|
let canvasPDF = document.createElement('canvas');
|
|
|
|
|
canvasPDF.classList.add('shadow-sm');
|
|
|
|
|
document.getElementById('container-pages').appendChild(canvasPDF);
|
|
|
|
|
let context = canvasPDF.getContext('2d');
|
|
|
|
|
canvasPDF.height = viewport.height;
|
|
|
|
|
canvasPDF.width = viewport.width;
|
|
|
|
|
|
|
|
|
|
if(pdfRenderTasks[pageIndex]) {
|
|
|
|
|
pdfRenderTasks[pageIndex].cancel();
|
|
|
|
|
}
|
|
|
|
|
pdfRenderTasks[pageIndex] = await page.render({
|
|
|
|
|
canvasContext: context,
|
|
|
|
|
viewport: viewport,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:43:20 +02:00
|
|
|
|
var addMetadata = function(key, value, type, focus) {
|
2023-04-20 15:37:01 +02:00
|
|
|
|
let input = document.querySelector('.input-metadata input[name="'+key+'"]');
|
|
|
|
|
|
2023-04-20 16:11:53 +02:00
|
|
|
|
if(input && !input.value) {
|
2023-04-20 15:37:01 +02:00
|
|
|
|
input.value = value;
|
|
|
|
|
}
|
2023-04-20 15:43:20 +02:00
|
|
|
|
if(input && focus) {
|
2023-04-20 15:37:01 +02:00
|
|
|
|
input.focus();
|
2023-04-20 15:43:20 +02:00
|
|
|
|
}
|
|
|
|
|
if(input) {
|
2023-04-20 15:37:01 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 02:29:24 +02:00
|
|
|
|
let div = document.createElement('div');
|
2023-04-19 13:00:30 +02:00
|
|
|
|
div.classList.add('form-floating', 'mt-3', 'input-metadata');
|
|
|
|
|
|
2023-04-20 15:37:01 +02:00
|
|
|
|
input = document.createElement('input');
|
2023-04-19 02:29:24 +02:00
|
|
|
|
input.value = value;
|
2023-04-20 15:37:01 +02:00
|
|
|
|
input.type = type;
|
|
|
|
|
input.name = key;
|
2023-04-19 02:29:24 +02:00
|
|
|
|
input.classList.add('form-control');
|
2023-04-19 13:00:30 +02:00
|
|
|
|
|
2023-04-19 02:29:24 +02:00
|
|
|
|
let label = document.createElement('label');
|
|
|
|
|
label.innerText = key;
|
2023-04-19 13:00:30 +02:00
|
|
|
|
|
|
|
|
|
let deleteButton = document.createElement('div')
|
2023-04-20 16:24:23 +02:00
|
|
|
|
deleteButton.title = "Supprimer cette metadonnée"
|
2023-04-19 13:00:30 +02:00
|
|
|
|
deleteButton.innerHTML = "×"
|
|
|
|
|
deleteButton.classList.add('delete-metadata')
|
|
|
|
|
|
2023-04-19 02:29:24 +02:00
|
|
|
|
div.appendChild(input);
|
|
|
|
|
div.appendChild(label);
|
2023-04-19 13:00:30 +02:00
|
|
|
|
div.appendChild(deleteButton);
|
2023-04-19 09:03:35 +02:00
|
|
|
|
document.getElementById('form-metadata-container').appendChild(div);
|
2023-04-19 13:00:30 +02:00
|
|
|
|
|
2023-04-20 15:43:20 +02:00
|
|
|
|
if(focus) {
|
|
|
|
|
input.focus();
|
|
|
|
|
}
|
2023-04-19 02:29:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 13:00:30 +02:00
|
|
|
|
const deleteMetadata = function(el) {
|
2023-04-19 15:42:48 +02:00
|
|
|
|
if (confirm("Souhaitez-vous supprimer ce champ ?") === false) return;
|
|
|
|
|
|
2023-04-19 13:00:30 +02:00
|
|
|
|
const input = el.closest('.input-metadata')
|
2023-04-20 15:52:27 +02:00
|
|
|
|
const label = input.querySelector('label').innerText
|
|
|
|
|
deletedMetadata.push(label)
|
2023-04-19 13:00:30 +02:00
|
|
|
|
input.remove()
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:17:49 +02:00
|
|
|
|
const DL = function (d,f) {
|
|
|
|
|
let a = document.createElement("a"),
|
|
|
|
|
u = URL.createObjectURL(d);
|
|
|
|
|
a.download = f,
|
|
|
|
|
a.href = u,
|
|
|
|
|
a.click(),
|
|
|
|
|
setTimeout(() => URL.revokeObjectURL(u))
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 13:21:44 +02:00
|
|
|
|
const save = async function () {
|
|
|
|
|
const PDFDocument = window['PDFLib'].PDFDocument
|
|
|
|
|
const PDFHexString = window['PDFLib'].PDFHexString
|
|
|
|
|
const PDFName = window['PDFLib'].PDFName
|
|
|
|
|
|
2023-04-20 15:52:27 +02:00
|
|
|
|
const arrayBuffer = await pdffile.arrayBuffer();
|
|
|
|
|
const pdf = await PDFDocument.load(arrayBuffer);
|
2023-04-20 13:21:44 +02:00
|
|
|
|
|
2023-04-20 15:52:27 +02:00
|
|
|
|
deletedMetadata.forEach(function (el) {
|
|
|
|
|
pdf.getInfoDict().delete(PDFName.of(el))
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
([...document.getElementsByClassName('input-metadata')] || []).forEach(function (el) {
|
|
|
|
|
const label = el.querySelector('label').innerText
|
|
|
|
|
const input = el.querySelector('input').value
|
|
|
|
|
|
|
|
|
|
pdf.getInfoDict().set(PDFName.of(label), PDFHexString.fromText(input));
|
|
|
|
|
});
|
2023-04-20 13:21:44 +02:00
|
|
|
|
|
2023-04-20 15:52:27 +02:00
|
|
|
|
const newPDF = new Blob([await pdf.save()], {type: "application/pdf"});
|
2023-04-20 15:55:35 +02:00
|
|
|
|
DL(newPDF, filename)
|
2023-04-20 13:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-18 23:44:38 +02:00
|
|
|
|
var createEventsListener = function() {
|
2023-04-19 09:03:35 +02:00
|
|
|
|
document.getElementById('form_metadata_add').addEventListener('submit', function(e) {
|
|
|
|
|
let formData = new FormData(this);
|
2023-04-20 15:43:20 +02:00
|
|
|
|
addMetadata(formData.get('metadata_key'), "", "text", true);
|
2023-04-20 00:02:02 +02:00
|
|
|
|
this.classList.add('invisible');
|
|
|
|
|
setTimeout(function() { document.getElementById('form_metadata_add').classList.remove('invisible'); }, 400);
|
2023-04-19 09:03:35 +02:00
|
|
|
|
this.reset();
|
|
|
|
|
e.preventDefault();
|
2023-04-20 00:02:02 +02:00
|
|
|
|
});
|
|
|
|
|
document.getElementById('input_metadata_value').addEventListener('focus', function(e) {
|
|
|
|
|
if(document.getElementById('input_metadata_key').value) {
|
|
|
|
|
document.querySelector('#form_metadata_add button').click();
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-04-19 13:00:30 +02:00
|
|
|
|
document.addEventListener('click', function (event) {
|
|
|
|
|
if (event.target.closest(".delete-metadata")) {
|
|
|
|
|
deleteMetadata(event.target)
|
|
|
|
|
}
|
|
|
|
|
})
|
2023-04-20 13:21:44 +02:00
|
|
|
|
|
|
|
|
|
document.getElementById('save').addEventListener('click', function (e) {
|
|
|
|
|
save()
|
|
|
|
|
})
|
2023-04-18 23:44:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
2023-05-03 01:34:07 +02:00
|
|
|
|
let cache;
|
|
|
|
|
try {
|
|
|
|
|
cache = await caches.open('pdf');
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e)
|
|
|
|
|
alert("Erreur d'accès au cache. Cette application ne fonctionne pas en mode de navigation privée");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-04-18 23:44:38 +02:00
|
|
|
|
document.getElementById('input_pdf_upload').addEventListener('change', async function(event) {
|
|
|
|
|
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) {
|
2023-04-20 15:55:35 +02:00
|
|
|
|
filename = url.replace('/pdf/', '');
|
2023-04-18 23:44:38 +02:00
|
|
|
|
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();
|
|
|
|
|
})
|
|
|
|
|
})();
|