SEBWIN-554, SEBWIN-544: Changed and improved load error handling (resource request do not trigger error message anymore).

This commit is contained in:
Damian Büchel 2022-05-13 16:47:18 +02:00
parent bc1583c070
commit bfe4a32098
7 changed files with 126 additions and 115 deletions

View file

@ -6,7 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using SafeExamBrowser.Applications.Contracts;
using SafeExamBrowser.Browser.Contracts.Events;
@ -38,8 +37,8 @@ namespace SafeExamBrowser.Browser.Contracts
event LoseFocusRequestedEventHandler LoseFocusRequested;
/// <summary>
/// Transfers the focus to 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>
/// Transfers the focus to the browser application. If the parameter is <c>true</c>, the first focusable element in the browser window
/// receives focus (passing forward of focus). Otherwise, the last element receives focus.
/// </summary>
void Focus(bool forward);
}

View file

@ -87,6 +87,14 @@ namespace SafeExamBrowser.Browser
this.windows = new List<BrowserWindow>();
}
public void Focus(bool forward)
{
windows.ForEach(window =>
{
window.Focus(forward);
});
}
public IEnumerable<IApplicationWindow> GetWindows()
{
return new List<IApplicationWindow>(windows);
@ -459,13 +467,5 @@ namespace SafeExamBrowser.Browser
CreateNewWindow();
logger.Info("Successfully reset browser.");
}
public void Focus(bool forward)
{
windows.ForEach(window =>
{
window.Focus(forward);
});
}
}
}

View file

@ -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()
{
control.AddressChanged += (o, e) => AddressChanged?.Invoke(e.Address);
@ -85,7 +102,7 @@ namespace SafeExamBrowser.Browser
control.FrameLoadStart += Control_FrameLoadStart;
control.IsBrowserInitializedChanged += Control_IsBrowserInitializedChanged;
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.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);
@ -94,28 +111,6 @@ namespace SafeExamBrowser.Browser
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()
{
control.BrowserCore.GoBack();
@ -146,18 +141,21 @@ namespace SafeExamBrowser.Browser
control.BrowserCore.SetZoomLevel(level);
}
/// <summary>
/// Executes the given Javascript code in the browser.
/// </summary>
public async void ExecuteJavascript(string javascript, Action<JavascriptResult> callback)
private void Control_FrameLoadStart(object sender, FrameLoadStartEventArgs e)
{
var result = await this.control.EvaluateScriptAsync(javascript);
callback(new JavascriptResult()
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)
{
Message = result.Message,
Result = result.Result,
Success = result.Success
});
control.BrowserCore.GetHost().SetFocus(true);
}
}
}
}

View file

@ -127,6 +127,19 @@ namespace SafeExamBrowser.Browser
Control.Destroy();
}
internal void Focus(bool forward)
{
if (forward)
{
window.FocusToolbar(forward);
}
else
{
window.FocusBrowser();
Activate();
}
}
internal void InitializeControl()
{
var cefSharpControl = default(ICefSharpControl);
@ -159,13 +172,13 @@ namespace SafeExamBrowser.Browser
downloadHandler.DownloadAborted += DownloadHandler_DownloadAborted;
downloadHandler.DownloadUpdated += DownloadHandler_DownloadUpdated;
keyboardHandler.FindRequested += KeyboardHandler_FindRequested;
keyboardHandler.FocusAddressBarRequested += KeyboardHandler_FocusAddressBarRequested;
keyboardHandler.HomeNavigationRequested += HomeNavigationRequested;
keyboardHandler.ReloadRequested += ReloadRequested;
keyboardHandler.TabPressed += KeyboardHandler_TabPressed;
keyboardHandler.ZoomInRequested += ZoomInRequested;
keyboardHandler.ZoomOutRequested += ZoomOutRequested;
keyboardHandler.ZoomResetRequested += ZoomResetRequested;
keyboardHandler.TabPressed += TabPressed;
keyboardHandler.FocusAddressBarRequested += FocusAddressBarRequested;
resourceHandler.SessionIdentifierDetected += (id) => SessionIdentifierDetected?.Invoke(id);
requestHandler.QuitUrlVisited += RequestHandler_QuitUrlVisited;
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.");
}
else if (errorCode == (int) CefErrorCode.UnknownUrlScheme)
{
logger.Info($"Request{(WindowSettings.UrlPolicy.CanLog() ? $" for '{url}'" : "")} contains unknown URL scheme and will be handled by the OS.");
}
else
}
private void HandleUnknownLoadFailure(int errorCode, string errorText, bool isMainRequest, string url)
{
var requestInfo = $"{errorText} ({errorCode}, {(isMainRequest ? "main" : "resource")} request)";
logger.Warn($"Request{(WindowSettings.UrlPolicy.CanLogError() ? $" for '{url}'" : "")} failed: {requestInfo}.");
if (isMainRequest)
{
var title = text.Get(TextKey.Browser_LoadErrorTitle);
var message = text.Get(TextKey.Browser_LoadErrorMessage).Replace("%%URL%%", WindowSettings.UrlPolicy.CanLogError() ? url : "") + $" {errorText} ({errorCode})";
logger.Warn($"Request{(WindowSettings.UrlPolicy.CanLogError() ? $" for '{url}'" : "")} failed: {errorText} ({errorCode}).");
var message = text.Get(TextKey.Browser_LoadErrorMessage).Replace("%%URL%%", WindowSettings.UrlPolicy.CanLogError() ? url : "") + $" {requestInfo}";
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();
}
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()
{
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()
{
return (zoomLevel * 25.0) + 100.0;

View file

@ -11,5 +11,5 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser.Events
/// <summary>
/// Indicates a load error for a browser request.
/// </summary>
public delegate void LoadFailedEventHandler(int errorCode, string errorText, string url);
public delegate void LoadFailedEventHandler(int errorCode, string errorText, bool isMainRequest, string url);
}

View file

@ -6,6 +6,7 @@
* 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.Events;
@ -63,9 +64,9 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser
void Destroy();
/// <summary>
/// Executes the given Javascript code in the browser.
/// Executes the given JavaScript code in the browser.
/// </summary>
void ExecuteJavascript(string javascript, System.Action<JavascriptResult> callback);
void ExecuteJavascript(string code, Action<JavascriptResult> callback);
/// <summary>
/// Attempts to find the given term on the current page according to the specified parameters.

View file

@ -29,7 +29,7 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser
/// Enables the forward navigation button.
/// </summary>
bool CanNavigateForwards { set; }
/// <summary>
/// The native handle of the window.
/// </summary>
@ -90,6 +90,22 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser
/// </summary>
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>
/// Displays the find toolbar to search the content of a page.
/// </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.
/// </summary>
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();
}
}