From 2f7593f8e67b72d2cfb97f265a6dbff9bb8d15fa Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sat, 6 May 2023 01:26:12 +0300 Subject: [PATCH 001/196] add Dimensions Settings --- .../CroppedDimensionsSettings.razor | 26 ++++++++++++++++ .../CroppedDimensionsSettings.razor.cs | 21 +++++++++++++ .../Client/Components/GetSetCropperData.razor | 8 +++-- .../Components/GetSetCropperData.razor.cs | 5 +-- ...Settings.razor => ZoomRatioSettings.razor} | 11 ++----- ...gs.razor.cs => ZoomRatioSettings.razor.cs} | 10 +++--- .../Client/Pages/CropperDemo.razor | 20 ++++++------ .../Client/Pages/CropperDemo.razor.cs | 31 ++++++++++++++++--- .../wwwroot/overrideCropperJsInteropModule.js | 4 +-- 9 files changed, 103 insertions(+), 33 deletions(-) create mode 100644 src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor create mode 100644 src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor.cs rename src/Cropper.Blazor/Client/Components/{ZoomRationSettings.razor => ZoomRatioSettings.razor} (63%) rename src/Cropper.Blazor/Client/Components/{ZoomRationSettings.razor.cs => ZoomRatioSettings.razor.cs} (55%) diff --git a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor new file mode 100644 index 00000000..cebea3b0 --- /dev/null +++ b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor @@ -0,0 +1,26 @@ + + + + Dimensions Settings +
This option may not work with arbitrary 'Aspect Ratios' images, it is recommended to use a free Aspect Ratio for this option or calculate the allowed values yourself
+
+ + + + + + + + +
+
diff --git a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor.cs b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor.cs new file mode 100644 index 00000000..d0673efa --- /dev/null +++ b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Components; + +namespace Cropper.Blazor.Client.Components +{ + public partial class CroppedDimensionsSettings + { + private decimal? minimumWidth = null; + private decimal? maximumWidth = null; + private decimal? minimumHeight = null; + private decimal? maximumHeight = null; + + [CascadingParameter(Name = "ResetCropperAction"), Required] + public Action ResetCropperAction { get; set; } = null!; + + public decimal? MinimumWidth { get => minimumWidth; set { minimumWidth = value; ResetCropperAction.Invoke(); } } + public decimal? MaximumWidth { get => maximumWidth; set { maximumWidth = value; ResetCropperAction.Invoke(); } } + public decimal? MinimumHeight { get => minimumHeight; set { minimumHeight = value; ResetCropperAction.Invoke(); } } + public decimal? MaximumHeight { get => maximumHeight; set { maximumHeight = value; ResetCropperAction.Invoke(); } } + } +} diff --git a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor index fc8583f6..d42ef8fd 100644 --- a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor +++ b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor @@ -1,8 +1,10 @@ @using Cropper.Blazor.Models -@*//---Cropper Data---//*@ - + @*//---Enable setup minimum and maximum cropped dimensions---//*@ + + @*//---Cropper Data---//*@ + Cropper Data @@ -95,7 +97,7 @@ @*//---Enable setup max/min zoom ratio---//*@ - + @*//---Canvas Data---//*@ diff --git a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor.cs b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor.cs index 363fbc28..a1feb545 100644 --- a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor.cs +++ b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor.cs @@ -29,7 +29,8 @@ public partial class GetSetCropperData private ContainerData ContainerData = null!; private ImageData ImageData = null!; private CanvasData CanvasData = null!; - private ZoomRationSettings ZoomRationSettingszoomRationSettings = null!; + private ZoomRatioSettings ZoomRatioSettings = null!; + public CroppedDimensionsSettings CroppedDimensionsSettings = null!; protected override void OnInitialized() { @@ -42,7 +43,7 @@ protected override void OnInitialized() public void OnZoomEvent(ZoomEvent? zoomEvent) { - ZoomRationSettingszoomRationSettings!.OnZoomEvent(zoomEvent); + ZoomRatioSettings!.OnZoomEvent(zoomEvent); } public void SetCropBoxData(SetCropBoxDataOptions cropBoxDataOptions) diff --git a/src/Cropper.Blazor/Client/Components/ZoomRationSettings.razor b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor similarity index 63% rename from src/Cropper.Blazor/Client/Components/ZoomRationSettings.razor rename to src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor index d56743e2..cedda9e3 100644 --- a/src/Cropper.Blazor/Client/Components/ZoomRationSettings.razor +++ b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor @@ -1,5 +1,6 @@  - + + Zoom Ratio Settings - - - Apply zoom rules for Cropper - - diff --git a/src/Cropper.Blazor/Client/Components/ZoomRationSettings.razor.cs b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs similarity index 55% rename from src/Cropper.Blazor/Client/Components/ZoomRationSettings.razor.cs rename to src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs index 318238dd..a001b990 100644 --- a/src/Cropper.Blazor/Client/Components/ZoomRationSettings.razor.cs +++ b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs @@ -4,11 +4,13 @@ namespace Cropper.Blazor.Client.Components { - public partial class ZoomRationSettings + public partial class ZoomRatioSettings { - private decimal? MinZoomRatio = null; - private decimal? MaxZoomRatio = null; + private decimal? minZoomRatio = null; + private decimal? maxZoomRatio = null; + private decimal? MinZoomRatio { get => minZoomRatio; set { minZoomRatio=value; ApplyZoomRulesForCropperAsync(); } } + private decimal? MaxZoomRatio { get => maxZoomRatio; set { maxZoomRatio=value; ApplyZoomRulesForCropperAsync(); } } [Inject] private IJSRuntime? JSRuntime { get; set; } private decimal? OldRatio { get; set; } = null; @@ -25,7 +27,7 @@ public void OnZoomEvent(ZoomEvent? zoomEvent) public async Task ApplyZoomRulesForCropperAsync() { - await JSRuntime!.InvokeVoidAsync("window.overrideCropperJsInteropModule", MinZoomRatio, MaxZoomRatio); + await JSRuntime!.InvokeVoidAsync("window.overrideOnZoomCropperEvent", MinZoomRatio, MaxZoomRatio); } } } diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index 968f4f67..2dae1df3 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -321,14 +321,16 @@ @*//+---// Get/Set all cropper data //---+//*@ - + + + diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index b1a0791a..4b7be633 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -63,11 +63,34 @@ public async void OnCropEvent(JSEventData cropJSEvent) ScaleXValue = cropJSEvent.Detail.ScaleX; ScaleYValue = cropJSEvent.Detail.ScaleY; - await InvokeAsync(() => + decimal width = Math.Round(cropJSEvent.Detail.Width ?? 0); + decimal height = Math.Round(cropJSEvent.Detail.Height ?? 0); + + if (width < GetSetCropperData!.CroppedDimensionsSettings.MinimumWidth + || height < GetSetCropperData!.CroppedDimensionsSettings.MinimumHeight + || width > GetSetCropperData!.CroppedDimensionsSettings.MaximumWidth + || height > GetSetCropperData!.CroppedDimensionsSettings.MaximumHeight + ) { - //JSRuntime!.InvokeVoidAsync("console.log", $"CropJSEvent {JsonSerializer.Serialize(cropJSEvent)}"); - CropperDataPreview?.OnCropEvent(cropJSEvent.Detail); - }); + CropperComponent!.SetData(new SetDataOptions + { + Width = Math.Max( + GetSetCropperData!.CroppedDimensionsSettings.MinimumWidth ?? 0M, + Math.Min(GetSetCropperData!.CroppedDimensionsSettings.MaximumWidth ?? 0M, width)), + Height = Math.Max( + GetSetCropperData!.CroppedDimensionsSettings.MinimumHeight ?? 0M, + Math.Min(GetSetCropperData!.CroppedDimensionsSettings.MaximumHeight ?? 0M, height)), + + }); + } + else + { + await InvokeAsync(() => + { + //JSRuntime!.InvokeVoidAsync("console.log", $"CropJSEvent {JsonSerializer.Serialize(cropJSEvent)}"); + CropperDataPreview?.OnCropEvent(cropJSEvent.Detail); + }); + } } } diff --git a/src/Cropper.Blazor/Client/wwwroot/overrideCropperJsInteropModule.js b/src/Cropper.Blazor/Client/wwwroot/overrideCropperJsInteropModule.js index f4173780..103ad7f7 100644 --- a/src/Cropper.Blazor/Client/wwwroot/overrideCropperJsInteropModule.js +++ b/src/Cropper.Blazor/Client/wwwroot/overrideCropperJsInteropModule.js @@ -1,4 +1,4 @@ -window.overrideCropperJsInteropModule = (minZoomRatio, maxZoomRatio) => { +window.overrideOnZoomCropperEvent = (minZoomRatio, maxZoomRatio) => { window.cropper.onZoom = function (imageObject, event, correlationId) { const jSEventData = this.getJSEventData(event, correlationId); const isApplyPreventZoomRatio = minZoomRatio != null || maxZoomRatio != null; @@ -10,4 +10,4 @@ imageObject.invokeMethodAsync('CropperIsZoomed', jSEventData); } }; -}; +}; \ No newline at end of file From 89089b15ed1621a4774c76fd792d71d558df97ae Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sat, 6 May 2023 02:12:47 +0300 Subject: [PATCH 002/196] Fix whitespace formatting. --- .../Components/ZoomRatioSettings.razor.cs | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs index a001b990..120ad49d 100644 --- a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs +++ b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs @@ -9,8 +9,24 @@ public partial class ZoomRatioSettings private decimal? minZoomRatio = null; private decimal? maxZoomRatio = null; - private decimal? MinZoomRatio { get => minZoomRatio; set { minZoomRatio=value; ApplyZoomRulesForCropperAsync(); } } - private decimal? MaxZoomRatio { get => maxZoomRatio; set { maxZoomRatio=value; ApplyZoomRulesForCropperAsync(); } } + private decimal? MinZoomRatio + { + get => minZoomRatio; + set + { + minZoomRatio = value; + ApplyZoomRulesForCropperAsync(); + } + } + private decimal? MaxZoomRatio + { + get => maxZoomRatio; + set + { + maxZoomRatio = value; + ApplyZoomRulesForCropperAsync(); + } + } [Inject] private IJSRuntime? JSRuntime { get; set; } private decimal? OldRatio { get; set; } = null; @@ -30,4 +46,4 @@ public async Task ApplyZoomRulesForCropperAsync() await JSRuntime!.InvokeVoidAsync("window.overrideOnZoomCropperEvent", MinZoomRatio, MaxZoomRatio); } } -} +} \ No newline at end of file From ca0865aba795c831577d3c9c3454ff2514b3c72a Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sun, 28 May 2023 21:52:04 +0300 Subject: [PATCH 003/196] add aspect ratio settings --- .../Components/AspectRatioSettings.razor | 19 ++++ .../Components/AspectRatioSettings.razor.cs | 89 +++++++++++++++++++ .../Client/Components/GetSetCropperData.razor | 3 +- .../Components/GetSetCropperData.razor.cs | 2 + .../Client/Pages/CropperDemo.razor | 50 ++++++----- .../Client/Pages/CropperDemo.razor.cs | 39 +++++++- 6 files changed, 176 insertions(+), 26 deletions(-) create mode 100644 src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor create mode 100644 src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor new file mode 100644 index 00000000..6f039b66 --- /dev/null +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor @@ -0,0 +1,19 @@ + + + Aspect Ratio Settings (only for FREE aspect ratio) + + + + + + Current aspect ratio: @AspectRatio + + + diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs new file mode 100644 index 00000000..df0392e6 --- /dev/null +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs @@ -0,0 +1,89 @@ +using System.ComponentModel.DataAnnotations; +using Cropper.Blazor.Client.Pages; +using Cropper.Blazor.Models; +using Microsoft.AspNetCore.Components; + +namespace Cropper.Blazor.Client.Components +{ + public partial class AspectRatioSettings + { + private decimal? maxAspectRatio; + private decimal? minAspectRatio; + private bool isEnableAspectRatioSettings; + + public decimal? MaxAspectRatio + { + get => maxAspectRatio; + set + { + maxAspectRatio = value; + ApplyAspectRatioRulesForCropperAsync(); + } + } + + public decimal? MinAspectRatio + { + get => minAspectRatio; + set + { + minAspectRatio = value; + ApplyAspectRatioRulesForCropperAsync(); + } + } + + [CascadingParameter(Name = "AspectRatio"), Required] + private decimal? AspectRatio { get; set; } + + [CascadingParameter(Name = "CropperDemo"), Required] + private CropperDemo CropperDemo { get; set; } = null!; + + [CascadingParameter(Name = "IsEnableAspectRatioSettings"), Required] + private bool IsEnableAspectRatioSettings + { + get => isEnableAspectRatioSettings; + set + { + if (!value) + { + minAspectRatio = null; + maxAspectRatio = null; + } + + isEnableAspectRatioSettings = value; + } + } + + public async Task ApplyAspectRatioRulesForCropperAsync() + { + if (minAspectRatio is not null || maxAspectRatio is not null) + { + ContainerData containerData = await CropperDemo.CropperComponent!.GetContainerDataAsync(); + CropBoxData cropBoxData = await CropperDemo.CropperComponent!.GetCropBoxDataAsync(); + + if (cropBoxData.Height != 0) + { + decimal aspectRatio = cropBoxData.Width / cropBoxData.Height; + + if (aspectRatio < minAspectRatio || aspectRatio > maxAspectRatio) + { + decimal? newCropBoxWidth = cropBoxData.Height * ((minAspectRatio + maxAspectRatio) / 2); + + CropperDemo.CropperComponent!.SetCropBoxData(new SetCropBoxDataOptions + { + Left = (containerData.Width - newCropBoxWidth) / 2, + Width = newCropBoxWidth, + }); + } + + SetUpAspectRatio(aspectRatio); + } + } + } + + public void SetUpAspectRatio(decimal aspectRatio) + { + AspectRatio = aspectRatio; + StateHasChanged(); + } + } +} \ No newline at end of file diff --git a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor index d42ef8fd..e91f3b37 100644 --- a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor +++ b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor @@ -72,8 +72,9 @@ @*//---Image Data---//*@ + - + Image Data diff --git a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor.cs b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor.cs index a1feb545..35c3868b 100644 --- a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor.cs +++ b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor.cs @@ -24,6 +24,8 @@ public partial class GetSetCropperData [Parameter, Required] public Func> GetCanvasData { get; set; } = null!; + public AspectRatioSettings AspectRatioSettings = null!; + private CropBoxData CropBoxData = null!; private CropperData CropperData = null!; private ContainerData ContainerData = null!; diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index 2dae1df3..2f3bd147 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -183,31 +183,31 @@ + Style="@(AspectRatio == 1.7777777777777777m && !IsEnableAspectRatioSettings ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 16:9 + Style="@(AspectRatio == 1.3333333333333333m && !IsEnableAspectRatioSettings ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 4:3 + Style="@(AspectRatio == 1m && !IsEnableAspectRatioSettings ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 1:1 + Style="@(AspectRatio == 0.6666666666666666m && !IsEnableAspectRatioSettings ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 2:3 - + Free @@ -243,31 +243,31 @@ + Style="@(AspectRatio == 1.7777777777777777m && !IsEnableAspectRatioSettings ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 16:9 + Style="@(AspectRatio == 1.3333333333333333m && !IsEnableAspectRatioSettings ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 4:3 + Style="@(AspectRatio == 1m && !IsEnableAspectRatioSettings ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 1:1 + Style="@(AspectRatio == 0.6666666666666666m && !IsEnableAspectRatioSettings ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 2:3 - + Free @@ -321,16 +321,22 @@ @*//+---// Get/Set all cropper data //---+//*@ - - + + + + + + + + diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 4b7be633..39fe603c 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -25,13 +25,14 @@ public partial class CropperDemo : IDisposable [Inject] private IJSRuntime? JSRuntime { get; set; } - private CropperComponent? CropperComponent = null!; + public CropperComponent? CropperComponent = null!; private CropperDataPreview? CropperDataPreview = null!; private GetSetCropperData? GetSetCropperData = null!; private Options Options = null!; private decimal? ScaleXValue; private decimal? ScaleYValue; private decimal AspectRatio = 1.7777777777777777m; + private bool IsEnableAspectRatioSettings; private string Src = "https://fengyuanchen.github.io/cropperjs/v2/picture.jpg"; private bool IsErrorLoadImage { get; set; } = false; @@ -155,6 +156,35 @@ public async void OnCropMoveEvent(JSEventData cropMoveJSEvent) // await JSRuntime!.InvokeVoidAsync("console.log", $"CropMoveJSEvent OriginalEvent clientX: {clientX}"); //} + + if (GetSetCropperData?.AspectRatioSettings?.MinAspectRatio is not null + || GetSetCropperData?.AspectRatioSettings?.MaxAspectRatio is not null) + { + CropBoxData cropBoxData = await CropperComponent!.GetCropBoxDataAsync(); + + if (cropBoxData.Height != 0) + { + decimal aspectRatio = cropBoxData.Width / cropBoxData.Height; + + AspectRatio = aspectRatio; + GetSetCropperData!.AspectRatioSettings.SetUpAspectRatio(aspectRatio); + + if (aspectRatio < GetSetCropperData!.AspectRatioSettings!.MinAspectRatio) + { + CropperComponent!.SetCropBoxData(new SetCropBoxDataOptions + { + Width = cropBoxData.Height * GetSetCropperData!.AspectRatioSettings.MinAspectRatio + }); + } + else if (aspectRatio > GetSetCropperData!.AspectRatioSettings!.MaxAspectRatio) + { + CropperComponent!.SetCropBoxData(new SetCropBoxDataOptions + { + Width = cropBoxData.Height * GetSetCropperData!.AspectRatioSettings.MaxAspectRatio + }); + } + } + } } public async void OnCropReadyEvent(JSEventData jSEventData) @@ -250,12 +280,15 @@ private void Destroy() CropperComponent?.RevokeObjectUrlAsync(Src); } - public void SetAspectRatio(decimal aspectRatio) + public void SetAspectRatio(decimal aspectRatio, bool isEnableAspectRatioSettings = false) { - this.AspectRatio = aspectRatio; + IsEnableAspectRatioSettings = isEnableAspectRatioSettings; + AspectRatio = aspectRatio; CropperComponent?.SetAspectRatio(aspectRatio); } + public void SetFreeAspectRatio() => SetAspectRatio(0, true); + public void SetViewMode(ViewMode viewMode) { Options.ViewMode = viewMode; From 26ec4f45f6ee11522c53cbeff4987b1874e9f082 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Mon, 29 May 2023 11:23:38 +0300 Subject: [PATCH 004/196] fix update current aspect ratio in settings --- .../Components/AspectRatioSettings.razor.cs | 2 +- .../Client/Pages/CropperDemo.razor.cs | 22 +++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs index df0392e6..8d2535aa 100644 --- a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs @@ -80,7 +80,7 @@ public async Task ApplyAspectRatioRulesForCropperAsync() } } - public void SetUpAspectRatio(decimal aspectRatio) + public void SetUpAspectRatio(decimal? aspectRatio) { AspectRatio = aspectRatio; StateHasChanged(); diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 39fe603c..5b95158b 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -156,19 +156,18 @@ public async void OnCropMoveEvent(JSEventData cropMoveJSEvent) // await JSRuntime!.InvokeVoidAsync("console.log", $"CropMoveJSEvent OriginalEvent clientX: {clientX}"); //} + CropBoxData cropBoxData = await CropperComponent!.GetCropBoxDataAsync(); - if (GetSetCropperData?.AspectRatioSettings?.MinAspectRatio is not null - || GetSetCropperData?.AspectRatioSettings?.MaxAspectRatio is not null) + if (cropBoxData.Height != 0) { - CropBoxData cropBoxData = await CropperComponent!.GetCropBoxDataAsync(); + decimal aspectRatio = cropBoxData.Width / cropBoxData.Height; - if (cropBoxData.Height != 0) - { - decimal aspectRatio = cropBoxData.Width / cropBoxData.Height; - - AspectRatio = aspectRatio; - GetSetCropperData!.AspectRatioSettings.SetUpAspectRatio(aspectRatio); + AspectRatio = aspectRatio; + GetSetCropperData!.AspectRatioSettings.SetUpAspectRatio(aspectRatio); + if (GetSetCropperData?.AspectRatioSettings?.MinAspectRatio is not null + || GetSetCropperData?.AspectRatioSettings?.MaxAspectRatio is not null) + { if (aspectRatio < GetSetCropperData!.AspectRatioSettings!.MinAspectRatio) { CropperComponent!.SetCropBoxData(new SetCropBoxDataOptions @@ -185,6 +184,11 @@ public async void OnCropMoveEvent(JSEventData cropMoveJSEvent) } } } + else + { + AspectRatio = 0; + GetSetCropperData!.AspectRatioSettings.SetUpAspectRatio(0); + } } public async void OnCropReadyEvent(JSEventData jSEventData) From 2a4d53499dc048572248aaa19a05a3408538b838 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Mon, 29 May 2023 11:34:27 +0300 Subject: [PATCH 005/196] small fix --- src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 5b95158b..607b378b 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -287,7 +287,12 @@ private void Destroy() public void SetAspectRatio(decimal aspectRatio, bool isEnableAspectRatioSettings = false) { IsEnableAspectRatioSettings = isEnableAspectRatioSettings; - AspectRatio = aspectRatio; + + if (aspectRatio != 0) + { + AspectRatio = aspectRatio; + } + CropperComponent?.SetAspectRatio(aspectRatio); } From 8dcea02c0eab8b91056ad992ca5acb087a1962c3 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Mon, 29 May 2023 16:51:56 +0300 Subject: [PATCH 006/196] update nuget packages --- src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj | 2 +- .../Cropper.Blazor.UnitTests.csproj | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj index dd59915f..ed83a32e 100644 --- a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj +++ b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj @@ -31,7 +31,7 @@ - + diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj index b41322a0..5cbf0acc 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj @@ -9,20 +9,20 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 5f4ce94a667aad23f279295be46bbff616ecda36 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Mon, 29 May 2023 17:02:13 +0300 Subject: [PATCH 007/196] fix tests --- .../Components/CropperComponent_Should.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs index f95a7cbd..4e22545a 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs @@ -480,8 +480,8 @@ public void Verify_Method_To_Be_Invokable_From_JS(string methodName) public void Dispose() { - _testContext.Dispose(); _testContext.DisposeComponents(); + _testContext.Dispose(); GC.SuppressFinalize(this); } } From c82d4e64ebf826856e2151a910ddeb049a26ccca Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Thu, 22 Jun 2023 00:45:25 +0300 Subject: [PATCH 008/196] add download cropped image functionality to UI --- .../Client/Cropper.Blazor.Client.csproj | 4 ++++ .../Client/Shared/CroppedCanvasDialog.razor | 17 +++++++-------- .../Shared/CroppedCanvasDialog.razor.cs | 21 +++++++++++++++++++ src/Cropper.Blazor/Client/wwwroot/helper.js | 7 +++++++ src/Cropper.Blazor/Client/wwwroot/index.html | 1 + 5 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 src/Cropper.Blazor/Client/Shared/CroppedCanvasDialog.razor.cs create mode 100644 src/Cropper.Blazor/Client/wwwroot/helper.js diff --git a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj index ed83a32e..1e7de7cc 100644 --- a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj +++ b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj @@ -104,6 +104,7 @@ + @@ -121,6 +122,7 @@ + @@ -129,12 +131,14 @@ + + diff --git a/src/Cropper.Blazor/Client/Shared/CroppedCanvasDialog.razor b/src/Cropper.Blazor/Client/Shared/CroppedCanvasDialog.razor index 8fd81c47..9759bb92 100644 --- a/src/Cropper.Blazor/Client/Shared/CroppedCanvasDialog.razor +++ b/src/Cropper.Blazor/Client/Shared/CroppedCanvasDialog.razor @@ -2,7 +2,9 @@ - + + + Cropped canvas data @@ -12,13 +14,8 @@ - + + Download image by link + - -@code { - [CascadingParameter] private MudDialogInstance MudDialog { get; set; } = null!; - - [Parameter] - [System.ComponentModel.DataAnnotations.Required] - public string Src { get; set; } = null!; -} \ No newline at end of file + \ No newline at end of file diff --git a/src/Cropper.Blazor/Client/Shared/CroppedCanvasDialog.razor.cs b/src/Cropper.Blazor/Client/Shared/CroppedCanvasDialog.razor.cs new file mode 100644 index 00000000..8fe26d08 --- /dev/null +++ b/src/Cropper.Blazor/Client/Shared/CroppedCanvasDialog.razor.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; + +namespace Cropper.Blazor.Client.Shared +{ + public partial class CroppedCanvasDialog + { + [Parameter] + [System.ComponentModel.DataAnnotations.Required] + public string Src { get; set; } = null!; + + [Inject] private IJSRuntime? JSRuntime { get; set; } + + public async Task DownloadImageSrcAsync() + { + await JSRuntime!.InvokeVoidAsync( + "downloadFromUrl", + new { Url = Src, FileName = $"{Guid.NewGuid()}.png" }); + } + } +} diff --git a/src/Cropper.Blazor/Client/wwwroot/helper.js b/src/Cropper.Blazor/Client/wwwroot/helper.js new file mode 100644 index 00000000..b4af1b2a --- /dev/null +++ b/src/Cropper.Blazor/Client/wwwroot/helper.js @@ -0,0 +1,7 @@ +window.downloadFromUrl = (options) => { + const anchorElement = document.createElement('a'); + anchorElement.href = options.url; + anchorElement.download = options.fileName ?? ''; + anchorElement.click(); + anchorElement.remove(); +}; \ No newline at end of file diff --git a/src/Cropper.Blazor/Client/wwwroot/index.html b/src/Cropper.Blazor/Client/wwwroot/index.html index e8caaf14..ca7e8df9 100644 --- a/src/Cropper.Blazor/Client/wwwroot/index.html +++ b/src/Cropper.Blazor/Client/wwwroot/index.html @@ -130,6 +130,7 @@ + From 9c9b371a91aa112274799f29c77c2cf283f850e5 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Thu, 22 Jun 2023 00:47:04 +0300 Subject: [PATCH 009/196] format file --- .../Client/Cropper.Blazor.Client.csproj | 320 +++++++++--------- 1 file changed, 160 insertions(+), 160 deletions(-) diff --git a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj index 1e7de7cc..e05c051b 100644 --- a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj +++ b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj @@ -1,163 +1,163 @@  - - - IncludeGeneratedStaticFiles; - $(ResolveStaticWebAssetsInputsDependsOn) - - - - - false - - - - net7.0 - enable - enable - service-worker-assets.js - - - - false - false - - - - - - - - - - - - - - - - - - - - - - - - <_ContentIncludedByDefault Remove="Pages\CroppedCanvasDialog.razor" /> - - - - - $(MSBuildThisFileDirectory)../ - - - - - - - $(SolutionDir)Cropper.Blazor.Client.Compiler/bin/Debug/netcoreapp3.1/Cropper.Blazor.Client.Compiler.dll - - - - - $(SolutionDir)Cropper.Blazor.Client.Compiler/bin/Debug/net7.0/Cropper.Blazor.Client.Compiler.dll - - - - - - - dotnet run --configuration release --project "$(SolutionDir)Cropper.Blazor.Client.Compiler/Cropper.Blazor.Client.Compiler.csproj" - - - - - - - - - - - - - - - - - - - - - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + IncludeGeneratedStaticFiles; + $(ResolveStaticWebAssetsInputsDependsOn) + + + + + false + + + + net7.0 + enable + enable + service-worker-assets.js + + + + false + false + + + + + + + + + + + + + + + + + + + + + + + + <_ContentIncludedByDefault Remove="Pages\CroppedCanvasDialog.razor" /> + + + + + $(MSBuildThisFileDirectory)../ + + + + + + + $(SolutionDir)Cropper.Blazor.Client.Compiler/bin/Debug/netcoreapp3.1/Cropper.Blazor.Client.Compiler.dll + + + + + $(SolutionDir)Cropper.Blazor.Client.Compiler/bin/Debug/net7.0/Cropper.Blazor.Client.Compiler.dll + + + + + + + dotnet run --configuration release --project "$(SolutionDir)Cropper.Blazor.Client.Compiler/Cropper.Blazor.Client.Compiler.csproj" + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 220aa7836aaa32668dca75f14bd6742d436f868d Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Thu, 22 Jun 2023 17:33:58 +0300 Subject: [PATCH 010/196] add replace image functionality --- .../Components/CropperComponent_Should.cs | 5 +++++ .../Components/CropperComponent.razor.cs | 14 ++++++++++++++ .../Cropper.Blazor/Services/CropperJsInterop.cs | 6 +++--- .../Cropper.Blazor/Services/ICropperJsInterop.cs | 4 ++-- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs index 4e22545a..9dcf36de 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs @@ -127,6 +127,8 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() decimal ratio = faker.Random.Decimal(); decimal pivotX = faker.Random.Decimal(); decimal pivotY = faker.Random.Decimal(); + string newUrlImage = faker.Random.Word(); + bool hasSameSize = faker.Random.Bool(); Action? onLoadImageHandler = () => { @@ -350,6 +352,9 @@ await cropperComponent.InvokeAsync(async () => expectedImageData.Should().Be(imageData); _mockCropperJsInterop.Verify(c => c.GetImageDataAsync(cancellationToken), Times.Once()); + await cropperComponent.Instance.ReplaceAsync(newUrlImage, hasSameSize); + _mockCropperJsInterop.Verify(c => c.ReplaceAsync(newUrlImage, hasSameSize, cancellationToken), Times.Once()); + string image = await cropperComponent.Instance.GetImageUsingStreamingAsync(imageFile, maxAllowedSize, cancellationToken); expectedImage.Should().Be(image); _mockCropperJsInterop.Verify(c => c.GetImageUsingStreamingAsync(imageFile, maxAllowedSize, cancellationToken), Times.Once()); diff --git a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs index 800494d0..10368cde 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs @@ -481,6 +481,20 @@ public async ValueTask GetContainerDataAsync(CancellationToken ca return await CropperJsIntertop!.GetContainerDataAsync(cancellationToken); } + /// + /// Replace the image's src and rebuild the cropper. + /// + /// The new URL. + /// If the new image has the same size as the old one, then it will not rebuild the cropper and only update the URLs of all related images. This can be used for applying filters. + /// The used to propagate notifications that the operation should be canceled. + /// A representing any asynchronous operation. + public async ValueTask ReplaceAsync(string url, + bool hasSameSize, + CancellationToken cancellationToken = default) + { + await CropperJsIntertop!.ReplaceAsync(url, hasSameSize, cancellationToken); + } + /// /// Output the image position, size and other related data. /// diff --git a/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs b/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs index 983ae6ee..51feb97d 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs @@ -315,12 +315,12 @@ public async ValueTask MoveToAsync( /// Replace the image's src and rebuild the cropper. /// /// The new URL. - /// Indicate if the new image has the same size as the old one. + /// If the new image has the same size as the old one, then it will not rebuild the cropper and only update the URLs of all related images. This can be used for applying filters. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask ReplaceAsync( string url, - bool onlyColorChanged, + bool hasSameSize, CancellationToken cancellationToken = default) { if (Module is null) @@ -328,7 +328,7 @@ public async ValueTask ReplaceAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.replace", cancellationToken, url, onlyColorChanged); + await _jsRuntime!.InvokeVoidAsync("cropper.replace", cancellationToken, url, hasSameSize); } /// diff --git a/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs b/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs index e6ce4421..7a811074 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs @@ -136,12 +136,12 @@ ValueTask MoveToAsync( /// Replace the image's src and rebuild the cropper. /// /// The new URL. - /// Indicate if the new image has the same size as the old one. + /// Indicate if the new image has the same size as the old one. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask ReplaceAsync( string url, - bool onlyColorChanged, + bool hasSameSize, CancellationToken cancellationToken = default); /// From bbe58f003993d46ce6e2b309c013ef2cf4576a99 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Thu, 22 Jun 2023 17:37:29 +0300 Subject: [PATCH 011/196] align code --- .../Cropper.Blazor/Components/CropperComponent.razor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs index 10368cde..2d0c19ab 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs @@ -488,7 +488,8 @@ public async ValueTask GetContainerDataAsync(CancellationToken ca /// If the new image has the same size as the old one, then it will not rebuild the cropper and only update the URLs of all related images. This can be used for applying filters. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - public async ValueTask ReplaceAsync(string url, + public async ValueTask ReplaceAsync( + string url, bool hasSameSize, CancellationToken cancellationToken = default) { From 33d17465caa280c59e70d38f6c5ee83b8b8f5692 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Thu, 22 Jun 2023 17:38:59 +0300 Subject: [PATCH 012/196] fix comment --- src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs b/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs index 7a811074..f137fc5e 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs @@ -136,7 +136,7 @@ ValueTask MoveToAsync( /// Replace the image's src and rebuild the cropper. /// /// The new URL. - /// Indicate if the new image has the same size as the old one. + /// If the new image has the same size as the old one, then it will not rebuild the cropper and only update the URLs of all related images. This can be used for applying filters. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask ReplaceAsync( From 9f3b953ddccc424c8b1e463cd0fd00cd206e2d01 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Thu, 22 Jun 2023 17:44:05 +0300 Subject: [PATCH 013/196] update version nuget package --- src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj index 2f389a1f..5e652df5 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj @@ -14,7 +14,7 @@ - 1.2.0 + 1.2.1 LICENSE NuGet.png Cropper.Blazor From ed9969bbf32b7052e0b484b3645194dce7aab1c9 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Thu, 22 Jun 2023 23:59:58 +0300 Subject: [PATCH 014/196] fix incorrect Base Path Resolution for CropperJSInterop.min.js --- .../Cropper.Blazor.MAUI.Net6.csproj | 2 +- .../Cropper.Blazor.MAUI.Net7.csproj | 4 +- .../Cropper.Blazor.Server.Net6.csproj | 2 +- .../Cropper.Blazor.Server.Net7.csproj | 4 +- ...Cropper.MVC.With.Blazor.Server.Net7.csproj | 2 +- .../Client/Cropper.Blazor.Client.csproj | 14 +- .../Client/Pages/CropperDemo.razor.cs | 2 +- .../Client/Shared/MainLayout.razor.cs | 4 +- .../Cropper.Blazor.Testing.csproj | 1 + .../ServiceCollectionMock.cs | 13 +- .../ServiceCollectionVerifier.cs | 21 ++- .../ServiceDescriptionExtensions.cs | 10 +- .../Cropper.Blazor.UnitTests.csproj | 4 +- .../ServiceCollectionExtensions_Should.cs | 35 +++-- .../Extensions/UriExtensions_Should.cs | 73 ++++++++++ .../Services/CropperJsInterop_Should.cs | 62 +------- .../Services/LoadCropperModule_Should.cs | 133 ++++++++++++++++++ .../Cropper.Blazor/Cropper.Blazor.csproj | 2 +- .../Extensions/ServiceCollectionExtensions.cs | 10 +- .../Extensions/UriExtensions.cs | 17 +++ .../ModuleOptions/CropperJsInteropOptions.cs | 23 +++ .../ModuleOptions/ICropperJsInteropOptions.cs | 23 +++ .../Services/CropperJsInterop.cs | 34 +++-- .../Server/Cropper.Blazor.Server.csproj | 2 +- 24 files changed, 387 insertions(+), 110 deletions(-) create mode 100644 src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/UriExtensions_Should.cs create mode 100644 src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/LoadCropperModule_Should.cs create mode 100644 src/Cropper.Blazor/Cropper.Blazor/Extensions/UriExtensions.cs create mode 100644 src/Cropper.Blazor/Cropper.Blazor/ModuleOptions/CropperJsInteropOptions.cs create mode 100644 src/Cropper.Blazor/Cropper.Blazor/ModuleOptions/ICropperJsInteropOptions.cs diff --git a/examples/Cropper.Blazor.MAUI.Net6/Cropper.Blazor.MAUI.Net6.csproj b/examples/Cropper.Blazor.MAUI.Net6/Cropper.Blazor.MAUI.Net6.csproj index d394fa69..9ee658db 100644 --- a/examples/Cropper.Blazor.MAUI.Net6/Cropper.Blazor.MAUI.Net6.csproj +++ b/examples/Cropper.Blazor.MAUI.Net6/Cropper.Blazor.MAUI.Net6.csproj @@ -50,7 +50,7 @@ - + diff --git a/examples/Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj b/examples/Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj index cfcbcb7a..810dea03 100644 --- a/examples/Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj +++ b/examples/Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj @@ -50,8 +50,8 @@ - - + + diff --git a/examples/Cropper.Blazor.Server.Net6/Cropper.Blazor.Server.Net6.csproj b/examples/Cropper.Blazor.Server.Net6/Cropper.Blazor.Server.Net6.csproj index 4566cee8..cc8a04b5 100644 --- a/examples/Cropper.Blazor.Server.Net6/Cropper.Blazor.Server.Net6.csproj +++ b/examples/Cropper.Blazor.Server.Net6/Cropper.Blazor.Server.Net6.csproj @@ -7,7 +7,7 @@ - + diff --git a/examples/Cropper.Blazor.Server.Net7/Cropper.Blazor.Server.Net7.csproj b/examples/Cropper.Blazor.Server.Net7/Cropper.Blazor.Server.Net7.csproj index 3ea12789..1a2efe86 100644 --- a/examples/Cropper.Blazor.Server.Net7/Cropper.Blazor.Server.Net7.csproj +++ b/examples/Cropper.Blazor.Server.Net7/Cropper.Blazor.Server.Net7.csproj @@ -1,4 +1,4 @@ - + net7.0 @@ -7,7 +7,7 @@ - + diff --git a/examples/Cropper.MVC.With.Blazor.Server.Net7/Cropper.MVC.With.Blazor.Server.Net7.csproj b/examples/Cropper.MVC.With.Blazor.Server.Net7/Cropper.MVC.With.Blazor.Server.Net7.csproj index 6b5a6dab..bf7f45f2 100644 --- a/examples/Cropper.MVC.With.Blazor.Server.Net7/Cropper.MVC.With.Blazor.Server.Net7.csproj +++ b/examples/Cropper.MVC.With.Blazor.Server.Net7/Cropper.MVC.With.Blazor.Server.Net7.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj index e05c051b..0ebddae2 100644 --- a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj +++ b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj @@ -27,13 +27,13 @@ - - - - - - - + + + + + + + diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 607b378b..5cd905e8 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -341,7 +341,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { - var subscriptionResult = await BreakpointListener.Subscribe((breakpoint) => + var subscriptionResult = await BreakpointListener.SubscribeAsync((breakpoint) => { InvokeAsync(StateHasChanged); }); diff --git a/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs index 2666d839..34fab34e 100644 --- a/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs @@ -25,7 +25,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { - SubscriptionId = await ResizeService.Subscribe((size) => + SubscriptionId = await ResizeService.SubscribeAsync((size) => { if (size.Width > 960) { @@ -48,7 +48,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) await base.OnAfterRenderAsync(firstRender); } - public async ValueTask DisposeAsync() => await ResizeService.Unsubscribe(SubscriptionId); + public async ValueTask DisposeAsync() => await ResizeService.UnsubscribeAsync(SubscriptionId); private async Task ApplyUserPreferences() { diff --git a/src/Cropper.Blazor/Cropper.Blazor.Testing/Cropper.Blazor.Testing.csproj b/src/Cropper.Blazor/Cropper.Blazor.Testing/Cropper.Blazor.Testing.csproj index 2964c3b7..913eae3d 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.Testing/Cropper.Blazor.Testing.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor.Testing/Cropper.Blazor.Testing.csproj @@ -7,6 +7,7 @@ + diff --git a/src/Cropper.Blazor/Cropper.Blazor.Testing/ServiceCollectionMock.cs b/src/Cropper.Blazor/Cropper.Blazor.Testing/ServiceCollectionMock.cs index cf53ebd7..76177d64 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.Testing/ServiceCollectionMock.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.Testing/ServiceCollectionMock.cs @@ -12,19 +12,24 @@ public ServiceCollectionMock(Mock serviceCollectionMock) _serviceCollectionVerifier = new ServiceCollectionVerifier(serviceCollectionMock); } + public void TryContainsSingletonService() + { + _serviceCollectionVerifier.TryContainsSingletonService(); + } + public void ContainsSingletonService() { _serviceCollectionVerifier.ContainsSingletonService(); } - public void ContainsTransientService() + public void TryContainsTransientService() { - _serviceCollectionVerifier.ContainsTransientService(); + _serviceCollectionVerifier.TryContainsTransientService(); } - public void ContainsScopedService() + public void TryContainsScopedService() { - _serviceCollectionVerifier.ContainsTransientService(); + _serviceCollectionVerifier.TryContainsScopedService(); } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.Testing/ServiceCollectionVerifier.cs b/src/Cropper.Blazor/Cropper.Blazor.Testing/ServiceCollectionVerifier.cs index 53758538..ee27b5cc 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.Testing/ServiceCollectionVerifier.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.Testing/ServiceCollectionVerifier.cs @@ -12,19 +12,31 @@ public ServiceCollectionVerifier(Mock serviceCollectionMock) _serviceCollectionMock = serviceCollectionMock; } + public void TryContainsSingletonService() + { + TryIsRegistered(ServiceLifetime.Singleton); + } + public void ContainsSingletonService() { IsRegistered(ServiceLifetime.Singleton); } - public void ContainsTransientService() + public void TryContainsTransientService() { - IsRegistered(ServiceLifetime.Transient); + TryIsRegistered(ServiceLifetime.Transient); } - public void ContainsScopedService() + public void TryContainsScopedService() { - IsRegistered(ServiceLifetime.Scoped); + TryIsRegistered(ServiceLifetime.Scoped); + } + + private void TryIsRegistered(ServiceLifetime lifetime) + { + _serviceCollectionMock + .Verify(serviceCollection => serviceCollection.Add( + It.Is(serviceDescriptor => serviceDescriptor.TryIs(lifetime)))); } private void IsRegistered(ServiceLifetime lifetime) @@ -32,7 +44,6 @@ private void IsRegistered(ServiceLifetime lifetime) _serviceCollectionMock .Verify(serviceCollection => serviceCollection.Add( It.Is(serviceDescriptor => serviceDescriptor.Is(lifetime)))); - } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.Testing/ServiceDescriptionExtensions.cs b/src/Cropper.Blazor/Cropper.Blazor.Testing/ServiceDescriptionExtensions.cs index efffdb22..c74ee646 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.Testing/ServiceDescriptionExtensions.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.Testing/ServiceDescriptionExtensions.cs @@ -4,7 +4,7 @@ namespace Cropper.Blazor.Testing { public static class ServiceDescriptionExtensions { - public static bool Is( + public static bool TryIs( this ServiceDescriptor serviceDescriptor, ServiceLifetime lifetime) { @@ -12,5 +12,13 @@ public static bool Is( && serviceDescriptor.ImplementationType == typeof(TInstance) && serviceDescriptor.Lifetime == lifetime; } + + public static bool Is( + this ServiceDescriptor serviceDescriptor, + ServiceLifetime lifetime) + { + return serviceDescriptor.ServiceType == typeof(TService) + && serviceDescriptor.Lifetime == lifetime; + } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj index 5cbf0acc..7626347e 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj @@ -15,7 +15,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -33,7 +33,7 @@ - + diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/ServiceCollectionExtensions_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/ServiceCollectionExtensions_Should.cs index 7fe675c4..9cc17931 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/ServiceCollectionExtensions_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/ServiceCollectionExtensions_Should.cs @@ -1,4 +1,6 @@ -using Cropper.Blazor.Extensions; +using System.Collections.Generic; +using Cropper.Blazor.Extensions; +using Cropper.Blazor.ModuleOptions; using Cropper.Blazor.Services; using Cropper.Blazor.Testing; using Microsoft.Extensions.DependencyInjection; @@ -9,20 +11,33 @@ namespace Cropper.Blazor.UnitTests.Extensions { public class ServiceCollectionExtensions_Should { - private readonly ServiceCollectionMock _serviceCollectionMock; + private ServiceCollectionMock ServiceCollectionMock = null!; + private readonly Mock ServiceCollection = new(); - public ServiceCollectionExtensions_Should() + [Theory, MemberData(nameof(TestData_AddCropper_Service))] + public void Verify_Cropper_Service_Is_Registered(CropperJsInteropOptions? cropperJsInteropOptions) { - Mock serviceCollection = new(); - serviceCollection.Object.AddCropper(); - _serviceCollectionMock = new ServiceCollectionMock(serviceCollection); + // act + ServiceCollection.Object.AddCropper(cropperJsInteropOptions); + + // assert + ServiceCollectionMock = new(ServiceCollection); + ServiceCollectionMock.ContainsSingletonService(); + ServiceCollectionMock.TryContainsTransientService(); } - [Fact] - public void Verify_Cropper_Service_Is_Registered() + public static IEnumerable TestData_AddCropper_Service() { - // assert - _serviceCollectionMock.ContainsTransientService(); + yield return WrapArgs(null); + + yield return WrapArgs(new CropperJsInteropOptions()); + + static object[] WrapArgs( + CropperJsInteropOptions? cropperJsInteropOptions) + => new object[] + { + cropperJsInteropOptions + }; } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/UriExtensions_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/UriExtensions_Should.cs new file mode 100644 index 00000000..8ef640c9 --- /dev/null +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/UriExtensions_Should.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using Cropper.Blazor.Extensions; +using FluentAssertions; +using Xunit; + +namespace Cropper.Blazor.UnitTests.Extensions +{ + public class UriExtensions_Should + { + [Theory, MemberData(nameof(TestData_ToHostName))] + public void ToHostName(Uri uri, string expectedHostName) + { + // act + string hostName = uri.GetHostName(); + + // assert + hostName.Should().Be(expectedHostName); + } + + public static IEnumerable TestData_ToHostName() + { + yield return WrapArgs(new Uri("http://localhost"), "http:localhost"); + + yield return WrapArgs(new Uri("https://localhost"), "https:localhost"); + + yield return WrapArgs(new Uri("http://localhost:5000"), "http:localhost:5000"); + + yield return WrapArgs(new Uri("https://localhost:5001"), "https:localhost:5001"); + + yield return WrapArgs(new Uri("http://localhost/"), "http:localhost"); + + yield return WrapArgs(new Uri("https://localhost/"), "https:localhost"); + + yield return WrapArgs(new Uri("http://localhost:5000/"), "http:localhost:5000"); + + yield return WrapArgs(new Uri("https://localhost:5001/"), "https:localhost:5001"); + + yield return WrapArgs(new Uri("http://localhost/testpath"), "http://localhost"); + + yield return WrapArgs(new Uri("https://localhost/testpath"), "https://localhost"); + + yield return WrapArgs(new Uri("http://localhost:5000/testpath"), "http://localhost:5000"); + + yield return WrapArgs(new Uri("https://localhost:5001/testpath"), "https://localhost:5001"); + + yield return WrapArgs(new Uri("http://localhost/testpath"), "http://localhost"); + + yield return WrapArgs(new Uri("https://localhost/testpath"), "https://localhost"); + + yield return WrapArgs(new Uri("http://localhost:5000/testpath"), "http://localhost:5000"); + + yield return WrapArgs(new Uri("https://localhost:5001/testpath"), "https://localhost:5001"); + + yield return WrapArgs(new Uri("http://localhost/testpath?name=123"), "http://localhost"); + + yield return WrapArgs(new Uri("https://localhost/testpath?name=123"), "https://localhost"); + + yield return WrapArgs(new Uri("http://localhost:5000/testpath?name=123"), "http://localhost:5000"); + + yield return WrapArgs(new Uri("https://localhost:5001/testpath?name=123"), "https://localhost:5001"); + + static object[] WrapArgs( + Uri uri, + string expectedHostName) + => new object[] + { + uri, + expectedHostName, + }; + } + } +} diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/CropperJsInterop_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/CropperJsInterop_Should.cs index bf8f6d36..988968b0 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/CropperJsInterop_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/CropperJsInterop_Should.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; @@ -10,6 +9,7 @@ using Cropper.Blazor.Base; using Cropper.Blazor.Extensions; using Cropper.Blazor.Models; +using Cropper.Blazor.ModuleOptions; using Cropper.Blazor.Services; using FluentAssertions; using Microsoft.AspNetCore.Components; @@ -26,7 +26,8 @@ public class CropperJsInterop_Should : IDisposable private readonly Faker _faker; private readonly TestContext _testContext; private readonly ICropperJsInterop _cropperJsInterop; - private string DefaultPathToCropperModule => Path.Combine("http:localhost", CropperJsInterop.PathToCropperModule); + private const string PathToCropperModule = "_content/Cropper.Blazor/cropperJsInterop.min.js"; + private static string DefaultPathToCropperModule => Path.Combine("http:localhost", PathToCropperModule); public CropperJsInterop_Should() { @@ -37,26 +38,10 @@ public CropperJsInterop_Should() FakeNavigationManager fakeNavigationManager = _testContext.Services.GetRequiredService(); _cropperJsInterop = new Faker() - .CustomInstantiator(f => new CropperJsInterop(_testContext.JSInterop.JSRuntime, fakeNavigationManager)) + .CustomInstantiator(f => new CropperJsInterop(_testContext.JSInterop.JSRuntime, fakeNavigationManager, new CropperJsInteropOptions())) .Generate(); } - [Theory, MemberData(nameof(TestData_LoadCropperModule))] - public async Task Verify_LoadCropperModuleAsync( - string pathToCropperModule, - string expectedPathToCropperModule) - { - // arrange - FakeNavigationManager fakeNavigationManager = _testContext.Services.GetRequiredService(); - fakeNavigationManager.NavigateTo(pathToCropperModule); - - // assert - VerifyLoadCropperModule(expectedPathToCropperModule); - - // act - await _cropperJsInterop.LoadModuleAsync(); - } - [Fact] public async Task Verify_InitCropperAsync() { @@ -679,7 +664,7 @@ public async Task Verify_DisposeAsync() { // arrange FakeNavigationManager fakeNavigationManager = _testContext.Services.GetRequiredService(); - CropperJsInterop cropperJsInterop = new(_testContext.JSInterop.JSRuntime, fakeNavigationManager); + CropperJsInterop cropperJsInterop = new(_testContext.JSInterop.JSRuntime, fakeNavigationManager, new CropperJsInteropOptions()); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); @@ -689,43 +674,6 @@ public async Task Verify_DisposeAsync() await cropperJsInterop.DisposeAsync(); } - public static IEnumerable TestData_LoadCropperModule() - { - yield return WrapArgs("http://localhost", Path.Combine("http:localhost", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("http://localhost/", Path.Combine("http:localhost", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("http://localhost/testPath", Path.Combine("http:localhost", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("http://localhost/testPath/", Path.Combine("http:localhost", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://localhost", Path.Combine("https:localhost", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://localhost/", Path.Combine("https:localhost", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://localhost/testPath", Path.Combine("https:localhost", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://localhost/testPath/", Path.Combine("https:localhost", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://localhost:5001", Path.Combine("https:localhost:5001", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://localhost:5001/", Path.Combine("https:localhost:5001", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://localhost:5001/testPath", Path.Combine("https:localhost:5001", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://localhost:5001/testPath/", Path.Combine("https:localhost:5001", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("http://cropperblazor.github.io", Path.Combine("http:cropperblazor.github.io", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("http://cropperblazor.github.io/", Path.Combine("http:cropperblazor.github.io", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("http://cropperblazor.github.io/testPath", Path.Combine("http:cropperblazor.github.io", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("http://cropperblazor.github.io/testPath/", Path.Combine("http:cropperblazor.github.io", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://cropperblazor.github.io", Path.Combine("https:cropperblazor.github.io", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://cropperblazor.github.io/", Path.Combine("https:cropperblazor.github.io", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://cropperblazor.github.io/testPath", Path.Combine("https:cropperblazor.github.io", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://cropperblazor.github.io/testPath/", Path.Combine("https:cropperblazor.github.io", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://cropperblazor.github.io:5001", Path.Combine("https:cropperblazor.github.io:5001", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://cropperblazor.github.io:5001/", Path.Combine("https:cropperblazor.github.io:5001", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://cropperblazor.github.io:5001/testPath", Path.Combine("https:cropperblazor.github.io:5001", CropperJsInterop.PathToCropperModule)); - yield return WrapArgs("https://cropperblazor.github.io:5001/testPath/", Path.Combine("https:cropperblazor.github.io:5001", CropperJsInterop.PathToCropperModule)); - - static object[] WrapArgs( - string pathToCropperModule, - string expectedPathToCropperModule) - => new object[] - { - pathToCropperModule, - expectedPathToCropperModule - }; - } - private void VerifyLoadCropperModule( string pathToCropperModule) { diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/LoadCropperModule_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/LoadCropperModule_Should.cs new file mode 100644 index 00000000..b9321143 --- /dev/null +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/LoadCropperModule_Should.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Bogus; +using Bunit; +using Bunit.TestDoubles; +using Cropper.Blazor.ModuleOptions; +using Cropper.Blazor.Services; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Cropper.Blazor.UnitTests.Services +{ + public class LoadCropperModule_Should : IDisposable + { + private readonly TestContext _testContext; + private ICropperJsInterop _cropperJsInterop; + private const string PathToCropperModule = "_content/Cropper.Blazor/cropperJsInterop.min.js"; + private static string DefaultPathToCropperModule => Path.Combine("http:localhost", PathToCropperModule); + + public LoadCropperModule_Should() + { + _testContext = new Faker() + .Generate(); + } + + [Theory, MemberData(nameof(TestData_LoadCropperModule))] + public async Task Verify_LoadCropperModuleAsync( + string pathToCropperModule, + CropperJsInteropOptions cropperJsInteropOptions, + string expectedPathToCropperModule) + { + // arrange + FakeNavigationManager fakeNavigationManager = _testContext.Services.GetRequiredService(); + + _cropperJsInterop = new Faker() + .CustomInstantiator(f => new CropperJsInterop(_testContext.JSInterop.JSRuntime, fakeNavigationManager, cropperJsInteropOptions)) + .Generate(); + + fakeNavigationManager.NavigateTo(pathToCropperModule); + + // assert + VerifyLoadCropperModule(expectedPathToCropperModule); + + // act + await _cropperJsInterop.LoadModuleAsync(); + } + + public static IEnumerable TestData_LoadCropperModule() + { + CropperJsInteropOptions cropperJsInteropOptions = new(); + + yield return WrapArgs("http://localhost", cropperJsInteropOptions, Path.Combine("http:localhost", PathToCropperModule)); + yield return WrapArgs("http://localhost/", cropperJsInteropOptions, Path.Combine("http:localhost", PathToCropperModule)); + yield return WrapArgs("http://localhost/testPath", cropperJsInteropOptions, Path.Combine("http:localhost", PathToCropperModule)); + yield return WrapArgs("http://localhost/testPath/", cropperJsInteropOptions, Path.Combine("http:localhost", PathToCropperModule)); + yield return WrapArgs("https://localhost", cropperJsInteropOptions, Path.Combine("https:localhost", PathToCropperModule)); + yield return WrapArgs("https://localhost/", cropperJsInteropOptions, Path.Combine("https:localhost", PathToCropperModule)); + yield return WrapArgs("https://localhost/testPath", cropperJsInteropOptions, Path.Combine("https:localhost", PathToCropperModule)); + yield return WrapArgs("https://localhost/testPath/", cropperJsInteropOptions, Path.Combine("https:localhost", PathToCropperModule)); + yield return WrapArgs("https://localhost:5001", cropperJsInteropOptions, Path.Combine("https:localhost:5001", PathToCropperModule)); + yield return WrapArgs("https://localhost:5001/", cropperJsInteropOptions, Path.Combine("https:localhost:5001", PathToCropperModule)); + yield return WrapArgs("https://localhost:5001/testPath", cropperJsInteropOptions, Path.Combine("https:localhost:5001", PathToCropperModule)); + yield return WrapArgs("https://localhost:5001/testPath/", cropperJsInteropOptions, Path.Combine("https:localhost:5001", PathToCropperModule)); + yield return WrapArgs("http://cropperblazor.github.io", cropperJsInteropOptions, Path.Combine("http:cropperblazor.github.io", PathToCropperModule)); + yield return WrapArgs("http://cropperblazor.github.io/", cropperJsInteropOptions, Path.Combine("http:cropperblazor.github.io", PathToCropperModule)); + yield return WrapArgs("http://cropperblazor.github.io/testPath", cropperJsInteropOptions, Path.Combine("http:cropperblazor.github.io", PathToCropperModule)); + yield return WrapArgs("http://cropperblazor.github.io/testPath/", cropperJsInteropOptions, Path.Combine("http:cropperblazor.github.io", PathToCropperModule)); + yield return WrapArgs("https://cropperblazor.github.io", cropperJsInteropOptions, Path.Combine("https:cropperblazor.github.io", PathToCropperModule)); + yield return WrapArgs("https://cropperblazor.github.io/", cropperJsInteropOptions, Path.Combine("https:cropperblazor.github.io", PathToCropperModule)); + yield return WrapArgs("https://cropperblazor.github.io/testPath", cropperJsInteropOptions, Path.Combine("https:cropperblazor.github.io", PathToCropperModule)); + yield return WrapArgs("https://cropperblazor.github.io/testPath/", cropperJsInteropOptions, Path.Combine("https:cropperblazor.github.io", PathToCropperModule)); + yield return WrapArgs("https://cropperblazor.github.io:5001", cropperJsInteropOptions, Path.Combine("https:cropperblazor.github.io:5001", PathToCropperModule)); + yield return WrapArgs("https://cropperblazor.github.io:5001/", cropperJsInteropOptions, Path.Combine("https:cropperblazor.github.io:5001", PathToCropperModule)); + yield return WrapArgs("https://cropperblazor.github.io:5001/testPath", cropperJsInteropOptions, Path.Combine("https:cropperblazor.github.io:5001", PathToCropperModule)); + yield return WrapArgs("https://cropperblazor.github.io:5001/testPath/", cropperJsInteropOptions, Path.Combine("https:cropperblazor.github.io:5001", PathToCropperModule)); + + cropperJsInteropOptions = new(); + cropperJsInteropOptions.IsActiveGlobalPath = true; + cropperJsInteropOptions.GlobalPathToCropperModule = "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"; + + yield return WrapArgs("http://localhost", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("http://localhost/", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("http://localhost/testPath", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("http://localhost/testPath/", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://localhost", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://localhost/", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://localhost/testPath", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://localhost/testPath/", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://localhost:5001", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://localhost:5001/", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://localhost:5001/testPath", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://localhost:5001/testPath/", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("http://cropperblazor.github.io", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("http://cropperblazor.github.io/", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("http://cropperblazor.github.io/testPath", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("http://cropperblazor.github.io/testPath/", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://cropperblazor.github.io", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://cropperblazor.github.io/", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://cropperblazor.github.io/testPath", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://cropperblazor.github.io/testPath/", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://cropperblazor.github.io:5001", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://cropperblazor.github.io:5001/", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://cropperblazor.github.io:5001/testPath", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + yield return WrapArgs("https://cropperblazor.github.io:5001/testPath/", cropperJsInteropOptions, "https://cropperblazor.github.io:5001/testPath/_content/Cropper.Blazor/cropperJsInterop.min.js"); + + static object[] WrapArgs( + string pathToCropperModule, + CropperJsInteropOptions cropperJsInteropOptions, + string expectedPathToCropperModule) + => new object[] + { + pathToCropperModule, + cropperJsInteropOptions, + expectedPathToCropperModule + }; + } + + private void VerifyLoadCropperModule( + string pathToCropperModule) + { + _testContext.JSInterop + .SetupModule(pathToCropperModule); + } + + public void Dispose() + { + _testContext.Dispose(); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj index 5e652df5..51fe4a07 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj @@ -105,7 +105,7 @@ - + diff --git a/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs b/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs index c784ac77..e8db01df 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ -using Cropper.Blazor.Services; +using Cropper.Blazor.ModuleOptions; +using Cropper.Blazor.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -13,10 +14,15 @@ public static class ServiceCollectionExtensions /// Adds a see as a Transient instance. /// /// Continues the chain. + /// Continues the chain. + /// When option is default (null) then uses internal path with default cropper JavaScript interop options. /// Continues the chain. - public static IServiceCollection AddCropper(this IServiceCollection services) + public static IServiceCollection AddCropper(this IServiceCollection services, CropperJsInteropOptions? cropperJsInteropOptions = null) { + services.AddSingleton(services => cropperJsInteropOptions ?? new CropperJsInteropOptions()); + services.TryAddTransient(); + return services; } } diff --git a/src/Cropper.Blazor/Cropper.Blazor/Extensions/UriExtensions.cs b/src/Cropper.Blazor/Cropper.Blazor/Extensions/UriExtensions.cs new file mode 100644 index 00000000..5001f5e3 --- /dev/null +++ b/src/Cropper.Blazor/Cropper.Blazor/Extensions/UriExtensions.cs @@ -0,0 +1,17 @@ +using System; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Cropper.Blazor.UnitTests")] + +namespace Cropper.Blazor.Extensions +{ + static internal class UriExtensions + { + static internal string GetHostName(this Uri baseUri) + { + string redundantPath = baseUri.PathAndQuery; + + return baseUri.ToString().Replace(redundantPath, string.Empty); + } + } +} diff --git a/src/Cropper.Blazor/Cropper.Blazor/ModuleOptions/CropperJsInteropOptions.cs b/src/Cropper.Blazor/Cropper.Blazor/ModuleOptions/CropperJsInteropOptions.cs new file mode 100644 index 00000000..cd5abe1f --- /dev/null +++ b/src/Cropper.Blazor/Cropper.Blazor/ModuleOptions/CropperJsInteropOptions.cs @@ -0,0 +1,23 @@ +namespace Cropper.Blazor.ModuleOptions +{ + /// + /// Contains cropper JavaScript interop options. + /// + public class CropperJsInteropOptions : ICropperJsInteropOptions + { + /// + /// Represents an internal (default) path to cropper js interop module. + /// + public string DefaultInternalPathToCropperModule { get; set; } = "_content/Cropper.Blazor/cropperJsInterop.min.js"; + + /// + /// Represents state regarding using global path to cropper js interop module instead of internal (default). + /// + public bool IsActiveGlobalPath { get; set; } = false; + + /// + /// Represents a global (conclusive) path to cropper js interop module. + /// + public string GlobalPathToCropperModule { get; set; } = string.Empty; + } +} diff --git a/src/Cropper.Blazor/Cropper.Blazor/ModuleOptions/ICropperJsInteropOptions.cs b/src/Cropper.Blazor/Cropper.Blazor/ModuleOptions/ICropperJsInteropOptions.cs new file mode 100644 index 00000000..e3672efa --- /dev/null +++ b/src/Cropper.Blazor/Cropper.Blazor/ModuleOptions/ICropperJsInteropOptions.cs @@ -0,0 +1,23 @@ +namespace Cropper.Blazor.ModuleOptions +{ + /// + /// Contains cropper JavaScript interop options. + /// + public interface ICropperJsInteropOptions + { + /// + /// Represents an internal (default) path to cropper js interop module. + /// + public string DefaultInternalPathToCropperModule { get; set; } + + /// + /// Represents state regarding using global path to cropper js interop module instead of internal (default). + /// + public bool IsActiveGlobalPath { get; set; } + + /// + /// Represents a global (conclusive) path to cropper js interop module. + /// + public string GlobalPathToCropperModule { get; set; } + } +} diff --git a/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs b/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs index 51feb97d..02f0a7d7 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs @@ -6,6 +6,7 @@ using Cropper.Blazor.Base; using Cropper.Blazor.Extensions; using Cropper.Blazor.Models; +using Cropper.Blazor.ModuleOptions; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Forms; using Microsoft.JSInterop; @@ -18,23 +19,24 @@ namespace Cropper.Blazor.Services public class CropperJsInterop : ICropperJsInterop, IAsyncDisposable { private readonly NavigationManager _navigationManager; + private readonly ICropperJsInteropOptions _cropperJsInteropOptions; private readonly IJSRuntime _jsRuntime; private IJSObjectReference? Module = null; - /// - /// Path to cropper js interop module. - /// - public const string PathToCropperModule = "_content/Cropper.Blazor/cropperJsInterop.min.js"; - /// /// Implementation of the constructor. /// /// The . /// The . - public CropperJsInterop(IJSRuntime jsRuntime, NavigationManager navigationManager) + /// The . + public CropperJsInterop( + IJSRuntime jsRuntime, + NavigationManager navigationManager, + ICropperJsInteropOptions cropperJsInteropOptions) { _jsRuntime = jsRuntime; _navigationManager = navigationManager; + _cropperJsInteropOptions = cropperJsInteropOptions; } /// @@ -46,15 +48,27 @@ public CropperJsInterop(IJSRuntime jsRuntime, NavigationManager navigationManage /// A representing any asynchronous operation. public async Task LoadModuleAsync(CancellationToken cancellationToken = default) { - Uri baseUri = new Uri(_navigationManager.BaseUri); - string pathAndQuery = baseUri.PathAndQuery; - string hostName = baseUri.ToString().Replace(pathAndQuery, string.Empty); - string globalPathToCropperModule = Path.Combine(hostName, PathToCropperModule); + string globalPathToCropperModule = GetGlobalPathToCropperModule(); Module = await _jsRuntime.InvokeAsync( "import", cancellationToken, globalPathToCropperModule); } + private string GetGlobalPathToCropperModule() + { + if (_cropperJsInteropOptions.IsActiveGlobalPath) + { + return _cropperJsInteropOptions.GlobalPathToCropperModule; + } + else + { + Uri baseUri = new(_navigationManager.BaseUri); + string hostName = baseUri.GetHostName(); + + return Path.Combine(hostName, _cropperJsInteropOptions.DefaultInternalPathToCropperModule); + } + } + /// /// Initializes cropper. /// diff --git a/src/Cropper.Blazor/Server/Cropper.Blazor.Server.csproj b/src/Cropper.Blazor/Server/Cropper.Blazor.Server.csproj index c982aec6..bc31deaa 100644 --- a/src/Cropper.Blazor/Server/Cropper.Blazor.Server.csproj +++ b/src/Cropper.Blazor/Server/Cropper.Blazor.Server.csproj @@ -8,7 +8,7 @@ - + From 46edcc60eed026d28e5388d2b4cc0e09a612850a Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Fri, 23 Jun 2023 00:50:31 +0300 Subject: [PATCH 015/196] consolidate nuget versions --- .../Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj | 2 +- src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj b/examples/Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj index 810dea03..a88302a5 100644 --- a/examples/Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj +++ b/examples/Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj @@ -50,7 +50,7 @@ - + diff --git a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj index 51fe4a07..5e652df5 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj @@ -105,7 +105,7 @@ - + From 9367a271042513612d1e3cd385a3bdf121138300 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Fri, 23 Jun 2023 17:33:00 +0300 Subject: [PATCH 016/196] Update README.md (#156) ## Target #### Open Questions ## Checklist - [x] Documentation updated - [ ] Tests cover new or modified code - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 684c4785..f280a439 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,23 @@ using Cropper.Blazor.Extensions; builder.Services.AddCropper(); ``` +In addition, you can change the path to the CropperJSInterop.min.js module if for some reason it is located outside the server root folder as follows: +- Override internal path to CropperJSInterop.min.js module: +```c# +builder.Services.AddCropper(new CropperJsInteropOptions() +{ + DefaultInternalPathToCropperModule = "/_content/Cropper.Blazor/cropperJsInterop.min.js" +}) +``` +- Override full global path to CropperJSInterop.min.js module: +```c# +builder.Services.AddCropper(new CropperJsInteropOptions() +{ + IsActiveGlobalPath = true, + GlobalPathToCropperModule = "/_content/Cropper.Blazor/cropperJsInterop.min.js" +}) +``` + Also for server-side (Blazor Server or MVC with Blazor Server) you need add configuration SignalR, increase MaximumReceiveMessageSize of a single incoming hub message (default is 32KB) and map SignalR to your path. [For example](https://github.com/CropperBlazor/Cropper.Blazor/blob/dev/examples/Cropper.Blazor.Server.Net7/Program.cs): ```c# builder.Services.AddServerSideBlazor() From e7fdc03e56b344324691a7c58b6f2d69a07d0674 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Fri, 23 Jun 2023 18:38:30 +0300 Subject: [PATCH 017/196] Fix double initialization cropper (#157) ## Target #### Open Questions ## Checklist - [ ] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [x] Version bumped ## Visuals --- LICENSE | 4 +- .../Client/Pages/CropperDemo.razor | 9 ++- .../Client/Pages/CropperDemo.razor.cs | 34 +++++++++- .../Components/CropperComponent_Should.cs | 68 +++++++++++++++++++ .../Components/CropperComponent.razor.cs | 14 +++- .../Cropper.Blazor/Cropper.Blazor.csproj | 4 +- 6 files changed, 123 insertions(+), 10 deletions(-) diff --git a/LICENSE b/LICENSE index 65d30e85..8fb2fe77 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Cropper Blazor +Copyright (c) 2022-2023 Cropper Blazor Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index 2f3bd147..8e990ebc 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -25,7 +25,8 @@ ErrorLoadImageSrc="@_errorLoadImageSrc" IsErrorLoadImage="@IsErrorLoadImage" OnErrorLoadImageEvent="OnErrorLoadImageEvent" - Options="Options" /> + Options="Options" + IsAvaibleInitCropper="IsAvaibleInitCropper" /> @@ -127,9 +128,13 @@ - + + diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 5cd905e8..51280a39 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -36,6 +36,7 @@ public partial class CropperDemo : IDisposable private string Src = "https://fengyuanchen.github.io/cropperjs/v2/picture.jpg"; private bool IsErrorLoadImage { get; set; } = false; + private bool IsAvaibleInitCropper { get; set; } = true; private readonly string _errorLoadImageSrc = "not-found-image.jpg"; private Breakpoint Start; private Guid SubscriptionId; @@ -324,19 +325,48 @@ public async void GetCroppedCanvasDataURL(GetCroppedCanvasOptions getCroppedCanv _dialogService.Show("CroppedCanvasDialog", parameters, options); } - public async Task InputFileChange(InputFileChangeEventArgs inputFileChangeEventArgs) + public async Task InputFileChangeAsync(InputFileChangeEventArgs inputFileChangeEventArgs) { var imageFile = inputFileChangeEventArgs.File; + if (imageFile != null) { - var oldSrc = Src; + string oldSrc = Src; + Src = await CropperComponent!.GetImageUsingStreamingAsync(imageFile, imageFile.Size); + + IsAvaibleInitCropper = true; IsErrorLoadImage = false; + CropperComponent?.Destroy(); CropperComponent?.RevokeObjectUrlAsync(oldSrc); } } + public async Task ReplaceImageAsync(InputFileChangeEventArgs inputFileChangeEventArgs) + { + var imageFile = inputFileChangeEventArgs.File; + + if (imageFile != null) + { + string oldSrc = Src; + string src = await CropperComponent!.GetImageUsingStreamingAsync(imageFile, imageFile.Size); + + if (IsErrorLoadImage) + { + IsAvaibleInitCropper = true; + IsErrorLoadImage = false; + } + else + { + IsAvaibleInitCropper = false; + } + + CropperComponent?.ReplaceAsync(src); + CropperComponent?.RevokeObjectUrlAsync(oldSrc); + } + } + protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs index 9dcf36de..0854704c 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs @@ -188,6 +188,9 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() ComponentParameter isErrorLoadImageParameter = ComponentParameter.CreateParameter( nameof(CropperComponent.IsErrorLoadImage), false); + ComponentParameter isAvaibleInitCropperParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.IsAvaibleInitCropper), + true); ComponentParameter onLoadImageParameter = ComponentParameter.CreateParameter( nameof(CropperComponent.OnLoadImageEvent), onLoadImageHandler); @@ -255,6 +258,7 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() loadingParameter, errorLoadImageSrcParameter, isErrorLoadImageParameter, + isAvaibleInitCropperParameter, srcParameter, imageClassParameter, onLoadImageParameter, @@ -461,6 +465,70 @@ public void Should_Render_CropperComponent_With_ErrorLoadImage_Parameter() expectedElement.GetAttribute("src").Should().Be(errorLoadImageSrcAttributeValue); expectedElement.GetAttribute("Attribute_TEST").Should().Be("TEST_VALUE"); expectedElement.GetAttribute("blazor:elementreference").Should().BeNullOrEmpty(); + + _mockCropperJsInterop.Verify(c => c.InitCropperAsync( + It.IsAny(), + It.IsAny(), + It.IsAny>(), + It.IsAny()), Times.Never()); + } + + [Fact] + public void Should_Not_Render_CropperComponent_With_IsNotAvaibleInitCropper_Parameter() + { + // arrange + string errorLoadImageClass = "cropper-error-load"; + string lazyAttributeValue = "lazy"; + Dictionary inputAttributes = new() + { + { "loading", lazyAttributeValue }, + { "Attribute_TEST", "TEST_VALUE" }, + { "src", "new_src" } + }; + string errorLoadImageSrcAttributeValue = "https://cropper/not-found-image.jpg"; + + ComponentParameter errorLoadImageClassParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.ErrorLoadImageClass), + errorLoadImageClass); + ComponentParameter loadingParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.InputAttributes), + inputAttributes); + ComponentParameter errorLoadImageSrcParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.ErrorLoadImageSrc), + errorLoadImageSrcAttributeValue); + ComponentParameter isErrorLoadImage = ComponentParameter.CreateParameter( + nameof(CropperComponent.IsErrorLoadImage), + true); + ComponentParameter isAvaibleInitCropperParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.IsAvaibleInitCropper), + false); + + // act + IRenderedComponent cropperComponent = _testContext + .RenderComponent( + errorLoadImageClassParameter, + loadingParameter, + errorLoadImageSrcParameter, + isErrorLoadImage, + isAvaibleInitCropperParameter); + + // assert + IElement expectedElement = cropperComponent.Find($"img.{errorLoadImageClass}"); + ElementReference elementReference = (ElementReference)cropperComponent.Instance + .GetInstanceField("ImageReference"); + + elementReference.Id.Should().BeNullOrEmpty(); + expectedElement.ClassName.Should().Be(errorLoadImageClass); + expectedElement.GetAttribute("loading").Should().Be(lazyAttributeValue); + expectedElement.GetAttribute("src").Should().Be(errorLoadImageSrcAttributeValue); + expectedElement.GetAttribute("Attribute_TEST").Should().Be("TEST_VALUE"); + expectedElement.GetAttribute("blazor:elementreference").Should().BeNullOrEmpty(); + + _mockCropperJsInterop.Verify(c => c.InitCropperAsync( + It.IsAny(), + It.IsAny(), + It.IsAny>(), + It.IsAny()), Times.Never()); } [Theory] diff --git a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs index 2d0c19ab..50a66659 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs @@ -59,6 +59,13 @@ public partial class CropperComponent : ICropperComponentBase, IAsyncDisposable [Parameter] public bool IsErrorLoadImage { get; set; } + /// + /// Responsible for allowing the initialization of the cropper after a successful image download, the default is always allowed (true). + /// In addition, it should be used to disable re-initialization (replace image) of cropper after successful image load when set to false. + /// + [Parameter] + public bool IsAvaibleInitCropper { get; set; } = true; + /// /// User class names, separated by space. /// @@ -154,7 +161,10 @@ protected override async Task OnAfterRenderAsync(bool firstRender) /// private void OnLoadImage(ProgressEventArgs progressEventArgs) { - InitCropper(); + if (IsAvaibleInitCropper) + { + InitCropper(); + } } /// @@ -490,7 +500,7 @@ public async ValueTask GetContainerDataAsync(CancellationToken ca /// A representing any asynchronous operation. public async ValueTask ReplaceAsync( string url, - bool hasSameSize, + bool hasSameSize = true, CancellationToken cancellationToken = default) { await CropperJsIntertop!.ReplaceAsync(url, hasSameSize, cancellationToken); diff --git a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj index 5e652df5..2bbe6ea5 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj @@ -14,12 +14,12 @@ - 1.2.1 + 1.2.2 LICENSE NuGet.png Cropper.Blazor Max56132, ColdForeign - Copyright 2022 Cropper.Blazor + Copyright 2022-present Cropper.Blazor Cropper.Blazor is a component element that wraps around Cropper.js Blazor, Cropper.Blazor, Cropper.js, Blazor Components, Blazor Library, Blazor Cropper, Cropper, Image, Crop, Resize, image-cropper, crop-image, csharp, blazor-cropper https://CropperBlazor.github.io From cb950488365906af8b0a397827df11ccc034c5ca Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Fri, 23 Jun 2023 20:42:14 +0300 Subject: [PATCH 018/196] Feature/fix styles (#158) ## Target #### Open Questions ## Checklist - [x] Documentation updated - [ ] Tests cover new or modified code - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- LICENSE | 2 +- src/Cropper.Blazor/Client/Pages/CropperDemo.razor | 2 +- .../InstallServicesNET6ExampleCode.html | 14 ++++++++++++++ .../Client/Shared/CroppedCanvasDialog.razor | 2 +- .../Client/Styles/Cropper.Blazor.Client.scss | 4 ++++ 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 8fb2fe77..580950fd 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022-2023 Cropper Blazor +Copyright (c) 2022-present Cropper Blazor Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index 8e990ebc..868706a2 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -182,7 +182,7 @@ @*//---Aspect Ratio | View Mode | Get Cropped Canvas---//*@ - + diff --git a/src/Cropper.Blazor/Client/Pages/ManualMarkdown/InstallServicesNET6ExampleCode.html b/src/Cropper.Blazor/Client/Pages/ManualMarkdown/InstallServicesNET6ExampleCode.html index 3be31c1f..a1b72368 100644 --- a/src/Cropper.Blazor/Client/Pages/ManualMarkdown/InstallServicesNET6ExampleCode.html +++ b/src/Cropper.Blazor/Client/Pages/ManualMarkdown/InstallServicesNET6ExampleCode.html @@ -5,6 +5,20 @@ builder.Services.AddCropper(); +// You can change the path to the CropperJSInterop.min.js module if for some reason it is located outside the server root folder as follows: + +• Override internal path to CropperJSInterop.min.js module: +builder.Services.AddCropper(new CropperJsInteropOptions() +{ + DefaultInternalPathToCropperModule = "{YourPath}/_content/Cropper.Blazor/cropperJsInterop.min.js" +}); + +• Override full global path to CropperJSInterop.min.js module: +builder.Services.AddCropper(new CropperJsInteropOptions() +{ + IsActiveGlobalPath = true, + GlobalPathToCropperModule = "{StartUrlWithPath}/_content/Cropper.Blazor/cropperJsInterop.min.js" +}); \ No newline at end of file diff --git a/src/Cropper.Blazor/Client/Shared/CroppedCanvasDialog.razor b/src/Cropper.Blazor/Client/Shared/CroppedCanvasDialog.razor index 9759bb92..179a863c 100644 --- a/src/Cropper.Blazor/Client/Shared/CroppedCanvasDialog.razor +++ b/src/Cropper.Blazor/Client/Shared/CroppedCanvasDialog.razor @@ -1,5 +1,5 @@ @using MudBlazor - + diff --git a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss index 5599cf14..09abc5ab 100644 --- a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss +++ b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss @@ -113,3 +113,7 @@ html, body { .cropper-container { max-height: inherit; } + +.cropped-canvas-dialog .mud-dialog-title { + padding-bottom: 0; +} From af7286a4996f3bca8baa6a3a80713afe2e0d3500 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Wed, 28 Jun 2023 14:45:40 +0300 Subject: [PATCH 019/196] add cropper view figures for demo (#161) ## Target #### Open Questions ## Checklist - [ ] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .github/dependabot.yml | 2 +- README.md | 8 +- .../Client/Enums/CropperFace.cs | 11 ++ .../Client/Pages/CropperDemo.razor | 118 +++++++++++++++++- .../Client/Pages/CropperDemo.razor.cs | 86 +++++++++++-- .../Client/Styles/Cropper.Blazor.Client.scss | 20 +++ src/Cropper.Blazor/Client/wwwroot/helper.js | 48 ++++++- 7 files changed, 274 insertions(+), 19 deletions(-) create mode 100644 src/Cropper.Blazor/Client/Enums/CropperFace.cs diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 25835c2d..0089655d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,4 +4,4 @@ updates: directory: "/src/Cropper.Blazor" target-branch: "dev" # Location of package manifests schedule: - interval: "weekly" + interval: "monthly" diff --git a/README.md b/README.md index f280a439..bf6c64c4 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,11 @@ - [CropperBlazor.github.io/demo](https://CropperBlazor.github.io/demo) ## Prerequisites -- Supported .NET versions - - [.NET 7.0](https://dotnet.microsoft.com/download/dotnet/7.0) for versions greater than v1.1.0 - - [.NET 6.0](https://dotnet.microsoft.com/download/dotnet/6.0) for v1.0.x +- Supported .NET 7.0, .NET 6.0 versions for these web platforms: + - Blazor WebAssembly + - Blazor Server + - Blazor Server Hybrid with MVC + - MAUI Blazor Hybrid ## Installation diff --git a/src/Cropper.Blazor/Client/Enums/CropperFace.cs b/src/Cropper.Blazor/Client/Enums/CropperFace.cs new file mode 100644 index 00000000..f3a700bd --- /dev/null +++ b/src/Cropper.Blazor/Client/Enums/CropperFace.cs @@ -0,0 +1,11 @@ +namespace Cropper.Blazor.Client.Enums +{ + public enum CropperFace + { + Default, + Close, + Pentagon, + Circle, + Arrow + } +} diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index 868706a2..098c880d 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -9,7 +9,7 @@ @*//---Cropper Component---//*@ -
+
- + - Get Cropped Canvas + Get Cropped Canvas by URL + + + + + Get Cropped Canvas by element - + 320×180 - - + + 640×360 @@ -243,6 +249,56 @@ + + + + + + + + + + + + + + + + + + + GET + + + @@ -303,6 +359,56 @@ + + + + + + + + + + + + + + + + + + + GET + + + diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 51280a39..6f51ca31 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -1,6 +1,7 @@ using System.Reflection; using System.Text.Json; using Cropper.Blazor.Client.Components; +using Cropper.Blazor.Client.Enums; using Cropper.Blazor.Components; using Cropper.Blazor.Events; using Cropper.Blazor.Events.CropEndEvent; @@ -29,6 +30,7 @@ public partial class CropperDemo : IDisposable private CropperDataPreview? CropperDataPreview = null!; private GetSetCropperData? GetSetCropperData = null!; private Options Options = null!; + private CropperFace CropperFace = CropperFace.Default; private decimal? ScaleXValue; private decimal? ScaleYValue; private decimal AspectRatio = 1.7777777777777777m; @@ -313,16 +315,40 @@ private void Reset() public async void GetCroppedCanvasDataURL(GetCroppedCanvasOptions getCroppedCanvasOptions) { - //CroppedCanvas croppedCanvas = await cropperComponent!.GetCroppedCanvasAsync(getCroppedCanvasOptions); - //string croppedCanvasDataURL = await croppedCanvas!.JSRuntimeObjectRef.InvokeAsync("toDataURL"); - string croppedCanvasDataURL = await CropperComponent!.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions); - DialogParameters parameters = new() + + OpenCroppedCanvasDialog(croppedCanvasDataURL); + } + + public async void GetCroppedCanvasData(GetCroppedCanvasOptions getCroppedCanvasOptions) + { + CroppedCanvas croppedCanvas = await CropperComponent!.GetCroppedCanvasAsync(getCroppedCanvasOptions); + string croppedCanvasDataURL = await croppedCanvas!.JSRuntimeObjectRef.InvokeAsync("toDataURL"); + + OpenCroppedCanvasDialog(croppedCanvasDataURL); + } + + public async void GetCroppedCanvasDataByPolygonFilter(GetCroppedCanvasOptions getCroppedCanvasOptions) + { + CroppedCanvas croppedCanvas = await CropperComponent!.GetCroppedCanvasAsync(getCroppedCanvasOptions); + string croppedCanvasDataURL; + + if (CropperFace == CropperFace.Default) { - { "Src", croppedCanvasDataURL } - }; - var options = new DialogOptions() { CloseButton = true, MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true }; - _dialogService.Show("CroppedCanvasDialog", parameters, options); + croppedCanvasDataURL = await croppedCanvas!.JSRuntimeObjectRef.InvokeAsync("toDataURL"); + } + else if (CropperFace == CropperFace.Circle) + { + croppedCanvasDataURL = await JSRuntime!.InvokeAsync("window.addClipPathEllipse", croppedCanvas!.JSRuntimeObjectRef); + } + else + { + IEnumerable croppedPathToCanvasCropper = GetCroppedPathToCanvasCropper(); + + croppedCanvasDataURL = await JSRuntime!.InvokeAsync("window.addClipPathPolygon", croppedCanvas!.JSRuntimeObjectRef, croppedPathToCanvasCropper); + } + + OpenCroppedCanvasDialog(croppedCanvasDataURL); } public async Task InputFileChangeAsync(InputFileChangeEventArgs inputFileChangeEventArgs) @@ -443,6 +469,50 @@ public void Dispose() GC.SuppressFinalize(this); } + public void SetCropperFace(CropperFace cropperFace) + { + CropperFace = cropperFace; + } + + public string GetClassNameCropper() => + "img-container" + CropperFace switch + { + CropperFace.Default => string.Empty, + CropperFace.Close => " cropper-face-close", + CropperFace.Pentagon => " cropper-face-pentagon", + CropperFace.Circle => " cropper-face-circle", + CropperFace.Arrow => " cropper-face-arrow", + _ => string.Empty, + }; + + public IEnumerable GetCroppedPathToCanvasCropper() => + CropperFace switch + { + // That enumerable is equivalent css like that (the same for another paths) - clip-path: polygon(20% 0%, 0% 20%, 30% 50%, 0% 80%, 20% 100%, 50% 70%, 80% 100%, 100% 80%, 70% 50%, 100% 20%, 80% 0%, 50% 30%); + CropperFace.Close => new List { 20, 0, 0, 20, 30, 50, 0, 80, 20, 100, 50, 70, 80, 100, 100, 80, 70, 50, 100, 20, 80, 0, 50, 30 }, + CropperFace.Pentagon => new List { 50, 0, 100, 38, 82, 100, 18, 100, 0, 38 }, + CropperFace.Arrow => new List { 40, 0, 40, 40, 100, 40, 100, 60, 40, 60, 40, 100, 0, 50 }, + _ => throw new InvalidOperationException() + }; + + private void OpenCroppedCanvasDialog(string croppedCanvasDataURL) + { + DialogParameters parameters = new() + { + { "Src", croppedCanvasDataURL } + }; + + DialogOptions options = new DialogOptions + { + CloseButton = true, + MaxWidth = MaxWidth.Medium, + FullWidth = true, + DisableBackdropClick = true + }; + + _dialogService.Show("CroppedCanvasDialog", parameters, options); + } + protected virtual void Dispose(bool disposing) { if (disposing) diff --git a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss index 09abc5ab..08abaa0b 100644 --- a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss +++ b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss @@ -117,3 +117,23 @@ html, body { .cropped-canvas-dialog .mud-dialog-title { padding-bottom: 0; } + +.cropper-face { + opacity: 25%; +} + +.img-container.cropper-face-close .cropper-container .cropper-crop-box .cropper-face { + clip-path: polygon(20% 0%, 0% 20%, 30% 50%, 0% 80%, 20% 100%, 50% 70%, 80% 100%, 100% 80%, 70% 50%, 100% 20%, 80% 0%, 50% 30%); +} + +.img-container.cropper-face-arrow .cropper-container .cropper-crop-box .cropper-face { + clip-path: polygon(40% 0%, 40% 40%, 100% 40%, 100% 60%, 40% 60%, 40% 100%, 0% 50%); +} + +.img-container.cropper-face-circle .cropper-container .cropper-crop-box .cropper-face { + border-radius: 50%; +} + +.img-container.cropper-face-pentagon .cropper-container .cropper-crop-box .cropper-face { + clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); +} diff --git a/src/Cropper.Blazor/Client/wwwroot/helper.js b/src/Cropper.Blazor/Client/wwwroot/helper.js index b4af1b2a..944931e6 100644 --- a/src/Cropper.Blazor/Client/wwwroot/helper.js +++ b/src/Cropper.Blazor/Client/wwwroot/helper.js @@ -4,4 +4,50 @@ anchorElement.download = options.fileName ?? ''; anchorElement.click(); anchorElement.remove(); -}; \ No newline at end of file +}; + +window.addClipPathPolygon = (sourceCanvas, path) => { + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + const width = sourceCanvas.width, + height = sourceCanvas.height; + + canvas.width = width; + canvas.height = height; + context.imageSmoothingEnabled = true; + + context.beginPath(); + context.moveTo(path[0] * width / 100, path[1] * height / 100); + context.fillStyle = "rgba(255, 255, 255, 0)"; + + for (let i = 2; i < path.length; i += 2) { + context.lineTo(path[i] * width / 100, path[i + 1] * height / 100); + } + + context.closePath(); + context.clip(); + context.fill(); + context.globalCompositeOperation = 'lighter'; + context.drawImage(sourceCanvas, 0, 0, width, height); + + return canvas.toDataURL(); +} + +window.addClipPathEllipse = (sourceCanvas) => { + const createdCanvas = document.createElement('canvas'); + const contextCanvas = createdCanvas.getContext('2d'); + const widthCanvas = sourceCanvas.width, + heightCanvas = sourceCanvas.height; + + createdCanvas.width = widthCanvas; + createdCanvas.height = heightCanvas; + contextCanvas.imageSmoothingEnabled = true; + + contextCanvas.drawImage(sourceCanvas, 0, 0, widthCanvas, heightCanvas); + contextCanvas.globalCompositeOperation = 'destination-in'; + contextCanvas.beginPath(); + contextCanvas.ellipse(widthCanvas / 2, heightCanvas / 2, widthCanvas / 2, heightCanvas / 2, 0 * Math.PI, 0, 180 * Math.PI, true); + contextCanvas.fill(); + + return createdCanvas.toDataURL(); +} From 1ab440fbe325975770817a04b79fe32c21a36933 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Fri, 7 Jul 2023 20:07:19 +0300 Subject: [PATCH 020/196] =?UTF-8?q?adding=20a=20=E2=80=9CNew=20Update=20Av?= =?UTF-8?q?ailable=E2=80=9D=20notification=20(#166)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Target #### Open Questions ## Checklist - [ ] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .../Client/Cropper.Blazor.Client.csproj | 6 ++- .../Client/Extensions/DocsVeiewExtension.cs | 6 +-- .../Client/Shared/MainLayout.razor | 1 + .../Shared/UpdateAvailableDetector.razor | 1 + .../Shared/UpdateAvailableDetector.razor.cs | 45 +++++++++++++++++++ .../Client/Styles/Cropper.Blazor.Client.scss | 1 + .../Styles/layout/_updateAvaibleDetector.scss | 5 +++ src/Cropper.Blazor/Client/wwwroot/index.html | 2 +- .../Client/wwwroot/sw-registrator.js | 38 ++++++++++++++++ .../Cropper.Blazor.UnitTests.csproj | 8 ++-- src/Cropper.Blazor/Cropper.Blazor.sln | 1 + 11 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor create mode 100644 src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor.cs create mode 100644 src/Cropper.Blazor/Client/Styles/layout/_updateAvaibleDetector.scss create mode 100644 src/Cropper.Blazor/Client/wwwroot/sw-registrator.js diff --git a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj index 0ebddae2..909aa279 100644 --- a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj +++ b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj @@ -31,7 +31,7 @@ - + @@ -105,6 +105,7 @@ + @@ -123,6 +124,7 @@ + @@ -132,6 +134,7 @@ + @@ -139,6 +142,7 @@ + diff --git a/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs b/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs index f2e9eab1..3ff7de2b 100644 --- a/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs +++ b/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs @@ -11,13 +11,13 @@ public static void TryAddDocsViewServices(this IServiceCollection services) { services.AddMudServices(config => { - config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomLeft; + config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomRight; config.SnackbarConfiguration.PreventDuplicates = false; config.SnackbarConfiguration.NewestOnTop = false; config.SnackbarConfiguration.ShowCloseIcon = true; config.SnackbarConfiguration.VisibleStateDuration = 10000; - config.SnackbarConfiguration.HideTransitionDuration = 500; - config.SnackbarConfiguration.ShowTransitionDuration = 500; + config.SnackbarConfiguration.HideTransitionDuration = 200; + config.SnackbarConfiguration.ShowTransitionDuration = 100; config.SnackbarConfiguration.SnackbarVariant = Variant.Filled; }); diff --git a/src/Cropper.Blazor/Client/Shared/MainLayout.razor b/src/Cropper.Blazor/Client/Shared/MainLayout.razor index 15be5a99..7d03b584 100644 --- a/src/Cropper.Blazor/Client/Shared/MainLayout.razor +++ b/src/Cropper.Blazor/Client/Shared/MainLayout.razor @@ -4,6 +4,7 @@ + diff --git a/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor b/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor @@ -0,0 +1 @@ + diff --git a/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor.cs b/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor.cs new file mode 100644 index 00000000..3d7dd439 --- /dev/null +++ b/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor.cs @@ -0,0 +1,45 @@ +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; +using MudBlazor; + +namespace Cropper.Blazor.Client.Shared +{ + public partial class UpdateAvailableDetector + { + [Inject] private IJSRuntime? JSRuntime { get; set; } + [Inject] private ISnackbar? Snackbar { get; set; } + [Inject] private NavigationManager? Navigation { get; set; } + + protected override async Task OnInitializedAsync() + { + await RegisterForUpdateAvailableNotification(); + } + + private async Task RegisterForUpdateAvailableNotification() + { + await JSRuntime!.InvokeAsync( + identifier: "registerForUpdateAvailableNotification", + DotNetObjectReference.Create(this), + nameof(OnUpdateAvailable)); + } + + [JSInvokable(nameof(OnUpdateAvailable))] + public void OnUpdateAvailable() + { + Snackbar!.Add("A new version of the application is available.", Severity.Warning, config => + { + config.Action = "Reload"; + config.IconColor = Color.Error; + config.ActionColor = Color.Error; + config.Icon = Icons.Material.Filled.BrowserUpdated; + config.RequireInteraction = true; + config.Onclick = snackbar => + { + Navigation!.NavigateTo(Navigation.Uri, true); + + return Task.CompletedTask; + }; + }); + } + } +} diff --git a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss index 08abaa0b..6179f399 100644 --- a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss +++ b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss @@ -1,5 +1,6 @@ @import 'layout/_mainlayout'; @import 'layout/_markdown'; +@import 'layout/_updateAvaibleDetector.scss'; @import 'components/docssection.scss'; .no-select { diff --git a/src/Cropper.Blazor/Client/Styles/layout/_updateAvaibleDetector.scss b/src/Cropper.Blazor/Client/Styles/layout/_updateAvaibleDetector.scss new file mode 100644 index 00000000..2291b4c9 --- /dev/null +++ b/src/Cropper.Blazor/Client/Styles/layout/_updateAvaibleDetector.scss @@ -0,0 +1,5 @@ +@media (min-width: 0) and (max-width: 510px) { + .mud-snackbar-location-bottom-right { + right: 0 !important; + } +} diff --git a/src/Cropper.Blazor/Client/wwwroot/index.html b/src/Cropper.Blazor/Client/wwwroot/index.html index ca7e8df9..15d27955 100644 --- a/src/Cropper.Blazor/Client/wwwroot/index.html +++ b/src/Cropper.Blazor/Client/wwwroot/index.html @@ -131,7 +131,7 @@ - + diff --git a/src/Cropper.Blazor/Client/wwwroot/sw-registrator.js b/src/Cropper.Blazor/Client/wwwroot/sw-registrator.js new file mode 100644 index 00000000..782e60b2 --- /dev/null +++ b/src/Cropper.Blazor/Client/wwwroot/sw-registrator.js @@ -0,0 +1,38 @@ +window.updateAvailable = new Promise((resolve, reject) => { + if (!('serviceWorker' in navigator)) { + const errorMessage = `This browser doesn't support service workers`; + console.error(errorMessage); + reject(errorMessage); + return; + } + + navigator.serviceWorker.register('/service-worker.min.js') + .then(registration => { + console.info(`Service worker registration successful (scope: ${registration.scope})`); + + setInterval(() => { + registration.update(); + }, 60 * 1000); // 60000ms -> check each minute + + registration.onupdatefound = () => { + const installingServiceWorker = registration.installing; + installingServiceWorker.onstatechange = () => { + if (installingServiceWorker.state === 'installed') { + resolve(!!navigator.serviceWorker.controller); + } + } + }; + }) + .catch(error => { + console.error('Service worker registration failed with error:', error); + reject(error); + }); +}); + +window.registerForUpdateAvailableNotification = (caller, methodName) => { + window.updateAvailable.then(isUpdateAvailable => { + if (isUpdateAvailable) { + caller.invokeMethodAsync(methodName).then(); + } + }); +}; \ No newline at end of file diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj index 7626347e..1fc65ae7 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj @@ -9,16 +9,16 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/Cropper.Blazor/Cropper.Blazor.sln b/src/Cropper.Blazor/Cropper.Blazor.sln index 29d818d7..15fbc932 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.sln +++ b/src/Cropper.Blazor/Cropper.Blazor.sln @@ -33,6 +33,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pipelines", "pipelines", "{ ..\..\.github\workflows\cd.yml = ..\..\.github\workflows\cd.yml ..\..\.github\workflows\ci.yml = ..\..\.github\workflows\ci.yml ..\..\.github\codecov.yml = ..\..\.github\codecov.yml + ..\..\.github\dependabot.yml = ..\..\.github\dependabot.yml ..\..\.github\workflows\release.yml = ..\..\.github\workflows\release.yml EndProjectSection EndProject From 70773ed360d710d823e97cab5ba820fec53d4f9c Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Mon, 10 Jul 2023 19:53:37 +0300 Subject: [PATCH 021/196] Update excubo.webcompiler --- src/Cropper.Blazor/Client/.config/dotnet-tools.json | 2 +- src/Cropper.Blazor/Cropper.Blazor/.config/dotnet-tools.json | 2 +- src/Cropper.Blazor/Cropper.Blazor/excubowebcompiler.json | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Cropper.Blazor/Client/.config/dotnet-tools.json b/src/Cropper.Blazor/Client/.config/dotnet-tools.json index 43057ad8..d8410c8d 100644 --- a/src/Cropper.Blazor/Client/.config/dotnet-tools.json +++ b/src/Cropper.Blazor/Client/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "excubo.webcompiler": { - "version": "3.5.20", + "version": "3.5.54", "commands": [ "webcompiler" ] diff --git a/src/Cropper.Blazor/Cropper.Blazor/.config/dotnet-tools.json b/src/Cropper.Blazor/Cropper.Blazor/.config/dotnet-tools.json index 873ad451..d8410c8d 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/.config/dotnet-tools.json +++ b/src/Cropper.Blazor/Cropper.Blazor/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "excubo.webcompiler": { - "version": "2.7.14", + "version": "3.5.54", "commands": [ "webcompiler" ] diff --git a/src/Cropper.Blazor/Cropper.Blazor/excubowebcompiler.json b/src/Cropper.Blazor/Cropper.Blazor/excubowebcompiler.json index 852c2d92..4e46967c 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/excubowebcompiler.json +++ b/src/Cropper.Blazor/Cropper.Blazor/excubowebcompiler.json @@ -42,8 +42,7 @@ "Sass": { "IndentType": "Space", "IndentWidth": 2, - "OutputStyle": "Nested", - "Precision": 5, + "OutputStyle": "Expanded", "RelativeUrls": true, "LineFeed": "Lf", "SourceMap": false From 388bcfa8624d0d16485b9d6ad7f7e27d6255592b Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Tue, 11 Jul 2023 18:19:20 +0300 Subject: [PATCH 022/196] extend GetCroppedCanvasDataURLAsync function (#172) ## Target extend GetCroppedCanvasDataURLAsync function #### Open Questions ## Checklist - [ ] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .../Client/Cropper.Blazor.Client.csproj | 2 +- .../Client/Pages/CropperDemo.razor | 8 +-- .../Client/Pages/CropperDemo.razor.cs | 4 +- src/Cropper.Blazor/Client/wwwroot/helper.js | 4 +- .../Components/CropperComponent_Should.cs | 56 +++++++++++++++++-- .../ServiceCollectionExtensions_Should.cs | 2 +- .../Services/CropperJsInterop_Should.cs | 8 ++- .../Components/CropperComponent.razor.cs | 22 +++++++- .../Services/CropperJsInterop.cs | 13 ++++- .../Services/ICropperJsInterop.cs | 6 ++ .../wwwroot/cropperJsInterop.js | 4 +- 11 files changed, 107 insertions(+), 22 deletions(-) diff --git a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj index 909aa279..ee7b3d0a 100644 --- a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj +++ b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj @@ -31,7 +31,7 @@ - + diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index 098c880d..1f43dc3e 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -160,25 +160,25 @@ Scale (-2, -1) - + Get Cropped Canvas by URL - + Get Cropped Canvas by element - + 320×180 - + 640×360 diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 6f51ca31..4fa4d9f4 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -323,7 +323,7 @@ public async void GetCroppedCanvasDataURL(GetCroppedCanvasOptions getCroppedCanv public async void GetCroppedCanvasData(GetCroppedCanvasOptions getCroppedCanvasOptions) { CroppedCanvas croppedCanvas = await CropperComponent!.GetCroppedCanvasAsync(getCroppedCanvasOptions); - string croppedCanvasDataURL = await croppedCanvas!.JSRuntimeObjectRef.InvokeAsync("toDataURL"); + string croppedCanvasDataURL = await croppedCanvas!.JSRuntimeObjectRef.InvokeAsync("toDataURL", "image/png", 1); OpenCroppedCanvasDialog(croppedCanvasDataURL); } @@ -335,7 +335,7 @@ public async void GetCroppedCanvasDataByPolygonFilter(GetCroppedCanvasOptions ge if (CropperFace == CropperFace.Default) { - croppedCanvasDataURL = await croppedCanvas!.JSRuntimeObjectRef.InvokeAsync("toDataURL"); + croppedCanvasDataURL = await croppedCanvas!.JSRuntimeObjectRef.InvokeAsync("toDataURL", "image/png", 1); } else if (CropperFace == CropperFace.Circle) { diff --git a/src/Cropper.Blazor/Client/wwwroot/helper.js b/src/Cropper.Blazor/Client/wwwroot/helper.js index 944931e6..59ad08a5 100644 --- a/src/Cropper.Blazor/Client/wwwroot/helper.js +++ b/src/Cropper.Blazor/Client/wwwroot/helper.js @@ -30,7 +30,7 @@ window.addClipPathPolygon = (sourceCanvas, path) => { context.globalCompositeOperation = 'lighter'; context.drawImage(sourceCanvas, 0, 0, width, height); - return canvas.toDataURL(); + return canvas.toDataURL("image/png", 1); } window.addClipPathEllipse = (sourceCanvas) => { @@ -49,5 +49,5 @@ window.addClipPathEllipse = (sourceCanvas) => { contextCanvas.ellipse(widthCanvas / 2, heightCanvas / 2, widthCanvas / 2, heightCanvas / 2, 0 * Math.PI, 0, 180 * Math.PI, true); contextCanvas.fill(); - return createdCanvas.toDataURL(); + return createdCanvas.toDataURL("image/png", 1); } diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs index 0854704c..4ee8b62a 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs @@ -45,6 +45,48 @@ public CropperComponent_Should() _testContext.Services.AddSingleton(_mockCropperJsInterop.Object); } + [Theory] + [InlineData(-100)] + [InlineData(-1)] + [InlineData(-0.99)] + [InlineData(1.11)] + [InlineData(111)] + public async Task Throw_Exception_Because_Of_Invalid_NumberAsync(float numberImageQuality) + { + // arrange + Faker faker = new(); + CancellationToken cancellationToken = new(); + + GetCroppedCanvasOptions getCroppedCanvasOptions = new Faker() + .Generate(); + string imageFormatType = faker.Random.Word(); + + IRenderedComponent cropperComponent = _testContext + .RenderComponent(); + + await cropperComponent.InvokeAsync(async () => + { + // act + Func func = async () => await cropperComponent.Instance.GetCroppedCanvasDataURLAsync( + getCroppedCanvasOptions, + imageFormatType, + numberImageQuality, + cancellationToken); + + // assert + await func + .Should() + .ThrowAsync() + .WithMessage($"The given number should be between 0 and 1 for indication the image quality, but found {numberImageQuality}. (Parameter 'number')"); + + _mockCropperJsInterop.Verify(c => c.GetCroppedCanvasDataURLAsync( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny()), Times.Never()); + }); + } + [Fact] public async Task Should_Render_CropperComponent_SuccessfulAsync() { @@ -95,7 +137,7 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() .Generate(); GetCroppedCanvasOptions getCroppedCanvasOptions = new Faker() .Generate(); - Mock mockIJSObjectReference = new Mock(); + Mock mockIJSObjectReference = new(); CroppedCanvas expectedCroppedCanvas = new Faker() .CustomInstantiator(c => new CroppedCanvas(mockIJSObjectReference.Object)); CropperData expectedCropperData = new Faker() @@ -129,6 +171,8 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() decimal pivotY = faker.Random.Decimal(); string newUrlImage = faker.Random.Word(); bool hasSameSize = faker.Random.Bool(); + string imageFormatType = faker.Random.Word(); + float numberImageQuality = faker.Random.Float(0, 1); Action? onLoadImageHandler = () => { @@ -236,7 +280,11 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() .ReturnsAsync(expectedCroppedCanvas); _mockCropperJsInterop - .Setup(c => c.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions, cancellationToken)) + .Setup(c => c.GetCroppedCanvasDataURLAsync( + getCroppedCanvasOptions, + imageFormatType, + numberImageQuality, + cancellationToken)) .ReturnsAsync(expectedCroppedCanvasDataURL); _mockCropperJsInterop @@ -344,9 +392,9 @@ await cropperComponent.InvokeAsync(async () => expectedCroppedCanvas.Should().BeEquivalentTo(croppedCanvas); _mockCropperJsInterop.Verify(c => c.GetCroppedCanvasAsync(getCroppedCanvasOptions, cancellationToken), Times.Once()); - string croppedCanvasDataURL = await cropperComponent.Instance.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions); + string croppedCanvasDataURL = await cropperComponent.Instance.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions, imageFormatType, numberImageQuality); expectedCroppedCanvasDataURL.Should().BeEquivalentTo(croppedCanvasDataURL); - _mockCropperJsInterop.Verify(c => c.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions, imageFormatType, numberImageQuality, cancellationToken), Times.Once()); CropperData cropperData = await cropperComponent.Instance.GetDataAsync(isRounded); expectedCropperData.Should().BeEquivalentTo(cropperData); diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/ServiceCollectionExtensions_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/ServiceCollectionExtensions_Should.cs index 9cc17931..7536026c 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/ServiceCollectionExtensions_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/ServiceCollectionExtensions_Should.cs @@ -36,7 +36,7 @@ static object[] WrapArgs( CropperJsInteropOptions? cropperJsInteropOptions) => new object[] { - cropperJsInteropOptions + cropperJsInteropOptions! }; } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/CropperJsInterop_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/CropperJsInterop_Should.cs index 988968b0..55d90ea4 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/CropperJsInterop_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/CropperJsInterop_Should.cs @@ -230,21 +230,23 @@ public async Task Verify_GetCroppedCanvasAsync() } [Fact] - public async Task Verify_GetCroppedCanvasDataURLAsync() + public async Task Verify_GetCroppedCanvasDataURL_By_TypeAndNumber_Async() { // arrange string expectedCroppedCanvasURL = _faker.Random.Word(); + string type = _faker.Random.Word(); + float number = _faker.Random.Float(); GetCroppedCanvasOptions getCroppedCanvasOptions = new Faker(); _testContext.JSInterop - .Setup("cropper.getCroppedCanvasDataURL", getCroppedCanvasOptions) + .Setup("cropper.getCroppedCanvasDataURL", getCroppedCanvasOptions, type, number) .SetResult(expectedCroppedCanvasURL); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - string croppedCanvasURL = await _cropperJsInterop.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions); + string croppedCanvasURL = await _cropperJsInterop.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions, type, number); // assert expectedCroppedCanvasURL.Should().BeEquivalentTo(croppedCanvasURL); diff --git a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs index 50a66659..ea97b3a4 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Threading; using System.Threading.Tasks; using Cropper.Blazor.Base; @@ -569,11 +570,28 @@ public async ValueTask GetCroppedCanvasAsync(GetCroppedCanvasOpti /// Get a canvas drawn from the cropped image (lossy compression). If it is not cropped, then returns a canvas drawn the whole image. /// /// Options for getting cropped canvas. + /// A string indicating the image format. The default type is image/png; this image format will be also used if the specified type is not supported. + /// A number between 0 and 1 indicating the image quality to be used when creating images using file formats that support lossy compression (such as image/jpeg or image/webp). + /// Different browsers have different image encoder compression, usually it is 92 or 80 percent of the full image quality. + /// /// The used to propagate notifications that the operation should be canceled. /// A representing canvas drawn the cropped image in URL format asynchronous operation. - public async ValueTask GetCroppedCanvasDataURLAsync(GetCroppedCanvasOptions getCroppedCanvasOptions, CancellationToken cancellationToken = default) + public async ValueTask GetCroppedCanvasDataURLAsync( + GetCroppedCanvasOptions getCroppedCanvasOptions, + string type = "image/png", + float number = 1, + CancellationToken cancellationToken = default) { - return await CropperJsIntertop!.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions, cancellationToken); + + return number switch + { + < 0 or > 1 => throw new ArgumentException($"The given number should be between 0 and 1 for indication the image quality, but found {number}.", nameof(number)), + _ => await CropperJsIntertop!.GetCroppedCanvasDataURLAsync( + getCroppedCanvasOptions, + type, + number, + cancellationToken) + }; } /// diff --git a/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs b/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs index 02f0a7d7..fdb30e4b 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs @@ -240,10 +240,16 @@ public async ValueTask GetCroppedCanvasAsync( /// Get a canvas drawn the cropped image. /// /// The config options. + /// A string indicating the image format. The default type is image/png; this image format will be also used if the specified type is not supported. + /// A number between 0 and 1 indicating the image quality to be used when creating images using file formats that support lossy compression (such as image/jpeg or image/webp). A user agent will use its default quality value if this option is not specified, or if the number is outside the allowed range. + /// Different browsers have different image encoder compression, usually it is 92 or 80 percent of the full image quality. + /// /// The used to propagate notifications that the operation should be canceled. /// A representing URL result canvas asynchronous operation. public async ValueTask GetCroppedCanvasDataURLAsync( GetCroppedCanvasOptions getCroppedCanvasOptions, + string type, + float number, CancellationToken cancellationToken = default) { if (Module is null) @@ -251,7 +257,12 @@ public async ValueTask GetCroppedCanvasDataURLAsync( await LoadModuleAsync(cancellationToken); } - return await _jsRuntime!.InvokeAsync("cropper.getCroppedCanvasDataURL", cancellationToken, getCroppedCanvasOptions); + return await _jsRuntime!.InvokeAsync( + "cropper.getCroppedCanvasDataURL", + cancellationToken, + getCroppedCanvasOptions, + type, + number); } /// diff --git a/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs b/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs index f137fc5e..0c781b42 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs @@ -308,10 +308,16 @@ ValueTask GetCroppedCanvasAsync( /// Get a canvas drawn the cropped image. /// /// The config options. + /// A string indicating the image format. The default type is image/png; this image format will be also used if the specified type is not supported. + /// A number between 0 and 1 indicating the image quality to be used when creating images using file formats that support lossy compression (such as image/jpeg or image/webp). A user agent will use its default quality value if this option is not specified, or if the number is outside the allowed range. + /// Different browsers have different image encoder compression, usually it is 92 or 80 percent of the full image quality. + /// /// The used to propagate notifications that the operation should be canceled. /// A representing URL result canvas asynchronous operation. ValueTask GetCroppedCanvasDataURLAsync( GetCroppedCanvasOptions getCroppedCanvasOptions, + string type, + float number, CancellationToken cancellationToken = default); /// diff --git a/src/Cropper.Blazor/Cropper.Blazor/wwwroot/cropperJsInterop.js b/src/Cropper.Blazor/Cropper.Blazor/wwwroot/cropperJsInterop.js index 7d9e89b3..07f35864 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/wwwroot/cropperJsInterop.js +++ b/src/Cropper.Blazor/Cropper.Blazor/wwwroot/cropperJsInterop.js @@ -40,8 +40,8 @@ class CropperDecorator { return this.cropperInstance.getCroppedCanvas(options); } - getCroppedCanvasDataURL(options) { - return this.cropperInstance.getCroppedCanvas(options).toDataURL(); + getCroppedCanvasDataURL(options, type, encoderOptions) { + return this.cropperInstance.getCroppedCanvas(options).toDataURL(type, encoderOptions); } getData(rounded) { From fc81ac9e19d00c22b9d06768558a072a9d8d73d7 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Sat, 15 Jul 2023 23:38:30 +0300 Subject: [PATCH 023/196] Extend preview in options (#173) ## Target #### Open Questions ## Checklist - [x] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .../Components/Docs/SectionContent.razor | 24 ++- .../Components/Docs/SectionContent.razor.cs | 27 ++- .../Client/Pages/CropperDemo.razor | 8 +- .../Client/Pages/CropperDemo.razor.cs | 22 ++- ...nstallServicesForBlazorServerExample.razor | 0 ...allServicesForBlazorServerExampleCode.html | 0 .../InstallationManualComponentsExample.razor | 0 ...stallationManualComponentsExampleCode.html | 18 +- .../InstallationManualCssFontsExample.razor | 0 ...InstallationManualCssFontsExampleCode.html | 0 .../InstallationManualImportsExample.razor | 0 .../InstallationManualImportsExampleCode.html | 0 .../InstallationManualPackageExample.razor | 0 .../InstallationManualPackageExampleCode.html | 0 ...ntReferenceSelectorComponentsExample.razor | 25 +++ ...ferenceSelectorComponentsExample.razor.css | 14 ++ ...eferenceSelectorComponentsExampleCode.html | 54 ++++++ ...ntReferenceSelectorComponentsExample.razor | 25 +++ ...ferenceSelectorComponentsExample.razor.css | 14 ++ ...eferenceSelectorComponentsExampleCode.html | 57 +++++++ ...wFromStringSelectorComponentsExample.razor | 16 ++ ...mStringSelectorComponentsExample.razor.css | 14 ++ ...omStringSelectorComponentsExampleCode.html | 45 +++++ src/Cropper.Blazor/Client/Pages/Index.razor | 28 +++- .../Client/Pages/Index.razor.cs | 34 ++++ .../Client/Styles/layout/_markdown.scss | 10 ++ .../Models/Options_Should.cs | 155 ++++++++++++++++++ src/Cropper.Blazor/Cropper.Blazor.sln | 1 - .../Cropper.Blazor/Cropper.Blazor.csproj | 2 +- .../Cropper.Blazor/Models/Options.cs | 76 ++++++++- 30 files changed, 643 insertions(+), 26 deletions(-) rename src/Cropper.Blazor/Client/Pages/Examples/{ => Installation}/InstallServicesForBlazorServerExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/Examples/{ => Installation}/InstallServicesForBlazorServerExampleCode.html (100%) rename src/Cropper.Blazor/Client/Pages/Examples/{ => Installation}/InstallationManualComponentsExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/Examples/{ => Installation}/InstallationManualComponentsExampleCode.html (75%) rename src/Cropper.Blazor/Client/Pages/Examples/{ => Installation}/InstallationManualCssFontsExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/Examples/{ => Installation}/InstallationManualCssFontsExampleCode.html (100%) rename src/Cropper.Blazor/Client/Pages/Examples/{ => Installation}/InstallationManualImportsExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/Examples/{ => Installation}/InstallationManualImportsExampleCode.html (100%) rename src/Cropper.Blazor/Client/Pages/Examples/{ => Installation}/InstallationManualPackageExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/Examples/{ => Installation}/InstallationManualPackageExampleCode.html (100%) create mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor create mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css create mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html create mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor create mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css create mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html create mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor create mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css create mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html create mode 100644 src/Cropper.Blazor/Client/Pages/Index.razor.cs create mode 100644 src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/Options_Should.cs diff --git a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor index 0bf6ce6a..31be8b04 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor +++ b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor @@ -14,20 +14,31 @@ @if (Codes != null || ChildContent != null) { + @if(Codes != null) { @foreach (var codefile in Codes) { - @codefile.title + + @codefile.title + } } @if (HasCode && ChildContent != null) { - - @(ShowCode ? "Hide code" : "Show code") + + @(ShowCode ? "Hide code" : "Show code") } + } @if (ChildContent != null) @@ -44,6 +55,11 @@
@CodeComponent(ActiveCode)
- + } \ No newline at end of file diff --git a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs index 4d3314e1..6d927df3 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs +++ b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs @@ -2,6 +2,7 @@ using Cropper.Blazor.Client.Models; using Microsoft.AspNetCore.Components; using MudBlazor; +using MudBlazor.Services; using MudBlazor.Utilities; namespace Cropper.Blazor.Client.Components.Docs; @@ -9,6 +10,7 @@ namespace Cropper.Blazor.Client.Components.Docs; public partial class SectionContent { [Inject] protected IJsApiService? JsApiService { get; set; } + [Inject] IBreakpointService BreakpointService { get; set; } = null!; protected string Classname => new CssBuilder("docs-section-content") @@ -17,6 +19,7 @@ public partial class SectionContent .AddClass("show-code", HasCode && ShowCode) .AddClass(Class) .Build(); + protected string ToolbarClassname => new CssBuilder("docs-section-content-toolbar") .AddClass($"outlined", Outlined && ChildContent != null) @@ -50,7 +53,9 @@ public partial class SectionContent [Parameter] public RenderFragment ChildContent { get; set; } private bool HasCode; - private string ActiveCode; + public string ActiveCode; + + private bool IsVerticalAlign = false; protected override void OnParametersSet() { @@ -59,13 +64,27 @@ protected override void OnParametersSet() HasCode = true; ActiveCode = Codes.FirstOrDefault().code; } - else if (!String.IsNullOrWhiteSpace(Code)) + else if (!string.IsNullOrWhiteSpace(Code)) { HasCode = true; ActiveCode = Code; } } + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + await BreakpointService!.SubscribeAsync((br) => + { + IsVerticalAlign = BreakpointService!.IsMediaSize(br, Breakpoint.Xs); + InvokeAsync(StateHasChanged); + }); + } + + await base.OnAfterRenderAsync(firstRender); + } + public void OnShowCode() { ShowCode = !ShowCode; @@ -88,9 +107,9 @@ private string GetActiveCode(string value) } } - private async Task CopyTextToClipboard() + private async Task CopyTextToClipboardAsync() { - await JsApiService.CopyToClipboardAsync(Snippets.GetCode(string.IsNullOrWhiteSpace(Code) ? ActiveCode : Code)); + await JsApiService!.CopyToClipboardAsync(Snippets.GetCode(string.IsNullOrWhiteSpace(Code) ? ActiveCode : Code)); } RenderFragment CodeComponent(string code) => builder => diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index 1f43dc3e..9577a519 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -34,12 +34,12 @@
-
+
-
+
-
-
+
+
diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 4fa4d9f4..208dfc1b 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -42,6 +42,10 @@ public partial class CropperDemo : IDisposable private readonly string _errorLoadImageSrc = "not-found-image.jpg"; private Breakpoint Start; private Guid SubscriptionId; + private ElementReference ElementReferencePreviewLg; + private ElementReference ElementReferencePreviewMd; + private ElementReference ElementReferencePreviewSm; + private ElementReference ElementReferencePreviewXs; public Dictionary InputAttributes { get; set; } = new Dictionary() @@ -54,12 +58,26 @@ protected override void OnInitialized() { Options = new Options() { - Preview = ".img-preview", + //Preview = ".img-preview", AspectRatio = (decimal)16 / 9, ViewMode = ViewMode.Vm0 }; } + protected override void OnAfterRender(bool firstRender) + { + if (firstRender) + { + Options.Preview = new ElementReference[] + { + ElementReferencePreviewXs, + ElementReferencePreviewSm, + ElementReferencePreviewMd, + ElementReferencePreviewLg + }; + } + } + public async void OnCropEvent(JSEventData cropJSEvent) { if (cropJSEvent?.Detail is not null) @@ -502,7 +520,7 @@ private void OpenCroppedCanvasDialog(string croppedCanvasDataURL) { "Src", croppedCanvasDataURL } }; - DialogOptions options = new DialogOptions + DialogOptions options = new() { CloseButton = true, MaxWidth = MaxWidth.Medium, diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallServicesForBlazorServerExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallServicesForBlazorServerExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/InstallServicesForBlazorServerExample.razor rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallServicesForBlazorServerExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallServicesForBlazorServerExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallServicesForBlazorServerExampleCode.html similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/InstallServicesForBlazorServerExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallServicesForBlazorServerExampleCode.html diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualComponentsExample.razor rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExampleCode.html similarity index 75% rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualComponentsExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExampleCode.html index f497f1ce..9b30e4fc 100644 --- a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualComponentsExampleCode.html +++ b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExampleCode.html @@ -1,5 +1,6 @@ 
-
+    
+
 @using Cropper.Blazor.Components;
 
 <CropperComponent 
@@ -7,5 +8,18 @@
     Src="cropperblazor.png"
     Options="Blazor.Models.Options()"
 />
-
+ +
+
+
+ // Add this style for cropper. +
+
+.cropper-example {
+    max-height: 300px;
+    width: 100%;
+}
+
+        
+
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualCssFontsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualCssFontsExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualCssFontsExample.razor rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualCssFontsExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualCssFontsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualCssFontsExampleCode.html similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualCssFontsExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualCssFontsExampleCode.html diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualImportsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualImportsExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualImportsExample.razor rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualImportsExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualImportsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualImportsExampleCode.html similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualImportsExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualImportsExampleCode.html diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualPackageExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualPackageExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualPackageExample.razor rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualPackageExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/InstallationManualPackageExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualPackageExampleCode.html similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/InstallationManualPackageExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualPackageExampleCode.html diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor new file mode 100644 index 00000000..5730dad3 --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor @@ -0,0 +1,25 @@ +@using Cropper.Blazor.Components + +
+ +
+
+ +@code { + private Blazor.Models.Options Options = new(); + private ElementReference ElementReference; + + protected override void OnAfterRender(bool firstRender) + { + if (firstRender) + { + Options.Preview = new ElementReference[] + { + ElementReference + }; + } + } +} diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css new file mode 100644 index 00000000..515e4e8c --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css @@ -0,0 +1,14 @@ +.cropper-example { + max-height: 300px; + width: 100%; +} + +.img-example-preview { + width: 100%; + height: 300px; + overflow: hidden; +} + +.img-example-preview > ::deep img { + max-width: 100%; +} diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html new file mode 100644 index 00000000..343478c0 --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html @@ -0,0 +1,54 @@ +
+
+
+@using Cropper.Blazor.Components;
+
+<div class="img-container"
+        <CropperComponent 
+            Class="cropper-example"
+            Src="cropperblazor.png"
+            Options="Options"
+        />
+</div>
+<div @ref="ElementReference" class="img-example-preview" />
+
+
@code {
+    private Blazor.Models.Options Options = new();
+    private Microsoft.AspNetCore.Components.ElementReference ElementReference;
+
+    protected override void OnAfterRender(bool firstRender)
+    {
+        if (firstRender)
+        {
+            Options.Preview = new ElementReference[]
+            {
+                ElementReference
+            };
+        }
+    }
+}
+
+
+
+
+ // Add this style for cropper and preview image. +
+
+.cropper-example {
+    max-height: 300px;
+    width: 100%;
+}
+
+.img-example-preview {
+    width: 100%;
+    height: 300px;
+    overflow: hidden;
+}
+
+.img-example-preview > ::deep img {
+    max-width: 100%;
+}
+
+        
+
+
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor new file mode 100644 index 00000000..04395890 --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor @@ -0,0 +1,25 @@ +@using Cropper.Blazor.Components + +
+ +
+
+
+ +@code { + private Blazor.Models.Options Options = new(); + private ElementReference FirstElementReference; + private ElementReference SecondElementReference; + + protected override void OnAfterRender(bool firstRender) + { + if (firstRender) + { + Options.Preview = new ElementReference[] + { + FirstElementReference, + SecondElementReference + }; + } + } +} diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css new file mode 100644 index 00000000..515e4e8c --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css @@ -0,0 +1,14 @@ +.cropper-example { + max-height: 300px; + width: 100%; +} + +.img-example-preview { + width: 100%; + height: 300px; + overflow: hidden; +} + +.img-example-preview > ::deep img { + max-width: 100%; +} diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html new file mode 100644 index 00000000..97293bd9 --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html @@ -0,0 +1,57 @@ +
+
+
+@using Cropper.Blazor.Components;
+
+<div class="img-container"
+        <CropperComponent 
+            Class="cropper-example"
+            Src="cropperblazor.png"
+            Options="Options"
+        />
+</div>
+<div @ref="FirstElementReference" class="img-example-preview" />
+<div @ref="SecondElementReference" class="img-example-preview" />
+
+
@code {
+    private Blazor.Models.Options Options = new();
+    private Microsoft.AspNetCore.Components.ElementReference FirstElementReference;
+    private Microsoft.AspNetCore.Components.ElementReference SecondElementReference;
+
+    protected override void OnAfterRender(bool firstRender)
+    {
+        if (firstRender)
+        {
+            Options.Preview = new ElementReference[]
+            {
+                FirstElementReference,
+                SecondElementReference
+            };
+        }
+    }
+}
+
+
+
+
+ // Add this style for cropper and preview image. +
+
+.cropper-example {
+    max-height: 300px;
+    width: 100%;
+}
+
+.img-example-preview {
+    width: 100%;
+    height: 300px;
+    overflow: hidden;
+}
+
+.img-example-preview > ::deep img {
+    max-width: 100%;
+}
+
+        
+
+
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor new file mode 100644 index 00000000..13f4d5a9 --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor @@ -0,0 +1,16 @@ +@using Cropper.Blazor.Components + +
+ +
+
+ +@code { + private Blazor.Models.Options Options = new Blazor.Models.Options + { + Preview = ".img-example-preview" + }; +} diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css new file mode 100644 index 00000000..515e4e8c --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css @@ -0,0 +1,14 @@ +.cropper-example { + max-height: 300px; + width: 100%; +} + +.img-example-preview { + width: 100%; + height: 300px; + overflow: hidden; +} + +.img-example-preview > ::deep img { + max-width: 100%; +} diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html new file mode 100644 index 00000000..11f76130 --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html @@ -0,0 +1,45 @@ +
+
+
+@using Cropper.Blazor.Components;
+
+<div class="img-container"
+        <CropperComponent 
+            Class="cropper-example"
+            Src="cropperblazor.png"
+            Options="Options"
+        />
+</div>
+<div class="img-example-preview" />
+
+
@code {
+    private Blazor.Models.Options Options = new Blazor.Models.Options
+    {
+        Preview = ".img-example-preview"
+    };
+}
+
+
+
+
+ // Add this style for cropper and preview image. +
+
+.cropper-example {
+    max-height: 300px;
+    width: 100%;
+}
+
+.img-example-preview {
+    width: 100%;
+    height: 300px;
+    overflow: hidden;
+}
+
+.img-example-preview > ::deep img {
+    max-width: 100%;
+}
+
+        
+
+
diff --git a/src/Cropper.Blazor/Client/Pages/Index.razor b/src/Cropper.Blazor/Client/Pages/Index.razor index 7defb1f2..7610889f 100644 --- a/src/Cropper.Blazor/Client/Pages/Index.razor +++ b/src/Cropper.Blazor/Client/Pages/Index.razor @@ -2,7 +2,8 @@ @using Cropper.Blazor.Client.Components @using Cropper.Blazor.Client.Components.Docs @using Cropper.Blazor.Client.Models; -@using Cropper.Blazor.Client.Pages.Examples +@using Cropper.Blazor.Client.Pages.Examples.Installation +@using Cropper.Blazor.Client.Pages.Examples.Uses.Preview @@ -22,8 +23,8 @@ - Cropper.Blazor - is a component element that wraps around + Cropper.Blazor + is a component element that wraps around Cropper.js @@ -113,6 +114,27 @@ + + + Add the following components to your MainLayout.razor + + Notes for Preview Option: + + + + + + + + + + diff --git a/src/Cropper.Blazor/Client/Pages/Index.razor.cs b/src/Cropper.Blazor/Client/Pages/Index.razor.cs new file mode 100644 index 00000000..d027320c --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Index.razor.cs @@ -0,0 +1,34 @@ +using Cropper.Blazor.Client.Components.Docs; +using Cropper.Blazor.Client.Pages.Examples.Uses.Preview; +using Microsoft.AspNetCore.Components; + +namespace Cropper.Blazor.Client.Pages +{ + public partial class Index + { + SectionContent ActivePreviewActive = null!; + + RenderFragment PreviewActiveRenderFragment => builder => + { + if (ActivePreviewActive.ActiveCode == nameof(UsesPreviewFromStringSelectorComponentsExample)) + { + builder.OpenComponent(1); + builder.CloseComponent(); + } + else if (ActivePreviewActive.ActiveCode == nameof(UsesPreviewFromElementReferenceSelectorComponentsExample)) + { + builder.OpenComponent(1); + builder.CloseComponent(); + } + else if (ActivePreviewActive.ActiveCode == nameof(UsesPreviewFromMultipleElementReferenceSelectorComponentsExample)) + { + builder.OpenComponent(1); + builder.CloseComponent(); + } + else + { + throw new InvalidOperationException(); + } + }; + } +} diff --git a/src/Cropper.Blazor/Client/Styles/layout/_markdown.scss b/src/Cropper.Blazor/Client/Styles/layout/_markdown.scss index ed250cab..3f0602b2 100644 --- a/src/Cropper.Blazor/Client/Styles/layout/_markdown.scss +++ b/src/Cropper.Blazor/Client/Styles/layout/_markdown.scss @@ -109,6 +109,16 @@ direction: ltr; } + & .css { + & .property { + color: hsl(76, 21%, 52%); + } + + & .comment { + color: #57a64a; + } + } + & .csharp { & .atSign { color: var(--mud-palette-text-primary); diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/Options_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/Options_Should.cs new file mode 100644 index 00000000..45741cb9 --- /dev/null +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/Options_Should.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Cropper.Blazor.Models; +using FluentAssertions; +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; +using Microsoft.JSInterop.Infrastructure; +using Xunit; + +namespace Cropper.Blazor.UnitTests.Models +{ + public class Options_Should + { + private readonly Options _options; + private readonly InternalJSRuntime _internalJSRuntime; + + public class InternalJSRuntime : JSRuntime + { + protected override void BeginInvokeJS(long taskId, string identifier, string? argsJson, JSCallResultType resultType, long targetInstanceId) + { + throw new System.NotImplementedException(); + } + + protected override void EndInvokeDotNet(DotNetInvocationInfo invocationInfo, in DotNetInvocationResult invocationResult) + { + throw new System.NotImplementedException(); + } + + public JsonSerializerOptions GetJsonSerializerOptions => JsonSerializerOptions; + } + + public class CustomElementReferenceContext : ElementReferenceContext + { + + } + + public Options_Should() + { + _options = new(); + _internalJSRuntime = new(); + } + + [Theory, MemberData(nameof(TestData_Setup_Options_Preview))] + public void Verify_Setup_Options_Preview(object? preview, string expectedObject) + { + // arrange + _options.Preview = preview; + + // act + string resultObj = JsonSerializer.Serialize( + _options, + _internalJSRuntime.GetJsonSerializerOptions); + + // assert + _options.Preview.Should().BeEquivalentTo(preview); + + resultObj.Should().BeEquivalentTo(expectedObject); + } + + [Theory, MemberData(nameof(TestData_Throw_ArgumentException_When_Setup_Options_Preview))] + public void Throw_ArgumentException_When_Setup_Options_Preview(object? preview, string expectedMessage) + { + // arrange + Action act = () => _options.Preview = preview; + + // act & assert + act + .Should() + .Throw() + .WithMessage(expectedMessage); + } + + public static IEnumerable TestData_Setup_Options_Preview() + { + yield return WrapArgs( + null, + "{\"correlationId\":\"Cropper.Blazor\"}"); + + yield return WrapArgs( + ".testClass", + "{\"preview\":\".testClass\",\"correlationId\":\"Cropper.Blazor\"}"); + + yield return WrapArgs( + new ElementReference("ElementReferenceId"), + "{\"preview\":{\"id\":\"ElementReferenceId\",\"context\":null},\"correlationId\":\"Cropper.Blazor\"}"); + + yield return WrapArgs( + new ElementReference("ElementReferenceId", new CustomElementReferenceContext()), + "{\"preview\":{\"id\":\"ElementReferenceId\",\"context\":{}},\"correlationId\":\"Cropper.Blazor\"}"); + + yield return WrapArgs( + new ElementReference[] + { + new ElementReference("ElementReferenceId"), + new ElementReference("ElementReferenceId", new CustomElementReferenceContext()) + }, + "{\"preview\":[{\"id\":\"ElementReferenceId\",\"context\":null},{\"id\":\"ElementReferenceId\",\"context\":{}}],\"correlationId\":\"Cropper.Blazor\"}"); + + static object[] WrapArgs( + object? preview, + string expectedObject) + => new object[] + { + preview!, + expectedObject + }; + } + + public static IEnumerable TestData_Throw_ArgumentException_When_Setup_Options_Preview() + { + yield return WrapArgs( + Array.Empty(), + "'Preview' should be not an empty collection of ElementReference."); + + yield return WrapArgs( + new ElementReference(), + "'Preview' must not contain an empty Reference element."); + + yield return WrapArgs( + new ElementReference[] + { + new ElementReference(), + new ElementReference("ElementReferenceId"), + new ElementReference("ElementReferenceId", new CustomElementReferenceContext()) + }, + "'Preview' must not contain an empty Reference element in the ElementReference collection."); + + yield return WrapArgs( + "", + "'Preview' should be not an empty or include white spaces in the string."); + + yield return WrapArgs( + " ", + "'Preview' should be not an empty or include white spaces in the string."); + + yield return WrapArgs( + new object(), + "'Preview' is only available for string, ElementReference, IEnumerable types, but found 'System.Object' type."); + + yield return WrapArgs( + new CustomElementReferenceContext(), + "'Preview' is only available for string, ElementReference, IEnumerable types, but found 'Cropper.Blazor.UnitTests.Models.Options_Should+CustomElementReferenceContext' type."); + + static object[] WrapArgs( + object? preview, + string expectedMessage) + => new object[] + { + preview!, + expectedMessage + }; + } + } +} diff --git a/src/Cropper.Blazor/Cropper.Blazor.sln b/src/Cropper.Blazor/Cropper.Blazor.sln index 15fbc932..027871bb 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.sln +++ b/src/Cropper.Blazor/Cropper.Blazor.sln @@ -32,7 +32,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pipelines", "pipelines", "{ ProjectSection(SolutionItems) = preProject ..\..\.github\workflows\cd.yml = ..\..\.github\workflows\cd.yml ..\..\.github\workflows\ci.yml = ..\..\.github\workflows\ci.yml - ..\..\.github\codecov.yml = ..\..\.github\codecov.yml ..\..\.github\dependabot.yml = ..\..\.github\dependabot.yml ..\..\.github\workflows\release.yml = ..\..\.github\workflows\release.yml EndProjectSection diff --git a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj index 2bbe6ea5..ecb17ad9 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj @@ -14,7 +14,7 @@ - 1.2.2 + 1.2.3 LICENSE NuGet.png Cropper.Blazor diff --git a/src/Cropper.Blazor/Cropper.Blazor/Models/Options.cs b/src/Cropper.Blazor/Cropper.Blazor/Models/Options.cs index 9643e0f4..4529fc33 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Models/Options.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Models/Options.cs @@ -1,5 +1,9 @@ -using System.ComponentModel.DataAnnotations; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; using System.Text.Json.Serialization; +using Microsoft.AspNetCore.Components; namespace Cropper.Blazor.Models { @@ -8,6 +12,8 @@ namespace Cropper.Blazor.Models ///
public class Options { + private object? preview = null; + /// /// Define the fixed aspect ratio of the crop box. /// @@ -20,14 +26,74 @@ public class Options /// /// Add extra elements (containers) for preview. - /// An element or an array of elements or a node list object or a valid selector for Document.querySelectorAll. + /// An element or an array of elements or a list or a valid string selector for Document.querySelectorAll. /// /// - /// Default: '' + /// Default: null. + ///
+ /// Notes: + ///
+ /// The maximum width is the initial width of the preview container. + ///
+ /// The maximum height is the initial height of the preview container. + ///
+ /// If you set an aspectRatio option, be sure to set the same aspect ratio to the preview container. + ///
+ /// If the preview does not display correctly, set the overflow: hidden style to the preview container. ///
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("preview")] - public string Preview { get; set; } = string.Empty; + public object? Preview + { + get => preview; + set + { + if (value is ElementReference elementReference) + { + if (elementReference.Equals(default(ElementReference))) + { + throw new ArgumentException("'Preview' must not contain an empty Reference element."); + } + + preview = value; + } + else if (value is string classValue) + { + if (!string.IsNullOrWhiteSpace(classValue)) + { + preview = value; + } + else + { + throw new ArgumentException("'Preview' should be not an empty or include white spaces in the string."); + } + } + else if (value is IEnumerable listElementReferences) + { + if (listElementReferences.Any(elementReference => elementReference.Equals(default(ElementReference)))) + { + throw new ArgumentException("'Preview' must not contain an empty Reference element in the ElementReference collection."); + } + + if (listElementReferences.Any()) + { + preview = value; + } + else + { + throw new ArgumentException("'Preview' should be not an empty collection of ElementReference."); + } + } + else if (value is null) + { + preview = value; + } + else + { + throw new ArgumentException($"'Preview' is only available for string, ElementReference, IEnumerable types, but found '{value!.GetType()}' type."); + } + } + } /// /// Enable to crop the image automatically when initialized. From 32e8cabac797ed9e09ffad2bf130129e8fc98b7c Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Tue, 18 Jul 2023 01:26:42 +0300 Subject: [PATCH 024/196] Feature/sync dev with master (#176) ## Target #### Open Questions ## Checklist - [ ] Documentation updated - [ ] Tests cover new or modified code - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --------- Co-authored-by: ColdForeign Co-authored-by: George Radchuk <38187349+ColdForeign@users.noreply.github.com> --- .../Client/Shared/MainLayout.razor | 1 - .../Client/Shared/MainLayout.razor.cs | 2 +- .../Shared/UpdateAvailableDetector.razor | 1 - .../Shared/UpdateAvailableDetector.razor.cs | 45 ------------------- .../wwwroot/service-worker.published.js | 35 +++++++++++++-- .../Client/wwwroot/sw-registrator.js | 8 ---- 6 files changed, 32 insertions(+), 60 deletions(-) delete mode 100644 src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor delete mode 100644 src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor.cs diff --git a/src/Cropper.Blazor/Client/Shared/MainLayout.razor b/src/Cropper.Blazor/Client/Shared/MainLayout.razor index 7d03b584..15be5a99 100644 --- a/src/Cropper.Blazor/Client/Shared/MainLayout.razor +++ b/src/Cropper.Blazor/Client/Shared/MainLayout.razor @@ -4,7 +4,6 @@ - diff --git a/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs index 34fab34e..0243cba5 100644 --- a/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs @@ -33,7 +33,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) } InvokeAsync(StateHasChanged); - }, new MudBlazor.Services.ResizeOptions + }, new ResizeOptions { ReportRate = 50, NotifyOnBreakpointOnly = false, diff --git a/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor b/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor deleted file mode 100644 index 8b137891..00000000 --- a/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor.cs b/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor.cs deleted file mode 100644 index 3d7dd439..00000000 --- a/src/Cropper.Blazor/Client/Shared/UpdateAvailableDetector.razor.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Microsoft.AspNetCore.Components; -using Microsoft.JSInterop; -using MudBlazor; - -namespace Cropper.Blazor.Client.Shared -{ - public partial class UpdateAvailableDetector - { - [Inject] private IJSRuntime? JSRuntime { get; set; } - [Inject] private ISnackbar? Snackbar { get; set; } - [Inject] private NavigationManager? Navigation { get; set; } - - protected override async Task OnInitializedAsync() - { - await RegisterForUpdateAvailableNotification(); - } - - private async Task RegisterForUpdateAvailableNotification() - { - await JSRuntime!.InvokeAsync( - identifier: "registerForUpdateAvailableNotification", - DotNetObjectReference.Create(this), - nameof(OnUpdateAvailable)); - } - - [JSInvokable(nameof(OnUpdateAvailable))] - public void OnUpdateAvailable() - { - Snackbar!.Add("A new version of the application is available.", Severity.Warning, config => - { - config.Action = "Reload"; - config.IconColor = Color.Error; - config.ActionColor = Color.Error; - config.Icon = Icons.Material.Filled.BrowserUpdated; - config.RequireInteraction = true; - config.Onclick = snackbar => - { - Navigation!.NavigateTo(Navigation.Uri, true); - - return Task.CompletedTask; - }; - }); - } - } -} diff --git a/src/Cropper.Blazor/Client/wwwroot/service-worker.published.js b/src/Cropper.Blazor/Client/wwwroot/service-worker.published.js index 861b54f8..241dae9e 100644 --- a/src/Cropper.Blazor/Client/wwwroot/service-worker.published.js +++ b/src/Cropper.Blazor/Client/wwwroot/service-worker.published.js @@ -2,8 +2,30 @@ // offline support. See https://aka.ms/blazor-offline-considerations self.importScripts('./service-worker-assets.js'); -self.addEventListener('install', event => event.waitUntil(onInstall(event))); -self.addEventListener('activate', event => event.waitUntil(onActivate(event))); +self.addEventListener('install', event => { + event.waitUntil( + Promise.all([ + onInstall(), + self.skipWaiting(), + ]) + ); +}); +self.addEventListener('activate', event => { + event.waitUntil( + Promise.all( + [ + onActivate(), + self.clients.claim(), + self.skipWaiting(), + ] + ) + .catch( + (err) => { + event.skipWaiting(); + } + ) + ); +}); self.addEventListener('fetch', event => event.respondWith(onFetch(event))); const cacheNamePrefix = 'offline-cache-'; @@ -18,8 +40,13 @@ async function onInstall(event) { const assetsRequests = self.assetsManifest.assets .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url))) .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url))) - .map(asset => new Request(asset.url, {integrity: asset.hash, cache: 'no-cache'})); - await caches.open(cacheName).then(cache => cache.addAll(assetsRequests)); + .map(asset => new Request(asset.url, { integrity: asset.hash, cache: 'no-cache' })); + + await caches.open(cacheName) + .then(cache => cache.addAll(assetsRequests)) + .then(() => { + return self.skipWaiting(); + }); } async function onActivate(event) { diff --git a/src/Cropper.Blazor/Client/wwwroot/sw-registrator.js b/src/Cropper.Blazor/Client/wwwroot/sw-registrator.js index 782e60b2..c4ec0c18 100644 --- a/src/Cropper.Blazor/Client/wwwroot/sw-registrator.js +++ b/src/Cropper.Blazor/Client/wwwroot/sw-registrator.js @@ -28,11 +28,3 @@ window.updateAvailable = new Promise((resolve, reject) => { reject(error); }); }); - -window.registerForUpdateAvailableNotification = (caller, methodName) => { - window.updateAvailable.then(isUpdateAvailable => { - if (isUpdateAvailable) { - caller.invokeMethodAsync(methodName).then(); - } - }); -}; \ No newline at end of file From 26f50045f90dd5cc2229d7c540344e3921cfd6f6 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Mon, 24 Jul 2023 09:52:57 +0300 Subject: [PATCH 025/196] Fix/isolation multiple active croppers (#178) ## Target Fix/isolation multiple active croppers. Issue: https://github.com/CropperBlazor/Cropper.Blazor/issues/168 #### Open Questions ## Checklist - [ ] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [x] Includes breaking changes - [x] Version bumped ## Visuals --------- Co-authored-by: ColdForeign Co-authored-by: George Radchuk <38187349+ColdForeign@users.noreply.github.com> --- .../Components/CropperComponent_Should.cs | 119 +++++--- .../ServiceCollectionExtensions_Should.cs | 2 +- .../Services/CropperJsInterop_Should.cs | 153 ++++++---- .../Components/CropperComponent.razor.cs | 92 +++--- .../Cropper.Blazor/Cropper.Blazor.csproj | 2 +- .../Extensions/ServiceCollectionExtensions.cs | 4 +- .../Services/CropperJsInterop.cs | 276 +++++++++++++++--- .../Services/ICropperJsInterop.cs | 91 +++++- .../wwwroot/cropperJsInterop.js | 158 ++++++---- 9 files changed, 651 insertions(+), 246 deletions(-) diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs index 4ee8b62a..e5cc633d 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs @@ -56,7 +56,6 @@ public async Task Throw_Exception_Because_Of_Invalid_NumberAsync(float numberIma // arrange Faker faker = new(); CancellationToken cancellationToken = new(); - GetCroppedCanvasOptions getCroppedCanvasOptions = new Faker() .Generate(); string imageFormatType = faker.Random.Word(); @@ -80,6 +79,7 @@ await func .WithMessage($"The given number should be between 0 and 1 for indication the image quality, but found {numberImageQuality}. (Parameter 'number')"); _mockCropperJsInterop.Verify(c => c.GetCroppedCanvasDataURLAsync( + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), @@ -87,6 +87,46 @@ await func }); } + [Fact] + private void Should_Dispose_CropperComponent_After_Render() + { + // arrange + CancellationToken cancellationToken = new(); + + // act + IRenderedComponent cropperComponent = _testContext + .RenderComponent(); + + // assert + Guid cropperComponentId = (Guid)cropperComponent.Instance + .GetInstanceField("CropperComponentId"); + + cropperComponent.Instance.Dispose(); + + _mockCropperJsInterop.Verify(c => c.DisposeAsync(), Times.Once()); + _mockCropperJsInterop.Verify(c => c.DestroyAsync(cropperComponentId, cancellationToken), Times.Once()); + } + + [Fact] + private async Task Should_DisposeAsync_CropperComponent_After_Render_Async() + { + // arrange + CancellationToken cancellationToken = new(); + + // act + IRenderedComponent cropperComponent = _testContext + .RenderComponent(); + + // assert + Guid cropperComponentId = (Guid)cropperComponent.Instance + .GetInstanceField("CropperComponentId"); + + await cropperComponent.Instance.DisposeAsync(); + + _mockCropperJsInterop.Verify(c => c.DisposeAsync(), Times.Once()); + _mockCropperJsInterop.Verify(c => c.DestroyAsync(cropperComponentId, cancellationToken), Times.Once()); + } + [Fact] public async Task Should_Render_CropperComponent_SuccessfulAsync() { @@ -264,23 +304,24 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() onCropReadyEventHandler); _mockCropperJsInterop - .Setup(c => c.GetCanvasDataAsync(cancellationToken)) + .Setup(c => c.GetCanvasDataAsync(It.IsAny(), cancellationToken)) .ReturnsAsync(expectedCanvasData); _mockCropperJsInterop - .Setup(c => c.GetContainerDataAsync(cancellationToken)) + .Setup(c => c.GetContainerDataAsync(It.IsAny(), cancellationToken)) .ReturnsAsync(expectedContainerData); _mockCropperJsInterop - .Setup(c => c.GetCropBoxDataAsync(cancellationToken)) + .Setup(c => c.GetCropBoxDataAsync(It.IsAny(), cancellationToken)) .ReturnsAsync(expectedCropBoxData); _mockCropperJsInterop - .Setup(c => c.GetCroppedCanvasAsync(getCroppedCanvasOptions, cancellationToken)) + .Setup(c => c.GetCroppedCanvasAsync(It.IsAny(), getCroppedCanvasOptions, cancellationToken)) .ReturnsAsync(expectedCroppedCanvas); _mockCropperJsInterop .Setup(c => c.GetCroppedCanvasDataURLAsync( + It.IsAny(), getCroppedCanvasOptions, imageFormatType, numberImageQuality, @@ -288,11 +329,11 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() .ReturnsAsync(expectedCroppedCanvasDataURL); _mockCropperJsInterop - .Setup(c => c.GetDataAsync(isRounded, cancellationToken)) + .Setup(c => c.GetDataAsync(It.IsAny(), isRounded, cancellationToken)) .ReturnsAsync(expectedCropperData); _mockCropperJsInterop - .Setup(c => c.GetImageDataAsync(cancellationToken)) + .Setup(c => c.GetImageDataAsync(It.IsAny(), cancellationToken)) .ReturnsAsync(expectedImageData); _mockCropperJsInterop @@ -323,6 +364,8 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() IElement expectedElement = cropperComponent.Find($"img.{imageClass}"); ElementReference elementReference = (ElementReference)cropperComponent.Instance .GetInstanceField("ImageReference"); + Guid cropperComponentId = (Guid)cropperComponent.Instance + .GetInstanceField("CropperComponentId"); _mockCropperJsInterop.Verify(c => c.LoadModuleAsync(cancellationToken), Times.Once()); elementReference.Id.Should().NotBeNullOrEmpty(); @@ -335,6 +378,7 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() expectedElement.TriggerEvent("onload", progressEventArgs); countCallsOnLoadImageHandler.Should().Be(1); _mockCropperJsInterop.Verify(c => c.InitCropperAsync( + cropperComponentId, elementReference, options, It.IsAny>(), @@ -347,10 +391,10 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() await cropperComponent.InvokeAsync(async () => { cropperComponent.Instance.Clear(); - _mockCropperJsInterop.Verify(c => c.ClearAsync(cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.ClearAsync(cropperComponentId, cancellationToken), Times.Once()); cropperComponent.Instance.Crop(); - _mockCropperJsInterop.Verify(c => c.CropAsync(cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.CropAsync(cropperComponentId, cancellationToken), Times.Once()); cropperComponent.Instance.CropperIsCroped(cropEvent); countCallsOnCropEventHandler.Should().Be(1); @@ -368,44 +412,44 @@ await cropperComponent.InvokeAsync(async () => countCallsOnZoomEventHandler.Should().Be(1); cropperComponent.Instance.Destroy(); - _mockCropperJsInterop.Verify(c => c.DestroyAsync(cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.DestroyAsync(cropperComponentId, cancellationToken), Times.Once()); cropperComponent.Instance.Disable(); - _mockCropperJsInterop.Verify(c => c.DisableAsync(cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.DisableAsync(cropperComponentId, cancellationToken), Times.Once()); cropperComponent.Instance.Enable(); - _mockCropperJsInterop.Verify(c => c.EnableAsync(cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.EnableAsync(cropperComponentId, cancellationToken), Times.Once()); CanvasData canvasData = await cropperComponent.Instance.GetCanvasDataAsync(); expectedCanvasData.Should().BeEquivalentTo(canvasData); - _mockCropperJsInterop.Verify(c => c.GetCanvasDataAsync(cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.GetCanvasDataAsync(cropperComponentId, cancellationToken), Times.Once()); ContainerData containerData = await cropperComponent.Instance.GetContainerDataAsync(); expectedContainerData.Should().BeEquivalentTo(containerData); - _mockCropperJsInterop.Verify(c => c.GetContainerDataAsync(cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.GetContainerDataAsync(cropperComponentId, cancellationToken), Times.Once()); CropBoxData cropBoxData = await cropperComponent.Instance.GetCropBoxDataAsync(); expectedCropBoxData.Should().BeEquivalentTo(cropBoxData); - _mockCropperJsInterop.Verify(c => c.GetCropBoxDataAsync(cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.GetCropBoxDataAsync(cropperComponentId, cancellationToken), Times.Once()); object croppedCanvas = await cropperComponent.Instance.GetCroppedCanvasAsync(getCroppedCanvasOptions); expectedCroppedCanvas.Should().BeEquivalentTo(croppedCanvas); - _mockCropperJsInterop.Verify(c => c.GetCroppedCanvasAsync(getCroppedCanvasOptions, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.GetCroppedCanvasAsync(cropperComponentId, getCroppedCanvasOptions, cancellationToken), Times.Once()); string croppedCanvasDataURL = await cropperComponent.Instance.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions, imageFormatType, numberImageQuality); expectedCroppedCanvasDataURL.Should().BeEquivalentTo(croppedCanvasDataURL); - _mockCropperJsInterop.Verify(c => c.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions, imageFormatType, numberImageQuality, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.GetCroppedCanvasDataURLAsync(cropperComponentId, getCroppedCanvasOptions, imageFormatType, numberImageQuality, cancellationToken), Times.Once()); CropperData cropperData = await cropperComponent.Instance.GetDataAsync(isRounded); expectedCropperData.Should().BeEquivalentTo(cropperData); - _mockCropperJsInterop.Verify(c => c.GetDataAsync(isRounded, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.GetDataAsync(cropperComponentId, isRounded, cancellationToken), Times.Once()); ImageData imageData = await cropperComponent.Instance.GetImageDataAsync(); expectedImageData.Should().Be(imageData); - _mockCropperJsInterop.Verify(c => c.GetImageDataAsync(cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.GetImageDataAsync(cropperComponentId, cancellationToken), Times.Once()); await cropperComponent.Instance.ReplaceAsync(newUrlImage, hasSameSize); - _mockCropperJsInterop.Verify(c => c.ReplaceAsync(newUrlImage, hasSameSize, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.ReplaceAsync(cropperComponentId, newUrlImage, hasSameSize, cancellationToken), Times.Once()); string image = await cropperComponent.Instance.GetImageUsingStreamingAsync(imageFile, maxAllowedSize, cancellationToken); expectedImage.Should().Be(image); @@ -415,55 +459,60 @@ await cropperComponent.InvokeAsync(async () => countCallsOnCropReadyEventHandler.Should().Be(1); cropperComponent.Instance.Move(offsetX, offsetY); - _mockCropperJsInterop.Verify(c => c.MoveAsync(offsetX, offsetY, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.MoveAsync(cropperComponentId, offsetX, offsetY, cancellationToken), Times.Once()); cropperComponent.Instance.MoveTo(x, y); - _mockCropperJsInterop.Verify(c => c.MoveToAsync(x, y, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.MoveToAsync(cropperComponentId, x, y, cancellationToken), Times.Once()); cropperComponent.Instance.OnErrorLoadImage(errorEventArgs); countCallsOnErrorLoadImageHandler.Should().Be(2); cropperComponent.Instance.Reset(); - _mockCropperJsInterop.Verify(c => c.ResetAsync(cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.ResetAsync(cropperComponentId, cancellationToken), Times.Once()); await cropperComponent.Instance.RevokeObjectUrlAsync(url); _mockCropperJsInterop.Verify(c => c.RevokeObjectUrlAsync(url, cancellationToken), Times.Once()); cropperComponent.Instance.Rotate(degree); - _mockCropperJsInterop.Verify(c => c.RotateAsync(degree, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.RotateAsync(cropperComponentId, degree, cancellationToken), Times.Once()); cropperComponent.Instance.Scale(scaleX, scaleY); - _mockCropperJsInterop.Verify(c => c.ScaleAsync(scaleX, scaleY, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.ScaleAsync(cropperComponentId, scaleX, scaleY, cancellationToken), Times.Once()); cropperComponent.Instance.ScaleX(scaleX); - _mockCropperJsInterop.Verify(c => c.ScaleXAsync(scaleX, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.ScaleXAsync(cropperComponentId, scaleX, cancellationToken), Times.Once()); cropperComponent.Instance.ScaleY(scaleY); - _mockCropperJsInterop.Verify(c => c.ScaleYAsync(scaleY, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.ScaleYAsync(cropperComponentId, scaleY, cancellationToken), Times.Once()); cropperComponent.Instance.SetAspectRatio(aspectRatio); - _mockCropperJsInterop.Verify(c => c.SetAspectRatioAsync(aspectRatio, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.SetAspectRatioAsync(cropperComponentId, aspectRatio, cancellationToken), Times.Once()); cropperComponent.Instance.SetCanvasData(setCanvasDataOptions); - _mockCropperJsInterop.Verify(c => c.SetCanvasDataAsync(setCanvasDataOptions, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.SetCanvasDataAsync(cropperComponentId, setCanvasDataOptions, cancellationToken), Times.Once()); cropperComponent.Instance.SetCropBoxData(setCropBoxDataOptions); - _mockCropperJsInterop.Verify(c => c.SetCropBoxDataAsync(setCropBoxDataOptions, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.SetCropBoxDataAsync(cropperComponentId, setCropBoxDataOptions, cancellationToken), Times.Once()); cropperComponent.Instance.SetData(setDataOptions); - _mockCropperJsInterop.Verify(c => c.SetDataAsync(setDataOptions, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.SetDataAsync(cropperComponentId, setDataOptions, cancellationToken), Times.Once()); cropperComponent.Instance.SetDragMode(dragMode); - _mockCropperJsInterop.Verify(c => c.SetDragModeAsync(dragMode, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.SetDragModeAsync(cropperComponentId, dragMode, cancellationToken), Times.Once()); cropperComponent.Instance.Zoom(ratio); - _mockCropperJsInterop.Verify(c => c.ZoomAsync(ratio, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.ZoomAsync(cropperComponentId, ratio, cancellationToken), Times.Once()); cropperComponent.Instance.ZoomTo(ratio, pivotX, pivotY); - _mockCropperJsInterop.Verify(c => c.ZoomToAsync(ratio, pivotX, pivotY, cancellationToken), Times.Once()); + _mockCropperJsInterop.Verify(c => c.ZoomToAsync(cropperComponentId, ratio, pivotX, pivotY, cancellationToken), Times.Once()); await cropperComponent.Instance.DisposeAsync(); _mockCropperJsInterop.Verify(c => c.DisposeAsync(), Times.Once()); + _mockCropperJsInterop.Verify(c => c.DestroyAsync(cropperComponentId, cancellationToken), Times.Exactly(2)); + + cropperComponent.Instance.Dispose(); + _mockCropperJsInterop.Verify(c => c.DisposeAsync(), Times.Exactly(2)); + _mockCropperJsInterop.Verify(c => c.DestroyAsync(cropperComponentId, cancellationToken), Times.Exactly(3)); }); } @@ -515,6 +564,7 @@ public void Should_Render_CropperComponent_With_ErrorLoadImage_Parameter() expectedElement.GetAttribute("blazor:elementreference").Should().BeNullOrEmpty(); _mockCropperJsInterop.Verify(c => c.InitCropperAsync( + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), @@ -573,6 +623,7 @@ public void Should_Not_Render_CropperComponent_With_IsNotAvaibleInitCropper_Para expectedElement.GetAttribute("blazor:elementreference").Should().BeNullOrEmpty(); _mockCropperJsInterop.Verify(c => c.InitCropperAsync( + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/ServiceCollectionExtensions_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/ServiceCollectionExtensions_Should.cs index 7536026c..7f923e18 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/ServiceCollectionExtensions_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Extensions/ServiceCollectionExtensions_Should.cs @@ -23,7 +23,7 @@ public void Verify_Cropper_Service_Is_Registered(CropperJsInteropOptions? croppe // assert ServiceCollectionMock = new(ServiceCollection); ServiceCollectionMock.ContainsSingletonService(); - ServiceCollectionMock.TryContainsTransientService(); + ServiceCollectionMock.TryContainsScopedService(); } public static IEnumerable TestData_AddCropper_Service() diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/CropperJsInterop_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/CropperJsInterop_Should.cs index 55d90ea4..a9c6f235 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/CropperJsInterop_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Services/CropperJsInterop_Should.cs @@ -46,6 +46,7 @@ public CropperJsInterop_Should() public async Task Verify_InitCropperAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); ElementReference elementReference = new(Guid.NewGuid().ToString()); Options options = new Faker().Generate(); ICropperComponentBase cropperComponentBase = new Mock().Object; @@ -54,6 +55,7 @@ public async Task Verify_InitCropperAsync() object[] expectedInitCropperMethodArguments = new object[] { + cropperComponentId, elementReference, options, refToCropperComponentBase @@ -67,99 +69,110 @@ public async Task Verify_InitCropperAsync() .SetVoidResult(); // act - await _cropperJsInterop.InitCropperAsync(elementReference, options, refToCropperComponentBase); + await _cropperJsInterop.InitCropperAsync(cropperComponentId, elementReference, options, refToCropperComponentBase); } [Fact] public async Task Verify_ClearAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); + _testContext.JSInterop - .SetupVoid("cropper.clear") + .SetupVoid("cropper.clear", cropperComponentId) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.ClearAsync(); + await _cropperJsInterop.ClearAsync(cropperComponentId); } [Fact] public async Task Verify_CropAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); + _testContext.JSInterop - .SetupVoid("cropper.crop") + .SetupVoid("cropper.crop", cropperComponentId) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.CropAsync(); + await _cropperJsInterop.CropAsync(cropperComponentId); } [Fact] public async Task Verify_DestroyAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); + _testContext.JSInterop - .SetupVoid("cropper.destroy") + .SetupVoid("cropper.destroy", cropperComponentId) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.DestroyAsync(); + await _cropperJsInterop.DestroyAsync(cropperComponentId); } [Fact] public async Task Verify_DisableAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); + _testContext.JSInterop - .SetupVoid("cropper.disable") + .SetupVoid("cropper.disable", cropperComponentId) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.DisableAsync(); + await _cropperJsInterop.DisableAsync(cropperComponentId); } [Fact] public async Task Verify_EnableAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); + _testContext.JSInterop - .SetupVoid("cropper.enable") + .SetupVoid("cropper.enable", cropperComponentId) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.EnableAsync(); + await _cropperJsInterop.EnableAsync(cropperComponentId); } [Fact] public async Task Verify_GetCanvasDataAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); CanvasData expectedCanvasData = new Faker(); _testContext.JSInterop - .Setup("cropper.getCanvasData") + .Setup("cropper.getCanvasData", cropperComponentId) .SetResult(expectedCanvasData); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - CanvasData canvasData = await _cropperJsInterop.GetCanvasDataAsync(); + CanvasData canvasData = await _cropperJsInterop.GetCanvasDataAsync(cropperComponentId); // assert expectedCanvasData.Should().BeEquivalentTo(canvasData); @@ -169,17 +182,18 @@ public async Task Verify_GetCanvasDataAsync() public async Task Verify_GetContainerDataAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); ContainerData expectedContainerData = new Faker(); _testContext.JSInterop - .Setup("cropper.getContainerData") + .Setup("cropper.getContainerData", cropperComponentId) .SetResult(expectedContainerData); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - ContainerData containerData = await _cropperJsInterop.GetContainerDataAsync(); + ContainerData containerData = await _cropperJsInterop.GetContainerDataAsync(cropperComponentId); // assert expectedContainerData.Should().BeEquivalentTo(containerData); @@ -189,17 +203,18 @@ public async Task Verify_GetContainerDataAsync() public async Task Verify_GetCropBoxDataAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); CropBoxData expectedCropBoxData = new Faker(); _testContext.JSInterop - .Setup("cropper.getCropBoxData") + .Setup("cropper.getCropBoxData", cropperComponentId) .SetResult(expectedCropBoxData); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - CropBoxData cropBoxData = await _cropperJsInterop.GetCropBoxDataAsync(); + CropBoxData cropBoxData = await _cropperJsInterop.GetCropBoxDataAsync(cropperComponentId); // assert expectedCropBoxData.Should().BeEquivalentTo(cropBoxData); @@ -209,6 +224,7 @@ public async Task Verify_GetCropBoxDataAsync() public async Task Verify_GetCroppedCanvasAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); Mock mockIJSObjectReference = new(); CroppedCanvas expectedCroppedCanvas = new Faker() @@ -216,14 +232,16 @@ public async Task Verify_GetCroppedCanvasAsync() GetCroppedCanvasOptions getCroppedCanvasOptions = new Faker(); _testContext.JSInterop - .SetupModule("cropper.getCroppedCanvas", invocation => invocation.Arguments?[0] is GetCroppedCanvasOptions argumentGetCroppedCanvasOptions - && argumentGetCroppedCanvasOptions.Equals(getCroppedCanvasOptions)); + .SetupModule("cropper.getCroppedCanvas", invocation => invocation.Arguments?[0] is Guid guid + && guid.Equals(cropperComponentId) + && invocation.Arguments?[1] is GetCroppedCanvasOptions argumentGetCroppedCanvasOptions + && argumentGetCroppedCanvasOptions.Equals(getCroppedCanvasOptions)); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - CroppedCanvas croppedCanvas = await _cropperJsInterop.GetCroppedCanvasAsync(getCroppedCanvasOptions); + CroppedCanvas croppedCanvas = await _cropperJsInterop.GetCroppedCanvasAsync(cropperComponentId, getCroppedCanvasOptions); // assert expectedCroppedCanvas.Should().BeEquivalentTo(croppedCanvas); @@ -233,20 +251,21 @@ public async Task Verify_GetCroppedCanvasAsync() public async Task Verify_GetCroppedCanvasDataURL_By_TypeAndNumber_Async() { // arrange + Guid cropperComponentId = Guid.NewGuid(); string expectedCroppedCanvasURL = _faker.Random.Word(); string type = _faker.Random.Word(); float number = _faker.Random.Float(); GetCroppedCanvasOptions getCroppedCanvasOptions = new Faker(); _testContext.JSInterop - .Setup("cropper.getCroppedCanvasDataURL", getCroppedCanvasOptions, type, number) + .Setup("cropper.getCroppedCanvasDataURL", cropperComponentId, getCroppedCanvasOptions, type, number) .SetResult(expectedCroppedCanvasURL); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - string croppedCanvasURL = await _cropperJsInterop.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions, type, number); + string croppedCanvasURL = await _cropperJsInterop.GetCroppedCanvasDataURLAsync(cropperComponentId, getCroppedCanvasOptions, type, number); // assert expectedCroppedCanvasURL.Should().BeEquivalentTo(croppedCanvasURL); @@ -256,18 +275,19 @@ public async Task Verify_GetCroppedCanvasDataURL_By_TypeAndNumber_Async() public async Task Verify_GetDataAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); CropperData expectedCropperData = new Faker(); bool rounded = _faker.Random.Bool(); _testContext.JSInterop - .Setup("cropper.getData", rounded) + .Setup("cropper.getData", cropperComponentId, rounded) .SetResult(expectedCropperData); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - CropperData cropperData = await _cropperJsInterop.GetDataAsync(rounded); + CropperData cropperData = await _cropperJsInterop.GetDataAsync(cropperComponentId, rounded); // assert expectedCropperData.Should().BeEquivalentTo(cropperData); @@ -277,17 +297,18 @@ public async Task Verify_GetDataAsync() public async Task Verify_GetImageDataAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); ImageData expectedImageData = new Faker(); _testContext.JSInterop - .Setup("cropper.getImageData") + .Setup("cropper.getImageData", cropperComponentId) .SetResult(expectedImageData); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - ImageData imageData = await _cropperJsInterop.GetImageDataAsync(); + ImageData imageData = await _cropperJsInterop.GetImageDataAsync(cropperComponentId); // assert expectedImageData.Should().BeEquivalentTo(imageData); @@ -340,36 +361,38 @@ bool VerifyStreamArgument(JSRuntimeInvocation jSRuntimeInvocation) public async Task Verify_MoveAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); decimal offsetX = _faker.Random.Decimal(); decimal? offsetY = _faker.Random.Decimal(); _testContext.JSInterop - .SetupVoid("cropper.move", offsetX, offsetY) + .SetupVoid("cropper.move", cropperComponentId, offsetX, offsetY) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.MoveAsync(offsetX, offsetY); + await _cropperJsInterop.MoveAsync(cropperComponentId, offsetX, offsetY); } [Fact] public async Task Verify_MoveToAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); decimal x = _faker.Random.Decimal(); decimal? y = _faker.Random.Decimal(); _testContext.JSInterop - .SetupVoid("cropper.moveTo", x, y) + .SetupVoid("cropper.moveTo", cropperComponentId, x, y) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.MoveToAsync(x, y); + await _cropperJsInterop.MoveToAsync(cropperComponentId, x, y); } [Fact] @@ -391,33 +414,35 @@ public async Task Verify_NoConflictAsync() public async Task Verify_ReplaceAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); string url = _faker.Random.String(); bool onlyColorChanged = _faker.Random.Bool(); _testContext.JSInterop - .SetupVoid("cropper.replace", url, onlyColorChanged) + .SetupVoid("cropper.replace", cropperComponentId, url, onlyColorChanged) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.ReplaceAsync(url, onlyColorChanged); + await _cropperJsInterop.ReplaceAsync(cropperComponentId, url, onlyColorChanged); } [Fact] public async Task Verify_ResetAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); _testContext.JSInterop - .SetupVoid("cropper.reset") + .SetupVoid("cropper.reset", cropperComponentId) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.ResetAsync(); + await _cropperJsInterop.ResetAsync(cropperComponentId); } [Fact] @@ -441,154 +466,163 @@ public async Task Verify_RevokeObjectUrlAsync() public async Task Verify_RotateAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); decimal degree = _faker.Random.Decimal(); _testContext.JSInterop - .SetupVoid("cropper.rotate", degree) + .SetupVoid("cropper.rotate", cropperComponentId, degree) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.RotateAsync(degree); + await _cropperJsInterop.RotateAsync(cropperComponentId, degree); } [Fact] public async Task Verify_RotateToAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); decimal degree = _faker.Random.Decimal(); _testContext.JSInterop - .SetupVoid("cropper.rotateTo", degree) + .SetupVoid("cropper.rotateTo", cropperComponentId, degree) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.RotateToAsync(degree); + await _cropperJsInterop.RotateToAsync(cropperComponentId, degree); } [Fact] public async Task Verify_ScaleAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); decimal scaleX = _faker.Random.Decimal(); decimal scaleY = _faker.Random.Decimal(); _testContext.JSInterop - .SetupVoid("cropper.scale", scaleX, scaleY) + .SetupVoid("cropper.scale", cropperComponentId, scaleX, scaleY) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.ScaleAsync(scaleX, scaleY); + await _cropperJsInterop.ScaleAsync(cropperComponentId, scaleX, scaleY); } [Fact] public async Task Verify_ScaleXAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); decimal scaleX = _faker.Random.Decimal(); _testContext.JSInterop - .SetupVoid("cropper.scaleX", scaleX) + .SetupVoid("cropper.scaleX", cropperComponentId, scaleX) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.ScaleXAsync(scaleX); + await _cropperJsInterop.ScaleXAsync(cropperComponentId, scaleX); } [Fact] public async Task Verify_ScaleYAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); decimal scaleY = _faker.Random.Decimal(); _testContext.JSInterop - .SetupVoid("cropper.scaleY", scaleY) + .SetupVoid("cropper.scaleY", cropperComponentId, scaleY) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.ScaleYAsync(scaleY); + await _cropperJsInterop.ScaleYAsync(cropperComponentId, scaleY); } [Fact] public async Task Verify_SetAspectRatioAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); decimal aspectRatio = _faker.Random.Decimal(); _testContext.JSInterop - .SetupVoid("cropper.setAspectRatio", aspectRatio) + .SetupVoid("cropper.setAspectRatio", cropperComponentId, aspectRatio) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.SetAspectRatioAsync(aspectRatio); + await _cropperJsInterop.SetAspectRatioAsync(cropperComponentId, aspectRatio); } [Fact] public async Task Verify_SetCanvasDataAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); SetCanvasDataOptions setCanvasDataOptions = new Faker(); _testContext.JSInterop - .SetupVoid("cropper.setCanvasData", setCanvasDataOptions) + .SetupVoid("cropper.setCanvasData", cropperComponentId, setCanvasDataOptions) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.SetCanvasDataAsync(setCanvasDataOptions); + await _cropperJsInterop.SetCanvasDataAsync(cropperComponentId, setCanvasDataOptions); } [Fact] public async Task Verify_SetCropBoxDataAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); SetCropBoxDataOptions setCropBoxDataOptions = new Faker(); _testContext.JSInterop - .SetupVoid("cropper.setCropBoxData", setCropBoxDataOptions) + .SetupVoid("cropper.setCropBoxData", cropperComponentId, setCropBoxDataOptions) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.SetCropBoxDataAsync(setCropBoxDataOptions); + await _cropperJsInterop.SetCropBoxDataAsync(cropperComponentId, setCropBoxDataOptions); } [Fact] public async Task Verify_SetDataAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); SetDataOptions setDataOptions = new Faker(); _testContext.JSInterop - .SetupVoid("cropper.setData", setDataOptions) + .SetupVoid("cropper.setData", cropperComponentId, setDataOptions) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.SetDataAsync(setDataOptions); + await _cropperJsInterop.SetDataAsync(cropperComponentId, setDataOptions); } [Fact] @@ -612,53 +646,56 @@ public async Task Verify_SetDefaultsAsync() public async Task Verify_SetDragModeAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); DragMode dragMode = _faker.Random.Enum(); _testContext.JSInterop - .SetupVoid("cropper.setDragMode", dragMode.ToEnumString()) + .SetupVoid("cropper.setDragMode", cropperComponentId, dragMode.ToEnumString()) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.SetDragModeAsync(dragMode); + await _cropperJsInterop.SetDragModeAsync(cropperComponentId, dragMode); } [Fact] public async Task Verify_ZoomAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); decimal ratio = _faker.Random.Decimal(); _testContext.JSInterop - .SetupVoid("cropper.zoom", ratio) + .SetupVoid("cropper.zoom", cropperComponentId, ratio) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.ZoomAsync(ratio); + await _cropperJsInterop.ZoomAsync(cropperComponentId, ratio); } [Fact] public async Task Verify_ZoomToAsync() { // arrange + Guid cropperComponentId = Guid.NewGuid(); decimal ratio = _faker.Random.Decimal(); decimal pivotX = _faker.Random.Decimal(); decimal pivotY = _faker.Random.Decimal(); _testContext.JSInterop - .SetupVoid("cropper.zoomTo", ratio, pivotX, pivotY) + .SetupVoid("cropper.zoomTo", cropperComponentId, ratio, pivotX, pivotY) .SetVoidResult(); // assert VerifyLoadCropperModule(DefaultPathToCropperModule); // act - await _cropperJsInterop.ZoomToAsync(ratio, pivotX, pivotY); + await _cropperJsInterop.ZoomToAsync(cropperComponentId, ratio, pivotX, pivotY); } [Fact] diff --git a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs index ea97b3a4..a6f59aa1 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Threading; using System.Threading.Tasks; using Cropper.Blazor.Base; @@ -24,12 +23,20 @@ namespace Cropper.Blazor.Components /// /// The cropper component. /// - public partial class CropperComponent : ICropperComponentBase, IAsyncDisposable + public partial class CropperComponent : ICropperComponentBase, IAsyncDisposable, IDisposable { [Inject] ICropperJsInterop CropperJsIntertop { get; set; } = null!; + /// + /// Gets a reference to the img HTML element rendered by the component. + /// private ElementReference ImageReference; + /// + /// The unique identifier of the cropper component. + /// + private Guid CropperComponentId; + /// /// The options for cropping. Check out the available . /// @@ -153,6 +160,14 @@ protected override async Task OnAfterRenderAsync(bool firstRender) await base.OnAfterRenderAsync(firstRender); } + /// + /// Called when initialized. + /// + protected override void OnInitialized() + { + CropperComponentId = Guid.NewGuid(); + } + /// /// This event is fired when the image is loaded. /// @@ -184,7 +199,7 @@ public void OnErrorLoadImage(ErrorEventArgs errorEventArgs) public void InitCropper(CancellationToken cancellationToken = default) { ICropperComponentBase cropperComponentBase = this; - CropperJsIntertop!.InitCropperAsync(ImageReference, Options!, DotNetObjectReference.Create(cropperComponentBase), cancellationToken); + CropperJsIntertop!.InitCropperAsync(CropperComponentId, ImageReference, Options!, DotNetObjectReference.Create(cropperComponentBase), cancellationToken); OnLoadImageEvent?.Invoke(); } @@ -255,7 +270,7 @@ public void IsReady(JSEventData jSEventData) /// The used to propagate notifications that the operation should be canceled. public void SetDragMode(DragMode dragMode, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetDragModeAsync(dragMode, cancellationToken); + CropperJsIntertop?.SetDragModeAsync(CropperComponentId, dragMode, cancellationToken); } /// @@ -269,7 +284,7 @@ public void SetDragMode(DragMode dragMode, CancellationToken cancellationToken = /// The used to propagate notifications that the operation should be canceled. public void Zoom(decimal ratio, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ZoomAsync(ratio, cancellationToken); + CropperJsIntertop?.ZoomAsync(CropperComponentId, ratio, cancellationToken); } /// @@ -281,7 +296,7 @@ public void Zoom(decimal ratio, CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void ZoomTo(decimal ratio, decimal pivotX, decimal pivotY, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ZoomToAsync(ratio, pivotX, pivotY, cancellationToken); + CropperJsIntertop?.ZoomToAsync(CropperComponentId, ratio, pivotX, pivotY, cancellationToken); } /// @@ -292,7 +307,7 @@ public void ZoomTo(decimal ratio, decimal pivotX, decimal pivotY, CancellationTo /// The used to propagate notifications that the operation should be canceled. public void Move(decimal offsetX, decimal? offsetY, CancellationToken cancellationToken = default) { - CropperJsIntertop?.MoveAsync(offsetX, offsetY, cancellationToken); + CropperJsIntertop?.MoveAsync(CropperComponentId, offsetX, offsetY, cancellationToken); } /// @@ -303,7 +318,7 @@ public void Move(decimal offsetX, decimal? offsetY, CancellationToken cancellati /// The used to propagate notifications that the operation should be canceled. public void MoveTo(decimal x, decimal? y, CancellationToken cancellationToken = default) { - CropperJsIntertop?.MoveToAsync(x, y, cancellationToken); + CropperJsIntertop?.MoveToAsync(CropperComponentId, x, y, cancellationToken); } /// @@ -317,7 +332,7 @@ public void MoveTo(decimal x, decimal? y, CancellationToken cancellationToken = /// The used to propagate notifications that the operation should be canceled. public void Rotate(decimal degree, CancellationToken cancellationToken = default) { - CropperJsIntertop?.RotateAsync(degree, cancellationToken); + CropperJsIntertop?.RotateAsync(CropperComponentId, degree, cancellationToken); } /// @@ -331,7 +346,7 @@ public void Rotate(decimal degree, CancellationToken cancellationToken = default /// The used to propagate notifications that the operation should be canceled. public void ScaleX(decimal scaleX, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ScaleXAsync(scaleX, cancellationToken); + CropperJsIntertop?.ScaleXAsync(CropperComponentId, scaleX, cancellationToken); } /// @@ -345,7 +360,7 @@ public void ScaleX(decimal scaleX, CancellationToken cancellationToken = default /// The used to propagate notifications that the operation should be canceled. public void ScaleY(decimal scaleY, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ScaleYAsync(scaleY, cancellationToken); + CropperJsIntertop?.ScaleYAsync(CropperComponentId, scaleY, cancellationToken); } /// @@ -364,7 +379,7 @@ public void ScaleY(decimal scaleY, CancellationToken cancellationToken = default /// The used to propagate notifications that the operation should be canceled. public void Scale(decimal scaleX, decimal scaleY, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ScaleAsync(scaleX, scaleY, cancellationToken); + CropperJsIntertop?.ScaleAsync(CropperComponentId, scaleX, scaleY, cancellationToken); } /// @@ -373,7 +388,7 @@ public void Scale(decimal scaleX, decimal scaleY, CancellationToken cancellation /// The used to propagate notifications that the operation should be canceled. public void Crop(CancellationToken cancellationToken = default) { - CropperJsIntertop?.CropAsync(cancellationToken); + CropperJsIntertop?.CropAsync(CropperComponentId, cancellationToken); } /// @@ -382,7 +397,7 @@ public void Crop(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Clear(CancellationToken cancellationToken = default) { - CropperJsIntertop?.ClearAsync(cancellationToken); + CropperJsIntertop?.ClearAsync(CropperComponentId, cancellationToken); } /// @@ -391,7 +406,7 @@ public void Clear(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Enable(CancellationToken cancellationToken = default) { - CropperJsIntertop?.EnableAsync(cancellationToken); + CropperJsIntertop?.EnableAsync(CropperComponentId, cancellationToken); } /// @@ -400,7 +415,7 @@ public void Enable(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Disable(CancellationToken cancellationToken = default) { - CropperJsIntertop?.DisableAsync(cancellationToken); + CropperJsIntertop?.DisableAsync(CropperComponentId, cancellationToken); } /// @@ -409,7 +424,7 @@ public void Disable(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Reset(CancellationToken cancellationToken = default) { - CropperJsIntertop?.ResetAsync(cancellationToken); + CropperJsIntertop?.ResetAsync(CropperComponentId, cancellationToken); } /// @@ -418,7 +433,7 @@ public void Reset(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Destroy(CancellationToken cancellationToken = default) { - CropperJsIntertop?.DestroyAsync(cancellationToken); + CropperJsIntertop?.DestroyAsync(CropperComponentId, cancellationToken); } /// @@ -428,7 +443,7 @@ public void Destroy(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void SetAspectRatio(decimal aspectRatio, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetAspectRatioAsync(aspectRatio, cancellationToken); + CropperJsIntertop?.SetAspectRatioAsync(CropperComponentId, aspectRatio, cancellationToken); } /// @@ -438,7 +453,7 @@ public void SetAspectRatio(decimal aspectRatio, CancellationToken cancellationTo /// The used to propagate notifications that the operation should be canceled. public void SetCropBoxData(SetCropBoxDataOptions cropBoxDataOptions, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetCropBoxDataAsync(cropBoxDataOptions, cancellationToken); + CropperJsIntertop?.SetCropBoxDataAsync(CropperComponentId, cropBoxDataOptions, cancellationToken); } /// @@ -448,7 +463,7 @@ public void SetCropBoxData(SetCropBoxDataOptions cropBoxDataOptions, Cancellatio /// The used to propagate notifications that the operation should be canceled. public void SetData(SetDataOptions setDataOptions, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetDataAsync(setDataOptions, cancellationToken); + CropperJsIntertop?.SetDataAsync(CropperComponentId, setDataOptions, cancellationToken); } /// @@ -458,7 +473,7 @@ public void SetData(SetDataOptions setDataOptions, CancellationToken cancellatio /// The used to propagate notifications that the operation should be canceled. public void SetCanvasData(SetCanvasDataOptions setCanvasDataOptions, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetCanvasDataAsync(setCanvasDataOptions, cancellationToken); + CropperJsIntertop?.SetCanvasDataAsync(CropperComponentId, setCanvasDataOptions, cancellationToken); } /// @@ -468,7 +483,7 @@ public void SetCanvasData(SetCanvasDataOptions setCanvasDataOptions, Cancellatio /// A representing cropper box options asynchronous operation. public async ValueTask GetCropBoxDataAsync(CancellationToken cancellationToken = default) { - return await CropperJsIntertop!.GetCropBoxDataAsync(cancellationToken); + return await CropperJsIntertop!.GetCropBoxDataAsync(CropperComponentId, cancellationToken); } /// @@ -479,7 +494,7 @@ public async ValueTask GetCropBoxDataAsync(CancellationToken cancel /// A representing cropper options asynchronous operation. public async ValueTask GetDataAsync(bool rounded, CancellationToken cancellationToken = default) { - return await CropperJsIntertop!.GetDataAsync(rounded, cancellationToken); + return await CropperJsIntertop!.GetDataAsync(CropperComponentId, rounded, cancellationToken); } /// @@ -489,7 +504,7 @@ public async ValueTask GetDataAsync(bool rounded, CancellationToken /// A representing container options asynchronous operation. public async ValueTask GetContainerDataAsync(CancellationToken cancellationToken = default) { - return await CropperJsIntertop!.GetContainerDataAsync(cancellationToken); + return await CropperJsIntertop!.GetContainerDataAsync(CropperComponentId, cancellationToken); } /// @@ -504,7 +519,7 @@ public async ValueTask ReplaceAsync( bool hasSameSize = true, CancellationToken cancellationToken = default) { - await CropperJsIntertop!.ReplaceAsync(url, hasSameSize, cancellationToken); + await CropperJsIntertop!.ReplaceAsync(CropperComponentId, url, hasSameSize, cancellationToken); } /// @@ -514,7 +529,7 @@ public async ValueTask ReplaceAsync( /// A representing image options asynchronous operation. public async ValueTask GetImageDataAsync(CancellationToken cancellationToken = default) { - return await CropperJsIntertop!.GetImageDataAsync(cancellationToken); + return await CropperJsIntertop!.GetImageDataAsync(CropperComponentId, cancellationToken); } /// @@ -524,7 +539,7 @@ public async ValueTask GetImageDataAsync(CancellationToken cancellati /// A representing canvas options asynchronous operation. public async ValueTask GetCanvasDataAsync(CancellationToken cancellationToken = default) { - return await CropperJsIntertop!.GetCanvasDataAsync(cancellationToken); + return await CropperJsIntertop!.GetCanvasDataAsync(CropperComponentId, cancellationToken); } /// @@ -563,7 +578,7 @@ public async ValueTask RevokeObjectUrlAsync(string url, CancellationToken cancel /// A representing canvas drawn the cropped image asynchronous operation. public async ValueTask GetCroppedCanvasAsync(GetCroppedCanvasOptions getCroppedCanvasOptions, CancellationToken cancellationToken = default) { - return await CropperJsIntertop!.GetCroppedCanvasAsync(getCroppedCanvasOptions, cancellationToken); + return await CropperJsIntertop!.GetCroppedCanvasAsync(CropperComponentId, getCroppedCanvasOptions, cancellationToken); } /// @@ -582,15 +597,15 @@ public async ValueTask GetCroppedCanvasDataURLAsync( float number = 1, CancellationToken cancellationToken = default) { - return number switch { < 0 or > 1 => throw new ArgumentException($"The given number should be between 0 and 1 for indication the image quality, but found {number}.", nameof(number)), _ => await CropperJsIntertop!.GetCroppedCanvasDataURLAsync( - getCroppedCanvasOptions, - type, - number, - cancellationToken) + CropperComponentId, + getCroppedCanvasOptions, + type, + number, + cancellationToken) }; } @@ -600,7 +615,16 @@ public async ValueTask GetCroppedCanvasDataURLAsync( /// A representing any asynchronous operation. public async ValueTask DisposeAsync() { + Destroy(); await CropperJsIntertop!.DisposeAsync(); } + + /// + /// Called to dispose this instance and internal services. + /// + public void Dispose() + { + DisposeAsync(); + } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj index ecb17ad9..617ed77f 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj @@ -14,7 +14,7 @@ - 1.2.3 + 1.2.4 LICENSE NuGet.png Cropper.Blazor diff --git a/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs b/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs index e8db01df..313162a0 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs @@ -11,7 +11,7 @@ namespace Cropper.Blazor.Extensions public static class ServiceCollectionExtensions { /// - /// Adds a see as a Transient instance. + /// Adds a see as a Scoped instance. /// /// Continues the chain. /// Continues the chain. @@ -21,7 +21,7 @@ public static IServiceCollection AddCropper(this IServiceCollection services, Cr { services.AddSingleton(services => cropperJsInteropOptions ?? new CropperJsInteropOptions()); - services.TryAddTransient(); + services.TryAddScoped(); return services; } diff --git a/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs b/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs index fdb30e4b..6a179b31 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Services/CropperJsInterop.cs @@ -54,6 +54,10 @@ public async Task LoadModuleAsync(CancellationToken cancellationToken = default) "import", cancellationToken, globalPathToCropperModule); } + /// + /// Finds path to the cropper module. + /// + /// The path to the cropper module. private string GetGlobalPathToCropperModule() { if (_cropperJsInteropOptions.IsActiveGlobalPath) @@ -72,12 +76,14 @@ private string GetGlobalPathToCropperModule() /// /// Initializes cropper. /// + /// The identifier of the cropper component. /// Reference to img html-DOM /// Cropper options /// Reference to base cropper component. Default equal to 'this' object. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask InitCropperAsync( + [NotNull] Guid cropperComponentId, [NotNull] ElementReference image, [NotNull] Options options, [NotNull] DotNetObjectReference cropperComponentBase, @@ -91,6 +97,7 @@ public async ValueTask InitCropperAsync( await _jsRuntime!.InvokeVoidAsync( "cropper.initCropper", cancellationToken, + cropperComponentId, image, options, cropperComponentBase); @@ -99,130 +106,180 @@ public async ValueTask InitCropperAsync( /// /// Clear the crop box. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - public async ValueTask ClearAsync(CancellationToken cancellationToken = default) + public async ValueTask ClearAsync( + [NotNull] Guid cropperComponentId, + CancellationToken cancellationToken = default) { if (Module is null) { await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.clear", cancellationToken); + await _jsRuntime!.InvokeVoidAsync( + "cropper.clear", + cancellationToken, + cropperComponentId); } /// /// Show the crop box manually. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - public async ValueTask CropAsync(CancellationToken cancellationToken = default) + public async ValueTask CropAsync( + [NotNull] Guid cropperComponentId, + CancellationToken cancellationToken = default) { if (Module is null) { await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.crop", cancellationToken); + await _jsRuntime!.InvokeVoidAsync( + "cropper.crop", + cancellationToken, + cropperComponentId); } /// /// Destroy the cropper and remove the instance from the image. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - public async ValueTask DestroyAsync(CancellationToken cancellationToken = default) + public async ValueTask DestroyAsync( + [NotNull] Guid cropperComponentId, + CancellationToken cancellationToken = default) { if (Module is null) { await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.destroy", cancellationToken); + await _jsRuntime!.InvokeVoidAsync( + "cropper.destroy", + cancellationToken, + cropperComponentId); } /// /// Disable (freeze) the cropper. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - public async ValueTask DisableAsync(CancellationToken cancellationToken = default) + public async ValueTask DisableAsync( + [NotNull] Guid cropperComponentId, + CancellationToken cancellationToken = default) { if (Module is null) { await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.disable", cancellationToken); + await _jsRuntime!.InvokeVoidAsync( + "cropper.disable", + cancellationToken, + cropperComponentId); } /// /// Enable (unfreeze) the cropper. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - public async ValueTask EnableAsync(CancellationToken cancellationToken = default) + public async ValueTask EnableAsync( + [NotNull] Guid cropperComponentId, + CancellationToken cancellationToken = default) { if (Module is null) { await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.enable", cancellationToken); + await _jsRuntime!.InvokeVoidAsync( + "cropper.enable", + cancellationToken, + cropperComponentId); } /// /// Get the canvas position and size data. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing result canvas data asynchronous operation. - public async ValueTask GetCanvasDataAsync(CancellationToken cancellationToken = default) + public async ValueTask GetCanvasDataAsync( + [NotNull] Guid cropperComponentId, + CancellationToken cancellationToken = default) { if (Module is null) { await LoadModuleAsync(cancellationToken); } - return await _jsRuntime!.InvokeAsync("cropper.getCanvasData", cancellationToken); + return await _jsRuntime!.InvokeAsync( + "cropper.getCanvasData", + cancellationToken, + cropperComponentId); } /// /// Get the container size data. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing result container data asynchronous operation. - public async ValueTask GetContainerDataAsync(CancellationToken cancellationToken = default) + public async ValueTask GetContainerDataAsync( + [NotNull] Guid cropperComponentId, + CancellationToken cancellationToken = default) { if (Module is null) { await LoadModuleAsync(cancellationToken); } - return await _jsRuntime!.InvokeAsync("cropper.getContainerData", cancellationToken); + return await _jsRuntime!.InvokeAsync( + "cropper.getContainerData", + cancellationToken, + cropperComponentId); } /// /// Get the crop box position and size data. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing result crop box data asynchronous operation. - public async ValueTask GetCropBoxDataAsync(CancellationToken cancellationToken = default) + public async ValueTask GetCropBoxDataAsync( + [NotNull] Guid cropperComponentId, + CancellationToken cancellationToken = default) { if (Module is null) { await LoadModuleAsync(cancellationToken); } - return await _jsRuntime!.InvokeAsync("cropper.getCropBoxData", cancellationToken); + return await _jsRuntime!.InvokeAsync( + "cropper.getCropBoxData", + cancellationToken, + cropperComponentId); } /// /// Get a canvas drawn the cropped image. /// + /// The identifier of the cropper component. /// The config options. /// The used to propagate notifications that the operation should be canceled. /// A representing result canvas asynchronous operation. public async ValueTask GetCroppedCanvasAsync( + [NotNull] Guid cropperComponentId, GetCroppedCanvasOptions getCroppedCanvasOptions, CancellationToken cancellationToken = default) { @@ -231,7 +288,11 @@ public async ValueTask GetCroppedCanvasAsync( await LoadModuleAsync(cancellationToken); } - IJSObjectReference jSCanvas = await _jsRuntime!.InvokeAsync("cropper.getCroppedCanvas", cancellationToken, getCroppedCanvasOptions); + IJSObjectReference jSCanvas = await _jsRuntime!.InvokeAsync( + "cropper.getCroppedCanvas", + cancellationToken, + cropperComponentId, + getCroppedCanvasOptions); return new CroppedCanvas(jSCanvas); } @@ -239,6 +300,7 @@ public async ValueTask GetCroppedCanvasAsync( /// /// Get a canvas drawn the cropped image. /// + /// The identifier of the cropper component. /// The config options. /// A string indicating the image format. The default type is image/png; this image format will be also used if the specified type is not supported. /// A number between 0 and 1 indicating the image quality to be used when creating images using file formats that support lossy compression (such as image/jpeg or image/webp). A user agent will use its default quality value if this option is not specified, or if the number is outside the allowed range. @@ -247,6 +309,7 @@ public async ValueTask GetCroppedCanvasAsync( /// The used to propagate notifications that the operation should be canceled. /// A representing URL result canvas asynchronous operation. public async ValueTask GetCroppedCanvasDataURLAsync( + [NotNull] Guid cropperComponentId, GetCroppedCanvasOptions getCroppedCanvasOptions, string type, float number, @@ -260,6 +323,7 @@ public async ValueTask GetCroppedCanvasDataURLAsync( return await _jsRuntime!.InvokeAsync( "cropper.getCroppedCanvasDataURL", cancellationToken, + cropperComponentId, getCroppedCanvasOptions, type, number); @@ -268,42 +332,58 @@ public async ValueTask GetCroppedCanvasDataURLAsync( /// /// Get the cropped area position and size data (base on the original image). /// + /// The identifier of the cropper component. /// Indicate if round the data values or not. /// The used to propagate notifications that the operation should be canceled. /// A representing result cropped data asynchronous operation. - public async ValueTask GetDataAsync(bool rounded, CancellationToken cancellationToken = default) + public async ValueTask GetDataAsync( + [NotNull] Guid cropperComponentId, + bool rounded, + CancellationToken cancellationToken = default) { if (Module is null) { await LoadModuleAsync(cancellationToken); } - return await _jsRuntime!.InvokeAsync("cropper.getData", cancellationToken, rounded); + return await _jsRuntime!.InvokeAsync( + "cropper.getData", + cancellationToken, + cropperComponentId, + rounded); } /// /// Get the image position and size data. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing result image data asynchronous operation. - public async ValueTask GetImageDataAsync(CancellationToken cancellationToken = default) + public async ValueTask GetImageDataAsync( + [NotNull] Guid cropperComponentId, + CancellationToken cancellationToken = default) { if (Module is null) { await LoadModuleAsync(cancellationToken); } - return await _jsRuntime!.InvokeAsync("cropper.getImageData", cancellationToken); + return await _jsRuntime!.InvokeAsync( + "cropper.getImageData", + cancellationToken, + cropperComponentId); } /// /// Move the canvas with relative offsets. /// + /// The identifier of the cropper component. /// The relative offset distance on the x-axis. /// The relative offset distance on the y-axis. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask MoveAsync( + [NotNull] Guid cropperComponentId, decimal offsetX, decimal? offsetY, CancellationToken cancellationToken = default) @@ -313,17 +393,24 @@ public async ValueTask MoveAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.move", cancellationToken, offsetX, offsetY); + await _jsRuntime!.InvokeVoidAsync( + "cropper.move", + cancellationToken, + cropperComponentId, + offsetX, + offsetY); } /// /// Move the canvas to an absolute point. /// + /// The identifier of the cropper component. /// The x-axis coordinate. /// The y-axis coordinate. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask MoveToAsync( + [NotNull] Guid cropperComponentId, decimal x, decimal? y, CancellationToken cancellationToken = default) @@ -333,17 +420,24 @@ public async ValueTask MoveToAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.moveTo", cancellationToken, x, y); + await _jsRuntime!.InvokeVoidAsync( + "cropper.moveTo", + cancellationToken, + cropperComponentId, + x, + y); } /// /// Replace the image's src and rebuild the cropper. /// + /// The identifier of the cropper component. /// The new URL. /// If the new image has the same size as the old one, then it will not rebuild the cropper and only update the URLs of all related images. This can be used for applying filters. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask ReplaceAsync( + [NotNull] Guid cropperComponentId, string url, bool hasSameSize, CancellationToken cancellationToken = default) @@ -353,31 +447,44 @@ public async ValueTask ReplaceAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.replace", cancellationToken, url, hasSameSize); + await _jsRuntime!.InvokeVoidAsync( + "cropper.replace", + cancellationToken, + cropperComponentId, + url, + hasSameSize); } /// /// Reset the image and crop box to their initial states. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - public async ValueTask ResetAsync(CancellationToken cancellationToken = default) + public async ValueTask ResetAsync( + [NotNull] Guid cropperComponentId, + CancellationToken cancellationToken = default) { if (Module is null) { await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.reset", cancellationToken); + await _jsRuntime!.InvokeVoidAsync( + "cropper.reset", + cancellationToken, + cropperComponentId); } /// /// Rotate the canvas with a relative degree. /// + /// The identifier of the cropper component. /// The rotate degree. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask RotateAsync( + [NotNull] Guid cropperComponentId, decimal degree, CancellationToken cancellationToken = default) { @@ -386,16 +493,22 @@ public async ValueTask RotateAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.rotate", cancellationToken, degree); + await _jsRuntime!.InvokeVoidAsync( + "cropper.rotate", + cancellationToken, + cropperComponentId, + degree); } /// /// Rotate the canvas to an absolute degree. /// + /// The identifier of the cropper component. /// The rotate degree. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask RotateToAsync( + [NotNull] Guid cropperComponentId, decimal degree, CancellationToken cancellationToken = default) { @@ -404,17 +517,23 @@ public async ValueTask RotateToAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.rotateTo", cancellationToken, degree); + await _jsRuntime!.InvokeVoidAsync( + "cropper.rotateTo", + cancellationToken, + cropperComponentId, + degree); } /// /// Scale the image. /// + /// The identifier of the cropper component. /// The scale ratio on the x-axis. /// The scale ratio on the y-axis. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask ScaleAsync( + [NotNull] Guid cropperComponentId, decimal scaleX, decimal scaleY, CancellationToken cancellationToken = default) @@ -424,16 +543,23 @@ public async ValueTask ScaleAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.scale", cancellationToken, scaleX, scaleY); + await _jsRuntime!.InvokeVoidAsync( + "cropper.scale", + cancellationToken, + cropperComponentId, + scaleX, + scaleY); } /// /// Scale the image on the x-axis. /// + /// The identifier of the cropper component. /// The scale ratio on the x-axis. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask ScaleXAsync( + [NotNull] Guid cropperComponentId, decimal scaleX, CancellationToken cancellationToken = default) { @@ -442,16 +568,22 @@ public async ValueTask ScaleXAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.scaleX", cancellationToken, scaleX); + await _jsRuntime!.InvokeVoidAsync( + "cropper.scaleX", + cancellationToken, + cropperComponentId, + scaleX); } /// /// Scale the image on the y-axis. /// + /// The identifier of the cropper component. /// The scale ratio on the y-axis. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask ScaleYAsync( + [NotNull] Guid cropperComponentId, decimal scaleY, CancellationToken cancellationToken = default) { @@ -460,16 +592,22 @@ public async ValueTask ScaleYAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.scaleY", cancellationToken, scaleY); + await _jsRuntime!.InvokeVoidAsync( + "cropper.scaleY", + cancellationToken, + cropperComponentId, + scaleY); } /// /// Change the aspect ratio of the crop box. /// + /// The identifier of the cropper component. /// The new aspect ratio. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask SetAspectRatioAsync( + [NotNull] Guid cropperComponentId, decimal aspectRatio, CancellationToken cancellationToken = default) { @@ -478,16 +616,22 @@ public async ValueTask SetAspectRatioAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.setAspectRatio", cancellationToken, aspectRatio); + await _jsRuntime!.InvokeVoidAsync( + "cropper.setAspectRatio", + cancellationToken, + cropperComponentId, + aspectRatio); } /// /// Set the canvas position and size with new data. /// + /// The identifier of the cropper component. /// The new canvas data. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask SetCanvasDataAsync( + [NotNull] Guid cropperComponentId, SetCanvasDataOptions setCanvasDataOptions, CancellationToken cancellationToken = default) { @@ -496,16 +640,22 @@ public async ValueTask SetCanvasDataAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.setCanvasData", cancellationToken, setCanvasDataOptions); + await _jsRuntime!.InvokeVoidAsync( + "cropper.setCanvasData", + cancellationToken, + cropperComponentId, + setCanvasDataOptions); } /// /// Set the crop box position and size with new data. /// + /// The identifier of the cropper component. /// The new crop box data. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask SetCropBoxDataAsync( + [NotNull] Guid cropperComponentId, SetCropBoxDataOptions cropBoxDataOptions, CancellationToken cancellationToken = default) { @@ -514,16 +664,22 @@ public async ValueTask SetCropBoxDataAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.setCropBoxData", cancellationToken, cropBoxDataOptions); + await _jsRuntime!.InvokeVoidAsync( + "cropper.setCropBoxData", + cancellationToken, + cropperComponentId, + cropBoxDataOptions); } /// /// Set the cropped area position and size with new data. /// + /// The identifier of the cropper component. /// The new data. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask SetDataAsync( + [NotNull] Guid cropperComponentId, SetDataOptions setDataOptions, CancellationToken cancellationToken = default) { @@ -532,16 +688,22 @@ public async ValueTask SetDataAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.setData", cancellationToken, setDataOptions); + await _jsRuntime!.InvokeVoidAsync( + "cropper.setData", + cancellationToken, + cropperComponentId, + setDataOptions); } /// /// Change the drag mode. /// + /// The identifier of the cropper component. /// The new drag mode. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask SetDragModeAsync( + [NotNull] Guid cropperComponentId, DragMode dragMode, CancellationToken cancellationToken = default) { @@ -550,16 +712,22 @@ public async ValueTask SetDragModeAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.setDragMode", cancellationToken, dragMode.ToEnumString()); + await _jsRuntime!.InvokeVoidAsync( + "cropper.setDragMode", + cancellationToken, + cropperComponentId, + dragMode.ToEnumString()); } /// /// Zoom the canvas with a relative ratio. /// + /// The identifier of the cropper component. /// The target ratio. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask ZoomAsync( + [NotNull] Guid cropperComponentId, decimal ratio, CancellationToken cancellationToken = default) { @@ -568,18 +736,24 @@ public async ValueTask ZoomAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.zoom", cancellationToken, ratio); + await _jsRuntime!.InvokeVoidAsync( + "cropper.zoom", + cancellationToken, + cropperComponentId, + ratio); } /// /// Zoom the canvas to an absolute ratio. /// + /// The identifier of the cropper component. /// The target ratio. /// The zoom pivot point X coordinate. /// The zoom pivot point Y coordinate. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. public async ValueTask ZoomToAsync( + [NotNull] Guid cropperComponentId, decimal ratio, decimal pivotX, decimal pivotY, @@ -590,7 +764,13 @@ public async ValueTask ZoomToAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.zoomTo", cancellationToken, ratio, pivotX, pivotY); + await _jsRuntime!.InvokeVoidAsync( + "cropper.zoomTo", + cancellationToken, + cropperComponentId, + ratio, + pivotX, + pivotY); } /// @@ -605,7 +785,9 @@ public async ValueTask NoConflictAsync(CancellationToken cancellationToken = def await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.noConflict", cancellationToken); + await _jsRuntime!.InvokeVoidAsync( + "cropper.noConflict", + cancellationToken); } /// @@ -623,7 +805,10 @@ public async ValueTask SetDefaultsAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime!.InvokeVoidAsync("cropper.setDefaults", cancellationToken, options); + await _jsRuntime!.InvokeVoidAsync( + "cropper.setDefaults", + cancellationToken, + options); } /// @@ -647,7 +832,11 @@ public async ValueTask GetImageUsingStreamingAsync( var jsImageStream = imageFile.OpenReadStream(maxAllowedSize, cancellationToken); var dotnetImageStream = new DotNetStreamReference(jsImageStream); - return await _jsRuntime.InvokeAsync("cropper.getImageUsingStreaming", cancellationToken, dotnetImageStream); + + return await _jsRuntime.InvokeAsync( + "cropper.getImageUsingStreaming", + cancellationToken, + dotnetImageStream); } /// @@ -665,7 +854,10 @@ public async ValueTask RevokeObjectUrlAsync( await LoadModuleAsync(cancellationToken); } - await _jsRuntime.InvokeVoidAsync("cropper.revokeObjectUrl", cancellationToken, url); + await _jsRuntime.InvokeVoidAsync( + "cropper.revokeObjectUrl", + cancellationToken, + url); } /// diff --git a/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs b/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs index 0c781b42..4cb47894 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Services/ICropperJsInterop.cs @@ -1,4 +1,5 @@ -using System.Diagnostics.CodeAnalysis; +using System; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Cropper.Blazor.Base; @@ -24,12 +25,14 @@ public interface ICropperJsInterop /// /// Initializes cropper. /// + /// The identifier of the cropper component. /// Reference to img html-DOM /// Cropper options /// Reference to base cropper component. Default equal to 'this' object. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask InitCropperAsync( + Guid cropperComponentId, [NotNull] ElementReference image, [NotNull] Options options, [NotNull] DotNetObjectReference cropperComponentBase, @@ -38,84 +41,115 @@ ValueTask InitCropperAsync( /// /// Clear the crop box. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - ValueTask ClearAsync(CancellationToken cancellationToken = default); + ValueTask ClearAsync( + Guid cropperComponentId, + CancellationToken cancellationToken = default); /// /// Show the crop box manually. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - ValueTask CropAsync(CancellationToken cancellationToken = default); + ValueTask CropAsync( + Guid cropperComponentId, + CancellationToken cancellationToken = default); /// /// Destroy the cropper and remove the instance from the image. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - ValueTask DestroyAsync(CancellationToken cancellationToken = default); + ValueTask DestroyAsync( + Guid cropperComponentId, + CancellationToken cancellationToken = default); /// /// Disable (freeze) the cropper. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - ValueTask DisableAsync(CancellationToken cancellationToken = default); + ValueTask DisableAsync( + Guid cropperComponentId, + CancellationToken cancellationToken = default); /// /// Enable (unfreeze) the cropper. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - ValueTask EnableAsync(CancellationToken cancellationToken = default); + ValueTask EnableAsync( + Guid cropperComponentId, + CancellationToken cancellationToken = default); /// /// Get the canvas position and size data. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing result canvas data asynchronous operation. - ValueTask GetCanvasDataAsync(CancellationToken cancellationToken = default); + ValueTask GetCanvasDataAsync( + Guid cropperComponentId, + CancellationToken cancellationToken = default); /// /// Get the container size data. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing result container data asynchronous operation. - ValueTask GetContainerDataAsync(CancellationToken cancellationToken = default); + ValueTask GetContainerDataAsync( + Guid cropperComponentId, + CancellationToken cancellationToken = default); /// /// Get the crop box position and size data. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing result crop box data asynchronous operation. - ValueTask GetCropBoxDataAsync(CancellationToken cancellationToken = default); + ValueTask GetCropBoxDataAsync( + Guid cropperComponentId, + CancellationToken cancellationToken = default); /// /// Get the cropped area position and size data (base on the original image). /// + /// The identifier of the cropper component. /// Indicate if round the data values or not. /// The used to propagate notifications that the operation should be canceled. /// A representing result cropped data asynchronous operation. ValueTask GetDataAsync( + Guid cropperComponentId, bool rounded, CancellationToken cancellationToken = default); /// /// Get the image position and size data. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing result image data asynchronous operation. - ValueTask GetImageDataAsync(CancellationToken cancellationToken = default); + ValueTask GetImageDataAsync( + Guid cropperComponentId, + CancellationToken cancellationToken = default); /// /// Move the canvas with relative offsets. /// + /// The identifier of the cropper component. /// The relative offset distance on the x-axis. /// The relative offset distance on the y-axis. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask MoveAsync( + Guid cropperComponentId, decimal offsetX, decimal? offsetY, CancellationToken cancellationToken = default); @@ -123,11 +157,13 @@ ValueTask MoveAsync( /// /// Move the canvas to an absolute point. /// + /// The identifier of the cropper component. /// The x-axis coordinate. /// The y-axis coordinate. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask MoveToAsync( + Guid cropperComponentId, decimal x, decimal? y, CancellationToken cancellationToken = default); @@ -135,11 +171,13 @@ ValueTask MoveToAsync( /// /// Replace the image's src and rebuild the cropper. /// + /// The identifier of the cropper component. /// The new URL. /// If the new image has the same size as the old one, then it will not rebuild the cropper and only update the URLs of all related images. This can be used for applying filters. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask ReplaceAsync( + Guid cropperComponentId, string url, bool hasSameSize, CancellationToken cancellationToken = default); @@ -147,38 +185,47 @@ ValueTask ReplaceAsync( /// /// Reset the image and crop box to their initial states. /// + /// The identifier of the cropper component. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. - ValueTask ResetAsync(CancellationToken cancellationToken = default); + ValueTask ResetAsync( + Guid cropperComponentId, + CancellationToken cancellationToken = default); /// /// Rotate the canvas with a relative degree. /// + /// The identifier of the cropper component. /// The rotate degree. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask RotateAsync( + Guid cropperComponentId, decimal degree, CancellationToken cancellationToken = default); /// /// Rotate the canvas to an absolute degree. /// + /// The identifier of the cropper component. /// The rotate degree. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask RotateToAsync( + Guid cropperComponentId, decimal degree, CancellationToken cancellationToken = default); /// /// Scale the image. /// + /// The identifier of the cropper component. /// The scale ratio on the x-axis. /// The scale ratio on the y-axis. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask ScaleAsync( + Guid cropperComponentId, decimal scaleX, decimal scaleY, CancellationToken cancellationToken = default); @@ -186,82 +233,98 @@ ValueTask ScaleAsync( /// /// Scale the image on the x-axis. /// + /// The identifier of the cropper component. /// The scale ratio on the x-axis. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask ScaleXAsync( + Guid cropperComponentId, decimal scaleX, CancellationToken cancellationToken = default); /// /// Scale the image on the y-axis. /// + /// The identifier of the cropper component. /// The scale ratio on the y-axis. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask ScaleYAsync( + Guid cropperComponentId, decimal scaleY, CancellationToken cancellationToken = default); /// /// Set the canvas position and size with new data. /// + /// The identifier of the cropper component. /// The new canvas data. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask SetCanvasDataAsync( + Guid cropperComponentId, SetCanvasDataOptions setCanvasDataOptions, CancellationToken cancellationToken = default); /// /// Set the crop box position and size with new data. /// + /// The identifier of the cropper component. /// The new crop box data. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask SetCropBoxDataAsync( + Guid cropperComponentId, SetCropBoxDataOptions cropBoxDataOptions, CancellationToken cancellationToken = default); /// /// Set the cropped area position and size with new data. /// + /// The identifier of the cropper component. /// The new data. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask SetDataAsync( + Guid cropperComponentId, SetDataOptions setDataOptions, CancellationToken cancellationToken = default); /// /// Change the drag mode. /// + /// The identifier of the cropper component. /// The new drag mode. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask SetDragModeAsync( + Guid cropperComponentId, DragMode dragMode, CancellationToken cancellationToken = default); /// /// Zoom the canvas with a relative ratio. /// + /// The identifier of the cropper component. /// The target ratio. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask ZoomAsync( + Guid cropperComponentId, decimal ratio, CancellationToken cancellationToken = default); /// /// Zoom the canvas to an absolute ratio. /// + /// The identifier of the cropper component. /// The target ratio. /// The zoom pivot point X coordinate. /// The zoom pivot point Y coordinate. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask ZoomToAsync( + Guid cropperComponentId, decimal ratio, decimal pivotX, decimal pivotY, @@ -287,26 +350,31 @@ ValueTask SetDefaultsAsync( /// /// Change the aspect ratio of the crop box. /// + /// The identifier of the cropper component. /// The new aspect ratio. /// The used to propagate notifications that the operation should be canceled. /// A representing any asynchronous operation. ValueTask SetAspectRatioAsync( + Guid cropperComponentId, decimal aspectRatio, CancellationToken cancellationToken = default); /// /// Get a canvas drawn the cropped image. /// + /// The identifier of the cropper component. /// The config options. /// The used to propagate notifications that the operation should be canceled. /// A representing result canvas asynchronous operation. ValueTask GetCroppedCanvasAsync( + Guid cropperComponentId, GetCroppedCanvasOptions getCroppedCanvasOptions, CancellationToken cancellationToken = default); /// /// Get a canvas drawn the cropped image. /// + /// The identifier of the cropper component. /// The config options. /// A string indicating the image format. The default type is image/png; this image format will be also used if the specified type is not supported. /// A number between 0 and 1 indicating the image quality to be used when creating images using file formats that support lossy compression (such as image/jpeg or image/webp). A user agent will use its default quality value if this option is not specified, or if the number is outside the allowed range. @@ -315,6 +383,7 @@ ValueTask GetCroppedCanvasAsync( /// The used to propagate notifications that the operation should be canceled. /// A representing URL result canvas asynchronous operation. ValueTask GetCroppedCanvasDataURLAsync( + Guid cropperComponentId, GetCroppedCanvasOptions getCroppedCanvasOptions, string type, float number, diff --git a/src/Cropper.Blazor/Cropper.Blazor/wwwroot/cropperJsInterop.js b/src/Cropper.Blazor/Cropper.Blazor/wwwroot/cropperJsInterop.js index 07f35864..0523316b 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/wwwroot/cropperJsInterop.js +++ b/src/Cropper.Blazor/Cropper.Blazor/wwwroot/cropperJsInterop.js @@ -1,119 +1,149 @@ class CropperDecorator { constructor() { - this.cropperInstance = {}; + this.cropperInstances = {}; } - clear() { - return this.cropperInstance.clear(); + clear(cropperComponentId) { + return this.cropperInstances[cropperComponentId] + .clear(); } - crop() { - return this.cropperInstance.crop(); + crop(cropperComponentId) { + return this.cropperInstances[cropperComponentId] + .crop(); } - destroy() { - return this.cropperInstance.destroy(); + destroy(cropperComponentId) { + this.cropperInstances[cropperComponentId] + .destroy(); + delete this.cropperInstances[cropperComponentId]; } - disable() { - return this.cropperInstance.disable(); + disable(cropperComponentId) { + return this.cropperInstances[cropperComponentId] + .disable(); } - enable() { - return this.cropperInstance.enable(); + enable(cropperComponentId) { + return this.cropperInstances[cropperComponentId] + .enable(); } - getCanvasData() { - return this.cropperInstance.getCanvasData(); + getCanvasData(cropperComponentId) { + return this.cropperInstances[cropperComponentId] + .getCanvasData(); } - getContainerData() { - return this.cropperInstance.getContainerData(); + getContainerData(cropperComponentId) { + return this.cropperInstances[cropperComponentId] + .getContainerData(); } - getCropBoxData() { - return this.cropperInstance.getCropBoxData(); + getCropBoxData(cropperComponentId) { + return this.cropperInstances[cropperComponentId] + .getCropBoxData(); } - getCroppedCanvas(options) { - return this.cropperInstance.getCroppedCanvas(options); + getCroppedCanvas(cropperComponentId, options) { + return this.cropperInstances[cropperComponentId] + .getCroppedCanvas(options); } - getCroppedCanvasDataURL(options, type, encoderOptions) { - return this.cropperInstance.getCroppedCanvas(options).toDataURL(type, encoderOptions); + getCroppedCanvasDataURL(cropperComponentId, options, type, encoderOptions) { + return this.cropperInstances[cropperComponentId] + .getCroppedCanvas(options) + .toDataURL(type, encoderOptions); } - getData(rounded) { - return this.cropperInstance.getData(rounded); + getData(cropperComponentId, rounded) { + return this.cropperInstances[cropperComponentId] + .getData(rounded); } - getImageData() { - return this.cropperInstance.getImageData(); + getImageData(cropperComponentId) { + return this.cropperInstances[cropperComponentId] + .getImageData(); } - move(offsetX, offsetY) { - return this.cropperInstance.move(offsetX, offsetY); + move(cropperComponentId, offsetX, offsetY) { + return this.cropperInstances[cropperComponentId] + .move(offsetX, offsetY); } - moveTo(x, y) { - return this.cropperInstance.moveTo(x, y); + moveTo(cropperComponentId, x, y) { + return this.cropperInstances[cropperComponentId] + .moveTo(x, y); } - replace(url, onlyColorChanged) { - return this.cropperInstance.replace(url, onlyColorChanged); + replace(cropperComponentId, url, onlyColorChanged) { + return this.cropperInstances[cropperComponentId] + .replace(url, onlyColorChanged); } - reset() { - return this.cropperInstance.reset(); + reset(cropperComponentId) { + return this.cropperInstances[cropperComponentId] + .reset(); } - rotate(degree) { - return this.cropperInstance.rotate(degree); + rotate(cropperComponentId, degree) { + return this.cropperInstances[cropperComponentId] + .rotate(degree); } - rotateTo(degree) { - return this.cropperInstance.rotateTo(degree); + rotateTo(cropperComponentId, degree) { + return this.cropperInstances[cropperComponentId] + .rotateTo(degree); } - scale(scaleX, scaleY) { - return this.cropperInstance.scale(scaleX, scaleY); + scale(cropperComponentId, scaleX, scaleY) { + return this.cropperInstances[cropperComponentId] + .scale(scaleX, scaleY); } - scaleX(scaleX) { - return this.cropperInstance.scaleX(scaleX); + scaleX(cropperComponentId, scaleX) { + return this.cropperInstances[cropperComponentId] + .scaleX(scaleX); } - scaleY(scaleY) { - return this.cropperInstance.scaleY(scaleY); + scaleY(cropperComponentId, scaleY) { + return this.cropperInstances[cropperComponentId] + .scaleY(scaleY); } - setAspectRatio(aspectRatio) { - return this.cropperInstance.setAspectRatio(aspectRatio); + setAspectRatio(cropperComponentId, aspectRatio) { + return this.cropperInstances[cropperComponentId] + .setAspectRatio(aspectRatio); } - setCanvasData(data) { - return this.cropperInstance.setCanvasData(data); + setCanvasData(cropperComponentId, data) { + return this.cropperInstances[cropperComponentId] + .setCanvasData(data); } - setCropBoxData(data) { - return this.cropperInstance.setCropBoxData(data); + setCropBoxData(cropperComponentId, data) { + return this.cropperInstances[cropperComponentId] + .setCropBoxData(data); } - setData(data) { - return this.cropperInstance.setData(data); + setData(cropperComponentId, data) { + return this.cropperInstances[cropperComponentId] + .setData(data); } - setDragMode(dragMode) { - return this.cropperInstance.setDragMode(dragMode); + setDragMode(cropperComponentId, dragMode) { + return this.cropperInstances[cropperComponentId] + .setDragMode(dragMode); } - zoom(ratio) { - return this.cropperInstance.zoom(ratio); + zoom(cropperComponentId, ratio) { + return this.cropperInstances[cropperComponentId] + .zoom(ratio); } - zoomTo(ratio, pivotX, pivotY) { - return this.cropperInstance.zoomTo(ratio, { pivotX, pivotY }); + zoomTo(cropperComponentId, ratio, pivotX, pivotY) { + return this.cropperInstances[cropperComponentId] + .zoomTo(ratio, { pivotX, pivotY }); } noConflict() { @@ -154,10 +184,10 @@ class CropperDecorator { getJSEventDataDetail(instance) { if (instance.type === "zoom") { return { - oldRatio: instance.detail.oldRatio, - ratio: instance.detail.ratio, - originalEvent: instance.detail.originalEvent ? - DotNet.createJSObjectReference(instance.detail.originalEvent) : null + oldRatio: instance.detail.oldRatio, + ratio: instance.detail.ratio, + originalEvent: instance.detail.originalEvent ? + DotNet.createJSObjectReference(instance.detail.originalEvent) : null }; } else if (instance.type === "cropstart" || instance.type === "cropend" || instance.type === "cropmove") { @@ -201,7 +231,7 @@ class CropperDecorator { imageObject.invokeMethodAsync('CropperIsZoomed', jSEventData); } - initCropper(image, optionsImage, imageObject) { + initCropper(cropperComponentId, image, optionsImage, imageObject) { if (image == null) { throw "Parameter 'image' must be is not null!"; } @@ -242,7 +272,9 @@ class CropperDecorator { }); } - this.cropperInstance = new Cropper(image, options); + const cropper = new Cropper(image, options); + + this.cropperInstances[cropperComponentId] = cropper; } } From 0ac933acc3f07ff61446f54f7d45efc6237eaa78 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sun, 7 May 2023 12:02:22 +0300 Subject: [PATCH 026/196] Demo's actions UI updated --- .../CroppedDimensionsSettings.razor | 10 +- .../Client/Pages/CropperDemo.razor | 765 +++++++++--------- 2 files changed, 394 insertions(+), 381 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor index cebea3b0..8b5484cb 100644 --- a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor +++ b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor @@ -1,9 +1,11 @@  + + + Dimensions Settings + This option may not work with arbitrary 'Aspect Ratios' images, it is recommended to use a free Aspect Ratio for this option or calculate the allowed values yourself + + - - Dimensions Settings -
This option may not work with arbitrary 'Aspect Ratios' images, it is recommended to use a free Aspect Ratio for this option or calculate the allowed values yourself
-
@*//---Cropper Component---//*@ - +
@*//---Img preview and data---//*@ - +
@@ -48,388 +48,399 @@
- @*//---Buttons for test cropper functional---//*@ - - - - - - - - - - + + + + +
+ + Actions +
+
+ + + @*//---Buttons for test cropper functional---//*@ + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - + + + + + + + + - - - Move to [0,0] - - - - - Zoom to 100% - - - - - 180° - - - - - Scale (-2, -1) - - - - - Get Cropped Canvas by URL - - - - - Get Cropped Canvas by element - - - - - - 320×180 - - - - - 640×360 - - - - - - @*//---Aspect Ratio | View Mode | Get Cropped Canvas---//*@ - - - - - - - - 16:9 - - - - - 4:3 - - - - - 1:1 - - - - - 2:3 - - - - - Free - - - - - - - VM0 - - - - - VM1 - - - - - VM2 - - - - - VM3 - - - - - - - - - - - - - - - - - - - - - - GET - - - - - - - - - 16:9 - - - - - 4:3 - - - - - 1:1 - - - - - 2:3 - - - - - Free - - - - - - - VM0 - - - - - VM1 - - - - - VM2 - - - - - VM3 - - - - - - - - - - - - - - - - - - - - - - GET - - - - - - - - Toggle Options - - - - - @foreach (var item in Options.GetType().GetProperties().Where(p => p.PropertyType == typeof(bool?))) - { - - - - } - - - - - + + + + + + + + + + + + + + + + Move to [0,0] + + + + + Zoom to 100% + + + + + 180° + + + + + Scale (-2, -1) + + + + + Get Cropped Canvas by URL + + + + + Get Cropped Canvas by element + + + + + + 320×180 + + + + + 640×360 + + + +
+
+ @*//---Aspect Ratio | View Mode | Get Cropped Canvas---//*@ + + + + + + + + GET + + + + + + + Toggle Options + + + + + @foreach (var item in Options.GetType().GetProperties().Where(p => p.PropertyType == typeof(bool?))) + { + + + + } + + + + + + + + 16:9 + + + + + 4:3 + + + + + 1:1 + + + + + 2:3 + + + + + Free + + + + + + + VM0 + + + + + VM1 + + + + + VM2 + + + + + VM3 + + + + + + + + + + + + + + + + + + + + + + + + + + GET + + + + + + + Toggle Options + + + + + @foreach (var item in Options.GetType().GetProperties().Where(p => p.PropertyType == typeof(bool?))) + { + + + + } + + + + + + + + 16:9 + + + + + 4:3 + + + + + 1:1 + + + + + 2:3 + + + + + Free + + + + + + + VM0 + + + + + VM1 + + + + + VM2 + + + + + VM3 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@*//+---// Get/Set all cropper data //---+//*@ @@ -444,7 +455,7 @@ SetCanvasDataOptions="SetCanvasData" SetDataOptions="SetData" SetCropBoxDataOptions="SetCropBoxData" - @ref="GetSetCropperData" /> + @ref="GetSetCropperData" /> From 7e13a2c6c2eae8231f50f1d219a63506d173cf6e Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sun, 7 May 2023 12:22:12 +0300 Subject: [PATCH 027/196] Demo's settings and GetSetData UI updated --- .../Components/AspectRatioSettings.razor | 7 +- .../CroppedDimensionsSettings.razor | 2 +- .../Client/Components/GetSetCropperData.razor | 322 +++++++++++------- .../Client/Components/ZoomRatioSettings.razor | 6 +- .../Client/Pages/CropperDemo.razor | 4 +- 5 files changed, 213 insertions(+), 128 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor index 6f039b66..3b4b43da 100644 --- a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor @@ -1,6 +1,11 @@  + + + Aspect Ratio Settings + This option work's only for FREE aspect ratio mode! + + - Aspect Ratio Settings (only for FREE aspect ratio) - + Dimensions Settings This option may not work with arbitrary 'Aspect Ratios' images, it is recommended to use a free Aspect Ratio for this option or calculate the allowed values yourself diff --git a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor index e91f3b37..25487afc 100644 --- a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor +++ b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor @@ -1,127 +1,203 @@ @using Cropper.Blazor.Models - - @*//---Enable setup minimum and maximum cropped dimensions---//*@ - - @*//---Cropper Data---//*@ - - - Cropper Data - - - - - - - - - - - - Get Data - - - - - Set Data - - - - - -@*//---Container and Crop Box Data---//*@ - - - - Container Data - - - - - - - Get Container Data - - - - - @*//---Crop Box Data---//*@ - - - Crop Box Data - - - - - - - - - Get Data - - - - - Set Data - - - - + + + + +
+ + Event`s settings +
+
+ + + + @*//---Enable setup minimum and maximum cropped dimensions---//*@ + + + + + @*//---Enable setup max/min zoom ratio---//*@ + + + + + @*//---Enable setup max/min aspect ratio---//*@ + + + + +
+
-@*//---Image Data---//*@ - - - - - Image Data - - - - - - - - - - - - - - - Get Image Data - - - - + + + + + + +
+ + Get or Set cropper component data +
+
+ + + + @*//---Cropper Data---//*@ + + + + Cropper Data + + + + + + + + + + + + + + + Get Data + + + + + Set Data + + + + + + + + @*//---Crop Box Data---//*@ + + + + Crop Box Data + + + + + + + + + + + + Get Data + + + + + Set Data + + + + + + + + @*//---Image Data---//*@ + + + + Image Data + + + + + + + + + + + + + + + + + + Get Image Data + + + + + + + + @*//---Canvas Data---//*@ + + + + Canvas Data + + + + + + + + + + + + + + Get Data + + + + + Set Data + + + + + + + +
+
- - @*//---Enable setup max/min zoom ratio---//*@ - - @*//---Canvas Data---//*@ - - - Canvas Data - - - - - - - - - - - Get Data - - - - - Set Data - - - - - \ No newline at end of file diff --git a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor index cedda9e3..bd38812e 100644 --- a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor +++ b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor @@ -1,6 +1,10 @@  + + + Zoom Ratio Settings + + - Zoom Ratio Settings @*//---Cropper Component---//*@ - +
@*//---Img preview and data---//*@ - +
From 8817ebe509ac7f4b3a0035b725d7a86fff716fac Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Wed, 26 Jul 2023 15:10:37 +0300 Subject: [PATCH 028/196] Update issue templates (#183) Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 41 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 8 +++++ .github/ISSUE_TEMPLATE/feature_request.md | 23 +++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..af120529 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,41 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. + +**Pull Request** +- [ ] I would like to do a Pull Request diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..d9eb5902 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Github Discussions + url: https://github.com/CropperBlazor/Cropper.Blazor/discussions + about: Please ask and answer questions here + - name: Telegram + url: https://t.me/+dLQD8Al6C9s0ZjMy + about: You can also ask and answer questions here \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..c59d488c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,23 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. + +**Pull Request** +- [ ] I would like to do a Pull Request From 4e8cad397d043121c410c30aeb22b57c4aa3d40f Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sun, 7 May 2023 13:01:03 +0300 Subject: [PATCH 029/196] Demo's settings UI updated --- .../Components/AspectRatioSettings.razor | 28 ++++++----- .../CroppedDimensionsSettings.razor | 47 ++++++++++--------- .../Client/Components/ZoomRatioSettings.razor | 44 ++++++++++------- 3 files changed, 69 insertions(+), 50 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor index 3b4b43da..050b0960 100644 --- a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor @@ -1,24 +1,28 @@  - + - Aspect Ratio Settings - This option work's only for FREE aspect ratio mode! +
+ Aspect Ratio Settings + + This option work's only for FREE aspect ratio mode! + +
- + + Min="0" Max="MaxAspectRatio"> - - - Current aspect ratio: @AspectRatio - +
+ Current aspect ratio: + +
diff --git a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor index 7620b571..3f9fd5b0 100644 --- a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor +++ b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor @@ -1,28 +1,33 @@  - + - Dimensions Settings - This option may not work with arbitrary 'Aspect Ratios' images, it is recommended to use a free Aspect Ratio for this option or calculate the allowed values yourself +
+ Dimensions Settings + + This setting may not work with a specific aspect ratio. + It is recommended to use a FREE aspect ratio for this + option or calculate the valid values yourself. + +
- - - - - - - - + +
+ + + + +
+
+ + + + +
diff --git a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor index bd38812e..c4598567 100644 --- a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor +++ b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor @@ -1,24 +1,34 @@  - + - Zoom Ratio Settings +
+ Zoom Ratio Settings + + Make sure that the current Zoom Ratio value is less than the minimum value, + otherwise this setting may not work correctly. + +
- - - - - - Zoom event old ratio: @OldRatio - - - Zoom event ratio: @Ratio - + +
+ + + + +
+
+ Zoom event old ratio: + +
+
+ Zoom event ratio: + +
From 037235ffac9fee14900da7d3fe91c18524804ca8 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Mon, 8 May 2023 11:05:01 +0300 Subject: [PATCH 030/196] Fix UI blocks spaces --- .../Components/AspectRatioSettings.razor | 8 +++++--- .../CroppedDimensionsSettings.razor | 20 +++++++++---------- .../Client/Components/ZoomRatioSettings.razor | 12 +++++++---- .../Client/Pages/CropperDemo.razor | 5 ++--- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor index 050b0960..d7475f5b 100644 --- a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor @@ -1,4 +1,4 @@ - +
@@ -9,7 +9,7 @@
- +
- Current aspect ratio: + + Current aspect ratio: +
diff --git a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor index 3f9fd5b0..9da00b72 100644 --- a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor +++ b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor @@ -1,4 +1,4 @@ - +
@@ -11,22 +11,22 @@
- +
- + - +
- + - +
diff --git a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor index c4598567..b164b4aa 100644 --- a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor +++ b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor @@ -1,4 +1,4 @@ - +
@@ -10,7 +10,7 @@
- +
- Zoom event old ratio: + + Zoom event old ratio: +
- Zoom event ratio: + + Zoom event ratio: +
diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index ff556973..7bda1ac5 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -62,8 +62,7 @@ @*//---Buttons for test cropper functional---//*@ - - + - + From a9805dae2110674b80dba73655487e53887527c3 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Mon, 8 May 2023 12:01:02 +0300 Subject: [PATCH 031/196] Update GetSetData, fix flex in settings --- .../Components/AspectRatioSettings.razor | 2 +- .../CroppedDimensionsSettings.razor | 4 +- .../Client/Components/GetSetCropperData.razor | 38 +++++++++++++++---- .../Client/Components/ZoomRatioSettings.razor | 6 +-- .../Client/Pages/CropperDemo.razor | 2 +- src/Cropper.Blazor/Client/Theme/Theme.cs | 1 - 6 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor index d7475f5b..8a32cf6e 100644 --- a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor @@ -19,7 +19,7 @@ Disabled="!IsEnableAspectRatioSettings" Min="MinAspectRatio ?? 0"> -
+
Current aspect ratio: diff --git a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor index 9da00b72..dfcc452a 100644 --- a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor +++ b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor @@ -13,7 +13,7 @@ -
+
@@ -21,7 +21,7 @@ Adornment="Adornment.End" AdornmentText="px" AdornmentColor="Color.Primary">
-
+
diff --git a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor index 25487afc..b86735de 100644 --- a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor +++ b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor @@ -2,7 +2,7 @@ - +
@@ -34,7 +34,7 @@ - +
@@ -46,12 +46,13 @@ @*//---Cropper Data---//*@ - + Cropper Data + @*//---Crop Box Data---//*@ - - + + Crop Box Data + + + + + + Container Dataa + + + + + + + + + + + Get Container Data + + + + @*//---Image Data---//*@ - + Image Data + @*//---Canvas Data---//*@ - + Canvas Data + -
+
@@ -20,14 +20,14 @@ Min="MinZoomRatio ?? 0">
-
+
Zoom event old ratio:
-
+
Zoom event ratio: diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index 7bda1ac5..f1594ccf 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -51,7 +51,7 @@ - +
diff --git a/src/Cropper.Blazor/Client/Theme/Theme.cs b/src/Cropper.Blazor/Client/Theme/Theme.cs index 5f5c41aa..4275f93f 100644 --- a/src/Cropper.Blazor/Client/Theme/Theme.cs +++ b/src/Cropper.Blazor/Client/Theme/Theme.cs @@ -71,7 +71,6 @@ public static MudTheme CropperBlazorDocsTheme() TableLines = "#33323e", Divider = "#292838", OverlayLight = "#1e1e2d80" - }; #endregion From bb780d2e587be700b17daf55a7de51a32d0a7815 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Thu, 27 Jul 2023 22:55:55 +0300 Subject: [PATCH 032/196] fix description in readme for cropper component, add release badge --- README.md | 3 ++- src/Cropper.Blazor/Client/Pages/Index.razor | 5 ++++- src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bf6c64c4..c7b5ded7 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,13 @@ Cropper.Blazor

- Cropper.Blazor is a component element that wraps around Cropper.js + Cropper.Blazor is a component that wraps around Cropper.js

[![Build and run test](https://github.com/CropperBlazor/Cropper.Blazor/actions/workflows/ci.yml/badge.svg?event=push)](https://github.com/CropperBlazor/Cropper.Blazor/actions/workflows/ci.yml) [![Deploy to GitHub Pages](https://github.com/CropperBlazor/Cropper.Blazor/actions/workflows/cd.yml/badge.svg?event=push)](https://github.com/CropperBlazor/Cropper.Blazor/actions/workflows/cd.yml) +[![Deploy to NuGet](https://github.com/CropperBlazor/Cropper.Blazor/actions/workflows/release.yml/badge.svg?event=push)](https://github.com/CropperBlazor/Cropper.Blazor/actions/workflows/release.yml) [![coverage](https://codecov.io/github/CropperBlazor/Cropper.Blazor/branch/dev/graph/badge.svg?token=39M66DO85T)](https://codecov.io/github/CropperBlazor/Cropper.Blazor) [![GitHub](https://img.shields.io/github/license/CropperBlazor/Cropper.Blazor?color=ff5c9b)](https://github.com/CropperBlazor/Cropper.Blazor/blob/dev/LICENSE) [![GitHub](https://img.shields.io/github/last-commit/CropperBlazor/Cropper.Blazor?color=009DEA)](https://github.com/CropperBlazor/Cropper.Blazor) diff --git a/src/Cropper.Blazor/Client/Pages/Index.razor b/src/Cropper.Blazor/Client/Pages/Index.razor index 7defb1f2..12fce707 100644 --- a/src/Cropper.Blazor/Client/Pages/Index.razor +++ b/src/Cropper.Blazor/Client/Pages/Index.razor @@ -23,7 +23,7 @@ Cropper.Blazor - is a component element that wraps around + is a component that wraps around Cropper.js @@ -37,6 +37,9 @@ Deploy to GitHub Pages + + Deploy to NuGet + Code coverage diff --git a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj index 2bbe6ea5..1bd33c19 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj @@ -20,7 +20,7 @@ Cropper.Blazor Max56132, ColdForeign Copyright 2022-present Cropper.Blazor - Cropper.Blazor is a component element that wraps around Cropper.js + Cropper.Blazor is a component that wraps around Cropper.js Blazor, Cropper.Blazor, Cropper.js, Blazor Components, Blazor Library, Blazor Cropper, Cropper, Image, Crop, Resize, image-cropper, crop-image, csharp, blazor-cropper https://CropperBlazor.github.io https://github.com/CropperBlazor/Cropper.Blazor From cb322bf3557fec6a846f97a85756da07466f768c Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Mon, 8 May 2023 12:01:02 +0300 Subject: [PATCH 033/196] Cards update --- .../Components/AspectRatioSettings.razor | 5 ++- .../CroppedDimensionsSettings.razor | 5 ++- .../Client/Components/GetSetCropperData.razor | 33 +++++++++---------- .../Client/Components/ZoomRatioSettings.razor | 5 ++- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor index 8a32cf6e..001d653f 100644 --- a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor @@ -1,5 +1,5 @@  - +
Aspect Ratio Settings @@ -9,8 +9,7 @@
- - + diff --git a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor index dfcc452a..b1bced79 100644 --- a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor +++ b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor @@ -1,5 +1,5 @@  - +
Dimensions Settings @@ -11,8 +11,7 @@
- - +
diff --git a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor index b86735de..f6e093e0 100644 --- a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor +++ b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor @@ -46,13 +46,12 @@ @*//---Cropper Data---//*@ - + Cropper Data - - + @@ -88,13 +87,12 @@ @*//---Crop Box Data---//*@ - + Crop Box Data - - + Get Data @@ -120,17 +118,20 @@ - + Container Dataa - - - + + - + Get Container Data @@ -143,13 +144,12 @@ @*//---Image Data---//*@ - + Image Data - - + @@ -185,13 +185,12 @@ @*//---Canvas Data---//*@ - + Canvas Data - - + Get Data diff --git a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor index 59273ab9..1c94edf0 100644 --- a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor +++ b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor @@ -1,5 +1,5 @@  - +
Zoom Ratio Settings @@ -10,8 +10,7 @@
- - +
From abca896de45a3665cf283f2f82bbe420bd57b637 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Mon, 8 May 2023 13:02:22 +0300 Subject: [PATCH 034/196] GetSetData updated. --- .../Client/Components/GetSetCropperData.razor | 158 ++++++++++-------- 1 file changed, 87 insertions(+), 71 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor index f6e093e0..1827dc2a 100644 --- a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor +++ b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor @@ -45,38 +45,43 @@ @*//---Cropper Data---//*@ - + Cropper Data - - - - - - - - + + + + + + + + + OnClick="@(()=>GetDataAsync(false))"> Get Data + OnClick="@(()=>SetData(new SetDataOptions(){ X = CropperData.X, Y = CropperData.Y, Height = CropperData.Height, Width = CropperData.Width, Rotate = CropperData.Rotate, ScaleX = CropperData.ScaleX, ScaleY = CropperData.ScaleY}))"> Set Data @@ -86,21 +91,23 @@ @*//---Crop Box Data---//*@ - + Crop Box Data - - - - - + + + + + @@ -110,26 +117,26 @@ + OnClick="@(()=>SetCropBoxData(new SetCropBoxDataOptions(){ Height = CropBoxData.Height, Left = CropBoxData.Left, Top = CropBoxData.Top, Width = CropBoxData.Width}))"> Set Data - + Container Dataa - - + + Label="Height" Variant="Variant.Text" Step=".2M" /> + Label="Width" Variant="Variant.Text" Step=".2M" /> @@ -149,32 +156,37 @@ Image Data - - - - - - - - - - - + + + + + + + + + + + + OnClick="GetImageDataAsync"> Get Image Data @@ -184,25 +196,29 @@ @*//---Canvas Data---//*@ - + Canvas Data - - - - - - - + + + + + + + @@ -212,7 +228,7 @@ + OnClick="@(()=>SetCanvasData(new SetCanvasDataOptions(){ Height = CanvasData.Height, Left = CanvasData.Left, Top = CanvasData.Top, Width = CanvasData.Width}))"> Set Data From f02c8189da0712f40377de8c0dd0ea734eb7da5b Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Tue, 9 May 2023 11:12:01 +0300 Subject: [PATCH 035/196] Fix margins and Numbers --- .../Client/Components/AspectRatioSettings.razor | 4 ++-- .../Client/Components/CroppedDimensionsSettings.razor | 2 +- .../Client/Components/CropperDataPreview.razor | 8 ++++---- .../Client/Components/GetSetCropperData.razor | 8 ++++---- .../Client/Components/ZoomRatioSettings.razor | 2 +- src/Cropper.Blazor/Client/Pages/CropperDemo.razor | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor index 001d653f..1dc9d5df 100644 --- a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor @@ -1,4 +1,4 @@ - +
@@ -22,7 +22,7 @@ Current aspect ratio: -
diff --git a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor index b1bced79..406fc01f 100644 --- a/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor +++ b/src/Cropper.Blazor/Client/Components/CroppedDimensionsSettings.razor @@ -1,4 +1,4 @@ - +
diff --git a/src/Cropper.Blazor/Client/Components/CropperDataPreview.razor b/src/Cropper.Blazor/Client/Components/CropperDataPreview.razor index 2ab25db6..ff8a490d 100644 --- a/src/Cropper.Blazor/Client/Components/CropperDataPreview.razor +++ b/src/Cropper.Blazor/Client/Components/CropperDataPreview.razor @@ -1,11 +1,11 @@  + Adornment="Adornment.End" AdornmentText="px" AdornmentColor="Color.Primary" Margin="Margin.Dense" Format="N4" /> + Adornment="Adornment.End" AdornmentText="px" AdornmentColor="Color.Primary" Margin="Margin.Dense" Format="N4" /> + Adornment="Adornment.End" AdornmentText="px" AdornmentColor="Color.Primary" Margin="Margin.Dense" Format="N4" /> + Adornment="Adornment.End" AdornmentText="px" AdornmentColor="Color.Primary" Margin="Margin.Dense" Format="N4" /> diff --git a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor index 1827dc2a..7a934f0f 100644 --- a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor +++ b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor @@ -1,12 +1,12 @@ @using Cropper.Blazor.Models - +
- Event`s settings + Event's settings
@@ -32,12 +32,12 @@
- +
- + Get or Set cropper component data
diff --git a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor index 1c94edf0..7fc1427d 100644 --- a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor +++ b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor @@ -1,4 +1,4 @@ - +
diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index f1594ccf..0410a804 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -49,7 +49,7 @@ - + From 1566e48bc02e5e01f9f9721a9b1ee4a0f731f3d9 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Fri, 28 Jul 2023 16:29:47 +0300 Subject: [PATCH 036/196] Fix initial zoom ratio in UI (#186) ## Target #### Open Questions ## Checklist - [ ] Documentation updated - [ ] Tests cover new or modified code - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .../Client/Components/GetSetCropperData.razor.cs | 5 +++++ .../Client/Components/ZoomRatioSettings.razor.cs | 7 +++++++ src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs | 8 ++++++++ 3 files changed, 20 insertions(+) diff --git a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor.cs b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor.cs index 35c3868b..52e3a861 100644 --- a/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor.cs +++ b/src/Cropper.Blazor/Client/Components/GetSetCropperData.razor.cs @@ -48,6 +48,11 @@ public void OnZoomEvent(ZoomEvent? zoomEvent) ZoomRatioSettings!.OnZoomEvent(zoomEvent); } + public void SetRatio(decimal? ratio) + { + ZoomRatioSettings!.SetRatio(ratio); + } + public void SetCropBoxData(SetCropBoxDataOptions cropBoxDataOptions) { SetCropBoxDataOptions.Invoke(cropBoxDataOptions); diff --git a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs index 120ad49d..86fdad9a 100644 --- a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs +++ b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs @@ -41,6 +41,13 @@ public void OnZoomEvent(ZoomEvent? zoomEvent) StateHasChanged(); } + public void SetRatio(decimal? ratio) + { + Ratio = ratio; + + StateHasChanged(); + } + public async Task ApplyZoomRulesForCropperAsync() { await JSRuntime!.InvokeVoidAsync("window.overrideOnZoomCropperEvent", MinZoomRatio, MaxZoomRatio); diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 208dfc1b..51b85743 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -215,6 +215,14 @@ public async void OnCropMoveEvent(JSEventData cropMoveJSEvent) public async void OnCropReadyEvent(JSEventData jSEventData) { await JSRuntime!.InvokeVoidAsync("console.log", $"CropReadyJSEvent, {JsonSerializer.Serialize(jSEventData)}"); + + await InvokeAsync(async () => + { + ImageData imageData = await CropperComponent!.GetImageDataAsync(); + decimal initZoomRatio = imageData.Width / imageData.NaturalWidth; + + GetSetCropperData!.SetRatio(initZoomRatio); + }); } public async void OnLoadImageEvent() From 233b092dee4f04f6f0d51ec97ad3ea034d491aeb Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Tue, 9 May 2023 12:06:09 +0300 Subject: [PATCH 037/196] Fix aspect ratio settings --- .../Client/Components/AspectRatioSettings.razor.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs index 8d2535aa..b50c6d46 100644 --- a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs @@ -1,5 +1,6 @@ using System.ComponentModel.DataAnnotations; using Cropper.Blazor.Client.Pages; +using Cropper.Blazor.Components; using Cropper.Blazor.Models; using Microsoft.AspNetCore.Components; @@ -34,8 +35,8 @@ public decimal? MinAspectRatio [CascadingParameter(Name = "AspectRatio"), Required] private decimal? AspectRatio { get; set; } - [CascadingParameter(Name = "CropperDemo"), Required] - private CropperDemo CropperDemo { get; set; } = null!; + [CascadingParameter(Name = "CropperComponent"), Required] + private CropperComponent CropperComponent { get; set; } = null!; [CascadingParameter(Name = "IsEnableAspectRatioSettings"), Required] private bool IsEnableAspectRatioSettings @@ -57,8 +58,8 @@ public async Task ApplyAspectRatioRulesForCropperAsync() { if (minAspectRatio is not null || maxAspectRatio is not null) { - ContainerData containerData = await CropperDemo.CropperComponent!.GetContainerDataAsync(); - CropBoxData cropBoxData = await CropperDemo.CropperComponent!.GetCropBoxDataAsync(); + ContainerData containerData = await CropperComponent!.GetContainerDataAsync(); + CropBoxData cropBoxData = await CropperComponent!.GetCropBoxDataAsync(); if (cropBoxData.Height != 0) { @@ -68,7 +69,7 @@ public async Task ApplyAspectRatioRulesForCropperAsync() { decimal? newCropBoxWidth = cropBoxData.Height * ((minAspectRatio + maxAspectRatio) / 2); - CropperDemo.CropperComponent!.SetCropBoxData(new SetCropBoxDataOptions + CropperComponent!.SetCropBoxData(new SetCropBoxDataOptions { Left = (containerData.Width - newCropBoxWidth) / 2, Width = newCropBoxWidth, From a6bb747a99f408da617e0b607cf817788cb25a60 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Wed, 10 May 2023 10:11:02 +0300 Subject: [PATCH 038/196] Fix zoom event settings --- .../Components/ZoomRatioSettings.razor.cs | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs index 120ad49d..5c368056 100644 --- a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs +++ b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs @@ -1,6 +1,9 @@ -using Cropper.Blazor.Events.ZoomEvent; +using Cropper.Blazor.Components; +using Cropper.Blazor.Events.ZoomEvent; +using Cropper.Blazor.Models; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; +using System.ComponentModel.DataAnnotations; namespace Cropper.Blazor.Client.Components { @@ -33,6 +36,9 @@ private decimal? MaxZoomRatio private decimal? Ratio { get; set; } = null; + [CascadingParameter(Name = "CropperComponent"), Required] + private CropperComponent CropperComponent { get; set; } = null!; + public void OnZoomEvent(ZoomEvent? zoomEvent) { OldRatio = zoomEvent?.OldRatio; @@ -43,7 +49,21 @@ public void OnZoomEvent(ZoomEvent? zoomEvent) public async Task ApplyZoomRulesForCropperAsync() { + ImageData currentImageData = await CropperComponent!.GetImageDataAsync(); + decimal currentZoomRatio = currentImageData.Width / currentImageData.NaturalWidth; + + if ((MinZoomRatio is not null) && (MinZoomRatio > currentZoomRatio)) + { + ContainerData containerData = await CropperComponent.GetContainerDataAsync(); + CropperComponent.ZoomTo((decimal)MinZoomRatio, containerData.Width / 2, containerData.Height / 2); + } + else if ((MaxZoomRatio is not null) && (currentZoomRatio > MaxZoomRatio)) + { + ContainerData containerData = await CropperComponent.GetContainerDataAsync(); + CropperComponent.ZoomTo((decimal)MaxZoomRatio, containerData.Width / 2, containerData.Height / 2); + } + await JSRuntime!.InvokeVoidAsync("window.overrideOnZoomCropperEvent", MinZoomRatio, MaxZoomRatio); } } -} \ No newline at end of file +} From 390d8e84cff4491942b8140e9a35252712912f87 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Wed, 10 May 2023 10:30:56 +0300 Subject: [PATCH 039/196] Fix override zoom event --- .../Client/wwwroot/overrideCropperJsInteropModule.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Cropper.Blazor/Client/wwwroot/overrideCropperJsInteropModule.js b/src/Cropper.Blazor/Client/wwwroot/overrideCropperJsInteropModule.js index 103ad7f7..087682ac 100644 --- a/src/Cropper.Blazor/Client/wwwroot/overrideCropperJsInteropModule.js +++ b/src/Cropper.Blazor/Client/wwwroot/overrideCropperJsInteropModule.js @@ -1,9 +1,11 @@ window.overrideOnZoomCropperEvent = (minZoomRatio, maxZoomRatio) => { window.cropper.onZoom = function (imageObject, event, correlationId) { - const jSEventData = this.getJSEventData(event, correlationId); - const isApplyPreventZoomRatio = minZoomRatio != null || maxZoomRatio != null; + const jSEventData = this.getJSEventData(event, correlationId); + + const isApplyPreventZoomMinRatio = (minZoomRatio != null) && (minZoomRatio > event.detail.ratio); + const isApplyPreventZoomMaxRatio = (maxZoomRatio != null) && (event.detail.ratio > maxZoomRatio); - if (isApplyPreventZoomRatio && (event.detail.ratio < minZoomRatio || event.detail.ratio > maxZoomRatio)) { + if (isApplyPreventZoomMinRatio || isApplyPreventZoomMaxRatio) { event.preventDefault(); } else { From c284b9f30526fb13837ffc8a58c7c0eea3c5a364 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Tue, 1 Aug 2023 23:10:59 +0300 Subject: [PATCH 040/196] Added SEO for demo site (#188) ## Target Added SEO for demo site #### Open Questions ## Checklist - [ ] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- src/Cropper.Blazor/Client/Pages/About.razor | 9 ++++ src/Cropper.Blazor/Client/Pages/Api.razor | 9 ++++ .../Client/Pages/CropperDemo.razor | 8 +++ src/Cropper.Blazor/Client/Pages/Index.razor | 13 ++++- .../Client/Shared/SeoHeader.razor | 12 +++++ .../Client/Shared/SeoHeader.razor.cs | 54 +++++++++++++++++++ 6 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/Cropper.Blazor/Client/Shared/SeoHeader.razor create mode 100644 src/Cropper.Blazor/Client/Shared/SeoHeader.razor.cs diff --git a/src/Cropper.Blazor/Client/Pages/About.razor b/src/Cropper.Blazor/Client/Pages/About.razor index d7c5e258..ef86d5ec 100644 --- a/src/Cropper.Blazor/Client/Pages/About.razor +++ b/src/Cropper.Blazor/Client/Pages/About.razor @@ -1,4 +1,13 @@ @page "/about" + + + Sorry Not available now diff --git a/src/Cropper.Blazor/Client/Pages/Api.razor b/src/Cropper.Blazor/Client/Pages/Api.razor index 5f1b1a0d..d0c75e2c 100644 --- a/src/Cropper.Blazor/Client/Pages/Api.razor +++ b/src/Cropper.Blazor/Client/Pages/Api.razor @@ -1,4 +1,13 @@ @page "/api" + + + Sorry Not available now diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index a1fb1912..51e7dec3 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -4,6 +4,14 @@ @using Cropper.Blazor.Extensions; @using Cropper.Blazor.Models + + @*//---Cropper Component---//*@ diff --git a/src/Cropper.Blazor/Client/Pages/Index.razor b/src/Cropper.Blazor/Client/Pages/Index.razor index 5b8c2ecf..5b29c84d 100644 --- a/src/Cropper.Blazor/Client/Pages/Index.razor +++ b/src/Cropper.Blazor/Client/Pages/Index.razor @@ -5,6 +5,15 @@ @using Cropper.Blazor.Client.Pages.Examples.Installation @using Cropper.Blazor.Client.Pages.Examples.Uses.Preview + + @@ -23,8 +32,8 @@ - Cropper.Blazor - is a component that wraps around + Cropper.Blazor + is a component that wraps around Cropper.js diff --git a/src/Cropper.Blazor/Client/Shared/SeoHeader.razor b/src/Cropper.Blazor/Client/Shared/SeoHeader.razor new file mode 100644 index 00000000..6999c9ab --- /dev/null +++ b/src/Cropper.Blazor/Client/Shared/SeoHeader.razor @@ -0,0 +1,12 @@ +@Title + + + + + @if (!string.IsNullOrEmpty(Overview)) + { + + + + } + \ No newline at end of file diff --git a/src/Cropper.Blazor/Client/Shared/SeoHeader.razor.cs b/src/Cropper.Blazor/Client/Shared/SeoHeader.razor.cs new file mode 100644 index 00000000..91cf0d2b --- /dev/null +++ b/src/Cropper.Blazor/Client/Shared/SeoHeader.razor.cs @@ -0,0 +1,54 @@ +using Microsoft.AspNetCore.Components; + +namespace Cropper.Blazor.Client.Shared +{ + public partial class SeoHeader + { + [Parameter] + public string? Title { get; set; } + + [Parameter] + public string? Overview { get; set; } + + [Parameter] + public IEnumerable Keywords { get; set; } = new List(); + + string GetSubTitle() + { + if (string.IsNullOrEmpty(Overview)) + return ""; + return Overview.TrimEnd('.') + "."; + } + + string GetKeywords() + { + var keywords = new List(); + + keywords.AddRange(Keywords); + + keywords.AddRange(new[] + { + "Cropper.Blazor", + "blazor", + "component", + "crop-image", + "cropper", + "cropperjs", + "Cropper.js", + "Blazor Components", + "Blazor Library", + "Blazor Cropper", + "Cropper", + "Image", + "Crop", + "Resize", + "image-cropper", + "crop-image", + "csharp", + "blazor-cropper" + }); + + return string.Join(", ", keywords); + } + } +} From 943f013bdb271bb85f47fb4528043b2d7c322e87 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Wed, 2 Aug 2023 14:30:56 +0300 Subject: [PATCH 041/196] Feature/add seo for wasm (#195) ## Target #### Open Questions ## Checklist - [ ] Documentation updated - [ ] Tests cover new or modified code - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .../Client/Cropper.Blazor.Client.csproj | 15 +++++----- .../Client/Extensions/DocsVeiewExtension.cs | 3 ++ src/Cropper.Blazor/Client/Pages/About.razor | 2 +- src/Cropper.Blazor/Client/Pages/Api.razor | 2 +- src/Cropper.Blazor/Client/Program.cs | 4 --- .../Cropper.Blazor.UnitTests.csproj | 2 +- .../Server/Cropper.Blazor.Server.csproj | 22 +++++++------- .../index.html => Server/Pages/_Host.cshtml} | 30 +++++++++++++++++-- .../Server/Pages/_Host.cshtml.cs | 11 +++++++ src/Cropper.Blazor/Server/Program.cs | 5 +++- 10 files changed, 66 insertions(+), 30 deletions(-) rename src/Cropper.Blazor/{Client/wwwroot/index.html => Server/Pages/_Host.cshtml} (82%) create mode 100644 src/Cropper.Blazor/Server/Pages/_Host.cshtml.cs diff --git a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj index ee7b3d0a..b53ea00f 100644 --- a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj +++ b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj @@ -27,13 +27,13 @@ - - - - - - - + + + + + + + @@ -160,7 +160,6 @@ - diff --git a/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs b/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs index 3ff7de2b..ee23c614 100644 --- a/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs +++ b/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs @@ -1,6 +1,7 @@ using Blazored.LocalStorage; using Cropper.Blazor.Client.Services; using Cropper.Blazor.Client.Services.UserPreferences; +using Cropper.Blazor.Extensions; using MudBlazor; using MudBlazor.Services; @@ -9,6 +10,8 @@ public static class DocsViewExtension { public static void TryAddDocsViewServices(this IServiceCollection services) { + services.AddCropper(); + services.AddMudServices(config => { config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomRight; diff --git a/src/Cropper.Blazor/Client/Pages/About.razor b/src/Cropper.Blazor/Client/Pages/About.razor index ef86d5ec..5f00f403 100644 --- a/src/Cropper.Blazor/Client/Pages/About.razor +++ b/src/Cropper.Blazor/Client/Pages/About.razor @@ -1,7 +1,7 @@ @page "/about" ("head::after"); builder.Services .AddScoped(sp => new HttpClient diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj index 1fc65ae7..de4c8218 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj @@ -9,7 +9,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Cropper.Blazor/Server/Cropper.Blazor.Server.csproj b/src/Cropper.Blazor/Server/Cropper.Blazor.Server.csproj index bc31deaa..92084a00 100644 --- a/src/Cropper.Blazor/Server/Cropper.Blazor.Server.csproj +++ b/src/Cropper.Blazor/Server/Cropper.Blazor.Server.csproj @@ -1,18 +1,18 @@  - - net7.0 - enable - enable - + + net7.0 + enable + enable + - - - + + + - - - + + + diff --git a/src/Cropper.Blazor/Client/wwwroot/index.html b/src/Cropper.Blazor/Server/Pages/_Host.cshtml similarity index 82% rename from src/Cropper.Blazor/Client/wwwroot/index.html rename to src/Cropper.Blazor/Server/Pages/_Host.cshtml index 15d27955..683e18c4 100644 --- a/src/Cropper.Blazor/Client/wwwroot/index.html +++ b/src/Cropper.Blazor/Server/Pages/_Host.cshtml @@ -1,11 +1,33 @@ +@page +@using Cropper.Blazor.Client; +@using Cropper.Blazor.Client.Shared; +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers + - + + + + + + + + + + + + + + + + + + - Cropper.Blazor + Cropper Blazor component for cropping images. @@ -22,6 +44,8 @@ + +
@@ -134,4 +158,4 @@ - + \ No newline at end of file diff --git a/src/Cropper.Blazor/Server/Pages/_Host.cshtml.cs b/src/Cropper.Blazor/Server/Pages/_Host.cshtml.cs new file mode 100644 index 00000000..e7e9cf83 --- /dev/null +++ b/src/Cropper.Blazor/Server/Pages/_Host.cshtml.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace Cropper.Blazor.Server.Pages +{ + public class _HostModel : PageModel + { + public void OnGet() + { + } + } +} diff --git a/src/Cropper.Blazor/Server/Program.cs b/src/Cropper.Blazor/Server/Program.cs index a80508e3..e7590f6f 100644 --- a/src/Cropper.Blazor/Server/Program.cs +++ b/src/Cropper.Blazor/Server/Program.cs @@ -1,9 +1,12 @@ +using Cropper.Blazor.Client.Extensions; + var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); builder.Services.AddRazorPages(); +builder.Services.TryAddDocsViewServices(); var app = builder.Build(); @@ -28,6 +31,6 @@ app.MapRazorPages(); app.MapControllers(); -app.MapFallbackToFile("index.html"); +app.MapFallbackToPage("/_Host"); app.Run(); From 8c5a9cda1f59b1ab1b8328edb63465b64e614885 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:26:55 +0300 Subject: [PATCH 042/196] Update cd.yml (#196) ## Target #### Open Questions Update cd.yml ## Checklist - [ ] Documentation updated - [x] Tests cover new or modified code - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .github/workflows/cd.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index f7ea99b3..ce9ec3a5 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -92,8 +92,8 @@ jobs: echo -n "$jsFile" > service-worker-assets.js # copy index.html to 404.html to serve the same file when a file is not found - - name: copy index.html to 404.html - run: cp release/wwwroot/index.html release/wwwroot/404.html + #- name: copy index.html to 404.html + # run: cp release/wwwroot/index.html release/wwwroot/404.html # add .nojekyll file to tell GitHub pages to not treat this as a Jekyll project. (Allow files and folders starting with an underscore) - name: Add .nojekyll file @@ -148,4 +148,4 @@ jobs: - name: DotNet Build Blazor MAUI Demo Project for .net 6 run: dotnet build --no-restore - working-directory: examples\Cropper.Blazor.MAUI.Net6 \ No newline at end of file + working-directory: examples\Cropper.Blazor.MAUI.Net6 From 30e9f49bb97441896578e210efa52a8b9060c563 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Wed, 10 May 2023 11:22:12 +0300 Subject: [PATCH 043/196] Fix dimensions settings --- .../Client/Pages/CropperDemo.razor.cs | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 208dfc1b..8a0b45b6 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -82,9 +82,6 @@ public async void OnCropEvent(JSEventData cropJSEvent) { if (cropJSEvent?.Detail is not null) { - ScaleXValue = cropJSEvent.Detail.ScaleX; - ScaleYValue = cropJSEvent.Detail.ScaleY; - decimal width = Math.Round(cropJSEvent.Detail.Width ?? 0); decimal height = Math.Round(cropJSEvent.Detail.Height ?? 0); @@ -94,15 +91,27 @@ public async void OnCropEvent(JSEventData cropJSEvent) || height > GetSetCropperData!.CroppedDimensionsSettings.MaximumHeight ) { - CropperComponent!.SetData(new SetDataOptions + decimal nWidth = Math.Max(GetSetCropperData!.CroppedDimensionsSettings.MinimumWidth ?? 0M, + Math.Min(GetSetCropperData!.CroppedDimensionsSettings.MaximumWidth ?? 0M, width)); + decimal nHeight = Math.Max(GetSetCropperData!.CroppedDimensionsSettings.MinimumHeight ?? 0M, + Math.Min(GetSetCropperData!.CroppedDimensionsSettings.MaximumHeight ?? 0M, height)); + + if (!IsEnableAspectRatioSettings) { - Width = Math.Max( - GetSetCropperData!.CroppedDimensionsSettings.MinimumWidth ?? 0M, - Math.Min(GetSetCropperData!.CroppedDimensionsSettings.MaximumWidth ?? 0M, width)), - Height = Math.Max( - GetSetCropperData!.CroppedDimensionsSettings.MinimumHeight ?? 0M, - Math.Min(GetSetCropperData!.CroppedDimensionsSettings.MaximumHeight ?? 0M, height)), + if (nWidth == 0) + { + nWidth = nHeight * AspectRatio; + } + else if (nHeight == 0) + { + nHeight = nWidth * AspectRatio; + } + } + CropperComponent!.SetData(new SetDataOptions + { + Width = nWidth, + Height = nHeight }); } else From c9b2af1831d5a53db3f8df3d24f80bd33e05d9c7 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Thu, 11 May 2023 09:56:01 +0300 Subject: [PATCH 044/196] Rename free aspect ratio variable --- .../Components/AspectRatioSettings.razor | 4 ++-- .../Components/AspectRatioSettings.razor.cs | 4 ++-- .../Client/Pages/CropperDemo.razor | 22 +++++++++---------- .../Client/Pages/CropperDemo.razor.cs | 16 +++++++------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor index 1dc9d5df..a786b447 100644 --- a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor @@ -11,11 +11,11 @@
diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs index b50c6d46..bc4d5b08 100644 --- a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs @@ -38,8 +38,8 @@ public decimal? MinAspectRatio [CascadingParameter(Name = "CropperComponent"), Required] private CropperComponent CropperComponent { get; set; } = null!; - [CascadingParameter(Name = "IsEnableAspectRatioSettings"), Required] - private bool IsEnableAspectRatioSettings + [CascadingParameter(Name = "IsFreeAspectRatioEnabled"), Required] + private bool IsFreeAspectRatioEnabled { get => isEnableAspectRatioSettings; set diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index a1fb1912..a8a5cc72 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -234,31 +234,31 @@ + Style="@(AspectRatio == 1.7777777777777777m && !IsFreeAspectRatioEnabled ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 16:9 + Style="@(AspectRatio == 1.3333333333333333m && !IsFreeAspectRatioEnabled ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 4:3 + Style="@(AspectRatio == 1m && !IsFreeAspectRatioEnabled ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 1:1 + Style="@(AspectRatio == 0.6666666666666666m && !IsFreeAspectRatioEnabled ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 2:3 + Style="@(IsFreeAspectRatioEnabled ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> Free @@ -350,31 +350,31 @@ + Style="@(AspectRatio == 1.7777777777777777m && !IsFreeAspectRatioEnabled ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 16:9 + Style="@(AspectRatio == 1.3333333333333333m && !IsFreeAspectRatioEnabled ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 4:3 + Style="@(AspectRatio == 1m && !IsFreeAspectRatioEnabled ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 1:1 + Style="@(AspectRatio == 0.6666666666666666m && !IsFreeAspectRatioEnabled ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> 2:3 + Style="@(IsFreeAspectRatioEnabled ? "background-color: var(--mud-palette-success-darken)" : "")" FullWidth="true"> Free @@ -444,7 +444,7 @@ @*//+---// Get/Set all cropper data //---+//*@ - + cropJSEvent) decimal nHeight = Math.Max(GetSetCropperData!.CroppedDimensionsSettings.MinimumHeight ?? 0M, Math.Min(GetSetCropperData!.CroppedDimensionsSettings.MaximumHeight ?? 0M, height)); - if (!IsEnableAspectRatioSettings) + if (!IsFreeAspectRatioEnabled) { if (nWidth == 0) { @@ -314,14 +314,14 @@ private void Destroy() CropperComponent?.RevokeObjectUrlAsync(Src); } - public void SetAspectRatio(decimal aspectRatio, bool isEnableAspectRatioSettings = false) + public void SetAspectRatio(decimal aspectRatio, bool isFreeAspectRatioEnabled = false) { - IsEnableAspectRatioSettings = isEnableAspectRatioSettings; + IsFreeAspectRatioEnabled = isFreeAspectRatioEnabled; - if (aspectRatio != 0) - { - AspectRatio = aspectRatio; - } + //if (aspectRatio != 0) + //{ + // AspectRatio = aspectRatio; + //} CropperComponent?.SetAspectRatio(aspectRatio); } From 457d2d0b0a4f9ba5308a29255f3f761299d1320a Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Wed, 2 Aug 2023 19:31:14 +0300 Subject: [PATCH 045/196] revert changes (#197) ## Target #### Open Questions ## Checklist - [ ] Documentation updated - [ ] Tests cover new or modified code - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .github/workflows/cd.yml | 4 +-- src/Cropper.Blazor/Client/Program.cs | 4 +++ .../wwwroot/index.html} | 33 ++++++++----------- .../Server/Pages/_Host.cshtml.cs | 11 ------- src/Cropper.Blazor/Server/Program.cs | 5 +-- 5 files changed, 20 insertions(+), 37 deletions(-) rename src/Cropper.Blazor/{Server/Pages/_Host.cshtml => Client/wwwroot/index.html} (93%) delete mode 100644 src/Cropper.Blazor/Server/Pages/_Host.cshtml.cs diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index ce9ec3a5..8e7d442f 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -92,8 +92,8 @@ jobs: echo -n "$jsFile" > service-worker-assets.js # copy index.html to 404.html to serve the same file when a file is not found - #- name: copy index.html to 404.html - # run: cp release/wwwroot/index.html release/wwwroot/404.html + - name: copy index.html to 404.html + run: cp release/wwwroot/index.html release/wwwroot/404.html # add .nojekyll file to tell GitHub pages to not treat this as a Jekyll project. (Allow files and folders starting with an underscore) - name: Add .nojekyll file diff --git a/src/Cropper.Blazor/Client/Program.cs b/src/Cropper.Blazor/Client/Program.cs index f41577df..5fbc41ed 100644 --- a/src/Cropper.Blazor/Client/Program.cs +++ b/src/Cropper.Blazor/Client/Program.cs @@ -1,8 +1,12 @@ +using Cropper.Blazor.Client; using Cropper.Blazor.Client.Extensions; using Cropper.Blazor.Extensions; +using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; var builder = WebAssemblyHostBuilder.CreateDefault(args); +builder.RootComponents.Add("#app"); +builder.RootComponents.Add("head::after"); builder.Services .AddScoped(sp => new HttpClient diff --git a/src/Cropper.Blazor/Server/Pages/_Host.cshtml b/src/Cropper.Blazor/Client/wwwroot/index.html similarity index 93% rename from src/Cropper.Blazor/Server/Pages/_Host.cshtml rename to src/Cropper.Blazor/Client/wwwroot/index.html index 683e18c4..dc8126cb 100644 --- a/src/Cropper.Blazor/Server/Pages/_Host.cshtml +++ b/src/Cropper.Blazor/Client/wwwroot/index.html @@ -1,9 +1,4 @@ -@page -@using Cropper.Blazor.Client; -@using Cropper.Blazor.Client.Shared; -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers - - + @@ -12,20 +7,20 @@ - - - - - + + + + + - - + + - - - - - + + + + + Cropper Blazor component for cropping images. @@ -44,8 +39,6 @@ - -
diff --git a/src/Cropper.Blazor/Server/Pages/_Host.cshtml.cs b/src/Cropper.Blazor/Server/Pages/_Host.cshtml.cs deleted file mode 100644 index e7e9cf83..00000000 --- a/src/Cropper.Blazor/Server/Pages/_Host.cshtml.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Microsoft.AspNetCore.Mvc.RazorPages; - -namespace Cropper.Blazor.Server.Pages -{ - public class _HostModel : PageModel - { - public void OnGet() - { - } - } -} diff --git a/src/Cropper.Blazor/Server/Program.cs b/src/Cropper.Blazor/Server/Program.cs index e7590f6f..a80508e3 100644 --- a/src/Cropper.Blazor/Server/Program.cs +++ b/src/Cropper.Blazor/Server/Program.cs @@ -1,12 +1,9 @@ -using Cropper.Blazor.Client.Extensions; - var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); builder.Services.AddRazorPages(); -builder.Services.TryAddDocsViewServices(); var app = builder.Build(); @@ -31,6 +28,6 @@ app.MapRazorPages(); app.MapControllers(); -app.MapFallbackToPage("/_Host"); +app.MapFallbackToFile("index.html"); app.Run(); From d48b0335869280727b397e9c1302d81b6ce85dbe Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Thu, 11 May 2023 11:22:32 +0300 Subject: [PATCH 046/196] Update Main Page --- .../Components/Docs/SectionContent.razor | 2 +- src/Cropper.Blazor/Client/Pages/Index.razor | 14 +- .../Client/Styles/Cropper.Blazor.Client.scss | 15 + .../Client/Styles/components/docssection.scss | 356 +++++++++--------- 4 files changed, 206 insertions(+), 181 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor index 31be8b04..fc6c380e 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor +++ b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor @@ -58,7 +58,7 @@
diff --git a/src/Cropper.Blazor/Client/Pages/Index.razor b/src/Cropper.Blazor/Client/Pages/Index.razor index 5b8c2ecf..a55fe225 100644 --- a/src/Cropper.Blazor/Client/Pages/Index.razor +++ b/src/Cropper.Blazor/Client/Pages/Index.razor @@ -23,14 +23,24 @@ - Cropper.Blazor - is a component that wraps around + Cropper.Blazor + is a component that wraps around Cropper.js + + + View Demo + + + Star on GitHub + +

Build and run test diff --git a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss index 6179f399..eb2fa284 100644 --- a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss +++ b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss @@ -96,6 +96,21 @@ html, body { height: 6px; } +.button-gradient { + position: relative; + animation-duration: 10s; + animation-delay: 1s; + animation-iteration-count: infinite; + animation-timing-function: ease; + animation-name: flow; + background-size: 400% 400%; + background-image: linear-gradient(82deg, #e73c7e 0%, #23a6d5 100%, #e73c7e 200%); +} + +.button-gradient:hover { + box-shadow: 0.3px 0.5px 0.4px hsla(200, 100%, 38%, 0.62), 0.3px 0.6px 0.5px -0.7px hsla(200, 100%, 38%, 0.54), 0.8px 1.6px 1.3px -1.4px hsla(200, 100%, 38%, 0.46), 2px 4.1px 3.4px -2.1px hsla(200, 100%, 38%, 0.38), 4.5px 9px 7.5px -2.9px hsla(200, 100%, 38%, 0.31), 8.5px 17.1px 14.3px -3.6px hsla(200, 100%, 38%, 0.23), 14.6px 29.2px 24.5px -4.3px hsla(200, 100%, 38%, 0.15), 23px 46px 38.6px -5px hsla(200, 100%, 38%, 0.08); +} + .cropper-error-load { max-height: inherit; max-width: inherit; diff --git a/src/Cropper.Blazor/Client/Styles/components/docssection.scss b/src/Cropper.Blazor/Client/Styles/components/docssection.scss index 0f33fde0..36741646 100644 --- a/src/Cropper.Blazor/Client/Styles/components/docssection.scss +++ b/src/Cropper.Blazor/Client/Styles/components/docssection.scss @@ -1,180 +1,180 @@ .docs-page-section { - .docs-section-header { - .mud-typography-h5 { - margin-top: 60px; - margin-bottom: 20px; - } - - .mud-typography-h6 { - margin-top: 32px; - margin-bottom: 12px; - } - } - - .docs-section-source { - position: relative; - overflow: hidden; - border-radius: 8px; - background-color: var(--mud-palette-background-grey); - transition: border-radius 250ms cubic-bezier(0.4, 0, 0.2, 1); - - .copy-code-button { - position: absolute; - bottom: 8px; - right: 8px; - color: rgba(5, 0, 51, 0); - transition: color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; - } - - .docs-section-source-container { - max-height: 0; - overflow: hidden; - transition: max-height 0.15s ease-out; - } - - &.show-code { - .docs-section-source-container { - overflow: auto; - max-height: 500px; - transition: max-height 0.25s ease-in; - - &::-webkit-scrollbar-thumb { - border-bottom-right-radius: 0; - } - } - } - - &:hover { - .copy-code-button { - color: var(--mud-palette-text-secondary) !important; - background-color: transparent; - } - } - } - - .docs-section-content { - border-radius: 8px; - background-color: var(--mud-palette-surface); - transition: border-radius 250ms cubic-bezier(0.4, 0, 0.2, 1); - display: flex; - flex-direction: column; - position: relative; - - .docs-section-content-toolbar { - height: unset; - padding: 0; - border-radius: 8px 8px 0 0; - - .mud-button { - text-transform: none; - font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; - font-size: 14px; - border-radius: 0; - padding: 4px 8px; - - &.file-button { - border-color: var(--mud-palette-lines-default); - letter-spacing: normal; - margin-top: -1px; - - &:first-child { - border-top-left-radius: 8px; - } - } - - &:last-child:not(.file-button) { - border-top-right-radius: 8px; - } - } - - &.darken { - background-color: var(--mud-palette-grey-light); - - .file-button { - &.active { - background-color: var(--mud-palette-background-grey); - } - } - } - - &.outlined { - .file-button { - &:not(.active) { - border: 1px solid var(--mud-palette-lines-default); - border-top: none; - border-radius: 0 0 4px 4px; - - &:first-child { - border-top-left-radius: 8px; - border-bottom-left-radius: 0; - border-left: none; - } - } - - &.active { - color: var(--mud-palette-primary); - } - } - } - } - - .docs-section-content-inner { - & > *:not(.mud-grid) { - margin: 8px; - } - } - - &.darken { - background: linear-gradient(0deg, var(--mud-palette-grey-lighter) 0%, var(--mud-palette-background-grey) 50%); - } - - &.outlined { - border: 1px solid var(--mud-palette-lines-default); - } - - &.show-code { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - - &.outlined { - border-bottom: none; - } - - + .docs-section-source { - border-top-left-radius: 0; - border-top-right-radius: 0; - - &.outlined { - border: 1px solid var(--mud-palette-lines-default); - } - } - } - } - - .docs-code { - display: inline-block; - padding: 0 5px; - direction: ltr; - font-size: 0.85em; - font-weight: 900; - font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; - line-height: 1.4; - border-radius: 2px; - -webkit-font-smoothing: subpixel-antialiased; - - &.docs-code-primary { - color: var(--mud-palette-primary); - background-color: var(--mud-palette-primary-hover); - } - - &.docs-code-secondary { - color: var(--mud-palette-secondary); - background-color: var(--mud-palette-secondary-hover); - } - - &.docs-code-tertiary { - color: var(--mud-palette-tertiary); - background-color: var(--mud-palette-tertiary-hover); - } - } + .docs-section-header { + .mud-typography-h5 { + margin-top: 60px; + margin-bottom: 20px; + } + + .mud-typography-h6 { + margin-top: 32px; + margin-bottom: 12px; + } + } + + .docs-section-source { + position: relative; + overflow: hidden; + border-radius: 8px; + background-color: var(--mud-palette-background-grey); + transition: border-radius 250ms cubic-bezier(0.4, 0, 0.2, 1); + + .copy-code-button { + position: absolute; + bottom: 8px; + right: 8px; + color: rgba(5, 0, 51, 0); + transition: color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + } + + .docs-section-source-container { + max-height: 0; + overflow: hidden; + transition: max-height 0.15s ease-out; + } + + &.show-code { + .docs-section-source-container { + overflow: auto; + max-height: 500px; + transition: max-height 0.25s ease-in; + + &::-webkit-scrollbar-thumb { + border-bottom-right-radius: 0; + } + } + } + + &:hover { + .copy-code-button { + color: var(--mud-palette-secondary-darken) !important; + background-color: transparent; + } + } + } + + .docs-section-content { + border-radius: 8px; + background-color: var(--mud-palette-surface); + transition: border-radius 250ms cubic-bezier(0.4, 0, 0.2, 1); + display: flex; + flex-direction: column; + position: relative; + + .docs-section-content-toolbar { + height: unset; + padding: 0; + border-radius: 8px 8px 0 0; + + .mud-button { + text-transform: none; + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; + font-size: 14px; + border-radius: 0; + padding: 4px 8px; + + &.file-button { + border-color: var(--mud-palette-lines-default); + letter-spacing: normal; + margin-top: -1px; + + &:first-child { + border-top-left-radius: 8px; + } + } + + &:last-child:not(.file-button) { + border-top-right-radius: 8px; + } + } + + &.darken { + background-color: var(--mud-palette-grey-light); + + .file-button { + &.active { + background-color: var(--mud-palette-background-grey); + } + } + } + + &.outlined { + .file-button { + &:not(.active) { + border: 1px solid var(--mud-palette-lines-default); + border-top: none; + border-radius: 0 0 4px 4px; + + &:first-child { + border-top-left-radius: 8px; + border-bottom-left-radius: 0; + border-left: none; + } + } + + &.active { + color: var(--mud-palette-primary); + } + } + } + } + + .docs-section-content-inner { + & > *:not(.mud-grid) { + margin: 8px; + } + } + + &.darken { + background: linear-gradient(0deg, var(--mud-palette-grey-lighter) 0%, var(--mud-palette-background-grey) 50%); + } + + &.outlined { + border: 1px solid var(--mud-palette-lines-default); + } + + &.show-code { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + + &.outlined { + border-bottom: none; + } + + + .docs-section-source { + border-top-left-radius: 0; + border-top-right-radius: 0; + + &.outlined { + border: 1px solid var(--mud-palette-lines-default); + } + } + } + } + + .docs-code { + display: inline-block; + padding: 0 5px; + direction: ltr; + font-size: 0.85em; + font-weight: 900; + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; + line-height: 1.4; + border-radius: 2px; + -webkit-font-smoothing: subpixel-antialiased; + + &.docs-code-primary { + color: var(--mud-palette-primary); + background-color: var(--mud-palette-primary-hover); + } + + &.docs-code-secondary { + color: var(--mud-palette-secondary); + background-color: var(--mud-palette-secondary-hover); + } + + &.docs-code-tertiary { + color: var(--mud-palette-tertiary); + background-color: var(--mud-palette-tertiary-hover); + } + } } From 1c2841ee436c5d399f8ec8fe6b3f5a7f5388bf77 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Thu, 11 May 2023 11:35:11 +0300 Subject: [PATCH 047/196] Fix warnings in scss --- .../Client/Styles/Cropper.Blazor.Client.scss | 23 ++++++++++--------- .../Client/Styles/components/docssection.scss | 6 ++--- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss index eb2fa284..1734bf43 100644 --- a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss +++ b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss @@ -7,7 +7,8 @@ user-select: none; } -html, body { +html, +body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } @@ -97,18 +98,18 @@ html, body { } .button-gradient { - position: relative; - animation-duration: 10s; - animation-delay: 1s; - animation-iteration-count: infinite; - animation-timing-function: ease; - animation-name: flow; - background-size: 400% 400%; - background-image: linear-gradient(82deg, #e73c7e 0%, #23a6d5 100%, #e73c7e 200%); + position: relative; + animation-duration: 10s; + animation-delay: 1s; + animation-iteration-count: infinite; + animation-timing-function: ease; + animation-name: flow; + background-size: 400% 400%; + background-image: linear-gradient(82deg, #e73c7e 0%, #23a6d5 100%, #e73c7e 200%); } .button-gradient:hover { - box-shadow: 0.3px 0.5px 0.4px hsla(200, 100%, 38%, 0.62), 0.3px 0.6px 0.5px -0.7px hsla(200, 100%, 38%, 0.54), 0.8px 1.6px 1.3px -1.4px hsla(200, 100%, 38%, 0.46), 2px 4.1px 3.4px -2.1px hsla(200, 100%, 38%, 0.38), 4.5px 9px 7.5px -2.9px hsla(200, 100%, 38%, 0.31), 8.5px 17.1px 14.3px -3.6px hsla(200, 100%, 38%, 0.23), 14.6px 29.2px 24.5px -4.3px hsla(200, 100%, 38%, 0.15), 23px 46px 38.6px -5px hsla(200, 100%, 38%, 0.08); + box-shadow: 0.3px 0.5px 0.4px hsla(200, 100%, 38%, 0.62), 0.3px 0.6px 0.5px -0.7px hsla(200, 100%, 38%, 0.54), 0.8px 1.6px 1.3px -1.4px hsla(200, 100%, 38%, 0.46), 2px 4.1px 3.4px -2.1px hsla(200, 100%, 38%, 0.38), 4.5px 9px 7.5px -2.9px hsla(200, 100%, 38%, 0.31), 8.5px 17.1px 14.3px -3.6px hsla(200, 100%, 38%, 0.23), 14.6px 29.2px 24.5px -4.3px hsla(200, 100%, 38%, 0.15), 23px 46px 38.6px -5px hsla(200, 100%, 38%, 0.08); } .cropper-error-load { @@ -152,4 +153,4 @@ html, body { .img-container.cropper-face-pentagon .cropper-container .cropper-crop-box .cropper-face { clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); -} +} \ No newline at end of file diff --git a/src/Cropper.Blazor/Client/Styles/components/docssection.scss b/src/Cropper.Blazor/Client/Styles/components/docssection.scss index 36741646..49c43545 100644 --- a/src/Cropper.Blazor/Client/Styles/components/docssection.scss +++ b/src/Cropper.Blazor/Client/Styles/components/docssection.scss @@ -119,7 +119,7 @@ } .docs-section-content-inner { - & > *:not(.mud-grid) { + &>*:not(.mud-grid) { margin: 8px; } } @@ -140,7 +140,7 @@ border-bottom: none; } - + .docs-section-source { + +.docs-section-source { border-top-left-radius: 0; border-top-right-radius: 0; @@ -177,4 +177,4 @@ background-color: var(--mud-palette-tertiary-hover); } } -} +} \ No newline at end of file From 7c7ec2b07ffc23f606659fa079b0fac78ab13505 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Thu, 11 May 2023 11:36:03 +0300 Subject: [PATCH 048/196] Fix warnings in scss --- .../Client/Styles/components/docssection.scss | 358 +++++++++--------- 1 file changed, 179 insertions(+), 179 deletions(-) diff --git a/src/Cropper.Blazor/Client/Styles/components/docssection.scss b/src/Cropper.Blazor/Client/Styles/components/docssection.scss index 49c43545..f83b32cf 100644 --- a/src/Cropper.Blazor/Client/Styles/components/docssection.scss +++ b/src/Cropper.Blazor/Client/Styles/components/docssection.scss @@ -1,180 +1,180 @@ .docs-page-section { - .docs-section-header { - .mud-typography-h5 { - margin-top: 60px; - margin-bottom: 20px; - } - - .mud-typography-h6 { - margin-top: 32px; - margin-bottom: 12px; - } - } - - .docs-section-source { - position: relative; - overflow: hidden; - border-radius: 8px; - background-color: var(--mud-palette-background-grey); - transition: border-radius 250ms cubic-bezier(0.4, 0, 0.2, 1); - - .copy-code-button { - position: absolute; - bottom: 8px; - right: 8px; - color: rgba(5, 0, 51, 0); - transition: color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; - } - - .docs-section-source-container { - max-height: 0; - overflow: hidden; - transition: max-height 0.15s ease-out; - } - - &.show-code { - .docs-section-source-container { - overflow: auto; - max-height: 500px; - transition: max-height 0.25s ease-in; - - &::-webkit-scrollbar-thumb { - border-bottom-right-radius: 0; - } - } - } - - &:hover { - .copy-code-button { - color: var(--mud-palette-secondary-darken) !important; - background-color: transparent; - } - } - } - - .docs-section-content { - border-radius: 8px; - background-color: var(--mud-palette-surface); - transition: border-radius 250ms cubic-bezier(0.4, 0, 0.2, 1); - display: flex; - flex-direction: column; - position: relative; - - .docs-section-content-toolbar { - height: unset; - padding: 0; - border-radius: 8px 8px 0 0; - - .mud-button { - text-transform: none; - font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; - font-size: 14px; - border-radius: 0; - padding: 4px 8px; - - &.file-button { - border-color: var(--mud-palette-lines-default); - letter-spacing: normal; - margin-top: -1px; - - &:first-child { - border-top-left-radius: 8px; - } - } - - &:last-child:not(.file-button) { - border-top-right-radius: 8px; - } - } - - &.darken { - background-color: var(--mud-palette-grey-light); - - .file-button { - &.active { - background-color: var(--mud-palette-background-grey); - } - } - } - - &.outlined { - .file-button { - &:not(.active) { - border: 1px solid var(--mud-palette-lines-default); - border-top: none; - border-radius: 0 0 4px 4px; - - &:first-child { - border-top-left-radius: 8px; - border-bottom-left-radius: 0; - border-left: none; - } - } - - &.active { - color: var(--mud-palette-primary); - } - } - } - } - - .docs-section-content-inner { - &>*:not(.mud-grid) { - margin: 8px; - } - } - - &.darken { - background: linear-gradient(0deg, var(--mud-palette-grey-lighter) 0%, var(--mud-palette-background-grey) 50%); - } - - &.outlined { - border: 1px solid var(--mud-palette-lines-default); - } - - &.show-code { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - - &.outlined { - border-bottom: none; - } - - +.docs-section-source { - border-top-left-radius: 0; - border-top-right-radius: 0; - - &.outlined { - border: 1px solid var(--mud-palette-lines-default); - } - } - } - } - - .docs-code { - display: inline-block; - padding: 0 5px; - direction: ltr; - font-size: 0.85em; - font-weight: 900; - font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; - line-height: 1.4; - border-radius: 2px; - -webkit-font-smoothing: subpixel-antialiased; - - &.docs-code-primary { - color: var(--mud-palette-primary); - background-color: var(--mud-palette-primary-hover); - } - - &.docs-code-secondary { - color: var(--mud-palette-secondary); - background-color: var(--mud-palette-secondary-hover); - } - - &.docs-code-tertiary { - color: var(--mud-palette-tertiary); - background-color: var(--mud-palette-tertiary-hover); - } - } -} \ No newline at end of file + .docs-section-header { + .mud-typography-h5 { + margin-top: 60px; + margin-bottom: 20px; + } + + .mud-typography-h6 { + margin-top: 32px; + margin-bottom: 12px; + } + } + + .docs-section-source { + position: relative; + overflow: hidden; + border-radius: 8px; + background-color: var(--mud-palette-background-grey); + transition: border-radius 250ms cubic-bezier(0.4, 0, 0.2, 1); + + .copy-code-button { + position: absolute; + bottom: 8px; + right: 8px; + color: rgba(5, 0, 51, 0); + transition: color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + } + + .docs-section-source-container { + max-height: 0; + overflow: hidden; + transition: max-height 0.15s ease-out; + } + + &.show-code { + .docs-section-source-container { + overflow: auto; + max-height: 500px; + transition: max-height 0.25s ease-in; + + &::-webkit-scrollbar-thumb { + border-bottom-right-radius: 0; + } + } + } + + &:hover { + .copy-code-button { + color: var(--mud-palette-secondary-darken) !important; + background-color: transparent; + } + } + } + + .docs-section-content { + border-radius: 8px; + background-color: var(--mud-palette-surface); + transition: border-radius 250ms cubic-bezier(0.4, 0, 0.2, 1); + display: flex; + flex-direction: column; + position: relative; + + .docs-section-content-toolbar { + height: unset; + padding: 0; + border-radius: 8px 8px 0 0; + + .mud-button { + text-transform: none; + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; + font-size: 14px; + border-radius: 0; + padding: 4px 8px; + + &.file-button { + border-color: var(--mud-palette-lines-default); + letter-spacing: normal; + margin-top: -1px; + + &:first-child { + border-top-left-radius: 8px; + } + } + + &:last-child:not(.file-button) { + border-top-right-radius: 8px; + } + } + + &.darken { + background-color: var(--mud-palette-grey-light); + + .file-button { + &.active { + background-color: var(--mud-palette-background-grey); + } + } + } + + &.outlined { + .file-button { + &:not(.active) { + border: 1px solid var(--mud-palette-lines-default); + border-top: none; + border-radius: 0 0 4px 4px; + + &:first-child { + border-top-left-radius: 8px; + border-bottom-left-radius: 0; + border-left: none; + } + } + + &.active { + color: var(--mud-palette-primary); + } + } + } + } + + .docs-section-content-inner { + & > *:not(.mud-grid) { + margin: 8px; + } + } + + &.darken { + background: linear-gradient(0deg, var(--mud-palette-grey-lighter) 0%, var(--mud-palette-background-grey) 50%); + } + + &.outlined { + border: 1px solid var(--mud-palette-lines-default); + } + + &.show-code { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + + &.outlined { + border-bottom: none; + } + + + .docs-section-source { + border-top-left-radius: 0; + border-top-right-radius: 0; + + &.outlined { + border: 1px solid var(--mud-palette-lines-default); + } + } + } + } + + .docs-code { + display: inline-block; + padding: 0 5px; + direction: ltr; + font-size: 0.85em; + font-weight: 900; + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; + line-height: 1.4; + border-radius: 2px; + -webkit-font-smoothing: subpixel-antialiased; + + &.docs-code-primary { + color: var(--mud-palette-primary); + background-color: var(--mud-palette-primary-hover); + } + + &.docs-code-secondary { + color: var(--mud-palette-secondary); + background-color: var(--mud-palette-secondary-hover); + } + + &.docs-code-tertiary { + color: var(--mud-palette-tertiary); + background-color: var(--mud-palette-tertiary-hover); + } + } +} From 85e49de1aabefcbe77dfd0095d2e11b6f4178e93 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Wed, 2 Aug 2023 20:25:01 +0300 Subject: [PATCH 049/196] verify site in google search console (#198) ## Target verify site in google search console #### Open Questions ## Checklist - [ ] Documentation updated - [ ] Tests cover new or modified code - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- src/Cropper.Blazor/Client/wwwroot/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Cropper.Blazor/Client/wwwroot/index.html b/src/Cropper.Blazor/Client/wwwroot/index.html index dc8126cb..149302ff 100644 --- a/src/Cropper.Blazor/Client/wwwroot/index.html +++ b/src/Cropper.Blazor/Client/wwwroot/index.html @@ -21,6 +21,7 @@ + Cropper Blazor component for cropping images. From d25c43a8bf61ec114ed3269de64aa94a434bd48f Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Fri, 12 May 2023 11:50:01 +0300 Subject: [PATCH 050/196] Fix warnings in scss --- src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss index 1734bf43..e107222b 100644 --- a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss +++ b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss @@ -7,8 +7,7 @@ user-select: none; } -html, -body { +html, body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } @@ -153,4 +152,4 @@ body { .img-container.cropper-face-pentagon .cropper-container .cropper-crop-box .cropper-face { clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); -} \ No newline at end of file +} From 1d308b1f966eee9a4b23d96140515c868be3df29 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Thu, 3 Aug 2023 11:24:42 +0300 Subject: [PATCH 051/196] Added sitemap.xml file (#199) ## Target Added sitemap.xml file #### Open Questions ## Checklist - [ ] Documentation updated - [x] Tests cover new or modified code - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- src/Cropper.Blazor/Client/wwwroot/sitemap.xml | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/Cropper.Blazor/Client/wwwroot/sitemap.xml diff --git a/src/Cropper.Blazor/Client/wwwroot/sitemap.xml b/src/Cropper.Blazor/Client/wwwroot/sitemap.xml new file mode 100644 index 00000000..03dff367 --- /dev/null +++ b/src/Cropper.Blazor/Client/wwwroot/sitemap.xml @@ -0,0 +1,27 @@ + + + + https://cropperblazor.github.io/ + 2023-08-02T21:02:02+03:00 + daily + 1.0 + + + https://cropperblazor.github.io/demo + 2023-08-02T21:02:02+03:00 + daily + 0.9 + + + https://cropperblazor.github.io/api + 2023-08-02T21:02:02+03:00 + daily + 0.8 + + + https://cropperblazor.github.io/about + 2023-08-02T21:02:02+03:00 + daily + 0.7 + + \ No newline at end of file From 5b8369f6de72ac6757a36b0a362ec4c83214f662 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Sat, 5 Aug 2023 17:04:02 +0300 Subject: [PATCH 052/196] fix UI bugs (#200) ## Target #### Open Questions ## Checklist - [ ] Documentation updated - [ ] Tests cover new or modified code - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .../Components/AspectRatioSettings.razor.cs | 11 ++- .../Components/Docs/SectionContent.razor.cs | 79 +++++++++++-------- .../Components/ZoomRatioSettings.razor.cs | 8 +- .../Client/Pages/CropperDemo.razor | 4 +- .../Client/Pages/CropperDemo.razor.cs | 3 + src/Cropper.Blazor/Client/Pages/Index.razor | 8 +- .../CodeSnippetsCompiler.cs | 9 ++- .../Cropper.Blazor.Client.Compiler/Program.cs | 3 +- 8 files changed, 72 insertions(+), 53 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs index bc4d5b08..39fc42a2 100644 --- a/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs +++ b/src/Cropper.Blazor/Client/Components/AspectRatioSettings.razor.cs @@ -1,5 +1,4 @@ using System.ComponentModel.DataAnnotations; -using Cropper.Blazor.Client.Pages; using Cropper.Blazor.Components; using Cropper.Blazor.Models; using Microsoft.AspNetCore.Components; @@ -18,7 +17,7 @@ public decimal? MaxAspectRatio set { maxAspectRatio = value; - ApplyAspectRatioRulesForCropperAsync(); + InvokeAsync(ApplyAspectRatioRulesForCropperAsync); } } @@ -28,7 +27,7 @@ public decimal? MinAspectRatio set { minAspectRatio = value; - ApplyAspectRatioRulesForCropperAsync(); + InvokeAsync(ApplyAspectRatioRulesForCropperAsync); } } @@ -68,12 +67,16 @@ public async Task ApplyAspectRatioRulesForCropperAsync() if (aspectRatio < minAspectRatio || aspectRatio > maxAspectRatio) { decimal? newCropBoxWidth = cropBoxData.Height * ((minAspectRatio + maxAspectRatio) / 2); + decimal? left = (containerData.Width - newCropBoxWidth) / 2; CropperComponent!.SetCropBoxData(new SetCropBoxDataOptions { - Left = (containerData.Width - newCropBoxWidth) / 2, + Left = left, Width = newCropBoxWidth, }); + + cropBoxData = await CropperComponent!.GetCropBoxDataAsync(); + aspectRatio = cropBoxData.Width / cropBoxData.Height; } SetUpAspectRatio(aspectRatio); diff --git a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs index 6d927df3..51cf10ec 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs +++ b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs @@ -2,15 +2,14 @@ using Cropper.Blazor.Client.Models; using Microsoft.AspNetCore.Components; using MudBlazor; -using MudBlazor.Services; using MudBlazor.Utilities; namespace Cropper.Blazor.Client.Components.Docs; -public partial class SectionContent +public partial class SectionContent : IBrowserViewportObserver { [Inject] protected IJsApiService? JsApiService { get; set; } - [Inject] IBreakpointService BreakpointService { get; set; } = null!; + [Inject] IBrowserViewportService BreakpointService { get; set; } = null!; protected string Classname => new CssBuilder("docs-section-content") @@ -41,28 +40,30 @@ public partial class SectionContent .AddClass("show-code", HasCode && ShowCode) .Build(); - [Parameter] public string Class { get; set; } + [Parameter] public string Class { get; set; } = string.Empty; [Parameter] public bool DarkenBackground { get; set; } [Parameter] public bool Outlined { get; set; } = true; [Parameter] public bool ShowCode { get; set; } = true; [Parameter] public bool Block { get; set; } [Parameter] public bool FullWidth { get; set; } - [Parameter] public string Code { get; set; } - [Parameter] public string HighLight { get; set; } - [Parameter] public IEnumerable Codes { get; set; } - [Parameter] public RenderFragment ChildContent { get; set; } + [Parameter] public string Code { get; set; } = string.Empty; + [Parameter] public string HighLight { get; set; } = string.Empty; + [Parameter] public IEnumerable? Codes { get; set; } = null; + [Parameter] public RenderFragment ChildContent { get; set; } = null!; private bool HasCode; - public string ActiveCode; + public string ActiveCode = string.Empty; private bool IsVerticalAlign = false; + Guid IBrowserViewportObserver.Id { get; } = Guid.NewGuid(); + protected override void OnParametersSet() { if (Codes != null) { HasCode = true; - ActiveCode = Codes.FirstOrDefault().code; + ActiveCode = Codes.First().code; } else if (!string.IsNullOrWhiteSpace(Code)) { @@ -75,11 +76,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { - await BreakpointService!.SubscribeAsync((br) => - { - IsVerticalAlign = BreakpointService!.IsMediaSize(br, Breakpoint.Xs); - InvokeAsync(StateHasChanged); - }); + await BreakpointService!.SubscribeAsync(this, fireImmediately: true); } await base.OnAfterRenderAsync(firstRender); @@ -116,35 +113,49 @@ RenderFragment CodeComponent(string code) => builder => { try { - var key = typeof(SectionContent).Assembly.GetManifestResourceNames().FirstOrDefault(x => x.Contains($".{code}Code.html")); - using (var stream = typeof(SectionContent).Assembly.GetManifestResourceStream(key)) - using (var reader = new StreamReader(stream)) - { - var read = reader.ReadToEnd(); + string? key = typeof(SectionContent).Assembly.GetManifestResourceNames().FirstOrDefault(x => x.Contains($".{code}Code.html")); + using var stream = typeof(SectionContent).Assembly.GetManifestResourceStream(key!); + using var reader = new StreamReader(stream!); + var read = reader.ReadToEnd(); - if (!string.IsNullOrEmpty(HighLight)) + if (!string.IsNullOrEmpty(HighLight)) + { + if (HighLight.Contains(',')) { - if (HighLight.Contains(",")) - { - var highlights = HighLight.Split(","); + var highlights = HighLight.Split(","); - foreach (var value in highlights) - { - read = Regex.Replace(read, $"{value}(?=\\s|\")", $"$&"); - } - } - else + foreach (var value in highlights) { - read = Regex.Replace(read, $"{HighLight}(?=\\s|\")", $"$&"); + read = Regex.Replace(read, $"{value}(?=\\s|\")", $"$&"); } } - - builder.AddMarkupContent(0, read); + else + { + read = Regex.Replace(read, $"{HighLight}(?=\\s|\")", $"$&"); + } } + + builder.AddMarkupContent(0, read); } catch (Exception ex) { - Console.WriteLine(ex.Message); + Console.WriteLine(ex.StackTrace); } }; + + public async Task NotifyBrowserViewportChangeAsync(BrowserViewportEventArgs browserViewportEventArgs) + { + if (browserViewportEventArgs.BrowserWindowSize.Width < 600) + { + IsVerticalAlign = true; + } + else + { + IsVerticalAlign = false; + } + + await InvokeAsync(StateHasChanged); + } + + public async ValueTask DisposeAsync() => await BreakpointService.UnsubscribeAsync(this); } diff --git a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs index d7fe871c..5beae325 100644 --- a/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs +++ b/src/Cropper.Blazor/Client/Components/ZoomRatioSettings.razor.cs @@ -1,9 +1,9 @@ -using Cropper.Blazor.Components; +using System.ComponentModel.DataAnnotations; +using Cropper.Blazor.Components; using Cropper.Blazor.Events.ZoomEvent; using Cropper.Blazor.Models; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; -using System.ComponentModel.DataAnnotations; namespace Cropper.Blazor.Client.Components { @@ -18,7 +18,7 @@ private decimal? MinZoomRatio set { minZoomRatio = value; - ApplyZoomRulesForCropperAsync(); + InvokeAsync(ApplyZoomRulesForCropperAsync); } } private decimal? MaxZoomRatio @@ -27,7 +27,7 @@ private decimal? MaxZoomRatio set { maxZoomRatio = value; - ApplyZoomRulesForCropperAsync(); + InvokeAsync(ApplyZoomRulesForCropperAsync); } } [Inject] private IJSRuntime? JSRuntime { get; set; } diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index 60fc1a17..7be9b6b4 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -117,10 +117,10 @@ - + - + diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 64b042a5..d9969711 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -82,6 +82,9 @@ public async void OnCropEvent(JSEventData cropJSEvent) { if (cropJSEvent?.Detail is not null) { + ScaleXValue = cropJSEvent.Detail.ScaleX; + ScaleYValue = cropJSEvent.Detail.ScaleY; + decimal width = Math.Round(cropJSEvent.Detail.Width ?? 0); decimal height = Math.Round(cropJSEvent.Detail.Height ?? 0); diff --git a/src/Cropper.Blazor/Client/Pages/Index.razor b/src/Cropper.Blazor/Client/Pages/Index.razor index 6912e45d..9617fc48 100644 --- a/src/Cropper.Blazor/Client/Pages/Index.razor +++ b/src/Cropper.Blazor/Client/Pages/Index.razor @@ -22,7 +22,7 @@ - Cropper.Blazor + Cropper.Blazor @@ -42,12 +42,12 @@ - View Demo + Class="button-gradient" Size="Size.Large" Href="/demo"> + View Demo - Star on GitHub + Star on GitHub

diff --git a/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/CodeSnippetsCompiler.cs b/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/CodeSnippetsCompiler.cs index 71196864..bee529cb 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/CodeSnippetsCompiler.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/CodeSnippetsCompiler.cs @@ -6,9 +6,9 @@ namespace Cropper.Blazor.Client.Compiler; -public class CodeSnippetsCompiler +public partial class CodeSnippetsCompiler { - public bool Execute() + public static bool Execute() { var paths = new Paths(); var success = true; @@ -61,7 +61,10 @@ public bool Execute() private static string EscapeComponentSource(string path) { var source = File.ReadAllText(path, Encoding.UTF8); - source = Regex.Replace(source, "@(namespace|layout|page) .+?\n", string.Empty); + source = EscapeComponentSourceRegex().Replace(source, string.Empty); return source.Replace("\"", "\"\"").Trim(); } + + [GeneratedRegex("@(namespace|layout|page) .+?\n")] + private static partial Regex EscapeComponentSourceRegex(); } diff --git a/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/Program.cs b/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/Program.cs index c84c9583..8cdaaaff 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/Program.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/Program.cs @@ -8,8 +8,7 @@ public class Program public static int Main() { var stopWatch = Stopwatch.StartNew(); - var success = - new CodeSnippetsCompiler().Execute(); + var success = CodeSnippetsCompiler.Execute(); Console.WriteLine($"Docs.Compiler completed in {stopWatch.ElapsedMilliseconds} msecs"); return success ? 0 : 1; From e9e922711d245c497914d108a3536236afaaf082 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Fri, 12 May 2023 14:21:34 +0300 Subject: [PATCH 053/196] New layouts --- .../Client/Shared/DocsLayout.razor | 80 ++++++++++++ .../Client/Shared/DocsLayout.razor.cs | 5 + .../Client/Shared/LandingLayout.razor | 30 +++++ .../Client/Shared/LandingLayout.razor.cs | 102 +++++++++++++++ .../Client/Shared/MainLayout.razor | 34 +---- .../Client/Shared/MainLayout.razor.cs | 120 +++++------------- src/Cropper.Blazor/Client/_Imports.razor | 1 + 7 files changed, 259 insertions(+), 113 deletions(-) create mode 100644 src/Cropper.Blazor/Client/Shared/DocsLayout.razor create mode 100644 src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs create mode 100644 src/Cropper.Blazor/Client/Shared/LandingLayout.razor create mode 100644 src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs diff --git a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor new file mode 100644 index 00000000..37c5ce3d --- /dev/null +++ b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor @@ -0,0 +1,80 @@ +@inherits LayoutComponentBase +@layout MainLayout + + + + + + + + + + @if (_topMenuOpen == false) + { + + } + else + { + + } + + + + + @if (_topMenuOpen == true) + { + + Docs + Getting Started + Discover More + + MudBlazor + TryMudBlazor + ThemeManager + Templates + Coming soon + MudStore + MudAcademy + MudExtensions + + + } + + + @if (!_topMenuOpen && LayoutService.GetDocsBasePage(NavigationManager.Uri) == DocsBasePage.Docs) + { + + } + else if (!_topMenuOpen && LayoutService.GetDocsBasePage(NavigationManager.Uri) == DocsBasePage.GettingStarted) + { + Getting Started + Installation + Layouts + Usage + Wireframes + } + else if (!_topMenuOpen && LayoutService.GetDocsBasePage(NavigationManager.Uri) == DocsBasePage.DiscoverMore) + { + Discover More + What is MudBlazor? + + Getting Help + Reporting Bugs + Contribution + + + Announcements + How it started + Releases + Roadmap + Sponsors & Backers + Team & Contributors + + } + + + @Body + + + + \ No newline at end of file diff --git a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs new file mode 100644 index 00000000..27a310a3 --- /dev/null +++ b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs @@ -0,0 +1,5 @@ +namespace Cropper.Blazor.Client.Shared; + +public partial class DocsLayout +{ +} \ No newline at end of file diff --git a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor new file mode 100644 index 00000000..15be5a99 --- /dev/null +++ b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor @@ -0,0 +1,30 @@ +@inherits LayoutComponentBase +@using Cropper.Blazor.Client.Enums + + + + + + + + + + + + + + + + + + + Demo + Api + About + + + + + @Body + + diff --git a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs new file mode 100644 index 00000000..639ef2e7 --- /dev/null +++ b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs @@ -0,0 +1,102 @@ +using Cropper.Blazor.Client.Enums; +using Cropper.Blazor.Client.Services; +using Microsoft.AspNetCore.Components; +using MudBlazor.Services; + +namespace Cropper.Blazor.Client.Shared; +public partial class LandingLayout : LayoutComponentBase +{ + [Inject] private LayoutService LayoutService { get; set; } = null!; + + [Inject] private NavigationManager NavigationManager { get; set; } = null!; + + [Inject] IResizeService ResizeService { get; set; } = null!; + + protected override void OnInitialized() + { + LayoutService.MajorUpdateOccured += LayoutServiceOnMajorUpdateOccured; + LayoutService.SetBaseTheme(Theme.Theme.CropperBlazorDocsTheme()); + base.OnInitialized(); + } + + private Guid SubscriptionId; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + SubscriptionId = await ResizeService.SubscribeAsync((size) => + { + if (size.Width > 960) + { + OnDrawerOpenChanged(false); + } + + InvokeAsync(StateHasChanged); + }, new ResizeOptions + { + ReportRate = 50, + NotifyOnBreakpointOnly = false, + }); + + var size = await ResizeService.GetBrowserWindowSize(); + + await ApplyUserPreferences(); + StateHasChanged(); + } + + await base.OnAfterRenderAsync(firstRender); + } + + public async ValueTask DisposeAsync() => await ResizeService.UnsubscribeAsync(SubscriptionId); + + private async Task ApplyUserPreferences() + { + //var defaultDarkMode = await _mudThemeProvider.GetSystemPreference(); + await LayoutService.ApplyUserPreferences(true); + } + + public void Dispose() + { + LayoutService.MajorUpdateOccured -= LayoutServiceOnMajorUpdateOccured; + } + + private void LayoutServiceOnMajorUpdateOccured(object? sender, EventArgs e) => StateHasChanged(); + + private bool DrawerOpen = false; + + private void ToggleDrawer() + { + DrawerOpen = !DrawerOpen; + } + + private void OnDrawerOpenChanged(bool value) + { + DrawerOpen = value; + StateHasChanged(); + } + + private string GetActiveClass(BasePage page) + { + return page == GetDocsBasePage(NavigationManager.Uri) ? "mud-chip-text mud-chip-color-primary ml-3" : "ml-3"; + } + public BasePage GetDocsBasePage(string uri) + { + if (uri.Contains("/demo")) + { + return BasePage.Demo; + } + else if (uri.Contains("/api")) + { + return BasePage.Api; + } + else if (uri.Contains("/about")) + { + return BasePage.About; + } + else + { + return BasePage.None; + } + } +} diff --git a/src/Cropper.Blazor/Client/Shared/MainLayout.razor b/src/Cropper.Blazor/Client/Shared/MainLayout.razor index 15be5a99..f2fa6428 100644 --- a/src/Cropper.Blazor/Client/Shared/MainLayout.razor +++ b/src/Cropper.Blazor/Client/Shared/MainLayout.razor @@ -1,30 +1,8 @@ -@inherits LayoutComponentBase -@using Cropper.Blazor.Client.Enums +@inherits LayoutComponentBase - - - - - - - - - - - - - - - +Cropper.Blazor - blazor component for cropping images - - Demo - Api - About - - - - - @Body - - + + + +@Body diff --git a/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs index 0243cba5..fedf21f5 100644 --- a/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs @@ -1,102 +1,52 @@ -using Cropper.Blazor.Client.Enums; -using Cropper.Blazor.Client.Services; +using System; +using System.Threading.Tasks; using Microsoft.AspNetCore.Components; -using MudBlazor.Services; +using Cropper.Blazor.Client.Services.UserPreferences; +using Cropper.Blazor.Client.Models; +using Cropper.Blazor.Client.Services; -namespace Cropper.Blazor.Client.Shared; -public partial class MainLayout : LayoutComponentBase +namespace Cropper.Blazor.Client.Shared { - [Inject] private LayoutService LayoutService { get; set; } = null!; - - [Inject] private NavigationManager NavigationManager { get; set; } = null!; - - [Inject] IResizeService ResizeService { get; set; } = null!; + public partial class MainLayout : LayoutComponentBase, IDisposable + { + [Inject] private LayoutService LayoutService { get; set; } + + private MudThemeProvider _mudThemeProvider; - protected override void OnInitialized() - { - LayoutService.MajorUpdateOccured += LayoutServiceOnMajorUpdateOccured; - LayoutService.SetBaseTheme(Theme.Theme.CropperBlazorDocsTheme()); - base.OnInitialized(); - } - - private Guid SubscriptionId; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) + protected override void OnInitialized() { - SubscriptionId = await ResizeService.SubscribeAsync((size) => - { - if (size.Width > 960) - { - OnDrawerOpenChanged(false); - } - - InvokeAsync(StateHasChanged); - }, new ResizeOptions - { - ReportRate = 50, - NotifyOnBreakpointOnly = false, - }); - - var size = await ResizeService.GetBrowserWindowSize(); - - await ApplyUserPreferences(); - StateHasChanged(); + LayoutService.MajorUpdateOccured += LayoutServiceOnMajorUpdateOccured; + base.OnInitialized(); } - await base.OnAfterRenderAsync(firstRender); - } - - public async ValueTask DisposeAsync() => await ResizeService.UnsubscribeAsync(SubscriptionId); - - private async Task ApplyUserPreferences() - { - //var defaultDarkMode = await _mudThemeProvider.GetSystemPreference(); - await LayoutService.ApplyUserPreferences(true); - } - - public void Dispose() - { - LayoutService.MajorUpdateOccured -= LayoutServiceOnMajorUpdateOccured; - } - - private void LayoutServiceOnMajorUpdateOccured(object? sender, EventArgs e) => StateHasChanged(); - - private bool DrawerOpen = false; - - private void ToggleDrawer() - { - DrawerOpen = !DrawerOpen; - } - - private void OnDrawerOpenChanged(bool value) - { - DrawerOpen = value; - StateHasChanged(); - } - - private string GetActiveClass(BasePage page) - { - return page == GetDocsBasePage(NavigationManager.Uri) ? "mud-chip-text mud-chip-color-primary ml-3" : "ml-3"; - } - public BasePage GetDocsBasePage(string uri) - { - if (uri.Contains("/demo")) + protected override async Task OnAfterRenderAsync(bool firstRender) { - return BasePage.Demo; + await base.OnAfterRenderAsync(firstRender); + + if (firstRender) + { + await ApplyUserPreferences(); + await _mudThemeProvider.WatchSystemPreference(OnSystemPreferenceChanged); + StateHasChanged(); + } } - else if (uri.Contains("/api")) + + private async Task ApplyUserPreferences() { - return BasePage.Api; + var defaultDarkMode = await _mudThemeProvider.GetSystemPreference(); + await LayoutService.ApplyUserPreferences(defaultDarkMode); } - else if (uri.Contains("/about")) + + private async Task OnSystemPreferenceChanged(bool newValue) { - return BasePage.About; + await LayoutService.OnSystemPreferenceChanged(newValue); } - else + + public void Dispose() { - return BasePage.None; + LayoutService.MajorUpdateOccured -= LayoutServiceOnMajorUpdateOccured; } + + private void LayoutServiceOnMajorUpdateOccured(object sender, EventArgs e) => StateHasChanged(); } } diff --git a/src/Cropper.Blazor/Client/_Imports.razor b/src/Cropper.Blazor/Client/_Imports.razor index c825bfdc..aac801a3 100644 --- a/src/Cropper.Blazor/Client/_Imports.razor +++ b/src/Cropper.Blazor/Client/_Imports.razor @@ -9,6 +9,7 @@ @using Cropper.Blazor.Client @using Cropper.Blazor.Client.Shared @using MudBlazor +@using MudBlazor.Services @using Blazored.LocalStorage; @inject IDialogService _dialogService From 65dacd719a64e798e184f63aea25c34601a452a2 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Fri, 12 May 2023 15:11:21 +0300 Subject: [PATCH 054/196] User Preferences service updated --- src/Cropper.Blazor/Client/Enums/ThemeMode.cs | 8 +++ .../Client/Services/LayoutService.cs | 59 +++++++++++++++---- .../UserPreferences/UserPreferences.cs | 8 ++- 3 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 src/Cropper.Blazor/Client/Enums/ThemeMode.cs diff --git a/src/Cropper.Blazor/Client/Enums/ThemeMode.cs b/src/Cropper.Blazor/Client/Enums/ThemeMode.cs new file mode 100644 index 00000000..feaa0abc --- /dev/null +++ b/src/Cropper.Blazor/Client/Enums/ThemeMode.cs @@ -0,0 +1,8 @@ +namespace Cropper.Blazor.Client.Enums; + +public enum ThemeMode +{ + System = 0, + Light = 1, + Dark = 2 +} diff --git a/src/Cropper.Blazor/Client/Services/LayoutService.cs b/src/Cropper.Blazor/Client/Services/LayoutService.cs index ec134445..d9091e0d 100644 --- a/src/Cropper.Blazor/Client/Services/LayoutService.cs +++ b/src/Cropper.Blazor/Client/Services/LayoutService.cs @@ -3,35 +3,53 @@ using MudBlazor; namespace Cropper.Blazor.Client.Services; + public class LayoutService { private readonly IUserPreferencesService _userPreferencesService = null!; - private UserPreferences.UserPreferences UserPreferences = null!; + private UserPreferences.UserPreferences _userPreferences = null!; + private bool _systemPreferences; public bool IsDarkMode { get; private set; } = false; + public ThemeMode ThemeMode = ThemeMode.System; + public MudTheme CurrentTheme { get; private set; } = null!; public event EventHandler MajorUpdateOccured = null!; public LayoutService(IUserPreferencesService userPreferencesService) => _userPreferencesService = userPreferencesService; - public void SetDarkMode(bool value) - { - IsDarkMode = value; - } + public void SetDarkMode(bool value) => IsDarkMode = value; public async Task ApplyUserPreferences(bool isDarkModeDefaultTheme) { - UserPreferences = await _userPreferencesService.LoadUserPreferences(); - if (UserPreferences != null) + _systemPreferences = isDarkModeDefaultTheme; + _userPreferences = await _userPreferencesService.LoadUserPreferences(); + if (_userPreferences != null) { - IsDarkMode = UserPreferences.IsDarkMode; + IsDarkMode = _userPreferences.ThemeMode switch + { + ThemeMode.Dark => true, + ThemeMode.Light => false, + ThemeMode.System => isDarkModeDefaultTheme, + _ => IsDarkMode + }; } else { IsDarkMode = isDarkModeDefaultTheme; - UserPreferences = new UserPreferences.UserPreferences { IsDarkMode = IsDarkMode }; - await _userPreferencesService.SaveUserPreferences(UserPreferences); + _userPreferences = new UserPreferences.UserPreferences { ThemeMode = ThemeMode.System }; + await _userPreferencesService.SaveUserPreferences(_userPreferences); + } + } + + public async Task OnSystemPreferenceChanged(bool newValue) + { + _systemPreferences = newValue; + if (ThemeMode == ThemeMode.System) + { + IsDarkMode = newValue; + OnMajorUpdateOccured(); } } @@ -39,9 +57,24 @@ public async Task ApplyUserPreferences(bool isDarkModeDefaultTheme) public async Task ToggleDarkMode() { - IsDarkMode = !IsDarkMode; - UserPreferences.IsDarkMode = IsDarkMode; - await _userPreferencesService.SaveUserPreferences(UserPreferences); + switch (ThemeMode) + { + case ThemeMode.System: + ThemeMode = ThemeMode.Light; + IsDarkMode = false; + break; + case ThemeMode.Light: + ThemeMode = ThemeMode.Dark; + IsDarkMode = true; + break; + case ThemeMode.Dark: + ThemeMode = ThemeMode.System; + IsDarkMode = _systemPreferences; + break; + } + + _userPreferences.ThemeMode = ThemeMode; + await _userPreferencesService.SaveUserPreferences(_userPreferences); OnMajorUpdateOccured(); } diff --git a/src/Cropper.Blazor/Client/Services/UserPreferences/UserPreferences.cs b/src/Cropper.Blazor/Client/Services/UserPreferences/UserPreferences.cs index e020021a..aba63397 100644 --- a/src/Cropper.Blazor/Client/Services/UserPreferences/UserPreferences.cs +++ b/src/Cropper.Blazor/Client/Services/UserPreferences/UserPreferences.cs @@ -1,8 +1,10 @@ -namespace Cropper.Blazor.Client.Services.UserPreferences; +using Cropper.Blazor.Client.Enums; + +namespace Cropper.Blazor.Client.Services.UserPreferences; public class UserPreferences { ///

- /// If true DarkTheme is used. LightTheme otherwise + /// The current mode of theme /// - public bool IsDarkMode { get; set; } + public ThemeMode ThemeMode { get; set; } } From 4ad4d63aa9845e64dda8c267db3e7c07fb0bbb48 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sat, 13 May 2023 09:34:37 +0300 Subject: [PATCH 055/196] Landing and Main layouts updated --- .../Client/Shared/LandingLayout.razor | 9 +---- .../Client/Shared/LandingLayout.razor.cs | 39 +++++-------------- .../Client/Shared/MainLayout.razor.cs | 13 +++---- 3 files changed, 16 insertions(+), 45 deletions(-) diff --git a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor index 15be5a99..1645567d 100644 --- a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor +++ b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor @@ -1,22 +1,17 @@ @inherits LayoutComponentBase -@using Cropper.Blazor.Client.Enums - - - - +@layout MainLayout - + - Demo Api diff --git a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs index 639ef2e7..957b051d 100644 --- a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs @@ -8,19 +8,20 @@ public partial class LandingLayout : LayoutComponentBase { [Inject] private LayoutService LayoutService { get; set; } = null!; - [Inject] private NavigationManager NavigationManager { get; set; } = null!; - [Inject] IResizeService ResizeService { get; set; } = null!; + public async ValueTask DisposeAsync() => await ResizeService.UnsubscribeAsync(SubscriptionId); + + private bool _drawerOpen = false; + + private Guid SubscriptionId; + protected override void OnInitialized() { - LayoutService.MajorUpdateOccured += LayoutServiceOnMajorUpdateOccured; - LayoutService.SetBaseTheme(Theme.Theme.CropperBlazorDocsTheme()); + LayoutService.SetBaseTheme(Theme.Theme.LandingPageTheme()); base.OnInitialized(); } - private Guid SubscriptionId; - protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) @@ -41,45 +42,23 @@ protected override async Task OnAfterRenderAsync(bool firstRender) var size = await ResizeService.GetBrowserWindowSize(); - await ApplyUserPreferences(); StateHasChanged(); } await base.OnAfterRenderAsync(firstRender); } - public async ValueTask DisposeAsync() => await ResizeService.UnsubscribeAsync(SubscriptionId); - - private async Task ApplyUserPreferences() - { - //var defaultDarkMode = await _mudThemeProvider.GetSystemPreference(); - await LayoutService.ApplyUserPreferences(true); - } - - public void Dispose() - { - LayoutService.MajorUpdateOccured -= LayoutServiceOnMajorUpdateOccured; - } - - private void LayoutServiceOnMajorUpdateOccured(object? sender, EventArgs e) => StateHasChanged(); - - private bool DrawerOpen = false; - private void ToggleDrawer() { - DrawerOpen = !DrawerOpen; + _drawerOpen = !_drawerOpen; } private void OnDrawerOpenChanged(bool value) { - DrawerOpen = value; + _drawerOpen = value; StateHasChanged(); } - private string GetActiveClass(BasePage page) - { - return page == GetDocsBasePage(NavigationManager.Uri) ? "mud-chip-text mud-chip-color-primary ml-3" : "ml-3"; - } public BasePage GetDocsBasePage(string uri) { if (uri.Contains("/demo")) diff --git a/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs index fedf21f5..7c25c1fa 100644 --- a/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/MainLayout.razor.cs @@ -1,17 +1,14 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; -using Cropper.Blazor.Client.Services.UserPreferences; -using Cropper.Blazor.Client.Models; +using Microsoft.AspNetCore.Components; using Cropper.Blazor.Client.Services; +using MudBlazor; namespace Cropper.Blazor.Client.Shared { public partial class MainLayout : LayoutComponentBase, IDisposable { - [Inject] private LayoutService LayoutService { get; set; } - - private MudThemeProvider _mudThemeProvider; + [Inject] private LayoutService LayoutService { get; set; } = null!; + + private MudThemeProvider _mudThemeProvider = null!; protected override void OnInitialized() { From f0f988dd96fc1ce7cc956665acb579e7c9b6014d Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sat, 13 May 2023 09:51:22 +0300 Subject: [PATCH 056/196] Additional fix for Landing layout --- src/Cropper.Blazor/Client/Pages/Index.razor | 1 + .../Client/Shared/LandingLayout.razor | 26 ++++++------- .../Client/Shared/LandingLayout.razor.cs | 37 ------------------- 3 files changed, 13 insertions(+), 51 deletions(-) diff --git a/src/Cropper.Blazor/Client/Pages/Index.razor b/src/Cropper.Blazor/Client/Pages/Index.razor index 9617fc48..4ebbd8c8 100644 --- a/src/Cropper.Blazor/Client/Pages/Index.razor +++ b/src/Cropper.Blazor/Client/Pages/Index.razor @@ -1,4 +1,5 @@ @page "/" +@layout LandingLayout @using Cropper.Blazor.Client.Components @using Cropper.Blazor.Client.Components.Docs @using Cropper.Blazor.Client.Models; diff --git a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor index 1645567d..a9ab7e0f 100644 --- a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor +++ b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor @@ -2,22 +2,20 @@ @layout MainLayout - + - - - - - - - - - Demo - Api - About - - + + + + + + + + Demo + Api + About + @Body diff --git a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs index 957b051d..a6355bcf 100644 --- a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs @@ -8,57 +8,20 @@ public partial class LandingLayout : LayoutComponentBase { [Inject] private LayoutService LayoutService { get; set; } = null!; - [Inject] IResizeService ResizeService { get; set; } = null!; - - public async ValueTask DisposeAsync() => await ResizeService.UnsubscribeAsync(SubscriptionId); private bool _drawerOpen = false; - private Guid SubscriptionId; - protected override void OnInitialized() { LayoutService.SetBaseTheme(Theme.Theme.LandingPageTheme()); base.OnInitialized(); } - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - SubscriptionId = await ResizeService.SubscribeAsync((size) => - { - if (size.Width > 960) - { - OnDrawerOpenChanged(false); - } - - InvokeAsync(StateHasChanged); - }, new ResizeOptions - { - ReportRate = 50, - NotifyOnBreakpointOnly = false, - }); - - var size = await ResizeService.GetBrowserWindowSize(); - - StateHasChanged(); - } - - await base.OnAfterRenderAsync(firstRender); - } - private void ToggleDrawer() { _drawerOpen = !_drawerOpen; } - private void OnDrawerOpenChanged(bool value) - { - _drawerOpen = value; - StateHasChanged(); - } - public BasePage GetDocsBasePage(string uri) { if (uri.Contains("/demo")) From 1a04274627c11860dedd3b21aa5c42099246d0df Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sat, 13 May 2023 11:12:43 +0300 Subject: [PATCH 057/196] Fix landinglayout --- .../Client/Shared/LandingLayout.razor | 1 + .../Client/Shared/LandingLayout.razor.cs | 20 ------------------- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor index a9ab7e0f..4e9d717a 100644 --- a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor +++ b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor @@ -13,6 +13,7 @@ Demo + Examples Api About diff --git a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs index a6355bcf..87390b81 100644 --- a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs @@ -21,24 +21,4 @@ private void ToggleDrawer() { _drawerOpen = !_drawerOpen; } - - public BasePage GetDocsBasePage(string uri) - { - if (uri.Contains("/demo")) - { - return BasePage.Demo; - } - else if (uri.Contains("/api")) - { - return BasePage.Api; - } - else if (uri.Contains("/about")) - { - return BasePage.About; - } - else - { - return BasePage.None; - } - } } From 541a80a21739bc26d3ee6b9c1674092bef012a68 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sun, 14 May 2023 09:48:18 +0300 Subject: [PATCH 058/196] Docs layout updated --- .../Client/Shared/DocsLayout.razor | 72 +++++-------------- .../Client/Shared/DocsLayout.razor.cs | 35 ++++++++- 2 files changed, 53 insertions(+), 54 deletions(-) diff --git a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor index 37c5ce3d..b48faa0a 100644 --- a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor +++ b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor @@ -1,80 +1,46 @@ -@inherits LayoutComponentBase +@using Cropper.Blazor.Client.Enums; +@inherits LayoutComponentBase @layout MainLayout - - - + + + - + @if (_topMenuOpen == false) { - + } else { - + } - - + + - + @if (_topMenuOpen == true) { - Docs - Getting Started - Discover More - - MudBlazor - TryMudBlazor - ThemeManager - Templates - Coming soon - MudStore - MudAcademy - MudExtensions - + Demo + Examples + Api + About } - - @if (!_topMenuOpen && LayoutService.GetDocsBasePage(NavigationManager.Uri) == DocsBasePage.Docs) - { - - } - else if (!_topMenuOpen && LayoutService.GetDocsBasePage(NavigationManager.Uri) == DocsBasePage.GettingStarted) - { - Getting Started - Installation - Layouts - Usage - Wireframes - } - else if (!_topMenuOpen && LayoutService.GetDocsBasePage(NavigationManager.Uri) == DocsBasePage.DiscoverMore) + + @if (!_topMenuOpen && LayoutService.GetDocsBasePage(NavigationManager.Uri) == BasePage.Demo) { - Discover More - What is MudBlazor? - - Getting Help - Reporting Bugs - Contribution - - - Announcements - How it started - Releases - Roadmap - Sponsors & Backers - Team & Contributors - + } @Body - + \ No newline at end of file diff --git a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs index 27a310a3..8ca24a88 100644 --- a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs @@ -1,5 +1,38 @@ +using Cropper.Blazor.Client.Services; +using Microsoft.AspNetCore.Components; +using static MudBlazor.CategoryTypes; + namespace Cropper.Blazor.Client.Shared; -public partial class DocsLayout +public partial class DocsLayout : LayoutComponentBase { + [Inject] private LayoutService LayoutService { get; set; } = null!; + + [Inject] private NavigationManager NavigationManager { get; set; } = null!; + + private NavMenu _navMenuRef; + private bool _drawerOpen = true; + private bool _topMenuOpen = false; + + protected override void OnInitialized() + { + LayoutService.SetBaseTheme(Theme.Theme.CropperBlazorDocsTheme()); + } + + protected override void OnAfterRender(bool firstRender) + { + //refresh nav menu because no parameters change in nav menu but internal data does + _navMenuRef?.Refresh(); + } + + private void ToggleDrawer() => _drawerOpen = !_drawerOpen; + + private void OpenTopMenu() => _topMenuOpen = true; + + private void OnDrawerOpenChanged(bool value) + { + _topMenuOpen = false; + _drawerOpen = value; + StateHasChanged(); + } } \ No newline at end of file From 347ddf5986cce124ac04c6a92c70dcc42f54937e Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sun, 14 May 2023 10:10:02 +0300 Subject: [PATCH 059/196] Menu Service added --- .../Client/Extensions/DocsVeiewExtension.cs | 3 +++ src/Cropper.Blazor/Client/Models/DocsLink.cs | 8 ++++++ .../Client/Services/MenuService.cs | 26 +++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 src/Cropper.Blazor/Client/Models/DocsLink.cs create mode 100644 src/Cropper.Blazor/Client/Services/MenuService.cs diff --git a/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs b/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs index ee23c614..05cab2f8 100644 --- a/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs +++ b/src/Cropper.Blazor/Client/Extensions/DocsVeiewExtension.cs @@ -27,5 +27,8 @@ public static void TryAddDocsViewServices(this IServiceCollection services) services.AddBlazoredLocalStorage(); services.AddScoped(); services.AddScoped(); + + services.AddSingleton(); + } } diff --git a/src/Cropper.Blazor/Client/Models/DocsLink.cs b/src/Cropper.Blazor/Client/Models/DocsLink.cs new file mode 100644 index 00000000..57c0baa5 --- /dev/null +++ b/src/Cropper.Blazor/Client/Models/DocsLink.cs @@ -0,0 +1,8 @@ +namespace Cropper.Blazor.Client.Models; + +public class DocsLink +{ + public string Href { get; set; } + public string Title { get; set; } + public string Group { get; set; } +} diff --git a/src/Cropper.Blazor/Client/Services/MenuService.cs b/src/Cropper.Blazor/Client/Services/MenuService.cs new file mode 100644 index 00000000..cb2f63cd --- /dev/null +++ b/src/Cropper.Blazor/Client/Services/MenuService.cs @@ -0,0 +1,26 @@ +using Cropper.Blazor.Client.Models; + +namespace Cropper.Blazor.Client.Services +{ + public interface IMenuService + { + //Menu sections + IEnumerable Examples { get; } + } + + /// + /// The aim of this class is to add new items to NavMenu + /// + public class MenuService : IMenuService + { + private IEnumerable _examples; + /// + /// Examples menu links + /// + public IEnumerable Examples => _examples ??= new List + { + new DocsLink {Title = "Breakpoints", Href = "examples/breakpoints"}, + new DocsLink {Title = "Localization", Href = "examples/localization"} + }.OrderBy(x => x.Title); + } +} From 8bde006f728e5fc7ac619d6a7d5d2eb97231ac45 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sun, 14 May 2023 10:12:22 +0300 Subject: [PATCH 060/196] Fix bugs --- src/Cropper.Blazor/Client/Shared/DocsLayout.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor index b48faa0a..3aaa0006 100644 --- a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor +++ b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor @@ -5,7 +5,7 @@ - + From 07ee2dc710082faf777c2995990c1542fdf0feb4 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sun, 14 May 2023 10:58:08 +0300 Subject: [PATCH 061/196] NavMenu added --- src/Cropper.Blazor/Client/Enums/BasePage.cs | 1 + .../Client/Shared/NavMenu.razor | 11 ++++++++ .../Client/Shared/NavMenu.razor.cs | 27 +++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 src/Cropper.Blazor/Client/Shared/NavMenu.razor create mode 100644 src/Cropper.Blazor/Client/Shared/NavMenu.razor.cs diff --git a/src/Cropper.Blazor/Client/Enums/BasePage.cs b/src/Cropper.Blazor/Client/Enums/BasePage.cs index c66c4888..ce626554 100644 --- a/src/Cropper.Blazor/Client/Enums/BasePage.cs +++ b/src/Cropper.Blazor/Client/Enums/BasePage.cs @@ -4,6 +4,7 @@ public enum BasePage { None, Demo, + Examples, Api, About } diff --git a/src/Cropper.Blazor/Client/Shared/NavMenu.razor b/src/Cropper.Blazor/Client/Shared/NavMenu.razor new file mode 100644 index 00000000..606d8a1d --- /dev/null +++ b/src/Cropper.Blazor/Client/Shared/NavMenu.razor @@ -0,0 +1,11 @@ +@using System.Linq +@using System.Text.RegularExpressions + +Docs +Demo + + @foreach (var link in MenuService.Examples) + { + @link.Title + } + diff --git a/src/Cropper.Blazor/Client/Shared/NavMenu.razor.cs b/src/Cropper.Blazor/Client/Shared/NavMenu.razor.cs new file mode 100644 index 00000000..75411c43 --- /dev/null +++ b/src/Cropper.Blazor/Client/Shared/NavMenu.razor.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Components; +using Cropper.Blazor.Client.Services; +using Cropper.Blazor.Client.Extensions; + +namespace Cropper.Blazor.Client.Shared +{ + public partial class NavMenu + { + [Inject] IMenuService MenuService { get; set; } + + [Inject] NavigationManager NavMan { get; set; } + + string _section; + + protected override void OnInitialized() + { + Refresh(); + base.OnInitialized(); + } + + public void Refresh() + { + _section = NavMan.GetSection(); + StateHasChanged(); + } + } +} From 2b99079c4b13c4f303699c04b9f34e1659a7b022 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sun, 14 May 2023 11:22:11 +0300 Subject: [PATCH 062/196] Fix Api page and create examples page --- src/Cropper.Blazor/Client/Pages/Api.razor | 1 + src/Cropper.Blazor/Client/Pages/Examples.razor | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 src/Cropper.Blazor/Client/Pages/Examples.razor diff --git a/src/Cropper.Blazor/Client/Pages/Api.razor b/src/Cropper.Blazor/Client/Pages/Api.razor index 919e1ca3..c9ddfb37 100644 --- a/src/Cropper.Blazor/Client/Pages/Api.razor +++ b/src/Cropper.Blazor/Client/Pages/Api.razor @@ -1,4 +1,5 @@ @page "/api" +@layout DocsLayout + Sorry + Not available now + From 499ab241e33cd097ad4101842fed62932d3337e1 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Mon, 15 May 2023 09:56:26 +0300 Subject: [PATCH 063/196] Fix DocsLayout --- src/Cropper.Blazor/Client/Services/LayoutService.cs | 2 ++ src/Cropper.Blazor/Client/Shared/DocsLayout.razor | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Cropper.Blazor/Client/Services/LayoutService.cs b/src/Cropper.Blazor/Client/Services/LayoutService.cs index d9091e0d..69e40020 100644 --- a/src/Cropper.Blazor/Client/Services/LayoutService.cs +++ b/src/Cropper.Blazor/Client/Services/LayoutService.cs @@ -88,6 +88,8 @@ public BasePage GetDocsBasePage(string uri) { if (uri.Contains("/demo")) return BasePage.Demo; + else if (uri.Contains("/examples")) + return BasePage.Examples; else if (uri.Contains("/api")) return BasePage.Api; else if (uri.Contains("/about")) diff --git a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor index 3aaa0006..22901811 100644 --- a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor +++ b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor @@ -28,12 +28,12 @@ Demo Examples Api - About + About sasa } - @if (!_topMenuOpen && LayoutService.GetDocsBasePage(NavigationManager.Uri) == BasePage.Demo) + @if (!_topMenuOpen && LayoutService.GetDocsBasePage(NavigationManager.Uri) == BasePage.Examples) { } From a521d732b2356c3ff195c0156bdaf4e007e298dc Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Tue, 16 May 2023 09:58:21 +0300 Subject: [PATCH 064/196] Fix AppBar and Demo --- src/Cropper.Blazor/Client/Pages/CropperDemo.razor | 1 + src/Cropper.Blazor/Client/Shared/Appbar.razor | 1 + src/Cropper.Blazor/Client/Shared/Appbar.razor.cs | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index 7be9b6b4..c68550aa 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -1,4 +1,5 @@ @page "/demo" +@layout LandingLayout @using Cropper.Blazor.Client.Components @using Cropper.Blazor.Components @using Cropper.Blazor.Extensions; diff --git a/src/Cropper.Blazor/Client/Shared/Appbar.razor b/src/Cropper.Blazor/Client/Shared/Appbar.razor index 88d4ea3b..c46e5c02 100644 --- a/src/Cropper.Blazor/Client/Shared/Appbar.razor +++ b/src/Cropper.Blazor/Client/Shared/Appbar.razor @@ -20,6 +20,7 @@ Cropper.Blazor Demo + Examples Api About diff --git a/src/Cropper.Blazor/Client/Shared/Appbar.razor.cs b/src/Cropper.Blazor/Client/Shared/Appbar.razor.cs index 41c0d81f..c88ee2b3 100644 --- a/src/Cropper.Blazor/Client/Shared/Appbar.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/Appbar.razor.cs @@ -15,4 +15,4 @@ private string GetActiveClass(BasePage page) { return page == LayoutService.GetDocsBasePage(NavigationManager.Uri) ? "mud-chip-text mud-chip-color-primary mx-1 px-3" : "mx-1 px-3"; } -} \ No newline at end of file +} From b30d429798b1e8cf307c751510175c15507b5709 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Tue, 16 May 2023 10:01:01 +0300 Subject: [PATCH 065/196] Move installation examples. --- .../Examples}/InstallServicesForBlazorServerExample.razor | 0 .../Examples}/InstallServicesForBlazorServerExampleCode.html | 0 .../Examples}/InstallationManualComponentsExample.razor | 0 .../Examples}/InstallationManualComponentsExampleCode.html | 0 .../Examples}/InstallationManualCssFontsExample.razor | 0 .../Examples}/InstallationManualCssFontsExampleCode.html | 0 .../Installation/Examples}/InstallationManualImportsExample.razor | 0 .../Examples}/InstallationManualImportsExampleCode.html | 0 .../Installation/Examples}/InstallationManualPackageExample.razor | 0 .../Examples}/InstallationManualPackageExampleCode.html | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename src/Cropper.Blazor/Client/Pages/{Examples/Installation => Home/Installation/Examples}/InstallServicesForBlazorServerExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Installation => Home/Installation/Examples}/InstallServicesForBlazorServerExampleCode.html (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Installation => Home/Installation/Examples}/InstallationManualComponentsExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Installation => Home/Installation/Examples}/InstallationManualComponentsExampleCode.html (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Installation => Home/Installation/Examples}/InstallationManualCssFontsExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Installation => Home/Installation/Examples}/InstallationManualCssFontsExampleCode.html (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Installation => Home/Installation/Examples}/InstallationManualImportsExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Installation => Home/Installation/Examples}/InstallationManualImportsExampleCode.html (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Installation => Home/Installation/Examples}/InstallationManualPackageExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Installation => Home/Installation/Examples}/InstallationManualPackageExampleCode.html (100%) diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallServicesForBlazorServerExample.razor b/src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallServicesForBlazorServerExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallServicesForBlazorServerExample.razor rename to src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallServicesForBlazorServerExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallServicesForBlazorServerExampleCode.html b/src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallServicesForBlazorServerExampleCode.html similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallServicesForBlazorServerExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallServicesForBlazorServerExampleCode.html diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualComponentsExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExample.razor rename to src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualComponentsExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualComponentsExampleCode.html similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualComponentsExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualComponentsExampleCode.html diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualCssFontsExample.razor b/src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualCssFontsExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualCssFontsExample.razor rename to src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualCssFontsExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualCssFontsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualCssFontsExampleCode.html similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualCssFontsExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualCssFontsExampleCode.html diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualImportsExample.razor b/src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualImportsExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualImportsExample.razor rename to src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualImportsExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualImportsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualImportsExampleCode.html similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualImportsExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualImportsExampleCode.html diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualPackageExample.razor b/src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualPackageExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualPackageExample.razor rename to src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualPackageExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualPackageExampleCode.html b/src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualPackageExampleCode.html similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Installation/InstallationManualPackageExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Home/Installation/Examples/InstallationManualPackageExampleCode.html From 3546b47d80f3e297b0157c6fc19836b55d9345ab Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Tue, 16 May 2023 10:09:31 +0300 Subject: [PATCH 066/196] Move uses examples. --- ...UsesPreviewFromElementReferenceSelectorComponentsExample.razor | 0 ...PreviewFromElementReferenceSelectorComponentsExample.razor.css | 0 ...sPreviewFromElementReferenceSelectorComponentsExampleCode.html | 0 ...iewFromMultipleElementReferenceSelectorComponentsExample.razor | 0 ...romMultipleElementReferenceSelectorComponentsExample.razor.css | 0 ...FromMultipleElementReferenceSelectorComponentsExampleCode.html | 0 .../UsesPreviewFromStringSelectorComponentsExample.razor | 0 .../UsesPreviewFromStringSelectorComponentsExample.razor.css | 0 .../UsesPreviewFromStringSelectorComponentsExampleCode.html | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename src/Cropper.Blazor/Client/Pages/{Examples/Uses/Preview => Home/Uses/Examples}/UsesPreviewFromElementReferenceSelectorComponentsExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Uses/Preview => Home/Uses/Examples}/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Uses/Preview => Home/Uses/Examples}/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Uses/Preview => Home/Uses/Examples}/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Uses/Preview => Home/Uses/Examples}/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Uses/Preview => Home/Uses/Examples}/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Uses/Preview => Home/Uses/Examples}/UsesPreviewFromStringSelectorComponentsExample.razor (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Uses/Preview => Home/Uses/Examples}/UsesPreviewFromStringSelectorComponentsExample.razor.css (100%) rename src/Cropper.Blazor/Client/Pages/{Examples/Uses/Preview => Home/Uses/Examples}/UsesPreviewFromStringSelectorComponentsExampleCode.html (100%) diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromElementReferenceSelectorComponentsExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor rename to src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromElementReferenceSelectorComponentsExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css b/src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css rename to src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor rename to src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css b/src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css rename to src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromStringSelectorComponentsExample.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor rename to src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromStringSelectorComponentsExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css b/src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromStringSelectorComponentsExample.razor.css similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css rename to src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromStringSelectorComponentsExample.razor.css diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromStringSelectorComponentsExampleCode.html similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html rename to src/Cropper.Blazor/Client/Pages/Home/Uses/Examples/UsesPreviewFromStringSelectorComponentsExampleCode.html From 91d538ae85cd69d4e69422131527107c41a190e4 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Wed, 17 May 2023 10:22:11 +0300 Subject: [PATCH 067/196] Fix Index page. --- src/Cropper.Blazor/Client/Pages/Index.razor | 4 ++-- src/Cropper.Blazor/Client/Pages/Index.razor.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Cropper.Blazor/Client/Pages/Index.razor b/src/Cropper.Blazor/Client/Pages/Index.razor index 4ebbd8c8..943370e8 100644 --- a/src/Cropper.Blazor/Client/Pages/Index.razor +++ b/src/Cropper.Blazor/Client/Pages/Index.razor @@ -3,8 +3,8 @@ @using Cropper.Blazor.Client.Components @using Cropper.Blazor.Client.Components.Docs @using Cropper.Blazor.Client.Models; -@using Cropper.Blazor.Client.Pages.Examples.Installation -@using Cropper.Blazor.Client.Pages.Examples.Uses.Preview +@using Cropper.Blazor.Client.Pages.Home.Installation.Examples +@using Cropper.Blazor.Client.Pages.Home.Uses.Examples Date: Wed, 17 May 2023 10:23:11 +0300 Subject: [PATCH 068/196] Rename Examples page. --- .../Client/Pages/{Examples.razor => UseExamples.razor} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Cropper.Blazor/Client/Pages/{Examples.razor => UseExamples.razor} (100%) diff --git a/src/Cropper.Blazor/Client/Pages/Examples.razor b/src/Cropper.Blazor/Client/Pages/UseExamples.razor similarity index 100% rename from src/Cropper.Blazor/Client/Pages/Examples.razor rename to src/Cropper.Blazor/Client/Pages/UseExamples.razor From e3c69cb6b8944bc689397244a9ab6953541565bb Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Thu, 18 May 2023 10:01:23 +0300 Subject: [PATCH 069/196] Add Nav Manager Extensions. --- .../Extensions/NavigationManagerExtensions.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/Cropper.Blazor/Client/Extensions/NavigationManagerExtensions.cs diff --git a/src/Cropper.Blazor/Client/Extensions/NavigationManagerExtensions.cs b/src/Cropper.Blazor/Client/Extensions/NavigationManagerExtensions.cs new file mode 100644 index 00000000..3889d3ad --- /dev/null +++ b/src/Cropper.Blazor/Client/Extensions/NavigationManagerExtensions.cs @@ -0,0 +1,45 @@ +using System; +using System.Linq; +using Microsoft.AspNetCore.Components; + +namespace Cropper.Blazor.Client.Extensions +{ + internal static class NavigationManagerExtensions + { + /// + /// Gets the section part of the documentation page + /// Ex: /components/button; "components" is the section + /// + public static string GetSection(this NavigationManager navMan) + { + // get the absolute path with out the base path + var currentUri = navMan.Uri.Remove(0, navMan.BaseUri.Length - 1); + var firstElement = currentUri + .Split("/", StringSplitOptions.RemoveEmptyEntries) + .FirstOrDefault(); + return firstElement; + } + + /// + /// Gets the link of the component on the documentation page + /// Ex: api/button; "button" is the component link, and "api" is the section + /// + public static string GetComponentLink(this NavigationManager navMan) + { + // get the absolute path with out the base path + var currentUri = navMan.Uri.Remove(0, navMan.BaseUri.Length - 1); + var secondElement = currentUri + .Split("/", StringSplitOptions.RemoveEmptyEntries) + .ElementAtOrDefault(1); + return secondElement; + } + + /// + /// Determines if the current page is the base page + /// + public static bool IsHomePage(this NavigationManager navMan) + { + return navMan.Uri == navMan.BaseUri; + } + } +} From 44af91b35402831b5c42e029289d2f933a921b2d Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Fri, 19 May 2023 11:03:53 +0300 Subject: [PATCH 070/196] decocde.min.js modified. --- src/Cropper.Blazor/Client/wwwroot/decode.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cropper.Blazor/Client/wwwroot/decode.min.js b/src/Cropper.Blazor/Client/wwwroot/decode.min.js index 53f8db21..6f9c551a 100644 --- a/src/Cropper.Blazor/Client/wwwroot/decode.min.js +++ b/src/Cropper.Blazor/Client/wwwroot/decode.min.js @@ -1 +1 @@ -function BrotliDecodeClosure(){"use strict";var z=new Int8Array(0);function c(e){this.data=e,this.offset=0}var $=Int32Array.from([1,2,3,4,0,5,17,6,16,7,8,9,10,11,12,13,14,15]),D=Int32Array.from([3,2,1,0,3,3,3,3,3,3,2,2,2,2,2,2]),F=Int32Array.from([0,0,0,0,-1,1,-2,2,-3,3,-1,1,-2,2,-3,3]),b=Int32Array.from([131072,131076,131075,196610,131072,131076,131075,262145,131072,131076,131075,196610,131072,131076,131075,262149]),N=Int32Array.from([0,0,0,0,0,4096,9216,21504,35840,44032,53248,63488,74752,87040,93696,100864,104704,106752,108928,113536,115968,118528,119872,121280,122016]),B=Int32Array.from([0,0,0,0,10,10,11,11,10,10,10,10,10,9,9,8,7,7,8,7,7,6,6,5,5]),o=Int32Array.from([1,5,9,13,17,25,33,41,49,65,81,97,113,145,177,209,241,305,369,497,753,1265,2289,4337,8433,16625]),r=Int32Array.from([2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,7,8,9,10,11,12,13,24]),M=Int32Array.from([0,1,2,3,4,5,6,8,10,14,18,26,34,50,66,98,130,194,322,578,1090,2114,6210,22594]),U=Int32Array.from([0,0,0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,7,8,9,10,12,14,24]),H=Int32Array.from([2,3,4,5,6,7,8,9,10,12,14,18,22,30,38,54,70,102,134,198,326,582,1094,2118]),R=Int32Array.from([0,0,0,0,0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,7,8,9,10,24]),O=Int32Array.from([0,0,8,8,0,16,8,16,16]),L=Int32Array.from([0,8,0,8,16,0,16,8,16]);function d(e,t){if(0!=e.t)throw"State MUST be uninitialized";var i;e.i=new Int32Array(6480),e.input=t,(i=e).o=new Int8Array(4160),i.s=0,i.l=new Int16Array(2080),i.h=32,i.p=2048,i.u=0,a(i);var n=function(e){if(16<=e.h&&(e.s=e.l[e.p++]<<16|e.s>>>16,e.h-=16),0==ne(e,1))return 16;var t=ne(e,3);return 0!=t?17+t:0!=(t=ne(e,3))?8+t:17}(e);if(9==n)throw"Invalid 'windowBits' code";e.m=1<>>16,e.h-=16),0==ne(e,1))return 0;var t=ne(e,3);return 0==t?1:ne(e,t)+(1<>>i.h,a=e[t+=255&n]>>16,o=65535&e[t];return a<=8?(i.h+=a,o):(t+=o,t+=(n&(1<>>8,i.h+=8+(e[t]>>16),65535&e[t])}function s(e,t,i){16<=i.h&&(i.s=i.l[i.p++]<<16|i.s>>>16,i.h-=16);var n=W(e,t,i),a=r[n];return 16<=i.h&&(i.s=i.l[i.p++]<<16|i.s>>>16,i.h-=16),o[n]+(a<=16?ne(i,a):ae(i,a))}function f(e,t){for(var i=e[t];0>>16,n.h-=16),1==(a=ne(n,2))){for(var s=e-1,l=0,c=new Int32Array(4),d=ne(n,2)+1;0!=s;)s>>=1,l++;for(var h=0;h>>16,n.h-=16),c[h]=ne(n,l)%e,r[c[h]]=2;switch(r[c[0]]=1,d){case 2:r[c[1]]=1;break;case 4:1==ne(n,1)?(r[c[2]]=3,r[c[3]]=3):r[c[0]]=2}o=function(e,t){for(var i=0;i>>16,n.h-=16);var g=n.s>>>n.h&15;n.h+=b[g]>>16;var P=65535&b[g];0!=(f[m]=P)&&(p-=32>>P,u++)}0!=p&&1!=u&&(o=0),function(e,t,i,n){var a=0,o=8,r=0,s=0,l=32768,c=new Int32Array(32);for(Q(c,0,5,e,18);a>>16,n.h-=16);var d=n.s>>>n.h&31;n.h+=c[d]>>16;var h=65535&c[d];if(h<16)(r=0)!=(i[a++]=h)&&(l-=32768>>(o=h));else{var f=h-14,p=0;16==h&&(p=o),s!=p&&(r=0,s=p);var u=r;0>>16,n.h-=16);var m=(r+=ne(n,f)+3)-u;if(t numSymbols";for(var g=0;g>>16,i.h-=16);var a=0;0!=ne(i,1)&&(a=ne(i,4)+1);var o=new Int32Array(1080);p(n+a,o,0,i);for(var r=0;r>>16,i.h-=16);var s=W(o,0,i);if(0==s)t[r]=0,r++;else if(s<=a){16<=i.h&&(i.s=i.l[i.p++]<<16|i.s>>>16,i.h-=16);for(var l=(1<>>16,i.h-=16),1==ne(i,1)&&function(e,t){for(var i=new Int32Array(256),n=0;n<256;n++)i[n]=n;for(n=0;n>>16,e.h-=16);var o=W(e.i,1080*t,e),r=s(e.i,1080*(t+3),e);return 1==o?o=n[a+1]+1:0==o?o=n[a]:o-=2,i<=o&&(o-=i),n[a]=n[a+1],n[a+1]=o,r}function G(e){e.$=_(e,0,e.v);var t=e.P[5];e.X=t<<6,e.Y=255&e.k[e.X],e.C=e.j[e.Y];var i=e.A[t];e.q=i<<9,e.I=e.q+256}function J(e){if(0!=e.T)return e.S=9,void(e.t=11);e.j=new Int32Array(0),e.D=new Int32Array(0),e.F=new Int32Array(0),2030>>16,e.h-=16),e.T=ne(e,1),e.N=0,e.B=0,(e.M=0)==e.T||0==ne(e,1)){var t=ne(e,2)+4;if(7==t){if(e.M=1,0!=ne(e,1))throw"Corrupted reserved bit";var i=ne(e,2);if(0==i)return;for(var n=0;n>>16,e.h-=16),0==(a=ne(e,8))&&n+1==i&&1>>16,e.h-=16),0==(a=ne(e,4))&&n+1==t&&41<<30&&(e.U=1<<30),e.He.U){for(var i=e.U;i>1;)t>>=1;0==e.T&&t<16384&&16384<=e.m&&(t=16384)}if(!(t<=e.H)){var n=new Int8Array(t+37);0!=e.R.length&&n.set(e.R.subarray(0,0+e.H),0),e.R=n,e.H=t}}(e)))}function u(e,t,i){return i<=1?1<<28:(p(i+2,e.i,1080*t,e),p(26,e.i,1080*(t+3),e),s(e.i,1080*(t+3),e))}function V(e){e.v=h(e)+1,e.$=u(e,0,e.v),e.O=h(e)+1,e.L=u(e,1,e.O),e.W=h(e)+1,e._=u(e,2,e.W),2030>>16,e.h-=16),e.G=ne(e,2),e.J=16+(ne(e,4)<>>16,e.h-=16),e.A[i]=ne(e,2);2030>6){e.K=0;break}e.Z=new Int8Array(e.W<<2);var r=l(e.W<<2,e.Z,e);e.j=m(256,a,e),e.D=m(704,e.O,e),e.F=m(t,r,e),e.X=0,e.ee=0,e.q=e.A[0]<<9,e.I=e.q+256,e.Y=0,e.C=e.j[0],e.te=e.D[0],e.P[4]=1,e.P[5]=0,e.P[6]=1,e.P[7]=0,e.P[8]=1,e.P[9]=0}function K(e){var t=e.R;if(e.N<=0)return n(e),void(e.t=1);var i=se(e.H-e.ie,e.N);if(function(e,t,i,n){if(0!=(7&e.h))throw"Unaligned copyBytes";for(;32!=e.h&&0!=n;)t[i++]=e.s>>>e.h,e.h+=8,n--;if(0==n)return;var a=se(k(e),n>>1);if(0>>16,e.h-=16);0!=n;)t[i++]=e.s>>>e.h,e.h+=8,n--;return ie(e,0)}for(;0>>16,e.h-=16);var h=W(e.D,e.te,e),f=h>>>6;e.se=0,2<=f&&(f-=2,e.se=-1);var p=O[f]+(h>>>3&7);16<=e.h&&(e.s=e.l[e.p++]<<16|e.s>>>16,e.h-=16);var u=U[p],m=u<=16?ne(e,u):ae(e,u);e.le=M[p]+m;var g=L[f]+(7&h);16<=e.h&&(e.s=e.l[e.p++]<<16|e.s>>>16,e.h-=16);var P=R[g],$=P<=16?ne(e,P):ae(e,P);e.ce=H[g]+$,e.de=0,e.t=6;case 6:if(0!=e.K){for(;e.de>>16,e.h-=16),d[e.ie]=W(e.j,e.C,e),e.ie++,e.de++,e.ie>=l){e.S=6,e.t=11;break}}else for(var b=255&d[e.ie-1&c],v=255&d[e.ie-2&c];e.de>>16,e.h-=16),b=W(e.j,e.j[y],e),d[e.ie]=b,e.ie++,e.de++,e.ie>=l){e.S=6,e.t=11;break}}if(6!=e.t)continue;if(e.N-=e.le,e.N<=0){e.t=3;continue}if(e.se<0&&(2030>>16,e.h-=16),e.se=W(e.F,e.F[255&e.Z[e.ee+(4=e.J)){e.se-=e.J;var X=e.se&e.V;e.se>>>=e.G;var w=1+(e.se>>>1),Y=(2+(1&e.se)<>>16,e.h-=16);var Q=w<=16?ne(e,w):ae(e,w);e.se=e.J+X+(Y+Q<e.maxDistance){e.t=8;continue}if(0e.N)throw"Invalid backward reference";e.de=0,e.t=7;case 7:var k=e.ie-e.he&c,x=e.ie,C=e.ce-e.de,j=k+C,A=x+C;if(j=l){e.S=7,e.t=11;break}7==e.t&&(e.t=3);continue;case 8:if(!(4<=e.ce&&e.ce<=24))throw"Invalid backward reference";Y=N[e.ce];var I=e.he-e.maxDistance-1,T=B[e.ce],S=I>>>T;if(Y+=(I&(1<=l){e.S=3,e.t=11;continue}e.t=3;continue;case 4:for(;0>>16,e.h-=16),ne(e,8),e.N--;e.t=1;continue;case 5:K(e);continue;case 11:e.pe=se(e.ie,e.H),e.t=12;case 12:if(0==(void 0,0!=(i=se((t=e).oe-t.re,t.pe-t.ae))&&(t.ue.set(t.R.subarray(t.ae,t.ae+i),t.me+t.re),t.re+=i,t.ae+=i),t.re=e.g&&(e.maxDistance=e.g),e.ie>=e.H&&(e.ie>e.H&&d.copyWithin(0,e.H,e.ie),e.ie&=c,e.ae=0),e.t=e.S;continue;default:throw"Unexpected state "+e.t}if(9==e.t){if(e.N<0)throw"Invalid metablock length";oe(e),ie(e,1)}}var P=new Int32Array(363),v=new Int8Array(217),y=new Int32Array(51);function ee(e,t,i,n,a,o){for(var r=t,s=3*o,l=y[P[s]],c=P[s+1],d=y[P[s+2]];0!=v[l];)e[r++]=v[l++];var h=12<=c?c-11:0;a>=1;return(e&i-1)+i}function w(e,t,i,n,a){for(;e[t+(n-=i)]=a,0>i),u,f,d-i<<16|s[r++]),o=X(o,d)}else for(o=0;o>1,a=e.l,o=0;o>3)-4;if(i>e.ge)throw"Read after end";if(0!=t&&i!=e.ge)throw"Unused bytes after end"}}function ne(e,t){var i=e.s>>>e.h&(1<>>16,e.h-=16,i|ne(e,t-16)<<16}function a(e){2030>>16,e.h-=16,e.s=e.l[e.p++]<<16|e.s>>>16,e.h-=16}function n(e){32==e.h&&a(e)}function oe(e){var t=32-e.h&7;if(0!=t&&0!=ne(e,t))throw"Corrupted padding bits"}function k(e){var t=2048;return 0!=e.u&&(t=e.ge+1>>1),t-e.p}!function(e,t,i,n,a){for(var o=n.length,r=1,s=0;s#\n#]# for # a # that #. # with #\'# from # by #. The # on # as # is #ing #\n\t#:#ed #(# at #ly #="# of the #. This #,# not #er #al #=\'#ful #ive #less #est #ize #ous #'," !! ! , *! &! \" ! ) * * - ! # ! #!*! + ,$ ! - % . / # 0 1 . \" 2 3!* 4% ! # / 5 6 7 8 0 1 & $ 9 + : ; < ' != > ?! 4 @ 4 2 & A *# ( B C& ) % ) !*# *-% A +! *. D! %' & E *6 F G% ! *A *% H! D I!+! J!+ K +- *4! A L!*4 M N +6 O!*% +.! K *G P +%( ! G *D +D Q +# *K!*G!+D!+# +G +A +4!+% +K!+4!*D!+K!*K");var re=new Int32Array(2048);function x(){this.R=new Int8Array(0),this.A=new Int8Array(0),this.k=new Int8Array(0),this.Z=new Int8Array(0),this.ue=new Int8Array(0),this.o=new Int8Array(0),this.l=new Int16Array(0),this.Pe=new Int32Array(0),this.P=new Int32Array(0),this.i=new Int32Array(0),this.j=new Int32Array(0),this.D=new Int32Array(0),this.F=new Int32Array(0),this.t=0,this.S=0,this.s=0,this.h=0,this.p=0,this.ge=0,this.u=0,this.N=0,this.T=0,this.B=0,this.M=0,this.$=0,this.v=0,this.L=0,this.O=0,this._=0,this.W=0,this.ie=0,this.maxDistance=0,this.fe=0,this.K=0,this.Y=0,this.C=0,this.de=0,this.le=0,this.X=0,this.ee=0,this.q=0,this.I=0,this.te=0,this.se=0,this.J=0,this.V=0,this.G=0,this.he=0,this.ce=0,this.g=0,this.m=0,this.H=0,this.U=0,this.me=0,this.oe=0,this.re=0,this.ae=0,this.pe=0,this.ne=0,this.input=null,this.R=new Int8Array(0),this.P=new Int32Array(10),this.P[0]=16,this.P[1]=15,this.P[2]=11,this.P[3]=4}!function(e,t,i){for(var n=0;n<256;++n)e[n]=63&n,e[512+n]=n>>2,e[1792+n]=2+(n>>6);for(n=0;n<128;++n)e[1024+n]=4*(t.charCodeAt(n)-32);for(n=0;n<64;++n)e[1152+n]=1&n,e[1216+n]=2+(1&n);for(var a=1280,o=0;o<19;++o){var r=3&o,s=i.charCodeAt(o)-32;for(n=0;nstopelseliestourpack.gifpastcss?graymean>rideshotlatesaidroadvar feeljohnrickportfast\'UA-deadpoorbilltypeU.S.woodmust2px;Inforankwidewantwalllead[0];paulwavesure$(\'#waitmassarmsgoesgainlangpaid!-- lockunitrootwalkfirmwifexml"songtest20pxkindrowstoolfontmailsafestarmapscorerainflowbabyspansays4px;6px;artsfootrealwikiheatsteptriporg/lakeweaktoldFormcastfansbankveryrunsjulytask1px;goalgrewslowedgeid="sets5px;.js?40pxif (soonseatnonetubezerosentreedfactintogiftharm18pxcamehillboldzoomvoideasyringfillpeakinitcost3px;jacktagsbitsrolleditknewnear\x3c!--growJSONdutyNamesaleyou lotspainjazzcoldeyesfishwww.risktabsprev10pxrise25pxBlueding300,ballfordearnwildbox.fairlackverspairjunetechif(!pickevil$("#warmlorddoespull,000ideadrawhugespotfundburnhrefcellkeystickhourlossfuel12pxsuitdealRSS"agedgreyGET"easeaimsgirlaids8px;navygridtips#999warsladycars); }php?helltallwhomzh:e*/\r\n 100hall.\n\nA7px;pushchat0px;crew*/ericmostguidbelldeschairmathatom/imgRluckcent000;tinygonehtmlselldrugFREEnodenick?id=losenullvastwindRSS wearrelybeensamedukenasacapewishgulfT23:hitsslotgatekickblurthey15px\'\'););">msiewinsbirdsortbetaseekT18:ordstreemall60pxfarmb\0\x19sboys[0].\');"POSTbearkids);}}marytend(UK)quadzh:f-siz----prop\');\rliftT19:viceandydebt>RSSpoolneckblowT16:doorevalT17:letsfailoralpollnovacolsgene b\0\x14softrometillross

pourfadepinkmini)|!(minezh:hbarshear00);milk --\x3eironfreddiskwentsoilputs/js/holyT22:ISBNT20:adamsees

json\', \'contT21: RSSloopasiamoon

soulLINEfortcartT14:

80px!--<9px;T04:mike:46ZniceinchYorkricezh:d\'));puremageparatonebond:37Z_of_\']);000,zh:gtankyardbowlbush:56ZJava30px\n|}\n%C3%:34ZjeffEXPIcashvisagolfsnowzh:iquer.csssickmeatmin.binddellhirepicsrent:36ZHTTP-201fotowolfEND xbox:54ZBODYdick;\n}\nexit:35Zvarsbeat\'});diet999;anne}}sonyguysfuckpipe|-\n!002)ndow[1];[];\nLog salt\r\n\t\tbangtrimbath){\r\n00px\n});ko:lfeesad>\rs:// [];tollplug(){\n{\r\n .js\'200pdualboat.JPG);\n}quot);\n\n\');\n\r\n}\r201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037201320122011201020092008200720062005200420032002200120001999199819971996199519941993199219911990198919881987198619851984198319821981198019791978197719761975197419731972197119701969196819671966196519641963196219611960195919581957195619551954195319521951195010001024139400009999comomC!sesteestaperotodohacecadaaC1obiendC-aasC-vidacasootroforosolootracualdijosidograntipotemadebealgoquC)estonadatrespococasabajotodasinoaguapuesunosantediceluisellamayozonaamorpisoobraclicellodioshoracasiP7P0P=P0P>PP>Q\x02P8P7P=P>P4P>Q\x02P>P6P5P>P=P8Q\x05P\x1dP0P5P5P1Q\vPP2Q\vP2P>P\x1dP>P>P1P\x1fP>P;P8P=P8P P$P\x1dP5P\x1cQ\vQ\x02Q\vP\x1eP=P8Pthing.org/multiheardPowerstandtokensolid(thisbringshipsstafftriedcallsfullyfactsagentThis //--\x3eadminegyptEvent15px;Emailtrue"crossspentblogsbox">notedleavechinasizesguest

robotheavytrue,sevengrandcrimesignsawaredancephase>\x3c!--en_US'200px_namelatinenjoyajax.ationsmithU.S. holdspeterindianav">chainscorecomesdoingpriorShare1990sromanlistsjapanfallstrialowneragreeabusealertopera"-//WcardshillsteamsPhototruthclean.php?saintmetallouismeantproofbriefrow">genretrucklooksValueFrame.net/--\x3e\n\n\x3c!--POST"ocean
floorspeakdepth sizebankscatchchart20px;aligndealswould50px;url="parksmouseMost ...drugs\x3c!-- aprilidealallenexactforthcodeslogicView seemsblankports (200saved_linkgoalsgrantgreekhomesringsrated30px;whoseparse();" Blocklinuxjonespixel\');">);if(-leftdavidhorseFocusraiseboxesTrackementbar">.src=toweralt="cablehenry24px;setupitalysharpminortastewantsthis.resetwheelgirls/css/100%;clubsstuffbiblevotes 1000korea});\r\nbandsqueue= {};80px;cking{\r\n\t\taheadclockirishlike ratiostatsForm"yahoo)[0];AboutfindsdebugtasksURL =cells})();12px;primetellsturns0x600.jpg"spainbeachtaxesmicroangel--\x3e\r\nname=diegopage swiss--\x3e\n\n#fff;">Log.com"treatsheet) && 14px;sleepntentfiledja:c\x03id="cName"worseshots-box-delta\n<bears:48Z spendbakershops= "";php">ction13px;brianhellosize=o=%2F joinmaybe, fjsimg" ")[0]MTopBType"newlyDanskczechtrailknowsfaq">zh-cn10);\n-1");type=bluestrulydavis.js\';>\r\n\r\nform jesus100% menu.\r\n\t\r\nwalesrisksumentddingb-likteachgif" vegasdanskeestishqipsuomisobredesdeentretodospuedeaC1osestC!tienehastaotrospartedondenuevohacerformamismomejormundoaquC-dC-assC3loayudafechatodastantomenosdatosotrassitiomuchoahoralugarmayorestoshorastenerantesfotosestaspaC-snuevasaludforosmedioquienmesespoderchileserC!vecesdecirjosC)estarventagrupohechoellostengoamigocosasnivelgentemismaairesjuliotemashaciafavorjuniolibrepuntobuenoautorabrilbuenatextomarzosaberlistaluegocC3moenerojuegoperC:haberestoynuncamujervalorfueralibrogustaigualvotoscasosguC-apuedosomosavisousteddebennochebuscafaltaeurosseriedichocursoclavecasasleC3nplazolargoobrasvistaapoyojuntotratavistocrearcampohemoscincocargopisosordenhacenC!readiscopedrocercapuedapapelmenorC:tilclarojorgecalleponertardenadiemarcasigueellassiglocochemotosmadreclaserestoniC1oquedapasarbancohijosviajepabloC)stevienereinodejarfondocanalnorteletracausatomarmanoslunesautosvillavendopesartipostengamarcollevapadreunidovamoszonasambosbandamariaabusomuchasubirriojavivirgradochicaallC-jovendichaestantalessalirsuelopesosfinesllamabuscoC)stalleganegroplazahumorpagarjuntadobleislasbolsabaC1ohablaluchaC\x01readicenjugarnotasvalleallC!cargadolorabajoestC)gustomentemariofirmacostofichaplatahogarartesleyesaquelmuseobasespocosmitadcielochicomiedoganarsantoetapadebesplayaredessietecortecoreadudasdeseoviejodeseaaguas"domaincommonstatuseventsmastersystemactionbannerremovescrollupdateglobalmediumfilternumberchangeresultpublicscreenchoosenormaltravelissuessourcetargetspringmodulemobileswitchphotosborderregionitselfsocialactivecolumnrecordfollowtitle>eitherlengthfamilyfriendlayoutauthorcreatereviewsummerserverplayedplayerexpandpolicyformatdoublepointsseriespersonlivingdesignmonthsforcesuniqueweightpeopleenergynaturesearchfigurehavingcustomoffsetletterwindowsubmitrendergroupsuploadhealthmethodvideosschoolfutureshadowdebatevaluesObjectothersrightsleaguechromesimplenoticesharedendingseasonreportonlinesquarebuttonimagesenablemovinglatestwinterFranceperiodstrongrepeatLondondetailformeddemandsecurepassedtoggleplacesdevicestaticcitiesstreamyellowattackstreetflighthiddeninfo">openedusefulvalleycausesleadersecretseconddamagesportsexceptratingsignedthingseffectfieldsstatesofficevisualeditorvolumeReportmuseummoviesparentaccessmostlymother" id="marketgroundchancesurveybeforesymbolmomentspeechmotioninsidematterCenterobjectexistsmiddleEuropegrowthlegacymannerenoughcareeransweroriginportalclientselectrandomclosedtopicscomingfatheroptionsimplyraisedescapechosenchurchdefinereasoncorneroutputmemoryiframepolicemodelsNumberduringoffersstyleskilledlistedcalledsilvermargindeletebetterbrowselimitsGlobalsinglewidgetcenterbudgetnowrapcreditclaimsenginesafetychoicespirit-stylespreadmakingneededrussiapleaseextentScriptbrokenallowschargedividefactormember-basedtheoryconfigaroundworkedhelpedChurchimpactshouldalwayslogo" bottomlist">){var prefixorangeHeader.push(couplegardenbridgelaunchReviewtakingvisionlittledatingButtonbeautythemesforgotSearchanchoralmostloadedChangereturnstringreloadMobileincomesupplySourceordersviewed courseAbout islandPhilipawardshandleimportOfficeregardskillsnationSportsdegreeweekly (e.g.behinddoctorloggedunitedbeyond-scaleacceptservedmarineFootercamera\n_form"leavesstress" />\r\n.gif" onloadloaderOxfordsistersurvivlistenfemaleDesignsize="appealtext">levelsthankshigherforcedanimalanyoneAfricaagreedrecentPeople
wonderpricesturned|| {};main">inlinesundaywrap">failedcensusminutebeaconquotes150px|estateremoteemail"linkedright;signalformal1.htmlsignupprincefloat:.png" forum.AccesspaperssoundsextendHeightsliderUTF-8"& Before. WithstudioownersmanageprofitjQueryannualparamsboughtfamousgooglelongeri++) {israelsayingdecidehome">headerensurebranchpiecesblock;statedtop">boston.test(avatartested_countforumsschemaindex,filledsharesreaderalert(appearSubmitline">body">\n* TheThoughseeingjerseyNews\nSystem DavidcancertablesprovedApril reallydriveritem">more">boardscolorscampusfirst || [];media.guitarfinishwidth:showedOther .php" assumelayerswilsonstoresreliefswedenCustomeasily your String\n\nWhiltaylorclear:resortfrenchthough") + "buyingbrandsMembername">oppingsector5px;">vspacepostermajor coffeemartinmaturehappenkansaslink">Images=falsewhile hspace0& \n\nIn powerPolski-colorjordanBottomStart -count2.htmlnews">01.jpgOnline-rightmillerseniorISBN 00,000 guidesvalue)ectionrepair.xml" rights.html-blockregExp:hoverwithinvirginphones\rusing \n\tvar >\');\n\t\n\nbahasabrasilgalegomagyarpolskisrpskiX1X/Y\bd8-f\x16\x07g.\0d=\x13g9\x01i+\x14d?!f\x01/d8-e\x1b=f\b\x11d;,d8\0d8*e\x05,e\x0f8g.!g\x10\x06h.:e\x1d\x1be\x0f/d;%f\x1c\re\n!f\x176i\x174d8*d::d:\'e\x13\x01h\x07*e71d<\x01d8\x1af\x1f%g\x1c\ve7%d=\x1ch\x01\x14g3;f2!f\x1c\tg=\x11g+\x19f\t\0f\x1c\th/\x04h.:d8-e?\x03f\x16\x07g+ g\x14(f\b7i&\x16i!5d=\x1ch\0\x05f\n\0f\x1c/i\x17.i"\x18g\x1b8e\x053d8\vh==f\x10\x1cg4"d=?g\x14(h=/d;6e\x1c(g:?d8;i"\x18h5\x04f\x16\x19h\'\x06i"\x11e\x1b\x1ee$\rf3(e\x06\fg=\x11g;\x1cf\x146h\x17\x0fe\x06\x05e.9f\x0e(h\r\x10e8\x02e\x1c:f6\bf\x01/g):i\x174e\x0f\x11e8\x03d;\0d9\be%=e\x0f\vg\x14\x1ff4;e\x1b>g\t\x07e\x0f\x11e1\x15e&\x02f\x1e\x1cf\t\vf\x1c:f\x160i\x17;f\x1c\0f\x160f\x169e<\x0fe\f\x17d:,f\x0f\x10d>\x1be\x053d:\x0ef\x1b4e$\x1ah?\x19d8*g3;g;\x1fg\x1f%i\x01\x13f88f\b\x0fe9?e\x11\ne\x056d;\x16e\x0f\x11h!(e.\te\x05(g,,d8\0d<\x1ae\x11\x18h?\x1bh!\fg\x029e\x07;g\t\bf\x1d\x03g\x145e-\x10d8\x16g\x15\fh.>h.!e\x05\rh49f\x15\x19h\x022e\n e\x05%f4;e\n(d;\x16d;,e\x15\x06e\x13\x01e\r\x1ae."g\x0e0e\x1c(d8\nf57e&\x02d=\x15e72g;\x0fg\x15\x19h(\0h/&g;\x06g$>e\f:g\x19;e=\x15f\x1c,g+\x19i\x1c\0h&\x01d;7f f\x0e%e\x1b=e.6e;:h.>f\x1c\ve\x0f\vi\x18\x05h/;f3\x15e>\vd=\rg=.g;\x0ff5\x0ei\0\tf\v)h?\x19f 7e=\x13e\t\re\b\x06g1;f\x0e\x12h!\fe\x1b d8:d:$f\x18\x13f\x1c\0e\x10\x0ei\x1f3d9\x10d8\rh\x03=i\0\x1ah?\x07h!\fd8\x1ag\'\x11f\n\0e\x0f/h\x03=h.>e$\x07e\x10\bd=\x1ce$\'e.6g$>d<\x1ag \x14g)6d8\x13d8\x1ae\x05(i\x03(i!9g\x1b.h?\x19i\x07\fh?\x18f\x18/e<\0e\'\vf\x03\x05e\x065g\x145h\x04\x11f\x16\x07d;6e\x13\x01g\t\fe8.e\n)f\x16\x07e\f\x16h5\x04f:\x10e$\'e-&e-&d9 e\x1c0e\x1d\0f5\x0fh\'\bf\n\x15h5\x04e7%g(\vh&\x01f1\x02f\0\x0ed9\bf\x176e\0\x19e\n\x1fh\x03=d8;h&\x01g\x1b.e\t\rh5\x04h./e\x1f\x0ee8\x02f\x169f3\x15g\x145e=1f\v\x1bh\x01\x18e#0f\x18\x0ed;;d=\x15e\x01%e:7f\x150f\r.g>\x0ee\x1b=f1=h=&d;\vg;\rd=\x06f\x18/d:$f5\x01g\x14\x1fd:\'f\t\0d;%g\x145h/\x1df\x18>g$:d8\0d:\x1be\r\x15d=\rd::e\x11\x18e\b\x06f\x1e\x10e\x1c0e\x1b>f\x17\x05f88e7%e\x057e-&g\x14\x1fg3;e\b\x17g=\x11e\x0f\ve8\x16e-\x10e/\x06g \x01i"\x11i\x01\x13f\x0e\'e\b6e\x1c0e\f:e\x1f:f\x1c,e\x05(e\x1b=g=\x11d8\ni\x07\rh&\x01g,,d:\fe\x16\x1cf,"h?\x1be\x05%e\x0f\vf\x03\x05h?\x19d:\x1bh\0\x03h/\x15e\x0f\x11g\x0e0e\x1f9h.-d;%d8\nf\x14?e:\x1cf\b\x10d8:g\x0e/e"\x03i&\x19f8/e\x10\ff\x176e(1d9\x10e\x0f\x11i\0\x01d8\0e.\x1ae<\0e\x0f\x11d=\x1ce\x13\x01f \x07e\x07\x06f,"h?\x0eh\'#e\x063e\x1c0f\x169d8\0d8\vd;%e\x0f\nh4#d;;f\b\x16h\0\x05e."f\b7d;#h!(g\'/e\b\x06e%3d::f\x150g \x01i\x14\0e\x14.e\x07:g\x0e0g&;g:?e:\x14g\x14(e\b\x17h!(d8\re\x10\fg<\x16h>\x11g;\x1fh.!f\x1f%h/"d8\rh&\x01f\x1c\te\x053f\x1c:f\x1e\x04e>\be$\x1af\x12-f\x14>g;\x04g;\x07f\x14?g-\x16g\x1b4f\x0e%h\x03=e\n\x1bf\x1d%f:\x10f\x19\x02i\x16\x13g\x1c\ve\b0g\x03-i\x17(e\x053i\x14.d8\x13e\f:i\x1d\x1ee88h\v1h/-g\x19>e:&e8\ff\x1c\x1bg>\x0ee%3f/\x14h>\x03g\x1f%h/\x06h\'\x04e.\x1ae;:h..i\x03(i\x17(f\x04\x0fh\'\x01g2>e=)f\x17%f\x1c,f\x0f\x10i+\x18e\x0f\x11h(\0f\x169i\x1d"e\x1f:i\x07\x11e$\x04g\x10\x06f\x1d\x03i\x19\x10e=1g\t\x07i\x136h!\fh?\x18f\x1c\te\b\x06d:+g\t)e\x13\x01g;\x0fh\x10%f7;e\n d8\x13e.6h?\x19g\'\rh/\x1di"\x18h57f\x1d%d8\x1ae\n!e\x05,e\x11\nh.0e=\x15g.\0d;\vh4(i\x07\x0fg\x147d::e=1e\x13\re<\x15g\x14(f\n%e\x11\ni\x03(e\b\x06e?+i\0\x1fe\x12(h/"f\x176e0\x1af3(f\x04\x0fg\x143h/7e-&f !e:\x14h/%e\x0e\x06e\x0f2e\x0f*f\x18/h?\x14e\x1b\x1eh4-d90e\x10\rg\'0d8:d:\x06f\b\x10e\n\x1fh/4f\x18\x0ed>\x1be:\x14e-)e-\x10d8\x13i"\x18g(\ve:\x0fd8\0h\b,f\x1c\x03e\x13!e\x0f*f\x1c\te\x056e.\x03d?\x1df\n$h\0\fd8\x14d;\ne$)g*\x17e\x0f#e\n(f\0\x01g\n6f\0\x01g\t9e\b+h.$d8:e?\x05i!;f\x1b4f\x160e0\x0fh/4f\b\x11e\0\x11d=\x1cd8:e*\x12d=\x13e\f\x05f\v,i\x02#d9\bd8\0f 7e\x1b=e\x06\x05f\x18/e\x10&f 9f\r.g\x145h\'\x06e-&i\x19"e\x057f\x1c\th?\x07g(\vg\x141d:\x0ed::f\t\re\x07:f\x1d%d8\rh?\x07f-#e\x1c(f\x18\x0ef\x18\x1ff\x15\x05d:\ve\x053g3;f \x07i"\x18e\x15\x06e\n!h>\x13e\x05%d8\0g\x1b4e\x1f:g!\0f\x15\x19e-&d:\x06h\'#e;:g-\x11g;\x13f\x1e\x1ce\x05(g\x10\x03i\0\x1ag\x1f%h.!e\b\x12e/9d:\x0eh\t:f\x1c/g\x1b8e\x06\fe\x0f\x11g\x14\x1fg\x1c\x1fg\x1a\x04e;:g+\vg-\tg:\'g1;e\x1e\vg;\x0fi*\fe.\x1eg\x0e0e\b6d=\x1cf\x1d%h\x07*f \x07g->d;%d8\ve\x0e\x1fe\b\x1bf\x17 f3\x15e\x056d8-e\0\vd::d8\0e\b\x07f\f\x07e\r\x17e\x053i\x17-i\x1b\x06e\x1b"g,,d8\te\x053f3(e\x1b f-$g\x05\'g\t\x07f71e\x1c3e\x15\x06d8\x1ae9?e7\x1ef\x17%f\x1c\x1fi+\x18g:\'f\x1c\0h?\x11g;\x11h!\fd8:d:$i\0\x1ah/\x04d;7h\'\te>\x17g2>e\r\x0ee.6e:-e.\ff\b\x10f\x04\x1fh\'\te.\th#\x05e>\x17e\b0i\x02.d;6e\b6e:&i#\x1fe\x13\x01h\x19=g\x046h=,h==f\n%d;7h.0h\0\x05f\x169f!\bh!\ff\x14?d::f0\x11g\x14(e\x13\x01d8\x1ch%?f\x0f\x10e\x07:i\x05\x12e:\x17g\x046e\x10\x0ed;\x18f,>g\x03-g\x029d;%e\t\re.\fe\x05(e\x0f\x11e8\x16h.>g=.i"\x06e/g%\x1eh\x0e7e>\x17e\b)g\x14(g;\'g;-d= d;,h?\x19d9\bf(!e<\x0fh/-h(\0h\x03=e$\x1fi\x1b\x05h\x19\x0ef\x13\rd=\x1ci#\x0ef d9&f\x1c\tf\x15\bf5\vh/\x15g\';e\n(f\t\rh\x03=e\x063e.\x1ah\x02!g%(d8\rf\x16-i\x1c\0f1\x02d8\re>\x17e\n\x1ef3\x15d9\vi\x174i\x07\x07g\x14(h\x10%i\x14\0f\n\x15h/\tg\x1b.f \x07g\b1f\x03\x05f\x11\x04e=1f\x1c\td:\x1bh$\x07h#=f\x16\x07e-&f\x1c:d<\x1af\x150e-\x17h#\x05d?.h4-g\t)e\x06\x1cf\x1d\x11e\x05(i\x1d"g2>e\x13\x01e\x056e.\x1ed:\vf\x03\x05f04e93f\x0f\x10g$:d8\ne8\x02h0"h0"f\x19.i\0\x1af\x15\x19e8\bd8\nd< g1;e\b+f-\ff\x1b2f\v%f\x1c\te\b\x1bf\x160i\x05\rd;6e\x0f*h&\x01f\x176d;#h3\x07h(\nh>>e\b0d::g\x14\x1fh."i\x18\x05h\0\x01e8\be1\x15g$:e?\x03g\x10\x06h44e-\x10g62g+\x19d8;i!\fh\x07*g\x046g:\'e\b+g.\0e\r\x15f\x149i\x1d)i\x02#d:\x1bf\x1d%h/4f\t\x13e<\0d;#g \x01e\b i\x19$h/\x01e\b8h\n\x02g\x1b.i\x07\rg\x029f,!f\x158e$\x1ae0\x11h\'\x04e\b\x12h5\x04i\x07\x11f\t>e\b0d;%e\x10\x0ee$\'e\x05(d8;i!5f\x1c\0d=3e\x1b\x1eg-\x14e$)d8\vd?\x1di\x1a\x1cg\x0e0d;#f#\0f\x1f%f\n\x15g%(e0\x0ff\x176f2\x12f\x1c\tf-#e88g\x14\x1ah\x073d;#g\x10\x06g\x1b.e=\x15e\x05,e<\0e$\re\b6i\x07\x11h\x1e\re98g&\x0fg\t\bf\x1c,e="f\b\x10e\x07\x06e$\x07h!\ff\x03\x05e\x1b\x1ee\b0f\0\x1df\x033f\0\x0ef 7e\r\x0fh..h.$h/\x01f\x1c\0e%=d:\'g\x14\x1ff\f\tg\x05\'f\x1c\rh#\x05e9?d8\x1ce\n(f<+i\x07\x07h4-f\x160f\t\vg;\x04e\x1b>i\x1d"f\x1d?e\x0f\x02h\0\x03f\x14?f2;e.9f\x18\x13e$)e\x1c0e\n*e\n\x1bd::d;,e\r\x07g:\'i\0\x1fe:&d::g\t)h0\x03f\x154f5\x01h!\fi\0 f\b\x10f\x16\x07e-\x17i\x1f)e\x1b=h48f\x18\x13e<\0e1\x15g\x1b8i\x17\x1ch!(g\x0e0e=1h\'\x06e&\x02f-$g>\x0ee.9e$\'e0\x0ff\n%i\x01\x13f\x1d!f,>e?\x03f\x03\x05h.8e$\x1af3\x15h\'\x04e.6e1\x05d9&e:\x17h?\x1ef\x0e%g+\ve\r3d8>f\n%f\n\0e7\'e%%h?\x10g\x19;e\x05%d;%f\x1d%g\x10\x06h.:d:\vd;6h\x07*g\x141d8-e\r\x0ee\n\x1ee\x05,e&\be&\bg\x1c\x1ff-#d8\ri\x14\x19e\x05(f\x16\x07e\x10\be\x10\fd;7e\0e7&e\x0f3h\x02!d;=g-\x14f!\be.\x1ei\x19\x05g\x145d?!g;\x0fg\x10\x06g\x14\x1fe\x11=e.#d< d;;e\n!f-#e<\x0fg\t9h\t2d8\vf\x1d%e\r\x0fd<\x1ae\x0f*h\x03=e=\x13g\x046i\x07\rf\x160e\x05\'e.9f\f\x07e/g(\ve\f;g\x16\x17g;\x0fh?\x07h?\x07e\x0e;d9\ve\t\rf\x146e\x05%e94e:&f\x1d\x02e?\x17g>\x0ed8=f\x1c\0i+\x18g\x19;i\x19\x06f\x1c*f\x1d%e\n e7%e\x05\rh4#f\x15\x19g(\vg\t\be\x1d\x17h:+d=\x13i\x07\re:\x06e\x07:e\x14.f\b\x10f\x1c,e="e<\x0fe\x1c\x1fh1\x06e\x07:e\x039d8\x1cf\x169i\x02.g.1e\r\x17d:,f1\x02h\x01\fe\x0f\x16e>\x17h\x01\fd=\rg\x1b8d?!i!5i\x1d"e\b\x06i\x12\x1fg=\x11i!5g!.e.\x1ae\x1b>d>\vg=\x11e\x1d\0g\'/f\x1e\x01i\x14\x19h//g\x1b.g\x1a\x04e.\x1dh4\x1df\x1c:e\x053i#\x0ei\x19)f\x0e\bf\x1d\x03g\x17\x05f/\x12e. g\t)i\x19$d:\x06h)\x15h+\x16g\x16>g\x17\x05e\x0f\nf\x176f1\x02h4-g+\x19g\x029e\x04?g+%f/\x0fe$)d8-e$.h.$h/\x06f/\x0fd8*e$)f4%e-\x17d=\x13e\x0f0g\x01#g;4f\n$f\x1c,i!5d8*f\0\'e.\x18f\x169e88h\'\x01g\x1b8f\x1c:f\b\x18g\x15%e:\x14e=\x13e>\ve8\bf\x169d>?f !e\x1b-h\x02!e8\x02f\b?e1\vf \x0fg\x1b.e\x11\x18e7%e/\x0ee\x05\x03e<\x15h57f\x149e\x0f\x18g,,e\x1b\x1bd<\x1ah.!h**f\x18\x0ei\x1a\x10g\'\x01e.\x1de.\x1dh\'\x04h\f\x03f6\bh49e\x051e\x10\fe?\x18h.0d=\x13g3;e8&f\x1d%e\x10\re-\x17g\x19e\n g\x1b\x1fe\x0f\x17e\b0d:\ff\t\ve$\'i\x07\x0ff\b\x10d::f\x150i\x07\x0fe\x051d:+e\f:e\x1f\x1fe%3e-)e\x0e\x1fe\b\x19f\t\0e\x1c(g;\x13f\x1d\x1fi\0\x1ad?!h6\x05g:\'i\x05\rg=.e=\x13f\x176d<\x18g\'\0f\0\'f\x04\x1ff\b?d:\'i\x01\nf\b2e\x07:e\x0f#f\x0f\x10d:$e01d8\x1ad?\x1de\x01%g(\ve:&e\x0f\x02f\x150d:\vd8\x1af\x154d8*e11d8\x1cf\x03\x05f\x04\x1fg\t9f.\ne\b\x06i!\x1ef\x10\x1ce0\ve1\x1ed:\x0ei\x17(f\b7h4"e\n!e#0i\x1f3e\x0f\ne\x056h4"g;\x0fe\x1d\x1af\f\x01e92i\x03(f\b\x10g+\ve\b)g\x1b\nh\0\x03h\x19\x11f\b\x10i\x03=e\f\x05h#\x05g\x14(f\b6f/\x14h5\x1bf\x16\x07f\x18\x0ef\v\x1be\x15\x06e.\ff\x154g\x1c\x1ff\x18/g\x1ce/\x06g"\x0ei#\x1fg;?h\t2g(3e.\x1ag;\bd:\x0eg\x14\x1fg\t)d>\x1bf1\x02f\x10\x1cg\v\x10e\n\x1bi\x07\x0fd8%i\x07\rf08h?\x1ce\x06\x19g\x1c\x1ff\x1c\ti\x19\x10g+\x1ed:\te/9h1!h49g\x14(d8\re%=g;\x1de/9e\r\x01e\b\x06d?\x03h?\x1bg\x029h/\x04e=1i\x1f3d<\x18e\n?d8\re0\x11f,#h5\x0fe96d8\x14f\x1c\tg\x029f\x169e\x10\x11e\x05(f\x160d?!g\x14(h.>f\x16=e="h1!h5\x04f \x0ee\x15\x06e\x1f\x0eg;\x1fd8\0e\x07:g\t\bf\t\x13i\0 g\x14"e\x13\x01f&\x02e\x065g\x14(d:\x0ed?\x1dg\x15\x19e\x1b g4 d8-e\x1c\ve-\x18e\x02(h44e\x1b>f\x1c\0f\x04\x1bi\x15?f\x1c\x1fe\x0f#d;7g\x10\x06h4"e\x1f:e\x1c0e.\tf\x0e\x12f-&f1\ti\x07\fi\x1d"e\b\x1be;:e$)g):i&\x16e\x05\be.\fe\x16\x04i)1e\n(d8\vi\x1d"d8\re\x06\rh/\x1ad?!f\x04\x0fd9\ti\x183e\x05\th\v1e\x1b=f<\x02d:.e\x06\x1bd:\vg\x0e)e.6g>$d<\x17e\x06\x1cf0\x11e\r3e\x0f/e\x10\rg(1e.6e\x057e\n(g\x14;f\x033e\b0f3(f\x18\x0ee0\x0fe-&f\0\'h\x03=h\0\x03g \x14g!,d;6h\'\x02g\x1c\vf8\x05f%\x1af\x10\x1eg,\x11i&\x16i \x01i;\x04i\x07\x11i\0\x02g\x14(f1\x1fh\v\x0fg\x1c\x1fe.\x1ed8;g.!i\x186f.5h(;e\x06\ng?;h/\x11f\x1d\x03e\b)e\x01\x1ae%=d<P:P0P:P8P;P8Q\rQ\x02P>P2Q\x01P5P5P3P>P?Q\0P8Q\x02P0P:P5Q\tP5Q\x03P6P5P\x1aP0P:P1P5P7P1Q\vP;P>P=P8P\x12Q\x01P5P?P>P4P-Q\x02P>Q\x02P>PP=P0P3P4P5PP3P>P4P2P>Q\x02Q\x02P0PP2P0Q\x01P2P0PQ\x02Q\x03Q\x02P=P0P4P4P=Q\x0fP\x12P>Q\x02Q\x02Q\0P8P=P5P9P\x12P0Q\x01P=P8PQ\x02Q\0Q\x03P1P\x1eP=P8PPP9P4P2P5P>P=P>Q\x01Q\x03P4`$\x15`%\x07`$9`%\b`$\x15`%\0`$8`%\x07`$\x15`$>`$\x15`%\v`$\x14`$0`$*`$0`$(`%\x07`$\x0f`$\x15`$\x15`$?`$-`%\0`$\x07`$8`$\x15`$0`$$`%\v`$9`%\v`$\x06`$*`$9`%\0`$/`$9`$/`$>`$$`$\x15`$%`$>jagran`$\x06`$\x1c`$\x1c`%\v`$\x05`$,`$&`%\v`$\x17`$\b`$\x1c`$>`$\x17`$\x0f`$9`$.`$\x07`$(`$5`$9`$/`%\x07`$%`%\x07`$%`%\0`$\x18`$0`$\x1c`$,`$&`%\0`$\x15`$\b`$\x1c`%\0`$5`%\x07`$(`$\b`$(`$\x0f`$9`$0`$\t`$8`$.`%\x07`$\x15`$.`$5`%\v`$2`%\x07`$8`$,`$.`$\b`$&`%\x07`$\x13`$0`$\x06`$.`$,`$8`$-`$0`$,`$(`$\x1a`$2`$.`$(`$\x06`$\x17`$8`%\0`$2`%\0X9Y\x04Y\tX%Y\x04Y\tY\x07X0X\'X"X.X1X9X/X/X\'Y\x04Y\tY\x07X0Y\x07X5Y\bX1X:Y\nX1Y\x03X\'Y\x06Y\bY\x04X\'X(Y\nY\x06X9X1X6X0Y\x04Y\x03Y\x07Y\x06X\'Y\nY\bY\x05Y\x02X\'Y\x04X9Y\x04Y\nX\'Y\x06X\'Y\x04Y\x03Y\x06X-X*Y\tY\x02X(Y\x04Y\bX-X)X\'X.X1Y\x01Y\x02X7X9X(X/X1Y\x03Y\x06X%X0X\'Y\x03Y\x05X\'X\'X-X/X%Y\x04X\'Y\x01Y\nY\x07X(X9X6Y\x03Y\nY\x01X(X-X+Y\bY\x05Y\x06Y\bY\x07Y\bX#Y\x06X\'X,X/X\'Y\x04Y\x07X\'X3Y\x04Y\x05X9Y\x06X/Y\x04Y\nX3X9X(X1X5Y\x04Y\tY\x05Y\x06X0X(Y\x07X\'X#Y\x06Y\x07Y\x05X+Y\x04Y\x03Y\x06X*X\'Y\x04X\'X-Y\nX+Y\x05X5X1X4X1X-X-Y\bY\x04Y\bY\x01Y\nX\'X0X\'Y\x04Y\x03Y\x04Y\x05X1X)X\'Y\x06X*X\'Y\x04Y\x01X#X(Y\bX.X\'X5X#Y\x06X*X\'Y\x06Y\x07X\'Y\x04Y\nX9X6Y\bY\bY\x02X/X\'X(Y\x06X.Y\nX1X(Y\x06X*Y\x04Y\x03Y\x05X4X\'X!Y\bY\x07Y\nX\'X(Y\bY\x02X5X5Y\bY\x05X\'X1Y\x02Y\x05X#X-X/Y\x06X-Y\x06X9X/Y\x05X1X#Y\nX\'X-X)Y\x03X*X(X/Y\bY\x06Y\nX,X(Y\x05Y\x06Y\x07X*X-X*X,Y\x07X)X3Y\x06X)Y\nX*Y\x05Y\x03X1X)X:X2X)Y\x06Y\x01X3X(Y\nX*Y\x04Y\x04Y\x07Y\x04Y\x06X\'X*Y\x04Y\x03Y\x02Y\x04X(Y\x04Y\x05X\'X9Y\x06Y\x07X#Y\bY\x04X4Y\nX!Y\x06Y\bX1X#Y\x05X\'Y\x01Y\nY\x03X(Y\x03Y\x04X0X\'X*X1X*X(X(X#Y\x06Y\x07Y\x05X3X\'Y\x06Y\x03X(Y\nX9Y\x01Y\x02X/X-X3Y\x06Y\x04Y\x07Y\x05X4X9X1X#Y\x07Y\x04X4Y\x07X1Y\x02X7X1X7Y\x04X(profileservicedefaulthimselfdetailscontentsupportstartedmessagesuccessfashioncountryaccountcreatedstoriesresultsrunningprocesswritingobjectsvisiblewelcomearticleunknownnetworkcompanydynamicbrowserprivacyproblemServicerespectdisplayrequestreservewebsitehistoryfriendsoptionsworkingversionmillionchannelwindow.addressvisitedweathercorrectproductedirectforwardyou canremovedsubjectcontrolarchivecurrentreadinglibrarylimitedmanagerfurthersummarymachineminutesprivatecontextprogramsocietynumberswrittenenabledtriggersourcesloadingelementpartnerfinallyperfectmeaningsystemskeepingculture",journalprojectsurfaces"expiresreviewsbalanceEnglishContentthroughPlease opinioncontactaverageprimaryvillageSpanishgallerydeclinemeetingmissionpopularqualitymeasuregeneralspeciessessionsectionwriterscounterinitialreportsfiguresmembersholdingdisputeearlierexpressdigitalpictureAnothermarriedtrafficleadingchangedcentralvictoryimages/reasonsstudiesfeaturelistingmust beschoolsVersionusuallyepisodeplayinggrowingobviousoverlaypresentactions</ul>\r\nwrapperalreadycertainrealitystorageanotherdesktopofferedpatternunusualDigitalcapitalWebsitefailureconnectreducedAndroiddecadesregular & animalsreleaseAutomatgettingmethodsnothingPopularcaptionletterscapturesciencelicensechangesEngland=1&History = new CentralupdatedSpecialNetworkrequirecommentwarningCollegetoolbarremainsbecauseelectedDeutschfinanceworkersquicklybetweenexactlysettingdiseaseSocietyweaponsexhibit<!--Controlclassescoveredoutlineattacksdevices(windowpurposetitle="Mobile killingshowingItaliandroppedheavilyeffects-1\']);\nconfirmCurrentadvancesharingopeningdrawingbillionorderedGermanyrelated</form>includewhetherdefinedSciencecatalogArticlebuttonslargestuniformjourneysidebarChicagoholidayGeneralpassage,"animatefeelingarrivedpassingnaturalroughly.\n\nThe but notdensityBritainChineselack oftributeIreland" data-factorsreceivethat isLibraryhusbandin factaffairsCharlesradicalbroughtfindinglanding:lang="return leadersplannedpremiumpackageAmericaEdition]"Messageneed tovalue="complexlookingstationbelievesmaller-mobilerecordswant tokind ofFirefoxyou aresimilarstudiedmaximumheadingrapidlyclimatekingdomemergedamountsfoundedpioneerformuladynastyhow to SupportrevenueeconomyResultsbrothersoldierlargelycalling."AccountEdward segmentRobert effortsPacificlearnedup withheight:we haveAngelesnations_searchappliedacquiremassivegranted: falsetreatedbiggestbenefitdrivingStudiesminimumperhapsmorningsellingis usedreversevariant role="missingachievepromotestudentsomeoneextremerestorebottom:evolvedall thesitemapenglishway to AugustsymbolsCompanymattersmusicalagainstserving})();\r\npaymenttroubleconceptcompareparentsplayersregionsmonitor \'\'The winningexploreadaptedGalleryproduceabilityenhancecareers). The collectSearch ancientexistedfooter handlerprintedconsoleEasternexportswindowsChannelillegalneutralsuggest_headersigning.html">settledwesterncausing-webkitclaimedJusticechaptervictimsThomas mozillapromisepartieseditionoutside:false,hundredOlympic_buttonauthorsreachedchronicdemandssecondsprotectadoptedprepareneithergreatlygreateroverallimprovecommandspecialsearch.worshipfundingthoughthighestinsteadutilityquarterCulturetestingclearlyexposedBrowserliberal} catchProjectexamplehide();FloridaanswersallowedEmperordefenseseriousfreedomSeveral-buttonFurtherout of != nulltrainedDenmarkvoid(0)/all.jspreventRequestStephen\n\nWhen observe</h2>\r\nModern provide" alt="borders.\n\nFor \n\nMany artistspoweredperformfictiontype ofmedicalticketsopposedCouncilwitnessjusticeGeorge Belgium...</a>twitternotablywaitingwarfare Other rankingphrasesmentionsurvivescholar</p>\r\n Countryignoredloss ofjust asGeorgiastrange<head><stopped1\']);\r\nislandsnotableborder:list ofcarried100,000</h3>\n severalbecomesselect wedding00.htmlmonarchoff theteacherhighly biologylife ofor evenrise of»plusonehunting(thoughDouglasjoiningcirclesFor theAncientVietnamvehiclesuch ascrystalvalue =Windowsenjoyeda smallassumed<a id="foreign All rihow theDisplayretiredhoweverhidden;battlesseekingcabinetwas notlook atconductget theJanuaryhappensturninga:hoverOnline French lackingtypicalextractenemieseven ifgeneratdecidedare not/searchbeliefs-image:locatedstatic.login">convertviolententeredfirst">circuitFinlandchemistshe was10px;">as suchdivided</span>will beline ofa greatmystery/index.fallingdue to railwaycollegemonsterdescentit withnuclearJewish protestBritishflowerspredictreformsbutton who waslectureinstantsuicidegenericperiodsmarketsSocial fishingcombinegraphicwinners<br /><by the NaturalPrivacycookiesoutcomeresolveSwedishbrieflyPersianso muchCenturydepictscolumnshousingscriptsnext tobearingmappingrevisedjQuery(-width:title">tooltipSectiondesignsTurkishyounger.match(})();\n\nburningoperatedegreessource=Richardcloselyplasticentries</tr>\r\ncolor:#ul id="possessrollingphysicsfailingexecutecontestlink toDefault<br />\n: true,chartertourismclassicproceedexplain</h1>\r\nonline.?xml vehelpingdiamonduse theairlineend --\x3e).attr(readershosting#ffffffrealizeVincentsignals src="/ProductdespitediversetellingPublic held inJoseph theatreaffects<style>a largedoesn\'tlater, ElementfaviconcreatorHungaryAirportsee theso thatMichaelSystemsPrograms, and width=e"tradingleft">\npersonsGolden Affairsgrammarformingdestroyidea ofcase ofoldest this is.src = cartoonregistrCommonsMuslimsWhat isin manymarkingrevealsIndeed,equally/show_aoutdoorescape(Austriageneticsystem,In the sittingHe alsoIslandsAcademy\n\t\t\x3c!--Daniel bindingblock">imposedutilizeAbraham(except{width:putting).html(|| [];\nDATA[ *kitchenmountedactual dialectmainly _blank\'installexpertsif(typeIt also© ">Termsborn inOptionseasterntalkingconcerngained ongoingjustifycriticsfactoryits ownassaultinvitedlastinghis ownhref="/" rel="developconcertdiagramdollarsclusterphp?id=alcohol);})();using a><span>vesselsrevivalAddressamateurandroidallegedillnesswalkingcentersqualifymatchesunifiedextinctDefensedied in\n\t\x3c!-- customslinkingLittle Book ofeveningmin.js?are thekontakttoday\'s.html" target=wearingAll Rig;\n})();raising Also, crucialabout">declare--\x3e\n<scfirefoxas muchappliesindex, s, but type = \n\r\n\x3c!--towardsRecordsPrivateForeignPremierchoicesVirtualreturnsCommentPoweredinline;povertychamberLiving volumesAnthonylogin" RelatedEconomyreachescuttinggravitylife inChapter-shadowNotable</td>\r\n returnstadiumwidgetsvaryingtravelsheld bywho arework infacultyangularwho hadairporttown of\n\nSome \'click\'chargeskeywordit willcity of(this);Andrew unique checkedor more300px; return;rsion="pluginswithin herselfStationFederalventurepublishsent totensionactresscome tofingersDuke ofpeople,exploitwhat isharmonya major":"httpin his menu">\nmonthlyofficercouncilgainingeven inSummarydate ofloyaltyfitnessand wasemperorsupremeSecond hearingRussianlongestAlbertalateralset of small">.appenddo withfederalbank ofbeneathDespiteCapitalgrounds), and percentit fromclosingcontainInsteadfifteenas well.yahoo.respondfighterobscurereflectorganic= Math.editingonline paddinga wholeonerroryear ofend of barrierwhen itheader home ofresumedrenamedstrong>heatingretainscloudfrway of March 1knowingin partBetweenlessonsclosestvirtuallinks">crossedEND --\x3efamous awardedLicenseHealth fairly wealthyminimalAfricancompetelabel">singingfarmersBrasil)discussreplaceGregoryfont copursuedappearsmake uproundedboth ofblockedsaw theofficescoloursif(docuwhen heenforcepush(fuAugust UTF-8">Fantasyin mostinjuredUsuallyfarmingclosureobject defenceuse of Medical<body>\nevidentbe usedkeyCodesixteenIslamic#000000entire widely active (typeofone cancolor =speakerextendsPhysicsterrain<tbody>funeralviewingmiddle cricketprophetshifteddoctorsRussell targetcompactalgebrasocial-bulk ofman and</td>\n he left).val()false);logicalbankinghome tonaming Arizonacredits);\n});\nfounderin turnCollinsbefore But thechargedTitle">CaptainspelledgoddessTag --\x3eAdding:but wasRecent patientback in=false&Lincolnwe knowCounterJudaismscript altered\']);\n has theunclearEvent\',both innot all\n\n\x3c!-- placinghard to centersort ofclientsstreetsBernardassertstend tofantasydown inharbourFreedomjewelry/about..searchlegendsis mademodern only ononly toimage" linear painterand notrarely acronymdelivershorter00&as manywidth="/* <![Ctitle =of the lowest picked escapeduses ofpeoples PublicMatthewtacticsdamagedway forlaws ofeasy to windowstrong simple}catch(seventhinfoboxwent topaintedcitizenI don\'tretreat. Some ww.");\nbombingmailto:made in. Many carries||{};wiwork ofsynonymdefeatsfavoredopticalpageTraunless sendingleft"><comScorAll thejQuery.touristClassicfalse" Wilhelmsuburbsgenuinebishops.split(global followsbody ofnominalContactsecularleft tochiefly-hidden-banner</li>\n\n. When in bothdismissExplorealways via thespaC1olwelfareruling arrangecaptainhis sonrule ofhe tookitself,=0&(calledsamplesto makecom/pagMartin Kennedyacceptsfull ofhandledBesides//--\x3e</able totargetsessencehim to its by common.mineralto takeways tos.org/ladvisedpenaltysimple:if theyLettersa shortHerbertstrikes groups.lengthflightsoverlapslowly lesser social </p>\n\t\tit intoranked rate oful>\r\n attemptpair ofmake itKontaktAntoniohaving ratings activestreamstrapped").css(hostilelead tolittle groups,Picture--\x3e\r\n\r\n rows=" objectinverse<footerCustomV><\\/scrsolvingChamberslaverywoundedwhereas!= \'undfor allpartly -right:Arabianbacked centuryunit ofmobile-Europe,is homerisk ofdesiredClintoncost ofage of become none ofp"Middle ead\')[0Criticsstudios>©group">assemblmaking pressedwidget.ps:" ? rebuiltby someFormer editorsdelayedCanonichad thepushingclass="but arepartialBabylonbottom carrierCommandits useAs withcoursesa thirddenotesalso inHouston20px;">accuseddouble goal ofFamous ).bind(priests Onlinein Julyst + "gconsultdecimalhelpfulrevivedis veryr\'+\'iptlosing femalesis alsostringsdays ofarrivalfuture <objectforcingString(" />\n\t\there isencoded. The balloondone by/commonbgcolorlaw of Indianaavoidedbut the2px 3pxjquery.after apolicy.men andfooter-= true;for usescreen.Indian image =family,http://  driverseternalsame asnoticedviewers})();\n is moreseasonsformer the newis justconsent Searchwas thewhy theshippedbr><br>width: height=made ofcuisineis thata very Admiral fixed;normal MissionPress, ontariocharsettry to invaded="true"spacingis mosta more totallyfall of});\r\n immensetime inset outsatisfyto finddown tolot of Playersin Junequantumnot thetime todistantFinnishsrc = (single help ofGerman law andlabeledforestscookingspace">header-well asStanleybridges/globalCroatia About [0];\n it, andgroupedbeing a){throwhe madelighterethicalFFFFFF"bottom"like a employslive inas seenprintermost ofub-linkrejectsand useimage">succeedfeedingNuclearinformato helpWomen\'sNeitherMexicanprotein<table by manyhealthylawsuitdevised.push({sellerssimply Through.cookie Image(older">us.js"> Since universlarger open to!-- endlies in\']);\r\n marketwho is ("DOMComanagedone fortypeof Kingdomprofitsproposeto showcenter;made itdressedwere inmixtureprecisearisingsrc = \'make a securedBaptistvoting \n\t\tvar March 2grew upClimate.removeskilledway the</head>face ofacting right">to workreduceshas haderectedshow();action=book ofan area== "htt<header\n<html>conformfacing cookie.rely onhosted .customhe wentbut forspread Family a meansout theforums.footage">MobilClements" id="as highintense--\x3e\x3c!--female is seenimpliedset thea stateand hisfastestbesidesbutton_bounded"><img Infoboxevents,a youngand areNative cheaperTimeoutand hasengineswon the(mostlyright: find a -bottomPrince area ofmore ofsearch_nature,legallyperiod,land ofor withinducedprovingmissilelocallyAgainstthe wayk"px;">\r\npushed abandonnumeralCertainIn thismore inor somename isand, incrownedISBN 0-createsOctobermay notcenter late inDefenceenactedwish tobroadlycoolingonload=it. TherecoverMembersheight assumes<html>\npeople.in one =windowfooter_a good reklamaothers,to this_cookiepanel">London,definescrushedbaptismcoastalstatus title" move tolost inbetter impliesrivalryservers SystemPerhapses and contendflowinglasted rise inGenesisview ofrising seem tobut in backinghe willgiven agiving cities.flow of Later all butHighwayonly bysign ofhe doesdiffersbattery&lasinglesthreatsintegertake onrefusedcalled =US&See thenativesby thissystem.head of:hover,lesbiansurnameand allcommon/header__paramsHarvard/pixel.removalso longrole ofjointlyskyscraUnicodebr />\r\nAtlantanucleusCounty,purely count">easily build aonclicka givenpointerh"events else {\nditionsnow the, with man whoorg/Webone andcavalryHe diedseattle00,000 {windowhave toif(windand itssolely m"renewedDetroitamongsteither them inSenatorUs</a><King ofFrancis-produche usedart andhim andused byscoringat hometo haverelatesibilityfactionBuffalolink"><what hefree toCity ofcome insectorscountedone daynervoussquare };if(goin whatimg" alis onlysearch/tuesdaylooselySolomonsexual - <a hrmedium"DO NOT France,with a war andsecond take a >\r\n\r\n\r\nmarket.highwaydone inctivity"last">obligedrise to"undefimade to Early praisedin its for hisathleteJupiterYahoo! termed so manyreally s. The a woman?value=direct right" bicycleacing="day andstatingRather,higher Office are nowtimes, when a pay foron this-link">;borderaround annual the Newput the.com" takin toa brief(in thegroups.; widthenzymessimple in late{returntherapya pointbanninginks">\n();" rea place\\u003Caabout atr>\r\n\t\tccount gives a<SCRIPTRailwaythemes/toolboxById("xhumans,watchesin some if (wicoming formats Under but hashanded made bythan infear ofdenoted/iframeleft involtagein eacha"base ofIn manyundergoregimesaction </p>\r\n<ustomVa;></importsor thatmostly &re size="</a></ha classpassiveHost = WhetherfertileVarious=[];(fucameras/></td>acts asIn some>\r\n\r\n<!organis <br />BeijingcatalC deutscheuropeueuskaragaeilgesvenskaespaC1amensajeusuariotrabajomC)xicopC!ginasiempresistemaoctubreduranteaC1adirempresamomentonuestroprimeratravC)sgraciasnuestraprocesoestadoscalidadpersonanC:meroacuerdomC:sicamiembroofertasalgunospaC-sesejemploderechoademC!sprivadoagregarenlacesposiblehotelessevillaprimeroC:ltimoeventosarchivoculturamujeresentradaanuncioembargomercadograndesestudiomejoresfebrerodiseC1oturismocC3digoportadaespaciofamiliaantoniopermiteguardaralgunaspreciosalguiensentidovisitastC-tuloconocersegundoconsejofranciaminutossegundatenemosefectosmC!lagasesiC3nrevistagranadacompraringresogarcC-aacciC3necuadorquienesinclusodeberC!materiahombresmuestrapodrC-amaC1anaC:ltimaestamosoficialtambienningC:nsaludospodemosmejorarpositionbusinesshomepagesecuritylanguagestandardcampaignfeaturescategoryexternalchildrenreservedresearchexchangefavoritetemplatemilitaryindustryservicesmaterialproductsz-index:commentssoftwarecompletecalendarplatformarticlesrequiredmovementquestionbuildingpoliticspossiblereligionphysicalfeedbackregisterpicturesdisabledprotocolaudiencesettingsactivityelementslearninganythingabstractprogressoverviewmagazineeconomictrainingpressurevarious <strong>propertyshoppingtogetheradvancedbehaviordownloadfeaturedfootballselectedLanguagedistanceremembertrackingpasswordmodifiedstudentsdirectlyfightingnortherndatabasefestivalbreakinglocationinternetdropdownpracticeevidencefunctionmarriageresponseproblemsnegativeprogramsanalysisreleasedbanner">purchasepoliciesregionalcreativeargumentbookmarkreferrerchemicaldivisioncallbackseparateprojectsconflicthardwareinterestdeliverymountainobtained= false;for(var acceptedcapacitycomputeridentityaircraftemployedproposeddomesticincludesprovidedhospitalverticalcollapseapproachpartnerslogo"><adaughterauthor" culturalfamilies/images/assemblypowerfulteachingfinisheddistrictcriticalcgi-bin/purposesrequireselectionbecomingprovidesacademicexerciseactuallymedicineconstantaccidentMagazinedocumentstartingbottom">observed: "extendedpreviousSoftwarecustomerdecisionstrengthdetailedslightlyplanningtextareacurrencyeveryonestraighttransferpositiveproducedheritageshippingabsolutereceivedrelevantbutton" violenceanywherebenefitslaunchedrecentlyalliancefollowedmultiplebulletinincludedoccurredinternal$(this).republic><tr><tdcongressrecordedultimatesolution<ul id="discoverHome</a>websitesnetworksalthoughentirelymemorialmessagescontinueactive">somewhatvictoriaWestern title="LocationcontractvisitorsDownloadwithout right">\nmeasureswidth = variableinvolvedvirginianormallyhappenedaccountsstandingnationalRegisterpreparedcontrolsaccuratebirthdaystrategyofficialgraphicscriminalpossiblyconsumerPersonalspeakingvalidateachieved.jpg" />machines</h2>\n keywordsfriendlybrotherscombinedoriginalcomposedexpectedadequatepakistanfollow" valuable</label>relativebringingincreasegovernorplugins/List of Header">" name=" ("graduate</head>\ncommercemalaysiadirectormaintain;height:schedulechangingback to catholicpatternscolor: #greatestsuppliesreliable</ul>\n\t\t<select citizensclothingwatching<li id="specificcarryingsentence<center>contrastthinkingcatch(e)southernMichael merchantcarouselpadding:interior.split("lizationOctober ){returnimproved-->\n\ncoveragechairman.png" />subjectsRichard whateverprobablyrecoverybaseballjudgmentconnect..css" /> websitereporteddefault"/></a>\r\nelectricscotlandcreationquantity. ISBN 0did not instance-search-" lang="speakersComputercontainsarchivesministerreactiondiscountItalianocriteriastrongly: \'http:\'script\'coveringofferingappearedBritish identifyFacebooknumerousvehiclesconcernsAmericanhandlingdiv id="William provider_contentaccuracysection andersonflexibleCategorylawrence<script>layout="approved maximumheader"></table>Serviceshamiltoncurrent canadianchannels/themes//articleoptionalportugalvalue=""intervalwirelessentitledagenciesSearch" measuredthousandspending…new Date" size="pageNamemiddle" " /></a>hidden">sequencepersonaloverflowopinionsillinoislinks">\n\t<title>versionssaturdayterminalitempropengineersectionsdesignerproposal="false"EspaC1olreleasessubmit" er"additionsymptomsorientedresourceright"><pleasurestationshistory.leaving border=contentscenter">.\n\nSome directedsuitablebulgaria.show();designedGeneral conceptsExampleswilliamsOriginal"><span>search">operatorrequestsa "allowingDocumentrevision. \n\nThe yourselfContact michiganEnglish columbiapriorityprintingdrinkingfacilityreturnedContent officersRussian generate-8859-1"indicatefamiliar qualitymargin:0 contentviewportcontacts-title">portable.length eligibleinvolvesatlanticonload="default.suppliedpaymentsglossary\n\nAfter guidance</td><tdencodingmiddle">came to displaysscottishjonathanmajoritywidgets.clinicalthailandteachers<head>\n\taffectedsupportspointer;toString</small>oklahomawill be investor0" alt="holidaysResourcelicensed (which . After considervisitingexplorerprimary search" android"quickly meetingsestimate;return ;color:# height=approval, " checked.min.js"magnetic></a></hforecast. While thursdaydvertiseéhasClassevaluateorderingexistingpatients Online coloradoOptions"campbell\x3c!-- end</span><<br />\r\n_popups|sciences," quality Windows assignedheight: <b classle" value=" Companyexamples<iframe believespresentsmarshallpart of properly).\n\nThe taxonomymuch of </span>\n" data-srtuguC*sscrollTo project<head>\r\nattorneyemphasissponsorsfancyboxworld\'s wildlifechecked=sessionsprogrammpx;font- Projectjournalsbelievedvacationthompsonlightingand the special border=0checking</tbody><button Completeclearfix\n<head>\narticle <sectionfindingsrole in popular Octoberwebsite exposureused to changesoperatedclickingenteringcommandsinformed numbers </div>creatingonSubmitmarylandcollegesanalyticlistingscontact.loggedInadvisorysiblingscontent"s")s. This packagescheckboxsuggestspregnanttomorrowspacing=icon.pngjapanesecodebasebutton">gamblingsuch as , while </span> missourisportingtop:1px .</span>tensionswidth="2lazyloadnovemberused in height="cript">\n </<tr><td height:2/productcountry include footer" <!-- title"></jquery.</form>\n(g.\0d=\x13)(g9\x01i+\x14)hrvatskiitalianoromC"nD\x03tC<rkC\'eX\'X1X/Y\btambiC)nnoticiasmensajespersonasderechosnacionalserviciocontactousuariosprogramagobiernoempresasanunciosvalenciacolombiadespuC)sdeportesproyectoproductopC:bliconosotroshistoriapresentemillonesmediantepreguntaanteriorrecursosproblemasantiagonuestrosopiniC3nimprimirmientrasamC)ricavendedorsociedadrespectorealizarregistropalabrasinterC)sentoncesespecialmiembrosrealidadcC3rdobazaragozapC!ginassocialesbloqueargestiC3nalquilersistemascienciascompletoversiC3ncompletaestudiospC:blicaobjetivoalicantebuscadorcantidadentradasaccionesarchivossuperiormayorC-aalemaniafunciC3nC:ltimoshaciendoaquellosediciC3nfernandoambientefacebooknuestrasclientesprocesosbastantepresentareportarcongresopublicarcomerciocontratojC3venesdistritotC)cnicaconjuntoenergC-atrabajarasturiasrecienteutilizarboletC-nsalvadorcorrectatrabajosprimerosnegocioslibertaddetallespantallaprC3ximoalmerC-aanimalesquiC)nescorazC3nsecciC3nbuscandoopcionesexteriorconceptotodavC-agalerC-aescribirmedicinalicenciaconsultaaspectoscrC-ticadC3laresjusticiadeberC!nperC-odonecesitamantenerpequeC1orecibidatribunaltenerifecanciC3ncanariasdescargadiversosmallorcarequieretC)cnicodeberC-aviviendafinanzasadelantefuncionaconsejosdifC-cilciudadesantiguasavanzadatC)rminounidadessC!nchezcampaC1asoftonicrevistascontienesectoresmomentosfacultadcrC)ditodiversassupuestofactoressegundospequeC1aP3P>P4P0P5Q\x01P;P8P5Q\x01Q\x02Q\fP1Q\vP;P>P1Q\vQ\x02Q\fQ\rQ\x02P>P<P\x15Q\x01P;P8Q\x02P>P3P>P<P5P=Q\x0fP2Q\x01P5Q\x05Q\rQ\x02P>P9P4P0P6P5P1Q\vP;P8P3P>P4Q\x03P4P5P=Q\fQ\rQ\x02P>Q\x02P1Q\vP;P0Q\x01P5P1Q\x0fP>P4P8P=Q\x01P5P1P5P=P0P4P>Q\x01P0P9Q\x02Q\x04P>Q\x02P>P=P5P3P>Q\x01P2P>P8Q\x01P2P>P9P8P3Q\0Q\vQ\x02P>P6P5P2Q\x01P5P<Q\x01P2P>Q\x0eP;P8Q\bQ\fQ\rQ\x02P8Q\x05P?P>P:P0P4P=P5P9P4P>P<P0P<P8Q\0P0P;P8P1P>Q\x02P5P<Q\x03Q\x05P>Q\x02Q\x0fP4P2Q\x03Q\x05Q\x01P5Q\x02P8P;Q\x0eP4P8P4P5P;P>P<P8Q\0P5Q\x02P5P1Q\x0fQ\x01P2P>P5P2P8P4P5Q\x07P5P3P>Q\rQ\x02P8P<Q\x01Q\x07P5Q\x02Q\x02P5P<Q\vQ\x06P5P=Q\vQ\x01Q\x02P0P;P2P5P4Q\fQ\x02P5P<P5P2P>P4Q\vQ\x02P5P1P5P2Q\vQ\bP5P=P0P<P8Q\x02P8P?P0Q\x02P>P<Q\x03P?Q\0P0P2P;P8Q\x06P0P>P4P=P0P3P>P4Q\vP7P=P0Q\x0eP<P>P3Q\x03P4Q\0Q\x03P3P2Q\x01P5P9P8P4P5Q\x02P:P8P=P>P>P4P=P>P4P5P;P0P4P5P;P5Q\x01Q\0P>P:P8Q\x0eP=Q\x0fP2P5Q\x01Q\fP\x15Q\x01Q\x02Q\fQ\0P0P7P0P=P0Q\bP8X\'Y\x04Y\x04Y\x07X\'Y\x04X*Y\nX,Y\x05Y\nX9X.X\'X5X)X\'Y\x04X0Y\nX9Y\x04Y\nY\x07X,X/Y\nX/X\'Y\x04X"Y\x06X\'Y\x04X1X/X*X-Y\x03Y\x05X5Y\x01X-X)Y\x03X\'Y\x06X*X\'Y\x04Y\x04Y\nY\nY\x03Y\bY\x06X4X(Y\x03X)Y\x01Y\nY\x07X\'X(Y\x06X\'X*X-Y\bX\'X!X#Y\x03X+X1X.Y\x04X\'Y\x04X\'Y\x04X-X(X/Y\x04Y\nY\x04X/X1Y\bX3X\'X6X:X7X*Y\x03Y\bY\x06Y\x07Y\x06X\'Y\x03X3X\'X-X)Y\x06X\'X/Y\nX\'Y\x04X7X(X9Y\x04Y\nY\x03X4Y\x03X1X\'Y\nY\x05Y\x03Y\x06Y\x05Y\x06Y\x07X\'X4X1Y\x03X)X1X&Y\nX3Y\x06X4Y\nX7Y\x05X\'X0X\'X\'Y\x04Y\x01Y\x06X4X(X\'X(X*X9X(X1X1X-Y\x05X)Y\x03X\'Y\x01X)Y\nY\x02Y\bY\x04Y\x05X1Y\x03X2Y\x03Y\x04Y\x05X)X#X-Y\x05X/Y\x02Y\x04X(Y\nY\nX9Y\x06Y\nX5Y\bX1X)X7X1Y\nY\x02X4X\'X1Y\x03X,Y\bX\'Y\x04X#X.X1Y\tY\x05X9Y\x06X\'X\'X(X-X+X9X1Y\bX6X(X4Y\x03Y\x04Y\x05X3X,Y\x04X(Y\x06X\'Y\x06X.X\'Y\x04X/Y\x03X*X\'X(Y\x03Y\x04Y\nX)X(X/Y\bY\x06X#Y\nX6X\'Y\nY\bX,X/Y\x01X1Y\nY\x02Y\x03X*X(X*X#Y\x01X6Y\x04Y\x05X7X(X.X\'Y\x03X+X1X(X\'X1Y\x03X\'Y\x01X6Y\x04X\'X-Y\x04Y\tY\x06Y\x01X3Y\x07X#Y\nX\'Y\x05X1X/Y\bX/X#Y\x06Y\x07X\'X/Y\nY\x06X\'X\'Y\x04X\'Y\x06Y\x05X9X1X6X*X9Y\x04Y\x05X/X\'X.Y\x04Y\x05Y\x05Y\x03Y\x06\0\0\0\0\0\0\0\0\x01\0\x01\0\x01\0\x01\0\x02\0\x02\0\x02\0\x02\0\x04\0\x04\0\x04\0\x04\0\0\x01\x02\x03\x04\x05\x06\x07\x07\x06\x05\x04\x03\x02\x01\0\b\t\n\v\f\r\x0e\x0f\x0f\x0e\r\f\v\n\t\b\x10\x11\x12\x13\x14\x15\x16\x17\x17\x16\x15\x14\x13\x12\x11\x10\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x1f\x1e\x1d\x1c\x1b\x1a\x19\x18\x7f\x7f\x7f\x7f\0\0\0\0\0\0\0\0\x7f\x7f\x7f\x7f\x01\0\0\0\x02\0\0\0\x02\0\0\0\x01\0\0\0\x01\0\0\0\x03\0\0\0\x7f\x7f\0\x01\0\0\0\x01\0\0\x7f\x7f\0\x01\0\0\0\b\0\b\0\b\0\b\0\0\0\x01\0\x02\0\x03\0\x04\0\x05\0\x06\0\x07resourcescountriesquestionsequipmentcommunityavailablehighlightDTD/xhtmlmarketingknowledgesomethingcontainerdirectionsubscribeadvertisecharacter" value="</select>Australia" class="situationauthorityfollowingprimarilyoperationchallengedevelopedanonymousfunction functionscompaniesstructureagreement" title="potentialeducationargumentssecondarycopyrightlanguagesexclusivecondition</form>\r\nstatementattentionBiography} else {\nsolutionswhen the Analyticstemplatesdangeroussatellitedocumentspublisherimportantprototypeinfluence»</effectivegenerallytransformbeautifultransportorganizedpublishedprominentuntil thethumbnailNational .focus();over the migrationannouncedfooter">\nexceptionless thanexpensiveformationframeworkterritoryndicationcurrentlyclassNamecriticismtraditionelsewhereAlexanderappointedmaterialsbroadcastmentionedaffiliate</option>treatmentdifferent/default.Presidentonclick="biographyotherwisepermanentFranC\'aisHollywoodexpansionstandards</style>\nreductionDecember preferredCambridgeopponentsBusiness confusion>\n<title>presentedexplaineddoes not worldwideinterfacepositionsnewspaper</table>\nmountainslike the essentialfinancialselectionaction="/abandonedEducationparseInt(stabilityunable to\nrelationsNote thatefficientperformedtwo yearsSince thethereforewrapper">alternateincreasedBattle ofperceivedtrying tonecessaryportrayedelectionsElizabethdiscoveryinsurances.length;legendaryGeographycandidatecorporatesometimesservices.inheritedCommunityreligiouslocationsCommitteebuildingsthe worldno longerbeginningreferencecannot befrequencytypicallyinto the relative;recordingpresidentinitiallytechniquethe otherit can beexistenceunderlinethis timetelephoneitemscopepracticesadvantage);return For otherprovidingdemocracyboth the extensivesufferingsupportedcomputers functionpracticalsaid thatit may beEnglish\nsuspectedmargin: 0spiritual\n\nmicrosoftgraduallydiscussedhe becameexecutivejquery.jshouseholdconfirmedpurchasedliterallydestroyedup to thevariationremainingit is notcenturiesJapanese among thecompletedalgorithminterestsrebellionundefinedencourageresizableinvolvingsensitiveuniversalprovision(althoughfeaturingconducted), which continued-header">February numerous overflow:componentfragmentsexcellentcolspan="technicalnear the Advanced source ofexpressedHong Kong Facebookmultiple mechanismelevationoffensive\n\tsponsoreddocument.or "there arethose whomovementsprocessesdifficultsubmittedrecommendconvincedpromoting" width=".replace(classicalcoalitionhis firstdecisionsassistantindicatedevolution-wrapper"enough toalong thedelivered--\x3e\r\n\x3c!--American protectedNovember substanceautomaticaspect ofAmong theconnectedestimatesAir Forcesystem ofobjectiveimmediatemaking itpaintingsconqueredare stillproceduregrowth ofheaded byEuropean divisionsmoleculesfranchiseintentionattractedchildhoodalso useddedicatedsingaporedegree offather ofconflicts

\ncame fromwere usednote thatreceivingExecutiveeven moreaccess tocommanderPoliticalmusiciansdeliciousprisonersadvent ofUTF-8" />ContactSouthern bgcolor="series of. It was in Europepermittedvalidate.appearingofficialsseriously-languageinitiatedextendinglong-terminflationsuch thatgetCookiemarked byimplementbut it isincreasesdown the requiringdependent--\x3e\n\x3c!-- interviewWith the copies ofconsensuswas builtVenezuela(formerlythe statepersonnelstrategicfavour ofinventionWikipediacontinentvirtuallywhich wasprincipleComplete identicalshow thatprimitiveaway frommolecularpreciselydissolvedUnder theversion="> span id="sought tobelow thesurviving}his deathas in thecaused bypartiallyexisting using thewas givena list oflevels ofnotion ofOfficial dismissedscientistresemblesduplicateexplosiverecoveredall othergalleries{padding:people ofregion ofaddressesassociateimg alt="in modernshould bemethod ofreportingtimestampneeded tothe Greatregardingseemed toviewed asimpact onidea thatthe Worldheight ofexpandingThese arecurrent">carefullymaintainscharge ofClassicaladdressedpredictedownership\ndepend onsearch">\npieces ofcompetingReferencetennesseewhich has version= <gives thehistorianvalue="">padding:0view thattogether,the most was foundsubset ofattack onchildren,points ofpersonal position:allegedlyClevelandwas laterand afterare givenwas stillscrollingdesign ofmakes themuch lessAmericans.\n\nAfter , but theMuseum oflouisiana(from theminnesotaparticlesa processDominicanvolume ofreturningdefensive00px|righmade frommouseover" style="states of(which iscontinuesFranciscobuilding without awith somewho woulda form ofa part ofbefore itknown as Serviceslocation and oftenmeasuringand it ispaperbackvalues of\r\n= window.determineer" played byand early</center>from thisthe threepower andof "innerHTML<a href="y:inline;Church ofthe eventvery highofficial -height: content="/cgi-bin/to createafrikaansesperantofranC\'aislatvieE!ulietuviE3D\feE!tinaD\reE!tina`9\x04`8\x17`8"f\x17%f\x1c,h*\x1eg.\0d=\x13e-\x17g9\x01i+\x14e-\x17m\x15\x1cj5-l\x164d8:d;\0d9\bh.!g.\x17f\x1c:g,\x14h.0f\x1c,h(\x0eh+\x16e\r\0f\x1c\re\n!e\x19(d:\x12h\x01\x14g=\x11f\b?e\x1c0d:\'d?1d9\x10i\x03(e\x07:g\t\bg$>f\x0e\x12h!\ff&\x1ci\x03(h\x10=f <h?\x1bd8\0f-%f\x14/d;\x18e.\x1di*\fh/\x01g \x01e\'\x14e\x11\x18d<\x1af\x150f\r.e:\x13f6\bh49h\0\x05e\n\x1ee\x05,e.$h.(h.:e\f:f71e\x1c3e8\x02f\x12-f\x14>e\x19(e\f\x17d:,e8\x02e$\'e-&g\x14\x1fh6\nf\x1d%h6\ng.!g\x10\x06e\x11\x18d?!f\x01/g=\x11serviciosartC-culoargentinabarcelonacualquierpublicadoproductospolC-ticarespuestawikipediasiguientebC:squedacomunidadseguridadprincipalpreguntascontenidorespondervenezuelaproblemasdiciembrerelaciC3nnoviembresimilaresproyectosprogramasinstitutoactividadencuentraeconomC-aimC!genescontactardescargarnecesarioatenciC3ntelC)fonocomisiC3ncancionescapacidadencontraranC!lisisfavoritostC)rminosprovinciaetiquetaselementosfuncionesresultadocarC!cterpropiedadprincipionecesidadmunicipalcreaciC3ndescargaspresenciacomercialopinionesejercicioeditorialsalamancagonzC!lezdocumentopelC-cularecientesgeneralestarragonaprC!cticanovedadespropuestapacientestC)cnicasobjetivoscontactos`$.`%\x07`$\x02`$2`$?`$\x0f`$9`%\b`$\x02`$\x17`$/`$>`$8`$>`$%`$\x0f`$5`$\x02`$0`$9`%\x07`$\x15`%\v`$\b`$\x15`%\x01`$\x1b`$0`$9`$>`$,`$>`$&`$\x15`$9`$>`$8`$-`%\0`$9`%\x01`$\x0f`$0`$9`%\0`$.`%\b`$\x02`$&`$?`$(`$,`$>`$$diplodocs`$8`$.`$/`$0`%\x02`$*`$(`$>`$.`$*`$$`$>`$+`$?`$0`$\x14`$8`$$`$$`$0`$9`$2`%\v`$\x17`$9`%\x01`$\x06`$,`$>`$0`$&`%\x07`$6`$9`%\x01`$\b`$\x16`%\x07`$2`$/`$&`$?`$\x15`$>`$.`$5`%\x07`$,`$$`%\0`$(`$,`%\0`$\x1a`$.`%\f`$$`$8`$>`$2`$2`%\x07`$\x16`$\x1c`%\t`$,`$.`$&`$&`$$`$%`$>`$(`$9`%\0`$6`$9`$0`$\x05`$2`$\x17`$\x15`$-`%\0`$(`$\x17`$0`$*`$>`$8`$0`$>`$$`$\x15`$?`$\x0f`$\t`$8`%\x07`$\x17`$/`%\0`$9`%\x02`$\x01`$\x06`$\x17`%\x07`$\x1f`%\0`$.`$\x16`%\v`$\x1c`$\x15`$>`$0`$\x05`$-`%\0`$\x17`$/`%\x07`$$`%\x01`$.`$5`%\v`$\x1f`$&`%\x07`$\x02`$\x05`$\x17`$0`$\x10`$8`%\x07`$.`%\x07`$2`$2`$\x17`$>`$9`$>`$2`$\n`$*`$0`$\x1a`$>`$0`$\x10`$8`$>`$&`%\x07`$0`$\x1c`$?`$8`$&`$?`$2`$,`$\x02`$&`$,`$(`$>`$9`%\x02`$\x02`$2`$>`$\x16`$\x1c`%\0`$$`$,`$\x1f`$(`$.`$?`$2`$\x07`$8`%\x07`$\x06`$(`%\x07`$(`$/`$>`$\x15`%\x01`$2`$2`%\t`$\x17`$-`$>`$\x17`$0`%\x07`$2`$\x1c`$\x17`$9`$0`$>`$.`$2`$\x17`%\x07`$*`%\x07`$\x1c`$9`$>`$%`$\x07`$8`%\0`$8`$9`%\0`$\x15`$2`$>`$ `%\0`$\x15`$9`$>`$\x01`$&`%\x02`$0`$$`$9`$$`$8`$>`$$`$/`$>`$&`$\x06`$/`$>`$*`$>`$\x15`$\x15`%\f`$(`$6`$>`$.`$&`%\x07`$\x16`$/`$9`%\0`$0`$>`$/`$\x16`%\x01`$&`$2`$\x17`%\0categoriesexperience\r\nCopyright javascriptconditionseverything

\nmembershiplinguisticpx;paddingphilosophyassistanceuniversityfacilitiesrecognizedpreferenceif (typeofmaintainedvocabularyhypothesis.submit();&nbsp;annotationbehind theFoundationpublisher"assumptionintroducedcorruptionscientistsexplicitlyinstead ofdimensions onClick="considereddepartmentoccupationsoon afterinvestmentpronouncedidentifiedexperimentManagementgeographic" height="link rel=".replace(/depressionconferencepunishmenteliminatedresistanceadaptationoppositionwell knownsupplementdeterminedh1 class="0px;marginmechanicalstatisticscelebratedGovernment\n\nDuring tdevelopersartificialequivalentoriginatedCommissionattachment\r\nabsolute; supportingextremely mainstream popularityemployment\r\n colspan="\n conversionabout the

integrated" lang="enPortuguesesubstituteindividualimpossiblemultimediaalmost allpx solid #apart fromsubject toin Englishcriticizedexcept forguidelinesoriginallyremarkablethe secondh2 class="
collection\r\nfunctionvisibilitythe use ofvolunteersattractionunder the threatened*\nevaluationemphasizedaccessiblesuccessionalong withMeanwhile,industries
has becomeaspects ofTelevisionsufficientbasketballboth sidescontinuingan articleadventureshis mothermanchesterprinciplesparticularcommentaryeffects ofdecided topublishersJournal ofdifficultyfacilitateacceptablestyle.css"\tfunction innovation>Copyrightsituationswould havebusinessesDictionarystatementsoften usedpersistentin Januarycomprising\n\tdiplomaticcontainingperformingextensionsmay not beconcept of onclick="It is alsofinancial making theLuxembourgadditionalare calledengaged in"script");but it waselectroniconsubmit="\n\x3c!-- End electricalofficiallysuggestiontop of theunlike theAustralianOriginallyreferences\n\r\nrecognisedinitializelimited toAlexandriaretirementAdventuresfour years\n\n<!-- increasingdecorationh3 class="origins ofobligationregulationclassified(function(advantagesbeing the historiansthe publicmany yearswhich wereover time,synonymouscontent">\npresumablyhis familyuserAgent.unexpectedincluding challengeda minorityundefined"belongs totaken fromin Octoberposition: said to bereligious Federation rowspan="only a fewmeant thatled to the--\x3e\r\n
Archbishop class="nobeing usedapproachesprivilegesnoscript>\nresults inmay be theEaster eggmechanismsreasonablePopulationCollectionselected">noscript>\r/index.phparrival of-jssdk\'));managed toincompletecasualtiescompletionChristiansSeptember arithmeticproceduresmight haveProductionit appearsPhilosophyfriendshipleading togiving thetoward theguaranteeddocumentedcolor:#000video gamecommissionreflectingchange theassociatedsans-serifonkeypress; padding:He was theunderlyingtypically , and the srcElementsuccessivesince the should be networkingaccountinguse of thelower thanshows that\n\t\tcomplaintscontinuousquantitiesastronomerhe did notdue to itsapplied toan averageefforts tothe futureattempt toTherefore,capabilityRepublicanwas formedElectronickilometerschallengespublishingthe formerindigenousdirectionssubsidiaryconspiracydetails ofand in theaffordablesubstancesreason forconventionitemtype="absolutelysupposedlyremained aattractivetravellingseparatelyfocuses onelementaryapplicablefound thatstylesheetmanuscriptstands for no-repeat(sometimesCommercialin Americaundertakenquarter ofan examplepersonallyindex.php?\npercentagebest-knowncreating a" dir="ltrLieutenant\n
is said tostructuralreferendummost oftena separate->\n
\r"; + + public const string MinMaxZoomRatio_Script = + """ + window.overrideOnZoomCropperEvent = (minZoomRatio, maxZoomRatio) => { + window.cropper.onZoom = function (imageObject, event, correlationId) { + const jSEventData = this.getJSEventData(event, correlationId); + + const isApplyPreventZoomMinRatio = (minZoomRatio != null) && (minZoomRatio > event.detail.ratio); + const isApplyPreventZoomMaxRatio = (maxZoomRatio != null) && (event.detail.ratio > maxZoomRatio); + + if (isApplyPreventZoomMinRatio || isApplyPreventZoomMaxRatio) { + event.preventDefault(); + } + else { + imageObject.invokeMethodAsync('CropperIsZoomed', jSEventData);\r\n + } + }; + }; + """; } } \ No newline at end of file From a4f22389d6f0f2f85b98d90083544d07bdfb2802 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sun, 25 Jun 2023 10:53:34 +0300 Subject: [PATCH 164/196] Absolute Crop Zoom example created --- .../Examples/AbsoluteZoomExample.razor | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/Cropper.Blazor/Client/Pages/CropZoom/Examples/AbsoluteZoomExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/CropZoom/Examples/AbsoluteZoomExample.razor b/src/Cropper.Blazor/Client/Pages/CropZoom/Examples/AbsoluteZoomExample.razor new file mode 100644 index 00000000..b7994c63 --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/CropZoom/Examples/AbsoluteZoomExample.razor @@ -0,0 +1,123 @@ +@using Cropper.Blazor.Models; +@using Cropper.Blazor.Events; +@using Cropper.Blazor.Events.ZoomEvent; +@using Cropper.Blazor.Events.CropReadyEvent; + + + + +
+ +
+
+
+ + + + + + + + + + +
+ +@code { + private CropperComponent? cropperComponent = null!; + + // Setting up initial dimensions of crop area + private Options cropperOptions = new Options + { + AspectRatio = 1m, + ViewMode = ViewMode.Vm0 + }; + + decimal _zoomRatio; + decimal _pivotX; + decimal _pivotY; + + public async void OnCropReadyEvent(JSEventData jSEventData) + { + await InvokeAsync(async () => + { + ImageData imageData = await cropperComponent!.GetImageDataAsync(); + decimal initZoomRatio = imageData.Width / imageData.NaturalWidth; + OldRatio = initZoomRatio; + + ContainerData containerData = await cropperComponent!.GetContainerDataAsync(); + // Zoom to 50% from the center of the container. + PivotX = containerData.Width / 2; + PivotY = containerData.Height / 2; + ZoomRatio = 0.5m; + StateHasChanged(); + }); + } + + private decimal ZoomRatio + { + get => _zoomRatio; + set + { + _zoomRatio = value; + cropperComponent?.ZoomTo(value, PivotX, PivotY); + } + } + + private decimal PivotX + { + get => _pivotX; + set + { + _pivotX = value; + cropperComponent?.ZoomTo(ZoomRatio, value, PivotY); + } + } + + + private decimal PivotY + { + get => _pivotY; + set + { + _pivotY = value; + cropperComponent?.ZoomTo(ZoomRatio, PivotX, value); + } + } + + private decimal? OldRatio { get; set; } + + private decimal? CurrentRatio { get; set; } + + public async void OnZoomEvent(JSEventData zoomJSEvent) + { + await InvokeAsync(() => + { + if (zoomJSEvent.Detail is not null) + { + OldRatio = zoomJSEvent.Detail.OldRatio; + CurrentRatio = zoomJSEvent.Detail.Ratio; + StateHasChanged(); + } + }); + } +} + + From 19f02d0aa74340dcc5fcb7438f973c6adb364275 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sun, 25 Jun 2023 12:15:25 +0300 Subject: [PATCH 165/196] Relative Crop Zoom example added --- .../Examples/RelativeZoomExample.razor | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/Cropper.Blazor/Client/Pages/CropZoom/Examples/RelativeZoomExample.razor diff --git a/src/Cropper.Blazor/Client/Pages/CropZoom/Examples/RelativeZoomExample.razor b/src/Cropper.Blazor/Client/Pages/CropZoom/Examples/RelativeZoomExample.razor new file mode 100644 index 00000000..775da207 --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/CropZoom/Examples/RelativeZoomExample.razor @@ -0,0 +1,91 @@ +@using Cropper.Blazor.Models; +@using Cropper.Blazor.Events; +@using Cropper.Blazor.Events.ZoomEvent; +@using Cropper.Blazor.Events.CropReadyEvent; + + + + +
+ +
+
+
+ + + + + + + + +
+ +@code { + private CropperComponent? cropperComponent = null!; + + // Setting up initial dimensions of crop area + private Options cropperOptions = new Options + { + AspectRatio = 1m, + ViewMode = ViewMode.Vm3 + }; + + decimal _zoomRatio; + + public async void OnCropReadyEvent(JSEventData jSEventData) + { + await InvokeAsync(async () => + { + ImageData imageData = await cropperComponent!.GetImageDataAsync(); + decimal initZoomRatio = imageData.Width / imageData.NaturalWidth; + + _zoomRatio = initZoomRatio; + StateHasChanged(); + }); + } + + private decimal ZoomRatio + { + get => _zoomRatio; + set + { + _zoomRatio = value; + cropperComponent?.Zoom(value); + } + } + + private decimal? OldRatio { get; set; } + + private decimal? CurrentRatio { get; set; } + + public async void OnZoomEvent(JSEventData zoomJSEvent) + { + await InvokeAsync(() => + { + if (zoomJSEvent.Detail is not null) + { + OldRatio = zoomJSEvent.Detail.OldRatio; + CurrentRatio = zoomJSEvent.Detail.Ratio; + StateHasChanged(); + } + }); + } +} + + From 89c41cedbab22bf17ee18a945ce77384a9ab463a Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Mon, 26 Jun 2023 12:42:35 +0300 Subject: [PATCH 166/196] Crop Zoom examples page updated --- .../Client/Cropper.Blazor.Client.csproj | 15 ++- .../Pages/CropZoom/CropperZoomPage.razor | 115 ++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor diff --git a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj index 4186358e..c7c26442 100644 --- a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj +++ b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj @@ -79,7 +79,17 @@ - + + + + + + + + + + + @@ -163,6 +173,9 @@ + + + diff --git a/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor b/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor new file mode 100644 index 00000000..830a708e --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor @@ -0,0 +1,115 @@ +@page "/examples/zooming" +@using Cropper.Blazor.Client.Models; +@using Cropper.Blazor.Client.Pages.CropZoom.Examples + + + + + + + Q&A +
+ + How to crop a new area after zooming in or zooming out? +
+ Just double-click your mouse to enter crop mode. +
+ + + + + You can use Zoomable boolean field in the + Option property to enable/disable to zoom the image. +

+ You can use ZoomOnTouch boolean field in the + Option property to enable/disable to + zoom the image by dragging touch. +

+ Boolean field ZoomOnWheel used to enable/disable + zoom the image by mouse wheeling. +
+
+ + + +
+ + + + + Use decimal field WheelZoomRatio in the + Option cropper component property + to define zoom ratio when zooming the image by mouse wheeling. +

+ By default, WheelZoomRatio is 0,1. +
+
+ + + +
+ + + + + For zoom the canvas (image wrapper) with a relative ratio + use Zoom(ratio) + CropperComponent method, where + ratio parameter is decimal number. +
+ + + Zoom in: requires a positive number (ratio > 0) + + + Zoom out: requires a negative number (ratio < 0) + + +
+
+ + + +
+ + + + + + For zoom the canvas (image wrapper) with a relative ratio + use ZoomTo(ratio, pivotX, pivotY) + CropperComponent method, where ratio + parameter is positive (ratio > 0) decimal number. pivotX and pivotY + parameters is the decimal coordinates of the center point for zooming, base on the top left corner of the cropper container. +

+ In the example, іmage zoomed to 50% from the center of the container. +
+
+ + + +
+ + + + + You can override the OnZoomEvent to establish minimum and/or + maximum ratio limits for zooming the canvas by preventing the default logic. +
+ To override the OnZoomEvent event, you need to use + JavaScript, in which you assign a new function to the + window.cropper.onZoom event. + An example of an event override is shown below. + + Make sure that the current Zoom Ratio value is less than the minimum value, + otherwise this setting may not work correctly. + +
+
+ + + +
+ +
+
From ed0d6693503a5483f345ab0cd12f4eb3842e9469 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sat, 21 Oct 2023 16:31:38 +0300 Subject: [PATCH 167/196] fix code smell --- src/Cropper.Blazor/Client/Models/Snippets.cs | 27 ++++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/Cropper.Blazor/Client/Models/Snippets.cs b/src/Cropper.Blazor/Client/Models/Snippets.cs index 3fa0ca4d..b81e4e78 100644 --- a/src/Cropper.Blazor/Client/Models/Snippets.cs +++ b/src/Cropper.Blazor/Client/Models/Snippets.cs @@ -20,23 +20,22 @@ public static string GetCode(string component) public const string InstallScriptManual = @""; - public const string MinMaxZoomRatio_Script = - """ + public const string MinMaxZoomRatio_Script = @" window.overrideOnZoomCropperEvent = (minZoomRatio, maxZoomRatio) => { - window.cropper.onZoom = function (imageObject, event, correlationId) { - const jSEventData = this.getJSEventData(event, correlationId); + window.cropper.onZoom = (imageObject, event, correlationId) => { + var jSEventData = this.getJSEventData(event, correlationId); - const isApplyPreventZoomMinRatio = (minZoomRatio != null) && (minZoomRatio > event.detail.ratio); - const isApplyPreventZoomMaxRatio = (maxZoomRatio != null) && (event.detail.ratio > maxZoomRatio); + var isApplyPreventZoomMinRatio = (minZoomRatio != null) && (minZoomRatio > event.detail.ratio); + var isApplyPreventZoomMaxRatio = (maxZoomRatio != null) && (event.detail.ratio > maxZoomRatio); - if (isApplyPreventZoomMinRatio || isApplyPreventZoomMaxRatio) { - event.preventDefault(); - } - else { - imageObject.invokeMethodAsync('CropperIsZoomed', jSEventData);\r\n - } + if (isApplyPreventZoomMinRatio || isApplyPreventZoomMaxRatio) { + event.preventDefault(); + } + else { + imageObject.invokeMethodAsync('CropperIsZoomed', jSEventData); + } + }; }; - }; - """; + "; } } From 4e7bfa369f321dd62c804b06387842162e3b3d6a Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sat, 21 Oct 2023 16:33:54 +0300 Subject: [PATCH 168/196] fix code smell --- src/Cropper.Blazor/Client/Models/Snippets.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Cropper.Blazor/Client/Models/Snippets.cs b/src/Cropper.Blazor/Client/Models/Snippets.cs index b81e4e78..c767c0d2 100644 --- a/src/Cropper.Blazor/Client/Models/Snippets.cs +++ b/src/Cropper.Blazor/Client/Models/Snippets.cs @@ -22,11 +22,11 @@ public static string GetCode(string component) public const string MinMaxZoomRatio_Script = @" window.overrideOnZoomCropperEvent = (minZoomRatio, maxZoomRatio) => { - window.cropper.onZoom = (imageObject, event, correlationId) => { - var jSEventData = this.getJSEventData(event, correlationId); + window.cropper.onZoom = function (imageObject, event, correlationId) { + const jSEventData = this.getJSEventData(event, correlationId); - var isApplyPreventZoomMinRatio = (minZoomRatio != null) && (minZoomRatio > event.detail.ratio); - var isApplyPreventZoomMaxRatio = (maxZoomRatio != null) && (event.detail.ratio > maxZoomRatio); + const isApplyPreventZoomMinRatio = (minZoomRatio != null) && (minZoomRatio > event.detail.ratio); + const isApplyPreventZoomMaxRatio = (maxZoomRatio != null) && (event.detail.ratio > maxZoomRatio); if (isApplyPreventZoomMinRatio || isApplyPreventZoomMaxRatio) { event.preventDefault(); From 015fce2a0fba3db0d890ee7daa9a7767338202d4 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sat, 21 Oct 2023 16:53:00 +0300 Subject: [PATCH 169/196] fix readme --- README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e790f6cc..39557f1c 100644 --- a/README.md +++ b/README.md @@ -123,9 +123,9 @@ And then use it in Razor file ([for example](https://github.com/CropperBlazor/Cr ```razor + Options="Options" + IsAvaibleInitCropper="IsAvaibleInitCropper"> ``` @@ -146,12 +147,14 @@ And then use it in [*.razor.cs file](https://github.com/CropperBlazor/Cropper.Bl You may override Cropper JavaScript module with execution script which can replace 6 event handlers (onReady, onCropStart, onCropMove, onCropEnd, onCrop, onZoom), such as overriding the onZoom callback in JavaScript: ```js -window.overrideCropperJsInteropModule = (minZoomRatio, maxZoomRatio) => { +window.overrideOnZoomCropperEvent = (minZoomRatio, maxZoomRatio) => { window.cropper.onZoom = function (imageObject, event, correlationId) { - const jSEventData = this.getJSEventData(event, correlationId); - const isApplyPreventZoomRatio = minZoomRatio != null || maxZoomRatio != null; + const jSEventData = this.getJSEventData(event, correlationId); + + const isApplyPreventZoomMinRatio = (minZoomRatio != null) && (minZoomRatio > event.detail.ratio); + const isApplyPreventZoomMaxRatio = (maxZoomRatio != null) && (event.detail.ratio > maxZoomRatio); - if (isApplyPreventZoomRatio && (event.detail.ratio < minZoomRatio || event.detail.ratio > maxZoomRatio)) { + if (isApplyPreventZoomMinRatio || isApplyPreventZoomMaxRatio) { event.preventDefault(); } else { From 5aae9e1c4a920c91b4922c9a86e935971b3f7c39 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sat, 21 Oct 2023 17:07:47 +0300 Subject: [PATCH 170/196] add examples to readme --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 39557f1c..afe9b873 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,10 @@ Cropper.Blazor is an essential component for building interactive image cropping - [CropperBlazor.github.io/demo](https://CropperBlazor.github.io/demo) ## API -- [https://cropperblazor.github.io/api](https://cropperblazor.github.io/api) +- [CropperBlazor.github.io/api](https://cropperblazor.github.io/api) + +## Examples +- [CropperBlazor.github.io/examples/cropperusage](https://cropperblazor.github.io/examples/cropperusage) ## Prerequisites - Supported .NET 7.0, .NET 6.0 versions for these web platforms: From 51264847a4ed6b51dd3759c707807b2caa8085f2 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sat, 21 Oct 2023 17:33:10 +0300 Subject: [PATCH 171/196] Fix merge bugs --- src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor | 7 ------- .../Client/Components/Docs/DocsPage.razor.cs | 2 -- .../Client/Styles/components/docssection.scss | 4 ++-- src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss | 2 +- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor b/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor index 947e263b..a94d66b8 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor +++ b/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor @@ -5,14 +5,7 @@ @ChildContent
- - @if (DisplayFooter) - { - - - } @if (_displayView) { diff --git a/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor.cs b/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor.cs index 20590af2..7acad243 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor.cs +++ b/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor.cs @@ -9,8 +9,6 @@ namespace Cropper.Blazor.Client.Components.Docs { public partial class DocsPage : ComponentBase { - [Parameter] public bool DisplayFooter { get; set; } - private Queue _bufferedSections = new(); private MudPageContentNavigation _contentNavigation; private Stopwatch _stopwatch = Stopwatch.StartNew(); diff --git a/src/Cropper.Blazor/Client/Styles/components/docssection.scss b/src/Cropper.Blazor/Client/Styles/components/docssection.scss index 413bec71..42307ec2 100644 --- a/src/Cropper.Blazor/Client/Styles/components/docssection.scss +++ b/src/Cropper.Blazor/Client/Styles/components/docssection.scss @@ -196,12 +196,12 @@ } } } - +/* @media (min-width: 1280px) { .mud-drawer-open-responsive-lg-right .mud-main-content { margin-right: 120px !important; } -} +}*/ .disabled { pointer-events: none; diff --git a/src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss b/src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss index 95380dbe..2622800a 100644 --- a/src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss +++ b/src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss @@ -1,7 +1,7 @@ .docs-title { font-family: 'Public Sans', 'Roboto', 'Arial', sans-serif; font-weight: 600; - font-size: 1.75rem; + font-size: 3.75rem; } .docs-title-description { From edfd7cbe5adc6f36314bd57521e480315a38dc9b Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sat, 21 Oct 2023 23:59:26 +0300 Subject: [PATCH 172/196] Fix scss linter warnings --- .../Client/Styles/components/docssection.scss | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Cropper.Blazor/Client/Styles/components/docssection.scss b/src/Cropper.Blazor/Client/Styles/components/docssection.scss index 42307ec2..5946a8ea 100644 --- a/src/Cropper.Blazor/Client/Styles/components/docssection.scss +++ b/src/Cropper.Blazor/Client/Styles/components/docssection.scss @@ -196,12 +196,6 @@ } } } -/* -@media (min-width: 1280px) { - .mud-drawer-open-responsive-lg-right .mud-main-content { - margin-right: 120px !important; - } -}*/ .disabled { pointer-events: none; From af0ac66a9c6cc174c0c39b1884b92ec3cf10ca96 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Sun, 22 Oct 2023 21:25:30 +0300 Subject: [PATCH 173/196] Add links for examples (#238) ## Target Add links for examples #### Open Questions ## Checklist - [x] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- src/Cropper.Blazor/Client/Components/Docs/DocsApi.razor | 1 + .../Client/Pages/AspectRatio/AspectRatioPage.razor | 4 ++-- .../Client/Pages/BasicUsage/BasicCropperUsagePage.razor | 6 +++--- .../Pages/CropBoxDimensions/CropBoxDimensionsPage.razor | 6 +++--- .../Client/Pages/CropZoom/CropperZoomPage.razor | 6 +++--- .../Client/Pages/ViewModes/ViewModesPage.razor | 6 +++--- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/Docs/DocsApi.razor b/src/Cropper.Blazor/Client/Components/Docs/DocsApi.razor index 9072c262..3ae611ce 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/DocsApi.razor +++ b/src/Cropper.Blazor/Client/Components/Docs/DocsApi.razor @@ -19,6 +19,7 @@
  • @Type.GetTypeDisplayName() diff --git a/src/Cropper.Blazor/Client/Pages/AspectRatio/AspectRatioPage.razor b/src/Cropper.Blazor/Client/Pages/AspectRatio/AspectRatioPage.razor index 64bb04f8..58b8b66f 100644 --- a/src/Cropper.Blazor/Client/Pages/AspectRatio/AspectRatioPage.razor +++ b/src/Cropper.Blazor/Client/Pages/AspectRatio/AspectRatioPage.razor @@ -23,7 +23,7 @@ You can use AspectRatio decimal field in the - Option property to define the fixed aspect ratio of the crop box. + Options property to define the fixed aspect ratio of the crop box.

    To enable free aspect ratio setting AspectRatio propety to 0. @@ -54,7 +54,7 @@ Use InitialAspectRatio in the - Option cropper component property + Options cropper component property to define the initial aspect ratio of the crop box.

    By default, it is the same as the aspect ratio of the canvas (image wrapper). diff --git a/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor b/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor index 2d6beae0..b3bea68f 100644 --- a/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor +++ b/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor @@ -8,7 +8,7 @@ Note The CropperComponent is dependant on ICropperComponentBase - Check the Installation page for instructions regarding default setup. + Check the Installation page for instructions regarding default setup. @@ -16,8 +16,8 @@ To start using the cropper component, you must specify the path to the image with which you will work in the Src property. - You also need to specify the cropper settings using the Options property, - which can be left as default, as in the example below. + You also need to specify the cropper settings using the Options property, + which can be left as default, as in the example below.
    Note: With the release of .NET 8, сropper's default settings will be set automatically, diff --git a/src/Cropper.Blazor/Client/Pages/CropBoxDimensions/CropBoxDimensionsPage.razor b/src/Cropper.Blazor/Client/Pages/CropBoxDimensions/CropBoxDimensionsPage.razor index 09324bde..8f6215c2 100644 --- a/src/Cropper.Blazor/Client/Pages/CropBoxDimensions/CropBoxDimensionsPage.razor +++ b/src/Cropper.Blazor/Client/Pages/CropBoxDimensions/CropBoxDimensionsPage.razor @@ -10,14 +10,14 @@ To set the initial dimensions of crop area (crop box), you can use the SetDataOptions property, - which is located in the Option property of the cropper. + which is located in the Options property of the cropper.

    To resize the crop area of ​​an already initialized cropper component you can use its SetData method.
    Note: This method only available when the value of the - ViewMode option is greater than or equal to 1. + ViewMode option is greater than or equal to 1. Height and width of the crop area are based on the natural size of the original image. @@ -53,7 +53,7 @@ Use the MinCropBoxHeight and MinCropBoxWidth - fields in the Option cropper component property to + fields in the Options cropper component property to enable minimum limit for the relative size of crop area
    diff --git a/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor b/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor index 830a708e..9d21193a 100644 --- a/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor +++ b/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor @@ -19,10 +19,10 @@ You can use Zoomable boolean field in the - Option property to enable/disable to zoom the image. + Options property to enable/disable to zoom the image.

    You can use ZoomOnTouch boolean field in the - Option property to enable/disable to + Options property to enable/disable to zoom the image by dragging touch.

    Boolean field ZoomOnWheel used to enable/disable @@ -38,7 +38,7 @@ Use decimal field WheelZoomRatio in the - Option cropper component property + Options cropper component property to define zoom ratio when zooming the image by mouse wheeling.

    By default, WheelZoomRatio is 0,1. diff --git a/src/Cropper.Blazor/Client/Pages/ViewModes/ViewModesPage.razor b/src/Cropper.Blazor/Client/Pages/ViewModes/ViewModesPage.razor index 4b260bf7..672ee524 100644 --- a/src/Cropper.Blazor/Client/Pages/ViewModes/ViewModesPage.razor +++ b/src/Cropper.Blazor/Client/Pages/ViewModes/ViewModesPage.razor @@ -8,7 +8,7 @@ - With the ViewMode in Options prop + With the ViewMode in Options prop you can change the view mode of the cropper.

    ViewMode enumeration contains the following view modes: @@ -34,14 +34,14 @@
    - If you set ViewMode to ViewMode. + If you set ViewMode to ViewMode. Vm0, the crop box can extend outside the canvas, while a value of Vm1, Vm2, or Vm3 will restrict the crop box to the size of the canvas. - ViewMode of Vm2 or Vm3 + ViewMode of Vm2 or Vm3 will additionally restrict the canvas to the container.
    There is no difference between Vm2 and Vm3 From a60f5a2ccd37664a6ac4a8144ab8a66fef6e9a00 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Sun, 22 Oct 2023 21:47:14 +0300 Subject: [PATCH 174/196] Feature/increase coverage unit tests (#239) ## Target Feature/increase coverage unit tests #### Open Questions ## Checklist - [x] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .github/codecov.yml | 2 +- README.md | 2 +- src/Cropper.Blazor/Client/Pages/About.razor | 1 + .../Client/Pages/CropperDemo.razor | 2 +- .../Client/Pages/CropperDemo.razor.cs | 14 +-- .../Components/CropperComponent_Should.cs | 87 +++++++++++++++++-- .../CropEndEvent/CropEndEvent_Should.cs | 40 ++++++--- .../CropMoveEvent/CropMoveEvent_Should.cs | 40 ++++++--- .../CropStartEvent/CropStartEvent_Should.cs | 40 ++++++--- .../Events/ZoomEvent/ZoomEvent_Should.cs | 40 ++++++--- .../Models/CroppedCanvas_Should.cs | 40 ++++++--- .../Components/CropperComponent.razor.cs | 42 ++++----- .../Extensions/ServiceCollectionExtensions.cs | 7 +- 13 files changed, 253 insertions(+), 104 deletions(-) diff --git a/.github/codecov.yml b/.github/codecov.yml index 4e94d0ae..1ec0f69f 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -15,7 +15,7 @@ coverage: status: project: default: - target: 90% # the required coverage value + target: 100% # the required coverage value threshold: 0.1% # the leniency in hitting the target patch: default: diff --git a/README.md b/README.md index afe9b873..0b37067f 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ And then use it in Razor file ([for example](https://github.com/CropperBlazor/Cr IsErrorLoadImage="@IsErrorLoadImage" OnErrorLoadImageEvent="OnErrorLoadImageEvent" Options="Options" - IsAvaibleInitCropper="IsAvaibleInitCropper"> + IsAvailableInitCropper="IsAvailableInitCropper"> ``` diff --git a/src/Cropper.Blazor/Client/Pages/About.razor b/src/Cropper.Blazor/Client/Pages/About.razor index 5f00f403..f13c3886 100644 --- a/src/Cropper.Blazor/Client/Pages/About.razor +++ b/src/Cropper.Blazor/Client/Pages/About.razor @@ -1,4 +1,5 @@ @page "/about" +@layout LandingLayout + IsAvailableInitCropper="IsAvailableInitCropper" />
diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 17ba0eec..7964c212 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -1,4 +1,6 @@ -using Cropper.Blazor.Client.Components; +using System.Reflection; +using System.Text.Json; +using Cropper.Blazor.Client.Components; using Cropper.Blazor.Client.Enums; using Cropper.Blazor.Components; using Cropper.Blazor.Events; @@ -14,8 +16,6 @@ using Microsoft.JSInterop; using MudBlazor; using MudBlazor.Services; -using System.Reflection; -using System.Text.Json; using ErrorEventArgs = Microsoft.AspNetCore.Components.Web.ErrorEventArgs; namespace Cropper.Blazor.Client.Pages @@ -38,7 +38,7 @@ public partial class CropperDemo : IDisposable private string Src = "https://fengyuanchen.github.io/cropperjs/v2/picture.jpg"; private bool IsErrorLoadImage { get; set; } = false; - private bool IsAvaibleInitCropper { get; set; } = true; + private bool IsAvailableInitCropper { get; set; } = true; private readonly string _errorLoadImageSrc = "not-found-image.jpg"; private Breakpoint Start; private Guid SubscriptionId; @@ -392,7 +392,7 @@ public async Task InputFileChangeAsync(InputFileChangeEventArgs inputFileChangeE Src = await CropperComponent!.GetImageUsingStreamingAsync(imageFile, imageFile.Size); - IsAvaibleInitCropper = true; + IsAvailableInitCropper = true; IsErrorLoadImage = false; CropperComponent?.Destroy(); @@ -411,12 +411,12 @@ public async Task ReplaceImageAsync(InputFileChangeEventArgs inputFileChangeEven if (IsErrorLoadImage) { - IsAvaibleInitCropper = true; + IsAvailableInitCropper = true; IsErrorLoadImage = false; } else { - IsAvaibleInitCropper = false; + IsAvailableInitCropper = false; } CropperComponent?.ReplaceAsync(src); diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs index e5cc633d..442343bc 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs @@ -272,8 +272,8 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() ComponentParameter isErrorLoadImageParameter = ComponentParameter.CreateParameter( nameof(CropperComponent.IsErrorLoadImage), false); - ComponentParameter isAvaibleInitCropperParameter = ComponentParameter.CreateParameter( - nameof(CropperComponent.IsAvaibleInitCropper), + ComponentParameter isAvailableInitCropperParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.IsAvailableInitCropper), true); ComponentParameter onLoadImageParameter = ComponentParameter.CreateParameter( nameof(CropperComponent.OnLoadImageEvent), @@ -347,7 +347,7 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() loadingParameter, errorLoadImageSrcParameter, isErrorLoadImageParameter, - isAvaibleInitCropperParameter, + isAvailableInitCropperParameter, srcParameter, imageClassParameter, onLoadImageParameter, @@ -597,8 +597,8 @@ public void Should_Not_Render_CropperComponent_With_IsNotAvaibleInitCropper_Para ComponentParameter isErrorLoadImage = ComponentParameter.CreateParameter( nameof(CropperComponent.IsErrorLoadImage), true); - ComponentParameter isAvaibleInitCropperParameter = ComponentParameter.CreateParameter( - nameof(CropperComponent.IsAvaibleInitCropper), + ComponentParameter isAvailableInitCropperParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.IsAvailableInitCropper), false); // act @@ -608,7 +608,7 @@ public void Should_Not_Render_CropperComponent_With_IsNotAvaibleInitCropper_Para loadingParameter, errorLoadImageSrcParameter, isErrorLoadImage, - isAvaibleInitCropperParameter); + isAvailableInitCropperParameter); // assert IElement expectedElement = cropperComponent.Find($"img.{errorLoadImageClass}"); @@ -650,6 +650,81 @@ public void Verify_Method_To_Be_Invokable_From_JS(string methodName) attribute.Should().NotBeNull(); } + [Fact] + public async Task Should_Render_CropperComponent_Without_Action_Parameters_SuccessfulAsync() + { + // arrange + CancellationToken cancellationToken = new(); + ProgressEventArgs progressEventArgs = new Faker() + .Generate(); + Options options = new Faker() + .Generate(); + ErrorEventArgs errorEventArgs = new Faker() + .Generate(); + JSEventData cropReadyEvent = new Faker>() + .Generate(); + JSEventData zoomEvent = new Faker>() + .Generate(); + JSEventData cropStartEvent = new Faker>() + .Generate(); + JSEventData cropMoveEvent = new Faker>() + .Generate(); + JSEventData cropEndEvent = new Faker>() + .Generate(); + JSEventData cropEvent = new Faker>() + .Generate(); + + ComponentParameter optionsParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.Options), + options); + ComponentParameter onLoadImageParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.OnLoadImageEvent), + null); + ComponentParameter onErrorLoadImageParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.OnErrorLoadImageEvent), + null); + + // act + IRenderedComponent cropperComponent = _testContext + .RenderComponent( + optionsParameter, + onLoadImageParameter, + onErrorLoadImageParameter); + + // assert + IElement expectedElement = cropperComponent.Find($"img"); + ElementReference elementReference = (ElementReference)cropperComponent.Instance + .GetInstanceField("ImageReference"); + Guid cropperComponentId = (Guid)cropperComponent.Instance + .GetInstanceField("CropperComponentId"); + + _mockCropperJsInterop.Verify(c => c.LoadModuleAsync(cancellationToken), Times.Once()); + elementReference.Id.Should().NotBeNullOrEmpty(); + expectedElement.ClassName.Should().BeNull(); + expectedElement.GetAttribute("src").Should().BeNull(); + expectedElement.GetAttribute("blazor:elementreference").Should().Be(elementReference.Id); + + expectedElement.TriggerEvent("onload", progressEventArgs); + _mockCropperJsInterop.Verify(c => c.InitCropperAsync( + cropperComponentId, + elementReference, + options, + It.IsAny>(), + cancellationToken), Times.Once()); + + expectedElement.TriggerEvent("onerror", errorEventArgs); + + await cropperComponent.InvokeAsync(() => + { + cropperComponent.Instance.IsReady(cropReadyEvent); + cropperComponent.Instance.CropperIsCroped(cropEvent); + cropperComponent.Instance.CropperIsEnded(cropEndEvent); + cropperComponent.Instance.CropperIsMoved(cropMoveEvent); + cropperComponent.Instance.CropperIsStarted(cropStartEvent); + cropperComponent.Instance.CropperIsZoomed(zoomEvent); + }); + } + public void Dispose() { _testContext.DisposeComponents(); diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropEndEvent/CropEndEvent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropEndEvent/CropEndEvent_Should.cs index 69d48e69..1f0b5efc 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropEndEvent/CropEndEvent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropEndEvent/CropEndEvent_Should.cs @@ -1,4 +1,5 @@ -using Bogus; +using System.Collections.Generic; +using Bogus; using Microsoft.JSInterop; using Moq; using Xunit; @@ -8,24 +9,37 @@ namespace Cropper.Blazor.UnitTests.Events.CropEndEvent { public class CropEndEvent_Should { - private readonly Mock _mockIJSObjectReference; - private readonly Event _event; + private static Mock _mockIJSObjectReference = null!; - public CropEndEvent_Should() + [Theory, MemberData(nameof(TestData_Verify_Dispose))] + public void Verify_Dispose(IJSObjectReference? jSObjectReference, Times times) { - _mockIJSObjectReference = new Mock(); - _event = new Faker() - .RuleFor(x => x.OriginalEvent, _mockIJSObjectReference.Object); - } + // arrange + Event @event = new Faker() + .RuleFor(x => x.OriginalEvent, jSObjectReference); - [Fact] - public void Verify_Dispose() - { // act - _event.Dispose(); + @event.Dispose(); // assert - _mockIJSObjectReference.Verify(c => c.DisposeAsync(), Times.Once()); + _mockIJSObjectReference.Verify(c => c.DisposeAsync(), times); + } + + public static IEnumerable TestData_Verify_Dispose() + { + yield return WrapArgs(null, Times.Never()); + + _mockIJSObjectReference = new Mock(); + yield return WrapArgs(_mockIJSObjectReference.Object, Times.Once()); + + static object[] WrapArgs( + IJSObjectReference? jSObjectReference, + Times times) + => new object[] + { + jSObjectReference, + times + }; } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropMoveEvent/CropMoveEvent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropMoveEvent/CropMoveEvent_Should.cs index 2d84321a..79cc67cd 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropMoveEvent/CropMoveEvent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropMoveEvent/CropMoveEvent_Should.cs @@ -1,4 +1,5 @@ -using Bogus; +using System.Collections.Generic; +using Bogus; using Microsoft.JSInterop; using Moq; using Xunit; @@ -8,24 +9,37 @@ namespace Cropper.Blazor.UnitTests.Events.CropMoveEvent { public class CropMoveEvent_Should { - private readonly Mock _mockIJSObjectReference; - private readonly Event _event; + private static Mock _mockIJSObjectReference = null!; - public CropMoveEvent_Should() + [Theory, MemberData(nameof(TestData_Verify_Dispose))] + public void Verify_Dispose(IJSObjectReference? jSObjectReference, Times times) { - _mockIJSObjectReference = new Mock(); - _event = new Faker() - .RuleFor(x => x.OriginalEvent, _mockIJSObjectReference.Object); - } + // arrange + Event @event = new Faker() + .RuleFor(x => x.OriginalEvent, jSObjectReference); - [Fact] - public void Verify_Dispose() - { // act - _event.Dispose(); + @event.Dispose(); // assert - _mockIJSObjectReference.Verify(c => c.DisposeAsync(), Times.Once()); + _mockIJSObjectReference.Verify(c => c.DisposeAsync(), times); + } + + public static IEnumerable TestData_Verify_Dispose() + { + yield return WrapArgs(null, Times.Never()); + + _mockIJSObjectReference = new Mock(); + yield return WrapArgs(_mockIJSObjectReference.Object, Times.Once()); + + static object[] WrapArgs( + IJSObjectReference? jSObjectReference, + Times times) + => new object[] + { + jSObjectReference, + times + }; } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropStartEvent/CropStartEvent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropStartEvent/CropStartEvent_Should.cs index 70d8d8c0..47471089 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropStartEvent/CropStartEvent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropStartEvent/CropStartEvent_Should.cs @@ -1,4 +1,5 @@ -using Bogus; +using System.Collections.Generic; +using Bogus; using Microsoft.JSInterop; using Moq; using Xunit; @@ -8,24 +9,37 @@ namespace Cropper.Blazor.UnitTests.Events.CropStartEvent { public class CropStartEvent_Should { - private readonly Mock _mockIJSObjectReference; - private readonly Event _event; + private static Mock _mockIJSObjectReference = null!; - public CropStartEvent_Should() + [Theory, MemberData(nameof(TestData_Verify_Dispose))] + public void Verify_Dispose(IJSObjectReference? jSObjectReference, Times times) { - _mockIJSObjectReference = new Mock(); - _event = new Faker() - .RuleFor(x => x.OriginalEvent, _mockIJSObjectReference.Object); - } + // arrange + Event @event = new Faker() + .RuleFor(x => x.OriginalEvent, jSObjectReference); - [Fact] - public void Verify_Dispose() - { // act - _event.Dispose(); + @event.Dispose(); // assert - _mockIJSObjectReference.Verify(c => c.DisposeAsync(), Times.Once()); + _mockIJSObjectReference.Verify(c => c.DisposeAsync(), times); + } + + public static IEnumerable TestData_Verify_Dispose() + { + yield return WrapArgs(null, Times.Never()); + + _mockIJSObjectReference = new Mock(); + yield return WrapArgs(_mockIJSObjectReference.Object, Times.Once()); + + static object[] WrapArgs( + IJSObjectReference? jSObjectReference, + Times times) + => new object[] + { + jSObjectReference, + times + }; } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/ZoomEvent/ZoomEvent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/ZoomEvent/ZoomEvent_Should.cs index d2328ee9..e79499b5 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/ZoomEvent/ZoomEvent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/ZoomEvent/ZoomEvent_Should.cs @@ -1,4 +1,5 @@ -using Bogus; +using System.Collections.Generic; +using Bogus; using Microsoft.JSInterop; using Moq; using Xunit; @@ -8,24 +9,37 @@ namespace Cropper.Blazor.UnitTests.Events.ZoomEvent { public class ZoomEvent_Should { - private readonly Mock _mockIJSObjectReference; - private readonly Event _event; + private static Mock _mockIJSObjectReference = null!; - public ZoomEvent_Should() + [Theory, MemberData(nameof(TestData_Verify_Dispose))] + public void Verify_Dispose(IJSObjectReference? jSObjectReference, Times times) { - _mockIJSObjectReference = new Mock(); - _event = new Faker() - .RuleFor(x => x.OriginalEvent, _mockIJSObjectReference.Object); - } + // arrange + Event @event = new Faker() + .RuleFor(x => x.OriginalEvent, jSObjectReference); - [Fact] - public void Verify_Dispose() - { // act - _event.Dispose(); + @event.Dispose(); // assert - _mockIJSObjectReference.Verify(c => c.DisposeAsync(), Times.Once()); + _mockIJSObjectReference.Verify(c => c.DisposeAsync(), times); + } + + public static IEnumerable TestData_Verify_Dispose() + { + yield return WrapArgs(null, Times.Never()); + + _mockIJSObjectReference = new Mock(); + yield return WrapArgs(_mockIJSObjectReference.Object, Times.Once()); + + static object[] WrapArgs( + IJSObjectReference? jSObjectReference, + Times times) + => new object[] + { + jSObjectReference, + times + }; } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/CroppedCanvas_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/CroppedCanvas_Should.cs index 1a2143ab..041d4525 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/CroppedCanvas_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/CroppedCanvas_Should.cs @@ -1,4 +1,5 @@ -using Bogus; +using System.Collections.Generic; +using Bogus; using Cropper.Blazor.Models; using Microsoft.JSInterop; using Moq; @@ -8,24 +9,37 @@ namespace Cropper.Blazor.UnitTests.Models { public class CroppedCanvas_Should { - private readonly Mock _mockIJSObjectReference; - private readonly CroppedCanvas _croppedCanvas; + private static Mock _mockIJSObjectReference = null!; - public CroppedCanvas_Should() + [Theory, MemberData(nameof(TestData_Verify_Dispose))] + public void Verify_Dispose(IJSObjectReference? jSObjectReference, Times times) { - _mockIJSObjectReference = new Mock(); - _croppedCanvas = new Faker() - .CustomInstantiator(f => new CroppedCanvas(_mockIJSObjectReference.Object)); - } + // arrange + CroppedCanvas croppedCanvas = new Faker() + .CustomInstantiator(f => new CroppedCanvas(jSObjectReference)); - [Fact] - public void Verify_Dispose() - { // act - _croppedCanvas.Dispose(); + croppedCanvas.Dispose(); // assert - _mockIJSObjectReference.Verify(c => c.DisposeAsync(), Times.Once()); + _mockIJSObjectReference.Verify(c => c.DisposeAsync(), times); + } + + public static IEnumerable TestData_Verify_Dispose() + { + yield return WrapArgs(null, Times.Never()); + + _mockIJSObjectReference = new Mock(); + yield return WrapArgs(_mockIJSObjectReference.Object, Times.Once()); + + static object[] WrapArgs( + IJSObjectReference? jSObjectReference, + Times times) + => new object[] + { + jSObjectReference, + times + }; } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs index b6808d58..4d186fd0 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs @@ -72,7 +72,7 @@ public partial class CropperComponent : ICropperComponentBase, IAsyncDisposable, /// In addition, it should be used to disable re-initialization (replace image) of cropper after successful image load when set to false. ///
[Parameter] - public bool IsAvaibleInitCropper { get; set; } = true; + public bool IsAvailableInitCropper { get; set; } = true; /// /// User class names, separated by space. @@ -177,7 +177,7 @@ protected override void OnInitialized() /// private void OnLoadImage(ProgressEventArgs progressEventArgs) { - if (IsAvaibleInitCropper) + if (IsAvailableInitCropper) { InitCropper(); } @@ -270,7 +270,7 @@ public void IsReady(JSEventData jSEventData) /// The used to propagate notifications that the operation should be canceled. public void SetDragMode(DragMode dragMode, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetDragModeAsync(CropperComponentId, dragMode, cancellationToken); + CropperJsIntertop!.SetDragModeAsync(CropperComponentId, dragMode, cancellationToken); } /// @@ -284,7 +284,7 @@ public void SetDragMode(DragMode dragMode, CancellationToken cancellationToken = /// The used to propagate notifications that the operation should be canceled. public void Zoom(decimal ratio, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ZoomAsync(CropperComponentId, ratio, cancellationToken); + CropperJsIntertop!.ZoomAsync(CropperComponentId, ratio, cancellationToken); } /// @@ -296,7 +296,7 @@ public void Zoom(decimal ratio, CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void ZoomTo(decimal ratio, decimal pivotX, decimal pivotY, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ZoomToAsync(CropperComponentId, ratio, pivotX, pivotY, cancellationToken); + CropperJsIntertop!.ZoomToAsync(CropperComponentId, ratio, pivotX, pivotY, cancellationToken); } /// @@ -307,7 +307,7 @@ public void ZoomTo(decimal ratio, decimal pivotX, decimal pivotY, CancellationTo /// The used to propagate notifications that the operation should be canceled. public void Move(decimal offsetX, decimal? offsetY, CancellationToken cancellationToken = default) { - CropperJsIntertop?.MoveAsync(CropperComponentId, offsetX, offsetY, cancellationToken); + CropperJsIntertop!.MoveAsync(CropperComponentId, offsetX, offsetY, cancellationToken); } /// @@ -318,7 +318,7 @@ public void Move(decimal offsetX, decimal? offsetY, CancellationToken cancellati /// The used to propagate notifications that the operation should be canceled. public void MoveTo(decimal x, decimal? y, CancellationToken cancellationToken = default) { - CropperJsIntertop?.MoveToAsync(CropperComponentId, x, y, cancellationToken); + CropperJsIntertop!.MoveToAsync(CropperComponentId, x, y, cancellationToken); } /// @@ -332,7 +332,7 @@ public void MoveTo(decimal x, decimal? y, CancellationToken cancellationToken = /// The used to propagate notifications that the operation should be canceled. public void Rotate(decimal degree, CancellationToken cancellationToken = default) { - CropperJsIntertop?.RotateAsync(CropperComponentId, degree, cancellationToken); + CropperJsIntertop!.RotateAsync(CropperComponentId, degree, cancellationToken); } /// @@ -346,7 +346,7 @@ public void Rotate(decimal degree, CancellationToken cancellationToken = default /// The used to propagate notifications that the operation should be canceled. public void ScaleX(decimal scaleX, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ScaleXAsync(CropperComponentId, scaleX, cancellationToken); + CropperJsIntertop!.ScaleXAsync(CropperComponentId, scaleX, cancellationToken); } /// @@ -360,7 +360,7 @@ public void ScaleX(decimal scaleX, CancellationToken cancellationToken = default /// The used to propagate notifications that the operation should be canceled. public void ScaleY(decimal scaleY, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ScaleYAsync(CropperComponentId, scaleY, cancellationToken); + CropperJsIntertop!.ScaleYAsync(CropperComponentId, scaleY, cancellationToken); } /// @@ -379,7 +379,7 @@ public void ScaleY(decimal scaleY, CancellationToken cancellationToken = default /// The used to propagate notifications that the operation should be canceled. public void Scale(decimal scaleX, decimal scaleY, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ScaleAsync(CropperComponentId, scaleX, scaleY, cancellationToken); + CropperJsIntertop!.ScaleAsync(CropperComponentId, scaleX, scaleY, cancellationToken); } /// @@ -388,7 +388,7 @@ public void Scale(decimal scaleX, decimal scaleY, CancellationToken cancellation /// The used to propagate notifications that the operation should be canceled. public void Crop(CancellationToken cancellationToken = default) { - CropperJsIntertop?.CropAsync(CropperComponentId, cancellationToken); + CropperJsIntertop!.CropAsync(CropperComponentId, cancellationToken); } /// @@ -397,7 +397,7 @@ public void Crop(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Clear(CancellationToken cancellationToken = default) { - CropperJsIntertop?.ClearAsync(CropperComponentId, cancellationToken); + CropperJsIntertop!.ClearAsync(CropperComponentId, cancellationToken); } /// @@ -406,7 +406,7 @@ public void Clear(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Enable(CancellationToken cancellationToken = default) { - CropperJsIntertop?.EnableAsync(CropperComponentId, cancellationToken); + CropperJsIntertop!.EnableAsync(CropperComponentId, cancellationToken); } /// @@ -415,7 +415,7 @@ public void Enable(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Disable(CancellationToken cancellationToken = default) { - CropperJsIntertop?.DisableAsync(CropperComponentId, cancellationToken); + CropperJsIntertop!.DisableAsync(CropperComponentId, cancellationToken); } /// @@ -424,7 +424,7 @@ public void Disable(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Reset(CancellationToken cancellationToken = default) { - CropperJsIntertop?.ResetAsync(CropperComponentId, cancellationToken); + CropperJsIntertop!.ResetAsync(CropperComponentId, cancellationToken); } /// @@ -433,7 +433,7 @@ public void Reset(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Destroy(CancellationToken cancellationToken = default) { - CropperJsIntertop?.DestroyAsync(CropperComponentId, cancellationToken); + CropperJsIntertop!.DestroyAsync(CropperComponentId, cancellationToken); } /// @@ -443,7 +443,7 @@ public void Destroy(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void SetAspectRatio(decimal aspectRatio, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetAspectRatioAsync(CropperComponentId, aspectRatio, cancellationToken); + CropperJsIntertop!.SetAspectRatioAsync(CropperComponentId, aspectRatio, cancellationToken); } /// @@ -453,7 +453,7 @@ public void SetAspectRatio(decimal aspectRatio, CancellationToken cancellationTo /// The used to propagate notifications that the operation should be canceled. public void SetCropBoxData(SetCropBoxDataOptions cropBoxDataOptions, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetCropBoxDataAsync(CropperComponentId, cropBoxDataOptions, cancellationToken); + CropperJsIntertop!.SetCropBoxDataAsync(CropperComponentId, cropBoxDataOptions, cancellationToken); } /// @@ -463,7 +463,7 @@ public void SetCropBoxData(SetCropBoxDataOptions cropBoxDataOptions, Cancellatio /// The used to propagate notifications that the operation should be canceled. public void SetData(SetDataOptions setDataOptions, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetDataAsync(CropperComponentId, setDataOptions, cancellationToken); + CropperJsIntertop!.SetDataAsync(CropperComponentId, setDataOptions, cancellationToken); } /// @@ -473,7 +473,7 @@ public void SetData(SetDataOptions setDataOptions, CancellationToken cancellatio /// The used to propagate notifications that the operation should be canceled. public void SetCanvasData(SetCanvasDataOptions setCanvasDataOptions, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetCanvasDataAsync(CropperComponentId, setCanvasDataOptions, cancellationToken); + CropperJsIntertop!.SetCanvasDataAsync(CropperComponentId, setCanvasDataOptions, cancellationToken); } /// diff --git a/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs b/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs index 313162a0..9bced276 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ -using Cropper.Blazor.ModuleOptions; +using System; +using Cropper.Blazor.ModuleOptions; using Cropper.Blazor.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -19,8 +20,10 @@ public static class ServiceCollectionExtensions /// Continues the chain. public static IServiceCollection AddCropper(this IServiceCollection services, CropperJsInteropOptions? cropperJsInteropOptions = null) { - services.AddSingleton(services => cropperJsInteropOptions ?? new CropperJsInteropOptions()); + CropperJsInteropOptions? options = cropperJsInteropOptions ?? new CropperJsInteropOptions(); + Func funcServiceProvider = (IServiceProvider serviceProvider) => options; + services.AddSingleton(funcServiceProvider); services.TryAddScoped(); return services; From 862e778343af6dc2f4ce8e043ec880cb2bff22ef Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Mon, 23 Oct 2023 17:18:33 +0300 Subject: [PATCH 175/196] Optimize cd pipeline (#240) ## Target Optimize cd pipeline #### Open Questions ## Checklist - [ ] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .github/workflows/cd.yml | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 8e7d442f..a1a876e9 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -111,6 +111,10 @@ jobs: name: Build Demo Projects runs-on: windows-latest + strategy: + matrix: + dotnet-version: ['6.0.x', '7.0.x'] + steps: - uses: actions/checkout@v3 @@ -118,9 +122,7 @@ jobs: - name: Setup .NET 7, 6 uses: actions/setup-dotnet@v3 with: - dotnet-version: | - 6.0.x - 7.0.x + dotnet-version: ${{ matrix.dotnet-version }} - name: Install MAUI Workloads run: | @@ -130,22 +132,27 @@ jobs: run: dotnet restore working-directory: examples - - name: DotNet Build MVC with Blazor Server Demo Project for .net 7 + - name: DotNet Build MVC with Blazor Server Demo Project run: dotnet build --no-restore working-directory: examples\Cropper.MVC.With.Blazor.Server.Net7 + if: matrix.dotnet-version == '7.0.x' - - name: DotNet Build Blazor Server Demo Project for .net 7 + - name: DotNet Build Blazor Server Demo Project run: dotnet build --no-restore working-directory: examples\Cropper.Blazor.Server.Net7 + if: matrix.dotnet-version == '7.0.x' - - name: DotNet Build Blazor MAUI Demo Project for .net 7 + - name: DotNet Build Blazor MAUI Demo Project run: dotnet build --no-restore working-directory: examples\Cropper.Blazor.MAUI.Net7 + if: matrix.dotnet-version == '7.0.x' - - name: DotNet Build Blazor Server Demo Project for .net 6 + - name: DotNet Build Blazor Server Demo Project run: dotnet build --no-restore working-directory: examples\Cropper.Blazor.Server.Net6 + if: matrix.dotnet-version == '6.0.x' - - name: DotNet Build Blazor MAUI Demo Project for .net 6 + - name: DotNet Build Blazor MAUI Demo Project run: dotnet build --no-restore working-directory: examples\Cropper.Blazor.MAUI.Net6 + if: matrix.dotnet-version == '6.0.x' From 9f28b1956826776d7a5d44122208f4672367d34b Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Mon, 23 Oct 2023 18:59:43 +0300 Subject: [PATCH 176/196] Feature/optimize cd pipeline, include coverage reports for .net 7 (#241) ## Target Feature/optimize cd pipeline, include coverage reports for .net 7 #### Open Questions ## Checklist - [ ] Documentation updated - [ ] Tests cover new or modified code - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .github/workflows/cd.yml | 20 ++++++++++++++------ .github/workflows/ci.yml | 4 ++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index a1a876e9..2279754d 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -42,9 +42,9 @@ jobs: working-directory: src/Cropper.Blazor/Cropper.Blazor.UnitTests - name: Coverage - uses: codecov/codecov-action@v3.1.1 + uses: codecov/codecov-action@v3.1.4 with: - file: coverage.net6.0.cobertura.xml + files: coverage.net6.0.cobertura.xml, coverage.net7.0.cobertura.xml fail_ci_if_error: true verbose: true @@ -107,9 +107,21 @@ jobs: folder: release/wwwroot repository-name: CropperBlazor/CropperBlazor.github.io + install-maui-workloads: + name: Install MAUI Workloads + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + + - name: Install MAUI Workloads + run: | + dotnet workload install maui --ignore-failed-sources + demo-projects-build: name: Build Demo Projects runs-on: windows-latest + needs: install-maui-workloads strategy: matrix: @@ -123,10 +135,6 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: ${{ matrix.dotnet-version }} - - - name: Install MAUI Workloads - run: | - dotnet workload install maui --ignore-failed-sources - name: Restore dependencies for Cropper.Blazor.Demo run: dotnet restore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b536a5e8..4ec6e1a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,9 +43,9 @@ jobs: working-directory: src/Cropper.Blazor/Cropper.Blazor.UnitTests - name: Coverage - uses: codecov/codecov-action@v3.1.1 + uses: codecov/codecov-action@v3.1.4 with: - file: coverage.net6.0.cobertura.xml + files: coverage.net6.0.cobertura.xml, coverage.net7.0.cobertura.xml fail_ci_if_error: true verbose: true From 7eb959281d9cb906a71566ad60037c28fed4d7dc Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Thu, 27 Jul 2023 11:22:52 +0300 Subject: [PATCH 177/196] Fix footer in DocsPage.razor --- src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor b/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor index a94d66b8..f50ca050 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor +++ b/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor @@ -1,4 +1,4 @@ - +
From 5e3883535c22a0528a6f154412ef801e4a0fd810 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Thu, 27 Jul 2023 12:53:11 +0300 Subject: [PATCH 178/196] Fix cropper's service registration snippet --- src/Cropper.Blazor/Client/Models/Snippets.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Cropper.Blazor/Client/Models/Snippets.cs b/src/Cropper.Blazor/Client/Models/Snippets.cs index c767c0d2..db20f5d5 100644 --- a/src/Cropper.Blazor/Client/Models/Snippets.cs +++ b/src/Cropper.Blazor/Client/Models/Snippets.cs @@ -20,6 +20,12 @@ public static string GetCode(string component) public const string InstallScriptManual = @""; + public const string InstallServicesNET6Manual = @" + using Cropper.Blazor.Extensions; + + builder.Services.AddCropper(); + "; + public const string MinMaxZoomRatio_Script = @" window.overrideOnZoomCropperEvent = (minZoomRatio, maxZoomRatio) => { window.cropper.onZoom = function (imageObject, event, correlationId) { From f56119061da5b3327675198ef230efc00385a1d6 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Fri, 28 Jul 2023 11:22:42 +0300 Subject: [PATCH 179/196] Fix routing for examples page --- .../Client/Pages/BasicUsage/BasicCropperUsagePage.razor | 1 + src/Cropper.Blazor/Client/Shared/Appbar.razor | 2 +- src/Cropper.Blazor/Client/Shared/Appbar.razor.cs | 1 - src/Cropper.Blazor/Client/Shared/DocsLayout.razor | 2 +- src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs | 3 --- 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor b/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor index b3bea68f..4c190131 100644 --- a/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor +++ b/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor @@ -1,4 +1,5 @@ @page "/examples/cropperusage" +@page "/examples" @using Cropper.Blazor.Client.Pages.BasicUsage.Examples diff --git a/src/Cropper.Blazor/Client/Shared/Appbar.razor b/src/Cropper.Blazor/Client/Shared/Appbar.razor index 33adb2a7..cc6fdff7 100644 --- a/src/Cropper.Blazor/Client/Shared/Appbar.razor +++ b/src/Cropper.Blazor/Client/Shared/Appbar.razor @@ -22,7 +22,7 @@ Cropper.Blazor Demo - Examples + Examples Api About diff --git a/src/Cropper.Blazor/Client/Shared/Appbar.razor.cs b/src/Cropper.Blazor/Client/Shared/Appbar.razor.cs index 74518e76..c88ee2b3 100644 --- a/src/Cropper.Blazor/Client/Shared/Appbar.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/Appbar.razor.cs @@ -10,7 +10,6 @@ public partial class Appbar [Parameter] public EventCallback DrawerToggleCallback { get; set; } [Inject] private NavigationManager NavigationManager { get; set; } = null!; [Inject] private LayoutService LayoutService { get; set; } = null!; - [Inject] IMenuService MenuService { get; set; } = null!; private string GetActiveClass(BasePage page) { diff --git a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor index 72fc4d25..bedcafee 100644 --- a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor +++ b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor @@ -26,7 +26,7 @@ { Demo - Examples + Examples Api About diff --git a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs index 8c51f93e..65d054ed 100644 --- a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs @@ -1,13 +1,10 @@ using Cropper.Blazor.Client.Services; using Microsoft.AspNetCore.Components; -using static MudBlazor.CategoryTypes; namespace Cropper.Blazor.Client.Shared; public partial class DocsLayout : LayoutComponentBase { - [Inject] IMenuService MenuService { get; set; } - [Inject] private LayoutService LayoutService { get; set; } = null!; [Inject] private NavigationManager NavigationManager { get; set; } = null!; From e5a2877691583de1887f42a73cd52904fc7193c8 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sat, 29 Jul 2023 09:01:42 +0300 Subject: [PATCH 180/196] Footer component was added --- src/Cropper.Blazor/Client/Shared/Footer.razor | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/Cropper.Blazor/Client/Shared/Footer.razor diff --git a/src/Cropper.Blazor/Client/Shared/Footer.razor b/src/Cropper.Blazor/Client/Shared/Footer.razor new file mode 100644 index 00000000..af688c86 --- /dev/null +++ b/src/Cropper.Blazor/Client/Shared/Footer.razor @@ -0,0 +1,40 @@ +@using MudBlazor.Utilities; + +
+ + +
+
+ + Cropper.Blazor +
+
+
+ +
+
+ + Demo + + + Examples + + + API + + + + Copyright © 2022-2023 Cropper.Blazor. + + +
+
+ +@code { + [Parameter] public string Class { get; set; } + + protected string ContainerClassnames => + new CssBuilder("section-container") + .AddClass(Class) + .Build(); +} From 254fa9580b6955c5d06cfcf691ca586c954f59ee Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sat, 29 Jul 2023 09:25:01 +0300 Subject: [PATCH 181/196] Add footer to landing layout, fix rounting to examples page --- src/Cropper.Blazor/Client/Shared/LandingLayout.razor | 8 +++++++- src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs | 6 +----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor index d3e72ede..a22fb199 100644 --- a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor +++ b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor @@ -14,12 +14,18 @@ Demo - Examples + Examples Api About @Body + +
+ + + + diff --git a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs index e56c9ea3..aaa648ef 100644 --- a/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/LandingLayout.razor.cs @@ -1,13 +1,9 @@ -using Cropper.Blazor.Client.Enums; -using Cropper.Blazor.Client.Services; +using Cropper.Blazor.Client.Services; using Microsoft.AspNetCore.Components; -using MudBlazor.Services; namespace Cropper.Blazor.Client.Shared; public partial class LandingLayout : LayoutComponentBase { - [Inject] IMenuService MenuService { get; set; } - [Inject] private LayoutService LayoutService { get; set; } = null!; From 0614d28c8fac6df0eb44f650a2eb31bfd52ae4c0 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Sat, 29 Jul 2023 09:31:21 +0300 Subject: [PATCH 182/196] Clear service registration example dummy file --- .../Pages/ManualMarkdown/InstallServicesNET6Manual.razor | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Cropper.Blazor/Client/Pages/ManualMarkdown/InstallServicesNET6Manual.razor b/src/Cropper.Blazor/Client/Pages/ManualMarkdown/InstallServicesNET6Manual.razor index 2a7d8daa..8f4cfdcb 100644 --- a/src/Cropper.Blazor/Client/Pages/ManualMarkdown/InstallServicesNET6Manual.razor +++ b/src/Cropper.Blazor/Client/Pages/ManualMarkdown/InstallServicesNET6Manual.razor @@ -1,5 +1,3 @@ @namespace Cropper.Blazor.Client.Pages.Examples -using Cropper.Blazor.Extensions; - -builder.Services.AddCropper(); \ No newline at end of file +@* Dummy file do not remove, needed for content section *@ From f6227c866e51dcdffb9e0ab829a2367af6523611 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Tue, 27 Jun 2023 09:31:21 +0300 Subject: [PATCH 183/196] Fix loader scss styles --- .../Client/Styles/Cropper.Blazor.Client.scss | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss index 51a2bd65..0a5892e5 100644 --- a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss +++ b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss @@ -38,11 +38,11 @@ display: flex; justify-content: center; align-items: center; - width: 400px; - height: 400px; + width: 25%; overflow: hidden; .loader-image { + height: 100%; position: absolute; inset: 0; @@ -56,7 +56,6 @@ &:nth-child(2) { z-index: 2; width: var(--blazor-load-percentage, 0%); - height: 400px; object-fit: cover; object-position: 0% 0%; transition: width 0.1s ease-in-out; @@ -68,8 +67,8 @@ z-index: 3; text-align: center; font-weight: bold; - inset: calc(200px - 1.25rem) 0 auto 0; - font-size: 2.5rem; + inset: calc(50% - 1.1rem) 0 auto 0; + font-size: 2.2rem; font-family: Roboto, Helvetica, Arial, sans-serif; &::after { From a4822647f9295c64651418be5adeb5672bcdb704 Mon Sep 17 00:00:00 2001 From: George Radchuk <38187349+ColdForeign@users.noreply.github.com> Date: Tue, 31 Oct 2023 23:23:42 +0200 Subject: [PATCH 184/196] docs: Fix loader scss styles (#243) ## Target #### Open Questions ## Checklist - [x] Documentation updated - [ ] Tests cover new or modified code - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .../Client/Styles/Cropper.Blazor.Client.scss | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss index 51a2bd65..0a5892e5 100644 --- a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss +++ b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss @@ -38,11 +38,11 @@ display: flex; justify-content: center; align-items: center; - width: 400px; - height: 400px; + width: 25%; overflow: hidden; .loader-image { + height: 100%; position: absolute; inset: 0; @@ -56,7 +56,6 @@ &:nth-child(2) { z-index: 2; width: var(--blazor-load-percentage, 0%); - height: 400px; object-fit: cover; object-position: 0% 0%; transition: width 0.1s ease-in-out; @@ -68,8 +67,8 @@ z-index: 3; text-align: center; font-weight: bold; - inset: calc(200px - 1.25rem) 0 auto 0; - font-size: 2.5rem; + inset: calc(50% - 1.1rem) 0 auto 0; + font-size: 2.2rem; font-family: Roboto, Helvetica, Arial, sans-serif; &::after { From 2f4e291684a30715288b470bdd14736061b902b1 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Wed, 28 Jun 2023 09:53:01 +0300 Subject: [PATCH 185/196] Menu service updated --- .../Client/Services/MenuService.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Cropper.Blazor/Client/Services/MenuService.cs b/src/Cropper.Blazor/Client/Services/MenuService.cs index 1c5db148..4852980a 100644 --- a/src/Cropper.Blazor/Client/Services/MenuService.cs +++ b/src/Cropper.Blazor/Client/Services/MenuService.cs @@ -6,6 +6,7 @@ public interface IMenuService { //Menu sections IEnumerable Examples { get; } + IEnumerable Api { get; } } /// @@ -14,6 +15,7 @@ public interface IMenuService public class MenuService : IMenuService { private IEnumerable _examples; + private IEnumerable _api; /// /// Examples menu links /// @@ -25,5 +27,28 @@ public class MenuService : IMenuService new DocsLink {Title = "Aspect Ratio", Href = "examples/aspectratio"}, new DocsLink {Title = "Zooming", Href = "examples/zooming"} }; + + + public IEnumerable Api => _api ??= new List + { + new DocsLink {Title = "CropperComponent", Href = "api#eventcallbacks"}, + new DocsLink {Title = "Options", Href = "contract/Options"}, + new DocsLink {Title = "GetCroppedCanvasOptions", Href = "contract/GetCroppedCanvasOptions"}, + new DocsLink {Title = "SetCropBoxDataOptions", Href = "contract/SetCropBoxDataOptions"}, + new DocsLink {Title = "SetCanvasDataOptions", Href = "contract/SetCanvasDataOptions"}, + new DocsLink {Title = "SetDataOptions", Href = "contract/SetDataOptions"}, + new DocsLink {Title = "DragMode", Href = "contract/DragMode"}, + new DocsLink {Title = "CropEndEvent", Href = "contract/CropEndEvent"}, + new DocsLink {Title = "CropMoveEvent", Href = "contract/CropMoveEvent"}, + new DocsLink {Title = "CropStartEvent", Href = "contract/CropStartEvent"}, + new DocsLink {Title = "CropReadyEvent", Href = "contract/CropReadyEvent"}, + new DocsLink {Title = "ZoomEvent", Href = "contract/ZoomEvent"}, + new DocsLink {Title = "CropperData", Href = "contract/CropperData"}, + new DocsLink {Title = "ImageData", Href = "contract/ImageData"}, + new DocsLink {Title = "ContainerData", Href = "contract/ContainerData"}, + new DocsLink {Title = "CanvasData", Href = "contract/CanvasData"}, + new DocsLink {Title = "CropBoxData", Href = "contract/CropBoxData"}, + new DocsLink {Title = "JSEventData", Href = "contract/JSEventData"} + }; } } From a76dea6205b93851c464ca0cc924e4941937a293 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Wed, 28 Jun 2023 09:58:53 +0300 Subject: [PATCH 186/196] Nav menu updated --- src/Cropper.Blazor/Client/Shared/NavMenu.razor | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Cropper.Blazor/Client/Shared/NavMenu.razor b/src/Cropper.Blazor/Client/Shared/NavMenu.razor index 1a48fd20..0a76b021 100644 --- a/src/Cropper.Blazor/Client/Shared/NavMenu.razor +++ b/src/Cropper.Blazor/Client/Shared/NavMenu.razor @@ -9,3 +9,9 @@ @link.Title } + + @foreach (var link in MenuService.Api) + { + @link.Title + } + From b719ab330910620727a80bf6bbf4fa0c4a0cd4d0 Mon Sep 17 00:00:00 2001 From: George Radchuk <38187349+ColdForeign@users.noreply.github.com> Date: Tue, 31 Oct 2023 23:55:45 +0200 Subject: [PATCH 187/196] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 0b37067f..d44324a4 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,13 @@ Cropper.Blazor is an essential component for building interactive image cropping - [CropperBlazor.github.io/examples/cropperusage](https://cropperblazor.github.io/examples/cropperusage) ## Prerequisites +| Cropper.Blazor | .NET | Support | +| :--- | :---: | :---: | +| - | .NET 3.1 | Not supported | +| - | .NET 5 | Not supported | +| 1.1.x | [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0) | :heavy_check_mark: | +| 1.2.x | [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0) & [.NET 7](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) | :heavy_check_mark: | + - Supported .NET 7.0, .NET 6.0 versions for these web platforms: - Blazor WebAssembly - Blazor Server From 82814a45ba996cc0af8283a20bccd59a913f0cbe Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Fri, 3 Nov 2023 18:16:12 +0200 Subject: [PATCH 188/196] Added Docs layout for API and contract (#251) ## Target Added Docs layout for API and contract #### Open Questions ## Checklist - [ ] Documentation updated - [x] Tests cover new or modified code - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- src/Cropper.Blazor/Client/Enums/BasePage.cs | 3 ++- src/Cropper.Blazor/Client/Services/LayoutService.cs | 2 ++ src/Cropper.Blazor/Client/Services/MenuService.cs | 3 ++- src/Cropper.Blazor/Client/Shared/DocsLayout.razor | 7 +++++-- src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs | 2 +- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Cropper.Blazor/Client/Enums/BasePage.cs b/src/Cropper.Blazor/Client/Enums/BasePage.cs index ce626554..cf5bd1b2 100644 --- a/src/Cropper.Blazor/Client/Enums/BasePage.cs +++ b/src/Cropper.Blazor/Client/Enums/BasePage.cs @@ -6,5 +6,6 @@ public enum BasePage Demo, Examples, Api, - About + About, + Contract } diff --git a/src/Cropper.Blazor/Client/Services/LayoutService.cs b/src/Cropper.Blazor/Client/Services/LayoutService.cs index 69e40020..2571548f 100644 --- a/src/Cropper.Blazor/Client/Services/LayoutService.cs +++ b/src/Cropper.Blazor/Client/Services/LayoutService.cs @@ -94,6 +94,8 @@ public BasePage GetDocsBasePage(string uri) return BasePage.Api; else if (uri.Contains("/about")) return BasePage.About; + else if (uri.Contains("/contract")) + return BasePage.Contract; else return BasePage.None; } diff --git a/src/Cropper.Blazor/Client/Services/MenuService.cs b/src/Cropper.Blazor/Client/Services/MenuService.cs index 4852980a..a77240bd 100644 --- a/src/Cropper.Blazor/Client/Services/MenuService.cs +++ b/src/Cropper.Blazor/Client/Services/MenuService.cs @@ -48,7 +48,8 @@ public class MenuService : IMenuService new DocsLink {Title = "ContainerData", Href = "contract/ContainerData"}, new DocsLink {Title = "CanvasData", Href = "contract/CanvasData"}, new DocsLink {Title = "CropBoxData", Href = "contract/CropBoxData"}, - new DocsLink {Title = "JSEventData", Href = "contract/JSEventData"} + new DocsLink {Title = "JSEventData", Href = "contract/JSEventData"}, + new DocsLink {Title = "ViewMode", Href = "contract/ViewMode"} }; } } diff --git a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor index bedcafee..72e256ca 100644 --- a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor +++ b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor @@ -30,10 +30,13 @@ Api About - } + } - @if (!_topMenuOpen && LayoutService.GetDocsBasePage(NavigationManager.Uri) == BasePage.Examples) + @{ + BasePage docsBasePage = LayoutService.GetDocsBasePage(NavigationManager.Uri); + } + @if (!_topMenuOpen && (docsBasePage== BasePage.Examples || docsBasePage == BasePage.Api || docsBasePage == BasePage.Contract)) { } diff --git a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs index 65d054ed..ea6618c2 100644 --- a/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs +++ b/src/Cropper.Blazor/Client/Shared/DocsLayout.razor.cs @@ -21,7 +21,7 @@ protected override void OnInitialized() protected override void OnAfterRender(bool firstRender) { //refresh nav menu because no parameters change in nav menu but internal data does - _navMenuRef?.Refresh(); + //_navMenuRef?.Refresh(); } private void ToggleDrawer() => _drawerOpen = !_drawerOpen; From f811b98c9f7c5cdb4714ac51f52b0c359a6d3f3c Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Thu, 29 Jun 2023 10:21:42 +0300 Subject: [PATCH 189/196] docs: Fix loader styles. Fix title size --- src/Cropper.Blazor/Client/Pages/Index.razor | 2 +- .../Client/Styles/Cropper.Blazor.Client.scss | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Cropper.Blazor/Client/Pages/Index.razor b/src/Cropper.Blazor/Client/Pages/Index.razor index 7548d220..3621ee91 100644 --- a/src/Cropper.Blazor/Client/Pages/Index.razor +++ b/src/Cropper.Blazor/Client/Pages/Index.razor @@ -23,7 +23,7 @@ - Cropper.Blazor + Cropper.Blazor diff --git a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss index 0a5892e5..65f20b8f 100644 --- a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss +++ b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss @@ -31,14 +31,12 @@ } .loader-box { - position: relative; - @include responsive-box(100%); - display: flex; justify-content: center; align-items: center; - width: 25%; + width: 400px; + padding: 25px; overflow: hidden; .loader-image { @@ -63,12 +61,14 @@ } .loader-text { + $loader-text-size: #{"clamp(16px, calc(24px + (48 - 16) * (100vw - 280px)/(1920 - 280)), 48px)"}; + position: absolute; z-index: 3; text-align: center; font-weight: bold; - inset: calc(50% - 1.1rem) 0 auto 0; - font-size: 2.2rem; + inset: calc(50% - (#{$loader-text-size} / 2)) 0 auto 0; + font-size: $loader-text-size; font-family: Roboto, Helvetica, Arial, sans-serif; &::after { @@ -153,6 +153,10 @@ -webkit-text-fill-color: transparent; font-weight: 800; letter-spacing: 1px; + + &.index-title { + font-size: #{"clamp(16px, calc(24px + (48 - 16) * (100vw - 280px)/(1920 - 280)), 48px)"}; + } } .divider { From 47b00a9c83175773960c893d9dd961c8b923218e Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Sat, 4 Nov 2023 22:00:01 +0200 Subject: [PATCH 190/196] Feature/add basic and advanced usage cropping (#252) ## Target Add basic and advanced usage cropping #### Open Questions ## Checklist - [x] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- NuGet_README.md | 199 ++++++++++++++++++ .../Client/Components/Docs/CodeInline.razor | 3 +- .../Client/Cropper.Blazor.Client.csproj | 1 + .../Client/Pages/Crop/CropPage.razor | 85 ++++++++ .../Crop/Examples/AdvancedCropExample.razor | 65 ++++++ .../Crop/Examples/BasicCropExample.razor | 63 ++++++ src/Cropper.Blazor/Client/Pages/Index.razor | 16 +- .../Client/Services/MenuService.cs | 59 +++--- .../Client/Styles/components/docspage.scss | 4 + .../Client/Styles/components/docssection.scss | 4 + .../DocStrings.cs | 20 +- .../Extensions/MethodInfoExtensions.cs | 2 +- .../Components/CropperComponent.razor.cs | 6 +- .../Cropper.Blazor/Cropper.Blazor.csproj | 4 +- 14 files changed, 478 insertions(+), 53 deletions(-) create mode 100644 NuGet_README.md create mode 100644 src/Cropper.Blazor/Client/Pages/Crop/CropPage.razor create mode 100644 src/Cropper.Blazor/Client/Pages/Crop/Examples/AdvancedCropExample.razor create mode 100644 src/Cropper.Blazor/Client/Pages/Crop/Examples/BasicCropExample.razor diff --git a/NuGet_README.md b/NuGet_README.md new file mode 100644 index 00000000..bd247d43 --- /dev/null +++ b/NuGet_README.md @@ -0,0 +1,199 @@ +## Cropper.Blazor is a component that wraps around Cropper.js version 1.6.1 + +[![Build and run test](https://github.com/CropperBlazor/Cropper.Blazor/actions/workflows/ci.yml/badge.svg?event=push)](https://github.com/CropperBlazor/Cropper.Blazor/actions/workflows/ci.yml) +[![Deploy to GitHub Pages](https://github.com/CropperBlazor/Cropper.Blazor/actions/workflows/cd.yml/badge.svg?event=push)](https://github.com/CropperBlazor/Cropper.Blazor/actions/workflows/cd.yml) +[![Deploy to NuGet](https://github.com/CropperBlazor/Cropper.Blazor/actions/workflows/release.yml/badge.svg?event=push)](https://github.com/CropperBlazor/Cropper.Blazor/actions/workflows/release.yml) +[![coverage](https://codecov.io/github/CropperBlazor/Cropper.Blazor/branch/dev/graph/badge.svg?token=39M66DO85T)](https://codecov.io/github/CropperBlazor/Cropper.Blazor) +[![GitHub](https://img.shields.io/github/license/CropperBlazor/Cropper.Blazor?color=ff5c9b)](https://github.com/CropperBlazor/Cropper.Blazor/blob/dev/LICENSE) +[![GitHub](https://img.shields.io/github/last-commit/CropperBlazor/Cropper.Blazor?color=009DEA)](https://github.com/CropperBlazor/Cropper.Blazor) +[![NuGet Badge](https://buildstats.info/nuget/Cropper.Blazor)](https://www.nuget.org/packages/Cropper.Blazor/) + +The most powerful image cropping tool for Blazor WebAssembly / Server, Hybrid with MAUI, MVC and +other frameworks. + +Cropper.Blazor is an essential component for building interactive image cropping and manipulation features in Blazor web applications. This versatile Blazor library empowers developers to integrate intuitive image cropping functionality directly into their Blazor projects, offering users a seamless and responsive image editing experience. + +## Demo +- [CropperBlazor.github.io/demo](https://CropperBlazor.github.io/demo) + +## API +- [CropperBlazor.github.io/api](https://cropperblazor.github.io/api) + +## Examples +- [CropperBlazor.github.io/examples/cropperusage](https://cropperblazor.github.io/examples/cropperusage) + +## Prerequisites +| Cropper.Blazor | .NET | Support | +| :--- | :---: | :---: | +| - | .NET 3.1 | Not supported | +| - | .NET 5 | Not supported | +| 1.1.x | [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0) | :heavy_check_mark: | +| 1.2.x | [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0) & [.NET 7](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) | :heavy_check_mark: | + +- Supported .NET 7.0, .NET 6.0 versions for these web platforms: + - Blazor WebAssembly + - Blazor Server + - Blazor Server Hybrid with MVC + - MAUI Blazor Hybrid + + Note: if you have problem with MAUI project dependencies: + - `dotnet workload update` + rebuilt the project. If that doesn't help, try the step below about override package + - override package, for example: `` + + ## Key features and aspects of the Cropper.Blazor package include + +- Blazor Integration: Cropper.Blazor is specifically designed for Blazor applications, allowing developers to effortlessly incorporate image cropping capabilities into their Blazor components and pages. +- Drag-and-Resize Interaction: Users can easily drag and resize the cropping area to precisely select the desired portion of an image. This intuitive interaction method ensures accurate and efficient cropping. +- Rotation Support: Cropper.Blazor includes the ability to rotate the selected image area, giving users full control over the orientation of their cropped content. +- Aspect Ratio Control: Developers can define custom aspect ratios for cropping, ensuring that the resulting image maintains specific proportions. This is particularly valuable for applications that require standardized image dimensions. +- Zoom Functionality: Cropper.Blazor allows users to zoom in and out of the image to fine-tune their cropping selection, guaranteeing precise results. +- Data Retrieval: The library provides methods to retrieve detailed information about the cropped area, such as coordinates and dimensions. This data can be easily captured and utilized for further processing or image uploads. +- Customization: Cropper.Blazor offers a wide range of configuration options, enabling developers to tailor the cropping experience to match the visual style and user interface of their Blazor applications. +- Cross-Browser Compatibility: The package is compatible with various modern web browsers, ensuring consistent functionality and user experience across different platforms. +- Documentation: Cropper.Blazor is accompanied by comprehensive documentation and practical examples, simplifying the integration process and helping developers make the most of its features. +- Open Source: Cropper.Blazor is open-source software, available for free use in both personal and commercial Blazor projects. + +Cropper.Blazor streamlines the implementation of image cropping and editing within Blazor applications, enhancing user engagement and enabling dynamic image manipulation. Whether you are developing a Blazor-based image editor, profile picture uploader, or any other application that requires image cropping, Cropper.Blazor is a valuable package that simplifies the development process and enriches your application's capabilities. + +## Installation + +``` +dotnet add package Cropper.Blazor +``` + +## Usage + +Import Custom Element: + +```razor +@using Cropper.Blazor.Components +``` + + +Add the following to `index.html` (client-side — Blazor Webassembly, Blazor MAUI) or `_Host.cshtml` (server-side — Blazor Server, MVC with Blazor Server) in the `head` +```razor + +``` + +Add the following to `index.html` or `_Host.cshtml` in the `body` +```razor + +``` + + +Add the following to the relevant sections of `Program.cs` +```c# +using Cropper.Blazor.Extensions; +``` +```c# +builder.Services.AddCropper(); +``` + +In addition, you can change the path to the CropperJSInterop.min.js module if for some reason it is located outside the server root folder as follows: +- Override internal path to CropperJSInterop.min.js module: +```c# +builder.Services.AddCropper(new CropperJsInteropOptions() +{ + DefaultInternalPathToCropperModule = "/_content/Cropper.Blazor/cropperJsInterop.min.js" +}) +``` +- Override full global path to CropperJSInterop.min.js module: +```c# +builder.Services.AddCropper(new CropperJsInteropOptions() +{ + IsActiveGlobalPath = true, + GlobalPathToCropperModule = "/_content/Cropper.Blazor/cropperJsInterop.min.js" +}) +``` + +Also for server-side (Blazor Server or MVC with Blazor Server) you need add configuration SignalR, increase MaximumReceiveMessageSize of a single incoming hub message (default is 32KB) and map SignalR to your path. [For example](https://github.com/CropperBlazor/Cropper.Blazor/blob/dev/examples/Cropper.Blazor.Server.Net7/Program.cs): +```c# +builder.Services.AddServerSideBlazor() + .AddHubOptions(options => + { + options.MaximumReceiveMessageSize = 32 * 1024 * 100; + }); +``` +```c# +app.MapBlazorHub(); +``` + + +And then use it in Razor file ([for example](https://github.com/CropperBlazor/Cropper.Blazor/blob/dev/src/Cropper.Blazor/Client/Pages/CropperDemo.razor)): + +```razor + + +``` + +And then use it in [*.razor.cs file](https://github.com/CropperBlazor/Cropper.Blazor/blob/dev/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs) + +You may override Cropper JavaScript module with execution script which can replace 6 event handlers (onReady, onCropStart, onCropMove, onCropEnd, onCrop, onZoom), such as overriding the onZoom callback in JavaScript: +```js +window.overrideOnZoomCropperEvent = (minZoomRatio, maxZoomRatio) => { + window.cropper.onZoom = function (imageObject, event, correlationId) { + const jSEventData = this.getJSEventData(event, correlationId); + + const isApplyPreventZoomMinRatio = (minZoomRatio != null) && (minZoomRatio > event.detail.ratio); + const isApplyPreventZoomMaxRatio = (maxZoomRatio != null) && (event.detail.ratio > maxZoomRatio); + + if (isApplyPreventZoomMinRatio || isApplyPreventZoomMaxRatio) { + event.preventDefault(); + } + else { + imageObject.invokeMethodAsync('CropperIsZoomed', jSEventData); + } + }; +}; +``` + +Analysis of the signature onReady, onCropStart, onCropMove, onCropEnd, onCrop, onZoom event handlers: +### imageObject + +- Type: `Object` + +Reference to base cropper component. + +### event + +- Type: `CustomEvent` + +Represent Cropper Event. + +### correlationId + +- Type: `String` +- Default: `Cropper.Blazor` + +A Correlation ID is a unique identifier that is added to the very first interaction(incoming request) +to identify the context and is passed to all components that are involved in the transaction flow. + +Definitely need to tell these rules in Blazor: +```c# +await JSRuntime!.InvokeVoidAsync("window.overrideCropperJsInteropModule", MinZoomRatio, MaxZoomRatio); +``` + +## Contributing + +1. Fork it! +2. Create your feature branch: `git checkout -b feature/` +3. Commit your changes: `git commit -m 'Add some feature'` +4. Push to the branch: `git push origin feature/` +5. Submit a pull request :D diff --git a/src/Cropper.Blazor/Client/Components/Docs/CodeInline.razor b/src/Cropper.Blazor/Client/Components/Docs/CodeInline.razor index 6087bb4a..d9bbdd54 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/CodeInline.razor +++ b/src/Cropper.Blazor/Client/Components/Docs/CodeInline.razor @@ -1,4 +1,4 @@ - + @if (Tag) {<}@Code@ChildContent@if (Tag) {>} @@ -7,6 +7,7 @@ [Parameter] public RenderFragment? ChildContent { get; set; } = null; [Parameter] public string? Code { get; set; } = null; + [Parameter] public string Style { get; set; } = string.Empty; [Parameter] public bool SecondaryColor { get; set; } diff --git a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj index 3d6b75d3..d2438ca2 100644 --- a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj +++ b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj @@ -153,6 +153,7 @@ + diff --git a/src/Cropper.Blazor/Client/Pages/Crop/CropPage.razor b/src/Cropper.Blazor/Client/Pages/Crop/CropPage.razor new file mode 100644 index 00000000..666951c2 --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Crop/CropPage.razor @@ -0,0 +1,85 @@ +@page "/examples/cropping" +@using Cropper.Blazor.Client.Models; +@using Cropper.Blazor.Client.Pages.Crop.Examples + + + + + + + + + With the GetCroppedCanvasDataURLAsync method + you can get canvas drawn the cropped image in URL format. +

+ GetCroppedCanvasDataURLAsync method have following arguments: + + + GetCroppedCanvasOptions (required) - used to get a cropped canvas; + + + type (not required) - string indicating the image format. The default type is image/png; + this image format will be also used if the specified type is not supported; + + + number (not required) - number between 0 and 1 indicating the image quality to be used when creating images using file formats that support lossy compression (such as image/jpeg or image/webp). + Different browsers have different image encoder compression, usually it is 92 or 80 percent of the full image quality. The default value is 1 with maximum image quality. + + + CancellationToken (not required) - used to propagate notifications that the operation should be canceled. + + +
+ + Note: If you intend to get a JPEG image from the output canvas, you should set the fillColor option first, if not, the transparent part in the JPEG image will become black by default. + +
+
+ + + +
+ + + + + With the GetCroppedCanvasAsync method + you can get a canvas drawn from the cropped image (lossy compression). If it is not cropped, then returns a canvas drawn the whole image. +

+ GetCroppedCanvasAsync method have following argument: + + + GetCroppedCanvasOptions (required) - used to get a cropped canvas; + + + CancellationToken (not required) - used to propagate notifications that the operation should be canceled. + + + + Note: If you intend to get a JPEG image from the output canvas, you should set the fillColor option first, if not, the transparent part in the JPEG image will become black by default. + +
+ This GetCroppedCanvasAsync method returns CroppedCanvas. + Use JSRuntimeObjectRef in the + CroppedCanvas which represents a reference to a JavaScript cropped canvas object for get a Data URL + via + HTMLCanvasElement.toDataURL: + + CroppedCanvas.JSRuntimeObjectRef.InvokeAsync<string>("toDataURL", type, encoderOptions) + . +
+ + Note: + Don't use InvokeAsync<string>("toDataURL") and InvokeAsync<string>("toDataURL", type) methods due to image quality was little lost through + default value encoderOptions. + In addition, different browsers have different image encoder compression, usually it is 92 or 80 percent of the full image quality. + +
+
+ + + +
+ +
+
\ No newline at end of file diff --git a/src/Cropper.Blazor/Client/Pages/Crop/Examples/AdvancedCropExample.razor b/src/Cropper.Blazor/Client/Pages/Crop/Examples/AdvancedCropExample.razor new file mode 100644 index 00000000..1cb642cf --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Crop/Examples/AdvancedCropExample.razor @@ -0,0 +1,65 @@ +@using Cropper.Blazor.Extensions; +@using Cropper.Blazor.Models; + +
+ +
+ +
+ Get cropped image +
+ + + +@* Make sure the size of the image fits perfectly into the container *@ + + +@code { + private CropperComponent? cropperComponent = null!; + private string croppedCanvasDataURL; + + public async Task GetCroppedCanvasAsync() + { + GetCroppedCanvasOptions getCroppedCanvasOptions = new GetCroppedCanvasOptions + { + MaxHeight = 4096, + MaxWidth = 4096, + ImageSmoothingQuality = ImageSmoothingQuality.High.ToEnumString() + }; + + // Get a reference to a JavaScript cropped canvas object. + CroppedCanvas croppedCanvas = await cropperComponent!.GetCroppedCanvasAsync(getCroppedCanvasOptions); + // Invoke toDataURL JavaScript function from the canvas object. + croppedCanvasDataURL = await croppedCanvas!.JSRuntimeObjectRef.InvokeAsync("toDataURL", "image/png", 1); + } +} diff --git a/src/Cropper.Blazor/Client/Pages/Crop/Examples/BasicCropExample.razor b/src/Cropper.Blazor/Client/Pages/Crop/Examples/BasicCropExample.razor new file mode 100644 index 00000000..6f8784af --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Crop/Examples/BasicCropExample.razor @@ -0,0 +1,63 @@ +@using Cropper.Blazor.Extensions; +@using Cropper.Blazor.Models; + +
+ +
+ +
+ Get cropped image +
+ + + +@* Make sure the size of the image fits perfectly into the container *@ + + +@code { + private CropperComponent? cropperComponent = null!; + private string croppedCanvasDataURL; + + public async Task GetCroppedCanvasDataURLAsync() + { + GetCroppedCanvasOptions getCroppedCanvasOptions = new GetCroppedCanvasOptions + { + MaxHeight = 4096, + MaxWidth = 4096, + ImageSmoothingQuality = ImageSmoothingQuality.High.ToEnumString() + }; + + croppedCanvasDataURL = await cropperComponent!.GetCroppedCanvasDataURLAsync(getCroppedCanvasOptions); + } +} diff --git a/src/Cropper.Blazor/Client/Pages/Index.razor b/src/Cropper.Blazor/Client/Pages/Index.razor index 7548d220..78d011b0 100644 --- a/src/Cropper.Blazor/Client/Pages/Index.razor +++ b/src/Cropper.Blazor/Client/Pages/Index.razor @@ -35,7 +35,7 @@ Cropper.Blazor is a component that wraps around - + Cropper.js version 1.6.1 @@ -53,25 +53,25 @@

- + Build and run test - + Deploy to GitHub Pages - + Deploy to NuGet - + Code coverage - + License - + Last commit - + Nuget version and downloads

diff --git a/src/Cropper.Blazor/Client/Services/MenuService.cs b/src/Cropper.Blazor/Client/Services/MenuService.cs index a77240bd..586ba311 100644 --- a/src/Cropper.Blazor/Client/Services/MenuService.cs +++ b/src/Cropper.Blazor/Client/Services/MenuService.cs @@ -16,40 +16,41 @@ public class MenuService : IMenuService { private IEnumerable _examples; private IEnumerable _api; + /// /// Examples menu links /// public IEnumerable Examples => _examples ??= new List - { - new DocsLink {Title = "Basic Usage", Href = "examples/cropperusage"}, - new DocsLink {Title = "Crop Box Dimensions", Href = "examples/dimensions"}, - new DocsLink {Title = "View Modes", Href = "examples/viewmodes"}, - new DocsLink {Title = "Aspect Ratio", Href = "examples/aspectratio"}, - new DocsLink {Title = "Zooming", Href = "examples/zooming"} - }; - + { + new DocsLink {Title = "Basic Usage", Href = "examples/cropperusage"}, + new DocsLink {Title = "Crop Box Dimensions", Href = "examples/dimensions"}, + new DocsLink {Title = "View Modes", Href = "examples/viewmodes"}, + new DocsLink {Title = "Aspect Ratio", Href = "examples/aspectratio"}, + new DocsLink {Title = "Zooming", Href = "examples/zooming"}, + new DocsLink {Title = "Cropping", Href = "examples/cropping"} + }; public IEnumerable Api => _api ??= new List - { - new DocsLink {Title = "CropperComponent", Href = "api#eventcallbacks"}, - new DocsLink {Title = "Options", Href = "contract/Options"}, - new DocsLink {Title = "GetCroppedCanvasOptions", Href = "contract/GetCroppedCanvasOptions"}, - new DocsLink {Title = "SetCropBoxDataOptions", Href = "contract/SetCropBoxDataOptions"}, - new DocsLink {Title = "SetCanvasDataOptions", Href = "contract/SetCanvasDataOptions"}, - new DocsLink {Title = "SetDataOptions", Href = "contract/SetDataOptions"}, - new DocsLink {Title = "DragMode", Href = "contract/DragMode"}, - new DocsLink {Title = "CropEndEvent", Href = "contract/CropEndEvent"}, - new DocsLink {Title = "CropMoveEvent", Href = "contract/CropMoveEvent"}, - new DocsLink {Title = "CropStartEvent", Href = "contract/CropStartEvent"}, - new DocsLink {Title = "CropReadyEvent", Href = "contract/CropReadyEvent"}, - new DocsLink {Title = "ZoomEvent", Href = "contract/ZoomEvent"}, - new DocsLink {Title = "CropperData", Href = "contract/CropperData"}, - new DocsLink {Title = "ImageData", Href = "contract/ImageData"}, - new DocsLink {Title = "ContainerData", Href = "contract/ContainerData"}, - new DocsLink {Title = "CanvasData", Href = "contract/CanvasData"}, - new DocsLink {Title = "CropBoxData", Href = "contract/CropBoxData"}, - new DocsLink {Title = "JSEventData", Href = "contract/JSEventData"}, - new DocsLink {Title = "ViewMode", Href = "contract/ViewMode"} - }; + { + new DocsLink {Title = "CropperComponent", Href = "api#eventcallbacks"}, + new DocsLink {Title = "Options", Href = "contract/Options"}, + new DocsLink {Title = "GetCroppedCanvasOptions", Href = "contract/GetCroppedCanvasOptions"}, + new DocsLink {Title = "SetCropBoxDataOptions", Href = "contract/SetCropBoxDataOptions"}, + new DocsLink {Title = "SetCanvasDataOptions", Href = "contract/SetCanvasDataOptions"}, + new DocsLink {Title = "SetDataOptions", Href = "contract/SetDataOptions"}, + new DocsLink {Title = "DragMode", Href = "contract/DragMode"}, + new DocsLink {Title = "CropEndEvent", Href = "contract/CropEndEvent"}, + new DocsLink {Title = "CropMoveEvent", Href = "contract/CropMoveEvent"}, + new DocsLink {Title = "CropStartEvent", Href = "contract/CropStartEvent"}, + new DocsLink {Title = "CropReadyEvent", Href = "contract/CropReadyEvent"}, + new DocsLink {Title = "ZoomEvent", Href = "contract/ZoomEvent"}, + new DocsLink {Title = "CropperData", Href = "contract/CropperData"}, + new DocsLink {Title = "ImageData", Href = "contract/ImageData"}, + new DocsLink {Title = "ContainerData", Href = "contract/ContainerData"}, + new DocsLink {Title = "CanvasData", Href = "contract/CanvasData"}, + new DocsLink {Title = "CropBoxData", Href = "contract/CropBoxData"}, + new DocsLink {Title = "JSEventData", Href = "contract/JSEventData"}, + new DocsLink {Title = "ViewMode", Href = "contract/ViewMode"} + }; } } diff --git a/src/Cropper.Blazor/Client/Styles/components/docspage.scss b/src/Cropper.Blazor/Client/Styles/components/docspage.scss index 520a3133..2b43cb98 100644 --- a/src/Cropper.Blazor/Client/Styles/components/docspage.scss +++ b/src/Cropper.Blazor/Client/Styles/components/docspage.scss @@ -88,3 +88,7 @@ } } } + +.text-anywhere-wrap { + overflow-wrap: anywhere; +} diff --git a/src/Cropper.Blazor/Client/Styles/components/docssection.scss b/src/Cropper.Blazor/Client/Styles/components/docssection.scss index 5946a8ea..065d6534 100644 --- a/src/Cropper.Blazor/Client/Styles/components/docssection.scss +++ b/src/Cropper.Blazor/Client/Styles/components/docssection.scss @@ -197,6 +197,10 @@ } } +.warning-color { + color: var(--mud-palette-warning) !important; +} + .disabled { pointer-events: none; cursor: default; diff --git a/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/DocStrings.cs b/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/DocStrings.cs index c7d953de..d20d3d0f 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/DocStrings.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/DocStrings.cs @@ -140,7 +140,7 @@ private static string ConvertMarkdownToHTML(string markdownText) string pattern = "<(\\w+) href=\"(.*?)\">(.*?)"; // Replace Markdown elements with HTML links - string htmlText = Regex.Replace(markdownText, pattern, "$3"); + string htmlText = Regex.Replace(markdownText, pattern, "$3"); return htmlText; } @@ -158,10 +158,10 @@ private static string ConvertCrefToHTML(string markdownText) if (result.EndsWith("Microsoft.AspNetCore.Components.Web.ErrorEventArgs")) { - return $"{value}"; + return $"{value}"; } - return $"{value}"; + return $"{value}"; }); return htmlText; @@ -172,13 +172,13 @@ private static string ConvertSeeTagsForMethod(string doc, string formattedReturn string result = doc .Replace("
", "") .Replace("", "scaleX") - .Replace("", "ElementReference") - .Replace("", "IBrowserFile") - .Replace("", "DotNetStreamReference") - .Replace("", "ValueTask") - .Replace("", $"{formattedReturnSignature}") - .Replace("", "JSEventData<>") - .Replace("", "CancellationToken"); + .Replace("", "ElementReference") + .Replace("", "IBrowserFile") + .Replace("", "DotNetStreamReference") + .Replace("", "ValueTask") + .Replace("", $"{formattedReturnSignature}") + .Replace("", "JSEventData<>") + .Replace("", "CancellationToken"); return result; } diff --git a/src/Cropper.Blazor/Cropper.Blazor.Shared/Extensions/MethodInfoExtensions.cs b/src/Cropper.Blazor/Cropper.Blazor.Shared/Extensions/MethodInfoExtensions.cs index 4a342d85..abd0e46f 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.Shared/Extensions/MethodInfoExtensions.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.Shared/Extensions/MethodInfoExtensions.cs @@ -231,7 +231,7 @@ public static string CreateLink(this string name) } else if (name == "Action") { - return $"{name}"; + return $"{name}"; } else if (name == "ErrorEventArgs") { diff --git a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs index 4d186fd0..5508a60b 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs @@ -576,7 +576,9 @@ public async ValueTask RevokeObjectUrlAsync(string url, CancellationToken cancel /// The used to get a cropped canvas. /// The used to propagate notifications that the operation should be canceled. /// A representing canvas drawn the cropped image asynchronous operation. - public async ValueTask GetCroppedCanvasAsync(GetCroppedCanvasOptions getCroppedCanvasOptions, CancellationToken cancellationToken = default) + public async ValueTask GetCroppedCanvasAsync( + GetCroppedCanvasOptions getCroppedCanvasOptions, + CancellationToken cancellationToken = default) { return await CropperJsIntertop!.GetCroppedCanvasAsync(CropperComponentId, getCroppedCanvasOptions, cancellationToken); } @@ -587,7 +589,7 @@ public async ValueTask GetCroppedCanvasAsync(GetCroppedCanvasOpti /// The used to get a cropped canvas. /// A string indicating the image format. The default type is image/png; this image format will be also used if the specified type is not supported. /// A number between 0 and 1 indicating the image quality to be used when creating images using file formats that support lossy compression (such as image/jpeg or image/webp). - /// Different browsers have different image encoder compression, usually it is 92 or 80 percent of the full image quality. + /// Different browsers have different image encoder compression, usually it is 92 or 80 percent of the full image quality. The default value is 1 with maximum image quality. /// /// The used to propagate notifications that the operation should be canceled. /// A representing canvas drawn the cropped image in URL format asynchronous operation. diff --git a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj index 58a1d128..9f3a0f96 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj @@ -32,7 +32,7 @@ false true false - README.md + NuGet_README.md @@ -54,7 +54,7 @@ - + True \ From a9c4d3a8990c716dfd14b37d180f7a65c8ec7512 Mon Sep 17 00:00:00 2001 From: ColdForeign Date: Thu, 29 Jun 2023 10:25:42 +0300 Subject: [PATCH 191/196] docs: Fix linter warnings --- src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss index 65f20b8f..7a00dd19 100644 --- a/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss +++ b/src/Cropper.Blazor/Client/Styles/Cropper.Blazor.Client.scss @@ -32,6 +32,7 @@ .loader-box { @include responsive-box(100%); + display: flex; justify-content: center; align-items: center; From a813081a8f4ee488d618c9ac60686017028c13d8 Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Sun, 5 Nov 2023 17:22:00 +0200 Subject: [PATCH 192/196] Add code snippet in crop page (#254) ## Target Add code snippet in crop page #### Open Questions ## Checklist - [x] Documentation updated - [ ] Tests cover new or modified code - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .../Client/Components/Docs/SectionCode.razor | 21 +++++++++++++++++++ .../Components/Docs/SectionContent.razor | 17 ++++++--------- .../Components/Docs/SectionContent.razor.cs | 8 +++++-- .../Client/Pages/Crop/CropPage.razor | 9 +++++--- .../Examples/InvokeToDataURLExample.razor | 1 + 5 files changed, 40 insertions(+), 16 deletions(-) create mode 100644 src/Cropper.Blazor/Client/Components/Docs/SectionCode.razor create mode 100644 src/Cropper.Blazor/Client/Pages/Crop/Examples/InvokeToDataURLExample.razor diff --git a/src/Cropper.Blazor/Client/Components/Docs/SectionCode.razor b/src/Cropper.Blazor/Client/Components/Docs/SectionCode.razor new file mode 100644 index 00000000..160280b2 --- /dev/null +++ b/src/Cropper.Blazor/Client/Components/Docs/SectionCode.razor @@ -0,0 +1,21 @@ +
+
+ @CodeComponent +
+ +
+ +@code { + [Parameter] + public string SourceClassname { get; set; } = string.Empty; + + [Parameter] + public RenderFragment CodeComponent { get; set; } + + [Parameter] + public EventCallback CopyTextToClipboard { get; set; } +} diff --git a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor index 37ecff8c..a4ecdc01 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor +++ b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor @@ -8,7 +8,7 @@ @using Cropper.Blazor.Client.Models; @using MudBlazor; -@if (Codes != null || ChildContent != null) +@if ((Codes != null || ChildContent != null) && !IsOnlySingleSectionCode) {
@if (Codes != null || ChildContent != null) @@ -54,16 +54,11 @@ }
} -@if (HasCode) +@if (HasCode || IsOnlySingleSectionCode) { -
-
+ + @CodeComponent(ActiveCode) -
- -
+ + } diff --git a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs index 51cf10ec..f56a6184 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs +++ b/src/Cropper.Blazor/Client/Components/Docs/SectionContent.razor.cs @@ -1,4 +1,5 @@ using System.Text.RegularExpressions; +using System.Web; using Cropper.Blazor.Client.Models; using Microsoft.AspNetCore.Components; using MudBlazor; @@ -38,9 +39,11 @@ public partial class SectionContent : IBrowserViewportObserver new CssBuilder("docs-section-source") .AddClass($"outlined", Outlined && ChildContent != null) .AddClass("show-code", HasCode && ShowCode) + .AddClass(ShowCodeClass) .Build(); [Parameter] public string Class { get; set; } = string.Empty; + [Parameter] public string ShowCodeClass { get; set; } = string.Empty; [Parameter] public bool DarkenBackground { get; set; } [Parameter] public bool Outlined { get; set; } = true; [Parameter] public bool ShowCode { get; set; } = true; @@ -50,6 +53,7 @@ public partial class SectionContent : IBrowserViewportObserver [Parameter] public string HighLight { get; set; } = string.Empty; [Parameter] public IEnumerable? Codes { get; set; } = null; [Parameter] public RenderFragment ChildContent { get; set; } = null!; + [Parameter] public bool IsOnlySingleSectionCode { get; set; } = false; private bool HasCode; public string ActiveCode = string.Empty; @@ -106,7 +110,7 @@ private string GetActiveCode(string value) private async Task CopyTextToClipboardAsync() { - await JsApiService!.CopyToClipboardAsync(Snippets.GetCode(string.IsNullOrWhiteSpace(Code) ? ActiveCode : Code)); + await JsApiService!.CopyToClipboardAsync(HttpUtility.HtmlDecode(Snippets.GetCode(string.IsNullOrWhiteSpace(Code) ? ActiveCode : Code))); } RenderFragment CodeComponent(string code) => builder => @@ -135,7 +139,7 @@ RenderFragment CodeComponent(string code) => builder => } } - builder.AddMarkupContent(0, read); + builder.AddMarkupContent(0, HttpUtility.HtmlDecode(read)); } catch (Exception ex) { diff --git a/src/Cropper.Blazor/Client/Pages/Crop/CropPage.razor b/src/Cropper.Blazor/Client/Pages/Crop/CropPage.razor index 666951c2..4631a76b 100644 --- a/src/Cropper.Blazor/Client/Pages/Crop/CropPage.razor +++ b/src/Cropper.Blazor/Client/Pages/Crop/CropPage.razor @@ -64,9 +64,12 @@ CroppedCanvas which represents a reference to a JavaScript cropped canvas object for get a Data URL via HTMLCanvasElement.toDataURL: - - CroppedCanvas.JSRuntimeObjectRef.InvokeAsync<string>("toDataURL", type, encoderOptions) - . +

+ + + + +
Note: diff --git a/src/Cropper.Blazor/Client/Pages/Crop/Examples/InvokeToDataURLExample.razor b/src/Cropper.Blazor/Client/Pages/Crop/Examples/InvokeToDataURLExample.razor new file mode 100644 index 00000000..ed19fc20 --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/Crop/Examples/InvokeToDataURLExample.razor @@ -0,0 +1 @@ +CroppedCanvas.JSRuntimeObjectRef.InvokeAsync<string>("toDataURL", type, encoderOptions); From da58751ca88059c9c505bdff6b0c5a5262905f7f Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Mon, 6 Nov 2023 18:39:57 +0200 Subject: [PATCH 193/196] Add about (#255) ## Target Add about #### Open Questions ## Checklist - [x] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [ ] Includes breaking changes - [ ] Version bumped ## Visuals --- .../Client/Models/TeamMember.cs | 13 +++ src/Cropper.Blazor/Client/Pages/About.razor | 92 ++++++++++++++++++- .../Client/Pages/About.razor.cs | 31 +++++++ .../Client/Styles/layout/_mainlayout.scss | 8 ++ 4 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 src/Cropper.Blazor/Client/Models/TeamMember.cs create mode 100644 src/Cropper.Blazor/Client/Pages/About.razor.cs diff --git a/src/Cropper.Blazor/Client/Models/TeamMember.cs b/src/Cropper.Blazor/Client/Models/TeamMember.cs new file mode 100644 index 00000000..493be6cb --- /dev/null +++ b/src/Cropper.Blazor/Client/Models/TeamMember.cs @@ -0,0 +1,13 @@ +namespace Cropper.Blazor.Client.Models +{ + public class TeamMember + { + public string Name { get; set; } + public string Role { get; set; } + public string From { get; set; } + public string Github { get; set; } + public string Avatar { get; set; } + public string LinkedIn { get; set; } + public string Languages { get; set; } + } +} diff --git a/src/Cropper.Blazor/Client/Pages/About.razor b/src/Cropper.Blazor/Client/Pages/About.razor index f13c3886..34751a59 100644 --- a/src/Cropper.Blazor/Client/Pages/About.razor +++ b/src/Cropper.Blazor/Client/Pages/About.razor @@ -10,6 +10,94 @@ })" /> - Sorry - Not available now + About + + Cropper.Blazor is a community-driven initiative aimed at enhancing image cropping in Blazor applications. With a dedicated group of motivated contributors, it's an open invitation for all to join in and make this library even more impressive. Join us to make it even more awesome! + + + + Core Team + + + The Core Team takes the lead in guiding, developing, and steering the Cropper.Blazor project's development. + + + @foreach (var teamMember in TeamMembers) + { + + + + + + + + + @teamMember.Name + + + @teamMember.Role + + + + + @if (!string.IsNullOrWhiteSpace(teamMember.LinkedIn)) + { + + + + } + @if (!string.IsNullOrWhiteSpace(teamMember.Github)) + { + + + + } + + + + + + + + + @if (!string.IsNullOrWhiteSpace(teamMember.Github)) + { + + + @teamMember.Github + + + } + @if (!string.IsNullOrWhiteSpace(teamMember.LinkedIn)) + { + + + @teamMember.LinkedIn + + + } + + + + + + } + diff --git a/src/Cropper.Blazor/Client/Pages/About.razor.cs b/src/Cropper.Blazor/Client/Pages/About.razor.cs new file mode 100644 index 00000000..95fba69c --- /dev/null +++ b/src/Cropper.Blazor/Client/Pages/About.razor.cs @@ -0,0 +1,31 @@ +using Cropper.Blazor.Client.Models; + +namespace Cropper.Blazor.Client.Pages +{ + public partial class About + { + public IEnumerable TeamMembers => new TeamMember[] + { + new TeamMember + { + Avatar = "https://avatars.githubusercontent.com/u/50423072?v=4", + From = "Kyiv, Ukraine", + Github = "https://github.com/MaxymGorn", + LinkedIn = "https://www.linkedin.com/in/maxym-gornytskiy/", + Name = "Maksym Hornytskiy", + Role = "Creator", + Languages = "English, Ukrainian" + }, + new TeamMember + { + Avatar = "https://avatars.githubusercontent.com/u/38187349?v=4", + From = "Ukraine", + Github = "https://github.com/ColdForeign", + LinkedIn = string.Empty, + Name = "George Radchuk", + Role = "Creator", + Languages = "English, Ukrainian" + } + }; + } +} diff --git a/src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss b/src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss index 2622800a..3648e72b 100644 --- a/src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss +++ b/src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss @@ -99,3 +99,11 @@ .docs-gray-bg { background-color: var(--mud-palette-background-grey); } + +.text-with-dots { + max-width: 100%; + overflow: hidden; + display: inline-block; + text-overflow: ellipsis; + white-space: nowrap; +} From 66680e164a292898288a88eea5fbddab3331caac Mon Sep 17 00:00:00 2001 From: Gornytskyi Maxim <50423072+MaxymGorn@users.noreply.github.com> Date: Wed, 8 Nov 2023 23:23:14 +0200 Subject: [PATCH 194/196] Fix default values cropper component, update dependencies (#256) ## Target Fix default values cropper component, update dependencies #### Open Questions ## Checklist - [x] Documentation updated - [x] Tests cover new or modified code - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] New dependencies added - [x] Includes breaking changes - [x] Version bumped ## Visuals --------- Co-authored-by: ColdForeign Co-authored-by: George Radchuk <38187349+ColdForeign@users.noreply.github.com> --- .../Cropper.Blazor.MAUI.Net6.csproj | 2 +- .../Cropper.Blazor.MAUI.Net7.csproj | 2 +- .../Cropper.Blazor.Server.Net6.csproj | 2 +- .../Cropper.Blazor.Server.Net7.csproj | 2 +- ...Cropper.MVC.With.Blazor.Server.Net7.csproj | 2 +- .../Client/Cropper.Blazor.Client.csproj | 6 +- .../BasicUsage/BasicCropperUsagePage.razor | 2 +- .../Cropper.Blazor.Client.Compiler.csproj | 8 +- .../Components/CropperComponent_Should.cs | 76 +++++++++++++++ .../Cropper.Blazor.UnitTests.csproj | 10 +- .../Models/Options_Should.cs | 14 +-- .../Components/CropperComponent.razor.cs | 4 +- .../Cropper.Blazor/Cropper.Blazor.csproj | 4 +- .../Models/GetCroppedCanvasOptions.cs | 17 ++-- .../Cropper.Blazor/Models/Options.cs | 96 +++++++++++++++++++ .../wwwroot/cropperJsInterop.js | 6 ++ .../Server/Cropper.Blazor.Server.csproj | 2 +- 17 files changed, 218 insertions(+), 37 deletions(-) diff --git a/examples/Cropper.Blazor.MAUI.Net6/Cropper.Blazor.MAUI.Net6.csproj b/examples/Cropper.Blazor.MAUI.Net6/Cropper.Blazor.MAUI.Net6.csproj index 5fbc8fa9..3411447d 100644 --- a/examples/Cropper.Blazor.MAUI.Net6/Cropper.Blazor.MAUI.Net6.csproj +++ b/examples/Cropper.Blazor.MAUI.Net6/Cropper.Blazor.MAUI.Net6.csproj @@ -50,7 +50,7 @@
- + diff --git a/examples/Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj b/examples/Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj index 0410e0d3..fe193706 100644 --- a/examples/Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj +++ b/examples/Cropper.Blazor.MAUI.Net7/Cropper.Blazor.MAUI.Net7.csproj @@ -52,7 +52,7 @@ - + diff --git a/examples/Cropper.Blazor.Server.Net6/Cropper.Blazor.Server.Net6.csproj b/examples/Cropper.Blazor.Server.Net6/Cropper.Blazor.Server.Net6.csproj index 2defdc2f..2d7cf1c1 100644 --- a/examples/Cropper.Blazor.Server.Net6/Cropper.Blazor.Server.Net6.csproj +++ b/examples/Cropper.Blazor.Server.Net6/Cropper.Blazor.Server.Net6.csproj @@ -7,7 +7,7 @@
- + diff --git a/examples/Cropper.Blazor.Server.Net7/Cropper.Blazor.Server.Net7.csproj b/examples/Cropper.Blazor.Server.Net7/Cropper.Blazor.Server.Net7.csproj index 9fa604ee..660da7be 100644 --- a/examples/Cropper.Blazor.Server.Net7/Cropper.Blazor.Server.Net7.csproj +++ b/examples/Cropper.Blazor.Server.Net7/Cropper.Blazor.Server.Net7.csproj @@ -7,7 +7,7 @@ - + diff --git a/examples/Cropper.MVC.With.Blazor.Server.Net7/Cropper.MVC.With.Blazor.Server.Net7.csproj b/examples/Cropper.MVC.With.Blazor.Server.Net7/Cropper.MVC.With.Blazor.Server.Net7.csproj index 373af909..5eacfe5c 100644 --- a/examples/Cropper.MVC.With.Blazor.Server.Net7/Cropper.MVC.With.Blazor.Server.Net7.csproj +++ b/examples/Cropper.MVC.With.Blazor.Server.Net7/Cropper.MVC.With.Blazor.Server.Net7.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj index d2438ca2..a142bc47 100644 --- a/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj +++ b/src/Cropper.Blazor/Client/Cropper.Blazor.Client.csproj @@ -29,10 +29,10 @@ - - + + - + diff --git a/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor b/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor index 4c190131..2aea1ba9 100644 --- a/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor +++ b/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor @@ -21,7 +21,7 @@ which can be left as default, as in the example below.
- Note: With the release of .NET 8, сropper's default settings will be set automatically, + Note: With the release of 1.2.7 Cropper.Blazor NuGet package, сropper's default settings will be set automatically, so you do not need to define them when declaring a component. diff --git a/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/Cropper.Blazor.Client.Compiler.csproj b/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/Cropper.Blazor.Client.Compiler.csproj index f4a42d09..faeaa202 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/Cropper.Blazor.Client.Compiler.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/Cropper.Blazor.Client.Compiler.csproj @@ -5,12 +5,12 @@ net7.0 + + + + - - - - diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs index 442343bc..43815a60 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs @@ -15,6 +15,7 @@ using Cropper.Blazor.Events.CropReadyEvent; using Cropper.Blazor.Events.CropStartEvent; using Cropper.Blazor.Events.ZoomEvent; +using Cropper.Blazor.Extensions; using Cropper.Blazor.Models; using Cropper.Blazor.Services; using Cropper.Blazor.Testing; @@ -725,6 +726,81 @@ await cropperComponent.InvokeAsync(() => }); } + [Fact] + public async Task Should_Render_CropperComponent_Without_Options_Parameter_SuccessfulAsync() + { + // arrange + CancellationToken cancellationToken = new(); + ProgressEventArgs progressEventArgs = new Faker() + .Generate(); + + ComponentParameter onLoadImageParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.OnLoadImageEvent), + null); + + // act + IRenderedComponent cropperComponent = _testContext + .RenderComponent( + onLoadImageParameter); + + // assert + IElement expectedElement = cropperComponent.Find($"img"); + ElementReference elementReference = (ElementReference)cropperComponent.Instance + .GetInstanceField("ImageReference"); + Guid cropperComponentId = (Guid)cropperComponent.Instance + .GetInstanceField("CropperComponentId"); + + _mockCropperJsInterop.Verify(c => c.LoadModuleAsync(cancellationToken), Times.Once()); + elementReference.Id.Should().NotBeNullOrEmpty(); + expectedElement.ClassName.Should().BeNull(); + expectedElement.GetAttribute("src").Should().BeNull(); + expectedElement.GetAttribute("blazor:elementreference").Should().Be(elementReference.Id); + + expectedElement.TriggerEvent("onload", progressEventArgs); + _mockCropperJsInterop.Verify(c => c.InitCropperAsync( + cropperComponentId, + elementReference, + It.Is(o => VerifyOptions(o)), + It.IsAny>(), + cancellationToken), Times.Once()); + } + + private bool VerifyOptions(Options options) => + options.ViewMode == ViewMode.Vm0 + && options.DragMode == DragMode.Crop.ToEnumString() + && options.InitialAspectRatio == null + && options.AspectRatio == null + && options.SetDataOptions == null + && options.Preview == null + && options.Responsive == true + && options.Restore == true + && options.CheckCrossOrigin == true + && options.CheckOrientation == true + && options.Modal == true + && options.Guides == true + && options.Center == true + && options.Highlight == true + && options.Background == true + && options.AutoCrop == true + && options.AutoCropArea == 0.8m + && options.Movable == true + && options.Rotatable == true + && options.Scalable == true + && options.Zoomable == true + && options.ZoomOnTouch == true + && options.ZoomOnWheel == true + && options.WheelZoomRatio == 0.1m + && options.CropBoxMovable == true + && options.CropBoxResizable == true + && options.ToggleDragModeOnDblclick == true + && options.MinCanvasWidth == 0 + && options.MinCanvasHeight == 0 + && options.MinCropBoxWidth == 0 + && options.MinCropBoxHeight == 0 + && options.MinContainerWidth == 200 + && options.MinContainerHeight == 100 + && options.CorrelationId == "Cropper.Blazor"; + public void Dispose() { _testContext.DisposeComponents(); diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj index fb045cb0..8df67614 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Cropper.Blazor.UnitTests.csproj @@ -9,16 +9,16 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -33,7 +33,7 @@ - + diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/Options_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/Options_Should.cs index 45741cb9..404a8070 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/Options_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/Options_Should.cs @@ -19,12 +19,12 @@ public class InternalJSRuntime : JSRuntime { protected override void BeginInvokeJS(long taskId, string identifier, string? argsJson, JSCallResultType resultType, long targetInstanceId) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } protected override void EndInvokeDotNet(DotNetInvocationInfo invocationInfo, in DotNetInvocationResult invocationResult) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public JsonSerializerOptions GetJsonSerializerOptions => JsonSerializerOptions; @@ -75,19 +75,19 @@ public static IEnumerable TestData_Setup_Options_Preview() { yield return WrapArgs( null, - "{\"correlationId\":\"Cropper.Blazor\"}"); + "{\"autoCrop\":true,\"autoCropArea\":0.8,\"background\":true,\"center\":true,\"checkCrossOrigin\":true,\"checkOrientation\":true,\"cropBoxMovable\":true,\"cropBoxResizable\":true,\"dragMode\":\"crop\",\"guides\":true,\"highlight\":true,\"minCanvasHeight\":0,\"minCanvasWidth\":0,\"minContainerHeight\":100,\"minContainerWidth\":200,\"minCropBoxHeight\":0,\"minCropBoxWidth\":0,\"modal\":true,\"movable\":true,\"responsive\":true,\"restore\":true,\"rotatable\":true,\"scalable\":true,\"toggleDragModeOnDblclick\":true,\"viewMode\":0,\"wheelZoomRatio\":0.1,\"zoomOnTouch\":true,\"zoomOnWheel\":true,\"zoomable\":true,\"correlationId\":\"Cropper.Blazor\"}"); yield return WrapArgs( ".testClass", - "{\"preview\":\".testClass\",\"correlationId\":\"Cropper.Blazor\"}"); + "{\"preview\":\".testClass\",\"autoCrop\":true,\"autoCropArea\":0.8,\"background\":true,\"center\":true,\"checkCrossOrigin\":true,\"checkOrientation\":true,\"cropBoxMovable\":true,\"cropBoxResizable\":true,\"dragMode\":\"crop\",\"guides\":true,\"highlight\":true,\"minCanvasHeight\":0,\"minCanvasWidth\":0,\"minContainerHeight\":100,\"minContainerWidth\":200,\"minCropBoxHeight\":0,\"minCropBoxWidth\":0,\"modal\":true,\"movable\":true,\"responsive\":true,\"restore\":true,\"rotatable\":true,\"scalable\":true,\"toggleDragModeOnDblclick\":true,\"viewMode\":0,\"wheelZoomRatio\":0.1,\"zoomOnTouch\":true,\"zoomOnWheel\":true,\"zoomable\":true,\"correlationId\":\"Cropper.Blazor\"}"); yield return WrapArgs( new ElementReference("ElementReferenceId"), - "{\"preview\":{\"id\":\"ElementReferenceId\",\"context\":null},\"correlationId\":\"Cropper.Blazor\"}"); + "{\"preview\":{\"id\":\"ElementReferenceId\",\"context\":null},\"autoCrop\":true,\"autoCropArea\":0.8,\"background\":true,\"center\":true,\"checkCrossOrigin\":true,\"checkOrientation\":true,\"cropBoxMovable\":true,\"cropBoxResizable\":true,\"dragMode\":\"crop\",\"guides\":true,\"highlight\":true,\"minCanvasHeight\":0,\"minCanvasWidth\":0,\"minContainerHeight\":100,\"minContainerWidth\":200,\"minCropBoxHeight\":0,\"minCropBoxWidth\":0,\"modal\":true,\"movable\":true,\"responsive\":true,\"restore\":true,\"rotatable\":true,\"scalable\":true,\"toggleDragModeOnDblclick\":true,\"viewMode\":0,\"wheelZoomRatio\":0.1,\"zoomOnTouch\":true,\"zoomOnWheel\":true,\"zoomable\":true,\"correlationId\":\"Cropper.Blazor\"}"); yield return WrapArgs( new ElementReference("ElementReferenceId", new CustomElementReferenceContext()), - "{\"preview\":{\"id\":\"ElementReferenceId\",\"context\":{}},\"correlationId\":\"Cropper.Blazor\"}"); + "{\"preview\":{\"id\":\"ElementReferenceId\",\"context\":{}},\"autoCrop\":true,\"autoCropArea\":0.8,\"background\":true,\"center\":true,\"checkCrossOrigin\":true,\"checkOrientation\":true,\"cropBoxMovable\":true,\"cropBoxResizable\":true,\"dragMode\":\"crop\",\"guides\":true,\"highlight\":true,\"minCanvasHeight\":0,\"minCanvasWidth\":0,\"minContainerHeight\":100,\"minContainerWidth\":200,\"minCropBoxHeight\":0,\"minCropBoxWidth\":0,\"modal\":true,\"movable\":true,\"responsive\":true,\"restore\":true,\"rotatable\":true,\"scalable\":true,\"toggleDragModeOnDblclick\":true,\"viewMode\":0,\"wheelZoomRatio\":0.1,\"zoomOnTouch\":true,\"zoomOnWheel\":true,\"zoomable\":true,\"correlationId\":\"Cropper.Blazor\"}"); yield return WrapArgs( new ElementReference[] @@ -95,7 +95,7 @@ public static IEnumerable TestData_Setup_Options_Preview() new ElementReference("ElementReferenceId"), new ElementReference("ElementReferenceId", new CustomElementReferenceContext()) }, - "{\"preview\":[{\"id\":\"ElementReferenceId\",\"context\":null},{\"id\":\"ElementReferenceId\",\"context\":{}}],\"correlationId\":\"Cropper.Blazor\"}"); + "{\"preview\":[{\"id\":\"ElementReferenceId\",\"context\":null},{\"id\":\"ElementReferenceId\",\"context\":{}}],\"autoCrop\":true,\"autoCropArea\":0.8,\"background\":true,\"center\":true,\"checkCrossOrigin\":true,\"checkOrientation\":true,\"cropBoxMovable\":true,\"cropBoxResizable\":true,\"dragMode\":\"crop\",\"guides\":true,\"highlight\":true,\"minCanvasHeight\":0,\"minCanvasWidth\":0,\"minContainerHeight\":100,\"minContainerWidth\":200,\"minCropBoxHeight\":0,\"minCropBoxWidth\":0,\"modal\":true,\"movable\":true,\"responsive\":true,\"restore\":true,\"rotatable\":true,\"scalable\":true,\"toggleDragModeOnDblclick\":true,\"viewMode\":0,\"wheelZoomRatio\":0.1,\"zoomOnTouch\":true,\"zoomOnWheel\":true,\"zoomable\":true,\"correlationId\":\"Cropper.Blazor\"}"); static object[] WrapArgs( object? preview, diff --git a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs index 5508a60b..4a3b1105 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs @@ -41,7 +41,7 @@ public partial class CropperComponent : ICropperComponentBase, IAsyncDisposable, /// The options for cropping. Check out the available . ///
[Parameter] - public Options Options { get; set; } = null!; + public Options Options { get; set; } = new Options(); /// /// Specifies the path to the image. @@ -268,7 +268,7 @@ public void IsReady(JSEventData jSEventData) /// /// The used to set new drag mode. /// The used to propagate notifications that the operation should be canceled. - public void SetDragMode(DragMode dragMode, CancellationToken cancellationToken = default) + public void SetDragMode(DragMode dragMode = DragMode.None, CancellationToken cancellationToken = default) { CropperJsIntertop!.SetDragModeAsync(CropperComponentId, dragMode, cancellationToken); } diff --git a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj index 9f3a0f96..8a5697e8 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj +++ b/src/Cropper.Blazor/Cropper.Blazor/Cropper.Blazor.csproj @@ -14,7 +14,7 @@ - 1.2.6 + 1.2.7 LICENSE NuGet.png Cropper.Blazor @@ -110,7 +110,7 @@ - + diff --git a/src/Cropper.Blazor/Cropper.Blazor/Models/GetCroppedCanvasOptions.cs b/src/Cropper.Blazor/Cropper.Blazor/Models/GetCroppedCanvasOptions.cs index 8cdd20e8..ff1b3a5a 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Models/GetCroppedCanvasOptions.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Models/GetCroppedCanvasOptions.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using Cropper.Blazor.Extensions; namespace Cropper.Blazor.Models { @@ -20,20 +21,20 @@ public class GetCroppedCanvasOptions /// /// The minimum destination width of the output canvas, the default value is 0. /// - public decimal? MinWidth { get; set; } + public decimal? MinWidth { get; set; } = 0; /// /// The minimum destination height of the output canvas, the default value is 0. /// - public decimal? MinHeight { get; set; } + public decimal? MinHeight { get; set; } = 0; /// - /// The maximum destination width of the output canvas, the default value is Infinity. + /// The maximum destination width of the output canvas, the default value is null (Infinity). /// public decimal? MaxWidth { get; set; } /// - /// The maximum destination height of the output canvas, the default value is Infinity. + /// The maximum destination height of the output canvas, the default value is null (Infinity). /// public decimal? MaxHeight { get; set; } @@ -44,18 +45,20 @@ public class GetCroppedCanvasOptions /// /// Set to change if images are smoothed (true, default) or not (false). + /// For more information see official imageSmoothingEnabled documentation. /// - public bool? ImageSmoothingEnabled { get; set; } + public bool? ImageSmoothingEnabled { get; set; } = true; /// /// Set the quality of image smoothing, one of "low" (default), "medium", or "high". + /// For more information see official imageSmoothingQuality documentation. /// [EnumDataType(typeof(ImageSmoothingQuality))] - public string? ImageSmoothingQuality { get; set; } + public string? ImageSmoothingQuality { get; set; } = Models.ImageSmoothingQuality.Low.ToEnumString(); /// /// Set true to use rounded values (the cropped area position and size data), the default value is false. /// - public bool? Rounded { get; set; } + public bool? Rounded { get; set; } = false; } } \ No newline at end of file diff --git a/src/Cropper.Blazor/Cropper.Blazor/Models/Options.cs b/src/Cropper.Blazor/Cropper.Blazor/Models/Options.cs index 4529fc33..21792e0a 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Models/Options.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Models/Options.cs @@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text.Json.Serialization; +using Cropper.Blazor.Extensions; using Microsoft.AspNetCore.Components; namespace Cropper.Blazor.Models @@ -12,6 +13,101 @@ namespace Cropper.Blazor.Models ///
public class Options { + /// + /// Implementation of the constructor. + /// + public Options() + { + // Define the view mode of the cropper + ViewMode = 0; // 0, 1, 2, 3 + + // Define the dragging mode of the cropper + DragMode = Models.DragMode.Crop.ToEnumString()!; // 'crop', 'move' or 'none' + + // Define the initial aspect ratio of the crop box + InitialAspectRatio = null; + + // Define the aspect ratio of the crop box + AspectRatio = null; + + // An object with the previous cropping result data + SetDataOptions = null; + + // A selector for adding extra containers to preview + Preview = null; + + // Re-render the cropper when resize the window + Responsive = true; + + // Restore the cropped area after resize the window + Restore = true; + + // Check if the current image is a cross-origin image + CheckCrossOrigin = true; + + // Check the current image's Exif Orientation information + CheckOrientation = true; + + // Show the black modal + Modal = true; + + // Show the dashed lines for guiding + Guides = true; + + // Show the center indicator for guiding + Center = true; + + // Show the white modal to highlight the crop box + Highlight = true; + + // Show the grid background + Background = true; + + // Enable to crop the image automatically when initialize + AutoCrop = true; + + // Define the percentage of automatic cropping area when initializes + AutoCropArea = 0.8m; + + // Enable to move the image + Movable = true; + + // Enable to rotate the image + Rotatable = true; + + // Enable to scale the image + Scalable = true; + + // Enable to zoom the image + Zoomable = true; + + // Enable to zoom the image by dragging touch + ZoomOnTouch = true; + + // Enable to zoom the image by wheeling mouse + ZoomOnWheel = true; + + // Define zoom ratio when zoom the image by wheeling mouse + WheelZoomRatio = 0.1m; + + // Enable to move the crop box + CropBoxMovable = true; + + // Enable to resize the crop box + CropBoxResizable = true; + + // Toggle drag mode between "crop" and "move" when click twice on the cropper + ToggleDragModeOnDblclick = true; + + // Size limitation + MinCanvasWidth = 0; + MinCanvasHeight = 0; + MinCropBoxWidth = 0; + MinCropBoxHeight = 0; + MinContainerWidth = 200; + MinContainerHeight = 100; + } + private object? preview = null; /// diff --git a/src/Cropper.Blazor/Cropper.Blazor/wwwroot/cropperJsInterop.js b/src/Cropper.Blazor/Cropper.Blazor/wwwroot/cropperJsInterop.js index 0523316b..98c1f0be 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/wwwroot/cropperJsInterop.js +++ b/src/Cropper.Blazor/Cropper.Blazor/wwwroot/cropperJsInterop.js @@ -46,11 +46,17 @@ class CropperDecorator { } getCroppedCanvas(cropperComponentId, options) { + options.maxWidth ??= Infinity; + options.maxHeight ??= Infinity; + return this.cropperInstances[cropperComponentId] .getCroppedCanvas(options); } getCroppedCanvasDataURL(cropperComponentId, options, type, encoderOptions) { + options.maxWidth ??= Infinity; + options.maxHeight ??= Infinity; + return this.cropperInstances[cropperComponentId] .getCroppedCanvas(options) .toDataURL(type, encoderOptions); diff --git a/src/Cropper.Blazor/Server/Cropper.Blazor.Server.csproj b/src/Cropper.Blazor/Server/Cropper.Blazor.Server.csproj index 4e46aa90..cddb215e 100644 --- a/src/Cropper.Blazor/Server/Cropper.Blazor.Server.csproj +++ b/src/Cropper.Blazor/Server/Cropper.Blazor.Server.csproj @@ -8,7 +8,7 @@ - + From d8bcb99a7ad36bb2975bf2eb4891a70e3725c787 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Thu, 9 Nov 2023 11:15:39 +0200 Subject: [PATCH 195/196] fix --- .../Components/Docs/SectionHeader.razor.cs | 2 - ...ntReferenceSelectorComponentsExample.razor | 25 -------- ...ferenceSelectorComponentsExample.razor.css | 14 ----- ...eferenceSelectorComponentsExampleCode.html | 54 ------------------ ...ntReferenceSelectorComponentsExample.razor | 25 -------- ...ferenceSelectorComponentsExample.razor.css | 14 ----- ...eferenceSelectorComponentsExampleCode.html | 57 ------------------- ...wFromStringSelectorComponentsExample.razor | 16 ------ ...mStringSelectorComponentsExample.razor.css | 14 ----- ...omStringSelectorComponentsExampleCode.html | 45 --------------- .../Cropper.Blazor/Models/Options.cs | 2 - 11 files changed, 268 deletions(-) delete mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor delete mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css delete mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html delete mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor delete mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css delete mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html delete mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor delete mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css delete mode 100644 src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html diff --git a/src/Cropper.Blazor/Client/Components/Docs/SectionHeader.razor.cs b/src/Cropper.Blazor/Client/Components/Docs/SectionHeader.razor.cs index 3c5df49f..749fa2e5 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/SectionHeader.razor.cs +++ b/src/Cropper.Blazor/Client/Components/Docs/SectionHeader.razor.cs @@ -15,7 +15,6 @@ public partial class SectionHeader [CascadingParameter] private DocsPage DocsPage { get; set; } [CascadingParameter] private DocsPageSection Section { get; set; } - [CascadingParameter] private DocsPage DocsPage { get; set; } [Parameter] public string Class { get; set; } @@ -27,7 +26,6 @@ public partial class SectionHeader [Parameter] public RenderFragment SubTitle { get; set; } [Parameter] public RenderFragment Description { get; set; } - public DocsSectionLink SectionInfo { get; set; } public ElementReference SectionReference; diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor deleted file mode 100644 index af750908..00000000 --- a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor +++ /dev/null @@ -1,25 +0,0 @@ -@using Cropper.Blazor.Components - -
- -
-
- -@code { - private Cropper.Blazor.Models.Options Options = new(); - private ElementReference ElementReference; - - protected override void OnAfterRender(bool firstRender) - { - if (firstRender) - { - Options.Preview = new ElementReference[] - { - ElementReference - }; - } - } -} diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css deleted file mode 100644 index 515e4e8c..00000000 --- a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExample.razor.css +++ /dev/null @@ -1,14 +0,0 @@ -.cropper-example { - max-height: 300px; - width: 100%; -} - -.img-example-preview { - width: 100%; - height: 300px; - overflow: hidden; -} - -.img-example-preview > ::deep img { - max-width: 100%; -} diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html deleted file mode 100644 index ee980e87..00000000 --- a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromElementReferenceSelectorComponentsExampleCode.html +++ /dev/null @@ -1,54 +0,0 @@ -
-
-
-@using Cropper.Blazor.Components;
-
-<div class="img-container"
-        <CropperComponent 
-            Class="cropper-example"
-            Src="cropperblazor.png"
-            Options="Options"
-        />
-</div>
-<div @ref="ElementReference" class="img-example-preview" />
-
-
@code {
-    private Cropper.Blazor.Models.Options Options = new();
-    private Microsoft.AspNetCore.Components.ElementReference ElementReference;
-
-    protected override void OnAfterRender(bool firstRender)
-    {
-        if (firstRender)
-        {
-            Options.Preview = new ElementReference[]
-            {
-                ElementReference
-            };
-        }
-    }
-}
-
-
-
-
- // Add this style for cropper and preview image. -
-
-.cropper-example {
-    max-height: 300px;
-    width: 100%;
-}
-
-.img-example-preview {
-    width: 100%;
-    height: 300px;
-    overflow: hidden;
-}
-
-.img-example-preview > ::deep img {
-    max-width: 100%;
-}
-
-        
-
-
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor deleted file mode 100644 index a619227f..00000000 --- a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor +++ /dev/null @@ -1,25 +0,0 @@ -@using Cropper.Blazor.Components - -
- -
-
-
- -@code { - private Cropper.Blazor.Models.Options Options = new(); - private ElementReference FirstElementReference; - private ElementReference SecondElementReference; - - protected override void OnAfterRender(bool firstRender) - { - if (firstRender) - { - Options.Preview = new ElementReference[] - { - FirstElementReference, - SecondElementReference - }; - } - } -} diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css deleted file mode 100644 index 515e4e8c..00000000 --- a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExample.razor.css +++ /dev/null @@ -1,14 +0,0 @@ -.cropper-example { - max-height: 300px; - width: 100%; -} - -.img-example-preview { - width: 100%; - height: 300px; - overflow: hidden; -} - -.img-example-preview > ::deep img { - max-width: 100%; -} diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html deleted file mode 100644 index 4524802d..00000000 --- a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromMultipleElementReferenceSelectorComponentsExampleCode.html +++ /dev/null @@ -1,57 +0,0 @@ -
-
-
-@using Cropper.Blazor.Components;
-
-<div class="img-container"
-        <CropperComponent 
-            Class="cropper-example"
-            Src="cropperblazor.png"
-            Options="Options"
-        />
-</div>
-<div @ref="FirstElementReference" class="img-example-preview" />
-<div @ref="SecondElementReference" class="img-example-preview" />
-
-
@code {
-    private Cropper.Blazor.Models.Options Options = new();
-    private Microsoft.AspNetCore.Components.ElementReference FirstElementReference;
-    private Microsoft.AspNetCore.Components.ElementReference SecondElementReference;
-
-    protected override void OnAfterRender(bool firstRender)
-    {
-        if (firstRender)
-        {
-            Options.Preview = new ElementReference[]
-            {
-                FirstElementReference,
-                SecondElementReference
-            };
-        }
-    }
-}
-
-
-
-
- // Add this style for cropper and preview image. -
-
-.cropper-example {
-    max-height: 300px;
-    width: 100%;
-}
-
-.img-example-preview {
-    width: 100%;
-    height: 300px;
-    overflow: hidden;
-}
-
-.img-example-preview > ::deep img {
-    max-width: 100%;
-}
-
-        
-
-
diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor deleted file mode 100644 index c61d27a1..00000000 --- a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor +++ /dev/null @@ -1,16 +0,0 @@ -@using Cropper.Blazor.Components - -
- -
-
- -@code { - private Cropper.Blazor.Models.Options Options = new Cropper.Blazor.Models.Options - { - Preview = ".img-example-preview" - }; -} diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css deleted file mode 100644 index 515e4e8c..00000000 --- a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExample.razor.css +++ /dev/null @@ -1,14 +0,0 @@ -.cropper-example { - max-height: 300px; - width: 100%; -} - -.img-example-preview { - width: 100%; - height: 300px; - overflow: hidden; -} - -.img-example-preview > ::deep img { - max-width: 100%; -} diff --git a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html b/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html deleted file mode 100644 index f6c984eb..00000000 --- a/src/Cropper.Blazor/Client/Pages/Examples/Uses/Preview/UsesPreviewFromStringSelectorComponentsExampleCode.html +++ /dev/null @@ -1,45 +0,0 @@ -
-
-
-@using Cropper.Blazor.Components;
-
-<div class="img-container"
-        <CropperComponent 
-            Class="cropper-example"
-            Src="cropperblazor.png"
-            Options="Options"
-        />
-</div>
-<div class="img-example-preview" />
-
-
@code {
-    private Cropper.Blazor.Models.Options Options = new Cropper.Blazor.Models.Options
-    {
-        Preview = ".img-example-preview"
-    };
-}
-
-
-
-
- // Add this style for cropper and preview image. -
-
-.cropper-example {
-    max-height: 300px;
-    width: 100%;
-}
-
-.img-example-preview {
-    width: 100%;
-    height: 300px;
-    overflow: hidden;
-}
-
-.img-example-preview > ::deep img {
-    max-width: 100%;
-}
-
-        
-
-
diff --git a/src/Cropper.Blazor/Cropper.Blazor/Models/Options.cs b/src/Cropper.Blazor/Cropper.Blazor/Models/Options.cs index c171755f..21792e0a 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Models/Options.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Models/Options.cs @@ -13,8 +13,6 @@ namespace Cropper.Blazor.Models ///
public class Options { - private object? preview = null; - /// /// Implementation of the constructor. /// From 501ea220978249d2229f4796cb52b53f5b85bcd1 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Thu, 9 Nov 2023 11:41:18 +0200 Subject: [PATCH 196/196] fix --- .../Client/Components/Docs/DocsPage.razor | 7 ----- .../Client/Components/Docs/DocsPage.razor.cs | 2 -- .../Components/Docs/DocsPageContent.razor | 3 +- .../Client/Pages/CropperDemo.razor | 2 +- .../Client/Pages/CropperDemo.razor.cs | 4 +-- .../Client/Styles/components/docssection.scss | 31 ------------------- .../Client/Styles/layout/_mainlayout.scss | 2 +- .../Cropper.Blazor.Client.Compiler/Program.cs | 1 - 8 files changed, 4 insertions(+), 48 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor b/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor index 14c09d45..f50ca050 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor +++ b/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor @@ -5,14 +5,7 @@ @ChildContent - - @if (DisplayFooter) - { - - - } @if (_displayView) { diff --git a/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor.cs b/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor.cs index 20590af2..7acad243 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor.cs +++ b/src/Cropper.Blazor/Client/Components/Docs/DocsPage.razor.cs @@ -9,8 +9,6 @@ namespace Cropper.Blazor.Client.Components.Docs { public partial class DocsPage : ComponentBase { - [Parameter] public bool DisplayFooter { get; set; } - private Queue _bufferedSections = new(); private MudPageContentNavigation _contentNavigation; private Stopwatch _stopwatch = Stopwatch.StartNew(); diff --git a/src/Cropper.Blazor/Client/Components/Docs/DocsPageContent.razor b/src/Cropper.Blazor/Client/Components/Docs/DocsPageContent.razor index 35783dc3..e1e388f4 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/DocsPageContent.razor +++ b/src/Cropper.Blazor/Client/Components/Docs/DocsPageContent.razor @@ -1,5 +1,4 @@ - -
+
@ChildContent
diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index b6ba428d..6ded163a 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -21,7 +21,7 @@
SetAspectRatio(0, true); - public void SetViewMode(ViewMode viewMode) { Options.ViewMode = viewMode; diff --git a/src/Cropper.Blazor/Client/Styles/components/docssection.scss b/src/Cropper.Blazor/Client/Styles/components/docssection.scss index 50855c7c..065d6534 100644 --- a/src/Cropper.Blazor/Client/Styles/components/docssection.scss +++ b/src/Cropper.Blazor/Client/Styles/components/docssection.scss @@ -197,37 +197,6 @@ } } -@media (min-width: 1280px) { - .mud-drawer-open-responsive-lg-right .mud-main-content { - margin-right: 120px !important; - } -} - -.disabled { - pointer-events: none; - cursor: default; - opacity: 0.6; -} - -.docs-content-api-max-width { - max-width: 800px; -} - -.docs-content-return-api-max-width, .docs-content-description-api-max-width { - max-width: 400px; -} - -.docs-content-api-sm-max-width { - text-align: end; - padding: 10px; -} - -.docs-content-api-desc-sm-max-width { - display: inline-flex; - flex-direction: row; - white-space: pre; -} - .warning-color { color: var(--mud-palette-warning) !important; } diff --git a/src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss b/src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss index 79321728..3648e72b 100644 --- a/src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss +++ b/src/Cropper.Blazor/Client/Styles/layout/_mainlayout.scss @@ -1,7 +1,7 @@ .docs-title { font-family: 'Public Sans', 'Roboto', 'Arial', sans-serif; font-weight: 600; - font-size: 1.75rem; + font-size: 3.75rem; } .docs-title-description { diff --git a/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/Program.cs b/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/Program.cs index 430b5459..2d20b197 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/Program.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.Client.Compiler/Program.cs @@ -14,7 +14,6 @@ public static int Main() && new DocStrings().Execute(); Console.WriteLine($"Docs.Compiler completed in {stopWatch.ElapsedMilliseconds} msecs"); - return success ? 0 : 1; } }