Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FileInput] Fix uploading the same file twice by drag&drop #2865

Merged
merged 8 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6337,6 +6337,11 @@
Gets or sets a value indicating whether the element is checked.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentMenuItem.KeepOpen">
<summary>
Gets or sets a value indicates whether the FluentMenu should remain open after an action.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentMenuItem.ChildContent">
<summary>
Gets or sets the content to be rendered inside the component.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Accept="image/*"
@bind-ProgressPercent="@ProgressPercent"
OnCompleted="@OnCompletedAsync"
Style="height: 300px; border: 1px dashed var(--accent-fill-rest);">
Style="height: 300px;">
<ChildContent>
<label for="my-file-uploader">
<FluentIcon Value="@(new @Icons.Regular.Size24.ArrowUpload())" />
Expand Down
16 changes: 5 additions & 11 deletions src/Core/Components/InputFile/FluentInputFile.razor
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,12 @@
@using Microsoft.AspNetCore.Components.Forms
@inherits FluentComponentBase

<div class="@ClassValue"
<div class="@ClassValue"
style="@StyleValue"
drop-files="@DropOver"
disabled="@Disabled"
@ondragenter="@(e => DropOver = true)"
@ondragenter:stopPropagation
@ondragover="@(e => DropOver = true)"
@ondragover:stopPropagation
@ondragleave="@(e => DropOver = false)"
@ondragleave:stopPropagation
@ondragend="@(e => DropOver = false)">
@ref="@_containerElement">

<div class="inputfile-content" style="z-index: @(DropOver ? null : 999)">
<div class="inputfile-content">

@ChildContent

Expand All @@ -31,8 +24,9 @@
</div>
</div>

<div style="grid-column: 1; grid-row: 1; @(DropOver ? $"z-index: {ZIndex.InputFileDropZone}" : null)">
<div style="grid-column: 1; grid-row: 1; ">
<InputFile OnChange="OnUploadFilesHandlerAsync"
@ref="@_inputFile"
id="@Id"
multiple=@Multiple
accept="@Accept"
Expand Down
32 changes: 27 additions & 5 deletions src/Core/Components/InputFile/FluentInputFile.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
namespace Microsoft.FluentUI.AspNetCore.Components;

/// <summary />
public partial class FluentInputFile : FluentComponentBase
public partial class FluentInputFile : FluentComponentBase, IAsyncDisposable
{
private ElementReference? _containerElement;
private InputFile? _inputFile;
private IJSObjectReference? _containerInstance;

public static string ResourceLoadingBefore = "Loading...";
public static string ResourceLoadingCompleted = "Completed";
public static string ResourceLoadingCanceled = "Canceled";
Expand Down Expand Up @@ -193,11 +197,16 @@ public async Task ShowFilesDialogAsync()
/// <summary />
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && !string.IsNullOrEmpty(AnchorId))
if (firstRender)
{
Module ??= await JSRuntime.InvokeAsync<IJSObjectReference>("import", JAVASCRIPT_FILE.FormatCollocatedUrl(LibraryConfiguration));

await Module.InvokeVoidAsync("attachClickHandler", AnchorId, Id);
if (!string.IsNullOrEmpty(AnchorId))
{
await Module.InvokeVoidAsync("attachClickHandler", AnchorId, Id);
}

_containerInstance = await Module.InvokeAsync<IJSObjectReference>("initializeFileDropZone", _containerElement, _inputFile!.Element);
}
}

Expand All @@ -209,8 +218,6 @@ protected async Task OnUploadFilesHandlerAsync(InputFileChangeEventArgs e)
throw new ApplicationException($"The maximum number of files accepted is {MaximumFileCount}, but {e.FileCount} were supplied.");
}

DropOver = false;

// Use the native Blazor event
if (OnInputFileChange.HasDelegate)
{
Expand Down Expand Up @@ -405,4 +412,19 @@ private async Task UpdateProgressAsync(int percent, string title)
ProgressTitle = title;
}
}

// Unregister the drop zone events
public async ValueTask DisposeAsync()
{
if (_containerInstance != null)
{
await _containerInstance.InvokeVoidAsync("dispose");
await _containerInstance.DisposeAsync();
}

if (Module != null)
{
await Module.DisposeAsync();
}
}
}
4 changes: 3 additions & 1 deletion src/Core/Components/InputFile/FluentInputFile.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
display: grid;
grid-gap: 10px;
background-color: var(--neutral-fill-hover);
border: 1px dashed var(--accent-fill-rest);
}

.fluent-inputfile-container[drop-files] {
border: 2px dashed var(--accent-foreground-focus);
border: 1px solid var(--accent-fill-rest);
}

.fluent-inputfile-container .inputfile-content {
grid-column: 1;
grid-row: 1;
Expand Down
50 changes: 49 additions & 1 deletion src/Core/Components/InputFile/FluentInputFile.razor.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export function raiseFluentInputFile(fileInputId) {
export function raiseFluentInputFile(fileInputId) {
var item = document.getElementById(fileInputId);
if (!!item) {
item.click();
Expand All @@ -21,3 +21,51 @@ export function previewImage(inputElem, index, imgElem) {
imgElem.src = url;
imgElem.alt = inputElem.files[index].name;
}

export function initializeFileDropZone(containerElement, inputFile) {
function onDragHover(e) {
e.preventDefault();
containerElement.setAttribute("drop-files", "true");
}

function onDragLeave(e) {
e.preventDefault();
containerElement.removeAttribute("drop-files");
}

// Handle the paste and drop events
function onDrop(e) {
e.preventDefault();
containerElement.removeAttribute("drop-files");

// Set the files property of the input element and raise the change event
inputFile.files = e.dataTransfer.files;
const event = new Event('change', { bubbles: true });
inputFile.dispatchEvent(event);
}

function onPaste(e) {
// Set the files property of the input element and raise the change event
inputFile.files = e.clipboardData.files;
const event = new Event('change', { bubbles: true });
inputFile.dispatchEvent(event);
}

// Register all events
containerElement.addEventListener("dragenter", onDragHover);
containerElement.addEventListener("dragover", onDragHover);
containerElement.addEventListener("dragleave", onDragLeave);
containerElement.addEventListener("drop", onDrop);
containerElement.addEventListener('paste', onPaste);

// The returned object allows to unregister the events when the Blazor component is destroyed
return {
dispose: () => {
containerElement.removeEventListener('dragenter', onDragHover);
containerElement.removeEventListener('dragover', onDragHover);
containerElement.removeEventListener('dragleave', onDragLeave);
containerElement.removeEventListener("drop", onDrop);
containerElement.removeEventListener('paste', onPaste);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

<div class="fluent-inputfile-container" blazor:ondragenter="1" blazor:ondragenter:stoppropagation="" blazor:ondragover="2" blazor:ondragover:stoppropagation="" blazor:ondragleave="3" blazor:ondragleave:stoppropagation="" blazor:ondragend="4" b-72uj7bp8pi="">
<div class="inputfile-content" style="z-index: 999" b-72uj7bp8pi="">
<div class="inputfile-content" b-72uj7bp8pi="">
Sample description
<div class="inputfile-progress" style="visibility: hidden;" b-72uj7bp8pi="">
<fluent-progress min="0" max="100" value="0" blazor:elementreference="xxx"></fluent-progress>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

<div class="fluent-inputfile-container" disabled="" blazor:ondragenter="1" blazor:ondragenter:stoppropagation="" blazor:ondragover="2" blazor:ondragover:stoppropagation="" blazor:ondragleave="3" blazor:ondragleave:stoppropagation="" blazor:ondragend="4" b-72uj7bp8pi="">
<div class="inputfile-content" style="z-index: 999" b-72uj7bp8pi="">
<div class="inputfile-content" b-72uj7bp8pi="">
Sample description
<div class="inputfile-progress" style="visibility: hidden;" b-72uj7bp8pi="">
<fluent-progress min="0" max="100" value="0" blazor:elementreference="xxx"></fluent-progress>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

<div class="fluent-inputfile-container" blazor:ondragenter="1" blazor:ondragenter:stoppropagation="" blazor:ondragover="2" blazor:ondragover:stoppropagation="" blazor:ondragleave="3" blazor:ondragleave:stoppropagation="" blazor:ondragend="4" b-72uj7bp8pi="">
<div class="inputfile-content" style="z-index: 999" b-72uj7bp8pi="">Sample description
<div class="inputfile-content" b-72uj7bp8pi="">Sample description
<div class="inputfile-progress" style="" b-72uj7bp8pi="">ProgressFileDetails { Index = 0, Name = , Percentage = 0 }</div>
</div>
<div style="grid-column: 1; grid-row: 1; " b-72uj7bp8pi="">
<input id="xxx" accept="" type="file" blazor:elementreference="xxx">
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@

<div class="fluent-inputfile-container" blazor:ondragenter="1" blazor:ondragenter:stoppropagation="" blazor:ondragover="2" blazor:ondragover:stoppropagation="" blazor:ondragleave="3" blazor:ondragleave:stoppropagation="" blazor:ondragend="4" b-72uj7bp8pi="">
<div class="inputfile-content" style="z-index: 999" b-72uj7bp8pi="">Sample description
<div class="inputfile-content" b-72uj7bp8pi="">Sample description
<div class="inputfile-progress" style="visibility: visible;" b-72uj7bp8pi="">
<fluent-progress min="0" max="100" value="100" blazor:elementreference=""></fluent-progress>
<br b-72uj7bp8pi="">Completed</div>
</div>
<div style="grid-column: 1; grid-row: 1; " b-72uj7bp8pi="">
<input id="xxx" multiple="" accept="image/*" type="file" blazor:elementreference="">
</div>
</div>
</div>
1 change: 1 addition & 0 deletions tests/Core/InputFile/FluentInputFileTests.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
{
public FluentInputFileTests()
{
JSInterop.Mode = JSRuntimeMode.Loose;
Services.AddSingleton(LibraryConfiguration.ForUnitTests);
}

Expand Down
Loading