using System;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;
namespace AntDesign
{
public partial class Dialog
{
private const string IdPrefix = "Ant-Design-";
[Parameter]
public DialogOptions Config { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public bool Visible { get; set; }
private string _maskAnimation = "";
private string _modalAnimation = "";
private string _maskHideClsName = "";
private bool _hasShow;
private bool _hasDestroy = true;
private string _wrapStyle = "";
private bool _disableBodyScroll;
private bool _doDragable = false;
///
/// dialog root container
///
private ElementReference _element;
private ElementReference _dialogHeader;
private ElementReference _modal;
private bool _isFirstRender = true;
#region ant-modal style
private string _modalStyle = null;
///
/// ant-modal style
///
///
private string GetStyle()
{
if (_modalStyle == null)
{
var style = $"{Config.GetWidth()};";
if (Config.Draggable)
{
string left = $"margin: 0; padding-bottom:0;";
style += left;
}
_modalStyle = style;
}
if (!string.IsNullOrWhiteSpace(Style))
{
return _modalStyle + Style + ";";
}
return _modalStyle;
}
///
/// if Modal is draggable, reset the position style similar with the first show
///
internal async Task TryResetModalStyle()
{
if (Config.Draggable)
{
await JsInvokeAsync(JSInteropConstants.ResetModalPosition, _dialogHeader);
}
}
#endregion
///
/// append To body
///
///
private async Task AppendToContainer()
{
await JsInvokeAsync(JSInteropConstants.AddElementTo, _element, Config.GetContainer);
}
#region mask and dialog click event
///
/// check is dialog click
///
private bool _dialogMouseDown = false;
private void OnDialogMouseDown()
{
_dialogMouseDown = true;
}
private async Task OnMaskClick(MouseEventArgs e)
{
if (Config.MaskClosable
&& !_dialogMouseDown)
{
await CloseAsync();
}
_dialogMouseDown = false;
}
#endregion
#region keyboard control
///
/// TAB keyboard control
///
private readonly string _sentinelStart = IdPrefix + Guid.NewGuid().ToString();
private readonly string _sentinelEnd = IdPrefix + Guid.NewGuid().ToString();
public string SentinelStart => _sentinelStart;
private async Task OnKeyDown(KeyboardEventArgs e)
{
if (Config.Keyboard && e.Key == "Escape")
{
await CloseAsync();
return;
}
if (Visible)
{
if (e.Key == "Tab")
{
var activeElement = await JsInvokeAsync(JSInteropConstants.GetActiveElement, _sentinelEnd);
if (e.ShiftKey)
{
if (activeElement == _sentinelStart)
{
await JsInvokeAsync(JSInteropConstants.Focus, "#" + _sentinelEnd);
}
}
else if (activeElement == _sentinelEnd)
{
await JsInvokeAsync(JSInteropConstants.Focus, "#" + _sentinelStart);
}
}
}
}
#endregion
private async Task OnCloserClick(MouseEventArgs e)
{
await CloseAsync();
}
private async Task CloseAsync()
{
if (_hasDestroy)
{
return;
}
if (Config.OnCancel != null)
{
await Config.OnCancel.Invoke(null);
}
}
#region control show and hide class name and style
private async Task Show()
{
if (_hasShow)
{
return;
}
if (Visible)
{
if (Config.Draggable)
{
_wrapStyle = "display:flex;justify-content: center;";
if (Config.Centered)
{
_wrapStyle += "align-items: center;";
}
else
{
_wrapStyle += "align-items: flex-start;";
}
}
else
{
_wrapStyle = "";
}
_maskHideClsName = "";
_maskAnimation = ModalAnimation.MaskEnter;
_modalAnimation = ModalAnimation.ModalEnter;
// wait for animation, "antZoomIn" animation take 0.3s
// see: @animation-duration-slow: 0.3s;
await Task.Delay(300);
_hasShow = true;
StateHasChanged();
}
}
public async Task Hide()
{
if (!_hasShow)
{
return;
}
if (!Visible)
{
_maskAnimation = ModalAnimation.MaskLeave;
_modalAnimation = ModalAnimation.ModalLeave;
await Task.Delay(200);
_wrapStyle = "display: none;";
_maskHideClsName = "ant-modal-mask-hidden";
_hasShow = false;
StateHasChanged();
if (Config.OnClosed != null)
{
await Config.OnClosed.Invoke();
}
}
}
public bool IsShow()
{
return _hasShow;
}
#endregion
private string GetMaskClsName()
{
string clsName = _maskHideClsName;
clsName += _maskAnimation;
return clsName;
}
private string GetModalClsName()
{
string clsName = Config.ClassName;
return clsName + _modalAnimation;
}
#region override
protected override async Task OnParametersSetAsync()
{
//Reduce one rendering when showing and not destroyed
if (Visible)
{
if (!_hasDestroy)
{
await Show();
}
else
{
_wrapStyle = "display: none;";
_maskHideClsName = "ant-modal-mask-hidden";
}
}
else
{
await Hide();
}
await base.OnParametersSetAsync();
}
protected override async Task OnAfterRenderAsync(bool isFirst)
{
_isFirstRender = isFirst;
if (Visible)
{
if (_hasDestroy)
{
await AppendToContainer();
_hasDestroy = false;
Show();
StateHasChanged();
}
if (!_disableBodyScroll)
{
_disableBodyScroll = true;
await JsInvokeAsync(JSInteropConstants.DisableBodyScroll);
}
if (Config.Draggable && !_doDragable)
{
_doDragable = true;
await JsInvokeAsync(JSInteropConstants.EnableDraggable, _dialogHeader, _modal, Config.DragInViewport);
}
}
else
{
if (_disableBodyScroll)
{
_disableBodyScroll = false;
await Task.Delay(250);
await JsInvokeAsync(JSInteropConstants.EnableBodyScroll);
}
if (Config.Draggable && _doDragable)
{
_doDragable = false;
await JsInvokeAsync(JSInteropConstants.DisableDraggable, _dialogHeader);
}
}
await base.OnAfterRenderAsync(isFirst);
}
#endregion
}
}