Compare commits

32 Commits

Author SHA1 Message Date
Developer 02
46f1633f79 feat(geoloc): Anfangsort hinzugefügt 2024-10-22 23:26:07 +02:00
Developer 02
1af07f0df8 feat: location-picker.css initialisiert.
- Minified CSS hinzugefügt
2024-10-22 21:40:38 +02:00
Developer 02
55c9dfb9c2 refactor(ShowEnvelope.cshtml): Interne Skripte, die sich auf die Ereignisse von readonly-send und geoloc Elementen beziehen, wurden in event-binder.js verschoben. 2024-10-22 20:38:44 +02:00
Developer 02
1a230306a3 refactor(ShowEnvelope.cshtml): collapseNav-Skript entfernt, das nach der Aktualisierung der Navigationsleiste nicht mehr benötigt wird 2024-10-22 20:32:14 +02:00
Developer 02
28022bc669 feat(_Layout.cshtml): LeafletLocationPicker in Pop-up hinzugefügt. 2024-10-22 20:28:54 +02:00
Developer 02
ad5843b7c9 feat(_Layout): leaflet-locationpicker-Abhängigkeiten hinzugefügt. 2024-10-22 16:52:46 +02:00
Developer 02
173b691e56 feat: leaflet und leaflet-locationpicker hinzufügen 2024-10-21 18:10:45 +02:00
Developer 02
8a0fe70a88 feat: Popup-Fenster für den Speicherort initialisiert.
- Schaltfläche im pspdf-kit-Symbolleistenmenü hinzugefügt.
2024-10-21 14:47:58 +02:00
Developer 02
c4114a3800 feat(HomeController): UserCulture zu EnvelopeSigned hinzugefügt 2024-10-18 13:27:42 +02:00
Developer 02
977486bb7d chore: Aktualisiert auf Version 2.4.0.0. 2024-10-18 10:40:24 +02:00
Developer 02
6ccc0d2e0a refactor(HomeController): Aktualisiert, um ein Dokument aus der Datenbank über EnvelopeDocumentDto zu lesen, anstatt das Dokument aus dem Dateipfad mit envelopeOldService zu lesen 2024-10-18 10:34:51 +02:00
Developer 02
084a9b7db4 refactor(EnvelopeDocumentDto): ByteDta-Eigenschaft hinzugefügt 2024-10-18 10:21:01 +02:00
Developer 02
826844cf46 refactor(EnvelopeDocument): ByteDta-Eigenschaft hinzugefügt 2024-10-18 10:17:28 +02:00
Developer 02
39cff26f2d feat(site.css): Die Schriftgröße der Fußzeile und die Anordnung der Elemente wurden angepasst, um eine bessere Reaktionsfähigkeit zu gewährleisten. 2024-10-18 10:05:03 +02:00
Developer 02
1619801526 refactor(appsettings) verschiebt DispatcherConfig in die Nähe von Mail config 2024-10-18 09:55:24 +02:00
Developer 02
5a1263ee3a refactor(CookieConsentSettings ): Entfernen Sie es und es ist DI Injection 2024-10-18 09:50:53 +02:00
Developer 02
bc91baa4fa refactor(appsettings): verschiebe appsettings about developmentement nach appsettings.Dev 2024-10-18 09:46:34 +02:00
Developer 02
a4882a7bfa refactor(appsettings): Der Pfad zu den Protokolldateien wurde auf einen zentralen Speicherort aktualisiert. 2024-10-18 09:43:39 +02:00
Developer 02
c254b5b8df refactor(Envelope): Entfernte DmzMoved-Eigenschaft 2024-10-18 09:32:49 +02:00
Developer 02
66718a3fd8 chore: das Projekt auf 2.3 aktualisiert 2024-10-16 15:06:01 +02:00
Developer 02
99fc2aecd9 refactor(app.js) : Entfernen von /ReadOnly beim Kopieren der Url 2024-10-16 14:56:54 +02:00
Developer 02
a41d03aed5 feat(HomeController): zentralisierte Standard-Kultur-Cookie-Zuweisung. 2024-10-16 14:42:58 +02:00
Developer 02
6d14b79c43 refactor(flag-dropdown): in die footer verschoben 2024-10-16 13:48:06 +02:00
Developer 02
faeac8f290 refactor(EnvelopeRejected): Unnötige _CookieConsentPartial entfernen 2024-10-16 11:58:23 +02:00
Developer 02
d172faacf3 refactor(ShowEnvelope): Unnötige _CookieConsentPartial entfernen 2024-10-16 11:56:54 +02:00
Developer 02
35d6beb3cb feat(ShowEnvelope): Wenn ReadOnly, machen Sie die Kopfzeile ViewDoc anstelle von SignDoc.
- ViewDoc-Schlüssel zu resx in beiden Sprachen hinzugefügt
2024-10-16 11:55:48 +02:00
Developer 02
7ff787ec28 refactor(_layout): City-Regex-Prüfung ignorieren, wenn IS_MOBILE_DEVICE
- IS_MOBILE_DEVICE als globalen konstanten Wert hinzugefügt
 - DEVICE_TYPE geändert in DEVICE_SCREEN_TYPE
 - IS_DESKTOP zu IS_DESKTOP_SIZE geändert
2024-10-16 11:32:25 +02:00
Developer 02
f6fc850a20 fix: Pull-Konflikte in Constant.vb gelöst. 2024-10-16 10:00:20 +02:00
Developer 02
04b8d0ef5d fix: Pull-Konflikte in Constant.vb gelöst. 2024-10-16 09:43:41 +02:00
Developer01
683ff03a0f Merge branch 'master' of http://git.dd:3000/AppStd/EnvelopeGenerator 2024-10-13 17:38:48 +02:00
Developer01
c9ba7eeaf9 MS 2024-10-13 17:38:31 +02:00
Developer01
6e7670f667 Service GDPicture 2024-09-24 17:48:29 +02:00
68 changed files with 11519 additions and 247 deletions

View File

@@ -7,6 +7,7 @@ namespace EnvelopeGenerator.Application.DTOs
int Id,
int EnvelopeId,
DateTime AddedWhen,
IEnumerable<DocumentReceiverElementDto>? Elements
byte[]? ByteData = null,
IEnumerable<DocumentReceiverElementDto>? Elements = null
) : IUnique<int>;
}

View File

@@ -213,6 +213,9 @@
<data name="UnexpectedError" xml:space="preserve">
<value>Ein unerwarteter Fehler ist aufgetreten.</value>
</data>
<data name="ViewDoc" xml:space="preserve">
<value>Dokument ansehen</value>
</data>
<data name="WelcomeToTheESignPortal" xml:space="preserve">
<value>Herzlich willkommen im eSign-Portal</value>
</data>

View File

@@ -213,6 +213,9 @@
<data name="UnexpectedError" xml:space="preserve">
<value>An unexpected error has occurred.</value>
</data>
<data name="ViewDoc" xml:space="preserve">
<value>View document</value>
</data>
<data name="WelcomeToTheESignPortal" xml:space="preserve">
<value>Welcome to the eSign portal</value>
</data>

View File

@@ -18,6 +18,7 @@
AccessCodeIncorrect = 2003
DocumentOpened = 2004
DocumentSigned = 2005
DocumentForwarded = 4001
SignatureConfirmed = 2006
DocumentRejected = 2007
EnvelopeShared = 2008
@@ -104,6 +105,8 @@
EnvelopeReceiver
EnvelopeReceiverReadOnly
Undefined
DocumentForwarded
DocumentShared
End Enum
#End Region
@@ -119,4 +122,4 @@
Public Const RED_300 = "#fecaca"
Public Const ORANGE_300 = "#fed7aa"
#End Region
End Class
End Class

View File

@@ -1,5 +1,5 @@
Public Class DbConfig
Public Property ExternalProgramName As String = "Sign Flow"
Public Property ExternalProgramName As String = "signFLOW"
Public Property DocumentPathOrigin As String = ""
Public Property DocumentPath As String = ""
Public Property ExportPath As String = ""

View File

@@ -138,6 +138,9 @@
<data name="Document Could Not Be Saved" xml:space="preserve">
<value>Document could not be saved!</value>
</data>
<data name="Document forwarded" xml:space="preserve">
<value>Document forwarded to receiver: {0}</value>
</data>
<data name="Edit Envelope" xml:space="preserve">
<value>Edit Envelope</value>
</data>

View File

@@ -138,6 +138,9 @@
<data name="Document Could Not Be Saved" xml:space="preserve">
<value>Dokument konnte nicht gespeichert werden!</value>
</data>
<data name="Document forwarded" xml:space="preserve">
<value>Umschlag an Empfänger {0} weitergeleitet.</value>
</data>
<data name="Edit Envelope" xml:space="preserve">
<value>Bearbeite Umschlag</value>
</data>

View File

@@ -127,6 +127,15 @@ Namespace My.Resources
End Get
End Property
'''<summary>
''' Sucht eine lokalisierte Zeichenfolge, die Umschlag an Empfänger {0} weitergeleitet. ähnelt.
'''</summary>
Public Shared ReadOnly Property Document_forwarded() As String
Get
Return ResourceManager.GetString("Document forwarded", resourceCulture)
End Get
End Property
'''<summary>
''' Sucht eine lokalisierte Zeichenfolge, die Bearbeite Umschlag ähnelt.
'''</summary>

View File

@@ -84,10 +84,6 @@ namespace EnvelopeGenerator.Domain.Entities
[Column("EXPIRES_WARNING_WHEN_DAYS")]
public int? ExpiresWarningWhenDays { get; set; }
[Required]
[Column("DMZ_MOVED")]
public bool DmzMoved { get; set; }
/// <summary>
/// The sender of envelope
/// </summary>

View File

@@ -31,6 +31,9 @@ namespace EnvelopeGenerator.Domain.Entities
[Column("FILENAME_ORIGINAL", TypeName = "nvarchar(256)")]
public required string FilenameOriginal { get; set; }
[Column("BYTE_DATA", TypeName = "varbinary(max)")]
public byte[]? ByteData { get; init; }
public IEnumerable<DocumentReceiverElement>? Elements { get; set; }
}
}

View File

@@ -158,6 +158,7 @@ Public Class EnvelopeEditorController
Dim oTempFilePath = Path.Combine(oTempFiles.TempPath, Guid.NewGuid().ToString + oFileInfo.Extension)
Await Helpers.CopyFileAsync(oFileInfo.FullName, oTempFilePath)
'File.Copy(oFileInfo.FullName, oTempFilePath, True)
Dim oFileInfoTemp = New FileInfo(oTempFilePath)
@@ -175,6 +176,7 @@ Public Class EnvelopeEditorController
Catch ex As Exception
Logger.Error(ex)
Logger.Warn($"error in CreateDocument: {ex.Message}")
Return Nothing
End Try
End Function
@@ -288,7 +290,9 @@ Public Class EnvelopeEditorController
#End Region
Private Function GetEnvelopePath(pEnvelope As Envelope) As String
Try
Dim oEnvelopePath As String = Path.Combine(State.DbConfig.DocumentPath, pEnvelope.Uuid)
Dim oTempFiles As New TempFiles(State.LogConfig)
Dim oTempFolderPath = oTempFiles.TempPath
Dim oEnvelopePath As String = Path.Combine(oTempFolderPath, pEnvelope.Uuid)
If Not Directory.Exists(oEnvelopePath) Then
Directory.CreateDirectory(oEnvelopePath)

View File

@@ -71,8 +71,9 @@
<Reference Include="DevExpress.XtraNavBar.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.XtraPrinting.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
<Reference Include="DevExpress.XtraTreeList.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
<Reference Include="DigitalData.Controls.DocumentViewer">
<HintPath>..\..\DDMonorepo\Controls.DocumentViewer\bin\Debug\DigitalData.Controls.DocumentViewer.dll</HintPath>
<Reference Include="DigitalData.Controls.DocumentViewer, Version=1.9.4.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\2_DLL Projekte\DDMonorepo\Controls.DocumentViewer\bin\Debug\DigitalData.Controls.DocumentViewer.dll</HintPath>
</Reference>
<Reference Include="DigitalData.GUIs.Common">
<HintPath>..\..\DDMonorepo\GUIs.Common\bin\Debug\DigitalData.GUIs.Common.dll</HintPath>
@@ -99,8 +100,8 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\EnvelopeGenerator.Common\bin\Debug\EnvelopeGenerator.Common.dll</HintPath>
</Reference>
<Reference Include="GdPicture.NET.14, Version=14.2.89.0, Culture=neutral, PublicKeyToken=f52a2e60ad468dbb, processorArchitecture=MSIL">
<HintPath>..\packages\GdPicture.14.2.89\lib\net462\GdPicture.NET.14.dll</HintPath>
<Reference Include="GdPicture.NET.14, Version=14.2.90.0, Culture=neutral, PublicKeyToken=f52a2e60ad468dbb, processorArchitecture=MSIL">
<HintPath>..\packages\GdPicture.14.2.90\lib\net462\GdPicture.NET.14.dll</HintPath>
</Reference>
<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>
@@ -271,12 +272,12 @@
</ProjectReference>
</ItemGroup>
<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')" />
<Import Project="..\packages\GdPicture.runtimes.windows.14.2.90\build\net462\GdPicture.runtimes.windows.targets" Condition="Exists('..\packages\GdPicture.runtimes.windows.14.2.90\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'))" />
<Error Condition="!Exists('..\packages\GdPicture.runtimes.windows.14.2.90\build\net462\GdPicture.runtimes.windows.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\GdPicture.runtimes.windows.14.2.90\build\net462\GdPicture.runtimes.windows.targets'))" />
</Target>
<!-- 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.

View File

@@ -72,7 +72,7 @@
<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" />
<bindingRedirect oldVersion="0.0.0.0-14.2.90.0" newVersion="14.2.90.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>

View File

@@ -878,7 +878,7 @@
<value>0</value>
</data>
<metadata name="FrmEditorBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 54</value>
<value>792, 17</value>
</metadata>
<metadata name="EnvelopeDocumentBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>557, 17</value>

View File

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

View File

@@ -60,7 +60,7 @@ builder.Services.AddDirectorySearchService();
builder.Services.AddCookieBasedLocalizer() ;
// Envelope generator serives
builder.Services.AddEnvelopeGenerator();
builder.Services.AddEnvelopeGenerator(config);
var app = builder.Build();

View File

@@ -14,6 +14,8 @@
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -66,9 +68,8 @@
<Reference Include="DigitalData.Modules.Messaging">
<HintPath>..\..\2_DLL Projekte\DDModules\Messaging\bin\Debug\DigitalData.Modules.Messaging.dll</HintPath>
</Reference>
<Reference Include="GdPicture.NET.14, Version=14.1.0.152, Culture=neutral, PublicKeyToken=f52a2e60ad468dbb, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>D:\ProgramFiles\GdPicture.NET 14\Redist\GdPicture.NET (.NET Framework 4.5)\GdPicture.NET.14.dll</HintPath>
<Reference Include="GdPicture.NET.14, Version=14.2.89.0, Culture=neutral, PublicKeyToken=f52a2e60ad468dbb, processorArchitecture=MSIL">
<HintPath>..\packages\GdPicture.14.2.89\lib\net462\GdPicture.NET.14.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
@@ -177,4 +178,11 @@
</ProjectReference>
</ItemGroup>
<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>

View File

@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
' übernehmen, indem Sie "*" eingeben:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.7.0.0")>
<Assembly: AssemblyFileVersion("1.7.0.0")>
<Assembly: AssemblyVersion("1.7.1.0")>
<Assembly: AssemblyFileVersion("1.7.1.0")>

View File

@@ -26,47 +26,52 @@ Public Class Scheduler
End Sub
Public Async Function Start(pInterval As Integer) As Task
Logger.Debug("Starting Scheduler..")
Try
Logger.Debug("Starting Scheduler..")
Dim oProperties As New NameValueCollection()
Dim oProperties As New NameValueCollection()
Scheduler = Await SchedulerBuilder.Create(oProperties).
UseDefaultThreadPool(Sub(x) x.MaxConcurrency = 5).
BuildScheduler()
Scheduler = Await SchedulerBuilder.Create(oProperties).
UseDefaultThreadPool(Sub(x) x.MaxConcurrency = 5).
BuildScheduler()
Dim oJobKey = New JobKey(JobName)
Dim oJobData = New JobDataMap() From {
{Common.Constants.GDPICTURE, LicenseKey},
{Common.Constants.LOGCONFIG, LogConfig},
{Common.Constants.DATABASE, ConnectionString},
{Common.Constants.IGNORED_LABELS, _ignoredLabels}
}
Dim oJobKey = New JobKey(JobName)
Dim oJobData = New JobDataMap() From {
{Common.Constants.GDPICTURE, LicenseKey},
{Common.Constants.LOGCONFIG, LogConfig},
{Common.Constants.DATABASE, ConnectionString},
{Common.Constants.IGNORED_LABELS, _ignoredLabels}
}
Logger.Debug("Initialized Job [{0}]", JobName)
Logger.Debug("Initialized Job [{0}]", JobName)
Dim oJob As IJobDetail = JobBuilder.Create(Of FinalizeDocumentJob).
UsingJobData(oJobData).
WithIdentity(oJobKey).
Build()
Dim oJob As IJobDetail = JobBuilder.Create(Of FinalizeDocumentJob).
UsingJobData(oJobData).
WithIdentity(oJobKey).
Build()
Dim oTrigger As ITrigger = TriggerBuilder.Create().
ForJob(oJobKey).
WithIdentity($"{JobName}-trigger").
WithSimpleSchedule(Sub(s) s.
RepeatForever().
WithIntervalInMinutes(pInterval)).
StartNow().
Build()
Dim oTrigger As ITrigger = TriggerBuilder.Create().
ForJob(oJobKey).
WithIdentity($"{JobName}-trigger").
WithSimpleSchedule(Sub(s) s.
RepeatForever().
WithIntervalInMinutes(pInterval)).
StartNow().
Build()
Logger.Debug("Initialized Trigger")
Logger.Debug("Initialized Trigger")
Await Scheduler.ScheduleJob(oJob, oTrigger)
Await Scheduler.ScheduleJob(oJob, oTrigger)
Logger.Debug("Job scheduled.")
Logger.Debug("Job scheduled.")
Await Scheduler.Start()
Await Scheduler.Start()
Logger.Info("Scheduler started!")
Catch ex As Exception
Logger.Error(ex)
End Try
Logger.Info("Scheduler started!")
End Function
Public Async Function [Stop]() As Task

View File

@@ -37,13 +37,14 @@ Public Class Service
TempFiles.Create()
' === Initialize Databases ===
Logger.Info("Inititalize Databases")
Logger.Info("Inititalize Database ...")
If Config.ConnectionString = String.Empty Then
Throw New ApplicationException("Connection String is empty!")
End If
Database = New MSSQLServer(LogConfig, Config.ConnectionString)
Logger.Debug("Database initialized")
If Database.DBInitialized = False Then
Throw New ApplicationException("Database connection could not be established!")

View File

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

View File

@@ -17,6 +17,7 @@ using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using static EnvelopeGenerator.Common.Constants;
using Ganss.Xss;
using Newtonsoft.Json;
using EnvelopeGenerator.Application.DTOs;
namespace EnvelopeGenerator.Web.Controllers
{
@@ -48,10 +49,20 @@ namespace EnvelopeGenerator.Web.Controllers
}
[HttpGet("EnvelopeKey/{envelopeReceiverId}")]
public async Task<IActionResult> MainAsync([FromRoute] string envelopeReceiverId)
public async Task<IActionResult> MainAsync([FromRoute] string envelopeReceiverId, [FromQuery] string? culture = null)
{
try
{
//TODO: add a middelware or use an asp.net functionality insead of this code-smell
culture = culture is not null ? _sanitizer.Sanitize(culture) : null;
envelopeReceiverId = _sanitizer.Sanitize(envelopeReceiverId);
if (UserLanguage is null && culture is null)
{
UserLanguage = _cultures.Default.Language;
return Redirect($"{Request.Headers["Referer"]}?culture={_cultures.Default.Language}");
}
envelopeReceiverId = _sanitizer.Sanitize(envelopeReceiverId);
if (!envelopeReceiverId.TryDecode(out var decoded))
@@ -99,22 +110,11 @@ namespace EnvelopeGenerator.Web.Controllers
}
[HttpGet("EnvelopeKey/{envelopeReceiverId}/Locked")]
public async Task<IActionResult> EnvelopeLocked([FromRoute] string envelopeReceiverId, [FromQuery] string? culture = null)
public async Task<IActionResult> EnvelopeLocked([FromRoute] string envelopeReceiverId)
{
try
{
culture = culture is not null ? _sanitizer.Sanitize(culture) : null;
envelopeReceiverId = _sanitizer.Sanitize(envelopeReceiverId);
if (UserLanguage is null && culture is null)
{
UserLanguage = _cultures.Default.Language;
return Redirect($"{Request.Headers["Referer"]}?culture={_cultures.Default.Language}");
}
else if (UserLanguage is not null && culture is not null)
return Redirect($"Locked");
ViewData["UserCulture"] = _cultures[UserLanguage ?? culture];
ViewData["UserCulture"] = _cultures[UserLanguage];
return await _envRcvService.IsExisting(envelopeReceiverId: envelopeReceiverId).ThenAsync(
Success: isExisting => isExisting ? View().WithData("EnvelopeKey", envelopeReceiverId) : this.ViewEnvelopeNotFound(),
@@ -189,15 +189,13 @@ namespace EnvelopeGenerator.Web.Controllers
if (await _historyService.IsSigned(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress))
return View("EnvelopeSigned");
if (response.Envelope.Documents.Count > 0)
if (er.Envelope.Documents?.FirstOrDefault() is EnvelopeDocumentDto doc && doc.ByteData is not null)
{
var document = await envelopeOldService.GetDocument(response.Envelope.Documents[0].Id, envelopeReceiverId);
byte[] bytes = await envelopeOldService.GetDocumentContents(document);
ViewData["DocumentBytes"] = bytes;
ViewData["DocumentBytes"] = doc.ByteData;
}
else
{
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: "No document was found.");
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: "No document byte-data was found in ENVELOPE_DOCUMENT table.");
return this.ViewDocumentNotFound();
}
@@ -259,6 +257,7 @@ namespace EnvelopeGenerator.Web.Controllers
return Redirect($"/EnvelopeKey/{envelopeReceiverId}/Locked");
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
ViewData["UserCulture"] = _cultures[UserLanguage];
ViewData["EnvelopeKey"] = envelopeReceiverId;
return View();
},
@@ -286,7 +285,7 @@ namespace EnvelopeGenerator.Web.Controllers
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return await _envRcvService.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId).ThenAsync(
SuccessAsync: async (er) =>
{
{ViewData["UserCulture"] = _cultures[UserLanguage];
ViewData["UserCulture"] = _cultures[UserLanguage];
return await _historyService.IsRejected(envelopeId: er.EnvelopeId)
? View(er)
@@ -311,6 +310,8 @@ namespace EnvelopeGenerator.Web.Controllers
{
try
{
ViewData["UserCulture"] = _cultures[UserLanguage];
readOnlyKey = _sanitizer.Sanitize(readOnlyKey);
// check if the readOnlyId is valid
@@ -350,12 +351,10 @@ namespace EnvelopeGenerator.Web.Controllers
_logger.LogNotice(hist_res.Notices);
}
if (response.Envelope.Documents.Count > 0)
if (er.Envelope.Documents?.FirstOrDefault() is EnvelopeDocumentDto doc && doc.ByteData is not null)
{
var document = await envelopeOldService.GetDocument(response.Envelope.Documents[0].Id, envelopeKey);
byte[] bytes = await envelopeOldService.GetDocumentContents(document);
ViewData["DocumentBytes"] = doc.ByteData;
ViewData["EnvelopeKey"] = envelopeKey;
ViewData["DocumentBytes"] = bytes;
ViewData["IsReadOnly"] = true;
ViewData["ReadOnly"] = erro;
ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"];
@@ -363,7 +362,7 @@ namespace EnvelopeGenerator.Web.Controllers
}
else
{
_logger.LogEnvelopeError(envelopeReceiverId: envelopeKey, message: "No document was found.");
_logger.LogEnvelopeError(envelopeReceiverId: envelopeKey, message: "No document byte-data was found in ENVELOPE_DOCUMENT table.");
return this.ViewDocumentNotFound();
}
},

View File

@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<PackageId>EnvelopeGenerator.Web</PackageId>
<Version>2.1.1.0</Version>
<Version>2.4.0.0</Version>
<Authors>Digital Data GmbH</Authors>
<Company>Digital Data GmbH</Company>
<Product>EnvelopeGenerator.Web</Product>
@@ -13,11 +13,30 @@
<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>
<ApplicationIcon>Assets\icon.ico</ApplicationIcon>
<AssemblyVersion>2.1.1.0</AssemblyVersion>
<FileVersion>2.1.1.0</FileVersion>
<AssemblyVersion>2.4.0.0</AssemblyVersion>
<FileVersion>2.4.0.0</FileVersion>
<Copyright>Copyright © 2024 Digital Data GmbH. All rights reserved.</Copyright>
</PropertyGroup>
<ItemGroup>
<Compile Remove="wwwroot\lib\leaflet\build\**" />
<Compile Remove="wwwroot\lib\leaflet\debug\**" />
<Compile Remove="wwwroot\lib\leaflet\spec\**" />
<Compile Remove="wwwroot\lib\leaflet\src\**" />
<Content Remove="wwwroot\lib\leaflet\build\**" />
<Content Remove="wwwroot\lib\leaflet\debug\**" />
<Content Remove="wwwroot\lib\leaflet\spec\**" />
<Content Remove="wwwroot\lib\leaflet\src\**" />
<EmbeddedResource Remove="wwwroot\lib\leaflet\build\**" />
<EmbeddedResource Remove="wwwroot\lib\leaflet\debug\**" />
<EmbeddedResource Remove="wwwroot\lib\leaflet\spec\**" />
<EmbeddedResource Remove="wwwroot\lib\leaflet\src\**" />
<None Remove="wwwroot\lib\leaflet\build\**" />
<None Remove="wwwroot\lib\leaflet\debug\**" />
<None Remove="wwwroot\lib\leaflet\spec\**" />
<None Remove="wwwroot\lib\leaflet\src\**" />
</ItemGroup>
<ItemGroup>
<Content Remove="bundleconfig.json" />
</ItemGroup>
@@ -34,6 +53,17 @@
<ItemGroup>
<None Include="bundleconfig.json" />
<None Include="wwwroot\lib\leaflet-locationpicker\dist\leaflet-locationpicker.min.js" />
<None Include="wwwroot\lib\leaflet-locationpicker\dist\leaflet-locationpicker.src.js" />
<None Include="wwwroot\lib\leaflet-locationpicker\Gruntfile.js" />
<None Include="wwwroot\lib\leaflet-locationpicker\index.tmpl" />
<None Include="wwwroot\lib\leaflet-locationpicker\LICENSE" />
<None Include="wwwroot\lib\leaflet-locationpicker\README.md" />
<None Include="wwwroot\lib\leaflet\dist\leaflet-src.js" />
<None Include="wwwroot\lib\leaflet\dist\leaflet.js" />
<None Include="wwwroot\lib\leaflet\LICENSE" />
<None Include="wwwroot\lib\leaflet\PLUGIN-GUIDE.md" />
<None Include="wwwroot\lib\leaflet\README.md" />
</ItemGroup>
<ItemGroup>

View File

@@ -130,8 +130,6 @@ try
builder.Services.AddSingleton(config.GetSection("ContactLink").Get<ContactLink>() ?? new());
builder.Services.AddCookieConsentSettings();
builder.Services.AddCookieBasedLocalizer();
builder.Services.AddSingleton(HtmlEncoder.Default);

View File

@@ -1,8 +1,6 @@
@{
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
var logo = _logoOpt.Value;
}
@{
ViewData["Title"] = _localizer[WebKey.DocProtected];
var userCulture = ViewData["UserCulture"] as Culture;
}
@@ -35,23 +33,6 @@
</span>
</button>
</div>
<div class="dropdown flag-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>
</form>
</div>
</div>
@@ -68,18 +49,4 @@
<p>@_localizer[WebKey.LockedFooterBody]</p>
</details>
</section>
</div>
<script nonce="@nonce">
document.addEventListener('DOMContentLoaded', function () {
var dropdownItems = document.querySelectorAll('.dropdown-item');
dropdownItems.forEach(function (item) {
item.addEventListener('click', async function(event) {
event.preventDefault();
var language = this.getAttribute('data-language');
var flagCode = this.getAttribute('data-flag');
document.getElementById('selectedFlag').className = 'fi ' + flagCode + ' me-2';
await setLanguage(language);
});
});
});
</script>
</div>

View File

@@ -9,7 +9,6 @@
@using Newtonsoft.Json
@using Newtonsoft.Json.Serialization
@model EnvelopeReceiverDto;
<partial name="_CookieConsentPartial" />
@{
var userCulture = ViewData["UserCulture"] as Culture;
var envelope = Model.Envelope;

View File

@@ -9,10 +9,6 @@
@using Newtonsoft.Json
@using Newtonsoft.Json.Serialization
@model EnvelopeReceiverDto;
@{
ViewData["Title"] = _localizer[WebKey.SignDoc];
}
<partial name="_CookieConsentPartial" />
@{
var userCulture = ViewData["UserCulture"] as Culture;
var envelope = Model.Envelope;
@@ -26,6 +22,8 @@
var isReadOnly = false;
if (ViewData["IsReadOnly"] is bool isReadOnly_bool)
isReadOnly = isReadOnly_bool;
ViewData["Title"] = isReadOnly ? _localizer[WebKey.ViewDoc] : _localizer[WebKey.SignDoc];
}
<div class="envelope-view">
@if (!isReadOnly)
@@ -129,81 +127,25 @@
</div>
</div>
</div>
<div class="modal fade" id="locationBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="locationBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<input id="geoloc" type="text" value="" size="20" />
<div id="fixedMapCont"></div>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div>
}
<div id='app'></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">
const collapseNav = () => {
document.addEventListener('click', function (event) {
var navbarToggle = document.getElementById('navbarToggleExternalContent');
var navbarButton = document.querySelector('[data-bs-target="#navbarToggleExternalContent"]');
var isCollapsed = new bootstrap.Collapse(navbarToggle)._isTransitioning;
if (!navbarToggle.contains(event.target) && !navbarButton.contains(event.target) && !isCollapsed) {
new bootstrap.Collapse(navbarToggle).hide();
}
});
}
@if (ViewData["DocumentBytes"] is byte[] documentBytes)
{
var settings = new JsonSerializerSettings

View File

@@ -3,7 +3,7 @@
@using Newtonsoft.Json.Serialization
@{
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
var userCulture = ViewData["UserCulture"] as Culture;
var isReadOnly = false;
if (ViewData["IsReadOnly"] is bool isReadOnly_bool)
isReadOnly = isReadOnly_bool;
@@ -21,9 +21,12 @@
<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="~/lib/flag-icons-main/css/flag-icons.min.css" asp-append-version="true" />
<link rel="stylesheet" href="~/css/location-picker.min.css" asp-append-version="true" />
<link rel="stylesheet" href="~/lib/alertifyjs/css/alertify.min.css" />
<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="~/lib/leaflet/dist/leaflet.css" />
<link rel="stylesheet" href="~/lib/leaflet-locationpicker/dist/leaflet-locationpicker.src.css" />
</head>
<body>
<style>
@@ -39,9 +42,11 @@
}
const IS_READONLY = @isReadOnly.ToString().ToLower();
const DEVICE_TYPE = window.innerWidth <= 768 ? 'mobile' : window.innerWidth <= 1024 ? 'tablet' : 'desktop';
const DEVICE_SCREEN_TYPE = window.innerWidth <= 768 ? 'mobile' : window.innerWidth <= 1024 ? 'tablet' : 'desktop';
const IS_DESKTOP = DEVICE_TYPE == 'desktop'
const IS_DESKTOP_SIZE = DEVICE_SCREEN_TYPE == 'desktop'
const IS_MOBILE_DEVICE = /Mobi|Android/i.test(window.navigator.userAgent);
</script>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
@@ -49,13 +54,15 @@
<script src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="~/lib/sweetalert2/sweetalert2.min.js"></script>
<script src="~/lib/alertifyjs/alertify.min.js"></script>
<script src="~/js/util.min.js" asp-append-version="true"></script>
<script src="~/js/ui.min.js" asp-append-version="true"></script>
<script src="~/js/annotation.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="~/lib/pspdfkit/dist-2024.3.2/pspdfkit.js"></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="~/lib/leaflet/dist/leaflet.js"></script>
<script src="~/lib/leaflet-locationpicker/dist/leaflet-locationpicker.min.js"></script>
@await RenderSectionAsync("Scripts", required: false)
@{
var settings = new JsonSerializerSettings
@@ -75,6 +82,23 @@
@Html.AntiForgeryToken()
<footer>
<span>&copy; SignFlow 2023-2024 <a href="https://digitaldata.works">Digital Data GmbH</a></span>
<div class="dropup flag-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 culture-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>
<a href="/privacy-policy.de-DE.html">Datenschutz</a>
</footer>
</body>

View File

@@ -34,5 +34,6 @@
public static readonly string RejectionInfo2_ext = nameof(RejectionInfo2_ext);
public static readonly string SigningProcessTitle = nameof(SigningProcessTitle);
public static readonly string WelcomeToTheESignPortal = nameof(WelcomeToTheESignPortal);
public static readonly string ViewDoc = nameof(ViewDoc);
}
}

View File

@@ -5,5 +5,7 @@
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
},
"AdminPassword": "dd",
"UseCSPInDev": false
}

View File

@@ -14,9 +14,7 @@
"ConnectionStrings": {
"Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"
},
"AdminPassword": "dd",
"PSPDFKitLicenseKey": "SXCtGGY9XA-31OGUXQK-r7c6AkdLGPm2ljuyDr1qu0kkhLvydg-Do-fxpNUF4Rq3fS_xAnZRNFRHbXpE6sQ2BMcCSVTcXVJO6tPviexjpiT-HnrDEySlUERJnnvh-tmeOWprxS6BySPnSILkmaVQtUfOIUS-cUbvvEYHTvQBKbSF8di4XHQFyfv49ihr51axm3NVV3AXwh2EiKL5C5XdqBZ4sQ4O7vXBjM2zvxdPxlxdcNYmiU83uAzw7B83O_jubPzya4CdUHh_YH7Nlp2gP56MeG1Sw2JhMtfG3Rj14Sg4ctaeL9p6AEWca5dDjJ2li5tFIV2fQSsw6A_cowLu0gtMm5i8IfJXeIcQbMC2-0wGv1oe9hZYJvFMdzhTM_FiejM0agemxt3lJyzuyP8zbBSOgp7Si6A85krLWPZptyZBTG7pp7IHboUHfPMxCXqi-zMsqewOJtQBE2mjntU-lPryKnssOpMPfswwQX7QSkJYV5EMqNmEhQX6mEkp2wcqFzMC7bJQew1aO4pOpvChUaMvb1vgRek0HxLag0nwQYX2YrYGh7F_xXJs-8HNwJe8H0-eW4x4faayCgM5rB5772CCCsD9ThZcvXFrjNHHLGJ8WuBUFm6LArvSfFQdii_7j-_sqHMpeKZt26NFgivj1A==",
"UseCSPInDev": false,
"Content-Security-Policy": [ // The first format parameter {0} will be replaced by the nonce value.
"default-src 'self'",
"script-src 'self' 'nonce-{0}' 'unsafe-eval'",
@@ -32,7 +30,7 @@
"NLog": {
"throwConfigExceptions": true,
"variables": {
"logDirectory": "E:\\EnvelopeGenerator\\Logs",
"logDirectory": "E:\\LogFiles\\Digital Data\\signFlow",
"logFileNamePrefix": "${shortdate}-ECM.EnvelopeGenerator.Web"
},
"targets": {
@@ -77,21 +75,6 @@
"Audience": null,
"Key": "8RGnd7x0G2TYLOIW4m_qlIls7MfbAIGNrpQJzMAUIvULHOLiG723znRa_MG-Z4yw3SErusOU4hTui2rVBMcCaQ"
},
"CookieConsentSettings": {
"PrivacyPolicyUrl": "./privacy-policy.en.html",
"LegalNoticeUrl": "./cookies-policy.en.html",
"ContentURL": "/cookie-consent-content",
"ButtonAgreeClass": "btn btn-primary",
"ButtonDontAgreeClass": "btn btn-link text-decoration-none none-display",
"ButtonSaveClass": "btn btn-secondary none-display",
"Lang": "de",
"DefaultLang": "en",
"CookieName": "cookie-consent-settings",
"CookieStorageDays": 1,
"ModalId": "bootstrapCookieConsentSettingsModal",
"AlsoUseLocalStorage": false,
"Categories": [ "necessary" ]
},
"ContactLink": {
"Label": "Kontakt",
"Href": "https://digitaldata.works/",
@@ -113,12 +96,6 @@
}
],
"DisableMultiLanguage": false,
"DispatcherConfig": {
"SendingProfile": 1,
"AddedWho": "DDEnvelopGenerator",
"ReminderTypeId": 202377,
"EmailAttmt1": ""
},
"Regexes": [
{
"Pattern": "/^\\p{L}+(?:([\\ \\-\\']|(\\.\\ ))\\p{L}+)*$/u",
@@ -136,6 +113,12 @@
"ShowPageClass": "dd-show-logo",
"LockedPageClass": "dd-locked-logo"
},
"DispatcherConfig": {
"SendingProfile": 1,
"AddedWho": "DDEnvelopGenerator",
"ReminderTypeId": 202377,
"EmailAttmt1": ""
},
"MailConfig": {
"Placeholders": {
"[NAME_PORTAL]": "signFlow",

View File

@@ -82,5 +82,11 @@
"inputFiles": [
"wwwroot/css/card.css"
]
},
{
"outputFileName": "wwwroot/css/location-picker.min.css",
"inputFiles": [
"wwwroot/css/location-picker.css"
]
}
]

View File

@@ -0,0 +1,9 @@
#fixedMapCont {
height: 100%;
width: 100%;
}
#locationBackdrop .modal-body {
padding: 0;
margin: 0;
}

View File

@@ -0,0 +1 @@
#fixedMapCont{height:100%;width:100%}#locationBackdrop .modal-body{padding:0;margin:0}

View File

@@ -158,11 +158,11 @@ footer {
width: 100%;
z-index: 998;
border-width: 0;
font-size: clamp(0.75rem, 1.5vw, 1rem);
font-size: clamp(0.58rem, 1.5vw, 1rem);
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: start;
align-items: center;
}
footer * {
@@ -174,6 +174,18 @@ footer {
text-decoration: none;
}
footer .dropdown-toggle, footer .flag-dropdown, footer li {
margin: 0;
padding: 0;
border-width: 0;
}
footer .dropdown-menu a {
padding: 0.25rem 1rem 0.25rem 1rem;
margin-left: 0;
user-select: none;
}
.page {
margin-top: 3rem;
background: white;
@@ -401,9 +413,9 @@ footer#page-footer {
height: 2.5rem;
}
.flag-dropdown button {
/*.flag-dropdown button {
height: 100%;
}
}*/
.header-1 {
align-items: center;

File diff suppressed because one or more lines are too long

View File

@@ -102,8 +102,8 @@
const formFieldCity = new PSPDFKit.FormFields.TextFormField({
name: id_city,
annotationIds: PSPDFKit.Immutable.List([annotation_city.id]),
value: isMobile() ? location.city : "",
readOnly: isMobile()
value: IS_MOBILE_DEVICE ? location.city : "",
readOnly: IS_MOBILE_DEVICE
})
this.markFieldAsRequired(formFieldCity);

View File

@@ -199,7 +199,7 @@ class App {
});
break;
case 'COPY_URL':
const url = window.location.href;
const url = window.location.href.replace(/\/readonly/gi, '');
navigator.clipboard.writeText(url).then(function () {
bsNotify('Kopiert', { alert_type: 'success', delay: 4, icon_name: 'check_circle' });
}).catch(function (err) {
@@ -211,6 +211,10 @@ class App {
// Show the modal
Comp.ShareBackdrop.show();
break;
case 'LOCATION':
// Show the modal
Comp.LocationBackdrop.show();
break;
}
}
@@ -235,7 +239,7 @@ class App {
const city_regex = new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$")
const iCityFields = iFormFieldValues.filter(f => Annotation.isCityField(f))
for (var f of iCityFields)
if (!city_regex.test(f.value)) {
if (!IS_MOBILE_DEVICE && !city_regex.test(f.value)) {
Swal.fire({
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.`,

View File

@@ -1,3 +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.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}}
`)}},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.replace(/\/readonly/gi,"");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();break;case"LOCATION":Comp.LocationBackdrop.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(!IS_MOBILE_DEVICE&&!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

@@ -8,6 +8,94 @@ document.querySelectorAll('.email-input').forEach(input => {
});
});
document.addEventListener('DOMContentLoaded', function () {
var dropdownItems = document.querySelectorAll('.culture-dropdown-item');
dropdownItems.forEach(function (item) {
item.addEventListener('click', async function (event) {
event.preventDefault();
var language = this.getAttribute('data-language');
var flagCode = this.getAttribute('data-flag');
document.getElementById('selectedFlag').className = 'fi ' + flagCode + ' me-2';
await setLanguage(language);
});
});
});
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));
});
document.addEventListener('DOMContentLoaded', async () => {
var coords;
try {
coords = await getCoordinates();
}
catch (err) {
coords = {
latitude: 0,
longitude: 0,
};
}
$('#geoloc').leafletLocationPicker({
alwaysOpen: true,
mapContainer: "#fixedMapCont",
location: { latitude: coords.latitude, longitude: coords.longitude }
});
});
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',
@@ -79,4 +167,10 @@ class Comp {
Comp.__ShareBackdrop ??= new bootstrap.Modal(document.getElementById('shareBackdrop'));
return this.__ShareBackdrop;
}
static __LocationBackdrop;
static get LocationBackdrop() {
Comp.__LocationBackdrop ??= new bootstrap.Modal(document.getElementById('locationBackdrop'));
return this.__LocationBackdrop;
}
}

View File

@@ -1 +1 @@
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}}
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")})});document.addEventListener("DOMContentLoaded",function(){var n=document.querySelectorAll(".culture-dropdown-item");n.forEach(function(n){n.addEventListener("click",async function(n){n.preventDefault();var t=this.getAttribute("data-language"),i=this.getAttribute("data-flag");document.getElementById("selectedFlag").className="fi "+i+" me-2";await setLanguage(t)})})});document.getElementById("readonly-send").addEventListener("click",async()=>{const n=document.getElementById("readonly-receiver-mail"),t=document.getElementById("readonly-date-valid"),i=n.value,r=t.value;if(!i||n.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}const u=new Date(Date.now()+864e5);if(new Date(r)<u){Swal.fire({icon:"error",title:"Falsches Datum",text:"Die Verteilung der Umschläge sollte mindestens einen Tag dauern."});return}shareEnvelope(i,r).then(n=>{n.ok?Swal.fire({title:"Gesendet",icon:"success"}):Swal.fire({icon:"error",title:`Fehler ${n.status}`,text:"Der Vorgang ist fehlgeschlagen. Bitte wenden Sie sich an das IT-Team."})}).catch(()=>{Swal.fire({icon:"error",title:"Unerwarteter Fehler",text:"Der Vorgang ist fehlgeschlagen. Bitte wenden Sie sich an das IT-Team."})});n.value="";t.valueAsDate=new Date((new Date).setDate((new Date).getDate()+8))});document.addEventListener("DOMContentLoaded",async()=>{var n;try{n=await getCoordinates()}catch(t){n={latitude:0,longitude:0}}$("#geoloc").leafletLocationPicker({alwaysOpen:!0,mapContainer:"#fixedMapCont",location:{latitude:n.latitude,longitude:n.longitude}})});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}static __LocationBackdrop;static get LocationBackdrop(){return Comp.__LocationBackdrop??=new bootstrap.Modal(document.getElementById("locationBackdrop")),this.__LocationBackdrop}}

View File

@@ -58,7 +58,7 @@
else
toolbarItems = toolbarItems.concat(UI.getWritableItems(handler));
if (!IS_DESKTOP && !IS_READONLY)
if (!IS_DESKTOP_SIZE && !IS_READONLY)
toolbarItems = toolbarItems.concat(UI.getMobileWritableItems(handler));
instance.setToolbarItems(toolbarItems)
@@ -89,6 +89,19 @@
icon: `<svg width="30" height="30" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<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"/>
</svg>`,
},
{
type: 'custom',
id: 'button-location',
className: 'button-location',
title: 'Location',
onPress() {
callback('LOCATION')
},
icon: `<svg width="30" height="30" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 21C15.5 17.4 19 14.1764 19 10.2C19 6.22355 15.866 3 12 3C8.13401 3 5 6.22355 5 10.2C5 14.1764 8.5 17.4 12 21Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 13C13.6569 13 15 11.6569 15 10C15 8.34315 13.6569 7 12 7C10.3431 7 9 8.34315 9 10C9 11.6569 10.3431 13 12 13Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>`,
}
];
}

View File

@@ -1,7 +1,10 @@
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 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">
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_SIZE||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 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"/>
</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-location",className:"button-location",title:"Location",onPress(){n("LOCATION")},icon:`<svg width="30" height="30" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 21C15.5 17.4 19 14.1764 19 10.2C19 6.22355 15.866 3 12 3C8.13401 3 5 6.22355 5 10.2C5 14.1764 8.5 17.4 12 21Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 13C13.6569 13 15 11.6569 15 10C15 8.34315 13.6569 7 12 7C10.3431 7 9 8.34315 9 10C9 11.6569 10.3431 13 12 13Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</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">
<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(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">

View File

@@ -57,12 +57,4 @@ function detailedCurrentDate() {
second: '2-digit',
timeZoneName: 'shortOffset'
}).format();
}
let __is_mobile = null;
function isMobile() {
if (__is_mobile === null) {
__is_mobile = /Mobi|Android/i.test(window.navigator.userAgent);
}
return __is_mobile;
}

View File

@@ -1 +1 @@
function getCoordinates(){return new Promise((n,t)=>{navigator.geolocation?navigator.geolocation.getCurrentPosition(t=>n(t.coords),n=>t(n)):t(new Error("Geolocation is not supported by this browser."))})}async function getCity(){try{const t=await getCoordinates(),i=await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${t.latitude}&lon=${t.longitude}`),n=await i.json();if(n&&n.address){const t=n.address.city||n.address.town||n.address.village||n.address.hamlet,i=n.address.postcode;return i+" "+t||""}}catch{return""}}async function getLocation(){try{const t=await getCoordinates(),i=await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${t.latitude}&lon=${t.longitude}`),n=await i.json();if(n&&n.address){const t=n.address.city||n.address.town||n.address.village||n.address.hamlet,i=n.address.postcode;return{postalCode:i,city:t}}}catch{return{postalCode:"",city:""}}}function detailedCurrentDate(){return new Intl.DateTimeFormat("de-DE",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit",timeZoneName:"shortOffset"}).format()}function isMobile(){return __is_mobile===null&&(__is_mobile=/Mobi|Android/i.test(window.navigator.userAgent)),__is_mobile}const B64ToBuff=n=>new Uint8Array(Array.from(atob(n),n=>n.charCodeAt(0))).buffer;const getLocaleDateString=()=>(new Date).toLocaleDateString("de-DE");let __is_mobile=null;
function getCoordinates(){return new Promise((n,t)=>{navigator.geolocation?navigator.geolocation.getCurrentPosition(t=>n(t.coords),n=>t(n)):t(new Error("Geolocation is not supported by this browser."))})}async function getCity(){try{const t=await getCoordinates(),i=await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${t.latitude}&lon=${t.longitude}`),n=await i.json();if(n&&n.address){const t=n.address.city||n.address.town||n.address.village||n.address.hamlet,i=n.address.postcode;return i+" "+t||""}}catch{return""}}async function getLocation(){try{const t=await getCoordinates(),i=await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${t.latitude}&lon=${t.longitude}`),n=await i.json();if(n&&n.address){const t=n.address.city||n.address.town||n.address.village||n.address.hamlet,i=n.address.postcode;return{postalCode:i,city:t}}}catch{return{postalCode:"",city:""}}}function detailedCurrentDate(){return new Intl.DateTimeFormat("de-DE",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit",timeZoneName:"shortOffset"}).format()}const B64ToBuff=n=>new Uint8Array(Array.from(atob(n),n=>n.charCodeAt(0))).buffer;const getLocaleDateString=()=>(new Date).toLocaleDateString("de-DE");

View File

@@ -0,0 +1,142 @@
'use strict';
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-markdown');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
meta: {
banner:
'/* \n'+
' * Leaflet Location Picker v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %> \n'+
' * \n'+
' * Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author.name %> \n'+
' * <%= pkg.author.email %> \n'+
' * <%= pkg.author.url %> \n'+
' * \n'+
' * Licensed under the <%= pkg.license %> license. \n'+
' * \n'+
' * Demo: \n'+
' * <%= pkg.homepage %> \n'+
' * \n'+
' * Source: \n'+
' * <%= pkg.repository.url %> \n'+
' * \n'+
' */\n',
features: [
"Custom location format, lat,lon separator and precision",
"Pick Location Latidute,Longitude clicking on map",
"Bind multiple events or single picker callback",
"Load picker map from preselected location",
"Bind callback on location picked",
"Enable disable location marker",
"Custom map baselayer"
],
sources: [
{name: "Github.com", url: 'https://github.com/stefanocudini/<%= pkg.name %>' },
{name: "Node Packaged Module", url: 'https://npmjs.org/package/<%= pkg.name %>' },
//{name: "Bitbuket", url: 'https://bitbucket.org/zakis_/<%= pkg.name %>' },
//{name: "Atmosphere", url: 'http://atmospherejs.com/package/<%= pkg.name %>' }
]
},
clean: {
homepage: {
src: ['index.html']
},
dist: {
src: ['dist/*']
}
},
jshint: {
options: {
globals: {
console: true,
module: true
},
"-W099": true, //ignora tabs e space warning
"-W033": true,
"-W044": true //ignore regexp
},
files: "src/<%= pkg.name %>.js"
},
concat: {
//TODO cut out SearchMarker
options: {
banner: '<%= meta.banner %>'
},
dist: {
files: {
'dist/<%= pkg.name %>.src.js': ['src/<%= pkg.name %>.js'],
'dist/<%= pkg.name %>.src.css': ['src/<%= pkg.name %>.css']
}
}
},
uglify: {
options: {
banner: '<%= meta.banner %>'
},
dist: {
files: {
'dist/<%= pkg.name %>.min.js': ['dist/<%= pkg.name %>.src.js']
}
}
},
markdown: {
readme: {
files: {
'index.html': ['README.md']
},
options: {
template: 'index.tmpl',
templateContext: function() {
var cfg = grunt.config();
cfg.title = cfg.pkg.name.replace(/-/g,' ');
cfg.ribbonurl = 'http://ghbtns.com/github-btn.html?user=stefanocudini&amp;repo='+cfg.pkg.name+'&amp;type=watch&amp;count=true';
cfg.examples = grunt.file.expand('examples/*.html');
cfg.features = cfg.meta.features;
cfg.sources = cfg.meta.sources;
cfg.giturl = cfg.meta.sources[0].url;
cfg.image = grunt.file.expand('images/'+cfg.pkg.name+'.png');
return cfg;
},
markdownOptions: {
gfm: true,
highlight: 'manual',
codeLines: {
before: '<div>',
after: '</div>'
}
}
}
}
},
watch: {
dist: {
options: { livereload: true },
files: ['src/*'],
tasks: ['clean','concat','jshint']
}
}
});
grunt.registerTask('default', [
'clean',
'concat',
'jshint',
'uglify',
'markdown'
]);
};

View File

@@ -0,0 +1,23 @@
The MIT License (MIT)
Copyright (c) 2014 Duy Anh Nguyen
Copyright (c) 2015 Josef Kufner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,68 @@
Leaflet Location Picker
============
[![npm version](https://badge.fury.io/js/leaflet-locationpicker.svg)](http://badge.fury.io/js/leaflet-locationpicker)
Simple location picker with Leaflet map
# Usage:
```html
<label>Insert a Geo Location
<input id="geoloc" type="text" value="" />
</label>
```
```javascript
$('#geoloc').leafletLocationPicker();
```
# Examples:
* [Simple](examples/simple.html)
![Image](https://raw.githubusercontent.com/stefanocudini/leaflet-locationpicker/master/images/leaflet-locationpicker.png)
# Options
| Option | Default | Description |
| --------------- | ---------------- | ----------------------------------------- |
|className | baseClassName |css classname applied to widget |
|location | optsMap.center | initial map center |
|locationFormat | '{lat}{sep}{lng}'| returne format of location value |
|locationMarker | true | render manker on map |
|locationDigits | 6 | coordinates precision |
|locationSep | ',' | coordinates separator|
|position | 'topright' | position relative to input|
|layer | 'OSM' | base layer on map|
|height | 140 | height of map |
|width | 200 | with f map|
|event | 'click' | event to fire location pick|
|cursorSize | '30px' | size of cross cursor |
|map | optsMap | custom [leflet map options](https://leafletjs.com/reference-1.6.0.html#map-option) |
|onChangeLocation | $.noop | callback retuned location after pick from map|
|alwaysOpen | false | always open Maps (without close button) |
|mapContainer | "" ||
# Install
```
npm install --save leaflet-locationpicker
```
# Build
Therefore the deployment require **npm** installed in your system.
```bash
npm install
grunt
```
# Source
* [Github](https://github.com/stefanocudini/leaflet-locationpicker)
* [NPM](https://npmjs.org/package/leaflet-locationpicker)

View File

@@ -0,0 +1,17 @@
/*
* Leaflet Location Picker v0.3.4 - 2022-11-18
*
* Copyright 2022 Stefano Cudini
* stefano.cudini@gmail.com
* https://opengeo.tech/
*
* Licensed under the MIT license.
*
* Demo:
* https://opengeo.tech/maps/leaflet-locationpicker/
*
* Source:
* git@github.com:stefanocudini/leaflet-locationpicker.git
*
*/
!function(a){if("function"==typeof define&&define.amd)define(["jquery","leaflet"],a);else if("undefined"!=typeof module)module.exports=a(require("jquery","leaflet"));else{if(void 0===window.jQuery)throw"jQuery must be loaded first";if(void 0===window.L)throw"Leaflet must be loaded first";a(window.jQuery,window.L)}}(function(a,b){var c=a;c.fn.leafletLocationPicker=function(a,d){function e(c){return c?b.latLng(parseFloat(c.lat).toFixed(a.locationDigits),parseFloat(c.lng).toFixed(a.locationDigits)):c}function f(d){var f=d;switch(c.type(d)){case"string":var g=d.split(a.locationSep);f=g[0]&&g[1]?b.latLng(g):null;break;case"array":f=b.latLng(d);break;case"object":var h,i;d.hasOwnProperty("lat")?h=d.lat:d.hasOwnProperty("latitude")&&(h=d.latitude),d.hasOwnProperty("lng")?i=d.lng:d.hasOwnProperty("lon")?i=d.lon:d.hasOwnProperty("longitude")&&(i=d.longitude),f=b.latLng(parseFloat(h),parseFloat(i));break;default:f=d}return e(f)}function g(d){if(d.divMap=document.createElement("div"),d.$map=c(document.createElement("div")).addClass(a.className+"-map").height(a.height).width(a.width).append(d.divMap),a.readOnly&&d.$map.addClass("read-only"),a.mapContainer&&c(a.mapContainer)?d.$map.appendTo(a.mapContainer).addClass("map-select"):d.$map.appendTo("body"),d.location&&(a.map.center=d.location),"string"==typeof a.layer&&k[a.layer]?a.map.layers=b.tileLayer(k[a.layer]):a.layer instanceof b.TileLayer||a.layer instanceof b.GridLayer||a.layer instanceof b.LayerGroup?a.map.layers=a.layer:a.map.layers=b.tileLayer(k.OSM),d.map=b.map(d.divMap,a.map).addControl(b.control.zoom({position:"bottomright"})).on(a.event,function(b){a.readOnly||d.setLocation(b.latlng)}),a.activeOnMove&&d.map.on("move",function(a){d.setLocation(a.target.getCenter())}),!0!==a.alwaysOpen){var e=b.control({position:"topright"});e.onAdd=function(c){var e=b.DomUtil.create("div","leaflet-bar"),f=b.DomUtil.create("a","leaflet-control "+a.className+"-close");return f.innerHTML="&times;",e.appendChild(f),b.DomEvent.on(f,"click",b.DomEvent.stop,d).on(f,"click",d.closeMap,d),e},e.addTo(d.map)}return a.locationMarker&&(d.marker=h(d.location).addTo(d.map)),d.$map}function h(c){return b.marker(f(c)||b.latLng(0,0),{icon:b.divIcon({className:a.className+"-marker",iconAnchor:b.point(0,0),html:"<div"+("30px"!==a.cursorSize?'style="width: '+a.cursorSize+"; height: "+a.cursorSize+';"':"")+'><div class="corner1"></div><div class="corner2"></div><div class="corner3"></div><div class="corner4"></div></div>'})})}var i=window.location.protocol,j="leaflet-locpicker",k={OSM:i+"//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"},l={zoom:0,center:b.latLng([40,0]),zoomControl:!1,attributionControl:!1};c.isPlainObject(a)&&c.isPlainObject(a.map)&&(l=c.extend(l,a.map));var m={alwaysOpen:!1,className:j,location:l.center,locationFormat:"{lat}{sep}{lng}",locationMarker:!0,locationDigits:6,locationSep:",",position:"topright",layer:"OSM",height:140,width:200,event:"click",cursorSize:"30px",readOnly:!1,map:l,onChangeLocation:c.noop,mapContainer:""};return a=c.isPlainObject(a)?c.extend(m,a):c.isFunction(a)?c.extend(m,{onChangeLocation:a}):m,c.isFunction(d)&&(a=c.extend(m,{onChangeLocation:d})),c(this).each(function(d,e){var h=this;h.$input=c(this),h.options=a,h.setReadOnly=function(b){a.readOnly=b,h.$map.toggleClass("read-only",b)},h.locationOri=h.$input.val(),h.onChangeLocation=function(){var b={latlng:h.location,location:h.getLocation()};h.$input.trigger(c.extend(b,{type:"changeLocation"})),a.onChangeLocation.call(h,b)},h.setLocation=function(a,b){a=a||m.location,h.location=f(a),h.marker&&h.marker.setLatLng(a),b||(h.$input.data("location",h.location),h.$input.val(h.getLocation()),h.onChangeLocation())},h.getLocation=function(){return h.location?b.Util.template(a.locationFormat,{lat:h.location.lat,lng:h.location.lng,sep:a.locationSep}):h.location},h.updatePosition=function(){switch(a.position){case"bottomleft":h.$map.css({top:h.$input.offset().top+h.$input.height()+6,left:h.$input.offset().left});break;case"topright":h.$map.css({top:h.$input.offset().top,left:h.$input.offset().left+h.$input.width()+5})}},h.openMap=function(){h.updatePosition(),h.$map.show(),h.map.invalidateSize(),h.$input.trigger("show")},h.closeMap=function(){h.$map.hide(),h.$input.trigger("hide")},h.setLocation(h.locationOri,!0),h.$map=g(h),h.$input.addClass(a.className).on("focus."+a.className,function(a){a.preventDefault(),h.openMap()}).on("blur."+a.className,function(a){a.preventDefault();for(var b=a.relatedTarget,c=!0;b;){if(b._leaflet){c=!1;break}b=b.parentElement}c&&setTimeout(function(){h.closeMap()},100)}),c(window).on("resize",function(){h.$map.is(":visible")&&h.updatePosition()}),a.alwaysOpen&&!0===a.alwaysOpen&&h.openMap()}),this}});

View File

@@ -0,0 +1,128 @@
/*
* Leaflet Location Picker v0.3.4 - 2022-11-18
*
* Copyright 2022 Stefano Cudini
* stefano.cudini@gmail.com
* https://opengeo.tech/
*
* Licensed under the MIT license.
*
* Demo:
* https://opengeo.tech/maps/leaflet-locationpicker/
*
* Source:
* git@github.com:stefanocudini/leaflet-locationpicker.git
*
*/
.leaflet-locpicker-active {
box-shadow: 0 0 5px rgba(0,0,0,0.3);
}
.leaflet-locpicker-map {
display: none;
position: absolute;
background: rgba(255,255,255,1);
box-shadow: 4px 4px 8px rgba(0,0,0,0.2);
}
.leaflet-locpicker-map:not(.read-only) .leaflet-container,
.leaflet-locpicker-map:not(.read-only) .leaflet-locpicker-marker {
cursor: crosshair;
}
.leaflet-locpicker-map.read-only .leaflet-locpicker-marker {
cursor: grab;
}
.leaflet-locpicker-close {
cursor: pointer;
width: 30px;
height: 30px;
line-height: 30px;
font: 700 22px 'Lucida Console', Monaco, monospace;
text-indent: 1px;
}
.leaflet-locpicker-map .leaflet-container {
position: absolute;
top: 5px;
right: 5px;
bottom: 5px;
left: 5px;
border: 1px solid rgba(100,100,100,0.2)
}
.leaflet-locpicker-map .leaflet-control {
box-shadow: none;
margin: 0;
}
.leaflet-locpicker-map .leaflet-bar {
border-radius: 0;
}
.leaflet-locpicker-map .leaflet-bar a:first-child {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.leaflet-locpicker-map .leaflet-bar a:last-child {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.map-select {
display: block !important;
position: relative;
left: 0 !important;
top: 0 !important;
width: 100% !important;
margin: 0 auto;
}
/* MARKER */
.leaflet-locpicker-map .leaflet-locpicker-marker > div {
position: relative;
top: -1px;
left: -1px;
padding: 0;
margin: 0;
width: 30px; /* defaults */
height: 30px;
}
.leaflet-locpicker-map .leaflet-locpicker-marker > div > div {
padding: 0;
margin: 0;
position: absolute;
outline: 1px solid #fff;
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.6);
}
.leaflet-locpicker-map .leaflet-locpicker-marker > div > .corner1 {
width: 50%;
height: 0;
left: -70%;
border-top: 2px solid black;
}
.leaflet-locpicker-map .leaflet-locpicker-marker > div > .corner2 {
width: 50%;
height: 0;
left: 30%;
border-top: 2px solid black;
}
.leaflet-locpicker-map .leaflet-locpicker-marker > div > .corner3 {
width: 0;
height: 50%;
top: 30%;
border-left: 2px solid black;
}
.leaflet-locpicker-map .leaflet-locpicker-marker > div > .corner4 {
width: 0;
height: 50%;
top: -70%;
border-left: 2px solid black;
}

View File

@@ -0,0 +1,339 @@
/*
* Leaflet Location Picker v0.3.4 - 2022-11-18
*
* Copyright 2022 Stefano Cudini
* stefano.cudini@gmail.com
* https://opengeo.tech/
*
* Licensed under the MIT license.
*
* Demo:
* https://opengeo.tech/maps/leaflet-locationpicker/
*
* Source:
* git@github.com:stefanocudini/leaflet-locationpicker.git
*
*/
(function (factory) {
if(typeof define === 'function' && define.amd) {
//AMD
define(['jquery','leaflet'], factory);
} else if(typeof module !== 'undefined') {
// Node/CommonJS
module.exports = factory(require('jquery','leaflet'));
} else {
// Browser globals
if(typeof window.jQuery === 'undefined')
throw 'jQuery must be loaded first';
if(typeof window.L === 'undefined')
throw 'Leaflet must be loaded first';
factory(window.jQuery, window.L);
}
})(function(jQuery, L) {
var $ = jQuery;
$.fn.leafletLocationPicker = function(opts, onChangeLocation) {
var http = window.location.protocol;
var baseClassName = 'leaflet-locpicker',
baseLayers = {
'OSM': http + '//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
// 'SAT': http + '//otile1.mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.png' // AK 2021-04-22: invalid URL!!
//TODO add more free base layers
};
var optsMap = {
zoom: 0,
center: L.latLng([40,0]),
zoomControl: false,
attributionControl: false
};
if($.isPlainObject(opts) && $.isPlainObject(opts.map))
optsMap = $.extend(optsMap, opts.map);
var defaults = {
alwaysOpen: false,
className: baseClassName,
location: optsMap.center,
locationFormat: '{lat}{sep}{lng}',
locationMarker: true,
locationDigits: 6,
locationSep: ',',
position: 'topright',
layer: 'OSM',
height: 140,
width: 200,
event: 'click',
cursorSize: '30px',
readOnly: false,
map: optsMap,
onChangeLocation: $.noop,
mapContainer: ""
};
if($.isPlainObject(opts))
opts = $.extend(defaults, opts);
else if($.isFunction(opts))
opts = $.extend(defaults, {
onChangeLocation: opts
});
else
opts = defaults;
if($.isFunction(onChangeLocation))
opts = $.extend(defaults, {
onChangeLocation: onChangeLocation
});
function roundLocation(loc) {
return loc ? L.latLng(
parseFloat(loc.lat).toFixed(opts.locationDigits),
parseFloat(loc.lng).toFixed(opts.locationDigits)
) : loc;
}
function parseLocation(loc) {
var retLoc = loc;
switch($.type(loc)) {
case 'string':
var ll = loc.split(opts.locationSep);
if(ll[0] && ll[1])
retLoc = L.latLng(ll);
else
retLoc = null;
break;
case 'array':
retLoc = L.latLng(loc);
break;
case 'object':
var lat, lng;
if(loc.hasOwnProperty('lat'))
lat = loc.lat;
else if(loc.hasOwnProperty('latitude'))
lat = loc.latitude;
if(loc.hasOwnProperty('lng'))
lng = loc.lng;
else if(loc.hasOwnProperty('lon'))
lng = loc.lon;
else if(loc.hasOwnProperty('longitude'))
lng = loc.longitude;
retLoc = L.latLng(parseFloat(lat),parseFloat(lng));
break;
default:
retLoc = loc;
}
return roundLocation( retLoc );
}
function buildMap(self) {
self.divMap = document.createElement('div');
self.$map = $(document.createElement('div'))
.addClass(opts.className + '-map')
.height(opts.height)
.width(opts.width)
.append(self.divMap);
if (opts.readOnly)
self.$map.addClass("read-only");
//adds either as global div or specified container
//if added to specified container add some style class
if(opts.mapContainer && $(opts.mapContainer))
self.$map.appendTo(opts.mapContainer)
.addClass('map-select');
else
self.$map.appendTo('body');
if(self.location)
opts.map.center = self.location;
if(typeof opts.layer === 'string' && baseLayers[opts.layer]) {
opts.map.layers = L.tileLayer(baseLayers[opts.layer]);
}else if (opts.layer instanceof L.TileLayer ||
opts.layer instanceof L.GridLayer ||
opts.layer instanceof L.LayerGroup) {
opts.map.layers = opts.layer;
}else {
opts.map.layers = L.tileLayer(baseLayers.OSM);
}
//leaflet map
self.map = L.map(self.divMap, opts.map)
.addControl( L.control.zoom({position: 'bottomright'}) )
.on(opts.event, function(e) {
if (!opts.readOnly)
self.setLocation(e.latlng);
});
if(opts.activeOnMove) {
self.map.on('move', function(e) {
self.setLocation(e.target.getCenter());
});
}
//only adds closeBtn if not alwaysOpen
if(opts.alwaysOpen!==true){
var xmap = L.control({position: 'topright'});
xmap.onAdd = function(map) {
var btn_holder = L.DomUtil.create('div', 'leaflet-bar');
var btn = L.DomUtil.create('a','leaflet-control '+opts.className+'-close');
btn.innerHTML = '&times;';
btn_holder.appendChild(btn);
L.DomEvent
.on(btn, 'click', L.DomEvent.stop, self)
.on(btn, 'click', self.closeMap, self);
return btn_holder;
};
xmap.addTo(self.map);
}
if(opts.locationMarker)
self.marker = buildMarker(self.location).addTo(self.map);
return self.$map;
}
function buildMarker(loc) {
return L.marker(parseLocation(loc) || L.latLng(0,0), {
icon: L.divIcon({
className: opts.className+'-marker',
iconAnchor: L.point(0, 0),
// TODO: get rid of inline CSS completely, in order to make it compliant with Content-Security-Policy that doesn't wallows 'unsafe-inline' CSS.
// AK: These additional styles can be set up with JavaScript, after creation of the marker icon element.
html: '<div' + ("30px" !== opts.cursorSize ? 'style="width: ' + opts.cursorSize + '; height: ' + opts.cursorSize + ';"' : '') + '>'+
'<div class="corner1"></div>'+
'<div class="corner2"></div>'+
'<div class="corner3"></div>'+
'<div class="corner4"></div>'+
'</div>'
})
});
}
$(this).each(function(index, input) {
var self = this;
self.$input = $(this);
self.options = opts; // access to options
self.setReadOnly = function(newReadOnly) {
opts.readOnly = newReadOnly;
self.$map.toggleClass("read-only", newReadOnly);
};
self.locationOri = self.$input.val();
self.onChangeLocation = function() {
var edata = {
latlng: self.location,
location: self.getLocation()
};
self.$input.trigger($.extend(edata, {
type: 'changeLocation'
}));
opts.onChangeLocation.call(self, edata);
};
self.setLocation = function(loc, noSet) {
loc = loc || defaults.location;
self.location = parseLocation(loc);
if(self.marker)
self.marker.setLatLng(loc);
if(!noSet) {
self.$input.data('location', self.location);
self.$input.val( self.getLocation() );
self.onChangeLocation();
}
};
self.getLocation = function() {
return self.location ? L.Util.template(opts.locationFormat, {
lat: self.location.lat,
lng: self.location.lng,
sep: opts.locationSep
}) : self.location;
};
self.updatePosition = function() {
switch(opts.position) {
case 'bottomleft':
self.$map.css({
top: self.$input.offset().top + self.$input.height() + 6,
left: self.$input.offset().left
});
break;
case 'topright':
self.$map.css({
top: self.$input.offset().top,
left: self.$input.offset().left + self.$input.width() + 5
});
break;
}
};
self.openMap = function() {
self.updatePosition();
self.$map.show();
self.map.invalidateSize();
self.$input.trigger('show');
};
self.closeMap = function() {
self.$map.hide();
self.$input.trigger('hide');
};
self.setLocation(self.locationOri, true);
self.$map = buildMap(self);
self.$input
.addClass(opts.className)
.on('focus.'+opts.className, function(e) {
e.preventDefault();
self.openMap();
})
.on('blur.'+opts.className, function(e) {
e.preventDefault();
var p = e.relatedTarget;
var close = true;
while (p) {
if (p._leaflet) {
close = false;
break;
}
p = p.parentElement;
}
if(close) {
setTimeout(function() {
self.closeMap();
}, 100);
}
});
$(window).on('resize', function() {
if (self.$map.is(':visible'))
self.updatePosition();
});
//opens map initially if alwaysOpen
if(opts.alwaysOpen && opts.alwaysOpen===true) self.openMap();
});
return this;
};
});

View File

@@ -0,0 +1,148 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<title>Leaflet Location Picker Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="//unpkg.com/leaflet@1.1.0/dist/leaflet.css" />
<link rel="stylesheet" href="../dist/leaflet-locationpicker.src.css" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h3><a href="../index.html"><big></big> Leaflet Location Picker</a></h3>
<h4>Simple Example: <em></em></h4>
<form id="insert">
<label>Insert new geographic location:</label><br />
<input class="geolocs" type="text" value="" size="20" />
<pre>
$('.geolocs').leafletLocationPicker();
</pre>
</form>
<form id="default">
Change default geographic location: <br />
<input class="geolocs" type="text" value="17.9787,81.0352" size="20" />
</form>
<form id="format">
Custom location format: <br />
<input id="geoloc2" type="text" value="" size="20" /> <br />
<pre>
$('#geoloc2').leafletLocationPicker({
locationFormat: '{lat}@{lng}#WGS84',
position: 'bottomleft'
});
</pre>
</form>
<form id="callback">
Custom callback: <br />
<input id="geoloc4" type="text" value="" size="20" />
<br /><br />
<i>Value from callback:</i><br />
<em style="color:blue"></em><br />
<pre>
$('#geoloc4').leafletLocationPicker(function(e) {
$(this).siblings('em').text(e.location);
});
</pre>
</form>
<form id="events">
Events: <em style="color:red"></em><br />
<input id="geoloc3" type="text" value="" size="20" />
<br />
<br /><input id="geolat" type="text" value="" size="20" />
<br /><input id="geolng" type="text" value="" size="20" />
<br /><i>string location</i><br />
<pre>
$('#geoloc3').leafletLocationPicker({
locationSep: ' - '
})
.on('show', function(e) {
$(this).siblings('em').text('click on map for insert the location');
})
.on('hide', function(e) {
$(this).siblings('em').text('');
})
.on('changeLocation', function(e) {
$(this)
.siblings('#geolat').val( e.latlng.lat )
.siblings('#geolng').val( e.latlng.lng )
.siblings('i').text('"'+e.location+'"');
});
</pre>
</form>
<script src="//unpkg.com/leaflet@1.1.0/dist/leaflet.js"></script>
<script src="//code.jquery.com/jquery-2.1.0.min.js"></script>
<form id="fixedContAlwaysOpen">
Fixed container and always open map: <br />
<div style="min-height: 140;min-width: 200;">
<input id="geoloc5" type="text" value="" size="20" />
<div id="fixedMapCont" style="border: 1px solid black; min-height: 140;min-width: 200;"></div>
</div>
<pre>
$('#geoloc5').leafletLocationPicker({
alwaysOpen: true,
mapContainer: "#fixedMapCont"
});
</pre>
</form>
<script src="../../leaflet/dist/leaflet.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script src="../dist/leaflet-locationpicker.min.js"></script>
<script>
//multiple istances
$('.geolocs').leafletLocationPicker();
//custom location format
$('#geoloc2').leafletLocationPicker({
locationFormat: '{lat}@{lng}#WGS84',
position: 'bottomleft'
});
//events
$('#geoloc3').leafletLocationPicker({
locationSep: ' - '
})
.on('show', function(e) {
$(this).siblings('em').text('click on map for insert the location');
})
.on('hide', function(e) {
$(this).siblings('em').text('');
})
.on('changeLocation', function(e) {
$(this)
.siblings('#geolat').val( e.latlng.lat )
.siblings('#geolng').val( e.latlng.lng )
.siblings('i').text('"'+e.location+'"');
});
//callback
$('#geoloc4').leafletLocationPicker(function(e) {
$(this).siblings('em').text(e.location);
});
//fix n alwaysOpen
$('#geoloc5').leafletLocationPicker({
alwaysOpen: true,
mapContainer: "#fixedMapCont"
});
</script>
<div id="copy"><a href="https://opengeo.tech/">Opengeo.tech</a> &bull; <a rel="author" href="https://opengeo.tech/stefano-cudini/">Stefano Cudini</a></div>
<script src="/labs-common.js"></script>
</body>
</html>

View File

@@ -0,0 +1,102 @@
body {
background:#b5d0d0;
color:#285585;
font-family:Arial;
}
body#home {
background:url('images/leaflet-panel.png') no-repeat top left #b5d0d0;
margin-left:200px;
}
a {
color:#1978cf;
}
a:hover {
color:#fff;
}
h2, h3, h4 {
white-space:nowrap;
margin:1em 0 0 0;
}
h3 a,
h3 a:hover {
text-decoration:none;
}
#desc {
float: left;
margin-bottom: 1em;
position: relative;
white-space:nowrap;
font-size:1em;
}
#map {
border:2px solid #1978cf;
box-shadow: 0 0 8px #999;
float:left;
width:800px;
height:400px;
}
label {
float: left;
clear: both;
}
pre {
font-family: "Courier New";
font-size: .85em;
color: #333;
float: left;
clear: both;
padding: 10px;
margin: 10px 0;
background-color: #fff;
box-shadow: inset 2px 2px 3px rgba(100,100,100,0.2);
border: 1px solid #ccc;
}
#copy {
position:fixed;
z-index:1000;
right:150px;
top:-8px;
font-size:.85em;
padding:8px 8px 2px 8px;
background: #323b44;
border: 2px solid #737c85;
border-radius:.7em;
opacity: 0.9;
box-shadow:0 0 8px #5f7182;
color:#eee
}
#copy a {
color:#ccc;
text-decoration:none
}
#copy a:hover {
color:#fff
}
#ribbon {
position: absolute;
top: 0;
right: 0;
border: 0;
filter: alpha(opacity=80);
-khtml-opacity: .8;
-moz-opacity: .8;
opacity: .8;
}
#comments {
margin-top:50px;
clear:both;
}
form {
margin: 20px;
padding: 20px;
background: #eee;
float: left;
min-height: 160px;
min-width: 400px
}
input {
margin: 5px 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,178 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<title>leaflet locationpicker</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
body {
background:#F2F9FF;
color:#666;
font-family:Arial;
}
a {
color:#f80;
text-decoration:none;
}
a:hover {
color:#635f94;
text-decoration:underline;
}
h1, h2, h3, h4 {
text-transform: capitalize;
white-space:nowrap;
margin: 0 0 .25em 0;
}
h4 {
color: #A1A8AD;
}
#desc {
float: left;
margin-bottom: 1em;
position: relative;
white-space:nowrap;
font-size:1em;
}
.box {
float: left;
min-width: 200px;
margin-right: 20px;
background: #fff;
padding:8px;
border:2px solid #c5cdd4;
border-radius:.45em;
box-shadow: 0 0 16px rgba(100,100,100,0.2);
}
.screenshot {
margin: 20px 20px 20px 0;
float: left;
clear: both;
background: #fff;
box-shadow: 0 0 10px rgba(120,120,120,0.2);
padding: 8px;
}
ul {
font-size:.85em;
margin:0;
padding:0;
}
li {
margin:0 0 2px 18px;
}
#copy {
position:fixed;
z-index:1000;
right:150px;
top:-8px;
font-size:.85em;
padding:8px 8px 2px 8px;
background: #eee;
border: 2px solid #bbb;
border-radius:.7em;
opacity: 0.9;
box-shadow:0 0 8px #aaa;
font-weight: bold;
color:#bbb;
}
#copy a {
color:#888;
text-decoration:none
}
#copy a:hover {
color:#f80
}
#ribbon {
position: absolute;
top: 0;
right: 0;
border: 0;
filter: alpha(opacity=80);
-khtml-opacity: .8;
-moz-opacity: .8;
opacity: .8;
}
</style>
</head>
<body id="home">
<h1>leaflet locationpicker</h1>
<div id="desc">
Simple location picker with Leaflet map
<div style="position:absolute;top:0;right:-120px">
<iframe src="http://ghbtns.com/github-btn.html?user=stefanocudini&amp;repo=leaflet-locationpicker&amp;type=watch&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="104px" height="20px"></iframe>
</div>
</div>
<div style="clear:both"></div>
<div class="box">
<h4>Features</h4>
<ul id="ff">
<li>Custom location format, lat,lon separator and precision</li>
<li>Pick Location Latidute,Longitude clicking on map</li>
<li>Bind multiple events or single picker callback</li>
<li>Load picker map from preselected location</li>
<li>Bind callback on location picked</li>
<li>Enable disable location marker</li>
<li>Custom map baselayer</li>
</ul>
</div>
<div class="box">
<h4>Code repositories</h4>
<a target="_blank" href="https://github.com/stefanocudini/leaflet-locationpicker">Github.com</a>
<br />
<a target="_blank" href="https://npmjs.org/package/leaflet-locationpicker">Node Packaged Module</a>
<br />
<h4>Homepage</h4>
<a href="https://opengeo.tech/maps/leaflet-locationpicker/">https://opengeo.tech/maps/leaflet-locationpicker/</a>
<br />
<h4>Download</h4>
<ul>
<li><a href="https://github.com/stefanocudini/leaflet-locationpicker/archive/master.zip">Dev Pack (.zip)</a></li>
</ul>
</div>
<div class="box">
<h4>Examples</h4>
<ul id="examples">
<li><a href="examples/simple.html">examples/simple.html</a></li>
</ul>
</div>
<div class="screenshot">
<img src="images/leaflet-locationpicker.png" />
</div>
<div id="copy"><a href="https://opengeo.tech/">Opengeo.tech</a> &bull; &copy;<a rel="author" href="https://opengeo.tech/stefano-cudini/">Stefano Cudini</a></div>
<a href="https://github.com/stefanocudini/leaflet-locationpicker"><img id="ribbon" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"></a>
<div style="clear:both;font-size:.85em;margin-bottom:1em">
<b>For questions and bugs</b> I recommend you to <a href="https://github.com/stefanocudini/leaflet-locationpicker/issues">create New Issue</a> on Github repository.</strong><br />
<br />
This is a micro discussion area for methods of implementation.<br />
</div>
<div id="comments">
<div id="disqus_thread"></div>
</div>
<script type="text/javascript" src="/labs-common.js"></script>
</body>
</html>

View File

@@ -0,0 +1,163 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<title><%=title%></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
body {
background:#F2F9FF;
color:#666;
font-family:Arial;
}
a {
color:#f80;
text-decoration:none;
}
a:hover {
color:#635f94;
text-decoration:underline;
}
h1, h2, h3, h4 {
text-transform: capitalize;
white-space:nowrap;
margin: 0 0 .25em 0;
}
h4 {
color: #A1A8AD;
}
#desc {
float: left;
margin-bottom: 1em;
position: relative;
white-space:nowrap;
font-size:1em;
}
.box {
float: left;
min-width: 200px;
margin-right: 20px;
background: #fff;
padding:8px;
border:2px solid #c5cdd4;
border-radius:.45em;
box-shadow: 0 0 16px rgba(100,100,100,0.2);
}
.screenshot {
margin: 20px 20px 20px 0;
float: left;
clear: both;
background: #fff;
box-shadow: 0 0 10px rgba(120,120,120,0.2);
padding: 8px;
}
ul {
font-size:.85em;
margin:0;
padding:0;
}
li {
margin:0 0 2px 18px;
}
#copy {
position:fixed;
z-index:1000;
right:150px;
top:-8px;
font-size:.85em;
padding:8px 8px 2px 8px;
background: #eee;
border: 2px solid #bbb;
border-radius:.7em;
opacity: 0.9;
box-shadow:0 0 8px #aaa;
font-weight: bold;
color:#bbb;
}
#copy a {
color:#888;
text-decoration:none
}
#copy a:hover {
color:#f80
}
#ribbon {
position: absolute;
top: 0;
right: 0;
border: 0;
filter: alpha(opacity=80);
-khtml-opacity: .8;
-moz-opacity: .8;
opacity: .8;
}
</style>
</head>
<body id="home">
<h1><%=title%></h1>
<div id="desc">
<%=pkg.description%>
<div style="position:absolute;top:0;right:-120px">
<iframe src="<%=ribbonurl%>" allowtransparency="true" frameborder="0" scrolling="0" width="104px" height="20px"></iframe>
</div>
</div>
<div style="clear:both"></div>
<div class="box">
<h4>Features</h4>
<ul id="ff">
<% _.forEach(features, function(f) { %>
<li><%- f%></li>
<% }); %>
</ul>
</div>
<div class="box">
<h4>Code repositories</h4>
<% _.forEach(sources, function(s) { %>
<a target="_blank" href="<%=s.url%>"><%- s.name%></a>
<br />
<% }); %>
<h4>Homepage</h4>
<a href="<%=pkg.homepage%>"><%=pkg.homepage%></a>
<br />
<h4>Download</h4>
<ul>
<li><a href="<%=giturl%>/archive/master.zip">Dev Pack (.zip)</a></li>
</ul>
</div>
<div class="box">
<h4>Examples</h4>
<ul id="examples">
<% _.forEach(examples, function(file) { %>
<li><a href="<%- file %>"><%- file%></a></li>
<% }); %>
</ul>
</div>
<div class="screenshot">
<img src="<%=image%>" />
</div>
<div id="copy"><a href="<%=pkg.author.url%>">Opengeo.tech</a> &bull; &copy;<a rel="author" href="https://opengeo.tech/stefano-cudini/"><%= pkg.author.name %></a></div>
<a href="<%=giturl%>"><img id="ribbon" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"></a>
<div style="clear:both;font-size:.85em;margin-bottom:1em">
<b>For questions and bugs</b> I recommend you to <a href="<%=giturl%>/issues">create New Issue</a> on Github repository.</strong><br />
<br />
This is a micro discussion area for methods of implementation.<br />
</div>
<div id="comments">
<div id="disqus_thread"></div>
</div>
<script type="text/javascript" src="/labs-common.js"></script>
</body>
</html>

View File

@@ -0,0 +1,23 @@
Copyright (c) 2010-2013, Vladimir Agafonkin
Copyright (c) 2010-2011, CloudMade
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,127 @@
# Leaflet Plugin Authoring Guide
One of the greatest things about Leaflet is its powerful plugin ecosystem.
The [Leaflet plugins page](http://leafletjs.com/plugins.html) lists dozens of awesome plugins, and more are being added every week.
This guide lists a number of best practices for publishing a Leaflet plugin that meets the quality standards of Leaflet itself.
1. [Presentation](#presentation)
- [Repository](#repository)
- [Name](#name)
- [Demo](#demo)
- [Readme](#readme)
- [License](#license)
2. [Code](#code)
- [File Structure](#file-structure)
- [Code Conventions](#code-conventions)
- [Plugin API](#plugin-api)
## Presentation
### Repository
The best place to put your Leaflet plugin to is a separate [GitHub](http://github.com) repository.
If you create a collection of plugins for different uses,
don't put them in one repo &mdash;
it's usually easier to work with small, self-contained plugins in individual repositories.
### Name
Most existing plugins follow the convention of naming plugins (and repos) like this: `Leaflet.MyPluginName`.
You can use other forms (e.g. "leaflet-my-plugin-name"),
just make sure to include the word "Leaflet" in the name so that it's obvious that it's a Leaflet plugin.
### Demo
The most essential thing to do when publishing a plugin is to include a demo that showcases what the plugin does &mdash;
it's usually the first thing people will look for.
The easiest way to put up a demo is using [GitHub Pages](http://pages.github.com/).
A good [starting point](https://help.github.com/articles/creating-project-pages-manually) is creating a `gh-pages` branch in your repo and adding an `index.html` page to it &mdash;
after pushing, it'll be published as `http://<user>.github.io/<repo>`.
### Readme
The next thing you need to have is a descriptive `README.md` in the root of the repo (or a link to a website with a similar content).
At a minimum it should contain the following items:
- name of the plugin
- a simple, concise description of what it does
- requirements
- Leaflet version
- other external dependencies (if any)
- browser / device compatibility
- links to demos
- instructions for including the plugin
- simple usage code example
- API reference (methods, options, events)
### License
Every open source repository should include a license.
If you don't know what open source license to choose for your code,
[MIT License](http://opensource.org/licenses/MIT) and [BSD 2-Clause License](http://opensource.org/licenses/BSD-2-Clause) are both good choices.
You can either put it in the repo as a `LICENSE` file or just link to the license from the Readme.
## Code
### File Structure
Keep the file structure clean and simple,
don't pile up lots of files in one place &mdash;
make it easy for a new person to find their way in your repo.
A barebones repo for a simple plugin would look like this:
```
my-plugin.js
README.md
```
An example of a more sophisticated plugin file structure:
```
/src - JS source files
/dist - minified plugin JS, CSS, images
/spec - test files
/lib - any external libraries/plugins if necessary
/examples - HTML examples of plugin usage
README.md
LICENSE
package.json
```
### Code Conventions
Everyone's tastes are different, but it's important to be consistent with whatever conventions you choose for your plugin.
For a good starting point, check out [Airbnb JavaScript Guide](https://github.com/airbnb/javascript).
Leaflet follows pretty much the same conventions
except for using smart tabs (hard tabs for indentation, spaces for alignment)
and putting a space after the `function` keyword.
### Plugin API
Never expose global variables in your plugin.<br>
If you have a new class, put it directly in the `L` namespace (`L.MyPlugin`).<br>
If you inherit one of the existing classes, make it a sub-property (`L.TileLayer.Banana`).<br>
If you want to add new methods to existing Leaflet classes, you can do it like this: `L.Marker.include({myPlugin: …})`.
Function, method and property names should be in `camelCase`.<br>
Class names should be in `CapitalizedCamelCase`.
If you have a lot of arguments in your function, consider accepting an options object instead
(putting default values where possible so that users don't need specify all of them):
```js
// bad
marker.myPlugin('bla', 'foo', null, {}, 5, 0);
// good
marker.myPlugin('bla', {
optionOne: 'foo',
optionThree: 5
});
```
And most importantly, keep it simple. Leaflet is all about *simplicity*.

View File

@@ -0,0 +1,34 @@
<img src="http://leafletjs.com/docs/images/logo.png" alt="Leaflet" />
Leaflet is an open source JavaScript library for **mobile-friendly interactive maps**.
It is developed by [Vladimir Agafonkin][] of [MapBox][] with a team of dedicated [contributors][].
Weighing just about 30 KB of gzipped JS code, it has all the [features][] most developers ever need for online maps.
Leaflet is designed with *simplicity*, *performance* and *usability* in mind.
It works efficiently across all major desktop and mobile platforms out of the box,
taking advantage of HTML5 and CSS3 on modern browsers while being accessible on older ones too.
It can be extended with a huge amount of [plugins][],
has a beautiful, easy to use and [well-documented][] API
and a simple, readable [source code][] that is a joy to [contribute][] to.
For more info, docs and tutorials, check out the [official website][].<br>
For **Leaflet downloads** (including the built master version), check out the [download page][].
We're happy to meet new contributors.
If you want to **get involved** with Leaflet development, check out the [contribution guide][contribute].
Let's make the best mapping library that will ever exist,
and push the limits of what's possible with online maps!
[![Build Status](https://travis-ci.org/Leaflet/Leaflet.png?branch=master)](https://travis-ci.org/Leaflet/Leaflet)
[Vladimir Agafonkin]: http://agafonkin.com/en
[contributors]: https://github.com/Leaflet/Leaflet/graphs/contributors
[features]: http://leafletjs.com/features.html
[plugins]: http://leafletjs.com/plugins.html
[well-documented]: http://leafletjs.com/reference.html "Leaflet API reference"
[source code]: https://github.com/Leaflet/Leaflet "Leaflet GitHub repository"
[hosted on GitHub]: http://github.com/Leaflet/Leaflet
[contribute]: https://github.com/Leaflet/Leaflet/blob/master/CONTRIBUTING.md "A guide to contributing to Leaflet"
[official website]: http://leafletjs.com
[download page]: http://leafletjs.com/download.html
[MapBox]: https://mapbox.com

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 797 B

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,479 @@
/* required styles */
.leaflet-map-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-pane,
.leaflet-tile-container,
.leaflet-overlay-pane,
.leaflet-shadow-pane,
.leaflet-marker-pane,
.leaflet-popup-pane,
.leaflet-overlay-pane svg,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
position: absolute;
left: 0;
top: 0;
}
.leaflet-container {
overflow: hidden;
-ms-touch-action: none;
touch-action: none;
}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-user-drag: none;
}
.leaflet-marker-icon,
.leaflet-marker-shadow {
display: block;
}
/* map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container img {
max-width: none !important;
}
/* stupid Android 2 doesn't understand "max-width: none" properly */
.leaflet-container img.leaflet-image-layer {
max-width: 15000px !important;
}
.leaflet-tile {
filter: inherit;
visibility: hidden;
}
.leaflet-tile-loaded {
visibility: inherit;
}
.leaflet-zoom-box {
width: 0;
height: 0;
}
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
.leaflet-overlay-pane svg {
-moz-user-select: none;
}
.leaflet-tile-pane { z-index: 2; }
.leaflet-objects-pane { z-index: 3; }
.leaflet-overlay-pane { z-index: 4; }
.leaflet-shadow-pane { z-index: 5; }
.leaflet-marker-pane { z-index: 6; }
.leaflet-popup-pane { z-index: 7; }
.leaflet-vml-shape {
width: 1px;
height: 1px;
}
.lvml {
behavior: url(#default#VML);
display: inline-block;
position: absolute;
}
/* control positioning */
.leaflet-control {
position: relative;
z-index: 7;
pointer-events: auto;
}
.leaflet-top,
.leaflet-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.leaflet-top {
top: 0;
}
.leaflet-right {
right: 0;
}
.leaflet-bottom {
bottom: 0;
}
.leaflet-left {
left: 0;
}
.leaflet-control {
float: left;
clear: both;
}
.leaflet-right .leaflet-control {
float: right;
}
.leaflet-top .leaflet-control {
margin-top: 10px;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 10px;
}
.leaflet-left .leaflet-control {
margin-left: 10px;
}
.leaflet-right .leaflet-control {
margin-right: 10px;
}
/* zoom and fade animations */
.leaflet-fade-anim .leaflet-tile,
.leaflet-fade-anim .leaflet-popup {
opacity: 0;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
-o-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-tile-loaded,
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
-o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile,
.leaflet-touching .leaflet-zoom-animated {
-webkit-transition: none;
-moz-transition: none;
-o-transition: none;
transition: none;
}
.leaflet-zoom-anim .leaflet-zoom-hide {
visibility: hidden;
}
/* cursors */
.leaflet-clickable {
cursor: pointer;
}
.leaflet-container {
cursor: -webkit-grab;
cursor: -moz-grab;
}
.leaflet-popup-pane,
.leaflet-control {
cursor: auto;
}
.leaflet-dragging .leaflet-container,
.leaflet-dragging .leaflet-clickable {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
}
/* visual tweaks */
.leaflet-container {
background: #ddd;
outline: 0;
}
.leaflet-container a {
color: #0078A8;
}
.leaflet-container a.leaflet-active {
outline: 2px solid orange;
}
.leaflet-zoom-box {
border: 2px dotted #38f;
background: rgba(255,255,255,0.5);
}
/* general typography */
.leaflet-container {
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
}
/* general toolbar styles */
.leaflet-bar {
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px;
}
.leaflet-bar a,
.leaflet-bar a:hover {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
height: 26px;
line-height: 26px;
display: block;
text-align: center;
text-decoration: none;
color: black;
}
.leaflet-bar a,
.leaflet-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.leaflet-bar a:hover {
background-color: #f4f4f4;
}
.leaflet-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.leaflet-bar a:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.leaflet-bar a.leaflet-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
.leaflet-touch .leaflet-bar a {
width: 30px;
height: 30px;
line-height: 30px;
}
/* zoom control */
.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
font: bold 18px 'Lucida Console', Monaco, monospace;
text-indent: 1px;
}
.leaflet-control-zoom-out {
font-size: 20px;
}
.leaflet-touch .leaflet-control-zoom-in {
font-size: 22px;
}
.leaflet-touch .leaflet-control-zoom-out {
font-size: 24px;
}
/* layers control */
.leaflet-control-layers {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #fff;
border-radius: 5px;
}
.leaflet-control-layers-toggle {
background-image: url(images/layers.png);
width: 36px;
height: 36px;
}
.leaflet-retina .leaflet-control-layers-toggle {
background-image: url(images/layers-2x.png);
background-size: 26px 26px;
}
.leaflet-touch .leaflet-control-layers-toggle {
width: 44px;
height: 44px;
}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
display: none;
}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
display: block;
position: relative;
}
.leaflet-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.leaflet-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.leaflet-control-layers label {
display: block;
}
.leaflet-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}
/* attribution and scale controls */
.leaflet-container .leaflet-control-attribution {
background: #fff;
background: rgba(255, 255, 255, 0.7);
margin: 0;
}
.leaflet-control-attribution,
.leaflet-control-scale-line {
padding: 0 5px;
color: #333;
}
.leaflet-control-attribution a {
text-decoration: none;
}
.leaflet-control-attribution a:hover {
text-decoration: underline;
}
.leaflet-container .leaflet-control-attribution,
.leaflet-container .leaflet-control-scale {
font-size: 11px;
}
.leaflet-left .leaflet-control-scale {
margin-left: 5px;
}
.leaflet-bottom .leaflet-control-scale {
margin-bottom: 5px;
}
.leaflet-control-scale-line {
border: 2px solid #777;
border-top: none;
line-height: 1.1;
padding: 2px 5px 1px;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
-moz-box-sizing: content-box;
box-sizing: content-box;
background: #fff;
background: rgba(255, 255, 255, 0.5);
}
.leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
box-shadow: none;
}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
/* popup */
.leaflet-popup {
position: absolute;
text-align: center;
}
.leaflet-popup-content-wrapper {
padding: 1px;
text-align: left;
border-radius: 12px;
}
.leaflet-popup-content {
margin: 13px 19px;
line-height: 1.4;
}
.leaflet-popup-content p {
margin: 18px 0;
}
.leaflet-popup-tip-container {
margin: 0 auto;
width: 40px;
height: 20px;
position: relative;
overflow: hidden;
}
.leaflet-popup-tip {
width: 17px;
height: 17px;
padding: 1px;
margin: -10px auto 0;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: white;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
}
.leaflet-container a.leaflet-popup-close-button {
position: absolute;
top: 0;
right: 0;
padding: 4px 4px 0 0;
text-align: center;
width: 18px;
height: 14px;
font: 16px/14px Tahoma, Verdana, sans-serif;
color: #c3c3c3;
text-decoration: none;
font-weight: bold;
background: transparent;
}
.leaflet-container a.leaflet-popup-close-button:hover {
color: #999;
}
.leaflet-popup-scrolled {
overflow: auto;
border-bottom: 1px solid #ddd;
border-top: 1px solid #ddd;
}
.leaflet-oldie .leaflet-popup-content-wrapper {
zoom: 1;
}
.leaflet-oldie .leaflet-popup-tip {
width: 24px;
margin: 0 auto;
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
}
.leaflet-oldie .leaflet-popup-tip-container {
margin-top: -1px;
}
.leaflet-oldie .leaflet-control-zoom,
.leaflet-oldie .leaflet-control-layers,
.leaflet-oldie .leaflet-popup-content-wrapper,
.leaflet-oldie .leaflet-popup-tip {
border: 1px solid #999;
}
/* div icon */
.leaflet-div-icon {
background: #fff;
border: 1px solid #666;
}

File diff suppressed because one or more lines are too long