Compare commits

..

83 Commits

Author SHA1 Message Date
Developer 02
891f6368f1 refactor(card.css): CSS der footer für Reaktionsfähigkeit bearbeitet 2024-10-16 02:11:07 +02:00
Developer 02
e6011b6201 refactor(card.css): CSS des Kopfbereichs für Reaktionsfähigkeit bearbeitet 2024-10-16 01:54:02 +02:00
Developer 02
8b86114998 refactor (card.css): unnötiges CSS entfernt 2024-10-16 00:31:32 +02:00
Developer 02
c20b115faf feat(logo): minimiertes Logo hinzugefügt 2024-10-16 00:11:14 +02:00
Developer 02
2c8ccd3e7c feat: signFlow-Logo hinzufügen 2024-10-14 19:18:40 +02:00
Developer 02
b1f771c320 feat: Kopierschaltfläche von der linken Navigationsleiste in die pspdf-kit Symbolleiste verschoben. 2024-10-14 18:54:29 +02:00
Developer 02
425645a610 feat: neue Klasse für Desktop-Schaltflächen mit dem Namen 'btn-desktop' erstellt
- CSS hinzugefügt, um die Klasse btn-desktop auszublenden, wenn die Breite weniger als 1024px beträgt.
2024-10-14 17:41:51 +02:00
Developer 02
24e6ffc5ef feat: CSS mit Bootstrap für mobil beschreibbare Toolbar-Elemente anordnen 2024-10-14 17:24:49 +02:00
Developer 02
1dd9ce6bbc feat: Aktivieren Sie die Schaltfläche für die mobile Ablehnung.
- Ereignis hinzugefügt.
 - In die Mitte der Schaltflächenleiste verschoben
2024-10-14 17:06:01 +02:00
Developer 02
e528fa6409 feat: getMobileItems umbenennen in getMobileWritableItems 2024-10-14 16:05:27 +02:00
Developer 02
6440dd09d1 feat: Erstellung der konstanten Variablen DEVICE_TYPE und IS_DESKTOP.
- Aufteilung der benutzerdefinierten Symbolleistenelemente in writableItems und mobileItems
 - beide werden abhängig von der jeweiligen Bedingung hinzugefügt
2024-10-14 15:44:21 +02:00
Developer 02
869493bd97 feat: Globale Konstante isReadOnly-Wert erstellt.
- Constraint für ReadOnly-Schaltfläche mit isReadOnly-Wert hinzugefügt
2024-10-14 14:02:02 +02:00
Developer 02
1cb9042736 feat(ui.js): Freigabe-Schaltfläche als Symbolleisten-Schaltfläche hinzugefügt.
- Share-Button auf der linken Seite der Kopfzeile entfernt
2024-10-14 11:27:41 +02:00
Developer 02
c9410a1e2e feat(ReadOnlyController): Try-Catch zur 'CreateAsync'-Methode hinzugefügt.
- Unnötige Testmethoden wurden aus dem Controller entfernt.
2024-10-14 09:38:16 +02:00
Developer 02
c4f0ce7d4b feat: bsNotify-Methode und Benachrichtigung für Clipboard-Kopie hinzufügen
- Implementierung der bsNotify-Methode für benutzerdefinierte Benachrichtigungen mit alertify.
- Hinzufügen von benutzerdefinierten Styles für den benutzerdefinierten Benachrichtigungstyp von alertify.
- Hinzufügen der Clipboard-Kopie-Funktionalität mit Erfolgs- und Fehlerbenachrichtigungen.
2024-10-11 14:15:06 +02:00
Developer 02
dc83486032 feat(ShowEnvelope): Nachricht auf Popup-Seite zum Teilen hinzugefügt 2024-10-11 09:51:02 +02:00
Developer 02
2a64091c87 feat: Funktionalität des Datumsauswählers zum Eingabefeld hinzufügen
- Einen Datumsauswähler implementiert, der beim Fokussieren des Eingabefeldes und beim Klicken auf das Kalendersymbol geöffnet wird.
- Sicherstellt, dass das Eingabefeld keine manuelle Dateneingabe zulässt, während der Kalender weiterhin angezeigt werden kann.
- Das `onkeydown`-Ereignis verwendet, um manuelle Eingaben zu verhindern und die Datenauswahl ausschließlich über den Datumsauswähler zu ermöglichen.
2024-10-11 00:59:00 +02:00
Developer 02
f65f749208 feat(ShowEnvelope): Der Rücksetzwert des Verfallsdatums der Briefumschlag-Aktie wird auf das Datum eine Woche später statt auf den leeren String gesetzt. 2024-10-11 00:45:37 +02:00
Developer 02
0b6ed00062 feat(EnvelopeReceiverReadOnlyCreateDto): EmailAddress und Required Attribute zu ReceiverMail hinzugefügt. 2024-10-11 00:36:18 +02:00
Developer 02
e87c976e19 fix(ShowEnvelope): Logik der E-Mail-Formatprüfung korrigiert 2024-10-10 22:00:52 +02:00
Developer 02
f31ece3a59 feat(ShowEnvelope): Logik zur Überprüfung des E-Mail-Formats hinzugefügt. Zeigt eine Fehlermeldung, wenn das Format falsch ist. 2024-10-10 21:56:32 +02:00
Developer 02
cfd08602ab feat(ShowEnvelope): Logik zur Überprüfung des Datums hinzugefügt. Wenn es weniger als einen Tag beträgt, wird eine Fehlermeldung angezeigt. 2024-10-10 21:46:06 +02:00
Developer 02
4b7152b272 feat(ShowEnvelope): Die Attribute min, max und value wurden zu readonly-date-valid hinzugefügt. 2024-10-10 20:47:55 +02:00
Developer 02
5117a66c81 feat(ShowEnvelope): Standarddatum nach 3 Tagen setzen 2024-10-10 19:30:19 +02:00
Developer 02
83794d4bbc feat: add email validation and toggle 'is-invalid' class for inputs with 'email-input' class 2024-10-10 19:21:15 +02:00
Developer 02
76f74778b4 feat(ShowEnvelope): Swal-Nachrichten zur Umschlagfreigabe-Anforderung hinzugefügt 2024-10-10 18:53:35 +02:00
Developer 02
ded3425e31 feat: Funktion hinzugefügt, um aktuelle URL beim Klicken auf den Button in die Zwischenablage zu kopieren 2024-10-09 16:53:44 +02:00
Developer 02
738b379fe5 feat(UI.js): PDF-Export-Symbolleiste zur pspdf-Instanz hinzugefügt 2024-10-09 16:50:01 +02:00
Developer 02
cf8b28441f feat(ShowEnvelope): Bedingung hinzugefügt, die auf Nur-Lesen basiert, um den Share-Button zu sehen.
- Wenn es schreibgeschützt ist, erscheint die Schaltfläche Kopie zur Zwischenablage hinzufügen.
2024-10-09 16:49:07 +02:00
Developer 02
0eb5897185 feat(share pop-up): Post-Request-Prozess hinzugefügt. 2024-10-09 15:03:54 +02:00
Developer 02
25cd1601a6 feat(share pop-up): Datumswähler hinzugefügt. 2024-10-09 13:54:16 +02:00
Developer 02
42e4d110ad refactor(wwwroot\lib): MDB und bootstrap-cookie-consent-settings-main entfernt 2024-10-09 12:43:18 +02:00
Developer 02
2538f34892 feat(ShowEnvelope). erstellt Basis-Popup-Menü, um das Dokument zu senden 2024-10-09 12:37:36 +02:00
Developer 02
3ce11f4cc7 feat(api-service): Methode für Share-Request erstellt. 2024-10-09 11:00:21 +02:00
Developer 02
f2cd34a79e feat(share-button): Basisstruktur der Klick-Aktion hinzugefügt 2024-10-09 10:50:26 +02:00
Developer 02
5f923ad485 feat(ShowEnvelope): Share-Button hinzugefügt
- CSS einstellen.
2024-10-09 10:46:18 +02:00
Developer 02
8f70f085d3 feat(HomeController): Historischer Prozess zum Speichern von Umschlägen hinzugefügt, die unter dem Endpunkt EnvelopeReceiverReadOnly angezeigt werden. 2024-10-09 09:58:20 +02:00
Developer 02
d6c09ed31a feat(ReadOnlyController): Speichern der EnvelopeShared-History zur CreateAsync-Methode hinzugefügt. 2024-10-09 09:37:02 +02:00
Developer 02
7d3ee1331d feat(EnvelopeStatus): Status „EnvelopeViewed“ hinzugefügt 2024-10-09 02:11:51 +02:00
Developer 02
cd5b90a1e2 feat(ReadOnlyControler): History-Dienst hinzugefügt, um envelope-shared-process zu speichern 2024-10-09 02:10:08 +02:00
Developer 02
ac861f5fa0 fix(DIExtensions): arrangierte Mail- und Dispatcher-Konfigurationen 2024-10-09 02:05:21 +02:00
Developer 02
c1d8f817bb feat(ReadOnlyController): envelope-id von create DTO automatisch aus envelope-id claim hinzugefügt. 2024-10-09 01:16:06 +02:00
Developer 02
da28a7332b feat(EnvelopeClaimTypes): „envelope ID“ als Auth-Claim hinzugefügt. 2024-10-09 00:51:59 +02:00
Developer 02
bfd4e6a8ed feat(MailConfig): Schnittstelle zur Mail-Konfiguration über appsettings erstellt. 2024-10-09 00:22:23 +02:00
Developer 02
b4e0e4b6b2 feat(EnvelopeMailService): Arrangiert den Mailservice für read-only Umschläge zum Versenden als E-Mail 2024-10-08 15:56:34 +02:00
Developer 02
e37caf5c8f refactor(ShowEnvelopeView): Kurzzeitanteil der Verfallszeit für schreibgeschützten Umschlag entfernen 2024-10-07 10:08:10 +02:00
Developer 02
e95cf24af7 feat(EnvelopeExpired-View): Erstellt eine Ansicht, die anzeigt, wenn der Umschlag abgelaufen ist 2024-10-05 04:19:52 +02:00
Developer 02
524a72caa0 feat(ShowEnvelope-View): Flex-Action-Panel ausblenden, wenn schreibgeschützt 2024-10-05 03:22:37 +02:00
Developer 02
1919c562cc feat(ShowEnvelope-View): ReadOnlyMessage wurde für verschiedene Kulturen erstellt. Zu View hinzugefügt.
- View-Benutzernachrichten sind so organisiert, dass sie davon abhängen, ob der Umschlag schreibgeschützt ist oder nicht.
2024-10-05 03:20:39 +02:00
Developer 02
62b54d6e75 feat(HomeController): Sanizer hinzugefügt 2024-10-05 02:16:14 +02:00
Developer 02
efa9160c04 feat(EnvelopeReceiverReadOnly): Modelldaten und Dokument im Endpunkt sind so eingestellt, dass sie als Bytes geladen werden. 2024-10-05 02:04:57 +02:00
Developer 02
bc6955055a feat(EnvelopeReceiverReadOnly): Created endpoint for ShowEnvelope view 2024-10-04 11:28:52 +02:00
Developer 02
dc997d5ff2 refactor(.Extensions): Extensions nach Gruppen aufgeteilt.
- erstellt dekodierende Erweiterungen.
 - Kodierungserweiterungen erstellt.
 - XSS-Erweiterungen in das Extensions-Paket verschoben.
 - EncodeTypes vom Paket Common in das Paket Constants verschoben.
2024-10-02 13:33:11 +02:00
Developer 02
a32f495038 refactor(HomeController): EnvelopeReceiverReadOnly-Endpunkt initialisiert.
- injiziert EnvelopeReceiverReadOnlyService
2024-10-01 18:14:59 +02:00
Developer 02
210466883c refactor(SendAccessCode): Prüfung hinzugefügt, ob die envelope-id schreibgeschützt ist. Wenn ja, Umleitung zu /ReadOnly
- Umbenannt in MainAsync
2024-10-01 17:51:31 +02:00
Developer 02
728385b70a feat(extensions): created extensions project.
- Moved encoding extensions from application to extensions project to increase the abstraction
2024-10-01 17:25:50 +02:00
Developer 02
792aa0b922 feat(decode): Methoden zur Konvertierung des dekodierten Arrays in eine Umschlag-Empfänger-ID und eine Nur-Lese-ID mit Ausnahmewirkung hinzugefügt. 2024-10-01 16:44:46 +02:00
Developer 02
6847b74095 feat(EncodeType): Enum zur Klassifizierung von Kodierungstypen erstellt.
- Erweiterungsmethoden hinzugefügt, um zu versuchen, String mit out-keyworld zu dekodieren.

- Erweiterungsmethode hinzugefügt, um den Typ des Kodierungstyps des dekodierten String-Arrays zu finden.
2024-10-01 16:04:44 +02:00
Developer 02
54e86b421c feat(EnvelopeReceiverReadOnly): Erweiterungsmethode zum Kodieren und Dekodieren von Envelope-Receiver ReadOnly Id hinzugefügt 2024-10-01 15:26:06 +02:00
Developer 02
370666cb0e refactor: EnvelopeReceiverReadOnlyRepository so angepasst, dass die Einbindung von Envelope bis zur Klärung des ID-Typs verschoben wird
- Konstruktor von EnvelopeReceiverReadOnlyRepository angepasst, um IEnvelopeRepository zu akzeptieren.
 - Die Zeile Include(erro => erro.Envelope) in der Methode ReadOnly auskommentiert, bis der EnvelopeId-Typ standardisiert ist.
 - Methoden IncludeEnvelope hinzugefügt, um Envelope manuell für jedes EnvelopeReceiverReadOnly einzubinden.
 - Markierte manuelle Einbindungs-Methoden als veraltet, um durch IQueryable.Include ersetzt zu werden, sobald der EnvelopeId-Typ geklärt ist.
2024-10-01 12:54:27 +02:00
Developer 02
e17f7df930 feat(EnvelopeReceiverReadOnly): Controller initialisieren
- Join mit Receiver und Read
 - DI-Konfiguration hinzufügen
 - Auslöser hinzufügen (TBSIG_ENVELOPE_RECEIVER_READ_ONLY_UPD)
2024-10-01 11:17:30 +02:00
Developer 02
0e91df7acc feat (Constants.EmailTemplateType): Einen neuen Typ namens „DocumentShared“ erstellt 2024-09-30 15:14:01 +02:00
Developer 02
ad26230da5 feat (EnvelopeReceiverReadOnly): Erstellt „EnvelopeReceiverReadOnlyService“ als Implementierung von „CRUDService“ und „IEnvelopeReceiverReadOnlyService-interface“ 2024-09-30 15:02:52 +02:00
Developer 02
a103f34230 feat (EnvelopeReceiverReadOnly): Erstellt „mapping-profiles“ für Auto-Mapper.
- EnvelopeReceiverReadOnly zu EnvelopeReceiverReadOnlyDto
 - EnvelopeReceiverReadOnlyCreateDto zu EnvelopeReceiverReadOnly
 - EnvelopeReceiverReadOnlyUpdateDto zu EnvelopeReceiverReadOnly
2024-09-30 14:43:30 +02:00
Developer 02
806bd3b248 feat (EnvelopeReceiverReadOnly): Erstellt „data-transfer-objects“.
- Erstellt „Read-DTO“
 - Erstellt „Create-DTO
 - Erstellt „Update-DTO“ um nur „DateValid“ zu aktualisieren.
2024-09-30 14:39:22 +02:00
Developer 02
c69c39fa44 refactor(EnvelopeReceiverReadOnly): ChangedWho Eigenschaft „nullable“ gemacht 2024-09-30 14:00:40 +02:00
Developer 02
b6badb44af feat(EnvelopeReceiverReadOnly): Erstellte Repository-Klasse mit der Interface-Implementierung 2024-09-30 13:54:39 +02:00
Developer 02
b2195ce13f feat(EnvelopeReceiverReadOnly): Entität erstellt 2024-09-30 13:43:57 +02:00
Developer 02
f3cb9b8510 feat(EnvelopeStatus): Neuer Status für die gemeinsame Nutzung von Umschlägen mit Code 2008 hinzugefügt. 2024-09-30 11:49:08 +02:00
Developer 02
8edfecb9dc refactor (privacy-policy): Fehlende Informationen und CSS aktualisieren 2024-09-30 11:32:14 +02:00
Developer 02
c123d103bb chore Upgrade auf 2.1.1.0 2024-09-25 16:09:01 +02:00
Developer 02
b92d9da387 refactor(envelope-locked): konvertiere submit-button bootstrap Klasse von btn-outline-primary zu btn-primary 2024-09-25 16:07:54 +02:00
Developer 02
8841698aab chore(web): Version auf 2.0.0.0 aktualisieren und Copyrights schreiben 2024-09-25 15:52:09 +02:00
Developer 02
6f140f16cd fix(footer): Entferne den Ursprung der Datenschutzrichtlinien-URL, um auf den aktuellen Ursprung umzuleiten 2024-09-25 15:49:38 +02:00
Developer 02
8bfd31997b Merge branch 'master' of http://git.dd:3000/AppStd/EnvelopeGenerator 2024-09-25 14:46:14 +02:00
Developer 02
4a1459d708 feat: add smooth width transition to progress bar with 1s ease animation 2024-09-25 14:46:08 +02:00
Developer 02
361bdeb2b2 feat(event-binder.js): Es wurde der Effekt hinzugefügt, dass die Breite des Fortschrittsbalkens nach dem Signaturprozess um einen bestimmten Anteil erhöht wird. 2024-09-25 14:41:30 +02:00
Developer 02
9ce5af7cd0 feat(event-binder.js): Signaturkomponente hinzugefügt, um die Animationen in der Fortschrittsleiste der Signatur zu behandeln
- Befehl zum Erhöhen der Anzahl von Signaturen unter der createAnnotationFrameBlob-Methode in annotation.js hinzugefügt

- Vorzeichenbehafteter Befehl zum Nullsetzen der Zählung unter RESET-case der handleClick-Methode in app.js hinzugefügt
2024-09-25 14:03:05 +02:00
Developer 02
84fa9e6e7c refactor(envelope-locked): Zugriffscode-Panel einrichten 2024-09-25 13:28:47 +02:00
Developer 02
36916ed5c8 refactor(envelope-lcoked): Konvertierung von 'access-code' Floating Input 2024-09-25 11:01:54 +02:00
Developer 02
fb366d3e0b refactor: Umschlag nav-menu bearbeiten. minfied card.css 2024-09-25 09:21:55 +02:00
Developer01
e82be8b6a5 Merge branch 'master' of http://git.dd:3000/AppStd/EnvelopeGenerator 2024-09-24 17:26:19 +02:00
Developer01
07320af4ee MS GPicture 2024-09-24 17:26:11 +02:00
468 changed files with 2020 additions and 58985 deletions

View File

@@ -0,0 +1,13 @@
namespace EnvelopeGenerator.Application.Configurations
{
public class DispatcherConfig
{
public int SendingProfile { get; init; } = 1;
public string AddedWho { get; init; } = "DDEnvelopGenerator";
public int ReminderTypeId { get; init; } = 202377;
public string EmailAttmt1 { get; init; } = string.Empty;
}
}

View File

@@ -0,0 +1,7 @@
namespace EnvelopeGenerator.Application.Configurations
{
public class MailConfig
{
public required Dictionary<string, string> Placeholders { get; init; }
}
}

View File

@@ -1,6 +1,7 @@
using DigitalData.Core.DTO; using DigitalData.Core.DTO;
using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts; using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Common; using EnvelopeGenerator.Common;
namespace EnvelopeGenerator.Application.Contracts namespace EnvelopeGenerator.Application.Contracts
@@ -8,6 +9,9 @@ namespace EnvelopeGenerator.Application.Contracts
public interface IEnvelopeMailService : IEmailOutService public interface IEnvelopeMailService : IEmailOutService
{ {
Task<DataResult<int>> SendAsync(EnvelopeReceiverDto envelopeReceiverDto, Constants.EmailTemplateType tempType); Task<DataResult<int>> SendAsync(EnvelopeReceiverDto envelopeReceiverDto, Constants.EmailTemplateType tempType);
Task<DataResult<int>> SendAsync(EnvelopeReceiverReadOnlyDto dto);
Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto envelopeReceiverDto); Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto envelopeReceiverDto);
} }
} }

View File

@@ -0,0 +1,10 @@
using DigitalData.Core.Abstractions.Application;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Contracts
{
public interface IEnvelopeReceiverReadOnlyService : ICRUDService<EnvelopeReceiverReadOnlyCreateDto, EnvelopeReceiverReadOnlyDto, EnvelopeReceiverReadOnlyUpdateDto, EnvelopeReceiverReadOnly, long>
{
}
}

View File

@@ -1,21 +1,18 @@
using DigitalData.UserManager.Application.MappingProfiles; using DigitalData.UserManager.Application.MappingProfiles;
using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.MappingProfiles; using EnvelopeGenerator.Application.MappingProfiles;
using EnvelopeGenerator.Application.Configurations;
using EnvelopeGenerator.Application.Services; using EnvelopeGenerator.Application.Services;
using EnvelopeGenerator.Infrastructure.Contracts; using EnvelopeGenerator.Infrastructure.Contracts;
using EnvelopeGenerator.Infrastructure.Repositories; using EnvelopeGenerator.Infrastructure.Repositories;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EnvelopeGenerator.Application namespace EnvelopeGenerator.Application
{ {
public static class DIExtensions public static class DIExtensions
{ {
public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services) public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfiguration dispatcherConfigSection, IConfiguration mailConfigSection)
{ {
//Inject CRUD Service and repositoriesad //Inject CRUD Service and repositoriesad
services.AddScoped<IConfigRepository, ConfigRepository>(); services.AddScoped<IConfigRepository, ConfigRepository>();
@@ -33,6 +30,7 @@ namespace EnvelopeGenerator.Application
services.AddScoped<IEnvelopeTypeRepository, EnvelopeTypeRepository>(); services.AddScoped<IEnvelopeTypeRepository, EnvelopeTypeRepository>();
services.AddScoped<IReceiverRepository, ReceiverRepository>(); services.AddScoped<IReceiverRepository, ReceiverRepository>();
services.AddScoped<IUserReceiverRepository, UserReceiverRepository>(); services.AddScoped<IUserReceiverRepository, UserReceiverRepository>();
services.AddScoped<IEnvelopeReceiverReadOnlyRepository, EnvelopeReceiverReadOnlyRepository>();
services.AddScoped<IConfigService, ConfigService>(); services.AddScoped<IConfigService, ConfigService>();
services.AddScoped<IDocumentReceiverElementService, DocumentReceiverElementService>(); services.AddScoped<IDocumentReceiverElementService, DocumentReceiverElementService>();
services.AddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>(); services.AddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>();
@@ -46,12 +44,20 @@ namespace EnvelopeGenerator.Application
services.AddScoped<IEnvelopeTypeService, EnvelopeTypeService>(); services.AddScoped<IEnvelopeTypeService, EnvelopeTypeService>();
services.AddScoped<IReceiverService, ReceiverService>(); services.AddScoped<IReceiverService, ReceiverService>();
services.AddScoped<IUserReceiverService, UserReceiverService>(); services.AddScoped<IUserReceiverService, UserReceiverService>();
services.AddScoped<IEnvelopeReceiverReadOnlyService, EnvelopeReceiverReadOnlyService>();
//Auto mapping profiles //Auto mapping profiles
services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly); services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly);
services.AddAutoMapper(typeof(UserMappingProfile).Assembly); services.AddAutoMapper(typeof(UserMappingProfile).Assembly);
services.Configure<DispatcherConfig>(dispatcherConfigSection);
services.Configure<MailConfig>(mailConfigSection);
return services; return services;
} }
public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfiguration config) => services.AddEnvelopeGenerator(
dispatcherConfigSection: config.GetSection("DispatcherConfig"),
mailConfigSection: config.GetSection("MailConfig"));
} }
} }

View File

@@ -0,0 +1,22 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly
{
public record EnvelopeReceiverReadOnlyCreateDto(
DateTime DateValid)
{
[EmailAddress]
[Required]
public required string ReceiverMail { get; init; }
[JsonIgnore]
public long? EnvelopeId { get; set; } = null;
[JsonIgnore]
public string? AddedWho { get; set; }
[JsonIgnore]
public DateTime AddedWhen { get; } = DateTime.Now;
};
}

View File

@@ -0,0 +1,16 @@
using EnvelopeGenerator.Application.DTOs.Receiver;
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly
{
public record EnvelopeReceiverReadOnlyDto(
long Id,
long EnvelopeId,
string ReceiverMail,
DateTime DateValid,
DateTime AddedWhen,
string AddedWho,
EnvelopeDto? Envelope = null,
string? ChangedWho = null,
DateTime? ChangedWhen = null,
ReceiverReadDto? Receiver = null);
}

View File

@@ -0,0 +1,12 @@
using DigitalData.Core.Abstractions;
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly
{
public record EnvelopeReceiverReadOnlyUpdateDto(
long Id,
DateTime DateValid,
string ChangedWho) : IUnique<long>
{
public DateTime ChangedWhen { get; } = DateTime.Now;
};
}

View File

@@ -1,13 +0,0 @@
namespace EnvelopeGenerator.Application
{
public class DispatcherConfig
{
public int SendingProfile { get; init; } = 1;
public string AddedWho { get; init; } = "DDEnvelopGenerator";
public int ReminderTypeId { get; init; } = 202377;
public string EmailAttmt1 { get; init; } = string.Empty;
}
}

View File

@@ -22,6 +22,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\EnvelopeGenerator.Extensions\EnvelopeGenerator.Extensions.csproj" />
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" /> <ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -2,6 +2,7 @@
using EnvelopeGenerator.Application.DTOs; using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory; using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Application.DTOs.Receiver; using EnvelopeGenerator.Application.DTOs.Receiver;
using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Domain.Entities;
@@ -28,6 +29,7 @@ namespace EnvelopeGenerator.Application.MappingProfiles
CreateMap<Receiver, ReceiverCreateDto>(); CreateMap<Receiver, ReceiverCreateDto>();
CreateMap<Receiver, ReceiverUpdateDto>(); CreateMap<Receiver, ReceiverUpdateDto>();
CreateMap<UserReceiver, UserReceiverDto>(); CreateMap<UserReceiver, UserReceiverDto>();
CreateMap<EnvelopeReceiverReadOnly, EnvelopeReceiverReadOnlyDto>();
// DTO to Entity mappings // DTO to Entity mappings
CreateMap<ConfigDto, Config>(); CreateMap<ConfigDto, Config>();
@@ -46,6 +48,8 @@ namespace EnvelopeGenerator.Application.MappingProfiles
CreateMap<ReceiverUpdateDto, Receiver>(); CreateMap<ReceiverUpdateDto, Receiver>();
CreateMap<UserReceiverDto, UserReceiver>(); CreateMap<UserReceiverDto, UserReceiver>();
CreateMap<EnvelopeReceiverBase, EnvelopeReceiverBasicDto>(); CreateMap<EnvelopeReceiverBase, EnvelopeReceiverBasicDto>();
CreateMap<EnvelopeReceiverReadOnlyCreateDto, EnvelopeReceiverReadOnly>();
CreateMap<EnvelopeReceiverReadOnlyUpdateDto, EnvelopeReceiverReadOnly>();
} }
} }
} }

View File

@@ -177,6 +177,9 @@
<data name="LockedTitle" xml:space="preserve"> <data name="LockedTitle" xml:space="preserve">
<value>Dokument erfordert einen Zugriffscode</value> <value>Dokument erfordert einen Zugriffscode</value>
</data> </data>
<data name="ReadOnlyMessage" xml:space="preserve">
<value>Weitergeleitet von {0}. Gültig bis {1}.</value>
</data>
<data name="Reject" xml:space="preserve"> <data name="Reject" xml:space="preserve">
<value>Ablehnen</value> <value>Ablehnen</value>
</data> </data>

View File

@@ -177,6 +177,9 @@
<data name="LockedTitle" xml:space="preserve"> <data name="LockedTitle" xml:space="preserve">
<value>Document requires an access code</value> <value>Document requires an access code</value>
</data> </data>
<data name="ReadOnlyMessage" xml:space="preserve">
<value>Forwarded by {0}. Valid until {1}.</value>
</data>
<data name="Reject" xml:space="preserve"> <data name="Reject" xml:space="preserve">
<value>Reject</value> <value>Reject</value>
</data> </data>

View File

@@ -3,14 +3,15 @@ using DigitalData.Core.DTO;
using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts; using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts;
using DigitalData.EmailProfilerDispatcher.Abstraction.DTOs.EmailOut; using DigitalData.EmailProfilerDispatcher.Abstraction.DTOs.EmailOut;
using DigitalData.EmailProfilerDispatcher.Abstraction.Services; using DigitalData.EmailProfilerDispatcher.Abstraction.Services;
using DigitalData.UserManager.Application;
using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using EnvelopeGenerator.Common; using EnvelopeGenerator.Common;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using static EnvelopeGenerator.Common.Constants; using static EnvelopeGenerator.Common.Constants;
using EnvelopeGenerator.Extensions;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Application.Configurations;
namespace EnvelopeGenerator.Application.Services namespace EnvelopeGenerator.Application.Services
{ {
@@ -20,39 +21,50 @@ namespace EnvelopeGenerator.Application.Services
private readonly IEnvelopeReceiverService _envRcvService; private readonly IEnvelopeReceiverService _envRcvService;
private readonly DispatcherConfig _dConfig; private readonly DispatcherConfig _dConfig;
private readonly IConfigService _configService; private readonly IConfigService _configService;
private readonly Dictionary<string, string> _placeholders;
public EnvelopeMailService(IEmailOutRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions<DispatcherConfig> dispatcherConfigOptions, IConfigService configService) : base(repository, mapper) public EnvelopeMailService(IEmailOutRepository repository, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions<DispatcherConfig> dispatcherConfigOptions, IConfigService configService, IOptions<MailConfig> mailConfig) : base(repository, mapper)
{ {
_tempService = tempService; _tempService = tempService;
_envRcvService = envelopeReceiverService; _envRcvService = envelopeReceiverService;
_dConfig = dispatcherConfigOptions.Value; _dConfig = dispatcherConfigOptions.Value;
_configService = configService; _configService = configService;
_placeholders = mailConfig.Value.Placeholders;
} }
//TODO: create ioptions and implement TemplatePlaceHolderAttribute instead of this method private async Task<Dictionary<string, string>> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? envelopeReceiverDto = null, EnvelopeReceiverReadOnlyDto? readOnlyDto = null)
private async Task<Dictionary<string, string>> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? envelopeReceiverDto = null)
{ {
Dictionary<string, string> placeholders = new() {
{ "[NAME_PORTAL]", "signFlow" },
{ "[SIGNATURE_TYPE]" , "signieren"},
{ "[REASON]", string.Empty } };
if (accessCode is not null) if (accessCode is not null)
placeholders["[DOCUMENT_ACCESS_CODE]"] = accessCode; _placeholders["[DOCUMENT_ACCESS_CODE]"] = accessCode;
if(envelopeReceiverDto is not null && envelopeReceiverDto.Envelope is not null && envelopeReceiverDto.Receiver is not null) if(envelopeReceiverDto?.Envelope is not null && envelopeReceiverDto.Receiver is not null)
{ {
var erId = (envelopeReceiverDto.Envelope.Uuid, envelopeReceiverDto.Receiver.Signature).EncodeEnvelopeReceiverId(); var erId = (envelopeReceiverDto.Envelope.Uuid, envelopeReceiverDto.Receiver.Signature).EncodeEnvelopeReceiverId();
var sigHost = await _configService.ReadDefaultSignatureHost(); var sigHost = await _configService.ReadDefaultSignatureHost();
var linkToDoc = $"{sigHost}/envelope/{erId}"; var linkToDoc = $"{sigHost}/EnvelopeKey/{erId}";
placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc; _placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc;
placeholders["[LINK_TO_DOCUMENT_TEXT]"] = linkToDoc[..Math.Min(40, linkToDoc.Length)]; _placeholders["[LINK_TO_DOCUMENT_TEXT]"] = linkToDoc[..Math.Min(40, linkToDoc.Length)] + "..";
} }
return placeholders; return _placeholders;
} }
public async Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto dto) => await SendAsync(dto: dto, tempType: Constants.EmailTemplateType.DocumentAccessCodeReceived); private async Task<Dictionary<string, string>> CreatePlaceholders(EnvelopeReceiverReadOnlyDto? readOnlyDto = null)
{
if (readOnlyDto?.Envelope is not null && readOnlyDto.Receiver is not null)
{
_placeholders["[NAME_RECEIVER]"] = await _envRcvService.ReadLastUsedReceiverNameByMail(readOnlyDto.AddedWho).ThenAsync(res => res, (msg, ntc) => string.Empty) ?? string.Empty;
var erReadOnlyId = (readOnlyDto.Id).EncodeEnvelopeReceiverId();
var sigHost = await _configService.ReadDefaultSignatureHost();
var linkToDoc = $"{sigHost}/EnvelopeKey/{erReadOnlyId}";
_placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc;
_placeholders["[LINK_TO_DOCUMENT_TEXT]"] = linkToDoc[..Math.Min(40, linkToDoc.Length)] + "..";
}
return _placeholders;
}
public async Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto dto) => await SendAsync(dto: dto, tempType: Constants.EmailTemplateType.DocumentAccessCodeReceived);
public async Task<DataResult<int>> SendAsync(EnvelopeReceiverDto dto, Constants.EmailTemplateType tempType) public async Task<DataResult<int>> SendAsync(EnvelopeReceiverDto dto, Constants.EmailTemplateType tempType)
{ {
@@ -92,8 +104,43 @@ namespace EnvelopeGenerator.Application.Services
var placeholders = await CreatePlaceholders(accessCode: accessCode, envelopeReceiverDto: dto); var placeholders = await CreatePlaceholders(accessCode: accessCode, envelopeReceiverDto: dto);
//TODO: remove the requirement to add the models using reflections
return await CreateWithTemplateAsync(createDto: mail,placeholders: placeholders, return await CreateWithTemplateAsync(createDto: mail,placeholders: placeholders,
dto, dto.Envelope.User!, dto.Envelope); dto, dto.Envelope.User!, dto.Envelope);
} }
}
public async Task<DataResult<int>> SendAsync(EnvelopeReceiverReadOnlyDto dto)
{
var tempSerResult = await _tempService.ReadByNameAsync(Constants.EmailTemplateType.DocumentShared);
if (tempSerResult.IsFailed)
return tempSerResult.ToFail<int>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"The email cannot send because '{Constants.EmailTemplateType.DocumentShared}' template cannot found.");
var temp = tempSerResult.Data;
var mail = new EmailOutCreateDto()
{
EmailAddress = dto.ReceiverMail,
EmailSubj = temp.Subject,
EmailBody = temp.Body,
//TODO: remove int casting when all
ReferenceId = (int) dto.EnvelopeId, //REFERENCE_ID = ENVELOPE_ID
ReferenceString = dto.Envelope!.Uuid, //REFERENCE_STRING = ENVELOPE_UUID
//receiver_name = receiver.name,
//receiver_access_code = receiver.access_code,
//sender_adress = envelope.user.email,
//sender_name = envelope.user.full_name,
//envelope_title = envelope.title,
ReminderTypeId = _dConfig.ReminderTypeId,
SendingProfile = _dConfig.SendingProfile,
EntityId = null,
WfId = (int)EnvelopeStatus.EnvelopeShared,
WfReference = null,
AddedWho = _dConfig.AddedWho,
EmailAttmt1 = _dConfig.EmailAttmt1
};
var placeholders = await CreatePlaceholders(readOnlyDto: dto);
return await CreateWithTemplateAsync(createDto: mail, placeholders: placeholders, dto.Envelope);
}
}
} }

View File

@@ -0,0 +1,16 @@
using AutoMapper;
using DigitalData.Core.Application;
using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
namespace EnvelopeGenerator.Application.Services
{
public class EnvelopeReceiverReadOnlyService : CRUDService<IEnvelopeReceiverReadOnlyRepository, EnvelopeReceiverReadOnlyCreateDto, EnvelopeReceiverReadOnlyDto, EnvelopeReceiverReadOnlyUpdateDto, EnvelopeReceiverReadOnly, long>, IEnvelopeReceiverReadOnlyService
{
public EnvelopeReceiverReadOnlyService(IEnvelopeReceiverReadOnlyRepository repository, IMapper mapper) : base(repository, mapper)
{
}
}
}

View File

@@ -8,6 +8,7 @@ using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts; using EnvelopeGenerator.Infrastructure.Contracts;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using EnvelopeGenerator.Extensions;
namespace EnvelopeGenerator.Application.Services namespace EnvelopeGenerator.Application.Services
{ {

View File

@@ -1,6 +1,7 @@
Public Class Constants Public Class Constants
#Region "Status Fields" #Region "Status Fields"
'http://wiki.dd/xwiki13/bin/view/Anwendungen/Produkt-Handbuch/Sonstiges/SignFlow/Envelope%20Status/
Public Enum EnvelopeStatus Public Enum EnvelopeStatus
Invalid = 0 Invalid = 0
EnvelopeCreated = 1001 EnvelopeCreated = 1001
@@ -19,6 +20,8 @@
DocumentSigned = 2005 DocumentSigned = 2005
SignatureConfirmed = 2006 SignatureConfirmed = 2006
DocumentRejected = 2007 DocumentRejected = 2007
EnvelopeShared = 2008
EnvelopeViewed = 2009
MessageInvitationSent = 3001 ' Wird von Trigger verwendet MessageInvitationSent = 3001 ' Wird von Trigger verwendet
MessageAccessCodeSent = 3002 MessageAccessCodeSent = 3002
MessageConfirmationSent = 3003 MessageConfirmationSent = 3003
@@ -94,6 +97,13 @@
DocumentDeleted DocumentDeleted
DocumentCompleted DocumentCompleted
DocumentAccessCodeReceived DocumentAccessCodeReceived
DocumentShared
End Enum
Public Enum EncodeType
EnvelopeReceiver
EnvelopeReceiverReadOnly
Undefined
End Enum End Enum
#End Region #End Region

View File

@@ -13,6 +13,8 @@
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<Deterministic>true</Deterministic> <Deterministic>true</Deterministic>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@@ -75,8 +77,8 @@
<Reference Include="DigitalData.Modules.Logging"> <Reference Include="DigitalData.Modules.Logging">
<HintPath>..\..\2_DLL Projekte\DDModules\Logging\bin\Debug\DigitalData.Modules.Logging.dll</HintPath> <HintPath>..\..\2_DLL Projekte\DDModules\Logging\bin\Debug\DigitalData.Modules.Logging.dll</HintPath>
</Reference> </Reference>
<Reference Include="GdPicture.NET.14"> <Reference Include="GdPicture.NET.14, Version=14.2.89.0, Culture=neutral, PublicKeyToken=f52a2e60ad468dbb, processorArchitecture=MSIL">
<HintPath>D:\ProgramFiles\GdPicture.NET 14\Redist\GdPicture.NET (.NET Framework 4.5)\GdPicture.NET.14.dll</HintPath> <HintPath>..\packages\GdPicture.14.2.89\lib\net462\GdPicture.NET.14.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL"> <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
@@ -287,4 +289,11 @@
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<Import Project="..\packages\GdPicture.runtimes.windows.14.2.89\build\net462\GdPicture.runtimes.windows.targets" Condition="Exists('..\packages\GdPicture.runtimes.windows.14.2.89\build\net462\GdPicture.runtimes.windows.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\GdPicture.runtimes.windows.14.2.89\build\net462\GdPicture.runtimes.windows.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\GdPicture.runtimes.windows.14.2.89\build\net462\GdPicture.runtimes.windows.targets'))" />
</Target>
</Project> </Project>

View File

@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
' indem Sie "*" wie unten gezeigt eingeben: ' indem Sie "*" wie unten gezeigt eingeben:
' <Assembly: AssemblyVersion("1.0.*")> ' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.9.2.0")> <Assembly: AssemblyVersion("1.9.3.0")>
<Assembly: AssemblyFileVersion("1.9.2.0")> <Assembly: AssemblyFileVersion("1.9.3.0")>

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="GdPicture" version="14.2.89" targetFramework="net462" />
<package id="GdPicture.runtimes.windows" version="14.2.89" targetFramework="net462" />
<package id="Microsoft.Extensions.Logging.Abstractions" version="2.1.1" targetFramework="net462" /> <package id="Microsoft.Extensions.Logging.Abstractions" version="2.1.1" targetFramework="net462" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net462" /> <package id="Newtonsoft.Json" version="13.0.3" targetFramework="net462" />
<package id="Quartz" version="3.8.0" targetFramework="net462" /> <package id="Quartz" version="3.8.0" targetFramework="net462" />

View File

@@ -0,0 +1,52 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using DigitalData.Core.Abstractions;
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
namespace EnvelopeGenerator.Domain.Entities
{
[Table("TBSIG_ENVELOPE_RECEIVER_READ_ONLY")]
public class EnvelopeReceiverReadOnly : IUnique<long>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("GUID")]
public long Id { get; init; }
[Column("ENVELOPE_ID")]
[Required]
public long EnvelopeId { get; init; }
//TODO: remove NotMapped attribute when EnvelopeId data type is standardized
[NotMapped]
public Envelope? Envelope { get; set; }
[Column("RECEIVER_MAIL")]
[Required]
[StringLength(250)]
[TemplatePlaceholder("NAME_RECEIVER")]
public required string ReceiverMail { get; init; }
[Column("DATE_VALID")]
[Required]
public DateTime DateValid { get; init; }
[Column("ADDED_WHO")]
[Required]
[StringLength(100)]
public required string AddedWho { get; init; }
public Receiver? Receiver { get; init; }
[Column("ADDED_WHEN")]
[Required]
public DateTime AddedWhen { get; init; }
[Column("CHANGED_WHO")]
[StringLength(100)]
public string? ChangedWho { get; init; }
[Column("CHANGED_WHEN")]
public DateTime? ChangedWhen { get; init; }
}
}

View File

@@ -1,12 +1,9 @@
using Microsoft.Extensions.Logging; using System.Text;
using System.Text; using static EnvelopeGenerator.Common.Constants;
namespace EnvelopeGenerator.Application namespace EnvelopeGenerator.Extensions
{ {
/// <summary> public static class DecodingExtensions
/// Provides extension methods for decoding and extracting information from an envelope receiver ID.
/// </summary>
public static class EnvelopeGeneratorExtensions
{ {
/// <summary> /// <summary>
/// Validates whether a given string is a correctly formatted Base-64 encoded string. /// Validates whether a given string is a correctly formatted Base-64 encoded string.
@@ -67,6 +64,40 @@ namespace EnvelopeGenerator.Application
return input.IndexOf('=') == -1; // No padding allowed except at the end return input.IndexOf('=') == -1; // No padding allowed except at the end
} }
public static bool TryDecode(this string encodedKey, out string[] decodedKeys)
{
try
{
byte[] bytes = Convert.FromBase64String(encodedKey);
string decodedString = Encoding.UTF8.GetString(bytes);
decodedKeys = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
return true;
}
catch(ArgumentNullException) { }
catch (FormatException) { }
catch(ArgumentException) { }
decodedKeys = Array.Empty<string>();
return false;
}
public static EncodeType GetEncodeType(this string[] decodedKeys) => decodedKeys.Length switch
{
2 => EncodeType.EnvelopeReceiver,
3 => long.TryParse(decodedKeys[1], out var _) ? EncodeType.EnvelopeReceiverReadOnly : EncodeType.Undefined,
_ => EncodeType.Undefined,
};
public static (string? EnvelopeUuid, string? ReceiverSignature) ParseEnvelopeReceiverId(this string[] decodedKeys)
=> decodedKeys.GetEncodeType() == EncodeType.EnvelopeReceiver
? (EnvelopeUuid: decodedKeys[0], ReceiverSignature: decodedKeys[1])
: throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver.");
public static long ParseReadOnlyId(this string[] decodedKeys)
=> decodedKeys.GetEncodeType() == EncodeType.EnvelopeReceiverReadOnly
? long.Parse(decodedKeys[1])
: throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver. ");
/// <summary> /// <summary>
/// Decodes the envelope receiver ID and extracts the envelope UUID and receiver signature. /// Decodes the envelope receiver ID and extracts the envelope UUID and receiver signature.
/// </summary> /// </summary>
@@ -79,7 +110,7 @@ namespace EnvelopeGenerator.Application
return (null, null); return (null, null);
} }
byte[] bytes = Convert.FromBase64String(envelopeReceiverId); byte[] bytes = Convert.FromBase64String(envelopeReceiverId);
string decodedString = System.Text.Encoding.UTF8.GetString(bytes); string decodedString = Encoding.UTF8.GetString(bytes);
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None); string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
if (parts.Length > 1) if (parts.Length > 1)
@@ -88,6 +119,22 @@ namespace EnvelopeGenerator.Application
return (string.Empty, string.Empty); return (string.Empty, string.Empty);
} }
public static long? DecodeEnvelopeReceiverReadOnlyId(this string envelopeReceiverReadOnlyId)
{
if (!envelopeReceiverReadOnlyId.IsBase64String())
{
return null;
}
byte[] bytes = Convert.FromBase64String(envelopeReceiverReadOnlyId);
string decodedString = System.Text.Encoding.UTF8.GetString(bytes);
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
if (parts.Length > 2)
return long.TryParse(parts[1], out long readOnlyId) ? readOnlyId : null;
else
return null;
}
/// <summary> /// <summary>
/// Gets the envelope UUID from the decoded envelope receiver ID. /// Gets the envelope UUID from the decoded envelope receiver ID.
/// </summary> /// </summary>
@@ -101,48 +148,5 @@ namespace EnvelopeGenerator.Application
/// <param name="envelopeReceiverId">The base64 encoded string to decode.</param> /// <param name="envelopeReceiverId">The base64 encoded string to decode.</param>
/// <returns>The receiver signature.</returns> /// <returns>The receiver signature.</returns>
public static string? GetReceiverSignature(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().ReceiverSignature; public static string? GetReceiverSignature(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().ReceiverSignature;
public static string EncodeEnvelopeReceiverId(this (string envelopeUuid, string receiverSignature) input)
{
string combinedString = $"{input.envelopeUuid}::{input.receiverSignature}";
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
string base64String = Convert.ToBase64String(bytes);
return base64String;
}
public static void LogEnvelopeError(this ILogger logger, string envelopeReceiverId, Exception? exception = null, string? message = null, params object?[] args)
{
var sb = new StringBuilder().AppendLine(envelopeReceiverId.DecodeEnvelopeReceiverId().ToTitle());
if (message is not null)
sb.AppendLine(message);
if(exception is null)
logger.Log(LogLevel.Error, sb.ToString(), args);
else
logger.Log(LogLevel.Error, exception, sb.AppendLine(exception.Message).ToString(), args);
}
public static void LogEnvelopeError(this ILogger logger, string? uuid, string? signature = null, Exception? exception = null, string? message = null, params object?[] args)
{
var sb = new StringBuilder($"Envelope Uuid: {uuid}");
if(signature is not null)
sb.AppendLine().Append($"Receiver Signature: {signature}");
if (message is not null)
sb.AppendLine().Append(message);
if (exception is null)
logger.Log(LogLevel.Error, sb.ToString(), args);
else
logger.Log(LogLevel.Error, exception, sb.ToString(), args);
}
public static string ToTitle(this (string? UUID, string? Signature) envelopeReceiverTuple)
{
return $"UUID is {envelopeReceiverTuple.UUID} and signature is {envelopeReceiverTuple.Signature}";
}
} }
} }

View File

@@ -0,0 +1,30 @@
using Microsoft.Extensions.Logging;
using System.Text;
namespace EnvelopeGenerator.Extensions
{
/// <summary>
/// Provides extension methods for decoding and extracting information from an envelope receiver ID.
/// </summary>
public static class EncodingExtensions
{
public static string EncodeEnvelopeReceiverId(this long readOnlyId)
{
//The random number is used as a salt to increase security but it is not saved in the database.
string combinedString = $"{Random.Shared.Next()}::{readOnlyId}::{Random.Shared.Next()}";
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
string base64String = Convert.ToBase64String(bytes);
return base64String;
}
public static string EncodeEnvelopeReceiverId(this (string envelopeUuid, string receiverSignature) input)
{
string combinedString = $"{input.envelopeUuid}::{input.receiverSignature}";
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
string base64String = Convert.ToBase64String(bytes);
return base64String;
}
}
}

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HtmlSanitizer" Version="8.0.865" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="7.0.19" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EnvelopeGenerator.Common\EnvelopeGenerator.Common.vbproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,42 @@
using Microsoft.Extensions.Logging;
using System.Text;
namespace EnvelopeGenerator.Extensions
{
public static class LoggerExtensions
{
public static void LogEnvelopeError(this ILogger logger, string envelopeReceiverId, Exception? exception = null, string? message = null, params object?[] args)
{
var sb = new StringBuilder().AppendLine(envelopeReceiverId.DecodeEnvelopeReceiverId().ToTitle());
if (message is not null)
sb.AppendLine(message);
if (exception is null)
logger.Log(LogLevel.Error, sb.ToString(), args);
else
logger.Log(LogLevel.Error, exception, sb.AppendLine(exception.Message).ToString(), args);
}
public static void LogEnvelopeError(this ILogger logger, string? uuid, string? signature = null, Exception? exception = null, string? message = null, params object?[] args)
{
var sb = new StringBuilder($"Envelope Uuid: {uuid}");
if (signature is not null)
sb.AppendLine().Append($"Receiver Signature: {signature}");
if (message is not null)
sb.AppendLine().Append(message);
if (exception is null)
logger.Log(LogLevel.Error, sb.ToString(), args);
else
logger.Log(LogLevel.Error, exception, sb.ToString(), args);
}
public static string ToTitle(this (string? UUID, string? Signature) envelopeReceiverTuple)
{
return $"UUID is {envelopeReceiverTuple.UUID} and signature is {envelopeReceiverTuple.Signature}";
}
}
}

View File

@@ -2,7 +2,7 @@
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
namespace EnvelopeGenerator.Web namespace EnvelopeGenerator.Extensions
{ {
public static class XSSExtensions public static class XSSExtensions
{ {

View File

@@ -14,6 +14,8 @@
<OptionCompare>Binary</OptionCompare> <OptionCompare>Binary</OptionCompare>
<OptionStrict>Off</OptionStrict> <OptionStrict>Off</OptionStrict>
<OptionInfer>On</OptionInfer> <OptionInfer>On</OptionInfer>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@@ -97,8 +99,8 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\EnvelopeGenerator.Common\bin\Debug\EnvelopeGenerator.Common.dll</HintPath> <HintPath>..\EnvelopeGenerator.Common\bin\Debug\EnvelopeGenerator.Common.dll</HintPath>
</Reference> </Reference>
<Reference Include="GdPicture.NET.14"> <Reference Include="GdPicture.NET.14, Version=14.2.89.0, Culture=neutral, PublicKeyToken=f52a2e60ad468dbb, processorArchitecture=MSIL">
<HintPath>D:\ProgramFiles\GdPicture.NET 14\Redist\GdPicture.NET (.NET Framework 4.5)\GdPicture.NET.14.dll</HintPath> <HintPath>..\packages\GdPicture.14.2.89\lib\net462\GdPicture.NET.14.dll</HintPath>
</Reference> </Reference>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL"> <Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.5.0.5\lib\net46\NLog.dll</HintPath> <HintPath>..\packages\NLog.5.0.5\lib\net46\NLog.dll</HintPath>
@@ -269,6 +271,13 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<Import Project="..\packages\GdPicture.runtimes.windows.14.2.89\build\net462\GdPicture.runtimes.windows.targets" Condition="Exists('..\packages\GdPicture.runtimes.windows.14.2.89\build\net462\GdPicture.runtimes.windows.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\GdPicture.runtimes.windows.14.2.89\build\net462\GdPicture.runtimes.windows.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\GdPicture.runtimes.windows.14.2.89\build\net462\GdPicture.runtimes.windows.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">

View File

@@ -68,4 +68,12 @@
<!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> --> <!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> -->
</sharedListeners> </sharedListeners>
</system.diagnostics> </system.diagnostics>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="GdPicture.NET.14" publicKeyToken="f52a2e60ad468dbb" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-14.2.89.0" newVersion="14.2.89.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration> </configuration>

View File

@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="GdPicture" version="14.2.89" targetFramework="net462" />
<package id="GdPicture.runtimes.windows" version="14.2.89" targetFramework="net462" />
<package id="NLog" version="5.0.5" targetFramework="net462" /> <package id="NLog" version="5.0.5" targetFramework="net462" />
</packages> </packages>

View File

@@ -0,0 +1,9 @@
using DigitalData.Core.Abstractions.Infrastructure;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Infrastructure.Contracts
{
public interface IEnvelopeReceiverReadOnlyRepository : ICRUDRepository<EnvelopeReceiverReadOnly, long>
{
}
}

View File

@@ -51,6 +51,8 @@ namespace EnvelopeGenerator.Infrastructure
public DbSet<EmailOut> EMailOuts { get; set; } public DbSet<EmailOut> EMailOuts { get; set; }
public DbSet<EnvelopeReceiverReadOnly> EnvelopeReceiverReadOnlys { get; set; }
public EGDbContext(DbContextOptions<EGDbContext> options) : base(options) public EGDbContext(DbContextOptions<EGDbContext> options) : base(options)
{ {
UserReceivers = Set<UserReceiver>(); UserReceivers = Set<UserReceiver>();
@@ -72,6 +74,7 @@ namespace EnvelopeGenerator.Infrastructure
Users = Set<User>(); Users = Set<User>();
UserReps = Set<UserRep>(); UserReps = Set<UserRep>();
EMailOuts = Set<EmailOut>(); EMailOuts = Set<EmailOut>();
EnvelopeReceiverReadOnlys = Set<EnvelopeReceiverReadOnly>();
} }
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
@@ -126,12 +129,19 @@ namespace EnvelopeGenerator.Infrastructure
.HasForeignKey(eh => eh.UserReference) .HasForeignKey(eh => eh.UserReference)
.HasPrincipalKey(e => e.Email); .HasPrincipalKey(e => e.Email);
modelBuilder.Entity<EnvelopeReceiverReadOnly>()
.HasOne(erro => erro.Receiver)
.WithMany()
.HasForeignKey(erro => erro.AddedWho)
.HasPrincipalKey(r => r.EmailAddress);
// Configure entities to handle database triggers // Configure entities to handle database triggers
modelBuilder.Entity<Envelope>().ToTable(tb => tb.HasTrigger("TBSIG_ENVELOPE_HISTORY_AFT_INS")); modelBuilder.Entity<Envelope>().ToTable(tb => tb.HasTrigger("TBSIG_ENVELOPE_HISTORY_AFT_INS"));
modelBuilder.Entity<EnvelopeHistory>().ToTable(tb => tb.HasTrigger("TBSIG_ENVELOPE_HISTORY_AFT_INS")); modelBuilder.Entity<EnvelopeHistory>().ToTable(tb => tb.HasTrigger("TBSIG_ENVELOPE_HISTORY_AFT_INS"));
modelBuilder.Entity<EmailOut>().ToTable(tb => tb.HasTrigger("TBEMLP_EMAIL_OUT_AFT_INS")); modelBuilder.Entity<EmailOut>().ToTable(tb => tb.HasTrigger("TBEMLP_EMAIL_OUT_AFT_INS"));
modelBuilder.Entity<EmailOut>().ToTable(tb => tb.HasTrigger("TBEMLP_EMAIL_OUT_AFT_UPD")); modelBuilder.Entity<EmailOut>().ToTable(tb => tb.HasTrigger("TBEMLP_EMAIL_OUT_AFT_UPD"));
modelBuilder.Entity<EnvelopeReceiverReadOnly>().ToTable(tb => tb.HasTrigger("TBSIG_ENVELOPE_RECEIVER_READ_ONLY_UPD"));
//configure model builder for user manager tables //configure model builder for user manager tables
modelBuilder.ConfigureUserManager(); modelBuilder.ConfigureUserManager();

View File

@@ -0,0 +1,70 @@
using DigitalData.Core.Infrastructure;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
using Microsoft.EntityFrameworkCore;
namespace EnvelopeGenerator.Infrastructure.Repositories
{
public class EnvelopeReceiverReadOnlyRepository : CRUDRepository<EnvelopeReceiverReadOnly, long, EGDbContext>, IEnvelopeReceiverReadOnlyRepository
{
private readonly IEnvelopeRepository _envRepo;
public EnvelopeReceiverReadOnlyRepository(EGDbContext dbContext, IEnvelopeRepository envelopeRepository) : base(dbContext, dbContext.EnvelopeReceiverReadOnlys)
{
_envRepo = envelopeRepository;
}
protected override IQueryable<EnvelopeReceiverReadOnly> ReadOnly()
{
return base.ReadOnly()
//TODO: add again when EnvelopeId data type is standardized
//.Include(erro => erro.Envelope)
.Include(erro => erro.Receiver);
}
public async override Task<IEnumerable<EnvelopeReceiverReadOnly>> ReadAllAsync()
{
var erros = await base.ReadAllAsync();
return await IncludeEnvelope(erros);
}
public override async Task<EnvelopeReceiverReadOnly?> ReadByIdAsync(long id)
{
var erro = await _dbSet.AsNoTracking()
.Include(erro => erro.Receiver)
.Where(erro => erro.Id == id)
.FirstOrDefaultAsync();
return await IncludeEnvelope(erro);
}
//TODO: Use IQueryable.Include instead of this when ID type is clarified.
[Obsolete("Use IQueryable.Include instead of this when ID type is clarified.")]
private async Task<EnvelopeReceiverReadOnly> IncludeEnvelope(EnvelopeReceiverReadOnly erro)
{
erro.Envelope = await _envRepo.ReadByIdAsync((int)erro.EnvelopeId);
return erro;
}
//TODO: Use IQueryable.Include instead of this when ID type is clarified.
[Obsolete("Use IQueryable.Include instead of this when ID type is clarified.")]
private async Task<IEnumerable<EnvelopeReceiverReadOnly>> IncludeEnvelope(params EnvelopeReceiverReadOnly[] erros)
{
foreach (var erro in erros)
erro.Envelope = await _envRepo.ReadByIdAsync((int) erro.EnvelopeId);
return erros;
}
//TODO: Use IQueryable.Include instead of this when ID type is clarified.
[Obsolete("Use IQueryable.Include instead of this when ID type is clarified.")]
private async Task<T> IncludeEnvelope<T>(T erros)
where T : IEnumerable<EnvelopeReceiverReadOnly>
{
foreach (var erro in erros)
erro.Envelope = await _envRepo.ReadByIdAsync((int)erro.EnvelopeId);
return erros;
}
}
}

View File

@@ -18,6 +18,12 @@ namespace EnvelopeGenerator.Web.Controllers
public static string? GetAuthEnvelopeTitle(this ControllerBase controller) => controller.User.FindFirstValue(EnvelopeClaimTypes.Title); public static string? GetAuthEnvelopeTitle(this ControllerBase controller) => controller.User.FindFirstValue(EnvelopeClaimTypes.Title);
public static int? GetAuthEnvelopeId(this ControllerBase controller)
{
var env_id_str = controller.User.FindFirstValue(EnvelopeClaimTypes.Id);
return int.TryParse(env_id_str, out int env_id) ? env_id : null;
}
//TODO: integrate localizer for ready-to-use views //TODO: integrate localizer for ready-to-use views
public static ViewResult ViewError(this Controller controller, ErrorViewModel errorViewModel) => controller.View("_Error", errorViewModel); public static ViewResult ViewError(this Controller controller, ErrorViewModel errorViewModel) => controller.View("_Error", errorViewModel);

View File

@@ -4,6 +4,7 @@ using EnvelopeGenerator.Web.Services;
using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.Contracts;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using EnvelopeGenerator.Application; using EnvelopeGenerator.Application;
using EnvelopeGenerator.Extensions;
namespace EnvelopeGenerator.Web.Controllers namespace EnvelopeGenerator.Web.Controllers
{ {

View File

@@ -6,8 +6,8 @@ using EnvelopeGenerator.Web.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
using static EnvelopeGenerator.Common.Constants; using static EnvelopeGenerator.Common.Constants;
using EnvelopeGenerator.Extensions;
namespace EnvelopeGenerator.Web.Controllers namespace EnvelopeGenerator.Web.Controllers
{ {

View File

@@ -7,14 +7,16 @@ using Microsoft.AspNetCore.Mvc;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using DigitalData.Core.API; using DigitalData.Core.API;
using EnvelopeGenerator.Application; using EnvelopeGenerator.Extensions;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using DigitalData.Core.DTO; using DigitalData.Core.DTO;
using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Localization;
using System.Text.Encodings.Web;
using EnvelopeGenerator.Web.Models; using EnvelopeGenerator.Web.Models;
using EnvelopeGenerator.Application.Resources; using EnvelopeGenerator.Application.Resources;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using static EnvelopeGenerator.Common.Constants;
using Ganss.Xss;
using Newtonsoft.Json;
namespace EnvelopeGenerator.Web.Controllers namespace EnvelopeGenerator.Web.Controllers
{ {
@@ -26,29 +28,41 @@ namespace EnvelopeGenerator.Web.Controllers
private readonly IEnvelopeHistoryService _historyService; private readonly IEnvelopeHistoryService _historyService;
private readonly IStringLocalizer<Resource> _localizer; private readonly IStringLocalizer<Resource> _localizer;
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
private readonly UrlEncoder _urlEncoder; private readonly HtmlSanitizer _sanitizer;
private readonly Cultures _cultures; private readonly Cultures _cultures;
private readonly IEnvelopeMailService _mailService; private readonly IEnvelopeMailService _mailService;
private readonly IEnvelopeReceiverReadOnlyService _readOnlyService;
public HomeController(EnvelopeOldService envelopeOldService, ILogger<HomeController> logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer<Resource> localizer, IConfiguration configuration, UrlEncoder urlEncoder, Cultures cultures, IEnvelopeMailService envelopeMailService)
public HomeController(EnvelopeOldService envelopeOldService, ILogger<HomeController> logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer<Resource> localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService)
{ {
this.envelopeOldService = envelopeOldService; this.envelopeOldService = envelopeOldService;
_envRcvService = envelopeReceiverService; _envRcvService = envelopeReceiverService;
_historyService = historyService; _historyService = historyService;
_localizer = localizer; _localizer = localizer;
_configuration = configuration; _configuration = configuration;
_urlEncoder = urlEncoder; _sanitizer = sanitizer;
_cultures = cultures; _cultures = cultures;
_mailService = envelopeMailService; _mailService = envelopeMailService;
_logger = logger; _logger = logger;
} _readOnlyService = readOnlyService;
}
[HttpGet("EnvelopeKey/{envelopeReceiverId}")] [HttpGet("EnvelopeKey/{envelopeReceiverId}")]
public async Task<IActionResult> SendAccessCode([FromRoute] string envelopeReceiverId) public async Task<IActionResult> MainAsync([FromRoute] string envelopeReceiverId)
{ {
try try
{ {
envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId); envelopeReceiverId = _sanitizer.Sanitize(envelopeReceiverId);
if (!envelopeReceiverId.TryDecode(out var decoded))
{
Response.StatusCode = StatusCodes.Status401Unauthorized;
return this.ViewDocumentNotFound();
}
if(decoded.GetEncodeType() == EncodeType.EnvelopeReceiverReadOnly)
return Redirect($"{envelopeReceiverId}/ReadOnly");
ViewData["EnvelopeKey"] = envelopeReceiverId; ViewData["EnvelopeKey"] = envelopeReceiverId;
return await _envRcvService.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId: envelopeReceiverId).ThenAsync<EnvelopeReceiverDto, IActionResult>( return await _envRcvService.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId: envelopeReceiverId).ThenAsync<EnvelopeReceiverDto, IActionResult>(
@@ -89,8 +103,8 @@ namespace EnvelopeGenerator.Web.Controllers
{ {
try try
{ {
culture = culture is not null ? _urlEncoder.Encode(culture) : null; culture = culture is not null ? _sanitizer.Sanitize(culture) : null;
envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId); envelopeReceiverId = _sanitizer.Sanitize(envelopeReceiverId);
if (UserLanguage is null && culture is null) if (UserLanguage is null && culture is null)
{ {
@@ -125,7 +139,7 @@ namespace EnvelopeGenerator.Web.Controllers
{ {
ViewData["UserCulture"] = _cultures[UserLanguage]; ViewData["UserCulture"] = _cultures[UserLanguage];
envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId); envelopeReceiverId = _sanitizer.Sanitize(envelopeReceiverId);
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId(); (string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
if (uuid is null || signature is null) if (uuid is null || signature is null)
@@ -185,14 +199,15 @@ namespace EnvelopeGenerator.Web.Controllers
{ {
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: "No document was found."); _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: "No document was found.");
return this.ViewDocumentNotFound(); return this.ViewDocumentNotFound();
} }
var claims = new List<Claim> { var claims = new List<Claim> {
new(ClaimTypes.NameIdentifier, uuid), new(ClaimTypes.NameIdentifier, uuid),
new(ClaimTypes.Hash, signature), new(ClaimTypes.Hash, signature),
new(ClaimTypes.Name, er.Name ?? string.Empty), new(ClaimTypes.Name, er.Name ?? string.Empty),
new(ClaimTypes.Email, er.Receiver.EmailAddress), new(ClaimTypes.Email, er.Receiver.EmailAddress),
new(EnvelopeClaimTypes.Title, er.Envelope.Title) new(EnvelopeClaimTypes.Title, er.Envelope.Title),
new(EnvelopeClaimTypes.Id, er.Envelope.Id.ToString())
}; };
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
@@ -232,7 +247,7 @@ namespace EnvelopeGenerator.Web.Controllers
{ {
try try
{ {
envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId); envelopeReceiverId = _sanitizer.Sanitize(envelopeReceiverId);
return await _envRcvService.IsExisting(envelopeReceiverId: envelopeReceiverId).ThenAsync( return await _envRcvService.IsExisting(envelopeReceiverId: envelopeReceiverId).ThenAsync(
SuccessAsync: async isExisting => SuccessAsync: async isExisting =>
{ {
@@ -266,7 +281,7 @@ namespace EnvelopeGenerator.Web.Controllers
{ {
try try
{ {
envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId); envelopeReceiverId = _sanitizer.Sanitize(envelopeReceiverId);
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return await _envRcvService.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId).ThenAsync( return await _envRcvService.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId).ThenAsync(
@@ -290,7 +305,81 @@ namespace EnvelopeGenerator.Web.Controllers
return this.ViewInnerServiceError(); return this.ViewInnerServiceError();
} }
} }
[HttpGet("EnvelopeKey/{readOnlyKey}/ReadOnly")]
public async Task<IActionResult> EnvelopeReceiverReadOnly([FromRoute] string readOnlyKey)
{
try
{
readOnlyKey = _sanitizer.Sanitize(readOnlyKey);
// check if the readOnlyId is valid
if (!readOnlyKey.TryDecode(out var decodedKeys) || decodedKeys.GetEncodeType() != EncodeType.EnvelopeReceiverReadOnly)
{
Response.StatusCode = StatusCodes.Status401Unauthorized;
return this.ViewDocumentNotFound();
}
var readOnlyId = decodedKeys.ParseReadOnlyId();
var erro_res = await _readOnlyService.ReadByIdAsync(readOnlyId);
if (erro_res.IsFailed)
{
_logger.LogNotice(erro_res.Notices);
return this.ViewInnerServiceError();
}
var erro = erro_res.Data;
if (DateTime.Now > erro.DateValid)
return View("EnvelopeExpired");
return await _envRcvService.ReadByUuidSignatureAsync(uuid: erro.Envelope!.Uuid, erro.Receiver!.Signature).ThenAsync(
SuccessAsync: async er =>
{
var envelopeKey = (er.Envelope!.Uuid, er.Receiver!.Signature).EncodeEnvelopeReceiverId();
EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeKey);
//TODO: implement multi-threading to history process (Task)
var hist_res = await _historyService.RecordAsync((int)erro.EnvelopeId, erro.AddedWho, EnvelopeStatus.EnvelopeViewed);
if (hist_res.IsFailed)
{
_logger.LogError(
"Although the envelope was sent as read-only, the EnvelopeShared hisotry could not be saved. ReadOnly-key: {readOnlyKey}\nEnvelope Receiver:\n{envelopeReceiver}",
readOnlyKey, JsonConvert.SerializeObject(er));
_logger.LogNotice(hist_res.Notices);
}
if (response.Envelope.Documents.Count > 0)
{
var document = await envelopeOldService.GetDocument(response.Envelope.Documents[0].Id, envelopeKey);
byte[] bytes = await envelopeOldService.GetDocumentContents(document);
ViewData["EnvelopeKey"] = envelopeKey;
ViewData["DocumentBytes"] = bytes;
ViewData["IsReadOnly"] = true;
ViewData["ReadOnly"] = erro;
ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"];
return View("ShowEnvelope", er);
}
else
{
_logger.LogEnvelopeError(envelopeReceiverId: envelopeKey, message: "No document was found.");
return this.ViewDocumentNotFound();
}
},
Fail: (messages, notices) =>
{
_logger.LogNotice(notices);
return this.ViewEnvelopeNotFound();
});
}
catch (Exception ex)
{
_logger.LogError(ex, "An unexpected error occurred while displaying a read-only envelope. Read-only key is {readOnlyKey}. {message}", readOnlyKey, ex.Message);
return this.ViewInnerServiceError();
}
}
[Authorize] [Authorize]
[HttpGet("IsAuthenticated")] [HttpGet("IsAuthenticated")]
public IActionResult IsAuthenticated() public IActionResult IsAuthenticated()
@@ -305,7 +394,7 @@ namespace EnvelopeGenerator.Web.Controllers
{ {
try try
{ {
language = _urlEncoder.Encode(language); language = _sanitizer.Sanitize(language);
if (!_cultures.Languages.Contains(language)) if (!_cultures.Languages.Contains(language))
return BadRequest(); return BadRequest();

View File

@@ -0,0 +1,102 @@
using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace EnvelopeGenerator.Web.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ReadOnlyController : ControllerBase
{
private readonly ILogger<ReadOnlyController> _logger;
private readonly IEnvelopeReceiverReadOnlyService _erroService;
private readonly IEnvelopeMailService _mailService;
private readonly IEnvelopeHistoryService _histService;
public ReadOnlyController(ILogger<ReadOnlyController> logger, IEnvelopeReceiverReadOnlyService erroService, IEnvelopeMailService mailService, IEnvelopeHistoryService histService)
{
_logger = logger;
_erroService = erroService;
_mailService = mailService;
_histService = histService;
}
[HttpPost]
[Authorize]
public async Task<IActionResult> CreateAsync([FromBody] EnvelopeReceiverReadOnlyCreateDto createDto)
{
try
{
//set AddedWho
var authReceiverMail = this.GetAuthReceiverMail();
if (authReceiverMail is null)
{
_logger.LogError("Email clam is not found in envelope-receiver-read-only creation process. Create DTO is:\n {dto}", JsonConvert.SerializeObject(createDto));
return Unauthorized();
}
var envelopeId = this.GetAuthEnvelopeId();
if (envelopeId is null)
{
_logger.LogError("Envelope Id clam is not found in envelope-receiver-read-only creation process. Create DTO is:\n {dto}", JsonConvert.SerializeObject(createDto));
return Unauthorized();
}
createDto.AddedWho = authReceiverMail;
createDto.EnvelopeId = envelopeId;
// create entity
var creation_res = await _erroService.CreateAsync(createDto: createDto);
if (creation_res.IsFailed)
{
_logger.LogNotice(creation_res);
return StatusCode(StatusCodes.Status500InternalServerError);
}
//read new entity
var read_res = await _erroService.ReadByIdAsync(creation_res.Data);
if (read_res.IsFailed)
{
_logger.LogNotice(creation_res);
return StatusCode(StatusCodes.Status500InternalServerError);
}
var new_erro = read_res.Data;
//send email two receiver
return await _mailService.SendAsync(new_erro).ThenAsync<int, IActionResult>(SuccessAsync: async res =>
{
//TODO: implement multi-threading to history process (Task)
//TODO: remove casting after change the id type
var hist_res = await _histService.RecordAsync((int)createDto.EnvelopeId, createDto.AddedWho, Common.Constants.EnvelopeStatus.EnvelopeShared);
if (hist_res.IsFailed)
{
_logger.LogError("Although the envelope was sent as read-only, the EnvelopeShared hisotry could not be saved. Create DTO:\n{createDto}", JsonConvert.SerializeObject(createDto));
_logger.LogNotice(hist_res.Notices);
}
return Ok();
},
Fail: (msg, ntc) =>
{
_logger.LogNotice(ntc);
return StatusCode(StatusCodes.Status500InternalServerError);
});
}
catch(Exception ex)
{
_logger.LogError(ex, "{Message}", ex.Message);
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
}

View File

@@ -1,8 +1,8 @@
using EnvelopeGenerator.Application; using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs; using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Domain.Entities;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using EnvelopeGenerator.Extensions;
namespace EnvelopeGenerator.Web.Controllers.Test namespace EnvelopeGenerator.Web.Controllers.Test
{ {

View File

@@ -1,7 +1,7 @@
using DigitalData.Core.API; using DigitalData.Core.API;
using DigitalData.Core.DTO; using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application; using EnvelopeGenerator.Extensions;
using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Domain.Entities;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
@@ -40,13 +40,27 @@ namespace EnvelopeGenerator.Web.Controllers.Test
} }
[HttpGet("decode")] [HttpGet("decode")]
public IActionResult DecodeEnvelopeReceiverId(string envelopeReceiverId) public IActionResult DecodeEnvelopeReceiverId(string envelopeReceiverId, bool isReadOnly = false)
{ {
var decoded = envelopeReceiverId.DecodeEnvelopeReceiverId(); if (isReadOnly)
return Ok(new { uuid = decoded.EnvelopeUuid, signature = decoded.ReceiverSignature }); {
var readOnlyId = envelopeReceiverId.DecodeEnvelopeReceiverReadOnlyId();
return Ok(new { readOnlyId });
}
else
{
var (EnvelopeUuid, ReceiverSignature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
return Ok(new { uuid = EnvelopeUuid, signature = ReceiverSignature });
}
} }
[HttpGet("encode")] [HttpGet("encode")]
public IActionResult EncodeEnvelopeReceiverId(string uuid, string signature) => Ok((uuid, signature).EncodeEnvelopeReceiverId()); public IActionResult EncodeEnvelopeReceiverId(string? uuid = null, string? signature = null, long? readOnlyId = null)
{
if(readOnlyId is long readOnlyId_long)
return Ok(readOnlyId_long.EncodeEnvelopeReceiverId());
else
return Ok((uuid ?? string.Empty, signature ?? string.Empty).EncodeEnvelopeReceiverId());
}
} }
} }

View File

@@ -9,5 +9,10 @@
/// Claim type for the title of an envelope. /// Claim type for the title of an envelope.
/// </summary> /// </summary>
public static readonly string Title = $"Envelope{nameof(Title)}"; public static readonly string Title = $"Envelope{nameof(Title)}";
/// <summary>
/// Claim type for the ID of an envelope.
/// </summary>
public static readonly string Id = $"Envelope{nameof(Id)}";
} }
} }

View File

@@ -5,7 +5,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<PackageId>EnvelopeGenerator.Web</PackageId> <PackageId>EnvelopeGenerator.Web</PackageId>
<Version>2.0.0.0</Version> <Version>2.1.1.0</Version>
<Authors>Digital Data GmbH</Authors> <Authors>Digital Data GmbH</Authors>
<Company>Digital Data GmbH</Company> <Company>Digital Data GmbH</Company>
<Product>EnvelopeGenerator.Web</Product> <Product>EnvelopeGenerator.Web</Product>
@@ -13,8 +13,9 @@
<PackageTags>digital data envelope generator web</PackageTags> <PackageTags>digital data envelope generator web</PackageTags>
<Description>EnvelopeGenerator.Web is an ASP.NET MVC application developed to manage signing processes. It uses Entity Framework Core (EF Core) for database operations. The user interface for signing processes is developed with Razor View Engine (.cshtml files) and JavaScript under wwwroot, integrated with PSPDFKit. This integration allows users to view and sign documents seamlessly.</Description> <Description>EnvelopeGenerator.Web is an ASP.NET MVC application developed to manage signing processes. It uses Entity Framework Core (EF Core) for database operations. The user interface for signing processes is developed with Razor View Engine (.cshtml files) and JavaScript under wwwroot, integrated with PSPDFKit. This integration allows users to view and sign documents seamlessly.</Description>
<ApplicationIcon>Assets\icon.ico</ApplicationIcon> <ApplicationIcon>Assets\icon.ico</ApplicationIcon>
<AssemblyVersion>2.0.0.0</AssemblyVersion> <AssemblyVersion>2.1.1.0</AssemblyVersion>
<FileVersion>2.0.0.0</FileVersion> <FileVersion>2.1.1.0</FileVersion>
<Copyright>Copyright © 2024 Digital Data GmbH. All rights reserved.</Copyright>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -70,6 +71,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" /> <ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
<ProjectReference Include="..\EnvelopeGenerator.Common\EnvelopeGenerator.Common.vbproj" /> <ProjectReference Include="..\EnvelopeGenerator.Common\EnvelopeGenerator.Common.vbproj" />
<ProjectReference Include="..\EnvelopeGenerator.Extensions\EnvelopeGenerator.Extensions.csproj" />
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" /> <ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -83,7 +83,7 @@ try
builder.Services.AddDbContext<EGDbContext>(options => options.UseSqlServer(connStr)); builder.Services.AddDbContext<EGDbContext>(options => options.UseSqlServer(connStr));
// Add envelope generator services // Add envelope generator services
builder.Services.AddEnvelopeGenerator(); builder.Services.AddEnvelopeGenerator(config);
builder.Services.Configure<CookiePolicyOptions>(options => builder.Services.Configure<CookiePolicyOptions>(options =>
{ {
@@ -157,8 +157,6 @@ try
builder.Services.AddMemoryCache(); builder.Services.AddMemoryCache();
builder.ConfigureBySection<DispatcherConfig>();
builder.ConfigureBySection<Logo>(); builder.ConfigureBySection<Logo>();
var app = builder.Build(); var app = builder.Build();

View File

@@ -0,0 +1,24 @@
@{
ViewData["Title"] = "Abgelaufen";
}
<div class="page container p-5">
<header class="text-center">
<div class="icon expired">
<svg width="72" height="72" viewBox="0 0 48 48" version="1" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 48 48">
<circle fill="#00ACC1" cx="17" cy="17" r="14" />
<circle fill="#eee" cx="17" cy="17" r="11" />
<rect x="16" y="8" width="2" height="9" />
<rect x="18.2" y="16" transform="matrix(-.707 .707 -.707 -.707 46.834 19.399)" width="2.4" height="6.8" />
<circle cx="17" cy="17" r="2" />
<circle fill="#00ACC1" cx="17" cy="17" r="1" />
<path fill="#FFC107" d="M11.9,42l14.4-24.1c0.8-1.3,2.7-1.3,3.4,0L44.1,42c0.8,1.3-0.2,3-1.7,3H13.6C12.1,45,11.1,43.3,11.9,42z" />
<path fill="#263238" d="M26.4,39.9c0-0.2,0-0.4,0.1-0.6s0.2-0.3,0.3-0.5s0.3-0.2,0.5-0.3s0.4-0.1,0.6-0.1s0.5,0,0.7,0.1 s0.4,0.2,0.5,0.3s0.2,0.3,0.3,0.5s0.1,0.4,0.1,0.6s0,0.4-0.1,0.6s-0.2,0.3-0.3,0.5s-0.3,0.2-0.5,0.3s-0.4,0.1-0.7,0.1 s-0.5,0-0.6-0.1s-0.4-0.2-0.5-0.3s-0.2-0.3-0.3-0.5S26.4,40.1,26.4,39.9z M29.2,36.8h-2.3L26.5,27h3L29.2,36.8z" />
</svg>
</div>
<h1>Abgelaufen!</h1>
</header>
<section class="text-center">
<p>Der Zeitraum für die gemeinsame Nutzung von Dokumenten ist abgelaufen.</p>
</section>
</div>
<footer class="container" id="page-footer">&copy; SignFlow 2023-2024 <a href="https://digitaldata.works">Digital Data GmbH</a></footer>

View File

@@ -23,45 +23,46 @@
<section class="text-center"> <section class="text-center">
<p>@_localizer[WebKey.LockedBody]</p> <p>@_localizer[WebKey.LockedBody]</p>
</section> </section>
<div class="row m-0 p-0 justify-content-center"> <div class="row m-0 p-0">
<div class="col-8 pe-0"> <div class="access-code-panel justify-content-center align-items-center p-0 m-0">
<form id="form-access-code" class="form" method="post"> <form id="form-access-code" class="form form-floating mb-0" method="post">
<div class="input"> <div class="form-floating access-code-form-floating">
<label class="visually-hidden" for="access_code">@_localizer[WebKey.LockedTitle]</label>
<input type="password" id="access_code" class="form-control" name="access_code" placeholder="@_localizer[WebKey.LockedAccessCode]" required="required"> <input type="password" id="access_code" class="form-control" name="access_code" placeholder="@_localizer[WebKey.LockedAccessCode]" required="required">
<div id="access-code-error-message" class="text-danger" style="height: 20px;"> <label for="access_code">@_localizer[WebKey.LockedAccessCode]</label>
@if (ViewData["ErrorMessage"] is string errMsg) <button type="submit" class="btn btn-primary">
{ <span class="material-symbols-outlined">
@_sanitizer.Sanitize(errMsg) login
} </span>
</div> </button>
</div> </div>
<div class="button"> <div class="dropdown flag-dropdown">
<button type="submit" class="btn btn-primary">@_localizer[WebKey.LocakedOpen]</button> <button class="btn btn-outline-secondary dropdown-toggle" type="button" id="langDropdownMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
<span class="fi @userCulture?.FIClass.TrySanitize(_sanitizer) me-2" id="selectedFlag"></span><span id="selectedLanguage"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="langDropdownMenuButton">
@foreach (var culture in _cultures)
{
var lang = culture.Language;
var info = culture.Info;
<li>
<a class="dropdown-item" data-language="@lang.TrySanitize(_sanitizer)" data-flag="@_cultures[lang]?.FIClass.TrySanitize(_sanitizer)">
<span class="fi @_cultures[lang]?.FIClass.TrySanitize(_sanitizer) me-2"></span>@info?.Parent.NativeName
</a>
</li>
}
</ul>
</div> </div>
</form> </form>
</div> </div>
<div class="col-4 mb-3 d-flex justify-content-center align-items-center">
<div class="dropdown">
<button class="btn btn-outline-secondary dropdown-toggle" type="button" id="langDropdownMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
<span class="fi @userCulture?.FIClass.TrySanitize(_sanitizer) me-2" id="selectedFlag"></span><span id="selectedLanguage"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="langDropdownMenuButton">
@foreach(var culture in _cultures)
{
var lang = culture.Language;
var info = culture.Info;
<li>
<a class="dropdown-item" data-language="@lang.TrySanitize(_sanitizer)" data-flag="@_cultures[lang]?.FIClass.TrySanitize(_sanitizer)">
<span class="fi @_cultures[lang]?.FIClass.TrySanitize(_sanitizer) me-2"></span>@info?.Parent.NativeName
</a>
</li>
}
</ul>
</div>
</div>
</div> </div>
<section class="text-center"> @if (ViewData["ErrorMessage"] is string errMsg)
{
<div id="access-code-error-message" class="alert alert-danger row" role="alert">
@_sanitizer.Sanitize(errMsg)
</div>
}
<section class="no-receiver-explanation text-center">
<details> <details>
<summary>@_localizer[WebKey.LockedFooterTitle]</summary> <summary>@_localizer[WebKey.LockedFooterTitle]</summary>
<p>@_localizer[WebKey.LockedFooterBody]</p> <p>@_localizer[WebKey.LockedFooterBody]</p>

View File

@@ -5,6 +5,7 @@
@using DigitalData.Core.DTO; @using DigitalData.Core.DTO;
@using EnvelopeGenerator.Application.DTOs; @using EnvelopeGenerator.Application.DTOs;
@using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver @using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver
@using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly
@using Newtonsoft.Json @using Newtonsoft.Json
@using Newtonsoft.Json.Serialization @using Newtonsoft.Json.Serialization
@model EnvelopeReceiverDto; @model EnvelopeReceiverDto;
@@ -15,79 +16,182 @@
@{ @{
var userCulture = ViewData["UserCulture"] as Culture; var userCulture = ViewData["UserCulture"] as Culture;
var envelope = Model.Envelope; var envelope = Model.Envelope;
var receiver_name = Model.Name;
var document = Model.Envelope?.Documents?.FirstOrDefault(); var document = Model.Envelope?.Documents?.FirstOrDefault();
var sender = Model.Envelope?.User; var sender = Model.Envelope?.User;
var pages = document?.Elements?.Select(e => e.Page) ?? Array.Empty<int>(); var pages = document?.Elements?.Select(e => e.Page) ?? Array.Empty<int>();
int? signatureCount = document?.Elements?.Count();
var stPageIndexes = string.Join(pages.Count() > 1 ? ", " : "", pages.Take(pages.Count() - 1)) var stPageIndexes = string.Join(pages.Count() > 1 ? ", " : "", pages.Take(pages.Count() - 1))
+ (pages.Count() > 1 ? $" {_localizer[WebKey.and].TrySanitize(_sanitizer)} " : "") + pages.LastOrDefault(); + (pages.Count() > 1 ? $" {_localizer[WebKey.and].TrySanitize(_sanitizer)} " : "") + pages.LastOrDefault();
var isReadOnly = false;
if (ViewData["IsReadOnly"] is bool isReadOnly_bool)
isReadOnly = isReadOnly_bool;
} }
<div class="d-flex flex-column min-vh-100"> <div class="envelope-view">
<nav class="navbar navbar-light bg-light"> @if (!isReadOnly)
<div class="container"> {
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarToggleExternalContent" aria-controls="navbarToggleExternalContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="material-symbols-outlined">
more_vert
</span>
</button>
<div class="envelope-message">
<span class="icon material-symbols-outlined">history_edu</span>
<span class="message navbar-brand">@($"{_localizer[WebKey.Hello]} {Model.Name}, {@envelope?.Message}".TrySanitize(_sanitizer))</span>
</div>
<div class="logo">
<img class="@logo.ShowPageClass" src="@logo.Src" alt="logo">
</div>
</div>
</nav>
<div class="collapse show bg-light " id="navbarToggleExternalContent" data-bs-theme="light">
<div class="card sender-card p-1 mb-3">
<div class="row g-0">
<div class="col p-0 m-0">
<div class="card-body p-0 m-0 ms-4">
<h5 class="card-title p-0 m-0">
<span class="signature-process-title">@($"{_localizer[WebKey.SigningProcessTitle]}: ".TrySanitize(_sanitizer))</span>
<span class="signature-process-name">@($"{envelope?.Title}".TrySanitize(_sanitizer))</span>
</h5>
<p class="card-text p-0 m-0">@Html.Raw(string.Format(_localizer[WebKey.EnvelopeInfo1], pages.Count(), stPageIndexes).TrySanitize(_hlSanitizer))</p>
<p class="card-text p-0 m-0">
<small class="text-body-secondary">
@Html.Raw(string.Format(_localizer[WebKey.EnvelopeInfo2], /* sanitize separately but don't sanitize the URI */
envelope?.AddedWhen.ToString(userCulture?.Info?.DateTimeFormat).TrySanitize(_sanitizer),
$"{sender?.Prename} {sender?.Name}".TrySanitize(_sanitizer),
sender?.Email.TrySanitize(_sanitizer),
envelope?.Title.TrySanitize(_sanitizer),
sender?.Prename.TrySanitize(_sanitizer),
sender?.Name.TrySanitize(_sanitizer),
sender?.Email.TrySanitize(_sanitizer)))
</small>
</p>
</div>
</div>
</div>
</div>
</div>
<div id="flex-action-panel" class="btn-group btn_group position-fixed bottom-0 end-0 d-flex align-items-center" role="group" aria-label="Basic mixed styles example"> <div id="flex-action-panel" class="btn-group btn_group position-fixed bottom-0 end-0 d-flex align-items-center" role="group" aria-label="Basic mixed styles example">
<button class="btn_complete btn btn-primary" type="button"> <button class="btn_complete btn btn-primary btn-desktop" type="button">
<svg class="icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 16"> <svg class="icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 16">
<path d="m10.036 8.278 9.258-7.79A1.979 1.979 0 0 0 18 0H2A1.987 1.987 0 0 0 .641.541l9.395 7.737Z" /> <path d="m10.036 8.278 9.258-7.79A1.979 1.979 0 0 0 18 0H2A1.987 1.987 0 0 0 .641.541l9.395 7.737Z" />
<path d="M11.241 9.817c-.36.275-.801.425-1.255.427-.428 0-.845-.138-1.187-.395L0 2.6V14a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V2.5l-8.759 7.317Z" /> <path d="M11.241 9.817c-.36.275-.801.425-1.255.427-.428 0-.845-.138-1.187-.395L0 2.6V14a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V2.5l-8.759 7.317Z" />
</svg> </svg>
<span>@_localizer[WebKey.Complete]</span> <span>@_localizer[WebKey.Complete]</span>
</button> </button>
<button class="btn_reject btn btn-danger" type="button"> <button class="btn_reject btn btn-danger btn-desktop" type="button">
<svg width="25px" height="25px" viewBox="43.5 43.5 512 512" version="1.1" fill="currentColor" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <svg width="25px" height="25px" viewBox="43.5 43.5 512 512" version="1.1" fill="currentColor" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path class="st0" d="M263.24,43.5c-117.36,0-212.5,95.14-212.5,212.5s95.14,212.5,212.5,212.5s212.5-95.14,212.5-212.5 S380.6,43.5,263.24,43.5z M367.83,298.36c17.18,17.18,17.18,45.04,0,62.23v0c-17.18,17.18-45.04,17.18-62.23,0l-42.36-42.36 l-42.36,42.36c-17.18,17.18-45.04,17.18-62.23,0v0c-17.18-17.18-17.18-45.04,0-62.23L201.01,256l-42.36-42.36 c-17.18-17.18-17.18-45.04,0-62.23v0c17.18-17.18,45.04-17.18,62.23,0l42.36,42.36l42.36-42.36c17.18-17.18,45.04-17.18,62.23,0v0 c17.18,17.18,17.18,45.04,0,62.23L325.46,256L367.83,298.36z" /> <path class="st0" d="M263.24,43.5c-117.36,0-212.5,95.14-212.5,212.5s95.14,212.5,212.5,212.5s212.5-95.14,212.5-212.5 S380.6,43.5,263.24,43.5z M367.83,298.36c17.18,17.18,17.18,45.04,0,62.23v0c-17.18,17.18-45.04,17.18-62.23,0l-42.36-42.36 l-42.36,42.36c-17.18,17.18-45.04,17.18-62.23,0v0c-17.18-17.18-17.18-45.04,0-62.23L201.01,256l-42.36-42.36 c-17.18-17.18-17.18-45.04,0-62.23v0c17.18-17.18,45.04-17.18,62.23,0l42.36,42.36l42.36-42.36c17.18-17.18,45.04-17.18,62.23,0v0 c17.18,17.18,17.18,45.04,0,62.23L325.46,256L367.83,298.36z" />
</svg> </svg>
<span>@_localizer[WebKey.Reject]</span> <span>@_localizer[WebKey.Reject]</span>
</button> </button>
<button class="btn_refresh btn btn-secondary" type="button"> <button class="btn_refresh btn btn-secondary btn-desktop" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z" /> <path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z" />
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z" /> <path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z" />
</svg> </svg>
</button> </button>
</div> </div>
<div id='app' class="flex-grow-1"></div> }
<div class="dd-cards-container">
<div class="dd-card">
<div class="dd-card-preview">
<img src="~/img/sign_flow_horizontal.svg" class="app-logo">
@if (!isReadOnly)
{
<div class="progress-container">
<div id="signed-count-bar" class="progress"></div>
<span class="progress-text">
<span id="signed-count">0</span>/<span id="signature-count">@signatureCount</span> Unterschriften
</span>
</div>
}
</div>
<div class="dd-card-info">
<div class="logo">
<img class="@logo.ShowPageClass" src="@logo.Src" alt="logo">
</div>
<h2>@($"{envelope?.Title}".TrySanitize(_sanitizer))</h2>
@if (isReadOnly)
{
var dateTimeSt = string.Empty;
if (ViewData["ReadOnly"] is EnvelopeReceiverReadOnlyDto readOnly)
dateTimeSt = readOnly.DateValid.ToLongDateString();
<h6>@string.Format(_localizer["ReadOnlyMessage"], receiver_name, dateTimeSt)</h6>
}
else
{
<h6>@($"{@envelope?.Message}".TrySanitize(_sanitizer))</h6>
}
<p>
<small class="text-body-secondary">
@Html.Raw(string.Format(_localizer[WebKey.EnvelopeInfo2], /* sanitize separately but don't sanitize the URI */
envelope?.AddedWhen.ToString(userCulture?.Info?.DateTimeFormat).TrySanitize(_sanitizer),
$"{sender?.Prename} {sender?.Name}".TrySanitize(_sanitizer),
sender?.Email.TrySanitize(_sanitizer),
envelope?.Title.TrySanitize(_sanitizer),
sender?.Prename.TrySanitize(_sanitizer),
sender?.Name.TrySanitize(_sanitizer),
sender?.Email.TrySanitize(_sanitizer)))
</small>
</p>
</div>
</div>
</div>
@if (!isReadOnly)
{
<div class="modal fade" id="shareBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="shareBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<small class="modal-title text-body-secondary" id="shareBackdropLabel">Geben Sie hier den Empfänger ein, mit welchem Sie das Dokument teilen wollen:</small>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="input-group mb-3">
<span class="input-group-text">E-Mail</span>
<input type="text" class="form-control email-input" placeholder="user@mail.com" id="readonly-receiver-mail" aria-label="">
</div>
<div class="input-group">
<span class="input-group-text">Gültig bis</span>
<input type="date" name="expiration" class="form-control" lang="de" id="readonly-date-valid" onkeydown="return false;" onclick="this.showPicker()"
min="@DateTime.Today.AddDays(1).ToString("yyyy-MM-dd")"
max="@DateTime.Today.AddDays(90).ToString("yyyy-MM-dd")"
value="@DateTime.Today.AddDays(7).ToString("yyyy-MM-dd")">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id="readonly-send">
<span class="material-symbols-outlined">
send
</span>
</button>
</div>
</div>
</div>
</div>
}
<div id='app'></div>
</div> </div>
@if (!isReadOnly)
{
<script nonce="@nonce">
document.getElementById('readonly-send').addEventListener('click', async () => {
const receiverMail = document.getElementById('readonly-receiver-mail');
const dateValid = document.getElementById('readonly-date-valid');
const receiverMail_value = receiverMail.value;
const dateValid_value = dateValid.value;
//check email
if (!receiverMail_value || receiverMail.classList.contains('is-invalid')) {
Swal.fire({
icon: "error",
title: "Falsche Email",
text: "Die E-Mail-Adresse ist ungültig. Bitte verwenden Sie das richtige Format, z. B.: user@mail.com."
});
return;
}
//check the date
const tomorrow = new Date(Date.now() + 86400000);
if (new Date(dateValid_value) < tomorrow) {
Swal.fire({
icon: "error",
title: "Falsches Datum",
text: "Die Verteilung der Umschläge sollte mindestens einen Tag dauern."
});
return;
}
shareEnvelope(receiverMail_value, dateValid_value)
.then(res => {
if (res.ok) {
Swal.fire({
title: "Gesendet",
icon: "success"
});
}
else {
Swal.fire({
icon: "error",
title: `Fehler ${res.status}`,
text: "Der Vorgang ist fehlgeschlagen. Bitte wenden Sie sich an das IT-Team."
});
}
})
.catch(err => {
Swal.fire({
icon: "error",
title: "Unerwarteter Fehler",
text: "Der Vorgang ist fehlgeschlagen. Bitte wenden Sie sich an das IT-Team."
});
})
receiverMail.value = '';
dateValid.valueAsDate = new Date(new Date().setDate(new Date().getDate() + 8));
});
</script>
}
<script nonce="@nonce"> <script nonce="@nonce">
const collapseNav = () => { const collapseNav = () => {
document.addEventListener('click', function (event) { document.addEventListener('click', function (event) {

View File

@@ -3,9 +3,13 @@
@using Newtonsoft.Json.Serialization @using Newtonsoft.Json.Serialization
@{ @{
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string; var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
var isReadOnly = false;
if (ViewData["IsReadOnly"] is bool isReadOnly_bool)
isReadOnly = isReadOnly_bool;
} }
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="de">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
@@ -14,10 +18,10 @@
<link rel="stylesheet" href="~/lib/sweetalert2/sweetalert2.min.css" /> <link rel="stylesheet" href="~/lib/sweetalert2/sweetalert2.min.css" />
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" /> <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
<link rel="stylesheet" href="~/css/logo.min.css" asp-append-version="true" /> <link rel="stylesheet" href="~/css/logo.min.css" asp-append-version="true" />
<link rel="stylesheet" href="~/css/card.min.css" asp-append-version="true" />
<link rel="stylesheet" href="~/EnvelopeGenerator.Web.styles.css" asp-append-version="true" /> <link rel="stylesheet" href="~/EnvelopeGenerator.Web.styles.css" asp-append-version="true" />
<link rel="stylesheet" href="~/lib/flag-icons-main/css/flag-icons.min.css" asp-append-version="true" /> <link rel="stylesheet" href="~/lib/flag-icons-main/css/flag-icons.min.css" asp-append-version="true" />
<link rel="stylesheet" href="~/lib/alertifyjs/css/alertify.min.css" /> <link rel="stylesheet" href="~/lib/alertifyjs/css/alertify.min.css" />
<link rel="stylesheet" href="~/lib/alertifyjs/css/themes/default.min.css" />
<link href="https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" />
</head> </head>
@@ -27,10 +31,19 @@
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24 font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24
} }
</style> </style>
<script nonce="@nonce">
@if (ViewData["EnvelopeKey"] is string envelopeKey) @if (ViewData["EnvelopeKey"] is string envelopeKey)
{ {
<script nonce="@nonce">const ENV_KEY = "@envelopeKey.TrySanitize(_sanitizer)"</script> @: const ENV_KEY = "@envelopeKey.TrySanitize(_sanitizer)"
} }
const IS_READONLY = @isReadOnly.ToString().ToLower();
const DEVICE_TYPE = window.innerWidth <= 768 ? 'mobile' : window.innerWidth <= 1024 ? 'tablet' : 'desktop';
const IS_DESKTOP = DEVICE_TYPE == 'desktop'
</script>
<script src="~/lib/jquery/dist/jquery.min.js"></script> <script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/popper/dist/umd/popper.min.js"></script> <script src="~/lib/popper/dist/umd/popper.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script> <script src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>
@@ -41,7 +54,6 @@
<script src="~/js/network.min.js" asp-append-version="true"></script> <script src="~/js/network.min.js" asp-append-version="true"></script>
<script src="~/js/app.min.js" asp-append-version="true"></script> <script src="~/js/app.min.js" asp-append-version="true"></script>
<script src="~/lib/pspdfkit/dist-2024.3.2/pspdfkit.js"></script> <script src="~/lib/pspdfkit/dist-2024.3.2/pspdfkit.js"></script>
<script src="~/lib/bootstrap-cookie-consent-settings-main/bootstrap-cookie-consent-settings.js" asp-append-version="true"></script>
<script src="~/js/util.min.js" asp-append-version="true"></script> <script src="~/js/util.min.js" asp-append-version="true"></script>
<script src="~/js/api-service.min.js" asp-append-version="true"></script> <script src="~/js/api-service.min.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false) @await RenderSectionAsync("Scripts", required: false)
@@ -61,6 +73,9 @@
</main> </main>
<script src="~/js/event-binder.min.js" asp-append-version="true"></script> <script src="~/js/event-binder.min.js" asp-append-version="true"></script>
@Html.AntiForgeryToken() @Html.AntiForgeryToken()
<footer>&copy; SignFlow 2023-2024 <a href="https://digitaldata.works">Digital Data GmbH</a></footer> <footer>
<span>&copy; SignFlow 2023-2024 <a href="https://digitaldata.works">Digital Data GmbH</a></span>
<a href="/privacy-policy.de-DE.html">Datenschutz</a>
</footer>
</body> </body>
</html> </html>

View File

@@ -1,6 +1,7 @@
@using EnvelopeGenerator.Web @using EnvelopeGenerator.Web
@using EnvelopeGenerator.Web.Models @using EnvelopeGenerator.Web.Models
@using EnvelopeGenerator.Web.Sanitizers @using EnvelopeGenerator.Web.Sanitizers
@using EnvelopeGenerator.Extensions
@using Microsoft.Extensions.Localization @using Microsoft.Extensions.Localization
@using EnvelopeGenerator.Application.Resources @using EnvelopeGenerator.Application.Resources
@using Microsoft.Extensions.Options @using Microsoft.Extensions.Options

View File

@@ -16,7 +16,7 @@
}, },
"AdminPassword": "dd", "AdminPassword": "dd",
"PSPDFKitLicenseKey": "SXCtGGY9XA-31OGUXQK-r7c6AkdLGPm2ljuyDr1qu0kkhLvydg-Do-fxpNUF4Rq3fS_xAnZRNFRHbXpE6sQ2BMcCSVTcXVJO6tPviexjpiT-HnrDEySlUERJnnvh-tmeOWprxS6BySPnSILkmaVQtUfOIUS-cUbvvEYHTvQBKbSF8di4XHQFyfv49ihr51axm3NVV3AXwh2EiKL5C5XdqBZ4sQ4O7vXBjM2zvxdPxlxdcNYmiU83uAzw7B83O_jubPzya4CdUHh_YH7Nlp2gP56MeG1Sw2JhMtfG3Rj14Sg4ctaeL9p6AEWca5dDjJ2li5tFIV2fQSsw6A_cowLu0gtMm5i8IfJXeIcQbMC2-0wGv1oe9hZYJvFMdzhTM_FiejM0agemxt3lJyzuyP8zbBSOgp7Si6A85krLWPZptyZBTG7pp7IHboUHfPMxCXqi-zMsqewOJtQBE2mjntU-lPryKnssOpMPfswwQX7QSkJYV5EMqNmEhQX6mEkp2wcqFzMC7bJQew1aO4pOpvChUaMvb1vgRek0HxLag0nwQYX2YrYGh7F_xXJs-8HNwJe8H0-eW4x4faayCgM5rB5772CCCsD9ThZcvXFrjNHHLGJ8WuBUFm6LArvSfFQdii_7j-_sqHMpeKZt26NFgivj1A==", "PSPDFKitLicenseKey": "SXCtGGY9XA-31OGUXQK-r7c6AkdLGPm2ljuyDr1qu0kkhLvydg-Do-fxpNUF4Rq3fS_xAnZRNFRHbXpE6sQ2BMcCSVTcXVJO6tPviexjpiT-HnrDEySlUERJnnvh-tmeOWprxS6BySPnSILkmaVQtUfOIUS-cUbvvEYHTvQBKbSF8di4XHQFyfv49ihr51axm3NVV3AXwh2EiKL5C5XdqBZ4sQ4O7vXBjM2zvxdPxlxdcNYmiU83uAzw7B83O_jubPzya4CdUHh_YH7Nlp2gP56MeG1Sw2JhMtfG3Rj14Sg4ctaeL9p6AEWca5dDjJ2li5tFIV2fQSsw6A_cowLu0gtMm5i8IfJXeIcQbMC2-0wGv1oe9hZYJvFMdzhTM_FiejM0agemxt3lJyzuyP8zbBSOgp7Si6A85krLWPZptyZBTG7pp7IHboUHfPMxCXqi-zMsqewOJtQBE2mjntU-lPryKnssOpMPfswwQX7QSkJYV5EMqNmEhQX6mEkp2wcqFzMC7bJQew1aO4pOpvChUaMvb1vgRek0HxLag0nwQYX2YrYGh7F_xXJs-8HNwJe8H0-eW4x4faayCgM5rB5772CCCsD9ThZcvXFrjNHHLGJ8WuBUFm6LArvSfFQdii_7j-_sqHMpeKZt26NFgivj1A==",
"UseCSPInDev": true, "UseCSPInDev": false,
"Content-Security-Policy": [ // The first format parameter {0} will be replaced by the nonce value. "Content-Security-Policy": [ // The first format parameter {0} will be replaced by the nonce value.
"default-src 'self'", "default-src 'self'",
"script-src 'self' 'nonce-{0}' 'unsafe-eval'", "script-src 'self' 'nonce-{0}' 'unsafe-eval'",
@@ -135,5 +135,12 @@
"Src": "/img/digital_data.svg", "Src": "/img/digital_data.svg",
"ShowPageClass": "dd-show-logo", "ShowPageClass": "dd-show-logo",
"LockedPageClass": "dd-locked-logo" "LockedPageClass": "dd-locked-logo"
},
"MailConfig": {
"Placeholders": {
"[NAME_PORTAL]": "signFlow",
"[SIGNATURE_TYPE]": "signieren",
"[REASON]": ""
}
} }
} }

View File

@@ -76,5 +76,11 @@
"inputFiles": [ "inputFiles": [
"wwwroot/css/privacy-policy.css" "wwwroot/css/privacy-policy.css"
] ]
},
{
"outputFileName": "wwwroot/css/card.min.css",
"inputFiles": [
"wwwroot/css/card.css"
]
} }
] ]

View File

@@ -0,0 +1,126 @@
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
* {
box-sizing: border-box;
}
.dd-cards-container {
font-family: 'Muli', sans-serif;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.dd-card {
background-color: #fff;
display: flex;
max-width: 100%;
margin: 0;
overflow: hidden;
width: 100%;
}
.dd-card h6 {
opacity: 0.6;
margin: 0;
letter-spacing: 0.0625rem;
font-size: clamp(0.6rem, 1.33vw, 0.8rem);
}
.dd-card h2 {
letter-spacing: 0.0625rem;
margin: 0;
font-size: clamp(1rem, 2.67vw, 1.67rem);
}
.uppercase {
text-transform: uppercase;
}
.dd-card-preview {
background-color: #2A265F;
color: #fff;
padding: 0.1rem 1rem 1rem 1rem;
margin:0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.dd-card-preview a {
color: #fff;
opacity: 0.6;
}
.dd-card-preview button {
border-width: 0;
align-items: center;
background-color: transparent;
color: white;
margin: 15% 0 0 0;
transition: color 0.25s ease;
}
.dd-card-preview button:hover {
color: #bebebe;
}
.dd-card-preview span {
}
.dd-card-info {
padding: clamp(0.55rem, 2vw, .875rem) 0 0 clamp(0.55rem, 2.5vw, 1.7rem);
margin: 0;
position: relative;
width: 100%;
}
.dd-card-info p, .dd-card-info a, .dd-card-info small, .dd-card-info span {
opacity: 0.65;
font-size: clamp(0.55rem, 1.23vw, 0.75rem);
margin: clamp(0.55rem, 2vw, .875rem) 0 clamp(0.55rem, 2vw, .875rem) 0;
text-decoration: none;
padding: 0;
}
.app-logo {
width: clamp(4rem, 10vw, 5rem);
margin: 1rem 0 0 0;
}
.progress-container {
text-align: right;
width: 100%;
margin: clamp(0.8rem, 2vw, 1rem) 0 0 0;
}
.progress {
background-color: #ddd;
border-radius: 0.1875rem;
height: clamp(0.25rem, 1vw, 0.3125rem);
width: clamp(6rem, 20vw, 10rem);
position: relative;
}
.progress::after {
background-color: #2A265F;
content: '';
position: absolute;
top: 0;
left: 0;
height: clamp(0.25rem, 1vw, 0.3125rem);
width: var(--progress-width, 1%);
transition: width 1s ease;
opacity: 0.85;
}
.progress-text {
font-size: clamp(0.5rem, 1.5vw, 0.625rem);
opacity: 0.6;
letter-spacing: clamp(0.05rem, 0.5vw, 0.0625rem);
text-align: left;
}

View File

@@ -0,0 +1 @@
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');*{box-sizing:border-box}.dd-cards-container{font-family:'Muli',sans-serif;display:flex;align-items:center;justify-content:center;flex-direction:column}.dd-card{background-color:#fff;display:flex;max-width:100%;margin:0;overflow:hidden;width:100%}.dd-card h6{opacity:.6;margin:0;letter-spacing:.0625rem;font-size:clamp(.6rem,1.33vw,.8rem)}.dd-card h2{letter-spacing:.0625rem;margin:0;font-size:clamp(1rem,2.67vw,1.67rem)}.uppercase{text-transform:uppercase}.dd-card-preview{background-color:#2a265f;color:#fff;padding:.1rem 1rem 1rem 1rem;margin:0;display:flex;flex-direction:column;justify-content:center;align-items:center}.dd-card-preview a{color:#fff;opacity:.6}.dd-card-preview button{border-width:0;align-items:center;background-color:transparent;color:#fff;margin:15% 0 0 0;transition:color .25s ease}.dd-card-preview button:hover{color:#bebebe}.dd-card-info{padding:clamp(.55rem,2vw,.875rem) 0 0 clamp(.55rem,2.5vw,1.7rem);margin:0;position:relative;width:100%}.dd-card-info p,.dd-card-info a,.dd-card-info small,.dd-card-info span{opacity:.65;font-size:clamp(.55rem,1.23vw,.75rem);margin:clamp(.55rem,2vw,.875rem) 0 clamp(.55rem,2vw,.875rem) 0;text-decoration:none;padding:0}.app-logo{width:clamp(4rem,10vw,5rem);margin:1rem 0 0 0}.progress-container{text-align:right;width:100%;margin:clamp(.8rem,2vw,1rem) 0 0 0}.progress{background-color:#ddd;border-radius:.1875rem;height:clamp(.25rem,1vw,.3125rem);width:clamp(6rem,20vw,10rem);position:relative}.progress::after{background-color:#2a265f;content:'';position:absolute;top:0;left:0;height:clamp(.25rem,1vw,.3125rem);width:var(--progress-width,1%);transition:width 1s ease;opacity:.85}.progress-text{font-size:clamp(.5rem,1.5vw,.625rem);opacity:.6;letter-spacing:clamp(.05rem,.5vw,.0625rem);text-align:left}

View File

@@ -5,6 +5,11 @@
.dd-show-logo { .dd-show-logo {
width: 9rem; width: 9rem;
position: absolute;
right: 0;
margin: 0 2rem 0 0;
padding: 0;
top:0;
} }
.cursor-locked-logo { .cursor-locked-logo {
@@ -19,6 +24,7 @@
@media (max-width: 767px) { @media (max-width: 767px) {
.dd-show-logo { .dd-show-logo {
width: 5rem; width: 5rem;
margin-right: 0rem;
} }
.cursor-show-logo { .cursor-show-logo {

View File

@@ -1 +1 @@
.dd-locked-logo{width:13rem;padding-top:1rem}.dd-show-logo{width:9rem}.cursor-locked-logo{width:9rem;padding-top:1rem}.cursor-show-logo{width:6rem}@media(max-width:767px){.dd-show-logo{width:5rem}.cursor-show-logo{width:3rem}} .dd-locked-logo{width:13rem;padding-top:1rem}.dd-show-logo{width:9rem;position:absolute;right:0;margin:0 2rem 0 0;padding:0;top:0}.cursor-locked-logo{width:9rem;padding-top:1rem}.cursor-show-logo{width:6rem}@media(max-width:767px){.dd-show-logo{width:5rem;margin-right:0}.cursor-show-logo{width:3rem}}

View File

@@ -1,5 +1,5 @@
body { body {
font-family: Arial, sans-serif; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
line-height: 1.6; line-height: 1.6;
margin: 1.25rem; margin: 1.25rem;
background-color: #f4f4f4; background-color: #f4f4f4;

View File

@@ -1 +1 @@
body{font-family:Arial,sans-serif;line-height:1.6;margin:1.25rem;background-color:#f4f4f4}header{text-align:center;margin:0 10rem 3rem 10rem;box-shadow:0 .25rem .5rem rgba(0,0,0,.1)}h1{color:#333}h2{color:#0056b3}section{background-color:#fff;padding:1.25rem;border-radius:.5rem;box-shadow:0 .25rem .5rem rgba(0,0,0,.1);margin:0 10rem 3rem 10rem}ul{list-style:disc inside}a{color:#0056b3;text-decoration:none}a:hover{text-decoration:underline} body{font-family:system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.6;margin:1.25rem;background-color:#f4f4f4}header{text-align:center;margin:0 10rem 3rem 10rem;box-shadow:0 .25rem .5rem rgba(0,0,0,.1)}h1{color:#333}h2{color:#0056b3}section{background-color:#fff;padding:1.25rem;border-radius:.5rem;box-shadow:0 .25rem .5rem rgba(0,0,0,.1);margin:0 10rem 3rem 10rem}ul{list-style:disc inside}a{color:#0056b3;text-decoration:none}a:hover{text-decoration:underline}

View File

@@ -4,22 +4,20 @@
*/ */
/* Toolbar Buttons */ /* Toolbar Buttons */
#app {
background: gray;
width: 100vw;
height: 80vh;
}
.navbar-toggler { .navbar-toggler {
border: 0; border: 0;
} }
.material-symbols-outlined {
align-content: center;
}
.btn-group { .btn-group {
margin-right: 10vw; margin-right: 10vw;
margin-bottom: 10vh; margin-bottom: 10vh;
} }
.btn_refresh, .btn_reject, .btn_complete { .btn_refresh, .btn_reject, .btn_complete {
height:2.5rem; height:2.5rem;
} }
@@ -33,44 +31,94 @@
} }
.button-finish { .button-finish {
transition: background-color linear 300ms; color: #fff;
background-color: #059669; /* emerald-600 */ background-color: #0d6efd;
color: white; border-color: #0d6efd;
border-left: none;
} }
.button-finish:hover, .button-finish:focus, .button-finish:active { .button-finish:hover {
background-color: #10b981; /* emerald-500 */ color: #fff;
color: white; background-color: #0b5ed7;
border-color: #0a58ca;
}
.button-finish:focus {
box-shadow: 0 0 0 0.25rem rgba(49, 132, 253, 0.5);
}
.button-finish:active {
color: #fff;
background-color: #0a58ca;
border-color: #0a53be;
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
.button-finish:disabled {
color: #fff;
background-color: #0d6efd;
border-color: #0d6efd;
} }
.button-reject { .button-reject {
transition: background-color linear 300ms; color: #fff;
background-color: #d97706; /* amber-600 */ background-color: #dc3545;
color: white; border-color: #dc3545;
border-left: none;
} }
.button-reject:hover, .button-reject:focus, .button-reject:active { .button-reject:hover {
background-color: #f59e0b; /* amber-500 */ color: #fff;
color: white; background-color: #bb2d3b;
border-color: #b02a37;
}
.button-reject:focus {
box-shadow: 0 0 0 0.25rem rgba(225, 83, 97, 0.5);
}
.button-reject:active {
color: #fff;
background-color: #b02a37;
border-color: #a52834;
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
.button-reject:disabled {
color: #fff;
background-color: #dc3545;
border-color: #dc3545;
} }
.button-reset { .button-reset {
transition: background-color linear 300ms; color: #fff;
background-color: #2563eb; /* blue-600 */ background-color: #6c757d;
color: white; border-color: #6c757d;
border-left: none;
} }
.button-reset:hover, .button-reset:focus, .button-reset:active { .button-reset:hover {
background-color: #3b82f6; /* blue-500 */ color: #fff;
color: white; background-color: #5c636a;
border-color: #565e64;
}
.button-reset:focus {
box-shadow: 0 0 0 0.25rem rgba(130, 138, 145, 0.5);
}
.button-reset:active {
color: #fff;
background-color: #565e64;
border-color: #51585e;
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
.button-reset:disabled {
color: #fff;
background-color: #6c757d;
border-color: #6c757d;
} }
body { body {
background-color: #bbb; background: #f8fcfc;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100vh; height: 100vh;
@@ -78,16 +126,53 @@ body {
} }
main { main {
flex: 1; display:flex;
margin: 0 0 0.5vh 0;
}
.envelope-view {
display: flex; /* d-flex */
flex-direction: column; /* flex-column */
width: 100vw;
height: 95.9vh;
}
#app {
background: gray;
width: 100vw;
height: 100%;
flex-grow: 1;
border-width: 0;
} }
footer { footer {
background: #333; height: 4vh;
color: white; min-height: 1.5rem;
text-align: center; background-color: #001F61;
padding: 10px 0; border-radius: 10px 10px 0 0;
color: #fff;
font-family: 'Muli';
padding: 0.5vh 0;
position: fixed;
bottom: 0;
width: 100%;
z-index: 998;
border-width: 0;
font-size: clamp(0.75rem, 1.5vw, 1rem);
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: start;
} }
footer * {
margin-left: clamp(0.5rem, 2vw, 1rem);
}
footer a {
color: #FF7500;
text-decoration: none;
}
.page { .page {
margin-top: 3rem; margin-top: 3rem;
@@ -129,6 +214,11 @@ footer {
color: #fff; color: #fff;
} }
.page header .icon.expired {
background-color: rgba(228, 216, 213, 0.5);
color: #fff;
}
.page .form { .page .form {
max-width: 30rem; max-width: 30rem;
margin: 2rem auto; margin: 2rem auto;
@@ -281,13 +371,44 @@ footer#page-footer {
} }
#form-access-code { #form-access-code {
margin-left: 5rem; justify-content: space-evenly;
}
.access-code-form-floating {
display: flex;
justify-content: start;
flex-direction: row;
}
.access-code-form-floating button {
align-content: center;
border-bottom-left-radius: 0;
border-top-left-radius: 0;
}
.access-code-form-floating input {
align-content: center;
border-bottom-right-radius: 0;
border-top-right-radius: 0;
border-right-width: 0;
width: 7rem;
}
#access-code-error-message {
justify-content: center;
align-content: center;
margin: 1.5rem 7rem 0 7rem;
height: 2.5rem;
}
.flag-dropdown button {
height: 100%;
} }
.header-1 { .header-1 {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-top:0; margin-top: 0;
padding-top: 0; padding-top: 0;
} }
@@ -298,6 +419,30 @@ footer#page-footer {
padding-top: 0; padding-top: 0;
} }
.no-receiver-explanation {
padding: 2.5rem;
}
.ajs-message.ajs-custom {
margin: 0rem 0rem 0rem 0rem;
padding: 0rem 0rem 0rem 0rem;
width:50rem;
}
.ajs-message.ajs-custom .alert {
display: flex;
flex-direction: row;
}
.ajs-message.ajs-custom span {
margin: 0 1rem 0 0;
}
.ajs-message.ajs-custom p {
margin: 0;
padding: 0;
}
/* styles for mobile responsiveness */ /* styles for mobile responsiveness */
@media (max-height: 850px) { @media (max-height: 850px) {
.navbar .container { .navbar .container {
@@ -406,6 +551,12 @@ footer#page-footer {
} }
} }
@media (max-width: 1024px) {
#flex-action-panel, .btn-desktop {
display: none;
}
}
@media (max-height: 600px) { @media (max-height: 600px) {
.collapse { .collapse {
height: 4rem; height: 4rem;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 256 256">
<defs>
<style>
.cls-1 {
fill: #ffd631;
}
.cls-1, .cls-2, .cls-3, .cls-4 {
stroke-width: 0px;
}
.cls-2 {
fill: #a52431;
}
.cls-3 {
fill: none;
}
.cls-4 {
fill: #FFFFFF;
}
.cls-5 {
clip-path: url(#clippath);
opacity: 0;
}
</style>
<clipPath id="clippath">
<rect class="cls-3" x="0" width="256" height="256"/>
</clipPath>
</defs>
<g class="cls-5">
<rect class="cls-2" x="0" width="256" height="256" rx="48.67" ry="48.67"/>
</g>
<path class="cls-1" d="M153.29,63.22l-20.08,28.03h-10.42l-20.08-28.03,8.74-5.57h33.09l8.74,5.57ZM89.25,71.8l19.69,27.49-11.88,14.56-14.5-37.78,6.69-4.26ZM104.33,128.96l17.33-21.24h12.67l17.33,21.24-23.67,19.17-23.67-19.17ZM158.94,113.85l-11.88-14.56,19.69-27.49,6.69,4.26-14.5,37.78ZM149.16,42.03v-.03h-42.32v.03s-43.57,27.76-43.57,27.76l.28.44,25.76,67.11,38.62,30.89.06.07h.01s.01,0,.01,0l.05-.07,38.62-30.89,25.76-67.11.28-.44-43.57-27.76Z"/>
<path class="cls-1" d="M191.6,222.14h5.32l4.9-17.08,4.83,17.08h5.35l5.39-24.5h-5.04l-3.33,16.56-4.76-16.56h-4.79l-4.76,16.56-3.33-16.56h-5.21l5.43,24.5ZM171.79,217.87c-4.38,0-7.74-3.47-7.74-7.98s3.36-7.98,7.74-7.98,7.77,3.43,7.77,7.98-3.36,7.98-7.77,7.98M171.79,222.52c7.28,0,12.95-5.56,12.95-12.64s-5.67-12.63-12.95-12.63-12.95,5.56-12.95,12.63,5.71,12.64,12.95,12.64M139.3,222.14h18.48v-4.48h-13.4v-20.02h-5.07v24.5ZM115.9,222.14h5.07v-10.04h9.21v-4.27h-9.21v-5.78h13.86v-4.41h-18.93v24.5Z"/>
<path class="cls-4" d="M92.79,222.14h4.8v-12.63c.84-1.16,2.13-1.82,3.74-1.82,2.31,0,3.78,1.51,3.78,3.85v10.6h4.79v-11.31c0-4.31-2.97-7.28-7.21-7.28-2,0-3.75.63-5.11,1.82v-1.47h-4.8v18.24ZM78.07,218.18c-2.97,0-5.25-2.31-5.25-5.29s2.31-5.18,5.28-5.18c1.68,0,3.19.63,4.24,1.65v7.14c-1.05,1.08-2.52,1.68-4.27,1.68M78.1,229.63c5.85,0,9.03-2.69,9.03-7.52v-18.2h-4.72v1.19c-1.44-.94-3.15-1.47-4.94-1.47-5.25,0-9.38,4.09-9.38,9.27s4.1,9.35,9.24,9.35c1.82,0,3.54-.59,5-1.65v1.44c0,2.41-1.47,3.64-4.34,3.64-1.93,0-3.82-.45-5.81-1.44l-1.68,3.71c2.13,1.08,4.79,1.68,7.59,1.68M58.75,222.14h4.8v-18.24h-4.8v18.24ZM61.13,201.73c1.51,0,2.73-1.26,2.73-2.73s-1.22-2.73-2.73-2.73-2.73,1.23-2.73,2.73,1.22,2.73,2.73,2.73M46.42,222.49c4.58,0,7.98-2.55,7.98-6.02,0-2.84-2-4.69-5.57-5.22l-3.5-.53c-1.78-.24-2.49-.74-2.49-1.75s1.16-1.78,2.87-1.78c1.85,0,3.64.56,5.63,1.78l2.31-3.12c-2.28-1.5-4.83-2.27-7.49-2.27-4.65,0-7.59,2.27-7.59,5.77,0,2.94,1.92,4.8,5.53,5.32l3.5.52c1.58.24,2.27.77,2.27,1.72,0,1.19-1.4,1.96-3.53,1.96-1.92,0-3.78-.66-5.91-2.1l-2.38,3.19c2.06,1.64,5.04,2.52,8.37,2.52"/>
<rect class="cls-3" x="0" width="256" height="256"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1,5 @@
<svg width="199" height="95" viewBox="0 0 199 95" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M67.515 15.8772L52.455 36.8498H44.64L29.58 15.8772L36.135 11.7096H60.9525L67.5075 15.8772H67.515ZM19.485 22.2969L34.2525 42.8654L25.3425 53.7595L14.4675 25.4918L19.485 22.3044V22.2969ZM30.795 65.0651L43.7925 49.1729H53.295L66.2925 65.0651L48.54 79.4084L30.7875 65.0651H30.795ZM71.7525 53.7595L62.8425 42.8654L77.61 22.2969L82.6275 25.4843L71.7525 53.752V53.7595ZM64.4175 0.0224456V0H32.6775V0.0224456L0 20.793L0.209999 21.1222L19.53 71.3352L48.495 94.4476L48.54 94.5H48.5475H48.555L48.5925 94.4476L77.5575 71.3352L96.8775 21.1222L97.0875 20.793L64.41 0.0224456H64.4175Z" fill="#FFD631"/>
<path d="M180.74 34.5908H185.54V22.0971C186.38 20.9496 187.67 20.2968 189.28 20.2968C191.59 20.2968 193.06 21.7905 193.06 24.1052V34.5908H197.85V23.4029C197.85 19.1394 194.88 16.2014 190.64 16.2014C188.64 16.2014 186.89 16.8246 185.53 18.0018V16.5477H180.73V34.5908H180.74ZM166.02 30.6735C163.05 30.6735 160.77 28.3885 160.77 25.4406C160.77 22.4928 163.08 20.3165 166.05 20.3165C167.73 20.3165 169.24 20.9397 170.29 21.9487V29.0117C169.24 30.08 167.77 30.6735 166.02 30.6735ZM166.05 42C171.9 42 175.08 39.339 175.08 34.5611V16.5576H170.36V17.7347C168.92 16.8049 167.21 16.2806 165.42 16.2806C160.17 16.2806 156.04 20.3264 156.04 25.4505C156.04 30.5746 160.14 34.6996 165.28 34.6996C167.1 34.6996 168.82 34.116 170.28 33.0674V34.4919C170.28 36.8759 168.81 38.0926 165.94 38.0926C164.01 38.0926 162.12 37.6475 160.13 36.6682L158.45 40.3381C160.58 41.4065 163.24 42 166.04 42M146.7 34.5908H151.5V16.5477H146.7V34.5908ZM149.08 14.4011C150.59 14.4011 151.81 13.1547 151.81 11.7005C151.81 10.2464 150.59 9 149.08 9C147.57 9 146.35 10.2167 146.35 11.7005C146.35 13.1843 147.57 14.4011 149.08 14.4011ZM134.37 34.9371C138.95 34.9371 142.35 32.4146 142.35 28.982C142.35 26.1727 140.35 24.3426 136.78 23.8183L133.28 23.2941C131.5 23.0567 130.79 22.562 130.79 21.5629C130.79 20.5638 131.95 19.8022 133.66 19.8022C135.51 19.8022 137.3 20.3561 139.29 21.5629L141.6 18.4766C139.32 16.9928 136.77 16.2311 134.11 16.2311C129.46 16.2311 126.52 18.4766 126.52 21.9389C126.52 24.8471 128.44 26.687 132.05 27.2014L135.55 27.7158C137.13 27.9532 137.82 28.4775 137.82 29.4173C137.82 30.5944 136.42 31.3561 134.29 31.3561C132.37 31.3561 130.51 30.7032 128.38 29.2788L126 32.4344C128.06 34.0567 131.04 34.9271 134.37 34.9271" fill="white"/>
<path d="M172.7 84.6241H178.02L182.92 67.7265L187.75 84.6241H193.1L198.49 60.3858H193.45L190.12 76.7689L185.36 60.3858H180.57L175.81 76.7689L172.48 60.3858H167.27L172.7 84.6241ZM152.89 80.3997C148.51 80.3997 145.15 76.9668 145.15 72.5049C145.15 68.0431 148.51 64.6102 152.89 64.6102C157.27 64.6102 160.66 68.0036 160.66 72.5049C160.66 77.0063 157.3 80.3997 152.89 80.3997ZM152.89 85C160.17 85 165.84 79.4994 165.84 72.4951C165.84 65.4907 160.17 60 152.89 60C145.61 60 139.94 65.5006 139.94 72.4951C139.94 79.4895 145.65 85 152.89 85ZM120.4 84.6241H138.88V80.1919H125.48V60.3858H120.41V84.6241H120.4ZM97 84.6241H102.07V74.6913H111.28V70.467H102.07V64.7487H115.93V60.3858H97V84.6241Z" fill="#FFD631"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -253,6 +253,7 @@
} }
static async createAnnotationFrameBlob(receiverName, receiverSignature, timestamp, width, height) { static async createAnnotationFrameBlob(receiverName, receiverSignature, timestamp, width, height) {
Comp.SignatureProgress.SignedCount += 1;
const canvas = document.createElement('canvas') const canvas = document.createElement('canvas')
const scale = 4 const scale = 4
const fontSize = 10 const fontSize = 10

View File

@@ -1,25 +1,29 @@
class Content { class Content {
static get JSON () { static get JSON() {
return 'application/json'; return 'application/json';
} }
} }
class API { class API {
static get REJECT_URL () { static get REJECT_URL() {
return `/api/envelope/reject`; return `/api/envelope/reject`;
} }
static get REJECT_REDIR_URL(){ static get REJECT_REDIR_URL() {
return `/envelopekey/${API.ENV_KEY}/rejected`; return `/envelopekey/${API.ENV_KEY}/rejected`;
} }
static get SHARE_URL() {
return `/api/readonly`
}
static __XSRF_TOKEN static __XSRF_TOKEN
static get XSRF_TOKEN() { static get XSRF_TOKEN() {
API.__XSRF_TOKEN ??= document.getElementsByName('__RequestVerificationToken')[0].value; API.__XSRF_TOKEN ??= document.getElementsByName('__RequestVerificationToken')[0].value;
return API.__XSRF_TOKEN; return API.__XSRF_TOKEN;
} }
static get ENV_KEY(){ static get ENV_KEY() {
return ENV_KEY ?? document.querySelector('meta[name="env-key"]').getAttribute('content'); return ENV_KEY ?? document.querySelector('meta[name="env-key"]').getAttribute('content');
} }
} }
@@ -28,20 +32,20 @@ const submitForm = async form => await fetch(form.action, {
method: form.method, method: form.method,
body: new FormData(form), body: new FormData(form),
headers: { headers: {
"X-Requested-With": "XMLHttpRequest" "X-Requested-With": "XMLHttpRequest"
} }
}) })
const createRequest = async (method, url, body, contentType) => { const createRequest = async (method, url, body, contentType) => {
return fetch(url, { return fetch(url, {
credentials: 'include', credentials: 'include',
method: method, method: method,
headers: { headers: {
'Content-Type': contentType, 'Content-Type': contentType,
'X-XSRF-TOKEN': API.XSRF_TOKEN 'X-XSRF-TOKEN': API.XSRF_TOKEN
}, },
body: JSON.stringify(body) body: JSON.stringify(body)
}) })
} }
const createPost = (url, body, contentType) => createRequest('POST', url, body, contentType); const createPost = (url, body, contentType) => createRequest('POST', url, body, contentType);
@@ -50,4 +54,6 @@ const rejectEnvelope = (reason) => createPost(API.REJECT_URL, reason, Content.JS
const redirect = (url) => window.location.href = url; const redirect = (url) => window.location.href = url;
const redirRejected = () => redirect(API.REJECT_REDIR_URL); const redirRejected = () => redirect(API.REJECT_REDIR_URL);
const shareEnvelope = (receiverMail, dateValid) => createPost(API.SHARE_URL, { receiverMail: receiverMail, dateValid: dateValid }, Content.JSON);

View File

@@ -1,2 +1,2 @@
class Content{static get JSON(){return"application/json"}}class API{static get REJECT_URL(){return`/api/envelope/reject`}static get REJECT_REDIR_URL(){return`/envelopekey/${API.ENV_KEY}/rejected`}static __XSRF_TOKEN class Content{static get JSON(){return"application/json"}}class API{static get REJECT_URL(){return`/api/envelope/reject`}static get REJECT_REDIR_URL(){return`/envelopekey/${API.ENV_KEY}/rejected`}static get SHARE_URL(){return`/api/readonly`}static __XSRF_TOKEN
static get XSRF_TOKEN(){return API.__XSRF_TOKEN??=document.getElementsByName("__RequestVerificationToken")[0].value,API.__XSRF_TOKEN}static get ENV_KEY(){return ENV_KEY??document.querySelector('meta[name="env-key"]').getAttribute("content")}}const submitForm=async n=>await fetch(n.action,{method:n.method,body:new FormData(n),headers:{"X-Requested-With":"XMLHttpRequest"}}),createRequest=async(n,t,i,r)=>fetch(t,{credentials:"include",method:n,headers:{"Content-Type":r,"X-XSRF-TOKEN":API.XSRF_TOKEN},body:JSON.stringify(i)}),createPost=(n,t,i)=>createRequest("POST",n,t,i),rejectEnvelope=n=>createPost(API.REJECT_URL,n,Content.JSON),redirect=n=>window.location.href=n,redirRejected=()=>redirect(API.REJECT_REDIR_URL); static get XSRF_TOKEN(){return API.__XSRF_TOKEN??=document.getElementsByName("__RequestVerificationToken")[0].value,API.__XSRF_TOKEN}static get ENV_KEY(){return ENV_KEY??document.querySelector('meta[name="env-key"]').getAttribute("content")}}const submitForm=async n=>await fetch(n.action,{method:n.method,body:new FormData(n),headers:{"X-Requested-With":"XMLHttpRequest"}}),createRequest=async(n,t,i,r)=>fetch(t,{credentials:"include",method:n,headers:{"Content-Type":r,"X-XSRF-TOKEN":API.XSRF_TOKEN},body:JSON.stringify(i)}),createPost=(n,t,i)=>createRequest("POST",n,t,i),rejectEnvelope=n=>createPost(API.REJECT_URL,n,Content.JSON),redirect=n=>window.location.href=n,redirRejected=()=>redirect(API.REJECT_REDIR_URL),shareEnvelope=(n,t)=>createPost(API.SHARE_URL,{receiverMail:n,dateValid:t},Content.JSON);

View File

@@ -48,7 +48,7 @@ class App {
// Load PSPDFKit // Load PSPDFKit
this.Instance = await UI.loadPSPDFKit(arrayBuffer, this.container, this.licenseKey, this.locale) this.Instance = await UI.loadPSPDFKit(arrayBuffer, this.container, this.licenseKey, this.locale)
UI.configurePSPDFKit(this.Instance, this.handleClick.bind(this)) UI.addToolbarItems(this.Instance, this.handleClick.bind(this))
this.Instance.addEventListener( this.Instance.addEventListener(
'annotations.load', 'annotations.load',
@@ -87,6 +87,7 @@ class App {
//add click events of external buttons //add click events of external buttons
[...document.getElementsByClassName('btn_refresh')].forEach(btn => btn.addEventListener('click', _ => this.handleClick('RESET'))); [...document.getElementsByClassName('btn_refresh')].forEach(btn => btn.addEventListener('click', _ => this.handleClick('RESET')));
[...document.getElementsByClassName('btn_complete')].forEach(btn => btn.addEventListener('click', _ => this.handleClick('FINISH'))); [...document.getElementsByClassName('btn_complete')].forEach(btn => btn.addEventListener('click', _ => this.handleClick('FINISH')));
[...document.getElementsByClassName('btn_reject')].forEach(btn => btn.addEventListener('click', _ => this.handleClick('REJECT')));
} }
handleAnnotationsLoad(loadedAnnotations) { handleAnnotationsLoad(loadedAnnotations) {
@@ -141,7 +142,7 @@ class App {
switch (eventType) { switch (eventType) {
case 'RESET': case 'RESET':
result = await this.handleReset(null) result = await this.handleReset(null)
Comp.SignatureProgress.SignedCount = 0;
if (result.isConfirmed) { if (result.isConfirmed) {
Swal.fire({ Swal.fire({
title: 'Erfolg', title: 'Erfolg',
@@ -149,8 +150,7 @@ class App {
icon: 'info', icon: 'info',
}) })
} }
break;
break
case 'FINISH': case 'FINISH':
result = await this.handleFinish(null) result = await this.handleFinish(null)
@@ -159,23 +159,70 @@ class App {
// Redirect to success page after saving to database // Redirect to success page after saving to database
window.location.href = `/EnvelopeKey/${this.envelopeKey}/Success` window.location.href = `/EnvelopeKey/${this.envelopeKey}/Success`
} }
break;
break
case 'REJECT': case 'REJECT':
alert('Dokument abgelent!') Swal.fire({
title: localized.rejection,
html: `<div class="text-start fs-6 p-0 m-0">${localized.rejectionReasonQ}</div>`,
icon: "question",
input: "text",
inputAttributes: {
autocapitalize: "off"
},
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: localized.complete,
cancelButtonText: localized.back,
showLoaderOnConfirm: true,
preConfirm: async (reason) => {
try {
var res = await rejectEnvelope(reason);
return res;
} catch (error) {
Swal.showValidationMessage(`
Request failed: ${error}
`);
}
},
allowOutsideClick: () => !Swal.isLoading()
}).then((result) => {
if (!result.isConfirmed)
return;
const res = result.value;
if (res.ok) {
redirRejected()
}
else
Swal.showValidationMessage(`Request failed: ${res.message}`);
});
break;
case 'COPY_URL':
const url = window.location.href;
navigator.clipboard.writeText(url).then(function () {
bsNotify('Kopiert', { alert_type: 'success', delay: 4, icon_name: 'check_circle' });
}).catch(function (err) {
bsNotify('Unerwarteter Fehler', { alert_type: 'danger', delay: 4, icon_name: 'error' });
});
break;
case 'SHARE':
// Show the modal
Comp.ShareBackdrop.show();
break;
} }
} }
async handleFinish(event) { async handleFinish(event) {
const iJSON = await this.Instance.exportInstantJSON() const iJSON = await this.Instance.exportInstantJSON()
const iFormFieldValues = await iJSON.formFieldValues; const iFormFieldValues = await iJSON.formFieldValues;
//check required //check required
const iReqFields = iFormFieldValues.filter(f => Annotation.isFieldRequired(f)) const iReqFields = iFormFieldValues.filter(f => Annotation.isFieldRequired(f))
const hasEmptyReq = iReqFields.some(f => (f.value === undefined || f.value === null || f.value === "")) const hasEmptyReq = iReqFields.some(f => (f.value === undefined || f.value === null || f.value === ""))
if (hasEmptyReq){ if (hasEmptyReq) {
Swal.fire({ Swal.fire({
title: 'Warnung', title: 'Warnung',
text: 'Bitte füllen Sie alle Standortinformationen vollständig aus!', text: 'Bitte füllen Sie alle Standortinformationen vollständig aus!',
@@ -187,8 +234,8 @@ class App {
//check city //check city
const city_regex = new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$") const city_regex = new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$")
const iCityFields = iFormFieldValues.filter(f => Annotation.isCityField(f)) const iCityFields = iFormFieldValues.filter(f => Annotation.isCityField(f))
for(var f of iCityFields) for (var f of iCityFields)
if(!city_regex.test(f.value)){ if (!city_regex.test(f.value)) {
Swal.fire({ Swal.fire({
title: 'Warnung', title: 'Warnung',
text: `Bitte überprüfen Sie die eingegebene Ortsangabe "${f.value}" auf korrekte Formatierung. Beispiele für richtige Formate sind: München, Île-de-France, Sauðárkrókur, San Francisco, St. Catharines usw.`, text: `Bitte überprüfen Sie die eingegebene Ortsangabe "${f.value}" auf korrekte Formatierung. Beispiele für richtige Formate sind: München, Île-de-France, Sauðárkrókur, San Francisco, St. Catharines usw.`,

View File

@@ -1 +1,3 @@
const ActionType={Created:0,Saved:1,Sent:2,EmailSent:3,Delivered:4,Seen:5,Signed:6,Rejected:7};class App{constructor(n,t,i,r,u,f){this.container=f??`#${this.constructor.name.toLowerCase()}`;this.envelopeKey=n;this.Network=new Network;this.Instance=null;this.currentDocument=null;this.currentReceiver=null;this.signatureCount=0;this.envelopeReceiver=t;this.documentBytes=i;this.licenseKey=r;this.locale=u}async init(){this.currentDocument=this.envelopeReceiver.envelope.documents[0];this.currentReceiver=this.envelopeReceiver.receiver;const n=this.documentBytes;if(n.fatal||n.error)return Swal.fire({title:"Fehler",text:"Dokument konnte nicht geladen werden!",icon:"error"});const t=this.documentBytes;this.Instance=await UI.loadPSPDFKit(t,this.container,this.licenseKey,this.locale);UI.configurePSPDFKit(this.Instance,this.handleClick.bind(this));this.Instance.addEventListener("annotations.load",this.handleAnnotationsLoad.bind(this));this.Instance.addEventListener("annotations.change",this.handleAnnotationsChange.bind(this));this.Instance.addEventListener("annotations.create",this.handleAnnotationsCreate.bind(this));this.Instance.addEventListener("annotations.willChange",()=>{Comp.ActPanel.Toggle()});try{this.signatureCount=this.currentDocument.elements.length;await Annotation.createAnnotations(this.currentDocument,this.Instance);const n=await this.Network.openDocument(this.envelopeKey);if(n.fatal||n.error)return Swal.fire({title:"Fehler",text:"Umschlag konnte nicht geöffnet werden!",icon:"error"})}catch(i){}[...document.getElementsByClassName("btn_refresh")].forEach(n=>n.addEventListener("click",()=>this.handleClick("RESET")));[...document.getElementsByClassName("btn_complete")].forEach(n=>n.addEventListener("click",()=>this.handleClick("FINISH")))}handleAnnotationsLoad(n){n.toJS()}handleAnnotationsChange(){}async handleAnnotationsCreate(n){const t=n.toJS()[0],i=!!t.formFieldName,r=!!t.isSignature;if(i===!1&&r===!0){const r=t.boundingBox.left-20,u=t.boundingBox.top-20,n=150,i=75,f=new Date,e=await Annotation.createAnnotationFrameBlob(this.envelopeReceiver.name,this.currentReceiver.signature,f,n,i),o=await fetch(e),s=await o.blob(),h=await this.Instance.createAttachment(s),c=Annotation.createImageAnnotation(new PSPDFKit.Geometry.Rect({left:r,top:u,width:n,height:i}),t.pageIndex,h);this.Instance.create(c)}}async handleClick(n){let t=!1;switch(n){case"RESET":t=await this.handleReset(null);t.isConfirmed&&Swal.fire({title:"Erfolg",text:"Dokument wurde zurückgesetzt",icon:"info"});break;case"FINISH":t=await this.handleFinish(null);t==!0&&(window.location.href=`/EnvelopeKey/${this.envelopeKey}/Success`);break;case"REJECT":alert("Dokument abgelent!")}}async handleFinish(){const n=await this.Instance.exportInstantJSON(),t=await n.formFieldValues,r=t.filter(n=>Annotation.isFieldRequired(n)),u=r.some(n=>n.value===undefined||n.value===null||n.value==="");if(u)return Swal.fire({title:"Warnung",text:"Bitte füllen Sie alle Standortinformationen vollständig aus!",icon:"warning"}),!1;const f=new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$"),e=t.filter(n=>Annotation.isCityField(n));for(var i of e)if(!f.test(i.value))return Swal.fire({title:"Warnung",text:`Bitte überprüfen Sie die eingegebene Ortsangabe "${i.value}" auf korrekte Formatierung. Beispiele für richtige Formate sind: München, Île-de-France, Sauðárkrókur, San Francisco, St. Catharines usw.`,icon:"warning"}),!1;const o=await this.validateAnnotations(this.signatureCount);return o===!1?(Swal.fire({title:"Warnung",text:"Es wurden nicht alle Signaturfelder ausgefüllt!",icon:"warning"}),!1):Swal.fire({title:localized.confirmation,html:`<div class="text-start fs-6 p-0 m-0">${localized.sigAgree}</div>`,icon:"question",showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.finalize,cancelButtonText:localized.back}).then(async t=>{if(t.isConfirmed){try{await this.Instance.save()}catch(i){return Swal.fire({title:"Fehler",text:"Umschlag konnte nicht signiert werden!",icon:"error"}),!1}try{const i=await n,t=await this.Network.postEnvelope(this.envelopeKey,this.currentDocument.id,i);return t.fatal?(Swal.fire({title:"Fehler",text:"Umschlag konnte nicht signiert werden!",icon:"error"}),!1):t.error?(Swal.fire({title:"Warnung",text:"Umschlag ist nicht mehr verfügbar.",icon:"warning"}),!1):!0}catch(i){return!1}}else return!1})}async validateAnnotations(n){const t=await Annotation.getAnnotations(this.Instance),i=t.map(n=>n.toJS()).filter(n=>n.isSignature);return n>i.length?!1:!0}async handleReset(){const n=await Swal.fire({title:"Sind sie sicher?",text:"Wollen Sie das Dokument und alle erstellten Signaturen zurücksetzen?",icon:"question",showCancelButton:!0});if(n.isConfirmed){const n=await Annotation.deleteAnnotations(this.Instance)}return n}} const ActionType={Created:0,Saved:1,Sent:2,EmailSent:3,Delivered:4,Seen:5,Signed:6,Rejected:7};class App{constructor(n,t,i,r,u,f){this.container=f??`#${this.constructor.name.toLowerCase()}`;this.envelopeKey=n;this.Network=new Network;this.Instance=null;this.currentDocument=null;this.currentReceiver=null;this.signatureCount=0;this.envelopeReceiver=t;this.documentBytes=i;this.licenseKey=r;this.locale=u}async init(){this.currentDocument=this.envelopeReceiver.envelope.documents[0];this.currentReceiver=this.envelopeReceiver.receiver;const n=this.documentBytes;if(n.fatal||n.error)return Swal.fire({title:"Fehler",text:"Dokument konnte nicht geladen werden!",icon:"error"});const t=this.documentBytes;this.Instance=await UI.loadPSPDFKit(t,this.container,this.licenseKey,this.locale);UI.addToolbarItems(this.Instance,this.handleClick.bind(this));this.Instance.addEventListener("annotations.load",this.handleAnnotationsLoad.bind(this));this.Instance.addEventListener("annotations.change",this.handleAnnotationsChange.bind(this));this.Instance.addEventListener("annotations.create",this.handleAnnotationsCreate.bind(this));this.Instance.addEventListener("annotations.willChange",()=>{Comp.ActPanel.Toggle()});try{this.signatureCount=this.currentDocument.elements.length;await Annotation.createAnnotations(this.currentDocument,this.Instance);const n=await this.Network.openDocument(this.envelopeKey);if(n.fatal||n.error)return Swal.fire({title:"Fehler",text:"Umschlag konnte nicht geöffnet werden!",icon:"error"})}catch(i){}[...document.getElementsByClassName("btn_refresh")].forEach(n=>n.addEventListener("click",()=>this.handleClick("RESET")));[...document.getElementsByClassName("btn_complete")].forEach(n=>n.addEventListener("click",()=>this.handleClick("FINISH")));[...document.getElementsByClassName("btn_reject")].forEach(n=>n.addEventListener("click",()=>this.handleClick("REJECT")))}handleAnnotationsLoad(n){n.toJS()}handleAnnotationsChange(){}async handleAnnotationsCreate(n){const t=n.toJS()[0],i=!!t.formFieldName,r=!!t.isSignature;if(i===!1&&r===!0){const r=t.boundingBox.left-20,u=t.boundingBox.top-20,n=150,i=75,f=new Date,e=await Annotation.createAnnotationFrameBlob(this.envelopeReceiver.name,this.currentReceiver.signature,f,n,i),o=await fetch(e),s=await o.blob(),h=await this.Instance.createAttachment(s),c=Annotation.createImageAnnotation(new PSPDFKit.Geometry.Rect({left:r,top:u,width:n,height:i}),t.pageIndex,h);this.Instance.create(c)}}async handleClick(n){let t=!1;switch(n){case"RESET":t=await this.handleReset(null);Comp.SignatureProgress.SignedCount=0;t.isConfirmed&&Swal.fire({title:"Erfolg",text:"Dokument wurde zurückgesetzt",icon:"info"});break;case"FINISH":t=await this.handleFinish(null);t==!0&&(window.location.href=`/EnvelopeKey/${this.envelopeKey}/Success`);break;case"REJECT":Swal.fire({title:localized.rejection,html:`<div class="text-start fs-6 p-0 m-0">${localized.rejectionReasonQ}</div>`,icon:"question",input:"text",inputAttributes:{autocapitalize:"off"},showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.complete,cancelButtonText:localized.back,showLoaderOnConfirm:!0,preConfirm:async n=>{try{return await rejectEnvelope(n)}catch(t){Swal.showValidationMessage(`
Request failed: ${t}
`)}},allowOutsideClick:()=>!Swal.isLoading()}).then(n=>{if(n.isConfirmed){const t=n.value;t.ok?redirRejected():Swal.showValidationMessage(`Request failed: ${t.message}`)}});break;case"COPY_URL":const n=window.location.href;navigator.clipboard.writeText(n).then(function(){bsNotify("Kopiert",{alert_type:"success",delay:4,icon_name:"check_circle"})}).catch(function(){bsNotify("Unerwarteter Fehler",{alert_type:"danger",delay:4,icon_name:"error"})});break;case"SHARE":Comp.ShareBackdrop.show()}}async handleFinish(){const n=await this.Instance.exportInstantJSON(),t=await n.formFieldValues,r=t.filter(n=>Annotation.isFieldRequired(n)),u=r.some(n=>n.value===undefined||n.value===null||n.value==="");if(u)return Swal.fire({title:"Warnung",text:"Bitte füllen Sie alle Standortinformationen vollständig aus!",icon:"warning"}),!1;const f=new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$"),e=t.filter(n=>Annotation.isCityField(n));for(var i of e)if(!f.test(i.value))return Swal.fire({title:"Warnung",text:`Bitte überprüfen Sie die eingegebene Ortsangabe "${i.value}" auf korrekte Formatierung. Beispiele für richtige Formate sind: München, Île-de-France, Sauðárkrókur, San Francisco, St. Catharines usw.`,icon:"warning"}),!1;const o=await this.validateAnnotations(this.signatureCount);return o===!1?(Swal.fire({title:"Warnung",text:"Es wurden nicht alle Signaturfelder ausgefüllt!",icon:"warning"}),!1):Swal.fire({title:localized.confirmation,html:`<div class="text-start fs-6 p-0 m-0">${localized.sigAgree}</div>`,icon:"question",showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.finalize,cancelButtonText:localized.back}).then(async t=>{if(t.isConfirmed){try{await this.Instance.save()}catch(i){return Swal.fire({title:"Fehler",text:"Umschlag konnte nicht signiert werden!",icon:"error"}),!1}try{const i=await n,t=await this.Network.postEnvelope(this.envelopeKey,this.currentDocument.id,i);return t.fatal?(Swal.fire({title:"Fehler",text:"Umschlag konnte nicht signiert werden!",icon:"error"}),!1):t.error?(Swal.fire({title:"Warnung",text:"Umschlag ist nicht mehr verfügbar.",icon:"warning"}),!1):!0}catch(i){return!1}}else return!1})}async validateAnnotations(n){const t=await Annotation.getAnnotations(this.Instance),i=t.map(n=>n.toJS()).filter(n=>n.isSignature);return n>i.length?!1:!0}async handleReset(){const n=await Swal.fire({title:"Sind sie sicher?",text:"Wollen Sie das Dokument und alle erstellten Signaturen zurücksetzen?",icon:"question",showCancelButton:!0});if(n.isConfirmed){const n=await Annotation.deleteAnnotations(this.Instance)}return n}}

View File

@@ -1,40 +1,17 @@
$('.btn_reject').click(_ => document.querySelectorAll('.email-input').forEach(input => {
Swal.fire({ input.addEventListener('input', function () {
title: localized.rejection, if (/^\S+@\S+\.\S+$/.test(this.value)) {
html: `<div class="text-start fs-6 p-0 m-0">${localized.rejectionReasonQ}</div>`, this.classList.remove('is-invalid');
icon: "question", } else {
input: "text", this.classList.add('is-invalid');
inputAttributes: {
autocapitalize: "off"
},
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: localized.complete,
cancelButtonText: localized.back,
showLoaderOnConfirm: true,
preConfirm: async (reason) => {
try {
var res = await rejectEnvelope(reason);
return res;
} catch (error) {
Swal.showValidationMessage(`
Request failed: ${error}
`);
}
},
allowOutsideClick: () => !Swal.isLoading()
}).then((result) => {
if (!result.isConfirmed)
return;
const res = result.value;
if (res.ok) {
redirRejected()
} }
else });
Swal.showValidationMessage(`Request failed: ${res.message}`); });
}));
const bsNotify = (message, options) => alertify.notify(
`<div class="alert ${options.alert_type ? 'alert-' + options.alert_type : ''}" role="alert"><span class="material-symbols-outlined">${options?.icon_name ?? ''}</span><p>${message}</p></div>`,
'custom',
options?.delay ?? 5);
class Comp { class Comp {
static ActPanel = class { static ActPanel = class {
@@ -64,4 +41,42 @@ class Comp {
Comp.ActPanel.Display = Comp.ActPanel.IsHided ? '' : 'none' Comp.ActPanel.Display = Comp.ActPanel.IsHided ? '' : 'none'
} }
} }
static SignatureProgress = class {
static __SignatureCount;
static get SignatureCount() {
this.__SignatureCount = parseInt(document.getElementById("signature-count").innerText);
return this.__SignatureCount;
}
static __SignedCountSpan;
static get SignedCountSpan() {
this.__SignedCountSpan ??= document.getElementById("signed-count");
return Comp.SignatureProgress.__SignedCountSpan;
}
static __signedCount = 0;
static get SignedCount() {
return this.__signedCount;
}
static set SignedCount(value) {
this.__signedCount = value;
const width = (value / this.SignatureCount) * 100;
this.SignedCountBar.style.setProperty('--progress-width', width + '%');
this.SignedCountSpan.innerText = value.toString();
}
static __SignedCountBar;
static get SignedCountBar() {
this.__SignedCountBar ??= document.getElementById("signed-count-bar");
return this.__SignedCountBar;
}
}
static __ShareBackdrop;
static get ShareBackdrop() {
Comp.__ShareBackdrop ??= new bootstrap.Modal(document.getElementById('shareBackdrop'));
return this.__ShareBackdrop;
}
} }

View File

@@ -1,3 +1 @@
$(".btn_reject").click(()=>Swal.fire({title:localized.rejection,html:`<div class="text-start fs-6 p-0 m-0">${localized.rejectionReasonQ}</div>`,icon:"question",input:"text",inputAttributes:{autocapitalize:"off"},showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.complete,cancelButtonText:localized.back,showLoaderOnConfirm:!0,preConfirm:async n=>{try{return await rejectEnvelope(n)}catch(t){Swal.showValidationMessage(` document.querySelectorAll(".email-input").forEach(n=>{n.addEventListener("input",function(){/^\S+@\S+\.\S+$/.test(this.value)?this.classList.remove("is-invalid"):this.classList.add("is-invalid")})});const bsNotify=(n,t)=>alertify.notify(`<div class="alert ${t.alert_type?"alert-"+t.alert_type:""}" role="alert"><span class="material-symbols-outlined">${t?.icon_name??""}</span><p>${n}</p></div>`,"custom",t?.delay??5);class Comp{static ActPanel=class{static __Root;static get Root(){Comp.ActPanel.__Root??=document.getElementById("flex-action-panel");return Comp.ActPanel.__Root}static get Elements(){return[...Comp.ActPanel.Root.children]}static get IsHided(){return Comp.ActPanel.Root.style.display=="none"}static set Display(n){Comp.ActPanel.Root.style.display=n;Comp.ActPanel.Elements.forEach(t=>t.style.display=n)}static Toggle(){Comp.ActPanel.Display=Comp.ActPanel.IsHided?"":"none"}};static SignatureProgress=class{static __SignatureCount;static get SignatureCount(){this.__SignatureCount=parseInt(document.getElementById("signature-count").innerText);return this.__SignatureCount}static __SignedCountSpan;static get SignedCountSpan(){this.__SignedCountSpan??=document.getElementById("signed-count");return Comp.SignatureProgress.__SignedCountSpan}static __signedCount=0;static get SignedCount(){return this.__signedCount}static set SignedCount(n){this.__signedCount=n;const t=(n/this.SignatureCount)*100;this.SignedCountBar.style.setProperty("--progress-width",t+"%");this.SignedCountSpan.innerText=n.toString()}static __SignedCountBar;static get SignedCountBar(){this.__SignedCountBar??=document.getElementById("signed-count-bar");return this.__SignedCountBar}};static __ShareBackdrop;static get ShareBackdrop(){return Comp.__ShareBackdrop??=new bootstrap.Modal(document.getElementById("shareBackdrop")),this.__ShareBackdrop}}
Request failed: ${t}
`)}},allowOutsideClick:()=>!Swal.isLoading()}).then(n=>{if(n.isConfirmed){const t=n.value;t.ok?redirRejected():Swal.showValidationMessage(`Request failed: ${t.message}`)}}));class Comp{static ActPanel=class{static __Root;static get Root(){Comp.ActPanel.__Root??=document.getElementById("flex-action-panel");return Comp.ActPanel.__Root}static get Elements(){return[...Comp.ActPanel.Root.children]}static get IsHided(){return Comp.ActPanel.Root.style.display=="none"}static set Display(n){Comp.ActPanel.Root.style.display=n;Comp.ActPanel.Elements.forEach(t=>t.style.display=n)}static Toggle(){Comp.ActPanel.Display=Comp.ActPanel.IsHided?"":"none"}};}

View File

@@ -10,6 +10,7 @@
'zoom-mode', 'zoom-mode',
'spacer', 'spacer',
'search', 'search',
'export-pdf'
] ]
// Load the PSPDFKit UI by setting a target element as the container to render in // Load the PSPDFKit UI by setting a target element as the container to render in
@@ -49,8 +50,17 @@
return UI.Instance; return UI.Instance;
} }
static configurePSPDFKit(instance, handler) { static addToolbarItems(instance, handler) {
const toolbarItems = UI.getToolbarItems(instance, handler) var toolbarItems = instance.toolbarItems.filter((item) => UI.allowedToolbarItems.includes(item.type));
if (IS_READONLY)
toolbarItems = toolbarItems.concat(UI.getReadOnlyItems(handler));
else
toolbarItems = toolbarItems.concat(UI.getWritableItems(handler));
if (!IS_DESKTOP && !IS_READONLY)
toolbarItems = toolbarItems.concat(UI.getMobileWritableItems(handler));
instance.setToolbarItems(toolbarItems) instance.setToolbarItems(toolbarItems)
} }
@@ -59,12 +69,6 @@
return null return null
} }
static getToolbarItems(instance, handler) {
const customItems = UI.getCustomItems(handler)
const defaultItems = UI.getDefaultItems(instance.toolbarItems)
return defaultItems.concat(customItems)
}
static createElementFromHTML(html) { static createElementFromHTML(html) {
const el = document.createElement('div') const el = document.createElement('div')
el.innerHTML = html.trim() el.innerHTML = html.trim()
@@ -72,21 +76,54 @@
return el.firstChild return el.firstChild
} }
static getCustomItems = function (callback) { static getWritableItems = function (callback) {
return []
return [ return [
{ {
type: 'custom', type: 'custom',
id: 'button-reset', id: 'button-share',
className: 'button-reset', className: 'button-share',
title: 'Zurücksetzen', title: 'Teilen',
onPress() { onPress() {
callback('RESET') callback('SHARE')
}, },
icon: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16"> icon: `<svg width="30" height="30" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z"/> <path d="M20 13V17.5C20 20.5577 16 20.5 12 20.5C8 20.5 4 20.5577 4 17.5V13M12 3L12 15M12 3L16 7M12 3L8 7" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"/> </svg>`,
</svg>`, }
];
}
static getReadOnlyItems = function (callback) {
return [
{
type: 'custom',
id: 'button-copy-url',
className: 'button-copy-url',
title: 'Teilen',
onPress() {
callback('COPY_URL')
},
icon: `<svg viewBox="4 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 3H9C6.79086 3 5 4.79086 5 7V15" stroke="#222222"/>
<path d="M8.5 11.5C8.5 10.3156 8.50074 9.46912 8.57435 8.81625C8.64681 8.17346 8.78457 7.78051 9.01662 7.4781C9.14962 7.30477 9.30477 7.14962 9.4781 7.01662C9.78051 6.78457 10.1735 6.64681 10.8163 6.57435C11.4691 6.50074 12.3156 6.5 13.5 6.5C14.6844 6.5 15.5309 6.50074 16.1837 6.57435C16.8265 6.64681 17.2195 6.78457 17.5219 7.01662C17.6952 7.14962 17.8504 7.30477 17.9834 7.4781C18.2154 7.78051 18.3532 8.17346 18.4257 8.81625C18.4993 9.46912 18.5 10.3156 18.5 11.5V15.5C18.5 16.6844 18.4993 17.5309 18.4257 18.1837C18.3532 18.8265 18.2154 19.2195 17.9834 19.5219C17.8504 19.6952 17.6952 19.8504 17.5219 19.9834C17.2195 20.2154 16.8265 20.3532 16.1837 20.4257C15.5309 20.4993 14.6844 20.5 13.5 20.5C12.3156 20.5 11.4691 20.4993 10.8163 20.4257C10.1735 20.3532 9.78051 20.2154 9.4781 19.9834C9.30477 19.8504 9.14962 19.6952 9.01662 19.5219C8.78457 19.2195 8.64681 18.8265 8.57435 18.1837C8.50074 17.5309 8.5 16.6844 8.5 15.5V11.5Z" stroke="#222222"/>
</svg>`,
}
];
}
static getMobileWritableItems = function (callback) {
return [
{
type: 'custom',
id: 'button-finish',
className: 'button-finish',
onPress() {
callback('FINISH')
},
icon: `<svg class="icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="-4 -4 26 26">
<path d="m10.036 8.278 9.258-7.79A1.979 1.979 0 0 0 18 0H2A1.987 1.987 0 0 0 .641.541l9.395 7.737Z" />
<path d="M11.241 9.817c-.36.275-.801.425-1.255.427-.428 0-.845-.138-1.187-.395L0 2.6V14a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V2.5l-8.759 7.317Z" />
</svg>`
}, },
{ {
type: 'custom', type: 'custom',
@@ -96,24 +133,24 @@
onPress() { onPress() {
callback('REJECT') callback('REJECT')
}, },
icon: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-hand-thumbs-down" viewBox="0 0 16 16"> icon: `<svg width="25px" height="25px" viewBox="43.5 43.5 512 512" version="1.1" fill="currentColor" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M8.864 15.674c-.956.24-1.843-.484-1.908-1.42-.072-1.05-.23-2.015-.428-2.59-.125-.36-.479-1.012-1.04-1.638-.557-.624-1.282-1.179-2.131-1.41C2.685 8.432 2 7.85 2 7V3c0-.845.682-1.464 1.448-1.546 1.07-.113 1.564-.415 2.068-.723l.048-.029c.272-.166.578-.349.97-.484C6.931.08 7.395 0 8 0h3.5c.937 0 1.599.478 1.934 1.064.164.287.254.607.254.913 0 .152-.023.312-.077.464.201.262.38.577.488.9.11.33.172.762.004 1.15.069.13.12.268.159.403.077.27.113.567.113.856 0 .289-.036.586-.113.856-.035.12-.08.244-.138.363.394.571.418 1.2.234 1.733-.206.592-.682 1.1-1.2 1.272-.847.283-1.803.276-2.516.211a9.877 9.877 0 0 1-.443-.05 9.364 9.364 0 0 1-.062 4.51c-.138.508-.55.848-1.012.964zM11.5 1H8c-.51 0-.863.068-1.14.163-.281.097-.506.229-.776.393l-.04.025c-.555.338-1.198.73-2.49.868-.333.035-.554.29-.554.55V7c0 .255.226.543.62.65 1.095.3 1.977.997 2.614 1.709.635.71 1.064 1.475 1.238 1.977.243.7.407 1.768.482 2.85.025.362.36.595.667.518l.262-.065c.16-.04.258-.144.288-.255a8.34 8.34 0 0 0-.145-4.726.5.5 0 0 1 .595-.643h.003l.014.004.058.013a8.912 8.912 0 0 0 1.036.157c.663.06 1.457.054 2.11-.163.175-.059.45-.301.57-.651.107-.308.087-.67-.266-1.021L12.793 7l.353-.354c.043-.042.105-.14.154-.315.048-.167.075-.37.075-.581 0-.211-.027-.414-.075-.581-.05-.174-.111-.273-.154-.315l-.353-.354.353-.354c.047-.047.109-.176.005-.488a2.224 2.224 0 0 0-.505-.804l-.353-.354.353-.354c.006-.005.041-.05.041-.17a.866.866 0 0 0-.121-.415C12.4 1.272 12.063 1 11.5 1"/> <path class="st0" d="M263.24,43.5c-117.36,0-212.5,95.14-212.5,212.5s95.14,212.5,212.5,212.5s212.5-95.14,212.5-212.5 S380.6,43.5,263.24,43.5z M367.83,298.36c17.18,17.18,17.18,45.04,0,62.23v0c-17.18,17.18-45.04,17.18-62.23,0l-42.36-42.36 l-42.36,42.36c-17.18,17.18-45.04,17.18-62.23,0v0c-17.18-17.18-17.18-45.04,0-62.23L201.01,256l-42.36-42.36 c-17.18-17.18-17.18-45.04,0-62.23v0c17.18-17.18,45.04-17.18,62.23,0l42.36,42.36l42.36-42.36c17.18-17.18,45.04-17.18,62.23,0v0 c17.18,17.18,17.18,45.04,0,62.23L325.46,256L367.83,298.36z" />
</svg>`, </svg>`,
}, },
{ {
type: 'custom', type: 'custom',
id: 'button-finish', id: 'button-reset',
className: 'button-finish', className: 'button-reset',
title: 'Abschließen', title: 'Zurücksetzen',
onPress() { onPress() {
callback('FINISH') callback('RESET')
}, },
}, icon: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="-1 -1 16 16">
] <path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z"/>
} <path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"/>
</svg>`,
static getDefaultItems(items) { }
return items.filter((item) => UI.allowedToolbarItems.includes(item.type)) ];
} }
static getPresets() { static getPresets() {

View File

@@ -1,7 +1,15 @@
class UI{static allowedToolbarItems=["sidebar-thumbnails","sidebar-document-ouline","sidebar-bookmarks","pager","pan","zoom-out","zoom-in","zoom-mode","spacer","search",];static Instance class UI{static allowedToolbarItems=["sidebar-thumbnails","sidebar-document-ouline","sidebar-bookmarks","pager","pan","zoom-out","zoom-in","zoom-mode","spacer","search","export-pdf"];static Instance
static loadPSPDFKit(n,t,i,r){return UI.Instance=PSPDFKit.load({inlineWorkers:!1,locale:r,licenseKey:i,styleSheets:["/css/site.css"],container:t,document:n,annotationPresets:UI.getPresets(),electronicSignatures:{creationModes:["DRAW","TYPE","IMAGE"]},initialViewState:new PSPDFKit.ViewState({sidebarMode:PSPDFKit.SidebarMode.THUMBNAILS}),isEditableAnnotation:function(n){return n.isSignature||n.description=="FRAME"?!1:!0},customRenderers:{Annotation:UI.annotationRenderer}}),UI.Instance}static configurePSPDFKit(n,t){const i=UI.getToolbarItems(n,t);n.setToolbarItems(i)}static annotationRenderer(){return null}static getToolbarItems(n,t){const i=UI.getCustomItems(t),r=UI.getDefaultItems(n.toolbarItems);return r.concat(i)}static createElementFromHTML(n){const t=document.createElement("div");return t.innerHTML=n.trim(),t.firstChild}static getCustomItems=function(n){return[];return[{type:"custom",id:"button-reset",className:"button-reset",title:"Zurücksetzen",onPress(){n("RESET")},icon:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16"> static loadPSPDFKit(n,t,i,r){return UI.Instance=PSPDFKit.load({inlineWorkers:!1,locale:r,licenseKey:i,styleSheets:["/css/site.css"],container:t,document:n,annotationPresets:UI.getPresets(),electronicSignatures:{creationModes:["DRAW","TYPE","IMAGE"]},initialViewState:new PSPDFKit.ViewState({sidebarMode:PSPDFKit.SidebarMode.THUMBNAILS}),isEditableAnnotation:function(n){return n.isSignature||n.description=="FRAME"?!1:!0},customRenderers:{Annotation:UI.annotationRenderer}}),UI.Instance}static addToolbarItems(n,t){var i=n.toolbarItems.filter(n=>UI.allowedToolbarItems.includes(n.type));i=IS_READONLY?i.concat(UI.getReadOnlyItems(t)):i.concat(UI.getWritableItems(t));IS_DESKTOP||IS_READONLY||(i=i.concat(UI.getMobileWritableItems(t)));n.setToolbarItems(i)}static annotationRenderer(){return null}static createElementFromHTML(n){const t=document.createElement("div");return t.innerHTML=n.trim(),t.firstChild}static getWritableItems=function(n){return[{type:"custom",id:"button-share",className:"button-share",title:"Teilen",onPress(){n("SHARE")},icon:`<svg width="30" height="30" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z"/> <path d="M20 13V17.5C20 20.5577 16 20.5 12 20.5C8 20.5 4 20.5577 4 17.5V13M12 3L12 15M12 3L16 7M12 3L8 7" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"/> </svg>`}]};static getReadOnlyItems=function(n){return[{type:"custom",id:"button-copy-url",className:"button-copy-url",title:"Teilen",onPress(){n("COPY_URL")},icon:`<svg viewBox="4 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
</svg>`},{type:"custom",id:"button-reject",className:"button-reject",title:"Ablehnen",onPress(){n("REJECT")},icon:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-hand-thumbs-down" viewBox="0 0 16 16"> <path d="M15 3H9C6.79086 3 5 4.79086 5 7V15" stroke="#222222"/>
<path d="M8.864 15.674c-.956.24-1.843-.484-1.908-1.42-.072-1.05-.23-2.015-.428-2.59-.125-.36-.479-1.012-1.04-1.638-.557-.624-1.282-1.179-2.131-1.41C2.685 8.432 2 7.85 2 7V3c0-.845.682-1.464 1.448-1.546 1.07-.113 1.564-.415 2.068-.723l.048-.029c.272-.166.578-.349.97-.484C6.931.08 7.395 0 8 0h3.5c.937 0 1.599.478 1.934 1.064.164.287.254.607.254.913 0 .152-.023.312-.077.464.201.262.38.577.488.9.11.33.172.762.004 1.15.069.13.12.268.159.403.077.27.113.567.113.856 0 .289-.036.586-.113.856-.035.12-.08.244-.138.363.394.571.418 1.2.234 1.733-.206.592-.682 1.1-1.2 1.272-.847.283-1.803.276-2.516.211a9.877 9.877 0 0 1-.443-.05 9.364 9.364 0 0 1-.062 4.51c-.138.508-.55.848-1.012.964zM11.5 1H8c-.51 0-.863.068-1.14.163-.281.097-.506.229-.776.393l-.04.025c-.555.338-1.198.73-2.49.868-.333.035-.554.29-.554.55V7c0 .255.226.543.62.65 1.095.3 1.977.997 2.614 1.709.635.71 1.064 1.475 1.238 1.977.243.7.407 1.768.482 2.85.025.362.36.595.667.518l.262-.065c.16-.04.258-.144.288-.255a8.34 8.34 0 0 0-.145-4.726.5.5 0 0 1 .595-.643h.003l.014.004.058.013a8.912 8.912 0 0 0 1.036.157c.663.06 1.457.054 2.11-.163.175-.059.45-.301.57-.651.107-.308.087-.67-.266-1.021L12.793 7l.353-.354c.043-.042.105-.14.154-.315.048-.167.075-.37.075-.581 0-.211-.027-.414-.075-.581-.05-.174-.111-.273-.154-.315l-.353-.354.353-.354c.047-.047.109-.176.005-.488a2.224 2.224 0 0 0-.505-.804l-.353-.354.353-.354c.006-.005.041-.05.041-.17a.866.866 0 0 0-.121-.415C12.4 1.272 12.063 1 11.5 1"/> <path d="M8.5 11.5C8.5 10.3156 8.50074 9.46912 8.57435 8.81625C8.64681 8.17346 8.78457 7.78051 9.01662 7.4781C9.14962 7.30477 9.30477 7.14962 9.4781 7.01662C9.78051 6.78457 10.1735 6.64681 10.8163 6.57435C11.4691 6.50074 12.3156 6.5 13.5 6.5C14.6844 6.5 15.5309 6.50074 16.1837 6.57435C16.8265 6.64681 17.2195 6.78457 17.5219 7.01662C17.6952 7.14962 17.8504 7.30477 17.9834 7.4781C18.2154 7.78051 18.3532 8.17346 18.4257 8.81625C18.4993 9.46912 18.5 10.3156 18.5 11.5V15.5C18.5 16.6844 18.4993 17.5309 18.4257 18.1837C18.3532 18.8265 18.2154 19.2195 17.9834 19.5219C17.8504 19.6952 17.6952 19.8504 17.5219 19.9834C17.2195 20.2154 16.8265 20.3532 16.1837 20.4257C15.5309 20.4993 14.6844 20.5 13.5 20.5C12.3156 20.5 11.4691 20.4993 10.8163 20.4257C10.1735 20.3532 9.78051 20.2154 9.4781 19.9834C9.30477 19.8504 9.14962 19.6952 9.01662 19.5219C8.78457 19.2195 8.64681 18.8265 8.57435 18.1837C8.50074 17.5309 8.5 16.6844 8.5 15.5V11.5Z" stroke="#222222"/>
</svg>`},{type:"custom",id:"button-finish",className:"button-finish",title:"Abschließen",onPress(){n("FINISH")}},]};static getDefaultItems(n){return n.filter(n=>UI.allowedToolbarItems.includes(n.type))}static getPresets(){const n=PSPDFKit.defaultAnnotationPresets;return n.ink={lineWidth:10},n.widget={readOnly:!0},n}} </svg>`}]};static getMobileWritableItems=function(n){return[{type:"custom",id:"button-finish",className:"button-finish",onPress(){n("FINISH")},icon:`<svg class="icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="-4 -4 26 26">
<path d="m10.036 8.278 9.258-7.79A1.979 1.979 0 0 0 18 0H2A1.987 1.987 0 0 0 .641.541l9.395 7.737Z" />
<path d="M11.241 9.817c-.36.275-.801.425-1.255.427-.428 0-.845-.138-1.187-.395L0 2.6V14a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V2.5l-8.759 7.317Z" />
</svg>`},{type:"custom",id:"button-reject",className:"button-reject",title:"Ablehnen",onPress(){n("REJECT")},icon:`<svg width="25px" height="25px" viewBox="43.5 43.5 512 512" version="1.1" fill="currentColor" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path class="st0" d="M263.24,43.5c-117.36,0-212.5,95.14-212.5,212.5s95.14,212.5,212.5,212.5s212.5-95.14,212.5-212.5 S380.6,43.5,263.24,43.5z M367.83,298.36c17.18,17.18,17.18,45.04,0,62.23v0c-17.18,17.18-45.04,17.18-62.23,0l-42.36-42.36 l-42.36,42.36c-17.18,17.18-45.04,17.18-62.23,0v0c-17.18-17.18-17.18-45.04,0-62.23L201.01,256l-42.36-42.36 c-17.18-17.18-17.18-45.04,0-62.23v0c17.18-17.18,45.04-17.18,62.23,0l42.36,42.36l42.36-42.36c17.18-17.18,45.04-17.18,62.23,0v0 c17.18,17.18,17.18,45.04,0,62.23L325.46,256L367.83,298.36z" />
</svg>`},{type:"custom",id:"button-reset",className:"button-reset",title:"Zurücksetzen",onPress(){n("RESET")},icon:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="-1 -1 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z"/>
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"/>
</svg>`}]};static getPresets(){const n=PSPDFKit.defaultAnnotationPresets;return n.ink={lineWidth:10},n.widget={readOnly:!0},n}}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,435 +0,0 @@
import EventHandler from '../../mdb/dom/event-handler';
import SelectorEngine from '../../mdb/dom/selector-engine';
import Manipulator from '../../mdb/dom/manipulator';
import {
isDisabled,
getElementFromSelector,
isVisible,
getSelectorFromElement,
} from '../../mdb/util';
import { enableDismissTrigger } from '../../bootstrap/mdb-prefix/util/component-functions';
const alertCallback = (component, initSelector) => {
const Alert = component;
enableDismissTrigger(Alert, 'close');
// MDB init
SelectorEngine.find(initSelector).forEach((element) => {
return Alert.getOrCreateInstance(element);
});
};
const buttonCallback = (component, initSelector) => {
const Button = component;
const EVENT_CLICK_DATA_API = `click.bs.${component.name}.data-api`;
// BS init
EventHandler.on(document, EVENT_CLICK_DATA_API, initSelector, (event) => {
event.preventDefault();
const button = event.target.closest(initSelector);
const data = Button.getOrCreateInstance(button);
data.toggle();
});
// MDB init
SelectorEngine.find(initSelector).forEach((element) => {
return Button.getOrCreateInstance(element);
});
};
const carouselCallback = (component, initSelector) => {
const EVENT_CLICK_DATA_API = `click.bs.${component.name}.data-api`;
const SELECTOR_DATA_SLIDE = '[data-mdb-slide], [data-mdb-slide-to]';
const CLASS_NAME_CAROUSEL = 'carousel';
const Carousel = component;
const EVENT_LOAD_DATA_API = `load.bs.${component.name}.data-api`;
const SELECTOR_DATA_RIDE = initSelector;
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {
const target = getElementFromSelector(this);
if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {
return;
}
event.preventDefault();
const carousel = Carousel.getOrCreateInstance(target);
const slideIndex = this.getAttribute('data-mdb-slide-to');
if (slideIndex) {
carousel.to(slideIndex);
carousel._maybeEnableCycle();
return;
}
if (Manipulator.getDataAttribute(this, 'slide') === 'next') {
carousel.next();
carousel._maybeEnableCycle();
return;
}
carousel.prev();
carousel._maybeEnableCycle();
});
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE);
carousels.forEach((carousel) => {
Carousel.getOrCreateInstance(carousel);
});
});
};
const collapseCallback = (component, initSelector) => {
const EVENT_CLICK_DATA_API = `click.bs.${component.name}.data-api`;
const SELECTOR_DATA_TOGGLE = initSelector;
const Collapse = component;
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
// preventDefault only for <a> elements (which change the URL) not inside the collapsible element
if (
event.target.tagName === 'A' ||
(event.delegateTarget && event.delegateTarget.tagName === 'A')
) {
event.preventDefault();
}
const selector = getSelectorFromElement(this);
const selectorElements = SelectorEngine.find(selector);
selectorElements.forEach((element) => {
Collapse.getOrCreateInstance(element, { toggle: false }).toggle();
});
});
SelectorEngine.find(SELECTOR_DATA_TOGGLE).forEach((el) => {
const selector = getSelectorFromElement(el);
const selectorElements = SelectorEngine.find(selector);
selectorElements.forEach((element) => {
Collapse.getOrCreateInstance(element, { toggle: false });
});
});
};
const dropdownCallback = (component, initSelector) => {
const EVENT_CLICK_DATA_API = `click.bs.${component.name}.data-api`;
const EVENT_KEYDOWN_DATA_API = `keydown.bs.${component.name}.data-api`;
const EVENT_KEYUP_DATA_API = `keyup.bs.${component.name}.data-api`;
const SELECTOR_MENU = '.dropdown-menu';
const SELECTOR_DATA_TOGGLE = `[data-mdb-${component.NAME}-initialized]`;
const Dropdown = component;
EventHandler.on(
document,
EVENT_KEYDOWN_DATA_API,
SELECTOR_DATA_TOGGLE,
Dropdown.dataApiKeydownHandler
);
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler);
EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus);
EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus);
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
event.preventDefault();
Dropdown.getOrCreateInstance(this).toggle();
});
SelectorEngine.find(initSelector).forEach((el) => {
Dropdown.getOrCreateInstance(el);
});
};
const inputCallback = (component, initSelector) => {
const SELECTOR_DATA_INIT = initSelector;
const SELECTOR_OUTLINE_INPUT = `${SELECTOR_DATA_INIT} input`;
const SELECTOR_OUTLINE_TEXTAREA = `${SELECTOR_DATA_INIT} textarea`;
const Input = component;
EventHandler.on(document, 'focus', SELECTOR_OUTLINE_INPUT, Input.activate(new Input()));
EventHandler.on(document, 'input', SELECTOR_OUTLINE_INPUT, Input.activate(new Input()));
EventHandler.on(document, 'blur', SELECTOR_OUTLINE_INPUT, Input.deactivate(new Input()));
EventHandler.on(document, 'focus', SELECTOR_OUTLINE_TEXTAREA, Input.activate(new Input()));
EventHandler.on(document, 'input', SELECTOR_OUTLINE_TEXTAREA, Input.activate(new Input()));
EventHandler.on(document, 'blur', SELECTOR_OUTLINE_TEXTAREA, Input.deactivate(new Input()));
EventHandler.on(window, 'shown.bs.modal', (e) => {
SelectorEngine.find(SELECTOR_OUTLINE_INPUT, e.target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.update();
});
SelectorEngine.find(SELECTOR_OUTLINE_TEXTAREA, e.target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.update();
});
});
EventHandler.on(window, 'shown.bs.dropdown', (e) => {
const target = e.target.parentNode.querySelector('.dropdown-menu');
if (target) {
SelectorEngine.find(SELECTOR_OUTLINE_INPUT, target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.update();
});
SelectorEngine.find(SELECTOR_OUTLINE_TEXTAREA, target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.update();
});
}
});
EventHandler.on(window, 'shown.bs.tab', (e) => {
let targetId;
if (e.target.href) {
targetId = e.target.href.split('#')[1];
} else {
targetId = Manipulator.getDataAttribute(e.target, 'target').split('#')[1];
}
const target = SelectorEngine.findOne(`#${targetId}`);
SelectorEngine.find(SELECTOR_OUTLINE_INPUT, target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.update();
});
SelectorEngine.find(SELECTOR_OUTLINE_TEXTAREA, target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.update();
});
});
// auto-init
SelectorEngine.find(SELECTOR_DATA_INIT).map((element) => new Input(element));
// form reset handler
EventHandler.on(window, 'reset', (e) => {
SelectorEngine.find(SELECTOR_OUTLINE_INPUT, e.target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.forceInactive();
});
SelectorEngine.find(SELECTOR_OUTLINE_TEXTAREA, e.target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.forceInactive();
});
});
// auto-fill
EventHandler.on(window, 'onautocomplete', (e) => {
const instance = Input.getInstance(e.target.parentNode);
if (!instance || !e.cancelable) {
return;
}
instance.forceActive();
});
};
const modalCallback = (component, initSelector) => {
const EVENT_CLICK_DATA_API = `click.bs.${component.name}.data-api`;
const OPEN_SELECTOR = '.modal.show';
const Modal = component;
const EVENT_SHOW = `show.bs.${component.name}`;
const EVENT_HIDDEN = `hidden.bs.${component.name}`;
EventHandler.on(document, EVENT_CLICK_DATA_API, initSelector, function (event) {
const target = getElementFromSelector(this);
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault();
}
EventHandler.one(target, EVENT_SHOW, (showEvent) => {
if (showEvent.defaultPrevented) {
// only register focus restorer if modal will actually get shown
return;
}
EventHandler.one(target, EVENT_HIDDEN, () => {
if (isVisible(this)) {
this.focus();
}
});
});
// avoid conflict when clicking modal toggler while another one is open
const alreadyOpenedModals = SelectorEngine.find(OPEN_SELECTOR);
alreadyOpenedModals.forEach((modal) => {
if (!modal.classList.contains('modal-non-invasive-show')) {
Modal.getInstance(modal).hide();
}
});
const data = Modal.getOrCreateInstance(target);
data.toggle(this);
});
enableDismissTrigger(Modal);
SelectorEngine.find(initSelector).forEach((el) => {
const selector = getSelectorFromElement(el);
const selectorElement = SelectorEngine.findOne(selector);
Modal.getOrCreateInstance(selectorElement);
});
};
const popoverCallback = (component, initSelector) => {
const Popover = component;
const SELECTOR_DATA_TOGGLE = initSelector;
SelectorEngine.find(SELECTOR_DATA_TOGGLE).forEach((el) => {
Popover.getOrCreateInstance(el);
});
};
const offcanvasCallback = (component, initSelector) => {
const EVENT_CLICK_DATA_API = `click.bs.${component.name}.data-api`;
const OPEN_SELECTOR = '.offcanvas.show';
const Offcanvas = component;
const EVENT_HIDDEN = `hidden.bs.${component.name}`;
const EVENT_LOAD_DATA_API = `load.bs.${component.name}.data-api`;
const EVENT_RESIZE = `resize.bs.${component.name}`;
EventHandler.on(document, EVENT_CLICK_DATA_API, initSelector, function (event) {
const target = getElementFromSelector(this);
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault();
}
if (isDisabled(this)) {
return;
}
EventHandler.one(target, EVENT_HIDDEN, () => {
// focus on trigger when it is closed
if (isVisible(this)) {
this.focus();
}
});
// avoid conflict when clicking a toggler of an offcanvas, while another is open
const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR);
if (alreadyOpen && alreadyOpen !== target) {
Offcanvas.getInstance(alreadyOpen).hide();
}
const data = Offcanvas.getOrCreateInstance(target);
data.toggle(this);
});
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
SelectorEngine.find(OPEN_SELECTOR).forEach((selector) => {
Offcanvas.getOrCreateInstance(selector).show();
});
});
EventHandler.on(window, EVENT_RESIZE, () => {
SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]').forEach((element) => {
if (getComputedStyle(element).position !== 'fixed') {
Offcanvas.getOrCreateInstance(element).hide();
}
});
});
enableDismissTrigger(Offcanvas);
};
const scrollspyCallback = (component, initSelector) => {
const EVENT_LOAD_DATA_API = `load.bs.${component.name}.data-api`;
const ScrollSpy = component;
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
SelectorEngine.find(initSelector).forEach((el) => {
ScrollSpy.getOrCreateInstance(el);
});
});
};
const tabCallback = (component, initSelector) => {
const EVENT_LOAD_DATA_API = `load.bs.${component.name}.data-api`;
const EVENT_CLICK_DATA_API = `click.bs.${component.name}.data-api`;
const CLASS_NAME_ACTIVE = 'active';
const SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-mdb-tab-init], .${CLASS_NAME_ACTIVE}[data-mdb-pill-init], .${CLASS_NAME_ACTIVE}[data-mdb-toggle="list"]`;
const Tab = component;
EventHandler.on(document, EVENT_CLICK_DATA_API, initSelector, function (event) {
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault();
}
if (isDisabled(this)) {
return;
}
Tab.getOrCreateInstance(this).show();
});
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE).forEach((element) => {
Tab.getOrCreateInstance(element);
});
});
};
const toastCallback = (component, initSelector) => {
const Toast = component;
enableDismissTrigger(Toast);
// MDB init
SelectorEngine.find(initSelector).forEach((element) => {
return Toast.getOrCreateInstance(element);
});
};
const rippleCallback = (component, initSelector) => {
const Ripple = component;
EventHandler.one(document, 'mousedown', initSelector, Ripple.autoInitial(new Ripple()));
};
export {
alertCallback,
buttonCallback,
carouselCallback,
collapseCallback,
dropdownCallback,
inputCallback,
modalCallback,
offcanvasCallback,
tabCallback,
toastCallback,
popoverCallback,
rippleCallback,
scrollspyCallback,
};

View File

@@ -1,7 +0,0 @@
import defaultInitSelectors from './initSelectors/free';
import { InitMDB } from './init';
const initMDBInstance = new InitMDB(defaultInitSelectors);
const initMDB = initMDBInstance.initMDB;
export default initMDB;

View File

@@ -1,105 +0,0 @@
import SelectorEngine from '../mdb/dom/selector-engine';
import { defineJQueryPlugin } from '../mdb/util/index';
const mapComponentsData = (() => {
const componentsData = [];
return {
set(componentName) {
componentsData.push(componentName);
},
get(componentName) {
return componentsData.includes(componentName);
},
};
})();
export const InitializedComponents = {
set(componentName) {
mapComponentsData.set(componentName);
},
get(componentName) {
return mapComponentsData.get(componentName);
},
};
const isInitialized = (componentName) => {
return InitializedComponents.get(componentName);
};
export const bindCallbackEventsIfNeeded = (component) => {
if (!isInitialized(component.NAME)) {
const manualInit = true;
initComponent(component, manualInit);
}
};
const initComponent = (component, manualInit = false) => {
if (!component || InitializedComponents.get(component.NAME)) {
return;
}
InitializedComponents.set(component.NAME);
const thisComponent = _defaultInitSelectors[component.NAME] || null;
const isToggler = thisComponent?.isToggler || false;
defineJQueryPlugin(component);
if (thisComponent?.advanced) {
thisComponent.advanced(component, thisComponent?.selector);
return;
}
if (isToggler) {
thisComponent.callback(component, thisComponent?.selector);
return;
}
if (manualInit) {
return;
}
SelectorEngine.find(thisComponent?.selector).forEach((element) => {
let instance = component.getInstance(element);
if (!instance) {
instance = new component(element); // eslint-disable-line
if (thisComponent?.onInit) {
instance[thisComponent.onInit]();
}
}
});
};
let _defaultInitSelectors;
export class InitMDB {
constructor(defaultInitSelectors) {
_defaultInitSelectors = defaultInitSelectors;
}
init = (components) => {
components.forEach((component) => initComponent(component));
};
initMDB = (components, checkOtherImports = false) => {
const componentList = Object.keys(_defaultInitSelectors).map((element) => {
const requireAutoInit = Boolean(
document.querySelector(_defaultInitSelectors[element].selector)
);
if (requireAutoInit) {
const component = components[_defaultInitSelectors[element].name];
if (!component && !InitializedComponents.get(element) && checkOtherImports) {
// eslint-disable-next-line no-console
console.warn(
`Please import ${_defaultInitSelectors[element].name} from "MDB" package and add it to a object parameter inside "initMDB" function`
);
}
return component;
}
return null;
});
this.init(componentList);
};
}

View File

@@ -1,108 +0,0 @@
import {
alertCallback,
dropdownCallback,
offcanvasCallback,
tabCallback,
buttonCallback,
modalCallback,
rippleCallback,
collapseCallback,
carouselCallback,
scrollspyCallback,
toastCallback,
inputCallback,
} from '../callbacks/free';
const defaultInitSelectors = {
// Bootstrap Components
alert: {
name: 'Alert',
selector: '[data-mdb-alert-init]',
isToggler: true,
callback: alertCallback,
},
button: {
name: 'Button',
selector: '[data-mdb-button-init]',
isToggler: true,
callback: buttonCallback,
},
carousel: {
name: 'Carousel',
selector: '[data-mdb-carousel-init]',
isToggler: true,
callback: carouselCallback,
},
collapse: {
name: 'Collapse',
selector: '[data-mdb-collapse-init]',
isToggler: true,
callback: collapseCallback,
},
dropdown: {
name: 'Dropdown',
selector: '[data-mdb-dropdown-init]',
isToggler: true,
callback: dropdownCallback,
},
modal: {
name: 'Modal',
selector: '[data-mdb-modal-init]',
isToggler: true,
callback: modalCallback,
},
offcanvas: {
name: 'Offcanvas',
selector: '[data-mdb-offcanvas-init]',
isToggler: true,
callback: offcanvasCallback,
},
scrollspy: {
name: 'ScrollSpy',
selector: '[data-mdb-scrollspy-init]',
isToggler: true,
callback: scrollspyCallback,
},
tab: {
name: 'Tab',
selector: '[data-mdb-tab-init], [data-mdb-pill-init], [data-mdb-list-init]',
isToggler: true,
callback: tabCallback,
},
toast: {
name: 'Toast',
selector: '[data-mdb-toast-init]',
isToggler: true,
callback: toastCallback,
},
tooltip: {
name: 'Tooltip',
selector: '[data-mdb-tooltip-init]',
isToggler: false,
},
input: {
name: 'Input',
selector: '[data-mdb-input-init]',
isToggler: true,
callback: inputCallback,
},
range: {
name: 'Range',
selector: '[data-mdb-range-init]',
isToggler: false,
},
ripple: {
name: 'Ripple',
selector: '[data-mdb-ripple-init]',
isToggler: true,
callback: rippleCallback,
},
popover: {
name: 'Popover',
selector: '[data-mdb-popover-init]',
isToggler: false,
callback: rippleCallback,
},
};
export default defaultInitSelectors;

View File

@@ -1,105 +0,0 @@
/*!
* Bootstrap alert.js v5.3.2 (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory(
require('./base-component.js'),
require('./dom/event-handler.js'),
require('./util/component-functions.js'),
require('./util/index.js')
))
: typeof define === 'function' && define.amd
? define(
['./base-component', './dom/event-handler', './util/component-functions', './util/index'],
factory
)
: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
(global.Alert = factory(
global.BaseComponent,
global.EventHandler,
global.ComponentFunctions,
global.Index
)));
})(this, function (BaseComponent, EventHandler, componentFunctions_js, index_js) {
'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap alert.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const NAME = 'alert';
const DATA_KEY = 'bs.alert';
const EVENT_KEY = `.${DATA_KEY}`;
const EVENT_CLOSE = `close${EVENT_KEY}`;
const EVENT_CLOSED = `closed${EVENT_KEY}`;
const CLASS_NAME_FADE = 'fade';
const CLASS_NAME_SHOW = 'show';
/**
* Class definition
*/
class Alert extends BaseComponent {
// Getters
static get NAME() {
return NAME;
}
// Public
close() {
const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE);
if (closeEvent.defaultPrevented) {
return;
}
this._element.classList.remove(CLASS_NAME_SHOW);
const isAnimated = this._element.classList.contains(CLASS_NAME_FADE);
this._queueCallback(() => this._destroyElement(), this._element, isAnimated);
}
// Private
_destroyElement() {
this._element.remove();
EventHandler.trigger(this._element, EVENT_CLOSED);
this.dispose();
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Alert.getOrCreateInstance(this);
if (typeof config !== 'string') {
return;
}
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`);
}
data[config](this);
});
}
}
/**
* Data API implementation
*/
componentFunctions_js.enableDismissTrigger(Alert, 'close');
/**
* jQuery
*/
index_js.defineJQueryPlugin(Alert);
return Alert;
});
//# sourceMappingURL=alert.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"alert.js","sources":["../src/alert.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n"],"names":["NAME","DATA_KEY","EVENT_KEY","EVENT_CLOSE","EVENT_CLOSED","CLASS_NAME_FADE","CLASS_NAME_SHOW","Alert","BaseComponent","close","closeEvent","EventHandler","trigger","_element","defaultPrevented","classList","remove","isAnimated","contains","_queueCallback","_destroyElement","dispose","jQueryInterface","config","each","data","getOrCreateInstance","undefined","startsWith","TypeError","enableDismissTrigger","defineJQueryPlugin"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;;EAOA;EACA;EACA;;EAEA,MAAMA,IAAI,GAAG,OAAO,CAAA;EACpB,MAAMC,QAAQ,GAAG,UAAU,CAAA;EAC3B,MAAMC,SAAS,GAAI,CAAGD,CAAAA,EAAAA,QAAS,CAAC,CAAA,CAAA;EAEhC,MAAME,WAAW,GAAI,CAAOD,KAAAA,EAAAA,SAAU,CAAC,CAAA,CAAA;EACvC,MAAME,YAAY,GAAI,CAAQF,MAAAA,EAAAA,SAAU,CAAC,CAAA,CAAA;EACzC,MAAMG,eAAe,GAAG,MAAM,CAAA;EAC9B,MAAMC,eAAe,GAAG,MAAM,CAAA;;EAE9B;EACA;EACA;;EAEA,MAAMC,KAAK,SAASC,aAAa,CAAC;EAChC;IACA,WAAWR,IAAIA,GAAG;EAChB,IAAA,OAAOA,IAAI,CAAA;EACb,GAAA;;EAEA;EACAS,EAAAA,KAAKA,GAAG;MACN,MAAMC,UAAU,GAAGC,YAAY,CAACC,OAAO,CAAC,IAAI,CAACC,QAAQ,EAAEV,WAAW,CAAC,CAAA;MAEnE,IAAIO,UAAU,CAACI,gBAAgB,EAAE;EAC/B,MAAA,OAAA;EACF,KAAA;MAEA,IAAI,CAACD,QAAQ,CAACE,SAAS,CAACC,MAAM,CAACV,eAAe,CAAC,CAAA;MAE/C,MAAMW,UAAU,GAAG,IAAI,CAACJ,QAAQ,CAACE,SAAS,CAACG,QAAQ,CAACb,eAAe,CAAC,CAAA;EACpE,IAAA,IAAI,CAACc,cAAc,CAAC,MAAM,IAAI,CAACC,eAAe,EAAE,EAAE,IAAI,CAACP,QAAQ,EAAEI,UAAU,CAAC,CAAA;EAC9E,GAAA;;EAEA;EACAG,EAAAA,eAAeA,GAAG;EAChB,IAAA,IAAI,CAACP,QAAQ,CAACG,MAAM,EAAE,CAAA;MACtBL,YAAY,CAACC,OAAO,CAAC,IAAI,CAACC,QAAQ,EAAET,YAAY,CAAC,CAAA;MACjD,IAAI,CAACiB,OAAO,EAAE,CAAA;EAChB,GAAA;;EAEA;IACA,OAAOC,eAAeA,CAACC,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACC,IAAI,CAAC,YAAY;EAC3B,MAAA,MAAMC,IAAI,GAAGlB,KAAK,CAACmB,mBAAmB,CAAC,IAAI,CAAC,CAAA;EAE5C,MAAA,IAAI,OAAOH,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA,OAAA;EACF,OAAA;EAEA,MAAA,IAAIE,IAAI,CAACF,MAAM,CAAC,KAAKI,SAAS,IAAIJ,MAAM,CAACK,UAAU,CAAC,GAAG,CAAC,IAAIL,MAAM,KAAK,aAAa,EAAE;EACpF,QAAA,MAAM,IAAIM,SAAS,CAAE,CAAmBN,iBAAAA,EAAAA,MAAO,GAAE,CAAC,CAAA;EACpD,OAAA;EAEAE,MAAAA,IAAI,CAACF,MAAM,CAAC,CAAC,IAAI,CAAC,CAAA;EACpB,KAAC,CAAC,CAAA;EACJ,GAAA;EACF,CAAA;;EAEA;EACA;EACA;;AAEAO,4CAAoB,CAACvB,KAAK,EAAE,OAAO,CAAC,CAAA;;EAEpC;EACA;EACA;;AAEAwB,6BAAkB,CAACxB,KAAK,CAAC;;;;;;;;"}

View File

@@ -1,98 +0,0 @@
/*!
* Bootstrap base-component.js v5.3.2 (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory(
require('./dom/data.js'),
require('./dom/event-handler.js'),
require('./util/config.js'),
require('./util/index.js')
))
: typeof define === 'function' && define.amd
? define(['./dom/data', './dom/event-handler', './util/config', './util/index'], factory)
: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
(global.BaseComponent = factory(
global.Data,
global.EventHandler,
global.Config,
global.Index
)));
})(this, function (Data, EventHandler, Config, index_js) {
'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap base-component.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const VERSION = '5.3.2';
/**
* Class definition
*/
class BaseComponent extends Config {
constructor(element, config) {
super();
element = index_js.getElement(element);
if (!element) {
return;
}
this._element = element;
this._config = this._getConfig(config);
Data.set(this._element, this.constructor.DATA_KEY, this);
}
// Public
dispose() {
Data.remove(this._element, this.constructor.DATA_KEY);
EventHandler.off(this._element, this.constructor.EVENT_KEY);
for (const propertyName of Object.getOwnPropertyNames(this)) {
this[propertyName] = null;
}
}
_queueCallback(callback, element, isAnimated = true) {
index_js.executeAfterTransition(callback, element, isAnimated);
}
_getConfig(config) {
config = this._mergeConfigObj(config, this._element);
config = this._configAfterMerge(config);
this._typeCheckConfig(config);
return config;
}
// Static
static getInstance(element) {
return Data.get(index_js.getElement(element), this.DATA_KEY);
}
static getOrCreateInstance(element, config = {}) {
return (
this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)
);
}
static get VERSION() {
return VERSION;
}
static get DATA_KEY() {
return `bs.${this.NAME}`;
}
static get EVENT_KEY() {
return `.${this.DATA_KEY}`;
}
static eventName(name) {
return `${name}${this.EVENT_KEY}`;
}
}
return BaseComponent;
});
//# sourceMappingURL=base-component.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"base-component.js","sources":["../src/base-component.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data.js'\nimport EventHandler from './dom/event-handler.js'\nimport Config from './util/config.js'\nimport { executeAfterTransition, getElement } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.2'\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super()\n\n element = getElement(element)\n if (!element) {\n return\n }\n\n this._element = element\n this._config = this._getConfig(config)\n\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null\n }\n }\n\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`\n }\n}\n\nexport default BaseComponent\n"],"names":["VERSION","BaseComponent","Config","constructor","element","config","getElement","_element","_config","_getConfig","Data","set","DATA_KEY","dispose","remove","EventHandler","off","EVENT_KEY","propertyName","Object","getOwnPropertyNames","_queueCallback","callback","isAnimated","executeAfterTransition","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","getInstance","get","getOrCreateInstance","NAME","eventName","name"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;;EAOA;EACA;EACA;;EAEA,MAAMA,OAAO,GAAG,OAAO,CAAA;;EAEvB;EACA;EACA;;EAEA,MAAMC,aAAa,SAASC,MAAM,CAAC;EACjCC,EAAAA,WAAWA,CAACC,OAAO,EAAEC,MAAM,EAAE;EAC3B,IAAA,KAAK,EAAE,CAAA;EAEPD,IAAAA,OAAO,GAAGE,mBAAU,CAACF,OAAO,CAAC,CAAA;MAC7B,IAAI,CAACA,OAAO,EAAE;EACZ,MAAA,OAAA;EACF,KAAA;MAEA,IAAI,CAACG,QAAQ,GAAGH,OAAO,CAAA;MACvB,IAAI,CAACI,OAAO,GAAG,IAAI,CAACC,UAAU,CAACJ,MAAM,CAAC,CAAA;EAEtCK,IAAAA,IAAI,CAACC,GAAG,CAAC,IAAI,CAACJ,QAAQ,EAAE,IAAI,CAACJ,WAAW,CAACS,QAAQ,EAAE,IAAI,CAAC,CAAA;EAC1D,GAAA;;EAEA;EACAC,EAAAA,OAAOA,GAAG;EACRH,IAAAA,IAAI,CAACI,MAAM,CAAC,IAAI,CAACP,QAAQ,EAAE,IAAI,CAACJ,WAAW,CAACS,QAAQ,CAAC,CAAA;EACrDG,IAAAA,YAAY,CAACC,GAAG,CAAC,IAAI,CAACT,QAAQ,EAAE,IAAI,CAACJ,WAAW,CAACc,SAAS,CAAC,CAAA;MAE3D,KAAK,MAAMC,YAAY,IAAIC,MAAM,CAACC,mBAAmB,CAAC,IAAI,CAAC,EAAE;EAC3D,MAAA,IAAI,CAACF,YAAY,CAAC,GAAG,IAAI,CAAA;EAC3B,KAAA;EACF,GAAA;IAEAG,cAAcA,CAACC,QAAQ,EAAElB,OAAO,EAAEmB,UAAU,GAAG,IAAI,EAAE;EACnDC,IAAAA,+BAAsB,CAACF,QAAQ,EAAElB,OAAO,EAAEmB,UAAU,CAAC,CAAA;EACvD,GAAA;IAEAd,UAAUA,CAACJ,MAAM,EAAE;MACjBA,MAAM,GAAG,IAAI,CAACoB,eAAe,CAACpB,MAAM,EAAE,IAAI,CAACE,QAAQ,CAAC,CAAA;EACpDF,IAAAA,MAAM,GAAG,IAAI,CAACqB,iBAAiB,CAACrB,MAAM,CAAC,CAAA;EACvC,IAAA,IAAI,CAACsB,gBAAgB,CAACtB,MAAM,CAAC,CAAA;EAC7B,IAAA,OAAOA,MAAM,CAAA;EACf,GAAA;;EAEA;IACA,OAAOuB,WAAWA,CAACxB,OAAO,EAAE;EAC1B,IAAA,OAAOM,IAAI,CAACmB,GAAG,CAACvB,mBAAU,CAACF,OAAO,CAAC,EAAE,IAAI,CAACQ,QAAQ,CAAC,CAAA;EACrD,GAAA;IAEA,OAAOkB,mBAAmBA,CAAC1B,OAAO,EAAEC,MAAM,GAAG,EAAE,EAAE;MAC/C,OAAO,IAAI,CAACuB,WAAW,CAACxB,OAAO,CAAC,IAAI,IAAI,IAAI,CAACA,OAAO,EAAE,OAAOC,MAAM,KAAK,QAAQ,GAAGA,MAAM,GAAG,IAAI,CAAC,CAAA;EACnG,GAAA;IAEA,WAAWL,OAAOA,GAAG;EACnB,IAAA,OAAOA,OAAO,CAAA;EAChB,GAAA;IAEA,WAAWY,QAAQA,GAAG;EACpB,IAAA,OAAQ,CAAK,GAAA,EAAA,IAAI,CAACmB,IAAK,CAAC,CAAA,CAAA;EAC1B,GAAA;IAEA,WAAWd,SAASA,GAAG;EACrB,IAAA,OAAQ,CAAG,CAAA,EAAA,IAAI,CAACL,QAAS,CAAC,CAAA,CAAA;EAC5B,GAAA;IAEA,OAAOoB,SAASA,CAACC,IAAI,EAAE;EACrB,IAAA,OAAQ,GAAEA,IAAK,CAAA,EAAE,IAAI,CAAChB,SAAU,CAAC,CAAA,CAAA;EACnC,GAAA;EACF;;;;;;;;"}

View File

@@ -1,85 +0,0 @@
/*!
* Bootstrap button.js v5.3.2 (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory(
require('./base-component.js'),
require('./dom/event-handler.js'),
require('./util/index.js')
))
: typeof define === 'function' && define.amd
? define(['./base-component', './dom/event-handler', './util/index'], factory)
: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
(global.Button = factory(global.BaseComponent, global.EventHandler, global.Index)));
})(this, function (BaseComponent, EventHandler, index_js) {
'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap button.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const NAME = 'button';
const DATA_KEY = 'bs.button';
const EVENT_KEY = `.${DATA_KEY}`;
const DATA_API_KEY = '.data-api';
const CLASS_NAME_ACTIVE = 'active';
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="button"]';
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
/**
* Class definition
*/
class Button extends BaseComponent {
// Getters
static get NAME() {
return NAME;
}
// Public
toggle() {
// Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method
this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE));
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Button.getOrCreateInstance(this);
if (config === 'toggle') {
data[config]();
}
});
}
}
/**
* Data API implementation
*/
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, (event) => {
event.preventDefault();
const button = event.target.closest(SELECTOR_DATA_TOGGLE);
const data = Button.getOrCreateInstance(button);
data.toggle();
});
/**
* jQuery
*/
index_js.defineJQueryPlugin(Button);
return Button;
});
//# sourceMappingURL=button.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"button.js","sources":["../src/button.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n"],"names":["NAME","DATA_KEY","EVENT_KEY","DATA_API_KEY","CLASS_NAME_ACTIVE","SELECTOR_DATA_TOGGLE","EVENT_CLICK_DATA_API","Button","BaseComponent","toggle","_element","setAttribute","classList","jQueryInterface","config","each","data","getOrCreateInstance","EventHandler","on","document","event","preventDefault","button","target","closest","defineJQueryPlugin"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;;EAMA;EACA;EACA;;EAEA,MAAMA,IAAI,GAAG,QAAQ,CAAA;EACrB,MAAMC,QAAQ,GAAG,WAAW,CAAA;EAC5B,MAAMC,SAAS,GAAI,CAAGD,CAAAA,EAAAA,QAAS,CAAC,CAAA,CAAA;EAChC,MAAME,YAAY,GAAG,WAAW,CAAA;EAEhC,MAAMC,iBAAiB,GAAG,QAAQ,CAAA;EAClC,MAAMC,oBAAoB,GAAG,2BAA2B,CAAA;EACxD,MAAMC,oBAAoB,GAAI,CAAA,KAAA,EAAOJ,SAAU,CAAA,EAAEC,YAAa,CAAC,CAAA,CAAA;;EAE/D;EACA;EACA;;EAEA,MAAMI,MAAM,SAASC,aAAa,CAAC;EACjC;IACA,WAAWR,IAAIA,GAAG;EAChB,IAAA,OAAOA,IAAI,CAAA;EACb,GAAA;;EAEA;EACAS,EAAAA,MAAMA,GAAG;EACP;EACA,IAAA,IAAI,CAACC,QAAQ,CAACC,YAAY,CAAC,cAAc,EAAE,IAAI,CAACD,QAAQ,CAACE,SAAS,CAACH,MAAM,CAACL,iBAAiB,CAAC,CAAC,CAAA;EAC/F,GAAA;;EAEA;IACA,OAAOS,eAAeA,CAACC,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACC,IAAI,CAAC,YAAY;EAC3B,MAAA,MAAMC,IAAI,GAAGT,MAAM,CAACU,mBAAmB,CAAC,IAAI,CAAC,CAAA;QAE7C,IAAIH,MAAM,KAAK,QAAQ,EAAE;EACvBE,QAAAA,IAAI,CAACF,MAAM,CAAC,EAAE,CAAA;EAChB,OAAA;EACF,KAAC,CAAC,CAAA;EACJ,GAAA;EACF,CAAA;;EAEA;EACA;EACA;;EAEAI,YAAY,CAACC,EAAE,CAACC,QAAQ,EAAEd,oBAAoB,EAAED,oBAAoB,EAAEgB,KAAK,IAAI;IAC7EA,KAAK,CAACC,cAAc,EAAE,CAAA;IAEtB,MAAMC,MAAM,GAAGF,KAAK,CAACG,MAAM,CAACC,OAAO,CAACpB,oBAAoB,CAAC,CAAA;EACzD,EAAA,MAAMW,IAAI,GAAGT,MAAM,CAACU,mBAAmB,CAACM,MAAM,CAAC,CAAA;IAE/CP,IAAI,CAACP,MAAM,EAAE,CAAA;EACf,CAAC,CAAC,CAAA;;EAEF;EACA;EACA;;AAEAiB,6BAAkB,CAACnB,MAAM,CAAC;;;;;;;;"}

View File

@@ -1,422 +0,0 @@
/*!
* Bootstrap carousel.js v5.3.2 (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory(
require('./base-component.js'),
require('./dom/event-handler.js'),
require('./dom/manipulator.js'),
require('./dom/selector-engine.js'),
require('./util/index.js'),
require('./util/swipe.js')
))
: typeof define === 'function' && define.amd
? define(
[
'./base-component',
'./dom/event-handler',
'./dom/manipulator',
'./dom/selector-engine',
'./util/index',
'./util/swipe',
],
factory
)
: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
(global.Carousel = factory(
global.BaseComponent,
global.EventHandler,
global.Manipulator,
global.SelectorEngine,
global.Index,
global.Swipe
)));
})(this, function (BaseComponent, EventHandler, Manipulator, SelectorEngine, index_js, Swipe) {
'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap carousel.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const NAME = 'carousel';
const DATA_KEY = 'bs.carousel';
const EVENT_KEY = `.${DATA_KEY}`;
const DATA_API_KEY = '.data-api';
const ARROW_LEFT_KEY = 'ArrowLeft';
const ARROW_RIGHT_KEY = 'ArrowRight';
const TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch
const ORDER_NEXT = 'next';
const ORDER_PREV = 'prev';
const DIRECTION_LEFT = 'left';
const DIRECTION_RIGHT = 'right';
const EVENT_SLIDE = `slide${EVENT_KEY}`;
const EVENT_SLID = `slid${EVENT_KEY}`;
const EVENT_KEYDOWN = `keydown${EVENT_KEY}`;
const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`;
const EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`;
const EVENT_DRAG_START = `dragstart${EVENT_KEY}`;
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`;
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
const CLASS_NAME_CAROUSEL = 'carousel';
const CLASS_NAME_ACTIVE = 'active';
const CLASS_NAME_SLIDE = 'slide';
const CLASS_NAME_END = 'carousel-item-end';
const CLASS_NAME_START = 'carousel-item-start';
const CLASS_NAME_NEXT = 'carousel-item-next';
const CLASS_NAME_PREV = 'carousel-item-prev';
const SELECTOR_ACTIVE = '.active';
const SELECTOR_ITEM = '.carousel-item';
const SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM;
const SELECTOR_ITEM_IMG = '.carousel-item img';
const SELECTOR_INDICATORS = '.carousel-indicators';
const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]';
const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]';
const KEY_TO_DIRECTION = {
[ARROW_LEFT_KEY]: DIRECTION_RIGHT,
[ARROW_RIGHT_KEY]: DIRECTION_LEFT,
};
const Default = {
interval: 5000,
keyboard: true,
pause: 'hover',
ride: false,
touch: true,
wrap: true,
};
const DefaultType = {
interval: '(number|boolean)',
// TODO:v6 remove boolean support
keyboard: 'boolean',
pause: '(string|boolean)',
ride: '(boolean|string)',
touch: 'boolean',
wrap: 'boolean',
};
/**
* Class definition
*/
class Carousel extends BaseComponent {
constructor(element, config) {
super(element, config);
this._interval = null;
this._activeElement = null;
this._isSliding = false;
this.touchTimeout = null;
this._swipeHelper = null;
this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element);
this._addEventListeners();
if (this._config.ride === CLASS_NAME_CAROUSEL) {
this.cycle();
}
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
}
// Public
next() {
this._slide(ORDER_NEXT);
}
nextWhenVisible() {
// FIXME TODO use `document.visibilityState`
// Don't call next when the page isn't visible
// or the carousel or its parent isn't visible
if (!document.hidden && index_js.isVisible(this._element)) {
this.next();
}
}
prev() {
this._slide(ORDER_PREV);
}
pause() {
if (this._isSliding) {
index_js.triggerTransitionEnd(this._element);
}
this._clearInterval();
}
cycle() {
this._clearInterval();
this._updateInterval();
this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval);
}
_maybeEnableCycle() {
if (!this._config.ride) {
return;
}
if (this._isSliding) {
EventHandler.one(this._element, EVENT_SLID, () => this.cycle());
return;
}
this.cycle();
}
to(index) {
const items = this._getItems();
if (index > items.length - 1 || index < 0) {
return;
}
if (this._isSliding) {
EventHandler.one(this._element, EVENT_SLID, () => this.to(index));
return;
}
const activeIndex = this._getItemIndex(this._getActive());
if (activeIndex === index) {
return;
}
const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV;
this._slide(order, items[index]);
}
dispose() {
if (this._swipeHelper) {
this._swipeHelper.dispose();
}
super.dispose();
}
// Private
_configAfterMerge(config) {
config.defaultInterval = config.interval;
return config;
}
_addEventListeners() {
if (this._config.keyboard) {
EventHandler.on(this._element, EVENT_KEYDOWN, (event) => this._keydown(event));
}
if (this._config.pause === 'hover') {
EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause());
EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle());
}
if (this._config.touch && Swipe.isSupported()) {
this._addTouchEventListeners();
}
}
_addTouchEventListeners() {
for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {
EventHandler.on(img, EVENT_DRAG_START, (event) => event.preventDefault());
}
const endCallBack = () => {
if (this._config.pause !== 'hover') {
return;
}
// If it's a touch-enabled device, mouseenter/leave are fired as
// part of the mouse compatibility events on first tap - the carousel
// would stop cycling until user tapped out of it;
// here, we listen for touchend, explicitly pause the carousel
// (as if it's the second time we tap on it, mouseenter compat event
// is NOT fired) and after a timeout (to allow for mouse compatibility
// events to fire) we explicitly restart cycling
this.pause();
if (this.touchTimeout) {
clearTimeout(this.touchTimeout);
}
this.touchTimeout = setTimeout(
() => this._maybeEnableCycle(),
TOUCHEVENT_COMPAT_WAIT + this._config.interval
);
};
const swipeConfig = {
leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),
rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),
endCallback: endCallBack,
};
this._swipeHelper = new Swipe(this._element, swipeConfig);
}
_keydown(event) {
if (/input|textarea/i.test(event.target.tagName)) {
return;
}
const direction = KEY_TO_DIRECTION[event.key];
if (direction) {
event.preventDefault();
this._slide(this._directionToOrder(direction));
}
}
_getItemIndex(element) {
return this._getItems().indexOf(element);
}
_setActiveIndicatorElement(index) {
if (!this._indicatorsElement) {
return;
}
const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement);
activeIndicator.classList.remove(CLASS_NAME_ACTIVE);
activeIndicator.removeAttribute('aria-current');
const newActiveIndicator = SelectorEngine.findOne(
`[data-bs-slide-to="${index}"]`,
this._indicatorsElement
);
if (newActiveIndicator) {
newActiveIndicator.classList.add(CLASS_NAME_ACTIVE);
newActiveIndicator.setAttribute('aria-current', 'true');
}
}
_updateInterval() {
const element = this._activeElement || this._getActive();
if (!element) {
return;
}
const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10);
this._config.interval = elementInterval || this._config.defaultInterval;
}
_slide(order, element = null) {
if (this._isSliding) {
return;
}
const activeElement = this._getActive();
const isNext = order === ORDER_NEXT;
const nextElement =
element ||
index_js.getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap);
if (nextElement === activeElement) {
return;
}
const nextElementIndex = this._getItemIndex(nextElement);
const triggerEvent = (eventName) => {
return EventHandler.trigger(this._element, eventName, {
relatedTarget: nextElement,
direction: this._orderToDirection(order),
from: this._getItemIndex(activeElement),
to: nextElementIndex,
});
};
const slideEvent = triggerEvent(EVENT_SLIDE);
if (slideEvent.defaultPrevented) {
return;
}
if (!activeElement || !nextElement) {
// Some weirdness is happening, so we bail
// TODO: change tests that use empty divs to avoid this check
return;
}
const isCycling = Boolean(this._interval);
this.pause();
this._isSliding = true;
this._setActiveIndicatorElement(nextElementIndex);
this._activeElement = nextElement;
const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END;
const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV;
nextElement.classList.add(orderClassName);
index_js.reflow(nextElement);
activeElement.classList.add(directionalClassName);
nextElement.classList.add(directionalClassName);
const completeCallBack = () => {
nextElement.classList.remove(directionalClassName, orderClassName);
nextElement.classList.add(CLASS_NAME_ACTIVE);
activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName);
this._isSliding = false;
triggerEvent(EVENT_SLID);
};
this._queueCallback(completeCallBack, activeElement, this._isAnimated());
if (isCycling) {
this.cycle();
}
}
_isAnimated() {
return this._element.classList.contains(CLASS_NAME_SLIDE);
}
_getActive() {
return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element);
}
_getItems() {
return SelectorEngine.find(SELECTOR_ITEM, this._element);
}
_clearInterval() {
if (this._interval) {
clearInterval(this._interval);
this._interval = null;
}
}
_directionToOrder(direction) {
if (index_js.isRTL()) {
return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT;
}
return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV;
}
_orderToDirection(order) {
if (index_js.isRTL()) {
return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT;
}
return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Carousel.getOrCreateInstance(this, config);
if (typeof config === 'number') {
data.to(config);
return;
}
if (typeof config === 'string') {
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
}
});
}
}
/**
* Data API implementation
*/
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {
const target = SelectorEngine.getElementFromSelector(this);
if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {
return;
}
event.preventDefault();
const carousel = Carousel.getOrCreateInstance(target);
const slideIndex = this.getAttribute('data-bs-slide-to');
if (slideIndex) {
carousel.to(slideIndex);
carousel._maybeEnableCycle();
return;
}
if (Manipulator.getDataAttribute(this, 'slide') === 'next') {
carousel.next();
carousel._maybeEnableCycle();
return;
}
carousel.prev();
carousel._maybeEnableCycle();
});
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE);
for (const carousel of carousels) {
Carousel.getOrCreateInstance(carousel);
}
});
/**
* jQuery
*/
index_js.defineJQueryPlugin(Carousel);
return Carousel;
});
//# sourceMappingURL=carousel.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,275 +0,0 @@
/*!
* Bootstrap collapse.js v5.3.2 (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory(
require('./base-component.js'),
require('./dom/event-handler.js'),
require('./dom/selector-engine.js'),
require('./util/index.js')
))
: typeof define === 'function' && define.amd
? define(
['./base-component', './dom/event-handler', './dom/selector-engine', './util/index'],
factory
)
: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
(global.Collapse = factory(
global.BaseComponent,
global.EventHandler,
global.SelectorEngine,
global.Index
)));
})(this, function (BaseComponent, EventHandler, SelectorEngine, index_js) {
'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap collapse.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const NAME = 'collapse';
const DATA_KEY = 'bs.collapse';
const EVENT_KEY = `.${DATA_KEY}`;
const DATA_API_KEY = '.data-api';
const EVENT_SHOW = `show${EVENT_KEY}`;
const EVENT_SHOWN = `shown${EVENT_KEY}`;
const EVENT_HIDE = `hide${EVENT_KEY}`;
const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
const CLASS_NAME_SHOW = 'show';
const CLASS_NAME_COLLAPSE = 'collapse';
const CLASS_NAME_COLLAPSING = 'collapsing';
const CLASS_NAME_COLLAPSED = 'collapsed';
const CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`;
const CLASS_NAME_HORIZONTAL = 'collapse-horizontal';
const WIDTH = 'width';
const HEIGHT = 'height';
const SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing';
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="collapse"]';
const Default = {
parent: null,
toggle: true,
};
const DefaultType = {
parent: '(null|element)',
toggle: 'boolean',
};
/**
* Class definition
*/
class Collapse extends BaseComponent {
constructor(element, config) {
super(element, config);
this._isTransitioning = false;
this._triggerArray = [];
const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE);
for (const elem of toggleList) {
const selector = SelectorEngine.getSelectorFromElement(elem);
const filterElement = SelectorEngine.find(selector).filter(
(foundElement) => foundElement === this._element
);
if (selector !== null && filterElement.length) {
this._triggerArray.push(elem);
}
}
this._initializeChildren();
if (!this._config.parent) {
this._addAriaAndCollapsedClass(this._triggerArray, this._isShown());
}
if (this._config.toggle) {
this.toggle();
}
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
}
// Public
toggle() {
if (this._isShown()) {
this.hide();
} else {
this.show();
}
}
show() {
if (this._isTransitioning || this._isShown()) {
return;
}
let activeChildren = [];
// find active children
if (this._config.parent) {
activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)
.filter((element) => element !== this._element)
.map((element) =>
Collapse.getOrCreateInstance(element, {
toggle: false,
})
);
}
if (activeChildren.length && activeChildren[0]._isTransitioning) {
return;
}
const startEvent = EventHandler.trigger(this._element, EVENT_SHOW);
if (startEvent.defaultPrevented) {
return;
}
for (const activeInstance of activeChildren) {
activeInstance.hide();
}
const dimension = this._getDimension();
this._element.classList.remove(CLASS_NAME_COLLAPSE);
this._element.classList.add(CLASS_NAME_COLLAPSING);
this._element.style[dimension] = 0;
this._addAriaAndCollapsedClass(this._triggerArray, true);
this._isTransitioning = true;
const complete = () => {
this._isTransitioning = false;
this._element.classList.remove(CLASS_NAME_COLLAPSING);
this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW);
this._element.style[dimension] = '';
EventHandler.trigger(this._element, EVENT_SHOWN);
};
const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
const scrollSize = `scroll${capitalizedDimension}`;
this._queueCallback(complete, this._element, true);
this._element.style[dimension] = `${this._element[scrollSize]}px`;
}
hide() {
if (this._isTransitioning || !this._isShown()) {
return;
}
const startEvent = EventHandler.trigger(this._element, EVENT_HIDE);
if (startEvent.defaultPrevented) {
return;
}
const dimension = this._getDimension();
this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`;
index_js.reflow(this._element);
this._element.classList.add(CLASS_NAME_COLLAPSING);
this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW);
for (const trigger of this._triggerArray) {
const element = SelectorEngine.getElementFromSelector(trigger);
if (element && !this._isShown(element)) {
this._addAriaAndCollapsedClass([trigger], false);
}
}
this._isTransitioning = true;
const complete = () => {
this._isTransitioning = false;
this._element.classList.remove(CLASS_NAME_COLLAPSING);
this._element.classList.add(CLASS_NAME_COLLAPSE);
EventHandler.trigger(this._element, EVENT_HIDDEN);
};
this._element.style[dimension] = '';
this._queueCallback(complete, this._element, true);
}
_isShown(element = this._element) {
return element.classList.contains(CLASS_NAME_SHOW);
}
// Private
_configAfterMerge(config) {
config.toggle = Boolean(config.toggle); // Coerce string values
config.parent = index_js.getElement(config.parent);
return config;
}
_getDimension() {
return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT;
}
_initializeChildren() {
if (!this._config.parent) {
return;
}
const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE);
for (const element of children) {
const selected = SelectorEngine.getElementFromSelector(element);
if (selected) {
this._addAriaAndCollapsedClass([element], this._isShown(selected));
}
}
}
_getFirstLevelChildren(selector) {
const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent);
// remove children if greater depth
return SelectorEngine.find(selector, this._config.parent).filter(
(element) => !children.includes(element)
);
}
_addAriaAndCollapsedClass(triggerArray, isOpen) {
if (!triggerArray.length) {
return;
}
for (const element of triggerArray) {
element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen);
element.setAttribute('aria-expanded', isOpen);
}
}
// Static
static jQueryInterface(config) {
const _config = {};
if (typeof config === 'string' && /show|hide/.test(config)) {
_config.toggle = false;
}
return this.each(function () {
const data = Collapse.getOrCreateInstance(this, _config);
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
}
});
}
}
/**
* Data API implementation
*/
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
// preventDefault only for <a> elements (which change the URL) not inside the collapsible element
if (
event.target.tagName === 'A' ||
(event.delegateTarget && event.delegateTarget.tagName === 'A')
) {
event.preventDefault();
}
for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {
Collapse.getOrCreateInstance(element, {
toggle: false,
}).toggle();
}
});
/**
* jQuery
*/
index_js.defineJQueryPlugin(Collapse);
return Collapse;
});
//# sourceMappingURL=collapse.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,70 +0,0 @@
/*!
* Bootstrap data.js v5.3.2 (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory())
: typeof define === 'function' && define.amd
? define(factory)
: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
(global.Data = factory()));
})(this, function () {
'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap dom/data.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const elementMap = new Map();
const data = {
set(element, key, instance) {
if (!elementMap.has(element)) {
elementMap.set(element, new Map());
}
const instanceMap = elementMap.get(element);
// make it clear we only want one instance per element
// can be removed later when multiple key/instances are fine to be used
if (!instanceMap.has(key) && instanceMap.size !== 0) {
// eslint-disable-next-line no-console
console.error(
`Bootstrap doesn't allow more than one instance per element. Bound instance: ${
Array.from(instanceMap.keys())[0]
}.`
);
return;
}
instanceMap.set(key, instance);
},
get(element, key) {
if (elementMap.has(element)) {
return elementMap.get(element).get(key) || null;
}
return null;
},
remove(element, key) {
if (!elementMap.has(element)) {
return;
}
const instanceMap = elementMap.get(element);
instanceMap.delete(key);
// free up element references if there are no instances left for an element
if (instanceMap.size === 0) {
elementMap.delete(element);
}
},
};
return data;
});
//# sourceMappingURL=data.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"data.js","sources":["../../src/dom/data.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n"],"names":["elementMap","Map","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;EAEA;EACA;EACA;;EAEA,MAAMA,UAAU,GAAG,IAAIC,GAAG,EAAE,CAAA;AAE5B,eAAe;EACbC,EAAAA,GAAGA,CAACC,OAAO,EAAEC,GAAG,EAAEC,QAAQ,EAAE;EAC1B,IAAA,IAAI,CAACL,UAAU,CAACM,GAAG,CAACH,OAAO,CAAC,EAAE;QAC5BH,UAAU,CAACE,GAAG,CAACC,OAAO,EAAE,IAAIF,GAAG,EAAE,CAAC,CAAA;EACpC,KAAA;EAEA,IAAA,MAAMM,WAAW,GAAGP,UAAU,CAACQ,GAAG,CAACL,OAAO,CAAC,CAAA;;EAE3C;EACA;EACA,IAAA,IAAI,CAACI,WAAW,CAACD,GAAG,CAACF,GAAG,CAAC,IAAIG,WAAW,CAACE,IAAI,KAAK,CAAC,EAAE;EACnD;EACAC,MAAAA,OAAO,CAACC,KAAK,CAAE,+EAA8EC,KAAK,CAACC,IAAI,CAACN,WAAW,CAACO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,GAAE,CAAC,CAAA;EAClI,MAAA,OAAA;EACF,KAAA;EAEAP,IAAAA,WAAW,CAACL,GAAG,CAACE,GAAG,EAAEC,QAAQ,CAAC,CAAA;KAC/B;EAEDG,EAAAA,GAAGA,CAACL,OAAO,EAAEC,GAAG,EAAE;EAChB,IAAA,IAAIJ,UAAU,CAACM,GAAG,CAACH,OAAO,CAAC,EAAE;EAC3B,MAAA,OAAOH,UAAU,CAACQ,GAAG,CAACL,OAAO,CAAC,CAACK,GAAG,CAACJ,GAAG,CAAC,IAAI,IAAI,CAAA;EACjD,KAAA;EAEA,IAAA,OAAO,IAAI,CAAA;KACZ;EAEDW,EAAAA,MAAMA,CAACZ,OAAO,EAAEC,GAAG,EAAE;EACnB,IAAA,IAAI,CAACJ,UAAU,CAACM,GAAG,CAACH,OAAO,CAAC,EAAE;EAC5B,MAAA,OAAA;EACF,KAAA;EAEA,IAAA,MAAMI,WAAW,GAAGP,UAAU,CAACQ,GAAG,CAACL,OAAO,CAAC,CAAA;EAE3CI,IAAAA,WAAW,CAACS,MAAM,CAACZ,GAAG,CAAC,CAAA;;EAEvB;EACA,IAAA,IAAIG,WAAW,CAACE,IAAI,KAAK,CAAC,EAAE;EAC1BT,MAAAA,UAAU,CAACgB,MAAM,CAACb,OAAO,CAAC,CAAA;EAC5B,KAAA;EACF,GAAA;EACF,CAAC;;;;;;;;"}

View File

@@ -1,303 +0,0 @@
/*!
* Bootstrap event-handler.js v5.3.2 (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory(require('../util/index.js')))
: typeof define === 'function' && define.amd
? define(['../util/index'], factory)
: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
(global.EventHandler = factory(global.Index)));
})(this, function (index_js) {
'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap dom/event-handler.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const namespaceRegex = /[^.]*(?=\..*)\.|.*/;
const stripNameRegex = /\..*/;
const stripUidRegex = /::\d+$/;
const eventRegistry = {}; // Events storage
let uidEvent = 1;
const customEvents = {
mouseenter: 'mouseover',
mouseleave: 'mouseout',
};
const nativeEvents = new Set([
'click',
'dblclick',
'mouseup',
'mousedown',
'contextmenu',
'mousewheel',
'DOMMouseScroll',
'mouseover',
'mouseout',
'mousemove',
'selectstart',
'selectend',
'keydown',
'keypress',
'keyup',
'orientationchange',
'touchstart',
'touchmove',
'touchend',
'touchcancel',
'pointerdown',
'pointermove',
'pointerup',
'pointerleave',
'pointercancel',
'gesturestart',
'gesturechange',
'gestureend',
'focus',
'blur',
'change',
'reset',
'select',
'submit',
'focusin',
'focusout',
'load',
'unload',
'beforeunload',
'resize',
'move',
'DOMContentLoaded',
'readystatechange',
'error',
'abort',
'scroll',
]);
/**
* Private methods
*/
function makeEventUid(element, uid) {
return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++;
}
function getElementEvents(element) {
const uid = makeEventUid(element);
element.uidEvent = uid;
eventRegistry[uid] = eventRegistry[uid] || {};
return eventRegistry[uid];
}
function bootstrapHandler(element, fn) {
return function handler(event) {
hydrateObj(event, {
delegateTarget: element,
});
if (handler.oneOff) {
EventHandler.off(element, event.type, fn);
}
return fn.apply(element, [event]);
};
}
function bootstrapDelegationHandler(element, selector, fn) {
return function handler(event) {
const domElements = element.querySelectorAll(selector);
for (let { target } = event; target && target !== this; target = target.parentNode) {
for (const domElement of domElements) {
if (domElement !== target) {
continue;
}
hydrateObj(event, {
delegateTarget: target,
});
if (handler.oneOff) {
EventHandler.off(element, event.type, selector, fn);
}
return fn.apply(target, [event]);
}
}
};
}
function findHandler(events, callable, delegationSelector = null) {
return Object.values(events).find(
(event) => event.callable === callable && event.delegationSelector === delegationSelector
);
}
function normalizeParameters(originalTypeEvent, handler, delegationFunction) {
const isDelegated = typeof handler === 'string';
// TODO: tooltip passes `false` instead of selector, so we need to check
const callable = isDelegated ? delegationFunction : handler || delegationFunction;
let typeEvent = getTypeEvent(originalTypeEvent);
if (!nativeEvents.has(typeEvent)) {
typeEvent = originalTypeEvent;
}
return [isDelegated, callable, typeEvent];
}
function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {
if (typeof originalTypeEvent !== 'string' || !element) {
return;
}
let [isDelegated, callable, typeEvent] = normalizeParameters(
originalTypeEvent,
handler,
delegationFunction
);
// in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position
// this prevents the handler from being dispatched the same way as mouseover or mouseout does
if (originalTypeEvent in customEvents) {
const wrapFunction = (fn) => {
return function (event) {
if (
!event.relatedTarget ||
(event.relatedTarget !== event.delegateTarget &&
!event.delegateTarget.contains(event.relatedTarget))
) {
return fn.call(this, event);
}
};
};
callable = wrapFunction(callable);
}
const events = getElementEvents(element);
const handlers = events[typeEvent] || (events[typeEvent] = {});
const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null);
if (previousFunction) {
previousFunction.oneOff = previousFunction.oneOff && oneOff;
return;
}
const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''));
const fn = isDelegated
? bootstrapDelegationHandler(element, handler, callable)
: bootstrapHandler(element, callable);
fn.delegationSelector = isDelegated ? handler : null;
fn.callable = callable;
fn.oneOff = oneOff;
fn.uidEvent = uid;
handlers[uid] = fn;
element.addEventListener(typeEvent, fn, isDelegated);
}
function removeHandler(element, events, typeEvent, handler, delegationSelector) {
const fn = findHandler(events[typeEvent], handler, delegationSelector);
if (!fn) {
return;
}
element.removeEventListener(typeEvent, fn, Boolean(delegationSelector));
delete events[typeEvent][fn.uidEvent];
}
function removeNamespacedHandlers(element, events, typeEvent, namespace) {
const storeElementEvent = events[typeEvent] || {};
for (const [handlerKey, event] of Object.entries(storeElementEvent)) {
if (handlerKey.includes(namespace)) {
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);
}
}
}
function getTypeEvent(event) {
// allow to get the native events from namespaced events ('click.bs.button' --> 'click')
event = event.replace(stripNameRegex, '');
return customEvents[event] || event;
}
const EventHandler = {
on(element, event, handler, delegationFunction) {
addHandler(element, event, handler, delegationFunction, false);
},
one(element, event, handler, delegationFunction) {
addHandler(element, event, handler, delegationFunction, true);
},
off(element, originalTypeEvent, handler, delegationFunction) {
if (typeof originalTypeEvent !== 'string' || !element) {
return;
}
const [isDelegated, callable, typeEvent] = normalizeParameters(
originalTypeEvent,
handler,
delegationFunction
);
const inNamespace = typeEvent !== originalTypeEvent;
const events = getElementEvents(element);
const storeElementEvent = events[typeEvent] || {};
const isNamespace = originalTypeEvent.startsWith('.');
if (typeof callable !== 'undefined') {
// Simplest case: handler is passed, remove that listener ONLY.
if (!Object.keys(storeElementEvent).length) {
return;
}
removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null);
return;
}
if (isNamespace) {
for (const elementEvent of Object.keys(events)) {
removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1));
}
}
for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {
const handlerKey = keyHandlers.replace(stripUidRegex, '');
if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);
}
}
},
trigger(element, event, args) {
if (typeof event !== 'string' || !element) {
return null;
}
const $ = index_js.getjQuery();
const typeEvent = getTypeEvent(event);
const inNamespace = event !== typeEvent;
let jQueryEvent = null;
let bubbles = true;
let nativeDispatch = true;
let defaultPrevented = false;
if (inNamespace && $) {
jQueryEvent = $.Event(event, args);
$(element).trigger(jQueryEvent);
bubbles = !jQueryEvent.isPropagationStopped();
nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();
defaultPrevented = jQueryEvent.isDefaultPrevented();
}
const evt = hydrateObj(
new Event(event, {
bubbles,
cancelable: true,
}),
args
);
if (defaultPrevented) {
evt.preventDefault();
}
if (nativeDispatch) {
element.dispatchEvent(evt);
}
if (evt.defaultPrevented && jQueryEvent) {
jQueryEvent.preventDefault();
}
return evt;
},
};
function hydrateObj(obj, meta = {}) {
for (const [key, value] of Object.entries(meta)) {
try {
obj[key] = value;
} catch (_unused) {
Object.defineProperty(obj, key, {
configurable: true,
get() {
return value;
},
});
}
}
return obj;
}
return EventHandler;
});
//# sourceMappingURL=event-handler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,77 +0,0 @@
/*!
* Bootstrap manipulator.js v5.3.2 (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory())
: typeof define === 'function' && define.amd
? define(factory)
: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
(global.Manipulator = factory()));
})(this, function () {
'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap dom/manipulator.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
function normalizeData(value) {
if (value === 'true') {
return true;
}
if (value === 'false') {
return false;
}
if (value === Number(value).toString()) {
return Number(value);
}
if (value === '' || value === 'null') {
return null;
}
if (typeof value !== 'string') {
return value;
}
try {
return JSON.parse(decodeURIComponent(value));
} catch (_unused) {
return value;
}
}
function normalizeDataKey(key) {
return key.replace(/[A-Z]/g, (chr) => `-${chr.toLowerCase()}`);
}
const Manipulator = {
setDataAttribute(element, key, value) {
element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value);
},
removeDataAttribute(element, key) {
element.removeAttribute(`data-bs-${normalizeDataKey(key)}`);
},
getDataAttributes(element) {
if (!element) {
return {};
}
const attributes = {};
const bsKeys = Object.keys(element.dataset).filter(
(key) => key.startsWith('bs') && !key.startsWith('bsConfig')
);
for (const key of bsKeys) {
let pureKey = key.replace(/^bs/, '');
pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length);
attributes[pureKey] = normalizeData(element.dataset[key]);
}
return attributes;
},
getDataAttribute(element, key) {
return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`));
},
};
return Manipulator;
});
//# sourceMappingURL=manipulator.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"manipulator.js","sources":["../../src/dom/manipulator.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n if (value === Number(value).toString()) {\n return Number(value)\n }\n\n if (value === '' || value === 'null') {\n return null\n }\n\n if (typeof value !== 'string') {\n return value\n }\n\n try {\n return JSON.parse(decodeURIComponent(value))\n } catch {\n return value\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)\n attributes[pureKey] = normalizeData(element.dataset[key])\n }\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n }\n}\n\nexport default Manipulator\n"],"names":["normalizeData","value","Number","toString","JSON","parse","decodeURIComponent","_unused","normalizeDataKey","key","replace","chr","toLowerCase","Manipulator","setDataAttribute","element","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","Object","keys","dataset","filter","startsWith","pureKey","charAt","slice","length","getDataAttribute","getAttribute"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;EAEA,SAASA,aAAaA,CAACC,KAAK,EAAE;IAC5B,IAAIA,KAAK,KAAK,MAAM,EAAE;EACpB,IAAA,OAAO,IAAI,CAAA;EACb,GAAA;IAEA,IAAIA,KAAK,KAAK,OAAO,EAAE;EACrB,IAAA,OAAO,KAAK,CAAA;EACd,GAAA;IAEA,IAAIA,KAAK,KAAKC,MAAM,CAACD,KAAK,CAAC,CAACE,QAAQ,EAAE,EAAE;MACtC,OAAOD,MAAM,CAACD,KAAK,CAAC,CAAA;EACtB,GAAA;EAEA,EAAA,IAAIA,KAAK,KAAK,EAAE,IAAIA,KAAK,KAAK,MAAM,EAAE;EACpC,IAAA,OAAO,IAAI,CAAA;EACb,GAAA;EAEA,EAAA,IAAI,OAAOA,KAAK,KAAK,QAAQ,EAAE;EAC7B,IAAA,OAAOA,KAAK,CAAA;EACd,GAAA;IAEA,IAAI;MACF,OAAOG,IAAI,CAACC,KAAK,CAACC,kBAAkB,CAACL,KAAK,CAAC,CAAC,CAAA;KAC7C,CAAC,OAAAM,OAAA,EAAM;EACN,IAAA,OAAON,KAAK,CAAA;EACd,GAAA;EACF,CAAA;EAEA,SAASO,gBAAgBA,CAACC,GAAG,EAAE;EAC7B,EAAA,OAAOA,GAAG,CAACC,OAAO,CAAC,QAAQ,EAAEC,GAAG,IAAK,CAAA,CAAA,EAAGA,GAAG,CAACC,WAAW,EAAG,EAAC,CAAC,CAAA;EAC9D,CAAA;AAEA,QAAMC,WAAW,GAAG;EAClBC,EAAAA,gBAAgBA,CAACC,OAAO,EAAEN,GAAG,EAAER,KAAK,EAAE;MACpCc,OAAO,CAACC,YAAY,CAAE,CAAUR,QAAAA,EAAAA,gBAAgB,CAACC,GAAG,CAAE,CAAA,CAAC,EAAER,KAAK,CAAC,CAAA;KAChE;EAEDgB,EAAAA,mBAAmBA,CAACF,OAAO,EAAEN,GAAG,EAAE;MAChCM,OAAO,CAACG,eAAe,CAAE,CAAA,QAAA,EAAUV,gBAAgB,CAACC,GAAG,CAAE,CAAA,CAAC,CAAC,CAAA;KAC5D;IAEDU,iBAAiBA,CAACJ,OAAO,EAAE;MACzB,IAAI,CAACA,OAAO,EAAE;EACZ,MAAA,OAAO,EAAE,CAAA;EACX,KAAA;MAEA,MAAMK,UAAU,GAAG,EAAE,CAAA;EACrB,IAAA,MAAMC,MAAM,GAAGC,MAAM,CAACC,IAAI,CAACR,OAAO,CAACS,OAAO,CAAC,CAACC,MAAM,CAAChB,GAAG,IAAIA,GAAG,CAACiB,UAAU,CAAC,IAAI,CAAC,IAAI,CAACjB,GAAG,CAACiB,UAAU,CAAC,UAAU,CAAC,CAAC,CAAA;EAE9G,IAAA,KAAK,MAAMjB,GAAG,IAAIY,MAAM,EAAE;QACxB,IAAIM,OAAO,GAAGlB,GAAG,CAACC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;QACpCiB,OAAO,GAAGA,OAAO,CAACC,MAAM,CAAC,CAAC,CAAC,CAAChB,WAAW,EAAE,GAAGe,OAAO,CAACE,KAAK,CAAC,CAAC,EAAEF,OAAO,CAACG,MAAM,CAAC,CAAA;EAC5EV,MAAAA,UAAU,CAACO,OAAO,CAAC,GAAG3B,aAAa,CAACe,OAAO,CAACS,OAAO,CAACf,GAAG,CAAC,CAAC,CAAA;EAC3D,KAAA;EAEA,IAAA,OAAOW,UAAU,CAAA;KAClB;EAEDW,EAAAA,gBAAgBA,CAAChB,OAAO,EAAEN,GAAG,EAAE;EAC7B,IAAA,OAAOT,aAAa,CAACe,OAAO,CAACiB,YAAY,CAAE,CAAUxB,QAAAA,EAAAA,gBAAgB,CAACC,GAAG,CAAE,CAAA,CAAC,CAAC,CAAC,CAAA;EAChF,GAAA;EACF;;;;;;;;"}

View File

@@ -1,123 +0,0 @@
/*!
* Bootstrap selector-engine.js v5.3.2 (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory(require('../util/index.js')))
: typeof define === 'function' && define.amd
? define(['../util/index'], factory)
: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
(global.SelectorEngine = factory(global.Index)));
})(this, function (index_js) {
'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap dom/selector-engine.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const getSelector = (element) => {
let selector = element.getAttribute('data-bs-target');
if (!selector || selector === '#') {
let hrefAttribute = element.getAttribute('href');
// The only valid content that could double as a selector are IDs or classes,
// so everything starting with `#` or `.`. If a "real" URL is used as the selector,
// `document.querySelector` will rightfully complain it is invalid.
// See https://github.com/twbs/bootstrap/issues/32273
if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {
return null;
}
// Just in case some CMS puts out a full URL with the anchor appended
if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {
hrefAttribute = `#${hrefAttribute.split('#')[1]}`;
}
selector =
hrefAttribute && hrefAttribute !== '#'
? index_js.parseSelector(hrefAttribute.trim())
: null;
}
return selector;
};
const SelectorEngine = {
find(selector, element = document.documentElement) {
return [].concat(...Element.prototype.querySelectorAll.call(element, selector));
},
findOne(selector, element = document.documentElement) {
return Element.prototype.querySelector.call(element, selector);
},
children(element, selector) {
return [].concat(...element.children).filter((child) => child.matches(selector));
},
parents(element, selector) {
const parents = [];
let ancestor = element.parentNode.closest(selector);
while (ancestor) {
parents.push(ancestor);
ancestor = ancestor.parentNode.closest(selector);
}
return parents;
},
prev(element, selector) {
let previous = element.previousElementSibling;
while (previous) {
if (previous.matches(selector)) {
return [previous];
}
previous = previous.previousElementSibling;
}
return [];
},
// TODO: this is now unused; remove later along with prev()
next(element, selector) {
let next = element.nextElementSibling;
while (next) {
if (next.matches(selector)) {
return [next];
}
next = next.nextElementSibling;
}
return [];
},
focusableChildren(element) {
const focusables = [
'a',
'button',
'input',
'textarea',
'select',
'details',
'[tabindex]',
'[contenteditable="true"]',
]
.map((selector) => `${selector}:not([tabindex^="-"])`)
.join(',');
return this.find(focusables, element).filter(
(el) => !index_js.isDisabled(el) && index_js.isVisible(el)
);
},
getSelectorFromElement(element) {
const selector = getSelector(element);
if (selector) {
return SelectorEngine.findOne(selector) ? selector : null;
}
return null;
},
getElementFromSelector(element) {
const selector = getSelector(element);
return selector ? SelectorEngine.findOne(selector) : null;
},
getMultipleElementsFromSelector(element) {
const selector = getSelector(element);
return selector ? SelectorEngine.find(selector) : [];
},
};
return SelectorEngine;
});
//# sourceMappingURL=selector-engine.js.map

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More