djgentelella 0.3.28__py3-none-any.whl → 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- djgentelella/__init__.py +4 -1
- djgentelella/admin.py +4 -3
- djgentelella/fields/files.py +27 -1
- djgentelella/firmador_digital/__init__.py +0 -0
- djgentelella/firmador_digital/config/__init__.py +0 -0
- djgentelella/firmador_digital/config/asgi_config.py +32 -0
- djgentelella/firmador_digital/config/asgi_worker.py +5 -0
- djgentelella/firmador_digital/config/websocket_urls.py +4 -0
- djgentelella/firmador_digital/consumers/__init__.py +0 -0
- djgentelella/firmador_digital/consumers/pdf_render.py +8 -0
- djgentelella/firmador_digital/consumers/sign.py +148 -0
- djgentelella/firmador_digital/forms.py +28 -0
- djgentelella/firmador_digital/gunicorn/config_asgi.py +12 -0
- djgentelella/firmador_digital/gunicorn/config_wsgi.py +13 -0
- djgentelella/firmador_digital/models.py +33 -0
- djgentelella/firmador_digital/signvalue_utils.py +41 -0
- djgentelella/firmador_digital/utils.py +154 -0
- djgentelella/firmador_digital/viewsets.py +77 -0
- djgentelella/groute.py +6 -1
- djgentelella/gtselects.py +5 -9
- djgentelella/locale/es/LC_MESSAGES/django.mo +0 -0
- djgentelella/locale/es/LC_MESSAGES/django.po +103 -6
- djgentelella/locale/es/LC_MESSAGES/djangojs.mo +0 -0
- djgentelella/locale/es/LC_MESSAGES/djangojs.po +107 -8
- djgentelella/management/commands/createbasejs.py +3 -0
- djgentelella/management/commands/loaddevstatic.py +18 -0
- djgentelella/migrations/0013_usersignatureconfig.py +25 -0
- djgentelella/serializers/firmador_digital.py +103 -0
- djgentelella/settings.py +5 -4
- djgentelella/static/djgentelella.readonly.vendors.min.css +1 -1
- djgentelella/static/djgentelella.readonly.vendors.min.js +1 -1
- djgentelella/static/djgentelella.vendors.header.min.js +1 -1
- djgentelella/static/djgentelella.vendors.min.css +2 -2
- djgentelella/static/gentelella/css/pdfviewer.css +147 -0
- djgentelella/static/gentelella/images/firmador.ico +0 -0
- djgentelella/static/gentelella/js/base/digital_signature.js +945 -0
- djgentelella/static/gentelella/js/base.js +947 -0
- djgentelella/static/gentelella/js/datatables.js +2 -2
- djgentelella/static/gentelella/js/widgets.js +72 -59
- djgentelella/static/vendors/friconix/friconix.js +1 -1
- djgentelella/static/vendors/pdfjs/images/altText_add.svg +3 -0
- djgentelella/static/vendors/pdfjs/images/altText_disclaimer.svg +3 -0
- djgentelella/static/vendors/pdfjs/images/altText_done.svg +3 -0
- djgentelella/static/vendors/pdfjs/images/altText_spinner.svg +30 -0
- djgentelella/static/vendors/pdfjs/images/altText_warning.svg +3 -0
- djgentelella/static/vendors/pdfjs/images/cursor-editorFreeHighlight.svg +6 -0
- djgentelella/static/vendors/pdfjs/images/cursor-editorFreeText.svg +3 -0
- djgentelella/static/vendors/pdfjs/images/cursor-editorInk.svg +4 -0
- djgentelella/static/vendors/pdfjs/images/cursor-editorTextHighlight.svg +8 -0
- djgentelella/static/vendors/pdfjs/images/editor-toolbar-delete.svg +5 -0
- djgentelella/static/vendors/pdfjs/images/loading-icon.gif +0 -0
- djgentelella/static/vendors/pdfjs/images/messageBar_closingButton.svg +3 -0
- djgentelella/static/vendors/pdfjs/images/messageBar_warning.svg +3 -0
- djgentelella/static/vendors/pdfjs/images/toolbarButton-editorHighlight.svg +6 -0
- djgentelella/static/vendors/pdfjs/images/toolbarButton-menuArrow.svg +3 -0
- djgentelella/static/vendors/timeline/css/timeline.css +1 -1
- djgentelella/static/vendors/timeline/js/timeline.js +1 -1
- djgentelella/templates/gentelella/registration/login.html +38 -42
- djgentelella/templates/gentelella/statics/javascript.html +75 -61
- djgentelella/templates/gentelella/statics/stylesheets.html +11 -10
- djgentelella/templates/gentelella/widgets/addtreeselect.html +1 -1
- djgentelella/templates/gentelella/widgets/chunkedupload.html +2 -2
- djgentelella/templates/gentelella/widgets/digital_signature.html +208 -0
- djgentelella/templates/gentelella/widgets/file.html +15 -16
- djgentelella/templatetags/gtsettings.py +4 -0
- djgentelella/urls.py +1 -1
- djgentelella/widgets/core.py +5 -2
- djgentelella/widgets/digital_signature.py +116 -0
- {djgentelella-0.3.28.dist-info → djgentelella-0.4.0.dist-info}/METADATA +18 -20
- {djgentelella-0.3.28.dist-info → djgentelella-0.4.0.dist-info}/RECORD +74 -37
- {djgentelella-0.3.28.dist-info → djgentelella-0.4.0.dist-info}/WHEEL +1 -1
- {djgentelella-0.3.28.dist-info → djgentelella-0.4.0.dist-info}/AUTHORS +0 -0
- {djgentelella-0.3.28.dist-info → djgentelella-0.4.0.dist-info}/LICENSE.txt +0 -0
- {djgentelella-0.3.28.dist-info → djgentelella-0.4.0.dist-info}/top_level.txt +0 -0
|
@@ -2248,6 +2248,953 @@ function getMediaRecord(element, mediatype){
|
|
|
2248
2248
|
}
|
|
2249
2249
|
|
|
2250
2250
|
|
|
2251
|
+
///////////////////////////////////////////////
|
|
2252
|
+
// Init widgets digital signature
|
|
2253
|
+
///////////////////////////////////////////////
|
|
2254
|
+
build_digital_signature = function (instance) {
|
|
2255
|
+
|
|
2256
|
+
const widgetId = instance.getAttribute("id");
|
|
2257
|
+
const url_ws = instance.getAttribute("data-ws-url");
|
|
2258
|
+
const container = instance.closest(".widget-digital-signature");
|
|
2259
|
+
const container_tag = `container-${widgetId}`;
|
|
2260
|
+
const doc_instance = {
|
|
2261
|
+
"pk": instance.getAttribute("data-pk"),
|
|
2262
|
+
"cc": instance.getAttribute("data-cc"),
|
|
2263
|
+
"value": instance.getAttribute("data-value")
|
|
2264
|
+
}
|
|
2265
|
+
const urls = {
|
|
2266
|
+
"logo": instance.getAttribute("data-logo"),
|
|
2267
|
+
"sign_doc": instance.getAttribute("data-renderurl"),
|
|
2268
|
+
"renderattr": instance.getAttribute("data-renderattr")
|
|
2269
|
+
}
|
|
2270
|
+
container.setAttribute("data-widget-id", container_tag);
|
|
2271
|
+
|
|
2272
|
+
// pdfviewer
|
|
2273
|
+
const defaultPage = instance.getAttribute("data-default-page") || "first";
|
|
2274
|
+
|
|
2275
|
+
// Create a new instance of the PDF viewer with the appropriate settings
|
|
2276
|
+
const pdfInstance = new PdfSignatureComponent(container, defaultPage, urls, doc_instance);
|
|
2277
|
+
|
|
2278
|
+
if (!doc_instance) {
|
|
2279
|
+
console.error("You must define the doc_instance variable.");
|
|
2280
|
+
return;
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
// Signature
|
|
2284
|
+
let signatureManager = new SignatureManager(widgetId, container, url_ws, pdfInstance);
|
|
2285
|
+
signatureManager.startSign(doc_instance, urls['logo']);
|
|
2286
|
+
|
|
2287
|
+
// Store the instance in a global object with key per widget ID
|
|
2288
|
+
if (!window.pdfSignatureComponents) {
|
|
2289
|
+
window.pdfSignatureComponents = {};
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
// Add the instance to the global object if it does not exist
|
|
2293
|
+
if (!window.pdfSignatureComponents[container_tag]) {
|
|
2294
|
+
window.pdfSignatureComponents[container_tag] = pdfInstance;
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
///////////////////////////////////////////////
|
|
2300
|
+
// PDF preview Digtal Signature
|
|
2301
|
+
///////////////////////////////////////////////
|
|
2302
|
+
class PdfSignatureComponent {
|
|
2303
|
+
constructor(container, defaultPage, urls, doc_instance) {
|
|
2304
|
+
this.container = container;
|
|
2305
|
+
this.defaultPage = defaultPage;
|
|
2306
|
+
this.widgetId = container.getAttribute("data-widget-id");
|
|
2307
|
+
this.urls=urls;
|
|
2308
|
+
this.doc_instance=doc_instance;
|
|
2309
|
+
|
|
2310
|
+
// Internal elements
|
|
2311
|
+
this.signature = container.querySelector('.signature');
|
|
2312
|
+
this.canvas = container.querySelector('.pdfviewer');
|
|
2313
|
+
this.btn_prev = container.querySelector('.prev');
|
|
2314
|
+
this.btn_next = container.querySelector('.next');
|
|
2315
|
+
this.page_num = container.querySelector('.page_num');
|
|
2316
|
+
this.page_number = container.querySelector('.page_number');
|
|
2317
|
+
this.page_count = container.querySelector('.page_count');
|
|
2318
|
+
this.sub_canvas_container = container.querySelector('.sub_canvas_container');
|
|
2319
|
+
|
|
2320
|
+
// Verify that all required elements are present
|
|
2321
|
+
if (!this.signature || !this.canvas || !this.btn_prev || !this.btn_next || !this.page_num || !this.page_number || !this.page_count || !this.sub_canvas_container) {
|
|
2322
|
+
console.warn("Falta alguno de los elementos requeridos en este componente. Se omite su inicialización.");
|
|
2323
|
+
return;
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
// Variables specific to the component
|
|
2327
|
+
this.pdfDoc = null;
|
|
2328
|
+
this.pageNum = 1;
|
|
2329
|
+
this.pageRendering = false;
|
|
2330
|
+
this.pageNumPending = null;
|
|
2331
|
+
this.scale = 1.2;
|
|
2332
|
+
this.signX = 0;
|
|
2333
|
+
this.signY = 198;
|
|
2334
|
+
this.signWidth = 133;
|
|
2335
|
+
this.signHeight = 133;
|
|
2336
|
+
|
|
2337
|
+
// Initializes the processes
|
|
2338
|
+
this.initEvents();
|
|
2339
|
+
this.initPDFViewer();
|
|
2340
|
+
this.initInteract();
|
|
2341
|
+
this.initSignatureSettings();
|
|
2342
|
+
|
|
2343
|
+
}
|
|
2344
|
+
|
|
2345
|
+
initEvents() {
|
|
2346
|
+
this.btn_prev.addEventListener('click', () => this.onPrevPage());
|
|
2347
|
+
this.btn_next.addEventListener('click', () => this.onNextPage());
|
|
2348
|
+
this.page_number.addEventListener('change', (e) => this.renderPage(e.target.value));
|
|
2349
|
+
this.page_number.addEventListener('keyup', (e) => this.renderPage(e.target.value));
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
initPDFViewer() {
|
|
2353
|
+
|
|
2354
|
+
if (typeof this.urls['sign_doc'] === 'undefined') {
|
|
2355
|
+
console.warn("The variable 'sign_doc' is not defined.");
|
|
2356
|
+
return;
|
|
2357
|
+
}
|
|
2358
|
+
pdfjsLib.getDocument(this.urls['sign_doc']+"?"+this.urls['renderattr']).promise.then((pdfDoc_) => {
|
|
2359
|
+
this.pdfDoc = pdfDoc_;
|
|
2360
|
+
this.page_count.textContent = pdfDoc_.numPages;
|
|
2361
|
+
|
|
2362
|
+
// define page number
|
|
2363
|
+
if (this.defaultPage === "last") {
|
|
2364
|
+
this.pageNum = this.pdfDoc.numPages;
|
|
2365
|
+
} else if (this.defaultPage === "first") {
|
|
2366
|
+
this.pageNum = 1;
|
|
2367
|
+
} else {
|
|
2368
|
+
let numPage = parseInt(this.defaultPage, 10);
|
|
2369
|
+
if (!isNaN(numPage) && numPage > 0 && numPage <= this.pdfDoc.numPages) {
|
|
2370
|
+
this.pageNum = numPage;
|
|
2371
|
+
} else {
|
|
2372
|
+
console.warn("Invalid page number, starting on the first page.");
|
|
2373
|
+
this.pageNum = 1;
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
|
|
2378
|
+
this.renderPage(this.pageNum);
|
|
2379
|
+
});
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
onPrevPage() {
|
|
2383
|
+
if (this.pageNum <= 1) return;
|
|
2384
|
+
this.pageNum--;
|
|
2385
|
+
this.queueRenderPage(this.pageNum);
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
onNextPage() {
|
|
2389
|
+
if (this.pageNum >= this.pdfDoc.numPages) return;
|
|
2390
|
+
this.pageNum++;
|
|
2391
|
+
this.queueRenderPage(this.pageNum);
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
queueRenderPage(num) {
|
|
2395
|
+
if (this.pageRendering) {
|
|
2396
|
+
this.pageNumPending = num;
|
|
2397
|
+
} else {
|
|
2398
|
+
this.renderPage(num);
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
renderPage(num) {
|
|
2403
|
+
this.pageRendering = true;
|
|
2404
|
+
this.pdfDoc.getPage(num).then((page) => {
|
|
2405
|
+
const viewport = page.getViewport({scale: this.scale});
|
|
2406
|
+
this.canvas.height = viewport.height;
|
|
2407
|
+
this.canvas.width = viewport.width;
|
|
2408
|
+
|
|
2409
|
+
const renderContext = {
|
|
2410
|
+
canvasContext: this.canvas.getContext('2d'), viewport: viewport
|
|
2411
|
+
};
|
|
2412
|
+
const renderTask = page.render(renderContext);
|
|
2413
|
+
|
|
2414
|
+
renderTask.promise.then(() => {
|
|
2415
|
+
this.pageRendering = false;
|
|
2416
|
+
if (this.pageNumPending !== null) {
|
|
2417
|
+
this.renderPage(this.pageNumPending);
|
|
2418
|
+
this.pageNumPending = null;
|
|
2419
|
+
}
|
|
2420
|
+
});
|
|
2421
|
+
});
|
|
2422
|
+
this.page_num.textContent = num;
|
|
2423
|
+
this.page_number.value = num;
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
initInteract() {
|
|
2427
|
+
// First instance of draggable and resizable with interact.js
|
|
2428
|
+
interact(this.signature)
|
|
2429
|
+
.draggable({
|
|
2430
|
+
inertia: true, modifiers: [interact.modifiers.restrictRect({
|
|
2431
|
+
restriction: this.canvas, endOnly: false
|
|
2432
|
+
})], autoScroll: true, listeners: {
|
|
2433
|
+
move: (event) => this.dragMoveListener(event)
|
|
2434
|
+
}
|
|
2435
|
+
})
|
|
2436
|
+
.resizable({
|
|
2437
|
+
edges: {left: true, right: true, bottom: true, top: true}, listeners: {
|
|
2438
|
+
move: (event) => {
|
|
2439
|
+
let target = event.target;
|
|
2440
|
+
let x = (parseFloat(target.getAttribute('data-x')) || 0);
|
|
2441
|
+
let y = (parseFloat(target.getAttribute('data-y')) || 0);
|
|
2442
|
+
|
|
2443
|
+
target.style.width = event.rect.width + 'px';
|
|
2444
|
+
target.style.height = event.rect.height + 'px';
|
|
2445
|
+
|
|
2446
|
+
x += event.deltaRect.left;
|
|
2447
|
+
y += event.deltaRect.top;
|
|
2448
|
+
|
|
2449
|
+
target.style.transform = `translate(${x}px, ${y}px)`;
|
|
2450
|
+
target.setAttribute('data-x', x);
|
|
2451
|
+
target.setAttribute('data-y', y);
|
|
2452
|
+
target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height);
|
|
2453
|
+
|
|
2454
|
+
this.signWidth = event.rect.width;
|
|
2455
|
+
this.signHeight = event.rect.height;
|
|
2456
|
+
this.signX = x;
|
|
2457
|
+
this.signY = y;
|
|
2458
|
+
}
|
|
2459
|
+
}, modifiers: [interact.modifiers.restrictEdges({outer: 'parent'}), interact.modifiers.restrictSize({
|
|
2460
|
+
min: {
|
|
2461
|
+
width: 100, height: 50
|
|
2462
|
+
}
|
|
2463
|
+
})], inertia: true
|
|
2464
|
+
});
|
|
2465
|
+
|
|
2466
|
+
// Second instance of draggable with autoScroll over the container
|
|
2467
|
+
interact(this.signature)
|
|
2468
|
+
.draggable({
|
|
2469
|
+
inertia: true, modifiers: [interact.modifiers.restrictRect({
|
|
2470
|
+
restriction: this.canvas, endOnly: false
|
|
2471
|
+
})], autoScroll: {
|
|
2472
|
+
container: this.sub_canvas_container, margin: 50, distance: 5, interval: 50
|
|
2473
|
+
}, listeners: {
|
|
2474
|
+
move: (event) => this.dragMoveListener(event)
|
|
2475
|
+
}
|
|
2476
|
+
});
|
|
2477
|
+
|
|
2478
|
+
this.canvas.addEventListener('dblclick', (event) => this.moveSignatureToClick(event));
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
moveSignatureToClick(event) {
|
|
2482
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
2483
|
+
const x = event.clientX - rect.left;
|
|
2484
|
+
const y = event.clientY - rect.top;
|
|
2485
|
+
|
|
2486
|
+
const signatureWidth = this.signature.offsetWidth;
|
|
2487
|
+
const signatureHeight = this.signature.offsetHeight;
|
|
2488
|
+
|
|
2489
|
+
const centerX = x - signatureWidth / 2;
|
|
2490
|
+
const centerY = y - signatureHeight / 2;
|
|
2491
|
+
|
|
2492
|
+
this.updatePosition(this.signature, centerX, centerY);
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
|
|
2496
|
+
dragMoveListener(event) {
|
|
2497
|
+
const target = event.target;
|
|
2498
|
+
const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
|
|
2499
|
+
const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
|
|
2500
|
+
this.updatePosition(target, x, y);
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
updatePosition(target, x, y) {
|
|
2504
|
+
target.style.transform = `translate(${x}px, ${y}px)`;
|
|
2505
|
+
const {x: xAdjusted, y: yAdjusted} = this.adjustPositionToFitWithinCanvas(target, x, y);
|
|
2506
|
+
target.style.transform = `translate(${xAdjusted}px, ${yAdjusted}px)`;
|
|
2507
|
+
target.setAttribute('data-x', xAdjusted);
|
|
2508
|
+
target.setAttribute('data-y', yAdjusted);
|
|
2509
|
+
this.signX = Math.round(xAdjusted);
|
|
2510
|
+
this.signY = Math.round(yAdjusted);
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
adjustPositionToFitWithinCanvas(target, x, y) {
|
|
2514
|
+
const canvasRect = this.canvas.getBoundingClientRect();
|
|
2515
|
+
const targetRect = target.getBoundingClientRect();
|
|
2516
|
+
if (targetRect.right > canvasRect.right) {
|
|
2517
|
+
x -= targetRect.right - canvasRect.right;
|
|
2518
|
+
}
|
|
2519
|
+
if (targetRect.bottom > canvasRect.bottom) {
|
|
2520
|
+
y -= targetRect.bottom - canvasRect.bottom;
|
|
2521
|
+
}
|
|
2522
|
+
return {x, y};
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
initSignatureSettings() {
|
|
2526
|
+
// A base configuration is applied by cloning the signature element
|
|
2527
|
+
const tempSignature = this.signature.cloneNode(true);
|
|
2528
|
+
tempSignature.style = '';
|
|
2529
|
+
tempSignature.classList.remove("right", "left", "top", "bottom", "full", "none");
|
|
2530
|
+
tempSignature.style.visibility = 'visible';
|
|
2531
|
+
tempSignature.style.width = 'auto';
|
|
2532
|
+
tempSignature.style.height = 'auto';
|
|
2533
|
+
tempSignature.style.overflow = 'visible';
|
|
2534
|
+
const textElem = tempSignature.querySelector('.text');
|
|
2535
|
+
if (textElem) textElem.style.wordBreak = 'break-word';
|
|
2536
|
+
|
|
2537
|
+
this.formatAndLoadContent(tempSignature)
|
|
2538
|
+
.then(() => {
|
|
2539
|
+
this.signature.className = tempSignature.className;
|
|
2540
|
+
this.signature.style.cssText = tempSignature.style.cssText;
|
|
2541
|
+
this.signature.innerHTML = tempSignature.innerHTML;
|
|
2542
|
+
this.updatePosition(this.signature, 198, 0);
|
|
2543
|
+
})
|
|
2544
|
+
.catch(error => {
|
|
2545
|
+
console.error(gettext("Error when applying setting to signature: "), error);
|
|
2546
|
+
});
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
async formatAndLoadContent(element, content) {
|
|
2550
|
+
const imageContainer = element.querySelector('.image');
|
|
2551
|
+
const textContainer = element.querySelector('.text');
|
|
2552
|
+
if (imageContainer) imageContainer.innerHTML = '';
|
|
2553
|
+
if (textContainer) textContainer.innerHTML = '';
|
|
2554
|
+
try {
|
|
2555
|
+
// Here you can load the image or update the text of the signature
|
|
2556
|
+
// await this.loadSignatureImage(signatureImageURL, imageContainer);
|
|
2557
|
+
} catch (error) {
|
|
2558
|
+
console.error(gettext("Error loading content: "), error);
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
|
|
2562
|
+
async createTemporarySignature(content) {
|
|
2563
|
+
let tempSignature = window.app.signature.cloneNode(true);
|
|
2564
|
+
tempSignature.id = 'temp_signature';
|
|
2565
|
+
tempSignature.style.position = 'absolute';
|
|
2566
|
+
tempSignature.style.visibility = 'hidden';
|
|
2567
|
+
let textElem = tempSignature.querySelector('.text');
|
|
2568
|
+
if (textElem) textElem.style.wordBreak = 'break-word';
|
|
2569
|
+
this.sub_canvas_container.appendChild(tempSignature);
|
|
2570
|
+
await this.formatAndLoadContent(tempSignature, content);
|
|
2571
|
+
return tempSignature;
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
// If required, you can define a method for loading an image
|
|
2575
|
+
loadSignatureImage(signatureImage, imageContainer) {
|
|
2576
|
+
return new Promise((resolve, reject) => {
|
|
2577
|
+
if (!signatureImage) {
|
|
2578
|
+
resolve();
|
|
2579
|
+
return;
|
|
2580
|
+
}
|
|
2581
|
+
const img = new Image();
|
|
2582
|
+
img.src = signatureImage;
|
|
2583
|
+
img.alt = 'signature-image';
|
|
2584
|
+
img.onload = () => {
|
|
2585
|
+
if (imageContainer) imageContainer.appendChild(img);
|
|
2586
|
+
resolve();
|
|
2587
|
+
};
|
|
2588
|
+
img.onerror = () => {
|
|
2589
|
+
reject(new Error(gettext("Error loading image")));
|
|
2590
|
+
};
|
|
2591
|
+
});
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
getDocumentSettings() {
|
|
2595
|
+
const displayScale = this.canvas.getBoundingClientRect().width / this.canvas.width;
|
|
2596
|
+
const xReal = this.signX / displayScale;
|
|
2597
|
+
const yReal = this.signY / displayScale;
|
|
2598
|
+
const wReal = this.signWidth / displayScale;
|
|
2599
|
+
const hReal = this.signHeight / displayScale;
|
|
2600
|
+
|
|
2601
|
+
const xPdf = xReal / this.scale;
|
|
2602
|
+
const yPdf = yReal / this.scale;
|
|
2603
|
+
const wPdf = wReal / this.scale;
|
|
2604
|
+
const hPdf = hReal / this.scale;
|
|
2605
|
+
|
|
2606
|
+
return {
|
|
2607
|
+
pageNumber: this.pageNum,
|
|
2608
|
+
signWidth: Math.round(wPdf),
|
|
2609
|
+
signHeight: Math.round(hPdf),
|
|
2610
|
+
signX: Math.round(xPdf),
|
|
2611
|
+
signY: Math.round(yPdf),
|
|
2612
|
+
};
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2616
|
+
///////////////////////////////////////////////
|
|
2617
|
+
// Signature manager Digital Signature
|
|
2618
|
+
///////////////////////////////////////////////
|
|
2619
|
+
class SignatureManager {
|
|
2620
|
+
constructor(input_id, container, url_ws, pdfvisor) {
|
|
2621
|
+
this.input_id=input_id;
|
|
2622
|
+
this.container = container;
|
|
2623
|
+
this.modal = new bootstrap.Modal(container.querySelector("#loading_sign"));
|
|
2624
|
+
this.firmador = new DocumentClient(container, container.getAttribute("data-widget-id"), this, url_ws, this.doc_instance);
|
|
2625
|
+
this.signerBtn = container.querySelector(".btn_signer");
|
|
2626
|
+
this.errorsContainer = container.querySelector(".errors_signer");
|
|
2627
|
+
this.refreshBtn = container.querySelector(".btn_signer_refresh");
|
|
2628
|
+
this.socketError = false;
|
|
2629
|
+
this.pdfvisor = pdfvisor;
|
|
2630
|
+
|
|
2631
|
+
this.initEvents();
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
initEvents() {
|
|
2635
|
+
if (this.signerBtn) {
|
|
2636
|
+
this.signerBtn.addEventListener('click', () => this.sign());
|
|
2637
|
+
}
|
|
2638
|
+
if (this.refreshBtn) {
|
|
2639
|
+
this.refreshBtn.addEventListener('click', () => this.refresh());
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
startSign(doc_instance, logo_url = null) {
|
|
2644
|
+
if (this.socketError) {
|
|
2645
|
+
alertSimple(errorInterpreter(3), gettext("Error"), "error");
|
|
2646
|
+
return;
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
this.doc_instance = doc_instance;
|
|
2650
|
+
this.logo_url = logo_url;
|
|
2651
|
+
|
|
2652
|
+
this.clearErrors();
|
|
2653
|
+
|
|
2654
|
+
this.firmador.start_sign(doc_instance, logo_url)
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2657
|
+
refresh() {
|
|
2658
|
+
this.socketError = false;
|
|
2659
|
+
this.firmador.remotesigner.inicialize();
|
|
2660
|
+
|
|
2661
|
+
this.clearErrors();
|
|
2662
|
+
this.firmador.start_sign(this.doc_instance, this.logo_url);
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
sign() {
|
|
2666
|
+
this.clearErrors();
|
|
2667
|
+
this.firmador.do_sign_remote();
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2670
|
+
addError(errorCode) {
|
|
2671
|
+
let title = document.createElement('p');
|
|
2672
|
+
title.classList.add('mt-2', 'text-danger', 'mb-0');
|
|
2673
|
+
title.innerHTML = `<i class="fa fa-times-circle" aria-hidden="true"></i> <span class="fw-bold"> ${gettext("Errors")} </span>`;
|
|
2674
|
+
let errorElement = document.createElement('p');
|
|
2675
|
+
errorElement.classList.add('text-danger', 'mx-3', 'small');
|
|
2676
|
+
errorElement.innerHTML = errorInterpreter(errorCode);
|
|
2677
|
+
this.errorsContainer.appendChild(title);
|
|
2678
|
+
this.errorsContainer.appendChild(errorElement);
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
clearErrors() {
|
|
2682
|
+
this.errorsContainer.innerHTML = '';
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
reloadPage() {
|
|
2686
|
+
window.location.reload();
|
|
2687
|
+
}
|
|
2688
|
+
|
|
2689
|
+
showLoading() {
|
|
2690
|
+
this.modal.show();
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2693
|
+
hideLoading() {
|
|
2694
|
+
setTimeout(() => {
|
|
2695
|
+
this.modal.hide();
|
|
2696
|
+
}, 500);
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
///////////////////////////////////////////////
|
|
2701
|
+
// Socket Digital Signature
|
|
2702
|
+
///////////////////////////////////////////////
|
|
2703
|
+
function responseManageTypeData(instance, err_json_fn, error_text_fn) {
|
|
2704
|
+
return function (response) {
|
|
2705
|
+
const contentType = response.headers.get("content-type");
|
|
2706
|
+
if (response.ok) {
|
|
2707
|
+
if (contentType && contentType.indexOf("application/json") !== -1) {
|
|
2708
|
+
return response.json();
|
|
2709
|
+
} else {
|
|
2710
|
+
return response.text();
|
|
2711
|
+
}
|
|
2712
|
+
} else {
|
|
2713
|
+
if (contentType && contentType.indexOf("application/json") !== -1) {
|
|
2714
|
+
response.json().then(data => err_json_fn(data));
|
|
2715
|
+
} else {
|
|
2716
|
+
if (response.status === 406) {
|
|
2717
|
+
// cierre de ventana para ingresar el PIN
|
|
2718
|
+
error_text_fn(errorInterpreter(4));
|
|
2719
|
+
} else {
|
|
2720
|
+
response.text().then(data => error_text_fn(data));
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
return Promise.reject(response);
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2728
|
+
function SocketManager(socket, signatureManager) {
|
|
2729
|
+
// If an error occurs during the connection
|
|
2730
|
+
socket.onerror = (event) => {
|
|
2731
|
+
// console.error("WebSocket error");
|
|
2732
|
+
signatureManager.hideLoading();
|
|
2733
|
+
alertSimple(errorInterpreter(3), gettext("Error"), "error");
|
|
2734
|
+
signatureManager.socketError = true;
|
|
2735
|
+
};
|
|
2736
|
+
|
|
2737
|
+
// If the connection is closed
|
|
2738
|
+
socket.onclose = (event) => {
|
|
2739
|
+
// console.warn("WebSocket cerrado");
|
|
2740
|
+
};
|
|
2741
|
+
|
|
2742
|
+
// If the connection is opened
|
|
2743
|
+
socket.onopen = (event) => {
|
|
2744
|
+
// console.log("WebSocket conectado");
|
|
2745
|
+
signatureManager.socket_error = false;
|
|
2746
|
+
};
|
|
2747
|
+
}
|
|
2748
|
+
|
|
2749
|
+
function callFetch(instance) {
|
|
2750
|
+
fetch(instance.url, {
|
|
2751
|
+
method: instance.type,
|
|
2752
|
+
body: instance.data,
|
|
2753
|
+
headers: {
|
|
2754
|
+
'X-CSRFToken': getCookie('csrftoken'),
|
|
2755
|
+
'Content-Type': 'application/json'
|
|
2756
|
+
},
|
|
2757
|
+
cache: 'no-cache', // do not use cache
|
|
2758
|
+
}).then(responseManageTypeData(instance, instance.error_json, instance.error_text))
|
|
2759
|
+
.then(data => instance.success(data))
|
|
2760
|
+
.catch(error => {
|
|
2761
|
+
instance.error(error);
|
|
2762
|
+
});
|
|
2763
|
+
}
|
|
2764
|
+
|
|
2765
|
+
function FirmadorLibreLocal(docmanager, signatureManager) {
|
|
2766
|
+
return {
|
|
2767
|
+
"cert_url": "http://localhost:3516/certificates",
|
|
2768
|
+
"sign_url": "http://localhost:3516/sign",
|
|
2769
|
+
"success_get_certificates": function (data) {
|
|
2770
|
+
docmanager.success_certificates(data);
|
|
2771
|
+
},
|
|
2772
|
+
"get_certificates": function () {
|
|
2773
|
+
let parent = this;
|
|
2774
|
+
|
|
2775
|
+
const instance = {
|
|
2776
|
+
url: this.cert_url,
|
|
2777
|
+
type: 'GET',
|
|
2778
|
+
data: null,
|
|
2779
|
+
success: function (data) {
|
|
2780
|
+
parent.success_get_certificates(data);
|
|
2781
|
+
},
|
|
2782
|
+
error_text: function (message) {
|
|
2783
|
+
// console.log(message);
|
|
2784
|
+
},
|
|
2785
|
+
error_json: function (error) {
|
|
2786
|
+
// console.log(error);
|
|
2787
|
+
},
|
|
2788
|
+
error: function (error) {
|
|
2789
|
+
// Unrecognized Firmador Libre
|
|
2790
|
+
if (String(error) === "TypeError: NetworkError when attempting to fetch resource.") {
|
|
2791
|
+
signatureManager.addError(1);
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2795
|
+
callFetch(instance);
|
|
2796
|
+
},
|
|
2797
|
+
"sign": function (data) {
|
|
2798
|
+
let json = JSON.stringify(data);
|
|
2799
|
+
let manager = docmanager;
|
|
2800
|
+
|
|
2801
|
+
const fetch_instance = {
|
|
2802
|
+
'url': this.sign_url,
|
|
2803
|
+
'type': 'POST',
|
|
2804
|
+
'data': json,
|
|
2805
|
+
"success": function (data) {
|
|
2806
|
+
// if the result is different from a string, it is possible that there is an error.
|
|
2807
|
+
// console.log(data)
|
|
2808
|
+
if (typeof data !== 'string') { //prevent option call
|
|
2809
|
+
manager.local_done(data);
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2812
|
+
},
|
|
2813
|
+
"error": function (error) {
|
|
2814
|
+
// console.log(error);
|
|
2815
|
+
signatureManager.hideLoading();
|
|
2816
|
+
if (typeof error === "object") {
|
|
2817
|
+
// close window for PIN entry
|
|
2818
|
+
if (error.status === 406 && error.statusText === "Not Acceptable") {
|
|
2819
|
+
alertSimple(errorInterpreter(4), gettext("Warning"), "warning");
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
},
|
|
2823
|
+
"error_text": function (message) {
|
|
2824
|
+
console.error("error_text", message);
|
|
2825
|
+
signatureManager.hideLoading();
|
|
2826
|
+
},
|
|
2827
|
+
"error_json": function (error) {
|
|
2828
|
+
console.error("error_json", error);
|
|
2829
|
+
signatureManager.hideLoading();
|
|
2830
|
+
},
|
|
2831
|
+
};
|
|
2832
|
+
|
|
2833
|
+
callFetch(fetch_instance);
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
|
|
2838
|
+
function FirmadorLibreWS(docmanager, url, signatureManager) {
|
|
2839
|
+
var firmador = {
|
|
2840
|
+
"url": url,
|
|
2841
|
+
"websocket": null,
|
|
2842
|
+
"firmador_url": "http://localhost:3516",
|
|
2843
|
+
"trans_received": function (instance) {
|
|
2844
|
+
return function (event) {
|
|
2845
|
+
try {
|
|
2846
|
+
const data = JSON.parse(event.data);
|
|
2847
|
+
instance.receive_json(data);
|
|
2848
|
+
} catch (err) {
|
|
2849
|
+
console.error("Error al parsear mensaje WS:", err);
|
|
2850
|
+
}
|
|
2851
|
+
};
|
|
2852
|
+
},
|
|
2853
|
+
"receive_json": function (data) {
|
|
2854
|
+
// validate socket errors
|
|
2855
|
+
if (data.result === false && data.error) {
|
|
2856
|
+
signatureManager.hideLoading();
|
|
2857
|
+
if (typeof data.details === "string") {
|
|
2858
|
+
// connection issues with the Firmador Libre API
|
|
2859
|
+
if (data.details.includes("Connection refused")) {
|
|
2860
|
+
signatureManager.addError(3);
|
|
2861
|
+
} else {
|
|
2862
|
+
alertSimple(errorInterpreter(999), gettext("Error"), "error");
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
} else if (data.code) {
|
|
2866
|
+
switch (data.code) {
|
|
2867
|
+
case 0:
|
|
2868
|
+
// when an unknown error occurs on the server
|
|
2869
|
+
alertSimple(errorInterpreter(0), gettext("Error"), "error");
|
|
2870
|
+
break;
|
|
2871
|
+
case 6:
|
|
2872
|
+
// when the new signature field position overlaps with an existing signature
|
|
2873
|
+
alertSimple(errorInterpreter(6), gettext("Error"), "error");
|
|
2874
|
+
break;
|
|
2875
|
+
case 7:
|
|
2876
|
+
// when the signature field is outside the page boundaries
|
|
2877
|
+
alertSimple(errorInterpreter(7), gettext("Error"), "error");
|
|
2878
|
+
break;
|
|
2879
|
+
case 8:
|
|
2880
|
+
// when an error occurs due to an incompatible library
|
|
2881
|
+
alertSimple(errorInterpreter(8), gettext("Error"), "error");
|
|
2882
|
+
break;
|
|
2883
|
+
case 9:
|
|
2884
|
+
// when an error occurs due to an unavailable cryptographic provider
|
|
2885
|
+
alertSimple(errorInterpreter(9), gettext("Error"), "error");
|
|
2886
|
+
break;
|
|
2887
|
+
case 10:
|
|
2888
|
+
// when an error occurs due to the signing algorithm
|
|
2889
|
+
alertSimple(errorInterpreter(10), gettext("Error"), "error");
|
|
2890
|
+
break;
|
|
2891
|
+
case 11:
|
|
2892
|
+
// when there are errors serializing data
|
|
2893
|
+
alertSimple(errorInterpreter(11), gettext("Error"), "error");
|
|
2894
|
+
break;
|
|
2895
|
+
case 12:
|
|
2896
|
+
// when an error occurs due to a signing service timeout
|
|
2897
|
+
alertSimple(errorInterpreter(12), gettext("Error"), "error");
|
|
2898
|
+
break;
|
|
2899
|
+
// when an unknown error occurs
|
|
2900
|
+
alertSimple(errorInterpreter(999), gettext("Error"), "error");
|
|
2901
|
+
break;
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
}else{
|
|
2905
|
+
|
|
2906
|
+
if(data.hasOwnProperty('tobesigned')){
|
|
2907
|
+
docmanager.do_sign_local(data);
|
|
2908
|
+
}else{
|
|
2909
|
+
docmanager.remote_done(data)
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
}
|
|
2913
|
+
},
|
|
2914
|
+
|
|
2915
|
+
"inicialize": function () {
|
|
2916
|
+
this.websocket = new WebSocket(url);
|
|
2917
|
+
SocketManager(this.websocket, signatureManager);
|
|
2918
|
+
this.websocket.onmessage = this.trans_received(this);
|
|
2919
|
+
},
|
|
2920
|
+
"local_done": function (data) {
|
|
2921
|
+
// console.log("local_done", data);
|
|
2922
|
+
},
|
|
2923
|
+
"sign": function (data) {
|
|
2924
|
+
data["action"] = "initial_signature";
|
|
2925
|
+
if (data.card !== undefined) {
|
|
2926
|
+
this.websocket.send(JSON.stringify(data));
|
|
2927
|
+
signatureManager.showLoading();
|
|
2928
|
+
} else {
|
|
2929
|
+
alertSimple(errorInterpreter(2), gettext("Error"), "error");
|
|
2930
|
+
signatureManager.addError(2);
|
|
2931
|
+
}
|
|
2932
|
+
},
|
|
2933
|
+
"complete_sign": function (data) {
|
|
2934
|
+
data["action"] = "complete_signature";
|
|
2935
|
+
|
|
2936
|
+
try {
|
|
2937
|
+
this.websocket.send(JSON.stringify(data));
|
|
2938
|
+
} catch (e) {
|
|
2939
|
+
// console.error("Error de comunicación WS");
|
|
2940
|
+
signatureManager.hideLoading();
|
|
2941
|
+
alertFunction(errorInterpreter(3), gettext("Error"), "error", false, closeModalSignature);
|
|
2942
|
+
}
|
|
2943
|
+
},
|
|
2944
|
+
};
|
|
2945
|
+
firmador.inicialize();
|
|
2946
|
+
return firmador;
|
|
2947
|
+
}
|
|
2948
|
+
|
|
2949
|
+
function DocumentClient(container, widgetId, signatureManager, url_ws) {
|
|
2950
|
+
const docmanager = {
|
|
2951
|
+
"widgetId": widgetId,
|
|
2952
|
+
"container": container,
|
|
2953
|
+
"signatureManager": signatureManager,
|
|
2954
|
+
"remotesigner": null,
|
|
2955
|
+
"localsigner": null,
|
|
2956
|
+
"certificates": null,
|
|
2957
|
+
"doc_instance": null,
|
|
2958
|
+
"logo_url": null,
|
|
2959
|
+
|
|
2960
|
+
"start_sign": function (doc_instance, logo_url = null) {
|
|
2961
|
+
this.doc_instance = doc_instance;
|
|
2962
|
+
this.logo_url = logo_url;
|
|
2963
|
+
this.localsigner.get_certificates();
|
|
2964
|
+
this.signatureManager.clearErrors();
|
|
2965
|
+
},
|
|
2966
|
+
"success_certificates": function (data) {
|
|
2967
|
+
|
|
2968
|
+
if (data.length > 0) {
|
|
2969
|
+
container.querySelector("#container_select_card").classList.remove("d-none");
|
|
2970
|
+
container.querySelector("#container_select_card_tem").classList.add("d-none");
|
|
2971
|
+
|
|
2972
|
+
let select_card = container.querySelector(".select_card");
|
|
2973
|
+
|
|
2974
|
+
if (!select_card) {
|
|
2975
|
+
console.error(`Select not found for widget ${widgetId}`);
|
|
2976
|
+
return;
|
|
2977
|
+
}
|
|
2978
|
+
select_card.innerHTML = "";
|
|
2979
|
+
this.certificates = {};
|
|
2980
|
+
|
|
2981
|
+
data.forEach((element) => {
|
|
2982
|
+
this.certificates[element.tokenSerialNumber] = element;
|
|
2983
|
+
let start_token = element.tokenSerialNumber.substring(0, 4);
|
|
2984
|
+
let newOption = new Option(
|
|
2985
|
+
`${start_token} ${element.commonName}`,
|
|
2986
|
+
element.tokenSerialNumber,
|
|
2987
|
+
false, false
|
|
2988
|
+
);
|
|
2989
|
+
select_card.appendChild(newOption);
|
|
2990
|
+
});
|
|
2991
|
+
} else {
|
|
2992
|
+
container.querySelector("#container_select_card").classList.add("d-none");
|
|
2993
|
+
container.querySelector("#container_select_card_tem").classList.remove("d-none");
|
|
2994
|
+
this.signatureManager.addError(2);
|
|
2995
|
+
}
|
|
2996
|
+
},
|
|
2997
|
+
|
|
2998
|
+
"do_sign_remote": function () {
|
|
2999
|
+
let select = container.querySelector(".select_card");
|
|
3000
|
+
let selected_card = select ? select.value : null;
|
|
3001
|
+
|
|
3002
|
+
if (selected_card && this.certificates) {
|
|
3003
|
+
let data = {
|
|
3004
|
+
'logo_url': this.logo_url,
|
|
3005
|
+
'instance': this.doc_instance,
|
|
3006
|
+
'card': this.certificates[selected_card],
|
|
3007
|
+
"docsettings": window.pdfSignatureComponents[widgetId].getDocumentSettings()
|
|
3008
|
+
};
|
|
3009
|
+
this.remotesigner.sign(data);
|
|
3010
|
+
} else if (!selected_card && !this.certificates) {
|
|
3011
|
+
signatureManager.hideLoading();
|
|
3012
|
+
alertSimple(errorInterpreter(1), gettext("Error"), "error");
|
|
3013
|
+
this.signatureManager.addError(1);
|
|
3014
|
+
} else if (!selected_card && this.certificates) {
|
|
3015
|
+
signatureManager.hideLoading();
|
|
3016
|
+
alertSimple(errorInterpreter(2), gettext("Error"), "error");
|
|
3017
|
+
this.signatureManager.addError(2);
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
},
|
|
3021
|
+
"do_sign_local": function (data) {
|
|
3022
|
+
this.localsigner.sign(data);
|
|
3023
|
+
},
|
|
3024
|
+
"local_done": function (data) {
|
|
3025
|
+
data['instance'] = this.doc_instance;
|
|
3026
|
+
data['logo_url'] = this.logo_url;
|
|
3027
|
+
this.remotesigner.complete_sign(data);
|
|
3028
|
+
},
|
|
3029
|
+
"remote_done": function (data) {
|
|
3030
|
+
if(data.result !== null ){
|
|
3031
|
+
const l = btoa(JSON.stringify({'token': data.result}));
|
|
3032
|
+
this.signatureManager.doc_instance['value'] =l;
|
|
3033
|
+
this.signatureManager.pdfvisor.urls['renderattr']="value="+l;
|
|
3034
|
+
document.getElementById(this.signatureManager.input_id).value=l;
|
|
3035
|
+
this.signatureManager.pdfvisor.initPDFViewer();
|
|
3036
|
+
signatureManager.hideLoading();
|
|
3037
|
+
alertFunction(
|
|
3038
|
+
gettext("The signing was successfully completed."),
|
|
3039
|
+
gettext("Success"),
|
|
3040
|
+
"success", false, function(){}
|
|
3041
|
+
);
|
|
3042
|
+
}
|
|
3043
|
+
},
|
|
3044
|
+
|
|
3045
|
+
};
|
|
3046
|
+
|
|
3047
|
+
docmanager["remotesigner"] = new FirmadorLibreWS(docmanager, url_ws, signatureManager);
|
|
3048
|
+
docmanager["localsigner"] = new FirmadorLibreLocal(docmanager, signatureManager);
|
|
3049
|
+
|
|
3050
|
+
return docmanager;
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
///////////////////////////////////////////////
|
|
3054
|
+
// Manage Errors Digital Signature
|
|
3055
|
+
///////////////////////////////////////////////
|
|
3056
|
+
function errorInterpreter(error) {
|
|
3057
|
+
|
|
3058
|
+
let textError = "";
|
|
3059
|
+
|
|
3060
|
+
switch (error) {
|
|
3061
|
+
case 0:
|
|
3062
|
+
// when an uncontrolled error occurs in the signing server
|
|
3063
|
+
textError = gettext("An error has occurred in the internal server of the uncontrolled 'Firmador Libre'.");
|
|
3064
|
+
break;
|
|
3065
|
+
case 1:
|
|
3066
|
+
// when the 'Firmador Libre' application fails to open
|
|
3067
|
+
textError = gettext("Make sure to start the 'Firmador Libre' application. If it is already running, please press the reload button.");
|
|
3068
|
+
break;
|
|
3069
|
+
case 2:
|
|
3070
|
+
// when there is no card connected
|
|
3071
|
+
textError = gettext("There is no card connected to the device. Please press the reload button and connect your card.");
|
|
3072
|
+
break;
|
|
3073
|
+
case 3:
|
|
3074
|
+
// when the signing service is not functioning
|
|
3075
|
+
textError = gettext("The internal signature service does not work. Please contact the support.");
|
|
3076
|
+
break;
|
|
3077
|
+
case 4:
|
|
3078
|
+
// when the modal is closed but the PIN entry window remains open
|
|
3079
|
+
textError = gettext("Authentication failed because the PIN entry window was detected closed, please try again.");
|
|
3080
|
+
break;
|
|
3081
|
+
case 5:
|
|
3082
|
+
// when the card is disconnected
|
|
3083
|
+
//! This error should be resolved within Firmador Libre
|
|
3084
|
+
textError = gettext("The device was disconnected, possibly the window was closed for signature. Please close the window for the authentication PIN.");
|
|
3085
|
+
break;
|
|
3086
|
+
case 6:
|
|
3087
|
+
// when the new signature field position overlaps with an existing signature
|
|
3088
|
+
textError = gettext("The new signature field position overlaps with an existing signature.");
|
|
3089
|
+
break;
|
|
3090
|
+
case 7:
|
|
3091
|
+
// when the signature is positioned outside the page boundaries
|
|
3092
|
+
textError = gettext("The new signature field position is outside the page dimensions.");
|
|
3093
|
+
break;
|
|
3094
|
+
case 8:
|
|
3095
|
+
// when an error occurs due to an incompatible library
|
|
3096
|
+
textError = gettext("The version of one or more libraries is incompatible.");
|
|
3097
|
+
break;
|
|
3098
|
+
case 9:
|
|
3099
|
+
// when an error occurs due to an unavailable cryptographic provider
|
|
3100
|
+
textError = gettext("The cryptographic provider is not available.");
|
|
3101
|
+
break;
|
|
3102
|
+
case 10:
|
|
3103
|
+
// when an error occurs due to the signing algorithm
|
|
3104
|
+
textError = gettext("The signing algorithm is not available.");
|
|
3105
|
+
break;
|
|
3106
|
+
case 11:
|
|
3107
|
+
// when errors occur while serializing data
|
|
3108
|
+
textError = gettext("Errors have been encountered in the data to be sent to the 'Free Signer'. Please press the reload button and try again.");
|
|
3109
|
+
break;
|
|
3110
|
+
case 12:
|
|
3111
|
+
// when an error occurs due to a signing service timeout
|
|
3112
|
+
textError = gettext("The request to the signing service timed out. Please, press the reload button and try again.");
|
|
3113
|
+
break;
|
|
3114
|
+
default:
|
|
3115
|
+
// when an unknown error occurs
|
|
3116
|
+
textError = gettext("We're sorry, an unexpected error occurred. Please, press the reload button and try again.");
|
|
3117
|
+
}
|
|
3118
|
+
|
|
3119
|
+
return textError;
|
|
3120
|
+
}
|
|
3121
|
+
|
|
3122
|
+
|
|
3123
|
+
///////////////////////////////////////////////
|
|
3124
|
+
// Alerts Digital Signature
|
|
3125
|
+
///////////////////////////////////////////////
|
|
3126
|
+
function alertSimple(text, title = "Error", icon = "error") {
|
|
3127
|
+
Swal.fire({
|
|
3128
|
+
icon: icon,
|
|
3129
|
+
title: title,
|
|
3130
|
+
text: text,
|
|
3131
|
+
confirmButtonText: gettext("Accept")
|
|
3132
|
+
});
|
|
3133
|
+
}
|
|
3134
|
+
|
|
3135
|
+
function alertFunction(text, title = "Error", icon = "error", cancelButton = false,
|
|
3136
|
+
callback = () => {
|
|
3137
|
+
}) {
|
|
3138
|
+
Swal.fire({
|
|
3139
|
+
icon: icon,
|
|
3140
|
+
title: title,
|
|
3141
|
+
text: text,
|
|
3142
|
+
confirmButtonText: gettext("Accept"),
|
|
3143
|
+
showCancelButton: cancelButton,
|
|
3144
|
+
cancelButtonText: gettext("Cancel"),
|
|
3145
|
+
confirmButtonColor: '#3085d6',
|
|
3146
|
+
cancelButtonColor: '#d33',
|
|
3147
|
+
}).then((result) => {
|
|
3148
|
+
if (result.isConfirmed) {
|
|
3149
|
+
callback();
|
|
3150
|
+
}
|
|
3151
|
+
});
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
///////////////////////////////////////////////
|
|
3155
|
+
// End widgets digital signature
|
|
3156
|
+
///////////////////////////////////////////////
|
|
3157
|
+
|
|
3158
|
+
|
|
3159
|
+
////////////////////////////////////////////////////////////////
|
|
3160
|
+
// copy action
|
|
3161
|
+
////////////////////////////////////////////////////////////////
|
|
3162
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
3163
|
+
|
|
3164
|
+
if (document.getElementById("copy-command-line")) {
|
|
3165
|
+
document.getElementById("copy-command-line").addEventListener("click", function () {
|
|
3166
|
+
let commandText = document.getElementById("command-line").innerText.trim();
|
|
3167
|
+
|
|
3168
|
+
navigator.clipboard.writeText(commandText)
|
|
3169
|
+
.then(() => {
|
|
3170
|
+
let text = document.getElementById("text-copy")
|
|
3171
|
+
text.classList.remove("d-none")
|
|
3172
|
+
setTimeout(() => {
|
|
3173
|
+
text.classList.add("d-none")
|
|
3174
|
+
}, 1500)
|
|
3175
|
+
})
|
|
3176
|
+
.catch(err => {
|
|
3177
|
+
console.error("Error al copiar el texto: ", err);
|
|
3178
|
+
});
|
|
3179
|
+
});
|
|
3180
|
+
|
|
3181
|
+
document.getElementById("show-command-line").addEventListener("click", () => {
|
|
3182
|
+
let container = document.getElementById("container-command-line")
|
|
3183
|
+
|
|
3184
|
+
if (container.classList.contains("d-none")) {
|
|
3185
|
+
container.classList.remove("d-none");
|
|
3186
|
+
} else {
|
|
3187
|
+
container.classList.add("d-none");
|
|
3188
|
+
}
|
|
3189
|
+
})
|
|
3190
|
+
}
|
|
3191
|
+
});
|
|
3192
|
+
|
|
3193
|
+
////////////////////////////////////////////////////////////////
|
|
3194
|
+
// End copy action
|
|
3195
|
+
////////////////////////////////////////////////////////////////
|
|
3196
|
+
|
|
3197
|
+
|
|
2251
3198
|
class CardList {
|
|
2252
3199
|
constructor(containerId, apiUrl, actions={}) {
|
|
2253
3200
|
this.container = document.getElementById(containerId);
|