Skip to content

feat(ai-win-ado-sep21): initial changes to replace WebBrowser control with WebView2 control #1205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="16.170.0" />
<PackageReference Include="Microsoft.VisualStudio.Services.Client" Version="16.170.0" />
<PackageReference Include="Microsoft.VisualStudio.Services.InteractiveClient" Version="16.170.0" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.992.28" />
<PackageReference Include="System.Buffers" Version="4.5.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.12.0" />
<PackageReference Include="System.Memory" Version="4.5.4" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using AccessibilityInsights.Extensions.AzureDevOps.Enums;
using AccessibilityInsights.Extensions.Helpers;
using AccessibilityInsights.Extensions.Interfaces.IssueReporting;
using Microsoft.Web.WebView2.Core;
using mshtml;
using System;
using System.Collections.Generic;
Expand All @@ -13,7 +14,6 @@
using System.Net;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using static System.FormattableString;

namespace AccessibilityInsights.Extensions.AzureDevOps.FileIssue
Expand Down Expand Up @@ -285,25 +285,37 @@ private static bool GuidsMatchInReproSteps(string targetGuid, string reproSteps)
/// Change the configuration zoom level for the embedded browser
/// </summary>
/// <param name="url"></param>
#pragma warning disable CA1801 // Review unused parameters
private static int? FileIssueWindow(Uri url, bool onTop, int zoomLevel, Action<int> updateZoom)
{
#if ADO_HAS_BEEN_FIXED
System.Diagnostics.Trace.WriteLine(Invariant($"Url is {url.AbsoluteUri.Length} long: {url}"));
IEBrowserEmulation.SetFeatureControls();
if (!IsWebView2RuntimeInstalled())
{
var webView = new WebviewRuntimeNotInstalled(onTop);
webView.ShowDialog();
return null;
}

Trace.WriteLine(Invariant($"Url is {url.AbsoluteUri.Length} long: {url}"));
var dlg = new IssueFileForm(url, onTop, zoomLevel, updateZoom);
dlg.ScriptToRun = "window.onerror = function(msg,url,line) { window.external.Log(msg); return true; };";

dlg.ShowDialog();

return dlg.IssueId;
#else
var dlg = new AdoNotSupportedDialog(onTop);
dlg.ShowDialog();
return null;
#endif
}
#pragma warning restore CA1801 // Review unused parameters

private static bool IsWebView2RuntimeInstalled()
{
try
{
CoreWebView2Environment.GetAvailableBrowserVersionString();
return true;
}
catch (WebView2RuntimeNotFoundException e)
{
e.ReportException();
return false;
}
}

/// <summary>
/// Creates a temp file with the given extension and returns its path
Expand Down

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using AccessibilityInsights.Extensions.Helpers;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;

Expand All @@ -16,13 +19,23 @@ namespace AccessibilityInsights.Extensions.AzureDevOps.FileIssue
/// </summary>
public partial class IssueFileForm: Form
{
enum State
{
Initializing,
TemplateIsOpen,
Saving,
Saved,
}

private const int ZOOM_MAX = 1000;
private const int ZOOM_MIN = 25;
private const int ZOOM_STEP_SIZE = 25;

// new work form item template URL
private Uri Url;

private State _currentState;

private bool makeTopMost;

private Action<int> UpdateZoomLevel;
Expand All @@ -49,6 +62,13 @@ public partial class IssueFileForm: Form
public IssueFileForm(Uri url, bool topmost, int zoomLevel, Action<int> updateZoom)
{
InitializeComponent();
this.fileIssueBrowser.CreationProperties = new CoreWebView2CreationProperties
{
// TODO: Pass this folder in from the main app!
UserDataFolder = Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.LocalApplicationData),
@"AccessibilityInsights\V1\Configurations\WebView2")
};
this.UpdateZoomLevel = updateZoom;
this.makeTopMost = topmost;
this.Url = url;
Expand All @@ -58,7 +78,7 @@ public IssueFileForm(Uri url, bool topmost, int zoomLevel, Action<int> updateZoo
this.zoomOut.FlatAppearance.BorderSize = 0;
this.ZoomValue = zoomLevel;
this.FormClosed += IssueFileForm_FormClosed;
this.fileIssueBrowser.ScriptErrorsSuppressed = true; // Hides script errors AND other dialog boxes.
ZoomToValue();
}

/// <summary>
Expand All @@ -74,51 +94,89 @@ private void IssueFileForm_FormClosed(object sender, FormClosedEventArgs e)
/// <summary>
/// Use URL changes to check whether the issue has been filed or not, close the window if issue has been filed or closed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Browser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
private void NavigationComplete(object sender, CoreWebView2NavigationCompletedEventArgs e)
{
ZoomToValue();
updateState();
}

private State updateState(bool revert = false)
{
Uri currentUri = fileIssueBrowser.Source;

var url = e.Url.PathAndQuery;
var savedUrlSubstrings = new List<String>() { "_queries/edit/", "_workitems/edit/", "_workitems?id=" };
int urlIndex = savedUrlSubstrings.FindIndex(str => url.Contains(str));
if (urlIndex >= 0)
if (currentUri != null)
{
var matched = savedUrlSubstrings[urlIndex];
var endIndex = url.IndexOf(matched, StringComparison.Ordinal) + matched.Length;

// URL looks like "_queries/edit/2222222/..." where 2222222 is issue id
// or is "_workitems/edit/2222222"
// or is "_workitems?id=2222222"
url = url.Substring(endIndex);
int result;
bool worked = int.TryParse(new String(url.TakeWhile(Char.IsDigit).ToArray()), out result);
if (worked)
switch (_currentState)
{
this.IssueId = result;
case State.Initializing:
if (currentUri.AbsoluteUri == Url.AbsoluteUri)
_currentState = State.TemplateIsOpen;
break;

case State.TemplateIsOpen:
if (currentUri.AbsoluteUri != Url.AbsoluteUri)
_currentState = State.Saving;
break;

case State.Saving:
_currentState = revert ? State.TemplateIsOpen : State.Saved;
break;
}
}

return _currentState;
}

private void CoreWebView2_HistoryChanged(object sender, object e)
{
if (updateState() == State.Saving)
{
var url = fileIssueBrowser.Source.PathAndQuery;
var savedUrlSubstrings = new List<String>() { "_queries/edit/", "_workitems/edit/", "_workitems?id=" };
int urlIndex = savedUrlSubstrings.FindIndex(str => url.Contains(str));
if (urlIndex >= 0)
{
var matched = savedUrlSubstrings[urlIndex];
var endIndex = url.IndexOf(matched, StringComparison.Ordinal) + matched.Length;

// URL looks like "_queries/edit/2222222/..." where 2222222 is issue id
// or is "_workitems/edit/2222222"
// or is "_workitems?id=2222222"
url = url.Substring(endIndex);
int result;
bool worked = int.TryParse(new String(url.TakeWhile(Char.IsDigit).ToArray()), out result);
if (worked)
{
this.IssueId = result;
}
else
{
this.IssueId = null;
}
updateState();
this.Close();
}
else
{
this.IssueId = null;
updateState(revert: true);
}
this.Close();
}
}

/// <summary>
/// Navigates to the given url
/// </summary>
/// <param name="url"></param>
private void Navigate(Uri url) => fileIssueBrowser.Navigate(url);
private void Navigate(Uri url) => fileIssueBrowser.Source = url;

private void IssueFileForm_Load(object sender, EventArgs e)
private async void IssueFileForm_Load(object sender, EventArgs e)
{
this.fileIssueBrowser.ObjectForScripting = new ScriptInterface(this);
this.fileIssueBrowser.DocumentCompleted += (s, ea) => this.fileIssueBrowser.Document.InvokeScript("eval", new object[] { ScriptToRun });
fileIssueBrowser.Navigated += Browser_Navigated;
Navigate(this.Url);
await this.fileIssueBrowser.EnsureCoreWebView2Async(null).ConfigureAwait(true);
this.fileIssueBrowser.NavigationCompleted += NavigationComplete;

this.TopMost = makeTopMost;
Navigate(this.Url);

this.fileIssueBrowser.CoreWebView2.HistoryChanged += CoreWebView2_HistoryChanged;
}

/// <summary>
Expand All @@ -129,8 +187,7 @@ private void ZoomToValue()
{
try
{
var browser = this.fileIssueBrowser.ActiveXInstance as SHDocVw.InternetExplorer;
browser.ExecWB(SHDocVw.OLECMDID.OLECMDID_OPTICAL_ZOOM, SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_DODEFAULT, ZoomValue, IntPtr.Zero);
this.fileIssueBrowser.ZoomFactor = ZoomValue / 100.0;
this.zoomLabel.Text = Invariant($"{ZoomValue}%");
}
catch (System.Runtime.InteropServices.COMException e)
Expand Down
Loading