From 2f7593f8e67b72d2cfb97f265a6dbff9bb8d15fa Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sat, 6 May 2023 01:26:12 +0300 Subject: [PATCH 01/15] 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 02/15] 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 03/15] 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 04/15] 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 05/15] 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 06/15] 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 07/15] 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 08/15] 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 09/15] 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 10/15] 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 11/15] 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 12/15] 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 13/15] 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 14/15] 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 15/15] 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 @@ - +