|
|
|
|
// 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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|