SEBWIN-554, SEBWIN-544: Changed and improved load error handling (resource request do not trigger error message anymore).
This commit is contained in:
parent
bc1583c070
commit
bfe4a32098
7 changed files with 126 additions and 115 deletions
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using SafeExamBrowser.Applications.Contracts;
|
using SafeExamBrowser.Applications.Contracts;
|
||||||
using SafeExamBrowser.Browser.Contracts.Events;
|
using SafeExamBrowser.Browser.Contracts.Events;
|
||||||
|
|
||||||
|
@ -38,8 +37,8 @@ namespace SafeExamBrowser.Browser.Contracts
|
||||||
event LoseFocusRequestedEventHandler LoseFocusRequested;
|
event LoseFocusRequestedEventHandler LoseFocusRequested;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transfers the focus to the browser window.
|
/// Transfers the focus to the browser application. If the parameter is <c>true</c>, the first focusable element in the browser window
|
||||||
/// <paramref name="forward">If true, the first focusable element in the browser window receives focus (passing forward of focus). Otherwise, the last element.</paramref>
|
/// receives focus (passing forward of focus). Otherwise, the last element receives focus.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Focus(bool forward);
|
void Focus(bool forward);
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,14 @@ namespace SafeExamBrowser.Browser
|
||||||
this.windows = new List<BrowserWindow>();
|
this.windows = new List<BrowserWindow>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Focus(bool forward)
|
||||||
|
{
|
||||||
|
windows.ForEach(window =>
|
||||||
|
{
|
||||||
|
window.Focus(forward);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<IApplicationWindow> GetWindows()
|
public IEnumerable<IApplicationWindow> GetWindows()
|
||||||
{
|
{
|
||||||
return new List<IApplicationWindow>(windows);
|
return new List<IApplicationWindow>(windows);
|
||||||
|
@ -459,13 +467,5 @@ namespace SafeExamBrowser.Browser
|
||||||
CreateNewWindow();
|
CreateNewWindow();
|
||||||
logger.Info("Successfully reset browser.");
|
logger.Info("Successfully reset browser.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Focus(bool forward)
|
|
||||||
{
|
|
||||||
windows.ForEach(window =>
|
|
||||||
{
|
|
||||||
window.Focus(forward);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,23 @@ namespace SafeExamBrowser.Browser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async void ExecuteJavascript(string javascript, Action<JavascriptResult> callback)
|
||||||
|
{
|
||||||
|
var result = await control.EvaluateScriptAsync(javascript);
|
||||||
|
|
||||||
|
callback(new JavascriptResult()
|
||||||
|
{
|
||||||
|
Message = result.Message,
|
||||||
|
Result = result.Result,
|
||||||
|
Success = result.Success
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Find(string term, bool isInitial, bool caseSensitive, bool forward = true)
|
||||||
|
{
|
||||||
|
control.Find(term, forward, caseSensitive, !isInitial);
|
||||||
|
}
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
control.AddressChanged += (o, e) => AddressChanged?.Invoke(e.Address);
|
control.AddressChanged += (o, e) => AddressChanged?.Invoke(e.Address);
|
||||||
|
@ -85,7 +102,7 @@ namespace SafeExamBrowser.Browser
|
||||||
control.FrameLoadStart += Control_FrameLoadStart;
|
control.FrameLoadStart += Control_FrameLoadStart;
|
||||||
control.IsBrowserInitializedChanged += Control_IsBrowserInitializedChanged;
|
control.IsBrowserInitializedChanged += Control_IsBrowserInitializedChanged;
|
||||||
control.KeyEvent += (w, b, t, k, n, m, s) => keyboardHandler.OnKeyEvent(w, b, t, k, n, m, s);
|
control.KeyEvent += (w, b, t, k, n, m, s) => keyboardHandler.OnKeyEvent(w, b, t, k, n, m, s);
|
||||||
control.LoadError += (o, e) => LoadFailed?.Invoke((int) e.ErrorCode, e.ErrorText, e.FailedUrl);
|
control.LoadError += (o, e) => LoadFailed?.Invoke((int) e.ErrorCode, e.ErrorText, e.Frame.IsMain, e.FailedUrl);
|
||||||
control.LoadingProgressChanged += (w, b, p) => displayHandler.OnLoadingProgressChange(w, b, p);
|
control.LoadingProgressChanged += (w, b, p) => displayHandler.OnLoadingProgressChange(w, b, p);
|
||||||
control.LoadingStateChanged += (o, e) => LoadingStateChanged?.Invoke(e.IsLoading);
|
control.LoadingStateChanged += (o, e) => LoadingStateChanged?.Invoke(e.IsLoading);
|
||||||
control.OpenUrlFromTab += (w, b, f, u, t, g, a) => a.Value = requestHandler.OnOpenUrlFromTab(w, b, f, u, t, g);
|
control.OpenUrlFromTab += (w, b, f, u, t, g, a) => a.Value = requestHandler.OnOpenUrlFromTab(w, b, f, u, t, g);
|
||||||
|
@ -94,28 +111,6 @@ namespace SafeExamBrowser.Browser
|
||||||
control.TitleChanged += (o, e) => TitleChanged?.Invoke(e.Title);
|
control.TitleChanged += (o, e) => TitleChanged?.Invoke(e.Title);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Control_FrameLoadStart(object sender, FrameLoadStartEventArgs e)
|
|
||||||
{
|
|
||||||
var browserExamKey = generator.CalculateBrowserExamKeyHash(e.Url);
|
|
||||||
var configurationKey = generator.CalculateConfigurationKeyHash(e.Url);
|
|
||||||
var api = contentLoader.LoadApi(browserExamKey, configurationKey, appConfig.ProgramBuildVersion);
|
|
||||||
|
|
||||||
e.Frame.ExecuteJavaScriptAsync(api);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Control_IsBrowserInitializedChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (control.IsBrowserInitialized)
|
|
||||||
{
|
|
||||||
control.BrowserCore.GetHost().SetFocus(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Find(string term, bool isInitial, bool caseSensitive, bool forward = true)
|
|
||||||
{
|
|
||||||
control.Find(term, forward, caseSensitive, !isInitial);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void NavigateBackwards()
|
public void NavigateBackwards()
|
||||||
{
|
{
|
||||||
control.BrowserCore.GoBack();
|
control.BrowserCore.GoBack();
|
||||||
|
@ -146,18 +141,21 @@ namespace SafeExamBrowser.Browser
|
||||||
control.BrowserCore.SetZoomLevel(level);
|
control.BrowserCore.SetZoomLevel(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void Control_FrameLoadStart(object sender, FrameLoadStartEventArgs e)
|
||||||
/// Executes the given Javascript code in the browser.
|
|
||||||
/// </summary>
|
|
||||||
public async void ExecuteJavascript(string javascript, Action<JavascriptResult> callback)
|
|
||||||
{
|
{
|
||||||
var result = await this.control.EvaluateScriptAsync(javascript);
|
var browserExamKey = generator.CalculateBrowserExamKeyHash(e.Url);
|
||||||
callback(new JavascriptResult()
|
var configurationKey = generator.CalculateConfigurationKeyHash(e.Url);
|
||||||
|
var api = contentLoader.LoadApi(browserExamKey, configurationKey, appConfig.ProgramBuildVersion);
|
||||||
|
|
||||||
|
e.Frame.ExecuteJavaScriptAsync(api);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Control_IsBrowserInitializedChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (control.IsBrowserInitialized)
|
||||||
{
|
{
|
||||||
Message = result.Message,
|
control.BrowserCore.GetHost().SetFocus(true);
|
||||||
Result = result.Result,
|
}
|
||||||
Success = result.Success
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,6 +127,19 @@ namespace SafeExamBrowser.Browser
|
||||||
Control.Destroy();
|
Control.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void Focus(bool forward)
|
||||||
|
{
|
||||||
|
if (forward)
|
||||||
|
{
|
||||||
|
window.FocusToolbar(forward);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window.FocusBrowser();
|
||||||
|
Activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal void InitializeControl()
|
internal void InitializeControl()
|
||||||
{
|
{
|
||||||
var cefSharpControl = default(ICefSharpControl);
|
var cefSharpControl = default(ICefSharpControl);
|
||||||
|
@ -159,13 +172,13 @@ namespace SafeExamBrowser.Browser
|
||||||
downloadHandler.DownloadAborted += DownloadHandler_DownloadAborted;
|
downloadHandler.DownloadAborted += DownloadHandler_DownloadAborted;
|
||||||
downloadHandler.DownloadUpdated += DownloadHandler_DownloadUpdated;
|
downloadHandler.DownloadUpdated += DownloadHandler_DownloadUpdated;
|
||||||
keyboardHandler.FindRequested += KeyboardHandler_FindRequested;
|
keyboardHandler.FindRequested += KeyboardHandler_FindRequested;
|
||||||
|
keyboardHandler.FocusAddressBarRequested += KeyboardHandler_FocusAddressBarRequested;
|
||||||
keyboardHandler.HomeNavigationRequested += HomeNavigationRequested;
|
keyboardHandler.HomeNavigationRequested += HomeNavigationRequested;
|
||||||
keyboardHandler.ReloadRequested += ReloadRequested;
|
keyboardHandler.ReloadRequested += ReloadRequested;
|
||||||
|
keyboardHandler.TabPressed += KeyboardHandler_TabPressed;
|
||||||
keyboardHandler.ZoomInRequested += ZoomInRequested;
|
keyboardHandler.ZoomInRequested += ZoomInRequested;
|
||||||
keyboardHandler.ZoomOutRequested += ZoomOutRequested;
|
keyboardHandler.ZoomOutRequested += ZoomOutRequested;
|
||||||
keyboardHandler.ZoomResetRequested += ZoomResetRequested;
|
keyboardHandler.ZoomResetRequested += ZoomResetRequested;
|
||||||
keyboardHandler.TabPressed += TabPressed;
|
|
||||||
keyboardHandler.FocusAddressBarRequested += FocusAddressBarRequested;
|
|
||||||
resourceHandler.SessionIdentifierDetected += (id) => SessionIdentifierDetected?.Invoke(id);
|
resourceHandler.SessionIdentifierDetected += (id) => SessionIdentifierDetected?.Invoke(id);
|
||||||
requestHandler.QuitUrlVisited += RequestHandler_QuitUrlVisited;
|
requestHandler.QuitUrlVisited += RequestHandler_QuitUrlVisited;
|
||||||
requestHandler.RequestBlocked += RequestHandler_RequestBlocked;
|
requestHandler.RequestBlocked += RequestHandler_RequestBlocked;
|
||||||
|
@ -267,26 +280,38 @@ namespace SafeExamBrowser.Browser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Control_LoadFailed(int errorCode, string errorText, string url)
|
private void Control_LoadFailed(int errorCode, string errorText, bool isMainRequest, string url)
|
||||||
{
|
{
|
||||||
if (errorCode == (int) CefErrorCode.None)
|
switch (errorCode)
|
||||||
{
|
{
|
||||||
logger.Info($"Request{(WindowSettings.UrlPolicy.CanLog() ? $" for '{url}'" : "")} was successful.");
|
case (int) CefErrorCode.Aborted:
|
||||||
|
logger.Info($"Request{(WindowSettings.UrlPolicy.CanLog() ? $" for '{url}'" : "")} was aborted.");
|
||||||
|
break;
|
||||||
|
case (int) CefErrorCode.InternetDisconnected:
|
||||||
|
logger.Info($"Request{(WindowSettings.UrlPolicy.CanLog() ? $" for '{url}'" : "")} has failed due to loss of internet connection.");
|
||||||
|
break;
|
||||||
|
case (int) CefErrorCode.None:
|
||||||
|
logger.Info($"Request{(WindowSettings.UrlPolicy.CanLog() ? $" for '{url}'" : "")} was successful.");
|
||||||
|
break;
|
||||||
|
case (int) CefErrorCode.UnknownUrlScheme:
|
||||||
|
logger.Info($"Request{(WindowSettings.UrlPolicy.CanLog() ? $" for '{url}'" : "")} has an unknown URL scheme and will be handled by the OS.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
HandleUnknownLoadFailure(errorCode, errorText, isMainRequest, url);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (errorCode == (int) CefErrorCode.Aborted)
|
}
|
||||||
{
|
|
||||||
logger.Info($"Request{(WindowSettings.UrlPolicy.CanLog() ? $" for '{url}'" : "")} was aborted.");
|
private void HandleUnknownLoadFailure(int errorCode, string errorText, bool isMainRequest, string url)
|
||||||
}
|
{
|
||||||
else if (errorCode == (int) CefErrorCode.UnknownUrlScheme)
|
var requestInfo = $"{errorText} ({errorCode}, {(isMainRequest ? "main" : "resource")} request)";
|
||||||
{
|
|
||||||
logger.Info($"Request{(WindowSettings.UrlPolicy.CanLog() ? $" for '{url}'" : "")} contains unknown URL scheme and will be handled by the OS.");
|
logger.Warn($"Request{(WindowSettings.UrlPolicy.CanLogError() ? $" for '{url}'" : "")} failed: {requestInfo}.");
|
||||||
}
|
|
||||||
else
|
if (isMainRequest)
|
||||||
{
|
{
|
||||||
var title = text.Get(TextKey.Browser_LoadErrorTitle);
|
var title = text.Get(TextKey.Browser_LoadErrorTitle);
|
||||||
var message = text.Get(TextKey.Browser_LoadErrorMessage).Replace("%%URL%%", WindowSettings.UrlPolicy.CanLogError() ? url : "") + $" {errorText} ({errorCode})";
|
var message = text.Get(TextKey.Browser_LoadErrorMessage).Replace("%%URL%%", WindowSettings.UrlPolicy.CanLogError() ? url : "") + $" {requestInfo}";
|
||||||
|
|
||||||
logger.Warn($"Request{(WindowSettings.UrlPolicy.CanLogError() ? $" for '{url}'" : "")} failed: {errorText} ({errorCode}).");
|
|
||||||
|
|
||||||
Task.Run(() => messageBox.Show(message, title, icon: MessageBoxIcon.Error, parent: window)).ContinueWith(_ => Control.NavigateBackwards());
|
Task.Run(() => messageBox.Show(message, title, icon: MessageBoxIcon.Error, parent: window)).ContinueWith(_ => Control.NavigateBackwards());
|
||||||
}
|
}
|
||||||
|
@ -465,11 +490,32 @@ namespace SafeExamBrowser.Browser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FocusAddressBarRequested()
|
private void KeyboardHandler_FocusAddressBarRequested()
|
||||||
{
|
{
|
||||||
window.FocusAddressBar();
|
window.FocusAddressBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void KeyboardHandler_TabPressed(bool shiftPressed)
|
||||||
|
{
|
||||||
|
Control.ExecuteJavascript("document.activeElement.tagName", result =>
|
||||||
|
{
|
||||||
|
var tagName = result.Result as string;
|
||||||
|
|
||||||
|
if (tagName != null && tagName.ToUpper() == "BODY")
|
||||||
|
{
|
||||||
|
// This means the user is now at the start of the focus / tabIndex chain in the website.
|
||||||
|
if (shiftPressed)
|
||||||
|
{
|
||||||
|
window.FocusToolbar(!shiftPressed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LoseFocusRequested?.Invoke(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private ChromiumHostControl LifeSpanHandler_CreatePopup()
|
private ChromiumHostControl LifeSpanHandler_CreatePopup()
|
||||||
{
|
{
|
||||||
var args = new PopupRequestedEventArgs();
|
var args = new PopupRequestedEventArgs();
|
||||||
|
@ -717,42 +763,6 @@ namespace SafeExamBrowser.Browser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TabPressed(bool shiftPressed)
|
|
||||||
{
|
|
||||||
Control.ExecuteJavascript("document.activeElement.tagName", result =>
|
|
||||||
{
|
|
||||||
var tagName = result.Result as string;
|
|
||||||
if (tagName != null)
|
|
||||||
{
|
|
||||||
if (tagName.ToUpper() == "BODY")
|
|
||||||
{
|
|
||||||
// this means the user is now at the start of the focus / tabIndex chain in the website
|
|
||||||
if (shiftPressed)
|
|
||||||
{
|
|
||||||
window.FocusToolbar(!shiftPressed);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LoseFocusRequested?.Invoke(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void Focus(bool forward)
|
|
||||||
{
|
|
||||||
if (forward)
|
|
||||||
{
|
|
||||||
window.FocusToolbar(forward);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
window.FocusBrowser();
|
|
||||||
Activate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private double CalculateZoomPercentage()
|
private double CalculateZoomPercentage()
|
||||||
{
|
{
|
||||||
return (zoomLevel * 25.0) + 100.0;
|
return (zoomLevel * 25.0) + 100.0;
|
||||||
|
|
|
@ -11,5 +11,5 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser.Events
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates a load error for a browser request.
|
/// Indicates a load error for a browser request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public delegate void LoadFailedEventHandler(int errorCode, string errorText, string url);
|
public delegate void LoadFailedEventHandler(int errorCode, string errorText, bool isMainRequest, string url);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Browser.Data;
|
using SafeExamBrowser.UserInterface.Contracts.Browser.Data;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Browser.Events;
|
using SafeExamBrowser.UserInterface.Contracts.Browser.Events;
|
||||||
|
|
||||||
|
@ -63,9 +64,9 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Executes the given Javascript code in the browser.
|
/// Executes the given JavaScript code in the browser.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void ExecuteJavascript(string javascript, System.Action<JavascriptResult> callback);
|
void ExecuteJavascript(string code, Action<JavascriptResult> callback);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to find the given term on the current page according to the specified parameters.
|
/// Attempts to find the given term on the current page according to the specified parameters.
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser
|
||||||
/// Enables the forward navigation button.
|
/// Enables the forward navigation button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool CanNavigateForwards { set; }
|
bool CanNavigateForwards { set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The native handle of the window.
|
/// The native handle of the window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -90,6 +90,22 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
event ActionRequestedEventHandler ZoomResetRequested;
|
event ActionRequestedEventHandler ZoomResetRequested;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the focus on the address bar of the window.
|
||||||
|
/// </summary>
|
||||||
|
void FocusAddressBar();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the focus on the browser content of the window.
|
||||||
|
/// </summary>
|
||||||
|
void FocusBrowser();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the focus on the toolbar of the window. If the parameter is set to true, the first focusable control on the toolbar gets focused.
|
||||||
|
/// If it is set to false, the last one.
|
||||||
|
/// </summary>
|
||||||
|
void FocusToolbar(bool forward);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Displays the find toolbar to search the content of a page.
|
/// Displays the find toolbar to search the content of a page.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -129,18 +145,5 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser
|
||||||
/// Updates the display value of the current page zoom. Value is expected to be in percentage.
|
/// Updates the display value of the current page zoom. Value is expected to be in percentage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void UpdateZoomLevel(double value);
|
void UpdateZoomLevel(double value);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the focus to the toolbar.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="forward">If true, the first focusable control on the toolbar gets focused. If false, the last one.</param>
|
|
||||||
void FocusToolbar(bool forward);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the focus to the browser.
|
|
||||||
/// </summary>
|
|
||||||
void FocusBrowser();
|
|
||||||
|
|
||||||
void FocusAddressBar();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue