mirror of
https://github.com/24eme/signaturepdf
synced 2026-03-14 13:55:44 +01:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
a1de37f95a
5 changed files with 118 additions and 64 deletions
24
README.md
24
README.md
|
|
@ -39,6 +39,7 @@ Open-source software under the AGPL V3 license.
|
|||
- [Disabling the Organize Mode](#disabling-the-organize-mode)
|
||||
- [Hiding or Modifying the Demo PDF Link](#hiding-or-modifying-the-demo-pdf-link)
|
||||
- [Customize the CSS](#customize-the-css)
|
||||
- [Custom retention period for shared PDF](#custom-retention-period-for-shared-pdf)
|
||||
- [Default Fields for Metadata Editing](#default-fields-for-metadata-editing)
|
||||
- [Update](#update)
|
||||
- [Tests](#tests)
|
||||
|
|
@ -141,6 +142,29 @@ It's possible to add a custom CSS file to the location `public/css/app-specific.
|
|||
|
||||
If this file exists, it will be loaded automatically.
|
||||
|
||||
|
||||
### Custom retention period for shared PDF
|
||||
|
||||
In `config/config.ini` file activate these options :
|
||||
|
||||
```
|
||||
[signature]
|
||||
|
||||
; Enable custom retention period for shared PDF
|
||||
; This override the default retention periods
|
||||
; Warning: Text on the right of the colon will be translated according to the .po files
|
||||
;retention[+1 year]="for one year"
|
||||
;retention[+6 months]="for six months"
|
||||
;retention[+1 month]="for one month"
|
||||
;retention[+1 week]="for one week"
|
||||
;retention[+1 day]="for one day"
|
||||
;retention[+1 hour]="for one hour"
|
||||
|
||||
retention[+10 days]="for ten days"
|
||||
```
|
||||
|
||||
This configuration allows the retention of the PDF for only 10 days
|
||||
|
||||
### Default Fields for Metadata Editing
|
||||
|
||||
In the `config/config.ini` file, you can add as many fields as you want with the HTML input type (text, date, number, email, etc.) that will be preloaded for each PDF.
|
||||
|
|
|
|||
|
|
@ -66,6 +66,14 @@
|
|||
left: 6px;
|
||||
}
|
||||
|
||||
#color-picker {
|
||||
display: block; position: fixed; height:28px; width: 28px; border-radius: 24px; background: #000; top: 14px; right: 366px; border: 2px solid #fff; color: #fff; font-size: 10px; text-align: center; line-height: 20px; opacity: 0.25;
|
||||
}
|
||||
|
||||
#color-picker:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.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-drag-here_mobile, .canvas-container .btn-cancel {
|
||||
font-size: 30px;
|
||||
cursor: move;
|
||||
|
|
|
|||
|
|
@ -22,50 +22,49 @@ function responsiveDisplay() {
|
|||
async function loadPDF(pdfBlob) {
|
||||
showLoading('Loading')
|
||||
|
||||
let filename = pdfBlob.name;
|
||||
let url = await URL.createObjectURL(pdfBlob);
|
||||
const filename = pdfBlob.name;
|
||||
const url = URL.createObjectURL(pdfBlob);
|
||||
document.title = filename + ' - ' + document.title;
|
||||
document.querySelector('#text_document_name span').innerText = filename;
|
||||
|
||||
pdffile = 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) {
|
||||
for(fieldKey in defaultFields) {
|
||||
addMetadata(fieldKey, null, defaultFields[fieldKey]['type'], false);
|
||||
}
|
||||
|
||||
for(metaKey in metadata.info) {
|
||||
if(metaKey == "Custom" || metaKey == "PDFFormatVersion" || metaKey.match(/^Is/) || metaKey == "Trapped") {
|
||||
continue;
|
||||
}
|
||||
addMetadata(metaKey, metadata.info[metaKey], "text", false);
|
||||
}
|
||||
const loadingTask = pdfjsLib.getDocument(url);
|
||||
const pdf = await loadingTask.promise;
|
||||
const metadata = await pdf.getMetadata()
|
||||
|
||||
for(metaKey in metadata.info.Custom) {
|
||||
if(metaKey == "sha256") {
|
||||
continue;
|
||||
}
|
||||
for(fieldKey in defaultFields) {
|
||||
addMetadata(fieldKey, null, defaultFields[fieldKey]['type'], false);
|
||||
}
|
||||
|
||||
addMetadata(metaKey, metadata.info.Custom[metaKey], "text", false);
|
||||
}
|
||||
for(metaKey in metadata.info) {
|
||||
if(metaKey == "Custom" || metaKey == "PDFFormatVersion" || metaKey.match(/^Is/) || metaKey == "Trapped") {
|
||||
continue;
|
||||
}
|
||||
addMetadata(metaKey, metadata.info[metaKey], "text", false);
|
||||
}
|
||||
|
||||
for(let pageNumber = 1; pageNumber <= pdf.numPages; pageNumber++ ) {
|
||||
pdf.getPage(pageNumber).then(function(page) {
|
||||
let pageIndex = (page.pageNumber - 1);
|
||||
pages[pageIndex] = page;
|
||||
pageRender(pageIndex);
|
||||
});
|
||||
}
|
||||
if(document.querySelector('.input-metadata input')) {
|
||||
document.querySelector('.input-metadata input').focus();
|
||||
} else {
|
||||
document.getElementById('input_metadata_key').focus();
|
||||
}
|
||||
for(metaKey in metadata.info.Custom) {
|
||||
if(metaKey == "sha256") {
|
||||
continue;
|
||||
}
|
||||
|
||||
addMetadata(metaKey, metadata.info.Custom[metaKey], "text", false);
|
||||
}
|
||||
|
||||
for(let pageNumber = 1; pageNumber <= pdf.numPages; pageNumber++ ) {
|
||||
pdf.getPage(pageNumber).then(function(page) {
|
||||
let pageIndex = (page.pageNumber - 1);
|
||||
pages[pageIndex] = page;
|
||||
pageRender(pageIndex);
|
||||
});
|
||||
}, function (reason) {
|
||||
console.error(reason);
|
||||
});
|
||||
}
|
||||
|
||||
if(document.querySelector('.input-metadata input')) {
|
||||
document.querySelector('.input-metadata input').focus();
|
||||
} else {
|
||||
document.getElementById('input_metadata_key').focus();
|
||||
}
|
||||
|
||||
endLoading();
|
||||
|
||||
|
|
@ -319,7 +318,9 @@ async function pageMetadata(url) {
|
|||
responsiveDisplay();
|
||||
createEventsListener();
|
||||
await convertInputFileImagesToPDF(document.getElementById('input_pdf_upload'));
|
||||
loadPDF(document.getElementById('input_pdf_upload').files[0]);
|
||||
await loadPDF(document.getElementById('input_pdf_upload').files[0]).catch(function (reason) {
|
||||
console.error(reason);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ let penColor = localStorage.getItem('penColor') ?? '#000000'
|
|||
let nblayers = null;
|
||||
let hasModifications = false;
|
||||
let currentTextScale = 1;
|
||||
const defaultScale = 1.5;
|
||||
|
||||
async function loadPDF(pdfBlob) {
|
||||
let filename = pdfBlob.name;
|
||||
|
|
@ -549,8 +550,20 @@ function createAndAddSvgInCanvas(canvas, item, x, y, height = null) {
|
|||
fill: penColor
|
||||
});
|
||||
|
||||
fabric.Textbox.prototype.customEnterAction = function (e) {
|
||||
if (e.ctrlKey) {
|
||||
this.insertChars('\n', undefined, this.selectionStart)
|
||||
this.exitEditing();
|
||||
this.enterEditing();
|
||||
this.moveCursorRight(e);
|
||||
return
|
||||
}
|
||||
|
||||
this.exitEditing()
|
||||
}
|
||||
|
||||
addObjectInCanvas(canvas, textbox).setActiveObject(textbox);
|
||||
textbox.keysMap[13] = "exitEditing";
|
||||
textbox.keysMap[13] = "customEnterAction";
|
||||
textbox.lockScalingFlip = true;
|
||||
textbox.scaleX = currentTextScale;
|
||||
textbox.scaleY = currentTextScale;
|
||||
|
|
@ -617,7 +630,6 @@ function createAndAddSvgInCanvas(canvas, item, x, y, height = null) {
|
|||
function autoZoom() {
|
||||
clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(resizePDF, 100);
|
||||
updateWatermark();
|
||||
};
|
||||
|
||||
function zoomChange(inOrOut) {
|
||||
|
|
@ -843,28 +855,15 @@ function createEventsListener() {
|
|||
document.querySelector('input[name=watermark]')?.addEventListener('keyup', debounce(function (e) {
|
||||
setIsChanged(hasModifications || !!e.target.value)
|
||||
updateFlatten();
|
||||
|
||||
// Pourquoi 27 : 40 / 1.5 = 26.6666
|
||||
// fontSize ^ ^ currentScale par défaut
|
||||
// Comme ça le texte de l'overlay ne bouge pas au zoom
|
||||
const text = new fabric.Text(e.target.value, {angle: -40, fill: "#0009", fontSize: 27 * currentScale})
|
||||
const overlay = new fabric.Rect({
|
||||
fill: new fabric.Pattern({
|
||||
source: text.toCanvasElement(),
|
||||
}),
|
||||
})
|
||||
|
||||
canvasEditions.forEach(function (canvas) {
|
||||
overlay.height = canvas.height
|
||||
overlay.width = canvas.width
|
||||
|
||||
canvas.objectCaching = false
|
||||
canvas.setOverlayImage(overlay, canvas.renderAll.bind(canvas), {
|
||||
objectCaching: false
|
||||
})
|
||||
})
|
||||
updateWatermark();
|
||||
}, 750))
|
||||
|
||||
document.querySelector('input[name=watermark]')?.addEventListener('change', function (e) {
|
||||
setIsChanged(hasModifications || !!e.target.value)
|
||||
updateFlatten();
|
||||
updateWatermark();
|
||||
});
|
||||
|
||||
if(document.querySelector('#alert-signature-help')) {
|
||||
document.getElementById('btn-signature-help').addEventListener('click', function(event) {
|
||||
document.querySelector('#alert-signature-help').classList.remove('d-none');
|
||||
|
|
@ -878,6 +877,11 @@ function createEventsListener() {
|
|||
|
||||
if(document.getElementById('save')) {
|
||||
document.getElementById('save').addEventListener('click', function(event) {
|
||||
let previousScale = currentScale;
|
||||
if(currentScale != defaultScale) {
|
||||
resizePDF(defaultScale)
|
||||
while(!renderComplete) { }
|
||||
}
|
||||
let dataTransfer = new DataTransfer();
|
||||
canvasEditions.forEach(function(canvasEdition, index) {
|
||||
dataTransfer.items.add(new File([canvasEdition.toSVG()], index+'.svg', {
|
||||
|
|
@ -885,6 +889,11 @@ function createEventsListener() {
|
|||
}));
|
||||
})
|
||||
document.getElementById('input_svg').files = dataTransfer.files;
|
||||
if(previousScale != currentScale) {
|
||||
clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(resizePDF(previousScale), 100);
|
||||
}
|
||||
|
||||
hasModifications = false;
|
||||
});
|
||||
}
|
||||
|
|
@ -1032,6 +1041,10 @@ function createEventsListener() {
|
|||
storePenColor(penColorPicker.value)
|
||||
})
|
||||
|
||||
document.getElementById('color-picker').addEventListener('click', function(event) {
|
||||
penColorPicker.click();
|
||||
})
|
||||
|
||||
window.addEventListener('beforeunload', function(event) {
|
||||
if(!hasModifications) {
|
||||
return;
|
||||
|
|
@ -1225,11 +1238,18 @@ function storePenColor(color) {
|
|||
penColor = color
|
||||
penColorPicker.value = color
|
||||
localStorage.setItem('penColor', penColor)
|
||||
document.getElementById('color-picker').style.backgroundColor = penColor;
|
||||
if(penColor != "#000000") {
|
||||
document.getElementById('color-picker').style.opacity = 1;
|
||||
} else {
|
||||
document.getElementById('color-picker').style.opacity = 0.25;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const toolBox = (function () {
|
||||
const _coloricon = document.createElement('img')
|
||||
_coloricon.src = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-palette" viewBox="0 0 16 16"><path d="M8 5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3m4 3a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3M5.5 7a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m.5 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3"/><path d="M16 8c0 3.15-1.866 2.585-3.567 2.07C11.42 9.763 10.465 9.473 10 10c-.603.683-.475 1.819-.351 2.92C9.826 14.495 9.996 16 8 16a8 8 0 1 1 8-8m-8 7c.611 0 .654-.171.655-.176.078-.146.124-.464.07-1.119-.014-.168-.037-.37-.061-.591-.052-.464-.112-1.005-.118-1.462-.01-.707.083-1.61.704-2.314.369-.417.845-.578 1.272-.618.404-.038.812.026 1.16.104.343.077.702.186 1.025.284l.028.008c.346.105.658.199.953.266.653.148.904.083.991.024C14.717 9.38 15 9.161 15 8a7 7 0 1 0-7 7"/></svg>'
|
||||
_coloricon.src = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-droplet-fill" viewBox="0 0 16 16"><path d="M8 16a6 6 0 0 0 6-6c0-1.655-1.122-2.904-2.432-4.362C10.254 4.176 8.75 2.503 8 0c0 0-6 5.686-6 10a6 6 0 0 0 6 6M6.646 4.646l.708.708c-.29.29-1.128 1.311-1.907 2.87l-.894-.448c.82-1.641 1.717-2.753 2.093-3.13"/></svg>'
|
||||
|
||||
function _renderIcon(icon) {
|
||||
return function renderIcon(ctx, left, top, styleOverride, fabricObject) {
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="color-picker" class="shadow-sm" title="Changer la couleur de l'encre"><i class="bi bi-droplet-fill"></i></button>
|
||||
<div class="position-fixed top-0 start-0 bg-white w-100 p-2 shadow-sm d-md-none">
|
||||
<div class="d-grid gap-2">
|
||||
<button id="btn_svn_select" class="btn btn-light btn-lg" data-bs-toggle="offcanvas" data-bs-target="#sidebarTools" aria-controls="sidebarTools"><?php echo sprintf(_("%s Select a signature"), '<i class="bi bi-hand-index"></i>'); ?></button>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue