@@ -21,45 +23,66 @@
@code {
private bool _isVisible = false;
- private bool IsVisible
- {
- get => _isVisible;
- set
- {
- if (value != _isVisible)
- {
- _isVisible = value;
- StateHasChanged();
- }
- }
- }
protected override async Task OnInitializedAsync()
{
+ WriteDiag("Component initialized...");
+
await _scrollHandler.RegisterPageScrollAsync(async (e) =>
{
var scrollSize = await _scrollHandler.GetPageScrollSizeAsync();
var percentage = (e.Y / scrollSize.Y) * 100;
- IsVisible = percentage >= VisibleFromPagePercentage;
+ var visible = percentage >= VisibleFromPagePercentage;
+ if (visible != _isVisible)
+ {
+ _isVisible = visible;
+ StateHasChanged();
+
+ WriteDiag($"Component visibilit changed visible: {_isVisible}.");
+ }
});
}
+ private ElementReference _inputRef;
///
- ///
+ /// Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+ ///
+ public ElementReference InnerElementReference => _inputRef;
+
+ ///
+ /// HTML Content of the scroll panel.
///
[Parameter] public RenderFragment Content { get; set; }
///
- ///
+ /// Element should be visible when scroll reached page % of given value.
///
[Parameter] public byte VisibleFromPagePercentage { get; set; } = 30;
///
- ///
+ /// Scroll shold be jump or smoothly scroll.
///
[Parameter] public bool SmootScroll { get; set; } = true;
+ ///
+ /// Required space from page bottom in px.
+ ///
+ [Parameter] public int PaddingFromBottom { get; set; } = 20;
+ ///
+ /// Required space from page (left/right) side in px.
+ ///
+ [Parameter] public int PaddingFromSide { get; set; } = 24;
+ ///
+ /// Element orientation on page.
+ ///
+ [Parameter] public PageScrollHorizontalOrientation HorizontalOrientation { get; set; } = PageScrollHorizontalOrientation.Right;
+
+
+ private void WriteDiag(string message)
+ {
+ _logger.LogDebug($"Component {this.GetType()}: {message}");
+ }
public async ValueTask DisposeAsync()
{
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.css b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.css
new file mode 100644
index 00000000..ab507144
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.css
@@ -0,0 +1,6 @@
+.scrollToPageTop {
+ position: fixed;
+ z-index: 20;
+ cursor: pointer;
+ transition: opacity 0.25s linear;
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.min.css b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.min.css
new file mode 100644
index 00000000..dbcc64b4
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.min.css
@@ -0,0 +1 @@
+.scrollToPageTop{position:fixed;z-index:20;cursor:pointer;transition:opacity .25s linear}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/bundleconfig.json b/src/Majorsoft.Blazor.Components.Common.JsInterop/bundleconfig.json
index 24d82cd4..48ca414e 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/bundleconfig.json
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/bundleconfig.json
@@ -58,5 +58,11 @@
"inputFiles": [
"wwwroot/head.js"
]
+ },
+ {
+ "outputFileName": "Scroll/ScrollToPageTop.razor.min.css",
+ "inputFiles": [
+ "Scroll/ScrollToPageTop.razor.css"
+ ]
}
]
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JSInterop.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JSInterop.razor
index 25bbe4d1..f357bc21 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JSInterop.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JSInterop.razor
@@ -14,24 +14,11 @@
Majorsoft.Blazor.Components.Common.JsInterop package is available on Nuget
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+@*Scroll to page end with ScrollHandler for custom floating component see ScrollToPageBottom*@
+
+Smooth scroll:
+
JS Interop features:
@@ -70,7 +57,10 @@
-
+@*Scroll to page end with ScrollHandler for custom floating component see ScrollToPageTop*@
+
+Smooth scroll:
+
@implements IAsyncDisposable
@inject IScrollHandler _scrollHandler
@@ -83,4 +73,6 @@
await _scrollHandler.DisposeAsync();
}
}
+
+ private bool _smmothScroll = true;
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
index 2a6ebd63..c2f567dd 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
@@ -1,4 +1,21 @@
-
+@*Scroll on page components, can be placed anywhere on a page but should be used one per page*@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Scroll JS
From 33f753f8a70904de161921b51ad434754d2f8e38 Mon Sep 17 00:00:00 2001
From: Major
Date: Sun, 28 Mar 2021 13:42:52 +0200
Subject: [PATCH 08/69] Implemented ScrollToPageBottom component.
---
...oft.Blazor.Components.Common.JsInterop.xml | 34 +++++++-
.../Scroll/ScrollToPageBottom.razor | 81 +++++++++++++++----
.../Scroll/ScrollToPageBottom.razor.css | 7 ++
.../Scroll/ScrollToPageBottom.razor.min.css | 1 +
.../Scroll/ScrollToPageTop.razor | 2 +-
.../Scroll/ScrollToPageTop.razor.css | 1 +
.../Scroll/ScrollToPageTop.razor.min.css | 2 +-
.../bundleconfig.json | 6 ++
8 files changed, 114 insertions(+), 20 deletions(-)
create mode 100644 src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor.css
create mode 100644 src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor.min.css
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml b/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml
index 94211681..c193d8a7 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml
@@ -807,14 +807,44 @@
Scroll Y value
+
+
+ Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+
+
-
+ HTML Content of the scroll panel.
+
+
+
+
+ Element should be visible when scroll reached page % of given value.
+
+
+
+
+ Element should be visible untill scroll reached page % of given value.
-
+ Scroll shold be jump or smoothly scroll.
+
+
+
+
+ Required space from page bottom in px.
+
+
+
+
+ Required space from page (left/right) side in px.
+
+
+
+
+ Element orientation on page.
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
index 104b6643..6e2ada15 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
@@ -1,44 +1,93 @@
-@if (_isVisible)
-{
-
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.css b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.css
index ab507144..8545dc75 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.css
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.css
@@ -3,4 +3,5 @@
z-index: 20;
cursor: pointer;
transition: opacity 0.25s linear;
+ outline: 0px;
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.min.css b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.min.css
index dbcc64b4..20d81bac 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.min.css
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.min.css
@@ -1 +1 @@
-.scrollToPageTop{position:fixed;z-index:20;cursor:pointer;transition:opacity .25s linear}
\ No newline at end of file
+.scrollToPageTop{position:fixed;z-index:20;cursor:pointer;transition:opacity .25s linear;outline:0}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/bundleconfig.json b/src/Majorsoft.Blazor.Components.Common.JsInterop/bundleconfig.json
index 48ca414e..bcb81836 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/bundleconfig.json
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/bundleconfig.json
@@ -64,5 +64,11 @@
"inputFiles": [
"Scroll/ScrollToPageTop.razor.css"
]
+ },
+ {
+ "outputFileName": "Scroll/ScrollToPageBottom.razor.min.css",
+ "inputFiles": [
+ "Scroll/ScrollToPageBottom.razor.css"
+ ]
}
]
From ec1b3cdc8fd6ae7daf8aa0a0c79b97a9de715d27 Mon Sep 17 00:00:00 2001
From: Major
Date: Sun, 28 Mar 2021 20:40:59 +0200
Subject: [PATCH 09/69] Scroll elements demo.
---
...oft.Blazor.Components.Common.JsInterop.xml | 14 ++---
...ion.cs => PageScrollHorizontalPosition.cs} | 2 +-
.../Scroll/ScrollToPageBottom.razor | 6 +-
.../Scroll/ScrollToPageTop.razor | 6 +-
.../Components/JSInterop.razor | 10 +--
.../Components/JsDemo/ScrollJs.razor | 61 ++++++++++++++++++-
6 files changed, 78 insertions(+), 21 deletions(-)
rename src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/{PageScrollHorizontalOrientation.cs => PageScrollHorizontalPosition.cs} (89%)
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml b/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml
index c193d8a7..1dc1c367 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml
@@ -757,17 +757,17 @@
PageScrollEventInfo event info to handle JS callback
-
+
Page scroll elements orientation on page and elements
-
+
Element placed to the Right side
-
+
Element placed to the Left side
@@ -842,9 +842,9 @@
Required space from page (left/right) side in px.
-
+
- Element orientation on page.
+ Element position on page.
@@ -877,9 +877,9 @@
Required space from page (left/right) side in px.
-
+
- Element orientation on page.
+ Element position on page.
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/PageScrollHorizontalOrientation.cs b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/PageScrollHorizontalPosition.cs
similarity index 89%
rename from src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/PageScrollHorizontalOrientation.cs
rename to src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/PageScrollHorizontalPosition.cs
index 0c62e6e0..602d3638 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/PageScrollHorizontalOrientation.cs
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/PageScrollHorizontalPosition.cs
@@ -3,7 +3,7 @@
///
/// Page scroll elements orientation on page and elements
///
- public enum PageScrollHorizontalOrientation
+ public enum PageScrollHorizontalPosition
{
///
/// Element placed to the Right side
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
index 6e2ada15..d7c24440 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
@@ -1,4 +1,4 @@
-
@@ -74,9 +74,9 @@
///
[Parameter] public int PaddingFromSide { get; set; } = 24;
///
- /// Element orientation on page.
+ /// Element position on page.
///
- [Parameter] public PageScrollHorizontalOrientation HorizontalOrientation { get; set; } = PageScrollHorizontalOrientation.Right;
+ [Parameter] public PageScrollHorizontalPosition HorizontalPosition { get; set; } = PageScrollHorizontalPosition.Right;
private void WriteDiag(string message)
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JSInterop.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JSInterop.razor
index f357bc21..7247062a 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JSInterop.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JSInterop.razor
@@ -16,9 +16,9 @@
@*Scroll to page end with ScrollHandler for custom floating component see ScrollToPageBottom*@
-
+
Smooth scroll:
-
+
JS Interop features:
@@ -58,9 +58,9 @@ Smooth scroll:
@*Scroll to page end with ScrollHandler for custom floating component see ScrollToPageTop*@
-
+
Smooth scroll:
-
+
@implements IAsyncDisposable
@inject IScrollHandler _scrollHandler
@@ -74,5 +74,5 @@ Smooth scroll:
}
}
- private bool _smmothScroll = true;
+ private bool _smoothScroll = true;
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
index c2f567dd..b43f8993 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
@@ -1,5 +1,10 @@
@*Scroll on page components, can be placed anywhere on a page but should be used one per page*@
-
+
@@ -7,7 +12,11 @@
-
+
@@ -34,6 +43,47 @@
+
+
+
+
+
+
+ Top/Bottom margin (can be set separately for both types of controls): @(_scrcollTopBottonMargin)px
+ _scrcollTopBottonMargin = int.Parse(e.Value?.ToString()))" />
+
+
+
+
+
+ Side right/left margin (can be set separately for both types of controls): @(_scrcollTopSideMargin)px
+ _scrcollTopSideMargin = int.Parse(e.Value?.ToString()))" />
+
+
+
+
+
+ Smooth scroll (can be set separately for both types of controls):
+
+
+
+
+
+ Horizontal Position right/left (can be set separately for both types of controls):
+
+
+
+
+
RegisterPageScrollAsync() will add event listener to HTML document/window scroll
@@ -101,6 +151,13 @@
_scrollSubscribed = !_scrollSubscribed;
}
+ //Page scroll elements
+ private int _scrcollTopBottonMargin = 20;
+ private int _scrcollTopSideMargin = 24;
+ private byte _scrcollBefore = 5;
+ private PageScrollHorizontalPosition _scrollHorizontalPosition = PageScrollHorizontalPosition.Right;
+ private bool _smoothScroll = true;
+
public async ValueTask DisposeAsync()
{
if (_scrollHandler is not null)
From 09ae2a9ef34d85515d0dd5ee09575de0fdcdace7 Mon Sep 17 00:00:00 2001
From: Major
Date: Sun, 28 Mar 2021 21:17:32 +0200
Subject: [PATCH 10/69] Scroll elements docs.
---
.github/docs/JsInterop.md | 54 ++++++++++++++++++-
...oft.Blazor.Components.Common.JsInterop.xml | 10 ++--
.../Scroll/ScrollToPageBottom.razor | 6 +--
.../Scroll/ScrollToPageTop.razor | 4 +-
.../Components/JsDemo/ScrollJs.razor | 4 +-
5 files changed, 65 insertions(+), 13 deletions(-)
diff --git a/.github/docs/JsInterop.md b/.github/docs/JsInterop.md
index efc941b1..22a95cfa 100644
--- a/.github/docs/JsInterop.md
+++ b/.github/docs/JsInterop.md
@@ -21,7 +21,8 @@ You can try it out by using the [demo app](https://blazorextensions.z6.web.core.
- **Global Mouse JS**: is an **injectable `IGlobalMouseEventHandler` service** for global mouse callback event handlers.
- **Focus JS**: is an injectable `IFocusHandler` service. **Focus JS is able to identify and restore focus on ANY DOM element without using Blazor `@ref=""` tag.**
- **Element info JS**: is a set of **Extension methods** for `ElementReference` objects.
-- **Scroll JS**: is a set of **Extension methods** for `ElementReference` objects. Also an **injectable `IScrollHandler` service** for non element level functions and callback event handlers.
+- **Scroll JS**: is a set of **Extension methods** for `ElementReference` objects. **`IScrollHandler` injectable service** for non element level functions and callback event handlers.
+ Also `ScrollToPageBottom` and `ScrollToPageTop` components will render "floating" element with customizable placing and content for wrapping Scroll JS scroll to page top or bottom functions.
- **Resize JS**: is an **injectable `IResizeHandler` service** for Window (global) and HTML Elements resize event callback handlers.
- **Clipboard JS**: is an **injectable `IClipboardHandler` service** for accessing computer Clipboard from Blazor Application.
- **Language JS**: is an **injectable `ILanguageService` service** for detect the browser language preference.
@@ -108,6 +109,57 @@ Returns the given HTML element ClintBoundRect data as `DomRect`.
## Scroll JS (See: [demo app](https://blazorextensions.z6.web.core.windows.net/jsinterop#scroll-js))
**Scroll JS** is a set of **Extension methods** for `ElementReference` objects.
Also an **injectable `IScrollHandler` service** for non element level functions and callback event handlers.
+`ScrollToPageBottom` and `ScrollToPageTop` components will render "floating" element with customizable placing and content for wrapping `Scroll JS` scroll to page top or bottom functions.
+**Note**: Both component can be set inside ANY components which will apply for the whole page. Hence both components should be added only once per page!
+
+### `ScrollToPageBottom` component
+`ScrollToPageBottom` component will render "floating" element with customizable placing and content for wrapping Scroll JS **scroll to page bottom** function.
+
+#### Properties
+- **`Content`: `RenderFragment` HTML content - Required**
+Required HTML content which will be wrapped into a `` which has the Click events listener registered.
+- **`VisibleFromPagePercentage`: `byte { get; set; }` (default: 5)**
+Element should be visible when scroll reached page % of given value.
+- **`VisibleUntilPagePercentage`: `byte { get; set; }` (default: 80)**
+Element should be visible until scroll reached page % of given value.
+- **`SmootScroll`: `bool { get; set; }` (default: true)**
+Scroll should be jump or smoothly scroll.
+- **`PaddingFromTop`: `int { get; set; }` (default: 24)**
+Required space from page bottom in px.
+- **`PaddingFromSide`: `int { get; set; }` (default: 24)**
+Required space from page (left/right) side in px.
+- **`HorizontalPosition`: `PageScrollHorizontalPosition { get; set; }` (default: 24)**
+Element position on page {Right, Left}.
+- **`InnerElementReference`: `ElementReference { get; }`**
+Exposes a Blazor `ElementReference` of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+
+#### Functions
+- **`DisposeAsync()`: `ValueTask IAsyncDisposable()` interface**
+Component implements `IAsyncDisposable` interface Blazor framework components also can `@implements IAsyncDisposable` where the injected service should be Disposed.
+
+### `ScrollToPageTop` component
+`ScrollToPageTop` component will render "floating" element with customizable placing and content for wrapping Scroll JS **scroll to page top** function.
+
+#### Properties
+- **`Content`: `RenderFragment` HTML content - Required**
+Required HTML content which will be wrapped into a `` which has the Click events listener registered.
+- **`VisibleFromPagePercentage`: `byte { get; set; }` (default: 30)**
+Element should be visible when scroll reached page % of given value.
+- **`SmootScroll`: `bool { get; set; }` (default: true)**
+Scroll should be jump or smoothly scroll.
+- **`PaddingFromTop`: `int { get; set; }` (default: 24)**
+Required space from page bottom in px.
+- **`PaddingFromSide`: `int { get; set; }` (default: 24)**
+Required space from page (left/right) side in px.
+- **`HorizontalPosition`: `PageScrollHorizontalPosition { get; set; }` (default: 24)**
+Element position on page {Right, Left}.
+- **`InnerElementReference`: `ElementReference { get; }`**
+Exposes a Blazor `ElementReference` of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+
+#### Functions
+- **`DisposeAsync()`: `ValueTask IAsyncDisposable()` interface**
+Component implements `IAsyncDisposable` interface Blazor framework components also can `@implements IAsyncDisposable` where the injected service should be Disposed.
+
### `IScrollHandler` Functions
- **`ScrollToElementAsync`**: **`Task ScrollToElementAsync(ElementReference elementReference)`**
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml b/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml
index 1dc1c367..645f1617 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml
@@ -824,12 +824,12 @@
- Element should be visible untill scroll reached page % of given value.
+ Element should be visible until scroll reached page % of given value.
- Scroll shold be jump or smoothly scroll.
+ Scroll should be jump or smoothly scroll.
@@ -844,7 +844,7 @@
- Element position on page.
+ Element position on page {Right, Left}.
@@ -864,7 +864,7 @@
- Scroll shold be jump or smoothly scroll.
+ Scroll should be jump or smoothly scroll.
@@ -879,7 +879,7 @@
- Element position on page.
+ Element position on page {Right, Left}.
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
index d7c24440..dac749f0 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
@@ -60,12 +60,12 @@
///
[Parameter] public byte VisibleFromPagePercentage { get; set; } = 5;
///
- /// Element should be visible untill scroll reached page % of given value.
+ /// Element should be visible until scroll reached page % of given value.
///
[Parameter] public byte VisibleUntilPagePercentage { get; set; } = 80;
///
- /// Scroll shold be jump or smoothly scroll.
+ /// Scroll should be jump or smoothly scroll.
///
[Parameter] public bool SmootScroll { get; set; } = true;
@@ -78,7 +78,7 @@
///
[Parameter] public int PaddingFromSide { get; set; } = 24;
///
- /// Element position on page.
+ /// Element position on page {Right, Left}.
///
[Parameter] public PageScrollHorizontalPosition HorizontalPosition { get; set; } = PageScrollHorizontalPosition.Right;
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor
index d5cea1e0..55a4bc6e 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor
@@ -61,7 +61,7 @@
[Parameter] public byte VisibleFromPagePercentage { get; set; } = 30;
///
- /// Scroll shold be jump or smoothly scroll.
+ /// Scroll should be jump or smoothly scroll.
///
[Parameter] public bool SmootScroll { get; set; } = true;
@@ -74,7 +74,7 @@
///
[Parameter] public int PaddingFromSide { get; set; } = 24;
///
- /// Element position on page.
+ /// Element position on page {Right, Left}.
///
[Parameter] public PageScrollHorizontalPosition HorizontalPosition { get; set; } = PageScrollHorizontalPosition.Right;
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
index b43f8993..d2bf7019 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
@@ -3,8 +3,8 @@
PaddingFromSide="@_scrcollTopSideMargin"
HorizontalPosition="@_scrollHorizontalPosition"
SmootScroll="@_smoothScroll"
- VisibleFromPagePercentage="5"
- VisibleUntilPagePercentage="70">
+ VisibleFromPagePercentage="2"
+ VisibleUntilPagePercentage="75">
From c28f40133b02583c0606b33c83645f34ae0289c5 Mon Sep 17 00:00:00 2001
From: Major
Date: Mon, 29 Mar 2021 10:06:50 +0200
Subject: [PATCH 11/69] JS docs updates.
---
.github/docs/JsInterop.md | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/.github/docs/JsInterop.md b/.github/docs/JsInterop.md
index 22a95cfa..d86aa0d2 100644
--- a/.github/docs/JsInterop.md
+++ b/.github/docs/JsInterop.md
@@ -16,13 +16,16 @@ You can try it out by using the [demo app](https://blazorextensions.z6.web.core.
# Features
-- **Click JS**: `ClickBoundariesElement` is a component which wraps the given content to a DIV and subscribes to all click events: `OnOutsideClick`, `OnInsideClick`.
- Also an **injectable `IClickBoundariesHandler` service** for callback event handlers.
+- **Click JS**:
+ - `ClickBoundariesElement` is a component which wraps the given content to a DIV and subscribes to all click events: `OnOutsideClick`, `OnInsideClick`.
+ - Also an **injectable `IClickBoundariesHandler` service** for callback event handlers.
- **Global Mouse JS**: is an **injectable `IGlobalMouseEventHandler` service** for global mouse callback event handlers.
- **Focus JS**: is an injectable `IFocusHandler` service. **Focus JS is able to identify and restore focus on ANY DOM element without using Blazor `@ref=""` tag.**
- **Element info JS**: is a set of **Extension methods** for `ElementReference` objects.
-- **Scroll JS**: is a set of **Extension methods** for `ElementReference` objects. **`IScrollHandler` injectable service** for non element level functions and callback event handlers.
- Also `ScrollToPageBottom` and `ScrollToPageTop` components will render "floating" element with customizable placing and content for wrapping Scroll JS scroll to page top or bottom functions.
+- **Scroll JS**:
+ - Set of **Extension methods** for `ElementReference` objects.
+ - **`IScrollHandler` injectable service** for non element level functions and callback event handlers.
+ - Also `ScrollToPageBottom` and `ScrollToPageTop` components will render "floating" element with customizable placing and content for wrapping Scroll JS scroll to page top or bottom functions.
- **Resize JS**: is an **injectable `IResizeHandler` service** for Window (global) and HTML Elements resize event callback handlers.
- **Clipboard JS**: is an **injectable `IClipboardHandler` service** for accessing computer Clipboard from Blazor Application.
- **Language JS**: is an **injectable `ILanguageService` service** for detect the browser language preference.
From 1b78b7615e489a0c5d51396289a4b5138301e218 Mon Sep 17 00:00:00 2001
From: Major
Date: Mon, 29 Mar 2021 11:40:45 +0200
Subject: [PATCH 12/69] Scroll on page components issue fixes with opacity.
---
.../Scroll/ScrollToPageBottom.razor | 2 +-
.../Scroll/ScrollToPageBottom.razor.css | 5 +++++
.../Scroll/ScrollToPageBottom.razor.min.css | 2 +-
.../Scroll/ScrollToPageTop.razor | 2 +-
.../Scroll/ScrollToPageTop.razor.css | 5 +++++
.../Scroll/ScrollToPageTop.razor.min.css | 2 +-
.../Components/JsDemo/ScrollJs.razor | 2 +-
7 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
index dac749f0..4d32e6a7 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
@@ -1,4 +1,4 @@
-
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.css b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.css
index 8545dc75..d4abf22c 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.css
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.css
@@ -4,4 +4,9 @@
cursor: pointer;
transition: opacity 0.25s linear;
outline: 0px;
+}
+
+.scrollToPageTop.hidden {
+ cursor: pointer;
+ pointer-events: none;
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.min.css b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.min.css
index 20d81bac..db204003 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.min.css
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor.min.css
@@ -1 +1 @@
-.scrollToPageTop{position:fixed;z-index:20;cursor:pointer;transition:opacity .25s linear;outline:0}
\ No newline at end of file
+.scrollToPageTop{position:fixed;z-index:20;cursor:pointer;transition:opacity .25s linear;outline:0}.scrollToPageTop.hidden{cursor:pointer;pointer-events:none}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
index d2bf7019..c0e68995 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
@@ -1,4 +1,4 @@
-@*Scroll on page components, can be placed anywhere on a page but should be used one per page*@
+@*Scroll on page components, can be placed anywhere on a page, moved to a new component, etc. but should be used once per page*@
Date: Mon, 29 Mar 2021 11:57:12 +0200
Subject: [PATCH 13/69] Update demo app with page scroll
---
.../Components/BrowserStorage.razor | 4 +++-
.../Components/Collapse.razor | 4 +++-
.../Components/CssEvents.razor | 2 ++
.../Components/Debounce.razor | 4 +++-
.../Components/Dialog.razor | 4 +++-
.../Components/Index.razor | 4 +++-
.../Components/JSInterop.razor | 4 ++--
.../Components/Loading.razor | 1 +
.../Components/Maps.razor | 2 ++
.../Components/Permalink.razor | 1 +
.../Components/Tabs.razor | 4 +++-
.../Components/Toggle.razor | 4 +++-
.../Components/Typeahead.razor | 1 +
.../Shared/PageScroll.razor | 16 ++++++++++++++++
14 files changed, 46 insertions(+), 9 deletions(-)
create mode 100644 src/Majorsoft.Blazor.Components.TestApps.Common/Shared/PageScroll.razor
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/BrowserStorage.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/BrowserStorage.razor
index 4e214371..867aeb57 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/BrowserStorage.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/BrowserStorage.razor
@@ -1,4 +1,6 @@
-
+
+
+
Browser Storage extensions
Enables Browser Local and Session storages and
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Collapse.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Collapse.razor
index e53a281e..66e7db01 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Collapse.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Collapse.razor
@@ -1,4 +1,6 @@
-
Collapse Components
+
+
+
Collapse Components
Blazor component that renders customizable Collapsible/Expandable panel and Accordion with many but only one active panel also custom content and header. For usege see soruce code and docs on
Github.
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/CssEvents.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/CssEvents.razor
index e734e8b1..4dccb7af 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/CssEvents.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/CssEvents.razor
@@ -12,6 +12,8 @@
Animations
+
+
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Debounce.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Debounce.razor
index b78c3384..911fef99 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Debounce.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Debounce.razor
@@ -1,4 +1,6 @@
-
Deboudnce Input controls
+
+
+
Deboudnce Input controls
Blazor component that renders an Input, InputText, Textarea or InputTextarea, etc. element with debounced onChange. For usege see soruce code and docs on
Github.
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Dialog.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Dialog.razor
index d19078d4..1a21b5b9 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Dialog.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Dialog.razor
@@ -1,4 +1,6 @@
-
Modal Component
+
+
+
Modal Component
Blazor component that can be used to render Modal dialog window with customizable content and parameterized Overlay, etc.. For usege see soruce code and docs on
Github.
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Index.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Index.razor
index 28374820..3aaeb98c 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Index.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Index.razor
@@ -1,4 +1,6 @@
-
ASP.NET Blazor Components
+
+
+
ASP.NET Blazor Components
Blazor Components is a set of UI Components and other useful Extensions for Blazor applications.
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JSInterop.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JSInterop.razor
index 7247062a..0434ef8c 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JSInterop.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JSInterop.razor
@@ -16,7 +16,7 @@
@*Scroll to page end with ScrollHandler for custom floating component see ScrollToPageBottom*@
-
+
Smooth scroll:
@@ -58,7 +58,7 @@ Smooth scroll:
@*Scroll to page end with ScrollHandler for custom floating component see ScrollToPageTop*@
-
+
Smooth scroll:
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Loading.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Loading.razor
index 3751c083..3151049c 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Loading.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Loading.razor
@@ -1,4 +1,5 @@
@using System.ComponentModel.DataAnnotations;
+
Blazor component that renders customizable Tabs element panel with many tabs and custom content. For usege see soruce code and docs on
Github.
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Toggle.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Toggle.razor
index 5522c9c4..1adcd984 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Toggle.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Toggle.razor
@@ -1,4 +1,6 @@
-
Toggler Components
+
+
+
Toggler Components
Blazor component that renders customizable Toggle Switch and Toggle Button components. For usege see soruce code and docs on
Github.
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Typeahead.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Typeahead.razor
index b17480d4..a1b87cfa 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Typeahead.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Typeahead.razor
@@ -3,6 +3,7 @@ textarea {
height: 150px !important;
}
+
Typeahead Input controls
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Shared/PageScroll.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Shared/PageScroll.razor
new file mode 100644
index 00000000..3cdd2ae6
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Shared/PageScroll.razor
@@ -0,0 +1,16 @@
+@*Scroll on page components wrapped into it's own component and applied on some demo pages*@
+
+
+
+ Blazor extension that enables WebAssemply site analytics e.g. Google, etc. For usage see source code and docs on
+ Github.
+ Majorsoft.Blazor.Extensions.Analytics package is available on Nuget
+
+
+
+
Browser Storage features:
+
+
Google Analytics
+
+
+
+
+@code {
+
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Pages/AnalyticsPage.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Pages/AnalyticsPage.razor
new file mode 100644
index 00000000..9850231d
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Pages/AnalyticsPage.razor
@@ -0,0 +1,3 @@
+@page "/analytics"
+
+
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Shared/NavMenu.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Shared/NavMenu.razor
index 018c8127..729bcfce 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Shared/NavMenu.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Shared/NavMenu.razor
@@ -24,7 +24,10 @@
Console logger
- Browser strorage
+ Browser storage
+
+
+ Analytics
diff --git a/src/Majorsoft.Blazor.Components.TestServerApp/Pages/AnalyticsPage.razor b/src/Majorsoft.Blazor.Components.TestServerApp/Pages/AnalyticsPage.razor
new file mode 100644
index 00000000..9850231d
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.TestServerApp/Pages/AnalyticsPage.razor
@@ -0,0 +1,3 @@
+@page "/analytics"
+
+
\ No newline at end of file
From a81b6a95bca5fc6d0c1d69aae4d99e11ab097586 Mon Sep 17 00:00:00 2001
From: Major
Date: Tue, 6 Apr 2021 21:31:25 +0200
Subject: [PATCH 16/69] Google analytics service.
---
.../Components/GoogleAnalytics.razor | 15 ++++++-
.../ExampleJsInterop.cs | 40 -----------------
.../Google/GoogleAnalyticsService.cs | 44 +++++++++++++++++++
.../Majorsoft.Blazor.Extensions.Analytics.xml | 10 +++++
4 files changed, 68 insertions(+), 41 deletions(-)
delete mode 100644 src/Majorsoft.Blazor.Extensions.Analytics/ExampleJsInterop.cs
create mode 100644 src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
index 68590c80..8148812d 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
@@ -9,11 +9,24 @@
-
Browser Storage features:
+
Supported Analytics service providers:
Google Analytics
+
+
+
+
Google Analytics
+
+
+ Google Analytics is a web analytics service offered by Google that tracks and reports website traffic, etc. inside the Google Marketing Platform.
+
+ IGoogleAnalyticsService is an injectable service for enabling
+ Google Analytics page tracking in Blazor Apps.
+
+
+
@code {
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/ExampleJsInterop.cs b/src/Majorsoft.Blazor.Extensions.Analytics/ExampleJsInterop.cs
deleted file mode 100644
index 807334e7..00000000
--- a/src/Majorsoft.Blazor.Extensions.Analytics/ExampleJsInterop.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using System.Threading.Tasks;
-
-using Microsoft.JSInterop;
-
-namespace Majorsoft.Blazor.Extensions.Analytics
-{
- // This class provides an example of how JavaScript functionality can be wrapped
- // in a .NET class for easy consumption. The associated JavaScript module is
- // loaded on demand when first needed.
- //
- // This class can be registered as scoped DI service and then injected into Blazor
- // components for use.
-
- public class ExampleJsInterop : IAsyncDisposable
- {
- private readonly Lazy> moduleTask;
-
- public ExampleJsInterop(IJSRuntime jsRuntime)
- {
- moduleTask = new(() => jsRuntime.InvokeAsync(
- "import", "./_content/Majorsoft.Blazor.Analytics/exampleJsInterop.js").AsTask());
- }
-
- public async ValueTask Prompt(string message)
- {
- var module = await moduleTask.Value;
- return await module.InvokeAsync("showPrompt", message);
- }
-
- public async ValueTask DisposeAsync()
- {
- if (moduleTask.IsValueCreated)
- {
- var module = await moduleTask.Value;
- await module.DisposeAsync();
- }
- }
- }
-}
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs
new file mode 100644
index 00000000..9ee3f049
--- /dev/null
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Threading.Tasks;
+
+using Microsoft.JSInterop;
+
+namespace Majorsoft.Blazor.Extensions.Analytics.Google
+{
+ ///
+ ///
+ ///
+ public interface IGoogleAnalyticsService : IAsyncDisposable
+ {
+
+ }
+
+ ///
+ ///
+ ///
+ public class GoogleAnalyticsService : IGoogleAnalyticsService
+ {
+ private readonly Lazy> moduleTask;
+
+ public GoogleAnalyticsService(IJSRuntime jsRuntime)
+ {
+ moduleTask = new(() => jsRuntime.InvokeAsync(
+ "import", "./_content/Majorsoft.Blazor.Analytics/googleAnalytics.js").AsTask());
+ }
+
+ public async ValueTask Configure(string trackingId)
+ {
+ var module = await moduleTask.Value;
+ await module.InvokeVoidAsync("configure", trackingId);
+ }
+
+ public async ValueTask DisposeAsync()
+ {
+ if (moduleTask.IsValueCreated)
+ {
+ var module = await moduleTask.Value;
+ await module.DisposeAsync();
+ }
+ }
+ }
+}
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml b/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
index 10b14e47..6913aca1 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
@@ -4,5 +4,15 @@
Majorsoft.Blazor.Extensions.Analytics
+
+
+
+
+
+
+
+
+
+
From 8d84c5b548474ae1f0eeac3ad32675075aec1384 Mon Sep 17 00:00:00 2001
From: Major
Date: Tue, 6 Apr 2021 22:04:54 +0200
Subject: [PATCH 17/69] Added scroll to page elements AnimateOnHover
functionality.
---
.github/docs/JsInterop.md | 4 ++++
.../Majorsoft.Blazor.Components.Common.JsInterop.xml | 10 ++++++++++
.../Scroll/ScrollToPageBottom.razor | 10 +++++++++-
.../Scroll/ScrollToPageTop.razor | 10 +++++++++-
.../Components/JsDemo/ScrollJs.razor | 6 +++++-
.../Shared/PageScroll.razor | 4 ++--
6 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/.github/docs/JsInterop.md b/.github/docs/JsInterop.md
index d86aa0d2..80667793 100644
--- a/.github/docs/JsInterop.md
+++ b/.github/docs/JsInterop.md
@@ -127,6 +127,8 @@ Element should be visible when scroll reached page % of given value.
Element should be visible until scroll reached page % of given value.
- **`SmootScroll`: `bool { get; set; }` (default: true)**
Scroll should be jump or smoothly scroll.
+- **`AnimateOnHover`: `bool { get; set; }` (default: true)**
+Apply animation (opacity) on icon when mouse hovered.
- **`PaddingFromTop`: `int { get; set; }` (default: 24)**
Required space from page bottom in px.
- **`PaddingFromSide`: `int { get; set; }` (default: 24)**
@@ -150,6 +152,8 @@ Required HTML content which will be wrapped into a `` which has the Click
Element should be visible when scroll reached page % of given value.
- **`SmootScroll`: `bool { get; set; }` (default: true)**
Scroll should be jump or smoothly scroll.
+- **`AnimateOnHover`: `bool { get; set; }` (default: true)**
+Apply animation (opacity) on icon when mouse hovered.
- **`PaddingFromTop`: `int { get; set; }` (default: 24)**
Required space from page bottom in px.
- **`PaddingFromSide`: `int { get; set; }` (default: 24)**
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml b/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml
index 645f1617..fb42b7bd 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Majorsoft.Blazor.Components.Common.JsInterop.xml
@@ -832,6 +832,11 @@
Scroll should be jump or smoothly scroll.
+
+
+ Apply animation (opacity) on icon when mouse hovered.
+
+
Required space from page bottom in px.
@@ -867,6 +872,11 @@
Scroll should be jump or smoothly scroll.
+
+
+ Apply animation (opacity) on icon when mouse hovered.
+
+
Required space from page bottom in px.
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
index 4d32e6a7..df63813a 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageBottom.razor
@@ -6,7 +6,10 @@
@implements IAsyncDisposable
@@ -25,82 +25,85 @@
@inject ILogger _logger
@code {
- private bool _isVisible = false;
-
- protected override async Task OnInitializedAsync()
- {
- WriteDiag("Component initialized...");
-
- await _scrollHandler.RegisterPageScrollAsync(async (e) =>
- {
- var scrollSize = await _scrollHandler.GetPageScrollSizeAsync();
- var percentage = (e.Y / scrollSize.Y) * 100;
-
- var visible = percentage >= VisibleFromPagePercentage && percentage <= VisibleUntilPagePercentage && !scrollSize.IsPageBottom;
- if (visible != _isVisible)
- {
- _isVisible = visible;
- StateHasChanged();
-
- WriteDiag($"Component visibilit changed visible: {_isVisible}.");
- }
- });
- }
-
- private ElementReference _inputRef;
- ///
- /// Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
- ///
- public ElementReference InnerElementReference => _inputRef;
-
- ///
- /// HTML Content of the scroll panel.
- ///
- [Parameter] public RenderFragment Content { get; set; }
-
- ///
- /// Element should be visible when scroll reached page % of given value.
- ///
- [Parameter] public byte VisibleFromPagePercentage { get; set; } = 5;
- ///
- /// Element should be visible until scroll reached page % of given value.
- ///
- [Parameter] public byte VisibleUntilPagePercentage { get; set; } = 80;
-
- ///
- /// Scroll should be jump or smoothly scroll.
- ///
- [Parameter] public bool SmootScroll { get; set; } = true;
-
- ///
- /// Apply animation (opacity) on icon when mouse hovered.
- ///
- [Parameter] public bool AnimateOnHover { get; set; } = true;
-
- ///
- /// Required space from page bottom in px.
- ///
- [Parameter] public int PaddingFromTop { get; set; } = 24;
- ///
- /// Required space from page (left/right) side in px.
- ///
- [Parameter] public int PaddingFromSide { get; set; } = 24;
- ///
- /// Element position on page {Right, Left}.
- ///
- [Parameter] public PageScrollHorizontalPosition HorizontalPosition { get; set; } = PageScrollHorizontalPosition.Right;
-
-
- private void WriteDiag(string message)
- {
- _logger.LogDebug($"Component {this.GetType()}: {message}");
- }
-
- public async ValueTask DisposeAsync()
- {
- if (_scrollHandler is not null)
- {
- await _scrollHandler.DisposeAsync();
- }
- }
+ private bool _isVisible = false;
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if(firstRender)
+ {
+ WriteDiag("Component rendered...");
+
+ await _scrollHandler.RegisterPageScrollAsync(async (e) =>
+ {
+ var scrollSize = await _scrollHandler.GetPageScrollSizeAsync();
+ var percentage = (e.Y / scrollSize.Y) * 100;
+
+ var visible = percentage >= VisibleFromPagePercentage && percentage <= VisibleUntilPagePercentage && !scrollSize.IsPageBottom;
+ if (visible != _isVisible)
+ {
+ _isVisible = visible;
+ StateHasChanged();
+
+ WriteDiag($"Component visibilit changed visible: {_isVisible}.");
+ }
+ });
+ }
+ }
+
+ private ElementReference _inputRef;
+ ///
+ /// Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+ ///
+ public ElementReference InnerElementReference => _inputRef;
+
+ ///
+ /// HTML Content of the scroll panel.
+ ///
+ [Parameter] public RenderFragment Content { get; set; }
+
+ ///
+ /// Element should be visible when scroll reached page % of given value.
+ ///
+ [Parameter] public byte VisibleFromPagePercentage { get; set; } = 5;
+ ///
+ /// Element should be visible until scroll reached page % of given value.
+ ///
+ [Parameter] public byte VisibleUntilPagePercentage { get; set; } = 80;
+
+ ///
+ /// Scroll should be jump or smoothly scroll.
+ ///
+ [Parameter] public bool SmootScroll { get; set; } = true;
+
+ ///
+ /// Apply animation (opacity) on icon when mouse hovered.
+ ///
+ [Parameter] public bool AnimateOnHover { get; set; } = true;
+
+ ///
+ /// Required space from page bottom in px.
+ ///
+ [Parameter] public int PaddingFromTop { get; set; } = 24;
+ ///
+ /// Required space from page (left/right) side in px.
+ ///
+ [Parameter] public int PaddingFromSide { get; set; } = 24;
+ ///
+ /// Element position on page {Right, Left}.
+ ///
+ [Parameter] public PageScrollHorizontalPosition HorizontalPosition { get; set; } = PageScrollHorizontalPosition.Right;
+
+
+ private void WriteDiag(string message)
+ {
+ _logger.LogDebug($"Component {this.GetType()}: {message}");
+ }
+
+ public async ValueTask DisposeAsync()
+ {
+ if (_scrollHandler is not null)
+ {
+ await _scrollHandler.DisposeAsync();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor
index 0e65bac3..e9d9e97a 100644
--- a/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor
+++ b/src/Majorsoft.Blazor.Components.Common.JsInterop/Scroll/ScrollToPageTop.razor
@@ -27,24 +27,27 @@
@code {
private bool _isVisible = false;
- protected override async Task OnInitializedAsync()
+ protected override async Task OnAfterRenderAsync(bool firstRender)
{
- WriteDiag("Component initialized...");
-
- await _scrollHandler.RegisterPageScrollAsync(async (e) =>
+ if (firstRender)
{
- var scrollSize = await _scrollHandler.GetPageScrollSizeAsync();
- var percentage = (e.Y / scrollSize.Y) * 100;
+ WriteDiag("Component rendered...");
- var visible = percentage >= VisibleFromPagePercentage;
- if (visible != _isVisible)
+ await _scrollHandler.RegisterPageScrollAsync(async (e) =>
{
- _isVisible = visible;
- StateHasChanged();
-
- WriteDiag($"Component visibilit changed visible: {_isVisible}.");
- }
- });
+ var scrollSize = await _scrollHandler.GetPageScrollSizeAsync();
+ var percentage = (e.Y / scrollSize.Y) * 100;
+
+ var visible = percentage >= VisibleFromPagePercentage;
+ if (visible != _isVisible)
+ {
+ _isVisible = visible;
+ StateHasChanged();
+
+ WriteDiag($"Component visibilit changed visible: {_isVisible}.");
+ }
+ });
+ }
}
private ElementReference _inputRef;
From a172378dbeadc0e81501cb7e4a5de2671cc612c8 Mon Sep 17 00:00:00 2001
From: Major
Date: Mon, 21 Jun 2021 19:06:45 +0200
Subject: [PATCH 31/69] Change Google analytics Get() to accept ExpandoObject.
---
.../Components/GoogleAnalytics.razor | 67 ++++++++++++-------
.../_Imports.razor | 4 +-
.../Startup.cs | 3 +
.../AnalyticsExtension.cs | 4 +-
.../Google/GoogleAnalyticsService.cs | 9 +--
.../Majorsoft.Blazor.Extensions.Analytics.xml | 6 +-
.../wwwroot/googleAnalytics.js | 19 ++++--
.../wwwroot/googleAnalytics.min.js | 4 +-
8 files changed, 74 insertions(+), 42 deletions(-)
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
index 8148812d..12523988 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
@@ -1,34 +1,49 @@
-
Website Analytics extensions
-
- Blazor extension that enables WebAssemply site analytics e.g. Google, etc. For usage see source code and docs on
- Github.
- Majorsoft.Blazor.Extensions.Analytics package is available on Nuget
-
-
-
-
Supported Analytics service providers:
-
-
Google Analytics
-
-
-
-
-
-
Google Analytics
-
-
- Google Analytics is a web analytics service offered by Google that tracks and reports website traffic, etc. inside the Google Marketing Platform.
-
- IGoogleAnalyticsService is an injectable service for enabling
- Google Analytics page tracking in Blazor Apps.
-
-
+
Website Analytics extensions
+
+ Blazor extension that enables WebAssemply site analytics e.g. Google, etc. For usage see source code and docs on
+ Github.
+ Majorsoft.Blazor.Extensions.Analytics package is available on Nuget
+
+
+
+
Supported Analytics service providers:
+
+
Google Analytics
+
+
+
+
+
+
Google Analytics
+
+
+ Google Analytics is a web analytics service offered by Google that tracks and reports website traffic, etc. inside the Google Marketing Platform.
+
+ IGoogleAnalyticsService is an injectable service for enabling
+ Google Analytics page tracking in Blazor Apps.
+
+
-@code {
+@using System.Dynamic;
+@inject IGoogleAnalyticsService _googleAnalytincsService;
+
+@code {
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if(firstRender)
+ {
+ await _googleAnalytincsService.Initialize("G-1QD2VGTEWX");
+
+ dynamic exp = new ExpandoObject();
+ exp.test = 27;
+ await _googleAnalytincsService.Set(exp);
+ await _googleAnalytincsService.Get("test");
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/_Imports.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/_Imports.razor
index d7a6adc7..5702ed14 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/_Imports.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/_Imports.razor
@@ -46,4 +46,6 @@
@using Majorsoft.Blazor.Components.Maps
@using Majorsoft.Blazor.Components.Maps.Google
-@using Majorsoft.Blazor.Extensions.BrowserStorage
\ No newline at end of file
+@using Majorsoft.Blazor.Extensions.BrowserStorage
+
+@using Majorsoft.Blazor.Extensions.Analytics.Google
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestServerApp/Startup.cs b/src/Majorsoft.Blazor.Components.TestServerApp/Startup.cs
index 892505d8..4456c637 100644
--- a/src/Majorsoft.Blazor.Components.TestServerApp/Startup.cs
+++ b/src/Majorsoft.Blazor.Components.TestServerApp/Startup.cs
@@ -11,6 +11,7 @@
using Majorsoft.Blazor.Server.Logging.Console;
using Majorsoft.Blazor.Components.Maps;
using Majorsoft.Blazor.Extensions.BrowserStorage;
+using Majorsoft.Blazor.Extensions.Analytics;
namespace Majorsoft.Blazor.Components.TestServerApp
{
@@ -35,6 +36,8 @@ public void ConfigureServices(IServiceCollection services)
services.AddMapExtensions();
services.AddBrowserStorage();
+
+ services.AddGoogleAnalytics();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/AnalyticsExtension.cs b/src/Majorsoft.Blazor.Extensions.Analytics/AnalyticsExtension.cs
index 2a3e54c7..f3eaf7a1 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/AnalyticsExtension.cs
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/AnalyticsExtension.cs
@@ -13,11 +13,11 @@ public static class AnalyticsExtension
/// Registers required Google Analytic services into IServiceCollection
///
/// IServiceCollection instance
- /// Google Tracking Id when provided will be called.
+ /// Google Tracking Id when provided will be called. DO NOT CALL with value in case of Blazor Server!
/// IServiceCollection
public static IServiceCollection AddGoogleAnalytics(this IServiceCollection services, string trackingId = "")
{
- services.AddSingleton();
+ services.AddTransient();
if (!string.IsNullOrWhiteSpace(trackingId))
{
services.BuildServiceProvider().GetRequiredService()?.Initialize(trackingId);
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs
index 447dca18..81206d26 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Dynamic;
using System.Linq;
using System.Threading.Tasks;
@@ -44,9 +45,9 @@ public interface IGoogleAnalyticsService : IAsyncDisposable
///
/// Allows you to set values that persist across all the subsequent gtag() calls on the page.
///
- /// Is a key name and the value that is to persist across gtag() calls.
+ /// Is a key name and the value that is to persist across gtag() calls.
/// Async ValueTask
- ValueTask Set(Dictionary? parameterValuePair = null);
+ ValueTask Set(ExpandoObject parameters);
///
/// Use the event command to send event data.
@@ -101,10 +102,10 @@ public async ValueTask Get(string fieldName, string trackingId = "")
var module = await moduleTask.Value;
await module.InvokeVoidAsync("get", string.IsNullOrWhiteSpace(trackingId) ? TrackingId : trackingId, fieldName); //TODO: callback results
}
- public async ValueTask Set(Dictionary? parameterValuePair = null)
+ public async ValueTask Set(ExpandoObject parameters)
{
var module = await moduleTask.Value;
- await module.InvokeVoidAsync("set", parameterValuePair?.ToList());
+ await module.InvokeVoidAsync("set", parameters);
}
public async ValueTask Event(string eventName, Dictionary eventParams)
{
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml b/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
index a699fc81..bbd86d39 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
@@ -14,7 +14,7 @@
Registers required Google Analytic services into IServiceCollection
IServiceCollection instance
- Google Tracking Id when provided will be called.
+ Google Tracking Id when provided will be called. DO NOT CALL with value in case of Blazor Server!
IServiceCollection
@@ -51,11 +51,11 @@
Is an identifier that uniquely identifies the target for hits, such as a Google Analytics property
Async ValueTask
-
+
Allows you to set values that persist across all the subsequent gtag() calls on the page.
- Is a key name and the value that is to persist across gtag() calls.
+ Is a key name and the value that is to persist across gtag() calls.
Async ValueTask
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js
index 22c893d1..a5ddd969 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js
@@ -4,13 +4,23 @@ export function init(trackingId) {
}
let src = "https://www.googletagmanager.com/gtag/js?id=";
+ let scriptsIncluded = false;
+
let scriptTags = document.querySelectorAll('head > script');
scriptTags.forEach(scriptTag => {
- if (scriptTag.getAttribute('src').startsWith(src)) {
- return;
+ if (scriptTag) {
+ let srcAttribute = scriptTag.getAttribute('src');
+ if (srcAttribute && srcAttribute.startsWith(src)) {
+ scriptsIncluded = true;
+ return;
+ }
}
});
+ if (scriptsIncluded && window.gtag) { //Prevent adding JS scripts to page multiple times.
+ return;
+ }
+
//Inject required Google JS scripts to HTML (only once!)
document.head.appendChild(document.createComment("Global site tag (gtag.js) - Google Analytics"));
@@ -38,13 +48,14 @@ export function config(trackingId, data) {
export function get(trackingId, fieldName) {
if (trackingId && window.gtag) {
gtag('get', trackingId, fieldName, (result) => {
- //callback method here...
+ //TOOD: callback method here...
+ console.log(result);
});
}
}
export function set(data) {
if (window.gtag && data) {
- gtag('set', trackingId, data);
+ gtag('set', data);
}
}
export function event(eventName, data) {
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.min.js b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.min.js
index 5594c0f8..0a1a89f5 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.min.js
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.min.js
@@ -1,5 +1,5 @@
-export function init(n){if(n){let i="https://www.googletagmanager.com/gtag/js?id=",u=document.querySelectorAll("head > script");u.forEach(n=>{n.getAttribute("src").startsWith(i)});document.head.appendChild(document.createComment("Global site tag (gtag.js) - Google Analytics"));let t=document.createElement("script");t.src=i+n;t.async=!0;document.head.appendChild(t);let r=document.createElement("script");r.textContent=`window.dataLayer = window.dataLayer || [];
+export function init(n){if(n){let i="https://www.googletagmanager.com/gtag/js?id=",r=!1,f=document.querySelectorAll("head > script");if(f.forEach(n=>{if(n){let t=n.getAttribute("src");if(t&&t.startsWith(i)){r=!0;return}}}),!r||!window.gtag){document.head.appendChild(document.createComment("Global site tag (gtag.js) - Google Analytics"));let t=document.createElement("script");t.src=i+n;t.async=!0;document.head.appendChild(t);let u=document.createElement("script");u.textContent=`window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag('js', new Date());
- gtag('config', '{0}');`.replace("{0}",n);document.head.appendChild(r)}}export function config(n,t){n&&window.gtag&>ag("config",n,t)}export function get(n,t){n&&window.gtag&>ag("get",n,t,()=>{})}export function set(n){window.gtag&&n&>ag("set",trackingId,n)}export function event(n,t){window.gtag&&n&&t&>ag("event",n,t)}
\ No newline at end of file
+ gtag('config', '{0}');`.replace("{0}",n);document.head.appendChild(u)}}}export function config(n,t){n&&window.gtag&>ag("config",n,t)}export function get(n,t){n&&window.gtag&>ag("get",n,t,n=>{console.log(n)})}export function set(n){window.gtag&&n&>ag("set",n)}export function event(n,t){window.gtag&&n&&t&>ag("event",n,t)}
\ No newline at end of file
From 17adac3cf9812f4d0331903acf7807ac72554aa3 Mon Sep 17 00:00:00 2001
From: Major
Date: Mon, 21 Jun 2021 19:07:00 +0200
Subject: [PATCH 32/69] Fix GoogleMaps JS script insert.
---
.../wwwroot/googleMaps.js | 13 +++++++++----
.../wwwroot/googleMaps.min.js | 2 +-
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/src/Majorsoft.Blazor.Components.Maps/wwwroot/googleMaps.js b/src/Majorsoft.Blazor.Components.Maps/wwwroot/googleMaps.js
index bdb034c9..76db8114 100644
--- a/src/Majorsoft.Blazor.Components.Maps/wwwroot/googleMaps.js
+++ b/src/Majorsoft.Blazor.Components.Maps/wwwroot/googleMaps.js
@@ -5,12 +5,17 @@
storeElementIdWithDotnetRef(_mapsElementDict, elementId, dotnetRef, backgroundColor, controlSize); //Store map info
+ let src = "https://maps.googleapis.com/maps/api/js?key=";
let scriptsIncluded = false;
+
let scriptTags = document.querySelectorAll('head > script');
scriptTags.forEach(scriptTag => {
- if (scriptTag.getAttribute('src').startsWith("https://maps.googleapis.com/maps/api/js?key=")) {
- scriptsIncluded = true;
- return;
+ if (scriptTag) {
+ let srcAttribute = scriptTag.getAttribute('src');
+ if (srcAttribute && srcAttribute.startsWith(src)) {
+ scriptsIncluded = true;
+ return;
+ }
}
});
@@ -26,7 +31,7 @@
importedPoly.src = "https://polyfill.io/v3/polyfill.min.js?features=default";
document.head.appendChild(importedPoly);
- let src = "https://maps.googleapis.com/maps/api/js?key=" + key + "&callback=initGoogleMaps&libraries=&v=weekly";
+ src = src + key + "&callback=initGoogleMaps&libraries=&v=weekly";
let importedMaps = document.createElement('script');
importedMaps.src = src;
importedMaps.defer = true;
diff --git a/src/Majorsoft.Blazor.Components.Maps/wwwroot/googleMaps.min.js b/src/Majorsoft.Blazor.Components.Maps/wwwroot/googleMaps.min.js
index 26b1cf06..68bbd396 100644
--- a/src/Majorsoft.Blazor.Components.Maps/wwwroot/googleMaps.min.js
+++ b/src/Majorsoft.Blazor.Components.Maps/wwwroot/googleMaps.min.js
@@ -1 +1 @@
-export function init(t,i,r,f,e){if(t&&i&&r){u(n,i,r,f,e);let s=!1,c=document.querySelectorAll("head > script");if(c.forEach(n=>{if(n.getAttribute("src").startsWith("https://maps.googleapis.com/maps/api/js?key=")){s=!0;return}}),s){window.google&&window.initGoogleMaps();return}let h=document.createElement("script");h.src="https://polyfill.io/v3/polyfill.min.js?features=default";document.head.appendChild(h);let l="https://maps.googleapis.com/maps/api/js?key="+t+"&callback=initGoogleMaps&libraries=&v=weekly",o=document.createElement("script");o.src=l;o.defer=!0;document.head.appendChild(o)}}function u(n,t,i,r,u){for(let i=0;i{e.invokeMethodAsync("CustomControlClicked",i)})}}}export function createMarkers(r,u){if(r&&u&&u.length){let o=t(n,r);if(o&&o.map)for(var f=0;f{o.ref.invokeMethodAsync("MarkerClicked",n.id),i&&i.open(o.map,t)})}if(n.draggable){t.addListener("drag",()=>{i("MarkerDrag",n.id,t.getPosition().toJSON())});t.addListener("dragend",()=>{i("MarkerDragEnd",n.id,t.getPosition().toJSON())});t.addListener("dragstart",()=>{i("MarkerDragStart",n.id,t.getPosition().toJSON())});function i(n,t,i){let r={Latitude:i.lat,Longitude:i.lng};o.ref.invokeMethodAsync(n,t,r)}}}}}export function removeMarkers(r,u){if(r&&u&&u.length){let e=t(n,r);if(e&&e.map)for(var f=0;f{if(n.id==t.id){t.setMap(null);i.splice(r,1);return}})}}}function e(n,t){t&&n&&(t.setPosition({lat:n.position.latitude,lng:n.position.longitude}),t.anchorPoint=n.anchorPoint?{x:n.anchorPoint.x,y:n.anchorPoint.y}:null,t.setAnimation(n.animation),t.setClickable(n.clickable),t.crossOnDrag=n.crossOnDrag,t.setCursor(n.cursor),t.setDraggable(n.draggable),t.setIcon(n.icon),t.setLabel(n.label),t.setOpacity(n.opacity),t.optimized=n.optimized,t.setShape(n.shape),t.setTitle(n.title),t.setVisible(n.visible),t.setZIndex(n.zIndex))}export function getAddressCoordinates(i,u){r(u,function(r){if(r){let u=t(n,i);u&&u.map&&u.ref.invokeMethodAsync("AddressSearch",r)}})}function r(n,t){let i=new google.maps.Geocoder;i.geocode({address:n},function(n,i){i==google.maps.GeocoderStatus.OK&&t(n)})}export function dispose(i){if(i){let r=t(n,i);r.map=null;r.ref=null;f(n,i)}}window.initGoogleMaps=()=>{for(let i=0;i{u(n,"MapClicked")});r.addListener("dblclick",n=>{u(n,"MapDoubleClicked")});r.addListener("contextmenu",n=>{u(n,"MapContextMenu")});r.addListener("mouseup",n=>{u(n,"MapMouseUp")});r.addListener("mousedown",n=>{u(n,"MapMouseDown")});r.addListener("mousemove",n=>{u(n,"MapMouseMove")});r.addListener("mouseover",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapMouseOver")}});r.addListener("mouseout",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapMouseOut")}});r.addListener("center_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);if(i&&r.getCenter()){let n=r.getCenter().toJSON(),t={Latitude:n.lat,Longitude:n.lng};i.ref.invokeMethodAsync("MapCenterChanged",t)}}});r.addListener("zoom_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapZoomChanged",r.getZoom())}});r.addListener("maptypeid_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapTypeIdChanged",r.getMapTypeId())}});r.addListener("heading_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapHeadingChanged",r.getHeading())}});r.addListener("tilt_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapTiltChanged",r.getTilt())}});r.addListener("bounds_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapBoundsChanged")}});r.addListener("projection_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapProjectionChanged")}});r.addListener("draggable_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapDraggableChanged")}});r.addListener("streetview_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapStreetviewChanged")}});r.addListener("drag",()=>{if(r&&r.elementId){let i=t(n,r.elementId);if(i&&r.getCenter()){let n=r.getCenter().toJSON(),t={Latitude:n.lat,Longitude:n.lng};i.ref.invokeMethodAsync("MapDrag",t)}}});r.addListener("dragend",()=>{if(r&&r.elementId){let i=t(n,r.elementId);if(i&&r.getCenter()){let n=r.getCenter().toJSON(),t={Latitude:n.lat,Longitude:n.lng};i.ref.invokeMethodAsync("MapDragEnd",t)}}});r.addListener("dragstart",()=>{if(r&&r.elementId){let i=t(n,r.elementId);if(i&&r.getCenter()){let n=r.getCenter().toJSON(),t={Latitude:n.lat,Longitude:n.lng};i.ref.invokeMethodAsync("MapDragStart",t)}}});r.addListener("resize",()=>{if(r&&r.elementId){let i=t(n,r.elementId);if(i){let n={Width:r.getDiv().offsetWidth,Height:r.getDiv().offsetHeight};i.ref.invokeMethodAsync("MapResized",n)}}});r.addListener("tilesloaded",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapTilesLoaded")}});r.addListener("idle",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapIdle")}});n[i].value.ref.invokeMethodAsync("MapInitialized",f)}}};let n=[],i=[];
\ No newline at end of file
+export function init(t,i,r,f,e){if(t&&i&&r){u(n,i,r,f,e);let o="https://maps.googleapis.com/maps/api/js?key=",h=!1,l=document.querySelectorAll("head > script");if(l.forEach(n=>{if(n){let t=n.getAttribute("src");if(t&&t.startsWith(o)){h=!0;return}}}),h){window.google&&window.initGoogleMaps();return}let c=document.createElement("script");c.src="https://polyfill.io/v3/polyfill.min.js?features=default";document.head.appendChild(c);o=o+t+"&callback=initGoogleMaps&libraries=&v=weekly";let s=document.createElement("script");s.src=o;s.defer=!0;document.head.appendChild(s)}}function u(n,t,i,r,u){for(let i=0;i{e.invokeMethodAsync("CustomControlClicked",i)})}}}export function createMarkers(r,u){if(r&&u&&u.length){let o=t(n,r);if(o&&o.map)for(var f=0;f{o.ref.invokeMethodAsync("MarkerClicked",n.id),i&&i.open(o.map,t)})}if(n.draggable){t.addListener("drag",()=>{i("MarkerDrag",n.id,t.getPosition().toJSON())});t.addListener("dragend",()=>{i("MarkerDragEnd",n.id,t.getPosition().toJSON())});t.addListener("dragstart",()=>{i("MarkerDragStart",n.id,t.getPosition().toJSON())});function i(n,t,i){let r={Latitude:i.lat,Longitude:i.lng};o.ref.invokeMethodAsync(n,t,r)}}}}}export function removeMarkers(r,u){if(r&&u&&u.length){let e=t(n,r);if(e&&e.map)for(var f=0;f{if(n.id==t.id){t.setMap(null);i.splice(r,1);return}})}}}function e(n,t){t&&n&&(t.setPosition({lat:n.position.latitude,lng:n.position.longitude}),t.anchorPoint=n.anchorPoint?{x:n.anchorPoint.x,y:n.anchorPoint.y}:null,t.setAnimation(n.animation),t.setClickable(n.clickable),t.crossOnDrag=n.crossOnDrag,t.setCursor(n.cursor),t.setDraggable(n.draggable),t.setIcon(n.icon),t.setLabel(n.label),t.setOpacity(n.opacity),t.optimized=n.optimized,t.setShape(n.shape),t.setTitle(n.title),t.setVisible(n.visible),t.setZIndex(n.zIndex))}export function getAddressCoordinates(i,u){r(u,function(r){if(r){let u=t(n,i);u&&u.map&&u.ref.invokeMethodAsync("AddressSearch",r)}})}function r(n,t){let i=new google.maps.Geocoder;i.geocode({address:n},function(n,i){i==google.maps.GeocoderStatus.OK&&t(n)})}export function dispose(i){if(i){let r=t(n,i);r.map=null;r.ref=null;f(n,i)}}window.initGoogleMaps=()=>{for(let i=0;i{u(n,"MapClicked")});r.addListener("dblclick",n=>{u(n,"MapDoubleClicked")});r.addListener("contextmenu",n=>{u(n,"MapContextMenu")});r.addListener("mouseup",n=>{u(n,"MapMouseUp")});r.addListener("mousedown",n=>{u(n,"MapMouseDown")});r.addListener("mousemove",n=>{u(n,"MapMouseMove")});r.addListener("mouseover",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapMouseOver")}});r.addListener("mouseout",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapMouseOut")}});r.addListener("center_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);if(i&&r.getCenter()){let n=r.getCenter().toJSON(),t={Latitude:n.lat,Longitude:n.lng};i.ref.invokeMethodAsync("MapCenterChanged",t)}}});r.addListener("zoom_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapZoomChanged",r.getZoom())}});r.addListener("maptypeid_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapTypeIdChanged",r.getMapTypeId())}});r.addListener("heading_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapHeadingChanged",r.getHeading())}});r.addListener("tilt_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapTiltChanged",r.getTilt())}});r.addListener("bounds_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapBoundsChanged")}});r.addListener("projection_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapProjectionChanged")}});r.addListener("draggable_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapDraggableChanged")}});r.addListener("streetview_changed",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapStreetviewChanged")}});r.addListener("drag",()=>{if(r&&r.elementId){let i=t(n,r.elementId);if(i&&r.getCenter()){let n=r.getCenter().toJSON(),t={Latitude:n.lat,Longitude:n.lng};i.ref.invokeMethodAsync("MapDrag",t)}}});r.addListener("dragend",()=>{if(r&&r.elementId){let i=t(n,r.elementId);if(i&&r.getCenter()){let n=r.getCenter().toJSON(),t={Latitude:n.lat,Longitude:n.lng};i.ref.invokeMethodAsync("MapDragEnd",t)}}});r.addListener("dragstart",()=>{if(r&&r.elementId){let i=t(n,r.elementId);if(i&&r.getCenter()){let n=r.getCenter().toJSON(),t={Latitude:n.lat,Longitude:n.lng};i.ref.invokeMethodAsync("MapDragStart",t)}}});r.addListener("resize",()=>{if(r&&r.elementId){let i=t(n,r.elementId);if(i){let n={Width:r.getDiv().offsetWidth,Height:r.getDiv().offsetHeight};i.ref.invokeMethodAsync("MapResized",n)}}});r.addListener("tilesloaded",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapTilesLoaded")}});r.addListener("idle",()=>{if(r&&r.elementId){let i=t(n,r.elementId);i&&i.ref.invokeMethodAsync("MapIdle")}});n[i].value.ref.invokeMethodAsync("MapInitialized",f)}}};let n=[],i=[];
\ No newline at end of file
From a2759dbaf440032d2592358fdcc2b91cfab4a2a0 Mon Sep 17 00:00:00 2001
From: Major
Date: Mon, 21 Jun 2021 21:33:30 +0200
Subject: [PATCH 33/69] Implement Google analytics get/set/event
---
.../Components/GoogleAnalytics.razor | 34 ++++++++--
.../Shared/MainLayout.razor | 15 ++++-
.../Startup.cs | 2 +-
.../_Imports.razor | 4 +-
.../AnalyticsExtension.cs | 15 ++++-
.../Google/GoogleAnalyticsCustomEventArgs.cs | 29 +++++++++
.../Google/GoogleAnalyticsEventTypes.cs | 33 ++++++++++
.../Google/GoogleAnalyticsService.cs | 45 ++++++++-----
.../Majorsoft.Blazor.Extensions.Analytics.xml | 64 ++++++++++++++++---
.../wwwroot/googleAnalytics.js | 10 +++
.../wwwroot/googleAnalytics.min.js | 2 +-
11 files changed, 218 insertions(+), 35 deletions(-)
create mode 100644 src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsCustomEventArgs.cs
create mode 100644 src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsEventTypes.cs
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
index 12523988..cd4eec9f 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
@@ -29,21 +29,45 @@
-@*Permalink*@
+@*Permalink initialize*@
@using Majorsoft.Blazor.Components.PermaLink
@using Microsoft.Extensions.Logging
@using Majorsoft.Blazor.Components.Common.JsInterop.Scroll
@@ -23,10 +23,13 @@
@inject NavigationManager _navigationManager
@inject ILogger _logger
-@*Server hoster Blazor console log*@
+@*Server hosted Blazor console log*@
@using Majorsoft.Blazor.Server.Logging.Console
@inject IBrowserConsoleLoggerService _browserConsoleLogger
+@* Google Analytics *@
+@inject IGoogleAnalyticsService _googleAnalytincsService
+
@implements IDisposable
@implements IAsyncDisposable
@@ -43,6 +46,9 @@
//setup console log
await _browserConsoleLogger.StartLoggerAsync();
+
+ //setup Google analitics
+ await _googleAnalytincsService.InitializeAsync("G-1QD2VGTEWX");
}
}
@@ -57,5 +63,10 @@
{
await _browserConsoleLogger.DisposeAsync();
}
+
+ if(_googleAnalytincsService is not null)
+ {
+ await _googleAnalytincsService.DisposeAsync();
+ }
}
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestServerApp/Startup.cs b/src/Majorsoft.Blazor.Components.TestServerApp/Startup.cs
index 4456c637..aff9b45b 100644
--- a/src/Majorsoft.Blazor.Components.TestServerApp/Startup.cs
+++ b/src/Majorsoft.Blazor.Components.TestServerApp/Startup.cs
@@ -37,7 +37,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddMapExtensions();
services.AddBrowserStorage();
- services.AddGoogleAnalytics();
+ services.AddGoogleAnalyticsForBlazorServer();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
diff --git a/src/Majorsoft.Blazor.Components.TestServerApp/_Imports.razor b/src/Majorsoft.Blazor.Components.TestServerApp/_Imports.razor
index 31bebc3b..26c534e7 100644
--- a/src/Majorsoft.Blazor.Components.TestServerApp/_Imports.razor
+++ b/src/Majorsoft.Blazor.Components.TestServerApp/_Imports.razor
@@ -11,4 +11,6 @@
@using Majorsoft.Blazor.Components.TestApps.Common
@using Majorsoft.Blazor.Components.TestApps.Common.Components
-@using Majorsoft.Blazor.Components.TestApps.Common.Shared
\ No newline at end of file
+@using Majorsoft.Blazor.Components.TestApps.Common.Shared
+
+@using Majorsoft.Blazor.Extensions.Analytics.Google
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/AnalyticsExtension.cs b/src/Majorsoft.Blazor.Extensions.Analytics/AnalyticsExtension.cs
index f3eaf7a1..89e3373d 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/AnalyticsExtension.cs
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/AnalyticsExtension.cs
@@ -11,19 +11,30 @@ public static class AnalyticsExtension
{
///
/// Registers required Google Analytic services into IServiceCollection
+ /// DO NOT CALL with value in case of Blazor Server!
///
/// IServiceCollection instance
- /// Google Tracking Id when provided will be called. DO NOT CALL with value in case of Blazor Server!
+ /// Google Tracking Id when provided will be called. DO NOT CALL with value in case of Blazor Server!
/// IServiceCollection
public static IServiceCollection AddGoogleAnalytics(this IServiceCollection services, string trackingId = "")
{
services.AddTransient();
if (!string.IsNullOrWhiteSpace(trackingId))
{
- services.BuildServiceProvider().GetRequiredService()?.Initialize(trackingId);
+ services.BuildServiceProvider().GetRequiredService()?.InitializeAsync(trackingId);
}
return services;
}
+
+ ///
+ /// Registers required Google Analytic services into IServiceCollection for Blazor Server
+ ///
+ /// IServiceCollection instance
+ /// IServiceCollection
+ public static IServiceCollection AddGoogleAnalyticsForBlazorServer(this IServiceCollection services)
+ {
+ return services.AddGoogleAnalytics();
+ }
}
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsCustomEventArgs.cs b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsCustomEventArgs.cs
new file mode 100644
index 00000000..da782dfe
--- /dev/null
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsCustomEventArgs.cs
@@ -0,0 +1,29 @@
+namespace Majorsoft.Blazor.Extensions.Analytics.Google
+{
+ ///
+ /// Data for custom event.
+ /// For more details see: https://developers.google.com/analytics/devguides/collection/gtagjs/events
+ ///
+ public class GoogleAnalyticsCustomEventArgs
+ {
+ ///
+ /// The value that will appear as the event action in Google Analytics Event reports.
+ ///
+ public string Action { get; set; }
+
+ ///
+ /// The category of the event.
+ ///
+ public string Category { get; set; }
+
+ ///
+ /// The label of the event.
+ ///
+ public string Label { get; set; }
+
+ ///
+ /// A non-negative integer that will appear as the event value.
+ ///
+ public int Value { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsEventTypes.cs b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsEventTypes.cs
new file mode 100644
index 00000000..46d22712
--- /dev/null
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsEventTypes.cs
@@ -0,0 +1,33 @@
+namespace Majorsoft.Blazor.Extensions.Analytics.Google
+{
+ ///
+ /// Event types for Google Analytics
+ /// for event and parameter details see: https://developers.google.com/gtagjs/reference/event
+ ///
+ public enum GoogleAnalyticsEventTypes
+ {
+ add_payment_info,
+ add_to_cart,
+ add_to_wishlist,
+ begin_checkout,
+ checkout_progress,
+ exception,
+ generate_lead,
+ login,
+ page_view,
+ purchase,
+ refund,
+ remove_from_cart,
+ screen_view,
+ search,
+ select_content,
+ set_checkout_option,
+ share,
+ sign_up,
+ timing_complete,
+ view_item,
+ view_item_list,
+ view_promotion,
+ view_search_results
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs
index 81206d26..73a35280 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs
@@ -14,7 +14,7 @@ namespace Majorsoft.Blazor.Extensions.Analytics.Google
public interface IGoogleAnalyticsService : IAsyncDisposable
{
///
- /// Google analytics uniquely Id which was used in method.
+ /// Google analytics uniquely Id which was used in method.
///
string TrackingId { get; }
@@ -23,7 +23,7 @@ public interface IGoogleAnalyticsService : IAsyncDisposable
///
/// Is an identifier that uniquely identifies the target for hits, such as a Google Analytics property
/// Async ValueTask
- ValueTask Initialize(string trackingId);
+ ValueTask InitializeAsync(string trackingId);
///
/// Allows you to add additional configuration information to targets. This is typically product-specific configuration for a product
@@ -32,7 +32,7 @@ public interface IGoogleAnalyticsService : IAsyncDisposable
/// Is an identifier that uniquely identifies the target for hits, such as a Google Analytics property
/// Is one or more optional parameter-value pairs
/// Async ValueTask
- ValueTask Config(string trackingId = "", Dictionary? configInfo = null);
+ ValueTask ConfigAsync(string trackingId = "", Dictionary? configInfo = null);
///
/// Allows you to get various values from gtag.js including values set with the set command.
@@ -40,22 +40,30 @@ public interface IGoogleAnalyticsService : IAsyncDisposable
/// The name of the field to get.
/// Is an identifier that uniquely identifies the target for hits, such as a Google Analytics property
/// Async ValueTask
- ValueTask Get(string fieldName, string trackingId = "");
+ ValueTask GetAsync(string fieldName, string trackingId = "");
///
/// Allows you to set values that persist across all the subsequent gtag() calls on the page.
///
/// Is a key name and the value that is to persist across gtag() calls.
/// Async ValueTask
- ValueTask Set(ExpandoObject parameters);
+ ValueTask SetAsync(ExpandoObject parameters);
///
/// Use the event command to send event data.
///
- /// A recommended event or a custom event name.
+ /// A recommended event
/// Is one or more parameter-value pairs.
/// Async ValueTask
- ValueTask Event(string eventName, Dictionary eventParams);
+ ValueTask EventAsync(GoogleAnalyticsEventTypes eventType, ExpandoObject eventParams);
+
+ ///
+ /// Use the event command to send custom event data.
+ ///
+ /// Custom event name.
+ /// Custom event data
+ /// Async ValueTask
+ ValueTask CustomEventAsync(string customEventName, GoogleAnalyticsCustomEventArgs eventData);
}
///
@@ -64,8 +72,9 @@ public interface IGoogleAnalyticsService : IAsyncDisposable
public class GoogleAnalyticsService : IGoogleAnalyticsService
{
private readonly Lazy> moduleTask;
+ private static string _trackingId; //Service cannot registered as Singleton.
- public string TrackingId { get; private set; }
+ public string TrackingId => _trackingId;
public GoogleAnalyticsService(IJSRuntime jsRuntime)
{
@@ -79,38 +88,44 @@ public GoogleAnalyticsService(IJSRuntime jsRuntime)
moduleTask = new(() => jsRuntime.InvokeAsync("import", js).AsTask());
}
- public async ValueTask Initialize(string trackingId)
+ public async ValueTask InitializeAsync(string trackingId)
{
if(!string.IsNullOrWhiteSpace(TrackingId) || string.IsNullOrWhiteSpace(trackingId)) //Already initializer or wrong id
{
return;
}
- TrackingId = trackingId;
+ _trackingId = trackingId;
var module = await moduleTask.Value;
await module.InvokeVoidAsync("init", trackingId);
}
- public async ValueTask Config(string trackingId = "", Dictionary? configInfo = null)
+ public async ValueTask ConfigAsync(string trackingId = "", Dictionary? configInfo = null)
{
var module = await moduleTask.Value;
await module.InvokeVoidAsync("config", string.IsNullOrWhiteSpace(trackingId) ? TrackingId : trackingId, configInfo?.ToList());
}
- public async ValueTask Get(string fieldName, string trackingId = "")
+ public async ValueTask GetAsync(string fieldName, string trackingId = "")
{
var module = await moduleTask.Value;
await module.InvokeVoidAsync("get", string.IsNullOrWhiteSpace(trackingId) ? TrackingId : trackingId, fieldName); //TODO: callback results
}
- public async ValueTask Set(ExpandoObject parameters)
+ public async ValueTask SetAsync(ExpandoObject parameters)
{
var module = await moduleTask.Value;
await module.InvokeVoidAsync("set", parameters);
}
- public async ValueTask Event(string eventName, Dictionary eventParams)
+ public async ValueTask EventAsync(GoogleAnalyticsEventTypes eventType, ExpandoObject eventParams)
+ {
+ var module = await moduleTask.Value;
+ await module.InvokeVoidAsync("event", eventType.ToString(), eventParams);
+ }
+
+ public async ValueTask CustomEventAsync(string customEventName, GoogleAnalyticsCustomEventArgs eventData)
{
var module = await moduleTask.Value;
- await module.InvokeVoidAsync("event", eventName, eventParams?.ToList());
+ await module.InvokeVoidAsync("customEvent", customEventName, eventData);
}
public async ValueTask DisposeAsync()
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml b/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
index bbd86d39..16b8d887 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
@@ -12,11 +12,51 @@
Registers required Google Analytic services into IServiceCollection
+ DO NOT CALL with value in case of Blazor Server!
IServiceCollection instance
- Google Tracking Id when provided will be called. DO NOT CALL with value in case of Blazor Server!
+ Google Tracking Id when provided will be called. DO NOT CALL with value in case of Blazor Server!
IServiceCollection
+
+
+ Registers required Google Analytic services into IServiceCollection for Blazor Server
+
+ IServiceCollection instance
+ IServiceCollection
+
+
+
+ Data for custom event.
+ For more details see: https://developers.google.com/analytics/devguides/collection/gtagjs/events
+
+
+
+
+ The value that will appear as the event action in Google Analytics Event reports.
+
+
+
+
+ The category of the event.
+
+
+
+
+ The label of the event.
+
+
+
+
+ A non-negative integer that will appear as the event value.
+
+
+
+
+ Event types for Google Analytics
+ for event and parameter details see: https://developers.google.com/gtagjs/reference/event
+
+
Injectable service to handle Google analytics gtag.js.
@@ -24,17 +64,17 @@
- Google analytics uniquely Id which was used in method.
+ Google analytics uniquely Id which was used in method.
-
+
Initialize Google analytics by registering gtag.js to the HTML document. Should be called once.
Is an identifier that uniquely identifies the target for hits, such as a Google Analytics property
Async ValueTask
-
+
Allows you to add additional configuration information to targets. This is typically product-specific configuration for a product
such as Google Ads or Google Analytics.
@@ -43,7 +83,7 @@
Is one or more optional parameter-value pairs
Async ValueTask
-
+
Allows you to get various values from gtag.js including values set with the set command.
@@ -51,21 +91,29 @@
Is an identifier that uniquely identifies the target for hits, such as a Google Analytics property
Async ValueTask
-
+
Allows you to set values that persist across all the subsequent gtag() calls on the page.
Is a key name and the value that is to persist across gtag() calls.
Async ValueTask
-
+
Use the event command to send event data.
- A recommended event or a custom event name.
+ A recommended event
Is one or more parameter-value pairs.
Async ValueTask
+
+
+ Use the event command to send custom event data.
+
+ Custom event name.
+ Custom event data
+ Async ValueTask
+
Implementation of
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js
index a5ddd969..8c325b8f 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js
@@ -62,4 +62,14 @@ export function event(eventName, data) {
if (window.gtag && eventName && data) {
gtag('event', eventName, data);
}
+}
+export function customEvent(eventName, data) {
+ if (window.gtag && eventName && data) {
+ gtag('event', eventName, {
+ 'event_action': data.Action,
+ 'event_category': data.Category,
+ 'event_label': data.Label,
+ 'value': data.Value
+ });
+ }
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.min.js b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.min.js
index 0a1a89f5..e4a28637 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.min.js
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.min.js
@@ -2,4 +2,4 @@ export function init(n){if(n){let i="https://www.googletagmanager.com/gtag/js?id
function gtag() { dataLayer.push(arguments); }
gtag('js', new Date());
- gtag('config', '{0}');`.replace("{0}",n);document.head.appendChild(u)}}}export function config(n,t){n&&window.gtag&>ag("config",n,t)}export function get(n,t){n&&window.gtag&>ag("get",n,t,n=>{console.log(n)})}export function set(n){window.gtag&&n&>ag("set",n)}export function event(n,t){window.gtag&&n&&t&>ag("event",n,t)}
\ No newline at end of file
+ gtag('config', '{0}');`.replace("{0}",n);document.head.appendChild(u)}}}export function config(n,t){n&&window.gtag&>ag("config",n,t)}export function get(n,t){n&&window.gtag&>ag("get",n,t,n=>{console.log(n)})}export function set(n){window.gtag&&n&>ag("set",n)}export function event(n,t){window.gtag&&n&&t&>ag("event",n,t)}export function customEvent(n,t){window.gtag&&n&&t&>ag("event",n,{event_action:t.Action,event_category:t.Category,event_label:t.Label,value:t.Value})}
\ No newline at end of file
From b8fa9f993f84a5671a812742ef07e66152b6d446 Mon Sep 17 00:00:00 2001
From: Major
Date: Mon, 21 Jun 2021 22:13:21 +0200
Subject: [PATCH 34/69] Finished Google Analytics features.
---
.../Components/GoogleAnalytics.razor | 14 ++--
.../_Imports.razor | 1 +
.../Google/GoogleAnalyticsGetEventInfo.cs | 26 +++++++
.../Google/GoogleAnalyticsService.cs | 77 ++++---------------
.../Google/IGoogleAnalyticsService.cs | 65 ++++++++++++++++
.../Majorsoft.Blazor.Extensions.Analytics.xml | 20 +++--
.../wwwroot/googleAnalytics.js | 6 +-
.../wwwroot/googleAnalytics.min.js | 2 +-
8 files changed, 134 insertions(+), 77 deletions(-)
create mode 100644 src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsGetEventInfo.cs
create mode 100644 src/Majorsoft.Blazor.Extensions.Analytics/Google/IGoogleAnalyticsService.cs
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
index cd4eec9f..ea523a14 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
@@ -25,12 +25,18 @@
IGoogleAnalyticsService is an injectable service for enabling
Google Analytics page tracking in Blazor Apps.
+
+
+ To see how Majorsoft.Blazor.Extensions.Analytics works please check the demo code. And Google
+ analytics features.
+
@using System.Dynamic
@inject IGoogleAnalyticsService _googleAnalytincsService
+@inject ILogger _logger
@implements IAsyncDisposable
@code {
@@ -38,19 +44,17 @@
{
if(firstRender)
{
- /*var sessionId = */
- await _googleAnalytincsService.GetAsync("session_id");
+ await _googleAnalytincsService.GetAsync("session_id", async (res) => { _logger.LogInformation($"Google analytics Get result: {res}"); });
//custom set/get
dynamic exp = new ExpandoObject();
exp.test = 27;
await _googleAnalytincsService.SetAsync(exp);
- /*var test =*/
- await _googleAnalytincsService.GetAsync("test");
+ await _googleAnalytincsService.GetAsync("test", async (res) => { _logger.LogInformation($"Google analytics Get result: {res}"); });
dynamic exp2 = new ExpandoObject();
- exp2.search_term = "heeeeeeeeeeee";
+ exp2.search_term = "Searching custom event...";
await _googleAnalytincsService.EventAsync(GoogleAnalyticsEventTypes.search, exp2);
await _googleAnalytincsService.CustomEventAsync("testEvent", new GoogleAnalyticsCustomEventArgs()
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/_Imports.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/_Imports.razor
index 5702ed14..3340f34a 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/_Imports.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/_Imports.razor
@@ -2,6 +2,7 @@
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Components.Routing
+@using Microsoft.Extensions.Logging
@using System.ComponentModel.DataAnnotations
@using System.Collections.ObjectModel
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsGetEventInfo.cs b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsGetEventInfo.cs
new file mode 100644
index 00000000..094f9b80
--- /dev/null
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsGetEventInfo.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Threading.Tasks;
+
+using Microsoft.JSInterop;
+
+namespace Majorsoft.Blazor.Extensions.Analytics.Google
+{
+ ///
+ /// Google analytics Get response event info to handle JS callback
+ ///
+ internal sealed class GoogleAnalyticsGetEventInfo
+ {
+ private readonly Func
+
+
+ Google analytics Get response event info to handle JS callback
+
+
+
+
+ Implementation of
+
+
Injectable service to handle Google analytics gtag.js.
@@ -74,7 +84,7 @@
Is an identifier that uniquely identifies the target for hits, such as a Google Analytics property
Async ValueTask
-
+
Allows you to add additional configuration information to targets. This is typically product-specific configuration for a product
such as Google Ads or Google Analytics.
@@ -83,11 +93,12 @@
Is one or more optional parameter-value pairs
Async ValueTask
-
+
Allows you to get various values from gtag.js including values set with the set command.
The name of the field to get.
+ A function that will be invoked with the requested field, or undefined if it is unset.
Is an identifier that uniquely identifies the target for hits, such as a Google Analytics property
Async ValueTask
@@ -114,10 +125,5 @@
Custom event data
Async ValueTask
-
-
- Implementation of
-
-
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js
index 8c325b8f..7aa43aac 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js
@@ -45,11 +45,11 @@ export function config(trackingId, data) {
gtag('config', trackingId, data);
}
}
-export function get(trackingId, fieldName) {
+export function get(trackingId, fieldName, dotnetRef) {
if (trackingId && window.gtag) {
gtag('get', trackingId, fieldName, (result) => {
- //TOOD: callback method here...
- console.log(result);
+ dotnetRef.invokeMethodAsync("GoogleAnalyticsResult", result);
+ //console.log(result);
});
}
}
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.min.js b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.min.js
index e4a28637..f8f74cf8 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.min.js
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.min.js
@@ -2,4 +2,4 @@ export function init(n){if(n){let i="https://www.googletagmanager.com/gtag/js?id
function gtag() { dataLayer.push(arguments); }
gtag('js', new Date());
- gtag('config', '{0}');`.replace("{0}",n);document.head.appendChild(u)}}}export function config(n,t){n&&window.gtag&>ag("config",n,t)}export function get(n,t){n&&window.gtag&>ag("get",n,t,n=>{console.log(n)})}export function set(n){window.gtag&&n&>ag("set",n)}export function event(n,t){window.gtag&&n&&t&>ag("event",n,t)}export function customEvent(n,t){window.gtag&&n&&t&>ag("event",n,{event_action:t.Action,event_category:t.Category,event_label:t.Label,value:t.Value})}
\ No newline at end of file
+ gtag('config', '{0}');`.replace("{0}",n);document.head.appendChild(u)}}}export function config(n,t){n&&window.gtag&>ag("config",n,t)}export function get(n,t,i){n&&window.gtag&>ag("get",n,t,n=>{i.invokeMethodAsync("GoogleAnalyticsResult",n)})}export function set(n){window.gtag&&n&>ag("set",n)}export function event(n,t){window.gtag&&n&&t&>ag("event",n,t)}export function customEvent(n,t){window.gtag&&n&&t&>ag("event",n,{event_action:t.Action,event_category:t.Category,event_label:t.Label,value:t.Value})}
\ No newline at end of file
From 5b77a790ff1d917e97b6e6d7c72d95cef9985fbe Mon Sep 17 00:00:00 2001
From: Major
Date: Tue, 22 Jun 2021 08:21:01 +0200
Subject: [PATCH 35/69] Simplify and unify Google analytics initialization.
---
.../Program.cs | 2 +-
.../Shared/MainLayout.razor | 4 +++
.../Shared/MainLayout.razor | 13 +++------
.../Startup.cs | 2 +-
.../AnalyticsExtension.cs | 19 +------------
.../Google/GoogleAnalyticsInitializer.razor | 27 +++++++++++++++++++
.../Majorsoft.Blazor.Extensions.Analytics.xml | 16 +++++------
.../wwwroot/googleAnalytics.js | 1 -
8 files changed, 43 insertions(+), 41 deletions(-)
create mode 100644 src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsInitializer.razor
diff --git a/src/Majorsoft.Blazor.Components.TestApp/Program.cs b/src/Majorsoft.Blazor.Components.TestApp/Program.cs
index bbdbcf61..6ac84a0b 100644
--- a/src/Majorsoft.Blazor.Components.TestApp/Program.cs
+++ b/src/Majorsoft.Blazor.Components.TestApp/Program.cs
@@ -29,7 +29,7 @@ public static async Task Main(string[] args)
builder.Services.AddMapExtensions();
builder.Services.AddBrowserStorage();
- builder.Services.AddGoogleAnalytics("G-1QD2VGTEWX");
+ builder.Services.AddGoogleAnalytics();
builder.Logging.AddBrowserConsole()
.SetMinimumLevel(LogLevel.Debug).AddFilter("Microsoft", LogLevel.Information);
diff --git a/src/Majorsoft.Blazor.Components.TestApp/Shared/MainLayout.razor b/src/Majorsoft.Blazor.Components.TestApp/Shared/MainLayout.razor
index 51ef1511..ba1aaea7 100644
--- a/src/Majorsoft.Blazor.Components.TestApp/Shared/MainLayout.razor
+++ b/src/Majorsoft.Blazor.Components.TestApp/Shared/MainLayout.razor
@@ -16,6 +16,10 @@
+@* Google Analytics initialize*@
+@using Majorsoft.Blazor.Extensions.Analytics.Google
+
+
@using Majorsoft.Blazor.Components.PermaLink
@inject IPermaLinkWatcherService _permalinkWatcher
@implements IDisposable
diff --git a/src/Majorsoft.Blazor.Components.TestServerApp/Shared/MainLayout.razor b/src/Majorsoft.Blazor.Components.TestServerApp/Shared/MainLayout.razor
index e9a55e4f..77e894ea 100644
--- a/src/Majorsoft.Blazor.Components.TestServerApp/Shared/MainLayout.razor
+++ b/src/Majorsoft.Blazor.Components.TestServerApp/Shared/MainLayout.razor
@@ -27,8 +27,9 @@
@using Majorsoft.Blazor.Server.Logging.Console
@inject IBrowserConsoleLoggerService _browserConsoleLogger
-@* Google Analytics *@
-@inject IGoogleAnalyticsService _googleAnalytincsService
+@* Google Analytics initialize*@
+@using Majorsoft.Blazor.Extensions.Analytics.Google
+
@implements IDisposable
@implements IAsyncDisposable
@@ -46,9 +47,6 @@
//setup console log
await _browserConsoleLogger.StartLoggerAsync();
-
- //setup Google analitics
- await _googleAnalytincsService.InitializeAsync("G-1QD2VGTEWX");
}
}
@@ -63,10 +61,5 @@
{
await _browserConsoleLogger.DisposeAsync();
}
-
- if(_googleAnalytincsService is not null)
- {
- await _googleAnalytincsService.DisposeAsync();
- }
}
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestServerApp/Startup.cs b/src/Majorsoft.Blazor.Components.TestServerApp/Startup.cs
index aff9b45b..4456c637 100644
--- a/src/Majorsoft.Blazor.Components.TestServerApp/Startup.cs
+++ b/src/Majorsoft.Blazor.Components.TestServerApp/Startup.cs
@@ -37,7 +37,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddMapExtensions();
services.AddBrowserStorage();
- services.AddGoogleAnalyticsForBlazorServer();
+ services.AddGoogleAnalytics();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/AnalyticsExtension.cs b/src/Majorsoft.Blazor.Extensions.Analytics/AnalyticsExtension.cs
index 89e3373d..51be9b4e 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/AnalyticsExtension.cs
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/AnalyticsExtension.cs
@@ -11,30 +11,13 @@ public static class AnalyticsExtension
{
///
/// Registers required Google Analytic services into IServiceCollection
- /// DO NOT CALL with value in case of Blazor Server!
///
/// IServiceCollection instance
- /// Google Tracking Id when provided will be called. DO NOT CALL with value in case of Blazor Server!
/// IServiceCollection
- public static IServiceCollection AddGoogleAnalytics(this IServiceCollection services, string trackingId = "")
+ public static IServiceCollection AddGoogleAnalytics(this IServiceCollection services)
{
services.AddTransient();
- if (!string.IsNullOrWhiteSpace(trackingId))
- {
- services.BuildServiceProvider().GetRequiredService()?.InitializeAsync(trackingId);
- }
-
return services;
}
-
- ///
- /// Registers required Google Analytic services into IServiceCollection for Blazor Server
- ///
- /// IServiceCollection instance
- /// IServiceCollection
- public static IServiceCollection AddGoogleAnalyticsForBlazorServer(this IServiceCollection services)
- {
- return services.AddGoogleAnalytics();
- }
}
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsInitializer.razor b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsInitializer.razor
new file mode 100644
index 00000000..6907157d
--- /dev/null
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsInitializer.razor
@@ -0,0 +1,27 @@
+@inject IGoogleAnalyticsService _googleAnalytincsService
+
+@implements IAsyncDisposable
+
+@code {
+ ///
+ /// Google Analytics Tracking id
+ ///
+ [Parameter] public string TrackingId { get; set; }
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender)
+ {
+ //Initialize Google Analytics once
+ await _googleAnalytincsService.InitializeAsync(TrackingId);
+ }
+ }
+
+ public async ValueTask DisposeAsync()
+ {
+ if (_googleAnalytincsService is not null)
+ {
+ await _googleAnalytincsService.DisposeAsync();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml b/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
index 4b17a8e4..a5e176d2 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
@@ -9,18 +9,9 @@
Extension methods to register required Analytic services into IServiceCollection
-
+
Registers required Google Analytic services into IServiceCollection
- DO NOT CALL with value in case of Blazor Server!
-
- IServiceCollection instance
- Google Tracking Id when provided will be called. DO NOT CALL with value in case of Blazor Server!
- IServiceCollection
-
-
-
- Registers required Google Analytic services into IServiceCollection for Blazor Server
IServiceCollection instance
IServiceCollection
@@ -125,5 +116,10 @@
Custom event data
Async ValueTask
+
+
+ Google Analytics Tracking id
+
+
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js
index 7aa43aac..ce57247b 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/wwwroot/googleAnalytics.js
@@ -49,7 +49,6 @@ export function get(trackingId, fieldName, dotnetRef) {
if (trackingId && window.gtag) {
gtag('get', trackingId, fieldName, (result) => {
dotnetRef.invokeMethodAsync("GoogleAnalyticsResult", result);
- //console.log(result);
});
}
}
From c7a0f249c3d09892dad4100bfa82e885bfcd065d Mon Sep 17 00:00:00 2001
From: Major
Date: Tue, 22 Jun 2021 08:40:39 +0200
Subject: [PATCH 36/69] Component rename.
---
README.md | 1 +
.../Majorsoft.Blazor.Components.TestApp.csproj | 3 +++
.../Pages/AnalyticsPage.razor | 2 +-
.../{GoogleAnalytics.razor => SiteAnalytics.razor} | 6 +++---
.../Pages/AnalyticsPage.razor | 2 +-
.../Majorsoft.Blazor.Components.TestServerApp.csproj | 3 +++
.../Pages/AnalyticsPage.razor | 2 +-
7 files changed, 13 insertions(+), 6 deletions(-)
rename src/Majorsoft.Blazor.Components.TestApps.Common/Components/{GoogleAnalytics.razor => SiteAnalytics.razor} (88%)
diff --git a/README.md b/README.md
index 649343f4..27425504 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,7 @@ Check out our planned components and extensions on the project [Wiki page](https
- **Majorsoft.Blazor.Server.Logging.Console**: Enables [Browser console logging](https://github.com/majorimi/blazor-components/blob/master/.github/docs/ServerHostedLogging.md) for Blazor applications using **Server Hosted model**.
- **Majorsoft.Blazor.WebAssembly.Logging.Console**: Enables [Browser console logging](https://github.com/majorimi/blazor-components/blob/master/.github/docs/WebAssemblyHostedLogging.md) for Blazor applications using **WebAssembly Hosting model**.
- **Majorsoft.Blazor.Extensions.BrowserStorage**: Enables [Browser Local and Session storages and Cookies store](https://github.com/majorimi/blazor-components/blob/master/.github/docs/BrowserStorage.md) access for Blazor applications.
+- **Majorsoft.Blazor.Extensions.Analytics**: Enables [Analytics services usage](https://github.com/majorimi/blazor-components/blob/master/.github/docs/Analytics.md) in WebAssemply Apps e.g. Google Analytics, etc.
### **Majorsoft Blazor Components**
diff --git a/src/Majorsoft.Blazor.Components.TestApp/Majorsoft.Blazor.Components.TestApp.csproj b/src/Majorsoft.Blazor.Components.TestApp/Majorsoft.Blazor.Components.TestApp.csproj
index de3f4c56..99091612 100644
--- a/src/Majorsoft.Blazor.Components.TestApp/Majorsoft.Blazor.Components.TestApp.csproj
+++ b/src/Majorsoft.Blazor.Components.TestApp/Majorsoft.Blazor.Components.TestApp.csproj
@@ -43,6 +43,9 @@
+
+ true
+ true
diff --git a/src/Majorsoft.Blazor.Components.TestApp/Pages/AnalyticsPage.razor b/src/Majorsoft.Blazor.Components.TestApp/Pages/AnalyticsPage.razor
index 9850231d..a6cd0ab8 100644
--- a/src/Majorsoft.Blazor.Components.TestApp/Pages/AnalyticsPage.razor
+++ b/src/Majorsoft.Blazor.Components.TestApp/Pages/AnalyticsPage.razor
@@ -1,3 +1,3 @@
@page "/analytics"
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/SiteAnalytics.razor
similarity index 88%
rename from src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
rename to src/Majorsoft.Blazor.Components.TestApps.Common/Components/SiteAnalytics.razor
index ea523a14..905dbc7b 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GoogleAnalytics.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/SiteAnalytics.razor
@@ -3,7 +3,7 @@
Website Analytics extensions
- Blazor extension that enables WebAssemply site analytics e.g. Google, etc. For usage see source code and docs on
+ Blazor extension that enables analytics services usage in WebAssemply Apps e.g. Google Analytics, etc. For usage see source code and docs on
Github.
Majorsoft.Blazor.Extensions.Analytics package is available on Nuget
@@ -28,7 +28,7 @@
To see how Majorsoft.Blazor.Extensions.Analytics works please check the demo code. And Google
- analytics features.
+ analytics features since this extension mostly a JS wrapper for gtag JS.
@@ -36,7 +36,7 @@
@using System.Dynamic
@inject IGoogleAnalyticsService _googleAnalytincsService
-@inject ILogger _logger
+@inject ILogger _logger
@implements IAsyncDisposable
@code {
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Pages/AnalyticsPage.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Pages/AnalyticsPage.razor
index 9850231d..a6cd0ab8 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Pages/AnalyticsPage.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Pages/AnalyticsPage.razor
@@ -1,3 +1,3 @@
@page "/analytics"
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestServerApp/Majorsoft.Blazor.Components.TestServerApp.csproj b/src/Majorsoft.Blazor.Components.TestServerApp/Majorsoft.Blazor.Components.TestServerApp.csproj
index d03986f3..e344d3e8 100644
--- a/src/Majorsoft.Blazor.Components.TestServerApp/Majorsoft.Blazor.Components.TestServerApp.csproj
+++ b/src/Majorsoft.Blazor.Components.TestServerApp/Majorsoft.Blazor.Components.TestServerApp.csproj
@@ -11,6 +11,9 @@
+
+ true
+ true
diff --git a/src/Majorsoft.Blazor.Components.TestServerApp/Pages/AnalyticsPage.razor b/src/Majorsoft.Blazor.Components.TestServerApp/Pages/AnalyticsPage.razor
index 9850231d..a6cd0ab8 100644
--- a/src/Majorsoft.Blazor.Components.TestServerApp/Pages/AnalyticsPage.razor
+++ b/src/Majorsoft.Blazor.Components.TestServerApp/Pages/AnalyticsPage.razor
@@ -1,3 +1,3 @@
@page "/analytics"
-
\ No newline at end of file
+
\ No newline at end of file
From 4244e2722cdc282f55e7b33c9d0309ffa1c28dfb Mon Sep 17 00:00:00 2001
From: Major
Date: Tue, 22 Jun 2021 19:07:55 +0200
Subject: [PATCH 37/69] Docs page for Google Analytics.
---
.github/docs/Analytics.md | 168 ++++++++++++++++++
README.md | 2 +-
.../Components/SiteAnalytics.razor | 18 +-
.../Google/GoogleAnalyticsInitializer.razor | 4 +-
.../Google/GoogleAnalyticsService.cs | 2 +-
.../Google/IGoogleAnalyticsService.cs | 1 +
.../Majorsoft.Blazor.Extensions.Analytics.xml | 3 +-
7 files changed, 187 insertions(+), 11 deletions(-)
create mode 100644 .github/docs/Analytics.md
diff --git a/.github/docs/Analytics.md b/.github/docs/Analytics.md
new file mode 100644
index 00000000..42dcf152
--- /dev/null
+++ b/.github/docs/Analytics.md
@@ -0,0 +1,168 @@
+Blazor Components Analytics extension
+============
+[![Build Status](https://dev.azure.com/major-soft/GitHub/_apis/build/status/blazor-components/blazor-components-build-check)](https://dev.azure.com/major-soft/GitHub/_build/latest?definitionId=6)
+[![Package Version](https://img.shields.io/nuget/v/Majorsoft.Blazor.Components.Analytics?label=Latest%20Version)](https://www.nuget.org/packages/Majorsoft.Blazor.Components.Analytics/)
+[![NuGet Downloads](https://img.shields.io/nuget/dt/Majorsoft.Blazor.Components.Analytics?label=Downloads)](https://www.nuget.org/packages/Majorsoft.Blazor.Components.Analytics/)
+[![License](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/majorimi/blazor-components/blob/master/LICENSE)
+
+# About
+
+Blazor extension that enables analytics services usage for Blazor applications e.g. Google Analytics, etc.
+**All components work with WebAssembly and Server hosted models** (Blazor server side configuration is different).
+For code examples [see usage](https://github.com/majorimi/blazor-components/blob/master/src/Majorsoft.Blazor.Components.TestApps.Common/Components/SiteAnalytics.razor).
+
+You can try it out by using the [demo app](https://blazorextensions.z6.web.core.windows.net/analytics).
+
+# Services
+
+- **`Google Analytics`**: is a web analytics service offered by Google that tracks and reports website traffic, etc. inside the Google Marketing Platform.
+`IGoogleAnalyticsService` is an injectable service for enabling [Google Analytics](https://support.google.com/analytics/answer/1008015?hl=en#) page tracking in Blazor Apps.
+To make the initialization simple use `GoogleAnalyticsInitializer` component in your `MainLayout.razor` page and provide Google Analytics `TrackingId`.
+
+## `Google Analytics` extension
+This is a JS wrapper for web analytics service offered by Google that tracks and reports website traffic, etc. inside the Google Marketing Platform.
+
+### `PermaLinkElement` component
+A convenient wrapper component for `IGoogleAnalyticsService` to make Google Analytics initialize simple.
+
+#### Properties
+- **`TrackingId`**: **`string TrackingId { get; set; }` - Required**
+Google Analytics TrackingId provided on Google Analytics manage page.
+
+### `IGoogleAnalyticsService` service
+Injectable service to handle Google analytics `gtag.js`.
+
+#### Functions
+- **`InitializeAsync()`**: **`ValueTask InitializeAsync(string trackingId)`**
+Initialize Google analytics by registering gtag.js to the HTML document. **Should be called once.
+ Do not call this method if you used `GoogleAnalyticsInitializer`.**
+- **`ConfigAsync()`**: **`ValueTask ConfigAsync(string trackingId = "", ExpandoObject? configInfo = null)`**
+Allows you to add additional configuration information to targets. This is typically product-specific configuration for a product
+such as Google Ads or Google Analytics.
+- **`GetAsync()`**: **``**
+Allows you to get various values from gtag.js including values set with the set command.
+- **`SetAsync()`**: **``**
+ Allows you to set values that persist across all the subsequent gtag() calls on the page.
+- **`EventAsync()`**: **``**
+Use the event command to send event data.
+- **`CustomEventAsync()`**: **``**
+Use the event command to send custom event data.
+
+# Configuration
+
+## Installation
+
+**Majorsoft.Blazor.Components.Analytics** is available on [NuGet](https://www.nuget.org/packages/Majorsoft.Blazor.Components.Analytics/).
+
+```sh
+dotnet add package Majorsoft.Blazor.Components.Analytics
+```
+Use the `--version` option to specify a [preview version](https://www.nuget.org/packages/Majorsoft.Blazor.Components.Analytics/absoluteLatest) to install.
+
+## Usage
+
+Add using statement to your Blazor .razor file. Or globally reference it into `_Imports.razor` file.
+```
+@using Majorsoft.Blazor.Components.Analytics
+@*Google Analytics*@
+@using Majorsoft.Blazor.Components.Analytics.Google
+```
+
+#### WebAssembly projects
+
+**In case of WebAssembly project register services in your `Program.cs` file:**
+```
+using Majorsoft.Blazor.Components.Analytics;
+...
+public static async Task Main(string[] args)
+{
+ var builder = WebAssemblyHostBuilder.CreateDefault(args);
+
+ //Register service
+ builder.Services.AddGoogleAnalytics();
+}
+```
+
+**Use `MainLayout.razor` file for WebAssembly project to initialize Google gtag.js only once:**
+
+```
+@*Google Analytics initialize*@
+
+
+@code {
+}
+```
+
+#### Server hosted projects
+**In case of Server hosted project register dependency services in your `Startup.cs` file:**
+
+```
+@using Majorsoft.Blazor.Components.Analytics
+...
+
+public void ConfigureServices(IServiceCollection services)
+{
+ //Register service
+ services.AddGoogleAnalytics();
+}
+```
+
+**Use `MainLayout.razor` file for WebAssembly project to initialize Google gtag.js only once:**
+```
+@*Google Analytics initialize*@
+
+
+@code {
+}
+```
+
+#### Using `IGoogleAnalyticsService` service
+
+Following code example shows how to Set and Get custom values. Also shows sending events and custom events.
+For full features supported by Google Analytics please see [docs page](https://developers.google.com/gtagjs/reference/api).
+
+```
+@using System.Dynamic
+@inject IGoogleAnalyticsService _googleAnalytincsService
+@implements IAsyncDisposable
+
+@code{
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if(firstRender)
+ {
+ await _googleAnalytincsService.GetAsync("session_id", async (res) => { _logger.LogInformation($"Google analytics Get result: {res}"); });
+
+ //Custom set
+ dynamic exp = new ExpandoObject();
+ exp.test = 27;
+
+ await _googleAnalytincsService.SetAsync(exp);
+
+ //Get cutoms set value
+ await _googleAnalytincsService.GetAsync("test", async (res) => { _logger.LogInformation($"Google analytics Get result: {res}"); });
+
+ //Built in Search event usage
+ dynamic exp2 = new ExpandoObject();
+ exp2.search_term = "Searching custom event...";
+ await _googleAnalytincsService.EventAsync(GoogleAnalyticsEventTypes.search, exp2);
+
+ //Custom event usage
+ await _googleAnalytincsService.CustomEventAsync("testEvent", new GoogleAnalyticsCustomEventArgs()
+ {
+ Action = "Test action",
+ Category = "Test category",
+ Label = "Test label",
+ Value = 1234
+ });
+
+
+ public async ValueTask DisposeAsync()
+ {
+ if(_googleAnalytincsService is not null)
+ {
+ await _googleAnalytincsService.DisposeAsync();
+ }
+ }
+}
+```
\ No newline at end of file
diff --git a/README.md b/README.md
index 27425504..111d3c53 100644
--- a/README.md
+++ b/README.md
@@ -55,7 +55,7 @@ Check out our planned components and extensions on the project [Wiki page](https
- **Majorsoft.Blazor.Server.Logging.Console**: Enables [Browser console logging](https://github.com/majorimi/blazor-components/blob/master/.github/docs/ServerHostedLogging.md) for Blazor applications using **Server Hosted model**.
- **Majorsoft.Blazor.WebAssembly.Logging.Console**: Enables [Browser console logging](https://github.com/majorimi/blazor-components/blob/master/.github/docs/WebAssemblyHostedLogging.md) for Blazor applications using **WebAssembly Hosting model**.
- **Majorsoft.Blazor.Extensions.BrowserStorage**: Enables [Browser Local and Session storages and Cookies store](https://github.com/majorimi/blazor-components/blob/master/.github/docs/BrowserStorage.md) access for Blazor applications.
-- **Majorsoft.Blazor.Extensions.Analytics**: Enables [Analytics services usage](https://github.com/majorimi/blazor-components/blob/master/.github/docs/Analytics.md) in WebAssemply Apps e.g. Google Analytics, etc.
+- **Majorsoft.Blazor.Extensions.Analytics**: Enables [Analytics services usage](https://github.com/majorimi/blazor-components/blob/master/.github/docs/Analytics.md) for Blazor applications e.g. Google Analytics, etc.
### **Majorsoft Blazor Components**
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/SiteAnalytics.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/SiteAnalytics.razor
index 905dbc7b..c1e24e34 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/SiteAnalytics.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/SiteAnalytics.razor
@@ -3,7 +3,7 @@
Website Analytics extensions
- Blazor extension that enables analytics services usage in WebAssemply Apps e.g. Google Analytics, etc. For usage see source code and docs on
+ Blazor extension that enables analytics services usage for Blazor applications e.g. Google Analytics, etc. For usage see source code and docs on
Github.
Majorsoft.Blazor.Extensions.Analytics package is available on Nuget
@@ -24,11 +24,13 @@
IGoogleAnalyticsService is an injectable service for enabling
Google Analytics page tracking in Blazor Apps.
+ To make the initialization simple use GoogleAnalyticsInitializer component in your MainLayout.razor page and provide Google Analytics TrackingId.
To see how Majorsoft.Blazor.Extensions.Analytics works please check the demo code. And Google
- analytics features since this extension mostly a JS wrapper for gtag JS.
+ analytics features since this extension mostly a JS wrapper for gtag.js.
+
@@ -46,23 +48,27 @@
{
await _googleAnalytincsService.GetAsync("session_id", async (res) => { _logger.LogInformation($"Google analytics Get result: {res}"); });
- //custom set/get
+ //Custom set
dynamic exp = new ExpandoObject();
exp.test = 27;
await _googleAnalytincsService.SetAsync(exp);
+
+ //Get cutoms set value
await _googleAnalytincsService.GetAsync("test", async (res) => { _logger.LogInformation($"Google analytics Get result: {res}"); });
+ //Built in Search event usage
dynamic exp2 = new ExpandoObject();
exp2.search_term = "Searching custom event...";
await _googleAnalytincsService.EventAsync(GoogleAnalyticsEventTypes.search, exp2);
+ //Custom event usage
await _googleAnalytincsService.CustomEventAsync("testEvent", new GoogleAnalyticsCustomEventArgs()
{
Action = "Test action",
- Category = "cat",
- Label = "label",
- Value = 22
+ Category = "Test category",
+ Label = "Test label",
+ Value = 1234
});
}
}
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsInitializer.razor b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsInitializer.razor
index 6907157d..6d003891 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsInitializer.razor
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsInitializer.razor
@@ -4,9 +4,9 @@
@code {
///
- /// Google Analytics Tracking id
+ /// Google Analytics TrackingId.
///
- [Parameter] public string TrackingId { get; set; }
+ [Parameter] public string TrackingId { get; set; } = "";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs
index e52ddcfb..9ff5815e 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Google/GoogleAnalyticsService.cs
@@ -15,7 +15,7 @@ public class GoogleAnalyticsService : IGoogleAnalyticsService
{
private List> _dotNetObjectReferences;
private readonly Lazy> moduleTask;
- private static string _trackingId; //Service cannot registered as Singleton.
+ private static string _trackingId = ""; //Service cannot registered as Singleton.
public string TrackingId => _trackingId;
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Google/IGoogleAnalyticsService.cs b/src/Majorsoft.Blazor.Extensions.Analytics/Google/IGoogleAnalyticsService.cs
index 9cfaa5dc..79762ad7 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/Google/IGoogleAnalyticsService.cs
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Google/IGoogleAnalyticsService.cs
@@ -16,6 +16,7 @@ public interface IGoogleAnalyticsService : IAsyncDisposable
///
/// Initialize Google analytics by registering gtag.js to the HTML document. Should be called once.
+ /// Do not call this method if you used .
///
/// Is an identifier that uniquely identifies the target for hits, such as a Google Analytics property
/// Async ValueTask
diff --git a/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml b/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
index a5e176d2..c4d5ba03 100644
--- a/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
+++ b/src/Majorsoft.Blazor.Extensions.Analytics/Majorsoft.Blazor.Extensions.Analytics.xml
@@ -71,6 +71,7 @@
Initialize Google analytics by registering gtag.js to the HTML document. Should be called once.
+ Do not call this method if you used .
Is an identifier that uniquely identifies the target for hits, such as a Google Analytics property
Async ValueTask
@@ -118,7 +119,7 @@
- Google Analytics Tracking id
+ Google Analytics TrackingId.
From 23419112be3a290667c8eb9a5017888f7ebf507a Mon Sep 17 00:00:00 2001
From: Major
Date: Tue, 22 Jun 2021 19:51:02 +0200
Subject: [PATCH 38/69] Created PermalinkWatcher initialize component.
---
.../PermaLinkInitializer.razor | 36 +++++++++++++++++++
.../Shared/MainLayout.razor | 17 +++------
.../Shared/MainLayout.razor | 19 +---------
3 files changed, 41 insertions(+), 31 deletions(-)
create mode 100644 src/Majorsoft.Blazor.Components.PermaLink/PermaLinkInitializer.razor
diff --git a/src/Majorsoft.Blazor.Components.PermaLink/PermaLinkInitializer.razor b/src/Majorsoft.Blazor.Components.PermaLink/PermaLinkInitializer.razor
new file mode 100644
index 00000000..9f46c100
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.PermaLink/PermaLinkInitializer.razor
@@ -0,0 +1,36 @@
+@using Microsoft.Extensions.Logging
+@using Majorsoft.Blazor.Components.Common.JsInterop.Scroll
+
+@inject IScrollHandler _scrollHandler
+@inject NavigationManager _navigationManager
+@inject ILogger _logger
+
+@implements IDisposable
+@implements IAsyncDisposable
+
+@code {
+ private IPermaLinkWatcherService _permalinkWatcher;
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender)
+ {
+ //setup permalink
+ _permalinkWatcher = new PermaLinkWatcherService(_scrollHandler, _navigationManager, _logger);
+ _permalinkWatcher.WatchPermaLinks();
+ }
+ }
+
+ public async ValueTask DisposeAsync()
+ {
+ if (_scrollHandler is not null)
+ {
+ await _scrollHandler.DisposeAsync();
+ }
+ }
+
+ public void Dispose()
+ {
+ _permalinkWatcher?.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApp/Shared/MainLayout.razor b/src/Majorsoft.Blazor.Components.TestApp/Shared/MainLayout.razor
index ba1aaea7..1231fe45 100644
--- a/src/Majorsoft.Blazor.Components.TestApp/Shared/MainLayout.razor
+++ b/src/Majorsoft.Blazor.Components.TestApp/Shared/MainLayout.razor
@@ -16,22 +16,13 @@
+@*Permalink initialize*@
+@using Majorsoft.Blazor.Components.PermaLink
+
+
@* Google Analytics initialize*@
@using Majorsoft.Blazor.Extensions.Analytics.Google
-@using Majorsoft.Blazor.Components.PermaLink
-@inject IPermaLinkWatcherService _permalinkWatcher
-@implements IDisposable
-
@code {
- protected override void OnInitialized()
- {
- _permalinkWatcher.WatchPermaLinks();
- }
-
- public void Dispose()
- {
- _permalinkWatcher.Dispose();
- }
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestServerApp/Shared/MainLayout.razor b/src/Majorsoft.Blazor.Components.TestServerApp/Shared/MainLayout.razor
index 77e894ea..29fdbe2d 100644
--- a/src/Majorsoft.Blazor.Components.TestServerApp/Shared/MainLayout.razor
+++ b/src/Majorsoft.Blazor.Components.TestServerApp/Shared/MainLayout.razor
@@ -16,12 +16,7 @@
@*Permalink initialize*@
@using Majorsoft.Blazor.Components.PermaLink
-@using Microsoft.Extensions.Logging
-@using Majorsoft.Blazor.Components.Common.JsInterop.Scroll
-
-@inject IScrollHandler _scrollHandler
-@inject NavigationManager _navigationManager
-@inject ILogger _logger
+
@*Server hosted Blazor console log*@
@using Majorsoft.Blazor.Server.Logging.Console
@@ -31,30 +26,18 @@
@using Majorsoft.Blazor.Extensions.Analytics.Google
-@implements IDisposable
@implements IAsyncDisposable
@code {
- private IPermaLinkWatcherService _permalinkWatcher;
-
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
- //setup permalink
- _permalinkWatcher = new PermaLinkWatcherService(_scrollHandler, _navigationManager, _logger);
- _permalinkWatcher.WatchPermaLinks();
-
//setup console log
await _browserConsoleLogger.StartLoggerAsync();
}
}
- public void Dispose()
- {
- _permalinkWatcher?.Dispose();
- }
-
public async ValueTask DisposeAsync()
{
if (_browserConsoleLogger is not null)
From 83760339201725c75c15523e338210f76fa86c1a Mon Sep 17 00:00:00 2001
From: Major
Date: Tue, 22 Jun 2021 19:51:25 +0200
Subject: [PATCH 39/69] Make demo components works with Sever side Blazor.
---
.../Components/BrowserStorage.razor | 5 ++++-
.../Components/JsDemo/LangJs.razor | 6 +++++-
.../Components/JsDemo/MouseJs.razor | 5 ++++-
.../Components/JsDemo/ResizeJs.razor | 5 ++++-
.../Components/JsDemo/ScrollJs.razor | 5 ++++-
.../Components/MapsGoogle.razor | 5 ++++-
6 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/BrowserStorage.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/BrowserStorage.razor
index 867aeb57..98e6e0fa 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/BrowserStorage.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/BrowserStorage.razor
@@ -193,8 +193,11 @@
public int Age { get; set; }
}
- protected override async Task OnInitializedAsync()
+ protected override async Task OnAfterRenderAsync(bool firstRender)
{
+ if (!firstRender)
+ return;
+
//LocalStorage
await InsertLocalStorageItems();
_localStorageCount = await _localStorageService.CountAsync();
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/LangJs.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/LangJs.razor
index d033841e..c4b64816 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/LangJs.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/LangJs.razor
@@ -20,9 +20,13 @@
@inject ILanguageService _languageService;
@code {
- protected override async Task OnInitializedAsync()
+ protected override async Task OnAfterRenderAsync(bool firstRender)
{
+ if (!firstRender)
+ return;
+
_detectedBrowserLang = await _languageService.GetBrowserLanguageAsync();
+ StateHasChanged();
}
//Broswer lang
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/MouseJs.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/MouseJs.razor
index 886f1992..3684f2d9 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/MouseJs.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/MouseJs.razor
@@ -25,8 +25,11 @@
@inject IGlobalMouseEventHandler _globalMouseEventHandler;
@code {
- protected override async Task OnInitializedAsync()
+ protected override async Task OnAfterRenderAsync(bool firstRender)
{
+ if (!firstRender)
+ return;
+
await GlobalClickEventHandler();
}
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ResizeJs.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ResizeJs.razor
index fb3f6fda..3611eb52 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ResizeJs.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ResizeJs.razor
@@ -33,8 +33,11 @@
@code {
private string _resizeEventId = null;
- protected override async Task OnInitializedAsync()
+ protected override async Task OnAfterRenderAsync(bool firstRender)
{
+ if (!firstRender)
+ return;
+
await ResizeEventHandler();
_pageSize = await _resizeHandler.GetPageSizeAsync();
}
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
index 432c6cc2..2eaf9dc5 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/JsDemo/ScrollJs.razor
@@ -117,8 +117,11 @@
@code {
private string _scrollEventId = null;
- protected override async Task OnInitializedAsync()
+ protected override async Task OnAfterRenderAsync(bool firstRender)
{
+ if (!firstRender)
+ return;
+
await ScrollEventHandler();
}
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/MapsGoogle.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/MapsGoogle.razor
index 2740e542..1f97aa32 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/MapsGoogle.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/MapsGoogle.razor
@@ -355,8 +355,11 @@
@code {
private string _googleMapsApiKey = "AIzaSyAv-6SailPQN1R5PytUAkbdaGI9IHZTU5s";
- protected override void OnInitialized()
+ protected override async Task OnAfterRenderAsync(bool firstRender)
{
+ if (!firstRender)
+ return;
+
//Static map
_staticMapMarkers.ElementAt(0).Locations.Add(new GeolocationData(1.111, 2.222));
_staticMapMarkers.ElementAt(1).Locations.Add(new GeolocationData(17.111, 33.222));
From 222e5d34cf8eb2020f2b5d480fc21bd38a14e460 Mon Sep 17 00:00:00 2001
From: Major
Date: Tue, 22 Jun 2021 21:03:55 +0200
Subject: [PATCH 40/69] Renamed Permalink initializers.
---
...azor => PermaLinkBlazorServerInitializer.razor} | 0
.../PermalinkBlazorWasmInitializer.razor | 14 ++++++++++++++
.../Shared/MainLayout.razor | 2 +-
.../Shared/MainLayout.razor | 2 +-
4 files changed, 16 insertions(+), 2 deletions(-)
rename src/Majorsoft.Blazor.Components.PermaLink/{PermaLinkInitializer.razor => PermaLinkBlazorServerInitializer.razor} (100%)
create mode 100644 src/Majorsoft.Blazor.Components.PermaLink/PermalinkBlazorWasmInitializer.razor
diff --git a/src/Majorsoft.Blazor.Components.PermaLink/PermaLinkInitializer.razor b/src/Majorsoft.Blazor.Components.PermaLink/PermaLinkBlazorServerInitializer.razor
similarity index 100%
rename from src/Majorsoft.Blazor.Components.PermaLink/PermaLinkInitializer.razor
rename to src/Majorsoft.Blazor.Components.PermaLink/PermaLinkBlazorServerInitializer.razor
diff --git a/src/Majorsoft.Blazor.Components.PermaLink/PermalinkBlazorWasmInitializer.razor b/src/Majorsoft.Blazor.Components.PermaLink/PermalinkBlazorWasmInitializer.razor
new file mode 100644
index 00000000..f59b1e6f
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.PermaLink/PermalinkBlazorWasmInitializer.razor
@@ -0,0 +1,14 @@
+@inject IPermaLinkWatcherService _permalinkWatcher
+@implements IDisposable
+
+@code {
+ protected override void OnInitialized()
+ {
+ _permalinkWatcher.WatchPermaLinks();
+ }
+
+ public void Dispose()
+ {
+ _permalinkWatcher.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApp/Shared/MainLayout.razor b/src/Majorsoft.Blazor.Components.TestApp/Shared/MainLayout.razor
index 1231fe45..fe39508f 100644
--- a/src/Majorsoft.Blazor.Components.TestApp/Shared/MainLayout.razor
+++ b/src/Majorsoft.Blazor.Components.TestApp/Shared/MainLayout.razor
@@ -18,7 +18,7 @@
@*Permalink initialize*@
@using Majorsoft.Blazor.Components.PermaLink
-
+
@* Google Analytics initialize*@
@using Majorsoft.Blazor.Extensions.Analytics.Google
diff --git a/src/Majorsoft.Blazor.Components.TestServerApp/Shared/MainLayout.razor b/src/Majorsoft.Blazor.Components.TestServerApp/Shared/MainLayout.razor
index 29fdbe2d..57515469 100644
--- a/src/Majorsoft.Blazor.Components.TestServerApp/Shared/MainLayout.razor
+++ b/src/Majorsoft.Blazor.Components.TestServerApp/Shared/MainLayout.razor
@@ -16,7 +16,7 @@
@*Permalink initialize*@
@using Majorsoft.Blazor.Components.PermaLink
-
+
@*Server hosted Blazor console log*@
@using Majorsoft.Blazor.Server.Logging.Console
From 45f9d447cdeb296e5806a82e8e17a6e9e51b78a6 Mon Sep 17 00:00:00 2001
From: Major
Date: Tue, 22 Jun 2021 21:09:31 +0200
Subject: [PATCH 41/69] Permalink initializer docs.
---
.github/docs/PermaLink.md | 26 ++++++++++++++++++-
.../Components/Permalink.razor | 3 ++-
2 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/.github/docs/PermaLink.md b/.github/docs/PermaLink.md
index a085b063..1dd3437d 100644
--- a/.github/docs/PermaLink.md
+++ b/.github/docs/PermaLink.md
@@ -19,8 +19,10 @@ You can try it out by using the [demo app](https://blazorextensions.z6.web.core.
- **`PermaLinkElement`**: is a wrapper component it renders the given content with `` tag and will add anchor icon with on hover activated Link copy function.
Hover over the top Header item to copy or navigate to URL as well.
-- **`IPermaLinkWatcherService`**: . It is registered as Singleton and should be injected only once for the whole application.
+- **`IPermaLinkWatcherService`**: is registered as Singleton and should be injected only once for the whole application.
Best way to use `MainLayout.razor`.
+- **`PermaLinkBlazorServerInitializer`**: (from v1.4.0) convenient wrapper component to initialize navigation watcher in your Blazor Server App `MainLayout.razor` page.
+- **`PermalinkBlazorWasmInitializer`**: (from v1.4.0) convenient wrapper component to initialize navigation watcher in your Blazor WebAssembly App `MainLayout.razor` page.
## `IPermaLinkWatcherService` extension
This is the main service which makes Permalink navigation possible. **Should be used as a Singleton** only in `MainLayout.razor` file.
@@ -125,6 +127,13 @@ Also instance should be disposed.
}
```
+**From v1.4.0 a simpler initializer is available!**
+```
+@*Permalink initialize*@
+@using Majorsoft.Blazor.Components.PermaLink
+
+```
+
#### Server hosted projects
**In case of Server hosted project register dependency services in your `Startup.cs` file:**
@@ -157,6 +166,7 @@ It has to be instantiated manually by using the following code. Also instance sh
@inject ILogger _logger
@implements IDisposable
+@implements IAsyncDisposable
@code{
private IPermaLinkWatcherService _permalinkWatcher;
@@ -170,6 +180,13 @@ It has to be instantiated manually by using the following code. Also instance sh
}
}
+ public async ValueTask DisposeAsync()
+ {
+ if (_scrollHandler is not null)
+ {
+ await _scrollHandler.DisposeAsync();
+ }
+ }
public void Dispose()
{
_permalinkWatcher?.Dispose();
@@ -177,6 +194,13 @@ It has to be instantiated manually by using the following code. Also instance sh
}
```
+**From v1.4.0 a simpler initializer is available!**
+```
+@*Permalink initialize*@
+@using Majorsoft.Blazor.Components.PermaLink
+
+```
+
#### Creating permalink (#) navigation points inside a Blazor page
This is a standard HTML `a` tag. Apply the well known **``** anchor element in your document
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Permalink.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Permalink.razor
index 9ed6acb3..32cb67ce 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Permalink.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Permalink.razor
@@ -9,7 +9,8 @@ textarea {
Blazor injectable IPermaLinkWatcherService service and PermaLinkElement wrapper component which allows navigation inside Blazor pages (#permalink).
- For usege see soruce code and docs on Github.
+ To initialize navigation watcher use PermalinkBlazorWasmInitializer or PermaLinkBlazorServerInitializer in your Blazor app MainLayout.razor page.
+ For usage see source code and docs on Github.
Majorsoft.Blazor.Components.PermaLink package is available on Nuget
diff --git a/src/Majorsoft.Blazor.Components.TestServerApp/Pages/MaxLengthInputPage.razor b/src/Majorsoft.Blazor.Components.TestServerApp/Pages/MaxLengthInputPage.razor
new file mode 100644
index 00000000..47643464
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.TestServerApp/Pages/MaxLengthInputPage.razor
@@ -0,0 +1,3 @@
+@page "/maxLengthInput"
+
+
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.sln b/src/Majorsoft.Blazor.Components.sln
index 7f29ea39..b988b268 100644
--- a/src/Majorsoft.Blazor.Components.sln
+++ b/src/Majorsoft.Blazor.Components.sln
@@ -87,6 +87,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsoft.Blazor.Extensions
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsoft.Blazor.Extensions.Analytics", "Majorsoft.Blazor.Extensions.Analytics\Majorsoft.Blazor.Extensions.Analytics.csproj", "{261B879A-4E63-4D4B-9B59-E8C8F84531FF}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Majorsoft.Blazor.Components.Inputs", "Majorsoft.Blazor.Components.Inputs\Majorsoft.Blazor.Components.Inputs.csproj", "{A1FF7E56-1ADE-4A53-A517-A9A0F3A70ECC}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -221,6 +223,10 @@ Global
{261B879A-4E63-4D4B-9B59-E8C8F84531FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{261B879A-4E63-4D4B-9B59-E8C8F84531FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{261B879A-4E63-4D4B-9B59-E8C8F84531FF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A1FF7E56-1ADE-4A53-A517-A9A0F3A70ECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A1FF7E56-1ADE-4A53-A517-A9A0F3A70ECC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A1FF7E56-1ADE-4A53-A517-A9A0F3A70ECC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A1FF7E56-1ADE-4A53-A517-A9A0F3A70ECC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -257,6 +263,7 @@ Global
{CE8AF2E1-6860-4F1B-BC96-F84042E55A2F} = {020CAF9C-D289-470A-BB97-E58D73DDCE70}
{B0BDDF05-5508-4D05-B766-6DB53C33D004} = {121A4471-EF7A-4F9A-A856-67E8376A4AD2}
{261B879A-4E63-4D4B-9B59-E8C8F84531FF} = {121A4471-EF7A-4F9A-A856-67E8376A4AD2}
+ {A1FF7E56-1ADE-4A53-A517-A9A0F3A70ECC} = {B6905E0B-759A-4928-B38A-9210B5CC8988}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F3E8B7F7-3F7C-4D6C-8B7B-48F1AF4694B9}
From 4e0f6eafe8e47f3b62371530af1b77ce394ca658 Mon Sep 17 00:00:00 2001
From: Major
Date: Fri, 2 Jul 2021 19:23:23 +0200
Subject: [PATCH 45/69] Implement MaxLengthInput component with demo
---
.../Majorsoft.Blazor.Components.Inputs.xml | 41 +++++++++
.../MaxLengthInput.razor | 85 ++++++++++++++++++-
.../_Imports.razor | 4 +-
.../Components/Debounce.razor | 10 +--
.../Components/MaxLengthInputs.razor | 55 +++++++++++-
.../_Imports.razor | 4 +-
6 files changed, 190 insertions(+), 9 deletions(-)
diff --git a/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml b/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml
index 21e0a407..57cd1913 100644
--- a/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml
+++ b/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml
@@ -4,5 +4,46 @@
Majorsoft.Blazor.Components.Inputs
+
+
+ Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+
+
+
+
+ Value of the rendered HTML element. Initial field value can be set to given string or omitted (leave empty).
+ Also control actual value can be read out (useful when MinLenght not reached).
+
+
+
+
+ Maximum allowed characters to type in.
+
+
+
+
+ Contdown label text to change or localize message.
+
+
+
+
+ Contdown label and value CSS calss property to style message.
+
+
+
+
+ Callback function called when HTML control received keyboard inputs.
+
+
+
+
+ Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
+
+
+
+
+ Blazor capture for any unmatched HTML attributes.
+
+
diff --git a/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInput.razor b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInput.razor
index d592bde4..5e5b48b4 100644
--- a/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInput.razor
+++ b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInput.razor
@@ -1,5 +1,88 @@
-
+
+
+
+@inject ILogger _logger;
@code {
+ protected override async Task OnParametersSetAsync()
+ {
+ await CalculateRemaining();
+ }
+
+ private int _remainingChars;
+ private ElementReference _inputRef;
+ ///
+ /// Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+ ///
+ public ElementReference InnerElementReference => _inputRef;
+
+ ///
+ /// Value of the rendered HTML element. Initial field value can be set to given string or omitted (leave empty).
+ /// Also control actual value can be read out (useful when MinLenght not reached).
+ ///
+ [Parameter] public string? Value { get; set; }
+
+ ///
+ /// Maximum allowed characters to type in.
+ ///
+ [Parameter] public int MaxAllowedChars { get; set; } = 50;
+
+ ///
+ /// Contdown label text to change or localize message.
+ ///
+ [Parameter] public string CountdownText { get; set; } = "Remaining characters: ";
+
+ ///
+ /// Contdown label and value CSS calss property to style message.
+ ///
+ [Parameter] public string CountdownTextClass { get; set; }
+
+ //Events
+ ///
+ /// Callback function called when HTML control received keyboard inputs.
+ ///
+ [Parameter] public EventCallback OnInput { get; set; }
+
+ ///
+ /// Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
+ ///
+ [Parameter] public EventCallback OnRemainingCharsChanged { get; set; }
+
+
+ ///
+ /// Blazor capture for any unmatched HTML attributes.
+ ///
+ [Parameter(CaptureUnmatchedValues = true)]
+ public Dictionary AllOtherAttributes { get; set; }
+
+ private async Task OnTextChange(ChangeEventArgs e)
+ {
+ WriteDiag($"{nameof(OnTextChange)} event: '{e.Value}', MaxAllowedChars: '{MaxAllowedChars}'.");
+
+ if (OnInput.HasDelegate) //Immediately notify listeners of text change e.g. @bind
+ {
+ await OnInput.InvokeAsync(e.Value?.ToString());
+ }
+
+ Value = e.Value?.ToString();
+ await CalculateRemaining();
+ }
+
+ private async Task CalculateRemaining()
+ {
+ var tmp = _remainingChars;
+ _remainingChars = MaxAllowedChars - (Value?.Length ?? 0);
+
+ WriteDiag($"{nameof(CalculateRemaining)} event value Length: '{Value?.Length}', _remainingChars: '{_remainingChars}'.");
+
+ if (OnRemainingCharsChanged.HasDelegate && tmp != _remainingChars)
+ {
+ await OnRemainingCharsChanged.InvokeAsync(_remainingChars);
+ }
+ }
+ private void WriteDiag(string message)
+ {
+ _logger.LogDebug($"Component {this.GetType()}: {message}");
+ }
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.Inputs/_Imports.razor b/src/Majorsoft.Blazor.Components.Inputs/_Imports.razor
index 77285129..848647bc 100644
--- a/src/Majorsoft.Blazor.Components.Inputs/_Imports.razor
+++ b/src/Majorsoft.Blazor.Components.Inputs/_Imports.razor
@@ -1 +1,3 @@
-@using Microsoft.AspNetCore.Components.Web
+@using Microsoft.AspNetCore.Components.Forms
+@using Microsoft.AspNetCore.Components.Web
+@using Microsoft.Extensions.Logging;
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Debounce.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Debounce.razor
index 911fef99..f8158b1b 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Debounce.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Debounce.razor
@@ -2,7 +2,7 @@
Deboudnce Input controls
- Blazor component that renders an Input, InputText, Textarea or InputTextarea, etc. element with debounced onChange. For usege see soruce code and docs on
+ Blazor component that renders an Input, InputText, Textarea or InputTextarea, etc. element with debounced onChange. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Debounce package is available on Nuget
@@ -24,7 +24,7 @@
-
@**@
-
-
@**@
- MaxLengthInputs
+
+
+
+
+
Max allowed length Input controls with Counter
+
+ Blazor components that renders an Input, InputText, Textarea or InputTextarea, etc. element with maxlength set and counter to show remaining characters. For usage see source code and docs on
+ Github.
+ Majorsoft.Blazor.Components.Inputs package is available on Nuget
+
+
+
+
+
MaxLengthInput component
+
Wraps around HTML Input control and sets maxlength property with notification onChange.
@code {
+ private int _maxLengthInputAllowed = 20;
+ private string _maxLengthInputValue = "";
+ private string _maxLengthInputTextClass = "countDownText";
+
+ private void MaxLengthInputRemainingCharsChanged(int remainingChars)
+ {
+ _maxLengthInputTextClass = "countDownText";
+ if (_maxLengthInputAllowed * 0.2 >= remainingChars)
+ {
+ _maxLengthInputTextClass = "countDownText red";
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/_Imports.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/_Imports.razor
index 3340f34a..dd78556a 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/_Imports.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/_Imports.razor
@@ -49,4 +49,6 @@
@using Majorsoft.Blazor.Extensions.BrowserStorage
-@using Majorsoft.Blazor.Extensions.Analytics.Google
\ No newline at end of file
+@using Majorsoft.Blazor.Extensions.Analytics.Google
+
+@using Majorsoft.Blazor.Components.Inputs
\ No newline at end of file
From 921ac075a3f62ea69208302cd9dae61a87d196c8 Mon Sep 17 00:00:00 2001
From: Major
Date: Fri, 2 Jul 2021 19:40:45 +0200
Subject: [PATCH 46/69] Implement MaxLengthTextarea with demo.
---
.../Majorsoft.Blazor.Components.Inputs.xml | 41 +++++++++
.../MaxLengthTextarea.razor | 88 +++++++++++++++++++
.../Components/MaxLengthInputs.razor | 39 +++++++-
3 files changed, 167 insertions(+), 1 deletion(-)
create mode 100644 src/Majorsoft.Blazor.Components.Inputs/MaxLengthTextarea.razor
diff --git a/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml b/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml
index 57cd1913..2f88adf2 100644
--- a/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml
+++ b/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml
@@ -45,5 +45,46 @@
Blazor capture for any unmatched HTML attributes.
+
+
+ Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+
+
+
+
+ Value of the rendered HTML element. Initial field value can be set to given string or omitted (leave empty).
+ Also control actual value can be read out (useful when MinLenght not reached).
+
+
+
+
+ Maximum allowed characters to type in.
+
+
+
+
+ Contdown label text to change or localize message.
+
+
+
+
+ Contdown label and value CSS calss property to style message.
+
+
+
+
+ Callback function called when HTML control received keyboard inputs.
+
+
+
+
+ Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
+
+
+
+
+ Blazor capture for any unmatched HTML attributes.
+
+
diff --git a/src/Majorsoft.Blazor.Components.Inputs/MaxLengthTextarea.razor b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthTextarea.razor
new file mode 100644
index 00000000..4f890c70
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthTextarea.razor
@@ -0,0 +1,88 @@
+
+
+
+@inject ILogger _logger;
+
+@code {
+ protected override async Task OnParametersSetAsync()
+ {
+ await CalculateRemaining();
+ }
+
+ private int _remainingChars;
+ private ElementReference _inputRef;
+ ///
+ /// Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+ ///
+ public ElementReference InnerElementReference => _inputRef;
+
+ ///
+ /// Value of the rendered HTML element. Initial field value can be set to given string or omitted (leave empty).
+ /// Also control actual value can be read out (useful when MinLenght not reached).
+ ///
+ [Parameter] public string? Value { get; set; }
+
+ ///
+ /// Maximum allowed characters to type in.
+ ///
+ [Parameter] public int MaxAllowedChars { get; set; } = 50;
+
+ ///
+ /// Contdown label text to change or localize message.
+ ///
+ [Parameter] public string CountdownText { get; set; } = "Remaining characters: ";
+
+ ///
+ /// Contdown label and value CSS calss property to style message.
+ ///
+ [Parameter] public string CountdownTextClass { get; set; }
+
+ //Events
+ ///
+ /// Callback function called when HTML control received keyboard inputs.
+ ///
+ [Parameter] public EventCallback OnInput { get; set; }
+
+ ///
+ /// Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
+ ///
+ [Parameter] public EventCallback OnRemainingCharsChanged { get; set; }
+
+
+ ///
+ /// Blazor capture for any unmatched HTML attributes.
+ ///
+ [Parameter(CaptureUnmatchedValues = true)]
+ public Dictionary AllOtherAttributes { get; set; }
+
+ private async Task OnTextChange(ChangeEventArgs e)
+ {
+ WriteDiag($"{nameof(OnTextChange)} event: '{e.Value}', MaxAllowedChars: '{MaxAllowedChars}'.");
+
+ if (OnInput.HasDelegate) //Immediately notify listeners of text change e.g. @bind
+ {
+ await OnInput.InvokeAsync(e.Value?.ToString());
+ }
+
+ Value = e.Value?.ToString();
+ await CalculateRemaining();
+ }
+
+ private async Task CalculateRemaining()
+ {
+ var tmp = _remainingChars;
+ _remainingChars = MaxAllowedChars - (Value?.Length ?? 0);
+
+ WriteDiag($"{nameof(CalculateRemaining)} event value Length: '{Value?.Length}', _remainingChars: '{_remainingChars}'.");
+
+ if (OnRemainingCharsChanged.HasDelegate && tmp != _remainingChars)
+ {
+ await OnRemainingCharsChanged.InvokeAsync(_remainingChars);
+ }
+ }
+
+ private void WriteDiag(string message)
+ {
+ _logger.LogDebug($"Component {this.GetType()}: {message}");
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/MaxLengthInputs.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/MaxLengthInputs.razor
index d55a9973..754b341a 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/MaxLengthInputs.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/MaxLengthInputs.razor
@@ -24,7 +24,7 @@
+
@code {
private int _maxLengthInputAllowed = 20;
private string _maxLengthInputValue = "";
@@ -55,4 +78,18 @@
_maxLengthInputTextClass = "countDownText red";
}
}
+
+ private int _maxLengthTextareaAllowed = 20;
+ private string _maxLengthTextareaValue = "";
+ private string _maxLengthTextareaTextClass = "countDownText";
+
+ private void MaxLengthTextareaRemainingCharsChanged(int remainingChars)
+ {
+ _maxLengthTextareaTextClass = "countDownText";
+
+ if (_maxLengthTextareaAllowed * 0.2 >= remainingChars)
+ {
+ _maxLengthTextareaTextClass = "countDownText red";
+ }
+ }
}
\ No newline at end of file
From 14a76110a0fbb6bd754f0d36190086fb43c9bff3 Mon Sep 17 00:00:00 2001
From: Major
Date: Fri, 2 Jul 2021 19:59:16 +0200
Subject: [PATCH 47/69] Move common code to base class.
---
.../Majorsoft.Blazor.Components.Inputs.xml | 56 ++---------
.../MaxLengthInput.razor | 89 +----------------
.../MaxLengthInput.razor.cs | 12 +++
.../MaxLengthInputsBase.cs | 98 +++++++++++++++++++
.../MaxLengthTextarea.razor | 89 +----------------
.../MaxLengthTextarea.razor.cs | 12 +++
.../Components/MaxLengthInputs.razor | 4 +-
7 files changed, 140 insertions(+), 220 deletions(-)
create mode 100644 src/Majorsoft.Blazor.Components.Inputs/MaxLengthInput.razor.cs
create mode 100644 src/Majorsoft.Blazor.Components.Inputs/MaxLengthInputsBase.cs
create mode 100644 src/Majorsoft.Blazor.Components.Inputs/MaxLengthTextarea.razor.cs
diff --git a/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml b/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml
index 2f88adf2..42c0272b 100644
--- a/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml
+++ b/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml
@@ -4,84 +4,48 @@
Majorsoft.Blazor.Components.Inputs
-
+
- Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
-
-
-
-
- Value of the rendered HTML element. Initial field value can be set to given string or omitted (leave empty).
- Also control actual value can be read out (useful when MinLenght not reached).
-
-
-
-
- Maximum allowed characters to type in.
-
-
-
-
- Contdown label text to change or localize message.
-
-
-
-
- Contdown label and value CSS calss property to style message.
-
-
-
-
- Callback function called when HTML control received keyboard inputs.
-
-
-
-
- Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
-
-
-
-
- Blazor capture for any unmatched HTML attributes.
+ Base class for MaxLength components.
-
+
Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
-
+
Value of the rendered HTML element. Initial field value can be set to given string or omitted (leave empty).
Also control actual value can be read out (useful when MinLenght not reached).
-
+
Maximum allowed characters to type in.
-
+
Contdown label text to change or localize message.
-
+
Contdown label and value CSS calss property to style message.
-
+
Callback function called when HTML control received keyboard inputs.
-
+
Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
-
+
Blazor capture for any unmatched HTML attributes.
diff --git a/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInput.razor b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInput.razor
index 5e5b48b4..552520ed 100644
--- a/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInput.razor
+++ b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInput.razor
@@ -1,88 +1,5 @@
-
-
-
+@inherits MaxLengthInputsBase
@inject ILogger _logger;
-@code {
- protected override async Task OnParametersSetAsync()
- {
- await CalculateRemaining();
- }
-
- private int _remainingChars;
- private ElementReference _inputRef;
- ///
- /// Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
- ///
- public ElementReference InnerElementReference => _inputRef;
-
- ///
- /// Value of the rendered HTML element. Initial field value can be set to given string or omitted (leave empty).
- /// Also control actual value can be read out (useful when MinLenght not reached).
- ///
- [Parameter] public string? Value { get; set; }
-
- ///
- /// Maximum allowed characters to type in.
- ///
- [Parameter] public int MaxAllowedChars { get; set; } = 50;
-
- ///
- /// Contdown label text to change or localize message.
- ///
- [Parameter] public string CountdownText { get; set; } = "Remaining characters: ";
-
- ///
- /// Contdown label and value CSS calss property to style message.
- ///
- [Parameter] public string CountdownTextClass { get; set; }
-
- //Events
- ///
- /// Callback function called when HTML control received keyboard inputs.
- ///
- [Parameter] public EventCallback OnInput { get; set; }
-
- ///
- /// Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
- ///
- [Parameter] public EventCallback OnRemainingCharsChanged { get; set; }
-
-
- ///
- /// Blazor capture for any unmatched HTML attributes.
- ///
- [Parameter(CaptureUnmatchedValues = true)]
- public Dictionary AllOtherAttributes { get; set; }
-
- private async Task OnTextChange(ChangeEventArgs e)
- {
- WriteDiag($"{nameof(OnTextChange)} event: '{e.Value}', MaxAllowedChars: '{MaxAllowedChars}'.");
-
- if (OnInput.HasDelegate) //Immediately notify listeners of text change e.g. @bind
- {
- await OnInput.InvokeAsync(e.Value?.ToString());
- }
-
- Value = e.Value?.ToString();
- await CalculateRemaining();
- }
-
- private async Task CalculateRemaining()
- {
- var tmp = _remainingChars;
- _remainingChars = MaxAllowedChars - (Value?.Length ?? 0);
-
- WriteDiag($"{nameof(CalculateRemaining)} event value Length: '{Value?.Length}', _remainingChars: '{_remainingChars}'.");
-
- if (OnRemainingCharsChanged.HasDelegate && tmp != _remainingChars)
- {
- await OnRemainingCharsChanged.InvokeAsync(_remainingChars);
- }
- }
-
- private void WriteDiag(string message)
- {
- _logger.LogDebug($"Component {this.GetType()}: {message}");
- }
-}
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInput.razor.cs b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInput.razor.cs
new file mode 100644
index 00000000..a5058925
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInput.razor.cs
@@ -0,0 +1,12 @@
+using Microsoft.Extensions.Logging;
+
+namespace Majorsoft.Blazor.Components.Inputs
+{
+ public partial class MaxLengthInput : MaxLengthInputsBase
+ {
+ protected override ILogger BaseLogger
+ {
+ get { return _logger; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInputsBase.cs b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInputsBase.cs
new file mode 100644
index 00000000..c316a8f7
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInputsBase.cs
@@ -0,0 +1,98 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Microsoft.AspNetCore.Components;
+using Microsoft.Extensions.Logging;
+
+namespace Majorsoft.Blazor.Components.Inputs
+{
+ ///
+ /// Base class for MaxLength components.
+ ///
+ public abstract class MaxLengthInputsBase : ComponentBase
+ {
+ protected abstract ILogger BaseLogger { get; }
+
+ protected override async Task OnParametersSetAsync()
+ {
+ await CalculateRemaining();
+ }
+
+ protected int _remainingChars;
+ protected ElementReference _inputRef;
+ ///
+ /// Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+ ///
+ public ElementReference InnerElementReference => _inputRef;
+
+ ///
+ /// Value of the rendered HTML element. Initial field value can be set to given string or omitted (leave empty).
+ /// Also control actual value can be read out (useful when MinLenght not reached).
+ ///
+ [Parameter] public string? Value { get; set; }
+
+ ///
+ /// Maximum allowed characters to type in.
+ ///
+ [Parameter] public int MaxAllowedChars { get; set; } = 50;
+
+ ///
+ /// Contdown label text to change or localize message.
+ ///
+ [Parameter] public string CountdownText { get; set; } = "Remaining characters: ";
+
+ ///
+ /// Contdown label and value CSS calss property to style message.
+ ///
+ [Parameter] public string CountdownTextClass { get; set; }
+
+ //Events
+ ///
+ /// Callback function called when HTML control received keyboard inputs.
+ ///
+ [Parameter] public EventCallback OnInput { get; set; }
+
+ ///
+ /// Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
+ ///
+ [Parameter] public EventCallback OnRemainingCharsChanged { get; set; }
+
+
+ ///
+ /// Blazor capture for any unmatched HTML attributes.
+ ///
+ [Parameter(CaptureUnmatchedValues = true)]
+ public Dictionary AllOtherAttributes { get; set; }
+
+ protected async Task OnTextChange(ChangeEventArgs e)
+ {
+ WriteDiag($"{nameof(OnTextChange)} event: '{e.Value}', MaxAllowedChars: '{MaxAllowedChars}'.");
+
+ if (OnInput.HasDelegate) //Immediately notify listeners of text change e.g. @bind
+ {
+ await OnInput.InvokeAsync(e.Value?.ToString());
+ }
+
+ Value = e.Value?.ToString();
+ await CalculateRemaining();
+ }
+
+ private async Task CalculateRemaining()
+ {
+ var tmp = _remainingChars;
+ _remainingChars = MaxAllowedChars - (Value?.Length ?? 0);
+
+ WriteDiag($"{nameof(CalculateRemaining)} event value Length: '{Value?.Length}', _remainingChars: '{_remainingChars}'.");
+
+ if (OnRemainingCharsChanged.HasDelegate && tmp != _remainingChars)
+ {
+ await OnRemainingCharsChanged.InvokeAsync(_remainingChars);
+ }
+ }
+
+ private void WriteDiag(string message)
+ {
+ BaseLogger.LogDebug($"Component {this.GetType()}: {message}");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.Inputs/MaxLengthTextarea.razor b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthTextarea.razor
index 4f890c70..d0ba31d6 100644
--- a/src/Majorsoft.Blazor.Components.Inputs/MaxLengthTextarea.razor
+++ b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthTextarea.razor
@@ -1,88 +1,5 @@
-
-
-
+@inherits MaxLengthInputsBase
@inject ILogger _logger;
-@code {
- protected override async Task OnParametersSetAsync()
- {
- await CalculateRemaining();
- }
-
- private int _remainingChars;
- private ElementReference _inputRef;
- ///
- /// Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
- ///
- public ElementReference InnerElementReference => _inputRef;
-
- ///
- /// Value of the rendered HTML element. Initial field value can be set to given string or omitted (leave empty).
- /// Also control actual value can be read out (useful when MinLenght not reached).
- ///
- [Parameter] public string? Value { get; set; }
-
- ///
- /// Maximum allowed characters to type in.
- ///
- [Parameter] public int MaxAllowedChars { get; set; } = 50;
-
- ///
- /// Contdown label text to change or localize message.
- ///
- [Parameter] public string CountdownText { get; set; } = "Remaining characters: ";
-
- ///
- /// Contdown label and value CSS calss property to style message.
- ///
- [Parameter] public string CountdownTextClass { get; set; }
-
- //Events
- ///
- /// Callback function called when HTML control received keyboard inputs.
- ///
- [Parameter] public EventCallback OnInput { get; set; }
-
- ///
- /// Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
- ///
- [Parameter] public EventCallback OnRemainingCharsChanged { get; set; }
-
-
- ///
- /// Blazor capture for any unmatched HTML attributes.
- ///
- [Parameter(CaptureUnmatchedValues = true)]
- public Dictionary AllOtherAttributes { get; set; }
-
- private async Task OnTextChange(ChangeEventArgs e)
- {
- WriteDiag($"{nameof(OnTextChange)} event: '{e.Value}', MaxAllowedChars: '{MaxAllowedChars}'.");
-
- if (OnInput.HasDelegate) //Immediately notify listeners of text change e.g. @bind
- {
- await OnInput.InvokeAsync(e.Value?.ToString());
- }
-
- Value = e.Value?.ToString();
- await CalculateRemaining();
- }
-
- private async Task CalculateRemaining()
- {
- var tmp = _remainingChars;
- _remainingChars = MaxAllowedChars - (Value?.Length ?? 0);
-
- WriteDiag($"{nameof(CalculateRemaining)} event value Length: '{Value?.Length}', _remainingChars: '{_remainingChars}'.");
-
- if (OnRemainingCharsChanged.HasDelegate && tmp != _remainingChars)
- {
- await OnRemainingCharsChanged.InvokeAsync(_remainingChars);
- }
- }
-
- private void WriteDiag(string message)
- {
- _logger.LogDebug($"Component {this.GetType()}: {message}");
- }
-}
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.Inputs/MaxLengthTextarea.razor.cs b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthTextarea.razor.cs
new file mode 100644
index 00000000..76a12a8c
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthTextarea.razor.cs
@@ -0,0 +1,12 @@
+using Microsoft.Extensions.Logging;
+
+namespace Majorsoft.Blazor.Components.Inputs
+{
+ public partial class MaxLengthTextarea : MaxLengthInputsBase
+ {
+ protected override ILogger BaseLogger
+ {
+ get { return _logger; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/MaxLengthInputs.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/MaxLengthInputs.razor
index 754b341a..1df7e3b5 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/MaxLengthInputs.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/MaxLengthInputs.razor
@@ -30,7 +30,7 @@
-
-
Date: Fri, 2 Jul 2021 20:33:26 +0200
Subject: [PATCH 48/69] Fixing max length components and demo
---
.../Majorsoft.Blazor.Components.Inputs.xml | 50 ++++++++++++
.../MaxLengthInputText.razor | 75 ++++++++++++++++++
.../MaxLengthInputTextArea.razor | 74 ++++++++++++++++++
.../Components/Collapse.razor | 2 +-
.../Components/ColorPicker.razor | 2 +-
.../Components/Dialog.razor | 2 +-
.../Components/Loading.razor | 2 +-
.../Components/Logger.razor | 4 +-
.../Components/MaxLengthInputs.razor | 77 +++++++++++++++++--
.../Components/Tabs.razor | 2 +-
.../Components/TimerComponent.razor | 2 +-
.../Components/Toggle.razor | 2 +-
.../Components/Typeahead.razor | 2 +-
13 files changed, 278 insertions(+), 18 deletions(-)
create mode 100644 src/Majorsoft.Blazor.Components.Inputs/MaxLengthInputText.razor
create mode 100644 src/Majorsoft.Blazor.Components.Inputs/MaxLengthInputTextArea.razor
diff --git a/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml b/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml
index 42c0272b..9a530763 100644
--- a/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml
+++ b/src/Majorsoft.Blazor.Components.Inputs/Majorsoft.Blazor.Components.Inputs.xml
@@ -50,5 +50,55 @@
Blazor capture for any unmatched HTML attributes.
+
+
+ Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+
+
+
+
+ Maximum allowed characters to type in.
+
+
+
+
+ Contdown label text to change or localize message.
+
+
+
+
+ Contdown label and value CSS calss property to style message.
+
+
+
+
+ Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
+
+
+
+
+ Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+
+
+
+
+ Maximum allowed characters to type in.
+
+
+
+
+ Contdown label text to change or localize message.
+
+
+
+
+ Contdown label and value CSS calss property to style message.
+
+
+
+
+ Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
+
+
diff --git a/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInputText.razor b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInputText.razor
new file mode 100644
index 00000000..ea904c67
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInputText.razor
@@ -0,0 +1,75 @@
+@inherits InputText
+@inject ILogger _logger;
+
+
+
+
+@*
+ Diffs with DebounceTimerBase:
+ - value="@CurrentValue"
+ - remove: [Parameter] public string? Value { get; set; }
+ - remove: public Dictionary AdditionalAttributes { get; set; }
+ - remove: [Parameter] public EventCallback OnInput { get; set; }
+ - OnTextChange(): CurrentValue = e.Value?.ToString();
+*@
+
+@code {
+ protected override async Task OnParametersSetAsync()
+ {
+ await CalculateRemaining();
+ }
+
+ private int _remainingChars;
+ private ElementReference _inputRef;
+ ///
+ /// Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+ ///
+ public ElementReference InnerElementReference => _inputRef;
+
+ ///
+ /// Maximum allowed characters to type in.
+ ///
+ [Parameter] public int MaxAllowedChars { get; set; } = 50;
+
+ ///
+ /// Contdown label text to change or localize message.
+ ///
+ [Parameter] public string CountdownText { get; set; } = "Remaining characters: ";
+
+ ///
+ /// Contdown label and value CSS calss property to style message.
+ ///
+ [Parameter] public string CountdownTextClass { get; set; }
+
+
+ ///
+ /// Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
+ ///
+ [Parameter] public EventCallback OnRemainingCharsChanged { get; set; }
+
+ private async Task OnTextChange(ChangeEventArgs e)
+ {
+ WriteDiag($"{nameof(OnTextChange)} event: '{e.Value}', MaxAllowedChars: '{MaxAllowedChars}'.");
+
+ CurrentValue = e.Value?.ToString();
+ await CalculateRemaining();
+ }
+
+ private async Task CalculateRemaining()
+ {
+ var tmp = _remainingChars;
+ _remainingChars = MaxAllowedChars - (CurrentValue?.Length ?? 0);
+
+ WriteDiag($"{nameof(CalculateRemaining)} event value Length: '{Value?.Length}', _remainingChars: '{_remainingChars}'.");
+
+ if (OnRemainingCharsChanged.HasDelegate && tmp != _remainingChars)
+ {
+ await OnRemainingCharsChanged.InvokeAsync(_remainingChars);
+ }
+ }
+
+ private void WriteDiag(string message)
+ {
+ _logger.LogDebug($"Component {this.GetType()}: {message}");
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInputTextArea.razor b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInputTextArea.razor
new file mode 100644
index 00000000..0dac7c22
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.Inputs/MaxLengthInputTextArea.razor
@@ -0,0 +1,74 @@
+@inherits InputTextArea
+@inject ILogger _logger;
+
+
+
+
+@*
+ Diffs with DebounceTimerBase:
+ - value="@CurrentValue"
+ - remove: [Parameter] public string? Value { get; set; }
+ - remove: public Dictionary AdditionalAttributes { get; set; }
+ - remove: [Parameter] public EventCallback OnInput { get; set; }
+ - OnTextChange(): CurrentValue = e.Value?.ToString();
+*@
+
+@code {
+ protected override async Task OnParametersSetAsync()
+ {
+ await CalculateRemaining();
+ }
+
+ private int _remainingChars;
+ private ElementReference _inputRef;
+ ///
+ /// Exposes a Blazor of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+ ///
+ public ElementReference InnerElementReference => _inputRef;
+
+ ///
+ /// Maximum allowed characters to type in.
+ ///
+ [Parameter] public int MaxAllowedChars { get; set; } = 50;
+
+ ///
+ /// Contdown label text to change or localize message.
+ ///
+ [Parameter] public string CountdownText { get; set; } = "Remaining characters: ";
+
+ ///
+ /// Contdown label and value CSS calss property to style message.
+ ///
+ [Parameter] public string CountdownTextClass { get; set; }
+
+ ///
+ /// Callback function called when HTML control received keyboard inputs remaining allowed chars calculated and sent as even args.
+ ///
+ [Parameter] public EventCallback OnRemainingCharsChanged { get; set; }
+
+ private async Task OnTextChange(ChangeEventArgs e)
+ {
+ WriteDiag($"{nameof(OnTextChange)} event: '{e.Value}', MaxAllowedChars: '{MaxAllowedChars}'.");
+
+ CurrentValue = e.Value?.ToString();
+ await CalculateRemaining();
+ }
+
+ private async Task CalculateRemaining()
+ {
+ var tmp = _remainingChars;
+ _remainingChars = MaxAllowedChars - (CurrentValue?.Length ?? 0);
+
+ WriteDiag($"{nameof(CalculateRemaining)} event value Length: '{Value?.Length}', _remainingChars: '{_remainingChars}'.");
+
+ if (OnRemainingCharsChanged.HasDelegate && tmp != _remainingChars)
+ {
+ await OnRemainingCharsChanged.InvokeAsync(_remainingChars);
+ }
+ }
+
+ private void WriteDiag(string message)
+ {
+ _logger.LogDebug($"Component {this.GetType()}: {message}");
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Collapse.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Collapse.razor
index 66e7db01..6a36b07e 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Collapse.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Collapse.razor
@@ -2,7 +2,7 @@
Collapse Components
- Blazor component that renders customizable Collapsible/Expandable panel and Accordion with many but only one active panel also custom content and header. For usege see soruce code and docs on
+ Blazor component that renders customizable Collapsible/Expandable panel and Accordion with many but only one active panel also custom content and header. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Collapse package is available on Nuget
- Blazor components that renders a Blazor Color Picker control with color info. For usege see soruce code and docs on
+ Blazor components that renders a Blazor Color Picker control with color info. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.ColorPicker package is available on Nuget
- Blazor component that can be used to render Modal dialog window with customizable content and parameterized Overlay, etc.. For usege see soruce code and docs on
+ Blazor component that can be used to render Modal dialog window with customizable content and parameterized Overlay, etc.. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Dialog package is available on Nuget
- Blazor components that renders Overlay for page load. HTML @("
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Logger.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Logger.razor
index 84376f94..87e142ba 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Logger.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Logger.razor
@@ -8,11 +8,11 @@
Blazor Extensions are providing useful features to develop Balazor applications:
- Blazor.Server.Logging.Console: Enables browser conole logging for Blazor applications using Server Hosted model.
+ Blazor.Server.Logging.Console: Enables browser console logging for Blazor applications using Server Hosted model.
Majorsoft.Blazor.Server.Logging.Console package is available on Nuget
- Blazor.WebAssembly.Logging.Console: Enables browser conole logging for Blazor applications using WebAssembly Hosting model.
+ Blazor.WebAssembly.Logging.Console: Enables browser console logging for Blazor applications using WebAssembly Hosting model.
Majorsoft.Blazor.WebAssembly.Logging.Console package is available on Nuget
@code {
- private int _maxLengthInputAllowed = 20;
+ //MaxLengthInput
+ private int _maxLengthInputAllowed = 10;
private string _maxLengthInputValue = "";
private string _maxLengthInputTextClass = "countDownText";
@@ -79,6 +112,22 @@
}
}
+ //MaxLengthInputText
+ private int _maxLengthInputTextAllowed = 10;
+ private string _maxLengthInputTextTextClass = "countDownText";
+
+ private void MaxLengthInputTextRemainingCharsChanged(int remainingChars)
+ {
+ _maxLengthInputTextTextClass = "countDownText";
+
+ if (_maxLengthInputTextAllowed * 0.2 >= remainingChars)
+ {
+ _maxLengthInputTextTextClass = "countDownText red";
+ }
+ }
+
+
+ //MaxLengthTextarea
private int _maxLengthTextareaAllowed = 20;
private string _maxLengthTextareaValue = "";
private string _maxLengthTextareaTextClass = "countDownText";
@@ -92,4 +141,16 @@
_maxLengthTextareaTextClass = "countDownText red";
}
}
+
+ //MaxLengthInputTextArea
+
+ //Form model
+ private ExampleModel exampleModel = new ExampleModel() { Name = "" };
+ private ExampleModel exampleModel2 = new ExampleModel();
+ public class ExampleModel
+ {
+ [Required]
+ [StringLength(10, ErrorMessage = "Name is too long.")]
+ public string Name { get; set; }
+ }
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Tabs.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Tabs.razor
index 4fa8ad56..7cbe7bc6 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Tabs.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Tabs.razor
@@ -2,7 +2,7 @@
Tabs Components
- Blazor component that renders customizable Tabs element panel with many tabs and custom content. For usege see soruce code and docs on
+ Blazor component that renders customizable Tabs element panel with many tabs and custom content. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Tabs package is available on Nuget
- Blazor component that can be used as a simple scheduler or performing periodically repeated tasks by calling custom async code. For usege see soruce code and docs on
+ Blazor component that can be used as a simple scheduler or performing periodically repeated tasks by calling custom async code. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Timer package is available on Nuget
- Blazor component that renders customizable Toggle Switch and Toggle Button components. For usege see soruce code and docs on
+ Blazor component that renders customizable Toggle Switch and Toggle Button components. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Toggle package is available on Nuget
- Blazor component that renders an HTML Input or InputText with Typeahead panel. For usege see soruce code and docs on
+ Blazor component that renders an HTML Input or InputText with Typeahead panel. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Typeahead package is available on Nuget
From 814de94e54736d4c43510cf7c82294b70f908e7c Mon Sep 17 00:00:00 2001
From: Major
Date: Fri, 2 Jul 2021 21:33:19 +0200
Subject: [PATCH 49/69] Finish demo and added link to Index page for Max
allowed length Input
---
.../Components/Index.razor | 1 +
.../Components/MaxLengthInputs.razor | 42 +++++++++++++++++++
2 files changed, 43 insertions(+)
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Index.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Index.razor
index 3aaeb98c..5aee5d9b 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Index.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Index.razor
@@ -32,6 +32,7 @@
@using System.Globalization
@using Majorsoft.Blazor.Components.Core.HtmlColors
+
+@implements IDisposable
+
@inject ILogger _logger
@inject IGdprConsentService _gdprConsentService
@code {
- private ElementReference _inputRef;
- ///
- /// Exposes a Blazor ElementReference of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
- ///
- public ElementReference InnerElementReference => _inputRef;
-
- ///
- /// HTML Content of the collapse panel.
- ///
- [Parameter] public RenderFragment Content { get; set; }
-
- private string _bannerColor = "128,128,128";//gray
- ///
- /// Sets the style of the HTML div background-color. Use HTML specified: Color Names, RGB, HEX or with HSL values.
- ///
- [Parameter]
- public string BannerBackgroundColor
- {
- get => _bannerColor;
- set => _bannerColor = new HtmlColor(value)?.RgbColor.ToRgbString();
- }
-
- ///
- /// Opacity of the overlay div. Value should be between 0..1. Where 0 means the overlay layer is not visible.
- ///
- [Parameter] public double BannerOpacity { get; set; } = 0.9;
-
- ///
- ///
- ///
- [Parameter] public DateTime AnswerValidUntil { get; set; } = DateTime.Now.AddMonths(1);
-
- ///
- /// Arbitrary HTML attributes e.g.: tabindex="1" will be passed to the corresponding rendered HTML element.
- ///
- [Parameter(CaptureUnmatchedValues = true)]
- public Dictionary AllOtherAttributes { get; set; }
+ private static bool Initialized = false;
+ protected override void OnInitialized()
+ {
+ if(Initialized)
+ {
+ throw new ApplicationException($"Component: '{nameof(GdprBanner)}' is not allowed to have multiple instances. Please define it one your e.g.: 'MainLayout.razor' or some common place.");
+ }
+
+ Initialized = true;
+ }
+
+ private ElementReference _inputRef;
+ ///
+ /// Exposes a Blazor ElementReference of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
+ ///
+ public ElementReference InnerElementReference => _inputRef;
+
+ ///
+ /// HTML Content of the collapse panel.
+ ///
+ [Parameter] public RenderFragment Content { get; set; }
+
+ private string _bannerColor = "128,128,128";//gray
+ ///
+ /// Sets the style of the HTML div background-color. Use HTML specified: Color Names, RGB, HEX or with HSL values.
+ ///
+ [Parameter]
+ public string BannerBackgroundColor
+ {
+ get => _bannerColor;
+ set => _bannerColor = new HtmlColor(value)?.RgbColor.ToRgbString();
+ }
+
+ ///
+ /// Opacity of the overlay div. Value should be between 0..1. Where 0 means the overlay layer is not visible.
+ ///
+ [Parameter] public double BannerOpacity { get; set; } = 0.9;
+
+ ///
+ ///
+ ///
+ [Parameter] public DateTime AnswerValidUntil { get; set; } = DateTime.Now.AddMonths(1);
+
+ ///
+ /// Arbitrary HTML attributes e.g.: tabindex="1" will be passed to the corresponding rendered HTML element.
+ ///
+ [Parameter(CaptureUnmatchedValues = true)]
+ public Dictionary AllOtherAttributes { get; set; }
+
+ public async void Dispose()
+ {
+ Initialized = false;
+ }
+
+ private void WriteDiag(string message)
+ {
+ _logger.LogDebug($"Component {this.GetType()}: {message}");
+ }
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.PermaLink/PermaLinkBlazorServerInitializer.razor b/src/Majorsoft.Blazor.Components.PermaLink/PermaLinkBlazorServerInitializer.razor
index 9f46c100..916cf2e3 100644
--- a/src/Majorsoft.Blazor.Components.PermaLink/PermaLinkBlazorServerInitializer.razor
+++ b/src/Majorsoft.Blazor.Components.PermaLink/PermaLinkBlazorServerInitializer.razor
@@ -5,11 +5,21 @@
@inject NavigationManager _navigationManager
@inject ILogger _logger
-@implements IDisposable
@implements IAsyncDisposable
@code {
private IPermaLinkWatcherService _permalinkWatcher;
+ private static bool Initialized = false;
+
+ protected override void OnInitialized()
+ {
+ if (Initialized)
+ {
+ throw new ApplicationException($"Component: '{nameof(PermalinkBlazorWasmInitializer)}' is not allowed to have multiple instances. Please define it one your e.g.: 'MainLayout.razor' or some common place.");
+ }
+
+ Initialized = true;
+ }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
@@ -27,10 +37,8 @@
{
await _scrollHandler.DisposeAsync();
}
- }
- public void Dispose()
- {
_permalinkWatcher?.Dispose();
+ Initialized = false;
}
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.PermaLink/PermalinkBlazorWasmInitializer.razor b/src/Majorsoft.Blazor.Components.PermaLink/PermalinkBlazorWasmInitializer.razor
index f59b1e6f..8347ecbf 100644
--- a/src/Majorsoft.Blazor.Components.PermaLink/PermalinkBlazorWasmInitializer.razor
+++ b/src/Majorsoft.Blazor.Components.PermaLink/PermalinkBlazorWasmInitializer.razor
@@ -2,13 +2,22 @@
@implements IDisposable
@code {
+ private static bool Initialized = false;
protected override void OnInitialized()
{
+ if (Initialized)
+ {
+ throw new ApplicationException($"Component: '{nameof(PermalinkBlazorWasmInitializer)}' is not allowed to have multiple instances. Please define it one your e.g.: 'MainLayout.razor' or some common place.");
+ }
+
+ Initialized = true;
+
_permalinkWatcher.WatchPermaLinks();
}
public void Dispose()
{
- _permalinkWatcher.Dispose();
+ _permalinkWatcher?.Dispose();
+ Initialized = false;
}
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
index 9070cee4..0f434f0e 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
@@ -2,16 +2,17 @@
GDPR Consents
- Blazor component that renders a customizable GDPR consent Banner or Popup witch Accept/Reject for cookie settings chosen value is persisted to Browser storage. For usage see source code and docs on
- Github.
+ Blazor injectable IGdprConsentService service and components that renders a customizable GDPR consent Banner or Popup witch Accept/Reject for cookie settings chosen value is persisted to Browser storage.
+ To initialize GDPR Consents use GdprBanner or GdprModalonly once in your Blazor App MainLayout.razor page or any common place.
+ For usage see source code and docs on Github.
Majorsoft.Blazor.Components.GdprConsent package is available on Nuget
-
Loading page
+
GDPR Consent Banner
-
Renders an Overlay layer for the whole page with customizable content for showing Page loading...
+
Renders a small Overlay layer at the bottom of the page with customizable content for showing the given GDPR message.
@@ -46,8 +47,8 @@
-
- This demo site actually does NOT uses cookies. Only demonstrate Cookie consent banner usage in your Blazor Application.
+
+ This demo site actually does NOT uses cookies. Only demonstrate Cookie Consent banner usage in your Blazor Application.I agreeDisagree
@@ -55,6 +56,8 @@
+@inject IGdprConsentService _gdprConsentService;
+
@code {
//GDPR banner
private string _bannerColor = "lightblue";
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Permalink.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Permalink.razor
index 32cb67ce..6b8a71e9 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Permalink.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/Permalink.razor
@@ -8,8 +8,8 @@ textarea {
Permalink (#link) extension and component
- Blazor injectable IPermaLinkWatcherService service and PermaLinkElement wrapper component which allows navigation inside Blazor pages (#permalink).
- To initialize navigation watcher use PermalinkBlazorWasmInitializer or PermaLinkBlazorServerInitializer in your Blazor app MainLayout.razor page.
+ Blazor injectable IPermaLinkWatcherService service and PermaLinkElement wrapper component which allows navigation inside Blazor pages (#permalink).
+ To initialize navigation watcher use PermalinkBlazorWasmInitializer or PermaLinkBlazorServerInitializeronly once in your Blazor App MainLayout.razor page or any common place.
For usage see source code and docs on Github.
Majorsoft.Blazor.Components.PermaLink package is available on Nuget
+
+@*THIS should be in a common part of your App e.g.: MainLayout.razor !!!*@
+
+
+
+
+
+
+ This demo site actually does NOT uses cookies. Only demonstrate Cookie Consent banner usage in your Blazor Application.
+
+ await _gdprBanner.Accepted()">I agree
+ await _gdprBanner.Rejected()">Disagree
+
+
+
+
+
+@inject IGdprConsentService _gdprConsentService
-@inject IGdprConsentService _gdprConsentService;
+@implements IDisposable
@code {
+ private GdprConsentData _gdprConsentData;
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender)
+ {
+ _gdprConsentService.ConsentNotificationService.GdprConsentStateChanged += OnConsentChanged; //Subscribe to change event
+
+ await OnConsentChanged(); //Initial check
+ }
+ }
+
//GDPR banner
+ private GdprBanner _gdprBanner;
private string _bannerColor = "lightblue";
+ private int _bannerConsentValidDays = 20;
private double _bannerOpacity = 90;
//GDPR popup
private string _overlayColor = "lightblue";
private double _overlayOpacity = 70;
+
+ private async Task OnConsentChanged()
+ {
+ _gdprConsentData = await _gdprConsentService.GetGdprConsentDataAsync();
+ StateHasChanged();
+ }
+
+ public async void Dispose()
+ {
+ _gdprConsentService.ConsentNotificationService.GdprConsentStateChanged -= OnConsentChanged; //Unsubscribe from change event
+ }
}
\ No newline at end of file
From a925b2019197a77ef5e79c3698564021fdc4ba11 Mon Sep 17 00:00:00 2001
From: Major
Date: Tue, 13 Jul 2021 21:33:13 +0200
Subject: [PATCH 61/69] Implemented GdprModal component.
---
.../GdprModal.razor | 166 ++++++++++++++
...ajorsoft.Blazor.Components.GdprConsent.xml | 78 +++++++
.../_Imports.razor | 4 +-
.../Components/GdprConsents.razor | 208 +++++++++++++-----
4 files changed, 405 insertions(+), 51 deletions(-)
create mode 100644 src/Majorsoft.Blazor.Components.GdprConsent/GdprModal.razor
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/GdprModal.razor b/src/Majorsoft.Blazor.Components.GdprConsent/GdprModal.razor
new file mode 100644
index 00000000..1a892864
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/GdprModal.razor
@@ -0,0 +1,166 @@
+
+
+ @Content
+
+
+
+
+@implements IDisposable
+
+@inject ILogger _logger
+@inject IGdprConsentService _gdprConsentService
+
+@code {
+ private static bool Initialized = false;
+ protected override void OnInitialized()
+ {
+ if (Initialized)
+ {
+ throw new ApplicationException($"Component: '{nameof(GdprBanner)}' is not allowed to have multiple instances. Please define it one your e.g.: 'MainLayout.razor' or some common place.");
+ }
+
+ Initialized = true;
+ _gdprConsentService.ConsentNotificationService.GdprConsentStateChanged += CheckConsent;
+
+ WriteDiag("Initialized successfuly.");
+ }
+
+ private ModalDialog _modal;
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ await CheckConsent();
+ }
+
+ ///
+ /// HTML Content of the collapse panel.
+ ///
+ [Parameter] public RenderFragment Content { get; set; }
+ ///
+ /// HTML content to show on the Modal footer (bottom). Can be any valid HTML but should be only custom action buttons.
+ /// Must not be defined if you want to leave it out.
+ ///
+ [Parameter] public RenderFragment Footer { get; set; }
+
+ ///
+ /// Sets the style of the HTML div background-color. Use HTML specified: Color Names, RGB, HEX or with HSL values.
+ ///
+ [Parameter]
+ public string OverlayBackgroundColor { get; set; } = "128,128,128";//gray
+
+ ///
+ /// Opacity of the overlay div. Value should be between 0..1. Where 0 means the overlay layer is not visible.
+ ///
+ [Parameter] public double OverlayOpacity { get; set; } = 0.7;
+
+ ///
+ ///
+ ///
+ [Parameter] public IEnumerable ConsentDetails { get; set; }
+
+ ///
+ /// Gets or Sets Consent choice validity date. After this date Consent will be asked again.
+ ///
+ [Parameter] public DateTime AnswerValidUntil { get; set; } = DateTime.Now.AddMonths(1);
+
+ //Size
+ ///
+ /// Modal dialog window Height in px if set to 0 Height is set auto.
+ ///
+ [Parameter] public double Height { get; set; } = 0;
+ ///
+ /// Modal dialog window Width in px if set to 0 Width is set auto.
+ ///
+ [Parameter] public double Width { get; set; } = 0;
+ ///
+ /// Modal dialog window minimum Height in px.
+ ///
+ [Parameter] public double MinHeight { get; set; } = 200;
+ ///
+ /// Modal dialog window minimum Width in px.
+ ///
+ [Parameter] public double MinWidth { get; set; } = 200;
+
+ ///
+ /// When true Modal dialog will be vertically centered, otherwise shown near to the top. Modal dialog horizontally always centered.
+ ///
+ [Parameter] public bool Centered { get; set; } = false;
+
+ ///
+ /// Arbitrary HTML attributes e.g.: tabindex="1" will be passed to the corresponding rendered HTML element.
+ ///
+ [Parameter(CaptureUnmatchedValues = true)]
+ public Dictionary AllOtherAttributes { get; set; }
+
+
+ ///
+ /// Accepting GDPR Consents.
+ ///
+ /// ValueTask
+ public async ValueTask Accepted()
+ {
+ await _gdprConsentService.SetGdprConsentDataAsync(CreateGdprConsentData(true));
+ WriteDiag("GDPR Consent was accepted.");
+ }
+
+ ///
+ /// Rejecting GDPR Consents.
+ ///
+ /// ValueTask
+ public async ValueTask Rejected()
+ {
+ await _gdprConsentService.SetGdprConsentDataAsync(CreateGdprConsentData(false));
+ WriteDiag("GDPR Consent was rejected.");
+ }
+
+ private GdprConsentData CreateGdprConsentData(bool accepted)
+ {
+ return new GdprConsentData()
+ {
+ AnsweredAt = DateTime.Now,
+ AnswerValidUntil = AnswerValidUntil,
+ GdprConsentDetails = ConsentDetails,
+ };
+ }
+
+ private async Task CheckConsent()
+ {
+ var gdprConsent = await _gdprConsentService.GetGdprConsentDataAsync();
+ var show = !gdprConsent?.IsValid ?? true;
+
+ WriteDiag($"GDPR Consent value changed Banner should show: '{show}'.");
+
+ if(show && !_modal.IsOpen)
+ {
+ await _modal.Open();
+ StateHasChanged();
+ }
+ else if (!show && _modal.IsOpen)
+ {
+ await _modal.Close();
+ StateHasChanged();
+ }
+ }
+
+ ///
+ /// Component dispose
+ ///
+ public async void Dispose()
+ {
+ Initialized = false;
+ _gdprConsentService.ConsentNotificationService.GdprConsentStateChanged -= CheckConsent;
+ }
+
+ private void WriteDiag(string message)
+ {
+ _logger.LogDebug($"Component {this.GetType()}: {message}");
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml b/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml
index afbbbd13..2e278685 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml
@@ -125,6 +125,84 @@
+
+
+ HTML Content of the collapse panel.
+
+
+
+
+ HTML content to show on the Modal footer (bottom). Can be any valid HTML but should be only custom action buttons.
+ Must not be defined if you want to leave it out.
+
+
+
+
+ Sets the style of the HTML div background-color. Use HTML specified: Color Names, RGB, HEX or with HSL values.
+
+
+
+
+ Opacity of the overlay div. Value should be between 0..1. Where 0 means the overlay layer is not visible.
+
+
+
+
+
+
+
+
+
+ Gets or Sets Consent choice validity date. After this date Consent will be asked again.
+
+
+
+
+ Modal dialog window Height in px if set to 0 Height is set auto.
+
+
+
+
+ Modal dialog window Width in px if set to 0 Width is set auto.
+
+
+
+
+ Modal dialog window minimum Height in px.
+
+
+
+
+ Modal dialog window minimum Width in px.
+
+
+
+
+ When true Modal dialog will be vertically centered, otherwise shown near to the top. Modal dialog horizontally always centered.
+
+
+
+
+ Arbitrary HTML attributes e.g.: tabindex="1" will be passed to the corresponding rendered HTML element.
+
+
+
+
+ Accepting GDPR Consents.
+
+ ValueTask
+
+
+
+ Rejecting GDPR Consents.
+
+ ValueTask
+
+
+
+ Component dispose
+
+
Exposes a Blazor ElementReference of the wrapped around HTML element. It can be used e.g. for JS interop, etc.
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/_Imports.razor b/src/Majorsoft.Blazor.Components.GdprConsent/_Imports.razor
index 848647bc..e3b2772b 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/_Imports.razor
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/_Imports.razor
@@ -1,3 +1,5 @@
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Web
-@using Microsoft.Extensions.Logging;
\ No newline at end of file
+@using Microsoft.Extensions.Logging
+
+@using Majorsoft.Blazor.Components.Modal
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
index 0c900010..78e028b1 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
@@ -9,32 +9,156 @@
-
-
GDPR Consent Banner
-
-
Renders a small Overlay layer at the bottom of the page with customizable content for showing the given GDPR message.
+ GDPR Component type: (only one of the GDPR components should be used by apply it on a common place in your App.)
+
+
- Overlay opacity: @(_bannerOpacity / 100)
- _bannerOpacity = int.Parse(e.Value?.ToString()))" />
+
+ @*THIS should be in a common part of your App e.g.: MainLayout.razor !!!*@
+
+
+
+
+
+
+ This demo site actually does NOT uses cookies. Only demonstrate Cookie Consent Banner usage in your Blazor Application.
+
+ await _gdprBanner.Accepted()">I agree
+ await _gdprBanner.Rejected()">Disagree
+
+
+
+
+}
+else if (_gdprControlType == "Modal")
+{
+
+
+
GDPR Consent Modal
+
+
Renders a Modal dialog with Overlay layer for the whole page with customizable content for showing the given GDPR message.
+ This demo site actually does NOT uses cookies. Only demonstrate Cookie Consent Modal usage in your Blazor Application.
+
+
+
+
+ Accept all Cookies:
+
+
+
+
+
+
+
+
+ Session all Cookies:
+
+
+
+
+
+
+
+ Tracking all Cookies:
+
+
+
+
+
+
+
+
+
+}
-
GDPR Consent data
+
+
GDPR Consent data
+
@@ -43,7 +167,7 @@
-
Consent Name
+
Cookie Consent Name
IsAccepted
@foreach (var item in _gdprConsentData.GdprConsentDetails)
@@ -65,36 +189,6 @@
-@*THIS should be in a common part of your App e.g.: MainLayout.razor !!!*@
-
-
-
-
-
-
- This demo site actually does NOT uses cookies. Only demonstrate Cookie Consent banner usage in your Blazor Application.
-
- await _gdprBanner.Accepted()">I agree
- await _gdprBanner.Rejected()">Disagree
-
-
-
-
-
@inject IGdprConsentService _gdprConsentService
@implements IDisposable
@@ -111,6 +205,19 @@
}
}
+ private string _gdprControlType = "Banner";
+ private List _gdprConsents;
+
+ protected override void OnInitialized()
+ {
+ _gdprConsents = new List()
+ {
+ new GdprConsentDetail() { ConsentName = "All", IsAccepted = true },
+ new GdprConsentDetail() { ConsentName = "Session", IsAccepted = true },
+ new GdprConsentDetail() { ConsentName = "Tracking", IsAccepted = true },
+ };
+ }
+
//GDPR banner
private GdprBanner _gdprBanner;
private string _bannerColor = "lightblue";
@@ -118,7 +225,8 @@
private double _bannerOpacity = 90;
//GDPR popup
- private string _overlayColor = "lightblue";
+ private GdprModal _gdprModal;
+ private string _overlayColor = "lightgray";
private double _overlayOpacity = 70;
private async Task OnConsentChanged()
From 62e5b09a813f90c8fd4028367fc799dccc95ba50 Mon Sep 17 00:00:00 2001
From: Major
Date: Wed, 14 Jul 2021 17:31:41 +0200
Subject: [PATCH 62/69] GDPR consent fixes and demo
---
.../GdprBanner.razor | 12 +++--
.../GdprConsentExtension.cs | 5 +++
.../GdprModal.razor | 45 +++++++++----------
...rsoft.Blazor.Components.GdprConsent.csproj | 2 +
...ajorsoft.Blazor.Components.GdprConsent.xml | 17 +++----
.../Components/GdprConsents.razor | 43 +++++++++++-------
6 files changed, 65 insertions(+), 59 deletions(-)
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/GdprBanner.razor b/src/Majorsoft.Blazor.Components.GdprConsent/GdprBanner.razor
index dbf4a45d..1a113962 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/GdprBanner.razor
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/GdprBanner.razor
@@ -64,10 +64,9 @@
[Parameter] public double BannerOpacity { get; set; } = 0.9;
///
- /// Gets or Sets Consent name Banner should be used for simple usage to accept ALL cookies. Default: `Cookies.All`
- /// For detailed choice use GdprModal.
+ /// GDPR Cookies consent details. An enumerable list of Cookie types with Accpeted flag.
///
- [Parameter] public string ConsentName { get; set; } = "Cookies.All";
+ [Parameter] public IEnumerable ConsentDetails { get; set; } = new GdprConsentDetail[] { new GdprConsentDetail() { ConsentName = "Cookies.All" } };
///
/// Gets or Sets Consent choice validity date. After this date Consent will be asked again.
@@ -102,14 +101,13 @@
private GdprConsentData CreateGdprConsentData(bool accepted)
{
+ ConsentDetails?.ToList().ForEach(f => f.IsAccepted = accepted);
return new GdprConsentData()
{
AnsweredAt = DateTime.Now,
AnswerValidUntil = AnswerValidUntil,
- GdprConsentDetails = new List()
- {
- new GdprConsentDetail() { IsAccepted = accepted, ConsentName = this.ConsentName }
- }
+ GdprConsentDetails = ConsentDetails
+
};
}
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/GdprConsentExtension.cs b/src/Majorsoft.Blazor.Components.GdprConsent/GdprConsentExtension.cs
index 67fb8025..23a9364a 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/GdprConsentExtension.cs
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/GdprConsentExtension.cs
@@ -1,5 +1,7 @@
using System;
+using Majorsoft.Blazor.Components.Common.JsInterop;
+using Majorsoft.Blazor.Components.CssEvents;
using Majorsoft.Blazor.Extensions.BrowserStorage;
using Microsoft.Extensions.DependencyInjection;
@@ -23,6 +25,9 @@ public static IServiceCollection AddGdprConsent(this IServiceCollection services
}
services.AddBrowserStorage();
+ services.AddJsInteropExtensions();
+ services.AddCssEvents();
+
services.AddTransient();
services.AddSingleton();
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/GdprModal.razor b/src/Majorsoft.Blazor.Components.GdprConsent/GdprModal.razor
index 1a892864..c5295568 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/GdprModal.razor
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/GdprModal.razor
@@ -1,11 +1,16 @@
-
+
@Content
@@ -25,7 +30,7 @@
{
if (Initialized)
{
- throw new ApplicationException($"Component: '{nameof(GdprBanner)}' is not allowed to have multiple instances. Please define it one your e.g.: 'MainLayout.razor' or some common place.");
+ throw new ApplicationException($"Component: '{nameof(GdprModal)}' is not allowed to have multiple instances. Please define it one your e.g.: 'MainLayout.razor' or some common place.");
}
Initialized = true;
@@ -62,9 +67,9 @@
[Parameter] public double OverlayOpacity { get; set; } = 0.7;
///
- ///
+ /// GDPR Cookies consent details. An enumerable list of Cookie types with Accpeted flag.
///
- [Parameter] public IEnumerable ConsentDetails { get; set; }
+ [Parameter] public IEnumerable ConsentDetails { get; set; } = new GdprConsentDetail[] { new GdprConsentDetail() { ConsentName = "Cookies.All" } };
///
/// Gets or Sets Consent choice validity date. After this date Consent will be asked again.
@@ -102,26 +107,16 @@
///
- /// Accepting GDPR Consents.
+ /// Save choiced GDPR Consents.
///
/// ValueTask
- public async ValueTask Accepted()
+ public async ValueTask SaveChoice()
{
- await _gdprConsentService.SetGdprConsentDataAsync(CreateGdprConsentData(true));
+ await _gdprConsentService.SetGdprConsentDataAsync(CreateGdprConsentData());
WriteDiag("GDPR Consent was accepted.");
}
- ///
- /// Rejecting GDPR Consents.
- ///
- /// ValueTask
- public async ValueTask Rejected()
- {
- await _gdprConsentService.SetGdprConsentDataAsync(CreateGdprConsentData(false));
- WriteDiag("GDPR Consent was rejected.");
- }
-
- private GdprConsentData CreateGdprConsentData(bool accepted)
+ private GdprConsentData CreateGdprConsentData()
{
return new GdprConsentData()
{
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.csproj b/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.csproj
index b3c8dff0..dc3ce3a6 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.csproj
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.csproj
@@ -41,6 +41,8 @@
+
+
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml b/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml
index 2e278685..0d53aec9 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml
@@ -148,7 +148,7 @@
-
+ GDPR Cookies consent details. An enumerable list of Cookie types with Accpeted flag.
@@ -186,15 +186,9 @@
Arbitrary HTML attributes e.g.: tabindex="1" will be passed to the corresponding rendered HTML element.
-
+
- Accepting GDPR Consents.
-
- ValueTask
-
-
-
- Rejecting GDPR Consents.
+ Save choiced GDPR Consents.
ValueTask
@@ -223,10 +217,9 @@
Opacity of the overlay div. Value should be between 0..1. Where 0 means the overlay layer is not visible.
-
+
- Gets or Sets Consent name Banner should be used for simple usage to accept ALL cookies. Default: `Cookies.All`
- For detailed choice use GdprModal.
+ GDPR Cookies consent details. An enumerable list of Cookie types with Accpeted flag.
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
index 78e028b1..585d4949 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
@@ -64,7 +64,7 @@
BannerOpacity="@(_bannerOpacity / 100)"
BannerBackgroundColor="@_bannerColor"
AnswerValidUntil="@DateTime.Now.AddDays(_bannerConsentValidDays)"
- ConsentName="All">
+ ConsentDetails="@_gdprConsents">
@@ -212,7 +225,7 @@ else if (_gdprControlType == "Modal")
{
_gdprConsents = new List()
{
- new GdprConsentDetail() { ConsentName = "All", IsAccepted = true },
+ new GdprConsentDetail() { ConsentName = "Required", IsAccepted = true },
new GdprConsentDetail() { ConsentName = "Session", IsAccepted = true },
new GdprConsentDetail() { ConsentName = "Tracking", IsAccepted = true },
};
From 4b6f097193977c5789ed15a94e7521bf9827071a Mon Sep 17 00:00:00 2001
From: Major
Date: Wed, 14 Jul 2021 17:32:32 +0200
Subject: [PATCH 63/69] Modal dialog fixes and unit tests updates.
---
.../ModalDialogTest.cs | 30 +++++++++----------
.../ModalDialog.razor | 2 ++
2 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/src/Majorsoft.Blazor.Components.Modal.Tests/ModalDialogTest.cs b/src/Majorsoft.Blazor.Components.Modal.Tests/ModalDialogTest.cs
index e5b14c5a..8e485e2a 100644
--- a/src/Majorsoft.Blazor.Components.Modal.Tests/ModalDialogTest.cs
+++ b/src/Majorsoft.Blazor.Components.Modal.Tests/ModalDialogTest.cs
@@ -63,7 +63,7 @@ public async Task ModalDialog_should_rendered_correctly_html_attributes_when_ope
);
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
@@ -107,7 +107,7 @@ public async Task ModalDialog_should_remove_dialog_from_DOM_when_closed()
rendered.MarkupMatches("");
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
Assert.AreEqual(true, rendered.Instance.IsOpen);
@@ -142,7 +142,7 @@ public async Task ModalDialog_should_remove_dialog_from_DOM_when_closed()
rendered.SetParametersAndRender(parameters => parameters
.Add(p => p.Animate, false));
- rendered.InvokeAsync(async () => await rendered.Instance.Close());
+ await rendered.InvokeAsync(async () => await rendered.Instance.Close());
rendered.Render();
Assert.AreEqual(false, rendered.Instance.IsOpen);
@@ -157,7 +157,7 @@ public async Task ModalDialog_should_rendered_background_correctly()
.Add(p => p.OverlayOpacity, 0.25));
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
@@ -201,7 +201,7 @@ public async Task ModalDialog_should_rendered_dimensions_correctly()
.Add(p => p.MinWidth, 555));
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
@@ -242,7 +242,7 @@ public async Task ModalDialog_should_not_rendered_close_button_correctly()
.Add(p => p.ShowCloseButton, false));
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
@@ -277,7 +277,7 @@ public async Task ModalDialog_should_rendered_dialog_centered_correctly()
.Add(p => p.Centered, true));
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
@@ -323,7 +323,7 @@ public async Task ModalDialog_should_not_rendered_close_button_but_render_haeder
);
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
@@ -364,7 +364,7 @@ public async Task ModalDialog_should_rendered_close_button_with_haeder_correctly
);
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
@@ -408,7 +408,7 @@ public async Task ModalDialog_should_rendered_content_correctly()
);
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
@@ -448,7 +448,7 @@ public async Task ModalDialog_should_rendered_footer_correctly()
);
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
@@ -486,7 +486,7 @@ public async Task ModalDialog_should_close_on_overlay_click()
.Add(p => p.OnClose, args => { closed = true; }));
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
@@ -519,7 +519,7 @@ public async Task ModalDialog_should_not_close_on_overlay_click()
.Add(p => p.OnClose, args => { closed = true; }));
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
@@ -569,7 +569,7 @@ public async Task ModalDialog_should_close_on_escape_key()
.Add(p => p.OnClose, args => { closed = true; }));
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
@@ -602,7 +602,7 @@ public async Task ModalDialog_should_not_close_on_escape_key()
.Add(p => p.OnClose, args => { closed = true; }));
//Open
- await rendered.Instance.Open();
+ await rendered.InvokeAsync(async () => { await rendered.Instance.Open(); });
rendered.Render();
var div = rendered.Find("div");
diff --git a/src/Majorsoft.Blazor.Components.Modal/ModalDialog.razor b/src/Majorsoft.Blazor.Components.Modal/ModalDialog.razor
index 4251654d..37a3b70d 100644
--- a/src/Majorsoft.Blazor.Components.Modal/ModalDialog.razor
+++ b/src/Majorsoft.Blazor.Components.Modal/ModalDialog.razor
@@ -251,7 +251,9 @@
{
_dialogTop = _dialogDefaultTop;//Reset dialog to page top
_isOpened = true;
+
WriteDiag($"Opening dialog currently, Opacity: {_opacity}, IsOpened: '{_isOpened}'.");
+ StateHasChanged(); //Force UI to render
if (Animate)
{
From e7a512c4ff411d1cb4f5ddc9408df542c1911c28 Mon Sep 17 00:00:00 2001
From: Major
Date: Wed, 14 Jul 2021 18:32:38 +0200
Subject: [PATCH 64/69] Added GDPR components XML comments.
---
.../GdprBanner.razor | 4 +-
.../GdprConsentNotificationService.cs | 15 +++++++
.../GdprModal.razor | 4 +-
.../IGdprConsentNotificationService.cs | 18 ++++++++
.../IGdprConsentService.cs | 45 ++++---------------
...ajorsoft.Blazor.Components.GdprConsent.xml | 38 ++++++++--------
.../Components/GdprConsents.razor | 7 +--
7 files changed, 68 insertions(+), 63 deletions(-)
create mode 100644 src/Majorsoft.Blazor.Components.GdprConsent/GdprConsentNotificationService.cs
create mode 100644 src/Majorsoft.Blazor.Components.GdprConsent/IGdprConsentNotificationService.cs
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/GdprBanner.razor b/src/Majorsoft.Blazor.Components.GdprConsent/GdprBanner.razor
index 1a113962..1455dea9 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/GdprBanner.razor
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/GdprBanner.razor
@@ -80,7 +80,7 @@
public Dictionary AllOtherAttributes { get; set; }
///
- /// Accepting GDPR Consents.
+ /// Accepting all GDPR Consents.
///
/// ValueTask
public async ValueTask Accepted()
@@ -90,7 +90,7 @@
}
///
- /// Rejecting GDPR Consents.
+ /// Rejecting all GDPR Consents.
///
/// ValueTask
public async ValueTask Rejected()
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/GdprConsentNotificationService.cs b/src/Majorsoft.Blazor.Components.GdprConsent/GdprConsentNotificationService.cs
new file mode 100644
index 00000000..a77898be
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/GdprConsentNotificationService.cs
@@ -0,0 +1,15 @@
+namespace Majorsoft.Blazor.Components.GdprConsent
+{
+ ///
+ /// Default implementation for
+ ///
+ public class GdprConsentNotificationService : IGdprConsentNotificationService
+ {
+ public event ConsentNotificationEventHandler GdprConsentStateChanged;
+
+ public void OnChange()
+ {
+ GdprConsentStateChanged?.Invoke();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/GdprModal.razor b/src/Majorsoft.Blazor.Components.GdprConsent/GdprModal.razor
index c5295568..38d7daa4 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/GdprModal.razor
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/GdprModal.razor
@@ -107,7 +107,7 @@
///
- /// Save choiced GDPR Consents.
+ /// Save user choosen GDPR Consents.
///
/// ValueTask
public async ValueTask SaveChoice()
@@ -148,7 +148,7 @@
///
/// Component dispose
///
- public async void Dispose()
+ public void Dispose()
{
Initialized = false;
_gdprConsentService.ConsentNotificationService.GdprConsentStateChanged -= CheckConsent;
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/IGdprConsentNotificationService.cs b/src/Majorsoft.Blazor.Components.GdprConsent/IGdprConsentNotificationService.cs
new file mode 100644
index 00000000..b4944d7d
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/IGdprConsentNotificationService.cs
@@ -0,0 +1,18 @@
+namespace Majorsoft.Blazor.Components.GdprConsent
+{
+ ///
+ /// Injectable singleton service to handle GDPR Consent changes.
+ ///
+ public interface IGdprConsentNotificationService
+ {
+ ///
+ /// Event handler to subscribe for GDPR Consent changes.
+ ///
+ event ConsentNotificationEventHandler GdprConsentStateChanged;
+
+ ///
+ /// Method called by to trigger Change event when GDPR Consent value was changed.
+ ///
+ void OnChange();
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/IGdprConsentService.cs b/src/Majorsoft.Blazor.Components.GdprConsent/IGdprConsentService.cs
index 86c82664..70cc68ad 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/IGdprConsentService.cs
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/IGdprConsentService.cs
@@ -2,35 +2,6 @@
namespace Majorsoft.Blazor.Components.GdprConsent
{
- ///
- ///
- ///
- public interface IGdprConsentNotificationService
- {
- ///
- ///
- ///
- event ConsentNotificationEventHandler GdprConsentStateChanged;
-
- ///
- ///
- ///
- void OnChange();
- }
-
- ///
- ///
- ///
- public class GdprConsentNotificationService : IGdprConsentNotificationService
- {
- public event ConsentNotificationEventHandler GdprConsentStateChanged;
-
- public void OnChange()
- {
- GdprConsentStateChanged?.Invoke();
- }
- }
-
///
/// Injectable service to handle GDPR Consent actions.
///
@@ -42,27 +13,27 @@ public interface IGdprConsentService
string ConsentStoreKeyName { get; }
///
- ///
+ /// Gets a to able to subscribe on Consent changed events.
///
IGdprConsentNotificationService ConsentNotificationService { get; }
///
- ///
+ /// Gets the GDPR Consent data from Browser local storage if any stored.
///
- ///
+ /// ValueTask
ValueTask GetGdprConsentDataAsync();
///
- ///
+ /// Sets or overrides the given GDPR Consent data in Browser local storage.
///
- ///
- ///
+ /// GDPR consent details with accepted and rejected cookies list
+ /// ValueTask
ValueTask SetGdprConsentDataAsync(GdprConsentData gdprConsentData);
///
- ///
+ /// Removes the GDPR Consent data from Browser local storage if any stored.
///
- ///
+ /// ValueTask
ValueTask ClearGdprConsentDataAsync();
}
}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml b/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml
index 0d53aec9..e54aa8cf 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml
@@ -66,6 +66,11 @@
IServiceCollection instance
+
+
+ Default implementation for
+
+
Implementation of
@@ -73,22 +78,17 @@
-
+ Injectable singleton service to handle GDPR Consent changes.
-
+ Event handler to subscribe for GDPR Consent changes.
-
-
-
-
-
-
+ Method called by to trigger Change event when GDPR Consent value was changed.
@@ -103,27 +103,27 @@
-
+ Gets a to able to subscribe on Consent changed events.
-
+ Gets the GDPR Consent data from Browser local storage if any stored.
-
+ ValueTask
-
+ Sets or overrides the given GDPR Consent data in Browser local storage.
-
-
+ GDPR consent details with accepted and rejected cookies list
+ ValueTask
-
+ Removes the GDPR Consent data from Browser local storage if any stored.
-
+ ValueTask
@@ -188,7 +188,7 @@
- Save choiced GDPR Consents.
+ Save user choosen GDPR Consents.
ValueTask
@@ -234,13 +234,13 @@
- Accepting GDPR Consents.
+ Accepting all GDPR Consents.
ValueTask
- Rejecting GDPR Consents.
+ Rejecting all GDPR Consents.
ValueTask
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
index 585d4949..040e6714 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
@@ -9,7 +9,8 @@
- GDPR Component type: (only one of the GDPR components should be used by apply it on a common place in your App.)
+ GDPR Component type: (only one of the GDPR components should be used once by apply it on a
+ common place in your App e.g.: MainLayout.razor!)
- @*THIS should be in a common part of your App e.g.: MainLayout.razor !!!*@
+ @*THIS should be in a common part of your App e.g.: MainLayout.razor!!!*@
"));
+ }
+
+ [TestMethod]
+ public async Task GdprModal_should_SaveChoice_as_user_choosen_ConsentDetails()
+ {
+ _dprConsentServiceMock.Setup(s => s.GetGdprConsentDataAsync())
+ .ReturnsAsync(new GdprConsentData()
+ {
+ AnsweredAt = DateTime.Now,
+ AnswerValidUntil = DateTime.Now.AddDays(1),
+ });
+ var details = new GdprConsentDetail[]
+ {
+ new GdprConsentDetail() { ConsentName = "All", IsAccepted = false },
+ new GdprConsentDetail() { ConsentName = "Tracking", IsAccepted = true },
+ new GdprConsentDetail() { ConsentName = "Session", IsAccepted = true },
+ };
+
+ var rendered = _testContext.RenderComponent(parameters => parameters
+ .Add(p => p.ConsentDetails, details));
+
+ await rendered.Instance.SaveChoice();
+
+ _dprConsentServiceMock.Verify(v => v.SetGdprConsentDataAsync(It.Is(v => !details[0].IsAccepted && details[1].IsAccepted && details[2].IsAccepted)),
+ Times.Once);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent.Tests/Majorsoft.Blazor.Components.GdprConsent.Tests.csproj b/src/Majorsoft.Blazor.Components.GdprConsent.Tests/Majorsoft.Blazor.Components.GdprConsent.Tests.csproj
new file mode 100644
index 00000000..f63344e3
--- /dev/null
+++ b/src/Majorsoft.Blazor.Components.GdprConsent.Tests/Majorsoft.Blazor.Components.GdprConsent.Tests.csproj
@@ -0,0 +1,26 @@
+
+
+
+ net5.0
+
+ false
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/GdprBanner.razor b/src/Majorsoft.Blazor.Components.GdprConsent/GdprBanner.razor
index 1455dea9..f09a7901 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/GdprBanner.razor
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/GdprBanner.razor
@@ -83,7 +83,7 @@
/// Accepting all GDPR Consents.
///
/// ValueTask
- public async ValueTask Accepted()
+ public async ValueTask AcceptAll()
{
await _gdprConsentService.SetGdprConsentDataAsync(CreateGdprConsentData(true));
WriteDiag("GDPR Consent was accepted.");
@@ -93,7 +93,7 @@
/// Rejecting all GDPR Consents.
///
/// ValueTask
- public async ValueTask Rejected()
+ public async ValueTask RejectAll()
{
await _gdprConsentService.SetGdprConsentDataAsync(CreateGdprConsentData(false));
WriteDiag("GDPR Consent was rejected.");
@@ -129,7 +129,7 @@
///
/// Component dispose
///
- public async void Dispose()
+ public void Dispose()
{
Initialized = false;
_gdprConsentService.ConsentNotificationService.GdprConsentStateChanged -= CheckConsent;
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/GdprConsentData.cs b/src/Majorsoft.Blazor.Components.GdprConsent/GdprConsentData.cs
index 49a6ab3d..94a1ee1d 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/GdprConsentData.cs
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/GdprConsentData.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
namespace Majorsoft.Blazor.Components.GdprConsent
{
@@ -28,6 +29,11 @@ public class GdprConsentData
///
public bool IsValid => AnswerValidUntil >= DateTime.Now;
+ ///
+ /// Gets weather all Consent were accepted.
+ ///
+ public bool AllAccepted => (GdprConsentDetails?.Any() ?? false) && (GdprConsentDetails?.All(x => x.IsAccepted) ?? false);
+
///
/// Default constructor
///
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/IGdprConsentService.cs b/src/Majorsoft.Blazor.Components.GdprConsent/IGdprConsentService.cs
index 70cc68ad..2d17583b 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/IGdprConsentService.cs
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/IGdprConsentService.cs
@@ -8,7 +8,7 @@ namespace Majorsoft.Blazor.Components.GdprConsent
public interface IGdprConsentService
{
///
- /// Gets GDPR Consent Browser storage key name
+ /// Gets GDPR Consent Browser local storage key name
///
string ConsentStoreKeyName { get; }
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml b/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml
index e54aa8cf..ef132897 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.xml
@@ -35,6 +35,11 @@
Gets weather the Consent answer is valid or not.
+
+
+ Gets weather all Consent were accepted.
+
+
Default constructor
@@ -98,7 +103,7 @@
- Gets GDPR Consent Browser storage key name
+ Gets GDPR Consent Browser local storage key name
@@ -232,13 +237,13 @@
Arbitrary HTML attributes e.g.: tabindex="1" will be passed to the corresponding rendered HTML element.
-
+
Accepting all GDPR Consents.
ValueTask
-
+
Rejecting all GDPR Consents.
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
index 040e6714..7b169336 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
@@ -71,10 +71,10 @@
This demo site actually does NOT uses cookies. Only demonstrate Cookie Consent Banner usage in your Blazor Application.
- await _gdprBanner.Accepted()">I agree
- await _gdprBanner.Rejected()">Disagree
+ await _gdprBanner.AcceptAll()">I agree
+ await _gdprBanner.RejectAll()">Disagree
- { _gdprControlType = "Modal"; }'>Customize
+ { _gdprControlType = "Modal"; }'>Customize
diff --git a/src/Majorsoft.Blazor.Components.sln b/src/Majorsoft.Blazor.Components.sln
index 1a4f5bb9..3cc4c8c6 100644
--- a/src/Majorsoft.Blazor.Components.sln
+++ b/src/Majorsoft.Blazor.Components.sln
@@ -93,6 +93,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsoft.Blazor.Components
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsoft.Blazor.Components.GdprConsent", "Majorsoft.Blazor.Components.GdprConsent\Majorsoft.Blazor.Components.GdprConsent.csproj", "{E3B6CBB8-619B-4F09-93F2-BA97BFD3C0EC}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Majorsoft.Blazor.Components.GdprConsent.Tests", "Majorsoft.Blazor.Components.GdprConsent.Tests\Majorsoft.Blazor.Components.GdprConsent.Tests.csproj", "{D7481B09-8B56-4FC7-BDE3-EEE54AB841AC}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -239,6 +241,10 @@ Global
{E3B6CBB8-619B-4F09-93F2-BA97BFD3C0EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E3B6CBB8-619B-4F09-93F2-BA97BFD3C0EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E3B6CBB8-619B-4F09-93F2-BA97BFD3C0EC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D7481B09-8B56-4FC7-BDE3-EEE54AB841AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D7481B09-8B56-4FC7-BDE3-EEE54AB841AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D7481B09-8B56-4FC7-BDE3-EEE54AB841AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D7481B09-8B56-4FC7-BDE3-EEE54AB841AC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -278,6 +284,7 @@ Global
{A1FF7E56-1ADE-4A53-A517-A9A0F3A70ECC} = {B6905E0B-759A-4928-B38A-9210B5CC8988}
{5A9DBE07-4666-4DEF-841A-477F2A1A28B9} = {020CAF9C-D289-470A-BB97-E58D73DDCE70}
{E3B6CBB8-619B-4F09-93F2-BA97BFD3C0EC} = {B6905E0B-759A-4928-B38A-9210B5CC8988}
+ {D7481B09-8B56-4FC7-BDE3-EEE54AB841AC} = {020CAF9C-D289-470A-BB97-E58D73DDCE70}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F3E8B7F7-3F7C-4D6C-8B7B-48F1AF4694B9}
From 58be526d31472b4ea69f0bd93ee2b8d571b09fe5 Mon Sep 17 00:00:00 2001
From: Major
Date: Thu, 15 Jul 2021 19:33:16 +0200
Subject: [PATCH 67/69] GDPR consents docs.
---
.github/docs/GdprConsent.md | 206 ++++++++++++++++++
.github/docs/Inputs.md | 2 +-
README.md | 1 +
...rsoft.Blazor.Components.GdprConsent.csproj | 2 +-
.../Components/GdprConsents.razor | 2 +-
5 files changed, 210 insertions(+), 3 deletions(-)
create mode 100644 .github/docs/GdprConsent.md
diff --git a/.github/docs/GdprConsent.md b/.github/docs/GdprConsent.md
new file mode 100644
index 00000000..a080ffa9
--- /dev/null
+++ b/.github/docs/GdprConsent.md
@@ -0,0 +1,206 @@
+Blazor GDPR Consent controls
+============
+[![Build Status](https://dev.azure.com/major-soft/GitHub/_apis/build/status/blazor-components/blazor-components-build-check)](https://dev.azure.com/major-soft/GitHub/_build/latest?definitionId=6)
+[![Package Version](https://img.shields.io/nuget/v/Majorsoft.Blazor.Components.GdprConsent?label=Latest%20Version)](https://www.nuget.org/packages/Majorsoft.Blazor.Components.GdprConsent/)
+[![NuGet Downloads](https://img.shields.io/nuget/dt/Majorsoft.Blazor.Components.GdprConsent?label=Downloads)](https://www.nuget.org/packages/Majorsoft.Blazor.Components.GdprConsent/)
+[![License](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/majorimi/blazor-components/blob/master/LICENSE)
+
+# About
+
+Blazor injectable `IGdprConsentService` service and components that renders a customizable GDPR consent Banner or Popup witch Accept/Reject for cookie settings chosen value is persisted to Browser storage.
+To initialize GDPR Consents use `GdprBanner` or `GdprModal` only once in your Blazor App MainLayout.razor page or any common place.
+
+**All components work with WebAssembly and Server hosted models**.
+For code examples [see usage](https://github.com/majorimi/blazor-components/blob/master/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor).
+
+You can try it out by using the [demo app](https://blazorextensions.z6.web.core.windows.net/gdpr).
+
+![GDPR Consent demo](https://github.com/majorimi/blazor-components-docs/raw/main/github/docs/gifs/gdprConsents.gif)
+
+# Components and Services
+
+- **`GdprBanner`**: renders a small Overlay layer at the bottom of the page with customizable content for showing the given GDPR message.
+- **`GdprModal`**: renders a Modal dialog with Overlay layer for the whole page with customizable content for showing the given GDPR message.
+- **`IGdprConsentService`**: injectable service to handle GDPR Consent actions.
+- **`IGdprConsentNotificationService`**: injectable singleton service to handle GDPR Consent changes.
+
+## `GdprBanner` component
+
+Modal dialogs are positioned over everything else in the document with optional Overlay (customizable opacity and color).
+Modal dialogs are removed from DOM when closed. **Only one modal window can be shown at a time.**
+Dialog automatically (can be disabled) focuses itself to capture keyboard events when closed will refocus the last element.
+
+### Properties
+- **`Header`: `RenderFragment` HTML content**
+HTML content to show on the Modal header (top), right to the close button (if visible). Can be any valid HTML but should be only Title text.
+**Must not be defined if you want to leave it out. Also `ShowCloseButton` must be set to `false`**
+- **`Content`: `RenderFragment` HTML content - Required**
+Required HTML content to show on the Modal dialog. Can be any valid HTML.
+- **`Footer`: `RenderFragment` HTML content**
+HTML content to show on the Modal footer (bottom). Can be any valid HTML but should be only custom action buttons.
+**Must not be defined if you want to leave it out.**
+- **`OverlayBackgroundColor`: `string { get; set; }` (default: "gray")**
+ Sets the `style` of the HTML `
` `background-color`. Use HTML specified: **Color Names**, **RGB** or with **HEX** values.
+- **`OverlayOpacity`: `double { get; set; }` (default: 0.9)**
+Opacity of the overlay `
`. Value should be **between 0..1**. Where 0 means the overlay layer is not visible.
+- **`CloseOnOverlayClick`: `bool { get; set; }` (default: true)**
+When `true` Modal dialog will be closed when Overlay (background) clicked. It works even if Overlay not visible (Opacity is set to 0)
+- **`CloseOnEscapeKey`: `bool { get; set; }` (default: true)**
+When `true` Modal dialog will be closed when **Esc** (Escape) key pressed.
+- **`Height`: `double { get; set; }` (default: 0)**
+Modal dialog window Height in **px** if set to **0** Height is set **auto**.
+- **`Width`: `double { get; set; }` (default: 0)**
+Modal dialog window Width in **px** if set to **0** Width is set **auto**.
+- **`MinHeight`: `double { get; set; }` (default: 200)**
+Modal dialog window minimum Height in **px**.
+- **`MinWidth`: `double { get; set; }` (default: 200)**
+Modal dialog window minimum Width in **px**.
+- **`Focus`: `bool { get; set; }` (default: true)**
+When `true` Modal dialog will automatically set focus to itself when it opens, and set it bact to the last focused element when it closes.
+In general this should never be set to false as it makes the Modal less accessible to screen-readers, etc.
+- **`Animate`: `bool { get; set; }` (default: true)**
+When `true` Modal dialog will appear and disappear by using smooth CSS slide and fade transitions.
+- **`Centered`: `bool { get; set; }` (default: false)**
+When `true` Modal dialog will be vertically centered, otherwise shown near to the top. Modal dialog horizontally always centered.
+- **`ShowCloseButton`: `bool { get; set; }` (default: true)**
+ When `true` Modal dialog will show Header (even if Header is not defined) with closed **x** button.
+- **`IsOpen`: `bool { get; }`**
+ Returns `true` if the Modal dialog is opened, otherwise `false`.
+
+**Arbitrary HTML attributes e.g.: `id="diag1"` will be passed to the corresponding rendered root HTML element Overlay `
`**.
+
+### Functions
+- **`Open()`: `Task Open()`**
+When method called Modal dialog will be opened. It should be `await`-ed.
+- **`Close()`: `Task Close()`**
+When method called Modal dialog will be closed. It should be `await`-ed.
+- **`DisposeAsync()`: `Task DisposeAsync()`**
+Component implements `IAsyncDisposable` interface Blazor framework will call it when parent removed from render tree.
+
+## `GdprModal` component
+
+Modal dialogs are positioned over everything else in the document with optional Overlay (customizable opacity and color).
+Modal dialogs are removed from DOM when closed. **Only one modal window can be shown at a time.**
+Dialog automatically (can be disabled) focuses itself to capture keyboard events when closed will refocus the last element.
+
+### Properties
+- **`Header`: `RenderFragment` HTML content**
+HTML content to show on the Modal header (top), right to the close button (if visible). Can be any valid HTML but should be only Title text.
+**Must not be defined if you want to leave it out. Also `ShowCloseButton` must be set to `false`**
+- **`Content`: `RenderFragment` HTML content - Required**
+Required HTML content to show on the Modal dialog. Can be any valid HTML.
+- **`Footer`: `RenderFragment` HTML content**
+HTML content to show on the Modal footer (bottom). Can be any valid HTML but should be only custom action buttons.
+**Must not be defined if you want to leave it out.**
+- **`OverlayBackgroundColor`: `string { get; set; }` (default: "gray")**
+ Sets the `style` of the HTML `
` `background-color`. Use HTML specified: **Color Names**, **RGB** or with **HEX** values.
+- **`OverlayOpacity`: `double { get; set; }` (default: 0.9)**
+Opacity of the overlay `
`. Value should be **between 0..1**. Where 0 means the overlay layer is not visible.
+- **`CloseOnOverlayClick`: `bool { get; set; }` (default: true)**
+When `true` Modal dialog will be closed when Overlay (background) clicked. It works even if Overlay not visible (Opacity is set to 0)
+- **`CloseOnEscapeKey`: `bool { get; set; }` (default: true)**
+When `true` Modal dialog will be closed when **Esc** (Escape) key pressed.
+- **`Height`: `double { get; set; }` (default: 0)**
+Modal dialog window Height in **px** if set to **0** Height is set **auto**.
+- **`Width`: `double { get; set; }` (default: 0)**
+Modal dialog window Width in **px** if set to **0** Width is set **auto**.
+- **`MinHeight`: `double { get; set; }` (default: 200)**
+Modal dialog window minimum Height in **px**.
+- **`MinWidth`: `double { get; set; }` (default: 200)**
+Modal dialog window minimum Width in **px**.
+- **`Focus`: `bool { get; set; }` (default: true)**
+When `true` Modal dialog will automatically set focus to itself when it opens, and set it bact to the last focused element when it closes.
+In general this should never be set to false as it makes the Modal less accessible to screen-readers, etc.
+- **`Animate`: `bool { get; set; }` (default: true)**
+When `true` Modal dialog will appear and disappear by using smooth CSS slide and fade transitions.
+- **`Centered`: `bool { get; set; }` (default: false)**
+When `true` Modal dialog will be vertically centered, otherwise shown near to the top. Modal dialog horizontally always centered.
+- **`ShowCloseButton`: `bool { get; set; }` (default: true)**
+ When `true` Modal dialog will show Header (even if Header is not defined) with closed **x** button.
+- **`IsOpen`: `bool { get; }`**
+ Returns `true` if the Modal dialog is opened, otherwise `false`.
+
+**Arbitrary HTML attributes e.g.: `id="diag1"` will be passed to the corresponding rendered root HTML element Overlay `
`**.
+
+### Functions
+- **`Open()`: `Task Open()`**
+When method called Modal dialog will be opened. It should be `await`-ed.
+- **`Close()`: `Task Close()`**
+When method called Modal dialog will be closed. It should be `await`-ed.
+- **`DisposeAsync()`: `Task DisposeAsync()`**
+Component implements `IAsyncDisposable` interface Blazor framework will call it when parent removed from render tree.
+
+
+# Configuration
+
+## Installation
+
+**Majorsoft.Blazor.Components.GdprConsent** is available on [NuGet](https://www.nuget.org/packages/Majorsoft.Blazor.Components.GdprConsent).
+
+```sh
+dotnet add package Majorsoft.Blazor.Components.GdprConsent
+```
+Use the `--version` option to specify a [preview version](https://www.nuget.org/packages/Majorsoft.Blazor.Components.GdprConsent/absoluteLatest) to install.
+
+## Usage
+
+Add using statement to your Blazor `.razor` file. Or globally reference it into `_Imports.razor` file.
+
+```
+@using Majorsoft.Blazor.Components.Toggle
+@using Majorsoft.Blazor.Extensions.BrowserStorage
+@using Majorsoft.Blazor.Components.Modal
+@using Majorsoft.Blazor.Components.Common.JsInterop.Focus
+@using Majorsoft.Blazor.Components.CssEvents
+@using Majorsoft.Blazor.Components.GdprConsent
+```
+
+### Dependences
+**Majorsoft.Blazor.Components.GdprConsent** package depends on other Majorsoft Nuget packages:
+- [Majorsoft.Blazor.Components.CssEvents](https://www.nuget.org/packages/Majorsoft.Blazor.Components.CssEvents)
+which handles CSS Transition and Animation events for the dialog animation.
+- [Majorsoft.Blazor.Components.Common.JsInterop](https://www.nuget.org/packages/Majorsoft.Blazor.Components.Common.JsInterop)
+which handles JS Interop for focusing previous elements.
+- [Majorsoft.Blazor.Components.CssEvents](https://www.nuget.org/packages/Majorsoft.Blazor.Components.Modal)
+which renders Model dialog window for `GdprModal`.
+- [Majorsoft.Blazor.Components.CssEvents](https://www.nuget.org/packages/Majorsoft.Blazor.Components.Toggle)
+which can be used to customize `` with ON/OFF switches to allow Cookie or not.
+- [Majorsoft.Blazor.Components.CssEvents](https://www.nuget.org/packages/)
+which stores user provided Consents in the Browser's Local storage.
+
+**In case of WebAssembly project register services in your `Program.cs` file:**
+```
+using Majorsoft.Blazor.Components.GdprConsent;
+...
+public static async Task Main(string[] args)
+{
+ var builder = WebAssemblyHostBuilder.CreateDefault(args);
+
+ //Register dependencies
+ builder.Services.AddGdprConsent();
+}
+```
+
+**In case of Server hosted project register services in your `Startup.cs` file:**
+```
+using Majorsoft.Blazor.Components.GdprConsent;
+...
+
+public void ConfigureServices(IServiceCollection services)
+{
+ //Register dependencies
+ services.AddGdprConsent();
+}
+```
+
+### `GdprBanner` usage
+
+```
+
+```
+
+### `GdprModal` usage
+
+```
+
+```
\ No newline at end of file
diff --git a/.github/docs/Inputs.md b/.github/docs/Inputs.md
index dcc4b2e0..cf1c2931 100644
--- a/.github/docs/Inputs.md
+++ b/.github/docs/Inputs.md
@@ -13,7 +13,7 @@ For code examples [see usage](https://github.com/majorimi/blazor-components/blob
You can try it out by using the [demo app](https://blazorextensions.z6.web.core.windows.net/maxLengthInput).
-![Debounce demo](https://github.com/majorimi/blazor-components-docs/raw/main/github/docs/gifs/maxLengthInput.gif)
+![Inputs demo](https://github.com/majorimi/blazor-components-docs/raw/main/github/docs/gifs/maxLengthInput.gif)
# Components
diff --git a/README.md b/README.md
index bc251d0e..dd1b897e 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,7 @@ Check out our planned components and extensions on the project [Wiki page](https
- **Majorsoft.Blazor.Components.Tabs**: [Tabs components](https://github.com/majorimi/blazor-components/blob/master/.github/docs/Tabs.md) that renders customizable Tabs panel with many tabs and custom content.
- **Majorsoft.Blazor.Components.Collapse**: [Collapse components](https://github.com/majorimi/blazor-components/blob/master/.github/docs/Collapse.md) that renders customizable Collapsable/Expandable panel and Accordion with many but only one active panel also custom content and header.
- **Majorsoft.Blazor.Components.Maps**: [Google/Bing Maps components](https://github.com/majorimi/blazor-components/blob/master/.github/docs/Maps.md) that renders **Google/Bing maps** wrapped into Blazor components allowing to control and mange maps with .Net code.
+- **Majorsoft.Blazor.Components.GdprConsent**: [GDPR Consent components](https://github.com/majorimi/blazor-components/blob/master/.github/docs/GdprConsent.md) injectable service and components that renders a customizable GDPR consent Banner or Popup witch Accept/Reject for cookie settings chosen value is persisted to Browser storage.
## Other info
- [Contributing](CONTRIBUTING.md)
diff --git a/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.csproj b/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.csproj
index dc3ce3a6..7e497217 100644
--- a/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.csproj
+++ b/src/Majorsoft.Blazor.Components.GdprConsent/Majorsoft.Blazor.Components.GdprConsent.csproj
@@ -17,7 +17,7 @@
Git.Net5 Blazor GDPR Consent Law Banner ModalWindow Modal Cookie CookiesBlazor Components GDPR Consent banner and popup
- Blazor component that renders a customizable GDPR consent Banner or Popup witch Accept/Reject for cookie settings chosen value is persisted to Browser storage. Part of Majorsoft Blazor library.
+ Blazor injectable IGdprConsentService service and components that renders a customizable GDPR consent Banner or Popup witch Accept/Reject for cookie settings chosen value is persisted to Browser storage. To initialize GDPR Consents use GdprBanner or GdprModal only once in your Blazor App MainLayout.razor page or any common place. Part of Majorsoft Blazor library.
diff --git a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
index 7b169336..60af3f3f 100644
--- a/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
+++ b/src/Majorsoft.Blazor.Components.TestApps.Common/Components/GdprConsents.razor
@@ -249,7 +249,7 @@ else if (_gdprControlType == "Modal")
StateHasChanged();
}
- public async void Dispose()
+ public void Dispose()
{
_gdprConsentService.ConsentNotificationService.GdprConsentStateChanged -= OnConsentChanged; //Unsubscribe from change event
}
From 27e63ea87dfe25346557eb3b4a4166c27ce5e0c9 Mon Sep 17 00:00:00 2001
From: Major
Date: Thu, 15 Jul 2021 20:12:20 +0200
Subject: [PATCH 68/69] Updated demo app to Nuget 1.4.0
---
.../Components/BrowserStorage.razor | 9 +-
.../Components/Collapse.razor | 6 +-
.../Components/ColorPicker.razor | 2 +-
.../Components/CssEvents.razor | 2 +
.../Components/Debounce.razor | 14 +-
.../Components/Dialog.razor | 40 +--
.../Components/GdprConsents.razor | 256 ++++++++++++++++++
.../Components/Index.razor | 10 +-
.../Components/JSInterop.razor | 20 +-
.../Components/JsDemo/BrowserDateJs.razor | 24 ++
.../Components/JsDemo/BrowserThemeJs.razor | 58 ++++
.../Components/JsDemo/LangJs.razor | 6 +-
.../Components/JsDemo/MouseJs.razor | 5 +-
.../Components/JsDemo/ResizeJs.razor | 5 +-
.../Components/JsDemo/ScrollJs.razor | 85 +++++-
.../Components/Loading.razor | 19 +-
.../Components/Logger.razor | 4 +-
.../Components/Maps.razor | 2 +
.../Components/MapsGoogle.razor | 12 +-
.../Components/MaxLengthInputs.razor | 197 ++++++++++++++
.../Components/Permalink.razor | 6 +-
.../Components/SiteAnalytics.razor | 83 ++++++
.../Components/Tabs.razor | 8 +-
.../Components/TimerComponent.razor | 2 +-
.../Components/Toggle.razor | 6 +-
.../Components/Typeahead.razor | 3 +-
...Majorsoft.Blazor.Components.DemoApp.csproj | 33 ++-
.../Pages/AnalyticsPage.razor | 3 +
.../Pages/GdprConsentPage.razor | 3 +
.../Pages/MaxLengthInputPage.razor | 3 +
.../Program.cs | 6 +
.../Shared/MainLayout.razor | 20 +-
.../Shared/NavMenu.razor | 13 +-
.../Shared/PageScroll.razor | 16 ++
.../_Imports.razor | 11 +-
.../wwwroot/blazor.components.png | Bin 0 -> 8130 bytes
36 files changed, 898 insertions(+), 94 deletions(-)
create mode 100644 demo/Majorsoft.Blazor.Components.DemoApp/Components/GdprConsents.razor
create mode 100644 demo/Majorsoft.Blazor.Components.DemoApp/Components/JsDemo/BrowserDateJs.razor
create mode 100644 demo/Majorsoft.Blazor.Components.DemoApp/Components/JsDemo/BrowserThemeJs.razor
create mode 100644 demo/Majorsoft.Blazor.Components.DemoApp/Components/MaxLengthInputs.razor
create mode 100644 demo/Majorsoft.Blazor.Components.DemoApp/Components/SiteAnalytics.razor
create mode 100644 demo/Majorsoft.Blazor.Components.DemoApp/Pages/AnalyticsPage.razor
create mode 100644 demo/Majorsoft.Blazor.Components.DemoApp/Pages/GdprConsentPage.razor
create mode 100644 demo/Majorsoft.Blazor.Components.DemoApp/Pages/MaxLengthInputPage.razor
create mode 100644 demo/Majorsoft.Blazor.Components.DemoApp/Shared/PageScroll.razor
create mode 100644 demo/Majorsoft.Blazor.Components.DemoApp/wwwroot/blazor.components.png
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Components/BrowserStorage.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Components/BrowserStorage.razor
index 4e214371..98e6e0fa 100644
--- a/demo/Majorsoft.Blazor.Components.DemoApp/Components/BrowserStorage.razor
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Components/BrowserStorage.razor
@@ -1,4 +1,6 @@
-
+
+
+
Browser Storage extensions
Enables Browser Local and Session storages and
@@ -191,8 +193,11 @@
public int Age { get; set; }
}
- protected override async Task OnInitializedAsync()
+ protected override async Task OnAfterRenderAsync(bool firstRender)
{
+ if (!firstRender)
+ return;
+
//LocalStorage
await InsertLocalStorageItems();
_localStorageCount = await _localStorageService.CountAsync();
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Components/Collapse.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Components/Collapse.razor
index e53a281e..6a36b07e 100644
--- a/demo/Majorsoft.Blazor.Components.DemoApp/Components/Collapse.razor
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Components/Collapse.razor
@@ -1,6 +1,8 @@
-
Collapse Components
+
+
+
Collapse Components
- Blazor component that renders customizable Collapsible/Expandable panel and Accordion with many but only one active panel also custom content and header. For usege see soruce code and docs on
+ Blazor component that renders customizable Collapsible/Expandable panel and Accordion with many but only one active panel also custom content and header. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Collapse package is available on Nuget
- Blazor components that renders a Blazor Color Picker control with color info. For usege see soruce code and docs on
+ Blazor components that renders a Blazor Color Picker control with color info. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.ColorPicker package is available on Nuget
+
+
\ No newline at end of file
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Components/Debounce.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Components/Debounce.razor
index b78c3384..f8158b1b 100644
--- a/demo/Majorsoft.Blazor.Components.DemoApp/Components/Debounce.razor
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Components/Debounce.razor
@@ -1,6 +1,8 @@
-
Deboudnce Input controls
+
+
+
Deboudnce Input controls
- Blazor component that renders an Input, InputText, Textarea or InputTextarea, etc. element with debounced onChange. For usege see soruce code and docs on
+ Blazor component that renders an Input, InputText, Textarea or InputTextarea, etc. element with debounced onChange. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Debounce package is available on Nuget
@@ -22,7 +24,7 @@
-
@**@
-
-
@**@
- Modal Component
+
+
+
Modal Component
- Blazor component that can be used to render Modal dialog window with customizable content and parameterized Overlay, etc.. For usege see soruce code and docs on
+ Blazor component that can be used to render Modal dialog window with customizable content and parameterized Overlay, etc.. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Dialog package is available on Nuget
+ Blazor injectable IGdprConsentService service and components that renders a customizable GDPR consent Banner or Popup witch Accept/Reject for cookie settings chosen value is persisted to Browser storage.
+ To initialize GDPR Consents use GdprBanner or GdprModalonly once in your Blazor App MainLayout.razor page or any common place.
+ For usage see source code and docs on Github.
+ Majorsoft.Blazor.Components.GdprConsent package is available on Nuget
+
+
+
+ GDPR Component type: (only one of the GDPR components should be used once by apply it on a
+ common place in your App e.g.: MainLayout.razor!)
+
+
+
+@if (_gdprControlType == "Banner")
+{
+
+
+
GDPR Consent Banner
+
+
Renders a small Overlay layer at the bottom of the page with customizable content for showing the given GDPR message.
Blazor Components is a set of UI Components and other useful Extensions for Blazor applications.
@@ -30,6 +32,7 @@
Debounce Inputs
Typeahead Inputs
+
Max allowed length with Counter Inputs
Timer Component
Loading Components
@@ -43,7 +46,10 @@
Resize Js
Clipboard Js
Language Js
+
Browser Date Js
+
Browser Theme Js
Geo Js
+
Head Js
@@ -85,6 +91,8 @@
Accordion
+
GDPR Consents
+
@*
Drag and Drop
Color Picker
*@
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Components/JSInterop.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Components/JSInterop.razor
index a08f189f..ddabac18 100644
--- a/demo/Majorsoft.Blazor.Components.DemoApp/Components/JSInterop.razor
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Components/JSInterop.razor
@@ -14,9 +14,11 @@
Majorsoft.Blazor.Components.Common.JsInterop package is available on Nuget
-@*Later add scroll components here*@
- await _scrollHandler.ScrollToPageEndAsync())">Scroll to Page bottom
+@*Scroll to page end with ScrollHandler for custom floating component see ScrollToPageBottom*@
+ await _scrollHandler.ScrollToPageEndAsync(_smoothScroll))">Scroll to Page bottom (See floating components)
+Smooth scroll:
+
JS Interop features:
@@ -29,6 +31,8 @@
Resize Js
Clipboard Js
Browser Language Js
+
Browser Date Js
+
Browser Theme Js
Geolocation Js
Head Js
@@ -50,13 +54,19 @@
+
+
+
+
-@*Later add scroll components here*@
- await _scrollHandler.ScrollToPageTopAsync())">Scroll to Page top
+@*Scroll to page end with ScrollHandler for custom floating component see ScrollToPageTop*@
+ await _scrollHandler.ScrollToPageTopAsync(_smoothScroll))">Scroll to Page top (See floating components)
+Smooth scroll:
+
@implements IAsyncDisposable
@inject IScrollHandler _scrollHandler
@@ -69,4 +79,6 @@
await _scrollHandler.DisposeAsync();
}
}
+
+ private bool _smoothScroll = true;
}
\ No newline at end of file
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Components/JsDemo/BrowserDateJs.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Components/JsDemo/BrowserDateJs.razor
new file mode 100644
index 00000000..038dc059
--- /dev/null
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Components/JsDemo/BrowserDateJs.razor
@@ -0,0 +1,24 @@
+
+
+
Browser Date JS
+
+
+ Browser Date JS is an injectable IBrowserDateService service simple JS call to new Date(); to retrieve client machine date and time.
+
+
+
+ Browser date time: @_date
+
+
+
+
+@inject IBrowserDateService _dateService
+
+@code {
+ private System.DateTime _date;
+
+ private async Task Clock()
+ {
+ _date = await _dateService.GetBrowserDateTimeAsync();
+ }
+}
\ No newline at end of file
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Components/JsDemo/BrowserThemeJs.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Components/JsDemo/BrowserThemeJs.razor
new file mode 100644
index 00000000..fb97d4c7
--- /dev/null
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Components/JsDemo/BrowserThemeJs.razor
@@ -0,0 +1,58 @@
+
+
+
Browser Theme JS
+
+
+ Browser Theme JS is an injectable IBrowserThemeService to handle Browser color scheme queries and changes.
+
+ Browser color theme is: @_theme.ToString()
+
+
+
+
+ @(_themeSubscribed ? "Unsubscribe from Browser theme Change" : "Subscribe to Browser theme Change")
+
+@*Scroll on page components, can be placed anywhere on a page, moved to a new component, etc. but should be used once per page*@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Scroll JS
@@ -17,6 +45,48 @@
+
+
+
+
+
+
+ Top/Bottom margin (can be set separately for both types of controls): @(_scrcollTopBottonMargin)px
+ _scrcollTopBottonMargin = int.Parse(e.Value?.ToString()))" />
+
+
+
+
+
+ Side right/left margin (can be set separately for both types of controls): @(_scrcollTopSideMargin)px
+ _scrcollTopSideMargin = int.Parse(e.Value?.ToString()))" />
+
+
+
+
+
+ Smooth scroll (can be set separately for both types of controls):
+ Animate on Hover (can be set separately for both types of controls):
+
+
+
+
+
+ Horizontal Position right/left (can be set separately for both types of controls):
+
+
+
+
+
RegisterPageScrollAsync() will add event listener to HTML document/window scroll
- Blazor components that renders Overlay for page load. HTML @("") with customizable content for showing async operation in progress/loading state. For usege see soruce code and docs on
+ Blazor components that renders Overlay for page load. HTML @("") with customizable content for showing async operation in progress/loading state. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Loading package is available on Nuget
";
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Components/Logger.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Components/Logger.razor
index 84376f94..87e142ba 100644
--- a/demo/Majorsoft.Blazor.Components.DemoApp/Components/Logger.razor
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Components/Logger.razor
@@ -8,11 +8,11 @@
Blazor Extensions are providing useful features to develop Balazor applications:
- Blazor.Server.Logging.Console: Enables browser conole logging for Blazor applications using Server Hosted model.
+ Blazor.Server.Logging.Console: Enables browser console logging for Blazor applications using Server Hosted model.
Majorsoft.Blazor.Server.Logging.Console package is available on Nuget
- Blazor.WebAssembly.Logging.Console: Enables browser conole logging for Blazor applications using WebAssembly Hosting model.
+ Blazor.WebAssembly.Logging.Console: Enables browser console logging for Blazor applications using WebAssembly Hosting model.
Majorsoft.Blazor.WebAssembly.Logging.Console package is available on Nuget
@@ -352,8 +355,11 @@
@code {
private string _googleMapsApiKey = "AIzaSyAv-6SailPQN1R5PytUAkbdaGI9IHZTU5s";
- protected override void OnInitialized()
+ protected override async Task OnAfterRenderAsync(bool firstRender)
{
+ if (!firstRender)
+ return;
+
//Static map
_staticMapMarkers.ElementAt(0).Locations.Add(new GeolocationData(1.111, 2.222));
_staticMapMarkers.ElementAt(1).Locations.Add(new GeolocationData(17.111, 33.222));
@@ -692,7 +698,7 @@
}
private async Task OnMapZoomLevelChanged(byte zoom)
{
- //Can be used with Binding and custom event: @bind-ZoomLevel="_jsMapZoomLevel" @bind-ZoomLevel:event="OnMapZoomLevelChanged"
+ //Can be used with Binding and custom event: @bind-Zoom="_jsMapZoomLevel" @bind-Zoom:event="OnMapZoomLevelChanged"
if (_logOtherEvents)
{
_mapsLog = await WriteLog(_mapsLog, $"Map Zoom level changed to: {zoom}");
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Components/MaxLengthInputs.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Components/MaxLengthInputs.razor
new file mode 100644
index 00000000..aaaa4811
--- /dev/null
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Components/MaxLengthInputs.razor
@@ -0,0 +1,197 @@
+
+
+
+
+
Max allowed length Input controls with Counter
+
+ Blazor components that renders an Input, InputText, Textarea or InputTextarea, etc. element with maxlength set and counter to show remaining characters. For usage see source code and docs on
+ Github.
+ Majorsoft.Blazor.Components.Inputs package is available on Nuget
+
+
+
+
+
MaxLengthInput component
+
Wraps around HTML Input control and sets maxlength property with notification onChange.
- Blazor injectable IPermaLinkWatcherService service and PermaLinkElement wrapper component which allows navigation inside Blazor pages (#permalink).
- For usege see soruce code and docs on Github.
+ Blazor injectable IPermaLinkWatcherService service and PermaLinkElement wrapper component which allows navigation inside Blazor pages (#permalink).
+ To initialize navigation watcher use PermalinkBlazorWasmInitializer or PermaLinkBlazorServerInitializeronly once in your Blazor App MainLayout.razor page or any common place.
+ For usage see source code and docs on Github.
Majorsoft.Blazor.Components.PermaLink package is available on Nuget
+ Blazor extension that enables analytics services usage for Blazor applications e.g. Google Analytics, etc. For usage see source code and docs on
+ Github.
+ Majorsoft.Blazor.Extensions.Analytics package is available on Nuget
+
+
+
+
Supported Analytics service providers:
+
+
Google Analytics
+
+
+
+
+
+
Google Analytics
+
+
+ Google Analytics is a web analytics service offered by Google that tracks and reports website traffic, etc. inside the Google Marketing Platform.
+
+ IGoogleAnalyticsService is an injectable service for enabling
+ Google Analytics page tracking in Blazor Apps.
+ To make the initialization simple use GoogleAnalyticsInitializer component in your MainLayout.razor page and provide Google Analytics TrackingId.
+
+
+
+ To see how Majorsoft.Blazor.Extensions.Analytics works please check the demo code. And Google
+ analytics features since this extension mostly a JS wrapper for gtag.js.
+
+
- Blazor component that renders customizable Tabs element panel with many tabs and custom content. For usege see soruce code and docs on
+ Blazor component that renders customizable Tabs element panel with many tabs and custom content. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Tabs package is available on Nuget
TabsPanel with TabItems
-
Renders TabsPanel container for TabItem components with custumizable header and content.
+
Renders TabsPanel container for TabItem components with customizable header and content.
- Blazor component that can be used as a simple scheduler or performing periodically repeated tasks by calling custom async code. For usege see soruce code and docs on
+ Blazor component that can be used as a simple scheduler or performing periodically repeated tasks by calling custom async code. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Timer package is available on Nuget
- Blazor component that renders customizable Toggle Switch and Toggle Button components. For usege see soruce code and docs on
+ Blazor component that renders customizable Toggle Switch and Toggle Button components. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Toggle package is available on Nuget
- Blazor component that renders an HTML Input or InputText with Typeahead panel. For usege see soruce code and docs on
+ Blazor component that renders an HTML Input or InputText with Typeahead panel. For usage see source code and docs on
Github.
Majorsoft.Blazor.Components.Typeahead package is available on Nuget
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Majorsoft.Blazor.Components.DemoApp.csproj b/demo/Majorsoft.Blazor.Components.DemoApp/Majorsoft.Blazor.Components.DemoApp.csproj
index 8f8dadcc..839d7030 100644
--- a/demo/Majorsoft.Blazor.Components.DemoApp/Majorsoft.Blazor.Components.DemoApp.csproj
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Majorsoft.Blazor.Components.DemoApp.csproj
@@ -6,21 +6,24 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Pages/AnalyticsPage.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Pages/AnalyticsPage.razor
new file mode 100644
index 00000000..a6cd0ab8
--- /dev/null
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Pages/AnalyticsPage.razor
@@ -0,0 +1,3 @@
+@page "/analytics"
+
+
\ No newline at end of file
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Pages/GdprConsentPage.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Pages/GdprConsentPage.razor
new file mode 100644
index 00000000..92e71ab7
--- /dev/null
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Pages/GdprConsentPage.razor
@@ -0,0 +1,3 @@
+@page "/gdpr"
+
+
\ No newline at end of file
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Pages/MaxLengthInputPage.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Pages/MaxLengthInputPage.razor
new file mode 100644
index 00000000..47643464
--- /dev/null
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Pages/MaxLengthInputPage.razor
@@ -0,0 +1,3 @@
+@page "/maxLengthInput"
+
+
\ No newline at end of file
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Program.cs b/demo/Majorsoft.Blazor.Components.DemoApp/Program.cs
index c573fdc8..d4afdcd3 100644
--- a/demo/Majorsoft.Blazor.Components.DemoApp/Program.cs
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Program.cs
@@ -12,6 +12,8 @@
using Majorsoft.Blazor.Components.PermaLink;
using Majorsoft.Blazor.Components.Maps;
using Majorsoft.Blazor.Extensions.BrowserStorage;
+using Majorsoft.Blazor.Components.GdprConsent;
+using Majorsoft.Blazor.Extensions.Analytics;
namespace Majorsoft.Blazor.Components.DemoApp
{
@@ -30,6 +32,10 @@ public static async Task Main(string[] args)
builder.Services.AddMapExtensions();
builder.Services.AddBrowserStorage();
+ builder.Services.AddGoogleAnalytics();
+
+ builder.Services.AddGdprConsent();
+
builder.Logging.AddBrowserConsole()
.SetMinimumLevel(LogLevel.Debug).AddFilter("Microsoft", LogLevel.Information);
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Shared/MainLayout.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Shared/MainLayout.razor
index d50db091..2cc23eec 100644
--- a/demo/Majorsoft.Blazor.Components.DemoApp/Shared/MainLayout.razor
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Shared/MainLayout.razor
@@ -16,18 +16,10 @@
-@using Blazor.Components.PermaLink
-@inject IPermaLinkWatcherService _permalinkWatcher
-@implements IDisposable
+@*Permalink initialize*@
+@using Majorsoft.Blazor.Components.PermaLink
+
-@code {
- protected override void OnInitialized()
- {
- _permalinkWatcher.WatchPermaLinks();
- }
-
- public void Dispose()
- {
- _permalinkWatcher.Dispose();
- }
-}
\ No newline at end of file
+@* Google Analytics initialize*@
+@using Majorsoft.Blazor.Extensions.Analytics.Google
+
\ No newline at end of file
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Shared/NavMenu.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Shared/NavMenu.razor
index 508a93dd..a7ecf29d 100644
--- a/demo/Majorsoft.Blazor.Components.DemoApp/Shared/NavMenu.razor
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Shared/NavMenu.razor
@@ -24,7 +24,10 @@
Console logger
- Browser strorage
+ Browser storage
+
+
+ Analytics
@@ -39,6 +42,9 @@
Typeahead
+
+ Max Length
+
@@ -92,6 +98,11 @@
Collapse
+
+
+ GDPR Consents
+
+
Drag and Drop
diff --git a/demo/Majorsoft.Blazor.Components.DemoApp/Shared/PageScroll.razor b/demo/Majorsoft.Blazor.Components.DemoApp/Shared/PageScroll.razor
new file mode 100644
index 00000000..b58cf3d4
--- /dev/null
+++ b/demo/Majorsoft.Blazor.Components.DemoApp/Shared/PageScroll.razor
@@ -0,0 +1,16 @@
+@*Scroll on page components wrapped into it's own component and applied on some demo pages*@
+
+
+