Skip to content

Commit

Permalink
#85 Add posibility to cancel dialog closing on close X and backdrop c…
Browse files Browse the repository at this point in the history
…lick
  • Loading branch information
fgilde committed Jun 28, 2024
1 parent 437c983 commit 9dc6ea8
Show file tree
Hide file tree
Showing 17 changed files with 235 additions and 58 deletions.
5 changes: 5 additions & 0 deletions MudBlazor.Extensions/Core/IDialogEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public class DialogClosedEvent : DialogBeforeOpenEvent
public DialogResult Result { get; set; }
}

public class DialogClosingEvent : BaseDialogEvent
{
public bool? Cancel { get; set; }
}

public class DialogDragEndEvent : BaseDialogEvent { }
public class DialogDragStartEvent : BaseDialogEvent { }
public class DialogDraggingEvent : BaseDialogEvent { }
Expand Down
2 changes: 1 addition & 1 deletion MudBlazor.Extensions/Core/IDialogEventService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ public interface IDialogEventService
/// <summary>
/// Publish a dialog event
/// </summary>
public Task Publish<TEvent>(TEvent eventToPublish) where TEvent : IDialogEvent;
public Task<TEvent> Publish<TEvent>(TEvent eventToPublish) where TEvent : IDialogEvent;
}
2 changes: 1 addition & 1 deletion MudBlazor.Extensions/MudBlazor.Extensions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
<PackageReference Include="MudBlazor.Markdown" Version="1.0.2" />
<PackageReference Include="Nextended.Blazor" Version="7.0.38" />
<PackageReference Include="Nextended.Core" Version="7.0.54" />
<PackageReference Include="BlazorJS" Version="2.1.5" />
<PackageReference Include="BlazorJS" Version="2.1.6" />
<PackageReference Include="OneOf" Version="3.0.271" />
<PackageReference Include="Blazored.FluentValidation" Version="2.2.0" />
<PackageReference Include="BuildBundlerMinifier" Version="3.2.449" />
Expand Down
13 changes: 13 additions & 0 deletions MudBlazor.Extensions/Options/DialogOptionsEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,19 @@ public DialogOptionsEx SetAsDefaultDialogOptions()
/// </summary>
public MudDialogButton[] Buttons { get; set; }

/// <summary>
/// Here you can set a callback that will be called before the dialog is closed.
/// Ensure your callback returns a boolean value and has the JsInvokable attribute set.
/// </summary>
public string CanCloseCallbackName { get; set; }

/// <summary>
/// the .NET object reference where the <see cref="CanCloseCallbackName"/> is located.
/// if you don't specify reference the dialog itself will be the reference.Then you need to have the CanCloseCallback Method on your DialogClass
/// </summary>
public DotNetObjectReference<object> CanCloseCallbackReference { get; set; }


/// <summary>
/// A MudDialogDragMode value indicating the drag mode of the dialog box.
/// </summary>
Expand Down
6 changes: 3 additions & 3 deletions MudBlazor.Extensions/Services/DialogEventService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ public void Unsubscribe<TEvent>(Func<TEvent, Task> handler) where TEvent : IDial
/// <summary>
/// Publish a dialog event
/// </summary>
public Task Publish<TEvent>(TEvent eventToPublish) where TEvent : IDialogEvent
public async Task<TEvent> Publish<TEvent>(TEvent eventToPublish) where TEvent : IDialogEvent
{
if (eventHandlers.TryGetValue(typeof(TEvent), out var handlers))
{
var tasks = handlers.Cast<Func<TEvent, Task>>().Select(handler => handler(eventToPublish));
return Task.WhenAll(tasks);
await Task.WhenAll(tasks);
}
return Task.CompletedTask;
return eventToPublish;
}
}
7 changes: 4 additions & 3 deletions MudBlazor.Extensions/Services/MudExDialogService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class MudExDialogService : IMudExDialogService
private readonly IDialogEventService _dialogEventService;

[JSInvokable]
public Task PublishEvent(string eventName, string dialogId, DotNetObjectReference<ComponentBase> dialog, BoundingClientRect rect)
public async Task<object> PublishEvent(string eventName, string dialogId, DotNetObjectReference<ComponentBase> dialog, BoundingClientRect rect)
{
dynamic eventToPublish = eventName switch
{
Expand All @@ -24,15 +24,16 @@ public Task PublishEvent(string eventName, string dialogId, DotNetObjectReferenc
"OnDragging" => new DialogDraggingEvent { Dialog = dialog.Value, Rect = rect, DialogId = dialogId },
"OnResizing" => new DialogResizingEvent { Dialog = dialog.Value, Rect = rect, DialogId = dialogId },
"OnResized" => new DialogResizedEvent { Dialog = dialog.Value, Rect = rect, DialogId = dialogId },
"OnDialogClosing" => new DialogClosingEvent { Dialog = dialog.Value, Rect = rect, DialogId = dialogId },
_ => null
};

if (eventToPublish != null)
{
return PublishDynamic(eventToPublish);
return await PublishDynamic(eventToPublish);
}

return Task.CompletedTask;
return null;
}

private Task PublishDynamic<TEvent>(TEvent eventToPublish) where TEvent : IDialogEvent
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions MudBlazor.Extensions/wwwroot/docs/MudBlazor.Extensions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20189,6 +20189,17 @@
An array of MudDialogButton.
</summary>
</member>
<member name="P:MudBlazor.Extensions.Options.DialogOptionsEx.CanCloseCallbackName">
<summary>
Here you can set a callback that will be called before the dialog is closed.
Ensure your callback returns a boolean value and has the JsInvokable attribute set.
</summary>
</member>
<member name="P:MudBlazor.Extensions.Options.DialogOptionsEx.CanCloseCallbackReference">
<summary>
the .NET object reference where the <see cref="P:MudBlazor.Extensions.Options.DialogOptionsEx.CanCloseCallbackName"/> is located.
</summary>
</member>
<member name="P:MudBlazor.Extensions.Options.DialogOptionsEx.DragMode">
<summary>
A MudDialogDragMode value indicating the drag mode of the dialog box.
Expand Down
75 changes: 54 additions & 21 deletions MudBlazor.Extensions/wwwroot/js/mudBlazorExtensions.all.js
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ class MudExEventHelper {
static stopFor(e, element, milliseconds) {
if (e === undefined || e === null)
return;
e.__internalDispatched = true;
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
Expand Down Expand Up @@ -818,7 +819,7 @@ class MudExDialogHandlerBase {

order = 99;

raiseDialogEvent(eventName) {
async raiseDialogEvent(eventName) {
// Get viewport dimensions
var windowHeight = window.innerHeight || document.documentElement.clientHeight;
var windowWidth = window.innerWidth || document.documentElement.clientWidth;
Expand All @@ -835,7 +836,7 @@ class MudExDialogHandlerBase {
scrollY: scrollY
};
const rect = Object.assign(extendedRect, JSON.parse(JSON.stringify(this.dialog.getBoundingClientRect())));
this.dotNetService.invokeMethodAsync('PublishEvent', eventName, this.dialog.id, this.dotNet, rect);
return await this.dotNetService.invokeMethodAsync('PublishEvent', eventName, this.dialog.id, this.dotNet, rect);
}

getAnimationDuration() {
Expand Down Expand Up @@ -929,36 +930,68 @@ class MudExDialogAnimationHandler extends MudExDialogHandlerBase {
if (this.options.animations != null && Array.isArray(this.options.animations) && this.options.animations.length) {
this.animate();
}
if (this.options.animateClose) {
this.extendCloseEvents();
}

this.extendCloseEvents();

}

async checkCanClose() {
const callbackName = this.options.canCloseCallbackName;
const reference = this.options.canCloseCallbackReference || this.dotNet;
if (callbackName && reference) {
try {
const result = await reference.invokeMethodAsync(callbackName);
if (result === false) {
return false;
}
} catch (e) {
console.error(e);
}
}
const closeEvent = await this.raiseDialogEvent('OnDialogClosing');
if (closeEvent?.cancel === true) {
return false;
}
return true;
}


extendCloseEvents() {
var closeButton = this.dialog.querySelector('.mud-button-close');
//this.dialogOverlay
if (this.dialogOverlay && this.options.modal && !this.options.disableBackdropClick) {
const handleClick = (e) => {
this.closeAnimation();
this.dialogOverlay.removeEventListener('click', handleClick);
MudExEventHelper.stopFor(e, this.dialogOverlay, this.options.animationDurationInMs);
const handleCloseEvent = (element) => {
const handleClick = async (e) => {
if (!e.__internalDispatched) {
e.__internalDispatched = true;
e.preventDefault();
e.stopPropagation();
const canClose = await this.checkCanClose();
if (canClose) {
setTimeout(() => {
element.dispatchEvent(e);
}, 1);
}
return;
}

if (this.options.animateClose) {
this.closeAnimation();
element.removeEventListener('click', handleClick);
MudExEventHelper.stopFor(e, element, this.options.animationDurationInMs);
}
};
element.addEventListener('click', handleClick);
};

this.dialogOverlay.addEventListener('click', handleClick);
}
const closeButton = this.dialog.querySelector('.mud-button-close');
if (closeButton) {

const handleClick = (e) => {
this.closeAnimation();
closeButton.removeEventListener('click', handleClick);
MudExEventHelper.stopFor(e, closeButton, this.options.animationDurationInMs);
};
handleCloseEvent(closeButton);
}

closeButton.addEventListener('click', handleClick);
if (this.dialogOverlay && this.options.modal && !this.options.disableBackdropClick) {
handleCloseEvent(this.dialogOverlay);
}
}


animate() {
this.dialog.style.animation = `${this.options.animationStyle}`;
}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

order = 99;

raiseDialogEvent(eventName) {
async raiseDialogEvent(eventName) {
// Get viewport dimensions
var windowHeight = window.innerHeight || document.documentElement.clientHeight;
var windowWidth = window.innerWidth || document.documentElement.clientWidth;
Expand All @@ -31,7 +31,7 @@
scrollY: scrollY
};
const rect = Object.assign(extendedRect, JSON.parse(JSON.stringify(this.dialog.getBoundingClientRect())));
this.dotNetService.invokeMethodAsync('PublishEvent', eventName, this.dialog.id, this.dotNet, rect);
return await this.dotNetService.invokeMethodAsync('PublishEvent', eventName, this.dialog.id, this.dotNet, rect);
}

getAnimationDuration() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,68 @@
if (this.options.animations != null && Array.isArray(this.options.animations) && this.options.animations.length) {
this.animate();
}
if (this.options.animateClose) {
this.extendCloseEvents();
}

this.extendCloseEvents();

}

async checkCanClose() {
const callbackName = this.options.canCloseCallbackName;
const reference = this.options.canCloseCallbackReference || this.dotNet;
if (callbackName && reference) {
try {
const result = await reference.invokeMethodAsync(callbackName);
if (result === false) {
return false;
}
} catch (e) {
console.error(e);
}
}
const closeEvent = await this.raiseDialogEvent('OnDialogClosing');
if (closeEvent?.cancel === true) {
return false;
}
return true;
}


extendCloseEvents() {
var closeButton = this.dialog.querySelector('.mud-button-close');
//this.dialogOverlay
if (this.dialogOverlay && this.options.modal && !this.options.disableBackdropClick) {
const handleClick = (e) => {
this.closeAnimation();
this.dialogOverlay.removeEventListener('click', handleClick);
MudExEventHelper.stopFor(e, this.dialogOverlay, this.options.animationDurationInMs);
const handleCloseEvent = (element) => {
const handleClick = async (e) => {
if (!e.__internalDispatched) {
e.__internalDispatched = true;
e.preventDefault();
e.stopPropagation();
const canClose = await this.checkCanClose();
if (canClose) {
setTimeout(() => {
element.dispatchEvent(e);
}, 1);
}
return;
}

if (this.options.animateClose) {
this.closeAnimation();
element.removeEventListener('click', handleClick);
MudExEventHelper.stopFor(e, element, this.options.animationDurationInMs);
}
};
element.addEventListener('click', handleClick);
};

this.dialogOverlay.addEventListener('click', handleClick);
}
const closeButton = this.dialog.querySelector('.mud-button-close');
if (closeButton) {

const handleClick = (e) => {
this.closeAnimation();
closeButton.removeEventListener('click', handleClick);
MudExEventHelper.stopFor(e, closeButton, this.options.animationDurationInMs);
};
handleCloseEvent(closeButton);
}

closeButton.addEventListener('click', handleClick);
if (this.dialogOverlay && this.options.modal && !this.options.disableBackdropClick) {
handleCloseEvent(this.dialogOverlay);
}
}


animate() {
this.dialog.style.animation = `${this.options.animationStyle}`;
}
Expand Down
1 change: 1 addition & 0 deletions MudBlazor.Extensions/wwwroot/js/utils/eventHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
static stopFor(e, element, milliseconds) {
if (e === undefined || e === null)
return;
e.__internalDispatched = true;
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
Expand Down
Loading

0 comments on commit 9dc6ea8

Please sign in to comment.