diff --git a/Plk.Blazor.DragDrop.Demo/Plk.Blazor.DragDrop.Demo.csproj b/Plk.Blazor.DragDrop.Demo/Plk.Blazor.DragDrop.Demo.csproj index 4d3f487..4b42d5d 100644 --- a/Plk.Blazor.DragDrop.Demo/Plk.Blazor.DragDrop.Demo.csproj +++ b/Plk.Blazor.DragDrop.Demo/Plk.Blazor.DragDrop.Demo.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + net5.0 f648770a-26a2-462b-87a0-17835ea631cb diff --git a/Plk.Blazor.DragDrop.Test/Plk.Blazor.DragDrop.Test.csproj b/Plk.Blazor.DragDrop.Test/Plk.Blazor.DragDrop.Test.csproj index 01cace5..17d3cb1 100644 --- a/Plk.Blazor.DragDrop.Test/Plk.Blazor.DragDrop.Test.csproj +++ b/Plk.Blazor.DragDrop.Test/Plk.Blazor.DragDrop.Test.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net5.0 3.0 diff --git a/Plk.Blazor.DragDrop/Dropzone.razor b/Plk.Blazor.DragDrop/Dropzone.razor index eb9dbe2..d988848 100644 --- a/Plk.Blazor.DragDrop/Dropzone.razor +++ b/Plk.Blazor.DragDrop/Dropzone.razor @@ -43,428 +43,4 @@ -@code { - private void OnDropItemOnSpacing(int newIndex) - { - if (!IsDropAllowed()) - { - DragDropService.Reset(); - return; - } - - var activeItem = DragDropService.ActiveItem; - var oldIndex = Items.IndexOf(activeItem); - var sameDropZone = false; - - if(oldIndex == -1) // item not present in target dropzone - { - if(CopyItem == null) - { - DragDropService.Items.Remove(activeItem); - } - } - else // same dropzone drop - { - sameDropZone = true; - Items.RemoveAt(oldIndex); - // the actual index could have shifted due to the removal - if (newIndex > oldIndex) newIndex--; - } - - if(CopyItem == null) - { - Items.Insert(newIndex, activeItem); - } - else - { - // for the same zone - do not call CopyItem - Items.Insert(newIndex, sameDropZone ? activeItem : CopyItem(activeItem)); - } - - //Operation is finished - DragDropService.Reset(); - OnItemDrop.InvokeAsync(activeItem); - } - - private bool IsMaxItemLimitReached() - { - var activeItem = DragDropService.ActiveItem; - - return (!Items.Contains(activeItem) && MaxItems.HasValue && MaxItems == Items.Count()); - } - - private string IsItemDragable(TItem item) - { - if (AllowsDrag == null) return "true"; - if (item == null) return "false"; - - return AllowsDrag(item).ToString(); - } - - private bool IsItemAccepted(TItem dragTargetItem) - { - if (Accepts == null) return true; - - return Accepts(DragDropService.ActiveItem, dragTargetItem); - } - - private bool IsValidItem() - { - return DragDropService.ActiveItem != null; - } - - protected override bool ShouldRender() - { - return DragDropService.ShouldRender; - } - - private void ForceRender(object sender, EventArgs e) - { - StateHasChanged(); - } - - - protected override void OnInitialized() - { - DragDropService.StateHasChanged += ForceRender; - - base.OnInitialized(); - } - - public string CheckIfDraggable(TItem item) - { - if (AllowsDrag == null) return ""; - if (item == null) return ""; - - if (AllowsDrag(item)) return ""; - - return "plk-dd-noselect"; - } - public string CheckIfDragOperationIsInProgess() - { - var activeItem = DragDropService.ActiveItem; - - return activeItem == null ? "" : "plk-dd-inprogess"; - } - - public void OnDragEnd() - { - if (DragEnd != null) - { - DragEnd(DragDropService.ActiveItem); - } - - DragDropService.Reset(); - //dragTargetItem = default; - } - - public void OnDragEnter(TItem item) - { - var activeItem = DragDropService.ActiveItem; - - if (item.Equals(activeItem)) return; - - if (!IsValidItem()) return; - - if (IsMaxItemLimitReached()) return; - - if (!IsItemAccepted(item)) return; - - DragDropService.DragTargetItem = item; - - if (InstantReplace) - { - Swap(DragDropService.DragTargetItem, activeItem); - } - - DragDropService.ShouldRender = true; - StateHasChanged(); - DragDropService.ShouldRender = false; - } - - public void OnDragLeave() - { - DragDropService.DragTargetItem = default; - - DragDropService.ShouldRender = true; - StateHasChanged(); - DragDropService.ShouldRender = false; - } - - public void OnDragStart(TItem item) - { - DragDropService.ShouldRender = true; - DragDropService.ActiveItem = item; - DragDropService.Items = Items; - StateHasChanged(); - DragDropService.ShouldRender = false; - } - - public string CheckIfItemIsInTransit(TItem item) - { - return item.Equals(DragDropService.ActiveItem) ? "plk-dd-in-transit no-pointer-events" : ""; - } - - public string CheckIfItemIsDragTarget(TItem item) - { - if (item.Equals(DragDropService.ActiveItem)) return ""; - - if (item.Equals(DragDropService.DragTargetItem)) - { - return IsItemAccepted(DragDropService.DragTargetItem) ? "plk-dd-dragged-over" : "plk-dd-dragged-over-denied"; - } - - return ""; - } - - private string GetClassesForDraggable(TItem item) - { - var builder = new StringBuilder(); - - builder.Append("plk-dd-draggable"); - - if (ItemWrapperClass != null) - { - var itemWrapperClass = ItemWrapperClass(item); - - builder.AppendLine(" " + itemWrapperClass); - } - - return builder.ToString(); - } - - private string GetClassesForDropzone() - { - var builder = new StringBuilder(); - - builder.Append("plk-dd-dropzone"); - - if (!String.IsNullOrEmpty(Class)) - { - builder.AppendLine(" " + Class); - } - - return builder.ToString(); - } - - private string GetClassesForSpacing(int spacerId) - { - var builder = new StringBuilder(); - - builder.Append("plk-dd-spacing"); - - //if active space id and item is from another dropzone -> always create insert space - if (DragDropService.ActiveSpacerId == spacerId && Items.IndexOf(DragDropService.ActiveItem) == -1) - { - builder.Append(" plk-dd-spacing-dragged-over"); - } // else -> check if active space id and that it is an item that needs space - else if (DragDropService.ActiveSpacerId == spacerId && (spacerId != Items.IndexOf(DragDropService.ActiveItem)) && (spacerId != Items.IndexOf(DragDropService.ActiveItem) + 1)) - { - builder.Append(" plk-dd-spacing-dragged-over"); - } - - return builder.ToString(); - } - - /// - /// Allows to pass a delegate which executes if something is dropped and decides if the item is accepted - /// - [Parameter] public Func Accepts { get; set; } - - - /// - /// Allows to pass a delegate which executes if something is dropped and decides if the item is accepted - /// - [Parameter] public Func AllowsDrag { get; set; } - - /// - /// Allows to pass a delegate which executes if a drag operation ends - /// - [Parameter] public Action DragEnd { get; set; } - - /// - /// Raises a callback with the dropped item as parameter in case the item can not be dropped due to the given Accept Delegate - /// - [Parameter] public EventCallback OnItemDropRejected { get; set; } - - /// - /// Raises a callback with the dropped item as parameter - /// - [Parameter] public EventCallback OnItemDrop { get; set; } - - /// - /// Raises a callback with the replaced item as parameter - /// - [Parameter] public EventCallback OnReplacedItemDrop { get; set; } - - /// - /// If set to true, items will we be swapped/inserted instantly. - /// - [Parameter] public bool InstantReplace { get; set; } - - /// - /// List of items for the dropzone - /// - [Parameter] public IList Items { get; set; } - - /// - /// Maximum Number of items which can be dropped in this dropzone. Defaults to null which means unlimited. - /// - [Parameter] public int? MaxItems { get; set; } - - /// - /// Raises a callback with the dropped item as parameter in case the item can not be dropped due to item limit. - /// - [Parameter] public EventCallback OnItemDropRejectedByMaxItemLimit { get; set; } - - [Parameter] public RenderFragment ChildContent { get; set; } - - /// - /// Specifies one or more classnames for the Dropzone element. - /// - [Parameter] public string Class { get; set; } - - /// - /// Specifies the id for the Dropzone element. - /// - [Parameter] public string Id { get; set; } - - /// - /// Allows to pass a delegate which specifies one or more classnames for the draggable div that wraps your elements. - /// - [Parameter] public Func ItemWrapperClass { get; set; } - - /// - /// If set items dropped are copied to this dropzone and are not removed from their source. - /// - [Parameter] public Func CopyItem { get; set; } - - private bool IsDropAllowed() - { - var activeItem = DragDropService.ActiveItem; - - if (!IsValidItem()) - { - return false; - } - - if (IsMaxItemLimitReached()) - { - OnItemDropRejectedByMaxItemLimit.InvokeAsync(activeItem); - return false; - } - - if (!IsItemAccepted(DragDropService.DragTargetItem)) - { - OnItemDropRejected.InvokeAsync(activeItem); - return false; - } - - return true; - } - - private void OnDrop() - { - DragDropService.ShouldRender = true; - - if (!IsDropAllowed()) - { - DragDropService.Reset(); - return; - } - - var activeItem = DragDropService.ActiveItem; - - if (DragDropService.DragTargetItem == null) //no direct drag target - { - if (!Items.Contains(activeItem)) //if dragged to another dropzone - { - if(CopyItem == null) - { - Items.Insert(Items.Count, activeItem); //insert item to new zone - DragDropService.Items.Remove(activeItem); //remove from old zone - } - else - { - Items.Insert(Items.Count, CopyItem(activeItem)); //insert item to new zone - } - } - else - { - //what to do here? - - } - } - else // we have a direct target - { - if( !Items.Contains( activeItem ) ) // if dragged to another dropzone - { - if( CopyItem == null ) - { - if( !InstantReplace ) - { - Swap(DragDropService.DragTargetItem, activeItem); //swap target with active item - } - } - else - { - if( !InstantReplace ) - { - Swap(DragDropService.DragTargetItem, CopyItem( activeItem ) ); //swap target with a copy of active item - } - } - } - else - { - // if dragged to the same dropzone - if (!InstantReplace) - { - Swap( DragDropService.DragTargetItem, activeItem ); //swap target with active item - } - } - - } - - DragDropService.Reset(); - - StateHasChanged(); - - OnItemDrop.InvokeAsync(activeItem); - } - - private void Swap(TItem draggedOverItem, TItem activeItem) - { - var indexDraggedOverItem = Items.IndexOf(draggedOverItem); - var indexActiveItem = Items.IndexOf(activeItem); - - if (indexActiveItem == -1) // item is new to the dropzone - { - //insert into new zone - Items.Insert(indexDraggedOverItem + 1, activeItem); - //remove from old zone - DragDropService.Items.Remove(activeItem); - } - else if (InstantReplace) //swap the items - { - if (indexDraggedOverItem == indexActiveItem) return; - TItem tmp = Items[indexDraggedOverItem]; - Items[indexDraggedOverItem] = Items[indexActiveItem]; - Items[indexActiveItem] = tmp; - OnReplacedItemDrop.InvokeAsync(Items[indexActiveItem]); - } - else //no instant replace, just insert it after - { - if (indexDraggedOverItem == indexActiveItem) return; - var tmp = Items[indexActiveItem]; - Items.RemoveAt(indexActiveItem); - Items.Insert(indexDraggedOverItem, tmp); - } - - } - - public void Dispose() - { - DragDropService.StateHasChanged -= ForceRender; - } -} diff --git a/Plk.Blazor.DragDrop/Dropzone.razor.cs b/Plk.Blazor.DragDrop/Dropzone.razor.cs new file mode 100644 index 0000000..07965cf --- /dev/null +++ b/Plk.Blazor.DragDrop/Dropzone.razor.cs @@ -0,0 +1,432 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; +using System.Text; + +namespace Plk.Blazor.DragDrop +{ + public partial class Dropzone + { + private void OnDropItemOnSpacing(int newIndex) + { + if (!IsDropAllowed()) + { + DragDropService.Reset(); + return; + } + + var activeItem = DragDropService.ActiveItem; + var oldIndex = Items.IndexOf(activeItem); + var sameDropZone = false; + if (oldIndex == -1) // item not present in target dropzone + { + if (CopyItem == null) + { + DragDropService.Items.Remove(activeItem); + } + } + else // same dropzone drop + { + sameDropZone = true; + Items.RemoveAt(oldIndex); + // the actual index could have shifted due to the removal + if (newIndex > oldIndex) + newIndex--; + } + + if (CopyItem == null) + { + Items.Insert(newIndex, activeItem); + } + else + { + // for the same zone - do not call CopyItem + Items.Insert(newIndex, sameDropZone ? activeItem : CopyItem(activeItem)); + } + + //Operation is finished + DragDropService.Reset(); + OnItemDrop.InvokeAsync(activeItem); + } + + private bool IsMaxItemLimitReached() + { + var activeItem = DragDropService.ActiveItem; + return (!Items.Contains(activeItem) && MaxItems.HasValue && MaxItems == Items.Count()); + } + + private string IsItemDragable(TItem item) + { + if (AllowsDrag == null) + return "true"; + if (item == null) + return "false"; + return AllowsDrag(item).ToString(); + } + + private bool IsItemAccepted(TItem dragTargetItem) + { + if (Accepts == null) + return true; + return Accepts(DragDropService.ActiveItem, dragTargetItem); + } + + private bool IsValidItem() + { + return DragDropService.ActiveItem != null; + } + + protected override bool ShouldRender() + { + return DragDropService.ShouldRender; + } + + private void ForceRender(object sender, EventArgs e) + { + StateHasChanged(); + } + + protected override void OnInitialized() + { + DragDropService.StateHasChanged += ForceRender; + base.OnInitialized(); + } + + public string CheckIfDraggable(TItem item) + { + if (AllowsDrag == null) + return ""; + if (item == null) + return ""; + if (AllowsDrag(item)) + return ""; + return "plk-dd-noselect"; + } + + public string CheckIfDragOperationIsInProgess() + { + var activeItem = DragDropService.ActiveItem; + return activeItem == null ? "" : "plk-dd-inprogess"; + } + + public void OnDragEnd() + { + if (DragEnd != null) + { + DragEnd(DragDropService.ActiveItem); + } + + DragDropService.Reset(); + //dragTargetItem = default; + } + + public void OnDragEnter(TItem item) + { + var activeItem = DragDropService.ActiveItem; + if (item.Equals(activeItem)) + return; + if (!IsValidItem()) + return; + if (IsMaxItemLimitReached()) + return; + if (!IsItemAccepted(item)) + return; + DragDropService.DragTargetItem = item; + if (InstantReplace) + { + Swap(DragDropService.DragTargetItem, activeItem); + } + + DragDropService.ShouldRender = true; + StateHasChanged(); + DragDropService.ShouldRender = false; + } + + public void OnDragLeave() + { + DragDropService.DragTargetItem = default; + DragDropService.ShouldRender = true; + StateHasChanged(); + DragDropService.ShouldRender = false; + } + + public void OnDragStart(TItem item) + { + DragDropService.ShouldRender = true; + DragDropService.ActiveItem = item; + DragDropService.Items = Items; + StateHasChanged(); + DragDropService.ShouldRender = false; + } + + public string CheckIfItemIsInTransit(TItem item) + { + return item.Equals(DragDropService.ActiveItem) ? "plk-dd-in-transit no-pointer-events" : ""; + } + + public string CheckIfItemIsDragTarget(TItem item) + { + if (item.Equals(DragDropService.ActiveItem)) + return ""; + if (item.Equals(DragDropService.DragTargetItem)) + { + return IsItemAccepted(DragDropService.DragTargetItem) ? "plk-dd-dragged-over" : "plk-dd-dragged-over-denied"; + } + + return ""; + } + + private string GetClassesForDraggable(TItem item) + { + var builder = new StringBuilder(); + builder.Append("plk-dd-draggable"); + if (ItemWrapperClass != null) + { + var itemWrapperClass = ItemWrapperClass(item); + builder.AppendLine(" " + itemWrapperClass); + } + + return builder.ToString(); + } + + private string GetClassesForDropzone() + { + var builder = new StringBuilder(); + builder.Append("plk-dd-dropzone"); + if (!String.IsNullOrEmpty(Class)) + { + builder.AppendLine(" " + Class); + } + + return builder.ToString(); + } + + private string GetClassesForSpacing(int spacerId) + { + var builder = new StringBuilder(); + builder.Append("plk-dd-spacing"); + //if active space id and item is from another dropzone -> always create insert space + if (DragDropService.ActiveSpacerId == spacerId && Items.IndexOf(DragDropService.ActiveItem) == -1) + { + builder.Append(" plk-dd-spacing-dragged-over"); + } // else -> check if active space id and that it is an item that needs space + else if (DragDropService.ActiveSpacerId == spacerId && (spacerId != Items.IndexOf(DragDropService.ActiveItem)) && (spacerId != Items.IndexOf(DragDropService.ActiveItem) + 1)) + { + builder.Append(" plk-dd-spacing-dragged-over"); + } + + return builder.ToString(); + } + + /// + /// Allows to pass a delegate which executes if something is dropped and decides if the item is accepted + /// + [Parameter] + public Func Accepts { get; set; } + + /// + /// Allows to pass a delegate which executes if something is dropped and decides if the item is accepted + /// + [Parameter] + public Func AllowsDrag { get; set; } + + /// + /// Allows to pass a delegate which executes if a drag operation ends + /// + [Parameter] + public Action DragEnd { get; set; } + + /// + /// Raises a callback with the dropped item as parameter in case the item can not be dropped due to the given Accept Delegate + /// + [Parameter] + public EventCallback OnItemDropRejected { get; set; } + + /// + /// Raises a callback with the dropped item as parameter + /// + [Parameter] + public EventCallback OnItemDrop { get; set; } + + /// + /// Raises a callback with the replaced item as parameter + /// + [Parameter] + public EventCallback OnReplacedItemDrop { get; set; } + + /// + /// If set to true, items will we be swapped/inserted instantly. + /// + [Parameter] + public bool InstantReplace { get; set; } + + /// + /// List of items for the dropzone + /// + [Parameter] + public IList Items { get; set; } + + /// + /// Maximum Number of items which can be dropped in this dropzone. Defaults to null which means unlimited. + /// + [Parameter] + public int? MaxItems { get; set; } + + /// + /// Raises a callback with the dropped item as parameter in case the item can not be dropped due to item limit. + /// + [Parameter] + public EventCallback OnItemDropRejectedByMaxItemLimit { get; set; } + + [Parameter] + public RenderFragment ChildContent { get; set; } + + /// + /// Specifies one or more classnames for the Dropzone element. + /// + [Parameter] + public string Class { get; set; } + + /// + /// Specifies the id for the Dropzone element. + /// + [Parameter] + public string Id { get; set; } + + /// + /// Allows to pass a delegate which specifies one or more classnames for the draggable div that wraps your elements. + /// + [Parameter] + public Func ItemWrapperClass { get; set; } + + /// + /// If set items dropped are copied to this dropzone and are not removed from their source. + /// + [Parameter] + public Func CopyItem { get; set; } + + private bool IsDropAllowed() + { + var activeItem = DragDropService.ActiveItem; + if (!IsValidItem()) + { + return false; + } + + if (IsMaxItemLimitReached()) + { + OnItemDropRejectedByMaxItemLimit.InvokeAsync(activeItem); + return false; + } + + if (!IsItemAccepted(DragDropService.DragTargetItem)) + { + OnItemDropRejected.InvokeAsync(activeItem); + return false; + } + + return true; + } + + private void OnDrop() + { + DragDropService.ShouldRender = true; + if (!IsDropAllowed()) + { + DragDropService.Reset(); + return; + } + + var activeItem = DragDropService.ActiveItem; + if (DragDropService.DragTargetItem == null) //no direct drag target + { + if (!Items.Contains(activeItem)) //if dragged to another dropzone + { + if (CopyItem == null) + { + Items.Insert(Items.Count, activeItem); //insert item to new zone + DragDropService.Items.Remove(activeItem); //remove from old zone + } + else + { + Items.Insert(Items.Count, CopyItem(activeItem)); //insert item to new zone + } + } + else + { + //what to do here? + } + } + else // we have a direct target + { + if (!Items.Contains(activeItem)) // if dragged to another dropzone + { + if (CopyItem == null) + { + if (!InstantReplace) + { + Swap(DragDropService.DragTargetItem, activeItem); //swap target with active item + } + } + else + { + if (!InstantReplace) + { + Swap(DragDropService.DragTargetItem, CopyItem(activeItem)); //swap target with a copy of active item + } + } + } + else + { + // if dragged to the same dropzone + if (!InstantReplace) + { + Swap(DragDropService.DragTargetItem, activeItem); //swap target with active item + } + } + } + + DragDropService.Reset(); + StateHasChanged(); + OnItemDrop.InvokeAsync(activeItem); + } + + private void Swap(TItem draggedOverItem, TItem activeItem) + { + var indexDraggedOverItem = Items.IndexOf(draggedOverItem); + var indexActiveItem = Items.IndexOf(activeItem); + if (indexActiveItem == -1) // item is new to the dropzone + { + //insert into new zone + Items.Insert(indexDraggedOverItem + 1, activeItem); + //remove from old zone + DragDropService.Items.Remove(activeItem); + } + else if (InstantReplace) //swap the items + { + if (indexDraggedOverItem == indexActiveItem) + return; + TItem tmp = Items[indexDraggedOverItem]; + Items[indexDraggedOverItem] = Items[indexActiveItem]; + Items[indexActiveItem] = tmp; + OnReplacedItemDrop.InvokeAsync(Items[indexActiveItem]); + } + else //no instant replace, just insert it after + { + if (indexDraggedOverItem == indexActiveItem) + return; + var tmp = Items[indexActiveItem]; + Items.RemoveAt(indexActiveItem); + Items.Insert(indexDraggedOverItem, tmp); + } + } + + public void Dispose() + { + DragDropService.StateHasChanged -= ForceRender; + } + } +} \ No newline at end of file diff --git a/Plk.Blazor.DragDrop/Plk.Blazor.DragDrop.csproj b/Plk.Blazor.DragDrop/Plk.Blazor.DragDrop.csproj index 3da9018..33984a7 100644 --- a/Plk.Blazor.DragDrop/Plk.Blazor.DragDrop.csproj +++ b/Plk.Blazor.DragDrop/Plk.Blazor.DragDrop.csproj @@ -1,9 +1,9 @@  - netstandard2.1 + net5.0 3.0 - 2.2.2 + 2.3.0 blazor-dragdrop Postlagerkarte Blazor Drag Drop Library