@esfaenza/extensions 15.2.25 → 15.2.26

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.
@@ -2,10 +2,11 @@ import * as i0 from '@angular/core';
2
2
  import { InjectionToken, Injectable, Optional, Inject, Pipe, NgModule, Injector } from '@angular/core';
3
3
  import * as i1 from '@esfaenza/localizations';
4
4
  import { LocalizationModule } from '@esfaenza/localizations';
5
- import { first, map } from 'rxjs/operators';
6
- import swal from 'sweetalert2';
7
- import { ToastrService } from 'ngx-toastr';
5
+ import { first, filter, take, map } from 'rxjs/operators';
8
6
  import { of, Subject } from 'rxjs';
7
+ import { ToastrService } from 'ngx-toastr';
8
+ import swal from 'sweetalert2';
9
+ import * as i2 from '@angular/router';
9
10
 
10
11
  /**
11
12
  * Token che indica il prefisso delle searchView che serve per storicizzarle evitando di tirarsi in memoria anche tutti gli oggetti. Se vuoto viene supposto 'Hot'
@@ -312,1882 +313,2029 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
312
313
  }]
313
314
  }] });
314
315
 
315
- // Angular
316
- /* Classe che contiene tutte le informazioni sull'embedding in un unico contenitore per semplicità */
317
- class AppEmbeddingExtensions {
318
- constructor() {
319
- this.Embedded = false;
320
- this.EmbeddingLevel = 0;
321
- this.MainWindow = window;
322
- while (this.MainWindow.parent != this.MainWindow) {
323
- this.MainWindow = this.MainWindow.parent;
324
- this.EmbeddingLevel++;
325
- this.Embedded = true;
326
- }
327
- }
328
- }
329
- AppEmbeddingExtensions.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AppEmbeddingExtensions, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
330
- AppEmbeddingExtensions.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AppEmbeddingExtensions, providedIn: "root" });
331
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AppEmbeddingExtensions, decorators: [{
332
- type: Injectable,
333
- args: [{ providedIn: "root" }]
334
- }], ctorParameters: function () { return []; } });
335
-
336
- // Angular
337
- /**
338
- * Service che fornisce un accesso base in lettura/scrittura sulla clipboard
339
- */
340
- class BaseExtensionsService {
341
- constructor(emb) {
342
- this.emb = emb;
343
- this.RedirectMap = {};
344
- this.RoutesMap = {};
345
- for (let prop in this.RedirectMap) {
346
- this.RoutesMap[prop] = { route: null };
347
- this.RoutesMap[prop].route = (param) => {
348
- let obj = {};
349
- obj[this.RedirectMap[prop].params[0]] = param;
350
- return [(this.emb.Embedded ? "pages_ext/" : "pages/") + this.RedirectMap[prop].url, obj];
351
- };
352
- }
353
- }
354
- }
355
- BaseExtensionsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: BaseExtensionsService, deps: [{ token: AppEmbeddingExtensions }], target: i0.ɵɵFactoryTarget.Injectable });
356
- BaseExtensionsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: BaseExtensionsService, providedIn: "root" });
357
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: BaseExtensionsService, decorators: [{
358
- type: Injectable,
359
- args: [{ providedIn: "root" }]
360
- }], ctorParameters: function () { return [{ type: AppEmbeddingExtensions }]; } });
361
-
362
- /**
363
- * Suffisso della proprietà da generare in cui salvare il navigatore
364
- * utilizzato dal servizio di esportazione per prendere il valore delle proprietà di un oggetto
365
- */
366
- const csvValueNavigator = "_csvnav";
367
- /** Suffisso con le informazioni del tipo per le esportazioni di oggetti */
368
- const csvValueType = "_csvtype";
369
- /** Suffisso della proprietà da generare in cui salvare l'ordine di esportazione */
370
- const csvOrdPrefix = "_csvord";
371
- /** Suffisso della proprietà da generare in cui salvare la visibilità di questa proprietà */
372
- const csvVisPrefix = "_csvvis";
373
- /** Suffisso della proprietà da generare in cui salvare il nome della colonna in cui salvare questa proprietà */
374
- const csvHdrPrefix = "_csvhdr";
375
- /** Suffisso della proprietà da generare in cui salvare il codice del th a cui si riferisce questo campo */
376
- const csvPropKey = "_csvkey";
377
- /** Suffisso della proprietà da generare in cui salvare il valore da prendere per una proprietà di tipo Lista */
378
- const listCsvValPrefix = "_listcsvval";
379
- /** Suffisso della proprietà da generare in cui salvare l'Header della proprietà di tipo Lista relativo al valore esportato nella proprietà con suffisso **listCsvValPrefix** */
380
- const listCsvHdrPrefix = "_listcsvhdr";
381
- /** Suffisso della proprietà da generare in cui salvare il formato della proprietà di tipo Lista relativo al valore esportato nella proprietà con suffisso **listCsvValPrefix** */
382
- const listCsvValFormat = "_listcsvvalformat";
383
- /** Suffisso della proprietà da generare in cui salvare il valore da prendere per una proprietà di tipo Dizionario */
384
- const dictionaryCsvValPrefix = "_flatlistcsvval";
385
- /** Suffisso della proprietà da generare in cui salvare l'Header della proprietà di un Dizionario relativo al valore esportato nella proprietà con suffisso **dictionaryCsvValPrefix** */
386
- const dictionaryCsvHdrPrefix = "_flatlistcsvhdr";
387
- /** Suffisso della proprietà da generare in cui salvare il formato della proprietà che si sta esportando */
388
- const csvFormatPrefix = "_csvfmt";
389
- /** Nome della proprietà che contiene tutti i nomi di tutte le proprietà da esportare */
390
- const exportList = "__export_list__";
391
- /** Nome della proprietà che contiene la classe di localizzazione da utilizzare per una data esportazione */
392
- const locProperty = "__loc__";
393
-
394
- /**
395
- * Mappatura del TypeCode del C#
396
- */
397
- var TypeCode;
398
- (function (TypeCode) {
399
- /** @ignore */ TypeCode[TypeCode["Empty"] = 0] = "Empty";
400
- /** @ignore */ TypeCode[TypeCode["Obj"] = 1] = "Obj";
401
- /** @ignore */ TypeCode[TypeCode["DBNull"] = 2] = "DBNull";
402
- /** @ignore */ TypeCode[TypeCode["Boolean"] = 3] = "Boolean";
403
- /** @ignore */ TypeCode[TypeCode["Char"] = 4] = "Char";
404
- /** @ignore */ TypeCode[TypeCode["SByte"] = 5] = "SByte";
405
- /** @ignore */ TypeCode[TypeCode["Byte"] = 6] = "Byte";
406
- /** @ignore */ TypeCode[TypeCode["Int16"] = 7] = "Int16";
407
- /** @ignore */ TypeCode[TypeCode["UInt16"] = 8] = "UInt16";
408
- /** @ignore */ TypeCode[TypeCode["Int32"] = 9] = "Int32";
409
- /** @ignore */ TypeCode[TypeCode["UInt32"] = 10] = "UInt32";
410
- /** @ignore */ TypeCode[TypeCode["Int64"] = 11] = "Int64";
411
- /** @ignore */ TypeCode[TypeCode["UInt64"] = 12] = "UInt64";
412
- /** @ignore */ TypeCode[TypeCode["Single"] = 13] = "Single";
413
- /** @ignore */ TypeCode[TypeCode["Double"] = 14] = "Double";
414
- /** @ignore */ TypeCode[TypeCode["Decimal"] = 15] = "Decimal";
415
- /** @ignore */ TypeCode[TypeCode["DateTime"] = 16] = "DateTime";
416
- /** @ignore */ TypeCode[TypeCode["String"] = 18] = "String";
417
- })(TypeCode || (TypeCode = {}));
418
-
419
316
  // Angular
420
317
  /**
421
- * Service che fornisce metodi di pubblica utilità
318
+ * Service che fornisce alcuni semplici funzioni di Hashing / GUID / ecc...
422
319
  */
423
- class UtilityService {
320
+ class HashingService {
424
321
  constructor() {
425
- // Funzione di throttling per non spammare richieste in caso di animazioni attivate
426
- //TODO: spostarla in un metodo di utilit� (esfaenza/extensions)
427
- /** @ignore */
428
- this.executionTimers = {};
322
+ /**
323
+ * Blacklist dei tipi da ignorare quando si effettua l'hashing degli oggetti
324
+ */
325
+ this.objBlacklist = {
326
+ "NgForm": true, "ElementRef": true, "ExtensionsService": true, "ToastrService": true, "LocaleService": true, "AppState": true, "Router": true,
327
+ "ActivatedRoute": true, "HTTPService": true, "Location": true, "CanvasComponent": true, "ModalDirective": true, "ChangeDetectorRef": true,
328
+ "DateService": true, "EventEmitter": true, "ViewRef_": true, "Subscriber": true, "ItemLocalization": true
329
+ };
330
+ /**
331
+ * Array dei possibili valori di un simbolo esadecimale
332
+ */
333
+ this.hex_chr = '0123456789abcdef'.split('');
429
334
  }
430
335
  /**
431
- * Deseleziona il testo eventualmente selezionato
336
+ * Generazione di un GUID pseudo-univoco
337
+ *
338
+ * @returns {string} il GUID generato
432
339
  */
433
- clearTextSelection() {
434
- if (window.getSelection) {
435
- if (window.getSelection().empty) // Chrome
436
- window.getSelection().empty();
437
- else if (window.getSelection().removeAllRanges) // Firefox
438
- window.getSelection().removeAllRanges();
439
- }
440
- else if (document.selection) // IE?
441
- document.selection.empty();
340
+ getGUID() {
341
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
342
+ var r = Math.random() * 16 | 0, v = c == "x" ? r : (r & 0x3 | 0x8);
343
+ return v.toString(16);
344
+ });
442
345
  }
443
346
  /**
444
- * Partendo da una lista, dato il nome della proprietà chiave e il valore della chiave selezionata,
445
- * trova e restituisce l'oggetto desiderato
347
+ * Calcolo dell'hash su un oggetto
446
348
  *
447
- * @param {T[]} sourceList Lista di oggetti dentro cui cercare
448
- * @param {string} sourceItemIdField Nome della proprietà che rappresenta la chiave di un oggetto di tipo T
449
- * @param {string} selectedValue Valore di chiave selezionato
349
+ * @param {any} o Oggetto di cui calcolare l'hash
350
+ * @param {number} level Livello di ricorsione nel caso venga effettuato l'hash di un oggetto che contiene altri oggetti
351
+ * @param {boolean} navigateFullDepth Indica se navigare l'oggetto per l'intera lunghezza. In caso contrario si ferma al secondo livello
450
352
  *
451
- * @returns {T} Oggetto la cui proprietà **sourceItemIdField** assume il valore **selectedValue**
353
+ * @returns {string} Hash generato per l'oggetto in questione
452
354
  */
453
- getSelectedItem(sourceList, sourceItemIdField, selectedValue) {
454
- for (let i = 0; i < sourceList.length; i++) {
455
- var item = sourceList[i];
456
- if (item[sourceItemIdField] == selectedValue)
457
- return item;
355
+ hashObject(o, level = 0, navigateFullDepth = false, precise = false) {
356
+ var strDef = this.stringify(o, level, navigateFullDepth);
357
+ var hash = precise ? this.md5(strDef) : this.simpleHash(strDef);
358
+ return hash;
359
+ }
360
+ /**
361
+ * Hash più semplice e più veloce dell'md5, ma meno sicuro
362
+ *
363
+ * Vedi https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript
364
+ *
365
+ * @param {string} str Stringa di cui calcolare l'hash
366
+ */
367
+ simpleHash(str, seed = 0) {
368
+ let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
369
+ for (let i = 0, ch; i < str.length; i++) {
370
+ ch = str.charCodeAt(i);
371
+ h1 = Math.imul(h1 ^ ch, 2654435761);
372
+ h2 = Math.imul(h2 ^ ch, 1597334677);
458
373
  }
459
- return null;
374
+ h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
375
+ h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
376
+ return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString();
460
377
  }
461
378
  /**
462
- * Effettua il reset di un Form di Angular
379
+ * Genera una stringa che identifica univocamente l'oggetto in questione
463
380
  *
464
- * @param {NgForm} form Form da resettare
465
- * @param {string} exception1 Campo da non resettare
466
- * @param {string} exception2 Campo da non resettare
381
+ * @param {any} o Oggetto di cui calcolare la stringa univoca
382
+ * @param {number} level Livello di ricorsione nel caso venga effettuato l'hash di un oggetto che contiene altri oggetti
383
+ * @param {boolean} navigateFullDepth Indica se navigare l'oggetto per l'intera lunghezza. In caso contrario si ferma al secondo livello
467
384
  */
468
- cleanForm(form, exception1 = null, exception2 = null) {
469
- for (let name in form.controls) {
470
- if (name && name != exception1 && name != exception1 + "_internal" && name != exception2 && name != exception2 + "_internal") {
471
- form.controls[name].reset();
385
+ stringify(o, level, navigateFullDepth) {
386
+ var i, r;
387
+ if (o === null)
388
+ return "n";
389
+ if (o === true)
390
+ return "t";
391
+ if (o === false)
392
+ return "f";
393
+ if (o instanceof Date)
394
+ return 'd:' + o.valueOf().toString();
395
+ i = typeof o;
396
+ if (i === "string")
397
+ return "s:" + o;
398
+ if (i === "number")
399
+ return "n:" + o;
400
+ if (o instanceof Function)
401
+ return "m:" + o.toString();
402
+ if (o instanceof Array) {
403
+ r = [];
404
+ for (i = 0; i < o.length; i++) {
405
+ let res = this.stringify(o[i], level, navigateFullDepth);
406
+ if (res)
407
+ r.push(res);
472
408
  }
473
- else {
474
- form.controls[name].markAsPristine();
475
- form.controls[name].markAsUntouched();
409
+ return r.length > 0 ? "a:" + r.join(";") : "";
410
+ }
411
+ r = [];
412
+ //Se è oggetto, escludo tutti quelli di sistema/inutili
413
+ if (o) {
414
+ var name = o.__proto__.constructor.name;
415
+ if (!this.objBlacklist[name]) {
416
+ for (i in o) {
417
+ if (o.hasOwnProperty(i) && (level <= 2 || navigateFullDepth)) {
418
+ let res = this.stringify(o[i], level + 1, navigateFullDepth);
419
+ if (res)
420
+ r.push(i + ":" + res);
421
+ }
422
+ }
476
423
  }
477
424
  }
478
- //Reimposto il submitted
479
- form.submitted = false;
425
+ return r.length > 0 ? "o:" + r.join(";") : "";
480
426
  }
481
427
  /**
482
- * Helper che permette di scaricare un file dato un URL (Generato da una chiamata ad **window.URL.createObjectURL**)
428
+ * Data una stringa restituisce l'md5
483
429
  *
484
- * @param {string} url ObjectURL che rappresenta il file da scaricare
485
- * @param {string} filename Nome del file suggerito in fase di salvataggio
430
+ * @param {string} s Stringa di cui calcolare l'md5
431
+ * @returns {string} md5 della stringa **s**
486
432
  */
487
- fileDownload(url, fileName) {
488
- var a = document.createElement("a");
489
- document.body.appendChild(a);
490
- a.className = "ta-display-none";
491
- a.href = url;
492
- a.download = fileName;
493
- a.click();
494
- window.URL.revokeObjectURL(url);
495
- document.body.removeChild(a);
433
+ md5(s) {
434
+ return this.hex(this.md51(s));
496
435
  }
497
436
  /**
498
- * Helper per la formattazione di un numero di millisecondi in una stringa più comprensibile per un umano
437
+ * @ignore
499
438
  *
500
- * @param {number} duration Tempo espresso in millisecondi
501
- *
502
- * @returns {string} Durata formattata
439
+ * Metodo di utilità per il calcolo dell'md5
503
440
  */
504
- msToTime(duration) {
505
- if (!duration)
506
- return "";
507
- var milliseconds = parseInt(((duration % 1000) / 100).toString()), seconds = parseInt(((duration / 1000) % 60).toString()), minutes = parseInt(((duration / (1000 * 60)) % 60).toString()), hours = parseInt(((duration / (1000 * 60 * 60)) % 24).toString());
508
- var st_hours = (hours < 10) ? "0" + hours : hours;
509
- var st_minutes = (minutes < 10) ? "0" + minutes : minutes;
510
- var st_seconds = (seconds < 10) ? "0" + seconds : seconds;
511
- return st_hours + ":" + st_minutes + ":" + st_seconds + "." + milliseconds;
441
+ md5cycle(x, k) {
442
+ var a = x[0], b = x[1], c = x[2], d = x[3];
443
+ a = this.ff(a, b, c, d, k[0], 7, -680876936);
444
+ d = this.ff(d, a, b, c, k[1], 12, -389564586);
445
+ c = this.ff(c, d, a, b, k[2], 17, 606105819);
446
+ b = this.ff(b, c, d, a, k[3], 22, -1044525330);
447
+ a = this.ff(a, b, c, d, k[4], 7, -176418897);
448
+ d = this.ff(d, a, b, c, k[5], 12, 1200080426);
449
+ c = this.ff(c, d, a, b, k[6], 17, -1473231341);
450
+ b = this.ff(b, c, d, a, k[7], 22, -45705983);
451
+ a = this.ff(a, b, c, d, k[8], 7, 1770035416);
452
+ d = this.ff(d, a, b, c, k[9], 12, -1958414417);
453
+ c = this.ff(c, d, a, b, k[10], 17, -42063);
454
+ b = this.ff(b, c, d, a, k[11], 22, -1990404162);
455
+ a = this.ff(a, b, c, d, k[12], 7, 1804603682);
456
+ d = this.ff(d, a, b, c, k[13], 12, -40341101);
457
+ c = this.ff(c, d, a, b, k[14], 17, -1502002290);
458
+ b = this.ff(b, c, d, a, k[15], 22, 1236535329);
459
+ a = this.gg(a, b, c, d, k[1], 5, -165796510);
460
+ d = this.gg(d, a, b, c, k[6], 9, -1069501632);
461
+ c = this.gg(c, d, a, b, k[11], 14, 643717713);
462
+ b = this.gg(b, c, d, a, k[0], 20, -373897302);
463
+ a = this.gg(a, b, c, d, k[5], 5, -701558691);
464
+ d = this.gg(d, a, b, c, k[10], 9, 38016083);
465
+ c = this.gg(c, d, a, b, k[15], 14, -660478335);
466
+ b = this.gg(b, c, d, a, k[4], 20, -405537848);
467
+ a = this.gg(a, b, c, d, k[9], 5, 568446438);
468
+ d = this.gg(d, a, b, c, k[14], 9, -1019803690);
469
+ c = this.gg(c, d, a, b, k[3], 14, -187363961);
470
+ b = this.gg(b, c, d, a, k[8], 20, 1163531501);
471
+ a = this.gg(a, b, c, d, k[13], 5, -1444681467);
472
+ d = this.gg(d, a, b, c, k[2], 9, -51403784);
473
+ c = this.gg(c, d, a, b, k[7], 14, 1735328473);
474
+ b = this.gg(b, c, d, a, k[12], 20, -1926607734);
475
+ a = this.hh(a, b, c, d, k[5], 4, -378558);
476
+ d = this.hh(d, a, b, c, k[8], 11, -2022574463);
477
+ c = this.hh(c, d, a, b, k[11], 16, 1839030562);
478
+ b = this.hh(b, c, d, a, k[14], 23, -35309556);
479
+ a = this.hh(a, b, c, d, k[1], 4, -1530992060);
480
+ d = this.hh(d, a, b, c, k[4], 11, 1272893353);
481
+ c = this.hh(c, d, a, b, k[7], 16, -155497632);
482
+ b = this.hh(b, c, d, a, k[10], 23, -1094730640);
483
+ a = this.hh(a, b, c, d, k[13], 4, 681279174);
484
+ d = this.hh(d, a, b, c, k[0], 11, -358537222);
485
+ c = this.hh(c, d, a, b, k[3], 16, -722521979);
486
+ b = this.hh(b, c, d, a, k[6], 23, 76029189);
487
+ a = this.hh(a, b, c, d, k[9], 4, -640364487);
488
+ d = this.hh(d, a, b, c, k[12], 11, -421815835);
489
+ c = this.hh(c, d, a, b, k[15], 16, 530742520);
490
+ b = this.hh(b, c, d, a, k[2], 23, -995338651);
491
+ a = this.ii(a, b, c, d, k[0], 6, -198630844);
492
+ d = this.ii(d, a, b, c, k[7], 10, 1126891415);
493
+ c = this.ii(c, d, a, b, k[14], 15, -1416354905);
494
+ b = this.ii(b, c, d, a, k[5], 21, -57434055);
495
+ a = this.ii(a, b, c, d, k[12], 6, 1700485571);
496
+ d = this.ii(d, a, b, c, k[3], 10, -1894986606);
497
+ c = this.ii(c, d, a, b, k[10], 15, -1051523);
498
+ b = this.ii(b, c, d, a, k[1], 21, -2054922799);
499
+ a = this.ii(a, b, c, d, k[8], 6, 1873313359);
500
+ d = this.ii(d, a, b, c, k[15], 10, -30611744);
501
+ c = this.ii(c, d, a, b, k[6], 15, -1560198380);
502
+ b = this.ii(b, c, d, a, k[13], 21, 1309151649);
503
+ a = this.ii(a, b, c, d, k[4], 6, -145523070);
504
+ d = this.ii(d, a, b, c, k[11], 10, -1120210379);
505
+ c = this.ii(c, d, a, b, k[2], 15, 718787259);
506
+ b = this.ii(b, c, d, a, k[9], 21, -343485551);
507
+ x[0] = this.add32(a, x[0]);
508
+ x[1] = this.add32(b, x[1]);
509
+ x[2] = this.add32(c, x[2]);
510
+ x[3] = this.add32(d, x[3]);
512
511
  }
513
512
  /**
514
- * Helper che permette di scaricare un file in Base64
513
+ * @ignore
515
514
  *
516
- * @param {string} base64Data Base64 che rappresenta il file da scaricare
517
- * @param {string} filename Nome del file suggerito in fase di salvataggio
515
+ * Metodo di utilità per il calcolo dell'md5
518
516
  */
519
- saveFile(base64Data, filename) {
520
- var sampleArr = this.base64ToArrayBuffer(base64Data);
521
- this.saveByteArray(sampleArr, filename);
517
+ cmn(q, a, b, x, s, t) {
518
+ a = this.add32(this.add32(a, q), this.add32(x, t));
519
+ return this.add32((a << s) | (a >>> (32 - s)), b);
522
520
  }
523
521
  /**
524
- * Trasforma un Base64 in un ArrayBuffer
525
- *
526
- * @param {string} base64Data Base64 da trasformare
522
+ * @ignore
527
523
  *
528
- * @returns {Uint8Array} Array UTF8
524
+ * Metodo di utilità per il calcolo dell'md5
529
525
  */
530
- base64ToArrayBuffer(base64Data) {
531
- var binaryString = window.atob(base64Data);
532
- var binaryLen = binaryString.length;
533
- var bytes = new Uint8Array(binaryLen);
534
- for (var i = 0; i < binaryLen; i++) {
535
- var ascii = binaryString.charCodeAt(i);
536
- bytes[i] = ascii;
537
- }
538
- return bytes;
526
+ ff(a, b, c, d, x, s, t) {
527
+ return this.cmn((b & c) | ((~b) & d), a, b, x, s, t);
539
528
  }
540
529
  /**
541
- * Helper che permette di scaricare un file dato un array di Byte (**Uint8Array**)
530
+ * @ignore
542
531
  *
543
- * @param {Uint8Array} byte Rappresentazione del file da scaricare
544
- * @param {string} filename Nome del file suggerito in fase di salvataggio
532
+ * Metodo di utilità per il calcolo dell'md5
545
533
  */
546
- saveByteArray(byte, filename) {
547
- var blob = new Blob([byte]);
548
- var link = document.createElement("a");
549
- document.body.appendChild(link);
550
- link.href = window.URL.createObjectURL(blob);
551
- var fileName = filename;
552
- link.download = fileName;
553
- link.click();
554
- document.body.removeChild(link);
534
+ gg(a, b, c, d, x, s, t) {
535
+ return this.cmn((b & d) | (c & (~d)), a, b, x, s, t);
555
536
  }
556
- ;
557
537
  /**
558
- * Utility per lo swap di due elementi di un array
538
+ * @ignore
559
539
  *
560
- * @param {any[]} array Array di cui invertire due elementi
561
- * @param {number} x Indice del primo elemento
562
- * @param {number} y Indice del secondo elemento
540
+ * Metodo di utilità per il calcolo dell'md5
563
541
  */
564
- swap(array, x, y) {
565
- var b = array[x];
566
- array[x] = array[y];
567
- array[y] = b;
542
+ hh(a, b, c, d, x, s, t) {
543
+ return this.cmn(b ^ c ^ d, a, b, x, s, t);
568
544
  }
569
545
  /**
570
- * Helper di trascodifica da tipo c# a tipo Typescript
546
+ * @ignore
571
547
  *
572
- * @param {TypeCode} type Tipo da trascodificare
548
+ * Metodo di utilità per il calcolo dell'md5
549
+ */
550
+ ii(a, b, c, d, x, s, t) {
551
+ return this.cmn(c ^ (b | (~d)), a, b, x, s, t);
552
+ }
553
+ /**
554
+ * @ignore
573
555
  *
574
- * @returns {"boolean" | "number" | "string" | "date"} Tipo Typescript corrispondente
556
+ * Metodo di utilità per il calcolo dell'md5
575
557
  */
576
- getJsTypeFromTypeCode(type) {
577
- switch (type) {
578
- case TypeCode.Boolean:
579
- return "boolean";
580
- case TypeCode.Decimal:
581
- case TypeCode.Double:
582
- case TypeCode.Single:
583
- case TypeCode.Int16:
584
- case TypeCode.Int32:
585
- case TypeCode.Int64:
586
- case TypeCode.Byte:
587
- case TypeCode.SByte:
588
- case TypeCode.UInt16:
589
- case TypeCode.UInt32:
590
- case TypeCode.UInt64:
591
- return "number";
592
- case TypeCode.Char:
593
- case TypeCode.String:
594
- return "string";
595
- case TypeCode.DateTime:
596
- return "date";
597
- default:
598
- console.log("Unrecognized input type. Typecode:" + type);
599
- return "string";
558
+ md51(s) {
559
+ var n = s.length, state = [1732584193, -271733879, -1732584194, 271733878], i;
560
+ for (i = 64; i <= s.length; i += 64)
561
+ this.md5cycle(state, this.md5blk(s.substring(i - 64, i)));
562
+ s = s.substring(i - 64);
563
+ var tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
564
+ for (i = 0; i < s.length; i++)
565
+ tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
566
+ tail[i >> 2] |= 0x80 << ((i % 4) << 3);
567
+ if (i > 55) {
568
+ this.md5cycle(state, tail);
569
+ for (i = 0; i < 16; i++)
570
+ tail[i] = 0;
600
571
  }
572
+ tail[14] = n * 8;
573
+ this.md5cycle(state, tail);
574
+ return state;
601
575
  }
602
576
  /**
603
- * Effettua la clonazione profonda di un oggetto in maniera molto più performante che JSON.parse(JSON.stringify()).
577
+ * @ignore
604
578
  *
605
- * Usare solo per oggetti puri e quantomeno semplici per evitare complicazioni derivanti dalle semplificazioni che questo metodo assume
579
+ * Metodo di utilità per il calcolo dell'md5
580
+ */
581
+ md5blk(s) {
582
+ var md5blks = [], i;
583
+ for (i = 0; i < 64; i += 4)
584
+ md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
585
+ return md5blks;
586
+ }
587
+ /**
588
+ * @ignore
606
589
  *
607
- * @param {any} source Oggetto da clonare
590
+ * Metodo di utilità per il calcolo dell'md5
591
+ */
592
+ rhex(n) {
593
+ var s = '', j = 0;
594
+ for (; j < 4; j++)
595
+ s += this.hex_chr[(n >> (j * 8 + 4)) & 0x0F] + this.hex_chr[(n >> (j * 8)) & 0x0F];
596
+ return s;
597
+ }
598
+ /**
599
+ * @ignore
608
600
  *
609
- * @return {any} Clone dell'oggetto passato
601
+ * Metodo di utilità per il calcolo dell'md5
610
602
  */
611
- deepClone(source) {
612
- // Valori semplici
613
- if (source == null || typeof source !== 'object')
614
- return source;
615
- // Pseudo Struct
616
- switch (toString.call(source)) {
617
- case '[object Boolean]':
618
- case '[object Number]':
619
- case '[object String]':
620
- case '[object Date]':
621
- return new source.constructor(source.valueOf());
622
- // Clonazione di un file -> Restituisco il riferimento al file stesso
623
- case "[object File]":
624
- return source;
625
- default: break;
626
- }
627
- // Oggetti Complessi
628
- return this.recursiveStep(source, Array.isArray(source) || source instanceof Array ? [] : Object.create(Object.getPrototypeOf(source)));
603
+ hex(x) {
604
+ for (var i = 0; i < x.length; i++)
605
+ x[i] = this.rhex(x[i]);
606
+ return x.join('');
629
607
  }
630
608
  /**
631
609
  * @ignore
632
- * Step ricorsivo per la clonatura degli oggetti. Vedere **deepClone**
610
+ *
611
+ * Metodo di utilità per il calcolo dell'md5
633
612
  */
634
- recursiveStep(source, destination) {
635
- if (Array.isArray(source) || source instanceof Array) {
636
- for (var i = 0, ii = source.length; i < ii; i++)
637
- destination.push(this.deepClone(source[i]));
638
- }
639
- else if (source && typeof source.hasOwnProperty === 'function') {
640
- for (let key in source) {
641
- if (source.hasOwnProperty(key))
642
- destination[key] = this.deepClone(source[key]);
643
- }
644
- }
645
- return destination;
646
- }
647
- cast(object, clss) {
648
- let ret = Object.assign(Object.create(clss.prototype), object);
649
- return ret;
650
- }
651
- /** @ignore */
652
- throttla(id, func, throttleTime) {
653
- //Se ho la funzione che vuole eseguire ripulisco quel timeout
654
- if (this.executionTimers[id])
655
- clearTimeout(this.executionTimers[id]);
656
- //Ricreo il timeout per eseguire quella funzione dopo throttleTime millisecondi
657
- this.executionTimers[id] = setTimeout(() => { func(); this.executionTimers[id] = null; }, throttleTime);
613
+ add32(a, b) {
614
+ return (a + b) & 0xFFFFFFFF;
658
615
  }
659
616
  }
660
- UtilityService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: UtilityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
661
- UtilityService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: UtilityService, providedIn: "root" });
662
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: UtilityService, decorators: [{
617
+ HashingService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: HashingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
618
+ HashingService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: HashingService, providedIn: "root" });
619
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: HashingService, decorators: [{
663
620
  type: Injectable,
664
621
  args: [{ providedIn: "root" }]
665
622
  }] });
666
623
 
667
624
  // Angular
668
625
  /**
669
- * Decoratore che fornisce la classe di localizzazione per tutte le proprietà esportate con @Export e qualsiasi altro tag che richieda localizzazioni.
670
- *
671
- * Sostanzilamente aggiunge la proprietà **__loc__** all'oggetto creato dalla classe corrente assegnandogli come valore il tipo del LocalizationService da usare per la traduzione
672
- *
673
- * @param {Type<LocalizationService>} loc Tipo ereditato dal LocalizationService che può essere creato a runtime sotto contesto della DI di Angular
674
- */
675
- function ExportLocalization(loc) {
676
- return function integrateLoc(constructor) {
677
- return class extends constructor {
678
- constructor() {
679
- super(...arguments);
680
- this.__loc__ = loc;
681
- }
682
- };
683
- };
684
- }
685
- /**
686
- * Decoratore di esportazione utilizzabile su una proprietà singola.
687
- * Verranno generate 3 proprietà che gestiranno l'esportazione: (prop, prop_csvvis, prop_csvhdr).
688
- *
689
- * Ad esempio, da questa configurazione:
690
- *
691
- * @example
692
- * ```
693
- * @Export(true, "MyHeader")
694
- * ciao: string;
695
- * ```
696
- *
697
- * Nasceranno le seguenti proprietà nell'oggetto esportabile:
698
- *
699
- * @example
700
- * ```
701
- * ciao_csvvis: string; => true
702
- * ciao: string;
703
- * ciao_csvhdr: string => "MyHeader"
704
- * ```
705
- *
706
- * @param {number} order Ordine di esportazione. Più piccolo è, prima appare il valore
707
- * @param {string} header Titolo della colonna nel file CSV esportato
708
- * @param {string} format Formato di esportazione. Può essere un formato data per i campi data o 'F' per i campi floating point
709
- */
710
- const Export = (order, header, format = null, tableid = null) => (target, propertyKey) => {
711
- if (format)
712
- Object.defineProperty(target, propertyKey + csvFormatPrefix, { value: format, writable: false });
713
- Object.defineProperty(target, propertyKey + csvOrdPrefix, { value: order, writable: false });
714
- Object.defineProperty(target, propertyKey + csvVisPrefix, { value: !!header, writable: false });
715
- Object.defineProperty(target, propertyKey + csvHdrPrefix, { value: header, writable: false });
716
- if (tableid)
717
- Object.defineProperty(target, propertyKey + csvPropKey, { value: tableid, writable: false });
718
- if (target[exportList])
719
- target[exportList].push(propertyKey + csvVisPrefix);
720
- else
721
- target[exportList] = [propertyKey + csvVisPrefix];
722
- };
723
- /**
724
- * Decoratore di esportazione utilizzabile su un oggetto.
725
- * Per ogni proprietà dell'oggetto verranno generate 3 proprietà che gestiranno l'esportazione: (prop, prop_csvvis, prop_csvhdr).
726
- * Per essere esportate, le proprietà dell'oggetto devono essere marcate con i Decoratori di esportazione
727
- *
728
- * Ad esempio, da questa configurazione:
729
- *
730
- * @example
731
- * ```
732
- * MyObj {
733
- * @Export(true, "MyHeader")
734
- * ciao: string;
735
- * }
736
- *
737
- * @ExportObject(true, "MyHeader")
738
- * test: MyObj;
739
- * ```
740
- *
741
- * Nasceranno le seguenti proprietà nell'oggetto esportabile:
742
- *
743
- * @example
744
- * ```
745
- * testciao: string; => Valore di MyObj.ciao
746
- * testciao_csvvis: string; => true
747
- * testciao_csvhdr: string => "MyHeader"
748
- * ```
749
- *
750
- * @param {number} order Ordine di esportazione. Più piccolo è, prima appare il valore
751
- * @param {any} type Tipo da esportare
752
- */
753
- const ExportAs = (order, type, prefix) => (target, propertyKey) => {
754
- var t = new type();
755
- var props = t[exportList];
756
- for (let i = 0; i < props.length; i++) {
757
- let prop = props[i].replace(csvVisPrefix, '');
758
- if (typeof t[prop + csvVisPrefix] !== "undefined") {
759
- var toEmit = t[prop + csvVisPrefix];
760
- var lbl = t[prop + csvHdrPrefix];
761
- var format = t[prop + csvFormatPrefix];
762
- var orderProp = t[prop + csvOrdPrefix];
763
- if (format)
764
- Object.defineProperty(target, propertyKey + prop + csvFormatPrefix, { value: format, writable: false });
765
- Object.defineProperty(target, propertyKey + prop + csvOrdPrefix, { value: orderProp + order, writable: false });
766
- Object.defineProperty(target, propertyKey + prop, { value: null, writable: true, enumerable: true });
767
- Object.defineProperty(target, propertyKey + prop + csvValueNavigator, { value: propertyKey + "." + prop, writable: false });
768
- Object.defineProperty(target, propertyKey + prop + csvVisPrefix, { value: toEmit, writable: false });
769
- Object.defineProperty(target, propertyKey + prop + csvHdrPrefix, { value: (prefix ? prefix + ' ' : '') + lbl, writable: false });
770
- Object.defineProperty(target, propertyKey + prop + csvValueType, { value: type, writable: false });
771
- if (target[exportList])
772
- target[exportList].push(propertyKey + prop + csvVisPrefix);
773
- else
774
- target[exportList] = [propertyKey + prop + csvVisPrefix];
775
- }
776
- }
777
- };
778
- /**
779
- * Decoratore di esportazione utilizzabile su una lista,
780
- * si utilizzano 2 navigator rispettivamente per la valorizzazione dell'Header e del Valore e
781
- * per ogni elemento dell'array verranno generate 3 proprietà che gestiranno l'esportazione: (prop, prop_csvvis, prop_csvhdr)
782
- *
783
- * ATTENZIONE: Gli oggetti esportati in questa modalità non devono presentare altri tag di tipo @Export{...} all'interno. Fa tutto questo decoratore
784
- *
785
- * I navigator hanno questa convenzione:
786
- *
787
- * . --> divide due proprietà da richiamare consecutivamente: "a.b" richiamerà "obj.a.b";
788
- *
789
- * | --> divide più proprietà per le concatenazioni con uno spazio fra una e l'altra: "regdesc|slice.slicename" diventerà obj.regdesc + " " + obj.slice.slicename
790
- *
791
- * @param {number} order Ordine di esportazione. Più piccolo è, prima appare il valore
792
- * @param {string} headernavigator Navigator col compito di selezionare il titolo per la colonna
793
- * @param {string} valuenavigator Navigator col compito di selezionare il valore per la colonna
794
- * @param {string} valueformat Formato di esportazione per i valori selezionati dal **valuenavigator**. Può essere un formato data per i campi data o 'F' per i campi floating point
795
- */
796
- const ExportList = (order, headernavigator, valuenavigator, valueformat = null) => (target, propertyKey) => {
797
- Object.defineProperty(target, propertyKey + csvOrdPrefix, { value: order, writable: false });
798
- Object.defineProperty(target, propertyKey + listCsvValPrefix, { value: valuenavigator, writable: false });
799
- Object.defineProperty(target, propertyKey + listCsvHdrPrefix, { value: headernavigator, writable: false });
800
- Object.defineProperty(target, propertyKey + listCsvValFormat, { value: valueformat, writable: false });
801
- if (target[exportList])
802
- target[exportList].push(propertyKey + listCsvHdrPrefix);
803
- else
804
- target[exportList] = [propertyKey + listCsvHdrPrefix];
805
- };
806
- /**
807
- * Decoratore di esportazione utilizzabile su un dizionario. Se ad esempio si vogliono generare le colonne
808
- *
809
- * Valore A = 1
810
- *
811
- * Valore B = 2
812
- *
813
- * Valore C = 3
814
- *
815
- * partendo da un oggetto iniziale { Valore { A: 1, B: 2, C: 3 } }
816
- *
817
- * @param {number} order Ordine di esportazione. Più piccolo è, prima appare il valore
818
- * @param {string} headernavigator Navigator col compito di selezionare il titolo per la colonna
819
- * @param {string} valuenavigator Navigator col compito di selezionare il valore per la colonna
820
- */
821
- const ExportDictionary = (order, headernavigator, valuenavigator) => (target, propertyKey) => {
822
- Object.defineProperty(target, propertyKey + csvOrdPrefix, { value: order, writable: false });
823
- Object.defineProperty(target, propertyKey + dictionaryCsvValPrefix, { value: valuenavigator, writable: false });
824
- Object.defineProperty(target, propertyKey + dictionaryCsvHdrPrefix, { value: headernavigator, writable: false });
825
- if (target[exportList])
826
- target[exportList].push(propertyKey + dictionaryCsvHdrPrefix);
827
- else
828
- target[exportList] = [propertyKey + dictionaryCsvHdrPrefix];
829
- };
830
- /**
831
- * Service che si occupa dell'esportazione degli oggetti marcati dai Decoratori **ExportDictionary**, **ExportList**, **ExportAs** o **Export**
626
+ * Service che fornisce funzionalità di alert nei tipi fondamentali: success, info, warning e danger
832
627
  */
833
- class ExportService {
628
+ class MessageService {
834
629
  /**
835
630
  * Costruttore
836
631
  *
837
632
  * @ignore
838
633
  */
839
- constructor(dates, utiExts, lc) {
840
- this.dates = dates;
841
- this.utiExts = utiExts;
842
- this.lc = lc;
634
+ constructor(injector, locProvider, emb, hash) {
635
+ this.injector = injector;
636
+ this.locProvider = locProvider;
637
+ this.emb = emb;
638
+ this.hash = hash;
639
+ /**
640
+ * Oggetto statico in supporto alla localizzazione
641
+ */
642
+ this.loc = {
643
+ 'Confirm': { 'en-US': "Confirm", 'it-IT': "Conferma", },
644
+ 'Cancel': { 'en-US': "Cancel", 'it-IT': "Annulla", },
645
+ 'Close': { 'en-US': "Close", 'it-IT': "Chiudi", },
646
+ 'Error': { 'en-US': "Error", 'it-IT': "Errore", },
647
+ 'Info': { 'en-US': "Info", 'it-IT': "Informazione", },
648
+ 'Success': { 'en-US': "Success", 'it-IT': "Successo", },
649
+ 'Warning': { 'en-US': "Warning", 'it-IT': "Attenzione", }
650
+ };
651
+ this.GuidRepsonseFunctionsMap = {};
652
+ this.init();
843
653
  }
844
- /**
845
- * Data una lista di oggetti genera gli header per l'esportazione e integra ogni oggetto con le proprietà esportabili dalla libreria **@ctrl/ngx-csv**
846
- *
847
- * @param {any[]} objs Oggetti da esportare
848
- *
849
- * @returns {CsvHeaders[]} Header di esportazione già ordinati correttamente
850
- */
851
- setupForExport(objs, columns = []) {
852
- let headers = [];
853
- let headersCache = {};
854
- if (!objs || objs.length == 0)
855
- return headers;
856
- // Devo per forza farlo per tutti gli oggetti dato che devo esporre le proprietà che mi servono da esportare
857
- // Gli header li raccolgo tutti poi faccio uan distinct in modo da esportare tutte le proprietà per bene
858
- let columnSelectionDictionary = {};
859
- if (columns?.length > 0)
860
- for (let i = 0; i < columns?.length; i++)
861
- columnSelectionDictionary[columns[i]] = true;
862
- for (let i = 0; i < objs.length; i++) {
863
- let hds = this.parseAndGetHeaders(objs[i], columnSelectionDictionary);
864
- // Aggiungo gli header facendo in modo di non aggiungerne mai due uguali per non dover fare una distinct dopo
865
- // che costerebbe comunque risorse. Utilizzo un dizionario d'appoggio per lookup istantanei
866
- for (let k = 0; k < hds.length; k++) {
867
- if (!headersCache[hds[k].key]) {
868
- headersCache[hds[k].key] = true;
869
- headers.push(hds[k]);
870
- }
871
- }
872
- }
873
- if (!columns || columns.length == 0)
874
- return headers.sort((a, b) => a.order - b.order);
875
- else {
876
- // Se mi arriva la lista di colonne non mi dà solo la visibilità, ma anche l'ordinamento
877
- // le esporto di conseguenza
878
- let orderedHeaders = [];
879
- for (let i = 0; i < columns.length; i++) {
880
- let thisId = columns[i];
881
- for (let i = 0; i < headers.length; i++) {
882
- if (headers[i].propKey == thisId) {
883
- orderedHeaders.push(headers[i]);
884
- break;
885
- }
886
- }
887
- }
888
- return orderedHeaders;
889
- }
654
+ get toastr() {
655
+ return this.injector.get(ToastrService);
890
656
  }
891
- /**
892
- * Data una lista di oggetti generici genera gli header per l'esportazione e integra ogni oggetto con le proprietà esportabili dalla libreria **@ctrl/ngx-csv**
893
- *
894
- * @param {GenericItem[]} objs Oggetti generici da esportare
895
- * @param {CsvHeaders[]} columns Colonne richieste dall'esportazione
896
- *
897
- * @returns {CsvHeaders[]} Header di esportazione già ordinati correttamente
898
- */
899
- setupForGenericExport(objs, columns) {
900
- let headers = [];
901
- if (!objs || objs.length == 0)
902
- return headers;
903
- // Devo per forza farlo per tutti gli oggetti dato che devo esporre le proprietà che mi servono da esportare
904
- objs.forEach((obj, index) => {
905
- if (index == 0)
906
- headers = this.parseAndGetGenericHeaders(obj, columns);
907
- else
908
- this.parseAndGetGenericHeaders(obj, columns);
657
+ async init() {
658
+ let LOCALE = this.locProvider ? await this.locProvider.Locale.pipe(first()).toPromise() : 'it-IT';
659
+ this.expiredSessionSwal = swal.mixin({
660
+ showCancelButton: false,
661
+ confirmButtonText: 'Login',
662
+ customClass: {
663
+ confirmButton: "btn btn-primary",
664
+ container: "app-wrap",
665
+ },
666
+ buttonsStyling: false,
667
+ reverseButtons: false,
668
+ allowOutsideClick: false,
669
+ icon: "warning"
670
+ });
671
+ this.successSwalWithCancel = swal.mixin({
672
+ title: this.loc["Success"][LOCALE],
673
+ customClass: {
674
+ confirmButton: "btn btn-primary",
675
+ cancelButton: "btn btn-secondary app-margin-right-10",
676
+ container: "app-wrap",
677
+ },
678
+ buttonsStyling: false,
679
+ reverseButtons: true,
680
+ showCancelButton: true,
681
+ confirmButtonText: this.loc["Confirm"][LOCALE],
682
+ cancelButtonText: this.loc["Cancel"][LOCALE],
683
+ icon: "success"
684
+ });
685
+ this.warningSwalWithCancel = swal.mixin({
686
+ title: this.loc["Warning"][LOCALE],
687
+ customClass: {
688
+ confirmButton: "btn btn-primary",
689
+ cancelButton: "btn btn-secondary app-margin-right-10",
690
+ container: "app-wrap",
691
+ },
692
+ buttonsStyling: false,
693
+ reverseButtons: true,
694
+ showCancelButton: true,
695
+ confirmButtonText: this.loc["Confirm"][LOCALE],
696
+ cancelButtonText: this.loc["Cancel"][LOCALE],
697
+ icon: "warning"
698
+ });
699
+ this.warningSwal = swal.mixin({
700
+ title: this.loc["Warning"][LOCALE],
701
+ customClass: {
702
+ confirmButton: "btn btn-primary",
703
+ container: "app-wrap",
704
+ },
705
+ buttonsStyling: false,
706
+ reverseButtons: true,
707
+ showCancelButton: false,
708
+ confirmButtonText: this.loc["Close"][LOCALE],
709
+ icon: "warning"
710
+ });
711
+ this.successSwal = swal.mixin({
712
+ title: this.loc["Success"][LOCALE],
713
+ customClass: {
714
+ confirmButton: "btn btn-primary",
715
+ container: "app-wrap",
716
+ },
717
+ buttonsStyling: false,
718
+ reverseButtons: true,
719
+ showCancelButton: false,
720
+ confirmButtonText: this.loc["Close"][LOCALE],
721
+ icon: "success"
722
+ });
723
+ this.errorSwal = swal.mixin({
724
+ title: this.loc["Error"][LOCALE],
725
+ customClass: {
726
+ confirmButton: "btn btn-primary",
727
+ container: "app-wrap",
728
+ },
729
+ buttonsStyling: false,
730
+ reverseButtons: true,
731
+ showCancelButton: false,
732
+ confirmButtonText: this.loc["Close"][LOCALE],
733
+ icon: "error"
734
+ });
735
+ this.infoSwal = swal.mixin({
736
+ title: this.loc["Info"][LOCALE],
737
+ customClass: {
738
+ confirmButton: "btn btn-primary",
739
+ container: "app-wrap",
740
+ },
741
+ buttonsStyling: false,
742
+ reverseButtons: true,
743
+ showCancelButton: false,
744
+ confirmButtonText: this.loc["Close"][LOCALE],
745
+ icon: "info"
909
746
  });
910
- return headers;
911
747
  }
912
748
  /**
913
- * Dato un oggetto generico genera gli header per l'esportazione e lo integra con le proprietà esportabili dalla libreria **@ctrl/ngx-csv**
914
- *
915
- * Metodo interno richiamato da **setupForGenericExport**
749
+ * Presentazione di un semplice messaggio di successo
916
750
  *
917
- * @param {GenericItem} obj Oggetto generico da esportare
918
- * @param {CsvColumn[]} columns Colonne richieste dall'esportazione
751
+ * Se viene chiamato con le impostazioni di default e toastr è abilitato, viene mostrato al centro
752
+ * Se viene chiamato con override su toastr vuol dire che è una notifica secondaria e appare in alto a destra
919
753
  *
920
- * @returns {CsvHeaders[]} Header di esportazione già ordinati correttamente
754
+ * @param {string} text Testo da mostrare
755
+ * @param {"toastr" | "swal" | null} secondaryNotificationType Qualora sia una notifica secondaria, ne indica il tipo
921
756
  */
922
- parseAndGetGenericHeaders(obj, columns) {
923
- if (!obj.properties)
924
- return null;
925
- var headers = [];
926
- //Miracle incoming
927
- columns.forEach(t => {
928
- var propValue = obj.properties[t.key];
929
- Object.defineProperty(obj, t.key + "_exp", { value: propValue, writable: false, enumerable: true });
930
- headers.push({ label: t.label, key: t.key + "_exp", order: t.order, type: t.type, propKey: null });
931
- });
932
- //Tirati fuori tutti gli header faccio sort sull'ordinamento
933
- return headers.sort((a, b) => { return a.order - b.order; });
757
+ simpleSuccess(text, secondaryNotificationType = null, secondaryNotificationTimeout = null) {
758
+ if (this.emb.Embedded) {
759
+ this.emb.MainWindow.postMessage({ type: "alert", level: 'success', msg: text }, "*");
760
+ return;
761
+ }
762
+ let tos = this.toastrOrSwal(secondaryNotificationType);
763
+ if (tos == "swal")
764
+ this.successSwal.fire("", text);
765
+ else
766
+ this.toastr.success(text, null, { positionClass: tos == "toastr" ? "toast-top-right" : "toast-top-center", timeOut: secondaryNotificationTimeout || (tos == "toastr" ? 0 : 5000), extendedTimeOut: tos == "toastr" ? 0 : 1000 });
934
767
  }
935
768
  /**
936
- * Dato un oggetto genera gli header per l'esportazione e lo integra con le proprietà esportabili dalla libreria **@ctrl/ngx-csv**
937
- *
938
- * Metodo interno richiamato da **setupForExport**
769
+ * Presentazione di un semplice messaggio di informazione
939
770
  *
940
- * @param {any} obj Oggetto generico da esportare
771
+ * Se viene chiamato con le impostazioni di default e toastr è abilitato, viene mostrato al centro
772
+ * Se viene chiamato con override su toastr vuol dire che è una notifica secondaria e appare in alto a destra
941
773
  *
942
- * @returns {CsvHeaders[]} Header di esportazione già ordinati correttamente
774
+ * @param {string} text Testo da mostrare
775
+ * @param {"toastr" | "swal" | null} secondaryNotificationType Qualora sia una notifica secondaria, ne indica il tipo
943
776
  */
944
- parseAndGetHeaders(obj, columnsSelection) {
945
- var headers = [];
946
- // Miracle incoming
947
- let exportProps = obj[exportList] || [];
948
- let loc = obj[locProperty] ? this.lc.generateFromType(obj[locProperty]) : null;
949
- if (exportProps.length == 0)
950
- console.warn("[@esfaenza/extensions] Nessuna colonna configurata da esportare!");
951
- for (let i = 0; i < exportProps.length; i++) {
952
- let prop = exportProps[i];
953
- let propBase = "";
954
- let toCall;
955
- if (prop.endsWith(listCsvHdrPrefix)) {
956
- propBase = prop.replace(listCsvHdrPrefix, '');
957
- toCall = this.parseList.bind(this);
958
- }
959
- else if (prop.endsWith(dictionaryCsvHdrPrefix)) {
960
- propBase = prop.replace(dictionaryCsvHdrPrefix, '');
961
- toCall = this.parseDictionary.bind(this);
962
- }
963
- else if (prop.endsWith(csvVisPrefix)) {
964
- propBase = prop.replace(csvVisPrefix, '');
965
- if (typeof obj[propBase + csvValueNavigator] !== "undefined")
966
- toCall = this.parseObject.bind(this);
967
- else
968
- toCall = this.parseProperty.bind(this);
969
- }
970
- if (toCall)
971
- toCall(obj, propBase, headers, columnsSelection, loc);
777
+ simpleInfo(text, secondaryNotificationType = null, secondaryNotificationTimeout = null) {
778
+ if (this.emb.Embedded) {
779
+ this.emb.MainWindow.postMessage({ type: "alert", level: 'info', msg: text }, "*");
780
+ return;
972
781
  }
973
- return headers;
782
+ let tos = this.toastrOrSwal(secondaryNotificationType);
783
+ if (tos == "swal")
784
+ this.infoSwal.fire("", text);
785
+ else
786
+ this.toastr.info(text, null, { positionClass: tos == "toastr" ? "toast-top-right" : "toast-top-center", timeOut: secondaryNotificationTimeout || (tos == "toastr" ? 0 : 5000), extendedTimeOut: tos == "toastr" ? 0 : 1000 });
974
787
  }
975
788
  /**
976
- * Setup per l'esportazione di una singola proprietà.
977
- * Viene generato l'header e la proprietà relativa al valore formattato o no
789
+ * Presentazione di un semplice messaggio di errore
978
790
  *
979
- * @param {any} obj Oggetto di cui esportare la proprietà **prop**
980
- * @param {string} prop Proprietà da esportare
981
- * @param {CsvHeaders} headers Contenitore degli header, verrà riempito da questa funzione
982
- * @param {LocalizationService} loc Servizio di localizzazione che traduce tutti i nomi che può
791
+ * Se viene chiamato con le impostazioni di default e toastr è abilitato, viene mostrato al centro
792
+ * Se viene chiamato con override su toastr vuol dire che è una notifica secondaria e appare in alto a destra
793
+ *
794
+ * @param {string} text Testo da mostrare
795
+ * @param {"toastr" | "swal" | null} secondaryNotificationType Qualora sia una notifica secondaria, ne indica il tipo
983
796
  */
984
- parseProperty(obj, prop, headers, columnsSelection, loc) {
985
- let toEmit = obj[prop + csvVisPrefix];
986
- let format = obj[prop + csvFormatPrefix];
987
- let propKey = obj[prop + csvPropKey];
988
- if (propKey && !columnsSelection[propKey] && Object.keys(columnsSelection).length > 0) {
989
- console.log("[@esfaenza/extensions] Colonna da non esportare: " + propKey);
990
- return;
991
- }
992
- let text = obj[prop + csvHdrPrefix];
993
- let label = loc && text ? loc.loc(text) : text || "";
994
- let order = obj[prop + csvOrdPrefix];
995
- if (!toEmit)
797
+ simpleError(text, secondaryNotificationType = null, secondaryNotificationTimeout = null) {
798
+ if (this.emb.Embedded) {
799
+ this.emb.MainWindow.postMessage({ type: "alert", level: 'error', msg: text }, "*");
996
800
  return;
997
- // Se non ho un formato esporto direttamente
998
- if (!format) {
999
- // Se è un formato data mi assicuro di non stampare mai una data 00:00:00 altrimenti in esportazione viene uno schifo
1000
- let val = obj[prop] ? this.dates.trimSeconds(obj[prop].toString()) : "";
1001
- let key = prop + "_nofmt";
1002
- Object.defineProperty(obj, key, { value: val, writable: false, enumerable: true });
1003
- headers.push({ label, key, order, type: "string", propKey });
1004
- }
1005
- else {
1006
- let key = prop + "_fmt";
1007
- // Caso formato numerico
1008
- if (format == "F") {
1009
- // Check considerando la possibilità di zeri
1010
- let val = obj[prop] != null ? obj[prop].toString() : "";
1011
- // Elimino tutte le virgole (indicatori di migliaia per la culture default en-US)
1012
- val = val.replace(/,/, "");
1013
- // Il singolo punto che c'è, se presente (separatore decimali) lo trasformo in virgola
1014
- let valConverted = val.replace(".", ",");
1015
- Object.defineProperty(obj, key, { value: valConverted, writable: false, enumerable: true });
1016
- headers.push({ label, key, order, type: "number", propKey });
1017
- }
1018
- else {
1019
- // Se ho un formato data trasformo in dayjs, formatto ed esporto
1020
- // Per la trasformazione in dayjs provo prima a passargli la stringa di netto, sperando la riconosca
1021
- // Se non funziona provo a definirgli la formattazione standard del metering per quel linguaggio
1022
- let val = this.dates.getFormatted(obj[prop], format.length <= 10, format.length > 16);
1023
- Object.defineProperty(obj, key, { value: val ?? "", writable: false, enumerable: true });
1024
- headers.push({ label, key, order, type: "date", propKey });
1025
- }
1026
801
  }
802
+ let tos = this.toastrOrSwal(secondaryNotificationType);
803
+ if (tos == "swal")
804
+ this.errorSwal.fire("", text);
805
+ else
806
+ this.toastr.error(text, null, { positionClass: tos == "toastr" ? "toast-top-right" : "toast-top-center", timeOut: secondaryNotificationTimeout || (tos == "toastr" ? 0 : 5000), extendedTimeOut: tos == "toastr" ? 0 : 1000 });
1027
807
  }
1028
808
  /**
1029
- * Setup per l'esportazione di una singola proprietà da un oggetto.
1030
- * Viene generato l'header e la proprietà relativa al valore formattato o no.
809
+ * Presentazione di un semplice messaggio di avviso
1031
810
  *
1032
- * Per ottenere il valore e l'header della proprietà vengono utilizzati i navigatori auto-generati nel decoratore **ExportAs**
811
+ * Se viene chiamato con le impostazioni di default e toastr è abilitato, viene mostrato al centro
812
+ * Se viene chiamato con override su toastr vuol dire che è una notifica secondaria e appare in alto a destra
1033
813
  *
1034
- * @param {any} obj Oggetto di cui esportare la proprietà **prop**
1035
- * @param {string} prop Proprietà da esportare
1036
- * @param {CsvHeaders} headers Contenitore degli header, verrà riempito da questa funzione
1037
- * @param {LocalizationService} loc Servizio di localizzazione che traduce tutti i nomi che può
814
+ * @param {string} text Testo da mostrare
815
+ * @param {"toastr" | "swal" | null} secondaryNotificationType Qualora sia una notifica secondaria, ne indica il tipo
1038
816
  */
1039
- parseObject(obj, prop, headers, columnsSelection, loc) {
1040
- //se questa proprietà ha un navigator significa che deriva da un oggetto interno, recupero il valore in questa fase dato che prima non ce l'ho
1041
- let valuenavigator = obj[prop + csvValueNavigator];
1042
- //Es. di valuenavigator obj.subobj.subsubobj.property
1043
- let jmps = valuenavigator.split(".");
1044
- // Localizzazione presa dalla classe base se c'è, altrimenti dalla classe interna (cioè dal primo saltino)
1045
- if (!loc) {
1046
- let type = obj[prop + csvValueType];
1047
- let proto = new type();
1048
- loc = proto[locProperty] ? this.lc.generateFromType(proto[locProperty]) : null;
1049
- }
1050
- //Mi clono l'oggetto originale per non uccidergli i riferimenti
1051
- let clone = JSON.parse(JSON.stringify(obj));
1052
- //Salto ricorsivamente su me stesso per arrivare alla proprietà
1053
- //Salto 1 > diventa obj
1054
- //Salto 2 > diventa obj.subobj
1055
- //ecc...
1056
- jmps.forEach(pp => { clone = clone[pp]; });
1057
- //Valore finale :D
1058
- let value = clone;
1059
- let text = obj[prop + csvHdrPrefix];
1060
- let label = loc && text ? loc.loc(text) : text || "";
1061
- let order = obj[prop + csvOrdPrefix];
1062
- //Se per questa proprietà ho un formato lo applico
1063
- let format = obj[prop + csvFormatPrefix];
1064
- let type = "string";
1065
- if (format == "F") {
1066
- let val = value.toString();
1067
- val = val.replace(/,/, "");
1068
- value = val.replace(".", ",");
1069
- type = "number";
1070
- }
1071
- else if (format) {
1072
- value = this.dates.getFormatted(value, format.length <= 10, format.length > 16);
1073
- type = "date";
817
+ simpleWarning(text, secondaryNotificationType = null, secondaryNotificationTimeout = null) {
818
+ if (this.emb.Embedded) {
819
+ this.emb.MainWindow.postMessage({ type: "alert", level: 'warning', msg: text }, "*");
820
+ return;
1074
821
  }
1075
- Object.defineProperty(obj, prop, { value: value ?? "", writable: false, enumerable: true });
1076
- headers.push({ label, key: prop, order, type, propKey: null });
822
+ let tos = this.toastrOrSwal(secondaryNotificationType);
823
+ if (tos == "swal")
824
+ this.warningSwal.fire("", text);
825
+ else
826
+ this.toastr.warning(text, null, { positionClass: tos == "toastr" ? "toast-top-right" : "toast-top-center", timeOut: secondaryNotificationTimeout || (tos == "toastr" ? 0 : 5000), extendedTimeOut: tos == "toastr" ? 0 : 1000 });
1077
827
  }
1078
828
  /**
1079
- * Setup per l'esportazione di una lista di valori pivottati dinamicamente:
829
+ * Ripulisce tutti i messaggi presenti in un dato momento sullo schermo
830
+ */
831
+ clearMessages() {
832
+ this.toastr.clear();
833
+ swal.close();
834
+ }
835
+ /**
836
+ * Mostra un messaggio di avviso con richiesta di conferma
1080
837
  *
1081
- * => Recupero il valore utilizzando i navigatori
838
+ * @param {string} title Titolo del messaggio
839
+ * @param {string} text Contenuto del messaggio
1082
840
  *
1083
- * => Recupero l'header utilizzando i navigatori
841
+ * @returns {Promise} Restituisce una Promise col risultato scelto dall'utente (conferma o no)
842
+ */
843
+ promiseWarningWithChoice(title, text) {
844
+ return this.warningSwalWithCancel.fire(title, text);
845
+ }
846
+ /**
847
+ * In base alla configurazione attuale e all'eventuale override per la chiamata del caso indica se bisogna utilizzare toastr o sweetalert
1084
848
  *
1085
- * => Con il valore ci creo la property
849
+ * @param {"toastr" | "swal" | null} providerOverride Override alla modalità configurata
1086
850
  *
1087
- * => Con l'header e il riferimento alla property appena creata creo un record negli header da esportare
851
+ * @returns {"toastr" | "swal"} Indicazione su che provider di messaggi di avviso debba essere utilizzato
852
+ */
853
+ toastrOrSwal(providerOverride) {
854
+ if (providerOverride != null)
855
+ return providerOverride;
856
+ return "swal";
857
+ }
858
+ /**
859
+ * Mostra un messaggio di avviso con richiesta di conferma e gestisce il risultato chiamato i callback **onsuccess** o **onerror**
1088
860
  *
1089
- * @param {any} obj Oggetto di cui esportare la proprietà **prop**
1090
- * @param {string} prop Proprietà da esportare
1091
- * @param {CsvHeaders} headers Contenitore degli header, verrà riempito da questa funzione
1092
- * @param {LocalizationService} loc Servizio di localizzazione che traduce tutti i nomi che può
861
+ * @param {string} title Titolo del messaggio
862
+ * @param {string} text Contenuto del messaggio
863
+ * @param {Function} onsuccess Callback da chimare su conferma
864
+ * @param {Function} onerror Callback da chimare su errori
1093
865
  */
1094
- parseList(obj, prop, headers, columnsSelection, loc) {
1095
- let headernavigator = obj[prop + listCsvHdrPrefix];
1096
- let valuenavigator = obj[prop + listCsvValPrefix];
1097
- let valueformat = obj[prop + listCsvValFormat];
1098
- let order = obj[prop + csvOrdPrefix];
1099
- var jumps, tmpRes;
1100
- var objs = obj[prop];
1101
- for (let idx = 0; idx < objs.length; idx++) {
1102
- let listitem = objs[idx];
1103
- var headersplit = headernavigator.split(" ");
1104
- var label = "";
1105
- // Per l'header si considera a se stante ogni pezzo separato da spazio per fare le concatenazioni
1106
- headersplit.forEach(pr => {
1107
- jumps = pr.split(".");
1108
- tmpRes = JSON.parse(JSON.stringify(listitem));
1109
- jumps.forEach(pp => { tmpRes = tmpRes[pp]; });
1110
- let localized = !!loc ? loc.loc(tmpRes) : tmpRes;
1111
- if (!label)
1112
- label = localized;
1113
- else
1114
- label += " " + localized;
866
+ _simpleWarningWithChoice(title, text, onsuccess = null, onerror = null) {
867
+ this.warningSwalWithCancel.fire(title, text).then((result) => {
868
+ if (result.value && onsuccess)
869
+ onsuccess();
870
+ else if (onerror)
871
+ onerror();
872
+ });
873
+ }
874
+ simpleWarningWithChoice(title, text, onsuccess, onerror) {
875
+ this.withChoiceBase("warning", title, text, onsuccess, onerror);
876
+ }
877
+ simpleSuccessWithChoice(title, text, onsuccess, onerror) {
878
+ this.withChoiceBase("success", title, text, onsuccess, onerror);
879
+ }
880
+ withChoiceBase(level, title, text, onsuccess, onerror) {
881
+ if (this.emb.Embedded) {
882
+ let guid = this.hash.getGUID();
883
+ this.GuidRepsonseFunctionsMap[guid] = { onsuccess, onerror };
884
+ this.emb.MainWindow.postMessage({ type: "confirm", level, title, text, guid }, "*");
885
+ // Observe sulla risposta
886
+ console.log("Inviata confirm request alla pagina principale, in attesa di risposta...");
887
+ this.emb.MessageObserver.pipe(filter(event => event?.data?.type == "confirm-response" && event?.data?.guid == guid), take(1)).subscribe(event => {
888
+ console.log("Event listener su window-message. Risposta pergiunta");
889
+ if (event?.data?.result === true)
890
+ this.GuidRepsonseFunctionsMap[guid].onsuccess();
891
+ else if (event?.data?.result === true)
892
+ this.GuidRepsonseFunctionsMap[guid].onerror();
1115
893
  });
1116
- jumps = valuenavigator.split(".");
1117
- tmpRes = JSON.parse(JSON.stringify(listitem));
1118
- jumps.forEach(pp => { tmpRes = tmpRes[pp]; });
1119
- let value = tmpRes;
1120
- let type = "string";
1121
- if (valueformat == "F") {
1122
- let val = value != null ? value.toString() : "";
1123
- val = val.replace(/,/, "");
1124
- value = val.replace(".", ",");
1125
- type = "number";
1126
- }
1127
- else if (valueformat) {
1128
- value = this.dates.getFormatted(obj[prop], valueformat.length <= 10, valueformat.length > 16);
1129
- type = "date";
1130
- }
1131
- Object.defineProperty(obj, prop + idx, { value: value ?? "", writable: false });
1132
- headers.push({ label, key: prop + idx, order: order + idx, type, propKey: null });
1133
894
  }
895
+ else
896
+ (level == "warning" ? this._simpleWarningWithChoice : this._simpleSuccessWithChoice)(title, text, onsuccess, onerror);
1134
897
  }
1135
898
  /**
1136
- * Setup per l'esportazione di una lista di valori pivottati dinamicamente:
1137
- *
1138
- * => Recupero il valore utilizzando i navigatori
1139
- *
1140
- * => Recupero l'header utilizzando i navigatori
899
+ * Mostra un messaggio di success con richiesta di conferma e gestisce il risultato chiamato i callback **onconfirm** o **onabort**
1141
900
  *
1142
- * => Con il valore ci creo la property
901
+ * @param {string} title Titolo del messaggio
902
+ * @param {string} text Contenuto del messaggio
903
+ * @param {Function} onconfirm Callback da chimare su conferma
904
+ * @param {Function} onabort Callback da chimare su annullamento
905
+ * @param {string} confirmtext Testo del pulsante di azione
906
+ * @param {string} aborttext Testo del pulsante di annullamento
907
+ */
908
+ _simpleSuccessWithChoice(title, text, onconfirm = null, onabort = null, confirmtext = "", aborttext = '') {
909
+ var configuration = {
910
+ title: title,
911
+ html: text
912
+ };
913
+ if (confirmtext)
914
+ configuration["confirmButtonText"] = confirmtext;
915
+ if (aborttext)
916
+ configuration["cancelButtonText"] = aborttext;
917
+ this.successSwalWithCancel.fire(configuration).then((result) => {
918
+ if (result.value && onconfirm)
919
+ onconfirm();
920
+ else if (onabort)
921
+ onabort();
922
+ });
923
+ }
924
+ /**
925
+ * Mostra un messaggio di avviso con richiesta di conferma e gestisce il risultato chiamato i callback **onsuccess** o **onerror**
1143
926
  *
1144
- * => Con l'header e il riferimento alla property appena creata creo un record negli header da esportare
927
+ * @param {string} title Titolo del messaggio
928
+ * @param {string} text Contenuto del messaggio
929
+ */
930
+ observableSimpleWarningWithChoice(title, text) {
931
+ return of(this.warningSwalWithCancel.fire(title, text)).pipe(map(t => !!t.value));
932
+ }
933
+ /**
934
+ * Mostra un messaggio di avviso che la sessione corrente è scaduta e propone all'utente di navigare al login. Qualora l'utente decidesse di farlo
935
+ * verrà chiamata la funzione di callback **onnavigate
1145
936
  *
1146
- * @param {any} obj Oggetto di cui esportare la proprietà **prop**
1147
- * @param {string} prop Proprietà da esportare
1148
- * @param {CsvHeaders} headers Contenitore degli header, verrà riempito da questa funzione
1149
- * @param {LocalizationService} loc Servizio di localizzazione che traduce tutti i nomi che può
937
+ * @param {string} title Titolo del messaggio
938
+ * @param {string} text Contenuto del messaggio
939
+ * @param {Function} onnavigate Callback da chimare su navigazione in corso
1150
940
  */
1151
- parseDictionary(obj, prop, headers, columnsSelection, loc) {
1152
- let headernavigator = obj[prop + dictionaryCsvHdrPrefix];
1153
- let valuenavigator = obj[prop + dictionaryCsvValPrefix];
1154
- let order = obj[prop + csvOrdPrefix];
1155
- var jumps, tmpRes;
1156
- var objs = obj[prop];
1157
- for (let idx = 0; idx < objs.length; idx++) {
1158
- let listitem = objs[idx];
1159
- var headersplit = headernavigator.split(" ");
1160
- var label = "";
1161
- headersplit.forEach(pr => {
1162
- jumps = pr.split(".");
1163
- tmpRes = JSON.parse(JSON.stringify(listitem));
1164
- jumps.forEach(pp => { tmpRes = tmpRes[pp]; });
1165
- if (!label)
1166
- label = !!loc ? loc.loc(tmpRes) : tmpRes;
1167
- else
1168
- label += " " + !!loc ? loc.loc(tmpRes) : tmpRes;
1169
- });
1170
- var valuesplit = valuenavigator.split(",");
1171
- valuesplit.forEach((t, idxinternal) => {
1172
- var navig = t.split("-")[1];
1173
- var desc = t.split("-")[0];
1174
- jumps = navig.split(".");
1175
- tmpRes = JSON.parse(JSON.stringify(listitem));
1176
- jumps.forEach(pp => { tmpRes = tmpRes[pp]; });
1177
- let value = tmpRes;
1178
- let propname = prop + idx.toString() + idxinternal.toString();
1179
- Object.defineProperty(obj, propname, { value: value ?? "", writable: false });
1180
- headers.push({ label: label + " " + !!loc ? loc.loc(desc) : desc, key: propname, order: order + idx, type: 'string', propKey: null });
1181
- });
1182
- }
941
+ expiredSessionMessage(title, text, onnavigate = null) {
942
+ this.expiredSessionSwal.fire(title, text).then((result) => {
943
+ if (result.value && onnavigate)
944
+ onnavigate();
945
+ });
1183
946
  }
1184
947
  /**
1185
- * Effettua l'esportazione in file CSV
948
+ * Metodo helper per gestire in maniera standardizzata una risposta di tipo **CallResult**
949
+ *
950
+ * @param {CallResult} response Risposta ricevuta dal server
951
+ * @param {string} successMsg Messaggio da visualizzare in caso di successo
952
+ * @param {string} errorMsg Messaggio da visualizzare in caso di fallimento
953
+ * @param {Function} postSuccess Callback da chimare in caso di successo
954
+ * @param {Function} postFailure Callback da chimare in caso di fallimento
1186
955
  */
1187
- exportCSV(fn, headers, data) {
1188
- let csvData = '', row = '', sep = ';';
1189
- for (let i = 0; i < headers.length; i++) {
1190
- let h = headers[i];
1191
- row += `${row != '' ? sep : ''}"${h.label}"`;
956
+ manageCallResultResponse(response, successMsg, errorMsg, postSuccess = null, postFailure = null) {
957
+ if (response.success) {
958
+ if (response.haswarning)
959
+ this.simpleWarning(response.warning);
960
+ else if (successMsg)
961
+ this.simpleSuccess(successMsg);
962
+ if (postSuccess)
963
+ postSuccess();
1192
964
  }
1193
- csvData += row + '\r\n';
1194
- for (let i = 0; i < data.length; i++) {
1195
- row = '';
1196
- let item = data[i];
1197
- for (let j = 0; j < headers.length; j++) {
1198
- let val = item[headers[j].key];
1199
- row += `${row != '' ? sep : ''}"${val}"`;
1200
- }
1201
- csvData += row + '\r\n';
965
+ else {
966
+ this.simpleError((errorMsg ? errorMsg + ": " : "") + response.haserror ? response.error : '[NO ERR.]');
967
+ if (postFailure)
968
+ postFailure();
1202
969
  }
1203
- var BOM = new Uint8Array([0xEF, 0xBB, 0xBF]);
1204
- var blob = new Blob([BOM, csvData], { type: 'text/csv' });
1205
- var objectUrl = URL.createObjectURL(blob);
1206
- this.utiExts.fileDownload(objectUrl, fn.endsWith('.xlsx') ? fn.replace('.xlsx', '.csv') : fn.endsWith('.csv') ? fn : fn + ".csv");
1207
970
  }
1208
- /** Effettua l'esportazione del file Excel basandosi sul modulo **ExcelJS**, sugli header **headers** e sui dati **data** */
1209
- async exportExcel(fn, headers, data) {
1210
- try {
1211
- this.ExcelJS = this.ExcelJS || await import('exceljs');
971
+ /**
972
+ * Metodo helper per gestire in maniera standardizzata una risposta di tipo **string**, considerando che:
973
+ *
974
+ * Stringa vuota --> Tutto bene
975
+ *
976
+ * Stringa piena --> Questo è il messaggio d'errore per cui la chiamata è fallita
977
+ *
978
+ * @param {string} response Risposta ricevuta dal server
979
+ * @param {string} successMsg Messaggio da visualizzare in caso di successo
980
+ * @param {string} errorMsg Messaggio da visualizzare in caso di fallimento
981
+ * @param {Function} postSuccess Callback da chimare in caso di successo
982
+ * @param {Function} postFailure Callback da chimare in caso di fallimento
983
+ */
984
+ manageStringResponse(response, successMsg, errorMsg, postSuccess = null, postFailure = null) {
985
+ if (!response) {
986
+ if (successMsg)
987
+ this.simpleSuccess(successMsg);
988
+ if (postSuccess)
989
+ postSuccess();
1212
990
  }
1213
- catch {
1214
- throw "Impossibile caricare la libreria per l'esportazione in Excel";
991
+ else {
992
+ if (errorMsg)
993
+ this.simpleError(errorMsg + ": " + response);
994
+ if (postFailure)
995
+ postFailure();
1215
996
  }
1216
- let iFix = 1;
1217
- let workbook = new this.ExcelJS.Workbook();
1218
- workbook.creator = "Ema's big Es-Table";
1219
- workbook.created = new Date();
1220
- let sheet = workbook.addWorksheet('Data');
1221
- let header = sheet.getRow(1);
1222
- header.font = { bold: true };
1223
- headers = headers.sort((a, b) => a.order - b.order);
1224
- for (let i = 0; i < headers.length; i++) {
1225
- let h = headers[i];
1226
- header.getCell(i + iFix).value = h.label;
997
+ }
998
+ /**
999
+ * Metodo helper per gestire in maniera standardizzata una risposta di tipo **boolean**
1000
+ *
1001
+ * @param {string} response Risposta ricevuta dal server
1002
+ * @param {string} successMsg Messaggio da visualizzare in caso di successo
1003
+ * @param {string} errorMsg Messaggio da visualizzare in caso di fallimento
1004
+ * @param {Function} postSuccess Callback da chimare in caso di successo
1005
+ * @param {Function} postFailure Callback da chimare in caso di fallimento
1006
+ */
1007
+ manageStringResponseBool(response, successMsg, errorMsg, postSuccess = null, postFailure = null) {
1008
+ if (response) {
1009
+ if (successMsg)
1010
+ this.simpleSuccess(successMsg);
1011
+ if (postSuccess)
1012
+ postSuccess();
1227
1013
  }
1228
- for (let i = 0; i < data.length; i++) {
1229
- let row = sheet.getRow(i + iFix + 1);
1230
- let item = data[i];
1231
- for (let i = 0; i < headers.length; i++) {
1232
- let h = headers[i];
1233
- let cell = row.getCell(i + 1);
1234
- let val = item[h.key];
1235
- if (!val) {
1236
- cell.value = "";
1237
- continue;
1238
- }
1239
- switch (h.type) {
1240
- case 'date':
1241
- // ExcelJS va di default in UTC quindi rischierebbe di tirare giù 2 ore ad ogni esportazione
1242
- // Bisogna aggiungere l'utc offset alla data attuale
1243
- let date = this.dates.getDateConvertion(val);
1244
- if (date) {
1245
- let correctedDate = date.add(date.utcOffset(), 'minute');
1246
- cell.value = correctedDate.toDate();
1247
- cell.numFmt = val.length > 10 ? 'dd/mm/yyyy h:m:s' : '';
1248
- }
1014
+ else {
1015
+ if (errorMsg)
1016
+ this.simpleError(errorMsg);
1017
+ if (postFailure)
1018
+ postFailure();
1019
+ }
1020
+ }
1021
+ }
1022
+ MessageService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MessageService, deps: [{ token: Injector }, { token: i1.BaseLocalization, optional: true }, { token: AppEmbeddingExtensions }, { token: HashingService }], target: i0.ɵɵFactoryTarget.Injectable });
1023
+ MessageService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MessageService, providedIn: "root" });
1024
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MessageService, decorators: [{
1025
+ type: Injectable,
1026
+ args: [{ providedIn: "root" }]
1027
+ }], ctorParameters: function () { return [{ type: i0.Injector, decorators: [{
1028
+ type: Inject,
1029
+ args: [Injector]
1030
+ }] }, { type: i1.BaseLocalization, decorators: [{
1031
+ type: Optional
1032
+ }] }, { type: AppEmbeddingExtensions }, { type: HashingService }]; } });
1033
+
1034
+ // Angular
1035
+ /* Classe che contiene tutte le informazioni sull'embedding in un unico contenitore per semplicità */
1036
+ class AppEmbeddingExtensions {
1037
+ constructor(msgService, router) {
1038
+ this.msgService = msgService;
1039
+ this.router = router;
1040
+ this.Embedded = false;
1041
+ this.EmbeddingLevel = 0;
1042
+ this.MessageObserver = new Subject();
1043
+ this.setupEmbeddability();
1044
+ this.MainWindow = window;
1045
+ while (this.MainWindow.parent != this.MainWindow) {
1046
+ this.MainWindow = this.MainWindow.parent;
1047
+ this.EmbeddingLevel++;
1048
+ this.Embedded = true;
1049
+ }
1050
+ }
1051
+ setupEmbeddability() {
1052
+ window.onmessage = (event) => {
1053
+ // Ignoro i miei messaggi dato che mi interessano solo quelli degli altri iframe
1054
+ if (event.source == window && event?.data?.type != "modal-open")
1055
+ return;
1056
+ this.MessageObserver.next({ event: "window-message", data: event?.data });
1057
+ if (event?.data?.type == "alert") {
1058
+ console.log(`Window message - alert -> Level: ${event?.data?.level}, Message: ${event?.data?.msg}`);
1059
+ switch (event?.data?.level) {
1060
+ case "success":
1061
+ this.msgService.simpleSuccess(event?.data?.msg);
1249
1062
  break;
1250
- case 'number':
1251
- let converted = parseFloat(val.replace(',', '.'));
1252
- cell.value = isNaN(converted) ? "" : converted;
1063
+ case "warning":
1064
+ this.msgService.simpleWarning(event?.data?.msg);
1253
1065
  break;
1254
- default:
1255
- cell.value = val;
1066
+ case "error":
1067
+ this.msgService.simpleError(event?.data?.msg);
1068
+ break;
1069
+ case "info":
1070
+ this.msgService.simpleInfo(event?.data?.msg);
1071
+ break;
1072
+ }
1073
+ }
1074
+ else if (event?.data?.type == "confirm") {
1075
+ console.log(`Window message - confirm -> Level: ${event?.data?.level}, Message: ${event?.data?.text}, Title: ${event?.data?.title}, ID: ${event?.data?.guid}`);
1076
+ var sourceWindow = event.source;
1077
+ var baseResponse = { type: "confirm-response", guid: event?.data?.guid };
1078
+ switch (event?.data?.level) {
1079
+ case "success":
1080
+ this.msgService.simpleSuccessWithChoice(event?.data?.title, event?.data?.text, () => {
1081
+ debugger;
1082
+ sourceWindow.postMessage({ result: true, ...baseResponse }, "*");
1083
+ }, () => {
1084
+ sourceWindow.postMessage({ result: false, ...baseResponse }, "*");
1085
+ });
1086
+ break;
1087
+ case "warning":
1088
+ this.msgService.simpleWarningWithChoice(event?.data?.title, event?.data?.text, () => {
1089
+ debugger;
1090
+ sourceWindow.postMessage({ result: true, ...baseResponse }, "*");
1091
+ }, () => {
1092
+ sourceWindow.postMessage({ result: false, ...baseResponse }, "*");
1093
+ });
1256
1094
  break;
1257
1095
  }
1258
1096
  }
1097
+ else if (event?.data?.type == "navigate") {
1098
+ console.log(`Window message - navigate -> ${event?.data?.url}`);
1099
+ this.router.navigate([event?.data?.url]);
1100
+ }
1101
+ else if (event?.data?.type == "redirect") {
1102
+ console.log(`Window message - redirect -> ${event?.data?.url}`);
1103
+ window.location.href = event?.data?.url;
1104
+ }
1105
+ else if (event?.data?.type == "navigation") {
1106
+ console.log(`Window message - Navigation -> ${event?.data?.internalNavigation ? "[internal]" : ""} ${event?.data?.title}`);
1107
+ this.MessageObserver.next({ event: "navigation", data: event?.data });
1108
+ }
1109
+ else if (event?.data?.type == "modal-open") {
1110
+ const wrapper = document.body.getElementsByClassName("main-wrapper")[0];
1111
+ let wrapperStyles = window.getComputedStyle(wrapper);
1112
+ const wrapperPaddingLeft = parseInt(wrapperStyles.getPropertyValue("padding-left"));
1113
+ const wrapperPaddingRight = parseInt(wrapperStyles.getPropertyValue("padding-right"));
1114
+ console.log(`Window message - Modal Open -> Backdrop Height: ${event?.data?.backdropHeight}`);
1115
+ var topHeight = 116; // valore fisso, distanza fra il top e l'inizio dell'iframe, non sarà mai diverso
1116
+ var rightSpace = wrapperPaddingRight; // valore fisso, distanza fra la fine dell'iframe e il lato sinistro dello schermo, non sarà mai diverso
1117
+ var leftSpace = 230 + wrapperPaddingLeft; // 230 è la variabile $sidebar-width
1118
+ let commonStyles = "position: absolute; z-index: 9999; background-color: #000; opacity: 0.5; ";
1119
+ wrapper.style.setProperty("overflow", "hidden", "important");
1120
+ const top = document.createElement("div");
1121
+ top.className = "embedded-modal-top";
1122
+ top.style.cssText = commonStyles + `height: ${topHeight}px; top: 0; width: calc(100% - ${leftSpace}px); left: ${leftSpace}px`;
1123
+ top.id = "top";
1124
+ const left = document.createElement("div");
1125
+ left.className = "embedded-modal-left";
1126
+ left.style.cssText = commonStyles + `height: 100%; top: 0; width: ${leftSpace}px;`;
1127
+ left.id = "left";
1128
+ const right = document.createElement("div");
1129
+ right.className = "embedded-modal-right";
1130
+ right.style.cssText = commonStyles + `height: calc(100% - ${topHeight}px); top: ${topHeight}px; right: 0; width: ${rightSpace}px;`;
1131
+ right.id = "right";
1132
+ document.body.appendChild(top);
1133
+ document.body.appendChild(left);
1134
+ document.body.appendChild(right);
1135
+ }
1136
+ else if (event?.data?.type == "modal-close") {
1137
+ console.log(`Window message - Modal Close`);
1138
+ let wrapper = document.body.getElementsByClassName("main-wrapper")[0];
1139
+ wrapper.style.removeProperty("overflow");
1140
+ const top = document.getElementById("top");
1141
+ const left = document.getElementById("left");
1142
+ const right = document.getElementById("right");
1143
+ if (top)
1144
+ document.body.removeChild(top);
1145
+ if (left)
1146
+ document.body.removeChild(left);
1147
+ if (right)
1148
+ document.body.removeChild(right);
1149
+ }
1150
+ };
1151
+ if (this.Embedded)
1152
+ document.body.style.setProperty("overflow-y", "auto", "important");
1153
+ }
1154
+ refreshBoundariesOnMenuCollapse() {
1155
+ const wrapper = document.body.getElementsByClassName("main-wrapper")[0];
1156
+ let wrapperStyles = window.getComputedStyle(wrapper);
1157
+ const wrapperPaddingLeft = parseInt(wrapperStyles.getPropertyValue("padding-left"));
1158
+ var leftSpace = 230 + wrapperPaddingLeft;
1159
+ const left = document.getElementById("left");
1160
+ const top = document.getElementById("top");
1161
+ if (top) {
1162
+ top.style.setProperty("left", (leftSpace) + "px");
1163
+ top.style.setProperty("width", `calc(100% - ${leftSpace}px)`);
1259
1164
  }
1260
- let buffer = await workbook.xlsx.writeBuffer();
1261
- let blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;" });
1262
- let objectUrl = URL.createObjectURL(blob);
1263
- this.utiExts.fileDownload(objectUrl, fn.endsWith('.csv') ? fn.replace('.csv', '.xlsx') : fn.endsWith('.xlsx') ? fn : fn + ".xlsx");
1264
- }
1265
- /**
1266
- * Metodo che effettivamente genera gli header e i dati per l'esportazione con **ngx-csv**
1267
- *
1268
- * @param {any[]} items Oggetti da esportare
1269
- */
1270
- export(items, format, fileName, type, columnsFilter, genericHeaders) {
1271
- var createdItems = items.map(t => {
1272
- let tmp = new type();
1273
- for (let property in t)
1274
- tmp[property] = t[property];
1275
- return tmp;
1276
- });
1277
- let headers = genericHeaders ? this.setupForGenericExport(createdItems, genericHeaders) : this.setupForExport(createdItems, columnsFilter);
1278
- (format == "CSV" ? this.exportCSV : this.exportExcel).bind(this)(fileName, headers, createdItems);
1165
+ if (left)
1166
+ left.style.setProperty("width", leftSpace + "px");
1279
1167
  }
1280
1168
  }
1281
- ExportService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ExportService, deps: [{ token: DateService }, { token: UtilityService }, { token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Injectable });
1282
- ExportService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ExportService, providedIn: "root" });
1283
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ExportService, decorators: [{
1169
+ AppEmbeddingExtensions.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AppEmbeddingExtensions, deps: [{ token: MessageService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable });
1170
+ AppEmbeddingExtensions.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AppEmbeddingExtensions, providedIn: "root" });
1171
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: AppEmbeddingExtensions, decorators: [{
1284
1172
  type: Injectable,
1285
1173
  args: [{ providedIn: "root" }]
1286
- }], ctorParameters: function () { return [{ type: DateService }, { type: UtilityService }, { type: i1.LocalizationService }]; } });
1174
+ }], ctorParameters: function () { return [{ type: MessageService }, { type: i2.Router }]; } });
1287
1175
 
1288
1176
  // Angular
1289
1177
  /**
1290
- * Service che fornisce funzionalità di alert nei tipi fondamentali: success, info, warning e danger
1178
+ * Service che fornisce un accesso base in lettura/scrittura sulla clipboard
1291
1179
  */
1292
- class MessageService {
1293
- /**
1294
- * Costruttore
1295
- *
1296
- * @ignore
1297
- */
1298
- constructor(injector, locProvider, emb) {
1299
- this.injector = injector;
1300
- this.locProvider = locProvider;
1180
+ class BaseExtensionsService {
1181
+ constructor(emb) {
1301
1182
  this.emb = emb;
1302
- /**
1303
- * Oggetto statico in supporto alla localizzazione
1304
- */
1305
- this.loc = {
1306
- 'Confirm': { 'en-US': "Confirm", 'it-IT': "Conferma", },
1307
- 'Cancel': { 'en-US': "Cancel", 'it-IT': "Annulla", },
1308
- 'Close': { 'en-US': "Close", 'it-IT': "Chiudi", },
1309
- 'Error': { 'en-US': "Error", 'it-IT': "Errore", },
1310
- 'Info': { 'en-US': "Info", 'it-IT': "Informazione", },
1311
- 'Success': { 'en-US': "Success", 'it-IT': "Successo", },
1312
- 'Warning': { 'en-US': "Warning", 'it-IT': "Attenzione", }
1313
- };
1314
- this.init();
1315
- }
1316
- get toastr() {
1317
- return this.injector.get(ToastrService);
1318
- }
1319
- async init() {
1320
- let LOCALE = this.locProvider ? await this.locProvider.Locale.pipe(first()).toPromise() : 'it-IT';
1321
- this.expiredSessionSwal = swal.mixin({
1322
- showCancelButton: false,
1323
- confirmButtonText: 'Login',
1324
- customClass: {
1325
- confirmButton: "btn btn-primary",
1326
- container: "app-wrap",
1327
- },
1328
- buttonsStyling: false,
1329
- reverseButtons: false,
1330
- allowOutsideClick: false,
1331
- icon: "warning"
1332
- });
1333
- this.successSwalWithCancel = swal.mixin({
1334
- title: this.loc["Success"][LOCALE],
1335
- customClass: {
1336
- confirmButton: "btn btn-primary",
1337
- cancelButton: "btn btn-secondary app-margin-right-10",
1338
- container: "app-wrap",
1339
- },
1340
- buttonsStyling: false,
1341
- reverseButtons: true,
1342
- showCancelButton: true,
1343
- confirmButtonText: this.loc["Confirm"][LOCALE],
1344
- cancelButtonText: this.loc["Cancel"][LOCALE],
1345
- icon: "success"
1346
- });
1347
- this.warningSwalWithCancel = swal.mixin({
1348
- title: this.loc["Warning"][LOCALE],
1349
- customClass: {
1350
- confirmButton: "btn btn-primary",
1351
- cancelButton: "btn btn-secondary app-margin-right-10",
1352
- container: "app-wrap",
1353
- },
1354
- buttonsStyling: false,
1355
- reverseButtons: true,
1356
- showCancelButton: true,
1357
- confirmButtonText: this.loc["Confirm"][LOCALE],
1358
- cancelButtonText: this.loc["Cancel"][LOCALE],
1359
- icon: "warning"
1360
- });
1361
- this.warningSwal = swal.mixin({
1362
- title: this.loc["Warning"][LOCALE],
1363
- customClass: {
1364
- confirmButton: "btn btn-primary",
1365
- container: "app-wrap",
1366
- },
1367
- buttonsStyling: false,
1368
- reverseButtons: true,
1369
- showCancelButton: false,
1370
- confirmButtonText: this.loc["Close"][LOCALE],
1371
- icon: "warning"
1372
- });
1373
- this.successSwal = swal.mixin({
1374
- title: this.loc["Success"][LOCALE],
1375
- customClass: {
1376
- confirmButton: "btn btn-primary",
1377
- container: "app-wrap",
1378
- },
1379
- buttonsStyling: false,
1380
- reverseButtons: true,
1381
- showCancelButton: false,
1382
- confirmButtonText: this.loc["Close"][LOCALE],
1383
- icon: "success"
1384
- });
1385
- this.errorSwal = swal.mixin({
1386
- title: this.loc["Error"][LOCALE],
1387
- customClass: {
1388
- confirmButton: "btn btn-primary",
1389
- container: "app-wrap",
1390
- },
1391
- buttonsStyling: false,
1392
- reverseButtons: true,
1393
- showCancelButton: false,
1394
- confirmButtonText: this.loc["Close"][LOCALE],
1395
- icon: "error"
1396
- });
1397
- this.infoSwal = swal.mixin({
1398
- title: this.loc["Info"][LOCALE],
1399
- customClass: {
1400
- confirmButton: "btn btn-primary",
1401
- container: "app-wrap",
1402
- },
1403
- buttonsStyling: false,
1404
- reverseButtons: true,
1405
- showCancelButton: false,
1406
- confirmButtonText: this.loc["Close"][LOCALE],
1407
- icon: "info"
1408
- });
1409
- }
1410
- /**
1411
- * Presentazione di un semplice messaggio di successo
1412
- *
1413
- * Se viene chiamato con le impostazioni di default e toastr è abilitato, viene mostrato al centro
1414
- * Se viene chiamato con override su toastr vuol dire che è una notifica secondaria e appare in alto a destra
1415
- *
1416
- * @param {string} text Testo da mostrare
1417
- * @param {"toastr" | "swal" | null} secondaryNotificationType Qualora sia una notifica secondaria, ne indica il tipo
1418
- */
1419
- simpleSuccess(text, secondaryNotificationType = null, secondaryNotificationTimeout = null) {
1420
- if (this.emb.Embedded) {
1421
- this.emb.MainWindow.postMessage({ type: "alert", level: 'success', msg: text }, "*");
1422
- return;
1183
+ this.RedirectMap = {};
1184
+ this.RoutesMap = {};
1185
+ for (let prop in this.RedirectMap) {
1186
+ this.RoutesMap[prop] = { route: null };
1187
+ this.RoutesMap[prop].route = (param) => {
1188
+ let obj = {};
1189
+ obj[this.RedirectMap[prop].params[0]] = param;
1190
+ return [(this.emb.Embedded ? "pages_ext/" : "pages/") + this.RedirectMap[prop].url, obj];
1191
+ };
1423
1192
  }
1424
- let tos = this.toastrOrSwal(secondaryNotificationType);
1425
- if (tos == "swal")
1426
- this.successSwal.fire("", text);
1427
- else
1428
- this.toastr.success(text, null, { positionClass: tos == "toastr" ? "toast-top-right" : "toast-top-center", timeOut: secondaryNotificationTimeout || (tos == "toastr" ? 0 : 5000), extendedTimeOut: tos == "toastr" ? 0 : 1000 });
1429
1193
  }
1430
- /**
1431
- * Presentazione di un semplice messaggio di informazione
1432
- *
1433
- * Se viene chiamato con le impostazioni di default e toastr è abilitato, viene mostrato al centro
1434
- * Se viene chiamato con override su toastr vuol dire che è una notifica secondaria e appare in alto a destra
1435
- *
1436
- * @param {string} text Testo da mostrare
1437
- * @param {"toastr" | "swal" | null} secondaryNotificationType Qualora sia una notifica secondaria, ne indica il tipo
1438
- */
1439
- simpleInfo(text, secondaryNotificationType = null, secondaryNotificationTimeout = null) {
1440
- if (this.emb.Embedded) {
1441
- this.emb.MainWindow.postMessage({ type: "alert", level: 'info', msg: text }, "*");
1442
- return;
1443
- }
1444
- let tos = this.toastrOrSwal(secondaryNotificationType);
1445
- if (tos == "swal")
1446
- this.infoSwal.fire("", text);
1447
- else
1448
- this.toastr.info(text, null, { positionClass: tos == "toastr" ? "toast-top-right" : "toast-top-center", timeOut: secondaryNotificationTimeout || (tos == "toastr" ? 0 : 5000), extendedTimeOut: tos == "toastr" ? 0 : 1000 });
1194
+ }
1195
+ BaseExtensionsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: BaseExtensionsService, deps: [{ token: AppEmbeddingExtensions }], target: i0.ɵɵFactoryTarget.Injectable });
1196
+ BaseExtensionsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: BaseExtensionsService, providedIn: "root" });
1197
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: BaseExtensionsService, decorators: [{
1198
+ type: Injectable,
1199
+ args: [{ providedIn: "root" }]
1200
+ }], ctorParameters: function () { return [{ type: AppEmbeddingExtensions }]; } });
1201
+
1202
+ /**
1203
+ * Suffisso della proprietà da generare in cui salvare il navigatore
1204
+ * utilizzato dal servizio di esportazione per prendere il valore delle proprietà di un oggetto
1205
+ */
1206
+ const csvValueNavigator = "_csvnav";
1207
+ /** Suffisso con le informazioni del tipo per le esportazioni di oggetti */
1208
+ const csvValueType = "_csvtype";
1209
+ /** Suffisso della proprietà da generare in cui salvare l'ordine di esportazione */
1210
+ const csvOrdPrefix = "_csvord";
1211
+ /** Suffisso della proprietà da generare in cui salvare la visibilità di questa proprietà */
1212
+ const csvVisPrefix = "_csvvis";
1213
+ /** Suffisso della proprietà da generare in cui salvare il nome della colonna in cui salvare questa proprietà */
1214
+ const csvHdrPrefix = "_csvhdr";
1215
+ /** Suffisso della proprietà da generare in cui salvare il codice del th a cui si riferisce questo campo */
1216
+ const csvPropKey = "_csvkey";
1217
+ /** Suffisso della proprietà da generare in cui salvare il valore da prendere per una proprietà di tipo Lista */
1218
+ const listCsvValPrefix = "_listcsvval";
1219
+ /** Suffisso della proprietà da generare in cui salvare l'Header della proprietà di tipo Lista relativo al valore esportato nella proprietà con suffisso **listCsvValPrefix** */
1220
+ const listCsvHdrPrefix = "_listcsvhdr";
1221
+ /** Suffisso della proprietà da generare in cui salvare il formato della proprietà di tipo Lista relativo al valore esportato nella proprietà con suffisso **listCsvValPrefix** */
1222
+ const listCsvValFormat = "_listcsvvalformat";
1223
+ /** Suffisso della proprietà da generare in cui salvare il valore da prendere per una proprietà di tipo Dizionario */
1224
+ const dictionaryCsvValPrefix = "_flatlistcsvval";
1225
+ /** Suffisso della proprietà da generare in cui salvare l'Header della proprietà di un Dizionario relativo al valore esportato nella proprietà con suffisso **dictionaryCsvValPrefix** */
1226
+ const dictionaryCsvHdrPrefix = "_flatlistcsvhdr";
1227
+ /** Suffisso della proprietà da generare in cui salvare il formato della proprietà che si sta esportando */
1228
+ const csvFormatPrefix = "_csvfmt";
1229
+ /** Nome della proprietà che contiene tutti i nomi di tutte le proprietà da esportare */
1230
+ const exportList = "__export_list__";
1231
+ /** Nome della proprietà che contiene la classe di localizzazione da utilizzare per una data esportazione */
1232
+ const locProperty = "__loc__";
1233
+
1234
+ /**
1235
+ * Mappatura del TypeCode del C#
1236
+ */
1237
+ var TypeCode;
1238
+ (function (TypeCode) {
1239
+ /** @ignore */ TypeCode[TypeCode["Empty"] = 0] = "Empty";
1240
+ /** @ignore */ TypeCode[TypeCode["Obj"] = 1] = "Obj";
1241
+ /** @ignore */ TypeCode[TypeCode["DBNull"] = 2] = "DBNull";
1242
+ /** @ignore */ TypeCode[TypeCode["Boolean"] = 3] = "Boolean";
1243
+ /** @ignore */ TypeCode[TypeCode["Char"] = 4] = "Char";
1244
+ /** @ignore */ TypeCode[TypeCode["SByte"] = 5] = "SByte";
1245
+ /** @ignore */ TypeCode[TypeCode["Byte"] = 6] = "Byte";
1246
+ /** @ignore */ TypeCode[TypeCode["Int16"] = 7] = "Int16";
1247
+ /** @ignore */ TypeCode[TypeCode["UInt16"] = 8] = "UInt16";
1248
+ /** @ignore */ TypeCode[TypeCode["Int32"] = 9] = "Int32";
1249
+ /** @ignore */ TypeCode[TypeCode["UInt32"] = 10] = "UInt32";
1250
+ /** @ignore */ TypeCode[TypeCode["Int64"] = 11] = "Int64";
1251
+ /** @ignore */ TypeCode[TypeCode["UInt64"] = 12] = "UInt64";
1252
+ /** @ignore */ TypeCode[TypeCode["Single"] = 13] = "Single";
1253
+ /** @ignore */ TypeCode[TypeCode["Double"] = 14] = "Double";
1254
+ /** @ignore */ TypeCode[TypeCode["Decimal"] = 15] = "Decimal";
1255
+ /** @ignore */ TypeCode[TypeCode["DateTime"] = 16] = "DateTime";
1256
+ /** @ignore */ TypeCode[TypeCode["String"] = 18] = "String";
1257
+ })(TypeCode || (TypeCode = {}));
1258
+
1259
+ // Angular
1260
+ /**
1261
+ * Service che fornisce metodi di pubblica utilità
1262
+ */
1263
+ class UtilityService {
1264
+ constructor() {
1265
+ // Funzione di throttling per non spammare richieste in caso di animazioni attivate
1266
+ //TODO: spostarla in un metodo di utilit� (esfaenza/extensions)
1267
+ /** @ignore */
1268
+ this.executionTimers = {};
1449
1269
  }
1450
1270
  /**
1451
- * Presentazione di un semplice messaggio di errore
1452
- *
1453
- * Se viene chiamato con le impostazioni di default e toastr è abilitato, viene mostrato al centro
1454
- * Se viene chiamato con override su toastr vuol dire che è una notifica secondaria e appare in alto a destra
1455
- *
1456
- * @param {string} text Testo da mostrare
1457
- * @param {"toastr" | "swal" | null} secondaryNotificationType Qualora sia una notifica secondaria, ne indica il tipo
1271
+ * Deseleziona il testo eventualmente selezionato
1458
1272
  */
1459
- simpleError(text, secondaryNotificationType = null, secondaryNotificationTimeout = null) {
1460
- if (this.emb.Embedded) {
1461
- this.emb.MainWindow.postMessage({ type: "alert", level: 'error', msg: text }, "*");
1462
- return;
1273
+ clearTextSelection() {
1274
+ if (window.getSelection) {
1275
+ if (window.getSelection().empty) // Chrome
1276
+ window.getSelection().empty();
1277
+ else if (window.getSelection().removeAllRanges) // Firefox
1278
+ window.getSelection().removeAllRanges();
1463
1279
  }
1464
- let tos = this.toastrOrSwal(secondaryNotificationType);
1465
- if (tos == "swal")
1466
- this.errorSwal.fire("", text);
1467
- else
1468
- this.toastr.error(text, null, { positionClass: tos == "toastr" ? "toast-top-right" : "toast-top-center", timeOut: secondaryNotificationTimeout || (tos == "toastr" ? 0 : 5000), extendedTimeOut: tos == "toastr" ? 0 : 1000 });
1280
+ else if (document.selection) // IE?
1281
+ document.selection.empty();
1469
1282
  }
1470
1283
  /**
1471
- * Presentazione di un semplice messaggio di avviso
1284
+ * Partendo da una lista, dato il nome della proprietà chiave e il valore della chiave selezionata,
1285
+ * trova e restituisce l'oggetto desiderato
1472
1286
  *
1473
- * Se viene chiamato con le impostazioni di default e toastr è abilitato, viene mostrato al centro
1474
- * Se viene chiamato con override su toastr vuol dire che è una notifica secondaria e appare in alto a destra
1287
+ * @param {T[]} sourceList Lista di oggetti dentro cui cercare
1288
+ * @param {string} sourceItemIdField Nome della proprietà che rappresenta la chiave di un oggetto di tipo T
1289
+ * @param {string} selectedValue Valore di chiave selezionato
1475
1290
  *
1476
- * @param {string} text Testo da mostrare
1477
- * @param {"toastr" | "swal" | null} secondaryNotificationType Qualora sia una notifica secondaria, ne indica il tipo
1291
+ * @returns {T} Oggetto la cui proprietà **sourceItemIdField** assume il valore **selectedValue**
1478
1292
  */
1479
- simpleWarning(text, secondaryNotificationType = null, secondaryNotificationTimeout = null) {
1480
- if (this.emb.Embedded) {
1481
- this.emb.MainWindow.postMessage({ type: "alert", level: 'warning', msg: text }, "*");
1482
- return;
1293
+ getSelectedItem(sourceList, sourceItemIdField, selectedValue) {
1294
+ for (let i = 0; i < sourceList.length; i++) {
1295
+ var item = sourceList[i];
1296
+ if (item[sourceItemIdField] == selectedValue)
1297
+ return item;
1483
1298
  }
1484
- let tos = this.toastrOrSwal(secondaryNotificationType);
1485
- if (tos == "swal")
1486
- this.warningSwal.fire("", text);
1487
- else
1488
- this.toastr.warning(text, null, { positionClass: tos == "toastr" ? "toast-top-right" : "toast-top-center", timeOut: secondaryNotificationTimeout || (tos == "toastr" ? 0 : 5000), extendedTimeOut: tos == "toastr" ? 0 : 1000 });
1299
+ return null;
1489
1300
  }
1490
1301
  /**
1491
- * Ripulisce tutti i messaggi presenti in un dato momento sullo schermo
1302
+ * Effettua il reset di un Form di Angular
1303
+ *
1304
+ * @param {NgForm} form Form da resettare
1305
+ * @param {string} exception1 Campo da non resettare
1306
+ * @param {string} exception2 Campo da non resettare
1492
1307
  */
1493
- clearMessages() {
1494
- this.toastr.clear();
1495
- swal.close();
1308
+ cleanForm(form, exception1 = null, exception2 = null) {
1309
+ for (let name in form.controls) {
1310
+ if (name && name != exception1 && name != exception1 + "_internal" && name != exception2 && name != exception2 + "_internal") {
1311
+ form.controls[name].reset();
1312
+ }
1313
+ else {
1314
+ form.controls[name].markAsPristine();
1315
+ form.controls[name].markAsUntouched();
1316
+ }
1317
+ }
1318
+ //Reimposto il submitted
1319
+ form.submitted = false;
1496
1320
  }
1497
1321
  /**
1498
- * Mostra un messaggio di avviso con richiesta di conferma
1499
- *
1500
- * @param {string} title Titolo del messaggio
1501
- * @param {string} text Contenuto del messaggio
1322
+ * Helper che permette di scaricare un file dato un URL (Generato da una chiamata ad **window.URL.createObjectURL**)
1502
1323
  *
1503
- * @returns {Promise} Restituisce una Promise col risultato scelto dall'utente (conferma o no)
1324
+ * @param {string} url ObjectURL che rappresenta il file da scaricare
1325
+ * @param {string} filename Nome del file suggerito in fase di salvataggio
1504
1326
  */
1505
- promiseWarningWithChoice(title, text) {
1506
- return this.warningSwalWithCancel.fire(title, text);
1327
+ fileDownload(url, fileName) {
1328
+ var a = document.createElement("a");
1329
+ document.body.appendChild(a);
1330
+ a.className = "ta-display-none";
1331
+ a.href = url;
1332
+ a.download = fileName;
1333
+ a.click();
1334
+ window.URL.revokeObjectURL(url);
1335
+ document.body.removeChild(a);
1507
1336
  }
1508
1337
  /**
1509
- * In base alla configurazione attuale e all'eventuale override per la chiamata del caso indica se bisogna utilizzare toastr o sweetalert
1338
+ * Helper per la formattazione di un numero di millisecondi in una stringa più comprensibile per un umano
1510
1339
  *
1511
- * @param {"toastr" | "swal" | null} providerOverride Override alla modalità configurata
1340
+ * @param {number} duration Tempo espresso in millisecondi
1512
1341
  *
1513
- * @returns {"toastr" | "swal"} Indicazione su che provider di messaggi di avviso debba essere utilizzato
1342
+ * @returns {string} Durata formattata
1514
1343
  */
1515
- toastrOrSwal(providerOverride) {
1516
- if (providerOverride != null)
1517
- return providerOverride;
1518
- return "swal";
1344
+ msToTime(duration) {
1345
+ if (!duration)
1346
+ return "";
1347
+ var milliseconds = parseInt(((duration % 1000) / 100).toString()), seconds = parseInt(((duration / 1000) % 60).toString()), minutes = parseInt(((duration / (1000 * 60)) % 60).toString()), hours = parseInt(((duration / (1000 * 60 * 60)) % 24).toString());
1348
+ var st_hours = (hours < 10) ? "0" + hours : hours;
1349
+ var st_minutes = (minutes < 10) ? "0" + minutes : minutes;
1350
+ var st_seconds = (seconds < 10) ? "0" + seconds : seconds;
1351
+ return st_hours + ":" + st_minutes + ":" + st_seconds + "." + milliseconds;
1519
1352
  }
1520
1353
  /**
1521
- * Mostra un messaggio di avviso con richiesta di conferma e gestisce il risultato chiamato i callback **onsuccess** o **onerror**
1354
+ * Helper che permette di scaricare un file in Base64
1522
1355
  *
1523
- * @param {string} title Titolo del messaggio
1524
- * @param {string} text Contenuto del messaggio
1525
- * @param {Function} onsuccess Callback da chimare su conferma
1526
- * @param {Function} onerror Callback da chimare su errori
1356
+ * @param {string} base64Data Base64 che rappresenta il file da scaricare
1357
+ * @param {string} filename Nome del file suggerito in fase di salvataggio
1527
1358
  */
1528
- simpleWarningWithChoice(title, text, onsuccess = null, onerror = null) {
1529
- this.warningSwalWithCancel.fire(title, text).then((result) => {
1530
- if (result.value && onsuccess)
1531
- onsuccess();
1532
- else if (onerror)
1533
- onerror();
1534
- });
1359
+ saveFile(base64Data, filename) {
1360
+ var sampleArr = this.base64ToArrayBuffer(base64Data);
1361
+ this.saveByteArray(sampleArr, filename);
1535
1362
  }
1536
1363
  /**
1537
- * Mostra un messaggio di success con richiesta di conferma e gestisce il risultato chiamato i callback **onconfirm** o **onabort**
1364
+ * Trasforma un Base64 in un ArrayBuffer
1538
1365
  *
1539
- * @param {string} title Titolo del messaggio
1540
- * @param {string} text Contenuto del messaggio
1541
- * @param {Function} onconfirm Callback da chimare su conferma
1542
- * @param {Function} onabort Callback da chimare su annullamento
1543
- * @param {string} confirmtext Testo del pulsante di azione
1544
- * @param {string} aborttext Testo del pulsante di annullamento
1366
+ * @param {string} base64Data Base64 da trasformare
1367
+ *
1368
+ * @returns {Uint8Array} Array UTF8
1545
1369
  */
1546
- simpleSuccessWithChoice(title, text, onconfirm = null, onabort = null, confirmtext = "", aborttext = '') {
1547
- var configuration = {
1548
- title: title,
1549
- html: text
1550
- };
1551
- if (confirmtext)
1552
- configuration["confirmButtonText"] = confirmtext;
1553
- if (aborttext)
1554
- configuration["cancelButtonText"] = aborttext;
1555
- this.successSwalWithCancel.fire(configuration).then((result) => {
1556
- if (result.value && onconfirm)
1557
- onconfirm();
1558
- else if (onabort)
1559
- onabort();
1560
- });
1370
+ base64ToArrayBuffer(base64Data) {
1371
+ var binaryString = window.atob(base64Data);
1372
+ var binaryLen = binaryString.length;
1373
+ var bytes = new Uint8Array(binaryLen);
1374
+ for (var i = 0; i < binaryLen; i++) {
1375
+ var ascii = binaryString.charCodeAt(i);
1376
+ bytes[i] = ascii;
1377
+ }
1378
+ return bytes;
1561
1379
  }
1562
1380
  /**
1563
- * Mostra un messaggio di avviso con richiesta di conferma e gestisce il risultato chiamato i callback **onsuccess** o **onerror**
1381
+ * Helper che permette di scaricare un file dato un array di Byte (**Uint8Array**)
1564
1382
  *
1565
- * @param {string} title Titolo del messaggio
1566
- * @param {string} text Contenuto del messaggio
1383
+ * @param {Uint8Array} byte Rappresentazione del file da scaricare
1384
+ * @param {string} filename Nome del file suggerito in fase di salvataggio
1567
1385
  */
1568
- observableSimpleWarningWithChoice(title, text) {
1569
- return of(this.warningSwalWithCancel.fire(title, text)).pipe(map(t => !!t.value));
1386
+ saveByteArray(byte, filename) {
1387
+ var blob = new Blob([byte]);
1388
+ var link = document.createElement("a");
1389
+ document.body.appendChild(link);
1390
+ link.href = window.URL.createObjectURL(blob);
1391
+ var fileName = filename;
1392
+ link.download = fileName;
1393
+ link.click();
1394
+ document.body.removeChild(link);
1570
1395
  }
1396
+ ;
1571
1397
  /**
1572
- * Mostra un messaggio di avviso che la sessione corrente è scaduta e propone all'utente di navigare al login. Qualora l'utente decidesse di farlo
1573
- * verrà chiamata la funzione di callback **onnavigate
1398
+ * Utility per lo swap di due elementi di un array
1574
1399
  *
1575
- * @param {string} title Titolo del messaggio
1576
- * @param {string} text Contenuto del messaggio
1577
- * @param {Function} onnavigate Callback da chimare su navigazione in corso
1400
+ * @param {any[]} array Array di cui invertire due elementi
1401
+ * @param {number} x Indice del primo elemento
1402
+ * @param {number} y Indice del secondo elemento
1578
1403
  */
1579
- expiredSessionMessage(title, text, onnavigate = null) {
1580
- this.expiredSessionSwal.fire(title, text).then((result) => {
1581
- if (result.value && onnavigate)
1582
- onnavigate();
1583
- });
1404
+ swap(array, x, y) {
1405
+ var b = array[x];
1406
+ array[x] = array[y];
1407
+ array[y] = b;
1584
1408
  }
1585
1409
  /**
1586
- * Metodo helper per gestire in maniera standardizzata una risposta di tipo **CallResult**
1410
+ * Helper di trascodifica da tipo c# a tipo Typescript
1587
1411
  *
1588
- * @param {CallResult} response Risposta ricevuta dal server
1589
- * @param {string} successMsg Messaggio da visualizzare in caso di successo
1590
- * @param {string} errorMsg Messaggio da visualizzare in caso di fallimento
1591
- * @param {Function} postSuccess Callback da chimare in caso di successo
1592
- * @param {Function} postFailure Callback da chimare in caso di fallimento
1412
+ * @param {TypeCode} type Tipo da trascodificare
1413
+ *
1414
+ * @returns {"boolean" | "number" | "string" | "date"} Tipo Typescript corrispondente
1593
1415
  */
1594
- manageCallResultResponse(response, successMsg, errorMsg, postSuccess = null, postFailure = null) {
1595
- if (response.success) {
1596
- if (response.haswarning)
1597
- this.simpleWarning(response.warning);
1598
- else if (successMsg)
1599
- this.simpleSuccess(successMsg);
1600
- if (postSuccess)
1601
- postSuccess();
1602
- }
1603
- else {
1604
- this.simpleError((errorMsg ? errorMsg + ": " : "") + response.haserror ? response.error : '[NO ERR.]');
1605
- if (postFailure)
1606
- postFailure();
1416
+ getJsTypeFromTypeCode(type) {
1417
+ switch (type) {
1418
+ case TypeCode.Boolean:
1419
+ return "boolean";
1420
+ case TypeCode.Decimal:
1421
+ case TypeCode.Double:
1422
+ case TypeCode.Single:
1423
+ case TypeCode.Int16:
1424
+ case TypeCode.Int32:
1425
+ case TypeCode.Int64:
1426
+ case TypeCode.Byte:
1427
+ case TypeCode.SByte:
1428
+ case TypeCode.UInt16:
1429
+ case TypeCode.UInt32:
1430
+ case TypeCode.UInt64:
1431
+ return "number";
1432
+ case TypeCode.Char:
1433
+ case TypeCode.String:
1434
+ return "string";
1435
+ case TypeCode.DateTime:
1436
+ return "date";
1437
+ default:
1438
+ console.log("Unrecognized input type. Typecode:" + type);
1439
+ return "string";
1607
1440
  }
1608
1441
  }
1609
1442
  /**
1610
- * Metodo helper per gestire in maniera standardizzata una risposta di tipo **string**, considerando che:
1443
+ * Effettua la clonazione profonda di un oggetto in maniera molto più performante che JSON.parse(JSON.stringify()).
1611
1444
  *
1612
- * Stringa vuota --> Tutto bene
1445
+ * Usare solo per oggetti puri e quantomeno semplici per evitare complicazioni derivanti dalle semplificazioni che questo metodo assume
1613
1446
  *
1614
- * Stringa piena --> Questo è il messaggio d'errore per cui la chiamata è fallita
1447
+ * @param {any} source Oggetto da clonare
1615
1448
  *
1616
- * @param {string} response Risposta ricevuta dal server
1617
- * @param {string} successMsg Messaggio da visualizzare in caso di successo
1618
- * @param {string} errorMsg Messaggio da visualizzare in caso di fallimento
1619
- * @param {Function} postSuccess Callback da chimare in caso di successo
1620
- * @param {Function} postFailure Callback da chimare in caso di fallimento
1449
+ * @return {any} Clone dell'oggetto passato
1621
1450
  */
1622
- manageStringResponse(response, successMsg, errorMsg, postSuccess = null, postFailure = null) {
1623
- if (!response) {
1624
- if (successMsg)
1625
- this.simpleSuccess(successMsg);
1626
- if (postSuccess)
1627
- postSuccess();
1628
- }
1629
- else {
1630
- if (errorMsg)
1631
- this.simpleError(errorMsg + ": " + response);
1632
- if (postFailure)
1633
- postFailure();
1451
+ deepClone(source) {
1452
+ // Valori semplici
1453
+ if (source == null || typeof source !== 'object')
1454
+ return source;
1455
+ // Pseudo Struct
1456
+ switch (toString.call(source)) {
1457
+ case '[object Boolean]':
1458
+ case '[object Number]':
1459
+ case '[object String]':
1460
+ case '[object Date]':
1461
+ return new source.constructor(source.valueOf());
1462
+ // Clonazione di un file -> Restituisco il riferimento al file stesso
1463
+ case "[object File]":
1464
+ return source;
1465
+ default: break;
1634
1466
  }
1467
+ // Oggetti Complessi
1468
+ return this.recursiveStep(source, Array.isArray(source) || source instanceof Array ? [] : Object.create(Object.getPrototypeOf(source)));
1635
1469
  }
1636
1470
  /**
1637
- * Metodo helper per gestire in maniera standardizzata una risposta di tipo **boolean**
1638
- *
1639
- * @param {string} response Risposta ricevuta dal server
1640
- * @param {string} successMsg Messaggio da visualizzare in caso di successo
1641
- * @param {string} errorMsg Messaggio da visualizzare in caso di fallimento
1642
- * @param {Function} postSuccess Callback da chimare in caso di successo
1643
- * @param {Function} postFailure Callback da chimare in caso di fallimento
1471
+ * @ignore
1472
+ * Step ricorsivo per la clonatura degli oggetti. Vedere **deepClone**
1644
1473
  */
1645
- manageStringResponseBool(response, successMsg, errorMsg, postSuccess = null, postFailure = null) {
1646
- if (response) {
1647
- if (successMsg)
1648
- this.simpleSuccess(successMsg);
1649
- if (postSuccess)
1650
- postSuccess();
1474
+ recursiveStep(source, destination) {
1475
+ if (Array.isArray(source) || source instanceof Array) {
1476
+ for (var i = 0, ii = source.length; i < ii; i++)
1477
+ destination.push(this.deepClone(source[i]));
1651
1478
  }
1652
- else {
1653
- if (errorMsg)
1654
- this.simpleError(errorMsg);
1655
- if (postFailure)
1656
- postFailure();
1479
+ else if (source && typeof source.hasOwnProperty === 'function') {
1480
+ for (let key in source) {
1481
+ if (source.hasOwnProperty(key))
1482
+ destination[key] = this.deepClone(source[key]);
1483
+ }
1657
1484
  }
1485
+ return destination;
1486
+ }
1487
+ cast(object, clss) {
1488
+ let ret = Object.assign(Object.create(clss.prototype), object);
1489
+ return ret;
1490
+ }
1491
+ /** @ignore */
1492
+ throttla(id, func, throttleTime) {
1493
+ //Se ho la funzione che vuole eseguire ripulisco quel timeout
1494
+ if (this.executionTimers[id])
1495
+ clearTimeout(this.executionTimers[id]);
1496
+ //Ricreo il timeout per eseguire quella funzione dopo throttleTime millisecondi
1497
+ this.executionTimers[id] = setTimeout(() => { func(); this.executionTimers[id] = null; }, throttleTime);
1658
1498
  }
1659
1499
  }
1660
- MessageService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MessageService, deps: [{ token: Injector }, { token: i1.BaseLocalization, optional: true }, { token: AppEmbeddingExtensions }], target: i0.ɵɵFactoryTarget.Injectable });
1661
- MessageService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MessageService, providedIn: "root" });
1662
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MessageService, decorators: [{
1500
+ UtilityService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: UtilityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1501
+ UtilityService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: UtilityService, providedIn: "root" });
1502
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: UtilityService, decorators: [{
1663
1503
  type: Injectable,
1664
1504
  args: [{ providedIn: "root" }]
1665
- }], ctorParameters: function () { return [{ type: i0.Injector, decorators: [{
1666
- type: Inject,
1667
- args: [Injector]
1668
- }] }, { type: i1.BaseLocalization, decorators: [{
1669
- type: Optional
1670
- }] }, { type: AppEmbeddingExtensions }]; } });
1505
+ }] });
1671
1506
 
1672
1507
  // Angular
1673
1508
  /**
1674
- * Service che fornisce un accesso base in lettura/scrittura sulla clipboard
1509
+ * Decoratore che fornisce la classe di localizzazione per tutte le proprietà esportate con @Export e qualsiasi altro tag che richieda localizzazioni.
1510
+ *
1511
+ * Sostanzilamente aggiunge la proprietà **__loc__** all'oggetto creato dalla classe corrente assegnandogli come valore il tipo del LocalizationService da usare per la traduzione
1512
+ *
1513
+ * @param {Type<LocalizationService>} loc Tipo ereditato dal LocalizationService che può essere creato a runtime sotto contesto della DI di Angular
1514
+ */
1515
+ function ExportLocalization(loc) {
1516
+ return function integrateLoc(constructor) {
1517
+ return class extends constructor {
1518
+ constructor() {
1519
+ super(...arguments);
1520
+ this.__loc__ = loc;
1521
+ }
1522
+ };
1523
+ };
1524
+ }
1525
+ /**
1526
+ * Decoratore di esportazione utilizzabile su una proprietà singola.
1527
+ * Verranno generate 3 proprietà che gestiranno l'esportazione: (prop, prop_csvvis, prop_csvhdr).
1528
+ *
1529
+ * Ad esempio, da questa configurazione:
1530
+ *
1531
+ * @example
1532
+ * ```
1533
+ * @Export(true, "MyHeader")
1534
+ * ciao: string;
1535
+ * ```
1536
+ *
1537
+ * Nasceranno le seguenti proprietà nell'oggetto esportabile:
1538
+ *
1539
+ * @example
1540
+ * ```
1541
+ * ciao_csvvis: string; => true
1542
+ * ciao: string;
1543
+ * ciao_csvhdr: string => "MyHeader"
1544
+ * ```
1545
+ *
1546
+ * @param {number} order Ordine di esportazione. Più piccolo è, prima appare il valore
1547
+ * @param {string} header Titolo della colonna nel file CSV esportato
1548
+ * @param {string} format Formato di esportazione. Può essere un formato data per i campi data o 'F' per i campi floating point
1549
+ */
1550
+ const Export = (order, header, format = null, tableid = null) => (target, propertyKey) => {
1551
+ if (format)
1552
+ Object.defineProperty(target, propertyKey + csvFormatPrefix, { value: format, writable: false });
1553
+ Object.defineProperty(target, propertyKey + csvOrdPrefix, { value: order, writable: false });
1554
+ Object.defineProperty(target, propertyKey + csvVisPrefix, { value: !!header, writable: false });
1555
+ Object.defineProperty(target, propertyKey + csvHdrPrefix, { value: header, writable: false });
1556
+ if (tableid)
1557
+ Object.defineProperty(target, propertyKey + csvPropKey, { value: tableid, writable: false });
1558
+ if (target[exportList])
1559
+ target[exportList].push(propertyKey + csvVisPrefix);
1560
+ else
1561
+ target[exportList] = [propertyKey + csvVisPrefix];
1562
+ };
1563
+ /**
1564
+ * Decoratore di esportazione utilizzabile su un oggetto.
1565
+ * Per ogni proprietà dell'oggetto verranno generate 3 proprietà che gestiranno l'esportazione: (prop, prop_csvvis, prop_csvhdr).
1566
+ * Per essere esportate, le proprietà dell'oggetto devono essere marcate con i Decoratori di esportazione
1567
+ *
1568
+ * Ad esempio, da questa configurazione:
1569
+ *
1570
+ * @example
1571
+ * ```
1572
+ * MyObj {
1573
+ * @Export(true, "MyHeader")
1574
+ * ciao: string;
1575
+ * }
1576
+ *
1577
+ * @ExportObject(true, "MyHeader")
1578
+ * test: MyObj;
1579
+ * ```
1580
+ *
1581
+ * Nasceranno le seguenti proprietà nell'oggetto esportabile:
1582
+ *
1583
+ * @example
1584
+ * ```
1585
+ * testciao: string; => Valore di MyObj.ciao
1586
+ * testciao_csvvis: string; => true
1587
+ * testciao_csvhdr: string => "MyHeader"
1588
+ * ```
1589
+ *
1590
+ * @param {number} order Ordine di esportazione. Più piccolo è, prima appare il valore
1591
+ * @param {any} type Tipo da esportare
1592
+ */
1593
+ const ExportAs = (order, type, prefix) => (target, propertyKey) => {
1594
+ var t = new type();
1595
+ var props = t[exportList];
1596
+ for (let i = 0; i < props.length; i++) {
1597
+ let prop = props[i].replace(csvVisPrefix, '');
1598
+ if (typeof t[prop + csvVisPrefix] !== "undefined") {
1599
+ var toEmit = t[prop + csvVisPrefix];
1600
+ var lbl = t[prop + csvHdrPrefix];
1601
+ var format = t[prop + csvFormatPrefix];
1602
+ var orderProp = t[prop + csvOrdPrefix];
1603
+ if (format)
1604
+ Object.defineProperty(target, propertyKey + prop + csvFormatPrefix, { value: format, writable: false });
1605
+ Object.defineProperty(target, propertyKey + prop + csvOrdPrefix, { value: orderProp + order, writable: false });
1606
+ Object.defineProperty(target, propertyKey + prop, { value: null, writable: true, enumerable: true });
1607
+ Object.defineProperty(target, propertyKey + prop + csvValueNavigator, { value: propertyKey + "." + prop, writable: false });
1608
+ Object.defineProperty(target, propertyKey + prop + csvVisPrefix, { value: toEmit, writable: false });
1609
+ Object.defineProperty(target, propertyKey + prop + csvHdrPrefix, { value: (prefix ? prefix + ' ' : '') + lbl, writable: false });
1610
+ Object.defineProperty(target, propertyKey + prop + csvValueType, { value: type, writable: false });
1611
+ if (target[exportList])
1612
+ target[exportList].push(propertyKey + prop + csvVisPrefix);
1613
+ else
1614
+ target[exportList] = [propertyKey + prop + csvVisPrefix];
1615
+ }
1616
+ }
1617
+ };
1618
+ /**
1619
+ * Decoratore di esportazione utilizzabile su una lista,
1620
+ * si utilizzano 2 navigator rispettivamente per la valorizzazione dell'Header e del Valore e
1621
+ * per ogni elemento dell'array verranno generate 3 proprietà che gestiranno l'esportazione: (prop, prop_csvvis, prop_csvhdr)
1622
+ *
1623
+ * ATTENZIONE: Gli oggetti esportati in questa modalità non devono presentare altri tag di tipo @Export{...} all'interno. Fa tutto questo decoratore
1624
+ *
1625
+ * I navigator hanno questa convenzione:
1626
+ *
1627
+ * . --> divide due proprietà da richiamare consecutivamente: "a.b" richiamerà "obj.a.b";
1628
+ *
1629
+ * | --> divide più proprietà per le concatenazioni con uno spazio fra una e l'altra: "regdesc|slice.slicename" diventerà obj.regdesc + " " + obj.slice.slicename
1630
+ *
1631
+ * @param {number} order Ordine di esportazione. Più piccolo è, prima appare il valore
1632
+ * @param {string} headernavigator Navigator col compito di selezionare il titolo per la colonna
1633
+ * @param {string} valuenavigator Navigator col compito di selezionare il valore per la colonna
1634
+ * @param {string} valueformat Formato di esportazione per i valori selezionati dal **valuenavigator**. Può essere un formato data per i campi data o 'F' per i campi floating point
1635
+ */
1636
+ const ExportList = (order, headernavigator, valuenavigator, valueformat = null) => (target, propertyKey) => {
1637
+ Object.defineProperty(target, propertyKey + csvOrdPrefix, { value: order, writable: false });
1638
+ Object.defineProperty(target, propertyKey + listCsvValPrefix, { value: valuenavigator, writable: false });
1639
+ Object.defineProperty(target, propertyKey + listCsvHdrPrefix, { value: headernavigator, writable: false });
1640
+ Object.defineProperty(target, propertyKey + listCsvValFormat, { value: valueformat, writable: false });
1641
+ if (target[exportList])
1642
+ target[exportList].push(propertyKey + listCsvHdrPrefix);
1643
+ else
1644
+ target[exportList] = [propertyKey + listCsvHdrPrefix];
1645
+ };
1646
+ /**
1647
+ * Decoratore di esportazione utilizzabile su un dizionario. Se ad esempio si vogliono generare le colonne
1648
+ *
1649
+ * Valore A = 1
1650
+ *
1651
+ * Valore B = 2
1652
+ *
1653
+ * Valore C = 3
1654
+ *
1655
+ * partendo da un oggetto iniziale { Valore { A: 1, B: 2, C: 3 } }
1656
+ *
1657
+ * @param {number} order Ordine di esportazione. Più piccolo è, prima appare il valore
1658
+ * @param {string} headernavigator Navigator col compito di selezionare il titolo per la colonna
1659
+ * @param {string} valuenavigator Navigator col compito di selezionare il valore per la colonna
1660
+ */
1661
+ const ExportDictionary = (order, headernavigator, valuenavigator) => (target, propertyKey) => {
1662
+ Object.defineProperty(target, propertyKey + csvOrdPrefix, { value: order, writable: false });
1663
+ Object.defineProperty(target, propertyKey + dictionaryCsvValPrefix, { value: valuenavigator, writable: false });
1664
+ Object.defineProperty(target, propertyKey + dictionaryCsvHdrPrefix, { value: headernavigator, writable: false });
1665
+ if (target[exportList])
1666
+ target[exportList].push(propertyKey + dictionaryCsvHdrPrefix);
1667
+ else
1668
+ target[exportList] = [propertyKey + dictionaryCsvHdrPrefix];
1669
+ };
1670
+ /**
1671
+ * Service che si occupa dell'esportazione degli oggetti marcati dai Decoratori **ExportDictionary**, **ExportList**, **ExportAs** o **Export**
1675
1672
  */
1676
- class ClipboardService {
1673
+ class ExportService {
1677
1674
  /**
1678
1675
  * Costruttore
1679
1676
  *
1680
1677
  * @ignore
1681
1678
  */
1682
- constructor(msgService, locProvider) {
1683
- this.msgService = msgService;
1684
- this.locProvider = locProvider;
1685
- /**
1686
- * Oggetto statico di localizzazione per i messaggi di questa Service
1687
- */
1688
- this.loc = {
1689
- "Unfortunately Firefox doesn't yet support direct Clipboard access if not via extensions, Please use Chrome to do this operation": {
1690
- 'en-US': "Unfortunately Firefox doesn't yet support direct Clipboard access if not via extensions, Please use Chrome to do this operation",
1691
- 'it-IT': "Mi dispiace ma Firefox non supporta l'accesso diretto alla Clipboard, se non attraverso le estensioni. Si prega di usare Chrome"
1692
- },
1693
- "Generic error during 'copy' command execution": {
1694
- 'en-US': "Generic error during 'copy' command execution",
1695
- 'it-IT': "Errore generico durante l'esecuzione del comando 'copy'"
1696
- },
1697
- "Error during Clipboard content read operation": {
1698
- 'en-US': "Error during Clipboard content read operation",
1699
- 'it-IT': "Errore nella lettura del contenuto della Clipboard"
1700
- },
1701
- "Error during Clipboard content copy operation": {
1702
- 'en-US': "Error during Clipboard content copy operation",
1703
- 'it-IT': "Errore nella scrittura del contenuto nella Clipboard"
1704
- },
1705
- "Please insert your clipboard content": {
1706
- 'en-US': "Please insert your clipboard content",
1707
- 'it-IT': "Si prega di incollare il contenuto della Clipboard"
1708
- },
1709
- "User input required": {
1710
- 'en-US': "User input required",
1711
- 'it-IT': "Richiesto Input utente"
1712
- },
1713
- "Your current browser does not support reading from the clipboard directly. Please paste your clipboard's content in this Input field and confirm the operation": {
1714
- 'en-US': "Your current browser does not support reading from the clipboard directly. Please paste your clipboard's content in this Input field and confirm the operation",
1715
- 'it-IT': "Il browser corrente non supporta la lettura diretta dei dati della Clipboard, si prega di effettuare un'incolla (CTRL + V) nella casella di testo e confermare l'operazione"
1716
- },
1717
- "Confirm": {
1718
- 'en-US': "Confirm",
1719
- 'it-IT': "Conferma"
1720
- },
1721
- "Cancel": {
1722
- 'en-US': "Cancel",
1723
- 'it-IT': "Annulla"
1724
- },
1725
- };
1679
+ constructor(dates, utiExts, lc) {
1680
+ this.dates = dates;
1681
+ this.utiExts = utiExts;
1682
+ this.lc = lc;
1726
1683
  }
1727
1684
  /**
1728
- * Prende il valore della clipboard.
1729
- * Si può specificare se ci si aspetta una lista o una matrice di valori in modo da ricevere già un risultato utilizzabile
1685
+ * Data una lista di oggetti genera gli header per l'esportazione e integra ogni oggetto con le proprietà esportabili dalla libreria **@ctrl/ngx-csv**
1730
1686
  *
1731
- * @param {'array' | 'matrix'} style Stile dell'output desiderato, se array o matrice
1732
- * @param {Function} valueFoundCallback Callback che questa funzione chiamerà una volta ottenuto i valori richiesti dalla clipboard
1687
+ * @param {any[]} objs Oggetti da esportare
1688
+ *
1689
+ * @returns {CsvHeaders[]} Header di esportazione già ordinati correttamente
1733
1690
  */
1734
- async getClipboard(style, valueFoundCallback) {
1735
- let LOCALE = this.locProvider ? await this.locProvider.Locale.pipe(first()).toPromise() : 'it-IT';
1736
- if (navigator.userAgent.indexOf("Firefox") != -1) {
1737
- swal.fire({
1738
- title: this.loc["User input required"][LOCALE],
1739
- text: this.loc["Your current browser does not support reading from the clipboard directly. Please paste your clipboard's content in this Input field and confirm the operation"][LOCALE],
1740
- input: 'textarea',
1741
- icon: "warning",
1742
- confirmButtonText: this.loc["Confirm"][LOCALE],
1743
- cancelButtonText: this.loc["Cancel"][LOCALE],
1744
- showCancelButton: true,
1745
- customClass: {
1746
- confirmButton: "btn btn-primary",
1747
- cancelButton: "btn btn-secondary app-margin-right-15",
1748
- container: "app-wrap",
1749
- },
1750
- reverseButtons: true,
1751
- allowOutsideClick: false,
1752
- inputValidator: (value) => {
1753
- if (!value)
1754
- return this.loc["Please insert your clipboard content"][LOCALE];
1755
- }
1756
- }).then(t => {
1757
- if (t.isConfirmed) {
1758
- console.log("[@esfaenza/extensions] Retrieving input data from user input");
1759
- this.doClipboardDataGet(t.value, style, valueFoundCallback);
1691
+ setupForExport(objs, columns = []) {
1692
+ let headers = [];
1693
+ let headersCache = {};
1694
+ if (!objs || objs.length == 0)
1695
+ return headers;
1696
+ // Devo per forza farlo per tutti gli oggetti dato che devo esporre le proprietà che mi servono da esportare
1697
+ // Gli header li raccolgo tutti poi faccio uan distinct in modo da esportare tutte le proprietà per bene
1698
+ let columnSelectionDictionary = {};
1699
+ if (columns?.length > 0)
1700
+ for (let i = 0; i < columns?.length; i++)
1701
+ columnSelectionDictionary[columns[i]] = true;
1702
+ for (let i = 0; i < objs.length; i++) {
1703
+ let hds = this.parseAndGetHeaders(objs[i], columnSelectionDictionary);
1704
+ // Aggiungo gli header facendo in modo di non aggiungerne mai due uguali per non dover fare una distinct dopo
1705
+ // che costerebbe comunque risorse. Utilizzo un dizionario d'appoggio per lookup istantanei
1706
+ for (let k = 0; k < hds.length; k++) {
1707
+ if (!headersCache[hds[k].key]) {
1708
+ headersCache[hds[k].key] = true;
1709
+ headers.push(hds[k]);
1760
1710
  }
1761
- });
1762
- return;
1763
- }
1764
- if (window.clipboardData) {
1765
- console.log("[@esfaenza/extensions] Found clipboardData");
1766
- let data = window.clipboardData.getData("Text");
1767
- this.doClipboardDataGet(data, style, valueFoundCallback);
1711
+ }
1768
1712
  }
1769
- else if (window.navigator.clipboard) {
1770
- console.log("[@esfaenza/extensions] Found navigator clipboard");
1771
- window.navigator.permissions.query({ name: 'clipboard-read' }).then(result => {
1772
- if (!(result.state === 'granted' || result.state === 'prompt')) {
1773
- console.error("[@esfaenza/extensions] Clipboard permission not granted");
1774
- if (valueFoundCallback)
1775
- valueFoundCallback([]);
1776
- return;
1713
+ if (!columns || columns.length == 0)
1714
+ return headers.sort((a, b) => a.order - b.order);
1715
+ else {
1716
+ // Se mi arriva la lista di colonne non mi dà solo la visibilità, ma anche l'ordinamento
1717
+ // le esporto di conseguenza
1718
+ let orderedHeaders = [];
1719
+ for (let i = 0; i < columns.length; i++) {
1720
+ let thisId = columns[i];
1721
+ for (let i = 0; i < headers.length; i++) {
1722
+ if (headers[i].propKey == thisId) {
1723
+ orderedHeaders.push(headers[i]);
1724
+ break;
1725
+ }
1777
1726
  }
1778
- console.log("[@esfaenza/extensions] Clipboard permission granted, retrieving values");
1779
- window.navigator.clipboard.readText()
1780
- .then((t) => this.doClipboardDataGet(t, style, valueFoundCallback))
1781
- .catch((err) => this.msgService.simpleError(this.loc["Error during Clipboard content read operation"][LOCALE] + ": " + err));
1782
- });
1727
+ }
1728
+ return orderedHeaders;
1783
1729
  }
1784
1730
  }
1785
- /** @ignore */
1786
- doClipboardDataGet(clipboardText, style, valueFoundCallback) {
1787
- console.log("[@esfaenza/extensions] Retrieved clipboard values: " + clipboardText);
1788
- let value = style == "array" ? this.getClipboardLines(clipboardText) :
1789
- style == "matrix" ? this.getClipboardMatrix(clipboardText) : [];
1790
- console.log(`[@esfaenza/extensions] Adapted for ${style}: ${JSON.stringify(value)}`);
1791
- if (valueFoundCallback)
1792
- valueFoundCallback(value);
1793
- }
1794
- /**
1795
- * Ottiene il contenuto della clipboard diviso per righe (separate da newline)
1796
- *
1797
- * @param {string} data contenuto letto dalla clipboard
1798
- *
1799
- * @returns {string[]} Array contenente il testo preso dalla clipboard diviso per riga
1800
- */
1801
- getClipboardLines(data) {
1802
- let trimmedData = data.trim();
1803
- if (!trimmedData.includes("\r\n") && trimmedData.includes("\n"))
1804
- return trimmedData.split("\n");
1805
- return trimmedData.split("\r\n");
1806
- }
1807
- /**
1808
- * Ottiene il contenuto della clipboard diviso per righe (separate da newline) e colonne (separate da tab)
1809
- *
1810
- * @param {string} data contenuto letto dalla clipboard
1811
- *
1812
- * @returns {string[][]} Matrice contenente il testo preso dalla clipboard diviso per riga e colonna
1813
- */
1814
- getClipboardMatrix(data) {
1815
- var ret = [];
1816
- var rows = !data.includes("\r\n") && data.includes("\n") ? data.split("\n") : data.split("\r\n");
1817
- // A quanto pare ogni valore è separato da un \t... spero che sia uno standard di quando si copia da excel altrimenti ciao
1818
- for (let i = 0; i < rows.length; i++)
1819
- ret.push(rows[i].split('\t').map(t => t.trim()));
1820
- return ret;
1821
- }
1822
1731
  /**
1823
- * Metodo che copia un testo all'interno della clipboard
1732
+ * Data una lista di oggetti generici genera gli header per l'esportazione e integra ogni oggetto con le proprietà esportabili dalla libreria **@ctrl/ngx-csv**
1824
1733
  *
1825
- * @param {string} text Testo da inserire nella clipboard
1826
- */
1827
- async copyTextToClipboard(text) {
1828
- let LOCALE = this.locProvider ? await this.locProvider.Locale.pipe(first()).toPromise() : 'it-IT';
1829
- var textArea = document.createElement("textarea");
1830
- //
1831
- // *** This styling is an extra step which is likely not required. ***
1832
- //
1833
- // Why is it here? To ensure:
1834
- // 1. the element is able to have focus and selection.
1835
- // 2. if element was to flash render it has minimal visual impact.
1836
- // 3. less flakyness with selection and copying which **might** occur if
1837
- // the textarea element is not visible.
1838
- //
1839
- // The likelihood is the element won't even render, not even a flash,
1840
- // so some of these are just precautions. However in IE the element
1841
- // is visible whilst the popup box asking the user for permission for
1842
- // the web page to copy to the clipboard.
1843
- //
1844
- // Place in top-left corner of screen regardless of scroll position.
1845
- textArea.style.position = "fixed";
1846
- textArea.style.top = "0";
1847
- textArea.style.left = "0";
1848
- // Ensure it has a small width and height. Setting to 1px / 1em
1849
- // doesn't work as this gives a negative w/h on some browsers.
1850
- textArea.style.width = "2em";
1851
- textArea.style.height = "2em";
1852
- // We don't need padding, reducing the size if it does flash render.
1853
- textArea.style.padding = "0";
1854
- // Clean up any borders.
1855
- textArea.style.border = "none";
1856
- textArea.style.outline = "none";
1857
- textArea.style.boxShadow = "none";
1858
- // Avoid flash of white box if rendered for any reason.
1859
- textArea.style.background = "transparent";
1860
- textArea.value = text;
1861
- document.body.appendChild(textArea);
1862
- textArea.focus();
1863
- textArea.select();
1864
- try {
1865
- var successful = document.execCommand("copy");
1866
- if (!successful)
1867
- this.msgService.simpleError(this.loc["Generic error during 'copy' command execution"][LOCALE]);
1868
- }
1869
- catch (err) {
1870
- this.msgService.simpleError(this.loc["Error during Clipboard content copy operation"][LOCALE] + ": " + err);
1871
- }
1872
- document.body.removeChild(textArea);
1873
- }
1874
- }
1875
- ClipboardService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ClipboardService, deps: [{ token: MessageService }, { token: i1.BaseLocalization, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
1876
- ClipboardService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ClipboardService, providedIn: "root" });
1877
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ClipboardService, decorators: [{
1878
- type: Injectable,
1879
- args: [{ providedIn: "root" }]
1880
- }], ctorParameters: function () { return [{ type: MessageService }, { type: i1.BaseLocalization, decorators: [{
1881
- type: Optional
1882
- }] }]; } });
1883
-
1884
- // Angular
1885
- /**
1886
- * Service che fornisce alcuni semplici funzioni di Hashing / GUID / ecc...
1887
- */
1888
- class HashingService {
1889
- constructor() {
1890
- /**
1891
- * Blacklist dei tipi da ignorare quando si effettua l'hashing degli oggetti
1892
- */
1893
- this.objBlacklist = {
1894
- "NgForm": true, "ElementRef": true, "ExtensionsService": true, "ToastrService": true, "LocaleService": true, "AppState": true, "Router": true,
1895
- "ActivatedRoute": true, "HTTPService": true, "Location": true, "CanvasComponent": true, "ModalDirective": true, "ChangeDetectorRef": true,
1896
- "DateService": true, "EventEmitter": true, "ViewRef_": true, "Subscriber": true, "ItemLocalization": true
1897
- };
1898
- /**
1899
- * Array dei possibili valori di un simbolo esadecimale
1900
- */
1901
- this.hex_chr = '0123456789abcdef'.split('');
1734
+ * @param {GenericItem[]} objs Oggetti generici da esportare
1735
+ * @param {CsvHeaders[]} columns Colonne richieste dall'esportazione
1736
+ *
1737
+ * @returns {CsvHeaders[]} Header di esportazione già ordinati correttamente
1738
+ */
1739
+ setupForGenericExport(objs, columns) {
1740
+ let headers = [];
1741
+ if (!objs || objs.length == 0)
1742
+ return headers;
1743
+ // Devo per forza farlo per tutti gli oggetti dato che devo esporre le proprietà che mi servono da esportare
1744
+ objs.forEach((obj, index) => {
1745
+ if (index == 0)
1746
+ headers = this.parseAndGetGenericHeaders(obj, columns);
1747
+ else
1748
+ this.parseAndGetGenericHeaders(obj, columns);
1749
+ });
1750
+ return headers;
1902
1751
  }
1903
1752
  /**
1904
- * Generazione di un GUID pseudo-univoco
1753
+ * Dato un oggetto generico genera gli header per l'esportazione e lo integra con le proprietà esportabili dalla libreria **@ctrl/ngx-csv**
1905
1754
  *
1906
- * @returns {string} il GUID generato
1755
+ * Metodo interno richiamato da **setupForGenericExport**
1756
+ *
1757
+ * @param {GenericItem} obj Oggetto generico da esportare
1758
+ * @param {CsvColumn[]} columns Colonne richieste dall'esportazione
1759
+ *
1760
+ * @returns {CsvHeaders[]} Header di esportazione già ordinati correttamente
1907
1761
  */
1908
- getGUID() {
1909
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
1910
- var r = Math.random() * 16 | 0, v = c == "x" ? r : (r & 0x3 | 0x8);
1911
- return v.toString(16);
1762
+ parseAndGetGenericHeaders(obj, columns) {
1763
+ if (!obj.properties)
1764
+ return null;
1765
+ var headers = [];
1766
+ //Miracle incoming
1767
+ columns.forEach(t => {
1768
+ var propValue = obj.properties[t.key];
1769
+ Object.defineProperty(obj, t.key + "_exp", { value: propValue, writable: false, enumerable: true });
1770
+ headers.push({ label: t.label, key: t.key + "_exp", order: t.order, type: t.type, propKey: null });
1912
1771
  });
1772
+ //Tirati fuori tutti gli header faccio sort sull'ordinamento
1773
+ return headers.sort((a, b) => { return a.order - b.order; });
1913
1774
  }
1914
1775
  /**
1915
- * Calcolo dell'hash su un oggetto
1776
+ * Dato un oggetto genera gli header per l'esportazione e lo integra con le proprietà esportabili dalla libreria **@ctrl/ngx-csv**
1916
1777
  *
1917
- * @param {any} o Oggetto di cui calcolare l'hash
1918
- * @param {number} level Livello di ricorsione nel caso venga effettuato l'hash di un oggetto che contiene altri oggetti
1919
- * @param {boolean} navigateFullDepth Indica se navigare l'oggetto per l'intera lunghezza. In caso contrario si ferma al secondo livello
1778
+ * Metodo interno richiamato da **setupForExport**
1920
1779
  *
1921
- * @returns {string} Hash generato per l'oggetto in questione
1780
+ * @param {any} obj Oggetto generico da esportare
1781
+ *
1782
+ * @returns {CsvHeaders[]} Header di esportazione già ordinati correttamente
1922
1783
  */
1923
- hashObject(o, level = 0, navigateFullDepth = false, precise = false) {
1924
- var strDef = this.stringify(o, level, navigateFullDepth);
1925
- var hash = precise ? this.md5(strDef) : this.simpleHash(strDef);
1926
- return hash;
1784
+ parseAndGetHeaders(obj, columnsSelection) {
1785
+ var headers = [];
1786
+ // Miracle incoming
1787
+ let exportProps = obj[exportList] || [];
1788
+ let loc = obj[locProperty] ? this.lc.generateFromType(obj[locProperty]) : null;
1789
+ if (exportProps.length == 0)
1790
+ console.warn("[@esfaenza/extensions] Nessuna colonna configurata da esportare!");
1791
+ for (let i = 0; i < exportProps.length; i++) {
1792
+ let prop = exportProps[i];
1793
+ let propBase = "";
1794
+ let toCall;
1795
+ if (prop.endsWith(listCsvHdrPrefix)) {
1796
+ propBase = prop.replace(listCsvHdrPrefix, '');
1797
+ toCall = this.parseList.bind(this);
1798
+ }
1799
+ else if (prop.endsWith(dictionaryCsvHdrPrefix)) {
1800
+ propBase = prop.replace(dictionaryCsvHdrPrefix, '');
1801
+ toCall = this.parseDictionary.bind(this);
1802
+ }
1803
+ else if (prop.endsWith(csvVisPrefix)) {
1804
+ propBase = prop.replace(csvVisPrefix, '');
1805
+ if (typeof obj[propBase + csvValueNavigator] !== "undefined")
1806
+ toCall = this.parseObject.bind(this);
1807
+ else
1808
+ toCall = this.parseProperty.bind(this);
1809
+ }
1810
+ if (toCall)
1811
+ toCall(obj, propBase, headers, columnsSelection, loc);
1812
+ }
1813
+ return headers;
1927
1814
  }
1928
1815
  /**
1929
- * Hash più semplice e più veloce dell'md5, ma meno sicuro
1816
+ * Setup per l'esportazione di una singola proprietà.
1817
+ * Viene generato l'header e la proprietà relativa al valore formattato o no
1930
1818
  *
1931
- * Vedi https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript
1819
+ * @param {any} obj Oggetto di cui esportare la proprietà **prop**
1820
+ * @param {string} prop Proprietà da esportare
1821
+ * @param {CsvHeaders} headers Contenitore degli header, verrà riempito da questa funzione
1822
+ * @param {LocalizationService} loc Servizio di localizzazione che traduce tutti i nomi che può
1823
+ */
1824
+ parseProperty(obj, prop, headers, columnsSelection, loc) {
1825
+ let toEmit = obj[prop + csvVisPrefix];
1826
+ let format = obj[prop + csvFormatPrefix];
1827
+ let propKey = obj[prop + csvPropKey];
1828
+ if (propKey && !columnsSelection[propKey] && Object.keys(columnsSelection).length > 0) {
1829
+ console.log("[@esfaenza/extensions] Colonna da non esportare: " + propKey);
1830
+ return;
1831
+ }
1832
+ let text = obj[prop + csvHdrPrefix];
1833
+ let label = loc && text ? loc.loc(text) : text || "";
1834
+ let order = obj[prop + csvOrdPrefix];
1835
+ if (!toEmit)
1836
+ return;
1837
+ // Se non ho un formato esporto direttamente
1838
+ if (!format) {
1839
+ // Se è un formato data mi assicuro di non stampare mai una data 00:00:00 altrimenti in esportazione viene uno schifo
1840
+ let val = obj[prop] ? this.dates.trimSeconds(obj[prop].toString()) : "";
1841
+ let key = prop + "_nofmt";
1842
+ Object.defineProperty(obj, key, { value: val, writable: false, enumerable: true });
1843
+ headers.push({ label, key, order, type: "string", propKey });
1844
+ }
1845
+ else {
1846
+ let key = prop + "_fmt";
1847
+ // Caso formato numerico
1848
+ if (format == "F") {
1849
+ // Check considerando la possibilità di zeri
1850
+ let val = obj[prop] != null ? obj[prop].toString() : "";
1851
+ // Elimino tutte le virgole (indicatori di migliaia per la culture default en-US)
1852
+ val = val.replace(/,/, "");
1853
+ // Il singolo punto che c'è, se presente (separatore decimali) lo trasformo in virgola
1854
+ let valConverted = val.replace(".", ",");
1855
+ Object.defineProperty(obj, key, { value: valConverted, writable: false, enumerable: true });
1856
+ headers.push({ label, key, order, type: "number", propKey });
1857
+ }
1858
+ else {
1859
+ // Se ho un formato data trasformo in dayjs, formatto ed esporto
1860
+ // Per la trasformazione in dayjs provo prima a passargli la stringa di netto, sperando la riconosca
1861
+ // Se non funziona provo a definirgli la formattazione standard del metering per quel linguaggio
1862
+ let val = this.dates.getFormatted(obj[prop], format.length <= 10, format.length > 16);
1863
+ Object.defineProperty(obj, key, { value: val ?? "", writable: false, enumerable: true });
1864
+ headers.push({ label, key, order, type: "date", propKey });
1865
+ }
1866
+ }
1867
+ }
1868
+ /**
1869
+ * Setup per l'esportazione di una singola proprietà da un oggetto.
1870
+ * Viene generato l'header e la proprietà relativa al valore formattato o no.
1932
1871
  *
1933
- * @param {string} str Stringa di cui calcolare l'hash
1872
+ * Per ottenere il valore e l'header della proprietà vengono utilizzati i navigatori auto-generati nel decoratore **ExportAs**
1873
+ *
1874
+ * @param {any} obj Oggetto di cui esportare la proprietà **prop**
1875
+ * @param {string} prop Proprietà da esportare
1876
+ * @param {CsvHeaders} headers Contenitore degli header, verrà riempito da questa funzione
1877
+ * @param {LocalizationService} loc Servizio di localizzazione che traduce tutti i nomi che può
1934
1878
  */
1935
- simpleHash(str, seed = 0) {
1936
- let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
1937
- for (let i = 0, ch; i < str.length; i++) {
1938
- ch = str.charCodeAt(i);
1939
- h1 = Math.imul(h1 ^ ch, 2654435761);
1940
- h2 = Math.imul(h2 ^ ch, 1597334677);
1879
+ parseObject(obj, prop, headers, columnsSelection, loc) {
1880
+ //se questa proprietà ha un navigator significa che deriva da un oggetto interno, recupero il valore in questa fase dato che prima non ce l'ho
1881
+ let valuenavigator = obj[prop + csvValueNavigator];
1882
+ //Es. di valuenavigator obj.subobj.subsubobj.property
1883
+ let jmps = valuenavigator.split(".");
1884
+ // Localizzazione presa dalla classe base se c'è, altrimenti dalla classe interna (cioè dal primo saltino)
1885
+ if (!loc) {
1886
+ let type = obj[prop + csvValueType];
1887
+ let proto = new type();
1888
+ loc = proto[locProperty] ? this.lc.generateFromType(proto[locProperty]) : null;
1941
1889
  }
1942
- h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
1943
- h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
1944
- return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString();
1890
+ //Mi clono l'oggetto originale per non uccidergli i riferimenti
1891
+ let clone = JSON.parse(JSON.stringify(obj));
1892
+ //Salto ricorsivamente su me stesso per arrivare alla proprietà
1893
+ //Salto 1 > diventa obj
1894
+ //Salto 2 > diventa obj.subobj
1895
+ //ecc...
1896
+ jmps.forEach(pp => { clone = clone[pp]; });
1897
+ //Valore finale :D
1898
+ let value = clone;
1899
+ let text = obj[prop + csvHdrPrefix];
1900
+ let label = loc && text ? loc.loc(text) : text || "";
1901
+ let order = obj[prop + csvOrdPrefix];
1902
+ //Se per questa proprietà ho un formato lo applico
1903
+ let format = obj[prop + csvFormatPrefix];
1904
+ let type = "string";
1905
+ if (format == "F") {
1906
+ let val = value.toString();
1907
+ val = val.replace(/,/, "");
1908
+ value = val.replace(".", ",");
1909
+ type = "number";
1910
+ }
1911
+ else if (format) {
1912
+ value = this.dates.getFormatted(value, format.length <= 10, format.length > 16);
1913
+ type = "date";
1914
+ }
1915
+ Object.defineProperty(obj, prop, { value: value ?? "", writable: false, enumerable: true });
1916
+ headers.push({ label, key: prop, order, type, propKey: null });
1945
1917
  }
1946
1918
  /**
1947
- * Genera una stringa che identifica univocamente l'oggetto in questione
1919
+ * Setup per l'esportazione di una lista di valori pivottati dinamicamente:
1948
1920
  *
1949
- * @param {any} o Oggetto di cui calcolare la stringa univoca
1950
- * @param {number} level Livello di ricorsione nel caso venga effettuato l'hash di un oggetto che contiene altri oggetti
1951
- * @param {boolean} navigateFullDepth Indica se navigare l'oggetto per l'intera lunghezza. In caso contrario si ferma al secondo livello
1921
+ * => Recupero il valore utilizzando i navigatori
1922
+ *
1923
+ * => Recupero l'header utilizzando i navigatori
1924
+ *
1925
+ * => Con il valore ci creo la property
1926
+ *
1927
+ * => Con l'header e il riferimento alla property appena creata creo un record negli header da esportare
1928
+ *
1929
+ * @param {any} obj Oggetto di cui esportare la proprietà **prop**
1930
+ * @param {string} prop Proprietà da esportare
1931
+ * @param {CsvHeaders} headers Contenitore degli header, verrà riempito da questa funzione
1932
+ * @param {LocalizationService} loc Servizio di localizzazione che traduce tutti i nomi che può
1952
1933
  */
1953
- stringify(o, level, navigateFullDepth) {
1954
- var i, r;
1955
- if (o === null)
1956
- return "n";
1957
- if (o === true)
1958
- return "t";
1959
- if (o === false)
1960
- return "f";
1961
- if (o instanceof Date)
1962
- return 'd:' + o.valueOf().toString();
1963
- i = typeof o;
1964
- if (i === "string")
1965
- return "s:" + o;
1966
- if (i === "number")
1967
- return "n:" + o;
1968
- if (o instanceof Function)
1969
- return "m:" + o.toString();
1970
- if (o instanceof Array) {
1971
- r = [];
1972
- for (i = 0; i < o.length; i++) {
1973
- let res = this.stringify(o[i], level, navigateFullDepth);
1974
- if (res)
1975
- r.push(res);
1934
+ parseList(obj, prop, headers, columnsSelection, loc) {
1935
+ let headernavigator = obj[prop + listCsvHdrPrefix];
1936
+ let valuenavigator = obj[prop + listCsvValPrefix];
1937
+ let valueformat = obj[prop + listCsvValFormat];
1938
+ let order = obj[prop + csvOrdPrefix];
1939
+ var jumps, tmpRes;
1940
+ var objs = obj[prop];
1941
+ for (let idx = 0; idx < objs.length; idx++) {
1942
+ let listitem = objs[idx];
1943
+ var headersplit = headernavigator.split(" ");
1944
+ var label = "";
1945
+ // Per l'header si considera a se stante ogni pezzo separato da spazio per fare le concatenazioni
1946
+ headersplit.forEach(pr => {
1947
+ jumps = pr.split(".");
1948
+ tmpRes = JSON.parse(JSON.stringify(listitem));
1949
+ jumps.forEach(pp => { tmpRes = tmpRes[pp]; });
1950
+ let localized = !!loc ? loc.loc(tmpRes) : tmpRes;
1951
+ if (!label)
1952
+ label = localized;
1953
+ else
1954
+ label += " " + localized;
1955
+ });
1956
+ jumps = valuenavigator.split(".");
1957
+ tmpRes = JSON.parse(JSON.stringify(listitem));
1958
+ jumps.forEach(pp => { tmpRes = tmpRes[pp]; });
1959
+ let value = tmpRes;
1960
+ let type = "string";
1961
+ if (valueformat == "F") {
1962
+ let val = value != null ? value.toString() : "";
1963
+ val = val.replace(/,/, "");
1964
+ value = val.replace(".", ",");
1965
+ type = "number";
1976
1966
  }
1977
- return r.length > 0 ? "a:" + r.join(";") : "";
1978
- }
1979
- r = [];
1980
- //Se è oggetto, escludo tutti quelli di sistema/inutili
1981
- if (o) {
1982
- var name = o.__proto__.constructor.name;
1983
- if (!this.objBlacklist[name]) {
1984
- for (i in o) {
1985
- if (o.hasOwnProperty(i) && (level <= 2 || navigateFullDepth)) {
1986
- let res = this.stringify(o[i], level + 1, navigateFullDepth);
1987
- if (res)
1988
- r.push(i + ":" + res);
1989
- }
1990
- }
1967
+ else if (valueformat) {
1968
+ value = this.dates.getFormatted(obj[prop], valueformat.length <= 10, valueformat.length > 16);
1969
+ type = "date";
1991
1970
  }
1971
+ Object.defineProperty(obj, prop + idx, { value: value ?? "", writable: false });
1972
+ headers.push({ label, key: prop + idx, order: order + idx, type, propKey: null });
1992
1973
  }
1993
- return r.length > 0 ? "o:" + r.join(";") : "";
1994
1974
  }
1995
1975
  /**
1996
- * Data una stringa restituisce l'md5
1976
+ * Setup per l'esportazione di una lista di valori pivottati dinamicamente:
1997
1977
  *
1998
- * @param {string} s Stringa di cui calcolare l'md5
1999
- * @returns {string} md5 della stringa **s**
2000
- */
2001
- md5(s) {
2002
- return this.hex(this.md51(s));
2003
- }
2004
- /**
2005
- * @ignore
1978
+ * => Recupero il valore utilizzando i navigatori
2006
1979
  *
2007
- * Metodo di utilità per il calcolo dell'md5
2008
- */
2009
- md5cycle(x, k) {
2010
- var a = x[0], b = x[1], c = x[2], d = x[3];
2011
- a = this.ff(a, b, c, d, k[0], 7, -680876936);
2012
- d = this.ff(d, a, b, c, k[1], 12, -389564586);
2013
- c = this.ff(c, d, a, b, k[2], 17, 606105819);
2014
- b = this.ff(b, c, d, a, k[3], 22, -1044525330);
2015
- a = this.ff(a, b, c, d, k[4], 7, -176418897);
2016
- d = this.ff(d, a, b, c, k[5], 12, 1200080426);
2017
- c = this.ff(c, d, a, b, k[6], 17, -1473231341);
2018
- b = this.ff(b, c, d, a, k[7], 22, -45705983);
2019
- a = this.ff(a, b, c, d, k[8], 7, 1770035416);
2020
- d = this.ff(d, a, b, c, k[9], 12, -1958414417);
2021
- c = this.ff(c, d, a, b, k[10], 17, -42063);
2022
- b = this.ff(b, c, d, a, k[11], 22, -1990404162);
2023
- a = this.ff(a, b, c, d, k[12], 7, 1804603682);
2024
- d = this.ff(d, a, b, c, k[13], 12, -40341101);
2025
- c = this.ff(c, d, a, b, k[14], 17, -1502002290);
2026
- b = this.ff(b, c, d, a, k[15], 22, 1236535329);
2027
- a = this.gg(a, b, c, d, k[1], 5, -165796510);
2028
- d = this.gg(d, a, b, c, k[6], 9, -1069501632);
2029
- c = this.gg(c, d, a, b, k[11], 14, 643717713);
2030
- b = this.gg(b, c, d, a, k[0], 20, -373897302);
2031
- a = this.gg(a, b, c, d, k[5], 5, -701558691);
2032
- d = this.gg(d, a, b, c, k[10], 9, 38016083);
2033
- c = this.gg(c, d, a, b, k[15], 14, -660478335);
2034
- b = this.gg(b, c, d, a, k[4], 20, -405537848);
2035
- a = this.gg(a, b, c, d, k[9], 5, 568446438);
2036
- d = this.gg(d, a, b, c, k[14], 9, -1019803690);
2037
- c = this.gg(c, d, a, b, k[3], 14, -187363961);
2038
- b = this.gg(b, c, d, a, k[8], 20, 1163531501);
2039
- a = this.gg(a, b, c, d, k[13], 5, -1444681467);
2040
- d = this.gg(d, a, b, c, k[2], 9, -51403784);
2041
- c = this.gg(c, d, a, b, k[7], 14, 1735328473);
2042
- b = this.gg(b, c, d, a, k[12], 20, -1926607734);
2043
- a = this.hh(a, b, c, d, k[5], 4, -378558);
2044
- d = this.hh(d, a, b, c, k[8], 11, -2022574463);
2045
- c = this.hh(c, d, a, b, k[11], 16, 1839030562);
2046
- b = this.hh(b, c, d, a, k[14], 23, -35309556);
2047
- a = this.hh(a, b, c, d, k[1], 4, -1530992060);
2048
- d = this.hh(d, a, b, c, k[4], 11, 1272893353);
2049
- c = this.hh(c, d, a, b, k[7], 16, -155497632);
2050
- b = this.hh(b, c, d, a, k[10], 23, -1094730640);
2051
- a = this.hh(a, b, c, d, k[13], 4, 681279174);
2052
- d = this.hh(d, a, b, c, k[0], 11, -358537222);
2053
- c = this.hh(c, d, a, b, k[3], 16, -722521979);
2054
- b = this.hh(b, c, d, a, k[6], 23, 76029189);
2055
- a = this.hh(a, b, c, d, k[9], 4, -640364487);
2056
- d = this.hh(d, a, b, c, k[12], 11, -421815835);
2057
- c = this.hh(c, d, a, b, k[15], 16, 530742520);
2058
- b = this.hh(b, c, d, a, k[2], 23, -995338651);
2059
- a = this.ii(a, b, c, d, k[0], 6, -198630844);
2060
- d = this.ii(d, a, b, c, k[7], 10, 1126891415);
2061
- c = this.ii(c, d, a, b, k[14], 15, -1416354905);
2062
- b = this.ii(b, c, d, a, k[5], 21, -57434055);
2063
- a = this.ii(a, b, c, d, k[12], 6, 1700485571);
2064
- d = this.ii(d, a, b, c, k[3], 10, -1894986606);
2065
- c = this.ii(c, d, a, b, k[10], 15, -1051523);
2066
- b = this.ii(b, c, d, a, k[1], 21, -2054922799);
2067
- a = this.ii(a, b, c, d, k[8], 6, 1873313359);
2068
- d = this.ii(d, a, b, c, k[15], 10, -30611744);
2069
- c = this.ii(c, d, a, b, k[6], 15, -1560198380);
2070
- b = this.ii(b, c, d, a, k[13], 21, 1309151649);
2071
- a = this.ii(a, b, c, d, k[4], 6, -145523070);
2072
- d = this.ii(d, a, b, c, k[11], 10, -1120210379);
2073
- c = this.ii(c, d, a, b, k[2], 15, 718787259);
2074
- b = this.ii(b, c, d, a, k[9], 21, -343485551);
2075
- x[0] = this.add32(a, x[0]);
2076
- x[1] = this.add32(b, x[1]);
2077
- x[2] = this.add32(c, x[2]);
2078
- x[3] = this.add32(d, x[3]);
2079
- }
2080
- /**
2081
- * @ignore
1980
+ * => Recupero l'header utilizzando i navigatori
2082
1981
  *
2083
- * Metodo di utilità per il calcolo dell'md5
1982
+ * => Con il valore ci creo la property
1983
+ *
1984
+ * => Con l'header e il riferimento alla property appena creata creo un record negli header da esportare
1985
+ *
1986
+ * @param {any} obj Oggetto di cui esportare la proprietà **prop**
1987
+ * @param {string} prop Proprietà da esportare
1988
+ * @param {CsvHeaders} headers Contenitore degli header, verrà riempito da questa funzione
1989
+ * @param {LocalizationService} loc Servizio di localizzazione che traduce tutti i nomi che può
2084
1990
  */
2085
- cmn(q, a, b, x, s, t) {
2086
- a = this.add32(this.add32(a, q), this.add32(x, t));
2087
- return this.add32((a << s) | (a >>> (32 - s)), b);
1991
+ parseDictionary(obj, prop, headers, columnsSelection, loc) {
1992
+ let headernavigator = obj[prop + dictionaryCsvHdrPrefix];
1993
+ let valuenavigator = obj[prop + dictionaryCsvValPrefix];
1994
+ let order = obj[prop + csvOrdPrefix];
1995
+ var jumps, tmpRes;
1996
+ var objs = obj[prop];
1997
+ for (let idx = 0; idx < objs.length; idx++) {
1998
+ let listitem = objs[idx];
1999
+ var headersplit = headernavigator.split(" ");
2000
+ var label = "";
2001
+ headersplit.forEach(pr => {
2002
+ jumps = pr.split(".");
2003
+ tmpRes = JSON.parse(JSON.stringify(listitem));
2004
+ jumps.forEach(pp => { tmpRes = tmpRes[pp]; });
2005
+ if (!label)
2006
+ label = !!loc ? loc.loc(tmpRes) : tmpRes;
2007
+ else
2008
+ label += " " + !!loc ? loc.loc(tmpRes) : tmpRes;
2009
+ });
2010
+ var valuesplit = valuenavigator.split(",");
2011
+ valuesplit.forEach((t, idxinternal) => {
2012
+ var navig = t.split("-")[1];
2013
+ var desc = t.split("-")[0];
2014
+ jumps = navig.split(".");
2015
+ tmpRes = JSON.parse(JSON.stringify(listitem));
2016
+ jumps.forEach(pp => { tmpRes = tmpRes[pp]; });
2017
+ let value = tmpRes;
2018
+ let propname = prop + idx.toString() + idxinternal.toString();
2019
+ Object.defineProperty(obj, propname, { value: value ?? "", writable: false });
2020
+ headers.push({ label: label + " " + !!loc ? loc.loc(desc) : desc, key: propname, order: order + idx, type: 'string', propKey: null });
2021
+ });
2022
+ }
2088
2023
  }
2089
2024
  /**
2090
- * @ignore
2091
- *
2092
- * Metodo di utilità per il calcolo dell'md5
2025
+ * Effettua l'esportazione in file CSV
2093
2026
  */
2094
- ff(a, b, c, d, x, s, t) {
2095
- return this.cmn((b & c) | ((~b) & d), a, b, x, s, t);
2027
+ exportCSV(fn, headers, data) {
2028
+ let csvData = '', row = '', sep = ';';
2029
+ for (let i = 0; i < headers.length; i++) {
2030
+ let h = headers[i];
2031
+ row += `${row != '' ? sep : ''}"${h.label}"`;
2032
+ }
2033
+ csvData += row + '\r\n';
2034
+ for (let i = 0; i < data.length; i++) {
2035
+ row = '';
2036
+ let item = data[i];
2037
+ for (let j = 0; j < headers.length; j++) {
2038
+ let val = item[headers[j].key];
2039
+ row += `${row != '' ? sep : ''}"${val}"`;
2040
+ }
2041
+ csvData += row + '\r\n';
2042
+ }
2043
+ var BOM = new Uint8Array([0xEF, 0xBB, 0xBF]);
2044
+ var blob = new Blob([BOM, csvData], { type: 'text/csv' });
2045
+ var objectUrl = URL.createObjectURL(blob);
2046
+ this.utiExts.fileDownload(objectUrl, fn.endsWith('.xlsx') ? fn.replace('.xlsx', '.csv') : fn.endsWith('.csv') ? fn : fn + ".csv");
2047
+ }
2048
+ /** Effettua l'esportazione del file Excel basandosi sul modulo **ExcelJS**, sugli header **headers** e sui dati **data** */
2049
+ async exportExcel(fn, headers, data) {
2050
+ try {
2051
+ this.ExcelJS = this.ExcelJS || await import('exceljs');
2052
+ }
2053
+ catch {
2054
+ throw "Impossibile caricare la libreria per l'esportazione in Excel";
2055
+ }
2056
+ let iFix = 1;
2057
+ let workbook = new this.ExcelJS.Workbook();
2058
+ workbook.creator = "Ema's big Es-Table";
2059
+ workbook.created = new Date();
2060
+ let sheet = workbook.addWorksheet('Data');
2061
+ let header = sheet.getRow(1);
2062
+ header.font = { bold: true };
2063
+ headers = headers.sort((a, b) => a.order - b.order);
2064
+ for (let i = 0; i < headers.length; i++) {
2065
+ let h = headers[i];
2066
+ header.getCell(i + iFix).value = h.label;
2067
+ }
2068
+ for (let i = 0; i < data.length; i++) {
2069
+ let row = sheet.getRow(i + iFix + 1);
2070
+ let item = data[i];
2071
+ for (let i = 0; i < headers.length; i++) {
2072
+ let h = headers[i];
2073
+ let cell = row.getCell(i + 1);
2074
+ let val = item[h.key];
2075
+ if (!val) {
2076
+ cell.value = "";
2077
+ continue;
2078
+ }
2079
+ switch (h.type) {
2080
+ case 'date':
2081
+ // ExcelJS va di default in UTC quindi rischierebbe di tirare giù 2 ore ad ogni esportazione
2082
+ // Bisogna aggiungere l'utc offset alla data attuale
2083
+ let date = this.dates.getDateConvertion(val);
2084
+ if (date) {
2085
+ let correctedDate = date.add(date.utcOffset(), 'minute');
2086
+ cell.value = correctedDate.toDate();
2087
+ cell.numFmt = val.length > 10 ? 'dd/mm/yyyy h:m:s' : '';
2088
+ }
2089
+ break;
2090
+ case 'number':
2091
+ let converted = parseFloat(val.replace(',', '.'));
2092
+ cell.value = isNaN(converted) ? "" : converted;
2093
+ break;
2094
+ default:
2095
+ cell.value = val;
2096
+ break;
2097
+ }
2098
+ }
2099
+ }
2100
+ let buffer = await workbook.xlsx.writeBuffer();
2101
+ let blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;" });
2102
+ let objectUrl = URL.createObjectURL(blob);
2103
+ this.utiExts.fileDownload(objectUrl, fn.endsWith('.csv') ? fn.replace('.csv', '.xlsx') : fn.endsWith('.xlsx') ? fn : fn + ".xlsx");
2096
2104
  }
2097
2105
  /**
2098
- * @ignore
2106
+ * Metodo che effettivamente genera gli header e i dati per l'esportazione con **ngx-csv**
2099
2107
  *
2100
- * Metodo di utilità per il calcolo dell'md5
2108
+ * @param {any[]} items Oggetti da esportare
2101
2109
  */
2102
- gg(a, b, c, d, x, s, t) {
2103
- return this.cmn((b & d) | (c & (~d)), a, b, x, s, t);
2110
+ export(items, format, fileName, type, columnsFilter, genericHeaders) {
2111
+ var createdItems = items.map(t => {
2112
+ let tmp = new type();
2113
+ for (let property in t)
2114
+ tmp[property] = t[property];
2115
+ return tmp;
2116
+ });
2117
+ let headers = genericHeaders ? this.setupForGenericExport(createdItems, genericHeaders) : this.setupForExport(createdItems, columnsFilter);
2118
+ (format == "CSV" ? this.exportCSV : this.exportExcel).bind(this)(fileName, headers, createdItems);
2104
2119
  }
2120
+ }
2121
+ ExportService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ExportService, deps: [{ token: DateService }, { token: UtilityService }, { token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Injectable });
2122
+ ExportService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ExportService, providedIn: "root" });
2123
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ExportService, decorators: [{
2124
+ type: Injectable,
2125
+ args: [{ providedIn: "root" }]
2126
+ }], ctorParameters: function () { return [{ type: DateService }, { type: UtilityService }, { type: i1.LocalizationService }]; } });
2127
+
2128
+ // Angular
2129
+ /**
2130
+ * Service che fornisce un accesso base in lettura/scrittura sulla clipboard
2131
+ */
2132
+ class ClipboardService {
2105
2133
  /**
2106
- * @ignore
2134
+ * Costruttore
2107
2135
  *
2108
- * Metodo di utilità per il calcolo dell'md5
2109
- */
2110
- hh(a, b, c, d, x, s, t) {
2111
- return this.cmn(b ^ c ^ d, a, b, x, s, t);
2112
- }
2113
- /**
2114
2136
  * @ignore
2115
- *
2116
- * Metodo di utilità per il calcolo dell'md5
2117
2137
  */
2118
- ii(a, b, c, d, x, s, t) {
2119
- return this.cmn(c ^ (b | (~d)), a, b, x, s, t);
2138
+ constructor(msgService, locProvider) {
2139
+ this.msgService = msgService;
2140
+ this.locProvider = locProvider;
2141
+ /**
2142
+ * Oggetto statico di localizzazione per i messaggi di questa Service
2143
+ */
2144
+ this.loc = {
2145
+ "Unfortunately Firefox doesn't yet support direct Clipboard access if not via extensions, Please use Chrome to do this operation": {
2146
+ 'en-US': "Unfortunately Firefox doesn't yet support direct Clipboard access if not via extensions, Please use Chrome to do this operation",
2147
+ 'it-IT': "Mi dispiace ma Firefox non supporta l'accesso diretto alla Clipboard, se non attraverso le estensioni. Si prega di usare Chrome"
2148
+ },
2149
+ "Generic error during 'copy' command execution": {
2150
+ 'en-US': "Generic error during 'copy' command execution",
2151
+ 'it-IT': "Errore generico durante l'esecuzione del comando 'copy'"
2152
+ },
2153
+ "Error during Clipboard content read operation": {
2154
+ 'en-US': "Error during Clipboard content read operation",
2155
+ 'it-IT': "Errore nella lettura del contenuto della Clipboard"
2156
+ },
2157
+ "Error during Clipboard content copy operation": {
2158
+ 'en-US': "Error during Clipboard content copy operation",
2159
+ 'it-IT': "Errore nella scrittura del contenuto nella Clipboard"
2160
+ },
2161
+ "Please insert your clipboard content": {
2162
+ 'en-US': "Please insert your clipboard content",
2163
+ 'it-IT': "Si prega di incollare il contenuto della Clipboard"
2164
+ },
2165
+ "User input required": {
2166
+ 'en-US': "User input required",
2167
+ 'it-IT': "Richiesto Input utente"
2168
+ },
2169
+ "Your current browser does not support reading from the clipboard directly. Please paste your clipboard's content in this Input field and confirm the operation": {
2170
+ 'en-US': "Your current browser does not support reading from the clipboard directly. Please paste your clipboard's content in this Input field and confirm the operation",
2171
+ 'it-IT': "Il browser corrente non supporta la lettura diretta dei dati della Clipboard, si prega di effettuare un'incolla (CTRL + V) nella casella di testo e confermare l'operazione"
2172
+ },
2173
+ "Confirm": {
2174
+ 'en-US': "Confirm",
2175
+ 'it-IT': "Conferma"
2176
+ },
2177
+ "Cancel": {
2178
+ 'en-US': "Cancel",
2179
+ 'it-IT': "Annulla"
2180
+ },
2181
+ };
2120
2182
  }
2121
2183
  /**
2122
- * @ignore
2184
+ * Prende il valore della clipboard.
2185
+ * Si può specificare se ci si aspetta una lista o una matrice di valori in modo da ricevere già un risultato utilizzabile
2123
2186
  *
2124
- * Metodo di utilità per il calcolo dell'md5
2187
+ * @param {'array' | 'matrix'} style Stile dell'output desiderato, se array o matrice
2188
+ * @param {Function} valueFoundCallback Callback che questa funzione chiamerà una volta ottenuto i valori richiesti dalla clipboard
2125
2189
  */
2126
- md51(s) {
2127
- var n = s.length, state = [1732584193, -271733879, -1732584194, 271733878], i;
2128
- for (i = 64; i <= s.length; i += 64)
2129
- this.md5cycle(state, this.md5blk(s.substring(i - 64, i)));
2130
- s = s.substring(i - 64);
2131
- var tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
2132
- for (i = 0; i < s.length; i++)
2133
- tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
2134
- tail[i >> 2] |= 0x80 << ((i % 4) << 3);
2135
- if (i > 55) {
2136
- this.md5cycle(state, tail);
2137
- for (i = 0; i < 16; i++)
2138
- tail[i] = 0;
2190
+ async getClipboard(style, valueFoundCallback) {
2191
+ let LOCALE = this.locProvider ? await this.locProvider.Locale.pipe(first()).toPromise() : 'it-IT';
2192
+ if (navigator.userAgent.indexOf("Firefox") != -1) {
2193
+ swal.fire({
2194
+ title: this.loc["User input required"][LOCALE],
2195
+ text: this.loc["Your current browser does not support reading from the clipboard directly. Please paste your clipboard's content in this Input field and confirm the operation"][LOCALE],
2196
+ input: 'textarea',
2197
+ icon: "warning",
2198
+ confirmButtonText: this.loc["Confirm"][LOCALE],
2199
+ cancelButtonText: this.loc["Cancel"][LOCALE],
2200
+ showCancelButton: true,
2201
+ customClass: {
2202
+ confirmButton: "btn btn-primary",
2203
+ cancelButton: "btn btn-secondary app-margin-right-15",
2204
+ container: "app-wrap",
2205
+ },
2206
+ reverseButtons: true,
2207
+ allowOutsideClick: false,
2208
+ inputValidator: (value) => {
2209
+ if (!value)
2210
+ return this.loc["Please insert your clipboard content"][LOCALE];
2211
+ }
2212
+ }).then(t => {
2213
+ if (t.isConfirmed) {
2214
+ console.log("[@esfaenza/extensions] Retrieving input data from user input");
2215
+ this.doClipboardDataGet(t.value, style, valueFoundCallback);
2216
+ }
2217
+ });
2218
+ return;
2219
+ }
2220
+ if (window.clipboardData) {
2221
+ console.log("[@esfaenza/extensions] Found clipboardData");
2222
+ let data = window.clipboardData.getData("Text");
2223
+ this.doClipboardDataGet(data, style, valueFoundCallback);
2224
+ }
2225
+ else if (window.navigator.clipboard) {
2226
+ console.log("[@esfaenza/extensions] Found navigator clipboard");
2227
+ window.navigator.permissions.query({ name: 'clipboard-read' }).then(result => {
2228
+ if (!(result.state === 'granted' || result.state === 'prompt')) {
2229
+ console.error("[@esfaenza/extensions] Clipboard permission not granted");
2230
+ if (valueFoundCallback)
2231
+ valueFoundCallback([]);
2232
+ return;
2233
+ }
2234
+ console.log("[@esfaenza/extensions] Clipboard permission granted, retrieving values");
2235
+ window.navigator.clipboard.readText()
2236
+ .then((t) => this.doClipboardDataGet(t, style, valueFoundCallback))
2237
+ .catch((err) => this.msgService.simpleError(this.loc["Error during Clipboard content read operation"][LOCALE] + ": " + err));
2238
+ });
2139
2239
  }
2140
- tail[14] = n * 8;
2141
- this.md5cycle(state, tail);
2142
- return state;
2143
2240
  }
2144
- /**
2145
- * @ignore
2146
- *
2147
- * Metodo di utilità per il calcolo dell'md5
2148
- */
2149
- md5blk(s) {
2150
- var md5blks = [], i;
2151
- for (i = 0; i < 64; i += 4)
2152
- md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
2153
- return md5blks;
2241
+ /** @ignore */
2242
+ doClipboardDataGet(clipboardText, style, valueFoundCallback) {
2243
+ console.log("[@esfaenza/extensions] Retrieved clipboard values: " + clipboardText);
2244
+ let value = style == "array" ? this.getClipboardLines(clipboardText) :
2245
+ style == "matrix" ? this.getClipboardMatrix(clipboardText) : [];
2246
+ console.log(`[@esfaenza/extensions] Adapted for ${style}: ${JSON.stringify(value)}`);
2247
+ if (valueFoundCallback)
2248
+ valueFoundCallback(value);
2154
2249
  }
2155
2250
  /**
2156
- * @ignore
2251
+ * Ottiene il contenuto della clipboard diviso per righe (separate da newline)
2157
2252
  *
2158
- * Metodo di utilità per il calcolo dell'md5
2253
+ * @param {string} data contenuto letto dalla clipboard
2254
+ *
2255
+ * @returns {string[]} Array contenente il testo preso dalla clipboard diviso per riga
2159
2256
  */
2160
- rhex(n) {
2161
- var s = '', j = 0;
2162
- for (; j < 4; j++)
2163
- s += this.hex_chr[(n >> (j * 8 + 4)) & 0x0F] + this.hex_chr[(n >> (j * 8)) & 0x0F];
2164
- return s;
2257
+ getClipboardLines(data) {
2258
+ let trimmedData = data.trim();
2259
+ if (!trimmedData.includes("\r\n") && trimmedData.includes("\n"))
2260
+ return trimmedData.split("\n");
2261
+ return trimmedData.split("\r\n");
2165
2262
  }
2166
2263
  /**
2167
- * @ignore
2264
+ * Ottiene il contenuto della clipboard diviso per righe (separate da newline) e colonne (separate da tab)
2168
2265
  *
2169
- * Metodo di utilità per il calcolo dell'md5
2266
+ * @param {string} data contenuto letto dalla clipboard
2267
+ *
2268
+ * @returns {string[][]} Matrice contenente il testo preso dalla clipboard diviso per riga e colonna
2170
2269
  */
2171
- hex(x) {
2172
- for (var i = 0; i < x.length; i++)
2173
- x[i] = this.rhex(x[i]);
2174
- return x.join('');
2270
+ getClipboardMatrix(data) {
2271
+ var ret = [];
2272
+ var rows = !data.includes("\r\n") && data.includes("\n") ? data.split("\n") : data.split("\r\n");
2273
+ // A quanto pare ogni valore è separato da un \t... spero che sia uno standard di quando si copia da excel altrimenti ciao
2274
+ for (let i = 0; i < rows.length; i++)
2275
+ ret.push(rows[i].split('\t').map(t => t.trim()));
2276
+ return ret;
2175
2277
  }
2176
2278
  /**
2177
- * @ignore
2279
+ * Metodo che copia un testo all'interno della clipboard
2178
2280
  *
2179
- * Metodo di utilità per il calcolo dell'md5
2281
+ * @param {string} text Testo da inserire nella clipboard
2180
2282
  */
2181
- add32(a, b) {
2182
- return (a + b) & 0xFFFFFFFF;
2283
+ async copyTextToClipboard(text) {
2284
+ let LOCALE = this.locProvider ? await this.locProvider.Locale.pipe(first()).toPromise() : 'it-IT';
2285
+ var textArea = document.createElement("textarea");
2286
+ //
2287
+ // *** This styling is an extra step which is likely not required. ***
2288
+ //
2289
+ // Why is it here? To ensure:
2290
+ // 1. the element is able to have focus and selection.
2291
+ // 2. if element was to flash render it has minimal visual impact.
2292
+ // 3. less flakyness with selection and copying which **might** occur if
2293
+ // the textarea element is not visible.
2294
+ //
2295
+ // The likelihood is the element won't even render, not even a flash,
2296
+ // so some of these are just precautions. However in IE the element
2297
+ // is visible whilst the popup box asking the user for permission for
2298
+ // the web page to copy to the clipboard.
2299
+ //
2300
+ // Place in top-left corner of screen regardless of scroll position.
2301
+ textArea.style.position = "fixed";
2302
+ textArea.style.top = "0";
2303
+ textArea.style.left = "0";
2304
+ // Ensure it has a small width and height. Setting to 1px / 1em
2305
+ // doesn't work as this gives a negative w/h on some browsers.
2306
+ textArea.style.width = "2em";
2307
+ textArea.style.height = "2em";
2308
+ // We don't need padding, reducing the size if it does flash render.
2309
+ textArea.style.padding = "0";
2310
+ // Clean up any borders.
2311
+ textArea.style.border = "none";
2312
+ textArea.style.outline = "none";
2313
+ textArea.style.boxShadow = "none";
2314
+ // Avoid flash of white box if rendered for any reason.
2315
+ textArea.style.background = "transparent";
2316
+ textArea.value = text;
2317
+ document.body.appendChild(textArea);
2318
+ textArea.focus();
2319
+ textArea.select();
2320
+ try {
2321
+ var successful = document.execCommand("copy");
2322
+ if (!successful)
2323
+ this.msgService.simpleError(this.loc["Generic error during 'copy' command execution"][LOCALE]);
2324
+ }
2325
+ catch (err) {
2326
+ this.msgService.simpleError(this.loc["Error during Clipboard content copy operation"][LOCALE] + ": " + err);
2327
+ }
2328
+ document.body.removeChild(textArea);
2183
2329
  }
2184
2330
  }
2185
- HashingService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: HashingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2186
- HashingService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: HashingService, providedIn: "root" });
2187
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: HashingService, decorators: [{
2331
+ ClipboardService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ClipboardService, deps: [{ token: MessageService }, { token: i1.BaseLocalization, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
2332
+ ClipboardService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ClipboardService, providedIn: "root" });
2333
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ClipboardService, decorators: [{
2188
2334
  type: Injectable,
2189
2335
  args: [{ providedIn: "root" }]
2190
- }] });
2336
+ }], ctorParameters: function () { return [{ type: MessageService }, { type: i1.BaseLocalization, decorators: [{
2337
+ type: Optional
2338
+ }] }]; } });
2191
2339
 
2192
2340
  /**
2193
2341
  * Classe che rappresenta una risposta ricevuta da un Backend