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