You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Components/Utilities/MaskAlgorithms/MultiMask.cs

101 lines
3.1 KiB

2 years ago
// Copyright (c) MudBlazor 2021
// MudBlazor licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Connected
{
public record struct MaskOption(string Id, string Mask, string Regex);
public class MultiMask : PatternMask
{
public MultiMask(string defaultMask, params MaskOption[] options) : base(defaultMask)
{
_defaultMask = defaultMask;
_options = options ?? new MaskOption[0];
}
private string _defaultMask;
private MaskOption[] _options;
public Action<MaskOption?, string> OptionDetected { get; set; }
public MaskOption? DetectedOption { get; private set; } = null;
public override void Insert(string input)
{
DoCheckAndRedo(() => base.Insert(input));
}
public override void Delete()
{
DoCheckAndRedo(base.Delete);
}
public override void Backspace()
{
DoCheckAndRedo(base.Backspace);
}
/// <summary>
/// This is a nifty trick to avoid writing three times the same code for Insert, Delete and Backspace.
/// This backs up the state. Executes the action, checks if option changed. If so, apply saved state and
/// re-apply the action.
/// </summary>
/// <param name="action"></param>
protected void DoCheckAndRedo(Action action)
{
// backup state
var text = Text;
var pos = CaretPos;
var sel = Selection;
// do it!
action();
var newOption = CheckOption();
if (newOption == DetectedOption)
return;
// detected a different option
DetectedOption = newOption;
// revert saved state
Text = text;
CaretPos = pos;
Selection = sel;
Mask = newOption != null ? newOption.Value.Mask : _defaultMask;
// when mask changes we need to re-initialize!
_initialized = false;
// do it again!
action();
OptionDetected?.Invoke(newOption, Text);
}
protected virtual MaskOption? CheckOption()
{
var text = Text ?? "";
foreach (var option in _options)
{
if (option.Regex != null && Regex.IsMatch(text, option.Regex))
return option;
}
return null;
}
public override void UpdateFrom(IMask other)
{
base.UpdateFrom(other);
var o = other as MultiMask;
if (o == null)
return;
// no need to re-initialize, just update the options
_defaultMask = o._defaultMask;
_options = o._options ?? new MaskOption[0];
OptionDetected = o.OptionDetected;
Refresh();
}
}
}