diff --git a/EgwCoreLib.BlazorTest/Pages/TestLoading.razor b/EgwCoreLib.BlazorTest/Pages/TestLoading.razor
new file mode 100644
index 0000000..9e66ea2
--- /dev/null
+++ b/EgwCoreLib.BlazorTest/Pages/TestLoading.razor
@@ -0,0 +1,14 @@
+@page "/TestLoading"
+
+
-
-
loading data
-
+@if (DisplaySize == CtrlSize.Small)
+{
+
+
+
+
+ loading data
+
+ @if (DisplayMode == SpinMode.Normal)
+ {
+
+ }
+ else if (DisplayMode == SpinMode.Growl)
+ {
+
+ Loading...
+
+ }
+ else
+ {
+
+ }
+
+
-
\ No newline at end of file
+}
+else if (DisplaySize == CtrlSize.Normal)
+{
+
+
+
loading data
+ @if (DisplayMode == SpinMode.Normal)
+ {
+
+ }
+ else if (DisplayMode == SpinMode.Growl)
+ {
+
+ Loading...
+
+ }
+ else
+ {
+
+ }
+
+
+}
+else if (DisplaySize == CtrlSize.Large)
+{
+
+
+
+
loading data
+ @if (DisplayMode == SpinMode.Normal)
+ {
+
+ }
+ else if (DisplayMode == SpinMode.Growl)
+ {
+
+ Loading...
+
+ }
+ else
+ {
+
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/EgwCoreLib.Razor/LoadingData.razor.cs b/EgwCoreLib.Razor/LoadingData.razor.cs
new file mode 100644
index 0000000..60b8647
--- /dev/null
+++ b/EgwCoreLib.Razor/LoadingData.razor.cs
@@ -0,0 +1,50 @@
+using Microsoft.AspNetCore.Components;
+
+namespace EgwCoreLib.Razor
+{
+ public partial class LoadingData
+ {
+ #region Public Enums
+
+ public enum CtrlSize
+ {
+ Normal,
+ Small,
+ Large
+ }
+
+ public enum SpinMode
+ {
+ Normal,
+ Growl,
+ BounceLine
+ }
+
+ #endregion Public Enums
+
+ #region Public Properties
+
+ ///
+ /// Modalità display principale
+ /// default: alert alert-primary
+ ///
+ [Parameter]
+ public string DisplayCss { get; set; } = "alert alert-primary";
+
+ ///
+ /// Modalità animazione
+ /// default: Normal
+ ///
+ [Parameter]
+ public SpinMode DisplayMode { get; set; } = SpinMode.Normal;
+
+ ///
+ /// Dimensione display
+ /// default: Normal
+ ///
+ [Parameter]
+ public CtrlSize DisplaySize { get; set; } = CtrlSize.Normal;
+
+ #endregion Public Properties
+ }
+}
\ No newline at end of file
diff --git a/EgwCoreLib.Razor/LoadingData.razor.css b/EgwCoreLib.Razor/LoadingData.razor.css
new file mode 100644
index 0000000..5530d10
--- /dev/null
+++ b/EgwCoreLib.Razor/LoadingData.razor.css
@@ -0,0 +1,126 @@
+.modalOrd {
+ position: relative;
+ z-index: 9999;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ background-color: #000000;
+ background-color: rgba(0, 0, 0, 0.6);
+}
+.loader {
+ width: 5rem;
+ position: relative;
+}
+.loader-text {
+ position: relative;
+ top: 0;
+ padding: 0;
+ margin: 0;
+ color: #C8B6FF;
+ animation: text_713 3.5s ease both infinite;
+ font-size: 0.8rem;
+ letter-spacing: 1px;
+}
+.load {
+ background-color: #9A79FF;
+ border-radius: 3rem;
+ display: block;
+ height: 1rem;
+ width: 1rem;
+ bottom: 0;
+ position: relative;
+ transform: translateX(64px);
+ animation: loading_713 3.5s ease both infinite;
+}
+.load::before {
+ position: relative;
+ content: "";
+ width: 100%;
+ height: 100%;
+ background-color: #D1C2FF;
+ border-radius: inherit;
+ animation: loading2_713 3.5s ease both infinite;
+}
+@keyframes text_713 {
+ 0% {
+ letter-spacing: 1px;
+ transform: translateX(0px);
+ }
+ 40% {
+ letter-spacing: 2px;
+ transform: translateX(26px);
+ }
+ 80% {
+ letter-spacing: 1px;
+ transform: translateX(32px);
+ }
+ 90% {
+ letter-spacing: 2px;
+ transform: translateX(0px);
+ }
+ 100% {
+ letter-spacing: 1px;
+ transform: translateX(0px);
+ }
+}
+@keyframes loading_713 {
+ 0% {
+ width: 16px;
+ transform: translateX(0px);
+ }
+ 40% {
+ width: 100%;
+ transform: translateX(0px);
+ }
+ 80% {
+ width: 16px;
+ transform: translateX(64px);
+ }
+ 90% {
+ width: 100%;
+ transform: translateX(0px);
+ }
+ 100% {
+ width: 16px;
+ transform: translateX(0px);
+ }
+}
+@keyframes loading2_713 {
+ 0% {
+ transform: translateX(0px);
+ width: 16px;
+ }
+ 40% {
+ transform: translateX(0%);
+ width: 80%;
+ }
+ 80% {
+ width: 100%;
+ transform: translateX(0px);
+ }
+ 90% {
+ width: 80%;
+ transform: translateX(15px);
+ }
+ 100% {
+ transform: translateX(0px);
+ width: 16px;
+ }
+}
+/* Modal Content/Box */
+.modalOrd-content-small {
+ margin: 0.4rem auto;
+ width: 50%;
+}
+.modalOrd-content {
+ margin: 1.4rem auto;
+ padding-left: 20%;
+ width: 50%;
+}
+.modalOrd-content-large {
+ margin: 2.4rem auto;
+ padding-left: 20%;
+ width: 50%;
+}
\ No newline at end of file
diff --git a/EgwCoreLib.Razor/LoadingData.razor.less b/EgwCoreLib.Razor/LoadingData.razor.less
new file mode 100644
index 0000000..018a6f2
--- /dev/null
+++ b/EgwCoreLib.Razor/LoadingData.razor.less
@@ -0,0 +1,147 @@
+.modalOrd {
+ position: relative;
+ z-index: 9999;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ background-color: rgb(0,0,0);
+ background-color: rgba(0,0,0,0.6);
+}
+
+
+.loader {
+ width: 5rem;
+ position: relative;
+}
+
+.loader-text {
+ position: relative;
+ top: 0;
+ padding: 0;
+ margin: 0;
+ color: #C8B6FF;
+ animation: text_713 3.5s ease both infinite;
+ font-size: .8rem;
+ letter-spacing: 1px;
+}
+
+.load {
+ background-color: #9A79FF;
+ border-radius: 3rem;
+ display: block;
+ height: 1rem;
+ width: 1rem;
+ bottom: 0;
+ position: relative;
+ transform: translateX(64px);
+ animation: loading_713 3.5s ease both infinite;
+}
+
+.load::before {
+ position: relative;
+ content: "";
+ width: 100%;
+ height: 100%;
+ background-color: #D1C2FF;
+ border-radius: inherit;
+ animation: loading2_713 3.5s ease both infinite;
+}
+
+@keyframes text_713 {
+ 0% {
+ letter-spacing: 1px;
+ transform: translateX(0px);
+ }
+
+ 40% {
+ letter-spacing: 2px;
+ transform: translateX(26px);
+ }
+
+ 80% {
+ letter-spacing: 1px;
+ transform: translateX(32px);
+ }
+
+ 90% {
+ letter-spacing: 2px;
+ transform: translateX(0px);
+ }
+
+ 100% {
+ letter-spacing: 1px;
+ transform: translateX(0px);
+ }
+}
+
+@keyframes loading_713 {
+ 0% {
+ width: 16px;
+ transform: translateX(0px);
+ }
+
+ 40% {
+ width: 100%;
+ transform: translateX(0px);
+ }
+
+ 80% {
+ width: 16px;
+ transform: translateX(64px);
+ }
+
+ 90% {
+ width: 100%;
+ transform: translateX(0px);
+ }
+
+ 100% {
+ width: 16px;
+ transform: translateX(0px);
+ }
+}
+
+@keyframes loading2_713 {
+ 0% {
+ transform: translateX(0px);
+ width: 16px;
+ }
+
+ 40% {
+ transform: translateX(0%);
+ width: 80%;
+ }
+
+ 80% {
+ width: 100%;
+ transform: translateX(0px);
+ }
+
+ 90% {
+ width: 80%;
+ transform: translateX(15px);
+ }
+
+ 100% {
+ transform: translateX(0px);
+ width: 16px;
+ }
+}
+
+/* Modal Content/Box */
+.modalOrd-content-small {
+ margin: 0.4rem auto;
+ width: 50%;
+}
+.modalOrd-content {
+ margin: 1.4rem auto;
+ padding-left: 20%;
+ width: 50%;
+}
+.modalOrd-content-large {
+ margin: 2.4rem auto;
+ padding-left: 20%;
+ width: 50%;
+}
diff --git a/EgwCoreLib.Razor/LoadingData.razor.min.css b/EgwCoreLib.Razor/LoadingData.razor.min.css
new file mode 100644
index 0000000..ce1a088
--- /dev/null
+++ b/EgwCoreLib.Razor/LoadingData.razor.min.css
@@ -0,0 +1 @@
+.modalOrd{position:relative;z-index:9999;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:#000;background-color:rgba(0,0,0,.6);}.loader{width:5rem;position:relative;}.loader-text{position:relative;top:0;padding:0;margin:0;color:#c8b6ff;animation:text_713 3.5s ease both infinite;font-size:.8rem;letter-spacing:1px;}.load{background-color:#9a79ff;border-radius:3rem;display:block;height:1rem;width:1rem;bottom:0;position:relative;transform:translateX(64px);animation:loading_713 3.5s ease both infinite;}.load::before{position:relative;content:"";width:100%;height:100%;background-color:#d1c2ff;border-radius:inherit;animation:loading2_713 3.5s ease both infinite;}@keyframes text_713{0%{letter-spacing:1px;transform:translateX(0);}40%{letter-spacing:2px;transform:translateX(26px);}80%{letter-spacing:1px;transform:translateX(32px);}90%{letter-spacing:2px;transform:translateX(0);}100%{letter-spacing:1px;transform:translateX(0);}}@keyframes loading_713{0%{width:16px;transform:translateX(0);}40%{width:100%;transform:translateX(0);}80%{width:16px;transform:translateX(64px);}90%{width:100%;transform:translateX(0);}100%{width:16px;transform:translateX(0);}}@keyframes loading2_713{0%{transform:translateX(0);width:16px;}40%{transform:translateX(0%);width:80%;}80%{width:100%;transform:translateX(0);}90%{width:80%;transform:translateX(15px);}100%{transform:translateX(0);width:16px;}}.modalOrd-content-small{margin:.4rem auto;width:50%;}.modalOrd-content{margin:1.4rem auto;padding-left:20%;width:50%;}.modalOrd-content-large{margin:2.4rem auto;padding-left:20%;width:50%;}
\ No newline at end of file
diff --git a/EgwCoreLib.Razor/ProgressDisplay.razor b/EgwCoreLib.Razor/ProgressDisplay.razor
new file mode 100644
index 0000000..988f338
--- /dev/null
+++ b/EgwCoreLib.Razor/ProgressDisplay.razor
@@ -0,0 +1,32 @@
+@if (isLoading)
+{
+
+}
\ No newline at end of file
diff --git a/EgwCoreLib.Razor/ProgressDisplay.razor.cs b/EgwCoreLib.Razor/ProgressDisplay.razor.cs
new file mode 100644
index 0000000..db4435b
--- /dev/null
+++ b/EgwCoreLib.Razor/ProgressDisplay.razor.cs
@@ -0,0 +1,223 @@
+using Microsoft.AspNetCore.Components;
+
+namespace EgwCoreLib.Razor
+{
+ public partial class ProgressDisplay : IDisposable
+ {
+ #region Public Enums
+
+ public enum ModalSize
+ {
+ Small,
+ Medium,
+ Large
+ }
+
+ #endregion Public Enums
+
+ #region Public Properties
+
+ ///
+ /// Valore corrente
+ ///
+ [Parameter]
+ public double CurrVal
+ {
+ get => actVal;
+ set
+ {
+ actVal = value;
+ startVal = value;
+ isLoading = actVal < MaxVal;
+ }
+ }
+
+ ///
+ /// Dimensioni attese modale
+ /// default: ModalSize.Medium
+ ///
+ [Parameter]
+ public ModalSize DisplaySize { get; set; } = ModalSize.Medium;
+
+ ///
+ /// Tempo atteso per prossimo step
+ /// default: 10000
+ ///
+ [Parameter]
+ public int ExpTimeMSec { get; set; } = 10000;
+
+ ///
+ /// Valore massimo ammesso
+ /// default: 100
+ ///
+ [Parameter]
+ public double MaxVal { get; set; } = 100;
+
+ ///
+ /// Style modale
+ /// default: card
+ /// alternative: card alert-primary
+ ///
+ [Parameter]
+ public string ModalCss { get; set; } = "card";
+
+ ///
+ /// Prossimo valore ammesso (fino al max)
+ /// default: 100
+ ///
+ [Parameter]
+ public double NextVal { get; set; } = 100;
+
+ ///
+ /// Style progressbar
+ /// default: progress-bar progress-bar-striped progress-bar-animated
+ ///
+ [Parameter]
+ public string ProgressCss { get; set; } = "progress-bar progress-bar-striped progress-bar-animated";
+
+ ///
+ /// Intervallo interno per refresh percentuale avanzamento
+ /// default: 100ms
+ ///
+ [Parameter]
+ public int RefreshInterval { get; set; } = 100;
+
+ ///
+ /// Indica se mostrare la percentuale vanzamento
+ /// default: true
+ ///
+ [Parameter]
+ public bool ShowPercent { get; set; } = true;
+
+ ///
+ /// Numero di secondi prima (rispetto valore ExpTimeMsec) da cui iniziare rallentamento
+ ///
+ [Parameter]
+ public int SlowWindowMSec { get; set; } = 3000;
+
+ //Titolo da mostrare (se "" NON lo mostra)
+ [Parameter]
+ public string Title { get; set; } = "Progress";
+
+ #endregion Public Properties
+
+ #region Public Methods
+
+ public void Dispose()
+ {
+ uiTimer?.Dispose();
+ }
+
+ #endregion Public Methods
+
+ #region Protected Properties
+
+ protected string modalDialogCss
+ {
+ get
+ {
+ string answ = "modal-dialog";
+ switch (DisplaySize)
+ {
+ case ModalSize.Small:
+ answ = "modal-dialog modal-sm";
+ break;
+
+ case ModalSize.Large:
+ answ = "modal-dialog modal-xl";
+ break;
+
+ case ModalSize.Medium:
+ default:
+ break;
+ }
+ return answ;
+ }
+ }
+
+ #endregion Protected Properties
+
+ #region Protected Methods
+
+ protected override async Task OnParametersSetAsync()
+ {
+ // salvo valori aggiornamento...
+ if (ExpTimeMSec > 0)
+ {
+ lastUpdate = DateTime.Now;
+ nextUpdate = lastUpdate.AddMilliseconds(ExpTimeMSec);
+ await RefreshDisplay();
+ }
+ if (isLoading)
+ {
+ uiTimer?.Dispose();
+ uiTimer = new PeriodicTimer(TimeSpan.FromMilliseconds(RefreshInterval));
+ RunTimer();
+ }
+ else
+ {
+ uiTimer = null;
+ }
+ }
+
+ #endregion Protected Methods
+
+ #region Private Fields
+
+ private PeriodicTimer? uiTimer = null;
+
+ #endregion Private Fields
+
+ #region Private Properties
+
+ private double actVal { get; set; } = 100;
+ private string currWidth { get; set; } = "";
+ private string displayMsg { get; set; } = "Loading...";
+
+ private bool isLoading { get; set; } = false;
+
+ private DateTime lastUpdate { get; set; } = DateTime.Now.AddMinutes(-1);
+
+ private DateTime nextUpdate { get; set; } = DateTime.Now;
+
+ private double startVal { get; set; } = 100;
+
+ #endregion Private Properties
+
+ #region Private Methods
+
+ private async Task RefreshDisplay()
+ {
+ currWidth = $"{(double)actVal / MaxVal:P0}";
+ if (ShowPercent)
+ {
+ displayMsg = $"{actVal / MaxVal:P2}";
+ }
+ await InvokeAsync(StateHasChanged);
+ }
+
+ private async void RunTimer()
+ {
+ while (uiTimer != null && await uiTimer.WaitForNextTickAsync())
+ {
+ if (isLoading)
+ {
+ DateTime adesso = DateTime.Now;
+ if (nextUpdate <= adesso.AddMilliseconds(SlowWindowMSec))
+ {
+ nextUpdate = adesso.AddMilliseconds(RefreshInterval);
+ }
+ // calcolo delta ms...
+ var numMs = adesso.Subtract(lastUpdate).TotalMilliseconds;
+ var denMs = nextUpdate.Subtract(lastUpdate).TotalMilliseconds;
+ denMs = denMs > 0 ? denMs : 1;
+ // aggiorno display...
+ actVal = startVal + (NextVal - startVal) * (numMs / denMs);
+ await RefreshDisplay();
+ }
+ }
+ }
+
+ #endregion Private Methods
+ }
+}
\ No newline at end of file
diff --git a/EgwCoreLib.Razor/compilerconfig.json b/EgwCoreLib.Razor/compilerconfig.json
index 3aa4469..47adeac 100644
--- a/EgwCoreLib.Razor/compilerconfig.json
+++ b/EgwCoreLib.Razor/compilerconfig.json
@@ -22,5 +22,9 @@
{
"outputFile": "CalWeekColumn.razor.css",
"inputFile": "CalWeekColumn.razor.less"
+ },
+ {
+ "outputFile": "LoadingData.razor.css",
+ "inputFile": "LoadingData.razor.less"
}
]
\ No newline at end of file