зеркало из https://github.com/github/VisualStudio.git
TwoFactorInput now handles paste event
This commit is contained in:
Родитель
e8a88ecfec
Коммит
d74db93d66
|
@ -4,7 +4,7 @@
|
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:DesignTimeStyleHelper"
|
||||
|
||||
xmlns:ui="clr-namespace:GitHub.UI;assembly=GitHub.UI"
|
||||
mc:Ignorable="d"
|
||||
Title="MainWindow" Height="350" Width="525">
|
||||
|
||||
|
@ -31,5 +31,9 @@
|
|||
<StackPanel x:Name="container">
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<Border Margin="20">
|
||||
<ui:TwoFactorInput />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Window>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using NullGuard;
|
||||
|
||||
namespace GitHub.UI
|
||||
{
|
||||
|
@ -13,26 +15,68 @@ namespace GitHub.UI
|
|||
public static readonly DependencyProperty TextProperty =
|
||||
DependencyProperty.Register("Text", typeof(string), typeof(TwoFactorInput), new PropertyMetadata(""));
|
||||
|
||||
TextBox[] TextBoxes;
|
||||
|
||||
public TwoFactorInput()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
SetupTextBox(one);
|
||||
SetupTextBox(two);
|
||||
SetupTextBox(three);
|
||||
SetupTextBox(four);
|
||||
SetupTextBox(five);
|
||||
SetupTextBox(six);
|
||||
TextBoxes = new[]
|
||||
{
|
||||
one,
|
||||
two,
|
||||
three,
|
||||
four,
|
||||
five,
|
||||
six
|
||||
};
|
||||
|
||||
foreach(var textBox in TextBoxes)
|
||||
{
|
||||
SetupTextBox(textBox);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPaste(object sender, DataObjectPastingEventArgs e)
|
||||
{
|
||||
var isText = e.SourceDataObject.GetDataPresent(DataFormats.Text, true);
|
||||
if (!isText) return;
|
||||
|
||||
var text = e.SourceDataObject.GetData(DataFormats.Text) as string;
|
||||
if (text == null) return;
|
||||
e.CancelCommand();
|
||||
SetText(text);
|
||||
}
|
||||
|
||||
void SetText(string text)
|
||||
{
|
||||
if (String.IsNullOrEmpty(text))
|
||||
{
|
||||
foreach (var textBox in TextBoxes)
|
||||
{
|
||||
textBox.Text = "";
|
||||
}
|
||||
SetValue(TextProperty, text);
|
||||
return;
|
||||
}
|
||||
var digits = text.Where(Char.IsDigit).ToList();
|
||||
for (int i = 0; i < Math.Min(6, digits.Count); i++)
|
||||
{
|
||||
TextBoxes[i].Text = digits[i].ToString();
|
||||
}
|
||||
SetValue(TextProperty, String.Join("", digits));
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get { return (string)GetValue(TextProperty); }
|
||||
private set { SetValue(TextProperty, value); }
|
||||
set { SetText(value); }
|
||||
}
|
||||
|
||||
private void SetupTextBox(TextBox textBox)
|
||||
{
|
||||
DataObject.AddPastingHandler(textBox, new DataObjectPastingEventHandler(OnPaste));
|
||||
|
||||
textBox.GotFocus += (sender, args) => textBox.SelectAll();
|
||||
|
||||
textBox.PreviewKeyDown += (sender, args) =>
|
||||
|
@ -48,18 +92,30 @@ namespace GitHub.UI
|
|||
&& args.Key != Key.D8
|
||||
&& args.Key != Key.D9
|
||||
&& args.Key != Key.Tab
|
||||
&& args.Key != Key.Escape)
|
||||
&& args.Key != Key.Escape
|
||||
&& (!(args.Key == Key.V && args.KeyboardDevice.Modifiers == ModifierKeys.Control))
|
||||
&& (!(args.Key == Key.Insert && args.KeyboardDevice.Modifiers == ModifierKeys.Shift)))
|
||||
{
|
||||
args.Handled = true;
|
||||
}
|
||||
};
|
||||
|
||||
textBox.SelectionChanged += (sender, args) =>
|
||||
{
|
||||
// Make sure we can't insert additional text into a textbox.
|
||||
// Each textbox should only allow one character.
|
||||
if (textBox.SelectionLength == 0 && textBox.Text.Any())
|
||||
{
|
||||
textBox.SelectAll();
|
||||
}
|
||||
};
|
||||
|
||||
textBox.TextChanged += (sender, args) =>
|
||||
{
|
||||
var tRequest = new TraversalRequest(FocusNavigationDirection.Next);
|
||||
var keyboardFocus = Keyboard.FocusedElement as UIElement;
|
||||
|
||||
Text = GetTwoFactorCode();
|
||||
SetValue(TextProperty, String.Join("", GetTwoFactorCode()));
|
||||
|
||||
if (keyboardFocus != null)
|
||||
{
|
||||
|
@ -68,19 +124,14 @@ namespace GitHub.UI
|
|||
};
|
||||
}
|
||||
|
||||
private string GetTextBoxValue(TextBox textBox)
|
||||
private static string GetTextBoxValue(TextBox textBox)
|
||||
{
|
||||
return String.IsNullOrEmpty(textBox.Text) ? " " : textBox.Text;
|
||||
}
|
||||
|
||||
private string GetTwoFactorCode()
|
||||
{
|
||||
return GetTextBoxValue(one)
|
||||
+ GetTextBoxValue(two)
|
||||
+ GetTextBoxValue(three)
|
||||
+ GetTextBoxValue(four)
|
||||
+ GetTextBoxValue(five)
|
||||
+ GetTextBoxValue(six);
|
||||
return String.Join("", TextBoxes.Select(textBox => textBox.Text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using GitHub.UI;
|
||||
using Xunit;
|
||||
using Xunit.Extensions;
|
||||
|
||||
public class TwoFactorInputTests
|
||||
{
|
||||
public class TheTextProperty
|
||||
{
|
||||
[Fact]
|
||||
public void SetsTextBoxesToIndividualCharacters()
|
||||
{
|
||||
var twoFactorInput = new TwoFactorInput();
|
||||
var textBoxes = GetChildrenRecursive(twoFactorInput).OfType<TextBox>().ToList();
|
||||
|
||||
twoFactorInput.Text = "012345";
|
||||
|
||||
Assert.Equal("012345", twoFactorInput.Text);
|
||||
Assert.Equal("0", textBoxes[0].Text);
|
||||
Assert.Equal("1", textBoxes[1].Text);
|
||||
Assert.Equal("2", textBoxes[2].Text);
|
||||
Assert.Equal("3", textBoxes[3].Text);
|
||||
Assert.Equal("4", textBoxes[4].Text);
|
||||
Assert.Equal("5", textBoxes[5].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IgnoresNonDigitCharacters()
|
||||
{
|
||||
var twoFactorInput = new TwoFactorInput();
|
||||
var textBoxes = GetChildrenRecursive(twoFactorInput).OfType<TextBox>().ToList();
|
||||
|
||||
twoFactorInput.Text = "01xyz2345";
|
||||
|
||||
Assert.Equal("012345", twoFactorInput.Text);
|
||||
Assert.Equal("0", textBoxes[0].Text);
|
||||
Assert.Equal("1", textBoxes[1].Text);
|
||||
Assert.Equal("2", textBoxes[2].Text);
|
||||
Assert.Equal("3", textBoxes[3].Text);
|
||||
Assert.Equal("4", textBoxes[4].Text);
|
||||
Assert.Equal("5", textBoxes[5].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HandlesNotEnoughCharacters()
|
||||
{
|
||||
var twoFactorInput = new TwoFactorInput();
|
||||
var textBoxes = GetChildrenRecursive(twoFactorInput).OfType<TextBox>().ToList();
|
||||
|
||||
twoFactorInput.Text = "012";
|
||||
|
||||
Assert.Equal("012", twoFactorInput.Text);
|
||||
Assert.Equal("0", textBoxes[0].Text);
|
||||
Assert.Equal("1", textBoxes[1].Text);
|
||||
Assert.Equal("2", textBoxes[2].Text);
|
||||
Assert.Equal("", textBoxes[3].Text);
|
||||
Assert.Equal("", textBoxes[4].Text);
|
||||
Assert.Equal("", textBoxes[5].Text);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData("", "")]
|
||||
[InlineData("xxxx", "")]
|
||||
public void HandlesNullAndStringsWithNoDigits(string input, string expected)
|
||||
{
|
||||
var twoFactorInput = new TwoFactorInput();
|
||||
var textBoxes = GetChildrenRecursive(twoFactorInput).OfType<TextBox>().ToList();
|
||||
|
||||
twoFactorInput.Text = input;
|
||||
|
||||
Assert.Equal(expected, twoFactorInput.Text);
|
||||
Assert.Equal("", textBoxes[0].Text);
|
||||
Assert.Equal("", textBoxes[1].Text);
|
||||
Assert.Equal("", textBoxes[2].Text);
|
||||
Assert.Equal("", textBoxes[3].Text);
|
||||
Assert.Equal("", textBoxes[4].Text);
|
||||
Assert.Equal("", textBoxes[5].Text);
|
||||
}
|
||||
|
||||
static IEnumerable<FrameworkElement> GetChildrenRecursive(FrameworkElement element)
|
||||
{
|
||||
yield return element;
|
||||
foreach (var child in LogicalTreeHelper.GetChildren(element)
|
||||
.Cast<FrameworkElement>()
|
||||
.SelectMany(GetChildrenRecursive))
|
||||
{
|
||||
yield return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,6 +58,8 @@
|
|||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\packages\NSubstitute.1.8.1.0\lib\net45\NSubstitute.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="ReactiveUI, Version=6.3.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\packages\reactiveui-core.6.3.1\lib\Net45\ReactiveUI.dll</HintPath>
|
||||
|
@ -73,11 +75,13 @@
|
|||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xaml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="xunit">
|
||||
<HintPath>..\..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
|
||||
</Reference>
|
||||
|
@ -88,6 +92,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Args.cs" />
|
||||
<Compile Include="GitHub.App\ViewModels\LoginControlViewModelTests.cs" />
|
||||
<Compile Include="GitHub.UI\TwoFactorInputTests.cs" />
|
||||
<Compile Include="GitHubPackageTests.cs" />
|
||||
<Compile Include="Helpers\LazySubstitute.cs" />
|
||||
<Compile Include="TestDoubles\FakeMenuCommandService.cs" />
|
||||
|
@ -106,6 +111,10 @@
|
|||
<Project>{158B05E8-FDBC-4D71-B871-C96E28D5ADF5}</Project>
|
||||
<Name>GitHub.UI.Reactive</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\GitHub.UI\GitHub.UI.csproj">
|
||||
<Project>{346384dd-2445-4a28-af22-b45f3957bd89}</Project>
|
||||
<Name>GitHub.UI</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\GitHub.VisualStudio\GitHub.VisualStudio.csproj">
|
||||
<Project>{11569514-5ae5-4b5b-92a2-f10b0967de5f}</Project>
|
||||
<Name>GitHub.VisualStudio</Name>
|
||||
|
|
Загрузка…
Ссылка в новой задаче