Skip to content

Commit

Permalink
[FileInput] Fix uploading the same file twice by drag&drop (#2865)
Browse files Browse the repository at this point in the history
* Fix #2849 by making the component more robust

* Fix tests

* Fix z-index for content part

* Fix tests, remove superfluous space

* Disable paste functionality for now
  • Loading branch information
vnbaaij authored Oct 28, 2024
1 parent 91e9639 commit 3114af3
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 35 deletions.
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
14 changes: 4 additions & 10 deletions src/Core/Components/InputFile/FluentInputFile.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,10 @@

<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" style="@($"z-index: {ZIndex.InputFileDropZone + 1}")">

@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
51 changes: 50 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,52 @@ 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);
}

// We'll implement this later
//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,12 +1,12 @@

<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-progress" style="visibility: hidden;" b-72uj7bp8pi="">
<fluent-progress min="0" max="100" value="0" blazor:elementreference="xxx"></fluent-progress>
<br b-72uj7bp8pi="">
<div class="inputfile-content" style="z-index: 991" 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>
<br b-72uj7bp8pi="">
</div>
</div>
</div>
<div style="grid-column: 1; grid-row: 1; " b-72uj7bp8pi="">
<input id="xxx" multiple="" accept="image/*" type="file" blazor:elementreference="xxx">
</div>
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" style="z-index: 991" 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,10 @@

<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-progress" style="" b-72uj7bp8pi="">ProgressFileDetails { Index = 0, Name = , Percentage = 0 }</div>
</div>
<div class="inputfile-content" style="z-index: 991" 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,13 @@

<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-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 class="inputfile-content" style="z-index: 991" 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

0 comments on commit 3114af3

Please sign in to comment.