From 3f7a41f0eb333eb0b99a3d1658d6a7c78a46e589 Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Tue, 1 Jul 2025 12:25:15 +0200 Subject: [PATCH 01/20] =?UTF-8?q?attachement:=20lecture=20des=20noeuds=20d?= =?UTF-8?q?es=20xml=20attach=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/js/metadata.js | 58 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/public/js/metadata.js b/public/js/metadata.js index 1c9079f..72e21ec 100644 --- a/public/js/metadata.js +++ b/public/js/metadata.js @@ -32,6 +32,7 @@ async function loadPDF(pdfBlob) { const loadingTask = pdfjsLib.getDocument(url); const pdf = await loadingTask.promise; const metadata = await pdf.getMetadata() + const attachments = await pdf.getAttachments(); for(fieldKey in defaultFields) { addMetadata(fieldKey, null, defaultFields[fieldKey]['type'], false); @@ -52,6 +53,39 @@ async function loadPDF(pdfBlob) { addMetadata(metaKey, metadata.info.Custom[metaKey], "text", false); } + if (attachments) { + Object.entries(attachments).forEach(([_key, value]) => { + if (value.filename.startsWith('factur-x') === false) { + return + } + const decodedAttachment = new TextDecoder().decode(value.content) + const parser = new DOMParser(); + const xml = parser.parseFromString(decodedAttachment, "application/xml") + const error = xml.querySelector('parseerror') + if (error) { + console.log(error) + return + } + + const walker = xml.createTreeWalker(xml.firstChild, NodeFilter.SHOW_TEXT) + while(walker.nextNode()) { + const node = walker.currentNode + + const treeKey = [] + treeKey.push(node.parentNode.localName) + + let root = node.parentNode + while (! (root.parentNode instanceof XMLDocument)) { + root = root.parentNode + treeKey.push(root.localName) // nodeName si on veut le namespace + } + + const newInput = addMetadata(treeKey.join(' « '), node.textContent.trim(), "text", false, true) + newInput.dataset.fromAttachment = value.filename + } + }) + } + for(let pageNumber = 1; pageNumber <= pdf.numPages; pageNumber++ ) { pdf.getPage(pageNumber).then(function(page) { let pageIndex = (page.pageNumber - 1); @@ -130,17 +164,19 @@ async function pageRender(pageIndex) { }) } -function addMetadata(key, value, type, focus) { - let input = document.querySelector('.input-metadata input[name="'+key+'"]'); +function addMetadata(key, value, type, focus, forceCreation = false) { + if (! forceCreation) { + let input = document.querySelector('.input-metadata input[name="'+key+'"]'); - if(input && !input.value) { - input.value = value; - } - if(input && focus) { - input.focus(); - } - if(input) { - return; + if(input && !input.value) { + input.value = value; + } + if(input && focus) { + input.focus(); + } + if(input) { + return input; + } } let div = document.createElement('div'); @@ -168,6 +204,8 @@ function addMetadata(key, value, type, focus) { if(focus) { input.focus(); } + + return input } function deleteMetadata(el) { From f69a0b1300fb31c3beb4d92a51cb7bafcbd4a1ce Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Tue, 1 Jul 2025 15:32:35 +0200 Subject: [PATCH 02/20] =?UTF-8?q?attachment=20on=20enregistre=20pas=20les?= =?UTF-8?q?=20infos=20des=20xml=20dans=20les=20metadonn=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/js/metadata.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/js/metadata.js b/public/js/metadata.js index 72e21ec..e44e8aa 100644 --- a/public/js/metadata.js +++ b/public/js/metadata.js @@ -242,6 +242,10 @@ async function save() { const label = el.querySelector('label').innerText const input = el.querySelector('input').value + if ('fromAttachment' in el.querySelector('input').dataset) { + return; + } + pdf.getInfoDict().set(PDFName.of(label), PDFHexString.fromText(input)); }); From d756be3409afffb05582cebfd878dda56a561f1f Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Tue, 1 Jul 2025 15:33:34 +0200 Subject: [PATCH 03/20] attachement: readonly les champs du xml --- public/js/metadata.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/js/metadata.js b/public/js/metadata.js index e44e8aa..2f1740b 100644 --- a/public/js/metadata.js +++ b/public/js/metadata.js @@ -82,6 +82,7 @@ async function loadPDF(pdfBlob) { const newInput = addMetadata(treeKey.join(' « '), node.textContent.trim(), "text", false, true) newInput.dataset.fromAttachment = value.filename + newInput.disabled = true } }) } From 92cc194441e9d8bd34f83c8037efb8640d513047 Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Tue, 1 Jul 2025 19:14:30 +0200 Subject: [PATCH 04/20] toolbox: enhanced form --- public/js/signature.js | 62 +++++++++++++++++++++++------------- templates/signature.html.php | 2 +- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/public/js/signature.js b/public/js/signature.js index 505fdcc..d4c4c2f 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -170,6 +170,20 @@ async function loadPDF(pdfBlob) { toolBox.init(event.selected[0]) }); + canvasEdition.on("selection:updated", function(event) { + toolBox.reset() + if (event.selected.length > 1 || event.selected.length === 0) { + return; + } + + toolBox.init(event.selected[0]) + }); + canvasEdition.on("object:moving", function(event) { + debounce(toolBox.move(), 500) + }); + canvasEdition.on("selection:cleared", function(event) { + toolBox.reset() + }); canvasEditions.push(canvasEdition); }); } @@ -1251,19 +1265,11 @@ const toolBox = (function () { const _coloricon = document.createElement('img') _coloricon.src = 'data:image/svg+xml,' - function _renderIcon(icon) { - return function renderIcon(ctx, left, top, styleOverride, fabricObject) { - const size = this.cornerSize; - ctx.save(); - ctx.translate(left, top); - ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle)); - ctx.drawImage(icon, -size/2, -size/2, size, size); - ctx.restore(); - } - } + let _elToolbox + let _elSelected function _changeColor(eventData, transform) { - const target = transform.target; + const target = transform const _colorpicker = document.createElement('input') _colorpicker.setAttribute('type', 'color') _colorpicker.value = penColor @@ -1281,21 +1287,31 @@ const toolBox = (function () { } function init(el) { - colorControl = new fabric.Control({ - x: 0.5, - y: -0.5, - offsetY: -16, - offsetX: 16, - cursorStyle: 'pointer', - mouseUpHandler: _changeColor, - render: _renderIcon(_coloricon), - cornerSize: 24 - }) + _elSelected = el - el.controls.color = colorControl + _elToolbox = document.createElement('div') + _elToolbox.classList.add('position-absolute', 'border', 'p-1', 'bg-secondary-subtle', 'shadow-sm') + _elToolbox.style.top = (el.top + el.height + _coloricon.height + 2)+'px' + _elToolbox.style.left = (el.left + _coloricon.width + el.width / 2)+'px' + _elToolbox.appendChild(_coloricon) + document.getElementById('container-pages').appendChild(_elToolbox) + + _coloricon.addEventListener('click', function() {_changeColor(null, _elSelected)}) + } + + function move() { + _elToolbox.style.top = (_elSelected.top + _elSelected.height + _coloricon.height + 20)+'px' + _elToolbox.style.left = (_elSelected.left + _coloricon.width + _elSelected.width / 2)+'px' + } + + function reset() { + _elSelected = null + _elToolbox.remove() } return { - init: init + init: init, + move: move, + reset: reset } })() diff --git a/templates/signature.html.php b/templates/signature.html.php index d41a8f2..be4e253 100644 --- a/templates/signature.html.php +++ b/templates/signature.html.php @@ -41,7 +41,7 @@
-
+
From 10e0dd0acddc9a0e6b7269c0c1d3c974292c1297 Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Tue, 1 Jul 2025 19:26:54 +0200 Subject: [PATCH 05/20] =?UTF-8?q?metadata:=20label=20width=20100%=20pour?= =?UTF-8?q?=20pas=20que=20=C3=A7a=20d=C3=A9passe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/css/app.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/css/app.css b/public/css/app.css index dadd176..a10db98 100644 --- a/public/css/app.css +++ b/public/css/app.css @@ -113,6 +113,10 @@ user-select: none; } +.input-metadata > label { + width: 110%; +} + .input-metadata:hover > .delete-metadata { display: block; } From 6747c7490d158843b8d4be97b1c52a18b077efef Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 11:29:24 +0200 Subject: [PATCH 06/20] toolbar: don't follow anymore, it's fixed top --- public/js/signature.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/public/js/signature.js b/public/js/signature.js index d4c4c2f..db177d2 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -178,9 +178,6 @@ async function loadPDF(pdfBlob) { toolBox.init(event.selected[0]) }); - canvasEdition.on("object:moving", function(event) { - debounce(toolBox.move(), 500) - }); canvasEdition.on("selection:cleared", function(event) { toolBox.reset() }); @@ -1290,20 +1287,14 @@ const toolBox = (function () { _elSelected = el _elToolbox = document.createElement('div') - _elToolbox.classList.add('position-absolute', 'border', 'p-1', 'bg-secondary-subtle', 'shadow-sm') - _elToolbox.style.top = (el.top + el.height + _coloricon.height + 2)+'px' - _elToolbox.style.left = (el.left + _coloricon.width + el.width / 2)+'px' + _elToolbox.classList.add('fixed-top', 'border', 'p-1', 'bg-body-secondary', 'shadow-sm', 'w-25', 'm-auto', 'mt-3', 'd-xs-none', 'd-sm-none', 'd-md-block') + _elToolbox.appendChild(_coloricon) - document.getElementById('container-pages').appendChild(_elToolbox) + document.body.appendChild(_elToolbox) _coloricon.addEventListener('click', function() {_changeColor(null, _elSelected)}) } - function move() { - _elToolbox.style.top = (_elSelected.top + _elSelected.height + _coloricon.height + 20)+'px' - _elToolbox.style.left = (_elSelected.left + _coloricon.width + _elSelected.width / 2)+'px' - } - function reset() { _elSelected = null _elToolbox.remove() @@ -1311,7 +1302,6 @@ const toolBox = (function () { return { init: init, - move: move, reset: reset } })() From 33439c2eb812e984b9a830eb01224b133ff21641 Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 11:31:47 +0200 Subject: [PATCH 07/20] change color function don't need parameters --- public/js/signature.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/public/js/signature.js b/public/js/signature.js index db177d2..5dc5739 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -1265,16 +1265,15 @@ const toolBox = (function () { let _elToolbox let _elSelected - function _changeColor(eventData, transform) { - const target = transform + function _changeColor() { const _colorpicker = document.createElement('input') _colorpicker.setAttribute('type', 'color') _colorpicker.value = penColor _colorpicker.addEventListener('input', function (e) { - target.set({ fill: e.target.value }) - target.canvas.requestRenderAll() - if(target.type != "rect") { + _elSelected.set({ fill: e.target.value }) + _elSelected.canvas.requestRenderAll() + if(_elSelected.type != "rect") { storePenColor(e.target.value) } }) @@ -1292,7 +1291,7 @@ const toolBox = (function () { _elToolbox.appendChild(_coloricon) document.body.appendChild(_elToolbox) - _coloricon.addEventListener('click', function() {_changeColor(null, _elSelected)}) + _coloricon.addEventListener('click', _changeColor) } function reset() { From 9cb833e8a72464eee14b12b84f95c16a23122752 Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 11:44:13 +0200 Subject: [PATCH 08/20] toolbox: cursor pointer --- public/css/app.css | 4 ++++ public/js/signature.js | 1 + 2 files changed, 5 insertions(+) diff --git a/public/css/app.css b/public/css/app.css index a10db98..e1a43ce 100644 --- a/public/css/app.css +++ b/public/css/app.css @@ -74,6 +74,10 @@ opacity: 1; } +#toolbox img { + cursor: pointer; +} + .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; diff --git a/public/js/signature.js b/public/js/signature.js index 5dc5739..ffa5049 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -1286,6 +1286,7 @@ const toolBox = (function () { _elSelected = el _elToolbox = document.createElement('div') + _elToolbox.id = 'toolbox' _elToolbox.classList.add('fixed-top', 'border', 'p-1', 'bg-body-secondary', 'shadow-sm', 'w-25', 'm-auto', 'mt-3', 'd-xs-none', 'd-sm-none', 'd-md-block') _elToolbox.appendChild(_coloricon) From bbaf40d970a7e9172e812f039984c20791d31c60 Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 11:55:30 +0200 Subject: [PATCH 09/20] toolbox: img to i --- public/css/app.css | 2 +- public/js/signature.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/css/app.css b/public/css/app.css index e1a43ce..d188b62 100644 --- a/public/css/app.css +++ b/public/css/app.css @@ -74,7 +74,7 @@ opacity: 1; } -#toolbox img { +#toolbox i { cursor: pointer; } diff --git a/public/js/signature.js b/public/js/signature.js index ffa5049..abc4e45 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -1259,8 +1259,8 @@ function storePenColor(color) { } const toolBox = (function () { - const _coloricon = document.createElement('img') - _coloricon.src = 'data:image/svg+xml,' + const _coloricon = document.createElement('i') + _coloricon.classList.add('bi', 'bi-droplet-fill', 'mx-1') let _elToolbox let _elSelected From 57932c187e5ee114de78ca4f6ba6972a65f607bb Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 12:07:16 +0200 Subject: [PATCH 10/20] toolbox: trashicon delete element --- public/js/signature.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/public/js/signature.js b/public/js/signature.js index abc4e45..ad3e753 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -1262,6 +1262,9 @@ const toolBox = (function () { const _coloricon = document.createElement('i') _coloricon.classList.add('bi', 'bi-droplet-fill', 'mx-1') + const _trashicon = document.createElement('i') + _trashicon.classList.add('bi', 'bi-trash3', 'float-end', 'border-start', 'mx-1', 'ps-1') + let _elToolbox let _elSelected @@ -1282,6 +1285,11 @@ const toolBox = (function () { _colorpicker.remove() } + function _delete() { + deleteActiveObject() + this.reset() + } + function init(el) { _elSelected = el @@ -1290,9 +1298,11 @@ const toolBox = (function () { _elToolbox.classList.add('fixed-top', 'border', 'p-1', 'bg-body-secondary', 'shadow-sm', 'w-25', 'm-auto', 'mt-3', 'd-xs-none', 'd-sm-none', 'd-md-block') _elToolbox.appendChild(_coloricon) + _elToolbox.appendChild(_trashicon) document.body.appendChild(_elToolbox) _coloricon.addEventListener('click', _changeColor) + _trashicon.addEventListener('click', _delete) } function reset() { From 4b977407a9d6f606f76de75971c8a571f9695d81 Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 12:31:44 +0200 Subject: [PATCH 11/20] toolbox: hidden in small screen + on the left --- public/js/signature.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/signature.js b/public/js/signature.js index ad3e753..0ec57a6 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -1295,7 +1295,7 @@ const toolBox = (function () { _elToolbox = document.createElement('div') _elToolbox.id = 'toolbox' - _elToolbox.classList.add('fixed-top', 'border', 'p-1', 'bg-body-secondary', 'shadow-sm', 'w-25', 'm-auto', 'mt-3', 'd-xs-none', 'd-sm-none', 'd-md-block') + _elToolbox.classList.add('fixed-top', 'border', 'p-1', 'bg-body-secondary', 'shadow-sm', 'w-25', 'ms-3', 'mt-3', 'd-none', 'd-md-block') _elToolbox.appendChild(_coloricon) _elToolbox.appendChild(_trashicon) From bab65b046b0f9357a77b44cfcaa7761c1d391b0e Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 12:46:47 +0200 Subject: [PATCH 12/20] toolbox: width max-content --- public/js/signature.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/public/js/signature.js b/public/js/signature.js index 0ec57a6..c890b89 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -1263,7 +1263,7 @@ const toolBox = (function () { _coloricon.classList.add('bi', 'bi-droplet-fill', 'mx-1') const _trashicon = document.createElement('i') - _trashicon.classList.add('bi', 'bi-trash3', 'float-end', 'border-start', 'mx-1', 'ps-1') + _trashicon.classList.add('bi', 'bi-trash3', 'float-end', 'border-start', 'border-2', 'mx-1', 'ps-1') let _elToolbox let _elSelected @@ -1295,7 +1295,8 @@ const toolBox = (function () { _elToolbox = document.createElement('div') _elToolbox.id = 'toolbox' - _elToolbox.classList.add('fixed-top', 'border', 'p-1', 'bg-body-secondary', 'shadow-sm', 'w-25', 'ms-3', 'mt-3', 'd-none', 'd-md-block') + _elToolbox.classList.add('fixed-top', 'border', 'p-1', 'bg-body-secondary', 'shadow-sm', 'ms-3', 'mt-3', 'd-none', 'd-md-block') + _elToolbox.style.width = 'max-content' _elToolbox.appendChild(_coloricon) _elToolbox.appendChild(_trashicon) From b7ef7218c9699b0c81d9b84a0b481f4e3249fba7 Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 12:58:11 +0200 Subject: [PATCH 13/20] toolbox: reset if div already exists fix issues where selection is made on multiples canvases --- public/js/signature.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/js/signature.js b/public/js/signature.js index c890b89..bd15591 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -1291,6 +1291,10 @@ const toolBox = (function () { } function init(el) { + if (_elToolbox) { + this.reset() + } + _elSelected = el _elToolbox = document.createElement('div') From 3ce7240682115d2ff400e518fd784389400ab53e Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 13:02:17 +0200 Subject: [PATCH 14/20] toolbox: copy item to all canvas --- public/js/signature.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/public/js/signature.js b/public/js/signature.js index bd15591..eb2f7f8 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -1265,6 +1265,9 @@ const toolBox = (function () { const _trashicon = document.createElement('i') _trashicon.classList.add('bi', 'bi-trash3', 'float-end', 'border-start', 'border-2', 'mx-1', 'ps-1') + const _copyicon = document.createElement('i') + _copyicon.classList.add('bi', 'bi-copy', 'mx-1') + let _elToolbox let _elSelected @@ -1285,6 +1288,19 @@ const toolBox = (function () { _colorpicker.remove() } + function _copy() { + canvasEditions.forEach(function (canvas) { + if (_elSelected.canvas === canvas) { + return + } + + _elSelected.clone(function (clonedItem) { + addObjectInCanvas(canvas, clonedItem) + }) + }) + + } + function _delete() { deleteActiveObject() this.reset() @@ -1304,10 +1320,12 @@ const toolBox = (function () { _elToolbox.appendChild(_coloricon) _elToolbox.appendChild(_trashicon) + _elToolbox.appendChild(_copyicon) document.body.appendChild(_elToolbox) _coloricon.addEventListener('click', _changeColor) _trashicon.addEventListener('click', _delete) + _copyicon.addEventListener('click', _copy) } function reset() { From 46ea01a315c4734b9cf06df8002a8895a9c8211f Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 13:03:23 +0200 Subject: [PATCH 15/20] fix issue with reset not a function when deleting elements --- public/js/signature.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/js/signature.js b/public/js/signature.js index eb2f7f8..3703b71 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -1303,12 +1303,12 @@ const toolBox = (function () { function _delete() { deleteActiveObject() - this.reset() + reset() } function init(el) { if (_elToolbox) { - this.reset() + reset() } _elSelected = el From e1f8a4c0bc4f8d36c922eb314c95887d06202d74 Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 16:52:23 +0200 Subject: [PATCH 16/20] =?UTF-8?q?toolbox:=20on=20recr=C3=A9er=20pas=20?= =?UTF-8?q?=C3=A0=20chaque=20s=C3=A9lection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit on calcule juste la position lors de la sélection --- public/js/signature.js | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/public/js/signature.js b/public/js/signature.js index 3703b71..e21cf1c 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -1268,9 +1268,22 @@ const toolBox = (function () { const _copyicon = document.createElement('i') _copyicon.classList.add('bi', 'bi-copy', 'mx-1') - let _elToolbox let _elSelected + const _elToolbox = document.createElement('div') + _elToolbox.id = 'toolbox' + _elToolbox.classList.add('position-fixed', 'border', 'p-1', 'bg-body-secondary', 'shadow-sm', 'ms-3', 'mt-3', 'd-none', 'd-md-block') + _elToolbox.style['z-index'] = 1030 + _elToolbox.style.width = 'max-content' + + _elToolbox.appendChild(_coloricon) + _elToolbox.appendChild(_trashicon) + _elToolbox.appendChild(_copyicon) + + _coloricon.addEventListener('click', _changeColor) + _trashicon.addEventListener('click', _delete) + _copyicon.addEventListener('click', _copy) + function _changeColor() { const _colorpicker = document.createElement('input') _colorpicker.setAttribute('type', 'color') @@ -1312,20 +1325,19 @@ const toolBox = (function () { } _elSelected = el - - _elToolbox = document.createElement('div') - _elToolbox.id = 'toolbox' - _elToolbox.classList.add('fixed-top', 'border', 'p-1', 'bg-body-secondary', 'shadow-sm', 'ms-3', 'mt-3', 'd-none', 'd-md-block') - _elToolbox.style.width = 'max-content' - - _elToolbox.appendChild(_coloricon) - _elToolbox.appendChild(_trashicon) - _elToolbox.appendChild(_copyicon) document.body.appendChild(_elToolbox) - _coloricon.addEventListener('click', _changeColor) - _trashicon.addEventListener('click', _delete) - _copyicon.addEventListener('click', _copy) + _elToolbox.style.left = ( + _elSelected.getBoundingRect().left + + _elSelected.getScaledWidth() / 2 + - _elToolbox.offsetWidth / 2 + + +window.getComputedStyle(_elToolbox).getPropertyValue("margin-left").replace('px', '') + ) + 'px' + _elToolbox.style.top = ( + _elSelected.getBoundingRect().top + + _elSelected.getScaledHeight() + + +window.getComputedStyle(_elToolbox).getPropertyValue("height").replace('px', '') / 2 + ) + 'px' } function reset() { From 1cc7bd08f94f5a7084ca8685cd7fb31839d32e9b Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 17:00:54 +0200 Subject: [PATCH 17/20] toolbox: follow object --- public/js/signature.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/js/signature.js b/public/js/signature.js index e21cf1c..c9c508b 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -178,6 +178,9 @@ async function loadPDF(pdfBlob) { toolBox.init(event.selected[0]) }); + canvasEdition.on("object:modified", function(event) { + toolBox.init(event.target) + }); canvasEdition.on("selection:cleared", function(event) { toolBox.reset() }); From 88aebb7cbddba591a22c458c76c5da3580ac4433 Mon Sep 17 00:00:00 2001 From: Gabriel Poma Date: Wed, 2 Jul 2025 19:07:43 +0200 Subject: [PATCH 18/20] toolbox: opti positionnement de la toolbox suit le scroll se place correctement quand on rotate --- public/js/signature.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/public/js/signature.js b/public/js/signature.js index c9c508b..2205c7e 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -1275,7 +1275,7 @@ const toolBox = (function () { const _elToolbox = document.createElement('div') _elToolbox.id = 'toolbox' - _elToolbox.classList.add('position-fixed', 'border', 'p-1', 'bg-body-secondary', 'shadow-sm', 'ms-3', 'mt-3', 'd-none', 'd-md-block') + _elToolbox.classList.add('position-absolute', 'border', 'p-1', 'bg-body-secondary', 'shadow-sm', 'ms-3', 'mt-3', 'd-none', 'd-md-block') _elToolbox.style['z-index'] = 1030 _elToolbox.style.width = 'max-content' @@ -1328,7 +1328,8 @@ const toolBox = (function () { } _elSelected = el - document.body.appendChild(_elToolbox) + const container = document.getElementById('container-pages') + container.appendChild(_elToolbox) _elToolbox.style.left = ( _elSelected.getBoundingRect().left @@ -1337,9 +1338,9 @@ const toolBox = (function () { + +window.getComputedStyle(_elToolbox).getPropertyValue("margin-left").replace('px', '') ) + 'px' _elToolbox.style.top = ( - _elSelected.getBoundingRect().top - + _elSelected.getScaledHeight() - + +window.getComputedStyle(_elToolbox).getPropertyValue("height").replace('px', '') / 2 + Math.max(..._elSelected.getCoords().map((c) => c.y)) // on sélectionne le coin le plus bas + + _elSelected.canvas._offset.top // hauteur du canvas dans le viewport + + container.scrollTop // haut du container ) + 'px' } From 4905790eb43d398b46e397d8b3fd137ecfee77d9 Mon Sep 17 00:00:00 2001 From: Vincent LAURENT Date: Thu, 3 Jul 2025 00:22:10 +0200 Subject: [PATCH 19/20] format: added page format in page title --- public/js/organization.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/js/organization.js b/public/js/organization.js index 9ad4bac..cf1a165 100644 --- a/public/js/organization.js +++ b/public/js/organization.js @@ -47,6 +47,10 @@ async function loadPDF(pdfBlob, filename, pdfIndex) { pdf.getPage(pageNumber).then(function(page) { let pageIndex = pdfLetter + "_" + (page.pageNumber - 1); pages[pageIndex] = page; + const viewportFormat = page.getViewport({ scale: 1 }); + const widthFormat = Math.round(viewportFormat.width * 25.4 / 72 * 10) / 10; + const heightFormat = Math.round(viewportFormat.height * 25.4 / 72 * 10) / 10; + formats[pageIndex] = widthFormat + " x " + heightFormat + " mm"; let pageHTML = '
'; pageHTML += ''; @@ -57,7 +61,7 @@ async function loadPDF(pdfBlob, filename, pdfIndex) { pageHTML += '
'; pageHTML += '
'; pageHTML += '
'; - pageHTML += '

' + trad['Page'] + ' ' + page.pageNumber + ' - ' + filename + '

'; + pageHTML += '

' + trad['Page'] + ' ' + page.pageNumber + ' - '+formats[pageIndex]+' - ' + filename + '

'; pageHTML += ''; pageHTML += ''; pageHTML += ''; From ffdce0233786303502d647615a2a2da6fc2f6511 Mon Sep 17 00:00:00 2001 From: Vincent LAURENT Date: Thu, 3 Jul 2025 00:26:30 +0200 Subject: [PATCH 20/20] format: Title page in title attribute --- public/js/organization.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/public/js/organization.js b/public/js/organization.js index cf1a165..585ea2a 100644 --- a/public/js/organization.js +++ b/public/js/organization.js @@ -23,6 +23,7 @@ if(is_mobile()) { let nbPDF = 0; let pages = []; +let formats = []; let pdfRenderTasks = []; async function loadPDF(pdfBlob, filename, pdfIndex) { @@ -51,7 +52,7 @@ async function loadPDF(pdfBlob, filename, pdfIndex) { const widthFormat = Math.round(viewportFormat.width * 25.4 / 72 * 10) / 10; const heightFormat = Math.round(viewportFormat.height * 25.4 / 72 * 10) / 10; formats[pageIndex] = widthFormat + " x " + heightFormat + " mm"; - + let pageTitle = trad['Page'] + ' ' + page.pageNumber + ' - '+formats[pageIndex]+' - ' + filename; let pageHTML = '
'; pageHTML += ''; pageHTML += '
'; @@ -61,7 +62,7 @@ async function loadPDF(pdfBlob, filename, pdfIndex) { pageHTML += '
'; pageHTML += '
'; pageHTML += '
'; - pageHTML += '

' + trad['Page'] + ' ' + page.pageNumber + ' - '+formats[pageIndex]+' - ' + filename + '

'; + pageHTML += '

' + pageTitle + '

'; pageHTML += ''; pageHTML += ''; pageHTML += ''; @@ -72,6 +73,7 @@ async function loadPDF(pdfBlob, filename, pdfIndex) { document.getElementById('container-pages').insertAdjacentHTML('beforeend', pageHTML); let canvasContainer = document.getElementById('canvas-container-' + pageIndex); + canvasContainer.title = pageTitle; canvasContainer.addEventListener('click', function(e) { canvasContainer.querySelector('.btn-select').click(); }); @@ -218,6 +220,7 @@ async function pageRender(pageIndex) { scrollWidth = -4; } let page = pages[pageIndex]; + let rotation = parseInt(document.querySelector('#input_rotate_'+pageIndex).value); let viewport = page.getViewport({scale: 1, rotation: rotation}); let sizeWidth = Math.floor((document.getElementById('container-pages').offsetWidth - (8*(nbPagePerLine+1)) - scrollWidth) / nbPagePerLine);